- fixed: The MIDI wave writer set the sample rate to save at too late.

This was done after the players had already been created. To ensure that everything gets set properly it is necessary to pass the desired sample rate to the device's constructor and let it make sure that a proper sample rate gets set.
This commit is contained in:
Christoph Oelckers 2018-03-06 22:41:27 +01:00
parent 72831c9db7
commit 9b61ee9618
9 changed files with 37 additions and 66 deletions

View file

@ -88,7 +88,7 @@ public:
#ifdef _WIN32 #ifdef _WIN32
MIDIDevice *CreateWinMIDIDevice(int mididevice); MIDIDevice *CreateWinMIDIDevice(int mididevice);
#endif #endif
MIDIDevice *CreateTimidityPPMIDIDevice(const char *args); MIDIDevice *CreateTimidityPPMIDIDevice(const char *args, int samplerate);
void TimidityPP_Shutdown(); void TimidityPP_Shutdown();
// Base class for software synthesizer MIDI output devices ------------------ // Base class for software synthesizer MIDI output devices ------------------
@ -97,7 +97,7 @@ class SoftSynthMIDIDevice : public MIDIDevice
{ {
friend class MIDIWaveWriter; friend class MIDIWaveWriter;
public: public:
SoftSynthMIDIDevice(); SoftSynthMIDIDevice(int samplerate, int minrate = 1, int maxrate = 1000000 /* something higher than any valid value */);
~SoftSynthMIDIDevice(); ~SoftSynthMIDIDevice();
void Close(); void Close();
@ -131,10 +131,6 @@ protected:
int OpenStream(int chunks, int flags, MidiCallback, void *userdata); int OpenStream(int chunks, int flags, MidiCallback, void *userdata);
static bool FillStream(SoundStream *stream, void *buff, int len, void *userdata); static bool FillStream(SoundStream *stream, void *buff, int len, void *userdata);
virtual bool ServiceStream (void *buff, int numbytes); virtual bool ServiceStream (void *buff, int numbytes);
virtual void SetSampleRate(int rate)
{
if (rate > 11025) { SampleRate = rate; }
}
int GetSampleRate() const { return SampleRate; } int GetSampleRate() const { return SampleRate; }
virtual void HandleEvent(int status, int parm1, int parm2) = 0; virtual void HandleEvent(int status, int parm1, int parm2) = 0;
@ -152,7 +148,6 @@ public:
void Close(); void Close();
int GetTechnology() const; int GetTechnology() const;
FString GetStats(); FString GetStats();
virtual void SetSampleRate(int rate) { } // cannot be changed.
protected: protected:
void CalcTickRate(); void CalcTickRate();
@ -182,14 +177,13 @@ namespace Timidity { struct Renderer; }
class TimidityMIDIDevice : public SoftSynthMIDIDevice class TimidityMIDIDevice : public SoftSynthMIDIDevice
{ {
public: public:
TimidityMIDIDevice(const char *args); TimidityMIDIDevice(const char *args, int samplerate);
~TimidityMIDIDevice(); ~TimidityMIDIDevice();
int Open(MidiCallback, void *userdata); int Open(MidiCallback, void *userdata);
void PrecacheInstruments(const uint16_t *instruments, int count); void PrecacheInstruments(const uint16_t *instruments, int count);
FString GetStats(); FString GetStats();
int GetDeviceType() const override { return MDEV_GUS; } int GetDeviceType() const override { return MDEV_GUS; }
virtual void SetSampleRate(int rate) { if (rate >= 11025 && rate < 65535) SampleRate = rate; }
protected: protected:
Timidity::Renderer *Renderer; Timidity::Renderer *Renderer;
@ -204,7 +198,7 @@ protected:
class MIDIWaveWriter : public SoftSynthMIDIDevice class MIDIWaveWriter : public SoftSynthMIDIDevice
{ {
public: public:
MIDIWaveWriter(const char *filename, MIDIDevice *devtouse, int rate); MIDIWaveWriter(const char *filename, MIDIDevice *devtouse);
~MIDIWaveWriter(); ~MIDIWaveWriter();
int Resume(); int Resume();
int Open(MidiCallback cb, void *userdata) int Open(MidiCallback cb, void *userdata)
@ -235,14 +229,13 @@ protected:
class WildMIDIDevice : public SoftSynthMIDIDevice class WildMIDIDevice : public SoftSynthMIDIDevice
{ {
public: public:
WildMIDIDevice(const char *args); WildMIDIDevice(const char *args, int samplerate);
~WildMIDIDevice(); ~WildMIDIDevice();
int Open(MidiCallback, void *userdata); int Open(MidiCallback, void *userdata);
void PrecacheInstruments(const uint16_t *instruments, int count); void PrecacheInstruments(const uint16_t *instruments, int count);
FString GetStats(); FString GetStats();
int GetDeviceType() const override { return MDEV_WILDMIDI; } int GetDeviceType() const override { return MDEV_WILDMIDI; }
virtual void SetSampleRate(int rate) { if (rate >= 11025 && SampleRate < rate) SampleRate = rate; }
protected: protected:
WildMidi_Renderer *Renderer; WildMidi_Renderer *Renderer;
@ -268,7 +261,7 @@ struct fluid_synth_t;
class FluidSynthMIDIDevice : public SoftSynthMIDIDevice class FluidSynthMIDIDevice : public SoftSynthMIDIDevice
{ {
public: public:
FluidSynthMIDIDevice(const char *args); FluidSynthMIDIDevice(const char *args, int samplerate);
~FluidSynthMIDIDevice(); ~FluidSynthMIDIDevice();
int Open(MidiCallback, void *userdata); int Open(MidiCallback, void *userdata);
@ -277,7 +270,6 @@ public:
void FluidSettingNum(const char *setting, double value); void FluidSettingNum(const char *setting, double value);
void FluidSettingStr(const char *setting, const char *value); void FluidSettingStr(const char *setting, const char *value);
int GetDeviceType() const override { return MDEV_FLUIDSYNTH; } int GetDeviceType() const override { return MDEV_FLUIDSYNTH; }
virtual void SetSampleRate(int rate) { if (rate >= 22050 && rate <= 96000) SampleRate = rate; }
protected: protected:
void HandleEvent(int status, int parm1, int parm2); void HandleEvent(int status, int parm1, int parm2);
@ -382,7 +374,7 @@ protected:
static EMidiDevice SelectMIDIDevice(EMidiDevice devtype); static EMidiDevice SelectMIDIDevice(EMidiDevice devtype);
MIDIDevice *CreateMIDIDevice(EMidiDevice devtype); MIDIDevice *CreateMIDIDevice(EMidiDevice devtype, int samplerate);
static void Callback(void *userdata); static void Callback(void *userdata);

View file

@ -274,7 +274,8 @@ CUSTOM_CVAR(Int, fluid_chorus_type, FLUID_CHORUS_DEFAULT_TYPE, CVAR_ARCHIVE|CVAR
// //
//========================================================================== //==========================================================================
FluidSynthMIDIDevice::FluidSynthMIDIDevice(const char *args) FluidSynthMIDIDevice::FluidSynthMIDIDevice(const char *args, int samplerate)
: SoftSynthMIDIDevice(samplerate <= 0? fluid_samplerate : samplerate, 22050, 96000)
{ {
FluidSynth = NULL; FluidSynth = NULL;
FluidSettings = NULL; FluidSettings = NULL;
@ -290,11 +291,6 @@ FluidSynthMIDIDevice::FluidSynthMIDIDevice(const char *args)
printf("Failed to create FluidSettings.\n"); printf("Failed to create FluidSettings.\n");
return; return;
} }
SampleRate = fluid_samplerate;
if (SampleRate < 22050 || SampleRate > 96000)
{ // Match sample rate to SFX rate
SampleRate = clamp((int)GSnd->GetOutputRate(), 22050, 96000);
}
fluid_settings_setnum(FluidSettings, "synth.sample-rate", SampleRate); fluid_settings_setnum(FluidSettings, "synth.sample-rate", SampleRate);
fluid_settings_setnum(FluidSettings, "synth.gain", fluid_gain); fluid_settings_setnum(FluidSettings, "synth.gain", fluid_gain);
fluid_settings_setint(FluidSettings, "synth.reverb.active", fluid_reverb); fluid_settings_setint(FluidSettings, "synth.reverb.active", fluid_reverb);

View file

@ -79,6 +79,7 @@ CVAR(Bool, opl_fullpan, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG);
//========================================================================== //==========================================================================
OPLMIDIDevice::OPLMIDIDevice(const char *args) OPLMIDIDevice::OPLMIDIDevice(const char *args)
: SoftSynthMIDIDevice((int)OPL_SAMPLE_RATE)
{ {
OPL_SetCore(args); OPL_SetCore(args);
FullPan = opl_fullpan; FullPan = opl_fullpan;
@ -88,7 +89,6 @@ OPLMIDIDevice::OPLMIDIDevice(const char *args)
data.Read(filehdr, 8); data.Read(filehdr, 8);
if (memcmp(filehdr, "#OPL_II#", 8)) I_Error("Corrupt GENMIDI lump"); if (memcmp(filehdr, "#OPL_II#", 8)) I_Error("Corrupt GENMIDI lump");
data.Read(OPLinstruments, sizeof(GenMidiInstrument) * GENMIDI_NUM_TOTAL); data.Read(OPLinstruments, sizeof(GenMidiInstrument) * GENMIDI_NUM_TOTAL);
SampleRate = (int)OPL_SAMPLE_RATE;
} }
//========================================================================== //==========================================================================

View file

@ -68,14 +68,15 @@ CVAR(Bool, synth_watch, false, 0)
// //
//========================================================================== //==========================================================================
SoftSynthMIDIDevice::SoftSynthMIDIDevice() SoftSynthMIDIDevice::SoftSynthMIDIDevice(int samplerate, int minrate, int maxrate)
{ {
Stream = NULL; Stream = NULL;
Tempo = 0; Tempo = 0;
Division = 0; Division = 0;
Events = NULL; Events = NULL;
Started = false; Started = false;
SampleRate = GSnd != NULL ? (int)GSnd->GetOutputRate() : 44100; SampleRate = samplerate;
if (SampleRate < minrate || SampleRate > maxrate) SampleRate = GSnd != NULL ? clamp((int)GSnd->GetOutputRate(), minrate, maxrate) : 44100;
} }
//========================================================================== //==========================================================================

View file

@ -66,9 +66,9 @@
// //
//========================================================================== //==========================================================================
TimidityMIDIDevice::TimidityMIDIDevice(const char *args) TimidityMIDIDevice::TimidityMIDIDevice(const char *args, int samplerate)
: SoftSynthMIDIDevice(samplerate, 11025, 65535)
{ {
Renderer = nullptr;
Renderer = new Timidity::Renderer((float)SampleRate, args); Renderer = new Timidity::Renderer((float)SampleRate, args);
} }

View file

@ -53,7 +53,7 @@ class TimidityPPMIDIDevice : public SoftSynthMIDIDevice
static TimidityPlus::Instruments *instruments; static TimidityPlus::Instruments *instruments;
int sampletime; int sampletime;
public: public:
TimidityPPMIDIDevice(const char *args); TimidityPPMIDIDevice(const char *args, int samplerate);
~TimidityPPMIDIDevice(); ~TimidityPPMIDIDevice();
int Open(MidiCallback, void *userdata); int Open(MidiCallback, void *userdata);
@ -65,10 +65,6 @@ public:
if (instruments != nullptr) delete instruments; if (instruments != nullptr) delete instruments;
instruments = nullptr; instruments = nullptr;
} }
virtual void SetSampleRate(int rate)
{
if (rate >= 4000 && SampleRate < rate) SampleRate = rate;
}
double test[3] = { 0, 0, 0 }; double test[3] = { 0, 0, 0 };
@ -91,13 +87,7 @@ CUSTOM_CVAR(String, timidity_config, "timidity.cfg", CVAR_ARCHIVE | CVAR_GLOBALC
} }
CUSTOM_CVAR (Int, timidity_frequency, 44100, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) CVAR (Int, timidity_frequency, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
{ // Clamp frequency to Timidity's limits
if (self < 4000)
self = 4000;
else if (self > 65000)
self = 65000;
}
//========================================================================== //==========================================================================
// //
@ -105,7 +95,8 @@ CUSTOM_CVAR (Int, timidity_frequency, 44100, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
// //
//========================================================================== //==========================================================================
TimidityPPMIDIDevice::TimidityPPMIDIDevice(const char *args) TimidityPPMIDIDevice::TimidityPPMIDIDevice(const char *args, int samplerate)
:SoftSynthMIDIDevice(samplerate <= 0? timidity_frequency : samplerate, 4000, 65000)
{ {
if (args == NULL || *args == 0) args = timidity_config; if (args == NULL || *args == 0) args = timidity_config;
@ -115,8 +106,8 @@ TimidityPPMIDIDevice::TimidityPPMIDIDevice(const char *args)
delete instruments; delete instruments;
instruments = nullptr; instruments = nullptr;
} }
TimidityPlus::set_playback_rate(timidity_frequency); TimidityPlus::set_playback_rate(SampleRate);
SampleRate = timidity_frequency;
if (instruments == nullptr) if (instruments == nullptr)
{ {
instruments = new TimidityPlus::Instruments; instruments = new TimidityPlus::Instruments;
@ -229,9 +220,9 @@ void TimidityPPMIDIDevice::ComputeOutput(float *buffer, int len)
// //
//========================================================================== //==========================================================================
MIDIDevice *CreateTimidityPPMIDIDevice(const char *args) MIDIDevice *CreateTimidityPPMIDIDevice(const char *args, int samplerate)
{ {
return new TimidityPPMIDIDevice(args); return new TimidityPPMIDIDevice(args, samplerate);
} }
void TimidityPP_Shutdown() void TimidityPP_Shutdown()

View file

@ -87,7 +87,8 @@ struct FmtChunk
// //
//========================================================================== //==========================================================================
MIDIWaveWriter::MIDIWaveWriter(const char *filename, MIDIDevice *playdevice, int rate) MIDIWaveWriter::MIDIWaveWriter(const char *filename, MIDIDevice *playdevice)
: SoftSynthMIDIDevice(playDevice->GetSampleRate())
{ {
File = FileWriter::Open(filename); File = FileWriter::Open(filename);
playDevice = (SoftSynthMIDIDevice*) playdevice; playDevice = (SoftSynthMIDIDevice*) playdevice;
@ -102,15 +103,13 @@ MIDIWaveWriter::MIDIWaveWriter(const char *filename, MIDIDevice *playdevice, int
if (4*3 != File->Write(work, 4 * 3)) goto fail; if (4*3 != File->Write(work, 4 * 3)) goto fail;
playDevice->SetSampleRate(rate);
playDevice->CalcTickRate(); playDevice->CalcTickRate();
rate = playDevice->GetSampleRate(); // read back what the device made of it.
fmt.ChunkID = MAKE_ID('f','m','t',' '); fmt.ChunkID = MAKE_ID('f','m','t',' ');
fmt.ChunkLen = LittleLong(uint32_t(sizeof(fmt) - 8)); fmt.ChunkLen = LittleLong(uint32_t(sizeof(fmt) - 8));
fmt.FormatTag = LittleShort(0xFFFE); // WAVE_FORMAT_EXTENSIBLE fmt.FormatTag = LittleShort(0xFFFE); // WAVE_FORMAT_EXTENSIBLE
fmt.Channels = LittleShort(2); fmt.Channels = LittleShort(2);
fmt.SamplesPerSec = LittleLong(rate); fmt.SamplesPerSec = LittleLong(SampleRate);
fmt.AvgBytesPerSec = LittleLong(rate * 8); fmt.AvgBytesPerSec = LittleLong(SampleRate * 8);
fmt.BlockAlign = LittleShort(8); fmt.BlockAlign = LittleShort(8);
fmt.BitsPerSample = LittleShort(32); fmt.BitsPerSample = LittleShort(32);
fmt.ExtensionSize = LittleShort(2 + 4 + 16); fmt.ExtensionSize = LittleShort(2 + 4 + 16);

View file

@ -89,19 +89,11 @@ CUSTOM_CVAR(Bool, wildmidi_enhanced_resampling, true, CVAR_ARCHIVE | CVAR_GLOBAL
// //
//========================================================================== //==========================================================================
WildMIDIDevice::WildMIDIDevice(const char *args) WildMIDIDevice::WildMIDIDevice(const char *args, int samplerate)
:SoftSynthMIDIDevice(samplerate <= 0? wildmidi_frequency : samplerate, 11025, 65535)
{ {
Renderer = NULL; Renderer = NULL;
if (wildmidi_frequency > 0)
{
SampleRate = clamp(*wildmidi_frequency, 11025, 65535);
}
else
{ // If nothing is set, use the active device's output rate.
SampleRate = (int)GSnd->GetOutputRate();
}
if (args == NULL || *args == 0) args = wildmidi_config; if (args == NULL || *args == 0) args = wildmidi_config;
if (CurrentConfig.CompareNoCase(args) != 0 || SampleRate != WildMidi_GetSampleRate()) if (CurrentConfig.CompareNoCase(args) != 0 || SampleRate != WildMidi_GetSampleRate())

View file

@ -182,7 +182,7 @@ EMidiDevice MIDIStreamer::SelectMIDIDevice(EMidiDevice device)
static EMidiDevice lastRequestedDevice, lastSelectedDevice; static EMidiDevice lastRequestedDevice, lastSelectedDevice;
MIDIDevice *MIDIStreamer::CreateMIDIDevice(EMidiDevice devtype) MIDIDevice *MIDIStreamer::CreateMIDIDevice(EMidiDevice devtype, int samplerate)
{ {
bool checked[MDEV_COUNT] = { false }; bool checked[MDEV_COUNT] = { false };
@ -197,7 +197,7 @@ MIDIDevice *MIDIStreamer::CreateMIDIDevice(EMidiDevice devtype)
switch (devtype) switch (devtype)
{ {
case MDEV_GUS: case MDEV_GUS:
dev = new TimidityMIDIDevice(Args); dev = new TimidityMIDIDevice(Args, samplerate);
break; break;
case MDEV_MMAPI: case MDEV_MMAPI:
@ -208,7 +208,7 @@ MIDIDevice *MIDIStreamer::CreateMIDIDevice(EMidiDevice devtype)
// Intentional fall-through for non-Windows systems. // Intentional fall-through for non-Windows systems.
case MDEV_FLUIDSYNTH: case MDEV_FLUIDSYNTH:
dev = new FluidSynthMIDIDevice(Args); dev = new FluidSynthMIDIDevice(Args, samplerate);
break; break;
case MDEV_OPL: case MDEV_OPL:
@ -216,11 +216,11 @@ MIDIDevice *MIDIStreamer::CreateMIDIDevice(EMidiDevice devtype)
break; break;
case MDEV_TIMIDITY: case MDEV_TIMIDITY:
dev = CreateTimidityPPMIDIDevice(Args); dev = CreateTimidityPPMIDIDevice(Args, samplerate);
break; break;
case MDEV_WILDMIDI: case MDEV_WILDMIDI:
dev = new WildMIDIDevice(Args); dev = new WildMIDIDevice(Args, samplerate);
break; break;
default: default:
@ -284,7 +284,7 @@ void MIDIStreamer::Play(bool looping, int subsong)
m_Looping = looping; m_Looping = looping;
source->SetMIDISubsong(subsong); source->SetMIDISubsong(subsong);
devtype = SelectMIDIDevice(DeviceType); devtype = SelectMIDIDevice(DeviceType);
MIDI = CreateMIDIDevice(devtype); MIDI = CreateMIDIDevice(devtype, 0);
InitPlayback(); InitPlayback();
} }
@ -319,8 +319,8 @@ bool MIDIStreamer::DumpWave(const char *filename, int subsong, int samplerate)
assert(MIDI == NULL); assert(MIDI == NULL);
auto devtype = SelectMIDIDevice(DeviceType); auto devtype = SelectMIDIDevice(DeviceType);
MIDI = CreateMIDIDevice(devtype); MIDI = CreateMIDIDevice(devtype, samplerate);
MIDI = new MIDIWaveWriter(filename, MIDI, samplerate); MIDI = new MIDIWaveWriter(filename, MIDI);
return InitPlayback(); return InitPlayback();
} }