/* 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/sci_midi.h" #include "sound/fmopl.h" namespace Sci { 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) { } ~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); void loadResource(Resource *res); 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 _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 *resmgr); int getPlayMask() const { return 0x04; } int getPolyphony() const { return MidiDriver_Adlib::kVoices; } bool hasRhythmChannel() const { return false; } void setVolume(byte volume) { static_cast(_driver)->setVolume(volume); } void playSwitch(bool play) { static_cast(_driver)->playSwitch(play); } void loadInstrument(int idx, byte *data); }; } // End of namespace Sci