Implemented Adlib Gold mixer.

This commit is contained in:
SarahW
2016-04-11 21:42:43 +01:00
parent 60440726a9
commit 3030325bd2
4 changed files with 317 additions and 12 deletions

BIN
nvr/adgold.bin Normal file

Binary file not shown.

View File

@@ -176,3 +176,106 @@ static inline float sb_iir(int i, float NewSample) {
return y[i][0];
}
#undef NCoef
#define NCoef 2
//fc=150Hz
static inline float adgold_highpass_iir(int i, float NewSample) {
float ACoef[NCoef+1] = {
0.98657437157334349000,
-1.97314874314668700000,
0.98657437157334349000
};
float BCoef[NCoef+1] = {
1.00000000000000000000,
-1.97223372919758360000,
0.97261396931534050000
};
static float y[2][NCoef+1]; //output samples
static float x[2][NCoef+1]; //input samples
int n;
//shift the old samples
for(n=NCoef; n>0; n--) {
x[i][n] = x[i][n-1];
y[i][n] = y[i][n-1];
}
//Calculate the new output
x[i][0] = NewSample;
y[i][0] = ACoef[0] * x[i][0];
for(n=1; n<=NCoef; n++)
y[i][0] += ACoef[n] * x[i][n] - BCoef[n] * y[i][n];
return y[i][0];
}
//fc=150Hz
static inline float adgold_lowpass_iir(int i, float NewSample) {
float ACoef[NCoef+1] = {
0.00009159473951071446,
0.00018318947902142891,
0.00009159473951071446
};
float BCoef[NCoef+1] = {
1.00000000000000000000,
-1.97223372919526560000,
0.97261396931306277000
};
static float y[2][NCoef+1]; //output samples
static float x[2][NCoef+1]; //input samples
int n;
//shift the old samples
for(n=NCoef; n>0; n--) {
x[i][n] = x[i][n-1];
y[i][n] = y[i][n-1];
}
//Calculate the new output
x[i][0] = NewSample;
y[i][0] = ACoef[0] * x[i][0];
for(n=1; n<=NCoef; n++)
y[i][0] += ACoef[n] * x[i][n] - BCoef[n] * y[i][n];
return y[i][0];
}
//fc=56Hz
static inline float adgold_pseudo_stereo_iir(float NewSample) {
float ACoef[NCoef+1] = {
0.00001409030866231767,
0.00002818061732463533,
0.00001409030866231767
};
float BCoef[NCoef+1] = {
1.00000000000000000000,
-1.98733021473466760000,
0.98738361004063568000
};
static float y[NCoef+1]; //output samples
static float x[NCoef+1]; //input samples
int n;
//shift the old samples
for(n=NCoef; n>0; n--) {
x[n] = x[n-1];
y[n] = y[n-1];
}
//Calculate the new output
x[0] = NewSample;
y[0] = ACoef[0] * x[0];
for(n=1; n<=NCoef; n++)
y[0] += ACoef[n] * x[n] - BCoef[n] * y[n];
return y[0];
}

View File

