Merge branch 'master' of https://github.com/tildearrow/furnace into es5506_alt

This commit is contained in:
cam900 2023-01-12 23:31:56 +09:00
commit 536c345763
137 changed files with 2912 additions and 1818 deletions

View file

@ -77,6 +77,15 @@ const char* DivEngine::getEffectDesc(unsigned char effect, int chan, bool notNul
return "81xx: Set panning (left channel)";
case 0x82:
return "82xx: Set panning (right channel)";
case 0x88:
return "88xx: Set panning (rear channels; x: left; y: right)";
break;
case 0x89:
return "89xx: Set panning (rear left channel)";
break;
case 0x8a:
return "8Axx: Set panning (rear right channel)";
break;
case 0xc0: case 0xc1: case 0xc2: case 0xc3:
return "Cxxx: Set tick rate (hz)";
case 0xe0:
@ -435,6 +444,7 @@ void writePackedCommandValues(SafeWriter* w, const DivCommand& c) {
case DIV_CMD_FM_FINE:
case DIV_CMD_AY_IO_WRITE:
case DIV_CMD_AY_AUTO_PWM:
case DIV_CMD_SURROUND_PANNING:
w->writeC(2); // length
w->writeC(c.value);
w->writeC(c.value2);
@ -897,11 +907,7 @@ void DivEngine::runExportThread() {
for (int i=0; i<song.systemLen; i++) {
sf[i]=NULL;
si[i].samplerate=got.rate;
if (disCont[i].dispatch->isStereo()) {
si[i].channels=2;
} else {
si[i].channels=1;
}
si[i].channels=disCont[i].dispatch->getOutputCount();
si[i].format=SF_FORMAT_WAV|SF_FORMAT_PCM_16;
}
@ -944,11 +950,12 @@ void DivEngine::runExportThread() {
if (isFadingOut) {
double mul=(1.0-((double)curFadeOutSample/(double)fadeOutSamples));
for (int i=0; i<song.systemLen; i++) {
if (!disCont[i].dispatch->isStereo()) {
sysBuf[i][j]=(double)disCont[i].bbOut[0][j]*mul;
} else {
sysBuf[i][j<<1]=(double)disCont[i].bbOut[0][j]*mul;
sysBuf[i][1+(j<<1)]=(double)disCont[i].bbOut[1][j]*mul;
for (int k=0; k<si[i].channels; k++) {
if (disCont[i].bbOut[k]==NULL) {
sysBuf[i][k+(j*si[i].channels)]=0;
} else {
sysBuf[i][k+(j*si[i].channels)]=(double)disCont[i].bbOut[k][j]*mul;
}
}
}
if (++curFadeOutSample>=fadeOutSamples) {
@ -957,11 +964,12 @@ void DivEngine::runExportThread() {
}
} else {
for (int i=0; i<song.systemLen; i++) {
if (!disCont[i].dispatch->isStereo()) {
sysBuf[i][j]=disCont[i].bbOut[0][j];
} else {
sysBuf[i][j<<1]=disCont[i].bbOut[0][j];
sysBuf[i][1+(j<<1)]=disCont[i].bbOut[1][j];
for (int k=0; k<si[i].channels; k++) {
if (disCont[i].bbOut[k]==NULL) {
sysBuf[i][k+(j*si[i].channels)]=0;
} else {
sysBuf[i][k+(j*si[i].channels)]=disCont[i].bbOut[k][j];
}
}
}
if (lastLoopPos>-1 && j>=lastLoopPos && totalLoops>=exportLoopCount) {
@ -1333,8 +1341,8 @@ String DivEngine::decodeSysDesc(String desc) {
int val=0;
int curStage=0;
int sysID=0;
int sysVol=0;
int sysPan=0;
float sysVol=0;
float sysPan=0;
int sysFlags=0;
int curSys=0;
desc+=' '; // ha
@ -1349,24 +1357,25 @@ String DivEngine::decodeSysDesc(String desc) {
curStage++;
break;
case 1:
sysVol=val;
sysVol=(float)val/64.0f;
curStage++;
break;
case 2:
sysPan=val;
sysPan=(float)val/127.0f;
curStage++;
break;
case 3:
sysFlags=val;
if (sysID!=0) {
if (sysVol<-128) sysVol=-128;
if (sysVol>127) sysVol=127;
if (sysPan<-128) sysPan=-128;
if (sysPan>127) sysPan=127;
if (sysVol<-1.0f) sysVol=-1.0f;
if (sysVol>1.0f) sysVol=1.0f;
if (sysPan<-1.0f) sysPan=-1.0f;
if (sysPan>1.0f) sysPan=1.0f;
newDesc.set(fmt::sprintf("id%d",curSys),sysID);
newDesc.set(fmt::sprintf("vol%d",curSys),sysVol);
newDesc.set(fmt::sprintf("pan%d",curSys),sysPan);
newDesc.set(fmt::sprintf("fr%d",curSys),0.0f);
DivConfig newFlagsC;
newFlagsC.clear();
convertOldFlags((unsigned int)sysFlags,newFlagsC,systemFromFileFur(sysID));
@ -1396,7 +1405,7 @@ String DivEngine::decodeSysDesc(String desc) {
return newDesc.toBase64();
}
void DivEngine::initSongWithDesc(const char* description, bool inBase64) {
void DivEngine::initSongWithDesc(const char* description, bool inBase64, bool oldVol) {
int chanCount=0;
DivConfig c;
if (inBase64) {
@ -1415,9 +1424,16 @@ void DivEngine::initSongWithDesc(const char* description, bool inBase64) {
song.system[index]=DIV_SYSTEM_NULL;
break;
}
song.systemVol[index]=c.getInt(fmt::sprintf("vol%d",index),DIV_SYSTEM_NULL);
song.systemPan[index]=c.getInt(fmt::sprintf("pan%d",index),DIV_SYSTEM_NULL);
song.systemVol[index]=c.getFloat(fmt::sprintf("vol%d",index),1.0f);
song.systemPan[index]=c.getFloat(fmt::sprintf("pan%d",index),0.0f);
song.systemPanFR[index]=c.getFloat(fmt::sprintf("fr%d",index),0.0f);
song.systemFlags[index].clear();
if (oldVol) {
song.systemVol[index]/=64.0f;
song.systemPan[index]/=127.0f;
}
String flags=c.getString(fmt::sprintf("flags%d",index),"");
song.systemFlags[index].loadFromBase64(flags.c_str());
}
@ -1667,14 +1683,36 @@ bool DivEngine::addSystem(DivSystem which) {
BUSY_BEGIN;
saveLock.lock();
song.system[song.systemLen]=which;
song.systemVol[song.systemLen]=64;
song.systemVol[song.systemLen]=1.0;
song.systemPan[song.systemLen]=0;
song.systemPanFR[song.systemLen]=0;
song.systemFlags[song.systemLen++].clear();
recalcChans();
saveLock.unlock();
BUSY_END;
initDispatch();
BUSY_BEGIN;
saveLock.lock();
if (song.patchbayAuto) {
autoPatchbay();
} else {
int i=song.systemLen-1;
if (disCont[i].dispatch!=NULL) {
unsigned int outs=disCont[i].dispatch->getOutputCount();
if (outs>16) outs=16;
if (outs<2) {
for (unsigned int j=0; j<DIV_MAX_OUTPUTS; j++) {
song.patchbay.push_back((i<<20)|j);
}
} else {
for (unsigned int j=0; j<outs; j++) {
song.patchbay.push_back((i<<20)|(j<<16)|j);
}
}
}
}
saveLock.unlock();
renderSamples();
reset();
BUSY_END;
@ -1707,12 +1745,21 @@ bool DivEngine::removeSystem(int index, bool preserveOrder) {
}
}
// patchbay
for (size_t i=0; i<song.patchbay.size(); i++) {
if (((song.patchbay[i]>>20)&0xfff)==(unsigned int)index) {
song.patchbay.erase(song.patchbay.begin()+i);
i--;
}
}
song.system[index]=DIV_SYSTEM_NULL;
song.systemLen--;
for (int i=index; i<song.systemLen; i++) {
song.system[i]=song.system[i+1];
song.systemVol[i]=song.systemVol[i+1];
song.systemPan[i]=song.systemPan[i+1];
song.systemPanFR[i]=song.systemPanFR[i+1];
song.systemFlags[i]=song.systemFlags[i+1];
}
recalcChans();
@ -1827,23 +1874,36 @@ bool DivEngine::swapSystem(int src, int dest, bool preserveOrder) {
}
DivSystem srcSystem=song.system[src];
float srcVol=song.systemVol[src];
float srcPan=song.systemPan[src];
float srcPanFR=song.systemPanFR[src];
song.system[src]=song.system[dest];
song.system[dest]=srcSystem;
song.systemVol[src]^=song.systemVol[dest];
song.systemVol[dest]^=song.systemVol[src];
song.systemVol[src]^=song.systemVol[dest];
song.systemVol[src]=song.systemVol[dest];
song.systemVol[dest]=srcVol;
song.systemPan[src]^=song.systemPan[dest];
song.systemPan[dest]^=song.systemPan[src];
song.systemPan[src]^=song.systemPan[dest];
song.systemPan[src]=song.systemPan[dest];
song.systemPan[dest]=srcPan;
song.systemPanFR[src]=song.systemPanFR[dest];
song.systemPanFR[dest]=srcPanFR;
// I am kinda scared to use std::swap
DivConfig oldFlags=song.systemFlags[src];
song.systemFlags[src]=song.systemFlags[dest];
song.systemFlags[dest]=oldFlags;
// patchbay
for (unsigned int& i: song.patchbay) {
if (((i>>20)&0xfff)==(unsigned int)src) {
i=(i&(~0xfff00000))|((unsigned int)dest<<20);
} else if (((i>>20)&0xfff)==(unsigned int)dest) {
i=(i&(~0xfff00000))|((unsigned int)src<<20);
}
}
recalcChans();
saveLock.unlock();
BUSY_END;
@ -1904,10 +1964,11 @@ String DivEngine::getPlaybackDebugInfo() {
"speed1: %d\n"
"speed2: %d\n"
"tempoAccum: %d\n"
"totalProcessed: %d\n",
"totalProcessed: %d\n"
"bufferPos: %d\n",
curOrder,prevOrder,curRow,prevRow,ticks,subticks,totalLoops,lastLoopPos,nextSpeed,divider,cycles,clockDrift,
changeOrd,changePos,totalSeconds,totalTicks,totalTicksR,totalCmds,lastCmds,cmdsPerSecond,globalPitch,
(int)extValue,(int)speed1,(int)speed2,(int)tempoAccum,(int)totalProcessed
(int)extValue,(int)speed1,(int)speed2,(int)tempoAccum,(int)totalProcessed,(int)bufferPos
);
}
@ -3752,6 +3813,102 @@ bool DivEngine::moveSampleDown(int which) {
return true;
}
void DivEngine::autoPatchbay() {
song.patchbay.clear();
for (unsigned int i=0; i<song.systemLen; i++) {
if (disCont[i].dispatch==NULL) continue;
unsigned int outs=disCont[i].dispatch->getOutputCount();
if (outs>16) outs=16;
if (outs<2) {
for (unsigned int j=0; j<DIV_MAX_OUTPUTS; j++) {
song.patchbay.push_back((i<<20)|j);
}
} else {
for (unsigned int j=0; j<outs; j++) {
song.patchbay.push_back((i<<20)|(j<<16)|j);
}
}
}
// wave/sample preview
for (unsigned int j=0; j<DIV_MAX_OUTPUTS; j++) {
song.patchbay.push_back(0xffd00000|j);
}
// metronome
for (unsigned int j=0; j<DIV_MAX_OUTPUTS; j++) {
song.patchbay.push_back(0xffe00000|j);
}
}
void DivEngine::autoPatchbayP() {
BUSY_BEGIN;
saveLock.lock();
autoPatchbay();
saveLock.unlock();
BUSY_END;
}
bool DivEngine::patchConnect(unsigned int src, unsigned int dest) {
unsigned int armed=(src<<16)|(dest&0xffff);
for (unsigned int i: song.patchbay) {
if (i==armed) return false;
}
BUSY_BEGIN;
saveLock.lock();
song.patchbay.push_back(armed);
song.patchbayAuto=false;
saveLock.unlock();
BUSY_END;
return true;
}
bool DivEngine::patchDisconnect(unsigned int src, unsigned int dest) {
unsigned int armed=(src<<16)|(dest&0xffff);
for (auto i=song.patchbay.begin(); i!=song.patchbay.end(); i++) {
if (*i==armed) {
BUSY_BEGIN;
saveLock.lock();
song.patchbay.erase(i);
song.patchbayAuto=false;
saveLock.unlock();
BUSY_END;
return true;
}
}
return false;
}
void DivEngine::patchDisconnectAll(unsigned int portSet) {
BUSY_BEGIN;
saveLock.lock();
if (portSet&0x1000) {
portSet&=0xfff;
for (size_t i=0; i<song.patchbay.size(); i++) {
if ((song.patchbay[i]&0xfff0)==(portSet<<4)) {
song.patchbay.erase(song.patchbay.begin()+i);
i--;
}
}
} else {
portSet&=0xfff;
for (size_t i=0; i<song.patchbay.size(); i++) {
if ((song.patchbay[i]&0xfff00000)==(portSet<<20)) {
song.patchbay.erase(song.patchbay.begin()+i);
i--;
}
}
}
saveLock.unlock();
BUSY_END;
}
void DivEngine::noteOn(int chan, int ins, int note, int vol) {
if (chan<0 || chan>=chans) return;
BUSY_BEGIN;
@ -3891,6 +4048,14 @@ void DivEngine::updateSysFlags(int system, bool restart) {
BUSY_BEGIN_SOFT;
disCont[system].dispatch->setFlags(song.systemFlags[system]);
disCont[system].setRates(got.rate);
// patchbay
if (song.patchbayAuto) {
saveLock.lock();
autoPatchbay();
saveLock.unlock();
}
if (restart && isPlaying()) {
playSub(false);
}
@ -4055,6 +4220,11 @@ void DivEngine::initDispatch() {
disCont[i].setRates(got.rate);
disCont[i].setQuality(lowQuality);
}
if (song.patchbayAuto) {
saveLock.lock();
autoPatchbay();
saveLock.unlock();
}
recalcChans();
BUSY_END;
}
@ -4153,10 +4323,13 @@ bool DivEngine::initAudioBackend() {
want.rate=getConfInt("audioRate",44100);
want.fragments=2;
want.inChans=0;
want.outChans=2;
want.outChans=getConfInt("audioChans",2);
want.outFormat=TA_AUDIO_FORMAT_F32;
want.name="Furnace";
if (want.outChans<1) want.outChans=1;
if (want.outChans>16) want.outChans=16;
output->setCallback(process,this);
if (!output->init(want,got)) {
@ -4167,6 +4340,13 @@ bool DivEngine::initAudioBackend() {
return false;
}
for (int i=0; i<got.outChans; i++) {
if (oscBuf[i]==NULL) {
oscBuf[i]=new float[32768];
}
memset(oscBuf[i],0,32768*sizeof(float));
}
if (output->initMidi(false)) {
midiIns=output->midiIn->listDevices();
midiOuts=output->midiOut->listDevices();
@ -4248,13 +4428,15 @@ bool DivEngine::init() {
if (!hasLoadedSomething) {
logD("setting default preset");
String preset=getConfString("initialSys2","");
bool oldVol=getConfInt("configVersion",DIV_ENGINE_VERSION)<135;
if (preset.empty()) {
// try loading old preset
preset=decodeSysDesc(getConfString("initialSys",""));
oldVol=false;
}
logD("preset size %ld",preset.size());
if (preset.size()>0 && (preset.size()&3)==0) {
initSongWithDesc(preset.c_str());
initSongWithDesc(preset.c_str(),true,oldVol);
}
String sysName=getConfString("initialSysName","");
if (sysName=="") {
@ -4283,6 +4465,9 @@ bool DivEngine::init() {
samp_bbIn=new short[32768];
samp_bbInLen=32768;
metroBuf=new float[8192];
metroBufLen=8192;
blip_set_rates(samp_bb,44100,got.rate);
@ -4299,12 +4484,6 @@ bool DivEngine::init() {
keyHit[i]=false;
}
oscBuf[0]=new float[32768];
oscBuf[1]=new float[32768];
memset(oscBuf[0],0,32768*sizeof(float));
memset(oscBuf[1],0,32768*sizeof(float));
initDispatch();
renderSamples();
reset();
@ -4313,6 +4492,10 @@ bool DivEngine::init() {
if (!haveAudio) {
return false;
} else {
if (output==NULL) {
logE("output is NULL!");
return false;
}
if (!output->setRun(true)) {
logE("error while activating!");
return false;
@ -4327,8 +4510,14 @@ bool DivEngine::quit() {
logI("saving config.");
saveConf();
active=false;
delete[] oscBuf[0];
delete[] oscBuf[1];
for (int i=0; i<DIV_MAX_OUTPUTS; i++) {
if (oscBuf[i]!=NULL) delete[] oscBuf[i];
}
if (metroBuf!=NULL) {
delete[] metroBuf;
metroBuf=NULL;
metroBufLen=0;
}
if (yrw801ROM!=NULL) delete[] yrw801ROM;
if (tg100ROM!=NULL) delete[] tg100ROM;
if (mu5ROM!=NULL) delete[] mu5ROM;