WIP sn76477 soundcore, hook it up to speak & rescue/stratovox

This commit is contained in:
dinkc64 2016-05-02 01:05:54 +00:00
parent 3c9056e4e1
commit ef27581980
4 changed files with 1108 additions and 3 deletions

View File

@ -93,7 +93,7 @@ depobj := $(drvobj) \
ay8910.o burn_y8950.o burn_ym2151.o burn_ym2203.o burn_ym2413.o burn_ym2608.o burn_ym2610.o burn_ym2612.o \
burn_ym3526.o burn_ym3812.o burn_ymf278b.o c6280.o dac.o es5506.o es8712.o flt_rc.o fm.o fmopl.o gaelco.o ics2115.o iremga20.o \
k005289.o k007232.o k051649.o k053260.o k054539.o msm5205.o msm5232.o msm6295.o namco_snd.o nes_apu.o tms36xx.o phoenixsound.o pleiadssound.o pokey.o rf5c68.o saa1099.o \
samples.o segapcm.o sn76496.o upd7759.o vlm5030.o x1010.o ym2151.o ym2413.o ymdeltat.o ymf278b.o ymz280b.o \
samples.o segapcm.o sn76477.o sn76496.o upd7759.o vlm5030.o x1010.o ym2151.o ym2413.o ymdeltat.o ymf278b.o ymz280b.o \
\
arm7_intf.o arm_intf.o h6280_intf.o hd6309_intf.o konami_intf.o m6502_intf.o m6800_intf.o m6805_intf.o m6809_intf.o \
m68000_intf.o nec_intf.o pic16c5x_intf.o s2650_intf.o tlcs90_intf.o z80_intf.o \

View File

@ -8,6 +8,7 @@
extern "C" {
#include "ay8910.h"
}
#include "sn76477.h"
//------------------------------------------------------------------------------------------------
@ -405,9 +406,23 @@ static INT32 DrvDoReset()
return 0;
}
void stratvox_sn76477_write(UINT32, UINT32)
void stratvox_sn76477_write(UINT32, UINT32 data)
{
SN76477_enable_w(0, (data >> 0) & 1);
SN76477_vco_w(0, (data >> 1) & 1);
SN76477_envelope_1_w(0, (data >> 2) & 1);
SN76477_envelope_2_w(0, (data >> 3) & 1);
SN76477_mixer_a_w(0, (data >> 4) & 1);
SN76477_mixer_b_w(0, (data >> 5) & 1);
SN76477_mixer_c_w(0, (data >> 6) & 1);
#if 0
SN76477_mixer_w(0,(data >> 4) & 7);
SN76477_envelope_w(0,(data >> 2) & 3);
SN76477_vco_w(0,(data >> 1) & 1);
SN76477_enable_w(0,data & 1);
#endif
}
static INT32 DrvSyncDAC()
@ -460,6 +475,28 @@ static INT32 DrvInit()
pAY8910Buffer[1] = pFMBuffer + nBurnSoundLen * 1;
pAY8910Buffer[2] = pFMBuffer + nBurnSoundLen * 2;
SN76477_init(0);
SN76477_set_noise_res(0, RES_K(47));
SN76477_set_filter_res(0, RES_K(150));
SN76477_set_filter_cap(0, CAP_U(0.001));
SN76477_set_decay_res(0, RES_M(3.3));
SN76477_set_attack_decay_cap(0, CAP_U(1.0));
SN76477_set_attack_res(0, RES_K(4.7));
SN76477_set_amplitude_res(0, RES_K(200));
SN76477_set_feedback_res(0, RES_K(55));
SN76477_set_oneshot_res(0, RES_K(4.7));
SN76477_set_oneshot_cap(0, CAP_U(2.2));
SN76477_set_pitch_voltage(0, 5.0);
SN76477_set_slf_res(0, RES_K(75));
SN76477_set_slf_cap(0, CAP_U(1.0));
SN76477_set_vco_res(0, RES_K(100));
SN76477_set_vco_cap(0, CAP_U(0.022));
SN76477_set_vco_voltage(0, 5.0*2/(2+10));
SN76477_mixer_w(0, 0);
SN76477_envelope_w(0, 0);
SN76477_set_mastervol(0, 1.00);
AY8910Init(0, 1250000, nBurnSoundRate, NULL, NULL, &stratvox_sn76477_write, NULL);
AY8910SetAllRoutes(0, 0.50, BURN_SND_ROUTE_BOTH);
@ -477,6 +514,7 @@ static INT32 DrvExit()
DACExit();
ZetExit();
AY8910Exit(0);
SN76477_exit(0);
BurnFree (Mem);
BurnFree (pFMBuffer);
@ -621,7 +659,7 @@ static INT32 DrvFrame()
INT32 nSegmentLength = nBurnSoundLen / nInterleave;
INT16* pSoundBuf = pBurnSoundOut + (nSoundBufferPos << 1);
AY8910Render(&pAY8910Buffer[0], pSoundBuf, nSegmentLength, 0);
SN76477_sound_update(0, pSoundBuf, nSegmentLength);
nSoundBufferPos += nSegmentLength;
}
}
@ -632,6 +670,7 @@ static INT32 DrvFrame()
INT16* pSoundBuf = pBurnSoundOut + (nSoundBufferPos << 1);
if (nSegmentLength) {
AY8910Render(&pAY8910Buffer[0], pSoundBuf, nSegmentLength, 0);
SN76477_sound_update(0, pSoundBuf, nSegmentLength);
}
DACUpdate(pBurnSoundOut, nBurnSoundLen);

