]> git.lizzy.rs Git - plan9front.git/blob - sys/src/games/mus.c
add games/mus midi converter (by qu7uux)
[plan9front.git] / sys / src / games / mus.c
1 #include <u.h>
2 #include <libc.h>
3
4 typedef struct Trk Trk;
5 typedef struct Ch Ch;
6
7 struct Ch{
8         uchar n[128];
9         uchar pitch;
10         uchar ctl[10];
11 };
12 struct Trk{
13         u32int len;
14         uchar *dat;
15         uchar *p;
16         uchar *end;
17         Ch c[16];
18         long delay;
19         int done;
20 };
21 Trk t;
22 uchar *mcmd, *mp, *me;
23 int fd;
24
25 #define PBIT16(p,v)     (p)[0]=(v);(p)[1]=(v)>>8
26 #define BBIT32(p,v)     (p)[3]=(v);(p)[2]=(v)>>8;(p)[1]=(v)>>16;(p)[0]=(v)>>24
27
28 void
29 eread(int fd, void *u, long n)
30 {
31         if(readn(fd, u, n) != n)
32                 sysfatal("readn: %r");
33 }
34
35 uchar
36 r8(void)
37 {
38         return *t.p++;
39 }
40
41 u32int
42 delay(void)
43 {
44         u32int t;
45         uchar v;
46
47         t = 0;
48         do{
49                 v = r8();
50                 t = t << 7 | v & 0x7f;
51                 *mp++ = v;
52         }while(v & 0x80);
53         return t;
54 }
55
56 void
57 putcmd(uchar *cmd, int n)
58 {
59         if(mp + n >= me){
60                 me += 8192;
61                 mcmd = realloc(mcmd, me - mcmd);
62                 if(mcmd == nil)
63                         sysfatal("realloc: %r");
64         }
65         memcpy(mp, cmd, n);
66         mp += n;
67 }
68
69 void
70 ev(void)
71 {
72         uchar e, v;
73         Ch *c;
74         uchar cmd[3], *p;
75
76         e = r8();
77         c = &t.c[e & 15];
78         p = cmd;
79         switch(e >> 4 & 7){
80         case 0:
81                 v = r8() & 0x7f;
82                 c->n[v] = 0;
83                 *p++ = e | 0x80;
84                 *p++ = v;
85                 *p++ = 0x40;
86                 break;
87         case 1:
88                 v = r8();
89                 if(v & 0x80){
90                         c->n[v] = r8() & 0x7f;
91                         c->ctl[3] = c->n[v];
92                 }else
93                         c->n[v] = c->ctl[3];
94                 *p++ = e | 0x80;
95                 *p++ = v & 0x7f;
96                 *p++ = c->n[v];
97                 break;
98         case 2:
99                 c->pitch = r8();
100                 *p++ = e | 0xc0;
101                 PBIT16(p, c->pitch << 7 & 0x7f7f);
102                 p += 2;
103                 break;
104         case 3:
105                 v = r8();
106                 *p++ = 0xb | e & 15;
107                 switch(v){
108                 case 10:
109                         for(v=0; v<128; v++)
110                                 c->n[v] = 0;
111                         *p++ = 0x78;
112                         break;
113                 case 11:
114                         for(v=0; v<128; v++)
115                                 c->n[v] = 0;
116                         *p++ = 0x7b;
117                         break;
118                 case 12:
119                         *p++ = 0x7e;
120                         break;
121                 case 13:
122                         *p++ = 0x7f;
123                         break;
124                 case 14:
125                         memset(c->n, 0, sizeof c->n);
126                         memset(c->ctl, 0, sizeof c->ctl);
127                         c->ctl[3] = 0x7f;
128                         c->ctl[4] = 64;
129                         if((e & 15) == 15)
130                                 c->pitch = 60;
131                         else
132                                 c->pitch = 128;
133                         *p++ = 0x79;
134                         break;
135                 default:
136                         sysfatal("unknown system event %ux\n", v);
137                 }
138                 *p++ = 0;
139                 break;
140         case 4:
141                 v = r8();
142                 if(v > 9)
143                         sysfatal("unknown controller %ux\n", v);
144                 c->ctl[v] = r8() & 0x7f;
145                 *p++ = 0xb0 | e & 15;
146                 switch(v){
147                 case 1: *p++ = 0x00; break;
148                 case 2: *p++ = 0x01; break;
149                 case 3: *p++ = 0x07; break;
150                 case 4: *p++ = 0x0a; break;
151                 case 5: *p++ = 0x0b; break;
152                 case 6: *p++ = 0x5b; break;
153                 case 7: *p++ = 0x5d; break;
154                 case 8: *p++ = 0x40; break;
155                 case 9: *p++ = 0x43; break;
156                 }
157                 *p++ = c->ctl[v];
158                 if(v == 0)
159                         cmd[0] += 0x10;
160                 break;
161         case 6:
162                 *p++ = 0xff;
163                 *p++ = 0x2f;
164                 e = 0;
165                 t.done++;
166                 break;
167         default:
168                 sysfatal("unknown event %ux\n", e >> 4 & 7);
169         }
170         if((e & 15) == 9)
171                 cmd[0] += 1;
172         if((e & 15) == 15)
173                 cmd[0] &= ~6;
174         putcmd(cmd, p-cmd);
175         t.delay = 0;
176         if(e & 0x80)
177                 t.delay = delay();
178         else
179                 *mp++ = 0;
180 }
181
182 void
183 reset(void)
184 {
185         Ch *c;
186
187         c = t.c;
188         while(c < t.c + nelem(t.c)){
189                 c->pitch = 128;
190                 c->ctl[3] = 0x7f;
191                 c->ctl[4] = 64;
192                 c++;
193         }
194         t.c[15].pitch = 60;
195         mcmd = mallocz(t.len * 2, 1);
196         if(mcmd == nil)
197                 sysfatal("mallocz: %r");
198         mp = mcmd;
199         me = mcmd + t.len * 2;
200 }
201
202 void
203 barf(void)
204 {
205         static uchar hdr[] = {
206                 'M', 'T', 'h', 'd',
207                 0x00, 0x00, 0x00, 0x06,
208                 0x00, 0x00,
209                 0x00, 0x01,
210                 0x01, 0x01,
211                 'M', 'T', 'r', 'k',
212                 0x00, 0x00, 0x00, 0x00,
213                 0x00, 0xb0, 0x07, 0x7f,
214                 0x00, 0xb1, 0x07, 0x7f,
215                 0x00, 0xb2, 0x07, 0x7f,
216                 0x00, 0xb3, 0x07, 0x7f,
217                 0x00, 0xb4, 0x07, 0x7f,
218                 0x00, 0xb5, 0x07, 0x7f,
219                 0x00, 0xb6, 0x07, 0x7f,
220                 0x00, 0xb7, 0x07, 0x7f,
221                 0x00, 0xb8, 0x07, 0x7f,
222                 0x00, 0xb9, 0x07, 0x7f,
223                 0x00, 0xba, 0x07, 0x7f,
224                 0x00, 0xff, 0x51, 0x03, 0x1b, 0x8a, 0x06,
225                 0x00
226         };
227         int n;
228
229         n = sizeof(hdr) - 22 + mp - mcmd;
230         BBIT32(hdr + 18, n);
231         write(1, hdr, sizeof hdr);
232         write(1, mcmd, mp - mcmd);
233 }
234
235 void
236 main(int argc, char *argv[])
237 {
238         int n, ofs;
239         uchar s[8], b[1024];
240
241         if(argc > 1){
242                 fd = open(argv[1], OREAD);
243                 if(fd < 0)
244                         sysfatal("open: %r");
245         }
246         eread(fd, s, sizeof s);
247         if(memcmp(s, "MUS\x1a", 4) != 0)
248                 sysfatal("invalid mus file: %r");
249         t.len = s[5] << 8 | s[4];
250         ofs = (s[7] << 8 | s[6]) - 8;
251         while(ofs > 0){
252                 n = ofs > sizeof b ? sizeof b : ofs;
253                 eread(fd, b, n);
254                 ofs -= n;
255         }
256         t.dat = malloc(t.len);
257         if(t.dat == nil)
258                 sysfatal("malloc: %r");
259         t.p = t.dat;
260         t.end = t.dat + t.len;
261         eread(fd, t.dat, t.len);
262         reset();
263         while(!t.done && t.p < t.end)
264                 ev();
265         barf();
266         exits(nil);
267 }