OSDN Git Service

[VM][General] Merge Upstream 2017-12-15.
[csp-qt/common_source_project-fm7.git] / source / src / vm / fmgen / opm.cpp
1 // ---------------------------------------------------------------------------
2 //      OPM interface
3 //      Copyright (C) cisc 1998, 2003.
4 // ---------------------------------------------------------------------------
5 //      $Id: opm.cpp,v 1.26 2003/08/25 13:53:08 cisc Exp $
6
7 #include "headers.h"
8 #include "misc.h"
9 #include "opm.h"
10 #include "fmgeninl.h"
11
12 #include "../../fileio.h"
13
14 //#define LOGNAME "opm"
15
16 namespace FM
17 {
18
19 int OPM::amtable[4][OPM_LFOENTS] = { -1, };
20 int OPM::pmtable[4][OPM_LFOENTS];
21
22 // ---------------------------------------------------------------------------
23 //      \8d\\92z
24 //
25 OPM::OPM()
26 {
27         lfo_count_ = 0;
28         lfo_count_prev_ = ~0;
29         BuildLFOTable();
30         for (int i=0; i<8; i++)
31         {
32                 ch[i].SetChip(&chip);
33                 ch[i].SetType(typeM);
34         }
35 }
36
37 // ---------------------------------------------------------------------------
38 //      \8f\89\8aú\89»
39 //
40 bool OPM::Init(uint c, uint rf, bool ip)
41 {
42         if (!SetRate(c, rf, ip))
43                 return false;
44         
45         Reset();
46
47         SetVolume(0, 0);
48         SetChannelMask(0);
49         return true;
50 }
51
52 // ---------------------------------------------------------------------------
53 //      \8dÄ\90Ý\92è
54 //
55 bool OPM::SetRate(uint c, uint r, bool)
56 {
57         clock = c;
58         pcmrate = r;
59         rate = r;
60
61         RebuildTimeTable();
62         
63         return true;
64 }
65
66 // ---------------------------------------------------------------------------
67 //      \83`\83\83\83\93\83l\83\8b\83}\83X\83N\82Ì\90Ý\92è
68 //
69 void OPM::SetChannelMask(uint mask)
70 {
71         for (int i=0; i<8; i++)
72                 ch[i].Mute(!!(mask & (1 << i)));
73 }
74
75 // ---------------------------------------------------------------------------
76 //      \83\8a\83Z\83b\83g
77 //
78 void OPM::Reset()
79 {
80         int i;
81         for (i=0x0; i<0x100; i++) SetReg(i, 0);
82         SetReg(0x19, 0x80);
83         Timer::Reset();
84         
85         status = 0;
86         interrupt = false;
87         noise = 12345;
88         noisecount = 0;
89         
90         for (i=0; i<8; i++)
91                 ch[i].Reset();
92 }
93
94 // ---------------------------------------------------------------------------
95 //      \8a\84\82è\8d\9e\82Ý\90M\8d\86\82Ì\8eæ\93¾
96 //
97 bool OPM::ReadIRQ()
98 {
99         return interrupt;
100 }
101
102 // ---------------------------------------------------------------------------
103 //      \90Ý\92è\82É\88Ë\91\82·\82é\83e\81[\83u\83\8b\82Ì\8dì\90¬
104 //
105 void OPM::RebuildTimeTable()
106 {
107         uint fmclock = clock / 64;
108
109         assert(fmclock < (0x80000000 >> FM_RATIOBITS));
110         rateratio = ((fmclock << FM_RATIOBITS) + rate/2) / rate;
111         SetTimerPrescaler(64);
112         
113 //      FM::MakeTimeTable(rateratio);
114         chip.SetRatio(rateratio);
115
116 //      lfo_diff_ = 
117
118
119 //      lfodcount = (16 + (lfofreq & 15)) << (lfofreq >> 4);
120 //      lfodcount = lfodcount * rateratio >> FM_RATIOBITS;
121 }
122
123 // ---------------------------------------------------------------------------
124 //      \83^\83C\83}\81[ A \94­\90\8e\9e\83C\83x\83\93\83g (CSM)
125 //
126 void OPM::TimerA()
127 {
128         if (regtc & 0x80)
129         {
130                 for (int i=0; i<8; i++)
131                 {
132                         ch[i].KeyControl(0);
133                         ch[i].KeyControl(0xf);
134                 }
135         }
136 }
137
138 // ---------------------------------------------------------------------------
139 //      \8a\84\82è\8d\9e\82Ý\90M\8d\86\82Ì\90Ý\92è
140 //
141 void OPM::Intr(bool value)
142 {
143         interrupt = value;
144 }
145
146 // ---------------------------------------------------------------------------
147 //      \89¹\97Ê\90Ý\92è
148 //
149 void OPM::SetVolume(int db_l, int db_r)
150 {
151         db_l = Min(db_l, 20);
152         db_r = Min(db_r, 20);
153         
154         if (db_l > -192)
155                 fmvolume_l = int(16384.0 * pow(10.0, db_l / 40.0));
156         else
157                 fmvolume_l = 0;
158         if (db_r > -192)
159                 fmvolume_r = int(16384.0 * pow(10.0, db_r / 40.0));
160         else
161                 fmvolume_r = 0;
162 }
163
164 // ---------------------------------------------------------------------------
165 //      \83X\83e\81[\83^\83X\83t\83\89\83O\90Ý\92è
166 //
167 void OPM::SetStatus(uint bits)
168 {
169         if (!(status & bits))
170         {
171                 status |= bits;
172                 Intr(true);
173         }
174 }
175
176 // ---------------------------------------------------------------------------
177 //      \83X\83e\81[\83^\83X\83t\83\89\83O\89ð\8f\9c
178 //
179 void OPM::ResetStatus(uint bits)
180 {
181         if (status & bits)
182         {
183                 status &= ~bits;
184                 if (!status)
185                         Intr(false);
186         }
187 }
188
189 // ---------------------------------------------------------------------------
190 //      \83\8c\83W\83X\83^\83A\83\8c\83C\82É\83f\81[\83^\82ð\90Ý\92è
191 //
192 void OPM::SetReg(uint addr, uint data)
193 {
194         if (addr >= 0x100)
195                 return;
196         
197         int c = addr & 7;
198         switch (addr & 0xff)
199         {
200         case 0x01:                                      // TEST (lfo restart)
201                 if (data & 2)
202                 {
203                         lfo_count_ = 0; 
204                         lfo_count_prev_ = ~0;
205                 }
206                 reg01 = data;
207                 break;
208                 
209         case 0x08:                                      // KEYON
210                 if (!(regtc & 0x80))
211                         ch[data & 7].KeyControl(data >> 3);
212                 else
213                 {
214                         c = data & 7;
215                         if (!(data & 0x08)) ch[c].op[0].KeyOff();
216                         if (!(data & 0x10)) ch[c].op[1].KeyOff();
217                         if (!(data & 0x20)) ch[c].op[2].KeyOff();
218                         if (!(data & 0x40)) ch[c].op[3].KeyOff();
219                 }
220                 break;
221                 
222         case 0x10: case 0x11:           // CLKA1, CLKA2
223                 SetTimerA(addr, data);
224                 break;
225
226         case 0x12:                                      // CLKB
227                 SetTimerB(data);
228                 break;
229
230         case 0x14:                                      // CSM, TIMER
231                 SetTimerControl(data);
232                 break;
233         
234         case 0x18:                                      // LFRQ(lfo freq)
235                 lfofreq = data;
236
237                 assert(16-4-FM_RATIOBITS >= 0);
238                 lfo_count_diff_ = 
239                         rateratio 
240                         * ((16 + (lfofreq & 15)) << (16 - 4 - FM_RATIOBITS)) 
241                         / (1 << (15 - (lfofreq >> 4)));
242                 
243                 break;
244                 
245         case 0x19:                                      // PMD/AMD
246                 (data & 0x80 ? pmd : amd) = data & 0x7f;
247                 break;
248
249         case 0x1b:                                      // CT, W(lfo waveform)
250                 lfowaveform = data & 3;
251                 break;
252
253                                                                 // RL, FB, Connect
254         case 0x20: case 0x21: case 0x22: case 0x23:
255         case 0x24: case 0x25: case 0x26: case 0x27:
256                 ch[c].SetFB((data >> 3) & 7);
257                 ch[c].SetAlgorithm(data & 7);
258                 pan[c] = (data >> 6) & 3;
259                 break;
260                 
261                                                                 // KC
262         case 0x28: case 0x29: case 0x2a: case 0x2b:
263         case 0x2c: case 0x2d: case 0x2e: case 0x2f:
264                 kc[c] = data;
265                 ch[c].SetKCKF(kc[c], kf[c]);
266                 break;
267                 
268                                                                 // KF
269         case 0x30: case 0x31: case 0x32: case 0x33:
270         case 0x34: case 0x35: case 0x36: case 0x37:
271                 kf[c] = data >> 2;
272                 ch[c].SetKCKF(kc[c], kf[c]);
273                 break;
274                 
275                                                                 // PMS, AMS
276         case 0x38: case 0x39: case 0x3a: case 0x3b:
277         case 0x3c: case 0x3d: case 0x3e: case 0x3f:
278                 ch[c].SetMS((data << 4) | (data >> 4));
279                 break;
280         
281         case 0x0f:                      // NE/NFRQ (noise)
282                 noisedelta = data;
283                 noisecount = 0;
284                 break;
285                 
286         default:
287                 if (addr >= 0x40)
288                         OPM::SetParameter(addr, data);
289                 break;
290         }
291 }
292
293
294 // ---------------------------------------------------------------------------
295 //      \83p\83\89\83\81\81[\83^\83Z\83b\83g
296 //
297 void OPM::SetParameter(uint addr, uint data)
298 {
299         const static uint8 sltable[16] = 
300         {
301                   0,   4,   8,  12,  16,  20,  24,  28,
302                  32,  36,  40,  44,  48,  52,  56, 124,
303         };
304         const static uint8 slottable[4] = { 0, 2, 1, 3 };
305
306         uint slot = slottable[(addr >> 3) & 3];
307         Operator* op = &ch[addr & 7].op[slot];
308
309         switch ((addr >> 5) & 7)
310         {
311         case 2: // 40-5F DT1/MULTI
312                 op->SetDT((data >> 4) & 0x07);
313                 op->SetMULTI(data & 0x0f);
314                 break;
315                 
316         case 3: // 60-7F TL
317                 op->SetTL(data & 0x7f, (regtc & 0x80) != 0);
318                 break;
319                 
320         case 4: // 80-9F KS/AR
321                 op->SetKS((data >> 6) & 3);
322                 op->SetAR((data & 0x1f) * 2);
323                 break;
324                 
325         case 5: // A0-BF DR/AMON(D1R/AMS-EN)
326                 op->SetDR((data & 0x1f) * 2);
327                 op->SetAMON((data & 0x80) != 0);
328                 break;
329                 
330         case 6: // C0-DF SR(D2R), DT2
331                 op->SetSR((data & 0x1f) * 2);
332                 op->SetDT2((data >> 6) & 3);
333                 break;
334                 
335         case 7: // E0-FF SL(D1L)/RR
336                 op->SetSL(sltable[(data >> 4) & 15]);
337                 op->SetRR((data & 0x0f) * 4 + 2);
338                 break;
339         }
340 }
341
342 // ---------------------------------------------------------------------------
343 //
344 //
345 void OPM::BuildLFOTable()
346 {
347         if (amtable[0][0] != -1)
348                 return;
349
350         for (int type=0; type<4; type++)
351         {
352                 int r = 0;
353                 for (int c=0; c<OPM_LFOENTS; c++)
354                 {
355                         int a, p;
356                         
357                         switch (type)
358                         {
359                         case 0:
360                                 p = (((c + 0x100) & 0x1ff) / 2) - 0x80;
361                                 a = 0xff - c / 2;
362                                 break;
363
364                         case 1:
365                                 a = c < 0x100 ? 0xff : 0;
366                                 p = c < 0x100 ? 0x7f : -0x80;
367                                 break;
368
369                         case 2:
370                                 p = (c + 0x80) & 0x1ff;
371                                 p = p < 0x100 ? p - 0x80 : 0x17f - p;
372                                 a = c < 0x100 ? 0xff - c : c - 0x100;
373                                 break;
374
375                         case 3:
376                                 if (!(c & 3))
377                                         r = (rand() / 17) & 0xff;
378                                 a = r;
379                                 p = r - 0x80;
380                                 break;
381                         }
382
383                         amtable[type][c] = a;
384                         pmtable[type][c] = -p-1;
385 //                      printf("%d ", p);
386                 }
387         }
388 }
389
390 // ---------------------------------------------------------------------------
391
392 inline void OPM::LFO()
393 {
394         if (lfowaveform != 3)
395         {
396 //              if ((lfo_count_ ^ lfo_count_prev_) & ~((1 << 15) - 1))
397                 {
398                         int c = (lfo_count_ >> 15) & 0x1fe;
399 //      fprintf(stderr, "%.8x %.2x\n", lfo_count_, c);
400                         chip.SetPML(pmtable[lfowaveform][c] * pmd / 128 + 0x80);
401                         chip.SetAML(amtable[lfowaveform][c] * amd / 128);
402                 }
403         }
404         else
405         {
406                 if ((lfo_count_ ^ lfo_count_prev_) & ~((1 << 17) - 1))
407                 {
408                         int c = (rand() / 17) & 0xff;
409                         chip.SetPML((c - 0x80) * pmd / 128 + 0x80);
410                         chip.SetAML(c * amd / 128);
411                 }
412         }
413         lfo_count_prev_ = lfo_count_;
414         lfo_step_++;
415         if ((lfo_step_ & 7) == 0)
416         {
417                 lfo_count_ += lfo_count_diff_;
418         }
419 }
420
421 inline uint OPM::Noise()
422 {
423         noisecount += 2 * rateratio;
424         if (noisecount >= (32 << FM_RATIOBITS))
425         {
426                 int n = 32 - (noisedelta & 0x1f);
427                 if (n == 1)
428                         n = 2;
429
430                 noisecount = noisecount - (n << FM_RATIOBITS);
431                 if ((noisedelta & 0x1f) == 0x1f) 
432                         noisecount -= FM_RATIOBITS;
433                 noise = (noise >> 1) ^ (noise & 1 ? 0x8408 : 0);
434         }
435         return noise;
436 }
437
438 // ---------------------------------------------------------------------------
439 //      \8d\87\90¬\82Ì\88ê\95\94
440 //
441 inline void OPM::MixSub(int activech, ISample** idest)
442 {
443         if (activech & 0x4000) (*idest[0]  = ch[0].Calc());
444         if (activech & 0x1000) (*idest[1] += ch[1].Calc());
445         if (activech & 0x0400) (*idest[2] += ch[2].Calc());
446         if (activech & 0x0100) (*idest[3] += ch[3].Calc());
447         if (activech & 0x0040) (*idest[4] += ch[4].Calc());
448         if (activech & 0x0010) (*idest[5] += ch[5].Calc());
449         if (activech & 0x0004) (*idest[6] += ch[6].Calc());
450         if (activech & 0x0001)
451         {
452                 if (noisedelta & 0x80)
453                         *idest[7] += ch[7].CalcN(Noise());
454                 else
455                         *idest[7] += ch[7].Calc();
456         }
457 }
458
459 inline void OPM::MixSubL(int activech, ISample** idest)
460 {
461         if (activech & 0x4000) (*idest[0]  = ch[0].CalcL());
462         if (activech & 0x1000) (*idest[1] += ch[1].CalcL());
463         if (activech & 0x0400) (*idest[2] += ch[2].CalcL());
464         if (activech & 0x0100) (*idest[3] += ch[3].CalcL());
465         if (activech & 0x0040) (*idest[4] += ch[4].CalcL());
466         if (activech & 0x0010) (*idest[5] += ch[5].CalcL());
467         if (activech & 0x0004) (*idest[6] += ch[6].CalcL());
468         if (activech & 0x0001)
469         {
470                 if (noisedelta & 0x80)
471                         *idest[7] += ch[7].CalcLN(Noise());
472                 else
473                         *idest[7] += ch[7].CalcL();
474         }
475 }
476
477
478 // ---------------------------------------------------------------------------
479 //      \8d\87\90¬ (stereo)
480 //
481 void OPM::Mix(Sample* buffer, int nsamples)
482 {
483 #define IStoSampleL(s)  ((Limit(s, 0xffff, -0x10000) * fmvolume_l) >> 14)
484 #define IStoSampleR(s)  ((Limit(s, 0xffff, -0x10000) * fmvolume_r) >> 14)
485 //#define IStoSample(s) ((s * fmvolume) >> 14)
486         
487         // odd bits - active, even bits - lfo
488         uint activech=0;
489         for (int i=0; i<8; i++)
490                 activech = (activech << 2) | ch[i].Prepare();
491
492         if (activech & 0x5555)
493         {
494                 // LFO \94g\8c`\8f\89\8aú\89»\83r\83b\83g = 1 \82È\82ç\82ΠLFO \82Í\82©\82©\82ç\82È\82¢?
495                 if (reg01 & 0x02)
496                         activech &= 0x5555;
497
498                 // Mix
499                 ISample ibuf[8];
500                 ISample* idest[8];
501                 idest[0] = &ibuf[pan[0]];
502                 idest[1] = &ibuf[pan[1]];
503                 idest[2] = &ibuf[pan[2]];
504                 idest[3] = &ibuf[pan[3]];
505                 idest[4] = &ibuf[pan[4]];
506                 idest[5] = &ibuf[pan[5]];
507                 idest[6] = &ibuf[pan[6]];
508                 idest[7] = &ibuf[pan[7]];
509                 
510                 Sample* limit = buffer + nsamples * 2;
511                 for (Sample* dest = buffer; dest < limit; dest+=2)
512                 {
513                         ibuf[1] = ibuf[2] = ibuf[3] = 0;
514                         if (activech & 0xaaaa)
515                                 LFO(), MixSubL(activech, idest);
516                         else
517                                 LFO(), MixSub(activech, idest);
518
519                         StoreSample(dest[0], IStoSampleL(ibuf[1] + ibuf[3]));
520                         StoreSample(dest[1], IStoSampleR(ibuf[2] + ibuf[3]));
521                 }
522         }
523 #undef IStoSampleL
524 #undef IStoSampleR
525 }
526
527 // ---------------------------------------------------------------------------
528 //      \83X\83e\81[\83g\83Z\81[\83u
529 //
530 #define OPM_STATE_VERSION       3
531
532 void OPM::SaveState(void *f)
533 {
534         FILEIO *state_fio = (FILEIO *)f;
535         
536         state_fio->FputUint32(OPM_STATE_VERSION);
537         
538         Timer::SaveState(f);
539         state_fio->FputInt32(fmvolume_l);
540         state_fio->FputInt32(fmvolume_r);
541         state_fio->FputUint32(clock);
542         state_fio->FputUint32(rate);
543         state_fio->FputUint32(pcmrate);
544         state_fio->FputUint32(pmd);
545         state_fio->FputUint32(amd);
546         state_fio->FputUint32(lfocount);
547         state_fio->FputUint32(lfodcount);
548         state_fio->FputUint32(lfo_count_);
549         state_fio->FputUint32(lfo_count_diff_);
550         state_fio->FputUint32(lfo_step_);
551         state_fio->FputUint32(lfo_count_prev_);
552         state_fio->FputUint32(lfowaveform);
553         state_fio->FputUint32(rateratio);
554         state_fio->FputUint32(noise);
555         state_fio->FputInt32(noisecount);
556         state_fio->FputUint32(noisedelta);
557         state_fio->FputBool(interpolation);
558         state_fio->FputUint8(lfofreq);
559         state_fio->FputUint8(status);
560         state_fio->FputBool(interrupt);
561         state_fio->FputUint8(reg01);
562         state_fio->Fwrite(kc, sizeof(kc), 1);
563         state_fio->Fwrite(kf, sizeof(kf), 1);
564         state_fio->Fwrite(pan, sizeof(pan), 1);
565         for(int i = 0; i < 8; i++) {
566                 ch[i].SaveState(f);
567         }
568         chip.SaveState(f);
569 }
570
571 bool OPM::LoadState(void *f)
572 {
573         FILEIO *state_fio = (FILEIO *)f;
574         
575         if(state_fio->FgetUint32() != OPM_STATE_VERSION) {
576                 return false;
577         }
578         if(!Timer::LoadState(f)) {
579                 return false;
580         }
581         fmvolume_l = state_fio->FgetInt32();
582         fmvolume_r = state_fio->FgetInt32();
583         clock = state_fio->FgetUint32();
584         rate = state_fio->FgetUint32();
585         pcmrate = state_fio->FgetUint32();
586         pmd = state_fio->FgetUint32();
587         amd = state_fio->FgetUint32();
588         lfocount = state_fio->FgetUint32();
589         lfodcount = state_fio->FgetUint32();
590         lfo_count_ = state_fio->FgetUint32();
591         lfo_count_diff_ = state_fio->FgetUint32();
592         lfo_step_ = state_fio->FgetUint32();
593         lfo_count_prev_ = state_fio->FgetUint32();
594         lfowaveform = state_fio->FgetUint32();
595         rateratio = state_fio->FgetUint32();
596         noise = state_fio->FgetUint32();
597         noisecount = state_fio->FgetInt32();
598         noisedelta = state_fio->FgetUint32();
599         interpolation = state_fio->FgetBool();
600         lfofreq = state_fio->FgetUint8();
601         status = state_fio->FgetUint8();
602         interrupt = state_fio->FgetBool();
603         reg01 = state_fio->FgetUint8();
604         state_fio->Fread(kc, sizeof(kc), 1);
605         state_fio->Fread(kf, sizeof(kf), 1);
606         state_fio->Fread(pan, sizeof(pan), 1);
607         for(int i = 0; i < 8; i++) {
608                 if(!ch[i].LoadState(f)) {
609                         return false;
610                 }
611         }
612         if(!chip.LoadState(f)) {
613                 return false;
614         }
615         return true;
616 }
617
618 }       // namespace FM
619