mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-14 08:31:23 +00:00
Added support for libOPNMIDI Playing device
This commit is contained in:
parent
46942cb27f
commit
6308fb311b
9 changed files with 4691 additions and 3 deletions
|
@ -645,6 +645,9 @@ if( NOT SEND_ANON_STATS )
|
||||||
add_definitions( -DNO_SEND_STATS )
|
add_definitions( -DNO_SEND_STATS )
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# OPLMIDI needs for USE_LEGACY_EMULATOR macro to be correctly built
|
||||||
|
add_definitions(-DUSE_LEGACY_EMULATOR)
|
||||||
|
|
||||||
# Project files should be aware of the header files. We can GLOB these since
|
# Project files should be aware of the header files. We can GLOB these since
|
||||||
# there's generally a new cpp for every header so this file will get changed
|
# there's generally a new cpp for every header so this file will get changed
|
||||||
if( WIN32 )
|
if( WIN32 )
|
||||||
|
@ -667,6 +670,7 @@ file( GLOB HEADER_FILES
|
||||||
intermission/*.h
|
intermission/*.h
|
||||||
menu/*.h
|
menu/*.h
|
||||||
sound/adlmidi/*.h*
|
sound/adlmidi/*.h*
|
||||||
|
sound/opnmidi/*.h*
|
||||||
sound/oplsynth/*.h
|
sound/oplsynth/*.h
|
||||||
sound/oplsynth/dosbox/*.h
|
sound/oplsynth/dosbox/*.h
|
||||||
posix/*.h
|
posix/*.h
|
||||||
|
@ -863,6 +867,14 @@ set( FASTMATH_SOURCES
|
||||||
sound/adlmidi/adlmidi_private.cpp
|
sound/adlmidi/adlmidi_private.cpp
|
||||||
sound/adlmidi/dbopl.cpp
|
sound/adlmidi/dbopl.cpp
|
||||||
sound/adlmidi/nukedopl3.c
|
sound/adlmidi/nukedopl3.c
|
||||||
|
sound/opnmidi/opnmidi.cpp
|
||||||
|
sound/opnmidi/opnmidi_load.cpp
|
||||||
|
sound/opnmidi/opnmidi_midiplay.cpp
|
||||||
|
sound/opnmidi/opnmidi_opn2.cpp
|
||||||
|
sound/opnmidi/opnmidi_private.cpp
|
||||||
|
sound/opnmidi/opnmidi_mus2mid.c
|
||||||
|
sound/opnmidi/opnmidi_xmi2mid.c
|
||||||
|
sound/opnmidi/Ym2612_ChipEmu.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
set (PCH_SOURCES
|
set (PCH_SOURCES
|
||||||
|
@ -1171,6 +1183,7 @@ set (PCH_SOURCES
|
||||||
sound/mididevices/music_adlmidi_mididevice.cpp
|
sound/mididevices/music_adlmidi_mididevice.cpp
|
||||||
sound/mididevices/music_opldumper_mididevice.cpp
|
sound/mididevices/music_opldumper_mididevice.cpp
|
||||||
sound/mididevices/music_opl_mididevice.cpp
|
sound/mididevices/music_opl_mididevice.cpp
|
||||||
|
sound/mididevices/music_opnmidi_mididevice.cpp
|
||||||
sound/mididevices/music_timiditypp_mididevice.cpp
|
sound/mididevices/music_timiditypp_mididevice.cpp
|
||||||
sound/mididevices/music_fluidsynth_mididevice.cpp
|
sound/mididevices/music_fluidsynth_mididevice.cpp
|
||||||
sound/mididevices/music_softsynth_mididevice.cpp
|
sound/mididevices/music_softsynth_mididevice.cpp
|
||||||
|
|
|
@ -335,6 +335,25 @@ protected:
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class OPNMIDIDevice : public SoftSynthMIDIDevice
|
||||||
|
{
|
||||||
|
struct OPN2_MIDIPlayer *Renderer;
|
||||||
|
TArray<int16_t> shortbuffer;
|
||||||
|
public:
|
||||||
|
OPNMIDIDevice(const char *args);
|
||||||
|
~OPNMIDIDevice();
|
||||||
|
|
||||||
|
int Open(MidiCallback, void *userdata);
|
||||||
|
int GetDeviceType() const override { return MDEV_OPN; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
void HandleEvent(int status, int parm1, int parm2);
|
||||||
|
void HandleLongEvent(const uint8_t *data, int len);
|
||||||
|
void ComputeOutput(float *buffer, int len);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
// Base class for streaming MUS and MIDI files ------------------------------
|
// Base class for streaming MUS and MIDI files ------------------------------
|
||||||
|
|
||||||
enum
|
enum
|
||||||
|
|
|
@ -163,6 +163,7 @@ enum EMidiDevice
|
||||||
MDEV_GUS = 5,
|
MDEV_GUS = 5,
|
||||||
MDEV_WILDMIDI = 6,
|
MDEV_WILDMIDI = 6,
|
||||||
MDEV_ADL = 7,
|
MDEV_ADL = 7,
|
||||||
|
MDEV_OPN = 8,
|
||||||
|
|
||||||
MDEV_COUNT
|
MDEV_COUNT
|
||||||
};
|
};
|
||||||
|
|
175
src/sound/mididevices/music_opnmidi_mididevice.cpp
Normal file
175
src/sound/mididevices/music_opnmidi_mididevice.cpp
Normal file
|
@ -0,0 +1,175 @@
|
||||||
|
/*
|
||||||
|
** music_opnmidi_mididevice.cpp
|
||||||
|
** Provides access to libOPNMIDI as a generic MIDI device.
|
||||||
|
**
|
||||||
|
**---------------------------------------------------------------------------
|
||||||
|
** Copyright 2008 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"
|
||||||
|
#include "opnmidi/opnmidi.h"
|
||||||
|
#include "opnmidi/default_bank/xg_opn_bank.h"
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
ME_NOTEOFF = 0x80,
|
||||||
|
ME_NOTEON = 0x90,
|
||||||
|
ME_KEYPRESSURE = 0xA0,
|
||||||
|
ME_CONTROLCHANGE = 0xB0,
|
||||||
|
ME_PROGRAM = 0xC0,
|
||||||
|
ME_CHANNELPRESSURE = 0xD0,
|
||||||
|
ME_PITCHWHEEL = 0xE0
|
||||||
|
};
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// OPNMIDIDevice Constructor
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
OPNMIDIDevice::OPNMIDIDevice(const char *args)
|
||||||
|
:SoftSynthMIDIDevice(44100)
|
||||||
|
{
|
||||||
|
Renderer = opn2_init(44100); // todo: make it configurable
|
||||||
|
if (Renderer != nullptr)
|
||||||
|
{
|
||||||
|
opn2_openBankData(Renderer, g_gm_opn2_bank, sizeof(g_gm_opn2_bank));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// OPNMIDIDevice Destructor
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
OPNMIDIDevice::~OPNMIDIDevice()
|
||||||
|
{
|
||||||
|
Close();
|
||||||
|
if (Renderer != nullptr)
|
||||||
|
{
|
||||||
|
opn2_close(Renderer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// OPNMIDIDevice :: Open
|
||||||
|
//
|
||||||
|
// Returns 0 on success.
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
int OPNMIDIDevice::Open(MidiCallback callback, void *userdata)
|
||||||
|
{
|
||||||
|
int ret = OpenStream(2, 0, callback, userdata);
|
||||||
|
if (ret == 0)
|
||||||
|
{
|
||||||
|
opn2_rt_resetState(Renderer);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// OPNMIDIDevice :: HandleEvent
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
void OPNMIDIDevice::HandleEvent(int status, int parm1, int parm2)
|
||||||
|
{
|
||||||
|
int command = status & 0xF0;
|
||||||
|
int chan = status & 0x0F;
|
||||||
|
|
||||||
|
switch (command)
|
||||||
|
{
|
||||||
|
case ME_NOTEON:
|
||||||
|
opn2_rt_noteOn(Renderer, chan, parm1, parm2);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ME_NOTEOFF:
|
||||||
|
opn2_rt_noteOff(Renderer, chan, parm1);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ME_KEYPRESSURE:
|
||||||
|
opn2_rt_noteAfterTouch(Renderer, chan, parm1, parm2);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ME_CONTROLCHANGE:
|
||||||
|
opn2_rt_controllerChange(Renderer, chan, parm1, parm2);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ME_PROGRAM:
|
||||||
|
opn2_rt_patchChange(Renderer, chan, parm1);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ME_CHANNELPRESSURE:
|
||||||
|
opn2_rt_channelAfterTouch(Renderer, chan, parm1);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ME_PITCHWHEEL:
|
||||||
|
opn2_rt_pitchBendML(Renderer, chan, parm2, parm1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// OPNMIDIDevice :: HandleLongEvent
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
void OPNMIDIDevice::HandleLongEvent(const uint8_t *data, int len)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// OPNMIDIDevice :: ComputeOutput
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
void OPNMIDIDevice::ComputeOutput(float *buffer, int len)
|
||||||
|
{
|
||||||
|
if ((int)shortbuffer.Size() < len*2) shortbuffer.Resize(len*2);
|
||||||
|
auto result = opn2_generate(Renderer, len*2, &shortbuffer[0]);
|
||||||
|
for(int i=0; i<result; i++)
|
||||||
|
{
|
||||||
|
buffer[i] = shortbuffer[i] * (5.f/32768.f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -50,7 +50,7 @@
|
||||||
static uint32_t nummididevices;
|
static uint32_t nummididevices;
|
||||||
static bool nummididevicesset;
|
static bool nummididevicesset;
|
||||||
|
|
||||||
#define NUM_DEF_DEVICES 6
|
#define NUM_DEF_DEVICES 7
|
||||||
|
|
||||||
static void AddDefaultMidiDevices(FOptionValues *opt)
|
static void AddDefaultMidiDevices(FOptionValues *opt)
|
||||||
{
|
{
|
||||||
|
@ -67,6 +67,8 @@ static void AddDefaultMidiDevices(FOptionValues *opt)
|
||||||
pair[4].Value = -3.0;
|
pair[4].Value = -3.0;
|
||||||
pair[5].Text = "libADL";
|
pair[5].Text = "libADL";
|
||||||
pair[5].Value = -7.0;
|
pair[5].Value = -7.0;
|
||||||
|
pair[6].Text = "libOPN";
|
||||||
|
pair[6].Value = -8.0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -201,6 +203,7 @@ CCMD (snd_listmididevices)
|
||||||
MIDIOUTCAPS caps;
|
MIDIOUTCAPS caps;
|
||||||
MMRESULT res;
|
MMRESULT res;
|
||||||
|
|
||||||
|
PrintMidiDevice(-8, "libOPN", MIDIDEV_FMSYNTH, 0);
|
||||||
PrintMidiDevice(-7, "libADL", MIDIDEV_FMSYNTH, 0);
|
PrintMidiDevice(-7, "libADL", MIDIDEV_FMSYNTH, 0);
|
||||||
PrintMidiDevice (-6, "WildMidi", MIDIDEV_SWSYNTH, 0);
|
PrintMidiDevice (-6, "WildMidi", MIDIDEV_SWSYNTH, 0);
|
||||||
PrintMidiDevice (-5, "FluidSynth", MIDIDEV_SWSYNTH, 0);
|
PrintMidiDevice (-5, "FluidSynth", MIDIDEV_SWSYNTH, 0);
|
||||||
|
@ -230,8 +233,8 @@ CCMD (snd_listmididevices)
|
||||||
|
|
||||||
CUSTOM_CVAR(Int, snd_mididevice, DEF_MIDIDEV, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
CUSTOM_CVAR(Int, snd_mididevice, DEF_MIDIDEV, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||||
{
|
{
|
||||||
if (self < -7)
|
if (self < -8)
|
||||||
self = -7;
|
self = -8;
|
||||||
else if (self > -2)
|
else if (self > -2)
|
||||||
self = -2;
|
self = -2;
|
||||||
else
|
else
|
||||||
|
@ -245,6 +248,7 @@ void I_BuildMIDIMenuList (FOptionValues *opt)
|
||||||
|
|
||||||
CCMD (snd_listmididevices)
|
CCMD (snd_listmididevices)
|
||||||
{
|
{
|
||||||
|
Printf("%s-8. libOPN\n", -7 == snd_mididevice ? TEXTCOLOR_BOLD : "");
|
||||||
Printf("%s-7. libADL\n", -6 == snd_mididevice ? TEXTCOLOR_BOLD : "");
|
Printf("%s-7. libADL\n", -6 == snd_mididevice ? TEXTCOLOR_BOLD : "");
|
||||||
Printf("%s-6. WildMidi\n", -6 == snd_mididevice ? TEXTCOLOR_BOLD : "");
|
Printf("%s-6. WildMidi\n", -6 == snd_mididevice ? TEXTCOLOR_BOLD : "");
|
||||||
Printf("%s-5. FluidSynth\n", -5 == snd_mididevice ? TEXTCOLOR_BOLD : "");
|
Printf("%s-5. FluidSynth\n", -5 == snd_mididevice ? TEXTCOLOR_BOLD : "");
|
||||||
|
|
|
@ -166,6 +166,7 @@ EMidiDevice MIDIStreamer::SelectMIDIDevice(EMidiDevice device)
|
||||||
case -5: return MDEV_FLUIDSYNTH;
|
case -5: return MDEV_FLUIDSYNTH;
|
||||||
case -6: return MDEV_WILDMIDI;
|
case -6: return MDEV_WILDMIDI;
|
||||||
case -7: return MDEV_ADL;
|
case -7: return MDEV_ADL;
|
||||||
|
case -8: return MDEV_OPN;
|
||||||
default:
|
default:
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
return MDEV_MMAPI;
|
return MDEV_MMAPI;
|
||||||
|
@ -205,6 +206,10 @@ MIDIDevice *MIDIStreamer::CreateMIDIDevice(EMidiDevice devtype, int samplerate)
|
||||||
dev = new ADLMIDIDevice(Args);
|
dev = new ADLMIDIDevice(Args);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case MDEV_OPN:
|
||||||
|
dev = new OPNMIDIDevice(Args);
|
||||||
|
break;
|
||||||
|
|
||||||
case MDEV_MMAPI:
|
case MDEV_MMAPI:
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
|
25
src/sound/opnmidi/default_bank/wopn2hpp.sh
Executable file
25
src/sound/opnmidi/default_bank/wopn2hpp.sh
Executable file
|
@ -0,0 +1,25 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
output="xg_opn_bank.h"
|
||||||
|
|
||||||
|
out()
|
||||||
|
{
|
||||||
|
printf "${1}" >> $output
|
||||||
|
}
|
||||||
|
|
||||||
|
truncate -s 0 $output
|
||||||
|
|
||||||
|
out "/*===============================================================*\n"
|
||||||
|
out " This file is automatically generated by wopn2hpp.sh script\n"
|
||||||
|
out " PLEASE DON'T EDIT THIS DIRECTLY. Edit the gm.wonp file first,\n"
|
||||||
|
out " and then run a wopn2hpp.sh script to generate this file again\n"
|
||||||
|
out " *===============================================================*/\n\n"
|
||||||
|
out "static unsigned char g_gm_opn2_bank[] = \n"
|
||||||
|
out "{\n"
|
||||||
|
hexdump -ve '12/1 "0x%02x, " "\n"' xg.wopn >> $output
|
||||||
|
out "0x00\n"
|
||||||
|
out "};\n"
|
||||||
|
out "\n"
|
||||||
|
|
||||||
|
sed -i "s/0x /0x00/g" $output
|
||||||
|
|
BIN
src/sound/opnmidi/default_bank/xg.wopn
Normal file
BIN
src/sound/opnmidi/default_bank/xg.wopn
Normal file
Binary file not shown.
4446
src/sound/opnmidi/default_bank/xg_opn_bank.h
Normal file
4446
src/sound/opnmidi/default_bank/xg_opn_bank.h
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue