Added support for libOPNMIDI Playing device

This commit is contained in:
Vitaly Novichkov 2018-03-24 17:58:47 +03:00
parent 46942cb27f
commit 6308fb311b
9 changed files with 4691 additions and 3 deletions

View file

@ -645,6 +645,9 @@ if( NOT SEND_ANON_STATS )
add_definitions( -DNO_SEND_STATS )
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
# there's generally a new cpp for every header so this file will get changed
if( WIN32 )
@ -667,6 +670,7 @@ file( GLOB HEADER_FILES
intermission/*.h
menu/*.h
sound/adlmidi/*.h*
sound/opnmidi/*.h*
sound/oplsynth/*.h
sound/oplsynth/dosbox/*.h
posix/*.h
@ -863,6 +867,14 @@ set( FASTMATH_SOURCES
sound/adlmidi/adlmidi_private.cpp
sound/adlmidi/dbopl.cpp
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
@ -1171,6 +1183,7 @@ set (PCH_SOURCES
sound/mididevices/music_adlmidi_mididevice.cpp
sound/mididevices/music_opldumper_mididevice.cpp
sound/mididevices/music_opl_mididevice.cpp
sound/mididevices/music_opnmidi_mididevice.cpp
sound/mididevices/music_timiditypp_mididevice.cpp
sound/mididevices/music_fluidsynth_mididevice.cpp
sound/mididevices/music_softsynth_mididevice.cpp

View file

@ -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 ------------------------------
enum

View file

@ -163,6 +163,7 @@ enum EMidiDevice
MDEV_GUS = 5,
MDEV_WILDMIDI = 6,
MDEV_ADL = 7,
MDEV_OPN = 8,
MDEV_COUNT
};

View 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);
}
}

View file

@ -50,7 +50,7 @@
static uint32_t nummididevices;
static bool nummididevicesset;
#define NUM_DEF_DEVICES 6
#define NUM_DEF_DEVICES 7
static void AddDefaultMidiDevices(FOptionValues *opt)
{
@ -67,6 +67,8 @@ static void AddDefaultMidiDevices(FOptionValues *opt)
pair[4].Value = -3.0;
pair[5].Text = "libADL";
pair[5].Value = -7.0;
pair[6].Text = "libOPN";
pair[6].Value = -8.0;
}
@ -201,6 +203,7 @@ CCMD (snd_listmididevices)
MIDIOUTCAPS caps;
MMRESULT res;
PrintMidiDevice(-8, "libOPN", MIDIDEV_FMSYNTH, 0);
PrintMidiDevice(-7, "libADL", MIDIDEV_FMSYNTH, 0);
PrintMidiDevice (-6, "WildMidi", 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)
{
if (self < -7)
self = -7;
if (self < -8)
self = -8;
else if (self > -2)
self = -2;
else
@ -245,6 +248,7 @@ void I_BuildMIDIMenuList (FOptionValues *opt)
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-6. WildMidi\n", -6 == snd_mididevice ? TEXTCOLOR_BOLD : "");
Printf("%s-5. FluidSynth\n", -5 == snd_mididevice ? TEXTCOLOR_BOLD : "");

View file

@ -166,6 +166,7 @@ EMidiDevice MIDIStreamer::SelectMIDIDevice(EMidiDevice device)
case -5: return MDEV_FLUIDSYNTH;
case -6: return MDEV_WILDMIDI;
case -7: return MDEV_ADL;
case -8: return MDEV_OPN;
default:
#ifdef _WIN32
return MDEV_MMAPI;
@ -205,6 +206,10 @@ MIDIDevice *MIDIStreamer::CreateMIDIDevice(EMidiDevice devtype, int samplerate)
dev = new ADLMIDIDevice(Args);
break;
case MDEV_OPN:
dev = new OPNMIDIDevice(Args);
break;
case MDEV_MMAPI:
#ifdef _WIN32

View 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

Binary file not shown.

File diff suppressed because it is too large Load diff