Cog/Frameworks/OpenMPT/OpenMPT/soundlib/OPL.h
Christopher Snowhill da1973bcd9 Build libOpenMPT from source once again
Bundle libOpenMPT as a dynamic framework, which should be safe once
again, now that there is only one version to bundle. Also, now it is
using the versions of libvorbisfile and libmpg123 that are bundled with
the player, instead of compiling minimp3 and stbvorbis.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-30 22:56:52 -07:00

125 lines
3.6 KiB
C++

/*
* OPL.h
* -----
* Purpose: Translate data coming from OpenMPT's mixer into OPL commands to be sent to the Opal emulator.
* Notes : (currently none)
* Authors: OpenMPT Devs
* The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
*/
#pragma once
#include "openmpt/all/BuildSettings.hpp"
#include "Snd_defs.h"
class Opal;
OPENMPT_NAMESPACE_BEGIN
class OPL
{
public:
enum OPLRegisters : uint8
{
// Operators (combine with result of OperatorToRegister)
AM_VIB = 0x20, // AM / VIB / EG / KSR / Multiple (0x20 to 0x35)
KSL_LEVEL = 0x40, // KSL / Total level (0x40 to 0x55)
ATTACK_DECAY = 0x60, // Attack rate / Decay rate (0x60 to 0x75)
SUSTAIN_RELEASE = 0x80, // Sustain level / Release rate (0x80 to 0x95)
WAVE_SELECT = 0xE0, // Wave select (0xE0 to 0xF5)
// Channels (combine with result of ChannelToRegister)
FNUM_LOW = 0xA0, // F-number low bits (0xA0 to 0xA8)
KEYON_BLOCK = 0xB0, // F-number high bits / Key on / Block (octave) (0xB0 to 0xB8)
FEEDBACK_CONNECTION = 0xC0, // Feedback / Connection (0xC0 to 0xC8)
};
enum OPLValues : uint8
{
// AM_VIB
TREMOLO_ON = 0x80,
VIBRATO_ON = 0x40,
SUSTAIN_ON = 0x20,
KSR = 0x10, // Key scaling rate
MULTIPLE_MASK = 0x0F, // Frequency multiplier
// KSL_LEVEL
KSL_MASK = 0xC0, // Envelope scaling bits
TOTAL_LEVEL_MASK = 0x3F, // Strength (volume) of OP
// ATTACK_DECAY
ATTACK_MASK = 0xF0,
DECAY_MASK = 0x0F,
// SUSTAIN_RELEASE
SUSTAIN_MASK = 0xF0,
RELEASE_MASK = 0x0F,
// KEYON_BLOCK
KEYON_BIT = 0x20,
// FEEDBACK_CONNECTION
FEEDBACK_MASK = 0x0E, // Valid just for first OP of a voice
CONNECTION_BIT = 0x01,
VOICE_TO_LEFT = 0x10,
VOICE_TO_RIGHT = 0x20,
STEREO_BITS = VOICE_TO_LEFT | VOICE_TO_RIGHT,
};
class IRegisterLogger
{
public:
virtual void Port(CHANNELINDEX c, uint16 reg, uint8 value) = 0;
virtual ~IRegisterLogger() {}
};
OPL(uint32 samplerate);
OPL(IRegisterLogger &logger);
~OPL();
void Initialize(uint32 samplerate);
void Mix(int32 *buffer, size_t count, uint32 volumeFactorQ16);
void NoteOff(CHANNELINDEX c);
void NoteCut(CHANNELINDEX c, bool unassign = true);
void Frequency(CHANNELINDEX c, uint32 milliHertz, bool keyOff, bool beatingOscillators);
void Volume(CHANNELINDEX c, uint8 vol, bool applyToModulator);
int8 Pan(CHANNELINDEX c, int32 pan);
void Patch(CHANNELINDEX c, const OPLPatch &patch);
bool IsActive(CHANNELINDEX c) const { return GetVoice(c) != OPL_CHANNEL_INVALID; }
void MoveChannel(CHANNELINDEX from, CHANNELINDEX to);
void Reset();
// A list of all registers for channels and operators
static std::vector<uint16> AllVoiceRegisters();
protected:
static uint16 ChannelToRegister(uint8 oplCh);
static uint16 OperatorToRegister(uint8 oplCh);
static uint8 CalcVolume(uint8 trackerVol, uint8 kslVolume);
uint8 GetVoice(CHANNELINDEX c) const;
uint8 AllocateVoice(CHANNELINDEX c);
void Port(CHANNELINDEX c, uint16 reg, uint8 value);
enum
{
OPL_CHANNELS = 18, // 9 for OPL2 or 18 for OPL3
OPL_CHANNEL_CUT = 0x80, // Indicates that the channel has been cut and used as a hint to re-use the channel for the same tracker channel if possible
OPL_CHANNEL_MASK = 0x7F,
OPL_CHANNEL_INVALID = 0xFF,
OPL_BASERATE = 49716,
};
std::unique_ptr<Opal> m_opl;
IRegisterLogger *m_logger = nullptr;
std::array<uint8, OPL_CHANNELS> m_KeyOnBlock;
std::array<CHANNELINDEX, OPL_CHANNELS> m_OPLtoChan;
std::array<uint8, MAX_CHANNELS> m_ChanToOPL;
std::array<OPLPatch, OPL_CHANNELS> m_Patches;
bool m_isActive = false;
};
OPENMPT_NAMESPACE_END