aboutsummaryrefslogtreecommitdiff
path: root/engines/sci
diff options
context:
space:
mode:
authorWalter van Niftrik2009-05-05 01:51:39 +0000
committerWalter van Niftrik2009-05-05 01:51:39 +0000
commit274d890f5b9430c44fdaa24a2c67faf54fd4cb18 (patch)
tree0ea097b60e98af27a544383fda42d0f582e93b15 /engines/sci
parente1208f7b2bb578bac6dc265b2bd8ec4eaafe4a2b (diff)
downloadscummvm-rg350-274d890f5b9430c44fdaa24a2c67faf54fd4cb18.tar.gz
scummvm-rg350-274d890f5b9430c44fdaa24a2c67faf54fd4cb18.tar.bz2
scummvm-rg350-274d890f5b9430c44fdaa24a2c67faf54fd4cb18.zip
SCI: Support for 0x4e control changes in new adlib driver, and some cleanup.
svn-id: r40312
Diffstat (limited to 'engines/sci')
-rw-r--r--engines/sci/sfx/player/player.cpp11
-rw-r--r--engines/sci/sfx/softseq/adlib.cpp94
-rw-r--r--engines/sci/sfx/softseq/adlib.h98
3 files changed, 116 insertions, 87 deletions
diff --git a/engines/sci/sfx/player/player.cpp b/engines/sci/sfx/player/player.cpp
index 90d99c8092..e2ad9e5213 100644
--- a/engines/sci/sfx/player/player.cpp
+++ b/engines/sci/sfx/player/player.cpp
@@ -156,8 +156,12 @@ static int player_add_iterator(SongIterator *it, uint32 start_time) {
SIMSG_SEND(it, SIMSG_SET_PLAYMASK(mididrv->getPlayMask()));
SIMSG_SEND(it, SIMSG_SET_RHYTHM(mididrv->hasRhythmChannel()));
- current_time = Audio::Timestamp(g_system->getMillis(), 1000000 / tempo);
- wakeup_time = Audio::Timestamp(start_time, SFX_TICKS_PER_SEC);
+ if (play_it == NULL) {
+ // Resync with clock
+ current_time = Audio::Timestamp(g_system->getMillis(), 1000000 / tempo);
+ wakeup_time = Audio::Timestamp(start_time, SFX_TICKS_PER_SEC);
+ }
+
play_it = sfx_iterator_combine(play_it, it);
play_it_done = 0;
mutex->unlock();
@@ -171,9 +175,12 @@ static int player_fade_out(void) {
}
static int player_stop(void) {
+ debug(3, "Player: Stopping song iterator %p", (void *)play_it);
mutex->lock();
delete play_it;
play_it = NULL;
+ for (int i = 0; i < MIDI_CHANNELS; i++)
+ static_cast<MidiDriver *>(mididrv)->send(0xb0 + i, SCI_MIDI_CHANNEL_NOTES_OFF, 0);
mutex->unlock();
return SFX_OK;
diff --git a/engines/sci/sfx/softseq/adlib.cpp b/engines/sci/sfx/softseq/adlib.cpp
index d12b4356cc..3481eaa7ad 100644
--- a/engines/sci/sfx/softseq/adlib.cpp
+++ b/engines/sci/sfx/softseq/adlib.cpp
@@ -41,7 +41,6 @@ namespace Sci {
// FIXME: We don't seem to be sending the polyphony init data, so disable this for now
#define ADLIB_DISABLE_VOICE_MAPPING
-#define ADLIB_SCI1
static const byte registerOffset[MidiDriver_Adlib::kVoices] = {
0x00, 0x01, 0x02, 0x08, 0x09, 0x0A, 0x10, 0x11, 0x12
@@ -75,11 +74,14 @@ static const int ym3812_note[13] = {
0x2ae
};
-int MidiDriver_Adlib::open() {
+int MidiDriver_Adlib::open(bool isSCI0) {
int rate = _mixer->getOutputRate();
_stereo = STEREO;
+ debug(3, "ADLIB: Starting driver in %s mode", (isSCI0 ? "SCI0" : "SCI1"));
+ _isSCI0 = isSCI0;
+
for (int i = 0; i < (isStereo() ? 2 : 1); i++) {
_fmopl[i] = makeAdlibOPL(rate);
@@ -153,6 +155,11 @@ void MidiDriver_Adlib::send(uint32 b) {
voiceMapping(channel, op2);
#endif
break;
+ case 0x4e:
+ // FIXME: this flag should be set to 0 when a new song is started
+ debug(3, "ADLIB: Setting velocity control flag for channel %i to %i", channel, op2);
+ _channels[channel].enableVelocity = op2;
+ break;
case SCI_MIDI_CHANNEL_NOTES_OFF:
for (int i = 0; i < kVoices; i++)
if ((_voices[i].channel == channel) && (_voices[i].note != -1))
@@ -481,57 +488,66 @@ void MidiDriver_Adlib::setNote(int voice, int note, bool key) {
setRegister(0xA0 + voice, fre & 0xff);
setRegister(0xB0 + voice, (key << 5) | (oct << 2) | (fre >> 8));
-// FIXME
-#ifdef ADLIB_SCI1
- int velocity = _channels[_voices[voice].channel].volume + 1;
- velocity = velocity * (velocityMap1[_voices[voice].velocity] + 1) / 64;
- velocity = velocity * (_masterVolume + 1) / 16;
- if (--velocity < 0)
- velocity = 0;
-#else
- int velocity = _masterVolume + 3;
- if (velocity > 15)
- velocity = 15;
- velocity *= 4;
-#endif
- if (!_playSwitch)
- velocity = 0;
-
- setVelocity(voice, velocity);
+ setVelocity(voice);
}
-void MidiDriver_Adlib::setVelocity(int voice, int velocity) {
+void MidiDriver_Adlib::setVelocity(int voice) {
AdlibPatch &patch = _patches[_voices[voice].patch];
int pan = _channels[_voices[voice].channel].pan;
- setVelocityReg(registerOffset[voice] + 3, velocity, pan, patch.op[1]);
+ setVelocityReg(registerOffset[voice] + 3, calcVelocity(voice, 1), patch.op[1].kbScaleLevel, pan);
// In AM mode we need to set the level for both operators
if (_patches[_voices[voice].patch].mod.algorithm == 1)
- setVelocityReg(registerOffset[voice], velocity, pan, patch.op[0]);
+ setVelocityReg(registerOffset[voice], calcVelocity(voice, 0), patch.op[0].kbScaleLevel, pan);
}
-void MidiDriver_Adlib::setVelocityReg(int regOffset, int velocity, int pan, AdlibOperator &op) {
-// FIXME
-#ifdef ADLIB_SCI1
- int vel = (velocityMap2[velocity] * (63 - op.totalLevel) / 63);
-#else
- int vel = (velocity / 4 * ((63 - op.totalLevel) / 15));
-#endif
+int MidiDriver_Adlib::calcVelocity(int voice, int op) {
+ if (_isSCI0) {
+ int velocity = _masterVolume;
+
+ if ((velocity > 0) && (velocity < 13))
+ velocity += 3;
+
+ int insVelocity;
+ if (_channels[_voices[voice].channel].enableVelocity)
+ insVelocity = _voices[voice].velocity;
+ else
+ insVelocity = 63 - _patches[_voices[voice].patch].op[op].totalLevel;
+
+ // Note: Later SCI0 has a static table that is close to this formula, but not exactly the same.
+ // Early SCI0 does (velocity * (insVelocity / 15))
+ return velocity * insVelocity / 15;
+ } else {
+ AdlibOperator &oper = _patches[_voices[voice].patch].op[op];
+ int velocity = _channels[_voices[voice].channel].volume + 1;
+ velocity = velocity * (velocityMap1[_voices[voice].velocity] + 1) / 64;
+ velocity = velocity * (_masterVolume + 1) / 16;
+
+ if (--velocity < 0)
+ velocity = 0;
+
+ return velocityMap2[velocity] * (63 - oper.totalLevel) / 63;
+ }
+}
+
+void MidiDriver_Adlib::setVelocityReg(int regOffset, int velocity, int kbScaleLevel, int pan) {
+ if (!_playSwitch)
+ velocity = 0;
if (isStereo()) {
- int velLeft = vel;
- int velRight = vel;
+ int velLeft = velocity;
+ int velRight = velocity;
if (pan > 0x40)
velLeft = velLeft * (0x7f - pan) / 0x3f;
else if (pan < 0x40)
velRight = velRight * pan / 0x40;
- setRegister(0x40 + regOffset, (op.kbScaleLevel << 6) | (63 - velLeft), kLeftChannel);
- setRegister(0x40 + regOffset, (op.kbScaleLevel << 6) | (63 - velRight), kRightChannel);
+ setRegister(0x40 + regOffset, (kbScaleLevel << 6) | (63 - velLeft), kLeftChannel);
+ setRegister(0x40 + regOffset, (kbScaleLevel << 6) | (63 - velRight), kRightChannel);
} else {
- setRegister(0x40 + regOffset, (op.kbScaleLevel << 6) | (63 - vel));
+ setRegister(0x40 + regOffset, (kbScaleLevel << 6) | (63 - velocity));
}
}
@@ -575,6 +591,8 @@ void MidiDriver_Adlib::playSwitch(bool play) {
}
int MidiPlayer_Adlib::open(ResourceManager *resmgr) {
+ assert(resmgr != NULL);
+
// Load up the patch.003 file, parse out the instruments
Resource *res = resmgr->findResource(kResourceTypePatch, 3, 0);
@@ -583,19 +601,19 @@ int MidiPlayer_Adlib::open(ResourceManager *resmgr) {
return -1;
}
- if (res->size < 1344) {
- error("ADLIB: Expected patch.003 of at least %d bytes, got %d", 1344, res->size);
+ if ((res->size != 1344) && (res->size != 2690)) {
+ error("ADLIB: Unsupported patch format (%i bytes)", res->size);
return -1;
}
for (int i = 0; i < 48; i++)
_driver->sysEx(res->data + (28 * i), 28);
- if (res->size > 1344)
+ if (res->size == 2690)
for (int i = 48; i < 96; i++)
_driver->sysEx(res->data + 2 + (28 * i), 28);
- return _driver->open();
+ return static_cast<MidiDriver_Adlib *>(_driver)->open(resmgr->_sciVersion == SCI_VERSION_0);
}
} // End of namespace Sci
diff --git a/engines/sci/sfx/softseq/adlib.h b/engines/sci/sfx/softseq/adlib.h
index 836a92ef07..a1128e6a96 100644
--- a/engines/sci/sfx/softseq/adlib.h
+++ b/engines/sci/sfx/softseq/adlib.h
@@ -34,6 +34,27 @@ public:
kVoices = 9
};
+ MidiDriver_Adlib(Audio::Mixer *mixer) : MidiDriver_Emulated(mixer), _playSwitch(true), _masterVolume(15) { }
+ ~MidiDriver_Adlib() { }
+
+ // MidiDriver
+ int open(bool isSCI0);
+ void close();
+ void send(uint32 b);
+ MidiChannel *allocateChannel() { return NULL; }
+ MidiChannel *getPercussionChannel() { return NULL; }
+
+ // AudioStream
+ bool isStereo() const { return _stereo; }
+ int getRate() const { return _mixer->getOutputRate(); }
+
+ // MidiDriver_Emulated
+ void generateSamples(int16 *buf, int len);
+
+ void setVolume(byte volume);
+ void playSwitch(bool play);
+
+private:
enum ChannelID {
kLeftChannel = 1,
kRightChannel = 2
@@ -44,18 +65,18 @@ public:
bool vibrato;
bool envelopeType;
bool kbScaleRate;
- byte frequencyMult; // (0-15)
- byte kbScaleLevel; // (0-3)
- byte totalLevel; // (0-63, 0=max, 63=min)
- byte attackRate; // (0-15)
- byte decayRate; // (0-15)
- byte sustainLevel; // (0-15)
- byte releaseRate; // (0-15)
- byte waveForm; // (0-3)
+ byte frequencyMult; // (0-15)
+ byte kbScaleLevel; // (0-3)
+ byte totalLevel; // (0-63, 0=max, 63=min)
+ byte attackRate; // (0-15)
+ byte decayRate; // (0-15)
+ byte sustainLevel; // (0-15)
+ byte releaseRate; // (0-15)
+ byte waveForm; // (0-3)
};
struct AdlibModulator {
- byte feedback; // (0-7)
+ byte feedback; // (0-7)
bool algorithm;
};
@@ -65,50 +86,32 @@ public:
};
struct Channel {
- uint8 patch; // Patch setting
- uint8 volume; // Channel volume (0-63)
- uint8 pan; // Pan setting (0-127, 64 is center)
- uint8 holdPedal; // Hold pedal setting (0 to 63 is off, 127 to 64 is on)
- uint8 extraVoices; // The number of additional voices this channel optimally needs
- uint16 pitchWheel; // Pitch wheel setting (0-16383, 8192 is center)
- uint8 lastVoice; // Last voice used for this MIDI channel
-
- Channel() : patch(0), volume(63), pan(64), holdPedal(0), extraVoices(0), pitchWheel(8192), lastVoice(0) { }
+ uint8 patch; // Patch setting
+ uint8 volume; // Channel volume (0-63)
+ uint8 pan; // Pan setting (0-127, 64 is center)
+ uint8 holdPedal; // Hold pedal setting (0 to 63 is off, 127 to 64 is on)
+ uint8 extraVoices; // The number of additional voices this channel optimally needs
+ uint16 pitchWheel; // Pitch wheel setting (0-16383, 8192 is center)
+ uint8 lastVoice; // Last voice used for this MIDI channel
+ bool enableVelocity; // Enable velocity control (SCI0)
+
+ Channel() : patch(0), volume(63), pan(64), holdPedal(0), extraVoices(0),
+ pitchWheel(8192), lastVoice(0), enableVelocity(false) { }
};
struct AdlibVoice {
- int8 channel; // MIDI channel that this voice is assigned to or -1
- int8 note; // Currently playing MIDI note or -1
- int8 patch; // Currently playing patch or -1
- uint8 velocity; // Note velocity
- bool isSustained; // Flag indicating a note that is being sustained by the hold pedal
- uint16 age; // Age of the current note
+ int8 channel; // MIDI channel that this voice is assigned to or -1
+ int8 note; // Currently playing MIDI note or -1
+ int8 patch; // Currently playing patch or -1
+ uint8 velocity; // Note velocity
+ bool isSustained; // Flag indicating a note that is being sustained by the hold pedal
+ uint16 age; // Age of the current note
AdlibVoice() : channel(-1), note(-1), patch(-1), velocity(0), isSustained(false), age(0) { }
};
- MidiDriver_Adlib(Audio::Mixer *mixer) : MidiDriver_Emulated(mixer), _playSwitch(true), _masterVolume(15) { }
- ~MidiDriver_Adlib() { }
-
- // MidiDriver
- int open();
- void close();
- void send(uint32 b);
- MidiChannel *allocateChannel() { return NULL; }
- MidiChannel *getPercussionChannel() { return NULL; }
-
- // AudioStream
- bool isStereo() const { return _stereo; }
- int getRate() const { return _mixer->getOutputRate(); }
-
- // MidiDriver_Emulated
- void generateSamples(int16 *buf, int len);
-
- void setVolume(byte volume);
- void playSwitch(bool play);
-
-private:
bool _stereo;
+ bool _isSCI0;
FM_OPL *_fmopl[2];
bool _playSwitch;
int _masterVolume;
@@ -122,7 +125,7 @@ private:
void voiceOff(int voice);
void setPatch(int voice, int patch);
void setNote(int voice, int note, bool key);
- void setVelocity(int voice, int velocity);
+ void setVelocity(int voice);
void setOperator(int oper, AdlibOperator &op);
void setRegister(int reg, int value, int channels = kLeftChannel | kRightChannel);
void renewNotes(int channel, bool key);
@@ -134,7 +137,8 @@ private:
void releaseVoices(int channel, int voices);
void donateVoices();
int findVoiceBasic(int channel);
- void setVelocityReg(int regOffset, int velocity, int pan, AdlibOperator &op);
+ void setVelocityReg(int regOffset, int velocity, int kbScaleLevel, int pan);
+ int calcVelocity(int voice, int op);
};
class MidiPlayer_Adlib : public MidiPlayer {