--- uae/src/audio.c 2018/04/24 17:16:19 1.1.1.16 +++ uae/src/audio.c 2018/04/24 17:19:54 1.1.1.18 @@ -6,6 +6,7 @@ * Copyright 1995, 1996, 1997 Bernd Schmidt * Copyright 1996 Marcus Sundberg * Copyright 1996 Manfred Thole + * Copyright 2005 Heikki Orsila * Copyright 2006 Toni Wilen * * new filter algorithm and anti&sinc interpolators by Antti S. Lankila @@ -14,6 +15,8 @@ #include "sysconfig.h" #include "sysdeps.h" +#include + #include "options.h" #include "memory.h" #include "custom.h" @@ -40,8 +43,7 @@ #define SINC_QUEUE_LENGTH (SINC_QUEUE_MAX_AGE / MIN_ALLOWED_PERIOD + NUMBER_OF_CPU_UPDATES_ALLOWED) typedef struct { - int age; - int output; + int age, output; } sinc_queue_t; struct audio_channel_data { @@ -56,6 +58,7 @@ struct audio_channel_data { int vol; int *voltbl; uae_u16 dat, nextdat, len; + int sample_accum, sample_accum_time; int sinc_output_state; sinc_queue_t sinc_queue[SINC_QUEUE_LENGTH]; int sinc_queue_length; @@ -78,30 +81,133 @@ void init_sound_table16 (void) for (i = 0; i < 256; i++) for (j = 0; j < 64; j++) - sound_table[j][i] = j * (uae_s8)i * (currprefs.sound_stereo ? 2 : 1); + sound_table[j][i] = j * (uae_s8)i * 2; } #ifdef MULTIPLICATION_PROFITABLE typedef uae_s8 sample8_t; #define DO_CHANNEL_1(v, c) do { (v) *= audio_channel[c].vol; } while (0) #define SBASEVAL16(logn) ((logn) == 1 ? SOUND16_BASE_VAL >> 1 : SOUND16_BASE_VAL) -#define FINISH_DATA(data,b,logn) do { if (14 - (b) + (logn) > 0) (data) >>= 14 - (b) + (logn); else (data) <<= (b) - 14 - (logn); } while (0); +#define FINISH_DATA(data, b, logn) do { if (14 - (b) + (logn) > 0) (data) >>= 14 - (b) + (logn); else (data) <<= (b) - 14 - (logn); } while (0); #else typedef uae_u8 sample8_t; #define DO_CHANNEL_1(v, c) do { (v) = audio_channel[c].voltbl[(v)]; } while (0) #define SBASEVAL16(logn) SOUND16_BASE_VAL -#define FINISH_DATA(data,b,logn) +#define FINISH_DATA(data, b, logn) #endif -/* Always put the right word before the left word. */ -#define DELAY_BUFFER 32 -static uae_u32 right_word_saved[DELAY_BUFFER]; -static uae_u32 left_word_saved[DELAY_BUFFER]; +static uae_u32 right_word_saved[SOUND_MAX_DELAY_BUFFER]; +static uae_u32 left_word_saved[SOUND_MAX_DELAY_BUFFER]; static int saved_ptr; +static int mixed_on, mixed_stereo_size, mixed_mul1, mixed_mul2; +static int led_filter_forced, sound_use_filter, sound_use_filter_sinc, led_filter_on; + +/* denormals are very small floating point numbers that force FPUs into slow + mode. All lowpass filters using floats are suspectible to denormals unless + a small offset is added to avoid very small floating point numbers. */ +#define DENORMAL_OFFSET (1E-10) + +static struct filter_state { + float rc1, rc2, rc3, rc4, rc5; +} sound_filter_state[4]; + +static float a500e_filter1_a0; +static float a500e_filter2_a0; +static float filter_a0; /* a500 and a1200 use the same */ + +enum { + FILTER_NONE = 0, + FILTER_MODEL_A500, + FILTER_MODEL_A1200 +}; + +/* Amiga has two separate filtering circuits per channel, a static RC filter + * on A500 and the LED filter. This code emulates both. + * + * The Amiga filtering circuitry depends on Amiga model. Older Amigas seem + * to have a 6 dB/oct RC filter with cutoff frequency such that the -6 dB + * point for filter is reached at 6 kHz, while newer Amigas have no filtering. + * + * The LED filter is complicated, and we are modelling it with a pair of + * RC filters, the other providing a highboost. The LED starts to cut + * into signal somewhere around 5-6 kHz, and there's some kind of highboost + * in effect above 12 kHz. Better measurements are required. + * + * The current filtering should be accurate to 2 dB with the filter on, + * and to 1 dB with the filter off. +*/ + +static int filter(int input, struct filter_state *fs) +{ + int o; + float normal_output, led_output; + + input = (uae_s16)input; + switch (sound_use_filter) { + case FILTER_NONE: + return input; + case FILTER_MODEL_A500: + fs->rc1 = a500e_filter1_a0 * input + (1 - a500e_filter1_a0) * fs->rc1 + DENORMAL_OFFSET; + fs->rc2 = a500e_filter2_a0 * fs->rc1 + (1-a500e_filter2_a0) * fs->rc2; + normal_output = fs->rc2; + + fs->rc3 = filter_a0 * normal_output + (1 - filter_a0) * fs->rc3; + fs->rc4 = filter_a0 * fs->rc3 + (1 - filter_a0) * fs->rc4; + fs->rc5 = filter_a0 * fs->rc4 + (1 - filter_a0) * fs->rc5; + + led_output = fs->rc5; + break; + + case FILTER_MODEL_A1200: + normal_output = input; + + fs->rc2 = filter_a0 * normal_output + (1 - filter_a0) * fs->rc2 + DENORMAL_OFFSET; + fs->rc3 = filter_a0 * fs->rc2 + (1 - filter_a0) * fs->rc3; + fs->rc4 = filter_a0 * fs->rc3 + (1 - filter_a0) * fs->rc4; + + led_output = fs->rc4; + break; + } + + if (led_filter_on) + o = led_output; + else + o = normal_output; + + if (o > 32767) + o = 32767; + else if (o < -32768) + o = -32768; + + return o; +} + +/* This computes the 1st order low-pass filter term b0. + * The a1 term is 1.0 - b0. The center frequency marks the -3 dB point. */ +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif +static float rc_calculate_a0 (int sample_rate, int cutoff_freq) +{ + float omega; + /* The BLT correction formula below blows up if the cutoff is above nyquist. */ + if (cutoff_freq >= sample_rate / 2) + return 1.0; + + omega = 2 * M_PI * cutoff_freq / sample_rate; + /* Compensate for the bilinear transformation. This allows us to specify the + * stop frequency more exactly, but the filter becomes less steep further + * from stopband. */ + omega = tan (omega / 2) * 2; + return 1 / (1 + 1 / omega); +} + +/* Always put the right word before the left word. */ + STATIC_INLINE void put_sound_word_right (uae_u32 w) { - if (currprefs.mixed_stereo) { + if (mixed_on) { right_word_saved[saved_ptr] = w; return; } @@ -111,27 +217,53 @@ STATIC_INLINE void put_sound_word_right STATIC_INLINE void put_sound_word_left (uae_u32 w) { - if (currprefs.mixed_stereo) { + if (mixed_on) { uae_u32 rold, lold, rnew, lnew, tmp; left_word_saved[saved_ptr] = w; lnew = w - SOUND16_BASE_VAL; rnew = right_word_saved[saved_ptr] - SOUND16_BASE_VAL; - saved_ptr = (saved_ptr + 1) & (DELAY_BUFFER - 1); + saved_ptr = (saved_ptr + 1) & mixed_stereo_size; + lold = left_word_saved[saved_ptr] - SOUND16_BASE_VAL; - tmp = (rnew * 5 + lold * 3) >> 3; + tmp = (rnew * mixed_mul2 + lold * mixed_mul1) / MIXED_STEREO_SCALE; tmp += SOUND16_BASE_VAL; PUT_SOUND_WORD_RIGHT (tmp); rold = right_word_saved[saved_ptr] - SOUND16_BASE_VAL; - w = (lnew * 5 + rold * 3) >> 3; + w = (lnew * mixed_mul2 + rold * mixed_mul1) / MIXED_STEREO_SCALE; } PUT_SOUND_WORD_LEFT (w); } #define DO_CHANNEL(v, c) do { (v) &= audio_channel[c].adk_mask; data += v; } while (0); +static void anti_prehandler (unsigned long best_evtime) +{ + int i, output; + struct audio_channel_data *acd; + + /* Handle accumulator antialiasiation */ + for (i = 0; i < 4; i++) { + acd = &audio_channel[i]; + output = (acd->current_sample * acd->vol) & acd->adk_mask; + acd->sample_accum += output * best_evtime; + acd->sample_accum_time += best_evtime; + } +} + +STATIC_INLINE void samplexx_anti_handler (int *datasp) +{ + int i; + for (i = 0; i < 4; i++) { + datasp[i] = audio_channel[i].sample_accum_time ? (audio_channel[i].sample_accum / audio_channel[i].sample_accum_time) : 0; + audio_channel[i].sample_accum = 0; + audio_channel[i].sample_accum_time = 0; + + } +} + static void sinc_prehandler (unsigned long best_evtime) { int i, j, output; @@ -176,12 +308,6 @@ STATIC_INLINE void samplexx_sinc_handler int i, n; int const *winsinc; -#if 1 - /* Amiga 500 filter model is default for now. Put n=2 for A1200. */ - n = 0; - if (gui_ledstate & 1) /* power led */ - n += 1; -#else if (sound_use_filter_sinc) { n = (sound_use_filter_sinc == FILTER_MODEL_A500) ? 0 : 2; if (led_filter_on) @@ -189,7 +315,6 @@ STATIC_INLINE void samplexx_sinc_handler } else { n = 4; } -#endif winsinc = winsinc_integral[n]; for (i = 0; i < 4; i += 1) { @@ -209,167 +334,24 @@ STATIC_INLINE void samplexx_sinc_handler } } -static void sample16i_sinc_handler (void) -{ - int datas[4], data1; - - samplexx_sinc_handler (datas); - data1 = datas[0] + datas[3] + datas[1] + datas[2]; - FINISH_DATA (data1, 16, 2); - PUT_SOUND_WORD (data1); - check_sound_buffers (); -} - -void sample16_handler (void) +static void sample16si_anti_handler (void) { - uae_u32 data0 = audio_channel[0].current_sample; - uae_u32 data1 = audio_channel[1].current_sample; - uae_u32 data2 = audio_channel[2].current_sample; - uae_u32 data3 = audio_channel[3].current_sample; - DO_CHANNEL_1 (data0, 0); - DO_CHANNEL_1 (data1, 1); - DO_CHANNEL_1 (data2, 2); - DO_CHANNEL_1 (data3, 3); - data0 &= audio_channel[0].adk_mask; - data1 &= audio_channel[1].adk_mask; - data2 &= audio_channel[2].adk_mask; - data3 &= audio_channel[3].adk_mask; - data0 += data1; - data0 += data2; - data0 += data3; - { - uae_u32 data = SBASEVAL16(2) + data0; - FINISH_DATA (data, 16, 2); - PUT_SOUND_WORD (data); - } - check_sound_buffers (); -} - -static void sample16i_rh_handler (void) -{ - unsigned long delta, ratio; - - uae_u32 data0 = audio_channel[0].current_sample; - uae_u32 data1 = audio_channel[1].current_sample; - uae_u32 data2 = audio_channel[2].current_sample; - uae_u32 data3 = audio_channel[3].current_sample; - uae_u32 data0p = audio_channel[0].last_sample; - uae_u32 data1p = audio_channel[1].last_sample; - uae_u32 data2p = audio_channel[2].last_sample; - uae_u32 data3p = audio_channel[3].last_sample; - DO_CHANNEL_1 (data0, 0); - DO_CHANNEL_1 (data1, 1); - DO_CHANNEL_1 (data2, 2); - DO_CHANNEL_1 (data3, 3); - DO_CHANNEL_1 (data0p, 0); - DO_CHANNEL_1 (data1p, 1); - DO_CHANNEL_1 (data2p, 2); - DO_CHANNEL_1 (data3p, 3); - - data0 &= audio_channel[0].adk_mask; - data0p &= audio_channel[0].adk_mask; - data1 &= audio_channel[1].adk_mask; - data1p &= audio_channel[1].adk_mask; - data2 &= audio_channel[2].adk_mask; - data2p &= audio_channel[2].adk_mask; - data3 &= audio_channel[3].adk_mask; - data3p &= audio_channel[3].adk_mask; - - /* linear interpolation and summing up... */ - delta = audio_channel[0].per; - ratio = ((audio_channel[0].evtime % delta) << 8) / delta; - data0 = (data0 * (256 - ratio) + data0p * ratio) >> 8; - delta = audio_channel[1].per; - ratio = ((audio_channel[1].evtime % delta) << 8) / delta; - data0 += (data1 * (256 - ratio) + data1p * ratio) >> 8; - delta = audio_channel[2].per; - ratio = ((audio_channel[2].evtime % delta) << 8) / delta; - data0 += (data2 * (256 - ratio) + data2p * ratio) >> 8; - delta = audio_channel[3].per; - ratio = ((audio_channel[3].evtime % delta) << 8) / delta; - data0 += (data3 * (256 - ratio) + data3p * ratio) >> 8; - - { - uae_u32 data = SBASEVAL16(2) + data0; - FINISH_DATA (data, 16, 2); - PUT_SOUND_WORD (data); - } - - check_sound_buffers (); -} - -static void sample16i_crux_handler (void) -{ - uae_u32 data0 = audio_channel[0].current_sample; - uae_u32 data1 = audio_channel[1].current_sample; - uae_u32 data2 = audio_channel[2].current_sample; - uae_u32 data3 = audio_channel[3].current_sample; - uae_u32 data0p = audio_channel[0].last_sample; - uae_u32 data1p = audio_channel[1].last_sample; - uae_u32 data2p = audio_channel[2].last_sample; - uae_u32 data3p = audio_channel[3].last_sample; - DO_CHANNEL_1 (data0, 0); - DO_CHANNEL_1 (data1, 1); - DO_CHANNEL_1 (data2, 2); - DO_CHANNEL_1 (data3, 3); - DO_CHANNEL_1 (data0p, 0); - DO_CHANNEL_1 (data1p, 1); - DO_CHANNEL_1 (data2p, 2); - DO_CHANNEL_1 (data3p, 3); - - data0 &= audio_channel[0].adk_mask; - data0p &= audio_channel[0].adk_mask; - data1 &= audio_channel[1].adk_mask; - data1p &= audio_channel[1].adk_mask; - data2 &= audio_channel[2].adk_mask; - data2p &= audio_channel[2].adk_mask; - data3 &= audio_channel[3].adk_mask; - data3p &= audio_channel[3].adk_mask; + int datas[4], data1, data2; - { - struct audio_channel_data *cdp; - unsigned long ratio, ratio1; -#define INTERVAL (scaled_sample_evtime * 3) - cdp = audio_channel + 0; - ratio1 = cdp->per - cdp->evtime; - ratio = (ratio1 << 12) / INTERVAL; - if (cdp->evtime < scaled_sample_evtime || ratio1 >= INTERVAL) - ratio = 4096; - data0 = (data0 * ratio + data0p * (4096 - ratio)) >> 12; - - cdp = audio_channel + 1; - ratio1 = cdp->per - cdp->evtime; - ratio = (ratio1 << 12) / INTERVAL; - if (cdp->evtime < scaled_sample_evtime || ratio1 >= INTERVAL) - ratio = 4096; - data1 = (data1 * ratio + data1p * (4096 - ratio)) >> 12; - - cdp = audio_channel + 2; - ratio1 = cdp->per - cdp->evtime; - ratio = (ratio1 << 12) / INTERVAL; - if (cdp->evtime < scaled_sample_evtime || ratio1 >= INTERVAL) - ratio = 4096; - data2 = (data2 * ratio + data2p * (4096 - ratio)) >> 12; - - cdp = audio_channel + 3; - ratio1 = cdp->per - cdp->evtime; - ratio = (ratio1 << 12) / INTERVAL; - if (cdp->evtime < scaled_sample_evtime || ratio1 >= INTERVAL) - ratio = 4096; - data3 = (data3 * ratio + data3p * (4096 - ratio)) >> 12; - } - data1 += data2; - data0 += data3; - data0 += data1; - { - uae_u32 data = SBASEVAL16(2) + data0; - FINISH_DATA (data, 16, 2); - PUT_SOUND_WORD (data); - } + samplexx_anti_handler (datas); + data1 = datas[0] + datas[3]; + data2 = datas[1] + datas[2]; + FINISH_DATA (data1, 16, 1); + if (sound_use_filter) + data1 = filter (data1, &sound_filter_state[0]); + put_sound_word_right (data1); + FINISH_DATA (data2, 16, 1); + if (sound_use_filter) + data2 = filter (data2, &sound_filter_state[1]); + put_sound_word_left (data2); check_sound_buffers (); } -#ifdef HAVE_STEREO_SUPPORT static void sample16si_sinc_handler (void) { int datas[4], data1, data2; @@ -378,9 +360,9 @@ static void sample16si_sinc_handler (voi data1 = datas[0] + datas[3]; data2 = datas[1] + datas[2]; FINISH_DATA (data1, 16, 1); - put_sound_word_left (data1); + put_sound_word_right (data1); FINISH_DATA (data2, 16, 1); - put_sound_word_right (data2); + put_sound_word_left (data2); check_sound_buffers (); } @@ -404,6 +386,8 @@ void sample16s_handler (void) { uae_u32 data = SBASEVAL16(1) + data0; FINISH_DATA (data, 16, 1); + if (sound_use_filter) + data = filter (data, &sound_filter_state[0]); put_sound_word_right (data); } @@ -411,182 +395,25 @@ void sample16s_handler (void) { uae_u32 data = SBASEVAL16(1) + data1; FINISH_DATA (data, 16, 1); + if (sound_use_filter) + data = filter (data, &sound_filter_state[1]); put_sound_word_left (data); } check_sound_buffers (); } -static void sample16si_crux_handler (void) -{ - uae_u32 data0 = audio_channel[0].current_sample; - uae_u32 data1 = audio_channel[1].current_sample; - uae_u32 data2 = audio_channel[2].current_sample; - uae_u32 data3 = audio_channel[3].current_sample; - uae_u32 data0p = audio_channel[0].last_sample; - uae_u32 data1p = audio_channel[1].last_sample; - uae_u32 data2p = audio_channel[2].last_sample; - uae_u32 data3p = audio_channel[3].last_sample; - - DO_CHANNEL_1 (data0, 0); - DO_CHANNEL_1 (data1, 1); - DO_CHANNEL_1 (data2, 2); - DO_CHANNEL_1 (data3, 3); - DO_CHANNEL_1 (data0p, 0); - DO_CHANNEL_1 (data1p, 1); - DO_CHANNEL_1 (data2p, 2); - DO_CHANNEL_1 (data3p, 3); - - data0 &= audio_channel[0].adk_mask; - data0p &= audio_channel[0].adk_mask; - data1 &= audio_channel[1].adk_mask; - data1p &= audio_channel[1].adk_mask; - data2 &= audio_channel[2].adk_mask; - data2p &= audio_channel[2].adk_mask; - data3 &= audio_channel[3].adk_mask; - data3p &= audio_channel[3].adk_mask; - - { - struct audio_channel_data *cdp; - unsigned long ratio, ratio1; -#define INTERVAL (scaled_sample_evtime * 3) - cdp = audio_channel + 0; - ratio1 = cdp->per - cdp->evtime; - ratio = (ratio1 << 12) / INTERVAL; - if (cdp->evtime < scaled_sample_evtime || ratio1 >= INTERVAL) - ratio = 4096; - data0 = (data0 * ratio + data0p * (4096 - ratio)) >> 12; - - cdp = audio_channel + 1; - ratio1 = cdp->per - cdp->evtime; - ratio = (ratio1 << 12) / INTERVAL; - if (cdp->evtime < scaled_sample_evtime || ratio1 >= INTERVAL) - ratio = 4096; - data1 = (data1 * ratio + data1p * (4096 - ratio)) >> 12; - - cdp = audio_channel + 2; - ratio1 = cdp->per - cdp->evtime; - ratio = (ratio1 << 12) / INTERVAL; - if (cdp->evtime < scaled_sample_evtime || ratio1 >= INTERVAL) - ratio = 4096; - data2 = (data2 * ratio + data2p * (4096 - ratio)) >> 12; - - cdp = audio_channel + 3; - ratio1 = cdp->per - cdp->evtime; - ratio = (ratio1 << 12) / INTERVAL; - if (cdp->evtime < scaled_sample_evtime || ratio1 >= INTERVAL) - ratio = 4096; - data3 = (data3 * ratio + data3p * (4096 - ratio)) >> 12; - } - data1 += data2; - data0 += data3; - { - uae_u32 data = SBASEVAL16 (1) + data0; - FINISH_DATA (data, 16, 1); - put_sound_word_right (data); - } - - { - uae_u32 data = SBASEVAL16 (1) + data1; - FINISH_DATA (data, 16, 1); - put_sound_word_left (data); - } - check_sound_buffers (); -} - -static void sample16si_rh_handler (void) -{ - unsigned long delta, ratio; - - uae_u32 data0 = audio_channel[0].current_sample; - uae_u32 data1 = audio_channel[1].current_sample; - uae_u32 data2 = audio_channel[2].current_sample; - uae_u32 data3 = audio_channel[3].current_sample; - uae_u32 data0p = audio_channel[0].last_sample; - uae_u32 data1p = audio_channel[1].last_sample; - uae_u32 data2p = audio_channel[2].last_sample; - uae_u32 data3p = audio_channel[3].last_sample; - - DO_CHANNEL_1 (data0, 0); - DO_CHANNEL_1 (data1, 1); - DO_CHANNEL_1 (data2, 2); - DO_CHANNEL_1 (data3, 3); - DO_CHANNEL_1 (data0p, 0); - DO_CHANNEL_1 (data1p, 1); - DO_CHANNEL_1 (data2p, 2); - DO_CHANNEL_1 (data3p, 3); - - data0 &= audio_channel[0].adk_mask; - data0p &= audio_channel[0].adk_mask; - data1 &= audio_channel[1].adk_mask; - data1p &= audio_channel[1].adk_mask; - data2 &= audio_channel[2].adk_mask; - data2p &= audio_channel[2].adk_mask; - data3 &= audio_channel[3].adk_mask; - data3p &= audio_channel[3].adk_mask; - - /* linear interpolation and summing up... */ - delta = audio_channel[0].per; - ratio = ((audio_channel[0].evtime % delta) << 8) / delta; - data0 = (data0 * (256 - ratio) + data0p * ratio) >> 8; - delta = audio_channel[1].per; - ratio = ((audio_channel[1].evtime % delta) << 8) / delta; - data1 = (data1 * (256 - ratio) + data1p * ratio) >> 8; - delta = audio_channel[2].per; - ratio = ((audio_channel[2].evtime % delta) << 8) / delta; - data1 += (data2 * (256 - ratio) + data2p * ratio) >> 8; - delta = audio_channel[3].per; - ratio = ((audio_channel[3].evtime % delta) << 8) / delta; - data0 += (data3 * (256 - ratio) + data3p * ratio) >> 8; - { - uae_u32 data = SBASEVAL16 (1) + data0; - FINISH_DATA (data, 16, 1); - put_sound_word_right (data); - } - - { - uae_u32 data = SBASEVAL16 (1) + data1; - FINISH_DATA (data, 16, 1); - put_sound_word_left (data); - } - check_sound_buffers (); -} - -#else -void sample16s_handler (void) -{ - sample16_handler (); -} -static void sample16si_crux_handler (void) -{ - sample16i_crux_handler (); -} -static void sample16si_rh_handler (void) -{ - sample16i_rh_handler (); -} -#endif - void switch_audio_interpol (void) { -#if defined HAVE_8BIT_AUDIO_SUPPORT || defined HAVE_ULAW_AUDIO_SUPPORT - if (currprefs.sound_bits == 8) - /* only supported for 16-bit audio */ - return; -#endif - if (currprefs.sound_interpol == 0) { changed_prefs.sound_interpol = 1; - write_log ("Interpol on: rh\n"); + write_log ("Resampler on: sinc\n"); } else if (currprefs.sound_interpol == 1) { changed_prefs.sound_interpol = 2; - write_log ("Interpol on: crux\n"); - } else if (currprefs.sound_interpol == 2) { - changed_prefs.sound_interpol = 3; - write_log ("Interpol on: sinc\n"); + write_log ("Resampler on: anti\n"); } else { changed_prefs.sound_interpol = 0; - write_log ("Interpol off\n"); + write_log ("Resampler off\n"); } return; } @@ -619,14 +446,10 @@ void schedule_audio (void) void update_sound (unsigned int freq) { if (obtainedfreq) { - if (0 /*is_vsync ()*/) { - if (currprefs.ntscmode) - scaled_sample_evtime = (unsigned long)(MAXHPOS_NTSC * MAXVPOS_NTSC * freq * CYCLE_UNIT + obtainedfreq - 1) / obtainedfreq; - else - scaled_sample_evtime = (unsigned long)(MAXHPOS_PAL * MAXVPOS_PAL * freq * CYCLE_UNIT + obtainedfreq - 1) / obtainedfreq; - } else { - scaled_sample_evtime = (unsigned long)(312.0 * 50 * CYCLE_UNIT / (obtainedfreq / 227.0)); - } + if (currprefs.ntscmode) + scaled_sample_evtime = (unsigned long)(MAXHPOS_NTSC * MAXVPOS_NTSC * freq * CYCLE_UNIT + obtainedfreq - 1) / obtainedfreq; + else + scaled_sample_evtime = (unsigned long)(MAXHPOS_PAL * MAXVPOS_PAL * freq * CYCLE_UNIT + obtainedfreq - 1) / obtainedfreq; } } @@ -648,7 +471,7 @@ static void audio_handler (unsigned int INTREQ(0x8000 | (0x80 << nr)); if (cdp->wlen != 1) cdp->wlen = (cdp->wlen - 1) & 0xFFFF; - cdp->nextdat = chipmem_wget (cdp->pt); + cdp->nextdat = chipmem_agnus_wget (cdp->pt); cdp->pt += 2; break; @@ -711,7 +534,7 @@ static void audio_handler (unsigned int cdp->evtime = cdp->per; - if ((INTREQR() & (0x80 << nr)) && !cdp->dmaen) { + if ((INTREQR () & (0x80 << nr)) && !cdp->dmaen) { cdp->state = 0; cdp->evtime = MAX_EV; cdp->last_sample = 0; @@ -780,6 +603,7 @@ void audio_reset (void) int i; struct audio_channel_data *cdp; + memset (sound_filter_state, 0, sizeof sound_filter_state); if (savestate_state != STATE_RESTORE) { for (i = 0; i < 4; i++) { cdp = &audio_channel[i]; @@ -799,7 +623,6 @@ void audio_reset (void) last_cycles = get_cycles (); next_sample_evtime = scaled_sample_evtime; - schedule_audio (); events_schedule (); } @@ -808,30 +631,43 @@ STATIC_INLINE int sound_prefs_changed (v { return (changed_prefs.produce_sound != currprefs.produce_sound || changed_prefs.sound_stereo != currprefs.sound_stereo - || changed_prefs.mixed_stereo != currprefs.mixed_stereo || changed_prefs.sound_maxbsiz != currprefs.sound_maxbsiz - || changed_prefs.sound_freq != currprefs.sound_freq - || changed_prefs.sound_bits != currprefs.sound_bits - || changed_prefs.sound_interpol != currprefs.sound_interpol); + || changed_prefs.sound_freq != currprefs.sound_freq); } void check_prefs_changed_audio (void) { + int old_mixed_on = mixed_on; + int old_mixed_size = mixed_stereo_size; + int sep, delay; + + /* Some options we can just apply without reinitializing the sound + backend. */ + currprefs.sound_interpol = changed_prefs.sound_interpol; + currprefs.sound_filter = changed_prefs.sound_filter; + currprefs.sound_filter_type = changed_prefs.sound_filter_type; + + sep = currprefs.sound_stereo_separation = changed_prefs.sound_stereo_separation; + delay = currprefs.sound_mixed_stereo_delay = changed_prefs.sound_mixed_stereo_delay; + mixed_mul1 = MIXED_STEREO_SCALE / 2 - sep; + mixed_mul2 = MIXED_STEREO_SCALE / 2 + sep; + mixed_stereo_size = delay > 0 ? (1 << (delay - 1)) - 1 : 0; + mixed_on = (sep > 0 && sep < MIXED_STEREO_MAX) || mixed_stereo_size > 0; + if (mixed_on && old_mixed_size != mixed_stereo_size) { + saved_ptr = 0; + memset (right_word_saved, 0, sizeof right_word_saved); + } + if (sound_available && sound_prefs_changed ()) { - close_sound (); + if (currprefs.produce_sound >= 2) + close_sound (); currprefs.produce_sound = changed_prefs.produce_sound; currprefs.sound_stereo = changed_prefs.sound_stereo; - currprefs.mixed_stereo = changed_prefs.mixed_stereo; - currprefs.sound_bits = changed_prefs.sound_bits; currprefs.sound_freq = changed_prefs.sound_freq; - currprefs.sound_interpol = changed_prefs.sound_interpol; currprefs.sound_maxbsiz = changed_prefs.sound_maxbsiz; if (currprefs.produce_sound >= 2) { - if (init_audio ()) { - last_cycles = get_cycles () - 1; - next_sample_evtime = scaled_sample_evtime; - } else + if (!init_audio ()) { if (! sound_available) { write_log ("Sound is not supported.\n"); } else { @@ -840,32 +676,50 @@ void check_prefs_changed_audio (void) /* So we don't do this every frame */ changed_prefs.produce_sound = 0; } + } + next_sample_evtime = scaled_sample_evtime; + last_cycles = get_cycles () - 1; + compute_vsynctime (); + } + if (currprefs.produce_sound == 0) { + eventtab[ev_audio].active = 0; + events_schedule (); } - compute_vsynctime (); } + + led_filter_forced = -1; // always off + sound_use_filter = sound_use_filter_sinc = 0; + if (currprefs.sound_filter != FILTER_SOUND_OFF) { + if (currprefs.sound_filter == FILTER_SOUND_ON) + led_filter_forced = 1; + if (currprefs.sound_filter == FILTER_SOUND_EMUL) + led_filter_forced = 0; + if (currprefs.sound_filter_type == FILTER_SOUND_TYPE_A500) + sound_use_filter = FILTER_MODEL_A500; + else if (currprefs.sound_filter_type == FILTER_SOUND_TYPE_A1200) + sound_use_filter = FILTER_MODEL_A1200; + } + a500e_filter1_a0 = rc_calculate_a0(currprefs.sound_freq, 6200); + a500e_filter2_a0 = rc_calculate_a0(currprefs.sound_freq, 20000); + filter_a0 = rc_calculate_a0(currprefs.sound_freq, 7000); + led_filter_audio(); + /* Select the right interpolation method. */ - if (sample_handler == sample16_handler - || sample_handler == sample16i_crux_handler - || sample_handler == sample16i_rh_handler - || sample_handler == sample16i_sinc_handler) { - sample_handler = (currprefs.sound_interpol == 0 ? sample16_handler - : currprefs.sound_interpol == 1 ? sample16i_rh_handler - : currprefs.sound_interpol == 2 ? sample16i_crux_handler - : sample16i_sinc_handler); - } else if (sample_handler == sample16s_handler - || sample_handler == sample16si_crux_handler - || sample_handler == sample16si_rh_handler - || sample_handler == sample16si_sinc_handler) + if (sample_handler == sample16s_handler + || sample_handler == sample16si_sinc_handler + || sample_handler == sample16si_anti_handler) + { sample_handler = (currprefs.sound_interpol == 0 ? sample16s_handler - : currprefs.sound_interpol == 1 ? sample16si_rh_handler - : currprefs.sound_interpol == 2 ? sample16si_crux_handler - : sample16si_sinc_handler); + : currprefs.sound_interpol == 1 ? sample16si_sinc_handler + : sample16si_anti_handler); + } sample_prehandler = NULL; - if (sample_handler == sample16si_sinc_handler || sample_handler == sample16i_sinc_handler) + if (currprefs.sound_interpol == 1) { + sound_use_filter_sinc = sound_use_filter; + sound_use_filter = 0; sample_prehandler = sinc_prehandler; - if (currprefs.produce_sound == 0) { - eventtab[ev_audio].active = 0; - events_schedule (); + } else if (currprefs.sound_interpol == 2) { + sample_prehandler = anti_prehandler; } } @@ -963,7 +817,7 @@ void audio_hsync (int dmaaction) if (cdp->data_written == 2) { cdp->data_written = 0; - cdp->nextdat = chipmem_wget (cdp->pt); + cdp->nextdat = chipmem_agnus_wget (cdp->pt); cdp->pt += 2; if (cdp->state == 2 || cdp->state == 3) { if (cdp->wlen == 1) { @@ -977,7 +831,7 @@ void audio_hsync (int dmaaction) } } -void AUDxDAT (unsigned int nr, uae_u16 v) +void AUDxDAT (int nr, uae_u16 v) { struct audio_channel_data *cdp = audio_channel + nr; @@ -987,9 +841,9 @@ void AUDxDAT (unsigned int nr, uae_u16 v update_audio (); cdp->dat = v; - if (cdp->state == 0 && !(INTREQR() & (0x80 << nr))) { + if (cdp->state == 0 && !(INTREQR () & (0x80 << nr))) { cdp->state = 2; - INTREQ(0x8000 | (0x80 << nr)); + INTREQ (0x8000 | (0x80 << nr)); /* data_written = 2 ???? */ cdp->evtime = cdp->per; schedule_audio (); @@ -997,21 +851,21 @@ void AUDxDAT (unsigned int nr, uae_u16 v } } -void AUDxLCH (unsigned int nr, uae_u16 v) +void AUDxLCH (int nr, uae_u16 v) { update_audio (); audio_channel[nr].lc = (audio_channel[nr].lc & 0xffff) | ((uae_u32)v << 16); } -void AUDxLCL (unsigned int nr, uae_u16 v) +void AUDxLCL (int nr, uae_u16 v) { update_audio (); audio_channel[nr].lc = (audio_channel[nr].lc & ~0xffff) | (v & 0xFFFE); } -void AUDxPER (unsigned int nr, uae_u16 v) +void AUDxPER (int nr, uae_u16 v) { unsigned long per = v * CYCLE_UNIT; update_audio (); @@ -1040,13 +894,13 @@ void AUDxPER (unsigned int nr, uae_u16 v audio_channel[nr].per = per; } -void AUDxLEN (unsigned int nr, uae_u16 v) +void AUDxLEN (int nr, uae_u16 v) { update_audio (); audio_channel[nr].len = v; } -void AUDxVOL (unsigned int nr, uae_u16 v) +void AUDxVOL (int nr, uae_u16 v) { int v2 = v & 64 ? 63 : v & 63; @@ -1076,6 +930,14 @@ int init_audio (void) return result; } +void led_filter_audio (void) +{ + led_filter_on = 0; + if (led_filter_forced > 0 || (gui_data.powerled && led_filter_forced >= 0)) + led_filter_on = 1; + gui_led (0, gui_data.powerled); +} + /* audio save/restore code FIXME: not working correctly */ /* help needed */