From: fundamental Date: Tue, 4 Jun 2019 01:00:20 +0000 (-0400) Subject: Avoid loading OGG segments into memory X-Git-Url: https://scope-eye.net/git/?a=commitdiff_plain;h=9c3df9cb1e00b9bbcca75de060972e0d419a7190;p=liskon_frotz.git Avoid loading OGG segments into memory Uses the virtual IO interface for sndfile providing pread() as the mechanism for loading data from the file handle. pread() makes it possible to read bytes from the file without impacting the offset which would be altered with normal fread()/fseek() or dup()+fread()/fseek() calls. By avoiding changing the shared offset values, pread() makes it possible to avoid multi-threaded data races while avoiding the modest memory usage of loading a single audio track to memory. --- diff --git a/src/curses/ux_audio.c b/src/curses/ux_audio.c index 30c32c9..a178ffe 100644 --- a/src/curses/ux_audio.c +++ b/src/curses/ux_audio.c @@ -31,6 +31,7 @@ #include #include #include +#include //pread #ifdef USE_NCURSES_H #include @@ -111,6 +112,13 @@ typedef struct { size_t pos; } buf_t; +typedef struct { + FILE *file; + size_t base_offset; + size_t len; + size_t pos; +} file_reader_t; + typedef struct { int (*process)(sound_stream_t *self, float *outl, float *outr, unsigned samples); void (*cleanup)(sound_stream_t *self); @@ -127,7 +135,7 @@ typedef struct { int repeats; /* Total times to play the sample 1..n*/ int pos; - buf_t buf; + file_reader_t freader; } sound_stream_aiff_t; typedef struct { @@ -179,7 +187,6 @@ static sound_engine_t frotz_audio; * * * getfiledata - get all bytes of a file after * * the start point * - * load_block_from_file - Load size bytes from current offset * * make_id - Create BLORB identifier * * get_type - Get OGG/FORM/AIFF type * * limit - x -> a <= x <= b * @@ -198,16 +205,6 @@ getfiledata(FILE *fp, long *size) return(data); } -static uint8_t * -load_block_from_file(FILE *fp, long size) -{ - long offset = ftell(fp); - uint8_t *data = (uint8_t*)malloc(size); - fread(data, size, sizeof(uint8_t), fp); - fseek(fp, offset, SEEK_SET); - return data; -} - static int32_t make_id(uint8_t a, uint8_t b, uint8_t c, uint8_t d) { @@ -455,39 +452,45 @@ cleanup_aiff(sound_stream_t *s) free(self->rsmp); sf_close(self->sndfile); free(self->floatbuffer); - free(self->buf.data); } static sf_count_t mem_snd_read(void *ptr_, sf_count_t size, void* datasource) { uint8_t *ptr = (uint8_t*)ptr_; - buf_t *buf = (buf_t *)datasource; + file_reader_t *fr = (file_reader_t *)datasource; size_t to_read = size; - size_t did_read = 0; - while(to_read > 0 && buf->pos < buf->len) { - *ptr++ = buf->data[buf->pos++]; - did_read++; - to_read--; + size_t read_total = 0; + ssize_t did_read = 0; + while(to_read > 0) { + did_read = pread(fileno(fr->file), ptr, size, fr->pos+fr->base_offset); + if(did_read < 0) + return did_read; + else if(did_read == 0) + return read_total; + read_total += did_read; + fr->pos += did_read; + ptr += did_read; + to_read -= did_read; } - return did_read; + return read_total; } static sf_count_t mem_snd_seek(sf_count_t offset, int whence, void *datasource) { - buf_t *buf = (buf_t *)datasource; + file_reader_t *fr = (file_reader_t *)datasource; int64_t pos = 0; if(whence == SEEK_SET) pos = offset; if(whence == SEEK_CUR) pos += offset; if(whence == SEEK_END) - pos = buf->len-offset; - if(pos >= (int64_t)buf->len) - pos = buf->len-1; + pos = fr->len-offset; + if(pos >= (int64_t)fr->len) + pos = fr->len-1; if(pos < 0) pos = 0; - buf->pos = pos; + fr->pos = pos; return 0; } @@ -495,15 +498,15 @@ mem_snd_seek(sf_count_t offset, int whence, void *datasource) { static long mem_tell(void *datasource) { - buf_t *buf = (buf_t *)datasource; - return buf->pos; + file_reader_t *fr = (file_reader_t*)datasource; + return fr->pos; } static sf_count_t mem_get_filelen(void *datasource) { - buf_t *buf = (buf_t *)datasource; - return buf->len; + file_reader_t *fr = (file_reader_t*)datasource; + return fr->len; } static sound_stream_t * @@ -520,8 +523,10 @@ load_aiff(FILE *fp, long startpos, long length, int id, float volume) aiff->sf_info.format = 0; fseek(fp, startpos, SEEK_SET); - aiff->buf.data = load_block_from_file(fp, length); - aiff->buf.len = length; + aiff->freader.file = fp; + aiff->freader.pos = 0; + aiff->freader.len = length; + aiff->freader.base_offset = startpos; SF_VIRTUAL_IO mem_cb = { .seek = mem_snd_seek, @@ -531,7 +536,7 @@ load_aiff(FILE *fp, long startpos, long length, int id, float volume) .write = NULL }; - aiff->sndfile = sf_open_virtual(&mem_cb, SFM_READ, &aiff->sf_info, &aiff->buf); + aiff->sndfile = sf_open_virtual(&mem_cb, SFM_READ, &aiff->sf_info, &aiff->freader); aiff->rsmp = resampler_init(aiff->sf_info.samplerate); aiff->floatbuffer = (float*)malloc(frotz_audio.buffer_size * aiff->sf_info.channels * sizeof(float));