diff --git a/src/include/86box/filters.h b/src/include/86box/filters.h index dfe19c654..16c9c7221 100644 --- a/src/include/86box/filters.h +++ b/src/include/86box/filters.h @@ -5,7 +5,7 @@ /* fc=150Hz */ static inline float -adgold_highpass_iir(int i, float NewSample) +adgold_highpass_iir(int c, int i, float NewSample) { float ACoef[NCoef + 1] = { 0.98657437157334349000, @@ -19,28 +19,28 @@ adgold_highpass_iir(int i, float NewSample) 0.97261396931534050000 }; - static float y[2][NCoef + 1]; /* output samples */ - static float x[2][NCoef + 1]; /* input samples */ + static float y[2][2][NCoef + 1]; /* output samples */ + static float x[2][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]; + x[c][i][n] = x[c][i][n - 1]; + y[c][i][n] = y[c][i][n - 1]; } /* Calculate the new output */ - x[i][0] = NewSample; - y[i][0] = ACoef[0] * x[i][0]; + x[c][i][0] = NewSample; + y[c][i][0] = ACoef[0] * x[c][i][0]; for (n = 1; n <= NCoef; n++) - y[i][0] += ACoef[n] * x[i][n] - BCoef[n] * y[i][n]; + y[c][i][0] += ACoef[n] * x[c][i][n] - BCoef[n] * y[c][i][n]; - return y[i][0]; + return y[c][i][0]; } /* fc=150Hz */ static inline float -adgold_lowpass_iir(int i, float NewSample) +adgold_lowpass_iir(int c, int i, float NewSample) { float ACoef[NCoef + 1] = { 0.00009159473951071446, @@ -54,23 +54,23 @@ adgold_lowpass_iir(int i, float NewSample) 0.97261396931306277000 }; - static float y[2][NCoef + 1]; /* output samples */ - static float x[2][NCoef + 1]; /* input samples */ + static float y[2][2][NCoef + 1]; /* output samples */ + static float x[2][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]; + x[c][i][n] = x[c][i][n - 1]; + y[c][i][n] = y[c][i][n - 1]; } /* Calculate the new output */ - x[i][0] = NewSample; - y[i][0] = ACoef[0] * x[i][0]; + x[c][i][0] = NewSample; + y[c][i][0] = ACoef[0] * x[c][i][0]; for (n = 1; n <= NCoef; n++) - y[i][0] += ACoef[n] * x[i][n] - BCoef[n] * y[i][n]; + y[c][i][0] += ACoef[n] * x[c][i][n] - BCoef[n] * y[c][i][n]; - return y[i][0]; + return y[c][i][0]; } /* fc=56Hz */ @@ -197,8 +197,8 @@ low_iir(int c, int i, double NewSample) 0.93726236021404663000 }; - static double y[3][2][NCoef + 1]; /* output samples */ - static double x[3][2][NCoef + 1]; /* input samples */ + static double y[4][2][NCoef + 1]; /* output samples */ + static double x[4][2][NCoef + 1]; /* input samples */ int n; /* shift the old samples */ @@ -232,8 +232,8 @@ low_cut_iir(int c, int i, double NewSample) 0.93726236021916731000 }; - static double y[3][2][NCoef + 1]; /* output samples */ - static double x[3][2][NCoef + 1]; /* input samples */ + static double y[4][2][NCoef + 1]; /* output samples */ + static double x[4][2][NCoef + 1]; /* input samples */ int n; /* shift the old samples */ @@ -266,8 +266,8 @@ high_iir(int c, int i, double NewSample) -1.36640781670578510000, 0.52352474706139873000 }; - static double y[3][2][NCoef + 1]; /* output samples */ - static double x[3][2][NCoef + 1]; /* input samples */ + static double y[4][2][NCoef + 1]; /* output samples */ + static double x[4][2][NCoef + 1]; /* input samples */ int n; /* shift the old samples */ @@ -300,8 +300,8 @@ high_cut_iir(int c, int i, double NewSample) -1.36640781666419950000, 0.52352474703279628000 }; - static double y[3][2][NCoef + 1]; /* output samples */ - static double x[3][2][NCoef + 1]; /* input samples */ + static double y[4][2][NCoef + 1]; /* output samples */ + static double x[4][2][NCoef + 1]; /* input samples */ int n; /* shift the old samples */ @@ -334,8 +334,8 @@ deemph_iir(int i, double NewSample) -1.05429146278569141337, 0.26412280202756849290 }; - static double y[3][NCoef + 1]; /* output samples */ - static double x[3][NCoef + 1]; /* input samples */ + static double y[4][NCoef + 1]; /* output samples */ + static double x[4][NCoef + 1]; /* input samples */ int n; /* shift the old samples */ @@ -372,8 +372,8 @@ sb_iir(int c, int i, double NewSample) 0.55326988968868285000 }; - static double y[3][2][NCoef + 1]; /* output samples */ - static double x[3][2][NCoef + 1]; /* input samples */ + static double y[4][2][NCoef + 1]; /* output samples */ + static double x[4][2][NCoef + 1]; /* input samples */ int n; /* shift the old samples */ @@ -395,13 +395,13 @@ sb_iir(int c, int i, double NewSample) #define NCoef 1 #define SB16_NCoef 51 -extern double low_fir_sb16_coef[3][SB16_NCoef]; +extern double low_fir_sb16_coef[4][SB16_NCoef]; static inline double low_fir_sb16(int c, int i, double NewSample) { - static double x[3][2][SB16_NCoef + 1]; // input samples - static int pos[3] = { 0, 0 }; + static double x[4][2][SB16_NCoef + 1]; // input samples + static int pos[4] = { 0, 0, 0, 0 }; double out = 0.0; int n; diff --git a/src/include/86box/snd_sb.h b/src/include/86box/snd_sb.h index f433dd107..621cb4ade 100644 --- a/src/include/86box/snd_sb.h +++ b/src/include/86box/snd_sb.h @@ -143,7 +143,6 @@ typedef struct sb_t { emu8k_t emu8k; void *gameport; - int pos; int pnp; uint8_t pos_regs[8]; @@ -165,6 +164,7 @@ extern uint8_t sb_ct1745_mixer_read(uint16_t addr, void *priv); extern void sb_ct1745_mixer_reset(sb_t *sb); extern void sb_get_buffer_sbpro(int32_t *buffer, int len, void *priv); +extern void sb_get_music_buffer_sbpro(int32_t *buffer, int len, void *priv); extern void sbpro_filter_cd_audio(int channel, double *buffer, void *priv); extern void sb16_awe32_filter_cd_audio(int channel, double *buffer, void *priv); extern void sb_close(void *priv); diff --git a/src/include/86box/snd_sb_dsp.h b/src/include/86box/snd_sb_dsp.h index ecabe426d..3e0e40e80 100644 --- a/src/include/86box/snd_sb_dsp.h +++ b/src/include/86box/snd_sb_dsp.h @@ -97,6 +97,8 @@ typedef struct sb_dsp_t { int sb_irqm16; int sb_irqm401; + uint8_t sb_has_real_opl; + uint8_t sb_asp_regs[256]; uint8_t sb_asp_mode; @@ -158,6 +160,8 @@ extern void sb_dsp_speed_changed(sb_dsp_t *dsp); extern void sb_dsp_poll(sb_dsp_t *dsp, int16_t *l, int16_t *r); +extern void sb_dsp_set_real_opl(sb_dsp_t *dsp, uint8_t has_real_opl); + extern void sb_dsp_set_stereo(sb_dsp_t *dsp, int stereo); extern void sb_dsp_update(sb_dsp_t *dsp); diff --git a/src/include/86box/sound.h b/src/include/86box/sound.h index 60628ece8..b8f9be5b2 100644 --- a/src/include/86box/sound.h +++ b/src/include/86box/sound.h @@ -33,6 +33,9 @@ extern int sound_gain; #define SOUND_FREQ FREQ_48000 #define SOUNDBUFLEN (SOUND_FREQ / 50) +#define MUSIC_FREQ FREQ_49716 +#define MUSICBUFLEN (MUSIC_FREQ / 36) + #define CD_FREQ FREQ_44100 #define CD_BUFLEN (CD_FREQ / 10) @@ -47,12 +50,18 @@ extern int speakval; extern int speakon; extern int sound_pos_global; +extern int music_pos_global; + extern int sound_card_current[SOUND_CARD_MAX]; extern void sound_add_handler(void (*get_buffer)(int32_t *buffer, int len, void *priv), void *priv); +extern void music_add_handler(void (*get_buffer)(int32_t *buffer, + int len, void *priv), + void *priv); + extern void sound_set_cd_audio_filter(void (*filter)(int channel, double *buffer, void *priv), void *priv); @@ -86,6 +95,7 @@ extern void sound_cd_thread_reset(void); extern void closeal(void); extern void inital(void); extern void givealbuffer(void *buf); +extern void givealbuffer_music(void *buf); extern void givealbuffer_cd(void *buf); #define sb_vibra16c_onboard_relocate_base sb_vibra16s_onboard_relocate_base diff --git a/src/sound/openal.c b/src/sound/openal.c index 76656c66e..98f87855e 100644 --- a/src/sound/openal.c +++ b/src/sound/openal.c @@ -38,10 +38,11 @@ #define FREQ SOUND_FREQ #define BUFLEN SOUNDBUFLEN -ALuint buffers[4]; /* front and back buffers */ -ALuint buffers_cd[4]; /* front and back buffers */ -ALuint buffers_midi[4]; /* front and back buffers */ -static ALuint source[3]; /* audio source */ +ALuint buffers[4]; /* front and back buffers */ +ALuint buffers_music[4]; /* front and back buffers */ +ALuint buffers_cd[4]; /* front and back buffers */ +ALuint buffers_midi[4]; /* front and back buffers */ +static ALuint source[4]; /* audio source */ static int midi_freq = 44100; static int midi_buf_size = 4410; @@ -99,9 +100,10 @@ closeal(void) alSourceStopv(sources, source); alDeleteSources(sources, source); - if (sources == 3) + if (sources == 4) alDeleteBuffers(4, buffers_midi); alDeleteBuffers(4, buffers_cd); + alDeleteBuffers(4, buffers_music); alDeleteBuffers(4, buffers); alutExit(); @@ -132,16 +134,18 @@ inital(void) if (strcmp(mdn, "none") && strcmp(mdn, SYSTEM_MIDI_INTERNAL_NAME)) init_midi = 1; /* If the device is neither none, nor system MIDI, initialize the MIDI buffer and source, otherwise, do not. */ - sources = 2 + !!init_midi; + sources = 3 + !!init_midi; if (sound_is_float) { - buf = (float *) calloc((BUFLEN << 1), sizeof(float)); - cd_buf = (float *) calloc((CD_BUFLEN << 1), sizeof(float)); + buf = (float *) calloc((BUFLEN << 1), sizeof(float)); + music_buf = (float *) calloc((MUSIC_BUFLEN << 1), sizeof(float)); + cd_buf = (float *) calloc((CD_BUFLEN << 1), sizeof(float)); if (init_midi) midi_buf = (float *) calloc(midi_buf_size, sizeof(float)); } else { - buf_int16 = (int16_t *) calloc((BUFLEN << 1), sizeof(int16_t)); - cd_buf_int16 = (int16_t *) calloc((CD_BUFLEN << 1), sizeof(int16_t)); + buf_int16 = (int16_t *) calloc((BUFLEN << 1), sizeof(int16_t)); + music_buf_int16 = (int16_t *) calloc((MUSIC_BUFLEN << 1), sizeof(int16_t)); + cd_buf_int16 = (int16_t *) calloc((CD_BUFLEN << 1), sizeof(int16_t)); if (init_midi) midi_buf_int16 = (int16_t *) calloc(midi_buf_size, sizeof(int16_t)); } @@ -189,11 +193,13 @@ inital(void) for (uint8_t c = 0; c < 4; c++) { if (sound_is_float) { alBufferData(buffers[c], AL_FORMAT_STEREO_FLOAT32, buf, BUFLEN * 2 * sizeof(float), FREQ); + alBufferData(buffers_music[c], AL_FORMAT_STEREO_FLOAT32, buf, MUSIC_BUFLEN * 2 * sizeof(float), MUSIC_FREQ); alBufferData(buffers_cd[c], AL_FORMAT_STEREO_FLOAT32, cd_buf, CD_BUFLEN * 2 * sizeof(float), CD_FREQ); if (init_midi) alBufferData(buffers_midi[c], AL_FORMAT_STEREO_FLOAT32, midi_buf, midi_buf_size * sizeof(float), midi_freq); } else { alBufferData(buffers[c], AL_FORMAT_STEREO16, buf_int16, BUFLEN * 2 * sizeof(int16_t), FREQ); + alBufferData(buffers_music[c], AL_FORMAT_STEREO16, buf_int16, MUSIC_BUFLEN * 2 * sizeof(int16_t), MUSIC_FREQ); alBufferData(buffers_cd[c], AL_FORMAT_STEREO16, cd_buf_int16, CD_BUFLEN * 2 * sizeof(int16_t), CD_FREQ); if (init_midi) alBufferData(buffers_midi[c], AL_FORMAT_STEREO16, midi_buf_int16, midi_buf_size * sizeof(int16_t), midi_freq); @@ -201,23 +207,27 @@ inital(void) } alSourceQueueBuffers(source[0], 4, buffers); - alSourceQueueBuffers(source[1], 4, buffers_cd); + alSourceQueueBuffers(source[1], 4, buffers_music); + alSourceQueueBuffers(source[2], 4, buffers_cd); if (init_midi) - alSourceQueueBuffers(source[2], 4, buffers_midi); + alSourceQueueBuffers(source[3], 4, buffers_midi); alSourcePlay(source[0]); alSourcePlay(source[1]); + alSourcePlay(source[2]); if (init_midi) - alSourcePlay(source[2]); + alSourcePlay(source[3]); if (sound_is_float) { if (init_midi) free(midi_buf); free(cd_buf); + free(music_buf); free(buf); } else { if (init_midi) free(midi_buf_int16); free(cd_buf_int16); + free(music_buf_int16); free(buf_int16); } @@ -263,14 +273,20 @@ givealbuffer(void *buf) givealbuffer_common(buf, 0, BUFLEN << 1, FREQ); } +void +givealbuffer_music(void *buf) +{ + givealbuffer_common(buf, 1, MUSIC_BUFLEN << 1, MUSIC_FREQ); +} + void givealbuffer_cd(void *buf) { - givealbuffer_common(buf, 1, CD_BUFLEN << 1, CD_FREQ); + givealbuffer_common(buf, 2, CD_BUFLEN << 1, CD_FREQ); } void givealbuffer_midi(void *buf, uint32_t size) { - givealbuffer_common(buf, 2, size, midi_freq); + givealbuffer_common(buf, 3, size, midi_freq); } diff --git a/src/sound/snd_adlib.c b/src/sound/snd_adlib.c index 5d0d7c7aa..f5eae9b93 100644 --- a/src/sound/snd_adlib.c +++ b/src/sound/snd_adlib.c @@ -112,7 +112,7 @@ adlib_init(UNUSED(const device_t *info)) adlib->opl.read, NULL, NULL, adlib->opl.write, NULL, NULL, adlib->opl.priv); - sound_add_handler(adlib_get_buffer, adlib); + music_add_handler(adlib_get_buffer, adlib); return adlib; } diff --git a/src/sound/snd_adlibgold.c b/src/sound/snd_adlibgold.c index 71cbbcaa6..488dcb8a6 100644 --- a/src/sound/snd_adlibgold.c +++ b/src/sound/snd_adlibgold.c @@ -788,13 +788,10 @@ adgold_get_buffer(int32_t *buffer, int len, void *priv) int c; - const int32_t *opl_buf = adgold->opl.update(adgold->opl.priv); adgold_update(adgold); for (c = 0; c < len * 2; c += 2) { - adgold_buffer[c] = ((opl_buf[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] = ((opl_buf[c + 1] * adgold->fm_vol_r) >> 7) / 2; adgold_buffer[c + 1] += ((adgold->mma_buffer[1][c >> 1] * adgold->samp_vol_r) >> 7) / 4; } @@ -857,8 +854,8 @@ adgold_get_buffer(int32_t *buffer, int len, void *priv) /*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); + lowpass = adgold_lowpass_iir(0, 0, temp); + highpass = adgold_highpass_iir(0, 0, temp); if (adgold->bass > 6) temp += (lowpass * bass_attenuation[adgold->bass]) >> 14; else if (adgold->bass < 6) @@ -874,8 +871,124 @@ adgold_get_buffer(int32_t *buffer, int len, void *priv) 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); + lowpass = adgold_lowpass_iir(0, 1, temp); + highpass = adgold_highpass_iir(0, 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->pos = 0; + + free(adgold_buffer); +} + +static void +adgold_get_music_buffer(int32_t *buffer, int len, void *priv) +{ + adgold_t *adgold = (adgold_t *) priv; + int16_t *adgold_buffer = malloc(sizeof(int16_t) * len * 2); + if (adgold_buffer == NULL) + fatal("adgold_buffer = NULL"); + + int c; + + const int32_t *opl_buf = adgold->opl.update(adgold->opl.priv); + adgold_update(adgold); + + for (c = 0; c < len * 2; c += 2) { + adgold_buffer[c] = ((opl_buf[c] * adgold->fm_vol_l) >> 7) / 2; + adgold_buffer[c + 1] = ((opl_buf[c + 1] * adgold->fm_vol_r) >> 7) / 2; + } + + 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++) + 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; + + default: + 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; + + default: + break; + } + + for (c = 0; c < len * 2; c += 2) { + int32_t temp; + int32_t lowpass; + int32_t highpass; + + /*Output is deliberately halved to avoid clipping*/ + temp = ((int32_t) adgold_buffer[c] * adgold->vol_l) >> 17; + lowpass = adgold_lowpass_iir(1, 0, temp); + highpass = adgold_highpass_iir(1, 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, 1, temp); + highpass = adgold_highpass_iir(1, 1, temp); if (adgold->bass > 6) temp += (lowpass * bass_attenuation[adgold->bass]) >> 14; else if (adgold->bass < 6) @@ -892,7 +1005,6 @@ adgold_get_buffer(int32_t *buffer, int len, void *priv) } adgold->opl.reset_buffer(adgold->opl.priv); - adgold->pos = 0; free(adgold_buffer); } @@ -1054,6 +1166,8 @@ adgold_init(UNUSED(const device_t *info)) timer_add(&adgold->adgold_mma_timer_count, adgold_timer_poll, adgold, 1); sound_add_handler(adgold_get_buffer, adgold); + music_add_handler(adgold_get_music_buffer, adgold); + sound_set_cd_audio_filter(adgold_filter_cd_audio, adgold); if (device_get_config_int("receive_input")) diff --git a/src/sound/snd_azt2316a.c b/src/sound/snd_azt2316a.c index 80d668599..28ab2b7ac 100644 --- a/src/sound/snd_azt2316a.c +++ b/src/sound/snd_azt2316a.c @@ -1237,6 +1237,7 @@ azt_init(const device_t *info) if (azt2316a->sb->opl_enabled) fm_driver_get(FM_YMF262, &azt2316a->sb->opl); + sb_dsp_set_real_opl(&azt2316a->sb->dsp, 1); sb_dsp_init(&azt2316a->sb->dsp, SBPRO2, azt2316a->type, azt2316a); sb_dsp_setaddr(&azt2316a->sb->dsp, azt2316a->cur_addr); sb_dsp_setirq(&azt2316a->sb->dsp, azt2316a->cur_irq); @@ -1253,6 +1254,8 @@ azt_init(const device_t *info) azt2316a_create_config_word(azt2316a); sound_add_handler(azt2316a_get_buffer, azt2316a); + if (azt2316a->sb->opl_enabled) + music_add_handler(sb_get_music_buffer_sbpro, azt2316a->sb); sound_set_cd_audio_filter(sbpro_filter_cd_audio, azt2316a->sb); if (azt2316a->cur_mpu401_enabled) { diff --git a/src/sound/snd_cs423x.c b/src/sound/snd_cs423x.c index fad1d76b9..90aa0b0dd 100644 --- a/src/sound/snd_cs423x.c +++ b/src/sound/snd_cs423x.c @@ -543,13 +543,31 @@ cs423x_ctxswitch_write(uint16_t addr, UNUSED(uint8_t val), void *priv) static void cs423x_get_buffer(int32_t *buffer, int len, void *priv) +{ + cs423x_t *dev = (cs423x_t *) priv; + + /* Output audio from the WSS codec, and also the OPL if we're in charge of it. */ + ad1848_update(&dev->ad1848); + + /* Don't output anything if the analog section is powered down. */ + if (!(dev->indirect_regs[2] & 0xa4)) { + for (int c = 0; c < len * 2; c += 2) { + buffer[c] += dev->ad1848.buffer[c] / 2; + buffer[c + 1] += dev->ad1848.buffer[c + 1] / 2; + } + } + + dev->ad1848.pos = 0; +} + +static void +cs423x_get_music_buffer(int32_t *buffer, int len, void *priv) { cs423x_t *dev = (cs423x_t *) priv; int opl_wss = dev->opl_wss; const int32_t *opl_buf = NULL; /* Output audio from the WSS codec, and also the OPL if we're in charge of it. */ - ad1848_update(&dev->ad1848); if (opl_wss) opl_buf = dev->sb->opl.update(dev->sb->opl.priv); @@ -560,13 +578,9 @@ cs423x_get_buffer(int32_t *buffer, int len, void *priv) buffer[c] += (opl_buf[c] * dev->ad1848.fm_vol_l) >> 16; buffer[c + 1] += (opl_buf[c + 1] * dev->ad1848.fm_vol_r) >> 16; } - - buffer[c] += dev->ad1848.buffer[c] / 2; - buffer[c + 1] += dev->ad1848.buffer[c + 1] / 2; } } - dev->ad1848.pos = 0; if (opl_wss) dev->sb->opl.reset_buffer(dev->sb->opl.priv); } @@ -846,6 +860,7 @@ cs423x_init(const device_t *info) /* Initialize RAM, registers and WSS codec. */ cs423x_reset(dev); sound_add_handler(cs423x_get_buffer, dev); + music_add_handler(cs423x_get_music_buffer, dev); /* Add Control/RAM backdoor handlers for CS4235. */ dev->ad1848.cram_priv = dev; diff --git a/src/sound/snd_opl_nuked.c b/src/sound/snd_opl_nuked.c index d8281ba1d..95b61638e 100644 --- a/src/sound/snd_opl_nuked.c +++ b/src/sound/snd_opl_nuked.c @@ -55,7 +55,8 @@ #define WRBUF_DELAY 1 #define RSM_FRAC 10 -#define OPL_FREQ FREQ_48000 +// #define OPL_FREQ FREQ_48000 +#define OPL_FREQ FREQ_49716 // Channel types enum { @@ -189,7 +190,7 @@ typedef struct { pc_timer_t timers[2]; int pos; - int32_t buffer[SOUNDBUFLEN * 2]; + int32_t buffer[MUSICBUFLEN * 2]; } nuked_drv_t; enum { @@ -1381,11 +1382,20 @@ nuked_generate_resampled(nuked_t *dev, int32_t *bufp) dev->samplecnt += 1 << RSM_FRAC; } +void +nuked_generate_raw(nuked_t *dev, int32_t *bufp) +{ + nuked_generate(dev, dev->samples); + + bufp[0] = (int32_t) dev->samples[0]; + bufp[1] = (int32_t) dev->samples[1]; +} + void nuked_generate_stream(nuked_t *dev, int32_t *sndptr, uint32_t num) { for (uint32_t i = 0; i < num; i++) { - nuked_generate_resampled(dev, sndptr); + nuked_generate_raw(dev, sndptr); sndptr += 2; } } @@ -1533,14 +1543,14 @@ nuked_drv_update(void *priv) { nuked_drv_t *dev = (nuked_drv_t *) priv; - if (dev->pos >= sound_pos_global) + if (dev->pos >= music_pos_global) return dev->buffer; nuked_generate_stream(&dev->opl, &dev->buffer[dev->pos * 2], - sound_pos_global - dev->pos); + music_pos_global - dev->pos); - for (; dev->pos < sound_pos_global; dev->pos++) { + for (; dev->pos < music_pos_global; dev->pos++) { dev->buffer[dev->pos * 2] /= 2; dev->buffer[(dev->pos * 2) + 1] /= 2; } diff --git a/src/sound/snd_opl_ymfm.cpp b/src/sound/snd_opl_ymfm.cpp index 0f996f6bc..55e7f1984 100644 --- a/src/sound/snd_opl_ymfm.cpp +++ b/src/sound/snd_opl_ymfm.cpp @@ -51,10 +51,11 @@ enum { class YMFMChipBase { public: - YMFMChipBase(UNUSED(uint32_t clock), fm_type type, UNUSED(uint32_t samplerate)) + YMFMChipBase(UNUSED(uint32_t clock), fm_type type, uint32_t samplerate) : m_buf_pos(0) , m_flags(0) , m_type(type) + , m_samplerate(samplerate) { memset(m_buffer, 0, sizeof(m_buffer)); } @@ -79,10 +80,11 @@ public: virtual void set_clock(uint32_t clock) = 0; protected: - int32_t m_buffer[SOUNDBUFLEN * 2]; - int m_buf_pos; - int8_t m_flags; - fm_type m_type; + int32_t m_buffer[MUSICBUFLEN * 2]; + int m_buf_pos; + int8_t m_flags; + fm_type m_type; + uint32_t m_samplerate; }; template @@ -170,6 +172,11 @@ public: virtual void generate_resampled(int32_t *data, uint32_t num_samples) override { + if (m_samplerate == FREQ_49716) { + generate(data, num_samples); + return; + } + for (uint32_t i = 0; i < num_samples; i++) { while (m_samplecnt >= m_rateratio) { m_oldsamples[0] = m_samples[0]; @@ -206,14 +213,26 @@ public: virtual int32_t *update() override { - if (m_buf_pos >= sound_pos_global) - return m_buffer; + if (m_samplerate == FREQ_49716) { + if (m_buf_pos >= music_pos_global) + return m_buffer; - generate_resampled(&m_buffer[m_buf_pos * 2], sound_pos_global - m_buf_pos); + generate(&m_buffer[m_buf_pos * 2], music_pos_global - m_buf_pos); - for (; m_buf_pos < sound_pos_global; m_buf_pos++) { - m_buffer[m_buf_pos * 2] /= 2; - m_buffer[(m_buf_pos * 2) + 1] /= 2; + for (; m_buf_pos < music_pos_global; m_buf_pos++) { + m_buffer[m_buf_pos * 2] /= 2; + m_buffer[(m_buf_pos * 2) + 1] /= 2; + } + } else { + if (m_buf_pos >= sound_pos_global) + return m_buffer; + + generate_resampled(&m_buffer[m_buf_pos * 2], sound_pos_global - m_buf_pos); + + for (; m_buf_pos < sound_pos_global; m_buf_pos++) { + m_buffer[m_buf_pos * 2] /= 2; + m_buffer[(m_buf_pos * 2) + 1] /= 2; + } } return m_buffer; @@ -314,11 +333,11 @@ ymfm_drv_init(const device_t *info) switch (info->local) { default: case FM_YM3812: - fm = (YMFMChipBase *) new YMFMChip(3579545, FM_YM3812, OPL_FREQ); + fm = (YMFMChipBase *) new YMFMChip(3579545, FM_YM3812, FREQ_49716); break; case FM_YMF262: - fm = (YMFMChipBase *) new YMFMChip(14318181, FM_YMF262, OPL_FREQ); + fm = (YMFMChipBase *) new YMFMChip(14318181, FM_YMF262, FREQ_49716); break; case FM_YMF289B: diff --git a/src/sound/snd_optimc.c b/src/sound/snd_optimc.c index d7afca382..245d9590e 100644 --- a/src/sound/snd_optimc.c +++ b/src/sound/snd_optimc.c @@ -391,6 +391,9 @@ optimc_init(const device_t *info) optimc->sb = calloc(1, sizeof(sb_t)); optimc->sb->opl_enabled = 1; + optimc->fm_type = (info->local & OPTIMC_OPL4) ? FM_YMF278B : FM_YMF262; + + sb_dsp_set_real_opl(&optimc->sb->dsp, optimc->fm_type != FM_YMF278B); sb_dsp_init(&optimc->sb->dsp, SBPRO2, SB_SUBTYPE_DEFAULT, optimc); sb_dsp_setaddr(&optimc->sb->dsp, optimc->cur_addr); sb_dsp_setirq(&optimc->sb->dsp, optimc->cur_irq); @@ -400,7 +403,6 @@ optimc_init(const device_t *info) optimc->sb->opl_mixer = optimc; optimc->sb->opl_mix = optimc_filter_opl; - optimc->fm_type = (info->local & OPTIMC_OPL4) ? FM_YMF278B : FM_YMF262; fm_driver_get(optimc->fm_type, &optimc->sb->opl); io_sethandler(optimc->cur_addr + 0, 0x0004, optimc->sb->opl.read, NULL, NULL, optimc->sb->opl.write, NULL, NULL, optimc->sb->opl.priv); io_sethandler(optimc->cur_addr + 8, 0x0002, optimc->sb->opl.read, NULL, NULL, optimc->sb->opl.write, NULL, NULL, optimc->sb->opl.priv); @@ -411,6 +413,10 @@ optimc_init(const device_t *info) io_sethandler(optimc->cur_addr + 4, 0x0002, sb_ct1345_mixer_read, NULL, NULL, sb_ct1345_mixer_write, NULL, NULL, optimc->sb); sound_add_handler(optimc_get_buffer, optimc); + if (optimc->fm_type == FM_YMF278B) + sound_add_handler(sb_get_music_buffer_sbpro, optimc->sb); + else + music_add_handler(sb_get_music_buffer_sbpro, optimc->sb); sound_set_cd_audio_filter(sbpro_filter_cd_audio, optimc->sb); /* CD audio filter for the default context */ optimc->mpu = (mpu_t *) malloc(sizeof(mpu_t)); diff --git a/src/sound/snd_pas16.c b/src/sound/snd_pas16.c index 674acfcbb..3ce9b5c4c 100644 --- a/src/sound/snd_pas16.c +++ b/src/sound/snd_pas16.c @@ -728,20 +728,29 @@ pas16_get_buffer(int32_t *buffer, int len, void *priv) { pas16_t *pas16 = (pas16_t *) priv; - const int32_t *opl_buf = pas16->opl.update(pas16->opl.priv); sb_dsp_update(&pas16->dsp); pas16_update(pas16); for (int c = 0; c < len * 2; c++) { - buffer[c] += opl_buf[c]; buffer[c] += (int16_t) (sb_iir(0, c & 1, (double) pas16->dsp.buffer[c]) / 1.3) / 2; buffer[c] += (pas16->pcm_buffer[c & 1][c >> 1] / 2); } pas16->pos = 0; - pas16->opl.reset_buffer(pas16->opl.priv); pas16->dsp.pos = 0; } +void +pas16_get_music_buffer(int32_t *buffer, int len, void *priv) +{ + pas16_t *pas16 = (pas16_t *) priv; + + const int32_t *opl_buf = pas16->opl.update(pas16->opl.priv); + for (int c = 0; c < len * 2; c++) + buffer[c] += opl_buf[c]; + + pas16->opl.reset_buffer(pas16->opl.priv); +} + static void * pas16_init(UNUSED(const device_t *info)) { @@ -756,6 +765,7 @@ pas16_init(UNUSED(const device_t *info)) timer_add(&pas16->pit.timer[0], pas16_pcm_poll, pas16, 0); sound_add_handler(pas16_get_buffer, pas16); + music_add_handler(pas16_get_music_buffer, pas16); return pas16; } diff --git a/src/sound/snd_sb.c b/src/sound/snd_sb.c index 3aa152b8f..98b17e3f0 100644 --- a/src/sound/snd_sb.c +++ b/src/sound/snd_sb.c @@ -185,10 +185,6 @@ sb_get_buffer_sb2(int32_t *buffer, int len, void *priv) double out_mono = 0.0; double out_l = 0.0; double out_r = 0.0; - const int32_t *opl_buf = NULL; - - if (sb->opl_enabled) - opl_buf = sb->opl.update(sb->opl.priv); sb_dsp_update(&sb->dsp); @@ -200,17 +196,12 @@ sb_get_buffer_sb2(int32_t *buffer, int len, void *priv) out_l = 0.0; out_r = 0.0; - if (sb->opl_enabled) - out_mono = ((double) opl_buf[c]) * 0.7171630859375; - if (sb->cms_enabled) { out_l += sb->cms.buffer[c]; out_r += sb->cms.buffer[c + 1]; } - out_l += out_mono; - out_r += out_mono; - if (((sb->opl_enabled) || (sb->cms_enabled)) && sb->mixer_enabled) { + if (sb->cms_enabled && sb->mixer_enabled) { out_l *= mixer->fm; out_r *= mixer->fm; } @@ -234,17 +225,55 @@ sb_get_buffer_sb2(int32_t *buffer, int len, void *priv) buffer[c + 1] += (int32_t) out_r; } - sb->pos = 0; - - if (sb->opl_enabled) - sb->opl.reset_buffer(sb->opl.priv); - sb->dsp.pos = 0; if (sb->cms_enabled) sb->cms.pos = 0; } +static void +sb_get_music_buffer_sb2(int32_t *buffer, int len, void *priv) +{ + sb_t *sb = (sb_t *) priv; + const sb_ct1335_mixer_t *mixer = &sb->mixer_sb2; + double out_mono = 0.0; + double out_l = 0.0; + double out_r = 0.0; + const int32_t *opl_buf = NULL; + + if (!sb->opl_enabled) + return; + + opl_buf = sb->opl.update(sb->opl.priv); + + for (int c = 0; c < len * 2; c += 2) { + out_mono = 0.0; + out_l = 0.0; + out_r = 0.0; + + if (sb->opl_enabled) + out_mono = ((double) opl_buf[c]) * 0.7171630859375; + + out_l += out_mono; + out_r += out_mono; + + if (sb->mixer_enabled) { + out_l *= mixer->fm; + out_r *= mixer->fm; + } + + if (sb->mixer_enabled) { + out_l *= mixer->master; + out_r *= mixer->master; + } + + buffer[c] += (int32_t) out_l; + buffer[c + 1] += (int32_t) out_r; + } + + sb->opl.reset_buffer(sb->opl.priv); +} + static void sb2_filter_cd_audio(UNUSED(int channel), double *buffer, void *priv) { @@ -253,10 +282,10 @@ sb2_filter_cd_audio(UNUSED(int channel), double *buffer, void *priv) double c; if (sb->mixer_enabled) { - c = ((sb_iir(1, 0, *buffer) / 1.3) * mixer->cd) / 3.0; + c = ((sb_iir(2, 0, *buffer) / 1.3) * mixer->cd) / 3.0; *buffer = c * mixer->master; } else { - c = (((sb_iir(1, 0, (*buffer)) / 1.3) * 65536) / 3.0) / 65536.0; + c = (((sb_iir(2, 0, (*buffer)) / 1.3) * 65536) / 3.0) / 65536.0; *buffer = c; } } @@ -268,16 +297,6 @@ sb_get_buffer_sbpro(int32_t *buffer, int len, void *priv) const sb_ct1345_mixer_t *mixer = &sb->mixer_sbpro; double out_l = 0.0; double out_r = 0.0; - const int32_t *opl_buf = NULL; - const int32_t *opl2_buf = NULL; - - if (sb->opl_enabled) { - if (sb->dsp.sb_type == SBPRO) { - opl_buf = sb->opl.update(sb->opl.priv); - opl2_buf = sb->opl2.update(sb->opl2.priv); - } else - opl_buf = sb->opl.update(sb->opl.priv); - } sb_dsp_update(&sb->dsp); @@ -285,21 +304,6 @@ sb_get_buffer_sbpro(int32_t *buffer, int len, void *priv) out_l = 0.0; out_r = 0.0; - if (sb->opl_enabled) { - if (sb->dsp.sb_type == SBPRO) { - /* Two chips for LEFT and RIGHT channels. - Each chip stores data into the LEFT channel only (no sample alternating.) */ - out_l = (((double) opl_buf[c]) * mixer->fm_l) * 0.7171630859375; - out_r = (((double) opl2_buf[c]) * mixer->fm_r) * 0.7171630859375; - } else { - out_l = (((double) opl_buf[c]) * mixer->fm_l) * 0.7171630859375; - out_r = (((double) opl_buf[c + 1]) * mixer->fm_r) * 0.7171630859375; - if (sb->opl_mix && sb->opl_mixer) { - sb->opl_mix(sb->opl_mixer, &out_l, &out_r); - } - } - } - /* TODO: Implement the stereo switch on the mixer instead of on the dsp? */ if (mixer->output_filter) { out_l += (sb_iir(0, 0, (double) sb->dsp.buffer[c]) * mixer->voice_l) / 3.9; @@ -317,15 +321,57 @@ sb_get_buffer_sbpro(int32_t *buffer, int len, void *priv) buffer[c + 1] += (int32_t) out_r; } - sb->pos = 0; + sb->dsp.pos = 0; +} - if (sb->opl_enabled) { - sb->opl.reset_buffer(sb->opl.priv); - if (sb->dsp.sb_type == SBPRO) - sb->opl2.reset_buffer(sb->opl2.priv); +void +sb_get_music_buffer_sbpro(int32_t *buffer, int len, void *priv) +{ + sb_t *sb = (sb_t *) priv; + const sb_ct1345_mixer_t *mixer = &sb->mixer_sbpro; + double out_l = 0.0; + double out_r = 0.0; + const int32_t *opl_buf = NULL; + const int32_t *opl2_buf = NULL; + + if (!sb->opl_enabled) + return; + + if (sb->dsp.sb_type == SBPRO) { + opl_buf = sb->opl.update(sb->opl.priv); + opl2_buf = sb->opl2.update(sb->opl2.priv); + } else + opl_buf = sb->opl.update(sb->opl.priv); + + sb_dsp_update(&sb->dsp); + + for (int c = 0; c < len * 2; c += 2) { + out_l = 0.0; + out_r = 0.0; + + if (sb->dsp.sb_type == SBPRO) { + /* Two chips for LEFT and RIGHT channels. + Each chip stores data into the LEFT channel only (no sample alternating.) */ + out_l = (((double) opl_buf[c]) * mixer->fm_l) * 0.7171630859375; + out_r = (((double) opl2_buf[c]) * mixer->fm_r) * 0.7171630859375; + } else { + out_l = (((double) opl_buf[c]) * mixer->fm_l) * 0.7171630859375; + out_r = (((double) opl_buf[c + 1]) * mixer->fm_r) * 0.7171630859375; + if (sb->opl_mix && sb->opl_mixer) + sb->opl_mix(sb->opl_mixer, &out_l, &out_r); + } + + /* TODO: recording CD, Mic with AGC or line in. Note: mic volume does not affect recording. */ + out_l *= mixer->master_l; + out_r *= mixer->master_r; + + buffer[c] += (int32_t) out_l; + buffer[c + 1] += (int32_t) out_r; } - sb->dsp.pos = 0; + sb->opl.reset_buffer(sb->opl.priv); + if (sb->dsp.sb_type == SBPRO) + sb->opl2.reset_buffer(sb->opl2.priv); } void @@ -338,7 +384,7 @@ sbpro_filter_cd_audio(int channel, double *buffer, void *priv) double master = channel ? mixer->master_r : mixer->master_l; if (mixer->output_filter) - c = (sb_iir(1, channel, *buffer) * cd) / 3.9; + c = (sb_iir(2, channel, *buffer) * cd) / 3.9; else c = (*buffer * cd) / 3.0; *buffer = c * master; @@ -349,21 +395,9 @@ sb_get_buffer_sb16_awe32(int32_t *buffer, int len, void *priv) { sb_t *sb = (sb_t *) priv; const sb_ct1745_mixer_t *mixer = &sb->mixer_sb16; - int dsp_rec_pos = sb->dsp.record_pos_write; - int c_emu8k = 0; - int c_record; - int32_t in_l; - int32_t in_r; double out_l = 0.0; double out_r = 0.0; double bass_treble; - const int32_t *opl_buf = NULL; - - if (sb->opl_enabled) - opl_buf = sb->opl.update(sb->opl.priv); - - if (sb->dsp.sb_type > SB16) - emu8k_update(&sb->emu8k); sb_dsp_update(&sb->dsp); @@ -371,25 +405,6 @@ sb_get_buffer_sb16_awe32(int32_t *buffer, int len, void *priv) out_l = 0.0; out_r = 0.0; - if (sb->dsp.sb_type > SB16) - c_emu8k = ((((c / 2) * FREQ_44100) / SOUND_FREQ) * 2); - - if (sb->opl_enabled) { - out_l = ((double) opl_buf[c]) * mixer->fm_l * 0.7171630859375; - out_r = ((double) opl_buf[c + 1]) * mixer->fm_r * 0.7171630859375; - } - - if (sb->dsp.sb_type > SB16) { - out_l += (((double) sb->emu8k.buffer[c_emu8k]) * mixer->fm_l); - out_r += (((double) sb->emu8k.buffer[c_emu8k + 1]) * mixer->fm_r); - } - - /* TODO: Multi-recording mic with agc/+20db, CD, and line in with channel inversion */ - in_l = (mixer->input_selector_left & INPUT_MIDI_L) ? ((int32_t) out_l) : 0 + (mixer->input_selector_left & INPUT_MIDI_R) ? ((int32_t) out_r) - : 0; - in_r = (mixer->input_selector_right & INPUT_MIDI_L) ? ((int32_t) out_l) : 0 + (mixer->input_selector_right & INPUT_MIDI_R) ? ((int32_t) out_r) - : 0; - if (mixer->output_filter) { /* We divide by 3 to get the volume down to normal. */ out_l += (low_fir_sb16(0, 0, (double) sb->dsp.buffer[c]) * mixer->voice_l) / 3.0; @@ -440,8 +455,100 @@ sb_get_buffer_sb16_awe32(int32_t *buffer, int len, void *priv) out_r = (out_l *bass_treble + high_cut_iir(0, 1, out_r) * (1.0 - bass_treble)); } + buffer[c] += (int32_t) (out_l * mixer->output_gain_L); + buffer[c + 1] += (int32_t) (out_r * mixer->output_gain_R); + } + + sb->dsp.pos = 0; +} + +static void +sb_get_music_buffer_sb16_awe32(int32_t *buffer, int len, void *priv) +{ + sb_t *sb = (sb_t *) priv; + const sb_ct1745_mixer_t *mixer = &sb->mixer_sb16; + int dsp_rec_pos = sb->dsp.record_pos_write; + int c_emu8k = 0; + int c_record; + int32_t in_l; + int32_t in_r; + double out_l = 0.0; + double out_r = 0.0; + double bass_treble; + const int32_t *opl_buf = NULL; + + if (sb->opl_enabled) + opl_buf = sb->opl.update(sb->opl.priv); + + if (sb->dsp.sb_type > SB16) + emu8k_update(&sb->emu8k); + + for (int c = 0; c < len * 2; c += 2) { + out_l = 0.0; + out_r = 0.0; + + if (sb->dsp.sb_type > SB16) + c_emu8k = ((((c / 2) * FREQ_44100) / MUSIC_FREQ) * 2); + + if (sb->opl_enabled) { + out_l = ((double) opl_buf[c]) * mixer->fm_l * 0.7171630859375; + out_r = ((double) opl_buf[c + 1]) * mixer->fm_r * 0.7171630859375; + } + + if (sb->dsp.sb_type > SB16) { + out_l += (((double) sb->emu8k.buffer[c_emu8k]) * mixer->fm_l); + out_r += (((double) sb->emu8k.buffer[c_emu8k + 1]) * mixer->fm_r); + } + + /* TODO: Multi-recording mic with agc/+20db, CD, and line in with channel inversion */ + in_l = (mixer->input_selector_left & INPUT_MIDI_L) ? ((int32_t) out_l) : 0 + (mixer->input_selector_left & INPUT_MIDI_R) ? ((int32_t) out_r) + : 0; + in_r = (mixer->input_selector_right & INPUT_MIDI_L) ? ((int32_t) out_l) : 0 + (mixer->input_selector_right & INPUT_MIDI_R) ? ((int32_t) out_r) + : 0; + + out_l *= mixer->master_l; + out_r *= mixer->master_r; + + /* This is not exactly how one does bass/treble controls, but the end result is like it. + A better implementation would reduce the CPU usage. */ + if (mixer->bass_l != 8) { + bass_treble = sb_bass_treble_4bits[mixer->bass_l]; + + if (mixer->bass_l > 8) + out_l += (low_iir(1, 0, out_l) * bass_treble); + else if (mixer->bass_l < 8) + out_l = (out_l *bass_treble + low_cut_iir(1, 0, out_l) * (1.0 - bass_treble)); + } + + if (mixer->bass_r != 8) { + bass_treble = sb_bass_treble_4bits[mixer->bass_r]; + + if (mixer->bass_r > 8) + out_r += (low_iir(1, 1, out_r) * bass_treble); + else if (mixer->bass_r < 8) + out_r = (out_r *bass_treble + low_cut_iir(1, 1, out_r) * (1.0 - bass_treble)); + } + + if (mixer->treble_l != 8) { + bass_treble = sb_bass_treble_4bits[mixer->treble_l]; + + if (mixer->treble_l > 8) + out_l += (high_iir(1, 0, out_l) * bass_treble); + else if (mixer->treble_l < 8) + out_l = (out_l *bass_treble + high_cut_iir(1, 0, out_l) * (1.0 - bass_treble)); + } + + if (mixer->treble_r != 8) { + bass_treble = sb_bass_treble_4bits[mixer->treble_r]; + + if (mixer->treble_r > 8) + out_r += (high_iir(1, 1, out_r) * bass_treble); + else if (mixer->treble_r < 8) + out_r = (out_l *bass_treble + high_cut_iir(1, 1, out_r) * (1.0 - bass_treble)); + } + if (sb->dsp.sb_enable_i) { - c_record = dsp_rec_pos + ((c * sb->dsp.sb_freq) / SOUND_FREQ); + c_record = dsp_rec_pos + ((c * sb->dsp.sb_freq) / MUSIC_FREQ); in_l <<= mixer->input_gain_L; in_r <<= mixer->input_gain_R; @@ -467,13 +574,9 @@ sb_get_buffer_sb16_awe32(int32_t *buffer, int len, void *priv) sb->dsp.record_pos_write += ((len * sb->dsp.sb_freq) / 24000); sb->dsp.record_pos_write &= 0xffff; - sb->pos = 0; - if (sb->opl_enabled) sb->opl.reset_buffer(sb->opl.priv); - sb->dsp.pos = 0; - if (sb->dsp.sb_type > SB16) sb->emu8k.pos = 0; } @@ -492,7 +595,7 @@ sb16_awe32_filter_cd_audio(int channel, double *buffer, void *priv) double output_gain = (channel ? mixer->output_gain_R : mixer->output_gain_L); if (mixer->output_filter) - c = (low_fir_sb16(1, channel, *buffer) * cd) / 3.0; + c = (low_fir_sb16(2, channel, *buffer) * cd) / 3.0; else c = ((*buffer) * cd) / 3.0; c *= master; @@ -503,18 +606,18 @@ sb16_awe32_filter_cd_audio(int channel, double *buffer, void *priv) bass_treble = sb_bass_treble_4bits[bass]; if (bass > 8) - c += (low_iir(1, channel, c) * bass_treble); + c += (low_iir(2, channel, c) * bass_treble); else if (bass < 8) - c = (c * bass_treble + low_cut_iir(1, channel, c) * (1.0 - bass_treble)); + c = (c * bass_treble + low_cut_iir(2, channel, c) * (1.0 - bass_treble)); } if (treble != 8) { bass_treble = sb_bass_treble_4bits[treble]; if (treble > 8) - c += (high_iir(1, channel, c) * bass_treble); + c += (high_iir(2, channel, c) * bass_treble); else if (treble < 8) - c = (c * bass_treble + high_cut_iir(1, channel, c) * (1.0 - bass_treble)); + c = (c * bass_treble + high_cut_iir(2, channel, c) * (1.0 - bass_treble)); } *buffer = c * output_gain; @@ -534,7 +637,7 @@ sb16_awe32_filter_pc_speaker(int channel, double *buffer, void *priv) double output_gain = (channel ? mixer->output_gain_R : mixer->output_gain_L); if (mixer->output_filter) - c = (low_fir_sb16(2, channel, *buffer) * spk) / 3.0; + c = (low_fir_sb16(3, channel, *buffer) * spk) / 3.0; else c = ((*buffer) * spk) / 3.0; c *= master; @@ -545,18 +648,18 @@ sb16_awe32_filter_pc_speaker(int channel, double *buffer, void *priv) bass_treble = sb_bass_treble_4bits[bass]; if (bass > 8) - c += (low_iir(2, channel, c) * bass_treble); + c += (low_iir(3, channel, c) * bass_treble); else if (bass < 8) - c = (c * bass_treble + low_cut_iir(1, channel, c) * (1.0 - bass_treble)); + c = (c * bass_treble + low_cut_iir(3, channel, c) * (1.0 - bass_treble)); } if (treble != 8) { bass_treble = sb_bass_treble_4bits[treble]; if (treble > 8) - c += (high_iir(2, channel, c) * bass_treble); + c += (high_iir(3, channel, c) * bass_treble); else if (treble < 8) - c = (c * bass_treble + high_cut_iir(1, channel, c) * (1.0 - bass_treble)); + c = (c * bass_treble + high_cut_iir(3, channel, c) * (1.0 - bass_treble)); } *buffer = c * output_gain; @@ -1706,6 +1809,7 @@ sb_1_init(UNUSED(const device_t *info)) if (sb->opl_enabled) fm_driver_get(FM_YM3812, &sb->opl); + sb_dsp_set_real_opl(&sb->dsp, 1); sb_dsp_init(&sb->dsp, SB1, SB_SUBTYPE_DEFAULT, sb); sb_dsp_setaddr(&sb->dsp, addr); sb_dsp_setirq(&sb->dsp, device_get_config_int("irq")); @@ -1731,6 +1835,8 @@ sb_1_init(UNUSED(const device_t *info)) sb->mixer_enabled = 0; sound_add_handler(sb_get_buffer_sb2, sb); + if (sb->opl_enabled) + music_add_handler(sb_get_music_buffer_sb2, sb); sound_set_cd_audio_filter(sb2_filter_cd_audio, sb); if (device_get_config_int("receive_input")) @@ -1754,6 +1860,7 @@ sb_15_init(UNUSED(const device_t *info)) if (sb->opl_enabled) fm_driver_get(FM_YM3812, &sb->opl); + sb_dsp_set_real_opl(&sb->dsp, 1); sb_dsp_init(&sb->dsp, SB15, SB_SUBTYPE_DEFAULT, sb); sb_dsp_setaddr(&sb->dsp, addr); sb_dsp_setirq(&sb->dsp, device_get_config_int("irq")); @@ -1781,6 +1888,8 @@ sb_15_init(UNUSED(const device_t *info)) sb->mixer_enabled = 0; sound_add_handler(sb_get_buffer_sb2, sb); + if (sb->opl_enabled) + music_add_handler(sb_get_music_buffer_sb2, sb); sound_set_cd_audio_filter(sb2_filter_cd_audio, sb); if (device_get_config_int("receive_input")) @@ -1802,6 +1911,7 @@ sb_mcv_init(UNUSED(const device_t *info)) if (sb->opl_enabled) fm_driver_get(FM_YM3812, &sb->opl); + sb_dsp_set_real_opl(&sb->dsp, 1); sb_dsp_init(&sb->dsp, SB15, SB_SUBTYPE_DEFAULT, sb); sb_dsp_setaddr(&sb->dsp, 0); sb_dsp_setirq(&sb->dsp, device_get_config_int("irq")); @@ -1809,6 +1919,8 @@ sb_mcv_init(UNUSED(const device_t *info)) sb->mixer_enabled = 0; sound_add_handler(sb_get_buffer_sb2, sb); + if (sb->opl_enabled) + music_add_handler(sb_get_music_buffer_sb2, sb); sound_set_cd_audio_filter(sb2_filter_cd_audio, sb); /* I/O handlers activated in sb_mcv_write */ @@ -1847,6 +1959,7 @@ sb_2_init(UNUSED(const device_t *info)) if (sb->opl_enabled) fm_driver_get(FM_YM3812, &sb->opl); + sb_dsp_set_real_opl(&sb->dsp, 1); sb_dsp_init(&sb->dsp, SB2, SB_SUBTYPE_DEFAULT, sb); sb_dsp_setaddr(&sb->dsp, addr); sb_dsp_setirq(&sb->dsp, device_get_config_int("irq")); @@ -1890,6 +2003,8 @@ sb_2_init(UNUSED(const device_t *info)) } else sb->mixer_enabled = 0; sound_add_handler(sb_get_buffer_sb2, sb); + if (sb->opl_enabled) + music_add_handler(sb_get_music_buffer_sb2, sb); sound_set_cd_audio_filter(sb2_filter_cd_audio, sb); if (device_get_config_int("receive_input")) @@ -1939,6 +2054,7 @@ sb_pro_v1_init(UNUSED(const device_t *info)) sb->opl2.set_do_cycles(sb->opl2.priv, 0); } + sb_dsp_set_real_opl(&sb->dsp, 1); sb_dsp_init(&sb->dsp, SBPRO, SB_SUBTYPE_DEFAULT, sb); sb_dsp_setaddr(&sb->dsp, addr); sb_dsp_setirq(&sb->dsp, device_get_config_int("irq")); @@ -1970,6 +2086,8 @@ sb_pro_v1_init(UNUSED(const device_t *info)) sb_ct1345_mixer_write, NULL, NULL, sb); sound_add_handler(sb_get_buffer_sbpro, sb); + if (sb->opl_enabled) + music_add_handler(sb_get_music_buffer_sbpro, sb); sound_set_cd_audio_filter(sbpro_filter_cd_audio, sb); if (device_get_config_int("receive_input")) @@ -1995,6 +2113,7 @@ sb_pro_v2_init(UNUSED(const device_t *info)) if (sb->opl_enabled) fm_driver_get(FM_YMF262, &sb->opl); + sb_dsp_set_real_opl(&sb->dsp, 1); sb_dsp_init(&sb->dsp, SBPRO2, SB_SUBTYPE_DEFAULT, sb); sb_dsp_setaddr(&sb->dsp, addr); sb_dsp_setirq(&sb->dsp, device_get_config_int("irq")); @@ -2022,6 +2141,8 @@ sb_pro_v2_init(UNUSED(const device_t *info)) sb_ct1345_mixer_write, NULL, NULL, sb); sound_add_handler(sb_get_buffer_sbpro, sb); + if (sb->opl_enabled) + music_add_handler(sb_get_music_buffer_sbpro, sb); sound_set_cd_audio_filter(sbpro_filter_cd_audio, sb); if (device_get_config_int("receive_input")) @@ -2044,11 +2165,14 @@ sb_pro_mcv_init(UNUSED(const device_t *info)) sb->opl_enabled = 1; fm_driver_get(FM_YMF262, &sb->opl); + sb_dsp_set_real_opl(&sb->dsp, 1); sb_dsp_init(&sb->dsp, SBPRO2, SB_SUBTYPE_DEFAULT, sb); sb_ct1345_mixer_reset(sb); sb->mixer_enabled = 1; sound_add_handler(sb_get_buffer_sbpro, sb); + if (sb->opl_enabled) + music_add_handler(sb_get_music_buffer_sbpro, sb); sound_set_cd_audio_filter(sbpro_filter_cd_audio, sb); /* I/O handlers activated in sb_pro_mcv_write */ @@ -2070,11 +2194,14 @@ sb_pro_compat_init(UNUSED(const device_t *info)) fm_driver_get(FM_YMF262, &sb->opl); + sb_dsp_set_real_opl(&sb->dsp, 1); sb_dsp_init(&sb->dsp, SBPRO2, SB_SUBTYPE_DEFAULT, sb); sb_ct1345_mixer_reset(sb); sb->mixer_enabled = 1; sound_add_handler(sb_get_buffer_sbpro, sb); + if (sb->opl_enabled) + music_add_handler(sb_get_music_buffer_sbpro, sb); sb->mpu = (mpu_t *) malloc(sizeof(mpu_t)); memset(sb->mpu, 0, sizeof(mpu_t)); @@ -2097,6 +2224,7 @@ sb_16_init(UNUSED(const device_t *info)) if (sb->opl_enabled) fm_driver_get(info->local, &sb->opl); + sb_dsp_set_real_opl(&sb->dsp, (info->local != FM_YMF289B)); sb_dsp_init(&sb->dsp, (info->local == FM_YMF289B) ? SBAWE32PNP : SB16, SB_SUBTYPE_DEFAULT, sb); sb_dsp_setaddr(&sb->dsp, addr); sb_dsp_setirq(&sb->dsp, device_get_config_int("irq")); @@ -2126,6 +2254,12 @@ sb_16_init(UNUSED(const device_t *info)) io_sethandler(addr + 4, 0x0002, sb_ct1745_mixer_read, NULL, NULL, sb_ct1745_mixer_write, NULL, NULL, sb); sound_add_handler(sb_get_buffer_sb16_awe32, sb); + if (sb->opl_enabled) { + if (info->local == FM_YMF289B) + sound_add_handler(sb_get_music_buffer_sb16_awe32, sb); + else + music_add_handler(sb_get_music_buffer_sb16_awe32, sb); + } sound_set_cd_audio_filter(sb16_awe32_filter_cd_audio, sb); if (device_get_config_int("control_pc_speaker")) sound_set_pc_speaker_filter(sb16_awe32_filter_pc_speaker, sb); @@ -2157,6 +2291,7 @@ sb_16_reply_mca_init(UNUSED(const device_t *info)) sb->opl_enabled = 1; fm_driver_get(FM_YMF262, &sb->opl); + sb_dsp_set_real_opl(&sb->dsp, 1); sb_dsp_init(&sb->dsp, SB16, SB_SUBTYPE_DEFAULT, sb); sb_dsp_setdma16_supported(&sb->dsp, 1); sb_dsp_setdma16_enabled(&sb->dsp, 1); @@ -2165,6 +2300,8 @@ sb_16_reply_mca_init(UNUSED(const device_t *info)) sb->mixer_enabled = 1; sb->mixer_sb16.output_filter = 1; sound_add_handler(sb_get_buffer_sb16_awe32, sb); + if (sb->opl_enabled) + music_add_handler(sb_get_music_buffer_sb16_awe32, sb); sound_set_cd_audio_filter(sb16_awe32_filter_cd_audio, sb); if (device_get_config_int("control_pc_speaker")) sound_set_pc_speaker_filter(sb16_awe32_filter_pc_speaker, sb); @@ -2207,6 +2344,8 @@ sb_16_pnp_init(UNUSED(const device_t *info)) sb->mixer_enabled = 1; sb->mixer_sb16.output_filter = 1; sound_add_handler(sb_get_buffer_sb16_awe32, sb); + if (sb->opl_enabled) + music_add_handler(sb_get_music_buffer_sb16_awe32, sb); sound_set_cd_audio_filter(sb16_awe32_filter_cd_audio, sb); if (device_get_config_int("control_pc_speaker")) sound_set_pc_speaker_filter(sb16_awe32_filter_pc_speaker, sb); @@ -2225,6 +2364,7 @@ sb_16_pnp_init(UNUSED(const device_t *info)) isapnp_add_card(sb_16_pnp_rom, sizeof(sb_16_pnp_rom), sb_16_pnp_config_changed, NULL, NULL, NULL, sb); + sb_dsp_set_real_opl(&sb->dsp, 1); sb_dsp_setaddr(&sb->dsp, 0); sb_dsp_setirq(&sb->dsp, 0); sb_dsp_setdma8(&sb->dsp, ISAPNP_DMA_DISABLED); @@ -2262,6 +2402,7 @@ sb_vibra16_pnp_init(UNUSED(const device_t *info)) sb->opl_enabled = 1; fm_driver_get(FM_YMF262, &sb->opl); + sb_dsp_set_real_opl(&sb->dsp, 1); sb_dsp_init(&sb->dsp, (info->local == 0) ? SBAWE64 : SBAWE32PNP, SB_SUBTYPE_DEFAULT, sb); /* The ViBRA 16XV does 16-bit DMA through 8-bit DMA. */ sb_dsp_setdma16_supported(&sb->dsp, info->local != 0); @@ -2270,6 +2411,8 @@ sb_vibra16_pnp_init(UNUSED(const device_t *info)) sb->mixer_enabled = 1; sb->mixer_sb16.output_filter = 1; sound_add_handler(sb_get_buffer_sb16_awe32, sb); + if (sb->opl_enabled) + music_add_handler(sb_get_music_buffer_sb16_awe32, sb); sound_set_cd_audio_filter(sb16_awe32_filter_cd_audio, sb); if (device_get_config_int("control_pc_speaker")) sound_set_pc_speaker_filter(sb16_awe32_filter_pc_speaker, sb); @@ -2340,6 +2483,7 @@ sb_16_compat_init(const device_t *info) fm_driver_get(FM_YMF262, &sb->opl); + sb_dsp_set_real_opl(&sb->dsp, 1); sb_dsp_init(&sb->dsp, SB16, SB_SUBTYPE_DEFAULT, sb); sb_dsp_setdma16_supported(&sb->dsp, 1); sb_dsp_setdma16_enabled(&sb->dsp, 1); @@ -2347,6 +2491,8 @@ sb_16_compat_init(const device_t *info) sb->mixer_enabled = 1; sound_add_handler(sb_get_buffer_sb16_awe32, sb); + if (sb->opl_enabled) + music_add_handler(sb_get_music_buffer_sb16_awe32, sb); sb->mpu = (mpu_t *) malloc(sizeof(mpu_t)); memset(sb->mpu, 0, sizeof(mpu_t)); @@ -2411,6 +2557,7 @@ sb_awe32_init(UNUSED(const device_t *info)) if (sb->opl_enabled) fm_driver_get(FM_YMF262, &sb->opl); + sb_dsp_set_real_opl(&sb->dsp, 1); sb_dsp_init(&sb->dsp, SBAWE32, SB_SUBTYPE_DEFAULT, sb); sb_dsp_setaddr(&sb->dsp, addr); sb_dsp_setirq(&sb->dsp, device_get_config_int("irq")); @@ -2440,6 +2587,8 @@ sb_awe32_init(UNUSED(const device_t *info)) io_sethandler(addr + 4, 0x0002, sb_ct1745_mixer_read, NULL, NULL, sb_ct1745_mixer_write, NULL, NULL, sb); sound_add_handler(sb_get_buffer_sb16_awe32, sb); + if (sb->opl_enabled) + music_add_handler(sb_get_music_buffer_sb16_awe32, sb); sound_set_cd_audio_filter(sb16_awe32_filter_cd_audio, sb); if (device_get_config_int("control_pc_speaker")) sound_set_pc_speaker_filter(sb16_awe32_filter_pc_speaker, sb); @@ -2482,9 +2631,12 @@ sb_awe32_pnp_init(const device_t *info) sb_dsp_setdma16_supported(&sb->dsp, 1); sb_ct1745_mixer_reset(sb); + sb_dsp_set_real_opl(&sb->dsp, 1); sb->mixer_enabled = 1; sb->mixer_sb16.output_filter = 1; sound_add_handler(sb_get_buffer_sb16_awe32, sb); + if (sb->opl_enabled) + music_add_handler(sb_get_music_buffer_sb16_awe32, sb); sound_set_cd_audio_filter(sb16_awe32_filter_cd_audio, sb); if (device_get_config_int("control_pc_speaker")) sound_set_pc_speaker_filter(sb16_awe32_filter_pc_speaker, sb); diff --git a/src/sound/snd_sb_dsp.c b/src/sound/snd_sb_dsp.c index 6fc7815ab..cf4498b4b 100644 --- a/src/sound/snd_sb_dsp.c +++ b/src/sound/snd_sb_dsp.c @@ -115,7 +115,7 @@ uint8_t adjustMap2[24] = { 252, 0, 252, 0 }; -double low_fir_sb16_coef[3][SB16_NCoef]; +double low_fir_sb16_coef[4][SB16_NCoef]; #ifdef ENABLE_SB_DSP_LOG int sb_dsp_do_log = ENABLE_SB_DSP_LOG; @@ -1256,8 +1256,12 @@ sb_dsp_init(sb_dsp_t *dsp, int type, int subtype, void *parent) /* Initialise SB16 filter to same cutoff as 8-bit SBs (3.2 kHz). This will be recalculated when a set frequency command is sent. */ recalc_sb16_filter(0, 3200 * 2); - recalc_sb16_filter(1, FREQ_44100); - recalc_sb16_filter(2, 18939); + if (dsp->sb_has_real_opl) + recalc_sb16_filter(1, FREQ_49716); + else + recalc_sb16_filter(1, FREQ_48000); + recalc_sb16_filter(2, FREQ_44100); + recalc_sb16_filter(3, 18939); /* Initialize SB16 8051 RAM and ASP internal RAM */ memset(dsp->sb_8051_ram, 0x00, sizeof(dsp->sb_8051_ram)); @@ -1283,6 +1287,12 @@ sb_dsp_setaddr(sb_dsp_t *dsp, uint16_t addr) } } +void +sb_dsp_set_real_opl(sb_dsp_t *dsp, uint8_t has_real_opl) +{ + dsp->sb_has_real_opl = has_real_opl; +} + void sb_dsp_set_stereo(sb_dsp_t *dsp, int stereo) { diff --git a/src/sound/snd_wss.c b/src/sound/snd_wss.c index a69d746da..da88b29e9 100644 --- a/src/sound/snd_wss.c +++ b/src/sound/snd_wss.c @@ -80,21 +80,28 @@ static void wss_get_buffer(int32_t *buffer, int len, void *priv) { wss_t *wss = (wss_t *) priv; - const int32_t *opl_buf = NULL; - - if (wss->opl_enabled) - opl_buf = wss->opl.update(wss->opl.priv); ad1848_update(&wss->ad1848); + for (int c = 0; c < len * 2; c++) + buffer[c] += wss->ad1848.buffer[c] / 2; + + wss->ad1848.pos = 0; +} + +static void +wss_get_music_buffer(int32_t *buffer, int len, void *priv) +{ + wss_t *wss = (wss_t *) priv; + const int32_t *opl_buf = NULL; + + opl_buf = wss->opl.update(wss->opl.priv); + for (int c = 0; c < len * 2; c++) { if (opl_buf) buffer[c] += opl_buf[c]; - buffer[c] += wss->ad1848.buffer[c] / 2; } - if (wss->opl_enabled) - wss->opl.reset_buffer(wss->opl.priv); - wss->ad1848.pos = 0; + wss->opl.reset_buffer(wss->opl.priv); } void * @@ -131,6 +138,9 @@ wss_init(UNUSED(const device_t *info)) sound_add_handler(wss_get_buffer, wss); + if (wss->opl_enabled) + music_add_handler(wss_get_music_buffer, wss); + return wss; } @@ -214,6 +224,9 @@ ncr_audio_init(UNUSED(const device_t *info)) sound_add_handler(wss_get_buffer, wss); + if (wss->opl_enabled) + music_add_handler(wss_get_music_buffer, wss); + return wss; } diff --git a/src/sound/sound.c b/src/sound/sound.c index ed7f821e0..81f70d921 100644 --- a/src/sound/sound.c +++ b/src/sound/sound.c @@ -53,9 +53,11 @@ typedef struct { int sound_card_current[SOUND_CARD_MAX] = { 0, 0, 0, 0 }; int sound_pos_global = 0; +int music_pos_global = 0; int sound_gain = 0; static sound_handler_t sound_handlers[8]; +static sound_handler_t music_handlers[8]; static thread_t *sound_cd_thread_h; static event_t *sound_cd_event; @@ -63,9 +65,15 @@ static event_t *sound_cd_start_event; static int32_t *outbuffer; static float *outbuffer_ex; static int16_t *outbuffer_ex_int16; +static int32_t *outbuffer_m; +static float *outbuffer_m_ex; +static int16_t *outbuffer_m_ex_int16; static int sound_handlers_num; +static int music_handlers_num; static pc_timer_t sound_poll_timer; static uint64_t sound_poll_latch; +static pc_timer_t music_poll_timer; +static uint64_t music_poll_latch; static int16_t cd_buffer[CDROM_NUM][CD_BUFLEN * 2]; static float cd_out_buffer[CD_BUFLEN * 2]; @@ -395,6 +403,28 @@ sound_realloc_buffers(void) } } +static void +music_realloc_buffers(void) +{ + if (outbuffer_m_ex != NULL) { + free(outbuffer_m_ex); + outbuffer_m_ex = NULL; + } + + if (outbuffer_m_ex_int16 != NULL) { + free(outbuffer_m_ex_int16); + outbuffer_m_ex_int16 = NULL; + } + + if (sound_is_float) { + outbuffer_m_ex = calloc(MUSICBUFLEN * 2, sizeof(float)); + memset(outbuffer_m_ex, 0x00, MUSICBUFLEN * 2 * sizeof(float)); + } else { + outbuffer_m_ex_int16 = calloc(MUSICBUFLEN * 2, sizeof(int16_t)); + memset(outbuffer_m_ex_int16, 0x00, MUSICBUFLEN * 2 * sizeof(int16_t)); + } +} + void sound_init(void) { @@ -403,10 +433,18 @@ sound_init(void) outbuffer_ex = NULL; outbuffer_ex_int16 = NULL; + outbuffer_m_ex = NULL; + outbuffer_m_ex_int16 = NULL; + outbuffer = NULL; outbuffer = calloc(SOUNDBUFLEN * 2, sizeof(int32_t)); memset(outbuffer, 0x00, SOUNDBUFLEN * 2 * sizeof(int32_t)); + outbuffer_m = NULL; + outbuffer_m = calloc(MUSICBUFLEN * 2, sizeof(int32_t)); + memset(outbuffer_m, 0x00, MUSICBUFLEN * 2 * sizeof(int32_t)); + + for (uint8_t i = 0; i < CDROM_NUM; i++) { if (cdrom[i].bus_type != CDROM_BUS_DISABLED) available_cdrom_drives++; @@ -438,6 +476,14 @@ sound_add_handler(void (*get_buffer)(int32_t *buffer, int len, void *priv), void sound_handlers_num++; } +void +music_add_handler(void (*get_buffer)(int32_t *buffer, int len, void *priv), void *priv) +{ + music_handlers[music_handlers_num].get_buffer = get_buffer; + music_handlers[music_handlers_num].priv = priv; + music_handlers_num++; +} + void sound_set_cd_audio_filter(void (*filter)(int channel, double *buffer, void *priv), void *priv) { @@ -502,10 +548,48 @@ sound_poll(UNUSED(void *priv)) } } +void +music_poll(UNUSED(void *priv)) +{ + timer_advance_u64(&music_poll_timer, music_poll_latch); + + music_pos_global++; + if (music_pos_global == MUSICBUFLEN) { + int c; + + memset(outbuffer_m, 0x00, MUSICBUFLEN * 2 * sizeof(int32_t)); + + for (c = 0; c < music_handlers_num; c++) + music_handlers[c].get_buffer(outbuffer_m, MUSICBUFLEN, music_handlers[c].priv); + + for (c = 0; c < MUSICBUFLEN * 2; c++) { + if (sound_is_float) + outbuffer_m_ex[c] = ((float) outbuffer_m[c]) / (float) 32768.0; + else { + if (outbuffer_m[c] > 32767) + outbuffer_m[c] = 32767; + if (outbuffer_m[c] < -32768) + outbuffer_m[c] = -32768; + + outbuffer_m_ex_int16[c] = outbuffer_m[c]; + } + } + + if (sound_is_float) + givealbuffer_music(outbuffer_m_ex); + else + givealbuffer_music(outbuffer_m_ex_int16); + + music_pos_global = 0; + } +} + void sound_speed_changed(void) { sound_poll_latch = (uint64_t) ((double) TIMER_USEC * (1000000.0 / (double) SOUND_FREQ)); + + music_poll_latch = (uint64_t) ((double) TIMER_USEC * (1000000.0 / (double) MUSIC_FREQ)); } void @@ -513,6 +597,8 @@ sound_reset(void) { sound_realloc_buffers(); + music_realloc_buffers(); + midi_out_device_init(); midi_in_device_init(); @@ -523,6 +609,11 @@ sound_reset(void) sound_handlers_num = 0; memset(sound_handlers, 0x00, 8 * sizeof(sound_handler_t)); + timer_add(&music_poll_timer, music_poll, NULL, 1); + + music_handlers_num = 0; + memset(music_handlers, 0x00, 8 * sizeof(sound_handler_t)); + filter_cd_audio = NULL; filter_cd_audio_p = NULL; diff --git a/src/sound/xaudio2.c b/src/sound/xaudio2.c index 0d9e7d909..78c3e2d35 100644 --- a/src/sound/xaudio2.c +++ b/src/sound/xaudio2.c @@ -51,6 +51,7 @@ static int initialized = 0; static IXAudio2 *xaudio2 = NULL; static IXAudio2MasteringVoice *mastervoice = NULL; static IXAudio2SourceVoice *srcvoice = NULL; +static IXAudio2SourceVoice *srcvoicemusic = NULL; static IXAudio2SourceVoice *srcvoicemidi = NULL; static IXAudio2SourceVoice *srcvoicecd = NULL; @@ -164,6 +165,12 @@ inital(void) return; } + fmt.nSamplesPerSec = MUSIC_FREQ; + fmt.nBlockAlign = fmt.nChannels * fmt.wBitsPerSample / 8; + fmt.nAvgBytesPerSec = fmt.nSamplesPerSec * fmt.nBlockAlign; + + IXAudio2_CreateSourceVoice(xaudio2, &srcvoicemusic, &fmt, 0, 2.0f, &callbacks, NULL, NULL); + fmt.nSamplesPerSec = CD_FREQ; fmt.nBlockAlign = fmt.nChannels * fmt.wBitsPerSample / 8; fmt.nAvgBytesPerSec = fmt.nSamplesPerSec * fmt.nBlockAlign; @@ -173,6 +180,7 @@ inital(void) IXAudio2SourceVoice_SetVolume(srcvoice, 1, XAUDIO2_COMMIT_NOW); IXAudio2SourceVoice_Start(srcvoice, 0, XAUDIO2_COMMIT_NOW); IXAudio2SourceVoice_Start(srcvoicecd, 0, XAUDIO2_COMMIT_NOW); + IXAudio2SourceVoice_Start(srcvoicemusic, 0, XAUDIO2_COMMIT_NOW); const char *mdn = midi_out_device_get_internal_name(midi_output_device_current); @@ -196,6 +204,8 @@ closeal(void) initialized = 0; IXAudio2SourceVoice_Stop(srcvoice, 0, XAUDIO2_COMMIT_NOW); IXAudio2SourceVoice_FlushSourceBuffers(srcvoice); + IXAudio2SourceVoice_Stop(srcvoicemusic, 0, XAUDIO2_COMMIT_NOW); + IXAudio2SourceVoice_FlushSourceBuffers(srcvoicemusic); IXAudio2SourceVoice_Stop(srcvoicecd, 0, XAUDIO2_COMMIT_NOW); IXAudio2SourceVoice_FlushSourceBuffers(srcvoicecd); if (srcvoicemidi) { @@ -203,8 +213,9 @@ closeal(void) IXAudio2SourceVoice_FlushSourceBuffers(srcvoicemidi); IXAudio2SourceVoice_DestroyVoice(srcvoicemidi); } - IXAudio2SourceVoice_DestroyVoice(srcvoice); IXAudio2SourceVoice_DestroyVoice(srcvoicecd); + IXAudio2SourceVoice_DestroyVoice(srcvoicemusic); + IXAudio2SourceVoice_DestroyVoice(srcvoice); IXAudio2MasteringVoice_DestroyVoice(mastervoice); IXAudio2_Release(xaudio2); srcvoice = srcvoicecd = srcvoicemidi = NULL; @@ -249,6 +260,12 @@ givealbuffer(void *buf) givealbuffer_common(buf, srcvoice, BUFLEN << 1); } +void +givealbuffer_music(void *buf) +{ + givealbuffer_common(buf, srcvoicemusic, MUSICBUFLEN << 1); +} + void givealbuffer_cd(void *buf) {