diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index 4ee8e48bb..153a8db97 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -1713,7 +1713,11 @@ int DivEngine::calcFreq(int base, int pitch, bool period, int octave, int pitch2 } int DivEngine::calcArp(int note, int arp, int offset) { - if (arp&0x40000000) return (arp&(~0x40000000))+offset; + if (arp<0) { + if (!(arp&0x40000000)) return (arp|0x40000000)+offset; + } else { + if (arp&0x40000000) return (arp&(~0x40000000))+offset; + } return note+arp; } diff --git a/src/engine/fileOps.cpp b/src/engine/fileOps.cpp index c2acd45d4..506dfc6f9 100644 --- a/src/engine/fileOps.cpp +++ b/src/engine/fileOps.cpp @@ -510,9 +510,9 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { } else { ins->std.arpMacro.mode=0; for (int j=0; jstd.arpMacro.len; j++) { - ins->std.arpMacro.val[i]|=0x40000000; + ins->std.arpMacro.val[j]^=0x40000000; } - if (ins->std.arpMacro.loopstd.arpMacro.len && ins->std.arpMacro.len<255) { + if (ins->std.arpMacro.loop>=ins->std.arpMacro.len && ins->std.arpMacro.len<255) { ins->std.arpMacro.val[ins->std.arpMacro.len++]=0; } } @@ -2928,7 +2928,7 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) { logV("unhandled pitch!"); } else { if (fm.val[j]>0x80) { - ins->std.arpMacro.val[ins->std.arpMacro.len]=(fm.val[j]-0x80+24)|0x40000000; + ins->std.arpMacro.val[ins->std.arpMacro.len]=(fm.val[j]-0x80+24)^0x40000000; } else { ins->std.arpMacro.val[ins->std.arpMacro.len]=fm.val[j]; } diff --git a/src/engine/instrument.cpp b/src/engine/instrument.cpp index bd28834c4..430e361ae 100644 --- a/src/engine/instrument.cpp +++ b/src/engine/instrument.cpp @@ -1347,9 +1347,9 @@ DivDataErrors DivInstrument::readInsData(SafeReader& reader, short version) { if (std.arpMacro.mode) { std.arpMacro.mode=0; for (int i=0; istd.arpMacro.loop && std.arpMacro.len<255) { + if ((std.arpMacro.loop>=std.arpMacro.len || std.arpMacro.rel>std.arpMacro.loop) && std.arpMacro.len<255) { std.arpMacro.val[std.arpMacro.len++]=0; } } diff --git a/src/engine/platform/gb.cpp b/src/engine/platform/gb.cpp index afed615d2..fea89c71d 100644 --- a/src/engine/platform/gb.cpp +++ b/src/engine/platform/gb.cpp @@ -169,7 +169,7 @@ void DivPlatformGB::tick(bool sysTick) { if (chan[i].baseFreq>255) chan[i].baseFreq=255; if (chan[i].baseFreq<0) chan[i].baseFreq=0; } else { - chan[i].baseFreq=NOTE_PERIODIC(parent->calcArp(chan[i].note,chan[i].std.arp.val)); + chan[i].baseFreq=NOTE_PERIODIC(parent->calcArp(chan[i].note,chan[i].std.arp.val,24)); } chan[i].freqChanged=true; } diff --git a/src/engine/platform/tia.cpp b/src/engine/platform/tia.cpp index fe7273a1c..d55200f9f 100644 --- a/src/engine/platform/tia.cpp +++ b/src/engine/platform/tia.cpp @@ -90,7 +90,9 @@ void DivPlatformTIA::tick(bool sysTick) { // TODO: the way arps work on TIA is really weird if (chan[i].std.arp.had) { if (!chan[i].inPorta) { - if (chan[i].std.arp.val&0x40000000) { + if (chan[i].std.arp.val<0 && (!(chan[i].std.arp.val&0x40000000))) { + chan[i].baseFreq=0x80000000|(chan[i].std.arp.val|0x40000000); + } else if (chan[i].std.arp.val&0x40000000) { chan[i].baseFreq=0x80000000|(chan[i].std.arp.val&(~0x40000000)); } else { chan[i].baseFreq=(chan[i].note+chan[i].std.arp.val)<<8; diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index c044ae664..8ea22a144 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -201,8 +201,13 @@ void FurnaceGUI::encodeMMLStr(String& target, int* macro, int macroLen, int macr for (int i=0; imacroMax) macro[macroLen]=macroMax; - if (setBit30) macro[macroLen]|=0x40000000; + if (setBit30) macro[macroLen]^=0x40000000; setBit30=false; macroLen++; buf=0; @@ -325,7 +330,7 @@ void FurnaceGUI::decodeMMLStr(String& source, int* macro, unsigned char& macroLe negaBuf=false; if (macro[macroLen]macroMax) macro[macroLen]=macroMax; - if (setBit30) macro[macroLen]|=0x40000000; + if (setBit30) macro[macroLen]^=0x40000000; setBit30=false; macroLen++; buf=0; @@ -341,7 +346,7 @@ void FurnaceGUI::decodeMMLStr(String& source, int* macro, unsigned char& macroLe negaBuf=false; if (macro[macroLen]macroMax) macro[macroLen]=macroMax; - if (setBit30) macro[macroLen]|=0x40000000; + if (setBit30) macro[macroLen]^=0x40000000; setBit30=false; macroLen++; buf=0; @@ -359,7 +364,7 @@ void FurnaceGUI::decodeMMLStr(String& source, int* macro, unsigned char& macroLe negaBuf=false; if (macro[macroLen]macroMax) macro[macroLen]=macroMax; - if (setBit30) macro[macroLen]|=0x40000000; + if (setBit30) macro[macroLen]^=0x40000000; setBit30=false; macroLen++; buf=0; @@ -1774,7 +1779,8 @@ void FurnaceGUI::showError(String what) { displayError=true; } -#define B30(tt) (macroDragBit30?((tt)&0x40000000):0) +// what monster did I just create here? +#define B30(tt) (macroDragBit30?((((tt)&0xc0000000)==0x40000000 || ((tt)&0xc0000000)==0x80000000)?0x40000000:0):0) #define MACRO_DRAG(t) \ if (macroDragBitMode) { \ @@ -1808,25 +1814,25 @@ void FurnaceGUI::showError(String what) { } \ if (macroDragMouseMoved) { \ if ((int)round(x-macroDragLineInitial.x)==0) { \ - t[x]=B30(t[x])|(int)(macroDragLineInitial.y); \ + t[x]=B30(t[x])^(int)(macroDragLineInitial.y); \ } else { \ if ((int)round(x-macroDragLineInitial.x)<0) { \ for (int i=0; i<=(int)round(macroDragLineInitial.x-x); i++) { \ int index=(int)round(x+i); \ if (index<0) continue; \ - t[index]=B30(t[index])|(int)(y+(macroDragLineInitial.y-y)*((float)i/(float)(macroDragLineInitial.x-x))); \ + t[index]=B30(t[index])^(int)(y+(macroDragLineInitial.y-y)*((float)i/(float)(macroDragLineInitial.x-x))); \ } \ } else { \ for (int i=0; i<=(int)round(x-macroDragLineInitial.x); i++) { \ int index=(int)round(i+macroDragLineInitial.x); \ if (index<0) continue; \ - t[index]=B30(t[index])|(int)(macroDragLineInitial.y+(y-macroDragLineInitial.y)*((float)i/(x-macroDragLineInitial.x))); \ + t[index]=B30(t[index])^(int)(macroDragLineInitial.y+(y-macroDragLineInitial.y)*((float)i/(x-macroDragLineInitial.x))); \ } \ } \ } \ } \ } else { \ - t[x]=B30(t[x])|(y); \ + t[x]=B30(t[x])^(y); \ } \ } diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index ea0717154..2a2c8ecd5 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -1197,6 +1197,16 @@ String genericGuide(float value) { return fmt::sprintf("%d",(int)value); } +inline int deBit30(const int val) { + if ((val&0xc0000000)==0x40000000 || (val&0xc0000000)==0x80000000) return val^0x40000000; + return val; +} + +inline bool enBit30(const int val) { + if ((val&0xc0000000)==0x40000000 || (val&0xc0000000)==0x80000000) return true; + return false; +} + void FurnaceGUI::drawMacros(std::vector& macros) { float asFloat[256]; int asInt[256]; @@ -1292,9 +1302,9 @@ void FurnaceGUI::drawMacros(std::vector& macros) { asFloat[j]=0; asInt[j]=0; } else { - asFloat[j]=i.macro->val[j+macroDragScroll]&(i.bit30?(~0x40000000):0xffffffff); - asInt[j]=(i.macro->val[j+macroDragScroll]&(i.bit30?(~0x40000000):0xffffffff))+i.bitOffset; - if (i.bit30) bit30Indicator[j]=(i.macro->val[j+macroDragScroll]&0x40000000)?1:0; + asFloat[j]=deBit30(i.macro->val[j+macroDragScroll]); + asInt[j]=deBit30(i.macro->val[j+macroDragScroll])+i.bitOffset; + if (i.bit30) bit30Indicator[j]=enBit30(i.macro->val[j+macroDragScroll]); } if (j+macroDragScroll>=i.macro->len || (j+macroDragScroll>i.macro->rel && i.macro->looprel)) { loopIndicator[j]=0; @@ -1461,10 +1471,10 @@ void FurnaceGUI::drawMacros(std::vector& macros) { ImGui::SetNextItemWidth(availableWidth); String& mmlStr=mmlString[index]; if (ImGui::InputText("##IMacroMML",&mmlStr)) { - decodeMMLStr(mmlStr,i.macro->val,i.macro->len,i.macro->loop,i.min,(i.isBitfield)?((1<<(i.isBitfield?i.max:0))-1):i.max,i.macro->rel); + decodeMMLStr(mmlStr,i.macro->val,i.macro->len,i.macro->loop,i.min,(i.isBitfield)?((1<<(i.isBitfield?i.max:0))-1):i.max,i.macro->rel,i.bit30); } if (!ImGui::IsItemActive()) { - encodeMMLStr(mmlStr,i.macro->val,i.macro->len,i.macro->loop,i.macro->rel); + encodeMMLStr(mmlStr,i.macro->val,i.macro->len,i.macro->loop,i.macro->rel,false,i.bit30); } } ImGui::PopStyleVar();