From 2f288f6dc93240fa88498840fd281e2ee77bf9c9 Mon Sep 17 00:00:00 2001 From: "Azamat H. Hackimov" Date: Sat, 11 May 2024 16:32:18 +0300 Subject: [PATCH] MVE: use deque for FIFO buffer Replacing circular ring implementation with queue that keeps decoded data between SDL audio callbacks. --- libmve/mve_audio.cpp | 51 +++++++------- libmve/mve_audio.h | 8 ++- libmve/mveplay.cpp | 154 +++++++++---------------------------------- 3 files changed, 66 insertions(+), 147 deletions(-) diff --git a/libmve/mve_audio.cpp b/libmve/mve_audio.cpp index 89a1fa74..1e88c05f 100644 --- a/libmve/mve_audio.cpp +++ b/libmve/mve_audio.cpp @@ -15,7 +15,13 @@ * along with this program. If not, see . */ -static int audio_exp_table[256] = { +#include +#include +#include + +#include "byteswap.h" + +static int16_t audio_exp_table[256] = { 0, 1, 2, 3, 4, 5, 6, 7, // 8 8, 9, 10, 11, 12, 13, 14, 15, // 16, 17, 18, 19, 20, 21, 22, 23, // @@ -50,31 +56,32 @@ static int audio_exp_table[256] = { -8, -7, -6, -5, -4, -3, -2, -1, // 256 }; -static int getWord(unsigned char **fin) { - int value = ((*fin)[1] << 8) | (*fin)[0]; +static int16_t getWord(unsigned char **fin) { + int16_t value = D3::convert_le(((*fin)[1] << 8) | (*fin)[0]); *fin += 2; return value; } -static void sendWord(short **fout, int nOffset) { *(*fout)++ = nOffset; } +void mveaudio_process(std::unique_ptr> &buffer, unsigned char *data, bool is_compressed) { + if (is_compressed) { + int nCurOffsets[2]; -static void processSwath(short *fout, unsigned char *data, int swath, int *offsets) { - int i; - for (i = 0; i < swath; i++) { - offsets[i & 1] += audio_exp_table[data[i]]; - sendWord(&fout, offsets[i & 1]); + data += 4; + int swath = getWord(&data) / 2; + 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)); + } + } else { + data += 2; + int samples = getWord(&data); + for (int i = 0; i < samples; i++) { + buffer->push_back(getWord(&data)); + } } } - -void mveaudio_uncompress(short *buffer, unsigned char *data, int length) { - int nCurOffsets[2]; - int swath; - - data += 4; - swath = getWord(&data) / 2; - nCurOffsets[0] = getWord(&data); - nCurOffsets[1] = getWord(&data); - sendWord(&buffer, nCurOffsets[0]); - sendWord(&buffer, nCurOffsets[1]); - processSwath(buffer, data, swath, nCurOffsets); -} diff --git a/libmve/mve_audio.h b/libmve/mve_audio.h index 24db393a..06ed6e89 100644 --- a/libmve/mve_audio.h +++ b/libmve/mve_audio.h @@ -18,6 +18,12 @@ #ifndef INCLUDED_MVE_AUDIO_H #define INCLUDED_MVE_AUDIO_H -void mveaudio_uncompress(short *buffer, unsigned char *data, int length); +/** + * Process input data and send parsed data into queue buffer + * @param buffer output queue buffer + * @param data input data + * @param is_compress true if input data is compressed + */ +void mveaudio_process(std::unique_ptr> &buffer, unsigned char *data, bool is_compressed = true); #endif /* INCLUDED_MVE_AUDIO_H */ diff --git a/libmve/mveplay.cpp b/libmve/mveplay.cpp index a1936d32..ff952f17 100644 --- a/libmve/mveplay.cpp +++ b/libmve/mveplay.cpp @@ -18,6 +18,9 @@ #define AUDIO #include +#include +#include + #ifdef _WIN32 #include #else @@ -122,7 +125,7 @@ unsigned long int timer_getmicroseconds() { #else unsigned long int timer_getmicroseconds() { - struct timeval tv; + struct timeval tv{}; static time_t starttime = 0; gettimeofday(&tv, nullptr); @@ -141,7 +144,7 @@ void timer_sleepmicroseconds(unsigned long int usec) { #elif defined(macintosh) Delay(usec / 1000); #else - struct timespec ts; + struct timespec ts{}; ts.tv_sec = usec / 1000000; ts.tv_nsec = usec % 1000000 * 1000; nanosleep(&ts, nullptr); @@ -207,75 +210,21 @@ end: *************************/ #ifdef AUDIO -#define TOTAL_AUDIO_BUFFERS 64 -static int audiobuf_created = 0; -static short *mve_audio_buffers[TOTAL_AUDIO_BUFFERS]; -static int mve_audio_buflens[TOTAL_AUDIO_BUFFERS]; -static int mve_audio_curbuf_curpos = 0; -static int mve_audio_bufhead = 0; -static int mve_audio_buftail = 0; +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 int mve_audio_enabled = 1; static void mve_audio_callback(void *userdata, unsigned char *stream, int len) { - int total = 0; - int length; - if (mve_audio_bufhead == mve_audio_buftail) - return /* 0 */; - - // fprintf(stderr, "+ <%d (%d), %d, %d>\n", mve_audio_bufhead, mve_audio_curbuf_curpos, mve_audio_buftail, len); - - while (mve_audio_bufhead != mve_audio_buftail /* while we have more buffers */ - && len > (mve_audio_buflens[mve_audio_bufhead] - mve_audio_curbuf_curpos)) /* and while we need more data */ - { - length = mve_audio_buflens[mve_audio_bufhead] - mve_audio_curbuf_curpos; - memcpy(stream, /* cur output position */ - ((unsigned char *)mve_audio_buffers[mve_audio_bufhead]) + mve_audio_curbuf_curpos, /* cur input position */ - length); /* cur input length */ - - total += length; - stream += length; /* advance output */ - len -= length; /* decrement avail ospace */ - mve_free(mve_audio_buffers[mve_audio_bufhead]); /* free the buffer */ - mve_audio_buffers[mve_audio_bufhead] = NULL; /* free the buffer */ - mve_audio_buflens[mve_audio_bufhead] = 0; /* free the buffer */ - - if (++mve_audio_bufhead == TOTAL_AUDIO_BUFFERS) /* next buffer */ - mve_audio_bufhead = 0; - mve_audio_curbuf_curpos = 0; + 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; } - - // fprintf(stderr, "= <%d (%d), %d, %d>: %d\n", mve_audio_bufhead, mve_audio_curbuf_curpos, mve_audio_buftail, len, - // total); - /* return total; */ - - if (len != 0 /* ospace remaining */ - && mve_audio_bufhead != mve_audio_buftail) /* buffers remaining */ - { - memcpy(stream, /* dest */ - ((unsigned char *)mve_audio_buffers[mve_audio_bufhead]) + mve_audio_curbuf_curpos, /* src */ - len); /* length */ - - mve_audio_curbuf_curpos += len; /* advance input */ - stream += len; /* advance output (unnecessary) */ - len -= len; /* advance output (unnecessary) */ - - if (mve_audio_curbuf_curpos >= mve_audio_buflens[mve_audio_bufhead]) /* if this ends the current chunk */ - { - mve_free(mve_audio_buffers[mve_audio_bufhead]); /* free buffer */ - mve_audio_buffers[mve_audio_bufhead] = NULL; - mve_audio_buflens[mve_audio_bufhead] = 0; - - if (++mve_audio_bufhead == TOTAL_AUDIO_BUFFERS) /* next buffer */ - mve_audio_bufhead = 0; - mve_audio_curbuf_curpos = 0; - } - } - - // fprintf(stderr, "- <%d (%d), %d, %d>\n", mve_audio_bufhead, mve_audio_curbuf_curpos, mve_audio_buftail, len); } #endif @@ -294,11 +243,6 @@ static int create_audiobuf_handler(unsigned char major, unsigned char minor, uns if (!mve_audio_enabled) return 1; - if (audiobuf_created) - return 1; - else - audiobuf_created = 1; - flags = get_ushort(data + 2); sample_rate = get_ushort(data + 4); desired_buffer = get_int(data + 6); @@ -343,8 +287,7 @@ static int create_audiobuf_handler(unsigned char major, unsigned char minor, uns mve_audio_canplay = 1; - memset(mve_audio_buffers, 0, sizeof(mve_audio_buffers)); - memset(mve_audio_buflens, 0, sizeof(mve_audio_buflens)); + mve_sound_buffer = std::make_unique>(); #endif return 1; @@ -352,7 +295,7 @@ 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 && mve_audio_bufhead != mve_audio_buftail) { + if (mve_audio_canplay && !mve_audio_playing) { SDL_PauseAudioDevice(device, 0); mve_audio_playing = 1; } @@ -363,40 +306,16 @@ 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; - int chan; - int nsamp; if (mve_audio_canplay) { - chan = get_ushort(data + 2); - nsamp = get_ushort(data + 4); + int chan = get_ushort(data + 2); if (chan & selected_chan) { - /* HACK: +4 mveaudio_uncompress adds 4 more bytes */ if (major == MVE_OPCODE_AUDIOFRAMEDATA) { - if (mve_audio_compressed) { - nsamp += 4; - - mve_audio_buflens[mve_audio_buftail] = nsamp; - mve_audio_buffers[mve_audio_buftail] = (short *)mve_alloc(nsamp); - mveaudio_uncompress(mve_audio_buffers[mve_audio_buftail], data, -1); /* XXX */ - } else { - nsamp -= 8; - data += 8; - - mve_audio_buflens[mve_audio_buftail] = nsamp; - mve_audio_buffers[mve_audio_buftail] = (short *)mve_alloc(nsamp); - memcpy(mve_audio_buffers[mve_audio_buftail], data, nsamp); - } + mveaudio_process(mve_sound_buffer, data, mve_audio_compressed); } else { - mve_audio_buflens[mve_audio_buftail] = nsamp; - mve_audio_buffers[mve_audio_buftail] = (short *)mve_alloc(nsamp); - - memset(mve_audio_buffers[mve_audio_buftail], 0, nsamp); /* XXX */ + // SILENCE, MORTALS! + int nsamp = get_ushort(data + 4); + mve_sound_buffer->insert(mve_sound_buffer->end(), nsamp, 0); } - - if (++mve_audio_buftail == TOTAL_AUDIO_BUFFERS) - mve_audio_buftail = 0; - - if (mve_audio_buftail == mve_audio_bufhead) - fprintf(stderr, "d'oh! buffer ring overrun (%d)\n", mve_audio_bufhead); } } #endif @@ -411,11 +330,11 @@ static int audio_data_handler(unsigned char major, unsigned char minor, unsigned static int videobuf_created = 0; static int video_initialized = 0; int g_width, g_height; -void *g_vBuffers = NULL, *g_vBackBuf1, *g_vBackBuf2; +void *g_vBuffers = nullptr, *g_vBackBuf1, *g_vBackBuf2; static int g_destX, g_destY; static int g_screenWidth, g_screenHeight; -static unsigned char *g_pCurMap = NULL; +static unsigned char *g_pCurMap = nullptr; static int g_nMapLength = 0; static int g_truecolor; @@ -449,7 +368,7 @@ static int create_videobuf_handler(unsigned char major, unsigned char minor, uns /* TODO: * 4 causes crashes on some files */ /* only malloc once */ - if (g_vBuffers == NULL) + if (g_vBuffers == nullptr) g_vBackBuf1 = g_vBuffers = mve_alloc(g_width * g_height * 8); if (truecolor) { g_vBackBuf2 = (unsigned short *)g_vBackBuf1 + (g_width * g_height); @@ -522,19 +441,15 @@ static int video_codemap_handler(unsigned char major, unsigned char minor, unsig } static int video_data_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context) { - short nFrameHot, nFrameCold; - short nXoffset, nYoffset; - short nXsize, nYsize; - unsigned short nFlags; unsigned char *temp; - nFrameHot = get_short(data); - nFrameCold = get_short(data + 2); - nXoffset = get_short(data + 4); - nYoffset = get_short(data + 6); - nXsize = get_short(data + 8); - nYsize = get_short(data + 10); - nFlags = get_ushort(data + 12); + short nFrameHot = get_short(data); + short nFrameCold = get_short(data + 2); + short nXoffset = get_short(data + 4); + short nYoffset = get_short(data + 6); + short nXsize = get_short(data + 8); + short nYsize = get_short(data + 10); + unsigned short nFlags = get_ushort(data + 12); if (nFlags & 1) { temp = (unsigned char *)g_vBackBuf1; @@ -553,7 +468,7 @@ static int video_data_handler(unsigned char major, unsigned char minor, unsigned } static int end_chunk_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context) { - g_pCurMap = NULL; + g_pCurMap = nullptr; return 1; } @@ -649,18 +564,9 @@ void MVE_rmEndMovie(MVESTREAM *mve) { SDL_CloseAudioDevice(device); mve_audio_canplay = 0; } - for (int i = 0; i < TOTAL_AUDIO_BUFFERS; i++) - if (mve_audio_buffers[i] != NULL) - mve_free(mve_audio_buffers[i]); - memset(mve_audio_buffers, 0, sizeof(mve_audio_buffers)); - memset(mve_audio_buflens, 0, sizeof(mve_audio_buflens)); - mve_audio_curbuf_curpos = 0; - mve_audio_bufhead = 0; - mve_audio_buftail = 0; mve_audio_playing = 0; mve_audio_canplay = 0; mve_audio_compressed = 0; - audiobuf_created = 0; #endif mve_free(g_vBuffers);