diff options
Diffstat (limited to 'src/emu/sound/ymf271.c')
-rw-r--r-- | src/emu/sound/ymf271.c | 1833 |
1 files changed, 1833 insertions, 0 deletions
diff --git a/src/emu/sound/ymf271.c b/src/emu/sound/ymf271.c new file mode 100644 index 00000000000..710fdc3b9d6 --- /dev/null +++ b/src/emu/sound/ymf271.c @@ -0,0 +1,1833 @@ +/* + Yamaha YMF271-F "OPX" emulator v0.1 + By R. Belmont. + Based in part on YMF278B emulator by R. Belmont and O. Galibert. + 12June04 update by Toshiaki Nijiura + Copyright (c) 2003 R. Belmont. + + This software is dual-licensed: it may be used in MAME and properly licensed + MAME derivatives under the terms of the MAME license. For use outside of + MAME and properly licensed derivatives, it is available under the + terms of the GNU Lesser General Public License (LGPL), version 2.1. + You may read the LGPL at http://www.gnu.org/licenses/lgpl.html +*/ + +#include <math.h> +#include "sndintrf.h" +#include "streams.h" +#include "ymf271.h" + +#define VERBOSE (1) + +#define MAXOUT (+32767) +#define MINOUT (-32768) + +#define SIN_BITS 10 +#define SIN_LEN (1<<SIN_BITS) +#define SIN_MASK (SIN_LEN-1) + +#define LFO_LENGTH 256 +#define LFO_SHIFT 8 +#define PLFO_MAX (+1.0) +#define PLFO_MIN (-1.0) +#define ALFO_MAX (+65536) +#define ALFO_MIN (0) + +#define log2(n) (log((float) n)/log((float) 2)) + +typedef struct +{ + INT8 extout; + UINT8 lfoFreq; + INT8 lfowave; + INT8 pms, ams; + INT8 detune; + INT8 multiple; + INT8 tl; + INT8 keyscale; + INT8 ar; + INT8 decay1rate, decay2rate; + INT8 decay1lvl; + INT8 relrate; + INT32 fns; + INT8 block; + INT8 feedback; + INT8 waveform; + INT8 accon; + INT8 algorithm; + INT8 ch0_level, ch1_level, ch2_level, ch3_level; + + UINT32 startaddr; + UINT32 loopaddr; + UINT32 endaddr; + INT8 fs, srcnote, srcb; + + INT64 step; + INT64 stepptr; + + INT8 active; + INT8 bits; + + // envelope generator + INT32 volume; + INT32 env_state; + INT32 env_attack_step; // volume increase step in attack state + INT32 env_decay1_step; + INT32 env_decay2_step; + INT32 env_release_step; + + INT64 feedback_modulation0; + INT64 feedback_modulation1; + + INT32 lfo_phase, lfo_step; + INT32 lfo_amplitude; + double lfo_phasemod; +} YMF271Slot; + +typedef struct +{ + INT8 sync, pfm; +} YMF271Group; + +typedef struct +{ + YMF271Slot slots[48]; + YMF271Group groups[12]; + + INT32 timerA, timerB; + INT32 timerAVal, timerBVal; + INT32 irqstate; + INT8 status; + INT8 enable; + + emu_timer *timA, *timB; + + INT8 reg0, reg1, reg2, reg3, pcmreg, timerreg; + UINT32 ext_address; + UINT8 ext_read; + + const UINT8 *rom; + read8_handler ext_mem_read; + write8_handler ext_mem_write; + void (*irq_callback)(int); + + int index; + UINT32 clock; + sound_stream * stream; +} YMF271Chip; + +// slot mapping assists +static const int fm_tab[] = { 0, 1, 2, -1, 3, 4, 5, -1, 6, 7, 8, -1, 9, 10, 11, -1 }; +static const int pcm_tab[] = { 0, 4, 8, -1, 12, 16, 20, -1, 24, 28, 32, -1, 36, 40, 44, -1 }; + +static INT16 *wavetable[8]; +static double plfo_table[4][8][LFO_LENGTH]; +static int alfo_table[4][LFO_LENGTH]; +static INT32 *mix; + +#define ENV_ATTACK 0 +#define ENV_DECAY1 1 +#define ENV_DECAY2 2 +#define ENV_RELEASE 3 + +#define ENV_VOLUME_SHIFT 16 + +#define INF 100000000.0 + +static const double ARTime[] = +{ + INF, INF, INF, INF, 6188.12, 4980.68, 4144.76, 3541.04, + 3094.06, 2490.34, 2072.38, 1770.52, 1547.03, 1245.17, 1036.19, 885.26, + 773.51, 622.59, 518.10, 441.63, 386.76, 311.29, 259.05, 221.32, + 193.38, 155.65, 129.52, 110.66, 96.69, 77.82, 64.76, 55.33, + 48.34, 38.91, 32.38, 27.66, 24.17, 19.46, 16.19, 13.83, + 12.09, 9.73, 8.10, 6.92, 6.04, 4.86, 4.05, 3.46, + 3.02, 2.47, 2.14, 1.88, 1.70, 1.38, 1.16, 1.02, + 0.88, 0.70, 0.57, 0.48, 0.43, 0.43, 0.43, 0.07 +}; + +static const double DCTime[] = +{ + INF, INF, INF, INF, 93599.64, 74837.91, 62392.02, 53475.56, + 46799.82, 37418.96, 31196.01, 26737.78, 23399.91, 18709.48, 15598.00, 13368.89, + 11699.95, 9354.74, 7799.00, 6684.44, 5849.98, 4677.37, 3899.50, 3342.22, + 2924.99, 2338.68, 1949.75, 1671.11, 1462.49, 1169.34, 974.88, 835.56, + 731.25, 584.67, 487.44, 417.78, 365.62, 292.34, 243.72, 208.89, + 182.81, 146.17, 121.86, 104.44, 91.41, 73.08, 60.93, 52.22, + 45.69, 36.55, 33.85, 26.09, 22.83, 18.28, 15.22, 13.03, + 11.41, 9.12, 7.60, 6.51, 5.69, 5.69, 5.69, 5.69 +}; + +static const double LFO_frequency_table[256] = +{ + 0.00066, 0.00068, 0.00070, 0.00073, 0.00075, 0.00078, 0.00081, 0.00084, + 0.00088, 0.00091, 0.00096, 0.00100, 0.00105, 0.00111, 0.00117, 0.00124, + 0.00131, 0.00136, 0.00140, 0.00145, 0.00150, 0.00156, 0.00162, 0.00168, + 0.00175, 0.00183, 0.00191, 0.00200, 0.00210, 0.00221, 0.00234, 0.00247, + 0.00263, 0.00271, 0.00280, 0.00290, 0.00300, 0.00312, 0.00324, 0.00336, + 0.00350, 0.00366, 0.00382, 0.00401, 0.00421, 0.00443, 0.00467, 0.00495, + 0.00526, 0.00543, 0.00561, 0.00580, 0.00601, 0.00623, 0.00647, 0.00673, + 0.00701, 0.00731, 0.00765, 0.00801, 0.00841, 0.00885, 0.00935, 0.00990, + 0.01051, 0.01085, 0.01122, 0.01160, 0.01202, 0.01246, 0.01294, 0.01346, + 0.01402, 0.01463, 0.01529, 0.01602, 0.01682, 0.01771, 0.01869, 0.01979, + 0.02103, 0.02171, 0.02243, 0.02320, 0.02403, 0.02492, 0.02588, 0.02692, + 0.02804, 0.02926, 0.03059, 0.03204, 0.03365, 0.03542, 0.03738, 0.03958, + 0.04206, 0.04341, 0.04486, 0.04641, 0.04807, 0.04985, 0.05176, 0.05383, + 0.05608, 0.05851, 0.06117, 0.06409, 0.06729, 0.07083, 0.07477, 0.07917, + 0.08411, 0.08683, 0.08972, 0.09282, 0.09613, 0.09969, 0.10353, 0.10767, + 0.11215, 0.11703, 0.12235, 0.12817, 0.13458, 0.14167, 0.14954, 0.15833, + 0.16823, 0.17365, 0.17944, 0.18563, 0.19226, 0.19938, 0.20705, 0.21533, + 0.22430, 0.23406, 0.24470, 0.25635, 0.26917, 0.28333, 0.29907, 0.31666, + 0.33646, 0.34731, 0.35889, 0.37126, 0.38452, 0.39876, 0.41410, 0.43066, + 0.44861, 0.46811, 0.48939, 0.51270, 0.53833, 0.56666, 0.59814, 0.63333, + 0.67291, 0.69462, 0.71777, 0.74252, 0.76904, 0.79753, 0.82820, 0.86133, + 0.89722, 0.93623, 0.97878, 1.02539, 1.07666, 1.13333, 1.19629, 1.26666, + 1.34583, 1.38924, 1.43555, 1.48505, 1.53809, 1.59509, 1.65640, 1.72266, + 1.79443, 1.87245, 1.95756, 2.05078, 2.15332, 2.26665, 2.39258, 2.53332, + 2.69165, 2.77848, 2.87109, 2.97010, 3.07617, 3.19010, 3.31280, 3.44531, + 3.58887, 3.74490, 3.92000, 4.10156, 4.30664, 4.53331, 4.78516, 5.06664, + 5.38330, 5.55696, 5.74219, 5.94019, 6.15234, 6.38021, 6.62560, 6.89062, + 7.17773, 7.48981, 7.83026, 8.20312, 8.61328, 9.06661, 9.57031, 10.13327, + 10.76660, 11.11391, 11.48438, 11.88039, 12.30469, 12.76042, 13.25120, 13.78125, + 13.35547, 14.97962, 15.66051, 16.40625, 17.22656, 18.13322, 19.14062, 20.26654, + 21.53320, 22.96875, 24.60938, 26.50240, 28.71094, 31.32102, 34.45312, 38.28125, + 43.06641, 49.21875, 57.42188, 68.90625, 86.13281, 114.84375, 172.26562, 344.53125 +}; + +static const int RKS_Table[32][8] = +{ + { 0, 0, 0, 0, 0, 2, 4, 8 }, + { 0, 0, 0, 0, 1, 3, 5, 9 }, + { 0, 0, 0, 1, 2, 4, 6, 10 }, + { 0, 0, 0, 1, 3, 5, 7, 11 }, + { 0, 0, 1, 2, 4, 6, 8, 12 }, + { 0, 0, 1, 2, 5, 7, 9, 13 }, + { 0, 0, 1, 3, 6, 8, 10, 14 }, + { 0, 0, 1, 3, 7, 9, 11, 15 }, + { 0, 1, 2, 4, 8, 10, 12, 16 }, + { 0, 1, 2, 4, 9, 11, 13, 17 }, + { 0, 1, 2, 5, 10, 12, 14, 18 }, + { 0, 1, 2, 5, 11, 13, 15, 19 }, + { 0, 1, 3, 6, 12, 14, 16, 20 }, + { 0, 1, 3, 6, 13, 15, 17, 21 }, + { 0, 1, 3, 7, 14, 16, 18, 22 }, + { 0, 1, 3, 7, 15, 17, 19, 23 }, + { 0, 2, 4, 8, 16, 18, 20, 24 }, + { 0, 2, 4, 8, 17, 19, 21, 25 }, + { 0, 2, 4, 9, 18, 20, 22, 26 }, + { 0, 2, 4, 9, 19, 21, 23, 27 }, + { 0, 2, 5, 10, 20, 22, 24, 28 }, + { 0, 2, 5, 10, 21, 23, 25, 29 }, + { 0, 2, 5, 11, 22, 24, 26, 30 }, + { 0, 2, 5, 11, 23, 25, 27, 31 }, + { 0, 3, 6, 12, 24, 26, 28, 31 }, + { 0, 3, 6, 12, 25, 27, 29, 31 }, + { 0, 3, 6, 13, 26, 28, 30, 31 }, + { 0, 3, 6, 13, 27, 29, 31, 31 }, + { 0, 3, 7, 14, 28, 30, 31, 31 }, + { 0, 3, 7, 14, 29, 31, 31, 31 }, + { 0, 3, 7, 15, 30, 31, 31, 31 }, + { 0, 3, 7, 15, 31, 31, 31, 31 }, +}; + +static const double channel_attenuation_table[16] = +{ + 0.0, 2.5, 6.0, 8.5, 12.0, 14.5, 18.1, 20.6, 24.1, 26.6, 30.1, 32.6, 36.1, 96.1, 96.1, 96.1 +}; + +static const int modulation_level[8] = { 16, 8, 4, 2, 1, 32, 64, 128 }; + +// feedback_level * 16 +static const int feedback_level[8] = { 0, 1, 2, 4, 8, 16, 32, 64 }; + +static int channel_attenuation[16]; +static int total_level[128]; +static int env_volume_table[256]; + +INLINE int GET_KEYSCALED_RATE(int rate, int keycode, int keyscale) +{ + int newrate = rate + RKS_Table[keycode][keyscale]; + + if (newrate > 63) + { + newrate = 63; + } + if (newrate < 0) + { + newrate = 0; + } + return newrate; +} + +INLINE int GET_INTERNAL_KEYCODE(int block, int fns) +{ + int n43; + if (fns < 0x780) + { + n43 = 0; + } + else if (fns < 0x900) + { + n43 = 1; + } + else if (fns < 0xa80) + { + n43 = 2; + } + else + { + n43 = 3; + } + + return ((block & 7) * 4) + n43; +} + +INLINE int GET_EXTERNAL_KEYCODE(int block, int fns) +{ + /* TODO: SrcB and SrcNote !? */ + int n43; + if (fns < 0x100) + { + n43 = 0; + } + else if (fns < 0x300) + { + n43 = 1; + } + else if (fns < 0x500) + { + n43 = 2; + } + else + { + n43 = 3; + } + + return ((block & 7) * 4) + n43; +} + +static const double multiple_table[16] = { 0.5, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }; + +static const double pow_table[16] = { 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 0.5, 1, 2, 4, 8, 16, 32, 64 }; + +static const double fs_frequency[4] = { 1.0/1.0, 1.0/2.0, 1.0/4.0, 1.0/8.0 }; + +INLINE void calculate_step(YMF271Slot *slot) +{ + double st; + + if (slot->waveform == 7) // external waveform (PCM) + { + st = (double)(2 * (slot->fns | 2048)) * pow_table[slot->block] * fs_frequency[slot->fs]; + st = st * multiple_table[slot->multiple]; + + // LFO phase modulation + st *= slot->lfo_phasemod; + + st /= (double)(524288/65536); // pre-multiply with 65536 + + slot->step = (UINT64)st; + } + else // internal waveform (FM) + { + st = (double)(2 * slot->fns) * pow_table[slot->block]; + st = st * multiple_table[slot->multiple] * (double)(SIN_LEN); + + // LFO phase modulation + st *= slot->lfo_phasemod; + + st /= (double)(536870912/65536); // pre-multiply with 65536 + + slot->step = (UINT64)st; + } +} + +static void update_envelope(YMF271Slot *slot) +{ + switch (slot->env_state) + { + case ENV_ATTACK: + { + slot->volume += slot->env_attack_step; + + if (slot->volume >= (255 << ENV_VOLUME_SHIFT)) + { + slot->volume = (255 << ENV_VOLUME_SHIFT); + slot->env_state = ENV_DECAY1; + } + break; + } + + case ENV_DECAY1: + { + int decay_level = 255 - (slot->decay1lvl << 4); + slot->volume -= slot->env_decay1_step; + + if ((slot->volume >> (ENV_VOLUME_SHIFT)) <= decay_level) + { + slot->env_state = ENV_DECAY2; + } + break; + } + + case ENV_DECAY2: + { + slot->volume -= slot->env_decay2_step; + + if (slot->volume < 0) + { + slot->volume = 0; + } + break; + } + + case ENV_RELEASE: + { + slot->volume -= slot->env_release_step; + + if (slot->volume <= (0 << ENV_VOLUME_SHIFT)) + { + slot->active = 0; + slot->volume = 0; + } + break; + } + } +} + +static void init_envelope(YMF271Slot *slot) +{ + int keycode, rate; + int attack_length, decay1_length, decay2_length, release_length; + int decay_level = 255 - (slot->decay1lvl << 4); + + double time; + + if (slot->waveform != 7) + { + keycode = GET_INTERNAL_KEYCODE(slot->block, slot->fns); + } + else + { + keycode = GET_EXTERNAL_KEYCODE(slot->block, slot->fns); + } + + // init attack state + rate = GET_KEYSCALED_RATE(slot->ar * 2, keycode, slot->keyscale); + time = ARTime[rate]; + + attack_length = (UINT32)((time * 44100.0) / 1000.0); // attack end time in samples + slot->env_attack_step = (int)(((double)(160-0) / (double)(attack_length)) * 65536.0); + + // init decay1 state + rate = GET_KEYSCALED_RATE(slot->decay1rate * 2, keycode, slot->keyscale); + time = DCTime[rate]; + + decay1_length = (UINT32)((time * 44100.0) / 1000.0); + slot->env_decay1_step = (int)(((double)(255-decay_level) / (double)(decay1_length)) * 65536.0); + + // init decay2 state + rate = GET_KEYSCALED_RATE(slot->decay2rate * 2, keycode, slot->keyscale); + time = DCTime[rate]; + + decay2_length = (UINT32)((time * 44100.0) / 1000.0); + slot->env_decay2_step = (int)(((double)(255-0) / (double)(decay2_length)) * 65536.0); + + // init release state + rate = GET_KEYSCALED_RATE(slot->relrate * 4, keycode, slot->keyscale); + time = ARTime[rate]; + + release_length = (UINT32)((time * 44100.0) / 1000.0); + slot->env_release_step = (int)(((double)(255-0) / (double)(release_length)) * 65536.0); + + slot->volume = (255-160) << ENV_VOLUME_SHIFT; // -60db + slot->env_state = ENV_ATTACK; +} + +static void init_lfo(YMF271Slot *slot) +{ + slot->lfo_phase = 0; + slot->lfo_amplitude = 0; + slot->lfo_phasemod = 0; + + slot->lfo_step = (int)((((double)LFO_LENGTH * LFO_frequency_table[slot->lfoFreq]) / 44100.0) * 256.0); +} + +INLINE void update_lfo(YMF271Slot *slot) +{ + slot->lfo_phase += slot->lfo_step; + + slot->lfo_amplitude = alfo_table[slot->lfowave][(slot->lfo_phase >> LFO_SHIFT) & (LFO_LENGTH-1)]; + slot->lfo_phasemod = plfo_table[slot->lfowave][slot->pms][(slot->lfo_phase >> LFO_SHIFT) & (LFO_LENGTH-1)]; + + calculate_step(slot); +} + +INLINE int calculate_slot_volume(YMF271Slot *slot) +{ + UINT64 volume; + UINT64 env_volume; + UINT64 lfo_volume = 65536; + + switch (slot->ams) + { + case 0: lfo_volume = 65536; break; // 0dB + case 1: lfo_volume = 65536 - (((UINT64)slot->lfo_amplitude * 33124) >> 16); break; // 5.90625dB + case 2: lfo_volume = 65536 - (((UINT64)slot->lfo_amplitude * 16742) >> 16); break; // 11.8125dB + case 3: lfo_volume = 65536 - (((UINT64)slot->lfo_amplitude * 4277) >> 16); break; // 23.625dB + } + + env_volume = ((UINT64)env_volume_table[255 - (slot->volume >> ENV_VOLUME_SHIFT)] * (UINT64)lfo_volume) >> 16; + + volume = ((UINT64)env_volume * (UINT64)total_level[slot->tl]) >> 16; + + return volume; +} + +static void update_pcm(YMF271Chip *chip, int slotnum, INT32 *mixp, int length) +{ + int i; + int final_volume; + INT16 sample; + INT64 ch0_vol, ch1_vol, ch2_vol, ch3_vol; + const UINT8 *rombase; + + YMF271Slot *slot = &chip->slots[slotnum]; + rombase = chip->rom; + + if (!slot->active) + { + return; + } + + if (slot->waveform != 7) + { + fatalerror("Waveform %d in update_pcm !!!", slot->waveform); + } + + for (i = 0; i < length; i++) + { + if (slot->bits == 8) + { + sample = rombase[slot->startaddr + (slot->stepptr>>16)]<<8; + } + else + { + if (slot->stepptr & 1) + sample = rombase[slot->startaddr + (slot->stepptr>>17)*3 + 2]<<8 | ((rombase[slot->startaddr + (slot->stepptr>>17)*3 + 1] << 4) & 0xf0); + else + sample = rombase[slot->startaddr + (slot->stepptr>>17)*3]<<8 | (rombase[slot->startaddr + (slot->stepptr>>17)*3 + 1] & 0xf0); + } + + update_envelope(slot); + update_lfo(slot); + + final_volume = calculate_slot_volume(slot); + + ch0_vol = ((UINT64)final_volume * (UINT64)channel_attenuation[slot->ch0_level]) >> 16; + ch1_vol = ((UINT64)final_volume * (UINT64)channel_attenuation[slot->ch1_level]) >> 16; + ch2_vol = ((UINT64)final_volume * (UINT64)channel_attenuation[slot->ch2_level]) >> 16; + ch3_vol = ((UINT64)final_volume * (UINT64)channel_attenuation[slot->ch3_level]) >> 16; + + if (ch0_vol > 65536) ch0_vol = 65536; + if (ch1_vol > 65536) ch1_vol = 65536; + + *mixp++ += (sample * ch0_vol) >> 16; + *mixp++ += (sample * ch1_vol) >> 16; + + slot->stepptr += slot->step; + if ((slot->stepptr>>16) > slot->endaddr) + { + // kill non-frac + slot->stepptr &= 0xffff; + slot->stepptr |= (slot->loopaddr<<16); + } + } +} + +// calculates 2 operator FM using algorithm 0 +// <--------| +// +--[S1]--+--[S3]--> +INLINE INT32 calculate_2op_fm_0(YMF271Chip *chip, int slotnum1, int slotnum2) +{ + YMF271Slot *slot1 = &chip->slots[slotnum1]; + YMF271Slot *slot2 = &chip->slots[slotnum2]; + INT64 env1, env2; + INT64 slot1_output, slot2_output; + INT64 phase_mod; + INT64 feedback; + + update_envelope(slot1); + update_lfo(slot1); + env1 = calculate_slot_volume(slot1); + update_envelope(slot2); + update_lfo(slot2); + env2 = calculate_slot_volume(slot2); + + feedback = (slot1->feedback_modulation0 + slot1->feedback_modulation1) / 2; + slot1->feedback_modulation0 = slot1->feedback_modulation1; + + slot1_output = wavetable[slot1->waveform][((slot1->stepptr + feedback) >> 16) & SIN_MASK]; + slot1_output = (slot1_output * env1) >> 16; + + phase_mod = ((slot1_output << (SIN_BITS-2)) * modulation_level[slot2->feedback]); + slot2_output = wavetable[slot2->waveform][((slot2->stepptr + phase_mod) >> 16) & SIN_MASK]; + slot2_output = (slot2_output * env2) >> 16; + + slot1->feedback_modulation1 = (((slot1_output << (SIN_BITS-2)) * feedback_level[slot1->feedback]) / 16); + + slot1->stepptr += slot1->step; + slot2->stepptr += slot2->step; + + return slot2_output; +} + +// calculates 2 operator FM using algorithm 1 +// <-----------------| +// +--[S1]--+--[S3]--|--> +INLINE INT32 calculate_2op_fm_1(YMF271Chip *chip, int slotnum1, int slotnum2) +{ + YMF271Slot *slot1 = &chip->slots[slotnum1]; + YMF271Slot *slot2 = &chip->slots[slotnum2]; + INT64 env1, env2; + INT64 slot1_output, slot2_output; + INT64 phase_mod; + INT64 feedback; + + update_envelope(slot1); + update_lfo(slot1); + env1 = calculate_slot_volume(slot1); + update_envelope(slot2); + update_lfo(slot2); + env2 = calculate_slot_volume(slot2); + + feedback = (slot1->feedback_modulation0 + slot1->feedback_modulation1) / 2; + slot1->feedback_modulation0 = slot1->feedback_modulation1; + + slot1_output = wavetable[slot1->waveform][((slot1->stepptr + feedback) >> 16) & SIN_MASK]; + slot1_output = (slot1_output * env1) >> 16; + + phase_mod = ((slot1_output << (SIN_BITS-2)) * modulation_level[slot2->feedback]); + slot2_output = wavetable[slot2->waveform][((slot2->stepptr + phase_mod) >> 16) & SIN_MASK]; + slot2_output = (slot2_output * env2) >> 16; + + slot1->feedback_modulation1 = (((slot2_output << (SIN_BITS-2)) * feedback_level[slot1->feedback]) / 16); + + slot1->stepptr += slot1->step; + slot2->stepptr += slot2->step; + + return slot2_output; +} + +// calculates the output of one FM operator +INLINE INT32 calculate_1op_fm_0(YMF271Chip *chip, int slotnum, int phase_modulation) +{ + YMF271Slot *slot = &chip->slots[slotnum]; + INT64 env; + INT64 slot_output; + INT64 phase_mod = phase_modulation; + + update_envelope(slot); + update_lfo(slot); + env = calculate_slot_volume(slot); + + phase_mod = ((phase_mod << (SIN_BITS-2)) * modulation_level[slot->feedback]); + + slot_output = wavetable[slot->waveform][((slot->stepptr + phase_mod) >> 16) & SIN_MASK]; + slot->stepptr += slot->step; + + slot_output = (slot_output * env) >> 16; + + return slot_output; +} + +// calculates the output of one FM operator with feedback modulation +// <--------| +// +--[S1]--| +INLINE INT32 calculate_1op_fm_1(YMF271Chip *chip, int slotnum) +{ + YMF271Slot *slot = &chip->slots[slotnum]; + INT64 env; + INT64 slot_output; + INT64 feedback; + + update_envelope(slot); + update_lfo(slot); + env = calculate_slot_volume(slot); + + feedback = slot->feedback_modulation0 + slot->feedback_modulation1; + slot->feedback_modulation0 = slot->feedback_modulation1; + + slot_output = wavetable[slot->waveform][((slot->stepptr + feedback) >> 16) & SIN_MASK]; + slot_output = (slot_output * env) >> 16; + + slot->feedback_modulation1 = (((slot_output << (SIN_BITS-2)) * feedback_level[slot->feedback]) / 16); + slot->stepptr += slot->step; + + return slot_output; +} + +static void ymf271_update(void *param, stream_sample_t **inputs, stream_sample_t **outputs, int length) +{ + int i, j; + int op; + INT32 *mixp; + YMF271Chip *chip = param; + + memset(mix, 0, sizeof(mix[0])*length*2); + + for (j = 0; j < 12; j++) + { + YMF271Group *slot_group = &chip->groups[j]; + mixp = &mix[0]; + + if (slot_group->pfm && slot_group->sync != 3) + { + mame_printf_debug("Group %d: PFM, Sync = %d, Waveform Slot1 = %d, Slot2 = %d, Slot3 = %d, Slot4 = %d\n", + j, slot_group->sync, chip->slots[j+0].waveform, chip->slots[j+12].waveform, chip->slots[j+24].waveform, chip->slots[j+36].waveform); + } + + switch (slot_group->sync) + { + case 0: // 4 operator FM + { + int slot1 = j + (0*12); + int slot2 = j + (1*12); + int slot3 = j + (2*12); + int slot4 = j + (3*12); + mixp = &mix[0]; + + if (chip->slots[slot1].active) + { + for (i = 0; i < length; i++) + { + INT64 output1 = 0, output2 = 0, output3 = 0, output4 = 0, phase_mod1 = 0, phase_mod2 = 0; + switch (chip->slots[slot1].algorithm) + { + // <--------| + // +--[S1]--+--[S3]--+--[S2]--+--[S4]--> + case 0: + phase_mod1 = calculate_2op_fm_0(chip, slot1, slot3); + phase_mod2 = calculate_1op_fm_0(chip, slot2, phase_mod1); + output4 = calculate_1op_fm_0(chip, slot4, phase_mod2); + break; + + // <-----------------| + // +--[S1]--+--[S3]--+--[S2]--+--[S4]--> + case 1: + phase_mod1 = calculate_2op_fm_1(chip, slot1, slot3); + phase_mod2 = calculate_1op_fm_0(chip, slot2, phase_mod1); + output4 = calculate_1op_fm_0(chip, slot4, phase_mod2); + break; + + // <--------| + // +--[S1]--| + // ---[S3]--+--[S2]--+--[S4]--> + case 2: + phase_mod1 = (calculate_1op_fm_1(chip, slot1) + calculate_1op_fm_0(chip, slot3, 0)) / 2; + phase_mod2 = calculate_1op_fm_0(chip, slot2, phase_mod1); + output4 = calculate_1op_fm_0(chip, slot4, phase_mod2); + break; + + // <--------| + // +--[S1]--| + // ---[S3]--+--[S2]--+--[S4]--> + case 3: + phase_mod1 = calculate_1op_fm_0(chip, slot3, 0); + phase_mod2 = (calculate_1op_fm_0(chip, slot2, phase_mod1) + calculate_1op_fm_1(chip, slot1)) / 2; + output4 = calculate_1op_fm_0(chip, slot4, phase_mod2); + break; + + // <--------| --[S2]--| + // ---[S1]--|-+--[S3]--+--[S4]--> + case 4: + phase_mod1 = (calculate_2op_fm_0(chip, slot1, slot3) + calculate_1op_fm_0(chip, slot2, 0)) / 2; + output4 = calculate_1op_fm_0(chip, slot4, phase_mod1); + break; + + // --[S2]-----| + // <-----------------| | + // ---[S1]--+--[S3]--|--+--[S4]--> + case 5: + phase_mod1 = (calculate_2op_fm_1(chip, slot1, slot3) + calculate_1op_fm_0(chip, slot2, 0)) / 2; + output4 = calculate_1op_fm_0(chip, slot4, phase_mod1); + break; + + // ---[S2]-----+--[S4]--| + // | + // <--------| | + // +--[S1]--|--+--[S3]--+--> + case 6: + output3 = calculate_2op_fm_0(chip, slot1, slot3); + phase_mod1 = calculate_1op_fm_0(chip, slot2, 0); + output4 = calculate_1op_fm_0(chip, slot4, phase_mod1); + break; + + // ---[S2]--+--[S4]-----| + // | + // <-----------------| | + // +--[S1]--+--[S3]--|--+--> + case 7: + output3 = calculate_2op_fm_1(chip, slot1, slot3); + phase_mod1 = calculate_1op_fm_0(chip, slot2, 0); + output4 = calculate_1op_fm_0(chip, slot4, phase_mod1); + break; + + // ---[S3]--+--[S2]--+--[S4]--| + // | + // <--------| | + // +--[S1]--|-----------------+--> + case 8: + output1 = calculate_1op_fm_1(chip, slot1); + phase_mod1 = calculate_1op_fm_0(chip, slot3, 0); + phase_mod2 = calculate_1op_fm_0(chip, slot2, phase_mod1); + output4 = calculate_1op_fm_0(chip, slot4, phase_mod2); + break; + + // <--------| + // -----------[S1]--| + // | + // --[S3]--| | + // --[S2]--+--[S4]--+--> + case 9: + phase_mod1 = (calculate_1op_fm_0(chip, slot2, 0) + calculate_1op_fm_0(chip, slot3, 0)) / 2; + output4 = calculate_1op_fm_0(chip, slot4, phase_mod1); + output1 = calculate_1op_fm_1(chip, slot1); + break; + + // --[S4]--| + // --[S2]--+ + // <--------| | + // +--[S1]--+--[S3]--+--> + case 10: + output3 = calculate_2op_fm_0(chip, slot1, slot3); + output2 = calculate_1op_fm_0(chip, slot2, 0); + output4 = calculate_1op_fm_0(chip, slot4, 0); + break; + + // --[S4]-----| + // --[S2]-----+ + // <-----------------| | + // +--[S1]--+--[S3]--|--+--> + case 11: + output3 = calculate_2op_fm_1(chip, slot1, slot3); + output2 = calculate_1op_fm_0(chip, slot2, 0); + output4 = calculate_1op_fm_0(chip, slot4, 0); + break; + + // |--+--[S4]--+ + // <--------| |--+--[S3]--+ + // +--[S1]--+-|--+--[S2]--+--> + case 12: + phase_mod1 = calculate_1op_fm_1(chip, slot1); + output2 = calculate_1op_fm_0(chip, slot2, phase_mod1); + output3 = calculate_1op_fm_0(chip, slot3, phase_mod1); + output4 = calculate_1op_fm_0(chip, slot4, phase_mod1); + break; + + // ---[S3]--+--[S2]--+ + // | + // ---[S4]-----------+ + // <--------| | + // +--[S1]--|--------+--> + case 13: + output1 = calculate_1op_fm_1(chip, slot1); + phase_mod1 = calculate_1op_fm_0(chip, slot3, 0); + output2 = calculate_1op_fm_0(chip, slot2, phase_mod1); + output4 = calculate_1op_fm_0(chip, slot4, 0); + break; + + // ---[S2]----+--[S4]--+ + // | + // <--------| +--[S3]--| + // +--[S1]--+-|--------+--> + case 14: + output1 = calculate_1op_fm_1(chip, slot1); + phase_mod1 = output1; + output3 = calculate_1op_fm_0(chip, slot3, phase_mod1); + phase_mod2 = calculate_1op_fm_0(chip, slot2, 0); + output4 = calculate_1op_fm_0(chip, slot4, phase_mod2); + break; + + // --[S4]-----+ + // --[S2]-----+ + // --[S3]-----+ + // <--------| | + // +--[S1]--|--+--> + case 15: + output1 = calculate_1op_fm_1(chip, slot1); + output2 = calculate_1op_fm_0(chip, slot2, 0); + output3 = calculate_1op_fm_0(chip, slot3, 0); + output4 = calculate_1op_fm_0(chip, slot4, 0); + break; + } + + *mixp++ += ((output1 * channel_attenuation[chip->slots[slot1].ch0_level]) + + (output2 * channel_attenuation[chip->slots[slot2].ch0_level]) + + (output3 * channel_attenuation[chip->slots[slot3].ch0_level]) + + (output4 * channel_attenuation[chip->slots[slot4].ch0_level])) >> 16; + *mixp++ += ((output1 * channel_attenuation[chip->slots[slot1].ch1_level]) + + (output2 * channel_attenuation[chip->slots[slot2].ch1_level]) + + (output3 * channel_attenuation[chip->slots[slot3].ch1_level]) + + (output4 * channel_attenuation[chip->slots[slot4].ch1_level])) >> 16; + } + } + break; + } + + case 1: // 2x 2 operator FM + { + for (op = 0; op < 2; op++) + { + int slot1 = j + ((op + 0) * 12); + int slot2 = j + ((op + 2) * 12); + + mixp = &mix[0]; + if (chip->slots[slot1].active) + { + for (i = 0; i < length; i++) + { + INT64 output1 = 0, output2 = 0, phase_mod = 0; + switch (chip->slots[slot1].algorithm & 3) + { + // <--------| + // +--[S1]--+--[S3]--> + case 0: + output2 = calculate_2op_fm_0(chip, slot1, slot2); + break; + + // <-----------------| + // +--[S1]--+--[S3]--|--> + case 1: + output2 = calculate_2op_fm_1(chip, slot1, slot2); + break; + + // ---[S3]-----| + // <--------| | + // +--[S1]--|--+--> + case 2: + output1 = calculate_1op_fm_1(chip, slot1); + output2 = calculate_1op_fm_0(chip, slot2, 0); + break; + // + // <--------| +--[S3]--| + // +--[S1]--|-|--------+--> + case 3: + output1 = calculate_1op_fm_1(chip, slot1); + phase_mod = output1; + output2 = calculate_1op_fm_0(chip, slot2, phase_mod); + break; + } + + *mixp++ += ((output1 * channel_attenuation[chip->slots[slot1].ch0_level]) + + (output2 * channel_attenuation[chip->slots[slot2].ch0_level])) >> 16; + *mixp++ += ((output1 * channel_attenuation[chip->slots[slot1].ch1_level]) + + (output2 * channel_attenuation[chip->slots[slot2].ch1_level])) >> 16; + } + } + } + break; + } + + case 2: // 3 operator FM + PCM + { + int slot1 = j + (0*12); + int slot2 = j + (1*12); + int slot3 = j + (2*12); + mixp = &mix[0]; + + if (chip->slots[slot1].active) + { + for (i = 0; i < length; i++) + { + INT64 output1 = 0, output2 = 0, output3 = 0, phase_mod = 0; + switch (chip->slots[slot1].algorithm & 7) + { + // <--------| + // +--[S1]--+--[S3]--+--[S2]--> + case 0: + phase_mod = calculate_2op_fm_0(chip, slot1, slot3); + output2 = calculate_1op_fm_0(chip, slot2, phase_mod); + break; + + // <-----------------| + // +--[S1]--+--[S3]--+--[S2]--> + case 1: + phase_mod = calculate_2op_fm_1(chip, slot1, slot3); + output2 = calculate_1op_fm_0(chip, slot2, phase_mod); + break; + + // ---[S3]-----| + // <--------| | + // +--[S1]--+--+--[S2]--> + case 2: + phase_mod = (calculate_1op_fm_1(chip, slot1) + calculate_1op_fm_0(chip, slot3, 0)) / 2; + output2 = calculate_1op_fm_0(chip, slot2, phase_mod); + break; + + // ---[S3]--+--[S2]--| + // <--------| | + // +--[S1]--|--------+--> + case 3: + phase_mod = calculate_1op_fm_0(chip, slot3, 0); + output2 = calculate_1op_fm_0(chip, slot2, phase_mod); + output1 = calculate_1op_fm_1(chip, slot1); + break; + + // ------------[S2]--| + // <--------| | + // +--[S1]--+--[S3]--+--> + case 4: + output3 = calculate_2op_fm_0(chip, slot1, slot3); + output2 = calculate_1op_fm_0(chip, slot2, 0); + break; + + // ------------[S2]--| + // <-----------------| + // +--[S1]--+--[S3]--+--> + case 5: + output3 = calculate_2op_fm_1(chip, slot1, slot3); + output2 = calculate_1op_fm_0(chip, slot2, 0); + break; + + // ---[S2]-----| + // ---[S3]-----+ + // <--------| | + // +--[S1]--+--+--> + case 6: + output1 = calculate_1op_fm_1(chip, slot1); + output3 = calculate_1op_fm_0(chip, slot3, 0); + output2 = calculate_1op_fm_0(chip, slot2, 0); + break; + + // --------------[S2]--+ + // <--------| +--[S3]--| + // +--[S1]--+-|--------+--> + case 7: + output1 = calculate_1op_fm_1(chip, slot1); + phase_mod = output1; + output3 = calculate_1op_fm_0(chip, slot3, phase_mod); + output2 = calculate_1op_fm_0(chip, slot2, 0); + break; + } + + *mixp++ += ((output1 * channel_attenuation[chip->slots[slot1].ch0_level]) + + (output2 * channel_attenuation[chip->slots[slot2].ch0_level]) + + (output3 * channel_attenuation[chip->slots[slot3].ch0_level])) >> 16; + *mixp++ += ((output1 * channel_attenuation[chip->slots[slot1].ch1_level]) + + (output2 * channel_attenuation[chip->slots[slot2].ch1_level]) + + (output3 * channel_attenuation[chip->slots[slot3].ch1_level])) >> 16; + } + } + + update_pcm(chip, j + (3*12), mixp, length); + break; + } + + case 3: // PCM + { + update_pcm(chip, j + (0*12), mixp, length); + update_pcm(chip, j + (1*12), mixp, length); + update_pcm(chip, j + (2*12), mixp, length); + update_pcm(chip, j + (3*12), mixp, length); + break; + } + + default: break; + } + } + + mixp = &mix[0]; + for (i = 0; i < length; i++) + { + outputs[0][i] = (*mixp++)>>2; + outputs[1][i] = (*mixp++)>>2; + } +} + +static void write_register(YMF271Chip *chip, int slotnum, int reg, int data) +{ + YMF271Slot *slot = &chip->slots[slotnum]; + + switch (reg) + { + case 0: + { + slot->extout = (data>>3)&0xf; + + if (data & 1) + { + // key on + slot->step = 0; + slot->stepptr = 0; + + slot->active = 1; + + calculate_step(slot); + init_envelope(slot); + init_lfo(slot); + slot->feedback_modulation0 = 0; + slot->feedback_modulation1 = 0; + } + else + { + if (slot->active) + { + //slot->active = 0; + slot->env_state = ENV_RELEASE; + } + } + break; + } + + case 1: + { + slot->lfoFreq = data; + break; + } + + case 2: + { + slot->lfowave = data & 3; + slot->pms = (data >> 3) & 0x7; + slot->ams = (data >> 6) & 0x3; + break; + } + + case 3: + { + slot->multiple = data & 0xf; + slot->detune = (data >> 4) & 0x7; + break; + } + + case 4: + { + slot->tl = data & 0x7f; + break; + } + + case 5: + { + slot->ar = data & 0x1f; + slot->keyscale = (data>>5)&0x7; + break; + } + + case 6: + { + slot->decay1rate = data & 0x1f; + break; + } + + case 7: + { + slot->decay2rate = data & 0x1f; + break; + } + + case 8: + { + slot->relrate = data & 0xf; + slot->decay1lvl = (data >> 4) & 0xf; + break; + } + + case 9: + { + slot->fns &= ~0xff; + slot->fns |= data; + + calculate_step(slot); + break; + } + + case 10: + { + slot->fns &= ~0xff00; + slot->fns |= (data & 0xf)<<8; + slot->block = (data>>4)&0xf; + break; + } + + case 11: + { + slot->waveform = data & 0x7; + slot->feedback = (data >> 4) & 0x7; + slot->accon = (data & 0x80) ? 1 : 0; + break; + } + + case 12: + { + slot->algorithm = data & 0xf; + break; + } + + case 13: + { + slot->ch0_level = data >> 4; + slot->ch1_level = data & 0xf; + break; + } + + case 14: + { + slot->ch2_level = data >> 4; + slot->ch3_level = data & 0xf; + break; + } + } +} + +static void ymf271_write_fm(YMF271Chip *chip, int grp, int adr, int data) +{ + int reg; + int slotnum; + int slot_group; + int sync_mode, sync_reg; + YMF271Slot *slot; + + slotnum = 12*grp; + slotnum += fm_tab[adr & 0xf]; + slot = &chip->slots[slotnum]; + slot_group = fm_tab[adr & 0xf]; + + reg = (adr >> 4) & 0xf; + + // check if the register is a synchronized register + sync_reg = 0; + switch (reg) + { + case 0: + case 9: + case 10: + case 12: + case 13: + case 14: + sync_reg = 1; + break; + + default: + break; + } + + // check if the slot is key on slot for synchronizing + sync_mode = 0; + switch (chip->groups[slot_group].sync) + { + case 0: // 4 slot mode + { + if (grp == 0) + sync_mode = 1; + break; + } + case 1: // 2x 2 slot mode + { + if (grp == 0 || grp == 1) + sync_mode = 1; + break; + } + case 2: // 3 slot + 1 slot mode + { + if (grp == 0) + sync_mode = 1; + break; + } + + default: + break; + } + + if (sync_mode && sync_reg) // key-on slot & synced register + { + switch (chip->groups[slot_group].sync) + { + case 0: // 4 slot mode + { + write_register(chip, (12 * 0) + slot_group, reg, data); + write_register(chip, (12 * 1) + slot_group, reg, data); + write_register(chip, (12 * 2) + slot_group, reg, data); + write_register(chip, (12 * 3) + slot_group, reg, data); + break; + } + case 1: // 2x 2 slot mode + { + if (grp == 0) // Slot 1 - Slot 3 + { + write_register(chip, (12 * 0) + slot_group, reg, data); + write_register(chip, (12 * 2) + slot_group, reg, data); + } + else // Slot 2 - Slot 4 + { + write_register(chip, (12 * 1) + slot_group, reg, data); + write_register(chip, (12 * 3) + slot_group, reg, data); + } + break; + } + case 2: // 3 slot + 1 slot mode + { + // 1 slot is handled normally + write_register(chip, (12 * 0) + slot_group, reg, data); + write_register(chip, (12 * 1) + slot_group, reg, data); + write_register(chip, (12 * 2) + slot_group, reg, data); + break; + } + default: + break; + } + } + else // write register normally + { + write_register(chip, (12 * grp) + slot_group, reg, data); + } +} + +static void ymf271_write_pcm(YMF271Chip *chip, int data) +{ + int slotnum; + YMF271Slot *slot; + + slotnum = pcm_tab[chip->pcmreg&0xf]; + slot = &chip->slots[slotnum]; + + switch ((chip->pcmreg>>4)&0xf) + { + case 0: + slot->startaddr &= ~0xff; + slot->startaddr |= data; + break; + case 1: + slot->startaddr &= ~0xff00; + slot->startaddr |= data<<8; + break; + case 2: + slot->startaddr &= ~0xff0000; + slot->startaddr |= data<<16; + break; + case 3: + slot->endaddr &= ~0xff; + slot->endaddr |= data; + break; + case 4: + slot->endaddr &= ~0xff00; + slot->endaddr |= data<<8; + break; + case 5: + slot->endaddr &= ~0xff0000; + slot->endaddr |= data<<16; + break; + case 6: + slot->loopaddr &= ~0xff; + slot->loopaddr |= data; + break; + case 7: + slot->loopaddr &= ~0xff00; + slot->loopaddr |= data<<8; + break; + case 8: + slot->loopaddr &= ~0xff0000; + slot->loopaddr |= data<<16; + break; + case 9: + slot->fs = data & 0x3; + slot->bits = (data & 0x4) ? 12 : 8; + slot->srcnote = (data >> 3) & 0x3; + slot->srcb = (data >> 5) & 0x7; + break; + } +} + +static TIMER_CALLBACK_PTR( ymf271_timer_a_tick ) +{ + YMF271Chip *chip = param; + + chip->status |= 1; + + if (chip->enable & 4) + { + chip->irqstate |= 1; + if (chip->irq_callback) chip->irq_callback(1); + } +} + +static TIMER_CALLBACK_PTR( ymf271_timer_b_tick ) +{ + YMF271Chip *chip = param; + + chip->status |= 2; + + if (chip->enable & 8) + { + chip->irqstate |= 2; + if (chip->irq_callback) chip->irq_callback(1); + } +} + +static UINT8 ymf271_read_ext_memory(YMF271Chip *chip, UINT32 address) +{ + if( chip->ext_mem_read ) { + return chip->ext_mem_read(address); + } else { + if( address < 0x800000) + return chip->rom[address]; + } + return 0xff; +} + +static void ymf271_write_ext_memory(YMF271Chip *chip, UINT32 address, UINT8 data) +{ + if( chip->ext_mem_write ) { + chip->ext_mem_write(address, data); + } +} + +static void ymf271_write_timer(YMF271Chip *chip, int data) +{ + int slotnum; + YMF271Group *group; + attotime period; + + slotnum = fm_tab[chip->timerreg & 0xf]; + group = &chip->groups[slotnum]; + + if ((chip->timerreg & 0xf0) == 0) + { + group->sync = data & 0x3; + group->pfm = data >> 7; + } + else + { + switch (chip->timerreg) + { + case 0x10: + chip->timerA &= ~0xff; + chip->timerA |= data; + break; + + case 0x11: + if (!(data & 0xfc)) + { + chip->timerA &= 0x00ff; + if ((data & 0x3) != 0x3) + { + chip->timerA |= (data & 0xff)<<8; + } + } + break; + + case 0x12: + chip->timerB = data; + break; + + case 0x13: + if (data & 1) + { // timer A load + chip->timerAVal = chip->timerA; + } + if (data & 2) + { // timer B load + chip->timerBVal = chip->timerB; + } + if (data & 4) + { + // timer A IRQ enable + chip->enable |= 4; + } + if (data & 8) + { + // timer B IRQ enable + chip->enable |= 8; + } + if (data & 0x10) + { // timer A reset + chip->irqstate &= ~1; + chip->status &= ~1; + + if (chip->irq_callback) chip->irq_callback(0); + + //period = (double)(256.0 - chip->timerAVal ) * ( 384.0 * 4.0 / (double)CLOCK); + period = attotime_mul(ATTOTIME_IN_HZ(chip->clock), 384 * (1024 - chip->timerAVal)); + + timer_adjust_ptr(chip->timA, period, period); + } + if (data & 0x20) + { // timer B reset + chip->irqstate &= ~2; + chip->status &= ~2; + + if (chip->irq_callback) chip->irq_callback(0); + + period = attotime_mul(ATTOTIME_IN_HZ(chip->clock), 384 * 16 * (256 - chip->timerBVal)); + + timer_adjust_ptr(chip->timB, period, period); + } + + break; + + case 0x14: + chip->ext_address &= ~0xff; + chip->ext_address |= data; + break; + case 0x15: + chip->ext_address &= ~0xff00; + chip->ext_address |= data << 8; + break; + case 0x16: + chip->ext_address &= ~0xff0000; + chip->ext_address |= (data & 0x7f) << 16; + chip->ext_read = (data & 0x80) ? 1 : 0; + if( !chip->ext_read ) + chip->ext_address = (chip->ext_address + 1) & 0x7fffff; + break; + case 0x17: + ymf271_write_ext_memory( chip, chip->ext_address, data ); + chip->ext_address = (chip->ext_address + 1) & 0x7fffff; + break; + } + } +} + +static void ymf271_w(int chipnum, int offset, int data) +{ + YMF271Chip *chip = sndti_token(SOUND_YMF271, chipnum); + + switch (offset) + { + case 0: + chip->reg0 = data; + break; + case 1: + ymf271_write_fm(chip, 0, chip->reg0, data); + break; + case 2: + chip->reg1 = data; + break; + case 3: + ymf271_write_fm(chip, 1, chip->reg1, data); + break; + case 4: + chip->reg2 = data; + break; + case 5: + ymf271_write_fm(chip, 2, chip->reg2, data); + break; + case 6: + chip->reg3 = data; + break; + case 7: + ymf271_write_fm(chip, 3, chip->reg3, data); + break; + case 8: + chip->pcmreg = data; + break; + case 9: + ymf271_write_pcm(chip, data); + break; + case 0xc: + chip->timerreg = data; + break; + case 0xd: + ymf271_write_timer(chip, data); + break; + } +} + +static int ymf271_r(int chipnum, int offset) +{ + UINT8 value; + YMF271Chip *chip = sndti_token(SOUND_YMF271, chipnum); + + switch(offset) + { + case 0: + return chip->status; + + case 2: + value = ymf271_read_ext_memory( chip, chip->ext_address ); + chip->ext_address = (chip->ext_address + 1) & 0x7fffff; + return value; + } + + return 0; +} + +static void init_tables(void) +{ + int i,j; + + for (i=0; i < ARRAY_LENGTH(wavetable); i++) + { + wavetable[i] = auto_malloc(SIN_LEN * sizeof(INT16)); + } + + for (i=0; i < SIN_LEN; i++) + { + double m = sin( ((i*2)+1) * M_PI / SIN_LEN ); + double m2 = sin( ((i*4)+1) * M_PI / SIN_LEN ); + + // Waveform 0: sin(wt) (0 <= wt <= 2PI) + wavetable[0][i] = (INT16)(m * MAXOUT); + + // Waveform 1: sin?(wt) (0 <= wt <= PI) -sin?(wt) (PI <= wt <= 2PI) + wavetable[1][i] = (i < (SIN_LEN/2)) ? (INT16)((m * m) * MAXOUT) : (INT16)((m * m) * MINOUT); + + // Waveform 2: sin(wt) (0 <= wt <= PI) -sin(wt) (PI <= wt <= 2PI) + wavetable[2][i] = (i < (SIN_LEN/2)) ? (INT16)(m * MAXOUT) : (INT16)(-m * MAXOUT); + + // Waveform 3: sin(wt) (0 <= wt <= PI) 0 + wavetable[3][i] = (i < (SIN_LEN/2)) ? (INT16)(m * MAXOUT) : 0; + + // Waveform 4: sin(2wt) (0 <= wt <= PI) 0 + wavetable[4][i] = (i < (SIN_LEN/2)) ? (INT16)(m2 * MAXOUT) : 0; + + // Waveform 5: |sin(2wt)| (0 <= wt <= PI) 0 + wavetable[5][i] = (i < (SIN_LEN/2)) ? (INT16)(fabs(m2) * MAXOUT) : 0; + + // Waveform 6: 1 (0 <= wt <= 2PI) + wavetable[6][i] = (INT16)(1 * MAXOUT); + + wavetable[7][i] = 0; + } + + for (i=0; i < LFO_LENGTH; i++) + { + int tri_wave; + double ftri_wave, fsaw_wave; + double plfo[4]; + + // LFO phase modulation + plfo[0] = 0; + + fsaw_wave = ((i % (LFO_LENGTH/2)) * PLFO_MAX) / (double)((LFO_LENGTH/2)-1); + plfo[1] = (i < (LFO_LENGTH/2)) ? fsaw_wave : fsaw_wave - PLFO_MAX; + + plfo[2] = (i < (LFO_LENGTH/2)) ? PLFO_MAX : PLFO_MIN; + + ftri_wave = ((i % (LFO_LENGTH/4)) * PLFO_MAX) / (double)(LFO_LENGTH/4); + switch (i / (LFO_LENGTH/4)) + { + case 0: plfo[3] = ftri_wave; break; + case 1: plfo[3] = PLFO_MAX - ftri_wave; break; + case 2: plfo[3] = 0 - ftri_wave; break; + case 3: plfo[3] = 0 - (PLFO_MAX - ftri_wave); break; + } + + for (j=0; j < 4; j++) + { + plfo_table[j][0][i] = pow(2.0, 0.0); + plfo_table[j][1][i] = pow(2.0, (3.378 * plfo[j]) / 1200.0); + plfo_table[j][2][i] = pow(2.0, (5.0646 * plfo[j]) / 1200.0); + plfo_table[j][3][i] = pow(2.0, (6.7495 * plfo[j]) / 1200.0); + plfo_table[j][4][i] = pow(2.0, (10.1143 * plfo[j]) / 1200.0); + plfo_table[j][5][i] = pow(2.0, (20.1699 * plfo[j]) / 1200.0); + plfo_table[j][6][i] = pow(2.0, (40.1076 * plfo[j]) / 1200.0); + plfo_table[j][7][i] = pow(2.0, (79.307 * plfo[j]) / 1200.0); + } + + // LFO amplitude modulation + alfo_table[0][i] = 0; + + alfo_table[1][i] = ALFO_MAX - ((i * ALFO_MAX) / LFO_LENGTH); + + alfo_table[2][i] = (i < (LFO_LENGTH/2)) ? ALFO_MAX : ALFO_MIN; + + tri_wave = ((i % (LFO_LENGTH/2)) * ALFO_MAX) / (LFO_LENGTH/2); + alfo_table[3][i] = (i < (LFO_LENGTH/2)) ? ALFO_MAX-tri_wave : tri_wave; + } + + mix = auto_malloc(48000*2*sizeof(*mix)); +} + +static void init_state(YMF271Chip *chip) +{ + int i, instance; + + for (i = 0; i < sizeof(chip->slots) / sizeof(chip->slots[0]); i++) + { + instance = chip->index * (sizeof(chip->slots) / sizeof(chip->slots[0])) + i; + + state_save_register_item("ymf271", instance, chip->slots[i].extout); + state_save_register_item("ymf271", instance, chip->slots[i].lfoFreq); + state_save_register_item("ymf271", instance, chip->slots[i].pms); + state_save_register_item("ymf271", instance, chip->slots[i].ams); + state_save_register_item("ymf271", instance, chip->slots[i].detune); + state_save_register_item("ymf271", instance, chip->slots[i].multiple); + state_save_register_item("ymf271", instance, chip->slots[i].tl); + state_save_register_item("ymf271", instance, chip->slots[i].keyscale); + state_save_register_item("ymf271", instance, chip->slots[i].ar); + state_save_register_item("ymf271", instance, chip->slots[i].decay1rate); + state_save_register_item("ymf271", instance, chip->slots[i].decay2rate); + state_save_register_item("ymf271", instance, chip->slots[i].decay1lvl); + state_save_register_item("ymf271", instance, chip->slots[i].relrate); + state_save_register_item("ymf271", instance, chip->slots[i].fns); + state_save_register_item("ymf271", instance, chip->slots[i].block); + state_save_register_item("ymf271", instance, chip->slots[i].feedback); + state_save_register_item("ymf271", instance, chip->slots[i].waveform); + state_save_register_item("ymf271", instance, chip->slots[i].accon); + state_save_register_item("ymf271", instance, chip->slots[i].algorithm); + state_save_register_item("ymf271", instance, chip->slots[i].ch0_level); + state_save_register_item("ymf271", instance, chip->slots[i].ch1_level); + state_save_register_item("ymf271", instance, chip->slots[i].ch2_level); + state_save_register_item("ymf271", instance, chip->slots[i].ch3_level); + state_save_register_item("ymf271", instance, chip->slots[i].startaddr); + state_save_register_item("ymf271", instance, chip->slots[i].loopaddr); + state_save_register_item("ymf271", instance, chip->slots[i].endaddr); + state_save_register_item("ymf271", instance, chip->slots[i].fs); + state_save_register_item("ymf271", instance, chip->slots[i].srcnote); + state_save_register_item("ymf271", instance, chip->slots[i].srcb); + state_save_register_item("ymf271", instance, chip->slots[i].step); + state_save_register_item("ymf271", instance, chip->slots[i].stepptr); + state_save_register_item("ymf271", instance, chip->slots[i].active); + state_save_register_item("ymf271", instance, chip->slots[i].bits); + state_save_register_item("ymf271", instance, chip->slots[i].volume); + state_save_register_item("ymf271", instance, chip->slots[i].env_state); + state_save_register_item("ymf271", instance, chip->slots[i].env_attack_step); + state_save_register_item("ymf271", instance, chip->slots[i].env_decay1_step); + state_save_register_item("ymf271", instance, chip->slots[i].env_decay2_step); + state_save_register_item("ymf271", instance, chip->slots[i].env_release_step); + state_save_register_item("ymf271", instance, chip->slots[i].feedback_modulation0); + state_save_register_item("ymf271", instance, chip->slots[i].feedback_modulation1); + state_save_register_item("ymf271", instance, chip->slots[i].lfo_phase); + state_save_register_item("ymf271", instance, chip->slots[i].lfo_step); + state_save_register_item("ymf271", instance, chip->slots[i].lfo_amplitude); + } + + for (i = 0; i < sizeof(chip->groups) / sizeof(chip->groups[0]); i++) + { + instance = chip->index * (sizeof(chip->groups) / sizeof(chip->groups[0])) + i; + state_save_register_item("ymf271", instance, chip->groups[i].sync); + state_save_register_item("ymf271", instance, chip->groups[i].pfm); + } + + state_save_register_item("ymf271", chip->index, chip->timerA); + state_save_register_item("ymf271", chip->index, chip->timerB); + state_save_register_item("ymf271", chip->index, chip->timerAVal); + state_save_register_item("ymf271", chip->index, chip->timerBVal); + state_save_register_item("ymf271", chip->index, chip->irqstate); + state_save_register_item("ymf271", chip->index, chip->status); + state_save_register_item("ymf271", chip->index, chip->enable); + state_save_register_item("ymf271", chip->index, chip->reg0); + state_save_register_item("ymf271", chip->index, chip->reg1); + state_save_register_item("ymf271", chip->index, chip->reg2); + state_save_register_item("ymf271", chip->index, chip->reg3); + state_save_register_item("ymf271", chip->index, chip->pcmreg); + state_save_register_item("ymf271", chip->index, chip->timerreg); + state_save_register_item("ymf271", chip->index, chip->ext_address); + state_save_register_item("ymf271", chip->index, chip->ext_read); +} + +static void ymf271_init(YMF271Chip *chip, UINT8 *rom, void (*cb)(int), read8_handler ext_read, write8_handler ext_write) +{ + chip->timA = timer_alloc_ptr(ymf271_timer_a_tick, chip); + chip->timB = timer_alloc_ptr(ymf271_timer_b_tick, chip); + + chip->rom = rom; + chip->irq_callback = cb; + + chip->ext_mem_read = ext_read; + chip->ext_mem_write = ext_write; + + init_tables(); + init_state(chip); +} + +static void *ymf271_start(int sndindex, int clock, const void *config) +{ + const struct YMF271interface *intf; + int i; + YMF271Chip *chip; + + chip = auto_malloc(sizeof(*chip)); + memset(chip, 0, sizeof(*chip)); + chip->index = sndindex; + chip->clock = clock; + + intf = config; + + ymf271_init(chip, memory_region(intf->region), intf->irq_callback, intf->ext_read, intf->ext_write); + chip->stream = stream_create(0, 2, clock/384, chip, ymf271_update); + + for (i = 0; i < 256; i++) + { + env_volume_table[i] = (int)(65536.0 / pow(10.0, ((double)i / (256.0 / 96.0)) / 20.0)); + } + + for (i = 0; i < 16; i++) + { + channel_attenuation[i] = (int)(65536.0 / pow(10.0, channel_attenuation_table[i] / 20.0)); + } + for (i = 0; i < 128; i++) + { + double db = 0.75 * (double)i; + total_level[i] = (int)(65536.0 / pow(10.0, db / 20.0)); + } + + return chip; +} + +READ8_HANDLER( YMF271_0_r ) +{ + return ymf271_r(0, offset); +} + +WRITE8_HANDLER( YMF271_0_w ) +{ + ymf271_w(0, offset, data); +} + +READ8_HANDLER( YMF271_1_r ) +{ + return ymf271_r(1, offset); +} + +WRITE8_HANDLER( YMF271_1_w ) +{ + ymf271_w(1, offset, data); +} + +static void ymf271_reset(void *token) +{ + int i; + YMF271Chip *chip = (YMF271Chip*)token; + + for (i = 0; i < 48; i++) + { + chip->slots[i].active = 0; + chip->slots[i].volume = 0; + } +} + +/************************************************************************** + * Generic get_info + **************************************************************************/ + +static void ymf271_set_info(void *token, UINT32 state, sndinfo *info) +{ + switch (state) + { + /* no parameters to set */ + } +} + + +void ymf271_get_info(void *token, UINT32 state, sndinfo *info) +{ + switch (state) + { + /* --- the following bits of info are returned as 64-bit signed integers --- */ + + /* --- the following bits of info are returned as pointers to data or functions --- */ + case SNDINFO_PTR_SET_INFO: info->set_info = ymf271_set_info; break; + case SNDINFO_PTR_START: info->start = ymf271_start; break; + case SNDINFO_PTR_STOP: /* Nothing */ break; + case SNDINFO_PTR_RESET: info->reset = ymf271_reset; break; + + /* --- the following bits of info are returned as NULL-terminated strings --- */ + case SNDINFO_STR_NAME: info->s = "YMF271"; break; + case SNDINFO_STR_CORE_FAMILY: info->s = "Yamaha FM"; break; + case SNDINFO_STR_CORE_VERSION: info->s = "1.0"; break; + case SNDINFO_STR_CORE_FILE: info->s = __FILE__; break; + case SNDINFO_STR_CORE_CREDITS: info->s = "Copyright (c) 2004, The MAME Team"; break; + } +} |