Sound.cpp
上传用户:luhy168
上传日期:2022-01-10
资源大小:240k
文件大小:17k
源码类别:

模拟服务器

开发平台:

Visual C++

  1. //------------------------------------------------------------------------------
  2. // Name: Sound.cpp
  3. // Desc: Holds all the functions that have to do with sound.
  4. //------------------------------------------------------------------------------
  5. #include "Sound.h"
  6. // Length table lookup table...sounds wierd.
  7. static const BYTE abyLengthTable[32] =
  8. {
  9. 0x05, 0x7F, 0x0A, 0x01, 0x13, 0x02, 0x28, 0x03,
  10. 0x50, 0x04, 0x1E, 0x05, 0x07, 0x06, 0x0D, 0x07,
  11. 0x06, 0x08, 0x0C, 0x09, 0x18, 0x0A, 0x30, 0x0B,
  12. 0x60, 0x0C, 0x24, 0x0D, 0x08, 0x0E, 0x10, 0x0F
  13. };
  14. static const BYTE abyDutyCycleTablePos[4] = { 2,  4,  8, 12};
  15. static const BYTE abyDutyCycleTableNeg[4] = {14, 12,  8,  4};
  16. //------------------------------------------------------------------------------
  17. // Global variables for this file.
  18. //------------------------------------------------------------------------------
  19. //CSound*        pcsndSquare1 = NULL; // Buffer for square channel 1.
  20. //CSoundManager* pcsndmanMain = NULL; // Main sound manager for our program.
  21. //LPSTR          strSquareWaveFile = "square1000hz44100.wav";
  22. NESAPU         APU;                 // Apu strucure.
  23. BOOL bCalculateSound = FALSE; // Tells the sound functions to use new or old data.
  24. DWORD dwNumCyclesPerSample = CPU_FREQUENCY / OPTIONS_NUM_SAMPLESPERSEC;
  25. // DirectSound stuff.
  26. LPDIRECTSOUND       lpDS           = NULL;
  27. LPDIRECTSOUNDBUFFER lpdsbSoundBuf = NULL;
  28. DWORD               dwMidSoundBuf = 0;
  29. //------------------------------------------------------------------------------
  30. // Name: CreateSound()
  31. // Desc: Creates DirectSound and sets the format of the primary buffer. Next
  32. //       it creates all the secondary buffers we need for streaming.
  33. //------------------------------------------------------------------------------
  34. BOOL CreateSound(HWND hwnd)
  35. {
  36. HRESULT hr;
  37. LPDIRECTSOUNDBUFFER lpdsbPrimary;
  38. DSBUFFERDESC dsbdesc;
  39. WAVEFORMATEX wfm;
  40. // Create DirectSound.
  41. if (FAILED(DirectSoundCreate(NULL, &lpDS, NULL)))
  42. return FALSE;
  43. // Set the cooperative level.
  44. if (FAILED(lpDS->SetCooperativeLevel(hwnd, DSSCL_PRIORITY)))
  45. return FALSE;
  46. // Set up the DSBUFFERDESC structure.
  47. memset(&dsbdesc, 0, sizeof(DSBUFFERDESC));
  48. dsbdesc.dwSize = sizeof(DSBUFFERDESC);
  49. dsbdesc.dwFlags = DSBCAPS_PRIMARYBUFFER;
  50. dsbdesc.dwBufferBytes = 0;
  51. dsbdesc.lpwfxFormat = NULL;
  52. // Set up strucure for the desired sound format.
  53. memset(&wfm, 0, sizeof(WAVEFORMATEX));
  54. wfm.wFormatTag = WAVE_FORMAT_PCM;
  55. wfm.nChannels = OPTIONS_NUM_CHANNELS;
  56. wfm.nSamplesPerSec = OPTIONS_NUM_SAMPLESPERSEC;
  57. wfm.wBitsPerSample = OPTIONS_NUM_BITSPERSAMPLE;
  58. wfm.nBlockAlign = (wfm.wBitsPerSample / 8) * wfm.nChannels;
  59. wfm.nAvgBytesPerSec = wfm.nSamplesPerSec * wfm.nBlockAlign;
  60. // Gain access to the primary buffer.
  61. hr = lpDS->CreateSoundBuffer(&dsbdesc, &lpdsbPrimary, NULL);
  62. // Set the primary buffer to the desired format. If this fails,
  63. // we will just ignore it and go with the default format.
  64. if (SUCCEEDED(hr))
  65. hr = lpdsbPrimary->SetFormat(&wfm);
  66. // Create the secondary streaming buffers.
  67. CreateStreamingSoundBuffer(lpdsbSoundBuf, &dwMidSoundBuf);
  68. return TRUE;
  69. } // end CreateDirectSound()
  70. //------------------------------------------------------------------------------
  71. // Name: DestroySound()
  72. // Desc: Shuts down DirectSound, this releases the secondary buffers as well.
  73. //------------------------------------------------------------------------------
  74. VOID DestroySound()
  75. {
  76. // Stop playing the buffer first.
  77. lpdsbSoundBuf->Stop();
  78. // Now release DirectSound.
  79. if (lpDS != NULL)
  80. {
  81. lpDS->Release();
  82. lpDS = NULL;
  83. }
  84. } // end DestroyDirectSound();
  85. //------------------------------------------------------------------------------
  86. // Name: FillBufferWithSilence()
  87. // Desc: Does exactly what is says. For 8-bit waves 0x80 is silent, for 
  88. //       16-bit wave files 0 is silence.
  89. //------------------------------------------------------------------------------
  90. BOOL FillBufferWithSilence(LPDIRECTSOUNDBUFFER& lpdsbSound)
  91. {
  92. WAVEFORMATEX    wfx;
  93. DWORD           dwSizeWritten;
  94. PBYTE   pb1;
  95. DWORD   cb1;
  96. if (FAILED(lpdsbSound->GetFormat(&wfx, sizeof(WAVEFORMATEX), &dwSizeWritten)))
  97. return FALSE;
  98. if (SUCCEEDED(lpdsbSound->Lock(0, 0, (LPVOID*)&pb1, &cb1, NULL, NULL, DSBLOCK_ENTIREBUFFER)))
  99. {
  100. FillMemory(pb1, cb1, (wfx.wBitsPerSample == 8) ? 128 : 0);
  101. lpdsbSound->Unlock(pb1, cb1, NULL, 0);
  102. return TRUE;
  103. }
  104. return FALSE;
  105. } // end FillBufferWithSilence()
  106. //------------------------------------------------------------------------------
  107. // Name: CreateStreamingSoundBuffer()
  108. // Desc: Creates a secondary buffer for streaming and fills it with silence. 
  109. //       Also returns the halfway point for later use.
  110. //------------------------------------------------------------------------------
  111. BOOL CreateStreamingSoundBuffer(LPDIRECTSOUNDBUFFER& lpdsbSound, DWORD* dwMidBuffer)
  112. {
  113. HRESULT hr;
  114. DSBUFFERDESC dsbdesc;
  115. WAVEFORMATEX wfm;
  116. // Set up strucure for the desired sound format.
  117. memset(&wfm, 0, sizeof(WAVEFORMATEX));
  118. wfm.wFormatTag = WAVE_FORMAT_PCM;
  119. wfm.nChannels = OPTIONS_NUM_CHANNELS;
  120. wfm.nSamplesPerSec = OPTIONS_NUM_SAMPLESPERSEC;
  121. wfm.wBitsPerSample = OPTIONS_NUM_BITSPERSAMPLE;
  122. wfm.nBlockAlign = (wfm.wBitsPerSample / 8) * wfm.nChannels;
  123. wfm.nAvgBytesPerSec = wfm.nSamplesPerSec * wfm.nBlockAlign;
  124. // Set up the DSBUFFERDESC structure.
  125. memset(&dsbdesc, 0, sizeof(DSBUFFERDESC));
  126. dsbdesc.dwSize = sizeof(DSBUFFERDESC);
  127. dsbdesc.dwFlags = DSBCAPS_GETCURRENTPOSITION2;
  128. dsbdesc.dwBufferBytes = wfm.nAvgBytesPerSec * OPTIONS_NUM_SECONDSFORBUFFER;
  129. dsbdesc.lpwfxFormat = &wfm;
  130. // Create the secondary buffer.
  131. hr = lpDS->CreateSoundBuffer(&dsbdesc, &lpdsbSound, NULL);
  132. if (FAILED(hr))
  133. return FALSE;
  134. FillBufferWithSilence(lpdsbSound);
  135. // Start playing the buffer.
  136. lpdsbSound->Play(0, 0, DSBPLAY_LOOPING);
  137. // Save the middle of the buffer so we can write to either
  138. // half depending on which half of the buffer is playing.
  139. *dwMidBuffer = dsbdesc.dwBufferBytes / 2;
  140. // Success!!!!!
  141. return TRUE;
  142. } // end CreateStreamingSoundBuffer()
  143. //------------------------------------------------------------------------------
  144. // Name: APU_DoFrame()
  145. // Desc: Takes care of the sound for a frame.
  146. //------------------------------------------------------------------------------
  147. BOOL APU_DoFrame()
  148. {
  149. // Stuff necessary for working with streaming buffers.
  150. HRESULT hr;
  151. DWORD   dwWritePos;
  152. DWORD   dwBytesLocked1;
  153. DWORD   dwBytesLocked2;
  154. DWORD   dwByteNum;
  155. VOID*   pvData1;
  156. VOID*   pvData2;
  157. VOID*   pvDataSave;
  158. static DWORD dwLastEndWritePos = 0;
  159. // Stuff for nintendo sound files.
  160. WORD wTotalOutputVol; // Sum of all the sound channel's volumes.
  161. // If the buffer is invalid then return.
  162. if (lpdsbSoundBuf == NULL)
  163. return FALSE;
  164. // Get the current write position within the buffer.
  165. if (FAILED(lpdsbSoundBuf->GetCurrentPosition(NULL, &dwWritePos)))
  166. return FALSE;
  167. // If the play cursor has just reached the first or second half
  168. // of the buffer, it's time to stream data to the other half.
  169. LONG lTemp = dwLastEndWritePos - 1000;
  170. if (lTemp < 0)
  171. lTemp = 0;
  172. //if (dwWritePos >= (dwLastEndWritePos))// || ())
  173. if (dwWritePos >= (DWORD)lTemp)// || ())
  174. {
  175. // Lock the buffer so we can write to it.
  176. hr = lpdsbSoundBuf->Lock(dwLastEndWritePos, OPTIONS_NUM_BYTESTOLOCK, 
  177. &pvData1, &dwBytesLocked1, &pvData2, &dwBytesLocked2, 0);
  178. if (SUCCEEDED(hr))
  179. {
  180. // For the first part of the loop calculate the sound values.
  181. bCalculateSound = TRUE;
  182. // Fill the whole locked portion of the sound buffer with
  183. // out sound data from each of the Nintendo's sound channels.
  184. // This involves two for loops since the buffer may wrap around.
  185. // Save a temp pointer to the first portions of the sound buffer.
  186. pvDataSave = pvData1;
  187. // First portion of the buffer.
  188. for (dwByteNum = 0; dwByteNum < dwBytesLocked1; 
  189. dwByteNum += OPTIONS_NUM_CHANNELS * (OPTIONS_NUM_BITSPERSAMPLE / 8))
  190. {
  191. // Clear the last volume outta there.
  192. wTotalOutputVol = 0;
  193. // Process the square channel 1.
  194. wTotalOutputVol += (WORD)APU_DoSquare1();
  195. // Write the data to the sound buffer and move the pointer 
  196. // to the buffer to the next data position.
  197. if (OPTIONS_NUM_BITSPERSAMPLE == 8)
  198. {
  199. *((BYTE*)pvDataSave) = (BYTE)wTotalOutputVol;
  200. pvDataSave = (BYTE*)pvDataSave + (OPTIONS_NUM_CHANNELS * 1);
  201. }
  202. else
  203. {
  204. *((WORD*)pvDataSave) = wTotalOutputVol;
  205. pvDataSave = (BYTE*)pvDataSave + (OPTIONS_NUM_CHANNELS * 2);
  206. }
  207. // Stop calculating the sound.
  208. if (bCalculateSound == TRUE)
  209. bCalculateSound = FALSE;
  210. }
  211. // If the locked portion of the buffer wrapped around to the 
  212. // beginning of the buffer then we need to write to it.
  213. if (dwBytesLocked2 > 0)
  214. {
  215. // Save a temp pointer to the second portions of the sound buffer.
  216. pvDataSave = pvData2;
  217. // Second portion of the buffer.
  218. for (dwByteNum = 0; dwByteNum < dwBytesLocked2; 
  219. dwByteNum += OPTIONS_NUM_CHANNELS * (OPTIONS_NUM_BITSPERSAMPLE / 8))
  220. {
  221. // Clear the last volume outta there.
  222. wTotalOutputVol = 0;
  223. // Process the square channel 1.
  224. wTotalOutputVol += (WORD)APU_DoSquare1();
  225. // Write the data to the sound buffer and move the pointer 
  226. // to the buffer to the next data position.
  227. if (OPTIONS_NUM_BITSPERSAMPLE == 8)
  228. {
  229. *((BYTE*)pvDataSave) = (BYTE)wTotalOutputVol;
  230. pvDataSave = (BYTE*)pvDataSave + (OPTIONS_NUM_CHANNELS * 1);
  231. }
  232. else
  233. {
  234. *((WORD*)pvDataSave) = wTotalOutputVol;
  235. pvDataSave = (BYTE*)pvDataSave + (OPTIONS_NUM_CHANNELS * 2);
  236. }
  237. }
  238. }
  239. // Unlock the buffer now that were done with it.
  240. lpdsbSoundBuf->Unlock(pvData1, dwBytesLocked1, pvData2, dwBytesLocked2);
  241. }
  242. // Save the position of the last place we wrote to so 
  243. // we can continue the next time this function is called.
  244. dwLastEndWritePos = (DWORD)(dwLastEndWritePos+dwBytesLocked1+dwBytesLocked2);
  245. if (dwLastEndWritePos >= ((OPTIONS_NUM_BITSPERSAMPLE/8)*OPTIONS_NUM_CHANNELS*OPTIONS_NUM_SAMPLESPERSEC)*OPTIONS_NUM_SECONDSFORBUFFER)
  246. {
  247. dwLastEndWritePos -= ((OPTIONS_NUM_BITSPERSAMPLE/8)*OPTIONS_NUM_CHANNELS*OPTIONS_NUM_SAMPLESPERSEC)*OPTIONS_NUM_SECONDSFORBUFFER;
  248. }
  249. }
  250. // Victory is ours!!!!
  251. return TRUE;
  252. } // end APU_DoFrame()
  253. //------------------------------------------------------------------------------
  254. // Name: APU_DoSquare1()
  255. // Desc: Process the first square wave sound channel.
  256. //------------------------------------------------------------------------------
  257. WORD APU_DoSquare1()
  258. {
  259. static DWORD dwNumCyclesElapsed = 0; // Keeps track of where we are in the wave.
  260. static DWORD dwDutyFlip = 0;         // How many times the programmable timer must 
  261.                                      // reload untill a duty flip.
  262. static DWORD dwWaveLength = 0;       // How many cycles till the programmable timer reloads.
  263. static BYTE  byOutput = 0x80; // The returned output volume.
  264. static BOOL  bDutyFlip = FALSE; // Has a duty flip happended?
  265. static BOOL bCalcSquare = FALSE;
  266. static BOOL bCalcOnNextFlag = FALSE;
  267. if (bCalculateSound)
  268. bCalcOnNextFlag = TRUE;
  269. // If the calculate flag is set, then we need to calculate everything
  270. // that is needed to return an output volume to the calling function.
  271. // Otherwise we just return the precalculated data that was stored
  272. // in the static variables.
  273. if (bCalcSquare)
  274. {
  275. CalculateIt:
  276. // First thing we need to do is start over by reseting the elapsed cycles.
  277. dwNumCyclesElapsed = 0;
  278. // Reset the duty toggle.
  279. bDutyFlip = FALSE;
  280. bCalcSquare = FALSE;
  281. bCalcOnNextFlag = FALSE;
  282. //---------------------------------------------------------------------
  283. // Do the length counter part.
  284. //---------------------------------------------------------------------
  285. // If the length counter is enabled then we need to process it.
  286. if (!(CPU.Memory[0x4000] & 0x20))
  287. {
  288. // If the length counter is not zero then decrement the value.
  289. if (APU.sndchanSquare1.byLengthCtr)
  290. APU.sndchanSquare1.byLengthCtr--;
  291. }
  292. //---------------------------------------------------------------------
  293. // TODO: This is where the sweeping unit needs to be emulated.
  294. //---------------------------------------------------------------------
  295. //---------------------------------------------------------------------
  296. // Emulate the programmable timer to get the wavelength.
  297. //---------------------------------------------------------------------
  298. // Take the 3 least significant bits from $4003 and
  299. // use those as the bits 8-10 for our wavelength. Bits
  300. // 0-7 come from $4002 to produce our 11-bit wavelength.
  301. // The we need to add one to it.
  302. dwWaveLength = ((((WORD)(CPU.Memory[0x4003]&0x7)) << 8) | 
  303. CPU.Memory[0x4002]) + 1;
  304. //---------------------------------------------------------------------
  305. // Emulate the duty flip part.
  306. //---------------------------------------------------------------------
  307. dwDutyFlip = abyDutyCycleTablePos[CPU.Memory[0x4000]>>6];
  308. //---------------------------------------------------------------------
  309. // Now finally send the signal through the volume/envelope decay unit.
  310. //---------------------------------------------------------------------
  311. // If the envelope decay bit is set, then the volume goes staight
  312. // to the DAC...or in our case DirectSound. This means that
  313. // the envelope decay is disabled.
  314. if (!(CPU.Memory[0x4000] & 0x10))
  315. {
  316. // There are a few conditions when 0 is sent straight
  317. // to the DAC for the volume. They are as follows:
  318. // 1.  If the length counter is 0
  319. // 2.  Something to do with the sweep unit.
  320. // 3.  On the negative portion of the output frequency 
  321. //     signal coming from the duty cycle.
  322. //
  323. // Otherwise bits (0-3) of $4000 are sent straight the
  324. // DAC for the volume.
  325. if (APU.sndchanSquare1.byLengthCtr == 0) // TODO: implement other conditions.
  326. byOutput = 0x80;
  327. else
  328. byOutput = ((CPU.Memory[0x4000] & 0x0F) << 3);
  329. }
  330. else
  331. byOutput = ((CPU.Memory[0x4000] & 0x0F) << 3);
  332. }
  333. // If we are done with the wave we need to start over.
  334. if (dwNumCyclesElapsed >= dwWaveLength)
  335. {
  336. // We need to flip the volume to negative if the amount of
  337. // times for a duty flip has passed.
  338. if ((dwDutyFlip--) == 0)
  339. {
  340. // If the duty flip is positive then we load the counter with the negative
  341. // value. If the duty flip is negative, then we load the counter
  342. // with the positive counter.
  343. if (bDutyFlip)
  344. {
  345. dwDutyFlip = abyDutyCycleTablePos[CPU.Memory[0x4000]>>6];
  346. if (bCalcOnNextFlag)
  347. {
  348. bCalcSquare = FALSE;
  349. //return (WORD)byOutput;
  350. goto CalculateIt;
  351. }
  352. }
  353. else
  354. {
  355. dwDutyFlip = abyDutyCycleTableNeg[CPU.Memory[0x4000]>>6];
  356. }
  357. // Flip the output wave.
  358. byOutput = -byOutput;
  359. // Toggle the duty flip indicator.
  360. bDutyFlip ^= TRUE;
  361. }
  362. dwNumCyclesElapsed -= dwWaveLength;
  363. }
  364. else
  365. // Keep moving along the phase of the wave form.
  366. dwNumCyclesElapsed += dwNumCyclesPerSample;
  367. // Return the final value.
  368. return (WORD)byOutput;
  369. } // end APU_DoSquare1()
  370. //------------------------------------------------------------------------------
  371. // Name: APU_Read()
  372. // Desc: Handles all the reads from the APU.
  373. //------------------------------------------------------------------------------
  374. BYTE APU_Read(WORD wReg)
  375. {
  376. BYTE byRetVal = 0;
  377. switch (wReg)
  378. {
  379. case 0x4015:
  380. // If the length counter is non-zero set bit 1.
  381. if (APU.sndchanSquare1.byLengthCtr) byRetVal |= 0x01;
  382. // Return the byte.
  383. return byRetVal;
  384. default:
  385. return 0;
  386. }
  387. return 0;
  388. } // end APU_Read()
  389. //------------------------------------------------------------------------------
  390. // Name: APU_Write()
  391. // Desc: Handles all the writes to the APU.
  392. //------------------------------------------------------------------------------
  393. VOID APU_Write(WORD wReg, BYTE byData)
  394. {
  395. // The old length counters for the channel since writing 0 into
  396. // $4015 sets the length counter to 0, but writing 1 sets the
  397. // length counter back to its origional value.
  398. static BYTE byOldLengthCounter = 0;
  399. switch (wReg)
  400. {
  401. case 0x4003:
  402. // Use a lookup table to set the length counter.
  403. // Bits 3-7 are used for this but they must be
  404. // right shifted to use the lookup table.
  405. APU.sndchanSquare1.byLengthCtr = abyLengthTable[byData >> 3];
  406. return;
  407. case 0x4015:
  408. // Deal with writes for the first square channel.
  409. if (byData & 0x1)
  410. APU.sndchanSquare1.byLengthCtr = byOldLengthCounter;
  411. else
  412. {
  413. // If the bit is not set the length counter is forced to 0,
  414. // but make sure to save the value for when a 1 gets written.
  415. byOldLengthCounter = APU.sndchanSquare1.byLengthCtr;
  416. APU.sndchanSquare1.byLengthCtr = 0;
  417. }
  418. return;
  419. default:
  420. return;
  421. }
  422. return;
  423. } // end APU_Write()