Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1662 lines
41 KiB

  1. /***************************************************************************
  2. *
  3. * dsp.c
  4. *
  5. * Copyright (c) 1991-1996 Microsoft Corporation. All Rights Reserved.
  6. *
  7. * This code provides VDD support for SB 2.0 sound output, specifically:
  8. * DSP 2.01+ (excluding SB-MIDI port)
  9. *
  10. ***************************************************************************/
  11. /*****************************************************************************
  12. *
  13. * #includes
  14. *
  15. *****************************************************************************/
  16. #include <windows.h> // The VDD is a win32 DLL
  17. #include <mmsystem.h> // Multi-media APIs
  18. #include <vddsvc.h> // Definition of VDD calls
  19. #include <vsb.h>
  20. #include <dsp.h>
  21. /*****************************************************************************
  22. *
  23. * Globals
  24. *
  25. *****************************************************************************/
  26. //
  27. // Definitions for MM api entry points. The functions will be linked
  28. // dynamically to avoid bringing winmm.dll in before wow32.
  29. //
  30. extern SETVOLUMEPROC SetVolumeProc;
  31. extern GETNUMDEVSPROC GetNumDevsProc;
  32. extern GETDEVCAPSPROC GetDevCapsProc;
  33. extern OPENPROC OpenProc;
  34. extern RESETPROC ResetProc;
  35. extern CLOSEPROC CloseProc;
  36. extern GETPOSITIONPROC GetPositionProc;
  37. extern WRITEPROC WriteProc;
  38. extern PREPAREHEADERPROC PrepareHeaderProc;
  39. extern UNPREPAREHEADERPROC UnprepareHeaderProc;
  40. /*
  41. * General globals
  42. */
  43. extern HINSTANCE GlobalHInstance; // handle passed to dll entry point
  44. BYTE IdentByte; // used with DSP_CARD_IDENTIFY
  45. BOOL SpeakerOn = FALSE; // TRUE when speaker is on
  46. BYTE ReservedRegister; // used with DSP_LOAD_RES_REG and DSP_READ_RES_REG
  47. ULONG PageSize; // size of pages for VirtualAlloc
  48. ULONG iHdr; // used to index wavehdr array
  49. /*
  50. * Event Globals
  51. */
  52. HANDLE SingleWaveSem; // used by app to indicate data to write
  53. HANDLE PauseEvent; // used to restart paused single
  54. HANDLE ThreadStarted; // signalled when thread starts running
  55. HANDLE ThreadFinished; // signalled when thread exits
  56. /*
  57. * Wave globals
  58. */
  59. UINT WaveOutDevice; // device identifier
  60. HWAVEOUT HWaveOut = NULL; // the current open wave output device
  61. PCMWAVEFORMAT WaveFormat = { { WAVE_FORMAT_PCM, 1, 0, 0, 1 }, 8};
  62. DWORD TimeConstant = (256 - 1000000/11025); // one byte format
  63. DWORD SBBlockSize = 0x800; // Block size set by apps, always size of transfer-1
  64. DWORD LookAheadFactor = DEFAULT_LOOKAHEAD;
  65. VDD_DMA_INFO dMAInfo;
  66. DWORD dMAPhysicalStart; // the starting address for this transfer
  67. DWORD dMACurrentPosition; // where we are currently reading from
  68. DWORD dMAVirtualStart; // what the app thinks the addr is for this transfer
  69. ULONG dMASize; // the size of the DMA memory-1
  70. WAVEHDR * WaveHdrs; // pointer to allocated wave headers
  71. BYTE * WaveData; // pointer to allocated wave buffer
  72. ULONG TotalNumberOfBursts;
  73. ULONG BurstsPerBlock;
  74. ULONG DesiredBytesOutstanding;
  75. ULONG BytesOutstanding = 0;
  76. ULONG PhysicalBytesPlayed = 0;
  77. ULONG LastBytesPlayedValue;
  78. BOOL bDspActive = FALSE; // dsp thread currently active, changed with interlocked
  79. BOOL bDspPause = FALSE; // dsp paused, changed with interlocked
  80. BOOL bDspReset = FALSE; // dsp stopped, changed with interlocked
  81. enum {
  82. Auto,
  83. Single
  84. } DspMode;
  85. /*****************************************************************************
  86. *
  87. * State Machines
  88. *
  89. *****************************************************************************/
  90. /*
  91. * DSP Reset State Machine
  92. */
  93. enum {
  94. ResetNotStarted = 1,
  95. Reset1Written
  96. }
  97. ResetState = ResetNotStarted; // state of current reset
  98. /*
  99. * DSP Write State Machine
  100. */
  101. enum {
  102. WriteCommand = 1, // Initial state and after reset
  103. CardIdent,
  104. TableMunge,
  105. LoadResReg,
  106. SetTimeConstant,
  107. BlockSizeFirstByte,
  108. BlockSizeSecondByte,
  109. BlockSizeFirstByteWrite,
  110. BlockSizeSecondByteWrite,
  111. BlockSizeFirstByteRead,
  112. BlockSizeSecondByteRead
  113. }
  114. DSPWriteState = WriteCommand; // state of current command/data being written
  115. /*
  116. * DSP Read State Machine
  117. */
  118. enum {
  119. NothingToRead = 1, // initial state and after reset
  120. Reset,
  121. FirstVersionByte,
  122. SecondVersionByte,
  123. ReadIdent,
  124. ReadResReg
  125. }
  126. DSPReadState = NothingToRead; // state of current command/data being read
  127. /*****************************************************************************
  128. *
  129. * General Functions
  130. *
  131. *****************************************************************************/
  132. BOOL
  133. DspProcessAttach(
  134. VOID
  135. )
  136. {
  137. HKEY hKey;
  138. ULONG dwType;
  139. ULONG cbData;
  140. SYSTEM_INFO SystemInfo;
  141. // create synchronization events
  142. PauseEvent=CreateEvent(NULL, FALSE, FALSE, NULL);
  143. SingleWaveSem=CreateSemaphore(NULL, 1, 100, NULL);
  144. ThreadStarted=CreateEvent(NULL, FALSE, FALSE, NULL);
  145. ThreadFinished=CreateEvent(NULL, FALSE, FALSE, NULL);
  146. if (!RegOpenKeyEx (HKEY_LOCAL_MACHINE,
  147. VSBD_PATH,
  148. 0,
  149. KEY_EXECUTE, // Requesting read access.
  150. &hKey)) {
  151. cbData = sizeof(ULONG);
  152. RegQueryValueEx(hKey,
  153. LOOKAHEAD_VALUE,
  154. NULL,
  155. &dwType,
  156. (LPSTR)&LookAheadFactor,
  157. &cbData);
  158. RegCloseKey(hKey);
  159. }
  160. // Allocate memory for wave buffer
  161. WaveData = (BYTE *) VirtualAlloc(NULL,
  162. 64*1024,
  163. MEM_RESERVE,
  164. PAGE_READWRITE);
  165. if(WaveData == NULL ) {
  166. dprintf1(("Unable to allocate memory"));
  167. return(FALSE);
  168. }
  169. GetSystemInfo(&SystemInfo);
  170. PageSize = SystemInfo.dwPageSize;
  171. return TRUE;
  172. }
  173. VOID
  174. DspProcessDetach(
  175. VOID
  176. )
  177. {
  178. // stop any active threads
  179. StopAutoWave(FALSE);
  180. StopSingleWave(FALSE);
  181. // close synchronization events
  182. CloseHandle(PauseEvent);
  183. CloseHandle(SingleWaveSem);
  184. CloseHandle(ThreadStarted);
  185. CloseHandle(ThreadFinished);
  186. VirtualFree(WaveData, 0, MEM_RELEASE);
  187. }
  188. /***************************************************************************/
  189. /*
  190. * Gets called when the application reads from port.
  191. * Returns results to application in data.
  192. */
  193. VOID
  194. DspReadStatus(
  195. BYTE * data
  196. )
  197. {
  198. // See if we think there is something to read
  199. *data = DSPReadState != NothingToRead ? 0xFF : 0x7F;
  200. }
  201. VOID
  202. DspReadData(
  203. BYTE * data
  204. )
  205. {
  206. switch (DSPReadState) {
  207. case NothingToRead:
  208. *data = 0xFF;
  209. break;
  210. case Reset:
  211. *data = 0xAA;
  212. DSPReadState = NothingToRead;
  213. break;
  214. case FirstVersionByte:
  215. *data = (BYTE)(SB_VERSION / 256);
  216. DSPReadState = SecondVersionByte;
  217. break;
  218. case SecondVersionByte:
  219. *data = (BYTE)(SB_VERSION % 256);
  220. DSPReadState = NothingToRead;
  221. break;
  222. case ReadIdent:
  223. *data = ~IdentByte;
  224. DSPReadState = NothingToRead;
  225. break;
  226. case ReadResReg:
  227. *data = ReservedRegister;
  228. DSPReadState = NothingToRead;
  229. break;
  230. default:
  231. dprintf1(("Unrecognized read state"));
  232. }
  233. }
  234. /***************************************************************************/
  235. /*
  236. * Gets called when an application writes data to port.
  237. */
  238. VOID
  239. DspResetWrite(
  240. BYTE data
  241. )
  242. {
  243. if (data == 1) {
  244. ResetState = Reset1Written;
  245. }
  246. else {
  247. if (ResetState == Reset1Written && data == 0) {
  248. ResetState = ResetNotStarted;
  249. ResetAll(); // OK - reset everything
  250. }
  251. }
  252. }
  253. VOID
  254. DspWrite(
  255. BYTE data
  256. )
  257. {
  258. DWORD ddata;
  259. switch (DSPWriteState) {
  260. case WriteCommand:
  261. WriteCommandByte(data);
  262. break;
  263. case CardIdent:
  264. IdentByte = data;
  265. DSPReadState = ReadIdent;
  266. DSPWriteState = WriteCommand;
  267. break;
  268. case TableMunge:
  269. TableMunger(data);
  270. DSPWriteState = WriteCommand;
  271. break;
  272. case LoadResReg:
  273. ReservedRegister = data;
  274. DSPWriteState = WriteCommand;
  275. break;
  276. case SetTimeConstant:
  277. TimeConstant = (DWORD)data;
  278. dprintf3(("Time constant is %X", TimeConstant));
  279. dprintf3(("Set sampling rate %d", GetSamplingRate()));
  280. DSPWriteState = WriteCommand;
  281. break;
  282. case BlockSizeFirstByte:
  283. SBBlockSize = (DWORD)data;
  284. DSPWriteState = BlockSizeSecondByte;
  285. break;
  286. case BlockSizeSecondByte:
  287. ddata = data;
  288. SBBlockSize = SBBlockSize + (ddata << 8);
  289. DSPWriteState = WriteCommand;
  290. dprintf2(("Block size set to 0x%x", SBBlockSize));
  291. break;
  292. case BlockSizeFirstByteWrite:
  293. SBBlockSize = (DWORD)data;
  294. DSPWriteState = BlockSizeSecondByteWrite;
  295. break;
  296. case BlockSizeSecondByteWrite:
  297. ddata = data;
  298. SBBlockSize = SBBlockSize + (ddata << 8);
  299. DSPWriteState = WriteCommand;
  300. dprintf3(("Block size set to 0x%x", SBBlockSize));
  301. // this is a hack to convince some apps a sb exists
  302. if(SBBlockSize==0) {
  303. VDM_TRACE(0x6a0,0,0);
  304. GenerateInterrupt();
  305. }
  306. StartSingleWave();
  307. break;
  308. case BlockSizeFirstByteRead:
  309. SBBlockSize = (DWORD)data;
  310. DSPWriteState = BlockSizeSecondByteRead;
  311. break;
  312. case BlockSizeSecondByteRead:
  313. ddata = data;
  314. SBBlockSize = SBBlockSize + (ddata << 8);
  315. DSPWriteState = WriteCommand;
  316. dprintf3(("Block size set to 0x%x", SBBlockSize));
  317. // this is a hack to convince some apps a sb exists
  318. if(SBBlockSize==0) {
  319. ULONG dMAPhysicalAddress;
  320. if((dMAPhysicalAddress=GetDMATransferAddress()) != -1L) {
  321. *(PUCHAR)dMAPhysicalAddress = 0x80;
  322. }
  323. VDM_TRACE(0x6a0,0,0);
  324. GenerateInterrupt();
  325. }
  326. break;
  327. }
  328. }
  329. /***************************************************************************/
  330. /*
  331. * Handles commands sent to the DSP.
  332. */
  333. VOID
  334. WriteCommandByte(
  335. BYTE command
  336. )
  337. {
  338. switch (command) {
  339. case DSP_GET_VERSION:
  340. dprintf2(("Command - Get Version"));
  341. DSPReadState = FirstVersionByte;
  342. break;
  343. case DSP_CARD_IDENTIFY:
  344. dprintf2(("Command - Identify"));
  345. DSPWriteState = CardIdent;
  346. break;
  347. case DSP_TABLE_MUNGE:
  348. dprintf2(("Command - DSP Table Munge"));
  349. DSPWriteState = TableMunge;
  350. break;
  351. case DSP_LOAD_RES_REG:
  352. dprintf2(("Command - Load Res Reg"));
  353. DSPWriteState = LoadResReg;
  354. break;
  355. case DSP_READ_RES_REG:
  356. dprintf2(("Command - Read Res Reg"));
  357. DSPReadState = ReadResReg;
  358. break;
  359. case DSP_GENERATE_INT:
  360. dprintf2(("Command - Generate interrupt DMA"));
  361. GenerateInterrupt();
  362. break;
  363. case DSP_SPEAKER_ON:
  364. dprintf2(("Command - Speaker ON"));
  365. SetSpeaker(TRUE);
  366. break;
  367. case DSP_SPEAKER_OFF:
  368. dprintf2(("Command - Speaker OFF"));
  369. SetSpeaker(FALSE);
  370. break;
  371. case DSP_SET_SAMPLE_RATE:
  372. dprintf3(("Command - Set Sample Rate"));
  373. DSPWriteState = SetTimeConstant;
  374. break;
  375. case DSP_SET_BLOCK_SIZE:
  376. dprintf2(("Command - Set Block Size"));
  377. DSPWriteState = BlockSizeFirstByte;
  378. break;
  379. case DSP_PAUSE_DMA:
  380. dprintf2(("Command - Pause DMA"));
  381. PauseDMA();
  382. break;
  383. case DSP_CONTINUE_DMA:
  384. dprintf2(("Command - Continue DMA"));
  385. ContinueDMA();
  386. break;
  387. case DSP_STOP_AUTO:
  388. dprintf2(("Command - Stop DMA"));
  389. StopAutoWave(TRUE);
  390. break;
  391. case DSP_WRITE:
  392. case DSP_WRITE_HS:
  393. dprintf3(("Command - Write - non Auto"));
  394. DSPWriteState = BlockSizeFirstByteWrite;
  395. break;
  396. case DSP_WRITE_AUTO:
  397. case DSP_WRITE_HS_AUTO:
  398. dprintf2(("Command - Write - Auto"));
  399. StartAutoWave();
  400. break;
  401. case DSP_READ:
  402. dprintf3(("Command - Read - non Auto"));
  403. DSPWriteState = BlockSizeFirstByteRead;
  404. break;
  405. default:
  406. dprintf1(("Unrecognized DSP command %2X", command));
  407. }
  408. }
  409. /*****************************************************************************
  410. *
  411. * Device manipulation and control routines
  412. *
  413. *****************************************************************************/
  414. /*
  415. * Reset threads/globals/events/state-machines to initial state.
  416. */
  417. VOID
  418. ResetDSP(
  419. VOID
  420. )
  421. {
  422. // Stop any active DMA threads
  423. StopAutoWave(TRUE);
  424. StopSingleWave(TRUE);
  425. // Set events and globals to initial state
  426. ResetEvent(PauseEvent);
  427. CloseHandle(SingleWaveSem);
  428. SingleWaveSem=CreateSemaphore(NULL, 1, 100, NULL);
  429. ResetEvent(ThreadStarted);
  430. ResetEvent(ThreadFinished);
  431. SetSpeaker(FALSE);
  432. SpeakerOn = FALSE;
  433. HWaveOut = NULL;
  434. TimeConstant = (256 - 1000000/11025);
  435. WaveFormat.wf.nSamplesPerSec = 0;
  436. WaveFormat.wf.nAvgBytesPerSec = 0;
  437. SBBlockSize = 0x800;
  438. bDspActive = FALSE;
  439. bDspReset = FALSE;
  440. bDspPause = FALSE;
  441. // Reset state machines
  442. DSPReadState = Reset;
  443. DSPWriteState = WriteCommand;
  444. }
  445. /***************************************************************************/
  446. /*
  447. * Munges (changes) a jump table in apps code,
  448. * Algorithm from sbvirt.asm in MMSNDSYS.
  449. */
  450. VOID
  451. TableMunger(
  452. BYTE data
  453. )
  454. {
  455. static BYTE TableMungeData;
  456. static BOOL TableMungeFirstByte = TRUE; // munging first or second byte
  457. BYTE comp, dataCopy;
  458. VDD_DMA_INFO dMAInfo;
  459. ULONG dMAPhysicalAddress;
  460. if(TableMungeFirstByte) {
  461. dprintf2(("Munging first byte"));
  462. dataCopy = data;
  463. dataCopy = dataCopy & 0x06;
  464. dataCopy = dataCopy << 1;
  465. if(data & 0x10) {
  466. comp = 0x40;
  467. }
  468. else {
  469. comp = 0x20;
  470. }
  471. comp = comp - dataCopy;
  472. data = data + comp;
  473. TableMungeData = data;
  474. // Update memory (code table) with munged data
  475. dprintf2(("Writing first byte"));
  476. if((dMAPhysicalAddress=GetDMATransferAddress()) == -1L) {
  477. dprintf1(("Unable to get dma address"));
  478. return;
  479. }
  480. CopyMemory((PVOID)dMAPhysicalAddress, &data, 1);
  481. // Update virtual DMA status
  482. VDDQueryDMA((HANDLE)GlobalHInstance, SB_DMA_CHANNEL, &dMAInfo);
  483. dprintf4(("DMA Info : addr %4X, count %4X, page %4X, status %2X, mode %2X, mask %2X",
  484. dMAInfo.addr, dMAInfo.count, dMAInfo.page, dMAInfo.status,
  485. dMAInfo.mode, dMAInfo.mask));
  486. dMAInfo.count = dMAInfo.count - 1;
  487. dMAInfo.addr = dMAInfo.addr + 1;
  488. VDDSetDMA((HANDLE)GlobalHInstance, SB_DMA_CHANNEL,
  489. VDD_DMA_COUNT|VDD_DMA_ADDR, &dMAInfo);
  490. TableMungeFirstByte = FALSE;
  491. }
  492. else {
  493. dprintf2(("Munging second byte"));
  494. data = data ^ 0xA5;
  495. data = data + TableMungeData;
  496. TableMungeData = data;
  497. // Update memory (code table) with munged data
  498. dprintf2(("Writing second byte"));
  499. if((dMAPhysicalAddress=GetDMATransferAddress()) == -1L) {
  500. dprintf1(("Unable to get dma address"));
  501. return;
  502. }
  503. CopyMemory((PVOID)dMAPhysicalAddress, &data, 1);
  504. // Update virtual DMA status
  505. VDDQueryDMA((HANDLE)GlobalHInstance, SB_DMA_CHANNEL, &dMAInfo);
  506. dMAInfo.count = dMAInfo.count - 1;
  507. dMAInfo.addr = dMAInfo.addr + 1;
  508. VDDSetDMA((HANDLE)GlobalHInstance, SB_DMA_CHANNEL,
  509. VDD_DMA_COUNT|VDD_DMA_ADDR, &dMAInfo);
  510. if(dMAInfo.count==0xFFFF) {
  511. SetDMAStatus(FALSE, TRUE);
  512. }
  513. TableMungeFirstByte = TRUE;
  514. }
  515. }
  516. /***************************************************************************/
  517. /*
  518. * Get sampling rate from time constant.
  519. * Returns sampling rate.
  520. */
  521. DWORD
  522. GetSamplingRate(
  523. VOID
  524. )
  525. {
  526. // Sampling rate = 1000000 / (256 - Time constant)
  527. return(1000000 / (256 - TimeConstant));
  528. }
  529. /***************************************************************************/
  530. /*
  531. * Generate device interrupt on dma channel SM_INTERRUPT on ICA_MASTER device.
  532. */
  533. VOID
  534. GenerateInterrupt(
  535. VOID
  536. )
  537. {
  538. // Generate an interrupt on the master controller
  539. dprintf3(("Generating interrupt"));
  540. VDM_TRACE(0x6a1,0,0);
  541. VDDSimulateInterrupt(ICA_MASTER, SB_INTERRUPT, 1);
  542. }
  543. /***************************************************************************/
  544. /*
  545. * Sets the speaker on or off.
  546. */
  547. VOID
  548. SetSpeaker(
  549. BOOL On
  550. )
  551. {
  552. if (HWaveOut) {
  553. if(On) {
  554. SetVolumeProc(HWaveOut, (DWORD)0x77777777UL);
  555. SpeakerOn = TRUE;
  556. }
  557. else {
  558. SetVolumeProc(HWaveOut, (DWORD)0x00000000UL);
  559. SpeakerOn = FALSE;
  560. }
  561. }
  562. return;
  563. }
  564. /****************************************************************************
  565. *
  566. * Wave device routines
  567. *
  568. ****************************************************************************/
  569. /*
  570. * Find a suitable wave output device.
  571. * Returns device or NO_DEVICE_FOUND if none found.
  572. */
  573. UINT
  574. FindWaveDevice(
  575. VOID
  576. )
  577. {
  578. UINT numDev;
  579. UINT device;
  580. WAVEOUTCAPS wc;
  581. numDev = GetNumDevsProc();
  582. for (device = 0; device < numDev; device++) {
  583. if (MMSYSERR_NOERROR == GetDevCapsProc(device, &wc, sizeof(wc))) {
  584. // Need 11025 and 44100 for device
  585. if ((wc.dwFormats & (WAVE_FORMAT_1M08 | WAVE_FORMAT_4M08)) ==
  586. (WAVE_FORMAT_1M08 | WAVE_FORMAT_4M08)) {
  587. WaveOutDevice = device;
  588. return TRUE;
  589. }
  590. }
  591. }
  592. dprintf1(("Wave device not found"));
  593. return FALSE;
  594. }
  595. /***************************************************************************/
  596. /*
  597. * Open wave device and start synchronization thread.
  598. * Returns TRUE on success.
  599. */
  600. BOOL
  601. OpenWaveDevice(
  602. VOID
  603. )
  604. {
  605. UINT rc;
  606. HANDLE tHandle;
  607. rc = OpenProc(&HWaveOut, (UINT)WaveOutDevice, (LPWAVEFORMATEX)
  608. &WaveFormat, 0, 0, CALLBACK_NULL);
  609. if (rc != MMSYSERR_NOERROR) {
  610. dprintf1(("Failed to open wave device - code %d", rc));
  611. return FALSE;
  612. }
  613. BytesOutstanding = 0;
  614. PhysicalBytesPlayed = 0;
  615. return TRUE;
  616. }
  617. /***************************************************************************/
  618. /*
  619. * Reset wave device.
  620. */
  621. VOID
  622. ResetWaveDevice(
  623. VOID
  624. )
  625. {
  626. // No synchronization required
  627. dprintf2(("Resetting wave device"));
  628. if (HWaveOut) {
  629. if(MMSYSERR_NOERROR != ResetProc(HWaveOut)) {
  630. dprintf1(("Unable to reset wave out device"));
  631. }
  632. }
  633. }
  634. /***************************************************************************/
  635. /*
  636. * Shut down and close wave device.
  637. */
  638. VOID
  639. CloseWaveDevice(
  640. VOID
  641. )
  642. {
  643. dprintf2(("Closing wave device"));
  644. ResetWaveDevice();
  645. if (HWaveOut) {
  646. if(MMSYSERR_NOERROR != CloseProc(HWaveOut)) {
  647. dprintf1(("Unable to close wave out device"));
  648. } else {
  649. HWaveOut = NULL;
  650. dprintf2(("Wave out device closed"));
  651. }
  652. }
  653. }
  654. /***************************************************************************/
  655. /*
  656. * Returns TRUE if current wave device supports sample rate.
  657. */
  658. BOOL
  659. TestWaveFormat(
  660. DWORD sampleRate
  661. )
  662. {
  663. PCMWAVEFORMAT format;
  664. format = WaveFormat;
  665. format.wf.nSamplesPerSec = sampleRate;
  666. format.wf.nAvgBytesPerSec = sampleRate;
  667. return(MMSYSERR_NOERROR == OpenProc(NULL, (UINT)WaveOutDevice,
  668. (LPWAVEFORMATEX) &format,
  669. 0, 0, WAVE_FORMAT_QUERY));
  670. }
  671. /***************************************************************************/
  672. /*
  673. * Make sure we've got a device that matches the current sampling rate.
  674. * Returns TRUE if device does NOT support current sampling rate and
  675. * wave format has changed, otherwise returns FALSE
  676. */
  677. BOOL
  678. SetWaveFormat(
  679. VOID
  680. )
  681. {
  682. DWORD sampleRate;
  683. DWORD testValue;
  684. UINT i = 0;
  685. if (TimeConstant != 0xFFFF) {
  686. // time constant has been reset since last checked
  687. sampleRate = GetSamplingRate();
  688. dprintf3(("Requested sample rate is %d", sampleRate));
  689. if (sampleRate != WaveFormat.wf.nSamplesPerSec) { // format has changed
  690. if (!TestWaveFormat(sampleRate)) {
  691. dprintf3(("Finding closest wave format"));
  692. // find some format that works and is close to requested
  693. for(i=0; i<50000; i++) {
  694. testValue = sampleRate-i;
  695. if(TestWaveFormat(testValue)) {
  696. sampleRate = testValue;
  697. break;
  698. }
  699. testValue = sampleRate+i;
  700. if(TestWaveFormat(testValue)) {
  701. sampleRate = testValue;
  702. break;
  703. }
  704. }
  705. if(sampleRate!=testValue) {
  706. dprintf1(("Unable to find suitable wave format"));
  707. return FALSE;
  708. }
  709. }
  710. // Set the new format if it's changed
  711. if (sampleRate != WaveFormat.wf.nSamplesPerSec) {
  712. dprintf2(("Setting %d samples per second", sampleRate));
  713. WaveFormat.wf.nSamplesPerSec = sampleRate;
  714. WaveFormat.wf.nAvgBytesPerSec = sampleRate;
  715. TimeConstant = 0xFFFF;
  716. return TRUE;
  717. }
  718. }
  719. }
  720. TimeConstant = 0xFFFF;
  721. return FALSE;
  722. }
  723. /***************************************************************************/
  724. /*
  725. * Stops auto init DMA, or pauses single cycle DMA.
  726. */
  727. VOID
  728. PauseDMA(
  729. VOID
  730. )
  731. {
  732. DWORD position = 0;
  733. MMTIME mmTime;
  734. dprintf2(("Pausing DMA"));
  735. switch(DspMode) {
  736. case Auto:
  737. StopAutoWave(TRUE); // simply stop auto dma
  738. break;
  739. case Single:
  740. ResetEvent(PauseEvent);
  741. InterlockedExchange(&bDspPause, 1);
  742. }
  743. }
  744. /***************************************************************************/
  745. /*
  746. * Start auto init DMA, or continues single cycle DMA.
  747. */
  748. VOID
  749. ContinueDMA(
  750. VOID
  751. )
  752. {
  753. switch(DspMode) {
  754. case Auto:
  755. StartAutoWave();
  756. break;
  757. case Single:
  758. SetEvent(PauseEvent);
  759. }
  760. }
  761. /***************************************************************************/
  762. /*
  763. * Get DMA transfer address.
  764. * Returns transfer address or -1 on failure.
  765. */
  766. ULONG
  767. GetDMATransferAddress(
  768. VOID
  769. )
  770. {
  771. ULONG address;
  772. VDD_DMA_INFO dMAInfo;
  773. if (VDDQueryDMA((HANDLE)GlobalHInstance, SB_DMA_CHANNEL, &dMAInfo)) {
  774. dprintf4(("DMA Info : addr %4X, count %4X, page %4X, status %2X, mode %2X, mask %2X",
  775. dMAInfo.addr, dMAInfo.count, dMAInfo.page, dMAInfo.status,
  776. dMAInfo.mode, dMAInfo.mask));
  777. // convert from 20 bit address to 32 bit address
  778. address = (((DWORD)dMAInfo.page) << (12 + 16)) + dMAInfo.addr;
  779. // get VDM pointer
  780. address = (ULONG)GetVDMPointer(address, ((DWORD)dMAInfo.count) + 1, 0);
  781. dprintf3(("Transfer address = %8X", (DWORD)address));
  782. return(address);
  783. }
  784. else {
  785. dprintf1(("Could not retrieve DMA Info"));
  786. return(ULONG)(-1L);
  787. }
  788. }
  789. /***************************************************************************/
  790. /*
  791. * Update the virtual DMA terminal count and request status.
  792. * Terminal count (tc) is set when DMA count loops to 0xFFFF.
  793. * Request status is set when DMA has data to transfer
  794. * (ignored in auto-init DMA).
  795. */
  796. VOID
  797. SetDMAStatus(
  798. BOOL requesting,
  799. BOOL tc
  800. )
  801. {
  802. VDD_DMA_INFO dMAInfo;
  803. if (VDDQueryDMA((HANDLE)GlobalHInstance, SB_DMA_CHANNEL, &dMAInfo)) {
  804. dprintf4(("DMA Info : addr %4X, count %4X, page %4X, status %2X, mode %2X, mask %2X",
  805. dMAInfo.addr, dMAInfo.count, dMAInfo.page, dMAInfo.status,
  806. dMAInfo.mode, dMAInfo.mask));
  807. if (requesting) {
  808. dMAInfo.status |= (0x10 << SB_DMA_CHANNEL); // Requesting
  809. dprintf3(("DMA set as requesting"));
  810. } else {
  811. dMAInfo.status &= ~(0x10 << SB_DMA_CHANNEL); // Not Requesting
  812. dprintf3(("DMA set as not requesting"));
  813. }
  814. if (tc) {
  815. dMAInfo.status |= (1 << SB_DMA_CHANNEL); // tc reached
  816. dprintf3(("DMA set as terminal count reached"));
  817. } else {
  818. dMAInfo.status &= ~(1 << SB_DMA_CHANNEL); // tc not reached
  819. dprintf3(("DMA set as terminal count not reached"));
  820. }
  821. VDDSetDMA((HANDLE)GlobalHInstance, SB_DMA_CHANNEL, VDD_DMA_STATUS,
  822. &dMAInfo);
  823. }
  824. else {
  825. dprintf1(("Could not retrieve DMA Info"));
  826. }
  827. }
  828. /***************************************************************************/
  829. /*
  830. * Start an auto wave.
  831. * Returns TRUE on success.
  832. */
  833. BOOL
  834. StartAutoWave(
  835. VOID
  836. )
  837. {
  838. HANDLE tHandle; // handle to auto thread
  839. VDD_DMA_INFO dMAInfo;
  840. ULONG i;
  841. DWORD id;
  842. dprintf2(("Starting auto wave"));
  843. StopSingleWave(TRUE);
  844. DspMode = Auto;
  845. // Open device
  846. SetWaveFormat();
  847. if (!OpenWaveDevice()) {
  848. dprintf1(("Can't open wave device", GetLastError()));
  849. return FALSE;
  850. }
  851. if(!(tHandle = CreateThread(NULL, 0, AutoThreadEntry, NULL,
  852. CREATE_SUSPENDED, &id))) {
  853. dprintf1(("Create auto thread failed code %d", GetLastError()));
  854. return FALSE;
  855. } else {
  856. if(!SetThreadPriority(tHandle, THREAD_PRIORITY_HIGHEST)) {
  857. dprintf1(("Unable to set auto thread priority"));
  858. }
  859. }
  860. ResumeThread(tHandle);
  861. CloseHandle(tHandle);
  862. WaitForSingleObject(ThreadStarted, INFINITE);
  863. return TRUE;
  864. }
  865. /***************************************************************************/
  866. /*
  867. * Stop Auto thread,
  868. * Should always be called with TRUE,
  869. * except if process exiting as wait causes deadlock
  870. */
  871. VOID
  872. StopAutoWave(
  873. BOOL wait
  874. )
  875. {
  876. if(bDspActive && (DspMode == Auto)) {
  877. dprintf2(("Stopping auto init"));
  878. InterlockedExchange(&bDspReset, TRUE);
  879. if(wait) {
  880. dprintf2(("Waiting for auto thread to exit"));
  881. WaitForSingleObject(ThreadFinished, INFINITE);
  882. dprintf2(("Auto thread has exited"));
  883. }
  884. }
  885. }
  886. /***************************************************************************/
  887. /*
  888. * Start a single cycle wave.
  889. * Returns TRUE on success.
  890. */
  891. BOOL
  892. StartSingleWave(
  893. VOID
  894. )
  895. {
  896. HANDLE tHandle; // handle to single thread
  897. DWORD id;
  898. ULONG i;
  899. StopAutoWave(TRUE);
  900. DspMode = Single;
  901. if(!bDspActive) {
  902. dprintf2(("Starting single cycle wave"));
  903. if(!(tHandle = CreateThread(NULL, 0, SingleThreadEntry, NULL,
  904. CREATE_SUSPENDED, &id))) {
  905. dprintf1(("Create single cycle thread failed code %d", GetLastError()));
  906. return FALSE;
  907. } else {
  908. // set synchronization events to a known state
  909. InterlockedExchange(&bDspActive, TRUE);
  910. InterlockedExchange(&bDspPause, FALSE);
  911. InterlockedExchange(&bDspReset, FALSE);
  912. CloseHandle(SingleWaveSem);
  913. SingleWaveSem=CreateSemaphore(NULL, 1, 100, NULL);
  914. if(!SetThreadPriority(tHandle, THREAD_PRIORITY_HIGHEST)) {
  915. dprintf1(("Unable to set thread priority"));
  916. }
  917. ResumeThread(tHandle);
  918. CloseHandle(tHandle);
  919. WaitForSingleObject(ThreadStarted, INFINITE);
  920. return TRUE;
  921. }
  922. } else {
  923. ContinueDMA(); // if app has paused dma
  924. ReleaseSemaphore(SingleWaveSem, 1, NULL); // new buffer to be written
  925. return TRUE;
  926. }
  927. Sleep(500);
  928. }
  929. /***************************************************************************/
  930. /*
  931. * Stop single cycle thread,
  932. * Should always be called with TRUE,
  933. * except if process exiting as wait causes deadlock.
  934. */
  935. VOID
  936. StopSingleWave(
  937. BOOL wait
  938. )
  939. {
  940. if(bDspActive && (DspMode == Single)) {
  941. dprintf2(("Stopping single wave"));
  942. InterlockedExchange(&bDspReset, TRUE);
  943. ContinueDMA(); // if app has paused DMA
  944. ReleaseSemaphore(SingleWaveSem, 1, NULL);
  945. if(wait) {
  946. dprintf2(("Waiting for single thread to exit"));
  947. WaitForSingleObject(ThreadFinished, INFINITE);
  948. dprintf2(("Single thread has exited"));
  949. }
  950. }
  951. }
  952. /***************************************************************************/
  953. /*
  954. * GetWaveOutPosition
  955. */
  956. BOOL
  957. GetWaveOutPosition(
  958. PULONG pPos
  959. )
  960. {
  961. MMTIME mmTime;
  962. mmTime.wType = TIME_BYTES;
  963. if (MMSYSERR_NOERROR == GetPositionProc(HWaveOut, &mmTime, sizeof(MMTIME))) {
  964. VDM_TRACE(0x640, 0x640, mmTime.u.cb);
  965. *pPos = mmTime.u.cb;
  966. return TRUE;
  967. }
  968. return FALSE;
  969. }
  970. VOID
  971. WaitOnWaveOutIdle(
  972. VOID
  973. )
  974. {
  975. ULONG LastBytesPlayedValue = 0;
  976. ULONG PhysicalBytesPlayed;
  977. //
  978. // Allow the device to finish playing current sounds before nuking buffers
  979. //
  980. while(GetWaveOutPosition(&PhysicalBytesPlayed)) {
  981. if (LastBytesPlayedValue == PhysicalBytesPlayed) {
  982. break; // no sounds are playing
  983. }
  984. LastBytesPlayedValue = PhysicalBytesPlayed;
  985. Sleep(1);
  986. }
  987. }
  988. /***************************************************************************/
  989. /*
  990. * WriteBurst
  991. */
  992. BOOL
  993. WriteBurst(
  994. WAVEHDR * WaveHdr
  995. )
  996. {
  997. MMRESULT mmResult;
  998. // Copy data to current buffer
  999. dprintf3(("Copying data to buffer %8X from %4X", WaveHdr->lpData,
  1000. dMACurrentPosition));
  1001. RtlCopyMemory(WaveHdr->lpData,
  1002. (CONST VOID *)dMACurrentPosition,
  1003. WaveHdr->dwBufferLength);
  1004. dMACurrentPosition += WaveHdr->dwBufferLength;
  1005. // Update virtual DMA status
  1006. dMAInfo.count = (WORD)(dMASize - (dMACurrentPosition-dMAPhysicalStart));
  1007. dMAInfo.addr = (WORD)(dMAVirtualStart +
  1008. (dMACurrentPosition-dMAPhysicalStart));
  1009. dprintf3(("Updated Dma Position = %4X, count = %4X", dMAInfo.addr,
  1010. dMAInfo.count));
  1011. VDDSetDMA((HANDLE)GlobalHInstance, SB_DMA_CHANNEL,
  1012. VDD_DMA_COUNT|VDD_DMA_ADDR, &dMAInfo);
  1013. if(dMACurrentPosition >= dMAPhysicalStart+dMASize) {
  1014. // looped in DMA buffer
  1015. dMACurrentPosition = dMAPhysicalStart;
  1016. }
  1017. // Actually write the data
  1018. VDM_TRACE(0x603, (USHORT)WaveHdr->dwBufferLength, (ULONG)WaveHdr);
  1019. mmResult = WriteProc(HWaveOut, WaveHdr, sizeof(WAVEHDR));
  1020. return (mmResult == MMSYSERR_NOERROR);
  1021. }
  1022. /***************************************************************************/
  1023. /*
  1024. * GenerateHdrs
  1025. * Build an array of MM wavehdrs and corresponding buffers
  1026. */
  1027. #define AUTO TRUE
  1028. #define SINGLE FALSE
  1029. BOOL
  1030. GenerateHdrs(
  1031. BOOL bAuto
  1032. )
  1033. {
  1034. static ULONG committedMemorySize = 0;
  1035. ULONG DesiredCommit;
  1036. ULONG BurstBufferSize;
  1037. ULONG BlocksPerGroup = 1;
  1038. ULONG NumberOfGroups = 1;
  1039. ULONG BurstSize; // minimum(AUTO_BLOCK_SIZE, SBBLockSize+1)
  1040. ULONG lastBurst = 0; // the size of the last buffer
  1041. BYTE *pDataInit;
  1042. ULONG i;
  1043. if(AUTO_BLOCK_SIZE > SBBlockSize+1) { // block size is no > than SBBlockSize+1
  1044. BurstSize = SBBlockSize+1;
  1045. } else {
  1046. BurstSize = AUTO_BLOCK_SIZE;
  1047. }
  1048. DesiredBytesOutstanding = LookAheadFactor;
  1049. BurstsPerBlock = (SBBlockSize+1)/BurstSize;
  1050. BurstBufferSize = BurstsPerBlock*BurstSize;
  1051. if((lastBurst = (SBBlockSize+1)%BurstSize) > 0 ) {
  1052. BurstsPerBlock++;
  1053. BurstBufferSize+=lastBurst;
  1054. }
  1055. BlocksPerGroup = (dMASize+1)/(SBBlockSize+1);
  1056. if ((dMASize+1)%(SBBlockSize+1)) {
  1057. dprintf2(("Error: SB block size not an integral factor of DMA size"));
  1058. return FALSE;
  1059. }
  1060. NumberOfGroups = MAX_WAVE_BYTES / (dMASize+1);
  1061. if (!NumberOfGroups) {
  1062. NumberOfGroups = 1;
  1063. }
  1064. TotalNumberOfBursts = NumberOfGroups * BlocksPerGroup * BurstsPerBlock;
  1065. //
  1066. // Make sure the # of wavehdrs doesn't get out of hand
  1067. //
  1068. while((TotalNumberOfBursts > 256) && (NumberOfGroups > 1)) {
  1069. NumberOfGroups /= 2;
  1070. TotalNumberOfBursts = NumberOfGroups * BlocksPerGroup * BurstsPerBlock;
  1071. }
  1072. BurstBufferSize *= NumberOfGroups * BlocksPerGroup;
  1073. dprintf2(("%d groups of %d blocks of %d bursts of size %X, remainder burst=%X", NumberOfGroups, BlocksPerGroup, BurstsPerBlock, BurstSize, lastBurst));
  1074. DesiredCommit = ((BurstBufferSize+PageSize-1)/PageSize)*PageSize;
  1075. dprintf2(("Total burst buffer size is %X bytes, rounding to %X", BurstBufferSize, DesiredCommit));
  1076. if (DesiredCommit > committedMemorySize) {
  1077. if (!VirtualAlloc(WaveData+committedMemorySize,
  1078. DesiredCommit-committedMemorySize,
  1079. MEM_COMMIT,
  1080. PAGE_READWRITE)) {
  1081. dprintf1(("Unable to commit memory"));
  1082. return(FALSE);
  1083. }
  1084. committedMemorySize = DesiredCommit;
  1085. } else if (DesiredCommit < committedMemorySize) {
  1086. if (VirtualFree(WaveData+DesiredCommit,
  1087. committedMemorySize-DesiredCommit,
  1088. MEM_DECOMMIT)) {
  1089. committedMemorySize = DesiredCommit;
  1090. } else {
  1091. dprintf1(("Unable to decommit memory"));
  1092. }
  1093. }
  1094. // malloc autoWaveHdrs
  1095. WaveHdrs = (WAVEHDR *) VirtualAlloc(NULL,
  1096. TotalNumberOfBursts*sizeof(WAVEHDR),
  1097. MEM_RESERVE | MEM_COMMIT,
  1098. PAGE_READWRITE);
  1099. if(WaveHdrs == NULL) {
  1100. dprintf1(("Unable to allocate memory"));
  1101. return(FALSE);
  1102. }
  1103. //
  1104. // Prepare autoWaveHdrs
  1105. //
  1106. pDataInit = WaveData;
  1107. for (i=0; i<TotalNumberOfBursts; i++) {
  1108. if ((!lastBurst) || ((i+1) % BurstsPerBlock)) {
  1109. WaveHdrs[i].dwBufferLength = BurstSize;
  1110. } else {
  1111. WaveHdrs[i].dwBufferLength = lastBurst;
  1112. }
  1113. WaveHdrs[i].lpData = pDataInit;
  1114. WaveHdrs[i].dwFlags = 0;
  1115. PrepareHeaderProc(HWaveOut, &WaveHdrs[i], sizeof(WAVEHDR));
  1116. pDataInit = (BYTE *) ((ULONG)pDataInit + WaveHdrs[i].dwBufferLength);
  1117. BurstBufferSize += WaveHdrs[i].dwBufferLength;
  1118. }
  1119. //
  1120. // Initialize iHdr for DspProcessBlock
  1121. //
  1122. iHdr = TotalNumberOfBursts-1;
  1123. return TRUE;
  1124. }
  1125. /***************************************************************************/
  1126. /*
  1127. * ProcessBlock
  1128. * Process a single block of data as defined by the SB block transfer size
  1129. */
  1130. VOID
  1131. DspProcessBlock(
  1132. VOID
  1133. )
  1134. {
  1135. ULONG i;
  1136. // Write the data, keeping DMA status current
  1137. for (i=0; i<BurstsPerBlock; i++) {
  1138. //
  1139. // Make sure we aren't getting too far ahead
  1140. //
  1141. if (BytesOutstanding > (PhysicalBytesPlayed + DesiredBytesOutstanding)) {
  1142. LastBytesPlayedValue = 0;
  1143. while(1) {
  1144. if (!GetWaveOutPosition(&PhysicalBytesPlayed)) {
  1145. break; // ERROR
  1146. }
  1147. if (BytesOutstanding <= (PhysicalBytesPlayed + DesiredBytesOutstanding)) {
  1148. break;
  1149. }
  1150. if (LastBytesPlayedValue == PhysicalBytesPlayed) {
  1151. break; // no sounds are playing
  1152. }
  1153. LastBytesPlayedValue = PhysicalBytesPlayed;
  1154. Sleep(1);
  1155. }
  1156. }
  1157. //
  1158. // Queue next buffer
  1159. //
  1160. iHdr = (iHdr+1)%TotalNumberOfBursts;
  1161. VDM_TRACE(0x601, (USHORT)iHdr, TotalNumberOfBursts);
  1162. VDM_TRACE(0x602, (USHORT)iHdr, dMACurrentPosition);
  1163. if (WriteBurst(&WaveHdrs[iHdr])) {
  1164. BytesOutstanding += WaveHdrs[iHdr].dwBufferLength;
  1165. VDM_TRACE(0x604, (USHORT)iHdr, BytesOutstanding);
  1166. } else {
  1167. VDM_TRACE(0x684, (USHORT)iHdr, BytesOutstanding);
  1168. }
  1169. // Check if we should pause
  1170. if(bDspPause) {
  1171. dprintf3(("Waiting for paused event"));
  1172. WaitForSingleObject(PauseEvent, INFINITE);
  1173. dprintf3(("Paused event received"));
  1174. InterlockedExchange(&bDspPause, 0);
  1175. }
  1176. // Check if we should keep going
  1177. if(bDspReset) {
  1178. return;
  1179. }
  1180. }
  1181. // Check if we should keep going
  1182. if(bDspReset) {
  1183. return;
  1184. }
  1185. // Generate interrupt
  1186. if(dMAInfo.count==0xFFFF) { // end of DMA buffer
  1187. SetDMAStatus(FALSE, TRUE);
  1188. }
  1189. VDM_TRACE(0x6a3,0,0);
  1190. GenerateInterrupt();
  1191. //
  1192. // This sleep gives the app thread some time to catch up with the interrupt.
  1193. // Granted this is an inexact method for doing this, but it empirically
  1194. // seems to be good enough for most apps.
  1195. //
  1196. Sleep(1);
  1197. if(dMAInfo.count==0xFFFF) { // end of DMA buffer
  1198. SetDMAStatus(FALSE, FALSE);
  1199. }
  1200. }
  1201. /***************************************************************************/
  1202. /*
  1203. * Auto-init DMA thread.
  1204. */
  1205. DWORD WINAPI
  1206. AutoThreadEntry(
  1207. LPVOID context
  1208. )
  1209. {
  1210. ULONG i;
  1211. dprintf2(("Auto thread starting"));
  1212. VDM_TRACE(0x600, 0, 0);
  1213. bDspActive = TRUE;
  1214. SetEvent(ThreadStarted);
  1215. //
  1216. // Initialize DMA information
  1217. //
  1218. VDDQueryDMA((HANDLE)GlobalHInstance, SB_DMA_CHANNEL, &dMAInfo);
  1219. dMAVirtualStart = dMAInfo.addr;
  1220. dMASize = dMAInfo.count;
  1221. if((dMAPhysicalStart=GetDMATransferAddress()) == -1L) {
  1222. dprintf1(("Unable to get dma address"));
  1223. return(FALSE);
  1224. }
  1225. dprintf2(("DMA Physical Start is %4X, DMA size is %4X", dMAPhysicalStart,
  1226. dMASize));
  1227. dMACurrentPosition = dMAPhysicalStart;
  1228. SetDMAStatus(FALSE, FALSE);
  1229. //
  1230. // Calculate NumberOfBursts in the current run
  1231. //
  1232. if (!GenerateHdrs(AUTO)) {
  1233. return FALSE;
  1234. }
  1235. //
  1236. // Start looping on the buffer
  1237. //
  1238. while(!bDspReset) {
  1239. DspProcessBlock();
  1240. }
  1241. WaitOnWaveOutIdle();
  1242. //
  1243. // Reset and close the device
  1244. //
  1245. CloseWaveDevice();
  1246. // Clean up hdrs and events
  1247. for(i=0; (ULONG)i<TotalNumberOfBursts; i++) {
  1248. UnprepareHeaderProc(HWaveOut, &WaveHdrs[i], sizeof(WAVEHDR));
  1249. }
  1250. // Clean up memory
  1251. VirtualFree(WaveHdrs, 0, MEM_RELEASE);
  1252. bDspActive = FALSE;
  1253. SetEvent(ThreadFinished);
  1254. dprintf2(("Auto thread exiting"));
  1255. return(0);
  1256. }
  1257. /***************************************************************************/
  1258. /*
  1259. * Single cycle DMA thread.
  1260. */
  1261. DWORD WINAPI
  1262. SingleThreadEntry(
  1263. LPVOID context
  1264. )
  1265. {
  1266. ULONG LastSBBlockSize = 0;
  1267. BOOL BlockSizeChanged; // set to TRUE if Size has changed
  1268. BOOL WaveFormatChanged;
  1269. BOOL HdrsInvalid = TRUE;
  1270. ULONG i;
  1271. dprintf2(("Single cycle thread starting"));
  1272. bDspActive = TRUE;
  1273. SetEvent(ThreadStarted);
  1274. while (!bDspReset) {
  1275. // Wait until app wants to transfer more data
  1276. dprintf3(("Waiting for single wave semaphore"));
  1277. WaitForSingleObject(SingleWaveSem, INFINITE);
  1278. dprintf3(("Single wave semaphore received"));
  1279. // Check if we should pause
  1280. if(bDspPause) {
  1281. dprintf3(("Waiting for paused event"));
  1282. WaitForSingleObject(PauseEvent, INFINITE);
  1283. dprintf3(("Paused event received"));
  1284. InterlockedExchange(&bDspPause, 0);
  1285. }
  1286. // Check if we should keep going
  1287. if(bDspReset) {
  1288. break; // break out of loop
  1289. }
  1290. // Initialize for this run
  1291. VDDQueryDMA((HANDLE)GlobalHInstance, SB_DMA_CHANNEL, &dMAInfo);
  1292. dprintf4(("DMA Info : addr %4X, count %4X, page %4X, status %2X, mode %2X, mask %2X",
  1293. dMAInfo.addr, dMAInfo.count, dMAInfo.page, dMAInfo.status,
  1294. dMAInfo.mode, dMAInfo.mask));
  1295. dMAVirtualStart = dMAInfo.addr;
  1296. dMASize = dMAInfo.count;
  1297. if(dMAInfo.count == 0xFFFF || dMAInfo.count == 0) {
  1298. continue; // next iteration of loop, app doesn't have data to transfer
  1299. }
  1300. if ((dMAPhysicalStart = GetDMATransferAddress()) == -1L) {
  1301. dprintf1(("Unable to get transfer address"));
  1302. continue; // next iteration of loop
  1303. }
  1304. dprintf3(("DMA Physical Start is %4X, DMA size is %4X",
  1305. dMAPhysicalStart, dMASize));
  1306. dMACurrentPosition = dMAPhysicalStart;
  1307. if(LastSBBlockSize != SBBlockSize) {
  1308. LastSBBlockSize = SBBlockSize;
  1309. BlockSizeChanged = TRUE;
  1310. } else {
  1311. BlockSizeChanged = FALSE;
  1312. }
  1313. WaveFormatChanged = SetWaveFormat();
  1314. // If we're changing our device
  1315. if ((WaveFormatChanged || BlockSizeChanged) && (HWaveOut != NULL)) {
  1316. dprintf3(("Single-Cycle Parameters changed"));
  1317. WaitOnWaveOutIdle();
  1318. HdrsInvalid = TRUE;
  1319. for(i=0; (ULONG)i<TotalNumberOfBursts; i++) {
  1320. UnprepareHeaderProc(HWaveOut, &WaveHdrs[i], sizeof(WAVEHDR));
  1321. }
  1322. VirtualFree(WaveHdrs, 0, MEM_RELEASE);
  1323. if (WaveFormatChanged) {
  1324. CloseWaveDevice();
  1325. }
  1326. }
  1327. if (HWaveOut == NULL) {
  1328. OpenWaveDevice();
  1329. }
  1330. if (HdrsInvalid) {
  1331. if (GenerateHdrs(SINGLE)) {
  1332. HdrsInvalid = FALSE;
  1333. } else {
  1334. return FALSE;
  1335. }
  1336. }
  1337. // show dma as requesting
  1338. SetDMAStatus(TRUE, FALSE);
  1339. DspProcessBlock();
  1340. }
  1341. WaitOnWaveOutIdle();
  1342. //
  1343. // Reset and close the device
  1344. //
  1345. CloseWaveDevice();
  1346. // Clean up hdrs and events
  1347. for(i=0; (ULONG)i<TotalNumberOfBursts; i++) {
  1348. UnprepareHeaderProc(HWaveOut, &WaveHdrs[i], sizeof(WAVEHDR));
  1349. }
  1350. // Clean up memory
  1351. VirtualFree(WaveHdrs, 0, MEM_RELEASE);
  1352. bDspActive = FALSE;
  1353. SetEvent(ThreadFinished);
  1354. dprintf2(("Single cycle wave is exiting"));
  1355. return(0);
  1356. }