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