wince6.0 音乐播放器_qq音乐付费音乐破解版_equalizer怎么播放音乐(2)

电脑杂谈  发布时间:2019-08-21 11:02:16  来源:网络整理

sample_right;CurrSamp0=CurrSamp0>>1;pCurrData+=4;}OutSamp0=PrevSamp0+(((CurrSamp0-PrevSamp0)*CurrT)>>8);//设置增益OutSamp0=(OutSamp0*fxpGain)>>VOLSHIFT;CurrT+=DeltaT;if(pBuffer<pBufferLast){OutSamp0+=*(HWSAMPLE*)pBuffer;}*(HWSAMPLE*)pBuffer=(HWSAMPLE)OutSamp0;pBuffer+=sizeof(HWSAMPLE);}}//endthe__tryblock__except(EXCEPTION_EXECUTE_HANDLER){RETAILMSG(1,(TEXT("InputStreamContext::Render2!/r/n")));m_lpCurrData=m_lpCurrDataEnd=NULL;returnNULL;}Exit:m_dwByteCount+=(pCurrData-m_lpCurrData);m_lpCurrData=pCurrData;m_CurrT=CurrT;m_PrevSamp[0]=PrevSamp0;m_CurrSamp[0]=CurrSamp0;returnpBuffer;}

从里面提到是与采样数据相乘,然后在左移16位。跟后边讲到的系统音量影响流音量是一样的。

上面讲了,DeviceContext的音量增益管理,现在来看下它的流管理。

StreamContext流管理:主要来管理StreamContext的建立、删除、渲染、传输等功能。

主要有如下几个函数

StreamContext*CreateStream(LPWAVEOPENDESClpWOD);DWORDOpenStream(LPWAVEOPENDESClpWOD,DWORDdwFlags,StreamContext**ppStreamContext);HRESULTOpen(DeviceContext*pDeviceContext,LPWAVEOPENDESClpWOD,DWORDdwFlags);voidNewStream(StreamContext*pStreamContext);voidDeleteStream(StreamContext*pStreamContext);voidStreamReadyToRender(StreamContext*pStreamContext);PBYTETransferBuffer(PBYTEpBuffer,PBYTEpBufferEnd,DWORD*pNumStreams,BOOLbMuteFlag);

在DeviceContext中有个m_StreamList的双向链表(LIST_ENTRY), m_StreamList用来指向数组的头。在StreamConext中也存在一个m_Link(LIST_ENTRY)。StreamContext是调用DeviceContext的OpenStream来建立的,然后把StreamContext对象加入到DeviceContext的m_StreamList中。我们从代码中去直接分析:

上层调用waveoutOpen,在wavedev2中会调用WODM_OPEN这个分支。在WODM_OPEN中的代码如下:

caseWODM_OPEN:{StreamContext*pStreamContext;pStreamContext=(StreamContext*)dwUser;dwRet=pDeviceContext->OpenStream((LPWAVEOPENDESC)dwParam1,dwParam2,(StreamContext**)pStreamContext);break;}

OpenStream的其流程图如下

wps_clip_image-7555[4]

StreamContext 初始化流程

CreateStream是依照WAVEFORMATEX这个结构体,来判别具体要构建StreamContext的哪个派生类,下面是CreateStream的流程图,不可不提,还是流程图清晰。

wps_clip_image-7702[4]

OutputDeviceContext:: CreateStream流程图

上面讲了上层通过WODM_OPEN创建一个StreamContext的过程,那么音频流被开启以后,接下来就是给StreamContext传入音频数据开始播放乐曲。Wavedev2提供了WODM_WRITE来向音频设定写入数据。我们先看下WODM_WRITE分支的代码

caseWODM_WRITE:{StreamContext*pStreamContext;pStreamContext=(StreamContext*)dwUser;dwRet=pStreamContext->QueueBuffer((LPWAVEHDR)dwParam1);break;}

equalizer怎么播放音乐_qq音乐付费音乐破解版_wince6.0 音乐播放器

