furnace/src/engine/dispatchContainer.cpp
cam900 234c5e9295 Reduce naming confusion in Bubble System Wavetable Sound
It means Custom wavetable sound generator logic on Bubble System.
It's wavetable select and volume is controlled by single AY-3-8910 IO for both channels, Another AY-3-8910 IO is used for reading sound status.

Schematics: http://pdf.textfiles.com/manuals/ARCADE/K-R/Nemesis%20[Schematics]%20[English].pdf (Nemesis, derivative of Bubble system)
2022-03-17 10:11:48 +09:00

300 lines
8.4 KiB
C++

/**
* 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/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/swan.h"
#include "platform/lynx.h"
#include "platform/bubsyswsg.h"
#include "platform/dummy.h"
#include "../ta-log.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 (lowQuality) {
for (size_t i=0; i<runtotal; i++) {
temp[0]=bbIn[0][i];
blip_add_delta_fast(bb[0],i,temp[0]-prevSample[0]);
prevSample[0]=temp[0];
}
if (dispatch->isStereo()) for (size_t i=0; i<runtotal; i++) {
temp[1]=bbIn[1][i];
blip_add_delta_fast(bb[1],i,temp[1]-prevSample[1]);
prevSample[1]=temp[1];
}
} else {
for (size_t i=0; i<runtotal; i++) {
temp[0]=bbIn[0][i];
blip_add_delta(bb[0],i,temp[0]-prevSample[0]);
prevSample[0]=temp[0];
}
if (dispatch->isStereo()) for (size_t i=0; i<runtotal; i++) {
temp[1]=bbIn[1][i];
blip_add_delta(bb[1],i,temp[1]-prevSample[1]);
prevSample[1]=temp[1];
}
}
blip_end_frame(bb[0],runtotal);
blip_read_samples(bb[0],bbOut[0]+offset,size,0);
/*if (totalRead<(int)size && totalRead>0) {
for (size_t i=totalRead; i<size; i++) {
bbOut[0][i]=bbOut[0][totalRead-1];//bbOut[0][totalRead];
}
}*/
if (dispatch->isStereo()) {
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;
// 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!\n");
return;
}
bb[1]=blip_new(32768);
if (bb[1]==NULL) {
logE("not enough memory!\n");
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;
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_TIA:
dispatch=new DivPlatformTIA;
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_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_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;
default:
logW("this system is not supported yet! using dummy platform.\n");
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]);
}