OSDN Git Service

[VM][COMMON_VM] Include IO:: class to common_vm.
[csp-qt/common_source_project-fm7.git] / source / src / vm / upd7752.cpp
1 //
2 // \83ÊPD7752 flavour voice engine
3 //
4 // Copyright (c) 2004 cisc.
5 // All rights reserved.
6 //
7 // This software is     provided 'as-is', without any express or implied
8 // warranty.  In no     event will the authors be held liable for any damages
9 // arising from the     use     of this software.
10 //
11 // Permission is granted to     anyone to use this software     for     any     purpose,
12 // including commercial applications, and to alter it and redistribute it
13 // freely, subject to the following     restrictions:
14 //
15 // 1. The origin of     this software must not be misrepresented; you must not
16 //  claim       that you wrote the original     software. If you use this software
17 //  in a product,       an acknowledgment in the product documentation would be
18 //  appreciated but is not required.
19 // 2. Altered source versions must be plainly marked as such, and must not be
20 //  misrepresented as being the original software.
21 // 3. This notice may not be removed or altered from any source distribution.
22 //
23 // translated into C for Cocoa iP6 by Koichi Nishida 2006
24 //
25
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29
30 #include "upd7752.h"
31
32 // internal     macros
33 #define I2F(a) (((D7752_FIXED) a) << 16)
34 #define F2I(a) ((int)((a) >> 16))
35
36 // amplitude table
37 static const int amp_table[16] = {0, 1, 1, 2, 3, 4, 5, 7, 9, 13, 17, 23, 31, 42, 56, 75};
38
39 // filter coefficiens (uPD7752 flavour)
40 static const int iir1[128] = {
41          11424, 11400, 11377, 11331, 11285,     11265, 11195, 11149,
42          11082, 11014, 10922, 10830, 10741,     10629, 10491, 10332,
43          10172,  9992,  9788,  9560,  9311,      9037,  8721,  8377,
44           8016,  7631,  7199,  6720,  6245,      5721,  5197,  4654,
45         -11245,-11200,-11131,-11064,-10995,-10905,-10813,-10700,
46         -10585,-10447,-10291,-10108, -9924,     -9722, -9470, -9223,
47          -8928, -8609, -8247, -7881, -7472,     -7019, -6566, -6068,
48          -5545, -4999, -4452, -3902, -3363,     -2844, -2316, -1864,
49          11585, 11561, 11561, 11561, 11561,     11540, 11540, 11540,
50          11515, 11515, 11494, 11470, 11470,     11448, 11424, 11400,
51          11377, 11356, 11307, 11285, 11241,     11195, 11149, 11082,
52          11014, 10943, 10874, 10784, 10695,     10583, 10468, 10332,
53          10193, 10013,  9833,  9628,  9399,      9155,  8876,  8584,
54           8218,  7857,  7445,  6970,  6472,      5925,  5314,  4654,
55           3948,  3178,  2312,  1429,   450,      -543, -1614, -2729,
56          -3883, -5066, -6250, -7404, -8500,     -9497,-10359,-11038
57 };
58
59 static const int iir2[64]       = {
60          8192, 8105, 7989, 7844, 7670, 7424, 7158, 6803,
61          6370, 5860, 5252, 4579, 3824, 3057, 2307, 1623,
62          8193, 8100, 7990, 7844, 7672, 7423, 7158, 6802,
63          6371, 5857, 5253, 4576, 3825, 3057, 2309, 1617,
64         -6739,-6476,-6141,-5738,-5225,-4604,-3872,-2975,
65         -1930, -706,  686, 2224, 3871, 5518, 6992, 8085,
66         -6746,-6481,-6140,-5738,-5228,-4602,-3873,-2972,
67         -1931, -705,  685, 2228, 3870, 5516, 6993, 8084
68 };
69
70 // start voice synthesis
71 // parameter: mode
72 //    b2 F:
73 //       F=0 10ms/frame
74 //       F=1 20ms/frame
75 //    b1-0 S:
76 //       S=00: NORMAL SPEED
77 //       S=01: SLOW SPEED
78 //       S=10: FAST SPEED
79 // return: error code
80 int     UPD7752::UPD7752_Start(int mode)
81 {
82         const static int frame_size[8] = {
83                 100,             //     10ms, NORMAL
84                 120,             //     10ms, SLOW
85                  80,             //     10ms, FAST
86                 100,             //     PROHIBITED
87                 200,             //     20ms, NORMAL
88                 240,             //     20ms, SLOW
89                 160,             //     20ms, FAST
90                 200,             //     PROHIBITED
91         };
92         
93         // initial filter parameter
94         const static int f_default[5] = {126, 64, 121, 111, 96};
95         const static int b_default[5] = {9,     4, 9, 9, 11};
96         int i;
97         
98         // initialise parameter variable
99         FrameSize =     frame_size[mode & 7];
100         
101         for(i=0; i<5; i++){
102                 Y[i][0]   =     0;
103                 Y[i][1]   =     0;
104                 Coef.f[i] =     I2F(f_default[i]);
105                 Coef.b[i] =     I2F(b_default[i]);
106         }
107         PitchCount = 0;
108         Coef.amp   = 0;
109         Coef.pitch = I2F(30);
110         
111         return D7752_ERR_SUCCESS;
112 }
113
114 //      get length of voice synthesis for 1 frame
115 int     UPD7752::GetFrameSize(void)
116 {
117         return FrameSize;
118 }
119
120 // synthesise voice for one frame
121 // frame: pointer for data store
122 // return: error code
123 int     UPD7752::Synth(uint8_t *param, D7752_SAMPLE *frame)
124 {
125         int     vu;
126         int     qmag;
127         int i, j;
128         D7752Coef *curr;
129         D7752Coef incr, next;
130         int p;
131         
132         if (!param || !frame) return D7752_ERR_PARAM;
133         touch_sound();
134         curr = &Coef;
135         
136         // expand parameters to coefficients
137         qmag = (param[0] & 4) != 0 ? 1 : 0;
138         
139         for (i=0; i<5; i++) {
140                 int b;
141                 int     f =     (param[i+1]     >> 3) & 31;
142                 if(f & 16) f -= 32;
143                 next.f[i] =     curr->f[i] + I2F( f     << qmag );
144                 
145                 b =     param[i+1] & 7;
146                 if(b & 4)       b -= 8;
147                 next.b[i] =     curr->b[i] + I2F( b     << qmag );
148         }
149         
150         next.amp = I2F(( param[6] >> 4) & 15);
151         
152         p =     param[6] & 7;
153         if (p & 4)      p -= 8;
154         next.pitch = curr->pitch + I2F(p);
155         
156         // calculate increase for linier correction
157         incr.amp   = ( next.amp   -     curr->amp )       /     FrameSize;
158         incr.pitch = ( next.pitch -     curr->pitch     ) /     FrameSize;
159         for (i=0; i<5; i++) {
160                 incr.b[i] =     ( next.b[i]     - curr->b[i] ) / FrameSize;
161                 incr.f[i] =     ( next.f[i]     - curr->f[i] ) / FrameSize;
162         }
163         
164         // check if there is impulse noise
165         vu      = param[0] & 1 ? 1 : 2;
166         vu |= param[6] & 4 ? 3 : 0;
167         
168         // synthesise
169         for (i=0; i<FrameSize; i++) {
170                 int     y =     0;
171                 
172                 // generate impulse
173                 int     c =     F2I(curr->pitch);
174                 if (PitchCount > (c     > 0     ? c     : 128)) {
175                         if(vu & 1) y = amp_table[F2I(curr->amp)] * 16 - 1;
176                         PitchCount = 0;
177                 }
178                 PitchCount++;
179
180                 // generate noise
181                 if (vu & 2)
182                         if(rand() & 1) y += amp_table[F2I(curr->amp)] * 4 - 1;   //     XXX     \83m\83C\83Y\8fÚ\8d×\95s\96¾
183
184                 // mysterious filter
185                 for (j=0; j<5; j++) {
186                         int     t;
187                         t  = Y[j][0] * iir1[ F2I( curr->f[j] ) & 0x7f             ]     / 8192;
188                         y += t           * iir1[(F2I( curr->b[j] ) * 2 + 1)     & 0x7f] / 8192;
189                         y -= Y[j][1] * iir2[ F2I( curr->b[j] ) & 0x3f             ]     / 8192;
190                         y =     y >     8191 ? 8191     : y     < -8192 ? -8192 : y;
191                         
192                         Y[j][1] = Y[j][0];
193                         Y[j][0] = y;
194                 }
195
196                 // store data
197                 *frame++ = y;
198                 // increase parameter
199                 curr->amp       += incr.amp;
200                 curr->pitch     += incr.pitch;
201                 for (j=0; j<5; j++) {
202                         curr->b[j] += incr.b[j];
203                         curr->f[j] += incr.f[j];
204                 }
205         }
206         
207         // shift parameter
208         memcpy(curr, &next, sizeof(D7752Coef));
209         
210         return D7752_ERR_SUCCESS;
211 }
212
213 //
214 // voice routine by Koichi Nishida 2006
215 // based on PC6001V voice routine by Mr.Yumitaro
216 //
217
218 /*
219         Skelton for retropc emulator
220
221         Author : Takeo.Namiki
222         Date   : 2013.12.08-
223
224         [ uPD7752 ]
225 */
226
227
228 // write to CoreAudio after converting sampling rate and bit width
229 void UPD7752::UpConvert(void)
230 {
231         int i;
232         // 10kHz -> actual sampling rate
233         int samples = GetFrameSize() * SOUND_RATE / 10000;
234         if (!voicebuf) {
235                 voicebuf=(unsigned char *)malloc(samples * 10000);
236                 memset(voicebuf, 0, samples * 10000);
237         }
238         for(i=0; i<samples; i++) {
239                 int dat = (int)((double)Fbuf[i*GetFrameSize()/samples]/10.0);
240                 if (dat > 127) dat = 127;
241                 if (dat < -128) dat = -128;
242                 voicebuf[fin++] = dat+128;
243         }
244         mute = false;
245 }
246
247 // abort voice
248 void UPD7752::AbortVoice(void)
249 {
250         touch_sound();
251         // stop thread loop
252         ThreadLoopStop = 1;
253         // cancel remaining parameters
254         Pnum = Fnum = PReady = 0;
255         // free the frame buffer
256         if (Fbuf) {
257                 free(Fbuf);
258                 Fbuf = NULL;
259         }
260         VStat &= ~D7752E_BSY;
261 }
262
263 // cancel voice
264 void UPD7752::CancelVoice(void)
265 {
266         if (!mute) {
267                 AbortVoice();
268                 mute = true;
269         }
270 }
271
272 // become 1 when synthesising voice
273 int UPD7752::VoiceOn(void)
274 {
275         return (mute ? 1:0);
276 }
277
278 // set mode
279 void UPD7752::VSetMode(uint8_t mode)
280 {
281         // start synthesising
282         UPD7752_Start(mode);
283         // clear status
284         VStat = D7752E_IDL;
285 }
286
287 // set command
288 void UPD7752::VSetCommand(uint8_t comm)
289 {
290         // if synthesising voice, abort
291         AbortVoice();
292         switch (comm) {
293         case 0x00:              // internal voice
294         case 0x01:
295         case 0x02:
296         case 0x03:
297         case 0x04:
298                 // not implemented
299                 break;
300         case 0xfe: {    // external voice
301                 // malloc frame buffer
302                 FbufLength = sizeof(D7752_SAMPLE)*GetFrameSize();
303                 Fbuf = (D7752_SAMPLE *)malloc(FbufLength);
304                 if(!Fbuf) break;
305                 // make external mode, start parameter request
306                 VStat = D7752E_BSY | D7752E_EXT | D7752E_REQ;
307                 break;
308         }
309         case 0xff:              // stop
310                 break;
311         default:                // invalid
312                 VStat = D7752E_ERR;
313                 break;
314         }
315 }
316
317 // transfer voice parameter
318 void UPD7752::VSetData(uint8_t data)
319 {
320         // accept data only when busy
321         if ((VStat & D7752E_BSY)&&(VStat & D7752E_REQ)) {
322                 if (Fnum == 0 || Pnum) {        // first frame?
323                         // if first frame, set repeat number
324                         if(Pnum == 0) {
325                                 Fnum = data>>3;
326                                 if (Fnum == 0) { PReady = 1; ThreadLoopStop = 0;}
327                         }
328                         // store to parameter buffer
329                         ParaBuf[Pnum++] = data;
330                         // if parameter buffer is full, ready!
331                         if(Pnum == 7) {
332                                 VStat &= ~D7752E_REQ;
333                                 Pnum = 0;
334                                 if(Fnum > 0) Fnum--;
335                                 ThreadLoopStop = 0;
336                                 PReady = 1;
337                         }
338                 } else {                                                // repeat frame?
339                         int i;
340                         for(i=1; i<6; i++) ParaBuf[i] = 0;
341                         ParaBuf[6] = data;
342                         VStat &= ~D7752E_REQ;
343                         Pnum = 0;
344                         Fnum--;
345                         ThreadLoopStop = 0;                     
346                         PReady = 1;
347                 }
348         }
349 }
350
351 // get status register
352 int UPD7752::VGetStatus(void)
353 {
354         int ret;
355         ret = VStat;
356         return ret;
357 }
358
359 void UPD7752::initialize()
360 {
361         DEVICE::initialize();
362         mute=true;
363         voicebuf=NULL;
364         Fbuf = NULL;
365         // register event to update the key status
366         register_frame_event(this);
367         return;
368 }
369
370 void UPD7752::release()
371 {
372         CancelVoice();
373         if (voicebuf) free(voicebuf);
374         // trash FreeVoice();
375         if (Fbuf) free(Fbuf);
376         return;
377 }
378
379 void UPD7752::reset()
380 {
381         io_E0H = io_E2H = io_E3H = 0;
382         Pnum    = 0;
383         Fnum    = 0;
384         PReady  = 0;
385         VStat   = D7752E_IDL;
386         fin = fout =0;
387         mute=true;
388         ThreadLoopStop=1;
389         return;
390 }
391
392 void UPD7752::write_io8(uint32_t addr, uint32_t data)
393 {
394         // disk I/O
395         uint16_t port=(addr & 0x00ff);
396         uint8_t Value=(data & 0xff);
397
398         switch(port)
399         {
400         case 0xE0:
401                 touch_sound();
402                 VSetData(data);
403                 break;
404         case 0xE2:
405                 touch_sound();
406                 VSetMode(data);
407                 break;
408         case 0xE3:
409                 touch_sound();
410                 VSetCommand(data);
411                 break;
412         }
413         return;
414 }
415
416 uint32_t UPD7752::read_io8(uint32_t addr)
417 {
418         uint16_t port=(addr & 0x00ff);
419         uint8_t Value=0xff;
420
421         switch(port)
422         {
423         case 0xE0:
424                 Value=VGetStatus();
425                 break;
426         case 0xE2:
427                 Value=io_E2H;
428                 break;
429         case 0xE3:
430                 Value=io_E3H;
431                 break;
432         }
433         return Value;
434 }
435
436 // voice thread
437 void UPD7752::event_frame()
438 {
439         if (ThreadLoopStop) return;
440         if (VStat & D7752E_EXT) {       // external voice
441                 if (PReady) {   // parameter set is complete ?
442                         // abort if frame number is 0
443                         if(!(ParaBuf[0]>>3)) {
444                                 AbortVoice();
445                                 mute = true;
446                         } else {
447                                 // synthesise 1 frame samples
448                                 Synth(ParaBuf, Fbuf);
449                                 // convert sampling rate and write to CoreAudio
450                                 UpConvert();
451                                 // accept next frame parameter
452                                 PReady = 0;
453                                 ThreadLoopStop = 1;
454                                 VStat |= D7752E_REQ;
455                         }
456                 } else {
457                         AbortVoice();           // abort voice
458                         VStat = D7752E_ERR;
459                 }
460         }
461 }
462
463 void UPD7752::mix(int32_t* buffer, int cnt)
464 {
465         if (mute && fout == fin) {
466                 fin = fout =0;
467                 return;
468         }
469         for(int i = 0; i < cnt; i++) {
470                 int32_t vol = 0;
471                 if ((fout < fin) && (voicebuf != NULL)) {
472                         vol=voicebuf[fout]-128;
473                         voicebuf[fout]=0;
474                         fout++;
475                 }
476                 *buffer++ = apply_volume(vol * 16, volume_l); // L
477                 *buffer++ = apply_volume(vol * 16, volume_r); // R
478         }
479 }
480
481 void UPD7752::set_volume(int ch, int decibel_l, int decibel_r)
482 {
483         volume_l = decibel_to_volume(decibel_l);
484         volume_r = decibel_to_volume(decibel_r);
485 }
486
487 #define STATE_VERSION   2
488
489 bool UPD7752::process_state(FILEIO* state_fio, bool loading)
490 {
491         if(!state_fio->StateCheckUint32(STATE_VERSION)) {
492                 return false;
493         }
494         if(!state_fio->StateCheckInt32(this_device_id)) {
495                 return false;
496         }
497         // pre process
498         if(loading) {
499                 if(Fbuf) {
500                         free(Fbuf);
501                         Fbuf = NULL;
502                 }
503                 if (voicebuf) {
504                         free(voicebuf);
505                         voicebuf = NULL;
506                 }
507         }
508         state_fio->StateValue(mute);
509         state_fio->StateValue(ThreadLoopStop);
510         state_fio->StateValue(io_E0H);
511         state_fio->StateValue(io_E2H);
512         state_fio->StateValue(io_E3H);
513         state_fio->StateValue(VStat);
514         state_fio->StateArray(ParaBuf, sizeof(ParaBuf), 1);
515         state_fio->StateValue(Pnum);
516         state_fio->StateValue(Fnum);
517         state_fio->StateValue(PReady);
518         if(loading) {
519                 FbufLength = state_fio->FgetInt32_LE();
520                 if(FbufLength > 0) {
521                         Fbuf = (D7752_SAMPLE *)malloc(FbufLength);
522                         state_fio->Fread(Fbuf, FbufLength, 1);
523                 }
524         } else {
525                 state_fio->FputInt32_LE(Fbuf != NULL ? FbufLength : 0);
526                 if(Fbuf != NULL && FbufLength > 0) {
527                         state_fio->Fwrite(Fbuf, FbufLength, 1);
528                 }
529         }
530         state_fio->StateValue(fin);
531         state_fio->StateValue(fout);
532         state_fio->StateArray(Coef.f, sizeof(Coef.f), 1);
533         state_fio->StateArray(Coef.b, sizeof(Coef.b), 1);
534         state_fio->StateValue(Coef.amp);
535         state_fio->StateValue(Coef.pitch);
536         state_fio->StateArray(&Y[0][0], sizeof(Y), 1);
537         state_fio->StateValue(PitchCount);
538         state_fio->StateValue(FrameSize);
539         return true;
540 }
541