diff --git a/libmve/CMakeLists.txt b/libmve/CMakeLists.txt
index ef90c497..5762c55d 100644
--- a/libmve/CMakeLists.txt
+++ b/libmve/CMakeLists.txt
@@ -3,6 +3,7 @@ set(CPPS
# mvelibl.cpp
# platform.cpp
lnxdsound.cpp
+ lnx_sound.cpp
# d2x implementation
decoder8.cpp
diff --git a/libmve/lnx_sound.cpp b/libmve/lnx_sound.cpp
new file mode 100644
index 00000000..4ccb77d5
--- /dev/null
+++ b/libmve/lnx_sound.cpp
@@ -0,0 +1,64 @@
+/*
+ * Descent 3
+ * Copyright (C) 2024 Descent Developers
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include
+#include "lnx_sound.h"
+
+namespace D3 {
+
+void MovieSoundDevice::SDLAudioCallback(void *userdata, unsigned char *stream, int len) {
+ auto device = static_cast(userdata);
+ for (int i = 0; i < len; i += 2) {
+ int16_t sample = device->m_sound_buffer->front();
+ device->m_sound_buffer->pop_front();
+ stream[i] = sample & 0xff;
+ stream[i + 1] = sample >> 8;
+ }
+}
+
+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;
+ SDL_AudioSpec spec{
+ .freq = sample_rate,
+ .format = format,
+ .channels = channels,
+ .size = buf_size,
+ .callback = &MovieSoundDevice::SDLAudioCallback,
+ .userdata = this,
+ };
+ m_device_id = SDL_OpenAudioDevice(nullptr, 0, &spec, nullptr, SDL_AUDIO_ALLOW_ANY_CHANGE);
+ m_is_compressed = is_compressed;
+};
+
+MovieSoundDevice::~MovieSoundDevice() {
+ if (m_device_id > 0) {
+ SDL_CloseAudioDevice(m_device_id);
+ }
+ m_sound_buffer.reset();
+}
+
+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::Unlock() { SDL_UnlockAudioDevice(m_device_id); };
+
+} // namespace D3
diff --git a/libmve/lnx_sound.h b/libmve/lnx_sound.h
new file mode 100644
index 00000000..d56d7a2e
--- /dev/null
+++ b/libmve/lnx_sound.h
@@ -0,0 +1,52 @@
+/*
+* Descent 3
+* Copyright (C) 2024 Descent Developers
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see .
+*/
+
+#ifndef LIBMVE_LNX_SOUND_H_
+#define LIBMVE_LNX_SOUND_H_
+
+#include
+
+#include "sound_interface.h"
+
+namespace D3 {
+
+class MovieSoundDevice : ISoundDevice {
+private:
+ SDL_AudioDeviceID m_device_id = 0;
+
+public:
+ MovieSoundDevice(int sample_rate, uint16_t sample_size, uint8_t channels, uint32_t buf_size, bool is_compressed);
+ ~MovieSoundDevice();
+
+ [[nodiscard]] bool IsInitialized() const { return m_device_id > 0 ? true : false; }
+
+ void static SDLAudioCallback(void *userdata, unsigned char *stream, int len);
+
+ void Play() override;
+ void Stop() override;
+ void Lock() override;
+ void Unlock() override;
+
+ using ISoundDevice::GetBuffer;
+ using ISoundDevice::IsCompressed;
+
+};
+
+}
+
+#endif // LIBMVE_LNX_SOUND_H_
diff --git a/libmve/mveplay.cpp b/libmve/mveplay.cpp
index ff952f17..44319a2e 100644
--- a/libmve/mveplay.cpp
+++ b/libmve/mveplay.cpp
@@ -28,15 +28,18 @@
#include
#endif // _WIN32
-#if defined(AUDIO)
-#include
-#endif
-
#include "byteswap.h"
#include "decoders.h"
#include "mvelib.h"
#include "mve_audio.h"
-#include "SystemInterfaces.h"
+
+#ifdef AUDIO
+#ifdef _WIN32
+
+#else
+#include "lnx_sound.h"
+#endif
+#endif
#define MVE_OPCODE_ENDOFSTREAM 0x00
#define MVE_OPCODE_ENDOFCHUNK 0x01
@@ -65,10 +68,6 @@ int g_spdFactorNum = 0;
static int g_spdFactorDenom = 10;
static int g_frameUpdated = 0;
-static ISoundDevice *snd_ds = nullptr;
-
-static SDL_AudioDeviceID device = 0;
-
static short get_short(const unsigned char *data) {
return D3::convert_le(data[0] | (data[1] << 8));
}
@@ -85,7 +84,6 @@ static unsigned int unhandled_chunks[32 * 256];
static int default_seg_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context) {
unhandled_chunks[major << 8 | minor]++;
- // fprintf(stderr, "unknown chunk type %02x/%02x\n", major, minor);
return 1;
}
@@ -210,84 +208,31 @@ end:
*************************/
#ifdef AUDIO
-
-static std::unique_ptr> mve_sound_buffer;
-
-static int mve_audio_playing = 0;
-static int mve_audio_canplay = 0;
-static int mve_audio_compressed = 0;
+static std::unique_ptr snd_ds;
static int mve_audio_enabled = 1;
-
-static void mve_audio_callback(void *userdata, unsigned char *stream, int len) {
- for(int i = 0; i < len; i += 2) {
- int16_t sample = mve_sound_buffer->front();
- mve_sound_buffer->pop_front();
- stream[i] = sample & 0xff;
- stream[i + 1] = sample >> 8;
- }
-}
+#else
+static int mve_audio_enabled = 0;
#endif
static int create_audiobuf_handler(unsigned char major, unsigned char minor, unsigned char *data, int len,
void *context) {
#ifdef AUDIO
- int flags;
- int sample_rate;
- int desired_buffer;
-
- int stereo;
- int bitsize;
-
- int format;
-
if (!mve_audio_enabled)
return 1;
- flags = get_ushort(data + 2);
- sample_rate = get_ushort(data + 4);
- desired_buffer = get_int(data + 6);
+ int flags = get_ushort(data + 2);
+ int sample_rate = get_ushort(data + 4);
+ int desired_buffer = get_int(data + 6);
- stereo = (flags & MVE_AUDIO_FLAGS_STEREO) ? 1 : 0;
- bitsize = (flags & MVE_AUDIO_FLAGS_16BIT) ? 1 : 0;
+ int channels = (flags & MVE_AUDIO_FLAGS_STEREO) ? 2 : 1;
+ int sample_size = (flags & MVE_AUDIO_FLAGS_16BIT) ? 2 : 1;
- mve_audio_compressed = 0;
+ bool is_compressed = false;
if (minor > 0 && (flags & MVE_AUDIO_FLAGS_COMPRESSED)) {
- mve_audio_compressed = 1;
+ is_compressed = true;
}
- if (bitsize == 1) {
-#ifdef OUTRAGE_BIG_ENDIAN
- format = AUDIO_S16MSB;
-#else
- format = AUDIO_S16LSB;
-#endif
- } else {
- format = AUDIO_U8;
- }
-
- fprintf(stderr, "creating audio buffers:\n");
- fprintf(stderr, "sample rate = %d, stereo = %d, bitsize = %d, compressed = %d\n", sample_rate, stereo,
- bitsize ? 16 : 8, mve_audio_compressed);
-
- SDL_AudioSpec spec {
- .freq = sample_rate,
- .format = (unsigned short)format,
- .channels = (unsigned char)(stereo ? 2 : 1),
- .size = 4096,
- .callback = mve_audio_callback,
- };
- device = SDL_OpenAudioDevice(nullptr, 0, &spec, nullptr, SDL_AUDIO_ALLOW_ANY_CHANGE);
- if (device != 0) {
- fprintf(stderr, " success\n");
- mve_audio_canplay = 1;
- } else {
- fprintf(stderr, " failure : %s\n", SDL_GetError());
- mve_audio_canplay = 0;
- }
-
- mve_audio_canplay = 1;
-
- mve_sound_buffer = std::make_unique>();
+ snd_ds = std::make_unique(sample_rate, sample_size, channels, 4096, is_compressed);
#endif
return 1;
@@ -295,9 +240,8 @@ static int create_audiobuf_handler(unsigned char major, unsigned char minor, uns
static int play_audio_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context) {
#ifdef AUDIO
- if (mve_audio_canplay && !mve_audio_playing) {
- SDL_PauseAudioDevice(device, 0);
- mve_audio_playing = 1;
+ if (snd_ds && snd_ds->IsInitialized()) {
+ snd_ds->Play();
}
#endif
return 1;
@@ -306,15 +250,19 @@ static int play_audio_handler(unsigned char major, unsigned char minor, unsigned
static int audio_data_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context) {
#ifdef AUDIO
static const int selected_chan = 1;
- if (mve_audio_canplay) {
+ if (snd_ds->IsInitialized()) {
int chan = get_ushort(data + 2);
if (chan & selected_chan) {
if (major == MVE_OPCODE_AUDIOFRAMEDATA) {
- mveaudio_process(mve_sound_buffer, data, mve_audio_compressed);
+ snd_ds->Lock();
+ mveaudio_process(snd_ds->GetBuffer(), data, snd_ds->IsCompressed());
+ snd_ds->Unlock();
} else {
// SILENCE, MORTALS!
int nsamp = get_ushort(data + 4);
- mve_sound_buffer->insert(mve_sound_buffer->end(), nsamp, 0);
+ snd_ds->Lock();
+ snd_ds->GetBuffer()->insert(snd_ds->GetBuffer()->end(), nsamp, 0);
+ snd_ds->Unlock();
}
}
}
@@ -559,14 +507,7 @@ void MVE_rmEndMovie(MVESTREAM *mve) {
timer_created = 0;
#ifdef AUDIO
- if (mve_audio_canplay) {
- // only close audio if we opened it
- SDL_CloseAudioDevice(device);
- mve_audio_canplay = 0;
- }
- mve_audio_playing = 0;
- mve_audio_canplay = 0;
- mve_audio_compressed = 0;
+ snd_ds.reset();
#endif
mve_free(g_vBuffers);
@@ -584,7 +525,7 @@ void MVE_rmHoldMovie() { timer_started = 0; }
void MVE_sndInit(ISoundDevice *lpDS) {
#ifdef AUDIO
- snd_ds = lpDS;
+ // snd_ds = lpDS;
#endif
}
diff --git a/libmve/sound_interface.h b/libmve/sound_interface.h
new file mode 100644
index 00000000..5dcfdd2e
--- /dev/null
+++ b/libmve/sound_interface.h
@@ -0,0 +1,46 @@
+/*
+* Descent 3
+* Copyright (C) 2024 Descent Developers
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see .
+ */
+
+#ifndef LIBMVE_SOUND_INTERFACE_H_
+#define LIBMVE_SOUND_INTERFACE_H_
+
+#include
+#include
+#include
+
+namespace D3 {
+
+class ISoundDevice {
+protected:
+ std::unique_ptr> m_sound_buffer;
+ bool m_is_compressed = false;
+
+public:
+ ISoundDevice() { m_sound_buffer = std::make_unique>(); };
+ virtual void Play() {};
+ virtual void Stop() {};
+ virtual void Lock() {};
+ virtual void Unlock() {};
+
+ std::unique_ptr> &GetBuffer() { return m_sound_buffer; }
+ [[nodiscard]] bool IsCompressed() const { return m_is_compressed; };
+
+};
+
+}
+#endif // LIBMVE_SOUND_INTERFACE_H_