vorbis and buffering
This commit is contained in:
parent
b2e83e695d
commit
c6960ffb9f
7 changed files with 158 additions and 18 deletions
|
|
@ -5,6 +5,7 @@
|
|||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ extern "C" {
|
|||
typedef struct _MDESoundDriver MDESoundDriverRec, *MDESoundDriver;
|
||||
typedef struct _MDESoundContext* MDESoundContext;
|
||||
typedef struct _MDESound* MDESound;
|
||||
typedef struct _MDESoundBuffer MDESoundBuffer;
|
||||
|
||||
struct _MDESoundContext {
|
||||
int sample_rate;
|
||||
|
|
@ -30,12 +31,20 @@ struct _MDESoundDriver {
|
|||
void (*seek)(MDESoundContext context, int frames);
|
||||
};
|
||||
|
||||
struct _MDESoundBuffer {
|
||||
short* data;
|
||||
int frames;
|
||||
int seek;
|
||||
};
|
||||
|
||||
struct _MDESound {
|
||||
MDESoundContext context;
|
||||
MDESoundDriver driver;
|
||||
MDESoundBuffer* buffer;
|
||||
};
|
||||
|
||||
extern MDESoundDriver MDESoundDriverMP3;
|
||||
extern MDESoundDriver MDESoundDriverVorbis;
|
||||
|
||||
MDESound MDESoundOpen(const char* path);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,10 @@
|
|||
include(MDEPkgConfig)
|
||||
|
||||
setup_lib(sound Sound)
|
||||
target_link_libraries(
|
||||
MDESound
|
||||
PRIVATE
|
||||
MDECore
|
||||
)
|
||||
|
||||
pkg_config_add(MDESound vorbisfile)
|
||||
|
|
|
|||
|
|
@ -27,11 +27,6 @@ static MDESoundContext mp3_open(const char* path){
|
|||
}
|
||||
|
||||
static void mp3_close(MDESoundContext ctx){
|
||||
if(ctx->title != NULL) free(ctx->title);
|
||||
if(ctx->artist != NULL) free(ctx->artist);
|
||||
if(ctx->album != NULL) free(ctx->album);
|
||||
if(ctx->genre != NULL) free(ctx->genre);
|
||||
|
||||
drmp3_uninit(ctx->opaque);
|
||||
free(ctx->opaque);
|
||||
free(ctx);
|
||||
74
sound/drv_vorbis.c
Normal file
74
sound/drv_vorbis.c
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
#include <MDE/Sound/Sound.h>
|
||||
#include <MDE/Core/String.h>
|
||||
|
||||
#include <vorbis/vorbisfile.h>
|
||||
|
||||
static MDESoundContext vorbis_open(const char* path){
|
||||
MDESoundContext ctx;
|
||||
FILE* f = fopen(path, "rb");
|
||||
vorbis_comment* comments;
|
||||
if(f == NULL) return NULL;
|
||||
|
||||
ctx = malloc(sizeof(*ctx));
|
||||
memset(ctx, 0, sizeof(*ctx));
|
||||
|
||||
ctx->opaque = malloc(sizeof(OggVorbis_File));
|
||||
if(ov_open_callbacks(f, ctx->opaque, NULL, 0, OV_CALLBACKS_DEFAULT) < 0){
|
||||
free(ctx->opaque);
|
||||
free(ctx);
|
||||
fclose(f);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
comments = ov_comment(ctx->opaque, -1);
|
||||
if(comments != NULL){
|
||||
int i;
|
||||
for(i = 0; i < comments->comments; i++){
|
||||
char* s = MDEStringDuplicate(comments->user_comments[i]);
|
||||
char* p = strchr(s, '=');
|
||||
if(p != NULL){
|
||||
p[0] = 0;
|
||||
if(strcasecmp(s, "TITLE") == 0){
|
||||
ctx->title = MDEStringDuplicate(p + 1);
|
||||
}else if(strcasecmp(s, "ALBUM") == 0){
|
||||
ctx->album = MDEStringDuplicate(p + 1);
|
||||
}else if(strcasecmp(s, "ARTIST") == 0){
|
||||
ctx->artist = MDEStringDuplicate(p + 1);
|
||||
}else if(strcasecmp(s, "GENRE") == 0){
|
||||
ctx->genre = MDEStringDuplicate(p + 1);
|
||||
}
|
||||
}
|
||||
|
||||
free(s);
|
||||
}
|
||||
}
|
||||
|
||||
ctx->channels = ov_info(ctx->opaque, -1)->channels;
|
||||
ctx->sample_rate = ov_info(ctx->opaque, -1)->rate;
|
||||
ctx->frames = ov_pcm_total(ctx->opaque, -1);
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
static void vorbis_close(MDESoundContext ctx){
|
||||
ov_clear(ctx->opaque);
|
||||
free(ctx->opaque);
|
||||
free(ctx);
|
||||
}
|
||||
|
||||
static int vorbis_read(MDESoundContext ctx, short* out, int frames){
|
||||
int n;
|
||||
return ov_read(ctx->opaque, (char*)out, frames * 2 * ctx->channels, 0, 2, 1, &n) / 2 / ctx->channels;
|
||||
}
|
||||
|
||||
static void vorbis_seek(MDESoundContext ctx, int frames){
|
||||
ov_pcm_seek(ctx->opaque, frames);
|
||||
}
|
||||
|
||||
static MDESoundDriverRec rec = {
|
||||
vorbis_open,
|
||||
vorbis_close,
|
||||
vorbis_read,
|
||||
vorbis_seek
|
||||
};
|
||||
MDESoundDriver MDESoundDriverVorbis = &rec;
|
||||
|
|
@ -1,5 +1,7 @@
|
|||
#include <MDE/Sound/Sound.h>
|
||||
|
||||
#include <stb_ds.h>
|
||||
|
||||
#define TRY_DRIVER(name) \
|
||||
if(sound->context == NULL){ \
|
||||
sound->driver = MDESoundDriver ## name; \
|
||||
|
|
@ -9,8 +11,10 @@
|
|||
MDESound MDESoundOpen(const char* path){
|
||||
MDESound sound = malloc(sizeof(*sound));
|
||||
sound->context = NULL;
|
||||
sound->buffer = NULL;
|
||||
|
||||
TRY_DRIVER(MP3);
|
||||
TRY_DRIVER(Vorbis);
|
||||
|
||||
if(sound->context == NULL){
|
||||
free(sound);
|
||||
|
|
@ -26,23 +30,63 @@ MDESound MDESoundOpen(const char* path){
|
|||
}
|
||||
|
||||
int MDESoundRead(MDESound sound, short* out, int frames){
|
||||
short* f = malloc(sizeof(*f) * sound->context->channels * frames);
|
||||
int r = sound->driver->read(sound->context, f, frames);
|
||||
int i;
|
||||
if(sound->context->channels == 2){
|
||||
for(i = 0; i < r * 2; i++){
|
||||
out[i] = f[i];
|
||||
}
|
||||
}else if(sound->context->channels == 1){
|
||||
for(i = 0; i < r; i++){
|
||||
out[i * 2 + 0] = f[i];
|
||||
out[i * 2 + 1] = f[i];
|
||||
}
|
||||
r *= 2;
|
||||
}
|
||||
free(f);
|
||||
int total = frames;
|
||||
int seek = 0;
|
||||
|
||||
return r;
|
||||
while(arrlen(sound->buffer) > 0 && total > 0){
|
||||
int fr = (sound->buffer[0].frames - sound->buffer[0].seek);
|
||||
if(fr > total) fr = total;
|
||||
|
||||
memcpy(out + seek * 2, sound->buffer[0].data + sound->buffer[0].seek * 2, 2 * 2 * fr);
|
||||
|
||||
sound->buffer[0].seek += fr;
|
||||
if(sound->buffer[0].seek == sound->buffer[0].frames){
|
||||
free(sound->buffer[0].data);
|
||||
arrdel(sound->buffer, 0);
|
||||
}
|
||||
total -= fr;
|
||||
seek += fr;
|
||||
}
|
||||
|
||||
while(total > 0){
|
||||
int i;
|
||||
short* buf = malloc(sizeof(*buf) * 2 * frames);
|
||||
short* f = malloc(sizeof(*f) * sound->context->channels * frames);
|
||||
int r = sound->driver->read(sound->context, f, frames);
|
||||
if(sound->context->channels == 2){
|
||||
for(i = 0; i < r * 2; i++){
|
||||
buf[i] = f[i];
|
||||
}
|
||||
}else if(sound->context->channels == 1){
|
||||
for(i = 0; i < r; i++){
|
||||
buf[i * 2 + 0] = f[i];
|
||||
buf[i * 2 + 1] = f[i];
|
||||
}
|
||||
}
|
||||
free(f);
|
||||
|
||||
if(r == 0){
|
||||
free(buf);
|
||||
break;
|
||||
}else if(total >= r){
|
||||
memcpy(out + seek * 2, buf, r * 2 * 2);
|
||||
seek += r;
|
||||
total -= r;
|
||||
free(buf);
|
||||
}else if(total < r){
|
||||
MDESoundBuffer buffer;
|
||||
buffer.data = buf;
|
||||
buffer.seek = total;
|
||||
buffer.frames = r;
|
||||
arrput(sound->buffer, buffer);
|
||||
|
||||
memcpy(out + seek * 2, buf, total * 2 * 2);
|
||||
seek += total;
|
||||
total -= total;
|
||||
}
|
||||
}
|
||||
|
||||
return seek;
|
||||
}
|
||||
|
||||
int MDESoundReadFloat(MDESound sound, float* out, int frames){
|
||||
|
|
@ -64,6 +108,17 @@ void MDESoundSeek(MDESound sound, int frames){
|
|||
}
|
||||
|
||||
void MDESoundClose(MDESound sound){
|
||||
int i;
|
||||
if(sound->context->title != NULL) free(sound->context->title);
|
||||
if(sound->context->artist != NULL) free(sound->context->artist);
|
||||
if(sound->context->album != NULL) free(sound->context->album);
|
||||
if(sound->context->genre != NULL) free(sound->context->genre);
|
||||
|
||||
sound->driver->close(sound->context);
|
||||
|
||||
for(i = 0; i < arrlen(sound->buffer); i++){
|
||||
free(sound->buffer[i].data);
|
||||
}
|
||||
arrfree(sound->buffer);
|
||||
free(sound);
|
||||
}
|
||||
|
|
|
|||
2
sound/stb_ds.c
Normal file
2
sound/stb_ds.c
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
#define STB_DS_IMPLEMENTATION
|
||||
#include <stb_ds.h>
|
||||
Loading…
Add table
Add a link
Reference in a new issue