mirror of
https://github.com/holub/mame
synced 2025-05-28 08:33:05 +03:00

Sent: Tuesday, December 09, 2008 8:13 PM To: submit@mamedev.org Cc: atariace@hotmail.com Subject: [patch] Add device parameter to stream_create() Hi mamedev, This patch adds the sound device to the parameters passed to stream_create so that the global Machine can be removed from streams.c. It assumes my previous patch which added CUSTOM_START and SAMPLES_START has been applied. ~aa
1844 lines
50 KiB
C
1844 lines
50 KiB
C
/*
|
|
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 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 "deprecat.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_space_func ext_mem_read;
|
|
write8_space_func ext_mem_write;
|
|
void (*irq_callback)(running_machine *, int);
|
|
|
|
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
|
|
};
|
|
|
|
/* Notes about the LFO Frequency Table below;
|
|
|
|
There appears to be at least 2 errors in the table from the original manual.
|
|
|
|
Both 201 & 202 where listed as 3.74490. 202 has be changed to 3.92000 which is "about right"
|
|
232 was listed as 13.35547. We use 14.35547 as it apears to be the correct value
|
|
*/
|
|
|
|
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,
|
|
14.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( ymf271_timer_a_tick )
|
|
{
|
|
YMF271Chip *chip = ptr;
|
|
|
|
chip->status |= 1;
|
|
|
|
if (chip->enable & 4)
|
|
{
|
|
chip->irqstate |= 1;
|
|
if (chip->irq_callback) chip->irq_callback(machine, 1);
|
|
}
|
|
}
|
|
|
|
static TIMER_CALLBACK( ymf271_timer_b_tick )
|
|
{
|
|
YMF271Chip *chip = ptr;
|
|
|
|
chip->status |= 2;
|
|
|
|
if (chip->enable & 8)
|
|
{
|
|
chip->irqstate |= 2;
|
|
if (chip->irq_callback) chip->irq_callback(machine, 1);
|
|
}
|
|
}
|
|
|
|
static UINT8 ymf271_read_ext_memory(YMF271Chip *chip, UINT32 address)
|
|
{
|
|
/* temporary hack until this is converted to a device */
|
|
const address_space *space = cpu_get_address_space(Machine->cpu[0], ADDRESS_SPACE_PROGRAM);
|
|
if( chip->ext_mem_read ) {
|
|
return chip->ext_mem_read(space,address);
|
|
} else {
|
|
if( address < 0x800000)
|
|
return chip->rom[address];
|
|
}
|
|
return 0xff;
|
|
}
|
|
|
|
static void ymf271_write_ext_memory(YMF271Chip *chip, UINT32 address, UINT8 data)
|
|
{
|
|
/* temporary hack until this is converted to a device */
|
|
const address_space *space = cpu_get_address_space(Machine->cpu[0], ADDRESS_SPACE_PROGRAM);
|
|
if( chip->ext_mem_write ) {
|
|
chip->ext_mem_write(space, address, data);
|
|
}
|
|
}
|
|
|
|
static void ymf271_write_timer(YMF271Chip *chip, int data)
|
|
{
|
|
int slotnum;
|
|
YMF271Group *group;
|
|
attotime period;
|
|
running_machine *machine = Machine;
|
|
|
|
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(machine, 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_periodic(chip->timA, period, 0, period);
|
|
}
|
|
if (data & 0x20)
|
|
{ // timer B reset
|
|
chip->irqstate &= ~2;
|
|
chip->status &= ~2;
|
|
|
|
if (chip->irq_callback) chip->irq_callback(machine, 0);
|
|
|
|
period = attotime_mul(ATTOTIME_IN_HZ(chip->clock), 384 * 16 * (256 - chip->timerBVal));
|
|
|
|
timer_adjust_periodic(chip->timB, period, 0, 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, const device_config *device)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < ARRAY_LENGTH(chip->slots); i++)
|
|
{
|
|
state_save_register_device_item(device, i, chip->slots[i].extout);
|
|
state_save_register_device_item(device, i, chip->slots[i].lfoFreq);
|
|
state_save_register_device_item(device, i, chip->slots[i].pms);
|
|
state_save_register_device_item(device, i, chip->slots[i].ams);
|
|
state_save_register_device_item(device, i, chip->slots[i].detune);
|
|
state_save_register_device_item(device, i, chip->slots[i].multiple);
|
|
state_save_register_device_item(device, i, chip->slots[i].tl);
|
|
state_save_register_device_item(device, i, chip->slots[i].keyscale);
|
|
state_save_register_device_item(device, i, chip->slots[i].ar);
|
|
state_save_register_device_item(device, i, chip->slots[i].decay1rate);
|
|
state_save_register_device_item(device, i, chip->slots[i].decay2rate);
|
|
state_save_register_device_item(device, i, chip->slots[i].decay1lvl);
|
|
state_save_register_device_item(device, i, chip->slots[i].relrate);
|
|
state_save_register_device_item(device, i, chip->slots[i].fns);
|
|
state_save_register_device_item(device, i, chip->slots[i].block);
|
|
state_save_register_device_item(device, i, chip->slots[i].feedback);
|
|
state_save_register_device_item(device, i, chip->slots[i].waveform);
|
|
state_save_register_device_item(device, i, chip->slots[i].accon);
|
|
state_save_register_device_item(device, i, chip->slots[i].algorithm);
|
|
state_save_register_device_item(device, i, chip->slots[i].ch0_level);
|
|
state_save_register_device_item(device, i, chip->slots[i].ch1_level);
|
|
state_save_register_device_item(device, i, chip->slots[i].ch2_level);
|
|
state_save_register_device_item(device, i, chip->slots[i].ch3_level);
|
|
state_save_register_device_item(device, i, chip->slots[i].startaddr);
|
|
state_save_register_device_item(device, i, chip->slots[i].loopaddr);
|
|
state_save_register_device_item(device, i, chip->slots[i].endaddr);
|
|
state_save_register_device_item(device, i, chip->slots[i].fs);
|
|
state_save_register_device_item(device, i, chip->slots[i].srcnote);
|
|
state_save_register_device_item(device, i, chip->slots[i].srcb);
|
|
state_save_register_device_item(device, i, chip->slots[i].step);
|
|
state_save_register_device_item(device, i, chip->slots[i].stepptr);
|
|
state_save_register_device_item(device, i, chip->slots[i].active);
|
|
state_save_register_device_item(device, i, chip->slots[i].bits);
|
|
state_save_register_device_item(device, i, chip->slots[i].volume);
|
|
state_save_register_device_item(device, i, chip->slots[i].env_state);
|
|
state_save_register_device_item(device, i, chip->slots[i].env_attack_step);
|
|
state_save_register_device_item(device, i, chip->slots[i].env_decay1_step);
|
|
state_save_register_device_item(device, i, chip->slots[i].env_decay2_step);
|
|
state_save_register_device_item(device, i, chip->slots[i].env_release_step);
|
|
state_save_register_device_item(device, i, chip->slots[i].feedback_modulation0);
|
|
state_save_register_device_item(device, i, chip->slots[i].feedback_modulation1);
|
|
state_save_register_device_item(device, i, chip->slots[i].lfo_phase);
|
|
state_save_register_device_item(device, i, chip->slots[i].lfo_step);
|
|
state_save_register_device_item(device, i, chip->slots[i].lfo_amplitude);
|
|
}
|
|
|
|
for (i = 0; i < sizeof(chip->groups) / sizeof(chip->groups[0]); i++)
|
|
{
|
|
state_save_register_device_item(device, i, chip->groups[i].sync);
|
|
state_save_register_device_item(device, i, chip->groups[i].pfm);
|
|
}
|
|
|
|
state_save_register_device_item(device, 0, chip->timerA);
|
|
state_save_register_device_item(device, 0, chip->timerB);
|
|
state_save_register_device_item(device, 0, chip->timerAVal);
|
|
state_save_register_device_item(device, 0, chip->timerBVal);
|
|
state_save_register_device_item(device, 0, chip->irqstate);
|
|
state_save_register_device_item(device, 0, chip->status);
|
|
state_save_register_device_item(device, 0, chip->enable);
|
|
state_save_register_device_item(device, 0, chip->reg0);
|
|
state_save_register_device_item(device, 0, chip->reg1);
|
|
state_save_register_device_item(device, 0, chip->reg2);
|
|
state_save_register_device_item(device, 0, chip->reg3);
|
|
state_save_register_device_item(device, 0, chip->pcmreg);
|
|
state_save_register_device_item(device, 0, chip->timerreg);
|
|
state_save_register_device_item(device, 0, chip->ext_address);
|
|
state_save_register_device_item(device, 0, chip->ext_read);
|
|
}
|
|
|
|
static void ymf271_init(const device_config *device, YMF271Chip *chip, UINT8 *rom, void (*cb)(running_machine *,int), read8_space_func ext_read, write8_space_func ext_write)
|
|
{
|
|
chip->timA = timer_alloc(device->machine, ymf271_timer_a_tick, chip);
|
|
chip->timB = timer_alloc(device->machine, 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, device);
|
|
}
|
|
|
|
static SND_START( ymf271 )
|
|
{
|
|
static const ymf271_interface defintrf = { 0 };
|
|
const ymf271_interface *intf;
|
|
int i;
|
|
YMF271Chip *chip;
|
|
|
|
chip = auto_malloc(sizeof(*chip));
|
|
memset(chip, 0, sizeof(*chip));
|
|
chip->clock = clock;
|
|
|
|
intf = (config != NULL) ? config : &defintrf;
|
|
|
|
ymf271_init(device, chip, device->region, intf->irq_callback, intf->ext_read, intf->ext_write);
|
|
chip->stream = stream_create(device, 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 SND_RESET( ymf271 )
|
|
{
|
|
int i;
|
|
YMF271Chip *chip = device->token;
|
|
|
|
for (i = 0; i < 48; i++)
|
|
{
|
|
chip->slots[i].active = 0;
|
|
chip->slots[i].volume = 0;
|
|
}
|
|
}
|
|
|
|
/**************************************************************************
|
|
* Generic get_info
|
|
**************************************************************************/
|
|
|
|
static SND_SET_INFO( ymf271 )
|
|
{
|
|
switch (state)
|
|
{
|
|
/* no parameters to set */
|
|
}
|
|
}
|
|
|
|
|
|
SND_GET_INFO( ymf271 )
|
|
{
|
|
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 = SND_SET_INFO_NAME( ymf271 ); break;
|
|
case SNDINFO_PTR_START: info->start = SND_START_NAME( ymf271 ); break;
|
|
case SNDINFO_PTR_STOP: /* Nothing */ break;
|
|
case SNDINFO_PTR_RESET: info->reset = SND_RESET_NAME( ymf271 ); 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 Nicola Salmoria and the MAME Team"; break;
|
|
}
|
|
}
|