From 569285794b9112f0134ddad4bb886308ea4a7be6 Mon Sep 17 00:00:00 2001 From: Torne Wuff Date: Sun, 6 Nov 2011 22:44:25 +0000 Subject: Bulk convert all DOS line endings to UNIX. For the git migration we want a nice clean repository with UNIX line endings. git does not use svn:eol-style, we just need the file contents to be sane. Sorry everybody. I know this messes up blame. Scumbag *NIX developer says migrating to git will make line ending issues go away; commits giant change to svn which changes line endings anyway. :) git-svn-id: svn://svn.rockbox.org/rockbox/trunk@30924 a1c6a512-1295-4272-9138-f99709370657 --- apps/codecs/libgme/emu2413.c | 3962 +++++++++++++++++++++--------------------- 1 file changed, 1981 insertions(+), 1981 deletions(-) (limited to 'apps/codecs/libgme/emu2413.c') diff --git a/apps/codecs/libgme/emu2413.c b/apps/codecs/libgme/emu2413.c index a4637ce15b..01075821cb 100644 --- a/apps/codecs/libgme/emu2413.c +++ b/apps/codecs/libgme/emu2413.c @@ -1,1981 +1,1981 @@ -/*********************************************************************************** - - emu2413.c -- YM2413 emulator written by Mitsutaka Okazaki 2001 - - 2001 01-08 : Version 0.10 -- 1st version. - 2001 01-15 : Version 0.20 -- semi-public version. - 2001 01-16 : Version 0.30 -- 1st public version. - 2001 01-17 : Version 0.31 -- Fixed bassdrum problem. - : Version 0.32 -- LPF implemented. - 2001 01-18 : Version 0.33 -- Fixed the drum problem, refine the mix-down method. - -- Fixed the LFO bug. - 2001 01-24 : Version 0.35 -- Fixed the drum problem, - support undocumented EG behavior. - 2001 02-02 : Version 0.38 -- Improved the performance. - Fixed the hi-hat and cymbal model. - Fixed the default percussive datas. - Noise reduction. - Fixed the feedback problem. - 2001 03-03 : Version 0.39 -- Fixed some drum bugs. - Improved the performance. - 2001 03-04 : Version 0.40 -- Improved the feedback. - Change the default table size. - Clock and Rate can be changed during play. - 2001 06-24 : Version 0.50 -- Improved the hi-hat and the cymbal tone. - Added VRC7 patch (OPLL_reset_patch is changed). - Fixed OPLL_reset() bug. - Added OPLL_setMask, OPLL_getMask and OPLL_toggleMask. - Added OPLL_writeIO. - 2001 09-28 : Version 0.51 -- Removed the noise table. - 2002 01-28 : Version 0.52 -- Added Stereo mode. - 2002 02-07 : Version 0.53 -- Fixed some drum bugs. - 2002 02-20 : Version 0.54 -- Added the best quality mode. - 2002 03-02 : Version 0.55 -- Removed OPLL_init & OPLL_close. - 2002 05-30 : Version 0.60 -- Fixed HH&CYM generator and all voice datas. - 2004 04-10 : Version 0.61 -- Added YMF281B tone (defined by Chabin). - - 2011 03-22 : --------------- Modified by gama to use precalculated tables. - - References: - fmopl.c -- 1999,2000 written by Tatsuyuki Satoh (MAME development). - fmopl.c(fixed) -- (C) 2002 Jarek Burczynski. - s_opl.c -- 2001 written by Mamiya (NEZplug development). - fmgen.cpp -- 1999,2000 written by cisc. - fmpac.ill -- 2000 created by NARUTO. - MSX-Datapack - YMU757 data sheet - YM2143 data sheet - -**************************************************************************************/ -#include -#include -#include -#include -#include "emu2413.h" - -#include "emutables.h" -#if !defined(ROCKBOX) - #define EMU2413_CALCUL_TABLES -#else - #define EMU2413_COMPACTION - #include "emutables.h" -#endif - -#if defined(EMU2413_COMPACTION) && !defined(ROCKBOX) -#define OPLL_TONE_NUM 1 -static unsigned char default_inst[OPLL_TONE_NUM][(16 + 3) * 16] = { - { -#include "2413tone.h" - } -}; -#else -#define OPLL_TONE_NUM 3 -static unsigned char default_inst[OPLL_TONE_NUM][(16 + 3) * 16] = { - { -#include "2413tone.h" - }, - { -#include "vrc7tone.h" - }, - { -#include "281btone.h" - } -}; -#endif - -/* Size of Sintable ( 8 -- 18 can be used. 9 recommended.) */ -#define PG_BITS 9 -#define PG_WIDTH (1<>(b)) - -/* Leave the lower b bit(s). */ -#define LOWBITS(c,b) ((c)&((1<<(b))-1)) - -/* Expand x which is s bits to d bits. */ -#define EXPAND_BITS(x,s,d) ((x)<<((d)-(s))) - -/* Expand x which is s bits to d bits and fill expanded bits '1' */ -#define EXPAND_BITS_X(x,s,d) (((x)<<((d)-(s)))|((1<<((d)-(s)))-1)) - -/* Adjust envelope speed which depends on sampling rate. */ -#define RATE_ADJUST(x) (rate==49716?(e_uint32)x:(e_uint32)(((long long)(x)*clk/rate+36)/72)) - -#define MOD(o,x) (&(o)->slot[(x)<<1]) -#define CAR(o,x) (&(o)->slot[((x)<<1)|1]) - -#define BIT(s,b) (((s)>>(b))&1) - -/* Input clock */ -static e_uint32 clk = 844451141; -/* Sampling rate */ -static e_uint32 rate = 3354932; - -/* WaveTable for each envelope amp */ -static e_uint16 fullsintable[PG_WIDTH]; -static e_uint16 halfsintable[PG_WIDTH]; - -static e_uint16 *waveform[2] = { fullsintable, halfsintable }; - -/* LFO Table */ -#ifdef EMU2413_CALCUL_TABLES - static e_int32 pmtable[PM_PG_WIDTH]; - static e_int32 amtable[AM_PG_WIDTH]; - #define PMTABLE(x) pmtable[x] - #define AMTABLE(x) amtable[x] -#else - #define PMTABLE(x) (e_int32)pm_coeff[x] - #if (PM_PG_WIDTH != 256) - #error PM_PG_WIDTH must be set to 256 if EMU2413_CALCUL_TABLES is not defined - #endif - #define AMTABLE(x) (e_int32)am_coeff[x] - #if (AM_PG_WIDTH != 256) - #error AM_PG_WIDTH must be set to 256 if EMU2413_CALCUL_TABLES is not defined - #endif -#endif - -/* Phase delta for LFO */ -static e_uint32 pm_dphase; -static e_uint32 am_dphase; - -/* dB to Liner table */ -static e_int16 DB2LIN_TABLE[(DB_MUTE + DB_MUTE) * 2]; - -/* Liner to Log curve conversion table (for Attack rate). */ -#ifdef EMU2413_CALCUL_TABLES - static e_uint16 ar_adjust_table[1 << EG_BITS]; - #define AR_ADJUST_TABLE(x) ar_adjust_table[x] -#else - #define AR_ADJUST_TABLE(x) ar_adjust_coeff[x] - #if (EG_BITS != 7) - #error EG_BITS must be set to 7 if EMU2413_CALCUL_TABLES is not defined - #endif -#endif - -/* Empty voice data */ -static OPLL_PATCH null_patch = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - -/* Basic voice Data */ -static OPLL_PATCH default_patch[OPLL_TONE_NUM][(16 + 3) * 2]; - -/* Definition of envelope mode */ -enum OPLL_EG_STATE -{ READY, ATTACK, DECAY, SUSHOLD, SUSTINE, RELEASE, SETTLE, FINISH }; - -/* Phase incr table for Attack */ -static e_uint32 dphaseARTable[16][16]; -/* Phase incr table for Decay and Release */ -static e_uint32 dphaseDRTable[16][16]; - -/* KSL + TL Table */ -e_uint8 tllTable[16][8][1 << TL_BITS][4]; -static e_int32 rksTable[2][8][2]; - -/* We may not have too much SRAM in rockbox */ -#if !defined(ROCKBOX) -/* Phase incr table for PG */ -static e_uint32 dphaseTable[512][8][16]; -#endif - -/*************************************************** - - Create tables - -****************************************************/ -#ifdef EMU2413_CALCUL_TABLES -INLINE static e_int32 -Min (e_int32 i, e_int32 j) -{ - if (i < j) - return i; - else - return j; -} - -/* Table for AR to LogCurve. */ -static void -makeAdjustTable (void) -{ - e_int32 i; - - ar_adjust_table[0] = (1 << EG_BITS) - 1; - for (i = 1; i < (1<= DB_MUTE) DB2LIN_TABLE[i] = 0; - DB2LIN_TABLE[i + DB_MUTE + DB_MUTE] = (e_int16) (-DB2LIN_TABLE[i]); - } -} - -#ifdef EMU2413_CALCUL_TABLES -/* Liner(+0.0 - +1.0) to dB((1<> (20 - DP_BITS)); -} -#endif - -static void -makeTllTable (void) -{ -/* Multiplication owith 8 to have an integer result. This allows to remove floating point operation. */ -#define dB2(x) (int)((x)*2*8) - - static int kltable[16] = { - dB2 ( 0.000), dB2 ( 9.000), dB2 (12.000), dB2 (13.875), dB2 (15.000), dB2 (16.125), dB2 (16.875), dB2 (17.625), - dB2 (18.000), dB2 (18.750), dB2 (19.125), dB2 (19.500), dB2 (19.875), dB2 (20.250), dB2 (20.625), dB2 (21.000) - }; - - e_int32 tmp; - e_int32 fnum, block, TL, KL; - - for (fnum = 0; fnum < 16; fnum++) - for (block = 0; block < 8; block++) - for (TL = 0; TL < 64; TL++) - for (KL = 0; KL < 4; KL++) - { - if (KL == 0) - { - tllTable[fnum][block][TL][KL] = TL2EG (TL); - } - else - { - tmp = (e_int32) ((kltable[fnum] - dB2 (3.000) * (7 - block))/8); - if (tmp <= 0) - tllTable[fnum][block][TL][KL] = TL2EG (TL); - else - /* tllTable[fnum][block][TL][KL] = (e_uint32) ((tmp >> (3 - KL)) / EG_STEP) + TL2EG (TL); */ - tllTable[fnum][block][TL][KL] = (e_uint32) ((tmp << KL) / (int)(EG_STEP*8)) + TL2EG (TL); - } - } -} - -#ifdef USE_SPEC_ENV_SPEED -static double attacktime[16][4] = { - {0, 0, 0, 0}, - {1730.15, 1400.60, 1153.43, 988.66}, - {865.08, 700.30, 576.72, 494.33}, - {432.54, 350.15, 288.36, 247.16}, - {216.27, 175.07, 144.18, 123.58}, - {108.13, 87.54, 72.09, 61.79}, - {54.07, 43.77, 36.04, 30.90}, - {27.03, 21.88, 18.02, 15.45}, - {13.52, 10.94, 9.01, 7.72}, - {6.76, 5.47, 4.51, 3.86}, - {3.38, 2.74, 2.25, 1.93}, - {1.69, 1.37, 1.13, 0.97}, - {0.84, 0.70, 0.60, 0.54}, - {0.50, 0.42, 0.34, 0.30}, - {0.28, 0.22, 0.18, 0.14}, - {0.00, 0.00, 0.00, 0.00} -}; - -static double decaytime[16][4] = { - {0, 0, 0, 0}, - {20926.60, 16807.20, 14006.00, 12028.60}, - {10463.30, 8403.58, 7002.98, 6014.32}, - {5231.64, 4201.79, 3501.49, 3007.16}, - {2615.82, 2100.89, 1750.75, 1503.58}, - {1307.91, 1050.45, 875.37, 751.79}, - {653.95, 525.22, 437.69, 375.90}, - {326.98, 262.61, 218.84, 187.95}, - {163.49, 131.31, 109.42, 93.97}, - {81.74, 65.65, 54.71, 46.99}, - {40.87, 32.83, 27.36, 23.49}, - {20.44, 16.41, 13.68, 11.75}, - {10.22, 8.21, 6.84, 5.87}, - {5.11, 4.10, 3.42, 2.94}, - {2.55, 2.05, 1.71, 1.47}, - {1.27, 1.27, 1.27, 1.27} -}; -#endif - -/* Rate Table for Attack */ -static void -makeDphaseARTable (void) -{ - e_int32 AR, Rks, RM, RL; - -#ifdef USE_SPEC_ENV_SPEED - e_uint32 attacktable[16][4]; - - for (RM = 0; RM < 16; RM++) - for (RL = 0; RL < 4; RL++) - { - if (RM == 0) - attacktable[RM][RL] = 0; - else if (RM == 15) - attacktable[RM][RL] = EG_DP_WIDTH; - else - attacktable[RM][RL] = (e_uint32) ((double) (1 << EG_DP_BITS) / (attacktime[RM][RL] * 3579545 / 72000)); - - } -#endif - - for (AR = 0; AR < 16; AR++) - for (Rks = 0; Rks < 16; Rks++) - { - RM = AR + (Rks >> 2); - RL = Rks & 3; - if (RM > 15) - RM = 15; - switch (AR) - { - case 0: - dphaseARTable[AR][Rks] = 0; - break; - case 15: - dphaseARTable[AR][Rks] = 0;/*EG_DP_WIDTH;*/ - break; - default: -#ifdef USE_SPEC_ENV_SPEED - dphaseARTable[AR][Rks] = RATE_ADJUST (attacktable[RM][RL]); -#else - dphaseARTable[AR][Rks] = RATE_ADJUST ((3 * (RL + 4) << (RM + 1))); -#endif - break; - } - } -} - -/* Rate Table for Decay and Release */ -static void -makeDphaseDRTable (void) -{ - e_int32 DR, Rks, RM, RL; - -#ifdef USE_SPEC_ENV_SPEED - e_uint32 decaytable[16][4]; - - for (RM = 0; RM < 16; RM++) - for (RL = 0; RL < 4; RL++) - if (RM == 0) - decaytable[RM][RL] = 0; - else - decaytable[RM][RL] = (e_uint32) ((double) (1 << EG_DP_BITS) / (decaytime[RM][RL] * 3579545 / 72000)); -#endif - - for (DR = 0; DR < 16; DR++) - for (Rks = 0; Rks < 16; Rks++) - { - RM = DR + (Rks >> 2); - RL = Rks & 3; - if (RM > 15) - RM = 15; - switch (DR) - { - case 0: - dphaseDRTable[DR][Rks] = 0; - break; - default: -#ifdef USE_SPEC_ENV_SPEED - dphaseDRTable[DR][Rks] = RATE_ADJUST (decaytable[RM][RL]); -#else - dphaseDRTable[DR][Rks] = RATE_ADJUST ((RL + 4) << (RM - 1)); -#endif - break; - } - } -} - -static void -makeRksTable (void) -{ - - e_int32 fnum8, block, KR; - - for (fnum8 = 0; fnum8 < 2; fnum8++) - for (block = 0; block < 8; block++) - for (KR = 0; KR < 2; KR++) - { - if (KR != 0) - rksTable[fnum8][block][KR] = (block << 1) + fnum8; - else - rksTable[fnum8][block][KR] = block >> 1; - } -} - -void -OPLL_dump2patch (const e_uint8 * dump, OPLL_PATCH * patch) -{ - patch[0].AM = (dump[0] >> 7) & 1; - patch[1].AM = (dump[1] >> 7) & 1; - patch[0].PM = (dump[0] >> 6) & 1; - patch[1].PM = (dump[1] >> 6) & 1; - patch[0].EG = (dump[0] >> 5) & 1; - patch[1].EG = (dump[1] >> 5) & 1; - patch[0].KR = (dump[0] >> 4) & 1; - patch[1].KR = (dump[1] >> 4) & 1; - patch[0].ML = (dump[0]) & 15; - patch[1].ML = (dump[1]) & 15; - patch[0].KL = (dump[2] >> 6) & 3; - patch[1].KL = (dump[3] >> 6) & 3; - patch[0].TL = (dump[2]) & 63; - patch[0].FB = (dump[3]) & 7; - patch[0].WF = (dump[3] >> 3) & 1; - patch[1].WF = (dump[3] >> 4) & 1; - patch[0].AR = (dump[4] >> 4) & 15; - patch[1].AR = (dump[5] >> 4) & 15; - patch[0].DR = (dump[4]) & 15; - patch[1].DR = (dump[5]) & 15; - patch[0].SL = (dump[6] >> 4) & 15; - patch[1].SL = (dump[7] >> 4) & 15; - patch[0].RR = (dump[6]) & 15; - patch[1].RR = (dump[7]) & 15; -} - -void -OPLL_getDefaultPatch (e_int32 type, e_int32 num, OPLL_PATCH * patch) -{ - OPLL_dump2patch (default_inst[type] + num * 16, patch); -} - -static void -makeDefaultPatch ( void ) -{ - e_int32 i, j; - - for (i = 0; i < OPLL_TONE_NUM; i++) - for (j = 0; j < 19; j++) - OPLL_getDefaultPatch (i, j, &default_patch[i][j * 2]); - -} - -void -OPLL_setPatch (OPLL * opll, const e_uint8 * dump) -{ - OPLL_PATCH patch[2]; - int i; - - for (i = 0; i < 19; i++) - { - OPLL_dump2patch (dump + i * 16, patch); - memcpy (&opll->patch[i*2+0], &patch[0], sizeof (OPLL_PATCH)); - memcpy (&opll->patch[i*2+1], &patch[1], sizeof (OPLL_PATCH)); - } -} - -void -OPLL_patch2dump (const OPLL_PATCH * patch, e_uint8 * dump) -{ - dump[0] = (e_uint8) ((patch[0].AM << 7) + (patch[0].PM << 6) + (patch[0].EG << 5) + (patch[0].KR << 4) + patch[0].ML); - dump[1] = (e_uint8) ((patch[1].AM << 7) + (patch[1].PM << 6) + (patch[1].EG << 5) + (patch[1].KR << 4) + patch[1].ML); - dump[2] = (e_uint8) ((patch[0].KL << 6) + patch[0].TL); - dump[3] = (e_uint8) ((patch[1].KL << 6) + (patch[1].WF << 4) + (patch[0].WF << 3) + patch[0].FB); - dump[4] = (e_uint8) ((patch[0].AR << 4) + patch[0].DR); - dump[5] = (e_uint8) ((patch[1].AR << 4) + patch[1].DR); - dump[6] = (e_uint8) ((patch[0].SL << 4) + patch[0].RR); - dump[7] = (e_uint8) ((patch[1].SL << 4) + patch[1].RR); - dump[8] = 0; - dump[9] = 0; - dump[10] = 0; - dump[11] = 0; - dump[12] = 0; - dump[13] = 0; - dump[14] = 0; - dump[15] = 0; -} - -/************************************************************ - - Calc Parameters - -************************************************************/ - -INLINE static e_uint32 -calc_eg_dphase (OPLL_SLOT * slot) -{ - - switch (slot->eg_mode) - { - case ATTACK: - return dphaseARTable[slot->patch->AR][slot->rks]; - - case DECAY: - return dphaseDRTable[slot->patch->DR][slot->rks]; - - case SUSHOLD: - return 0; - - case SUSTINE: - return dphaseDRTable[slot->patch->RR][slot->rks]; - - case RELEASE: - if (slot->sustine) - return dphaseDRTable[5][slot->rks]; - else if (slot->patch->EG) - return dphaseDRTable[slot->patch->RR][slot->rks]; - else - return dphaseDRTable[7][slot->rks]; - - case SETTLE: - return dphaseDRTable[15][0]; - - case FINISH: - return 0; - - default: - return 0; - } -} - -/************************************************************* - - OPLL internal interfaces - -*************************************************************/ -#define SLOT_BD1 12 -#define SLOT_BD2 13 -#define SLOT_HH 14 -#define SLOT_SD 15 -#define SLOT_TOM 16 -#define SLOT_CYM 17 - -/* We will set this dinamically, but not sure if this affects playback */ -#if defined(ROCKBOX) -INLINE static void -UPDATE_PG(OPLL_SLOT * slot) -{ - static const e_uint32 mltable[16] = - { 1, 1 * 2, 2 * 2, 3 * 2, 4 * 2, 5 * 2, 6 * 2, 7 * 2, 8 * 2, 9 * 2, 10 * 2, 10 * 2, 12 * 2, 12 * 2, 15 * 2, 15 * 2 }; - - slot->dphase = RATE_ADJUST (((slot->fnum * mltable[slot->patch->ML]) << slot->block) >> (20 - DP_BITS)); -} -#else -#define UPDATE_PG(S) (S)->dphase = dphaseTable[(S)->fnum][(S)->block][(S)->patch->ML] -#endif - -#define UPDATE_TLL(S)\ -(((S)->type==0)?\ -((S)->tll = tllTable[((S)->fnum)>>5][(S)->block][(S)->patch->TL][(S)->patch->KL]):\ -((S)->tll = tllTable[((S)->fnum)>>5][(S)->block][(S)->volume][(S)->patch->KL])) -#define UPDATE_RKS(S) (S)->rks = rksTable[((S)->fnum)>>8][(S)->block][(S)->patch->KR] -#define UPDATE_WF(S) (S)->sintbl = waveform[(S)->patch->WF] -#define UPDATE_EG(S) (S)->eg_dphase = calc_eg_dphase(S) -#define UPDATE_ALL(S)\ - UPDATE_PG(S);\ - UPDATE_TLL(S);\ - UPDATE_RKS(S);\ - UPDATE_WF(S); \ - UPDATE_EG(S) /* EG should be updated last. */ - - -/* Slot key on */ -INLINE static void -slotOn (OPLL_SLOT * slot) -{ - slot->eg_mode = ATTACK; - slot->eg_phase = 0; - slot->phase = 0; - UPDATE_EG(slot); -} - -/* Slot key on without reseting the phase */ -INLINE static void -slotOn2 (OPLL_SLOT * slot) -{ - slot->eg_mode = ATTACK; - slot->eg_phase = 0; - UPDATE_EG(slot); -} - -/* Slot key off */ -INLINE static void -slotOff (OPLL_SLOT * slot) -{ - if (slot->eg_mode == ATTACK) - slot->eg_phase = EXPAND_BITS (AR_ADJUST_TABLE(HIGHBITS (slot->eg_phase, EG_DP_BITS - EG_BITS)), EG_BITS, EG_DP_BITS); - slot->eg_mode = RELEASE; - UPDATE_EG(slot); -} - -/* Channel key on */ -INLINE static void -keyOn (OPLL * opll, e_int32 i) -{ - if (!opll->slot_on_flag[i * 2]) - slotOn (MOD(opll,i)); - if (!opll->slot_on_flag[i * 2 + 1]) - slotOn (CAR(opll,i)); - opll->key_status[i] = 1; -} - -/* Channel key off */ -INLINE static void -keyOff (OPLL * opll, e_int32 i) -{ - if (opll->slot_on_flag[i * 2 + 1]) - slotOff (CAR(opll,i)); - opll->key_status[i] = 0; -} - -INLINE static void -keyOn_BD (OPLL * opll) -{ - keyOn (opll, 6); -} -INLINE static void -keyOn_SD (OPLL * opll) -{ - if (!opll->slot_on_flag[SLOT_SD]) - slotOn (CAR(opll,7)); -} -INLINE static void -keyOn_TOM (OPLL * opll) -{ - if (!opll->slot_on_flag[SLOT_TOM]) - slotOn (MOD(opll,8)); -} -INLINE static void -keyOn_HH (OPLL * opll) -{ - if (!opll->slot_on_flag[SLOT_HH]) - slotOn2 (MOD(opll,7)); -} -INLINE static void -keyOn_CYM (OPLL * opll) -{ - if (!opll->slot_on_flag[SLOT_CYM]) - slotOn2 (CAR(opll,8)); -} - -/* Drum key off */ -INLINE static void -keyOff_BD (OPLL * opll) -{ - keyOff (opll, 6); -} -INLINE static void -keyOff_SD (OPLL * opll) -{ - if (opll->slot_on_flag[SLOT_SD]) - slotOff (CAR(opll,7)); -} -INLINE static void -keyOff_TOM (OPLL * opll) -{ - if (opll->slot_on_flag[SLOT_TOM]) - slotOff (MOD(opll,8)); -} -INLINE static void -keyOff_HH (OPLL * opll) -{ - if (opll->slot_on_flag[SLOT_HH]) - slotOff (MOD(opll,7)); -} -INLINE static void -keyOff_CYM (OPLL * opll) -{ - if (opll->slot_on_flag[SLOT_CYM]) - slotOff (CAR(opll,8)); -} - -/* Change a voice */ -INLINE static void -setPatch (OPLL * opll, e_int32 i, e_int32 num) -{ - opll->patch_number[i] = num; - MOD(opll,i)->patch = &opll->patch[num * 2 + 0]; - CAR(opll,i)->patch = &opll->patch[num * 2 + 1]; -} - -/* Change a rhythm voice */ -INLINE static void -setSlotPatch (OPLL_SLOT * slot, OPLL_PATCH * patch) -{ - slot->patch = patch; -} - -/* Set sustine parameter */ -INLINE static void -setSustine (OPLL * opll, e_int32 c, e_int32 sustine) -{ - CAR(opll,c)->sustine = sustine; - if (MOD(opll,c)->type) - MOD(opll,c)->sustine = sustine; -} - -/* Volume : 6bit ( Volume register << 2 ) */ -INLINE static void -setVolume (OPLL * opll, e_int32 c, e_int32 volume) -{ - CAR(opll,c)->volume = volume; -} - -INLINE static void -setSlotVolume (OPLL_SLOT * slot, e_int32 volume) -{ - slot->volume = volume; -} - -/* Set F-Number ( fnum : 9bit ) */ -INLINE static void -setFnumber (OPLL * opll, e_int32 c, e_int32 fnum) -{ - CAR(opll,c)->fnum = fnum; - MOD(opll,c)->fnum = fnum; -} - -/* Set Block data (block : 3bit ) */ -INLINE static void -setBlock (OPLL * opll, e_int32 c, e_int32 block) -{ - CAR(opll,c)->block = block; - MOD(opll,c)->block = block; -} - -/* Change Rhythm Mode */ -INLINE static void -update_rhythm_mode (OPLL * opll) -{ - if (opll->patch_number[6] & 0x10) - { - if (!(opll->slot_on_flag[SLOT_BD2] | (opll->reg[0x0e] & 32))) - { - opll->slot[SLOT_BD1].eg_mode = FINISH; - opll->slot[SLOT_BD2].eg_mode = FINISH; - setPatch (opll, 6, opll->reg[0x36] >> 4); - } - } - else if (opll->reg[0x0e] & 32) - { - opll->patch_number[6] = 16; - opll->slot[SLOT_BD1].eg_mode = FINISH; - opll->slot[SLOT_BD2].eg_mode = FINISH; - setSlotPatch (&opll->slot[SLOT_BD1], &opll->patch[16 * 2 + 0]); - setSlotPatch (&opll->slot[SLOT_BD2], &opll->patch[16 * 2 + 1]); - } - - if (opll->patch_number[7] & 0x10) - { - if (!((opll->slot_on_flag[SLOT_HH] && opll->slot_on_flag[SLOT_SD]) | (opll->reg[0x0e] & 32))) - { - opll->slot[SLOT_HH].type = 0; - opll->slot[SLOT_HH].eg_mode = FINISH; - opll->slot[SLOT_SD].eg_mode = FINISH; - setPatch (opll, 7, opll->reg[0x37] >> 4); - } - } - else if (opll->reg[0x0e] & 32) - { - opll->patch_number[7] = 17; - opll->slot[SLOT_HH].type = 1; - opll->slot[SLOT_HH].eg_mode = FINISH; - opll->slot[SLOT_SD].eg_mode = FINISH; - setSlotPatch (&opll->slot[SLOT_HH], &opll->patch[17 * 2 + 0]); - setSlotPatch (&opll->slot[SLOT_SD], &opll->patch[17 * 2 + 1]); - } - - if (opll->patch_number[8] & 0x10) - { - if (!((opll->slot_on_flag[SLOT_CYM] && opll->slot_on_flag[SLOT_TOM]) | (opll->reg[0x0e] & 32))) - { - opll->slot[SLOT_TOM].type = 0; - opll->slot[SLOT_TOM].eg_mode = FINISH; - opll->slot[SLOT_CYM].eg_mode = FINISH; - setPatch (opll, 8, opll->reg[0x38] >> 4); - } - } - else if (opll->reg[0x0e] & 32) - { - opll->patch_number[8] = 18; - opll->slot[SLOT_TOM].type = 1; - opll->slot[SLOT_TOM].eg_mode = FINISH; - opll->slot[SLOT_CYM].eg_mode = FINISH; - setSlotPatch (&opll->slot[SLOT_TOM], &opll->patch[18 * 2 + 0]); - setSlotPatch (&opll->slot[SLOT_CYM], &opll->patch[18 * 2 + 1]); - } -} - -INLINE static void -update_key_status (OPLL * opll) -{ - int ch; - - for (ch = 0; ch < 9; ch++) - opll->slot_on_flag[ch * 2] = opll->slot_on_flag[ch * 2 + 1] = (opll->reg[0x20 + ch]) & 0x10; - - if (opll->reg[0x0e] & 32) - { - opll->slot_on_flag[SLOT_BD1] |= (opll->reg[0x0e] & 0x10); - opll->slot_on_flag[SLOT_BD2] |= (opll->reg[0x0e] & 0x10); - opll->slot_on_flag[SLOT_SD] |= (opll->reg[0x0e] & 0x08); - opll->slot_on_flag[SLOT_HH] |= (opll->reg[0x0e] & 0x01); - opll->slot_on_flag[SLOT_TOM] |= (opll->reg[0x0e] & 0x04); - opll->slot_on_flag[SLOT_CYM] |= (opll->reg[0x0e] & 0x02); - } -} - -void -OPLL_copyPatch (OPLL * opll, e_int32 num, OPLL_PATCH * patch) -{ - memcpy (&opll->patch[num], patch, sizeof (OPLL_PATCH)); -} - -/*********************************************************** - - Initializing - -***********************************************************/ - -static void -OPLL_SLOT_reset (OPLL_SLOT * slot, int type) -{ - slot->type = type; - slot->sintbl = waveform[0]; - slot->phase = 0; - slot->dphase = 0; - slot->output[0] = 0; - slot->output[1] = 0; - slot->feedback = 0; - slot->eg_mode = FINISH; - slot->eg_phase = EG_DP_WIDTH; - slot->eg_dphase = 0; - slot->rks = 0; - slot->tll = 0; - slot->sustine = 0; - slot->fnum = 0; - slot->block = 0; - slot->volume = 0; - slot->pgout = 0; - slot->egout = 0; - slot->patch = &null_patch; -} - -static void -internal_refresh (void) -{ -#if !defined(ROCKBOX) - makeDphaseTable (); -#endif - makeDphaseARTable (); - makeDphaseDRTable (); - pm_dphase = (e_uint32) RATE_ADJUST ((int)(PM_SPEED * PM_DP_WIDTH) / (clk / 72)); - am_dphase = (e_uint32) RATE_ADJUST ((int)(AM_SPEED * AM_DP_WIDTH) / (clk / 72)); -} - -static void -maketables (e_uint32 c, e_uint32 r) -{ - if (c != clk) - { - clk = c; -#ifdef EMU2413_CALCUL_TABLES - makePmTable (); - makeAmTable (); - makeAdjustTable (); -#endif - makeDB2LinTable (); - makeTllTable (); - makeRksTable (); - makeSinTable (); - makeDefaultPatch (); - } - - if (r != rate) - { - rate = r; - internal_refresh (); - } -} - -void -OPLL_new (OPLL *opll, e_uint32 clk, e_uint32 rate) -{ - e_int32 i; - - maketables (clk, rate); - - memset(opll, 0, sizeof (OPLL)); - for (i = 0; i < 19 * 2; i++) - memcpy(&opll->patch[i],&null_patch,sizeof(OPLL_PATCH)); - - opll->mask = 0; - - OPLL_reset (opll); - OPLL_reset_patch (opll, 0); -} - - -void -OPLL_delete (OPLL * opll) -{ - (void) opll; -} - - -/* Reset patch datas by system default. */ -void -OPLL_reset_patch (OPLL * opll, e_int32 type) -{ - e_int32 i; - - for (i = 0; i < 19 * 2; i++) - OPLL_copyPatch (opll, i, &default_patch[type % OPLL_TONE_NUM][i]); -} - -/* Reset whole of OPLL except patch datas. */ -void -OPLL_reset (OPLL * opll) -{ - e_int32 i; - - if (!opll) - return; - - opll->adr = 0; - opll->out = 0; - - opll->pm_phase = 0; - opll->am_phase = 0; - - opll->noise_seed = 0xffff; - opll->mask = 0; - - for (i = 0; i <18; i++) - OPLL_SLOT_reset(&opll->slot[i], i%2); - - for (i = 0; i < 9; i++) - { - opll->key_status[i] = 0; - setPatch (opll, i, 0); - } - - for (i = 0; i < 0x40; i++) - OPLL_writeReg (opll, i, 0); - -#ifndef EMU2413_COMPACTION - opll->realstep = (e_uint32) ((1 << 31) / rate); - opll->opllstep = (e_uint32) ((1 << 31) / (clk / 72)); - opll->oplltime = 0; - for (i = 0; i < 14; i++) - opll->pan[i] = 2; - opll->sprev[0] = opll->sprev[1] = 0; - opll->snext[0] = opll->snext[1] = 0; -#endif -} - -/* Force Refresh (When external program changes some parameters). */ -void -OPLL_forceRefresh (OPLL * opll) -{ - e_int32 i; - - if (opll == NULL) - return; - - for (i = 0; i < 9; i++) - setPatch(opll,i,opll->patch_number[i]); - - for (i = 0; i < 18; i++) - { - UPDATE_PG (&opll->slot[i]); - UPDATE_RKS (&opll->slot[i]); - UPDATE_TLL (&opll->slot[i]); - UPDATE_WF (&opll->slot[i]); - UPDATE_EG (&opll->slot[i]); - } -} - -void -OPLL_set_rate (OPLL * opll, e_uint32 r) -{ - if (rate == r) return; - if (opll->quality) - rate = 49716; - else - rate = r; - internal_refresh (); - rate = r; -} - -void -OPLL_set_quality (OPLL * opll, e_uint32 q) -{ - opll->quality = q; - OPLL_set_rate (opll, rate); -} - -/********************************************************* - - Generate wave data - -*********************************************************/ -/* Convert Amp(0 to EG_HEIGHT) to Phase(0 to 2PI). */ -#if ( SLOT_AMP_BITS - PG_BITS ) > 0 -#define wave2_2pi(e) ( (e) >> ( SLOT_AMP_BITS - PG_BITS )) -#else -#define wave2_2pi(e) ( (e) << ( PG_BITS - SLOT_AMP_BITS )) -#endif - -/* Convert Amp(0 to EG_HEIGHT) to Phase(0 to 4PI). */ -#if ( SLOT_AMP_BITS - PG_BITS - 1 ) == 0 -#define wave2_4pi(e) (e) -#elif ( SLOT_AMP_BITS - PG_BITS - 1 ) > 0 -#define wave2_4pi(e) ( (e) >> ( SLOT_AMP_BITS - PG_BITS - 1 )) -#else -#define wave2_4pi(e) ( (e) << ( 1 + PG_BITS - SLOT_AMP_BITS )) -#endif - -/* Convert Amp(0 to EG_HEIGHT) to Phase(0 to 8PI). */ -#if ( SLOT_AMP_BITS - PG_BITS - 2 ) == 0 -#define wave2_8pi(e) (e) -#elif ( SLOT_AMP_BITS - PG_BITS - 2 ) > 0 -#define wave2_8pi(e) ( (e) >> ( SLOT_AMP_BITS - PG_BITS - 2 )) -#else -#define wave2_8pi(e) ( (e) << ( 2 + PG_BITS - SLOT_AMP_BITS )) -#endif - -/* Update AM, PM unit */ -INLINE static void -update_ampm (OPLL * opll) -{ - opll->pm_phase = (opll->pm_phase + pm_dphase) & (PM_DP_WIDTH - 1); - opll->am_phase = (opll->am_phase + am_dphase) & (AM_DP_WIDTH - 1); - opll->lfo_am = AMTABLE(HIGHBITS (opll->am_phase, AM_DP_BITS - AM_PG_BITS)); - opll->lfo_pm = PMTABLE(HIGHBITS (opll->pm_phase, PM_DP_BITS - PM_PG_BITS)); -} - -/* PG */ -INLINE static void -calc_phase (OPLL_SLOT * slot, e_int32 lfo) -{ - if (slot->patch->PM) - slot->phase += (slot->dphase * lfo) >> PM_AMP_BITS; - else - slot->phase += slot->dphase; - - slot->phase &= (DP_WIDTH - 1); - - slot->pgout = HIGHBITS (slot->phase, DP_BASE_BITS); -} - -/* Update Noise unit */ -INLINE static void -update_noise (OPLL * opll) -{ - if(opll->noise_seed&1) opll->noise_seed ^= 0x8003020; - opll->noise_seed >>= 1; -} - -/* EG */ -INLINE static void -calc_envelope (OPLL_SLOT * slot, e_int32 lfo) -{ -#define S2E(x) (SL2EG((e_int32)(x/SL_STEP))<<(EG_DP_BITS-EG_BITS)) - - static e_uint32 SL[16] = { - S2E (0.0), S2E (3.0), S2E (6.0), S2E (9.0), S2E (12.0), S2E (15.0), S2E (18.0), S2E (21.0), - S2E (24.0), S2E (27.0), S2E (30.0), S2E (33.0), S2E (36.0), S2E (39.0), S2E (42.0), S2E (48.0) - }; - - e_uint32 egout; - - switch (slot->eg_mode) - { - case ATTACK: - egout = AR_ADJUST_TABLE(HIGHBITS (slot->eg_phase, EG_DP_BITS - EG_BITS)); - slot->eg_phase += slot->eg_dphase; - if((EG_DP_WIDTH & slot->eg_phase)||(slot->patch->AR==15)) - { - egout = 0; - slot->eg_phase = 0; - slot->eg_mode = DECAY; - UPDATE_EG (slot); - } - break; - - case DECAY: - egout = HIGHBITS (slot->eg_phase, EG_DP_BITS - EG_BITS); - slot->eg_phase += slot->eg_dphase; - if (slot->eg_phase >= SL[slot->patch->SL]) - { - if (slot->patch->EG) - { - slot->eg_phase = SL[slot->patch->SL]; - slot->eg_mode = SUSHOLD; - UPDATE_EG (slot); - } - else - { - slot->eg_phase = SL[slot->patch->SL]; - slot->eg_mode = SUSTINE; - UPDATE_EG (slot); - } - } - break; - - case SUSHOLD: - egout = HIGHBITS (slot->eg_phase, EG_DP_BITS - EG_BITS); - if (slot->patch->EG == 0) - { - slot->eg_mode = SUSTINE; - UPDATE_EG (slot); - } - break; - - case SUSTINE: - case RELEASE: - egout = HIGHBITS (slot->eg_phase, EG_DP_BITS - EG_BITS); - slot->eg_phase += slot->eg_dphase; - if (egout >= (1 << EG_BITS)) - { - slot->eg_mode = FINISH; - egout = (1 << EG_BITS) - 1; - } - break; - - case SETTLE: - egout = HIGHBITS (slot->eg_phase, EG_DP_BITS - EG_BITS); - slot->eg_phase += slot->eg_dphase; - if (egout >= (1 << EG_BITS)) - { - slot->eg_mode = ATTACK; - egout = (1 << EG_BITS) - 1; - UPDATE_EG(slot); - } - break; - - case FINISH: - egout = (1 << EG_BITS) - 1; - break; - - default: - egout = (1 << EG_BITS) - 1; - break; - } - - if (slot->patch->AM) - egout = EG2DB (egout + slot->tll) + lfo; - else - egout = EG2DB (egout + slot->tll); - - if (egout >= DB_MUTE) - egout = DB_MUTE - 1; - - slot->egout = egout | 3; -} - -/* CARRIOR */ -INLINE static e_int32 -calc_slot_car (OPLL_SLOT * slot, e_int32 fm) -{ - if (slot->egout >= (DB_MUTE - 1)) - { - slot->output[0] = 0; - } - else - { - slot->output[0] = DB2LIN_TABLE[slot->sintbl[(slot->pgout+wave2_8pi(fm))&(PG_WIDTH-1)] + slot->egout]; - } - - slot->output[1] = (slot->output[1] + slot->output[0]) >> 1; - return slot->output[1]; -} - -/* MODULATOR */ -INLINE static e_int32 -calc_slot_mod (OPLL_SLOT * slot) -{ - e_int32 fm; - - slot->output[1] = slot->output[0]; - - if (slot->egout >= (DB_MUTE - 1)) - { - slot->output[0] = 0; - } - else if (slot->patch->FB != 0) - { - fm = wave2_4pi (slot->feedback) >> (7 - slot->patch->FB); - slot->output[0] = DB2LIN_TABLE[slot->sintbl[(slot->pgout+fm)&(PG_WIDTH-1)] + slot->egout]; - } - else - { - slot->output[0] = DB2LIN_TABLE[slot->sintbl[slot->pgout] + slot->egout]; - } - - slot->feedback = (slot->output[1] + slot->output[0]) >> 1; - - return slot->feedback; - -} - -/* TOM */ -INLINE static e_int32 -calc_slot_tom (OPLL_SLOT * slot) -{ - if (slot->egout >= (DB_MUTE - 1)) - return 0; - - return DB2LIN_TABLE[slot->sintbl[slot->pgout] + slot->egout]; - -} - -/* SNARE */ -INLINE static e_int32 -calc_slot_snare (OPLL_SLOT * slot, e_uint32 noise) -{ - if(slot->egout>=(DB_MUTE-1)) - return 0; - - if(BIT(slot->pgout,7)) - return DB2LIN_TABLE[(noise?DB_POS(0):DB_POS(15))+slot->egout]; - else - return DB2LIN_TABLE[(noise?DB_NEG(0):DB_NEG(15))+slot->egout]; -} - -/* - TOP-CYM - */ -INLINE static e_int32 -calc_slot_cym (OPLL_SLOT * slot, e_uint32 pgout_hh) -{ - e_uint32 dbout; - - if (slot->egout >= (DB_MUTE - 1)) - return 0; - else if( - /* the same as fmopl.c */ - ((BIT(pgout_hh,PG_BITS-8)^BIT(pgout_hh,PG_BITS-1))|BIT(pgout_hh,PG_BITS-7)) ^ - /* different from fmopl.c */ - (BIT(slot->pgout,PG_BITS-7)&!BIT(slot->pgout,PG_BITS-5)) - ) - dbout = DB_NEG(3); - else - dbout = DB_POS(3); - - return DB2LIN_TABLE[dbout + slot->egout]; -} - -/* - HI-HAT -*/ -INLINE static e_int32 -calc_slot_hat (OPLL_SLOT *slot, e_int32 pgout_cym, e_uint32 noise) -{ - e_uint32 dbout; - - if (slot->egout >= (DB_MUTE - 1)) - return 0; - else if( - /* the same as fmopl.c */ - ((BIT(slot->pgout,PG_BITS-8)^BIT(slot->pgout,PG_BITS-1))|BIT(slot->pgout,PG_BITS-7)) ^ - /* different from fmopl.c */ - (BIT(pgout_cym,PG_BITS-7)&!BIT(pgout_cym,PG_BITS-5)) - ) - { - if(noise) - dbout = DB_NEG(12); - else - dbout = DB_NEG(24); - } - else - { - if(noise) - dbout = DB_POS(12); - else - dbout = DB_POS(24); - } - - return DB2LIN_TABLE[dbout + slot->egout]; -} - -static e_int16 -calc (OPLL * opll) EMU2413_CALC_ICODE; -static e_int16 -calc (OPLL * opll) -{ - e_int32 i; - - update_ampm (opll); - update_noise (opll); - - for (i = 0; i < 18; i++) - { - calc_phase(&opll->slot[i],opll->lfo_pm); - calc_envelope(&opll->slot[i],opll->lfo_am); - } - - e_uint32 channel_mask = opll->mask; - for (i = 0; i < 9; i++) { - if (CAR(opll,i)->eg_mode != FINISH) - channel_mask |= (1 << i); - } - - e_int32 mix = 0; - - /* CH6 */ - if (opll->patch_number[6] & 0x10) { - if (channel_mask & OPLL_MASK_CH (6)) { - mix += calc_slot_car (CAR(opll,6), calc_slot_mod(MOD(opll,6))); - channel_mask &= ~(1 << 6); - } - } - - /* CH7 */ - if (opll->patch_number[7] & 0x10) { - if (MOD(opll,7)->eg_mode != FINISH) - mix += calc_slot_hat (MOD(opll,7), CAR(opll,8)->pgout, opll->noise_seed&1); - if (channel_mask & OPLL_MASK_SD) { - mix -= calc_slot_snare (CAR(opll,7), opll->noise_seed&1); - channel_mask &= ~OPLL_MASK_SD; - } - } - - /* CH8 */ - if (opll->patch_number[8] & 0x10) { - if (MOD(opll,8)->eg_mode != FINISH) - mix += calc_slot_tom (MOD(opll,8)); - if (channel_mask & OPLL_MASK_CYM) { - mix -= calc_slot_cym (CAR(opll,8), MOD(opll,7)->pgout); - channel_mask &= ~OPLL_MASK_CYM; - } - } - - mix <<= 1; - - opll->current_mask = channel_mask; - for (i = 0; channel_mask; channel_mask >>= 1, ++i) { - if (channel_mask & 1) { - mix += calc_slot_car (CAR(opll,i), calc_slot_mod(MOD(opll,i))); - } - } - - return (e_int16) mix << 3; -} - -void -OPLL_set_internal_mute(OPLL * opll, e_uint32 mute) -{ - opll->internal_mute = mute; -} - -e_uint32 -OPLL_is_internal_muted(OPLL * opll) -{ - return opll->internal_mute; -} - -static e_uint32 -check_mute_helper(OPLL * opll) -{ - for (int i = 0; i < 6; i++) { - /* if (ch[i].car.eg_mode != FINISH) return 0; */ - if (!(opll->current_mask & OPLL_MASK_CH (i)) && (CAR(opll,i)->eg_mode != FINISH)) return 0; - } - - if (!(opll->reg[0x0e] & 0x20)) { - for(int i = 6; i < 9; i++) { - /* if (ch[i].car.eg_mode != FINISH) return 0; */ - if (!(opll->current_mask & OPLL_MASK_CH (i)) && (CAR(opll,i)->eg_mode != FINISH)) return 0; - } - } else { - /* if (ch[6].car.eg_mode != FINISH) return false; - if (ch[7].mod.eg_mode != FINISH) return false; - if (ch[7].car.eg_mode != FINISH) return false; - if (ch[8].mod.eg_mode != FINISH) return false; - if (ch[8].car.eg_mode != FINISH) return false; */ - if (!(opll->current_mask & OPLL_MASK_CH (6)) && (CAR(opll,6)->eg_mode != FINISH)) return 0; - if (!(opll->current_mask & OPLL_MASK_CH (7)) && (MOD(opll,7)->eg_mode != FINISH)) return 0; - if (!(opll->current_mask & OPLL_MASK_CH (7)) && (CAR(opll,7)->eg_mode != FINISH)) return 0; - if (!(opll->current_mask & OPLL_MASK_CH (8)) && (MOD(opll,8)->eg_mode != FINISH)) return 0; - if (!(opll->current_mask & OPLL_MASK_CH (8)) && (CAR(opll,8)->eg_mode != FINISH)) return 0; - } - - return 1; /* nothing is playing, then mute */ -} - -static void -check_mute(OPLL * opll) -{ - OPLL_set_internal_mute (opll, check_mute_helper (opll)); -} - -EMU2413_API e_int16 *OPLL_update_buffer(OPLL * opll, e_uint32 length) -{ - e_int16* buf = opll->buffer; - while (length--) { - *(buf++) = calc (opll); - } - check_mute (opll); - - return opll->buffer; -} - -#ifdef EMU2413_COMPACTION -e_int16 -OPLL_calc (OPLL * opll) -{ - return calc (opll); -} -#else -e_int16 -OPLL_calc (OPLL * opll) -{ - if (!opll->quality) - return calc (opll); - - while (opll->realstep > opll->oplltime) - { - opll->oplltime += opll->opllstep; - opll->prev = opll->next; - opll->next = calc (opll); - } - - opll->oplltime -= opll->realstep; - opll->out = (e_int16) (((double) opll->next * (opll->opllstep - opll->oplltime) - + (double) opll->prev * opll->oplltime) / opll->opllstep); - - return (e_int16) opll->out; -} -#endif - -e_uint32 -OPLL_setMask (OPLL * opll, e_uint32 mask) -{ - e_uint32 ret; - - if (opll) - { - ret = opll->mask; - opll->mask = mask; - return ret; - } - else - return 0; -} - -e_uint32 -OPLL_toggleMask (OPLL * opll, e_uint32 mask) -{ - e_uint32 ret; - - if (opll) - { - ret = opll->mask; - opll->mask ^= mask; - return ret; - } - else - return 0; -} - -/**************************************************** - - I/O Ctrl - -*****************************************************/ - -void -OPLL_writeReg (OPLL * opll, e_uint32 reg, e_uint32 data) -{ - e_int32 i, v, ch; - - data = data & 0xff; - reg = reg & 0x3f; - opll->reg[reg] = (e_uint8) data; - - switch (reg) - { - case 0x00: - opll->patch[0].AM = (data >> 7) & 1; - opll->patch[0].PM = (data >> 6) & 1; - opll->patch[0].EG = (data >> 5) & 1; - opll->patch[0].KR = (data >> 4) & 1; - opll->patch[0].ML = (data) & 15; - for (i = 0; i < 9; i++) - { - if (opll->patch_number[i] == 0) - { - UPDATE_PG (MOD(opll,i)); - UPDATE_RKS (MOD(opll,i)); - UPDATE_EG (MOD(opll,i)); - } - } - break; - - case 0x01: - opll->patch[1].AM = (data >> 7) & 1; - opll->patch[1].PM = (data >> 6) & 1; - opll->patch[1].EG = (data >> 5) & 1; - opll->patch[1].KR = (data >> 4) & 1; - opll->patch[1].ML = (data) & 15; - for (i = 0; i < 9; i++) - { - if (opll->patch_number[i] == 0) - { - UPDATE_PG (CAR(opll,i)); - UPDATE_RKS (CAR(opll,i)); - UPDATE_EG (CAR(opll,i)); - } - } - break; - - case 0x02: - opll->patch[0].KL = (data >> 6) & 3; - opll->patch[0].TL = (data) & 63; - for (i = 0; i < 9; i++) - { - if (opll->patch_number[i] == 0) - { - UPDATE_TLL(MOD(opll,i)); - } - } - break; - - case 0x03: - opll->patch[1].KL = (data >> 6) & 3; - opll->patch[1].WF = (data >> 4) & 1; - opll->patch[0].WF = (data >> 3) & 1; - opll->patch[0].FB = (data) & 7; - for (i = 0; i < 9; i++) - { - if (opll->patch_number[i] == 0) - { - UPDATE_WF(MOD(opll,i)); - UPDATE_WF(CAR(opll,i)); - } - } - break; - - case 0x04: - opll->patch[0].AR = (data >> 4) & 15; - opll->patch[0].DR = (data) & 15; - for (i = 0; i < 9; i++) - { - if (opll->patch_number[i] == 0) - { - UPDATE_EG (MOD(opll,i)); - } - } - break; - - case 0x05: - opll->patch[1].AR = (data >> 4) & 15; - opll->patch[1].DR = (data) & 15; - for (i = 0; i < 9; i++) - { - if (opll->patch_number[i] == 0) - { - UPDATE_EG(CAR(opll,i)); - } - } - break; - - case 0x06: - opll->patch[0].SL = (data >> 4) & 15; - opll->patch[0].RR = (data) & 15; - for (i = 0; i < 9; i++) - { - if (opll->patch_number[i] == 0) - { - UPDATE_EG (MOD(opll,i)); - } - } - break; - - case 0x07: - opll->patch[1].SL = (data >> 4) & 15; - opll->patch[1].RR = (data) & 15; - for (i = 0; i < 9; i++) - { - if (opll->patch_number[i] == 0) - { - UPDATE_EG (CAR(opll,i)); - } - } - break; - - case 0x0e: - update_rhythm_mode (opll); - if (data & 32) - { - if (data & 0x10) - keyOn_BD (opll); - else - keyOff_BD (opll); - if (data & 0x8) - keyOn_SD (opll); - else - keyOff_SD (opll); - if (data & 0x4) - keyOn_TOM (opll); - else - keyOff_TOM (opll); - if (data & 0x2) - keyOn_CYM (opll); - else - keyOff_CYM (opll); - if (data & 0x1) - keyOn_HH (opll); - else - keyOff_HH (opll); - } - update_key_status (opll); - - UPDATE_ALL (MOD(opll,6)); - UPDATE_ALL (CAR(opll,6)); - UPDATE_ALL (MOD(opll,7)); - UPDATE_ALL (CAR(opll,7)); - UPDATE_ALL (MOD(opll,8)); - UPDATE_ALL (CAR(opll,8)); - - break; - - case 0x0f: - break; - - case 0x10: - case 0x11: - case 0x12: - case 0x13: - case 0x14: - case 0x15: - case 0x16: - case 0x17: - case 0x18: - ch = reg - 0x10; - setFnumber (opll, ch, data + ((opll->reg[0x20 + ch] & 1) << 8)); - UPDATE_ALL (MOD(opll,ch)); - UPDATE_ALL (CAR(opll,ch)); - break; - - case 0x20: - case 0x21: - case 0x22: - case 0x23: - case 0x24: - case 0x25: - case 0x26: - case 0x27: - case 0x28: - ch = reg - 0x20; - setFnumber (opll, ch, ((data & 1) << 8) + opll->reg[0x10 + ch]); - setBlock (opll, ch, (data >> 1) & 7); - setSustine (opll, ch, (data >> 5) & 1); - if (data & 0x10) - keyOn (opll, ch); - else - keyOff (opll, ch); - UPDATE_ALL (MOD(opll,ch)); - UPDATE_ALL (CAR(opll,ch)); - update_key_status (opll); - update_rhythm_mode (opll); - break; - - case 0x30: - case 0x31: - case 0x32: - case 0x33: - case 0x34: - case 0x35: - case 0x36: - case 0x37: - case 0x38: - i = (data >> 4) & 15; - v = data & 15; - if ((opll->reg[0x0e] & 32) && (reg >= 0x36)) - { - switch (reg) - { - case 0x37: - setSlotVolume (MOD(opll,7), i << 2); - break; - case 0x38: - setSlotVolume (MOD(opll,8), i << 2); - break; - default: - break; - } - } - else - { - setPatch (opll, reg - 0x30, i); - } - setVolume (opll, reg - 0x30, v << 2); - UPDATE_ALL (MOD(opll,reg - 0x30)); - UPDATE_ALL (CAR(opll,reg - 0x30)); - break; - - default: - break; - - } -} - -void -OPLL_writeIO (OPLL * opll, e_uint32 adr, e_uint32 val) -{ - if (adr & 1) - OPLL_writeReg (opll, opll->adr, val); - else - opll->adr = val; -} - -e_uint32 -OPLL_read(OPLL * opll, e_uint32 a) -{ - if( !(a&1) ) - { - /* status port */ - return opll->status; - } - return 0xff; -} - -#ifndef EMU2413_COMPACTION -/* STEREO MODE (OPT) */ -void -OPLL_set_pan (OPLL * opll, e_uint32 ch, e_uint32 pan) -{ - opll->pan[ch & 15] = pan & 3; -} - -static void -calc_stereo (OPLL * opll, e_int32 out[2]) -{ - e_int32 b[4] = { 0, 0, 0, 0 }; /* Ignore, Right, Left, Center */ - e_int32 r[4] = { 0, 0, 0, 0 }; /* Ignore, Right, Left, Center */ - e_int32 i; - - update_ampm (opll); - update_noise (opll); - - for(i=0;i<18;i++) - { - calc_phase(&opll->slot[i],opll->lfo_pm); - calc_envelope(&opll->slot[i],opll->lfo_am); - } - - for (i = 0; i < 6; i++) - if (!(opll->mask & OPLL_MASK_CH (i)) && (CAR(opll,i)->eg_mode != FINISH)) - b[opll->pan[i]] += calc_slot_car (CAR(opll,i), calc_slot_mod (MOD(opll,i))); - - - if (opll->patch_number[6] <= 15) - { - if (!(opll->mask & OPLL_MASK_CH (6)) && (CAR(opll,6)->eg_mode != FINISH)) - b[opll->pan[6]] += calc_slot_car (CAR(opll,6), calc_slot_mod (MOD(opll,6))); - } - else - { - if (!(opll->mask & OPLL_MASK_BD) && (CAR(opll,6)->eg_mode != FINISH)) - r[opll->pan[9]] += calc_slot_car (CAR(opll,6), calc_slot_mod (MOD(opll,6))); - } - - if (opll->patch_number[7] <= 15) - { - if (!(opll->mask & OPLL_MASK_CH (7)) && (CAR (opll,7)->eg_mode != FINISH)) - b[opll->pan[7]] += calc_slot_car (CAR (opll,7), calc_slot_mod (MOD (opll,7))); - } - else - { - if (!(opll->mask & OPLL_MASK_HH) && (MOD (opll,7)->eg_mode != FINISH)) - r[opll->pan[10]] += calc_slot_hat (MOD (opll,7), CAR(opll,8)->pgout, opll->noise_seed&1); - if (!(opll->mask & OPLL_MASK_SD) && (CAR (opll,7)->eg_mode != FINISH)) - r[opll->pan[11]] -= calc_slot_snare (CAR (opll,7), opll->noise_seed&1); - } - - if (opll->patch_number[8] <= 15) - { - if (!(opll->mask & OPLL_MASK_CH (8)) && (CAR (opll,8)->eg_mode != FINISH)) - b[opll->pan[8]] += calc_slot_car (CAR (opll,8), calc_slot_mod (MOD (opll,8))); - } - else - { - if (!(opll->mask & OPLL_MASK_TOM) && (MOD (opll,8)->eg_mode != FINISH)) - r[opll->pan[12]] += calc_slot_tom (MOD (opll,8)); - if (!(opll->mask & OPLL_MASK_CYM) && (CAR (opll,8)->eg_mode != FINISH)) - r[opll->pan[13]] -= calc_slot_cym (CAR (opll,8), MOD(opll,7)->pgout); - } - - out[1] = (b[1] + b[3] + ((r[1] + r[3]) << 1)) <<3; - out[0] = (b[2] + b[3] + ((r[2] + r[3]) << 1)) <<3; -} - -void -OPLL_calc_stereo (OPLL * opll, e_int32 out[2]) -{ - if (!opll->quality) - { - calc_stereo (opll, out); - return; - } - - while (opll->realstep > opll->oplltime) - { - opll->oplltime += opll->opllstep; - opll->sprev[0] = opll->snext[0]; - opll->sprev[1] = opll->snext[1]; - calc_stereo (opll, opll->snext); - } - - opll->oplltime -= opll->realstep; - out[0] = (e_int16) (((double) opll->snext[0] * (opll->opllstep - opll->oplltime) - + (double) opll->sprev[0] * opll->oplltime) / opll->opllstep); - out[1] = (e_int16) (((double) opll->snext[1] * (opll->opllstep - opll->oplltime) - + (double) opll->sprev[1] * opll->oplltime) / opll->opllstep); -} -#endif /* EMU2413_COMPACTION */ +/*********************************************************************************** + + emu2413.c -- YM2413 emulator written by Mitsutaka Okazaki 2001 + + 2001 01-08 : Version 0.10 -- 1st version. + 2001 01-15 : Version 0.20 -- semi-public version. + 2001 01-16 : Version 0.30 -- 1st public version. + 2001 01-17 : Version 0.31 -- Fixed bassdrum problem. + : Version 0.32 -- LPF implemented. + 2001 01-18 : Version 0.33 -- Fixed the drum problem, refine the mix-down method. + -- Fixed the LFO bug. + 2001 01-24 : Version 0.35 -- Fixed the drum problem, + support undocumented EG behavior. + 2001 02-02 : Version 0.38 -- Improved the performance. + Fixed the hi-hat and cymbal model. + Fixed the default percussive datas. + Noise reduction. + Fixed the feedback problem. + 2001 03-03 : Version 0.39 -- Fixed some drum bugs. + Improved the performance. + 2001 03-04 : Version 0.40 -- Improved the feedback. + Change the default table size. + Clock and Rate can be changed during play. + 2001 06-24 : Version 0.50 -- Improved the hi-hat and the cymbal tone. + Added VRC7 patch (OPLL_reset_patch is changed). + Fixed OPLL_reset() bug. + Added OPLL_setMask, OPLL_getMask and OPLL_toggleMask. + Added OPLL_writeIO. + 2001 09-28 : Version 0.51 -- Removed the noise table. + 2002 01-28 : Version 0.52 -- Added Stereo mode. + 2002 02-07 : Version 0.53 -- Fixed some drum bugs. + 2002 02-20 : Version 0.54 -- Added the best quality mode. + 2002 03-02 : Version 0.55 -- Removed OPLL_init & OPLL_close. + 2002 05-30 : Version 0.60 -- Fixed HH&CYM generator and all voice datas. + 2004 04-10 : Version 0.61 -- Added YMF281B tone (defined by Chabin). + + 2011 03-22 : --------------- Modified by gama to use precalculated tables. + + References: + fmopl.c -- 1999,2000 written by Tatsuyuki Satoh (MAME development). + fmopl.c(fixed) -- (C) 2002 Jarek Burczynski. + s_opl.c -- 2001 written by Mamiya (NEZplug development). + fmgen.cpp -- 1999,2000 written by cisc. + fmpac.ill -- 2000 created by NARUTO. + MSX-Datapack + YMU757 data sheet + YM2143 data sheet + +**************************************************************************************/ +#include +#include +#include +#include +#include "emu2413.h" + +#include "emutables.h" +#if !defined(ROCKBOX) + #define EMU2413_CALCUL_TABLES +#else + #define EMU2413_COMPACTION + #include "emutables.h" +#endif + +#if defined(EMU2413_COMPACTION) && !defined(ROCKBOX) +#define OPLL_TONE_NUM 1 +static unsigned char default_inst[OPLL_TONE_NUM][(16 + 3) * 16] = { + { +#include "2413tone.h" + } +}; +#else +#define OPLL_TONE_NUM 3 +static unsigned char default_inst[OPLL_TONE_NUM][(16 + 3) * 16] = { + { +#include "2413tone.h" + }, + { +#include "vrc7tone.h" + }, + { +#include "281btone.h" + } +}; +#endif + +/* Size of Sintable ( 8 -- 18 can be used. 9 recommended.) */ +#define PG_BITS 9 +#define PG_WIDTH (1<>(b)) + +/* Leave the lower b bit(s). */ +#define LOWBITS(c,b) ((c)&((1<<(b))-1)) + +/* Expand x which is s bits to d bits. */ +#define EXPAND_BITS(x,s,d) ((x)<<((d)-(s))) + +/* Expand x which is s bits to d bits and fill expanded bits '1' */ +#define EXPAND_BITS_X(x,s,d) (((x)<<((d)-(s)))|((1<<((d)-(s)))-1)) + +/* Adjust envelope speed which depends on sampling rate. */ +#define RATE_ADJUST(x) (rate==49716?(e_uint32)x:(e_uint32)(((long long)(x)*clk/rate+36)/72)) + +#define MOD(o,x) (&(o)->slot[(x)<<1]) +#define CAR(o,x) (&(o)->slot[((x)<<1)|1]) + +#define BIT(s,b) (((s)>>(b))&1) + +/* Input clock */ +static e_uint32 clk = 844451141; +/* Sampling rate */ +static e_uint32 rate = 3354932; + +/* WaveTable for each envelope amp */ +static e_uint16 fullsintable[PG_WIDTH]; +static e_uint16 halfsintable[PG_WIDTH]; + +static e_uint16 *waveform[2] = { fullsintable, halfsintable }; + +/* LFO Table */ +#ifdef EMU2413_CALCUL_TABLES + static e_int32 pmtable[PM_PG_WIDTH]; + static e_int32 amtable[AM_PG_WIDTH]; + #define PMTABLE(x) pmtable[x] + #define AMTABLE(x) amtable[x] +#else + #define PMTABLE(x) (e_int32)pm_coeff[x] + #if (PM_PG_WIDTH != 256) + #error PM_PG_WIDTH must be set to 256 if EMU2413_CALCUL_TABLES is not defined + #endif + #define AMTABLE(x) (e_int32)am_coeff[x] + #if (AM_PG_WIDTH != 256) + #error AM_PG_WIDTH must be set to 256 if EMU2413_CALCUL_TABLES is not defined + #endif +#endif + +/* Phase delta for LFO */ +static e_uint32 pm_dphase; +static e_uint32 am_dphase; + +/* dB to Liner table */ +static e_int16 DB2LIN_TABLE[(DB_MUTE + DB_MUTE) * 2]; + +/* Liner to Log curve conversion table (for Attack rate). */ +#ifdef EMU2413_CALCUL_TABLES + static e_uint16 ar_adjust_table[1 << EG_BITS]; + #define AR_ADJUST_TABLE(x) ar_adjust_table[x] +#else + #define AR_ADJUST_TABLE(x) ar_adjust_coeff[x] + #if (EG_BITS != 7) + #error EG_BITS must be set to 7 if EMU2413_CALCUL_TABLES is not defined + #endif +#endif + +/* Empty voice data */ +static OPLL_PATCH null_patch = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + +/* Basic voice Data */ +static OPLL_PATCH default_patch[OPLL_TONE_NUM][(16 + 3) * 2]; + +/* Definition of envelope mode */ +enum OPLL_EG_STATE +{ READY, ATTACK, DECAY, SUSHOLD, SUSTINE, RELEASE, SETTLE, FINISH }; + +/* Phase incr table for Attack */ +static e_uint32 dphaseARTable[16][16]; +/* Phase incr table for Decay and Release */ +static e_uint32 dphaseDRTable[16][16]; + +/* KSL + TL Table */ +e_uint8 tllTable[16][8][1 << TL_BITS][4]; +static e_int32 rksTable[2][8][2]; + +/* We may not have too much SRAM in rockbox */ +#if !defined(ROCKBOX) +/* Phase incr table for PG */ +static e_uint32 dphaseTable[512][8][16]; +#endif + +/*************************************************** + + Create tables + +****************************************************/ +#ifdef EMU2413_CALCUL_TABLES +INLINE static e_int32 +Min (e_int32 i, e_int32 j) +{ + if (i < j) + return i; + else + return j; +} + +/* Table for AR to LogCurve. */ +static void +makeAdjustTable (void) +{ + e_int32 i; + + ar_adjust_table[0] = (1 << EG_BITS) - 1; + for (i = 1; i < (1<= DB_MUTE) DB2LIN_TABLE[i] = 0; + DB2LIN_TABLE[i + DB_MUTE + DB_MUTE] = (e_int16) (-DB2LIN_TABLE[i]); + } +} + +#ifdef EMU2413_CALCUL_TABLES +/* Liner(+0.0 - +1.0) to dB((1<> (20 - DP_BITS)); +} +#endif + +static void +makeTllTable (void) +{ +/* Multiplication owith 8 to have an integer result. This allows to remove floating point operation. */ +#define dB2(x) (int)((x)*2*8) + + static int kltable[16] = { + dB2 ( 0.000), dB2 ( 9.000), dB2 (12.000), dB2 (13.875), dB2 (15.000), dB2 (16.125), dB2 (16.875), dB2 (17.625), + dB2 (18.000), dB2 (18.750), dB2 (19.125), dB2 (19.500), dB2 (19.875), dB2 (20.250), dB2 (20.625), dB2 (21.000) + }; + + e_int32 tmp; + e_int32 fnum, block, TL, KL; + + for (fnum = 0; fnum < 16; fnum++) + for (block = 0; block < 8; block++) + for (TL = 0; TL < 64; TL++) + for (KL = 0; KL < 4; KL++) + { + if (KL == 0) + { + tllTable[fnum][block][TL][KL] = TL2EG (TL); + } + else + { + tmp = (e_int32) ((kltable[fnum] - dB2 (3.000) * (7 - block))/8); + if (tmp <= 0) + tllTable[fnum][block][TL][KL] = TL2EG (TL); + else + /* tllTable[fnum][block][TL][KL] = (e_uint32) ((tmp >> (3 - KL)) / EG_STEP) + TL2EG (TL); */ + tllTable[fnum][block][TL][KL] = (e_uint32) ((tmp << KL) / (int)(EG_STEP*8)) + TL2EG (TL); + } + } +} + +#ifdef USE_SPEC_ENV_SPEED +static double attacktime[16][4] = { + {0, 0, 0, 0}, + {1730.15, 1400.60, 1153.43, 988.66}, + {865.08, 700.30, 576.72, 494.33}, + {432.54, 350.15, 288.36, 247.16}, + {216.27, 175.07, 144.18, 123.58}, + {108.13, 87.54, 72.09, 61.79}, + {54.07, 43.77, 36.04, 30.90}, + {27.03, 21.88, 18.02, 15.45}, + {13.52, 10.94, 9.01, 7.72}, + {6.76, 5.47, 4.51, 3.86}, + {3.38, 2.74, 2.25, 1.93}, + {1.69, 1.37, 1.13, 0.97}, + {0.84, 0.70, 0.60, 0.54}, + {0.50, 0.42, 0.34, 0.30}, + {0.28, 0.22, 0.18, 0.14}, + {0.00, 0.00, 0.00, 0.00} +}; + +static double decaytime[16][4] = { + {0, 0, 0, 0}, + {20926.60, 16807.20, 14006.00, 12028.60}, + {10463.30, 8403.58, 7002.98, 6014.32}, + {5231.64, 4201.79, 3501.49, 3007.16}, + {2615.82, 2100.89, 1750.75, 1503.58}, + {1307.91, 1050.45, 875.37, 751.79}, + {653.95, 525.22, 437.69, 375.90}, + {326.98, 262.61, 218.84, 187.95}, + {163.49, 131.31, 109.42, 93.97}, + {81.74, 65.65, 54.71, 46.99}, + {40.87, 32.83, 27.36, 23.49}, + {20.44, 16.41, 13.68, 11.75}, + {10.22, 8.21, 6.84, 5.87}, + {5.11, 4.10, 3.42, 2.94}, + {2.55, 2.05, 1.71, 1.47}, + {1.27, 1.27, 1.27, 1.27} +}; +#endif + +/* Rate Table for Attack */ +static void +makeDphaseARTable (void) +{ + e_int32 AR, Rks, RM, RL; + +#ifdef USE_SPEC_ENV_SPEED + e_uint32 attacktable[16][4]; + + for (RM = 0; RM < 16; RM++) + for (RL = 0; RL < 4; RL++) + { + if (RM == 0) + attacktable[RM][RL] = 0; + else if (RM == 15) + attacktable[RM][RL] = EG_DP_WIDTH; + else + attacktable[RM][RL] = (e_uint32) ((double) (1 << EG_DP_BITS) / (attacktime[RM][RL] * 3579545 / 72000)); + + } +#endif + + for (AR = 0; AR < 16; AR++) + for (Rks = 0; Rks < 16; Rks++) + { + RM = AR + (Rks >> 2); + RL = Rks & 3; + if (RM > 15) + RM = 15; + switch (AR) + { + case 0: + dphaseARTable[AR][Rks] = 0; + break; + case 15: + dphaseARTable[AR][Rks] = 0;/*EG_DP_WIDTH;*/ + break; + default: +#ifdef USE_SPEC_ENV_SPEED + dphaseARTable[AR][Rks] = RATE_ADJUST (attacktable[RM][RL]); +#else + dphaseARTable[AR][Rks] = RATE_ADJUST ((3 * (RL + 4) << (RM + 1))); +#endif + break; + } + } +} + +/* Rate Table for Decay and Release */ +static void +makeDphaseDRTable (void) +{ + e_int32 DR, Rks, RM, RL; + +#ifdef USE_SPEC_ENV_SPEED + e_uint32 decaytable[16][4]; + + for (RM = 0; RM < 16; RM++) + for (RL = 0; RL < 4; RL++) + if (RM == 0) + decaytable[RM][RL] = 0; + else + decaytable[RM][RL] = (e_uint32) ((double) (1 << EG_DP_BITS) / (decaytime[RM][RL] * 3579545 / 72000)); +#endif + + for (DR = 0; DR < 16; DR++) + for (Rks = 0; Rks < 16; Rks++) + { + RM = DR + (Rks >> 2); + RL = Rks & 3; + if (RM > 15) + RM = 15; + switch (DR) + { + case 0: + dphaseDRTable[DR][Rks] = 0; + break; + default: +#ifdef USE_SPEC_ENV_SPEED + dphaseDRTable[DR][Rks] = RATE_ADJUST (decaytable[RM][RL]); +#else + dphaseDRTable[DR][Rks] = RATE_ADJUST ((RL + 4) << (RM - 1)); +#endif + break; + } + } +} + +static void +makeRksTable (void) +{ + + e_int32 fnum8, block, KR; + + for (fnum8 = 0; fnum8 < 2; fnum8++) + for (block = 0; block < 8; block++) + for (KR = 0; KR < 2; KR++) + { + if (KR != 0) + rksTable[fnum8][block][KR] = (block << 1) + fnum8; + else + rksTable[fnum8][block][KR] = block >> 1; + } +} + +void +OPLL_dump2patch (const e_uint8 * dump, OPLL_PATCH * patch) +{ + patch[0].AM = (dump[0] >> 7) & 1; + patch[1].AM = (dump[1] >> 7) & 1; + patch[0].PM = (dump[0] >> 6) & 1; + patch[1].PM = (dump[1] >> 6) & 1; + patch[0].EG = (dump[0] >> 5) & 1; + patch[1].EG = (dump[1] >> 5) & 1; + patch[0].KR = (dump[0] >> 4) & 1; + patch[1].KR = (dump[1] >> 4) & 1; + patch[0].ML = (dump[0]) & 15; + patch[1].ML = (dump[1]) & 15; + patch[0].KL = (dump[2] >> 6) & 3; + patch[1].KL = (dump[3] >> 6) & 3; + patch[0].TL = (dump[2]) & 63; + patch[0].FB = (dump[3]) & 7; + patch[0].WF = (dump[3] >> 3) & 1; + patch[1].WF = (dump[3] >> 4) & 1; + patch[0].AR = (dump[4] >> 4) & 15; + patch[1].AR = (dump[5] >> 4) & 15; + patch[0].DR = (dump[4]) & 15; + patch[1].DR = (dump[5]) & 15; + patch[0].SL = (dump[6] >> 4) & 15; + patch[1].SL = (dump[7] >> 4) & 15; + patch[0].RR = (dump[6]) & 15; + patch[1].RR = (dump[7]) & 15; +} + +void +OPLL_getDefaultPatch (e_int32 type, e_int32 num, OPLL_PATCH * patch) +{ + OPLL_dump2patch (default_inst[type] + num * 16, patch); +} + +static void +makeDefaultPatch ( void ) +{ + e_int32 i, j; + + for (i = 0; i < OPLL_TONE_NUM; i++) + for (j = 0; j < 19; j++) + OPLL_getDefaultPatch (i, j, &default_patch[i][j * 2]); + +} + +void +OPLL_setPatch (OPLL * opll, const e_uint8 * dump) +{ + OPLL_PATCH patch[2]; + int i; + + for (i = 0; i < 19; i++) + { + OPLL_dump2patch (dump + i * 16, patch); + memcpy (&opll->patch[i*2+0], &patch[0], sizeof (OPLL_PATCH)); + memcpy (&opll->patch[i*2+1], &patch[1], sizeof (OPLL_PATCH)); + } +} + +void +OPLL_patch2dump (const OPLL_PATCH * patch, e_uint8 * dump) +{ + dump[0] = (e_uint8) ((patch[0].AM << 7) + (patch[0].PM << 6) + (patch[0].EG << 5) + (patch[0].KR << 4) + patch[0].ML); + dump[1] = (e_uint8) ((patch[1].AM << 7) + (patch[1].PM << 6) + (patch[1].EG << 5) + (patch[1].KR << 4) + patch[1].ML); + dump[2] = (e_uint8) ((patch[0].KL << 6) + patch[0].TL); + dump[3] = (e_uint8) ((patch[1].KL << 6) + (patch[1].WF << 4) + (patch[0].WF << 3) + patch[0].FB); + dump[4] = (e_uint8) ((patch[0].AR << 4) + patch[0].DR); + dump[5] = (e_uint8) ((patch[1].AR << 4) + patch[1].DR); + dump[6] = (e_uint8) ((patch[0].SL << 4) + patch[0].RR); + dump[7] = (e_uint8) ((patch[1].SL << 4) + patch[1].RR); + dump[8] = 0; + dump[9] = 0; + dump[10] = 0; + dump[11] = 0; + dump[12] = 0; + dump[13] = 0; + dump[14] = 0; + dump[15] = 0; +} + +/************************************************************ + + Calc Parameters + +************************************************************/ + +INLINE static e_uint32 +calc_eg_dphase (OPLL_SLOT * slot) +{ + + switch (slot->eg_mode) + { + case ATTACK: + return dphaseARTable[slot->patch->AR][slot->rks]; + + case DECAY: + return dphaseDRTable[slot->patch->DR][slot->rks]; + + case SUSHOLD: + return 0; + + case SUSTINE: + return dphaseDRTable[slot->patch->RR][slot->rks]; + + case RELEASE: + if (slot->sustine) + return dphaseDRTable[5][slot->rks]; + else if (slot->patch->EG) + return dphaseDRTable[slot->patch->RR][slot->rks]; + else + return dphaseDRTable[7][slot->rks]; + + case SETTLE: + return dphaseDRTable[15][0]; + + case FINISH: + return 0; + + default: + return 0; + } +} + +/************************************************************* + + OPLL internal interfaces + +*************************************************************/ +#define SLOT_BD1 12 +#define SLOT_BD2 13 +#define SLOT_HH 14 +#define SLOT_SD 15 +#define SLOT_TOM 16 +#define SLOT_CYM 17 + +/* We will set this dinamically, but not sure if this affects playback */ +#if defined(ROCKBOX) +INLINE static void +UPDATE_PG(OPLL_SLOT * slot) +{ + static const e_uint32 mltable[16] = + { 1, 1 * 2, 2 * 2, 3 * 2, 4 * 2, 5 * 2, 6 * 2, 7 * 2, 8 * 2, 9 * 2, 10 * 2, 10 * 2, 12 * 2, 12 * 2, 15 * 2, 15 * 2 }; + + slot->dphase = RATE_ADJUST (((slot->fnum * mltable[slot->patch->ML]) << slot->block) >> (20 - DP_BITS)); +} +#else +#define UPDATE_PG(S) (S)->dphase = dphaseTable[(S)->fnum][(S)->block][(S)->patch->ML] +#endif + +#define UPDATE_TLL(S)\ +(((S)->type==0)?\ +((S)->tll = tllTable[((S)->fnum)>>5][(S)->block][(S)->patch->TL][(S)->patch->KL]):\ +((S)->tll = tllTable[((S)->fnum)>>5][(S)->block][(S)->volume][(S)->patch->KL])) +#define UPDATE_RKS(S) (S)->rks = rksTable[((S)->fnum)>>8][(S)->block][(S)->patch->KR] +#define UPDATE_WF(S) (S)->sintbl = waveform[(S)->patch->WF] +#define UPDATE_EG(S) (S)->eg_dphase = calc_eg_dphase(S) +#define UPDATE_ALL(S)\ + UPDATE_PG(S);\ + UPDATE_TLL(S);\ + UPDATE_RKS(S);\ + UPDATE_WF(S); \ + UPDATE_EG(S) /* EG should be updated last. */ + + +/* Slot key on */ +INLINE static void +slotOn (OPLL_SLOT * slot) +{ + slot->eg_mode = ATTACK; + slot->eg_phase = 0; + slot->phase = 0; + UPDATE_EG(slot); +} + +/* Slot key on without reseting the phase */ +INLINE static void +slotOn2 (OPLL_SLOT * slot) +{ + slot->eg_mode = ATTACK; + slot->eg_phase = 0; + UPDATE_EG(slot); +} + +/* Slot key off */ +INLINE static void +slotOff (OPLL_SLOT * slot) +{ + if (slot->eg_mode == ATTACK) + slot->eg_phase = EXPAND_BITS (AR_ADJUST_TABLE(HIGHBITS (slot->eg_phase, EG_DP_BITS - EG_BITS)), EG_BITS, EG_DP_BITS); + slot->eg_mode = RELEASE; + UPDATE_EG(slot); +} + +/* Channel key on */ +INLINE static void +keyOn (OPLL * opll, e_int32 i) +{ + if (!opll->slot_on_flag[i * 2]) + slotOn (MOD(opll,i)); + if (!opll->slot_on_flag[i * 2 + 1]) + slotOn (CAR(opll,i)); + opll->key_status[i] = 1; +} + +/* Channel key off */ +INLINE static void +keyOff (OPLL * opll, e_int32 i) +{ + if (opll->slot_on_flag[i * 2 + 1]) + slotOff (CAR(opll,i)); + opll->key_status[i] = 0; +} + +INLINE static void +keyOn_BD (OPLL * opll) +{ + keyOn (opll, 6); +} +INLINE static void +keyOn_SD (OPLL * opll) +{ + if (!opll->slot_on_flag[SLOT_SD]) + slotOn (CAR(opll,7)); +} +INLINE static void +keyOn_TOM (OPLL * opll) +{ + if (!opll->slot_on_flag[SLOT_TOM]) + slotOn (MOD(opll,8)); +} +INLINE static void +keyOn_HH (OPLL * opll) +{ + if (!opll->slot_on_flag[SLOT_HH]) + slotOn2 (MOD(opll,7)); +} +INLINE static void +keyOn_CYM (OPLL * opll) +{ + if (!opll->slot_on_flag[SLOT_CYM]) + slotOn2 (CAR(opll,8)); +} + +/* Drum key off */ +INLINE static void +keyOff_BD (OPLL * opll) +{ + keyOff (opll, 6); +} +INLINE static void +keyOff_SD (OPLL * opll) +{ + if (opll->slot_on_flag[SLOT_SD]) + slotOff (CAR(opll,7)); +} +INLINE static void +keyOff_TOM (OPLL * opll) +{ + if (opll->slot_on_flag[SLOT_TOM]) + slotOff (MOD(opll,8)); +} +INLINE static void +keyOff_HH (OPLL * opll) +{ + if (opll->slot_on_flag[SLOT_HH]) + slotOff (MOD(opll,7)); +} +INLINE static void +keyOff_CYM (OPLL * opll) +{ + if (opll->slot_on_flag[SLOT_CYM]) + slotOff (CAR(opll,8)); +} + +/* Change a voice */ +INLINE static void +setPatch (OPLL * opll, e_int32 i, e_int32 num) +{ + opll->patch_number[i] = num; + MOD(opll,i)->patch = &opll->patch[num * 2 + 0]; + CAR(opll,i)->patch = &opll->patch[num * 2 + 1]; +} + +/* Change a rhythm voice */ +INLINE static void +setSlotPatch (OPLL_SLOT * slot, OPLL_PATCH * patch) +{ + slot->patch = patch; +} + +/* Set sustine parameter */ +INLINE static void +setSustine (OPLL * opll, e_int32 c, e_int32 sustine) +{ + CAR(opll,c)->sustine = sustine; + if (MOD(opll,c)->type) + MOD(opll,c)->sustine = sustine; +} + +/* Volume : 6bit ( Volume register << 2 ) */ +INLINE static void +setVolume (OPLL * opll, e_int32 c, e_int32 volume) +{ + CAR(opll,c)->volume = volume; +} + +INLINE static void +setSlotVolume (OPLL_SLOT * slot, e_int32 volume) +{ + slot->volume = volume; +} + +/* Set F-Number ( fnum : 9bit ) */ +INLINE static void +setFnumber (OPLL * opll, e_int32 c, e_int32 fnum) +{ + CAR(opll,c)->fnum = fnum; + MOD(opll,c)->fnum = fnum; +} + +/* Set Block data (block : 3bit ) */ +INLINE static void +setBlock (OPLL * opll, e_int32 c, e_int32 block) +{ + CAR(opll,c)->block = block; + MOD(opll,c)->block = block; +} + +/* Change Rhythm Mode */ +INLINE static void +update_rhythm_mode (OPLL * opll) +{ + if (opll->patch_number[6] & 0x10) + { + if (!(opll->slot_on_flag[SLOT_BD2] | (opll->reg[0x0e] & 32))) + { + opll->slot[SLOT_BD1].eg_mode = FINISH; + opll->slot[SLOT_BD2].eg_mode = FINISH; + setPatch (opll, 6, opll->reg[0x36] >> 4); + } + } + else if (opll->reg[0x0e] & 32) + { + opll->patch_number[6] = 16; + opll->slot[SLOT_BD1].eg_mode = FINISH; + opll->slot[SLOT_BD2].eg_mode = FINISH; + setSlotPatch (&opll->slot[SLOT_BD1], &opll->patch[16 * 2 + 0]); + setSlotPatch (&opll->slot[SLOT_BD2], &opll->patch[16 * 2 + 1]); + } + + if (opll->patch_number[7] & 0x10) + { + if (!((opll->slot_on_flag[SLOT_HH] && opll->slot_on_flag[SLOT_SD]) | (opll->reg[0x0e] & 32))) + { + opll->slot[SLOT_HH].type = 0; + opll->slot[SLOT_HH].eg_mode = FINISH; + opll->slot[SLOT_SD].eg_mode = FINISH; + setPatch (opll, 7, opll->reg[0x37] >> 4); + } + } + else if (opll->reg[0x0e] & 32) + { + opll->patch_number[7] = 17; + opll->slot[SLOT_HH].type = 1; + opll->slot[SLOT_HH].eg_mode = FINISH; + opll->slot[SLOT_SD].eg_mode = FINISH; + setSlotPatch (&opll->slot[SLOT_HH], &opll->patch[17 * 2 + 0]); + setSlotPatch (&opll->slot[SLOT_SD], &opll->patch[17 * 2 + 1]); + } + + if (opll->patch_number[8] & 0x10) + { + if (!((opll->slot_on_flag[SLOT_CYM] && opll->slot_on_flag[SLOT_TOM]) | (opll->reg[0x0e] & 32))) + { + opll->slot[SLOT_TOM].type = 0; + opll->slot[SLOT_TOM].eg_mode = FINISH; + opll->slot[SLOT_CYM].eg_mode = FINISH; + setPatch (opll, 8, opll->reg[0x38] >> 4); + } + } + else if (opll->reg[0x0e] & 32) + { + opll->patch_number[8] = 18; + opll->slot[SLOT_TOM].type = 1; + opll->slot[SLOT_TOM].eg_mode = FINISH; + opll->slot[SLOT_CYM].eg_mode = FINISH; + setSlotPatch (&opll->slot[SLOT_TOM], &opll->patch[18 * 2 + 0]); + setSlotPatch (&opll->slot[SLOT_CYM], &opll->patch[18 * 2 + 1]); + } +} + +INLINE static void +update_key_status (OPLL * opll) +{ + int ch; + + for (ch = 0; ch < 9; ch++) + opll->slot_on_flag[ch * 2] = opll->slot_on_flag[ch * 2 + 1] = (opll->reg[0x20 + ch]) & 0x10; + + if (opll->reg[0x0e] & 32) + { + opll->slot_on_flag[SLOT_BD1] |= (opll->reg[0x0e] & 0x10); + opll->slot_on_flag[SLOT_BD2] |= (opll->reg[0x0e] & 0x10); + opll->slot_on_flag[SLOT_SD] |= (opll->reg[0x0e] & 0x08); + opll->slot_on_flag[SLOT_HH] |= (opll->reg[0x0e] & 0x01); + opll->slot_on_flag[SLOT_TOM] |= (opll->reg[0x0e] & 0x04); + opll->slot_on_flag[SLOT_CYM] |= (opll->reg[0x0e] & 0x02); + } +} + +void +OPLL_copyPatch (OPLL * opll, e_int32 num, OPLL_PATCH * patch) +{ + memcpy (&opll->patch[num], patch, sizeof (OPLL_PATCH)); +} + +/*********************************************************** + + Initializing + +***********************************************************/ + +static void +OPLL_SLOT_reset (OPLL_SLOT * slot, int type) +{ + slot->type = type; + slot->sintbl = waveform[0]; + slot->phase = 0; + slot->dphase = 0; + slot->output[0] = 0; + slot->output[1] = 0; + slot->feedback = 0; + slot->eg_mode = FINISH; + slot->eg_phase = EG_DP_WIDTH; + slot->eg_dphase = 0; + slot->rks = 0; + slot->tll = 0; + slot->sustine = 0; + slot->fnum = 0; + slot->block = 0; + slot->volume = 0; + slot->pgout = 0; + slot->egout = 0; + slot->patch = &null_patch; +} + +static void +internal_refresh (void) +{ +#if !defined(ROCKBOX) + makeDphaseTable (); +#endif + makeDphaseARTable (); + makeDphaseDRTable (); + pm_dphase = (e_uint32) RATE_ADJUST ((int)(PM_SPEED * PM_DP_WIDTH) / (clk / 72)); + am_dphase = (e_uint32) RATE_ADJUST ((int)(AM_SPEED * AM_DP_WIDTH) / (clk / 72)); +} + +static void +maketables (e_uint32 c, e_uint32 r) +{ + if (c != clk) + { + clk = c; +#ifdef EMU2413_CALCUL_TABLES + makePmTable (); + makeAmTable (); + makeAdjustTable (); +#endif + makeDB2LinTable (); + makeTllTable (); + makeRksTable (); + makeSinTable (); + makeDefaultPatch (); + } + + if (r != rate) + { + rate = r; + internal_refresh (); + } +} + +void +OPLL_new (OPLL *opll, e_uint32 clk, e_uint32 rate) +{ + e_int32 i; + + maketables (clk, rate); + + memset(opll, 0, sizeof (OPLL)); + for (i = 0; i < 19 * 2; i++) + memcpy(&opll->patch[i],&null_patch,sizeof(OPLL_PATCH)); + + opll->mask = 0; + + OPLL_reset (opll); + OPLL_reset_patch (opll, 0); +} + + +void +OPLL_delete (OPLL * opll) +{ + (void) opll; +} + + +/* Reset patch datas by system default. */ +void +OPLL_reset_patch (OPLL * opll, e_int32 type) +{ + e_int32 i; + + for (i = 0; i < 19 * 2; i++) + OPLL_copyPatch (opll, i, &default_patch[type % OPLL_TONE_NUM][i]); +} + +/* Reset whole of OPLL except patch datas. */ +void +OPLL_reset (OPLL * opll) +{ + e_int32 i; + + if (!opll) + return; + + opll->adr = 0; + opll->out = 0; + + opll->pm_phase = 0; + opll->am_phase = 0; + + opll->noise_seed = 0xffff; + opll->mask = 0; + + for (i = 0; i <18; i++) + OPLL_SLOT_reset(&opll->slot[i], i%2); + + for (i = 0; i < 9; i++) + { + opll->key_status[i] = 0; + setPatch (opll, i, 0); + } + + for (i = 0; i < 0x40; i++) + OPLL_writeReg (opll, i, 0); + +#ifndef EMU2413_COMPACTION + opll->realstep = (e_uint32) ((1 << 31) / rate); + opll->opllstep = (e_uint32) ((1 << 31) / (clk / 72)); + opll->oplltime = 0; + for (i = 0; i < 14; i++) + opll->pan[i] = 2; + opll->sprev[0] = opll->sprev[1] = 0; + opll->snext[0] = opll->snext[1] = 0; +#endif +} + +/* Force Refresh (When external program changes some parameters). */ +void +OPLL_forceRefresh (OPLL * opll) +{ + e_int32 i; + + if (opll == NULL) + return; + + for (i = 0; i < 9; i++) + setPatch(opll,i,opll->patch_number[i]); + + for (i = 0; i < 18; i++) + { + UPDATE_PG (&opll->slot[i]); + UPDATE_RKS (&opll->slot[i]); + UPDATE_TLL (&opll->slot[i]); + UPDATE_WF (&opll->slot[i]); + UPDATE_EG (&opll->slot[i]); + } +} + +void +OPLL_set_rate (OPLL * opll, e_uint32 r) +{ + if (rate == r) return; + if (opll->quality) + rate = 49716; + else + rate = r; + internal_refresh (); + rate = r; +} + +void +OPLL_set_quality (OPLL * opll, e_uint32 q) +{ + opll->quality = q; + OPLL_set_rate (opll, rate); +} + +/********************************************************* + + Generate wave data + +*********************************************************/ +/* Convert Amp(0 to EG_HEIGHT) to Phase(0 to 2PI). */ +#if ( SLOT_AMP_BITS - PG_BITS ) > 0 +#define wave2_2pi(e) ( (e) >> ( SLOT_AMP_BITS - PG_BITS )) +#else +#define wave2_2pi(e) ( (e) << ( PG_BITS - SLOT_AMP_BITS )) +#endif + +/* Convert Amp(0 to EG_HEIGHT) to Phase(0 to 4PI). */ +#if ( SLOT_AMP_BITS - PG_BITS - 1 ) == 0 +#define wave2_4pi(e) (e) +#elif ( SLOT_AMP_BITS - PG_BITS - 1 ) > 0 +#define wave2_4pi(e) ( (e) >> ( SLOT_AMP_BITS - PG_BITS - 1 )) +#else +#define wave2_4pi(e) ( (e) << ( 1 + PG_BITS - SLOT_AMP_BITS )) +#endif + +/* Convert Amp(0 to EG_HEIGHT) to Phase(0 to 8PI). */ +#if ( SLOT_AMP_BITS - PG_BITS - 2 ) == 0 +#define wave2_8pi(e) (e) +#elif ( SLOT_AMP_BITS - PG_BITS - 2 ) > 0 +#define wave2_8pi(e) ( (e) >> ( SLOT_AMP_BITS - PG_BITS - 2 )) +#else +#define wave2_8pi(e) ( (e) << ( 2 + PG_BITS - SLOT_AMP_BITS )) +#endif + +/* Update AM, PM unit */ +INLINE static void +update_ampm (OPLL * opll) +{ + opll->pm_phase = (opll->pm_phase + pm_dphase) & (PM_DP_WIDTH - 1); + opll->am_phase = (opll->am_phase + am_dphase) & (AM_DP_WIDTH - 1); + opll->lfo_am = AMTABLE(HIGHBITS (opll->am_phase, AM_DP_BITS - AM_PG_BITS)); + opll->lfo_pm = PMTABLE(HIGHBITS (opll->pm_phase, PM_DP_BITS - PM_PG_BITS)); +} + +/* PG */ +INLINE static void +calc_phase (OPLL_SLOT * slot, e_int32 lfo) +{ + if (slot->patch->PM) + slot->phase += (slot->dphase * lfo) >> PM_AMP_BITS; + else + slot->phase += slot->dphase; + + slot->phase &= (DP_WIDTH - 1); + + slot->pgout = HIGHBITS (slot->phase, DP_BASE_BITS); +} + +/* Update Noise unit */ +INLINE static void +update_noise (OPLL * opll) +{ + if(opll->noise_seed&1) opll->noise_seed ^= 0x8003020; + opll->noise_seed >>= 1; +} + +/* EG */ +INLINE static void +calc_envelope (OPLL_SLOT * slot, e_int32 lfo) +{ +#define S2E(x) (SL2EG((e_int32)(x/SL_STEP))<<(EG_DP_BITS-EG_BITS)) + + static e_uint32 SL[16] = { + S2E (0.0), S2E (3.0), S2E (6.0), S2E (9.0), S2E (12.0), S2E (15.0), S2E (18.0), S2E (21.0), + S2E (24.0), S2E (27.0), S2E (30.0), S2E (33.0), S2E (36.0), S2E (39.0), S2E (42.0), S2E (48.0) + }; + + e_uint32 egout; + + switch (slot->eg_mode) + { + case ATTACK: + egout = AR_ADJUST_TABLE(HIGHBITS (slot->eg_phase, EG_DP_BITS - EG_BITS)); + slot->eg_phase += slot->eg_dphase; + if((EG_DP_WIDTH & slot->eg_phase)||(slot->patch->AR==15)) + { + egout = 0; + slot->eg_phase = 0; + slot->eg_mode = DECAY; + UPDATE_EG (slot); + } + break; + + case DECAY: + egout = HIGHBITS (slot->eg_phase, EG_DP_BITS - EG_BITS); + slot->eg_phase += slot->eg_dphase; + if (slot->eg_phase >= SL[slot->patch->SL]) + { + if (slot->patch->EG) + { + slot->eg_phase = SL[slot->patch->SL]; + slot->eg_mode = SUSHOLD; + UPDATE_EG (slot); + } + else + { + slot->eg_phase = SL[slot->patch->SL]; + slot->eg_mode = SUSTINE; + UPDATE_EG (slot); + } + } + break; + + case SUSHOLD: + egout = HIGHBITS (slot->eg_phase, EG_DP_BITS - EG_BITS); + if (slot->patch->EG == 0) + { + slot->eg_mode = SUSTINE; + UPDATE_EG (slot); + } + break; + + case SUSTINE: + case RELEASE: + egout = HIGHBITS (slot->eg_phase, EG_DP_BITS - EG_BITS); + slot->eg_phase += slot->eg_dphase; + if (egout >= (1 << EG_BITS)) + { + slot->eg_mode = FINISH; + egout = (1 << EG_BITS) - 1; + } + break; + + case SETTLE: + egout = HIGHBITS (slot->eg_phase, EG_DP_BITS - EG_BITS); + slot->eg_phase += slot->eg_dphase; + if (egout >= (1 << EG_BITS)) + { + slot->eg_mode = ATTACK; + egout = (1 << EG_BITS) - 1; + UPDATE_EG(slot); + } + break; + + case FINISH: + egout = (1 << EG_BITS) - 1; + break; + + default: + egout = (1 << EG_BITS) - 1; + break; + } + + if (slot->patch->AM) + egout = EG2DB (egout + slot->tll) + lfo; + else + egout = EG2DB (egout + slot->tll); + + if (egout >= DB_MUTE) + egout = DB_MUTE - 1; + + slot->egout = egout | 3; +} + +/* CARRIOR */ +INLINE static e_int32 +calc_slot_car (OPLL_SLOT * slot, e_int32 fm) +{ + if (slot->egout >= (DB_MUTE - 1)) + { + slot->output[0] = 0; + } + else + { + slot->output[0] = DB2LIN_TABLE[slot->sintbl[(slot->pgout+wave2_8pi(fm))&(PG_WIDTH-1)] + slot->egout]; + } + + slot->output[1] = (slot->output[1] + slot->output[0]) >> 1; + return slot->output[1]; +} + +/* MODULATOR */ +INLINE static e_int32 +calc_slot_mod (OPLL_SLOT * slot) +{ + e_int32 fm; + + slot->output[1] = slot->output[0]; + + if (slot->egout >= (DB_MUTE - 1)) + { + slot->output[0] = 0; + } + else if (slot->patch->FB != 0) + { + fm = wave2_4pi (slot->feedback) >> (7 - slot->patch->FB); + slot->output[0] = DB2LIN_TABLE[slot->sintbl[(slot->pgout+fm)&(PG_WIDTH-1)] + slot->egout]; + } + else + { + slot->output[0] = DB2LIN_TABLE[slot->sintbl[slot->pgout] + slot->egout]; + } + + slot->feedback = (slot->output[1] + slot->output[0]) >> 1; + + return slot->feedback; + +} + +/* TOM */ +INLINE static e_int32 +calc_slot_tom (OPLL_SLOT * slot) +{ + if (slot->egout >= (DB_MUTE - 1)) + return 0; + + return DB2LIN_TABLE[slot->sintbl[slot->pgout] + slot->egout]; + +} + +/* SNARE */ +INLINE static e_int32 +calc_slot_snare (OPLL_SLOT * slot, e_uint32 noise) +{ + if(slot->egout>=(DB_MUTE-1)) + return 0; + + if(BIT(slot->pgout,7)) + return DB2LIN_TABLE[(noise?DB_POS(0):DB_POS(15))+slot->egout]; + else + return DB2LIN_TABLE[(noise?DB_NEG(0):DB_NEG(15))+slot->egout]; +} + +/* + TOP-CYM + */ +INLINE static e_int32 +calc_slot_cym (OPLL_SLOT * slot, e_uint32 pgout_hh) +{ + e_uint32 dbout; + + if (slot->egout >= (DB_MUTE - 1)) + return 0; + else if( + /* the same as fmopl.c */ + ((BIT(pgout_hh,PG_BITS-8)^BIT(pgout_hh,PG_BITS-1))|BIT(pgout_hh,PG_BITS-7)) ^ + /* different from fmopl.c */ + (BIT(slot->pgout,PG_BITS-7)&!BIT(slot->pgout,PG_BITS-5)) + ) + dbout = DB_NEG(3); + else + dbout = DB_POS(3); + + return DB2LIN_TABLE[dbout + slot->egout]; +} + +/* + HI-HAT +*/ +INLINE static e_int32 +calc_slot_hat (OPLL_SLOT *slot, e_int32 pgout_cym, e_uint32 noise) +{ + e_uint32 dbout; + + if (slot->egout >= (DB_MUTE - 1)) + return 0; + else if( + /* the same as fmopl.c */ + ((BIT(slot->pgout,PG_BITS-8)^BIT(slot->pgout,PG_BITS-1))|BIT(slot->pgout,PG_BITS-7)) ^ + /* different from fmopl.c */ + (BIT(pgout_cym,PG_BITS-7)&!BIT(pgout_cym,PG_BITS-5)) + ) + { + if(noise) + dbout = DB_NEG(12); + else + dbout = DB_NEG(24); + } + else + { + if(noise) + dbout = DB_POS(12); + else + dbout = DB_POS(24); + } + + return DB2LIN_TABLE[dbout + slot->egout]; +} + +static e_int16 +calc (OPLL * opll) EMU2413_CALC_ICODE; +static e_int16 +calc (OPLL * opll) +{ + e_int32 i; + + update_ampm (opll); + update_noise (opll); + + for (i = 0; i < 18; i++) + { + calc_phase(&opll->slot[i],opll->lfo_pm); + calc_envelope(&opll->slot[i],opll->lfo_am); + } + + e_uint32 channel_mask = opll->mask; + for (i = 0; i < 9; i++) { + if (CAR(opll,i)->eg_mode != FINISH) + channel_mask |= (1 << i); + } + + e_int32 mix = 0; + + /* CH6 */ + if (opll->patch_number[6] & 0x10) { + if (channel_mask & OPLL_MASK_CH (6)) { + mix += calc_slot_car (CAR(opll,6), calc_slot_mod(MOD(opll,6))); + channel_mask &= ~(1 << 6); + } + } + + /* CH7 */ + if (opll->patch_number[7] & 0x10) { + if (MOD(opll,7)->eg_mode != FINISH) + mix += calc_slot_hat (MOD(opll,7), CAR(opll,8)->pgout, opll->noise_seed&1); + if (channel_mask & OPLL_MASK_SD) { + mix -= calc_slot_snare (CAR(opll,7), opll->noise_seed&1); + channel_mask &= ~OPLL_MASK_SD; + } + } + + /* CH8 */ + if (opll->patch_number[8] & 0x10) { + if (MOD(opll,8)->eg_mode != FINISH) + mix += calc_slot_tom (MOD(opll,8)); + if (channel_mask & OPLL_MASK_CYM) { + mix -= calc_slot_cym (CAR(opll,8), MOD(opll,7)->pgout); + channel_mask &= ~OPLL_MASK_CYM; + } + } + + mix <<= 1; + + opll->current_mask = channel_mask; + for (i = 0; channel_mask; channel_mask >>= 1, ++i) { + if (channel_mask & 1) { + mix += calc_slot_car (CAR(opll,i), calc_slot_mod(MOD(opll,i))); + } + } + + return (e_int16) mix << 3; +} + +void +OPLL_set_internal_mute(OPLL * opll, e_uint32 mute) +{ + opll->internal_mute = mute; +} + +e_uint32 +OPLL_is_internal_muted(OPLL * opll) +{ + return opll->internal_mute; +} + +static e_uint32 +check_mute_helper(OPLL * opll) +{ + for (int i = 0; i < 6; i++) { + /* if (ch[i].car.eg_mode != FINISH) return 0; */ + if (!(opll->current_mask & OPLL_MASK_CH (i)) && (CAR(opll,i)->eg_mode != FINISH)) return 0; + } + + if (!(opll->reg[0x0e] & 0x20)) { + for(int i = 6; i < 9; i++) { + /* if (ch[i].car.eg_mode != FINISH) return 0; */ + if (!(opll->current_mask & OPLL_MASK_CH (i)) && (CAR(opll,i)->eg_mode != FINISH)) return 0; + } + } else { + /* if (ch[6].car.eg_mode != FINISH) return false; + if (ch[7].mod.eg_mode != FINISH) return false; + if (ch[7].car.eg_mode != FINISH) return false; + if (ch[8].mod.eg_mode != FINISH) return false; + if (ch[8].car.eg_mode != FINISH) return false; */ + if (!(opll->current_mask & OPLL_MASK_CH (6)) && (CAR(opll,6)->eg_mode != FINISH)) return 0; + if (!(opll->current_mask & OPLL_MASK_CH (7)) && (MOD(opll,7)->eg_mode != FINISH)) return 0; + if (!(opll->current_mask & OPLL_MASK_CH (7)) && (CAR(opll,7)->eg_mode != FINISH)) return 0; + if (!(opll->current_mask & OPLL_MASK_CH (8)) && (MOD(opll,8)->eg_mode != FINISH)) return 0; + if (!(opll->current_mask & OPLL_MASK_CH (8)) && (CAR(opll,8)->eg_mode != FINISH)) return 0; + } + + return 1; /* nothing is playing, then mute */ +} + +static void +check_mute(OPLL * opll) +{ + OPLL_set_internal_mute (opll, check_mute_helper (opll)); +} + +EMU2413_API e_int16 *OPLL_update_buffer(OPLL * opll, e_uint32 length) +{ + e_int16* buf = opll->buffer; + while (length--) { + *(buf++) = calc (opll); + } + check_mute (opll); + + return opll->buffer; +} + +#ifdef EMU2413_COMPACTION +e_int16 +OPLL_calc (OPLL * opll) +{ + return calc (opll); +} +#else +e_int16 +OPLL_calc (OPLL * opll) +{ + if (!opll->quality) + return calc (opll); + + while (opll->realstep > opll->oplltime) + { + opll->oplltime += opll->opllstep; + opll->prev = opll->next; + opll->next = calc (opll); + } + + opll->oplltime -= opll->realstep; + opll->out = (e_int16) (((double) opll->next * (opll->opllstep - opll->oplltime) + + (double) opll->prev * opll->oplltime) / opll->opllstep); + + return (e_int16) opll->out; +} +#endif + +e_uint32 +OPLL_setMask (OPLL * opll, e_uint32 mask) +{ + e_uint32 ret; + + if (opll) + { + ret = opll->mask; + opll->mask = mask; + return ret; + } + else + return 0; +} + +e_uint32 +OPLL_toggleMask (OPLL * opll, e_uint32 mask) +{ + e_uint32 ret; + + if (opll) + { + ret = opll->mask; + opll->mask ^= mask; + return ret; + } + else + return 0; +} + +/**************************************************** + + I/O Ctrl + +*****************************************************/ + +void +OPLL_writeReg (OPLL * opll, e_uint32 reg, e_uint32 data) +{ + e_int32 i, v, ch; + + data = data & 0xff; + reg = reg & 0x3f; + opll->reg[reg] = (e_uint8) data; + + switch (reg) + { + case 0x00: + opll->patch[0].AM = (data >> 7) & 1; + opll->patch[0].PM = (data >> 6) & 1; + opll->patch[0].EG = (data >> 5) & 1; + opll->patch[0].KR = (data >> 4) & 1; + opll->patch[0].ML = (data) & 15; + for (i = 0; i < 9; i++) + { + if (opll->patch_number[i] == 0) + { + UPDATE_PG (MOD(opll,i)); + UPDATE_RKS (MOD(opll,i)); + UPDATE_EG (MOD(opll,i)); + } + } + break; + + case 0x01: + opll->patch[1].AM = (data >> 7) & 1; + opll->patch[1].PM = (data >> 6) & 1; + opll->patch[1].EG = (data >> 5) & 1; + opll->patch[1].KR = (data >> 4) & 1; + opll->patch[1].ML = (data) & 15; + for (i = 0; i < 9; i++) + { + if (opll->patch_number[i] == 0) + { + UPDATE_PG (CAR(opll,i)); + UPDATE_RKS (CAR(opll,i)); + UPDATE_EG (CAR(opll,i)); + } + } + break; + + case 0x02: + opll->patch[0].KL = (data >> 6) & 3; + opll->patch[0].TL = (data) & 63; + for (i = 0; i < 9; i++) + { + if (opll->patch_number[i] == 0) + { + UPDATE_TLL(MOD(opll,i)); + } + } + break; + + case 0x03: + opll->patch[1].KL = (data >> 6) & 3; + opll->patch[1].WF = (data >> 4) & 1; + opll->patch[0].WF = (data >> 3) & 1; + opll->patch[0].FB = (data) & 7; + for (i = 0; i < 9; i++) + { + if (opll->patch_number[i] == 0) + { + UPDATE_WF(MOD(opll,i)); + UPDATE_WF(CAR(opll,i)); + } + } + break; + + case 0x04: + opll->patch[0].AR = (data >> 4) & 15; + opll->patch[0].DR = (data) & 15; + for (i = 0; i < 9; i++) + { + if (opll->patch_number[i] == 0) + { + UPDATE_EG (MOD(opll,i)); + } + } + break; + + case 0x05: + opll->patch[1].AR = (data >> 4) & 15; + opll->patch[1].DR = (data) & 15; + for (i = 0; i < 9; i++) + { + if (opll->patch_number[i] == 0) + { + UPDATE_EG(CAR(opll,i)); + } + } + break; + + case 0x06: + opll->patch[0].SL = (data >> 4) & 15; + opll->patch[0].RR = (data) & 15; + for (i = 0; i < 9; i++) + { + if (opll->patch_number[i] == 0) + { + UPDATE_EG (MOD(opll,i)); + } + } + break; + + case 0x07: + opll->patch[1].SL = (data >> 4) & 15; + opll->patch[1].RR = (data) & 15; + for (i = 0; i < 9; i++) + { + if (opll->patch_number[i] == 0) + { + UPDATE_EG (CAR(opll,i)); + } + } + break; + + case 0x0e: + update_rhythm_mode (opll); + if (data & 32) + { + if (data & 0x10) + keyOn_BD (opll); + else + keyOff_BD (opll); + if (data & 0x8) + keyOn_SD (opll); + else + keyOff_SD (opll); + if (data & 0x4) + keyOn_TOM (opll); + else + keyOff_TOM (opll); + if (data & 0x2) + keyOn_CYM (opll); + else + keyOff_CYM (opll); + if (data & 0x1) + keyOn_HH (opll); + else + keyOff_HH (opll); + } + update_key_status (opll); + + UPDATE_ALL (MOD(opll,6)); + UPDATE_ALL (CAR(opll,6)); + UPDATE_ALL (MOD(opll,7)); + UPDATE_ALL (CAR(opll,7)); + UPDATE_ALL (MOD(opll,8)); + UPDATE_ALL (CAR(opll,8)); + + break; + + case 0x0f: + break; + + case 0x10: + case 0x11: + case 0x12: + case 0x13: + case 0x14: + case 0x15: + case 0x16: + case 0x17: + case 0x18: + ch = reg - 0x10; + setFnumber (opll, ch, data + ((opll->reg[0x20 + ch] & 1) << 8)); + UPDATE_ALL (MOD(opll,ch)); + UPDATE_ALL (CAR(opll,ch)); + break; + + case 0x20: + case 0x21: + case 0x22: + case 0x23: + case 0x24: + case 0x25: + case 0x26: + case 0x27: + case 0x28: + ch = reg - 0x20; + setFnumber (opll, ch, ((data & 1) << 8) + opll->reg[0x10 + ch]); + setBlock (opll, ch, (data >> 1) & 7); + setSustine (opll, ch, (data >> 5) & 1); + if (data & 0x10) + keyOn (opll, ch); + else + keyOff (opll, ch); + UPDATE_ALL (MOD(opll,ch)); + UPDATE_ALL (CAR(opll,ch)); + update_key_status (opll); + update_rhythm_mode (opll); + break; + + case 0x30: + case 0x31: + case 0x32: + case 0x33: + case 0x34: + case 0x35: + case 0x36: + case 0x37: + case 0x38: + i = (data >> 4) & 15; + v = data & 15; + if ((opll->reg[0x0e] & 32) && (reg >= 0x36)) + { + switch (reg) + { + case 0x37: + setSlotVolume (MOD(opll,7), i << 2); + break; + case 0x38: + setSlotVolume (MOD(opll,8), i << 2); + break; + default: + break; + } + } + else + { + setPatch (opll, reg - 0x30, i); + } + setVolume (opll, reg - 0x30, v << 2); + UPDATE_ALL (MOD(opll,reg - 0x30)); + UPDATE_ALL (CAR(opll,reg - 0x30)); + break; + + default: + break; + + } +} + +void +OPLL_writeIO (OPLL * opll, e_uint32 adr, e_uint32 val) +{ + if (adr & 1) + OPLL_writeReg (opll, opll->adr, val); + else + opll->adr = val; +} + +e_uint32 +OPLL_read(OPLL * opll, e_uint32 a) +{ + if( !(a&1) ) + { + /* status port */ + return opll->status; + } + return 0xff; +} + +#ifndef EMU2413_COMPACTION +/* STEREO MODE (OPT) */ +void +OPLL_set_pan (OPLL * opll, e_uint32 ch, e_uint32 pan) +{ + opll->pan[ch & 15] = pan & 3; +} + +static void +calc_stereo (OPLL * opll, e_int32 out[2]) +{ + e_int32 b[4] = { 0, 0, 0, 0 }; /* Ignore, Right, Left, Center */ + e_int32 r[4] = { 0, 0, 0, 0 }; /* Ignore, Right, Left, Center */ + e_int32 i; + + update_ampm (opll); + update_noise (opll); + + for(i=0;i<18;i++) + { + calc_phase(&opll->slot[i],opll->lfo_pm); + calc_envelope(&opll->slot[i],opll->lfo_am); + } + + for (i = 0; i < 6; i++) + if (!(opll->mask & OPLL_MASK_CH (i)) && (CAR(opll,i)->eg_mode != FINISH)) + b[opll->pan[i]] += calc_slot_car (CAR(opll,i), calc_slot_mod (MOD(opll,i))); + + + if (opll->patch_number[6] <= 15) + { + if (!(opll->mask & OPLL_MASK_CH (6)) && (CAR(opll,6)->eg_mode != FINISH)) + b[opll->pan[6]] += calc_slot_car (CAR(opll,6), calc_slot_mod (MOD(opll,6))); + } + else + { + if (!(opll->mask & OPLL_MASK_BD) && (CAR(opll,6)->eg_mode != FINISH)) + r[opll->pan[9]] += calc_slot_car (CAR(opll,6), calc_slot_mod (MOD(opll,6))); + } + + if (opll->patch_number[7] <= 15) + { + if (!(opll->mask & OPLL_MASK_CH (7)) && (CAR (opll,7)->eg_mode != FINISH)) + b[opll->pan[7]] += calc_slot_car (CAR (opll,7), calc_slot_mod (MOD (opll,7))); + } + else + { + if (!(opll->mask & OPLL_MASK_HH) && (MOD (opll,7)->eg_mode != FINISH)) + r[opll->pan[10]] += calc_slot_hat (MOD (opll,7), CAR(opll,8)->pgout, opll->noise_seed&1); + if (!(opll->mask & OPLL_MASK_SD) && (CAR (opll,7)->eg_mode != FINISH)) + r[opll->pan[11]] -= calc_slot_snare (CAR (opll,7), opll->noise_seed&1); + } + + if (opll->patch_number[8] <= 15) + { + if (!(opll->mask & OPLL_MASK_CH (8)) && (CAR (opll,8)->eg_mode != FINISH)) + b[opll->pan[8]] += calc_slot_car (CAR (opll,8), calc_slot_mod (MOD (opll,8))); + } + else + { + if (!(opll->mask & OPLL_MASK_TOM) && (MOD (opll,8)->eg_mode != FINISH)) + r[opll->pan[12]] += calc_slot_tom (MOD (opll,8)); + if (!(opll->mask & OPLL_MASK_CYM) && (CAR (opll,8)->eg_mode != FINISH)) + r[opll->pan[13]] -= calc_slot_cym (CAR (opll,8), MOD(opll,7)->pgout); + } + + out[1] = (b[1] + b[3] + ((r[1] + r[3]) << 1)) <<3; + out[0] = (b[2] + b[3] + ((r[2] + r[3]) << 1)) <<3; +} + +void +OPLL_calc_stereo (OPLL * opll, e_int32 out[2]) +{ + if (!opll->quality) + { + calc_stereo (opll, out); + return; + } + + while (opll->realstep > opll->oplltime) + { + opll->oplltime += opll->opllstep; + opll->sprev[0] = opll->snext[0]; + opll->sprev[1] = opll->snext[1]; + calc_stereo (opll, opll->snext); + } + + opll->oplltime -= opll->realstep; + out[0] = (e_int16) (((double) opll->snext[0] * (opll->opllstep - opll->oplltime) + + (double) opll->sprev[0] * opll->oplltime) / opll->opllstep); + out[1] = (e_int16) (((double) opll->snext[1] * (opll->opllstep - opll->oplltime) + + (double) opll->sprev[1] * opll->oplltime) / opll->opllstep); +} +#endif /* EMU2413_COMPACTION */ -- cgit v1.2.3