aboutsummaryrefslogtreecommitdiff
path: root/src/chips/opal/opal.h
diff options
context:
space:
mode:
authorWohlstand <admin@wohlnet.ru>2023-05-26 03:43:01 +0300
committerWohlstand <admin@wohlnet.ru>2023-05-26 03:43:01 +0300
commitf742d3eca4a72af940da7399d69e0b93c0d981f5 (patch)
treefccc624aa1b1dfcf3bed4bce09e7fead94f8946a /src/chips/opal/opal.h
parentd9f55120fb939b3b45af8929ad09243b3b09c08e (diff)
downloadlibADLMIDI-f742d3eca4a72af940da7399d69e0b93c0d981f5.tar.gz
libADLMIDI-f742d3eca4a72af940da7399d69e0b93c0d981f5.tar.bz2
libADLMIDI-f742d3eca4a72af940da7399d69e0b93c0d981f5.zip
Opal: Convert entire Opal code into the Pure C
Diffstat (limited to 'src/chips/opal/opal.h')
-rw-r--r--src/chips/opal/opal.h165
1 files changed, 165 insertions, 0 deletions
diff --git a/src/chips/opal/opal.h b/src/chips/opal/opal.h
new file mode 100644
index 0000000..0772d3e
--- /dev/null
+++ b/src/chips/opal/opal.h
@@ -0,0 +1,165 @@
+/*
+
+ The Opal OPL3 emulator.
+
+ Note: this is not a complete emulator, just enough for Reality Adlib Tracker tunes.
+
+ Missing features compared to a real OPL3:
+
+ - Timers/interrupts
+ - OPL3 enable bit (it defaults to always on)
+ - CSW mode
+ - Test register
+ - Percussion mode
+
+*/
+
+#ifndef OPAL_HHHH
+#define OPAL_HHHH
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define OPAL_TRUE 1
+#define OPAL_FALSE 0
+typedef int opal_bool;
+
+typedef struct OpalChannel_t OpalChannel;
+typedef struct OpalOperator_t OpalOperator;
+typedef struct Opal_t Opal;
+
+/* Various constants */
+typedef enum OpalEnum_t
+{
+ OpalOPL3SampleRate = 49716,
+ OpalNumChannels = 18,
+ OpalNumOperators = 36,
+} OpalEnum;
+
+/* A single FM operator */
+struct OpalOperator_t
+{
+ Opal* Master; /* Master object */
+ OpalChannel* Chan; /* Owning channel */
+ uint32_t Phase; /* The current offset in the selected waveform */
+ uint16_t Waveform; /* The waveform id this operator is using */
+ uint16_t FreqMultTimes2; /* Frequency multiplier * 2 */
+ int EnvelopeStage; /* Which stage the envelope is at (see Env* enums above) */
+ int16_t EnvelopeLevel; /* 0 - $1FF, 0 being the loudest */
+ uint16_t OutputLevel; /* 0 - $FF */
+ uint16_t AttackRate;
+ uint16_t DecayRate;
+ uint16_t SustainLevel;
+ uint16_t ReleaseRate;
+ uint16_t AttackShift;
+ uint16_t AttackMask;
+ uint16_t AttackAdd;
+ const uint16_t* AttackTab;
+ uint16_t DecayShift;
+ uint16_t DecayMask;
+ uint16_t DecayAdd;
+ const uint16_t* DecayTab;
+ uint16_t ReleaseShift;
+ uint16_t ReleaseMask;
+ uint16_t ReleaseAdd;
+ const uint16_t* ReleaseTab;
+ uint16_t KeyScaleShift;
+ uint16_t KeyScaleLevel;
+ int16_t Out[2];
+ opal_bool KeyOn;
+ opal_bool KeyScaleRate; /* Affects envelope rate scaling */
+ opal_bool SustainMode; /* Whether to sustain during the sustain phase, or release instead */
+ opal_bool TremoloEnable;
+ opal_bool VibratoEnable;
+};
+
+/* A single channel, which can contain two or more operators */
+struct OpalChannel_t
+{
+ OpalOperator* Op[4];
+
+ Opal* Master; /* Master object */
+ uint16_t Freq; /* Frequency; actually it's a phase stepping value */
+ uint16_t Octave; /* Also known as "block" in Yamaha parlance */
+ uint32_t PhaseStep;
+ uint16_t KeyScaleNumber;
+ uint16_t FeedbackShift;
+ uint16_t ModulationType;
+ OpalChannel* ChannelPair;
+ opal_bool Enable;
+ opal_bool LeftEnable, RightEnable;
+ uint16_t LeftPan, RightPan;
+};
+
+
+/*==================================================================================================
+ Opal instance.
+ ==================================================================================================*/
+struct Opal_t
+{
+ int32_t SampleRate;
+ int32_t SampleAccum;
+ int16_t LastOutput[2], CurrOutput[2];
+ OpalChannel Chan[OpalNumChannels];
+ OpalOperator Op[OpalNumOperators];
+ uint16_t Clock;
+ uint16_t TremoloClock;
+ uint16_t TremoloLevel;
+ uint16_t VibratoTick;
+ uint16_t VibratoClock;
+ opal_bool NoteSel;
+ opal_bool TremoloDepth;
+ opal_bool VibratoDepth;
+};
+
+
+/*==================================================================================================
+ Public API.
+ ==================================================================================================*/
+/*!
+ * \brief Initialize Opal with a given output sample rate
+ * \param self Pointer to the Opal instance
+ * \param sample_rate Desired output sample rate
+ */
+extern void Opal_Init(Opal *self, int sample_rate);
+
+/*!
+ * \brief Change the output sample rate of existing initialized instance
+ * \param self Pointer to the Opal instance
+ * \param sample_rate Desired output sample rate
+ */
+extern void Opal_SetSampleRate(Opal *self, int sample_rate);
+
+/*!
+ * \brief Send the register data to the Opal
+ * \param self Pointer to the Opal instance
+ * \param reg_num OPL3 Register address
+ * \param val Value to write
+ */
+extern void Opal_Port(Opal *self, uint16_t reg_num, uint8_t val);
+
+/*!
+ * \brief Panorama level per channel
+ * \param self Pointer to the Opal instance
+ * \param reg_num Channel number (multiplied by 256)
+ * \param pan Panorama level (0 - left, 64 - middle, 127 - right)
+ */
+extern void Opal_Pan(Opal *self, uint16_t reg_num, uint8_t pan);
+
+/*!
+ * \brief Generate one 16-bit PCM sample in system endian (there are two integers will be written)
+ * \param self Pointer to the Opal instance
+ * \param left Sample for the left chanel
+ * \param right Sample for the right channel
+ */
+extern void Opal_Sample(Opal *self, int16_t* left, int16_t* right);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* OPAL_HHHH */