mirror of
https://github.com/kevinbentley/Descent3.git
synced 2025-01-22 11:28:56 +00:00
Use SDL_QueueAudio() instead callbacks on filling sound buffer
Fixes some issues when sound buffer get exhausted before refilling.
This commit is contained in:
parent
87f6ef009f
commit
976f00a1f3
@ -21,15 +21,6 @@
|
||||
|
||||
namespace D3 {
|
||||
|
||||
void MovieSoundDevice::SDLAudioCallback(void *userdata, unsigned char *stream, int len) {
|
||||
auto device = static_cast<MovieSoundDevice *>(userdata);
|
||||
for (int i = 0; i < len; i += 2) {
|
||||
int16_t sample = device->m_sound_buffer->front();
|
||||
device->m_sound_buffer->pop_front();
|
||||
memcpy(&stream[i], &sample, 2);
|
||||
}
|
||||
}
|
||||
|
||||
MovieSoundDevice::MovieSoundDevice(int sample_rate, uint16_t sample_size, uint8_t channels, uint32_t buf_size,
|
||||
bool is_compressed) {
|
||||
SDL_AudioFormat format = (sample_size == 2) ? AUDIO_S16LSB : AUDIO_U8;
|
||||
@ -37,8 +28,8 @@ MovieSoundDevice::MovieSoundDevice(int sample_rate, uint16_t sample_size, uint8_
|
||||
spec.freq = sample_rate;
|
||||
spec.format = format;
|
||||
spec.channels = channels;
|
||||
spec.size = 4096;
|
||||
spec.callback = &MovieSoundDevice::SDLAudioCallback;
|
||||
spec.size = buf_size;
|
||||
spec.callback = nullptr;
|
||||
spec.userdata = this;
|
||||
|
||||
m_device_id = SDL_OpenAudioDevice(nullptr, 0, &spec, nullptr, 0);
|
||||
@ -48,16 +39,20 @@ MovieSoundDevice::MovieSoundDevice(int sample_rate, uint16_t sample_size, uint8_
|
||||
MovieSoundDevice::~MovieSoundDevice() {
|
||||
if (m_device_id > 0) {
|
||||
SDL_CloseAudioDevice(m_device_id);
|
||||
m_device_id = 0;
|
||||
}
|
||||
m_sound_buffer.reset();
|
||||
}
|
||||
|
||||
void MovieSoundDevice::FillBuffer(char *stream, int len) const {
|
||||
SDL_QueueAudio(m_device_id, stream, len);
|
||||
};
|
||||
|
||||
void MovieSoundDevice::Play() { SDL_PauseAudioDevice(m_device_id, 0); }
|
||||
|
||||
void MovieSoundDevice::Stop() { SDL_PauseAudioDevice(m_device_id, 1); }
|
||||
|
||||
void MovieSoundDevice::Lock() { SDL_LockAudioDevice(m_device_id); };
|
||||
void MovieSoundDevice::Lock() { SDL_LockAudioDevice(m_device_id); }
|
||||
|
||||
void MovieSoundDevice::Unlock() { SDL_UnlockAudioDevice(m_device_id); };
|
||||
void MovieSoundDevice::Unlock() { SDL_UnlockAudioDevice(m_device_id); }
|
||||
|
||||
} // namespace D3
|
||||
|
@ -49,19 +49,17 @@ public:
|
||||
[[nodiscard]] bool IsInitialized() const { return m_device_id > 0; }
|
||||
|
||||
/**
|
||||
* Callback for filling SDL audio buffer
|
||||
* @param userdata pointer to instance of this class
|
||||
* @param stream stream that will be filled on callback
|
||||
* @param len length of stream
|
||||
* Fill internal audio stream to be played
|
||||
* @param stream source buffer
|
||||
* @param len length of source buffer
|
||||
*/
|
||||
void static SDLAudioCallback(void *userdata, unsigned char *stream, int len);
|
||||
void FillBuffer(char *stream, int len) const;
|
||||
|
||||
void Play() override;
|
||||
void Stop() override;
|
||||
void Lock() override;
|
||||
void Unlock() override;
|
||||
|
||||
using ISoundDevice::GetBuffer;
|
||||
using ISoundDevice::IsCompressed;
|
||||
|
||||
};
|
||||
|
@ -16,8 +16,7 @@
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <deque>
|
||||
#include <memory>
|
||||
#include <cstring>
|
||||
|
||||
#include "byteswap.h"
|
||||
|
||||
@ -62,26 +61,23 @@ static int16_t getWord(unsigned char **fin) {
|
||||
return value;
|
||||
}
|
||||
|
||||
void mveaudio_process(std::unique_ptr<std::deque<int16_t>> &buffer, unsigned char *data, bool is_compressed) {
|
||||
void mveaudio_process(char *buffer, unsigned char *data, bool is_compressed) {
|
||||
if (is_compressed) {
|
||||
int nCurOffsets[2];
|
||||
|
||||
data += 4;
|
||||
int swath = getWord(&data) / 2;
|
||||
int samples = getWord(&data) / 2;
|
||||
// Fill predictors
|
||||
nCurOffsets[0] = getWord(&data);
|
||||
nCurOffsets[1] = getWord(&data);
|
||||
buffer->push_back((int16_t)std::clamp(nCurOffsets[0], -32768, 32767));
|
||||
buffer->push_back((int16_t)std::clamp(nCurOffsets[1], -32768, 32767));
|
||||
|
||||
for (int i = 0; i < swath; i++) {
|
||||
nCurOffsets[i & 1] += audio_exp_table[data[i]];
|
||||
buffer->push_back((int16_t)std::clamp(nCurOffsets[i & 1], -32768, 32767));
|
||||
for (int i = 0; i < samples; i++) {
|
||||
nCurOffsets[i & 1] = std::clamp(nCurOffsets[i & 1] + audio_exp_table[data[i]], -32768, 32767);
|
||||
memcpy(buffer + i * 2, &nCurOffsets[i & 1], 2);
|
||||
}
|
||||
} else {
|
||||
data += 2;
|
||||
int samples = getWord(&data);
|
||||
for (int i = 0; i < samples; i++) {
|
||||
buffer->push_back(getWord(&data));
|
||||
}
|
||||
memcpy(buffer, &data, samples * 2);
|
||||
}
|
||||
}
|
||||
|
@ -24,6 +24,6 @@
|
||||
* @param data input data
|
||||
* @param is_compress true if input data is compressed
|
||||
*/
|
||||
void mveaudio_process(std::unique_ptr<std::deque<int16_t>> &buffer, unsigned char *data, bool is_compressed = true);
|
||||
void mveaudio_process(char *buffer, unsigned char *data, bool is_compressed = true);
|
||||
|
||||
#endif /* INCLUDED_MVE_AUDIO_H */
|
||||
|
@ -184,7 +184,7 @@ static int create_audiobuf_handler(unsigned char major, unsigned char minor, uns
|
||||
is_compressed = true;
|
||||
}
|
||||
|
||||
snd_ds = std::make_unique<D3::MovieSoundDevice>(sample_rate, sample_size, channels, desired_buffer, is_compressed);
|
||||
snd_ds = std::make_unique<D3::MovieSoundDevice>(sample_rate, sample_size, channels, 4096, is_compressed);
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
@ -204,18 +204,17 @@ static int audio_data_handler(unsigned char major, unsigned char minor, unsigned
|
||||
static const int selected_chan = 1;
|
||||
if (snd_ds->IsInitialized()) {
|
||||
int chan = get_ushort(data + 2);
|
||||
int size = get_ushort(data + 4);
|
||||
if (chan & selected_chan) {
|
||||
void *buf = malloc(size);
|
||||
if (major == MVE_OPCODE_AUDIOFRAMEDATA) {
|
||||
snd_ds->Lock();
|
||||
mveaudio_process(snd_ds->GetBuffer(), data, snd_ds->IsCompressed());
|
||||
snd_ds->Unlock();
|
||||
mveaudio_process((char *)buf, data, snd_ds->IsCompressed());
|
||||
} else {
|
||||
// SILENCE, MORTALS!
|
||||
int nsamp = get_ushort(data + 4);
|
||||
snd_ds->Lock();
|
||||
snd_ds->GetBuffer()->insert(snd_ds->GetBuffer()->end(), nsamp, 0);
|
||||
snd_ds->Unlock();
|
||||
memset(data, 0, size);
|
||||
}
|
||||
snd_ds->FillBuffer((char *)buf, size);
|
||||
free(buf);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -20,19 +20,15 @@
|
||||
#define LIBMVE_SOUND_INTERFACE_H_
|
||||
|
||||
#include <cstdint>
|
||||
#include <deque>
|
||||
#include <memory>
|
||||
|
||||
namespace D3 {
|
||||
|
||||
/// Abstract class for sound device.
|
||||
class ISoundDevice {
|
||||
protected:
|
||||
std::unique_ptr<std::deque<int16_t>> m_sound_buffer;
|
||||
bool m_is_compressed = false;
|
||||
|
||||
public:
|
||||
ISoundDevice() { this->m_sound_buffer = std::make_unique<std::deque<int16_t>>(); };
|
||||
/// Play stream
|
||||
virtual void Play() {};
|
||||
/// Stop stream
|
||||
@ -42,8 +38,6 @@ public:
|
||||
/// Unlock buffer
|
||||
virtual void Unlock() {};
|
||||
|
||||
/// Get access to sound buffer
|
||||
std::unique_ptr<std::deque<int16_t>> &GetBuffer() { return m_sound_buffer; }
|
||||
/// Check if encoded sound is compressed
|
||||
[[nodiscard]] bool IsCompressed() const { return m_is_compressed; };
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user