]> git.unchartedbackwaters.co.uk Git - francis/winuae.git/commitdiff
CD audio Paula audio mixing hang. Direct jumps replaced with dynamic callback function.
authorToni Wilen <twilen@winuae.net>
Fri, 16 Sep 2016 14:33:04 +0000 (17:33 +0300)
committerToni Wilen <twilen@winuae.net>
Fri, 16 Sep 2016 14:33:04 +0000 (17:33 +0300)
audio.cpp
include/audio.h
od-win32/sounddep/sound.cpp
sndboard.cpp

index a7e5a473580a23754c51f0fb05fe82d646355354..b014de1d55951d878cd6bcbe220b7553692e5b7a 100644 (file)
--- a/audio.cpp
+++ b/audio.cpp
@@ -98,6 +98,7 @@ struct audio_stream_data
        bool active;
        unsigned int evtime;
        struct audio_channel_data2 data[AUDIO_CHANNEL_MAX_STREAM_CH];
+       SOUND_STREAM_CALLBACK cb;
 };
 
 struct audio_channel_data
@@ -1644,7 +1645,15 @@ static void audio_state_channel (int nr, bool perfin)
                audio_state_channel2 (nr, perfin);
                cdp->dat_written = false;
        } else {
-               audio_state_stream(nr - AUDIO_CHANNELS_PAULA + 1);
+               bool ok = false;
+               int streamid = nr - AUDIO_CHANNELS_PAULA + 1;
+               struct audio_stream_data *asd = &audio_stream[nr - AUDIO_CHANNELS_PAULA];
+               if (asd->cb) {
+                       ok = asd->cb(streamid);
+               }
+               if (!ok) {
+                       audio_state_stream_state(streamid, NULL, 0, MAX_EV);
+               }
        }
 }
 
@@ -2362,7 +2371,7 @@ static void audio_set_extra_channels(void)
        set_extra_prehandler();
 }
 
-int audio_enable_stream(bool enable, int streamid, int ch)
+int audio_enable_stream(bool enable, int streamid, int ch, SOUND_STREAM_CALLBACK cb)
 {
        if (streamid == 0)
                return 0;
@@ -2386,6 +2395,7 @@ int audio_enable_stream(bool enable, int streamid, int ch)
                }
                audio_extra_streams[streamid] = ch;
                struct audio_stream_data *asd = audio_stream + streamid;
+               asd->cb = cb;
                asd->evtime = CYCLE_UNIT;
                for (int i = 0; i < ch; i++) {
                        struct audio_channel_data2 *acd = &asd->data[i];
@@ -2409,7 +2419,7 @@ void audio_state_stream_state(int streamid, int *samplep, int highestch, unsigne
        for (int i = 0; i < audio_extra_streams[streamid]; i++) {
                struct audio_channel_data2 *acd = &asd->data[i];
                acd->last_sample = acd->current_sample;
-               acd->current_sample = samplep[i];
+               acd->current_sample = samplep ? samplep[i] : 0;
        }
        asd->evtime = evt;
 }
@@ -2439,6 +2449,27 @@ void audio_cda_volume(int left, int right)
        }
 }
 
