OSDN Git Service

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