zmusic/thirdparty/adlmidi/adlmidi_opl3.hpp

357 lines
11 KiB
C++
Raw Normal View History

Update libADLMIDI up to 1.5.0 ## 1.5.0 2020-09-28 * Drum note length expanding is now supported in real-time mode (Thanks to [Jean Pierre Cimalando](https://github.com/jpcima) for a work!) * Channels manager has been improved (Thanks to [Jean Pierre Cimalando](https://github.com/jpcima) for a work!) * Nuked OPL3 1.8 emulator got some optimizations ported from 1.7 where they are was applied previously (Thanks to [Jean Pierre Cimalando](https://github.com/jpcima) for a work!) * Reworked rhythm-mode percussions system, WOPL banks with rhythm-mode percussions * Added Public Domain Opal OPL3 emulator made by Reality (a team who originally made the Reality Adlib Tracker) (Thanks to [Jean Pierre Cimalando](https://github.com/jpcima) for a work!) * Added LGPL licensed JavaOPL3 emulator made by Robson Cozendey in Java and later rewritten into C++ for GZDoom (Thanks to [Jean Pierre Cimalando](https://github.com/jpcima) for a work!) * Fully rewritten an embedded bank database format, embedded banks now supports a wider set (more than 127:127 instruments in one bank) * Improved accuracy of the DMX volume model, include the buggy AM interpretation * Improved accuracy of Apogee volume model, include the bug of AM instruments * Improved accuracy of the Win9X volume model * Removed C++ extras. C++-bounded instruments tester is useless since a real-time MIDI API can completely replace it * Added AIL volume model * Added Generic FM variant of Win9X volume model * Fixed an incorrect work of CC-121 (See https://github.com/Wohlstand/libADLMIDI/issues/227 for details) * Added HMI volume model (Thanks to [Alexey Khokholov](https://github.com/nukeykt) for help with research!) * Added frequency models, assigned to every volume model: AIL, HMI, DMX, Apogee, 9X, and the Generic formula
2020-09-28 18:17:46 +00:00
/*
* libADLMIDI is a free Software MIDI synthesizer library with OPL3 emulation
*
* Original ADLMIDI code: Copyright (c) 2010-2014 Joel Yliluoma <bisqwit@iki.fi>
* ADLMIDI Library API: Copyright (c) 2015-2020 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 "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<AdlMIDI_SPtr<OPLChipBase > > m_chips;
#endif
private:
//! Cached patch data, needed by Touch()
std::vector<OplTimbre> 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
OplInstMeta ins[128];
};
typedef BasicBankMap<Bank> 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<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 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