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.
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
){
51 src
->read(buf
,W
,src
->ud
);
54 src
->read(buf
,C
,src
->ud
);
57 octet
read_one(orgux_reader
* src
){
59 src
->read(byte
,1,src
->ud
);
63 int get_delta(orgux_reader
* src
){
64 octet a
= read_one(src
);
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
){
81 char string
[STRING_MAX
];
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]);
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]);
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
);
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
++){
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]);
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
);
118 int end_of_track
= 0;
119 int last_type
= 0x80;
122 int delta
= get_delta(src
);
123 printf("delta = %d\n",delta
);
124 if(delta
< 0) return -1;
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
132 int chan
= buf
[0] & 0x0f;
134 if(src
->read(buf
,2,src
->ud
)<0) return -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
142 if(src
->read(buf
,1,src
->ud
)<0) return -1;
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;
150 printf("meta event\n");
151 int len
= get_delta(src
);
152 if(len
< 0) return -1;
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];
160 case 0x58: printf("time sig\n");/*time signature*/
161 if(src
->read(buf
,4,src
->ud
)<0) return -1;
164 case 0x01: printf("text\n");/*text*/
165 if(len
>= STRING_MAX
){skip_ahead(src
, len
);}
167 if(src
->read(string
,len
,src
->ud
)<0) return -1;
169 if(strncmp(string
,"LoopStart",len
)==0){
172 else if(strncmp(string
,"LoopEnd",len
)==0){
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;
195 //orgux_set_loop_positions(S, loopstart, loopend);
202 int read_file(unsigned char* buf
, int count
, void* ud
){
204 int n
= fread(buf
, 1, count
, f
);
205 if(n
< count
){return -1;}
209 int orgux_load_smf(orgux_state
* S
, char* filename
){
210 FILE* f
= fopen(filename
, "r");
214 src
.read
= read_file
;
215 printf("loading midi file\n");
216 if(orgux_load_song(S
, &src
) < 0){fclose(f
); return -1;}