+static bool audio_state_cda(int streamid)
+{
+       if (cda_bufptr >= dummy_buffer && cda_bufptr <= dummy_buffer + 4) {
+               audio_enable_stream(false, cda_streamid, 0, NULL);
+               cda_streamid = 0;
+               return false;
+       }
+       if (cda_streamid <= 0)
+               return false;
+       int samples[2];
+       samples[0] = cda_bufptr[0] * cda_volume[0] / 32768;
+       samples[1] = cda_bufptr[1] * cda_volume[1] / 32768;
+       audio_state_stream_state(streamid, samples, 2, cda_evt);
+       cda_bufptr += 2;
+       cda_length--;
+       if (cda_length <= 0 && cda_next_cd_audio_buffer_callback) {
+               cda_next_cd_audio_buffer_callback(cda_userdata);
+       }
+       return true;
+}
+
 void audio_cda_new_buffer(uae_s16 *buffer, int length, int userdata, CDA_CALLBACK next_cd_audio_buffer_callback)
 {
        if (!buffer) {
@@ -2449,33 +2480,8 @@ void audio_cda_new_buffer(uae_s16 *buffer, int length, int userdata, CDA_CALLBAC
                cda_length = length;
                cda_userdata = userdata;
                if (cda_streamid <= 0)
-                       cda_streamid = audio_enable_stream(true, -1, 2);
+                       cda_streamid = audio_enable_stream(true, -1, 2, audio_state_cda);
        }
        cda_next_cd_audio_buffer_callback = next_cd_audio_buffer_callback;
        audio_activate();
 }
-
-static void audio_state_cda(void)
-{
-       if (cda_bufptr >= dummy_buffer && cda_bufptr <= dummy_buffer + 4) {
-               audio_enable_stream(false, cda_streamid, 0);
-               cda_streamid = 0;
-               return; 
-       }
-       if (cda_streamid <= 0)
-               return;
-       struct audio_stream_data *asd = audio_stream + cda_streamid;
-       asd->evtime = cda_evt;
-       struct audio_channel_data2 *acd;
-       acd = &asd->data[0];
-       acd->last_sample = acd->current_sample;
-       acd->current_sample = cda_bufptr[0] * cda_volume[0] / 32768;
-       acd = &asd->data[1];
-       acd->last_sample = acd->current_sample;
-       acd->current_sample = cda_bufptr[1] * cda_volume[1] / 32768;
-       cda_bufptr += 2;
-       cda_length--;
-       if (cda_length <= 0 && cda_next_cd_audio_buffer_callback) {
-               cda_next_cd_audio_buffer_callback(cda_userdata);
-       }
-}
index 24819c2630f9aa0d62bd3c55e6450d4836c68701..a1c7d237709cf27fd36d635432a79593b14246f5 100644 (file)
@@ -49,11 +49,12 @@ bool audio_is_event_frame_possible(int);
 
 extern int sampleripper_enabled;
 
-extern int audio_enable_stream(bool, int, int);
-extern void audio_state_stream(int);
+typedef void(*CDA_CALLBACK)(int);
+typedef bool(*SOUND_STREAM_CALLBACK)(int);
+
+extern int audio_enable_stream(bool, int, int, SOUND_STREAM_CALLBACK);
 extern void audio_state_stream_state(int, int*, int, unsigned int);
 
-typedef void (*CDA_CALLBACK)(int);
 extern void audio_cda_new_buffer(uae_s16 *buffer, int length, int userdata, CDA_CALLBACK next_cd_audio_buffer_callback);
 extern void audio_cda_volume(int left, int right);
 
index 6a8a9fc3361ea50f2a769f861d9ad96e51c5b6aa..c277e219215e6c2f5f4658979ef7824bfccc3f1b 100644 (file)
@@ -105,7 +105,7 @@ struct sound_dp
        int wasapigoodsize;
        
        int pullmode;
-       HANDLE pullevent;
+       HANDLE pullevent, pullevent2;
        uae_u8 *pullbuffer;
        int pullbufferlen;
        int pullbuffermaxlen;
@@ -678,8 +678,12 @@ static int _cdecl portAudioCallback (const void *inputBuffer, void *outputBuffer
                return paContinue;
 
        if (s->pullbufferlen <= 0) {
+               ResetEvent(s->pullevent2);
                SetEvent(s->pullevent);
-               return paContinue;
+               WaitForSingleObject(s->pullevent2, 1);
+               if (s->pullbufferlen <= 0) {
+                       return paContinue;
+               }
        }
 
        bytestocopy = framesPerBuffer * sd->samplesize;
@@ -701,6 +705,12 @@ static void close_audio_pa (struct sound_data *sd)
 
        if (s->pastream)
                Pa_CloseStream (s->pastream);
+       if (s->pullevent)
+               CloseHandle(s->pullevent);
+       s->pullevent = NULL;
+       if (s->pullevent2)
+               CloseHandle(s->pullevent2);
+       s->pullevent2 = NULL;
        s->pastream = NULL;
 }
 
@@ -786,7 +796,8 @@ fixfreq:
        }
 
        s->pullevent = CreateEvent(NULL, TRUE, FALSE, NULL);
-       s->pullbuffermaxlen = sd->sndbufsize;
+       s->pullevent2 = CreateEvent(NULL, FALSE, FALSE, NULL);
+       s->pullbuffermaxlen = sd->sndbufsize * 2;
        s->pullbuffer = xcalloc(uae_u8, s->pullbuffermaxlen);
        s->pullbufferlen = 0;
 
@@ -1520,6 +1531,8 @@ void pause_sound_device (struct sound_data *sd)
 #endif
        if (s->pullevent)
                ResetEvent(s->pullevent);
