Preliminary preparation for new YM2612 FM emulator.

All the hooks are in, but actual implementation
needs to be checked for portability.

svn-id: r10615
This commit is contained in:
Jamieson Christian 2003-10-05 15:36:52 +00:00
parent 7174a32c8e
commit a722d0601e
16 changed files with 154 additions and 60 deletions

3
README
View file

@ -567,9 +567,10 @@ emulation. MIDI may not be available on all operating systems or may need
manual configuration. If you ARE using MIDI, you have several different manual configuration. If you ARE using MIDI, you have several different
choices of output, depending on your operating system and configuration. choices of output, depending on your operating system and configuration.
adlib - Uses internal Adlib Emulation (default) adlib - Uses internal Adlib Emulation (default)
pcjr - Uses internal PCjr Emulation pcjr - Uses internal PCjr Emulation
pcspk - Uses internal PC Speaker Emulation pcspk - Uses internal PC Speaker Emulation
towns - Uses FM-Towns YM2612 Emulation
windows - Windows MIDI. Uses built-in sequencer, for Windows users windows - Windows MIDI. Uses built-in sequencer, for Windows users
seq - Uses /dev/sequencer for MIDI, *nix users. See below. seq - Uses /dev/sequencer for MIDI, *nix users. See below.
qt - Quicktime sound, for Macintosh users. qt - Quicktime sound, for Macintosh users.

31
backends/midi/ym2612.cpp Normal file
View file

@ -0,0 +1,31 @@
/* ScummVM - Scumm Interpreter
* Copyright (C) 2001-2003 The ScummVM project
*
* YM2612 tone generation code written by Tomoaki Hayasaka.
* Used under the terms of the GNU General Public License.
* Adpated to ScummVM by Jamieson Christian.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* $Header$
*/
// Real implementation coming soon! :)
#include "sound/mididrv.h"
MidiDriver *MidiDriver_YM2612_create(SoundMixer *mixer) {
return 0;
}

View file

@ -11,7 +11,8 @@ MODULE_OBJS := \
backends/midi/quicktime.o \ backends/midi/quicktime.o \
backends/midi/seq.o \ backends/midi/seq.o \
backends/midi/alsa.o \ backends/midi/alsa.o \
backends/midi/windows.o backends/midi/windows.o \
backends/midi/ym2612.o
MODULE_DIRS += \ MODULE_DIRS += \
backends \ backends \

View file

