SDL2: MVE: fix noise from reading undefined sound data
Commit 07245a0bc2
added the SDL_mixer backend for MVE audio. That
commit set the length of the converted sound equal to the size of the
buffer that SDL requested as a work area. No one ever touched that
logic, until now. In SDL1, that choice worked fine. In SDL2, this
causes garbage to play after the sound, because SDL2 considers the
buffer to be defined only up to the length returned in
`SDL_AudioCVT::cvt_len`. Bytes beyond that length are undefined[1], and
in practice contain garbage. Fix the noise by setting the sound length
equal to the length returned by SDL2, so that the undefined bytes are
not treated as sound. SDL1 also maintains this length value, so no
version-specific logic is required.
[1]: https://wiki.libsdl.org/SDL_ConvertAudio
Reported-by: andrew-strong <https://github.com/dxx-rebirth/dxx-rebirth/issues/398>
This commit is contained in:
parent
1b8ff6ac77
commit
524f042659
|
@ -261,7 +261,7 @@ struct MVE_audio_clamp
|
||||||
static int audiobuf_created = 0;
|
static int audiobuf_created = 0;
|
||||||
static void mve_audio_callback(void *userdata, unsigned char *stream, int len);
|
static void mve_audio_callback(void *userdata, unsigned char *stream, int len);
|
||||||
static array<std::unique_ptr<short[], MVE_audio_deleter>, TOTAL_AUDIO_BUFFERS> mve_audio_buffers;
|
static array<std::unique_ptr<short[], MVE_audio_deleter>, TOTAL_AUDIO_BUFFERS> mve_audio_buffers;
|
||||||
static int mve_audio_buflens[TOTAL_AUDIO_BUFFERS];
|
static array<unsigned, TOTAL_AUDIO_BUFFERS> mve_audio_buflens;
|
||||||
static int mve_audio_curbuf_curpos=0;
|
static int mve_audio_curbuf_curpos=0;
|
||||||
static int mve_audio_bufhead=0;
|
static int mve_audio_bufhead=0;
|
||||||
static int mve_audio_buftail=0;
|
static int mve_audio_buftail=0;
|
||||||
|
@ -393,8 +393,7 @@ static int create_audiobuf_handler(unsigned char, unsigned char minor, const uns
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
mve_audio_buffers = {};
|
mve_audio_buffers = {};
|
||||||
memset(mve_audio_buflens, 0, sizeof(mve_audio_buflens));
|
mve_audio_buflens = {};
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -415,17 +414,6 @@ static int play_audio_handler(unsigned char, unsigned char, const unsigned char
|
||||||
|
|
||||||
static int audio_data_handler(unsigned char major, unsigned char, const unsigned char *data, int, void *)
|
static int audio_data_handler(unsigned char major, unsigned char, const unsigned char *data, int, void *)
|
||||||
{
|
{
|
||||||
|
|
||||||
#if DXX_USE_SDLMIXER
|
|
||||||
// MD2211: for audio conversion
|
|
||||||
SDL_AudioCVT cvt;
|
|
||||||
int clen;
|
|
||||||
int out_freq;
|
|
||||||
Uint16 out_format;
|
|
||||||
int out_channels;
|
|
||||||
// end MD2211
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static const int selected_chan=1;
|
static const int selected_chan=1;
|
||||||
int chan;
|
int chan;
|
||||||
int nsamp;
|
int nsamp;
|
||||||
|
@ -474,37 +462,44 @@ static int audio_data_handler(unsigned char major, unsigned char, const unsigned
|
||||||
p.reset(reinterpret_cast<int16_t *>(mve_alloc(nsamp)));
|
p.reset(reinterpret_cast<int16_t *>(mve_alloc(nsamp)));
|
||||||
memset(p.get(), 0, nsamp); /* XXX */
|
memset(p.get(), 0, nsamp); /* XXX */
|
||||||
}
|
}
|
||||||
mve_audio_buflens[mve_audio_buftail] = nsamp;
|
unsigned buflen = nsamp;
|
||||||
mve_audio_buffers[mve_audio_buftail] = std::move(p);
|
|
||||||
|
|
||||||
// MD2211: the following block does on-the-fly audio conversion for SDL_mixer
|
// MD2211: the following block does on-the-fly audio conversion for SDL_mixer
|
||||||
#if DXX_USE_SDLMIXER
|
#if DXX_USE_SDLMIXER
|
||||||
if (!CGameArg.SndDisableSdlMixer) {
|
if (!CGameArg.SndDisableSdlMixer) {
|
||||||
// build converter: in = MVE format, out = SDL_mixer output
|
// build converter: in = MVE format, out = SDL_mixer output
|
||||||
|
int out_freq;
|
||||||
|
Uint16 out_format;
|
||||||
|
int out_channels;
|
||||||
Mix_QuerySpec(&out_freq, &out_format, &out_channels); // get current output settings
|
Mix_QuerySpec(&out_freq, &out_format, &out_channels); // get current output settings
|
||||||
|
|
||||||
|
SDL_AudioCVT cvt{};
|
||||||
SDL_BuildAudioCVT(&cvt, mve_audio_spec->format, mve_audio_spec->channels, mve_audio_spec->freq,
|
SDL_BuildAudioCVT(&cvt, mve_audio_spec->format, mve_audio_spec->channels, mve_audio_spec->freq,
|
||||||
out_format, out_channels, out_freq);
|
out_format, out_channels, out_freq);
|
||||||
|
|
||||||
clen = nsamp * cvt.len_mult;
|
|
||||||
RAIIdmem<uint8_t[]> cvtbuf;
|
RAIIdmem<uint8_t[]> cvtbuf;
|
||||||
MALLOC(cvtbuf, uint8_t[], clen);
|
MALLOC(cvtbuf, uint8_t[], nsamp * cvt.len_mult);
|
||||||
cvt.buf = cvtbuf.get();
|
cvt.buf = cvtbuf.get();
|
||||||
cvt.len = nsamp;
|
cvt.len = nsamp;
|
||||||
|
|
||||||
// read the audio buffer into the conversion buffer
|
// read the audio buffer into the conversion buffer
|
||||||
memcpy(cvt.buf, mve_audio_buffers[mve_audio_buftail].get(), nsamp);
|
memcpy(cvt.buf, p.get(), nsamp);
|
||||||
|
|
||||||
// do the conversion
|
// do the conversion
|
||||||
if (SDL_ConvertAudio(&cvt))
|
if (SDL_ConvertAudio(&cvt))
|
||||||
con_puts(CON_DEBUG,"audio conversion failed!");
|
con_printf(CON_URGENT, "%s:%u: SDL_ConvertAudio failed: nsamp=%u out_format=%i out_channels=%i out_freq=%i", __FILE__, __LINE__, nsamp, out_format, out_channels, out_freq);
|
||||||
|
else
|
||||||
|
{
|
||||||
// copy back to the audio buffer
|
// copy back to the audio buffer
|
||||||
mve_audio_buffers[mve_audio_buftail].reset(reinterpret_cast<int16_t *>(mve_alloc(clen))); // free the old audio buffer
|
const std::size_t converted_buffer_size = cvt.len_cvt;
|
||||||
mve_audio_buflens[mve_audio_buftail] = clen;
|
p.reset(reinterpret_cast<int16_t *>(mve_alloc(converted_buffer_size))); // free the old audio buffer
|
||||||
memcpy(mve_audio_buffers[mve_audio_buftail].get(), cvt.buf, clen);
|
buflen = converted_buffer_size;
|
||||||
|
memcpy(p.get(), cvt.buf, converted_buffer_size);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
mve_audio_buffers[mve_audio_buftail] = std::move(p);
|
||||||
|
mve_audio_buflens[mve_audio_buftail] = buflen;
|
||||||
|
|
||||||
if (++mve_audio_buftail == TOTAL_AUDIO_BUFFERS)
|
if (++mve_audio_buftail == TOTAL_AUDIO_BUFFERS)
|
||||||
mve_audio_buftail = 0;
|
mve_audio_buftail = 0;
|
||||||
|
@ -775,7 +770,7 @@ void MVE_rmEndMovie(std::unique_ptr<MVESTREAM>)
|
||||||
mve_audio_canplay = 0;
|
mve_audio_canplay = 0;
|
||||||
}
|
}
|
||||||
mve_audio_buffers = {};
|
mve_audio_buffers = {};
|
||||||
memset(mve_audio_buflens, 0, sizeof(mve_audio_buflens));
|
mve_audio_buflens = {};
|
||||||
|
|
||||||
mve_audio_curbuf_curpos=0;
|
mve_audio_curbuf_curpos=0;
|
||||||
mve_audio_bufhead=0;
|
mve_audio_bufhead=0;
|
||||||
|
|
Loading…
Reference in a new issue