Merge branch 'master' into newMixer
This commit is contained in:
commit
678a095822
96 changed files with 2015 additions and 1491 deletions
|
|
@ -1138,15 +1138,7 @@ if (USE_BACKWARD)
|
|||
list(APPEND USED_SOURCES src/backtrace.cpp)
|
||||
if (WIN32)
|
||||
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||
include(CheckCXXCompilerFlag)
|
||||
check_cxx_compiler_flag(-gcodeview GCC_CODEVIEW)
|
||||
if (GCC_CODEVIEW OR FORCE_CODEVIEW)
|
||||
set(CMAKE_EXE_LINKER_FLAGS "-Wl,--pdb= ")
|
||||
add_compile_options(-gcodeview)
|
||||
message(STATUS "Enabling -gcodeview flag for backward-cpp.")
|
||||
else()
|
||||
message(WARNING "Could not enable -gcodeview! backward-cpp will not work.")
|
||||
endif()
|
||||
message(WARNING "Could not enable -gcodeview! backward-cpp will not work.")
|
||||
list(APPEND DEPENDENCIES_LIBRARIES dbghelp psapi)
|
||||
endif()
|
||||
endif()
|
||||
|
|
|
|||
Binary file not shown.
BIN
demos/arcade/Crystal Dimension Section 2 WSG Mix.fur
Normal file
BIN
demos/arcade/Crystal Dimension Section 2 WSG Mix.fur
Normal file
Binary file not shown.
BIN
demos/arcade/JoyfulStart_Seta.fur
Normal file
BIN
demos/arcade/JoyfulStart_Seta.fur
Normal file
Binary file not shown.
BIN
demos/arcade/REPROGRAMMED.fur
Normal file
BIN
demos/arcade/REPROGRAMMED.fur
Normal file
Binary file not shown.
BIN
demos/arcade/SHIN_YA.fur
Normal file
BIN
demos/arcade/SHIN_YA.fur
Normal file
Binary file not shown.
BIN
demos/arcade/Slow Brew.fur
Normal file
BIN
demos/arcade/Slow Brew.fur
Normal file
Binary file not shown.
BIN
demos/arcade/living crystal cave.fur
Normal file
BIN
demos/arcade/living crystal cave.fur
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
demos/misc/Back_In_Detroit_Supervision.fur
Normal file
BIN
demos/misc/Back_In_Detroit_Supervision.fur
Normal file
Binary file not shown.
Binary file not shown.
BIN
demos/misc/david.fur
Normal file
BIN
demos/misc/david.fur
Normal file
Binary file not shown.
Binary file not shown.
BIN
demos/misc/hittingtherevlimiter_RF5C68.fur
Normal file
BIN
demos/misc/hittingtherevlimiter_RF5C68.fur
Normal file
Binary file not shown.
Binary file not shown.
BIN
demos/misc/sawmen_break_SM8521.fur
Normal file
BIN
demos/misc/sawmen_break_SM8521.fur
Normal file
Binary file not shown.
BIN
demos/misc/spite_is_the_best_motivator_PV1000.fur
Normal file
BIN
demos/misc/spite_is_the_best_motivator_PV1000.fur
Normal file
Binary file not shown.
BIN
demos/misc/tech_low_qual_era_RF5C68.fur
Normal file
BIN
demos/misc/tech_low_qual_era_RF5C68.fur
Normal file
Binary file not shown.
Binary file not shown.
BIN
demos/multichip/CR_yasui_cs.fur
Normal file
BIN
demos/multichip/CR_yasui_cs.fur
Normal file
Binary file not shown.
Binary file not shown.
BIN
demos/multichip/Furnace-tan VS the spirit of the Mask.fur
Normal file
BIN
demos/multichip/Furnace-tan VS the spirit of the Mask.fur
Normal file
Binary file not shown.
BIN
demos/multichip/Melancholy_Girl_multichip.fur
Normal file
BIN
demos/multichip/Melancholy_Girl_multichip.fur
Normal file
Binary file not shown.
Binary file not shown.
BIN
demos/multichip/WakeUpAndDance_MMC5_SM8521.fur
Normal file
BIN
demos/multichip/WakeUpAndDance_MMC5_SM8521.fur
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
demos/nes/blanketcritter release ver.fur
Normal file
BIN
demos/nes/blanketcritter release ver.fur
Normal file
Binary file not shown.
BIN
demos/opl/Air_Combat_Over_the_Vast_Mountain.fur
Normal file
BIN
demos/opl/Air_Combat_Over_the_Vast_Mountain.fur
Normal file
Binary file not shown.
BIN
demos/opl/One_Sided_Love_Again.fur
Normal file
BIN
demos/opl/One_Sided_Love_Again.fur
Normal file
Binary file not shown.
BIN
demos/opl/femteknyl.fur
Normal file
BIN
demos/opl/femteknyl.fur
Normal file
Binary file not shown.
BIN
demos/opz/'90 lost media.fur
Normal file
BIN
demos/opz/'90 lost media.fur
Normal file
Binary file not shown.
BIN
demos/opz/Clashing Angels.fur
Normal file
BIN
demos/opz/Clashing Angels.fur
Normal file
Binary file not shown.
BIN
demos/opz/Fly to the Leaden Sky.fur
Normal file
BIN
demos/opz/Fly to the Leaden Sky.fur
Normal file
Binary file not shown.
BIN
demos/opz/Glacier BM0.fur
Normal file
BIN
demos/opz/Glacier BM0.fur
Normal file
Binary file not shown.
BIN
demos/opz/The Hedgehog Knows One Thing.fur
Normal file
BIN
demos/opz/The Hedgehog Knows One Thing.fur
Normal file
Binary file not shown.
BIN
demos/opz/The bongos and teh base OPZx2.fur
Normal file
BIN
demos/opz/The bongos and teh base OPZx2.fur
Normal file
Binary file not shown.
BIN
demos/opz/boost.fur
Normal file
BIN
demos/opz/boost.fur
Normal file
Binary file not shown.
BIN
demos/opz/goodbye my dreams.fur
Normal file
BIN
demos/opz/goodbye my dreams.fur
Normal file
Binary file not shown.
BIN
demos/opz/myst_grove.fur
Normal file
BIN
demos/opz/myst_grove.fur
Normal file
Binary file not shown.
BIN
demos/opz/only_dream_opz.fur
Normal file
BIN
demos/opz/only_dream_opz.fur
Normal file
Binary file not shown.
BIN
demos/opz/sea of crises.fur
Normal file
BIN
demos/opz/sea of crises.fur
Normal file
Binary file not shown.
Binary file not shown.
BIN
demos/pce/Contest thing 2025.fur
Normal file
BIN
demos/pce/Contest thing 2025.fur
Normal file
Binary file not shown.
BIN
demos/pce/Peace.fur
Normal file
BIN
demos/pce/Peace.fur
Normal file
Binary file not shown.
BIN
demos/pce/Processing Plant 2025 Edit.fur
Normal file
BIN
demos/pce/Processing Plant 2025 Edit.fur
Normal file
Binary file not shown.
BIN
demos/pce/fd_PCB.fur
Normal file
BIN
demos/pce/fd_PCB.fur
Normal file
Binary file not shown.
BIN
demos/pce/pcengineasdmo.fur
Normal file
BIN
demos/pce/pcengineasdmo.fur
Normal file
Binary file not shown.
Binary file not shown.
BIN
demos/vic20/h.fur
Normal file
BIN
demos/vic20/h.fur
Normal file
Binary file not shown.
BIN
demos/wonderswan/Space Station of Enormous Proportions.fur
Normal file
BIN
demos/wonderswan/Space Station of Enormous Proportions.fur
Normal file
Binary file not shown.
Binary file not shown.
BIN
demos/ymz280b/evilevilsong.fur
Normal file
BIN
demos/ymz280b/evilevilsong.fur
Normal file
Binary file not shown.
BIN
demos/ymz280b/notreallyfm.fur
Normal file
BIN
demos/ymz280b/notreallyfm.fur
Normal file
Binary file not shown.
3
extern/imgui_software_renderer/imgui_sw.cpp
vendored
3
extern/imgui_software_renderer/imgui_sw.cpp
vendored
|
|
@ -678,6 +678,9 @@ void ImGui_ImplSW_Shutdown() {
|
|||
|
||||
void ImGui_ImplSW_NewFrame() {
|
||||
ImGui_ImplSW_Data* bd = ImGui_ImplSW_GetBackendData();
|
||||
// look I am USING THIS VARIABLE
|
||||
// don't go around saying I don't use it
|
||||
if (bd==NULL) abort();
|
||||
IM_ASSERT(bd != nullptr);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -58,6 +58,9 @@ bool DivConfig::save(const char* path, bool redundancy) {
|
|||
reportError(fmt::sprintf("could not write config file! %s",strerror(errno)));
|
||||
return false;
|
||||
}
|
||||
if (redundancy) {
|
||||
fputs("!DIV_CONFIG_START!\n",f);
|
||||
}
|
||||
for (auto& i: conf) {
|
||||
String toWrite=fmt::sprintf("%s=%s\n",i.first,i.second);
|
||||
if (fwrite(toWrite.c_str(),1,toWrite.size(),f)!=toWrite.size()) {
|
||||
|
|
@ -69,6 +72,9 @@ bool DivConfig::save(const char* path, bool redundancy) {
|
|||
return false;
|
||||
}
|
||||
}
|
||||
if (redundancy) {
|
||||
fputs("~DIV_CONFIG_END~\n",f);
|
||||
}
|
||||
fclose(f);
|
||||
logD("config file written successfully.");
|
||||
return true;
|
||||
|
|
@ -124,8 +130,12 @@ bool DivConfig::loadFromFile(const char* path, bool createOnFail, bool redundanc
|
|||
if (redundancy) {
|
||||
unsigned char* readBuf=new unsigned char[CHECK_BUF_SIZE];
|
||||
size_t readBufLen=0;
|
||||
bool weRescued=false;
|
||||
for (int i=0; i<REDUNDANCY_NUM_ATTEMPTS; i++) {
|
||||
bool viable=false;
|
||||
bool startCheck=true;
|
||||
bool hasStartMarker=false;
|
||||
unsigned char endMarker[18];
|
||||
if (i>0) {
|
||||
snprintf(line,4095,"%s.%d",path,i);
|
||||
} else {
|
||||
|
|
@ -143,15 +153,27 @@ bool DivConfig::loadFromFile(const char* path, bool createOnFail, bool redundanc
|
|||
|
||||
// check whether there's something
|
||||
while (!feof(f)) {
|
||||
bool willBreak=false;
|
||||
readBufLen=fread(readBuf,1,CHECK_BUF_SIZE,f);
|
||||
if (ferror(f)) {
|
||||
logV("fread(): %s",strerror(errno));
|
||||
break;
|
||||
}
|
||||
|
||||
if (startCheck) {
|
||||
if (readBufLen>=19) {
|
||||
if (memcmp(readBuf,"!DIV_CONFIG_START!\n",19)==0) {
|
||||
hasStartMarker=true;
|
||||
logV("start marker found");
|
||||
}
|
||||
}
|
||||
startCheck=false;
|
||||
}
|
||||
|
||||
for (size_t j=0; j<readBufLen; j++) {
|
||||
if (readBuf[j]==0) {
|
||||
viable=false;
|
||||
willBreak=true;
|
||||
logW("a zero?");
|
||||
break;
|
||||
}
|
||||
|
|
@ -160,7 +182,30 @@ bool DivConfig::loadFromFile(const char* path, bool createOnFail, bool redundanc
|
|||
}
|
||||
}
|
||||
|
||||
if (viable) break;
|
||||
if (readBufLen>=18) {
|
||||
memcpy(endMarker,&readBuf[readBufLen-18],18);
|
||||
} else if (readBufLen>0) {
|
||||
// shift buffer left
|
||||
for (size_t j=0, k=readBufLen; j<readBufLen && k<18; j++, k++) {
|
||||
endMarker[j]=endMarker[k];
|
||||
}
|
||||
|
||||
// copy to end
|
||||
memcpy(&endMarker[18-readBufLen],readBuf,readBufLen);
|
||||
}
|
||||
|
||||
if (willBreak) break;
|
||||
}
|
||||
|
||||
// check for end marker if start marker is present
|
||||
if (hasStartMarker) {
|
||||
if (memcmp(endMarker,"\n~DIV_CONFIG_END~\n",18)!=0) {
|
||||
// file is incomplete
|
||||
viable=false;
|
||||
logV("end marker NOT found!");
|
||||
reportError("saved from an incomplete config.\nyeah! for a second I thought you were going to lose it.");
|
||||
weRescued=true;
|
||||
}
|
||||
}
|
||||
|
||||
// there's something
|
||||
|
|
@ -184,6 +229,9 @@ bool DivConfig::loadFromFile(const char* path, bool createOnFail, bool redundanc
|
|||
logD("config does not exist");
|
||||
if (createOnFail) {
|
||||
logI("creating default config.");
|
||||
if (weRescued) {
|
||||
reportError("what the FUCK is that supposed to mean?!");
|
||||
}
|
||||
//reportError(fmt::sprintf("Creating default config: %s",strerror(errno)));
|
||||
return save(path,redundancy);
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -31,6 +31,22 @@
|
|||
#define DIV_MAX_COLS 32
|
||||
#define DIV_MAX_EFFECTS 8
|
||||
|
||||
// pattern fields
|
||||
#define DIV_PAT_NOTE 0
|
||||
#define DIV_PAT_INS 1
|
||||
#define DIV_PAT_VOL 2
|
||||
#define DIV_PAT_FX(_x) (3+((_x)<<1))
|
||||
#define DIV_PAT_FXVAL(_x) (4+((_x)<<1))
|
||||
|
||||
// column type checks
|
||||
#define DIV_PAT_IS_EFFECT(_x) ((_x)>DIV_PAT_VOL && (!((_x)&1)))
|
||||
#define DIV_PAT_IS_EFFECT_VAL(_x) ((_x)>DIV_PAT_VOL && ((_x)&1))
|
||||
|
||||
#define DIV_NOTE_NULL_PAT 252
|
||||
#define DIV_NOTE_OFF 253
|
||||
#define DIV_NOTE_REL 254
|
||||
#define DIV_MACRO_REL 255
|
||||
|
||||
// sample related
|
||||
#define DIV_MAX_SAMPLE_TYPE 4
|
||||
|
||||
|
|
|
|||
|
|
@ -947,8 +947,8 @@ void DivEngine::delUnusedIns() {
|
|||
for (int k=0; k<DIV_MAX_PATTERNS; k++) {
|
||||
if (song.subsong[j]->pat[i].data[k]==NULL) continue;
|
||||
for (int l=0; l<song.subsong[j]->patLen; l++) {
|
||||
if (song.subsong[j]->pat[i].data[k]->data[l][2]>=0 && song.subsong[j]->pat[i].data[k]->data[l][2]<256) {
|
||||
isUsed[song.subsong[j]->pat[i].data[k]->data[l][2]]=true;
|
||||
if (song.subsong[j]->pat[i].data[k]->newData[l][DIV_PAT_INS]>=0 && song.subsong[j]->pat[i].data[k]->newData[l][DIV_PAT_INS]<256) {
|
||||
isUsed[song.subsong[j]->pat[i].data[k]->newData[l][DIV_PAT_INS]]=true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1033,38 +1033,6 @@ void DivEngine::delUnusedSamples() {
|
|||
}
|
||||
}
|
||||
|
||||
// scan in pattern (legacy sample mode)
|
||||
// disabled because it is unreliable
|
||||
/*
|
||||
for (DivSubSong* i: song.subsong) {
|
||||
for (int j=0; j<getTotalChannelCount(); j++) {
|
||||
bool is17On=false;
|
||||
int bank=0;
|
||||
for (int k=0; k<i->ordersLen; k++) {
|
||||
DivPattern* p=i->pat[j].getPattern(i->orders.ord[j][k],false);
|
||||
for (int l=0; l<i->patLen; l++) {
|
||||
for (int m=0; m<i->pat[j].effectCols; m++) {
|
||||
if (p->data[l][4+(m<<1)]==0x17) {
|
||||
is17On=(p->data[l][5+(m<<1)]>0);
|
||||
}
|
||||
if (p->data[l][4+(m<<1)]==0xeb) {
|
||||
bank=p->data[l][5+(m<<1)];
|
||||
if (bank==-1) bank=0;
|
||||
}
|
||||
}
|
||||
if (is17On) {
|
||||
if (p->data[l][1]!=0 || p->data[l][0]!=0) {
|
||||
if (p->data[l][0]<=12) {
|
||||
int note=(12*bank)+(p->data[l][0]%12);
|
||||
if (note<256) isUsed[note]=true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
// delete
|
||||
for (int i=0; i<song.sampleLen; i++) {
|
||||
if (!isUsed[i]) {
|
||||
|
|
@ -2293,6 +2261,64 @@ int DivEngine::getEffectiveSampleRate(int rate) {
|
|||
return rate;
|
||||
}
|
||||
|
||||
short DivEngine::splitNoteToNote(short note, short octave) {
|
||||
if (note==100) {
|
||||
return DIV_NOTE_OFF;
|
||||
} else if (note==101) {
|
||||
return DIV_NOTE_REL;
|
||||
} else if (note==102) {
|
||||
return DIV_MACRO_REL;
|
||||
} else if (note==0 && octave!=0) {
|
||||
// "BUG" note!
|
||||
return DIV_NOTE_NULL_PAT;
|
||||
} else if (note==0 && octave==0) {
|
||||
return -1;
|
||||
} else {
|
||||
int seek=(note+(signed char)octave*12)+60;
|
||||
if (seek<0 || seek>=180) {
|
||||
return DIV_NOTE_NULL_PAT;
|
||||
} else {
|
||||
return seek;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void DivEngine::noteToSplitNote(short note, short& outNote, short& outOctave) {
|
||||
switch (note) {
|
||||
case DIV_NOTE_OFF:
|
||||
outNote=100;
|
||||
outOctave=0;
|
||||
break;
|
||||
case DIV_NOTE_REL:
|
||||
outNote=101;
|
||||
outOctave=0;
|
||||
break;
|
||||
case DIV_MACRO_REL:
|
||||
outNote=102;
|
||||
outOctave=0;
|
||||
break;
|
||||
case DIV_NOTE_NULL_PAT:
|
||||
// "BUG" note!
|
||||
outNote=0;
|
||||
outOctave=1;
|
||||
break;
|
||||
case -1:
|
||||
outNote=0;
|
||||
outOctave=0;
|
||||
break;
|
||||
default:
|
||||
outNote=note%12;
|
||||
outOctave=(unsigned char)(note-60)/12;
|
||||
if (outNote==0) {
|
||||
outNote=12;
|
||||
outOctave--;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void DivEngine::previewSample(int sample, int note, int pStart, int pEnd) {
|
||||
BUSY_BEGIN;
|
||||
previewSampleNoLock(sample,note,pStart,pEnd);
|
||||
|
|
@ -2749,8 +2775,8 @@ void DivEngine::delInstrumentUnsafe(int index) {
|
|||
for (int k=0; k<DIV_MAX_PATTERNS; k++) {
|
||||
if (song.subsong[j]->pat[i].data[k]==NULL) continue;
|
||||
for (int l=0; l<song.subsong[j]->patLen; l++) {
|
||||
if (song.subsong[j]->pat[i].data[k]->data[l][2]>index) {
|
||||
song.subsong[j]->pat[i].data[k]->data[l][2]--;
|
||||
if (song.subsong[j]->pat[i].data[k]->newData[l][DIV_PAT_INS]>index) {
|
||||
song.subsong[j]->pat[i].data[k]->newData[l][DIV_PAT_INS]--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3111,7 +3137,7 @@ void DivEngine::deepCloneOrder(int pos, bool where) {
|
|||
order[i]=j;
|
||||
DivPattern* oldPat=curPat[i].getPattern(origOrd,false);
|
||||
DivPattern* pat=curPat[i].getPattern(j,true);
|
||||
memcpy(pat->data,oldPat->data,DIV_MAX_ROWS*DIV_MAX_COLS*sizeof(short));
|
||||
memcpy(pat->newData,oldPat->newData,DIV_MAX_ROWS*DIV_MAX_COLS*sizeof(short));
|
||||
logD("found at %d",j);
|
||||
didNotFind=false;
|
||||
break;
|
||||
|
|
@ -3217,10 +3243,10 @@ void DivEngine::exchangeIns(int one, int two) {
|
|||
for (int k=0; k<DIV_MAX_PATTERNS; k++) {
|
||||
if (song.subsong[j]->pat[i].data[k]==NULL) continue;
|
||||
for (int l=0; l<song.subsong[j]->patLen; l++) {
|
||||
if (song.subsong[j]->pat[i].data[k]->data[l][2]==one) {
|
||||
song.subsong[j]->pat[i].data[k]->data[l][2]=two;
|
||||
} else if (song.subsong[j]->pat[i].data[k]->data[l][2]==two) {
|
||||
song.subsong[j]->pat[i].data[k]->data[l][2]=one;
|
||||
if (song.subsong[j]->pat[i].data[k]->newData[l][DIV_PAT_INS]==one) {
|
||||
song.subsong[j]->pat[i].data[k]->newData[l][DIV_PAT_INS]=two;
|
||||
} else if (song.subsong[j]->pat[i].data[k]->newData[l][DIV_PAT_INS]==two) {
|
||||
song.subsong[j]->pat[i].data[k]->newData[l][DIV_PAT_INS]=one;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,8 +54,8 @@ class DivWorkPool;
|
|||
|
||||
#define DIV_UNSTABLE
|
||||
|
||||
#define DIV_VERSION "dev233"
|
||||
#define DIV_ENGINE_VERSION 233
|
||||
#define DIV_VERSION "dev235"
|
||||
#define DIV_ENGINE_VERSION 235
|
||||
// for imports
|
||||
#define DIV_VERSION_MOD 0xff01
|
||||
#define DIV_VERSION_FC 0xff02
|
||||
|
|
@ -140,7 +140,7 @@ struct DivChannelState {
|
|||
int panDepth, panRate, panPos, panSpeed;
|
||||
int sampleOff;
|
||||
unsigned char arp, arpStage, arpTicks, panL, panR, panRL, panRR, lastVibrato, lastPorta, cutType;
|
||||
bool doNote, legato, portaStop, keyOn, keyOff, nowYouCanStop, stopOnOff, releasing;
|
||||
bool doNote, legato, portaStop, keyOn, keyOff, stopOnOff, releasing;
|
||||
bool arpYield, delayLocked, inPorta, scheduledSlideReset, shorthandPorta, wasShorthandPorta, noteOnInhibit, resetArp, sampleOffSet;
|
||||
bool wentThroughNote, goneThroughNote;
|
||||
|
||||
|
|
@ -197,7 +197,6 @@ struct DivChannelState {
|
|||
portaStop(false),
|
||||
keyOn(false),
|
||||
keyOff(false),
|
||||
nowYouCanStop(true),
|
||||
stopOnOff(false),
|
||||
releasing(false),
|
||||
arpYield(false),
|
||||
|
|
@ -723,7 +722,7 @@ class DivEngine {
|
|||
SafeWriter* saveDMF(unsigned char version);
|
||||
// save as .fur.
|
||||
// if notPrimary is true then the song will not be altered
|
||||
SafeWriter* saveFur(bool notPrimary=false, bool newPatternFormat=true);
|
||||
SafeWriter* saveFur(bool notPrimary=false);
|
||||
// return a ROM exporter.
|
||||
DivROMExport* buildROM(DivROMExportOptions sys);
|
||||
// dump to VGM.
|
||||
|
|
@ -929,6 +928,10 @@ class DivEngine {
|
|||
// get effective sample rate
|
||||
int getEffectiveSampleRate(int rate);
|
||||
|
||||
// convert between old and new note/octave format
|
||||
short splitNoteToNote(short note, short octave);
|
||||
void noteToSplitNote(short note, short& outNote, short& outOctave);
|
||||
|
||||
// is FM system
|
||||
bool isFMSystem(DivSystem sys);
|
||||
|
||||
|
|
|
|||
|
|
@ -783,109 +783,113 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) {
|
|||
DivPattern* pat=chan.getPattern(ds.subsong[0]->orders.ord[i][j],true);
|
||||
if (ds.version>0x08) { // current pattern format
|
||||
for (int k=0; k<ds.subsong[0]->patLen; k++) {
|
||||
// note
|
||||
pat->data[k][0]=reader.readS();
|
||||
// octave
|
||||
pat->data[k][1]=reader.readS();
|
||||
if (ds.system[0]==DIV_SYSTEM_SMS && ds.version<0x0e && pat->data[k][1]>0) {
|
||||
short note=reader.readS();
|
||||
short octave=reader.readS();
|
||||
if (ds.system[0]==DIV_SYSTEM_SMS && ds.version<0x0e && octave>0) {
|
||||
// apparently it was up one octave before
|
||||
pat->data[k][1]--;
|
||||
} else if (ds.system[0]==DIV_SYSTEM_GENESIS && ds.version<0x0e && pat->data[k][1]>0 && i>5) {
|
||||
octave--;
|
||||
} else if (ds.system[0]==DIV_SYSTEM_GENESIS && ds.version<0x0e && octave>0 && i>5) {
|
||||
// ditto
|
||||
pat->data[k][1]--;
|
||||
} else if (ds.system[0]==DIV_SYSTEM_MSX2 && pat->data[k][1]>0 && i<3) {
|
||||
octave--;
|
||||
} else if (ds.system[0]==DIV_SYSTEM_MSX2 && octave>0 && i<3) {
|
||||
// why the hell?
|
||||
pat->data[k][1]++;
|
||||
octave++;
|
||||
}
|
||||
if (ds.version<0x12) {
|
||||
if (ds.system[0]==DIV_SYSTEM_GB && i==3 && pat->data[k][1]>0) {
|
||||
if (ds.system[0]==DIV_SYSTEM_GB && i==3 && octave>0) {
|
||||
// back then noise was 2 octaves lower
|
||||
pat->data[k][1]-=2;
|
||||
octave-=2;
|
||||
}
|
||||
}
|
||||
if (ds.system[0]==DIV_SYSTEM_YMU759 && pat->data[k][0]!=0) {
|
||||
if (ds.system[0]==DIV_SYSTEM_YMU759 && note!=0) {
|
||||
// apparently YMU759 is stored 2 octaves lower
|
||||
pat->data[k][1]+=2;
|
||||
octave+=2;
|
||||
}
|
||||
if (pat->data[k][0]==0 && pat->data[k][1]!=0) {
|
||||
logD("what? %d:%d:%d note %d octave %d",i,j,k,pat->data[k][0],pat->data[k][1]);
|
||||
pat->data[k][0]=12;
|
||||
pat->data[k][1]--;
|
||||
if (note==0 && octave!=0) {
|
||||
logD("what? %d:%d:%d note %d octave %d",i,j,k,note,octave);
|
||||
note=12;
|
||||
octave--;
|
||||
}
|
||||
|
||||
pat->newData[k][DIV_PAT_NOTE]=splitNoteToNote(note,octave);
|
||||
|
||||
// volume
|
||||
pat->data[k][3]=reader.readS();
|
||||
pat->newData[k][DIV_PAT_VOL]=reader.readS();
|
||||
if (ds.version<0x0a) {
|
||||
// back then volume was stored as 00-ff instead of 00-7f/0-f
|
||||
if (i>5) {
|
||||
pat->data[k][3]>>=4;
|
||||
pat->newData[k][DIV_PAT_VOL]>>=4;
|
||||
} else {
|
||||
pat->data[k][3]>>=1;
|
||||
pat->newData[k][DIV_PAT_VOL]>>=1;
|
||||
}
|
||||
}
|
||||
if (ds.version<0x12) {
|
||||
if (ds.system[0]==DIV_SYSTEM_GB && i==2 && pat->data[k][3]>0) {
|
||||
if (ds.system[0]==DIV_SYSTEM_GB && i==2 && pat->newData[k][DIV_PAT_VOL]>0) {
|
||||
// volume range of GB wave channel was 0-3 rather than 0-F
|
||||
pat->data[k][3]=(pat->data[k][3]&3)*5;
|
||||
pat->newData[k][DIV_PAT_VOL]=(pat->newData[k][DIV_PAT_VOL]&3)*5;
|
||||
}
|
||||
}
|
||||
for (int l=0; l<chan.effectCols; l++) {
|
||||
// effect
|
||||
pat->data[k][4+(l<<1)]=reader.readS();
|
||||
pat->data[k][5+(l<<1)]=reader.readS();
|
||||
pat->newData[k][DIV_PAT_FX(l)]=reader.readS();
|
||||
pat->newData[k][DIV_PAT_FXVAL(l)]=reader.readS();
|
||||
|
||||
if (ds.version<0x14) {
|
||||
if (pat->data[k][4+(l<<1)]==0xe5 && pat->data[k][5+(l<<1)]!=-1) {
|
||||
pat->data[k][5+(l<<1)]=128+((pat->data[k][5+(l<<1)]-128)/4);
|
||||
// the range of E5xx was different back then
|
||||
if (pat->newData[k][DIV_PAT_FX(l)]==0xe5 && pat->newData[k][DIV_PAT_FXVAL(l)]!=-1) {
|
||||
pat->newData[k][DIV_PAT_FXVAL(l)]=128+((pat->newData[k][DIV_PAT_FXVAL(l)]-128)/4);
|
||||
}
|
||||
}
|
||||
}
|
||||
// instrument
|
||||
pat->data[k][2]=reader.readS();
|
||||
pat->newData[k][DIV_PAT_INS]=reader.readS();
|
||||
|
||||
// this is sad
|
||||
if (ds.system[0]==DIV_SYSTEM_NES_FDS) {
|
||||
if (i==5 && pat->data[k][2]!=-1) {
|
||||
if (pat->data[k][2]>=0 && pat->data[k][2]<ds.insLen) {
|
||||
ds.ins[pat->data[k][2]]->type=DIV_INS_FDS;
|
||||
if (i==5 && pat->newData[k][DIV_PAT_INS]!=-1) {
|
||||
if (pat->newData[k][DIV_PAT_INS]>=0 && pat->newData[k][DIV_PAT_INS]<ds.insLen) {
|
||||
ds.ins[pat->newData[k][DIV_PAT_INS]]->type=DIV_INS_FDS;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ds.system[0]==DIV_SYSTEM_MSX2) {
|
||||
if (i>=3 && pat->data[k][2]!=-1) {
|
||||
if (pat->data[k][2]>=0 && pat->data[k][2]<ds.insLen) {
|
||||
ds.ins[pat->data[k][2]]->type=DIV_INS_SCC;
|
||||
if (i>=3 && pat->newData[k][DIV_PAT_INS]!=-1) {
|
||||
if (pat->newData[k][DIV_PAT_INS]>=0 && pat->newData[k][DIV_PAT_INS]<ds.insLen) {
|
||||
ds.ins[pat->newData[k][DIV_PAT_INS]]->type=DIV_INS_SCC;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else { // historic pattern format
|
||||
if (i<16) pat->data[0][2]=historicColIns[i];
|
||||
if (i<16) pat->newData[0][DIV_PAT_INS]=historicColIns[i];
|
||||
for (int k=0; k<ds.subsong[0]->patLen; k++) {
|
||||
// note
|
||||
pat->data[k][0]=reader.readC();
|
||||
// octave
|
||||
pat->data[k][1]=reader.readC();
|
||||
if (pat->data[k][0]!=0) {
|
||||
short note=reader.readC();
|
||||
short octave=reader.readC();
|
||||
|
||||
if (note!=0) {
|
||||
// YMU759 is stored 2 octaves lower
|
||||
pat->data[k][1]+=2;
|
||||
octave+=2;
|
||||
}
|
||||
if (pat->data[k][0]==0 && pat->data[k][1]!=0) {
|
||||
logD("what? %d:%d:%d note %d octave %d",i,j,k,pat->data[k][0],pat->data[k][1]);
|
||||
pat->data[k][0]=12;
|
||||
pat->data[k][1]--;
|
||||
if (note==0 && octave!=0) {
|
||||
logD("what? %d:%d:%d note %d octave %d",i,j,k,note,octave);
|
||||
note=12;
|
||||
octave--;
|
||||
}
|
||||
|
||||
pat->newData[k][DIV_PAT_NOTE]=splitNoteToNote(note,octave);
|
||||
|
||||
// volume and effect
|
||||
unsigned char vol=reader.readC();
|
||||
unsigned char fx=reader.readC();
|
||||
unsigned char fxVal=reader.readC();
|
||||
pat->data[k][3]=(vol==0x80 || vol==0xff)?-1:vol;
|
||||
pat->newData[k][DIV_PAT_VOL]=(vol==0x80 || vol==0xff)?-1:vol;
|
||||
// effect
|
||||
pat->data[k][4]=(fx==0x80 || fx==0xff)?-1:fx;
|
||||
pat->data[k][5]=(fxVal==0x80 || fx==0xff)?-1:fxVal;
|
||||
pat->newData[k][DIV_PAT_FX(0)]=(fx==0x80 || fx==0xff)?-1:fx;
|
||||
pat->newData[k][DIV_PAT_FXVAL(0)]=(fxVal==0x80 || fx==0xff)?-1:fxVal;
|
||||
// instrument
|
||||
if (ds.version>0x05) {
|
||||
pat->data[k][2]=reader.readC();
|
||||
if (pat->data[k][2]==0x80 || pat->data[k][2]==0xff) pat->data[k][2]=-1;
|
||||
pat->newData[k][DIV_PAT_INS]=reader.readC();
|
||||
if (pat->newData[k][DIV_PAT_INS]==0x80 || pat->newData[k][DIV_PAT_INS]==0xff) pat->newData[k][DIV_PAT_INS]=-1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1630,12 +1634,13 @@ SafeWriter* DivEngine::saveDMF(unsigned char version) {
|
|||
bool relWarning=false;
|
||||
|
||||
for (int i=0; i<getChannelCount(sys); i++) {
|
||||
short note, octave;
|
||||
w->writeC(curPat[i].effectCols);
|
||||
|
||||
for (int j=0; j<curSubSong->ordersLen; j++) {
|
||||
DivPattern* pat=curPat[i].getPattern(curOrders->ord[i][j],false);
|
||||
for (int k=0; k<curSubSong->patLen; k++) {
|
||||
if ((pat->data[k][0]==101 || pat->data[k][0]==102) && pat->data[k][1]==0) {
|
||||
if (pat->newData[k][DIV_PAT_NOTE]==DIV_NOTE_REL || pat->newData[k][DIV_PAT_NOTE]==DIV_MACRO_REL) {
|
||||
w->writeS(100);
|
||||
w->writeS(0);
|
||||
if (!relWarning) {
|
||||
|
|
@ -1643,18 +1648,19 @@ SafeWriter* DivEngine::saveDMF(unsigned char version) {
|
|||
addWarning("note/macro release will be converted to note off!");
|
||||
}
|
||||
} else {
|
||||
w->writeS(pat->data[k][0]); // note
|
||||
w->writeS(pat->data[k][1]); // octave
|
||||
noteToSplitNote(pat->newData[k][DIV_PAT_NOTE],note,octave);
|
||||
w->writeS(note); // note
|
||||
w->writeS(octave); // octave
|
||||
}
|
||||
w->writeS(pat->data[k][3]); // volume
|
||||
w->writeS(pat->newData[k][DIV_PAT_VOL]); // volume
|
||||
#ifdef TA_BIG_ENDIAN
|
||||
for (int l=0; l<curPat[i].effectCols*2; l++) {
|
||||
w->writeS(pat->data[k][4+l]);
|
||||
w->writeS(pat->newData[k][DIV_PAT_FX(0)+l]);
|
||||
}
|
||||
#else
|
||||
w->write(&pat->data[k][4],2*curPat[i].effectCols*2); // effects
|
||||
w->write(&pat->newData[k][DIV_PAT_FX(0)],2*curPat[i].effectCols*2); // effects
|
||||
#endif
|
||||
w->writeS(pat->data[k][2]); // instrument
|
||||
w->writeS(pat->newData[k][DIV_PAT_INS]); // instrument
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -418,8 +418,8 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) {
|
|||
ds.subsong[0]->orders.ord[j][i]=i;
|
||||
DivPattern* p=ds.subsong[0]->pat[j].getPattern(i,true);
|
||||
if (j==3 && seq[i].speed) {
|
||||
p->data[0][6]=0x0f;
|
||||
p->data[0][7]=seq[i].speed;
|
||||
p->newData[0][DIV_PAT_FX(1)]=0x0f;
|
||||
p->newData[0][DIV_PAT_FXVAL(1)]=seq[i].speed;
|
||||
}
|
||||
|
||||
bool ignoreNext=false;
|
||||
|
|
@ -428,80 +428,65 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) {
|
|||
FCPattern& fp=pat[seq[i].pat[j]];
|
||||
if (fp.note[k]>0 && fp.note[k]<0x49) {
|
||||
lastNote[j]=fp.note[k];
|
||||
short note=(fp.note[k]+seq[i].transpose[j])%12;
|
||||
short octave=2+((fp.note[k]+seq[i].transpose[j])/12);
|
||||
if (fp.note[k]>=0x3d) octave-=6;
|
||||
if (note==0) {
|
||||
note=12;
|
||||
octave--;
|
||||
}
|
||||
octave&=0xff;
|
||||
p->data[k][0]=note;
|
||||
p->data[k][1]=octave;
|
||||
p->newData[k][DIV_PAT_NOTE]=fp.note[k]+seq[i].transpose[j]+84;
|
||||
// wrap-around if the note is too high
|
||||
if (fp.note[k]>=0x3d) p->newData[k][DIV_PAT_NOTE]-=6*12;
|
||||
if (isSliding[j]) {
|
||||
isSliding[j]=false;
|
||||
p->data[k][4]=2;
|
||||
p->data[k][5]=0;
|
||||
p->newData[k][DIV_PAT_FX(0)]=2;
|
||||
p->newData[k][DIV_PAT_FXVAL(0)]=0;
|
||||
}
|
||||
} else if (fp.note[k]==0x49) {
|
||||
if (k>0) {
|
||||
p->data[k-1][4]=0x0d;
|
||||
p->data[k-1][5]=0;
|
||||
p->newData[k-1][DIV_PAT_FX(0)]=0x0d;
|
||||
p->newData[k-1][DIV_PAT_FXVAL(0)]=0;
|
||||
}
|
||||
} else if (k==0 && lastTranspose[j]!=seq[i].transpose[j]) {
|
||||
p->data[0][2]=lastIns[j];
|
||||
p->data[0][4]=0x03;
|
||||
p->data[0][5]=0xff;
|
||||
p->newData[0][DIV_PAT_INS]=lastIns[j];
|
||||
p->newData[0][DIV_PAT_FX(0)]=0x03;
|
||||
p->newData[0][DIV_PAT_FXVAL(0)]=0xff;
|
||||
lastTranspose[j]=seq[i].transpose[j];
|
||||
|
||||
short note=(lastNote[j]+seq[i].transpose[j])%12;
|
||||
short octave=2+((lastNote[j]+seq[i].transpose[j])/12);
|
||||
if (lastNote[j]>=0x3d) octave-=6;
|
||||
if (note==0) {
|
||||
note=12;
|
||||
octave--;
|
||||
}
|
||||
octave&=0xff;
|
||||
p->data[k][0]=note;
|
||||
p->data[k][1]=octave;
|
||||
p->newData[k][DIV_PAT_NOTE]=lastNote[j]+seq[i].transpose[j]+84;
|
||||
// wrap-around if the note is too high
|
||||
if (lastNote[j]>=0x3d) p->newData[k][DIV_PAT_NOTE]-=6*12;
|
||||
}
|
||||
if (fp.val[k]) {
|
||||
if (ignoreNext) {
|
||||
ignoreNext=false;
|
||||
} else {
|
||||
if (fp.val[k]==0xf0) {
|
||||
p->data[k][0]=100;
|
||||
p->data[k][1]=0;
|
||||
p->data[k][2]=-1;
|
||||
p->newData[k][DIV_PAT_NOTE]=DIV_NOTE_OFF;
|
||||
p->newData[k][DIV_PAT_INS]=-1;
|
||||
} else if (fp.val[k]&0xe0) {
|
||||
if (fp.val[k]&0x40) {
|
||||
p->data[k][4]=2;
|
||||
p->data[k][5]=0;
|
||||
p->newData[k][DIV_PAT_FX(0)]=2;
|
||||
p->newData[k][DIV_PAT_FXVAL(0)]=0;
|
||||
isSliding[j]=false;
|
||||
} else if (fp.val[k]&0x80) {
|
||||
isSliding[j]=true;
|
||||
if (k<31) {
|
||||
if (fp.val[k+1]&0x20) {
|
||||
p->data[k][4]=2;
|
||||
p->data[k][5]=fp.val[k+1]&0x1f;
|
||||
p->newData[k][DIV_PAT_FX(0)]=2;
|
||||
p->newData[k][DIV_PAT_FXVAL(0)]=fp.val[k+1]&0x1f;
|
||||
} else {
|
||||
p->data[k][4]=1;
|
||||
p->data[k][5]=fp.val[k+1]&0x1f;
|
||||
p->newData[k][DIV_PAT_FX(0)]=1;
|
||||
p->newData[k][DIV_PAT_FXVAL(0)]=fp.val[k+1]&0x1f;
|
||||
}
|
||||
ignoreNext=true;
|
||||
} else {
|
||||
p->data[k][4]=2;
|
||||
p->data[k][5]=0;
|
||||
p->newData[k][DIV_PAT_FX(0)]=2;
|
||||
p->newData[k][DIV_PAT_FXVAL(0)]=0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
p->data[k][2]=(fp.val[k]+seq[i].offsetIns[j])&0x3f;
|
||||
lastIns[j]=p->data[k][2];
|
||||
p->newData[k][DIV_PAT_INS]=(fp.val[k]+seq[i].offsetIns[j])&0x3f;
|
||||
lastIns[j]=p->newData[k][DIV_PAT_INS];
|
||||
}
|
||||
}
|
||||
} else if (fp.note[k]>0 && fp.note[k]<0x49) {
|
||||
p->data[k][2]=seq[i].offsetIns[j];
|
||||
lastIns[j]=p->data[k][2];
|
||||
p->newData[k][DIV_PAT_INS]=seq[i].offsetIns[j];
|
||||
lastIns[j]=p->newData[k][DIV_PAT_INS];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -270,7 +270,7 @@ int convert_vrc6_duties[4] = {1, 3, 7, 3};
|
|||
|
||||
int findEmptyFx(short* data) {
|
||||
for (int i=0; i<7; i++) {
|
||||
if (data[4+i*2]==-1) return i;
|
||||
if (data[DIV_PAT_FX(i)]==-1) return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
|
@ -1752,17 +1752,13 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
|
|||
|
||||
if (map_channels[ch] != 0xff) {
|
||||
if (nextNote == 0x0d) {
|
||||
pat->data[row][0] = 101;
|
||||
pat->newData[row][DIV_PAT_NOTE] = DIV_NOTE_REL;
|
||||
} else if (nextNote == 0x0e) {
|
||||
pat->data[row][0] = 100;
|
||||
} else if (nextNote == 0x01) {
|
||||
pat->data[row][0] = 12;
|
||||
pat->data[row][1] = nextOctave - 1;
|
||||
pat->newData[row][DIV_PAT_NOTE] = DIV_NOTE_OFF;
|
||||
} else if (nextNote == 0) {
|
||||
pat->data[row][0] = 0;
|
||||
pat->newData[row][DIV_PAT_NOTE] = -1;
|
||||
} else if (nextNote < 0x0d) {
|
||||
pat->data[row][0] = nextNote - 1;
|
||||
pat->data[row][1] = nextOctave;
|
||||
pat->newData[row][DIV_PAT_NOTE] = nextOctave*12 + (nextNote - 1) + 60;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1770,27 +1766,27 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
|
|||
// TODO: you sure about 0xff?
|
||||
if (map_channels[ch] != 0xff) {
|
||||
if (nextIns < 0x40 && nextNote != 0x0d && nextNote != 0x0e) {
|
||||
pat->data[row][2] = nextIns;
|
||||
pat->newData[row][DIV_PAT_INS] = nextIns;
|
||||
} else {
|
||||
pat->data[row][2] = -1;
|
||||
pat->newData[row][DIV_PAT_INS] = -1;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned char nextVol = reader.readC();
|
||||
if (map_channels[ch] != 0xff) {
|
||||
if (nextVol < 0x10) {
|
||||
pat->data[row][3] = nextVol;
|
||||
pat->newData[row][DIV_PAT_VOL] = nextVol;
|
||||
if (map_channels[ch] == vrc6_saw_chan) // scale volume
|
||||
{
|
||||
// TODO: shouldn't it be 32?
|
||||
pat->data[row][3] = (pat->data[row][3] * 42) / 15;
|
||||
pat->newData[row][DIV_PAT_VOL] = (pat->newData[row][DIV_PAT_VOL] * 42) / 15;
|
||||
}
|
||||
|
||||
if (map_channels[ch] == fds_chan) {
|
||||
pat->data[row][3] = (pat->data[row][3] * 31) / 15;
|
||||
pat->newData[row][DIV_PAT_VOL] = (pat->newData[row][DIV_PAT_VOL] * 31) / 15;
|
||||
}
|
||||
} else {
|
||||
pat->data[row][3] = -1;
|
||||
pat->newData[row][DIV_PAT_VOL] = -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1829,15 +1825,15 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
|
|||
if (nextEffect == FT_EF_SPEED && nextEffectVal < 20)
|
||||
nextEffectVal++;
|
||||
|
||||
if (pat->data[row][3] == 0)
|
||||
pat->data[row][3] = 0xf;
|
||||
if (pat->newData[row][DIV_PAT_VOL] == 0)
|
||||
pat->newData[row][DIV_PAT_VOL] = 0xf;
|
||||
else {
|
||||
pat->data[row][3]--;
|
||||
pat->data[row][3] &= 0x0F;
|
||||
pat->newData[row][DIV_PAT_VOL]--;
|
||||
pat->newData[row][DIV_PAT_VOL] &= 0x0F;
|
||||
}
|
||||
|
||||
if (pat->data[row][0] == 0)
|
||||
pat->data[row][2] = -1;
|
||||
if (pat->newData[row][DIV_PAT_NOTE] == -1)
|
||||
pat->newData[row][DIV_PAT_INS] = -1;
|
||||
}
|
||||
|
||||
if (blockVersion == 3) {
|
||||
|
|
@ -1902,43 +1898,43 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
|
|||
|
||||
if (map_channels[ch] != 0xff) {
|
||||
if (nextEffect == 0 && nextEffectVal == 0) {
|
||||
pat->data[row][4 + (j * 2)] = -1;
|
||||
pat->data[row][5 + (j * 2)] = -1;
|
||||
pat->newData[row][DIV_PAT_FX(j)] = -1;
|
||||
pat->newData[row][DIV_PAT_FXVAL(j)] = -1;
|
||||
} else {
|
||||
if ((eft && nextEffect<eftEffectMapSize) || (!eft && nextEffect<ftEffectMapSize)) {
|
||||
if (eft) {
|
||||
pat->data[row][4 + (j * 2)] = eftEffectMap[nextEffect];
|
||||
pat->data[row][5 + (j * 2)] = eftEffectMap[nextEffect] == -1 ? -1 : nextEffectVal;
|
||||
pat->newData[row][DIV_PAT_FX(j)] = eftEffectMap[nextEffect];
|
||||
pat->newData[row][DIV_PAT_FXVAL(j)] = eftEffectMap[nextEffect] == -1 ? -1 : nextEffectVal;
|
||||
|
||||
if (pat->data[row][4 + (j * 2)] == 0x100) {
|
||||
pat->data[row][3] += pat->data[row][5 + (j * 2)] ? 0x10 : 0; // extra volume bit for AY8930
|
||||
pat->data[row][4 + (j * 2)] = -1;
|
||||
pat->data[row][5 + (j * 2)] = -1;
|
||||
if (pat->newData[row][DIV_PAT_FX(j)] == 0x100) {
|
||||
pat->newData[row][DIV_PAT_VOL] += pat->newData[row][DIV_PAT_FXVAL(j)] ? 0x10 : 0; // extra volume bit for AY8930
|
||||
pat->newData[row][DIV_PAT_FX(j)] = -1;
|
||||
pat->newData[row][DIV_PAT_FXVAL(j)] = -1;
|
||||
}
|
||||
|
||||
if (eftEffectMap[nextEffect] == 0x0f && nextEffectVal > 0x1f) {
|
||||
pat->data[row][4 + (j * 2)] = 0xfd; // BPM speed change!
|
||||
pat->newData[row][DIV_PAT_FX(j)] = 0xfd; // BPM speed change!
|
||||
}
|
||||
|
||||
if ((eftEffectMap[nextEffect] == 0xe1 || eftEffectMap[nextEffect] == 0xe2) && (nextEffectVal & 0xf0) == 0) {
|
||||
pat->data[row][5 + (j * 2)] |= 0x10; // in FamiTracker if e1/e2 commands speed is 0 the portamento still has some speed!
|
||||
pat->newData[row][DIV_PAT_FXVAL(j)] |= 0x10; // in FamiTracker if e1/e2 commands speed is 0 the portamento still has some speed!
|
||||
}
|
||||
} else {
|
||||
pat->data[row][4 + (j * 2)] = ftEffectMap[nextEffect];
|
||||
pat->data[row][5 + (j * 2)] = ftEffectMap[nextEffect] == -1 ? -1 : nextEffectVal;
|
||||
pat->newData[row][DIV_PAT_FX(j)] = ftEffectMap[nextEffect];
|
||||
pat->newData[row][DIV_PAT_FXVAL(j)] = ftEffectMap[nextEffect] == -1 ? -1 : nextEffectVal;
|
||||
|
||||
if (ftEffectMap[nextEffect] == 0x0f && nextEffectVal > 0x1f) {
|
||||
pat->data[row][4 + (j * 2)] = 0xfd; // BPM speed change!
|
||||
pat->newData[row][DIV_PAT_FX(j)] = 0xfd; // BPM speed change!
|
||||
}
|
||||
|
||||
if ((ftEffectMap[nextEffect] == 0xe1 || ftEffectMap[nextEffect] == 0xe2) && (nextEffectVal & 0xf0) == 0) {
|
||||
pat->data[row][5 + (j * 2)] |= 0x10; // in FamiTracker if e1/e2 commands speed is 0 the portamento still has some speed!
|
||||
pat->newData[row][DIV_PAT_FXVAL(j)] |= 0x10; // in FamiTracker if e1/e2 commands speed is 0 the portamento still has some speed!
|
||||
}
|
||||
}
|
||||
for (int v = 0; v < 8; v++) {
|
||||
if (map_channels[ch] == n163_chans[v]) {
|
||||
if (pat->data[row][4 + (j * 2)] == 0x12) {
|
||||
pat->data[row][4 + (j * 2)] = 0x110; // N163 wave change (we'll map this later)
|
||||
if (pat->newData[row][DIV_PAT_FX(j)] == 0x12) {
|
||||
pat->newData[row][DIV_PAT_FX(j)] = 0x110; // N163 wave change (we'll map this later)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1947,23 +1943,24 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
|
|||
{
|
||||
if (map_channels[ch] == vrc7_chans[vrr])
|
||||
{
|
||||
if (pat->data[row][4 + (j * 2)] == 0x12)
|
||||
if (pat->newData[row][DIV_PAT_FX(j)] == 0x12)
|
||||
{
|
||||
pat->data[row][4 + (j * 2)] = 0x10; // set VRC7 patch
|
||||
pat->newData[row][DIV_PAT_FX(j)] = 0x10; // set VRC7 patch
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int v = 0; v < 3; v++) {
|
||||
if (map_channels[ch] == s5b_chans[v] || map_channels[ch] == ay8930_chans[v]) {
|
||||
if (pat->data[row][4 + (j * 2)] == 0x22 && (pat->data[row][5 + (j * 2)] & 0xf0) != 0) {
|
||||
pat->data[row][4 + (7 * 2)] = -666; //marker
|
||||
if (pat->newData[row][DIV_PAT_FX(j)] == 0x22 && (pat->newData[row][DIV_PAT_FXVAL(j)] & 0xf0) != 0) {
|
||||
// TODO: in the second stage of pattern refactor this will have to change.
|
||||
pat->newData[row][DIV_PAT_FX(7)] = -666; //marker
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
pat->data[row][4 + (j * 2)] = -1;
|
||||
pat->data[row][5 + (j * 2)] = -1;
|
||||
pat->newData[row][DIV_PAT_FX(j)] = -1;
|
||||
pat->newData[row][DIV_PAT_FXVAL(j)] = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2438,8 +2435,8 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
|
|||
if (ds.subsong[j]->pat[ii].data[k] == NULL)
|
||||
continue;
|
||||
for (int l = 0; l < ds.subsong[j]->patLen; l++) {
|
||||
if (ds.subsong[j]->pat[ii].data[k]->data[l][2] > index) {
|
||||
ds.subsong[j]->pat[ii].data[k]->data[l][2]--;
|
||||
if (ds.subsong[j]->pat[ii].data[k]->newData[l][DIV_PAT_INS] > index) {
|
||||
ds.subsong[j]->pat[ii].data[k]->newData[l][DIV_PAT_INS]--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2456,12 +2453,12 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
|
|||
if (ds.subsong[j]->pat[ii].data[k] == NULL)
|
||||
continue;
|
||||
for (int l = 0; l < ds.subsong[j]->patLen; l++) {
|
||||
if (ds.subsong[j]->pat[ii].data[k]->data[l][4 + 7*2] == -666) {
|
||||
if (ds.subsong[j]->pat[ii].data[k]->newData[l][DIV_PAT_FX(7)] == -666) {
|
||||
bool converted = false;
|
||||
// for()? if()? THESE ARE NOT FUNCTIONS!
|
||||
for (int hh = 0; hh < 7; hh++) { // oh and now you 1TBS up. oh man...
|
||||
if (ds.subsong[j]->pat[ii].data[k]->data[l][4 + hh*2] == 0x22 && !converted) {
|
||||
int slot = findEmptyFx(ds.subsong[j]->pat[ii].data[k]->data[l]);
|
||||
if (ds.subsong[j]->pat[ii].data[k]->newData[l][DIV_PAT_FX(hh)] == 0x22 && !converted) {
|
||||
int slot = findEmptyFx(ds.subsong[j]->pat[ii].data[k]->newData[l]);
|
||||
if (slot != -1) {
|
||||
// space your comments damn it!
|
||||
// Hxy - Envelope automatic pitch
|
||||
|
|
@ -2469,7 +2466,7 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
|
|||
// Sets envelope period to the note period shifted by x and envelope type y.
|
||||
// Approximate envelope frequency is note frequency * (2^|x - 8|) / 32.
|
||||
|
||||
int ftAutoEnv = (ds.subsong[j]->pat[ii].data[k]->data[l][5 + hh*2] >> 4) & 15;
|
||||
int ftAutoEnv = (ds.subsong[j]->pat[ii].data[k]->newData[l][DIV_PAT_FXVAL(hh)] >> 4) & 15;
|
||||
int autoEnvDen = 16; // ???? with 32 it's an octave lower...
|
||||
int autoEnvNum = (1 << (abs(ftAutoEnv - 8)));
|
||||
|
||||
|
|
@ -2479,18 +2476,18 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
|
|||
}
|
||||
|
||||
if (autoEnvDen < 16 && autoEnvNum < 16) {
|
||||
ds.subsong[j]->pat[ii].data[k]->data[l][4 + slot*2] = 0x29;
|
||||
ds.subsong[j]->pat[ii].data[k]->data[l][5 + slot*2] = (autoEnvNum << 4) | autoEnvDen;
|
||||
ds.subsong[j]->pat[ii].data[k]->newData[l][DIV_PAT_FX(slot)] = 0x29;
|
||||
ds.subsong[j]->pat[ii].data[k]->newData[l][DIV_PAT_FXVAL(slot)] = (autoEnvNum << 4) | autoEnvDen;
|
||||
}
|
||||
|
||||
ds.subsong[j]->pat[ii].data[k]->data[l][5 + hh*2] = (ds.subsong[j]->pat[ii].data[k]->data[l][5 + hh*2] & 0xf) << 4;
|
||||
ds.subsong[j]->pat[ii].data[k]->newData[l][DIV_PAT_FXVAL(hh)] = (ds.subsong[j]->pat[ii].data[k]->newData[l][DIV_PAT_FXVAL(hh)] & 0xf) << 4;
|
||||
|
||||
converted = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ds.subsong[j]->pat[ii].data[k]->data[l][4 + (7 * 2)] = -1; //delete marker
|
||||
ds.subsong[j]->pat[ii].data[k]->newData[l][DIV_PAT_FX(7)] = -1; //delete marker
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2506,10 +2503,10 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
|
|||
for (int p = 0; p < s->ordersLen; p++) {
|
||||
for (int r = 0; r < s->patLen; r++) {
|
||||
DivPattern* pat = s->pat[c].getPattern(s->orders.ord[c][p], true);
|
||||
short* s_row_data = pat->data[r];
|
||||
short* s_row_data = pat->newData[r];
|
||||
|
||||
for (int eff = 0; eff < DIV_MAX_EFFECTS - 1; eff++) {
|
||||
if (s_row_data[4 + 2 * eff] != -1 && eff + 1 > num_fx) {
|
||||
if (s_row_data[DIV_PAT_FX(eff)] != -1 && eff + 1 > num_fx) {
|
||||
num_fx = eff + 1;
|
||||
}
|
||||
}
|
||||
|
|
@ -2556,7 +2553,7 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
|
|||
continue;
|
||||
for (int l = 0; l < ds.subsong[j]->patLen; l++) {
|
||||
// 1TBS > GNU
|
||||
if (ds.subsong[j]->pat[ii].data[k]->data[l][2] == i) { // instrument
|
||||
if (ds.subsong[j]->pat[ii].data[k]->newData[l][DIV_PAT_INS] == i) { // instrument
|
||||
DivInstrument* ins = ds.ins[i];
|
||||
bool go_to_end = false;
|
||||
|
||||
|
|
@ -2606,7 +2603,7 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
|
|||
if (ds.subsong[j]->pat[ii].data[k] == NULL)
|
||||
continue;
|
||||
for (int l = 0; l < ds.subsong[j]->patLen; l++) {
|
||||
if (ds.subsong[j]->pat[ii].data[k]->data[l][2] == i) // instrument
|
||||
if (ds.subsong[j]->pat[ii].data[k]->newData[l][DIV_PAT_INS] == i) // instrument
|
||||
{
|
||||
DivInstrument* ins = ds.ins[i];
|
||||
bool go_to_end = false;
|
||||
|
|
@ -2658,7 +2655,7 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
|
|||
if (ds.subsong[j]->pat[ii].data[k] == NULL)
|
||||
continue;
|
||||
for (int l = 0; l < ds.subsong[j]->patLen; l++) {
|
||||
if (ds.subsong[j]->pat[ii].data[k]->data[l][2] == i) // instrument
|
||||
if (ds.subsong[j]->pat[ii].data[k]->newData[l][DIV_PAT_INS] == i) // instrument
|
||||
{
|
||||
DivInstrument* ins = ds.ins[i];
|
||||
bool go_to_end = false;
|
||||
|
|
@ -2729,17 +2726,17 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
|
|||
if (ds.subsong[j]->pat[ii].data[k] == NULL)
|
||||
continue;
|
||||
for (int l = 0; l < ds.subsong[j]->patLen; l++) {
|
||||
if (ds.subsong[j]->pat[ii].data[k]->data[l][2] == ins_vrc6_conv[i][0] && (ii == vrc6_chans[0] || ii == vrc6_chans[1])) // change ins index
|
||||
if (ds.subsong[j]->pat[ii].data[k]->newData[l][DIV_PAT_INS] == ins_vrc6_conv[i][0] && (ii == vrc6_chans[0] || ii == vrc6_chans[1])) // change ins index
|
||||
{
|
||||
ds.subsong[j]->pat[ii].data[k]->data[l][2] = ins_vrc6_conv[i][1];
|
||||
ds.subsong[j]->pat[ii].data[k]->newData[l][DIV_PAT_INS] = ins_vrc6_conv[i][1];
|
||||
}
|
||||
|
||||
if (ds.subsong[j]->pat[ii].data[k]->data[l][2] == ins_vrc6_saw_conv[i][0] && ii == vrc6_saw_chan) {
|
||||
ds.subsong[j]->pat[ii].data[k]->data[l][2] = ins_vrc6_saw_conv[i][1];
|
||||
if (ds.subsong[j]->pat[ii].data[k]->newData[l][DIV_PAT_INS] == ins_vrc6_saw_conv[i][0] && ii == vrc6_saw_chan) {
|
||||
ds.subsong[j]->pat[ii].data[k]->newData[l][DIV_PAT_INS] = ins_vrc6_saw_conv[i][1];
|
||||
}
|
||||
|
||||
if (ds.subsong[j]->pat[ii].data[k]->data[l][2] == ins_nes_conv[i][0] && (ii == mmc5_chans[0] || ii == mmc5_chans[1] || ii < 5)) {
|
||||
ds.subsong[j]->pat[ii].data[k]->data[l][2] = ins_nes_conv[i][1];
|
||||
if (ds.subsong[j]->pat[ii].data[k]->newData[l][DIV_PAT_INS] == ins_nes_conv[i][0] && (ii == mmc5_chans[0] || ii == mmc5_chans[1] || ii < 5)) {
|
||||
ds.subsong[j]->pat[ii].data[k]->newData[l][DIV_PAT_INS] = ins_nes_conv[i][1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2785,19 +2782,19 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
|
|||
DivPattern* p=i->pat[j].getPattern(i->orders.ord[j][k],true);
|
||||
for (int l=0; l<i->patLen; l++) {
|
||||
// check for instrument change
|
||||
if (p->data[l][2]!=-1) {
|
||||
curWaveOff=n163WaveOff[p->data[l][2]&127];
|
||||
if (p->newData[l][DIV_PAT_INS]!=-1) {
|
||||
curWaveOff=n163WaveOff[p->newData[l][DIV_PAT_INS]&127];
|
||||
}
|
||||
|
||||
// check effect columns for 0x110 (dummy wave change)
|
||||
for (int m=0; m<i->pat[j].effectCols; m++) {
|
||||
if (p->data[l][4+(m<<1)]==0x110) {
|
||||
if (p->newData[l][DIV_PAT_FX(m)]==0x110) {
|
||||
// map wave
|
||||
p->data[l][4+(m<<1)]=0x10;
|
||||
if (p->data[l][5+(m<<1)]==-1) {
|
||||
p->data[l][5+(m<<1)]=curWaveOff&0xff;
|
||||
p->newData[l][DIV_PAT_FX(m)]=0x10;
|
||||
if (p->newData[l][DIV_PAT_FXVAL(m)]==-1) {
|
||||
p->newData[l][DIV_PAT_FXVAL(m)]=curWaveOff&0xff;
|
||||
} else {
|
||||
p->data[l][5+(m<<1)]=(p->data[l][5+(m<<1)]+curWaveOff)&0xff;
|
||||
p->newData[l][DIV_PAT_FXVAL(m)]=(p->newData[l][DIV_PAT_FXVAL(m)]+curWaveOff)&0xff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1778,32 +1778,28 @@ bool DivEngine::loadFur(unsigned char* file, size_t len, int variantID) {
|
|||
|
||||
if (mask&1) { // note
|
||||
unsigned char note=reader.readC();
|
||||
// TODO: PAT2 format with new off/===/rel values!
|
||||
if (note==180) {
|
||||
pat->data[j][0]=100;
|
||||
pat->data[j][1]=0;
|
||||
pat->newData[j][0]=DIV_NOTE_OFF;
|
||||
} else if (note==181) {
|
||||
pat->data[j][0]=101;
|
||||
pat->data[j][1]=0;
|
||||
pat->newData[j][0]=DIV_NOTE_REL;
|
||||
} else if (note==182) {
|
||||
pat->data[j][0]=102;
|
||||
pat->data[j][1]=0;
|
||||
pat->newData[j][0]=DIV_MACRO_REL;
|
||||
} else if (note<180) {
|
||||
pat->data[j][0]=newFormatNotes[note];
|
||||
pat->data[j][1]=newFormatOctaves[note];
|
||||
pat->newData[j][DIV_PAT_NOTE]=note;
|
||||
} else {
|
||||
pat->data[j][0]=0;
|
||||
pat->data[j][1]=0;
|
||||
pat->newData[j][0]=-1;
|
||||
}
|
||||
}
|
||||
if (mask&2) { // instrument
|
||||
pat->data[j][2]=(unsigned char)reader.readC();
|
||||
pat->newData[j][DIV_PAT_INS]=(unsigned char)reader.readC();
|
||||
}
|
||||
if (mask&4) { // volume
|
||||
pat->data[j][3]=(unsigned char)reader.readC();
|
||||
pat->newData[j][DIV_PAT_VOL]=(unsigned char)reader.readC();
|
||||
}
|
||||
for (unsigned char k=0; k<16; k++) {
|
||||
if (effectMask&(1<<k)) {
|
||||
pat->data[j][4+k]=(unsigned char)reader.readC();
|
||||
pat->newData[j][DIV_PAT_FX(0)+k]=(unsigned char)reader.readC();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1844,18 +1840,20 @@ bool DivEngine::loadFur(unsigned char* file, size_t len, int variantID) {
|
|||
|
||||
DivPattern* pat=ds.subsong[subs]->pat[chan].getPattern(index,true);
|
||||
for (int j=0; j<ds.subsong[subs]->patLen; j++) {
|
||||
pat->data[j][0]=reader.readS();
|
||||
pat->data[j][1]=reader.readS();
|
||||
pat->data[j][2]=reader.readS();
|
||||
pat->data[j][3]=reader.readS();
|
||||
for (int k=0; k<ds.subsong[subs]->pat[chan].effectCols; k++) {
|
||||
pat->data[j][4+(k<<1)]=reader.readS();
|
||||
pat->data[j][5+(k<<1)]=reader.readS();
|
||||
short note=reader.readS();
|
||||
short octave=reader.readS();
|
||||
if (note==0 && octave!=0) {
|
||||
logD("what? %d:%d:%d note %d octave %d",chan,i,j,note,octave);
|
||||
note=12;
|
||||
octave--;
|
||||
}
|
||||
if (pat->data[j][0]==0 && pat->data[j][1]!=0) {
|
||||
logD("what? %d:%d:%d note %d octave %d",chan,i,j,pat->data[j][0],pat->data[j][1]);
|
||||
pat->data[j][0]=12;
|
||||
pat->data[j][1]--;
|
||||
pat->newData[j][DIV_PAT_NOTE]=splitNoteToNote(note,octave);
|
||||
|
||||
pat->newData[j][DIV_PAT_INS]=reader.readS();
|
||||
pat->newData[j][DIV_PAT_VOL]=reader.readS();
|
||||
for (int k=0; k<ds.subsong[subs]->pat[chan].effectCols; k++) {
|
||||
pat->newData[j][DIV_PAT_FX(k)]=reader.readS();
|
||||
pat->newData[j][DIV_PAT_FXVAL(k)]=reader.readS();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2171,7 +2169,7 @@ bool DivEngine::loadFur(unsigned char* file, size_t len, int variantID) {
|
|||
return true;
|
||||
}
|
||||
|
||||
SafeWriter* DivEngine::saveFur(bool notPrimary, bool newPatternFormat) {
|
||||
SafeWriter* DivEngine::saveFur(bool notPrimary) {
|
||||
saveLock.lock();
|
||||
std::vector<int> subSongPtr;
|
||||
std::vector<int> sysFlagsPtr;
|
||||
|
|
@ -2622,133 +2620,100 @@ SafeWriter* DivEngine::saveFur(bool notPrimary, bool newPatternFormat) {
|
|||
DivPattern* pat=song.subsong[i.subsong]->pat[i.chan].getPattern(i.pat,false);
|
||||
patPtr.push_back(w->tell());
|
||||
|
||||
if (newPatternFormat) {
|
||||
w->write("PATN",4);
|
||||
blockStartSeek=w->tell();
|
||||
w->writeI(0);
|
||||
w->write("PATN",4);
|
||||
blockStartSeek=w->tell();
|
||||
w->writeI(0);
|
||||
|
||||
w->writeC(i.subsong);
|
||||
w->writeC(i.chan);
|
||||
w->writeS(i.pat);
|
||||
w->writeString(pat->name,false);
|
||||
w->writeC(i.subsong);
|
||||
w->writeC(i.chan);
|
||||
w->writeS(i.pat);
|
||||
w->writeString(pat->name,false);
|
||||
|
||||
unsigned char emptyRows=0;
|
||||
unsigned char emptyRows=0;
|
||||
|
||||
for (int j=0; j<song.subsong[i.subsong]->patLen; j++) {
|
||||
unsigned char mask=0;
|
||||
unsigned char finalNote=255;
|
||||
unsigned short effectMask=0;
|
||||
for (int j=0; j<song.subsong[i.subsong]->patLen; j++) {
|
||||
unsigned char mask=0;
|
||||
unsigned char finalNote=255;
|
||||
unsigned short effectMask=0;
|
||||
|
||||
if (pat->data[j][0]==100) {
|
||||
finalNote=180;
|
||||
} else if (pat->data[j][0]==101) { // note release
|
||||
finalNote=181;
|
||||
} else if (pat->data[j][0]==102) { // macro release
|
||||
finalNote=182;
|
||||
} else if (pat->data[j][1]==0 && pat->data[j][0]==0) {
|
||||
finalNote=255;
|
||||
} else {
|
||||
int seek=(pat->data[j][0]+(signed char)pat->data[j][1]*12)+60;
|
||||
if (seek<0 || seek>=180) {
|
||||
finalNote=255;
|
||||
} else {
|
||||
finalNote=seek;
|
||||
}
|
||||
}
|
||||
|
||||
if (finalNote!=255) mask|=1; // note
|
||||
if (pat->data[j][2]!=-1) mask|=2; // instrument
|
||||
if (pat->data[j][3]!=-1) mask|=4; // volume
|
||||
for (int k=0; k<song.subsong[i.subsong]->pat[i.chan].effectCols*2; k+=2) {
|
||||
if (k==0) {
|
||||
if (pat->data[j][4+k]!=-1) mask|=8;
|
||||
if (pat->data[j][5+k]!=-1) mask|=16;
|
||||
} else if (k<8) {
|
||||
if (pat->data[j][4+k]!=-1 || pat->data[j][5+k]!=-1) mask|=32;
|
||||
} else {
|
||||
if (pat->data[j][4+k]!=-1 || pat->data[j][5+k]!=-1) mask|=64;
|
||||
}
|
||||
|
||||
if (pat->data[j][4+k]!=-1) effectMask|=(1<<k);
|
||||
if (pat->data[j][5+k]!=-1) effectMask|=(2<<k);
|
||||
}
|
||||
|
||||
if (mask==0) {
|
||||
emptyRows++;
|
||||
if (emptyRows>127) {
|
||||
w->writeC(128|(emptyRows-2));
|
||||
emptyRows=0;
|
||||
}
|
||||
} else {
|
||||
if (emptyRows>1) {
|
||||
w->writeC(128|(emptyRows-2));
|
||||
emptyRows=0;
|
||||
} else if (emptyRows) {
|
||||
w->writeC(0);
|
||||
emptyRows=0;
|
||||
}
|
||||
|
||||
w->writeC(mask);
|
||||
|
||||
if (mask&32) w->writeC(effectMask&0xff);
|
||||
if (mask&64) w->writeC((effectMask>>8)&0xff);
|
||||
|
||||
if (mask&1) w->writeC(finalNote);
|
||||
if (mask&2) w->writeC(pat->data[j][2]);
|
||||
if (mask&4) w->writeC(pat->data[j][3]);
|
||||
if (mask&8) w->writeC(pat->data[j][4]);
|
||||
if (mask&16) w->writeC(pat->data[j][5]);
|
||||
if (mask&32) {
|
||||
if (effectMask&4) w->writeC(pat->data[j][6]);
|
||||
if (effectMask&8) w->writeC(pat->data[j][7]);
|
||||
if (effectMask&16) w->writeC(pat->data[j][8]);
|
||||
if (effectMask&32) w->writeC(pat->data[j][9]);
|
||||
if (effectMask&64) w->writeC(pat->data[j][10]);
|
||||
if (effectMask&128) w->writeC(pat->data[j][11]);
|
||||
}
|
||||
if (mask&64) {
|
||||
if (effectMask&256) w->writeC(pat->data[j][12]);
|
||||
if (effectMask&512) w->writeC(pat->data[j][13]);
|
||||
if (effectMask&1024) w->writeC(pat->data[j][14]);
|
||||
if (effectMask&2048) w->writeC(pat->data[j][15]);
|
||||
if (effectMask&4096) w->writeC(pat->data[j][16]);
|
||||
if (effectMask&8192) w->writeC(pat->data[j][17]);
|
||||
if (effectMask&16384) w->writeC(pat->data[j][18]);
|
||||
if (effectMask&32768) w->writeC(pat->data[j][19]);
|
||||
}
|
||||
}
|
||||
if (pat->newData[j][DIV_PAT_NOTE]==DIV_NOTE_OFF) { // note off
|
||||
finalNote=180;
|
||||
} else if (pat->newData[j][DIV_PAT_NOTE]==DIV_NOTE_REL) { // note release
|
||||
finalNote=181;
|
||||
} else if (pat->newData[j][DIV_PAT_NOTE]==DIV_MACRO_REL) { // macro release
|
||||
finalNote=182;
|
||||
} else if (pat->newData[j][DIV_PAT_NOTE]==-1) { // empty
|
||||
finalNote=255;
|
||||
} else {
|
||||
finalNote=pat->newData[j][DIV_PAT_NOTE];
|
||||
}
|
||||
|
||||
// stop
|
||||
w->writeC(0xff);
|
||||
} else {
|
||||
w->write("PATR",4);
|
||||
blockStartSeek=w->tell();
|
||||
w->writeI(0);
|
||||
|
||||
w->writeS(i.chan);
|
||||
w->writeS(i.pat);
|
||||
w->writeS(i.subsong);
|
||||
|
||||
w->writeS(0); // reserved
|
||||
|
||||
for (int j=0; j<song.subsong[i.subsong]->patLen; j++) {
|
||||
w->writeS(pat->data[j][0]); // note
|
||||
w->writeS(pat->data[j][1]); // octave
|
||||
w->writeS(pat->data[j][2]); // instrument
|
||||
w->writeS(pat->data[j][3]); // volume
|
||||
#ifdef TA_BIG_ENDIAN
|
||||
for (int k=0; k<song.subsong[i.subsong]->pat[i.chan].effectCols*2; k++) {
|
||||
w->writeS(pat->data[j][4+k]);
|
||||
if (finalNote!=255) mask|=1; // note
|
||||
if (pat->newData[j][DIV_PAT_INS]!=-1) mask|=2; // instrument
|
||||
if (pat->newData[j][DIV_PAT_VOL]!=-1) mask|=4; // volume
|
||||
for (int k=0; k<song.subsong[i.subsong]->pat[i.chan].effectCols*2; k+=2) {
|
||||
if (k==0) {
|
||||
if (pat->newData[j][DIV_PAT_FX(0)+k]!=-1) mask|=8;
|
||||
if (pat->newData[j][DIV_PAT_FXVAL(0)+k]!=-1) mask|=16;
|
||||
} else if (k<8) {
|
||||
if (pat->newData[j][DIV_PAT_FX(0)+k]!=-1 || pat->newData[j][DIV_PAT_FXVAL(0)+k]!=-1) mask|=32;
|
||||
} else {
|
||||
if (pat->newData[j][DIV_PAT_FX(0)+k]!=-1 || pat->newData[j][DIV_PAT_FXVAL(0)+k]!=-1) mask|=64;
|
||||
}
|
||||
#else
|
||||
w->write(&pat->data[j][4],2*song.subsong[i.subsong]->pat[i.chan].effectCols*2); // effects
|
||||
#endif
|
||||
|
||||
if (pat->newData[j][DIV_PAT_FX(0)+k]!=-1) effectMask|=(1<<k);
|
||||
if (pat->newData[j][DIV_PAT_FXVAL(0)+k]!=-1) effectMask|=(2<<k);
|
||||
}
|
||||
|
||||
w->writeString(pat->name,false);
|
||||
if (mask==0) {
|
||||
emptyRows++;
|
||||
if (emptyRows>127) {
|
||||
w->writeC(128|(emptyRows-2));
|
||||
emptyRows=0;
|
||||
}
|
||||
} else {
|
||||
if (emptyRows>1) {
|
||||
w->writeC(128|(emptyRows-2));
|
||||
emptyRows=0;
|
||||
} else if (emptyRows) {
|
||||
w->writeC(0);
|
||||
emptyRows=0;
|
||||
}
|
||||
|
||||
w->writeC(mask);
|
||||
|
||||
if (mask&32) w->writeC(effectMask&0xff);
|
||||
if (mask&64) w->writeC((effectMask>>8)&0xff);
|
||||
|
||||
if (mask&1) w->writeC(finalNote);
|
||||
if (mask&2) w->writeC(pat->newData[j][DIV_PAT_INS]);
|
||||
if (mask&4) w->writeC(pat->newData[j][DIV_PAT_VOL]);
|
||||
if (mask&8) w->writeC(pat->newData[j][DIV_PAT_FX(0)]);
|
||||
if (mask&16) w->writeC(pat->newData[j][DIV_PAT_FXVAL(0)]);
|
||||
if (mask&32) {
|
||||
if (effectMask&4) w->writeC(pat->newData[j][DIV_PAT_FX(1)]);
|
||||
if (effectMask&8) w->writeC(pat->newData[j][DIV_PAT_FXVAL(1)]);
|
||||
if (effectMask&16) w->writeC(pat->newData[j][DIV_PAT_FX(2)]);
|
||||
if (effectMask&32) w->writeC(pat->newData[j][DIV_PAT_FXVAL(2)]);
|
||||
if (effectMask&64) w->writeC(pat->newData[j][DIV_PAT_FX(3)]);
|
||||
if (effectMask&128) w->writeC(pat->newData[j][DIV_PAT_FXVAL(3)]);
|
||||
}
|
||||
if (mask&64) {
|
||||
if (effectMask&256) w->writeC(pat->newData[j][DIV_PAT_FX(4)]);
|
||||
if (effectMask&512) w->writeC(pat->newData[j][DIV_PAT_FXVAL(4)]);
|
||||
if (effectMask&1024) w->writeC(pat->newData[j][DIV_PAT_FX(5)]);
|
||||
if (effectMask&2048) w->writeC(pat->newData[j][DIV_PAT_FXVAL(5)]);
|
||||
if (effectMask&4096) w->writeC(pat->newData[j][DIV_PAT_FX(6)]);
|
||||
if (effectMask&8192) w->writeC(pat->newData[j][DIV_PAT_FXVAL(6)]);
|
||||
if (effectMask&16384) w->writeC(pat->newData[j][DIV_PAT_FX(7)]);
|
||||
if (effectMask&32768) w->writeC(pat->newData[j][DIV_PAT_FXVAL(7)]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// stop
|
||||
w->writeC(0xff);
|
||||
|
||||
blockEndSeek=w->tell();
|
||||
w->seek(blockStartSeek,SEEK_SET);
|
||||
w->writeI(blockEndSeek-blockStartSeek-4);
|
||||
|
|
|
|||
|
|
@ -1062,7 +1062,7 @@ bool DivEngine::loadIT(unsigned char* file, size_t len) {
|
|||
int readRow=0;
|
||||
bool mustCommitInitial=true;
|
||||
|
||||
memset(effectCol,4,64);
|
||||
memset(effectCol,0,64);
|
||||
memset(vibStatus,0,64);
|
||||
memset(vibStatusChanged,0,64*sizeof(bool));
|
||||
memset(vibing,0,64*sizeof(bool));
|
||||
|
|
@ -1139,86 +1139,86 @@ bool DivEngine::loadIT(unsigned char* file, size_t len) {
|
|||
for (int j=0; j<64; j++) {
|
||||
DivPattern* p=ds.subsong[0]->pat[j].getPattern(i,true);
|
||||
if (vibing[j]!=vibingOld[j] || vibStatusChanged[j]) {
|
||||
p->data[readRow][effectCol[j]++]=0x04;
|
||||
p->data[readRow][effectCol[j]++]=vibing[j]?vibStatus[j]:0;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=0x04;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=vibing[j]?vibStatus[j]:0;
|
||||
doesVibrato[j]=true;
|
||||
} else if (doesVibrato[j] && mustCommitInitial) {
|
||||
p->data[readRow][effectCol[j]++]=0x04;
|
||||
p->data[readRow][effectCol[j]++]=0;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=0x04;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=0;
|
||||
}
|
||||
|
||||
if (volSliding[j]!=volSlidingOld[j] || volSlideStatusChanged[j]) {
|
||||
if (volSlideStatus[j]>=0xf1 && volSliding[j]) {
|
||||
p->data[readRow][effectCol[j]++]=0xf9;
|
||||
p->data[readRow][effectCol[j]++]=volSlideStatus[j]&15;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=0xf9;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=volSlideStatus[j]&15;
|
||||
volSliding[j]=false;
|
||||
} else if ((volSlideStatus[j]&15)==15 && volSlideStatus[j]>=0x10 && volSliding[j]) {
|
||||
p->data[readRow][effectCol[j]++]=0xf8;
|
||||
p->data[readRow][effectCol[j]++]=volSlideStatus[j]>>4;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=0xf8;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=volSlideStatus[j]>>4;
|
||||
volSliding[j]=false;
|
||||
} else {
|
||||
p->data[readRow][effectCol[j]++]=0xfa;
|
||||
p->data[readRow][effectCol[j]++]=volSliding[j]?volSlideStatus[j]:0;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=0xfa;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=volSliding[j]?volSlideStatus[j]:0;
|
||||
}
|
||||
doesVolSlide[j]=true;
|
||||
} else if (doesVolSlide[j] && mustCommitInitial) {
|
||||
p->data[readRow][effectCol[j]++]=0xfa;
|
||||
p->data[readRow][effectCol[j]++]=0;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=0xfa;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=0;
|
||||
}
|
||||
|
||||
if (porting[j]!=portingOld[j] || portaStatusChanged[j]) {
|
||||
if (portaStatus[j]>=0xe0 && portaType[j]!=3 && porting[j]) {
|
||||
p->data[readRow][effectCol[j]++]=portaType[j]|0xf0;
|
||||
p->data[readRow][effectCol[j]++]=(portaStatus[j]&15)*((portaStatus[j]>=0xf0)?1:1);
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=portaType[j]|0xf0;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=(portaStatus[j]&15)*((portaStatus[j]>=0xf0)?1:1);
|
||||
porting[j]=false;
|
||||
} else {
|
||||
p->data[readRow][effectCol[j]++]=portaType[j];
|
||||
p->data[readRow][effectCol[j]++]=porting[j]?portaStatus[j]:0;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=portaType[j];
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=porting[j]?portaStatus[j]:0;
|
||||
}
|
||||
doesPitchSlide[j]=true;
|
||||
} else if (doesPitchSlide[j] && mustCommitInitial) {
|
||||
p->data[readRow][effectCol[j]++]=0x01;
|
||||
p->data[readRow][effectCol[j]++]=0;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=0x01;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=0;
|
||||
}
|
||||
|
||||
if (arping[j]!=arpingOld[j] || arpStatusChanged[j]) {
|
||||
p->data[readRow][effectCol[j]++]=0x00;
|
||||
p->data[readRow][effectCol[j]++]=arping[j]?arpStatus[j]:0;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=0x00;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=arping[j]?arpStatus[j]:0;
|
||||
doesArp[j]=true;
|
||||
} else if (doesArp[j] && mustCommitInitial) {
|
||||
p->data[readRow][effectCol[j]++]=0x00;
|
||||
p->data[readRow][effectCol[j]++]=0;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=0x00;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=0;
|
||||
}
|
||||
|
||||
if (treming[j]!=tremingOld[j] || tremStatusChanged[j]) {
|
||||
p->data[readRow][effectCol[j]++]=0x07;
|
||||
p->data[readRow][effectCol[j]++]=treming[j]?tremStatus[j]:0;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=0x07;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=treming[j]?tremStatus[j]:0;
|
||||
doesTremolo[j]=true;
|
||||
} else if (doesTremolo[j] && mustCommitInitial) {
|
||||
p->data[readRow][effectCol[j]++]=0x07;
|
||||
p->data[readRow][effectCol[j]++]=0;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=0x07;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=0;
|
||||
}
|
||||
|
||||
if (panning[j]!=panningOld[j] || panStatusChanged[j]) {
|
||||
p->data[readRow][effectCol[j]++]=0x84;
|
||||
p->data[readRow][effectCol[j]++]=panning[j]?panStatus[j]:0;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=0x84;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=panning[j]?panStatus[j]:0;
|
||||
doesPanbrello[j]=true;
|
||||
} else if (doesPanbrello[j] && mustCommitInitial) {
|
||||
p->data[readRow][effectCol[j]++]=0x84;
|
||||
p->data[readRow][effectCol[j]++]=0;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=0x84;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=0;
|
||||
}
|
||||
|
||||
if (panSliding[j]!=panSlidingOld[j] || panSlideStatusChanged[j]) {
|
||||
p->data[readRow][effectCol[j]++]=0x83;
|
||||
p->data[readRow][effectCol[j]++]=panSliding[j]?panSlideStatus[j]:0;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=0x83;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=panSliding[j]?panSlideStatus[j]:0;
|
||||
doesPanSlide[j]=true;
|
||||
} else if (doesPanSlide[j] && mustCommitInitial) {
|
||||
p->data[readRow][effectCol[j]++]=0x83;
|
||||
p->data[readRow][effectCol[j]++]=0;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=0x83;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=0;
|
||||
}
|
||||
|
||||
if ((effectCol[j]>>1)-2>ds.subsong[0]->pat[j].effectCols) {
|
||||
ds.subsong[0]->pat[j].effectCols=(effectCol[j]>>1)-1;
|
||||
if ((effectCol[j]>>1)>=ds.subsong[0]->pat[j].effectCols) {
|
||||
ds.subsong[0]->pat[j].effectCols=(effectCol[j]>>1)+1;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1250,16 +1250,16 @@ bool DivEngine::loadIT(unsigned char* file, size_t len) {
|
|||
if (readRow>0) {
|
||||
// place end of pattern marker
|
||||
DivPattern* p=ds.subsong[0]->pat[0].getPattern(i,true);
|
||||
p->data[readRow-1][effectCol[0]++]=0x0d;
|
||||
p->data[readRow-1][effectCol[0]++]=0;
|
||||
p->newData[readRow-1][DIV_PAT_FX(0)+effectCol[0]++]=0x0d;
|
||||
p->newData[readRow-1][DIV_PAT_FX(0)+effectCol[0]++]=0;
|
||||
|
||||
if ((effectCol[0]>>1)-2>ds.subsong[0]->pat[0].effectCols) {
|
||||
ds.subsong[0]->pat[0].effectCols=(effectCol[0]>>1)-1;
|
||||
if ((effectCol[0]>>1)>=ds.subsong[0]->pat[0].effectCols) {
|
||||
ds.subsong[0]->pat[0].effectCols=(effectCol[0]>>1)+1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
memset(effectCol,4,64);
|
||||
memset(effectCol,0,64);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -1302,25 +1302,17 @@ bool DivEngine::loadIT(unsigned char* file, size_t len) {
|
|||
|
||||
if (hasNote) {
|
||||
if (note[chan]==255) { // note release
|
||||
p->data[readRow][0]=101;
|
||||
p->data[readRow][1]=0;
|
||||
p->newData[readRow][DIV_PAT_NOTE]=DIV_NOTE_REL;
|
||||
} else if (note[chan]==254) { // note off
|
||||
p->data[readRow][0]=100;
|
||||
p->data[readRow][1]=0;
|
||||
p->newData[readRow][DIV_PAT_NOTE]=DIV_NOTE_OFF;
|
||||
} else if (note[chan]<120) {
|
||||
p->data[readRow][0]=note[chan]%12;
|
||||
p->data[readRow][1]=note[chan]/12;
|
||||
if (p->data[readRow][0]==0) {
|
||||
p->data[readRow][0]=12;
|
||||
p->data[readRow][1]--;
|
||||
}
|
||||
p->newData[readRow][DIV_PAT_NOTE]=note[chan]+60;
|
||||
} else { // note fade, but Furnace does not support that
|
||||
p->data[readRow][0]=102;
|
||||
p->data[readRow][1]=0;
|
||||
p->newData[readRow][DIV_PAT_NOTE]=DIV_MACRO_REL;
|
||||
}
|
||||
}
|
||||
if (hasIns) {
|
||||
p->data[readRow][2]=ins[chan]-1;
|
||||
p->newData[readRow][DIV_PAT_INS]=ins[chan]-1;
|
||||
if ((note[chan]<120 || ds.insLen==0) && ins[chan]>0) {
|
||||
unsigned char targetPan=0;
|
||||
if (ds.insLen==0) {
|
||||
|
|
@ -1332,26 +1324,26 @@ bool DivEngine::loadIT(unsigned char* file, size_t len) {
|
|||
}
|
||||
}
|
||||
if (targetPan&128) {
|
||||
p->data[readRow][effectCol[chan]++]=0x80;
|
||||
p->data[readRow][effectCol[chan]++]=CLAMP((targetPan&127)<<2,0,255);
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0x80;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=CLAMP((targetPan&127)<<2,0,255);
|
||||
}
|
||||
}
|
||||
|
||||
if (hasNote && (note[chan]<120 || ds.insLen==0) && ins[chan]>0) {
|
||||
if (ds.insLen==0) {
|
||||
p->data[readRow][3]=defVol[(ins[chan]-1)&255];
|
||||
p->newData[readRow][DIV_PAT_VOL]=defVol[(ins[chan]-1)&255];
|
||||
} else {
|
||||
p->data[readRow][3]=defVol[noteMap[(ins[chan]-1)&255][note[chan]]];
|
||||
p->newData[readRow][DIV_PAT_VOL]=defVol[noteMap[(ins[chan]-1)&255][note[chan]]];
|
||||
}
|
||||
}
|
||||
}
|
||||
if (hasVol) {
|
||||
if (vol[chan]<=64) {
|
||||
p->data[readRow][3]=vol[chan];
|
||||
p->newData[readRow][DIV_PAT_VOL]=vol[chan];
|
||||
} else { // effects in volume column
|
||||
if (vol[chan]>=128 && vol[chan]<=192) { // panning
|
||||
p->data[readRow][effectCol[chan]++]=0x80;
|
||||
p->data[readRow][effectCol[chan]++]=CLAMP((vol[chan]-128)<<2,0,255);
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0x80;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=CLAMP((vol[chan]-128)<<2,0,255);
|
||||
} else if (vol[chan]>=65 && vol[chan]<=74) { // fine vol up
|
||||
} else if (vol[chan]>=75 && vol[chan]<=84) { // fine vol down
|
||||
} else if (vol[chan]>=85 && vol[chan]<=94) { // vol slide up
|
||||
|
|
@ -1398,16 +1390,16 @@ bool DivEngine::loadIT(unsigned char* file, size_t len) {
|
|||
if (hasEffect) {
|
||||
switch (effect[chan]+'A'-1) {
|
||||
case 'A': // speed
|
||||
p->data[readRow][effectCol[chan]++]=0x0f;
|
||||
p->data[readRow][effectCol[chan]++]=effectVal[chan];
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0x0f;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=effectVal[chan];
|
||||
break;
|
||||
case 'B': // go to order
|
||||
p->data[readRow][effectCol[chan]++]=0x0b;
|
||||
p->data[readRow][effectCol[chan]++]=orders[effectVal[chan]];
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0x0b;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=orders[effectVal[chan]];
|
||||
break;
|
||||
case 'C': // next order
|
||||
p->data[readRow][effectCol[chan]++]=0x0d;
|
||||
p->data[readRow][effectCol[chan]++]=effectVal[chan];
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0x0d;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=effectVal[chan];
|
||||
break;
|
||||
case 'D': // vol slide
|
||||
if (effectVal[chan]!=0) {
|
||||
|
|
@ -1490,8 +1482,8 @@ bool DivEngine::loadIT(unsigned char* file, size_t len) {
|
|||
case 'N': // channel vol slide
|
||||
break;
|
||||
case 'O': // offset
|
||||
p->data[readRow][effectCol[chan]++]=0x91;
|
||||
p->data[readRow][effectCol[chan]++]=effectVal[chan];
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0x91;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=effectVal[chan];
|
||||
break;
|
||||
case 'P': // pan slide
|
||||
if (effectVal[chan]!=0) {
|
||||
|
|
@ -1504,8 +1496,8 @@ bool DivEngine::loadIT(unsigned char* file, size_t len) {
|
|||
if (effectVal[chan]!=0) {
|
||||
lastRetrig[chan]=effectVal[chan];
|
||||
}
|
||||
p->data[readRow][effectCol[chan]++]=0x0c;
|
||||
p->data[readRow][effectCol[chan]++]=lastRetrig[chan]&15;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0x0c;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=lastRetrig[chan]&15;
|
||||
break;
|
||||
case 'R': // tremolo
|
||||
if (effectVal[chan]!=0) {
|
||||
|
|
@ -1519,77 +1511,77 @@ bool DivEngine::loadIT(unsigned char* file, size_t len) {
|
|||
case 0x3: // vibrato waveform
|
||||
switch (effectVal[chan]&3) {
|
||||
case 0x0: // sine
|
||||
p->data[readRow][effectCol[chan]++]=0xe3;
|
||||
p->data[readRow][effectCol[chan]++]=0x00;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0xe3;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0x00;
|
||||
break;
|
||||
case 0x1: // ramp down
|
||||
p->data[readRow][effectCol[chan]++]=0xe3;
|
||||
p->data[readRow][effectCol[chan]++]=0x05;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0xe3;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0x05;
|
||||
break;
|
||||
case 0x2: // square
|
||||
p->data[readRow][effectCol[chan]++]=0xe3;
|
||||
p->data[readRow][effectCol[chan]++]=0x06;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0xe3;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0x06;
|
||||
break;
|
||||
case 0x3: // random
|
||||
p->data[readRow][effectCol[chan]++]=0xe3;
|
||||
p->data[readRow][effectCol[chan]++]=0x07;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0xe3;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0x07;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0x7:
|
||||
switch (effectVal[chan]&15) {
|
||||
case 0x7: // volume envelope off
|
||||
p->data[readRow][effectCol[chan]++]=0xf5;
|
||||
p->data[readRow][effectCol[chan]++]=0x00;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0xf5;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0x00;
|
||||
break;
|
||||
case 0x8: // volume envelope on
|
||||
p->data[readRow][effectCol[chan]++]=0xf6;
|
||||
p->data[readRow][effectCol[chan]++]=0x00;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0xf6;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0x00;
|
||||
break;
|
||||
case 0x9: // panning envelope off
|
||||
p->data[readRow][effectCol[chan]++]=0xf5;
|
||||
p->data[readRow][effectCol[chan]++]=0x0c;
|
||||
p->data[readRow][effectCol[chan]++]=0xf5;
|
||||
p->data[readRow][effectCol[chan]++]=0x0d;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0xf5;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0x0c;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0xf5;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0x0d;
|
||||
break;
|
||||
case 0xa: // panning envelope on
|
||||
p->data[readRow][effectCol[chan]++]=0xf6;
|
||||
p->data[readRow][effectCol[chan]++]=0x0c;
|
||||
p->data[readRow][effectCol[chan]++]=0xf6;
|
||||
p->data[readRow][effectCol[chan]++]=0x0d;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0xf6;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0x0c;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0xf6;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0x0d;
|
||||
break;
|
||||
case 0xb: // pitch envelope off
|
||||
p->data[readRow][effectCol[chan]++]=0xf5;
|
||||
p->data[readRow][effectCol[chan]++]=0x04;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0xf5;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0x04;
|
||||
break;
|
||||
case 0xc: //pitch envelope on
|
||||
p->data[readRow][effectCol[chan]++]=0xf6;
|
||||
p->data[readRow][effectCol[chan]++]=0x04;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0xf6;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0x04;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0x8: // panning
|
||||
p->data[readRow][effectCol[chan]++]=0x80;
|
||||
p->data[readRow][effectCol[chan]++]=(effectVal[chan]&15)<<4;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0x80;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=(effectVal[chan]&15)<<4;
|
||||
break;
|
||||
case 0xa: // offset (high nibble)
|
||||
p->data[readRow][effectCol[chan]++]=0x92;
|
||||
p->data[readRow][effectCol[chan]++]=effectVal[chan]&15;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0x92;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=effectVal[chan]&15;
|
||||
break;
|
||||
case 0xc: // note cut
|
||||
p->data[readRow][effectCol[chan]++]=0xec;
|
||||
p->data[readRow][effectCol[chan]++]=effectVal[chan]&15;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0xec;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=effectVal[chan]&15;
|
||||
break;
|
||||
case 0xd: // note delay
|
||||
p->data[readRow][effectCol[chan]++]=0xed;
|
||||
p->data[readRow][effectCol[chan]++]=effectVal[chan]&15;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0xed;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=effectVal[chan]&15;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 'T': // tempo
|
||||
if (effectVal[chan]>=0x20) {
|
||||
p->data[readRow][effectCol[chan]++]=0xf0;
|
||||
p->data[readRow][effectCol[chan]++]=effectVal[chan];
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0xf0;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=effectVal[chan];
|
||||
}
|
||||
break;
|
||||
case 'U': // fine vibrato
|
||||
|
|
@ -1604,8 +1596,8 @@ bool DivEngine::loadIT(unsigned char* file, size_t len) {
|
|||
case 'W': // global volume slide (!)
|
||||
break;
|
||||
case 'X': // panning
|
||||
p->data[readRow][effectCol[chan]++]=0x80;
|
||||
p->data[readRow][effectCol[chan]++]=effectVal[chan];
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0x80;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=effectVal[chan];
|
||||
break;
|
||||
case 'Y': // panbrello
|
||||
if (effectVal[chan]!=0) {
|
||||
|
|
@ -1690,18 +1682,18 @@ bool DivEngine::loadIT(unsigned char* file, size_t len) {
|
|||
for (int j=0; j<maxChan; j++) {
|
||||
DivPattern* p=ds.subsong[i]->pat[j].getPattern(ds.subsong[i]->orders.ord[j][0],true);
|
||||
for (int k=0; k<DIV_MAX_EFFECTS; k++) {
|
||||
if (p->data[0][4+(k<<1)]==0x80) {
|
||||
if (p->newData[0][DIV_PAT_FX(k)]==0x80) {
|
||||
// give up if there's a panning effect already
|
||||
break;
|
||||
}
|
||||
if (p->data[0][4+(k<<1)]==-1) {
|
||||
if (p->newData[0][DIV_PAT_FX(k)]==-1) {
|
||||
if ((chanPan[j]&127)==100) {
|
||||
// should be surround...
|
||||
p->data[0][4+(k<<1)]=0x80;
|
||||
p->data[0][5+(k<<1)]=0x80;
|
||||
p->newData[0][DIV_PAT_FX(k)]=0x80;
|
||||
p->newData[0][DIV_PAT_FXVAL(k)]=0x80;
|
||||
} else {
|
||||
p->data[0][4+(k<<1)]=0x80;
|
||||
p->data[0][5+(k<<1)]=CLAMP((chanPan[j]&127)<<2,0,255);
|
||||
p->newData[0][DIV_PAT_FX(k)]=0x80;
|
||||
p->newData[0][DIV_PAT_FXVAL(k)]=CLAMP((chanPan[j]&127)<<2,0,255);
|
||||
}
|
||||
if (ds.subsong[i]->pat[j].effectCols<=k) ds.subsong[i]->pat[j].effectCols=k+1;
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -185,21 +185,20 @@ bool DivEngine::loadMod(unsigned char* file, size_t len) {
|
|||
}
|
||||
for (int row=0; row<64; row++) {
|
||||
for (int ch=0; ch<chCount; ch++) {
|
||||
short* dstrow=chpats[ch]->data[row];
|
||||
short* dstrowN=chpats[ch]->newData[row];
|
||||
unsigned char data[4];
|
||||
reader.read(&data,4);
|
||||
// instrument
|
||||
short ins=(data[0]&0xf0)|(data[2]>>4);
|
||||
if (ins>0) {
|
||||
dstrow[2]=ins-1;
|
||||
dstrow[3]=defaultVols[ins-1];
|
||||
dstrowN[DIV_PAT_INS]=ins-1;
|
||||
dstrowN[DIV_PAT_VOL]=defaultVols[ins-1];
|
||||
}
|
||||
// note
|
||||
int period=data[1]+((data[0]&0x0f)<<8);
|
||||
if (period>0 && period<0x0fff) {
|
||||
short note=(short)round(log2(3424.0/period)*12);
|
||||
dstrow[0]=((note+11)%12)+1;
|
||||
dstrow[1]=(note-1)/12+1;
|
||||
dstrowN[DIV_PAT_NOTE]=note+72;
|
||||
if (period<114) {
|
||||
bypassLimits=true;
|
||||
}
|
||||
|
|
@ -207,8 +206,8 @@ bool DivEngine::loadMod(unsigned char* file, size_t len) {
|
|||
// effects are done later
|
||||
short fxtyp=data[2]&0x0f;
|
||||
short fxval=data[3];
|
||||
dstrow[4]=fxtyp;
|
||||
dstrow[5]=fxval;
|
||||
dstrowN[DIV_PAT_FX(0)]=fxtyp;
|
||||
dstrowN[DIV_PAT_FXVAL(0)]=fxval;
|
||||
switch (fxtyp) {
|
||||
case 0:
|
||||
if (fxval!=0) fxUsage[ch][0]=true;
|
||||
|
|
@ -256,7 +255,7 @@ bool DivEngine::loadMod(unsigned char* file, size_t len) {
|
|||
for (int ch=0; ch<=chCount; ch++) {
|
||||
unsigned char fxCols=1;
|
||||
for (int pat=0; pat<=patMax; pat++) {
|
||||
auto* data=ds.subsong[0]->pat[ch].getPattern(pat,true)->data;
|
||||
auto* newData=ds.subsong[0]->pat[ch].getPattern(pat,true)->newData;
|
||||
short lastPitchEffect=-1;
|
||||
short lastEffectState[5]={-1,-1,-1,-1,-1};
|
||||
short setEffectState[5]={-1,-1,-1,-1,-1};
|
||||
|
|
@ -264,11 +263,11 @@ bool DivEngine::loadMod(unsigned char* file, size_t len) {
|
|||
const short fxUsageTyp[5]={0x00,0x01,0x04,0x07,0xFA};
|
||||
short effectState[5]={0,0,0,0,0};
|
||||
unsigned char curFxCol=0;
|
||||
short fxTyp=data[row][4];
|
||||
short fxVal=data[row][5];
|
||||
auto writeFxCol=[data,row,&curFxCol](short typ, short val) {
|
||||
data[row][4+curFxCol*2]=typ;
|
||||
data[row][5+curFxCol*2]=val;
|
||||
short fxTyp=newData[row][DIV_PAT_FX(0)];
|
||||
short fxVal=newData[row][DIV_PAT_FXVAL(0)];
|
||||
auto writeFxCol=[newData,row,&curFxCol](short typ, short val) {
|
||||
newData[row][DIV_PAT_FX(curFxCol)]=typ;
|
||||
newData[row][DIV_PAT_FXVAL(curFxCol)]=val;
|
||||
curFxCol++;
|
||||
};
|
||||
writeFxCol(-1,-1);
|
||||
|
|
@ -293,7 +292,7 @@ bool DivEngine::loadMod(unsigned char* file, size_t len) {
|
|||
effectState[1]=fxVal;
|
||||
if ((effectState[1]!=lastEffectState[1]) ||
|
||||
(fxTyp!=lastPitchEffect) ||
|
||||
(effectState[1]!=0 && data[row][0]>0)) {
|
||||
(effectState[1]!=0 && newData[row][DIV_PAT_NOTE]>-1)) {
|
||||
writeFxCol(fxTyp,fxVal);
|
||||
}
|
||||
lastPitchEffect=fxTyp;
|
||||
|
|
@ -331,7 +330,7 @@ bool DivEngine::loadMod(unsigned char* file, size_t len) {
|
|||
writeFxCol(fxTyp,fxVal);
|
||||
break;
|
||||
case 12: // set vol
|
||||
data[row][3]=MIN(0x40,fxVal);
|
||||
newData[row][DIV_PAT_VOL]=MIN(0x40,fxVal);
|
||||
break;
|
||||
case 13: // break to row (BCD)
|
||||
writeFxCol(fxTyp,((fxVal>>4)*10)+(fxVal&15));
|
||||
|
|
@ -387,7 +386,7 @@ bool DivEngine::loadMod(unsigned char* file, size_t len) {
|
|||
for (int i=0; i<5; i++) {
|
||||
// pitch slide and volume slide needs to be kept active on new note
|
||||
// even after target/max is reached
|
||||
if (fxUsage[ch][i] && (effectState[i]!=lastEffectState[i] || (effectState[i]!=0 && i==4 && data[row][3]>=0))) {
|
||||
if (fxUsage[ch][i] && (effectState[i]!=lastEffectState[i] || (effectState[i]!=0 && i==4 && newData[row][DIV_PAT_VOL]>=0))) {
|
||||
writeFxCol(fxUsageTyp[i],effectState[i]);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -771,7 +771,7 @@ bool DivEngine::loadS3M(unsigned char* file, size_t len) {
|
|||
|
||||
bool mustCommitInitial=true;
|
||||
|
||||
memset(effectCol,4,32);
|
||||
memset(effectCol,0,32);
|
||||
memset(vibStatus,0,32);
|
||||
memset(vibStatusChanged,0,32*sizeof(bool));
|
||||
memset(vibing,0,32*sizeof(bool));
|
||||
|
|
@ -811,95 +811,95 @@ bool DivEngine::loadS3M(unsigned char* file, size_t len) {
|
|||
for (int j=0; j<32; j++) {
|
||||
DivPattern* p=ds.subsong[0]->pat[chanMap[j]].getPattern(i,true);
|
||||
if (vibing[j]!=vibingOld[j] || vibStatusChanged[j]) {
|
||||
p->data[readRow][effectCol[j]++]=0x04;
|
||||
p->data[readRow][effectCol[j]++]=vibing[j]?vibStatus[j]:0;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=0x04;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=vibing[j]?vibStatus[j]:0;
|
||||
doesVibrato[j]=true;
|
||||
} else if (doesVibrato[j] && mustCommitInitial) {
|
||||
p->data[readRow][effectCol[j]++]=0x04;
|
||||
p->data[readRow][effectCol[j]++]=0;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=0x04;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=0;
|
||||
}
|
||||
|
||||
if (volSliding[j]!=volSlidingOld[j] || volSlideStatusChanged[j]) {
|
||||
if (volSlideStatus[j]>=0xf1 && volSliding[j]) {
|
||||
p->data[readRow][effectCol[j]++]=0xf9;
|
||||
p->data[readRow][effectCol[j]++]=volSlideStatus[j]&15;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=0xf9;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=volSlideStatus[j]&15;
|
||||
volSliding[j]=false;
|
||||
} else if ((volSlideStatus[j]&15)==15 && volSlideStatus[j]>=0x10 && volSliding[j]) {
|
||||
p->data[readRow][effectCol[j]++]=0xf8;
|
||||
p->data[readRow][effectCol[j]++]=volSlideStatus[j]>>4;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=0xf8;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=volSlideStatus[j]>>4;
|
||||
volSliding[j]=false;
|
||||
} else {
|
||||
p->data[readRow][effectCol[j]++]=0xfa;
|
||||
p->data[readRow][effectCol[j]++]=volSliding[j]?volSlideStatus[j]:0;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=0xfa;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=volSliding[j]?volSlideStatus[j]:0;
|
||||
}
|
||||
doesVolSlide[j]=true;
|
||||
} else if (doesVolSlide[j] && mustCommitInitial) {
|
||||
p->data[readRow][effectCol[j]++]=0xfa;
|
||||
p->data[readRow][effectCol[j]++]=0;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=0xfa;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=0;
|
||||
}
|
||||
|
||||
if (porting[j]!=portingOld[j] || portaStatusChanged[j]) {
|
||||
if (portaStatus[j]>=0xe0 && portaType[j]!=3 && porting[j]) {
|
||||
p->data[readRow][effectCol[j]++]=portaType[j]|0xf0;
|
||||
p->data[readRow][effectCol[j]++]=(portaStatus[j]&15)*((portaStatus[j]>=0xf0)?1:1);
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=portaType[j]|0xf0;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=(portaStatus[j]&15)*((portaStatus[j]>=0xf0)?1:1);
|
||||
porting[j]=false;
|
||||
} else {
|
||||
p->data[readRow][effectCol[j]++]=portaType[j];
|
||||
p->data[readRow][effectCol[j]++]=porting[j]?portaStatus[j]:0;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=portaType[j];
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=porting[j]?portaStatus[j]:0;
|
||||
}
|
||||
doesPitchSlide[j]=true;
|
||||
} else if (doesPitchSlide[j] && mustCommitInitial) {
|
||||
p->data[readRow][effectCol[j]++]=0x01;
|
||||
p->data[readRow][effectCol[j]++]=0;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=0x01;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=0;
|
||||
}
|
||||
|
||||
if (arping[j]!=arpingOld[j] || arpStatusChanged[j]) {
|
||||
p->data[readRow][effectCol[j]++]=0x00;
|
||||
p->data[readRow][effectCol[j]++]=arping[j]?arpStatus[j]:0;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=0x00;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=arping[j]?arpStatus[j]:0;
|
||||
doesArp[j]=true;
|
||||
} else if (doesArp[j] && mustCommitInitial) {
|
||||
p->data[readRow][effectCol[j]++]=0x00;
|
||||
p->data[readRow][effectCol[j]++]=0;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=0x00;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=0;
|
||||
}
|
||||
|
||||
if (treming[j]!=tremingOld[j] || tremStatusChanged[j]) {
|
||||
p->data[readRow][effectCol[j]++]=0x07;
|
||||
p->data[readRow][effectCol[j]++]=treming[j]?tremStatus[j]:0;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=0x07;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=treming[j]?tremStatus[j]:0;
|
||||
doesTremolo[j]=true;
|
||||
} else if (doesTremolo[j] && mustCommitInitial) {
|
||||
p->data[readRow][effectCol[j]++]=0x07;
|
||||
p->data[readRow][effectCol[j]++]=0;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=0x07;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=0;
|
||||
}
|
||||
|
||||
if (panning[j]!=panningOld[j] || panStatusChanged[j]) {
|
||||
p->data[readRow][effectCol[j]++]=0x84;
|
||||
p->data[readRow][effectCol[j]++]=panning[j]?panStatus[j]:0;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=0x84;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=panning[j]?panStatus[j]:0;
|
||||
doesPanbrello[j]=true;
|
||||
} else if (doesPanbrello[j] && mustCommitInitial) {
|
||||
p->data[readRow][effectCol[j]++]=0x84;
|
||||
p->data[readRow][effectCol[j]++]=0;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=0x84;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=0;
|
||||
}
|
||||
|
||||
if (panSliding[j]!=panSlidingOld[j] || panSlideStatusChanged[j]) {
|
||||
p->data[readRow][effectCol[j]++]=0x83;
|
||||
p->data[readRow][effectCol[j]++]=panSliding[j]?panSlideStatus[j]:0;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=0x83;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=panSliding[j]?panSlideStatus[j]:0;
|
||||
doesPanSlide[j]=true;
|
||||
} else if (doesPanSlide[j] && mustCommitInitial) {
|
||||
p->data[readRow][effectCol[j]++]=0x83;
|
||||
p->data[readRow][effectCol[j]++]=0;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=0x83;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=0;
|
||||
}
|
||||
|
||||
if (effectCol[j]>=4+8*2) {
|
||||
if (effectCol[j]>=8*2) {
|
||||
logE("oh crap!");
|
||||
}
|
||||
|
||||
if ((effectCol[j]>>1)-2>ds.subsong[0]->pat[j].effectCols) {
|
||||
ds.subsong[0]->pat[chanMap[j]].effectCols=(effectCol[j]>>1)-1;
|
||||
if ((effectCol[j]>>1)>=ds.subsong[0]->pat[j].effectCols) {
|
||||
ds.subsong[0]->pat[chanMap[j]].effectCols=(effectCol[j]>>1)+1;
|
||||
}
|
||||
}
|
||||
|
||||
readRow++;
|
||||
memset(effectCol,4,32);
|
||||
memset(effectCol,0,32);
|
||||
memcpy(vibingOld,vibing,32*sizeof(bool));
|
||||
memcpy(volSlidingOld,volSliding,32*sizeof(bool));
|
||||
memcpy(portingOld,porting,32*sizeof(bool));
|
||||
|
|
@ -935,22 +935,16 @@ bool DivEngine::loadS3M(unsigned char* file, size_t len) {
|
|||
unsigned char ins=reader.readC();
|
||||
|
||||
if (note==254) { // note off
|
||||
p->data[readRow][0]=100;
|
||||
p->data[readRow][1]=0;
|
||||
p->newData[readRow][DIV_PAT_NOTE]=DIV_NOTE_OFF;
|
||||
} else if (note!=255) {
|
||||
p->data[readRow][0]=note&15;
|
||||
p->data[readRow][1]=note>>4;
|
||||
if ((note&15)==0) {
|
||||
p->data[readRow][0]=12;
|
||||
p->data[readRow][1]--;
|
||||
}
|
||||
p->newData[readRow][DIV_PAT_NOTE]=(note&15)+(note>>4)*12+60;
|
||||
}
|
||||
p->data[readRow][2]=(short)ins-1;
|
||||
p->newData[readRow][DIV_PAT_INS]=(short)ins-1;
|
||||
}
|
||||
if (hasVol) {
|
||||
unsigned char vol=reader.readC();
|
||||
if (vol==255) {
|
||||
p->data[readRow][3]=-1;
|
||||
p->newData[readRow][DIV_PAT_VOL]=-1;
|
||||
} else {
|
||||
// check for OPL channel
|
||||
if ((chanSettings[chan]&31)>=16) {
|
||||
|
|
@ -958,17 +952,17 @@ bool DivEngine::loadS3M(unsigned char* file, size_t len) {
|
|||
} else {
|
||||
if (vol>64) vol=64;
|
||||
}
|
||||
p->data[readRow][3]=vol;
|
||||
p->newData[readRow][DIV_PAT_VOL]=vol;
|
||||
}
|
||||
} else if (p->data[readRow][2]!=-1) {
|
||||
} else if (p->newData[readRow][DIV_PAT_INS]!=-1) {
|
||||
// populate with instrument volume
|
||||
unsigned char vol=defVol[p->data[readRow][2]&255];
|
||||
unsigned char vol=defVol[p->newData[readRow][DIV_PAT_INS]&255];
|
||||
if ((chanSettings[chan]&31)>=16) {
|
||||
if (vol>63) vol=63;
|
||||
} else {
|
||||
if (vol>64) vol=64;
|
||||
}
|
||||
p->data[readRow][3]=vol;
|
||||
p->newData[readRow][DIV_PAT_VOL]=vol;
|
||||
}
|
||||
if (hasEffect) {
|
||||
unsigned char effect=reader.readC();
|
||||
|
|
@ -976,17 +970,17 @@ bool DivEngine::loadS3M(unsigned char* file, size_t len) {
|
|||
|
||||
switch (effect+'A'-1) {
|
||||
case 'A': // speed
|
||||
p->data[readRow][effectCol[chan]++]=0x0f;
|
||||
p->data[readRow][effectCol[chan]++]=effectVal;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0x0f;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=effectVal;
|
||||
break;
|
||||
case 'B': // go to order
|
||||
p->data[readRow][effectCol[chan]++]=0x0b;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0x0b;
|
||||
logD("0B: %x %x",effectVal,orders[effectVal]);
|
||||
p->data[readRow][effectCol[chan]++]=orders[effectVal];
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=orders[effectVal];
|
||||
break;
|
||||
case 'C': // next order
|
||||
p->data[readRow][effectCol[chan]++]=0x0d;
|
||||
p->data[readRow][effectCol[chan]++]=(effectVal>>4)*10+(effectVal&15);
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0x0d;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=(effectVal>>4)*10+(effectVal&15);
|
||||
break;
|
||||
case 'D': // vol slide
|
||||
if (effectVal!=0) {
|
||||
|
|
@ -1078,8 +1072,8 @@ bool DivEngine::loadS3M(unsigned char* file, size_t len) {
|
|||
case 'N': // channel vol slide (extension)
|
||||
break;
|
||||
case 'O': // offset
|
||||
p->data[readRow][effectCol[chan]++]=0x91;
|
||||
p->data[readRow][effectCol[chan]++]=effectVal;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0x91;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=effectVal;
|
||||
break;
|
||||
case 'P': // pan slide (extension)
|
||||
if (effectVal!=0) {
|
||||
|
|
@ -1089,8 +1083,8 @@ bool DivEngine::loadS3M(unsigned char* file, size_t len) {
|
|||
panSliding[chan]=true;
|
||||
break;
|
||||
case 'Q': // retrigger
|
||||
p->data[readRow][effectCol[chan]++]=0x0c;
|
||||
p->data[readRow][effectCol[chan]++]=effectVal&15;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0x0c;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=effectVal&15;
|
||||
break;
|
||||
case 'R': // tremolo
|
||||
if (effectVal!=0) {
|
||||
|
|
@ -1104,40 +1098,40 @@ bool DivEngine::loadS3M(unsigned char* file, size_t len) {
|
|||
case 0x3: // vibrato waveform
|
||||
switch (effectVal&3) {
|
||||
case 0x0: // sine
|
||||
p->data[readRow][effectCol[chan]++]=0xe3;
|
||||
p->data[readRow][effectCol[chan]++]=0x00;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0xe3;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0x00;
|
||||
break;
|
||||
case 0x1: // ramp down
|
||||
p->data[readRow][effectCol[chan]++]=0xe3;
|
||||
p->data[readRow][effectCol[chan]++]=0x05;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0xe3;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0x05;
|
||||
break;
|
||||
case 0x2: // square
|
||||
p->data[readRow][effectCol[chan]++]=0xe3;
|
||||
p->data[readRow][effectCol[chan]++]=0x06;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0xe3;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0x06;
|
||||
break;
|
||||
case 0x3: // random
|
||||
p->data[readRow][effectCol[chan]++]=0xe3;
|
||||
p->data[readRow][effectCol[chan]++]=0x07;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0xe3;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0x07;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0x8: // panning
|
||||
p->data[readRow][effectCol[chan]++]=0x80;
|
||||
p->data[readRow][effectCol[chan]++]=(effectVal&15)<<4;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0x80;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=(effectVal&15)<<4;
|
||||
break;
|
||||
case 0xc: // note cut
|
||||
p->data[readRow][effectCol[chan]++]=0xec;
|
||||
p->data[readRow][effectCol[chan]++]=effectVal&15;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0xec;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=effectVal&15;
|
||||
break;
|
||||
case 0xd: // note delay
|
||||
p->data[readRow][effectCol[chan]++]=0xed;
|
||||
p->data[readRow][effectCol[chan]++]=effectVal&15;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0xed;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=effectVal&15;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 'T': // tempo
|
||||
p->data[readRow][effectCol[chan]++]=0xf0;
|
||||
p->data[readRow][effectCol[chan]++]=effectVal;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0xf0;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=effectVal;
|
||||
break;
|
||||
case 'U': // fine vibrato
|
||||
if (effectVal!=0) {
|
||||
|
|
@ -1152,8 +1146,8 @@ bool DivEngine::loadS3M(unsigned char* file, size_t len) {
|
|||
break;
|
||||
case 'X': // panning (extension)
|
||||
if (effectVal<=0x80) {
|
||||
p->data[readRow][effectCol[chan]++]=0x80;
|
||||
p->data[readRow][effectCol[chan]++]=(effectVal&0x80)?0xff:(effectVal<<1);
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0x80;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=(effectVal&0x80)?0xff:(effectVal<<1);
|
||||
}
|
||||
break;
|
||||
case 'Y': // panbrello (extension)
|
||||
|
|
@ -1193,16 +1187,16 @@ bool DivEngine::loadS3M(unsigned char* file, size_t len) {
|
|||
for (int j=0; j<16; j++) {
|
||||
DivPattern* p=ds.subsong[i]->pat[chanMap[j]].getPattern(ds.subsong[i]->orders.ord[j][0],true);
|
||||
for (int k=0; k<DIV_MAX_EFFECTS; k++) {
|
||||
if (p->data[0][4+(k<<1)]==0x80) {
|
||||
if (p->newData[0][DIV_PAT_FX(k)]==0x80) {
|
||||
// give up if there's a panning effect already
|
||||
break;
|
||||
}
|
||||
if (p->data[0][4+(k<<1)]==-1) {
|
||||
p->data[0][4+(k<<1)]=0x80;
|
||||
if (p->newData[0][DIV_PAT_FX(k)]==-1) {
|
||||
p->newData[0][DIV_PAT_FX(k)]=0x80;
|
||||
if (chanPan[j]&16) {
|
||||
p->data[0][5+(k<<1)]=(j&1)?0xcc:0x33;
|
||||
p->newData[0][DIV_PAT_FXVAL(k)]=(j&1)?0xcc:0x33;
|
||||
} else {
|
||||
p->data[0][5+(k<<1)]=(chanPan[j]&15)|((chanPan[j]&15)<<4);
|
||||
p->newData[0][DIV_PAT_FXVAL(k)]=(chanPan[j]&15)|((chanPan[j]&15)<<4);
|
||||
}
|
||||
if (ds.subsong[i]->pat[chanMap[j]].effectCols<=k) ds.subsong[i]->pat[chanMap[j]].effectCols=k+1;
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -321,9 +321,8 @@ SafeWriter* DivEngine::saveText(bool separatePatterns) {
|
|||
|
||||
for (int l=0; l<chans; l++) {
|
||||
DivPattern* p=s->pat[l].getPattern(s->orders.ord[l][j],false);
|
||||
|
||||
int note=p->data[k][0];
|
||||
int octave=p->data[k][1];
|
||||
short note, octave;
|
||||
noteToSplitNote(p->newData[k][DIV_PAT_NOTE],note,octave);
|
||||
|
||||
if (note==0 && octave==0) {
|
||||
w->writeText("|... ");
|
||||
|
|
@ -344,28 +343,28 @@ SafeWriter* DivEngine::saveText(bool separatePatterns) {
|
|||
w->writeText(fmt::sprintf("|%s%d ",(octave<0)?notesNegative[note]:notes[note],(octave<0)?(-octave):octave));
|
||||
}
|
||||
|
||||
if (p->data[k][2]==-1) {
|
||||
if (p->newData[k][DIV_PAT_INS]==-1) {
|
||||
w->writeText(".. ");
|
||||
} else {
|
||||
w->writeText(fmt::sprintf("%.2X ",p->data[k][2]&0xff));
|
||||
w->writeText(fmt::sprintf("%.2X ",p->newData[k][DIV_PAT_INS]&0xff));
|
||||
}
|
||||
|
||||
if (p->data[k][3]==-1) {
|
||||
if (p->newData[k][DIV_PAT_VOL]==-1) {
|
||||
w->writeText("..");
|
||||
} else {
|
||||
w->writeText(fmt::sprintf("%.2X",p->data[k][3]&0xff));
|
||||
w->writeText(fmt::sprintf("%.2X",p->newData[k][DIV_PAT_VOL]&0xff));
|
||||
}
|
||||
|
||||
for (int m=0; m<s->pat[l].effectCols; m++) {
|
||||
if (p->data[k][4+(m<<1)]==-1) {
|
||||
if (p->newData[k][DIV_PAT_FX(m)]==-1) {
|
||||
w->writeText(" ..");
|
||||
} else {
|
||||
w->writeText(fmt::sprintf(" %.2X",p->data[k][4+(m<<1)]&0xff));
|
||||
w->writeText(fmt::sprintf(" %.2X",p->newData[k][DIV_PAT_FX(m)]&0xff));
|
||||
}
|
||||
if (p->data[k][5+(m<<1)]==-1) {
|
||||
if (p->newData[k][DIV_PAT_FXVAL(m)]==-1) {
|
||||
w->writeText("..");
|
||||
} else {
|
||||
w->writeText(fmt::sprintf("%.2X",p->data[k][5+(m<<1)]&0xff));
|
||||
w->writeText(fmt::sprintf("%.2X",p->newData[k][DIV_PAT_FXVAL(m)]&0xff));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -254,16 +254,10 @@ void TFMParsePattern(struct TFMParsePatternInfo info) {
|
|||
if (patDataBuf[k]==0) continue;
|
||||
else if (patDataBuf[k]==1) {
|
||||
// note off
|
||||
pat->data[k][0]=100;
|
||||
pat->newData[k][DIV_PAT_NOTE]=DIV_NOTE_OFF;
|
||||
} else {
|
||||
unsigned char invertedNote=~patDataBuf[k];
|
||||
pat->data[k][0]=invertedNote%12;
|
||||
pat->data[k][1]=(invertedNote/12)-1;
|
||||
|
||||
if (pat->data[k][0]==0) {
|
||||
pat->data[k][0]=12;
|
||||
pat->data[k][1]--;
|
||||
}
|
||||
pat->newData[k][DIV_PAT_NOTE]=invertedNote+60;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -273,7 +267,7 @@ void TFMParsePattern(struct TFMParsePatternInfo info) {
|
|||
logD("parsing volumes of pattern %d channel %d",i,j);
|
||||
for (int k=0; k<256; k++) {
|
||||
if (patDataBuf[k]==0) continue;
|
||||
else pat->data[k][3]=0x60+patDataBuf[k];
|
||||
else pat->newData[k][DIV_PAT_VOL]=0x60+patDataBuf[k];
|
||||
}
|
||||
|
||||
// instrument
|
||||
|
|
@ -282,7 +276,7 @@ void TFMParsePattern(struct TFMParsePatternInfo info) {
|
|||
logD("parsing instruments of pattern %d channel %d",i,j);
|
||||
for (int k=0; k<256; k++) {
|
||||
if (patDataBuf[k]==0) continue;
|
||||
pat->data[k][2]=info.insNumMaps[patDataBuf[k]-1];
|
||||
pat->newData[k][DIV_PAT_INS]=info.insNumMaps[patDataBuf[k]-1];
|
||||
}
|
||||
|
||||
// effects
|
||||
|
|
@ -300,76 +294,76 @@ void TFMParsePattern(struct TFMParsePatternInfo info) {
|
|||
case 0:
|
||||
// arpeggio or no effect (if effect val is 0)
|
||||
if (effectVal[k]==0) break;
|
||||
pat->data[k][4+(l*2)]=effectNum[k];
|
||||
pat->data[k][5+(l*2)]=effectVal[k];
|
||||
pat->newData[k][DIV_PAT_FX(l)]=effectNum[k];
|
||||
pat->newData[k][DIV_PAT_FXVAL(l)]=effectVal[k];
|
||||
break;
|
||||
case 1:
|
||||
// pitch slide up
|
||||
case 2:
|
||||
// pitch slide down
|
||||
pat->data[k][4+(l*2)]=effectNum[k];
|
||||
pat->newData[k][DIV_PAT_FX(l)]=effectNum[k];
|
||||
if (effectVal[k]) {
|
||||
lastSlide=effectVal[k];
|
||||
pat->data[k][5+(l*2)]=effectVal[k];
|
||||
pat->newData[k][DIV_PAT_FXVAL(l)]=effectVal[k];
|
||||
} else {
|
||||
pat->data[k][5+(l*2)]=lastSlide;
|
||||
pat->newData[k][DIV_PAT_FXVAL(l)]=lastSlide;
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
// portamento
|
||||
case 4:
|
||||
// vibrato
|
||||
pat->data[k][5+(l*2)]=0;
|
||||
pat->newData[k][DIV_PAT_FXVAL(l)]=0;
|
||||
if (effectVal[k]&0xF0) {
|
||||
pat->data[k][5+(l*2)]|=effectVal[k]&0xF0;
|
||||
pat->newData[k][DIV_PAT_FXVAL(l)]|=effectVal[k]&0xF0;
|
||||
} else {
|
||||
pat->data[k][5+(l*2)]|=lastVibrato&0xF0;
|
||||
pat->newData[k][DIV_PAT_FXVAL(l)]|=lastVibrato&0xF0;
|
||||
}
|
||||
if (effectVal[k]&0x0F) {
|
||||
pat->data[k][5+(l*2)]|=effectVal[k]&0x0F;
|
||||
pat->newData[k][DIV_PAT_FXVAL(l)]|=effectVal[k]&0x0F;
|
||||
} else {
|
||||
pat->data[k][5+(l*2)]|=lastVibrato&0x0F;
|
||||
pat->newData[k][DIV_PAT_FXVAL(l)]|=lastVibrato&0x0F;
|
||||
}
|
||||
pat->data[k][4+(l*2)]=effectNum[k];
|
||||
lastVibrato=pat->data[k][5+(l*2)];
|
||||
pat->newData[k][DIV_PAT_FX(l)]=effectNum[k];
|
||||
lastVibrato=pat->newData[k][DIV_PAT_FXVAL(l)];
|
||||
break;
|
||||
case 5:
|
||||
// poramento + volume slide
|
||||
pat->data[k][4+(l*2)]=0x06;
|
||||
pat->data[k][5+(l*2)]=effectVal[k];
|
||||
pat->newData[k][DIV_PAT_FX(l)]=0x06;
|
||||
pat->newData[k][DIV_PAT_FXVAL(l)]=effectVal[k];
|
||||
break;
|
||||
case 6:
|
||||
// vibrato + volume slide
|
||||
pat->data[k][4+(l*2)]=0x05;
|
||||
pat->data[k][5+(l*2)]=effectVal[k];
|
||||
pat->newData[k][DIV_PAT_FX(l)]=0x05;
|
||||
pat->newData[k][DIV_PAT_FXVAL(l)]=effectVal[k];
|
||||
break;
|
||||
case 8:
|
||||
// modify TL of operator 1
|
||||
pat->data[k][4+(l*2)]=0x12;
|
||||
pat->data[k][5+(l*2)]=effectVal[k];
|
||||
pat->newData[k][DIV_PAT_FX(l)]=0x12;
|
||||
pat->newData[k][DIV_PAT_FXVAL(l)]=effectVal[k];
|
||||
break;
|
||||
case 9:
|
||||
// modify TL of operator 2
|
||||
pat->data[k][4+(l*2)]=0x13;
|
||||
pat->data[k][5+(l*2)]=effectVal[k];
|
||||
pat->newData[k][DIV_PAT_FX(l)]=0x13;
|
||||
pat->newData[k][DIV_PAT_FXVAL(l)]=effectVal[k];
|
||||
break;
|
||||
case 10:
|
||||
// volume slide
|
||||
pat->data[k][4+(l*2)]=0xA;
|
||||
pat->data[k][5+(l*2)]=effectVal[k];
|
||||
pat->newData[k][DIV_PAT_FX(l)]=0xA;
|
||||
pat->newData[k][DIV_PAT_FXVAL(l)]=effectVal[k];
|
||||
break;
|
||||
case 11:
|
||||
// multi-frequency mode of CH3 control
|
||||
// TODO
|
||||
case 12:
|
||||
// modify TL of operator 3
|
||||
pat->data[k][4+(l*2)]=0x14;
|
||||
pat->data[k][5+(l*2)]=effectVal[k];
|
||||
pat->newData[k][DIV_PAT_FX(l)]=0x14;
|
||||
pat->newData[k][DIV_PAT_FXVAL(l)]=effectVal[k];
|
||||
break;
|
||||
case 13:
|
||||
// modify TL of operator 4
|
||||
pat->data[k][4+(l*2)]=0x15;
|
||||
pat->data[k][5+(l*2)]=effectVal[k];
|
||||
pat->newData[k][DIV_PAT_FX(l)]=0x15;
|
||||
pat->newData[k][DIV_PAT_FXVAL(l)]=effectVal[k];
|
||||
break;
|
||||
case 14:
|
||||
switch (effectVal[k]>>4) {
|
||||
|
|
@ -378,18 +372,18 @@ void TFMParsePattern(struct TFMParsePatternInfo info) {
|
|||
case 2:
|
||||
case 3:
|
||||
// modify multiplier of operators
|
||||
pat->data[k][4+(l*2)]=0x16;
|
||||
pat->data[k][5+(l*2)]=((effectVal[k]&0xF0)+0x100)|(effectVal[k]&0xF);
|
||||
pat->newData[k][DIV_PAT_FX(l)]=0x16;
|
||||
pat->newData[k][DIV_PAT_FXVAL(l)]=((effectVal[k]&0xF0)+0x100)|(effectVal[k]&0xF);
|
||||
break;
|
||||
case 8:
|
||||
// pan
|
||||
pat->data[k][4+(l*2)]=0x80;
|
||||
pat->newData[k][DIV_PAT_FX(l)]=0x80;
|
||||
if ((effectVal[k]&0xF)==1) {
|
||||
pat->data[k][5+(l*2)]=0;
|
||||
pat->newData[k][DIV_PAT_FXVAL(l)]=0;
|
||||
} else if ((effectVal[k]&0xF)==2) {
|
||||
pat->data[k][5+(l*2)]=0xFF;
|
||||
pat->newData[k][DIV_PAT_FXVAL(l)]=0xFF;
|
||||
} else {
|
||||
pat->data[k][5+(l*2)]=0x80;
|
||||
pat->newData[k][DIV_PAT_FXVAL(l)]=0x80;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
@ -407,9 +401,9 @@ void TFMParsePattern(struct TFMParsePatternInfo info) {
|
|||
speed.interleaveFactor=effectVal[k]&0xF;
|
||||
} else if ((effectVal[k]>>4)==(effectVal[k]&0xF)) {
|
||||
// if both speeds are equal
|
||||
pat->data[k][4+(l*2)]=0x0F;
|
||||
pat->newData[k][DIV_PAT_FX(l)]=0x0F;
|
||||
unsigned char speedSet=effectVal[k]>>4;
|
||||
pat->data[k][5+(l*2)]=speedSet;
|
||||
pat->newData[k][DIV_PAT_FXVAL(l)]=speedSet;
|
||||
break;
|
||||
} else {
|
||||
speed.speedEven=effectVal[k]>>4;
|
||||
|
|
@ -418,8 +412,8 @@ void TFMParsePattern(struct TFMParsePatternInfo info) {
|
|||
|
||||
auto speedIndex = speeds.find(speed);
|
||||
if (speedIndex != speeds.end()) {
|
||||
pat->data[k][4+(l*2)]=0x09;
|
||||
pat->data[k][5+(l*2)]=speedIndex->second;
|
||||
pat->newData[k][DIV_PAT_FX(l)]=0x09;
|
||||
pat->newData[k][DIV_PAT_FXVAL(l)]=speedIndex->second;
|
||||
break;
|
||||
}
|
||||
if (speed.interleaveFactor>8) {
|
||||
|
|
@ -437,8 +431,8 @@ void TFMParsePattern(struct TFMParsePatternInfo info) {
|
|||
info.ds->grooves.push_back(groove);
|
||||
speeds[speed]=speedGrooveIndex;
|
||||
|
||||
pat->data[k][4+(l*2)]=0x09;
|
||||
pat->data[k][5+(l*2)]=speedGrooveIndex;
|
||||
pat->newData[k][DIV_PAT_FX(l)]=0x09;
|
||||
pat->newData[k][DIV_PAT_FXVAL(l)]=speedGrooveIndex;
|
||||
speedGrooveIndex++;
|
||||
break;
|
||||
}
|
||||
|
|
@ -447,8 +441,8 @@ void TFMParsePattern(struct TFMParsePatternInfo info) {
|
|||
|
||||
// put a "jump to next pattern" effect if the pattern is smaller than the maximum pattern length
|
||||
if (info.patLens[i]!=0 && info.patLens[i]<info.ds->subsong[0]->patLen) {
|
||||
pat->data[info.patLens[i]-1][4+(usedEffectsCol*4)]=0x0D;
|
||||
pat->data[info.patLens[i]-1][5+(usedEffectsCol*4)]=0x00;
|
||||
pat->newData[info.patLens[i]-1][DIV_PAT_FX(0)+(usedEffectsCol*4)]=0x0D;
|
||||
pat->newData[info.patLens[i]-1][DIV_PAT_FXVAL(0)+(usedEffectsCol*4)]=0x00;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -473,28 +467,30 @@ void TFMParsePattern(struct TFMParsePatternInfo info) {
|
|||
unsigned char truePatLen=(info.patLens[info.orderList[i]]<info.ds->subsong[0]->patLen) ? info.patLens[info.orderList[i]] : info.ds->subsong[0]->patLen;
|
||||
|
||||
// default instrument
|
||||
if (i==0 && pat->data[0][2]==-1) pat->data[0][2]=0;
|
||||
if (i==0 && pat->newData[0][DIV_PAT_INS]==-1) pat->newData[0][DIV_PAT_INS]=0;
|
||||
|
||||
for (int k=0; k<truePatLen; k++) {
|
||||
if (chArpeggio[j] && pat->data[k][4+(l*2)]!=0x00 && pat->data[k][0]!=-1) {
|
||||
pat->data[k][4+usedEffectsCol*2+(l*2)]=0x00;
|
||||
pat->data[k][5+usedEffectsCol*2+(l*2)]=0;
|
||||
// TODO: -1 check? does it still work after refactor?
|
||||
if (chArpeggio[j] && pat->newData[k][DIV_PAT_FX(l)]!=0x00 && pat->newData[k][DIV_PAT_NOTE]!=-1) {
|
||||
pat->newData[k][DIV_PAT_FX(usedEffectsCol)+(l*2)]=0x00;
|
||||
pat->newData[k][DIV_PAT_FXVAL(usedEffectsCol)+(l*2)]=0;
|
||||
chArpeggio[j]=false;
|
||||
} else if (chPorta[j] && pat->data[k][4+(l*2)]!=0x03 && pat->data[k][4+(l*2)]!=0x01 && pat->data[k][4+(l*2)]!=0x02) {
|
||||
pat->data[k][4+usedEffectsCol*2+(l*2)]=0x03;
|
||||
pat->data[k][5+usedEffectsCol*2+(l*2)]=0;
|
||||
} else if (chPorta[j] && pat->newData[k][DIV_PAT_FX(l)]!=0x03 && pat->newData[k][DIV_PAT_FX(l)]!=0x01 && pat->newData[k][DIV_PAT_FX(l)]!=0x02) {
|
||||
pat->newData[k][DIV_PAT_FX(usedEffectsCol)+(l*2)]=0x03;
|
||||
pat->newData[k][DIV_PAT_FXVAL(usedEffectsCol)+(l*2)]=0;
|
||||
chPorta[j]=false;
|
||||
} else if (chVibrato[j] && pat->data[k][4+(l*2)]!=0x04 && pat->data[k][0]!=-1) {
|
||||
pat->data[k][4+usedEffectsCol*2+(l*2)]=0x04;
|
||||
pat->data[k][5+usedEffectsCol*2+(l*2)]=0;
|
||||
} else if (chVibrato[j] && pat->newData[k][DIV_PAT_FX(l)]!=0x04 && pat->newData[k][DIV_PAT_NOTE]!=-1) {
|
||||
pat->newData[k][DIV_PAT_FX(usedEffectsCol)+(l*2)]=0x04;
|
||||
pat->newData[k][DIV_PAT_FXVAL(usedEffectsCol)+(l*2)]=0;
|
||||
chVibrato[j]=false;
|
||||
} else if (chVolumeSlide[j] && pat->data[k][4+(l*2)]!=0x0A) {
|
||||
pat->data[k][4+usedEffectsCol*2+(l*2)]=0x0A;
|
||||
pat->data[k][5+usedEffectsCol*2+(l*2)]=0;
|
||||
} else if (chVolumeSlide[j] && pat->newData[k][DIV_PAT_FX(l)]!=0x0A) {
|
||||
pat->newData[k][DIV_PAT_FX(usedEffectsCol)+(l*2)]=0x0A;
|
||||
pat->newData[k][DIV_PAT_FXVAL(usedEffectsCol)+(l*2)]=0;
|
||||
chVolumeSlide[j]=false;
|
||||
}
|
||||
|
||||
switch (pat->data[k][4+l]) {
|
||||
// TODO: looks like we have a bug here! it should be DIV_PAT_FX(l), right?
|
||||
switch (pat->newData[k][DIV_PAT_FX(0)+l]) {
|
||||
case 0:
|
||||
chArpeggio[j]=true;
|
||||
break;
|
||||
|
|
@ -527,16 +523,16 @@ void TFMParsePattern(struct TFMParsePatternInfo info) {
|
|||
lastPat->copyOn(newPat);
|
||||
|
||||
info.ds->subsong[0]->orders.ord[i][info.ds->subsong[0]->ordersLen - 1] = info.maxPat;
|
||||
newPat->data[info.patLens[lastPatNum]-1][4+(usedEffectsCol*4)] = 0x0B;
|
||||
newPat->data[info.patLens[lastPatNum]-1][5+(usedEffectsCol*4)] = info.loopPos;
|
||||
newPat->newData[info.patLens[lastPatNum]-1][DIV_PAT_FX(usedEffectsCol*2)] = 0x0B;
|
||||
newPat->newData[info.patLens[lastPatNum]-1][DIV_PAT_FXVAL(usedEffectsCol*2)] = info.loopPos;
|
||||
info.ds->subsong[0]->pat[i].data[info.maxPat] = newPat;
|
||||
}
|
||||
} else {
|
||||
for (int i=0;i<6;i++) {
|
||||
int lastPatNum=info.ds->subsong[0]->orders.ord[i][info.ds->subsong[0]->ordersLen - 1];
|
||||
DivPattern* lastPat=info.ds->subsong[0]->pat[i].getPattern(lastPatNum, false);
|
||||
lastPat->data[info.patLens[lastPatNum]-1][4+(usedEffectsCol*4)] = 0x0B;
|
||||
lastPat->data[info.patLens[lastPatNum]-1][5+(usedEffectsCol*4)] = info.loopPos;
|
||||
lastPat->newData[info.patLens[lastPatNum]-1][DIV_PAT_FX(usedEffectsCol*2)] = 0x0B;
|
||||
lastPat->newData[info.patLens[lastPatNum]-1][DIV_PAT_FXVAL(usedEffectsCol*2)] = info.loopPos;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -786,7 +786,7 @@ bool DivEngine::loadXM(unsigned char* file, size_t len) {
|
|||
|
||||
bool mustCommitInitial=true;
|
||||
|
||||
memset(effectCol,4,128);
|
||||
memset(effectCol,0,128);
|
||||
memset(vibStatus,0,128);
|
||||
memset(vibStatusChanged,0,128*sizeof(bool));
|
||||
memset(vibing,0,128*sizeof(bool));
|
||||
|
|
@ -901,32 +901,26 @@ bool DivEngine::loadXM(unsigned char* file, size_t len) {
|
|||
if (note!=0) {
|
||||
lastNote[k]=note;
|
||||
if (note>96) {
|
||||
p->data[j][0]=101;
|
||||
p->data[j][1]=0;
|
||||
p->newData[j][DIV_PAT_NOTE]=DIV_NOTE_REL;
|
||||
} else {
|
||||
note--;
|
||||
p->data[j][0]=note%12;
|
||||
p->data[j][1]=note/12;
|
||||
if (p->data[j][0]==0) {
|
||||
p->data[j][0]=12;
|
||||
p->data[j][1]=(unsigned char)(p->data[j][1]-1);
|
||||
}
|
||||
p->newData[j][DIV_PAT_NOTE]=note+60;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (hasIns) {
|
||||
ins=reader.readC();
|
||||
p->data[j][2]=((int)ins)-1;
|
||||
p->newData[j][DIV_PAT_INS]=((int)ins)-1;
|
||||
// default volume
|
||||
if (lastNote[k]<96 && ins>0) {
|
||||
p->data[j][3]=sampleVol[(((ins-1)&255)<<8)|(noteMap[(((ins-1)&255)<<7)|(lastNote[k]&127)])];
|
||||
p->newData[j][DIV_PAT_VOL]=sampleVol[(((ins-1)&255)<<8)|(noteMap[(((ins-1)&255)<<7)|(lastNote[k]&127)])];
|
||||
}
|
||||
writePanning=true;
|
||||
}
|
||||
if (hasVol) {
|
||||
vol=reader.readC();
|
||||
if (vol>=0x10 && vol<=0x50) {
|
||||
p->data[j][3]=vol-0x10;
|
||||
p->newData[j][DIV_PAT_VOL]=vol-0x10;
|
||||
} else { // effects in volume column
|
||||
switch (vol>>4) {
|
||||
case 0x6: // vol slide down
|
||||
|
|
@ -986,11 +980,11 @@ bool DivEngine::loadXM(unsigned char* file, size_t len) {
|
|||
vibing[k]=true;
|
||||
break;
|
||||
case 0xc: // panning
|
||||
p->data[j][effectCol[k]++]=0x80;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=0x80;
|
||||
if ((vol&15)==8) {
|
||||
p->data[j][effectCol[k]++]=0x80;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=0x80;
|
||||
} else {
|
||||
p->data[j][effectCol[k]++]=(vol&15)|((vol&15)<<4);
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=(vol&15)|((vol&15)<<4);
|
||||
}
|
||||
writePanning=false;
|
||||
break;
|
||||
|
|
@ -1113,14 +1107,14 @@ bool DivEngine::loadXM(unsigned char* file, size_t len) {
|
|||
treming[k]=true;
|
||||
break;
|
||||
case 8: // panning
|
||||
p->data[j][effectCol[k]++]=0x80;
|
||||
p->data[j][effectCol[k]++]=effectVal;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=0x80;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=effectVal;
|
||||
writePanning=false;
|
||||
break;
|
||||
case 9: // offset
|
||||
if (hasNote) {
|
||||
p->data[j][effectCol[k]++]=0x91;
|
||||
p->data[j][effectCol[k]++]=effectVal;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=0x91;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=effectVal;
|
||||
}
|
||||
break;
|
||||
case 0xa: // vol slide
|
||||
|
|
@ -1134,15 +1128,15 @@ bool DivEngine::loadXM(unsigned char* file, size_t len) {
|
|||
volSliding[k]=true;
|
||||
break;
|
||||
case 0xb: // go to order
|
||||
p->data[j][effectCol[k]++]=0x0b;
|
||||
p->data[j][effectCol[k]++]=effectVal;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=0x0b;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=effectVal;
|
||||
break;
|
||||
case 0xc: // set volume
|
||||
p->data[j][3]=effectVal;
|
||||
p->newData[j][DIV_PAT_VOL]=effectVal;
|
||||
break;
|
||||
case 0xd: // next order
|
||||
p->data[j][effectCol[k]++]=0x0d;
|
||||
p->data[j][effectCol[k]++]=effectVal;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=0x0d;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=effectVal;
|
||||
break;
|
||||
case 0xe: // special...
|
||||
// TODO: implement the rest
|
||||
|
|
@ -1150,27 +1144,27 @@ bool DivEngine::loadXM(unsigned char* file, size_t len) {
|
|||
case 0x4: // vibrato waveform
|
||||
switch (effectVal&3) {
|
||||
case 0x0: // sine
|
||||
p->data[j][effectCol[k]++]=0xe3;
|
||||
p->data[j][effectCol[k]++]=0x00;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=0xe3;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=0x00;
|
||||
break;
|
||||
case 0x1: // ramp down
|
||||
p->data[j][effectCol[k]++]=0xe3;
|
||||
p->data[j][effectCol[k]++]=0x05;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=0xe3;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=0x05;
|
||||
break;
|
||||
case 0x2: // square
|
||||
case 0x3:
|
||||
p->data[j][effectCol[k]++]=0xe3;
|
||||
p->data[j][effectCol[k]++]=0x06;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=0xe3;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=0x06;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0x5: // fine tune
|
||||
p->data[j][effectCol[k]++]=0xe5;
|
||||
p->data[j][effectCol[k]++]=(effectVal&15)<<4;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=0xe5;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=(effectVal&15)<<4;
|
||||
break;
|
||||
case 0x9: // retrigger
|
||||
p->data[j][effectCol[k]++]=0x0c;
|
||||
p->data[j][effectCol[k]++]=(effectVal&15);
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=0x0c;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=(effectVal&15);
|
||||
break;
|
||||
case 0xa: // vol slide up (fine)
|
||||
volSlideStatus[k]=((effectVal&15)<<4)|0xf;
|
||||
|
|
@ -1189,32 +1183,32 @@ bool DivEngine::loadXM(unsigned char* file, size_t len) {
|
|||
volSliding[k]=true;
|
||||
break;
|
||||
case 0xc: // note cut
|
||||
p->data[j][effectCol[k]++]=0xdc;
|
||||
p->data[j][effectCol[k]++]=MAX(1,effectVal&15);
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=0xdc;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=MAX(1,effectVal&15);
|
||||
break;
|
||||
case 0xd: // note delay
|
||||
p->data[j][effectCol[k]++]=0xed;
|
||||
p->data[j][effectCol[k]++]=MAX(1,effectVal&15);
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=0xed;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=MAX(1,effectVal&15);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0xf: // speed/tempo
|
||||
if (effectVal>=0x20) {
|
||||
p->data[j][effectCol[k]++]=0xf0;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=0xf0;
|
||||
} else if (effectVal==0) {
|
||||
p->data[j][effectCol[k]++]=0xff;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=0xff;
|
||||
} else {
|
||||
p->data[j][effectCol[k]++]=0x0f;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=0x0f;
|
||||
}
|
||||
p->data[j][effectCol[k]++]=effectVal;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=effectVal;
|
||||
break;
|
||||
case 0x10: // G: global volume (!)
|
||||
break;
|
||||
case 0x11: // H: global volume slide (!)
|
||||
break;
|
||||
case 0x14: // K: key off
|
||||
p->data[j][effectCol[k]++]=0xe7;
|
||||
p->data[j][effectCol[k]++]=effectVal;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=0xe7;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=effectVal;
|
||||
break;
|
||||
case 0x15: // L: set envelope position (!)
|
||||
break;
|
||||
|
|
@ -1226,8 +1220,8 @@ bool DivEngine::loadXM(unsigned char* file, size_t len) {
|
|||
panSliding[k]=true;
|
||||
break;
|
||||
case 0x1b: // R: retrigger
|
||||
p->data[j][effectCol[k]++]=0x0c;
|
||||
p->data[j][effectCol[k]++]=effectVal;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=0x0c;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=effectVal;
|
||||
break;
|
||||
case 0x1d: // T: tremor (!)
|
||||
break;
|
||||
|
|
@ -1244,8 +1238,8 @@ bool DivEngine::loadXM(unsigned char* file, size_t len) {
|
|||
}
|
||||
|
||||
if (writePanning && hasNote && note<96 && ins>0) {
|
||||
p->data[j][effectCol[k]++]=0x80;
|
||||
p->data[j][effectCol[k]++]=samplePan[(((ins-1)&255)<<8)|(noteMap[(((ins-1)&255)<<7)|(note&127)])];
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=0x80;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=samplePan[(((ins-1)&255)<<8)|(noteMap[(((ins-1)&255)<<7)|(note&127)])];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1253,80 +1247,80 @@ bool DivEngine::loadXM(unsigned char* file, size_t len) {
|
|||
for (int k=0; k<totalChans; k++) {
|
||||
DivPattern* p=ds.subsong[0]->pat[k].getPattern(i,true);
|
||||
if (vibing[k]!=vibingOld[k] || vibStatusChanged[k]) {
|
||||
p->data[j][effectCol[k]++]=0x04;
|
||||
p->data[j][effectCol[k]++]=vibing[k]?vibStatus[k]:0;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=0x04;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=vibing[k]?vibStatus[k]:0;
|
||||
doesVibrato[k]=true;
|
||||
} else if (doesVibrato[k] && mustCommitInitial) {
|
||||
p->data[j][effectCol[k]++]=0x04;
|
||||
p->data[j][effectCol[k]++]=0;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=0x04;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=0;
|
||||
}
|
||||
|
||||
if (volSliding[k]!=volSlidingOld[k] || volSlideStatusChanged[k]) {
|
||||
if (volSlideStatus[k]>=0xf1 && volSliding[k]) {
|
||||
p->data[j][effectCol[k]++]=0xf9;
|
||||
p->data[j][effectCol[k]++]=volSlideStatus[k]&15;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=0xf9;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=volSlideStatus[k]&15;
|
||||
volSliding[k]=false;
|
||||
} else if ((volSlideStatus[k]&15)==15 && volSlideStatus[k]>=0x10 && volSliding[k]) {
|
||||
p->data[j][effectCol[k]++]=0xf8;
|
||||
p->data[j][effectCol[k]++]=volSlideStatus[k]>>4;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=0xf8;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=volSlideStatus[k]>>4;
|
||||
volSliding[k]=false;
|
||||
} else {
|
||||
p->data[j][effectCol[k]++]=0xfa;
|
||||
p->data[j][effectCol[k]++]=volSliding[k]?volSlideStatus[k]:0;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=0xfa;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=volSliding[k]?volSlideStatus[k]:0;
|
||||
}
|
||||
doesVolSlide[k]=true;
|
||||
} else if (doesVolSlide[k] && mustCommitInitial) {
|
||||
p->data[j][effectCol[k]++]=0xfa;
|
||||
p->data[j][effectCol[k]++]=0;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=0xfa;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=0;
|
||||
}
|
||||
|
||||
if (porting[k]!=portingOld[k] || portaStatusChanged[k]) {
|
||||
p->data[j][effectCol[k]++]=portaType[k];
|
||||
p->data[j][effectCol[k]++]=porting[k]?portaStatus[k]:0;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=portaType[k];
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=porting[k]?portaStatus[k]:0;
|
||||
doesPitchSlide[k]=true;
|
||||
} else if (doesPitchSlide[k] && mustCommitInitial) {
|
||||
p->data[j][effectCol[k]++]=0x01;
|
||||
p->data[j][effectCol[k]++]=0;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=0x01;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=0;
|
||||
}
|
||||
|
||||
if (arping[k]!=arpingOld[k] || arpStatusChanged[k]) {
|
||||
p->data[j][effectCol[k]++]=0x00;
|
||||
p->data[j][effectCol[k]++]=arping[k]?arpStatus[k]:0;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=0x00;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=arping[k]?arpStatus[k]:0;
|
||||
doesArp[k]=true;
|
||||
} else if (doesArp[k] && mustCommitInitial) {
|
||||
p->data[j][effectCol[k]++]=0x00;
|
||||
p->data[j][effectCol[k]++]=0;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=0x00;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=0;
|
||||
}
|
||||
|
||||
if (treming[k]!=tremingOld[k] || tremStatusChanged[k]) {
|
||||
p->data[j][effectCol[k]++]=0x07;
|
||||
p->data[j][effectCol[k]++]=treming[k]?tremStatus[k]:0;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=0x07;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=treming[k]?tremStatus[k]:0;
|
||||
doesTremolo[k]=true;
|
||||
} else if (doesTremolo[k] && mustCommitInitial) {
|
||||
p->data[j][effectCol[k]++]=0x07;
|
||||
p->data[j][effectCol[k]++]=0;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=0x07;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=0;
|
||||
}
|
||||
|
||||
if (panning[k]!=panningOld[k] || panStatusChanged[k]) {
|
||||
p->data[j][effectCol[k]++]=0x84;
|
||||
p->data[j][effectCol[k]++]=panning[k]?panStatus[k]:0;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=0x84;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=panning[k]?panStatus[k]:0;
|
||||
doesPanbrello[k]=true;
|
||||
} else if (doesPanbrello[k] && mustCommitInitial) {
|
||||
p->data[j][effectCol[k]++]=0x84;
|
||||
p->data[j][effectCol[k]++]=0;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=0x84;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=0;
|
||||
}
|
||||
|
||||
if (panSliding[k]!=panSlidingOld[k] || panSlideStatusChanged[k]) {
|
||||
p->data[j][effectCol[k]++]=0x83;
|
||||
p->data[j][effectCol[k]++]=panSliding[k]?panSlideStatus[k]:0;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=0x83;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=panSliding[k]?panSlideStatus[k]:0;
|
||||
doesPanSlide[k]=true;
|
||||
} else if (doesPanSlide[k] && mustCommitInitial) {
|
||||
p->data[j][effectCol[k]++]=0x83;
|
||||
p->data[j][effectCol[k]++]=0;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=0x83;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=0;
|
||||
}
|
||||
|
||||
if ((effectCol[k]>>1)-2>ds.subsong[0]->pat[k].effectCols) {
|
||||
ds.subsong[0]->pat[k].effectCols=(effectCol[k]>>1)-1;
|
||||
if ((effectCol[k]>>1)>=ds.subsong[0]->pat[k].effectCols) {
|
||||
ds.subsong[0]->pat[k].effectCols=(effectCol[k]>>1)+1;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1346,14 +1340,14 @@ bool DivEngine::loadXM(unsigned char* file, size_t len) {
|
|||
if (j==totalRows-1) {
|
||||
// place end of pattern marker
|
||||
DivPattern* p=ds.subsong[0]->pat[0].getPattern(i,true);
|
||||
p->data[j][effectCol[0]++]=0x0d;
|
||||
p->data[j][effectCol[0]++]=0;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[0]++]=0x0d;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[0]++]=0;
|
||||
|
||||
if ((effectCol[0]>>1)-2>ds.subsong[0]->pat[0].effectCols) {
|
||||
ds.subsong[0]->pat[0].effectCols=(effectCol[0]>>1)-1;
|
||||
if ((effectCol[0]>>1)>=ds.subsong[0]->pat[0].effectCols) {
|
||||
ds.subsong[0]->pat[0].effectCols=(effectCol[0]>>1)+1;
|
||||
}
|
||||
}
|
||||
memset(effectCol,4,64);
|
||||
memset(effectCol,0,64);
|
||||
}
|
||||
|
||||
logV("seeking to %x...",packedSeek);
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ std::vector<std::pair<int,int>> DivChannelData::optimize() {
|
|||
for (int j=0; j<DIV_MAX_PATTERNS; j++) {
|
||||
if (j==i) continue;
|
||||
if (data[j]==NULL) continue;
|
||||
if (memcmp(data[i]->data,data[j]->data,DIV_MAX_ROWS*DIV_MAX_COLS*sizeof(short))==0) {
|
||||
if (memcmp(data[i]->newData,data[j]->newData,DIV_MAX_ROWS*DIV_MAX_COLS*sizeof(short))==0) {
|
||||
delete data[j];
|
||||
data[j]=NULL;
|
||||
logV("%d == %d",i,j);
|
||||
|
|
@ -86,15 +86,11 @@ void DivChannelData::wipePatterns() {
|
|||
|
||||
void DivPattern::copyOn(DivPattern* dest) {
|
||||
dest->name=name;
|
||||
memcpy(dest->data,data,sizeof(data));
|
||||
memcpy(dest->newData,newData,sizeof(newData));
|
||||
}
|
||||
|
||||
void DivPattern::clear() {
|
||||
memset(data,-1,DIV_MAX_ROWS*DIV_MAX_COLS*sizeof(short));
|
||||
for (int i=0; i<DIV_MAX_ROWS; i++) {
|
||||
data[i][0]=0;
|
||||
data[i][1]=0;
|
||||
}
|
||||
memset(newData,-1,DIV_MAX_ROWS*DIV_MAX_COLS*sizeof(short));
|
||||
}
|
||||
|
||||
DivChannelData::DivChannelData():
|
||||
|
|
|
|||
|
|
@ -22,7 +22,22 @@
|
|||
|
||||
struct DivPattern {
|
||||
String name;
|
||||
short data[DIV_MAX_ROWS][DIV_MAX_COLS];
|
||||
/**
|
||||
* pattern data is stored in this order:
|
||||
* - 0 note: 0 (min) is C-(-5), 60 is C-0, and 179 (max) is B-9.
|
||||
252 is null/bug, 253 is note off, 254 is note release and
|
||||
255 is macro release.
|
||||
* - 1 instrument
|
||||
* - 2 volume
|
||||
* - 3 effect
|
||||
* - 4 effect value
|
||||
* - 5... (the rest of effects/effect values)
|
||||
*
|
||||
* use the DIV_PAT_* macros in defines.h for convenience.
|
||||
*
|
||||
* if a cell is -1, it means "empty".
|
||||
*/
|
||||
short newData[DIV_MAX_ROWS][DIV_MAX_COLS];
|
||||
|
||||
/**
|
||||
* clear the pattern.
|
||||
|
|
@ -39,14 +54,10 @@ struct DivPattern {
|
|||
|
||||
struct DivChannelData {
|
||||
unsigned char effectCols;
|
||||
// data goes as follows: data[ROW][TYPE]
|
||||
// TYPE is:
|
||||
// 0: note
|
||||
// 1: octave
|
||||
// 2: instrument
|
||||
// 3: volume
|
||||
// 4-5+: effect/effect value
|
||||
// do NOT access directly unless you know what you're doing!
|
||||
/**
|
||||
* do NOT access directly unless you know what you're doing!
|
||||
* use getPattern() instead.
|
||||
*/
|
||||
DivPattern* data[DIV_MAX_PATTERNS];
|
||||
|
||||
/**
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -543,7 +543,11 @@ bool DivSample::saveRaw(const char* path) {
|
|||
}
|
||||
|
||||
// 16-bit memory is padded to 512, to make things easier for ADPCM-A/B.
|
||||
bool DivSample::initInternal(DivSampleDepth d, unsigned int count) {
|
||||
bool DivSample::initInternal(DivSampleDepth d, int count) {
|
||||
if (count<0) {
|
||||
logE("initInternal(%d,%d) - NEGATIVE!",(int)d,count);
|
||||
return false;
|
||||
}
|
||||
logV("initInternal(%d,%d)",(int)d,count);
|
||||
switch (d) {
|
||||
case DIV_SAMPLE_DEPTH_1BIT: // 1-bit
|
||||
|
|
@ -650,8 +654,11 @@ bool DivSample::initInternal(DivSampleDepth d, unsigned int count) {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool DivSample::init(unsigned int count) {
|
||||
if (count>16777215) return false;
|
||||
bool DivSample::init(int count) {
|
||||
if (count<0 || count>16777215) {
|
||||
logE("tried to init sample with length %d!",count);
|
||||
return false;
|
||||
}
|
||||
if (!initInternal(depth,count)) return false;
|
||||
setSampleCount(count);
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -236,14 +236,14 @@ struct DivSample {
|
|||
* @param count number of samples.
|
||||
* @return whether it was successful.
|
||||
*/
|
||||
bool initInternal(DivSampleDepth d, unsigned int count);
|
||||
bool initInternal(DivSampleDepth d, int count);
|
||||
|
||||
/**
|
||||
* initialize sample data. make sure you have set `depth` before doing so.
|
||||
* @param count number of samples.
|
||||
* @return whether it was successful.
|
||||
*/
|
||||
bool init(unsigned int count);
|
||||
bool init(int count);
|
||||
|
||||
/**
|
||||
* resize sample data. make sure the sample has been initialized before doing so.
|
||||
|
|
|
|||
|
|
@ -54,9 +54,9 @@ bool DivSubSong::walk(int& loopOrder, int& loopRow, int& loopEnd, int chans, int
|
|||
}
|
||||
for (int k=0; k<chans; k++) {
|
||||
for (int l=0; l<pat[k].effectCols; l++) {
|
||||
effectVal=subPat[k]->data[j][5+(l<<1)];
|
||||
effectVal=subPat[k]->newData[j][DIV_PAT_FXVAL(l)];
|
||||
if (effectVal<0) effectVal=0;
|
||||
if (subPat[k]->data[j][4+(l<<1)]==0x0d) {
|
||||
if (subPat[k]->newData[j][DIV_PAT_FX(l)]==0x0d) {
|
||||
if (jumpTreatment==2) {
|
||||
if ((i<ordersLen-1 || !ignoreJumpAtEnd)) {
|
||||
nextOrder=i+1;
|
||||
|
|
@ -78,7 +78,7 @@ bool DivSubSong::walk(int& loopOrder, int& loopRow, int& loopEnd, int chans, int
|
|||
nextRow=effectVal;
|
||||
}
|
||||
}
|
||||
} else if (subPat[k]->data[j][4+(l<<1)]==0x0b) {
|
||||
} else if (subPat[k]->newData[j][DIV_PAT_FX(l)]==0x0b) {
|
||||
if (nextOrder==-1 || jumpTreatment==0) {
|
||||
nextOrder=effectVal;
|
||||
if (jumpTreatment==1 || jumpTreatment==2 || !jumpingOrder) {
|
||||
|
|
@ -160,10 +160,10 @@ void DivSubSong::findLength(int loopOrder, int loopRow, double fadeoutLen, int&
|
|||
}
|
||||
for (int k=0; k<chans; k++) {
|
||||
for (int l=0; l<pat[k].effectCols; l++) {
|
||||
effectVal=subPat[k]->data[j][5+(l<<1)];
|
||||
effectVal=subPat[k]->newData[j][DIV_PAT_FXVAL(l)];
|
||||
if (effectVal<0) effectVal=0;
|
||||
|
||||
if (subPat[k]->data[j][4+(l<<1)]==0xff) {
|
||||
if (subPat[k]->newData[j][DIV_PAT_FX(l)]==0xff) {
|
||||
hasFFxx=true;
|
||||
|
||||
// FFxx makes YOU SHALL NOT PASS!!! move
|
||||
|
|
@ -173,7 +173,7 @@ void DivSubSong::findLength(int loopOrder, int loopRow, double fadeoutLen, int&
|
|||
return;
|
||||
}
|
||||
|
||||
switch (subPat[k]->data[j][4+(l<<1)]) {
|
||||
switch (subPat[k]->newData[j][DIV_PAT_FX(l)]) {
|
||||
case 0x09: { // select groove pattern/speed 1
|
||||
if (grooves.empty()) {
|
||||
if (effectVal>0) curSpeeds.val[0]=effectVal;
|
||||
|
|
@ -208,7 +208,7 @@ void DivSubSong::findLength(int loopOrder, int loopRow, double fadeoutLen, int&
|
|||
}
|
||||
}
|
||||
|
||||
if (subPat[k]->data[j][4+(l<<1)]==0x0d) {
|
||||
if (subPat[k]->newData[j][DIV_PAT_FX(l)]==0x0d) {
|
||||
if (jumpTreatment==2) {
|
||||
if ((i<ordersLen-1 || !ignoreJumpAtEnd)) {
|
||||
nextOrder=i+1;
|
||||
|
|
@ -230,7 +230,7 @@ void DivSubSong::findLength(int loopOrder, int loopRow, double fadeoutLen, int&
|
|||
nextRow=effectVal;
|
||||
}
|
||||
}
|
||||
} else if (subPat[k]->data[j][4+(l<<1)]==0x0b) {
|
||||
} else if (subPat[k]->newData[j][DIV_PAT_FX(l)]==0x0b) {
|
||||
if (nextOrder==-1 || jumpTreatment==0) {
|
||||
nextOrder=effectVal;
|
||||
if (jumpTreatment==1 || jumpTreatment==2 || !jumpingOrder) {
|
||||
|
|
|
|||
|
|
@ -902,10 +902,8 @@ void FurnaceGUI::drawChanOsc() {
|
|||
case 'n': {
|
||||
DivChannelState* chanState=e->getChanState(ch);
|
||||
if (chanState==NULL || !(chanState->keyOn)) break;
|
||||
short tempNote=chanState->note; //all of this conversion is necessary because notes 100-102 are special chars
|
||||
short noteMod=tempNote%12+12; //also note 0 is a BUG, hence +12 on the note and -1 on the octave
|
||||
short oct=tempNote/12-1;
|
||||
text+=fmt::sprintf("%s",noteName(noteMod,oct));
|
||||
// no more conversion necessary after the note/octave unification :>
|
||||
text+=fmt::sprintf("%s",noteName(chanState->note));
|
||||
break;
|
||||
}
|
||||
case 'l': {
|
||||
|
|
|
|||
|
|
@ -179,7 +179,6 @@ void FurnaceGUI::drawDebug() {
|
|||
ImGui::TextColored(ch->portaStop?uiColors[GUI_COLOR_MACRO_VOLUME]:uiColors[GUI_COLOR_HEADER],">> PortaStop");
|
||||
ImGui::TextColored(ch->keyOn?uiColors[GUI_COLOR_MACRO_VOLUME]:uiColors[GUI_COLOR_HEADER],">> Key On");
|
||||
ImGui::TextColored(ch->keyOff?uiColors[GUI_COLOR_MACRO_VOLUME]:uiColors[GUI_COLOR_HEADER],">> Key Off");
|
||||
ImGui::TextColored(ch->nowYouCanStop?uiColors[GUI_COLOR_MACRO_VOLUME]:uiColors[GUI_COLOR_HEADER],">> NowYouCanStop");
|
||||
ImGui::TextColored(ch->stopOnOff?uiColors[GUI_COLOR_MACRO_VOLUME]:uiColors[GUI_COLOR_HEADER],">> Stop on Off");
|
||||
ImGui::TextColored(ch->arpYield?uiColors[GUI_COLOR_MACRO_VOLUME]:uiColors[GUI_COLOR_HEADER],">> Arp Yield");
|
||||
ImGui::TextColored(ch->delayLocked?uiColors[GUI_COLOR_MACRO_VOLUME]:uiColors[GUI_COLOR_HEADER],">> DelayLocked");
|
||||
|
|
|
|||
|
|
@ -697,10 +697,10 @@ void FurnaceGUI::doAction(int what) {
|
|||
break;
|
||||
case GUI_ACTION_PAT_LATCH: {
|
||||
DivPattern* pat=e->curPat[cursor.xCoarse].getPattern(e->curOrders->ord[cursor.xCoarse][cursor.order],true);
|
||||
latchIns=pat->data[cursor.y][2];
|
||||
latchVol=pat->data[cursor.y][3];
|
||||
latchEffect=pat->data[cursor.y][4];
|
||||
latchEffectVal=pat->data[cursor.y][5];
|
||||
latchIns=pat->newData[cursor.y][DIV_PAT_INS];
|
||||
latchVol=pat->newData[cursor.y][DIV_PAT_VOL];
|
||||
latchEffect=pat->newData[cursor.y][DIV_PAT_FX(0)];
|
||||
latchEffectVal=pat->newData[cursor.y][DIV_PAT_FXVAL(0)];
|
||||
latchTarget=0;
|
||||
latchNibble=false;
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -35,21 +35,22 @@ static const char* modPlugFormatHeaders[]={
|
|||
NULL,
|
||||
};
|
||||
|
||||
const char* FurnaceGUI::noteNameNormal(short note, short octave) {
|
||||
if (note==100) { // note cut
|
||||
const char* FurnaceGUI::noteNameNormal(short note) {
|
||||
if (note==DIV_NOTE_OFF) { // note cut
|
||||
return "OFF";
|
||||
} else if (note==101) { // note off and envelope release
|
||||
} else if (note==DIV_NOTE_REL) { // note off and envelope release
|
||||
return "===";
|
||||
} else if (note==102) { // envelope release only
|
||||
} else if (note==DIV_MACRO_REL) { // envelope release only
|
||||
return "REL";
|
||||
} else if (octave==0 && note==0) {
|
||||
} else if (note==-1) {
|
||||
return "...";
|
||||
} else if (note==DIV_NOTE_NULL_PAT) {
|
||||
return "BUG";
|
||||
}
|
||||
int seek=(note+(signed char)octave*12)+60;
|
||||
if (seek<0 || seek>=180) {
|
||||
if (note<0 || note>=180) {
|
||||
return "???";
|
||||
}
|
||||
return noteNames[seek];
|
||||
return noteNames[note];
|
||||
}
|
||||
|
||||
void FurnaceGUI::prepareUndo(ActionType action, UndoRegion region) {
|
||||
|
|
@ -222,16 +223,16 @@ void FurnaceGUI::makeUndo(ActionType action, UndoRegion region) {
|
|||
|
||||
for (int j=jBegin; j<=jEnd; j++) {
|
||||
for (int k=0; k<DIV_MAX_COLS; k++) {
|
||||
if (p->data[j][k]!=op->data[j][k]) {
|
||||
s.pat.push_back(UndoPatternData(subSong,i,e->curOrders->ord[i][h],j,k,op->data[j][k],p->data[j][k]));
|
||||
if (p->newData[j][k]!=op->newData[j][k]) {
|
||||
s.pat.push_back(UndoPatternData(subSong,i,e->curOrders->ord[i][h],j,k,op->newData[j][k],p->newData[j][k]));
|
||||
|
||||
if (k>=4) {
|
||||
if (op->data[j][k&(~1)]==0x0b ||
|
||||
p->data[j][k&(~1)]==0x0b ||
|
||||
op->data[j][k&(~1)]==0x0d ||
|
||||
p->data[j][k&(~1)]==0x0d ||
|
||||
op->data[j][k&(~1)]==0xff ||
|
||||
p->data[j][k&(~1)]==0xff) {
|
||||
if (k>=DIV_PAT_FX(0)) {
|
||||
if (op->newData[j][k&(~1)]==0x0b ||
|
||||
p->newData[j][k&(~1)]==0x0b ||
|
||||
op->newData[j][k&(~1)]==0x0d ||
|
||||
p->newData[j][k&(~1)]==0x0d ||
|
||||
op->newData[j][k&(~1)]==0xff ||
|
||||
p->newData[j][k&(~1)]==0xff) {
|
||||
shallWalk=true;
|
||||
}
|
||||
}
|
||||
|
|
@ -366,13 +367,12 @@ void FurnaceGUI::doDelete() {
|
|||
for (; j<e->curSubSong->patLen && (j<=selEnd.y || jOrder<selEnd.order); j++) {
|
||||
touch(jOrder,j);
|
||||
if (iFine==0) {
|
||||
pat->data[j][iFine]=0;
|
||||
if (selStart.y==selEnd.y && selStart.order==selEnd.order) pat->data[j][2]=-1;
|
||||
if (selStart.y==selEnd.y && selStart.order==selEnd.order) pat->newData[j][DIV_PAT_VOL]=-1;
|
||||
}
|
||||
pat->data[j][iFine+1]=(iFine<1)?0:-1;
|
||||
pat->newData[j][iFine]=-1;
|
||||
|
||||
if (selStart.y==selEnd.y && selStart.order==selEnd.order && iFine>2 && iFine&1 && settings.effectDeletionAltersValue) {
|
||||
pat->data[j][iFine+2]=-1;
|
||||
if (selStart.y==selEnd.y && selStart.order==selEnd.order && DIV_PAT_IS_EFFECT(iFine) && settings.effectDeletionAltersValue) {
|
||||
pat->newData[j][iFine+1]=-1;
|
||||
}
|
||||
}
|
||||
j=0;
|
||||
|
|
@ -439,16 +439,12 @@ void FurnaceGUI::doPullDelete() {
|
|||
for (; iFine<3+e->curPat[iCoarse].effectCols*2 && (iCoarse<sEnd.xCoarse || iFine<=sEnd.xFine); iFine++) {
|
||||
maskOut(opMaskPullDelete,iFine);
|
||||
for (int j=sStart.y; j<e->curSubSong->patLen; j++) {
|
||||
// TODO: we've got a problem here. this should pull from the next row if the selection spans
|
||||
// more than one order.
|
||||
if (j<e->curSubSong->patLen-1) {
|
||||
if (iFine==0) {
|
||||
pat->data[j][iFine]=pat->data[j+1][iFine];
|
||||
}
|
||||
pat->data[j][iFine+1]=pat->data[j+1][iFine+1];
|
||||
pat->newData[j][iFine]=pat->newData[j+1][iFine];
|
||||
} else {
|
||||
if (iFine==0) {
|
||||
pat->data[j][iFine]=0;
|
||||
}
|
||||
pat->data[j][iFine+1]=(iFine<1)?0:-1;
|
||||
pat->newData[j][iFine]=-1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -486,15 +482,9 @@ void FurnaceGUI::doInsert() {
|
|||
maskOut(opMaskInsert,iFine);
|
||||
for (int j=e->curSubSong->patLen-1; j>=sStart.y; j--) {
|
||||
if (j==sStart.y) {
|
||||
if (iFine==0) {
|
||||
pat->data[j][iFine]=0;
|
||||
}
|
||||
pat->data[j][iFine+1]=(iFine<1)?0:-1;
|
||||
pat->newData[j][iFine]=-1;
|
||||
} else {
|
||||
if (iFine==0) {
|
||||
pat->data[j][iFine]=pat->data[j-1][iFine];
|
||||
}
|
||||
pat->data[j][iFine+1]=pat->data[j-1][iFine+1];
|
||||
pat->newData[j][iFine]=pat->newData[j-1][iFine];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -522,45 +512,22 @@ void FurnaceGUI::doTranspose(int amount, OperationMask& mask) {
|
|||
DivPattern* pat=e->curPat[iCoarse].getPattern(e->curOrders->ord[iCoarse][jOrder],true);
|
||||
for (; j<e->curSubSong->patLen && (j<=selEnd.y || jOrder<selEnd.order); j++) {
|
||||
touch(jOrder,j);
|
||||
if (iFine==0) {
|
||||
int origNote=pat->data[j][0];
|
||||
int origOctave=(signed char)pat->data[j][1];
|
||||
if (origNote!=0 && origNote!=100 && origNote!=101 && origNote!=102) {
|
||||
origNote+=amount;
|
||||
while (origNote>12) {
|
||||
origNote-=12;
|
||||
origOctave++;
|
||||
}
|
||||
while (origNote<1) {
|
||||
origNote+=12;
|
||||
origOctave--;
|
||||
}
|
||||
if (origOctave==9 && origNote>11) {
|
||||
origNote=11;
|
||||
origOctave=9;
|
||||
}
|
||||
if (origOctave>9) {
|
||||
origNote=11;
|
||||
origOctave=9;
|
||||
}
|
||||
if (origOctave<-5) {
|
||||
origNote=1;
|
||||
origOctave=-5;
|
||||
}
|
||||
pat->data[j][0]=origNote;
|
||||
pat->data[j][1]=(unsigned char)origOctave;
|
||||
}
|
||||
} else {
|
||||
int top=255;
|
||||
if (iFine==1) {
|
||||
if (e->song.ins.empty()) continue;
|
||||
top=e->song.ins.size()-1;
|
||||
} else if (iFine==2) { // volume
|
||||
top=e->getMaxVolumeChan(iCoarse);
|
||||
}
|
||||
if (pat->data[j][iFine+1]==-1) continue;
|
||||
pat->data[j][iFine+1]=MIN(top,MAX(0,pat->data[j][iFine+1]+amount));
|
||||
int top=255;
|
||||
if (iFine==DIV_PAT_NOTE) {
|
||||
top=179;
|
||||
// don't transpose special notes
|
||||
if (pat->newData[j][iFine]==DIV_NOTE_OFF) continue;
|
||||
if (pat->newData[j][iFine]==DIV_NOTE_REL) continue;
|
||||
if (pat->newData[j][iFine]==DIV_MACRO_REL) continue;
|
||||
if (pat->newData[j][iFine]==DIV_NOTE_NULL_PAT) continue;
|
||||
} else if (iFine==DIV_PAT_INS) {
|
||||
if (e->song.ins.empty()) continue;
|
||||
top=e->song.ins.size()-1;
|
||||
} else if (iFine==DIV_PAT_VOL) { // volume
|
||||
top=e->getMaxVolumeChan(iCoarse);
|
||||
}
|
||||
if (pat->newData[j][iFine]==-1) continue;
|
||||
pat->newData[j][iFine]=MIN(top,MAX(0,pat->newData[j][iFine]+amount));
|
||||
}
|
||||
j=0;
|
||||
}
|
||||
|
|
@ -596,19 +563,18 @@ String FurnaceGUI::doCopy(bool cut, bool writeClipboard, const SelectionPoint& s
|
|||
DivPattern* pat=e->curPat[iCoarse].getPattern(e->curOrders->ord[iCoarse][jOrder],true);
|
||||
for (; iFine<3+e->curPat[iCoarse].effectCols*2 && (iCoarse<sEnd.xCoarse || iFine<=sEnd.xFine); iFine++) {
|
||||
if (iFine==0) {
|
||||
clipb+=noteNameNormal(pat->data[j][0],pat->data[j][1]);
|
||||
clipb+=noteNameNormal(pat->newData[j][DIV_PAT_NOTE]);
|
||||
if (cut) {
|
||||
pat->data[j][0]=0;
|
||||
pat->data[j][1]=0;
|
||||
pat->newData[j][DIV_PAT_NOTE]=-1;
|
||||
}
|
||||
} else {
|
||||
if (pat->data[j][iFine+1]==-1) {
|
||||
if (pat->newData[j][iFine]==-1) {
|
||||
clipb+="..";
|
||||
} else {
|
||||
clipb+=fmt::sprintf("%.2X",pat->data[j][iFine+1]);
|
||||
clipb+=fmt::sprintf("%.2X",pat->newData[j][iFine]);
|
||||
}
|
||||
if (cut) {
|
||||
pat->data[j][iFine+1]=-1;
|
||||
pat->newData[j][iFine]=-1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -685,12 +651,12 @@ void FurnaceGUI::doPasteFurnace(PasteMode mode, int arg, bool readClipboard, Str
|
|||
mode==GUI_PASTE_MODE_INS_BG || mode==GUI_PASTE_MODE_INS_FG) && strcmp(note,"...")==0) {
|
||||
// do nothing.
|
||||
} else {
|
||||
if (!(mode==GUI_PASTE_MODE_MIX_BG || mode==GUI_PASTE_MODE_INS_BG) || (pat->data[j][0]==0 && pat->data[j][1]==0)) {
|
||||
if (!decodeNote(note,pat->data[j][0],pat->data[j][1])) {
|
||||
if (!(mode==GUI_PASTE_MODE_MIX_BG || mode==GUI_PASTE_MODE_INS_BG) || (pat->newData[j][DIV_PAT_NOTE]==-1)) {
|
||||
if (!decodeNote(note,pat->newData[j][DIV_PAT_NOTE])) {
|
||||
invalidData=true;
|
||||
break;
|
||||
}
|
||||
if (mode==GUI_PASTE_MODE_INS_BG || mode==GUI_PASTE_MODE_INS_FG) pat->data[j][2]=arg;
|
||||
if (mode==GUI_PASTE_MODE_INS_BG || mode==GUI_PASTE_MODE_INS_FG) pat->newData[j][DIV_PAT_INS]=arg;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
|
@ -706,12 +672,12 @@ void FurnaceGUI::doPasteFurnace(PasteMode mode, int arg, bool readClipboard, Str
|
|||
note[1]=line[charPos++];
|
||||
note[2]=0;
|
||||
|
||||
if (iFine==1) {
|
||||
if (iFine==DIV_PAT_INS) {
|
||||
if (!opMaskPaste.ins || mode==GUI_PASTE_MODE_INS_BG || mode==GUI_PASTE_MODE_INS_FG) {
|
||||
iFine++;
|
||||
continue;
|
||||
}
|
||||
} else if (iFine==2) {
|
||||
} else if (iFine==DIV_PAT_VOL) {
|
||||
if (!opMaskPaste.vol) {
|
||||
iFine++;
|
||||
continue;
|
||||
|
|
@ -731,7 +697,7 @@ void FurnaceGUI::doPasteFurnace(PasteMode mode, int arg, bool readClipboard, Str
|
|||
if (strcmp(note,"..")==0) {
|
||||
if (!(mode==GUI_PASTE_MODE_MIX_BG || mode==GUI_PASTE_MODE_MIX_FG ||
|
||||
mode==GUI_PASTE_MODE_INS_BG || mode==GUI_PASTE_MODE_INS_FG)) {
|
||||
pat->data[j][iFine+1]=-1;
|
||||
pat->newData[j][iFine]=-1;
|
||||
}
|
||||
} else {
|
||||
unsigned int val=0;
|
||||
|
|
@ -739,8 +705,8 @@ void FurnaceGUI::doPasteFurnace(PasteMode mode, int arg, bool readClipboard, Str
|
|||
invalidData=true;
|
||||
break;
|
||||
}
|
||||
if (!(mode==GUI_PASTE_MODE_MIX_BG || mode==GUI_PASTE_MODE_INS_BG) || pat->data[j][iFine+1]==-1) {
|
||||
if (iFine<(3+e->curPat[iCoarse].effectCols*2)) pat->data[j][iFine+1]=val;
|
||||
if (!(mode==GUI_PASTE_MODE_MIX_BG || mode==GUI_PASTE_MODE_INS_BG) || pat->newData[j][iFine]==-1) {
|
||||
if (iFine<(3+e->curPat[iCoarse].effectCols*2)) pat->newData[j][iFine]=val;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1024,7 +990,7 @@ void FurnaceGUI::doPasteMPT(PasteMode mode, int arg, bool readClipboard, String
|
|||
charPos++;
|
||||
continue;
|
||||
}
|
||||
if (iFine==0) { // note
|
||||
if (iFine==DIV_PAT_NOTE) { // note
|
||||
if (charPos>=line.size()) {
|
||||
invalidData=true;
|
||||
break;
|
||||
|
|
@ -1050,25 +1016,28 @@ void FurnaceGUI::doPasteMPT(PasteMode mode, int arg, bool readClipboard, String
|
|||
if (strcmp(note,"...")==0 || strcmp(note," ")==0) {
|
||||
// do nothing.
|
||||
} else {
|
||||
if (!(mode==GUI_PASTE_MODE_MIX_BG || mode==GUI_PASTE_MODE_INS_BG) || (pat->data[j][0]==0 && pat->data[j][1]==0)) {
|
||||
if (!decodeNote(note,pat->data[j][0],pat->data[j][1])) {
|
||||
if (!(mode==GUI_PASTE_MODE_MIX_BG || mode==GUI_PASTE_MODE_INS_BG) || (pat->newData[j][DIV_PAT_NOTE]==-1)) {
|
||||
if (!decodeNote(note,pat->newData[j][DIV_PAT_NOTE])) {
|
||||
if (strcmp(note, "^^^")==0) {
|
||||
pat->data[j][0]=100;
|
||||
pat->data[j][1]=0;
|
||||
pat->newData[j][0]=DIV_NOTE_OFF;
|
||||
} else if (strcmp(note, "~~~")==0 || strcmp(note,"===")==0) {
|
||||
pat->data[j][0]=101;
|
||||
pat->data[j][1]=0;
|
||||
pat->newData[j][0]=DIV_NOTE_REL;
|
||||
} else {
|
||||
invalidData=true;
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
pat->data[j][1]--; // MPT is one octave higher...
|
||||
// MPT is one octave higher...
|
||||
if (pat->newData[j][DIV_PAT_NOTE]<12) {
|
||||
pat->newData[j][DIV_PAT_NOTE]=0;
|
||||
} else {
|
||||
pat->newData[j][DIV_PAT_NOTE]-=12;
|
||||
}
|
||||
}
|
||||
if (mode==GUI_PASTE_MODE_INS_BG || mode==GUI_PASTE_MODE_INS_FG) pat->data[j][2]=arg;
|
||||
if (mode==GUI_PASTE_MODE_INS_BG || mode==GUI_PASTE_MODE_INS_FG) pat->newData[j][DIV_PAT_INS]=arg;
|
||||
}
|
||||
}
|
||||
} else if (iFine==1) { // instrument
|
||||
} else if (iFine==DIV_PAT_INS) { // instrument
|
||||
if (charPos>=line.size()) {
|
||||
invalidData=true;
|
||||
break;
|
||||
|
|
@ -1081,7 +1050,7 @@ void FurnaceGUI::doPasteMPT(PasteMode mode, int arg, bool readClipboard, String
|
|||
note[1]=line[charPos++];
|
||||
note[2]=0;
|
||||
|
||||
if (iFine==1) {
|
||||
if (iFine==DIV_PAT_INS) {
|
||||
if (!opMaskPaste.ins || mode==GUI_PASTE_MODE_INS_BG || mode==GUI_PASTE_MODE_INS_FG) {
|
||||
iFine++;
|
||||
continue;
|
||||
|
|
@ -1091,7 +1060,7 @@ void FurnaceGUI::doPasteMPT(PasteMode mode, int arg, bool readClipboard, String
|
|||
if (strcmp(note,"..")==0 || strcmp(note," ")==0) {
|
||||
if (!(mode==GUI_PASTE_MODE_MIX_BG || mode==GUI_PASTE_MODE_MIX_FG ||
|
||||
mode==GUI_PASTE_MODE_INS_BG || mode==GUI_PASTE_MODE_INS_FG)) {
|
||||
pat->data[j][iFine+1]=-1;
|
||||
pat->newData[j][iFine]=-1;
|
||||
}
|
||||
} else {
|
||||
unsigned int val=0;
|
||||
|
|
@ -1100,8 +1069,8 @@ void FurnaceGUI::doPasteMPT(PasteMode mode, int arg, bool readClipboard, String
|
|||
break;
|
||||
}
|
||||
|
||||
if (!(mode==GUI_PASTE_MODE_MIX_BG || mode==GUI_PASTE_MODE_INS_BG) || pat->data[j][iFine+1]==-1) {
|
||||
pat->data[j][iFine+1]=val-1;
|
||||
if (!(mode==GUI_PASTE_MODE_MIX_BG || mode==GUI_PASTE_MODE_INS_BG) || pat->newData[j][iFine]==-1) {
|
||||
pat->newData[j][iFine]=val-1;
|
||||
}
|
||||
}
|
||||
} else { // volume and effects
|
||||
|
|
@ -1122,14 +1091,12 @@ void FurnaceGUI::doPasteMPT(PasteMode mode, int arg, bool readClipboard, String
|
|||
note[2]=line[charPos++];
|
||||
note[3]=0;
|
||||
|
||||
if (iFine==2) {
|
||||
if (iFine==DIV_PAT_VOL) {
|
||||
if (!opMaskPaste.vol) {
|
||||
iFine++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
else if ((iFine&1)==0) {
|
||||
} else if ((iFine&1)==0) { // FUCKING HELL WITH THE INDENTATION?!?!
|
||||
if (!opMaskPaste.effectVal) {
|
||||
iFine++;
|
||||
continue;
|
||||
|
|
@ -1143,9 +1110,8 @@ void FurnaceGUI::doPasteMPT(PasteMode mode, int arg, bool readClipboard, String
|
|||
|
||||
if (strcmp(note,"...")==0 || strcmp(note," ")==0) {
|
||||
if (!(mode==GUI_PASTE_MODE_MIX_BG || mode==GUI_PASTE_MODE_MIX_FG ||
|
||||
mode==GUI_PASTE_MODE_INS_BG || mode==GUI_PASTE_MODE_INS_FG))
|
||||
{
|
||||
pat->data[j][iFine+1]=-1;
|
||||
mode==GUI_PASTE_MODE_INS_BG || mode==GUI_PASTE_MODE_INS_FG)) {
|
||||
pat->newData[j][iFine]=-1;
|
||||
}
|
||||
} else {
|
||||
unsigned int val=0;
|
||||
|
|
@ -1153,19 +1119,19 @@ void FurnaceGUI::doPasteMPT(PasteMode mode, int arg, bool readClipboard, String
|
|||
|
||||
symbol=note[0];
|
||||
|
||||
if (iFine==2) {
|
||||
if (iFine==DIV_PAT_VOL) {
|
||||
sscanf(¬e[1],"%2d",&val);
|
||||
} else {
|
||||
sscanf(¬e[1],"%2X",&val);
|
||||
}
|
||||
|
||||
if (!(mode==GUI_PASTE_MODE_MIX_BG || mode==GUI_PASTE_MODE_INS_BG) || pat->data[j][iFine+1]==-1) {
|
||||
// if (iFine<(3+e->curPat[iCoarse].effectCols*2)) pat->data[j][iFine+1]=val;
|
||||
if (iFine==2) { // volume
|
||||
if (!(mode==GUI_PASTE_MODE_MIX_BG || mode==GUI_PASTE_MODE_INS_BG) || pat->newData[j][iFine]==-1) {
|
||||
// if (iFine<(3+e->curPat[iCoarse].effectCols*2)) pat->newData[j][iFine]=val;
|
||||
if (iFine==DIV_PAT_VOL) { // volume
|
||||
switch(symbol) {
|
||||
case 'v':
|
||||
{
|
||||
pat->data[j][iFine+1]=val;
|
||||
pat->newData[j][iFine]=val;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
|
@ -1176,7 +1142,7 @@ void FurnaceGUI::doPasteMPT(PasteMode mode, int arg, bool readClipboard, String
|
|||
if (mptFormat==0) {
|
||||
eff=convertEffectMPT_MOD(symbol, val); // up to 4 effects stored in one variable
|
||||
if (((eff&0x0f00)>>8)==0x0C) { // set volume
|
||||
pat->data[j][iFine]=eff&0xff;
|
||||
pat->newData[j][iFine-1]=eff&0xff;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1189,7 +1155,7 @@ void FurnaceGUI::doPasteMPT(PasteMode mode, int arg, bool readClipboard, String
|
|||
|
||||
if (((eff&0x0f00)>>8)==0x0C)
|
||||
{
|
||||
pat->data[j][iFine]=eff&0xff;
|
||||
pat->newData[j][iFine-1]=eff&0xff;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1201,12 +1167,12 @@ void FurnaceGUI::doPasteMPT(PasteMode mode, int arg, bool readClipboard, String
|
|||
eff=convertEffectMPT_MPTM(symbol, val);
|
||||
}
|
||||
|
||||
pat->data[j][iFine+1]=((eff&0xff00)>>8);
|
||||
pat->data[j][iFine+2]=(eff&0xff);
|
||||
pat->newData[j][iFine]=((eff&0xff00)>>8);
|
||||
pat->newData[j][iFine+1]=(eff&0xff);
|
||||
|
||||
if (eff>0xffff) {
|
||||
pat->data[j][iFine+3]=((eff&0xff000000)>>24);
|
||||
pat->data[j][iFine+4]=((eff&0xff0000)>>16);
|
||||
pat->newData[j][iFine+2]=((eff&0xff000000)>>24);
|
||||
pat->newData[j][iFine+3]=((eff&0xff0000)>>16);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1346,8 +1312,8 @@ void FurnaceGUI::doChangeIns(int ins) {
|
|||
DivPattern* pat=e->curPat[iCoarse].getPattern(e->curOrders->ord[iCoarse][jOrder],true);
|
||||
for (; j<e->curSubSong->patLen && (j<=selEnd.y || jOrder<selEnd.order); j++) {
|
||||
touch(jOrder,j);
|
||||
if (pat->data[j][2]!=-1 || !((pat->data[j][0]==0 || pat->data[j][0]==100 || pat->data[j][0]==101 || pat->data[j][0]==102) && pat->data[j][1]==0)) {
|
||||
pat->data[j][2]=ins;
|
||||
if (pat->newData[j][DIV_PAT_INS]!=-1 || !(pat->newData[j][DIV_PAT_NOTE]==-1 || pat->newData[j][DIV_PAT_NOTE]==DIV_NOTE_OFF || pat->newData[j][DIV_PAT_NOTE]==DIV_NOTE_REL || pat->newData[j][DIV_PAT_NOTE]==DIV_MACRO_REL)) {
|
||||
pat->newData[j][DIV_PAT_INS]=ins;
|
||||
}
|
||||
}
|
||||
j=0;
|
||||
|
|
@ -1372,15 +1338,15 @@ void FurnaceGUI::doInterpolate() {
|
|||
maskOut(opMaskInterpolate,iFine);
|
||||
points.clear();
|
||||
resetTouches;
|
||||
if (iFine!=0) {
|
||||
if (iFine!=DIV_PAT_NOTE) {
|
||||
int jOrder=selStart.order;
|
||||
int j=selStart.y;
|
||||
for (; jOrder<=selEnd.order; jOrder++) {
|
||||
DivPattern* pat=e->curPat[iCoarse].getPattern(e->curOrders->ord[iCoarse][jOrder],true);
|
||||
for (; j<e->curSubSong->patLen && (j<=selEnd.y || jOrder<selEnd.order); j++) {
|
||||
touch(jOrder,j);
|
||||
if (pat->data[j][iFine+1]!=-1) {
|
||||
points.emplace(points.end(),j|(jOrder<<8),pat->data[j][iFine+1]);
|
||||
if (pat->newData[j][iFine]!=-1) {
|
||||
points.emplace(points.end(),j|(jOrder<<8),pat->newData[j][iFine]);
|
||||
}
|
||||
}
|
||||
j=0;
|
||||
|
|
@ -1395,7 +1361,7 @@ void FurnaceGUI::doInterpolate() {
|
|||
);
|
||||
for (int k=0, k_p=curPoint.first; k<distance; k++) {
|
||||
DivPattern* pat=e->curPat[iCoarse].getPattern(e->curOrders->ord[iCoarse][(k_p>>8)&0xff],true);
|
||||
pat->data[k_p&0xff][iFine+1]=curPoint.second+((nextPoint.second-curPoint.second)*(double)k/(double)distance);
|
||||
pat->newData[k_p&0xff][iFine]=curPoint.second+((nextPoint.second-curPoint.second)*(double)k/(double)distance);
|
||||
k_p++;
|
||||
if ((k_p&0xff)>=e->curSubSong->patLen) {
|
||||
k_p&=~0xff;
|
||||
|
|
@ -1410,9 +1376,9 @@ void FurnaceGUI::doInterpolate() {
|
|||
DivPattern* pat=e->curPat[iCoarse].getPattern(e->curOrders->ord[iCoarse][jOrder],true);
|
||||
for (; j<e->curSubSong->patLen && (j<=selEnd.y || jOrder<selEnd.order); j++) {
|
||||
touch(jOrder,j);
|
||||
if (pat->data[j][0]!=0 || pat->data[j][1]!=0) {
|
||||
if (pat->data[j][0]!=100 && pat->data[j][0]!=101 && pat->data[j][0]!=102) {
|
||||
points.emplace(points.end(),j|(jOrder<<8),pat->data[j][0]+(signed char)pat->data[j][1]*12);
|
||||
if (pat->newData[j][DIV_PAT_NOTE]!=-1) {
|
||||
if (pat->newData[j][DIV_PAT_NOTE]!=DIV_NOTE_OFF && pat->newData[j][DIV_PAT_NOTE]!=DIV_NOTE_REL && pat->newData[j][DIV_PAT_NOTE]!=DIV_MACRO_REL) {
|
||||
points.emplace(points.end(),j|(jOrder<<8),pat->newData[j][DIV_PAT_NOTE]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1429,13 +1395,7 @@ void FurnaceGUI::doInterpolate() {
|
|||
for (int k=0, k_p=curPoint.first; k<distance; k++) {
|
||||
DivPattern* pat=e->curPat[iCoarse].getPattern(e->curOrders->ord[iCoarse][(k_p>>8)&0xff],true);
|
||||
int val=curPoint.second+((nextPoint.second-curPoint.second)*(double)k/(double)distance);
|
||||
pat->data[k_p&0xff][0]=val%12;
|
||||
pat->data[k_p&0xff][1]=val/12;
|
||||
if (pat->data[k_p&0xff][0]==0) {
|
||||
pat->data[k_p&0xff][0]=12;
|
||||
pat->data[k_p&0xff][1]--;
|
||||
}
|
||||
pat->data[k_p&0xff][1]&=255;
|
||||
pat->newData[k_p&0xff][DIV_PAT_NOTE]=val%12;
|
||||
k_p++;
|
||||
if ((k_p&0xff)>=e->curSubSong->patLen) {
|
||||
k_p&=~0xff;
|
||||
|
|
@ -1469,12 +1429,12 @@ void FurnaceGUI::doFade(int p0, int p1, bool mode) {
|
|||
int j_p=0;
|
||||
maskOut(opMaskFade,iFine);
|
||||
resetTouches;
|
||||
if (iFine!=0) {
|
||||
if (iFine!=DIV_PAT_NOTE) {
|
||||
int absoluteTop=255;
|
||||
if (iFine==1) {
|
||||
if (iFine==DIV_PAT_INS) {
|
||||
if (e->song.ins.empty()) continue;
|
||||
absoluteTop=e->song.ins.size()-1;
|
||||
} else if (iFine==2) { // volume
|
||||
} else if (iFine==DIV_PAT_VOL) { // volume
|
||||
absoluteTop=e->getMaxVolumeChan(iCoarse);
|
||||
}
|
||||
if (distance<1) continue;
|
||||
|
|
@ -1485,9 +1445,9 @@ void FurnaceGUI::doFade(int p0, int p1, bool mode) {
|
|||
int value=p0+double(p1-p0)*fraction;
|
||||
if (mode) { // nibble
|
||||
value&=15;
|
||||
pat->data[j][iFine+1]=MIN(absoluteTop,value|(value<<4));
|
||||
pat->newData[j][iFine]=MIN(absoluteTop,value|(value<<4));
|
||||
} else { // byte
|
||||
pat->data[j][iFine+1]=MIN(absoluteTop,value);
|
||||
pat->newData[j][iFine]=MIN(absoluteTop,value);
|
||||
}
|
||||
j_p++;
|
||||
}
|
||||
|
|
@ -1514,20 +1474,20 @@ void FurnaceGUI::doInvertValues() {
|
|||
int j=selStart.y;
|
||||
maskOut(opMaskInvertVal,iFine);
|
||||
resetTouches;
|
||||
if (iFine!=0) {
|
||||
if (iFine!=DIV_PAT_NOTE) {
|
||||
int top=255;
|
||||
if (iFine==1) {
|
||||
if (iFine==DIV_PAT_INS) {
|
||||
if (e->song.ins.empty()) continue;
|
||||
top=e->song.ins.size()-1;
|
||||
} else if (iFine==2) { // volume
|
||||
} else if (iFine==DIV_PAT_VOL) { // volume
|
||||
top=e->getMaxVolumeChan(iCoarse);
|
||||
}
|
||||
for (; jOrder<=selEnd.order; jOrder++) {
|
||||
DivPattern* pat=e->curPat[iCoarse].getPattern(e->curOrders->ord[iCoarse][jOrder],true);
|
||||
for (; j<e->curSubSong->patLen && (j<=selEnd.y || jOrder<selEnd.order); j++) {
|
||||
touch(jOrder,j);
|
||||
if (pat->data[j][iFine+1]==-1) continue;
|
||||
pat->data[j][iFine+1]=top-pat->data[j][iFine+1];
|
||||
if (pat->newData[j][iFine]==-1) continue;
|
||||
pat->newData[j][iFine]=top-pat->newData[j][iFine];
|
||||
}
|
||||
j=0;
|
||||
}
|
||||
|
|
@ -1552,20 +1512,20 @@ void FurnaceGUI::doScale(float top) {
|
|||
int j=selStart.y;
|
||||
maskOut(opMaskScale,iFine);
|
||||
resetTouches;
|
||||
if (iFine!=0) {
|
||||
if (iFine!=DIV_PAT_NOTE) {
|
||||
int absoluteTop=255;
|
||||
if (iFine==1) {
|
||||
if (iFine==DIV_PAT_INS) {
|
||||
if (e->song.ins.empty()) continue;
|
||||
absoluteTop=e->song.ins.size()-1;
|
||||
} else if (iFine==2) { // volume
|
||||
} else if (iFine==DIV_PAT_VOL) { // volume
|
||||
absoluteTop=e->getMaxVolumeChan(iCoarse);
|
||||
}
|
||||
for (; jOrder<=selEnd.order; jOrder++) {
|
||||
DivPattern* pat=e->curPat[iCoarse].getPattern(e->curOrders->ord[iCoarse][jOrder],true);
|
||||
for (; j<e->curSubSong->patLen && (j<=selEnd.y || jOrder<selEnd.order); j++) {
|
||||
touch(jOrder,j);
|
||||
if (pat->data[j][iFine+1]==-1) continue;
|
||||
pat->data[j][iFine+1]=MIN(absoluteTop,(double)pat->data[j][iFine+1]*(top/100.0f));
|
||||
if (pat->newData[j][iFine]==-1) continue;
|
||||
pat->newData[j][iFine]=MIN(absoluteTop,(double)pat->newData[j][iFine]*(top/100.0f));
|
||||
}
|
||||
j=0;
|
||||
}
|
||||
|
|
@ -1590,63 +1550,40 @@ void FurnaceGUI::doRandomize(int bottom, int top, bool mode, bool eff, int effVa
|
|||
int j=selStart.y;
|
||||
maskOut(opMaskRandomize,iFine);
|
||||
resetTouches;
|
||||
if (iFine!=0) {
|
||||
int absoluteTop=255;
|
||||
if (iFine==1) {
|
||||
if (e->song.ins.empty()) continue;
|
||||
absoluteTop=e->song.ins.size()-1;
|
||||
} else if (iFine==2) { // volume
|
||||
absoluteTop=e->getMaxVolumeChan(iCoarse);
|
||||
}
|
||||
for (; jOrder<=selEnd.order; jOrder++) {
|
||||
DivPattern* pat=e->curPat[iCoarse].getPattern(e->curOrders->ord[iCoarse][jOrder],true);
|
||||
for (; j<e->curSubSong->patLen && (j<=selEnd.y || jOrder<selEnd.order); j++) {
|
||||
int value=0;
|
||||
int value2=0;
|
||||
touch(jOrder,j);
|
||||
if (top-bottom<=0) {
|
||||
value=MIN(absoluteTop,bottom);
|
||||
value2=MIN(absoluteTop,bottom);
|
||||
} else {
|
||||
value=MIN(absoluteTop,bottom+(rand()%(top-bottom+1)));
|
||||
value2=MIN(absoluteTop,bottom+(rand()%(top-bottom+1)));
|
||||
}
|
||||
if (mode) {
|
||||
value&=15;
|
||||
value2&=15;
|
||||
pat->data[j][iFine+1]=value|(value2<<4);
|
||||
} else {
|
||||
pat->data[j][iFine+1]=value;
|
||||
}
|
||||
if (eff && iFine>2 && (iFine&1)) {
|
||||
pat->data[j][iFine+1]=effVal;
|
||||
}
|
||||
int absoluteTop=255;
|
||||
if (iFine==DIV_PAT_NOTE) {
|
||||
absoluteTop=179;
|
||||
} else if (iFine==DIV_PAT_INS) {
|
||||
if (e->song.ins.empty()) continue;
|
||||
absoluteTop=e->song.ins.size()-1;
|
||||
} else if (iFine==DIV_PAT_VOL) { // volume
|
||||
absoluteTop=e->getMaxVolumeChan(iCoarse);
|
||||
}
|
||||
for (; jOrder<=selEnd.order; jOrder++) {
|
||||
DivPattern* pat=e->curPat[iCoarse].getPattern(e->curOrders->ord[iCoarse][jOrder],true);
|
||||
for (; j<e->curSubSong->patLen && (j<=selEnd.y || jOrder<selEnd.order); j++) {
|
||||
int value=0;
|
||||
int value2=0;
|
||||
touch(jOrder,j);
|
||||
if (top-bottom<=0) {
|
||||
value=MIN(absoluteTop,bottom);
|
||||
value2=MIN(absoluteTop,bottom);
|
||||
} else {
|
||||
value=MIN(absoluteTop,bottom+(rand()%(top-bottom+1)));
|
||||
value2=MIN(absoluteTop,bottom+(rand()%(top-bottom+1)));
|
||||
}
|
||||
j=0;
|
||||
}
|
||||
} else {
|
||||
// random notes
|
||||
int absoluteTop=179;
|
||||
for (; jOrder<=selEnd.order; jOrder++) {
|
||||
DivPattern* pat=e->curPat[iCoarse].getPattern(e->curOrders->ord[iCoarse][jOrder],true);
|
||||
for (; j<e->curSubSong->patLen && (j<=selEnd.y || jOrder<selEnd.order); j++) {
|
||||
int value=0;
|
||||
touch(jOrder,j);
|
||||
if (top-bottom<=0) {
|
||||
value=MIN(absoluteTop,bottom);
|
||||
} else {
|
||||
value=MIN(absoluteTop,bottom+(rand()%(top-bottom+1)));
|
||||
}
|
||||
pat->data[j][0]=value%12;
|
||||
pat->data[j][1]=(value-60)/12;
|
||||
if (pat->data[j][0]==0) {
|
||||
pat->data[j][0]=12;
|
||||
pat->data[j][1]--;
|
||||
}
|
||||
pat->data[j][1]=(unsigned char)pat->data[j][1];
|
||||
if (mode) {
|
||||
value&=15;
|
||||
value2&=15;
|
||||
pat->newData[j][iFine]=value|(value2<<4);
|
||||
} else {
|
||||
pat->newData[j][iFine]=value;
|
||||
}
|
||||
if (eff && iFine>2 && (iFine&1)) {
|
||||
pat->newData[j][iFine]=effVal;
|
||||
}
|
||||
j=0;
|
||||
}
|
||||
j=0;
|
||||
}
|
||||
}
|
||||
iFine=0;
|
||||
|
|
@ -1678,7 +1615,7 @@ void FurnaceGUI::doFlip() {
|
|||
DivPattern* pat=e->curPat[iCoarse].getPattern(e->curOrders->ord[iCoarse][jOrder],true);
|
||||
for (; j<e->curSubSong->patLen && (j<=selEnd.y || jOrder<selEnd.order); j++) {
|
||||
PatBufferEntry put;
|
||||
memcpy(put.data,pat->data[j],DIV_MAX_COLS*sizeof(short));
|
||||
memcpy(put.data,pat->newData[j],DIV_MAX_COLS*sizeof(short));
|
||||
patBuffer.push_back(put);
|
||||
}
|
||||
j=0;
|
||||
|
|
@ -1697,10 +1634,7 @@ void FurnaceGUI::doFlip() {
|
|||
for (; j<e->curSubSong->patLen && (j<=selEnd.y || jOrder<selEnd.order); j++) {
|
||||
j_i--;
|
||||
touch(jOrder,j);
|
||||
if (iFine==0) {
|
||||
pat->data[j][0]=patBuffer[j_i].data[0];
|
||||
}
|
||||
pat->data[j][iFine+1]=patBuffer[j_i].data[iFine+1];
|
||||
pat->newData[j][iFine]=patBuffer[j_i].data[iFine];
|
||||
}
|
||||
j=0;
|
||||
}
|
||||
|
|
@ -1734,38 +1668,18 @@ void FurnaceGUI::doCollapse(int divider, const SelectionPoint& sStart, const Sel
|
|||
for (; iFine<3+e->curPat[iCoarse].effectCols*2 && (iCoarse<sEnd.xCoarse || iFine<=sEnd.xFine); iFine++) {
|
||||
maskOut(opMaskCollapseExpand,iFine);
|
||||
for (int j=sStart.y; j<=sEnd.y; j++) {
|
||||
if (iFine==0) {
|
||||
patBuffer.data[j][0]=pat->data[j][0];
|
||||
}
|
||||
patBuffer.data[j][iFine+1]=pat->data[j][iFine+1];
|
||||
patBuffer.newData[j][iFine]=pat->newData[j][iFine];
|
||||
}
|
||||
for (int j=0; j<=sEnd.y-sStart.y; j++) {
|
||||
if (j*divider>=sEnd.y-sStart.y) {
|
||||
if (iFine==0) {
|
||||
pat->data[j+sStart.y][0]=0;
|
||||
pat->data[j+sStart.y][1]=0;
|
||||
} else {
|
||||
pat->data[j+sStart.y][iFine+1]=-1;
|
||||
}
|
||||
pat->newData[j+sStart.y][iFine]=-1;
|
||||
} else {
|
||||
if (iFine==0) {
|
||||
pat->data[j+sStart.y][0]=patBuffer.data[j*divider+sStart.y][0];
|
||||
}
|
||||
pat->data[j+sStart.y][iFine+1]=patBuffer.data[j*divider+sStart.y][iFine+1];
|
||||
pat->newData[j+sStart.y][iFine+1]=patBuffer.newData[j*divider+sStart.y][iFine];
|
||||
|
||||
if (iFine==0) {
|
||||
for (int k=1; k<divider; k++) {
|
||||
if ((j*divider+k)>=sEnd.y-sStart.y) break;
|
||||
if (!(pat->data[j+sStart.y][0]==0 && pat->data[j+sStart.y][1]==0)) break;
|
||||
pat->data[j+sStart.y][0]=patBuffer.data[j*divider+sStart.y+k][0];
|
||||
pat->data[j+sStart.y][1]=patBuffer.data[j*divider+sStart.y+k][1];
|
||||
}
|
||||
} else {
|
||||
for (int k=1; k<divider; k++) {
|
||||
if ((j*divider+k)>=sEnd.y-sStart.y) break;
|
||||
if (pat->data[j+sStart.y][iFine+1]!=-1) break;
|
||||
pat->data[j+sStart.y][iFine+1]=patBuffer.data[j*divider+sStart.y+k][iFine+1];
|
||||
}
|
||||
for (int k=1; k<divider; k++) {
|
||||
if ((j*divider+k)>=sEnd.y-sStart.y) break;
|
||||
if (pat->newData[j+sStart.y][iFine]!=-1) break;
|
||||
pat->newData[j+sStart.y][iFine]=patBuffer.newData[j*divider+sStart.y+k][iFine];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1795,26 +1709,15 @@ void FurnaceGUI::doExpand(int multiplier, const SelectionPoint& sStart, const Se
|
|||
for (; iFine<3+e->curPat[iCoarse].effectCols*2 && (iCoarse<sEnd.xCoarse || iFine<=sEnd.xFine); iFine++) {
|
||||
maskOut(opMaskCollapseExpand,iFine);
|
||||
for (int j=sStart.y; j<=sEnd.y; j++) {
|
||||
if (iFine==0) {
|
||||
patBuffer.data[j][0]=pat->data[j][0];
|
||||
}
|
||||
patBuffer.data[j][iFine+1]=pat->data[j][iFine+1];
|
||||
patBuffer.newData[j][iFine]=pat->newData[j][iFine];
|
||||
}
|
||||
for (int j=0; j<=(sEnd.y-sStart.y)*multiplier; j++) {
|
||||
if ((j+sStart.y)>=e->curSubSong->patLen) break;
|
||||
if ((j%multiplier)!=0) {
|
||||
if (iFine==0) {
|
||||
pat->data[j+sStart.y][0]=0;
|
||||
pat->data[j+sStart.y][1]=0;
|
||||
} else {
|
||||
pat->data[j+sStart.y][iFine+1]=-1;
|
||||
}
|
||||
pat->newData[j+sStart.y][iFine]=-1;
|
||||
continue;
|
||||
}
|
||||
if (iFine==0) {
|
||||
pat->data[j+sStart.y][0]=patBuffer.data[j/multiplier+sStart.y][0];
|
||||
}
|
||||
pat->data[j+sStart.y][iFine+1]=patBuffer.data[j/multiplier+sStart.y][iFine+1];
|
||||
pat->newData[j+sStart.y][iFine]=patBuffer.newData[j/multiplier+sStart.y][iFine];
|
||||
}
|
||||
}
|
||||
iFine=0;
|
||||
|
|
@ -1846,24 +1749,17 @@ void FurnaceGUI::doCollapseSong(int divider) {
|
|||
pat->clear();
|
||||
for (int k=0; k<DIV_MAX_ROWS; k++) {
|
||||
for (int l=0; l<DIV_MAX_COLS; l++) {
|
||||
if (l==0) {
|
||||
if (!(pat->data[k/divider][0]==0 && pat->data[k/divider][1]==0)) continue;
|
||||
} else {
|
||||
if (pat->data[k/divider][l+1]!=-1) continue;
|
||||
}
|
||||
if (pat->newData[k/divider][l]!=-1) continue;
|
||||
|
||||
if (l==0) {
|
||||
pat->data[k/divider][l]=patCopy.data[k][l];
|
||||
}
|
||||
pat->data[k/divider][l+1]=patCopy.data[k][l+1];
|
||||
pat->newData[k/divider][l]=patCopy.newData[k][l];
|
||||
|
||||
if (l>3 && !(l&1)) { // scale effects as needed
|
||||
switch (pat->data[k/divider][l]) {
|
||||
if (DIV_PAT_IS_EFFECT(l)) { // scale effects as needed
|
||||
switch (pat->newData[k/divider][l]) {
|
||||
case 0x0d:
|
||||
pat->data[k/divider][l+1]/=divider;
|
||||
pat->newData[k/divider][l+1]/=divider;
|
||||
break;
|
||||
case 0x0f:
|
||||
pat->data[k/divider][l+1]=CLAMP(pat->data[k/divider][l+1]*divider,1,255);
|
||||
pat->newData[k/divider][l+1]=CLAMP(pat->newData[k/divider][l+1]*divider,1,255);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -1873,8 +1769,8 @@ void FurnaceGUI::doCollapseSong(int divider) {
|
|||
// put undo
|
||||
for (int k=0; k<DIV_MAX_ROWS; k++) {
|
||||
for (int l=0; l<DIV_MAX_COLS; l++) {
|
||||
if (pat->data[k][l]!=patCopy.data[k][l]) {
|
||||
us.pat.push_back(UndoPatternData(subSong,i,j,k,l,patCopy.data[k][l],pat->data[k][l]));
|
||||
if (pat->newData[k][l]!=patCopy.newData[k][l]) {
|
||||
us.pat.push_back(UndoPatternData(subSong,i,j,k,l,patCopy.newData[k][l],pat->newData[k][l]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1929,24 +1825,17 @@ void FurnaceGUI::doExpandSong(int multiplier) {
|
|||
pat->clear();
|
||||
for (int k=0; k<(256/multiplier); k++) {
|
||||
for (int l=0; l<DIV_MAX_COLS; l++) {
|
||||
if (l==0) {
|
||||
if (!(pat->data[k*multiplier][0]==0 && pat->data[k*multiplier][1]==0)) continue;
|
||||
} else {
|
||||
if (pat->data[k*multiplier][l+1]!=-1) continue;
|
||||
}
|
||||
if (pat->newData[k*multiplier][l]!=-1) continue;
|
||||
|
||||
if (l==0) {
|
||||
pat->data[k*multiplier][l]=patCopy.data[k][l];
|
||||
}
|
||||
pat->data[k*multiplier][l+1]=patCopy.data[k][l+1];
|
||||
pat->newData[k*multiplier][l]=patCopy.newData[k][l];
|
||||
|
||||
if (l>3 && !(l&1)) { // scale effects as needed
|
||||
switch (pat->data[k*multiplier][l]) {
|
||||
if (DIV_PAT_IS_EFFECT(l)) { // scale effects as needed
|
||||
switch (pat->newData[k*multiplier][l]) {
|
||||
case 0x0d:
|
||||
pat->data[k*multiplier][l+1]/=multiplier;
|
||||
pat->newData[k*multiplier][l+1]/=multiplier;
|
||||
break;
|
||||
case 0x0f:
|
||||
pat->data[k*multiplier][l+1]=CLAMP(pat->data[k*multiplier][l+1]/multiplier,1,255);
|
||||
pat->newData[k*multiplier][l+1]=CLAMP(pat->newData[k*multiplier][l+1]/multiplier,1,255);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -1956,8 +1845,8 @@ void FurnaceGUI::doExpandSong(int multiplier) {
|
|||
// put undo
|
||||
for (int k=0; k<DIV_MAX_ROWS; k++) {
|
||||
for (int l=0; l<DIV_MAX_COLS; l++) {
|
||||
if (pat->data[k][l]!=patCopy.data[k][l]) {
|
||||
us.pat.push_back(UndoPatternData(subSong,i,j,k,l,patCopy.data[k][l],pat->data[k][l]));
|
||||
if (pat->newData[k][l]!=patCopy.newData[k][l]) {
|
||||
us.pat.push_back(UndoPatternData(subSong,i,j,k,l,patCopy.newData[k][l],pat->newData[k][l]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2006,28 +1895,23 @@ void FurnaceGUI::doAbsorbInstrument() {
|
|||
for (int i=searchStartRow; i>=0 && !foundAll(); i--) {
|
||||
|
||||
// absorb most recent instrument
|
||||
if (!foundIns && pat->data[i][2] >= 0) {
|
||||
if (!foundIns && pat->newData[i][DIV_PAT_INS] >= 0) {
|
||||
foundIns=true;
|
||||
curIns=pat->data[i][2];
|
||||
curIns=pat->newData[i][DIV_PAT_INS];
|
||||
}
|
||||
|
||||
// absorb most recent octave (i.e. set curOctave such that the "main row" (QWERTY) of
|
||||
// notes will result in an octave number equal to the previous note). make sure to
|
||||
// skip "special note values" like OFF/REL/=== and "none", since there won't be valid
|
||||
// octave values
|
||||
unsigned char note=pat->data[i][0];
|
||||
if (!foundOctave && note!=0 && note!=100 && note!=101 && note!=102) {
|
||||
short note=pat->newData[i][DIV_PAT_NOTE];
|
||||
if (!foundOctave && note!=-1 && note!=DIV_NOTE_OFF && note!=DIV_NOTE_REL && note!=DIV_MACRO_REL) {
|
||||
foundOctave=true;
|
||||
|
||||
// decode octave data (was signed cast to unsigned char)
|
||||
int octave=pat->data[i][1];
|
||||
if (octave>128) octave-=256;
|
||||
// decode octave data
|
||||
int octave=(pat->newData[i][DIV_PAT_NOTE]-60)/12;
|
||||
|
||||
// @NOTE the special handling when note==12, which is really an octave above what's
|
||||
// stored in the octave data. without this handling, if you press Q, then
|
||||
// "ABSORB_INSTRUMENT", then Q again, you'd get a different octave!
|
||||
if (pat->data[i][0]==12) octave++;
|
||||
curOctave=CLAMP(octave-1, GUI_EDIT_OCTAVE_MIN, GUI_EDIT_OCTAVE_MAX);
|
||||
curOctave=CLAMP(octave-1,GUI_EDIT_OCTAVE_MIN,GUI_EDIT_OCTAVE_MAX);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2221,7 +2105,7 @@ void FurnaceGUI::doUndo() {
|
|||
for (UndoPatternData& i: us.pat) {
|
||||
e->changeSongP(i.subSong);
|
||||
DivPattern* p=e->curPat[i.chan].getPattern(i.pat,true);
|
||||
p->data[i.row][i.col]=i.oldVal;
|
||||
p->newData[i.row][i.col]=i.oldVal;
|
||||
}
|
||||
if (us.type!=GUI_UNDO_REPLACE) {
|
||||
if (!e->isPlaying() || !followPattern) {
|
||||
|
|
@ -2299,7 +2183,7 @@ void FurnaceGUI::doRedo() {
|
|||
for (UndoPatternData& i: us.pat) {
|
||||
e->changeSongP(i.subSong);
|
||||
DivPattern* p=e->curPat[i.chan].getPattern(i.pat,true);
|
||||
p->data[i.row][i.col]=i.newVal;
|
||||
p->newData[i.row][i.col]=i.newVal;
|
||||
}
|
||||
if (us.type!=GUI_UNDO_REPLACE) {
|
||||
if (!e->isPlaying() || !followPattern) {
|
||||
|
|
|
|||
|
|
@ -43,25 +43,6 @@ const char* queryReplaceModes[GUI_QUERY_REPLACE_MAX]={
|
|||
_N("clear")
|
||||
};
|
||||
|
||||
int queryNote(int note, int octave) {
|
||||
if (note==100) {
|
||||
return 128;
|
||||
} else if (note==101) { // note off and envelope release
|
||||
return 129;
|
||||
} else if (note==102) { // envelope release only
|
||||
return 130;
|
||||
} else if (octave==0 && note==0) {
|
||||
return -61;
|
||||
} else if (note==0 && octave!=0) {
|
||||
return -61; // bug note?
|
||||
}
|
||||
int seek=(note+(signed char)octave*12);
|
||||
if (seek<-60 || seek>=120) {
|
||||
return -61; // out of range note
|
||||
}
|
||||
return seek;
|
||||
}
|
||||
|
||||
bool checkCondition(int mode, int arg, int argMax, int val, bool noteMode=false) {
|
||||
const int emptyVal=noteMode?-61:-1;
|
||||
switch (mode) {
|
||||
|
|
@ -137,9 +118,9 @@ void FurnaceGUI::doFind() {
|
|||
for (FurnaceGUIFindQuery& l: curQuery) {
|
||||
if (matched) break;
|
||||
|
||||
if (!checkCondition(l.noteMode,l.note,l.noteMax,queryNote(p->data[j][0],p->data[j][1]),true)) continue;
|
||||
if (!checkCondition(l.insMode,l.ins,l.insMax,p->data[j][2])) continue;
|
||||
if (!checkCondition(l.volMode,l.vol,l.volMax,p->data[j][3])) continue;
|
||||
if (!checkCondition(l.noteMode,l.note,l.noteMax,p->newData[j][DIV_PAT_NOTE],true)) continue;
|
||||
if (!checkCondition(l.insMode,l.ins,l.insMax,p->newData[j][DIV_PAT_INS])) continue;
|
||||
if (!checkCondition(l.volMode,l.vol,l.volMax,p->newData[j][DIV_PAT_VOL])) continue;
|
||||
|
||||
if (l.effectCount>0) {
|
||||
bool notMatched=false;
|
||||
|
|
@ -148,8 +129,8 @@ void FurnaceGUI::doFind() {
|
|||
for (int m=0; m<l.effectCount; m++) {
|
||||
bool allGood=false;
|
||||
for (int n=0; n<e->curPat[k].effectCols; n++) {
|
||||
if (!checkCondition(l.effectMode[m],l.effect[m],l.effectMax[m],p->data[j][4+n*2])) continue;
|
||||
if (!checkCondition(l.effectValMode[m],l.effectVal[m],l.effectValMax[m],p->data[j][5+n*2])) continue;
|
||||
if (!checkCondition(l.effectMode[m],l.effect[m],l.effectMax[m],p->newData[j][DIV_PAT_FX(n)])) continue;
|
||||
if (!checkCondition(l.effectValMode[m],l.effectVal[m],l.effectValMax[m],p->newData[j][DIV_PAT_FXVAL(n)])) continue;
|
||||
allGood=true;
|
||||
effectPos[m]=n;
|
||||
break;
|
||||
|
|
@ -164,8 +145,8 @@ void FurnaceGUI::doFind() {
|
|||
// locate first effect
|
||||
int posOfFirst=-1;
|
||||
for (int m=0; m<e->curPat[k].effectCols; m++) {
|
||||
if (!checkCondition(l.effectMode[0],l.effect[0],l.effectMax[0],p->data[j][4+m*2])) continue;
|
||||
if (!checkCondition(l.effectValMode[0],l.effectVal[0],l.effectValMax[0],p->data[j][5+m*2])) continue;
|
||||
if (!checkCondition(l.effectMode[0],l.effect[0],l.effectMax[0],p->newData[j][DIV_PAT_FX(m)])) continue;
|
||||
if (!checkCondition(l.effectValMode[0],l.effectVal[0],l.effectValMax[0],p->newData[j][DIV_PAT_FXVAL(m)])) continue;
|
||||
posOfFirst=m;
|
||||
break;
|
||||
}
|
||||
|
|
@ -180,11 +161,11 @@ void FurnaceGUI::doFind() {
|
|||
}
|
||||
// search from first effect location
|
||||
for (int m=0; m<l.effectCount; m++) {
|
||||
if (!checkCondition(l.effectMode[m],l.effect[m],l.effectMax[m],p->data[j][4+(m+posOfFirst)*2])) {
|
||||
if (!checkCondition(l.effectMode[m],l.effect[m],l.effectMax[m],p->newData[j][DIV_PAT_FX(m+posOfFirst)])) {
|
||||
notMatched=true;
|
||||
break;
|
||||
}
|
||||
if (!checkCondition(l.effectValMode[m],l.effectVal[m],l.effectValMax[m],p->data[j][5+(m+posOfFirst)*2])) {
|
||||
if (!checkCondition(l.effectValMode[m],l.effectVal[m],l.effectValMax[m],p->newData[j][DIV_PAT_FXVAL(m+posOfFirst)])) {
|
||||
notMatched=true;
|
||||
break;
|
||||
}
|
||||
|
|
@ -198,11 +179,11 @@ void FurnaceGUI::doFind() {
|
|||
notMatched=true;
|
||||
} else {
|
||||
for (int m=0; m<effectMax; m++) {
|
||||
if (!checkCondition(l.effectMode[m],l.effect[m],l.effectMax[m],p->data[j][4+m*2])) {
|
||||
if (!checkCondition(l.effectMode[m],l.effect[m],l.effectMax[m],p->newData[j][DIV_PAT_FX(m)])) {
|
||||
notMatched=true;
|
||||
break;
|
||||
}
|
||||
if (!checkCondition(l.effectValMode[m],l.effectVal[m],l.effectValMax[m],p->data[j][5+m*2])) {
|
||||
if (!checkCondition(l.effectValMode[m],l.effectVal[m],l.effectValMax[m],p->newData[j][DIV_PAT_FXVAL(m)])) {
|
||||
notMatched=true;
|
||||
break;
|
||||
}
|
||||
|
|
@ -248,131 +229,107 @@ void FurnaceGUI::doReplace() {
|
|||
if (touched[i.x][(patIndex<<8)|i.y]) continue;
|
||||
touched[i.x][(patIndex<<8)|i.y]=true;
|
||||
|
||||
memcpy(prevVal,p->data[i.y],DIV_MAX_COLS*sizeof(short));
|
||||
memcpy(prevVal,p->newData[i.y],DIV_MAX_COLS*sizeof(short));
|
||||
|
||||
// replace note
|
||||
if (queryReplaceNoteDo) {
|
||||
switch (queryReplaceNoteMode) {
|
||||
case GUI_QUERY_REPLACE_SET:
|
||||
if (queryReplaceNote==130) { // macro release
|
||||
p->data[i.y][0]=102;
|
||||
p->data[i.y][1]=0;
|
||||
} else if (queryReplaceNote==129) { // note release
|
||||
p->data[i.y][0]=101;
|
||||
p->data[i.y][1]=0;
|
||||
} else if (queryReplaceNote==128) { // note off
|
||||
p->data[i.y][0]=100;
|
||||
p->data[i.y][1]=0;
|
||||
} else if (queryReplaceNote>=-60 && queryReplaceNote<120) { // note
|
||||
p->data[i.y][0]=(queryReplaceNote+60)%12;
|
||||
if (p->data[i.y][0]==0) p->data[i.y][0]=12;
|
||||
p->data[i.y][1]=(unsigned char)((queryReplaceNote-1)/12);
|
||||
} else { // invalid
|
||||
p->data[i.y][0]=0;
|
||||
p->data[i.y][1]=0;
|
||||
}
|
||||
p->newData[i.y][DIV_PAT_NOTE]=queryReplaceNote;
|
||||
break;
|
||||
case GUI_QUERY_REPLACE_ADD:
|
||||
if (p->data[i.y][0]<100) {
|
||||
int note=queryNote(p->data[i.y][0],p->data[i.y][1]);
|
||||
if (note>=-60 && note<120) {
|
||||
note+=queryReplaceNote;
|
||||
if (note<-60) note=-60;
|
||||
if (note>119) note=119;
|
||||
case GUI_QUERY_REPLACE_ADD: {
|
||||
int note=p->newData[i.y][DIV_PAT_NOTE];
|
||||
if (note>=0 && note<180) {
|
||||
note+=queryReplaceNote;
|
||||
if (note<0) note=0;
|
||||
if (note>179) note=179;
|
||||
|
||||
p->data[i.y][0]=(note+60)%12;
|
||||
p->data[i.y][1]=(unsigned char)(((note+60)/12)-5);
|
||||
if (p->data[i.y][0]==0) {
|
||||
p->data[i.y][0]=12;
|
||||
p->data[i.y][1]=(unsigned char)(p->data[i.y][1]-1);
|
||||
}
|
||||
}
|
||||
p->newData[i.y][DIV_PAT_NOTE]=note;
|
||||
}
|
||||
break;
|
||||
case GUI_QUERY_REPLACE_ADD_OVERFLOW:
|
||||
if (p->data[i.y][0]<100) {
|
||||
int note=queryNote(p->data[i.y][0],p->data[i.y][1]);
|
||||
if (note>=-60 && note<120) {
|
||||
}
|
||||
case GUI_QUERY_REPLACE_ADD_OVERFLOW: {
|
||||
int note=p->newData[i.y][DIV_PAT_NOTE];
|
||||
if (note>=0 && note<180) {
|
||||
note+=queryReplaceNote;
|
||||
if (note<-60) {
|
||||
while (note<-60) note+=180;
|
||||
} else if (note>119) {
|
||||
while (note>119) note-=180;
|
||||
if (note<0) {
|
||||
while (note<0) note+=180;
|
||||
} else if (note>179) {
|
||||
while (note>179) note-=180;
|
||||
}
|
||||
|
||||
p->data[i.y][0]=(note+60)%12;
|
||||
p->data[i.y][1]=(unsigned char)(((note+60)/12)-5);
|
||||
if (p->data[i.y][0]==0) {
|
||||
p->data[i.y][0]=12;
|
||||
p->data[i.y][1]=(unsigned char)(p->data[i.y][1]-1);
|
||||
}
|
||||
p->newData[i.y][DIV_PAT_NOTE]=note;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case GUI_QUERY_REPLACE_SCALE:
|
||||
break;
|
||||
case GUI_QUERY_REPLACE_CLEAR:
|
||||
p->data[i.y][0]=0;
|
||||
p->data[i.y][1]=0;
|
||||
p->newData[i.y][DIV_PAT_NOTE]=-1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// replace ins
|
||||
if (queryReplaceInsDo) {
|
||||
switch (queryReplaceInsMode) {
|
||||
case GUI_QUERY_REPLACE_SET:
|
||||
p->data[i.y][2]=queryReplaceIns;
|
||||
p->newData[i.y][DIV_PAT_INS]=queryReplaceIns;
|
||||
break;
|
||||
case GUI_QUERY_REPLACE_ADD:
|
||||
if (p->data[i.y][2]>=0) {
|
||||
p->data[i.y][2]+=queryReplaceIns;
|
||||
if (p->data[i.y][2]<0) p->data[i.y][2]=0;
|
||||
if (p->data[i.y][2]>255) p->data[i.y][2]=255;
|
||||
if (p->newData[i.y][DIV_PAT_INS]>=0) {
|
||||
p->newData[i.y][DIV_PAT_INS]+=queryReplaceIns;
|
||||
if (p->newData[i.y][DIV_PAT_INS]<0) p->newData[i.y][DIV_PAT_INS]=0;
|
||||
if (p->newData[i.y][DIV_PAT_INS]>255) p->newData[i.y][DIV_PAT_INS]=255;
|
||||
}
|
||||
break;
|
||||
case GUI_QUERY_REPLACE_ADD_OVERFLOW:
|
||||
if (p->data[i.y][2]>=0) p->data[i.y][2]=(p->data[i.y][2]+queryReplaceIns)&0xff;
|
||||
if (p->newData[i.y][DIV_PAT_INS]>=0) p->newData[i.y][DIV_PAT_INS]=(p->newData[i.y][DIV_PAT_INS]+queryReplaceIns)&0xff;
|
||||
break;
|
||||
case GUI_QUERY_REPLACE_SCALE:
|
||||
if (p->data[i.y][2]>=0) {
|
||||
p->data[i.y][2]=(p->data[i.y][2]*queryReplaceIns)/100;
|
||||
if (p->data[i.y][2]<0) p->data[i.y][2]=0;
|
||||
if (p->data[i.y][2]>255) p->data[i.y][2]=255;
|
||||
if (p->newData[i.y][DIV_PAT_INS]>=0) {
|
||||
p->newData[i.y][DIV_PAT_INS]=(p->newData[i.y][DIV_PAT_INS]*queryReplaceIns)/100;
|
||||
if (p->newData[i.y][DIV_PAT_INS]<0) p->newData[i.y][DIV_PAT_INS]=0;
|
||||
if (p->newData[i.y][DIV_PAT_INS]>255) p->newData[i.y][DIV_PAT_INS]=255;
|
||||
}
|
||||
break;
|
||||
case GUI_QUERY_REPLACE_CLEAR:
|
||||
p->data[i.y][2]=-1;
|
||||
p->newData[i.y][DIV_PAT_INS]=-1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// replace vol
|
||||
if (queryReplaceVolDo) {
|
||||
switch (queryReplaceVolMode) {
|
||||
case GUI_QUERY_REPLACE_SET:
|
||||
p->data[i.y][3]=queryReplaceVol;
|
||||
p->newData[i.y][DIV_PAT_VOL]=queryReplaceVol;
|
||||
break;
|
||||
case GUI_QUERY_REPLACE_ADD:
|
||||
if (p->data[i.y][3]>=0) {
|
||||
p->data[i.y][3]+=queryReplaceVol;
|
||||
if (p->data[i.y][3]<0) p->data[i.y][3]=0;
|
||||
if (p->data[i.y][3]>255) p->data[i.y][3]=255;
|
||||
if (p->newData[i.y][DIV_PAT_VOL]>=0) {
|
||||
p->newData[i.y][DIV_PAT_VOL]+=queryReplaceVol;
|
||||
if (p->newData[i.y][DIV_PAT_VOL]<0) p->newData[i.y][DIV_PAT_VOL]=0;
|
||||
if (p->newData[i.y][DIV_PAT_VOL]>255) p->newData[i.y][DIV_PAT_VOL]=255;
|
||||
}
|
||||
break;
|
||||
case GUI_QUERY_REPLACE_ADD_OVERFLOW:
|
||||
if (p->data[i.y][3]>=0) p->data[i.y][3]=(p->data[i.y][3]+queryReplaceVol)&0xff;
|
||||
if (p->newData[i.y][DIV_PAT_VOL]>=0) p->newData[i.y][DIV_PAT_VOL]=(p->newData[i.y][DIV_PAT_VOL]+queryReplaceVol)&0xff;
|
||||
break;
|
||||
case GUI_QUERY_REPLACE_SCALE:
|
||||
if (p->data[i.y][3]>=0) {
|
||||
p->data[i.y][3]=(p->data[i.y][3]*queryReplaceVol)/100;
|
||||
if (p->data[i.y][3]<0) p->data[i.y][3]=0;
|
||||
if (p->data[i.y][3]>255) p->data[i.y][3]=255;
|
||||
if (p->newData[i.y][DIV_PAT_VOL]>=0) {
|
||||
p->newData[i.y][DIV_PAT_VOL]=(p->newData[i.y][DIV_PAT_VOL]*queryReplaceVol)/100;
|
||||
if (p->newData[i.y][DIV_PAT_VOL]<0) p->newData[i.y][DIV_PAT_VOL]=0;
|
||||
if (p->newData[i.y][DIV_PAT_VOL]>255) p->newData[i.y][DIV_PAT_VOL]=255;
|
||||
}
|
||||
break;
|
||||
case GUI_QUERY_REPLACE_CLEAR:
|
||||
p->data[i.y][3]=-1;
|
||||
p->newData[i.y][DIV_PAT_VOL]=-1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// effect replacement is a bit more complicated
|
||||
// first we consider effect replacement position
|
||||
signed char effectOrder[8];
|
||||
memset(effectOrder,-1,8);
|
||||
|
||||
|
|
@ -388,7 +345,7 @@ void FurnaceGUI::doReplace() {
|
|||
effectOrder[placementIndex++]=i.effectPos[j];
|
||||
}
|
||||
for (int j=0; j<e->song.subsong[i.subsong]->pat[i.x].effectCols && placementIndex<8 && j<8; j++) {
|
||||
if (p->data[i.y][4+j*2]!=-1 || p->data[i.y][5+j*2]!=-1) {
|
||||
if (p->newData[i.y][DIV_PAT_FX(j)]!=-1 || p->newData[i.y][DIV_PAT_FXVAL(j)]!=-1) {
|
||||
effectOrder[placementIndex++]=j;
|
||||
}
|
||||
}
|
||||
|
|
@ -400,12 +357,12 @@ void FurnaceGUI::doReplace() {
|
|||
effectOrder[placementIndex++]=i.effectPos[j];
|
||||
}
|
||||
for (int j=0; j<e->song.subsong[i.subsong]->pat[i.x].effectCols && placementIndex<8 && j<8; j++) {
|
||||
if (p->data[i.y][4+j*2]!=-1 || p->data[i.y][5+j*2]!=-1) {
|
||||
if (p->newData[i.y][DIV_PAT_FX(j)]!=-1 || p->newData[i.y][DIV_PAT_FXVAL(j)]!=-1) {
|
||||
effectOrder[placementIndex++]=j;
|
||||
}
|
||||
}
|
||||
for (int j=0; j<e->song.subsong[i.subsong]->pat[i.x].effectCols; j++) {
|
||||
if (p->data[i.y][4+j*2]==-1 && p->data[i.y][5+j*2]==-1) {
|
||||
if (p->newData[i.y][DIV_PAT_FX(j)]==-1 && p->newData[i.y][DIV_PAT_FXVAL(j)]==-1) {
|
||||
effectOrder[placementIndex++]=j;
|
||||
}
|
||||
}
|
||||
|
|
@ -414,7 +371,7 @@ void FurnaceGUI::doReplace() {
|
|||
case 3: { // insert in free spaces
|
||||
int placementIndex=0;
|
||||
for (int j=0; j<e->song.subsong[i.subsong]->pat[i.x].effectCols && j<8; j++) {
|
||||
if (p->data[i.y][4+j*2]==-1 && p->data[i.y][5+j*2]==-1) {
|
||||
if (p->newData[i.y][DIV_PAT_FX(j)]==-1 && p->newData[i.y][DIV_PAT_FXVAL(j)]==-1) {
|
||||
effectOrder[placementIndex++]=j;
|
||||
}
|
||||
}
|
||||
|
|
@ -422,61 +379,66 @@ void FurnaceGUI::doReplace() {
|
|||
}
|
||||
}
|
||||
|
||||
// then we replace effects/values
|
||||
for (int j=0; j<queryReplaceEffectCount && j<8; j++) {
|
||||
signed char pos=effectOrder[j];
|
||||
// don't replace if we cannot find a position
|
||||
if (pos==-1) continue;
|
||||
|
||||
// replace effect
|
||||
if (queryReplaceEffectDo[j]) {
|
||||
switch (queryReplaceEffectMode[j]) {
|
||||
case GUI_QUERY_REPLACE_SET:
|
||||
p->data[i.y][4+pos*2]=queryReplaceEffect[j];
|
||||
p->newData[i.y][DIV_PAT_FX(pos)]=queryReplaceEffect[j];
|
||||
break;
|
||||
case GUI_QUERY_REPLACE_ADD:
|
||||
if (p->data[i.y][4+pos*2]>=0) {
|
||||
p->data[i.y][4+pos*2]+=queryReplaceEffect[j];
|
||||
if (p->data[i.y][4+pos*2]<0) p->data[i.y][4+pos*2]=0;
|
||||
if (p->data[i.y][4+pos*2]>255) p->data[i.y][4+pos*2]=255;
|
||||
if (p->newData[i.y][DIV_PAT_FX(pos)]>=0) {
|
||||
p->newData[i.y][DIV_PAT_FX(pos)]+=queryReplaceEffect[j];
|
||||
if (p->newData[i.y][DIV_PAT_FX(pos)]<0) p->newData[i.y][DIV_PAT_FX(pos)]=0;
|
||||
if (p->newData[i.y][DIV_PAT_FX(pos)]>255) p->newData[i.y][DIV_PAT_FX(pos)]=255;
|
||||
}
|
||||
break;
|
||||
case GUI_QUERY_REPLACE_ADD_OVERFLOW:
|
||||
if (p->data[i.y][4+pos*2]>=0) p->data[i.y][4+pos*2]=(p->data[i.y][4+pos*2]+queryReplaceEffect[j])&0xff;
|
||||
if (p->newData[i.y][DIV_PAT_FX(pos)]>=0) p->newData[i.y][DIV_PAT_FX(pos)]=(p->newData[i.y][DIV_PAT_FX(pos)]+queryReplaceEffect[j])&0xff;
|
||||
break;
|
||||
case GUI_QUERY_REPLACE_SCALE:
|
||||
if (p->data[i.y][4+pos*2]>=0) {
|
||||
p->data[i.y][4+pos*2]=(p->data[i.y][4+pos*2]*queryReplaceEffect[j])/100;
|
||||
if (p->data[i.y][4+pos*2]<0) p->data[i.y][4+pos*2]=0;
|
||||
if (p->data[i.y][4+pos*2]>255) p->data[i.y][4+pos*2]=255;
|
||||
if (p->newData[i.y][DIV_PAT_FX(pos)]>=0) {
|
||||
p->newData[i.y][DIV_PAT_FX(pos)]=(p->newData[i.y][DIV_PAT_FX(pos)]*queryReplaceEffect[j])/100;
|
||||
if (p->newData[i.y][DIV_PAT_FX(pos)]<0) p->newData[i.y][DIV_PAT_FX(pos)]=0;
|
||||
if (p->newData[i.y][DIV_PAT_FX(pos)]>255) p->newData[i.y][DIV_PAT_FX(pos)]=255;
|
||||
}
|
||||
break;
|
||||
case GUI_QUERY_REPLACE_CLEAR:
|
||||
p->data[i.y][4+pos*2]=-1;
|
||||
p->newData[i.y][DIV_PAT_FX(pos)]=-1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// replace effect value
|
||||
if (queryReplaceEffectValDo[j]) {
|
||||
switch (queryReplaceEffectValMode[j]) {
|
||||
case GUI_QUERY_REPLACE_SET:
|
||||
p->data[i.y][5+pos*2]=queryReplaceEffectVal[j];
|
||||
p->newData[i.y][DIV_PAT_FXVAL(pos)]=queryReplaceEffectVal[j];
|
||||
break;
|
||||
case GUI_QUERY_REPLACE_ADD:
|
||||
if (p->data[i.y][5+pos*2]>=0) {
|
||||
p->data[i.y][5+pos*2]+=queryReplaceEffectVal[j];
|
||||
if (p->data[i.y][5+pos*2]<0) p->data[i.y][5+pos*2]=0;
|
||||
if (p->data[i.y][5+pos*2]>255) p->data[i.y][5+pos*2]=255;
|
||||
if (p->newData[i.y][DIV_PAT_FXVAL(pos)]>=0) {
|
||||
p->newData[i.y][DIV_PAT_FXVAL(pos)]+=queryReplaceEffectVal[j];
|
||||
if (p->newData[i.y][DIV_PAT_FXVAL(pos)]<0) p->newData[i.y][DIV_PAT_FXVAL(pos)]=0;
|
||||
if (p->newData[i.y][DIV_PAT_FXVAL(pos)]>255) p->newData[i.y][DIV_PAT_FXVAL(pos)]=255;
|
||||
}
|
||||
break;
|
||||
case GUI_QUERY_REPLACE_ADD_OVERFLOW:
|
||||
if (p->data[i.y][5+pos*2]>=0) p->data[i.y][5+pos*2]=(p->data[i.y][5+pos*2]+queryReplaceEffectVal[j])&0xff;
|
||||
if (p->newData[i.y][DIV_PAT_FXVAL(pos)]>=0) p->newData[i.y][DIV_PAT_FXVAL(pos)]=(p->newData[i.y][DIV_PAT_FXVAL(pos)]+queryReplaceEffectVal[j])&0xff;
|
||||
break;
|
||||
case GUI_QUERY_REPLACE_SCALE:
|
||||
if (p->data[i.y][5+pos*2]>=0) {
|
||||
p->data[i.y][5+pos*2]=(p->data[i.y][5+pos*2]*queryReplaceEffectVal[j])/100;
|
||||
if (p->data[i.y][5+pos*2]<0) p->data[i.y][5+pos*2]=0;
|
||||
if (p->data[i.y][5+pos*2]>255) p->data[i.y][5+pos*2]=255;
|
||||
if (p->newData[i.y][DIV_PAT_FXVAL(pos)]>=0) {
|
||||
p->newData[i.y][DIV_PAT_FXVAL(pos)]=(p->newData[i.y][DIV_PAT_FXVAL(pos)]*queryReplaceEffectVal[j])/100;
|
||||
if (p->newData[i.y][DIV_PAT_FXVAL(pos)]<0) p->newData[i.y][DIV_PAT_FXVAL(pos)]=0;
|
||||
if (p->newData[i.y][DIV_PAT_FXVAL(pos)]>255) p->newData[i.y][DIV_PAT_FXVAL(pos)]=255;
|
||||
}
|
||||
break;
|
||||
case GUI_QUERY_REPLACE_CLEAR:
|
||||
p->data[i.y][5+pos*2]=-1;
|
||||
p->newData[i.y][DIV_PAT_FXVAL(pos)]=-1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -484,8 +446,8 @@ void FurnaceGUI::doReplace() {
|
|||
|
||||
// issue undo step
|
||||
for (int j=0; j<DIV_MAX_COLS; j++) {
|
||||
if (p->data[i.y][j]!=prevVal[j]) {
|
||||
us.pat.push_back(UndoPatternData(i.subsong,i.x,patIndex,i.y,j,prevVal[j],p->data[i.y][j]));
|
||||
if (p->newData[i.y][j]!=prevVal[j]) {
|
||||
us.pat.push_back(UndoPatternData(i.subsong,i.x,patIndex,i.y,j,prevVal[j],p->newData[i.y][j]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -615,15 +577,15 @@ void FurnaceGUI::drawFindReplace() {
|
|||
ImGui::Combo("##NCondition",&i.noteMode,LocalizedComboGetter,queryModes,GUI_QUERY_MAX);
|
||||
ImGui::TableNextColumn();
|
||||
if (FIRST_VISIBLE(i.noteMode)) {
|
||||
if ((i.noteMode==GUI_QUERY_RANGE || i.noteMode==GUI_QUERY_RANGE_NOT) && i.note>=120) {
|
||||
i.note=0;
|
||||
if ((i.noteMode==GUI_QUERY_RANGE || i.noteMode==GUI_QUERY_RANGE_NOT) && i.note>=180) {
|
||||
i.note=108;
|
||||
}
|
||||
NoteSelector(&i.note, i.noteMode!=GUI_QUERY_RANGE && i.noteMode!=GUI_QUERY_RANGE_NOT);
|
||||
}
|
||||
ImGui::TableNextColumn();
|
||||
if (SECOND_VISIBLE(i.noteMode)) {
|
||||
if (i.noteMax<-60 || i.noteMax>=120) {
|
||||
i.noteMax=0;
|
||||
if (i.noteMax<0 || i.noteMax>=256) {
|
||||
i.noteMax=108;
|
||||
}
|
||||
NoteSelector(&i.noteMax, false);
|
||||
}
|
||||
|
|
|
|||
215
src/gui/gui.cpp
215
src/gui/gui.cpp
|
|
@ -97,66 +97,54 @@ void FurnaceGUI::enableSafeMode() {
|
|||
safeMode=true;
|
||||
}
|
||||
|
||||
const char* FurnaceGUI::noteName(short note, short octave) {
|
||||
if (note==100) {
|
||||
const char* FurnaceGUI::noteName(short note) {
|
||||
if (note==DIV_NOTE_OFF) {
|
||||
return noteOffLabel;
|
||||
} else if (note==101) { // note off and envelope release
|
||||
} else if (note==DIV_NOTE_REL) { // note off and envelope release
|
||||
return noteRelLabel;
|
||||
} else if (note==102) { // envelope release only
|
||||
} else if (note==DIV_MACRO_REL) { // envelope release only
|
||||
return macroRelLabel;
|
||||
} else if (octave==0 && note==0) {
|
||||
} else if (note==-1) {
|
||||
return emptyLabel;
|
||||
} else if (note==0 && octave!=0) {
|
||||
} else if (note==DIV_NOTE_NULL_PAT) {
|
||||
return "BUG";
|
||||
}
|
||||
int seek=(note+(signed char)octave*12)+60;
|
||||
if (seek<0 || seek>=180) {
|
||||
if (note<0 || note>=180) {
|
||||
return "???";
|
||||
}
|
||||
if (settings.flatNotes) {
|
||||
if (settings.germanNotation) return noteNamesGF[seek];
|
||||
return noteNamesF[seek];
|
||||
if (settings.germanNotation) return noteNamesGF[note];
|
||||
return noteNamesF[note];
|
||||
}
|
||||
if (settings.germanNotation) return noteNamesG[seek];
|
||||
return noteNames[seek];
|
||||
if (settings.germanNotation) return noteNamesG[note];
|
||||
return noteNames[note];
|
||||
}
|
||||
|
||||
bool FurnaceGUI::decodeNote(const char* what, short& note, short& octave) {
|
||||
bool FurnaceGUI::decodeNote(const char* what, short& note) {
|
||||
if (strlen(what)!=3) return false;
|
||||
if (strcmp(what,"...")==0) {
|
||||
note=0;
|
||||
octave=0;
|
||||
note=-1;
|
||||
return true;
|
||||
}
|
||||
if (strcmp(what,"???")==0) {
|
||||
note=0;
|
||||
octave=0;
|
||||
note=DIV_NOTE_NULL_PAT;
|
||||
return true;
|
||||
}
|
||||
if (strcmp(what,"OFF")==0) {
|
||||
note=100;
|
||||
octave=0;
|
||||
note=DIV_NOTE_OFF;
|
||||
return true;
|
||||
}
|
||||
if (strcmp(what,"===")==0) {
|
||||
note=101;
|
||||
octave=0;
|
||||
note=DIV_NOTE_REL;
|
||||
return true;
|
||||
}
|
||||
if (strcmp(what,"REL")==0) {
|
||||
note=102;
|
||||
octave=0;
|
||||
note=DIV_MACRO_REL;
|
||||
return true;
|
||||
}
|
||||
for (int i=0; i<180; i++) {
|
||||
if (strcmp(what,noteNames[i])==0) {
|
||||
if ((i%12)==0) {
|
||||
note=12;
|
||||
octave=(unsigned char)((i/12)-6);
|
||||
} else {
|
||||
note=i%12;
|
||||
octave=(unsigned char)((i/12)-5);
|
||||
}
|
||||
note=i;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -573,53 +561,53 @@ bool FurnaceGUI::InvCheckbox(const char* label, bool* value) {
|
|||
bool FurnaceGUI::NoteSelector(int* value, bool showOffRel, int octaveMin, int octaveMax) {
|
||||
bool ret=false, calcNote=false;
|
||||
char tempID[64];
|
||||
if (*value==130) {
|
||||
if (*value==DIV_MACRO_REL) {
|
||||
snprintf(tempID,64,"%s##MREL",macroRelLabel);
|
||||
} else if (*value==129) {
|
||||
} else if (*value==DIV_NOTE_REL) {
|
||||
snprintf(tempID,64,"%s##NREL",noteRelLabel);
|
||||
} else if (*value==128) {
|
||||
} else if (*value==DIV_NOTE_OFF) {
|
||||
snprintf(tempID,64,"%s##NOFF",noteOffLabel);
|
||||
} else if (*value>=-60 && *value<120) {
|
||||
snprintf(tempID,64,"%c%c",noteNames[*value%12+72][0],(noteNames[*value%12+72][1]=='-')?' ':noteNames[*value%12+72][1]);
|
||||
} else if (*value>=0 && *value<180) {
|
||||
snprintf(tempID,64,"%c%c",noteNames[60+(*value%12)][0],(noteNames[60+(*value%12)][1]=='-')?' ':noteNames[60+(*value%12)][1]);
|
||||
} else {
|
||||
snprintf(tempID,64,"???");
|
||||
*value=0;
|
||||
}
|
||||
float width=ImGui::GetContentRegionAvail().x/2-ImGui::GetStyle().FramePadding.x;
|
||||
ImGui::SetNextItemWidth(width);
|
||||
int note=(*value+60)%12;
|
||||
int oct=0;
|
||||
if (*value<120) oct=(*value-note)/12;
|
||||
int note=(*value)%12;
|
||||
int oct=-5;
|
||||
if (*value<180) oct=(*value-note-60)/12;
|
||||
ImGui::BeginGroup();
|
||||
ImGui::PushID(value);
|
||||
if (ImGui::BeginCombo("##NoteSelectorNote",tempID)) {
|
||||
for (int j=0; j<12; j++) {
|
||||
snprintf(tempID,64,"%c%c",noteNames[j+72][0],(noteNames[j+72][1]=='-')?' ':noteNames[j+72][1]);
|
||||
if (ImGui::Selectable(tempID,note==j && *value<128)) {
|
||||
snprintf(tempID,64,"%c%c",noteNames[60+j][0],(noteNames[60+j][1]=='-')?' ':noteNames[60+j][1]);
|
||||
if (ImGui::Selectable(tempID,note==j && *value<180)) {
|
||||
note=j;
|
||||
calcNote=true;
|
||||
}
|
||||
if (note==j && *value<120) ImGui::SetItemDefaultFocus();
|
||||
if (note==j && *value<180) ImGui::SetItemDefaultFocus();
|
||||
}
|
||||
if (showOffRel) {
|
||||
if (ImGui::Selectable(noteOffLabel,*value==128)) {
|
||||
*value=128;
|
||||
if (ImGui::Selectable(noteOffLabel,*value==DIV_NOTE_OFF)) {
|
||||
*value=DIV_NOTE_OFF;
|
||||
ret=true;
|
||||
}
|
||||
if (ImGui::Selectable(noteRelLabel,*value==129)) {
|
||||
*value=129;
|
||||
if (ImGui::Selectable(noteRelLabel,*value==DIV_NOTE_REL)) {
|
||||
*value=DIV_NOTE_REL;
|
||||
ret=true;
|
||||
}
|
||||
if (ImGui::Selectable(macroRelLabel,*value==130)) {
|
||||
*value=130;
|
||||
if (ImGui::Selectable(macroRelLabel,*value==DIV_MACRO_REL)) {
|
||||
*value=DIV_MACRO_REL;
|
||||
ret=true;
|
||||
}
|
||||
if (*value>=128 && *value<=130) ImGui::SetItemDefaultFocus();
|
||||
if (*value>=DIV_NOTE_OFF && *value<=DIV_MACRO_REL) ImGui::SetItemDefaultFocus();
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (*value<120) {
|
||||
if (*value<180) {
|
||||
ImGui::SetNextItemWidth(width/2);
|
||||
if (ImGui::InputScalar("##NoteSelectorOctave",ImGuiDataType_S32,&oct)) {
|
||||
if (oct<octaveMin) oct=octaveMin;
|
||||
|
|
@ -628,7 +616,7 @@ bool FurnaceGUI::NoteSelector(int* value, bool showOffRel, int octaveMin, int oc
|
|||
}
|
||||
}
|
||||
if (calcNote) {
|
||||
*value=oct*12+note;
|
||||
*value=(oct+5)*12+note;
|
||||
ret=true;
|
||||
}
|
||||
ImGui::PopID();
|
||||
|
|
@ -1395,48 +1383,39 @@ void FurnaceGUI::noteInput(int num, int key, int vol) {
|
|||
prepareUndo(GUI_UNDO_PATTERN_EDIT);
|
||||
|
||||
if (key==GUI_NOTE_OFF) { // note off
|
||||
pat->data[y][0]=100;
|
||||
pat->data[y][1]=0;
|
||||
pat->newData[y][DIV_PAT_NOTE]=DIV_NOTE_OFF;
|
||||
removeIns=true;
|
||||
} else if (key==GUI_NOTE_OFF_RELEASE) { // note off + env release
|
||||
pat->data[y][0]=101;
|
||||
pat->data[y][1]=0;
|
||||
pat->newData[y][DIV_PAT_NOTE]=DIV_NOTE_REL;
|
||||
removeIns=true;
|
||||
} else if (key==GUI_NOTE_RELEASE) { // env release only
|
||||
pat->data[y][0]=102;
|
||||
pat->data[y][1]=0;
|
||||
pat->newData[y][DIV_PAT_NOTE]=DIV_MACRO_REL;
|
||||
removeIns=true;
|
||||
} else {
|
||||
pat->data[y][0]=num%12;
|
||||
pat->data[y][1]=num/12;
|
||||
if (pat->data[y][0]==0) {
|
||||
pat->data[y][0]=12;
|
||||
pat->data[y][1]--;
|
||||
}
|
||||
pat->data[y][1]=(unsigned char)pat->data[y][1];
|
||||
pat->newData[y][DIV_PAT_NOTE]=num+60;
|
||||
if (latchIns==-2) {
|
||||
if (curIns>=(int)e->song.ins.size()) curIns=-1;
|
||||
if (curIns>=0) {
|
||||
pat->data[y][2]=curIns;
|
||||
pat->newData[y][DIV_PAT_INS]=curIns;
|
||||
}
|
||||
} else if (latchIns!=-1 && !e->song.ins.empty()) {
|
||||
pat->data[y][2]=MIN(((int)e->song.ins.size())-1,latchIns);
|
||||
pat->newData[y][DIV_PAT_INS]=MIN(((int)e->song.ins.size())-1,latchIns);
|
||||
}
|
||||
int maxVol=e->getMaxVolumeChan(ch);
|
||||
if (latchVol!=-1) {
|
||||
pat->data[y][3]=MIN(maxVol,latchVol);
|
||||
pat->newData[y][DIV_PAT_VOL]=MIN(maxVol,latchVol);
|
||||
} else if (vol!=-1) {
|
||||
pat->data[y][3]=e->mapVelocity(ch,pow((float)vol/127.0f,midiMap.volExp));
|
||||
pat->newData[y][DIV_PAT_VOL]=e->mapVelocity(ch,pow((float)vol/127.0f,midiMap.volExp));
|
||||
}
|
||||
if (latchEffect!=-1) pat->data[y][4]=latchEffect;
|
||||
if (latchEffectVal!=-1) pat->data[y][5]=latchEffectVal;
|
||||
if (latchEffect!=-1) pat->newData[y][DIV_PAT_FX(0)]=latchEffect;
|
||||
if (latchEffectVal!=-1) pat->newData[y][DIV_PAT_FXVAL(0)]=latchEffectVal;
|
||||
}
|
||||
if (removeIns) {
|
||||
if (settings.removeInsOff) {
|
||||
pat->data[y][2]=-1;
|
||||
pat->newData[y][DIV_PAT_INS]=-1;
|
||||
}
|
||||
if (settings.removeVolOff) {
|
||||
pat->data[y][3]=-1;
|
||||
pat->newData[y][DIV_PAT_VOL]=-1;
|
||||
}
|
||||
}
|
||||
editAdvance();
|
||||
|
|
@ -1455,26 +1434,27 @@ void FurnaceGUI::valueInput(int num, bool direct, int target) {
|
|||
|
||||
DivPattern* pat=e->curPat[ch].getPattern(e->curOrders->ord[ch][ord],true);
|
||||
prepareUndo(GUI_UNDO_PATTERN_EDIT);
|
||||
if (target==-1) target=cursor.xFine+1;
|
||||
if (target==-1) target=cursor.xFine;
|
||||
if (direct) {
|
||||
pat->data[y][target]=num&0xff;
|
||||
pat->newData[y][target]=num&0xff;
|
||||
} else {
|
||||
if (pat->data[y][target]==-1) pat->data[y][target]=0;
|
||||
if (pat->newData[y][target]==-1) pat->newData[y][target]=0;
|
||||
if (!settings.pushNibble && !curNibble) {
|
||||
pat->data[y][target]=num;
|
||||
pat->newData[y][target]=num;
|
||||
} else {
|
||||
pat->data[y][target]=((pat->data[y][target]<<4)|num)&0xff;
|
||||
pat->newData[y][target]=((pat->newData[y][target]<<4)|num)&0xff;
|
||||
}
|
||||
}
|
||||
if (cursor.xFine==1) { // instrument
|
||||
if (pat->data[y][target]>=(int)e->song.ins.size()) {
|
||||
pat->data[y][target]&=0x0f;
|
||||
if (pat->data[y][target]>=(int)e->song.ins.size()) {
|
||||
pat->data[y][target]=(int)e->song.ins.size()-1;
|
||||
// TODO: shouldn't this be target?
|
||||
if (cursor.xFine==DIV_PAT_INS) { // instrument
|
||||
if (pat->newData[y][target]>=(int)e->song.ins.size()) {
|
||||
pat->newData[y][target]&=0x0f;
|
||||
if (pat->newData[y][target]>=(int)e->song.ins.size()) {
|
||||
pat->newData[y][target]=(int)e->song.ins.size()-1;
|
||||
}
|
||||
}
|
||||
if (settings.absorbInsInput) {
|
||||
curIns=pat->data[y][target];
|
||||
curIns=pat->newData[y][target];
|
||||
wavePreviewInit=true;
|
||||
updateFMPreview=true;
|
||||
}
|
||||
|
|
@ -1490,18 +1470,18 @@ void FurnaceGUI::valueInput(int num, bool direct, int target) {
|
|||
}
|
||||
}
|
||||
makeUndo(GUI_UNDO_PATTERN_EDIT);
|
||||
} else if (cursor.xFine==2) {
|
||||
} else if (cursor.xFine==DIV_PAT_VOL) {
|
||||
if (curNibble) {
|
||||
if (pat->data[y][target]>e->getMaxVolumeChan(ch)) pat->data[y][target]=e->getMaxVolumeChan(ch);
|
||||
if (pat->newData[y][target]>e->getMaxVolumeChan(ch)) pat->newData[y][target]=e->getMaxVolumeChan(ch);
|
||||
} else {
|
||||
pat->data[y][target]&=15;
|
||||
pat->newData[y][target]&=15;
|
||||
}
|
||||
if (direct) {
|
||||
curNibble=false;
|
||||
} else {
|
||||
if (e->getMaxVolumeChan(ch)<16) {
|
||||
curNibble=false;
|
||||
if (pat->data[y][target]>e->getMaxVolumeChan(ch)) pat->data[y][target]=e->getMaxVolumeChan(ch);
|
||||
if (pat->newData[y][target]>e->getMaxVolumeChan(ch)) pat->newData[y][target]=e->getMaxVolumeChan(ch);
|
||||
editAdvance();
|
||||
} else {
|
||||
curNibble=!curNibble;
|
||||
|
|
@ -2380,7 +2360,6 @@ void FurnaceGUI::openFileDialog(FurnaceGUIFileDialogs type) {
|
|||
break;
|
||||
}
|
||||
if (hasOpened) curFileDialog=type;
|
||||
//ImGui::GetIO().ConfigFlags|=ImGuiConfigFlags_NavEnableKeyboard;
|
||||
}
|
||||
|
||||
int FurnaceGUI::save(String path, int dmfVersion) {
|
||||
|
|
@ -2390,7 +2369,7 @@ int FurnaceGUI::save(String path, int dmfVersion) {
|
|||
if (dmfVersion<24) dmfVersion=24;
|
||||
w=e->saveDMF(dmfVersion);
|
||||
} else {
|
||||
w=e->saveFur(false,settings.newPatternFormat);
|
||||
w=e->saveFur(false);
|
||||
}
|
||||
if (w==NULL) {
|
||||
lastError=e->getLastError();
|
||||
|
|
@ -3197,10 +3176,10 @@ void FurnaceGUI::editOptions(bool topMenu) {
|
|||
ImGui::SameLine();
|
||||
if (ImGui::Button(_("Set"))) {
|
||||
DivPattern* pat=e->curPat[cursor.xCoarse].getPattern(e->curOrders->ord[cursor.xCoarse][curOrder],true);
|
||||
latchIns=pat->data[cursor.y][2];
|
||||
latchVol=pat->data[cursor.y][3];
|
||||
latchEffect=pat->data[cursor.y][4];
|
||||
latchEffectVal=pat->data[cursor.y][5];
|
||||
latchIns=pat->newData[cursor.y][DIV_PAT_INS];
|
||||
latchVol=pat->newData[cursor.y][DIV_PAT_VOL];
|
||||
latchEffect=pat->newData[cursor.y][DIV_PAT_FX(0)];
|
||||
latchEffectVal=pat->newData[cursor.y][DIV_PAT_FXVAL(0)];
|
||||
latchTarget=0;
|
||||
latchNibble=false;
|
||||
}
|
||||
|
|
@ -4915,46 +4894,50 @@ bool FurnaceGUI::loop() {
|
|||
DivPattern* p=e->curPat[cursor.xCoarse].getPattern(e->curOrders->ord[cursor.xCoarse][curOrder],false);
|
||||
if (cursor.xFine>=0) switch (cursor.xFine) {
|
||||
case 0: // note
|
||||
if (p->data[cursor.y][0]>0) {
|
||||
if (p->data[cursor.y][0]==100) {
|
||||
if (p->newData[cursor.y][DIV_PAT_NOTE]>=0) {
|
||||
if (p->newData[cursor.y][DIV_PAT_NOTE]==DIV_NOTE_OFF) {
|
||||
info=fmt::sprintf(_("Note off (cut)"));
|
||||
} else if (p->data[cursor.y][0]==101) {
|
||||
} else if (p->newData[cursor.y][DIV_PAT_NOTE]==DIV_NOTE_REL) {
|
||||
info=fmt::sprintf(_("Note off (release)"));
|
||||
} else if (p->data[cursor.y][0]==102) {
|
||||
} else if (p->newData[cursor.y][DIV_PAT_NOTE]==DIV_MACRO_REL) {
|
||||
info=fmt::sprintf(_("Macro release only"));
|
||||
} else {
|
||||
info=fmt::sprintf(_("Note on: %s"),noteName(p->data[cursor.y][0],p->data[cursor.y][1]));
|
||||
info=fmt::sprintf(_("Note on: %s"),noteName(p->newData[cursor.y][DIV_PAT_NOTE]));
|
||||
}
|
||||
hasInfo=true;
|
||||
}
|
||||
break;
|
||||
case 1: // instrument
|
||||
if (p->data[cursor.y][2]>-1) {
|
||||
if (p->data[cursor.y][2]>=(int)e->song.ins.size()) {
|
||||
info=fmt::sprintf(_("Ins %d: <invalid>"),p->data[cursor.y][2]);
|
||||
if (p->newData[cursor.y][DIV_PAT_INS]>-1) {
|
||||
if (p->newData[cursor.y][DIV_PAT_INS]>=(int)e->song.ins.size()) {
|
||||
info=fmt::sprintf(_("Ins %d: <invalid>"),p->newData[cursor.y][DIV_PAT_INS]);
|
||||
} else {
|
||||
DivInstrument* ins=e->getIns(p->data[cursor.y][2]);
|
||||
info=fmt::sprintf(_("Ins %d: %s"),p->data[cursor.y][2],ins->name);
|
||||
DivInstrument* ins=e->getIns(p->newData[cursor.y][DIV_PAT_INS]);
|
||||
info=fmt::sprintf(_("Ins %d: %s"),p->newData[cursor.y][DIV_PAT_INS],ins->name);
|
||||
}
|
||||
hasInfo=true;
|
||||
}
|
||||
break;
|
||||
case 2: // volume
|
||||
if (p->data[cursor.y][3]>-1) {
|
||||
if (p->newData[cursor.y][DIV_PAT_VOL]>-1) {
|
||||
int maxVol=e->getMaxVolumeChan(cursor.xCoarse);
|
||||
if (maxVol<1 || p->data[cursor.y][3]>maxVol) {
|
||||
info=fmt::sprintf(_("Set volume: %d (%.2X, INVALID!)"),p->data[cursor.y][3],p->data[cursor.y][3]);
|
||||
if (maxVol<1 || p->newData[cursor.y][DIV_PAT_VOL]>maxVol) {
|
||||
info=fmt::sprintf(_("Set volume: %d (%.2X, INVALID!)"),p->newData[cursor.y][DIV_PAT_VOL],p->newData[cursor.y][DIV_PAT_VOL]);
|
||||
} else {
|
||||
float realVol=e->getGain(cursor.xCoarse,p->data[cursor.y][3]);
|
||||
info=fmt::sprintf(_("Set volume: %d (%.2X, %d%%)"),p->data[cursor.y][3],p->data[cursor.y][3],(int)(realVol*100.0f));
|
||||
float realVol=e->getGain(cursor.xCoarse,p->newData[cursor.y][DIV_PAT_VOL]);
|
||||
info=fmt::sprintf(_("Set volume: %d (%.2X, %d%%)"),p->newData[cursor.y][DIV_PAT_VOL],p->newData[cursor.y][DIV_PAT_VOL],(int)(realVol*100.0f));
|
||||
}
|
||||
hasInfo=true;
|
||||
}
|
||||
break;
|
||||
default: // effect
|
||||
int actualCursor=((cursor.xFine+1)&(~1));
|
||||
if (p->data[cursor.y][actualCursor]>-1) {
|
||||
info=e->getEffectDesc(p->data[cursor.y][actualCursor],cursor.xCoarse,true);
|
||||
if (cursor.xFine<DIV_MAX_COLS) {
|
||||
if (p->newData[cursor.y][cursor.xFine]>-1) {
|
||||
info=e->getEffectDesc(p->newData[cursor.y][cursor.xFine],cursor.xCoarse,true);
|
||||
hasInfo=true;
|
||||
}
|
||||
} else {
|
||||
info=_("Error!");
|
||||
hasInfo=true;
|
||||
}
|
||||
break;
|
||||
|
|
@ -6536,11 +6519,7 @@ bool FurnaceGUI::loop() {
|
|||
e->lockEngine([this]() {
|
||||
for (int i=0; i<e->getTotalChannelCount(); i++) {
|
||||
DivPattern* pat=e->curPat[i].getPattern(e->curOrders->ord[i][curOrder],true);
|
||||
memset(pat->data,-1,DIV_MAX_ROWS*DIV_MAX_COLS*sizeof(short));
|
||||
for (int j=0; j<DIV_MAX_ROWS; j++) {
|
||||
pat->data[j][0]=0;
|
||||
pat->data[j][1]=0;
|
||||
}
|
||||
memset(pat->newData,-1,DIV_MAX_ROWS*DIV_MAX_COLS*sizeof(short));
|
||||
}
|
||||
});
|
||||
MARK_MODIFIED;
|
||||
|
|
@ -7307,7 +7286,7 @@ bool FurnaceGUI::loop() {
|
|||
}
|
||||
}
|
||||
logD("saving backup...");
|
||||
SafeWriter* w=e->saveFur(true,true);
|
||||
SafeWriter* w=e->saveFur(true);
|
||||
logV("writing file...");
|
||||
|
||||
if (w!=NULL) {
|
||||
|
|
@ -7982,6 +7961,8 @@ bool FurnaceGUI::init() {
|
|||
prepareLayout();
|
||||
|
||||
ImGui::GetIO().ConfigFlags|=ImGuiConfigFlags_DockingEnable;
|
||||
//ImGui::GetIO().ConfigFlags|=ImGuiConfigFlags_NavEnableKeyboard;
|
||||
//ImGui::GetIO().ConfigFlags&=~ImGuiConfigFlags_NavCaptureKeyboard;
|
||||
toggleMobileUI(mobileUI,true);
|
||||
|
||||
firstFrame=true;
|
||||
|
|
@ -8840,7 +8821,7 @@ FurnaceGUI::FurnaceGUI():
|
|||
queryReplaceNoteMode(0),
|
||||
queryReplaceInsMode(0),
|
||||
queryReplaceVolMode(0),
|
||||
queryReplaceNote(0),
|
||||
queryReplaceNote(108),
|
||||
queryReplaceIns(0),
|
||||
queryReplaceVol(0),
|
||||
queryReplaceNoteDo(false),
|
||||
|
|
|
|||
|
|
@ -1467,8 +1467,8 @@ struct FurnaceGUIFindQuery {
|
|||
insMode(GUI_QUERY_IGNORE),
|
||||
volMode(GUI_QUERY_IGNORE),
|
||||
effectCount(0),
|
||||
note(0),
|
||||
noteMax(0),
|
||||
note(108),
|
||||
noteMax(108),
|
||||
ins(0),
|
||||
insMax(0),
|
||||
vol(0),
|
||||
|
|
@ -2002,7 +2002,6 @@ class FurnaceGUI {
|
|||
int iCannotWait;
|
||||
int orderButtonPos;
|
||||
int compress;
|
||||
int newPatternFormat;
|
||||
int renderClearPos;
|
||||
int insertBehavior;
|
||||
int pullDeleteRow;
|
||||
|
|
@ -2257,7 +2256,6 @@ class FurnaceGUI {
|
|||
iCannotWait(0),
|
||||
orderButtonPos(2),
|
||||
compress(1),
|
||||
newPatternFormat(1),
|
||||
renderClearPos(0),
|
||||
insertBehavior(1),
|
||||
pullDeleteRow(1),
|
||||
|
|
@ -3151,9 +3149,9 @@ class FurnaceGUI {
|
|||
void showWarning(String what, FurnaceGUIWarnings type);
|
||||
void showError(String what);
|
||||
String getLastError();
|
||||
const char* noteNameNormal(short note, short octave);
|
||||
const char* noteName(short note, short octave);
|
||||
bool decodeNote(const char* what, short& note, short& octave);
|
||||
const char* noteNameNormal(short note);
|
||||
const char* noteName(short note);
|
||||
bool decodeNote(const char* what, short& note);
|
||||
void bindEngine(DivEngine* eng);
|
||||
void enableSafeMode();
|
||||
void updateScroll(int amount);
|
||||
|
|
|
|||
|
|
@ -1952,7 +1952,7 @@ void FurnaceGUI::drawGBEnv(unsigned char vol, unsigned char len, unsigned char s
|
|||
ImGui::RenderFrame(rect.Min,rect.Max,ImGui::GetColorU32(ImGuiCol_FrameBg),true,style.FrameRounding);
|
||||
|
||||
float volY=1.0-((float)vol/15.0);
|
||||
float lenPos=(sLen>62)?1.0:((float)sLen/384.0);
|
||||
float lenPos=(sLen>63)?1.0:((float)sLen/384.0);
|
||||
float envEndPoint=((float)len/7.0)*((float)(dir?(15-vol):vol)/15.0);
|
||||
|
||||
ImVec2 pos1=ImLerp(rect.Min,rect.Max,ImVec2(0.0,volY));
|
||||
|
|
@ -1978,10 +1978,10 @@ void FurnaceGUI::drawGBEnv(unsigned char vol, unsigned char len, unsigned char s
|
|||
pos2=ImLerp(rect.Min,rect.Max,ImVec2(lenPos,volY));
|
||||
}
|
||||
}
|
||||
ImVec2 pos3=ImLerp(rect.Min,rect.Max,ImVec2(lenPos,(len>0 || sLen<63)?((dir && sLen>62)?0.0:1.0):volY));
|
||||
ImVec2 pos3=ImLerp(rect.Min,rect.Max,ImVec2(lenPos,(len>0 || sLen<64)?((dir && sLen>62)?0.0:1.0):volY));
|
||||
|
||||
addAALine(dl,pos1,pos2,color);
|
||||
if (lenPos>=envEndPoint && sLen<63 && dir) {
|
||||
if (lenPos>=envEndPoint && sLen<64 && dir) {
|
||||
pos3=ImLerp(rect.Min,rect.Max,ImVec2(lenPos,0.0));
|
||||
addAALine(dl,pos2,pos3,color);
|
||||
ImVec2 pos4=ImLerp(rect.Min,rect.Max,ImVec2(lenPos,1.0));
|
||||
|
|
@ -6447,7 +6447,7 @@ void FurnaceGUI::drawInsSID3(DivInstrument* ins) {
|
|||
"If this is disabled,filter cutoff will increase if you increase the pitch."));
|
||||
}
|
||||
|
||||
snprintf(buffer2,100,_("%s"),noteNameNormal(filt->bindCutoffToNoteCenter%12,(short)(filt->bindCutoffToNoteCenter / 12)-5));
|
||||
snprintf(buffer2,100,_("%s"),noteNameNormal(filt->bindCutoffToNoteCenter));
|
||||
snprintf(buffer,100,_("Cutoff change center note##bindcutcenternote%d"),i+1);
|
||||
P(CWSliderScalar(buffer,ImGuiDataType_U8,&filt->bindCutoffToNoteCenter,&_ZERO,&_ONE_HUNDRED_SEVENTY_NINE,buffer2)); rightClickable
|
||||
if (ImGui::IsItemHovered()) {
|
||||
|
|
@ -6480,7 +6480,7 @@ void FurnaceGUI::drawInsSID3(DivInstrument* ins) {
|
|||
"If this is disabled,filter resonance will increase if you increase the pitch."));
|
||||
}
|
||||
|
||||
snprintf(buffer2,100,_("%s"),noteNameNormal(filt->bindResonanceToNoteCenter%12,(short)(filt->bindResonanceToNoteCenter / 12)-5));
|
||||
snprintf(buffer2,100,_("%s"),noteNameNormal(filt->bindResonanceToNoteCenter));
|
||||
snprintf(buffer,100,_("Resonance change center note##bindrescenternote%d"),i+1);
|
||||
P(CWSliderScalar(buffer,ImGuiDataType_U8,&filt->bindResonanceToNoteCenter,&_ZERO,&_ONE_HUNDRED_SEVENTY_NINE,buffer2)); rightClickable
|
||||
if (ImGui::IsItemHovered()) {
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <imgui.h>
|
||||
#include <imgui_internal.h>
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#include <shlwapi.h>
|
||||
|
|
@ -977,7 +978,6 @@ void FurnaceFilePicker::drawFileList(ImVec2& tableSize, bool& acknowledged) {
|
|||
|
||||
// file list
|
||||
entryLock.lock();
|
||||
int index=0;
|
||||
listClipper.Begin(filteredEntries.size(),rowHeight);
|
||||
while (listClipper.Step()) {
|
||||
for (int _i=listClipper.DisplayStart; _i<listClipper.DisplayEnd; _i++) {
|
||||
|
|
@ -1003,7 +1003,7 @@ void FurnaceFilePicker::drawFileList(ImVec2& tableSize, bool& acknowledged) {
|
|||
// name
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::PushStyleColor(ImGuiCol_Text,ImGui::GetColorU32(style->color));
|
||||
ImGui::PushID(index++);
|
||||
ImGui::PushID(_i);
|
||||
if (ImGui::Selectable(style->icon.c_str(),i->isSelected,ImGuiSelectableFlags_AllowDoubleClick|ImGuiSelectableFlags_SpanAllColumns|ImGuiSelectableFlags_SpanAvailWidth)) {
|
||||
bool doNotAcknowledge=false;
|
||||
if ((ImGui::IsKeyDown(ImGuiKey_LeftShift) || ImGui::IsKeyDown(ImGuiKey_RightShift)) && multiSelect) {
|
||||
|
|
@ -1054,12 +1054,13 @@ void FurnaceFilePicker::drawFileList(ImVec2& tableSize, bool& acknowledged) {
|
|||
ImGui::PopID();
|
||||
ImGui::SameLine();
|
||||
|
||||
ImGui::TextUnformatted(i->name.c_str());
|
||||
// why? can't I just not format?
|
||||
ImGui::TextNoHashHide("%s",i->name.c_str());
|
||||
|
||||
// type
|
||||
if (displayType) {
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextUnformatted(i->ext.c_str());
|
||||
ImGui::TextNoHashHide("%s",i->ext.c_str());
|
||||
}
|
||||
|
||||
// size
|
||||
|
|
@ -1172,11 +1173,21 @@ void FurnaceFilePicker::drawBookmarks(ImVec2& tableSize, String& newDir) {
|
|||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::PushID(200000+index);
|
||||
if (ImGui::Selectable(iName.c_str(),iPath==path)) {
|
||||
if (ImGui::Selectable(iName.c_str(),iPath==path,ImGuiSelectableFlags_NoHashTextHide)) {
|
||||
newDir=iPath;
|
||||
}
|
||||
if (ImGui::BeginPopupContextItem("BookmarkOpts")) {
|
||||
if (ImGui::MenuItem(_("edit"))) {
|
||||
|
||||
size_t separator=i.find('\n');
|
||||
if (separator!=String::npos) {
|
||||
editingBookmark=index;
|
||||
newBookmarkName=i.substr(0,separator);
|
||||
newBookmarkPath=i.substr(separator+1);
|
||||
}
|
||||
}
|
||||
if (ImGui::MenuItem(_("remove"))) {
|
||||
|
||||
markedForRemoval=index;
|
||||
if (iPath==path) isPathBookmarked=false;
|
||||
}
|
||||
|
|
@ -1189,6 +1200,24 @@ void FurnaceFilePicker::drawBookmarks(ImVec2& tableSize, String& newDir) {
|
|||
}
|
||||
ImGui::EndTable();
|
||||
}
|
||||
|
||||
if (editingBookmark>=0 && editingBookmark<(int)bookmarks.size()) {
|
||||
ImGui::OpenPopup("BookmarkEdit");
|
||||
}
|
||||
if (ImGui::BeginPopup("BookmarkEdit",ImGuiWindowFlags_AlwaysAutoResize|ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoSavedSettings)) {
|
||||
ImGui::Text("Name:");
|
||||
ImGui::InputText("##BookEditText",&newBookmarkName);
|
||||
if (ImGui::Button("OK")) {
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
if (!ImGui::IsPopupOpen("BookmarkEdit")) {
|
||||
if (editingBookmark>=0 && editingBookmark<(int)bookmarks.size()) {
|
||||
bookmarks[editingBookmark]=newBookmarkName+"\n"+newBookmarkPath;
|
||||
}
|
||||
editingBookmark=-1;
|
||||
}
|
||||
}
|
||||
|
||||
bool FurnaceFilePicker::draw(ImGuiWindowFlags winFlags) {
|
||||
|
|
@ -1395,7 +1424,7 @@ bool FurnaceFilePicker::draw(ImGuiWindowFlags winFlags) {
|
|||
// create button
|
||||
ImGui::PushID(100000+pathLevel);
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button(nextButton.c_str())) {
|
||||
if (ImGui::ButtonEx(nextButton.c_str(),ImVec2(0,0),ImGuiButtonFlags_NoHashTextHide)) {
|
||||
newDir=pathAsOfNow;
|
||||
}
|
||||
pathLevel++;
|
||||
|
|
@ -1926,6 +1955,8 @@ FurnaceFilePicker::FurnaceFilePicker():
|
|||
isPathBookmarked(false),
|
||||
isSearch(false),
|
||||
scheduledSort(0),
|
||||
imguiFlags(0),
|
||||
editingBookmark(-1),
|
||||
curFilterType(0),
|
||||
lastScrollY(0.0f),
|
||||
enforceScrollY(0),
|
||||
|
|
|
|||
|
|
@ -114,7 +114,7 @@ class FurnaceFilePicker {
|
|||
bool multiSelect;
|
||||
bool confirmOverwrite, dirSelect, noClose, isModal, isEmbed, hasSizeConstraints;
|
||||
bool isPathBookmarked, isSearch;
|
||||
int scheduledSort, imguiFlags;
|
||||
int scheduledSort, imguiFlags, editingBookmark;
|
||||
size_t curFilterType;
|
||||
float lastScrollY;
|
||||
int enforceScrollY;
|
||||
|
|
|
|||
|
|
@ -201,8 +201,8 @@ inline void FurnaceGUI::patternRow(int i, bool isPlaying, float lineHeight, int
|
|||
bool cursorVol=(cursor.order==ord && cursor.y==i && cursor.xCoarse==j && cursor.xFine==2 && curWindowLast==GUI_WINDOW_PATTERN);
|
||||
|
||||
// note
|
||||
snprintf(id,63,"%.31s###PN_%d_%d",noteName(pat->data[i][0],pat->data[i][1]),i,j);
|
||||
if (pat->data[i][0]==0 && pat->data[i][1]==0) {
|
||||
snprintf(id,63,"%.31s###PN_%d_%d",noteName(pat->newData[i][DIV_PAT_NOTE]),i,j);
|
||||
if (pat->newData[i][DIV_PAT_NOTE]==-1) {
|
||||
ImGui::PushStyleColor(ImGuiCol_Text,inactiveColor);
|
||||
} else {
|
||||
ImGui::PushStyleColor(ImGuiCol_Text,activeColor);
|
||||
|
|
@ -234,21 +234,21 @@ inline void FurnaceGUI::patternRow(int i, bool isPlaying, float lineHeight, int
|
|||
// the following is only visible when the channel is not collapsed
|
||||
if (e->curSubSong->chanCollapse[j]<3) {
|
||||
// instrument
|
||||
if (pat->data[i][2]==-1) {
|
||||
if (pat->newData[i][DIV_PAT_INS]==-1) {
|
||||
ImGui::PushStyleColor(ImGuiCol_Text,inactiveColor);
|
||||
snprintf(id,63,"%.31s###PI_%d_%d",emptyLabel2,i,j);
|
||||
} else {
|
||||
if (pat->data[i][2]<0 || pat->data[i][2]>=e->song.insLen) {
|
||||
if (pat->newData[i][DIV_PAT_INS]<0 || pat->newData[i][DIV_PAT_INS]>=e->song.insLen) {
|
||||
ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PATTERN_INS_ERROR]);
|
||||
} else {
|
||||
DivInstrumentType t=e->song.ins[pat->data[i][2]]->type;
|
||||
DivInstrumentType t=e->song.ins[pat->newData[i][DIV_PAT_INS]]->type;
|
||||
if (t!=DIV_INS_AMIGA && t!=e->getPreferInsType(j)) {
|
||||
ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PATTERN_INS_WARN]);
|
||||
} else {
|
||||
ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PATTERN_INS]);
|
||||
}
|
||||
}
|
||||
snprintf(id,63,"%.2X###PI_%d_%d",pat->data[i][2],i,j);
|
||||
snprintf(id,63,"%.2X###PI_%d_%d",pat->newData[i][DIV_PAT_INS],i,j);
|
||||
}
|
||||
ImGui::SameLine(0.0f,0.0f);
|
||||
if (cursorIns) {
|
||||
|
|
@ -278,14 +278,14 @@ inline void FurnaceGUI::patternRow(int i, bool isPlaying, float lineHeight, int
|
|||
|
||||
if (e->curSubSong->chanCollapse[j]<2) {
|
||||
// volume
|
||||
if (pat->data[i][3]==-1) {
|
||||
if (pat->newData[i][DIV_PAT_VOL]==-1) {
|
||||
snprintf(id,63,"%.31s###PV_%d_%d",emptyLabel2,i,j);
|
||||
ImGui::PushStyleColor(ImGuiCol_Text,inactiveColor);
|
||||
} else {
|
||||
int volColor=(pat->data[i][3]*127)/chanVolMax;
|
||||
int volColor=(pat->newData[i][DIV_PAT_VOL]*127)/chanVolMax;
|
||||
if (volColor>127) volColor=127;
|
||||
if (volColor<0) volColor=0;
|
||||
snprintf(id,63,"%.2X###PV_%d_%d",pat->data[i][3],i,j);
|
||||
snprintf(id,63,"%.2X###PV_%d_%d",pat->newData[i][DIV_PAT_VOL],i,j);
|
||||
ImGui::PushStyleColor(ImGuiCol_Text,volColors[volColor]);
|
||||
}
|
||||
ImGui::SameLine(0.0f,0.0f);
|
||||
|
|
@ -317,26 +317,27 @@ inline void FurnaceGUI::patternRow(int i, bool isPlaying, float lineHeight, int
|
|||
if (e->curSubSong->chanCollapse[j]<1) {
|
||||
// effects
|
||||
for (int k=0; k<e->curPat[j].effectCols; k++) {
|
||||
int index=4+(k<<1);
|
||||
bool selectedEffect=selectedRow && (j32+index-1>=sel1XSum && j32+index-1<=sel2XSum);
|
||||
bool selectedEffectVal=selectedRow && (j32+index>=sel1XSum && j32+index<=sel2XSum);
|
||||
bool cursorEffect=(cursor.order==ord && cursor.y==i && cursor.xCoarse==j && cursor.xFine==index-1 && curWindowLast==GUI_WINDOW_PATTERN);
|
||||
bool cursorEffectVal=(cursor.order==ord && cursor.y==i && cursor.xCoarse==j && cursor.xFine==index && curWindowLast==GUI_WINDOW_PATTERN);
|
||||
int index=DIV_PAT_FX(k);
|
||||
int indexVal=DIV_PAT_FXVAL(k);
|
||||
bool selectedEffect=selectedRow && (j32+index>=sel1XSum && j32+index<=sel2XSum);
|
||||
bool selectedEffectVal=selectedRow && (j32+indexVal>=sel1XSum && j32+indexVal<=sel2XSum);
|
||||
bool cursorEffect=(cursor.order==ord && cursor.y==i && cursor.xCoarse==j && cursor.xFine==index && curWindowLast==GUI_WINDOW_PATTERN);
|
||||
bool cursorEffectVal=(cursor.order==ord && cursor.y==i && cursor.xCoarse==j && cursor.xFine==indexVal && curWindowLast==GUI_WINDOW_PATTERN);
|
||||
|
||||
// effect
|
||||
if (pat->data[i][index]==-1) {
|
||||
if (pat->newData[i][index]==-1) {
|
||||
snprintf(id,63,"%.31s###PE%d_%d_%d",emptyLabel2,k,i,j);
|
||||
ImGui::PushStyleColor(ImGuiCol_Text,inactiveColor);
|
||||
} else {
|
||||
if (pat->data[i][index]>0xff) {
|
||||
if (pat->newData[i][index]>0xff) {
|
||||
snprintf(id,63,"??###PE%d_%d_%d",k,i,j);
|
||||
ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PATTERN_EFFECT_INVALID]);
|
||||
} else if (pat->data[i][index]>=0x10 || settings.oneDigitEffects==0) {
|
||||
const unsigned char data=pat->data[i][index];
|
||||
} else if (pat->newData[i][index]>=0x10 || settings.oneDigitEffects==0) {
|
||||
const unsigned char data=pat->newData[i][index];
|
||||
snprintf(id,63,"%.2X###PE%d_%d_%d",data,k,i,j);
|
||||
ImGui::PushStyleColor(ImGuiCol_Text,uiColors[fxColors[data]]);
|
||||
} else {
|
||||
const unsigned char data=pat->data[i][index];
|
||||
const unsigned char data=pat->newData[i][index];
|
||||
snprintf(id,63," %.1X###PE%d_%d_%d",data,k,i,j);
|
||||
ImGui::PushStyleColor(ImGuiCol_Text,uiColors[fxColors[data]]);
|
||||
}
|
||||
|
|
@ -354,10 +355,10 @@ inline void FurnaceGUI::patternRow(int i, bool isPlaying, float lineHeight, int
|
|||
if (selectedEffect) ImGui::PopStyleColor();
|
||||
}
|
||||
if (ImGui::IsItemClicked()) {
|
||||
startSelection(j,index-1,i,ord);
|
||||
startSelection(j,index,i,ord);
|
||||
}
|
||||
if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem)) {
|
||||
updateSelection(j,index-1,i,ord);
|
||||
updateSelection(j,index,i,ord);
|
||||
}
|
||||
if (ImGui::IsItemActive() && CHECK_LONG_HOLD) {
|
||||
ImGui::InhibitInertialScroll();
|
||||
|
|
@ -366,10 +367,10 @@ inline void FurnaceGUI::patternRow(int i, bool isPlaying, float lineHeight, int
|
|||
}
|
||||
|
||||
// effect value
|
||||
if (pat->data[i][index+1]==-1) {
|
||||
if (pat->newData[i][indexVal]==-1) {
|
||||
snprintf(id,63,"%.31s###PF%d_%d_%d",emptyLabel2,k,i,j);
|
||||
} else {
|
||||
snprintf(id,63,"%.2X###PF%d_%d_%d",pat->data[i][index+1],k,i,j);
|
||||
snprintf(id,63,"%.2X###PF%d_%d_%d",pat->newData[i][indexVal],k,i,j);
|
||||
}
|
||||
ImGui::SameLine(0.0f,0.0f);
|
||||
if (cursorEffectVal) {
|
||||
|
|
@ -384,10 +385,10 @@ inline void FurnaceGUI::patternRow(int i, bool isPlaying, float lineHeight, int
|
|||
if (selectedEffectVal) ImGui::PopStyleColor();
|
||||
}
|
||||
if (ImGui::IsItemClicked()) {
|
||||
startSelection(j,index,i,ord);
|
||||
startSelection(j,indexVal,i,ord);
|
||||
}
|
||||
if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem)) {
|
||||
updateSelection(j,index,i,ord);
|
||||
updateSelection(j,indexVal,i,ord);
|
||||
}
|
||||
if (ImGui::IsItemActive() && CHECK_LONG_HOLD) {
|
||||
ImGui::InhibitInertialScroll();
|
||||
|
|
|
|||
|
|
@ -853,15 +853,6 @@ void FurnaceGUI::drawSettings() {
|
|||
settingsChanged=true;
|
||||
}
|
||||
|
||||
bool newPatternFormatB=settings.newPatternFormat;
|
||||
if (ImGui::Checkbox(_("Use new pattern format when saving"),&newPatternFormatB)) {
|
||||
settings.newPatternFormat=newPatternFormatB;
|
||||
settingsChanged=true;
|
||||
}
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip(_("use a packed format which saves space when saving songs.\ndisable if you need compatibility with older Furnace and/or tools\nwhich do not support this format."));
|
||||
}
|
||||
|
||||
bool noDMFCompatB=settings.noDMFCompat;
|
||||
if (ImGui::Checkbox(_("Don't apply compatibility flags when loading .dmf"),&noDMFCompatB)) {
|
||||
settings.noDMFCompat=noDMFCompatB;
|
||||
|
|
@ -4898,7 +4889,6 @@ void FurnaceGUI::readConfig(DivConfig& conf, FurnaceGUISettingGroups groups) {
|
|||
settings.noMaximizeWorkaround=conf.getInt("noMaximizeWorkaround",0);
|
||||
|
||||
settings.compress=conf.getInt("compress",1);
|
||||
settings.newPatternFormat=conf.getInt("newPatternFormat",1);
|
||||
settings.newSongBehavior=conf.getInt("newSongBehavior",0);
|
||||
settings.playOnLoad=conf.getInt("playOnLoad",0);
|
||||
settings.centerPopup=conf.getInt("centerPopup",1);
|
||||
|
|
@ -5368,7 +5358,6 @@ void FurnaceGUI::readConfig(DivConfig& conf, FurnaceGUISettingGroups groups) {
|
|||
clampSetting(settings.iCannotWait,0,1);
|
||||
clampSetting(settings.orderButtonPos,0,2);
|
||||
clampSetting(settings.compress,0,1);
|
||||
clampSetting(settings.newPatternFormat,0,1);
|
||||
clampSetting(settings.renderClearPos,0,1);
|
||||
clampSetting(settings.insertBehavior,0,1);
|
||||
clampSetting(settings.pullDeleteRow,0,1);
|
||||
|
|
@ -5500,7 +5489,6 @@ void FurnaceGUI::writeConfig(DivConfig& conf, FurnaceGUISettingGroups groups) {
|
|||
conf.set("noMaximizeWorkaround",settings.noMaximizeWorkaround);
|
||||
|
||||
conf.set("compress",settings.compress);
|
||||
conf.set("newPatternFormat",settings.newPatternFormat);
|
||||
conf.set("newSongBehavior",settings.newSongBehavior);
|
||||
conf.set("playOnLoad",settings.playOnLoad);
|
||||
conf.set("centerPopup",settings.centerPopup);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue