From 08d250fdea812ac3dce87c9b1f07bb57cfc6c6a7 Mon Sep 17 00:00:00 2001 From: EvanR Date: Sat, 13 Jun 2009 12:34:58 -0400 Subject: [PATCH] Added more smf reading code. Fixed user src interface. Now you either provide orgux with a file name or a reader structure (similar to SDL RWops) which is used internally to get more data. --- core.c | 3 ++ orgux.h | 14 +++++++- sdlclient.c | 19 +++++++++- smf.c | 113 +++++++++++++++++++++++++++++++++++++++++++----------------- 4 files changed, 115 insertions(+), 34 deletions(-) diff --git a/core.c b/core.c index af47f05..8faaaa4 100644 --- a/core.c +++ b/core.c @@ -483,3 +483,6 @@ void orgux_seq_sort(orgux_state* S){ } +void orgux_play(orgux_state* S, int yesno){ + S->seq_en = yesno; +} \ No newline at end of file diff --git a/orgux.h b/orgux.h index 074cce6..932df2e 100644 --- a/orgux.h +++ b/orgux.h @@ -21,10 +21,22 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. typedef struct orgux_state orgux_state; +typedef struct { + int (*read)(unsigned char* buf, int count, void* ud); + void* ud; +} orgux_reader; + void orgux_process(orgux_state* S, float* lbuf, float* rbuf, int len); void orgux_schedule(orgux_state* S, int sample, unsigned char midi[3]); void orgux_control(orgux_state* S, int type, int chan, int val1, int val2); orgux_state* orgux_init(int sample_rate); void orgux_free(orgux_state* S); -int orgux_load_song(orgux_state* S, int (*pull) (unsigned char* buf, int bytes)); +int orgux_load_smf(orgux_state* S, char* filename); +int orgux_load_song(orgux_state* S, orgux_reader* src); +void orgux_play(orgux_state* S, int yesno); +void orgux_set_position(orgux_state* S, int tick); +void orgux_set_volume(orgux_state* S, float level); +void orgux_set_tempo(orgux_state* S, float bpm); +void orgux_fade_out(orgux_state* S, float speed); +void orgux_fade_in(orgux_state* S, float speed); \ No newline at end of file diff --git a/sdlclient.c b/sdlclient.c index 377203a..dfbaad3 100644 --- a/sdlclient.c +++ b/sdlclient.c @@ -48,11 +48,23 @@ void audio_callback(void *userdata, Uint8 *stream, int len){ } +int pull(unsigned char* buf, int count, void* ud){ + FILE* f = (FILE*)ud; + int n = fread(buf,1,count,f); + if(n < count) return -1; + return 0; +} + + + int main(int argc, char* argv[]){ S = orgux_init(SAMPLE_RATE); - //load midi file + if(orgux_load_smf(S, "song.mid") < 0){ + printf("cannot open midi file\n"); + exit(-1); + } audio.freq = SAMPLE_RATE; audio.format = AUDIO_S16; @@ -66,8 +78,13 @@ int main(int argc, char* argv[]){ } SDL_PauseAudio(0); + SDL_Delay(1000); + + orgux_play(S, 1); while(1){ SDL_Delay(1000); } + + return 0; } diff --git a/smf.c b/smf.c index 5f27884..6b475a5 100644 --- a/smf.c +++ b/smf.c @@ -19,13 +19,14 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. /* smf */ +#include +#include + #include "orgux.h" #define STRING_MAX 256 typedef unsigned char octet; -typedef int (*reader)(octet* buf, int count); - extern void orgux_seq_append(orgux_state* S, int tick, int type, int chan, int val1, int val2); extern void orgux_seq_sort(orgux_state* S); @@ -40,71 +41,75 @@ int bytes2int(octet arr[4]){ /* read a bunch of bytes and discard */ -void skip_ahead(reader pull, int count){ +void skip_ahead(orgux_reader* src, int count){ const int W = 256; char buf[W]; int C = count; while(C > W){ - pull(buf,W); + src->read(buf,W,src->ud); C -= W; } - pull(buf,C); + src->read(buf,C,src->ud); } -octet read_one(reader pull){ +octet read_one(orgux_reader* src){ octet byte[1]; - pull(byte,1); + src->read(byte,1,src->ud); return byte[0]; } -int get_delta(reader pull){ - octet a = read_one(pull); +int get_delta(orgux_reader* src){ + octet a = read_one(src); if(a<0x80){return a;} - octet b = read_one(pull); + octet b = read_one(src); if(b<0x80){return ((a&0x7f)<<7) | b;} - octet c = read_one(pull); + octet c = read_one(src); if(c<0x80){return ((a&0x7f)<<14) | ((b&0x7f)<<7) | c;} - octet d = read_one(pull); + octet d = read_one(src); return ((a&0x7f)<<21) | ((b&0x7f)<<14) | ((c&0x7f)<<7) | d; } -int orgux_load_song(orgux_state* S, int (*pull) (unsigned char* buf, int bytes)){ +int orgux_load_song(orgux_state* S, orgux_reader* src){ char buf[16]; char string[STRING_MAX]; int e; int n; + int loopstart; + int loopend; + int uspq; + /*MThd*/ - if(pull(buf,4)<0) return -1; + if(src->read(buf,4,src->ud)<0) return -1; /*0x00000006*/ - if(pull(buf,4)<0) return -1; + if(src->read(buf,4,src->ud)<0) return -1; /*format type: 0x0000 0x0001 or 0x0002*/ - if(pull(buf,2)<0) return -1; + if(src->read(buf,2,src->ud)<0) return -1; /*number of tracks*/ - if(pull(buf,2)<0) return -1; + if(src->read(buf,2,src->ud)<0) return -1; int track_count = bytes2short(buf); /* time division */ - if(pull(buf,2)<0) return -1; + if(src->read(buf,2,src->ud)<0) return -1; //code to figure out time division for(int i=0; iread(buf,4,src->ud)<0) return -1; /* chunk size */ - if(pull(buf,4)<0) return -1; + if(src->read(buf,4,src->ud)<0) return -1; int chunk_size = bytes2int(buf); int tick = 0; @@ -112,18 +117,18 @@ int orgux_load_song(orgux_state* S, int (*pull) (unsigned char* buf, int bytes)) int last_type = 0x80; int last_chan = 0; while(1){ - int delta = get_delta(pull); + int delta = get_delta(src); if(delta < 0) return -1; tick += delta; //type and channel - if(pull(buf,1)<0) return -1; + if(src->read(buf,1,src->ud)<0) return -1; int type = buf[0] & 0xf0; if(type >= 0x80 && type <= 0xe0){//normal event last_type = type; int chan = buf[0] & 0x0f; last_chan = chan; - if(pull(buf,2)<0) return -1; + if(src->read(buf,2,src->ud)<0) return -1; int val1 = buf[0]; int val2 = buf[1]; @@ -131,28 +136,49 @@ int orgux_load_song(orgux_state* S, int (*pull) (unsigned char* buf, int bytes)) } else if(type < 0x80){//running status int val1 = buf[0]; - if(pull(buf,1)<0) return -1; + if(src->read(buf,1,src->ud)<0) return -1; int val2 = buf[0]; orgux_seq_append(S,tick,last_type,last_chan,val1,val2); } else if(type == 0xff){//meta event - if(pull(buf,1)<0) return -1; + if(src->read(buf,1,src->ud)<0) return -1; type = buf[0]; - int len = get_delta(pull); + int len = get_delta(src); if(len < 0) return -1; switch(type){ case 0x2f: end_of_track = 1; break; - case 0x51: /*tempo change*/ break; - case 0x58: /*time signature*/ break; - case 0x01: /*text*/ break; - default: skip_ahead(pull,len); break; + case 0x51:/*tempo*/ + if(src->read(buf,3,src->ud)<0) return -1; + uspq = (buf[0]<<16) | (buf[1]<<8) | buf[0]; + break; + case 0x58: /*time signature*/ + if(src->read(buf,4,src->ud)<0) return -1; + //... + break; + case 0x01: /*text*/ + if(len >= STRING_MAX){skip_ahead(src, len);} + else{ + if(src->read(string,len,src->ud)<0) return -1; + string[len] = '\0'; + if(strncmp(string,"LoopStart",len)==0){ + loopstart = tick; + } + else if(strncmp(string,"LoopEnd",len)==0){ + loopend = tick; + } + } + + break; + default: skip_ahead(src,len); break; } } - else{// sysex and such... - + else{//sysex and such... + int len = get_delta(src); + if(len < 0) return -1; + skip_ahead(src, len); } if(end_of_track) break; @@ -161,6 +187,29 @@ int orgux_load_song(orgux_state* S, int (*pull) (unsigned char* buf, int bytes)) } orgux_seq_sort(S); + + //orgux_set_tempo(); + //orgux_set_loop_positions(S, loopstart, loopend); + return 0; } + + +int read_file(unsigned char* buf, int count, void* ud){ + FILE* f = (FILE*)ud; + int n = fread(buf, 1, count, f); + if(n < count){return -1;} + return 0; +} + +int orgux_load_smf(orgux_state* S, char* filename){ + FILE* f = fopen(filename, "r"); + if(!f){return -1;} + orgux_reader src; + src.ud = f; + src.read = read_file; + if(orgux_load_song(S, &src) < 0){fclose(f); return -1;} + fclose(f); + return 0; +} -- 2.11.4.GIT