984
src/burn/snd/sn76477.cpp Normal file
View File

@ -0,0 +1,984 @@
/*****************************************************************************
SN76477 pins and assigned interface variables/functions
SN76477_envelope_w()
/ \
[ 1] ENV SEL 1 ENV SEL 2 [28]
[ 2] GND MIXER C [27] \
SN76477_noise_clock_w [ 3] NOISE EXT OSC MIXER A [26] > SN76477_mixer_w()
noise_res [ 4] RES NOISE OSC MIXER B [25] /
filter_res [ 5] NOISE FILTER RES O/S RES [24] oneshot_res
filter_cap [ 6] NOISE FILTER CAP O/S CAP [23] oneshot_cap
decay_res [ 7] DECAY RES VCO SEL [22] SN76477_vco_w()
attack_decay_cap [ 8] A/D CAP SLF CAP [21] slf_cap
SN76477_enable_w() [ 9] ENABLE SLF RES [20] slf_res
attack_res [10] ATTACK RES PITCH [19] pitch_voltage
amplitude_res [11] AMP VCO RES [18] vco_res
feedback_res [12] FEEDBACK VCO CAP [17] vco_cap
[13] OUTPUT VCO EXT CONT [16] vco_voltage
[14] Vcc +5V REG OUT [15]
All resistor values in Ohms.
All capacitor values in Farads.
Use RES_K, RES_M and CAP_U, CAP_N, CAP_P macros to convert
magnitudes, eg. 220k = RES_K(220), 47nF = CAP_N(47)
*****************************************************************************/
#include "burnint.h"
#include "sn76477.h"
#define VERBOSE 0
#if VERBOSE >= 0
#define LOG(n,x) //if( VERBOSE >= (n) ) logerror x
#else
#define LOG(n,x)
#endif
#define VMIN 0x0000
#define VMAX 0x7fff
struct SN76477 {
double mastervol;
int samplerate; /* from Machine->sample_rate */
int vol; /* current volume (attack/decay) */
int vol_count; /* volume adjustment counter */
int vol_rate; /* volume adjustment rate - dervied from attack/decay */
int vol_step; /* volume adjustment step */
double slf_count; /* SLF emulation */
double slf_freq; /* frequency - derived */
double slf_level; /* triangular wave level */
int slf_dir; /* triangular wave direction */
int slf_out; /* rectangular output signal state */
double vco_count; /* VCO emulation */
double vco_freq; /* frequency - derived */
double vco_step; /* modulated frequency - derived */
int vco_out; /* rectangular output signal state */
int noise_count; /* NOISE emulation */
int noise_clock; /* external clock signal */
int noise_freq; /* filter frequency - derived */
int noise_poly; /* polynome */
int noise_out; /* rectangular output signal state */
double envelope_timer; /* ENVELOPE timer */
int envelope_state; /* attack / decay toggle */
double attack_time; /* ATTACK time (time until vol reaches 100%) */
double decay_time; /* DECAY time (time until vol reaches 0%) */
double oneshot_time; /* ONE-SHOT time */
double oneshot_timer; /* ONE-SHOT timer */
int envelope; /* pin 1, pin 28 */
double noise_res; /* pin 4 */
double filter_res; /* pin 5 */
double filter_cap; /* pin 6 */
double decay_res; /* pin 7 */
double attack_decay_cap;/* pin 8 */
int enable; /* pin 9 */
double attack_res; /* pin 10 */
double amplitude_res; /* pin 11 */
double feedback_res; /* pin 12 */
double vco_voltage; /* pin 16 */
double vco_cap; /* pin 17 */
double vco_res; /* pin 18 */
double pitch_voltage; /* pin 19 */
double slf_res; /* pin 20 */
double slf_cap; /* pin 21 */
int vco_select; /* pin 22 */
double oneshot_cap; /* pin 23 */
double oneshot_res; /* pin 24 */
int mixer; /* pin 25,26,27 */
INT16 vol_lookup[VMAX+1-VMIN]; /* volume lookup table */
};
//static struct SN76477interface *intf;
struct SN76477 *sn76477[MAX_SN76477];
static void attack_decay(int param)
{
struct SN76477 *sn = sn76477[param];
sn->envelope_state ^= 1;
if( sn->envelope_state )
{
/* start ATTACK */
sn->vol_rate = ( sn->attack_time > 0 ) ? VMAX / sn->attack_time : VMAX;
sn->vol_step = +1;
LOG(2,("SN76477 #%d: ATTACK rate %d/%d = %d/sec\n", param, sn->vol_rate, sn->samplerate, sn->vol_rate/sn->samplerate));
}
else
{
/* start DECAY */
sn->vol = VMAX; /* just in case... */
sn->vol_rate = ( sn->decay_time > 0 ) ? VMAX / sn->decay_time : VMAX;
sn->vol_step = -1;
LOG(2,("SN76477 #%d: DECAY rate %d/%d = %d/sec\n", param, sn->vol_rate, sn->samplerate, sn->vol_rate/sn->samplerate));
}
}
static void vco_envelope_cb(int param)
{
attack_decay(param);
}
static void oneshot_envelope_cb(int param)
{
attack_decay(param);
}
static void sntimer_tick(int param)
{
if (sn76477[param]->envelope_timer > 0.0) {
vco_envelope_cb(param);
sn76477[param]->envelope_timer -= 0.0001;
//if (!sn76477[param]->envelope_timer)
// bprintf(0, _T("envtimer done!"));
}
if (sn76477[param]->oneshot_timer > 0.0) {
oneshot_envelope_cb(param);
sn76477[param]->oneshot_timer -= 0.0001;
//if (!sn76477[param]->oneshot_timer)
// bprintf(0, _T("shottimer done!"));
}
}
#if VERBOSE
static const char *mixer_mode[8] = {
"VCO",
"SLF",
"Noise",
"VCO/Noise",
"SLF/Noise",
"SLF/VCO/Noise",
"SLF/VCO",
"Inhibit"
};
#endif
/*****************************************************************************
* set MIXER select inputs
*****************************************************************************/
void SN76477_mixer_w(int chip, int data)
{
struct SN76477 *sn = sn76477[chip];
if( data == sn->mixer )
return;
sn->mixer = data;
LOG(1,("SN76477 #%d: MIXER mode %d [%s]\n", chip, sn->mixer, mixer_mode[sn->mixer]));
}
void SN76477_mixer_a_w(int chip, int data)
{
struct SN76477 *sn = sn76477[chip];
data = data ? 1 : 0;
if( data == (sn->mixer & 1) )
return;
sn->mixer = (sn->mixer & ~1) | data;
LOG(1,("SN76477 #%d: MIXER mode %d [%s]\n", chip, sn->mixer, mixer_mode[sn->mixer]));
}
void SN76477_mixer_b_w(int chip, int data)
{
struct SN76477 *sn = sn76477[chip];
data = data ? 2 : 0;
if( data == (sn->mixer & 2) )
return;
sn->mixer = (sn->mixer & ~2) | data;
LOG(1,("SN76477 #%d: MIXER mode %d [%s]\n", chip, sn->mixer, mixer_mode[sn->mixer]));
}
void SN76477_mixer_c_w(int chip, int data)
{
struct SN76477 *sn = sn76477[chip];
data = data ? 4 : 0;
if( data == (sn->mixer & 4) )
return;
sn->mixer = (sn->mixer & ~4) | data;
LOG(1,("SN76477 #%d: MIXER mode %d [%s]\n", chip, sn->mixer, mixer_mode[sn->mixer]));
}
#if VERBOSE
static const char *envelope_mode[4] = {
"VCO",
"One-Shot",
"Mixer only",
"VCO with alternating Polarity"
};
#endif
/*****************************************************************************
* set ENVELOPE select inputs
*****************************************************************************/
void SN76477_envelope_w(int chip, int data)
{
struct SN76477 *sn = sn76477[chip];
if( data == sn->envelope )
return;
sn->envelope = data;
LOG(1,("SN76477 #%d: ENVELOPE mode %d [%s]\n", chip, sn->envelope, envelope_mode[sn->envelope]));
}
void SN76477_envelope_1_w(int chip, int data)
{
struct SN76477 *sn = sn76477[chip];
if( data == (sn->envelope & 1) )
return;
sn->envelope = (sn->envelope & ~1) | data;
LOG(1,("SN76477 #%d: ENVELOPE mode %d [%s]\n", chip, sn->envelope, envelope_mode[sn->envelope]));
}
void SN76477_envelope_2_w(int chip, int data)
{
struct SN76477 *sn = sn76477[chip];
data <<= 1;
if( data == (sn->envelope & 2) )
return;
sn->envelope = (sn->envelope & ~2) | data;
LOG(1,("SN76477 #%d: ENVELOPE mode %d [%s]\n", chip, sn->envelope, envelope_mode[sn->envelope]));
}
/*****************************************************************************
* set VCO external/SLF input
*****************************************************************************/
void SN76477_vco_w(int chip, int data)
{
struct SN76477 *sn = sn76477[chip];
if( data == sn->vco_select )
return;
sn->vco_select = data;
LOG(1,("SN76477 #%d: VCO select %d [%s]\n", chip, sn->vco_select, sn->vco_select ? "Internal (SLF)" : "External (Pin 16)"));
}
/*****************************************************************************
* set VCO enable input
*****************************************************************************/
void SN76477_enable_w(int chip, int data)
{
struct SN76477 *sn = sn76477[chip];
if( data == sn->enable )
return;
sn->enable = data;
sn->envelope_state = data;
sn->envelope_timer = 0;
sn->oneshot_timer = 0;
if( sn->enable == 0 )
{
switch( sn->envelope )
{
case 0: /* VCO */
if( sn->vco_res > 0 && sn->vco_cap > 0 )
sn->envelope_timer = TIME_IN_HZ(0.64/(sn->vco_res * sn->vco_cap));
else
oneshot_envelope_cb(chip);
break;
case 1: /* One-Shot */
oneshot_envelope_cb(chip);
if (sn->oneshot_time > 0)
sn->oneshot_timer = sn->oneshot_time;
break;
case 2: /* MIXER only */
sn->vol = VMAX;
break;
default: /* VCO with alternating polariy */
/* huh? */
if( sn->vco_res > 0 && sn->vco_cap > 0 )
sn->envelope_timer = TIME_IN_HZ(0.64/(sn->vco_res * sn->vco_cap)/2);
else
oneshot_envelope_cb(chip);
break;
}
}
else
{
switch( sn->envelope )
{
case 0: /* VCO */
if( sn->vco_res > 0 && sn->vco_cap > 0 )
sn->envelope_timer = TIME_IN_HZ(0.64/(sn->vco_res * sn->vco_cap));
else
oneshot_envelope_cb(chip);
break;
case 1: /* One-Shot */
oneshot_envelope_cb(chip);
break;
case 2: /* MIXER only */
sn->vol = VMIN;
break;
default: /* VCO with alternating polariy */
/* huh? */
if( sn->vco_res > 0 && sn->vco_cap > 0 )
sn->envelope_timer = TIME_IN_HZ(0.64/(sn->vco_res * sn->vco_cap)/2);
else
oneshot_envelope_cb(chip);
break;
}
}
LOG(1,("SN76477 #%d: ENABLE line %d [%s]\n", chip, sn->enable, sn->enable ? "Inhibited" : "Enabled" ));
}
/*****************************************************************************
* set NOISE external signal (pin 3)
*****************************************************************************/
void SN76477_noise_clock_w(int chip, int data)
{
struct SN76477 *sn = sn76477[chip];
if( data == sn->noise_clock )
return;
sn->noise_clock = data;
/* on the rising edge shift the polynome */
if( sn->noise_clock )
sn->noise_poly = ((sn->noise_poly << 7) + (sn->noise_poly >> 10) + 0x18000) & 0x1ffff;
}
/*****************************************************************************
* set NOISE resistor (pin 4)
*****************************************************************************/
void SN76477_set_noise_res(int chip, double res)
{
struct SN76477 *sn = sn76477[chip];
sn->noise_res = res;
}
/*****************************************************************************
* set NOISE FILTER resistor (pin 5)
*****************************************************************************/
void SN76477_set_filter_res(int chip, double res)
{
struct SN76477 *sn = sn76477[chip];
if( res == sn->filter_res )
return;
sn->filter_res = res;
if( sn->filter_res > 0 && sn->filter_cap > 0 )
{
sn->noise_freq = (int)(1.28 / (sn->filter_res * sn->filter_cap));
LOG(1,("SN76477 #%d: NOISE FILTER freqency %d\n", chip, sn->noise_freq));
}
else
sn->noise_freq = sn->samplerate;
}
/*****************************************************************************
* set NOISE FILTER capacitor (pin 6)
*****************************************************************************/
void SN76477_set_filter_cap(int chip, double cap)
{
struct SN76477 *sn = sn76477[chip];
if( cap == sn->filter_cap )
return;
sn->filter_cap = cap;
if( sn->filter_res > 0 && sn->filter_cap > 0 )
{
sn->noise_freq = (int)(1.28 / (sn->filter_res * sn->filter_cap));
LOG(1,("SN76477 #%d: NOISE FILTER freqency %d\n", chip, sn->noise_freq));
}
else
sn->noise_freq = sn->samplerate;
}
/*****************************************************************************
* set DECAY resistor (pin 7)
*****************************************************************************/
void SN76477_set_decay_res(int chip, double res)
{
struct SN76477 *sn = sn76477[chip];
if( res == sn->decay_res )
return;
sn->decay_res = res;
sn->decay_time = sn->decay_res * sn->attack_decay_cap;
LOG(1,("SN76477 #%d: DECAY time is %fs\n", chip, sn->decay_time));
}
/*****************************************************************************
* set ATTACK/DECAY capacitor (pin 8)
*****************************************************************************/
void SN76477_set_attack_decay_cap(int chip, double cap)
{
struct SN76477 *sn = sn76477[chip];
if( cap == sn->attack_decay_cap )
return;
sn->attack_decay_cap = cap;
sn->decay_time = sn->decay_res * sn->attack_decay_cap;
sn->attack_time = sn->attack_res * sn->attack_decay_cap;
LOG(1,("SN76477 #%d: ATTACK time is %fs\n", chip, sn->attack_time));
LOG(1,("SN76477 #%d: DECAY time is %fs\n", chip, sn->decay_time));
}
/*****************************************************************************
* set ATTACK resistor (pin 10)
*****************************************************************************/
void SN76477_set_attack_res(int chip, double res)
{
struct SN76477 *sn = sn76477[chip];
if( res == sn->attack_res )
return;
sn->attack_res = res;
sn->attack_time = sn->attack_res * sn->attack_decay_cap;
LOG(1,("SN76477 #%d: ATTACK time is %fs\n", chip, sn->attack_time));
}
/*****************************************************************************
* set AMP resistor (pin 11)
*****************************************************************************/
void SN76477_set_amplitude_res(int chip, double res)
{
struct SN76477 *sn = sn76477[chip];
int i;
if( res == sn->amplitude_res )
return;
sn->amplitude_res = res;
if( sn->amplitude_res > 0 )
{
#if VERBOSE
int clip = 0;
#endif
for( i = 0; i < VMAX+1; i++ )
{
int vol = (int)((3.4 * sn->feedback_res / sn->amplitude_res) * 32767 * i / (VMAX+1));
#if VERBOSE
if( vol > 32767 && !clip )
clip = i;
LOG(3,("%d\n", vol));
#endif
if( vol > 32767 ) vol = 32767;
sn->vol_lookup[i] = vol * sn->mastervol / 100;
}
LOG(1,("SN76477 #%d: volume range from -%d to +%d (clip at %d%%)\n", chip, sn->vol_lookup[VMAX-VMIN], sn->vol_lookup[VMAX-VMIN], clip * 100 / 256));
}
else
{
memset(sn->vol_lookup, 0, sizeof(sn->vol_lookup));
}
}
/*****************************************************************************
* set FEEDBACK resistor (pin 12)
*****************************************************************************/
void SN76477_set_feedback_res(int chip, double res)
{
struct SN76477 *sn = sn76477[chip];
int i;
if( res == sn->feedback_res )
return;
sn->feedback_res = res;
if( sn->amplitude_res > 0 )
{
#if VERBOSE
int clip = 0;
#endif
for( i = 0; i < VMAX+1; i++ )
{
int vol = (int)((3.4 * sn->feedback_res / sn->amplitude_res) * 32767 * i / (VMAX+1));
#if VERBOSE
if( vol > 32767 && !clip ) clip = i;
#endif
if( vol > 32767 ) vol = 32767;
sn->vol_lookup[i] = vol * sn->mastervol / 100;
}
LOG(1,("SN76477 #%d: volume range from -%d to +%d (clip at %d%%)\n", chip, sn->vol_lookup[VMAX-VMIN], sn->vol_lookup[VMAX-VMIN], clip * 100 / 256));
}
else
{
memset(sn->vol_lookup, 0, sizeof(sn->vol_lookup));
}
}
/*****************************************************************************
* set PITCH voltage (pin 19)
* TODO: fill with live...
*****************************************************************************/
void SN76477_set_pitch_voltage(int chip, double voltage)
{
struct SN76477 *sn = sn76477[chip];
if( voltage == sn->pitch_voltage )
return;
sn->pitch_voltage = voltage;
LOG(1,("SN76477 #%d: VCO pitch voltage %f (%d%% duty cycle)\n", chip, sn->pitch_voltage, 0));
}
/*****************************************************************************
* set VCO resistor (pin 18)
*****************************************************************************/
void SN76477_set_vco_res(int chip, double res)
{
struct SN76477 *sn = sn76477[chip];
if( res == sn->vco_res )
return;
sn->vco_res = res;
if( sn->vco_res > 0 && sn->vco_cap > 0 )
{
sn->vco_freq = 0.64 / (sn->vco_res * sn->vco_cap);
LOG(1,("SN76477 #%d: VCO freqency %f\n", chip, sn->vco_freq));
}
else
sn->vco_freq = 0;
}
/*****************************************************************************
* set VCO capacitor (pin 17)
*****************************************************************************/
void SN76477_set_vco_cap(int chip, double cap)
{
struct SN76477 *sn = sn76477[chip];
if( cap == sn->vco_cap )
return;
sn->vco_cap = cap;
if( sn->vco_res > 0 && sn->vco_cap > 0 )
{
sn->vco_freq = 0.64 / (sn->vco_res * sn->vco_cap);
LOG(1,("SN76477 #%d: VCO freqency %f\n", chip, sn->vco_freq));
}
else
sn->vco_freq = 0;
}
/*****************************************************************************
* set VCO voltage (pin 16)
*****************************************************************************/
void SN76477_set_vco_voltage(int chip, double voltage)
{
struct SN76477 *sn = sn76477[chip];
if( voltage == sn->vco_voltage )
return;
sn->vco_voltage = voltage;
LOG(1,("SN76477 #%d: VCO ext. voltage %f (%f * %f = %f Hz)\n", chip,
sn->vco_voltage,
sn->vco_freq,
10.0 * (5.0 - sn->vco_voltage) / 5.0,
sn->vco_freq * 10.0 * (5.0 - sn->vco_voltage) / 5.0));
}
/*****************************************************************************
* set SLF resistor (pin 20)
*****************************************************************************/
void SN76477_set_slf_res(int chip, double res)
{
struct SN76477 *sn = sn76477[chip];
if( res == sn->slf_res )
return;
sn->slf_res = res;
if( sn->slf_res > 0 && sn->slf_cap > 0 )
{
sn->slf_freq = 0.64 / (sn->slf_res * sn->slf_cap);
LOG(1,("SN76477 #%d: SLF freqency %f\n", chip, sn->slf_freq));
}
else
sn->slf_freq = 0;
}
/*****************************************************************************
* set SLF capacitor (pin 21)
*****************************************************************************/
void SN76477_set_slf_cap(int chip, double cap)
{
struct SN76477 *sn = sn76477[chip];
if( cap == sn->slf_cap )
return;
sn->slf_cap = cap;
if( sn->slf_res > 0 && sn->slf_cap > 0 )
{
sn->slf_freq = 0.64 / (sn->slf_res * sn->slf_cap);
LOG(1,("SN76477 #%d: SLF freqency %f\n", chip, sn->slf_freq));
}
else
sn->slf_freq = 0;
}
/*****************************************************************************
* set ONESHOT resistor (pin 24)
*****************************************************************************/
void SN76477_set_oneshot_res(int chip, double res)
{
struct SN76477 *sn = sn76477[chip];
if( res == sn->oneshot_res )
return;
sn->oneshot_res = res;
sn->oneshot_time = 0.8 * sn->oneshot_res * sn->oneshot_cap;
//bprintf(0,_T("SN76477 #%d: ONE-SHOT(res) time %fs\n"), chip, sn->oneshot_time);
}
/*****************************************************************************
* set ONESHOT capacitor (pin 23)
*****************************************************************************/
void SN76477_set_oneshot_cap(int chip, double cap)
{
struct SN76477 *sn = sn76477[chip];
if( cap == sn->oneshot_cap )
return;
sn->oneshot_cap = cap;
sn->oneshot_time = 0.8 * sn->oneshot_res * sn->oneshot_cap;
//bprintf(0,_T("SN76477 #%d: ONE-SHOT(cap) time %fs\n"), chip, sn->oneshot_time);
}
void SN76477_set_mastervol(int chip, double vol)
{
struct SN76477 *sn = sn76477[chip];
sn->mastervol = vol;
}
#define UPDATE_SLF \
/************************************* \
* SLF super low frequency oscillator \
* frequency = 0.64 / (r_slf * c_slf) \
*************************************/ \
sn->slf_count -= sn->slf_freq; \
while( sn->slf_count <= 0 ) \
{ \
sn->slf_count += sn->samplerate; \
sn->slf_out ^= 1; \
}
#define UPDATE_VCO \
/************************************ \
* VCO voltage controlled oscilator \
* min. freq = 0.64 / (r_vco * c_vco) \
* freq. range is approx. 10:1 \
************************************/ \
if( sn->vco_select ) \
{ \
/* VCO is controlled by SLF */ \
if( sn->slf_dir == 0 ) \
{ \
sn->slf_level -= sn->slf_freq * 2 * 5.0 / sn->samplerate; \
if( sn->slf_level <= 0.0 ) \
{ \
sn->slf_level = 0.0; \
sn->slf_dir = 1; \
} \
} \
else \
if( sn->slf_dir == 1 ) \
{ \
sn->slf_level += sn->slf_freq * 2 * 5.0 / sn->samplerate; \
if( sn->slf_level >= 5.0 ) \
{ \
sn->slf_level = 5.0; \
sn->slf_dir = 0; \
} \
} \
sn->vco_step = sn->vco_freq * sn->slf_level; \
} \
else \
{ \
/* VCO is controlled by external voltage */ \
sn->vco_step = sn->vco_freq * sn->vco_voltage; \
} \
sn->vco_count -= sn->vco_step; \
while( sn->vco_count <= 0 ) \
{ \
sn->vco_count += sn->samplerate; \
sn->vco_out ^= 1; \
}
#define UPDATE_NOISE \
/************************************* \
* NOISE pseudo rand number generator \
*************************************/ \
if( sn->noise_res > 0 ) \
sn->noise_poly = ( (sn->noise_poly << 7) + \
(sn->noise_poly >> 10) + \
0x18000 ) & 0x1ffff; \
\
/* low pass filter: sample every noise_freq pseudo random value */ \
sn->noise_count -= sn->noise_freq; \
while( sn->noise_count <= 0 ) \
{ \
sn->noise_count = sn->samplerate; \
sn->noise_out = sn->noise_poly & 1; \
}
#define UPDATE_VOLUME \
/************************************* \
* VOLUME adjust for attack/decay \
*************************************/ \
sn->vol_count -= sn->vol_rate; \
if( sn->vol_count <= 0 ) \
{ \
int n = - sn->vol_count / sn->samplerate + 1; /* number of steps */ \
sn->vol_count += n * sn->samplerate; \
sn->vol += n * sn->vol_step; \
if( sn->vol < VMIN ) sn->vol = VMIN; \
if( sn->vol > VMAX ) sn->vol = VMAX; \
LOG(3,("SN76477 #%d: vol = $%04X\n", chip, sn->vol)); \
}
/*****************************************************************************
* mixer select 0 0 0 : VCO
*****************************************************************************/
static void SN76477_update_0(int chip, INT16 *buffer, int length)
{
struct SN76477 *sn = sn76477[chip];
while( length-- )
{
UPDATE_VCO;
UPDATE_VOLUME;
INT16 sam = (sn->vco_out ? sn->vol_lookup[sn->vol-VMIN] : -sn->vol_lookup[sn->vol-VMIN]);// * SNMASTERVOL;
*buffer = BURN_SND_CLIP(*buffer + sam);
buffer++;
*buffer = BURN_SND_CLIP(*buffer + sam);
buffer++;
sntimer_tick(chip);
}
}
/*****************************************************************************
* mixer select 0 0 1 : SLF
*****************************************************************************/
static void SN76477_update_1(int chip, INT16 *buffer, int length)
{
struct SN76477 *sn = sn76477[chip];
while( length-- )
{
UPDATE_SLF;
UPDATE_VOLUME;
INT16 sam = (sn->slf_out ? sn->vol_lookup[sn->vol-VMIN] : -sn->vol_lookup[sn->vol-VMIN]);// * SNMASTERVOL;
*buffer = BURN_SND_CLIP(*buffer + sam);
buffer++;
*buffer = BURN_SND_CLIP(*buffer + sam);
buffer++;
sntimer_tick(chip);
}
}
/*****************************************************************************
* mixer select 0 1 0 : NOISE
*****************************************************************************/
static void SN76477_update_2(int chip, INT16 *buffer, int length)
{
struct SN76477 *sn = sn76477[chip];
while( length-- )
{
UPDATE_NOISE;
UPDATE_VOLUME;
INT16 sam = (sn->noise_out ? sn->vol_lookup[sn->vol-VMIN] : -sn->vol_lookup[sn->vol-VMIN]);// * SNMASTERVOL;
*buffer = BURN_SND_CLIP(*buffer + sam);
buffer++;
*buffer = BURN_SND_CLIP(*buffer + sam);
buffer++;
sntimer_tick(chip);
}
}
/*****************************************************************************
* mixer select 0 1 1 : VCO and NOISE
*****************************************************************************/
static void SN76477_update_3(int chip, INT16 *buffer, int length)
{
struct SN76477 *sn = sn76477[chip];
while( length-- )
{
UPDATE_VCO;
UPDATE_NOISE;
UPDATE_VOLUME;
INT16 sam = ((sn->vco_out & sn->noise_out) ? sn->vol_lookup[sn->vol-VMIN] : -sn->vol_lookup[sn->vol-VMIN]);// * SNMASTERVOL;
*buffer = BURN_SND_CLIP(*buffer + sam);
buffer++;
*buffer = BURN_SND_CLIP(*buffer + sam);
buffer++;
sntimer_tick(chip);
}
}
/*****************************************************************************
* mixer select 1 0 0 : SLF and NOISE
*****************************************************************************/
static void SN76477_update_4(int chip, INT16 *buffer, int length)
{
struct SN76477 *sn = sn76477[chip];
while( length-- )
{
UPDATE_SLF;
UPDATE_NOISE;
UPDATE_VOLUME;
INT16 sam = ((sn->slf_out & sn->noise_out) ? sn->vol_lookup[sn->vol-VMIN] : -sn->vol_lookup[sn->vol-VMIN]);// * SNMASTERVOL;
*buffer = BURN_SND_CLIP(*buffer + sam);
buffer++;
*buffer = BURN_SND_CLIP(*buffer + sam);
buffer++;
sntimer_tick(chip);
}
}
/*****************************************************************************
* mixer select 1 0 1 : VCO, SLF and NOISE
*****************************************************************************/
static void SN76477_update_5(int chip, INT16 *buffer, int length)
{
struct SN76477 *sn = sn76477[chip];
while( length-- )
{
UPDATE_SLF;
UPDATE_VCO;
UPDATE_NOISE;
UPDATE_VOLUME;
INT16 sam = ((sn->vco_out & sn->slf_out & sn->noise_out) ? sn->vol_lookup[sn->vol-VMIN] : -sn->vol_lookup[sn->vol-VMIN]);// * SNMASTERVOL;
*buffer = BURN_SND_CLIP(*buffer + sam);
buffer++;
*buffer = BURN_SND_CLIP(*buffer + sam);
buffer++;
sntimer_tick(chip);
}
}
/*****************************************************************************
* mixer select 1 1 0 : VCO and SLF
*****************************************************************************/
static void SN76477_update_6(int chip, INT16 *buffer, int length)
{
struct SN76477 *sn = sn76477[chip];
while( length-- )
{
UPDATE_SLF;
UPDATE_VCO;
UPDATE_VOLUME;
INT16 sam = ((sn->vco_out & sn->slf_out) ? sn->vol_lookup[sn->vol-VMIN] : -sn->vol_lookup[sn->vol-VMIN]);// * SNMASTERVOL;
*buffer = BURN_SND_CLIP(*buffer + sam);
buffer++;
*buffer = BURN_SND_CLIP(*buffer + sam);
buffer++;
sntimer_tick(chip);
}
}
/*****************************************************************************
* mixer select 1 1 1 : Inhibit
*****************************************************************************/
static void SN76477_update_7(int chip, INT16 *buffer, int length)
{
/*while( length-- ) {
*buffer++ = 0;
*buffer++ = 0;
}*/
}
void SN76477_sound_update(int param, INT16 *buffer, int length)
{
struct SN76477 *sn = sn76477[param];
if( sn->enable )
{
SN76477_update_7(param,buffer,length);
}
else
{
switch( sn->mixer )
{
case 0:
SN76477_update_0(param,buffer,length);
break;
case 1:
SN76477_update_1(param,buffer,length);
break;
case 2:
SN76477_update_2(param,buffer,length);
break;
case 3:
SN76477_update_3(param,buffer,length);
break;
case 4:
SN76477_update_4(param,buffer,length);
break;
case 5:
SN76477_update_5(param,buffer,length);
break;
case 6:
SN76477_update_6(param,buffer,length);
break;
default:
SN76477_update_7(param,buffer,length);
break;
}
}
#if 0
if (sn76477[param]->oneshot_timer > 0.0)
bprintf(0, _T("ost: %fs, "), sn76477[param]->oneshot_timer);
if (sn76477[param]->envelope_timer > 0.0)
bprintf(0, _T("envt: %fs, "), sn76477[param]->envelope_timer);
#endif
}
void SN76477_exit(int num) // yea, needs work. I know..
{
if (sn76477[num]) {
free(sn76477[num]);
sn76477[num] = NULL;
}
}
void SN76477_init(int num)
{
sn76477[num] = (SN76477 *)malloc(sizeof(struct SN76477));
if( !sn76477[num] )
{
LOG(0,("%s failed to malloc struct SN76477\n", name));
return;
}
memset(sn76477[num], 0, sizeof(struct SN76477));
sn76477[num]->samplerate = nBurnSoundRate;
sn76477[num]->envelope_timer = 0;
sn76477[num]->oneshot_timer = 0;
sn76477[num]->mastervol = 1.00;
SN76477_mixer_w(num, 0x07); /* turn off mixing */
SN76477_envelope_w(num, 0x03); /* envelope inputs open */
SN76477_enable_w(num, 0x01); /* enable input open */
}