@ -676,12 +676,15 @@ bool GameDetector::detectMain() {
if (_game.midi & MDT_PREFER_NATIVE) if (_game.midi & MDT_PREFER_NATIVE)
_midi_driver = getMidiDriverType(); _midi_driver = getMidiDriverType();
else else
_midi_driver = MD_ADLIB; _midi_driver = MD_TOWNS;
} }
bool nativeMidiDriver = bool nativeMidiDriver =
(_midi_driver != MD_NULL && _midi_driver != MD_ADLIB && (_midi_driver != MD_NULL && _midi_driver != MD_ADLIB &&
_midi_driver != MD_PCSPK && _midi_driver != MD_PCJR); _midi_driver != MD_PCSPK && _midi_driver != MD_PCJR &&
_midi_driver != MD_TOWNS);
if (nativeMidiDriver && !(_game.midi & MDT_NATIVE)) if (nativeMidiDriver && !(_game.midi & MDT_NATIVE))
_midi_driver = MD_TOWNS;
if (_midi_driver == MD_TOWNS && !(_game.midi & MDT_TOWNS))
_midi_driver = MD_ADLIB; _midi_driver = MD_ADLIB;
if (_midi_driver == MD_ADLIB && !(_game.midi & MDT_ADLIB)) if (_midi_driver == MD_ADLIB && !(_game.midi & MDT_ADLIB))
_midi_driver = MD_PCJR; _midi_driver = MD_PCJR;
@ -770,12 +773,15 @@ MidiDriver *GameDetector::createMidi() {
switch(drv) { switch(drv) {
case MD_NULL: return MidiDriver_NULL_create(); case MD_NULL: return MidiDriver_NULL_create();
// In the case of Adlib, we won't specify anything. // In the case of Adlib, we won't specify anything.
// IMuse is designed to set up its own Adlib driver // IMuse is designed to set up its own Adlib driver
// if need be, and we only have to specify a native // if need be, and we only have to specify a native
// driver. // driver.
case MD_ADLIB: return NULL; case MD_ADLIB: return NULL;
case MD_TOWNS: return MidiDriver_YM2612_create(g_engine->_mixer);
// Right now PC Speaker and PCjr are handled // Right now PC Speaker and PCjr are handled
// outside the MidiDriver architecture, so // outside the MidiDriver architecture, so
// don't create anything for now. // don't create anything for now.

View file

@ -70,8 +70,9 @@ enum MidiDriverType {
MDT_NONE = 0, MDT_NONE = 0,
MDT_PCSPK = 1, // MD_PCSPK and MD_PCJR MDT_PCSPK = 1, // MD_PCSPK and MD_PCJR
MDT_ADLIB = 2, // MD_ADLIB MDT_ADLIB = 2, // MD_ADLIB
MDT_NATIVE = 4, // Everything else MDT_TOWNS = 4, // MD_TOWNS
MDT_PREFER_NATIVE = 8 MDT_NATIVE = 8, // Everything else
MDT_PREFER_NATIVE = 16
}; };
struct TargetSettings { struct TargetSettings {

View file

@ -540,6 +540,10 @@ SOURCE=..\..\backends\midi\null.cpp
SOURCE=..\..\backends\midi\windows.cpp SOURCE=..\..\backends\midi\windows.cpp
# End Source File # End Source File
# Begin Source File
SOURCE=..\..\backends\midi\ym2612.cpp
# End Source File
# End Group # End Group
# End Group # End Group
# End Group # End Group

View file

@ -355,6 +355,9 @@
<File <File
RelativePath="..\..\backends\midi\windows.cpp"> RelativePath="..\..\backends\midi\windows.cpp">
</File> </File>
<File
RelativePath="..\..\backends\midi\ym2612.cpp">
</File>
</Filter> </Filter>
</Filter> </Filter>
<Filter <Filter

View file

@ -54,6 +54,7 @@ _initialized(false),
_tempoFactor(0), _tempoFactor(0),
_player_limit(ARRAYSIZE(_players)), _player_limit(ARRAYSIZE(_players)),
_recycle_players(false), _recycle_players(false),
_direct_passthrough(false),
_queue_end(0), _queue_end(0),
_queue_pos(0), _queue_pos(0),
_queue_sound(0), _queue_sound(0),
@ -250,7 +251,7 @@ bool IMuseInternal::startSound(int sound) {
return false; return false;
player->clear(); player->clear();
return player->startSound(sound, driver); return player->startSound(sound, driver, _direct_passthrough);
} }
@ -1117,10 +1118,14 @@ uint32 IMuseInternal::property(int prop, uint32 value) {
break; break;
case IMuse::PROP_RECYCLE_PLAYERS: case IMuse::PROP_RECYCLE_PLAYERS:
if (value > 0 && value <= ARRAYSIZE(_players)) _recycle_players = (value != 0);
_recycle_players = (value != 0); break;
case IMuse::PROP_DIRECT_PASSTHROUGH:
_direct_passthrough = (value != 0);
break; break;
} }
return 0; return 0;
} }

View file

@ -51,12 +51,13 @@ public:
~IMuse(); ~IMuse();
enum { enum {
PROP_TEMPO_BASE = 1, PROP_TEMPO_BASE,
PROP_NATIVE_MT32 = 2, PROP_NATIVE_MT32,
PROP_MULTI_MIDI = 3, PROP_MULTI_MIDI,
PROP_OLD_ADLIB_INSTRUMENTS = 4, PROP_OLD_ADLIB_INSTRUMENTS,
PROP_LIMIT_PLAYERS = 5, PROP_LIMIT_PLAYERS,
PROP_RECYCLE_PLAYERS = 6 PROP_RECYCLE_PLAYERS,
PROP_DIRECT_PASSTHROUGH
}; };
void on_timer(MidiDriver *midi); void on_timer(MidiDriver *midi);

View file

