diff options
author | Walter van Niftrik | 2009-05-05 01:51:39 +0000 |
---|---|---|
committer | Walter van Niftrik | 2009-05-05 01:51:39 +0000 |
commit | 274d890f5b9430c44fdaa24a2c67faf54fd4cb18 (patch) | |
tree | 0ea097b60e98af27a544383fda42d0f582e93b15 /engines/sci/sfx/softseq | |
parent | e1208f7b2bb578bac6dc265b2bd8ec4eaafe4a2b (diff) | |
download | scummvm-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/sfx/softseq')
-rw-r--r-- | engines/sci/sfx/softseq/adlib.cpp | 94 | ||||
-rw-r--r-- | engines/sci/sfx/softseq/adlib.h | 98 |
2 files changed, 107 insertions, 85 deletions
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 { |