@@ -12,6 +12,8 @@
#include "sound.h"
#include "timer.h"
#include "filters.h"
typedef struct adgold_t
{
int adgold_irq_status;
@@ -47,6 +49,11 @@ typedef struct adgold_t
opl_t opl;
ym7128_t ym7128;
int fm_vol_l, fm_vol_r;
int samp_vol_l, samp_vol_r;
int vol_l, vol_r;
int treble, bass;
int16_t opl_buffer[SOUNDBUFLEN * 2];
int16_t mma_buffer[2][SOUNDBUFLEN];
@@ -56,6 +63,67 @@ typedef struct adgold_t
int surround_enabled;
} adgold_t;
static int attenuation[0x40];
static int bass_attenuation[0x10] =
{
(int)(1.995 * 16384), /*12 dB - filter output is at +6 dB so we use 6 dB here*/
(int)(1.995 * 16384),
(int)(1.995 * 16384),
(int)(1.413 * 16384), /*9 dB*/
(int)(1 * 16384), /*6 dB*/
(int)(0.708 * 16384), /*3 dB*/
(int)(0 * 16384), /*0 dB*/
(int)(0.708 * 16384), /*3 dB*/
(int)(1 * 16384), /*6 dB*/
(int)(1.413 * 16384), /*9 dB*/
(int)(1.995 * 16384), /*12 dB*/
(int)(2.819 * 16384), /*15 dB*/
(int)(2.819 * 16384),
(int)(2.819 * 16384),
(int)(2.819 * 16384),
(int)(2.819 * 16384)
};
static int bass_cut[6] =
{
(int)(0.126 * 16384), /*-12 dB*/
(int)(0.126 * 16384), /*-12 dB*/
(int)(0.126 * 16384), /*-12 dB*/
(int)(0.178 * 16384), /*-9 dB*/
(int)(0.251 * 16384), /*-6 dB*/
(int)(0.354 * 16384) /*-3 dB - filter output is at +6 dB*/
};
static int treble_attenuation[0x10] =
{
(int)(1.995 * 16384), /*12 dB - filter output is at +6 dB so we use 6 dB here*/
(int)(1.995 * 16384),
(int)(1.995 * 16384),
(int)(1.413 * 16384), /*9 dB*/
(int)(1 * 16384), /*6 dB*/
(int)(0.708 * 16384), /*3 dB*/
(int)(0 * 16384), /*0 dB*/
(int)(0.708 * 16384), /*3 dB*/
(int)(1 * 16384), /*6 dB*/
(int)(1.413 * 16384), /*9 dB*/
(int)(1.995 * 16384), /*12 dB*/
(int)(1.995 * 16384),
(int)(1.995 * 16384),
(int)(1.995 * 16384),
(int)(1.995 * 16384),
(int)(1.995 * 16384)
};
static int treble_cut[6] =
{
(int)(0.126 * 16384), /*-12 dB*/
(int)(0.126 * 16384), /*-12 dB*/
(int)(0.126 * 16384), /*-12 dB*/
(int)(0.178 * 16384), /*-9 dB*/
(int)(0.251 * 16384), /*-6 dB*/
(int)(0.354 * 16384) /*-3 dB - filter output is at +6 dB*/
};
void adgold_timer_poll();
void adgold_update(adgold_t *adgold);
@@ -114,7 +182,7 @@ void adgold_getsamp_dma(adgold_t *adgold, int channel)
void adgold_write(uint16_t addr, uint8_t val, void *p)
{
adgold_t *adgold = (adgold_t *)p;
if (addr > 0x389) pclog("adgold_write : addr %04X val %02X %04X:%04X\n", addr, val, CS, pc);
// if (addr > 0x389) pclog("adgold_write : addr %04X val %02X %04X:%04X\n", addr, val, CS, pc);
switch (addr & 7)
{
case 0: case 1:
@@ -150,6 +218,40 @@ void adgold_write(uint16_t addr, uint8_t val, void *p)
memcpy(adgold->adgold_eeprom, adgold->adgold_38x_regs, 0x19);
break;
case 0x04: /*Final output volume left*/
adgold->adgold_38x_regs[0x04] = val;
adgold->vol_l = attenuation[val & 0x3f];
break;
case 0x05: /*Final output volume right*/
adgold->adgold_38x_regs[0x05] = val;
adgold->vol_r = attenuation[val & 0x3f];
break;
case 0x06: /*Bass*/
adgold->adgold_38x_regs[0x06] = val;
adgold->bass = val & 0xf;
break;
case 0x07: /*Treble*/
adgold->adgold_38x_regs[0x07] = val;
adgold->treble = val & 0xf;
break;
case 0x09: /*FM volume left*/
adgold->adgold_38x_regs[0x09] = val;
adgold->fm_vol_l = (int)(int8_t)(val - 128);
break;
case 0x0a: /*FM volume right*/
adgold->adgold_38x_regs[0x0a] = val;
adgold->fm_vol_r = (int)(int8_t)(val - 128);
break;
case 0x0b: /*Sample volume left*/
adgold->adgold_38x_regs[0x0b] = val;
adgold->samp_vol_l = (int)(int8_t)(val - 128);
break;
case 0x0c: /*Sample volume right*/
adgold->adgold_38x_regs[0x0c] = val;
adgold->samp_vol_r = (int)(int8_t)(val - 128);
break;
case 0x18: /*Surround*/
adgold->adgold_38x_regs[0x18] = val;
ym7128_write(&adgold->ym7128, val);
@@ -557,19 +659,101 @@ static void adgold_get_buffer(int16_t *buffer, int len, void *p)
int c;
opl3_update2(&adgold->opl);
for (c = 0; c < len * 2; c++)
for (c = 0; c < len * 2; c += 2)
{
adgold_buffer[c] = adgold->opl.buffer[c] / 2;
adgold_buffer[c] += adgold->mma_buffer[c & 1][c >> 1] / 4;
buffer[c] += adgold_buffer[c];
adgold_buffer[c] = ((adgold->opl.buffer[c] * adgold->fm_vol_l) >> 7) / 2;
adgold_buffer[c] += ((adgold->mma_buffer[0][c >> 1] * adgold->samp_vol_l) >> 7) / 4;
adgold_buffer[c+1] = ((adgold->opl.buffer[c+1] * adgold->fm_vol_r) >> 7) / 2;
adgold_buffer[c+1] += ((adgold->mma_buffer[1][c >> 1] * adgold->samp_vol_r) >> 7) / 4;
}
if (adgold->surround_enabled)
{
ym7128_apply(&adgold->ym7128, adgold_buffer, len);
switch (adgold->adgold_38x_regs[0x8] & 6)
{
case 0:
for (c = 0; c < len * 2; c++)
buffer[c] += adgold_buffer[c];
adgold_buffer[c] = 0;
break;
case 2: /*Left channel only*/
for (c = 0; c < len * 2; c += 2)
adgold_buffer[c+1] = adgold_buffer[c];
break;
case 4: /*Right channel only*/
for (c = 0; c < len * 2; c += 2)
adgold_buffer[c] = adgold_buffer[c+1];
break;
case 6: /*Left and right channels*/
break;
}
switch (adgold->adgold_38x_regs[0x8] & 0x18)
{
case 0x00: /*Forced mono*/
for (c = 0; c < len * 2; c += 2)
adgold_buffer[c] = adgold_buffer[c+1] = ((int32_t)adgold_buffer[c] + (int32_t)adgold_buffer[c+1]) / 2;
break;
case 0x08: /*Linear stereo*/
break;
case 0x10: /*Pseudo stereo*/
/*Filter left channel, leave right channel unchanged*/
/*Filter cutoff is largely a guess*/
for (c = 0; c < len * 2; c += 2)
adgold_buffer[c] += adgold_pseudo_stereo_iir(adgold_buffer[c]);
break;
case 0x18: /*Spatial stereo*/
/*Quite probably wrong, I only have the diagram in the TDA8425 datasheet
and a very vague understanding of how op-amps work to go on*/
for (c = 0; c < len * 2; c += 2)
{
int16_t l = adgold_buffer[c];
int16_t r = adgold_buffer[c+1];
adgold_buffer[c] += (r / 3) + ((l * 2) / 3);
adgold_buffer[c+1] += (l / 3) + ((r * 2) / 3);
}
break;
}
for (c = 0; c < len * 2; c += 2)
{
int32_t temp, lowpass, highpass;
/*Output is deliberately halved to avoid clipping*/
temp = ((int32_t)adgold_buffer[c] * adgold->vol_l) >> 17;
lowpass = adgold_lowpass_iir(0, temp);
highpass = adgold_highpass_iir(0, temp);
if (adgold->bass > 6)
temp += (lowpass * bass_attenuation[adgold->bass]) >> 14;
else if (adgold->bass < 6)
temp = highpass + ((temp * bass_cut[adgold->bass]) >> 14);
if (adgold->treble > 6)
temp += (highpass * treble_attenuation[adgold->treble]) >> 14;
else if (adgold->treble < 6)
temp = lowpass + ((temp * treble_cut[adgold->treble]) >> 14);
if (temp < -32768)
temp = -32768;
if (temp > 32767)
temp = 32767;
buffer[c] += temp;
temp = ((int32_t)adgold_buffer[c+1] * adgold->vol_r) >> 17;
lowpass = adgold_lowpass_iir(1, temp);
highpass = adgold_highpass_iir(1, temp);
if (adgold->bass > 6)
temp += (lowpass * bass_attenuation[adgold->bass]) >> 14;
else if (adgold->bass < 6)
temp = highpass + ((temp * bass_cut[adgold->bass]) >> 14);
if (adgold->treble > 6)
temp += (highpass * treble_attenuation[adgold->treble]) >> 14;
else if (adgold->treble < 6)
temp = lowpass + ((temp * treble_cut[adgold->treble]) >> 14);
if (temp < -32768)
temp = -32768;
if (temp > 32767)
temp = 32767;
buffer[c+1] += temp;
}
adgold->opl.pos = 0;
@@ -580,6 +764,8 @@ static void adgold_get_buffer(int16_t *buffer, int len, void *p)
void *adgold_init()
{
FILE *f;
int c;
double out;
adgold_t *adgold = malloc(sizeof(adgold_t));
memset(adgold, 0, sizeof(adgold_t));
@@ -589,6 +775,15 @@ void *adgold_init()
if (adgold->surround_enabled)
ym7128_init(&adgold->ym7128);
out = 65536.0; /*Main volume control ranges from +6 dB to -64 dB in 2 dB steps, then remaining settings are -80 dB (effectively 0)*/
for (c = 0x3f; c >= 0x1c; c--)
{
attenuation[c] = (int)out;
out /= 1.25963; /*2 dB steps*/
}
for (; c >= 0; c--)
attenuation[c] = 0;
f = romfopen("nvr/adgold.bin", "rb");
if (f)
{
@@ -598,11 +793,18 @@ void *adgold_init()
adgold->adgold_status = 0xf;
adgold->adgold_38x_addr = 0;
adgold->adgold_eeprom[0x09] = adgold->adgold_eeprom[0x0a] = 255;
adgold->adgold_eeprom[0x13] = 3 | (1 << 4); /*IRQ 7, DMA 1*/
adgold->adgold_eeprom[0x14] = 3 << 4; /*DMA 3*/
adgold->adgold_eeprom[0x15] = 0x388 / 8; /*Present at 388-38f*/
memcpy(adgold->adgold_38x_regs, adgold->adgold_eeprom, 0x19);
adgold->vol_l = attenuation[adgold->adgold_eeprom[0x04] & 0x3f];
adgold->vol_r = attenuation[adgold->adgold_eeprom[0x05] & 0x3f];
adgold->bass = adgold->adgold_eeprom[0x06] & 0xf;
adgold->treble = adgold->adgold_eeprom[0x07] & 0xf;
adgold->fm_vol_l = (int)(int8_t)(adgold->adgold_eeprom[0x09] - 128);
adgold->fm_vol_r = (int)(int8_t)(adgold->adgold_eeprom[0x0a] - 128);
adgold->samp_vol_l = (int)(int8_t)(adgold->adgold_eeprom[0x0b] - 128);
adgold->samp_vol_r = (int)(int8_t)(adgold->adgold_eeprom[0x0c] - 128);
adgold->adgold_mma_enable[0] = 0;
adgold->adgold_mma_fifo_start[0] = adgold->adgold_mma_fifo_end[0] = 0;

View File

@@ -126,10 +126,10 @@ void ym7128_apply(ym7128_t *ym7128, int16_t *buffer, int len)
samp_l = (samp_l * ym7128->vl*2) >> 16;
samp_r = (samp_r * ym7128->vr*2) >> 16;
buffer[c] = ((int32_t)samp_l + (int32_t)ym7128->prev_l) / 2;
buffer[c+1] = ((int32_t)samp_r + (int32_t)ym7128->prev_r) / 2;
buffer[c+2] = samp_l;
buffer[c+3] = samp_r;
buffer[c] += ((int32_t)samp_l + (int32_t)ym7128->prev_l) / 2;
buffer[c+1] += ((int32_t)samp_r + (int32_t)ym7128->prev_r) / 2;
buffer[c+2] += samp_l;
buffer[c+3] += samp_r;
ym7128->delay_pos++;
if (ym7128->delay_pos >= 2400)