This commit is contained in:
BlastBrothers 2022-02-21 14:00:08 -05:00
commit 8c7dd59e53
10 changed files with 428 additions and 253 deletions

View file

@ -14,7 +14,7 @@ set(CMAKE_CXX_STANDARD 14)
set(CMAKE_PROJECT_VERSION_MAJOR 0) set(CMAKE_PROJECT_VERSION_MAJOR 0)
set(CMAKE_PROJECT_VERSION_MINOR 5) set(CMAKE_PROJECT_VERSION_MINOR 5)
set(CMAKE_PROJECT_VERSION_PATCH 6) set(CMAKE_PROJECT_VERSION_PATCH 7)
if (ANDROID) if (ANDROID)
set(BUILD_GUI_DEFAULT OFF) set(BUILD_GUI_DEFAULT OFF)

View file

@ -150,6 +150,8 @@ size | description
| - 0xa5: OPL3 4-op (YMF262) - 12 channels | - 0xa5: OPL3 4-op (YMF262) - 12 channels
| - 0xa6: OPL3 4-op + drums (YMF262) - 14 channels | - 0xa6: OPL3 4-op + drums (YMF262) - 14 channels
| - 0xa7: OPLL drums (YM2413) - 11 channels | - 0xa7: OPLL drums (YM2413) - 11 channels
| - 0xa8: Atari Lynx - 4 channels
| - 0xe0: QSound - 16 channels
32 | sound chip volumes 32 | sound chip volumes
| - signed char, 64=1.0, 127=~2.0 | - signed char, 64=1.0, 127=~2.0
32 | sound chip panning 32 | sound chip panning

View file

@ -15,17 +15,17 @@
<key>CFBundleInfoDictionaryVersion</key> <key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string> <string>6.0</string>
<key>CFBundleLongVersionString</key> <key>CFBundleLongVersionString</key>
<string>0.5.6</string> <string>0.5.7</string>
<key>CFBundleName</key> <key>CFBundleName</key>
<string>Furnace</string> <string>Furnace</string>
<key>CFBundlePackageType</key> <key>CFBundlePackageType</key>
<string>APPL</string> <string>APPL</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>0.5.6</string> <string>0.5.7</string>
<key>CFBundleSignature</key> <key>CFBundleSignature</key>
<string>????</string> <string>????</string>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>0.5.6</string> <string>0.5.7</string>
<key>NSHumanReadableCopyright</key> <key>NSHumanReadableCopyright</key>
<string></string> <string></string>
<key>NSHighResolutionCapable</key> <key>NSHighResolutionCapable</key>

View file

