This commit is contained in:
Nishi 2025-11-25 01:36:54 +09:00
commit a74bd0b3e7
Signed by: nishi
GPG key ID: 27EF69B208EB9343
4 changed files with 139 additions and 141 deletions

View file

@ -4,46 +4,45 @@
#define DR_MP3_IMPLEMENTATION #define DR_MP3_IMPLEMENTATION
#include <dr_mp3.h> #include <dr_mp3.h>
static MDESoundContext mp3_open(const char* path){ static MDESoundContext mp3_open(const char* path) {
MDESoundContext ctx = malloc(sizeof(*ctx)); MDESoundContext ctx = malloc(sizeof(*ctx));
memset(ctx, 0, sizeof(*ctx)); memset(ctx, 0, sizeof(*ctx));
ctx->title = MDEID3GetString(path, "TIT2"); ctx->title = MDEID3GetString(path, "TIT2");
ctx->artist = MDEID3GetString(path, "TPE1"); ctx->artist = MDEID3GetString(path, "TPE1");
ctx->album = MDEID3GetString(path, "TALB"); ctx->album = MDEID3GetString(path, "TALB");
ctx->genre = MDEID3GetString(path, "TCON"); ctx->genre = MDEID3GetString(path, "TCON");
ctx->opaque = malloc(sizeof(drmp3)); ctx->opaque = malloc(sizeof(drmp3));
if(!drmp3_init_file(ctx->opaque, path, NULL)){ if(!drmp3_init_file(ctx->opaque, path, NULL)) {
free(ctx); free(ctx);
return NULL; return NULL;
} }
ctx->channels = ((drmp3*)ctx->opaque)->channels; ctx->channels = ((drmp3*)ctx->opaque)->channels;
ctx->sample_rate = ((drmp3*)ctx->opaque)->sampleRate; ctx->sample_rate = ((drmp3*)ctx->opaque)->sampleRate;
ctx->frames = drmp3_get_pcm_frame_count(ctx->opaque); ctx->frames = drmp3_get_pcm_frame_count(ctx->opaque);
return ctx; return ctx;
} }
static void mp3_close(MDESoundContext ctx){ static void mp3_close(MDESoundContext ctx) {
drmp3_uninit(ctx->opaque); drmp3_uninit(ctx->opaque);
free(ctx->opaque); free(ctx->opaque);
free(ctx); free(ctx);
} }
static int mp3_read(MDESoundContext ctx, short* out, int frames){ static int mp3_read(MDESoundContext ctx, short* out, int frames) {
return drmp3_read_pcm_frames_s16(ctx->opaque, frames, out); return drmp3_read_pcm_frames_s16(ctx->opaque, frames, out);
} }
static void mp3_seek(MDESoundContext ctx, int frames){ static void mp3_seek(MDESoundContext ctx, int frames) {
drmp3_seek_to_pcm_frame(ctx->opaque, frames); drmp3_seek_to_pcm_frame(ctx->opaque, frames);
} }
static MDESoundDriverRec rec = { static MDESoundDriverRec rec = {
mp3_open, mp3_open,
mp3_close, mp3_close,
mp3_read, mp3_read,
mp3_seek mp3_seek};
};
MDESoundDriver MDESoundDriverMP3 = &rec; MDESoundDriver MDESoundDriverMP3 = &rec;

View file

