From cd5581199cb9c33255024144859164e36fcaa166 Mon Sep 17 00:00:00 2001 From: havoc Date: Wed, 27 Feb 2008 15:22:17 +0000 Subject: [PATCH] implemented threaded audio mixing for SDL client (required some minor clean up of S_PaintAndSubmit and the functions it called, the buffer painting management makes a lot more sense now) fixed bug with looping sounds mixing sound to the wrong part of the buffer after looping (uses a pointer instead of paintbuffer now) git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@8146 d7cf8633-e32d-0410-b094-e92efae38249 --- snd_main.c | 42 +++++- snd_main.h | 5 +- snd_mix.c | 425 ++++++++++++++++++++++++----------------------------- snd_sdl.c | 10 ++ 4 files changed, 245 insertions(+), 237 deletions(-) diff --git a/snd_main.c b/snd_main.c index 988f0109..af9c4a30 100644 --- a/snd_main.c +++ b/snd_main.c @@ -140,10 +140,12 @@ channel_t channels[MAX_CHANNELS]; unsigned int total_channels; snd_ringbuffer_t *snd_renderbuffer = NULL; -unsigned int soundtime = 0; +static unsigned int soundtime = 0; static unsigned int oldpaintedtime = 0; static unsigned int extrasoundtime = 0; static double snd_starttime = 0.0; +qboolean snd_threaded = false; +qboolean snd_usethreadedmixing = false; vec3_t listener_origin; matrix4x4_t listener_matrix[SND_LISTENERS]; @@ -1471,6 +1473,7 @@ static void S_PaintAndSubmit (void) return; // Update sound time + snd_usethreadedmixing = false; usesoundtimehack = true; if (cls.timedemo) // SUPER NASTY HACK to mix non-realtime sound for more reliable benchmarking { @@ -1489,6 +1492,7 @@ static void S_PaintAndSubmit (void) } else { + snd_usethreadedmixing = snd_threaded && !cls.capturevideo.soundrate; usesoundtimehack = 0; newsoundtime = SndSys_GetSoundTime(); } @@ -1516,6 +1520,9 @@ static void S_PaintAndSubmit (void) if (!soundtimehack && snd_blocked > 0) return; + if (snd_usethreadedmixing) + return; // the audio thread will mix its own data + newsoundtime += extrasoundtime; if (newsoundtime < soundtime) { @@ -1543,6 +1550,18 @@ static void S_PaintAndSubmit (void) soundtime = newsoundtime; recording_sound = (cls.capturevideo.soundrate != 0); + // Remove outdated samples from the ring buffer, if any + if (snd_renderbuffer->startframe < soundtime) + snd_renderbuffer->startframe = soundtime; + + // Lock submitbuffer + if (!simsound && !SndSys_LockRenderBuffer()) + { + // If the lock failed, stop here + Con_DPrint(">> S_PaintAndSubmit: SndSys_LockRenderBuffer() failed\n"); + return; + } + // Check to make sure that we haven't overshot paintedtime = snd_renderbuffer->endframe; if (paintedtime < soundtime) @@ -1557,7 +1576,26 @@ static void S_PaintAndSubmit (void) maxtime = paintedtime + snd_renderbuffer->maxframes - usedframes; endtime = min(endtime, maxtime); - S_PaintChannels(snd_renderbuffer, paintedtime, endtime); + while (paintedtime < endtime) + { + unsigned int startoffset; + unsigned int nbframes; + + // see how much we can fit in the paint buffer + nbframes = endtime - paintedtime; + // limit to the end of the ring buffer (in case of wrapping) + startoffset = paintedtime % snd_renderbuffer->maxframes; + nbframes = min(nbframes, snd_renderbuffer->maxframes - startoffset); + + // mix into the buffer + S_MixToBuffer(&snd_renderbuffer->ring[startoffset * snd_renderbuffer->format.width * snd_renderbuffer->format.channels], nbframes); + + paintedtime += nbframes; + } + if (!simsound) + SndSys_UnlockRenderBuffer(); + + snd_renderbuffer->endframe = endtime; if (simsound) snd_renderbuffer->startframe = snd_renderbuffer->endframe; diff --git a/snd_main.h b/snd_main.h index 5efc8719..0eea2fdd 100644 --- a/snd_main.h +++ b/snd_main.h @@ -121,7 +121,8 @@ extern unsigned int total_channels; extern channel_t channels[MAX_CHANNELS]; extern snd_ringbuffer_t *snd_renderbuffer; -extern unsigned int soundtime; // WARNING: sound modules must NOT use it +extern qboolean snd_threaded; // enables use of snd_usethreadedmixing, provided that no sound hacks are in effect (like timedemo) +extern qboolean snd_usethreadedmixing; // if true, the main thread does not mix sound, soundtime does not advance, and neither does snd_renderbuffer->endframe, instead the audio thread will call S_MixToBuffer as needed extern cvar_t _snd_mixahead; extern cvar_t snd_swapstereo; @@ -146,7 +147,7 @@ extern qboolean simsound; // Architecture-independent functions // ==================================================================== -void S_PaintChannels (snd_ringbuffer_t* rb, unsigned int starttime, unsigned int endtime); +void S_MixToBuffer(void *stream, unsigned int frames); qboolean S_LoadSound (sfx_t *sfx, qboolean complain); diff --git a/snd_mix.c b/snd_mix.c index c6b68d88..ebf16654 100644 --- a/snd_mix.c +++ b/snd_mix.c @@ -29,7 +29,7 @@ typedef struct portable_samplepair_s // LordHavoc: was 512, expanded to 2048 #define PAINTBUFFER_SIZE 2048 -portable_sampleframe_t paintbuffer[PAINTBUFFER_SIZE]; +static portable_sampleframe_t paintbuffer[PAINTBUFFER_SIZE]; extern void SCR_CaptureVideo_SoundFrame(unsigned char *bufstereo16le, size_t length, int rate); @@ -60,157 +60,121 @@ static void S_CaptureAVISound(size_t length) SCR_CaptureVideo_SoundFrame(out, length, snd_renderbuffer->format.speed); } -static unsigned int S_TransferPaintBuffer(snd_ringbuffer_t* rb, unsigned int starttime, unsigned int endtime) +static void S_ConvertPaintBuffer(const portable_sampleframe_t *painted_ptr, void *rb_ptr, int nbframes, int width, int channels) { - unsigned int partialend; - - // Lock submitbuffer - if (!simsound && !SndSys_LockRenderBuffer()) - return 0; - - partialend = starttime; - while (partialend < endtime) // handle recirculating buffer issues + int i, val; + if (width == 2) // 16bit { - unsigned int startoffset, maxframes, nbframes, i; - void *rb_ptr; - portable_sampleframe_t *painted_ptr; - int val; - - startoffset = partialend % rb->maxframes; - maxframes = rb->maxframes - startoffset; - nbframes = endtime - partialend; - if (nbframes > maxframes) - nbframes = maxframes; - - rb_ptr = &rb->ring[startoffset * rb->format.width * rb->format.channels]; - painted_ptr = &paintbuffer[partialend - starttime]; - - if (rb->format.width == 2) // 16bit + short *snd_out = (short*)rb_ptr; + if (channels == 8) // 7.1 surround { - short *snd_out = (short*)rb_ptr; - if (rb->format.channels == 8) // 7.1 surround + for (i = 0;i < nbframes;i++, painted_ptr++) { - for (i = 0;i < nbframes;i++, painted_ptr++) - { - *snd_out++ = bound(-32768, painted_ptr->sample[0], 32767); - *snd_out++ = bound(-32768, painted_ptr->sample[1], 32767); - *snd_out++ = bound(-32768, painted_ptr->sample[2], 32767); - *snd_out++ = bound(-32768, painted_ptr->sample[3], 32767); - *snd_out++ = bound(-32768, painted_ptr->sample[4], 32767); - *snd_out++ = bound(-32768, painted_ptr->sample[5], 32767); - *snd_out++ = bound(-32768, painted_ptr->sample[6], 32767); - *snd_out++ = bound(-32768, painted_ptr->sample[7], 32767); - } + *snd_out++ = bound(-32768, painted_ptr->sample[0], 32767); + *snd_out++ = bound(-32768, painted_ptr->sample[1], 32767); + *snd_out++ = bound(-32768, painted_ptr->sample[2], 32767); + *snd_out++ = bound(-32768, painted_ptr->sample[3], 32767); + *snd_out++ = bound(-32768, painted_ptr->sample[4], 32767); + *snd_out++ = bound(-32768, painted_ptr->sample[5], 32767); + *snd_out++ = bound(-32768, painted_ptr->sample[6], 32767); + *snd_out++ = bound(-32768, painted_ptr->sample[7], 32767); } - else if (rb->format.channels == 6) // 5.1 surround + } + else if (channels == 6) // 5.1 surround + { + for (i = 0; i < nbframes; i++, painted_ptr++) { - for (i = 0; i < nbframes; i++, painted_ptr++) - { - *snd_out++ = bound(-32768, painted_ptr->sample[0], 32767); - *snd_out++ = bound(-32768, painted_ptr->sample[1], 32767); - *snd_out++ = bound(-32768, painted_ptr->sample[2], 32767); - *snd_out++ = bound(-32768, painted_ptr->sample[3], 32767); - *snd_out++ = bound(-32768, painted_ptr->sample[4], 32767); - *snd_out++ = bound(-32768, painted_ptr->sample[5], 32767); - } + *snd_out++ = bound(-32768, painted_ptr->sample[0], 32767); + *snd_out++ = bound(-32768, painted_ptr->sample[1], 32767); + *snd_out++ = bound(-32768, painted_ptr->sample[2], 32767); + *snd_out++ = bound(-32768, painted_ptr->sample[3], 32767); + *snd_out++ = bound(-32768, painted_ptr->sample[4], 32767); + *snd_out++ = bound(-32768, painted_ptr->sample[5], 32767); } - else if (rb->format.channels == 4) // 4.0 surround + } + else if (channels == 4) // 4.0 surround + { + for (i = 0; i < nbframes; i++, painted_ptr++) { - for (i = 0; i < nbframes; i++, painted_ptr++) - { - *snd_out++ = bound(-32768, painted_ptr->sample[0], 32767); - *snd_out++ = bound(-32768, painted_ptr->sample[1], 32767); - *snd_out++ = bound(-32768, painted_ptr->sample[2], 32767); - *snd_out++ = bound(-32768, painted_ptr->sample[3], 32767); - } + *snd_out++ = bound(-32768, painted_ptr->sample[0], 32767); + *snd_out++ = bound(-32768, painted_ptr->sample[1], 32767); + *snd_out++ = bound(-32768, painted_ptr->sample[2], 32767); + *snd_out++ = bound(-32768, painted_ptr->sample[3], 32767); } - else if (rb->format.channels == 2) // 2.0 stereo + } + else if (channels == 2) // 2.0 stereo + { + for (i = 0; i < nbframes; i++, painted_ptr++) { - for (i = 0; i < nbframes; i++, painted_ptr++) - { - *snd_out++ = bound(-32768, painted_ptr->sample[0], 32767); - *snd_out++ = bound(-32768, painted_ptr->sample[1], 32767); - } + *snd_out++ = bound(-32768, painted_ptr->sample[0], 32767); + *snd_out++ = bound(-32768, painted_ptr->sample[1], 32767); } - else if (rb->format.channels == 1) // 1.0 mono + } + else if (channels == 1) // 1.0 mono + { + for (i = 0; i < nbframes; i++, painted_ptr++) { - for (i = 0; i < nbframes; i++, painted_ptr++) - { - val = (painted_ptr->sample[0] + painted_ptr->sample[1]) >> 1; - *snd_out++ = bound(-32768, val, 32767); - } + val = (painted_ptr->sample[0] + painted_ptr->sample[1]) >> 1; + *snd_out++ = bound(-32768, val, 32767); } } - else // 8bit + } + else // 8bit + { + unsigned char *snd_out = (unsigned char*)rb_ptr; + if (channels == 8) // 7.1 surround { - unsigned char *snd_out = (unsigned char*)rb_ptr; - if (rb->format.channels == 8) // 7.1 surround + for (i = 0; i < nbframes; i++, painted_ptr++) { - for (i = 0; i < nbframes; i++, painted_ptr++) - { - val = (painted_ptr->sample[0] >> 8) + 128; *snd_out++ = bound(0, val, 255); - val = (painted_ptr->sample[1] >> 8) + 128; *snd_out++ = bound(0, val, 255); - val = (painted_ptr->sample[2] >> 8) + 128; *snd_out++ = bound(0, val, 255); - val = (painted_ptr->sample[3] >> 8) + 128; *snd_out++ = bound(0, val, 255); - val = (painted_ptr->sample[4] >> 8) + 128; *snd_out++ = bound(0, val, 255); - val = (painted_ptr->sample[5] >> 8) + 128; *snd_out++ = bound(0, val, 255); - val = (painted_ptr->sample[6] >> 8) + 128; *snd_out++ = bound(0, val, 255); - val = (painted_ptr->sample[7] >> 8) + 128; *snd_out++ = bound(0, val, 255); - } + val = (painted_ptr->sample[0] >> 8) + 128; *snd_out++ = bound(0, val, 255); + val = (painted_ptr->sample[1] >> 8) + 128; *snd_out++ = bound(0, val, 255); + val = (painted_ptr->sample[2] >> 8) + 128; *snd_out++ = bound(0, val, 255); + val = (painted_ptr->sample[3] >> 8) + 128; *snd_out++ = bound(0, val, 255); + val = (painted_ptr->sample[4] >> 8) + 128; *snd_out++ = bound(0, val, 255); + val = (painted_ptr->sample[5] >> 8) + 128; *snd_out++ = bound(0, val, 255); + val = (painted_ptr->sample[6] >> 8) + 128; *snd_out++ = bound(0, val, 255); + val = (painted_ptr->sample[7] >> 8) + 128; *snd_out++ = bound(0, val, 255); } - else if (rb->format.channels == 6) // 5.1 surround + } + else if (channels == 6) // 5.1 surround + { + for (i = 0; i < nbframes; i++, painted_ptr++) { - for (i = 0; i < nbframes; i++, painted_ptr++) - { - val = (painted_ptr->sample[0] >> 8) + 128; *snd_out++ = bound(0, val, 255); - val = (painted_ptr->sample[1] >> 8) + 128; *snd_out++ = bound(0, val, 255); - val = (painted_ptr->sample[2] >> 8) + 128; *snd_out++ = bound(0, val, 255); - val = (painted_ptr->sample[3] >> 8) + 128; *snd_out++ = bound(0, val, 255); - val = (painted_ptr->sample[4] >> 8) + 128; *snd_out++ = bound(0, val, 255); - val = (painted_ptr->sample[5] >> 8) + 128; *snd_out++ = bound(0, val, 255); - } + val = (painted_ptr->sample[0] >> 8) + 128; *snd_out++ = bound(0, val, 255); + val = (painted_ptr->sample[1] >> 8) + 128; *snd_out++ = bound(0, val, 255); + val = (painted_ptr->sample[2] >> 8) + 128; *snd_out++ = bound(0, val, 255); + val = (painted_ptr->sample[3] >> 8) + 128; *snd_out++ = bound(0, val, 255); + val = (painted_ptr->sample[4] >> 8) + 128; *snd_out++ = bound(0, val, 255); + val = (painted_ptr->sample[5] >> 8) + 128; *snd_out++ = bound(0, val, 255); } - else if (rb->format.channels == 4) // 4.0 surround + } + else if (channels == 4) // 4.0 surround + { + for (i = 0; i < nbframes; i++, painted_ptr++) { - for (i = 0; i < nbframes; i++, painted_ptr++) - { - val = (painted_ptr->sample[0] >> 8) + 128; *snd_out++ = bound(0, val, 255); - val = (painted_ptr->sample[1] >> 8) + 128; *snd_out++ = bound(0, val, 255); - val = (painted_ptr->sample[2] >> 8) + 128; *snd_out++ = bound(0, val, 255); - val = (painted_ptr->sample[3] >> 8) + 128; *snd_out++ = bound(0, val, 255); - } + val = (painted_ptr->sample[0] >> 8) + 128; *snd_out++ = bound(0, val, 255); + val = (painted_ptr->sample[1] >> 8) + 128; *snd_out++ = bound(0, val, 255); + val = (painted_ptr->sample[2] >> 8) + 128; *snd_out++ = bound(0, val, 255); + val = (painted_ptr->sample[3] >> 8) + 128; *snd_out++ = bound(0, val, 255); } - else if (rb->format.channels == 2) // 2.0 stereo + } + else if (channels == 2) // 2.0 stereo + { + for (i = 0; i < nbframes; i++, painted_ptr++) { - for (i = 0; i < nbframes; i++, painted_ptr++) - { - val = (painted_ptr->sample[0] >> 8) + 128; *snd_out++ = bound(0, val, 255); - val = (painted_ptr->sample[1] >> 8) + 128; *snd_out++ = bound(0, val, 255); - } + val = (painted_ptr->sample[0] >> 8) + 128; *snd_out++ = bound(0, val, 255); + val = (painted_ptr->sample[1] >> 8) + 128; *snd_out++ = bound(0, val, 255); } - else if (rb->format.channels == 1) // 1.0 mono + } + else if (channels == 1) // 1.0 mono + { + for (i = 0;i < nbframes;i++, painted_ptr++) { - for (i = 0;i < nbframes;i++, painted_ptr++) - { - val = ((painted_ptr->sample[0] + painted_ptr->sample[1]) >> 9) + 128; - *snd_out++ = bound(0, val, 255); - } + val = ((painted_ptr->sample[0] + painted_ptr->sample[1]) >> 9) + 128; + *snd_out++ = bound(0, val, 255); } } - - partialend += nbframes; } - - rb->endframe = endtime; - - // Remove outdated samples from the ring buffer, if any - if (rb->startframe < soundtime) - rb->startframe = soundtime; - - if (!simsound) - SndSys_UnlockRenderBuffer(); - - return endtime - starttime; } @@ -222,7 +186,7 @@ CHANNEL MIXING =============================================================================== */ -static qboolean SND_PaintChannel (channel_t *ch, unsigned int count) +static qboolean SND_PaintChannel (channel_t *ch, portable_sampleframe_t *paint, unsigned int count) { int snd_vol, vol[SND_LISTENERS]; const snd_buffer_t *sb; @@ -273,14 +237,14 @@ static qboolean SND_PaintChannel (channel_t *ch, unsigned int count) { for (i = 0;i < count;i++) { - paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 8; - paintbuffer[i].sample[1] += (samples[1] * vol[1]) >> 8; - paintbuffer[i].sample[2] += (samples[0] * vol[2]) >> 8; - paintbuffer[i].sample[3] += (samples[1] * vol[3]) >> 8; - paintbuffer[i].sample[4] += ((samples[0] + samples[1]) * vol[4]) >> 9; - paintbuffer[i].sample[5] += ((samples[0] + samples[1]) * vol[5]) >> 9; - paintbuffer[i].sample[6] += (samples[0] * vol[6]) >> 8; - paintbuffer[i].sample[7] += (samples[1] * vol[7]) >> 8; + paint[i].sample[0] += (samples[0] * vol[0]) >> 8; + paint[i].sample[1] += (samples[1] * vol[1]) >> 8; + paint[i].sample[2] += (samples[0] * vol[2]) >> 8; + paint[i].sample[3] += (samples[1] * vol[3]) >> 8; + paint[i].sample[4] += ((samples[0] + samples[1]) * vol[4]) >> 9; + paint[i].sample[5] += ((samples[0] + samples[1]) * vol[5]) >> 9; + paint[i].sample[6] += (samples[0] * vol[6]) >> 8; + paint[i].sample[7] += (samples[1] * vol[7]) >> 8; samples += 2; } } @@ -288,12 +252,12 @@ static qboolean SND_PaintChannel (channel_t *ch, unsigned int count) { for (i = 0;i < count;i++) { - paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 8; - paintbuffer[i].sample[1] += (samples[1] * vol[1]) >> 8; - paintbuffer[i].sample[2] += (samples[0] * vol[2]) >> 8; - paintbuffer[i].sample[3] += (samples[1] * vol[3]) >> 8; - paintbuffer[i].sample[4] += ((samples[0] + samples[1]) * vol[4]) >> 9; - paintbuffer[i].sample[5] += ((samples[0] + samples[1]) * vol[5]) >> 9; + paint[i].sample[0] += (samples[0] * vol[0]) >> 8; + paint[i].sample[1] += (samples[1] * vol[1]) >> 8; + paint[i].sample[2] += (samples[0] * vol[2]) >> 8; + paint[i].sample[3] += (samples[1] * vol[3]) >> 8; + paint[i].sample[4] += ((samples[0] + samples[1]) * vol[4]) >> 9; + paint[i].sample[5] += ((samples[0] + samples[1]) * vol[5]) >> 9; samples += 2; } } @@ -301,10 +265,10 @@ static qboolean SND_PaintChannel (channel_t *ch, unsigned int count) { for (i = 0;i < count;i++) { - paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 8; - paintbuffer[i].sample[1] += (samples[1] * vol[1]) >> 8; - paintbuffer[i].sample[2] += (samples[0] * vol[2]) >> 8; - paintbuffer[i].sample[3] += (samples[1] * vol[3]) >> 8; + paint[i].sample[0] += (samples[0] * vol[0]) >> 8; + paint[i].sample[1] += (samples[1] * vol[1]) >> 8; + paint[i].sample[2] += (samples[0] * vol[2]) >> 8; + paint[i].sample[3] += (samples[1] * vol[3]) >> 8; samples += 2; } } @@ -312,8 +276,8 @@ static qboolean SND_PaintChannel (channel_t *ch, unsigned int count) { for (i = 0;i < count;i++) { - paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 8; - paintbuffer[i].sample[1] += (samples[1] * vol[1]) >> 8; + paint[i].sample[0] += (samples[0] * vol[0]) >> 8; + paint[i].sample[1] += (samples[1] * vol[1]) >> 8; samples += 2; } } @@ -324,14 +288,14 @@ static qboolean SND_PaintChannel (channel_t *ch, unsigned int count) { for (i = 0;i < count;i++) { - paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 8; - paintbuffer[i].sample[1] += (samples[0] * vol[1]) >> 8; - paintbuffer[i].sample[2] += (samples[0] * vol[2]) >> 8; - paintbuffer[i].sample[3] += (samples[0] * vol[3]) >> 8; - paintbuffer[i].sample[4] += (samples[0] * vol[4]) >> 8; - paintbuffer[i].sample[5] += (samples[0] * vol[5]) >> 8; - paintbuffer[i].sample[6] += (samples[0] * vol[6]) >> 8; - paintbuffer[i].sample[7] += (samples[0] * vol[7]) >> 8; + paint[i].sample[0] += (samples[0] * vol[0]) >> 8; + paint[i].sample[1] += (samples[0] * vol[1]) >> 8; + paint[i].sample[2] += (samples[0] * vol[2]) >> 8; + paint[i].sample[3] += (samples[0] * vol[3]) >> 8; + paint[i].sample[4] += (samples[0] * vol[4]) >> 8; + paint[i].sample[5] += (samples[0] * vol[5]) >> 8; + paint[i].sample[6] += (samples[0] * vol[6]) >> 8; + paint[i].sample[7] += (samples[0] * vol[7]) >> 8; samples += 1; } } @@ -339,12 +303,12 @@ static qboolean SND_PaintChannel (channel_t *ch, unsigned int count) { for (i = 0;i < count;i++) { - paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 8; - paintbuffer[i].sample[1] += (samples[0] * vol[1]) >> 8; - paintbuffer[i].sample[2] += (samples[0] * vol[2]) >> 8; - paintbuffer[i].sample[3] += (samples[0] * vol[3]) >> 8; - paintbuffer[i].sample[4] += (samples[0] * vol[4]) >> 8; - paintbuffer[i].sample[5] += (samples[0] * vol[5]) >> 8; + paint[i].sample[0] += (samples[0] * vol[0]) >> 8; + paint[i].sample[1] += (samples[0] * vol[1]) >> 8; + paint[i].sample[2] += (samples[0] * vol[2]) >> 8; + paint[i].sample[3] += (samples[0] * vol[3]) >> 8; + paint[i].sample[4] += (samples[0] * vol[4]) >> 8; + paint[i].sample[5] += (samples[0] * vol[5]) >> 8; samples += 1; } } @@ -352,10 +316,10 @@ static qboolean SND_PaintChannel (channel_t *ch, unsigned int count) { for (i = 0;i < count;i++) { - paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 8; - paintbuffer[i].sample[1] += (samples[0] * vol[1]) >> 8; - paintbuffer[i].sample[2] += (samples[0] * vol[2]) >> 8; - paintbuffer[i].sample[3] += (samples[0] * vol[3]) >> 8; + paint[i].sample[0] += (samples[0] * vol[0]) >> 8; + paint[i].sample[1] += (samples[0] * vol[1]) >> 8; + paint[i].sample[2] += (samples[0] * vol[2]) >> 8; + paint[i].sample[3] += (samples[0] * vol[3]) >> 8; samples += 1; } } @@ -363,8 +327,8 @@ static qboolean SND_PaintChannel (channel_t *ch, unsigned int count) { for (i = 0;i < count;i++) { - paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 8; - paintbuffer[i].sample[1] += (samples[0] * vol[1]) >> 8; + paint[i].sample[0] += (samples[0] * vol[0]) >> 8; + paint[i].sample[1] += (samples[0] * vol[1]) >> 8; samples += 1; } } @@ -383,14 +347,14 @@ static qboolean SND_PaintChannel (channel_t *ch, unsigned int count) { for (i = 0;i < count;i++) { - paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 16; - paintbuffer[i].sample[1] += (samples[1] * vol[1]) >> 16; - paintbuffer[i].sample[2] += (samples[0] * vol[2]) >> 16; - paintbuffer[i].sample[3] += (samples[1] * vol[3]) >> 16; - paintbuffer[i].sample[4] += ((samples[0] + samples[1]) * vol[4]) >> 17; - paintbuffer[i].sample[5] += ((samples[0] + samples[1]) * vol[5]) >> 17; - paintbuffer[i].sample[6] += (samples[0] * vol[6]) >> 16; - paintbuffer[i].sample[7] += (samples[1] * vol[7]) >> 16; + paint[i].sample[0] += (samples[0] * vol[0]) >> 16; + paint[i].sample[1] += (samples[1] * vol[1]) >> 16; + paint[i].sample[2] += (samples[0] * vol[2]) >> 16; + paint[i].sample[3] += (samples[1] * vol[3]) >> 16; + paint[i].sample[4] += ((samples[0] + samples[1]) * vol[4]) >> 17; + paint[i].sample[5] += ((samples[0] + samples[1]) * vol[5]) >> 17; + paint[i].sample[6] += (samples[0] * vol[6]) >> 16; + paint[i].sample[7] += (samples[1] * vol[7]) >> 16; samples += 2; } } @@ -398,12 +362,12 @@ static qboolean SND_PaintChannel (channel_t *ch, unsigned int count) { for (i = 0;i < count;i++) { - paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 16; - paintbuffer[i].sample[1] += (samples[1] * vol[1]) >> 16; - paintbuffer[i].sample[2] += (samples[0] * vol[2]) >> 16; - paintbuffer[i].sample[3] += (samples[1] * vol[3]) >> 16; - paintbuffer[i].sample[4] += ((samples[0] + samples[1]) * vol[4]) >> 17; - paintbuffer[i].sample[5] += ((samples[0] + samples[1]) * vol[5]) >> 17; + paint[i].sample[0] += (samples[0] * vol[0]) >> 16; + paint[i].sample[1] += (samples[1] * vol[1]) >> 16; + paint[i].sample[2] += (samples[0] * vol[2]) >> 16; + paint[i].sample[3] += (samples[1] * vol[3]) >> 16; + paint[i].sample[4] += ((samples[0] + samples[1]) * vol[4]) >> 17; + paint[i].sample[5] += ((samples[0] + samples[1]) * vol[5]) >> 17; samples += 2; } } @@ -411,10 +375,10 @@ static qboolean SND_PaintChannel (channel_t *ch, unsigned int count) { for (i = 0;i < count;i++) { - paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 16; - paintbuffer[i].sample[1] += (samples[1] * vol[1]) >> 16; - paintbuffer[i].sample[2] += (samples[0] * vol[2]) >> 16; - paintbuffer[i].sample[3] += (samples[1] * vol[3]) >> 16; + paint[i].sample[0] += (samples[0] * vol[0]) >> 16; + paint[i].sample[1] += (samples[1] * vol[1]) >> 16; + paint[i].sample[2] += (samples[0] * vol[2]) >> 16; + paint[i].sample[3] += (samples[1] * vol[3]) >> 16; samples += 2; } } @@ -422,8 +386,8 @@ static qboolean SND_PaintChannel (channel_t *ch, unsigned int count) { for (i = 0;i < count;i++) { - paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 16; - paintbuffer[i].sample[1] += (samples[1] * vol[1]) >> 16; + paint[i].sample[0] += (samples[0] * vol[0]) >> 16; + paint[i].sample[1] += (samples[1] * vol[1]) >> 16; samples += 2; } } @@ -434,14 +398,14 @@ static qboolean SND_PaintChannel (channel_t *ch, unsigned int count) { for (i = 0;i < count;i++) { - paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 16; - paintbuffer[i].sample[1] += (samples[0] * vol[1]) >> 16; - paintbuffer[i].sample[2] += (samples[0] * vol[2]) >> 16; - paintbuffer[i].sample[3] += (samples[0] * vol[3]) >> 16; - paintbuffer[i].sample[4] += (samples[0] * vol[4]) >> 16; - paintbuffer[i].sample[5] += (samples[0] * vol[5]) >> 16; - paintbuffer[i].sample[6] += (samples[0] * vol[6]) >> 16; - paintbuffer[i].sample[7] += (samples[0] * vol[7]) >> 16; + paint[i].sample[0] += (samples[0] * vol[0]) >> 16; + paint[i].sample[1] += (samples[0] * vol[1]) >> 16; + paint[i].sample[2] += (samples[0] * vol[2]) >> 16; + paint[i].sample[3] += (samples[0] * vol[3]) >> 16; + paint[i].sample[4] += (samples[0] * vol[4]) >> 16; + paint[i].sample[5] += (samples[0] * vol[5]) >> 16; + paint[i].sample[6] += (samples[0] * vol[6]) >> 16; + paint[i].sample[7] += (samples[0] * vol[7]) >> 16; samples += 1; } } @@ -449,12 +413,12 @@ static qboolean SND_PaintChannel (channel_t *ch, unsigned int count) { for (i = 0;i < count;i++) { - paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 16; - paintbuffer[i].sample[1] += (samples[0] * vol[1]) >> 16; - paintbuffer[i].sample[2] += (samples[0] * vol[2]) >> 16; - paintbuffer[i].sample[3] += (samples[0] * vol[3]) >> 16; - paintbuffer[i].sample[4] += (samples[0] * vol[4]) >> 16; - paintbuffer[i].sample[5] += (samples[0] * vol[5]) >> 16; + paint[i].sample[0] += (samples[0] * vol[0]) >> 16; + paint[i].sample[1] += (samples[0] * vol[1]) >> 16; + paint[i].sample[2] += (samples[0] * vol[2]) >> 16; + paint[i].sample[3] += (samples[0] * vol[3]) >> 16; + paint[i].sample[4] += (samples[0] * vol[4]) >> 16; + paint[i].sample[5] += (samples[0] * vol[5]) >> 16; samples += 1; } } @@ -462,10 +426,10 @@ static qboolean SND_PaintChannel (channel_t *ch, unsigned int count) { for (i = 0;i < count;i++) { - paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 16; - paintbuffer[i].sample[1] += (samples[0] * vol[1]) >> 16; - paintbuffer[i].sample[2] += (samples[0] * vol[2]) >> 16; - paintbuffer[i].sample[3] += (samples[0] * vol[3]) >> 16; + paint[i].sample[0] += (samples[0] * vol[0]) >> 16; + paint[i].sample[1] += (samples[0] * vol[1]) >> 16; + paint[i].sample[2] += (samples[0] * vol[2]) >> 16; + paint[i].sample[3] += (samples[0] * vol[3]) >> 16; samples += 1; } } @@ -473,8 +437,8 @@ static qboolean SND_PaintChannel (channel_t *ch, unsigned int count) { for (i = 0;i < count;i++) { - paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 16; - paintbuffer[i].sample[1] += (samples[0] * vol[1]) >> 16; + paint[i].sample[0] += (samples[0] * vol[0]) >> 16; + paint[i].sample[1] += (samples[0] * vol[1]) >> 16; samples += 1; } } @@ -486,24 +450,21 @@ static qboolean SND_PaintChannel (channel_t *ch, unsigned int count) return true; } -void S_PaintChannels (snd_ringbuffer_t* rb, unsigned int starttime, unsigned int endtime) +void S_MixToBuffer(void *stream, unsigned int bufferframes) { - unsigned int paintedtime; + unsigned int i; + channel_t *ch; + unsigned int frames; + unsigned char *outbytes = stream; - paintedtime = starttime; - while (paintedtime < endtime) + // mix as many times as needed to fill the requested buffer + while (bufferframes) { - unsigned int partialend, i, framecount; - channel_t *ch; - - // if paintbuffer is too small - if (endtime > paintedtime + PAINTBUFFER_SIZE) - partialend = paintedtime + PAINTBUFFER_SIZE; - else - partialend = endtime; + // limit to the size of the paint buffer + frames = min(bufferframes, PAINTBUFFER_SIZE); // clear the paint buffer - memset (paintbuffer, 0, (partialend - paintedtime) * sizeof (paintbuffer[0])); + memset (paintbuffer, 0, frames * sizeof (paintbuffer[0])); // paint in the channels. // channels with zero volumes still advance in time but don't paint. @@ -522,23 +483,23 @@ void S_PaintChannels (snd_ringbuffer_t* rb, unsigned int starttime, unsigned int if (ch->flags & CHANNELFLAG_PAUSED) continue; - ltime = paintedtime; + ltime = 0; if (ch->pos < 0) { count = -ch->pos; - count = min(count, partialend - ltime); + count = min(count, frames); ch->pos += count; ltime += count; } - while (ltime < partialend) + while (ltime < frames) { // paint up to end of buffer or of input, whichever is lower count = sfx->total_length - ch->pos; - count = bound(0, count, partialend - ltime); + count = bound(0, count, frames - ltime); if (count) { - SND_PaintChannel (ch, count); + SND_PaintChannel (ch, paintbuffer + ltime, count); ch->pos += count; ltime += count; } @@ -559,15 +520,13 @@ void S_PaintChannels (snd_ringbuffer_t* rb, unsigned int starttime, unsigned int } } - S_CaptureAVISound (partialend - paintedtime); - framecount = S_TransferPaintBuffer (rb, paintedtime, partialend); - paintedtime += framecount; + if (!snd_usethreadedmixing) + S_CaptureAVISound(frames); - // If there was not enough free space in the sound buffer, stop here - if (paintedtime != partialend) - { - Con_DPrintf(">> S_PaintChannels: Not enough free space in the sound buffer ( %u != %u)\n", paintedtime, partialend); - break; - } + S_ConvertPaintBuffer(paintbuffer, outbytes, frames, snd_renderbuffer->format.width, snd_renderbuffer->format.channels); + + // advance the output pointer + outbytes += frames * snd_renderbuffer->format.width * snd_renderbuffer->format.channels; + bufferframes -= frames; } } diff --git a/snd_sdl.c b/snd_sdl.c index 032e5750..4bcc0e7c 100644 --- a/snd_sdl.c +++ b/snd_sdl.c @@ -39,6 +39,12 @@ static void Buffer_Callback (void *userdata, Uint8 *stream, int len) RequestedFrames = (unsigned int)len / factor; + if (snd_usethreadedmixing) + { + S_MixToBuffer(stream, RequestedFrames); + return; + } + // Transfert up to a chunk of samples from snd_renderbuffer to stream MaxFrames = snd_renderbuffer->endframe - snd_renderbuffer->startframe; if (MaxFrames > RequestedFrames) @@ -83,6 +89,8 @@ qboolean SndSys_Init (const snd_format_t* requested, snd_format_t* suggested) SDL_AudioSpec wantspec; SDL_AudioSpec obtainspec; + snd_threaded = false; + Con_DPrint ("SndSys_Init: using the SDL module\n"); // Init the SDL Audio subsystem @@ -140,6 +148,8 @@ qboolean SndSys_Init (const snd_format_t* requested, snd_format_t* suggested) return false; } + snd_threaded = true; + snd_renderbuffer = Snd_CreateRingBuffer(requested, 0, NULL); if (snd_channellayout.integer == SND_CHANNELLAYOUT_AUTO) { -- 2.39.2