1983 lines
56 KiB
C
1983 lines
56 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
|
|
|
|
TODO:
|
|
- A/L bit (alternate loop)
|
|
- EN and EXT Out bits
|
|
- Src B and Src NOTE bits
|
|
- statusreg Busy and End bits
|
|
- timer register 0x11
|
|
- ch2/ch3 (4 speakers)
|
|
- PFM (FM using external PCM waveform)
|
|
- detune (should be same as on other Yamaha chips)
|
|
- Acc On bit (some sound effects in viprp1?). The documentation says
|
|
"determines if slot output is accumulated(1), or output directly(0)"
|
|
- Is memory handling 100% correct? At the moment, seibuspi.c is the only
|
|
hardware currently emulated that uses external handlers.
|
|
*/
|
|
|
|
#include <math.h>
|
|
#include "mamedef.h"
|
|
//#include "sndintrf.h"
|
|
//#include "streams.h"
|
|
#ifdef _DEBUG
|
|
#include <stdio.h>
|
|
#endif
|
|
#include <stdlib.h>
|
|
#include <memory.h>
|
|
#include "ymf271.h"
|
|
|
|
#ifndef __cplusplus // C++ already has the bool-type
|
|
#define false 0x00
|
|
#define true 0x01
|
|
typedef unsigned char bool;
|
|
#endif // !__cplusplus
|
|
|
|
#define NULL ((void *)0)
|
|
|
|
//#define DEVCB_NULL { DEVCB_TYPE_NULL }
|
|
#define DEVCB_NULL DEVCB_TYPE_NULL
|
|
#define DEVCB_TYPE_NULL (0)
|
|
|
|
#define VERBOSE (1)
|
|
|
|
#define STD_CLOCK (16934400)
|
|
|
|
#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 ENV_ATTACK 0
|
|
#define ENV_DECAY1 1
|
|
#define ENV_DECAY2 2
|
|
#define ENV_RELEASE 3
|
|
|
|
#define OP_INPUT_FEEDBACK -1
|
|
#define OP_INPUT_NONE -2
|
|
|
|
#define ENV_VOLUME_SHIFT 16
|
|
|
|
#define INF -1.0
|
|
|
|
static const double ARTime[64] =
|
|
{
|
|
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[64] =
|
|
{
|
|
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 are 2 known errors in the LFO table listed in the original manual.
|
|
|
|
Both 201 & 202 are listed as 3.74490. 202 has been computed/corrected to 3.91513
|
|
232 was listed as 13.35547 but has been replaced with the correct value of 14.35547.
|
|
|
|
Corrections are computed values based on formulas by Olivier Galibert & Nicola Salmoria listed below:
|
|
|
|
LFO period seems easy to compute:
|
|
|
|
Olivier Galibert's version Nicola Salmoria's version
|
|
|
|
int lfo_period(int entry) or int calc_lfo_period(int entry)
|
|
{ {
|
|
int ma, ex; entry = 256 - entry;
|
|
entry = 256-entry;
|
|
ma = entry & 15; if (entry < 16)
|
|
{
|
|
ex = entry >> 4; return (entry & 0x0f) << 7;
|
|
if(ex) }
|
|
return (ma | 16) << (ex+6); else
|
|
else {
|
|
return ma << 7; int shift = 6 + (entry >> 4);
|
|
} return (0x10 + (entry & 0x0f)) << shift;
|
|
}
|
|
lfo_freq = 44100 / lfo_period }
|
|
|
|
*/
|
|
|
|
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.91513, 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 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 };
|
|
|
|
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 };
|
|
|
|
// slot mapping assists
|
|
static const int fm_tab[16] = { 0, 1, 2, -1, 3, 4, 5, -1, 6, 7, 8, -1, 9, 10, 11, -1 };
|
|
static const int pcm_tab[16] = { 0, 4, 8, -1, 12, 16, 20, -1, 24, 28, 32, -1, 36, 40, 44, -1 };
|
|
|
|
|
|
typedef struct
|
|
{
|
|
UINT8 ext_en;
|
|
UINT8 ext_out;
|
|
UINT8 lfoFreq;
|
|
UINT8 lfowave;
|
|
UINT8 pms, ams;
|
|
UINT8 detune;
|
|
UINT8 multiple;
|
|
UINT8 tl;
|
|
UINT8 keyscale;
|
|
UINT8 ar;
|
|
UINT8 decay1rate, decay2rate;
|
|
UINT8 decay1lvl;
|
|
UINT8 relrate;
|
|
UINT8 block;
|
|
UINT8 fns_hi;
|
|
UINT32 fns;
|
|
UINT8 feedback;
|
|
UINT8 waveform;
|
|
UINT8 accon;
|
|
UINT8 algorithm;
|
|
UINT8 ch0_level, ch1_level, ch2_level, ch3_level;
|
|
|
|
UINT32 startaddr;
|
|
UINT32 loopaddr;
|
|
UINT32 endaddr;
|
|
UINT8 altloop;
|
|
UINT8 fs;
|
|
UINT8 srcnote, srcb;
|
|
|
|
UINT32 step;
|
|
UINT64 stepptr;
|
|
|
|
UINT8 active;
|
|
UINT8 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
|
|
{
|
|
UINT8 sync, pfm;
|
|
UINT8 Muted;
|
|
} YMF271Group;
|
|
|
|
typedef struct
|
|
{
|
|
// lookup tables
|
|
INT16 *lut_waves[8];
|
|
double *lut_plfo[4][8];
|
|
int *lut_alfo[4];
|
|
double lut_ar[64];
|
|
double lut_dc[64];
|
|
double lut_lfo[256];
|
|
int lut_attenuation[16];
|
|
int lut_total_level[128];
|
|
int lut_env_volume[256];
|
|
|
|
YMF271Slot slots[48];
|
|
YMF271Group groups[12];
|
|
|
|
UINT8 regs_main[0x10];
|
|
|
|
UINT32 timerA, timerB;
|
|
UINT32 timerAVal, timerBVal;
|
|
UINT32 irqstate;
|
|
UINT8 status;
|
|
UINT8 enable;
|
|
|
|
UINT32 ext_address;
|
|
UINT8 ext_rw;
|
|
UINT8 ext_readlatch;
|
|
|
|
UINT8 *mem_base;
|
|
UINT32 mem_size;
|
|
UINT32 clock;
|
|
|
|
//emu_timer *timA, *timB;
|
|
//sound_stream * stream;
|
|
INT32 *mix_buffer;
|
|
//const device_config *device;
|
|
|
|
//devcb_resolved_read8 ext_mem_read;
|
|
//devcb_resolved_write8 ext_mem_write;
|
|
//void (*irq_callback)(const device_config *, int);
|
|
//void (*irq_callback)(int);
|
|
} YMF271Chip;
|
|
|
|
|
|
/*INLINE YMF271Chip *get_safe_token(const device_config *device)
|
|
{
|
|
assert(device != NULL);
|
|
assert(device->token != NULL);
|
|
assert(device->type == SOUND);
|
|
assert(sound_get_type(device) == SOUND_YMF271);
|
|
return (YMF271Chip *)device->token;
|
|
}*/
|
|
|
|
static UINT8 ymf271_read_memory(YMF271Chip *chip, UINT32 offset);
|
|
|
|
|
|
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 = (UINT32)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 = (UINT32)st;
|
|
}
|
|
}
|
|
|
|
INLINE bool check_envelope_end(YMF271Slot *slot)
|
|
{
|
|
if (slot->volume <= 0)
|
|
{
|
|
slot->active = 0;
|
|
slot->volume = 0;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
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 (!check_envelope_end(slot) && (slot->volume >> ENV_VOLUME_SHIFT) <= decay_level)
|
|
{
|
|
slot->env_state = ENV_DECAY2;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case ENV_DECAY2:
|
|
{
|
|
slot->volume -= slot->env_decay2_step;
|
|
check_envelope_end(slot);
|
|
break;
|
|
}
|
|
|
|
case ENV_RELEASE:
|
|
{
|
|
slot->volume -= slot->env_release_step;
|
|
check_envelope_end(slot);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
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)
|
|
{
|
|
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 void init_envelope(YMF271Chip *chip, YMF271Slot *slot)
|
|
{
|
|
int keycode, rate;
|
|
int decay_level = 255 - (slot->decay1lvl << 4);
|
|
|
|
if (slot->waveform != 7)
|
|
{
|
|
keycode = get_internal_keycode(slot->block, slot->fns);
|
|
}
|
|
else
|
|
{
|
|
keycode = get_external_keycode(slot->block, slot->fns & 0x7ff);
|
|
/* keycode = (keycode + slot->srcb * 4 + slot->srcnote) / 2; */ // not sure
|
|
}
|
|
|
|
// init attack state
|
|
rate = get_keyscaled_rate(slot->ar * 2, keycode, slot->keyscale);
|
|
slot->env_attack_step = (rate < 4) ? 0 : (int)(((double)(255-0) / chip->lut_ar[rate]) * 65536.0);
|
|
|
|
// init decay1 state
|
|
rate = get_keyscaled_rate(slot->decay1rate * 2, keycode, slot->keyscale);
|
|
slot->env_decay1_step = (rate < 4) ? 0 : (int)(((double)(255-decay_level) / chip->lut_dc[rate]) * 65536.0);
|
|
|
|
// init decay2 state
|
|
rate = get_keyscaled_rate(slot->decay2rate * 2, keycode, slot->keyscale);
|
|
slot->env_decay2_step = (rate < 4) ? 0 : (int)(((double)(255-0) / chip->lut_dc[rate]) * 65536.0);
|
|
|
|
// init release state
|
|
rate = get_keyscaled_rate(slot->relrate * 4, keycode, slot->keyscale);
|
|
slot->env_release_step = (rate < 4) ? 0 : (int)(((double)(255-0) / chip->lut_ar[rate]) * 65536.0);
|
|
|
|
slot->volume = (255-160) << ENV_VOLUME_SHIFT; // -60db
|
|
slot->env_state = ENV_ATTACK;
|
|
}
|
|
|
|
static void init_lfo(YMF271Chip *chip, YMF271Slot *slot)
|
|
{
|
|
slot->lfo_phase = 0;
|
|
slot->lfo_amplitude = 0;
|
|
slot->lfo_phasemod = 0;
|
|
|
|
slot->lfo_step = (int)((((double)LFO_LENGTH * chip->lut_lfo[slot->lfoFreq]) / 44100.0) * 256.0);
|
|
}
|
|
|
|
INLINE void update_lfo(YMF271Chip *chip, YMF271Slot *slot)
|
|
{
|
|
slot->lfo_phase += slot->lfo_step;
|
|
|
|
slot->lfo_amplitude = chip->lut_alfo[slot->lfowave][(slot->lfo_phase >> LFO_SHIFT) & (LFO_LENGTH-1)];
|
|
slot->lfo_phasemod = chip->lut_plfo[slot->lfowave][slot->pms][(slot->lfo_phase >> LFO_SHIFT) & (LFO_LENGTH-1)];
|
|
|
|
calculate_step(slot);
|
|
}
|
|
|
|
INLINE int calculate_slot_volume(YMF271Chip *chip, YMF271Slot *slot)
|
|
{
|
|
// Note: Actually everyone of these stores only INT32 (16.16 fixed point),
|
|
// but the calculations need INT64.
|
|
INT32 volume;
|
|
INT64 env_volume;
|
|
INT64 lfo_volume = 65536;
|
|
|
|
switch (slot->ams)
|
|
{
|
|
case 0: lfo_volume = 65536; break; // 0dB
|
|
case 1: lfo_volume = 65536 - ((slot->lfo_amplitude * 33124) >> 16); break; // 5.90625dB
|
|
case 2: lfo_volume = 65536 - ((slot->lfo_amplitude * 16742) >> 16); break; // 11.8125dB
|
|
case 3: lfo_volume = 65536 - ((slot->lfo_amplitude * 4277) >> 16); break; // 23.625dB
|
|
}
|
|
|
|
env_volume = (chip->lut_env_volume[255 - (slot->volume >> ENV_VOLUME_SHIFT)] * lfo_volume) >> 16;
|
|
|
|
volume = (env_volume * chip->lut_total_level[slot->tl]) >> 16;
|
|
|
|
return volume;
|
|
}
|
|
|
|
static void update_pcm(YMF271Chip *chip, int slotnum, INT32 *mixp, int length)
|
|
{
|
|
int i;
|
|
INT64 final_volume;
|
|
INT16 sample;
|
|
INT64 ch0_vol, ch1_vol; //, ch2_vol, ch3_vol;
|
|
|
|
YMF271Slot *slot = &chip->slots[slotnum];
|
|
|
|
if (!slot->active)
|
|
{
|
|
return;
|
|
}
|
|
|
|
#ifdef _DEBUG
|
|
if (slot->waveform != 7)
|
|
{
|
|
logerror("Waveform %d in update_pcm !!!\n", slot->waveform);
|
|
}
|
|
#endif
|
|
|
|
for (i = 0; i < length; i++)
|
|
{
|
|
// loop
|
|
if ((slot->stepptr>>16) > slot->endaddr)
|
|
{
|
|
slot->stepptr = slot->stepptr - ((UINT64)slot->endaddr<<16) + ((UINT64)slot->loopaddr<<16);
|
|
if ((slot->stepptr>>16) > slot->endaddr)
|
|
{
|
|
// overflow
|
|
slot->stepptr &= 0xffff;
|
|
slot->stepptr |= ((UINT64)slot->loopaddr<<16);
|
|
if ((slot->stepptr>>16) > slot->endaddr)
|
|
{
|
|
// still overflow? (triggers in rdft2, rarely)
|
|
slot->stepptr &= 0xffff;
|
|
slot->stepptr |= ((UINT64)slot->endaddr<<16);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (slot->bits == 8)
|
|
{
|
|
// 8bit
|
|
sample = ymf271_read_memory(chip, slot->startaddr + (slot->stepptr>>16))<<8;
|
|
}
|
|
else
|
|
{
|
|
// 12bit
|
|
if (slot->stepptr & 0x10000)
|
|
sample = ymf271_read_memory(chip, slot->startaddr + (slot->stepptr>>17)*3 + 2)<<8 | ((ymf271_read_memory(chip, slot->startaddr + (slot->stepptr>>17)*3 + 1) << 4) & 0xf0);
|
|
else
|
|
sample = ymf271_read_memory(chip, slot->startaddr + (slot->stepptr>>17)*3)<<8 | (ymf271_read_memory(chip, slot->startaddr + (slot->stepptr>>17)*3 + 1) & 0xf0);
|
|
}
|
|
|
|
update_envelope(slot);
|
|
update_lfo(chip, slot);
|
|
|
|
final_volume = calculate_slot_volume(chip, slot);
|
|
|
|
ch0_vol = (final_volume * chip->lut_attenuation[slot->ch0_level]) >> 16;
|
|
ch1_vol = (final_volume * chip->lut_attenuation[slot->ch1_level]) >> 16;
|
|
// ch2_vol = (final_volume * chip->lut_attenuation[slot->ch2_level]) >> 16;
|
|
// ch3_vol = (final_volume * chip->lut_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;
|
|
|
|
// go to next step
|
|
slot->stepptr += slot->step;
|
|
}
|
|
}
|
|
|
|
// calculates the output of one FM operator
|
|
static INT64 calculate_op(YMF271Chip *chip, int slotnum, INT64 inp)
|
|
{
|
|
YMF271Slot *slot = &chip->slots[slotnum];
|
|
INT64 env, slot_output, slot_input = 0;
|
|
|
|
update_envelope(slot);
|
|
update_lfo(chip, slot);
|
|
env = calculate_slot_volume(chip, slot);
|
|
|
|
if (inp == OP_INPUT_FEEDBACK)
|
|
{
|
|
// from own feedback
|
|
slot_input = (slot->feedback_modulation0 + slot->feedback_modulation1) / 2;
|
|
slot->feedback_modulation0 = slot->feedback_modulation1;
|
|
}
|
|
else if (inp != OP_INPUT_NONE)
|
|
{
|
|
// from previous slot output
|
|
slot_input = ((inp << (SIN_BITS-2)) * modulation_level[slot->feedback]);
|
|
}
|
|
|
|
slot_output = chip->lut_waves[slot->waveform][((slot->stepptr + slot_input) >> 16) & SIN_MASK];
|
|
slot_output = (slot_output * env) >> 16;
|
|
slot->stepptr += slot->step;
|
|
|
|
return slot_output;
|
|
}
|
|
|
|
static void set_feedback(YMF271Chip *chip, int slotnum, INT64 inp)
|
|
{
|
|
YMF271Slot *slot = &chip->slots[slotnum];
|
|
slot->feedback_modulation1 = (((inp << (SIN_BITS-2)) * feedback_level[slot->feedback]) / 16);
|
|
}
|
|
|
|
//static STREAM_UPDATE( ymf271_update )
|
|
void ymf271_update(void *param, stream_sample_t **outputs, int samples)
|
|
{
|
|
int i, j;
|
|
int op;
|
|
INT32 *mixp;
|
|
YMF271Chip *chip = (YMF271Chip *)param;
|
|
|
|
memset(chip->mix_buffer, 0, sizeof(chip->mix_buffer[0])*samples*2);
|
|
|
|
for (j = 0; j < 12; j++)
|
|
{
|
|
YMF271Group *slot_group = &chip->groups[j];
|
|
mixp = &chip->mix_buffer[0];
|
|
|
|
if (slot_group->Muted)
|
|
continue;
|
|
|
|
#ifdef _DEBUG
|
|
if (slot_group->pfm && slot_group->sync != 3)
|
|
{
|
|
logerror("ymf271 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);
|
|
}
|
|
#endif
|
|
|
|
switch (slot_group->sync)
|
|
{
|
|
// 4 operator FM
|
|
case 0:
|
|
{
|
|
int slot1 = j + (0*12);
|
|
int slot2 = j + (1*12);
|
|
int slot3 = j + (2*12);
|
|
int slot4 = j + (3*12);
|
|
//mixp = chip->mix_buffer;
|
|
|
|
if (chip->slots[slot1].active)
|
|
{
|
|
for (i = 0; i < samples; i++)
|
|
{
|
|
INT64 output1 = 0, output2 = 0, output3 = 0, output4 = 0;
|
|
INT64 phase_mod1 = 0, phase_mod2 = 0, phase_mod3 = 0;
|
|
switch (chip->slots[slot1].algorithm)
|
|
{
|
|
// <--------|
|
|
// +--[S1]--|--+--[S3]--+--[S2]--+--[S4]-->
|
|
case 0:
|
|
phase_mod1 = calculate_op(chip, slot1, OP_INPUT_FEEDBACK);
|
|
set_feedback(chip, slot1, phase_mod1);
|
|
phase_mod3 = calculate_op(chip, slot3, phase_mod1);
|
|
phase_mod2 = calculate_op(chip, slot2, phase_mod3);
|
|
output4 = calculate_op(chip, slot4, phase_mod2);
|
|
break;
|
|
|
|
// <-----------------|
|
|
// +--[S1]--+--[S3]--|--+--[S2]--+--[S4]-->
|
|
case 1:
|
|
phase_mod1 = calculate_op(chip, slot1, OP_INPUT_FEEDBACK);
|
|
phase_mod3 = calculate_op(chip, slot3, phase_mod1);
|
|
set_feedback(chip, slot1, phase_mod3);
|
|
phase_mod2 = calculate_op(chip, slot2, phase_mod3);
|
|
output4 = calculate_op(chip, slot4, phase_mod2);
|
|
break;
|
|
|
|
// <--------|
|
|
// +--[S1]--|
|
|
// |
|
|
// --[S3]--+--[S2]--+--[S4]-->
|
|
case 2:
|
|
phase_mod1 = calculate_op(chip, slot1, OP_INPUT_FEEDBACK);
|
|
set_feedback(chip, slot1, phase_mod1);
|
|
phase_mod3 = calculate_op(chip, slot3, OP_INPUT_NONE);
|
|
phase_mod2 = calculate_op(chip, slot2, (phase_mod1 + phase_mod3) / 1);
|
|
output4 = calculate_op(chip, slot4, phase_mod2);
|
|
break;
|
|
|
|
// <--------|
|
|
// +--[S1]--|
|
|
// |
|
|
// --[S3]--+--[S2]--+--[S4]-->
|
|
case 3:
|
|
phase_mod1 = calculate_op(chip, slot1, OP_INPUT_FEEDBACK);
|
|
set_feedback(chip, slot1, phase_mod1);
|
|
phase_mod3 = calculate_op(chip, slot3, OP_INPUT_NONE);
|
|
phase_mod2 = calculate_op(chip, slot2, phase_mod3);
|
|
output4 = calculate_op(chip, slot4, (phase_mod1 + phase_mod2) / 1);
|
|
break;
|
|
|
|
// --[S2]--|
|
|
// <--------| |
|
|
// +--[S1]--|--+--[S3]--+--[S4]-->
|
|
case 4:
|
|
phase_mod1 = calculate_op(chip, slot1, OP_INPUT_FEEDBACK);
|
|
set_feedback(chip, slot1, phase_mod1);
|
|
phase_mod3 = calculate_op(chip, slot3, phase_mod1);
|
|
phase_mod2 = calculate_op(chip, slot2, OP_INPUT_NONE);
|
|
output4 = calculate_op(chip, slot4, (phase_mod3 + phase_mod2) / 1);
|
|
break;
|
|
|
|
// --[S2]-----|
|
|
// <-----------------| |
|
|
// +--[S1]--+--[S3]--|--+--[S4]-->
|
|
case 5:
|
|
phase_mod1 = calculate_op(chip, slot1, OP_INPUT_FEEDBACK);
|
|
phase_mod3 = calculate_op(chip, slot3, phase_mod1);
|
|
set_feedback(chip, slot1, phase_mod3);
|
|
phase_mod2 = calculate_op(chip, slot2, OP_INPUT_NONE);
|
|
output4 = calculate_op(chip, slot4, (phase_mod3 + phase_mod2) / 1);
|
|
break;
|
|
|
|
// --[S2]-----+--[S4]--|
|
|
// |
|
|
// <--------| |
|
|
// +--[S1]--|--+--[S3]--+-->
|
|
case 6:
|
|
phase_mod1 = calculate_op(chip, slot1, OP_INPUT_FEEDBACK);
|
|
set_feedback(chip, slot1, phase_mod1);
|
|
output3 = calculate_op(chip, slot3, phase_mod1);
|
|
phase_mod2 = calculate_op(chip, slot2, OP_INPUT_NONE);
|
|
output4 = calculate_op(chip, slot4, phase_mod2);
|
|
break;
|
|
|
|
// --[S2]--+--[S4]-----|
|
|
// |
|
|
// <-----------------| |
|
|
// +--[S1]--+--[S3]--|--+-->
|
|
case 7:
|
|
phase_mod1 = calculate_op(chip, slot1, OP_INPUT_FEEDBACK);
|
|
phase_mod3 = calculate_op(chip, slot3, phase_mod1);
|
|
set_feedback(chip, slot1, phase_mod3);
|
|
output3 = phase_mod3;
|
|
phase_mod2 = calculate_op(chip, slot2, OP_INPUT_NONE);
|
|
output4 = calculate_op(chip, slot4, phase_mod2);
|
|
break;
|
|
|
|
// --[S3]--+--[S2]--+--[S4]--|
|
|
// |
|
|
// <--------| |
|
|
// +--[S1]--|-----------------+-->
|
|
case 8:
|
|
phase_mod1 = calculate_op(chip, slot1, OP_INPUT_FEEDBACK);
|
|
set_feedback(chip, slot1, phase_mod1);
|
|
output1 = phase_mod1;
|
|
phase_mod3 = calculate_op(chip, slot3, OP_INPUT_NONE);
|
|
phase_mod2 = calculate_op(chip, slot2, phase_mod3);
|
|
output4 = calculate_op(chip, slot4, phase_mod2);
|
|
break;
|
|
|
|
// <--------|
|
|
// +--[S1]--|
|
|
// |
|
|
// --[S3]--| |
|
|
// --[S2]--+--[S4]--+-->
|
|
case 9:
|
|
phase_mod1 = calculate_op(chip, slot1, OP_INPUT_FEEDBACK);
|
|
set_feedback(chip, slot1, phase_mod1);
|
|
output1 = phase_mod1;
|
|
phase_mod3 = calculate_op(chip, slot3, OP_INPUT_NONE);
|
|
phase_mod2 = calculate_op(chip, slot2, OP_INPUT_NONE);
|
|
output4 = calculate_op(chip, slot4, (phase_mod3 + phase_mod2) / 1);
|
|
break;
|
|
|
|
// --[S4]--|
|
|
// --[S2]--|
|
|
// <--------| |
|
|
// +--[S1]--|--+--[S3]--+-->
|
|
case 10:
|
|
phase_mod1 = calculate_op(chip, slot1, OP_INPUT_FEEDBACK);
|
|
set_feedback(chip, slot1, phase_mod1);
|
|
output3 = calculate_op(chip, slot3, phase_mod1);
|
|
output2 = calculate_op(chip, slot2, OP_INPUT_NONE);
|
|
output4 = calculate_op(chip, slot4, OP_INPUT_NONE);
|
|
break;
|
|
|
|
// --[S4]-----|
|
|
// --[S2]-----|
|
|
// <-----------------| |
|
|
// +--[S1]--+--[S3]--|--+-->
|
|
case 11:
|
|
phase_mod1 = calculate_op(chip, slot1, OP_INPUT_FEEDBACK);
|
|
phase_mod3 = calculate_op(chip, slot3, phase_mod1);
|
|
set_feedback(chip, slot1, phase_mod3);
|
|
output3 = phase_mod3;
|
|
output2 = calculate_op(chip, slot2, OP_INPUT_NONE);
|
|
output4 = calculate_op(chip, slot4, OP_INPUT_NONE);
|
|
break;
|
|
|
|
// |--+--[S4]--|
|
|
// <--------| |--+--[S3]--|
|
|
// +--[S1]--|--|--+--[S2]--+-->
|
|
case 12:
|
|
phase_mod1 = calculate_op(chip, slot1, OP_INPUT_FEEDBACK);
|
|
set_feedback(chip, slot1, phase_mod1);
|
|
output3 = calculate_op(chip, slot3, phase_mod1);
|
|
output2 = calculate_op(chip, slot2, phase_mod1);
|
|
output4 = calculate_op(chip, slot4, phase_mod1);
|
|
break;
|
|
|
|
// --[S3]--+--[S2]--|
|
|
// |
|
|
// --[S4]-----------|
|
|
// <--------| |
|
|
// +--[S1]--|--------+-->
|
|
case 13:
|
|
phase_mod1 = calculate_op(chip, slot1, OP_INPUT_FEEDBACK);
|
|
set_feedback(chip, slot1, phase_mod1);
|
|
output1 = phase_mod1;
|
|
phase_mod3 = calculate_op(chip, slot3, OP_INPUT_NONE);
|
|
output2 = calculate_op(chip, slot2, phase_mod3);
|
|
output4 = calculate_op(chip, slot4, OP_INPUT_NONE);
|
|
break;
|
|
|
|
// --[S2]-----+--[S4]--|
|
|
// |
|
|
// <--------| +--[S3]--|
|
|
// +--[S1]--|--|--------+-->
|
|
case 14:
|
|
phase_mod1 = calculate_op(chip, slot1, OP_INPUT_FEEDBACK);
|
|
set_feedback(chip, slot1, phase_mod1);
|
|
output1 = phase_mod1;
|
|
output3 = calculate_op(chip, slot3, phase_mod1);
|
|
phase_mod2 = calculate_op(chip, slot2, OP_INPUT_NONE);
|
|
output4 = calculate_op(chip, slot4, phase_mod2);
|
|
break;
|
|
|
|
// --[S4]-----|
|
|
// --[S2]-----|
|
|
// --[S3]-----|
|
|
// <--------| |
|
|
// +--[S1]--|--+-->
|
|
case 15:
|
|
phase_mod1 = calculate_op(chip, slot1, OP_INPUT_FEEDBACK);
|
|
set_feedback(chip, slot1, phase_mod1);
|
|
output1 = phase_mod1;
|
|
output3 = calculate_op(chip, slot3, OP_INPUT_NONE);
|
|
output2 = calculate_op(chip, slot2, OP_INPUT_NONE);
|
|
output4 = calculate_op(chip, slot4, OP_INPUT_NONE);
|
|
break;
|
|
}
|
|
|
|
*mixp++ += ((output1 * chip->lut_attenuation[chip->slots[slot1].ch0_level]) +
|
|
(output2 * chip->lut_attenuation[chip->slots[slot2].ch0_level]) +
|
|
(output3 * chip->lut_attenuation[chip->slots[slot3].ch0_level]) +
|
|
(output4 * chip->lut_attenuation[chip->slots[slot4].ch0_level])) >> 16;
|
|
*mixp++ += ((output1 * chip->lut_attenuation[chip->slots[slot1].ch1_level]) +
|
|
(output2 * chip->lut_attenuation[chip->slots[slot2].ch1_level]) +
|
|
(output3 * chip->lut_attenuation[chip->slots[slot3].ch1_level]) +
|
|
(output4 * chip->lut_attenuation[chip->slots[slot4].ch1_level])) >> 16;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
// 2x 2 operator FM
|
|
case 1:
|
|
{
|
|
for (op = 0; op < 2; op++)
|
|
{
|
|
int slot1 = j + ((op + 0) * 12);
|
|
int slot3 = j + ((op + 2) * 12);
|
|
|
|
mixp = chip->mix_buffer;
|
|
if (chip->slots[slot1].active)
|
|
{
|
|
for (i = 0; i < samples; i++)
|
|
{
|
|
INT64 output1 = 0, output3 = 0;
|
|
INT64 phase_mod1, phase_mod3 = 0;
|
|
switch (chip->slots[slot1].algorithm & 3)
|
|
{
|
|
// <--------|
|
|
// +--[S1]--|--+--[S3]-->
|
|
case 0:
|
|
phase_mod1 = calculate_op(chip, slot1, OP_INPUT_FEEDBACK);
|
|
set_feedback(chip, slot1, phase_mod1);
|
|
output3 = calculate_op(chip, slot3, phase_mod1);
|
|
break;
|
|
|
|
// <-----------------|
|
|
// +--[S1]--+--[S3]--|-->
|
|
case 1:
|
|
phase_mod1 = calculate_op(chip, slot1, OP_INPUT_FEEDBACK);
|
|
phase_mod3 = calculate_op(chip, slot3, phase_mod1);
|
|
set_feedback(chip, slot1, phase_mod3);
|
|
output3 = phase_mod3;
|
|
break;
|
|
|
|
// --[S3]-----|
|
|
// <--------| |
|
|
// +--[S1]--|--+-->
|
|
case 2:
|
|
phase_mod1 = calculate_op(chip, slot1, OP_INPUT_FEEDBACK);
|
|
set_feedback(chip, slot1, phase_mod1);
|
|
output1 = phase_mod1;
|
|
output3 = calculate_op(chip, slot3, OP_INPUT_NONE);
|
|
break;
|
|
//
|
|
// <--------| +--[S3]--|
|
|
// +--[S1]--|--|--------+-->
|
|
case 3:
|
|
phase_mod1 = calculate_op(chip, slot1, OP_INPUT_FEEDBACK);
|
|
set_feedback(chip, slot1, phase_mod1);
|
|
output1 = phase_mod1;
|
|
output3 = calculate_op(chip, slot3, phase_mod1);
|
|
break;
|
|
}
|
|
|
|
*mixp++ += ((output1 * chip->lut_attenuation[chip->slots[slot1].ch0_level]) +
|
|
(output3 * chip->lut_attenuation[chip->slots[slot3].ch0_level])) >> 16;
|
|
*mixp++ += ((output1 * chip->lut_attenuation[chip->slots[slot1].ch1_level]) +
|
|
(output3 * chip->lut_attenuation[chip->slots[slot3].ch1_level])) >> 16;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
// 3 operator FM + PCM
|
|
case 2:
|
|
{
|
|
int slot1 = j + (0*12);
|
|
int slot2 = j + (1*12);
|
|
int slot3 = j + (2*12);
|
|
//mixp = chip->mix_buffer;
|
|
|
|
if (chip->slots[slot1].active)
|
|
{
|
|
for (i = 0; i < samples; i++)
|
|
{
|
|
INT64 output1 = 0, output2 = 0, output3 = 0;
|
|
INT64 phase_mod1 = 0, phase_mod3 = 0;
|
|
switch (chip->slots[slot1].algorithm & 7)
|
|
{
|
|
// <--------|
|
|
// +--[S1]--|--+--[S3]--+--[S2]-->
|
|
case 0:
|
|
phase_mod1 = calculate_op(chip, slot1, OP_INPUT_FEEDBACK);
|
|
set_feedback(chip, slot1, phase_mod1);
|
|
phase_mod3 = calculate_op(chip, slot3, phase_mod1);
|
|
output2 = calculate_op(chip, slot2, phase_mod3);
|
|
break;
|
|
|
|
// <-----------------|
|
|
// +--[S1]--+--[S3]--|--+--[S2]-->
|
|
case 1:
|
|
phase_mod1 = calculate_op(chip, slot1, OP_INPUT_FEEDBACK);
|
|
phase_mod3 = calculate_op(chip, slot3, phase_mod1);
|
|
set_feedback(chip, slot1, phase_mod3);
|
|
output2 = calculate_op(chip, slot2, phase_mod3);
|
|
break;
|
|
|
|
// --[S3]-----|
|
|
// <--------| |
|
|
// +--[S1]--|--+--[S2]-->
|
|
case 2:
|
|
phase_mod1 = calculate_op(chip, slot1, OP_INPUT_FEEDBACK);
|
|
set_feedback(chip, slot1, phase_mod1);
|
|
phase_mod3 = calculate_op(chip, slot3, OP_INPUT_NONE);
|
|
output2 = calculate_op(chip, slot2, (phase_mod1 + phase_mod3) / 1);
|
|
break;
|
|
|
|
// --[S3]--+--[S2]--|
|
|
// <--------| |
|
|
// +--[S1]--|--------+-->
|
|
case 3:
|
|
phase_mod1 = calculate_op(chip, slot1, OP_INPUT_FEEDBACK);
|
|
set_feedback(chip, slot1, phase_mod1);
|
|
output1 = phase_mod1;
|
|
phase_mod3 = calculate_op(chip, slot3, OP_INPUT_NONE);
|
|
output2 = calculate_op(chip, slot2, phase_mod3);
|
|
break;
|
|
|
|
// --[S2]--|
|
|
// <--------| |
|
|
// +--[S1]--|--+--[S3]--+-->
|
|
case 4:
|
|
phase_mod1 = calculate_op(chip, slot1, OP_INPUT_FEEDBACK);
|
|
set_feedback(chip, slot1, phase_mod1);
|
|
output3 = calculate_op(chip, slot3, phase_mod1);
|
|
output2 = calculate_op(chip, slot2, OP_INPUT_NONE);
|
|
break;
|
|
|
|
// --[S2]--|
|
|
// <-----------------| |
|
|
// +--[S1]--+--[S3]--|--+-->
|
|
case 5:
|
|
phase_mod1 = calculate_op(chip, slot1, OP_INPUT_FEEDBACK);
|
|
phase_mod3 = calculate_op(chip, slot3, phase_mod1);
|
|
set_feedback(chip, slot1, phase_mod3);
|
|
output3 = phase_mod3;
|
|
output2 = calculate_op(chip, slot2, OP_INPUT_NONE);
|
|
break;
|
|
|
|
// --[S2]-----|
|
|
// --[S3]-----|
|
|
// <--------| |
|
|
// +--[S1]--|--+-->
|
|
case 6:
|
|
phase_mod1 = calculate_op(chip, slot1, OP_INPUT_FEEDBACK);
|
|
set_feedback(chip, slot1, phase_mod1);
|
|
output1 = phase_mod1;
|
|
output3 = calculate_op(chip, slot3, OP_INPUT_NONE);
|
|
output2 = calculate_op(chip, slot2, OP_INPUT_NONE);
|
|
break;
|
|
|
|
// --[S2]--|
|
|
// <--------| +--[S3]--|
|
|
// +--[S1]--|--|--------+-->
|
|
case 7:
|
|
phase_mod1 = calculate_op(chip, slot1, OP_INPUT_FEEDBACK);
|
|
set_feedback(chip, slot1, phase_mod1);
|
|
output1 = phase_mod1;
|
|
output3 = calculate_op(chip, slot3, phase_mod1);
|
|
output2 = calculate_op(chip, slot2, OP_INPUT_NONE);
|
|
break;
|
|
}
|
|
|
|
*mixp++ += ((output1 * chip->lut_attenuation[chip->slots[slot1].ch0_level]) +
|
|
(output2 * chip->lut_attenuation[chip->slots[slot2].ch0_level]) +
|
|
(output3 * chip->lut_attenuation[chip->slots[slot3].ch0_level])) >> 16;
|
|
*mixp++ += ((output1 * chip->lut_attenuation[chip->slots[slot1].ch1_level]) +
|
|
(output2 * chip->lut_attenuation[chip->slots[slot2].ch1_level]) +
|
|
(output3 * chip->lut_attenuation[chip->slots[slot3].ch1_level])) >> 16;
|
|
}
|
|
}
|
|
|
|
mixp = chip->mix_buffer;
|
|
update_pcm(chip, j + (3*12), mixp, samples);
|
|
break;
|
|
}
|
|
|
|
// PCM
|
|
case 3:
|
|
{
|
|
update_pcm(chip, j + (0*12), mixp, samples);
|
|
update_pcm(chip, j + (1*12), mixp, samples);
|
|
update_pcm(chip, j + (2*12), mixp, samples);
|
|
update_pcm(chip, j + (3*12), mixp, samples);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
mixp = chip->mix_buffer;
|
|
for (i = 0; i < samples; i++)
|
|
{
|
|
outputs[0][i] = (*mixp++)>>2;
|
|
outputs[1][i] = (*mixp++)>>2;
|
|
}
|
|
}
|
|
|
|
static void write_register(YMF271Chip *chip, int slotnum, int reg, UINT8 data)
|
|
{
|
|
YMF271Slot *slot = &chip->slots[slotnum];
|
|
|
|
switch (reg)
|
|
{
|
|
case 0x0:
|
|
slot->ext_en = (data & 0x80) ? 1 : 0;
|
|
slot->ext_out = (data>>3)&0xf;
|
|
|
|
if (data & 1)
|
|
{
|
|
// key on
|
|
slot->step = 0;
|
|
slot->stepptr = 0;
|
|
|
|
slot->active = 1;
|
|
|
|
calculate_step(slot);
|
|
init_envelope(chip, slot);
|
|
init_lfo(chip, slot);
|
|
slot->feedback_modulation0 = 0;
|
|
slot->feedback_modulation1 = 0;
|
|
}
|
|
else
|
|
{
|
|
if (slot->active)
|
|
{
|
|
slot->env_state = ENV_RELEASE;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 0x1:
|
|
slot->lfoFreq = data;
|
|
break;
|
|
|
|
case 0x2:
|
|
slot->lfowave = data & 3;
|
|
slot->pms = (data >> 3) & 0x7;
|
|
slot->ams = (data >> 6) & 0x3;
|
|
break;
|
|
|
|
case 0x3:
|
|
slot->multiple = data & 0xf;
|
|
slot->detune = (data >> 4) & 0x7;
|
|
break;
|
|
|
|
case 0x4:
|
|
slot->tl = data & 0x7f;
|
|
break;
|
|
|
|
case 0x5:
|
|
slot->ar = data & 0x1f;
|
|
slot->keyscale = (data >> 5) & 0x7;
|
|
break;
|
|
|
|
case 0x6:
|
|
slot->decay1rate = data & 0x1f;
|
|
break;
|
|
|
|
case 0x7:
|
|
slot->decay2rate = data & 0x1f;
|
|
break;
|
|
|
|
case 0x8:
|
|
slot->relrate = data & 0xf;
|
|
slot->decay1lvl = (data >> 4) & 0xf;
|
|
break;
|
|
|
|
case 0x9:
|
|
// write frequency and block here
|
|
slot->fns = (slot->fns_hi << 8 & 0x0f00) | data;
|
|
slot->block = slot->fns_hi >> 4 & 0xf;
|
|
break;
|
|
|
|
case 0xa:
|
|
slot->fns_hi = data;
|
|
break;
|
|
|
|
case 0xb:
|
|
slot->waveform = data & 0x7;
|
|
slot->feedback = (data >> 4) & 0x7;
|
|
slot->accon = (data & 0x80) ? 1 : 0;
|
|
break;
|
|
|
|
case 0xc:
|
|
slot->algorithm = data & 0xf;
|
|
break;
|
|
|
|
case 0xd:
|
|
slot->ch0_level = data >> 4;
|
|
slot->ch1_level = data & 0xf;
|
|
break;
|
|
|
|
case 0xe:
|
|
slot->ch2_level = data >> 4;
|
|
slot->ch3_level = data & 0xf;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void ymf271_write_fm(YMF271Chip *chip, int bank, UINT8 address, UINT8 data)
|
|
{
|
|
int groupnum = fm_tab[address & 0xf];
|
|
int reg = (address >> 4) & 0xf;
|
|
int sync_reg;
|
|
int sync_mode;
|
|
|
|
if (groupnum == -1)
|
|
{
|
|
logerror("ymf271_write_fm invalid group %02X %02X\n", address, data);
|
|
return;
|
|
}
|
|
|
|
// 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[groupnum].sync)
|
|
{
|
|
// 4 slot mode
|
|
case 0:
|
|
if (bank == 0)
|
|
sync_mode = 1;
|
|
break;
|
|
|
|
// 2x 2 slot mode
|
|
case 1:
|
|
if (bank == 0 || bank == 1)
|
|
sync_mode = 1;
|
|
break;
|
|
|
|
// 3 slot + 1 slot mode
|
|
case 2:
|
|
if (bank == 0)
|
|
sync_mode = 1;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
// key-on slot & synced register
|
|
if (sync_mode && sync_reg)
|
|
{
|
|
switch (chip->groups[groupnum].sync)
|
|
{
|
|
// 4 slot mode
|
|
case 0:
|
|
write_register(chip, (12 * 0) + groupnum, reg, data);
|
|
write_register(chip, (12 * 1) + groupnum, reg, data);
|
|
write_register(chip, (12 * 2) + groupnum, reg, data);
|
|
write_register(chip, (12 * 3) + groupnum, reg, data);
|
|
break;
|
|
|
|
// 2x 2 slot mode
|
|
case 1:
|
|
if (bank == 0)
|
|
{
|
|
// Slot 1 - Slot 3
|
|
write_register(chip, (12 * 0) + groupnum, reg, data);
|
|
write_register(chip, (12 * 2) + groupnum, reg, data);
|
|
}
|
|
else
|
|
{
|
|
// Slot 2 - Slot 4
|
|
write_register(chip, (12 * 1) + groupnum, reg, data);
|
|
write_register(chip, (12 * 3) + groupnum, reg, data);
|
|
}
|
|
break;
|
|
|
|
// 3 slot + 1 slot mode (1 slot is handled normally)
|
|
case 2:
|
|
write_register(chip, (12 * 0) + groupnum, reg, data);
|
|
write_register(chip, (12 * 1) + groupnum, reg, data);
|
|
write_register(chip, (12 * 2) + groupnum, reg, data);
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// write register normally
|
|
write_register(chip, (12 * bank) + groupnum, reg, data);
|
|
}
|
|
}
|
|
|
|
static void ymf271_write_pcm(YMF271Chip *chip, UINT8 address, UINT8 data)
|
|
{
|
|
int slotnum = pcm_tab[address & 0xf];
|
|
YMF271Slot *slot;
|
|
if (slotnum == -1)
|
|
{
|
|
logerror("ymf271_write_pcm invalid slot %02X %02X\n", address, data);
|
|
return;
|
|
}
|
|
slot = &chip->slots[slotnum];
|
|
|
|
switch ((address >> 4) & 0xf)
|
|
{
|
|
case 0x0:
|
|
slot->startaddr &= ~0xff;
|
|
slot->startaddr |= data;
|
|
break;
|
|
|
|
case 0x1:
|
|
slot->startaddr &= ~0xff00;
|
|
slot->startaddr |= data<<8;
|
|
break;
|
|
|
|
case 0x2:
|
|
slot->startaddr &= ~0xff0000;
|
|
slot->startaddr |= (data & 0x7f)<<16;
|
|
slot->altloop = (data & 0x80) ? 1 : 0;
|
|
//if (slot->altloop)
|
|
// popmessage("ymf271 A/L, contact MAMEdev");
|
|
break;
|
|
|
|
case 0x3:
|
|
slot->endaddr &= ~0xff;
|
|
slot->endaddr |= data;
|
|
break;
|
|
|
|
case 0x4:
|
|
slot->endaddr &= ~0xff00;
|
|
slot->endaddr |= data<<8;
|
|
break;
|
|
|
|
case 0x5:
|
|
slot->endaddr &= ~0xff0000;
|
|
slot->endaddr |= (data & 0x7f)<<16;
|
|
break;
|
|
|
|
case 0x6:
|
|
slot->loopaddr &= ~0xff;
|
|
slot->loopaddr |= data;
|
|
break;
|
|
|
|
case 0x7:
|
|
slot->loopaddr &= ~0xff00;
|
|
slot->loopaddr |= data<<8;
|
|
break;
|
|
|
|
case 0x8:
|
|
slot->loopaddr &= ~0xff0000;
|
|
slot->loopaddr |= (data & 0x7f)<<16;
|
|
break;
|
|
|
|
case 0x9:
|
|
slot->fs = data & 0x3;
|
|
slot->bits = (data & 0x4) ? 12 : 8;
|
|
slot->srcnote = (data >> 3) & 0x3;
|
|
slot->srcb = (data >> 5) & 0x7;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*static TIMER_CALLBACK( ymf271_timer_a_tick )
|
|
{
|
|
YMF271Chip *chip = (YMF271Chip *)ptr;
|
|
|
|
chip->status |= 1;
|
|
|
|
if (chip->enable & 4)
|
|
{
|
|
chip->irqstate |= 1;
|
|
if (chip->irq_callback) chip->irq_callback(chip->device, 1);
|
|
}
|
|
}
|
|
|
|
static TIMER_CALLBACK( ymf271_timer_b_tick )
|
|
{
|
|
YMF271Chip *chip = (YMF271Chip *)ptr;
|
|
|
|
chip->status |= 2;
|
|
|
|
if (chip->enable & 8)
|
|
{
|
|
chip->irqstate |= 2;
|
|
if (chip->irq_callback) chip->irq_callback(chip->device, 1);
|
|
}
|
|
}*/
|
|
|
|
static UINT8 ymf271_read_memory(YMF271Chip *chip, UINT32 offset)
|
|
{
|
|
/*if (m_ext_read_handler.isnull())
|
|
{
|
|
if (offset < chip->mem_size)
|
|
return chip->mem_base[offset];
|
|
|
|
// 8MB chip limit (shouldn't happen)
|
|
else if (offset > 0x7fffff)
|
|
return chip->mem_base[offset & 0x7fffff];
|
|
|
|
else
|
|
return 0;
|
|
}
|
|
else
|
|
return m_ext_read_handler(offset);*/
|
|
|
|
offset &= 0x7FFFFF;
|
|
if (offset < chip->mem_size)
|
|
return chip->mem_base[offset];
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
static void ymf271_write_timer(YMF271Chip *chip, UINT8 address, UINT8 data)
|
|
{
|
|
if ((address & 0xf0) == 0)
|
|
{
|
|
int groupnum = fm_tab[address & 0xf];
|
|
YMF271Group *group;
|
|
if (groupnum == -1)
|
|
{
|
|
logerror("ymf271_write_timer invalid group %02X %02X\n", address, data);
|
|
return;
|
|
}
|
|
group = &chip->groups[groupnum];
|
|
|
|
group->sync = data & 0x3;
|
|
group->pfm = data >> 7;
|
|
}
|
|
else
|
|
{
|
|
switch (address)
|
|
{
|
|
case 0x10:
|
|
chip->timerA = data;
|
|
break;
|
|
|
|
case 0x11:
|
|
// According to Yamaha's documentation, this sets timer A upper 2 bits
|
|
// (it says timer A is 10 bits). But, PCB audio recordings proves
|
|
// otherwise: it doesn't affect timer A frequency. (see ms32.c tetrisp)
|
|
// Does this register have another function regarding timer A/B?
|
|
break;
|
|
|
|
case 0x12:
|
|
chip->timerB = data;
|
|
break;
|
|
|
|
case 0x13:
|
|
// timer A load
|
|
if (~chip->enable & data & 1)
|
|
{
|
|
//attotime period = attotime::from_hz(chip->clock) * (384 * 4 * (256 - chip->timerA));
|
|
//chip->timA->adjust((data & 1) ? period : attotime::never, 0);
|
|
}
|
|
|
|
// timer B load
|
|
if (~chip->enable & data & 2)
|
|
{
|
|
//attotime period = attotime::from_hz(chip->clock) * (384 * 16 * (256 - chip->timerB));
|
|
//chip->timB->adjust((data & 2) ? period : attotime::never, 0);
|
|
}
|
|
|
|
// timer A reset
|
|
if (data & 0x10)
|
|
{
|
|
chip->irqstate &= ~1;
|
|
chip->status &= ~1;
|
|
|
|
//if (!chip->irq_handler.isnull() && ~chip->irqstate & 2)
|
|
// chip->irq_handler(0);
|
|
}
|
|
|
|
// timer B reset
|
|
if (data & 0x20)
|
|
{
|
|
chip->irqstate &= ~2;
|
|
chip->status &= ~2;
|
|
|
|
//if (!chip->irq_handler.isnull() && ~chip->irqstate & 1)
|
|
// chip->irq_handler(0);
|
|
}
|
|
|
|
chip->enable = data;
|
|
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_rw = (data & 0x80) ? 1 : 0;
|
|
break;
|
|
case 0x17:
|
|
chip->ext_address = (chip->ext_address + 1) & 0x7fffff;
|
|
//if (!chip->ext_rw && !chip->ext_write_handler.isnull())
|
|
// chip->ext_write_handler(chip->ext_address, data);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//WRITE8_DEVICE_HANDLER( ymf271_w )
|
|
void ymf271_w(void *_info, offs_t offset, UINT8 data)
|
|
{
|
|
//YMF271Chip *chip = get_safe_token(device);
|
|
YMF271Chip *chip = (YMF271Chip *)_info;
|
|
|
|
chip->regs_main[offset & 0xf] = data;
|
|
|
|
switch (offset & 0xf)
|
|
{
|
|
case 0x0:
|
|
case 0x2:
|
|
case 0x4:
|
|
case 0x6:
|
|
case 0x8:
|
|
case 0xc:
|
|
// address regs
|
|
break;
|
|
|
|
case 0x1:
|
|
ymf271_write_fm(chip, 0, chip->regs_main[0x0], data);
|
|
break;
|
|
|
|
case 0x3:
|
|
ymf271_write_fm(chip, 1, chip->regs_main[0x2], data);
|
|
break;
|
|
|
|
case 0x5:
|
|
ymf271_write_fm(chip, 2, chip->regs_main[0x4], data);
|
|
break;
|
|
|
|
case 0x7:
|
|
ymf271_write_fm(chip, 3, chip->regs_main[0x6], data);
|
|
break;
|
|
|
|
case 0x9:
|
|
ymf271_write_pcm(chip, chip->regs_main[0x8], data);
|
|
break;
|
|
|
|
case 0xd:
|
|
ymf271_write_timer(chip, chip->regs_main[0xc], data);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
//READ8_DEVICE_HANDLER( ymf271_r )
|
|
UINT8 ymf271_r(void *_info, offs_t offset)
|
|
{
|
|
//YMF271Chip *chip = get_safe_token(device);
|
|
YMF271Chip *chip = (YMF271Chip *)_info;
|
|
|
|
switch (offset & 0xf)
|
|
{
|
|
case 0x0:
|
|
return chip->status;
|
|
|
|
case 0x1:
|
|
// statusreg 2
|
|
return 0;
|
|
|
|
case 0x2:
|
|
{
|
|
UINT8 ret;
|
|
if (!chip->ext_rw)
|
|
return 0xff;
|
|
|
|
ret = chip->ext_readlatch;
|
|
chip->ext_address = (chip->ext_address + 1) & 0x7fffff;
|
|
chip->ext_readlatch = ymf271_read_memory(chip, chip->ext_address);
|
|
return ret;
|
|
}
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return 0xff;
|
|
}
|
|
|
|
static void init_tables(YMF271Chip *chip)
|
|
{
|
|
int i,j;
|
|
double clock_correction;
|
|
|
|
for (i = 0; i < 8; i++)
|
|
chip->lut_waves[i] = (INT16*)malloc(sizeof(INT16) * SIN_LEN);
|
|
|
|
for (i = 0; i < 4*8; i++)
|
|
chip->lut_plfo[i>>3][i&7] = (double*)malloc(sizeof(double) * LFO_LENGTH);
|
|
|
|
for (i = 0; i < 4; i++)
|
|
chip->lut_alfo[i] = (int*)malloc(sizeof(int) * LFO_LENGTH);
|
|
|
|
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)
|
|
chip->lut_waves[0][i] = (INT16)(m * MAXOUT);
|
|
|
|
// Waveform 1: sin?(wt) (0 <= wt <= PI) -sin?(wt) (PI <= wt <= 2PI)
|
|
chip->lut_waves[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)
|
|
chip->lut_waves[2][i] = (i < (SIN_LEN/2)) ? (INT16)(m * MAXOUT) : (INT16)(-m * MAXOUT);
|
|
|
|
// Waveform 3: sin(wt) (0 <= wt <= PI) 0
|
|
chip->lut_waves[3][i] = (i < (SIN_LEN/2)) ? (INT16)(m * MAXOUT) : 0;
|
|
|
|
// Waveform 4: sin(2wt) (0 <= wt <= PI) 0
|
|
chip->lut_waves[4][i] = (i < (SIN_LEN/2)) ? (INT16)(m2 * MAXOUT) : 0;
|
|
|
|
// Waveform 5: |sin(2wt)| (0 <= wt <= PI) 0
|
|
chip->lut_waves[5][i] = (i < (SIN_LEN/2)) ? (INT16)(fabs(m2) * MAXOUT) : 0;
|
|
|
|
// Waveform 6: 1 (0 <= wt <= 2PI)
|
|
chip->lut_waves[6][i] = (INT16)(1 * MAXOUT);
|
|
|
|
chip->lut_waves[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;
|
|
default: plfo[3] = 0; /*assert(0);*/ break;
|
|
}
|
|
|
|
for (j = 0; j < 4; j++)
|
|
{
|
|
chip->lut_plfo[j][0][i] = pow(2.0, 0.0);
|
|
chip->lut_plfo[j][1][i] = pow(2.0, (3.378 * plfo[j]) / 1200.0);
|
|
chip->lut_plfo[j][2][i] = pow(2.0, (5.0646 * plfo[j]) / 1200.0);
|
|
chip->lut_plfo[j][3][i] = pow(2.0, (6.7495 * plfo[j]) / 1200.0);
|
|
chip->lut_plfo[j][4][i] = pow(2.0, (10.1143 * plfo[j]) / 1200.0);
|
|
chip->lut_plfo[j][5][i] = pow(2.0, (20.1699 * plfo[j]) / 1200.0);
|
|
chip->lut_plfo[j][6][i] = pow(2.0, (40.1076 * plfo[j]) / 1200.0);
|
|
chip->lut_plfo[j][7][i] = pow(2.0, (79.307 * plfo[j]) / 1200.0);
|
|
}
|
|
|
|
// LFO amplitude modulation
|
|
chip->lut_alfo[0][i] = 0;
|
|
|
|
chip->lut_alfo[1][i] = ALFO_MAX - ((i * ALFO_MAX) / LFO_LENGTH);
|
|
|
|
chip->lut_alfo[2][i] = (i < (LFO_LENGTH/2)) ? ALFO_MAX : ALFO_MIN;
|
|
|
|
tri_wave = ((i % (LFO_LENGTH/2)) * ALFO_MAX) / (LFO_LENGTH/2);
|
|
chip->lut_alfo[3][i] = (i < (LFO_LENGTH/2)) ? ALFO_MAX-tri_wave : tri_wave;
|
|
}
|
|
|
|
for (i = 0; i < 256; i++)
|
|
{
|
|
chip->lut_env_volume[i] = (int)(65536.0 / pow(10.0, ((double)i / (256.0 / 96.0)) / 20.0));
|
|
}
|
|
|
|
for (i = 0; i < 16; i++)
|
|
{
|
|
chip->lut_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;
|
|
chip->lut_total_level[i] = (int)(65536.0 / pow(10.0, db / 20.0));
|
|
}
|
|
|
|
// timing may use a non-standard XTAL
|
|
clock_correction = (double)(STD_CLOCK) / (double)(chip->clock);
|
|
for (i = 0; i < 256; i++)
|
|
{
|
|
chip->lut_lfo[i] = LFO_frequency_table[i] * clock_correction;
|
|
}
|
|
|
|
for (i = 0; i < 64; i++)
|
|
{
|
|
// attack/release rate in number of samples
|
|
chip->lut_ar[i] = (ARTime[i] * clock_correction * 44100.0) / 1000.0;
|
|
}
|
|
for (i = 0; i < 64; i++)
|
|
{
|
|
// decay rate in number of samples
|
|
chip->lut_dc[i] = (DCTime[i] * clock_correction * 44100.0) / 1000.0;
|
|
}
|
|
}
|
|
|
|
/*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].ext_out);
|
|
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 DEVICE_START( ymf271 )
|
|
int device_start_ymf271(void **_info, int clock)
|
|
{
|
|
//static const ymf271_interface defintrf = { DEVCB_NULL };
|
|
//const ymf271_interface *intf;
|
|
int i;
|
|
//YMF271Chip *chip = get_safe_token(device);
|
|
YMF271Chip *chip;
|
|
|
|
chip = (YMF271Chip *) calloc(1, sizeof(YMF271Chip));
|
|
*_info = (void *) chip;
|
|
|
|
//chip->device = device;
|
|
chip->clock = clock;
|
|
|
|
//intf = (device->static_config != NULL) ? (const ymf271_interface *)device->static_config : &defintrf;
|
|
|
|
chip->mem_size = 0x00;
|
|
chip->mem_base = NULL;
|
|
|
|
init_tables(chip);
|
|
//init_state(chip);
|
|
//chip->stream = stream_create(device, 0, 2, device->clock/384, chip, ymf271_update);
|
|
|
|
//chip->mix_buffer = auto_alloc_array(machine, INT32, 44100*2);
|
|
chip->mix_buffer = (INT32*)malloc(44100*2 * sizeof(INT32));
|
|
|
|
for (i = 0; i < 12; i ++)
|
|
chip->groups[i].Muted = 0x00;
|
|
|
|
return clock/384;
|
|
}
|
|
|
|
//static DEVICE_STOP( ymf271 )
|
|
void device_stop_ymf271(void *_info)
|
|
{
|
|
int i;
|
|
YMF271Chip *chip = (YMF271Chip *)_info;
|
|
|
|
free(chip->mem_base); chip->mem_base = NULL;
|
|
|
|
for (i=0; i < 8; i++)
|
|
{
|
|
free(chip->lut_waves[i]);
|
|
chip->lut_waves[i] = NULL;
|
|
}
|
|
for (i = 0; i < 4*8; i++)
|
|
{
|
|
free(chip->lut_plfo[i>>3][i&7]);
|
|
chip->lut_plfo[i>>3][i&7] = NULL;
|
|
}
|
|
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
free(chip->lut_alfo[i]);
|
|
chip->lut_alfo[i] = NULL;
|
|
}
|
|
|
|
free(chip->mix_buffer);
|
|
chip->mix_buffer = NULL;
|
|
|
|
free(chip);
|
|
|
|
return;
|
|
}
|
|
|
|
//static DEVICE_RESET( ymf271 )
|
|
void device_reset_ymf271(void *_info)
|
|
{
|
|
int i;
|
|
//YMF271Chip *chip = get_safe_token(device);
|
|
YMF271Chip *chip = (YMF271Chip *)_info;
|
|
|
|
for (i = 0; i < 48; i++)
|
|
{
|
|
chip->slots[i].active = 0;
|
|
chip->slots[i].volume = 0;
|
|
}
|
|
|
|
// reset timers and IRQ
|
|
//chip->timA->reset();
|
|
//chip->timB->reset();
|
|
|
|
chip->irqstate = 0;
|
|
chip->status = 0;
|
|
chip->enable = 0;
|
|
|
|
//if (!chip->irq_handler.isnull())
|
|
// chip->irq_handler(0);
|
|
}
|
|
|
|
void ymf271_write_rom(void *_info, offs_t ROMSize, offs_t DataStart, offs_t DataLength,
|
|
const UINT8* ROMData)
|
|
{
|
|
YMF271Chip *chip = (YMF271Chip *)_info;
|
|
|
|
if (chip->mem_size != ROMSize)
|
|
{
|
|
chip->mem_base = (UINT8*)realloc(chip->mem_base, ROMSize);
|
|
chip->mem_size = ROMSize;
|
|
memset(chip->mem_base, 0xFF, ROMSize);
|
|
}
|
|
if (DataStart > ROMSize)
|
|
return;
|
|
if (DataStart + DataLength > ROMSize)
|
|
DataLength = ROMSize - DataStart;
|
|
|
|
memcpy(chip->mem_base + DataStart, ROMData, DataLength);
|
|
|
|
return;
|
|
}
|
|
|
|
void ymf271_set_mute_mask(void *_info, UINT32 MuteMask)
|
|
{
|
|
YMF271Chip *chip = (YMF271Chip *)_info;
|
|
UINT8 CurChn;
|
|
|
|
for (CurChn = 0; CurChn < 12; CurChn ++)
|
|
chip->groups[CurChn].Muted = (MuteMask >> CurChn) & 0x01;
|
|
|
|
return;
|
|
}
|
|
|
|
/**************************************************************************
|
|
* Generic get_info
|
|
**************************************************************************/
|
|
|
|
/*DEVICE_GET_INFO( ymf271 )
|
|
{
|
|
switch (state)
|
|
{
|
|
// --- the following bits of info are returned as 64-bit signed integers ---
|
|
case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(YMF271Chip); break;
|
|
|
|
// --- the following bits of info are returned as pointers to data or functions
|
|
case DEVINFO_FCT_START: info->start = DEVICE_START_NAME( ymf271 ); break;
|
|
case DEVINFO_FCT_STOP: // Nothing break;
|
|
case DEVINFO_FCT_RESET: info->reset = DEVICE_RESET_NAME( ymf271 ); break;
|
|
|
|
// --- the following bits of info are returned as NULL-terminated strings ---
|
|
case DEVINFO_STR_NAME: strcpy(info->s, "YMF271"); break;
|
|
case DEVINFO_STR_FAMILY: strcpy(info->s, "Yamaha FM"); break;
|
|
case DEVINFO_STR_VERSION: strcpy(info->s, "1.0"); break;
|
|
case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break;
|
|
case DEVINFO_STR_CREDITS: strcpy(info->s, "Copyright Nicola Salmoria and the MAME Team"); break;
|
|
}
|
|
}*/
|