DSound中音频与时间的转换

来源:互联网 发布:centos 安装ssh服务 编辑:程序博客网 时间:2024/06/05 05:55
 在DSound播放文件的同时,我们维系了一个变量来递增显示当前播放的时间,下面讲其中几个比较重要的函数

  1.     HRESULT CScopeFilter::getCurPos()
  2.     {
  3.         if(!buffer) return DSERR_UNINITIALIZED;
  4.         clockLock.Lock();
  5.         DWORD p;
  6.         HRESULT hr= buffer->GetCurrentPosition(&p,0);
  7.         if(hr==DS_OK){
  8.             static DWORD pp,cnt; ///实际情况在播放的时候不可能p==pp
  9.             if(p==pp){
  10.                 if(playing && ++cnt>9){
  11.                     stop();
  12.                     play(); 
  13.                     cnt=0;
  14.                 }
  15.             }else{
  16.                 cnt=0;
  17.                 pp=p;
  18.             }
  19.             if(p<curPos){
  20.                 //因为在播放音乐的时候是一个一个Buff来播放的,获得Buff的位置p,那么证明我们的curPos
  21.                 //存储的只是上一帧的位置,需要加上这一帧的大小
  22.                 offsetBuf+=bufSize;
  23.                 //并且我们的buff个数也要加一
  24.                 cycleDif++;
  25.             }
  26.             //注意这里的CurPos永远都是相对于Buff
  27.             //buff在一个接一个播放的,因而curPos都在变
  28.             //但是相对于文件来说,我们播放了多长时间了,就要参考GetPrivateTime函数
  29.             //看他们之间的关系
  30.             curPos=p;
  31.         }
  32.         clockLock.Unlock();
  33.         return hr;
  34.     }
这里一般情况下都会是p<curPos,那么offsetbuf,就是描述一个buf的偏移量,不断的累加,cycleDif是一个描述偏移次数的东东,这个函数下来,改变得有三个offsetBuf、cycleDif和curPos,这个curPos描述的相对与当前Buf的位置。那理论上,我们播放一个bufSize的时候就要调用这个函数一次在什么地方时候时候调用。
我们可以看到这个函数在,音乐播放的While循环里面调用过,这样我们就想通了。
好,这个修改的只是Buf的位置,如何转换成时间呢?
  1. REFERENCE_TIME CScopeFilter::GetPrivateTime()
  2.     {
  3.         HRESULT hr= getCurPos();
  4.         if(hr==DS_OK){
  5.             clockLock.Lock();
  6.             REFERENCE_TIME result= UNITS*(curPos+offsetBuf)/bufFormat.Format.nAvgBytesPerSec;
  7.             clockLock.Unlock();
  8.             return result;
  9.         }
  10.         return 0;
  11.     }
其中UNITS为10^7,(curPos+offsetBuf)/bufFormat.Format.nAvgBytesPerSec这个返回的是秒为单位,乘以UNITS之后,精度变为10^-7s了,前面好像说过IRef实现的函数可以为空,这句话不完全正确,函数为空只是针对于那些需要同步的函数如GetAdviceTime这类函数,但是里面的一个最基本的GetTime还是要做的,因为Graph要知道当前的播放进度就是通过这个函数,这个函数必须的实现,为了实现这个函数,我们首先写了这个函数:
  1. REFERENCE_TIME CScopeFilter::getWriteTime()
  2.     {
  3.         clockLock.Lock();
  4.         REFERENCE_TIME result= UNITS*(offsetBuf+(writePos+(1-cycleDif)*bufSize))/bufFormat.Format.nAvgBytesPerSec;
  5.         clockLock.Unlock();
  6.         return result;
  7.     }
  1. STDMETHODIMP CScopeFilter::GetTime(REFERENCE_TIME *pTime)
  2.     {
  3.         CheckPointer(pTime,E_POINTER);
  4.         *pTime= GetPrivateTime();
  5.         if(*pTime<beginTime) *pTime=beginTime;
  6.         return S_OK;
  7.     }
  8. int CScopeFilter::msToB(int ms)
  9. {
  10.     return MulDiv(ms, bufFormat.Format.nSamplesPerSec, 1000)*bufFormat.Format.nBlockAlign;
  11.  }
这都是时间相关的函数,可以参考一下。
下面有两个相对的函数;
  1. int CScopeFilter::getFree()
  2.     {
  3.         clockLock.Lock();
  4.         int result= int(curPos-writePos)+cycleDif*bufSize;
  5.         clockLock.Unlock();
  6.         return result;
  7.     }
  1. int CScopeFilter::getFilled()
  2.     {
  3.         clockLock.Lock();
  4.         int result= int(writePos-curPos)+(1-cycleDif)*bufSize;
  5.         clockLock.Unlock();
  6.         return result;
  7.     }
返回的分别是空闲和已读的字节数。

原创粉丝点击