2 //
\83ÊPD7752 flavour voice engine
4 // Copyright (c) 2004 cisc.
5 // All rights reserved.
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.
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:
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.
23 // translated into C for Cocoa iP6 by Koichi Nishida 2006
33 #define I2F(a) (((D7752_FIXED) a) << 16)
34 #define F2I(a) ((int)((a) >> 16))
37 static const int amp_table[16] = {0, 1, 1, 2, 3, 4, 5, 7, 9, 13, 17, 23, 31, 42, 56, 75};
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
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
70 // start voice synthesis
80 int UPD7752::UPD7752_Start(int mode)
82 const static int frame_size[8] = {
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};
98 // initialise parameter variable
99 FrameSize = frame_size[mode & 7];
104 Coef.f[i] = I2F(f_default[i]);
105 Coef.b[i] = I2F(b_default[i]);
109 Coef.pitch = I2F(30);
111 return D7752_ERR_SUCCESS;
114 // get length of voice synthesis for 1 frame
115 int UPD7752::GetFrameSize(void)
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)
129 D7752Coef incr, next;
132 if (!param || !frame) return D7752_ERR_PARAM;
136 // expand parameters to coefficients
137 qmag = (param[0] & 4) != 0 ? 1 : 0;
139 for (i=0; i<5; i++) {
141 int f = (param[i+1] >> 3) & 31;
143 next.f[i] = curr->f[i] + I2F( f << qmag );
147 next.b[i] = curr->b[i] + I2F( b << qmag );
150 next.amp = I2F(( param[6] >> 4) & 15);
154 next.pitch = curr->pitch + I2F(p);
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;
164 // check if there is impulse noise
165 vu = param[0] & 1 ? 1 : 2;
166 vu |= param[6] & 4 ? 3 : 0;
169 for (i=0; i<FrameSize; i++) {
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;
182 if(rand() & 1) y += amp_table[F2I(curr->amp)] * 4 - 1; // XXX
\83m
\83C
\83Y
\8fÚ
\8d×
\95s
\96¾
185 for (j=0; j<5; j++) {
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;
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];
208 memcpy(curr, &next, sizeof(D7752Coef));
210 return D7752_ERR_SUCCESS;
214 // voice routine by Koichi Nishida 2006
215 // based on PC6001V voice routine by Mr.Yumitaro
219 Skelton for retropc emulator
221 Author : Takeo.Namiki
228 // write to CoreAudio after converting sampling rate and bit width
229 void UPD7752::UpConvert(void)
232 // 10kHz -> actual sampling rate
233 int samples = GetFrameSize() * SOUND_RATE / 10000;
235 voicebuf=(unsigned char *)malloc(samples * 10000);
236 memset(voicebuf, 0, samples * 10000);
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;
248 void UPD7752::AbortVoice(void)
253 // cancel remaining parameters
254 Pnum = Fnum = PReady = 0;
255 // free the frame buffer
260 VStat &= ~D7752E_BSY;
264 void UPD7752::CancelVoice(void)
272 // become 1 when synthesising voice
273 int UPD7752::VoiceOn(void)
279 void UPD7752::VSetMode(uint8_t mode)
281 // start synthesising
288 void UPD7752::VSetCommand(uint8_t comm)
290 // if synthesising voice, abort
293 case 0x00: // internal voice
300 case 0xfe: { // external voice
301 // malloc frame buffer
302 FbufLength = sizeof(D7752_SAMPLE)*GetFrameSize();
303 Fbuf = (D7752_SAMPLE *)malloc(FbufLength);
305 // make external mode, start parameter request
306 VStat = D7752E_BSY | D7752E_EXT | D7752E_REQ;
317 // transfer voice parameter
318 void UPD7752::VSetData(uint8_t data)
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
326 if (Fnum == 0) { PReady = 1; ThreadLoopStop = 0;}
328 // store to parameter buffer
329 ParaBuf[Pnum++] = data;
330 // if parameter buffer is full, ready!
332 VStat &= ~D7752E_REQ;
338 } else { // repeat frame?
340 for(i=1; i<6; i++) ParaBuf[i] = 0;
342 VStat &= ~D7752E_REQ;
351 // get status register
352 int UPD7752::VGetStatus(void)
359 void UPD7752::initialize()
361 DEVICE::initialize();
365 // register event to update the key status
366 register_frame_event(this);
370 void UPD7752::release()
373 if (voicebuf) free(voicebuf);
374 // trash FreeVoice();
375 if (Fbuf) free(Fbuf);
379 void UPD7752::reset()
381 io_E0H = io_E2H = io_E3H = 0;
392 void UPD7752::write_io8(uint32_t addr, uint32_t data)
395 uint16_t port=(addr & 0x00ff);
396 uint8_t Value=(data & 0xff);
416 uint32_t UPD7752::read_io8(uint32_t addr)
418 uint16_t port=(addr & 0x00ff);
437 void UPD7752::event_frame()
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)) {
447 // synthesise 1 frame samples
448 Synth(ParaBuf, Fbuf);
449 // convert sampling rate and write to CoreAudio
451 // accept next frame parameter
457 AbortVoice(); // abort voice
463 void UPD7752::mix(int32_t* buffer, int cnt)
465 if (mute && fout == fin) {
469 for(int i = 0; i < cnt; i++) {
471 if ((fout < fin) && (voicebuf != NULL)) {
472 vol=voicebuf[fout]-128;
476 *buffer++ = apply_volume(vol * 16, volume_l); // L
477 *buffer++ = apply_volume(vol * 16, volume_r); // R
481 void UPD7752::set_volume(int ch, int decibel_l, int decibel_r)
483 volume_l = decibel_to_volume(decibel_l);
484 volume_r = decibel_to_volume(decibel_r);
487 #define STATE_VERSION 2
489 bool UPD7752::process_state(FILEIO* state_fio, bool loading)
491 if(!state_fio->StateCheckUint32(STATE_VERSION)) {
494 if(!state_fio->StateCheckInt32(this_device_id)) {
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);
519 FbufLength = state_fio->FgetInt32_LE();
521 Fbuf = (D7752_SAMPLE *)malloc(FbufLength);
522 state_fio->Fread(Fbuf, FbufLength, 1);
525 state_fio->FputInt32_LE(Fbuf != NULL ? FbufLength : 0);
526 if(Fbuf != NULL && FbufLength > 0) {
527 state_fio->Fwrite(Fbuf, FbufLength, 1);
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);