diff --git a/Makefile.wii b/Makefile.wii index 9290e11..3619bc9 100644 --- a/Makefile.wii +++ b/Makefile.wii @@ -34,7 +34,7 @@ LDFLAGS = -g $(MACHDEP) -Wl,-Map,$(notdir $@).map #--------------------------------------------------------------------------------- # any extra libraries we wish to link with the project #--------------------------------------------------------------------------------- -LIBS := -lfat -lwiiuse -lbte -logc -lm -lz +LIBS := -lfat -lwiiuse -lbte -logc -lm -lz -lsamplerate #--------------------------------------------------------------------------------- # list of directories containing libraries, this must be the top level containing diff --git a/source/sound/fm.c b/source/sound/fm.c index 33601ae..bb1cd68 100644 --- a/source/sound/fm.c +++ b/source/sound/fm.c @@ -120,7 +120,7 @@ /* globals */ #define FREQ_SH 16 /* 16.16 fixed point (frequency calculations) */ -#define EG_SH 16 /* 16.16 fixed point (envelope generator timing) */ +#define EG_SH 16 /* 16.16 fixed point (envelope generator timing) */ #define LFO_SH 24 /* 8.24 fixed point (LFO calculations) */ #define TIMER_SH 16 /* 16.16 fixed point (timers calculations) */ @@ -146,8 +146,8 @@ #define TL_RES_LEN (256) /* 8 bits addressing (real chip) */ -#define MAXOUT (+16383) -#define MINOUT (-16384) +#define MAXOUT (+32767) +#define MINOUT (-32768) /* TL_TAB_LEN is calculated as: @@ -550,8 +550,8 @@ typedef struct /* local time tables */ INT32 dt_tab[8][32];/* DeTune table */ - UINT32 Inter_Cnt; // Interpolation Counter - UINT32 Inter_Step; // Interpolation Step + // UINT32 Inter_Cnt; // Interpolation Counter +// UINT32 Inter_Step; // Interpolation Step } FM_ST; @@ -1456,25 +1456,30 @@ static void OPNSetPres(int pres) { int i; - /* frequency base */ - ym2612.OPN.ST.freqbase = ((double) ym2612.OPN.ST.clock / (double) ym2612.OPN.ST.rate) / ((double) pres); - - /* timer increment in usecs (timers are incremented after each updated samples) */ - ym2612.OPN.ST.TimerBase = 1000000.0 / (double)ym2612.OPN.ST.rate; - if (config.hq_fm) { - ym2612.OPN.ST.Inter_Step = (unsigned int) ((1.0 / ym2612.OPN.ST.freqbase) * (double) (0x4000)); - ym2612.OPN.ST.Inter_Cnt = 0; - ym2612.OPN.ST.freqbase = 1.0; - } - else - { - ym2612.OPN.ST.Inter_Step = 0x4000; - ym2612.OPN.ST.Inter_Cnt = 0; - } + //ym2612.OPN.ST.Inter_Step = (unsigned int) ((1.0 / ym2612.OPN.ST.freqbase) * (double) (0x4000)); + //ym2612.OPN.ST.Inter_Cnt = 0; + //ym2612.OPN.ST.freqbase = 1.0; + ym2612.OPN.ST.rate = ym2612.OPN.ST.clock / pres; - ym2612.OPN.eg_timer_add = (UINT32)((1<>0) & ym2612.OPN.pan[0]); rt = ((out_fm[0]>>0) & ym2612.OPN.pan[1]); @@ -1904,7 +1911,7 @@ void YM2612UpdateOne(int **buffer, int length) INTERNAL_TIMER_B(length); - ym2612.OPN.ST.Inter_Cnt = int_cnt; + //ym2612.OPN.ST.Inter_Cnt = int_cnt; } diff --git a/source/sound/sound.c b/source/sound/sound.c index a70a680..822a351 100644 --- a/source/sound/sound.c +++ b/source/sound/sound.c @@ -22,6 +22,7 @@ ****************************************************************************************/ #include "shared.h" +#include "samplerate.h" /* generic functions */ int (*_YM2612_Write)(unsigned char adr, unsigned char data); @@ -29,19 +30,32 @@ int (*_YM2612_Read)(void); void (*_YM2612_Update)(int **buf, int length); int (*_YM2612_Reset)(void); -static double m68cycles_per_sample; -static double z80cycles_per_sample; +static double m68cycles_per_sample[2]; +static double z80cycles_per_sample[2]; + +static float fm_buffer_48kHz[960*2]; +static float fm_buffer_53kHz[1060*2]; + +static int fm_buffer[2][1060]; + +static SRC_DATA data; /* YM2612 data */ -int fm_reg[2][0x100]; /* Register arrays (2x256) */ +int fm_reg[2][0x100]; /* Register arrays (2x256) */ double fm_timera_tab[0x400]; /* Precalculated timer A values (in usecs) */ double fm_timerb_tab[0x100]; /* Precalculated timer B values (in usecs) */ /* return the number of samples that should have been rendered so far */ -static inline uint32 sound_sample_cnt(uint8 is_z80) +static inline uint32 fm_sample_cnt(uint8 is_z80) { - if (is_z80) return (uint32) ((double)(count_z80 + current_z80 - z80_ICount) / z80cycles_per_sample); - else return (uint32) ((double) count_m68k / m68cycles_per_sample); + if (is_z80) return (uint32) ((double)(count_z80 + current_z80 - z80_ICount) / z80cycles_per_sample[0]); + else return (uint32) ((double) count_m68k / m68cycles_per_sample[0]); +} + +static inline uint32 psg_sample_cnt(uint8 is_z80) +{ + if (is_z80) return (uint32) ((double)(count_z80 + current_z80 - z80_ICount) / z80cycles_per_sample[1]); + else return (uint32) ((double) count_m68k / m68cycles_per_sample[1]); } /* update FM samples */ @@ -49,10 +63,19 @@ static inline void fm_update() { if(snd.fm.curStage - snd.fm.lastStage > 1) { - //error("%d(%d): FM update (%d) %d from %d samples (%08x)\n", v_counter, count_z80 + current_z80 - z80_ICount, cpu, snd.fm.curStage , snd.fm.lastStage, m68k_get_reg (NULL, M68K_REG_PC)); - int *tempBuffer[2]; - tempBuffer[0] = snd.fm.buffer[0] + snd.fm.lastStage; - tempBuffer[1] = snd.fm.buffer[1] + snd.fm.lastStage; + int *tempBuffer[2]; + + if (config.hq_fm && !config.fm_core) + { + tempBuffer[0] = fm_buffer[0] + snd.fm.lastStage; + tempBuffer[1] = fm_buffer[1] + snd.fm.lastStage; + } + else + { + tempBuffer[0] = snd.fm.buffer[0] + snd.fm.lastStage; + tempBuffer[1] = snd.fm.buffer[1] + snd.fm.lastStage; + } + _YM2612_Update(tempBuffer, snd.fm.curStage - snd.fm.lastStage); snd.fm.lastStage = snd.fm.curStage; } @@ -83,9 +106,28 @@ void sound_init(int rate) /* Formula is "time(us) = 16 * (256 - B) * 144 * 1000000 / clock" */ for(i = 0; i < 256; i += 1) fm_timerb_tab[i] = ((double)((256 - i) * 16 * 144) * 1000000.0 / vclk); - /* Cycle-Accurate sample generation */ - m68cycles_per_sample = ((double)m68cycles_per_line * (double)lines_per_frame) / (double) (rate / vdp_rate); - z80cycles_per_sample = ((double)z80cycles_per_line * (double)lines_per_frame) / (double) (rate / vdp_rate); + /* cycle-accurate FM samples */ + if (config.hq_fm && !config.fm_core) + { + m68cycles_per_sample[0] = 144; + z80cycles_per_sample[0] = (144 * 7) / 15; + + /* set samplerate converter data */ + data.data_in = fm_buffer_53kHz; + data.data_out = fm_buffer_48kHz; + data.input_frames = vdp_pal ? 1060 : 888; + data.output_frames = vdp_pal ? 960 : 800; + data.src_ratio = 48000.0 / (vdp_pal ? 52781.0 : 53267.0); + } + else + { + m68cycles_per_sample[0] = ((double)m68cycles_per_line * (double)lines_per_frame) / (double) (rate / vdp_rate); + z80cycles_per_sample[0] = ((double)z80cycles_per_line * (double)lines_per_frame) / (double) (rate / vdp_rate); + } + + /* cycle-accurate PSG samples */ + m68cycles_per_sample[1] = ((double)m68cycles_per_line * (double)lines_per_frame) / (double) (rate / vdp_rate); + z80cycles_per_sample[1] = ((double)z80cycles_per_line * (double)lines_per_frame) / (double) (rate / vdp_rate); /* initialize sound chips */ SN76489_Init(0, (int)zclk, rate); @@ -119,7 +161,59 @@ void sound_update(void) fm_update(); psg_update(); - /* reset samples count */ + /* Resampling */ + if (config.hq_fm && !config.fm_core) + { + double scaled_value ; + int len = vdp_pal ? 1060 : 888; + + /* this is basically libsamplerate "src_int_to_float_array" function, adapted to interlace samples */ + while (len) + { + len -- ; + fm_buffer_53kHz [len*2] = (float) (fm_buffer[0] [len] / (8.0 * 0x10000000)) ; + fm_buffer_53kHz [len*2 + 1] = (float) (fm_buffer[1] [len] / (8.0 * 0x10000000)) ; + } + + /* samplerate conversion */ + src_simple (&data, SRC_SINC_FASTEST, 2); + + /* this is basically libsamplerate "src_float_to_int_array" function, adapted to interlace samples */ + len = vdp_pal ? 960 : 800; + while (len) + { + len -- ; + scaled_value = fm_buffer_48kHz [len*2] * (8.0 * 0x10000000); + if (scaled_value >= (1.0 * 0x7FFFFFFF)) + { + snd.fm.buffer[0][len] = 0x7fffffff; + } + else if (scaled_value <= (-8.0 * 0x10000000)) + { + snd.fm.buffer[0][len] = -1 - 0x7fffffff; + } + else + { + snd.fm.buffer[0][len] = (long)scaled_value; + } + + scaled_value = fm_buffer_48kHz [len*2+1] * (8.0 * 0x10000000); + if (scaled_value >= (1.0 * 0x7FFFFFFF)) + { + snd.fm.buffer[1][len] = 0x7fffffff; + } + else if (scaled_value <= (-8.0 * 0x10000000)) + { + snd.fm.buffer[1][len] = -1 - 0x7fffffff; + } + else + { + snd.fm.buffer[1][len] = (long)scaled_value; + } + } + } + + /* reset samples count */ snd.fm.curStage = 0; snd.fm.lastStage = 0; snd.psg.curStage = 0; @@ -147,7 +241,7 @@ void fm_restore(void) /* write FM chip */ void fm_write(unsigned int cpu, unsigned int address, unsigned int data) { - snd.fm.curStage = sound_sample_cnt(cpu); + snd.fm.curStage = fm_sample_cnt(cpu); fm_update(); _YM2612_Write(address & 3, data); } @@ -155,7 +249,7 @@ void fm_write(unsigned int cpu, unsigned int address, unsigned int data) /* read FM status */ unsigned int fm_read(unsigned int cpu, unsigned int address) { - snd.fm.curStage = sound_sample_cnt(cpu); + snd.fm.curStage = fm_sample_cnt(cpu); fm_update(); return (_YM2612_Read() & 0xff); } @@ -164,7 +258,7 @@ unsigned int fm_read(unsigned int cpu, unsigned int address) /* PSG write */ void psg_write(unsigned int cpu, unsigned int data) { - snd.psg.curStage = sound_sample_cnt(cpu); + snd.psg.curStage = psg_sample_cnt(cpu); psg_update(); SN76489_Write(0, data); } diff --git a/source/sound/ym2612.c b/source/sound/ym2612.c index d203d5d..c7a87dd 100644 --- a/source/sound/ym2612.c +++ b/source/sound/ym2612.c @@ -280,15 +280,15 @@ INLINE void CALC_FINC_SL(slot_ *SL, int finc, int kc) SL->Finc = (finc + SL->DT[kc]) * SL->MUL; - /* YM2612 Detune Bug (discovered by Nemesis) */ - if (SL->Finc < 0) - { - /* Phase overflow (best result with BLOCK = 5) */ - finc = (int)((double)FINC_TAB[0x7FF] / YM2612.Frequence) >> 2; - SL->Finc = (finc + SL->DT[kc]) * SL->MUL; - } + /* YM2612 Detune Bug (discovered by Nemesis) */ + if (SL->Finc < 0) + { + /* Phase overflow (best result with BLOCK = 5) */ + finc = (int)((double)FINC_TAB[0x7FF] / YM2612.Frequence) >> 2; + SL->Finc = (finc + SL->DT[kc]) * SL->MUL; + } - ksr = kc >> SL->KSR_S; // keycode atténuation + ksr = kc >> SL->KSR_S; // keycode atténuation #if YM_DEBUG_LEVEL > 1 fprintf(debug_file, "FINC = %d SL->Finc = %d\n", finc, SL->Finc); @@ -575,7 +575,7 @@ int CHANNEL_SET(int Adr, unsigned char data) CH->FOCT[0] = (data & 0x38) >> 3; CH->KC[0] = (CH->FOCT[0] << 2) | FKEY_TAB[CH->FNUM[0] >> 7]; - //CH->SLOT[0].Finc = -1; + CH->SLOT[0].Finc = -1; #if YM_DEBUG_LEVEL > 1 fprintf(debug_file, "CHANNEL[%d] part2 FNUM = %d FOCT = %d KC = %d\n", num, CH->FNUM[0], CH->FOCT[0], CH->KC[0]); @@ -611,7 +611,7 @@ int CHANNEL_SET(int Adr, unsigned char data) YM2612.CHANNEL[2].FOCT[num] = (data & 0x38) >> 3; YM2612.CHANNEL[2].KC[num] = (YM2612.CHANNEL[2].FOCT[num] << 2) | FKEY_TAB[YM2612.CHANNEL[2].FNUM[num] >> 7]; - //YM2612.CHANNEL[2].SLOT[0].Finc = -1; + YM2612.CHANNEL[2].SLOT[0].Finc = -1; #if YM_DEBUG_LEVEL > 1 fprintf(debug_file, "CHANNEL[2] part2 FNUM[%d] = %d FOCT[%d] = %d KC[%d] = %d\n", num, YM2612.CHANNEL[2].FNUM[num], num, YM2612.CHANNEL[2].FOCT[num], num, YM2612.CHANNEL[2].KC[num]);