+       if (s->pullevent2)
+               ResetEvent(s->pullevent2);
 }
 void resume_sound_device (struct sound_data *sd)
 {
@@ -1538,6 +1551,8 @@ void resume_sound_device (struct sound_data *sd)
 #endif
        if (s->pullevent)
                ResetEvent(s->pullevent);
+       if (s->pullevent2)
+               ResetEvent(s->pullevent2);
        sd->paused = 0;
 }
 
@@ -2214,6 +2229,7 @@ static bool send_sound_do(struct sound_data *sd)
        } else if (type == SOUND_DEVICE_PA) {
                struct sound_dp *s = sd->data;
                ResetEvent(s->pullevent);
+               SetEvent(s->pullevent2);
        }
        return false;
 }
index dee3873fd26437911506a33eb772640a537fb3aa..e37f88d36864896c5b01ec0454f56b6c786cc252 100644 (file)
@@ -190,6 +190,8 @@ static struct uaesndboard_data uaesndboard[MAX_DUPLICATE_SOUND_BOARDS];
 
 */
 
+static bool audio_state_sndboard_uae(int streamid);
+
 static bool uaesnd_rethink(void)
 {
        bool irq = false;
@@ -261,7 +263,7 @@ static void uaesndboard_stop(struct uaesndboard_stream *s)
                return;
        s->play = 0;
        data->streammask &= ~(1 << (s - data->stream));
-       audio_enable_stream(false, s->streamid, 0);
+       audio_enable_stream(false, s->streamid, 0, NULL);
        s->streamid = 0;
        data->streamcnt--;
 }
@@ -282,7 +284,7 @@ static void uaesndboard_start(struct uaesndboard_stream *s)
                s->sample[i] = 0;
        }
        uaesnd_setfreq(s);
-       s->streamid = audio_enable_stream(true, -1, MAX_UAE_CHANNELS);
+       s->streamid = audio_enable_stream(true, -1, MAX_UAE_CHANNELS, audio_state_sndboard_uae);
        if (!s->streamid) {
                uaesndboard_stop(s);
        }
@@ -417,12 +419,15 @@ static void uaesnd_streammask(uae_u32 m)
        }
 }
 
-static void audio_state_sndboard_uae(int streamid)
+static bool audio_state_sndboard_uae(int streamid)
 {
        struct uaesndboard_data *data = &uaesndboard[0];
        struct uaesndboard_stream *s = NULL;
        int highestch = s->ch;
 
+       if (!uaesnd_active)
+               return false;
+
        for (int i = 0; i < MAX_UAE_STREAMS; i++) {
                if (data->stream[i].streamid == streamid) {
                        s = &data->stream[i];
@@ -431,7 +436,7 @@ static void audio_state_sndboard_uae(int streamid)
        }
        int streamnum = s - data->stream;
        if (!s)
-               return;
+               return false;
        if (s->play && (data->streammask & (1 << streamnum))) {
                int len = s->repeating ? s->replen : s->len;
                uaecptr addr = s->repeating ? s->repeat : s->address;
@@ -531,6 +536,7 @@ static void audio_state_sndboard_uae(int streamid)
                s->sample[7] = lfe;
        }
        audio_state_stream_state(s->streamid, s->sample, highestch, s->event_time);
+       return true;
 }
 
 static void uaesnd_latch(struct uaesndboard_stream *s)
@@ -797,7 +803,7 @@ void uaesndboard_reset(void)
                if (data->enabled) {
                        for (int i = 0; i < MAX_UAE_STREAMS; i++) {
                                if (data->stream[i].streamid) {
-                                       audio_enable_stream(false, data->stream[i].streamid, 0);
+                                       audio_enable_stream(false, data->stream[i].streamid, 0, NULL);
                                        memset(&data->stream[i], 0, sizeof(struct uaesndboard_stream));
                                }
                        }
@@ -911,11 +917,13 @@ static void process_fifo(void)
                data->fifo_half |= STATUS_FIFO_PLAY;
 }
 
-static void audio_state_sndboard_toccata(int streamid)
+static bool audio_state_sndboard_toccata(int streamid)
 {
        struct toccata_data *data = &toccata[0];
+       if (!toccata[0].toccata_active)
+               return false;
        if (data->streamid != streamid)
-               return;
+               return false;
        if ((data->toccata_active & STATUS_FIFO_PLAY)) {
                // get all bytes at once to prevent fifo going out of sync
                // if fifo has for example 3 bytes remaining but we need 4.
@@ -937,6 +945,7 @@ static void audio_state_sndboard_toccata(int streamid)
                }
        }
        audio_state_stream_state(data->streamid, data->ch_sample, 2, data->event_time);
+       return true;
 }
 
 static int get_volume(uae_u8 v)