@ -743,6 +743,7 @@ void DivEngine::getCommandStream(std::vector<DivCommand>& where) {
} }
void DivEngine::playSub(bool preserveDrift, int goalRow) { void DivEngine::playSub(bool preserveDrift, int goalRow) {
for (int i=0; i<song.systemLen; i++) disCont[i].dispatch->setSkipRegisterWrites(false);
reset(); reset();
if (preserveDrift && curOrder==0) return; if (preserveDrift && curOrder==0) return;
bool oldRepeatPattern=repeatPattern; bool oldRepeatPattern=repeatPattern;
@ -767,11 +768,11 @@ void DivEngine::playSub(bool preserveDrift, int goalRow) {
playing=true; playing=true;
for (int i=0; i<song.systemLen; i++) disCont[i].dispatch->setSkipRegisterWrites(true); for (int i=0; i<song.systemLen; i++) disCont[i].dispatch->setSkipRegisterWrites(true);
while (playing && curOrder<goal) { while (playing && curOrder<goal) {
if (nextTick(preserveDrift)) break; if (nextTick(preserveDrift)) return;
} }
int oldOrder=curOrder; int oldOrder=curOrder;
while (playing && curRow<goalRow) { while (playing && curRow<goalRow) {
if (nextTick(preserveDrift)) break; if (nextTick(preserveDrift)) return;
if (oldOrder!=curOrder) break; if (oldOrder!=curOrder) break;
} }
for (int i=0; i<song.systemLen; i++) disCont[i].dispatch->setSkipRegisterWrites(false); for (int i=0; i<song.systemLen; i++) disCont[i].dispatch->setSkipRegisterWrites(false);
@ -804,8 +805,8 @@ int DivEngine::calcBaseFreq(double clock, double divider, int note, bool period)
int DivEngine::calcFreq(int base, int pitch, bool period, int octave) { int DivEngine::calcFreq(int base, int pitch, bool period, int octave) {
if (song.linearPitch) { if (song.linearPitch) {
return period? return period?
round(base*pow(2,-(double)pitch/(12.0*128.0))/(98.0+globalPitch*6.0)*98.0): base*pow(2,-(double)pitch/(12.0*128.0))/(98.0+globalPitch*6.0)*98.0:
(round(base*pow(2,(double)pitch/(12.0*128.0))*(98+globalPitch*6))/98); (base*pow(2,(double)pitch/(12.0*128.0))*(98+globalPitch*6))/98;
} }
return period? return period?
base-pitch: base-pitch:
@ -1195,8 +1196,24 @@ int DivEngine::addInstrument(int refChan) {
return insCount; return insCount;
} }
enum DivInsFormats {
DIV_INSFORMAT_DMP,
DIV_INSFORMAT_TFI,
DIV_INSFORMAT_VGI,
DIV_INSFORMAT_FTI,
DIV_INSFORMAT_BTI
};
bool DivEngine::addInstrumentFromFile(const char *path) { bool DivEngine::addInstrumentFromFile(const char *path) {
warnings=""; warnings="";
const char* pathRedux=strrchr(path,DIR_SEPARATOR);
if (pathRedux==NULL) {
pathRedux="Instrument";
} else {
pathRedux++;
}
FILE* f=ps_fopen(path,"rb"); FILE* f=ps_fopen(path,"rb");
if (f==NULL) { if (f==NULL) {
lastError=strerror(errno); lastError=strerror(errno);
@ -1273,251 +1290,356 @@ bool DivEngine::addInstrumentFromFile(const char *path) {
delete[] buf; delete[] buf;
return false; return false;
} }
} else { // read as .dmp } else { // read as a different format
// this is a ridiculous mess const char* ext=strrchr(path,'.');
unsigned char version=0; DivInsFormats format=DIV_INSFORMAT_DMP;
unsigned char sys=0; if (ext!=NULL) {
try { String extS;
reader.seek(0,SEEK_SET); for (; *ext; ext++) {
version=reader.readC(); char i=*ext;
} catch (EndOfFileException e) { if (i>='A' && i<='Z') {
lastError="premature end of file"; i+='a'-'A';
logE("premature end of file!\n"); }
delete ins; extS+=i;
delete[] buf; }
return false; if (extS==String(".dmp")) {
format=DIV_INSFORMAT_DMP;
} else if (extS==String(".tfi")) {
format=DIV_INSFORMAT_TFI;
} else if (extS==String(".vgi")) {
format=DIV_INSFORMAT_VGI;
} else if (extS==String(".fti")) {
format=DIV_INSFORMAT_FTI;
} else if (extS==String(".bti")) {
format=DIV_INSFORMAT_BTI;
}
} }
switch (format) {
case DIV_INSFORMAT_DMP: {
// this is a ridiculous mess
unsigned char version=0;
unsigned char sys=0;
try {
reader.seek(0,SEEK_SET);
version=reader.readC();
} catch (EndOfFileException e) {
lastError="premature end of file";
logE("premature end of file!\n");
delete ins;
delete[] buf;
return false;
}
if (version>11) { if (version>11) {
lastError="unknown instrument version!"; lastError="unknown instrument version!";
delete ins; delete ins;
delete[] buf; delete[] buf;
return false; return false;
} }
if (version>=11) { // 1.0 ins->name=pathRedux;
try {
sys=reader.readC();
switch (sys) { if (version>=11) { // 1.0
case 1: // YMU759 try {
ins->type=DIV_INS_FM; sys=reader.readC();
break;
case 2: // Genesis switch (sys) {
ins->type=DIV_INS_FM; case 1: // YMU759
break; ins->type=DIV_INS_FM;
case 3: // SMS break;
ins->type=DIV_INS_STD; case 2: // Genesis
break; ins->type=DIV_INS_FM;
case 4: // Game Boy break;
ins->type=DIV_INS_GB; case 3: // SMS
break; ins->type=DIV_INS_STD;
case 5: // PC Engine break;
ins->type=DIV_INS_PCE; case 4: // Game Boy
break; ins->type=DIV_INS_GB;
case 6: // NES break;
ins->type=DIV_INS_STD; case 5: // PC Engine
break; ins->type=DIV_INS_PCE;
case 7: case 0x17: // C64 break;
ins->type=DIV_INS_C64; case 6: // NES
break; ins->type=DIV_INS_STD;
case 8: // Arcade break;
ins->type=DIV_INS_FM; case 7: case 0x17: // C64
break; ins->type=DIV_INS_C64;
default: break;
lastError="unknown instrument type!"; case 8: // Arcade
ins->type=DIV_INS_FM;
break;
default:
lastError="unknown instrument type!";
delete ins;
delete[] buf;
return false;
break;
}
} catch (EndOfFileException e) {
lastError="premature end of file";
logE("premature end of file!\n");
delete ins; delete ins;
delete[] buf; delete[] buf;
return false; return false;
break;
}
} catch (EndOfFileException e) {
lastError="premature end of file";
logE("premature end of file!\n");
delete ins;
delete[] buf;
return false;
}
}
try {
bool mode=true;
if (version>1) {
mode=reader.readC();
if (mode==0) {
if (version<11) {
ins->type=DIV_INS_STD;
} }
} else {
ins->type=DIV_INS_FM;
} }
} else {
ins->type=DIV_INS_FM;
}
if (mode) { // FM try {
if (version<10) { bool mode=true;
if (version>1) { if (version>1) {
ins->fm.ops=reader.readC()?4:2; mode=reader.readC();
} else { if (mode==0) {
ins->fm.ops=reader.readC()?2:4; if (version<11) {
} ins->type=DIV_INS_STD;
} }
if (version>1) { // HELP! in which version of the format did we start storing FMS! } else {
ins->fm.fms=reader.readC(); ins->type=DIV_INS_FM;
}
ins->fm.fb=reader.readC();
ins->fm.alg=reader.readC();
// DITTO
if (sys!=1) ins->fm.ams=reader.readC();
for (int j=0; j<ins->fm.ops; j++) {
ins->fm.op[j].mult=reader.readC();
ins->fm.op[j].tl=reader.readC();
ins->fm.op[j].ar=reader.readC();
ins->fm.op[j].dr=reader.readC();
ins->fm.op[j].sl=reader.readC();
ins->fm.op[j].rr=reader.readC();
ins->fm.op[j].am=reader.readC();
// what the hell how do I tell!
if (sys==1) { // YMU759
ins->fm.op[j].ws=reader.readC();
ins->fm.op[j].ksl=reader.readC();
ins->fm.op[j].vib=reader.readC();
ins->fm.op[j].egt=reader.readC();
ins->fm.op[j].sus=reader.readC();
ins->fm.op[j].ksr=reader.readC();
ins->fm.op[j].dvb=reader.readC();
ins->fm.op[j].dam=reader.readC();
} else {
ins->fm.op[j].rs=reader.readC();
ins->fm.op[j].dt=reader.readC();
ins->fm.op[j].dt2=ins->fm.op[j].dt>>4;
ins->fm.op[j].dt&=15;
ins->fm.op[j].d2r=reader.readC();
ins->fm.op[j].ssgEnv=reader.readC();
}
}
} else { // STD
if (ins->type!=DIV_INS_GB) {
ins->std.volMacroLen=reader.readC();
if (version>5) {
for (int i=0; i<ins->std.volMacroLen; i++) {
ins->std.volMacro[i]=reader.readI();
} }
} else { } else {
for (int i=0; i<ins->std.volMacroLen; i++) { ins->type=DIV_INS_FM;
ins->std.volMacro[i]=reader.readC(); }
if (mode) { // FM
if (version<10) {
if (version>1) {
ins->fm.ops=reader.readC()?4:2;
} else {
ins->fm.ops=reader.readC()?2:4;
}
}
if (version>1) { // HELP! in which version of the format did we start storing FMS!
ins->fm.fms=reader.readC();
}
ins->fm.fb=reader.readC();
ins->fm.alg=reader.readC();
// DITTO
if (sys!=1) ins->fm.ams=reader.readC();
for (int j=0; j<ins->fm.ops; j++) {
ins->fm.op[j].mult=reader.readC();
ins->fm.op[j].tl=reader.readC();
ins->fm.op[j].ar=reader.readC();
ins->fm.op[j].dr=reader.readC();
ins->fm.op[j].sl=reader.readC();
ins->fm.op[j].rr=reader.readC();
ins->fm.op[j].am=reader.readC();
// what the hell how do I tell!
if (sys==1) { // YMU759
ins->fm.op[j].ws=reader.readC();
ins->fm.op[j].ksl=reader.readC();
ins->fm.op[j].vib=reader.readC();
ins->fm.op[j].egt=reader.readC();
ins->fm.op[j].sus=reader.readC();
ins->fm.op[j].ksr=reader.readC();
ins->fm.op[j].dvb=reader.readC();
ins->fm.op[j].dam=reader.readC();
} else {
ins->fm.op[j].rs=reader.readC();
ins->fm.op[j].dt=reader.readC();
ins->fm.op[j].dt2=ins->fm.op[j].dt>>4;
ins->fm.op[j].dt&=15;
ins->fm.op[j].d2r=reader.readC();
ins->fm.op[j].ssgEnv=reader.readC();
}
}
} else { // STD
if (ins->type!=DIV_INS_GB) {
ins->std.volMacroLen=reader.readC();
if (version>5) {
for (int i=0; i<ins->std.volMacroLen; i++) {
ins->std.volMacro[i]=reader.readI();
}
} else {
for (int i=0; i<ins->std.volMacroLen; i++) {
ins->std.volMacro[i]=reader.readC();
}
}
if (version<11) for (int i=0; i<ins->std.volMacroLen; i++) {
if (ins->std.volMacro[i]>15 && ins->type==DIV_INS_STD) ins->type=DIV_INS_PCE;
}
if (ins->std.volMacroLen>0) {
ins->std.volMacroOpen=true;
ins->std.volMacroLoop=reader.readC();
} else {
ins->std.volMacroOpen=false;
}
}
ins->std.arpMacroLen=reader.readC();
if (version>5) {
for (int i=0; i<ins->std.arpMacroLen; i++) {
ins->std.arpMacro[i]=reader.readI();
}
} else {
for (int i=0; i<ins->std.arpMacroLen; i++) {
ins->std.arpMacro[i]=reader.readC();
}
}
if (ins->std.arpMacroLen>0) {
ins->std.arpMacroOpen=true;
ins->std.arpMacroLoop=reader.readC();
} else {
ins->std.arpMacroOpen=false;
}
if (version>8) { // TODO: when?
ins->std.arpMacroMode=reader.readC();
}
ins->std.dutyMacroLen=reader.readC();
if (version>5) {
for (int i=0; i<ins->std.dutyMacroLen; i++) {
ins->std.dutyMacro[i]=reader.readI();
}
} else {
for (int i=0; i<ins->std.dutyMacroLen; i++) {
ins->std.dutyMacro[i]=reader.readC();
}
}
if (ins->std.dutyMacroLen>0) {
ins->std.dutyMacroOpen=true;
ins->std.dutyMacroLoop=reader.readC();
} else {
ins->std.dutyMacroOpen=false;
}
ins->std.waveMacroLen=reader.readC();
if (version>5) {
for (int i=0; i<ins->std.waveMacroLen; i++) {
ins->std.waveMacro[i]=reader.readI();
}
} else {
for (int i=0; i<ins->std.waveMacroLen; i++) {
ins->std.waveMacro[i]=reader.readC();
}
}
if (ins->std.waveMacroLen>0) {
ins->std.waveMacroOpen=true;
ins->std.waveMacroLoop=reader.readC();
} else {
ins->std.waveMacroOpen=false;
}
if (ins->type==DIV_INS_C64) {
ins->c64.triOn=reader.readC();
ins->c64.sawOn=reader.readC();
ins->c64.pulseOn=reader.readC();
ins->c64.noiseOn=reader.readC();
ins->c64.a=reader.readC();
ins->c64.d=reader.readC();
ins->c64.s=reader.readC();
ins->c64.r=reader.readC();
ins->c64.duty=(reader.readC()*4095)/100;
ins->c64.ringMod=reader.readC();
ins->c64.oscSync=reader.readC();
ins->c64.toFilter=reader.readC();
if (version<0x07) { // TODO: UNSURE
ins->c64.volIsCutoff=reader.readI();
} else {
ins->c64.volIsCutoff=reader.readC();
}
ins->c64.initFilter=reader.readC();
ins->c64.res=reader.readC();
ins->c64.cut=(reader.readC()*2047)/100;
ins->c64.hp=reader.readC();
ins->c64.bp=reader.readC();
ins->c64.lp=reader.readC();
ins->c64.ch3off=reader.readC();
}
if (ins->type==DIV_INS_GB) {
ins->gb.envVol=reader.readC();
ins->gb.envDir=reader.readC();
ins->gb.envLen=reader.readC();
ins->gb.soundLen=reader.readC();
} }
} }
if (version<11) for (int i=0; i<ins->std.volMacroLen; i++) { } catch (EndOfFileException e) {
if (ins->std.volMacro[i]>15 && ins->type==DIV_INS_STD) ins->type=DIV_INS_PCE; lastError="premature end of file";
} logE("premature end of file!\n");
if (ins->std.volMacroLen>0) { delete ins;
ins->std.volMacroOpen=true; delete[] buf;
ins->std.volMacroLoop=reader.readC(); return false;
} else {
ins->std.volMacroOpen=false;
}
}
ins->std.arpMacroLen=reader.readC();
if (version>5) {
for (int i=0; i<ins->std.arpMacroLen; i++) {
ins->std.arpMacro[i]=reader.readI();
}
} else {
for (int i=0; i<ins->std.arpMacroLen; i++) {
ins->std.arpMacro[i]=reader.readC();
}
}
if (ins->std.arpMacroLen>0) {
ins->std.arpMacroOpen=true;
ins->std.arpMacroLoop=reader.readC();
} else {
ins->std.arpMacroOpen=false;
}
if (version>8) { // TODO: when?
ins->std.arpMacroMode=reader.readC();
}
ins->std.dutyMacroLen=reader.readC();
if (version>5) {
for (int i=0; i<ins->std.dutyMacroLen; i++) {
ins->std.dutyMacro[i]=reader.readI();
}
} else {
for (int i=0; i<ins->std.dutyMacroLen; i++) {
ins->std.dutyMacro[i]=reader.readC();
}
}
if (ins->std.dutyMacroLen>0) {
ins->std.dutyMacroOpen=true;
ins->std.dutyMacroLoop=reader.readC();
} else {
ins->std.dutyMacroOpen=false;
}
ins->std.waveMacroLen=reader.readC();
if (version>5) {
for (int i=0; i<ins->std.waveMacroLen; i++) {
ins->std.waveMacro[i]=reader.readI();
}
} else {
for (int i=0; i<ins->std.waveMacroLen; i++) {
ins->std.waveMacro[i]=reader.readC();
}
}
if (ins->std.waveMacroLen>0) {
ins->std.waveMacroOpen=true;
ins->std.waveMacroLoop=reader.readC();
} else {
ins->std.waveMacroOpen=false;
}
if (ins->type==DIV_INS_C64) {
ins->c64.triOn=reader.readC();
ins->c64.sawOn=reader.readC();
ins->c64.pulseOn=reader.readC();
ins->c64.noiseOn=reader.readC();
ins->c64.a=reader.readC();
ins->c64.d=reader.readC();
ins->c64.s=reader.readC();
ins->c64.r=reader.readC();
ins->c64.duty=(reader.readC()*4095)/100;
ins->c64.ringMod=reader.readC();
ins->c64.oscSync=reader.readC();
ins->c64.toFilter=reader.readC();
if (version<0x07) { // TODO: UNSURE
ins->c64.volIsCutoff=reader.readI();
} else {
ins->c64.volIsCutoff=reader.readC();
}
ins->c64.initFilter=reader.readC();
ins->c64.res=reader.readC();
ins->c64.cut=(reader.readC()*2047)/100;
ins->c64.hp=reader.readC();
ins->c64.bp=reader.readC();
ins->c64.lp=reader.readC();
ins->c64.ch3off=reader.readC();
}
if (ins->type==DIV_INS_GB) {
ins->gb.envVol=reader.readC();
ins->gb.envDir=reader.readC();
ins->gb.envLen=reader.readC();
ins->gb.soundLen=reader.readC();
} }
break;
} }
} catch (EndOfFileException e) { case DIV_INSFORMAT_TFI:
lastError="premature end of file"; try {
logE("premature end of file!\n"); reader.seek(0,SEEK_SET);
delete ins;
delete[] buf; ins->type=DIV_INS_FM;
return false; ins->name=pathRedux;
ins->fm.alg=reader.readC();
ins->fm.fb=reader.readC();
for (int i=0; i<4; i++) {
DivInstrumentFM::Operator& op=ins->fm.op[i];
op.mult=reader.readC();
op.dt=reader.readC();
op.tl=reader.readC();
op.rs=reader.readC();
op.ar=reader.readC();
op.dr=reader.readC();
op.d2r=reader.readC();
op.rr=reader.readC();
op.sl=reader.readC();
op.ssgEnv=reader.readC();
}
} catch (EndOfFileException e) {
lastError="premature end of file";
logE("premature end of file!\n");
delete ins;
delete[] buf;
return false;
}
break;
case DIV_INSFORMAT_VGI:
try {
reader.seek(0,SEEK_SET);
ins->type=DIV_INS_FM;
ins->name=pathRedux;
ins->fm.alg=reader.readC();
ins->fm.fb=reader.readC();
unsigned char fmsams=reader.readC();
ins->fm.fms=fmsams&7;
ins->fm.ams=fmsams>>4;
for (int i=0; i<4; i++) {
DivInstrumentFM::Operator& op=ins->fm.op[i];
op.mult=reader.readC();
op.dt=reader.readC();
op.tl=reader.readC();
op.rs=reader.readC();
op.ar=reader.readC();
op.dr=reader.readC();
if (op.dr&0x80) {
op.am=1;
op.dr&=0x7f;
}
op.d2r=reader.readC();
op.rr=reader.readC();
op.sl=reader.readC();
op.ssgEnv=reader.readC();
}
} catch (EndOfFileException e) {
lastError="premature end of file";
logE("premature end of file!\n");
delete ins;
delete[] buf;
return false;
}
break;
case DIV_INSFORMAT_FTI:
break;
case DIV_INSFORMAT_BTI:
break;
} }
if (reader.tell()<reader.size()) { if (reader.tell()<reader.size()) {
@ -1828,19 +1950,24 @@ void DivEngine::deepCloneOrder(bool where) {
warnings=""; warnings="";
isBusy.lock(); isBusy.lock();
for (int i=0; i<chans; i++) { for (int i=0; i<chans; i++) {
bool didNotFind=true;
logD("channel %d\n",i);
order[i]=song.orders.ord[i][curOrder]; order[i]=song.orders.ord[i][curOrder];
// find free slot // find free slot
for (int j=0; j<128; j++) { for (int j=0; j<128; j++) {
logD("finding free slot in %d...\n",j);
if (song.pat[i].data[j]==NULL) { if (song.pat[i].data[j]==NULL) {
int origOrd=order[i]; int origOrd=order[i];
order[i]=j; order[i]=j;
DivPattern* oldPat=song.pat[i].getPattern(origOrd,false); DivPattern* oldPat=song.pat[i].getPattern(origOrd,false);
DivPattern* pat=song.pat[i].getPattern(j,true); DivPattern* pat=song.pat[i].getPattern(j,true);
memcpy(pat->data,oldPat->data,256*32*sizeof(short)); memcpy(pat->data,oldPat->data,256*32*sizeof(short));
logD("found at %d\n",j);
didNotFind=false;
break; break;
} }
} }
if (order[i]==song.orders.ord[i][curOrder]) { if (didNotFind) {
addWarning(fmt::sprintf("no free patterns in channel %d!",i)); addWarning(fmt::sprintf("no free patterns in channel %d!",i));
} }
} }

View file

@ -37,8 +37,8 @@
warnings+=(String("\n")+x); \ warnings+=(String("\n")+x); \
} }
#define DIV_VERSION "0.5.7pre3" #define DIV_VERSION "0.5.7pre4"
#define DIV_ENGINE_VERSION 51 #define DIV_ENGINE_VERSION 52
enum DivStatusView { enum DivStatusView {
DIV_STATUS_NOTHING=0, DIV_STATUS_NOTHING=0,

View file

@ -171,7 +171,7 @@ void DivPlatformC64::tick() {
if (!chan[i].resetMask && !isMuted[i]) { if (!chan[i].resetMask && !isMuted[i]) {
rWrite(i*7+5,0); rWrite(i*7+5,0);
rWrite(i*7+6,0); rWrite(i*7+6,0);
rWrite(i*7+4,(isMuted[i]?0:(chan[i].wave<<4))|8|(chan[i].ring<<2)|(chan[i].sync<<1)); rWrite(i*7+4,(isMuted[i]?8:(chan[i].wave<<4))|8|(chan[i].ring<<2)|(chan[i].sync<<1));
} }
} }
} }
@ -246,8 +246,8 @@ int DivPlatformC64::dispatch(DivCommand c) {
filtCut=ins->c64.cut; filtCut=ins->c64.cut;
filtRes=ins->c64.res; filtRes=ins->c64.res;
filtControl=ins->c64.lp|(ins->c64.bp<<1)|(ins->c64.hp<<2)|(ins->c64.ch3off<<3); filtControl=ins->c64.lp|(ins->c64.bp<<1)|(ins->c64.hp<<2)|(ins->c64.ch3off<<3);
updateFilter();
} }
updateFilter();
} }
if (chan[c.chan].insChanged) { if (chan[c.chan].insChanged) {
chan[c.chan].insChanged=false; chan[c.chan].insChanged=false;

View file

@ -977,7 +977,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop) {
writeLoop=true; writeLoop=true;
} }
} }
if (nextTick()) { if (nextTick() || !playing) {
done=true; done=true;
if (!loop) { if (!loop) {
for (int i=0; i<song.systemLen; i++) { for (int i=0; i<song.systemLen; i++) {
@ -991,6 +991,11 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop) {
w->writeC(i); w->writeC(i);
loopSample[i]=-1; loopSample[i]=-1;
} }
if (!playing) {
writeLoop=false;
loopPos=-1;
}
} }
// get register dumps // get register dumps
for (int i=0; i<song.systemLen; i++) { for (int i=0; i<song.systemLen; i++) {
@ -1126,8 +1131,13 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop) {
w->writeI(gd3Off-0x14); w->writeI(gd3Off-0x14);
w->writeI(tickCount); w->writeI(tickCount);
if (loop) { if (loop) {
w->writeI(loopPos-0x1c); if (loopPos==-1) {
w->writeI(tickCount-loopTick-1); w->writeI(0);
w->writeI(0);
} else {
w->writeI(loopPos-0x1c);
w->writeI(tickCount-loopTick-1);
}
} else { } else {
w->writeI(0); w->writeI(0);
w->writeI(0); w->writeI(0);

View file

@ -3820,7 +3820,7 @@ void FurnaceGUI::openFileDialog(FurnaceGUIFileDialogs type) {
ImGuiFileDialog::Instance()->OpenModal("FileDialog","Save File","DefleMask 1.0/legacy module{.dmf}",workingDir,1,nullptr,ImGuiFileDialogFlags_ConfirmOverwrite); ImGuiFileDialog::Instance()->OpenModal("FileDialog","Save File","DefleMask 1.0/legacy module{.dmf}",workingDir,1,nullptr,ImGuiFileDialogFlags_ConfirmOverwrite);
break; break;
case GUI_FILE_INS_OPEN: case GUI_FILE_INS_OPEN:
ImGuiFileDialog::Instance()->OpenModal("FileDialog","Load Instrument","compatible files{.fui,.dmp},.*",workingDir); ImGuiFileDialog::Instance()->OpenModal("FileDialog","Load Instrument","compatible files{.fui,.dmp,.tfi,.vgi},.*",workingDir);
break; break;
case GUI_FILE_INS_SAVE: case GUI_FILE_INS_SAVE:
ImGuiFileDialog::Instance()->OpenModal("FileDialog","Save Instrument","Furnace instrument{.fui}",workingDir,1,nullptr,ImGuiFileDialogFlags_ConfirmOverwrite); ImGuiFileDialog::Instance()->OpenModal("FileDialog","Save Instrument","Furnace instrument{.fui}",workingDir,1,nullptr,ImGuiFileDialogFlags_ConfirmOverwrite);
@ -5486,6 +5486,11 @@ bool FurnaceGUI::init() {
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".otf",ImVec4(0.3f,1.0f,0.6f,1.0f),ICON_FA_FONT); ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".otf",ImVec4(0.3f,1.0f,0.6f,1.0f),ICON_FA_FONT);
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".ttc",ImVec4(0.3f,1.0f,0.6f,1.0f),ICON_FA_FONT); ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".ttc",ImVec4(0.3f,1.0f,0.6f,1.0f),ICON_FA_FONT);
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".tfi",ImVec4(1.0f,0.5f,0.5f,1.0f),ICON_FA_FILE);
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".vgi",ImVec4(1.0f,0.5f,0.5f,1.0f),ICON_FA_FILE);
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".fti",ImVec4(1.0f,0.5f,0.5f,1.0f),ICON_FA_FILE);
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".bti",ImVec4(1.0f,0.5f,0.5f,1.0f),ICON_FA_FILE);
updateWindowTitle(); updateWindowTitle();
for (int i=0; i<DIV_MAX_CHANS; i++) { for (int i=0; i<DIV_MAX_CHANS; i++) {
@ -5574,6 +5579,8 @@ FurnaceGUI::FurnaceGUI():
loopRow(-1), loopRow(-1),
loopEnd(-1), loopEnd(-1),
isClipping(0), isClipping(0),
extraChannelButtons(0),
patNameTarget(-1),
editControlsOpen(true), editControlsOpen(true),
ordersOpen(true), ordersOpen(true),
insListOpen(true), insListOpen(true),
@ -5598,13 +5605,13 @@ FurnaceGUI::FurnaceGUI():
selecting(false), selecting(false),
curNibble(false), curNibble(false),
orderNibble(false), orderNibble(false),
extraChannelButtons(false),
followOrders(true), followOrders(true),
followPattern(true), followPattern(true),
changeAllOrders(false), changeAllOrders(false),
collapseWindow(false), collapseWindow(false),
demandScrollX(false), demandScrollX(false),
fancyPattern(false), fancyPattern(false),
wantPatName(false),
curWindow(GUI_WINDOW_NOTHING), curWindow(GUI_WINDOW_NOTHING),
nextWindow(GUI_WINDOW_NOTHING), nextWindow(GUI_WINDOW_NOTHING),
wavePreviewOn(false), wavePreviewOn(false),

View file

@ -516,14 +516,14 @@ class FurnaceGUI {
char finalLayoutPath[4096]; char finalLayoutPath[4096];
int curIns, curWave, curSample, curOctave, oldRow, oldOrder, oldOrder1, editStep, exportLoops, soloChan, soloTimeout, orderEditMode, orderCursor; int curIns, curWave, curSample, curOctave, oldRow, oldOrder, oldOrder1, editStep, exportLoops, soloChan, soloTimeout, orderEditMode, orderCursor;
int loopOrder, loopRow, loopEnd, isClipping; int loopOrder, loopRow, loopEnd, isClipping, extraChannelButtons, patNameTarget;
bool editControlsOpen, ordersOpen, insListOpen, songInfoOpen, patternOpen, insEditOpen; bool editControlsOpen, ordersOpen, insListOpen, songInfoOpen, patternOpen, insEditOpen;
bool waveListOpen, waveEditOpen, sampleListOpen, sampleEditOpen, aboutOpen, settingsOpen; bool waveListOpen, waveEditOpen, sampleListOpen, sampleEditOpen, aboutOpen, settingsOpen;
bool mixerOpen, debugOpen, oscOpen, volMeterOpen, statsOpen, compatFlagsOpen; bool mixerOpen, debugOpen, oscOpen, volMeterOpen, statsOpen, compatFlagsOpen;
bool pianoOpen, notesOpen, channelsOpen; bool pianoOpen, notesOpen, channelsOpen;
SelectionPoint selStart, selEnd, cursor; SelectionPoint selStart, selEnd, cursor;
bool selecting, curNibble, orderNibble, extraChannelButtons, followOrders, followPattern, changeAllOrders; bool selecting, curNibble, orderNibble, followOrders, followPattern, changeAllOrders;
bool collapseWindow, demandScrollX, fancyPattern; bool collapseWindow, demandScrollX, fancyPattern, wantPatName;
FurnaceGUIWindows curWindow, nextWindow; FurnaceGUIWindows curWindow, nextWindow;
float peak[2]; float peak[2];
float patChanX[DIV_MAX_CHANS+1]; float patChanX[DIV_MAX_CHANS+1];

View file

@ -17,10 +17,12 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/ */
#include <imgui.h>
#define _USE_MATH_DEFINES #define _USE_MATH_DEFINES
#include "gui.h" #include "gui.h"
#include "imgui_internal.h" #include "imgui_internal.h"
#include "IconsFontAwesome4.h" #include "IconsFontAwesome4.h"
#include "misc/cpp/imgui_stdlib.h"
#include "guiConst.h" #include "guiConst.h"
#include <fmt/printf.h> #include <fmt/printf.h>
@ -376,8 +378,8 @@ void FurnaceGUI::drawPattern() {
} }
ImGui::TableNextRow(); ImGui::TableNextRow();
ImGui::TableNextColumn(); ImGui::TableNextColumn();
if (ImGui::Selectable(extraChannelButtons?" --##ExtraChannelButtons":" ++##ExtraChannelButtons",false,ImGuiSelectableFlags_NoPadWithHalfSpacing,ImVec2(0.0f,lineHeight+1.0f*dpiScale))) { if (ImGui::Selectable((extraChannelButtons==2)?" --##ExtraChannelButtons":" ++##ExtraChannelButtons",false,ImGuiSelectableFlags_NoPadWithHalfSpacing,ImVec2(0.0f,lineHeight+1.0f*dpiScale))) {
extraChannelButtons=!extraChannelButtons; if (++extraChannelButtons>2) extraChannelButtons=0;
} }
if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) { if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) {
fancyPattern=!fancyPattern; fancyPattern=!fancyPattern;
@ -448,7 +450,34 @@ void FurnaceGUI::drawPattern() {
if (settings.soloAction!=2) if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) { if (settings.soloAction!=2) if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) {
e->toggleSolo(i); e->toggleSolo(i);
} }
if (extraChannelButtons) { if (extraChannelButtons==2) {
DivPattern* pat=e->song.pat[i].getPattern(e->song.orders.ord[i][ord],true);
ImGui::PushFont(mainFont);
if (patNameTarget==i) {
snprintf(chanID,2048,"##PatNameI%d_%d",i,ord);
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x-(8.0f*dpiScale));
ImGui::SetCursorPosX(ImGui::GetCursorPosX()+4.0f*dpiScale);
ImGui::InputText(chanID,&pat->name);
if (wantPatName) {
wantPatName=false;
ImGui::SetItemDefaultFocus();
ImGui::SetKeyboardFocusHere(-1);
} else {
if (!ImGui::IsItemActive()) {
patNameTarget=-1;
}
}
} else {
snprintf(chanID,2048," %s##PatName%d",pat->name.c_str(),i);
if (ImGui::Selectable(chanID,true,ImGuiSelectableFlags_NoPadWithHalfSpacing,ImVec2(0.0f,lineHeight+1.0f*dpiScale))) {
patNameTarget=i;
wantPatName=true;
snprintf(chanID,2048,"##PatNameI%d_%d",i,ord);
ImGui::SetActiveID(ImGui::GetID(chanID),ImGui::GetCurrentWindow());
}
}
ImGui::PopFont();
} else if (extraChannelButtons==1) {
snprintf(chanID,2048,"%c##_HCH%d",e->song.chanCollapse[i]?'+':'-',i); snprintf(chanID,2048,"%c##_HCH%d",e->song.chanCollapse[i]?'+':'-',i);
ImGui::SetCursorPosX(ImGui::GetCursorPosX()+4.0f*dpiScale); ImGui::SetCursorPosX(ImGui::GetCursorPosX()+4.0f*dpiScale);
if (ImGui::SmallButton(chanID)) { if (ImGui::SmallButton(chanID)) {