Norbert wrote:Suggestions on how to proceed are most welcome.
The simplest workaround would be to replace "dlen*cvt.len_mult" with "dlen*(cvt.len_mult+1)".
I tried this and it works.
By the way, I see that most wavs were exported with an old version of PR that doesn't know about the header of wave resources (and thus treats the header as part of the wave data). It can be heard as a pop at the beginning of sound. This is the most hearable in save.wav.
Most waves should have 11000 Hz samplerates, except popup.wav, which should be 14000 Hz.
Norbert wrote:Maybe I should point people from the SDL mailing list (or IRC channel) to this thread; maybe a bug report is in order?
Yes, this seems to be an SDL bug, see below.
It looks like it was fixed in a newer version, see the end of my post.
I just downloaded the sources of SDL 1.2 and 2.0.
I found some differences between the audio conversion in the two versions: (SDL_audiocvt.c)
1.2 seems to do only "hi_rate = lo_rate*2^x" conversions. (It has a "SDL_RateSLOW" converter, but the only call to it is disabled with an #if.)
If this is not the case, the new rate is rounded to the a rate that satisfies the above equation. (That is, new = old * some power of 2.)
2.0 has a "SDL_BuildAudioResampleCVT" to handle arbitrary rate conversions.
The part that calculates len_mult is this:
Code: Select all
if (src_rate < dst_rate) {
const double mult = ((double) dst_rate) / ((double) src_rate);
cvt->len_mult *= (int) SDL_ceil(mult);
cvt->len_ratio *= mult;
} else {
cvt->len_ratio /= ((double) src_rate) / ((double) dst_rate);
}
And SDL_ceil is defined as... (in SDL_stdlib.c)
Code: Select all
double
SDL_ceil(double x)
{
#ifdef HAVE_CEIL
return ceil(x);
#else
return (double)(int)((x)+0.5);
#endif /* HAVE_CEIL */
}
... and HAVE_CEIL is not defined, because HAVE_LIBC is not defined.
But the custom re-implementation rounds up only from 0.5! Ouch!
Perhaps they assumed that the (int) typecast rounds to the nearest integer, but in fact it rounds (truncates) toward zero.
Even the C standard says that: (in 6.3.1.4)
When a finite value of real floating type is converted to an integer type other than _Bool, the fractional part is discarded (i.e., the value is truncated toward zero).
It seems that the whole "custom math library" was introduced in 2.0, it's not in 1.2.
Finally, it looks like this bug was fixed in a newer version:
(more precisely, it was fixed in the repository, meaning that the next version won't have this bug)
https://bugzilla.libsdl.org/show_bug.cgi?id=2274
http://lists.libsdl.org/pipermail/commi ... 07679.html
http://hg.libsdl.org/SDL/rev/8181c3a4a055
The SDL_ceil function is implemented incorrectly when HAVE_CEIL is not defined (HAVE_LIBC not defined).
[...]
This functions is used in the SDL_BuildAudioResampleCVT function of the audio subsystem (SDL_audiocvt.c), and causes a bug in that function.
Norbert wrote:After I had made that first change, two samples were still distorted, chomper.wav and extras.wav, the two WAVs that you also mentioned.
[...]
I decided: I'll try various sampling rates other than 22050 and if nothing works, I'll file a bug report.
Since 44100 fixed the problem (on Linux), I didn't do the latter.
I just tried it: with 22050 Hz, they are also distorted under Windows.
The length of the converted chomper sound is 41053, which can't be correct, because the target of conversion is a 16-bit format. Plus the data is preceded by an extra byte, effectively swapping the upper and lower bytes of the samples.
The actual conversion is done by SDL_Upsample_U16LSB_1c (in SDL_audiotypecvt.c).
It goes from the end of the buffer to the beginning (because the input and output buffer are the same).
And the calculation of the new size ignores the fact that each sample is 2 byte.
Code: Select all
const int dstsize = (int) (((double)cvt->len_cvt) * cvt->rate_incr);
So this is another SDL2 bug.
Some other people have noticed this:
http://forums.libsdl.org/viewtopic.php? ... b868fd3415
https://bitbucket.org/bgK/sdl_psl1ght/c ... 5c1aacfa6d
http://forums.libsdl.org/viewtopic.php?t=7975
Another consequence of this bug:
https://bugzilla.libsdl.org/show_bug.cgi?id=1014 ...but that "fix" doesn't fix this bug.