mirror of
https://github.com/libretro/FBNeo.git
synced 2024-11-30 20:40:53 +00:00
sys16b/upd7759: add 2000hz lp filter for less hollow sound
This commit is contained in:
parent
37f9687904
commit
1cca6fa54e
@ -2064,6 +2064,7 @@ INT32 System16Init()
|
||||
UPD7759SetDrqCallback(0, System16UPD7759DrqCallback);
|
||||
UPD7759SetSyncCallback(0, ZetTotalCycles, 5000000);
|
||||
UPD7759SetRoute(0, 0.48, BURN_SND_ROUTE_BOTH);
|
||||
UPD7759SetFilter(0, 2000);
|
||||
BurnTimerAttachZet(5000000);
|
||||
}
|
||||
|
||||
|
104
src/burn/snd/biquad.h
Normal file
104
src/burn/snd/biquad.h
Normal file
@ -0,0 +1,104 @@
|
||||
// (also appears in k054539.cpp, d_spectrum.cpp c/o dink)
|
||||
// direct form II(transposed) biquadradic filter, needed for delay(echo) effect's filter taps -dink
|
||||
enum { FILT_HIGHPASS = 0, FILT_LOWPASS = 1, FILT_LOWSHELF = 2, FILT_HIGHSHELF = 3 };
|
||||
|
||||
struct BIQ {
|
||||
double a0;
|
||||
double a1;
|
||||
double a2;
|
||||
double b1;
|
||||
double b2;
|
||||
double q;
|
||||
double z1;
|
||||
double z2;
|
||||
double frequency;
|
||||
double samplerate;
|
||||
double output;
|
||||
|
||||
float filter(float input) {
|
||||
output = input * a0 + z1;
|
||||
z1 = input * a1 + z2 - b1 * output;
|
||||
z2 = input * a2 - b2 * output;
|
||||
return (float)output;
|
||||
}
|
||||
|
||||
void reset() {
|
||||
z1 = 0.0; z2 = 0.0; output = 0.0;
|
||||
}
|
||||
|
||||
void exit() {
|
||||
reset();
|
||||
}
|
||||
|
||||
void init(INT32 type, INT32 sample_rate, INT32 freqhz, double q_, double gain) {
|
||||
samplerate = sample_rate;
|
||||
frequency = freqhz;
|
||||
q = q_;
|
||||
|
||||
reset();
|
||||
|
||||
double k = tan(3.14159265358979323846 * frequency / samplerate);
|
||||
double norm = 1 / (1 + k / q + k * k);
|
||||
double v = pow(10, fabs(gain) / 20);
|
||||
|
||||
switch (type) {
|
||||
case FILT_HIGHPASS:
|
||||
{
|
||||
a0 = 1 * norm;
|
||||
a1 = -2 * a0;
|
||||
a2 = a0;
|
||||
b1 = 2 * (k * k - 1) * norm;
|
||||
b2 = (1 - k / q + k * k) * norm;
|
||||
}
|
||||
break;
|
||||
case FILT_LOWPASS:
|
||||
{
|
||||
a0 = k * k * norm;
|
||||
a1 = 2 * a0;
|
||||
a2 = a0;
|
||||
b1 = 2 * (k * k - 1) * norm;
|
||||
b2 = (1 - k / q + k * k) * norm;
|
||||
}
|
||||
break;
|
||||
case FILT_LOWSHELF:
|
||||
{
|
||||
if (gain >= 0) {
|
||||
norm = 1 / (1 + sqrt(2.0) * k + k * k);
|
||||
a0 = (1 + sqrt(2*v) * k + v * k * k) * norm;
|
||||
a1 = 2 * (v * k * k - 1) * norm;
|
||||
a2 = (1 - sqrt(2*v) * k + v * k * k) * norm;
|
||||
b1 = 2 * (k * k - 1) * norm;
|
||||
b2 = (1 - sqrt(2.0) * k + k * k) * norm;
|
||||
} else {
|
||||
norm = 1 / (1 + sqrt(2*v) * k + v * k * k);
|
||||
a0 = (1 + sqrt(2.0) * k + k * k) * norm;
|
||||
a1 = 2 * (k * k - 1) * norm;
|
||||
a2 = (1 - sqrt(2.0) * k + k * k) * norm;
|
||||
b1 = 2 * (v * k * k - 1) * norm;
|
||||
b2 = (1 - sqrt(2*v) * k + v * k * k) * norm;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case FILT_HIGHSHELF:
|
||||
{
|
||||
if (gain >= 0) {
|
||||
norm = 1 / (1 + sqrt(2.0) * k + k * k);
|
||||
a0 = (v + sqrt(2*v) * k + k * k) * norm;
|
||||
a1 = 2 * (k * k - v) * norm;
|
||||
a2 = (v - sqrt(2*v) * k + k * k) * norm;
|
||||
b1 = 2 * (k * k - 1) * norm;
|
||||
b2 = (1 - sqrt(2.0) * k + k * k) * norm;
|
||||
} else {
|
||||
norm = 1 / (v + sqrt(2*v) * k + k * k);
|
||||
a0 = (1 + sqrt(2.0) * k + k * k) * norm;
|
||||
a1 = 2 * (k * k - 1) * norm;
|
||||
a2 = (1 - sqrt(2.0) * k + k * k) * norm;
|
||||
b1 = 2 * (k * k - v) * norm;
|
||||
b2 = (v - sqrt(2*v) * k + k * k) * norm;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
// end biquad filter
|
@ -5,6 +5,7 @@
|
||||
#include "downsample.h"
|
||||
#include "timer.h"
|
||||
#include <math.h>
|
||||
#include "biquad.h"
|
||||
|
||||
#define FRAC_BITS 20
|
||||
#define FRAC_ONE (1 << FRAC_BITS)
|
||||
@ -75,13 +76,13 @@ struct upd7759_chip
|
||||
Downsampler resamp;
|
||||
INT16 * out_buf;
|
||||
INT16 * out_buf_linear;
|
||||
INT16 * out_buf_linear_resampled;
|
||||
INT32 out_buf_size;
|
||||
INT32 out_pos;
|
||||
|
||||
// filter
|
||||
INT32 filt_sa;
|
||||
INT32 filt_sb;
|
||||
INT32 filt_prev;
|
||||
BIQ biquadL;
|
||||
BIQ biquadR;
|
||||
|
||||
// stream sync
|
||||
INT32 (*pTotalCyclesCB)();
|
||||
@ -474,8 +475,16 @@ void UPD7759Render(INT32 chip, INT16 *pSoundBuf, INT32 samples)
|
||||
Chip->out_buf[cpos] = 0;
|
||||
}
|
||||
|
||||
// resample to host rate & mixdown
|
||||
Chip->resamp.resample(Chip->out_buf_linear, pSoundBuf, samples, Chip->volume, Chip->output_dir);
|
||||
// resample to host rate
|
||||
Chip->resamp.resample(Chip->out_buf_linear, Chip->out_buf_linear_resampled, samples, Chip->volume, Chip->output_dir);
|
||||
|
||||
// filter and mix into pSoundBuf
|
||||
for (INT32 i = 0; i < samples; i++) {
|
||||
INT32 l = Chip->biquadL.filter(Chip->out_buf_linear_resampled[i*2 + 0]);
|
||||
INT32 r = Chip->biquadR.filter(Chip->out_buf_linear_resampled[i*2 + 1]);
|
||||
pSoundBuf[i*2 + 0] = BURN_SND_CLIP(pSoundBuf[i*2 + 0] + l);
|
||||
pSoundBuf[i*2 + 1] = BURN_SND_CLIP(pSoundBuf[i*2 + 0] + r);
|
||||
}
|
||||
|
||||
Chip->sample_counts = 0; // ready for next frame!
|
||||
}
|
||||
@ -536,22 +545,25 @@ void UPD7759Init(INT32 chip, INT32 clock, UINT8* pSoundData)
|
||||
SlaveMode = 0;
|
||||
|
||||
Chip->ChipNum = chip;
|
||||
Chip->resamp.init(clock / 4, nBurnSoundRate, 1);
|
||||
// init resampler
|
||||
Chip->resamp.init(clock / 4, nBurnSoundRate, 0);
|
||||
|
||||
// Init 2khz lp filter coefficient @ (clock / 4)hz
|
||||
double omeg = exp(-2.0 * 3.1415926 * 2000 / (clock / 4));
|
||||
Chip->filt_sa = (INT32)(omeg * (double)(1 << 12));
|
||||
Chip->filt_sb = (1 << 12) - Chip->filt_sa;
|
||||
// init filter (basically passthru w/these settings)
|
||||
Chip->biquadL.init(FILT_LOWPASS, nBurnSoundRate, 15000, 0.554, 0.0);
|
||||
Chip->biquadR.init(FILT_LOWPASS, nBurnSoundRate, 15000, 0.554, 0.0);
|
||||
|
||||
Chip->step = (INT32)(4 * FRAC_ONE);
|
||||
Chip->state = STATE_IDLE;
|
||||
Chip->clock_period = 1.0 / (double)clock;
|
||||
|
||||
// our 16bit (INT16) output buffer is 2 frames in length @ 640,000 kHz
|
||||
// out_buf - circular buffer @ clock/4 rate
|
||||
// out_buf_linear - linearized right before resampling and rendering
|
||||
// out_buf_linear_resampled - resampled and ready to be filtered
|
||||
Chip->out_buf_size = (clock / 4) * 100 / (nBurnFPS / 2); // word-size (byte size = *2)
|
||||
Chip->out_buf = (INT16*)BurnMalloc(Chip->out_buf_size * sizeof(INT16));
|
||||
Chip->out_buf_linear = (INT16*)BurnMalloc(Chip->out_buf_size * sizeof(INT16));
|
||||
|
||||
Chip->out_buf_linear_resampled = (INT16*)BurnMalloc(Chip->out_buf_size * sizeof(INT16));
|
||||
Chip->out_pos = 0;
|
||||
|
||||
if (pSoundData) {
|
||||
@ -572,6 +584,19 @@ void UPD7759Init(INT32 chip, INT32 clock, UINT8* pSoundData)
|
||||
UPD7759Reset();
|
||||
}
|
||||
|
||||
void UPD7759SetFilter(INT32 chip, INT32 nCutOff)
|
||||
{
|
||||
#if defined FBNEO_DEBUG
|
||||
if (!DebugSnd_UPD7759Initted) bprintf(PRINT_ERROR, _T("UPD7759SetFilter called without init\n"));
|
||||
if (chip > nNumChips) bprintf(PRINT_ERROR, _T("UPD7759SetFilter called with invalid chip %i\n"), chip);
|
||||
#endif
|
||||
|
||||
Chip = Chips[chip];
|
||||
|
||||
Chip->biquadL.init(FILT_LOWPASS, nBurnSoundRate, nCutOff, 0.554, 0.0);
|
||||
Chip->biquadR.init(FILT_LOWPASS, nBurnSoundRate, nCutOff, 0.554, 0.0);
|
||||
}
|
||||
|
||||
void UPD7759SetRoute(INT32 chip, double nVolume, INT32 nRouteDir)
|
||||
{
|
||||
#if defined FBNEO_DEBUG
|
||||
@ -730,8 +755,11 @@ void UPD7759Exit()
|
||||
{
|
||||
Chip = Chips[i];
|
||||
if (Chip) {
|
||||
Chip->biquadL.exit();
|
||||
Chip->biquadR.exit();
|
||||
BurnFree(Chip->out_buf);
|
||||
BurnFree(Chip->out_buf_linear);
|
||||
BurnFree(Chip->out_buf_linear_resampled);
|
||||
BurnFree(Chips[i]);
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ void UPD7759Render(INT32 chip, INT16 *pSoundBuf, INT32 samples); // render singl
|
||||
void UPD7759Reset();
|
||||
void UPD7759Init(INT32 chip, INT32 clock, UINT8* pSoundData);
|
||||
void UPD7759SetRoute(INT32 chip, double nVolume, INT32 nRouteDir);
|
||||
void UPD7759SetFilter(INT32 chip, INT32 nCutOff);
|
||||
void UPD7759SetDrqCallback(INT32 chip, drqcallback Callback);
|
||||
void UPD7759SetSyncCallback(INT32 chip, INT32 (*pCPUCyclesCB)(), INT32 nCPUMhz);
|
||||
INT32 UPD7759BusyRead(INT32 chip);
|
||||
|
Loading…
Reference in New Issue
Block a user