diff options
Diffstat (limited to 'utils/winmm_drv/src')
-rw-r--r-- | utils/winmm_drv/src/MidiSynth.cpp | 110 | ||||
-rw-r--r-- | utils/winmm_drv/src/MidiSynth.h | 12 | ||||
-rw-r--r-- | utils/winmm_drv/src/winmm_drv.cpp | 27 |
3 files changed, 124 insertions, 25 deletions
diff --git a/utils/winmm_drv/src/MidiSynth.cpp b/utils/winmm_drv/src/MidiSynth.cpp index 29cbb78..e559a4f 100644 --- a/utils/winmm_drv/src/MidiSynth.cpp +++ b/utils/winmm_drv/src/MidiSynth.cpp @@ -23,6 +23,8 @@ namespace OPL3Emu static MidiSynth &midiSynth = MidiSynth::getInstance(); +static const unsigned int s_audioChannels = 2; + static class MidiStream { private: @@ -133,10 +135,13 @@ private: bool stopProcessing; public: - int Init(Bit16s *buffer, unsigned int bufferSize, unsigned int chunkSize, bool useRingBuffer, unsigned int sampleRate) + int Init(float *buffer, unsigned int bufferSize, + unsigned int chunkSize, bool useRingBuffer, + unsigned int sampleRate, UINT outDevice) { DWORD callbackType = CALLBACK_NULL; DWORD_PTR callback = (DWORD_PTR)NULL; + hEvent = NULL; if(!useRingBuffer) { @@ -145,10 +150,18 @@ public: callbackType = CALLBACK_EVENT; } - PCMWAVEFORMAT wFormat = {WAVE_FORMAT_PCM, 2, sampleRate, sampleRate * 4, 4, 16}; + PCMWAVEFORMAT wFormat = + { + WAVE_FORMAT_IEEE_FLOAT, s_audioChannels, + sampleRate, + (DWORD)(sampleRate * sizeof(float) * s_audioChannels), + s_audioChannels * sizeof(float), + 8 * sizeof(float) + }; // Open waveout device - int wResult = waveOutOpen(&hWaveOut, WAVE_MAPPER, (LPWAVEFORMATEX)&wFormat, callback, (DWORD_PTR)&midiSynth, callbackType); + int wResult = waveOutOpen(&hWaveOut, outDevice, (LPWAVEFORMATEX)&wFormat, + callback, (DWORD_PTR)&midiSynth, callbackType); if(wResult != MMSYSERR_NOERROR) { MessageBoxW(NULL, L"Failed to open waveform output device", L"libADLMIDI", MB_OK | MB_ICONEXCLAMATION); @@ -158,13 +171,15 @@ public: // Prepare headers chunks = useRingBuffer ? 1 : bufferSize / chunkSize; WaveHdr = new WAVEHDR[chunks]; + LPSTR chunkStart = (LPSTR)buffer; - DWORD chunkBytes = 4 * chunkSize; + DWORD chunkBytes = s_audioChannels * sizeof(float) * chunkSize; + for(UINT i = 0; i < chunks; i++) { if(useRingBuffer) { - WaveHdr[i].dwBufferLength = 4 * bufferSize; + WaveHdr[i].dwBufferLength = s_audioChannels * sizeof(float) * bufferSize; WaveHdr[i].lpData = chunkStart; WaveHdr[i].dwFlags = WHDR_BEGINLOOP | WHDR_ENDLOOP; WaveHdr[i].dwLoops = -1L; @@ -237,7 +252,7 @@ public: return 4; } } - _beginthread(RenderingThread, 16384, this); + _beginthread(RenderingThread, 16384 * 2, this); return 0; } @@ -288,6 +303,7 @@ public: std::cout << "OPL3: GetPos() wrap: " << delta << "\n"; ++getPosWraps; } + prevPlayPos = mmTime.u.sample; return mmTime.u.sample + getPosWraps * (1 << 27); } @@ -308,17 +324,22 @@ void WaveOutWin32::RenderingThread(void *) while(!s_waveOut.stopProcessing) { bool allBuffersRendered = true; + for(UINT i = 0; i < s_waveOut.chunks; i++) { if(s_waveOut.WaveHdr[i].dwFlags & WHDR_DONE) { allBuffersRendered = false; - midiSynth.Render((Bit16s *)s_waveOut.WaveHdr[i].lpData, s_waveOut.WaveHdr[i].dwBufferLength / 4); + midiSynth.Render((float *)s_waveOut.WaveHdr[i].lpData, + s_waveOut.WaveHdr[i].dwBufferLength / (sizeof(float) * 2)); + if(waveOutWrite(s_waveOut.hWaveOut, &s_waveOut.WaveHdr[i], sizeof(WAVEHDR)) != MMSYSERR_NOERROR) MessageBoxW(NULL, L"Failed to write block to device", L"libADLMIDI", MB_OK | MB_ICONEXCLAMATION); + midiSynth.CheckForSignals(); } } + if(allBuffersRendered) WaitForSingleObject(s_waveOut.hEvent, INFINITE); } @@ -369,12 +390,12 @@ void MidiSynth::RenderAvailableSpace() return; } } - midiSynth.Render(buffer + 2 * framesRendered, framesToRender); + midiSynth.Render(buffer + sizeof(float) * framesRendered, framesToRender); } // Renders totalFrames frames starting from bufpos // The number of frames rendered is added to the global counter framesRendered -void MidiSynth::Render(Bit16s *bufpos, DWORD totalFrames) +void MidiSynth::Render(float *bufpos, DWORD totalFrames) { while(totalFrames > 0) { @@ -440,10 +461,22 @@ void MidiSynth::Render(Bit16s *bufpos, DWORD totalFrames) } synthEvent.Wait(); - adl_generate(synth, framesToRender * 2, bufpos); + adl_generateFormat(synth, framesToRender * s_audioChannels, + (ADL_UInt8*)bufpos, (ADL_UInt8*)bufpos + synthAudioFormat.containerSize, + &synthAudioFormat); + + // Apply the volume + float g_l = volumeFactorL * gain; + float g_r = volumeFactorR * gain; + for(size_t i = 0; i < framesToRender * s_audioChannels; i += s_audioChannels) + { + bufpos[i + 0] *= g_l; + bufpos[i + 1] *= g_r; + } + synthEvent.Release(); framesRendered += framesToRender; - bufpos += 2 * framesToRender; // each frame consists of two samples for both the Left and Right channels + bufpos += s_audioChannels * framesToRender; // each frame consists of two samples for both the Left and Right channels totalFrames -= framesToRender; } @@ -461,15 +494,19 @@ void MidiSynth::CheckForSignals() switch(cmd) { - case 1: // Reload settings on the fly + case DRV_SIGNAL_RELOAD_SETUP: // Reload settings on the fly this->loadSetup(); LoadSynthSetup(); break; - case 2: + case DRV_SIGNAL_RESET_SYNTH: adl_reset(synth); break; + case DRV_SIGNAL_UPDATE_GAIN: + this->loadGain(); + break; + default: break; } @@ -490,6 +527,10 @@ void MidiSynth::LoadSettings() chunkSize = MillisToFrames(10); midiLatency = MillisToFrames(0); useRingBuffer = false; + volumeFactorL = 1.0f; + volumeFactorR = 1.0f; + gain = 1.0f; + if(!useRingBuffer) { // Number of chunks should be ceil(bufferSize / chunkSize) @@ -502,7 +543,7 @@ void MidiSynth::LoadSettings() int MidiSynth::Init() { LoadSettings(); - buffer = new Bit16s[2 * bufferSize]; // each frame consists of two samples for both the Left and Right channels + buffer = new float[s_audioChannels * bufferSize]; // each frame consists of two samples for both the Left and Right channels // Init synth if(synthEvent.Init()) @@ -515,14 +556,25 @@ int MidiSynth::Init() return 1; } + synthAudioFormat.type = ADLMIDI_SampleType_F32; + synthAudioFormat.sampleOffset = s_audioChannels * sizeof(float); + synthAudioFormat.containerSize = sizeof(float); + m_setupInit = false; LoadSynthSetup(); - UINT wResult = s_waveOut.Init(buffer, bufferSize, chunkSize, useRingBuffer, sampleRate); - if(wResult) return wResult; + UINT wResult = s_waveOut.Init(buffer, bufferSize, chunkSize, useRingBuffer, sampleRate, m_setup.outputDevice); + + if(wResult) + return wResult; + + m_setupCurrent.outputDevice = m_setup.outputDevice; // Start playing stream - adl_generate(synth, bufferSize * 2, buffer); + adl_generateFormat(synth, bufferSize * s_audioChannels, + (ADL_UInt8*)buffer, + (ADL_UInt8*)buffer + synthAudioFormat.containerSize, + &synthAudioFormat); framesRendered = 0; wResult = s_waveOut.Start(); @@ -586,9 +638,27 @@ void MidiSynth::PlaySysex(Bit8u *bufpos, DWORD len) synthEvent.Release(); } +void MidiSynth::SetVolume(DWORD vol) +{ + volumeFactorR = (float)0xFFFF / HIWORD(vol); + volumeFactorL = (float)0xFFFF / LOWORD(vol); +} + +DWORD MidiSynth::GetVolume() +{ + return MAKELONG((DWORD)(0xFFFF * volumeFactorL), (DWORD)(0xFFFF * volumeFactorR)); +} + void MidiSynth::loadSetup() { ::loadSetup(&m_setup); + gain = (float)m_setup.gain100 / 100.f; +} + +void MidiSynth::loadGain() +{ + ::getGain(&m_setup); + gain = (float)m_setup.gain100 / 100.f; } void MidiSynth::LoadSynthSetup() @@ -664,6 +734,12 @@ void MidiSynth::LoadSynthSetup() m_setupCurrent.volumeModel = m_setup.volumeModel; } + if(!m_setupInit || m_setupCurrent.chanAlloc != m_setup.chanAlloc) + { + adl_setChannelAllocMode(synth, m_setup.chanAlloc); + m_setupCurrent.chanAlloc = m_setup.chanAlloc; + } + if(!m_setupInit || m_setupCurrent.numChips != m_setup.numChips) { adl_setNumChips(synth, m_setup.numChips); diff --git a/utils/winmm_drv/src/MidiSynth.h b/utils/winmm_drv/src/MidiSynth.h index bf2da02..0442f7b 100644 --- a/utils/winmm_drv/src/MidiSynth.h +++ b/utils/winmm_drv/src/MidiSynth.h @@ -52,11 +52,15 @@ private: Bit8u reverbMode; Bit8u reverbTime; Bit8u reverbLevel; + float volumeFactorL; + float volumeFactorR; + float gain; - Bit16s *buffer; + float *buffer; DWORD framesRendered; ADL_MIDIPlayer *synth; + ADLMIDI_AudioFormat synthAudioFormat; bool m_setupInit; DriverSettings m_setup; @@ -76,12 +80,16 @@ public: void ResetSynth(); void PanicSynth(); void RenderAvailableSpace(); - void Render(Bit16s *bufpos, DWORD totalFrames); + void Render(float *bufpos, DWORD totalFrames); void CheckForSignals(); void PushMIDI(DWORD msg); void PlaySysex(Bit8u *bufpos, DWORD len); + void SetVolume(DWORD vol); + DWORD GetVolume(); + void loadSetup(); + void loadGain(); void LoadSynthSetup(); }; diff --git a/utils/winmm_drv/src/winmm_drv.cpp b/utils/winmm_drv/src/winmm_drv.cpp index 7f65dda..09f38d2 100644 --- a/utils/winmm_drv/src/winmm_drv.cpp +++ b/utils/winmm_drv/src/winmm_drv.cpp @@ -201,6 +201,7 @@ EXTERN_C HRESULT modGetCaps(PVOID capsPtr, DWORD capsSize) CHAR synthName[] = "libADLMIDI synth\0"; WCHAR synthNameW[] = L"libADLMIDI synth\0"; + DWORD support = MIDICAPS_VOLUME | MIDICAPS_LRVOLUME; switch(capsSize) { @@ -214,7 +215,7 @@ EXTERN_C HRESULT modGetCaps(PVOID capsPtr, DWORD capsSize) myCapsA->wVoices = 0; myCapsA->wNotes = 0; myCapsA->wChannelMask = 0xffff; - myCapsA->dwSupport = 0; + myCapsA->dwSupport = support; return MMSYSERR_NOERROR; case(sizeof(MIDIOUTCAPSW)): @@ -227,7 +228,7 @@ EXTERN_C HRESULT modGetCaps(PVOID capsPtr, DWORD capsSize) myCapsW->wVoices = 0; myCapsW->wNotes = 0; myCapsW->wChannelMask = 0xffff; - myCapsW->dwSupport = 0; + myCapsW->dwSupport = support; return MMSYSERR_NOERROR; case(sizeof(MIDIOUTCAPS2A)): @@ -240,7 +241,7 @@ EXTERN_C HRESULT modGetCaps(PVOID capsPtr, DWORD capsSize) myCaps2A->wVoices = 0; myCaps2A->wNotes = 0; myCaps2A->wChannelMask = 0xffff; - myCaps2A->dwSupport = 0; + myCaps2A->dwSupport = support; return MMSYSERR_NOERROR; case(sizeof(MIDIOUTCAPS2W)): @@ -253,7 +254,7 @@ EXTERN_C HRESULT modGetCaps(PVOID capsPtr, DWORD capsSize) myCaps2W->wVoices = 0; myCaps2W->wNotes = 0; myCaps2W->wChannelMask = 0xffff; - myCaps2W->dwSupport = 0; + myCaps2W->dwSupport = support; return MMSYSERR_NOERROR; default: @@ -265,8 +266,12 @@ void DoCallback(int driverNum, DWORD_PTR clientNum, DWORD msg, DWORD_PTR param1, { Driver::Client *client = &drivers[driverNum].clients[clientNum]; #ifdef __MINGW32__ - if(s_DriverCallback) + if(!s_DriverCallback) + { initWorkarounds(); + if(!s_DriverCallback) + return; // Ouch! + } #endif DriverCallback(client->callback, client->flags, drivers[driverNum].hdrvr, msg, client->instance, param1, param2); } @@ -316,7 +321,8 @@ LONG CloseDriver(Driver *driver, UINT uDeviceID, UINT uMsg, DWORD_PTR dwUser, DW return MMSYSERR_NOERROR; } -EXTERN_C DWORD __declspec(dllexport) __stdcall modMessage(DWORD uDeviceID, DWORD uMsg, DWORD_PTR dwUser, DWORD_PTR dwParam1, DWORD_PTR dwParam2) +EXTERN_C DWORD __declspec(dllexport) __stdcall +modMessage(DWORD uDeviceID, DWORD uMsg, DWORD_PTR dwUser, DWORD_PTR dwParam1, DWORD_PTR dwParam2) { MIDIHDR *midiHdr; Driver *driver = &drivers[uDeviceID]; @@ -377,6 +383,15 @@ EXTERN_C DWORD __declspec(dllexport) __stdcall modMessage(DWORD uDeviceID, DWORD DoCallback(uDeviceID, dwUser, MOM_DONE, dwParam1, (DWORD_PTR)NULL); return MMSYSERR_NOERROR; + case MODM_GETVOLUME: + if(dwParam1) + *(DWORD *)dwParam1 = midiSynth.GetVolume(); + return MMSYSERR_NOERROR; + + case MODM_SETVOLUME: + midiSynth.SetVolume(dwParam1); + return MMSYSERR_NOERROR; + case MODM_GETNUMDEVS: return 0x1; |