summaryrefslogtreecommitdiff
path: root/apps/codecs/libgme/ym2612_emu.h
diff options
context:
space:
mode:
Diffstat (limited to 'apps/codecs/libgme/ym2612_emu.h')
-rw-r--r--apps/codecs/libgme/ym2612_emu.h237
1 files changed, 237 insertions, 0 deletions
diff --git a/apps/codecs/libgme/ym2612_emu.h b/apps/codecs/libgme/ym2612_emu.h
new file mode 100644
index 0000000000..19f0903d61
--- /dev/null
+++ b/apps/codecs/libgme/ym2612_emu.h
@@ -0,0 +1,237 @@
1// YM2612 FM sound chip emulator
2
3// Game_Music_Emu 0.6-pre
4#ifndef YM2612_EMU_H
5#define YM2612_EMU_H
6
7#include "blargg_common.h"
8
9enum { ym2612_out_chan_count = 2 }; // stereo
10enum { ym2612_channel_count = 6 };
11enum { ym2612_disabled_time = -1 };
12
13struct slot_t
14{
15 const int *DT; // parametre detune
16 int MUL; // parametre "multiple de frequence"
17 int TL; // Total Level = volume lorsque l'enveloppe est au plus haut
18 int TLL; // Total Level ajusted
19 int SLL; // Sustin Level (ajusted) = volume où l'enveloppe termine sa premiere phase de regression
20 int KSR_S; // Key Scale Rate Shift = facteur de prise en compte du KSL dans la variations de l'enveloppe
21 int KSR; // Key Scale Rate = cette valeur est calculee par rapport à la frequence actuelle, elle va influer
22 // sur les differents parametres de l'enveloppe comme l'attaque, le decay ... comme dans la realite !
23 int SEG; // Type enveloppe SSG
24 int env_xor;
25 int env_max;
26
27 const int *AR; // Attack Rate (table pointeur) = Taux d'attaque (AR [KSR])
28 const int *DR; // Decay Rate (table pointeur) = Taux pour la regression (DR [KSR])
29 const int *SR; // Sustin Rate (table pointeur) = Taux pour le maintien (SR [KSR])
30 const int *RR; // Release Rate (table pointeur) = Taux pour le rel'chement (RR [KSR])
31 int Fcnt; // Frequency Count = compteur-frequence pour determiner l'amplitude actuelle (SIN [Finc >> 16])
32 int Finc; // frequency step = pas d'incrementation du compteur-frequence
33 // plus le pas est grand, plus la frequence est aïgu (ou haute)
34 int Ecurp; // Envelope current phase = cette variable permet de savoir dans quelle phase
35 // de l'enveloppe on se trouve, par exemple phase d'attaque ou phase de maintenue ...
36 // en fonction de la valeur de cette variable, on va appeler une fonction permettant
37 // de mettre à jour l'enveloppe courante.
38 int Ecnt; // Envelope counter = le compteur-enveloppe permet de savoir où l'on se trouve dans l'enveloppe
39 int Einc; // Envelope step courant
40 int Ecmp; // Envelope counter limite pour la prochaine phase
41 int EincA; // Envelope step for Attack = pas d'incrementation du compteur durant la phase d'attaque
42 // cette valeur est egal à AR [KSR]
43 int EincD; // Envelope step for Decay = pas d'incrementation du compteur durant la phase de regression
44 // cette valeur est egal à DR [KSR]
45 int EincS; // Envelope step for Sustain = pas d'incrementation du compteur durant la phase de maintenue
46 // cette valeur est egal à SR [KSR]
47 int EincR; // Envelope step for Release = pas d'incrementation du compteur durant la phase de rel'chement
48 // cette valeur est egal à RR [KSR]
49 int *OUTp; // pointeur of SLOT output = pointeur permettant de connecter la sortie de ce slot à l'entree
50 // d'un autre ou carrement à la sortie de la voie
51 int INd; // input data of the slot = donnees en entree du slot
52 int ChgEnM; // Change envelop mask.
53 int AMS; // AMS depth level of this SLOT = degre de modulation de l'amplitude par le LFO
54 int AMSon; // AMS enable flag = drapeau d'activation de l'AMS
55};
56
57struct channel_
58{
59 int S0_OUT [4]; // anciennes sorties slot 0 (pour le feed back)
60 int LEFT; // LEFT enable flag
61 int RIGHT; // RIGHT enable flag
62 int ALGO; // Algorythm = determine les connections entre les operateurs
63 int FB; // shift count of self feed back = degre de "Feed-Back" du SLOT 1 (il est son unique entree)
64 int FMS; // Frequency Modulation Sensitivity of channel = degre de modulation de la frequence sur la voie par le LFO
65 int AMS; // Amplitude Modulation Sensitivity of channel = degre de modulation de l'amplitude sur la voie par le LFO
66 int FNUM [4]; // hauteur frequence de la voie (+ 3 pour le mode special)
67 int FOCT [4]; // octave de la voie (+ 3 pour le mode special)
68 int KC [4]; // Key Code = valeur fonction de la frequence (voir KSR pour les slots, KSR = KC >> KSR_S)
69 struct slot_t SLOT [4]; // four slot.operators = les 4 slots de la voie
70 int FFlag; // Frequency step recalculation flag
71};
72
73struct state_t
74{
75 int TimerBase; // TimerBase calculation
76 int Status; // YM2612 Status (timer overflow)
77 int TimerA; // timerA limit = valeur jusqu'à laquelle le timer A doit compter
78 int TimerAL;
79 int TimerAcnt; // timerA counter = valeur courante du Timer A
80 int TimerB; // timerB limit = valeur jusqu'à laquelle le timer B doit compter
81 int TimerBL;
82 int TimerBcnt; // timerB counter = valeur courante du Timer B
83 int Mode; // Mode actuel des voie 3 et 6 (normal / special)
84 int DAC; // DAC enabled flag
85 struct channel_ CHANNEL [ym2612_channel_count]; // Les 6 voies du YM2612
86 int REG [2] [0x100]; // Sauvegardes des valeurs de tout les registres, c'est facultatif
87 // cela nous rend le debuggage plus facile
88};
89
90#undef PI
91#define PI 3.14159265358979323846
92
93#define ATTACK 0
94#define DECAY 1
95#define SUBSTAIN 2
96#define RELEASE 3
97
98// SIN_LBITS <= 16
99// LFO_HBITS <= 16
100// (SIN_LBITS + SIN_HBITS) <= 26
101// (ENV_LBITS + ENV_HBITS) <= 28
102// (LFO_LBITS + LFO_HBITS) <= 28
103
104#define SIN_HBITS 12 // Sinus phase counter int part
105#define SIN_LBITS (26 - SIN_HBITS) // Sinus phase counter float part (best setting)
106
107#if (SIN_LBITS > 16)
108#define SIN_LBITS 16 // Can't be greater than 16 bits
109#endif
110
111#define ENV_HBITS 12 // Env phase counter int part
112#define ENV_LBITS (28 - ENV_HBITS) // Env phase counter float part (best setting)
113
114#define LFO_HBITS 10 // LFO phase counter int part
115#define LFO_LBITS (28 - LFO_HBITS) // LFO phase counter float part (best setting)
116
117#define SIN_LENGHT (1 << SIN_HBITS)
118#define ENV_LENGHT (1 << ENV_HBITS)
119#define LFO_LENGHT (1 << LFO_HBITS)
120
121#define TL_LENGHT (ENV_LENGHT * 3) // Env + TL scaling + LFO
122
123#define SIN_MASK (SIN_LENGHT - 1)
124#define ENV_MASK (ENV_LENGHT - 1)
125#define LFO_MASK (LFO_LENGHT - 1)
126
127#define ENV_STEP (96.0 / ENV_LENGHT) // ENV_MAX = 96 dB
128
129#define ENV_ATTACK ((ENV_LENGHT * 0) << ENV_LBITS)
130#define ENV_DECAY ((ENV_LENGHT * 1) << ENV_LBITS)
131#define ENV_END ((ENV_LENGHT * 2) << ENV_LBITS)
132
133#define MAX_OUT_BITS (SIN_HBITS + SIN_LBITS + 2) // Modulation = -4 <--> +4
134#define MAX_OUT ((1 << MAX_OUT_BITS) - 1)
135
136#define PG_CUT_OFF ((int) (78.0 / ENV_STEP))
137//#define ENV_CUT_OFF ((int) (68.0 / ENV_STEP))
138
139#define AR_RATE 399128
140#define DR_RATE 5514396
141
142//#define AR_RATE 426136
143//#define DR_RATE (AR_RATE * 12)
144
145#define LFO_FMS_LBITS 9 // FIXED (LFO_FMS_BASE gives somethink as 1)
146#define LFO_FMS_BASE ((int) (0.05946309436 * 0.0338 * (double) (1 << LFO_FMS_LBITS)))
147
148#define S0 0 // Stupid typo of the YM2612
149#define S1 2
150#define S2 1
151#define S3 3
152
153struct tables_t
154{
155 short SIN_TAB [SIN_LENGHT]; // SINUS TABLE (offset into TL TABLE)
156 int LFOcnt; // LFO counter = compteur-frequence pour le LFO
157 int LFOinc; // LFO step counter = pas d'incrementation du compteur-frequence du LFO
158 // plus le pas est grand, plus la frequence est grande
159 unsigned int AR_TAB [128]; // Attack rate table
160 unsigned int DR_TAB [96]; // Decay rate table
161 unsigned int DT_TAB [8] [32]; // Detune table
162 unsigned int SL_TAB [16]; // Substain level table
163 unsigned int NULL_RATE [32]; // Table for NULL rate
164 int LFO_INC_TAB [8]; // LFO step table
165
166 short ENV_TAB [2 * ENV_LENGHT + 8]; // ENV CURVE TABLE (attack & decay)
167
168 short LFO_ENV_TAB [LFO_LENGHT]; // LFO AMS TABLE (adjusted for 11.8 dB)
169 short LFO_FREQ_TAB [LFO_LENGHT]; // LFO FMS TABLE
170 int TL_TAB [TL_LENGHT * 2]; // TOTAL LEVEL TABLE (positif and minus)
171 unsigned int DECAY_TO_ATTACK [ENV_LENGHT]; // Conversion from decay to attack phase
172 unsigned int FINC_TAB [2048]; // Frequency step table
173};
174
175struct Ym2612_Impl
176{
177 struct state_t YM2612;
178 int mute_mask;
179 struct tables_t g;
180};
181
182void impl_reset( struct Ym2612_Impl* impl );
183
184struct Ym2612_Emu {
185 struct Ym2612_Impl impl;
186
187 // Impl
188 int last_time;
189 int sample_rate;
190 int clock_rate;
191 short* out;
192};
193
194static inline void Ym2612_init( struct Ym2612_Emu* this_ )
195{
196 this_->last_time = ym2612_disabled_time; this_->out = 0;
197 this_->impl.mute_mask = 0;
198}
199
200// Sets sample rate and chip clock rate, in Hz. Returns non-zero
201// if error. If clock_rate=0, uses sample_rate*144
202const char* Ym2612_set_rate( struct Ym2612_Emu* this_, double sample_rate, double clock_rate );
203
204// Resets to power-up state
205void Ym2612_reset( struct Ym2612_Emu* this_ );
206
207// Mutes voice n if bit n (1 << n) of mask is set
208void Ym2612_mute_voices( struct Ym2612_Emu* this_, int mask );
209
210// Writes addr to register 0 then data to register 1
211void Ym2612_write0( struct Ym2612_Emu* this_, int addr, int data ) ICODE_ATTR;
212
213// Writes addr to register 2 then data to register 3
214void Ym2612_write1( struct Ym2612_Emu* this_, int addr, int data ) ICODE_ATTR;
215
216// Runs and adds pair_count*2 samples into current output buffer contents
217void Ym2612_run( struct Ym2612_Emu* this_, int pair_count, short* out ) ICODE_ATTR;
218
219static inline void Ym2612_enable( struct Ym2612_Emu* this_, bool b ) { this_->last_time = b ? 0 : ym2612_disabled_time; }
220static inline bool Ym2612_enabled( struct Ym2612_Emu* this_ ) { return this_->last_time != ym2612_disabled_time; }
221static inline void Ym2612_begin_frame( struct Ym2612_Emu* this_, short* buf ) { this_->out = buf; this_->last_time = 0; }
222
223static inline int Ym2612_run_until( struct Ym2612_Emu* this_, int time )
224{
225 int count = time - this_->last_time;
226 if ( count > 0 )
227 {
228 if ( this_->last_time < 0 )
229 return false;
230 this_->last_time = time;
231 short* p = this_->out;
232 this_->out += count * ym2612_out_chan_count;
233 Ym2612_run( this_, count, p );
234 }
235 return true;
236}
237#endif