aboutsummaryrefslogtreecommitdiff
path: root/backends/midi/ym2612.cpp
diff options
context:
space:
mode:
authorJamieson Christian2003-10-06 14:08:33 +0000
committerJamieson Christian2003-10-06 14:08:33 +0000
commit83ace36fcc3bd256040129db699a6fbd75b6002d (patch)
treef054fba7bc80ea6e0950e589c4940c408c7ee49a /backends/midi/ym2612.cpp
parent4ef2541a3afdd88df3266754f00e7d0e9387ea23 (diff)
downloadscummvm-rg350-83ace36fcc3bd256040129db699a6fbd75b6002d.tar.gz
scummvm-rg350-83ace36fcc3bd256040129db699a6fbd75b6002d.tar.bz2
scummvm-rg350-83ace36fcc3bd256040129db699a6fbd75b6002d.zip
Per-channel polyphony now > 1
svn-id: r10641
Diffstat (limited to 'backends/midi/ym2612.cpp')
-rw-r--r--backends/midi/ym2612.cpp104
1 files changed, 84 insertions, 20 deletions
diff --git a/backends/midi/ym2612.cpp b/backends/midi/ym2612.cpp
index f6f072d05c..61d9edf764 100644
--- a/backends/midi/ym2612.cpp
+++ b/backends/midi/ym2612.cpp
@@ -53,7 +53,7 @@ static int *attackOut = 0;
class Operator2612;
class Voice2612;
class MidiChannel_YM2612;
-class MidiDriver_YM2612_Internal;
+class MidiDriver_YM2612;
class Operator2612 {
protected:
@@ -96,6 +96,11 @@ public:
};
class Voice2612 {
+public:
+ Voice2612 *prev, *next;
+ bool _in_use; // Fix this.
+ uint16 _rate;
+
protected:
Operator2612 *_opr[4];
int _velocity;
@@ -106,9 +111,6 @@ protected:
int _algorithm;
public:
- uint16 _rate;
-
-public:
Voice2612();
~Voice2612();
void setControlParameter(int control, int value);
@@ -119,14 +121,18 @@ public:
bool noteOff(int note);
void pitchBend(int value);
void recalculateFrequency();
+ bool inUse() { return _in_use; }
};
class MidiChannel_YM2612 : public MidiChannel {
protected:
- Voice2612 *_voice;
+ MidiDriver_YM2612 *_owner;
+ uint16 _rate;
+ byte _instrument[48];
+ Voice2612 *_voices;
public:
- MidiChannel_YM2612();
+ MidiChannel_YM2612 (MidiDriver_YM2612 *owner);
virtual ~MidiChannel_YM2612();
// MidiChannel interface
@@ -149,8 +155,10 @@ public:
class MidiDriver_YM2612 : public MidiDriver {
protected:
MidiChannel_YM2612 *_channel[16];
+ Voice2612 *_voices[32];
+
+ int _next_voice;
int _volume;
- int _rate;
bool _isOpen;
SoundMixer *_mixer;
@@ -170,6 +178,9 @@ protected:
static void premix_proc(void *param, int16 *buf, uint len);
public:
+ Voice2612 *allocateVoice();
+
+public:
MidiDriver_YM2612(SoundMixer *mixer);
virtual ~MidiDriver_YM2612();
@@ -419,6 +430,7 @@ void Operator2612::nextTick(uint16 rate, const int *phasebuf, int *outbuf, int b
////////////////////////////////////////
Voice2612::Voice2612() {
+ _in_use = false;
_control7 = 127;
_note = 40;
_frequency = 440;
@@ -607,43 +619,80 @@ void Voice2612::recalculateFrequency() {
//
////////////////////////////////////////
-MidiChannel_YM2612::MidiChannel_YM2612() {
- _voice = new Voice2612();
+MidiChannel_YM2612::MidiChannel_YM2612 (MidiDriver_YM2612 *owner) {
+// _voice = new Voice2612();
+ _owner = owner;
+ _voices = 0;
}
MidiChannel_YM2612::~MidiChannel_YM2612() {
- delete _voice;
+// delete _voice;
}
void MidiChannel_YM2612::noteOn(byte note, byte onVelo) {
- _voice->noteOn(note, onVelo);
+ Voice2612 *voice = _owner->allocateVoice();
+ if (!voice)
+ return;
+ voice->_in_use = true;
+ voice->_rate = _rate;
+ voice->setInstrument (_instrument);
+ voice->next = _voices;
+ voice->prev = 0;
+ if (_voices)
+ _voices->prev = voice;
+ _voices = voice;
+ voice->noteOn(note, onVelo);
}
void MidiChannel_YM2612::noteOff(byte note) {
- _voice->noteOff(note);
+ Voice2612 *voice = _voices;
+ for (; voice; voice = voice->next) {
+ if (voice->noteOff(note)) {
+ voice->_in_use = false;
+ if (voice->next)
+ voice->next->prev = voice->prev;
+ if (voice->prev)
+ voice->prev->next = voice->next;
+ else
+ _voices = voice->next;
+ }
+ }
}
void MidiChannel_YM2612::controlChange(byte control, byte value) {
// いいのかこれで?
- _voice->setControlParameter(control, value);
+ Voice2612 *voice = _voices;
+ for (; voice; voice = voice->next)
+ voice->setControlParameter(control, value);
}
void MidiChannel_YM2612::sysEx_customInstrument(uint32 type, byte *fmInst) {
- if (type == 'EUP ')
- _voice->setInstrument(fmInst);
+ if (type != 'EUP ')
+ return;
+ memcpy (_instrument, fmInst, 48);
+ Voice2612 *voice = _voices;
+ for (; voice; voice = voice->next)
+ voice->setInstrument(fmInst);
}
void MidiChannel_YM2612::pitchBend(int16 value) {
// いいのかこれで?
- _voice->pitchBend(value);
+ Voice2612 *voice = _voices;
+ for (; voice; voice = voice->next)
+ voice->pitchBend(value);
}
void MidiChannel_YM2612::nextTick(int *outbuf, int buflen) {
- _voice->nextTick(outbuf, buflen);
+ Voice2612 *voice = _voices;
+ for (; voice; voice = voice->next)
+ voice->nextTick(outbuf, buflen);
}
void MidiChannel_YM2612::rate(uint16 r) {
- _voice->_rate = r;
+ _rate = r;
+ Voice2612 *voice = _voices;
+ for (; voice; voice = voice->next)
+ voice->_rate = r;
}
////////////////////////////////////////
@@ -660,12 +709,15 @@ _mixer(mixer)
_timer_param = 0;
_next_tick = 0;
_samples_per_tick = (_mixer->getOutputRate() << FIXP_SHIFT) / BASE_FREQ;
+ _next_voice = 0;
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;
+ _channel[i] = new MidiChannel_YM2612 (this);
rate(_mixer->getOutputRate());
}
@@ -673,6 +725,8 @@ 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;
@@ -792,7 +846,6 @@ void MidiDriver_YM2612::nextTick(int16 *buf1, int buflen) {
void MidiDriver_YM2612::rate(uint16 r)
{
- _rate = r;
int i;
for (i = 0; i < ARRAYSIZE(_channel); i++)
_channel[i]->rate(r);
@@ -870,6 +923,17 @@ void MidiDriver_YM2612::createLookupTables() {
}
}
+Voice2612 *MidiDriver_YM2612::allocateVoice() {
+ _next_voice %= ARRAYSIZE(_voices);
+ int oldStart = _next_voice;
+ do {
+ if (!_voices[_next_voice++]->inUse())
+ return _voices[_next_voice-1];
+ _next_voice %= ARRAYSIZE(_voices);
+ } while (_next_voice != oldStart);
+ return 0;
+}
+
////////////////////////////////////////
//
// MidiDriver_YM2612 factory