/* * libADLMIDI is a free Software MIDI synthesizer library with OPL3 emulation * * Original ADLMIDI code: Copyright (c) 2010-2014 Joel Yliluoma * ADLMIDI Library API: Copyright (c) 2015-2020 Vitaly Novichkov * * Library is based on the ADLMIDI, a MIDI player for Linux and Windows with OPL3 emulation: * http://iki.fi/bisqwit/source/adlmidi.html * * 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 3 of the License, or * 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, see . */ #ifndef ADLMIDI_OPL3_HPP #define ADLMIDI_OPL3_HPP #include "oplinst.h" #include "adlmidi_ptr.hpp" #include "adlmidi_private.hpp" #include "adlmidi_bankmap.h" #define BEND_COEFFICIENT 172.4387 #define OPL3_CHANNELS_MELODIC_BASE 0 #define OPL3_CHANNELS_RHYTHM_BASE 18 #define NUM_OF_CHANNELS 23 #define NUM_OF_4OP_CHANNELS 6 #define NUM_OF_2OP_CHANNELS 18 #define NUM_OF_2x2_CHANNELS 9 #define NUM_OF_RM_CHANNELS 5 /** * @brief OPL3 Chip management class */ class OPL3 { friend class MIDIplay; friend class AdlInstrumentTester; friend int adlCalculateFourOpChannels(MIDIplay *play, bool silent); public: enum { PercussionTag = 1 << 15, CustomBankTag = 0xFFFFFFFF }; //! Total number of chip channels between all running emulators uint32_t m_numChannels; //! Just a padding. Reserved. char _padding[4]; #ifndef ADLMIDI_HW_OPL //! Running chip emulators std::vector > m_chips; #endif private: //! Cached patch data, needed by Touch() std::vector m_insCache; //! Value written to B0, cached, needed by NoteOff. /*! Contains Key on/off state, octave block and frequency number values */ std::vector m_keyBlockFNumCache; //! Cached BD registry value (flags register: DeepTremolo, DeepVibrato, and RhythmMode) std::vector m_regBD; public: /** * @brief MIDI bank entry */ struct Bank { //! MIDI Bank instruments OplInstMeta ins[128]; }; typedef BasicBankMap BankMap; //! MIDI bank instruments data BankMap m_insBanks; //! MIDI bank-wide setup OplBankSetup m_insBankSetup; public: //! Blank instrument template static const OplInstMeta m_emptyInstrument; //! Total number of running concurrent emulated chips uint32_t m_numChips; //! Currently running embedded bank number. "CustomBankTag" means usign of the custom bank. uint32_t m_embeddedBank; //! Total number of needed four-operator channels in all running chips uint32_t m_numFourOps; //! Turn global Deep Tremolo mode on bool m_deepTremoloMode; //! Turn global Deep Vibrato mode on bool m_deepVibratoMode; //! Use Rhythm Mode percussions bool m_rhythmMode; //! Carriers-only are scaled by default by volume level. This flag will tell to scale modulators too. bool m_scaleModulators; //! Run emulator at PCM rate if that possible. Reduces sounding accuracy, but decreases CPU usage on lower rates. bool m_runAtPcmRate; //! Enable soft panning bool m_softPanning; //! Master volume, controlled via SysEx (0...127) uint8_t m_masterVolume; //! Just a padding. Reserved. char _padding2[3]; /** * @brief Music playing mode */ enum MusicMode { //! MIDI mode MODE_MIDI, //! AIL XMIDI mode MODE_XMIDI, //! Id-Software Music mode MODE_IMF, //! Creative Music Files mode MODE_CMF, //! EA-MUS (a.k.a. RSXX) mode MODE_RSXX } m_musicMode; /** * @brief Volume models enum */ enum VolumesScale { //! Generic volume model (linearization of logarithmic scale) VOLUME_Generic, //! OPL3 native logarithmic scale VOLUME_NATIVE, //! DMX volume scale logarithmic table VOLUME_DMX, //! Apoge Sound System volume scaling model VOLUME_APOGEE, //! Windows 9x SB16 driver volume scale table VOLUME_9X, //! DMX model with a fixed bug of AM voices VOLUME_DMX_FIXED, //! Apogee model with a fixed bug of AM voices VOLUME_APOGEE_FIXED, //! Audio Interfaces Library volume scaling model VOLUME_AIL, //! Windows 9x Generic FM driver volume scale table VOLUME_9X_GENERIC_FM, //! HMI Sound Operating System volume scale table VOLUME_HMI, //! HMI Sound Operating System volume scale model, older variant VOLUME_HMI_OLD } m_volumeScale; //! Reserved char _padding3[8]; /** * @brief Channel categiry enumeration */ enum ChanCat { //! Regular melodic/percussion channel ChanCat_Regular = 0, //! Four-op first part ChanCat_4op_First = 1, //! Four-op second part ChanCat_4op_Second = 2, //! Rhythm-mode Bass drum ChanCat_Rhythm_Bass = 3, //! Rhythm-mode Snare drum ChanCat_Rhythm_Snare = 4, //! Rhythm-mode Tom-Tom ChanCat_Rhythm_Tom = 5, //! Rhythm-mode Cymbal ChanCat_Rhythm_Cymbal = 6, //! Rhythm-mode Hi-Hat ChanCat_Rhythm_HiHat = 7, //! Rhythm-mode Secondary channel ChanCat_Rhythm_Secondary = 8 }; //! Category of the channel /*! 1 = quad-first, 2 = quad-second, 0 = regular 3 = percussion BassDrum 4 = percussion Snare 5 = percussion Tom 6 = percussion Crash cymbal 7 = percussion Hihat 8 = percussion Secondary */ std::vector m_channelCategory; /** * @brief C.O. Constructor */ OPL3(); /** * @brief C.O. Destructor */ ~OPL3(); /** * @brief Checks are setup locked to be changed on the fly or not * @return true when setup on the fly is locked */ bool setupLocked(); /** * @brief Choose one of embedded banks * @param bank ID of the bank */ void setEmbeddedBank(uint32_t bank); /** * @brief Write data to OPL3 chip register * @param chip Index of emulated chip. In hardware OPL3 builds, this parameter is ignored * @param address Register address to write * @param value Value to write */ void writeReg(size_t chip, uint16_t address, uint8_t value); /** * @brief Write data to OPL3 chip register * @param chip Index of emulated chip. In hardware OPL3 builds, this parameter is ignored * @param address Register address to write * @param value Value to write */ void writeRegI(size_t chip, uint32_t address, uint32_t value); /** * @brief Write to soft panning control of OPL3 chip emulator * @param chip Index of emulated chip. * @param address Register of channel to write * @param value Value to write */ void writePan(size_t chip, uint32_t address, uint32_t value); /** * @brief Off the note in specified chip channel * @param c Channel of chip (Emulated chip choosing by next formula: [c = ch + (chipId * 23)]) */ void noteOff(size_t c); /** * @brief On the note in specified chip channel with specified frequency of the tone * @param c1 Channel of chip [or master 4-op channel] (Emulated chip choosing by next formula: [c = ch + (chipId * 23)]) * @param c2 Second 4-op channel of chip, unused for 2op (Emulated chip choosing by next formula: [c = ch + (chipId * 23)]) * @param tone The tone to play (integer part - MIDI halftone, decimal part - relative bend offset) */ void noteOn(size_t c1, size_t c2, double tone); /** * @brief Change setup of instrument in specified chip channel * @param c Channel of chip (Emulated chip choosing by next formula: [c = ch + (chipId * 23)]) * @param velocity Note velocity (from 0 to 127) * @param channelVolume Channel volume level (from 0 to 127) * @param channelExpression Channel expression level (from 0 to 127) * @param brightness CC74 Brightness level (from 0 to 127) * @param isDrum Is this a drum note? This flag is needed for some volume model algorithms */ void touchNote(size_t c, uint_fast32_t velocity, uint_fast32_t channelVolume = 127, uint_fast32_t channelExpression = 127, uint_fast32_t brightness = 127, bool isDrum = false); /** * @brief Set the instrument into specified chip channel * @param c Channel of chip (Emulated chip choosing by next formula: [c = ch + (chipId * 23)]) * @param instrument Instrument data to set into the chip channel */ void setPatch(size_t c, const OplTimbre &instrument); /** * @brief Set panpot position * @param c Channel of chip (Emulated chip choosing by next formula: [c = ch + (chipId * 23)]) * @param value 3-bit panpot value */ void setPan(size_t c, uint8_t value); /** * @brief Shut up all chip channels */ void silenceAll(); /** * @brief Commit updated flag states to chip registers */ void updateChannelCategories(); /** * @brief commit deepTremolo and deepVibrato flags */ void commitDeepFlags(); /** * @brief Set the volume scaling model * @param volumeModel Type of volume scale model scale */ void setVolumeScaleModel(ADLMIDI_VolumeModels volumeModel); /** * @brief Get the volume scaling model */ ADLMIDI_VolumeModels getVolumeScaleModel(); #ifndef ADLMIDI_HW_OPL /** * @brief Clean up all running emulated chip instances */ void clearChips(); #endif /** * @brief Reset chip properties and initialize them * @param emulator Type of chip emulator * @param PCM_RATE Output sample rate to generate on output * @param audioTickHandler PCM-accurate clock hook */ void reset(int emulator, unsigned long PCM_RATE, void *audioTickHandler); }; /** * @brief Check emulator availability * @param emulator Emulator ID (ADL_Emulator) * @return true when emulator is available */ extern bool adl_isEmulatorAvailable(int emulator); /** * @brief Find highest emulator * @return The ADL_Emulator enum value which contains ID of highest emulator */ extern int adl_getHighestEmulator(); /** * @brief Find lowest emulator * @return The ADL_Emulator enum value which contains ID of lowest emulator */ extern int adl_getLowestEmulator(); #endif // ADLMIDI_OPL3_HPP