diff --git a/src/sound/mididevices/midi_cvars.cpp b/src/sound/mididevices/midi_cvars.cpp index fdd37d9b0..99a9de6ea 100644 --- a/src/sound/mididevices/midi_cvars.cpp +++ b/src/sound/mididevices/midi_cvars.cpp @@ -37,6 +37,7 @@ #include "i_soundfont.h" #include "adlmidi.h" #include "cmdlib.h" +#include "doomerrors.h" // do this without including windows.h for this one single prototype extern "C" unsigned __stdcall GetSystemDirectoryA(char* lpBuffer, unsigned uSize); @@ -51,7 +52,8 @@ static void CheckRestart(int devtype) ADLConfig adlConfig; FluidConfig fluidConfig; - +OPLMidiConfig oplMidiConfig; + CUSTOM_CVAR(Int, adl_chips_count, 6, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) { @@ -413,3 +415,57 @@ CUSTOM_CVAR(Int, fluid_chorus_type, FLUID_CHORUS_DEFAULT_TYPE, CVAR_ARCHIVE|CVAR } } + + + +CUSTOM_CVAR(Int, opl_numchips, 2, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +{ + if (*self <= 0) + { + self = 1; + } + else if (*self > MAXOPL2CHIPS) + { + self = MAXOPL2CHIPS; + } + else + { + if (currSong != NULL) + currSong->ChangeSettingInt("opl.numchips", self); + oplMidiConfig.numchips = self; + } +} + +CUSTOM_CVAR(Int, opl_core, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +{ + if (currSong != nullptr && currSong->GetDeviceType() == MDEV_OPL) + { + MIDIDeviceChanged(-1, true); + } +} + +CUSTOM_CVAR(Bool, opl_fullpan, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +{ + oplMidiConfig.fullpan = self; +} + +void LoadGenMidi() +{ + // The OPL renderer should not care about where this comes from. + // Note: No I_Error here - this needs to be consistent with the rest of the music code. + auto lump = Wads.CheckNumForName("GENMIDI", ns_global); + if (lump < 0) throw std::runtime_error("No GENMIDI lump found"); + auto data = Wads.OpenLumpReader(lump); + + uint8_t filehdr[8]; + data.Read(filehdr, 8); + if (memcmp(filehdr, "#OPL_II#", 8)) throw std::runtime_error("Corrupt GENMIDI lump"); + data.Read(oplMidiConfig.OPLinstruments, sizeof(GenMidiInstrument) * GENMIDI_NUM_TOTAL); +} + +int getOPLCore(const char* args) +{ + int current_opl_core = opl_core; + if (args != NULL && *args >= '0' && *args < '4') current_opl_core = *args - '0'; + return current_opl_core; +} diff --git a/src/sound/mididevices/music_opl_mididevice.cpp b/src/sound/mididevices/music_opl_mididevice.cpp index 88247ffcc..66074dd94 100644 --- a/src/sound/mididevices/music_opl_mididevice.cpp +++ b/src/sound/mididevices/music_opl_mididevice.cpp @@ -30,27 +30,16 @@ ** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. **--------------------------------------------------------------------------- ** -** Uses Vladimir Arnost's MUS player library. +** */ // HEADER FILES ------------------------------------------------------------ #include "i_musicinterns.h" -#include "w_wad.h" -#include "v_text.h" -#include "doomerrors.h" #include "oplsynth/opl.h" // MACROS ------------------------------------------------------------------ -#if defined(_DEBUG) && defined(_WIN32) && defined(_MSC_VER) -void I_DebugPrint(const char *cp); -#define DEBUGOUT(m,c,s,t) \ - { char foo[128]; mysnprintf(foo, countof(foo), m, c, s, t); I_DebugPrint(foo); } -#else -#define DEBUGOUT(m,c,s,t) -#endif - // EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- // PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- @@ -59,13 +48,31 @@ void I_DebugPrint(const char *cp); // EXTERNAL DATA DECLARATIONS ---------------------------------------------- -EXTERN_CVAR(Int, opl_numchips) - // PRIVATE DATA DEFINITIONS ------------------------------------------------ -// PUBLIC DATA DEFINITIONS ------------------------------------------------- +// OPL implementation of a MIDI output device ------------------------------- -CVAR(Bool, opl_fullpan, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG); +class OPLMIDIDevice : public SoftSynthMIDIDevice, protected OPLmusicBlock +{ +public: + OPLMIDIDevice(OPLMidiConfig *config); + int Open(MidiCallback, void *userdata); + void Close(); + int GetTechnology() const; + FString GetStats(); + +protected: + void CalcTickRate(); + int PlayTick(); + void HandleEvent(int status, int parm1, int parm2); + void HandleLongEvent(const uint8_t *data, int len); + void ComputeOutput(float *buffer, int len); + bool ServiceStream(void *buff, int numbytes); + int GetDeviceType() const override { return MDEV_OPL; } +}; + + +// PUBLIC DATA DEFINITIONS ------------------------------------------------- // CODE -------------------------------------------------------------------- @@ -74,27 +81,12 @@ CVAR(Bool, opl_fullpan, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG); // OPLMIDIDevice Contructor // //========================================================================== -EXTERN_CVAR(Int, opl_core) -int getOPLCore(const char* args) + +OPLMIDIDevice::OPLMIDIDevice(OPLMidiConfig *config) + : SoftSynthMIDIDevice((int)OPL_SAMPLE_RATE), OPLmusicBlock(config->core, config->numchips) { - int current_opl_core = opl_core; - if (args != NULL && *args >= '0' && *args < '4') current_opl_core = *args - '0'; - return current_opl_core; -} - - -OPLMIDIDevice::OPLMIDIDevice(const char *args) - : SoftSynthMIDIDevice((int)OPL_SAMPLE_RATE), OPLmusicBlock(getOPLCore(args), opl_numchips) -{ - FullPan = opl_fullpan; - auto lump = Wads.CheckNumForName("GENMIDI", ns_global); - if (lump < 0) I_Error("No GENMIDI lump found"); - auto data = Wads.OpenLumpReader(lump); - - uint8_t filehdr[8]; - data.Read(filehdr, 8); - if (memcmp(filehdr, "#OPL_II#", 8)) I_Error("Corrupt GENMIDI lump"); - data.Read(OPLinstruments, sizeof(GenMidiInstrument) * GENMIDI_NUM_TOTAL); + FullPan = config->fullpan; + memcpy(OPLinstruments, config->OPLinstruments, sizeof(OPLinstruments)); } //========================================================================== @@ -107,7 +99,7 @@ OPLMIDIDevice::OPLMIDIDevice(const char *args) int OPLMIDIDevice::Open(MidiCallback callback, void *userdata) { - if (io == NULL || 0 == (NumChips = io->Init(currentCore, opl_numchips, FullPan, true))) + if (io == NULL || 0 == (NumChips = io->Init(currentCore, NumChips, FullPan, true))) { return 1; } @@ -116,7 +108,6 @@ int OPLMIDIDevice::Open(MidiCallback callback, void *userdata) { stopAllVoices(); resetAllControllers(100); - DEBUGOUT("========= New song started ==========\n", 0, 0, 0); } return ret; } @@ -210,7 +201,7 @@ void OPLMIDIDevice::HandleEvent(int status, int parm1, int parm2) break; case MIDI_POLYPRESS: - DEBUGOUT("Unhandled note aftertouch: Channel %d, note %d, value %d\n", channel, parm1, parm2); + //DEBUGOUT("Unhandled note aftertouch: Channel %d, note %d, value %d\n", channel, parm1, parm2); break; case MIDI_CTRLCHANGE: @@ -238,7 +229,7 @@ void OPLMIDIDevice::HandleEvent(int status, int parm1, int parm2) //case 126: changeMono(channel, parm2); break; //case 127: changePoly(channel, parm2); break; default: - DEBUGOUT("Unhandled controller: Channel %d, controller %d, value %d\n", channel, parm1, parm2); + //DEBUGOUT("Unhandled controller: Channel %d, controller %d, value %d\n", channel, parm1, parm2); break; } break; @@ -248,7 +239,7 @@ void OPLMIDIDevice::HandleEvent(int status, int parm1, int parm2) break; case MIDI_CHANPRESS: - DEBUGOUT("Unhandled channel aftertouch: Channel %d, value %d\n", channel, parm1, 0); + //DEBUGOUT("Unhandled channel aftertouch: Channel %d, value %d\n", channel, parm1, 0); break; case MIDI_PITCHBEND: @@ -299,26 +290,31 @@ bool OPLMIDIDevice::ServiceStream(void *buff, int numbytes) FString OPLMIDIDevice::GetStats() { FString out; - char star[3] = { TEXTCOLOR_ESCAPE, 'A', '*' }; for (uint32_t i = 0; i < io->NumChannels; ++i) { + char star = '*'; if (voices[i].index == ~0u) { - star[1] = CR_BRICK + 'A'; + star = '/'; } else if (voices[i].sustained) { - star[1] = CR_ORANGE + 'A'; + star = '-'; } else if (voices[i].current_instr_voice == &voices[i].current_instr->voices[1]) { - star[1] = CR_BLUE + 'A'; + star = '\\'; } else { - star[1] = CR_GREEN + 'A'; + star = '+'; } - out.AppendCStrPart (star, 3); + out += star; } return out; } + +MIDIDevice* CreateOplMIDIDevice(OPLMidiConfig* config) +{ + return new OPLMIDIDevice(config); +} diff --git a/src/sound/music/i_musicinterns.h b/src/sound/music/i_musicinterns.h index 34cc0eec4..2d0beeaf9 100644 --- a/src/sound/music/i_musicinterns.h +++ b/src/sound/music/i_musicinterns.h @@ -65,6 +65,17 @@ struct FluidConfig extern FluidConfig fluidConfig; +struct OPLMidiConfig +{ + int numchips = 2; + int core = 0; + bool fullpan = true; + struct GenMidiInstrument OPLinstruments[GENMIDI_NUM_TOTAL]; +}; + +extern OPLMidiConfig oplMidiConfig; + + class MIDIStreamer; typedef void(*MidiCallback)(void *); @@ -155,37 +166,6 @@ protected: virtual void ComputeOutput(float *buffer, int len) = 0; }; -// OPL implementation of a MIDI output device ------------------------------- - -class OPLMIDIDevice : public SoftSynthMIDIDevice, protected OPLmusicBlock -{ -public: - OPLMIDIDevice(const char *args); - int Open(MidiCallback, void *userdata); - void Close(); - int GetTechnology() const; - FString GetStats(); - -protected: - void CalcTickRate(); - int PlayTick(); - void HandleEvent(int status, int parm1, int parm2); - void HandleLongEvent(const uint8_t *data, int len); - void ComputeOutput(float *buffer, int len); - bool ServiceStream(void *buff, int numbytes); - int GetDeviceType() const override { return MDEV_OPL; } -}; - -// OPL dumper implementation of a MIDI output device ------------------------ - -class OPLDumperMIDIDevice : public OPLMIDIDevice -{ -public: - OPLDumperMIDIDevice(const char *filename); - ~OPLDumperMIDIDevice(); - int Resume(); - void Stop(); -}; // Internal disk writing version of a MIDI device ------------------ @@ -371,6 +351,12 @@ public: CDDAFile (FileReader &reader); }; +// Data interface + +int BuildFluidPatchSetList(const char* patches, bool systemfallback); +void LoadGenMidi(); +int getOPLCore(const char* args); + // Module played via foo_dumb ----------------------------------------------- MusInfo *MOD_OpenSong(FileReader &reader); diff --git a/src/sound/musicformats/music_midistream.cpp b/src/sound/musicformats/music_midistream.cpp index 874a2112a..75a345e28 100644 --- a/src/sound/musicformats/music_midistream.cpp +++ b/src/sound/musicformats/music_midistream.cpp @@ -56,6 +56,7 @@ MIDIDevice *CreateTimidityPPMIDIDevice(const char *args, int samplerate); MIDIDevice *CreateADLMIDIDevice(const char *args, const ADLConfig* config); MIDIDevice *CreateOPNMIDIDevice(const char *args); MIDIDevice *CreateWildMIDIDevice(const char *args, int samplerate); +MIDIDevice* CreateOplMIDIDevice(OPLMidiConfig* config); int BuildFluidPatchSetList(const char* patches, bool systemfallback); // PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- @@ -233,7 +234,9 @@ MIDIDevice *MIDIStreamer::CreateMIDIDevice(EMidiDevice devtype, int samplerate) break; case MDEV_OPL: - dev = new OPLMIDIDevice(Args); + LoadGenMidi(); + oplMidiConfig.core = getOPLCore(Args); + dev = CreateOplMIDIDevice(&oplMidiConfig); break; case MDEV_TIMIDITY: diff --git a/src/sound/musicformats/music_opl.cpp b/src/sound/musicformats/music_opl.cpp index d2e87b326..f501c9bf6 100644 --- a/src/sound/musicformats/music_opl.cpp +++ b/src/sound/musicformats/music_opl.cpp @@ -36,29 +36,7 @@ static bool OPL_Active; -CUSTOM_CVAR (Int, opl_numchips, 2, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -{ - if (*self <= 0) - { - self = 1; - } - else if (*self > MAXOPL2CHIPS) - { - self = MAXOPL2CHIPS; - } - else if (OPL_Active && currSong != NULL) - { - static_cast(currSong)->ResetChips (); - } -} - -CUSTOM_CVAR(Int, opl_core, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) -{ - if (currSong != nullptr && currSong->GetDeviceType() == MDEV_OPL) - { - MIDIDeviceChanged(-1, true); - } -} +EXTERN_CVAR (Int, opl_numchips) int getOPLCore(const char* args);