21const char* gf_audio_mod_sig[] = {
"M!K!",
"M.K.",
"FLT4",
"FLT8",
"4CHN",
"6CHN",
"8CHN",
"10CH",
"12CH",
"14CH",
"16CH",
"18CH",
"20CH",
"22CH",
"24CH",
"26CH",
"28CH",
"30CH",
"32CH"};
23void gf_audio_callback(ma_device* dev,
void* output,
const void* input, ma_uint32 frame) {
26 ma_int16* out = (ma_int16*)output;
27 float* tmp = malloc(
sizeof(*tmp) * frame * 2);
30 for(i = 0; i < (gf_audio_id_t)frame; i++) {
35 ma_mutex_lock(audio->
mutex);
40 ma_int16* r = malloc(
sizeof(*r) * frame * 2);
41 ma_decoder_read_pcm_frames(audio->
decoder[i].
decoder, r, frame, &readframe);
42 for(j = 0; j < readframe; j++) {
43 tmp[2 * j + 0] += (double)r[2 * j + 0] / 32768.0;
44 tmp[2 * j + 1] += (double)r[2 * j + 1] / 32768.0;
47 if(frame > readframe) {
48 ma_mutex_unlock(audio->
mutex);
50 gf_audio_decoder_destroy(&audio->
decoder[i]);
55 float* r = malloc(
sizeof(*r) * frame * 2);
56 jar_xm_generate_samples(audio->
decoder[i].
xm, r, frame);
57 gotframe = audio->
decoder[i].
samples > (gf_audio_id_t)frame ? frame : audio->decoder[i].samples;
58 for(j = 0; j < gotframe; j++) {
59 tmp[2 * j + 0] += (double)r[2 * j + 0];
60 tmp[2 * j + 1] += (double)r[2 * j + 1];
65 ma_mutex_unlock(audio->
mutex);
67 gf_audio_decoder_destroy(&audio->
decoder[i]);
72 ma_int16* r = malloc(
sizeof(*r) * frame * 2);
73 jar_mod_fillbuffer(audio->
decoder[i].
mod, r, frame, NULL);
74 gotframe = audio->
decoder[i].
samples > (gf_audio_id_t)frame ? frame : audio->decoder[i].samples;
75 for(j = 0; j < gotframe; j++) {
76 tmp[2 * j + 0] += (double)r[2 * j + 0] / 32768.0;
77 tmp[2 * j + 1] += (double)r[2 * j + 1] / 32768.0;
82 ma_mutex_unlock(audio->
mutex);
84 gf_audio_decoder_destroy(&audio->
decoder[i]);
88 if(!unlocked) ma_mutex_unlock(audio->
mutex);
90 for(i = 0; i < (gf_audio_id_t)frame; i++) {
91 out[2 * i + 0] = tmp[2 * i + 0] * 32768;
92 out[2 * i + 1] = tmp[2 * i + 1] * 32768;
97gf_audio_id_t gf_audio_load(
gf_audio_t* audio,
const void* data,
size_t size) {
99 ma_mutex_lock(audio->
mutex);
102 int xm_cond = size > 37 && memcmp(data,
"Extended Module: ", 17) == 0 && ((
char*)data)[37] == 0x1a;
103 int mod_cond = size > 1080;
107 int mod_sig_cond = 0;
108 for(j = 0; j <
sizeof(gf_audio_mod_sig) /
sizeof(gf_audio_mod_sig[0]); j++) {
109 mod_sig_cond = mod_sig_cond || (memcmp((
char*)data + 1080, gf_audio_mod_sig[j], 4) == 0);
111 mod_cond = mod_cond && mod_sig_cond;
118 ma_mutex_unlock(audio->
mutex);
122 }
else if(mod_cond) {
126 if(jar_mod_load(audio->
decoder[i].
mod, (
void*)data, size)) {
129 ma_mutex_unlock(audio->
mutex);
138 ma_mutex_unlock(audio->
mutex);
143 ma_mutex_unlock(audio->
mutex);
147 ma_mutex_unlock(audio->
mutex);
151gf_audio_id_t gf_audio_load_file(
gf_audio_t* audio,
const char* path) {
152 FILE* f = fopen(path,
"rb");
156 if(f == NULL)
return -1;
157 fseek(f, 0, SEEK_END);
159 fseek(f, 0, SEEK_SET);
162 fread(data, sz, 1, f);
163 st = gf_audio_load(audio, data, sz);
174 memset(audio, 0,
sizeof(*audio));
177 audio->
device_config = ma_device_config_init(ma_device_type_playback);
198 gf_audio_destroy(audio);
203 if(ma_mutex_init(audio->
mutex) != MA_SUCCESS) {
207 gf_audio_destroy(audio);
211 if(ma_device_start(audio->
device) != MA_SUCCESS) {
213 gf_audio_destroy(audio);
229 ma_decoder_uninit(decoder->
decoder);
233 if(decoder->
xm != NULL) {
234 jar_xm_free_context(decoder->
xm);
237 if(decoder->
mod != NULL) {
238 jar_mod_unload(decoder->
mod);
248 if(audio->
device != NULL) {
249 ma_device_uninit(audio->
device);
252 if(audio->
mutex != NULL) {
253 ma_mutex_uninit(audio->
mutex);
257 gf_audio_decoder_destroy(&audio->
decoder[i]);
264 ma_mutex_lock(audio->
mutex);
266 ma_mutex_unlock(audio->
mutex);
270 ma_mutex_lock(audio->
mutex);
272 ma_mutex_unlock(audio->
mutex);
275void gf_audio_stop(
gf_audio_t* audio, gf_audio_id_t
id) { gf_audio_decoder_destroy(&audio->
decoder[
id]); }
#define GF_AUDIO_MAX_DECODERS
Max decoders audio interface can handle.
#define gf_log_function(engine, fmt,...)
Output log with line number and function name.
Required headers before anything.
Type definitions related to math.
jar_xm_context_t * xm
XM context.
ma_decoder_config decoder_config
miniaudio decoder config
int used
1 if used, -1 if used but paused, otherwise 0
int samples
Remaining samples.
jar_mod_context_t * mod
MOD context.
gf_audio_t * audio
Audio interface.
ma_decoder * decoder
miniaudio decoder
ma_device_config device_config
miniaudio device config
ma_device * device
miniaudio device
gf_audio_decoder_t decoder[64]
Decoder.
gf_engine_t * engine
Engine instance.