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.
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
){
56 octet
read_one(reader pull
){
62 int get_delta(reader pull
){
63 octet a
= read_one(pull
);
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
)){
80 char string
[STRING_MAX
];
85 if(pull(buf
,4)<0) return -1;
88 if(pull(buf
,4)<0) return -1;
90 /*format type: 0x0000 0x0001 or 0x0002*/
91 if(pull(buf
,2)<0) return -1;
94 if(pull(buf
,2)<0) return -1;
95 int track_count
= bytes2short(buf
);
98 if(pull(buf
,2)<0) return -1;
99 //code to figure out time division
101 for(int i
=0; i
<track_count
; i
++){
104 if(pull(buf
,4)<0) return -1;
107 if(pull(buf
,4)<0) return -1;
108 int chunk_size
= bytes2int(buf
);
111 int end_of_track
= 0;
112 int last_type
= 0x80;
115 int delta
= get_delta(pull
);
116 if(delta
< 0) return -1;
120 if(pull(buf
,1)<0) return -1;
121 int type
= buf
[0] & 0xf0;
122 if(type
>= 0x80 && type
<= 0xe0){//normal event
124 int chan
= buf
[0] & 0x0f;
126 if(pull(buf
,2)<0) return -1;
130 orgux_seq_append(S
,tick
,type
,chan
,val1
,val2
);
132 else if(type
< 0x80){//running status
134 if(pull(buf
,1)<0) return -1;
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;
143 int len
= get_delta(pull
);
144 if(len
< 0) return -1;
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;