aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README3
-rw-r--r--backends/midi/ym2612.cpp31
-rw-r--r--backends/module.mk3
-rw-r--r--base/gameDetector.cpp10
-rw-r--r--base/gameDetector.h5
-rw-r--r--dists/msvc6/scummvm.dsp4
-rw-r--r--dists/msvc7/scummvm.vcproj3
-rw-r--r--scumm/imuse.cpp11
-rw-r--r--scumm/imuse.h13
-rw-r--r--scumm/imuse_internal.h12
-rw-r--r--scumm/imuse_player.cpp31
-rw-r--r--scumm/midiparser_eup.cpp47
-rw-r--r--scumm/scummvm.cpp8
-rw-r--r--sound/mididrv.cpp1
-rw-r--r--sound/mididrv.h23
-rw-r--r--sound/mpu401.h9
16 files changed, 154 insertions, 60 deletions
diff --git a/README b/README
index d536097ae0..20ded23d51 100644
--- a/README
+++ b/README
@@ -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
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
pcspk - Uses internal PC Speaker Emulation
+ towns - Uses FM-Towns YM2612 Emulation
windows - Windows MIDI. Uses built-in sequencer, for Windows users
seq - Uses /dev/sequencer for MIDI, *nix users. See below.
qt - Quicktime sound, for Macintosh users.
diff --git a/backends/midi/ym2612.cpp b/backends/midi/ym2612.cpp
new file mode 100644
index 0000000000..1da6f64c37
--- /dev/null
+++ b/backends/midi/ym2612.cpp
@@ -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;
+}
diff --git a/backends/module.mk b/backends/module.mk
index bb10fa7bb5..80030f0781 100644
--- a/backends/module.mk
+++ b/backends/module.mk
@@ -11,7 +11,8 @@ MODULE_OBJS := \
backends/midi/quicktime.o \
backends/midi/seq.o \
backends/midi/alsa.o \
- backends/midi/windows.o
+ backends/midi/windows.o \
+ backends/midi/ym2612.o
MODULE_DIRS += \
backends \
diff --git a/base/gameDetector.cpp b/base/gameDetector.cpp
index d1c8bde1d1..7c73715da1 100644
--- a/base/gameDetector.cpp
+++ b/base/gameDetector.cpp
@@ -676,12 +676,15 @@ bool GameDetector::detectMain() {
if (_game.midi & MDT_PREFER_NATIVE)
_midi_driver = getMidiDriverType();
else
- _midi_driver = MD_ADLIB;
+ _midi_driver = MD_TOWNS;
}
bool nativeMidiDriver =
(_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))
+ _midi_driver = MD_TOWNS;
+ if (_midi_driver == MD_TOWNS && !(_game.midi & MDT_TOWNS))
_midi_driver = MD_ADLIB;
if (_midi_driver == MD_ADLIB && !(_game.midi & MDT_ADLIB))
_midi_driver = MD_PCJR;
@@ -770,12 +773,15 @@ MidiDriver *GameDetector::createMidi() {
switch(drv) {
case MD_NULL: return MidiDriver_NULL_create();
+
// In the case of Adlib, we won't specify anything.
// IMuse is designed to set up its own Adlib driver
// if need be, and we only have to specify a native
// driver.
case MD_ADLIB: return NULL;
+ case MD_TOWNS: return MidiDriver_YM2612_create(g_engine->_mixer);
+
// Right now PC Speaker and PCjr are handled
// outside the MidiDriver architecture, so
// don't create anything for now.
diff --git a/base/gameDetector.h b/base/gameDetector.h
index 038a7681c4..a78288e437 100644
--- a/base/gameDetector.h
+++ b/base/gameDetector.h
@@ -70,8 +70,9 @@ enum MidiDriverType {
MDT_NONE = 0,
MDT_PCSPK = 1, // MD_PCSPK and MD_PCJR
MDT_ADLIB = 2, // MD_ADLIB
- MDT_NATIVE = 4, // Everything else
- MDT_PREFER_NATIVE = 8
+ MDT_TOWNS = 4, // MD_TOWNS
+ MDT_NATIVE = 8, // Everything else
+ MDT_PREFER_NATIVE = 16
};
struct TargetSettings {
diff --git a/dists/msvc6/scummvm.dsp b/dists/msvc6/scummvm.dsp
index d708117110..d5a9f6581f 100644
--- a/dists/msvc6/scummvm.dsp
+++ b/dists/msvc6/scummvm.dsp
@@ -540,6 +540,10 @@ SOURCE=..\..\backends\midi\null.cpp
SOURCE=..\..\backends\midi\windows.cpp
# End Source File
+# Begin Source File
+
+SOURCE=..\..\backends\midi\ym2612.cpp
+# End Source File
# End Group
# End Group
# End Group
diff --git a/dists/msvc7/scummvm.vcproj b/dists/msvc7/scummvm.vcproj
index cb9366490a..d7b29f98bf 100644
--- a/dists/msvc7/scummvm.vcproj
+++ b/dists/msvc7/scummvm.vcproj
@@ -355,6 +355,9 @@
<File
RelativePath="..\..\backends\midi\windows.cpp">
</File>
+ <File
+ RelativePath="..\..\backends\midi\ym2612.cpp">
+ </File>
</Filter>
</Filter>
<Filter
diff --git a/scumm/imuse.cpp b/scumm/imuse.cpp
index 223e32ad4f..602627ef4b 100644
--- a/scumm/imuse.cpp
+++ b/scumm/imuse.cpp
@@ -54,6 +54,7 @@ _initialized(false),
_tempoFactor(0),
_player_limit(ARRAYSIZE(_players)),
_recycle_players(false),
+_direct_passthrough(false),
_queue_end(0),
_queue_pos(0),
_queue_sound(0),
@@ -250,7 +251,7 @@ bool IMuseInternal::startSound(int sound) {
return false;
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;
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;
}
+
return 0;
}
diff --git a/scumm/imuse.h b/scumm/imuse.h
index be19ba0372..acebe40529 100644
--- a/scumm/imuse.h
+++ b/scumm/imuse.h
@@ -51,12 +51,13 @@ public:
~IMuse();
enum {
- PROP_TEMPO_BASE = 1,
- PROP_NATIVE_MT32 = 2,
- PROP_MULTI_MIDI = 3,
- PROP_OLD_ADLIB_INSTRUMENTS = 4,
- PROP_LIMIT_PLAYERS = 5,
- PROP_RECYCLE_PLAYERS = 6
+ PROP_TEMPO_BASE,
+ PROP_NATIVE_MT32,
+ PROP_MULTI_MIDI,
+ PROP_OLD_ADLIB_INSTRUMENTS,
+ PROP_LIMIT_PLAYERS,
+ PROP_RECYCLE_PLAYERS,
+ PROP_DIRECT_PASSTHROUGH
};
void on_timer(MidiDriver *midi);
diff --git a/scumm/imuse_internal.h b/scumm/imuse_internal.h
index 0265df65d5..e7e91b3f22 100644
--- a/scumm/imuse_internal.h
+++ b/scumm/imuse_internal.h
@@ -60,10 +60,6 @@ class ScummEngine;
#define TICKS_PER_BEAT 480
-#define IMUSE_SYSEX_ID 0x7D
-#define ROLAND_SYSEX_ID 0x41
-#define PERCUSSION_CHANNEL 9
-
#define TRIGGER_ID 0
#define COMMAND_ID 1
@@ -158,6 +154,7 @@ protected:
protected:
MidiDriver *_midi;
MidiParser *_parser;
+ bool _passThrough; // Only respond to EOT, all else direct to MidiDriver
Part *_parts;
bool _active;
@@ -259,7 +256,7 @@ public:
void setSpeed(byte speed);
int setTranspose(byte relative, int b);
int setVolume(byte vol);
- bool startSound(int sound, MidiDriver *midi);
+ bool startSound(int sound, MidiDriver *midi, bool passThrough);
int getMusicTimer() const;
public:
@@ -366,8 +363,9 @@ protected:
int _tempoFactor;
- 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?
+ 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 _direct_passthrough; // Pass data direct to MidiDriver (no interactivity)
uint _queue_end, _queue_pos, _queue_sound;
byte _queue_adding;
diff --git a/scumm/imuse_player.cpp b/scumm/imuse_player.cpp
index 69b577ed43..23048341b3 100644
--- a/scumm/imuse_player.cpp
+++ b/scumm/imuse_player.cpp
@@ -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_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;
int i;
@@ -111,6 +116,7 @@ bool Player::startSound(int sound, MidiDriver *midi) {
_pan = 0;
_transpose = 0;
_detune = 0;
+ _passThrough = passThrough;
for (i = 0; i < ARRAYSIZE(_parameterFaders); ++i)
_parameterFaders[i].init();
@@ -152,8 +158,11 @@ void Player::clear() {
debug (0, "Stopping music %d", _id);
#endif
- if (_parser)
+ if (_parser) {
_parser->unloadMusic();
+ delete _parser;
+ _parser = 0;
+ }
uninit_parts();
_se->ImFireAllTriggers(_id);
_active = false;
@@ -224,6 +233,11 @@ void Player::setSpeed(byte speed) {
}
void Player::send(uint32 b) {
+ if (_passThrough) {
+ _midi->send (b);
+ return;
+ }
+
byte cmd = (byte)(b & 0xF0);
byte chan = (byte)(b & 0x0F);
byte param1 = (byte)((b >> 8) & 0xFF);
@@ -333,8 +347,12 @@ void Player::sysEx(byte *p, uint16 len) {
byte buf[128];
Part *part;
+ if (_passThrough) {
+ _midi->sysEx (p, len);
+ return;
+ }
+
// Check SysEx manufacturer.
- // Roland is 0x41
a = *p++;
--len;
if (a != IMUSE_SYSEX_ID) {
@@ -346,6 +364,9 @@ void Player::sysEx(byte *p, uint16 len) {
if (part->clearToTransmit())
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 {
warning("Unknown SysEx manufacturer 0x%02X", (int) a);
}
@@ -1124,10 +1145,8 @@ uint32 Player::getBaseTempo() {
}
void Player::metaEvent(byte type, byte *msg, uint16 len) {
- if (type == 0x2F) {
- _parser->unloadMusic();
+ if (type == 0x2F)
clear();
- }
}
diff --git a/scumm/midiparser_eup.cpp b/scumm/midiparser_eup.cpp
index a094ade5ce..8ba23c1a96 100644
--- a/scumm/midiparser_eup.cpp
+++ b/scumm/midiparser_eup.cpp
@@ -32,6 +32,8 @@ namespace Scumm {
*/
class MidiParser_EUP : public MidiParser {
protected:
+ byte _instruments[6][50]; // Two extra bytes for SysEx ID and channel #
+ byte _channel_instr[16];
struct {
byte *enable;
int8 *channel;
@@ -69,14 +71,22 @@ void MidiParser_EUP::parseNextEvent (EventInfo &info) {
// program changes to get a reasonable "one-size-
// fits-all" sound until we actually support the
// FM synthesis capabilities of FM Towns.
- if (_presend) {
- --_presend;
+ for (; _presend < 32; ++_presend) {
+ if (_channel_instr[_presend >> 1] == 0xFF) continue;
info.start = pos;
info.delta = 0;
- info.event = ((_presend & 1) ? 0xB0 : 0xC0) | (_presend >> 1);
- info.basic.param1 = ((_presend & 1) ? 7 : 0x38);
- info.basic.param2 = ((_presend & 1) ? 127 : 0);
- _presend = (_presend + 2) % 32;
+ if (_presend & 1) {
+ info.event = 0xB0;
+ info.basic.param1 = 7;
+ 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;
}
@@ -89,7 +99,17 @@ void MidiParser_EUP::parseNextEvent (EventInfo &info) {
channel = cmd & 0x0F;
uint16 tick = (pos[2] | ((uint16) pos[3] << 7)) + _base_tick;
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;
if (_presets.enable[preset]) {
uint16 duration = pos[1] | (pos[2] << 4);
@@ -148,7 +168,12 @@ bool MidiParser_EUP::loadMusic (byte *data, uint32 size) {
}
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
_presets.enable = pos;
@@ -161,6 +186,10 @@ bool MidiParser_EUP::loadMusic (byte *data, uint32 size) {
pos += 32;
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 += 4; // Skip the music size for now.
pos++; // Unknown byte
@@ -183,7 +212,7 @@ bool MidiParser_EUP::loadMusic (byte *data, uint32 size) {
void MidiParser_EUP::resetTracking() {
MidiParser::resetTracking();
- _presend = 1;
+ _presend = 0;
_base_tick = 0;
}
diff --git a/scumm/scummvm.cpp b/scumm/scummvm.cpp
index fc8dfa16d0..ad421fb38d 100644
--- a/scumm/scummvm.cpp
+++ b/scumm/scummvm.cpp
@@ -92,15 +92,15 @@ static const TargetSettings scumm_settings[] = {
/* Scumm Version 3 */
{"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"},
- {"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"},
{"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"},
- {"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"},
{"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"},
- {"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"},
/* Scumm Version 4 */
@@ -696,6 +696,8 @@ ScummEngine::ScummEngine(GameDetector *detector, OSystem *syst)
_imuse->property(IMuse::PROP_LIMIT_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);
}
}
diff --git a/sound/mididrv.cpp b/sound/mididrv.cpp
index 3f175ce1f6..d6ab13762c 100644
--- a/sound/mididrv.cpp
+++ b/sound/mididrv.cpp
@@ -54,6 +54,7 @@ static const struct MidiDriverDescription midiDrivers[] = {
{"adlib", "Adlib", MD_ADLIB},
{"pcspk", "PC Speaker", MD_PCSPK},
{"pcjr", "IBM PCjr", MD_PCJR},
+ {"towns", "FM Towns", MD_TOWNS},
#endif
#if defined(__PALM_OS__)
diff --git a/sound/mididrv.h b/sound/mididrv.h
index 65043ff5f9..b82787b62d 100644
--- a/sound/mididrv.h
+++ b/sound/mididrv.h
@@ -44,8 +44,8 @@ enum {
MD_ADLIB = 10,
MD_PCSPK = 11,
MD_PCJR = 12,
-
- MD_YPA1 = 100 // palmos
+ MD_TOWNS = 13,
+ MD_YPA1 = 14 // PalmOS
};
/**
@@ -144,16 +144,16 @@ public:
// Control Change messages
virtual void controlChange (byte control, byte value) = 0;
- virtual void modulationWheel (byte value) = 0;
- virtual void volume (byte value) = 0;
- virtual void panPosition (byte value) = 0;
+ virtual void modulationWheel (byte value) { controlChange (1, value); }
+ virtual void volume (byte value) { controlChange (7, value); }
+ virtual void panPosition (byte value) { controlChange (10, value); }
virtual void pitchBendFactor (byte value) = 0;
- virtual void detune (byte value) = 0;
- virtual void priority (byte value) = 0;
- virtual void sustain (bool value) = 0;
- virtual void effectLevel (byte value) = 0;
- virtual void chorusLevel (byte value) = 0;
- virtual void allNotesOff() = 0;
+ virtual void detune (byte value) { controlChange (17, value); }
+ virtual void priority (byte value) { controlChange (18, value); }
+ virtual void sustain (bool value) { controlChange (64, value ? 1 : 0); }
+ virtual void effectLevel (byte value) { controlChange (91, value); }
+ virtual void chorusLevel (byte value) { controlChange (93, value); }
+ virtual void allNotesOff() { controlChange (123, 0); }
// SysEx messages
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_ETUDE_create();
extern MidiDriver *MidiDriver_ALSA_create();
+extern MidiDriver *MidiDriver_YM2612_create(SoundMixer *mixer);
extern MidiDriver *MidiDriver_YamahaPa1_create();
#endif
diff --git a/sound/mpu401.h b/sound/mpu401.h
index aef0ea9abb..c97726e6fb 100644
--- a/sound/mpu401.h
+++ b/sound/mpu401.h
@@ -59,16 +59,7 @@ public:
// Control Change messages
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 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
void sysEx_customInstrument (uint32 type, byte *instr);