introduce MDESound

This commit is contained in:
Nishi 2025-11-24 19:49:08 +09:00
commit b2e83e695d
Signed by: nishi
GPG key ID: 27EF69B208EB9343
10 changed files with 318 additions and 9 deletions

View file

@ -36,6 +36,7 @@ endmacro()
add_subdirectory(core)
add_subdirectory(audio)
add_subdirectory(sound)
install(
DIRECTORY include/

View file

@ -22,7 +22,7 @@ static void* thread_routine(void* arg) {
return NULL;
}
void* MDEAudioOpen(MDEAudioHandler handler, void* user) {
MDEAudio MDEAudioOpen(MDEAudioHandler handler, void* user) {
int rate = MDEAudioRate;
driver_t* drv = malloc(sizeof(*drv));
memset(drv, 0, sizeof(*drv));
@ -42,7 +42,7 @@ void* MDEAudioOpen(MDEAudioHandler handler, void* user) {
return drv;
}
void MDEAudioClose(void* handle) {
void MDEAudioClose(MDEAudio handle) {
driver_t* drv = handle;
void* ret;
@ -60,7 +60,7 @@ void MDEAudioClose(void* handle) {
free(drv);
}
void MDEAudioStart(void* handle) {
void MDEAudioStart(MDEAudio handle) {
driver_t* drv = handle;
pthread_create(&drv->thread, NULL, thread_routine, handle);

View file

@ -1,5 +1,5 @@
#ifndef __MDE_AUDIO_H__
#define __MDE_AUDIO_H__
#ifndef __MDE_AUDIO_AUDIO_H__
#define __MDE_AUDIO_AUDIO_H__
#include <MDE/MachDep.h>
@ -12,15 +12,17 @@ extern "C" {
/* always stereo, btw */
#define MDEAudioRate 48000
typedef void* MDEAudio;
/* S16, stereo. frames*2*2 == bytes */
typedef void (*MDEAudioHandler)(void* handle, void* user, void* data, int frames);
typedef void (*MDEAudioHandler)(MDEAudio handle, void* user, void* data, int frames);
/* driver functions */
void* MDEAudioOpen(MDEAudioHandler handler, void* user);
MDEAudio MDEAudioOpen(MDEAudioHandler handler, void* user);
void MDEAudioClose(void* handle);
void MDEAudioClose(MDEAudio handle);
void MDEAudioStart(void* handle);
void MDEAudioStart(MDEAudio handle);
#ifdef __cplusplus
}

View file

@ -10,4 +10,7 @@
#include <MDE/Audio/Audio.h>
#include <MDE/Sound/Sound.h>
#include <MDE/Sound/ID3.h>
#endif

18
include/MDE/Sound/ID3.h Normal file
View file

@ -0,0 +1,18 @@
#ifndef __MDE_SOUND_ID3_H__
#define __MDE_SOUND_ID3_H__
#include <MDE/MachDep.h>
#ifdef __cplusplus
extern "C" {
#endif
char* MDEID3GetTag(const char* path, const char* name, size_t* size);
char* MDEID3GetString(const char* path, const char* name);
#ifdef __cplusplus
}
#endif
#endif

54
include/MDE/Sound/Sound.h Normal file
View file

@ -0,0 +1,54 @@
#ifndef __MDE_SOUND_SOUND_H__
#define __MDE_SOUND_SOUND_H__
#include <MDE/MachDep.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct _MDESoundDriver MDESoundDriverRec, *MDESoundDriver;
typedef struct _MDESoundContext* MDESoundContext;
typedef struct _MDESound* MDESound;
struct _MDESoundContext {
int sample_rate;
int channels;
int frames;
void* opaque;
char* title;
char* album;
char* artist;
char* genre;
};
struct _MDESoundDriver {
MDESoundContext (*open)(const char* path);
void (*close)(MDESoundContext context);
int (*read)(MDESoundContext context, short* out, int frames);
void (*seek)(MDESoundContext context, int frames);
};
struct _MDESound {
MDESoundContext context;
MDESoundDriver driver;
};
extern MDESoundDriver MDESoundDriverMP3;
MDESound MDESoundOpen(const char* path);
int MDESoundRead(MDESound sound, short* out, int frames);
int MDESoundReadFloat(MDESound sound, float* out, int frames);
void MDESoundSeek(MDESound sound, int frames);
void MDESoundClose(MDESound sound);
#ifdef __cplusplus
}
#endif
#endif

6
sound/CMakeLists.txt Normal file
View file

@ -0,0 +1,6 @@
setup_lib(sound Sound)
target_link_libraries(
MDESound
PRIVATE
MDECore
)

102
sound/id3.c Normal file
View file

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

54
sound/mp3.c Normal file
View file

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

69
sound/sound.c Normal file
View file

@ -0,0 +1,69 @@
#include <MDE/Sound/Sound.h>
#define TRY_DRIVER(name) \
if(sound->context == NULL){ \
sound->driver = MDESoundDriver ## name; \
sound->context = MDESoundDriver ## name->open(path); \
}
MDESound MDESoundOpen(const char* path){
MDESound sound = malloc(sizeof(*sound));
sound->context = NULL;
TRY_DRIVER(MP3);
if(sound->context == NULL){
free(sound);
return NULL;
}
if(sound->context->channels != 2 && sound->context->channels != 1){
MDESoundClose(sound);
return NULL;
}
return sound;
}
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);
return r;
}
int MDESoundReadFloat(MDESound sound, float* out, int frames){
short* f = malloc(sizeof(*f) * 2 * frames);
int i;
int r = MDESoundRead(sound, f, frames);
for(i = 0; i < r * 2; i++){
out[i] = f[i] / 32767.0;
}
free(f);
return r;
}
void MDESoundSeek(MDESound sound, int frames){
sound->driver->seek(sound->context, frames);
}
void MDESoundClose(MDESound sound){
sound->driver->close(sound->context);
free(sound);
}