MVE: use deque for FIFO buffer

Replacing circular ring implementation with queue that keeps decoded data between SDL audio callbacks.
This commit is contained in:
Azamat H. Hackimov 2024-05-11 16:32:18 +03:00
parent 8d56e1c1ff
commit 2f288f6dc9
3 changed files with 66 additions and 147 deletions

View File

@ -15,7 +15,13 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
static int audio_exp_table[256] = {
#include <algorithm>
#include <deque>
#include <memory>
#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<int16_t>(((*fin)[1] << 8) | (*fin)[0]);
*fin += 2;
return value;
}
static void sendWord(short **fout, int nOffset) { *(*fout)++ = nOffset; }
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]);
}
}
void mveaudio_uncompress(short *buffer, unsigned char *data, int length) {
void mveaudio_process(std::unique_ptr<std::deque<int16_t>> &buffer, unsigned char *data, bool is_compressed) {
if (is_compressed) {
int nCurOffsets[2];
int swath;
data += 4;
swath = getWord(&data) / 2;
int 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);
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));
}
}
}

View File

@ -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<std::deque<int16_t>> &buffer, unsigned char *data, bool is_compressed = true);
#endif /* INCLUDED_MVE_AUDIO_H */

View File

@ -18,6 +18,9 @@
#define AUDIO
#include <cstring>
#include <deque>
#include <memory>
#ifdef _WIN32
#include <windows.h>
#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<std::deque<int16_t>> 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<std::deque<int16_t >>();
#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 */
mveaudio_process(mve_sound_buffer, data, mve_audio_compressed);
} 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);
// SILENCE, MORTALS!
int nsamp = get_ushort(data + 4);
mve_sound_buffer->insert(mve_sound_buffer->end(), nsamp, 0);
}
} 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 */
}
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);