diff options
-rw-r--r-- | src/adlmidi_opl3.cpp | 12 | ||||
-rw-r--r-- | src/adlmidi_opl3.hpp | 326 | ||||
-rw-r--r-- | src/adlmidi_private.hpp | 292 |
3 files changed, 339 insertions, 291 deletions
diff --git a/src/adlmidi_opl3.cpp b/src/adlmidi_opl3.cpp index f3672d3..0f977e2 100644 --- a/src/adlmidi_opl3.cpp +++ b/src/adlmidi_opl3.cpp @@ -21,6 +21,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ +#include "adlmidi_opl3.hpp" #include "adlmidi_private.hpp" #include <stdlib.h> #include <cassert> @@ -148,6 +149,13 @@ static const uint16_t g_channelsMap[23] = Ports: ??? */ +enum +{ + OPL_PANNING_LEFT = 0x10, + OPL_PANNING_RIGHT = 0x20, + OPL_PANNING_BOTH = 0x30 +}; + static adlinsdata2 makeEmptyInstrument() { adlinsdata2 ins; @@ -181,6 +189,10 @@ OPL3::OPL3() : #endif } +OPL3::~OPL3() +{ +} + bool OPL3::setupLocked() { return (m_musicMode == MODE_CMF || diff --git a/src/adlmidi_opl3.hpp b/src/adlmidi_opl3.hpp new file mode 100644 index 0000000..7282de4 --- /dev/null +++ b/src/adlmidi_opl3.hpp @@ -0,0 +1,326 @@ +/* + * libADLMIDI is a free MIDI to WAV conversion library with OPL3 emulation + * + * Original ADLMIDI code: Copyright (c) 2010-2014 Joel Yliluoma <bisqwit@iki.fi> + * ADLMIDI Library API: Copyright (c) 2015-2018 Vitaly Novichkov <admin@wohlnet.ru> + * + * 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 <http://www.gnu.org/licenses/>. + */ + +#ifndef ADLMIDI_OPL3_HPP +#define ADLMIDI_OPL3_HPP + +#include "adldata.hh" +#include "adlmidi_ptr.hpp" +#include "adlmidi_bankmap.h" +#include "adlmidi.h" +#include <vector> +#include <stdint.h> + +class MIDIplay; +class OPLChipBase; + +/** + * @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<AdlMIDI_SPtr<OPLChipBase > > m_chips; +#endif + +private: + //! Cached patch data, needed by Touch() + std::vector<adldata> m_insCache; + //! Value written to B0, cached, needed by NoteOff. + /*! Contains Key on/off state, octave block and frequency number values + */ + std::vector<uint32_t> m_keyBlockFNumCache; + //! Cached BD registry value (flags register: DeepTremolo, DeepVibrato, and RhythmMode) + std::vector<uint32_t> m_regBD; + +public: + /** + * @brief MIDI bank entry + */ + struct Bank + { + //! MIDI Bank instruments + adlinsdata2 ins[128]; + }; + typedef BasicBankMap<Bank> BankMap; + //! MIDI bank instruments data + BankMap m_insBanks; + //! MIDI bank-wide setup + AdlBankSetup m_insBankSetup; + +public: + //! Blank instrument template + static const adlinsdata2 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; + + //! Just a padding. Reserved. + char _padding2[3]; + + /** + * @brief Music playing mode + */ + enum MusicMode + { + //! MIDI mode + MODE_MIDI, + //! 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 driver volume scale table + VOLUME_9X + } m_volumeScale; + + //! Reserved + char _padding3[8]; + + /** + * @brief Channel categiry enumeration + */ + enum ChanCat + { + //! Regular melodic/percussion channel + ChanCat_Regular = 0, + //! Four-op master + ChanCat_4op_Master = 1, + //! Four-op slave + ChanCat_4op_Slave = 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 Slave channel + ChanCat_Rhythm_Slave = 8 + }; + + //! Category of the channel + /*! 1 = quad-master, 2 = quad-slave, 0 = regular + 3 = percussion BassDrum + 4 = percussion Snare + 5 = percussion Tom + 6 = percussion Crash cymbal + 7 = percussion Hihat + 8 = percussion slave + */ + std::vector<uint32_t> 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 Slave 4-op channel of chip, unused for 2op (Emulated chip choosing by next formula: [c = ch + (chipId * 23)]) + * @param hertz Frequency of the tone in hertzes + */ + void noteOn(size_t c1, size_t c2, double hertz); + + /** + * @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 volume Volume level (from 0 to 63) + * @param brightness CC74 Brightness level (from 0 to 127) + */ + void touchNote(size_t c, uint8_t volume, uint8_t brightness = 127); + + /** + * @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 adldata &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 diff --git a/src/adlmidi_private.hpp b/src/adlmidi_private.hpp index 59ba555..95e6ea9 100644 --- a/src/adlmidi_private.hpp +++ b/src/adlmidi_private.hpp @@ -153,14 +153,10 @@ typedef BW_MidiSequencer MidiSequencer; #endif #include "adlmidi_ptr.hpp" -#include "adlmidi_bankmap.h" +#include "adlmidi_opl3.hpp" #define ADL_UNUSED(x) (void)x -#define OPL_PANNING_LEFT 0x10 -#define OPL_PANNING_RIGHT 0x20 -#define OPL_PANNING_BOTH 0x30 - #ifdef ADLMIDI_HW_OPL #define ADL_MAX_CHIPS 1 #define ADL_MAX_CHIPS_STR "1" //Why not just "#MaxCards" ? Watcom fails to pass this with "syntax error" :-P @@ -218,273 +214,6 @@ inline int32_t adl_cvtU32(int32_t x) return (uint32_t)adl_cvtS32(x) - (uint32_t)INT32_MIN; } -struct ADL_MIDIPlayer; -class MIDIplay; -/** - * @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<AdlMIDI_SPtr<OPLChipBase > > m_chips; -#endif - -private: - //! Cached patch data, needed by Touch() - std::vector<adldata> m_insCache; - //! Value written to B0, cached, needed by NoteOff. - /*! Contains Key on/off state, octave block and frequency number values - */ - std::vector<uint32_t> m_keyBlockFNumCache; - //! Cached BD registry value (flags register: DeepTremolo, DeepVibrato, and RhythmMode) - std::vector<uint32_t> m_regBD; - -public: - /** - * @brief MIDI bank entry - */ - struct Bank - { - //! MIDI Bank instruments - adlinsdata2 ins[128]; - }; - typedef BasicBankMap<Bank> BankMap; - //! MIDI bank instruments data - BankMap m_insBanks; - //! MIDI bank-wide setup - AdlBankSetup m_insBankSetup; - -public: - //! Blank instrument template - static const adlinsdata2 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; - - //! Just a padding. Reserved. - char _padding2[3]; - - /** - * @brief Music playing mode - */ - enum MusicMode - { - //! MIDI mode - MODE_MIDI, - //! 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 driver volume scale table - VOLUME_9X - } m_volumeScale; - - //! Reserved - char _padding3[8]; - - /** - * @brief Channel categiry enumeration - */ - enum ChanCat - { - //! Regular melodic/percussion channel - ChanCat_Regular = 0, - //! Four-op master - ChanCat_4op_Master = 1, - //! Four-op slave - ChanCat_4op_Slave = 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 Slave channel - ChanCat_Rhythm_Slave = 8 - }; - - //! Category of the channel - /*! 1 = quad-master, 2 = quad-slave, 0 = regular - 3 = percussion BassDrum - 4 = percussion Snare - 5 = percussion Tom - 6 = percussion Crash cymbal - 7 = percussion Hihat - 8 = percussion slave - */ - std::vector<uint32_t> m_channelCategory; - - - /** - * @brief C.O. Constructor - */ - 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 Slave 4-op channel of chip, unused for 2op (Emulated chip choosing by next formula: [c = ch + (chipId * 23)]) - * @param hertz Frequency of the tone in hertzes - */ - void noteOn(size_t c1, size_t c2, double hertz); - - /** - * @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 volume Volume level (from 0 to 63) - * @param brightness CC74 Brightness level (from 0 to 127) - */ - void touchNote(size_t c, uint8_t volume, uint8_t brightness = 127); - - /** - * @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 adldata &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 Hooks of the internal events @@ -1505,23 +1234,4 @@ extern void adl_audioTickHandler(void *instance, uint32_t chipId, uint32_t rate) */ extern int adlCalculateFourOpChannels(MIDIplay *play, bool silent = false); -/** - * @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_PRIVATE_HPP |