OSDN Git Service

[VM][Qt] Add SANYOPHC-20, PHC-25 and SEIKO MAP-1010 .
[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(byte *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         curr = &Coef;
134         
135         // expand parameters to coefficients
136         qmag = (param[0] & 4) != 0 ? 1 : 0;
137         
138         for (i=0; i<5; i++) {
139                 int b;
140                 int     f =     (param[i+1]     >> 3) & 31;
141                 if(f & 16) f -= 32;
142                 next.f[i] =     curr->f[i] + I2F( f     << qmag );
143                 
144                 b =     param[i+1] & 7;
145                 if(b & 4)       b -= 8;
146                 next.b[i] =     curr->b[i] + I2F( b     << qmag );
147         }
148         
149         next.amp = I2F(( param[6] >> 4) & 15);
150         
151         p =     param[6] & 7;
152         if (p & 4)      p -= 8;
153         next.pitch = curr->pitch + I2F(p);
154         
155         // calculate increase for linier correction
156         incr.amp   = ( next.amp   -     curr->amp )       /     FrameSize;
157         incr.pitch = ( next.pitch -     curr->pitch     ) /     FrameSize;
158         for (i=0; i<5; i++) {
159                 incr.b[i] =     ( next.b[i]     - curr->b[i] ) / FrameSize;
160                 incr.f[i] =     ( next.f[i]     - curr->f[i] ) / FrameSize;
161         }
162         
163         // check if there is impulse noise
164         vu      = param[0] & 1 ? 1 : 2;
165         vu |= param[6] & 4 ? 3 : 0;
166         
167         // synthesise
168         for (i=0; i<FrameSize; i++) {
169                 int     y =     0;
170                 
171                 // generate impulse
172                 int     c =     F2I(curr->pitch);
173                 if (PitchCount > (c     > 0     ? c     : 128)) {
174                         if(vu & 1) y = amp_table[F2I(curr->amp)] * 16 - 1;
175                         PitchCount = 0;
176                 }
177                 PitchCount++;
178
179                 // generate noise
180                 if (vu & 2)
181                         if(rand() & 1) y += amp_table[F2I(curr->amp)] * 4 - 1;   //     XXX     \83m\83C\83Y\8fÚ\8d×\95s\96¾
182
183                 // mysterious filter
184                 for (j=0; j<5; j++) {
185                         int     t;
186                         t  = Y[j][0] * iir1[ F2I( curr->f[j] ) & 0x7f             ]     / 8192;
187                         y += t           * iir1[(F2I( curr->b[j] ) * 2 + 1)     & 0x7f] / 8192;
188                         y -= Y[j][1] * iir2[ F2I( curr->b[j] ) & 0x3f             ]     / 8192;
189                         y =     y >     8191 ? 8191     : y     < -8192 ? -8192 : y;
190                         
191                         Y[j][1] = Y[j][0];
192                         Y[j][0] = y;
193                 }
194
195                 // store data
196                 *frame++ = y;
197                 // increase parameter
198                 curr->amp       += incr.amp;
199                 curr->pitch     += incr.pitch;
200                 for (j=0; j<5; j++) {
201                         curr->b[j] += incr.b[j];
202                         curr->f[j] += incr.f[j];
203                 }
204         }
205         
206         // shift parameter
207         memcpy(curr, &next, sizeof(D7752Coef));
208         
209         return D7752_ERR_SUCCESS;
210 }
211
212 //
213 // voice routine by Koichi Nishida 2006
214 // based on PC6001V voice routine by Mr.Yumitaro
215 //
216
217 /*
218         Skelton for retropc emulator
219
220         Author : Takeo.Namiki
221         Date   : 2013.12.08-
222
223         [ uPD7752 ]
224 */
225
226
227 // write to CoreAudio after converting sampling rate and bit width
228 void UPD7752::UpConvert(void)
229 {
230         int i;
231         // 10kHz -> actual sampling rate
232         int samples = GetFrameSize() * SOUND_RATE / 10000;
233         if (!voicebuf) {
234                 voicebuf=(unsigned char *)malloc(samples * 10000);
235                 memset(voicebuf, 0, samples * 10000);
236         }
237         for(i=0; i<samples; i++) {
238                 int dat = (int)((double)Fbuf[i*GetFrameSize()/samples]/10.0);
239                 if (dat > 127) dat = 127;
240                 if (dat < -128) dat = -128;
241                 voicebuf[fin++] = dat+128;
242         }
243         mute = false;
244 }
245
246 // abort voice
247 void UPD7752::AbortVoice(void)
248 {
249         // stop thread loop
250         ThreadLoopStop = 1;
251         // cancel remaining parameters
252         Pnum = Fnum = PReady = 0;
253         // free the frame buffer
254         if (Fbuf) {
255                 free(Fbuf);
256                 Fbuf = NULL;
257         }
258         VStat &= ~D7752E_BSY;
259 }
260
261 // cancel voice
262 void UPD7752::CancelVoice(void)
263 {
264         if (!mute) {
265                 AbortVoice();
266                 mute = true;
267         }
268 }
269
270 // become 1 when synthesising voice
271 int UPD7752::VoiceOn(void)
272 {
273         return (mute ? 1:0);
274 }
275
276 // set mode
277 void UPD7752::VSetMode(byte mode)
278 {
279         // start synthesising
280         UPD7752_Start(mode);
281         // clear status
282         VStat = D7752E_IDL;
283 }
284
285 // set command
286 void UPD7752::VSetCommand(byte comm)
287 {
288         // if synthesising voice, abort
289         AbortVoice();
290         switch (comm) {
291         case 0x00:              // internal voice
292         case 0x01:
293         case 0x02:
294         case 0x03:
295         case 0x04:
296                 // not implemented
297                 break;
298         case 0xfe: {    // external voice
299                 // malloc frame buffer
300                 FbufLength = sizeof(D7752_SAMPLE)*GetFrameSize();
301                 Fbuf = (D7752_SAMPLE *)malloc(FbufLength);
302                 if(!Fbuf) break;
303                 // make external mode, start parameter request
304                 VStat = D7752E_BSY | D7752E_EXT | D7752E_REQ;
305                 break;
306         }
307         case 0xff:              // stop
308                 break;
309         default:                // invalid
310                 VStat = D7752E_ERR;
311                 break;
312         }
313 }
314
315 // transfer voice parameter
316 void UPD7752::VSetData(byte data)
317 {
318         // accept data only when busy
319         if ((VStat & D7752E_BSY)&&(VStat & D7752E_REQ)) {
320                 if (Fnum == 0 || Pnum) {        // first frame?
321                         // if first frame, set repeat number
322                         if(Pnum == 0) {
323                                 Fnum = data>>3;
324                                 if (Fnum == 0) { PReady = 1; ThreadLoopStop = 0;}
325                         }
326                         // store to parameter buffer
327                         ParaBuf[Pnum++] = data;
328                         // if parameter buffer is full, ready!
329                         if(Pnum == 7) {
330                                 VStat &= ~D7752E_REQ;
331                                 Pnum = 0;
332                                 if(Fnum > 0) Fnum--;
333                                 ThreadLoopStop = 0;
334                                 PReady = 1;
335                         }
336                 } else {                                                // repeat frame?
337                         int i;
338                         for(i=1; i<6; i++) ParaBuf[i] = 0;
339                         ParaBuf[6] = data;
340                         VStat &= ~D7752E_REQ;
341                         Pnum = 0;
342                         Fnum--;
343                         ThreadLoopStop = 0;                     
344                         PReady = 1;
345                 }
346         }
347 }
348
349 // get status register
350 int UPD7752::VGetStatus(void)
351 {
352         int ret;
353         ret = VStat;
354         return ret;
355 }
356
357 void UPD7752::initialize()
358 {
359         mute=true;
360         voicebuf=NULL;
361         Fbuf = NULL;
362         // register event to update the key status
363         register_frame_event(this);
364         return;
365 }
366
367 void UPD7752::release()
368 {
369         CancelVoice();
370         if (voicebuf) free(voicebuf);
371         // trash FreeVoice();
372         if (Fbuf) free(Fbuf);
373         return;
374 }
375
376 void UPD7752::reset()
377 {
378         io_E0H = io_E2H = io_E3H = 0;
379         Pnum    = 0;
380         Fnum    = 0;
381         PReady  = 0;
382         VStat   = D7752E_IDL;
383         fin = fout =0;
384         mute=true;
385         ThreadLoopStop=1;
386         return;
387 }
388
389 void UPD7752::write_io8(uint32 addr, uint32 data)
390 {
391         // disk I/O
392         uint16 port=(addr & 0x00ff);
393         byte Value=(data & 0xff);
394
395         switch(port)
396         {
397         case 0xE0:
398                 VSetData(data);
399                 break;
400         case 0xE2:
401                 VSetMode(data);
402                 break;
403         case 0xE3:
404                 VSetCommand(data);
405                 break;
406         }
407         return;
408 }
409
410 uint32 UPD7752::read_io8(uint32 addr)
411 {
412         uint16 port=(addr & 0x00ff);
413         byte Value=0xff;
414
415         switch(port)
416         {
417         case 0xE0:
418                 Value=VGetStatus();
419                 break;
420         case 0xE2:
421                 Value=io_E2H;
422                 break;
423         case 0xE3:
424                 Value=io_E3H;
425                 break;
426         }
427         return Value;
428 }
429
430 // voice thread
431 void UPD7752::event_frame()
432 {
433         if (ThreadLoopStop) return;
434         if (VStat & D7752E_EXT) {       // external voice
435                 if (PReady) {   // parameter set is complete ?
436                         // abort if frame number is 0
437                         if(!(ParaBuf[0]>>3)) {
438                                 AbortVoice();
439                                 mute = true;
440                         } else {
441                                 // synthesise 1 frame samples
442                                 Synth(ParaBuf, Fbuf);
443                                 // convert sampling rate and write to CoreAudio
444                                 UpConvert();
445                                 // accept next frame parameter
446                                 PReady = 0;
447                                 ThreadLoopStop = 1;
448                                 VStat |= D7752E_REQ;
449                         }
450                 } else {
451                         AbortVoice();           // abort voice
452                         VStat = D7752E_ERR;
453                 }
454         }
455 }
456
457 void UPD7752::mix(int32* buffer, int cnt)
458 {
459         if (mute && fout == fin) {
460                 fin = fout =0;
461                 return;
462         }
463         for(int i = 0; i < cnt; i++) {
464                 int32 vol = 0;
465                 if (fout < fin) {
466                         vol=voicebuf[fout];
467                         voicebuf[fout]=0;
468                         fout++;
469                 }
470                 *buffer++ = vol << 4;
471         }
472 }
473
474 #define STATE_VERSION   1
475
476 void UPD7752::save_state(FILEIO* state_fio)
477 {
478         state_fio->FputUint32(STATE_VERSION);
479         state_fio->FputInt32(this_device_id);
480         
481         state_fio->FputBool(mute);
482         state_fio->FputInt32(ThreadLoopStop);
483         state_fio->FputUint8(io_E0H);
484         state_fio->FputUint8(io_E2H);
485         state_fio->FputUint8(io_E3H);
486         state_fio->FputInt32(VStat);
487         state_fio->Fwrite(ParaBuf, sizeof(ParaBuf), 1);
488         state_fio->FputUint8(Pnum);
489         state_fio->FputInt32(Fnum);
490         state_fio->FputInt32(PReady);
491         state_fio->FputInt32(Fbuf != NULL ? FbufLength : 0);
492         if(Fbuf != NULL && FbufLength > 0) {
493                 state_fio->Fread(Fbuf, FbufLength, 1);
494         }
495         state_fio->FputInt32(fin);
496         state_fio->FputInt32(fout);
497         state_fio->Fwrite(&Coef, sizeof(D7752Coef), 1);
498         state_fio->Fwrite(Y, sizeof(Y), 1);
499         state_fio->FputInt32(PitchCount);
500         state_fio->FputInt32(FrameSize);
501 }
502
503 bool UPD7752::load_state(FILEIO* state_fio)
504 {
505         // pre process
506         if(Fbuf) {
507                 free(Fbuf);
508                 Fbuf = NULL;
509         }
510         if (voicebuf) {
511                 free(voicebuf);
512                 voicebuf = NULL;
513         }
514         
515         if(state_fio->FgetUint32() != STATE_VERSION) {
516                 return false;
517         }
518         if(state_fio->FgetInt32() != this_device_id) {
519                 return false;
520         }
521         mute = state_fio->FgetBool();
522         ThreadLoopStop = state_fio->FgetInt32();
523         io_E0H = state_fio->FgetUint8();
524         io_E2H = state_fio->FgetUint8();
525         io_E3H = state_fio->FgetUint8();
526         VStat = state_fio->FgetInt32();
527         state_fio->Fread(ParaBuf, sizeof(ParaBuf), 1);
528         Pnum = state_fio->FgetUint8();
529         Fnum = state_fio->FgetInt32();
530         PReady = state_fio->FgetInt32();
531         FbufLength = state_fio->FgetInt32();
532         if(FbufLength > 0) {
533                 Fbuf = (D7752_SAMPLE *)malloc(FbufLength);
534                 state_fio->Fread(Fbuf, FbufLength, 1);
535         }
536         fin = state_fio->FgetInt32();
537         fout = state_fio->FgetInt32();
538         state_fio->Fread(&Coef, sizeof(D7752Coef), 1);
539         state_fio->Fread(Y, sizeof(Y), 1);
540         PitchCount = state_fio->FgetInt32();
541         FrameSize = state_fio->FgetInt32();
542         return true;
543 }
544