@@ -1031,7 +1040,7 @@ static void codec_start(void)
        data->record_event_counter = 0;
 
        if (data->toccata_active & STATUS_FIFO_PLAY) {
-               data->streamid = audio_enable_stream(true, -1, 2);
+               data->streamid = audio_enable_stream(true, -1, 2, audio_state_sndboard_toccata);
        }
        if (data->toccata_active & STATUS_FIFO_RECORD) {
                capture_buffer = xcalloc(uae_u8, capture_buffer_size);
@@ -1045,7 +1054,7 @@ static void codec_stop(void)
        write_log(_T("TOCCATA stop\n"));
        data->toccata_active = 0;
        sndboard_free_capture();
-       audio_enable_stream(false, data->streamid, 0);
+       audio_enable_stream(false, data->streamid, 0, NULL);
        data->streamid = 0;
        xfree(capture_buffer);
        capture_buffer = NULL;
@@ -1447,7 +1456,7 @@ void sndboard_reset(void)
        struct toccata_data *data = &toccata[0];
        data->ch_sample[0] = 0;
        data->ch_sample[1] = 0;
-       audio_enable_stream(false, data->streamid, 0);
+       audio_enable_stream(false, data->streamid, 0, NULL);
        data->streamid = 0;
 }
 
@@ -1491,7 +1500,7 @@ static void fm801_stop(struct fm801_data *data)
 {
        write_log(_T("FM801 STOP\n"));
        data->play_on = false;
-       audio_enable_stream(false, data->streamid, 0);
+       audio_enable_stream(false, data->streamid, 0, NULL);
        data->streamid = 0;
 }
 
@@ -1514,12 +1523,14 @@ static void fm801_interrupt(struct fm801_data *data)
        }
 }
 
-static void audio_state_sndboard_fm801(int streamid)
+static bool audio_state_sndboard_fm801(int streamid)
 {
        struct fm801_data *data = &fm801;
 
+       if (!fm801_active)
+               return false;
        if (data->streamid != streamid)
-               return;
+               return false;
        if (data->play_on) {
                uae_u8 sample[2 * 6] = { 0 };
                pci_read_dma(data->pcibs, data->play_dma2[data->dmach], sample, data->bytesperframe);
@@ -1546,6 +1557,7 @@ static void audio_state_sndboard_fm801(int streamid)
                }
        }
        audio_state_stream_state(data->streamid, data->ch_sample, data->ch, data->event_time);
+       return true;
 }
 
 static void fm801_hsync_handler(struct pci_board_state *pcibs)
@@ -1587,7 +1599,7 @@ static void fm801_play(struct fm801_data *data)
 
        write_log(_T("FM801 PLAY: freq=%d ch=%d bits=%d\n"), data->freq, data->ch, data->bits);
 
-       data->streamid = audio_enable_stream(true, -1, data->ch);
+       data->streamid = audio_enable_stream(true, -1, data->ch, audio_state_sndboard_fm801);
 }
 
 static void fm801_pause(struct fm801_data *data, bool pause)
@@ -1853,6 +1865,53 @@ const struct pci_board solo1_pci_board =
 
 static SWVoiceOut *qemu_voice_out;
 
