More work on loading and playing midi files.
[orgux.git] / smf.c
blob0a13be3197352fe7ac9cd223da69d54e23336559
1 /*
2 orgux - a just-for-fun real time synth
3 Copyright (C) 2009 Evan Rinehart
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 /* smf */
22 #include <stdio.h>
23 #include <string.h>
25 #include "orgux.h"
27 #define STRING_MAX 256
29 typedef unsigned char octet;
31 extern void orgux_seq_append(orgux_state* S, int tick, int type, int chan, int val1, int val2);
32 extern void orgux_seq_sort(orgux_state* S);
34 int bytes2short(octet arr[2]){
35 return (arr[0]<<8) | arr[1];
38 int bytes2int(octet arr[4]){
39 return (arr[0]<<24) | (arr[1]<<16) | (arr[2]<<8) | arr[3];
43 /* read a bunch of bytes and discard */
44 void skip_ahead(orgux_reader* src, int count){
45 const int W = 256;
46 char buf[W];
48 int C = count;
50 while(C > W){
51 src->read(buf,W,src->ud);
52 C -= W;
54 src->read(buf,C,src->ud);
57 octet read_one(orgux_reader* src){
58 octet byte[1];
59 src->read(byte,1,src->ud);
60 return byte[0];
63 int get_delta(orgux_reader* src){
64 octet a = read_one(src);
65 if(a<0x80){return a;}
67 octet b = read_one(src);
68 if(b<0x80){return ((a&0x7f)<<7) | b;}
70 octet c = read_one(src);
71 if(c<0x80){return ((a&0x7f)<<14) | ((b&0x7f)<<7) | c;}
73 octet d = read_one(src);
74 return ((a&0x7f)<<21) | ((b&0x7f)<<14) | ((c&0x7f)<<7) | d;
78 int orgux_load_song(orgux_state* S, orgux_reader* src){
80 char buf[16];
81 char string[STRING_MAX];
82 int e;
83 int n;
85 int loopstart;
86 int loopend;
87 int uspq;
89 /*MThd*/
90 if(src->read(buf,4,src->ud)<0) return -1;
91 printf("%x %x %x %x\n",buf[0],buf[1],buf[2],buf[3]);
92 /*0x00000006*/
93 if(src->read(buf,4,src->ud)<0) return -1;
94 printf("%x %x %x %x\n",buf[0],buf[1],buf[2],buf[3]);
95 /*format type: 0x0000 0x0001 or 0x0002*/
96 if(src->read(buf,2,src->ud)<0) return -1;
97 printf("%x %x\n",buf[0],buf[1]);
98 /*number of tracks*/
99 if(src->read(buf,2,src->ud)<0) return -1;
100 int track_count = bytes2short(buf);
101 printf("%x %x\n",buf[0],buf[1]);
102 printf("track count = %d\n",track_count);
103 /* time division */
104 if(src->read(buf,2,src->ud)<0) return -1;
105 //code to figure out time division
106 printf("%x %x\n",buf[0],buf[1]);
107 for(int i=0; i<track_count; i++){
109 /*MTrk*/
110 if(src->read(buf,4,src->ud)<0) return -1;
111 printf("%x %x %x %x\n",buf[0],buf[1],buf[2],buf[3]);
112 /* chunk size */
113 if(src->read(buf,4,src->ud)<0) return -1;
114 int chunk_size = bytes2int(buf);
115 printf("%x %x %x %x\n",buf[0],buf[1],buf[2],buf[3]);
116 printf("chunk size = %d\n",chunk_size);
117 int tick = 0;
118 int end_of_track = 0;
119 int last_type = 0x80;
120 int last_chan = 0;
121 while(1){
122 int delta = get_delta(src);
123 printf("delta = %d\n",delta);
124 if(delta < 0) return -1;
125 tick += delta;
127 //type and channel
128 if(src->read(buf,1,src->ud)<0) return -1;
129 int type = buf[0] & 0xf0;
130 if(type >= 0x80 && type <= 0xe0){//normal event
131 last_type = type;
132 int chan = buf[0] & 0x0f;
133 last_chan = chan;
134 if(src->read(buf,2,src->ud)<0) return -1;
135 int val1 = buf[0];
136 int val2 = buf[1];
137 printf("normal %x %x %x\n",type|chan,val1,val2);
138 orgux_seq_append(S,tick,type,chan,val1,val2);
140 else if(type < 0x80){//running status
141 int val1 = buf[0];
142 if(src->read(buf,1,src->ud)<0) return -1;
143 int val2 = buf[0];
144 printf("running %x %x %x\n",last_type|last_chan,val1,val2);
145 orgux_seq_append(S,tick,last_type,last_chan,val1,val2);
147 else if(type == 0xff){//meta event
148 if(src->read(buf,1,src->ud)<0) return -1;
149 type = buf[0];
150 printf("meta event\n");
151 int len = get_delta(src);
152 if(len < 0) return -1;
154 switch(type){
155 case 0x2f: printf("end of track\n"); end_of_track = 1; break;
156 case 0x51:printf("tempo change\n");/*tempo*/
157 if(src->read(buf,3,src->ud)<0) return -1;
158 uspq = (buf[0]<<16) | (buf[1]<<8) | buf[0];
159 break;
160 case 0x58: printf("time sig\n");/*time signature*/
161 if(src->read(buf,4,src->ud)<0) return -1;
162 //...
163 break;
164 case 0x01: printf("text\n");/*text*/
165 if(len >= STRING_MAX){skip_ahead(src, len);}
166 else{
167 if(src->read(string,len,src->ud)<0) return -1;
168 string[len] = '\0';
169 if(strncmp(string,"LoopStart",len)==0){
170 loopstart = tick;
172 else if(strncmp(string,"LoopEnd",len)==0){
173 loopend = tick;
177 break;
178 default: skip_ahead(src,len); break;
181 else{printf("sysex\n");//sysex and such...
182 int len = get_delta(src);
183 if(len < 0) return -1;
184 skip_ahead(src, len);
187 if(end_of_track) break;
192 orgux_seq_sort(S);
194 //orgux_set_tempo();
195 //orgux_set_loop_positions(S, loopstart, loopend);
197 return 0;
202 int read_file(unsigned char* buf, int count, void* ud){
203 FILE* f = (FILE*)ud;
204 int n = fread(buf, 1, count, f);
205 if(n < count){return -1;}
206 return 0;
209 int orgux_load_smf(orgux_state* S, char* filename){
210 FILE* f = fopen(filename, "r");
211 if(!f){return -1;}
212 orgux_reader src;
213 src.ud = f;
214 src.read = read_file;
215 printf("loading midi file\n");
216 if(orgux_load_song(S, &src) < 0){fclose(f); return -1;}
217 fclose(f);
218 return 0;