5 #define Function _Function
7 #define WIN32_LEAN_AND_MEAN
8 #define MessageBox _MessageBox
10 #define String _String
26 public void AudioSetBalance(double percent)
29 streamingSound.balance = percent;
32 static HWAVEOUT hWaveOut;
35 public void OpenMixer()
37 WAVEFORMATEX waveFormat = { 0 };
38 waveFormat.nSamplesPerSec = 44100; //(cur_stream && cur_stream->audio_st && cur_stream->audio_st->codec) ? cur_stream->audio_st->codec->sample_rate : 44100;
39 waveFormat.wBitsPerSample = 16;
40 waveFormat.nChannels = 2;
41 waveFormat.cbSize = 0;
42 waveFormat.wFormatTag = WAVE_FORMAT_PCM;
43 waveFormat.nBlockAlign = (uint16)((waveFormat.wBitsPerSample >> 3) * waveFormat.nChannels);
44 waveFormat.nAvgBytesPerSec = waveFormat.nBlockAlign * waveFormat.nSamplesPerSec;
46 waveOutOpen(&hWaveOut, WAVE_MAPPER, &waveFormat, 0, 0, CALLBACK_NULL);
47 mixerOpen((HMIXER *)&hmx, (uint)(uintptr)hWaveOut, 0, 0, MIXER_OBJECTF_HWAVEOUT);
50 public void CloseMixer()
52 mixerClose((HMIXER)hmx);
53 waveOutClose(hWaveOut);
56 public bool AudioSetVolume(VolumeControl type, double percent)
59 if(type == application)
63 streamingSound.volume = percent;
71 // waveOutSetVolume((HWAVEOUT)0, (uint)(percent * 0xFFFF) | ((uint)(percent * 0xFFFF) << 16));
73 uMixerLine.cbStruct = sizeof(MIXERLINE);
74 uMixerLine.dwComponentType = (type == pcm) ? MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT : MIXERLINE_COMPONENTTYPE_DST_SPEAKERS;
75 if(mixerGetLineInfo(hmx, &uMixerLine, MIXER_GETLINEINFOF_COMPONENTTYPE) == MMSYSERR_NOERROR)
77 MIXERLINECONTROLS uMixerLineControls;
78 MIXERCONTROL mixerControl;
80 uMixerLineControls.cbStruct = sizeof(MIXERLINECONTROLS);
81 uMixerLineControls.dwLineID = uMixerLine.dwLineID;
82 uMixerLineControls.dwControlID = MIXERCONTROL_CONTROLTYPE_VOLUME;
83 uMixerLineControls.cControls = 1;
84 uMixerLineControls.cbmxctrl = sizeof(MIXERCONTROL);
85 uMixerLineControls.pamxctrl = &mixerControl;
86 if(mixerGetLineControls(hmx, &uMixerLineControls, MIXER_GETLINECONTROLSF_ONEBYTYPE) == MMSYSERR_NOERROR)
88 MIXERCONTROLDETAILS uDetails;
91 uDetails.cMultipleItems = 0;
92 uDetails.dwControlID = mixerControl.dwControlID;
93 uDetails.cbStruct = sizeof(MIXERCONTROLDETAILS);
94 uDetails.cbDetails = sizeof(uint);
95 uDetails.paDetails = &value;
96 uDetails.cChannels = 1;
97 value = (uint)(percent * mixerControl.Bounds.lMaximum);
98 mixerSetControlDetails(hmx, &uDetails, MIXER_SETCONTROLDETAILSF_VALUE);
106 public bool AudioGetVolume(VolumeControl type, double * percent)
109 if(type == application)
113 *percent = streamingSound.volume;
119 MIXERLINE uMixerLine;
121 uMixerLine.cbStruct = sizeof(MIXERLINE);
122 uMixerLine.dwComponentType = (type == pcm) ? MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT : MIXERLINE_COMPONENTTYPE_DST_SPEAKERS;
123 if(mixerGetLineInfo(hmx, &uMixerLine, MIXER_GETLINEINFOF_COMPONENTTYPE) == MMSYSERR_NOERROR)
125 MIXERLINECONTROLS uMixerLineControls;
126 MIXERCONTROL mixerControl;
128 uMixerLineControls.cbStruct = sizeof(MIXERLINECONTROLS);
129 uMixerLineControls.dwLineID = uMixerLine.dwLineID;
130 uMixerLineControls.dwControlID = MIXERCONTROL_CONTROLTYPE_VOLUME;
131 uMixerLineControls.cControls = 1;
132 uMixerLineControls.cbmxctrl = sizeof(MIXERCONTROL);
134 uMixerLineControls.pamxctrl = &mixerControl;
135 if(mixerGetLineControls(hmx, &uMixerLineControls, MIXER_GETLINECONTROLSF_ONEBYTYPE) == MMSYSERR_NOERROR)
137 MIXERCONTROLDETAILS uDetails;
140 uDetails.cMultipleItems = 0;
141 uDetails.dwControlID = mixerControl.dwControlID;
142 uDetails.cbStruct = sizeof(MIXERCONTROLDETAILS);
143 uDetails.cbDetails = sizeof(uint);
144 uDetails.paDetails = &value;
145 uDetails.cChannels = 1;
146 mixerGetControlDetails(hmx, &uDetails, MIXER_SETCONTROLDETAILSF_VALUE);
147 *percent = (double)value / mixerControl.Bounds.lMaximum;
155 public int OpenAudio(AudioSpec wanted, AudioSpec result)
157 #define NUM_PLAY_NOTIFICATIONS 16
158 uint nBlockAlign, dwNotifySize;
160 delete streamingSound;
162 g_pSoundManager.Initialize(wanted.windowHandle);
163 g_pSoundManager.SetPrimaryBufferFormat(wanted.channels, wanted.freq, wanted.bits);
167 nBlockAlign = wanted.bits / 8 * wanted.channels;
168 // dwNotifySize = 16384 / NUM_PLAY_NOTIFICATIONS; //wanted.freq * 3 * nBlockAlign / NUM_PLAY_NOTIFICATIONS;
169 dwNotifySize = wanted.freq / 2 / NUM_PLAY_NOTIFICATIONS; //wanted.freq * 3 * nBlockAlign / NUM_PLAY_NOTIFICATIONS;
170 dwNotifySize -= dwNotifySize % nBlockAlign;
172 result.size = dwNotifySize * NUM_PLAY_NOTIFICATIONS;
174 g_pSoundManager.InitStreaming(&streamingSound, NUM_PLAY_NOTIFICATIONS, dwNotifySize, dSoundThread.g_hNotificationEvent,
175 (void *)wanted.callback, wanted.userdata, wanted.channels, wanted.freq, wanted.bits);
178 streamingSound.volume = wanted.volume;
179 dSoundThread.bDone = false;
181 //dSoundThread.Create();
187 public void PauseAudio(int value)
192 dSoundThread.Create();
196 public void CloseAudio()
200 dSoundThread.bDone = true;
201 SetEvent(dSoundThread.g_hNotificationEvent);
204 delete streamingSound;
207 static bool PlayBuffer( bool bLooped )
213 if(streamingSound.Reset())
216 //pDSB = streamingSound.GetBuffer( 0 );
218 SetEvent(dSoundThread.g_hNotificationEvent);
222 static class StreamingSound
224 IDirectSoundBuffer ** apDSBuffer;
225 IDirectSoundBuffer * pDSB;
229 uint dwCreationFlags;
233 uint dwNextWriteOffset;
234 bool bFillNextNotificationWithSilence;
235 void (*callback)(void * data, void * buffer, int len);
239 public property double volume
243 int vol = (int)(20 * log10(value) * 100);
244 vol = Max(-10000, vol);
245 IDirectSoundBuffer_SetVolume(apDSBuffer[0], vol);
254 public property double balance
258 int pan = -2173 + (int)(value * 2173 * 2);
259 IDirectSoundBuffer_SetPan(apDSBuffer[0], pan);
263 property uint dwNumBuffers
267 dwNumBuffers = value;
268 apDSBuffer = new0 IDirectSoundBuffer *[dwNumBuffers];
272 property IDirectSoundBuffer ** apDSBuffer
279 for( i=0; i<dwNumBuffers; i++ )
280 apDSBuffer[i] = value[i];
288 for( i=0; i<dwNumBuffers; i++ )
292 IDirectSoundBuffer_Release( apDSBuffer[i] );
297 delete( apDSBuffer );
300 int RestoreBuffer( IDirectSoundBuffer * pDSB, bool* pbWasRestored )
306 return CO_E_NOTINITIALIZED;
308 *pbWasRestored = false;
310 if( FAILED( hr = IDirectSoundBuffer_GetStatus(pDSB, &dwStatus) ) )
311 return 1; //DXUT_ERR( L"GetStatus", hr );
313 if( dwStatus & DSBSTATUS_BUFFERLOST )
315 // Since the app could have just been activated, then
316 // DirectSound may not be giving us control yet, so
317 // the restoring the buffer may fail.
318 // If it does, sleep until DirectSound gives us control.
321 hr = IDirectSoundBuffer_Restore(pDSB);
322 if( hr == DSERR_BUFFERLOST )
325 while( ( hr = IDirectSoundBuffer_Restore(pDSB) ) == DSERR_BUFFERLOST );
327 if( pbWasRestored != null )
328 *pbWasRestored = true;
334 return S_OK; //FALSE;
338 IDirectSoundBuffer * GetFreeBuffer()
344 for( i=0; i<dwNumBuffers; i++ )
349 IDirectSoundBuffer_GetStatus(apDSBuffer[i], &dwStatus );
350 if ( ( dwStatus & DSBSTATUS_PLAYING ) == 0 )
355 if( i != dwNumBuffers )
356 return apDSBuffer[ i ];
358 return apDSBuffer[ rand() % dwNumBuffers ];
361 IDirectSoundBuffer * GetBuffer( uint dwIndex )
363 if( apDSBuffer == null )
365 if( dwIndex >= dwNumBuffers )
368 return apDSBuffer[dwIndex];
371 int Play( uint dwPriority, uint dwFlags, uint lVolume, uint lFrequency, uint lPan )
376 //IDirectSoundBuffer * pDSB;
378 // For Streaming Sound
379 dwFlags |= DSBPLAY_LOOPING;
381 if( apDSBuffer == null )
382 return CO_E_NOTINITIALIZED;
384 pDSB = GetFreeBuffer();
387 return 1; //DXUT_ERR( L"GetFreeBuffer", E_FAIL );
389 // Restore the buffer if it was lost
390 if( FAILED( hr = RestoreBuffer( pDSB, &bRestored ) ) )
391 return 1; //DXUT_ERR( L"RestoreBuffer", hr );
395 // The buffer was restored, so we need to fill it with new data
396 if( FAILED( hr = FillBufferWithSound( pDSB, false ) ) )
397 return 1; //DXUT_ERR( L"FillBufferWithSound", hr );
400 if( dwCreationFlags & DSBCAPS_CTRLVOLUME )
402 //IDirectSoundBuffer_SetVolume(pDSB, lVolume);
405 if( lFrequency != -1 &&
406 (dwCreationFlags & DSBCAPS_CTRLFREQUENCY) )
408 IDirectSoundBuffer_SetFrequency(pDSB, lFrequency);
411 if( dwCreationFlags & DSBCAPS_CTRLPAN )
413 //IDirectSoundBuffer_SetPan(pDSB, lPan);
415 result = IDirectSoundBuffer_Play(pDSB, 0, dwPriority, dwFlags);
424 if( apDSBuffer == null )
425 return CO_E_NOTINITIALIZED;
427 for( i=0; i<dwNumBuffers; i++ )
428 hr |= IDirectSoundBuffer_Stop(apDSBuffer[i]);
434 bool HandleWaveStreamNotification( )
436 DWORD dwCurrentPlayPos;
437 void * pDSLockedBuffer = null;
438 void * pDSLockedBuffer2 = null;
439 DWORD dwDSLockedBufferSize;
440 DWORD dwDSLockedBufferSize2;
441 uint playCursor, writeCursor;
450 // Figure out how much data has been played so far. When we have played
451 // past the end of the file, we will either need to start filling the
452 // buffer with silence or starting reading from the beginning of the file,
453 // depending if the user wants to loop the sound
454 if(IDirectSoundBuffer_GetCurrentPosition(apDSBuffer[0], &dwCurrentPlayPos, null))
458 playCursor = (dwCurrentPlayPos / dwNotifySize);
459 writeCursor = dwNextWriteOffset;
461 //printf("Play Cursor : %d, Write Cursor %d\n", playCursor, writeCursor);
462 if(writeCursor > playCursor)
465 size = (dwDSBufferSize / dwNotifySize) - start;
466 for(c = start; c<start + size; c++)
470 //printf("Writing %d - %d\n", c, c);
471 IDirectSoundBuffer_Lock(apDSBuffer[0], c * dwNotifySize, 1 * dwNotifySize, &pDSLockedBuffer, &dwDSLockedBufferSize, &pDSLockedBuffer2, &dwDSLockedBufferSize2, 0L);
472 //printf("In callback...");
473 callback(data, pDSLockedBuffer, dwDSLockedBufferSize);
475 IDirectSoundBuffer_Unlock(apDSBuffer[0], pDSLockedBuffer, dwDSLockedBufferSize, null, 0 );
476 dwNextWriteOffset = 0;
483 for(c = start; c<start + size; c++)
487 //printf("Writing %d - %d\n", c, c);
488 IDirectSoundBuffer_Lock(apDSBuffer[0], c * dwNotifySize, 1 * dwNotifySize, &pDSLockedBuffer, &dwDSLockedBufferSize, &pDSLockedBuffer2, &dwDSLockedBufferSize2, 0L);
489 //printf("In callback...");
490 callback(data, pDSLockedBuffer, dwDSLockedBufferSize);
492 IDirectSoundBuffer_Unlock(apDSBuffer[0], pDSLockedBuffer, dwDSLockedBufferSize, null, 0 );
493 dwNextWriteOffset = (playCursor) % (dwDSBufferSize / dwNotifySize);
500 size = playCursor - writeCursor;
501 for(c = start; c<start + size; c++)
505 //printf("Writing %d - %d\n", c, c);
506 IDirectSoundBuffer_Lock(apDSBuffer[0], c * dwNotifySize, 1 * dwNotifySize, &pDSLockedBuffer, &dwDSLockedBufferSize, &pDSLockedBuffer2, &dwDSLockedBufferSize2, 0L);
507 //printf("In callback...");
508 callback(data, pDSLockedBuffer, dwDSLockedBufferSize);
510 IDirectSoundBuffer_Unlock(apDSBuffer[0], pDSLockedBuffer, dwDSLockedBufferSize, null, 0 );
511 dwNextWriteOffset = (playCursor) % (dwDSBufferSize / dwNotifySize);
514 //printf("Next Offset: %d\n", dwNextWriteOffset);
529 dwNextWriteOffset = 0;
530 bFillNextNotificationWithSilence = false;
532 // Restore the buffer if it was lost
533 if(RestoreBuffer( apDSBuffer[0], &bRestored ))
538 // The buffer was restored, so we need to fill it with new data
539 if(FillBufferWithSound( apDSBuffer[0], false))
543 result = IDirectSoundBuffer_SetCurrentPosition(apDSBuffer[0], 0L );
547 int FillBufferWithSound( IDirectSoundBuffer * pDSB, bool bRepeatWavIfBufferLarger )
549 void * pDSLockedBuffer = null; // Pointer to locked buffer memory
550 DWORD dwDSLockedBufferSize = 0; // Size of the locked DirectSound buffer
553 return CO_E_NOTINITIALIZED;
555 // Make sure we have focus, and we didn't just switch in from
556 // an app which had a DirectSound device
557 if(RestoreBuffer( pDSB, null ))
560 // Lock the buffer down
561 if(IDirectSoundBuffer_Lock(pDSB, 0, dwDSBufferSize, &pDSLockedBuffer, &dwDSLockedBufferSize, null, null, 0L ))
564 callback(data, pDSLockedBuffer, dwDSLockedBufferSize);
566 // printf("Filling 16 spots\n");
567 IDirectSoundBuffer_Unlock(pDSB, pDSLockedBuffer, dwDSLockedBufferSize, null, 0 );
569 //dwNextWriteOffset = dwNotifySize*2;
574 static class CSoundManager
581 IDirectSound_Release( pDS );
584 int Initialize( void * hWnd )
590 IDirectSound_Release( pDS );
594 // Create IDirectSound using the primary sound device
595 if( FAILED( hr = DirectSoundCreate8( null, &pDS, null ) ) )
596 return 1; //DXUT_ERR( L"DirectSoundCreate8", hr );
598 // Set DirectSound coop level
599 if( FAILED( hr = IDirectSound_SetCooperativeLevel(pDS, hWnd, DSSCL_PRIORITY ) ) )
600 return 1; //DXUT_ERR( L"SetCooperativeLevel", hr );
606 int SetPrimaryBufferFormat( uint dwPrimaryChannels, uint dwPrimaryFreq, uint dwPrimaryBitRate )
609 IDirectSoundBuffer * pDSBPrimary = null;
614 return CO_E_NOTINITIALIZED;
616 // Get the primary buffer
617 ZeroMemory( &dsbd, sizeof(DSBUFFERDESC) );
618 dsbd.dwSize = sizeof(DSBUFFERDESC);
619 dsbd.dwFlags = DSBCAPS_PRIMARYBUFFER | DSBCAPS_CTRLPAN | DSBCAPS_CTRLVOLUME;
620 dsbd.dwBufferBytes = 0;
621 dsbd.lpwfxFormat = null;
623 if( FAILED( hr = IDirectSound_CreateSoundBuffer(pDS, &dsbd, &pDSBPrimary, null ) ) )
624 return 1; // DXUT_ERR( L"CreateSoundBuffer", hr );
626 ZeroMemory( &wfx, sizeof(WAVEFORMATEX) );
627 wfx.wFormatTag = (WORD) WAVE_FORMAT_PCM;
628 wfx.nChannels = (WORD) dwPrimaryChannels;
629 wfx.nSamplesPerSec = (uint) dwPrimaryFreq;
630 wfx.wBitsPerSample = (WORD) dwPrimaryBitRate;
631 wfx.nBlockAlign = (WORD) (wfx.wBitsPerSample / 8 * wfx.nChannels);
632 wfx.nAvgBytesPerSec = (uint) (wfx.nSamplesPerSec * wfx.nBlockAlign);
634 if( FAILED( hr = IDirectSoundBuffer_SetFormat(pDSBPrimary, &wfx) ) )
635 return 1; //DXUT_ERR( L"SetFormat", hr );
639 IDirectSoundBuffer_Release( pDSBPrimary );
646 bool InitStreaming(StreamingSound * ppStreamingSound, uint dwNotifyCount, uint dwNotifySize, void * hNotifyEvent,
647 void (*callback)(void * data, void * buffer, int len), void * data, int nChannels, int freq,int bits)
649 IDirectSoundBuffer * pDSBuffer = null;
650 uint dwDSBufferSize = 0;
651 DSBPOSITIONNOTIFY * aPosNotify = null;
652 IDirectSoundNotify * pDSNotify = null;
658 if(!ppStreamingSound || !hNotifyEvent)
661 dwDSBufferSize = dwNotifySize * dwNotifyCount;
663 ZeroMemory( &dsbd, sizeof(DSBUFFERDESC) );
664 dsbd.dwSize= sizeof(DSBUFFERDESC);
665 dsbd.dwFlags = DSBCAPS_GLOBALFOCUS | DSBCAPS_CTRLPOSITIONNOTIFY | DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLPAN | DSBCAPS_CTRLVOLUME;
666 dsbd.dwBufferBytes = dwDSBufferSize;
667 dsbd.guid3DAlgorithm = DS3DALG_DEFAULT;
668 dsbd.lpwfxFormat = new0 WAVEFORMATEX[1];
669 dsbd.lpwfxFormat->wFormatTag = WAVE_FORMAT_PCM;
670 dsbd.lpwfxFormat->nChannels = (uint16)nChannels;
671 dsbd.lpwfxFormat->nSamplesPerSec = freq;
672 dsbd.lpwfxFormat->wBitsPerSample = (uint16)bits;
673 dsbd.lpwfxFormat->nBlockAlign = dsbd.lpwfxFormat->nChannels * dsbd.lpwfxFormat->wBitsPerSample / 8;
674 dsbd.lpwfxFormat->nAvgBytesPerSec = dsbd.lpwfxFormat->nSamplesPerSec * dsbd.lpwfxFormat->nBlockAlign;
676 if(IDirectSound_CreateSoundBuffer(pDS, &dsbd, &pDSBuffer, null))
678 delete dsbd.lpwfxFormat;
681 delete dsbd.lpwfxFormat;
683 if(IDirectSoundBuffer_QueryInterface(pDSBuffer, &IID_IDirectSoundNotify, (void**)&pDSNotify))
689 aPosNotify = new DSBPOSITIONNOTIFY[ dwNotifyCount ];
690 if( aPosNotify == null )
693 for( i = 0; i < dwNotifyCount; i++ )
695 aPosNotify[i].dwOffset = (dwNotifySize * i) + dwNotifySize - 1;
696 aPosNotify[i].hEventNotify = hNotifyEvent;
699 if(IDirectSoundNotify_SetNotificationPositions(pDSNotify, dwNotifyCount, aPosNotify ))
702 IDirectSoundNotify_Release(pDSNotify);
703 delete( aPosNotify );
708 IDirectSoundNotify_Release(pDSNotify);
711 *ppStreamingSound = StreamingSound
713 dwCreationFlags = DSBCAPS_CTRLPAN|DSBCAPS_CTRLVOLUME, dwNumBuffers = 1, dwNotifySize = dwNotifySize, dwDSBufferSize = dwDSBufferSize, apDSBuffer = &pDSBuffer,
715 callback = callback, data = data
717 // ppStreamingSound->FillBufferWithSound( pDSBuffer, false );
722 static DSoundThread dSoundThread { };
724 static CSoundManager g_pSoundManager { };
725 static StreamingSound streamingSound;
727 static class DSoundThread : Thread
729 void * g_hNotificationEvent;
733 g_hNotificationEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
737 CloseHandle( g_hNotificationEvent );
742 SetPriority(timeCritical);
745 WaitForSingleObject(g_hNotificationEvent, INFINITE);
750 streamingSound.FillBufferWithSound( streamingSound.GetBuffer( 0 ), false );
751 streamingSound.Play( 0, 0, 0, -1, 0);
754 else if(!streamingSound.HandleWaveStreamNotification())