Added more smf decoding code. Do not use.
[orgux.git] / smf.c
blob5f2788482bf97c3b67fc5dc653ffbde801226a81
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 "orgux.h"
24 #define STRING_MAX 256
26 typedef unsigned char octet;
27 typedef int (*reader)(octet* buf, int count);
30 extern void orgux_seq_append(orgux_state* S, int tick, int type, int chan, int val1, int val2);
31 extern void orgux_seq_sort(orgux_state* S);
33 int bytes2short(octet arr[2]){
34 return (arr[1]<<8) | arr[0];
37 int bytes2int(octet arr[4]){
38 return (arr[3]<<24) | (arr[2]<<16) | (arr[1]<<8) | arr[0];
42 /* read a bunch of bytes and discard */
43 void skip_ahead(reader pull, int count){
44 const int W = 256;
45 char buf[W];
47 int C = count;
49 while(C > W){
50 pull(buf,W);
51 C -= W;
53 pull(buf,C);
56 octet read_one(reader pull){
57 octet byte[1];
58 pull(byte,1);
59 return byte[0];
62 int get_delta(reader pull){
63 octet a = read_one(pull);
64 if(a<0x80){return a;}
66 octet b = read_one(pull);
67 if(b<0x80){return ((a&0x7f)<<7) | b;}
69 octet c = read_one(pull);
70 if(c<0x80){return ((a&0x7f)<<14) | ((b&0x7f)<<7) | c;}
72 octet d = read_one(pull);
73 return ((a&0x7f)<<21) | ((b&0x7f)<<14) | ((c&0x7f)<<7) | d;
77 int orgux_load_song(orgux_state* S, int (*pull) (unsigned char* buf, int bytes)){
79 char buf[16];
80 char string[STRING_MAX];
81 int e;
82 int n;
84 /*MThd*/
85 if(pull(buf,4)<0) return -1;
87 /*0x00000006*/
88 if(pull(buf,4)<0) return -1;
90 /*format type: 0x0000 0x0001 or 0x0002*/
91 if(pull(buf,2)<0) return -1;
93 /*number of tracks*/
94 if(pull(buf,2)<0) return -1;
95 int track_count = bytes2short(buf);
97 /* time division */
98 if(pull(buf,2)<0) return -1;
99 //code to figure out time division
101 for(int i=0; i<track_count; i++){
103 /*MTrk*/
104 if(pull(buf,4)<0) return -1;
106 /* chunk size */
107 if(pull(buf,4)<0) return -1;
108 int chunk_size = bytes2int(buf);
110 int tick = 0;
111 int end_of_track = 0;
112 int last_type = 0x80;
113 int last_chan = 0;
114 while(1){
115 int delta = get_delta(pull);
116 if(delta < 0) return -1;
117 tick += delta;
119 //type and channel
120 if(pull(buf,1)<0) return -1;
121 int type = buf[0] & 0xf0;
122 if(type >= 0x80 && type <= 0xe0){//normal event
123 last_type = type;
124 int chan = buf[0] & 0x0f;
125 last_chan = chan;
126 if(pull(buf,2)<0) return -1;
127 int val1 = buf[0];
128 int val2 = buf[1];
130 orgux_seq_append(S,tick,type,chan,val1,val2);
132 else if(type < 0x80){//running status
133 int val1 = buf[0];
134 if(pull(buf,1)<0) return -1;
135 int val2 = buf[0];
137 orgux_seq_append(S,tick,last_type,last_chan,val1,val2);
139 else if(type == 0xff){//meta event
140 if(pull(buf,1)<0) return -1;
141 type = buf[0];
143 int len = get_delta(pull);
144 if(len < 0) return -1;
146 switch(type){
147 case 0x2f: end_of_track = 1; break;
148 case 0x51: /*tempo change*/ break;
149 case 0x58: /*time signature*/ break;
150 case 0x01: /*text*/ break;
151 default: skip_ahead(pull,len); break;
154 else{// sysex and such...
158 if(end_of_track) break;
163 orgux_seq_sort(S);
164 return 0;