D:/work/code_by/Wave/WavePlayer.cpp

查看本檔案說明文件.
00001 #include <stdio.h>
00002 #include "WavePlayer.h"
00003 
00004 TWavePlayerWindow::TWavePlayerWindow(TWavePlayer *Wave) : THiddenWindow("WavePlayerWindow")
00005 {
00006   WavePlayer = Wave;
00007 }
00008 
00009 void TWavePlayerWindow::WndProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
00010 {
00011   if (uMsg == WM_APP + 111)
00012     WavePlayer->RecordComplete();
00013   else if (uMsg == WM_APP + 222)
00014     WavePlayer->PlayComplete();
00015 }
00016 
00017 static void CALLBACK WavePlayerInProc(HWAVEIN hwi, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2)
00018 {
00019   TWavePlayer *WavePlayer;
00020 
00021   if (uMsg == WIM_DATA)  //代表錄滿一個buffer
00022   {
00023     WavePlayer = (TWavePlayer *)dwInstance;
00024     if (WavePlayer->GetMode() != TWavePlayer::IDLE)
00025       WavePlayer->RecordABuffer();
00026   }
00027 }
00028 
00029 static void CALLBACK WavePlayerOutProc(HWAVEOUT hwo, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2)
00030 {
00031   TWavePlayer *WavePlayer;
00032 
00033   if (uMsg == WOM_DONE)  //代表播完一個buffer
00034   {
00035     WavePlayer = (TWavePlayer *)dwInstance;
00036     if (WavePlayer->GetMode() != TWavePlayer::IDLE)
00037       WavePlayer->PlayABuffer();
00038   }
00039 }
00040 
00041 TWavePlayer::TWavePlayer(int sampleRate, int bitRate) : Speaker()
00042 {
00043   int i;
00044 
00045   mode = IDLE;  //非錄音、非播放模式
00046   echoOn = false;  //沒有迴音
00047   echoVolume = 5;  //迴音音量
00048   wave = NULL;
00049   Clear();  //清除聲波
00050 
00051   for (i = 0; i < 3; i++)
00052   {
00053     waveInHdr[i].lpData = NULL;
00054     waveOutHdr[i].lpData = NULL;
00055   }
00056 
00057   SetFormat(sampleRate, bitRate);
00058   SetBufferSize(sampleRate / 5);
00059   HiddenWindow = new TWavePlayerWindow(this);  //建立一隱藏視窗
00060 }
00061 
00062 TWavePlayer::~TWavePlayer()
00063 {
00064   StopRecord();  //停止錄音
00065   StopPlay();  //停止播放
00066   Clear();  //清除聲波
00067   delete HiddenWindow;  //釋放隱藏視窗
00068 }
00069 
00070 int TWavePlayer::GetMode(void)
00071 {
00072   return mode;  //錄音或播放模式
00073 }
00074 
00075 int TWavePlayer::GetSampleRate(void)
00076 {
00077   return waveFormat.nSamplesPerSec;  //每秒幾個sample
00078 }
00079 
00080 int TWavePlayer::GetBitRate(void)
00081 {
00082   return waveFormat.wBitsPerSample;  //每個sample幾bit
00083 }
00084 
00085 bool TWavePlayer::IsEchoOn(void)
00086 {
00087   return echoOn;  //是否已開啟錄音模式
00088 }
00089 
00090 void TWavePlayer::SetFormat(int newSampleRate, int newBitRate)
00091 {
00092   int i;
00093 
00094   if (mode != IDLE)  //正在錄音或播放
00095     return;
00096 
00097   if (newBitRate != GetBitRate())
00098   {
00099     if (newBitRate == 8)
00100       for (i = 0; i < waveSize; i++)
00101         wave[i] = wave[i] >> 8;
00102     else
00103       for (i = 0; i < waveSize; i++)
00104         wave[i] = wave[i] << 8;
00105   }
00106   Resample(newSampleRate);
00107 
00108   waveFormat.wFormatTag = WAVE_FORMAT_PCM;
00109   waveFormat.nChannels = 1;
00110   waveFormat.nSamplesPerSec = newSampleRate;
00111   waveFormat.wBitsPerSample = newBitRate;
00112   waveFormat.nBlockAlign = waveFormat.nChannels * waveFormat.wBitsPerSample / 8;
00113   waveFormat.nAvgBytesPerSec = waveFormat.nSamplesPerSec * waveFormat.nBlockAlign;
00114   waveFormat.cbSize = 0;
00115 
00116   bytesPerSample = newBitRate / 8;  //1代表8 bits,2代表16 bits
00117   bytesPerBuffer = bufferSize * bytesPerSample;
00118 }
00119 
00120 void TWavePlayer::Resample(int newSampleRate)
00121 {
00122   int i, j, r, n, sampleRate;
00123   int *newWave;
00124 
00125   sampleRate = GetSampleRate();
00126   if (newSampleRate == sampleRate || waveSize == 0)
00127     return;
00128 
00129   //本來是 waveSize = (waveSize - 1) * newSampleRate / sampleRate,
00130   //但是 (waveSize - 1) * newSampleRate 可能會overflow,所以拆成兩行
00131   r = (waveSize - 1) % sampleRate;
00132   waveSize = (waveSize - 1 - r) / sampleRate * newSampleRate + r * newSampleRate / sampleRate;
00133   bufferTotal = (waveSize + bufferSize - 1) / bufferSize;
00134   newWave = new int[bufferTotal * bufferSize + 16000];
00135   for (i = 0; i < waveSize; i++)
00136   {
00137     //本來是 j = i * sampleRate / newSampleRate
00138     //但是 i * sampleRate 可能會overflow,所以拆成兩行
00139     r = i % newSampleRate;
00140     j = (i - r) / newSampleRate * sampleRate + r * sampleRate / newSampleRate;
00141     n = (10.0f * i * sampleRate) / newSampleRate - 10 * j;
00142     newWave[i] = (wave[j] * (10 - n) + wave[j + 1] * n) / 10;
00143   }
00144   memset(newWave + waveSize, 0, (bufferTotal * bufferSize + 16000 - waveSize) * sizeof(int));  //把多餘的部份設為靜音
00145 
00146   delete[] wave;
00147   wave = newWave;
00148 }
00149 
00150 int TWavePlayer::GetBufferSize(void)
00151 {
00152   return bufferSize;
00153 }
00154 
00155 void TWavePlayer::SetBufferSize(int size)
00156 {
00157   if (mode != IDLE)  //正在錄音或播放
00158     return;
00159 
00160   bufferSize = size;
00161   bytesPerBuffer = bufferSize * bytesPerSample;
00162   bufferTotal = (waveSize + bufferSize - 1) / bufferSize;
00163 }
00164 
00165 void TWavePlayer::SetWave(int *w, int size)
00166 {
00167   if (mode != IDLE)  //正在錄音或播放
00168     return;
00169 
00170   Clear();  //清除聲波
00171   waveSize = size;
00172   duration = (float)waveSize / GetSampleRate();
00173   bufferTotal = (waveSize + bufferSize - 1) / bufferSize;  //buffer個數
00174   wave = new int[bufferTotal * bufferSize + 16000];  //讓wave陣列大一點,比較不用判斷陣列的邊界問題
00175   memcpy(wave, w, waveSize * sizeof(int));  //把聲波複製到wave陣列
00176   memset(wave + waveSize, 0, (bufferTotal * bufferSize + 16000 - waveSize) * sizeof(int));  //把多餘的部份設為靜音
00177 }
00178 
00179 void TWavePlayer::SetWave(TWaveFile *WaveFile)
00180 {
00181   if (mode != IDLE)  //正在錄音或播放
00182     return;
00183 
00184   Clear();  //清除聲波
00185   SetFormat(WaveFile->GetSampleRate(), WaveFile->GetBitRate());  //把格式設成和WaveFile相同
00186   SetWave(WaveFile->wave, WaveFile->waveSize);  //把聲波設成和WaveFile相同
00187 }
00188 
00189 bool TWavePlayer::Load(char *name)
00190 {
00191   TWaveFile WaveFile;
00192 
00193   if (mode != IDLE)  //正在錄音或播放
00194     return false;
00195 
00196   Clear();  //清除聲波
00197   if (!WaveFile.Load(name))  //載入wav檔
00198     return false;
00199   SetWave(&WaveFile);  //把載入的聲波複製進來
00200   return true;
00201 }
00202 
00203 bool TWavePlayer::Save(char *name)
00204 {
00205   TWaveFile WaveFile;
00206 
00207   if (mode != IDLE)  //正在錄音或播放
00208     return false;
00209 
00210   WaveFile.SetFormat(GetSampleRate(), GetBitRate());  //設定WaveFile的格式
00211   WaveFile.SetWave(wave, waveSize);  //設定WaveFile的聲波
00212   return WaveFile.Save(name);  //儲存wav檔
00213 }
00214 
00215 bool TWavePlayer::OpenRecordDevice(void)
00216 {
00217   int i;
00218 
00219   if (mode == RECORDING)  //正在錄音
00220     return true;
00221 
00222   if (waveInOpen(&waveIn, WAVE_MAPPER, &waveFormat, (DWORD)WavePlayerInProc, (DWORD)this, CALLBACK_FUNCTION) != MMSYSERR_NOERROR)  //錄音設備開啟失敗
00223     return false;
00224 
00225   for (i = 0; i < 3; i++)
00226   {
00227     waveInHdr[i].dwBufferLength = bytesPerBuffer;
00228     waveInHdr[i].lpData = new char[bytesPerBuffer];
00229     waveInHdr[i].dwFlags = 0;
00230     memset(waveInHdr[i].lpData, bytesPerSample == 1? 128 : 0, bytesPerBuffer);  //先清成靜音
00231     waveInPrepareHeader(waveIn, waveInHdr + i, sizeof(WAVEHDR));
00232   }
00233   //一次錄2個buffer才不會有間斷的聲音
00234   waveInAddBuffer(waveIn, waveInHdr, sizeof(WAVEHDR));
00235   waveInAddBuffer(waveIn, waveInHdr + 1, sizeof(WAVEHDR));
00236   return true;
00237 }
00238 
00239 void TWavePlayer::CloseRecordDevice(void)
00240 {
00241   int i;
00242 
00243   waveInReset(waveIn);
00244   for (i = 0; i < 3; i++)
00245   {
00246     waveInUnprepareHeader(waveIn, waveInHdr + i, sizeof(WAVEHDR));
00247     delete[] waveInHdr[i].lpData;
00248     waveInHdr[i].lpData = NULL;
00249   }
00250   waveInClose(waveIn);
00251 }
00252 
00253 bool TWavePlayer::OpenPlayDevice(void)
00254 {
00255   int i;
00256 
00257   if (mode == PLAYING)  //正在播放
00258     return true;
00259 
00260   if (waveOutOpen(&waveOut, WAVE_MAPPER, &waveFormat, (DWORD)WavePlayerOutProc, (DWORD)this, CALLBACK_FUNCTION) != MMSYSERR_NOERROR)  //放音設備開啟失敗
00261     return false;
00262 
00263   for (i = 0; i < 3; i++)
00264   {
00265     waveOutHdr[i].dwBufferLength = bytesPerBuffer;
00266     waveOutHdr[i].lpData = new char[bytesPerBuffer];
00267     waveOutHdr[i].dwFlags = waveOutHdr[i].dwLoops = 0;
00268     waveOutPrepareHeader(waveOut, waveOutHdr + i, sizeof(WAVEHDR));
00269   }
00270   return true;
00271 }
00272 
00273 void TWavePlayer::ClosePlayDevice(void)
00274 {
00275   int i;
00276 
00277   waveOutReset(waveOut);
00278   for (i = 0; i < 3; i++)
00279   {
00280     waveOutUnprepareHeader(waveOut, waveOutHdr + i, sizeof(WAVEHDR));
00281     delete[] waveOutHdr[i].lpData;
00282     waveOutHdr[i].lpData = NULL;
00283   }
00284   waveOutClose(waveOut);
00285 }
00286 
00287 bool TWavePlayer::Record(int maxDuration)
00288 {
00289   if (mode == RECORDING)  //正在錄音
00290     return true;
00291 
00292   StopPlay();  //停止播放
00293   Clear();  //清除舊的聲波
00294   if (!OpenRecordDevice())  //開啟錄音裝置
00295     return false;
00296 
00297   mode = RECORDING;
00298   duration = maxDuration;  //最多要錄幾秒
00299   bufferTotal = (duration * GetSampleRate() + bufferSize - 1) / bufferSize;  //最多會用到幾個buffer
00300   wave = new int[bufferTotal * bufferSize + 16000];  //讓wave陣列大一點,比較不用判斷陣列的邊界問題
00301   waveInStart(waveIn);  //開始錄音
00302 
00303   if (duration == 0)
00304   {
00305     RecordComplete();
00306     return true;
00307   }
00308 
00309   if (echoOn)  //已經開啟迴音模式
00310   {
00311     if (OpenPlayDevice())  //開啟播放裝置
00312       firstEcho = true;
00313   }
00314 
00315   return true;
00316 }
00317 
00318 void TWavePlayer::StopRecord(void)
00319 {
00320   if (mode != RECORDING)  //不是錄音模式
00321     return;
00322 
00323   mode = IDLE;
00324   bufferTotal = (waveSize + bufferSize - 1) / bufferSize;  //總共錄了幾個buffer
00325   duration = (float)waveSize / GetSampleRate();  //總共錄了幾秒
00326   CloseRecordDevice();  //關閉錄音裝置
00327   if (echoOn)
00328     ClosePlayDevice();  //關閉放音裝置
00329 }
00330 
00331 bool TWavePlayer::Play(void)
00332 {
00333   int i;
00334 
00335   if (mode == PLAYING)  //正在播放
00336     return true;
00337 
00338   StopRecord();  //停止錄音
00339   if (!OpenPlayDevice())  //開啟播放裝置
00340     return false;
00341 
00342   mode = PLAYING;
00343   playBufferCount = 0;  //已播放的buffer數目
00344 
00345   if (waveSize == 0)
00346   {
00347     PlayComplete();
00348     return true;
00349   }
00350 
00351   WaveCopy(waveOutHdr[0].lpData, wave, bufferSize);
00352   if (waveSize > bufferSize)
00353     WaveCopy(waveOutHdr[1].lpData, wave + bufferSize, bufferSize);
00354 
00355   waveOutWrite(waveOut, waveOutHdr, sizeof(WAVEHDR));  //播放
00356   if (waveSize > bufferSize)
00357     waveOutWrite(waveOut, waveOutHdr + 1, sizeof(WAVEHDR));  //播放
00358 
00359   return true;
00360 }
00361 
00362 void TWavePlayer::StopPlay(void)
00363 {
00364   if (mode != PLAYING)  //不是播放模式
00365     return;
00366 
00367   mode = IDLE;
00368   ClosePlayDevice();  //關閉播放裝置
00369 }
00370 
00371 void TWavePlayer::EchoOn(void)
00372 {
00373   if (echoOn)  //已經開啟迴音模式
00374     return;
00375 
00376   echoOn = true;
00377   if (mode == RECORDING)  //錄音模式
00378     if (OpenPlayDevice())  //開啟播放裝置
00379       firstEcho = true;
00380 }
00381 
00382 void TWavePlayer::EchoOff(void)
00383 {
00384   if (!echoOn)  //沒有開啟迴音模式
00385     return;
00386 
00387   echoOn = false;
00388   if (mode == RECORDING)  //錄音模式
00389     ClosePlayDevice();  //關閉放音裝置
00390 }
00391 
00392 float TWavePlayer::GetDuration(void)
00393 {
00394   return duration;  //聲波秒數
00395 }
00396 
00397 float TWavePlayer::GetTimeCode(void)
00398 {
00399   if (mode == IDLE || bufferTotal == 0)  //沒有在錄音或播放
00400     return 0;
00401   return (mode == RECORDING? recordBufferCount : playBufferCount) * duration / bufferTotal;  //已錄或播放的秒數
00402 }
00403 
00404 void TWavePlayer::Seek(int percent)
00405 {
00406   if (mode != PLAYING)  //沒有在播放
00407     return;
00408 
00409   playBufferCount = bufferTotal * percent / 100;  //把播放的起點移到正確的進度
00410 }
00411 
00412 void TWavePlayer::Clear()
00413 {
00414   delete[] wave;
00415   wave = NULL;
00416   waveSize = 0;
00417   duration = 0.0f;
00418   bufferTotal = recordBufferCount = playBufferCount = 0;
00419 }
00420 
00421 void TWavePlayer::Trim(int from, int to)
00422 {
00423   int *newwave;
00424 
00425   if (from < 0)
00426     from = 0;
00427   if (to >= waveSize)
00428     to = waveSize - 1;
00429   if (from > to)
00430     to = from - 1;
00431   waveSize = to - from + 1;
00432   duration = (float)waveSize / GetSampleRate();
00433   bufferTotal = (waveSize + bufferSize - 1) / bufferSize;  //buffer個數
00434   newwave = new int[bufferTotal * bufferSize + 16000];  //讓wave陣列大一點,比較不用判斷陣列的邊界問題
00435   memcpy(newwave, wave + from, waveSize * sizeof(int));
00436   memset(newwave + waveSize, 0, (bufferTotal * bufferSize + 16000 - waveSize) * sizeof(int));  //把多餘的部份設為靜音
00437   delete[] wave;
00438   wave = newwave;
00439 }
00440 
00441 void TWavePlayer::RecordABuffer(void)
00442 {
00443   if (mode != RECORDING)  //不是錄音模式
00444     return;
00445 
00446   WaveCopy(wave + waveSize, waveInHdr[recordBufferCount % 3].lpData, bufferSize);  //把這次錄好的聲波複製到wave陣列
00447   waveSize += bufferSize;  //wave陣列的大小變大
00448 
00449   ++recordBufferCount;  //已經錄完的buffer數目
00450   if (recordBufferCount == bufferTotal)  //錄音完畢
00451   {
00452     PostMessage(HiddenWindow->Handle, WM_APP + 111, 0, 0);
00453     return;
00454   }
00455   if (mode == RECORDING)
00456     Deliver(EVENT_RECORD_BUFFER, wave + (recordBufferCount - 1) * bufferSize);
00457 
00458   if (recordBufferCount < bufferTotal - 1)  //在錄音完畢之前
00459   {
00460     if (echoOn && firstEcho)  //正打開迴音
00461     {
00462       firstEcho = false;
00463       firstEchoBufferIndex = recordBufferCount - 1;  //第1個要迴音的buffer
00464       memset(waveOutHdr[0].lpData, bytesPerSample == 1? 128 : 0, bytesPerBuffer);  //清成靜音
00465       memcpy(waveOutHdr[1].lpData, waveInHdr[(recordBufferCount + 2) % 3].lpData, bytesPerBuffer);
00466       //一次播放2個buffer才不會有間斷的聲音
00467       waveOutWrite(waveOut, waveOutHdr, sizeof(WAVEHDR));
00468       waveOutWrite(waveOut, waveOutHdr + 1, sizeof(WAVEHDR));
00469     }
00470 
00471     waveInAddBuffer(waveIn, waveInHdr + (recordBufferCount + 1) % 3, sizeof(WAVEHDR));  //繼續錄音
00472   }
00473 }
00474 
00475 void TWavePlayer::PlayABuffer(void)
00476 {
00477   WAVEHDR *waveHdr;
00478   int i, *ip3, vol;
00479   short *sp1, *sp2, *sp3;
00480   unsigned char *ucp1, *ucp2, *ucp3;
00481 
00482   ++playBufferCount;  //已經播完的buffer數目
00483   if (playBufferCount == bufferTotal && mode == PLAYING)  //播放完畢
00484   {
00485     PostMessage(HiddenWindow->Handle, WM_APP + 222, 0, 0);
00486     return;
00487   }
00488   if (mode == PLAYING)
00489     Deliver(EVENT_PLAY_BUFFER, wave + (playBufferCount - 1) * bufferSize);
00490 
00491   if (playBufferCount == bufferTotal - 1)  //即將播放完畢,只等最後一個buffer播放完畢
00492     return;
00493 
00494   waveHdr = waveOutHdr + (playBufferCount + 1) % 3;  //下次要播放的buffer
00495   if (echoOn)  //開啟迴音模式
00496   {
00497     if (bytesPerSample == 1)
00498     {
00499       ucp1 = (unsigned char *)waveHdr->lpData;  //下次要播放的buffer
00500       ucp2 = (unsigned char *)waveOutHdr[playBufferCount % 3].lpData;  //正在播放的buffer
00501       if (mode == RECORDING)  //錄音模式
00502       {
00503         ucp3 = (unsigned char *)waveInHdr[(firstEchoBufferIndex + playBufferCount) % 3].lpData;  //這次錄完的buffer,也就是這次要播的
00504         for (i = bufferSize - 1; i >= 0; i--)
00505         {
00506           vol = (ucp2[i] - 128) * echoVolume / 10 + ucp3[i];  //把正在播放和這次要播的混合在一起
00507           if (vol > 255)
00508             ucp1[i] = 255;
00509           else if (vol < 0)
00510             ucp1[i] = 0;
00511           else
00512             ucp1[i] = vol;
00513         }
00514       }
00515       else  //播放模式
00516       {
00517         ip3 = wave + (playBufferCount + 1) * bufferSize;  //這次要播的buffer
00518         for (i = bufferSize - 1; i >= 0; i--)
00519         {
00520           vol = (ucp2[i] - 128) * echoVolume / 10 + ip3[i] + 128;  //把這次播完和這次要播的混合在一起
00521           if (vol > 255)
00522             ucp1[i] = 255;
00523           else if (vol < 0)
00524             ucp1[i] = 0;
00525           else
00526             ucp1[i] = vol;
00527         }
00528       }
00529     }
00530     else
00531     {
00532       sp1 = (short *)waveHdr->lpData;  //下次要播放的buffer
00533       sp2 = (short *)waveOutHdr[playBufferCount % 3].lpData;  //正在播放的buffer
00534       if (mode == RECORDING)  //錄音模式
00535       {
00536         sp3 = (short *)waveInHdr[(firstEchoBufferIndex + playBufferCount) % 3].lpData;  //這次錄完的buffer,也就是這次要播的
00537         for (i = bufferSize - 1; i >= 0; i--)
00538         {
00539           vol = sp2[i] * echoVolume / 10 + sp3[i];  //把正在播放和這次要播的混合在一起
00540           if (vol > 32767)
00541             sp1[i] = 32767;
00542           else if (vol < -32768)
00543             sp1[i] = -32768;
00544           else
00545             sp1[i] = vol;
00546         }
00547       }
00548       else  //播放模式
00549       {
00550         ip3 = wave + playBufferCount * bufferSize;  //這次要播的buffer
00551         for (i = bufferSize - 1; i >= 0; i--)
00552         {
00553           vol = sp2[i] * echoVolume / 10 + ip3[i];  //把這次播完和這次要播的混合在一起
00554           if (vol > 32767)
00555             sp1[i] = 32767;
00556           else if (vol < -32768)
00557             sp1[i] = -32768;
00558           else
00559             sp1[i] = vol;
00560         }
00561       }
00562     }
00563     waveOutWrite(waveOut, waveHdr, sizeof(WAVEHDR));  //播放
00564   }
00565   else if (mode == PLAYING)  //沒有開啟迴音,播放模式
00566   {
00567     WaveCopy(waveHdr->lpData, wave + (playBufferCount + 1) * bufferSize, bufferSize);
00568     waveOutWrite(waveOut, waveHdr, sizeof(WAVEHDR));  //播放
00569   }
00570 }
00571 
00572 void TWavePlayer::RecordComplete(void)
00573 {
00574   StopRecord();
00575   Deliver(EVENT_RECORD_COMPLETE);  //送出錄音完畢的訊息
00576 }
00577 
00578 void TWavePlayer::PlayComplete(void)
00579 {
00580   StopPlay();
00581   Deliver(EVENT_PLAY_COMPLETE);  //送出播放完畢的訊息
00582 }
00583 

產生日期:Tue Jul 11 11:52:19 2006, 專案:cbmr, 產生器:  doxygen 1.4.7