- 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
MIDIDevice *CreateWinMIDIDevice(int mididevice);
#endif
MIDIDevice *CreateTimidityPPMIDIDevice(const char *args);
MIDIDevice *CreateTimidityPPMIDIDevice(const char *args, int samplerate);
void TimidityPP_Shutdown();
// Base class for software synthesizer MIDI output devices ------------------
@ -97,7 +97,7 @@ class SoftSynthMIDIDevice : public MIDIDevice
{
friend class MIDIWaveWriter;
public:
SoftSynthMIDIDevice();
SoftSynthMIDIDevice(int samplerate, int minrate = 1, int maxrate = 1000000 /* something higher than any valid value */);
~SoftSynthMIDIDevice();
void Close();
@ -131,10 +131,6 @@ protected:
int OpenStream(int chunks, int flags, MidiCallback, void *userdata);
static bool FillStream(SoundStream *stream, void *buff, int len, void *userdata);
virtual bool ServiceStream (void *buff, int numbytes);
virtual void SetSampleRate(int rate)
{
if (rate > 11025) { SampleRate = rate; }
}
int GetSampleRate() const { return SampleRate; }
virtual void HandleEvent(int status, int parm1, int parm2) = 0;
@ -152,7 +148,6 @@ public:
void Close();
int GetTechnology() const;
FString GetStats();
virtual void SetSampleRate(int rate) { } // cannot be changed.
protected:
void CalcTickRate();
@ -182,14 +177,13 @@ namespace Timidity { struct Renderer; }
class TimidityMIDIDevice : public SoftSynthMIDIDevice
{
public:
TimidityMIDIDevice(const char *args);
TimidityMIDIDevice(const char *args, int samplerate);
~TimidityMIDIDevice();
int Open(MidiCallback, void *userdata);
void PrecacheInstruments(const uint16_t *instruments, int count);
FString GetStats();
int GetDeviceType() const override { return MDEV_GUS; }
virtual void SetSampleRate(int rate) { if (rate >= 11025 && rate < 65535) SampleRate = rate; }
protected:
Timidity::Renderer *Renderer;
@ -204,7 +198,7 @@ protected:
class MIDIWaveWriter : public SoftSynthMIDIDevice
{
public:
MIDIWaveWriter(const char *filename, MIDIDevice *devtouse, int rate);
MIDIWaveWriter(const char *filename, MIDIDevice *devtouse);
~MIDIWaveWriter();
int Resume();
int Open(MidiCallback cb, void *userdata)
@ -235,14 +229,13 @@ protected:
class WildMIDIDevice : public SoftSynthMIDIDevice
{
public:
WildMIDIDevice(const char *args);
WildMIDIDevice(const char *args, int samplerate);
~WildMIDIDevice();
int Open(MidiCallback, void *userdata);
void PrecacheInstruments(const uint16_t *instruments, int count);
FString GetStats();
int GetDeviceType() const override { return MDEV_WILDMIDI; }
virtual void SetSampleRate(int rate) { if (rate >= 11025 && SampleRate < rate) SampleRate = rate; }
protected:
WildMidi_Renderer *Renderer;
@ -268,7 +261,7 @@ struct fluid_synth_t;
class FluidSynthMIDIDevice : public SoftSynthMIDIDevice
{
public:
FluidSynthMIDIDevice(const char *args);
FluidSynthMIDIDevice(const char *args, int samplerate);
~FluidSynthMIDIDevice();
int Open(MidiCallback, void *userdata);
@ -277,7 +270,6 @@ public:
void FluidSettingNum(const char *setting, double value);
void FluidSettingStr(const char *setting, const char *value);
int GetDeviceType() const override { return MDEV_FLUIDSYNTH; }
virtual void SetSampleRate(int rate) { if (rate >= 22050 && rate <= 96000) SampleRate = rate; }
protected:
void HandleEvent(int status, int parm1, int parm2);
@ -382,7 +374,7 @@ protected:
static EMidiDevice SelectMIDIDevice(EMidiDevice devtype);
MIDIDevice *CreateMIDIDevice(EMidiDevice devtype);
MIDIDevice *CreateMIDIDevice(EMidiDevice devtype, int samplerate);
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;
FluidSettings = NULL;
@ -290,11 +291,6 @@ FluidSynthMIDIDevice::FluidSynthMIDIDevice(const char *args)
printf("Failed to create FluidSettings.\n");
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.gain", fluid_gain);
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)
: SoftSynthMIDIDevice((int)OPL_SAMPLE_RATE)
{
OPL_SetCore(args);
FullPan = opl_fullpan;
@ -88,7 +89,6 @@ OPLMIDIDevice::OPLMIDIDevice(const char *args)
data.Read(filehdr, 8);
if (memcmp(filehdr, "#OPL_II#", 8)) I_Error("Corrupt GENMIDI lump");
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;
Tempo = 0;
Division = 0;
Events = NULL;
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);
}

View file

@ -53,7 +53,7 @@ class TimidityPPMIDIDevice : public SoftSynthMIDIDevice
static TimidityPlus::Instruments *instruments;
int sampletime;
public:
TimidityPPMIDIDevice(const char *args);
TimidityPPMIDIDevice(const char *args, int samplerate);
~TimidityPPMIDIDevice();
int Open(MidiCallback, void *userdata);
@ -65,10 +65,6 @@ public:
if (instruments != nullptr) delete instruments;
instruments = nullptr;
}
virtual void SetSampleRate(int rate)
{
if (rate >= 4000 && SampleRate < rate) SampleRate = rate;
}
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)
{ // Clamp frequency to Timidity's limits
if (self < 4000)
self = 4000;
else if (self > 65000)
self = 65000;
}
CVAR (Int, timidity_frequency, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
//==========================================================================
//
@ -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;
@ -115,8 +106,8 @@ TimidityPPMIDIDevice::TimidityPPMIDIDevice(const char *args)
delete instruments;
instruments = nullptr;
}
TimidityPlus::set_playback_rate(timidity_frequency);
SampleRate = timidity_frequency;
TimidityPlus::set_playback_rate(SampleRate);
if (instruments == nullptr)
{
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()

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);
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;
playDevice->SetSampleRate(rate);
playDevice->CalcTickRate();
rate = playDevice->GetSampleRate(); // read back what the device made of it.
fmt.ChunkID = MAKE_ID('f','m','t',' ');
fmt.ChunkLen = LittleLong(uint32_t(sizeof(fmt) - 8));
fmt.FormatTag = LittleShort(0xFFFE); // WAVE_FORMAT_EXTENSIBLE
fmt.Channels = LittleShort(2);
fmt.SamplesPerSec = LittleLong(rate);
fmt.AvgBytesPerSec = LittleLong(rate * 8);
fmt.SamplesPerSec = LittleLong(SampleRate);
fmt.AvgBytesPerSec = LittleLong(SampleRate * 8);
fmt.BlockAlign = LittleShort(8);
fmt.BitsPerSample = LittleShort(32);
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;
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 (CurrentConfig.CompareNoCase(args) != 0 || SampleRate != WildMidi_GetSampleRate())

View file

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