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 <stdlib.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <strings.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ extern "C" {
|
||||||
typedef struct _MDESoundDriver MDESoundDriverRec, *MDESoundDriver;
|
typedef struct _MDESoundDriver MDESoundDriverRec, *MDESoundDriver;
|
||||||
typedef struct _MDESoundContext* MDESoundContext;
|
typedef struct _MDESoundContext* MDESoundContext;
|
||||||
typedef struct _MDESound* MDESound;
|
typedef struct _MDESound* MDESound;
|
||||||
|
typedef struct _MDESoundBuffer MDESoundBuffer;
|
||||||
|
|
||||||
struct _MDESoundContext {
|
struct _MDESoundContext {
|
||||||
int sample_rate;
|
int sample_rate;
|
||||||
|
|
@ -30,12 +31,20 @@ struct _MDESoundDriver {
|
||||||
void (*seek)(MDESoundContext context, int frames);
|
void (*seek)(MDESoundContext context, int frames);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct _MDESoundBuffer {
|
||||||
|
short* data;
|
||||||
|
int frames;
|
||||||
|
int seek;
|
||||||
|
};
|
||||||
|
|
||||||
struct _MDESound {
|
struct _MDESound {
|
||||||
MDESoundContext context;
|
MDESoundContext context;
|
||||||
MDESoundDriver driver;
|
MDESoundDriver driver;
|
||||||
|
MDESoundBuffer* buffer;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern MDESoundDriver MDESoundDriverMP3;
|
extern MDESoundDriver MDESoundDriverMP3;
|
||||||
|
extern MDESoundDriver MDESoundDriverVorbis;
|
||||||
|
|
||||||
MDESound MDESoundOpen(const char* path);
|
MDESound MDESoundOpen(const char* path);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,10 @@
|
||||||
|
include(MDEPkgConfig)
|
||||||
|
|
||||||
setup_lib(sound Sound)
|
setup_lib(sound Sound)
|
||||||
target_link_libraries(
|
target_link_libraries(
|
||||||
MDESound
|
MDESound
|
||||||
PRIVATE
|
PRIVATE
|
||||||
MDECore
|
MDECore
|
||||||
)
|
)
|
||||||
|
|
||||||
|
pkg_config_add(MDESound vorbisfile)
|
||||||
|
|
|
||||||
|
|
@ -27,11 +27,6 @@ static MDESoundContext mp3_open(const char* path){
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mp3_close(MDESoundContext ctx){
|
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);
|
drmp3_uninit(ctx->opaque);
|
||||||
free(ctx->opaque);
|
free(ctx->opaque);
|
||||||
free(ctx);
|
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 <MDE/Sound/Sound.h>
|
||||||
|
|
||||||
|
#include <stb_ds.h>
|
||||||
|
|
||||||
#define TRY_DRIVER(name) \
|
#define TRY_DRIVER(name) \
|
||||||
if(sound->context == NULL){ \
|
if(sound->context == NULL){ \
|
||||||
sound->driver = MDESoundDriver ## name; \
|
sound->driver = MDESoundDriver ## name; \
|
||||||
|
|
@ -9,8 +11,10 @@
|
||||||
MDESound MDESoundOpen(const char* path){
|
MDESound MDESoundOpen(const char* path){
|
||||||
MDESound sound = malloc(sizeof(*sound));
|
MDESound sound = malloc(sizeof(*sound));
|
||||||
sound->context = NULL;
|
sound->context = NULL;
|
||||||
|
sound->buffer = NULL;
|
||||||
|
|
||||||
TRY_DRIVER(MP3);
|
TRY_DRIVER(MP3);
|
||||||
|
TRY_DRIVER(Vorbis);
|
||||||
|
|
||||||
if(sound->context == NULL){
|
if(sound->context == NULL){
|
||||||
free(sound);
|
free(sound);
|
||||||
|
|
@ -26,23 +30,63 @@ MDESound MDESoundOpen(const char* path){
|
||||||
}
|
}
|
||||||
|
|
||||||
int MDESoundRead(MDESound sound, short* out, int frames){
|
int MDESoundRead(MDESound sound, short* out, int frames){
|
||||||
short* f = malloc(sizeof(*f) * sound->context->channels * frames);
|
int total = frames;
|
||||||
int r = sound->driver->read(sound->context, f, frames);
|
int seek = 0;
|
||||||
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);
|
|
||||||
|
|
||||||
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){
|
int MDESoundReadFloat(MDESound sound, float* out, int frames){
|
||||||
|
|
@ -64,6 +108,17 @@ void MDESoundSeek(MDESound sound, int frames){
|
||||||
}
|
}
|
||||||
|
|
||||||
void MDESoundClose(MDESound sound){
|
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);
|
sound->driver->close(sound->context);
|
||||||
|
|
||||||
|
for(i = 0; i < arrlen(sound->buffer); i++){
|
||||||
|
free(sound->buffer[i].data);
|
||||||
|
}
|
||||||
|
arrfree(sound->buffer);
|
||||||
free(sound);
|
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