@ -60,10 +60,6 @@ class ScummEngine;
#define TICKS_PER_BEAT 480 #define TICKS_PER_BEAT 480
#define IMUSE_SYSEX_ID 0x7D
#define ROLAND_SYSEX_ID 0x41
#define PERCUSSION_CHANNEL 9
#define TRIGGER_ID 0 #define TRIGGER_ID 0
#define COMMAND_ID 1 #define COMMAND_ID 1
@ -158,6 +154,7 @@ protected:
protected: protected:
MidiDriver *_midi; MidiDriver *_midi;
MidiParser *_parser; MidiParser *_parser;
bool _passThrough; // Only respond to EOT, all else direct to MidiDriver
Part *_parts; Part *_parts;
bool _active; bool _active;
@ -259,7 +256,7 @@ public:
void setSpeed(byte speed); void setSpeed(byte speed);
int setTranspose(byte relative, int b); int setTranspose(byte relative, int b);
int setVolume(byte vol); int setVolume(byte vol);
bool startSound(int sound, MidiDriver *midi); bool startSound(int sound, MidiDriver *midi, bool passThrough);
int getMusicTimer() const; int getMusicTimer() const;
public: public:
@ -366,8 +363,9 @@ protected:
int _tempoFactor; int _tempoFactor;
int _player_limit; // Limits how many simultaneous music tracks are played int _player_limit; // Limits how many simultaneous music tracks are played
bool _recycle_players; // Can we stop a player in order to start another one? bool _recycle_players; // Can we stop a player in order to start another one?
bool _direct_passthrough; // Pass data direct to MidiDriver (no interactivity)
uint _queue_end, _queue_pos, _queue_sound; uint _queue_end, _queue_pos, _queue_sound;
byte _queue_adding; byte _queue_adding;

View file

