aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJamieson Christian2003-10-07 15:15:26 +0000
committerJamieson Christian2003-10-07 15:15:26 +0000
commitda9fcd9cebf4f381696820e062e368b9be9b610a (patch)
treec8d51f1c7396a526e01ac056f467bfbb3e0cadaf
parent69964cda56f6570158197def169564a2aa1776ac (diff)
downloadscummvm-rg350-da9fcd9cebf4f381696820e062e368b9be9b610a.tar.gz
scummvm-rg350-da9fcd9cebf4f381696820e062e368b9be9b610a.tar.bz2
scummvm-rg350-da9fcd9cebf4f381696820e062e368b9be9b610a.zip
More Euphony/YM2612 instrument layering and polyphony
fixes. Aside from variations in the instrument timbre, the output from ScummVM now seems to match up with the output from UNZ (MAME YM2612 emulator). svn-id: r10672
-rw-r--r--backends/midi/ym2612.cpp141
-rw-r--r--scumm/midiparser_eup.cpp26
2 files changed, 68 insertions, 99 deletions
diff --git a/backends/midi/ym2612.cpp b/backends/midi/ym2612.cpp
index fcdfa26f25..69bfef8cc9 100644
--- a/backends/midi/ym2612.cpp
+++ b/backends/midi/ym2612.cpp
@@ -97,9 +97,7 @@ public:
class Voice2612 {
public:
- MidiChannel_YM2612 *_owner;
- Voice2612 *prev, *next;
- bool _in_use;
+ Voice2612 *next;
uint16 _rate;
protected:
@@ -129,18 +127,17 @@ public:
class MidiChannel_YM2612 : public MidiChannel {
protected:
- MidiDriver_YM2612 *_owner;
uint16 _rate;
- byte _instrument[48];
Voice2612 *_voices;
+ Voice2612 *_next_voice;
public:
- void removeVoice (Voice2612 *voice);
+ void removeAllVoices();
void nextTick(int *outbuf, int buflen);
void rate(uint16 r);
public:
- MidiChannel_YM2612 (MidiDriver_YM2612 *owner);
+ MidiChannel_YM2612();
virtual ~MidiChannel_YM2612();
// MidiChannel interface
@@ -160,7 +157,6 @@ public:
class MidiDriver_YM2612 : public MidiDriver {
protected:
MidiChannel_YM2612 *_channel[16];
- Voice2612 *_voices[32];
int _next_voice;
int _volume;
@@ -183,9 +179,6 @@ protected:
static void premix_proc(void *param, int16 *buf, uint len);
public:
- Voice2612 *allocateVoice();
-
-public:
MidiDriver_YM2612(SoundMixer *mixer);
virtual ~MidiDriver_YM2612();
@@ -318,7 +311,7 @@ void Operator2612::frequency(int freq) {
r = _specifiedReleaseRate;
if (r != 0) {
- r = r * 2 + 1; // このタイミングで良いのかわからん
+ r = r * 2 + 1; // (Translated) I cannot know whether the timing is a good choice or not
r = r * 2 + (keyscaleTable[freq/262205] >> (3-_keyScale));
// KS による補正はあるらしい。赤p.206 では記述されてないけど。
if (r >= 64)
@@ -435,9 +428,7 @@ void Operator2612::nextTick(const int *phasebuf, int *outbuf, int buflen) {
////////////////////////////////////////
Voice2612::Voice2612() {
- _owner = 0;
- prev = next = 0;
- _in_use = false;
+ next = 0;
_control7 = 127;
_note = 40;
_frequency = 440;
@@ -513,16 +504,8 @@ void Voice2612::setInstrument(byte const *instrument) {
}
void Voice2612::nextTick(int *outbuf, int buflen) {
- if (!_in_use || _velocity == 0)
+ if (_velocity == 0)
return;
- if (!_opr[0]->inUse() && !_opr[1]->inUse() &&
- !_opr[2]->inUse() && !_opr[3]->inUse())
- {
- _in_use = false;
- if (_owner)
- _owner->removeVoice (this);
- return;
- }
if (_buflen < buflen) {
free(_buffer);
@@ -593,7 +576,6 @@ void Voice2612::noteOn(int n, int onVelo) {
_note = n;
velocity(onVelo);
recalculateFrequency();
- _in_use = true;
int i;
for (i = 0; i < ARRAYSIZE(_opr); i++)
_opr[i]->keyOn();
@@ -645,64 +627,71 @@ void Voice2612::recalculateFrequency() {
//
////////////////////////////////////////
-MidiChannel_YM2612::MidiChannel_YM2612 (MidiDriver_YM2612 *owner) {
-// _voice = new Voice2612();
- _owner = owner;
+MidiChannel_YM2612::MidiChannel_YM2612() {
_voices = 0;
+ _next_voice = 0;
}
MidiChannel_YM2612::~MidiChannel_YM2612() {
-// delete _voice;
+ removeAllVoices();
}
-void MidiChannel_YM2612::noteOn(byte note, byte onVelo) {
- Voice2612 *voice = _owner->allocateVoice();
- if (!voice)
+void MidiChannel_YM2612::removeAllVoices() {
+ if (!_voices)
return;
- voice->_owner = this;
- voice->_rate = _rate;
- voice->next = _voices;
- voice->prev = 0;
- if (_voices)
- _voices->prev = voice;
- _voices = voice;
- voice->setInstrument (_instrument);
- voice->noteOn(note, onVelo);
+ Voice2612 *last, *voice = _voices;
+ for (; voice; voice = last) {
+ last = voice->next;
+ delete voice;
+ }
+ _voices = _next_voice = 0;
}
-void MidiChannel_YM2612::noteOff(byte note) {
- Voice2612 *voice = _voices;
- for (; voice; voice = voice->next) {
- if (voice->noteOff(note))
- removeVoice(voice);
- }
+void MidiChannel_YM2612::noteOn(byte note, byte onVelo) {
+ if (!_voices)
+ return;
+ _next_voice = _next_voice ? _next_voice : _voices;
+ _next_voice->noteOn(note, onVelo);
+ _next_voice = _next_voice->next;
}
-void MidiChannel_YM2612::removeVoice(Voice2612 *voice) {
- // We ASSUME that the voice belongs to us.
- voice->_owner = 0;
- if (voice->next)
- voice->next->prev = voice->prev;
- if (voice->prev)
- voice->prev->next = voice->next;
- else
- _voices = voice->next;
+void MidiChannel_YM2612::noteOff(byte note) {
+ if (!_voices)
+ return;
+ if (_next_voice == _voices)
+ _next_voice = 0;
+ Voice2612 *voice = _next_voice;
+ do {
+ if (!voice)
+ voice = _voices;
+ if (voice->noteOff(note)) {
+ _next_voice = voice;
+ break;
+ }
+ voice = voice->next;
+ } while (voice != _next_voice);
}
void MidiChannel_YM2612::controlChange(byte control, byte value) {
- // いいのかこれで?
- Voice2612 *voice = _voices;
- for (; voice; voice = voice->next)
- voice->setControlParameter(control, value);
+ // いいのかこれで?
+ if (control == 121) {
+ // Reset controller
+ removeAllVoices();
+ } else {
+ Voice2612 *voice = _voices;
+ for (; voice; voice = voice->next)
+ voice->setControlParameter(control, value);
+ }
}
void MidiChannel_YM2612::sysEx_customInstrument(uint32 type, byte *fmInst) {
if (type != 'EUP ')
return;
- memcpy (_instrument, fmInst, 48);
- Voice2612 *voice = _voices;
- for (; voice; voice = voice->next)
- voice->setInstrument(fmInst);
+ Voice2612 *voice = new Voice2612;
+ voice->next = _voices;
+ _voices = voice;
+ voice->_rate = _rate;
+ voice->setInstrument(fmInst);
}
void MidiChannel_YM2612::pitchBend(int16 value) {
@@ -744,10 +733,8 @@ _mixer(mixer)
createLookupTables();
_volume = 256;
int i;
- for (i = 0; i < ARRAYSIZE(_voices); i++)
- _voices[i] = new Voice2612;
for (i = 0; i < ARRAYSIZE(_channel); i++)
- _channel[i] = new MidiChannel_YM2612 (this);
+ _channel[i] = new MidiChannel_YM2612;
rate(_mixer->getOutputRate());
}
@@ -755,8 +742,6 @@ MidiDriver_YM2612::~MidiDriver_YM2612() {
int i;
for (i = 0; i < ARRAYSIZE(_channel); i++)
delete _channel[i];
- for (i = 0; i < ARRAYSIZE(_voices); i++)
- delete _voices[i];
delete sintbl;
delete powtbl;
delete frequencyTable;
@@ -865,8 +850,8 @@ void MidiDriver_YM2612::nextTick(int16 *buf1, int buflen) {
int *buf0 = (int *)buf1;
int i;
- for (i = 0; i < ARRAYSIZE(_voices); i++)
- _voices[i]->nextTick(buf0, buflen);
+ for (i = 0; i < ARRAYSIZE(_channel); i++)
+ _channel[i]->nextTick(buf0, buflen);
for (i = 0; i < buflen; ++i)
buf1[i*2+1] = buf1[i*2] = ((buf0[i] * volume()) >> 10) & 0xffff;
@@ -951,20 +936,6 @@ void MidiDriver_YM2612::createLookupTables() {
}
}
-Voice2612 *MidiDriver_YM2612::allocateVoice() {
- _next_voice %= ARRAYSIZE(_voices);
- int oldStart = _next_voice;
- do {
- if (!_voices[_next_voice++]->_in_use)
- return _voices[_next_voice-1];
- _next_voice %= ARRAYSIZE(_voices);
- } while (_next_voice != oldStart);
- Voice2612 *voice = _voices[_next_voice++];
- if (voice->_owner)
- voice->_owner->removeVoice (voice);
- return voice;
-}
-
////////////////////////////////////////
//
// MidiDriver_YM2612 factory
diff --git a/scumm/midiparser_eup.cpp b/scumm/midiparser_eup.cpp
index eeca9fbb6d..c8c6f95fdc 100644
--- a/scumm/midiparser_eup.cpp
+++ b/scumm/midiparser_eup.cpp
@@ -33,7 +33,7 @@ namespace Scumm {
class MidiParser_EUP : public MidiParser {
protected:
byte _instruments[6][50]; // Two extra bytes for SysEx ID and channel #
- byte _channel_instr[16];
+ byte *_instr_to_channel;
struct {
byte *enable;
int8 *channel;
@@ -71,20 +71,21 @@ 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.
- for (; _presend < 32; ++_presend) {
- if (_channel_instr[_presend >> 1] == 0xFF) continue;
+ for (; _presend < 12; ++_presend) {
+ if (_instr_to_channel[_presend>>1] >= 16)
+ continue;
info.start = pos;
info.delta = 0;
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;
+ byte *data = &_instruments[_presend>>1][0];
+ data[1] = _instr_to_channel[_presend>>1];
info.event = 0xF0;
info.ext.data = data;
info.length = 48;
+ } else {
+ info.event = 0xB0 | (_presend >> 1);
+ info.basic.param1 = 121;
+ info.basic.param2 = 0;
}
++_presend;
return;
@@ -186,11 +187,8 @@ 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)
+ _instr_to_channel = pos; // Instrument-to-channel mapping
+ pos += 6;
pos += 4; // Skip the music size for now.
pos++; // Unknown byte
byte tempo = *pos++;