From f40bfc9267b13b54e6379dfe7539447662879d24 Mon Sep 17 00:00:00 2001 From: Sean Bartell Date: Sat, 25 Jun 2011 21:32:25 -0400 Subject: Add codecs to librbcodec. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: Id7f4717d51ed02d67cb9f9cb3c0ada4a81843f97 Reviewed-on: http://gerrit.rockbox.org/137 Reviewed-by: Nils Wallménius Tested-by: Nils Wallménius --- lib/rbcodec/codecs/libgme/ym2612_emu.h | 248 +++++++++++++++++++++++++++++++++ 1 file changed, 248 insertions(+) create mode 100644 lib/rbcodec/codecs/libgme/ym2612_emu.h (limited to 'lib/rbcodec/codecs/libgme/ym2612_emu.h') 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 @@ +// YM2612 FM sound chip emulator + +// Game_Music_Emu 0.6-pre +#ifndef YM2612_EMU_H +#define YM2612_EMU_H + +#include "blargg_common.h" + +#if !defined(ROCKBOX) + #define YM2612_CALCUL_TABLES +#endif + +#if MEMORYSIZE > 2 + #define YM2612_USE_TL_TAB +#endif + +enum { ym2612_out_chan_count = 2 }; // stereo +enum { ym2612_channel_count = 6 }; +enum { ym2612_disabled_time = -1 }; + +struct slot_t +{ + const int *DT; // parametre detune + int MUL; // parametre "multiple de frequence" + int TL; // Total Level = volume lorsque l'enveloppe est au plus haut + int TLL; // Total Level ajusted + int SLL; // Sustin Level (ajusted) = volume où l'enveloppe termine sa premiere phase de regression + int KSR_S; // Key Scale Rate Shift = facteur de prise en compte du KSL dans la variations de l'enveloppe + int KSR; // Key Scale Rate = cette valeur est calculee par rapport à la frequence actuelle, elle va influer + // sur les differents parametres de l'enveloppe comme l'attaque, le decay ... comme dans la realite ! + int SEG; // Type enveloppe SSG + int env_xor; + int env_max; + + const int *AR; // Attack Rate (table pointeur) = Taux d'attaque (AR [KSR]) + const int *DR; // Decay Rate (table pointeur) = Taux pour la regression (DR [KSR]) + const int *SR; // Sustin Rate (table pointeur) = Taux pour le maintien (SR [KSR]) + const int *RR; // Release Rate (table pointeur) = Taux pour le rel'chement (RR [KSR]) + int Fcnt; // Frequency Count = compteur-frequence pour determiner l'amplitude actuelle (SIN [Finc >> 16]) + int Finc; // frequency step = pas d'incrementation du compteur-frequence + // plus le pas est grand, plus la frequence est aïgu (ou haute) + int Ecurp; // Envelope current phase = cette variable permet de savoir dans quelle phase + // de l'enveloppe on se trouve, par exemple phase d'attaque ou phase de maintenue ... + // en fonction de la valeur de cette variable, on va appeler une fonction permettant + // de mettre à jour l'enveloppe courante. + int Ecnt; // Envelope counter = le compteur-enveloppe permet de savoir où l'on se trouve dans l'enveloppe + int Einc; // Envelope step courant + int Ecmp; // Envelope counter limite pour la prochaine phase + int EincA; // Envelope step for Attack = pas d'incrementation du compteur durant la phase d'attaque + // cette valeur est egal à AR [KSR] + int EincD; // Envelope step for Decay = pas d'incrementation du compteur durant la phase de regression + // cette valeur est egal à DR [KSR] + int EincS; // Envelope step for Sustain = pas d'incrementation du compteur durant la phase de maintenue + // cette valeur est egal à SR [KSR] + int EincR; // Envelope step for Release = pas d'incrementation du compteur durant la phase de rel'chement + // cette valeur est egal à RR [KSR] + int *OUTp; // pointeur of SLOT output = pointeur permettant de connecter la sortie de ce slot à l'entree + // d'un autre ou carrement à la sortie de la voie + int INd; // input data of the slot = donnees en entree du slot + int ChgEnM; // Change envelop mask. + int AMS; // AMS depth level of this SLOT = degre de modulation de l'amplitude par le LFO + int AMSon; // AMS enable flag = drapeau d'activation de l'AMS +}; + +struct channel_ +{ + int S0_OUT [4]; // anciennes sorties slot 0 (pour le feed back) + int LEFT; // LEFT enable flag + int RIGHT; // RIGHT enable flag + int ALGO; // Algorythm = determine les connections entre les operateurs + int FB; // shift count of self feed back = degre de "Feed-Back" du SLOT 1 (il est son unique entree) + int FMS; // Frequency Modulation Sensitivity of channel = degre de modulation de la frequence sur la voie par le LFO + int AMS; // Amplitude Modulation Sensitivity of channel = degre de modulation de l'amplitude sur la voie par le LFO + int FNUM [4]; // hauteur frequence de la voie (+ 3 pour le mode special) + int FOCT [4]; // octave de la voie (+ 3 pour le mode special) + int KC [4]; // Key Code = valeur fonction de la frequence (voir KSR pour les slots, KSR = KC >> KSR_S) + struct slot_t SLOT [4]; // four slot.operators = les 4 slots de la voie + int FFlag; // Frequency step recalculation flag +}; + +struct state_t +{ + int TimerBase; // TimerBase calculation + int Status; // YM2612 Status (timer overflow) + int TimerA; // timerA limit = valeur jusqu'à laquelle le timer A doit compter + int TimerAL; + int TimerAcnt; // timerA counter = valeur courante du Timer A + int TimerB; // timerB limit = valeur jusqu'à laquelle le timer B doit compter + int TimerBL; + int TimerBcnt; // timerB counter = valeur courante du Timer B + int Mode; // Mode actuel des voie 3 et 6 (normal / special) + int DAC; // DAC enabled flag + struct channel_ CHANNEL [ym2612_channel_count]; // Les 6 voies du YM2612 + int REG [2] [0x100]; // Sauvegardes des valeurs de tout les registres, c'est facultatif + // cela nous rend le debuggage plus facile +}; + +#undef PI +#define PI 3.14159265358979323846 + +#define ATTACK 0 +#define DECAY 1 +#define SUBSTAIN 2 +#define RELEASE 3 + +// SIN_LBITS <= 16 +// LFO_HBITS <= 16 +// (SIN_LBITS + SIN_HBITS) <= 26 +// (ENV_LBITS + ENV_HBITS) <= 28 +// (LFO_LBITS + LFO_HBITS) <= 28 + +#define SIN_HBITS 12 // Sinus phase counter int part +#define SIN_LBITS (26 - SIN_HBITS) // Sinus phase counter float part (best setting) + +#if (SIN_LBITS > 16) +#define SIN_LBITS 16 // Can't be greater than 16 bits +#endif + +#define ENV_HBITS 12 // Env phase counter int part +#define ENV_LBITS (28 - ENV_HBITS) // Env phase counter float part (best setting) + +#define LFO_HBITS 10 // LFO phase counter int part +#define LFO_LBITS (28 - LFO_HBITS) // LFO phase counter float part (best setting) + +#define SIN_LENGHT (1 << SIN_HBITS) +#define ENV_LENGHT (1 << ENV_HBITS) +#define LFO_LENGHT (1 << LFO_HBITS) + +#define TL_LENGHT (ENV_LENGHT * 3) // Env + TL scaling + LFO + +#define SIN_MASK (SIN_LENGHT - 1) +#define ENV_MASK (ENV_LENGHT - 1) +#define LFO_MASK (LFO_LENGHT - 1) + +#define ENV_STEP (96.0 / ENV_LENGHT) // ENV_MAX = 96 dB + +#define ENV_ATTACK ((ENV_LENGHT * 0) << ENV_LBITS) +#define ENV_DECAY ((ENV_LENGHT * 1) << ENV_LBITS) +#define ENV_END ((ENV_LENGHT * 2) << ENV_LBITS) + +#define MAX_OUT_BITS (SIN_HBITS + SIN_LBITS + 2) // Modulation = -4 <--> +4 +#define MAX_OUT ((1 << MAX_OUT_BITS) - 1) + +#define PG_CUT_OFF ((int) (78.0 / ENV_STEP)) +//#define ENV_CUT_OFF ((int) (68.0 / ENV_STEP)) + +#define AR_RATE 399128 +#define DR_RATE 5514396 + +//#define AR_RATE 426136 +//#define DR_RATE (AR_RATE * 12) + +#define LFO_FMS_LBITS 9 // FIXED (LFO_FMS_BASE gives somethink as 1) +#define LFO_FMS_BASE ((int) (0.05946309436 * 0.0338 * (double) (1 << LFO_FMS_LBITS))) + +#define S0 0 // Stupid typo of the YM2612 +#define S1 2 +#define S2 1 +#define S3 3 + +struct tables_t +{ + short SIN_TAB [SIN_LENGHT]; // SINUS TABLE (offset into TL TABLE) + int LFOcnt; // LFO counter = compteur-frequence pour le LFO + int LFOinc; // LFO step counter = pas d'incrementation du compteur-frequence du LFO + // plus le pas est grand, plus la frequence est grande + unsigned int AR_TAB [128]; // Attack rate table + unsigned int DR_TAB [96]; // Decay rate table + unsigned int DT_TAB [8] [32]; // Detune table + unsigned int SL_TAB [16]; // Substain level table + unsigned int NULL_RATE [32]; // Table for NULL rate + int LFO_INC_TAB [8]; // LFO step table + + short ENV_TAB [2 * ENV_LENGHT + 8]; // ENV CURVE TABLE (attack & decay) +#ifdef YM2612_CALCUL_TABLES + short LFO_ENV_TAB [LFO_LENGHT]; // LFO AMS TABLE (adjusted for 11.8 dB) + short LFO_FREQ_TAB [LFO_LENGHT]; // LFO FMS TABLE +#endif +#ifdef YM2612_USE_TL_TAB + int TL_TAB [TL_LENGHT * 2]; // TOTAL LEVEL TABLE (positif and minus) +#endif + unsigned int DECAY_TO_ATTACK [ENV_LENGHT]; // Conversion from decay to attack phase + unsigned int FINC_TAB [2048]; // Frequency step table +}; + +struct Ym2612_Impl +{ + struct state_t YM2612; + int mute_mask; + struct tables_t g; +}; + +void impl_reset( struct Ym2612_Impl* impl ); + +struct Ym2612_Emu { + struct Ym2612_Impl impl; + + // Impl + int last_time; + int sample_rate; + int clock_rate; + short* out; +}; + +static inline void Ym2612_init( struct Ym2612_Emu* this_ ) +{ + this_->last_time = ym2612_disabled_time; this_->out = 0; + this_->impl.mute_mask = 0; +} + +// Sets sample rate and chip clock rate, in Hz. Returns non-zero +// if error. If clock_rate=0, uses sample_rate*144 +const char* Ym2612_set_rate( struct Ym2612_Emu* this_, int sample_rate, int clock_rate ); + +// Resets to power-up state +void Ym2612_reset( struct Ym2612_Emu* this_ ); + +// Mutes voice n if bit n (1 << n) of mask is set +void Ym2612_mute_voices( struct Ym2612_Emu* this_, int mask ); + +// Writes addr to register 0 then data to register 1 +void Ym2612_write0( struct Ym2612_Emu* this_, int addr, int data ); + +// Writes addr to register 2 then data to register 3 +void Ym2612_write1( struct Ym2612_Emu* this_, int addr, int data ); + +// Runs and adds pair_count*2 samples into current output buffer contents +void Ym2612_run( struct Ym2612_Emu* this_, int pair_count, short* out ); + +static inline void Ym2612_enable( struct Ym2612_Emu* this_, bool b ) { this_->last_time = b ? 0 : ym2612_disabled_time; } +static inline bool Ym2612_enabled( struct Ym2612_Emu* this_ ) { return this_->last_time != ym2612_disabled_time; } +static inline void Ym2612_begin_frame( struct Ym2612_Emu* this_, short* buf ) { this_->out = buf; this_->last_time = 0; } + +static inline int Ym2612_run_until( struct Ym2612_Emu* this_, int time ) +{ + int count = time - this_->last_time; + if ( count > 0 ) + { + if ( this_->last_time < 0 ) + return false; + this_->last_time = time; + short* p = this_->out; + this_->out += count * ym2612_out_chan_count; + Ym2612_run( this_, count, p ); + } + return true; +} +#endif -- cgit v1.2.3