/* 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. * */ #ifndef AUDIO_ADLIB_MS_H #define AUDIO_ADLIB_MS_H #include "audio/mididrv_ms.h" #include "audio/fmopl.h" /** * Data for one operator of an OPL instrument definition. */ struct OplInstrumentOperatorDefinition { /** * 2x register: frequency multiplier, key scaling rate, envelope gain type, * vibrato and modulation. */ uint8 freqMultMisc; /** * 4x register: level and key scaling level. */ uint8 level; /** * 6x register: decay and attack. */ uint8 decayAttack; /** * 8x register: release and sustain. */ uint8 releaseSustain; /** * Ex register: waveform select. */ uint8 waveformSelect; }; /** * Instrument definition for an OPL2 or OPL3 chip. Contains the data for all * registers belonging to an OPL channel, except the Ax and Bx registers (these * determine the frequency and are derived from the note played). */ struct OplInstrumentDefinition { /** * Indicates if this instrument uses 2 or 4 operators. */ bool fourOperator; /** * Operator data. 2 operator instruments use operators 0 and 1 only. */ OplInstrumentOperatorDefinition operator0; OplInstrumentOperatorDefinition operator1; OplInstrumentOperatorDefinition operator2; OplInstrumentOperatorDefinition operator3; /** * Cx register: connection and feedback. * Note: panning is determined by a MIDI controller and not part of the * instrument definition. */ uint8 connectionFeedback0; /** * Second Cx register (used by 4 operator instruments). */ uint8 connectionFeedback1; /** * Notes played on a MIDI rhythm channel indicate which rhythm instrument * should be played, not which note should be played. This field indicates * the pitch (MIDI note) which should be used to play this rhythm * instrument. Not used for melodic instruments. */ uint8 rhythmNote; /** * Check if this instrument definition contains any data. * * @return True if this instrument is empty; false otherwise. */ bool isEmpty(); /** * Returns the number of operators used by this instrument definition. * * @return The number of operators (2 or 4). */ uint8 getNumberOfOperators(); /** * Returns the definition data for the operator with the specified number. * Specify 0 or 1 for 2 operator instruments or 0-3 for 4 operator * instruments. * * @param operatorNum The operator for which the data should be returned. * @return Pointer to the definition data for the specified operator. */ OplInstrumentOperatorDefinition &getOperatorDefinition(uint8 operatorNum); }; #include "common/pack-start.h" // START STRUCT PACKING /** * Data for one operator of an OPL instrument definition in the AdLib BNK * format. */ struct AdLibBnkInstrumentOperatorDefinition { /** * Individual fields for each setting in the 2x-8x registers. * Note that waveform select is not part of the operator data in this * format; it is included in the instrument data as a separate field. */ uint8 keyScalingLevel; uint8 frequencyMultiplier; uint8 feedback; // ignored for operator 1 uint8 attack; uint8 sustain; uint8 envelopeGainType; // 0x00: not sustained, >= 0x01: sustained uint8 decay; uint8 release; uint8 level; uint8 amplitudeModulation; // 0x00: off, >= 0x01: on uint8 vibrato; // 0x00: off, >= 0x01: on uint8 keyScalingRate; // 0x00: low, >= 0x01: high uint8 connection; // 0x00: additive, >= 0x01: FM; ignored for operator 1 /** * Copies the data in this AdLib BNK operator definition to the specified * OplInstrumentOperatorDefinition struct. * * @param operatorDef The operator definition to which the data should be * copied. * @param waveformSelect The value of the waveform select parameter for * this operator. */ void toOplInstrumentOperatorDefinition(OplInstrumentOperatorDefinition &operatorDef, uint8 waveformSelect); } PACKED_STRUCT; /** * Instrument definition for an OPL2 chip in the format used by the AdLib BNK * instrument bank file format. */ struct AdLibBnkInstrumentDefinition { /** * The type of instrument (0x00: melodic, 0x01: rhythm). */ uint8 instrumentType; /** * TODO Unclear what this represents; might be the same as rhythmNote. */ uint8 rhythmVoiceNumber; /** * Operator data. */ AdLibBnkInstrumentOperatorDefinition operator0; AdLibBnkInstrumentOperatorDefinition operator1; /** * Waveform select parameter for each operator. */ uint8 waveformSelect0; uint8 waveformSelect1; /** * Copies the data in this AdLib BNK instrument definition to the specified * OplInstrumentDefinition struct. * * @param instrumentDef The instrument definition to which the data should * be copied. */ void toOplInstrumentDefinition(OplInstrumentDefinition &instrumentDef); } PACKED_STRUCT; #include "common/pack-end.h" // END STRUCT PACKING /** * MIDI driver for AdLib / OPL2 and OPL3 emulators and devices with support for * multiple simultaneous sources of MIDI data. * * This driver converts MIDI events to OPL chip register writes. When opened it * will initialize an OPL emulator or device using the specified OPL type. It * tracks the MIDI state of each source separately to avoid conflicts. * The default behavior of the driver plays General MIDI data with the same * output as the SoudBlaster 16 Windows 95 driver. It can be subclassed and * customized to match the specific behavior of a game. * * Customization * * Depending on the platform and the type of music data the game uses, you can * customize the driver to match this behavior: * - Windows: If the game uses the standard Windows APIs to play General MIDI * data, the default behavior of the driver should give identical output. * - DOS, General MIDI: The default behavior of the driver should give you a * decent starting point, but because there is no standard way to handle GM * on OPL chips in DOS, it is probably not accurate. The instruments used by * the game can be set in the _instrumentBank and _rhythmBank fields. * You can subclass the driver to override more behavior, such as the * calculateFrequency, calculatePitchBend, calculateUnscaledVolume and * allocateOplChannel functions. * - DOS, other type of MIDI: Additionally, you will need to override the * functions that handle the various MIDI events and controllers when they do * not match the General MIDI standard. You can override determineInstrument * if the game uses some other way than instrument banks to set instruments. * - DOS, does not use MIDI: Write new code to access the OPL registers * directly instead of using this driver. * * TODO Dual OPL2 and 4 operator instrument support is unfinished. */ class MidiDriver_ADLIB_Multisource : public MidiDriver_Multisource { public: /** * The available accuracy modes for frequency and volume calculation. */ enum AccuracyMode { /** * Accurate to the behavior of the Windows 95 SB16 driver. */ ACCURACY_MODE_SB16_WIN95, /** * Accurate to the General MIDI and MIDI specifications. */ ACCURACY_MODE_GM }; /** * The available modes for OPL channel allocation. */ enum ChannelAllocationMode { /** * Dynamic channel allocation (new OPL channel allocated to each note * played). */ ALLOCATION_MODE_DYNAMIC, /** * Static channel allocation (fixed OPL channel allocated to each MIDI * channel). */ ALLOCATION_MODE_STATIC }; /** * The available modes for the OPL note select setting. */ enum NoteSelectMode { NOTE_SELECT_MODE_0, NOTE_SELECT_MODE_1 }; /** * The available modes for the OPL modulation depth setting. */ enum ModulationDepth { /** * Low modulation depth (1 dB). */ MODULATION_DEPTH_LOW, /** * High modulation depth (4.8 dB). */ MODULATION_DEPTH_HIGH }; /** * The available modes for the OPL vibrato depth setting. */ enum VibratoDepth { /** * Low vibrato depth (7 %). */ VIBRATO_DEPTH_LOW, /** * High vibrato depth (14 %). */ VIBRATO_DEPTH_HIGH }; /** * The number of available channels on each OPL chip. */ static const uint8 OPL2_NUM_CHANNELS = 9; static const uint8 OPL3_NUM_CHANNELS = 18; /** * OPL test and timer registers. */ static const uint8 OPL_REGISTER_TEST = 0x01; static const uint8 OPL_REGISTER_TIMER1 = 0x02; static const uint8 OPL_REGISTER_TIMER2 = 0x03; static const uint8 OPL_REGISTER_TIMERCONTROL = 0x04; /** * OPL global setting registers. */ static const uint8 OPL_REGISTER_NOTESELECT_CSM = 0x08; static const uint8 OPL_REGISTER_RHYTHM = 0xBD; /** * OPL operator base registers. */ static const uint8 OPL_REGISTER_BASE_FREQMULT_MISC = 0x20; static const uint8 OPL_REGISTER_BASE_LEVEL = 0x40; static const uint8 OPL_REGISTER_BASE_DECAY_ATTACK = 0x60; static const uint8 OPL_REGISTER_BASE_RELEASE_SUSTAIN = 0x80; static const uint8 OPL_REGISTER_BASE_WAVEFORMSELECT = 0xE0; /** * OPL channel base registers. */ static const uint8 OPL_REGISTER_BASE_FNUMLOW = 0xA0; static const uint8 OPL_REGISTER_BASE_FNUMHIGH_BLOCK_KEYON = 0xB0; static const uint8 OPL_REGISTER_BASE_CONNECTION_FEEDBACK_PANNING = 0xC0; /** * OPL3-specific global setting registers. */ static const uint16 OPL3_REGISTER_CONNECTIONSELECT = 0x104; static const uint16 OPL3_REGISTER_NEW = 0x105; /** * Offset to the second register set (for dual OPL2 and OPL3). */ static const uint16 OPL_REGISTER_SET_2_OFFSET = 0x100; /** * Bitmasks for various parameters in the OPL registers. */ static const uint8 OPL_MASK_LEVEL = 0x3F; static const uint8 OPL_MASK_FNUMHIGH_BLOCK = 0x1F; static const uint8 OPL_MASK_KEYON = 0x20; static const uint8 OPL_MASK_PANNING = 0x30; /** * Settings for the panning bits in the OPL Cx registers. */ static const uint8 OPL_PANNING_CENTER = 0x30; static const uint8 OPL_PANNING_LEFT = 0x10; static const uint8 OPL_PANNING_RIGHT = 0x20; /** * The default melodic instrument definitions. */ static OplInstrumentDefinition OPL_INSTRUMENT_BANK[]; /** * The default rhythm instrument definitions. */ static OplInstrumentDefinition OPL_RHYTHM_BANK[]; protected: /** * Default setting for OPL channel volume (level). */ static const uint8 OPL_LEVEL_DEFAULT = 0x3F; /** * The lowest MIDI panning controller value interpreted as left panning. */ static const uint8 OPL_MIDI_PANNING_LEFT_LIMIT = 0x2F; /** * The highest MIDI panning controller value interpreted as right panning. */ static const uint8 OPL_MIDI_PANNING_RIGHT_LIMIT = 0x51; /** * OPL frequency (F-num) value for each octave semitone. The values assume * octave 5. */ static const uint16 OPL_NOTE_FREQUENCIES[]; /** * OPL volume lookup array for a MIDI volume value shifted from 7 to 5 bits. */ static const uint8 OPL_VOLUME_LOOKUP[]; /** * Contains the current controller settings for a MIDI channel. */ struct MidiChannelControlData { uint8 program; uint8 channelPressure; uint16 pitchBend; // 14 bit value; 0x2000 is neutral uint8 modulation; uint8 volume; uint8 panning; // 0x40 is center uint8 expression; bool sustain; uint16 rpn; // Two 7 bit values stored in 8 bits each uint8 pitchBendSensitivity; // Semitones uint8 pitchBendSensitivityCents; uint16 masterTuningFine; // 14 bit value; 0x2000 is neutral uint8 masterTuningCoarse; // Semitones; 0x40 is neutral MidiChannelControlData(); /** * Initializes the controller settings to default values. */ void init(); }; /** * Contains information on the currently active note on an OPL channel. */ struct ActiveNote { /** * True if a note is currently playing (including if it is sustained, * but not if it is in the "release" phase). */ bool noteActive; /** * True if the currently playing note is sustained, i.e. note has been * turned off but is kept active due to the sustain controller. */ bool noteSustained; /** * The MIDI note value as it appeared in the note on event. */ uint8 note; /** * The MIDI velocity value of the note on event. */ uint8 velocity; /** * The MIDI channel that played the current/last note (0xFF if no note * has been played since initialization). */ uint8 channel; /** * The source that played the current/last note (0xFF if no note has * been played since initialization). */ uint8 source; /** * The MIDI note value that is actually played. This is the same as the * note field for melodic instruments, but on the MIDI rhythm channel * the note indicates which rhythm instrument should be played instead * of the pitch. In that case this field is different * (@see determineInstrument). */ uint8 oplNote; /** * The OPL frequency (F-num) and octave (block) (in Ax (low byte) and * Bx (high byte) register format) that was calculated to play the MIDI * note. */ uint16 oplFrequency; /** * The value of the note counter when a note was last turned on or off * on this OPL channel. */ uint32 noteCounterValue; /** * A unique identifier of the instrument that is used to play the note. * In the default implementation this is the MIDI program number for * melodic instruments and the rhythm channel note number + 0x80 for * rhythm instruments (@see determineInstrument). */ uint8 instrumentId; /** * Pointer to the instrument definition used to play the note. */ OplInstrumentDefinition *instrumentDef; /** * True if this OPL channel has been allocated to a MIDI channel. * Note that in the default driver implementation only the static * channel allocation algorithm uses this field. */ bool channelAllocated; ActiveNote(); /** * Initializes the active note data to default values. */ void init(); }; /** * OPL instrument data for playing a note. */ struct InstrumentInfo { /** * MIDI note value to use for playing this instrument * (@see ActiveNote.oplNote). */ uint8 oplNote; /** * Pointer to the instrument definition. */ OplInstrumentDefinition *instrumentDef; /** * Unique identifer for this instrument (@see ActiveNote.instrumentId). */ uint8 instrumentId; }; public: /** * Checks if the specified type of OPL chip is supported by the OPL * emulator or hardware that is used. * * @param oplType The type of OPL chip that should be detected. * @return True if the specified type of OPL chip is supported by the OPL * emulator/hardware; false otherwise. */ static bool detectOplType(OPL::Config::OplType oplType); /** * Constructs a new AdLib multisource MIDI driver using the specified type * of OPL chip. * * @param oplType The type of OPL chip that should be used. */ MidiDriver_ADLIB_Multisource(OPL::Config::OplType oplType); ~MidiDriver_ADLIB_Multisource(); /** * Prepares the driver for processing MIDI data and initializes the OPL * emulator or hardware. * * @return 0 if the driver was opened successfully; a MidiDriver error code * otherwise. */ int open() override; bool isOpen() const override; void close() override; uint32 property(int prop, uint32 param) override; uint32 getBaseTempo() override; /** * This driver does not use MidiChannel objects, so this function returns 0. * * @return 0 */ MidiChannel *allocateChannel() override; /** * This driver does not use MidiChannel objects, so this function returns 0. * * @return 0 */ MidiChannel *getPercussionChannel() override; void send(int8 source, uint32 b) override; void sysEx(const byte *msg, uint16 length) override; void metaEvent(int8 source, byte type, byte *data, uint16 length) override; void stopAllNotes(bool stopSustainedNotes = false) override; void stopAllNotes(uint8 source, uint8 channel) override; void deinitSource(uint8 source) override; protected: void applySourceVolume(uint8 source) override; /** * Initializes the OPL registers to their default values. */ virtual void initOpl(); /** * Processes a MIDI note off event. * * @param channel The MIDI channel on which the note is active. * @param note The MIDI note that should be turned off. * @param velocity The release velocity (not implemented). * @param source The source sending the note off event. */ virtual void noteOff(uint8 channel, uint8 note, uint8 velocity, uint8 source); /** * Processes a MIDI note on event. * * @param channel The MIDI channel on which the note is played. * @param note The MIDI note that should be turned on. * @param velocity The MIDI velocity of the played note. * @param source The source sending the note on event. */ virtual void noteOn(uint8 channel, uint8 note, uint8 velocity, uint8 source); /** * Processes a MIDI polyphonic aftertouch event. * Note: this event has no default implementation because it is not * implemented in the Win95 SB16 driver. * * @param channel The MIDI channel on which the event is sent. * @param note The MIDI note on which aftertouch should be applied. * @param pressure The aftertouch amount that should be applied. * @param source The source sending the aftertouch event. */ virtual void polyAftertouch(uint8 channel, uint8 note, uint8 pressure, uint8 source); /** * Processes a MIDI control change event. The individual controllers are * handled by separate functions (@see modulation etc.). * * @param channel The MIDI channel on which the event is sent. * @param controller The MIDI controller whose value should be changed. * @param value The value that should be applied to the controller. * @param source The source sending the conrol change event. */ virtual void controlChange(uint8 channel, uint8 controller, uint8 value, uint8 source); /** * Processes a MIDI program (instrument) change event. * * @param channel The MIDI channel on which the instrument should be set. * @param program The instrument that should be set on the channel. * @param source The source sending the program change event. */ virtual void programChange(uint8 channel, uint8 program, uint8 source); /** * Processes a MIDI channel aftertouch event. * Note: this event has no default implementation because it is not * implemented in the Win95 SB16 driver. * * @param channel The MIDI channel on which aftertouch should be applied. * @param pressure The aftertouch amount that should be applied. * @param source The source sending the aftertouch event. */ virtual void channelAftertouch(uint8 channel, uint8 pressure, uint8 source); /** * Processes a MIDI pitch bend event. * Note that MIDI pitch bend is a 14 bit value sent as 2 7 bit values, with * the LSB sent first. * * @param channel The MIDI channel on which pitch bend should be applied. * @param pitchBendLsb The LSB of the pitch bend value. * @param pitchBendMsb The MSB of the pitch bend value. * @param source The source sending the pitch bend event. */ virtual void pitchBend(uint8 channel, uint8 pitchBendLsb, uint8 pitchBendMsb, uint8 source); /** * Processes a MIDI modulation control change event. * Note: this event has no default implementation because it is not * implemented in the Win95 SB16 driver. * * @param channel The MIDI channel on which modulation should be applied. * @param modulation The modulation amount that should be applied. * @param source The source sending the control change event. */ virtual void modulation(uint8 channel, uint8 modulation, uint8 source); /** * Processes a MIDI data entry control change event. This sets the MSB * and/or LSB of the currently selected registered parameter number. * Note that a MIDI data entry event contains either the MSB or LSB; * specify 0xFF for the other data byte to leave it unchanged. * RPNs pitch bend sensitivity, master tuning fine and coarse are supported * in accuracy mode GM only. * * @param channel The MIDI channel on which the RPN data byte should be set. * @param dataMsb The MSB of the RPN data value; 0xFF to not set the MSB. * @param dataLsb The LSB of the RPN data value; 0xFF to not set the LSB. * @param source The source sending the control change event. */ virtual void dataEntry(uint8 channel, uint8 dataMsb, uint8 dataLsb, uint8 source); /** * Process a MIDI volume control change event. * * @param channel The MIDI channel on which volume should be set. * @param volume The volume level that should be set. * @param source The source sending the control change event. */ virtual void volume(uint8 channel, uint8 volume, uint8 source); /** * Process a MIDI panning control change event. * Note that panning is not supported on an OPL2 chip because it has mono * output. * * @param channel The MIDI channel on which panning should be set. * @param panning The panning value that should be set. * @param source The source sending the control change event. */ virtual void panning(uint8 channel, uint8 panning, uint8 source); /** * Process a MIDI expression control change event. * * @param channel The MIDI channel on which expression should be set. * @param expression The expression value that should be set. * @param source The source sending the control change event. */ virtual void expression(uint8 channel, uint8 expression, uint8 source); /** * Process a MIDI sustain control change event. * * @param channel The MIDI channel on which sustain should be set. * @param sustain The sustain value that should be set. * @param source The source sending the control change event. */ virtual void sustain(uint8 channel, uint8 sustain, uint8 source); /** * Process a MIDI registered parameter number control change event. This * sets the currently active RPN; subsequent data entry control change * events will set the value for the selected RPN. * Note that a MIDI PRN event contains either the MSB or LSB; specify 0xFF * for the other rpn byte to leave it unchanged. * RPNs pitch bend sensitivity, master tuning fine and coarse are supported * in accuracy mode GM only. * * @param channel The MIDI channel on which the active PRN should be set. * @param rpnMsb The MSB of the RPN number; 0xFF to not set the MSB. * @param rpnLsb The LSB of the RPN number; 0xFF to not set the LSB. * @param source The source sending the control change event. */ virtual void registeredParameterNumber(uint8 channel, uint8 rpnMsb, uint8 rpnLsb, uint8 source); /** * Process a MIDI all sound off channel mode event. * Note that this should immediately stop all sound, but it is not possible * to abort the "release" phase of a note on an OPL chip. So this will * function like an all notes off event, except it will also stop sustained * notes. * * @param channel The MIDI channel on which the all sound off channel mode * event is sent. * @param source The source sending the control change event. */ virtual void allSoundOff(uint8 channel, uint8 source); /** * Process a MIDI reset all controllers channel mode event. This will reset * the following controllers to their default values: * - modulation * - expression * - sustain * - active RPN * - pitch bend * - channel aftertouch * It should also reset polyphonic aftertouch, but this is not implemented. * * @param channel The MIDI channel on which the reset all controllers * channel mode event is sent. * @param source The source sending the control change event. */ virtual void resetAllControllers(uint8 channel, uint8 source); /** * Process a MIDI all notes off channel mode event. This will turn off all * non-sustained notes or sustain all notes if the sustain controller is on. * * @param channel The MIDI channel on which the all notes off channel mode * event is sent. * @param source The source sending the control change event. */ virtual void allNotesOff(uint8 channel, uint8 source); /** * Recalculates and writes the frequencies of the active notes on the * specified MIDI channel and source. * * @param channel The MIDI channel on which the note frequencies should be * recalculated. * @param source The source for which the note frequencies should be * recalculated. */ virtual void recalculateFrequencies(uint8 channel, uint8 source); /** * Recalculates and writes the volumes of the active notes on the specified * MIDI channel and source. 0xFF can be specified to recalculate volumes of * notes on all MIDI channels and/or sources. * * @param channel The MIDI channel on which the note volumes should be * recalculated; 0xFF to recalculate volumes for all channels. * @param source The source for which the note volumes should be * recalculated; 0xFF to recalculate volumes for all sources. */ virtual void recalculateVolumes(uint8 channel, uint8 source); /** * Determines the instrument data necessary to play the specified note on * the specified MIDI channel and source. This will determine the * instrument definition to use, the note that should be played and an * instrument ID for use by the dynamic channel allocation algorithm. * * @param channel The MIDI channel on which the note is played. * @param source The source playing the note. * @param note The MIDI note which is played. * @return The instrument data for playing the note, or an empty struct if * the note cannot be played. */ virtual InstrumentInfo determineInstrument(uint8 channel, uint8 source, uint8 note); /** * Allocates an OPL channel to play a note on the specified MIDI channel * and source with the specified instrument ID. Allocation behavior depends * on the active channel allocation mode: * - Dynamic: allocates an unused channel, a channel playing a note using * the same instrument or the channel playing the oldest note. This will * always allocate a channel to play the note. This is the same behavior * as the Win95 SB16 driver. * - Static: allocates an unused OPL channel and assigns it to the MIDI * channel playing the note. All subsequent notes on this MIDI channel * will be played using this OPL channel. If there are no free channels, * it will fail to allocate a channel. The MIDI data must play one note * at a time on each channel and not use more MIDI channels than there * are OPL channels for this algorithm to work properly. * * @param channel The MIDI channel on which the note is played. * @param source The source playing the note. * @param instrumentId The ID of the instrument playing the note. Not used * by the static channel allocation mode. * @return The number of the allocated OPL channel; 0xFF if allocation * failed (not possible using the dynamic channel allocation mode). */ virtual uint8 allocateOplChannel(uint8 channel, uint8 source, uint8 instrumentId); /** * Calculates the OPL frequency (F-num) and octave (block) to play the * specified note on the specified MIDI channel and source, taking into * account the MIDI controllers pitch bend and (on accuracy mode GM) pitch * bend sensitivity and master tuning. The result is returned in the format * of the Ax (low byte) and Bx (high byte) OPL registers. * Note that the MIDI note range exceeds the frequency range of an OPL * chip, so the highest MIDI notes will be shifted down one or two octaves. * The SB16 Win95 accuracy mode calculates the same frequencies as the * Windows 95 SB16 driver. The GM accuracy mode is more accurate, but the * calculations are more CPU intensive. This mode also supports pitch bend * sensitivity (which is fixed at 2 semitones in SB16 Win95 mode) and * master tuning. * * @param channel The MIDI channel on which the note is played. * @param source The source playing the note. * @param note The MIDI note which is played. * @return The F-num and block to play the note on the OPL chip. */ virtual uint16 calculateFrequency(uint8 channel, uint8 source, uint8 note); /** * Calculates the pitch bend value to apply to the specified OPL frequency * (F-num) on the specified MIDI channel and source. If the accuracy mode * is GM, pitch bend sensitivity and master tuning settings are also * applied. The result is an adjustment which can be added to the OPL * frequency to get the pitch bent note. * * @param channel The MIDI channel for which pitch bend should be * calculated. * @param source The source for which pitch bend should be calculated. * @param oplFrequency The OPL frequency for which pitch bend should be * calculated. * @return The calculated pitch bend (OPL frequency adjustment). */ virtual int32 calculatePitchBend(uint8 channel, uint8 source, uint16 oplFrequency); /** * Calculates the volume for the specified operator of a note on the * specified MIDI channel and source, using the specified MIDI velocity and * instrument definition. * This function will check if the operator will need to have volume * applied to it or if the operator volume from the instrument definition * should be used without adjustment (this depends on the connection type). * If volume should be applied, unscaled volume is calculated * (@see calculateUnscaledVolume) and volume is scaled to source and user * volume. The volume is returned as an OPL 2x register volume (level) * value, i.e. 0 = maximum volume, 3F = minimum volume. * * @param channel The MIDI channel on which the note is played. * @param source The source playing the note. * @param velocity The MIDI velocity of the note for which volume should be * calculated. * @param instrumentDef The instrument definition used to play the note. * @param operatorNum The number of the operator for which volume should be * calculated; 0-1 for 2 operator instruments, 0-3 for 4 operator * instruments. * @return The calculated operator volume (level). */ virtual uint8 calculateVolume(uint8 channel, uint8 source, uint8 velocity, OplInstrumentDefinition &instrumentDef, uint8 operatorNum); /** * Calculates the unscaled volume for the specified operator of a note on * the specified MIDI channel and source, using the specified MIDI velocity * and instrument definition. * The SB16 Win95 accuracy mode calculates the same values as the Windows * 95 SB16 driver. The GM accuracy mode is more accurate to the volume * curve in the General MIDI specification and supports the expression * controller, but the calculation is more CPU intensive. * The volume is returned as an OPL 2x register volume (level) value, * i.e. 0 = maximum volume, 3F = minimum volume. * * @param channel The MIDI channel on which the note is played. * @param source The source playing the note. * @param velocity The MIDI velocity of the note for which volume should be * calculated. * @param instrumentDef The instrument definition used to play the note. * @param operatorNum The number of the operator for which volume should be * calculated; 0-1 for 2 operator instruments, 0-3 for 4 operator * instruments. * @return The calculated unscaled operator volume (level). */ virtual uint8 calculateUnscaledVolume(uint8 channel, uint8 source, uint8 velocity, OplInstrumentDefinition &instrumentDef, uint8 operatorNum); /** * Determines the panning that should be applied to notes played on the * specified MIDI channel and source. * This will convert the MIDI panning controller value to simple left, * right and center panning and return the result as a Cx register panning * value (in bits 4 and 5) for an OPL3 chip. * * @param channel The MIDI channel for which panning should be calculated. * @param source The source for which panning should be calculated. * @return The calculated panning. */ virtual uint8 calculatePanning(uint8 channel, uint8 source); /** * Determines the number of channels available on the OPL chip used by the * driver. * * @return The number of OPL channels (9 or 18). */ uint8 determineNumOplChannels(); /** * Determines the offset from a base register for the specified operator of * the specified OPL channel. * Add the offset to the base register to get the correct register for this * operator and channel. * * @param oplChannel The OPL channel for which to determine the offset. * @param operatorNum The operator for which to determine the offset; * 0-1 for 2 operator instruments, 0-3 for 4 operator instruments. * @param fourOperator True if the instrument used is a 4 operator * instrument; false if it is a 2 operator instrument. * @return The offset to the base register for this operator. */ uint16 determineOperatorRegisterOffset(uint8 oplChannel, uint8 operatorNum, bool fourOperator = false); /** * Determines the offset from a base register for the specified OPL channel. * Add the offset to the base register to get the correct register for this * channel. * * @param oplChannel The OPL channel for which to determine the offset. * @param fourOperator True if the instrument used is a 4 operator * instrument; false if it is a 2 operator instrument. * @return The offset to the base register for this channel. */ uint16 determineChannelRegisterOffset(uint8 oplChannel, bool fourOperator = false); /** * Sets the key on bit to false on the specified OPL channel and updates * _activeNotes with the new status. * Specify forceWrite to force the OPL register to be written, even if the * key on bit is already false according to the shadow registers. * * @param oplChannel The OPL channel on which the key on bit should be set * to false. * @param forceWrite True if the OPL register write should be forced; false * otherwise. */ void writeKeyOff(uint8 oplChannel, bool forceWrite = false); /** * Calculates the volume for the specified OPL channel and operator * (@see calculateVolume) and writes the new value to the OPL registers. * * @param oplChannel The OPL channel for which volume should be calculated * and written. * @param operatorNum The operator for which volume should be calculated * and written. */ void writeVolume(uint8 oplChannel, uint8 operatorNum); /** * Calculates the panning for the specified OPL channel * (@see calculatePanning) and writes the new value to the OPL registers. * * @param oplChannel The OPL channel for which panning should be calculated * and written. */ void writePanning(uint8 oplChannel); /** * Calculates the frequency for the active note on the specified OPL * channel (@see calculateFrequency) and writes the new value to the OPL * registers. * * @param oplChannel The OPL channel for which the frequency should be * calculated and written. */ void writeFrequency(uint8 oplChannel); /** * Writes the specified value to the specified OPL register. * If the specified value is the same as the current value according to the * shadow registers, the value is not written unless forceWrite is * specified. * * @param reg The OPL register where the value should be written * (>= 0x100 for the second register set). * @param value The value to write in the register. * @param forceWrite True if the register write should be forced; false * otherwise. */ void writeRegister(uint16 reg, uint8 value, bool forceWrite = false); // The type of OPL chip to use. OPL::Config::OplType _oplType; // The OPL emulator / hardware interface. OPL::OPL *_opl; // True if the driver has been successfully opened. bool _isOpen; // Controls the behavior for calculating note frequency and volume. AccuracyMode _accuracyMode; // Controls the OPL channel allocation behavior. ChannelAllocationMode _allocationMode; // OPL global settings. Set these, then call oplInit or open to apply the // new values. NoteSelectMode _noteSelect; ModulationDepth _modulationDepth; VibratoDepth _vibratoDepth; // Pointer to the melodic instrument definitions. OplInstrumentDefinition *_instrumentBank; // Pointer to the rhythm instrument definitions. OplInstrumentDefinition *_rhythmBank; // The MIDI note value of the first rhythm instrument in the bank. uint8 _rhythmBankFirstNote; // The MIDI note value of the last rhythm instrument in the bank. uint8 _rhythmBankLastNote; // The current MIDI controller values for each MIDI channel and source. MidiChannelControlData _controlData[MAXIMUM_SOURCES][MIDI_CHANNEL_COUNT]; // The active note data for each OPL channel. ActiveNote _activeNotes[OPL3_NUM_CHANNELS]; // The OPL channel allocated to each MIDI channel and source; 0xFF if a // MIDI channel has no OPL channel allocated. Note that this is only used by // the static channel allocation mode. uint8 _channelAllocations[MAXIMUM_SOURCES][MIDI_CHANNEL_COUNT]; // The amount of notes played since the driver was opened / reset. uint32 _noteCounter; // Factor to convert a frequency in Hertz to the format used by the OPL // registers (F - num). float _oplFrequencyConversionFactor; // The values last written to each OPL register. uint8 _shadowRegisters[0x200]; Common::Mutex _allocationMutex; // For operations on channel allocations Common::Mutex _activeNotesMutex; // For operations on active notes }; #endif