#if defined(__WIN32__) #define byte _byte #define Method _Method #define Function _Function #define int64 _int64 #define WIN32_LEAN_AND_MEAN #define MessageBox _MessageBox #define Array _Array #define String _String #include #include #include #undef Array #undef MessageBox #undef byte #undef Method #undef Function #undef int64 #undef String import "audio" public void AudioSetBalance(double percent) { if(streamingSound) streamingSound.balance = percent; } static HWAVEOUT hWaveOut; static HMIXEROBJ hmx; public void OpenMixer() { WAVEFORMATEX waveFormat = { 0 }; waveFormat.nSamplesPerSec = 44100; //(cur_stream && cur_stream->audio_st && cur_stream->audio_st->codec) ? cur_stream->audio_st->codec->sample_rate : 44100; waveFormat.wBitsPerSample = 16; waveFormat.nChannels = 2; waveFormat.cbSize = 0; waveFormat.wFormatTag = WAVE_FORMAT_PCM; waveFormat.nBlockAlign = (uint16)((waveFormat.wBitsPerSample >> 3) * waveFormat.nChannels); waveFormat.nAvgBytesPerSec = waveFormat.nBlockAlign * waveFormat.nSamplesPerSec; waveOutOpen(&hWaveOut, WAVE_MAPPER, &waveFormat, 0, 0, CALLBACK_NULL); mixerOpen((HMIXER *)&hmx, (uint)(uintptr)hWaveOut, 0, 0, MIXER_OBJECTF_HWAVEOUT); } public void CloseMixer() { mixerClose((HMIXER)hmx); waveOutClose(hWaveOut); } public bool AudioSetVolume(VolumeControl type, double percent) { bool result = false; if(type == application) { if(streamingSound) { streamingSound.volume = percent; result = true; } } else { MIXERLINE uMixerLine; // waveOutSetVolume((HWAVEOUT)0, (uint)(percent * 0xFFFF) | ((uint)(percent * 0xFFFF) << 16)); uMixerLine.cbStruct = sizeof(MIXERLINE); uMixerLine.dwComponentType = (type == pcm) ? MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT : MIXERLINE_COMPONENTTYPE_DST_SPEAKERS; if(mixerGetLineInfo(hmx, &uMixerLine, MIXER_GETLINEINFOF_COMPONENTTYPE) == MMSYSERR_NOERROR) { MIXERLINECONTROLS uMixerLineControls; MIXERCONTROL mixerControl; uMixerLineControls.cbStruct = sizeof(MIXERLINECONTROLS); uMixerLineControls.dwLineID = uMixerLine.dwLineID; uMixerLineControls.dwControlID = MIXERCONTROL_CONTROLTYPE_VOLUME; uMixerLineControls.cControls = 1; uMixerLineControls.cbmxctrl = sizeof(MIXERCONTROL); uMixerLineControls.pamxctrl = &mixerControl; if(mixerGetLineControls(hmx, &uMixerLineControls, MIXER_GETLINECONTROLSF_ONEBYTYPE) == MMSYSERR_NOERROR) { MIXERCONTROLDETAILS uDetails; uint value; uDetails.cMultipleItems = 0; uDetails.dwControlID = mixerControl.dwControlID; uDetails.cbStruct = sizeof(MIXERCONTROLDETAILS); uDetails.cbDetails = sizeof(uint); uDetails.paDetails = &value; uDetails.cChannels = 1; value = (uint)(percent * mixerControl.Bounds.lMaximum); mixerSetControlDetails(hmx, &uDetails, MIXER_SETCONTROLDETAILSF_VALUE); result = true; } } } return result; } public bool AudioGetVolume(VolumeControl type, double * percent) { bool result = false; if(type == application) { if(streamingSound) { *percent = streamingSound.volume; result = true; } } else { MIXERLINE uMixerLine; uMixerLine.cbStruct = sizeof(MIXERLINE); uMixerLine.dwComponentType = (type == pcm) ? MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT : MIXERLINE_COMPONENTTYPE_DST_SPEAKERS; if(mixerGetLineInfo(hmx, &uMixerLine, MIXER_GETLINEINFOF_COMPONENTTYPE) == MMSYSERR_NOERROR) { MIXERLINECONTROLS uMixerLineControls; MIXERCONTROL mixerControl; uMixerLineControls.cbStruct = sizeof(MIXERLINECONTROLS); uMixerLineControls.dwLineID = uMixerLine.dwLineID; uMixerLineControls.dwControlID = MIXERCONTROL_CONTROLTYPE_VOLUME; uMixerLineControls.cControls = 1; uMixerLineControls.cbmxctrl = sizeof(MIXERCONTROL); uMixerLineControls.pamxctrl = &mixerControl; if(mixerGetLineControls(hmx, &uMixerLineControls, MIXER_GETLINECONTROLSF_ONEBYTYPE) == MMSYSERR_NOERROR) { MIXERCONTROLDETAILS uDetails; uint value; uDetails.cMultipleItems = 0; uDetails.dwControlID = mixerControl.dwControlID; uDetails.cbStruct = sizeof(MIXERCONTROLDETAILS); uDetails.cbDetails = sizeof(uint); uDetails.paDetails = &value; uDetails.cChannels = 1; mixerGetControlDetails(hmx, &uDetails, MIXER_SETCONTROLDETAILSF_VALUE); *percent = (double)value / mixerControl.Bounds.lMaximum; result = true; } } } return result; } public int OpenAudio(AudioSpec wanted, AudioSpec result) { #define NUM_PLAY_NOTIFICATIONS 16 uint nBlockAlign, dwNotifySize; delete streamingSound; g_pSoundManager.Initialize(wanted.windowHandle); g_pSoundManager.SetPrimaryBufferFormat(wanted.channels, wanted.freq, wanted.bits); if(!wanted.channels) wanted.channels = 2; nBlockAlign = wanted.bits / 8 * wanted.channels; // dwNotifySize = 16384 / NUM_PLAY_NOTIFICATIONS; //wanted.freq * 3 * nBlockAlign / NUM_PLAY_NOTIFICATIONS; dwNotifySize = wanted.freq / 2 / NUM_PLAY_NOTIFICATIONS; //wanted.freq * 3 * nBlockAlign / NUM_PLAY_NOTIFICATIONS; dwNotifySize -= dwNotifySize % nBlockAlign; result = wanted; result.size = dwNotifySize * NUM_PLAY_NOTIFICATIONS; g_pSoundManager.InitStreaming(&streamingSound, NUM_PLAY_NOTIFICATIONS, dwNotifySize, dSoundThread.g_hNotificationEvent, (void *)wanted.callback, wanted.userdata, wanted.channels, wanted.freq, wanted.bits); if(streamingSound) { streamingSound.volume = wanted.volume; dSoundThread.bDone = false; //dSoundThread.Create(); return 1; } return 0; } public void PauseAudio(bool value) { if(value) { dSoundThread.bDone = true; SetEvent(dSoundThread.g_hNotificationEvent); dSoundThread.Wait(); } else { PlayBuffer(false); dSoundThread.Create(); } } public void CloseAudio() { if(dSoundThread) { dSoundThread.bDone = true; SetEvent(dSoundThread.g_hNotificationEvent); dSoundThread.Wait(); } delete streamingSound; } static bool PlayBuffer( bool bLooped ) { //void * pDSB; if(!streamingSound) return false; if(streamingSound.Reset()) return false; //pDSB = streamingSound.GetBuffer( 0 ); SetEvent(dSoundThread.g_hNotificationEvent); return true; } static class StreamingSound { IDirectSoundBuffer ** apDSBuffer; IDirectSoundBuffer * pDSB; uint dwDSBufferSize; uint dwNumBuffers; uint dwCreationFlags; uint dwLastPlayPos; uint dwPlayProgress; uint dwNotifySize; uint dwNextWriteOffset; bool bFillNextNotificationWithSilence; void (*callback)(void * data, void * buffer, int len); void * data; double volume; public property double volume { set { int vol = (int)(20 * log10(value) * 100); vol = Max(-10000, vol); IDirectSoundBuffer_SetVolume(apDSBuffer[0], vol); volume = value; } get { return volume; } }; public property double balance { set { int pan = -2173 + (int)(value * 2173 * 2); IDirectSoundBuffer_SetPan(apDSBuffer[0], pan); } } property uint dwNumBuffers { set { dwNumBuffers = value; apDSBuffer = new0 IDirectSoundBuffer *[dwNumBuffers]; } } property IDirectSoundBuffer ** apDSBuffer { set { if( apDSBuffer ) { uint i; for( i=0; i= dwNumBuffers ) return null; return apDSBuffer[dwIndex]; } int Play( uint dwPriority, uint dwFlags, uint lVolume, uint lFrequency, uint lPan ) { int result; int hr; bool bRestored; //IDirectSoundBuffer * pDSB; // For Streaming Sound dwFlags |= DSBPLAY_LOOPING; if( apDSBuffer == null ) return CO_E_NOTINITIALIZED; pDSB = GetFreeBuffer(); if( pDSB == null ) return 1; //DXUT_ERR( L"GetFreeBuffer", E_FAIL ); // Restore the buffer if it was lost if( FAILED( hr = RestoreBuffer( pDSB, &bRestored ) ) ) return 1; //DXUT_ERR( L"RestoreBuffer", hr ); if( bRestored ) { // The buffer was restored, so we need to fill it with new data if( FAILED( hr = FillBufferWithSound( pDSB, false ) ) ) return 1; //DXUT_ERR( L"FillBufferWithSound", hr ); } if( dwCreationFlags & DSBCAPS_CTRLVOLUME ) { //IDirectSoundBuffer_SetVolume(pDSB, lVolume); } if( lFrequency != -1 && (dwCreationFlags & DSBCAPS_CTRLFREQUENCY) ) { IDirectSoundBuffer_SetFrequency(pDSB, lFrequency); } if( dwCreationFlags & DSBCAPS_CTRLPAN ) { //IDirectSoundBuffer_SetPan(pDSB, lPan); } result = IDirectSoundBuffer_Play(pDSB, 0, dwPriority, dwFlags); return result; } /* int Stop() { int hr = 0; uint i; if( apDSBuffer == null ) return CO_E_NOTINITIALIZED; for( i=0; i playCursor) { start = writeCursor; size = (dwDSBufferSize / dwNotifySize) - start; for(c = start; c 0) { start = 0; size = playCursor; for(c = start; cwFormatTag = WAVE_FORMAT_PCM; dsbd.lpwfxFormat->nChannels = (uint16)nChannels; dsbd.lpwfxFormat->nSamplesPerSec = freq; dsbd.lpwfxFormat->wBitsPerSample = (uint16)bits; dsbd.lpwfxFormat->nBlockAlign = dsbd.lpwfxFormat->nChannels * dsbd.lpwfxFormat->wBitsPerSample / 8; dsbd.lpwfxFormat->nAvgBytesPerSec = dsbd.lpwfxFormat->nSamplesPerSec * dsbd.lpwfxFormat->nBlockAlign; if(IDirectSound_CreateSoundBuffer(pDS, &dsbd, &pDSBuffer, null)) { delete dsbd.lpwfxFormat; return false; } delete dsbd.lpwfxFormat; if(IDirectSoundBuffer_QueryInterface(pDSBuffer, &IID_IDirectSoundNotify, (void**)&pDSNotify)) { delete aPosNotify; return false; } aPosNotify = new DSBPOSITIONNOTIFY[ dwNotifyCount ]; if( aPosNotify == null ) return false; for( i = 0; i < dwNotifyCount; i++ ) { aPosNotify[i].dwOffset = (dwNotifySize * i) + dwNotifySize - 1; aPosNotify[i].hEventNotify = hNotifyEvent; } if(IDirectSoundNotify_SetNotificationPositions(pDSNotify, dwNotifyCount, aPosNotify )) { if(pDSNotify) IDirectSoundNotify_Release(pDSNotify); delete( aPosNotify ); return false; } if(pDSNotify) IDirectSoundNotify_Release(pDSNotify); delete aPosNotify; *ppStreamingSound = StreamingSound { dwCreationFlags = DSBCAPS_CTRLPAN|DSBCAPS_CTRLVOLUME, dwNumBuffers = 1, dwNotifySize = dwNotifySize, dwDSBufferSize = dwDSBufferSize, apDSBuffer = &pDSBuffer, callback = callback, data = data }; // ppStreamingSound->FillBufferWithSound( pDSBuffer, false ); return true; } } static DSoundThread dSoundThread { }; static CSoundManager g_pSoundManager { }; static StreamingSound streamingSound; static class DSoundThread : Thread { void * g_hNotificationEvent; bool bDone; DSoundThread() { g_hNotificationEvent = CreateEvent( NULL, FALSE, FALSE, NULL ); } ~DSoundThread() { CloseHandle( g_hNotificationEvent ); } uint Main( ) { bool filled = false; SetPriority(timeCritical); while( !bDone ) { WaitForSingleObject(g_hNotificationEvent, INFINITE); if(streamingSound) { if(!filled) { streamingSound.FillBufferWithSound( streamingSound.GetBuffer( 0 ), false ); streamingSound.Play( 0, 0, 0, -1, 0); filled = true; } else if(!streamingSound.HandleWaveStreamNotification()) { bDone = true; } } } return 0; } } #endif