1 //
2 // /home/ms/source/sidplay/libsidplay/RCS/eeconfig.cpp,v
3 //
4 // SID Emulator Engine configuration interface class.
5 // Quick documentation in header file ``include/emucfg.h''.
6
7 #include "eeconfig.h"
8
9 // ------------------------------------------------------------- constructors
10
emuEngine()11 emuEngine::emuEngine()
12 {
13 // Set the defaults.
14 config.frequency = 44100;
15 config.bitsPerSample = SIDEMU_16BIT;
16 config.sampleFormat = SIDEMU_SIGNED_PCM;
17 config.channels = SIDEMU_MONO;
18 config.sidChips = 1;
19 config.volumeControl = SIDEMU_NONE;
20 config.mos8580 = false;
21 config.measuredVolume = true;
22 config.digiPlayerScans = 10*50;
23 config.emulateFilter = true;
24 config.autoPanning = SIDEMU_NONE;
25 config.memoryMode = MPU_BANK_SWITCHING;
26 config.clockSpeed = SIDTUNE_CLOCK_PAL;
27 config.forceSongSpeed = false;
28
29 #if defined(SIDEMU_TIME_COUNT)
30 // Reset data counter.
31 bytesCountTotal = (bytesCountSong = 0);
32 secondsTotal = (secondsThisSong = 0);
33 #endif
34
35 isThreeVoiceTune = false;
36
37 extern void sidEmuResetAutoPanning(int);
38 sidEmuResetAutoPanning(config.autoPanning);
39
40 // Allocate memory for the interpreter.
41 c64memFree();
42 MPUstatus = c64memAlloc();
43
44 // Allocate memory for the SID emulator engine.
45 freeMem();
46 if ( MPUstatus && allocMem() )
47 {
48 setRandomSeed();
49 MPUreset();
50 configureSID();
51 initMixerEngine();
52 setDefaultVoiceVolumes();
53 setDefaultFilterStrength();
54 isReady = true;
55 reset();
56 }
57 else
58 {
59 isReady = false;
60 }
61 }
62
63 // -------------------------------------------------------------- destructors
64
~emuEngine()65 emuEngine::~emuEngine()
66 {
67 c64memFree();
68 freeMem();
69 }
70
71 // -------------------------------------------------- public member functions
72
73 const char* versionString = emu_version;
74
getVersionString()75 const char* emuEngine::getVersionString()
76 {
77 return versionString;
78 }
79
setConfig(struct emuConfig & inCfg)80 bool emuEngine::setConfig( struct emuConfig& inCfg )
81 {
82 bool gotInvalidConfig = false;
83
84 // Validate input value.
85 if ((inCfg.memoryMode == MPU_BANK_SWITCHING)
86 || (inCfg.memoryMode == MPU_TRANSPARENT_ROM)
87 || (inCfg.memoryMode == MPU_PLAYSID_ENVIRONMENT))
88 {
89 config.memoryMode = inCfg.memoryMode;
90 }
91 else
92 {
93 gotInvalidConfig = true; // invalid settings
94 }
95
96 // Validate input value.
97 // Check various settings before doing a single SID-config call.
98 bool newSIDconfig = false;
99 bool newFilterInit = false;
100
101 if ((inCfg.clockSpeed == SIDTUNE_CLOCK_PAL)
102 || (inCfg.clockSpeed == SIDTUNE_CLOCK_NTSC))
103 {
104 if (inCfg.clockSpeed != config.clockSpeed)
105 {
106 config.clockSpeed = inCfg.clockSpeed;
107 newSIDconfig = true;
108 }
109 }
110 else
111 {
112 gotInvalidConfig = true; // invalid settings
113 }
114
115 if (inCfg.forceSongSpeed != config.forceSongSpeed)
116 {
117 config.forceSongSpeed = (inCfg.forceSongSpeed == true);
118 }
119
120 // Range-check the sample frequency.
121 if (( inCfg.frequency >= 4000 ) && ( inCfg.frequency <= 48000 ))
122 {
123 // Has it changed ? Then do the necessary initialization.
124 if ( inCfg.frequency != config.frequency )
125 {
126 config.frequency = inCfg.frequency;
127 newSIDconfig = true;
128 newFilterInit = true;
129 }
130 }
131 else
132 {
133 gotInvalidConfig = true; // invalid settings
134 }
135
136 if (inCfg.measuredVolume != config.measuredVolume)
137 {
138 config.measuredVolume = (inCfg.measuredVolume == true);
139 newSIDconfig = true;
140 }
141
142 // The mixer mode, the sample format, the number of channels and bits per
143 // sample all affect the mixing tables and settings.
144 // Hence we define a handy flag here.
145 bool newMixerSettings = false;
146
147 // Is the requested sample format valid?
148 if (( inCfg.sampleFormat == SIDEMU_UNSIGNED_PCM )
149 || ( inCfg.sampleFormat == SIDEMU_SIGNED_PCM ))
150 {
151 // Has it changed ? Then do the necessary initialization.
152 if ( inCfg.sampleFormat != config.sampleFormat )
153 {
154 config.sampleFormat = inCfg.sampleFormat;
155 newMixerSettings = true;
156 }
157 }
158 else
159 {
160 gotInvalidConfig = true; // invalid settings
161 }
162
163 // Is the requested number of channels valid?
164 if (( inCfg.channels == SIDEMU_MONO )
165 || ( inCfg.channels == SIDEMU_STEREO ))
166 {
167 // Has it changed ? Then do the necessary initialization.
168 if ( inCfg.channels != config.channels )
169 {
170 config.channels = inCfg.channels;
171 setDefaultVoiceVolumes();
172 newMixerSettings = true;
173 }
174 }
175 else
176 {
177 gotInvalidConfig = true; // invalid settings
178 }
179
180 // Is the requested sample precision valid?
181 if (( inCfg.bitsPerSample == SIDEMU_8BIT )
182 || ( inCfg.bitsPerSample == SIDEMU_16BIT ))
183 {
184 // Has it changed ? Then do the necessary initialization.
185 if ( inCfg.bitsPerSample != config.bitsPerSample )
186 {
187 config.bitsPerSample = inCfg.bitsPerSample;
188 newMixerSettings = true;
189 }
190 }
191 else
192 {
193 gotInvalidConfig = true; // invalid settings
194 }
195
196 // Is the requested mixing mode valid?
197 if (( inCfg.volumeControl == SIDEMU_NONE )
198 || ( inCfg.volumeControl == SIDEMU_VOLCONTROL )
199 || ( inCfg.volumeControl == SIDEMU_FULLPANNING )
200 || ( inCfg.volumeControl == SIDEMU_HWMIXING )
201 || ( inCfg.volumeControl == SIDEMU_STEREOSURROUND ))
202 {
203 // Has it changed ? Then do the necessary initialization.
204 if ( inCfg.volumeControl != config.volumeControl )
205 {
206 config.volumeControl = inCfg.volumeControl;
207 setDefaultVoiceVolumes();
208 newMixerSettings = true;
209 }
210 }
211 else
212 {
213 gotInvalidConfig = true; // invalid settings
214 }
215
216 if ((inCfg.autoPanning == SIDEMU_NONE)
217 || (inCfg.autoPanning == SIDEMU_CENTEREDAUTOPANNING))
218 {
219 if (inCfg.autoPanning != config.autoPanning)
220 {
221 config.autoPanning = inCfg.autoPanning;
222 if (config.autoPanning != SIDEMU_NONE)
223 {
224 if (( config.volumeControl != SIDEMU_FULLPANNING )
225 && ( config.volumeControl != SIDEMU_STEREOSURROUND ))
226 {
227 config.autoPanning = false;
228 gotInvalidConfig = true; // wrong mixing mode
229 }
230 }
231 extern void sidEmuResetAutoPanning(int);
232 sidEmuResetAutoPanning(config.autoPanning);
233 }
234 }
235 else
236 {
237 gotInvalidConfig = true; // invalid panning mode
238 }
239
240 if (inCfg.emulateFilter != config.emulateFilter)
241 {
242 config.emulateFilter = (inCfg.emulateFilter == true);
243 newSIDconfig = true; // filter
244 newMixerSettings = true; // amplification
245 }
246 // Range-check the filter settings.
247 if (( inCfg.filterFs >= 1.0 ) && ( inCfg.filterFm != 0 ))
248 {
249 // Have they changed? Then do the necessary initialization.
250 if ((inCfg.filterFs != config.filterFs)
251 || (inCfg.filterFm != config.filterFm)
252 || (inCfg.filterFt != config.filterFt))
253 {
254 config.filterFs = inCfg.filterFs;
255 config.filterFm = inCfg.filterFm;
256 config.filterFt = inCfg.filterFt;
257 newFilterInit = true;
258 }
259 }
260 else
261 {
262 gotInvalidConfig = true; // invalid settings
263 }
264
265 if (inCfg.digiPlayerScans != config.digiPlayerScans)
266 {
267 config.digiPlayerScans = inCfg.digiPlayerScans;
268 newMixerSettings = true; // extra amplification
269 }
270
271 if ((config.channels==SIDEMU_MONO) &&
272 ((config.volumeControl==SIDEMU_STEREOSURROUND)
273 ||(config.autoPanning!=SIDEMU_NONE)))
274 {
275 gotInvalidConfig = true; // invalid settings
276 }
277
278 if (inCfg.mos8580 != config.mos8580)
279 {
280 config.mos8580 = (inCfg.mos8580 == true);
281 newSIDconfig = true;
282 }
283
284 // Here re-initialize the SID, if required.
285 if (newSIDconfig)
286 {
287 configureSID();
288 }
289
290 // Here re-initialize the mixer engine, if required.
291 if (newMixerSettings)
292 {
293 initMixerEngine();
294 }
295
296 // Here re-initialize the filter settings, if required.
297 if (newFilterInit)
298 {
299 filterTableInit();
300 }
301
302 // Return flag, whether input config was valid.
303 return !gotInvalidConfig;
304 }
305
getConfig(struct emuConfig & outCfg)306 void emuEngine::getConfig( struct emuConfig& outCfg )
307 {
308 outCfg = config;
309 }
310
setDefaultFilterStrength()311 void emuEngine::setDefaultFilterStrength()
312 {
313 config.filterFs = SIDEMU_DEFAULTFILTERFS;
314 config.filterFm = SIDEMU_DEFAULTFILTERFM;
315 config.filterFt = SIDEMU_DEFAULTFILTERFT;
316 filterTableInit();
317 }
318
verifyEndianess()319 bool emuEngine::verifyEndianess()
320 {
321 // Test endianess. Should swap bytes.
322 ubyte endTest[2];
323 writeLEword(endTest,0x55aa);
324 if (0xaa55!=readBEword(endTest))
325 return false;
326 else
327 return true;
328 }
329
330 #if defined(SIDEMU_TIME_COUNT)
getSecondsThisSong()331 int emuEngine::getSecondsThisSong()
332 {
333 return secondsThisSong;
334 }
335
getSecondsTotal()336 int emuEngine::getSecondsTotal()
337 {
338 return secondsTotal;
339 }
340 #endif
341
342 // ------------------------------------------------- private member functions
343
freeMem()344 bool emuEngine::freeMem()
345 {
346 if ( ampMod1x8 != 0 )
347 delete[] ampMod1x8;
348 ampMod1x8 = 0;
349 if ( signedPanMix8 != 0 )
350 delete[] signedPanMix8;
351 signedPanMix8 = 0;
352 if ( signedPanMix16 != 0 )
353 delete[] signedPanMix16;
354 signedPanMix16 = 0;
355 return true;
356 }
357
allocMem()358 bool emuEngine::allocMem()
359 {
360 // Keep track of memory allocation failures.
361 bool wasSuccess = true;
362 // Seems as if both tables are needed for panning-mixing with 16-bit samples.
363 // 8-bit
364 #ifdef SID_HAVE_EXCEPTIONS
365 if (( ampMod1x8 = new(std::nothrow) sbyte[256*256] ) == 0 )
366 #else
367 if (( ampMod1x8 = new sbyte[256*256] ) == 0 )
368 #endif
369 wasSuccess = false;
370 #ifdef SID_HAVE_EXCEPTIONS
371 if (( signedPanMix8 = new(std::nothrow) sbyte[256*256] ) == 0 )
372 #else
373 if (( signedPanMix8 = new sbyte[256*256] ) == 0 )
374 #endif
375 wasSuccess = false;
376 // 16-bit
377 #ifdef SID_HAVE_EXCEPTIONS
378 if (( signedPanMix16 = new(std::nothrow) sword[256*256] ) == 0 )
379 #else
380 if (( signedPanMix16 = new sword[256*256] ) == 0 )
381 #endif
382 wasSuccess = false;
383
384 if (!wasSuccess)
385 {
386 freeMem();
387 }
388 return wasSuccess;
389 }
390
MPUreset()391 void emuEngine::MPUreset()
392 {
393 if (MPUstatus)
394 {
395 initInterpreter(config.memoryMode);
396 c64memClear();
397 c64memReset(config.clockSpeed,randomSeed);
398 }
399 }
400
MPUreturnRAMbase()401 ubyte * emuEngine::MPUreturnRAMbase()
402 {
403 if (MPUstatus)
404 {
405 return c64mem1;
406 }
407 else
408 {
409 return 0;
410 }
411 }
412
setRandomSeed()413 void emuEngine::setRandomSeed()
414 {
415 time_t now = time(NULL);
416 randomSeed = (ubyte)now;
417 }
418
reset()419 bool emuEngine::reset()
420 {
421 if (isReady)
422 {
423 // Check internal mixer state whether tables have to be redone.
424 if (config.digiPlayerScans != 0)
425 {
426 if (isThreeVoiceAmplified != isThreeVoiceTune) // needs diff.ampl.
427 {
428 initMixerEngine();
429 }
430 }
431 else if (isThreeVoiceAmplified) // and do not want amplification
432 {
433 initMixerEngine();
434 }
435 extern bool sidEmuReset();
436 sidEmuReset();
437
438 resetSampleEmu();
439 }
440 return isReady;
441 }
442
resetSampleEmu()443 bool emuEngine::resetSampleEmu()
444 {
445 sampleEmuReset();
446 return true;
447 }
448
amplifyThreeVoiceTunes(bool inIsThreeVoiceTune)449 void emuEngine::amplifyThreeVoiceTunes(bool inIsThreeVoiceTune)
450 {
451 // ::initMixerEngine depends on this and config.digiPlayerScans.
452 // Specify whether a sidtune uses only three voices (here: no digis).
453 isThreeVoiceTune = inIsThreeVoiceTune;
454 }
455
456 // Initialize the SID chip and everything that depends on the frequency.
configureSID()457 void emuEngine::configureSID()
458 {
459 extern void sidEmuConfigure(udword PCMfrequency, bool measuredEnveValues,
460 bool isNewSID, bool emulateFilter, int clockSpeed);
461 sidEmuConfigure(config.frequency,config.measuredVolume,config.mos8580,
462 config.emulateFilter,config.clockSpeed);
463 }
464
initMixerEngine()465 void emuEngine::initMixerEngine()
466 {
467 uword uk;
468
469 // If just three (instead of four) voices, do different amplification,
470 // if that is desired (digiPlayerScans!=0).
471 if ((config.digiPlayerScans!=0) && isThreeVoiceTune)
472 {
473 isThreeVoiceAmplified = true;
474 }
475 else
476 {
477 isThreeVoiceAmplified = false;
478 }
479
480 #if defined(SID_FPUMIXERINIT)
481 sdword si, sj;
482
483 // 8-bit volume modulation tables.
484 float filterAmpl = 1.0;
485 if (config.emulateFilter)
486 {
487 filterAmpl = 0.7;
488 }
489 uk = 0;
490 for ( si = 0; si < 256; si++ )
491 {
492 for ( sj = -128; sj < 128; sj++, uk++ )
493 {
494 ampMod1x8[uk] = (sbyte)(((si*sj)/255)*filterAmpl);
495 }
496 }
497
498 // Determine single-voice de-amplification.
499 float ampDiv; // logical voices per physical channel
500 if ( config.volumeControl == SIDEMU_HWMIXING )
501 {
502 ampDiv = 1.0;
503 }
504 else if ((config.channels==SIDEMU_STEREO) &&
505 ((config.volumeControl==SIDEMU_NONE)
506 ||(config.volumeControl==SIDEMU_VOLCONTROL)))
507 {
508 ampDiv = 2.0;
509 }
510 else // SIDEMU_MONO or SIDEMU_FULLPANNING or SIDEMU_STEREOSURROUND
511 {
512 if (isThreeVoiceAmplified)
513 {
514 ampDiv = 3.0;
515 }
516 else
517 {
518 ampDiv = 4.0;
519 }
520 }
521
522 uk = 0;
523 for ( si = 0; si < 256; si++ )
524 {
525 for ( sj = -128; sj < 128; sj++, uk++ )
526 {
527 // 8-bit mixing modulation tables.
528 signedPanMix8[uk] = (sbyte)(((si*sj)/255)/ampDiv);
529 // 16-bit mixing modulation tables.
530 signedPanMix16[uk] = (uword)((si*sj)/ampDiv);
531 }
532 }
533 #else
534 sdword si, sj;
535
536 // 8-bit volume modulation tables.
537 sword filterAmpl = 10;
538 if (config.emulateFilter)
539 {
540 filterAmpl = 7;
541 }
542 uk = 0;
543 for ( si = 0; si < 256; si++ )
544 {
545 for ( sj = -128; sj < 128; sj++, uk++ )
546 {
547 ampMod1x8[uk] = (sbyte)((si*sj*filterAmpl)/(255*10));
548 }
549 }
550
551 // Determine single-voice de-amplification.
552 short ampDiv; // logical voices per physical channel
553 if ( config.volumeControl == SIDEMU_HWMIXING )
554 {
555 ampDiv = 1;
556 }
557 else if ((config.channels==SIDEMU_STEREO) &&
558 ((config.volumeControl==SIDEMU_NONE)
559 ||(config.volumeControl==SIDEMU_VOLCONTROL)))
560 {
561 ampDiv = 2;
562 }
563 else // SIDEMU_MONO or SIDEMU_FULLPANNING or SIDEMU_STEREOSURROUND
564 {
565 if (isThreeVoiceAmplified)
566 {
567 ampDiv = 3;
568 }
569 else
570 {
571 ampDiv = 4;
572 }
573 }
574
575 uk = 0;
576 for ( si = 0; si < 256; si++ )
577 {
578 for ( sj = -128; sj < 128; sj++, uk++ )
579 {
580 // 8-bit mixing modulation tables.
581 signedPanMix8[uk] = (sbyte)((si*sj)/(255*ampDiv));
582 // 16-bit mixing modulation tables.
583 signedPanMix16[uk] = (uword)((si*sj)/ampDiv);
584 }
585 }
586 #endif
587
588 // ------------------------------------------------- Init mixer function.
589
590 extern void* fill8bitMono(void*, udword);
591 extern void* fill8bitMonoControl(void*, udword);
592 extern void* fill8bitSplit(void*, udword);
593 extern void* fill8bitStereo(void*, udword);
594 extern void* fill8bitStereoControl(void*, udword);
595 extern void* fill8bitStereoSurround(void*, udword);
596 extern void* fill16bitMono(void*, udword);
597 extern void* fill16bitMonoControl(void*, udword);
598 extern void* fill16bitStereo(void*, udword);
599 extern void* fill16bitStereoControl(void*, udword);
600 extern void* fill16bitStereoSurround(void*, udword);
601 extern void* fill16bitSplit(void*, udword);
602
603 typedef void* (*ptr2fillfunc)(void*,udword);
604 // Fill function lookup-table.
605 // bits, mono/stereo, control
606 const ptr2fillfunc fillfunctions[2][2][4] =
607 {
608 {
609 {
610 &fill8bitMono, &fill8bitSplit, &fill8bitMonoControl, &fill8bitMonoControl
611 },
612 {
613 &fill8bitStereo, &fill8bitSplit, &fill8bitStereoControl, &fill8bitStereoSurround
614 },
615 },
616 {
617 {
618 &fill16bitMono, &fill16bitSplit, &fill16bitMonoControl, &fill16bitMonoControl
619 },
620 {
621 &fill16bitStereo, &fill16bitSplit, &fill16bitStereoControl, &fill16bitStereoSurround
622 },
623 }
624 };
625
626 int bitsIndex, monoIndex, controlIndex;
627
628 // Define the ``zero'' sample for signed or unsigned samples.
629 ubyte zero8bit = 0x80;
630 uword zero16bit = 0;
631
632 if ( config.bitsPerSample == SIDEMU_16BIT )
633 {
634 bitsIndex = 1;
635 switch( config.sampleFormat )
636 {
637 // waveform and amplification tables are signed samples,
638 // so adjusting the sign should do the conversion
639 case SIDEMU_SIGNED_PCM:
640 {
641 zero16bit = 0;
642 break;
643 }
644 case SIDEMU_UNSIGNED_PCM:
645 default:
646 {
647 zero16bit = 0x8000;
648 break;
649 }
650 }
651 }
652 else // if ( config.bitsPerSample == SIDEMU_8BIT )
653 {
654 bitsIndex = 0;
655 switch( config.sampleFormat )
656 {
657 // waveform and amplification tables are signed samples,
658 // so adjusting the sign should do the conversion
659 case SIDEMU_SIGNED_PCM:
660 {
661 zero8bit = 0;
662 break;
663 }
664 case SIDEMU_UNSIGNED_PCM:
665 default:
666 {
667 zero8bit = 0x80;
668 break;
669 }
670 }
671 } // end else config.bitsPerSample
672
673 switch( config.channels )
674 {
675 case SIDEMU_MONO:
676 {
677 monoIndex = 0;
678 break;
679 }
680 case SIDEMU_STEREO:
681 default:
682 {
683 monoIndex = 1;
684 break;
685 }
686 }
687
688 if ( config.volumeControl == SIDEMU_NONE )
689 controlIndex = 0;
690 else if ( config.volumeControl == SIDEMU_HWMIXING )
691 controlIndex = 1;
692 else if ( config.volumeControl == SIDEMU_STEREOSURROUND )
693 controlIndex = 3;
694 else
695 controlIndex = 2;
696
697 extern void* (*sidEmuFillFunc)(void*, udword);
698 sidEmuFillFunc = fillfunctions[bitsIndex][monoIndex][controlIndex];
699
700 // Call a function which inits more local tables.
701 extern void MixerInit(bool threeVoiceAmplify, ubyte zero8, uword zero16);
702 MixerInit(isThreeVoiceAmplified,zero8bit,zero16bit);
703
704 // ----------------------------------------------------------------------
705
706 // ensure that samplebuffer will be divided into
707 // correct number of samples
708 // 8-bit mono: buflen x = x samples
709 // stereo: = x/2 samples
710 // 16-bit mono: buflen x = x/2 samples
711 // stereo: = x/4 samples
712 extern ubyte bufferScale;
713 bufferScale = 0;
714 // HWMIXING mode does not know about stereo.
715 if ((config.channels == SIDEMU_STEREO)
716 && !(config.volumeControl == SIDEMU_HWMIXING))
717 bufferScale++;
718 if ( config.bitsPerSample == SIDEMU_16BIT )
719 bufferScale++;
720 }
721
722
setDefaultVoiceVolumes()723 void emuEngine::setDefaultVoiceVolumes()
724 {
725 // Adjust default mixing gain. Does not matter, whether this will be used.
726 // Signed 8-bit samples will be added to base array index.
727 // So middle must be 0x80.
728 // [-80,-81,...,-FE,-FF,0,1,...,7E,7F]
729 // Mono: left channel only used.
730 if ( config.channels == SIDEMU_MONO )
731 {
732 setVoiceVolume(1,255,0,256);
733 setVoiceVolume(2,255,0,256);
734 setVoiceVolume(3,255,0,256);
735 setVoiceVolume(4,255,0,256);
736 }
737 // Stereo:
738 else
739 { // if ( config.channels == SIDEMU_STEREO )
740 if ( config.volumeControl == SIDEMU_STEREOSURROUND )
741 {
742 setVoiceVolume(1,255,255,256);
743 setVoiceVolume(2,255,255,256);
744 setVoiceVolume(3,255,255,256);
745 setVoiceVolume(4,255,255,256);
746 }
747 else
748 {
749 setVoiceVolume(1,255,0,256);
750 setVoiceVolume(2,0,255,256);
751 setVoiceVolume(3,255,0,256);
752 setVoiceVolume(4,0,255,256);
753 }
754 }
755 }
756
757
filterTableInit()758 void emuEngine::filterTableInit()
759 {
760 uword uk;
761 // Parameter calculation has not been moved to a separate function
762 // by purpose.
763 const float filterRefFreq = 44100.0;
764
765 extern filterfloat filterTable[0x800];
766 float yMax = 1.0;
767 float yMin = 0.01;
768 uk = 0;
769 for ( float rk = 0; rk < 0x800; rk++ )
770 {
771 filterTable[uk] = (((exp(rk/0x800*log(config.filterFs))/config.filterFm)+config.filterFt)
772 *filterRefFreq) / config.frequency;
773 if ( filterTable[uk] < yMin )
774 filterTable[uk] = yMin;
775 if ( filterTable[uk] > yMax )
776 filterTable[uk] = yMax;
777 uk++;
778 }
779
780 extern filterfloat bandPassParam[0x800];
781 yMax = 0.22;
782 yMin = 0.05; // less for some R1/R4 chips
783 float yAdd = (yMax-yMin)/2048.0;
784 float yTmp = yMin;
785 uk = 0;
786 // Some C++ compilers still have non-local scope!
787 for ( float rk2 = 0; rk2 < 0x800; rk2++ )
788 {
789 bandPassParam[uk] = (yTmp*filterRefFreq) / config.frequency;
790 yTmp += yAdd;
791 uk++;
792 }
793
794 extern filterfloat filterResTable[16];
795 float resDyMax = 1.0;
796 float resDyMin = 2.0;
797 float resDy = resDyMin;
798 for ( uk = 0; uk < 16; uk++ )
799 {
800 filterResTable[uk] = resDy;
801 resDy -= (( resDyMin - resDyMax ) / 15 );
802 }
803 filterResTable[0] = resDyMin;
804 filterResTable[15] = resDyMax;
805 }
806
setVoiceVolume(int voice,ubyte leftLevel,ubyte rightLevel,uword total)807 bool emuEngine::setVoiceVolume(int voice, ubyte leftLevel, ubyte rightLevel, uword total)
808 {
809 if ( config.volumeControl == SIDEMU_NONE )
810 return false;
811 if ((voice < 1) || (voice > 4) || (total > 256))
812 return false;
813 if ( config.channels == SIDEMU_MONO )
814 rightLevel = 0;
815 extern void sidEmuSetVoiceVolume(int v,uword L,uword R,uword T);
816 sidEmuSetVoiceVolume(voice,leftLevel,rightLevel,total);
817 return true;
818 }
819
getVoiceVolume(int voice)820 uword emuEngine::getVoiceVolume(int voice)
821 {
822 extern uword sidEmuReturnVoiceVolume(int);
823 if (( voice < 1 ) || ( voice > 4 ))
824 return 0;
825 else
826 return sidEmuReturnVoiceVolume(voice);
827 }
828