--- uae/src/audio.c 2018/04/24 17:14:06 1.1.1.15 +++ uae/src/audio.c 2018/04/24 17:16:19 1.1.1.16 @@ -1,17 +1,19 @@ /* * UAE - The Un*x Amiga Emulator * - * OS specific functions + * Paula audio emulation * * Copyright 1995, 1996, 1997 Bernd Schmidt * Copyright 1996 Marcus Sundberg * Copyright 1996 Manfred Thole + * Copyright 2006 Toni Wilen + * + * new filter algorithm and anti&sinc interpolators by Antti S. Lankila */ #include "sysconfig.h" #include "sysdeps.h" -#include "config.h" #include "options.h" #include "memory.h" #include "custom.h" @@ -22,17 +24,54 @@ #include "events.h" #include "audio.h" #include "savestate.h" +#include "sinctable.h" +#include "gui.h" + +#define MAX_EV ~0ul -struct audio_channel_data audio_channel[4]; +/* periods less than this value are replaced by this value. */ +#define MIN_ALLOWED_PERIOD 16 +/* reserve ~20 extra slots in sinc queue for cpu volume or some such updates + * even at maximum period. This avoids sinc queue overflow on games like + * battle squadron that write these low period values and do cpu-based + * updates on paula registers, probably volume. */ +#define NUMBER_OF_CPU_UPDATES_ALLOWED 20 + +#define SINC_QUEUE_LENGTH (SINC_QUEUE_MAX_AGE / MIN_ALLOWED_PERIOD + NUMBER_OF_CPU_UPDATES_ALLOWED) + +typedef struct { + int age; + int output; +} sinc_queue_t; + +struct audio_channel_data { + unsigned long adk_mask; + unsigned long evtime; + unsigned long per; + uae_u8 dmaen, intreq2, data_written; + uaecptr lc, pt; + int state, wper; + unsigned int wlen; + int current_sample, last_sample; + int vol; + int *voltbl; + uae_u16 dat, nextdat, len; + int sinc_output_state; + sinc_queue_t sinc_queue[SINC_QUEUE_LENGTH]; + int sinc_queue_length; +}; + +static struct audio_channel_data audio_channel[4]; int sound_available = 0; int sound_table[64][256]; void (*sample_handler) (void); +static void (*sample_prehandler) (unsigned long best_evtime); -unsigned long sample_evtime, scaled_sample_evtime; -int scaled_sample_evtime_ok; - +static unsigned long scaled_sample_evtime; static unsigned long last_cycles, next_sample_evtime; +unsigned int obtainedfreq; + void init_sound_table16 (void) { int i,j; @@ -42,29 +81,16 @@ void init_sound_table16 (void) sound_table[j][i] = j * (uae_s8)i * (currprefs.sound_stereo ? 2 : 1); } -void init_sound_table8 (void) -{ - int i,j; - - 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)) / 256; -} - -#define MULTIPLICATION_PROFITABLE - #ifdef MULTIPLICATION_PROFITABLE typedef uae_s8 sample8_t; #define DO_CHANNEL_1(v, c) do { (v) *= audio_channel[c].vol; } while (0) -#define SBASEVAL8(logn) ((logn) == 1 ? SOUND8_BASE_VAL << 7 : SOUND8_BASE_VAL << 8) #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); #else typedef uae_u8 sample8_t; #define DO_CHANNEL_1(v, c) do { (v) = audio_channel[c].voltbl[(v)]; } while (0) -#define SBASEVAL8(logn) SOUND8_BASE_VAL #define SBASEVAL16(logn) SOUND16_BASE_VAL -#define FINISH_DATA(b,logn) +#define FINISH_DATA(data,b,logn) #endif /* Always put the right word before the left word. */ @@ -106,6 +132,94 @@ STATIC_INLINE void put_sound_word_left ( #define DO_CHANNEL(v, c) do { (v) &= audio_channel[c].adk_mask; data += v; } while (0); +static void sinc_prehandler (unsigned long best_evtime) +{ + int i, j, output; + struct audio_channel_data *acd; + + for (i = 0; i < 4; i++) { + acd = &audio_channel[i]; + output = (acd->current_sample * acd->vol) & acd->adk_mask; + + /* age the sinc queue and truncate it when necessary */ + for (j = 0; j < acd->sinc_queue_length; j += 1) { + acd->sinc_queue[j].age += best_evtime; + if (acd->sinc_queue[j].age >= SINC_QUEUE_MAX_AGE) { + acd->sinc_queue_length = j; + break; + } + } + /* if output state changes, record the state change and also + * write data into sinc queue for mixing in the BLEP */ + if (acd->sinc_output_state != output) { + if (acd->sinc_queue_length > SINC_QUEUE_LENGTH - 1) { + write_log ("warning: sinc queue truncated. Last age: %d.\n", + acd->sinc_queue[SINC_QUEUE_LENGTH-1].age); + acd->sinc_queue_length = SINC_QUEUE_LENGTH - 1; + } + /* make room for new and add the new value */ + memmove (&acd->sinc_queue[1], &acd->sinc_queue[0], + sizeof(acd->sinc_queue[0]) * acd->sinc_queue_length); + acd->sinc_queue_length += 1; + acd->sinc_queue[0].age = best_evtime; + acd->sinc_queue[0].output = output - acd->sinc_output_state; + acd->sinc_output_state = output; + } + } +} + + +/* this interpolator performs BLEP mixing (bleps are shaped like integrated sinc + * functions) with a type of BLEP that matches the filtering configuration. */ +STATIC_INLINE void samplexx_sinc_handler (int *datasp) +{ + 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) + n += 1; + } else { + n = 4; + } +#endif + winsinc = winsinc_integral[n]; + + for (i = 0; i < 4; i += 1) { + int j, v; + struct audio_channel_data *acd = &audio_channel[i]; + /* The sum rings with harmonic components up to infinity... */ + int sum = acd->sinc_output_state << 17; + /* ...but we cancel them through mixing in BLEPs instead */ + for (j = 0; j < acd->sinc_queue_length; j += 1) + sum -= winsinc[acd->sinc_queue[j].age] * acd->sinc_queue[j].output; + v = sum >> 17; + if (v > 32767) + v = 32767; + else if (v < -32768) + v = -32768; + datasp[i] = v; + } +} + +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) { uae_u32 data0 = audio_channel[0].current_sample; @@ -131,7 +245,7 @@ void sample16_handler (void) check_sound_buffers (); } -void sample16i_rh_handler (void) +static void sample16i_rh_handler (void) { unsigned long delta, ratio; @@ -184,7 +298,7 @@ void sample16i_rh_handler (void) check_sound_buffers (); } -void sample16i_crux_handler (void) +static void sample16i_crux_handler (void) { uae_u32 data0 = audio_channel[0].current_sample; uae_u32 data1 = audio_channel[1].current_sample; @@ -255,33 +369,21 @@ void sample16i_crux_handler (void) check_sound_buffers (); } -void sample8_handler (void) +#ifdef HAVE_STEREO_SUPPORT +static void sample16si_sinc_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 = SBASEVAL8(2) + data0; - FINISH_DATA (data, 8, 2); - PUT_SOUND_BYTE (data); - } + int datas[4], data1, data2; + samplexx_sinc_handler (datas); + data1 = datas[0] + datas[3]; + data2 = datas[1] + datas[2]; + FINISH_DATA (data1, 16, 1); + put_sound_word_left (data1); + FINISH_DATA (data2, 16, 1); + put_sound_word_right (data2); check_sound_buffers (); } -#ifdef HAVE_STEREO_SUPPORT void sample16s_handler (void) { uae_u32 data0 = audio_channel[0].current_sample; @@ -315,7 +417,7 @@ void sample16s_handler (void) check_sound_buffers (); } -void sample16si_crux_handler (void) +static void sample16si_crux_handler (void) { uae_u32 data0 = audio_channel[0].current_sample; uae_u32 data1 = audio_channel[1].current_sample; @@ -392,7 +494,7 @@ void sample16si_crux_handler (void) check_sound_buffers (); } -void sample16si_rh_handler (void) +static void sample16si_rh_handler (void) { unsigned long delta, ratio; @@ -450,117 +552,56 @@ void sample16si_rh_handler (void) check_sound_buffers (); } -void sample8s_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 += data3; - { - uae_u32 data = SBASEVAL8(1) + data0; - FINISH_DATA (data, 8, 1); - PUT_SOUND_BYTE_RIGHT (data); - } - data1 += data2; - { - uae_u32 data = SBASEVAL8(1) + data1; - FINISH_DATA (data, 8, 1); - PUT_SOUND_BYTE_LEFT (data); - } - - check_sound_buffers (); -} #else -void sample8s_handler (void) -{ - sample8_handler(); -} void sample16s_handler (void) { - sample16_handler(); + sample16_handler (); } -void sample16si_crux_handler (void) +static void sample16si_crux_handler (void) { - sample16i_crux_handler(); + sample16i_crux_handler (); } -void sample16si_rh_handler (void) +static void sample16si_rh_handler (void) { - sample16i_rh_handler(); + sample16i_rh_handler (); } #endif -static uae_u8 int2ulaw (int ch) +void switch_audio_interpol (void) { - int mask; +#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 (ch < 0) { - ch = -ch; - mask = 0x7f; - } - else { - mask = 0xff; - } - - if (ch < 32) { - ch = 0xF0 | ( 15 - (ch/2) ); - } else if (ch < 96) { - ch = 0xE0 | ( 15 - (ch-32)/4 ); - } else if (ch < 224) { - ch = 0xD0 | ( 15 - (ch-96)/8 ); - } else if (ch < 480) { - ch = 0xC0 | ( 15 - (ch-224)/16 ); - } else if (ch < 992 ) { - ch = 0xB0 | ( 15 - (ch-480)/32 ); - } else if (ch < 2016) { - ch = 0xA0 | ( 15 - (ch-992)/64 ); - } else if (ch < 4064) { - ch = 0x90 | ( 15 - (ch-2016)/128 ); - } else if (ch < 8160) { - ch = 0x80 | ( 15 - (ch-4064)/256 ); + if (currprefs.sound_interpol == 0) { + changed_prefs.sound_interpol = 1; + write_log ("Interpol on: rh\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"); } else { - ch = 0x80; + changed_prefs.sound_interpol = 0; + write_log ("Interpol off\n"); } - return (uae_u8)(mask & ch); -} - -void sample_ulaw_handler (void) -{ - int nr; - uae_u32 data = 0; - - for (nr = 0; nr < 4; nr++) { - if (!(adkcon & (0x11 << nr))) { - uae_u32 d = audio_channel[nr].current_sample; - DO_CHANNEL_1 (d, nr); - data += d; - } - } - PUT_SOUND_BYTE (int2ulaw (data)); - check_sound_buffers (); + return; } - + void schedule_audio (void) { - unsigned long best = ~0ul; + unsigned long best = MAX_EV; int i; eventtab[ev_audio].active = 0; eventtab[ev_audio].oldcycles = get_cycles (); - for (i = 0; i < 6; i++) { + for (i = 0; i < 4; i++) { struct audio_channel_data *cdp = audio_channel + i; - if (cdp->state != 0) { + if (cdp->evtime != MAX_EV) { if (best > cdp->evtime) { best = cdp->evtime; eventtab[ev_audio].active = 1; @@ -570,10 +611,30 @@ void schedule_audio (void) eventtab[ev_audio].evtime = get_cycles () + best; } -static void audio_handler (int nr) +/* + * TODO: This function has been moved here from the audio back-end layer + * since it was common to all. + * Needs further cleaning up and a better name - or replacing entirely. + */ +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)); + } + } +} + +static void audio_handler (unsigned int nr) { struct audio_channel_data *cdp = audio_channel + nr; + cdp->evtime = MAX_EV; switch (cdp->state) { case 0: write_log ("Bug in sound code\n"); @@ -652,6 +713,7 @@ static void audio_handler (int nr) if ((INTREQR() & (0x80 << nr)) && !cdp->dmaen) { cdp->state = 0; + cdp->evtime = MAX_EV; cdp->last_sample = 0; cdp->current_sample = 0; break; @@ -691,26 +753,9 @@ static void audio_handler (int nr) } } -void aud0_handler (void) -{ - audio_handler (0); -} -void aud1_handler (void) -{ - audio_handler (1); -} -void aud2_handler (void) -{ - audio_handler (2); -} -void aud3_handler (void) -{ - audio_handler (3); -} - -void audio_channel_enable_dma (struct audio_channel_data *cdp) +static void audio_channel_enable_dma (struct audio_channel_data *cdp) { - if (cdp->state == 0) { + if (cdp->evtime == MAX_EV) { cdp->state = 1; cdp->pt = cdp->lc; cdp->wper = cdp->per; @@ -720,10 +765,11 @@ void audio_channel_enable_dma (struct au } } -void audio_channel_disable_dma (struct audio_channel_data *cdp) +static void audio_channel_disable_dma (struct audio_channel_data *cdp) { if (cdp->state == 1 || cdp->state == 5) { cdp->state = 0; + cdp->evtime = MAX_EV; cdp->last_sample = 0; cdp->current_sample = 0; } @@ -732,29 +778,30 @@ void audio_channel_disable_dma (struct a void audio_reset (void) { int i; + struct audio_channel_data *cdp; + if (savestate_state != STATE_RESTORE) { - memset (audio_channel, 0, 4 * sizeof *audio_channel); - audio_channel[0].per = PERIOD_MAX; - audio_channel[1].per = PERIOD_MAX; - audio_channel[2].per = PERIOD_MAX; - audio_channel[3].per = PERIOD_MAX; - audio_channel[0].voltbl = sound_table[0]; - audio_channel[1].voltbl = sound_table[0]; - audio_channel[2].voltbl = sound_table[0]; - audio_channel[3].voltbl = sound_table[0]; + for (i = 0; i < 4; i++) { + cdp = &audio_channel[i]; + memset (cdp, 0, sizeof *audio_channel); + cdp->per = PERIOD_MAX; + cdp->vol = 0; + cdp->evtime = MAX_EV; + } } else for (i = 0; i < 4; i++) audio_channel[i].dmaen = (dmacon & 0x200) && (dmacon & (1 << i)); #ifndef MULTIPLICATION_PROFITABLE for (i = 0; i < 4; i++) - audio_channel[nr].voltbl = sound_table[audio_channel[nr].vol]; + audio_channel[i].voltbl = sound_table[audio_channel[i].vol]; #endif - last_cycles = 0; + last_cycles = get_cycles (); next_sample_evtime = scaled_sample_evtime; schedule_audio (); + events_schedule (); } STATIC_INLINE int sound_prefs_changed (void) @@ -764,7 +811,8 @@ STATIC_INLINE int sound_prefs_changed (v || 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_bits != currprefs.sound_bits + || changed_prefs.sound_interpol != currprefs.sound_interpol); } void check_prefs_changed_audio (void) @@ -777,6 +825,7 @@ void check_prefs_changed_audio (void) 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 ()) { @@ -797,16 +846,23 @@ void check_prefs_changed_audio (void) /* Select the right interpolation method. */ if (sample_handler == sample16_handler || sample_handler == sample16i_crux_handler - || sample_handler == sample16i_rh_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 - : sample16i_crux_handler); - else if (sample_handler == sample16s_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_rh_handler + || sample_handler == sample16si_sinc_handler) sample_handler = (currprefs.sound_interpol == 0 ? sample16s_handler : currprefs.sound_interpol == 1 ? sample16si_rh_handler - : sample16si_crux_handler); + : currprefs.sound_interpol == 2 ? sample16si_crux_handler + : sample16si_sinc_handler); + sample_prehandler = NULL; + if (sample_handler == sample16si_sinc_handler || sample_handler == sample16i_sinc_handler) + sample_prehandler = sinc_prehandler; if (currprefs.produce_sound == 0) { eventtab[ev_audio].active = 0; events_schedule (); @@ -823,13 +879,13 @@ void update_audio (void) n_cycles = get_cycles () - last_cycles; for (;;) { unsigned long int best_evtime = n_cycles + 1; - if (audio_channel[0].state != 0 && best_evtime > audio_channel[0].evtime) + if (audio_channel[0].evtime != MAX_EV && best_evtime > audio_channel[0].evtime) best_evtime = audio_channel[0].evtime; - if (audio_channel[1].state != 0 && best_evtime > audio_channel[1].evtime) + if (audio_channel[1].evtime != MAX_EV && best_evtime > audio_channel[1].evtime) best_evtime = audio_channel[1].evtime; - if (audio_channel[2].state != 0 && best_evtime > audio_channel[2].evtime) + if (audio_channel[2].evtime != MAX_EV && best_evtime > audio_channel[2].evtime) best_evtime = audio_channel[2].evtime; - if (audio_channel[3].state != 0 && best_evtime > audio_channel[3].evtime) + if (audio_channel[3].evtime != MAX_EV && best_evtime > audio_channel[3].evtime) best_evtime = audio_channel[3].evtime; if (currprefs.produce_sound > 1 && best_evtime > next_sample_evtime) best_evtime = next_sample_evtime; @@ -837,28 +893,55 @@ void update_audio (void) if (best_evtime > n_cycles) break; - next_sample_evtime -= best_evtime; - audio_channel[0].evtime -= best_evtime; - audio_channel[1].evtime -= best_evtime; - audio_channel[2].evtime -= best_evtime; - audio_channel[3].evtime -= best_evtime; + if (audio_channel[0].evtime != MAX_EV) + audio_channel[0].evtime -= best_evtime; + if (audio_channel[1].evtime != MAX_EV) + audio_channel[1].evtime -= best_evtime; + if (audio_channel[2].evtime != MAX_EV) + audio_channel[2].evtime -= best_evtime; + if (audio_channel[3].evtime != MAX_EV) + audio_channel[3].evtime -= best_evtime; n_cycles -= best_evtime; - if (next_sample_evtime == 0 && currprefs.produce_sound > 1) { - next_sample_evtime = scaled_sample_evtime; - (*sample_handler) (); + if (currprefs.produce_sound > 1) { + next_sample_evtime -= best_evtime; + if (sample_prehandler) + sample_prehandler (best_evtime / CYCLE_UNIT); + if (next_sample_evtime == 0) { + next_sample_evtime = scaled_sample_evtime; + (*sample_handler) (); + } } - if (audio_channel[0].evtime == 0 && audio_channel[0].state != 0) + if (audio_channel[0].evtime == 0) audio_handler (0); - if (audio_channel[1].evtime == 0 && audio_channel[1].state != 0) + if (audio_channel[1].evtime == 0) audio_handler (1); - if (audio_channel[2].evtime == 0 && audio_channel[2].state != 0) + if (audio_channel[2].evtime == 0) audio_handler (2); - if (audio_channel[3].evtime == 0 && audio_channel[3].state != 0) + if (audio_channel[3].evtime == 0) audio_handler (3); } last_cycles = get_cycles () - n_cycles; } +void update_audio_dmacon (void) +{ + unsigned int i; + update_audio (); + + for (i = 0; i < 4; i++) { + struct audio_channel_data *cdp = audio_channel + i; + int chan_ena = (dmacon & 0x200) && (dmacon & (1<dmaen == chan_ena) + continue; + cdp->dmaen = chan_ena; + if (cdp->dmaen) + audio_channel_enable_dma (cdp); + else + audio_channel_disable_dma (cdp); + } + schedule_audio (); +} + void audio_evhandler (void) { if (currprefs.produce_sound == 0) @@ -894,7 +977,7 @@ void audio_hsync (int dmaaction) } } -void AUDxDAT (int nr, uae_u16 v) +void AUDxDAT (unsigned int nr, uae_u16 v) { struct audio_channel_data *cdp = audio_channel + nr; @@ -914,21 +997,21 @@ void AUDxDAT (int nr, uae_u16 v) } } -void AUDxLCH (int nr, uae_u16 v) +void AUDxLCH (unsigned int nr, uae_u16 v) { update_audio (); audio_channel[nr].lc = (audio_channel[nr].lc & 0xffff) | ((uae_u32)v << 16); } -void AUDxLCL (int nr, uae_u16 v) +void AUDxLCL (unsigned int nr, uae_u16 v) { update_audio (); audio_channel[nr].lc = (audio_channel[nr].lc & ~0xffff) | (v & 0xFFFE); } -void AUDxPER (int nr, uae_u16 v) +void AUDxPER (unsigned int nr, uae_u16 v) { unsigned long per = v * CYCLE_UNIT; update_audio (); @@ -938,26 +1021,32 @@ void AUDxPER (int nr, uae_u16 v) if (per < maxhpos * CYCLE_UNIT / 2 && currprefs.produce_sound < 3) per = maxhpos * CYCLE_UNIT / 2; + /* the sinc code registers paula output state changes, but has a finite + * buffer in which to do so. Hence, we forbid very low values; this should + * only limit the accurate rendering of supersonic sounds, which are + * filtered away on the sinc output path anyway. */ + if (currprefs.produce_sound == 3 && sample_handler == sample16si_sinc_handler && per < MIN_ALLOWED_PERIOD * CYCLE_UNIT) + per = MIN_ALLOWED_PERIOD * CYCLE_UNIT; - if (audio_channel[nr].per == PERIOD_MAX - && per != PERIOD_MAX) - { + if (audio_channel[nr].per == PERIOD_MAX && per != PERIOD_MAX + && audio_channel[nr].evtime != MAX_EV) { audio_channel[nr].evtime = CYCLE_UNIT; if (currprefs.produce_sound > 0) { schedule_audio (); events_schedule (); } } + audio_channel[nr].per = per; } -void AUDxLEN (int nr, uae_u16 v) +void AUDxLEN (unsigned int nr, uae_u16 v) { update_audio (); audio_channel[nr].len = v; } -void AUDxVOL (int nr, uae_u16 v) +void AUDxVOL (unsigned int nr, uae_u16 v) { int v2 = v & 64 ? 63 : v & 63; @@ -982,20 +1071,15 @@ void update_adkmasks (void) int init_audio (void) { - int retval; - /* Some backward compatibility hacks until every port initializes - scaled_sample_evtime... */ - scaled_sample_evtime_ok = 0; - retval = init_sound (); - if (! scaled_sample_evtime_ok) - scaled_sample_evtime = sample_evtime * CYCLE_UNIT; - return retval; + int result = init_sound (); + update_sound (vblank_hz); + return result; } /* audio save/restore code FIXME: not working correctly */ /* help needed */ -uae_u8 *restore_audio (int i, uae_u8 *src) +const uae_u8 *restore_audio (int i, const uae_u8 *src) { struct audio_channel_data *acd; uae_u16 p;