introduce MDESound
This commit is contained in:
parent
04651ea59b
commit
b2e83e695d
10 changed files with 318 additions and 9 deletions
|
|
@ -36,6 +36,7 @@ endmacro()
|
|||
|
||||
add_subdirectory(core)
|
||||
add_subdirectory(audio)
|
||||
add_subdirectory(sound)
|
||||
|
||||
install(
|
||||
DIRECTORY include/
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
18
include/MDE/Sound/ID3.h
Normal 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
54
include/MDE/Sound/Sound.h
Normal 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
6
sound/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
setup_lib(sound Sound)
|
||||
target_link_libraries(
|
||||
MDESound
|
||||
PRIVATE
|
||||
MDECore
|
||||
)
|
||||
102
sound/id3.c
Normal file
102
sound/id3.c
Normal 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
54
sound/mp3.c
Normal 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
69
sound/sound.c
Normal 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);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue