--- uae/src/audio.c 2018/04/24 16:39:49 1.1 +++ uae/src/audio.c 2018/04/24 16:47:17 1.1.1.5 @@ -36,14 +36,14 @@ unsigned long sh_count = 0; #endif -int sound_available = 0; - struct audio_channel_data audio_channel[4]; - +int sound_available = 0; int sound_table[64][256]; +void (*sample_handler) (void); unsigned long int sample_evtime; +static unsigned long last_cycles, next_sample_evtime; -void init_sound_table16(void) +void init_sound_table16 (void) { int i,j; @@ -61,41 +61,6 @@ void init_sound_table8 (void) sound_table[j][i] = (j * (uae_s8)i * (currprefs.stereo ? 2 : 1)) / 256; } -void AUDxDAT(int nr, uae_u16 v) -{ - struct audio_channel_data *cdp = audio_channel + nr; - cdp->dat = v; - if (cdp->state == 0 && !(INTREQR() & (0x80 << nr))) { - cdp->state = 2; - INTREQ(0x8000 | (0x80 << nr)); - /* data_written = 2 ???? */ - eventtab[ev_aud0 + nr].evtime = cycles + cdp->per; - eventtab[ev_aud0 + nr].oldcycles = cycles; - eventtab[ev_aud0 + nr].active = 1; - events_schedule(); - } -} - -void AUDxLCH(int nr, uae_u16 v) { audio_channel[nr].lc = (audio_channel[nr].lc & 0xffff) | ((uae_u32)v << 16); } -void AUDxLCL(int nr, uae_u16 v) { audio_channel[nr].lc = (audio_channel[nr].lc & ~0xffff) | (v & 0xFFFE); } -void AUDxPER(int nr, uae_u16 v) -{ - if (v <= 0) { -#if 0 /* v == 0 is rather common, and harmless, and the value isn't signed anyway */ - static int warned = 0; - if (!warned) - write_log ("Broken program accessing the sound hardware\n"), warned++; -#endif - v = 65535; - } - if (v < maxhpos/2 && currprefs.produce_sound < 3) - v = maxhpos/2; - - audio_channel[nr].per = v; -} - -void AUDxLEN(int nr, uae_u16 v) { audio_channel[nr].len = v; } - #define MULTIPLICATION_PROFITABLE #ifdef MULTIPLICATION_PROFITABLE @@ -112,19 +77,9 @@ typedef uae_u8 sample8_t; #define FINISH_DATA(b,logn) #endif -void AUDxVOL(int nr, uae_u16 v) -{ - int v2 = v & 64 ? 63 : v & 63; - audio_channel[nr].vol = v2; -#ifndef MULTIPLICATION_PROFITABLE - audio_channel[nr].voltbl = sound_table[v2]; -#endif -} - #define DO_CHANNEL(v, c) do { (v) &= audio_channel[c].adk_mask; data += v; } while (0); -/* Templates! I want templates! */ -void sample16_handler(void) +void sample16_handler (void) { BEGIN_BENCH @@ -151,12 +106,65 @@ void sample16_handler(void) END_BENCH check_sound_buffers (); +} + +void sample16i_handler (void) +{ + unsigned long delta, ratio; + + BEGIN_BENCH - eventtab[ev_sample].evtime = cycles + sample_evtime; - eventtab[ev_sample].oldcycles = cycles; + 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(16, 2); + PUT_SOUND_WORD (data); + } + END_BENCH + + check_sound_buffers (); } -void sample8_handler(void) +void sample8_handler (void) { BEGIN_BENCH @@ -183,13 +191,10 @@ void sample8_handler(void) END_BENCH check_sound_buffers (); - - eventtab[ev_sample].evtime = cycles + sample_evtime; - eventtab[ev_sample].oldcycles = cycles; } #ifdef HAVE_STEREO_SUPPORT -void sample16s_handler(void) +void sample16s_handler (void) { BEGIN_BENCH @@ -224,12 +229,109 @@ void sample16s_handler(void) END_BENCH check_sound_buffers (); +} + +void sample16si_handler (void) +{ + unsigned long delta, ratio; + + BEGIN_BENCH + + 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; + +# if 0 + /* 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; +#else + { + struct audio_channel_data *cdp; + int ratio, ratio1; +#define INTERVAL (sample_evtime) + cdp = audio_channel + 0; + ratio1 = cdp->per - cdp->evtime; + ratio = (ratio1 << 12) / INTERVAL; + if (cdp->evtime < 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 < 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 < 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 < sample_evtime || ratio1 >= INTERVAL) + ratio = 4096; + data3 = (data3 * ratio + data3p * (4096 - ratio)) >> 12; + } + data1 += data2; + data0 += data3; +#endif + { + uae_u32 data = SBASEVAL16 (1) + data0; + FINISH_DATA (16, 1); + PUT_SOUND_WORD_RIGHT (data); + } - eventtab[ev_sample].evtime = cycles + sample_evtime; - eventtab[ev_sample].oldcycles = cycles; + { + uae_u32 data = SBASEVAL16 (1) + data1; + FINISH_DATA (16, 1); + PUT_SOUND_WORD_LEFT (data); + } + + END_BENCH + + check_sound_buffers (); } -void sample8s_handler(void) +void sample8s_handler (void) { BEGIN_BENCH @@ -263,22 +365,19 @@ void sample8s_handler(void) END_BENCH check_sound_buffers (); - - eventtab[ev_sample].evtime = cycles + sample_evtime; - eventtab[ev_sample].oldcycles = cycles; } #else -void sample8s_handler(void) +void sample8s_handler (void) { sample8_handler(); } -void sample16s_handler(void) +void sample16s_handler (void) { sample16_handler(); } #endif -static uae_u8 int2ulaw(int ch) +static uae_u8 int2ulaw (int ch) { int mask; @@ -317,9 +416,6 @@ void sample_ulaw_handler (void) int nr; uae_u32 data = 0; - eventtab[ev_sample].evtime += cycles - eventtab[ev_sample].oldcycles; - eventtab[ev_sample].oldcycles = cycles; - for (nr = 0; nr < 4; nr++) { if (!(adkcon & (0x11 << nr))) { uae_u32 d = audio_channel[nr].current_sample; @@ -342,8 +438,7 @@ static void audio_handler (int nr) case 1: /* We come here at the first hsync after DMA was turned on. */ - eventtab[ev_aud0 + nr].evtime += maxhpos; - eventtab[ev_aud0 + nr].oldcycles += maxhpos; + cdp->evtime = maxhpos; cdp->state = 5; INTREQ(0x8000 | (0x80 << nr)); @@ -359,9 +454,9 @@ static void audio_handler (int nr) if (currprefs.produce_sound == 0) cdp->per = 65535; - eventtab[ev_aud0 + nr].evtime = cycles + cdp->per; - eventtab[ev_aud0 + nr].oldcycles = cycles; + cdp->evtime = cdp->per; cdp->dat = cdp->nextdat; + cdp->last_sample = cdp->current_sample; cdp->current_sample = (sample8_t)(cdp->dat >> 8); cdp->state = 2; @@ -379,9 +474,9 @@ static void audio_handler (int nr) if (currprefs.produce_sound == 0) cdp->per = 65535; + cdp->last_sample = cdp->current_sample; cdp->current_sample = (sample8_t)(cdp->dat & 0xFF); - eventtab[ev_aud0 + nr].evtime = cycles + cdp->per; - eventtab[ev_aud0 + nr].oldcycles = cycles; + cdp->evtime = cdp->per; cdp->state = 3; @@ -411,13 +506,12 @@ static void audio_handler (int nr) if (currprefs.produce_sound == 0) cdp->per = 65535; - eventtab[ev_aud0 + nr].evtime = cycles + cdp->per; - eventtab[ev_aud0 + nr].oldcycles = cycles; + cdp->evtime = cdp->per; if ((INTREQR() & (0x80 << nr)) && !cdp->dmaen) { cdp->state = 0; + cdp->last_sample = 0; cdp->current_sample = 0; - eventtab[ev_aud0 + nr].active = 0; break; } else { int audav = adkcon & (1 << nr); @@ -431,6 +525,7 @@ static void audio_handler (int nr) cdp->intreq2 = 0; cdp->dat = cdp->nextdat; + cdp->last_sample = cdp->current_sample; cdp->current_sample = (sample8_t)(cdp->dat >> 8); if (cdp->dmaen && napnav) @@ -450,7 +545,6 @@ static void audio_handler (int nr) default: cdp->state = 0; - eventtab[ev_aud0 + nr].active = 0; break; } } @@ -483,6 +577,155 @@ void audio_reset (void) audio_channel[1].voltbl = sound_table[0]; audio_channel[2].voltbl = sound_table[0]; audio_channel[3].voltbl = sound_table[0]; + + last_cycles = 0; + next_sample_evtime = sample_evtime; +} + +static __inline__ int sound_prefs_changed (void) +{ + return (changed_prefs.produce_sound != currprefs.produce_sound + || changed_prefs.stereo != currprefs.stereo + || changed_prefs.sound_freq != currprefs.sound_freq + || changed_prefs.sound_bits != currprefs.sound_bits); +} + +void check_prefs_changed_audio (void) +{ + if (! sound_available || ! sound_prefs_changed ()) + return; + + close_sound (); + + currprefs.produce_sound = changed_prefs.produce_sound; + currprefs.stereo = changed_prefs.stereo; + currprefs.sound_bits = changed_prefs.sound_bits; + currprefs.sound_freq = changed_prefs.sound_freq; + + if (currprefs.produce_sound < 2) + return; + + if (init_sound ()) { + last_cycles = cycles - 1; + next_sample_evtime = sample_evtime; + return; + } + if (! sound_available) { + fprintf (stderr, "Sound is not supported.\n"); + } else { + fprintf (stderr, "Sorry, can't initialize sound.\n"); + currprefs.produce_sound = 0; + /* So we don't do this every frame */ + changed_prefs.produce_sound = 0; + } +} + +void update_audio (void) +{ + unsigned long int n_cycles; + + if (currprefs.produce_sound < 2) + return; + + n_cycles = cycles - last_cycles; + for (;;) { + int best = -1; + unsigned long int best_evtime = n_cycles + 1; + if (audio_channel[0].state != 0 && best_evtime > audio_channel[0].evtime) + best = 0, best_evtime = audio_channel[0].evtime; + if (audio_channel[1].state != 0 && best_evtime > audio_channel[1].evtime) + best = 1, best_evtime = audio_channel[1].evtime; + if (audio_channel[2].state != 0 && best_evtime > audio_channel[2].evtime) + best = 2, best_evtime = audio_channel[2].evtime; + if (audio_channel[3].state != 0 && best_evtime > audio_channel[3].evtime) + best = 3, best_evtime = audio_channel[3].evtime; + if (best_evtime > next_sample_evtime) + best_evtime = next_sample_evtime; + + 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; + n_cycles -= best_evtime; + if (next_sample_evtime == 0 && currprefs.produce_sound > 1) { + next_sample_evtime = sample_evtime; + (*sample_handler) (); + } + if (audio_channel[0].evtime == 0 && audio_channel[0].state != 0) + audio_handler (0); + if (audio_channel[1].evtime == 0 && audio_channel[1].state != 0) + audio_handler (1); + if (audio_channel[2].evtime == 0 && audio_channel[2].state != 0) + audio_handler (2); + if (audio_channel[3].evtime == 0 && audio_channel[3].state != 0) + audio_handler (3); + } + last_cycles = cycles - n_cycles; +} + +void AUDxDAT (int nr, uae_u16 v) +{ + struct audio_channel_data *cdp = audio_channel + nr; + + update_audio (); + + cdp->dat = v; + if (cdp->state == 0 && !(INTREQR() & (0x80 << nr))) { + cdp->state = 2; + INTREQ(0x8000 | (0x80 << nr)); + /* data_written = 2 ???? */ + cdp->evtime = cdp->per; + } +} + +void AUDxLCH (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) +{ + update_audio (); + + audio_channel[nr].lc = (audio_channel[nr].lc & ~0xffff) | (v & 0xFFFE); +} + +void AUDxPER (int nr, uae_u16 v) +{ + update_audio (); + + if (v == 0) + v = 65535; + + if (v < maxhpos/2 && currprefs.produce_sound < 3) + v = maxhpos/2; + + audio_channel[nr].per = v; +} + +void AUDxLEN (int nr, uae_u16 v) +{ + update_audio (); + + audio_channel[nr].len = v; +} + +void AUDxVOL (int nr, uae_u16 v) +{ + int v2 = v & 64 ? 63 : v & 63; + + update_audio (); + + audio_channel[nr].vol = v2; +#ifndef MULTIPLICATION_PROFITABLE + audio_channel[nr].voltbl = sound_table[v2]; +#endif } void dump_audio_bench (void)