Merge commit '772a572431' into scripting

Conflicts:
	src/p_pspr.cpp
	src/thingdef/thingdef_codeptr.cpp
This commit is contained in:
Christoph Oelckers 2016-01-17 20:00:45 +01:00
commit cfcd2668cc
94 changed files with 6366 additions and 964 deletions

View file

@ -44,7 +44,7 @@ extern HWND Window;
#define FALSE 0
#define TRUE 1
#endif
#ifdef __APPLE__
#if defined(__FreeBSD__) || defined(__APPLE__)
#include <stdlib.h>
#elif __sun
#include <alloca.h>

View file

@ -162,7 +162,7 @@ void I_InitMusic (void)
if (!setatterm)
{
setatterm = true;
atterm (I_ShutdownMusic);
atterm (I_ShutdownMusicExit);
#ifndef _WIN32
signal (SIGCHLD, ChildSigHandler);
@ -178,7 +178,7 @@ void I_InitMusic (void)
//
//==========================================================================
void I_ShutdownMusic(void)
void I_ShutdownMusic(bool onexit)
{
if (MusicDown)
return;
@ -189,11 +189,17 @@ void I_ShutdownMusic(void)
assert (currSong == NULL);
}
Timidity::FreeAll();
if (onexit) WildMidi_Shutdown();
#ifdef _WIN32
I_ShutdownMusicWin32();
#endif // _WIN32
}
void I_ShutdownMusicExit()
{
I_ShutdownMusic(true);
}
//==========================================================================
//
@ -280,6 +286,10 @@ void MusInfo::FluidSettingStr(const char *, const char *)
{
}
void MusInfo::WildMidiSetOption(int opt, int set)
{
}
FString MusInfo::GetStats()
{
return "No stats available for this song";
@ -301,21 +311,21 @@ MusInfo *MusInfo::GetWaveDumper(const char *filename, int rate)
//
//==========================================================================
static MIDIStreamer *CreateMIDIStreamer(FileReader &reader, EMidiDevice devtype, EMIDIType miditype)
static MIDIStreamer *CreateMIDIStreamer(FileReader &reader, EMidiDevice devtype, EMIDIType miditype, const char *args)
{
switch (miditype)
{
case MIDI_MUS:
return new MUSSong2(reader, devtype);
return new MUSSong2(reader, devtype, args);
case MIDI_MIDI:
return new MIDISong2(reader, devtype);
return new MIDISong2(reader, devtype, args);
case MIDI_HMI:
return new HMISong(reader, devtype);
return new HMISong(reader, devtype, args);
case MIDI_XMI:
return new XMISong(reader, devtype);
return new XMISong(reader, devtype, args);
default:
return NULL;
@ -377,7 +387,7 @@ static EMIDIType IdentifyMIDIType(DWORD *id, int size)
//
//==========================================================================
MusInfo *I_RegisterSong (FileReader *reader, int device)
MusInfo *I_RegisterSong (FileReader *reader, MidiDeviceSetting *device)
{
MusInfo *info = NULL;
const char *fmt;
@ -395,12 +405,6 @@ MusInfo *I_RegisterSong (FileReader *reader, int device)
return 0;
}
#ifndef _WIN32
// non-Windows platforms don't support MDEV_MMAPI so map to MDEV_SNDSYS
if (device == MDEV_MMAPI)
device = MDEV_SNDSYS;
#endif
// Check for gzip compression. Some formats are expected to have players
// that can handle it, so it simplifies things if we make all songs
// gzippable.
@ -437,10 +441,15 @@ MusInfo *I_RegisterSong (FileReader *reader, int device)
EMIDIType miditype = IdentifyMIDIType(id, sizeof(id));
if (miditype != MIDI_NOTMIDI)
{
EMidiDevice devtype = (EMidiDevice)device;
EMidiDevice devtype = device == NULL? MDEV_DEFAULT : (EMidiDevice)device->device;
#ifndef _WIN32
// non-Windows platforms don't support MDEV_MMAPI so map to MDEV_SNDSYS
if (devtype == MDEV_MMAPI)
devtype = MDEV_SNDSYS;
#endif
retry_as_sndsys:
info = CreateMIDIStreamer(*reader, devtype, miditype);
info = CreateMIDIStreamer(*reader, devtype, miditype, device != NULL? device->args.GetChars() : "");
if (info != NULL && !info->IsValid())
{
delete info;
@ -454,7 +463,7 @@ retry_as_sndsys:
#ifdef _WIN32
if (info == NULL && devtype != MDEV_MMAPI && snd_mididevice >= 0)
{
info = CreateMIDIStreamer(*reader, MDEV_MMAPI, miditype);
info = CreateMIDIStreamer(*reader, MDEV_MMAPI, miditype, "");
}
#endif
}
@ -465,7 +474,7 @@ retry_as_sndsys:
(id[0] == MAKE_ID('D','B','R','A') && id[1] == MAKE_ID('W','O','P','L')) || // DosBox Raw OPL
(id[0] == MAKE_ID('A','D','L','I') && *((BYTE *)id + 4) == 'B')) // Martin Fernandez's modified IMF
{
info = new OPLMUSSong (*reader);
info = new OPLMUSSong (*reader, device != NULL? device->args.GetChars() : "");
}
// Check for game music
else if ((fmt = GME_CheckFormat(id[0])) != NULL && fmt[0] != '\0')

View file

@ -43,7 +43,8 @@ struct FOptionValues;
// MUSIC I/O
//
void I_InitMusic ();
void I_ShutdownMusic ();
void I_ShutdownMusic (bool onexit = false);
void I_ShutdownMusicExit ();
void I_BuildMIDIMenuList (FOptionValues *);
void I_UpdateMusic ();
@ -52,7 +53,8 @@ void I_SetMusicVolume (float volume);
// Registers a song handle to song data.
class MusInfo;
MusInfo *I_RegisterSong (FileReader *reader, int device);
struct MidiDeviceSetting;
MusInfo *I_RegisterSong (FileReader *reader, MidiDeviceSetting *device);
MusInfo *I_RegisterCDSong (int track, int cdid = 0);
MusInfo *I_RegisterURLSong (const char *url);
@ -81,6 +83,7 @@ public:
virtual void FluidSettingInt(const char *setting, int value); // FluidSynth settings
virtual void FluidSettingNum(const char *setting, double value); // "
virtual void FluidSettingStr(const char *setting, const char *value); // "
virtual void WildMidiSetOption(int opt, int set);
void Start(bool loop, float rel_vol = -1.f, int subsong = 0);

View file

@ -24,6 +24,7 @@
#include "i_music.h"
#include "s_sound.h"
#include "files.h"
#include "wildmidi/wildmidi_lib.h"
void I_InitMusicWin32 ();
void I_ShutdownMusicWin32 ();
@ -101,6 +102,7 @@ public:
virtual void FluidSettingInt(const char *setting, int value);
virtual void FluidSettingNum(const char *setting, double value);
virtual void FluidSettingStr(const char *setting, const char *value);
virtual void WildMidiSetOption(int opt, int set);
virtual bool Preprocess(MIDIStreamer *song, bool looping);
virtual FString GetStats();
};
@ -183,7 +185,7 @@ public:
class TimidityPPMIDIDevice : public PseudoMIDIDevice
{
public:
TimidityPPMIDIDevice();
TimidityPPMIDIDevice(const char *args);
~TimidityPPMIDIDevice();
int Open(void (*callback)(unsigned int, void *, DWORD, DWORD), void *userdata);
@ -218,7 +220,6 @@ protected:
#endif
};
// Base class for software synthesizer MIDI output devices ------------------
class SoftSynthMIDIDevice : public MIDIDevice
@ -269,7 +270,7 @@ protected:
class OPLMIDIDevice : public SoftSynthMIDIDevice, protected OPLmusicBlock
{
public:
OPLMIDIDevice();
OPLMIDIDevice(const char *args);
int Open(void (*callback)(unsigned int, void *, DWORD, DWORD), void *userdata);
void Close();
int GetTechnology() const;
@ -302,7 +303,7 @@ namespace Timidity { struct Renderer; }
class TimidityMIDIDevice : public SoftSynthMIDIDevice
{
public:
TimidityMIDIDevice();
TimidityMIDIDevice(const char *args);
~TimidityMIDIDevice();
int Open(void (*callback)(unsigned int, void *, DWORD, DWORD), void *userdata);
@ -331,6 +332,27 @@ protected:
FILE *File;
};
// WildMidi implementation of a MIDI device ---------------------------------
class WildMIDIDevice : public SoftSynthMIDIDevice
{
public:
WildMIDIDevice(const char *args);
~WildMIDIDevice();
int Open(void (*callback)(unsigned int, void *, DWORD, DWORD), void *userdata);
void PrecacheInstruments(const WORD *instruments, int count);
FString GetStats();
protected:
WildMidi_Renderer *Renderer;
void HandleEvent(int status, int parm1, int parm2);
void HandleLongEvent(const BYTE *data, int len);
void ComputeOutput(float *buffer, int len);
void WildMidiSetOption(int opt, int set);
};
// FluidSynth implementation of a MIDI device -------------------------------
#ifdef HAVE_FLUIDSYNTH
@ -344,7 +366,7 @@ struct fluid_synth_t;
class FluidSynthMIDIDevice : public SoftSynthMIDIDevice
{
public:
FluidSynthMIDIDevice();
FluidSynthMIDIDevice(const char *args);
~FluidSynthMIDIDevice();
int Open(void (*callback)(unsigned int, void *, DWORD, DWORD), void *userdata);
@ -409,7 +431,7 @@ protected:
class MIDIStreamer : public MusInfo
{
public:
MIDIStreamer(EMidiDevice type);
MIDIStreamer(EMidiDevice type, const char *args);
~MIDIStreamer();
void MusicVolumeChanged();
@ -427,6 +449,7 @@ public:
void FluidSettingInt(const char *setting, int value);
void FluidSettingNum(const char *setting, double value);
void FluidSettingStr(const char *setting, const char *value);
void WildMidiSetOption(int opt, int set);
void CreateSMF(TArray<BYTE> &file, int looplimit=0);
protected:
@ -494,6 +517,7 @@ protected:
bool CallbackIsThreaded;
int LoopLimit;
FString DumpFilename;
FString Args;
};
// MUS file played with a MIDI stream ---------------------------------------
@ -501,7 +525,7 @@ protected:
class MUSSong2 : public MIDIStreamer
{
public:
MUSSong2(FileReader &reader, EMidiDevice type);
MUSSong2(FileReader &reader, EMidiDevice type, const char *args);
~MUSSong2();
MusInfo *GetOPLDumper(const char *filename);
@ -527,7 +551,7 @@ protected:
class MIDISong2 : public MIDIStreamer
{
public:
MIDISong2(FileReader &reader, EMidiDevice type);
MIDISong2(FileReader &reader, EMidiDevice type, const char *args);
~MIDISong2();
MusInfo *GetOPLDumper(const char *filename);
@ -546,7 +570,7 @@ protected:
struct TrackInfo;
void ProcessInitialMetaEvents ();
DWORD *SendCommand (DWORD *event, TrackInfo *track, DWORD delay);
DWORD *SendCommand (DWORD *event, TrackInfo *track, DWORD delay, ptrdiff_t room, bool &sysex_noroom);
TrackInfo *FindNextDue ();
BYTE *MusHeader;
@ -584,7 +608,7 @@ protected:
class HMISong : public MIDIStreamer
{
public:
HMISong(FileReader &reader, EMidiDevice type);
HMISong(FileReader &reader, EMidiDevice type, const char *args);
~HMISong();
MusInfo *GetOPLDumper(const char *filename);
@ -627,7 +651,7 @@ protected:
class XMISong : public MIDIStreamer
{
public:
XMISong(FileReader &reader, EMidiDevice type);
XMISong(FileReader &reader, EMidiDevice type, const char *args);
~XMISong();
MusInfo *GetOPLDumper(const char *filename);
@ -690,7 +714,7 @@ protected:
class OPLMUSSong : public StreamSong
{
public:
OPLMUSSong (FileReader &reader);
OPLMUSSong (FileReader &reader, const char *args);
~OPLMUSSong ();
void Play (bool looping, int subsong);
bool IsPlaying ();

View file

@ -255,7 +255,7 @@ CUSTOM_CVAR(Int, fluid_chorus_type, FLUID_CHORUS_DEFAULT_TYPE, CVAR_ARCHIVE|CVAR
//
//==========================================================================
FluidSynthMIDIDevice::FluidSynthMIDIDevice()
FluidSynthMIDIDevice::FluidSynthMIDIDevice(const char *args)
{
FluidSynth = NULL;
FluidSettings = NULL;
@ -293,7 +293,15 @@ FluidSynthMIDIDevice::FluidSynthMIDIDevice()
fluid_reverb_width, fluid_reverb_level);
fluid_synth_set_chorus(FluidSynth, fluid_chorus_voices, fluid_chorus_level,
fluid_chorus_speed, fluid_chorus_depth, fluid_chorus_type);
if (0 == LoadPatchSets(fluid_patchset))
// try loading a patch set that got specified with $mididevice.
int res = 0;
if (args != NULL && *args != 0)
{
res = LoadPatchSets(args);
}
if (res == 0 && 0 == LoadPatchSets(fluid_patchset))
{
#ifdef __unix__
// This is the standard location on Ubuntu.

View file

@ -128,8 +128,8 @@ extern char MIDI_CommonLengths[15];
//
//==========================================================================
HMISong::HMISong (FileReader &reader, EMidiDevice type)
: MIDIStreamer(type), MusHeader(0), Tracks(0)
HMISong::HMISong (FileReader &reader, EMidiDevice type, const char *args)
: MIDIStreamer(type, args), MusHeader(0), Tracks(0)
{
#ifdef _WIN32
if (ExitEvent == NULL)

View file

@ -11,9 +11,9 @@ static DWORD nummididevices;
static bool nummididevicesset;
#ifdef HAVE_FLUIDSYNTH
#define NUM_DEF_DEVICES 5
#define NUM_DEF_DEVICES 6
#else
#define NUM_DEF_DEVICES 4
#define NUM_DEF_DEVICES 5
#endif
static void AddDefaultMidiDevices(FOptionValues *opt)
@ -33,8 +33,10 @@ static void AddDefaultMidiDevices(FOptionValues *opt)
pair[p+1].Value = -3.0;
pair[p+2].Text = "TiMidity++";
pair[p+2].Value = -2.0;
pair[p+3].Text = "Sound System";
pair[p+3].Value = -1.0;
pair[p+3].Text = "WildMidi";
pair[p+3].Value = -6.0;
pair[p+4].Text = "Sound System";
pair[p+4].Value = -1.0;
}
@ -70,7 +72,7 @@ CUSTOM_CVAR (Int, snd_mididevice, -1, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
if (!nummididevicesset)
return;
if ((self >= (signed)nummididevices) || (self < -5))
if ((self >= (signed)nummididevices) || (self < -6))
{
Printf ("ID out of range. Using default device.\n");
self = 0;
@ -166,6 +168,7 @@ CCMD (snd_listmididevices)
MIDIOUTCAPS caps;
MMRESULT res;
PrintMidiDevice (-6, "WildMidi", MOD_SWSYNTH, 0);
#ifdef HAVE_FLUIDSYNTH
PrintMidiDevice (-5, "FluidSynth", MOD_SWSYNTH, 0);
#endif
@ -196,8 +199,8 @@ CCMD (snd_listmididevices)
CUSTOM_CVAR(Int, snd_mididevice, -1, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
{
if (self < -5)
self = -5;
if (self < -6)
self = -6;
else if (self > -1)
self = -1;
else
@ -211,6 +214,7 @@ void I_BuildMIDIMenuList (FOptionValues *opt)
CCMD (snd_listmididevices)
{
Printf("%s-6. WildMidi\n", -6 == snd_mididevice ? TEXTCOLOR_BOLD : "");
#ifdef HAVE_FLUIDSYNTH
Printf("%s-5. FluidSynth\n", -5 == snd_mididevice ? TEXTCOLOR_BOLD : "");
#endif

View file

@ -72,7 +72,7 @@ CUSTOM_CVAR (Int, timidity_frequency, 22050, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
//
//==========================================================================
TimidityPPMIDIDevice::TimidityPPMIDIDevice()
TimidityPPMIDIDevice::TimidityPPMIDIDevice(const char *args)
: DiskName("zmid"),
#ifdef _WIN32
ReadWavePipe(INVALID_HANDLE_VALUE), WriteWavePipe(INVALID_HANDLE_VALUE),
@ -85,7 +85,13 @@ TimidityPPMIDIDevice::TimidityPPMIDIDevice()
#ifndef _WIN32
WavePipe[0] = WavePipe[1] = -1;
#endif
if (args == NULL || *args == 0) args = timidity_exe;
CommandLine.Format("%s %s -EFchorus=%s -EFreverb=%s -s%d ",
args, *timidity_extargs,
*timidity_chorus, *timidity_reverb, *timidity_frequency);
if (DiskName == NULL)
{
Printf(PRINT_BOLD, "Could not create temp music file\n");
@ -187,10 +193,6 @@ int TimidityPPMIDIDevice::Open(void (*callback)(unsigned int, void *, DWORD, DWO
Validated = true;
#endif // WIN32
CommandLine.Format("%s %s -EFchorus=%s -EFreverb=%s -s%d ",
*timidity_exe, *timidity_extargs,
*timidity_chorus, *timidity_reverb, *timidity_frequency);
pipeSize = (timidity_pipe * timidity_frequency / 1000)
<< (timidity_stereo + !timidity_8bit);

View file

@ -89,12 +89,12 @@ static const BYTE StaticMIDIhead[] =
//
//==========================================================================
MIDIStreamer::MIDIStreamer(EMidiDevice type)
MIDIStreamer::MIDIStreamer(EMidiDevice type, const char *args)
:
#ifdef _WIN32
PlayerThread(0), ExitEvent(0), BufferDoneEvent(0),
#endif
MIDI(0), Division(0), InitialTempo(500000), DeviceType(type)
MIDI(0), Division(0), InitialTempo(500000), DeviceType(type), Args(args)
{
#ifdef _WIN32
BufferDoneEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
@ -240,6 +240,7 @@ EMidiDevice MIDIStreamer::SelectMIDIDevice(EMidiDevice device)
#ifdef HAVE_FLUIDSYNTH
case -5: return MDEV_FLUIDSYNTH;
#endif
case -6: return MDEV_WILDMIDI;
default:
#ifdef _WIN32
return MDEV_MMAPI;
@ -268,19 +269,19 @@ MIDIDevice *MIDIStreamer::CreateMIDIDevice(EMidiDevice devtype) const
#ifdef HAVE_FLUIDSYNTH
case MDEV_FLUIDSYNTH:
return new FluidSynthMIDIDevice;
return new FluidSynthMIDIDevice(Args);
#endif
case MDEV_SNDSYS:
return new SndSysMIDIDevice;
case MDEV_GUS:
return new TimidityMIDIDevice;
return new TimidityMIDIDevice(Args);
case MDEV_OPL:
try
{
return new OPLMIDIDevice;
return new OPLMIDIDevice(Args);
}
catch (CRecoverableError &err)
{
@ -290,7 +291,10 @@ MIDIDevice *MIDIStreamer::CreateMIDIDevice(EMidiDevice devtype) const
}
case MDEV_TIMIDITY:
return new TimidityPPMIDIDevice;
return new TimidityPPMIDIDevice(Args);
case MDEV_WILDMIDI:
return new WildMIDIDevice(Args);
default:
return NULL;
@ -622,6 +626,21 @@ void MIDIStreamer::FluidSettingStr(const char *setting, const char *value)
}
//==========================================================================
//
// MIDIDeviceStreamer :: WildMidiSetOption
//
//==========================================================================
void MIDIStreamer::WildMidiSetOption(int opt, int set)
{
if (MIDI != NULL)
{
MIDI->WildMidiSetOption(opt, set);
}
}
//==========================================================================
//
// MIDIStreamer :: OutputVolume
@ -1192,9 +1211,15 @@ void MIDIStreamer::CreateSMF(TArray<BYTE> &file, int looplimit)
len--;
file.Push(MIDI_SYSEX);
WriteVarLen(file, len);
memcpy(&file[file.Reserve(len - 1)], bytes, len);
running_status = 255;
memcpy(&file[file.Reserve(len)], bytes + 1, len);
}
else
{
file.Push(MIDI_SYSEXEND);
WriteVarLen(file, len);
memcpy(&file[file.Reserve(len)], bytes, len);
}
running_status = 255;
}
else if (MEVT_EVENTTYPE(event[2]) == 0)
{
@ -1512,6 +1537,16 @@ void MIDIDevice::FluidSettingStr(const char *setting, const char *value)
{
}
//==========================================================================
//
// MIDIDevice :: WildMidiSetOption
//
//==========================================================================
void MIDIDevice::WildMidiSetOption(int opt, int set)
{
}
//==========================================================================
//
// MIDIDevice :: GetStats

View file

@ -43,6 +43,7 @@
#include "doomdef.h"
#include "m_swap.h"
#include "files.h"
#include "s_sound.h"
// MACROS ------------------------------------------------------------------
@ -92,8 +93,8 @@ static const BYTE CtrlTranslate[15] =
//
//==========================================================================
MUSSong2::MUSSong2 (FileReader &reader, EMidiDevice type)
: MIDIStreamer(type), MusHeader(0), MusBuffer(0)
MUSSong2::MUSSong2 (FileReader &reader, EMidiDevice type, const char *args)
: MIDIStreamer(type, args), MusHeader(0), MusBuffer(0)
{
#ifdef _WIN32
if (ExitEvent == NULL)
@ -210,23 +211,44 @@ bool MUSSong2::CheckDone()
void MUSSong2::Precache()
{
WORD *work = (WORD *)alloca(MusHeader->NumInstruments * sizeof(WORD));
const WORD *used = (WORD *)MusHeader + sizeof(MUSHeader) / sizeof(WORD);
int i, j;
TArray<WORD> work(MusHeader->NumInstruments);
const BYTE *used = (BYTE *)MusHeader + sizeof(MUSHeader) / sizeof(BYTE);
int i, k;
for (i = j = 0; i < MusHeader->NumInstruments; ++i)
for (i = k = 0; i < MusHeader->NumInstruments; ++i)
{
WORD instr = LittleShort(used[i]);
BYTE instr = used[k++];
WORD val;
if (instr < 128)
{
work[j++] = instr;
val = instr;
}
else if (used[i] >= 135 && used[i] <= 181)
else if (instr >= 135 && instr <= 188)
{ // Percussions are 100-based, not 128-based, eh?
work[j++] = instr - 100 + (1 << 14);
val = instr - 100 + (1 << 14);
}
else
{
// skip it.
val = used[k++];
k += val;
continue;
}
int numbanks = used[k++];
if (numbanks > 0)
{
for (int b = 0; b < numbanks; b++)
{
work.Push(val | (used[k++] << 7));
}
}
else
{
work.Push(val);
}
}
MIDI->PrecacheInstruments(&work[0], j);
MIDI->PrecacheInstruments(&work[0], work.Size());
}
//==========================================================================

View file

@ -20,16 +20,25 @@ CUSTOM_CVAR (Int, opl_numchips, 2, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
}
}
CVAR(Int, opl_core, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
CVAR(Int, opl_core, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
int current_opl_core;
OPLMUSSong::OPLMUSSong (FileReader &reader)
// Get OPL core override from $mididevice
void OPL_SetCore(const char *args)
{
current_opl_core = opl_core;
if (args != NULL && *args >= '0' && *args < '4') current_opl_core = *args - '0';
}
OPLMUSSong::OPLMUSSong (FileReader &reader, const char *args)
{
int samples = int(OPL_SAMPLE_RATE / 14);
OPL_SetCore(args);
Music = new OPLmusicFile (&reader);
m_Stream = GSnd->CreateStream (FillStream, samples*4,
(opl_core == 0 ? SoundStream::Mono : 0) | SoundStream::Float, int(OPL_SAMPLE_RATE), this);
(current_opl_core == 0 ? SoundStream::Mono : 0) | SoundStream::Float, int(OPL_SAMPLE_RATE), this);
if (m_Stream == NULL)
{
Printf (PRINT_BOLD, "Could not create music stream.\n");

View file

@ -102,8 +102,8 @@ char MIDI_CommonLengths[15] = { 0, 1, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
//
//==========================================================================
MIDISong2::MIDISong2 (FileReader &reader, EMidiDevice type)
: MIDIStreamer(type), MusHeader(0), Tracks(0)
MIDISong2::MIDISong2 (FileReader &reader, EMidiDevice type, const char *args)
: MIDIStreamer(type, args), MusHeader(0), Tracks(0)
{
int p;
int i;
@ -322,7 +322,12 @@ DWORD *MIDISong2::MakeEvents(DWORD *events, DWORD *max_event_p, DWORD max_time)
// Play all events for this tick.
do
{
DWORD *new_events = SendCommand(events, TrackDue, time);
bool sysex_noroom = false;
DWORD *new_events = SendCommand(events, TrackDue, time, max_event_p - events, sysex_noroom);
if (sysex_noroom)
{
return events;
}
TrackDue = FindNextDue();
if (new_events != events)
{
@ -366,12 +371,15 @@ void MIDISong2::AdvanceTracks(DWORD time)
//
//==========================================================================
DWORD *MIDISong2::SendCommand (DWORD *events, TrackInfo *track, DWORD delay)
DWORD *MIDISong2::SendCommand (DWORD *events, TrackInfo *track, DWORD delay, ptrdiff_t room, bool &sysex_noroom)
{
DWORD len;
BYTE event, data1 = 0, data2 = 0;
int i;
sysex_noroom = false;
size_t start_p = track->TrackP;
CHECK_FINISHED
event = track->TrackBegin[track->TrackP++];
CHECK_FINISHED
@ -588,13 +596,44 @@ DWORD *MIDISong2::SendCommand (DWORD *events, TrackInfo *track, DWORD delay)
}
else
{
// Skip SysEx events just because I don't want to bother with them.
// The old MIDI player ignored them too, so this won't break
// anything that played before.
// SysEx events could potentially not have enough room in the buffer...
if (event == MIDI_SYSEX || event == MIDI_SYSEXEND)
{
len = track->ReadVarLen ();
track->TrackP += len;
len = track->ReadVarLen();
if (len >= (MAX_EVENTS-1)*3*4)
{ // This message will never fit. Throw it away.
track->TrackP += len;
}
else if (len + 12 >= (size_t)room * 4)
{ // Not enough room left in this buffer. Backup and wait for the next one.
track->TrackP = start_p;
sysex_noroom = true;
return events;
}
else
{
events[0] = delay;
events[1] = 0;
BYTE *msg = (BYTE *)&events[3];
if (event == MIDI_SYSEX)
{ // Need to add the SysEx marker to the message.
events[2] = (MEVT_LONGMSG << 24) | (len + 1);
*msg++ = MIDI_SYSEX;
}
else
{
events[2] = (MEVT_LONGMSG << 24) | len;
}
memcpy(msg, &track->TrackBegin[track->TrackP], len);
msg += len;
// Must pad with 0
while ((size_t)msg & 3)
{
*msg++ = 0;
}
events = (DWORD *)msg;
track->TrackP += len;
}
}
else if (event == MIDI_META)
{

View file

@ -86,10 +86,10 @@ struct FmtChunk
//
//==========================================================================
TimidityMIDIDevice::TimidityMIDIDevice()
TimidityMIDIDevice::TimidityMIDIDevice(const char *args)
{
Renderer = NULL;
Renderer = new Timidity::Renderer((float)SampleRate);
Renderer = new Timidity::Renderer((float)SampleRate, args);
}
//==========================================================================
@ -245,6 +245,7 @@ FString TimidityMIDIDevice::GetStats()
//==========================================================================
TimidityWaveWriterMIDIDevice::TimidityWaveWriterMIDIDevice(const char *filename, int rate)
:TimidityMIDIDevice(NULL)
{
File = fopen(filename, "wb");
if (File != NULL)

View file

@ -0,0 +1,234 @@
/*
** music_wildmidi_mididevice.cpp
** Provides access to WildMidi as a generic MIDI device.
**
**---------------------------------------------------------------------------
** Copyright 2015 Randy Heit
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** 3. The name of the author may not be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**---------------------------------------------------------------------------
**
*/
// HEADER FILES ------------------------------------------------------------
#include "i_musicinterns.h"
#include "templates.h"
#include "doomdef.h"
#include "m_swap.h"
#include "w_wad.h"
#include "v_text.h"
// MACROS ------------------------------------------------------------------
// TYPES -------------------------------------------------------------------
// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
// EXTERNAL DATA DECLARATIONS ----------------------------------------------
// PRIVATE DATA DEFINITIONS ------------------------------------------------
static FString CurrentConfig;
// PUBLIC DATA DEFINITIONS -------------------------------------------------
CVAR(String, wildmidi_config, "", CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
CVAR(Int, wildmidi_frequency, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
CUSTOM_CVAR(Bool, wildmidi_reverb, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL)
{
if (currSong != NULL)
currSong->WildMidiSetOption(WM_MO_REVERB, *self? WM_MO_REVERB:0);
}
CUSTOM_CVAR(Bool, wildmidi_enhanced_resampling, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL)
{
if (currSong != NULL)
currSong->WildMidiSetOption(WM_MO_ENHANCED_RESAMPLING, *self? WM_MO_ENHANCED_RESAMPLING:0);
}
// CODE --------------------------------------------------------------------
//==========================================================================
//
// WildMIDIDevice Constructor
//
//==========================================================================
WildMIDIDevice::WildMIDIDevice(const char *args)
{
Renderer = NULL;
if (wildmidi_frequency >= 11025 && wildmidi_frequency < 65536)
{ // Use our own sample rate instead of the global one
SampleRate = wildmidi_frequency;
}
else
{ // Else make sure we're not outside of WildMidi's range
SampleRate = clamp(SampleRate, 11025, 65535);
}
if (args == NULL || *args == 0) args = wildmidi_config;
if (CurrentConfig.CompareNoCase(args) != 0 || SampleRate != WildMidi_GetSampleRate())
{
if (CurrentConfig.IsNotEmpty())
{
WildMidi_Shutdown();
CurrentConfig = "";
}
if (!WildMidi_Init(args, SampleRate, 0))
{
CurrentConfig = args;
}
}
if (CurrentConfig.IsNotEmpty())
{
Renderer = new WildMidi_Renderer();
int flags = 0;
if (wildmidi_enhanced_resampling) flags |= WM_MO_ENHANCED_RESAMPLING;
if (wildmidi_reverb) flags |= WM_MO_REVERB;
Renderer->SetOption(WM_MO_ENHANCED_RESAMPLING | WM_MO_REVERB, flags);
}
}
//==========================================================================
//
// WildMIDIDevice Destructor
//
//==========================================================================
WildMIDIDevice::~WildMIDIDevice()
{
Close();
if (Renderer != NULL)
{
delete Renderer;
}
// Do not shut down the device so that it can be reused for the next song being played.
}
//==========================================================================
//
// WildMIDIDevice :: Open
//
// Returns 0 on success.
//
//==========================================================================
int WildMIDIDevice::Open(void (*callback)(unsigned int, void *, DWORD, DWORD), void *userdata)
{
if (Renderer == NULL)
{
return 1;
}
int ret = OpenStream(2, 0, callback, userdata);
if (ret == 0)
{
// Renderer->Reset();
}
return ret;
}
//==========================================================================
//
// WildMIDIDevice :: PrecacheInstruments
//
// Each entry is packed as follows:
// Bits 0- 6: Instrument number
// Bits 7-13: Bank number
// Bit 14: Select drum set if 1, tone bank if 0
//
//==========================================================================
void WildMIDIDevice::PrecacheInstruments(const WORD *instruments, int count)
{
for (int i = 0; i < count; ++i)
{
Renderer->LoadInstrument((instruments[i] >> 7) & 127, instruments[i] >> 14, instruments[i] & 127);
}
}
//==========================================================================
//
// WildMIDIDevice :: HandleEvent
//
//==========================================================================
void WildMIDIDevice::HandleEvent(int status, int parm1, int parm2)
{
Renderer->ShortEvent(status, parm1, parm2);
}
//==========================================================================
//
// WildMIDIDevice :: HandleLongEvent
//
//==========================================================================
void WildMIDIDevice::HandleLongEvent(const BYTE *data, int len)
{
Renderer->LongEvent(data, len);
}
//==========================================================================
//
// WildMIDIDevice :: ComputeOutput
//
//==========================================================================
void WildMIDIDevice::ComputeOutput(float *buffer, int len)
{
Renderer->ComputeOutput(buffer, len);
}
//==========================================================================
//
// WildMIDIDevice :: GetStats
//
//==========================================================================
FString WildMIDIDevice::GetStats()
{
FString out;
out.Format("%3d voices", Renderer->GetVoiceCount());
return out;
}
//==========================================================================
//
// WildMIDIDevice :: GetStats
//
//==========================================================================
void WildMIDIDevice::WildMidiSetOption(int opt, int set)
{
Renderer->SetOption(opt, set);
}

View file

@ -108,8 +108,8 @@ extern char MIDI_CommonLengths[15];
//
//==========================================================================
XMISong::XMISong (FileReader &reader, EMidiDevice type)
: MIDIStreamer(type), MusHeader(0), Songs(0)
XMISong::XMISong (FileReader &reader, EMidiDevice type, const char *args)
: MIDIStreamer(type, args), MusHeader(0), Songs(0)
{
#ifdef _WIN32
if (ExitEvent == NULL)