diff options
Diffstat (limited to 'apps/codecs/libgme/ym2612_emu.h')
-rw-r--r-- | apps/codecs/libgme/ym2612_emu.h | 237 |
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 | |||
9 | enum { ym2612_out_chan_count = 2 }; // stereo | ||
10 | enum { ym2612_channel_count = 6 }; | ||
11 | enum { ym2612_disabled_time = -1 }; | ||
12 | |||
13 | struct 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 | |||
57 | struct 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 | |||
73 | struct 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 | |||
153 | struct 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 | |||
175 | struct Ym2612_Impl | ||
176 | { | ||
177 | struct state_t YM2612; | ||
178 | int mute_mask; | ||
179 | struct tables_t g; | ||
180 | }; | ||
181 | |||
182 | void impl_reset( struct Ym2612_Impl* impl ); | ||
183 | |||
184 | struct 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 | |||
194 | static 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 | ||
202 | const char* Ym2612_set_rate( struct Ym2612_Emu* this_, double sample_rate, double clock_rate ); | ||
203 | |||
204 | // Resets to power-up state | ||
205 | void Ym2612_reset( struct Ym2612_Emu* this_ ); | ||
206 | |||
207 | // Mutes voice n if bit n (1 << n) of mask is set | ||
208 | void Ym2612_mute_voices( struct Ym2612_Emu* this_, int mask ); | ||
209 | |||
210 | // Writes addr to register 0 then data to register 1 | ||
211 | void Ym2612_write0( struct Ym2612_Emu* this_, int addr, int data ) ICODE_ATTR; | ||
212 | |||
213 | // Writes addr to register 2 then data to register 3 | ||
214 | void 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 | ||
217 | void Ym2612_run( struct Ym2612_Emu* this_, int pair_count, short* out ) ICODE_ATTR; | ||
218 | |||
219 | static inline void Ym2612_enable( struct Ym2612_Emu* this_, bool b ) { this_->last_time = b ? 0 : ym2612_disabled_time; } | ||
220 | static inline bool Ym2612_enabled( struct Ym2612_Emu* this_ ) { return this_->last_time != ym2612_disabled_time; } | ||
221 | static inline void Ym2612_begin_frame( struct Ym2612_Emu* this_, short* buf ) { this_->out = buf; this_->last_time = 0; } | ||
222 | |||
223 | static 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 | ||