diff --git a/scripts/release-winxp.sh b/scripts/release-winxp.sh index 71ff675ea..5901f1643 100755 --- a/scripts/release-winxp.sh +++ b/scripts/release-winxp.sh @@ -15,7 +15,7 @@ fi cd xpbuild # TODO: potential Arch-ism? -i686-w64-mingw32-cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_C_FLAGS="-O2" -DCMAKE_CXX_FLAGS="-O2 -Wall -Wextra -Wno-unused-parameter -Wno-cast-function-type" -DBUILD_SHARED_LIBS=OFF -DSUPPORT_XP=ON -DWITH_RENDER_DX11=OFF -DSDL_SSE2=OFF -DSDL_SSE3=OFF -DENABLE_SSE=OFF -DENABLE_SSE2=OFF -DENABLE_AVX=OFF -DENABLE_AVX2=OFF .. || exit 1 +i686-w64-mingw32-cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_C_FLAGS="-O2" -DCMAKE_CXX_FLAGS="-O2 -Wall -Wextra -Wno-unused-parameter -Wno-cast-function-type" -DBUILD_SHARED_LIBS=OFF -DSUPPORT_XP=ON -DWITH_RENDER_DX11=OFF -DSDL_SSE2=OFF -DSDL_SSE3=OFF -DENABLE_SSE=OFF -DENABLE_SSE2=OFF -DENABLE_AVX=OFF -DENABLE_AVX2=OFF -DUSE_BACKWARD=ON .. || exit 1 make -j8 || exit 1 cd .. diff --git a/src/engine/platform/dave.cpp b/src/engine/platform/dave.cpp index fbe91ae33..d316ae58f 100644 --- a/src/engine/platform/dave.cpp +++ b/src/engine/platform/dave.cpp @@ -25,7 +25,7 @@ //#define rWrite(a,v) pendingWrites[a]=v; #define rWrite(a,v) if (!skipRegisterWrites) {writes.push(QueuedWrite(a,v)); if (dumpWrites) {addWrite(a,v);} } -#define CHIP_DIVIDER 32 +#define CHIP_DIVIDER 8 const char* regCheatSheetDave[]={ "Freq0", "00", @@ -48,36 +48,54 @@ const char* regCheatSheetDave[]={ NULL }; +const unsigned char snapPeriodLong[15]={ + 0, 1, 3, 3, 3, 6, 6, 7, 7, 10, 10, 12, 12, 13, 13 +}; + +const unsigned char snapPeriodShort[15]={ + 2, 2, 2, 2, 5, 5, 5, 8, 8, 8, 11, 11, 11, 11, 11 +}; + +const unsigned char waveMap[8]={ + 0, 1, 1, 2, 3, 0, 0, 0 +}; + const char** DivPlatformDave::getRegisterSheet() { return regCheatSheetDave; } void DivPlatformDave::acquire(short** buf, size_t len) { for (size_t h=0; hrate) { DivSample* s=parent->getSample(chan[i].dacSample); if (s->samples<=0) { chan[i].dacSample=-1; + writeControl=true; + chan[0].writeVol=true; continue; } - signed char dacData=((signed char)((unsigned char)s->data8[chan[i].dacPos]^0x80))>>3; - chan[i].dacOut=CLAMP(dacData,-16,15); + signed char dacData=(s->data8[chan[i].dacPos]*chan[i].outVol)>>8; + chan[i].dacOut=dacData+32; chan[i].dacPos++; + if (!isMuted[i]) { + rWrite(8+((i-4)<<2),chan[i].dacOut&0x3f); + } if (s->isLoopable() && chan[i].dacPos>=(unsigned int)s->loopEnd) { chan[i].dacPos=s->loopStart; } else if (chan[i].dacPos>=s->samples) { chan[i].dacSample=-1; + writeControl=true; + chan[0].writeVol=true; } chan[i].dacPeriod-=rate; } } } - while (!writes.empty()) { + if (!writes.empty()) { QueuedWrite w=writes.front(); dave->writePort(w.addr,w.val); regPool[w.addr&0x1f]=w.val; @@ -101,18 +119,24 @@ void DivPlatformDave::tick(bool sysTick) { chan[i].writeVol=true; } if (chan[i].std.duty.had) { + chan[i].noiseFreq=chan[i].std.duty.val&3; chan[i].freqChanged=true; } if (NEW_ARP_STRAT) { chan[i].handleArp(); } else if (chan[i].std.arp.had) { if (!chan[i].inPorta) { - chan[i].baseFreq=parent->calcArp(chan[i].note,chan[i].std.arp.val); + if (i>=4) { + chan[i].baseFreq=parent->calcBaseFreq(1,1,parent->calcArp(chan[i].note,chan[i].std.arp.val),false); + } else { + chan[i].baseFreq=NOTE_PERIODIC(parent->calcArp(chan[i].note,chan[i].std.arp.val)); + } } chan[i].freqChanged=true; } if (chan[i].std.wave.had) { - chan[i].wave=chan[i].std.wave.val; + chan[i].wave=chan[i].std.wave.val&7; + if (i==3 && chan[i].wave>3) chan[i].wave=3; chan[i].freqChanged=true; } if (chan[i].std.panL.had) { @@ -124,6 +148,13 @@ void DivPlatformDave::tick(bool sysTick) { if (chan[i].std.panL.had || chan[i].std.panR.had) { chan[i].writeVol=true; } + if (chan[i].std.ex1.had) { + chan[i].highPass=chan[i].std.ex1.val&1; + chan[i].ringMod=chan[i].std.ex1.val&2; + chan[i].swapCounters=chan[i].std.ex1.val&4; + chan[i].lowPass=chan[i].std.ex1.val&8; + chan[i].freqChanged=true; + } if (chan[i].std.pitch.had) { if (chan[i].std.pitch.mode) { chan[i].pitch2+=chan[i].std.pitch.val; @@ -140,53 +171,135 @@ void DivPlatformDave::tick(bool sysTick) { chan[i].dacPeriod=0; chan[i].keyOn=true; } + } else { + chan[i].resetPhase=true; + writeControl=true; } } if (chan[i].writeVol) { - if (chan[i].active) { - rWrite(8+i,(63+chan[i].outVol*chan[i].panL)>>6); - rWrite(12+i,(63+chan[i].outVol*chan[i].panR)>>6); - } else { - rWrite(8+i,0); - rWrite(12+i,0); + if (i<4) { + if (chan[i].active && !isMuted[i]) { + if (i!=0 || chan[4].dacSample<0) { + rWrite(8+i,(63+chan[i].outVol*chan[i].panL)>>6); + } + if (i!=0 || chan[5].dacSample<0) { + rWrite(12+i,(63+chan[i].outVol*chan[i].panR)>>6); + } + } else { + if (i!=0 || chan[4].dacSample<0) { + rWrite(8+i,0); + } + if (i!=0 || chan[5].dacSample<0) { + rWrite(12+i,0); + } + } } + chan[i].writeVol=false; } if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) { - //DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_PCE); - chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,chan[i].fixedArp?chan[i].baseNoteOverride:chan[i].arpOff,chan[i].fixedArp,true,0,chan[i].pitch2,chipClock,CHIP_DIVIDER); - if (chan[i].freq<1) chan[i].freq=1; - if (chan[i].freq>4095) chan[i].freq=4095; + if (i>=4) { + chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,chan[i].fixedArp?chan[i].baseNoteOverride:chan[i].arpOff,chan[i].fixedArp,false,0,chan[i].pitch2,1,1); + } else { + chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,chan[i].fixedArp?chan[i].baseNoteOverride:chan[i].arpOff,chan[i].fixedArp,true,0,chan[i].pitch2,chipClock,CHIP_DIVIDER); + } if (i<3) { - rWrite((i<<1),chan[i].freq&0xff); - rWrite(1+(i<<1),(chan[i].freq>>8)|((chan[i].wave&3)<<4)); + switch (chan[i].wave) { + case 0: + chan[i].freq>>=2; + break; + case 1: + chan[i].freq/=5; + chan[i].freq>>=1; + break; + case 2: + chan[i].freq/=15; + chan[i].freq>>=1; + break; + case 3: + chan[i].freq/=63; + break; + case 4: + chan[i].freq>>=5; + break; + } } - if (chan[i].keyOn) { + if (i<4) { + if (chan[i].freq<1) chan[i].freq=1; + if (chan[i].freq>4095) chan[i].freq=4095; } - if (chan[i].keyOff) { + + if (i<3) { + if (chan[i].wave==1) { // short 1 + chan[i].freq=15*(chan[i].freq/15)+snapPeriodShort[(chan[i].freq%15)]; + } else if (chan[i].wave==2) { // long 1 + chan[i].freq=15*(chan[i].freq/15)+snapPeriodLong[(chan[i].freq%15)]; + } else if (chan[i].wave==3) { // long 2 (30, 61, 92, 123... result in silence) + if ((chan[i].freq%30)==(chan[i].freq/30)-1) chan[i].freq++; + } + rWrite((i<<1),chan[i].freq&0xff); + rWrite(1+(i<<1),(chan[i].freq>>8)|((waveMap[chan[i].wave])<<4)|(chan[i].highPass?0x40:0)|(chan[i].ringMod?0x80:0)); + } else if (i==3) { + rWrite(6,(chan[i].noiseFreq&3)|((chan[i].wave&3)<<2)|(chan[i].swapCounters?0x10:0)|(chan[i].lowPass?0x20:0)|(chan[i].highPass?0x40:0)|(chan[i].ringMod?0x80:0)); } + if (chan[i].keyOn) chan[i].keyOn=false; if (chan[i].keyOff) chan[i].keyOff=false; chan[i].freqChanged=false; } } + + if (writeControl) { + rWrite(7,(chan[0].resetPhase?1:0)|(chan[1].resetPhase?2:0)|(chan[2].resetPhase?4:0)|((chan[4].dacSample>=0)?8:0)|((chan[5].dacSample>=0)?16:0)); + rWrite(7,((chan[4].dacSample>=0)?8:0)|((chan[5].dacSample>=0)?16:0)); + chan[0].resetPhase=false; + chan[1].resetPhase=false; + chan[2].resetPhase=false; + chan[3].resetPhase=false; + writeControl=false; + } } int DivPlatformDave::dispatch(DivCommand c) { switch (c.cmd) { case DIV_CMD_NOTE_ON: { - DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_PCE); - // TODO: handle DAC - if (c.chan>=4) break; - chan[c.chan].sampleNote=DIV_NOTE_NULL; - chan[c.chan].sampleNoteDelta=0; - if (c.value!=DIV_NOTE_NULL) { - chan[c.chan].baseFreq=NOTE_PERIODIC(c.value); - chan[c.chan].freqChanged=true; - chan[c.chan].note=c.value; + DivInstrument* ins=NULL; + // DAC + if (c.chan>=4) { + ins=parent->getIns(chan[c.chan].ins,DIV_INS_AMIGA); + if (c.value!=DIV_NOTE_NULL) { + chan[c.chan].dacSample=ins->amiga.getSample(c.value); + chan[c.chan].sampleNote=c.value; + c.value=ins->amiga.getFreq(c.value); + chan[c.chan].sampleNoteDelta=c.value-chan[c.chan].sampleNote; + } else if (chan[c.chan].sampleNote!=DIV_NOTE_NULL) { + chan[c.chan].dacSample=ins->amiga.getSample(chan[c.chan].sampleNote); + c.value=ins->amiga.getFreq(chan[c.chan].sampleNote); + } + if (chan[c.chan].dacSample<0 || chan[c.chan].dacSample>=parent->song.sampleLen) { + chan[c.chan].dacSample=-1; + chan[0].writeVol=true; + } + if (c.value!=DIV_NOTE_NULL) { + chan[c.chan].baseFreq=parent->calcBaseFreq(1,1,c.value,false); + chan[c.chan].freqChanged=true; + chan[c.chan].note=c.value; + } + chan[c.chan].dacPos=0; + chan[c.chan].dacPeriod=0; + writeControl=true; + } else { + ins=parent->getIns(chan[c.chan].ins,DIV_INS_DAVE); + chan[c.chan].sampleNote=DIV_NOTE_NULL; + chan[c.chan].sampleNoteDelta=0; + if (c.value!=DIV_NOTE_NULL) { + chan[c.chan].baseFreq=NOTE_PERIODIC(c.value); + chan[c.chan].freqChanged=true; + chan[c.chan].note=c.value; + } } chan[c.chan].active=true; chan[c.chan].keyOn=true; @@ -202,6 +315,11 @@ int DivPlatformDave::dispatch(DivCommand c) { chan[c.chan].active=false; chan[c.chan].keyOff=true; chan[c.chan].writeVol=true; + if (c.chan>=4) { + chan[c.chan].dacSample=-1; + chan[0].writeVol=true; + writeControl=true; + } chan[c.chan].macroInit(NULL); break; case DIV_CMD_NOTE_OFF_ENV: @@ -220,6 +338,7 @@ int DivPlatformDave::dispatch(DivCommand c) { if (!chan[c.chan].std.vol.has) { chan[c.chan].outVol=c.value; if (chan[c.chan].active) { + chan[c.chan].writeVol=true; } } } @@ -236,7 +355,7 @@ int DivPlatformDave::dispatch(DivCommand c) { break; case DIV_CMD_WAVE: chan[c.chan].wave=c.value; - chan[c.chan].keyOn=true; + chan[c.chan].freqChanged=true; break; case DIV_CMD_NOTE_PORTA: { int destFreq=NOTE_PERIODIC(c.value2+chan[c.chan].sampleNoteDelta); @@ -267,13 +386,13 @@ int DivPlatformDave::dispatch(DivCommand c) { break; } case DIV_CMD_LEGATO: - chan[c.chan].baseFreq=NOTE_PERIODIC(c.value+chan[c.chan].sampleNoteDelta+((HACKY_LEGATO_MESS)?(chan[c.chan].std.arp.val):(0))); + chan[c.chan].baseFreq=NOTE_PERIODIC(c.value+chan[c.chan].sampleNoteDelta); chan[c.chan].freqChanged=true; chan[c.chan].note=c.value; break; case DIV_CMD_PRE_PORTA: if (chan[c.chan].active && c.value2) { - if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_PCE)); + if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_DAVE)); } if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note); chan[c.chan].inPorta=c.value; @@ -298,14 +417,16 @@ int DivPlatformDave::dispatch(DivCommand c) { void DivPlatformDave::muteChannel(int ch, bool mute) { isMuted[ch]=mute; - // TODO + chan[ch].writeVol=true; } void DivPlatformDave::forceIns() { for (int i=0; i<6; i++) { chan[i].insChanged=true; chan[i].freqChanged=true; + chan[i].writeVol=true; } + writeControl=true; } void* DivPlatformDave::getChanState(int ch) { @@ -364,16 +485,8 @@ void DivPlatformDave::reset() { if (dumpWrites) { addWrite(0xffffffff,0); } + writeControl=false; dave->reset(true); - lastPan=0xff; - cycles=0; - curChan=-1; - // set global volume - rWrite(0,0); - rWrite(0x01,0xff); - // set per-channel initial panning - for (int i=0; i<6; i++) { - } } int DivPlatformDave::getOutputCount() { diff --git a/src/engine/platform/dave.h b/src/engine/platform/dave.h index 0af0e2a26..9fea7a3b1 100644 --- a/src/engine/platform/dave.h +++ b/src/engine/platform/dave.h @@ -29,10 +29,11 @@ class DivPlatformDave: public DivDispatch { int dacPeriod, dacRate, dacOut; unsigned int dacPos; int dacSample; + unsigned char noiseFreq; unsigned char panL; unsigned char panR; unsigned char wave; - bool writeVol; + bool writeVol, highPass, ringMod, swapCounters, lowPass, resetPhase; Channel(): SharedChannel(63), dacPeriod(0), @@ -40,10 +41,16 @@ class DivPlatformDave: public DivDispatch { dacOut(0), dacPos(0), dacSample(-1), + noiseFreq(0), panL(63), panR(63), wave(0), - writeVol(false) {} + writeVol(false), + highPass(false), + ringMod(false), + swapCounters(false), + lowPass(false), + resetPhase(false) {} }; Channel chan[6]; DivDispatchOscBuffer* oscBuf[6]; @@ -55,9 +62,8 @@ class DivPlatformDave: public DivDispatch { QueuedWrite(unsigned char a, unsigned char v): addr(a), val(v) {} }; FixedQueue writes; - unsigned char lastPan; + bool writeControl; - int cycles, curChan; Ep128::Dave* dave; unsigned char regPool[32]; friend void putDispatchChip(void*,int); diff --git a/src/engine/sysDef.cpp b/src/engine/sysDef.cpp index 684226515..96b5228e2 100644 --- a/src/engine/sysDef.cpp +++ b/src/engine/sysDef.cpp @@ -2003,7 +2003,7 @@ void DivEngine::registerSystems() { ); sysDefs[DIV_SYSTEM_DAVE]=new DivSysDef( - "Dave", NULL, 0xd5, 0, 6, false, true, 0, false, 0, 0, 0, + "Dave", NULL, 0xd5, 0, 6, false, true, 0, false, 1U<type==DIV_INS_POWERNOISE_SLOPE) { dutyMax=0; } + if (ins->type==DIV_INS_DAVE) { + dutyLabel="Noise Freq"; + dutyMax=3; + } const char* waveLabel="Waveform"; int waveMax=(ins->type==DIV_INS_VERA)?3:(MAX(1,e->song.waveLen-1)); @@ -6953,7 +6961,7 @@ void FurnaceGUI::drawInsEdit() { if (ins->type==DIV_INS_POWERNOISE) waveMax=0; if (ins->type==DIV_INS_POWERNOISE_SLOPE) waveMax=0; if (ins->type==DIV_INS_SU || ins->type==DIV_INS_POKEY) waveMax=7; - if (ins->type==DIV_INS_DAVE) waveMax=3; + if (ins->type==DIV_INS_DAVE) waveMax=4; if (ins->type==DIV_INS_PET) { waveMax=8; waveBitMode=true; @@ -7020,12 +7028,15 @@ void FurnaceGUI::drawInsEdit() { ex1Max=5; ex2Max=11; } + if (ins->type==DIV_INS_DAVE) { + ex1Max=4; + } int panMin=0; int panMax=0; bool panSingle=false; bool panSingleNoBit=false; - if (ins->type==DIV_INS_STD ||//Game Gear + if (ins->type==DIV_INS_STD || // Game Gear ins->type==DIV_INS_FM || ins->type==DIV_INS_OPM || ins->type==DIV_INS_GB || @@ -7097,6 +7108,9 @@ void FurnaceGUI::drawInsEdit() { if (ins->type==DIV_INS_POWERNOISE_SLOPE) { panMax=15; } + if (ins->type==DIV_INS_DAVE) { + panMax=63; + } if (volMax>0) { macroList.push_back(FurnaceGUIMacroDesc(volumeLabel,&ins->std.volMacro,volMin,volMax,160,uiColors[GUI_COLOR_MACRO_VOLUME])); @@ -7186,7 +7200,8 @@ void FurnaceGUI::drawInsEdit() { ins->type==DIV_INS_TED || ins->type==DIV_INS_ESFM || ins->type==DIV_INS_POWERNOISE || - ins->type==DIV_INS_POWERNOISE_SLOPE) { + ins->type==DIV_INS_POWERNOISE_SLOPE || + ins->type==DIV_INS_DAVE) { macroList.push_back(FurnaceGUIMacroDesc("Phase Reset",&ins->std.phaseResetMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); } if (ex1Max>0) { @@ -7220,6 +7235,8 @@ void FurnaceGUI::drawInsEdit() { macroList.push_back(FurnaceGUIMacroDesc("Special",&ins->std.ex1Macro,0,ex1Max,96,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,snesModeBits)); } else if (ins->type==DIV_INS_MSM5232) { macroList.push_back(FurnaceGUIMacroDesc("Group Attack",&ins->std.ex1Macro,0,ex1Max,96,uiColors[GUI_COLOR_MACRO_OTHER])); + } else if (ins->type==DIV_INS_DAVE) { + macroList.push_back(FurnaceGUIMacroDesc("Control",&ins->std.ex1Macro,0,ex1Max,64,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,daveControlBits)); } else { macroList.push_back(FurnaceGUIMacroDesc("Duty",&ins->std.ex1Macro,0,ex1Max,160,uiColors[GUI_COLOR_MACRO_OTHER])); } diff --git a/src/gui/presets.cpp b/src/gui/presets.cpp index 0c8894615..768304330 100644 --- a/src/gui/presets.cpp +++ b/src/gui/presets.cpp @@ -952,6 +952,12 @@ void FurnaceGUI::initSystemPresets() { CH(DIV_SYSTEM_SAA1099, 1.0f, 0, "") } ); + ENTRY( + "Enterprise 128", { + CH(DIV_SYSTEM_DAVE, 1.0f, 0, "") + }, + "tickRate=50" + ); ENTRY( "BBC Micro", { CH(DIV_SYSTEM_SMS, 1.0f, 0, @@ -2778,6 +2784,12 @@ void FurnaceGUI::initSystemPresets() { CH(DIV_SYSTEM_POWERNOISE, 1.0f, 0, "") } ); + ENTRY( + "Dave", { + CH(DIV_SYSTEM_DAVE, 1.0f, 0, "") + }, + "tickRate=50" + ); CATEGORY_END; CATEGORY_BEGIN("DefleMask-compatible","these configurations are compatible with DefleMask.\nselect this if you need to save as .dmf or work with that program.");