5 #define Function _Function
7 #define WIN32_LEAN_AND_MEAN
8 #define MessageBox _MessageBox
22 void AudioSetBalance(double percent)
25 streamingSound.balance = percent;
28 static HWAVEOUT hWaveOut;
34 WAVEFORMATEX waveFormat = { 0 };
35 waveFormat.nSamplesPerSec = 44100; //(cur_stream && cur_stream->audio_st && cur_stream->audio_st->codec) ? cur_stream->audio_st->codec->sample_rate : 44100;
36 waveFormat.wBitsPerSample = 16;
37 waveFormat.nChannels = 2;
38 waveFormat.cbSize = 0;
39 waveFormat.wFormatTag = WAVE_FORMAT_PCM;
40 waveFormat.nBlockAlign = (waveFormat.wBitsPerSample >> 3) * waveFormat.nChannels;
41 waveFormat.nAvgBytesPerSec = waveFormat.nBlockAlign * waveFormat.nSamplesPerSec;
43 waveOutOpen(&hWaveOut, WAVE_MAPPER, &waveFormat, 0, 0, CALLBACK_NULL);
44 mixerOpen((HMIXER *)&hmx, (uint)hWaveOut, 0, 0, MIXER_OBJECTF_HWAVEOUT);
49 mixerClose((HMIXER)hmx);
50 waveOutClose(hWaveOut);
53 bool AudioSetVolume(VolumeControl type, double percent)
56 if(type == application)
60 streamingSound.volume = percent;
68 // waveOutSetVolume((HWAVEOUT)0, (uint)(percent * 0xFFFF) | ((uint)(percent * 0xFFFF) << 16));
70 uMixerLine.cbStruct = sizeof(MIXERLINE);
71 uMixerLine.dwComponentType = (type == pcm) ? MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT : MIXERLINE_COMPONENTTYPE_DST_SPEAKERS;
72 if(mixerGetLineInfo(hmx, &uMixerLine, MIXER_GETLINEINFOF_COMPONENTTYPE) == MMSYSERR_NOERROR)
74 MIXERLINECONTROLS uMixerLineControls;
75 MIXERCONTROL mixerControl;
77 uMixerLineControls.cbStruct = sizeof(MIXERLINECONTROLS);
78 uMixerLineControls.dwLineID = uMixerLine.dwLineID;
79 uMixerLineControls.dwControlID = MIXERCONTROL_CONTROLTYPE_VOLUME;
80 uMixerLineControls.cControls = 1;
81 uMixerLineControls.cbmxctrl = sizeof(MIXERCONTROL);
82 uMixerLineControls.pamxctrl = &mixerControl;
83 if(mixerGetLineControls(hmx, &uMixerLineControls, MIXER_GETLINECONTROLSF_ONEBYTYPE) == MMSYSERR_NOERROR)
85 MIXERCONTROLDETAILS uDetails;
88 uDetails.cMultipleItems = 0;
89 uDetails.dwControlID = mixerControl.dwControlID;
90 uDetails.cbStruct = sizeof(MIXERCONTROLDETAILS);
91 uDetails.cbDetails = sizeof(uint);
92 uDetails.paDetails = &value;
93 uDetails.cChannels = 1;
94 value = (uint)(percent * mixerControl.Bounds.lMaximum);
95 mixerSetControlDetails(hmx, &uDetails, MIXER_SETCONTROLDETAILSF_VALUE);
103 bool AudioGetVolume(VolumeControl type, double * percent)
106 if(type == application)
110 *percent = streamingSound.volume;
116 MIXERLINE uMixerLine;
118 uMixerLine.cbStruct = sizeof(MIXERLINE);
119 uMixerLine.dwComponentType = (type == pcm) ? MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT : MIXERLINE_COMPONENTTYPE_DST_SPEAKERS;
120 if(mixerGetLineInfo(hmx, &uMixerLine, MIXER_GETLINEINFOF_COMPONENTTYPE) == MMSYSERR_NOERROR)
122 MIXERLINECONTROLS uMixerLineControls;
123 MIXERCONTROL mixerControl;
125 uMixerLineControls.cbStruct = sizeof(MIXERLINECONTROLS);
126 uMixerLineControls.dwLineID = uMixerLine.dwLineID;
127 uMixerLineControls.dwControlID = MIXERCONTROL_CONTROLTYPE_VOLUME;
128 uMixerLineControls.cControls = 1;
129 uMixerLineControls.cbmxctrl = sizeof(MIXERCONTROL);
131 uMixerLineControls.pamxctrl = &mixerControl;
132 if(mixerGetLineControls(hmx, &uMixerLineControls, MIXER_GETLINECONTROLSF_ONEBYTYPE) == MMSYSERR_NOERROR)
134 MIXERCONTROLDETAILS uDetails;
137 uDetails.cMultipleItems = 0;
138 uDetails.dwControlID = mixerControl.dwControlID;
139 uDetails.cbStruct = sizeof(MIXERCONTROLDETAILS);
140 uDetails.cbDetails = sizeof(uint);
141 uDetails.paDetails = &value;
142 uDetails.cChannels = 1;
143 mixerGetControlDetails(hmx, &uDetails, MIXER_SETCONTROLDETAILSF_VALUE);
144 *percent = (double)value / mixerControl.Bounds.lMaximum;
152 int OpenAudio(AudioSpec wanted, AudioSpec result)
154 #define NUM_PLAY_NOTIFICATIONS 16
155 uint nBlockAlign, dwNotifySize;
157 delete streamingSound;
159 g_pSoundManager.Initialize(wanted.windowHandle);
160 g_pSoundManager.SetPrimaryBufferFormat(wanted.channels, wanted.freq, wanted.bits);
164 nBlockAlign = wanted.bits / 8 * wanted.channels;
165 // dwNotifySize = 16384 / NUM_PLAY_NOTIFICATIONS; //wanted.freq * 3 * nBlockAlign / NUM_PLAY_NOTIFICATIONS;
166 dwNotifySize = wanted.freq / 2 / NUM_PLAY_NOTIFICATIONS; //wanted.freq * 3 * nBlockAlign / NUM_PLAY_NOTIFICATIONS;
167 dwNotifySize -= dwNotifySize % nBlockAlign;
169 result.size = dwNotifySize * NUM_PLAY_NOTIFICATIONS;
171 g_pSoundManager.InitStreaming(&streamingSound, NUM_PLAY_NOTIFICATIONS, dwNotifySize, dSoundThread.g_hNotificationEvent,
172 wanted.callback, wanted.userdata, wanted.channels, wanted.freq, wanted.bits);
175 streamingSound.volume = wanted.volume;
176 dSoundThread.bDone = false;
178 //dSoundThread.Create();
184 void PauseAudio(int value)
189 dSoundThread.Create();
197 dSoundThread.bDone = true;
198 SetEvent(dSoundThread.g_hNotificationEvent);
201 delete streamingSound;
204 static bool PlayBuffer( bool bLooped )
210 if(streamingSound.Reset())
213 pDSB = streamingSound.GetBuffer( 0 );
215 SetEvent(dSoundThread.g_hNotificationEvent);
219 static class StreamingSound
221 IDirectSoundBuffer ** apDSBuffer;
222 IDirectSoundBuffer * pDSB;
226 uint dwCreationFlags;
230 uint dwNextWriteOffset;
231 bool bFillNextNotificationWithSilence;
232 void (*callback)(void * data, void * buffer, int len);
236 public property double volume
240 int vol = (int)(20 * log10(value) * 100);
241 vol = Max(-10000, vol);
242 IDirectSoundBuffer_SetVolume(apDSBuffer[0], vol);
251 public property double balance
255 int pan = -2173 + (int)(value * 2173 * 2);
256 IDirectSoundBuffer_SetPan(apDSBuffer[0], pan);
260 property uint dwNumBuffers
264 dwNumBuffers = value;
265 apDSBuffer = new0 IDirectSoundBuffer *[dwNumBuffers];
269 property IDirectSoundBuffer ** apDSBuffer
276 for( i=0; i<dwNumBuffers; i++ )
277 apDSBuffer[i] = value[i];
285 for( i=0; i<dwNumBuffers; i++ )
289 IDirectSoundBuffer_Release( apDSBuffer[i] );
294 delete( apDSBuffer );
297 int RestoreBuffer( IDirectSoundBuffer * pDSB, bool* pbWasRestored )
303 return CO_E_NOTINITIALIZED;
305 *pbWasRestored = false;
307 if( FAILED( hr = IDirectSoundBuffer_GetStatus(pDSB, &dwStatus) ) )
308 return 1; //DXUT_ERR( L"GetStatus", hr );
310 if( dwStatus & DSBSTATUS_BUFFERLOST )
312 // Since the app could have just been activated, then
313 // DirectSound may not be giving us control yet, so
314 // the restoring the buffer may fail.
315 // If it does, sleep until DirectSound gives us control.
318 hr = IDirectSoundBuffer_Restore(pDSB);
319 if( hr == DSERR_BUFFERLOST )
322 while( ( hr = IDirectSoundBuffer_Restore(pDSB) ) == DSERR_BUFFERLOST );
324 if( pbWasRestored != null )
325 *pbWasRestored = true;
331 return S_OK; //FALSE;
335 IDirectSoundBuffer * GetFreeBuffer()
341 for( i=0; i<dwNumBuffers; i++ )
346 IDirectSoundBuffer_GetStatus(apDSBuffer[i], &dwStatus );
347 if ( ( dwStatus & DSBSTATUS_PLAYING ) == 0 )
352 if( i != dwNumBuffers )
353 return apDSBuffer[ i ];
355 return apDSBuffer[ rand() % dwNumBuffers ];
358 IDirectSoundBuffer * GetBuffer( uint dwIndex )
360 if( apDSBuffer == null )
362 if( dwIndex >= dwNumBuffers )
365 return apDSBuffer[dwIndex];
368 int Play( uint dwPriority, uint dwFlags, uint lVolume, uint lFrequency, uint lPan )
373 //IDirectSoundBuffer * pDSB;
375 // For Streaming Sound
376 dwFlags |= DSBPLAY_LOOPING;
378 if( apDSBuffer == null )
379 return CO_E_NOTINITIALIZED;
381 pDSB = GetFreeBuffer();
384 return 1; //DXUT_ERR( L"GetFreeBuffer", E_FAIL );
386 // Restore the buffer if it was lost
387 if( FAILED( hr = RestoreBuffer( pDSB, &bRestored ) ) )
388 return 1; //DXUT_ERR( L"RestoreBuffer", hr );
392 // The buffer was restored, so we need to fill it with new data
393 if( FAILED( hr = FillBufferWithSound( pDSB, false ) ) )
394 return 1; //DXUT_ERR( L"FillBufferWithSound", hr );
397 if( dwCreationFlags & DSBCAPS_CTRLVOLUME )
399 //IDirectSoundBuffer_SetVolume(pDSB, lVolume);
402 if( lFrequency != -1 &&
403 (dwCreationFlags & DSBCAPS_CTRLFREQUENCY) )
405 IDirectSoundBuffer_SetFrequency(pDSB, lFrequency);
408 if( dwCreationFlags & DSBCAPS_CTRLPAN )
410 //IDirectSoundBuffer_SetPan(pDSB, lPan);
412 result = IDirectSoundBuffer_Play(pDSB, 0, dwPriority, dwFlags);
420 if( apDSBuffer == null )
421 return CO_E_NOTINITIALIZED;
423 for( i=0; i<dwNumBuffers; i++ )
424 hr |= IDirectSoundBuffer_Stop(apDSBuffer[i]);
429 bool HandleWaveStreamNotification( )
431 uint dwCurrentPlayPos;
433 uint dwBytesWrittenToBuffer;
434 void * pDSLockedBuffer = null;
435 void * pDSLockedBuffer2 = null;
436 uint dwDSLockedBufferSize;
437 uint dwDSLockedBufferSize2;
438 uint playCursor, writeCursor;
449 // Figure out how much data has been played so far. When we have played
450 // past the end of the file, we will either need to start filling the
451 // buffer with silence or starting reading from the beginning of the file,
452 // depending if the user wants to loop the sound
453 if(IDirectSoundBuffer_GetCurrentPosition(apDSBuffer[0], &dwCurrentPlayPos, null))
457 playCursor = (dwCurrentPlayPos / dwNotifySize);
458 writeCursor = dwNextWriteOffset;
460 //printf("Play Cursor : %d, Write Cursor %d\n", playCursor, writeCursor);
461 if(writeCursor > playCursor)
464 size = (dwDSBufferSize / dwNotifySize) - start;
465 for(c = start; c<start + size; c++)
469 //printf("Writing %d - %d\n", c, c);
470 IDirectSoundBuffer_Lock(apDSBuffer[0], c * dwNotifySize, 1 * dwNotifySize, &pDSLockedBuffer, &dwDSLockedBufferSize, &pDSLockedBuffer2, &dwDSLockedBufferSize2, 0L);
471 //printf("In callback...");
472 callback(data, pDSLockedBuffer, dwDSLockedBufferSize);
474 IDirectSoundBuffer_Unlock(apDSBuffer[0], pDSLockedBuffer, dwDSLockedBufferSize, null, 0 );
475 dwNextWriteOffset = 0;
482 for(c = start; c<start + size; c++)
486 //printf("Writing %d - %d\n", c, c);
487 IDirectSoundBuffer_Lock(apDSBuffer[0], c * dwNotifySize, 1 * dwNotifySize, &pDSLockedBuffer, &dwDSLockedBufferSize, &pDSLockedBuffer2, &dwDSLockedBufferSize2, 0L);
488 //printf("In callback...");
489 callback(data, pDSLockedBuffer, dwDSLockedBufferSize);
491 IDirectSoundBuffer_Unlock(apDSBuffer[0], pDSLockedBuffer, dwDSLockedBufferSize, null, 0 );
492 dwNextWriteOffset = (playCursor) % (dwDSBufferSize / dwNotifySize);
499 size = playCursor - writeCursor;
500 for(c = start; c<start + size; c++)
504 //printf("Writing %d - %d\n", c, c);
505 IDirectSoundBuffer_Lock(apDSBuffer[0], c * dwNotifySize, 1 * dwNotifySize, &pDSLockedBuffer, &dwDSLockedBufferSize, &pDSLockedBuffer2, &dwDSLockedBufferSize2, 0L);
506 //printf("In callback...");
507 callback(data, pDSLockedBuffer, dwDSLockedBufferSize);
509 IDirectSoundBuffer_Unlock(apDSBuffer[0], pDSLockedBuffer, dwDSLockedBufferSize, null, 0 );
510 dwNextWriteOffset = (playCursor) % (dwDSBufferSize / dwNotifySize);
513 //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 )
550 void* pDSLockedBuffer = null; // Pointer to locked buffer memory
551 uint dwDSLockedBufferSize = 0; // Size of the locked DirectSound buffer
552 uint dwWavDataRead = 0; // Amount of data read from the wav file
555 return CO_E_NOTINITIALIZED;
557 // Make sure we have focus, and we didn't just switch in from
558 // an app which had a DirectSound device
559 if(RestoreBuffer( pDSB, null ))
562 // Lock the buffer down
563 if(IDirectSoundBuffer_Lock(pDSB, 0, dwDSBufferSize, &pDSLockedBuffer, &dwDSLockedBufferSize, null, null, 0L ))
566 callback(data, pDSLockedBuffer, dwDSLockedBufferSize);
568 dwWavDataRead = dwDSLockedBufferSize;
570 printf("Filling 16 spots\n");
571 IDirectSoundBuffer_Unlock(pDSB, pDSLockedBuffer, dwDSLockedBufferSize, null, 0 );
573 //dwNextWriteOffset = dwNotifySize*2;
578 static class CSoundManager
585 IDirectSound_Release( pDS );
588 int Initialize( void * hWnd )
594 IDirectSound_Release( pDS );
598 // Create IDirectSound using the primary sound device
599 if( FAILED( hr = DirectSoundCreate8( null, &pDS, null ) ) )
600 return 1; //DXUT_ERR( L"DirectSoundCreate8", hr );
602 // Set DirectSound coop level
603 if( FAILED( hr = IDirectSound_SetCooperativeLevel(pDS, hWnd, DSSCL_PRIORITY ) ) )
604 return 1; //DXUT_ERR( L"SetCooperativeLevel", hr );
610 int SetPrimaryBufferFormat( uint dwPrimaryChannels, uint dwPrimaryFreq, uint dwPrimaryBitRate )
613 IDirectSoundBuffer * pDSBPrimary = null;
618 return CO_E_NOTINITIALIZED;
620 // Get the primary buffer
621 ZeroMemory( &dsbd, sizeof(DSBUFFERDESC) );
622 dsbd.dwSize = sizeof(DSBUFFERDESC);
623 dsbd.dwFlags = DSBCAPS_PRIMARYBUFFER | DSBCAPS_CTRLPAN | DSBCAPS_CTRLVOLUME;
624 dsbd.dwBufferBytes = 0;
625 dsbd.lpwfxFormat = null;
627 if( FAILED( hr = IDirectSound_CreateSoundBuffer(pDS, &dsbd, &pDSBPrimary, null ) ) )
628 return 1; // DXUT_ERR( L"CreateSoundBuffer", hr );
630 ZeroMemory( &wfx, sizeof(WAVEFORMATEX) );
631 wfx.wFormatTag = (WORD) WAVE_FORMAT_PCM;
632 wfx.nChannels = (WORD) dwPrimaryChannels;
633 wfx.nSamplesPerSec = (uint) dwPrimaryFreq;
634 wfx.wBitsPerSample = (WORD) dwPrimaryBitRate;
635 wfx.nBlockAlign = (WORD) (wfx.wBitsPerSample / 8 * wfx.nChannels);
636 wfx.nAvgBytesPerSec = (uint) (wfx.nSamplesPerSec * wfx.nBlockAlign);
638 if( FAILED( hr = IDirectSoundBuffer_SetFormat(pDSBPrimary, &wfx) ) )
639 return 1; //DXUT_ERR( L"SetFormat", hr );
643 IDirectSoundBuffer_Release( pDSBPrimary );
650 bool InitStreaming(StreamingSound * ppStreamingSound, uint dwNotifyCount, uint dwNotifySize, void * hNotifyEvent,
651 void (*callback)(void * data, void * buffer, int len), void * data, int nChannels, int freq,int bits)
654 IDirectSoundBuffer * pDSBuffer = null;
655 uint dwDSBufferSize = 0;
656 DSBPOSITIONNOTIFY * aPosNotify = null;
657 IDirectSoundNotify * pDSNotify = null;
663 if(!ppStreamingSound || !hNotifyEvent)
666 dwDSBufferSize = dwNotifySize * dwNotifyCount;
668 ZeroMemory( &dsbd, sizeof(DSBUFFERDESC) );
669 dsbd.dwSize= sizeof(DSBUFFERDESC);
670 dsbd.dwFlags = DSBCAPS_GLOBALFOCUS | DSBCAPS_CTRLPOSITIONNOTIFY | DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLPAN | DSBCAPS_CTRLVOLUME;
671 dsbd.dwBufferBytes = dwDSBufferSize;
672 dsbd.guid3DAlgorithm = DS3DALG_DEFAULT;
673 dsbd.lpwfxFormat = new0 WAVEFORMATEX[1];
674 dsbd.lpwfxFormat->wFormatTag = WAVE_FORMAT_PCM;
675 dsbd.lpwfxFormat->nChannels = (uint16)nChannels;
676 dsbd.lpwfxFormat->nSamplesPerSec = freq;
677 dsbd.lpwfxFormat->wBitsPerSample = (uint16)bits;
678 dsbd.lpwfxFormat->nBlockAlign = dsbd.lpwfxFormat->nChannels * dsbd.lpwfxFormat->wBitsPerSample / 8;
679 dsbd.lpwfxFormat->nAvgBytesPerSec = dsbd.lpwfxFormat->nSamplesPerSec * dsbd.lpwfxFormat->nBlockAlign;
681 if(IDirectSound_CreateSoundBuffer(pDS, &dsbd, &pDSBuffer, null))
683 delete dsbd.lpwfxFormat;
686 delete dsbd.lpwfxFormat;
688 if(IDirectSoundBuffer_QueryInterface(pDSBuffer, &IID_IDirectSoundNotify, (void**)&pDSNotify))
694 aPosNotify = new DSBPOSITIONNOTIFY[ dwNotifyCount ];
695 if( aPosNotify == null )
698 for( i = 0; i < dwNotifyCount; i++ )
700 aPosNotify[i].dwOffset = (dwNotifySize * i) + dwNotifySize - 1;
701 aPosNotify[i].hEventNotify = hNotifyEvent;
704 if(IDirectSoundNotify_SetNotificationPositions(pDSNotify, dwNotifyCount, aPosNotify ))
707 IDirectSoundNotify_Release(pDSNotify);
708 delete( aPosNotify );
713 IDirectSoundNotify_Release(pDSNotify);
716 *ppStreamingSound = StreamingSound
718 dwCreationFlags = DSBCAPS_CTRLPAN|DSBCAPS_CTRLVOLUME, dwNumBuffers = 1, dwNotifySize = dwNotifySize, dwDSBufferSize = dwDSBufferSize, apDSBuffer = &pDSBuffer,
720 callback = callback, data = data
722 // ppStreamingSound->FillBufferWithSound( pDSBuffer, false );
727 static DSoundThread dSoundThread { };
729 static CSoundManager g_pSoundManager { };
730 static StreamingSound streamingSound;
732 static class DSoundThread : Thread
734 void * g_hNotificationEvent;
738 g_hNotificationEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
742 CloseHandle( g_hNotificationEvent );
747 SetPriority(timeCritical);
750 WaitForSingleObject(g_hNotificationEvent, INFINITE);
755 streamingSound.FillBufferWithSound( streamingSound.GetBuffer( 0 ), false );
756 streamingSound.Play( 0, 0, 0, -1, 0);
759 else if(!streamingSound.HandleWaveStreamNotification())