这里调用了StreamContext中的QueueBuffer,QueueBuffer的作用就是把WAVEHDR中的数据加入到StreamContext的队列中,等待播放。下面是QueueBuffer的流程图

wps_clip_image-8173[4]

QueueBuffer流程图

在QueueBuffer中调用DeviceContext中的StreamReadyToReander通知可以开始渲染了,流程图中的箭头方向是StreamReadyToReander调用步骤,最终调用SetEvent(hOutputIntEvent),来通知线程数据将要准备好,得到通知后,就起初播放了。该泛型在HardwareContext中的OutputInterruptThread函数中

OutputInterruptThread流程如下

wps_clip_image-8440[5]

WinCE平台上的DMA

CEDDK提供了DMA的相关函数,在CEDDK/DDK_DMA/ddk_dma.c中定义。最有用的就两个函数,HalAllocateCommonBuffer(..)和HalFreeCommonBuffer(..)分别用于为DMA申请和释放存储。

(1)首先介绍一下会用到的DMA适配器结构,在ceddk.h中定义,如下:

typedef struct _DMA_ADAPTER_OBJECT_

{

USHORT ObjectSize; //该结构的大小

INTERFACE_TYPE InterfaceType; //接口类别,一般用做DMA时设定为Internal

ULONG BusNumber; //一般设定为0

} DMA_ADAPTER_OBJECT, *PDMA_ADAPTER_OBJECT;

(2)DMA内存分配变量:

PVOID HalAllocateCommonBuffer(PDMA_ADAPTER_OBJECT DmaAdapter, ULONG Length, PPHYSICAL_ADDRESS LogicalAddress, BOOLEAN CacheEnabled)

DmaAdapter: DMA适配器结构指针

Length: 要分配的存储的大小

LogicalAddress: 分配成功后,内存的物理起始地址

CacheEnabled: 是否使用Cache

实际上该变量通过读取AllocPhysMem函数来分配一段物理地址连续的存储,这段硬盘默认是64KB字节对齐的,DMA操作的物理内存必须是连续的。该变量调用失败之后,返回值是虚拟地址,可以在驱动中访问其中的内容,函数的第三个参数返回存储的物理地址,可以赋值给DMA控制器来完成DMA操作。

(3)DMA内存释放函数:

VOID HalFreeCommonBuffer(PDMA_ADAPTER_OBJECT DmaAdapter, ULONG Length, PHYSICAL_ADDRESS LogicalAddress, PVOID VirtualAddress, BOOLEAN CacheEnabled)

DmaAdapter: DMA适配器结构指针

Length: 内存的大小

LogicalAddress: 内存的物理起始地址

VirtualAddress: 内存的虚拟地址

qq音乐付费音乐破解版_wince6.0 音乐播放器_equalizer怎么播放音乐

CacheEnabled: 是否使用Cache

该变量通过读取FreePhysMem函数来完成存储的释放,所以在使用该变量的之后,只有函数的第四个参数是需要的,也就是内存的虚拟地址,其他的都可以忽略。

(4)下面给个使用里面两个函数的举例:

DMA_ADAPTER_OBJECT dmaAdapter;

//初始化DMA适配器

dmaAdapter.ObjectSize = sizeof(dmaAdapter);

dmaAdapter.InterfaceType = Internal;

dmaAdapter.BusNumber = 0;

//分配DMA内存

m_pDMABuf = (PBYTE)HalAllocateCommonBuffer( &dmaAdapter, 256 * 1024, &m_pDMABufPhys, FALSE );

//将物理地址赋值给DMA控制器

vm_pDMAreg->DST = (int)m_pDMABufPhys.LowPart;

...

//释放DMA内存

if( m_pDMABuf != NULL )

{

HalFreeCommonBuffer( NULL, 0, 0, m_pDMABuffer, FALSE);

m_pDMABuf = NULL;

}

在ddk_dma.c中,还可以提到其他太多DMA相关的操作变量。这些DMA函数是拿来操作DMA设备的,通过CreateFile来开启DMA设备,然后读取DeviceIoControl函数来访问DMA设备。DMA设备驱动在/WINCE600/PUBLIC/Common/Oak/Drivers/DMA下面,该DMA驱动以流设施驱动的方式谋求。

