diff options
Diffstat (limited to 'engines/sci/sfx/softseq')
-rw-r--r-- | engines/sci/sfx/softseq/adlib.cpp | 827 | ||||
-rw-r--r-- | engines/sci/sfx/softseq/amiga.cpp | 676 | ||||
-rw-r--r-- | engines/sci/sfx/softseq/mididriver.h | 110 | ||||
-rw-r--r-- | engines/sci/sfx/softseq/pcjr.cpp | 209 | ||||
-rw-r--r-- | engines/sci/sfx/softseq/pcjr.h | 84 |
5 files changed, 0 insertions, 1906 deletions
diff --git a/engines/sci/sfx/softseq/adlib.cpp b/engines/sci/sfx/softseq/adlib.cpp deleted file mode 100644 index 11802917a2..0000000000 --- a/engines/sci/sfx/softseq/adlib.cpp +++ /dev/null @@ -1,827 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -#include "sci/sci.h" - -#include "sound/fmopl.h" -#include "sound/softsynth/emumidi.h" - -#include "sci/resource.h" -#include "sci/sfx/softseq/mididriver.h" - -namespace Sci { - -#ifdef __DC__ -#define STEREO false -#else -#define STEREO true -#endif - -// FIXME: We don't seem to be sending the polyphony init data, so disable this for now -#define ADLIB_DISABLE_VOICE_MAPPING - -class MidiDriver_Adlib : public MidiDriver_Emulated { -public: - enum { - kVoices = 9, - kRhythmKeys = 62 - }; - - MidiDriver_Adlib(Audio::Mixer *mixer) : MidiDriver_Emulated(mixer), _playSwitch(true), _masterVolume(15), _rhythmKeyMap(0), _opl(0) { } - virtual ~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); - bool loadResource(const byte *data, uint size); - virtual uint32 property(int prop, uint32 param); - -private: - enum ChannelID { - kLeftChannel = 1, - kRightChannel = 2 - }; - - struct AdlibOperator { - bool amplitudeMod; - 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) - }; - - struct AdlibModulator { - byte feedback; // (0-7) - bool algorithm; - }; - - struct AdlibPatch { - AdlibOperator op[2]; - AdlibModulator mod; - }; - - 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 - 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 - int 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) { } - }; - - bool _stereo; - bool _isSCI0; - OPL::OPL *_opl; - bool _playSwitch; - int _masterVolume; - Channel _channels[MIDI_CHANNELS]; - AdlibVoice _voices[kVoices]; - byte *_rhythmKeyMap; - Common::Array<AdlibPatch> _patches; - - void loadInstrument(const byte *ins); - void voiceOn(int voice, int note, int velocity); - void voiceOff(int voice); - void setPatch(int voice, int patch); - void setNote(int voice, int note, bool key); - 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); - void noteOn(int channel, int note, int velocity); - void noteOff(int channel, int note); - int findVoice(int channel); - void voiceMapping(int channel, int voices); - void assignVoices(int channel, int voices); - void releaseVoices(int channel, int voices); - void donateVoices(); - int findVoiceBasic(int channel); - void setVelocityReg(int regOffset, int velocity, int kbScaleLevel, int pan); - int calcVelocity(int voice, int op); -}; - -class MidiPlayer_Adlib : public MidiPlayer { -public: - MidiPlayer_Adlib() { _driver = new MidiDriver_Adlib(g_system->getMixer()); } - int open(ResourceManager *resMan); - int getPlayMask(SciVersion soundVersion); - int getPolyphony() const { return MidiDriver_Adlib::kVoices; } - bool hasRhythmChannel() const { return false; } - void setVolume(byte volume) { static_cast<MidiDriver_Adlib *>(_driver)->setVolume(volume); } - void playSwitch(bool play) { static_cast<MidiDriver_Adlib *>(_driver)->playSwitch(play); } - void loadInstrument(int idx, byte *data); -}; - -static const byte registerOffset[MidiDriver_Adlib::kVoices] = { - 0x00, 0x01, 0x02, 0x08, 0x09, 0x0A, 0x10, 0x11, 0x12 -}; - -static const byte velocityMap1[64] = { - 0x00, 0x0c, 0x0d, 0x0e, 0x0f, 0x11, 0x12, 0x13, - 0x14, 0x16, 0x17, 0x18, 0x1a, 0x1b, 0x1c, 0x1d, - 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, - 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2d, 0x2d, 0x2e, - 0x2f, 0x30, 0x31, 0x32, 0x32, 0x33, 0x34, 0x34, - 0x35, 0x36, 0x36, 0x37, 0x38, 0x38, 0x39, 0x3a, - 0x3b, 0x3b, 0x3b, 0x3c, 0x3c, 0x3c, 0x3d, 0x3d, - 0x3d, 0x3e, 0x3e, 0x3e, 0x3e, 0x3f, 0x3f, 0x3f -}; - -static const byte velocityMap2[64] = { - 0x00, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, - 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x21, - 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, - 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x2f, 0x30, - 0x31, 0x32, 0x32, 0x33, 0x34, 0x34, 0x35, 0x36, - 0x36, 0x37, 0x38, 0x38, 0x39, 0x39, 0x3a, 0x3a, - 0x3b, 0x3b, 0x3b, 0x3c, 0x3c, 0x3c, 0x3d, 0x3d, - 0x3d, 0x3e, 0x3e, 0x3e, 0x3e, 0x3f, 0x3f, 0x3f -}; - -static const int ym3812_note[13] = { - 0x157, 0x16b, 0x181, 0x198, 0x1b0, 0x1ca, - 0x1e5, 0x202, 0x220, 0x241, 0x263, 0x287, - 0x2ae -}; - -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; - - _opl = OPL::Config::create(isStereo() ? OPL::Config::kDualOpl2 : OPL::Config::kOpl2); - - // Try falling back to mono, thus plain OPL2 emualtor, when no Dual OPL2 is available. - if (!_opl && _stereo) { - _stereo = false; - _opl = OPL::Config::create(OPL::Config::kOpl2); - } - - if (!_opl) - return -1; - - _opl->init(rate); - - setRegister(0xBD, 0); - setRegister(0x08, 0); - setRegister(0x01, 0x20); - - MidiDriver_Emulated::open(); - - _mixer->playInputStream(Audio::Mixer::kMusicSoundType, &_mixerSoundHandle, this, -1, _mixer->kMaxChannelVolume, 0, false); - - return 0; -} - -void MidiDriver_Adlib::close() { - _mixer->stopHandle(_mixerSoundHandle); - - delete _opl; - delete[] _rhythmKeyMap; -} - -void MidiDriver_Adlib::setVolume(byte volume) { - _masterVolume = volume; - renewNotes(-1, true); -} - -// MIDI messages can be found at http://www.midi.org/techspecs/midimessages.php -void MidiDriver_Adlib::send(uint32 b) { - byte command = b & 0xf0; - byte channel = b & 0xf; - byte op1 = (b >> 8) & 0xff; - byte op2 = (b >> 16) & 0xff; - - switch (command) { - case 0x80: - noteOff(channel, op1); - break; - case 0x90: - noteOn(channel, op1, op2); - break; - case 0xe0: - _channels[channel].pitchWheel = (op1 & 0x7f) | ((op2 & 0x7f) << 7); - renewNotes(channel, true); - break; - case 0xb0: - switch (op1) { - case 0x07: - _channels[channel].volume = op2 >> 1; - renewNotes(channel, true); - break; - case 0x0a: - _channels[channel].pan = op2; - renewNotes(channel, true); - break; - case 0x40: - _channels[channel].holdPedal = op2; - if (op2 == 0) { - for (int i = 0; i < kVoices; i++) { - if ((_voices[i].channel == channel) && _voices[i].isSustained) - voiceOff(i); - } - } - break; - case 0x4b: -#ifndef ADLIB_DISABLE_VOICE_MAPPING - 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)) - voiceOff(i); - break; - default: - //warning("ADLIB: ignoring MIDI command %02x %02x %02x", command | channel, op1, op2); - break; - } - break; - case 0xc0: - _channels[channel].patch = op1; - break; - // The original adlib driver from sierra ignores aftertouch completely, so should we - case 0xa0: // Polyphonic key pressure (aftertouch) - case 0xd0: // Channel pressure (aftertouch) - break; - case 0xf0: // SysEx, ignore it - break; - default: - warning("ADLIB: Unknown event %02x", command); - } -} - -void MidiDriver_Adlib::generateSamples(int16 *data, int len) { - if (isStereo()) - len <<= 1; - _opl->readBuffer(data, len); - - // Increase the age of the notes - for (int i = 0; i < kVoices; i++) { - if (_voices[i].note != -1) - _voices[i].age++; - } -} - -void MidiDriver_Adlib::loadInstrument(const byte *ins) { - AdlibPatch patch; - - // Set data for the operators - for (int i = 0; i < 2; i++) { - const byte *op = ins + i * 13; - patch.op[i].kbScaleLevel = op[0] & 0x3; - patch.op[i].frequencyMult = op[1] & 0xf; - patch.op[i].attackRate = op[3] & 0xf; - patch.op[i].sustainLevel = op[4] & 0xf; - patch.op[i].envelopeType = op[5]; - patch.op[i].decayRate = op[6] & 0xf; - patch.op[i].releaseRate = op[7] & 0xf; - patch.op[i].totalLevel = op[8] & 0x3f; - patch.op[i].amplitudeMod = op[9]; - patch.op[i].vibrato = op[10]; - patch.op[i].kbScaleRate = op[11]; - } - patch.op[0].waveForm = ins[26] & 0x3; - patch.op[1].waveForm = ins[27] & 0x3; - - // Set data for the modulator - patch.mod.feedback = ins[2] & 0x7; - patch.mod.algorithm = !ins[12]; // Flag is inverted - - _patches.push_back(patch); -} - -void MidiDriver_Adlib::voiceMapping(int channel, int voices) { - int curVoices = 0; - - for (int i = 0; i < kVoices; i++) - if (_voices[i].channel == channel) - curVoices++; - - curVoices += _channels[channel].extraVoices; - - if (curVoices < voices) { - debug(3, "ADLIB: assigning %i additional voices to channel %i", voices - curVoices, channel); - assignVoices(channel, voices - curVoices); - } else if (curVoices > voices) { - debug(3, "ADLIB: releasing %i voices from channel %i", curVoices - voices, channel); - releaseVoices(channel, curVoices - voices); - donateVoices(); - } -} - -void MidiDriver_Adlib::assignVoices(int channel, int voices) { - assert(voices > 0); - - for (int i = 0; i < kVoices; i++) - if (_voices[i].channel == -1) { - _voices[i].channel = channel; - if (--voices == 0) - return; - } - - _channels[channel].extraVoices += voices; -} - -void MidiDriver_Adlib::releaseVoices(int channel, int voices) { - if (_channels[channel].extraVoices >= voices) { - _channels[channel].extraVoices -= voices; - return; - } - - voices -= _channels[channel].extraVoices; - _channels[channel].extraVoices = 0; - - for (int i = 0; i < kVoices; i++) { - if ((_voices[i].channel == channel) && (_voices[i].note == -1)) { - _voices[i].channel = -1; - if (--voices == 0) - return; - } - } - - for (int i = 0; i < kVoices; i++) { - if (_voices[i].channel == channel) { - voiceOff(i); - _voices[i].channel = -1; - if (--voices == 0) - return; - } - } -} - -void MidiDriver_Adlib::donateVoices() { - int freeVoices = 0; - - for (int i = 0; i < kVoices; i++) - if (_voices[i].channel == -1) - freeVoices++; - - if (freeVoices == 0) - return; - - for (int i = 0; i < MIDI_CHANNELS; i++) { - if (_channels[i].extraVoices >= freeVoices) { - assignVoices(i, freeVoices); - _channels[i].extraVoices -= freeVoices; - return; - } else if (_channels[i].extraVoices > 0) { - assignVoices(i, _channels[i].extraVoices); - freeVoices -= _channels[i].extraVoices; - _channels[i].extraVoices = 0; - } - } -} - -void MidiDriver_Adlib::renewNotes(int channel, bool key) { - for (int i = 0; i < kVoices; i++) { - // Update all notes playing this channel - if ((channel == -1) || (_voices[i].channel == channel)) { - if (_voices[i].note != -1) - setNote(i, _voices[i].note, key); - } - } -} - -void MidiDriver_Adlib::noteOn(int channel, int note, int velocity) { - if (velocity == 0) - return noteOff(channel, note); - - velocity >>= 1; - - // Check for playable notes - if ((note < 12) || (note > 107)) - return; - - for (int i = 0; i < kVoices; i++) { - if ((_voices[i].channel == channel) && (_voices[i].note == note)) { - voiceOff(i); - voiceOn(i, note, velocity); - return; - } - } - -#ifdef ADLIB_DISABLE_VOICE_MAPPING - int voice = findVoiceBasic(channel); -#else - int voice = findVoice(channel); -#endif - - if (voice == -1) { - debug(3, "ADLIB: failed to find free voice assigned to channel %i", channel); - return; - } - - voiceOn(voice, note, velocity); -} - -// FIXME: Temporary, see comment at top of file regarding ADLIB_DISABLE_VOICE_MAPPING -int MidiDriver_Adlib::findVoiceBasic(int channel) { - int voice = -1; - int oldestVoice = -1; - int oldestAge = -1; - - // Try to find a voice assigned to this channel that is free (round-robin) - for (int i = 0; i < kVoices; i++) { - int v = (_channels[channel].lastVoice + i + 1) % kVoices; - - if (_voices[v].note == -1) { - voice = v; - break; - } - - // We also keep track of the oldest note in case the search fails - if (_voices[v].age > oldestAge) { - oldestAge = _voices[v].age; - oldestVoice = v; - } - } - - if (voice == -1) { - if (oldestVoice != -1) { - voiceOff(oldestVoice); - voice = oldestVoice; - } else { - return -1; - } - } - - _voices[voice].channel = channel; - _channels[channel].lastVoice = voice; - return voice; -} - -int MidiDriver_Adlib::findVoice(int channel) { - int voice = -1; - int oldestVoice = -1; - uint32 oldestAge = 0; - - // Try to find a voice assigned to this channel that is free (round-robin) - for (int i = 0; i < kVoices; i++) { - int v = (_channels[channel].lastVoice + i + 1) % kVoices; - - if (_voices[v].channel == channel) { - if (_voices[v].note == -1) { - voice = v; - break; - } - - // We also keep track of the oldest note in case the search fails - // Notes started in the current time slice will not be selected - if (_voices[v].age > oldestAge) { - oldestAge = _voices[v].age; - oldestVoice = v; - } - } - } - - if (voice == -1) { - if (oldestVoice != -1) { - voiceOff(oldestVoice); - voice = oldestVoice; - } else { - return -1; - } - } - - _channels[channel].lastVoice = voice; - return voice; -} - -void MidiDriver_Adlib::noteOff(int channel, int note) { - for (int i = 0; i < kVoices; i++) { - if ((_voices[i].channel == channel) && (_voices[i].note == note)) { - if (_channels[channel].holdPedal) - _voices[i].isSustained = true; - else - voiceOff(i); - return; - } - } -} - -void MidiDriver_Adlib::voiceOn(int voice, int note, int velocity) { - int channel = _voices[voice].channel; - int patch; - - _voices[voice].age = 0; - - if ((channel == 9) && _rhythmKeyMap) { - patch = CLIP(note, 27, 88) + 101; - } else { - patch = _channels[channel].patch; - } - - // Set patch if different from current patch - if ((patch != _voices[voice].patch) && _playSwitch) - setPatch(voice, patch); - - _voices[voice].velocity = velocity; - setNote(voice, note, true); -} - -void MidiDriver_Adlib::voiceOff(int voice) { - _voices[voice].isSustained = false; - setNote(voice, _voices[voice].note, 0); - _voices[voice].note = -1; - _voices[voice].age = 0; -} - -void MidiDriver_Adlib::setNote(int voice, int note, bool key) { - int channel = _voices[voice].channel; - int n, fre, oct; - float delta; - int bend = _channels[channel].pitchWheel; - - if ((channel == 9) && _rhythmKeyMap) { - note = _rhythmKeyMap[CLIP(note, 27, 88) - 27]; - } - - _voices[voice].note = note; - - delta = 0; - - n = note % 12; - - if (bend < 8192) - bend = 8192 - bend; - delta = (float)pow(2.0, (bend % 8192) / 8192.0); - - if (bend > 8192) - fre = (int)(ym3812_note[n] * delta); - else - fre = (int)(ym3812_note[n] / delta); - - oct = note / 12 - 1; - - if (oct < 0) - oct = 0; - - if (oct > 7) - oct = 7; - - setRegister(0xA0 + voice, fre & 0xff); - setRegister(0xB0 + voice, (key << 5) | (oct << 2) | (fre >> 8)); - - setVelocity(voice); -} - -void MidiDriver_Adlib::setVelocity(int voice) { - AdlibPatch &patch = _patches[_voices[voice].patch]; - int pan = _channels[_voices[voice].channel].pan; - 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], calcVelocity(voice, 0), patch.op[0].kbScaleLevel, pan); -} - -int MidiDriver_Adlib::calcVelocity(int voice, int op) { - if (_isSCI0) { - int velocity = _masterVolume; - - if (velocity > 0) - velocity += 3; - - if (velocity > 15) - velocity = 15; - - 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 = velocity; - int velRight = velocity; - - if (pan > 0x40) - velLeft = velLeft * (0x7f - pan) / 0x3f; - else if (pan < 0x40) - velRight = velRight * pan / 0x40; - - setRegister(0x40 + regOffset, (kbScaleLevel << 6) | (63 - velLeft), kLeftChannel); - setRegister(0x40 + regOffset, (kbScaleLevel << 6) | (63 - velRight), kRightChannel); - } else { - setRegister(0x40 + regOffset, (kbScaleLevel << 6) | (63 - velocity)); - } -} - -void MidiDriver_Adlib::setPatch(int voice, int patch) { - if ((patch < 0) || ((uint)patch >= _patches.size())) { - warning("ADLIB: Invalid patch %i requested", patch); - patch = 0; - } - - _voices[voice].patch = patch; - AdlibModulator &mod = _patches[patch].mod; - - // Set the common settings for both operators - setOperator(registerOffset[voice], _patches[patch].op[0]); - setOperator(registerOffset[voice] + 3, _patches[patch].op[1]); - - // Set the additional settings for the modulator - byte algorithm = mod.algorithm ? 1 : 0; - setRegister(0xC0 + voice, (mod.feedback << 1) | algorithm); -} - -void MidiDriver_Adlib::setOperator(int reg, AdlibOperator &op) { - setRegister(0x40 + reg, (op.kbScaleLevel << 6) | op.totalLevel); - setRegister(0x60 + reg, (op.attackRate << 4) | op.decayRate); - setRegister(0x80 + reg, (op.sustainLevel << 4) | op.releaseRate); - setRegister(0x20 + reg, (op.amplitudeMod << 7) | (op.vibrato << 6) - | (op.envelopeType << 5) | (op.kbScaleRate << 4) | op.frequencyMult); - setRegister(0xE0 + reg, op.waveForm); -} - -void MidiDriver_Adlib::setRegister(int reg, int value, int channels) { - if (channels & kLeftChannel) { - _opl->write(0x220, reg); - _opl->write(0x221, value); - } - - if (isStereo()) { - if (channels & kRightChannel) { - _opl->write(0x222, reg); - _opl->write(0x223, value); - } - } -} - -void MidiDriver_Adlib::playSwitch(bool play) { - _playSwitch = play; - renewNotes(-1, play); -} - -bool MidiDriver_Adlib::loadResource(const byte *data, uint size) { - if ((size != 1344) && (size != 2690) && (size != 5382)) { - warning("ADLIB: Unsupported patch format (%i bytes)", size); - return false; - } - - for (int i = 0; i < 48; i++) - loadInstrument(data + (28 * i)); - - if (size == 2690) { - for (int i = 48; i < 96; i++) - loadInstrument(data + 2 + (28 * i)); - } else if (size == 5382) { - for (int i = 48; i < 190; i++) - loadInstrument(data + (28 * i)); - _rhythmKeyMap = new byte[kRhythmKeys]; - memcpy(_rhythmKeyMap, data + 5320, kRhythmKeys); - } - - return true; -} - -uint32 MidiDriver_Adlib::property(int prop, uint32 param) { - switch(prop) { - case MIDI_PROP_MASTER_VOLUME: - if (param != 0xffff) - _masterVolume = param; - return _masterVolume; - default: - break; - } - return 0; -} - - -int MidiPlayer_Adlib::open(ResourceManager *resMan) { - assert(resMan != NULL); - - // Load up the patch.003 file, parse out the instruments - Resource *res = resMan->findResource(ResourceId(kResourceTypePatch, 3), 0); - bool ok = false; - - if (res) { - ok = static_cast<MidiDriver_Adlib *>(_driver)->loadResource(res->data, res->size); - } else { - // Early SCI0 games have the sound bank embedded in the adlib driver - - Common::File f; - - if (f.open("ADL.DRV")) { - int size = f.size(); - const uint patchSize = 1344; - - if ((size == 5684) || (size == 5720) || (size == 5727)) { - byte *buf = new byte[patchSize]; - - if (f.seek(0x45a) && (f.read(buf, patchSize) == patchSize)) - ok = static_cast<MidiDriver_Adlib *>(_driver)->loadResource(buf, patchSize); - - delete[] buf; - } - } - } - - if (!ok) { - warning("ADLIB: Failed to load patch.003"); - return -1; - } - - return static_cast<MidiDriver_Adlib *>(_driver)->open(getSciVersion() <= SCI_VERSION_0_LATE); -} - -int MidiPlayer_Adlib::getPlayMask(SciVersion soundVersion) { - return (soundVersion == SCI_VERSION_0_EARLY) ? 0x01 : 0x04; -} - -MidiPlayer *MidiPlayer_Adlib_create() { - return new MidiPlayer_Adlib(); -} - -MidiDriver *MidiDriver_Adlib_create() { - return new MidiDriver_Adlib(g_system->getMixer()); -} - -} // End of namespace Sci diff --git a/engines/sci/sfx/softseq/amiga.cpp b/engines/sci/sfx/softseq/amiga.cpp deleted file mode 100644 index d16e82fab5..0000000000 --- a/engines/sci/sfx/softseq/amiga.cpp +++ /dev/null @@ -1,676 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -#include "sound/softsynth/emumidi.h" -#include "sci/sfx/softseq/mididriver.h" - -#include "common/file.h" -#include "common/frac.h" -#include "common/util.h" - -namespace Sci { - -/* #define DEBUG */ - -// Frequencies for every note -// FIXME Store only one octave -static const int freq_table[] = { - 58, 62, 65, 69, 73, 78, 82, 87, - 92, 98, 104, 110, 117, 124, 131, 139, - 147, 156, 165, 175, 185, 196, 208, 220, - 234, 248, 262, 278, 294, 312, 331, 350, - 371, 393, 417, 441, 468, 496, 525, 556, - 589, 625, 662, 701, 743, 787, 834, 883, - 936, 992, 1051, 1113, 1179, 1250, 1324, 1403, - 1486, 1574, 1668, 1767, 1872, 1984, 2102, 2227, - 2359, 2500, 2648, 2806, 2973, 3149, 3337, 3535, - 3745, 3968, 4204, 4454, 4719, 5000, 5297, 5612, - 5946, 6299, 6674, 7071, 7491, 7937, 8408, 8908, - 9438, 10000, 10594, 11224, 11892, 12599, 13348, 14142, - 14983, 15874, 16817, 17817, 18877, 20000, 21189, 22449, - 23784, 25198, 26696, 28284, 29966, 31748, 33635, 35635, - 37754, 40000, 42378, 44898, 47568, 50396, 53393, 56568, - 59932, 63496, 67271, 71271, 75509, 80000, 84757, 89796 -}; - -class MidiDriver_Amiga : public MidiDriver_Emulated { -public: - enum { - kVoices = 4 - }; - - MidiDriver_Amiga(Audio::Mixer *mixer) : MidiDriver_Emulated(mixer), _playSwitch(true), _masterVolume(15) { } - virtual ~MidiDriver_Amiga() { } - - // MidiDriver - int open(); - void close(); - void send(uint32 b); - MidiChannel *allocateChannel() { return NULL; } - MidiChannel *getPercussionChannel() { return NULL; } - - // AudioStream - bool isStereo() const { return true; } - int getRate() const { return _mixer->getOutputRate(); } - - // MidiDriver_Emulated - void generateSamples(int16 *buf, int len); - - void setVolume(byte volume); - void playSwitch(bool play); - virtual uint32 property(int prop, uint32 param); - -private: - enum { - kModeLoop = 1 << 0, // Instrument looping flag - kModePitch = 1 << 1 // Instrument pitch changes flag - }; - - enum { - kChannels = 10, - kBaseFreq = 20000, // Samplerate of the instrument bank - kPanLeft = 91, - kPanRight = 164 - }; - - struct Channel { - int instrument; - int volume; - int pan; - }; - - struct Envelope { - int length; // Phase period length in samples - int delta; // Velocity delta per period - int target; // Target velocity - }; - - struct Voice { - int instrument; - int note; - int note_velocity; - int velocity; - int envelope; - int envelope_samples; // Number of samples till next envelope event - int decay; - int looping; - int hw_channel; - frac_t offset; - frac_t rate; - }; - - struct Instrument { - char name[30]; - int mode; - int size; // Size of non-looping part in bytes - int loop_size; // Starting offset and size of loop in bytes - int transpose; // Transpose value in semitones - Envelope envelope[4]; // Envelope - int8 *samples; - int8 *loop; - }; - - struct Bank { - char name[30]; - uint size; - Instrument *instruments[256]; - }; - - bool _playSwitch; - int _masterVolume; - int _frequency; - Envelope _envDecay; - Bank _bank; // Instrument bank - - Channel _channels[MIDI_CHANNELS]; - /* Internal channels */ - Voice _voices[kChannels]; - - void setEnvelope(Voice *channel, Envelope *envelope, int phase); - int interpolate(int8 *samples, frac_t offset); - void playInstrument(int16 *dest, Voice *channel, int count); - void changeInstrument(int channel, int instrument); - void stopChannel(int ch); - void stopNote(int ch, int note); - void startNote(int ch, int note, int velocity); - Instrument *readInstrument(Common::File &file, int *id); -}; - -void MidiDriver_Amiga::setEnvelope(Voice *channel, Envelope *envelope, int phase) { - channel->envelope = phase; - channel->envelope_samples = envelope[phase].length; - - if (phase == 0) - channel->velocity = channel->note_velocity / 2; - else - channel->velocity = envelope[phase - 1].target; -} - -int MidiDriver_Amiga::interpolate(int8 *samples, frac_t offset) { - int x = fracToInt(offset); - int diff = (samples[x + 1] - samples[x]) << 8; - - return (samples[x] << 8) + fracToInt(diff * (offset & FRAC_LO_MASK)); -} - -void MidiDriver_Amiga::playInstrument(int16 *dest, Voice *channel, int count) { - int index = 0; - int vol = _channels[channel->hw_channel].volume; - Instrument *instrument = _bank.instruments[channel->instrument]; - - while (1) { - /* Available source samples until end of segment */ - frac_t lin_avail; - int seg_end, rem, i, amount; - int8 *samples; - - if (channel->looping) { - samples = instrument->loop; - seg_end = instrument->loop_size; - } else { - samples = instrument->samples; - seg_end = instrument->size; - } - - lin_avail = intToFrac(seg_end) - channel->offset; - - rem = count - index; - - /* Amount of destination samples that we will compute this iteration */ - amount = lin_avail / channel->rate; - - if (lin_avail % channel->rate) - amount++; - - if (amount > rem) - amount = rem; - - /* Stop at next envelope event */ - if ((channel->envelope_samples != -1) && (amount > channel->envelope_samples)) - amount = channel->envelope_samples; - - for (i = 0; i < amount; i++) { - dest[index++] = interpolate(samples, channel->offset) * channel->velocity / 64 * channel->note_velocity * vol / (127 * 127); - channel->offset += channel->rate; - } - - if (channel->envelope_samples != -1) - channel->envelope_samples -= amount; - - if (channel->envelope_samples == 0) { - Envelope *envelope; - int delta, target, velocity; - - if (channel->decay) - envelope = &_envDecay; - else - envelope = &instrument->envelope[channel->envelope]; - - delta = envelope->delta; - target = envelope->target; - velocity = channel->velocity - envelope->delta; - - /* Check whether we have reached the velocity target for the current phase */ - if ((delta >= 0 && velocity <= target) || (delta < 0 && velocity >= target)) { - channel->velocity = target; - - /* Stop note after velocity has dropped to 0 */ - if (target == 0) { - channel->note = -1; - break; - } else - switch (channel->envelope) { - case 0: - case 2: - /* Go to next phase */ - setEnvelope(channel, instrument->envelope, channel->envelope + 1); - break; - case 1: - case 3: - /* Stop envelope */ - channel->envelope_samples = -1; - break; - } - } else { - /* We haven't reached the target yet */ - channel->envelope_samples = envelope->length; - channel->velocity = velocity; - } - } - - if (index == count) - break; - - if (fracToInt(channel->offset) >= seg_end) { - if (instrument->mode & kModeLoop) { - /* Loop the samples */ - channel->offset -= intToFrac(seg_end); - channel->looping = 1; - } else { - /* All samples have been played */ - channel->note = -1; - break; - } - } - } -} - -void MidiDriver_Amiga::changeInstrument(int channel, int instrument) { -#ifdef DEBUG - if (_bank.instruments[instrument]) - printf("[sfx:seq:amiga] Setting channel %i to \"%s\" (%i)\n", channel, _bank.instruments[instrument]->name, instrument); - else - warning("[sfx:seq:amiga] instrument %i does not exist (channel %i)", instrument, channel); -#endif - _channels[channel].instrument = instrument; -} - -void MidiDriver_Amiga::stopChannel(int ch) { - int i; - - /* Start decay phase for note on this hw channel, if any */ - for (i = 0; i < kChannels; i++) - if (_voices[i].note != -1 && _voices[i].hw_channel == ch && !_voices[i].decay) { - /* Trigger fast decay envelope */ - _voices[i].decay = 1; - _voices[i].envelope_samples = _envDecay.length; - break; - } -} - -void MidiDriver_Amiga::stopNote(int ch, int note) { - int channel; - Instrument *instrument; - - for (channel = 0; channel < kChannels; channel++) - if (_voices[channel].note == note && _voices[channel].hw_channel == ch && !_voices[channel].decay) - break; - - if (channel == kChannels) { -#ifdef DEBUG - warning("[sfx:seq:amiga] cannot stop note %i on channel %i", note, ch); -#endif - return; - } - - instrument = _bank.instruments[_voices[channel].instrument]; - - /* Start the envelope phases for note-off if looping is on and envelope is enabled */ - if ((instrument->mode & kModeLoop) && (instrument->envelope[0].length != 0)) - setEnvelope(&_voices[channel], instrument->envelope, 2); -} - -void MidiDriver_Amiga::startNote(int ch, int note, int velocity) { - Instrument *instrument; - int channel; - - if (_channels[ch].instrument < 0 || _channels[ch].instrument > 255) { - warning("[sfx:seq:amiga] invalid instrument %i on channel %i", _channels[ch].instrument, ch); - return; - } - - instrument = _bank.instruments[_channels[ch].instrument]; - - if (!instrument) { - warning("[sfx:seq:amiga] instrument %i does not exist", _channels[ch].instrument); - return; - } - - for (channel = 0; channel < kChannels; channel++) - if (_voices[channel].note == -1) - break; - - if (channel == kChannels) { - warning("[sfx:seq:amiga] could not find a free channel"); - return; - } - - stopChannel(ch); - - if (instrument->mode & kModePitch) { - int fnote = note + instrument->transpose; - - if (fnote < 0 || fnote > 127) { - warning("[sfx:seq:amiga] illegal note %i\n", fnote); - return; - } - - /* Compute rate for note */ - _voices[channel].rate = doubleToFrac(freq_table[fnote] / (double) _frequency); - } else - _voices[channel].rate = doubleToFrac(kBaseFreq / (double) _frequency); - - _voices[channel].instrument = _channels[ch].instrument; - _voices[channel].note = note; - _voices[channel].note_velocity = velocity; - - if ((instrument->mode & kModeLoop) && (instrument->envelope[0].length != 0)) - setEnvelope(&_voices[channel], instrument->envelope, 0); - else { - _voices[channel].velocity = 64; - _voices[channel].envelope_samples = -1; - } - - _voices[channel].offset = 0; - _voices[channel].hw_channel = ch; - _voices[channel].decay = 0; - _voices[channel].looping = 0; -} - -MidiDriver_Amiga::Instrument *MidiDriver_Amiga::readInstrument(Common::File &file, int *id) { - Instrument *instrument; - byte header[61]; - int size; - int seg_size[3]; - int loop_offset; - int i; - - if (file.read(header, 61) < 61) { - warning("[sfx:seq:amiga] failed to read instrument header"); - return NULL; - } - - instrument = new Instrument; - - seg_size[0] = READ_BE_UINT16(header + 35) * 2; - seg_size[1] = READ_BE_UINT16(header + 41) * 2; - seg_size[2] = READ_BE_UINT16(header + 47) * 2; - - instrument->mode = header[33]; - instrument->transpose = (int8) header[34]; - for (i = 0; i < 4; i++) { - int length = (int8) header[49 + i]; - - if (length == 0 && i > 0) - length = 256; - - instrument->envelope[i].length = length * _frequency / 60; - instrument->envelope[i].delta = (int8)header[53 + i]; - instrument->envelope[i].target = header[57 + i]; - } - /* Final target must be 0 */ - instrument->envelope[3].target = 0; - - loop_offset = READ_BE_UINT32(header + 37) & ~1; - size = seg_size[0] + seg_size[1] + seg_size[2]; - - *id = READ_BE_UINT16(header); - - strncpy(instrument->name, (char *) header + 2, 29); - instrument->name[29] = 0; -#ifdef DEBUG - printf("[sfx:seq:amiga] Reading instrument %i: \"%s\" (%i bytes)\n", - *id, instrument->name, size); - printf(" Mode: %02x\n", instrument->mode); - printf(" Looping: %s\n", instrument->mode & kModeLoop ? "on" : "off"); - printf(" Pitch changes: %s\n", instrument->mode & kModePitch ? "on" : "off"); - printf(" Segment sizes: %i %i %i\n", seg_size[0], seg_size[1], seg_size[2]); - printf(" Segment offsets: 0 %i %i\n", loop_offset, read_int32(header + 43)); -#endif - instrument->samples = (int8 *) malloc(size + 1); - if (file.read(instrument->samples, size) < (unsigned int)size) { - warning("[sfx:seq:amiga] failed to read instrument samples"); - free(instrument->samples); - delete instrument; - return NULL; - } - - if (instrument->mode & kModeLoop) { - if (loop_offset + seg_size[1] > size) { -#ifdef DEBUG - warning("[sfx:seq:amiga] looping samples extend %i bytes past end of sample block", - loop_offset + seg_size[1] - size); -#endif - seg_size[1] = size - loop_offset; - } - - if (seg_size[1] < 0) { - warning("[sfx:seq:amiga] invalid looping point"); - free(instrument->samples); - delete instrument; - return NULL; - } - - instrument->size = seg_size[0]; - instrument->loop_size = seg_size[1]; - - instrument->loop = (int8*)malloc(instrument->loop_size + 1); - memcpy(instrument->loop, instrument->samples + loop_offset, instrument->loop_size); - - instrument->samples[instrument->size] = instrument->loop[0]; - instrument->loop[instrument->loop_size] = instrument->loop[0]; - } else { - instrument->loop = NULL; - instrument->size = size; - instrument->samples[instrument->size] = 0; - } - - return instrument; -} - -uint32 MidiDriver_Amiga::property(int prop, uint32 param) { - switch(prop) { - case MIDI_PROP_MASTER_VOLUME: - if (param != 0xffff) - _masterVolume = param; - return _masterVolume; - default: - break; - } - return 0; -} - -int MidiDriver_Amiga::open() { - _frequency = _mixer->getOutputRate(); - _envDecay.length = _frequency / (32 * 64); - _envDecay.delta = 1; - _envDecay.target = 0; - - Common::File file; - byte header[40]; - - if (!file.open("bank.001")) { - warning("[sfx:seq:amiga] file bank.001 not found"); - return Common::kUnknownError; - } - - if (file.read(header, 40) < 40) { - warning("[sfx:seq:amiga] failed to read header of file bank.001"); - return Common::kUnknownError; - } - - for (uint i = 0; i < 256; i++) - _bank.instruments[i] = NULL; - - for (uint i = 0; i < kChannels; i++) { - _voices[i].note = -1; - _voices[i].hw_channel = 0; - } - - for (uint i = 0; i < MIDI_CHANNELS; i++) { - _channels[i].instrument = -1; - _channels[i].volume = 127; - _channels[i].pan = (i % 4 == 0 || i % 4 == 3 ? kPanLeft : kPanRight); - } - - _bank.size = READ_BE_UINT16(header + 38); - strncpy(_bank.name, (char *) header + 8, 29); - _bank.name[29] = 0; -#ifdef DEBUG - printf("[sfx:seq:amiga] Reading %i instruments from bank \"%s\"\n", _bank.size, _bank.name); -#endif - - for (uint i = 0; i < _bank.size; i++) { - int id; - Instrument *instrument = readInstrument(file, &id); - - if (!instrument) { - warning("[sfx:seq:amiga] failed to read bank.001"); - return Common::kUnknownError; - } - - if (id < 0 || id > 255) { - warning("[sfx:seq:amiga] Error: instrument ID out of bounds"); - return Common::kUnknownError; - } - - _bank.instruments[id] = instrument; - } - - MidiDriver_Emulated::open(); - - _mixer->playInputStream(Audio::Mixer::kMusicSoundType, &_mixerSoundHandle, this, -1, _mixer->kMaxChannelVolume, 0, false); - - return Common::kNoError; -} - -void MidiDriver_Amiga::close() { - _mixer->stopHandle(_mixerSoundHandle); - - for (uint i = 0; i < _bank.size; i++) { - if (_bank.instruments[i]) { - if (_bank.instruments[i]->loop) - free(_bank.instruments[i]->loop); - free(_bank.instruments[i]->samples); - delete _bank.instruments[i]; - } - } -} - -void MidiDriver_Amiga::playSwitch(bool play) { - _playSwitch = play; -} - -void MidiDriver_Amiga::setVolume(byte volume_) { - _masterVolume = volume_; -} - -void MidiDriver_Amiga::send(uint32 b) { - byte command = b & 0xf0; - byte channel = b & 0xf; - byte op1 = (b >> 8) & 0xff; - byte op2 = (b >> 16) & 0xff; - - switch (command) { - case 0x80: - stopNote(channel, op1); - break; - case 0x90: - if (op2 > 0) - startNote(channel, op1, op2); - else - stopNote(channel, op1); - break; - case 0xb0: - switch (op1) { - case 0x07: - _channels[channel].volume = op2; - break; - case 0x0a: -#ifdef DEBUG - warning("[sfx:seq:amiga] ignoring pan 0x%02x event for channel %i", op2, channel); -#endif - break; - case 0x7b: - stopChannel(channel); - break; - default: - warning("[sfx:seq:amiga] unknown control event 0x%02x", op1); - } - break; - case 0xc0: - changeInstrument(channel, op1); - break; - default: - warning("[sfx:seq:amiga] unknown event %02x", command); - } -} - -void MidiDriver_Amiga::generateSamples(int16 *data, int len) { - if (len == 0) - return; - - int16 *buffers = (int16*)malloc(len * 2 * kChannels); - - memset(buffers, 0, len * 2 * kChannels); - - /* Generate samples for all notes */ - for (int i = 0; i < kChannels; i++) - if (_voices[i].note >= 0) - playInstrument(buffers + i * len, &_voices[i], len); - - if (isStereo()) { - for (int j = 0; j < len; j++) { - int mixedl = 0, mixedr = 0; - - /* Mix and pan */ - for (int i = 0; i < kChannels; i++) { - mixedl += buffers[i * len + j] * (256 - _channels[_voices[i].hw_channel].pan); - mixedr += buffers[i * len + j] * _channels[_voices[i].hw_channel].pan; - } - - /* Adjust volume */ - data[2 * j] = mixedl * _masterVolume >> 13; - data[2 * j + 1] = mixedr * _masterVolume >> 13; - } - } else { - for (int j = 0; j < len; j++) { - int mixed = 0; - - /* Mix */ - for (int i = 0; i < kChannels; i++) - mixed += buffers[i * len + j]; - - /* Adjust volume */ - data[j] = mixed * _masterVolume >> 6; - } - } - - free(buffers); -} - -class MidiPlayer_Amiga : public MidiPlayer { -public: - MidiPlayer_Amiga() { _driver = new MidiDriver_Amiga(g_system->getMixer()); } - int getPlayMask(SciVersion soundVersion); - int getPolyphony() const { return MidiDriver_Amiga::kVoices; } - bool hasRhythmChannel() const { return false; } - void setVolume(byte volume) { static_cast<MidiDriver_Amiga *>(_driver)->setVolume(volume); } - void playSwitch(bool play) { static_cast<MidiDriver_Amiga *>(_driver)->playSwitch(play); } - void loadInstrument(int idx, byte *data); -}; - -MidiPlayer *MidiPlayer_Amiga_create() { - return new MidiPlayer_Amiga(); -} - -int MidiPlayer_Amiga::getPlayMask(SciVersion soundVersion) { - if (soundVersion == SCI_VERSION_0_EARLY) - error("No amiga support for sci0early"); - - return 0x40; -} - -} // End of namespace Sci diff --git a/engines/sci/sfx/softseq/mididriver.h b/engines/sci/sfx/softseq/mididriver.h deleted file mode 100644 index df0532d732..0000000000 --- a/engines/sci/sfx/softseq/mididriver.h +++ /dev/null @@ -1,110 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -#ifndef SCI_SFX_SOFTSEQ_MIDIDRIVER_H -#define SCI_SFX_SOFTSEQ_MIDIDRIVER_H - -#include "sci/sci.h" -#include "sound/mididrv.h" -#include "sound/softsynth/emumidi.h" -#include "common/error.h" - -namespace Sci { - -class ResourceManager; - -enum { - MIDI_CHANNELS = 16, - MIDI_PROP_MASTER_VOLUME = 0 -}; - - -#define MIDI_RHYTHM_CHANNEL 9 - -/* Special SCI sound stuff */ - -#define SCI_MIDI_TIME_EXPANSION_PREFIX 0xF8 -#define SCI_MIDI_TIME_EXPANSION_LENGTH 240 - -#define SCI_MIDI_EOT 0xFC -#define SCI_MIDI_SET_SIGNAL 0xCF -#define SCI_MIDI_SET_POLYPHONY 0x4B -#define SCI_MIDI_RESET_ON_SUSPEND 0x4C -#define SCI_MIDI_CHANNEL_MUTE 0x4E -#define SCI_MIDI_SET_REVERB 0x50 -#define SCI_MIDI_HOLD 0x52 -#define SCI_MIDI_CUMULATIVE_CUE 0x60 -#define SCI_MIDI_CHANNEL_SOUND_OFF 0x78 /* all-sound-off for Bn */ -#define SCI_MIDI_CHANNEL_NOTES_OFF 0x7B /* all-notes-off for Bn */ - -#define SCI_MIDI_SET_SIGNAL_LOOP 0x7F -/* If this is the parameter of 0xCF, the loop point is set here */ - -#define SCI_MIDI_CONTROLLER(status) ((status & 0xF0) == 0xB0) - -class MidiPlayer : public MidiDriver { -protected: - MidiDriver *_driver; -public: - int open() { - ResourceManager *resMan = ((SciEngine *)g_engine)->getResourceManager(); // HACK - return open(resMan); - } - virtual int open(ResourceManager *resMan) { return _driver->open(); } - virtual void close() { _driver->close(); } - virtual void send(uint32 b) { _driver->send(b); } - uint32 getBaseTempo() { return _driver->getBaseTempo(); } - virtual bool hasRhythmChannel() const = 0; - MidiChannel *allocateChannel() { return _driver->allocateChannel(); } - MidiChannel *getPercussionChannel() { return _driver->getPercussionChannel(); } - void setTimerCallback(void *timer_param, Common::TimerManager::TimerProc timer_proc) { _driver->setTimerCallback(timer_param, timer_proc); } - - virtual int getPlayMask(SciVersion soundVersion) = 0; - virtual int getPolyphony() const = 0; - - virtual void setVolume(byte volume) { - if(_driver) - _driver->property(MIDI_PROP_MASTER_VOLUME, volume); - } - - virtual int getVolume() { - return _driver ? _driver->property(MIDI_PROP_MASTER_VOLUME, 0xffff) : 0; - } - - virtual void playSwitch(bool play) { - if (!play) { - // Send "All Sound Off" on all channels - for (int i = 0; i < MIDI_CHANNELS; ++i) - _driver->send(0xb0 + i, SCI_MIDI_CHANNEL_NOTES_OFF, 0); - } - } -}; - -extern MidiPlayer *MidiPlayer_Adlib_create(); -extern MidiPlayer *MidiPlayer_Amiga_create(); - -} // End of namespace Sci - -#endif // SCI_SFX_SOFTSEQ_MIDIDRIVER_H diff --git a/engines/sci/sfx/softseq/pcjr.cpp b/engines/sci/sfx/softseq/pcjr.cpp deleted file mode 100644 index a80a188751..0000000000 --- a/engines/sci/sfx/softseq/pcjr.cpp +++ /dev/null @@ -1,209 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -#include "sci/sfx/softseq/mididriver.h" -#include "sci/sfx/softseq/pcjr.h" - -namespace Sci { - -#define FREQUENCY 44100 -#define VOLUME_SHIFT 3 - -#define BASE_NOTE 129 // A10 -#define BASE_OCTAVE 10 // A10, as I said - -const static int freq_table[12] = { // A4 is 440Hz, halftone map is x |-> ** 2^(x/12) - 28160, // A10 - 29834, - 31608, - 33488, - 35479, - 37589, - 39824, - 42192, - 44701, - 47359, - 50175, - 53159 -}; - -static inline int get_freq(int note) { - int halftone_delta = note - BASE_NOTE; - int oct_diff = ((halftone_delta + BASE_OCTAVE * 12) / 12) - BASE_OCTAVE; - int halftone_index = (halftone_delta + (12 * 100)) % 12 ; - int freq = (!note) ? 0 : freq_table[halftone_index] / (1 << (-oct_diff)); - - return freq; -} - -void MidiDriver_PCJr::send(uint32 b) { - byte command = b & 0xff; - byte op1 = (b >> 8) & 0xff; - byte op2 = (b >> 16) & 0xff; - int i; - int mapped_chan = -1; - int chan_nr = command & 0xf; - - // First, test for channel having been assigned already - if (_channels_assigned & (1 << chan_nr)) { - // Already assigned this channel number: - for (i = 0; i < _channels_nr; i++) - if (_chan_nrs[i] == chan_nr) { - mapped_chan = i; - break; - } - } else if ((command & 0xe0) == 0x80) { - // Assign new channel round-robin - - // Mark channel as unused: - if (_chan_nrs[_channel_assigner] >= 0) - _channels_assigned &= ~(1 << _chan_nrs[_channel_assigner]); - - // Remember channel: - _chan_nrs[_channel_assigner] = chan_nr; - // Mark channel as used - _channels_assigned |= (1 << _chan_nrs[_channel_assigner]); - - // Save channel for use later in this call: - mapped_chan = _channel_assigner; - // Round-ropin iterate channel assigner: - _channel_assigner = (_channel_assigner + 1) % _channels_nr; - } - - if (mapped_chan == -1) - return; - - switch (command & 0xf0) { - - case 0x80: - if (op1 == _notes[mapped_chan]) - _notes[mapped_chan] = 0; - break; - - case 0x90: - if (!op2) { - if (op1 == _notes[mapped_chan]) - _notes[mapped_chan] = 0; - } else { - _notes[mapped_chan] = op1; - _volumes[mapped_chan] = op2; - } - break; - - case 0xb0: - if ((op1 == SCI_MIDI_CHANNEL_NOTES_OFF) || (op1 == SCI_MIDI_CHANNEL_SOUND_OFF)) - _notes[mapped_chan] = 0; - break; - - default: - debug(2, "Unused MIDI command %02x %02x %02x", command, op1, op2); - break; /* ignore */ - } -} - -void MidiDriver_PCJr::generateSamples(int16 *data, int len) { - int i; - int chan; - int freq[kMaxChannels]; - - for (chan = 0; chan < _channels_nr; chan++) - freq[chan] = get_freq(_notes[chan]); - - for (i = 0; i < len; i++) { - int16 result = 0; - - for (chan = 0; chan < _channels_nr; chan++) - if (_notes[chan]) { - int volume = (_global_volume * _volumes[chan]) - >> VOLUME_SHIFT; - - _freq_count[chan] += freq[chan]; - while (_freq_count[chan] >= (FREQUENCY << 1)) - _freq_count[chan] -= (FREQUENCY << 1); - - if (_freq_count[chan] - freq[chan] < 0) { - /* Unclean rising edge */ - int l = volume << 1; - result += -volume + (l * _freq_count[chan]) / freq[chan]; - } else if (_freq_count[chan] >= FREQUENCY - && _freq_count[chan] - freq[chan] < FREQUENCY) { - /* Unclean falling edge */ - int l = volume << 1; - result += volume - (l * (_freq_count[chan] - FREQUENCY)) / freq[chan]; - } else { - if (_freq_count[chan] < FREQUENCY) - result += volume; - else - result += -volume; - } - } - data[i] = result; - } -} - -int MidiDriver_PCJr::open(int channels) { - if (_isOpen) - return MERR_ALREADY_OPEN; - - if (channels > kMaxChannels) - return -1; - - _channels_nr = channels; - _global_volume = 100; - for (int i = 0; i < _channels_nr; i++) { - _volumes[i] = 100; - _notes[i] = 0; - _freq_count[i] = 0; - _chan_nrs[i] = -1; - } - _channel_assigner = 0; - _channels_assigned = 0; - - MidiDriver_Emulated::open(); - - _mixer->playInputStream(Audio::Mixer::kPlainSoundType, &_mixerSoundHandle, this, -1); - - return 0; -} - -void MidiDriver_PCJr::close() { - _mixer->stopHandle(_mixerSoundHandle); -} - -int MidiPlayer_PCJr::getPlayMask(SciVersion soundVersion) { - if (soundVersion == SCI_VERSION_0_EARLY) - return 0x10; // FIXME: Not correct - - return 0x10; -} - -int MidiPlayer_PCSpeaker::getPlayMask(SciVersion soundVersion) { - if (soundVersion == SCI_VERSION_0_EARLY) - return 0x02; - - return 0x20; -} - -} // End of namespace Sci diff --git a/engines/sci/sfx/softseq/pcjr.h b/engines/sci/sfx/softseq/pcjr.h deleted file mode 100644 index 60032817fd..0000000000 --- a/engines/sci/sfx/softseq/pcjr.h +++ /dev/null @@ -1,84 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -#include "sci/sfx/softseq/mididriver.h" - -namespace Sci { - -class MidiDriver_PCJr : public MidiDriver_Emulated { -public: - friend class MidiPlayer_PCJr; - - enum { - kMaxChannels = 3 - }; - - MidiDriver_PCJr(Audio::Mixer *mixer) : MidiDriver_Emulated(mixer) { } - ~MidiDriver_PCJr() { } - - // MidiDriver - int open() { return open(kMaxChannels); } - void close(); - void send(uint32 b); - MidiChannel *allocateChannel() { return NULL; } - MidiChannel *getPercussionChannel() { return NULL; } - - // AudioStream - bool isStereo() const { return false; } - int getRate() const { return _mixer->getOutputRate(); } - - // MidiDriver_Emulated - void generateSamples(int16 *buf, int len); - - int open(int channels); -private: - int _channels_nr; - int _global_volume; // Base volume - int _volumes[kMaxChannels]; - int _notes[kMaxChannels]; // Current halftone, or 0 if off - int _freq_count[kMaxChannels]; - int _channel_assigner; - int _channels_assigned; - int _chan_nrs[kMaxChannels]; -}; - -class MidiPlayer_PCJr : public MidiPlayer { -public: - MidiPlayer_PCJr() { _driver = new MidiDriver_PCJr(g_system->getMixer()); } - int open(ResourceManager *resMan) { return static_cast<MidiDriver_PCJr *>(_driver)->open(getPolyphony()); } - int getPlayMask(SciVersion soundVersion); - int getPolyphony() const { return 3; } - bool hasRhythmChannel() const { return false; } - void setVolume(byte volume) { static_cast<MidiDriver_PCJr *>(_driver)->_global_volume = volume; } -}; - -class MidiPlayer_PCSpeaker : public MidiPlayer_PCJr { -public: - int getPlayMask(SciVersion soundVersion); - int getPolyphony() const { return 1; } -}; - -} // End of namespace Sci - |