home *** CD-ROM | disk | FTP | other *** search
/ Chip 2004 July / CMCD0704.ISO / Software / Freeware / Utilitare / VisualBoyAdvance-1.7.2 / src / win32 / DirectSound.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2004-05-13  |  9.6 KB  |  374 lines

  1. // VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator.
  2. // Copyright (C) 1999-2003 Forgotten
  3. // Copyright (C) 2004 Forgotten and the VBA development team
  4.  
  5. // This program is free software; you can redistribute it and/or modify
  6. // it under the terms of the GNU General Public License as published by
  7. // the Free Software Foundation; either version 2, or(at your option)
  8. // any later version.
  9. //
  10. // This program is distributed in the hope that it will be useful,
  11. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. // GNU General Public License for more details.
  14. //
  15. // You should have received a copy of the GNU General Public License
  16. // along with this program; if not, write to the Free Software Foundation,
  17. // Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  18.  
  19. #include "stdafx.h"
  20. #include "VBA.h"
  21. #include "AVIWrite.h"
  22. #include "Sound.h"
  23. #include "WavWriter.h"
  24.  
  25. #include "../System.h"
  26. #include "../GBA.h"
  27. #include "../Globals.h"
  28. #include "../Sound.h"
  29.  
  30. #include <mmreg.h>
  31. #include <dsound.h>
  32.  
  33. class DirectSound : public ISound
  34. {
  35. private:
  36.   HINSTANCE            dsoundDLL;
  37.   LPDIRECTSOUND        pDirectSound;
  38.   LPDIRECTSOUNDBUFFER  dsbPrimary;
  39.   LPDIRECTSOUNDBUFFER  dsbSecondary;
  40.   LPDIRECTSOUNDNOTIFY  dsbNotify;
  41.   HANDLE               dsbEvent;
  42.   WAVEFORMATEX         wfx;
  43.  
  44. public:
  45.   DirectSound();
  46.   virtual ~DirectSound();
  47.  
  48.   bool init();
  49.   void pause();
  50.   void reset();
  51.   void resume();
  52.   void write();
  53. };
  54.  
  55. DirectSound::DirectSound()
  56. {
  57.   dsoundDLL    = NULL;
  58.   pDirectSound = NULL;
  59.   dsbPrimary   = NULL;
  60.   dsbSecondary = NULL;
  61.   dsbNotify    = NULL;
  62.   dsbEvent     = NULL;
  63. }
  64.  
  65. DirectSound::~DirectSound()
  66. {
  67.   if(theApp.aviRecorder != NULL) {
  68.     delete theApp.aviRecorder;
  69.     theApp.aviRecorder = NULL;
  70.     theApp.aviFrameNumber = 0;
  71.   }
  72.  
  73.   if(theApp.soundRecording) {
  74.     if(theApp.soundRecorder != NULL) {
  75.       delete theApp.soundRecorder;
  76.       theApp.soundRecorder = NULL;
  77.     }
  78.     theApp.soundRecording = false;
  79.   }
  80.   
  81.   if(dsbNotify != NULL) {
  82.     dsbNotify->Release();
  83.     dsbNotify = NULL;
  84.   }
  85.  
  86.   if(dsbEvent != NULL) {
  87.     CloseHandle(dsbEvent);
  88.     dsbEvent = NULL;
  89.   }
  90.   
  91.   if(pDirectSound != NULL) {
  92.     if(dsbPrimary != NULL) {
  93.       dsbPrimary->Release();
  94.       dsbPrimary = NULL;
  95.     }
  96.     
  97.     if(dsbSecondary != NULL) {
  98.       dsbSecondary->Release();
  99.       dsbSecondary = NULL;
  100.     }
  101.     
  102.     pDirectSound->Release();
  103.     pDirectSound = NULL;
  104.   }
  105.   
  106.   if(dsoundDLL != NULL) {
  107.     FreeLibrary(dsoundDLL);
  108.     dsoundDLL = NULL;
  109.   }
  110. }
  111.  
  112. bool DirectSound::init()
  113. {
  114.   HRESULT hr;
  115.  
  116.   dsoundDLL = LoadLibrary("DSOUND.DLL");
  117.   HRESULT (WINAPI *DSoundCreate)(LPCGUID,LPDIRECTSOUND *,IUnknown *);  
  118.   if(dsoundDLL != NULL) {    
  119.     DSoundCreate = (HRESULT (WINAPI *)(LPCGUID,LPDIRECTSOUND *,IUnknown *))
  120.       GetProcAddress(dsoundDLL, "DirectSoundCreate");
  121.     
  122.     if(DSoundCreate == NULL) {
  123.       theApp.directXMessage("DirectSoundCreate");
  124.       return false;
  125.     }
  126.   } else {
  127.     theApp.directXMessage("DSOUND.DLL");
  128.     return false;
  129.   }
  130.   
  131.   if((hr = DSoundCreate(NULL,&pDirectSound,NULL) != DS_OK)) {
  132.     //    errorMessage(myLoadString(IDS_ERROR_SOUND_CREATE), hr);
  133.     systemMessage(IDS_CANNOT_CREATE_DIRECTSOUND,
  134.                   "Cannot create DirectSound %08x", hr);
  135.     pDirectSound = NULL;
  136.     dsbSecondary = NULL;
  137.     return false;
  138.   }
  139.  
  140.   if((hr=pDirectSound->SetCooperativeLevel((HWND)*theApp.m_pMainWnd,
  141.                                            DSSCL_EXCLUSIVE)) != DS_OK) {
  142.     //    errorMessage(myLoadString(IDS_ERROR_SOUND_LEVEL), hr);
  143.     systemMessage(IDS_CANNOT_SETCOOPERATIVELEVEL,
  144.                   "Cannot SetCooperativeLevel %08x", hr);
  145.     return false;
  146.   }
  147.  
  148.   DSBUFFERDESC dsbdesc;
  149.   ZeroMemory(&dsbdesc,sizeof(DSBUFFERDESC));
  150.   dsbdesc.dwSize=sizeof(DSBUFFERDESC);
  151.   dsbdesc.dwFlags = DSBCAPS_PRIMARYBUFFER;
  152.   
  153.   if((hr=pDirectSound->CreateSoundBuffer(&dsbdesc,
  154.                                          &dsbPrimary,
  155.                                          NULL) != DS_OK)) {
  156.     //    errorMessage(myLoadString(IDS_ERROR_SOUND_BUFFER),hr);
  157.     systemMessage(IDS_CANNOT_CREATESOUNDBUFFER,
  158.                   "Cannot CreateSoundBuffer %08x", hr);
  159.     return false;
  160.   }
  161.   
  162.   // Set primary buffer format
  163.  
  164.   memset(&wfx, 0, sizeof(WAVEFORMATEX)); 
  165.   wfx.wFormatTag = WAVE_FORMAT_PCM; 
  166.   wfx.nChannels = 2;
  167.   switch(soundQuality) {
  168.   case 2:
  169.     wfx.nSamplesPerSec = 22050;
  170.     soundBufferLen = 736*2;
  171.     soundBufferTotalLen = 7360*2;
  172.     break;
  173.   case 4:
  174.     wfx.nSamplesPerSec = 11025;
  175.     soundBufferLen = 368*2;
  176.     soundBufferTotalLen = 3680*2;
  177.     break;
  178.   default:
  179.     soundQuality = 1;
  180.     wfx.nSamplesPerSec = 44100;
  181.     soundBufferLen = 1470*2;
  182.     soundBufferTotalLen = 14700*2;
  183.   }
  184.   wfx.wBitsPerSample = 16; 
  185.   wfx.nBlockAlign = (wfx.wBitsPerSample / 8) * wfx.nChannels;
  186.   wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
  187.  
  188.   if((hr = dsbPrimary->SetFormat(&wfx)) != DS_OK) {
  189.     //    errorMessage(myLoadString(IDS_ERROR_SOUND_PRIMARY),hr);
  190.     systemMessage(IDS_CANNOT_SETFORMAT_PRIMARY,
  191.                   "Cannot SetFormat for primary %08x", hr);
  192.     return false;
  193.   }
  194.   
  195.   ZeroMemory(&dsbdesc,sizeof(DSBUFFERDESC));  
  196.   dsbdesc.dwSize = sizeof(DSBUFFERDESC);
  197.   dsbdesc.dwFlags = DSBCAPS_GETCURRENTPOSITION2|DSBCAPS_CTRLPOSITIONNOTIFY;
  198.   dsbdesc.dwBufferBytes = soundBufferTotalLen;
  199.   dsbdesc.lpwfxFormat = &wfx;
  200.  
  201.   if((hr = pDirectSound->CreateSoundBuffer(&dsbdesc, &dsbSecondary, NULL))
  202.      != DS_OK) {
  203.     dsbdesc.dwFlags = DSBCAPS_GETCURRENTPOSITION2;
  204.     if((hr = pDirectSound->CreateSoundBuffer(&dsbdesc, &dsbSecondary, NULL))
  205.        != DS_OK) {
  206.       systemMessage(IDS_CANNOT_CREATESOUNDBUFFER_SEC,
  207.                     "Cannot CreateSoundBuffer secondary %08x", hr);
  208.       return false;
  209.     }
  210.   }
  211.  
  212.   dsbSecondary->SetCurrentPosition(0);
  213.  
  214.   if(!theApp.useOldSync) {
  215.     hr = dsbSecondary->QueryInterface(IID_IDirectSoundNotify,
  216.                                       (void **)&dsbNotify);
  217.     if(!FAILED(hr)) {
  218.       dsbEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  219.       
  220.       DSBPOSITIONNOTIFY notify[10];
  221.       
  222.       for(int i = 0; i < 10; i++) {
  223.         notify[i].dwOffset = i*soundBufferLen;
  224.         notify[i].hEventNotify = dsbEvent;
  225.       }
  226.       if(FAILED(dsbNotify->SetNotificationPositions(10, notify))) {
  227.         dsbNotify->Release();
  228.         dsbNotify = NULL;
  229.         CloseHandle(dsbEvent);
  230.         dsbEvent = NULL;
  231.       }
  232.     }
  233.   }
  234.   
  235.   hr = dsbPrimary->Play(0,0,DSBPLAY_LOOPING);
  236.  
  237.   if(hr != DS_OK) {
  238.     //    errorMessage(myLoadString(IDS_ERROR_SOUND_PLAYPRIM), hr);
  239.     systemMessage(IDS_CANNOT_PLAY_PRIMARY, "Cannot Play primary %08x", hr);
  240.     return false;
  241.   }
  242.  
  243.   systemSoundOn = true;
  244.   
  245.   return true;
  246. }
  247.  
  248. void DirectSound::pause()
  249. {
  250.   if(dsbSecondary != NULL) {
  251.     DWORD status = 0;
  252.     dsbSecondary->GetStatus(&status);
  253.     
  254.     if(status & DSBSTATUS_PLAYING) {
  255.       dsbSecondary->Stop();
  256.     }
  257.   }  
  258. }
  259.  
  260. void DirectSound::reset()
  261. {
  262.   if(dsbSecondary) {
  263.     dsbSecondary->Stop();
  264.     dsbSecondary->SetCurrentPosition(0);
  265.   }  
  266. }
  267.  
  268. void DirectSound::resume()
  269. {
  270.   if(dsbSecondary != NULL) {
  271.     dsbSecondary->Play(0,0,DSBPLAY_LOOPING);
  272.   }  
  273. }
  274.  
  275. void DirectSound::write()
  276. {
  277.   int len = soundBufferLen;
  278.   LPVOID  lpvPtr1; 
  279.   DWORD   dwBytes1; 
  280.   LPVOID  lpvPtr2; 
  281.   DWORD   dwBytes2; 
  282.  
  283.   if(!pDirectSound)
  284.     return;
  285.  
  286.   if(theApp.soundRecording) {
  287.     if(dsbSecondary) {
  288.       if(theApp.soundRecorder == NULL) {
  289.         theApp.soundRecorder = new WavWriter;
  290.         WAVEFORMATEX format;
  291.         dsbSecondary->GetFormat(&format, sizeof(format), NULL);
  292.         if(theApp.soundRecorder->Open(theApp.soundRecordName))
  293.           theApp.soundRecorder->SetFormat(&format);
  294.       }
  295.     }
  296.       
  297.     if(theApp.soundRecorder) {
  298.       theApp.soundRecorder->AddSound((u8 *)soundFinalWave, len);
  299.     }
  300.   }
  301.  
  302.   if(theApp.aviRecording) {
  303.     if(theApp.aviRecorder) {
  304.       if(dsbSecondary) {
  305.         if(!theApp.aviRecorder->IsSoundAdded()) {
  306.           WAVEFORMATEX format;
  307.           dsbSecondary->GetFormat(&format, sizeof(format), NULL);
  308.           theApp.aviRecorder->SetSoundFormat(&format);
  309.         }
  310.       }
  311.       
  312.       theApp.aviRecorder->AddSound((const char *)soundFinalWave, len);
  313.     }
  314.   }
  315.   
  316.   HRESULT hr;
  317.  
  318.   if(!speedup && synchronize && !theApp.throttle) {
  319.     DWORD status=0;
  320.     hr = dsbSecondary->GetStatus(&status);
  321.     if(status && DSBSTATUS_PLAYING) {
  322.       if(!soundPaused) {      
  323.         DWORD play;
  324.         while(true) {
  325.           dsbSecondary->GetCurrentPosition(&play, NULL);
  326.  
  327.           if(play < soundNextPosition ||
  328.              play > soundNextPosition+soundBufferLen) {
  329.             break;
  330.           }
  331.  
  332.           if(dsbEvent) {
  333.             WaitForSingleObject(dsbEvent, 50);
  334.           }
  335.         }
  336.       }
  337.     } else {
  338.       soundPaused = 1;
  339.     }
  340.   }
  341.   // Obtain memory address of write block. This will be in two parts
  342.   // if the block wraps around.
  343.   hr = dsbSecondary->Lock(soundNextPosition, soundBufferLen, &lpvPtr1, 
  344.                           &dwBytes1, &lpvPtr2, &dwBytes2,
  345.                           0);
  346.   
  347.   // If DSERR_BUFFERLOST is returned, restore and retry lock. 
  348.   if (DSERR_BUFFERLOST == hr) { 
  349.     dsbSecondary->Restore(); 
  350.     hr = dsbSecondary->Lock(soundNextPosition, soundBufferLen,&lpvPtr1,
  351.                             &dwBytes1, &lpvPtr2, &dwBytes2,
  352.                             0);
  353.   } 
  354.  
  355.   soundNextPosition += soundBufferLen;
  356.   soundNextPosition = soundNextPosition % soundBufferTotalLen;
  357.   
  358.   if SUCCEEDED(hr) { 
  359.     // Write to pointers. 
  360.     CopyMemory(lpvPtr1, soundFinalWave, dwBytes1); 
  361.     if (NULL != lpvPtr2) { 
  362.       CopyMemory(lpvPtr2, soundFinalWave+dwBytes1, dwBytes2); 
  363.     } 
  364.     // Release the data back to DirectSound. 
  365.     hr = dsbSecondary->Unlock(lpvPtr1, dwBytes1, lpvPtr2, 
  366.                               dwBytes2);
  367.   }
  368. }
  369.  
  370. ISound *newDirectSound()
  371. {
  372.   return new DirectSound();
  373. }
  374.