一般来说,DMA驱动会配合其他仪器驱动来完成数据存储,所以很少会被单独成为一个设备来使用,大多数情况我们研发设备驱动时还要用到DMA的之后,会用到上面两个函数来申请和释放存储。

(5)音频驱动中的DMA

以S3C2440A为例,它的DMA控制器没有内置的DMA存储区域,所以驱动程序必须在硬盘内为音频器材分配DMA缓冲区。缓冲区设置是否合理比较关键,缓冲区太小易于导致缓冲区溢出,而要填充大的缓冲区,CPU就要一次处理长期的数据,容易引起延迟。

所以在本驱动中采取双缓冲区来缓解这个弊端,也就是当CPU在处理某一个缓冲区音频数据的同时,DMA控制器可以完成另一个缓冲区音频数据的存储,如此交替下去,则可以增强系统的并行能力,提高音频处理的实时性。本驱动所选用的DMA1通道和DMA2通道分别设定了两个缓冲区。采用DMA控制器通道1控制录制的音频数据的存储,采用通道2控制播放的音频数据的存储。

以放音为例,如下:

新的音频数据在CPU的控制下先提到DMA缓冲区A中,此时DMA控制器正在从DMA缓冲区B中迁移音频数据到IIS总线。当缓冲区B的数据全部存储完成过后,DMA控制器产生INT_DMA2中断,该中止通知CPU开始往缓冲区B中写新的音频数据,与此同时DMA控制器从缓冲区A中迁移数据到IIS总线。这样交替循环,由于CPU和DMA控制器没有同时处理同一块缓冲区,就减低了资源访问的矛盾,并且能否最大程度上增强音频处理的实时性。

放音的协作过程:

equalizer怎么播放音乐_wince6.0 音乐播放器_qq音乐付费音乐破解版

A,DMA请求,开始播放音乐时,DMA控制器收到IIS的发送请求后,向CPU提出接管总线要求,以便进行上面的DMA数据存储。

B,DMA音频数据存储,DMA控制器得到总线的控制权后,通知IIS控制器DMA应答,这时开始处于DMA数据存储,DMA控制器从输出缓冲区A中取出CPU填充的音频数据到IIS控制器的发送FIFO,当前的DMA传输结束,也即2048个字节的音频数据已借助IIS总线发送到音频编。

C,DMA中断wince6.0 音乐播放器,DMA传输结束后DMA控制器向CPU发出INT_DMA2中断,表示输出缓冲区A的数据已经被迁移到音频编,这时CPU(这之前CPU往输出缓冲区B写入音频数据)转而向输出缓冲区A写入音频数据,而DMA控制器同时从输出缓冲区B中迁移数据到发送的FIFO。CPU和DMA控制器如此交替访问缓冲区,实现音频数据的迅速存储。

录音时DMA的操作类似。

Devctxt.cpp

器件关联——包含了音频流的创造,删除,打开,关闭,格式等功能

Hwctxt.cpp

硬件关联——包含了基本的软件功用在各个状态的全局配置

I2citf.cpp

I2C传输配置

I2S.cpp

I2S传输配置

Input.cpp

负责输入音频流

Output.cpp

负责输出音频流

Midinote.cpp

负责输出MIDI

Midistrm.cpp

负责MIDI的开关以及控制

Mixerdrv.cpp

系统硬件混音

RTcodecComm.cpp

Wm8753的所有用途配置,以及初始化设置

Strmctxt.cpp

负责所有音频流的增益,buffer请求等功能以及对Devctxt的控制

Wavemain.cpp

包含了所有的流接口函数


本文来自电脑杂谈,转载请注明本文网址:
https://www.pc-fly.com/a/bofangqi/article-120037-2.html

相关阅读
    发表评论  请自觉遵守互联网相关的政策法规,严禁发布、暴力、反动的言论

    热点图片
    拼命载入中...