+static bool audio_state_sndboard_qemu(int streamid)
+{
+       SWVoiceOut *out = qemu_voice_out;
+
+       if (!out || !out->active)
+               return false;
+       if (streamid != out->streamid)
+               return false;
+       if (out->active) {
+               uae_s16 l, r;
+               if (out->samplebuf_index >= out->samplebuf_total) {
+                       int maxsize = sizeof(out->samplebuf);
+                       int size = 128 * out->bytesperframe;
+                       if (size > maxsize)
+                               size = maxsize;
+                       out->callback(out->opaque, size);
+                       out->samplebuf_index = 0;
+               }
+               uae_u8 *p = out->samplebuf + out->samplebuf_index;
+               if (out->bits == 8) {
+                       if (out->ch == 1) {
+                               p[1] = p[0];
+                               p[2] = p[0];
+                               p[3] = p[0];
+                       } else {
+                               p[2] = p[1];
+                               p[3] = p[1];
+                               p[1] = p[0];
+                       }
+               } else {
+                       if (out->ch == 1) {
+                               p[2] = p[0];
+                               p[3] = p[1];
+                       }
+               }
+               l = (p[1] << 8) | p[0];
+               r = (p[3] << 8) | p[2];
+               out->ch_sample[0] = l;
+               out->ch_sample[1] = r;
+               out->ch_sample[0] = out->ch_sample[0] * out->left_volume / 32768;
+               out->ch_sample[1] = out->ch_sample[1] * out->right_volume / 32768;
+               out->samplebuf_index += out->bytesperframe;
+       }
+       audio_state_stream_state(out->streamid, out->ch_sample, out->ch, out->event_time);
+       return true;
+}
+
 static void calculate_volume_qemu(void)
 {
        SWVoiceOut *out = qemu_voice_out;
@@ -1882,10 +1941,10 @@ void AUD_set_active_out(SWVoiceOut *sw, int on)
        sw->samplebuf_index = 0;
        sw->samplebuf_total = 0;
        calculate_volume_qemu();
-       audio_enable_stream(false, sw->streamid, 2);
+       audio_enable_stream(false, sw->streamid, 2, NULL);
        sw->streamid = 0;
        if (on) {
-               sw->streamid = audio_enable_stream(true, -1, 2);
+               sw->streamid = audio_enable_stream(true, -1, 2, audio_state_sndboard_qemu);
        }
 }
 void AUD_set_active_in(SWVoiceIn *sw, int on)
@@ -1899,7 +1958,7 @@ void AUD_close_out(QEMUSoundCard *card, SWVoiceOut *sw)
 {
        qemu_voice_out = NULL;
        if (sw) {
-               audio_enable_stream(false, sw->streamid, 0);
+               audio_enable_stream(false, sw->streamid, 0, NULL);
                sw->streamid = 0;
                xfree(sw);
        }
@@ -1949,69 +2008,11 @@ SWVoiceOut *AUD_open_out(
        return out;
 }
 
-static void audio_state_sndboard_qemu(int streamid)
-{
-       SWVoiceOut *out = qemu_voice_out;
-
-       if (!out)
-               return;
-       if (streamid != out->streamid)
-               return;
-       if (out->active) {
-               uae_s16 l, r;
-               if (out->samplebuf_index >= out->samplebuf_total) {
-                       int maxsize = sizeof(out->samplebuf);
-                       int size = 128 * out->bytesperframe;
-                       if (size > maxsize)
-                               size = maxsize;
-                       out->callback(out->opaque, size);
-                       out->samplebuf_index = 0;
-               }
-               uae_u8 *p = out->samplebuf + out->samplebuf_index;
-               if (out->bits == 8) {
-                       if (out->ch == 1) {
-                               p[1] = p[0];
-                               p[2] = p[0];
-                               p[3] = p[0];
-                       } else {
-                               p[2] = p[1];
-                               p[3] = p[1];
-                               p[1] = p[0];
-                       }
-               } else {
-                       if (out->ch == 1) {
-                               p[2] = p[0];
-                               p[3] = p[1];
-                       }
-               }
-               l = (p[1] << 8) | p[0];
-               r = (p[3] << 8) | p[2];
-               out->ch_sample[0] = l;
-               out->ch_sample[1] = r;
-               out->ch_sample[0] = out->ch_sample[0] * out->left_volume / 32768;
-               out->ch_sample[1] = out->ch_sample[1] * out->right_volume / 32768;
-               out->samplebuf_index += out->bytesperframe;
-       }
-       audio_state_stream_state(out->streamid, out->ch_sample, out->ch, out->event_time);
-}
-
 static void sndboard_vsync_qemu(void)
 {
        audio_activate();
 }
 
-void audio_state_stream(int streamid)
-{
-       if (toccata[0].toccata_active)
-               audio_state_sndboard_toccata(streamid);
-       if (fm801_active)
-               audio_state_sndboard_fm801(streamid);
-       if (qemu_voice_out && qemu_voice_out->active)
-               audio_state_sndboard_qemu(streamid);
-       if (uaesnd_active)
-               audio_state_sndboard_uae(streamid);
-}
-
 void sndboard_vsync(void)
 {
        if (toccata[0].toccata_active)