From 23dc374917acd0d7100c6e9db7ae5333338cee28 Mon Sep 17 00:00:00 2001 From: Wohlstand Date: Thu, 22 Aug 2024 10:19:38 +0300 Subject: WinMM: Added chan-alloc and audio output options --- utils/winmm_drv/src/MidiSynth.cpp | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) (limited to 'utils/winmm_drv/src/MidiSynth.cpp') diff --git a/utils/winmm_drv/src/MidiSynth.cpp b/utils/winmm_drv/src/MidiSynth.cpp index 29cbb78..b1baa13 100644 --- a/utils/winmm_drv/src/MidiSynth.cpp +++ b/utils/winmm_drv/src/MidiSynth.cpp @@ -133,7 +133,7 @@ private: bool stopProcessing; public: - int Init(Bit16s *buffer, unsigned int bufferSize, unsigned int chunkSize, bool useRingBuffer, unsigned int sampleRate) + int Init(Bit16s *buffer, unsigned int bufferSize, unsigned int chunkSize, bool useRingBuffer, unsigned int sampleRate, UINT outDevice) { DWORD callbackType = CALLBACK_NULL; DWORD_PTR callback = (DWORD_PTR)NULL; @@ -148,7 +148,7 @@ public: PCMWAVEFORMAT wFormat = {WAVE_FORMAT_PCM, 2, sampleRate, sampleRate * 4, 4, 16}; // 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); @@ -308,17 +308,21 @@ 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); + 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); } @@ -518,8 +522,12 @@ int MidiSynth::Init() 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); @@ -664,6 +672,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); -- cgit v1.2.3 From c68dc6970d5b4abab13e138ac977f7212ef32e4a Mon Sep 17 00:00:00 2001 From: Wohlstand Date: Thu, 22 Aug 2024 11:26:10 +0300 Subject: WinMM: Use the Float32 for WaveOut --- utils/winmm_drv/src/MidiSynth.cpp | 53 +++++++++++++++++++++++++++++---------- 1 file changed, 40 insertions(+), 13 deletions(-) (limited to 'utils/winmm_drv/src/MidiSynth.cpp') diff --git a/utils/winmm_drv/src/MidiSynth.cpp b/utils/winmm_drv/src/MidiSynth.cpp index b1baa13..a03ee42 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, UINT outDevice) + 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, outDevice, (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); } @@ -314,7 +330,8 @@ void WaveOutWin32::RenderingThread(void *) 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); @@ -373,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) { @@ -444,10 +461,12 @@ 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); 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; } @@ -494,6 +513,7 @@ void MidiSynth::LoadSettings() chunkSize = MillisToFrames(10); midiLatency = MillisToFrames(0); useRingBuffer = false; + if(!useRingBuffer) { // Number of chunks should be ceil(bufferSize / chunkSize) @@ -506,7 +526,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()) @@ -519,6 +539,10 @@ int MidiSynth::Init() return 1; } + synthAudioFormat.type = ADLMIDI_SampleType_F32; + synthAudioFormat.sampleOffset = s_audioChannels * sizeof(float); + synthAudioFormat.containerSize = sizeof(float); + m_setupInit = false; LoadSynthSetup(); @@ -530,7 +554,10 @@ int MidiSynth::Init() 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(); -- cgit v1.2.3 From b00d3f8d933fc7de26b954bedf841cb484139562 Mon Sep 17 00:00:00 2001 From: Wohlstand Date: Thu, 22 Aug 2024 18:26:45 +0300 Subject: WinMM: Added gaining function --- utils/winmm_drv/src/MidiSynth.cpp | 39 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) (limited to 'utils/winmm_drv/src/MidiSynth.cpp') diff --git a/utils/winmm_drv/src/MidiSynth.cpp b/utils/winmm_drv/src/MidiSynth.cpp index a03ee42..e559a4f 100644 --- a/utils/winmm_drv/src/MidiSynth.cpp +++ b/utils/winmm_drv/src/MidiSynth.cpp @@ -464,6 +464,16 @@ void MidiSynth::Render(float *bufpos, DWORD totalFrames) 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 += s_audioChannels * framesToRender; // each frame consists of two samples for both the Left and Right channels @@ -484,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; } @@ -513,6 +527,9 @@ void MidiSynth::LoadSettings() chunkSize = MillisToFrames(10); midiLatency = MillisToFrames(0); useRingBuffer = false; + volumeFactorL = 1.0f; + volumeFactorR = 1.0f; + gain = 1.0f; if(!useRingBuffer) { @@ -621,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() -- cgit v1.2.3