@ -3,9 +3,9 @@
#include <vorbis/vorbisfile.h> #include <vorbis/vorbisfile.h>
static MDESoundContext vorbis_open(const char* path){ static MDESoundContext vorbis_open(const char* path) {
MDESoundContext ctx; MDESoundContext ctx;
FILE* f = fopen(path, "rb"); FILE* f = fopen(path, "rb");
vorbis_comment* comments; vorbis_comment* comments;
if(f == NULL) return NULL; if(f == NULL) return NULL;
@ -13,7 +13,7 @@ static MDESoundContext vorbis_open(const char* path){
memset(ctx, 0, sizeof(*ctx)); memset(ctx, 0, sizeof(*ctx));
ctx->opaque = malloc(sizeof(OggVorbis_File)); ctx->opaque = malloc(sizeof(OggVorbis_File));
if(ov_open_callbacks(f, ctx->opaque, NULL, 0, OV_CALLBACKS_DEFAULT) < 0){ if(ov_open_callbacks(f, ctx->opaque, NULL, 0, OV_CALLBACKS_DEFAULT) < 0) {
free(ctx->opaque); free(ctx->opaque);
free(ctx); free(ctx);
fclose(f); fclose(f);
@ -21,54 +21,53 @@ static MDESoundContext vorbis_open(const char* path){
} }
comments = ov_comment(ctx->opaque, -1); comments = ov_comment(ctx->opaque, -1);
if(comments != NULL){ if(comments != NULL) {
int i; int i;
for(i = 0; i < comments->comments; i++){ for(i = 0; i < comments->comments; i++) {
char* s = MDEStringDuplicate(comments->user_comments[i]); char* s = MDEStringDuplicate(comments->user_comments[i]);
char* p = strchr(s, '='); char* p = strchr(s, '=');
if(p != NULL){ if(p != NULL) {
p[0] = 0; p[0] = 0;
if(strcasecmp(s, "TITLE") == 0){ if(strcasecmp(s, "TITLE") == 0) {
ctx->title = MDEStringDuplicate(p + 1); ctx->title = MDEStringDuplicate(p + 1);
}else if(strcasecmp(s, "ALBUM") == 0){ } else if(strcasecmp(s, "ALBUM") == 0) {
ctx->album = MDEStringDuplicate(p + 1); ctx->album = MDEStringDuplicate(p + 1);
}else if(strcasecmp(s, "ARTIST") == 0){ } else if(strcasecmp(s, "ARTIST") == 0) {
ctx->artist = MDEStringDuplicate(p + 1); ctx->artist = MDEStringDuplicate(p + 1);
}else if(strcasecmp(s, "GENRE") == 0){ } else if(strcasecmp(s, "GENRE") == 0) {
ctx->genre = MDEStringDuplicate(p + 1); ctx->genre = MDEStringDuplicate(p + 1);
} }
} }
free(s); free(s);
} }
} }
ctx->channels = ov_info(ctx->opaque, -1)->channels; ctx->channels = ov_info(ctx->opaque, -1)->channels;
ctx->sample_rate = ov_info(ctx->opaque, -1)->rate; ctx->sample_rate = ov_info(ctx->opaque, -1)->rate;
ctx->frames = ov_pcm_total(ctx->opaque, -1); ctx->frames = ov_pcm_total(ctx->opaque, -1);
return ctx; return ctx;
} }
static void vorbis_close(MDESoundContext ctx){ static void vorbis_close(MDESoundContext ctx) {
ov_clear(ctx->opaque); ov_clear(ctx->opaque);
free(ctx->opaque); free(ctx->opaque);
free(ctx); free(ctx);
} }
static int vorbis_read(MDESoundContext ctx, short* out, int frames){ static int vorbis_read(MDESoundContext ctx, short* out, int frames) {
int n; int n;
return ov_read(ctx->opaque, (char*)out, frames * 2 * ctx->channels, 0, 2, 1, &n) / 2 / ctx->channels; 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){ static void vorbis_seek(MDESoundContext ctx, int frames) {
ov_pcm_seek(ctx->opaque, frames); ov_pcm_seek(ctx->opaque, frames);
} }
static MDESoundDriverRec rec = { static MDESoundDriverRec rec = {
vorbis_open, vorbis_open,
vorbis_close, vorbis_close,
vorbis_read, vorbis_read,
vorbis_seek vorbis_seek};
};
MDESoundDriver MDESoundDriverVorbis = &rec; MDESoundDriver MDESoundDriverVorbis = &rec;

View file

@ -2,93 +2,93 @@
#include <MDE/Core/String.h> #include <MDE/Core/String.h>
static unsigned int syncsafe(FILE* f) { static unsigned int syncsafe(FILE* f) {
unsigned char d[4]; unsigned char d[4];
unsigned int r = 0; unsigned int r = 0;
int i; int i;
fread(d, 4, 1, f); fread(d, 4, 1, f);
for(i = 0; i < 4; i++) { for(i = 0; i < 4; i++) {
r = r << 7; r = r << 7;
r = r | (d[i] & 127); r = r | (d[i] & 127);
} }
return r; return r;
} }
static unsigned int big(FILE* f) { static unsigned int big(FILE* f) {
unsigned char d[4]; unsigned char d[4];
unsigned int r = 0; unsigned int r = 0;
int i; int i;
fread(d, 4, 1, f); fread(d, 4, 1, f);
for(i = 0; i < 4; i++) { for(i = 0; i < 4; i++) {
r = r << 8; r = r << 8;
r = r | d[i]; r = r | d[i];
} }
return r; return r;
} }
char* MDEID3GetTag(const char* path, const char* name, size_t* size){ char* MDEID3GetTag(const char* path, const char* name, size_t* size) {
FILE* f = fopen(path, "rb"); FILE* f = fopen(path, "rb");
unsigned char* d = NULL; unsigned char* d = NULL;
char sig[3]; char sig[3];
unsigned char ver[2]; unsigned char ver[2];
unsigned char flag; unsigned char flag;
unsigned char frame[4]; unsigned char frame[4];
unsigned int dsz = 0; unsigned int dsz = 0;
if(f == NULL) return NULL; if(f == NULL) return NULL;
fread(sig, 3, 1, f); fread(sig, 3, 1, f);
if(memcmp(sig, "ID3", 3) != 0) return NULL; if(memcmp(sig, "ID3", 3) != 0) return NULL;
fread(ver, 2, 1, f); fread(ver, 2, 1, f);
if(memcmp(ver, "\x04\x00", 2) != 0 && memcmp(ver, "\x03\x00", 2) != 0) return NULL; if(memcmp(ver, "\x04\x00", 2) != 0 && memcmp(ver, "\x03\x00", 2) != 0) return NULL;
fread(&flag, 1, 1, f); fread(&flag, 1, 1, f);
if(flag & (1 << 6)) return NULL; /* FIXME */ if(flag & (1 << 6)) return NULL; /* FIXME */
if(flag & (1 << 7)) return NULL; /* what even is this??? */ if(flag & (1 << 7)) return NULL; /* what even is this??? */
dsz = syncsafe(f); dsz = syncsafe(f);
while(dsz > 0) { while(dsz > 0) {
unsigned int fsz; unsigned int fsz;
fread(frame, 4, 1, f); fread(frame, 4, 1, f);
if(frame[0] == 0) break; /* XXX: Is this ok? */ if(frame[0] == 0) break; /* XXX: Is this ok? */
if(memcmp(ver, "\x04\x00", 2) == 0) { if(memcmp(ver, "\x04\x00", 2) == 0) {
fsz = syncsafe(f); fsz = syncsafe(f);
} else { } else {
fsz = big(f); fsz = big(f);
} }
fseek(f, 2, SEEK_CUR); fseek(f, 2, SEEK_CUR);
if(memcmp(frame, name, strlen(name)) == 0) { if(memcmp(frame, name, strlen(name)) == 0) {
d = malloc(fsz); d = malloc(fsz);
fread(d, fsz, 1, f); fread(d, fsz, 1, f);
*size = fsz; *size = fsz;
break; break;
} else { } else {
fseek(f, fsz, SEEK_CUR); fseek(f, fsz, SEEK_CUR);
} }
dsz -= 4 + 4 + 2 + fsz; dsz -= 4 + 4 + 2 + fsz;
} }
fclose(f); fclose(f);
return d; return d;
} }
char* MDEID3GetString(const char* path, const char* name){ char* MDEID3GetString(const char* path, const char* name) {
size_t sz; size_t sz;
unsigned char* d = MDEID3GetTag(path, name, &sz); unsigned char* d = MDEID3GetTag(path, name, &sz);
char* s; char* s;
int i; int i;
if(d == NULL) return NULL; if(d == NULL) return NULL;
if(d[0] == 2){ if(d[0] == 2) {
free(d); free(d);
return NULL; return NULL;
} }
@ -96,24 +96,24 @@ char* MDEID3GetString(const char* path, const char* name){
s = malloc(sz - 1 + 1); s = malloc(sz - 1 + 1);
memcpy(s, d + 1, sz - 1); memcpy(s, d + 1, sz - 1);
s[sz - 1] = 0; s[sz - 1] = 0;
if(d[0] == 1){ if(d[0] == 1) {
unsigned short bom = *(unsigned short*)&s[0]; unsigned short bom = *(unsigned short*)&s[0];
for(i = 1; i < sz - 1; i++){ for(i = 1; i < sz - 1; i++) {
if(bom == 0xfffe){ if(bom == 0xfffe) {
unsigned short n = 0; unsigned short n = 0;
n = n << 8; n = n << 8;
n = n | s[2 * i + 0]; n = n | s[2 * i + 0];
n = n << 8; n = n << 8;
n = n | s[2 * i + 1]; n = n | s[2 * i + 1];
s[i - 1] = n & 0x7f; s[i - 1] = n & 0x7f;
}else if(bom == 0xfeff){ } else if(bom == 0xfeff) {
unsigned short n = 0; unsigned short n = 0;
n = n << 8; n = n << 8;
n = n | s[2 * i + 1]; n = n | s[2 * i + 1];
n = n << 8; n = n << 8;
n = n | s[2 * i + 0]; n = n | s[2 * i + 0];
s[i - 1] = n & 0x7f; s[i - 1] = n & 0x7f;
} }
} }
s[i - 1] = 0; s[i - 1] = 0;

View file

@ -3,25 +3,25 @@
#include <stb_ds.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; \
sound->context = MDESoundDriver ## name->open(path); \ sound->context = MDESoundDriver##name->open(path); \
} }
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; sound->buffer = NULL;
TRY_DRIVER(MP3); TRY_DRIVER(MP3);
TRY_DRIVER(Vorbis); TRY_DRIVER(Vorbis);
if(sound->context == NULL){ if(sound->context == NULL) {
free(sound); free(sound);
return NULL; return NULL;
} }
if(sound->context->channels != 2 && sound->context->channels != 1){ if(sound->context->channels != 2 && sound->context->channels != 1) {
MDESoundClose(sound); MDESoundClose(sound);
return NULL; return NULL;
} }
@ -29,18 +29,18 @@ MDESound MDESoundOpen(const char* path){
return sound; return sound;
} }
int MDESoundRead(MDESound sound, short* out, int frames){ int MDESoundRead(MDESound sound, short* out, int frames) {
int total = frames; int total = frames;
int seek = 0; int seek = 0;
while(arrlen(sound->buffer) > 0 && total > 0){ while(arrlen(sound->buffer) > 0 && total > 0) {
int fr = (sound->buffer[0].frames - sound->buffer[0].seek); int fr = (sound->buffer[0].frames - sound->buffer[0].seek);
if(fr > total) fr = total; if(fr > total) fr = total;
memcpy(out + seek * 2, sound->buffer[0].data + sound->buffer[0].seek * 2, 2 * 2 * fr); memcpy(out + seek * 2, sound->buffer[0].data + sound->buffer[0].seek * 2, 2 * 2 * fr);
sound->buffer[0].seek += fr; sound->buffer[0].seek += fr;
if(sound->buffer[0].seek == sound->buffer[0].frames){ if(sound->buffer[0].seek == sound->buffer[0].frames) {
free(sound->buffer[0].data); free(sound->buffer[0].data);
arrdel(sound->buffer, 0); arrdel(sound->buffer, 0);
} }
@ -48,35 +48,35 @@ int MDESoundRead(MDESound sound, short* out, int frames){
seek += fr; seek += fr;
} }
while(total > 0){ while(total > 0) {
int i; int i;
short* buf = malloc(sizeof(*buf) * 2 * frames); short* buf = malloc(sizeof(*buf) * 2 * frames);
short* f = malloc(sizeof(*f) * sound->context->channels * frames); short* f = malloc(sizeof(*f) * sound->context->channels * frames);
int r = sound->driver->read(sound->context, f, frames); int r = sound->driver->read(sound->context, f, frames);
if(sound->context->channels == 2){ if(sound->context->channels == 2) {
for(i = 0; i < r * 2; i++){ for(i = 0; i < r * 2; i++) {
buf[i] = f[i]; buf[i] = f[i];
} }
}else if(sound->context->channels == 1){ } else if(sound->context->channels == 1) {
for(i = 0; i < r; i++){ for(i = 0; i < r; i++) {
buf[i * 2 + 0] = f[i]; buf[i * 2 + 0] = f[i];
buf[i * 2 + 1] = f[i]; buf[i * 2 + 1] = f[i];
} }
} }
free(f); free(f);
if(r == 0){ if(r == 0) {
free(buf); free(buf);
break; break;
}else if(total >= r){ } else if(total >= r) {
memcpy(out + seek * 2, buf, r * 2 * 2); memcpy(out + seek * 2, buf, r * 2 * 2);
seek += r; seek += r;
total -= r; total -= r;
free(buf); free(buf);
}else if(total < r){ } else if(total < r) {
MDESoundBuffer buffer; MDESoundBuffer buffer;
buffer.data = buf; buffer.data = buf;
buffer.seek = total; buffer.seek = total;
buffer.frames = r; buffer.frames = r;
arrput(sound->buffer, buffer); arrput(sound->buffer, buffer);
@ -89,12 +89,12 @@ int MDESoundRead(MDESound sound, short* out, int frames){
return seek; return seek;
} }
int MDESoundReadFloat(MDESound sound, float* out, int frames){ int MDESoundReadFloat(MDESound sound, float* out, int frames) {
short* f = malloc(sizeof(*f) * 2 * frames); short* f = malloc(sizeof(*f) * 2 * frames);
int i; int i;
int r = MDESoundRead(sound, f, frames); int r = MDESoundRead(sound, f, frames);
for(i = 0; i < r * 2; i++){ for(i = 0; i < r * 2; i++) {
out[i] = f[i] / 32767.0; out[i] = f[i] / 32767.0;
} }
@ -103,11 +103,11 @@ int MDESoundReadFloat(MDESound sound, float* out, int frames){
return r; return r;
} }
void MDESoundSeek(MDESound sound, int frames){ void MDESoundSeek(MDESound sound, int frames) {
sound->driver->seek(sound->context, frames); sound->driver->seek(sound->context, frames);
} }
void MDESoundClose(MDESound sound){ void MDESoundClose(MDESound sound) {
int i; int i;
if(sound->context->title != NULL) free(sound->context->title); if(sound->context->title != NULL) free(sound->context->title);
if(sound->context->artist != NULL) free(sound->context->artist); if(sound->context->artist != NULL) free(sound->context->artist);
@ -116,7 +116,7 @@ void MDESoundClose(MDESound sound){
sound->driver->close(sound->context); sound->driver->close(sound->context);
for(i = 0; i < arrlen(sound->buffer); i++){ for(i = 0; i < arrlen(sound->buffer); i++) {
free(sound->buffer[i].data); free(sound->buffer[i].data);
} }
arrfree(sound->buffer); arrfree(sound->buffer);