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