1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
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 */
|