@ -39,6 +39,11 @@ namespace Scumm {
// //
//////////////////////////////////////// ////////////////////////////////////////
#define IMUSE_SYSEX_ID 0x7D
#define YM2612_SYSEX_ID 0x7C
#define ROLAND_SYSEX_ID 0x41
#define PERCUSSION_CHANNEL 9
extern MidiParser *MidiParser_createRO(); extern MidiParser *MidiParser_createRO();
extern MidiParser *MidiParser_createEUP(); extern MidiParser *MidiParser_createEUP();
@ -85,7 +90,7 @@ Player::~Player() {
} }
} }
bool Player::startSound(int sound, MidiDriver *midi) { bool Player::startSound(int sound, MidiDriver *midi, bool passThrough) {
void *ptr; void *ptr;
int i; int i;
@ -111,6 +116,7 @@ bool Player::startSound(int sound, MidiDriver *midi) {
_pan = 0; _pan = 0;
_transpose = 0; _transpose = 0;
_detune = 0; _detune = 0;
_passThrough = passThrough;
for (i = 0; i < ARRAYSIZE(_parameterFaders); ++i) for (i = 0; i < ARRAYSIZE(_parameterFaders); ++i)
_parameterFaders[i].init(); _parameterFaders[i].init();
@ -152,8 +158,11 @@ void Player::clear() {
debug (0, "Stopping music %d", _id); debug (0, "Stopping music %d", _id);
#endif #endif
if (_parser) if (_parser) {
_parser->unloadMusic(); _parser->unloadMusic();
delete _parser;
_parser = 0;
}
uninit_parts(); uninit_parts();
_se->ImFireAllTriggers(_id); _se->ImFireAllTriggers(_id);
_active = false; _active = false;
@ -224,6 +233,11 @@ void Player::setSpeed(byte speed) {
} }
void Player::send(uint32 b) { void Player::send(uint32 b) {
if (_passThrough) {
_midi->send (b);
return;
}
byte cmd = (byte)(b & 0xF0); byte cmd = (byte)(b & 0xF0);
byte chan = (byte)(b & 0x0F); byte chan = (byte)(b & 0x0F);
byte param1 = (byte)((b >> 8) & 0xFF); byte param1 = (byte)((b >> 8) & 0xFF);
@ -333,8 +347,12 @@ void Player::sysEx(byte *p, uint16 len) {
byte buf[128]; byte buf[128];
Part *part; Part *part;
if (_passThrough) {
_midi->sysEx (p, len);
return;
}
// Check SysEx manufacturer. // Check SysEx manufacturer.
// Roland is 0x41
a = *p++; a = *p++;
--len; --len;
if (a != IMUSE_SYSEX_ID) { if (a != IMUSE_SYSEX_ID) {
@ -346,6 +364,9 @@ void Player::sysEx(byte *p, uint16 len) {
if (part->clearToTransmit()) if (part->clearToTransmit())
part->_instrument.send(part->_mc); part->_instrument.send(part->_mc);
} }
} else if (a == YM2612_SYSEX_ID) {
// FM-Towns custom instrument definition
_midi->sysEx_customInstrument (p[0], 'EUP ', p + 1);
} else { } else {
warning("Unknown SysEx manufacturer 0x%02X", (int) a); warning("Unknown SysEx manufacturer 0x%02X", (int) a);
} }
@ -1124,10 +1145,8 @@ uint32 Player::getBaseTempo() {
} }
void Player::metaEvent(byte type, byte *msg, uint16 len) { void Player::metaEvent(byte type, byte *msg, uint16 len) {
if (type == 0x2F) { if (type == 0x2F)
_parser->unloadMusic();
clear(); clear();
}
} }

View file

@ -32,6 +32,8 @@ namespace Scumm {
*/ */
class MidiParser_EUP : public MidiParser { class MidiParser_EUP : public MidiParser {
protected: protected:
byte _instruments[6][50]; // Two extra bytes for SysEx ID and channel #
byte _channel_instr[16];
struct { struct {
byte *enable; byte *enable;
int8 *channel; int8 *channel;
@ -69,14 +71,22 @@ void MidiParser_EUP::parseNextEvent (EventInfo &info) {
// program changes to get a reasonable "one-size- // program changes to get a reasonable "one-size-
// fits-all" sound until we actually support the // fits-all" sound until we actually support the
// FM synthesis capabilities of FM Towns. // FM synthesis capabilities of FM Towns.
if (_presend) { for (; _presend < 32; ++_presend) {
--_presend; if (_channel_instr[_presend >> 1] == 0xFF) continue;
info.start = pos; info.start = pos;
info.delta = 0; info.delta = 0;
info.event = ((_presend & 1) ? 0xB0 : 0xC0) | (_presend >> 1); if (_presend & 1) {
info.basic.param1 = ((_presend & 1) ? 7 : 0x38); info.event = 0xB0;
info.basic.param2 = ((_presend & 1) ? 127 : 0); info.basic.param1 = 7;
_presend = (_presend + 2) % 32; info.basic.param2 = 127;
} else {
byte *data = &_instruments[_channel_instr[_presend >> 1]][0];
data[1] = _presend >> 1;
info.event = 0xF0;
info.ext.data = data;
info.length = 48;
}
++_presend;
return; return;
} }
@ -89,7 +99,17 @@ void MidiParser_EUP::parseNextEvent (EventInfo &info) {
channel = cmd & 0x0F; channel = cmd & 0x0F;
uint16 tick = (pos[2] | ((uint16) pos[3] << 7)) + _base_tick; uint16 tick = (pos[2] | ((uint16) pos[3] << 7)) + _base_tick;
int note = (int) pos[4] + _presets.transpose[preset]; int note = (int) pos[4] + _presets.transpose[preset];
int volume = (int) pos[5] + _presets.volume[preset]; int volume = (int) pos[5];
// HACK: Loom-Towns distaff tracks seem to
// contain zero-volume note events, so change
// those to full volume.
if (!volume)
volume = 127;
volume += _presets.volume[preset];
if (volume > 127)
volume = 127;
else if (volume < 0)
volume = 0;
pos += 6; pos += 6;
if (_presets.enable[preset]) { if (_presets.enable[preset]) {
uint16 duration = pos[1] | (pos[2] << 4); uint16 duration = pos[1] | (pos[2] << 4);
@ -148,7 +168,12 @@ bool MidiParser_EUP::loadMusic (byte *data, uint32 size) {
} }
byte numInstruments = pos[16]; byte numInstruments = pos[16];
pos += (16 + 2 + numInstruments * 48); pos += 16 + 2;
for (int i = 0; i < numInstruments; ++i) {
_instruments[i][0] = 0x7C;
memcpy (&_instruments[i][2], pos, 48);
pos += 48;
}
// Load the prest pointers // Load the prest pointers
_presets.enable = pos; _presets.enable = pos;
@ -161,6 +186,10 @@ bool MidiParser_EUP::loadMusic (byte *data, uint32 size) {
pos += 32; pos += 32;
pos += 8; // Unknown bytes pos += 8; // Unknown bytes
for (i = 0; i < 16; ++i)
_channel_instr[i] = 0xFF;
for (i = 0; i < 6; ++i)
_channel_instr[pos[i]] = i;
pos += 6; // Instrument-to-channel mapping (not supported yet) pos += 6; // Instrument-to-channel mapping (not supported yet)
pos += 4; // Skip the music size for now. pos += 4; // Skip the music size for now.
pos++; // Unknown byte pos++; // Unknown byte
@ -183,7 +212,7 @@ bool MidiParser_EUP::loadMusic (byte *data, uint32 size) {
void MidiParser_EUP::resetTracking() { void MidiParser_EUP::resetTracking() {
MidiParser::resetTracking(); MidiParser::resetTracking();
_presend = 1; _presend = 0;
_base_tick = 0; _base_tick = 0;
} }

View file

@ -92,15 +92,15 @@ static const TargetSettings scumm_settings[] = {
/* Scumm Version 3 */ /* Scumm Version 3 */
{"indy3EGA", "Indiana Jones and the Last Crusade", GID_INDY3, 3, MDT_PCSPK | MDT_ADLIB, {"indy3EGA", "Indiana Jones and the Last Crusade", GID_INDY3, 3, MDT_PCSPK | MDT_ADLIB,
GF_SMALL_HEADER | GF_SMALL_NAMES | GF_NO_SCALING | GF_USE_KEY | GF_16COLOR | GF_OLD_BUNDLE, "00.LFL"}, GF_SMALL_HEADER | GF_SMALL_NAMES | GF_NO_SCALING | GF_USE_KEY | GF_16COLOR | GF_OLD_BUNDLE, "00.LFL"},
{"indy3Towns", "Indiana Jones and the Last Crusade (FM Towns)", GID_INDY3, 3, MDT_ADLIB, {"indy3Towns", "Indiana Jones and the Last Crusade (FM Towns)", GID_INDY3, 3, MDT_TOWNS,
GF_SMALL_HEADER | GF_SMALL_NAMES | GF_NO_SCALING | GF_OLD256 | GF_FEW_LOCALS | GF_FMTOWNS | GF_AUDIOTRACKS, "00.LFL"}, GF_SMALL_HEADER | GF_SMALL_NAMES | GF_NO_SCALING | GF_OLD256 | GF_FEW_LOCALS | GF_FMTOWNS | GF_AUDIOTRACKS, "00.LFL"},
{"indy3", "Indiana Jones and the Last Crusade (256)", GID_INDY3, 3, MDT_PCSPK | MDT_ADLIB, {"indy3", "Indiana Jones and the Last Crusade (256)", GID_INDY3, 3, MDT_PCSPK | MDT_ADLIB,
GF_SMALL_HEADER | GF_SMALL_NAMES | GF_NO_SCALING | GF_OLD256 | GF_FEW_LOCALS, "00.LFL"}, GF_SMALL_HEADER | GF_SMALL_NAMES | GF_NO_SCALING | GF_OLD256 | GF_FEW_LOCALS, "00.LFL"},
{"zak256", "Zak McKracken and the Alien Mindbenders (256)", GID_ZAK256, 3, MDT_ADLIB, {"zak256", "Zak McKracken and the Alien Mindbenders (256)", GID_ZAK256, 3, MDT_TOWNS,
GF_SMALL_HEADER | GF_SMALL_NAMES | GF_NO_SCALING | GF_OLD256 | GF_FMTOWNS | GF_AUDIOTRACKS, "00.LFL"}, GF_SMALL_HEADER | GF_SMALL_NAMES | GF_NO_SCALING | GF_OLD256 | GF_FMTOWNS | GF_AUDIOTRACKS, "00.LFL"},
{"loom", "Loom", GID_LOOM, 3, MDT_PCSPK | MDT_ADLIB | MDT_NATIVE, {"loom", "Loom", GID_LOOM, 3, MDT_PCSPK | MDT_ADLIB | MDT_NATIVE,
GF_SMALL_HEADER | GF_SMALL_NAMES | GF_NO_SCALING | GF_USE_KEY | GF_16COLOR | GF_OLD_BUNDLE, "00.LFL"}, GF_SMALL_HEADER | GF_SMALL_NAMES | GF_NO_SCALING | GF_USE_KEY | GF_16COLOR | GF_OLD_BUNDLE, "00.LFL"},
{"loomTowns", "Loom (FM Towns)", GID_LOOM, 3, MDT_ADLIB, {"loomTowns", "Loom (FM Towns)", GID_LOOM, 3, MDT_TOWNS,
GF_SMALL_HEADER | GF_SMALL_NAMES | GF_NO_SCALING | GF_OLD256 | GF_FMTOWNS | GF_AUDIOTRACKS, "00.LFL"}, GF_SMALL_HEADER | GF_SMALL_NAMES | GF_NO_SCALING | GF_OLD256 | GF_FMTOWNS | GF_AUDIOTRACKS, "00.LFL"},
/* Scumm Version 4 */ /* Scumm Version 4 */
@ -696,6 +696,8 @@ ScummEngine::ScummEngine(GameDetector *detector, OSystem *syst)
_imuse->property(IMuse::PROP_LIMIT_PLAYERS, 1); _imuse->property(IMuse::PROP_LIMIT_PLAYERS, 1);
_imuse->property(IMuse::PROP_RECYCLE_PLAYERS, 1); _imuse->property(IMuse::PROP_RECYCLE_PLAYERS, 1);
} }
if (_features & GF_FMTOWNS)
_imuse->property(IMuse::PROP_DIRECT_PASSTHROUGH, 1);
_imuse->set_music_volume(_sound->_sound_volume_music); _imuse->set_music_volume(_sound->_sound_volume_music);
} }
} }

View file

@ -54,6 +54,7 @@ static const struct MidiDriverDescription midiDrivers[] = {
{"adlib", "Adlib", MD_ADLIB}, {"adlib", "Adlib", MD_ADLIB},
{"pcspk", "PC Speaker", MD_PCSPK}, {"pcspk", "PC Speaker", MD_PCSPK},
{"pcjr", "IBM PCjr", MD_PCJR}, {"pcjr", "IBM PCjr", MD_PCJR},
{"towns", "FM Towns", MD_TOWNS},
#endif #endif
#if defined(__PALM_OS__) #if defined(__PALM_OS__)

View file

@ -44,8 +44,8 @@ enum {
MD_ADLIB = 10, MD_ADLIB = 10,
MD_PCSPK = 11, MD_PCSPK = 11,
MD_PCJR = 12, MD_PCJR = 12,
MD_TOWNS = 13,
MD_YPA1 = 100 // palmos MD_YPA1 = 14 // PalmOS
}; };
/** /**
@ -144,16 +144,16 @@ public:
// Control Change messages // Control Change messages
virtual void controlChange (byte control, byte value) = 0; virtual void controlChange (byte control, byte value) = 0;
virtual void modulationWheel (byte value) = 0; virtual void modulationWheel (byte value) { controlChange (1, value); }
virtual void volume (byte value) = 0; virtual void volume (byte value) { controlChange (7, value); }
virtual void panPosition (byte value) = 0; virtual void panPosition (byte value) { controlChange (10, value); }
virtual void pitchBendFactor (byte value) = 0; virtual void pitchBendFactor (byte value) = 0;
virtual void detune (byte value) = 0; virtual void detune (byte value) { controlChange (17, value); }
virtual void priority (byte value) = 0; virtual void priority (byte value) { controlChange (18, value); }
virtual void sustain (bool value) = 0; virtual void sustain (bool value) { controlChange (64, value ? 1 : 0); }
virtual void effectLevel (byte value) = 0; virtual void effectLevel (byte value) { controlChange (91, value); }
virtual void chorusLevel (byte value) = 0; virtual void chorusLevel (byte value) { controlChange (93, value); }
virtual void allNotesOff() = 0; virtual void allNotesOff() { controlChange (123, 0); }
// SysEx messages // SysEx messages
virtual void sysEx_customInstrument (uint32 type, byte *instr) = 0; virtual void sysEx_customInstrument (uint32 type, byte *instr) = 0;
@ -169,6 +169,7 @@ extern MidiDriver *MidiDriver_QT_create();
extern MidiDriver *MidiDriver_CORE_create(); extern MidiDriver *MidiDriver_CORE_create();
extern MidiDriver *MidiDriver_ETUDE_create(); extern MidiDriver *MidiDriver_ETUDE_create();
extern MidiDriver *MidiDriver_ALSA_create(); extern MidiDriver *MidiDriver_ALSA_create();
extern MidiDriver *MidiDriver_YM2612_create(SoundMixer *mixer);
extern MidiDriver *MidiDriver_YamahaPa1_create(); extern MidiDriver *MidiDriver_YamahaPa1_create();
#endif #endif

View file

@ -59,16 +59,7 @@ public:
// Control Change messages // Control Change messages
void controlChange (byte control, byte value); void controlChange (byte control, byte value);
void modulationWheel (byte value) { controlChange (1, value); }
void volume (byte value) { controlChange (7, value); }
void panPosition (byte value) { controlChange (10, value); }
void pitchBendFactor (byte value); void pitchBendFactor (byte value);
void detune (byte value) { controlChange (17, value); }
void priority (byte value) { controlChange (18, value); }
void sustain (bool value) { controlChange (64, value ? 1 : 0); }
void effectLevel (byte value) { controlChange (91, value); }
void chorusLevel (byte value) { controlChange (93, value); }
void allNotesOff() { controlChange (123, 0); }
// SysEx messages // SysEx messages
void sysEx_customInstrument (uint32 type, byte *instr); void sysEx_customInstrument (uint32 type, byte *instr);