home *** CD-ROM | disk | FTP | other *** search
/ Cubase Magazine 30 / Issue #30.iso / pc / 2-SOFTWARE / RTEQ 3.0 / SRC / SOUND.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  2000-12-06  |  12.3 KB  |  410 lines

  1. /**********************************************************************************
  2. *                                                                                 *
  3. *    SOUND.CPP: The interface to the sound device                                 *
  4. *                                                                                 *
  5. *    Copyright (C) 2000  Andrei Grecu                                             *
  6. *                                                                                 *
  7. *    This program is free software; you can redistribute it and/or modify         *
  8. *    it under the terms of the GNU General Public License as published by         *
  9. *    the Free Software Foundation; either version 2 of the License, or            *
  10. *    (at your option) any later version.                                          *
  11. *                                                                                 *
  12. *    This program is distributed in the hope that it will be useful,              *
  13. *    but WITHOUT ANY WARRANTY; without even the implied warranty of               *
  14. *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                *
  15. *    GNU General Public License for more details.                                 *
  16. *                                                                                 *
  17. *    You should have received a copy of the GNU General Public License            *
  18. *    along with this program; if not, write to the Free Software                  *
  19. *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA    *
  20. *                                                                                 *
  21. *    If you have questions, bug reports regarding my code please contact me at:   *
  22. *    andrei.grecu@aon.at                                                          *
  23. *                                                                                 *
  24. *    Home page:                                                                   *
  25. *    http://members.aon.at/grxpage/index.htm                                      *
  26. *                                                                                 *
  27. **********************************************************************************/
  28.  
  29. #include "precomp.h"
  30. #include <objbase.h>
  31. #include <initguid.h>
  32. #include <math.h>
  33. #include <dsound.h>
  34.  
  35. #include "misc.h"
  36.  
  37. typedef struct tagBUFFER {
  38.  
  39.     LPSHORT data;
  40.     LPVOID next;
  41.  
  42. } BUFFER;
  43.  
  44. typedef BUFFER *   LPBUFFER;
  45.  
  46. DWORD REC_FREQ = 44100;           // sample freqvency **can be changed**
  47.  
  48. DWORD REC_BASEBUFSIZE = 65536; // buffer size - must be a power of 2
  49.                                // *can be changed but be cautious
  50. BYTE REC_CHANNELS = 2;           // Number of channels to receive
  51.                                // Now, only 2 supported, but will 
  52.                                // become 255. 1 = MONO; 2 = STEREO
  53.  
  54. extern DWORD REC_PERIOD;
  55.  
  56. WORD bufCount;
  57. DWORD play_prevReadPos;
  58. DWORD capt_prevReadPos;
  59.  
  60. DWORD prevCtPos = 0, prevRdPos = 0;
  61.  
  62. LPDIRECTSOUND lpDS;
  63. LPDIRECTSOUNDBUFFER lpDSBuffer;  
  64.  
  65. LPDIRECTSOUNDCAPTURE lpDSC;
  66. LPDIRECTSOUNDCAPTUREBUFFER lpDSCBuffer;  
  67.  
  68. LPBUFFER SoundBuffer = NULL;
  69. LPBUFFER SoundBufferPointer = NULL;
  70.  
  71. // These Functions are not allowed to change pointers! CONST
  72. void DeInterlace(const LPSHORT src, const LPSHORT Ldest, const LPSHORT Rdest);
  73. void Interlace(const LPSHORT Lsrc, const LPSHORT Rsrc, const LPSHORT dest);
  74. BOOL CheckDX(HRESULT hr);
  75.  
  76. BOOL InitInputBuffer(void);
  77. BOOL InitOutputBuffer(void);
  78. void DestroyInputBuffer(void);
  79. void DestroyOutputBuffer(void);
  80. int RTEQMessageBox(DWORD message, UINT params);
  81.  
  82. HFILE LogFile;
  83.  
  84. void InitInput(void) {
  85.  
  86.   // Create the Sound Capture Object 
  87.   CheckDX(DirectSoundCaptureCreate(NULL, &lpDSC, NULL));
  88.  
  89.   InitInputBuffer();
  90.  
  91. }
  92.  
  93. BOOL InitInputBuffer(void) {
  94.  
  95.   DSCBUFFERDESC DSCBufferDesc;
  96.   WAVEFORMATEX wfmx;
  97.  
  98.   DestroyInputBuffer();
  99.  
  100.   wfmx.wFormatTag = WAVE_FORMAT_PCM;
  101.   wfmx.nChannels = REC_CHANNELS;  
  102.   wfmx.nSamplesPerSec = REC_FREQ;
  103.   wfmx.nAvgBytesPerSec = REC_CHANNELS * (16 / 8) * REC_FREQ;
  104.   wfmx.nBlockAlign = REC_CHANNELS * (16 / 8);
  105.   wfmx.wBitsPerSample = 16;
  106.   wfmx.cbSize = NULL;
  107.  
  108.   DSCBufferDesc.dwSize = sizeof(DSCBUFFERDESC);
  109.   DSCBufferDesc.dwFlags = NULL;
  110.   DSCBufferDesc.dwBufferBytes = REC_BASEBUFSIZE * 2 * 2;
  111.   DSCBufferDesc.dwReserved = NULL;
  112.   DSCBufferDesc.lpwfxFormat = &wfmx;
  113.  
  114.   // Create the buffer to the object
  115.   if(!CheckDX(lpDSC->CreateCaptureBuffer(&DSCBufferDesc, &lpDSCBuffer, NULL))) { lpDSCBuffer = NULL; return FALSE; }
  116.  
  117.   // Start capturing: at the end of the buffer the capture pointer will wrap around
  118.   lpDSCBuffer->Start(DSCBSTART_LOOPING);
  119.   capt_prevReadPos = REC_BASEBUFSIZE * 2;
  120.  
  121.   prevCtPos = 0; prevRdPos = 0;
  122.  
  123.   return TRUE;
  124.  
  125. }
  126.  
  127. BOOL Input(const LPSHORT Lbuf, const LPSHORT Rbuf) {
  128.  
  129.   DWORD CapturePos, ReadPos, i;
  130.   LPSHORT iBuf;
  131.  
  132.   if(!lpDSCBuffer) return FALSE;
  133.  
  134.   CheckDX(lpDSCBuffer->GetCurrentPosition(&CapturePos, &ReadPos));
  135.  
  136.   // Without these lines, a very interesting bug occurs
  137.   if(prevCtPos == CapturePos && prevRdPos == ReadPos) {
  138.         lpDSCBuffer->Stop();
  139.         lpDSCBuffer->Start(DSCBSTART_LOOPING);
  140.   }
  141.   prevCtPos = CapturePos;
  142.   prevRdPos = ReadPos;
  143.   // Check if there is enough data into the capture buffer to read
  144.   if((ReadPos > capt_prevReadPos + REC_PERIOD * 2 * REC_CHANNELS) || (ReadPos < capt_prevReadPos)) {
  145.   
  146.     lpDSCBuffer->Lock(capt_prevReadPos, REC_PERIOD * 2, (LPVOID *) &iBuf, &i, NULL, NULL, NULL);
  147.     if(REC_CHANNELS == 2) {
  148.         // If there are 2 channels they must be deinterlaced (121212 -> 111, 222)
  149.         DeInterlace(iBuf, Lbuf, Rbuf);
  150.     }
  151.     else {
  152.         CopyMemory(Lbuf, iBuf, REC_PERIOD * 2);
  153.     }
  154.     lpDSCBuffer->Unlock(iBuf, REC_PERIOD * 2, NULL, NULL);
  155.     // Store the position of the read pointer
  156.     capt_prevReadPos += REC_PERIOD * 2 * REC_CHANNELS; 
  157.     capt_prevReadPos %= REC_BASEBUFSIZE * 2 * 2;
  158.  
  159.     return(1);
  160.   }
  161.   else return(0);
  162. }
  163.  
  164. void DeInterlace(const LPSHORT src, const LPSHORT Ldest, const LPSHORT Rdest) {
  165.  
  166.     DWORD i;
  167.  
  168.     for(i = 0; i < REC_PERIOD; i++) {
  169.         Ldest[i] = src[2 * i];
  170.         Rdest[i] = src[2 * i + 1];
  171.     }
  172.  
  173. }
  174.  
  175. void DestroyInput(void) {
  176.  
  177.   // Destroy the Sound Capture Object
  178.     DestroyInputBuffer();
  179.     if(lpDSC) {
  180.         lpDSC->Release();
  181.         lpDSC = NULL;
  182.     }
  183.  
  184.     _lclose(LogFile);
  185.  
  186. }
  187.  
  188. void DestroyInputBuffer(void) {
  189.  
  190.     if(lpDSCBuffer) {
  191.         lpDSCBuffer->Stop();
  192.         lpDSCBuffer->Release();
  193.         lpDSCBuffer = NULL;
  194.     }
  195.  
  196. }
  197.  
  198. void InitOutput(HWND hwnd) {
  199.  
  200.   // Create Sound Object
  201.   CheckDX(DirectSoundCreate(NULL, &lpDS, NULL));
  202.   CheckDX(lpDS->SetCooperativeLevel(hwnd, DSSCL_NORMAL));
  203.   
  204.   // Create the buffer to the sound object
  205.   if(InitOutputBuffer() != TRUE) {
  206.       DWORD sREC_FREQ = REC_FREQ;
  207.       BOOL success = FALSE;
  208.  
  209.       if(!success) {
  210.           REC_FREQ = 22050; 
  211.           if(InitInputBuffer() == TRUE && InitOutputBuffer() == TRUE) success = TRUE;
  212.       }
  213.       if(!success) {
  214.           REC_FREQ = 11025; 
  215.           if(InitInputBuffer() == TRUE && InitOutputBuffer() == TRUE) success = TRUE;
  216.       }
  217.       if(!success) {
  218.           REC_FREQ = 8000; 
  219.           if(InitInputBuffer() == TRUE && InitOutputBuffer() == TRUE) success = TRUE;
  220.       }
  221.       if(!success) {
  222.           REC_FREQ = 44100; 
  223.           if(InitInputBuffer() == TRUE && InitOutputBuffer() == TRUE) success = TRUE;
  224.       }
  225.       if(!success) {
  226.           REC_FREQ = 48000; 
  227.           if(InitInputBuffer() == TRUE && InitOutputBuffer() == TRUE) success = TRUE;
  228.       }
  229.       if(!success) {
  230.           RTEQMessageBox(IDS_DXERR_GENERIC, MB_OK | MB_ICONEXCLAMATION);
  231.           REC_FREQ = sREC_FREQ;
  232.           return;
  233.       }
  234.  
  235.   }
  236. /**/
  237.   lpDSBuffer->Play(NULL, NULL, DSBPLAY_LOOPING);
  238. /**/
  239.   bufCount = 0;
  240.   DWORD play_prevReadPos = 0;
  241.  
  242. }
  243.  
  244. BOOL InitOutputBuffer(void) {
  245.  
  246.   DSBUFFERDESC DSBufferDesc;
  247.   WAVEFORMATEX wfmx;
  248.  
  249.   wfmx.wFormatTag = WAVE_FORMAT_PCM;
  250.   wfmx.nChannels = REC_CHANNELS; 
  251.   wfmx.nSamplesPerSec = REC_FREQ;
  252.   wfmx.nAvgBytesPerSec = REC_CHANNELS * (16 / 8) * REC_FREQ;
  253.   wfmx.nBlockAlign = REC_CHANNELS * (16 / 8);
  254.   wfmx.wBitsPerSample = 16;
  255.   wfmx.cbSize = NULL;
  256.  
  257.   DSBufferDesc.dwSize = sizeof(DSBUFFERDESC);
  258.   DSBufferDesc.dwFlags = DSBCAPS_GLOBALFOCUS | DSBCAPS_STATIC;
  259.   DSBufferDesc.dwBufferBytes = REC_BASEBUFSIZE * 2 * 2;
  260.   DSBufferDesc.dwReserved = NULL;
  261.   DSBufferDesc.lpwfxFormat = &wfmx;
  262.  
  263.   // Create the buffer to the sound object
  264.   if(!CheckDX(lpDS->CreateSoundBuffer(&DSBufferDesc, &lpDSBuffer, NULL))) { lpDSBuffer = NULL; return FALSE; }
  265.   play_prevReadPos = 0;
  266.   SoundBufferPointer = NULL;
  267.  
  268.   return TRUE;
  269.  
  270. }
  271.  
  272. BOOL Output(const LPSHORT Lbuf, const LPSHORT Rbuf) {
  273.  
  274.   DWORD i, WritePos, PlayPos;
  275.   short int *iBuf;
  276.  
  277.   if(!lpDSBuffer) return FALSE;
  278.  
  279.   CheckDX(lpDSBuffer->GetCurrentPosition(&PlayPos, &WritePos));
  280.  
  281.   if(Lbuf != NULL) {
  282.  
  283.         LPBUFFER tSoundBuffer = (LPBUFFER) GlobalAlloc(GPTR, sizeof(BUFFER));
  284.         tSoundBuffer->data = (LPSHORT) GlobalAlloc(GPTR, REC_PERIOD * 2 * REC_CHANNELS);
  285.         tSoundBuffer->next = NULL;
  286.  
  287.         if(REC_CHANNELS == 2) {
  288.               // If there are 2 channels they must be interlaced before playing (111, 222 -> 121212)
  289.             Interlace(Lbuf, Rbuf, tSoundBuffer->data);
  290.         }
  291.         else {
  292.             CopyMemory(tSoundBuffer->data, Lbuf, REC_PERIOD * 2);
  293.         }
  294.  
  295.         if(SoundBufferPointer) {
  296.             SoundBufferPointer->next = tSoundBuffer;
  297.             SoundBufferPointer = tSoundBuffer;
  298.         }
  299.         else {
  300.             SoundBufferPointer = tSoundBuffer;
  301.             SoundBuffer           = tSoundBuffer;
  302.         }
  303.   }
  304.  
  305.  
  306.   // If DirectSound reads on the position where we want to write then go back two steps
  307.   if((PlayPos < play_prevReadPos + REC_PERIOD * 2 * REC_CHANNELS) && (PlayPos > play_prevReadPos)) {
  308.     /*play_prevReadPos -= REC_PERIOD * REC_CHANNELS * 2 /* twice a block --> * * 2;
  309.     play_prevReadPos %= REC_BASEBUFSIZE * 2 * 2;*/
  310.       return(FALSE);
  311.   }
  312.  
  313.   lpDSBuffer->Lock(play_prevReadPos, REC_PERIOD * REC_CHANNELS * 2, (LPVOID *) &iBuf, &i, NULL, NULL, NULL);
  314. /*  if(REC_CHANNELS == 2) {
  315.         // If there are 2 channels they must be interlaced before playing (111, 222 -> 121212)
  316.       Interlace(Lbuf, Rbuf, iBuf);
  317.   }
  318.   else {
  319.       CopyMemory(iBuf, Lbuf, REC_PERIOD * 2);
  320.   }*/
  321.   if(SoundBuffer != NULL && iBuf) {
  322.  
  323.         CopyMemory(iBuf, SoundBuffer->data, REC_PERIOD * 2 * REC_CHANNELS);
  324.         GlobalFree(SoundBuffer->data);
  325.         
  326.         LPBUFFER tSoundBuffer;
  327.         tSoundBuffer = SoundBuffer;
  328.  
  329.         if(SoundBuffer->next != NULL) SoundBuffer = (LPBUFFER) SoundBuffer->next;
  330.         else {
  331.             SoundBuffer = NULL;
  332.             SoundBufferPointer = NULL;
  333.         }
  334.  
  335.         GlobalFree(tSoundBuffer);
  336.  
  337.   }
  338.   else {
  339.       lpDSBuffer->Unlock(iBuf, REC_PERIOD * REC_CHANNELS * 2, NULL, NULL);
  340.       return(FALSE);
  341.   }
  342.   lpDSBuffer->Unlock(iBuf, REC_PERIOD * REC_CHANNELS * 2, NULL, NULL);
  343.  
  344.   // Store the position of the play pointer
  345.   play_prevReadPos += REC_PERIOD * REC_CHANNELS * 2;
  346.   play_prevReadPos %= REC_BASEBUFSIZE * 2 * 2;
  347.   // If there is enough data stored into the buffer then start playing
  348. /*  if(bufCount == REC_BASEBUFSIZE / (REC_PERIOD * REC_CHANNELS * 2)) lpDSBuffer->Play(NULL, NULL, DSBPLAY_LOOPING);
  349.   if(bufCount <= REC_BASEBUFSIZE / (REC_PERIOD * REC_CHANNELS * 2)) bufCount++;*/
  350.   return(TRUE);
  351.  
  352. }
  353.  
  354. void Interlace(const LPSHORT Lsrc, const LPSHORT Rsrc, const LPSHORT dest) {
  355.  
  356.     DWORD i;
  357.  
  358.     for(i = 0; i < REC_PERIOD; i++) {
  359.         dest[2 * i] = Lsrc[i];
  360.         dest[2 * i + 1] = Rsrc[i];
  361.     }
  362.  
  363. }
  364.  
  365. void DestroyOutput(void) {
  366.  
  367.   // Destroy the Sound Object
  368.     if(lpDSBuffer) {
  369.         lpDSBuffer->Stop();
  370.     }
  371.     if(lpDS) {
  372.         lpDS->Release();
  373.         lpDSBuffer = NULL;
  374.         lpDS = NULL;
  375.     }
  376.  
  377. }
  378.  
  379. BOOL CheckDX(HRESULT hr) {
  380.  
  381.     switch(hr) {
  382.         case DS_OK:                    return TRUE;
  383.         case DSERR_ALLOCATED:        RTEQMessageBox(IDS_DXERR_ALLOCATED,    MB_OK | MB_ICONSTOP); exit(1);
  384.         case DSERR_NODRIVER:        RTEQMessageBox(IDS_DXERR_NODRIVER,     MB_OK | MB_ICONSTOP); exit(1);
  385.         case DSERR_OUTOFMEMORY:        MessageBox(NULL, "Not enough memory to start DirectX, cannot continue.", "RTEQ - Real Time Equalizer", MB_OK | MB_ICONSTOP); exit(1);
  386.         case DSERR_BADFORMAT:        return FALSE;
  387.         case DSERR_GENERIC:            RTEQMessageBox(IDS_DXERR_GENERIC,      MB_OK | MB_ICONSTOP); exit(1);
  388.         case DSERR_UNSUPPORTED:        RTEQMessageBox(IDS_DXERR_UNSUPPORTED,  MB_OK | MB_ICONSTOP); exit(1);
  389.  
  390.         case DSERR_INVALIDPARAM:
  391.         case DSERR_NOAGGREGATION:    
  392.         default:                    RTEQMessageBox(IDS_DXERR_UNDOCUMENTED, MB_OK | MB_ICONSTOP); exit(1);
  393.     }
  394.  
  395.     return FALSE;
  396. }
  397.  
  398. extern HINSTANCE hInst;
  399.  
  400. int RTEQMessageBox(DWORD message, UINT params) {
  401.  
  402.     char titleStr[1024];
  403.     char messageStr[1024];
  404.  
  405.     LoadString(hInst, IDS_APP_TITLE, titleStr, 1024);
  406.     LoadString(hInst, message, messageStr, 1024);
  407.  
  408.     return(MessageBox(NULL, messageStr, titleStr, params));
  409.  
  410. }