00001
00002
00003
00004
00005
00006
00007 #include "eeconfig.h"
00008 #include "mixing.h"
00009
00010
00011
00012
00013 EXPORT_C emuEngine::emuEngine()
00014 :bufferScale(0)
00015 {
00016 CTOR(emuEngine);
00017
00018
00019 config.frequency = 22050;
00020 config.bitsPerSample = SIDEMU_8BIT;
00021 config.sampleFormat = SIDEMU_UNSIGNED_PCM;
00022 config.channels = SIDEMU_MONO;
00023 config.sidChips = 1;
00024 config.volumeControl = SIDEMU_NONE;
00025 config.mos8580 = false;
00026 config.measuredVolume = true;
00027 config.digiPlayerScans = 10*50;
00028 config.emulateFilter = true;
00029 config.autoPanning = SIDEMU_NONE;
00030 config.memoryMode = MPU_TRANSPARENT_ROM;
00031 config.clockSpeed = SIDTUNE_CLOCK_PAL;
00032 config.forceSongSpeed = false;
00033
00034 #if defined(SIDEMU_TIME_COUNT)
00035
00036 bytesCount = 0;
00037 secondsTotal = (secondsThisSong = 0);
00038 #endif
00039
00040 isThreeVoiceTune = false;
00041
00042
00043 iThe6510 = new C6510;
00044
00045
00046 MPUstatus = iThe6510->c64memAlloc();
00047
00048
00049 iTheSidEmu = new sidEmu(this);
00050 iTheMixer = new Mixer(this, iTheSidEmu);
00051
00052 iTheSidEmu->sidEmuResetAutoPanning(config.autoPanning);
00053
00054
00055 if ( MPUstatus && allocMem() )
00056 {
00057 setRandomSeed();
00058 MPUreset();
00059 configureSID();
00060 initMixerEngine();
00061 setDefaultVoiceVolumes();
00062 setDefaultFilterStrength();
00063 reset();
00064 isReady = true;
00065 }
00066 else
00067 {
00068 isReady = false;
00069 }
00070 }
00071
00072
00073
00074 emuEngine::~emuEngine()
00075 {
00076 DTOR(emuEngine);
00077 freeMem();
00078
00079 delete iTheMixer;
00080 delete iTheSidEmu;
00081 delete iThe6510;
00082 }
00083
00084
00085
00086 EXPORT_C bool emuEngine::setConfig( struct emuConfig& inCfg )
00093 {
00094 bool gotInvalidConfig = false;
00095
00096
00097 if ((inCfg.memoryMode == MPU_BANK_SWITCHING)
00098 || (inCfg.memoryMode == MPU_TRANSPARENT_ROM)
00099 || (inCfg.memoryMode == MPU_PLAYSID_ENVIRONMENT))
00100 {
00101 config.memoryMode = inCfg.memoryMode;
00102 }
00103 else
00104 {
00105 gotInvalidConfig = true;
00106 }
00107
00108
00109
00110 bool newSIDconfig = false;
00111
00112 if ((inCfg.clockSpeed == SIDTUNE_CLOCK_PAL)
00113 || (inCfg.clockSpeed == SIDTUNE_CLOCK_NTSC))
00114 {
00115 if (inCfg.clockSpeed != config.clockSpeed)
00116 {
00117 config.clockSpeed = inCfg.clockSpeed;
00118 newSIDconfig = true;
00119 }
00120 }
00121 else
00122 {
00123 gotInvalidConfig = true;
00124 }
00125
00126 if (inCfg.forceSongSpeed != config.forceSongSpeed)
00127 {
00128 config.forceSongSpeed = (inCfg.forceSongSpeed == true);
00129 }
00130
00131
00132 if (( inCfg.frequency >= 4000 ) && ( inCfg.frequency <= 48000 ))
00133 {
00134
00135 if ( inCfg.frequency != config.frequency )
00136 {
00137 config.frequency = inCfg.frequency;
00138 newSIDconfig = true;
00139 }
00140 }
00141 else
00142 {
00143 gotInvalidConfig = true;
00144 }
00145
00146 if (inCfg.measuredVolume != config.measuredVolume)
00147 {
00148 config.measuredVolume = (inCfg.measuredVolume == true);
00149 newSIDconfig = true;
00150 }
00151
00152
00153
00154
00155 bool newMixerSettings = false;
00156
00157
00158 if (( inCfg.sampleFormat == SIDEMU_UNSIGNED_PCM )
00159 || ( inCfg.sampleFormat == SIDEMU_SIGNED_PCM ))
00160 {
00161
00162 if ( inCfg.sampleFormat != config.sampleFormat )
00163 {
00164 config.sampleFormat = inCfg.sampleFormat;
00165 newMixerSettings = true;
00166 }
00167 }
00168 else
00169 {
00170 gotInvalidConfig = true;
00171 }
00172
00173
00174 if (( inCfg.channels == SIDEMU_MONO )
00175 || ( inCfg.channels == SIDEMU_STEREO ))
00176 {
00177
00178 if ( inCfg.channels != config.channels )
00179 {
00180 config.channels = inCfg.channels;
00181 setDefaultVoiceVolumes();
00182 newMixerSettings = true;
00183 }
00184 }
00185 else
00186 {
00187 gotInvalidConfig = true;
00188 }
00189
00190
00191 if (( inCfg.bitsPerSample == SIDEMU_8BIT )
00192 || ( inCfg.bitsPerSample == SIDEMU_16BIT ))
00193 {
00194
00195 if ( inCfg.bitsPerSample != config.bitsPerSample )
00196 {
00197 config.bitsPerSample = inCfg.bitsPerSample;
00198 newMixerSettings = true;
00199 }
00200 }
00201 else
00202 {
00203 gotInvalidConfig = true;
00204 }
00205
00206
00207 if (( inCfg.volumeControl == SIDEMU_NONE )
00208 || ( inCfg.volumeControl == SIDEMU_VOLCONTROL )
00209 || ( inCfg.volumeControl == SIDEMU_FULLPANNING )
00210 || ( inCfg.volumeControl == SIDEMU_HWMIXING )
00211 || ( inCfg.volumeControl == SIDEMU_STEREOSURROUND ))
00212 {
00213
00214 if ( inCfg.volumeControl != config.volumeControl )
00215 {
00216 config.volumeControl = inCfg.volumeControl;
00217 setDefaultVoiceVolumes();
00218 newMixerSettings = true;
00219 }
00220 }
00221 else
00222 {
00223 gotInvalidConfig = true;
00224 }
00225
00226 if ((inCfg.autoPanning == SIDEMU_NONE)
00227 || (inCfg.autoPanning == SIDEMU_CENTEREDAUTOPANNING))
00228 {
00229 if (inCfg.autoPanning != config.autoPanning)
00230 {
00231 config.autoPanning = inCfg.autoPanning;
00232 if (config.autoPanning != SIDEMU_NONE)
00233 {
00234 if (( config.volumeControl != SIDEMU_FULLPANNING )
00235 && ( config.volumeControl != SIDEMU_STEREOSURROUND ))
00236 {
00237 config.autoPanning = false;
00238 gotInvalidConfig = true;
00239 }
00240 }
00241
00242 iTheSidEmu->sidEmuResetAutoPanning(config.autoPanning);
00243 }
00244 }
00245 else
00246 {
00247 gotInvalidConfig = true;
00248 }
00249
00250 if (inCfg.emulateFilter != config.emulateFilter)
00251 {
00252 config.emulateFilter = (inCfg.emulateFilter == true);
00253 newSIDconfig = true;
00254 newMixerSettings = true;
00255 }
00256
00257 if (( inCfg.filterFs >= 1.0 ) && ( inCfg.filterFm != 0 ))
00258 {
00259
00260 if ((inCfg.filterFs != config.filterFs)
00261 || (inCfg.filterFm != config.filterFm)
00262 || (inCfg.filterFt != config.filterFt))
00263 {
00264 config.filterFs = inCfg.filterFs;
00265 config.filterFm = inCfg.filterFm;
00266 config.filterFt = inCfg.filterFt;
00267 filterTableInit();
00268 }
00269 }
00270 else
00271 {
00272 gotInvalidConfig = true;
00273 }
00274
00275 if (inCfg.digiPlayerScans != config.digiPlayerScans)
00276 {
00277 config.digiPlayerScans = (inCfg.digiPlayerScans == true);
00278 newMixerSettings = true;
00279 }
00280
00281 if ((config.channels==SIDEMU_MONO) &&
00282 ((config.volumeControl==SIDEMU_STEREOSURROUND)
00283 ||(config.autoPanning!=SIDEMU_NONE)))
00284 {
00285 gotInvalidConfig = true;
00286 }
00287
00288 if (inCfg.mos8580 != config.mos8580)
00289 {
00290 config.mos8580 = (inCfg.mos8580 == true);
00291 newSIDconfig = true;
00292 }
00293
00294
00295 if (newSIDconfig)
00296 {
00297 configureSID();
00298 }
00299
00300
00301 if (newMixerSettings)
00302 {
00303 initMixerEngine();
00304 }
00305
00306
00307 return !gotInvalidConfig;
00308 }
00309
00310 EXPORT_C void emuEngine::getConfig( struct emuConfig& outCfg )
00311 {
00312 outCfg = config;
00313 }
00314
00315 void emuEngine::setDefaultFilterStrength()
00316 {
00317 config.filterFs = SIDEMU_DEFAULTFILTERFS;
00318 config.filterFm = SIDEMU_DEFAULTFILTERFM;
00319 config.filterFt = SIDEMU_DEFAULTFILTERFT;
00320 filterTableInit();
00321 }
00322
00323 EXPORT_C bool emuEngine::verifyEndianess()
00324 {
00325
00326 ubyte endTest[2];
00327 writeLEword(endTest,0x55aa);
00328 if (0xaa55!=readBEword(endTest))
00329 return false;
00330 else
00331 return true;
00332 }
00333
00334 EXPORT_C void emuEngine::FillBuffer(sidTune& thistune, void* buffer, udword bufferLen)
00335 {
00336 iTheSidEmu->sidEmuFillBuffer(*this, thistune, buffer, bufferLen);
00337 }
00338
00339
00340 #if defined(SIDEMU_TIME_COUNT)
00341 EXPORT_C int emuEngine::getSecondsThisSong()
00342 {
00343 return secondsThisSong;
00344 }
00345
00346 EXPORT_C int emuEngine::getSecondsTotal()
00347 {
00348 return secondsTotal;
00349 }
00350 #endif
00351
00352
00353
00354 bool emuEngine::freeMem()
00355 {
00356 if ( ampMod1x8 != 0 )
00357 delete[] ampMod1x8;
00358 ampMod1x8 = 0;
00359 if ( iTheMixer->signedPanMix8 != 0 )
00360 delete[] iTheMixer->signedPanMix8;
00361 iTheMixer->signedPanMix8 = 0;
00362 if ( iTheMixer->signedPanMix16 != 0 )
00363 delete[] iTheMixer->signedPanMix16;
00364 iTheMixer->signedPanMix16 = 0;
00365 return true;
00366 }
00367
00368 bool emuEngine::allocMem()
00369 {
00370
00371 bool wasSuccess = true;
00372
00373
00374 if (( ampMod1x8 = new sbyte[256*256] ) == 0 )
00375 wasSuccess = false;
00376 if (( iTheMixer->signedPanMix8 = new sbyte[256*256] ) == 0 )
00377 wasSuccess = false;
00378
00379 if (( iTheMixer->signedPanMix16 = new sword[256*256] ) == 0 )
00380 wasSuccess = false;
00381
00382 if (!wasSuccess)
00383 {
00384 freeMem();
00385 }
00386 return wasSuccess;
00387 }
00388
00389 void emuEngine::MPUreset()
00390 {
00391 if (MPUstatus)
00392 {
00393 iThe6510->initInterpreter(config.memoryMode);
00394 iThe6510->c64memClear();
00395 iThe6510->c64memReset(config.clockSpeed,randomSeed);
00396 }
00397 }
00398
00399 ubyte * emuEngine::MPUreturnRAMbase()
00400 {
00401 if (MPUstatus)
00402 {
00403 return iThe6510->c64mem1;
00404 }
00405 else
00406 {
00407 return 0;
00408 }
00409 }
00410
00411 void emuEngine::setRandomSeed()
00412 {
00413 time_t now = time(NULL);
00414 randomSeed = (ubyte)now;
00415 }
00416
00417 bool emuEngine::reset()
00418 {
00419 if (isReady)
00420 {
00421
00422 if (config.digiPlayerScans != 0)
00423 {
00424 if (isThreeVoiceAmplified != isThreeVoiceTune)
00425 {
00426 initMixerEngine();
00427 }
00428 }
00429 else if (isThreeVoiceAmplified)
00430 {
00431 initMixerEngine();
00432 }
00433
00434 iTheSidEmu->sidEmuReset();
00435
00436 resetSampleEmu();
00437 }
00438 return isReady;
00439 }
00440
00441 bool emuEngine::resetSampleEmu()
00442 {
00443 iTheSidEmu->iTheSampler->sampleEmuReset(iTheSidEmu);
00444 return true;
00445 }
00446
00447 void emuEngine::amplifyThreeVoiceTunes(bool inIsThreeVoiceTune)
00448 {
00449
00450
00451 isThreeVoiceTune = inIsThreeVoiceTune;
00452 }
00453
00454
00455 void emuEngine::configureSID()
00456 {
00457 iTheSidEmu->sidEmuConfigure(config);
00458 }
00459
00460 void emuEngine::initMixerEngine()
00461 {
00462 ELOG1(_L8("initMixerEngine\n"));
00463
00464 uword uk;
00465
00466
00467
00468 if ((config.digiPlayerScans!=0) && isThreeVoiceTune)
00469 {
00470 isThreeVoiceAmplified = true;
00471 }
00472 else
00473 {
00474 isThreeVoiceAmplified = false;
00475 }
00476
00477 #if defined(SID_FPUMIXERINIT)
00478 sdword si, sj;
00479
00480
00481 float filterAmpl = 1.0;
00482 if (config.emulateFilter)
00483 {
00484 filterAmpl = 0.7f;
00485 }
00486 uk = 0;
00487 for ( si = 0; si < 256; si++ )
00488 {
00489 for ( sj = -128; sj < 128; sj++, uk++ )
00490 {
00491 ampMod1x8[uk] = (sbyte)(((si*sj)/255)*filterAmpl);
00492 }
00493 }
00494
00495
00496 float ampDiv;
00497 if ( config.volumeControl == SIDEMU_HWMIXING )
00498 {
00499 ampDiv = 1.0;
00500 }
00501 else if ((config.channels==SIDEMU_STEREO) &&
00502 ((config.volumeControl==SIDEMU_NONE)
00503 ||(config.volumeControl==SIDEMU_VOLCONTROL)))
00504 {
00505 ampDiv = 2.0;
00506 }
00507 else
00508 {
00509 if (isThreeVoiceAmplified)
00510 {
00511 ampDiv = 3.0;
00512 }
00513 else
00514 {
00515 ampDiv = 4.0;
00516 }
00517 }
00518
00519 uk = 0;
00520 for ( si = 0; si < 256; si++ )
00521 {
00522 for ( sj = -128; sj < 128; sj++, uk++ )
00523 {
00524
00525 iTheMixer->signedPanMix8[uk] = (sbyte)(((si*sj)/255)/ampDiv);
00526
00527
00528 iTheMixer->signedPanMix16[uk] = (sword)((si*sj)/ampDiv);
00529 }
00530 }
00531 #else
00532 sdword si, sj;
00533
00534
00535 sword filterAmpl = 10;
00536 if (config.emulateFilter)
00537 {
00538 filterAmpl = 7;
00539 }
00540 uk = 0;
00541 for ( si = 0; si < 256; si++ )
00542 {
00543 for ( sj = -128; sj < 128; sj++, uk++ )
00544 {
00545 ampMod1x8[uk] = (sbyte)((si*sj*filterAmpl)/(255*10));
00546 }
00547 }
00548
00549
00550 short ampDiv;
00551 if ( config.volumeControl == SIDEMU_HWMIXING )
00552 {
00553 ampDiv = 1;
00554 }
00555 else if ((config.channels==SIDEMU_STEREO) &&
00556 ((config.volumeControl==SIDEMU_NONE)
00557 ||(config.volumeControl==SIDEMU_VOLCONTROL)))
00558 {
00559 ampDiv = 2;
00560 }
00561 else
00562 {
00563 if (isThreeVoiceAmplified)
00564 {
00565 ampDiv = 3;
00566 }
00567 else
00568 {
00569 ampDiv = 4;
00570 }
00571 }
00572
00573 uk = 0;
00574 for ( si = 0; si < 256; si++ )
00575 {
00576 for ( sj = -128; sj < 128; sj++, uk++ )
00577 {
00578
00579 iTheMixer->signedPanMix8[uk] = (sbyte)((si*sj)/(255*ampDiv));
00580
00581 iTheMixer->signedPanMix16[uk] = (uword)((si*sj)/ampDiv);
00582 }
00583 }
00584 #endif
00585
00586
00587
00588 typedef void* (Mixer::*ptr2fillfunc)(void*,udword);
00589
00590
00591 const ptr2fillfunc fillfunctions[2][2][4] =
00592 {
00593 {
00594 {
00595 &Mixer::fill8bitMono,
00596 &Mixer::fill8bitsplit,
00597 &Mixer::fill8bitMonoControl,
00598 &Mixer::fill8bitMonoControl
00599 },
00600 {
00601 &Mixer::fill8bitStereo,
00602 &Mixer::fill8bitsplit,
00603 &Mixer::fill8bitStereoControl,
00604 &Mixer::fill8bitStereoSurround
00605 },
00606 },
00607 {
00608 {
00609 &Mixer::fill16bitMono,
00610 &Mixer::fill16bitsplit,
00611 &Mixer::fill16bitMonoControl,
00612 &Mixer::fill16bitMonoControl
00613 },
00614 {
00615 &Mixer::fill16bitStereo,
00616 &Mixer::fill16bitsplit,
00617 &Mixer::fill16bitStereoControl,
00618 &Mixer::fill16bitStereoSurround
00619 },
00620 }
00621 };
00622
00623 int bitsIndex, monoIndex, controlIndex;
00624
00625
00626 ubyte zero8bit = 0x80;
00627 uword zero16bit = 0;
00628
00629 if ( config.bitsPerSample == SIDEMU_16BIT )
00630 {
00631 bitsIndex = 1;
00632 switch( config.sampleFormat )
00633 {
00634
00635
00636 case SIDEMU_SIGNED_PCM:
00637 {
00638 zero16bit = 0;
00639 break;
00640 }
00641 case SIDEMU_UNSIGNED_PCM:
00642 default:
00643 {
00644 zero16bit = 0x8000;
00645 break;
00646 }
00647 }
00648 }
00649 else
00650 {
00651 bitsIndex = 0;
00652 switch( config.sampleFormat )
00653 {
00654
00655
00656 case SIDEMU_SIGNED_PCM:
00657 {
00658 zero8bit = 0;
00659 break;
00660 }
00661 case SIDEMU_UNSIGNED_PCM:
00662 default:
00663 {
00664 zero8bit = 0x80;
00665 break;
00666 }
00667 }
00668 }
00669
00670 switch( config.channels )
00671 {
00672 case SIDEMU_MONO:
00673 {
00674 monoIndex = 0;
00675 break;
00676 }
00677 case SIDEMU_STEREO:
00678 default:
00679 {
00680 monoIndex = 1;
00681 break;
00682 }
00683 }
00684
00685 if ( config.volumeControl == SIDEMU_NONE )
00686 controlIndex = 0;
00687 else if ( config.volumeControl == SIDEMU_HWMIXING )
00688 controlIndex = 1;
00689 else if ( config.volumeControl == SIDEMU_STEREOSURROUND )
00690 controlIndex = 3;
00691 else
00692 controlIndex = 2;
00693
00694 iTheMixer->sidEmuFillFunc = fillfunctions[bitsIndex][monoIndex][controlIndex];
00695
00696
00697 iTheMixer->MixerInit(isThreeVoiceAmplified,zero8bit,zero16bit);
00698
00699
00700
00701
00702
00703
00704
00705
00706
00707 bufferScale = 0;
00708
00709 if ((config.channels == SIDEMU_STEREO)
00710 && !(config.volumeControl == SIDEMU_HWMIXING))
00711 bufferScale++;
00712 if ( config.bitsPerSample == SIDEMU_16BIT )
00713 bufferScale++;
00714 }
00715
00716
00717 void emuEngine::setDefaultVoiceVolumes()
00718 {
00719
00720
00721
00722
00723
00724 if ( config.channels == SIDEMU_MONO )
00725 {
00726 setVoiceVolume(1,255,0,256);
00727 setVoiceVolume(2,255,0,256);
00728 setVoiceVolume(3,255,0,256);
00729 setVoiceVolume(4,255,0,256);
00730 }
00731
00732 else
00733 {
00734 if ( config.volumeControl == SIDEMU_STEREOSURROUND )
00735 {
00736 setVoiceVolume(1,255,255,256);
00737 setVoiceVolume(2,255,255,256);
00738 setVoiceVolume(3,255,255,256);
00739 setVoiceVolume(4,255,255,256);
00740 }
00741 else
00742 {
00743 setVoiceVolume(1,255,0,256);
00744 setVoiceVolume(2,0,255,256);
00745 setVoiceVolume(3,255,0,256);
00746 setVoiceVolume(4,0,255,256);
00747 }
00748 }
00749 }
00750
00751
00752 void emuEngine::filterTableInit()
00753 {
00754 uword uk;
00755
00756
00757
00758 float* filterTable = iTheSidEmu->filterTable;
00759
00760 float yMax = 1.0;
00761 float yMin = (float)0.01;
00762 uk = 0;
00763 for ( float rk = 0; rk < 0x800; rk++ )
00764 {
00765 filterTable[uk] = (float)(( exp( rk/2048*log(config.filterFs) ) / config.filterFm ) + config.filterFt);
00766 if ( filterTable[uk] < yMin )
00767 filterTable[uk] = yMin;
00768 if ( filterTable[uk] > yMax )
00769 filterTable[uk] = yMax;
00770 uk++;
00771 }
00772
00773 float* bandPassParam = iTheSidEmu->bandPassParam;
00774
00775 yMax = (float)0.22;
00776 yMin = (float)0.002;
00777 float yAdd = (float)((yMax-yMin)/2048.0);
00778 float yTmp = yMin;
00779 uk = 0;
00780 for ( float rk2 = 0; rk2 < 0x800; rk2++ )
00781 {
00782 bandPassParam[uk] = yTmp;
00783 yTmp += yAdd;
00784 uk++;
00785 }
00786
00787 float* filterResTable = iTheSidEmu->filterResTable;
00788
00789 float resDyMax = 1.0;
00790 float resDyMin = 2.0;
00791 float resDy = resDyMin;
00792 for ( uk = 0; uk < 16; uk++ )
00793 {
00794 filterResTable[uk] = resDy;
00795 resDy -= (( resDyMin - resDyMax ) / 15 );
00796 }
00797 filterResTable[0] = resDyMin;
00798 filterResTable[15] = resDyMax;
00799 }
00800
00801 bool emuEngine::setVoiceVolume(int voice, ubyte leftLevel, ubyte rightLevel, uword total)
00802 {
00803 if ( config.volumeControl == SIDEMU_NONE )
00804 return false;
00805 if ((voice < 1) || (voice > 4) || (total > 256))
00806 return false;
00807 if ( config.channels == SIDEMU_MONO )
00808 rightLevel = 0;
00809
00810 iTheSidEmu->sidEmuSetVoiceVolume(voice,leftLevel,rightLevel,total);
00811 return true;
00812 }
00813
00814 uword emuEngine::getVoiceVolume(int voice)
00815 {
00816
00817 if (( voice < 1 ) || ( voice > 4 ))
00818 return false;
00819 else
00820 return iTheSidEmu->sidEmuReturnVoiceVolume(voice);
00821 }