aboutsummaryrefslogtreecommitdiff
path: root/utils
diff options
context:
space:
mode:
authorWohlstand <admin@wohlnet.ru>2025-03-17 13:20:41 +0300
committerWohlstand <admin@wohlnet.ru>2025-03-17 13:20:41 +0300
commitd1d2584158b03f375cecdfdfd24f3f8ed23fd05d (patch)
tree9022b75f818c322287a25d3a0907552954871d3f /utils
parent6def5a7c318368eb3e2c692ff3b4aab7dbb8b56e (diff)
downloadlibADLMIDI-d1d2584158b03f375cecdfdfd24f3f8ed23fd05d.tar.gz
libADLMIDI-d1d2584158b03f375cecdfdfd24f3f8ed23fd05d.tar.bz2
libADLMIDI-d1d2584158b03f375cecdfdfd24f3f8ed23fd05d.zip
WinMM: Allow fallback to PCM16 if FLOAT32 fails
Diffstat (limited to 'utils')
-rw-r--r--utils/winmm_drv/src/MidiSynth.cpp164
-rw-r--r--utils/winmm_drv/src/MidiSynth.h5
-rw-r--r--utils/winmm_drv/src/stdafx.h2
3 files changed, 131 insertions, 40 deletions
diff --git a/utils/winmm_drv/src/MidiSynth.cpp b/utils/winmm_drv/src/MidiSynth.cpp
index e559a4f..670e74f 100644
--- a/utils/winmm_drv/src/MidiSynth.cpp
+++ b/utils/winmm_drv/src/MidiSynth.cpp
@@ -133,16 +133,38 @@ private:
DWORD prevPlayPos;
DWORD getPosWraps;
bool stopProcessing;
+ WORD formatType;
+ DWORD sizeSample;
public:
- int Init(float *buffer, unsigned int bufferSize,
+ WaveOutWin32() :
+ hWaveOut(NULL),
+ WaveHdr(NULL),
+ hEvent(NULL),
+ chunks(0),
+ prevPlayPos(0),
+ getPosWraps(0),
+ stopProcessing(false),
+ formatType(0),
+ sizeSample(0)
+ {}
+
+ int Init(ADL_UInt8 *buffer, size_t bufferSize,
+ WORD formatTag,
unsigned int chunkSize, bool useRingBuffer,
unsigned int sampleRate, UINT outDevice)
{
DWORD callbackType = CALLBACK_NULL;
DWORD_PTR callback = (DWORD_PTR)NULL;
+ size_t numFrames;
+
+ if(hWaveOut)
+ Close();
+
+ formatType = formatTag;
+ sizeSample = formatType == WAVE_FORMAT_IEEE_FLOAT ? sizeof(float) : sizeof(Bit16s);
+ numFrames = bufferSize / (sizeSample * s_audioChannels);
- hEvent = NULL;
if(!useRingBuffer)
{
hEvent = CreateEvent(NULL, false, true, NULL);
@@ -152,34 +174,38 @@ public:
PCMWAVEFORMAT wFormat =
{
- WAVE_FORMAT_IEEE_FLOAT, s_audioChannels,
+ formatType, s_audioChannels,
sampleRate,
- (DWORD)(sampleRate * sizeof(float) * s_audioChannels),
- s_audioChannels * sizeof(float),
- 8 * sizeof(float)
+ (DWORD)(sampleRate * sizeSample * s_audioChannels),
+ (WORD)(s_audioChannels * sizeSample),
+ (WORD)(8 * sizeSample)
};
// Open waveout device
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);
+ if(formatType != WAVE_FORMAT_IEEE_FLOAT)
+ MessageBoxW(NULL, L"Failed to open waveform output device", L"libADLMIDI", MB_OK | MB_ICONEXCLAMATION);
+
+ Close();
return 2;
}
// Prepare headers
- chunks = useRingBuffer ? 1 : bufferSize / chunkSize;
+ chunks = useRingBuffer ? 1 : numFrames / chunkSize;
WaveHdr = new WAVEHDR[chunks];
LPSTR chunkStart = (LPSTR)buffer;
- DWORD chunkBytes = s_audioChannels * sizeof(float) * chunkSize;
+ DWORD chunkBytes = s_audioChannels * sizeSample * chunkSize;
for(UINT i = 0; i < chunks; i++)
{
if(useRingBuffer)
{
- WaveHdr[i].dwBufferLength = s_audioChannels * sizeof(float) * bufferSize;
+ WaveHdr[i].dwBufferLength = bufferSize;
WaveHdr[i].lpData = chunkStart;
WaveHdr[i].dwFlags = WHDR_BEGINLOOP | WHDR_ENDLOOP;
WaveHdr[i].dwLoops = -1L;
@@ -192,6 +218,7 @@ public:
WaveHdr[i].dwLoops = 0L;
chunkStart += chunkBytes;
}
+
wResult = waveOutPrepareHeader(hWaveOut, &WaveHdr[i], sizeof(WAVEHDR));
if(wResult != MMSYSERR_NOERROR)
{
@@ -199,19 +226,27 @@ public:
return 3;
}
}
+
stopProcessing = false;
return 0;
}
int Close()
{
+ int wResult;
+
stopProcessing = true;
- SetEvent(hEvent);
- int wResult = waveOutReset(hWaveOut);
- if(wResult != MMSYSERR_NOERROR)
+ if(hEvent != NULL)
+ SetEvent(hEvent);
+
+ if(hWaveOut != NULL)
{
- MessageBoxW(NULL, L"Failed to Reset WaveOut", L"libADLMIDI", MB_OK | MB_ICONEXCLAMATION);
- return 8;
+ wResult = waveOutReset(hWaveOut);
+ if(wResult != MMSYSERR_NOERROR)
+ {
+ MessageBoxW(NULL, L"Failed to Reset WaveOut", L"libADLMIDI", MB_OK | MB_ICONEXCLAMATION);
+ return 8;
+ }
}
for(UINT i = 0; i < chunks; i++)
@@ -223,20 +258,29 @@ public:
return 8;
}
}
- delete[] WaveHdr;
+
+ if(WaveHdr != NULL)
+ delete[] WaveHdr;
WaveHdr = NULL;
- wResult = waveOutClose(hWaveOut);
- if(wResult != MMSYSERR_NOERROR)
+ if(hWaveOut != NULL)
{
- MessageBoxW(NULL, L"Failed to Close WaveOut", L"libADLMIDI", MB_OK | MB_ICONEXCLAMATION);
- return 8;
+ wResult = waveOutClose(hWaveOut);
+ if(wResult != MMSYSERR_NOERROR)
+ {
+ MessageBoxW(NULL, L"Failed to Close WaveOut", L"libADLMIDI", MB_OK | MB_ICONEXCLAMATION);
+ return 8;
+ }
}
+
+ hWaveOut = NULL;
+
if(hEvent != NULL)
{
CloseHandle(hEvent);
hEvent = NULL;
}
+
return 0;
}
@@ -330,8 +374,8 @@ void WaveOutWin32::RenderingThread(void *)
if(s_waveOut.WaveHdr[i].dwFlags & WHDR_DONE)
{
allBuffersRendered = false;
- midiSynth.Render((float *)s_waveOut.WaveHdr[i].lpData,
- s_waveOut.WaveHdr[i].dwBufferLength / (sizeof(float) * 2));
+ midiSynth.Render((Bit8u *)s_waveOut.WaveHdr[i].lpData,
+ s_waveOut.WaveHdr[i].dwBufferLength);
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);
@@ -348,9 +392,16 @@ void WaveOutWin32::RenderingThread(void *)
MidiSynth::MidiSynth() :
+ buffer(NULL),
+ bufferSizeB(0),
synth(NULL)
{
m_setupInit = false;
+ useRingBuffer = false;
+ volumeFactorL = 1.0f;
+ volumeFactorR = 1.0f;
+ gain = 1.0f;
+
setupDefault(&m_setup);
loadSetup();
::openSignalListener();
@@ -390,13 +441,16 @@ void MidiSynth::RenderAvailableSpace()
return;
}
}
- midiSynth.Render(buffer + sizeof(float) * framesRendered, framesToRender);
+
+ midiSynth.Render(buffer + (synthAudioFormat.containerSize * framesRendered), framesToRender);
}
// Renders totalFrames frames starting from bufpos
// The number of frames rendered is added to the global counter framesRendered
-void MidiSynth::Render(float *bufpos, DWORD totalFrames)
+void MidiSynth::Render(Bit8u *bufpos_p, DWORD bufSize)
{
+ DWORD totalFrames = bufSize / (synthAudioFormat.containerSize * s_audioChannels);
+
while(totalFrames > 0)
{
DWORD timeStamp;
@@ -462,21 +516,36 @@ void MidiSynth::Render(float *bufpos, DWORD totalFrames)
synthEvent.Wait();
adl_generateFormat(synth, framesToRender * s_audioChannels,
- (ADL_UInt8*)bufpos, (ADL_UInt8*)bufpos + synthAudioFormat.containerSize,
+ bufpos_p, bufpos_p + 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)
+
+ if(synthAudioFormat.type == ADLMIDI_SampleType_F32)
{
- bufpos[i + 0] *= g_l;
- bufpos[i + 1] *= g_r;
+ float *bufpos = (float *)bufpos_p;
+ for(size_t i = 0; i < framesToRender * s_audioChannels; i += s_audioChannels)
+ {
+ bufpos[i + 0] *= g_l;
+ bufpos[i + 1] *= g_r;
+ }
+ }
+ else
+ {
+ Bit16s *bufpos = (Bit16s *)bufpos_p;
+ 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
+ // each frame consists of two samples for both the Left and Right channels
+ bufpos_p += s_audioChannels * framesToRender * synthAudioFormat.containerSize;
totalFrames -= framesToRender;
}
@@ -526,10 +595,6 @@ void MidiSynth::LoadSettings()
bufferSize = MillisToFrames(100);
chunkSize = MillisToFrames(10);
midiLatency = MillisToFrames(0);
- useRingBuffer = false;
- volumeFactorL = 1.0f;
- volumeFactorR = 1.0f;
- gain = 1.0f;
if(!useRingBuffer)
{
@@ -543,7 +608,12 @@ void MidiSynth::LoadSettings()
int MidiSynth::Init()
{
LoadSettings();
- buffer = new float[s_audioChannels * bufferSize]; // each frame consists of two samples for both the Left and Right channels
+
+ if(!buffer)
+ {
+ bufferSizeB = s_audioChannels * bufferSize * sizeof(float);
+ buffer = (ADL_UInt8 *)malloc(bufferSizeB); // each frame consists of two samples for both the Left and Right channels
+ }
// Init synth
if(synthEvent.Init())
@@ -563,7 +633,22 @@ int MidiSynth::Init()
m_setupInit = false;
LoadSynthSetup();
- UINT wResult = s_waveOut.Init(buffer, bufferSize, chunkSize, useRingBuffer, sampleRate, m_setup.outputDevice);
+ UINT wResult = s_waveOut.Init(buffer, bufferSizeB,
+ WAVE_FORMAT_IEEE_FLOAT,
+ chunkSize, useRingBuffer, sampleRate, m_setup.outputDevice);
+
+ if(wResult)
+ {
+ synthAudioFormat.type = ADLMIDI_SampleType_S16;
+ synthAudioFormat.sampleOffset = s_audioChannels * sizeof(Bit16s);
+ synthAudioFormat.containerSize = sizeof(Bit16s);
+
+ bufferSizeB = s_audioChannels * bufferSize * sizeof(Bit16s);
+ buffer = (ADL_UInt8 *)realloc(buffer, bufferSizeB); // Shrink the buffer
+ wResult = s_waveOut.Init(buffer, bufferSizeB,
+ WAVE_FORMAT_PCM,
+ chunkSize, useRingBuffer, sampleRate, m_setup.outputDevice);
+ }
if(wResult)
return wResult;
@@ -572,8 +657,8 @@ int MidiSynth::Init()
// Start playing stream
adl_generateFormat(synth, bufferSize * s_audioChannels,
- (ADL_UInt8*)buffer,
- (ADL_UInt8*)buffer + synthAudioFormat.containerSize,
+ buffer,
+ buffer + synthAudioFormat.containerSize,
&synthAudioFormat);
framesRendered = 0;
@@ -788,7 +873,10 @@ void MidiSynth::Close()
if(synth)
adl_close(synth);
synth = NULL;
- delete buffer;
+
+ if(buffer)
+ free(buffer);
+ buffer = NULL;
synthEvent.Close();
}
diff --git a/utils/winmm_drv/src/MidiSynth.h b/utils/winmm_drv/src/MidiSynth.h
index 0442f7b..f7f08ad 100644
--- a/utils/winmm_drv/src/MidiSynth.h
+++ b/utils/winmm_drv/src/MidiSynth.h
@@ -56,7 +56,8 @@ private:
float volumeFactorR;
float gain;
- float *buffer;
+ unsigned char *buffer;
+ size_t bufferSizeB;
DWORD framesRendered;
ADL_MIDIPlayer *synth;
@@ -80,7 +81,7 @@ public:
void ResetSynth();
void PanicSynth();
void RenderAvailableSpace();
- void Render(float *bufpos, DWORD totalFrames);
+ void Render(Bit8u *bufpos_p, DWORD bufSize);
void CheckForSignals();
void PushMIDI(DWORD msg);
void PlaySysex(Bit8u *bufpos, DWORD len);
diff --git a/utils/winmm_drv/src/stdafx.h b/utils/winmm_drv/src/stdafx.h
index dd8b15c..185e474 100644
--- a/utils/winmm_drv/src/stdafx.h
+++ b/utils/winmm_drv/src/stdafx.h
@@ -7,6 +7,8 @@
#include "targetver.h"
+#include <stdlib.h>
+
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
// Windows Header Files:
#include <windows.h>