/** * Furnace Tracker - multi-system chiptune tracker * Copyright (C) 2021-2022 tildearrow and contributors * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "blip_buf.h" #include "engine.h" #include "platform/genesis.h" #include "platform/genesisext.h" #include "platform/sms.h" #include "platform/opll.h" #include "platform/gb.h" #include "platform/pce.h" #include "platform/nes.h" #include "platform/c64.h" #include "platform/arcade.h" #include "platform/tx81z.h" #include "platform/ym2203.h" #include "platform/ym2203ext.h" #include "platform/ym2608.h" #include "platform/ym2608ext.h" #include "platform/ym2610.h" #include "platform/ym2610ext.h" #include "platform/ym2610b.h" #include "platform/ym2610bext.h" #include "platform/ay.h" #include "platform/ay8930.h" #include "platform/opl.h" #include "platform/tia.h" #include "platform/saa.h" #include "platform/amiga.h" #include "platform/pcspkr.h" #include "platform/segapcm.h" #include "platform/qsound.h" #include "platform/vera.h" #include "platform/x1_010.h" #include "platform/su.h" #include "platform/swan.h" #include "platform/lynx.h" #include "platform/bubsyswsg.h" #include "platform/n163.h" #include "platform/pet.h" #include "platform/vic20.h" #include "platform/vrc6.h" #include "platform/fds.h" #include "platform/mmc5.h" #include "platform/scc.h" #include "platform/dummy.h" #include "../ta-log.h" #include "platform/zxbeeper.h" #include "song.h" void DivDispatchContainer::setRates(double gotRate) { blip_set_rates(bb[0],dispatch->rate,gotRate); blip_set_rates(bb[1],dispatch->rate,gotRate); } void DivDispatchContainer::setQuality(bool lowQual) { lowQuality=lowQual; } void DivDispatchContainer::acquire(size_t offset, size_t count) { dispatch->acquire(bbIn[0],bbIn[1],offset,count); } void DivDispatchContainer::flush(size_t count) { blip_read_samples(bb[0],bbOut[0],count,0); if (dispatch->isStereo()) { blip_read_samples(bb[1],bbOut[1],count,0); } } void DivDispatchContainer::fillBuf(size_t runtotal, size_t offset, size_t size) { if (dcOffCompensation && runtotal>0) { dcOffCompensation=false; prevSample[0]=bbIn[0][0]; if (dispatch->isStereo()) prevSample[1]=bbIn[1][0]; } if (lowQuality) { for (size_t i=0; iisStereo()) for (size_t i=0; iisStereo()) for (size_t i=0; i0) { for (size_t i=totalRead; iisStereo()) { blip_end_frame(bb[1],runtotal); blip_read_samples(bb[1],bbOut[1]+offset,size,0); } } void DivDispatchContainer::clear() { blip_clear(bb[0]); blip_clear(bb[1]); temp[0]=0; temp[1]=0; prevSample[0]=0; prevSample[1]=0; if (dispatch->getDCOffRequired()) { dcOffCompensation=true; } // run for one cycle to determine DC offset // TODO: SAA1099 doesn't like that /*dispatch->acquire(bbIn[0],bbIn[1],0,1); temp[0]=bbIn[0][0]; temp[1]=bbIn[1][0]; prevSample[0]=temp[0]; prevSample[1]=temp[1];*/ } void DivDispatchContainer::init(DivSystem sys, DivEngine* eng, int chanCount, double gotRate, unsigned int flags) { if (dispatch!=NULL) return; bb[0]=blip_new(32768); if (bb[0]==NULL) { logE("not enough memory!"); return; } bb[1]=blip_new(32768); if (bb[1]==NULL) { logE("not enough memory!"); return; } bbOut[0]=new short[32768]; bbOut[1]=new short[32768]; bbIn[0]=new short[32768]; bbIn[1]=new short[32768]; bbInLen=32768; switch (sys) { case DIV_SYSTEM_YMU759: dispatch=new DivPlatformOPL; ((DivPlatformOPL*)dispatch)->setOPLType(759,false); break; case DIV_SYSTEM_YM2612: dispatch=new DivPlatformGenesis; ((DivPlatformGenesis*)dispatch)->setYMFM(eng->getConfInt("ym2612Core",0)); break; case DIV_SYSTEM_YM2612_EXT: dispatch=new DivPlatformGenesisExt; ((DivPlatformGenesisExt*)dispatch)->setYMFM(eng->getConfInt("ym2612Core",0)); break; case DIV_SYSTEM_SMS: dispatch=new DivPlatformSMS; break; case DIV_SYSTEM_GB: dispatch=new DivPlatformGB; break; case DIV_SYSTEM_PCE: dispatch=new DivPlatformPCE; break; case DIV_SYSTEM_NES: dispatch=new DivPlatformNES; ((DivPlatformNES*)dispatch)->setNSFPlay(eng->getConfInt("nesCore",0)==1); break; case DIV_SYSTEM_C64_6581: dispatch=new DivPlatformC64; ((DivPlatformC64*)dispatch)->setChipModel(true); break; case DIV_SYSTEM_C64_8580: dispatch=new DivPlatformC64; ((DivPlatformC64*)dispatch)->setChipModel(false); break; case DIV_SYSTEM_YM2151: dispatch=new DivPlatformArcade; ((DivPlatformArcade*)dispatch)->setYMFM(eng->getConfInt("arcadeCore",0)==0); break; case DIV_SYSTEM_YM2610: case DIV_SYSTEM_YM2610_FULL: dispatch=new DivPlatformYM2610; break; case DIV_SYSTEM_YM2610_EXT: case DIV_SYSTEM_YM2610_FULL_EXT: dispatch=new DivPlatformYM2610Ext; break; case DIV_SYSTEM_YM2610B: dispatch=new DivPlatformYM2610B; break; case DIV_SYSTEM_YM2610B_EXT: dispatch=new DivPlatformYM2610BExt; break; case DIV_SYSTEM_AMIGA: dispatch=new DivPlatformAmiga; break; case DIV_SYSTEM_AY8910: dispatch=new DivPlatformAY8910; break; case DIV_SYSTEM_AY8930: dispatch=new DivPlatformAY8930; break; case DIV_SYSTEM_FDS: dispatch=new DivPlatformFDS; ((DivPlatformFDS*)dispatch)->setNSFPlay(eng->getConfInt("fdsCore",0)==1); break; case DIV_SYSTEM_TIA: dispatch=new DivPlatformTIA; break; case DIV_SYSTEM_OPN: dispatch=new DivPlatformYM2203; break; case DIV_SYSTEM_OPN_EXT: dispatch=new DivPlatformYM2203Ext; break; case DIV_SYSTEM_PC98: dispatch=new DivPlatformYM2608; break; case DIV_SYSTEM_PC98_EXT: dispatch=new DivPlatformYM2608Ext; break; case DIV_SYSTEM_OPLL: case DIV_SYSTEM_OPLL_DRUMS: case DIV_SYSTEM_VRC7: dispatch=new DivPlatformOPLL; ((DivPlatformOPLL*)dispatch)->setVRC7(sys==DIV_SYSTEM_VRC7); ((DivPlatformOPLL*)dispatch)->setProperDrums(sys==DIV_SYSTEM_OPLL_DRUMS); break; case DIV_SYSTEM_OPL: dispatch=new DivPlatformOPL; ((DivPlatformOPL*)dispatch)->setOPLType(1,false); break; case DIV_SYSTEM_OPL_DRUMS: dispatch=new DivPlatformOPL; ((DivPlatformOPL*)dispatch)->setOPLType(1,true); break; case DIV_SYSTEM_OPL2: dispatch=new DivPlatformOPL; ((DivPlatformOPL*)dispatch)->setOPLType(2,false); break; case DIV_SYSTEM_OPL2_DRUMS: dispatch=new DivPlatformOPL; ((DivPlatformOPL*)dispatch)->setOPLType(2,true); break; case DIV_SYSTEM_OPL3: dispatch=new DivPlatformOPL; ((DivPlatformOPL*)dispatch)->setOPLType(3,false); break; case DIV_SYSTEM_OPL3_DRUMS: dispatch=new DivPlatformOPL; ((DivPlatformOPL*)dispatch)->setOPLType(3,true); break; case DIV_SYSTEM_Y8950: dispatch=new DivPlatformOPL; ((DivPlatformOPL*)dispatch)->setOPLType(8950,false); break; case DIV_SYSTEM_Y8950_DRUMS: dispatch=new DivPlatformOPL; ((DivPlatformOPL*)dispatch)->setOPLType(8950,true); break; case DIV_SYSTEM_OPZ: dispatch=new DivPlatformTX81Z; break; case DIV_SYSTEM_SAA1099: { int saaCore=eng->getConfInt("saaCore",1); if (saaCore<0 || saaCore>2) saaCore=0; dispatch=new DivPlatformSAA1099; ((DivPlatformSAA1099*)dispatch)->setCore((DivSAACores)saaCore); break; } case DIV_SYSTEM_PCSPKR: dispatch=new DivPlatformPCSpeaker; break; case DIV_SYSTEM_SFX_BEEPER: dispatch=new DivPlatformZXBeeper; break; case DIV_SYSTEM_LYNX: dispatch=new DivPlatformLynx; break; case DIV_SYSTEM_QSOUND: dispatch=new DivPlatformQSound; break; case DIV_SYSTEM_SEGAPCM: case DIV_SYSTEM_SEGAPCM_COMPAT: dispatch=new DivPlatformSegaPCM; break; case DIV_SYSTEM_X1_010: dispatch=new DivPlatformX1_010; break; case DIV_SYSTEM_SWAN: dispatch=new DivPlatformSwan; break; case DIV_SYSTEM_VERA: dispatch=new DivPlatformVERA; break; case DIV_SYSTEM_BUBSYS_WSG: dispatch=new DivPlatformBubSysWSG; break; case DIV_SYSTEM_N163: dispatch=new DivPlatformN163; break; case DIV_SYSTEM_PET: dispatch=new DivPlatformPET; break; case DIV_SYSTEM_VIC20: dispatch=new DivPlatformVIC20; break; case DIV_SYSTEM_VRC6: dispatch=new DivPlatformVRC6; break; case DIV_SYSTEM_MMC5: dispatch=new DivPlatformMMC5; break; case DIV_SYSTEM_SCC: dispatch=new DivPlatformSCC; ((DivPlatformSCC*)dispatch)->setChipModel(false); break; case DIV_SYSTEM_SCC_PLUS: dispatch=new DivPlatformSCC; ((DivPlatformSCC*)dispatch)->setChipModel(true); break; case DIV_SYSTEM_SOUND_UNIT: dispatch=new DivPlatformSoundUnit; break; case DIV_SYSTEM_DUMMY: dispatch=new DivPlatformDummy; break; default: logW("this system is not supported yet! using dummy platform."); dispatch=new DivPlatformDummy; break; } dispatch->init(eng,chanCount,gotRate,flags); } void DivDispatchContainer::quit() { if (dispatch==NULL) return; dispatch->quit(); delete dispatch; dispatch=NULL; delete[] bbOut[0]; delete[] bbOut[1]; delete[] bbIn[0]; delete[] bbIn[1]; bbInLen=0; blip_delete(bb[0]); blip_delete(bb[1]); }