]> git.lizzy.rs Git - plan9front.git/blob - sys/src/games/md/ym.c
devcons: fix permissions for reboot and sysstat
[plan9front.git] / sys / src / games / md / ym.c
1 #include <u.h>
2 #include <libc.h>
3 #include <thread.h>
4 #include "../eui.h"
5 #include "dat.h"
6 #include "fns.h"
7
8 u8int ym[512];
9 enum {
10         MODE = 0x27,
11         FDIV = 1048576 * 2 * 144,
12 };
13
14 #define min(a, b) ((a)<=(b)?(a):(b))
15
16 typedef struct oper oper;
17 typedef struct fm fm;
18
19 struct oper {
20         enum {OFF, ATTACK, DECAY, SUSTAIN, RELEASE} st;
21         u8int *r;
22         int env;
23         u8int ar, sr, dr, rs, rr, mult;
24         u16int tl, sl;
25         u8int keyon, keyoff, rate;
26         int det;
27         u8int kc;
28         u32int phi, amp, dp;
29         int val, val0;
30 };
31
32 struct fm {
33         oper op[4];
34         u8int st, alg, en, fbs;
35         float samp;
36 } fms[6];
37 u8int ymstat;
38 static u32int cyc;
39 static u16int tima;
40 static u8int timb;
41
42 static short sbuf[2 * 2000], *sbufp;
43 static int fd;
44 static int sint[256], expt[256];
45
46 static void
47 timers(void)
48 {
49         u8int m;
50         static u8int bdiv;
51
52         m = ym[0x27];
53         if((m & 1) != 0){
54                 tima = (tima + 1) & 0x3ff;
55                 if(tima == 0 && (m & 4) != 0){
56                         ymstat |= 1;
57                         tima = ym[0x24] | ym[0x25] << 8 & 0x300;
58                 }
59         }
60         if(++bdiv == 8){
61                 bdiv = 0;
62                 if((m & 2) != 0){
63                         timb++;
64                         if(timb == 0 && (m & 8) != 0){
65                                 ymstat |= 2;
66                                 timb = ym[0x26];
67                         }
68                 }
69         }
70 }
71
72 static void
73 calcfreq(int n)
74 {
75         int i, fr;
76         fm *f;
77         oper *p;
78         uchar *r;
79         static u8int det[4][32] = {
80                 {0},
81                 {0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2,
82                  2, 3, 3, 3, 4, 4, 4, 5, 5, 6, 6, 7, 8, 8, 8, 8},
83                 {1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5,
84                  5, 6, 6, 7, 8, 8, 9,10,11,12,13,14,16,16,16,16},
85                 {2, 2, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 6, 6, 7,
86                  8, 8, 9,10,11,12,13,14,16,17,19,20,22,22,22,22}
87         };              
88         
89         r = ym;
90         f = &fms[n];
91         if(n >= 3){
92                 n -= 3;
93                 r += 0x100;
94         }
95         fr = r[0xa0 + n] | r[0xa4 + n] << 8 & 0x3f00;
96         for(i = 0; i < 3; i++){
97                 p = &f->op[i];
98                 if(n == 2 && (ym[MODE] & 0xc0) == 0x40 && i != 0)
99                         fr = r[0xa7+i] | r[0xab+i] << 8 & 0x3f00;
100                 p->kc = fr >> 9 & 0x1e;
101                 if((fr & 0x780) >= 0x380 && (fr & 0x780) != 0x400)
102                         p->kc |= 1;
103                 p->dp = ((fr & 0x7ff) << (fr >> 11)) >> 1;
104                 if((p->det & 4) != 0)
105                         p->dp -= det[p->det & 3][p->kc];
106                 else
107                         p->dp += det[p->det][p->kc];
108                 if(p->mult != 0)
109                         p->dp = (p->dp & 0x1ffff) * p->mult;
110                 else
111                         p->dp = (u16int)(p->dp >> 1);
112                 
113         }
114 }
115
116 void
117 ymwrite(u8int a, u8int v, u8int c)
118 {
119         int ch, i;
120         oper *p;
121         fm *f;
122
123         ym[c ? a|0x100 : a] = v;
124         if(a >= 0x30 && a < 0xa0){
125                 ch = a & 3;
126                 if(ch == 3)
127                         return;
128                 ch += c;
129                 f = &fms[ch];
130                 i = a >> 3 & 1 | a >> 1 & 2;
131                 p = &f->op[i];
132                 switch(a & 0xf0){
133                 case 0x30:
134                         p->mult = v & 0x0f;
135                         p->det = v >> 4 & 7;
136                         calcfreq(ch);
137                         break;
138                 case 0x40:
139                         p->tl = v << 3 & 0x3f8;
140                         break;
141                 case 0x50:
142                         p->ar = v << 1 & 0x3e;
143                         p->rs = 3 - (v >> 6);
144                         break;
145                 case 0x60:
146                         p->dr = v << 1 & 0x3e;
147                         break;
148                 case 0x70:
149                         p->sr = v << 1 & 0x3e;
150                         break;
151                 case 0x80:
152                         p->sl = v << 2 & 0x3c0;
153                         p->rr = v << 2 & 0x3c | 0x02;
154                         break;
155                 };
156         }else{
157                 ch = c + (a & 3);
158                 switch(a){
159                 case MODE:
160                         if((v & 0x10) != 0)
161                                 ymstat &= ~2;
162                         if((v & 0x20) != 0)
163                                 ymstat &= ~1;
164                         calcfreq(2);
165                         calcfreq(5);
166                         break;
167                 case 0x28:
168                         ch = v & 3;
169                         if(ch == 3)
170                                 break;
171                         if((v & 4) != 0)
172                                 ch += 3;
173                         f = &fms[ch];
174                         for(i = 0; i < 4; i++){
175                                 p = &f->op[i];
176                                 if((v & 1<<4+i) != 0){
177                                         if(p->st == OFF || p->st == RELEASE)
178                                                 p->keyon++;
179                                 }else
180                                         if(p->st != OFF)
181                                                 p->keyoff++;
182                         }
183                         break;
184                 case 0xa0: case 0xa1: case 0xa2:
185                 case 0xa4: case 0xa5: case 0xa6:
186                         calcfreq(ch);
187                         break;
188                 case 0xa8: case 0xa9: case 0xaa:
189                 case 0xac: case 0xad: case 0xae:
190                         calcfreq((a & 0x100) != 0 ? 5 : 2);
191                         break;
192                 case 0xb0: case 0xb1: case 0xb2:
193                         fms[ch].alg = v & 7;
194                         fms[ch].fbs = 7 - (v >> 3 & 7);
195                         break;
196                 case 0xb4: case 0xb5: case 0xb6:
197                         fms[ch].en = v;
198                         break;
199                 }
200         }
201 }
202
203 static void
204 tables(void)
205 {
206         int i;
207         double x;
208         
209         for(i = 0; i < 256; i++){
210                 x = sin(((i << 1) + 1) * PI / 1024);
211                 x = -log(x)/log(2);
212                 sint[i] = x * 256 + 0.5;
213         }
214         for(i = 0; i < 256; i++){
215                 x = pow(2, -(i+1)/256.0);
216                 expt[i] = x * 2048 + 0.5;
217         }
218 }
219
220 void
221 ymreset(void)
222 {
223         int i, j;
224         
225         for(i = 0; i < 6; i++){
226                 fms[i].en = 0xc0;
227                 for(j = 0; j < 4; j++)
228                         fms[i].op[j].rs = 3;
229         }
230         tables();
231 }
232
233 static u8int
234 rate(oper *p, u8int r)
235 {
236         if(r == 0)
237                 return 0;
238         r += p->kc >> p->rs;
239         if(r > 63)
240                 return 63;
241         return r;
242 }
243
244 static void
245 env(oper *p)
246 {
247         int v, sh, ai;
248         static u8int ait[64][8] = {
249                 {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,1,0,1,0,1,0,1}, {0,1,0,1,0,1,0,1},
250                 {0,1,0,1,0,1,0,1}, {0,1,0,1,0,1,0,1}, {0,1,1,1,0,1,1,1}, {0,1,1,1,0,1,1,1},
251                 {0,1,0,1,0,1,0,1}, {0,1,0,1,1,1,0,1}, {0,1,1,1,0,1,1,1}, {0,1,1,1,1,1,1,1},
252                 {0,1,0,1,0,1,0,1}, {0,1,0,1,1,1,0,1}, {0,1,1,1,0,1,1,1}, {0,1,1,1,1,1,1,1},
253                 {0,1,0,1,0,1,0,1}, {0,1,0,1,1,1,0,1}, {0,1,1,1,0,1,1,1}, {0,1,1,1,1,1,1,1},
254                 {0,1,0,1,0,1,0,1}, {0,1,0,1,1,1,0,1}, {0,1,1,1,0,1,1,1}, {0,1,1,1,1,1,1,1},
255                 {0,1,0,1,0,1,0,1}, {0,1,0,1,1,1,0,1}, {0,1,1,1,0,1,1,1}, {0,1,1,1,1,1,1,1},
256                 {0,1,0,1,0,1,0,1}, {0,1,0,1,1,1,0,1}, {0,1,1,1,0,1,1,1}, {0,1,1,1,1,1,1,1},
257                 {0,1,0,1,0,1,0,1}, {0,1,0,1,1,1,0,1}, {0,1,1,1,0,1,1,1}, {0,1,1,1,1,1,1,1},
258                 {0,1,0,1,0,1,0,1}, {0,1,0,1,1,1,0,1}, {0,1,1,1,0,1,1,1}, {0,1,1,1,1,1,1,1},
259                 {0,1,0,1,0,1,0,1}, {0,1,0,1,1,1,0,1}, {0,1,1,1,0,1,1,1}, {0,1,1,1,1,1,1,1},
260                 {0,1,0,1,0,1,0,1}, {0,1,0,1,1,1,0,1}, {0,1,1,1,0,1,1,1}, {0,1,1,1,1,1,1,1},
261                 {1,1,1,1,1,1,1,1}, {1,1,1,2,1,1,1,2}, {1,2,1,2,1,2,1,2}, {1,2,2,2,1,2,2,2},
262                 {2,2,2,2,2,2,2,2}, {2,2,2,4,2,2,2,4}, {2,4,2,4,2,4,2,4}, {2,4,4,4,2,4,4,4},
263                 {4,4,4,4,4,4,4,4}, {4,4,4,8,4,4,4,8}, {4,8,4,8,4,8,4,8}, {4,8,8,8,4,8,8,8},
264                 {8,8,8,8,8,8,8,8}, {8,8,8,8,8,8,8,8}, {8,8,8,8,8,8,8,8}, {8,8,8,8,8,8,8,8},
265         };
266         if(p->keyon > 0){
267                 p->st = ATTACK;
268                 p->rate = rate(p, p->ar);
269                 p->env = 0;
270                 p->keyon = 0;
271         }else if(p->keyoff > 0){
272                 p->st = RELEASE;
273                 p->rate = rate(p, p->rr);
274                 p->keyoff = 0;
275         }
276         if(p->rate > 0){
277                 sh = p->rate >> 2;
278                 if(sh < 11)
279                         sh = 11 - sh;
280                 else
281                         sh = 0;
282                 if((cyc & (1 << sh) - 1) == 0){
283                         ai = ait[p->rate][(cyc >> sh) & 7];
284                         switch(p->st){
285                         case ATTACK:
286                                 p->env += ai * ((1024 - p->env >> 4) + 1);
287                                 if(p->env >= 1024){
288                                         p->env = 0;
289                                         p->st = DECAY;
290                                         p->rate = rate(p, p->dr);
291                                 }
292                                 break;
293                         case DECAY:
294                                 p->env += ai;
295                                 if(p->env >= 1024)
296                                         p->env = 1023;
297                                 if(p->env >= p->sl){
298                                         p->st = SUSTAIN;
299                                         p->rate = rate(p, p->sr);
300                                 }
301                                 break;
302                         case SUSTAIN:
303                         case RELEASE:
304                                 p->env += ai;
305                                 if(p->env >= 1024){
306                                         p->env = 1023;
307                                         p->st = OFF;
308                                         p->rate = 0;
309                                 }
310                                 break;
311                         }
312                 }
313         }
314         if(p->st == OFF){
315                 p->amp = 1023;
316                 return;
317         }
318         v = p->env;
319         if(p->st == ATTACK)
320                 v ^= 1023;
321         v += p->tl;
322         if(v > 1023)
323                 p->amp = 1023;
324         else
325                 p->amp = v;
326 }
327
328 static void
329 opr(oper *p, int inp)
330 {
331         int v, x, r;
332
333         p->phi += p->dp;
334         v = (p->phi >> 10) + inp;
335         if((v & 0x100) != 0)
336                 v ^= 0xff;
337         x = sint[v & 0xff] + (p->amp << 2);
338         r = expt[x & 0xff] << 2 >> (x >> 8);
339         p->val0 = p->val;
340         if((v & 0x200) != 0)
341                 p->val = -r;
342         else
343                 p->val = r;
344 }
345
346 void
347 ymstep(void)
348 {
349         static int ymch, ymop, ymcyc;
350         fm *f;
351         oper *p;
352         int x;
353         
354         f = fms + ymch;
355         p = f->op + ymop;
356         x = 0;
357         if(ymop == 0){
358                 if(f->fbs != 7)
359                         x = p->val + p->val0 >> f->fbs + 2;
360         }else{
361                 switch(f->alg << 4 | ymop){
362                 default: x = p[-1].val; break;
363                 case 0x11: break;
364                 case 0x12: x = f->op[0].val + f->op[1].val; break;
365                 case 0x21: break;
366                 case 0x23: x = f->op[0].val + f->op[2].val; break;
367                 case 0x32: break;
368                 case 0x33: x = f->op[1].val + f->op[2].val; break;
369                 case 0x42: break;
370                 case 0x52: case 0x53: x = f->op[0].val; break;
371                 case 0x62: case 0x63: break;
372                 case 0x71: case 0x72: case 0x73: break;
373                 }
374                 x >>= 1;
375         }
376         if(ymcyc == 0)
377                 env(p);
378         opr(p, x);
379         if(ymop == 3){
380                 switch(f->alg){
381                 default: x = p->val >> 5; break;
382                 case 4: x = (f->op[1].val >> 5) + (p->val >> 5); break;
383                 case 5: case 6: x = (f->op[1].val >> 5) + (f->op[2].val >> 5) + (p->val >> 5); break;
384                 case 7: x = (f->op[0].val >> 5) + (f->op[1].val >> 5) + (f->op[2].val >> 5) + (p->val >> 5); break;
385                 }
386                 if(x > 256) x = 256;
387                 if(x < -256) x = -256;
388                 f->samp = x / 256.0;
389                 if(++ymch == 6){
390                         ymch = 0;
391                         if(++ymcyc == 3){
392                                 cyc++;
393                                 ymcyc = 0;
394                                 timers();
395                         }
396                 }
397                 ymop = 0;
398         }else
399                 ymop++;
400 }
401
402 void
403 audiosample(void)
404 {
405         int i;
406         u8int x;
407         float v, vl, vr;
408         
409         if(sbufp == nil)
410                 return;
411         vl = vr = 0;
412         for(i = 0; i < 6; i++){
413                 if(i == 5 && (ym[0x2b] & 0x80) != 0)
414                         v = ym[0x2a] / 255.0;
415                 else
416                         v = fms[i].samp;
417                 x = fms[i].en;
418                 if((x & 0x80) != 0)
419                         vl += v;
420                 if((x & 0x40) != 0)
421                         vr += v;
422         }
423         if(sbufp < sbuf + nelem(sbuf) - 1){
424                 *sbufp++ = vl * 5000;
425                 *sbufp++ = vr * 5000;
426         }
427 }
428
429 int
430 audioout(void)
431 {
432         int rc;
433
434         if(sbufp == nil)
435                 return -1;
436         if(sbufp == sbuf)
437                 return 0;
438         rc = warp10 ? (sbufp - sbuf) * 2 : write(fd, sbuf, (sbufp - sbuf) * 2);
439         if(rc > 0)
440                 sbufp -= (rc+1)/2;
441         if(sbufp < sbuf)
442                 sbufp = sbuf;
443         return 0;
444 }
445
446 void
447 initaudio(void)
448 {
449         fd = open("/dev/audio", OWRITE);
450         if(fd < 0)
451                 return;
452         sbufp = sbuf;
453 }