82
src/burn/snd/sn76477.h Normal file
View File

@ -0,0 +1,82 @@
/*****************************************************************************
SN76477 pins and assigned interface variables/functions
SN76477_envelope_w()
/ \
[ 1] ENV SEL 1 ENV SEL 2 [28]
[ 2] GND MIXER C [27] \
SN76477_noise_w() [ 3] NOISE EXT OSC MIXER A [26] > SN76477_mixer_w()
noise_res [ 4] RES NOISE OSC MIXER B [25] /
filter_res [ 5] NOISE FILTER RES O/S RES [24] oneshot_res
filter_cap [ 6] NOISE FILTER CAP O/S CAP [23] oneshot_cap
decay_res [ 7] DECAY RES VCO SEL [22] SN76477_vco_w()
attack_decay_cap [ 8] A/D CAP SLF CAP [21] slf_cap
SN76477_enable_w() [ 9] ENABLE SLF RES [20] slf_res
attack_res [10] ATTACK RES PITCH [19] pitch_voltage
amplitude_res [11] AMP VCO RES [18] vco_res
feedback_res [12] FEEDBACK VCO CAP [17] vco_cap
[13] OUTPUT VCO EXT CONT [16] vco_voltage
[14] Vcc +5V REG OUT [15]
All resistor values in Ohms.
All capacitor values in Farads.
Use RES_K, RES_M and CAP_U, CAP_N, CAP_P macros to convert
magnitudes, eg. 220k = RES_K(220), 47nF = CAP_N(47)
*****************************************************************************/
#define MAX_SN76477 4
/* Little helpers for magnitude conversions */
#define RES_K(res) ((double)res*1e3)
#define RES_M(res) ((double)res*1e6)
#define CAP_U(cap) ((double)cap*1e-6)
#define CAP_N(cap) ((double)cap*1e-9)
#define CAP_P(cap) ((double)cap*1e-12)
#define TIME_IN_HZ(hz) (1.0 / (double)(hz))
/* Noise clock write, useful only if noise_res is zero */
extern void SN76477_noise_clock_w(int chip, int data);
/* Enable (one input line: 0 enabled, 1 inhibited) - resets one shot */
extern void SN76477_enable_w(int chip, int data);
/* Mixer select (three input lines, data 0 to 7) */
extern void SN76477_mixer_w(int chip, int data);
/* Alternatively write the single input lines */
extern void SN76477_mixer_a_w(int chip, int data);
extern void SN76477_mixer_b_w(int chip, int data);
extern void SN76477_mixer_c_w(int chip, int data);
/* Select envelope (two input lines, data 0 to 3) */
extern void SN76477_envelope_w(int chip, int data);
/* Alternatively use the single input lines */
extern void SN76477_envelope_1_w(int chip, int data);
extern void SN76477_envelope_2_w(int chip, int data);
/* VCO select (one input line: 0 external control, 1: SLF control) */
extern void SN76477_vco_w(int chip, int data);
void SN76477_set_noise_res(int chip, double res);
void SN76477_set_filter_res(int chip, double res);
void SN76477_set_filter_cap(int chip, double cap);
void SN76477_set_decay_res(int chip, double res);
void SN76477_set_attack_decay_cap(int chip, double cap);
void SN76477_set_attack_res(int chip, double res);
void SN76477_set_amplitude_res(int chip, double res);
void SN76477_set_feedback_res(int chip, double res);
void SN76477_set_slf_res(int chip, double res);
void SN76477_set_slf_cap(int chip, double cap);
void SN76477_set_oneshot_res(int chip, double res);
void SN76477_set_oneshot_cap(int chip, double cap);
void SN76477_set_vco_res(int chip, double res);
void SN76477_set_vco_cap(int chip, double cap);
void SN76477_set_pitch_voltage(int chip, double voltage);
void SN76477_set_vco_voltage(int chip, double voltage);
void SN76477_set_mastervol(int chip, double vol);
void SN76477_sound_update(int param, INT16 *buffer, int length);
void SN76477_init(int num);
void SN76477_exit(int num);