MixSDL now handles resampling correctly (less cracklings); added cubic interpolation for high quality mode; some cleanups

git-svn-id: svn://svn.code.sf.net/p/sc2/code/trunk@1050 8092fc87-c524-0410-9efc-e669fe64eaf9
This commit is contained in:
gewlitys
2003-07-14 20:18:32 +00:00
parent 1a36fdd8b4
commit 580186f5d1
7 changed files with 280 additions and 300 deletions
+2
View File
@@ -1,4 +1,6 @@
Changes towards version 0.3: Changes towards version 0.3:
- MixSDL now handles resampling correctly (less cracklings);
added cubic interpolation for high quality mode -Mika
- Removed the redundant "GameExiting" variable -Michael - Removed the redundant "GameExiting" variable -Michael
- Added quit options to ingame menu (bug #409), from Paxtez - Added quit options to ingame menu (bug #409), from Paxtez
- Fix position of blinking save/load in melee (bug #406), from Paxtez - Fix position of blinking save/load in melee (bug #406), from Paxtez
+266 -268
View File
@@ -55,6 +55,7 @@ static uint32 mixer_chansize;
static uint32 mixer_sampsize; static uint32 mixer_sampsize;
static sint32 mixer_silence; static sint32 mixer_silence;
static uint32 mixer_freq; static uint32 mixer_freq;
static mixSDL_Quality mixer_quality;
/* mixer interim work-buffer; size in one-channel samples */ /* mixer interim work-buffer; size in one-channel samples */
static uint32 mixer_datasize; static uint32 mixer_datasize;
@@ -253,6 +254,7 @@ mixSDL_OpenAudio (uint32 frequency, uint32 format, uint32 samples_buf,
mixer_chansize, mixer_spec.channels); mixer_chansize, mixer_spec.channels);
mixer_sampsize = mixer_chansize * mixer_spec.channels; mixer_sampsize = mixer_chansize * mixer_spec.channels;
mixer_freq = mixer_spec.freq; mixer_freq = mixer_spec.freq;
mixer_quality = quality;
/* 2x size the sound playback buffer should be enough for anything */ /* 2x size the sound playback buffer should be enough for anything */
mixer_datasize = samples_buf * mixer_spec.channels * 2; mixer_datasize = samples_buf * mixer_spec.channels * 2;
@@ -348,8 +350,10 @@ mixSDL_GenSources (uint32 n, mixSDL_Object *psrcobj)
src->cprocessed = 0; src->cprocessed = 0;
src->firstqueued = 0; src->firstqueued = 0;
src->nextqueued = 0; src->nextqueued = 0;
src->prevqueued = 0;
src->lastqueued = 0; src->lastqueued = 0;
src->curbufofs = 0; src->curbufofs = 0;
src->curbufdelta = 0;
*psrcobj = (mixSDL_Object) src; *psrcobj = (mixSDL_Object) src;
} }
@@ -483,6 +487,7 @@ mixSDL_Sourcei (mixSDL_Object srcobj, mixSDL_SourceProp pname,
src->firstqueued = buf; src->firstqueued = buf;
src->nextqueued = src->firstqueued; src->nextqueued = src->firstqueued;
src->prevqueued = 0;
src->lastqueued = src->nextqueued; src->lastqueued = src->nextqueued;
if (src->lastqueued) if (src->lastqueued)
src->lastqueued->next = 0; src->lastqueued->next = 0;
@@ -854,6 +859,7 @@ mixSDL_SourceQueueBuffers (mixSDL_Object srcobj, uint32 n,
{ {
src->firstqueued = buf; src->firstqueued = buf;
src->nextqueued = buf; src->nextqueued = buf;
src->prevqueued = 0;
} }
src->cqueued++; src->cqueued++;
buf->state = MIX_BUF_QUEUED; buf->state = MIX_BUF_QUEUED;
@@ -924,6 +930,8 @@ mixSDL_SourceUnqueueBuffers (mixSDL_Object srcobj, uint32 n,
/* remove buffer from the chain */ /* remove buffer from the chain */
if (src->nextqueued == buf) if (src->nextqueued == buf)
src->nextqueued = buf->next; src->nextqueued = buf->next;
if (src->prevqueued == buf)
src->prevqueued = 0;
if (src->lastqueued == buf) if (src->lastqueued == buf)
src->lastqueued = 0; src->lastqueued = 0;
src->firstqueued = buf->next; src->firstqueued = buf->next;
@@ -983,10 +991,12 @@ mixSDL_SourceUnqueueAll (mixSDL_Source *src)
src->firstqueued = 0; src->firstqueued = 0;
src->nextqueued = 0; src->nextqueued = 0;
src->prevqueued = 0;
src->lastqueued = 0; src->lastqueued = 0;
src->cqueued = 0; src->cqueued = 0;
src->cprocessed = 0; src->cprocessed = 0;
src->curbufofs = 0; src->curbufofs = 0;
src->curbufdelta = 0;
} }
/* add the source to the active array */ /* add the source to the active array */
@@ -1098,7 +1108,9 @@ mixSDL_SourceStop_internal (mixSDL_Source *src)
src->lastqueued = 0; src->lastqueued = 0;
} }
src->nextqueued = 0; src->nextqueued = 0;
src->prevqueued = 0;
src->curbufofs = 0; src->curbufofs = 0;
src->curbufdelta = 0;
mixSDL_UnlockMutex (buf_mutex); mixSDL_UnlockMutex (buf_mutex);
} }
@@ -1124,18 +1136,20 @@ mixSDL_SourceRewind_internal (mixSDL_Source *src)
mixSDL_UnlockMutex (buf_mutex); mixSDL_UnlockMutex (buf_mutex);
src->curbufofs = 0; src->curbufofs = 0;
src->curbufdelta = 0;
src->cprocessed = 0; src->cprocessed = 0;
src->nextqueued = src->firstqueued; src->nextqueued = src->firstqueued;
src->prevqueued = 0;
src->state = MIX_INITIAL; src->state = MIX_INITIAL;
} }
/* get the sample next in queue in internal format */ /* get the sample next in queue in internal format */
static __inline__ bool static __inline__ bool
mixSDL_SourceGetNextSample (mixSDL_Source *src, sint32* psamp) mixSDL_SourceGetNextSample (mixSDL_Source *src, sint32* psamp, bool left)
{ {
/* fake the data if requested */ /* fake the data if requested */
if (mixer_driverflags & MIX_DRIVER_FAKE_DATA) if (mixer_driverflags & MIX_DRIVER_FAKE_DATA)
return mixSDL_SourceGetFakeSample (src, psamp); return mixSDL_SourceGetFakeSample (src, psamp, left);
while (src->nextqueued) while (src->nextqueued)
{ {
@@ -1148,14 +1162,35 @@ mixSDL_SourceGetNextSample (mixSDL_Source *src, sint32* psamp)
/* buffer invalid, go next */ /* buffer invalid, go next */
buf->state = MIX_BUF_PROCESSED; buf->state = MIX_BUF_PROCESSED;
src->curbufofs = 0; src->curbufofs = 0;
src->curbufdelta = 0;
src->prevqueued = src->nextqueued;
src->nextqueued = src->nextqueued->next; src->nextqueued = src->nextqueued->next;
src->cprocessed++; src->cprocessed++;
continue; continue;
} }
data = buf->data + src->curbufofs; if (mixer_freq == buf->orgfreq)
{
data = buf->data + (uint32)src->curbufofs;
samp = mixSDL_GetSampleInt (data, mixer_chansize); samp = mixSDL_GetSampleInt (data, mixer_chansize);
src->curbufofs += mixer_chansize; src->curbufofs += mixer_chansize;
}
else if (mixer_freq > buf->orgfreq)
{
if (mixer_quality == MIX_QUALITY_DEFAULT)
samp = mixSDL_GetResampledInt_linear (src, left);
else if (mixer_quality == MIX_QUALITY_HIGH)
samp = mixSDL_GetResampledInt_cubic (src, left);
else
samp = mixSDL_GetResampledInt_nearest (src, left);
}
else
{
/* because currently linear and cubic resamplers do not work
for downsampling */
samp = mixSDL_GetResampledInt_nearest (src, left);
}
samp *= src->gain; samp *= src->gain;
if (mixer_chansize == 2) if (mixer_chansize == 2)
@@ -1184,6 +1219,8 @@ mixSDL_SourceGetNextSample (mixSDL_Source *src, sint32* psamp)
/* buffer exhausted, go next */ /* buffer exhausted, go next */
buf->state = MIX_BUF_PROCESSED; buf->state = MIX_BUF_PROCESSED;
src->curbufofs = 0; src->curbufofs = 0;
src->curbufdelta = 0;
src->prevqueued = src->nextqueued;
src->nextqueued = src->nextqueued->next; src->nextqueued = src->nextqueued->next;
src->cprocessed++; src->cprocessed++;
} }
@@ -1206,20 +1243,47 @@ mixSDL_SourceGetNextSample (mixSDL_Source *src, sint32* psamp)
/* fake the next sample, but process buffers and states */ /* fake the next sample, but process buffers and states */
static __inline__ bool static __inline__ bool
mixSDL_SourceGetFakeSample (mixSDL_Source *src, sint32* psamp) mixSDL_SourceGetFakeSample (mixSDL_Source *src, sint32* psamp, bool left)
{ {
while (src->nextqueued) while (src->nextqueued)
{ {
mixSDL_Buffer *buf = src->nextqueued; mixSDL_Buffer *buf = src->nextqueued;
*psamp = 0; if (mixer_freq == buf->orgfreq)
{
src->curbufofs += mixer_chansize; src->curbufofs += mixer_chansize;
}
else
{
double offset, intoffset;
if (MIX_FORMAT_CHANS (mixer_format) == 2)
{
if (!left)
{
offset = src->curbufdelta +
(double)src->nextqueued->orgfreq / mixer_freq;
src->curbufdelta = modf (offset, &intoffset);
src->curbufofs += (uint32)intoffset * mixer_sampsize;
}
}
else
{
offset = src->curbufdelta +
(double)src->nextqueued->orgfreq / mixer_freq;
src->curbufdelta = modf (offset, &intoffset);
src->curbufofs += (uint32)intoffset * mixer_sampsize;
}
}
*psamp = 0;
if (src->curbufofs >= buf->size) if (src->curbufofs >= buf->size)
{ {
/* buffer exhausted, go next */ /* buffer exhausted, go next */
buf->state = MIX_BUF_PROCESSED; buf->state = MIX_BUF_PROCESSED;
src->curbufofs = 0; src->curbufofs = 0;
src->curbufdelta = 0;
src->prevqueued = src->nextqueued;
src->nextqueued = src->nextqueued->next; src->nextqueued = src->nextqueued->next;
src->cprocessed++; src->cprocessed++;
} }
@@ -1498,12 +1562,11 @@ mixSDL_BufferData (mixSDL_Object bufobj, uint32 format, void* data,
buf->orgchannels = MIX_FORMAT_CHANS (format); buf->orgchannels = MIX_FORMAT_CHANS (format);
buf->orgchansize = MIX_FORMAT_BPC (format); buf->orgchansize = MIX_FORMAT_BPC (format);
conv.srcsamples = size / MIX_FORMAT_SAMPSIZE (format); conv.srcsamples = conv.dstsamples =
conv.dstsamples = (uint32) size / MIX_FORMAT_SAMPSIZE (format);
((double)conv.srcsamples * mixer_freq / freq);
if (conv.dstsamples > if (conv.dstsamples >
UINT32_MAX / MIX_FORMAT_SAMPSIZE (mixer_format)) UINT32_MAX / MIX_FORMAT_SAMPSIZE (format))
{ {
mixSDL_SetError (MIX_INVALID_VALUE); mixSDL_SetError (MIX_INVALID_VALUE);
} }
@@ -1518,7 +1581,7 @@ mixSDL_BufferData (mixSDL_Object bufobj, uint32 format, void* data,
{ {
buf->data = HMalloc (dstsize); buf->data = HMalloc (dstsize);
if (format == mixer_format && freq == mixer_freq) if (format == mixer_format)
{ {
/* format identical to internal */ /* format identical to internal */
buf->locked = true; buf->locked = true;
@@ -1542,11 +1605,9 @@ mixSDL_BufferData (mixSDL_Object bufobj, uint32 format, void* data,
conv.srcfmt = format; conv.srcfmt = format;
conv.srcdata = data; conv.srcdata = data;
conv.srcsize = size; conv.srcsize = size;
conv.srcfreq = freq;
conv.dstfmt = mixer_format; conv.dstfmt = mixer_format;
conv.dstdata = buf->data; conv.dstdata = buf->data;
conv.dstsize = dstsize; conv.dstsize = dstsize;
conv.dstfreq = mixer_freq;
buf->locked = true; buf->locked = true;
mixSDL_UnlockMutex (buf_mutex); mixSDL_UnlockMutex (buf_mutex);
@@ -1565,73 +1626,6 @@ mixSDL_BufferData (mixSDL_Object bufobj, uint32 format, void* data,
mixSDL_UnlockMutex (buf_mutex); mixSDL_UnlockMutex (buf_mutex);
} }
/* convert a user buffer from one format to another */
void
mixSDL_ConvertBuffer (uint32 srcfmt, void* srcdata, uint32 srcsize,
uint32 srcfreq, uint32 dstfmt, void* dstdata,
uint32 dstfreq, uint32 dstsize)
{
mixSDL_Convertion conv;
uint32 reqsize;
if (!srcdata || !dstdata)
{
mixSDL_SetError (MIX_INVALID_VALUE);
fprintf (stderr, "mixSDL_ConvertBuffer(): called "
"with null buffer\n");
return;
}
conv.srcsamples = srcsize / MIX_FORMAT_SAMPSIZE (srcfmt);
conv.dstsamples = (uint32)
((double)conv.srcsamples * dstfreq / srcfreq);
if (conv.dstsamples > UINT32_MAX / MIX_FORMAT_SAMPSIZE (dstfmt))
{
mixSDL_SetError (MIX_INVALID_VALUE);
return;
}
reqsize = conv.dstsamples * MIX_FORMAT_SAMPSIZE (mixer_format);
if (reqsize > dstsize)
{
mixSDL_SetError (MIX_INVALID_VALUE);
fprintf (stderr, "mixSDL_ConvertBuffer(): "
"destination buffer too small\n");
return;
}
if (srcfmt == dstfmt && srcfreq == dstfreq)
{
/* user buffer, no S8->U8 convertion */
memcpy (dstdata, srcdata, srcsize);
}
else
{
conv.srcfmt = srcfmt;
conv.srcdata = srcdata;
conv.srcsize = srcsize;
conv.srcfreq = srcfreq;
conv.dstfmt = dstfmt;
conv.dstdata = dstdata;
conv.dstsize = dstsize;
conv.dstfreq = dstfreq;
mixSDL_ConvertBuffer_internal (&conv);
if (conv.dstbpc == 1)
{
/* converted buffer is in S8 format
* have to make it U8
*/
uint8* dst;
for (dst = conv.dstdata; dstsize; dstsize--, dst++)
*dst ^= 0x80;
}
}
}
/************************************************* /*************************************************
* Buffer internals * Buffer internals
@@ -1690,24 +1684,7 @@ mixSDL_ConvertBuffer_internal (mixSDL_Convertion *conv)
else if (conv->srcchans < conv->dstchans) else if (conv->srcchans < conv->dstchans)
conv->flags |= mixConvStereoUp; conv->flags |= mixConvStereoUp;
if (conv->srcfreq == conv->dstfreq)
{
mixSDL_ResampleFlat (conv); mixSDL_ResampleFlat (conv);
}
else if (conv->dstfreq > conv->srcfreq)
{
if (conv->dstfreq % conv->srcfreq == 0)
mixSDL_ResampleUp_fast (conv);
else
mixSDL_Resample_frac (conv);
}
else
{
if (conv->srcfreq % conv->dstfreq == 0)
mixSDL_ResampleDown_fast (conv);
else
mixSDL_Resample_frac (conv);
}
} }
/************************************************* /*************************************************
@@ -1760,6 +1737,184 @@ mixSDL_PutSampleInt (void *dst, uint32 bpc, sint32 samp)
*(sint8 *)dst = samp; *(sint8 *)dst = samp;
} }
/* get a resampled sample from internal buffer (nearest neighbor) */
static __inline__ sint32
mixSDL_GetResampledInt_nearest (mixSDL_Source *src, bool left)
{
uint8 *d0 = src->nextqueued->data + src->curbufofs;
double offset, intoffset;
if (MIX_FORMAT_CHANS (mixer_format) == 2)
{
if (!left)
{
d0 += mixer_chansize;
offset = src->curbufdelta +
(double)src->nextqueued->orgfreq / mixer_freq;
src->curbufdelta = modf (offset, &intoffset);
src->curbufofs += (uint32)intoffset * mixer_sampsize;
}
}
else
{
offset = src->curbufdelta +
(double)src->nextqueued->orgfreq / mixer_freq;
src->curbufdelta = modf (offset, &intoffset);
src->curbufofs += (uint32)intoffset * mixer_sampsize;
}
return mixSDL_GetSampleInt (d0, mixer_chansize);
}
/* get a resampled sample from internal buffer (linear interpolation) */
static __inline__ sint32
mixSDL_GetResampledInt_linear (mixSDL_Source *src, bool left)
{
// TODO: support for downsampling
mixSDL_Buffer *curr = src->nextqueued;
mixSDL_Buffer *next = src->nextqueued->next;
uint8 *d0, *d1;
sint32 s0, s1, samp;
double offset, intoffset, delta;
delta = src->curbufdelta;
d0 = curr->data + src->curbufofs;
if (MIX_FORMAT_CHANS (mixer_format) == 2)
{
if (!left)
{
d0 += mixer_chansize;
offset = src->curbufdelta +
(double)src->nextqueued->orgfreq / mixer_freq;
src->curbufdelta = modf (offset, &intoffset);
src->curbufofs += (uint32)intoffset * mixer_sampsize;
}
}
else
{
offset = src->curbufdelta +
(double)src->nextqueued->orgfreq / mixer_freq;
src->curbufdelta = modf (offset, &intoffset);
src->curbufofs += (uint32)intoffset * mixer_sampsize;
}
if (d0 + mixer_sampsize >= curr->data + curr->size)
{
if (next && next->data && next->size >= mixer_sampsize)
{
d1 = next->data;
if (!left)
d1 += mixer_chansize;
}
else
d1 = d0;
}
else
d1 = d0 + mixer_sampsize;
s0 = mixSDL_GetSampleInt (d0, mixer_chansize);
s1 = mixSDL_GetSampleInt (d1, mixer_chansize);
samp = s0 + (sint32)(delta * (s1 - s0));
return samp;
}
/* get a resampled sample from internal buffer (cubic interpolation) */
static __inline__ sint32
mixSDL_GetResampledInt_cubic (mixSDL_Source *src, bool left)
{
// TODO: support for downsampling
mixSDL_Buffer *prev = src->prevqueued;
mixSDL_Buffer *curr = src->nextqueued;
mixSDL_Buffer *next = src->nextqueued->next;
uint8 *d0, *d1, *d2, *d3; /* prev, curr, next, next + 1 */
sint32 samp;
double offset, intoffset;
float delta, delta2, a, b, c, s0, s1, s2, s3;
delta = (float)src->curbufdelta;
delta2 = delta * delta;
d1 = curr->data + src->curbufofs;
if (MIX_FORMAT_CHANS (mixer_format) == 2)
{
if (!left)
{
d1 += mixer_chansize;
offset = src->curbufdelta +
(double)src->nextqueued->orgfreq / mixer_freq;
src->curbufdelta = modf (offset, &intoffset);
src->curbufofs += (uint32)intoffset * mixer_sampsize;
}
}
else
{
offset = src->curbufdelta +
(double)src->nextqueued->orgfreq / mixer_freq;
src->curbufdelta = modf (offset, &intoffset);
src->curbufofs += (uint32)intoffset * mixer_sampsize;
}
if (d1 - mixer_sampsize < curr->data)
{
if (prev && prev->data && prev->size >= mixer_sampsize)
{
d0 = prev->data + prev->size - mixer_sampsize;
if (!left)
d0 += mixer_chansize;
}
else
d0 = d1;
}
else
d0 = d1 - mixer_sampsize;
if (d1 + mixer_sampsize >= curr->data + curr->size)
{
if (next && next->data && next->size >= mixer_sampsize * 2)
{
d2 = next->data;
if (!left)
d2 += mixer_chansize;
d3 = d2 + mixer_sampsize;
}
else
d2 = d3 = d1;
}
else
{
d2 = d1 + mixer_sampsize;
if (d2 + mixer_sampsize >= curr->data + curr->size)
{
if (next && next->data && next->size >= mixer_sampsize)
{
d3 = next->data;
if (!left)
d3 += mixer_chansize;
}
else
d3 = d2;
}
else
d3 = d2 + mixer_sampsize;
}
s0 = (float)mixSDL_GetSampleInt (d0, mixer_chansize);
s1 = (float)mixSDL_GetSampleInt (d1, mixer_chansize);
s2 = (float)mixSDL_GetSampleInt (d2, mixer_chansize);
s3 = (float)mixSDL_GetSampleInt (d3, mixer_chansize);
a = (3.0f * (s1 - s2) - s0 + s3) * 0.5f;
b = 2.0f * s2 + s0 - ((5.0f * s1 + s3) * 0.5f);
c = (s2 - s0) * 0.5f;
samp = (sint32)(a * delta2 * delta + b * delta2 + c * delta + s1);
return samp;
}
/* get next sample from external buffer /* get next sample from external buffer
* in internal format, while performing * in internal format, while performing
* convertion if necessary * convertion if necessary
@@ -1811,88 +1966,6 @@ mixSDL_PutConvSample (uint8 **pdst, uint32 bpc, uint32 flags, sint32 samp)
} }
} }
/* resampling with fractional rate change */
static void
mixSDL_Resample_frac (mixSDL_Convertion *conv)
{
mixSDL_ConvFlags flags = conv->flags;
uint8 *src = conv->srcdata;
uint8 *dst = conv->dstdata;
uint32 srcsamples = conv->srcsamples;
uint32 srcbpc = conv->srcbpc;
uint32 dstbpc = conv->dstbpc;
double convrate = (double)conv->srcfreq / conv->dstfreq;
double dstpos = 0;
uint32 nextsrcpos; /* next position already read */
sint32 sampl, sampr, nextsampl, nextsampr;
uint32 srcjump = srcbpc * conv->srcchans;
bool stereo = conv->srcchans == 2 && !(flags & mixConvStereoDown);
uint32 i;
nextsampl = mixSDL_GetConvSample (&src, srcbpc, flags);
if (stereo)
nextsampr = mixSDL_GetConvSample (&src, srcbpc, flags);
else
nextsampr = 0;
nextsrcpos = 0;
for (i = conv->dstsamples; i; i--)
{
double delta, intdstpos;
uint32 srcpos;
uint32 samp;
delta = modf (dstpos, &intdstpos);
srcpos = (uint32) intdstpos;
if (srcpos >= nextsrcpos)
{
if (srcpos == nextsrcpos)
{
sampl = nextsampl;
sampr = nextsampr;
nextsrcpos++;
}
else
{
src += srcjump * (srcpos - nextsrcpos - 1);
sampl = mixSDL_GetConvSample (&src, srcbpc, flags);
if (stereo)
sampr = mixSDL_GetConvSample (&src, srcbpc, flags);
nextsrcpos = srcpos + 1;
}
if (nextsrcpos < srcsamples)
{
nextsampl = mixSDL_GetConvSample (&src, srcbpc, flags);
if (stereo)
nextsampr = mixSDL_GetConvSample (&src, srcbpc, flags);
}
else
{
/* theoretically, here we need to get the next sample
* somehow, which is in the next buffer in the stream;
* leaving the next sample equal to the previous should
* do for now; this will create some-20 minimal
* distortions per second
*/
/* nextsampl = nextsampr = 0; */
}
}
/* iterpolate */
samp = sampl + (sint32) (delta * (nextsampl - sampl));
mixSDL_PutConvSample (&dst, dstbpc, flags, samp);
if (stereo)
{
samp = sampr + (sint32) (delta * (nextsampr - sampr));
mixSDL_PutConvSample (&dst, dstbpc, flags, samp);
}
dstpos += convrate;
}
}
/* resampling with respect to sample size only */ /* resampling with respect to sample size only */
static void static void
mixSDL_ResampleFlat (mixSDL_Convertion *conv) mixSDL_ResampleFlat (mixSDL_Convertion *conv)
@@ -1917,93 +1990,6 @@ mixSDL_ResampleFlat (mixSDL_Convertion *conv)
} }
} }
/* integer-periodic resampling with rate increase */
static void
mixSDL_ResampleUp_fast (mixSDL_Convertion *conv)
{
mixSDL_ConvFlags flags = conv->flags;
uint8 *src = conv->srcdata;
uint8 *dst = conv->dstdata;
uint32 srcbpc = conv->srcbpc;
uint32 dstbpc = conv->dstbpc;
uint32 convrate = conv->dstfreq / conv->srcfreq;
sint32 nextsampl, nextsampr;
bool stereo = conv->srcchans == 2 && !(flags & mixConvStereoDown);
uint32 i;
/* read one sample ahead */
nextsampl = mixSDL_GetConvSample (&src, srcbpc, flags);
if (stereo)
nextsampr = mixSDL_GetConvSample (&src, srcbpc, flags);
else
nextsampr = 0;
for (i = conv->srcsamples; i; i--)
{
sint32 sampl = nextsampl;
sint32 sampr = nextsampr;
sint32 di;
if (i > 1)
{
nextsampl = mixSDL_GetConvSample (&src, srcbpc, flags);
if (stereo)
nextsampr = mixSDL_GetConvSample (&src, srcbpc, flags);
}
else
{
/* theoretically, here we need to get the next sample
* somehow, which is in the next buffer in the stream;
* leaving the next sample equal to the previous should
* do for now; this will create some-20 minimal
* distortions per second
*/
/* nextsampl = nextsampr = 0; */
}
for (di = convrate; di > 0; di--)
{
mixSDL_PutConvSample (&dst, dstbpc, flags, sampl);
sampl += (nextsampl - sampl) / di;
if (stereo)
{
mixSDL_PutConvSample (&dst, dstbpc, flags, sampr);
sampr += (nextsampr - sampr) / di;
}
}
}
}
/* integer-periodic resampling with rate decrease */
static void
mixSDL_ResampleDown_fast (mixSDL_Convertion *conv)
{
mixSDL_ConvFlags flags = conv->flags;
uint8 *src = conv->srcdata;
uint8 *dst = conv->dstdata;
uint32 srcbpc = conv->srcbpc;
uint32 dstbpc = conv->dstbpc;
uint32 convrate = conv->srcfreq / conv->dstfreq;
uint32 srcjump = (convrate - 1) * srcbpc * conv->srcchans;
bool stereo = conv->srcchans == 2 && !(flags & mixConvStereoDown);
uint32 i;
for (i = conv->dstsamples; i; i--)
{
sint32 samp;
samp = mixSDL_GetConvSample (&src, srcbpc, flags);
mixSDL_PutConvSample (&dst, dstbpc, flags, samp);
if (stereo)
{
samp = mixSDL_GetConvSample (&src, srcbpc, flags);
mixSDL_PutConvSample (&dst, dstbpc, flags, samp);
}
src += srcjump;
}
}
/********************************************************** /**********************************************************
* THE mixer - higher quality; smoothed-out clipping * THE mixer - higher quality; smoothed-out clipping
@@ -2018,6 +2004,8 @@ mixSDL_mix_channels (void *userdata, uint8 *stream, sint32 len)
sint32 *end_data = mixer_data + samples; sint32 *end_data = mixer_data + samples;
sint32 *data; sint32 *data;
uint32 step; uint32 step;
bool left = true;
uint32 chans = MIX_FORMAT_CHANS (mixer_format);
/* mixer_datasize < samples should not happen ever, but for now.. */ /* mixer_datasize < samples should not happen ever, but for now.. */
if (mixer_datasize < samples) if (mixer_datasize < samples)
@@ -2051,7 +2039,7 @@ mixSDL_mix_channels (void *userdata, uint8 *stream, sint32 len)
for (; i < MAX_SOURCES && ( for (; i < MAX_SOURCES && (
(src = active_sources[i]) == 0 (src = active_sources[i]) == 0
|| src->state != MIX_PLAYING || src->state != MIX_PLAYING
|| !mixSDL_SourceGetNextSample (src, &samp)); || !mixSDL_SourceGetNextSample (src, &samp, left));
i++) i++)
; ;
@@ -2063,6 +2051,8 @@ mixSDL_mix_channels (void *userdata, uint8 *stream, sint32 len)
} }
*data = fullsamp; *data = fullsamp;
if (chans == 2)
left = !left;
} }
/* unclip work-buffer */ /* unclip work-buffer */
@@ -2176,6 +2166,8 @@ static void
mixSDL_mix_lowq (void *userdata, uint8 *stream, sint32 len) mixSDL_mix_lowq (void *userdata, uint8 *stream, sint32 len)
{ {
uint8 *end_stream = stream + len; uint8 *end_stream = stream + len;
bool left = true;
uint32 chans = MIX_FORMAT_CHANS (mixer_format);
/* keep this order or die */ /* keep this order or die */
mixSDL_LockMutex (src_mutex); mixSDL_LockMutex (src_mutex);
@@ -2198,7 +2190,7 @@ mixSDL_mix_lowq (void *userdata, uint8 *stream, sint32 len)
for (; i < MAX_SOURCES && ( for (; i < MAX_SOURCES && (
(src = active_sources[i]) == 0 (src = active_sources[i]) == 0
|| src->state != MIX_PLAYING || src->state != MIX_PLAYING
|| !mixSDL_SourceGetNextSample (src, &samp)); || !mixSDL_SourceGetNextSample (src, &samp, left));
i++) i++)
; ;
@@ -2228,6 +2220,8 @@ mixSDL_mix_lowq (void *userdata, uint8 *stream, sint32 len)
} }
mixSDL_PutSampleExt (stream, mixer_chansize, fullsamp); mixSDL_PutSampleExt (stream, mixer_chansize, fullsamp);
if (chans == 2)
left = !left;
} }
/* keep this order or die */ /* keep this order or die */
@@ -2243,6 +2237,8 @@ static void
mixSDL_mix_fake (void *userdata, uint8 *stream, sint32 len) mixSDL_mix_fake (void *userdata, uint8 *stream, sint32 len)
{ {
uint8 *end_stream = stream + len; uint8 *end_stream = stream + len;
bool left = true;
uint32 chans = MIX_FORMAT_CHANS (mixer_format);
/* keep this order or die */ /* keep this order or die */
mixSDL_LockMutex (src_mutex); mixSDL_LockMutex (src_mutex);
@@ -2262,10 +2258,12 @@ mixSDL_mix_fake (void *userdata, uint8 *stream, sint32 len)
for (; i < MAX_SOURCES && ( for (; i < MAX_SOURCES && (
(src = active_sources[i]) == 0 (src = active_sources[i]) == 0
|| src->state != MIX_PLAYING || src->state != MIX_PLAYING
|| !mixSDL_SourceGetFakeSample (src, &samp)); || !mixSDL_SourceGetFakeSample (src, &samp, left));
i++) i++)
; ;
} }
if (chans == 2)
left = !left;
} }
/* keep this order or die */ /* keep this order or die */
+2 -4
View File
@@ -192,8 +192,10 @@ typedef struct
uint32 cprocessed; uint32 cprocessed;
mixSDL_Buffer *firstqueued; /* first buf in the queue */ mixSDL_Buffer *firstqueued; /* first buf in the queue */
mixSDL_Buffer *nextqueued; /* next to play, or 0 */ mixSDL_Buffer *nextqueued; /* next to play, or 0 */
mixSDL_Buffer *prevqueued; /* previously played */
mixSDL_Buffer *lastqueued; /* last in queue */ mixSDL_Buffer *lastqueued; /* last in queue */
uint32 curbufofs; uint32 curbufofs;
double curbufdelta;
} mixSDL_Source; } mixSDL_Source;
@@ -258,10 +260,6 @@ void mixSDL_GetBufferi (mixSDL_Object bufobj, mixSDL_BufferProp pname,
void mixSDL_BufferData (mixSDL_Object bufobj, uint32 format, void* data, void mixSDL_BufferData (mixSDL_Object bufobj, uint32 format, void* data,
uint32 size, uint32 freq); uint32 size, uint32 freq);
void mixSDL_ConvertBuffer (uint32 srcfmt, void* srcdata, uint32 srcsize,
uint32 srcfreq, uint32 dstfmt, void* dstdata,
uint32 dstsize, uint32 dstfreq);
/* Make sure the prop-value type is of suitable size /* Make sure the prop-value type is of suitable size
* it must be able to store both int and void* * it must be able to store both int and void*
+6 -7
View File
@@ -43,7 +43,6 @@ typedef struct
uint32 srcfmt; uint32 srcfmt;
void *srcdata; void *srcdata;
uint32 srcsize; uint32 srcsize;
uint32 srcfreq;
uint32 srcbpc; /* bytes/sample for 1 chan */ uint32 srcbpc; /* bytes/sample for 1 chan */
uint32 srcchans; uint32 srcchans;
uint32 srcsamples; uint32 srcsamples;
@@ -51,7 +50,6 @@ typedef struct
uint32 dstfmt; uint32 dstfmt;
void *dstdata; void *dstdata;
uint32 dstsize; uint32 dstsize;
uint32 dstfreq;
uint32 dstbpc; /* bytes/sample for 1 chan */ uint32 dstbpc; /* bytes/sample for 1 chan */
uint32 dstchans; uint32 dstchans;
uint32 dstsamples; uint32 dstsamples;
@@ -61,10 +59,7 @@ typedef struct
} mixSDL_Convertion; } mixSDL_Convertion;
static void mixSDL_ConvertBuffer_internal (mixSDL_Convertion *conv); static void mixSDL_ConvertBuffer_internal (mixSDL_Convertion *conv);
static void mixSDL_Resample_frac (mixSDL_Convertion *conv);
static void mixSDL_ResampleFlat (mixSDL_Convertion *conv); static void mixSDL_ResampleFlat (mixSDL_Convertion *conv);
static void mixSDL_ResampleUp_fast (mixSDL_Convertion *conv);
static void mixSDL_ResampleDown_fast (mixSDL_Convertion *conv);
static __inline__ sint32 mixSDL_GetSampleExt (void *src, uint32 bpc); static __inline__ sint32 mixSDL_GetSampleExt (void *src, uint32 bpc);
static __inline__ sint32 mixSDL_GetSampleInt (void *src, uint32 bpc); static __inline__ sint32 mixSDL_GetSampleInt (void *src, uint32 bpc);
@@ -73,6 +68,10 @@ static __inline__ void mixSDL_PutSampleInt (void *dst, uint32 bpc,
static __inline__ void mixSDL_PutSampleExt (void *dst, uint32 bpc, static __inline__ void mixSDL_PutSampleExt (void *dst, uint32 bpc,
sint32 samp); sint32 samp);
static __inline__ sint32 mixSDL_GetResampledInt_nearest (mixSDL_Source *src, bool left);
static __inline__ sint32 mixSDL_GetResampledInt_linear (mixSDL_Source *src, bool left);
static __inline__ sint32 mixSDL_GetResampledInt_cubic (mixSDL_Source *src, bool left);
/* Source manipulation */ /* Source manipulation */
static void mixSDL_SourceUnqueueAll (mixSDL_Source *src); static void mixSDL_SourceUnqueueAll (mixSDL_Source *src);
static void mixSDL_SourceStop_internal (mixSDL_Source *src); static void mixSDL_SourceStop_internal (mixSDL_Source *src);
@@ -124,9 +123,9 @@ static void mixSDL_mix_fake (void *userdata, uint8 *stream, sint32 len);
static void mixSDL_UnclipWorkBuffer (sint32 *data, sint32 *end_data, static void mixSDL_UnclipWorkBuffer (sint32 *data, sint32 *end_data,
uint32 step); uint32 step);
static __inline__ bool mixSDL_SourceGetNextSample (mixSDL_Source *src, static __inline__ bool mixSDL_SourceGetNextSample (mixSDL_Source *src,
sint32* samp); sint32* samp, bool left);
static __inline__ bool mixSDL_SourceGetFakeSample (mixSDL_Source *src, static __inline__ bool mixSDL_SourceGetFakeSample (mixSDL_Source *src,
sint32* psamp); sint32* psamp, bool left);
/* SDL driver */ /* SDL driver */
static const char* mixSDL_DriverGetName (void); static const char* mixSDL_DriverGetName (void);
@@ -55,7 +55,6 @@
#define TFBSound_IsBuffer mixSDL_IsBuffer #define TFBSound_IsBuffer mixSDL_IsBuffer
#define TFBSound_GetBufferi mixSDL_GetBufferi #define TFBSound_GetBufferi mixSDL_GetBufferi
#define TFBSound_BufferData mixSDL_BufferData #define TFBSound_BufferData mixSDL_BufferData
#define TFBSound_ConvertBuffer mixSDL_ConvertBuffer
#define TFBSOUND_GAIN MIX_GAIN #define TFBSOUND_GAIN MIX_GAIN
#define TFBSOUND_BUFFER MIX_BUFFER #define TFBSOUND_BUFFER MIX_BUFFER
@@ -244,18 +244,6 @@ TFBSound_BufferData (TFBSound_Object bufobj, uint32 format, void* data,
mixSDL_BufferData ((mixSDL_Object) bufobj, format, data, size, freq); mixSDL_BufferData ((mixSDL_Object) bufobj, format, data, size, freq);
} }
void
TFBSound_ConvertBuffer (uint32 srcfmt, void* srcdata, uint32 srcsize,
uint32 srcfreq, uint32 dstfmt, void* dstdata,
uint32 dstsize, uint32 dstfreq)
{
if (SoundDriver == TFB_SOUNDDRIVER_OPENAL)
fprintf (stderr, "ConvertBuffer is not supported bu openAL\n");
else
mixSDL_ConvertBuffer (srcfmt, srcdata, srcsize, srcfreq, dstfmt, dstdata,
dstsize, dstfreq);
}
int int
TFB_choose_InitSound (int driver, int flags) TFB_choose_InitSound (int driver, int flags)
{ {
@@ -83,10 +83,6 @@ void TFBSound_GetBufferi (TFBSound_Object bufobj, TFBSound_BufferProp pname,
void TFBSound_BufferData (TFBSound_Object bufobj, uint32 format, void* data, void TFBSound_BufferData (TFBSound_Object bufobj, uint32 format, void* data,
uint32 size, uint32 freq); uint32 size, uint32 freq);
void TFBSound_ConvertBuffer (uint32 srcfmt, void* srcdata, uint32 srcsize,
uint32 srcfreq, uint32 dstfmt, void* dstdata,
uint32 dstsize, uint32 dstfreq);
#define TFBSound_BufferData_Linux alBufferWriteData_LOKI #define TFBSound_BufferData_Linux alBufferWriteData_LOKI
enum enum
{ {