Merge branch 'master' into spectrum
This commit is contained in:
commit
8626937f89
2907 changed files with 1544042 additions and 23152 deletions
|
|
@ -118,9 +118,22 @@ const char* aboutLine[]={
|
|||
_N("zlib by Jean-loup Gailly"),
|
||||
_N("and Mark Adler"),
|
||||
_N("libsndfile by Erik de Castro Lopo"),
|
||||
#ifdef HAVE_OGG
|
||||
_N("libogg by Xiph.Org Foundation"),
|
||||
_N("libvorbis by Xiph.Org Foundation"),
|
||||
_N("FLAC library by Xiph.Org Foundation"),
|
||||
_N("libopus by Xiph.Org and contributors"),
|
||||
#endif
|
||||
#ifdef HAVE_MP3_EXPORT
|
||||
_N("libmpg123 by Michael Hipp, Thomas Orgis, Taihei Momma and contributors"),
|
||||
_N("LAME by Mike Cheng, Mark Taylor and The LAME Project"),
|
||||
#endif
|
||||
_N("Portable File Dialogs by Sam Hocevar"),
|
||||
_N("Native File Dialog by Frogtoss Games"),
|
||||
"PortAudio",
|
||||
#ifdef HAVE_ASIO
|
||||
_N("ASIO® by Steinberg Media Technologies"),
|
||||
#endif
|
||||
_N("Weak-JACK by x42"),
|
||||
_N("RtMidi by Gary P. Scavone"),
|
||||
_N("FFTW by Matteo Frigo and Steven G. Johnson"),
|
||||
|
|
@ -186,8 +199,13 @@ const char* aboutLine[]={
|
|||
"",
|
||||
_N("copyright © 2021-2025 tildearrow"),
|
||||
_N("(and contributors)."),
|
||||
#ifdef FURNACE_GPL3
|
||||
_N("licensed under GPLv3! see"),
|
||||
_N("LICENSE for more information."),
|
||||
#else
|
||||
_N("licensed under GPLv2+! see"),
|
||||
_N("LICENSE for more information."),
|
||||
#endif
|
||||
"",
|
||||
_N("help Furnace grow:"),
|
||||
"https://github.com/tildearrow/furnace",
|
||||
|
|
@ -203,6 +221,10 @@ const char* aboutLine[]={
|
|||
_N("the original program."),
|
||||
"",
|
||||
_N("it also comes with ABSOLUTELY NO WARRANTY."),
|
||||
#ifdef HAVE_ASIO
|
||||
"",
|
||||
_N("ASIO is a registered trademark of Steinberg Media Technologies GmbH."),
|
||||
#endif
|
||||
"",
|
||||
_N("thanks to all contributors/bug reporters!")
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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+60));
|
||||
break;
|
||||
}
|
||||
case 'l': {
|
||||
|
|
|
|||
|
|
@ -50,7 +50,6 @@ void FurnaceGUI::drawChannels() {
|
|||
ImGui::TableNextColumn();
|
||||
ImGui::Text(_("Osc"));
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text(_("Swap"));
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text(_("Name"));
|
||||
for (int i=0; i<e->getTotalChannelCount(); i++) {
|
||||
|
|
@ -79,14 +78,17 @@ void FurnaceGUI::drawChannels() {
|
|||
ImGui::Button(ICON_FA_ARROWS "##ChanDrag");
|
||||
ImGui::EndDragDropSource();
|
||||
} else if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip(_("%s #%d\n(drag to swap channels)"),e->getSystemName(e->sysOfChan[i]),e->dispatchChanOfChan[i]);
|
||||
ImGui::SetTooltip(_("%s #%d\n(drag to swap channels)\n(Shift-drag to copy channel contents)"),e->getSystemName(e->sysOfChan[i]),e->dispatchChanOfChan[i]);
|
||||
}
|
||||
if (ImGui::BeginDragDropTarget()) {
|
||||
const ImGuiPayload* dragItem=ImGui::AcceptDragDropPayload("FUR_CHAN");
|
||||
if (dragItem!=NULL) {
|
||||
if (dragItem->IsDataType("FUR_CHAN")) {
|
||||
if (chanToMove!=i && chanToMove>=0) {
|
||||
e->swapChannelsP(chanToMove,i);
|
||||
if (ImGui::IsKeyDown(ImGuiKey_LeftShift) || ImGui::IsKeyDown(ImGuiKey_RightShift))
|
||||
e->copyChannelP(chanToMove,i);
|
||||
else
|
||||
e->swapChannelsP(chanToMove,i);
|
||||
MARK_MODIFIED;
|
||||
}
|
||||
chanToMove=-1;
|
||||
|
|
|
|||
|
|
@ -302,26 +302,15 @@ void FurnaceGUI::drawCompatFlags() {
|
|||
if (ImGui::BeginTabItem(_("Pitch/Playback"))) {
|
||||
ImGui::Text(_("Pitch linearity:"));
|
||||
ImGui::Indent();
|
||||
if (ImGui::RadioButton(_("None"),e->song.linearPitch==0)) {
|
||||
if (ImGui::RadioButton(_("None"),!e->song.linearPitch)) {
|
||||
e->song.linearPitch=0;
|
||||
MARK_MODIFIED;
|
||||
}
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip(_("like ProTracker/FamiTracker"));
|
||||
}
|
||||
if (e->song.linearPitch==1) {
|
||||
pushWarningColor(true);
|
||||
if (ImGui::RadioButton(_("Partial (only 04xy/E5xx)"),e->song.linearPitch==1)) {
|
||||
e->song.linearPitch=1;
|
||||
MARK_MODIFIED;
|
||||
}
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip(_("like DefleMask\n\nthis pitch linearity mode is deprecated due to:\n- excessive complexity\n- lack of possible optimization\n\nit is recommended to change it now because I will remove this option in the future!"));
|
||||
}
|
||||
popWarningColor();
|
||||
}
|
||||
if (ImGui::RadioButton(_("Full"),e->song.linearPitch==2)) {
|
||||
e->song.linearPitch=2;
|
||||
if (ImGui::RadioButton(_("Full"),e->song.linearPitch)) {
|
||||
e->song.linearPitch=1;
|
||||
MARK_MODIFIED;
|
||||
}
|
||||
if (ImGui::IsItemHovered()) {
|
||||
|
|
|
|||
|
|
@ -279,6 +279,7 @@ void FurnaceGUI::sampleListItem(int i, int dir, int asset) {
|
|||
curSample=i;
|
||||
samplePos=0;
|
||||
updateSampleTex=true;
|
||||
notifySampleChange=true;
|
||||
lastAssetType=2;
|
||||
}
|
||||
if (ImGui::IsItemHovered() && !mobileUI) {
|
||||
|
|
@ -309,6 +310,7 @@ void FurnaceGUI::sampleListItem(int i, int dir, int asset) {
|
|||
curSample=i;
|
||||
samplePos=0;
|
||||
updateSampleTex=true;
|
||||
notifySampleChange=true;
|
||||
lastAssetType=2;
|
||||
ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_TEXT]);
|
||||
if (ImGui::MenuItem(_("edit"))) {
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@
|
|||
#include "../engine/platform/k053260.h"
|
||||
#include "../engine/platform/c140.h"
|
||||
#include "../engine/platform/msm6295.h"
|
||||
#include "../engine/platform/multipcm.h"
|
||||
#include "../engine/platform/dummy.h"
|
||||
|
||||
#define COMMON_CHIP_DEBUG \
|
||||
|
|
@ -550,6 +551,16 @@ void putDispatchChip(void* data, int type) {
|
|||
COMMON_CHIP_DEBUG_BOOL;
|
||||
break;
|
||||
}
|
||||
case DIV_SYSTEM_MULTIPCM: {
|
||||
DivPlatformMultiPCM* ch=(DivPlatformMultiPCM*)data;
|
||||
ImGui::Text("> MultiPCM");
|
||||
COMMON_CHIP_DEBUG;
|
||||
ImGui::Text("- delay: %d",ch->delay);
|
||||
ImGui::Text("- curChan: %.2x",ch->curChan);
|
||||
ImGui::Text("- curAddr: %.2x",ch->curAddr);
|
||||
COMMON_CHIP_DEBUG_BOOL;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
DivDispatch* ch=(DivDispatch*)data;
|
||||
COMMON_CHIP_DEBUG;
|
||||
|
|
@ -1097,6 +1108,22 @@ void putDispatchChan(void* data, int chanNum, int type) {
|
|||
ImGui::TextColored(ch->setPos?colorOn:colorOff,">> SetPos");
|
||||
break;
|
||||
}
|
||||
case DIV_SYSTEM_MULTIPCM: {
|
||||
DivPlatformMultiPCM::Channel* ch=(DivPlatformMultiPCM::Channel*)data;
|
||||
ImGui::Text("> MultiPCM");
|
||||
COMMON_CHAN_DEBUG;
|
||||
ImGui::Text("- Sample: %d",ch->sample);
|
||||
ImGui::Text("- freqHL: %.2x%.2x",ch->freqH,ch->freqL);
|
||||
ImGui::Text("- lfo: %.2x",ch->lfo);
|
||||
ImGui::Text("- vib: %.2x",ch->vib);
|
||||
ImGui::Text("- am: %.2x",ch->am);
|
||||
ImGui::Text("- pan: %.2x",ch->pan);
|
||||
ImGui::Text("- macroVolMul: %.2x",ch->macroVolMul);
|
||||
COMMON_CHAN_DEBUG_BOOL;
|
||||
ImGui::TextColored(ch->writeCtrl?colorOn:colorOff,">> WriteCtrl");
|
||||
ImGui::TextColored(ch->levelDirect?colorOn:colorOff,">> LevelDirect");
|
||||
break;
|
||||
}
|
||||
default:
|
||||
ImGui::Text("Unimplemented chip! Help!");
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
@ -335,6 +334,35 @@ void FurnaceGUI::drawDebug() {
|
|||
ImGui::Unindent();
|
||||
ImGui::TreePop();
|
||||
}
|
||||
if (ImGui::TreeNode("New File Picker Test")) {
|
||||
static bool check0, check1, check2, check3, check4, check5;
|
||||
|
||||
ImGui::Checkbox("Modal",&check0);
|
||||
ImGui::Checkbox("No Close",&check1);
|
||||
ImGui::Checkbox("Save",&check2);
|
||||
ImGui::Checkbox("Multi Select",&check3);
|
||||
ImGui::Checkbox("Dir Select",&check4);
|
||||
ImGui::Checkbox("Embeddable",&check5);
|
||||
|
||||
int fpFlags=(
|
||||
(check0?FP_FLAGS_MODAL:0)|
|
||||
(check1?FP_FLAGS_NO_CLOSE:0)|
|
||||
(check2?FP_FLAGS_SAVE:0)|
|
||||
(check3?FP_FLAGS_MULTI_SELECT:0)|
|
||||
(check4?FP_FLAGS_DIR_SELECT:0)|
|
||||
(check5?FP_FLAGS_EMBEDDABLE:0)
|
||||
);
|
||||
|
||||
if (ImGui::Button("Open")) {
|
||||
newFilePicker->open("New File Picker","/home","",fpFlags,
|
||||
{_("songs"), "*.fur *.dmf *.mod *.s3m *.xm *.it *.fc13 *.fc14 *.smod *.fc *.ftm *.0cc *.dnm *.eft *.fub *.tfe",
|
||||
_("instruments"), "*.fui *.dmp *.tfi *.vgi *.s3i *.sbi *.opli *.opni *.y12 *.bnk *.ff *.gyb *.opm *.wopl *.wopn",
|
||||
_("audio"), "*.wav",
|
||||
_("all files"), "*"}
|
||||
);
|
||||
}
|
||||
ImGui::TreePop();
|
||||
}
|
||||
if (ImGui::TreeNode("File Selection Test")) {
|
||||
if (ImGui::Button("Test Open")) {
|
||||
openFileDialog(GUI_FILE_TEST_OPEN);
|
||||
|
|
@ -365,12 +393,17 @@ void FurnaceGUI::drawDebug() {
|
|||
ImGui::TreePop();
|
||||
}
|
||||
if (ImGui::TreeNode("Scroll Text Test")) {
|
||||
/*
|
||||
ImGui::ScrollText(ImGui::GetID("scrolltest1"),"Lorem ipsum, quia dolor sit, amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt, ut labore et dolore magnam aliquam quaerat voluptatem. ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur?");
|
||||
ImGui::ScrollText(ImGui::GetID("scrolltest2"),"quis autem vel eum iure reprehenderit");
|
||||
ImGui::ScrollText(ImGui::GetID("scrolltest3"),"qui in ea voluptate velit esse",ImVec2(100.0f*dpiScale,0),true);
|
||||
ImGui::ScrollText(ImGui::GetID("scrolltest4"),"quam nihil molestiae consequatur, vel illum, qui dolorem eum fugiat, quo voluptas nulla pariatur?",ImVec2(0,0),true);
|
||||
*/
|
||||
ImGui::ScrollText(ImGui::GetID("scrolltest1"),"Lorem ipsum, quia dolor sit, amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt, ut labore et dolore magnam aliquam quaerat voluptatem. ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur?",ImGui::GetCursorPos());
|
||||
ImGui::ScrollText(ImGui::GetID("scrolltest2"),"quis autem vel eum iure reprehenderit",ImGui::GetCursorPos());
|
||||
ImGui::ScrollText(ImGui::GetID("scrolltest3"),"qui in ea voluptate velit esse",ImGui::GetCursorPos(),ImVec2(100.0f*dpiScale,0),true);
|
||||
ImGui::ScrollText(ImGui::GetID("scrolltest4"),"quam nihil molestiae consequatur, vel illum, qui dolorem eum fugiat, quo voluptas nulla pariatur?",ImGui::GetCursorPos(),ImVec2(0,0),true);
|
||||
ImGui::TreePop();
|
||||
}
|
||||
if (ImGui::TreeNode("Vertical Text Test")) {
|
||||
VerticalText("Test");
|
||||
VerticalText("Test 2");
|
||||
ImGui::SameLine();
|
||||
VerticalText("Test 3");
|
||||
ImGui::TreePop();
|
||||
}
|
||||
if (ImGui::TreeNode("Pitch Table Calculator")) {
|
||||
|
|
|
|||
|
|
@ -222,6 +222,9 @@ void FurnaceGUI::doAction(int what) {
|
|||
}
|
||||
break;
|
||||
}
|
||||
case GUI_ACTION_OPEN_EDIT_MENU:
|
||||
openEditMenu=true;
|
||||
break;
|
||||
case GUI_ACTION_PANIC:
|
||||
e->syncReset();
|
||||
break;
|
||||
|
|
@ -700,10 +703,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;
|
||||
|
|
@ -936,10 +939,10 @@ void FurnaceGUI::doAction(int what) {
|
|||
sample->loopEnd=waveLen;
|
||||
sample->loop=true;
|
||||
sample->loopMode=DIV_SAMPLE_LOOP_FORWARD;
|
||||
sample->depth=DIV_SAMPLE_DEPTH_8BIT;
|
||||
sample->depth=DIV_SAMPLE_DEPTH_16BIT;
|
||||
if (sample->init(waveLen)) {
|
||||
for (unsigned short i=0; i<waveLen; i++) {
|
||||
sample->data8[i]=((wave->data[i]*256)/(wave->max+1))-128;
|
||||
sample->data16[i]=((wave->data[i]*65535.0f)/(wave->max))-32768;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -949,6 +952,7 @@ void FurnaceGUI::doAction(int what) {
|
|||
MARK_MODIFIED;
|
||||
}
|
||||
updateSampleTex=true;
|
||||
notifySampleChange=true;
|
||||
}
|
||||
break;
|
||||
case GUI_ACTION_WAVE_LIST_MOVE_UP:
|
||||
|
|
@ -1006,6 +1010,7 @@ void FurnaceGUI::doAction(int what) {
|
|||
MARK_MODIFIED;
|
||||
}
|
||||
updateSampleTex=true;
|
||||
notifySampleChange=true;
|
||||
break;
|
||||
case GUI_ACTION_SAMPLE_LIST_DUPLICATE:
|
||||
if (curSample>=0 && curSample<(int)e->song.sample.size()) {
|
||||
|
|
@ -1040,6 +1045,7 @@ void FurnaceGUI::doAction(int what) {
|
|||
MARK_MODIFIED;
|
||||
}
|
||||
updateSampleTex=true;
|
||||
notifySampleChange=true;
|
||||
}
|
||||
break;
|
||||
case GUI_ACTION_SAMPLE_LIST_OPEN:
|
||||
|
|
@ -1065,6 +1071,7 @@ void FurnaceGUI::doAction(int what) {
|
|||
curSample--;
|
||||
wantScrollListSample=true;
|
||||
updateSampleTex=true;
|
||||
notifySampleChange=true;
|
||||
MARK_MODIFIED;
|
||||
}
|
||||
break;
|
||||
|
|
@ -1073,6 +1080,7 @@ void FurnaceGUI::doAction(int what) {
|
|||
curSample++;
|
||||
wantScrollListSample=true;
|
||||
updateSampleTex=true;
|
||||
notifySampleChange=true;
|
||||
MARK_MODIFIED;
|
||||
}
|
||||
break;
|
||||
|
|
@ -1084,6 +1092,7 @@ void FurnaceGUI::doAction(int what) {
|
|||
curSample--;
|
||||
}
|
||||
updateSampleTex=true;
|
||||
notifySampleChange=true;
|
||||
break;
|
||||
case GUI_ACTION_SAMPLE_LIST_EDIT:
|
||||
sampleEditOpen=true;
|
||||
|
|
@ -1092,11 +1101,13 @@ void FurnaceGUI::doAction(int what) {
|
|||
if (--curSample<0) curSample=0;
|
||||
wantScrollListSample=true;
|
||||
updateSampleTex=true;
|
||||
notifySampleChange=true;
|
||||
break;
|
||||
case GUI_ACTION_SAMPLE_LIST_DOWN:
|
||||
if (++curSample>=(int)e->song.sample.size()) curSample=((int)e->song.sample.size())-1;
|
||||
wantScrollListSample=true;
|
||||
updateSampleTex=true;
|
||||
notifySampleChange=true;
|
||||
break;
|
||||
case GUI_ACTION_SAMPLE_LIST_PREVIEW:
|
||||
e->previewSample(curSample);
|
||||
|
|
@ -1186,6 +1197,7 @@ void FurnaceGUI::doAction(int what) {
|
|||
e->lockEngine([this,sample,start,end]() {
|
||||
sample->strip(start,end);
|
||||
updateSampleTex=true;
|
||||
notifySampleChange=true;
|
||||
|
||||
e->renderSamples(curSample);
|
||||
});
|
||||
|
|
@ -1238,6 +1250,7 @@ void FurnaceGUI::doAction(int what) {
|
|||
sampleSelStart=pos;
|
||||
sampleSelEnd=pos+sampleClipboardLen;
|
||||
updateSampleTex=true;
|
||||
notifySampleChange=true;
|
||||
MARK_MODIFIED;
|
||||
break;
|
||||
}
|
||||
|
|
@ -1269,6 +1282,7 @@ void FurnaceGUI::doAction(int what) {
|
|||
sampleSelEnd=pos+sampleClipboardLen;
|
||||
if (sampleSelEnd>(int)sample->samples) sampleSelEnd=sample->samples;
|
||||
updateSampleTex=true;
|
||||
notifySampleChange=true;
|
||||
MARK_MODIFIED;
|
||||
break;
|
||||
}
|
||||
|
|
@ -1306,6 +1320,7 @@ void FurnaceGUI::doAction(int what) {
|
|||
sampleSelEnd=pos+sampleClipboardLen;
|
||||
if (sampleSelEnd>(int)sample->samples) sampleSelEnd=sample->samples;
|
||||
updateSampleTex=true;
|
||||
notifySampleChange=true;
|
||||
MARK_MODIFIED;
|
||||
break;
|
||||
}
|
||||
|
|
@ -1371,6 +1386,7 @@ void FurnaceGUI::doAction(int what) {
|
|||
}
|
||||
|
||||
updateSampleTex=true;
|
||||
notifySampleChange=true;
|
||||
|
||||
e->renderSamples(curSample);
|
||||
});
|
||||
|
|
@ -1402,6 +1418,7 @@ void FurnaceGUI::doAction(int what) {
|
|||
}
|
||||
|
||||
updateSampleTex=true;
|
||||
notifySampleChange=true;
|
||||
|
||||
e->renderSamples(curSample);
|
||||
});
|
||||
|
|
@ -1433,6 +1450,7 @@ void FurnaceGUI::doAction(int what) {
|
|||
}
|
||||
|
||||
updateSampleTex=true;
|
||||
notifySampleChange=true;
|
||||
|
||||
e->renderSamples(curSample);
|
||||
});
|
||||
|
|
@ -1462,6 +1480,7 @@ void FurnaceGUI::doAction(int what) {
|
|||
}
|
||||
|
||||
updateSampleTex=true;
|
||||
notifySampleChange=true;
|
||||
|
||||
e->renderSamples(curSample);
|
||||
});
|
||||
|
|
@ -1478,6 +1497,7 @@ void FurnaceGUI::doAction(int what) {
|
|||
|
||||
sample->strip(start,end);
|
||||
updateSampleTex=true;
|
||||
notifySampleChange=true;
|
||||
|
||||
e->renderSamples(curSample);
|
||||
});
|
||||
|
|
@ -1496,6 +1516,7 @@ void FurnaceGUI::doAction(int what) {
|
|||
|
||||
sample->trim(start,end);
|
||||
updateSampleTex=true;
|
||||
notifySampleChange=true;
|
||||
|
||||
e->renderSamples(curSample);
|
||||
});
|
||||
|
|
@ -1531,6 +1552,7 @@ void FurnaceGUI::doAction(int what) {
|
|||
}
|
||||
|
||||
updateSampleTex=true;
|
||||
notifySampleChange=true;
|
||||
|
||||
e->renderSamples(curSample);
|
||||
});
|
||||
|
|
@ -1558,6 +1580,7 @@ void FurnaceGUI::doAction(int what) {
|
|||
}
|
||||
|
||||
updateSampleTex=true;
|
||||
notifySampleChange=true;
|
||||
|
||||
e->renderSamples(curSample);
|
||||
});
|
||||
|
|
@ -1583,6 +1606,7 @@ void FurnaceGUI::doAction(int what) {
|
|||
}
|
||||
|
||||
updateSampleTex=true;
|
||||
notifySampleChange=true;
|
||||
|
||||
e->renderSamples(curSample);
|
||||
});
|
||||
|
|
@ -1716,6 +1740,7 @@ void FurnaceGUI::doAction(int what) {
|
|||
sample->loopEnd=end;
|
||||
sample->loop=true;
|
||||
updateSampleTex=true;
|
||||
notifySampleChange=true;
|
||||
|
||||
e->renderSamples(curSample);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ const char* mobileButtonLabels[32]={
|
|||
|
||||
// page 4
|
||||
_N("fade"),
|
||||
_N("randomize"),
|
||||
_N("menu"),
|
||||
_N("opmask"),
|
||||
_N("scroll\nmode"),
|
||||
_N("input\nlatch"),
|
||||
|
|
@ -118,7 +118,7 @@ const int mobileButtonActions[32]={
|
|||
|
||||
// page 4
|
||||
GUI_ACTION_PAT_FADE,
|
||||
0,
|
||||
GUI_ACTION_OPEN_EDIT_MENU,
|
||||
0,
|
||||
GUI_ACTION_PAT_SCROLL_MODE,
|
||||
0,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
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,40 +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)));
|
||||
}
|
||||
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;
|
||||
|
|
@ -1655,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;
|
||||
|
|
@ -1674,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;
|
||||
}
|
||||
|
|
@ -1711,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]=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];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1772,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;
|
||||
|
|
@ -1823,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;
|
||||
}
|
||||
}
|
||||
|
|
@ -1850,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]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1906,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;
|
||||
}
|
||||
}
|
||||
|
|
@ -1933,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]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1983,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2198,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) {
|
||||
|
|
@ -2276,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) {
|
||||
|
|
|
|||
|
|
@ -23,6 +23,22 @@
|
|||
#include "misc/cpp/imgui_stdlib.h"
|
||||
#include <imgui.h>
|
||||
|
||||
const char* audioExportFormats[]={
|
||||
_N("Wave"),
|
||||
_N("Opus"),
|
||||
_N("FLAC (Free Lossless Audio Codec)"),
|
||||
_N("Vorbis"),
|
||||
_N("MP3"),
|
||||
NULL
|
||||
};
|
||||
|
||||
const char* audioExportWavFormats[]={
|
||||
_N("8-bit int (unsigned)"),
|
||||
_N("16-bit int"),
|
||||
_N("32-bit float"),
|
||||
NULL
|
||||
};
|
||||
|
||||
void FurnaceGUI::drawExportAudio(bool onWindow) {
|
||||
exitDisabledTimer=1;
|
||||
|
||||
|
|
@ -34,27 +50,46 @@ void FurnaceGUI::drawExportAudio(bool onWindow) {
|
|||
}
|
||||
if (ImGui::RadioButton(_("multiple files (one per chip)"),audioExportOptions.mode==DIV_EXPORT_MODE_MANY_SYS)) {
|
||||
audioExportOptions.mode=DIV_EXPORT_MODE_MANY_SYS;
|
||||
}
|
||||
audioExportOptions.format=DIV_EXPORT_FORMAT_WAV;
|
||||
audioExportOptions.wavFormat=DIV_EXPORT_WAV_S16;
|
||||
}
|
||||
if (ImGui::RadioButton(_("multiple files (one per channel)"),audioExportOptions.mode==DIV_EXPORT_MODE_MANY_CHAN)) {
|
||||
audioExportOptions.mode=DIV_EXPORT_MODE_MANY_CHAN;
|
||||
}
|
||||
ImGui::Unindent();
|
||||
ImGui::Separator();
|
||||
|
||||
if (audioExportOptions.mode!=DIV_EXPORT_MODE_MANY_SYS) {
|
||||
ImGui::Text(_("Bit depth:"));
|
||||
ImGui::Indent();
|
||||
if (ImGui::RadioButton(_("16-bit integer"),audioExportOptions.format==DIV_EXPORT_FORMAT_S16)) {
|
||||
audioExportOptions.format=DIV_EXPORT_FORMAT_S16;
|
||||
if (ImGui::BeginCombo(_("File Format"),audioExportFormats[audioExportOptions.format])) {
|
||||
for (size_t i=0; i<(supportsMP3?5:4); i++) {
|
||||
if (ImGui::Selectable(_(audioExportFormats[i]),audioExportOptions.format==i)) {
|
||||
audioExportOptions.format=(DivAudioExportFormats)i;
|
||||
}
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
if (ImGui::RadioButton(_("32-bit float"),audioExportOptions.format==DIV_EXPORT_FORMAT_F32)) {
|
||||
audioExportOptions.format=DIV_EXPORT_FORMAT_F32;
|
||||
ImGui::Separator();
|
||||
} else {
|
||||
audioExportOptions.format=DIV_EXPORT_FORMAT_WAV;
|
||||
audioExportOptions.wavFormat=DIV_EXPORT_WAV_S16;
|
||||
}
|
||||
|
||||
if (audioExportOptions.mode!=DIV_EXPORT_MODE_MANY_SYS && audioExportOptions.format==DIV_EXPORT_FORMAT_WAV) {
|
||||
if (ImGui::BeginCombo(_("Format"),audioExportWavFormats[audioExportOptions.wavFormat])) {
|
||||
for (size_t i=0; audioExportWavFormats[i]; i++) {
|
||||
if (ImGui::Selectable(_(audioExportWavFormats[i]),audioExportOptions.wavFormat==i)) {
|
||||
audioExportOptions.wavFormat=(DivAudioExportWavFormats)i;
|
||||
}
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
ImGui::Unindent();
|
||||
}
|
||||
|
||||
if (ImGui::InputInt(_("Sample rate"),&audioExportOptions.sampleRate,100,10000)) {
|
||||
if (audioExportOptions.sampleRate<8000) audioExportOptions.sampleRate=8000;
|
||||
if (audioExportOptions.sampleRate>384000) audioExportOptions.sampleRate=384000;
|
||||
if (audioExportOptions.format!=DIV_EXPORT_FORMAT_OPUS) {
|
||||
if (ImGui::InputInt(_("Sample rate"),&audioExportOptions.sampleRate,100,10000)) {
|
||||
if (audioExportOptions.sampleRate<8000) audioExportOptions.sampleRate=8000;
|
||||
if (audioExportOptions.sampleRate>384000) audioExportOptions.sampleRate=384000;
|
||||
}
|
||||
}
|
||||
|
||||
if (audioExportOptions.mode!=DIV_EXPORT_MODE_MANY_SYS) {
|
||||
|
|
@ -64,6 +99,57 @@ void FurnaceGUI::drawExportAudio(bool onWindow) {
|
|||
}
|
||||
}
|
||||
|
||||
if (audioExportOptions.format==DIV_EXPORT_FORMAT_MPEG_L3) {
|
||||
ImGui::Text(_("Bit rate mode:"));
|
||||
ImGui::Indent();
|
||||
if (ImGui::RadioButton(_("Constant"),audioExportOptions.bitRateMode==DIV_EXPORT_BITRATE_CONSTANT)) {
|
||||
audioExportOptions.bitRateMode=DIV_EXPORT_BITRATE_CONSTANT;
|
||||
}
|
||||
if (ImGui::RadioButton(_("Variable"),audioExportOptions.bitRateMode==DIV_EXPORT_BITRATE_VARIABLE)) {
|
||||
audioExportOptions.bitRateMode=DIV_EXPORT_BITRATE_VARIABLE;
|
||||
}
|
||||
if (ImGui::RadioButton(_("Average"),audioExportOptions.bitRateMode==DIV_EXPORT_BITRATE_AVERAGE)) {
|
||||
audioExportOptions.bitRateMode=DIV_EXPORT_BITRATE_AVERAGE;
|
||||
}
|
||||
ImGui::Unindent();
|
||||
}
|
||||
|
||||
int minBitRate=6000;
|
||||
int maxBitRate=256000;
|
||||
|
||||
if (audioExportOptions.format==DIV_EXPORT_FORMAT_MPEG_L3) {
|
||||
if (audioExportOptions.sampleRate>=32000) {
|
||||
minBitRate=32000;
|
||||
maxBitRate=320000;
|
||||
} else if (audioExportOptions.sampleRate>=16000) {
|
||||
minBitRate=8000;
|
||||
maxBitRate=160000;
|
||||
} else {
|
||||
minBitRate=8000;
|
||||
maxBitRate=64000;
|
||||
}
|
||||
}
|
||||
|
||||
if (audioExportOptions.format!=DIV_EXPORT_FORMAT_WAV) {
|
||||
if (audioExportOptions.format==DIV_EXPORT_FORMAT_FLAC) {
|
||||
if (ImGui::SliderFloat(_("Compression level"),&audioExportOptions.vbrQuality,0,8)) {
|
||||
if (audioExportOptions.vbrQuality<0) audioExportOptions.vbrQuality=0;
|
||||
if (audioExportOptions.vbrQuality>8) audioExportOptions.vbrQuality=8;
|
||||
}
|
||||
} else if (audioExportOptions.format==DIV_EXPORT_FORMAT_VORBIS || (audioExportOptions.format==DIV_EXPORT_FORMAT_MPEG_L3 && audioExportOptions.bitRateMode==DIV_EXPORT_BITRATE_VARIABLE)) {
|
||||
if (ImGui::SliderFloat(_("Quality"),&audioExportOptions.vbrQuality,0,10)) {
|
||||
if (audioExportOptions.vbrQuality<0) audioExportOptions.vbrQuality=0;
|
||||
if (audioExportOptions.vbrQuality>10) audioExportOptions.vbrQuality=10;
|
||||
}
|
||||
} else {
|
||||
if (ImGui::InputInt(_("Bit rate"),&audioExportOptions.bitRate,1000,10000)) {
|
||||
}
|
||||
if (audioExportOptions.bitRate<minBitRate) audioExportOptions.bitRate=minBitRate;
|
||||
if (audioExportOptions.bitRate>maxBitRate) audioExportOptions.bitRate=maxBitRate;
|
||||
}
|
||||
}
|
||||
ImGui::Separator();
|
||||
|
||||
if (ImGui::InputInt(_("Loops"),&audioExportOptions.loops,1,2)) {
|
||||
if (audioExportOptions.loops<0) audioExportOptions.loops=0;
|
||||
}
|
||||
|
|
@ -125,6 +211,30 @@ void FurnaceGUI::drawExportAudio(bool onWindow) {
|
|||
|
||||
if (isOneOn) {
|
||||
if (ImGui::Button(_("Export"),ImVec2(200.0f*dpiScale,0))) {
|
||||
switch (audioExportOptions.format) {
|
||||
case DIV_EXPORT_FORMAT_WAV:
|
||||
audioExportFilterName=_("Wave file");
|
||||
audioExportFilterExt=".wav";
|
||||
break;
|
||||
case DIV_EXPORT_FORMAT_OPUS:
|
||||
case DIV_EXPORT_FORMAT_VORBIS:
|
||||
audioExportFilterName=_("Ogg files");
|
||||
audioExportFilterExt=".ogg";
|
||||
break;
|
||||
case DIV_EXPORT_FORMAT_FLAC:
|
||||
audioExportFilterName=_("FLAC files");
|
||||
audioExportFilterExt=".flac";
|
||||
break;
|
||||
case DIV_EXPORT_FORMAT_MPEG_L3:
|
||||
audioExportFilterName=_("MPEG Layer 3 files");
|
||||
audioExportFilterExt=".mp3";
|
||||
break;
|
||||
default:
|
||||
audioExportFilterName=_("all files");
|
||||
audioExportFilterExt="*";
|
||||
break;
|
||||
}
|
||||
|
||||
switch (audioExportOptions.mode) {
|
||||
case DIV_EXPORT_MODE_ONE:
|
||||
openFileDialog(GUI_FILE_EXPORT_AUDIO_ONE);
|
||||
|
|
@ -540,7 +650,7 @@ void FurnaceGUI::drawExport() {
|
|||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
if (ImGui::Button(_("Set pitch linearity to Partial"))) {
|
||||
e->song.linearPitch=1;
|
||||
showError(_("No!"));
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
if (ImGui::Button(_("Set fat to max"))) {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
#include "fileDialog.h"
|
||||
#include "ImGuiFileDialog.h"
|
||||
#include "util.h"
|
||||
#include "../ta-log.h"
|
||||
|
||||
|
|
@ -192,13 +191,8 @@ bool FurnaceGUIFileDialog::openLoad(String header, std::vector<String> filter, S
|
|||
}
|
||||
#endif
|
||||
|
||||
convertFilterList(filter);
|
||||
|
||||
ImGuiFileDialog::Instance()->singleClickSel=mobileUI;
|
||||
ImGuiFileDialog::Instance()->DpiScale=dpiScale;
|
||||
ImGuiFileDialog::Instance()->mobileMode=mobileUI;
|
||||
ImGuiFileDialog::Instance()->homePath=getHomeDir();
|
||||
ImGuiFileDialog::Instance()->OpenModal("FileDialog",header,filter.empty()?NULL:noSysFilter,path,hint,allowMultiple?999:1,nullptr,0,clickCallback);
|
||||
newFilePicker->setHomeDir(getHomeDir());
|
||||
newFilePicker->open(header+"###FileDialog",path,hint,FP_FLAGS_MODAL|(allowMultiple?FP_FLAGS_MULTI_SELECT:0),filter,clickCallback);
|
||||
}
|
||||
opened=true;
|
||||
return true;
|
||||
|
|
@ -281,13 +275,8 @@ bool FurnaceGUIFileDialog::openSave(String header, std::vector<String> filter, S
|
|||
} else {
|
||||
hasError=false;
|
||||
|
||||
convertFilterList(filter);
|
||||
|
||||
ImGuiFileDialog::Instance()->singleClickSel=false;
|
||||
ImGuiFileDialog::Instance()->DpiScale=dpiScale;
|
||||
ImGuiFileDialog::Instance()->mobileMode=mobileUI;
|
||||
ImGuiFileDialog::Instance()->homePath=getHomeDir();
|
||||
ImGuiFileDialog::Instance()->OpenModal("FileDialog",header,noSysFilter,path,hint,1,nullptr,ImGuiFileDialogFlags_ConfirmOverwrite);
|
||||
newFilePicker->setHomeDir(getHomeDir());
|
||||
newFilePicker->open(header+"###FileDialog",path,hint,FP_FLAGS_MODAL|FP_FLAGS_SAVE,filter);
|
||||
}
|
||||
opened=true;
|
||||
return true;
|
||||
|
|
@ -334,11 +323,8 @@ bool FurnaceGUIFileDialog::openSelectDir(String header, String path, double dpiS
|
|||
}
|
||||
#endif
|
||||
|
||||
ImGuiFileDialog::Instance()->singleClickSel=mobileUI;
|
||||
ImGuiFileDialog::Instance()->DpiScale=dpiScale;
|
||||
ImGuiFileDialog::Instance()->mobileMode=mobileUI;
|
||||
ImGuiFileDialog::Instance()->homePath=getHomeDir();
|
||||
ImGuiFileDialog::Instance()->OpenModal("FileDialog",header,NULL,path,hint,1,nullptr,0);
|
||||
newFilePicker->setHomeDir(getHomeDir());
|
||||
newFilePicker->open(header+"###FileDialog",path,hint,FP_FLAGS_MODAL|FP_FLAGS_DIR_SELECT,{});
|
||||
}
|
||||
opened=true;
|
||||
return true;
|
||||
|
|
@ -348,7 +334,7 @@ bool FurnaceGUIFileDialog::accepted() {
|
|||
if (sysDialog) {
|
||||
return (!fileName.empty());
|
||||
} else {
|
||||
return ImGuiFileDialog::Instance()->IsOk();
|
||||
return (newFilePicker->getStatus()==FP_STATUS_ACCEPTED);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -391,7 +377,7 @@ void FurnaceGUIFileDialog::close() {
|
|||
dialogOK=false;
|
||||
#endif
|
||||
} else {
|
||||
ImGuiFileDialog::Instance()->Close();
|
||||
newFilePicker->close();
|
||||
}
|
||||
opened=false;
|
||||
}
|
||||
|
|
@ -468,7 +454,8 @@ bool FurnaceGUIFileDialog::render(const ImVec2& min, const ImVec2& max) {
|
|||
return false;
|
||||
#endif
|
||||
} else {
|
||||
return ImGuiFileDialog::Instance()->Display("FileDialog",ImGuiWindowFlags_NoCollapse|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoScrollWithMouse,min,max);
|
||||
newFilePicker->setSizeConstraints(min,max);
|
||||
return newFilePicker->draw(ImGuiWindowFlags_NoCollapse|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoScrollWithMouse);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -490,7 +477,7 @@ String FurnaceGUIFileDialog::getPath() {
|
|||
logD("curPath: %s",curPath.c_str());
|
||||
return curPath;
|
||||
} else {
|
||||
return ImGuiFileDialog::Instance()->GetCurrentPath();
|
||||
return newFilePicker->getPath();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -499,14 +486,7 @@ std::vector<String>& FurnaceGUIFileDialog::getFileName() {
|
|||
return fileName;
|
||||
} else {
|
||||
fileName.clear();
|
||||
if (dialogType!=0) {
|
||||
fileName.push_back(ImGuiFileDialog::Instance()->GetFilePathName());
|
||||
} else {
|
||||
for (auto& i: ImGuiFileDialog::Instance()->GetSelection()) {
|
||||
fileName.push_back(i.second);
|
||||
}
|
||||
}
|
||||
//
|
||||
fileName=newFilePicker->getSelected();
|
||||
return fileName;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
#include "../ta-utils.h"
|
||||
#include "imgui.h"
|
||||
#include "newFilePicker.h"
|
||||
#include <functional>
|
||||
#include "../pch.h"
|
||||
|
||||
|
|
@ -38,6 +38,7 @@ class FurnaceGUIFileDialog {
|
|||
bool hasError;
|
||||
char noSysFilter[4096];
|
||||
String curPath;
|
||||
FurnaceFilePicker* newFilePicker;
|
||||
std::vector<String> fileName;
|
||||
#ifdef USE_NFD
|
||||
std::thread* dialogO;
|
||||
|
|
@ -73,11 +74,12 @@ class FurnaceGUIFileDialog {
|
|||
bool isError();
|
||||
String getPath();
|
||||
std::vector<String>& getFileName();
|
||||
explicit FurnaceGUIFileDialog(bool system):
|
||||
explicit FurnaceGUIFileDialog(bool system, FurnaceFilePicker* builtInPicker):
|
||||
sysDialog(system),
|
||||
opened(false),
|
||||
dialogType(0),
|
||||
hasError(false),
|
||||
newFilePicker(builtInPicker),
|
||||
#ifdef ANDROID
|
||||
jniEnv(NULL),
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -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,93 +577,17 @@ 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.note==130) {
|
||||
snprintf(tempID,1024,"%s##MREL",macroRelLabel);
|
||||
} else if (i.note==129) {
|
||||
snprintf(tempID,1024,"%s##NREL",noteRelLabel);
|
||||
} else if (i.note==128) {
|
||||
snprintf(tempID,1024,"%s##NOFF",noteOffLabel);
|
||||
} else if (i.note>=-60 && i.note<120) {
|
||||
snprintf(tempID,1024,"%c%c",noteNames[i.note+60][0],(noteNames[i.note+60][1]=='-')?' ':noteNames[i.note+60][1]);
|
||||
} else {
|
||||
snprintf(tempID,1024,"???");
|
||||
i.note=0;
|
||||
}
|
||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x/2);
|
||||
bool updateNote1=false;
|
||||
int note1=i.note%12;
|
||||
int oct1=i.note/12;
|
||||
if (ImGui::BeginCombo("##NN1",tempID)) {
|
||||
for (int j=0; j<12; j++) {
|
||||
snprintf(tempID,1024,"%c%c",noteNames[j+72][0],(noteNames[j+72][1]=='-')?' ':noteNames[j+72][1]);
|
||||
if (ImGui::Selectable(tempID,note1==j)) {
|
||||
note1=j;
|
||||
updateNote1=true;
|
||||
}
|
||||
}
|
||||
if (i.noteMode!=GUI_QUERY_RANGE && i.noteMode!=GUI_QUERY_RANGE_NOT) {
|
||||
if (ImGui::Selectable(noteOffLabel,note1==13)) {
|
||||
i.note=128;
|
||||
}
|
||||
if (ImGui::Selectable(noteRelLabel,note1==14)) {
|
||||
i.note=129;
|
||||
}
|
||||
if (ImGui::Selectable(macroRelLabel,note1==15)) {
|
||||
i.note=130;
|
||||
}
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (i.note<128) {
|
||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x/2);
|
||||
if (ImGui::InputScalar("##NNO1",ImGuiDataType_S32,&oct1)) {
|
||||
if (oct1<-5) oct1=-5;
|
||||
if (oct1>9) oct1=9;
|
||||
updateNote1=true;
|
||||
}
|
||||
}
|
||||
if (updateNote1) {
|
||||
i.note=oct1*12+note1;
|
||||
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>=-60 && i.noteMax<120) {
|
||||
snprintf(tempID,1024,"%c%c",noteNames[i.noteMax+60][0],(noteNames[i.noteMax+60][1]=='-')?' ':noteNames[i.noteMax+60][1]);
|
||||
} else {
|
||||
snprintf(tempID,1024,"???");
|
||||
}
|
||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x/2);
|
||||
bool updateNote2=false;
|
||||
int note2=i.noteMax%12;
|
||||
int oct2=i.noteMax/12;
|
||||
if (ImGui::BeginCombo("##NN2",tempID)) {
|
||||
for (int j=0; j<12; j++) {
|
||||
snprintf(tempID,1024,"%c%c",noteNames[j+72][0],(noteNames[j+72][1]=='-')?' ':noteNames[j+72][1]);
|
||||
if (ImGui::Selectable(tempID,note2==j)) {
|
||||
note2=j;
|
||||
updateNote2=true;
|
||||
}
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
ImGui::SameLine();
|
||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x/2);
|
||||
if (ImGui::InputScalar("##NNO2",ImGuiDataType_S32,&oct2)) {
|
||||
if (oct2<-5) oct2=-5;
|
||||
if (oct2>9) oct2=9;
|
||||
updateNote2=true;
|
||||
}
|
||||
if (updateNote2) {
|
||||
i.noteMax=oct2*12+note2;
|
||||
if (i.noteMax<0 || i.noteMax>=256) {
|
||||
i.noteMax=108;
|
||||
}
|
||||
NoteSelector(&i.noteMax, false);
|
||||
}
|
||||
|
||||
ImGui::TableNextRow();
|
||||
|
|
@ -912,53 +798,7 @@ void FurnaceGUI::drawFindReplace() {
|
|||
ImGui::TableNextColumn();
|
||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||
if (queryReplaceNoteMode==GUI_QUERY_REPLACE_SET) {
|
||||
if (queryReplaceNote==130) {
|
||||
snprintf(tempID,1024,"%s##MREL",macroRelLabel);
|
||||
} else if (queryReplaceNote==129) {
|
||||
snprintf(tempID,1024,"%s##NREL",noteRelLabel);
|
||||
} else if (queryReplaceNote==128) {
|
||||
snprintf(tempID,1024,"%s##NOFF",noteOffLabel);
|
||||
} else if (queryReplaceNote>=-60 && queryReplaceNote<120) {
|
||||
snprintf(tempID,1024,"%c%c",noteNames[queryReplaceNote+60][0],(noteNames[queryReplaceNote+60][1]=='-')?' ':noteNames[queryReplaceNote+60][1]);
|
||||
} else {
|
||||
snprintf(tempID,1024,"???");
|
||||
queryReplaceNote=0;
|
||||
}
|
||||
bool updateNote=false;
|
||||
int note1=queryReplaceNote%12;
|
||||
int oct1=queryReplaceNote/12;
|
||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x/2);
|
||||
if (ImGui::BeginCombo("##NRValueC",tempID)) {
|
||||
for (int i=0; i<12; i++) {
|
||||
snprintf(tempID,1024,"%c%c",noteNames[i+72][0],(noteNames[i+72][1]=='-')?' ':noteNames[i+72][1]);
|
||||
if (ImGui::Selectable(tempID,note1==i)) {
|
||||
note1=i;
|
||||
updateNote=true;
|
||||
}
|
||||
}
|
||||
if (ImGui::Selectable(noteOffLabel,note1==13)) {
|
||||
queryReplaceNote=128;
|
||||
}
|
||||
if (ImGui::Selectable(noteRelLabel,note1==14)) {
|
||||
queryReplaceNote=129;
|
||||
}
|
||||
if (ImGui::Selectable(macroRelLabel,note1==15)) {
|
||||
queryReplaceNote=130;
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (queryReplaceNote<128) {
|
||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x/2);
|
||||
if (ImGui::InputScalar("##NRValueCO",ImGuiDataType_S32,&oct1)) {
|
||||
if (oct1<-5) oct1=-5;
|
||||
if (oct1>9) oct1=9;
|
||||
updateNote=true;
|
||||
}
|
||||
}
|
||||
if (updateNote) {
|
||||
queryReplaceNote=oct1*12+note1;
|
||||
}
|
||||
NoteSelector(&queryReplaceNote, true);
|
||||
} else if (queryReplaceNoteMode==GUI_QUERY_REPLACE_ADD || queryReplaceNoteMode==GUI_QUERY_REPLACE_ADD_OVERFLOW) {
|
||||
if (ImGui::InputInt("##NRValue",&queryReplaceNote,1,12)) {
|
||||
if (queryReplaceNote<-180) queryReplaceNote=-180;
|
||||
|
|
|
|||
|
|
@ -38,9 +38,21 @@ struct InflateBlock {
|
|||
};
|
||||
|
||||
ImFont* FurnaceGUI::addFontZlib(const void* data, size_t len, float size_pixels, const ImFontConfig* font_cfg, const ImWchar* glyph_ranges) {
|
||||
// find font in cache
|
||||
logV("addFontZlib...");
|
||||
for (FurnaceGUIUncompFont& i: fontCache) {
|
||||
if (i.origPtr==data && i.origLen==len) {
|
||||
logV("found in cache");
|
||||
ImFontConfig fontConfig=(font_cfg==NULL)?ImFontConfig():(*font_cfg);
|
||||
fontConfig.FontDataOwnedByAtlas=false;
|
||||
|
||||
return ImGui::GetIO().Fonts->AddFontFromMemoryTTF(i.data,i.len,size_pixels,&fontConfig,glyph_ranges);
|
||||
}
|
||||
}
|
||||
|
||||
z_stream zl;
|
||||
memset(&zl,0,sizeof(z_stream));
|
||||
logV("addFontZlib...");
|
||||
logV("not found in cache - decompressing...");
|
||||
|
||||
zl.avail_in=len;
|
||||
zl.next_in=(Bytef*)data;
|
||||
|
|
@ -116,10 +128,11 @@ ImFont* FurnaceGUI::addFontZlib(const void* data, size_t len, float size_pixels,
|
|||
delete i;
|
||||
}
|
||||
blocks.clear();
|
||||
len=finalSize;
|
||||
|
||||
fontCache.push_back(FurnaceGUIUncompFont(data,len,finalData,finalSize));
|
||||
|
||||
ImFontConfig fontConfig=(font_cfg==NULL)?ImFontConfig():(*font_cfg);
|
||||
fontConfig.FontDataOwnedByAtlas=true;
|
||||
fontConfig.FontDataOwnedByAtlas=false;
|
||||
|
||||
return ImGui::GetIO().Fonts->AddFontFromMemoryTTF(finalData,finalSize,size_pixels,&fontConfig,glyph_ranges);
|
||||
}
|
||||
|
|
|
|||
406
src/gui/gui.cpp
406
src/gui/gui.cpp
|
|
@ -29,7 +29,6 @@
|
|||
#include "../fileutils.h"
|
||||
#include "imgui.h"
|
||||
#include "imgui_internal.h"
|
||||
#include "ImGuiFileDialog.h"
|
||||
#include "IconsFontAwesome4.h"
|
||||
#include "misc/cpp/imgui_stdlib.h"
|
||||
#include "plot_nolerp.h"
|
||||
|
|
@ -99,6 +98,17 @@ void FurnaceGUI::enableSafeMode() {
|
|||
}
|
||||
|
||||
const char* FurnaceGUI::noteName(short note) {
|
||||
if (note==DIV_NOTE_OFF) {
|
||||
return noteOffLabel;
|
||||
} else if (note==DIV_NOTE_REL) { // note off and envelope release
|
||||
return noteRelLabel;
|
||||
} else if (note==DIV_MACRO_REL) { // envelope release only
|
||||
return macroRelLabel;
|
||||
} else if (note==-1) {
|
||||
return emptyLabel;
|
||||
} else if (note==DIV_NOTE_NULL_PAT) {
|
||||
return "BUG";
|
||||
}
|
||||
if (note<0 || note>=180) {
|
||||
return "???";
|
||||
}
|
||||
|
|
@ -110,66 +120,31 @@ const char* FurnaceGUI::noteName(short note) {
|
|||
return noteNames[note];
|
||||
}
|
||||
|
||||
const char* FurnaceGUI::noteName(short note, short octave) {
|
||||
if (note==100) {
|
||||
return noteOffLabel;
|
||||
} else if (note==101) { // note off and envelope release
|
||||
return noteRelLabel;
|
||||
} else if (note==102) { // envelope release only
|
||||
return macroRelLabel;
|
||||
} else if (octave==0 && note==0) {
|
||||
return emptyLabel;
|
||||
} else if (note==0 && octave!=0) {
|
||||
return "BUG";
|
||||
}
|
||||
int seek=(note+(signed char)octave*12)+60;
|
||||
if (seek<0 || seek>=180) {
|
||||
return "???";
|
||||
}
|
||||
if (settings.flatNotes) {
|
||||
if (settings.germanNotation) return noteNamesGF[seek];
|
||||
return noteNamesF[seek];
|
||||
}
|
||||
if (settings.germanNotation) return noteNamesG[seek];
|
||||
return noteNames[seek];
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
@ -452,6 +427,42 @@ bool FurnaceGUI::isCtrlWheelModifierHeld() const {
|
|||
}
|
||||
}
|
||||
|
||||
void FurnaceGUI::VerticalText(const char* fmt, ...) {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
ImVec2 pos=ImGui::GetCursorScreenPos();
|
||||
ImDrawList* dl=ImGui::GetWindowDrawList();
|
||||
int vtxBegin, vtxEnd;
|
||||
vtxBegin=dl->_VtxCurrentIdx;
|
||||
char text[4096];
|
||||
vsnprintf(text, 4096, fmt, args);
|
||||
ImVec2 size=ImGui::CalcTextSize(text);
|
||||
dl->AddText(pos, ImGui::GetColorU32(ImGuiCol_Text), text);
|
||||
vtxEnd=dl->_VtxCurrentIdx;
|
||||
ImGui::ShadeVertsTransformPos(dl, vtxBegin, vtxEnd, pos+ImVec2(size.x,0), 0, -1, ImGui::GetCursorScreenPos());
|
||||
ImGui::Dummy(ImVec2(size.y,size.x));
|
||||
}
|
||||
|
||||
void FurnaceGUI::VerticalText(float maxSize, bool centered, const char* fmt, ...) {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
ImVec2 pos=ImGui::GetWindowPos();
|
||||
ImDrawList* dl=ImGui::GetWindowDrawList();
|
||||
int vtxBegin, vtxEnd;
|
||||
vtxBegin=dl->_VtxCurrentIdx;
|
||||
char text[4096];
|
||||
vsnprintf(text, 4096, fmt, args);
|
||||
const char* textEol=ImGui::FindRenderedTextEnd(text);
|
||||
ImVec2 size=ImGui::CalcTextSize(text);
|
||||
dl->PushClipRect(pos,pos+ImGui::GetWindowSize());
|
||||
ImGui::RenderTextEllipsis(dl,pos,pos+ImVec2(maxSize,ImGui::GetFontSize()),maxSize,text,textEol,&size);
|
||||
dl->PopClipRect();
|
||||
vtxEnd=dl->_VtxCurrentIdx;
|
||||
float ySize=(size.x>maxSize)?maxSize:size.x;
|
||||
ImGui::ShadeVertsTransformPos(dl, vtxBegin, vtxEnd, pos, 0, -1, ImGui::GetCursorScreenPos()+ImVec2(0,(size.x+ySize)/2+(centered?(maxSize-size.x)/2.0f:0)));
|
||||
ImGui::Dummy(ImVec2(size.y,centered?maxSize:ySize));
|
||||
}
|
||||
|
||||
bool FurnaceGUI::CWSliderScalar(const char* label, ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max, const char* format, ImGuiSliderFlags flags) {
|
||||
flags^=ImGuiSliderFlags_AlwaysClamp;
|
||||
if (ImGui::SliderScalar(label,data_type,p_data,p_min,p_max,format,flags)) {
|
||||
|
|
@ -547,6 +558,72 @@ bool FurnaceGUI::InvCheckbox(const char* label, bool* value) {
|
|||
return false;
|
||||
}
|
||||
|
||||
bool FurnaceGUI::NoteSelector(int* value, bool showOffRel, int octaveMin, int octaveMax) {
|
||||
bool ret=false, calcNote=false;
|
||||
char tempID[64];
|
||||
if (*value==DIV_MACRO_REL) {
|
||||
snprintf(tempID,64,"%s##MREL",macroRelLabel);
|
||||
} else if (*value==DIV_NOTE_REL) {
|
||||
snprintf(tempID,64,"%s##NREL",noteRelLabel);
|
||||
} else if (*value==DIV_NOTE_OFF) {
|
||||
snprintf(tempID,64,"%s##NOFF",noteOffLabel);
|
||||
} 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)%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[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<180) ImGui::SetItemDefaultFocus();
|
||||
}
|
||||
if (showOffRel) {
|
||||
if (ImGui::Selectable(noteOffLabel,*value==DIV_NOTE_OFF)) {
|
||||
*value=DIV_NOTE_OFF;
|
||||
ret=true;
|
||||
}
|
||||
if (ImGui::Selectable(noteRelLabel,*value==DIV_NOTE_REL)) {
|
||||
*value=DIV_NOTE_REL;
|
||||
ret=true;
|
||||
}
|
||||
if (ImGui::Selectable(macroRelLabel,*value==DIV_MACRO_REL)) {
|
||||
*value=DIV_MACRO_REL;
|
||||
ret=true;
|
||||
}
|
||||
if (*value>=DIV_NOTE_OFF && *value<=DIV_MACRO_REL) ImGui::SetItemDefaultFocus();
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (*value<180) {
|
||||
ImGui::SetNextItemWidth(width/2);
|
||||
if (ImGui::InputScalar("##NoteSelectorOctave",ImGuiDataType_S32,&oct)) {
|
||||
if (oct<octaveMin) oct=octaveMin;
|
||||
if (oct>octaveMax) oct=octaveMax;
|
||||
calcNote=true;
|
||||
}
|
||||
}
|
||||
if (calcNote) {
|
||||
*value=(oct+5)*12+note;
|
||||
ret=true;
|
||||
}
|
||||
ImGui::PopID();
|
||||
ImGui::EndGroup();
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool FurnaceGUI::LocalizedComboGetter(void* data, int idx, const char** out_text) {
|
||||
const char* const* items=(const char* const*)data;
|
||||
if (out_text) *out_text=_(items[idx]);
|
||||
|
|
@ -1311,48 +1388,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();
|
||||
|
|
@ -1371,26 +1439,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;
|
||||
}
|
||||
|
|
@ -1406,18 +1475,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;
|
||||
|
|
@ -1507,7 +1576,7 @@ void FurnaceGUI::keyDown(SDL_Event& ev) {
|
|||
mapped|=FURKMOD_SHIFT;
|
||||
}
|
||||
|
||||
if (!ImGuiFileDialog::Instance()->IsOpened()) {
|
||||
if (!newFilePicker->isOpened()) {
|
||||
if (bindSetActive) {
|
||||
if (!ev.key.repeat) {
|
||||
switch (ev.key.keysym.sym) {
|
||||
|
|
@ -1760,7 +1829,7 @@ void FurnaceGUI::keyDown(SDL_Event& ev) {
|
|||
if (actionI!=actionMapGlobal.cend()) {
|
||||
int action=actionI->second;
|
||||
if (action>0) {
|
||||
if (ImGuiFileDialog::Instance()->IsOpened()) {
|
||||
if (newFilePicker->isOpened()) {
|
||||
if (action!=GUI_ACTION_OCTAVE_UP && action!=GUI_ACTION_OCTAVE_DOWN) return;
|
||||
}
|
||||
doAction(action);
|
||||
|
|
@ -1855,11 +1924,12 @@ void FurnaceGUI::openFileDialog(FurnaceGUIFileDialogs type) {
|
|||
if (!dirExists(workingDirIns)) workingDirIns=getHomeDir();
|
||||
hasOpened=fileDialog->openLoad(
|
||||
_("Load Instrument"),
|
||||
{_("all compatible files"), "*.fui *.dmp *.tfi *.vgi *.s3i *.sbi *.opli *.opni *.y12 *.bnk *.ff *.gyb *.opm *.wopl *.wopn",
|
||||
{_("all compatible files"), "*.fui *.dmp *.tfi *.vgi *.eif *.s3i *.sbi *.opli *.opni *.y12 *.bnk *.ff *.gyb *.opm *.wopl *.wopn",
|
||||
_("Furnace instrument"), "*.fui",
|
||||
_("DefleMask preset"), "*.dmp",
|
||||
_("TFM Music Maker instrument"), "*.tfi",
|
||||
_("VGM Music Maker instrument"), "*.vgi",
|
||||
_("Echo instrument"), "*.eif",
|
||||
_("Scream Tracker 3 instrument"), "*.s3i",
|
||||
_("SoundBlaster instrument"), "*.sbi",
|
||||
_("Wohlstand OPL instrument"), "*.opli",
|
||||
|
|
@ -1887,6 +1957,7 @@ void FurnaceGUI::openFileDialog(FurnaceGUIFileDialogs type) {
|
|||
}
|
||||
if (prevIns>=0 && prevIns<=(int)e->song.ins.size()) {
|
||||
*e->song.ins[prevIns]=*instruments[0];
|
||||
e->notifyInsChange(prevIns);
|
||||
}
|
||||
} else {
|
||||
e->loadTempIns(instruments[0]);
|
||||
|
|
@ -2031,7 +2102,7 @@ void FurnaceGUI::openFileDialog(FurnaceGUIFileDialogs type) {
|
|||
if (!dirExists(workingDirAudioExport)) workingDirAudioExport=getHomeDir();
|
||||
hasOpened=fileDialog->openSave(
|
||||
_("Export Audio"),
|
||||
{_("Wave file"), "*.wav"},
|
||||
{audioExportFilterName, "*"+audioExportFilterExt},
|
||||
workingDirAudioExport,
|
||||
dpiScale,
|
||||
(settings.autoFillSave)?shortName:""
|
||||
|
|
@ -2041,7 +2112,7 @@ void FurnaceGUI::openFileDialog(FurnaceGUIFileDialogs type) {
|
|||
if (!dirExists(workingDirAudioExport)) workingDirAudioExport=getHomeDir();
|
||||
hasOpened=fileDialog->openSave(
|
||||
_("Export Audio"),
|
||||
{_("Wave file"), "*.wav"},
|
||||
{audioExportFilterName, "*"+audioExportFilterExt},
|
||||
workingDirAudioExport,
|
||||
dpiScale,
|
||||
(settings.autoFillSave)?shortName:""
|
||||
|
|
@ -2051,7 +2122,7 @@ void FurnaceGUI::openFileDialog(FurnaceGUIFileDialogs type) {
|
|||
if (!dirExists(workingDirAudioExport)) workingDirAudioExport=getHomeDir();
|
||||
hasOpened=fileDialog->openSave(
|
||||
_("Export Audio"),
|
||||
{_("Wave file"), "*.wav"},
|
||||
{audioExportFilterName, "*"+audioExportFilterExt},
|
||||
workingDirAudioExport,
|
||||
dpiScale,
|
||||
(settings.autoFillSave)?shortName:""
|
||||
|
|
@ -2294,7 +2365,6 @@ void FurnaceGUI::openFileDialog(FurnaceGUIFileDialogs type) {
|
|||
break;
|
||||
}
|
||||
if (hasOpened) curFileDialog=type;
|
||||
//ImGui::GetIO().ConfigFlags|=ImGuiConfigFlags_NavEnableKeyboard;
|
||||
}
|
||||
|
||||
int FurnaceGUI::save(String path, int dmfVersion) {
|
||||
|
|
@ -2304,7 +2374,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();
|
||||
|
|
@ -2651,7 +2721,7 @@ void FurnaceGUI::exportAudio(String path, DivAudioExportModes mode) {
|
|||
e->findSongLength(loopOrder,loopRow,audioExportOptions.fadeOut,songFadeoutSectionLength,songHasSongEndCommand,songOrdersLengths,songLength); // for progress estimation
|
||||
|
||||
songLoopedSectionLength=songLength;
|
||||
for (int i=0; i<loopOrder; i++) {
|
||||
for (int i=0; i<loopOrder && i<(int)songOrdersLengths.size(); i++) {
|
||||
songLoopedSectionLength-=songOrdersLengths[i];
|
||||
}
|
||||
songLoopedSectionLength-=loopRow;
|
||||
|
|
@ -2864,6 +2934,7 @@ void FurnaceGUI::processDrags(int dragX, int dragY) {
|
|||
for (int i=x; i<=x1; i++) ((signed char*)sampleDragTarget)[i]=val;
|
||||
}
|
||||
updateSampleTex=true;
|
||||
notifySampleChange=true;
|
||||
}
|
||||
} else { // select
|
||||
if (sampleSelStart<0) {
|
||||
|
|
@ -3110,10 +3181,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;
|
||||
}
|
||||
|
|
@ -3310,6 +3381,7 @@ void FurnaceGUI::toggleMobileUI(bool enable, bool force) {
|
|||
ImGui::GetIO().ConfigFlags|=ImGuiConfigFlags_NoHoverColors;
|
||||
ImGui::GetIO().AlwaysScrollText=true;
|
||||
fileDialog->mobileUI=true;
|
||||
newFilePicker->setMobile(true);
|
||||
} else {
|
||||
ImGui::GetIO().IniFilename=NULL;
|
||||
if (!ImGui::LoadIniSettingsFromDisk(finalLayoutPath,true)) {
|
||||
|
|
@ -3320,6 +3392,7 @@ void FurnaceGUI::toggleMobileUI(bool enable, bool force) {
|
|||
ImGui::GetIO().ConfigFlags&=~ImGuiConfigFlags_NoHoverColors;
|
||||
ImGui::GetIO().AlwaysScrollText=false;
|
||||
fileDialog->mobileUI=false;
|
||||
newFilePicker->setMobile(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3913,7 +3986,7 @@ bool FurnaceGUI::loop() {
|
|||
}
|
||||
#endif
|
||||
case SDL_KEYDOWN:
|
||||
if (!ImGui::GetIO().WantCaptureKeyboard || (ImGuiFileDialog::Instance()->IsOpened() && !ImGui::GetIO().WantTextInput)) {
|
||||
if (!ImGui::GetIO().WantCaptureKeyboard || (newFilePicker->isOpened() && !ImGui::GetIO().WantTextInput)) {
|
||||
keyDown(ev);
|
||||
}
|
||||
if (introPos<11.0 && !shortIntro) {
|
||||
|
|
@ -3969,26 +4042,22 @@ bool FurnaceGUI::loop() {
|
|||
}
|
||||
nextWindow=GUI_WINDOW_WAVE_LIST;
|
||||
MARK_MODIFIED;
|
||||
}
|
||||
else if (!samples.empty())
|
||||
{
|
||||
} else if (!samples.empty()) {
|
||||
if (e->song.sampleLen!=sampleCountBefore) {
|
||||
//e->renderSamplesP();
|
||||
}
|
||||
if (!e->getWarnings().empty())
|
||||
{
|
||||
if (!e->getWarnings().empty()) {
|
||||
showWarning(e->getWarnings(),GUI_WARN_GENERIC);
|
||||
}
|
||||
int sampleCount=-1;
|
||||
for (DivSample* s: samples)
|
||||
{
|
||||
for (DivSample* s: samples) {
|
||||
sampleCount=e->addSamplePtr(s);
|
||||
}
|
||||
//sampleCount=e->addSamplePtr(droppedSample);
|
||||
if (sampleCount>=0 && settings.selectAssetOnLoad)
|
||||
{
|
||||
if (sampleCount>=0 && settings.selectAssetOnLoad) {
|
||||
curSample=sampleCount;
|
||||
updateSampleTex=true;
|
||||
notifySampleChange=true;
|
||||
}
|
||||
nextWindow=GUI_WINDOW_SAMPLE_LIST;
|
||||
MARK_MODIFIED;
|
||||
|
|
@ -4227,6 +4296,11 @@ bool FurnaceGUI::loop() {
|
|||
e->notifyWaveChange(curWave);
|
||||
}
|
||||
|
||||
if (notifySampleChange) {
|
||||
notifySampleChange=false;
|
||||
e->notifySampleChange(curSample);
|
||||
}
|
||||
|
||||
eventTimeEnd=SDL_GetPerformanceCounter();
|
||||
|
||||
if (SDL_GetWindowFlags(sdlWin)&SDL_WINDOW_MINIMIZED) {
|
||||
|
|
@ -4265,6 +4339,17 @@ bool FurnaceGUI::loop() {
|
|||
});
|
||||
}
|
||||
|
||||
// recover from audio resets
|
||||
TAAudioDeviceStatus audioStatus=e->getAudioDeviceStatus();
|
||||
if (audioStatus!=TA_AUDIO_DEVICE_OK) {
|
||||
logI("audio device reset!");
|
||||
e->acceptAudioDeviceStatus();
|
||||
|
||||
if (!e->switchMaster(false)) {
|
||||
showError(_("audio device has reset or has been disconnected! check audio settings."));
|
||||
}
|
||||
}
|
||||
|
||||
// recover from dead graphics
|
||||
if (rend->isDead() || killGraphics) {
|
||||
killGraphics=false;
|
||||
|
|
@ -4828,46 +4913,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-1)|1],cursor.xCoarse,true);
|
||||
hasInfo=true;
|
||||
}
|
||||
} else {
|
||||
info=_("Error!");
|
||||
hasInfo=true;
|
||||
}
|
||||
break;
|
||||
|
|
@ -4963,6 +5052,7 @@ bool FurnaceGUI::loop() {
|
|||
MEASURE(effectList,drawEffectList());
|
||||
MEASURE(userPresets,drawUserPresets());
|
||||
MEASURE(patManager,drawPatManager());
|
||||
|
||||
} else {
|
||||
globalWinFlags=0;
|
||||
ImGui::DockSpaceOverViewport(0,NULL,lockLayout?(ImGuiDockNodeFlags_NoWindowMenuButton|ImGuiDockNodeFlags_NoMove|ImGuiDockNodeFlags_NoResize|ImGuiDockNodeFlags_NoCloseButton|ImGuiDockNodeFlags_NoDocking|ImGuiDockNodeFlags_NoDockingSplit|ImGuiDockNodeFlags_NoDockingSplitOther):0);
|
||||
|
|
@ -5007,6 +5097,7 @@ bool FurnaceGUI::loop() {
|
|||
MEASURE(log,drawLog());
|
||||
MEASURE(effectList,drawEffectList());
|
||||
MEASURE(userPresets,drawUserPresets());
|
||||
|
||||
}
|
||||
|
||||
// release selection if mouse released
|
||||
|
|
@ -5025,7 +5116,7 @@ bool FurnaceGUI::loop() {
|
|||
}
|
||||
|
||||
for (int i=0; i<e->getTotalChannelCount(); i++) {
|
||||
keyHit1[i]-=0.2f;
|
||||
keyHit1[i]-=0.08f;
|
||||
if (keyHit1[i]<0.0f) keyHit1[i]=0.0f;
|
||||
}
|
||||
|
||||
|
|
@ -5071,6 +5162,7 @@ bool FurnaceGUI::loop() {
|
|||
if (prevInsData!=NULL) {
|
||||
if (prevIns>=0 && prevIns<(int)e->song.ins.size()) {
|
||||
*e->song.ins[prevIns]=*prevInsData;
|
||||
e->notifyInsChange(prevIns);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
|
@ -5191,11 +5283,15 @@ bool FurnaceGUI::loop() {
|
|||
if (curFileDialog==GUI_FILE_SAVE_DMF_LEGACY) {
|
||||
checkExtension(".dmf");
|
||||
}
|
||||
if (curFileDialog==GUI_FILE_SAMPLE_SAVE ||
|
||||
curFileDialog==GUI_FILE_EXPORT_AUDIO_ONE ||
|
||||
if (curFileDialog==GUI_FILE_SAMPLE_SAVE) {
|
||||
checkExtension(".wav");
|
||||
}
|
||||
if (curFileDialog==GUI_FILE_EXPORT_AUDIO_ONE ||
|
||||
curFileDialog==GUI_FILE_EXPORT_AUDIO_PER_SYS ||
|
||||
curFileDialog==GUI_FILE_EXPORT_AUDIO_PER_CHANNEL) {
|
||||
checkExtension(".wav");
|
||||
if (audioExportFilterExt!="*") {
|
||||
checkExtension(audioExportFilterExt.c_str());
|
||||
}
|
||||
}
|
||||
if (curFileDialog==GUI_FILE_INS_SAVE) {
|
||||
checkExtension(".fui");
|
||||
|
|
@ -5475,6 +5571,7 @@ bool FurnaceGUI::loop() {
|
|||
MARK_MODIFIED;
|
||||
});
|
||||
updateSampleTex=true;
|
||||
notifySampleChange=true;
|
||||
} else {
|
||||
showError(_("...but you haven't selected a sample!"));
|
||||
delete samples[0];
|
||||
|
|
@ -5600,6 +5697,7 @@ bool FurnaceGUI::loop() {
|
|||
// reset macro zoom
|
||||
memset(e->song.ins[curIns]->temp.vZoom,-1,sizeof(e->song.ins[curIns]->temp.vZoom));
|
||||
MARK_MODIFIED;
|
||||
e->notifyInsChange(curIns);
|
||||
} else {
|
||||
showError(_("...but you haven't selected an instrument!"));
|
||||
}
|
||||
|
|
@ -6179,7 +6277,9 @@ bool FurnaceGUI::loop() {
|
|||
|
||||
centerNextWindow(_("Warning"),canvasW,canvasH);
|
||||
if (ImGui::BeginPopupModal(_("Warning"),NULL,ImGuiWindowFlags_AlwaysAutoResize)) {
|
||||
ImGui::Text("%s",warnString.c_str());
|
||||
ImGui::PushTextWrapPos(canvasW);
|
||||
ImGui::TextUnformatted(warnString.c_str());
|
||||
ImGui::PopTextWrapPos();
|
||||
switch (warnAction) {
|
||||
case GUI_WARN_QUIT:
|
||||
if (ImGui::Button(_("Yes"))) {
|
||||
|
|
@ -6445,11 +6545,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;
|
||||
|
|
@ -6498,6 +6594,14 @@ bool FurnaceGUI::loop() {
|
|||
MARK_MODIFIED;
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
if (ImGui::Button(_("Remove unused patterns"))) {
|
||||
stop();
|
||||
e->lockEngine([this]() {
|
||||
e->curSubSong->removeUnusedPatterns();
|
||||
});
|
||||
MARK_MODIFIED;
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
if (ImGui::Button(_("Remove unused instruments"))) {
|
||||
stop();
|
||||
e->delUnusedIns();
|
||||
|
|
@ -6813,6 +6917,7 @@ bool FurnaceGUI::loop() {
|
|||
*e->song.ins[curIns]=*i.first;
|
||||
// reset macro zoom
|
||||
memset(e->song.ins[curIns]->temp.vZoom,-1,sizeof(e->song.ins[curIns]->temp.vZoom));
|
||||
e->notifyInsChange(curIns);
|
||||
} else {
|
||||
showError(_("...but you haven't selected an instrument!"));
|
||||
}
|
||||
|
|
@ -7096,6 +7201,7 @@ bool FurnaceGUI::loop() {
|
|||
MARK_MODIFIED;
|
||||
});
|
||||
updateSampleTex=true;
|
||||
notifySampleChange=true;
|
||||
} else {
|
||||
showError(_("...but you haven't selected a sample!"));
|
||||
delete s;
|
||||
|
|
@ -7206,7 +7312,7 @@ bool FurnaceGUI::loop() {
|
|||
}
|
||||
}
|
||||
logD("saving backup...");
|
||||
SafeWriter* w=e->saveFur(true,true);
|
||||
SafeWriter* w=e->saveFur(true);
|
||||
logV("writing file...");
|
||||
|
||||
if (w!=NULL) {
|
||||
|
|
@ -7464,6 +7570,9 @@ bool FurnaceGUI::loop() {
|
|||
bool FurnaceGUI::init() {
|
||||
logI("initializing GUI.");
|
||||
|
||||
newFilePicker=new FurnaceFilePicker;
|
||||
newFilePicker->setConfigPrefix("fp_");
|
||||
|
||||
opTouched=new bool[DIV_MAX_PATTERNS*DIV_MAX_ROWS];
|
||||
|
||||
syncState();
|
||||
|
|
@ -7878,6 +7987,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;
|
||||
|
|
@ -7992,9 +8103,23 @@ bool FurnaceGUI::init() {
|
|||
// just in case
|
||||
if (strcmp(f.extension,"dmc")==0) continue;
|
||||
if (strcmp(f.extension,"brr")==0) continue;
|
||||
audioLoadFormats.push_back(f.name);
|
||||
audioLoadFormats.push_back(fmt::sprintf("*.%s",f.extension));
|
||||
compatFormats+=fmt::sprintf("*.%s ",f.extension);
|
||||
|
||||
// special treatment for Ogg and MPEG
|
||||
if (strcmp(f.extension,"oga")==0) {
|
||||
supportsOgg=true;
|
||||
audioLoadFormats.push_back(f.name);
|
||||
audioLoadFormats.push_back("*.ogg *.oga *.opus");
|
||||
compatFormats+="*.ogg *.oga *.opus ";
|
||||
} else if (strcmp(f.extension,"m1a")==0) {
|
||||
supportsMP3=true;
|
||||
audioLoadFormats.push_back(f.name);
|
||||
audioLoadFormats.push_back("*.m1a *.mp1 *.mp2 *.mp3");
|
||||
compatFormats+="*.m1a *.mp1 *.mp2 *.mp3 ";
|
||||
} else {
|
||||
audioLoadFormats.push_back(f.name);
|
||||
audioLoadFormats.push_back(fmt::sprintf("*.%s",f.extension));
|
||||
compatFormats+=fmt::sprintf("*.%s ",f.extension);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
@ -8197,6 +8322,8 @@ void FurnaceGUI::syncState() {
|
|||
xyOscThickness=e->getConfFloat("xyOscThickness",2.0f);
|
||||
|
||||
cvHiScore=e->getConfInt("cvHiScore",25000);
|
||||
|
||||
newFilePicker->loadSettings(e->getConfObject());
|
||||
}
|
||||
|
||||
void FurnaceGUI::commitState(DivConfig& conf) {
|
||||
|
|
@ -8362,6 +8489,8 @@ void FurnaceGUI::commitState(DivConfig& conf) {
|
|||
}
|
||||
|
||||
conf.set("cvHiScore",cvHiScore);
|
||||
|
||||
newFilePicker->saveSettings(e->getConfObject());
|
||||
}
|
||||
|
||||
bool FurnaceGUI::finish(bool saveConfig) {
|
||||
|
|
@ -8480,6 +8609,7 @@ FurnaceGUI::FurnaceGUI():
|
|||
sysDupEnd(false),
|
||||
noteInputPoly(true),
|
||||
notifyWaveChange(false),
|
||||
notifySampleChange(false),
|
||||
wantScrollListIns(false),
|
||||
wantScrollListWave(false),
|
||||
wantScrollListSample(false),
|
||||
|
|
@ -8547,6 +8677,7 @@ FurnaceGUI::FurnaceGUI():
|
|||
postWarnAction(GUI_WARN_GENERIC),
|
||||
mobScene(GUI_SCENE_PATTERN),
|
||||
fileDialog(NULL),
|
||||
newFilePicker(NULL),
|
||||
scrW(GUI_WIDTH_DEFAULT),
|
||||
scrH(GUI_HEIGHT_DEFAULT),
|
||||
scrConfW(GUI_WIDTH_DEFAULT),
|
||||
|
|
@ -8717,6 +8848,7 @@ FurnaceGUI::FurnaceGUI():
|
|||
dragMobileEditButton(false),
|
||||
wantGrooveListFocus(false),
|
||||
mobilePatSel(false),
|
||||
openEditMenu(false),
|
||||
lastAssetType(0),
|
||||
curWindow(GUI_WINDOW_NOTHING),
|
||||
nextWindow(GUI_WINDOW_NOTHING),
|
||||
|
|
@ -8749,13 +8881,15 @@ FurnaceGUI::FurnaceGUI():
|
|||
queryReplaceNoteMode(0),
|
||||
queryReplaceInsMode(0),
|
||||
queryReplaceVolMode(0),
|
||||
queryReplaceNote(0),
|
||||
queryReplaceNote(108),
|
||||
queryReplaceIns(0),
|
||||
queryReplaceVol(0),
|
||||
queryReplaceNoteDo(false),
|
||||
queryReplaceInsDo(false),
|
||||
queryReplaceVolDo(false),
|
||||
queryViewingResults(false),
|
||||
supportsOgg(false),
|
||||
supportsMP3(false),
|
||||
wavePreviewOn(false),
|
||||
wavePreviewKey((SDL_Scancode)0),
|
||||
wavePreviewNote(0),
|
||||
|
|
@ -9011,6 +9145,8 @@ FurnaceGUI::FurnaceGUI():
|
|||
csExportResult(NULL),
|
||||
csExportTarget(false),
|
||||
csExportDone(false),
|
||||
audioExportFilterName("???"),
|
||||
audioExportFilterExt("*"),
|
||||
dmfExportVersion(0),
|
||||
curExportType(GUI_EXPORT_NONE),
|
||||
romTarget(DIV_ROM_ABSTRACT),
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
#include "../engine/workPool.h"
|
||||
#include "../engine/waveSynth.h"
|
||||
#include "imgui.h"
|
||||
#include "imgui_internal.h"
|
||||
#include "imgui_impl_sdl2.h"
|
||||
#include <SDL.h>
|
||||
#include <fftw3.h>
|
||||
|
|
@ -38,6 +39,7 @@
|
|||
#include "../pch.h"
|
||||
|
||||
#include "fileDialog.h"
|
||||
#include "newFilePicker.h"
|
||||
|
||||
#define FURNACE_APP_ID "org.tildearrow.furnace"
|
||||
|
||||
|
|
@ -235,6 +237,7 @@ enum FurnaceGUIColors {
|
|||
GUI_COLOR_FILE_SONG_IMPORT,
|
||||
GUI_COLOR_FILE_INSTR,
|
||||
GUI_COLOR_FILE_AUDIO,
|
||||
GUI_COLOR_FILE_AUDIO_COMPRESSED,
|
||||
GUI_COLOR_FILE_WAVE,
|
||||
GUI_COLOR_FILE_VGM,
|
||||
GUI_COLOR_FILE_ZSM,
|
||||
|
|
@ -720,6 +723,7 @@ enum FurnaceGUIActions {
|
|||
GUI_ACTION_FOLLOW_PATTERN,
|
||||
GUI_ACTION_FULLSCREEN,
|
||||
GUI_ACTION_TX81Z_REQUEST,
|
||||
GUI_ACTION_OPEN_EDIT_MENU,
|
||||
GUI_ACTION_PANIC,
|
||||
GUI_ACTION_CLEAR,
|
||||
|
||||
|
|
@ -1466,8 +1470,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),
|
||||
|
|
@ -1548,6 +1552,18 @@ struct FurnaceGUIPerfMetric {
|
|||
elapsed(0) {}
|
||||
};
|
||||
|
||||
struct FurnaceGUIUncompFont {
|
||||
const void* origPtr;
|
||||
size_t origLen;
|
||||
void* data;
|
||||
size_t len;
|
||||
FurnaceGUIUncompFont(const void* ptr, size_t len, void* d, size_t l):
|
||||
origPtr(ptr),
|
||||
origLen(len),
|
||||
data(d),
|
||||
len(l) {}
|
||||
};
|
||||
|
||||
struct FurnaceGUIBackupEntry {
|
||||
String name;
|
||||
uint64_t size;
|
||||
|
|
@ -1696,7 +1712,7 @@ class FurnaceGUI {
|
|||
bool vgmExportDirectStream, displayInsTypeList, displayWaveSizeList;
|
||||
bool portrait, injectBackUp, mobileMenuOpen, warnColorPushed;
|
||||
bool wantCaptureKeyboard, oldWantCaptureKeyboard, displayMacroMenu;
|
||||
bool displayNew, displayExport, displayPalette, fullScreen, preserveChanPos, sysDupCloneChannels, sysDupEnd, noteInputPoly, notifyWaveChange;
|
||||
bool displayNew, displayExport, displayPalette, fullScreen, preserveChanPos, sysDupCloneChannels, sysDupEnd, noteInputPoly, notifyWaveChange, notifySampleChange;
|
||||
bool wantScrollListIns, wantScrollListWave, wantScrollListSample;
|
||||
bool displayPendingIns, pendingInsSingle, displayPendingRawSample, snesFilterHex, modTableHex, displayEditString;
|
||||
bool displayPendingSamples, replacePendingSample;
|
||||
|
|
@ -1754,6 +1770,7 @@ class FurnaceGUI {
|
|||
FurnaceGUIMobileScenes mobScene;
|
||||
|
||||
FurnaceGUIFileDialog* fileDialog;
|
||||
FurnaceFilePicker* newFilePicker;
|
||||
|
||||
int scrW, scrH, scrConfW, scrConfH, canvasW, canvasH;
|
||||
int scrX, scrY, scrConfX, scrConfY;
|
||||
|
|
@ -1780,6 +1797,7 @@ class FurnaceGUI {
|
|||
MIDIMap midiMap;
|
||||
int learning;
|
||||
|
||||
std::vector<FurnaceGUIUncompFont> fontCache;
|
||||
ImFont* mainFont;
|
||||
ImFont* iconFont;
|
||||
ImFont* furIconFont;
|
||||
|
|
@ -1987,7 +2005,6 @@ class FurnaceGUI {
|
|||
int iCannotWait;
|
||||
int orderButtonPos;
|
||||
int compress;
|
||||
int newPatternFormat;
|
||||
int renderClearPos;
|
||||
int insertBehavior;
|
||||
int pullDeleteRow;
|
||||
|
|
@ -2045,6 +2062,9 @@ class FurnaceGUI {
|
|||
int vibrationLength;
|
||||
int s3mOPL3;
|
||||
int songNotesWrap;
|
||||
int rackShowLEDs;
|
||||
int sampleImportInstDetune;
|
||||
int mixerStyle;
|
||||
String mainFontPath;
|
||||
String headFontPath;
|
||||
String patFontPath;
|
||||
|
|
@ -2239,7 +2259,6 @@ class FurnaceGUI {
|
|||
iCannotWait(0),
|
||||
orderButtonPos(2),
|
||||
compress(1),
|
||||
newPatternFormat(1),
|
||||
renderClearPos(0),
|
||||
insertBehavior(1),
|
||||
pullDeleteRow(1),
|
||||
|
|
@ -2297,6 +2316,9 @@ class FurnaceGUI {
|
|||
vibrationLength(20),
|
||||
s3mOPL3(1),
|
||||
songNotesWrap(0),
|
||||
rackShowLEDs(1),
|
||||
sampleImportInstDetune(0),
|
||||
mixerStyle(1),
|
||||
mainFontPath(""),
|
||||
headFontPath(""),
|
||||
patFontPath(""),
|
||||
|
|
@ -2388,6 +2410,7 @@ class FurnaceGUI {
|
|||
bool collapseWindow, demandScrollX, fancyPattern, firstFrame, tempoView, waveHex, waveSigned, waveGenVisible, lockLayout, editOptsVisible, latchNibble, nonLatchNibble;
|
||||
bool keepLoopAlive, keepGrooveAlive, orderScrollLocked, orderScrollTolerance, dragMobileMenu, dragMobileEditButton, wantGrooveListFocus;
|
||||
bool mobilePatSel;
|
||||
bool openEditMenu;
|
||||
unsigned char lastAssetType;
|
||||
FurnaceGUIWindows curWindow, nextWindow, curWindowLast;
|
||||
std::atomic<FurnaceGUIWindows> curWindowThreadSafe;
|
||||
|
|
@ -2473,6 +2496,7 @@ class FurnaceGUI {
|
|||
std::vector<FurnaceGUISysCategory> sysCategories;
|
||||
|
||||
std::vector<String> audioLoadFormats;
|
||||
bool supportsOgg, supportsMP3;
|
||||
|
||||
bool wavePreviewOn;
|
||||
SDL_Scancode wavePreviewKey;
|
||||
|
|
@ -2797,6 +2821,7 @@ class FurnaceGUI {
|
|||
|
||||
// export options
|
||||
DivAudioExportOptions audioExportOptions;
|
||||
String audioExportFilterName, audioExportFilterExt;
|
||||
int dmfExportVersion;
|
||||
FurnaceGUIExportTypes curExportType;
|
||||
DivCSOptions csExportOptions;
|
||||
|
|
@ -2846,6 +2871,9 @@ class FurnaceGUI {
|
|||
void renderFMPreviewOPZ(const DivInstrumentFM& params, int pos=0);
|
||||
void renderFMPreviewESFM(const DivInstrumentFM& params, const DivInstrumentESFM& esfmParams, int pos=0);
|
||||
|
||||
void VerticalText(const char* fmt, ...);
|
||||
void VerticalText(float maxSize, bool centered, const char* fmt, ...);
|
||||
|
||||
// combo with locale
|
||||
static bool LocalizedComboGetter(void* data, int idx, const char** out_text);
|
||||
|
||||
|
|
@ -2860,7 +2888,10 @@ class FurnaceGUI {
|
|||
// inverted checkbox
|
||||
bool InvCheckbox(const char* label, bool* value);
|
||||
|
||||
bool NoteSelector(int* value, bool showOffRel, int octaveMin=-5, int octaveMax=9);
|
||||
|
||||
// mixer stuff
|
||||
bool chipMixer(int which, ImVec2 size);
|
||||
ImVec2 calcPortSetSize(String label, int ins, int outs);
|
||||
bool portSet(String label, unsigned int portSetID, int ins, int outs, int activeIns, int activeOuts, int& clickedPort, std::map<unsigned int,ImVec2>& portPos);
|
||||
|
||||
|
|
@ -2970,8 +3001,10 @@ class FurnaceGUI {
|
|||
void drawTutorial();
|
||||
void drawXYOsc();
|
||||
void drawUserPresets();
|
||||
void drawSystemChannelInfo(const DivSysDef* whichDef);
|
||||
|
||||
float drawSystemChannelInfo(const DivSysDef* whichDef, int keyHitOffset=-1, float width=-1.0f);
|
||||
void drawSystemChannelInfoText(const DivSysDef* whichDef);
|
||||
void drawVolMeterInternal(ImDrawList* dl, ImRect rect, float* data, int chans, bool aspectRatio);
|
||||
|
||||
void assignActionMap(std::map<int,int>& actionMap, int first, int last);
|
||||
void drawKeybindSettingsTableRow(FurnaceGUIActions actionIdx);
|
||||
|
|
@ -3128,10 +3161,9 @@ class FurnaceGUI {
|
|||
void showWarning(String what, FurnaceGUIWarnings type);
|
||||
void showError(String what);
|
||||
String getLastError();
|
||||
const char* noteNameNormal(short note, short octave);
|
||||
const char* noteNameNormal(short note);
|
||||
const char* noteName(short note);
|
||||
const char* noteName(short note, short octave);
|
||||
bool decodeNote(const char* what, short& note, short& octave);
|
||||
bool decodeNote(const char* what, short& note);
|
||||
void bindEngine(DivEngine* eng);
|
||||
void enableSafeMode();
|
||||
void updateScroll(int amount);
|
||||
|
|
|
|||
|
|
@ -603,6 +603,7 @@ const FurnaceGUIActionDef guiActions[GUI_ACTION_MAX]={
|
|||
D("FOLLOW_PATTERN", _N("Follow pattern"), 0),
|
||||
D("FULLSCREEN", _N("Toggle full-screen"), SDLK_F11),
|
||||
D("TX81Z_REQUEST", _N("Request voice from TX81Z"), 0),
|
||||
D("OPEN_EDIT_MENU", _N("Open pattern edit menu"), 0),
|
||||
D("PANIC", _N("Panic"), SDLK_F12),
|
||||
D("CLEAR", _N("Clear song data"), 0),
|
||||
|
||||
|
|
@ -932,6 +933,7 @@ const FurnaceGUIColorDef guiColors[GUI_COLOR_MAX]={
|
|||
D(GUI_COLOR_FILE_SONG_IMPORT,"",ImVec4(0.5f,1.0f,0.8f,1.0f)),
|
||||
D(GUI_COLOR_FILE_INSTR,"",ImVec4(1.0f,0.5f,0.5f,1.0f)),
|
||||
D(GUI_COLOR_FILE_AUDIO,"",ImVec4(1.0f,1.0f,0.5f,1.0f)),
|
||||
D(GUI_COLOR_FILE_AUDIO_COMPRESSED,"",ImVec4(0.7f,1.0f,0.3f,1.0f)),
|
||||
D(GUI_COLOR_FILE_WAVE,"",ImVec4(1.0f,0.75f,0.5f,1.0f)),
|
||||
D(GUI_COLOR_FILE_VGM,"",ImVec4(1.0f,1.0f,0.5f,1.0f)),
|
||||
D(GUI_COLOR_FILE_ZSM,"",ImVec4(1.0f,1.0f,0.5f,1.0f)),
|
||||
|
|
@ -1331,6 +1333,7 @@ const int availableSystems[]={
|
|||
DIV_SYSTEM_SUPERVISION,
|
||||
DIV_SYSTEM_UPD1771C,
|
||||
DIV_SYSTEM_SID3,
|
||||
DIV_SYSTEM_MULTIPCM,
|
||||
0 // don't remove this last one!
|
||||
};
|
||||
|
||||
|
|
@ -1463,6 +1466,7 @@ const int chipsSample[]={
|
|||
DIV_SYSTEM_GBA_MINMOD,
|
||||
DIV_SYSTEM_OPL4,
|
||||
DIV_SYSTEM_OPL4_DRUMS,
|
||||
DIV_SYSTEM_MULTIPCM,
|
||||
0 // don't remove this last one!
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -838,6 +838,22 @@ String macroSoundUnitWaves(int id, float val, void* u) {
|
|||
return fmt::sprintf("%d: %s",id,label);
|
||||
}
|
||||
|
||||
String macroTFXModes(int id, float val, void* u) {
|
||||
switch (((int)val)&3) {
|
||||
case 0:
|
||||
return _("Disabled");
|
||||
case 1:
|
||||
return _("PWM");
|
||||
case 2:
|
||||
return _("SyncBuzzer");
|
||||
case 3:
|
||||
return _("Reserved");
|
||||
default:
|
||||
return "???";
|
||||
}
|
||||
return "???";
|
||||
}
|
||||
|
||||
String macroSID3SpecialWaves(int id, float val, void* u) {
|
||||
if ((int)val<0 || (int)val>=SID3_NUM_SPECIAL_WAVES) return "???";
|
||||
|
||||
|
|
@ -1936,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));
|
||||
|
|
@ -1962,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));
|
||||
|
|
@ -2099,12 +2115,12 @@ void FurnaceGUI::drawMacroEdit(FurnaceGUIMacroDesc& i, int totalFit, float avail
|
|||
}
|
||||
}
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding,ImVec2(0.0f,0.0f));
|
||||
|
||||
if (MACRO_VZOOM<1) {
|
||||
if (i.macro->macroType==DIV_MACRO_ARP || i.isArp) {
|
||||
MACRO_VZOOM=24;
|
||||
MACRO_VSCROLL=120-12;
|
||||
} else if (i.macro->macroType==DIV_MACRO_PITCH || i.isPitch) {
|
||||
}
|
||||
else if ((i.macro->macroType == DIV_MACRO_PITCH || i.isPitch) || (i.macro->macroType == DIV_MACRO_EX7 && i.isPitch)) {
|
||||
MACRO_VZOOM=128;
|
||||
MACRO_VSCROLL=2048-64;
|
||||
} else {
|
||||
|
|
@ -3465,6 +3481,7 @@ void FurnaceGUI::insTabSample(DivInstrument* ins) {
|
|||
if (ImGui::InputInt(_("Sample bank slot##BANKSLOT"),&ins->x1_010.bankSlot,1,4)) { PARAMETER
|
||||
if (ins->x1_010.bankSlot<0) ins->x1_010.bankSlot=0;
|
||||
if (ins->x1_010.bankSlot>=7) ins->x1_010.bankSlot=7;
|
||||
notifySampleChange=true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3478,6 +3495,7 @@ void FurnaceGUI::insTabSample(DivInstrument* ins) {
|
|||
id=fmt::sprintf("%d: %s",i,e->song.sample[i]->name);
|
||||
if (ImGui::Selectable(id.c_str(),ins->amiga.initSample==i)) { PARAMETER
|
||||
ins->amiga.initSample=i;
|
||||
notifySampleChange=true;
|
||||
}
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
|
|
@ -3508,10 +3526,15 @@ void FurnaceGUI::insTabSample(DivInstrument* ins) {
|
|||
}
|
||||
}
|
||||
ImGui::EndDisabled();
|
||||
} else {
|
||||
ins->amiga.useWave=false;
|
||||
}
|
||||
// Note map
|
||||
ImGui::BeginDisabled(ins->amiga.useWave);
|
||||
P(ImGui::Checkbox(_("Use sample map"),&ins->amiga.useNoteMap));
|
||||
if ((ins->type==DIV_INS_MULTIPCM) && ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip(_("Only for OPL4 PCM."));
|
||||
}
|
||||
if (ins->amiga.useNoteMap) {
|
||||
if (ImGui::IsMouseClicked(ImGuiMouseButton_Left) && ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows)) sampleMapFocused=false;
|
||||
if (curWindowLast!=GUI_WINDOW_INS_EDIT) sampleMapFocused=false;
|
||||
|
|
@ -4671,7 +4694,7 @@ void FurnaceGUI::insTabFM(DivInstrument* ins) {
|
|||
op.egt=egtOn;
|
||||
}
|
||||
if (egtOn) {
|
||||
pushWarningColor(susOn && e->song.linearPitch!=2);
|
||||
pushWarningColor(susOn && !e->song.linearPitch);
|
||||
if (ImGui::Checkbox(_("Pitch control"),&susOn)) { PARAMETER
|
||||
op.sus=susOn;
|
||||
// HACK: reset zoom and scroll in fixed pitch macros so that they draw correctly
|
||||
|
|
@ -4680,7 +4703,7 @@ void FurnaceGUI::insTabFM(DivInstrument* ins) {
|
|||
}
|
||||
popWarningColor();
|
||||
if (ImGui::IsItemHovered()) {
|
||||
if (susOn && e->song.linearPitch!=2) {
|
||||
if (susOn && !e->song.linearPitch) {
|
||||
ImGui::SetTooltip(_("only works on linear pitch! go to Compatibility Flags > Pitch/Playback and set Pitch linearity to Full."));
|
||||
} else {
|
||||
ImGui::SetTooltip(_("use op's arpeggio and pitch macros control instead of block/f-num macros"));
|
||||
|
|
@ -5447,7 +5470,7 @@ void FurnaceGUI::insTabFM(DivInstrument* ins) {
|
|||
P(CWSliderScalar("##FINE",ImGuiDataType_U8,&op.dvb,&_ZERO,&_FIFTEEN,tempID)); rightClickable
|
||||
} else {
|
||||
bool susOn=op.sus;
|
||||
pushWarningColor(susOn && e->song.linearPitch!=2);
|
||||
pushWarningColor(susOn && !e->song.linearPitch);
|
||||
if (ImGui::Checkbox(_("Pitch control"),&susOn)) { PARAMETER
|
||||
op.sus=susOn;
|
||||
// HACK: reset zoom and scroll in fixed pitch macros so that they draw correctly
|
||||
|
|
@ -5456,7 +5479,7 @@ void FurnaceGUI::insTabFM(DivInstrument* ins) {
|
|||
}
|
||||
popWarningColor();
|
||||
if (ImGui::IsItemHovered()) {
|
||||
if (susOn && e->song.linearPitch!=2) {
|
||||
if (susOn && !e->song.linearPitch) {
|
||||
ImGui::SetTooltip(_("only works on linear pitch! go to Compatibility Flags > Pitch/Playback and set Pitch linearity to Full."));
|
||||
} else {
|
||||
ImGui::SetTooltip(_("use op's arpeggio and pitch macros control instead of block/f-num macros"));
|
||||
|
|
@ -5770,7 +5793,7 @@ void FurnaceGUI::insTabFM(DivInstrument* ins) {
|
|||
bool susOn=op.sus;
|
||||
if (fixedOn) {
|
||||
ImGui::SameLine();
|
||||
pushWarningColor(susOn && e->song.linearPitch!=2);
|
||||
pushWarningColor(susOn && !e->song.linearPitch);
|
||||
if (ImGui::Checkbox(_("Pitch control"),&susOn)) { PARAMETER
|
||||
op.sus=susOn;
|
||||
// HACK: reset zoom and scroll in fixed pitch macros so that they draw correctly
|
||||
|
|
@ -5779,7 +5802,7 @@ void FurnaceGUI::insTabFM(DivInstrument* ins) {
|
|||
}
|
||||
popWarningColor();
|
||||
if (ImGui::IsItemHovered()) {
|
||||
if (susOn && e->song.linearPitch!=2) {
|
||||
if (susOn && !e->song.linearPitch) {
|
||||
ImGui::SetTooltip(_("only works on linear pitch! go to Compatibility Flags > Pitch/Playback and set Pitch linearity to Full."));
|
||||
} else {
|
||||
ImGui::SetTooltip(_("use op's arpeggio and pitch macros control instead of block/f-num macros"));
|
||||
|
|
@ -6424,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()) {
|
||||
|
|
@ -6457,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()) {
|
||||
|
|
@ -7697,7 +7720,7 @@ void FurnaceGUI::drawInsEdit() {
|
|||
modTableInt[i]=ins->fds.modTable[i];
|
||||
}
|
||||
ImVec2 modTableSize=ImVec2(ImGui::GetContentRegionAvail().x,96.0f*dpiScale);
|
||||
PlotCustom("ModTable",modTable,32,0,NULL,-4,3,modTableSize,sizeof(float),ImVec4(1.0f,1.0f,1.0f,1.0f),0,NULL,NULL,true);
|
||||
PlotCustom("##ModTable",modTable,32,0,NULL,-4,3,modTableSize,sizeof(float),ImVec4(1.0f,1.0f,1.0f,1.0f),0,NULL,NULL,true);
|
||||
if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) {
|
||||
macroDragStart=ImGui::GetItemRectMin();
|
||||
macroDragAreaSize=modTableSize;
|
||||
|
|
@ -7748,7 +7771,7 @@ void FurnaceGUI::drawInsEdit() {
|
|||
modTableInt[i]=modTableHex?((unsigned char)ins->fds.modTable[i]):ins->fds.modTable[i];
|
||||
}
|
||||
ImVec2 modTableSize=ImVec2(ImGui::GetContentRegionAvail().x,256.0f*dpiScale);
|
||||
PlotCustom("ModTable",modTable,32,0,NULL,-128,127,modTableSize,sizeof(float),ImVec4(1.0f,1.0f,1.0f,1.0f),0,NULL,NULL,true);
|
||||
PlotCustom("##ModTable",modTable,32,0,NULL,-128,127,modTableSize,sizeof(float),ImVec4(1.0f,1.0f,1.0f,1.0f),0,NULL,NULL,true);
|
||||
if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) {
|
||||
macroDragStart=ImGui::GetItemRectMin();
|
||||
macroDragAreaSize=modTableSize;
|
||||
|
|
@ -8755,16 +8778,12 @@ void FurnaceGUI::drawInsEdit() {
|
|||
{
|
||||
if (ImGui::BeginTabItem(_("Timer Macros")))
|
||||
{
|
||||
ImGui::Text(_("warning: timer effects are not supported by VGM export!"));
|
||||
macroList.push_back(FurnaceGUIMacroDesc(_("Timer FX"),&ins->std.ex6Macro,0,3,64,uiColors[GUI_COLOR_MACRO_OTHER]));
|
||||
macroList.push_back(FurnaceGUIMacroDesc(_("TFX Offset"),&ins->std.ex7Macro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true));
|
||||
ImGui::Text(_("warning: timer effects require direct stream mode to be enabled during VGM export!"));
|
||||
macroList.push_back(FurnaceGUIMacroDesc(_("Timer FX"),&ins->std.ex6Macro,0,2,64,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,macroTFXModes));
|
||||
macroList.push_back(FurnaceGUIMacroDesc(_("Timer Offset"),&ins->std.ex7Macro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true,macroRelativeMode,NULL,false,NULL,false,NULL,false,true));
|
||||
macroList.push_back(FurnaceGUIMacroDesc(_("Timer Num"),&ins->std.ex8Macro,0,15,64,uiColors[GUI_COLOR_MACRO_OTHER]));
|
||||
macroList.push_back(FurnaceGUIMacroDesc(_("Timer Den"),&ins->std.fmsMacro,0,15,64,uiColors[GUI_COLOR_MACRO_OTHER]));
|
||||
macroList.push_back(FurnaceGUIMacroDesc(_("PWM Boundary"),&ins->std.amsMacro,0,15,64,uiColors[GUI_COLOR_MACRO_OTHER]));
|
||||
// workaround, because the gui will not set
|
||||
// zoom or scroll if we're not in macros tab
|
||||
ins->temp.vZoom[DIV_MACRO_EX7]=128;
|
||||
ins->temp.vScroll[DIV_MACRO_EX7]=2048-64;
|
||||
drawMacros(macroList,macroEditStateMacros,ins);
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -226,74 +226,58 @@ void FurnaceGUI::drawMixer() {
|
|||
if (ImGui::Begin("Mixer",&mixerOpen,globalWinFlags|(settings.allowEditDocking?0:ImGuiWindowFlags_NoDocking),_("Mixer"))) {
|
||||
if (ImGui::BeginTabBar("MixerView")) {
|
||||
if (ImGui::BeginTabItem(_("Mixer"))) {
|
||||
if (ImGui::SliderFloat(_("Master Volume"),&e->song.masterVol,0,3,"%.2fx")) {
|
||||
float maxY=ImGui::GetContentRegionAvail().y;
|
||||
VerticalText(maxY,true,_("Master Volume"));
|
||||
ImGui::SameLine();
|
||||
if (settings.mixerStyle==2) {
|
||||
ImVec2 pos=ImGui::GetCursorScreenPos();
|
||||
drawVolMeterInternal(ImGui::GetWindowDrawList(),ImRect(pos,pos+ImVec2(40*dpiScale,maxY)),peak,e->getAudioDescGot().outChans,false);
|
||||
ImGui::PushStyleColor(ImGuiCol_FrameBg,0);
|
||||
ImGui::PushStyleColor(ImGuiCol_FrameBgActive,0);
|
||||
ImGui::PushStyleColor(ImGuiCol_FrameBgHovered,127<<IM_COL32_A_SHIFT);
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding,0);
|
||||
}
|
||||
if (ImGui::VSliderFloat("##mixerMaster",ImVec2(40*dpiScale,maxY),&e->song.masterVol,0,3,"%.2fx")) {
|
||||
if (e->song.masterVol<0) e->song.masterVol=0;
|
||||
if (e->song.masterVol>3) e->song.masterVol=3;
|
||||
MARK_MODIFIED;
|
||||
} rightClickable
|
||||
|
||||
if (ImGui::BeginTable("CurPortSet",2)) {
|
||||
ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthStretch);
|
||||
ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthFixed);
|
||||
|
||||
for (int i=0; i<e->song.systemLen; i++) {
|
||||
bool doInvert=e->song.systemVol[i]<0;
|
||||
float vol=fabs(e->song.systemVol[i]);
|
||||
|
||||
ImGui::PushID(i);
|
||||
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::AlignTextToFramePadding();
|
||||
ImGui::Text("%d. %s",i+1,getSystemName(e->song.system[i]));
|
||||
ImGui::TableNextColumn();
|
||||
if (ImGui::Checkbox(_("Invert"),&doInvert)) {
|
||||
e->song.systemVol[i]=-e->song.systemVol[i];
|
||||
MARK_MODIFIED;
|
||||
}
|
||||
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||
if (CWSliderFloat("##Volume",&vol,0,2)) {
|
||||
if (doInvert) {
|
||||
if (vol<0.0001) vol=0.0001;
|
||||
}
|
||||
if (vol<0) vol=0;
|
||||
if (vol>10) vol=10;
|
||||
e->song.systemVol[i]=(doInvert)?-vol:vol;
|
||||
MARK_MODIFIED;
|
||||
} rightClickable
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text(_("Volume"));
|
||||
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||
if (CWSliderFloat("##Panning",&e->song.systemPan[i],-1.0f,1.0f)) {
|
||||
if (e->song.systemPan[i]<-1.0f) e->song.systemPan[i]=-1.0f;
|
||||
if (e->song.systemPan[i]>1.0f) e->song.systemPan[i]=1.0f;
|
||||
MARK_MODIFIED;
|
||||
} rightClickable
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text(_("Panning"));
|
||||
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||
if (CWSliderFloat("##FrontRear",&e->song.systemPanFR[i],-1.0f,1.0f)) {
|
||||
if (e->song.systemPanFR[i]<-1.0f) e->song.systemPanFR[i]=-1.0f;
|
||||
if (e->song.systemPanFR[i]>1.0f) e->song.systemPanFR[i]=1.0f;
|
||||
MARK_MODIFIED;
|
||||
} rightClickable
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text(_("Front/Rear"));
|
||||
|
||||
ImGui::PopID();
|
||||
}
|
||||
|
||||
ImGui::EndTable();
|
||||
ImGui::SameLine();
|
||||
if (settings.mixerStyle==2) {
|
||||
ImGui::PopStyleColor(3);
|
||||
ImGui::PopStyleVar();
|
||||
} else if (settings.mixerStyle==1) {
|
||||
ImVec2 pos=ImGui::GetCursorScreenPos();
|
||||
drawVolMeterInternal(ImGui::GetWindowDrawList(),ImRect(pos,pos+ImVec2(40*dpiScale,maxY)),peak,e->getAudioDescGot().outChans,false);
|
||||
ImGui::Dummy(ImVec2(40*dpiScale,maxY));
|
||||
ImGui::SameLine();
|
||||
}
|
||||
|
||||
const float itemWidth=60*dpiScale;
|
||||
// figure out if we need to cut the height for the scrollbar
|
||||
float itemCalcWidth=
|
||||
itemWidth+
|
||||
1.5f*ImGui::GetStyle().FramePadding.x+
|
||||
4*ImGui::GetStyle().FramePadding.x+
|
||||
dpiScale+ // separator
|
||||
(settings.mixerStyle==1?(itemWidth-ImGui::GetFontSize()-ImGui::GetStyle().FramePadding.x):0)
|
||||
;
|
||||
float realwidth=ImGui::GetWindowWidth()-ImGui::GetCursorPosX();
|
||||
if ((itemCalcWidth*e->song.systemLen)>realwidth) maxY-=ImGui::GetStyle().ScrollbarSize;
|
||||
if (ImGui::BeginChild("##mixerPerChipContainer",ImVec2(0,0),0,ImGuiWindowFlags_HorizontalScrollbar)) {
|
||||
for (int i=0; i<e->song.systemLen; i++) {
|
||||
ImGui::GetWindowDrawList()->AddRectFilled(
|
||||
ImGui::GetCursorScreenPos(),
|
||||
ImGui::GetCursorScreenPos()+ImVec2(dpiScale,maxY),
|
||||
ImGui::GetColorU32(ImGuiCol_Separator)
|
||||
);
|
||||
ImGui::Dummy(ImVec2(dpiScale,maxY));
|
||||
ImGui::SameLine();
|
||||
if (chipMixer(i,ImVec2(itemWidth,maxY))) MARK_MODIFIED;
|
||||
ImGui::SameLine();
|
||||
}
|
||||
}
|
||||
ImGui::EndChild();
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
if (ImGui::BeginTabItem(_("Patchbay"))) {
|
||||
|
|
@ -459,3 +443,88 @@ void FurnaceGUI::drawMixer() {
|
|||
if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_MIXER;
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
bool FurnaceGUI::chipMixer(int which, ImVec2 size) {
|
||||
bool ret=false;
|
||||
ImGui::PushID(which);
|
||||
ImGui::BeginGroup();
|
||||
float textHeight=ImGui::GetFontSize();
|
||||
|
||||
float vol=fabs(e->song.systemVol[which]);
|
||||
bool doInvert=e->song.systemVol[which]<0;
|
||||
if (ImGui::Checkbox("##ChipInvert",&doInvert)) {
|
||||
e->song.systemVol[which]=doInvert?-vol:vol;
|
||||
ret=true;
|
||||
}
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip(_("Invert"));
|
||||
}
|
||||
// hack to get the same line from here
|
||||
ImGui::SameLine();
|
||||
ImVec2 curPos=ImGui::GetCursorPos();
|
||||
ImGui::NewLine();
|
||||
|
||||
float volSliderHeight=size.y-ImGui::GetStyle().FramePadding.y*7-textHeight*2;
|
||||
|
||||
VerticalText(volSliderHeight-(ImGui::GetCursorPosY()-curPos.y),true,"%s",e->getSystemName(e->song.system[which]));
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
float vTextWidth=textHeight+2*ImGui::GetStyle().FramePadding.x;
|
||||
|
||||
ImGui::SetCursorPos(curPos);
|
||||
ImVec2 pos=ImGui::GetCursorScreenPos();
|
||||
if (settings.mixerStyle==2) {
|
||||
drawVolMeterInternal(ImGui::GetWindowDrawList(),ImRect(pos,pos+ImVec2(size.x-vTextWidth,volSliderHeight)),e->chipPeak[which],e->getDispatch(which)->getOutputCount(),false);
|
||||
|
||||
ImGui::PushStyleColor(ImGuiCol_FrameBg,0);
|
||||
ImGui::PushStyleColor(ImGuiCol_FrameBgActive,0);
|
||||
ImGui::PushStyleColor(ImGuiCol_FrameBgHovered,127<<IM_COL32_A_SHIFT);
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding,0);
|
||||
}
|
||||
if (ImGui::VSliderFloat("##ChipVol",ImVec2(size.x-vTextWidth,volSliderHeight),&vol,0.0f,2.0f)) {
|
||||
if (doInvert) {
|
||||
if (vol<0.0001) vol=0.0001;
|
||||
}
|
||||
if (vol<0) vol=0;
|
||||
if (vol>10) vol=10;
|
||||
e->song.systemVol[which]=doInvert?-vol:vol;
|
||||
ret=true;
|
||||
} rightClickable
|
||||
if (ImGui::IsItemHovered(ImGuiHoveredFlags_DelayShort)) {
|
||||
ImGui::SetTooltip(_("Volume"));
|
||||
}
|
||||
if (settings.mixerStyle==2) {
|
||||
ImGui::PopStyleVar(1);
|
||||
ImGui::PopStyleColor(3);
|
||||
} else if (settings.mixerStyle==1) {
|
||||
ImGui::SetCursorPos(curPos+ImVec2(size.x-vTextWidth+ImGui::GetStyle().FramePadding.x,0));
|
||||
pos=ImGui::GetCursorScreenPos();
|
||||
ImGui::Dummy(ImVec2(size.x-vTextWidth,volSliderHeight));
|
||||
drawVolMeterInternal(ImGui::GetWindowDrawList(),ImRect(pos,pos+ImVec2(size.x-vTextWidth,volSliderHeight)),e->chipPeak[which],e->getDispatch(which)->getOutputCount(),false);
|
||||
}
|
||||
float panSliderWidth=size.x+1.5f*ImGui::GetStyle().FramePadding.x+((settings.mixerStyle!=1)?0:size.x-vTextWidth+ImGui::GetStyle().FramePadding.x);
|
||||
ImGui::SetNextItemWidth(panSliderWidth);
|
||||
if (ImGui::SliderFloat("##ChipPan",&e->song.systemPan[which],-1.0f,1.0f)) {
|
||||
if (e->song.systemPan[which]<-1.0f) e->song.systemPan[which]=-1.0f;
|
||||
if (e->song.systemPan[which]>1.0f) e->song.systemPan[which]=1.0f;
|
||||
ret=true;
|
||||
} rightClickable
|
||||
if (ImGui::IsItemHovered(ImGuiHoveredFlags_DelayShort)) {
|
||||
ImGui::SetTooltip(_("Panning"));
|
||||
}
|
||||
|
||||
ImGui::SetNextItemWidth(panSliderWidth);
|
||||
if (ImGui::SliderFloat("##ChipPanFR",&e->song.systemPanFR[which],-1.0f,1.0f)) {
|
||||
if (e->song.systemPanFR[which]<-1.0f) e->song.systemPanFR[which]=-1.0f;
|
||||
if (e->song.systemPanFR[which]>1.0f) e->song.systemPanFR[which]=1.0f;
|
||||
ret=true;
|
||||
} rightClickable
|
||||
if (ImGui::IsItemHovered(ImGuiHoveredFlags_DelayShort)) {
|
||||
ImGui::SetTooltip(_("Front/Rear"));
|
||||
}
|
||||
|
||||
ImGui::EndGroup();
|
||||
ImGui::PopID();
|
||||
return ret;
|
||||
}
|
||||
|
|
|
|||
1983
src/gui/newFilePicker.cpp
Normal file
1983
src/gui/newFilePicker.cpp
Normal file
File diff suppressed because it is too large
Load diff
186
src/gui/newFilePicker.h
Normal file
186
src/gui/newFilePicker.h
Normal file
|
|
@ -0,0 +1,186 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2025 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef _NEW_FILE_DIALOG_H
|
||||
#define _NEW_FILE_DIALOG_H
|
||||
|
||||
#include "../ta-utils.h"
|
||||
#include "../engine/config.h"
|
||||
#include <stdint.h>
|
||||
#include <functional>
|
||||
#include <thread>
|
||||
#include "imgui.h"
|
||||
|
||||
enum FilePickerStatus {
|
||||
FP_STATUS_WAITING=0,
|
||||
FP_STATUS_ACCEPTED,
|
||||
FP_STATUS_CLOSED
|
||||
};
|
||||
|
||||
enum FileType {
|
||||
FP_TYPE_UNKNOWN=0,
|
||||
FP_TYPE_NORMAL,
|
||||
FP_TYPE_DIR,
|
||||
FP_TYPE_LINK,
|
||||
FP_TYPE_PIPE,
|
||||
FP_TYPE_SOCKET,
|
||||
FP_TYPE_CHARDEV,
|
||||
FP_TYPE_BLOCKDEV,
|
||||
|
||||
FP_TYPE_MAX
|
||||
};
|
||||
|
||||
enum FilePickerFlags {
|
||||
// display file picker as a modal pop-up
|
||||
FP_FLAGS_MODAL=1,
|
||||
// don't close the file picker on result
|
||||
FP_FLAGS_NO_CLOSE=2,
|
||||
// confirm overwrite and don't auto-acknowledge-on-tap on mobile
|
||||
FP_FLAGS_SAVE=4,
|
||||
// allow multiple selection
|
||||
FP_FLAGS_MULTI_SELECT=8,
|
||||
// directory selection mode
|
||||
FP_FLAGS_DIR_SELECT=16,
|
||||
// allows you to embed the file picker in an existing window (with draw())
|
||||
// DO NOT USE with FP_FLAGS_MODAL!
|
||||
FP_FLAGS_EMBEDDABLE=32
|
||||
};
|
||||
|
||||
typedef std::function<void(const char*)> FilePickerSelectCallback;
|
||||
|
||||
class FurnaceFilePicker {
|
||||
enum SortModes {
|
||||
FP_SORT_NAME=0,
|
||||
FP_SORT_EXT,
|
||||
FP_SORT_SIZE,
|
||||
FP_SORT_DATE,
|
||||
|
||||
FP_SORT_MAX
|
||||
};
|
||||
struct FileTypeStyle {
|
||||
String ext;
|
||||
String icon;
|
||||
ImVec4 color;
|
||||
FileTypeStyle():
|
||||
ext(""), icon(""), color(0.0f,0.0f,0.0f,1.0f) {}
|
||||
};
|
||||
struct FileEntry {
|
||||
String path;
|
||||
String name;
|
||||
String nameLower;
|
||||
String ext;
|
||||
bool hasSize, hasTime, isDir, isHidden, isSelected;
|
||||
uint64_t size;
|
||||
struct tm time;
|
||||
FileType type;
|
||||
FileEntry():
|
||||
hasSize(false), hasTime(false), isDir(false), isHidden(false), isSelected(false),
|
||||
size(0), type(FP_TYPE_UNKNOWN) {}
|
||||
};
|
||||
std::vector<FileEntry*> entries;
|
||||
std::vector<FileEntry*> sortedEntries;
|
||||
std::vector<FileEntry*> filteredEntries;
|
||||
std::vector<FileEntry*> chosenEntries;
|
||||
std::vector<String> finalSelection;
|
||||
std::vector<String> filterOptions;
|
||||
std::thread* fileThread;
|
||||
std::mutex entryLock;
|
||||
String windowName;
|
||||
String path, filter, searchQuery;
|
||||
String failMessage;
|
||||
String homeDir;
|
||||
String entryName;
|
||||
String entryNameHint;
|
||||
ImGuiListClipper listClipper;
|
||||
ImVec2 minSize, maxSize;
|
||||
bool haveFiles, haveStat, stopReading, isOpen, isMobile;
|
||||
bool sortInvert[FP_SORT_MAX];
|
||||
bool multiSelect;
|
||||
bool confirmOverwrite, dirSelect, noClose, isModal, isEmbed, hasSizeConstraints;
|
||||
bool isPathBookmarked, isSearch;
|
||||
int scheduledSort, imguiFlags, editingBookmark;
|
||||
size_t curFilterType;
|
||||
float lastScrollY;
|
||||
int enforceScrollY;
|
||||
SortModes sortMode;
|
||||
FilePickerStatus curStatus;
|
||||
FilePickerSelectCallback selCallback;
|
||||
|
||||
std::vector<FileTypeStyle> fileTypeRegistry;
|
||||
FileTypeStyle defaultTypeStyle[FP_TYPE_MAX];
|
||||
|
||||
// for "create directory"
|
||||
String mkdirPath, mkdirError;
|
||||
|
||||
// for "create bookmark"
|
||||
String newBookmarkName, newBookmarkPath;
|
||||
|
||||
// for the "edit path" button
|
||||
String editablePath;
|
||||
bool editingPath;
|
||||
|
||||
// configuration
|
||||
String configPrefix;
|
||||
std::vector<String> bookmarks;
|
||||
bool showBookmarks;
|
||||
bool showHiddenFiles;
|
||||
bool singleClickSelect;
|
||||
bool clearSearchOnDirChange;
|
||||
bool sortDirsFirst;
|
||||
bool naturalSort;
|
||||
bool displayType, displaySize, displayDate;
|
||||
|
||||
void sortFiles();
|
||||
void filterFiles();
|
||||
void clearAllFiles();
|
||||
void updateEntryName();
|
||||
bool readDirectory(String path);
|
||||
String normalizePath(const String& which);
|
||||
bool isPathAbsolute(const String& p);
|
||||
void addBookmark(const String& p, String n="");
|
||||
FileEntry* makeEntry(void* _entry, const char* prefix=NULL);
|
||||
void completeStat();
|
||||
|
||||
void drawFileList(ImVec2& tableSize, bool& acknowledged);
|
||||
void drawBookmarks(ImVec2& tableSize, String& newDir);
|
||||
|
||||
public:
|
||||
void readDirectorySub();
|
||||
void searchSub(String subPath, int depth);
|
||||
void setHomeDir(String where);
|
||||
FilePickerStatus getStatus();
|
||||
const String& getPath();
|
||||
const String& getEntryName();
|
||||
const std::vector<String>& getSelected();
|
||||
void setMobile(bool val);
|
||||
void setSizeConstraints(const ImVec2& min, const ImVec2& max);
|
||||
bool draw(ImGuiWindowFlags winFlags=0);
|
||||
bool isOpened();
|
||||
void close();
|
||||
bool open(String name, String path, String hint, int flags, const std::vector<String>& filter, FilePickerSelectCallback selectCallback=NULL);
|
||||
void loadSettings(DivConfig& conf);
|
||||
void saveSettings(DivConfig& conf);
|
||||
void setTypeStyle(FileType type, ImVec4 color, String icon);
|
||||
void registerType(String ext, ImVec4 color, String icon);
|
||||
void clearTypes();
|
||||
void setConfigPrefix(String prefix);
|
||||
FurnaceFilePicker();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -289,6 +289,7 @@ void FurnaceGUI::drawNewSong() {
|
|||
orderCursor=-1;
|
||||
samplePos=0;
|
||||
updateSampleTex=true;
|
||||
notifySampleChange=true;
|
||||
selStart=SelectionPoint();
|
||||
selEnd=SelectionPoint();
|
||||
cursor=SelectionPoint();
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
@ -1907,6 +1908,7 @@ void FurnaceGUI::drawPattern() {
|
|||
ImGui::PopStyleVar();
|
||||
if (patternOpen) {
|
||||
if (!inhibitMenu && ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows) && ImGui::IsMouseClicked(ImGuiMouseButton_Right)) ImGui::OpenPopup("patternActionMenu");
|
||||
if (openEditMenu) ImGui::OpenPopup("patternActionMenu");
|
||||
if (ImGui::BeginPopup("patternActionMenu",ImGuiWindowFlags_NoMove|ImGuiWindowFlags_AlwaysAutoResize|ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoSavedSettings)) {
|
||||
editOptions(false);
|
||||
ImGui::EndPopup();
|
||||
|
|
@ -1914,5 +1916,7 @@ void FurnaceGUI::drawPattern() {
|
|||
}
|
||||
if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_PATTERN;
|
||||
ImGui::End();
|
||||
|
||||
openEditMenu=false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -135,7 +135,7 @@ int PlotNoLerpEx(ImGuiPlotType plot_type, const char* label, float (*values_gett
|
|||
const ImU32 col_base = ImGui::GetColorU32((plot_type == ImGuiPlotType_Lines) ? ImGuiCol_PlotLines : ImGuiCol_PlotHistogram);
|
||||
const ImU32 col_hovered = ImGui::GetColorU32((plot_type == ImGuiPlotType_Lines) ? ImGuiCol_PlotLinesHovered : ImGuiCol_PlotHistogramHovered);
|
||||
|
||||
for (int n = 0; n < res_w; n++)
|
||||
for (int n = 1; n <= res_w; n++)
|
||||
{
|
||||
const float t1 = t0 + t_step;
|
||||
const int v1_idx = (int)(t0 * item_count + 0.5f);
|
||||
|
|
@ -153,7 +153,8 @@ int PlotNoLerpEx(ImGuiPlotType plot_type, const char* label, float (*values_gett
|
|||
if (plot_type == ImGuiPlotType_Lines)
|
||||
{
|
||||
window->DrawList->AddLine(pos0, pos1, idx_hovered == v1_idx ? col_hovered : col_base);
|
||||
window->DrawList->AddLine(pos2, pos3, idx_hovered == v1_idx ? col_hovered : col_base);
|
||||
if (n < res_w)
|
||||
window->DrawList->AddLine(pos2, pos3, idx_hovered == v1_idx ? col_hovered : col_base);
|
||||
}
|
||||
else if (plot_type == ImGuiPlotType_Histogram)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -328,7 +328,8 @@ void FurnaceGUI::initSystemPresets() {
|
|||
ENTRY(
|
||||
"Watara Supervision", {
|
||||
CH(DIV_SYSTEM_SUPERVISION, 1.0f, 0, "")
|
||||
}
|
||||
},
|
||||
"tickRate=50.81300813008130081301"
|
||||
);
|
||||
CATEGORY_END;
|
||||
|
||||
|
|
@ -2626,6 +2627,63 @@ void FurnaceGUI::initSystemPresets() {
|
|||
) // 12.5MHz
|
||||
}
|
||||
);
|
||||
SUB_ENTRY(
|
||||
_("Sega System Multi 32"), {
|
||||
CH(DIV_SYSTEM_YM2612, 1.0f, 0,
|
||||
"clockSel=2\n"
|
||||
"chipType=0\n"
|
||||
), // discrete 8MHz YM3438
|
||||
CH(DIV_SYSTEM_MULTIPCM, 1.0f, 0, "")
|
||||
}
|
||||
);
|
||||
SUB_ENTRY(
|
||||
_("Sega System Multi 32 (extended channel 3)"), {
|
||||
CH(DIV_SYSTEM_YM2612_EXT, 1.0f, 0,
|
||||
"clockSel=2\n"
|
||||
"chipType=0\n"
|
||||
), // discrete 8MHz YM3438
|
||||
CH(DIV_SYSTEM_MULTIPCM, 1.0f, 0, "")
|
||||
}
|
||||
);
|
||||
SUB_ENTRY(
|
||||
_("Sega System Multi 32 (CSM)"), {
|
||||
CH(DIV_SYSTEM_YM2612_CSM, 1.0f, 0,
|
||||
"clockSel=2\n"
|
||||
"chipType=0\n"
|
||||
), // discrete 8MHz YM3438
|
||||
CH(DIV_SYSTEM_MULTIPCM, 1.0f, 0, "")
|
||||
}
|
||||
);
|
||||
SUB_ENTRY(
|
||||
_("Sega Model 1/2"), {
|
||||
CH(DIV_SYSTEM_YM2612, 1.0f, 0,
|
||||
"clockSel=2\n"
|
||||
"chipType=0\n"
|
||||
), // discrete 8MHz YM3438
|
||||
CH(DIV_SYSTEM_MULTIPCM, 1.0f, 0, ""),
|
||||
CH(DIV_SYSTEM_MULTIPCM, 1.0f, 0, "")
|
||||
}
|
||||
);
|
||||
SUB_ENTRY(
|
||||
_("Sega Model 1/2 (extended channel 3)"), {
|
||||
CH(DIV_SYSTEM_YM2612_EXT, 1.0f, 0,
|
||||
"clockSel=2\n"
|
||||
"chipType=0\n"
|
||||
), // discrete 8MHz YM3438
|
||||
CH(DIV_SYSTEM_MULTIPCM, 1.0f, 0, ""),
|
||||
CH(DIV_SYSTEM_MULTIPCM, 1.0f, 0, "")
|
||||
}
|
||||
);
|
||||
SUB_ENTRY(
|
||||
_("Sega Model 1/2 (CSM)"), {
|
||||
CH(DIV_SYSTEM_YM2612_CSM, 1.0f, 0,
|
||||
"clockSel=2\n"
|
||||
"chipType=0\n"
|
||||
), // discrete 8MHz YM3438
|
||||
CH(DIV_SYSTEM_MULTIPCM, 1.0f, 0, ""),
|
||||
CH(DIV_SYSTEM_MULTIPCM, 1.0f, 0, "")
|
||||
}
|
||||
);
|
||||
|
||||
ENTRY(
|
||||
_("Seta"), {}
|
||||
|
|
@ -3657,6 +3715,11 @@ void FurnaceGUI::initSystemPresets() {
|
|||
CH(DIV_SYSTEM_OPL4_DRUMS, 1.0f, 0, "")
|
||||
}
|
||||
);
|
||||
ENTRY(
|
||||
"Yamaha YMW258-F (MultiPCM)", {
|
||||
CH(DIV_SYSTEM_MULTIPCM, 1.0f, 0, "")
|
||||
}
|
||||
);
|
||||
CATEGORY_END;
|
||||
|
||||
CATEGORY_BEGIN(_("Wavetable"),_("chips which use user-specified waveforms to generate sound."));
|
||||
|
|
|
|||
|
|
@ -60,6 +60,18 @@ const double timeMultipliers[13]={
|
|||
_x+=_text; \
|
||||
}
|
||||
|
||||
// with sample pointer header in sample memory
|
||||
#define REFRESH_SAMPLE \
|
||||
bool hasSamplePtr=false; \
|
||||
for (int s=0; s<e->song.systemLen; s++) { \
|
||||
if (e->getDispatch(s)->hasSamplePtrHeader()) { \
|
||||
hasSamplePtr=true; \
|
||||
} \
|
||||
} \
|
||||
if (hasSamplePtr) { \
|
||||
e->renderSamplesP(curSample); \
|
||||
}
|
||||
|
||||
#define MAX_RATE(_name,_x) \
|
||||
if (e->isPreviewingSample()) { \
|
||||
if ((int)e->getSamplePreviewRate()>(int)(_x)) { \
|
||||
|
|
@ -285,6 +297,7 @@ void FurnaceGUI::drawSampleEdit() {
|
|||
int tryWith=(sample->loopEnd-8)&(~127);
|
||||
if (tryWith>(int)sample->samples) tryWith-=128;
|
||||
tryWith+=8; // +1 bc of how sample length is treated: https://www.nesdev.org/wiki/APU_DMC
|
||||
if (tryWith<8) tryWith=8;
|
||||
String alignHint=fmt::sprintf(_("NES: loop end must be a multiple of 128 + 8 (try with %d)"),tryWith);
|
||||
SAMPLE_WARN(warnLoopEnd,alignHint);
|
||||
}
|
||||
|
|
@ -563,6 +576,11 @@ void FurnaceGUI::drawSampleEdit() {
|
|||
SAMPLE_WARN(warnLength,_("ES5506: maximum sample length is 2097024"));
|
||||
}
|
||||
break;
|
||||
case DIV_SYSTEM_MULTIPCM:
|
||||
if (sample->samples>65535) {
|
||||
SAMPLE_WARN(warnLength,_("MultiPCM: maximum sample length is 65535"));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
@ -638,9 +656,8 @@ void FurnaceGUI::drawSampleEdit() {
|
|||
sample->loopEnd=sample->samples;*/
|
||||
}
|
||||
updateSampleTex=true;
|
||||
if (e->getSampleFormatMask()&(1U<<DIV_SAMPLE_DEPTH_BRR)) {
|
||||
e->renderSamplesP(curSample);
|
||||
}
|
||||
notifySampleChange=true;
|
||||
REFRESH_SAMPLE
|
||||
}
|
||||
popWarningColor();
|
||||
if (ImGui::IsItemHovered() && (!warnLoop.empty() || sample->depth==DIV_SAMPLE_DEPTH_BRR)) {
|
||||
|
|
@ -672,6 +689,7 @@ void FurnaceGUI::drawSampleEdit() {
|
|||
e->renderSamples(curSample);
|
||||
});
|
||||
updateSampleTex=true;
|
||||
notifySampleChange=true;
|
||||
MARK_MODIFIED;
|
||||
}
|
||||
}
|
||||
|
|
@ -692,6 +710,7 @@ void FurnaceGUI::drawSampleEdit() {
|
|||
sample->brrEmphasis=be;
|
||||
e->renderSamplesP(curSample);
|
||||
updateSampleTex=true;
|
||||
notifySampleChange=true;
|
||||
MARK_MODIFIED;
|
||||
}
|
||||
if (ImGui::IsItemHovered()) {
|
||||
|
|
@ -709,6 +728,7 @@ void FurnaceGUI::drawSampleEdit() {
|
|||
sample->brrNoFilter=bf;
|
||||
e->renderSamplesP(curSample);
|
||||
updateSampleTex=true;
|
||||
notifySampleChange=true;
|
||||
MARK_MODIFIED;
|
||||
}
|
||||
if (ImGui::IsItemHovered()) {
|
||||
|
|
@ -722,6 +742,7 @@ void FurnaceGUI::drawSampleEdit() {
|
|||
sample->dither=di;
|
||||
e->renderSamplesP(curSample);
|
||||
updateSampleTex=true;
|
||||
notifySampleChange=true;
|
||||
MARK_MODIFIED;
|
||||
}
|
||||
if (ImGui::IsItemHovered()) {
|
||||
|
|
@ -854,6 +875,7 @@ void FurnaceGUI::drawSampleEdit() {
|
|||
sample->loopMode=(DivSampleLoopMode)i;
|
||||
e->renderSamplesP(curSample);
|
||||
updateSampleTex=true;
|
||||
notifySampleChange=true;
|
||||
MARK_MODIFIED;
|
||||
}
|
||||
}
|
||||
|
|
@ -877,9 +899,8 @@ void FurnaceGUI::drawSampleEdit() {
|
|||
sample->loopStart=sample->loopEnd;
|
||||
}
|
||||
updateSampleTex=true;
|
||||
if (e->getSampleFormatMask()&(1U<<DIV_SAMPLE_DEPTH_BRR)) {
|
||||
e->renderSamplesP(curSample);
|
||||
}
|
||||
notifySampleChange=true;
|
||||
REFRESH_SAMPLE
|
||||
}
|
||||
if (ImGui::IsItemActive()) {
|
||||
keepLoopAlive=true;
|
||||
|
|
@ -920,9 +941,8 @@ void FurnaceGUI::drawSampleEdit() {
|
|||
sample->loopEnd=sample->samples;
|
||||
}
|
||||
updateSampleTex=true;
|
||||
if (e->getSampleFormatMask()&(1U<<DIV_SAMPLE_DEPTH_BRR)) {
|
||||
e->renderSamplesP(curSample);
|
||||
}
|
||||
notifySampleChange=true;
|
||||
REFRESH_SAMPLE
|
||||
}
|
||||
if (ImGui::IsItemActive()) {
|
||||
keepLoopAlive=true;
|
||||
|
|
@ -1096,6 +1116,7 @@ void FurnaceGUI::drawSampleEdit() {
|
|||
e->renderSamples(curSample);
|
||||
});
|
||||
updateSampleTex=true;
|
||||
notifySampleChange=true;
|
||||
sampleSelStart=-1;
|
||||
sampleSelEnd=-1;
|
||||
MARK_MODIFIED;
|
||||
|
|
@ -1123,7 +1144,7 @@ void FurnaceGUI::drawSampleEdit() {
|
|||
if (resampleTarget>384000) resampleTarget=384000;
|
||||
}
|
||||
double factor=resampleTarget/(double)targetRate;
|
||||
unsigned int targetLength=sample->samples*factor;
|
||||
unsigned int targetLength=round(sample->samples*factor);
|
||||
if (ImGui::InputScalar("Length##SRLen",ImGuiDataType_U32,&targetLength, &_ONE, &_SIXTEEN)) {
|
||||
if (targetLength<1) targetLength=1;
|
||||
resampleTarget=targetRate*targetLength/(double)sample->samples;
|
||||
|
|
@ -1160,6 +1181,7 @@ void FurnaceGUI::drawSampleEdit() {
|
|||
e->renderSamples(curSample);
|
||||
});
|
||||
updateSampleTex=true;
|
||||
notifySampleChange=true;
|
||||
sampleSelStart=-1;
|
||||
sampleSelEnd=-1;
|
||||
MARK_MODIFIED;
|
||||
|
|
@ -1227,6 +1249,7 @@ void FurnaceGUI::drawSampleEdit() {
|
|||
}
|
||||
|
||||
updateSampleTex=true;
|
||||
notifySampleChange=true;
|
||||
|
||||
e->renderSamples(curSample);
|
||||
});
|
||||
|
|
@ -1280,6 +1303,7 @@ void FurnaceGUI::drawSampleEdit() {
|
|||
e->renderSamples(curSample);
|
||||
});
|
||||
updateSampleTex=true;
|
||||
notifySampleChange=true;
|
||||
sampleSelStart=pos;
|
||||
sampleSelEnd=pos+silenceSize;
|
||||
MARK_MODIFIED;
|
||||
|
|
@ -1455,6 +1479,7 @@ void FurnaceGUI::drawSampleEdit() {
|
|||
}
|
||||
|
||||
updateSampleTex=true;
|
||||
notifySampleChange=true;
|
||||
|
||||
e->renderSamples(curSample);
|
||||
});
|
||||
|
|
@ -1534,6 +1559,7 @@ void FurnaceGUI::drawSampleEdit() {
|
|||
}
|
||||
}
|
||||
updateSampleTex=true;
|
||||
notifySampleChange=true;
|
||||
|
||||
e->renderSamples(curSample);
|
||||
});
|
||||
|
|
@ -2496,6 +2522,7 @@ void FurnaceGUI::doUndoSample() {
|
|||
if (sample->undo()==2) {
|
||||
e->renderSamples(curSample);
|
||||
updateSampleTex=true;
|
||||
notifySampleChange=true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -2508,6 +2535,7 @@ void FurnaceGUI::doRedoSample() {
|
|||
if (sample->redo()==2) {
|
||||
e->renderSamples(curSample);
|
||||
updateSampleTex=true;
|
||||
notifySampleChange=true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,7 +26,6 @@
|
|||
#include "util.h"
|
||||
#include "guiConst.h"
|
||||
#include "intConst.h"
|
||||
#include "ImGuiFileDialog.h"
|
||||
#include "IconsFontAwesome4.h"
|
||||
#include "furIcons.h"
|
||||
#include "misc/cpp/imgui_stdlib.h"
|
||||
|
|
@ -131,7 +130,10 @@ const char* patFonts[]={
|
|||
const char* audioBackends[]={
|
||||
"JACK",
|
||||
"SDL",
|
||||
"PortAudio"
|
||||
"PortAudio",
|
||||
// pipe (invalid choice in GUI)
|
||||
"Uhh, can you explain to me what exactly you were trying to do?",
|
||||
"ASIO"
|
||||
};
|
||||
|
||||
const char* audioQualities[]={
|
||||
|
|
@ -854,15 +856,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;
|
||||
|
|
@ -1162,9 +1155,10 @@ void FurnaceGUI::drawSettings() {
|
|||
settings.newSongBehavior=1;
|
||||
settingsChanged=true;
|
||||
}
|
||||
if (ImGui::InputText(_("Default author name"), &settings.defaultAuthorName)) settingsChanged=true;
|
||||
ImGui::Unindent();
|
||||
|
||||
if (ImGui::InputText(_("Default author name"),&settings.defaultAuthorName)) settingsChanged=true;
|
||||
|
||||
// SUBSECTION START-UP
|
||||
CONFIG_SUBSECTION(_("Start-up"));
|
||||
#ifndef NO_INTRO
|
||||
|
|
@ -1230,6 +1224,14 @@ void FurnaceGUI::drawSettings() {
|
|||
settings.s3mOPL3=s3mOPL3B;
|
||||
settingsChanged=true;
|
||||
}
|
||||
bool sampleImportInstDetuneB=settings.sampleImportInstDetune;
|
||||
if (ImGui::Checkbox(_("Load sample fine tuning when importing a sample"),&sampleImportInstDetuneB)) {
|
||||
settings.sampleImportInstDetune=sampleImportInstDetuneB;
|
||||
settingsChanged=true;
|
||||
}
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip(_("this may result in glitches with some samples."));
|
||||
}
|
||||
|
||||
#ifdef ANDROID
|
||||
// SUBSECTION ANDROID
|
||||
|
|
@ -1249,7 +1251,7 @@ void FurnaceGUI::drawSettings() {
|
|||
if (ImGui::BeginTable("##Output",2)) {
|
||||
ImGui::TableSetupColumn("##Label",ImGuiTableColumnFlags_WidthFixed);
|
||||
ImGui::TableSetupColumn("##Combo",ImGuiTableColumnFlags_WidthStretch);
|
||||
#if defined(HAVE_JACK) || defined(HAVE_PA)
|
||||
#if defined(HAVE_JACK) || defined(HAVE_PA) || defined(HAVE_ASIO)
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::AlignTextToFramePadding();
|
||||
|
|
@ -1272,6 +1274,12 @@ void FurnaceGUI::drawSettings() {
|
|||
settings.audioEngine=DIV_AUDIO_PORTAUDIO;
|
||||
settingsChanged=true;
|
||||
}
|
||||
#endif
|
||||
#ifdef HAVE_ASIO
|
||||
if (ImGui::Selectable("ASIO",settings.audioEngine==DIV_AUDIO_ASIO)) {
|
||||
settings.audioEngine=DIV_AUDIO_ASIO;
|
||||
settingsChanged=true;
|
||||
}
|
||||
#endif
|
||||
if (settings.audioEngine!=prevAudioEngine) {
|
||||
audioEngineChanged=true;
|
||||
|
|
@ -1339,6 +1347,15 @@ void FurnaceGUI::drawSettings() {
|
|||
}
|
||||
}
|
||||
|
||||
if (settings.audioEngine==DIV_AUDIO_ASIO) {
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button(_("Control panel"))) {
|
||||
if (e->audioBackendCommand(TA_AUDIO_CMD_SETUP)!=1) {
|
||||
showError(_("this driver doesn't have a control panel."));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::AlignTextToFramePadding();
|
||||
|
|
@ -3839,15 +3856,37 @@ void FurnaceGUI::drawSettings() {
|
|||
// SUBSECTION SONG COMMENTS
|
||||
CONFIG_SUBSECTION(_("Song Comments"));
|
||||
bool songNotesWrapB=settings.songNotesWrap;
|
||||
if (ImGui::Checkbox(_("Wrap text"), &songNotesWrapB)) {
|
||||
if (ImGui::Checkbox(_("Wrap text"),&songNotesWrapB)) {
|
||||
settings.songNotesWrap=songNotesWrapB;
|
||||
settingsChanged=true;
|
||||
}
|
||||
settings.songNotesWrap=false;
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip(_("Sorry, but, can you leave me alone?\nThere's plenty of other settings here for you to mess with."));
|
||||
|
||||
// SUBSECTION CHIP MANAGER
|
||||
CONFIG_SUBSECTION(_("Chip Manager"));
|
||||
bool rackShowLEDsB=settings.rackShowLEDs;
|
||||
if (ImGui::Checkbox(_("Show channel indicators"),&rackShowLEDsB)) {
|
||||
settings.rackShowLEDs=rackShowLEDsB;
|
||||
settingsChanged=true;
|
||||
}
|
||||
|
||||
// SUBSECTION MIXER
|
||||
CONFIG_SUBSECTION(_("Mixer"))
|
||||
ImGui::Text(_("Mixer style:"));
|
||||
ImGui::Indent();
|
||||
if (ImGui::RadioButton(_("No volume meters"),settings.mixerStyle==0)) {
|
||||
settings.mixerStyle=0;
|
||||
settingsChanged=true;
|
||||
}
|
||||
if (ImGui::RadioButton(_("Volume meters to the side"),settings.mixerStyle==1)) {
|
||||
settings.mixerStyle=1;
|
||||
settingsChanged=true;
|
||||
}
|
||||
if (ImGui::RadioButton(_("Volume meters in volume sliders"),settings.mixerStyle==2)) {
|
||||
settings.mixerStyle=2;
|
||||
settingsChanged=true;
|
||||
}
|
||||
ImGui::Unindent();
|
||||
|
||||
// SUBSECTION WINDOWS
|
||||
CONFIG_SUBSECTION(_("Windows"));
|
||||
bool roundedWindowsB=settings.roundedWindows;
|
||||
|
|
@ -4030,6 +4069,7 @@ void FurnaceGUI::drawSettings() {
|
|||
UI_COLOR_CONFIG(GUI_COLOR_FILE_SONG_IMPORT,_("Song (import)"));
|
||||
UI_COLOR_CONFIG(GUI_COLOR_FILE_INSTR,_("Instrument"));
|
||||
UI_COLOR_CONFIG(GUI_COLOR_FILE_AUDIO,_("Audio"));
|
||||
UI_COLOR_CONFIG(GUI_COLOR_FILE_AUDIO_COMPRESSED,_("Audio (compressed)"));
|
||||
UI_COLOR_CONFIG(GUI_COLOR_FILE_WAVE,_("Wavetable"));
|
||||
UI_COLOR_CONFIG(GUI_COLOR_FILE_VGM,_("VGM"));
|
||||
UI_COLOR_CONFIG(GUI_COLOR_FILE_ZSM,_("ZSM"));
|
||||
|
|
@ -4868,7 +4908,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);
|
||||
|
|
@ -4877,6 +4916,7 @@ void FurnaceGUI::readConfig(DivConfig& conf, FurnaceGUISettingGroups groups) {
|
|||
settings.vibrationLength=conf.getInt("vibrationLength",20);
|
||||
|
||||
settings.s3mOPL3=conf.getInt("s3mOPL3",1);
|
||||
settings.sampleImportInstDetune=conf.getInt("sampleImportInstDetune",0);
|
||||
|
||||
settings.backupEnable=conf.getInt("backupEnable",1);
|
||||
settings.backupInterval=conf.getInt("backupInterval",30);
|
||||
|
|
@ -4895,6 +4935,8 @@ void FurnaceGUI::readConfig(DivConfig& conf, FurnaceGUISettingGroups groups) {
|
|||
settings.audioEngine=DIV_AUDIO_JACK;
|
||||
} else if (conf.getString("audioEngine","SDL")=="PortAudio") {
|
||||
settings.audioEngine=DIV_AUDIO_PORTAUDIO;
|
||||
} else if (conf.getString("audioEngine","SDL")=="ASIO") {
|
||||
settings.audioEngine=DIV_AUDIO_ASIO;
|
||||
} else {
|
||||
settings.audioEngine=DIV_AUDIO_SDL;
|
||||
}
|
||||
|
|
@ -5028,7 +5070,11 @@ void FurnaceGUI::readConfig(DivConfig& conf, FurnaceGUISettingGroups groups) {
|
|||
settings.oscAntiAlias=conf.getInt("oscAntiAlias",1);
|
||||
settings.oscLineSize=conf.getFloat("oscLineSize",1.0f);
|
||||
|
||||
settings.songNotesWrap=conf.getInt("songNotesWrap", 0);
|
||||
settings.songNotesWrap=conf.getInt("songNotesWrap",0);
|
||||
|
||||
settings.rackShowLEDs=conf.getInt("rackShowLEDs",1);
|
||||
|
||||
settings.mixerStyle=conf.getInt("mixerStyle",1);
|
||||
|
||||
settings.channelColors=conf.getInt("channelColors",1);
|
||||
settings.channelTextColors=conf.getInt("channelTextColors",0);
|
||||
|
|
@ -5175,7 +5221,7 @@ void FurnaceGUI::readConfig(DivConfig& conf, FurnaceGUISettingGroups groups) {
|
|||
clampSetting(settings.headFontSize,2,96);
|
||||
clampSetting(settings.patFontSize,2,96);
|
||||
clampSetting(settings.iconSize,2,48);
|
||||
clampSetting(settings.audioEngine,0,2);
|
||||
clampSetting(settings.audioEngine,0,4);
|
||||
clampSetting(settings.audioQuality,0,1);
|
||||
clampSetting(settings.audioHiPass,0,1);
|
||||
clampSetting(settings.audioBufSize,32,4096);
|
||||
|
|
@ -5333,7 +5379,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);
|
||||
|
|
@ -5366,7 +5411,9 @@ void FurnaceGUI::readConfig(DivConfig& conf, FurnaceGUISettingGroups groups) {
|
|||
clampSetting(settings.playbackTime,0,1);
|
||||
clampSetting(settings.shaderOsc,0,1);
|
||||
clampSetting(settings.oscLineSize,0.25f,16.0f);
|
||||
clampSetting(settings.songNotesWrap, 0, 1);
|
||||
clampSetting(settings.songNotesWrap,0,1);
|
||||
clampSetting(settings.rackShowLEDs,0,1);
|
||||
clampSetting(settings.mixerStyle,0,2);
|
||||
clampSetting(settings.cursorWheelStep,0,2);
|
||||
clampSetting(settings.vsync,0,4);
|
||||
clampSetting(settings.frameRateLimit,0,1000);
|
||||
|
|
@ -5389,6 +5436,7 @@ void FurnaceGUI::readConfig(DivConfig& conf, FurnaceGUISettingGroups groups) {
|
|||
clampSetting(settings.autoFillSave,0,1);
|
||||
clampSetting(settings.autoMacroStepSize,0,2);
|
||||
clampSetting(settings.s3mOPL3,0,1);
|
||||
clampSetting(settings.sampleImportInstDetune,0,1);
|
||||
clampSetting(settings.backgroundPlay,0,1);
|
||||
clampSetting(settings.noMaximizeWorkaround,0,1);
|
||||
|
||||
|
|
@ -5462,7 +5510,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);
|
||||
|
|
@ -5471,6 +5518,7 @@ void FurnaceGUI::writeConfig(DivConfig& conf, FurnaceGUISettingGroups groups) {
|
|||
conf.set("vibrationLength",settings.vibrationLength);
|
||||
|
||||
conf.set("s3mOPL3",settings.s3mOPL3);
|
||||
conf.set("sampleImportInstDetune",settings.sampleImportInstDetune);
|
||||
|
||||
conf.set("backupEnable",settings.backupEnable);
|
||||
conf.set("backupInterval",settings.backupInterval);
|
||||
|
|
@ -5612,6 +5660,10 @@ void FurnaceGUI::writeConfig(DivConfig& conf, FurnaceGUISettingGroups groups) {
|
|||
|
||||
conf.set("songNotesWrap",settings.songNotesWrap);
|
||||
|
||||
conf.set("rackShowLEDs",settings.rackShowLEDs);
|
||||
|
||||
conf.set("mixerStyle",settings.mixerStyle);
|
||||
|
||||
conf.set("channelColors",settings.channelColors);
|
||||
conf.set("channelTextColors",settings.channelTextColors);
|
||||
conf.set("channelStyle",settings.channelStyle);
|
||||
|
|
@ -6170,8 +6222,6 @@ void FurnaceGUI::popWarningColor() {
|
|||
}
|
||||
}
|
||||
|
||||
#define IGFD_FileStyleByExtension IGFD_FileStyleByExtention
|
||||
|
||||
#ifdef _WIN32
|
||||
#define SYSTEM_FONT_PATH_1 "C:\\Windows\\Fonts\\segoeui.ttf"
|
||||
#define SYSTEM_FONT_PATH_2 "C:\\Windows\\Fonts\\tahoma.ttf"
|
||||
|
|
@ -6607,6 +6657,11 @@ void FurnaceGUI::applyUISettings(bool updateFonts) {
|
|||
//fontConf.RasterizerMultiply=1.5;
|
||||
//fontConfP.RasterizerMultiply=1.5;
|
||||
|
||||
fontConf.PixelSnapH=0;
|
||||
fontConfP.PixelSnapH=0;
|
||||
fontConfB.PixelSnapH=0;
|
||||
fontConfH.PixelSnapH=0;
|
||||
|
||||
if (settings.mainFont<0 || settings.mainFont>6) settings.mainFont=0;
|
||||
if (settings.headFont<0 || settings.headFont>6) settings.headFont=0;
|
||||
if (settings.patFont<0 || settings.patFont>6) settings.patFont=0;
|
||||
|
|
@ -6761,7 +6816,7 @@ void FurnaceGUI::applyUISettings(bool updateFonts) {
|
|||
logW("could not load header font! reverting to default font");
|
||||
settings.headFont=0;
|
||||
if ((headFont=addFontZlib(builtinFont[settings.headFont],builtinFontLen[settings.headFont],MAX(1,e->getConfInt("headFontSize",27)*dpiScale),&fontConfH))==NULL) {
|
||||
logE("could not load header font! falling back to IBM Plex Sans.");
|
||||
logE("could not load header font! falling back to fallback. wahahaha, get it? fallback.");
|
||||
headFont=ImGui::GetIO().Fonts->AddFontDefault();
|
||||
}
|
||||
}
|
||||
|
|
@ -6775,8 +6830,16 @@ void FurnaceGUI::applyUISettings(bool updateFonts) {
|
|||
}
|
||||
}
|
||||
|
||||
mainFont->FallbackChar='?';
|
||||
mainFont->EllipsisChar='.';
|
||||
// four fallback fonts
|
||||
if (settings.loadFallback) {
|
||||
headFont=addFontZlib(font_plexSans_compressed_data,font_plexSans_compressed_size,MAX(1,e->getConfInt("headFontSize",27)*dpiScale),&fc1);
|
||||
headFont=addFontZlib(font_plexSansJP_compressed_data,font_plexSansJP_compressed_size,MAX(1,e->getConfInt("headFontSize",27)*dpiScale),&fc1);
|
||||
headFont=addFontZlib(font_plexSansKR_compressed_data,font_plexSansKR_compressed_size,MAX(1,e->getConfInt("headFontSize",27)*dpiScale),&fc1);
|
||||
headFont=addFontZlib(font_unifont_compressed_data,font_unifont_compressed_size,MAX(1,e->getConfInt("headFontSize",27)*dpiScale),&fc1);
|
||||
}
|
||||
|
||||
//mainFont->FallbackChar='?';
|
||||
//mainFont->EllipsisChar='.';
|
||||
//mainFont->EllipsisCharCount=3;
|
||||
} else if (updateFonts) {
|
||||
// safe mode
|
||||
|
|
@ -6784,91 +6847,97 @@ void FurnaceGUI::applyUISettings(bool updateFonts) {
|
|||
patFont=mainFont;
|
||||
bigFont=mainFont;
|
||||
headFont=mainFont;
|
||||
|
||||
mainFont->FallbackChar='?';
|
||||
mainFont->EllipsisChar='.';
|
||||
//mainFont->EllipsisCharCount=3;
|
||||
}
|
||||
|
||||
ImGuiFileDialog::Instance()->okButtonString=_("OK");
|
||||
ImGuiFileDialog::Instance()->cancelButtonString=_("Cancel");
|
||||
ImGuiFileDialog::Instance()->searchString=_("Search");
|
||||
ImGuiFileDialog::Instance()->dirEntryString=_("[Dir]");
|
||||
ImGuiFileDialog::Instance()->linkEntryString=_("[Link]");
|
||||
ImGuiFileDialog::Instance()->fileEntryString=_("[File]");
|
||||
ImGuiFileDialog::Instance()->fileNameString=_("Name:");
|
||||
ImGuiFileDialog::Instance()->dirNameString=_("Path:");
|
||||
ImGuiFileDialog::Instance()->buttonResetSearchString=_("Reset search");
|
||||
ImGuiFileDialog::Instance()->buttonDriveString=_("Drives");
|
||||
ImGuiFileDialog::Instance()->buttonEditPathString=_("Edit path\nYou can also right click on path buttons");
|
||||
ImGuiFileDialog::Instance()->buttonResetPathString=_("Go to home directory");
|
||||
ImGuiFileDialog::Instance()->buttonParentDirString=_("Go to parent directory");
|
||||
ImGuiFileDialog::Instance()->buttonCreateDirString=_("Create Directory");
|
||||
ImGuiFileDialog::Instance()->tableHeaderFileNameString=_("File name");
|
||||
ImGuiFileDialog::Instance()->tableHeaderFileTypeString=_("Type");
|
||||
ImGuiFileDialog::Instance()->tableHeaderFileSizeString=_("Size");
|
||||
ImGuiFileDialog::Instance()->tableHeaderFileDateString=_("Date");
|
||||
ImGuiFileDialog::Instance()->OverWriteDialogTitleString=_("Warning");
|
||||
ImGuiFileDialog::Instance()->OverWriteDialogMessageString=_("The file you selected already exists! Would you like to overwrite it?");
|
||||
ImGuiFileDialog::Instance()->OverWriteDialogConfirmButtonString=_("Yes");
|
||||
ImGuiFileDialog::Instance()->OverWriteDialogCancelButtonString=_("No");
|
||||
ImGuiFileDialog::Instance()->DateTimeFormat=_("%Y/%m/%d %H:%M");
|
||||
// set built-in file picker up (NEW)
|
||||
newFilePicker->clearTypes();
|
||||
|
||||
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByTypeDir,"",uiColors[GUI_COLOR_FILE_DIR],ICON_FA_FOLDER_O);
|
||||
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByTypeFile,"",uiColors[GUI_COLOR_FILE_OTHER],ICON_FA_FILE_O);
|
||||
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".fur",uiColors[GUI_COLOR_FILE_SONG_NATIVE],ICON_FA_FILE);
|
||||
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".fui",uiColors[GUI_COLOR_FILE_INSTR],ICON_FA_FILE);
|
||||
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".fuw",uiColors[GUI_COLOR_FILE_WAVE],ICON_FA_FILE);
|
||||
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".dmp",uiColors[GUI_COLOR_FILE_INSTR],ICON_FA_FILE);
|
||||
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".dmw",uiColors[GUI_COLOR_FILE_WAVE],ICON_FA_FILE);
|
||||
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".wav",uiColors[GUI_COLOR_FILE_AUDIO],ICON_FA_FILE_AUDIO_O);
|
||||
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".dmc",uiColors[GUI_COLOR_FILE_AUDIO],ICON_FA_FILE_AUDIO_O);
|
||||
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".brr",uiColors[GUI_COLOR_FILE_AUDIO],ICON_FA_FILE_AUDIO_O);
|
||||
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".vgm",uiColors[GUI_COLOR_FILE_VGM],ICON_FA_FILE_AUDIO_O);
|
||||
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".zsm",uiColors[GUI_COLOR_FILE_ZSM],ICON_FA_FILE_AUDIO_O);
|
||||
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".ttf",uiColors[GUI_COLOR_FILE_FONT],ICON_FA_FONT);
|
||||
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".otf",uiColors[GUI_COLOR_FILE_FONT],ICON_FA_FONT);
|
||||
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".ttc",uiColors[GUI_COLOR_FILE_FONT],ICON_FA_FONT);
|
||||
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".dfont",uiColors[GUI_COLOR_FILE_FONT],ICON_FA_FONT);
|
||||
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".fon",uiColors[GUI_COLOR_FILE_FONT],ICON_FA_FONT);
|
||||
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".pcf",uiColors[GUI_COLOR_FILE_FONT],ICON_FA_FONT);
|
||||
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".psf",uiColors[GUI_COLOR_FILE_FONT],ICON_FA_FONT);
|
||||
newFilePicker->setTypeStyle(FP_TYPE_UNKNOWN,uiColors[GUI_COLOR_FILE_OTHER],ICON_FA_QUESTION);
|
||||
newFilePicker->setTypeStyle(FP_TYPE_NORMAL,uiColors[GUI_COLOR_FILE_OTHER],ICON_FA_FILE_O);
|
||||
newFilePicker->setTypeStyle(FP_TYPE_DIR,uiColors[GUI_COLOR_FILE_DIR],ICON_FA_FOLDER_O);
|
||||
newFilePicker->setTypeStyle(FP_TYPE_LINK,uiColors[GUI_COLOR_FILE_OTHER],ICON_FA_EXTERNAL_LINK);
|
||||
newFilePicker->setTypeStyle(FP_TYPE_PIPE,uiColors[GUI_COLOR_FILE_OTHER],ICON_FA_EXCHANGE);
|
||||
newFilePicker->setTypeStyle(FP_TYPE_SOCKET,uiColors[GUI_COLOR_FILE_OTHER],ICON_FA_PLUG);
|
||||
newFilePicker->setTypeStyle(FP_TYPE_CHARDEV,uiColors[GUI_COLOR_FILE_OTHER],ICON_FA_MICROCHIP);
|
||||
newFilePicker->setTypeStyle(FP_TYPE_BLOCKDEV,uiColors[GUI_COLOR_FILE_OTHER],ICON_FA_HDD_O);
|
||||
|
||||
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".dmf",uiColors[GUI_COLOR_FILE_SONG_IMPORT],ICON_FA_FILE);
|
||||
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".mod",uiColors[GUI_COLOR_FILE_SONG_IMPORT],ICON_FA_FILE);
|
||||
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".s3m",uiColors[GUI_COLOR_FILE_SONG_IMPORT],ICON_FA_FILE);
|
||||
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".xm",uiColors[GUI_COLOR_FILE_SONG_IMPORT],ICON_FA_FILE);
|
||||
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".it",uiColors[GUI_COLOR_FILE_SONG_IMPORT],ICON_FA_FILE);
|
||||
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".fc13",uiColors[GUI_COLOR_FILE_SONG_IMPORT],ICON_FA_FILE);
|
||||
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".fc14",uiColors[GUI_COLOR_FILE_SONG_IMPORT],ICON_FA_FILE);
|
||||
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".fc",uiColors[GUI_COLOR_FILE_SONG_IMPORT],ICON_FA_FILE);
|
||||
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".smod",uiColors[GUI_COLOR_FILE_SONG_IMPORT],ICON_FA_FILE);
|
||||
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".ftm",uiColors[GUI_COLOR_FILE_SONG_IMPORT],ICON_FA_FILE);
|
||||
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".0cc",uiColors[GUI_COLOR_FILE_SONG_IMPORT],ICON_FA_FILE);
|
||||
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".dnm",uiColors[GUI_COLOR_FILE_SONG_IMPORT],ICON_FA_FILE);
|
||||
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".eft",uiColors[GUI_COLOR_FILE_SONG_IMPORT],ICON_FA_FILE);
|
||||
newFilePicker->registerType(".fur",uiColors[GUI_COLOR_FILE_SONG_NATIVE],ICON_FA_FILE);
|
||||
newFilePicker->registerType(".fui",uiColors[GUI_COLOR_FILE_INSTR],ICON_FA_FILE);
|
||||
newFilePicker->registerType(".dmp",uiColors[GUI_COLOR_FILE_INSTR],ICON_FA_FILE);
|
||||
newFilePicker->registerType(".fuw",uiColors[GUI_COLOR_FILE_WAVE],ICON_FA_FILE);
|
||||
newFilePicker->registerType(".dmw",uiColors[GUI_COLOR_FILE_WAVE],ICON_FA_FILE);
|
||||
|
||||
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".fub",uiColors[GUI_COLOR_FILE_SONG_IMPORT],ICON_FA_FILE);
|
||||
newFilePicker->registerType(".wav",uiColors[GUI_COLOR_FILE_AUDIO],ICON_FA_FILE_AUDIO_O);
|
||||
newFilePicker->registerType(".dmc",uiColors[GUI_COLOR_FILE_AUDIO],ICON_FA_FILE_AUDIO_O);
|
||||
newFilePicker->registerType(".aiff",uiColors[GUI_COLOR_FILE_AUDIO],ICON_FA_FILE_AUDIO_O);
|
||||
newFilePicker->registerType(".aifc",uiColors[GUI_COLOR_FILE_AUDIO],ICON_FA_FILE_AUDIO_O);
|
||||
newFilePicker->registerType(".au",uiColors[GUI_COLOR_FILE_AUDIO],ICON_FA_FILE_AUDIO_O);
|
||||
newFilePicker->registerType(".caf",uiColors[GUI_COLOR_FILE_AUDIO],ICON_FA_FILE_AUDIO_O);
|
||||
newFilePicker->registerType(".iff",uiColors[GUI_COLOR_FILE_AUDIO],ICON_FA_FILE_AUDIO_O);
|
||||
newFilePicker->registerType(".mat",uiColors[GUI_COLOR_FILE_AUDIO],ICON_FA_FILE_AUDIO_O);
|
||||
newFilePicker->registerType(".w64",uiColors[GUI_COLOR_FILE_AUDIO],ICON_FA_FILE_AUDIO_O);
|
||||
newFilePicker->registerType(".wve",uiColors[GUI_COLOR_FILE_AUDIO],ICON_FA_FILE_AUDIO_O);
|
||||
newFilePicker->registerType(".rf64",uiColors[GUI_COLOR_FILE_AUDIO],ICON_FA_FILE_AUDIO_O);
|
||||
|
||||
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".tfi",uiColors[GUI_COLOR_FILE_INSTR],ICON_FA_FILE);
|
||||
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".vgi",uiColors[GUI_COLOR_FILE_INSTR],ICON_FA_FILE);
|
||||
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".s3i",uiColors[GUI_COLOR_FILE_INSTR],ICON_FA_FILE);
|
||||
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".sbi",uiColors[GUI_COLOR_FILE_INSTR],ICON_FA_FILE);
|
||||
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".opli",uiColors[GUI_COLOR_FILE_INSTR],ICON_FA_FILE);
|
||||
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".opni",uiColors[GUI_COLOR_FILE_INSTR],ICON_FA_FILE);
|
||||
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".y12",uiColors[GUI_COLOR_FILE_INSTR],ICON_FA_FILE);
|
||||
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".bnk",uiColors[GUI_COLOR_FILE_INSTR],ICON_FA_FILE);
|
||||
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".fti",uiColors[GUI_COLOR_FILE_INSTR],ICON_FA_FILE);
|
||||
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".bti",uiColors[GUI_COLOR_FILE_INSTR],ICON_FA_FILE);
|
||||
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".ff",uiColors[GUI_COLOR_FILE_INSTR],ICON_FA_FILE);
|
||||
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".opm",uiColors[GUI_COLOR_FILE_INSTR],ICON_FA_FILE);
|
||||
newFilePicker->registerType(".brr",uiColors[GUI_COLOR_FILE_AUDIO_COMPRESSED],ICON_FA_FILE_AUDIO_O);
|
||||
newFilePicker->registerType(".flac",uiColors[GUI_COLOR_FILE_AUDIO_COMPRESSED],ICON_FA_FILE_AUDIO_O);
|
||||
newFilePicker->registerType(".m1a",uiColors[GUI_COLOR_FILE_AUDIO_COMPRESSED],ICON_FA_FILE_AUDIO_O);
|
||||
newFilePicker->registerType(".mp1",uiColors[GUI_COLOR_FILE_AUDIO_COMPRESSED],ICON_FA_FILE_AUDIO_O);
|
||||
newFilePicker->registerType(".mp2",uiColors[GUI_COLOR_FILE_AUDIO_COMPRESSED],ICON_FA_FILE_AUDIO_O);
|
||||
newFilePicker->registerType(".mp3",uiColors[GUI_COLOR_FILE_AUDIO_COMPRESSED],ICON_FA_FILE_AUDIO_O);
|
||||
newFilePicker->registerType(".oga",uiColors[GUI_COLOR_FILE_AUDIO_COMPRESSED],ICON_FA_FILE_AUDIO_O);
|
||||
newFilePicker->registerType(".ogg",uiColors[GUI_COLOR_FILE_AUDIO_COMPRESSED],ICON_FA_FILE_AUDIO_O);
|
||||
newFilePicker->registerType(".opus",uiColors[GUI_COLOR_FILE_AUDIO_COMPRESSED],ICON_FA_FILE_AUDIO_O);
|
||||
newFilePicker->registerType(".pvf",uiColors[GUI_COLOR_FILE_AUDIO_COMPRESSED],ICON_FA_FILE_AUDIO_O);
|
||||
newFilePicker->registerType(".voc",uiColors[GUI_COLOR_FILE_AUDIO_COMPRESSED],ICON_FA_FILE_AUDIO_O);
|
||||
newFilePicker->registerType(".vox",uiColors[GUI_COLOR_FILE_AUDIO_COMPRESSED],ICON_FA_FILE_AUDIO_O);
|
||||
|
||||
newFilePicker->registerType(".vgm",uiColors[GUI_COLOR_FILE_VGM],ICON_FA_FILE_AUDIO_O);
|
||||
newFilePicker->registerType(".zsm",uiColors[GUI_COLOR_FILE_ZSM],ICON_FA_FILE_AUDIO_O);
|
||||
|
||||
newFilePicker->registerType(".ttf",uiColors[GUI_COLOR_FILE_FONT],ICON_FA_FONT);
|
||||
newFilePicker->registerType(".otf",uiColors[GUI_COLOR_FILE_FONT],ICON_FA_FONT);
|
||||
newFilePicker->registerType(".ttc",uiColors[GUI_COLOR_FILE_FONT],ICON_FA_FONT);
|
||||
newFilePicker->registerType(".dfont",uiColors[GUI_COLOR_FILE_FONT],ICON_FA_FONT);
|
||||
newFilePicker->registerType(".fon",uiColors[GUI_COLOR_FILE_FONT],ICON_FA_FONT);
|
||||
newFilePicker->registerType(".pcf",uiColors[GUI_COLOR_FILE_FONT],ICON_FA_FONT);
|
||||
newFilePicker->registerType(".psf",uiColors[GUI_COLOR_FILE_FONT],ICON_FA_FONT);
|
||||
|
||||
newFilePicker->registerType(".dmf",uiColors[GUI_COLOR_FILE_SONG_IMPORT],ICON_FA_FILE);
|
||||
newFilePicker->registerType(".mod",uiColors[GUI_COLOR_FILE_SONG_IMPORT],ICON_FA_FILE);
|
||||
newFilePicker->registerType(".s3m",uiColors[GUI_COLOR_FILE_SONG_IMPORT],ICON_FA_FILE);
|
||||
newFilePicker->registerType(".xm",uiColors[GUI_COLOR_FILE_SONG_IMPORT],ICON_FA_FILE);
|
||||
newFilePicker->registerType(".it",uiColors[GUI_COLOR_FILE_SONG_IMPORT],ICON_FA_FILE);
|
||||
newFilePicker->registerType(".fc13",uiColors[GUI_COLOR_FILE_SONG_IMPORT],ICON_FA_FILE);
|
||||
newFilePicker->registerType(".fc14",uiColors[GUI_COLOR_FILE_SONG_IMPORT],ICON_FA_FILE);
|
||||
newFilePicker->registerType(".fc",uiColors[GUI_COLOR_FILE_SONG_IMPORT],ICON_FA_FILE);
|
||||
newFilePicker->registerType(".smod",uiColors[GUI_COLOR_FILE_SONG_IMPORT],ICON_FA_FILE);
|
||||
newFilePicker->registerType(".ftm",uiColors[GUI_COLOR_FILE_SONG_IMPORT],ICON_FA_FILE);
|
||||
newFilePicker->registerType(".0cc",uiColors[GUI_COLOR_FILE_SONG_IMPORT],ICON_FA_FILE);
|
||||
newFilePicker->registerType(".dnm",uiColors[GUI_COLOR_FILE_SONG_IMPORT],ICON_FA_FILE);
|
||||
newFilePicker->registerType(".eft",uiColors[GUI_COLOR_FILE_SONG_IMPORT],ICON_FA_FILE);
|
||||
|
||||
newFilePicker->registerType(".fub",uiColors[GUI_COLOR_FILE_SONG_IMPORT],ICON_FA_FILE);
|
||||
|
||||
newFilePicker->registerType(".tfi",uiColors[GUI_COLOR_FILE_INSTR],ICON_FA_FILE);
|
||||
newFilePicker->registerType(".vgi",uiColors[GUI_COLOR_FILE_INSTR],ICON_FA_FILE);
|
||||
newFilePicker->registerType(".s3i",uiColors[GUI_COLOR_FILE_INSTR],ICON_FA_FILE);
|
||||
newFilePicker->registerType(".sbi",uiColors[GUI_COLOR_FILE_INSTR],ICON_FA_FILE);
|
||||
newFilePicker->registerType(".opli",uiColors[GUI_COLOR_FILE_INSTR],ICON_FA_FILE);
|
||||
newFilePicker->registerType(".opni",uiColors[GUI_COLOR_FILE_INSTR],ICON_FA_FILE);
|
||||
newFilePicker->registerType(".y12",uiColors[GUI_COLOR_FILE_INSTR],ICON_FA_FILE);
|
||||
newFilePicker->registerType(".bnk",uiColors[GUI_COLOR_FILE_INSTR],ICON_FA_FILE);
|
||||
newFilePicker->registerType(".fti",uiColors[GUI_COLOR_FILE_INSTR],ICON_FA_FILE);
|
||||
newFilePicker->registerType(".bti",uiColors[GUI_COLOR_FILE_INSTR],ICON_FA_FILE);
|
||||
newFilePicker->registerType(".ff",uiColors[GUI_COLOR_FILE_INSTR],ICON_FA_FILE);
|
||||
newFilePicker->registerType(".opm",uiColors[GUI_COLOR_FILE_INSTR],ICON_FA_FILE);
|
||||
|
||||
if (updateFonts) {
|
||||
if (fileDialog!=NULL) delete fileDialog;
|
||||
#ifdef FLATPAK_WORKAROUNDS
|
||||
fileDialog=new FurnaceGUIFileDialog(false);
|
||||
fileDialog=new FurnaceGUIFileDialog(false,newFilePicker);
|
||||
#else
|
||||
fileDialog=new FurnaceGUIFileDialog(settings.sysFileDialog);
|
||||
fileDialog=new FurnaceGUIFileDialog(settings.sysFileDialog,newFilePicker);
|
||||
#endif
|
||||
|
||||
fileDialog->mobileUI=mobileUI;
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ void FurnaceGUI::drawNotes(bool asChild) {
|
|||
if (!notesOpen && !asChild) return;
|
||||
bool began=asChild?ImGui::BeginChild("Song Info##Song Information"):ImGui::Begin("Song Comments",¬esOpen,globalWinFlags,_("Song Comments"));
|
||||
if (began) {
|
||||
if (ImGui::InputTextMultiline("##SongNotes",&e->song.notes,ImGui::GetContentRegionAvail(),ImGuiInputTextFlags_UndoRedo|(settings.songNotesWrap?ImGuiInputTextFlags_WordWrapping:0))) {
|
||||
if (ImGui::InputTextMultiline("##SongNotes",&e->song.notes,ImGui::GetContentRegionAvail(),ImGuiInputTextFlags_UndoRedo|(settings.songNotesWrap?ImGuiInputTextFlags_WordWrap:0))) {
|
||||
MARK_MODIFIED;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -136,7 +136,7 @@ void FurnaceGUI::drawSubSongs(bool asChild) {
|
|||
}
|
||||
|
||||
if (ImGui::GetContentRegionAvail().y>(10.0f*dpiScale)) {
|
||||
if (ImGui::InputTextMultiline("##SubSongNotes",&e->curSubSong->notes,ImGui::GetContentRegionAvail(),ImGuiInputTextFlags_UndoRedo|(settings.songNotesWrap?ImGuiInputTextFlags_WordWrapping:0))) {
|
||||
if (ImGui::InputTextMultiline("##SubSongNotes",&e->curSubSong->notes,ImGui::GetContentRegionAvail(),ImGuiInputTextFlags_UndoRedo|(settings.songNotesWrap?ImGuiInputTextFlags_WordWrap:0))) {
|
||||
MARK_MODIFIED;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1242,6 +1242,7 @@ bool FurnaceGUI::drawSysConf(int chan, int sysPos, DivSystem type, DivConfig& fl
|
|||
|
||||
if (ImGui::Checkbox(_("Bankswitched (Seta 2)"),&isBanked)) {
|
||||
altered=true;
|
||||
mustRender=true;
|
||||
}
|
||||
|
||||
if (altered) {
|
||||
|
|
@ -1320,11 +1321,11 @@ bool FurnaceGUI::drawSysConf(int chan, int sysPos, DivSystem type, DivConfig& fl
|
|||
if (ImGui::Checkbox(_("Amiga channel volumes (64)"),&amigaVol)) {
|
||||
altered=true;
|
||||
}
|
||||
pushWarningColor(amigaPitch && e->song.linearPitch==2);
|
||||
pushWarningColor(amigaPitch && e->song.linearPitch);
|
||||
if (ImGui::Checkbox(_("Amiga-like pitch (non-linear pitch only)"),&amigaPitch)) {
|
||||
altered=true;
|
||||
}
|
||||
if (amigaPitch && e->song.linearPitch==2) {
|
||||
if (amigaPitch && e->song.linearPitch) {
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("pitch linearity is set to linear. this won't do anything!");
|
||||
}
|
||||
|
|
@ -1743,6 +1744,7 @@ bool FurnaceGUI::drawSysConf(int chan, int sysPos, DivSystem type, DivConfig& fl
|
|||
|
||||
if (ImGui::Checkbox(_("Bankswitched (NMK112)"),&isBanked)) {
|
||||
altered=true;
|
||||
mustRender=true;
|
||||
}
|
||||
|
||||
if (altered) {
|
||||
|
|
@ -2728,6 +2730,7 @@ bool FurnaceGUI::drawSysConf(int chan, int sysPos, DivSystem type, DivConfig& fl
|
|||
case DIV_SYSTEM_BIFURCATOR:
|
||||
case DIV_SYSTEM_POWERNOISE:
|
||||
case DIV_SYSTEM_UPD1771C:
|
||||
case DIV_SYSTEM_MULTIPCM:
|
||||
break;
|
||||
case DIV_SYSTEM_YMU759:
|
||||
case DIV_SYSTEM_ESFM:
|
||||
|
|
|
|||
|
|
@ -39,25 +39,23 @@ void FurnaceGUI::drawSysManager() {
|
|||
//ImGui::SetNextWindowSizeConstraints(ImVec2(440.0f*dpiScale,400.0f*dpiScale),ImVec2(canvasW,canvasH));
|
||||
}
|
||||
if (ImGui::Begin("Chip Manager",&sysManagerOpen,globalWinFlags,_("Chip Manager"))) {
|
||||
ImGuiStorage* openedConfig=ImGui::GetStateStorage();
|
||||
ImGui::Checkbox(_("Preserve channel order"),&preserveChanPos);
|
||||
ImGui::SameLine();
|
||||
ImGui::Checkbox(_("Clone channel data"),&sysDupCloneChannels);
|
||||
ImGui::SameLine();
|
||||
ImGui::Checkbox(_("Clone at end"),&sysDupEnd);
|
||||
if (ImGui::BeginTable("SystemList",3)) {
|
||||
ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthFixed);
|
||||
ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthStretch);
|
||||
ImGui::TableSetupColumn("c3",ImGuiTableColumnFlags_WidthFixed);
|
||||
ImGui::TableNextRow(ImGuiTableRowFlags_Headers);
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text(_("Name"));
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text(_("Actions"));
|
||||
for (unsigned char i=0; i<e->song.systemLen; i++) {
|
||||
ImGui::PushID(i);
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
|
||||
// this is a "rack" style chip list
|
||||
int dispatchOff=0;
|
||||
for (int i=0; i<e->song.systemLen; i++) {
|
||||
String rackID=fmt::sprintf("SysEntry%d",i);
|
||||
String rackNameID=fmt::sprintf("SysName%d",i);
|
||||
const DivSysDef* sysDef=e->getSystemDef(e->song.system[i]);
|
||||
|
||||
ImGui::PushID(i);
|
||||
if (ImGui::BeginChild(rackID.c_str(),ImVec2(0,0),ImGuiChildFlags_Border|ImGuiChildFlags_AutoResizeY)) {
|
||||
// swap handle and name
|
||||
if (ImGui::Button(ICON_FA_ARROWS)) {
|
||||
}
|
||||
if (ImGui::BeginDragDropSource()) {
|
||||
|
|
@ -81,30 +79,16 @@ void FurnaceGUI::drawSysManager() {
|
|||
}
|
||||
ImGui::EndDragDropTarget();
|
||||
}
|
||||
ImGui::TableNextColumn();
|
||||
bool isNotCollapsed=true;
|
||||
if (ImGui::TreeNode(fmt::sprintf("%d. %s##_SYSM%d",i+1,getSystemName(e->song.system[i]),i).c_str())) {
|
||||
drawSysConf(i,i,e->song.system[i],e->song.systemFlags[i],true);
|
||||
isNotCollapsed=false;
|
||||
ImGui::TreePop();
|
||||
}
|
||||
if (ImGui::IsItemHovered(ImGuiHoveredFlags_Stationary) && isNotCollapsed) {
|
||||
if (e->song.system[i]!=DIV_SYSTEM_NULL) {
|
||||
const DivSysDef* sysDef=e->getSystemDef(e->song.system[i]);
|
||||
if (ImGui::BeginTooltip()) {
|
||||
ImGui::Dummy(ImVec2(MIN(scrW*dpiScale,400.0f*dpiScale),0.0f));
|
||||
ImGui::PushTextWrapPos(MIN(scrW*dpiScale,400.0f*dpiScale)); // arbitrary constant
|
||||
ImGui::TextWrapped("%s",sysDef->description);
|
||||
ImGui::Separator();
|
||||
drawSystemChannelInfoText(sysDef);
|
||||
drawSystemChannelInfo(sysDef);
|
||||
ImGui::PopTextWrapPos();
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
}
|
||||
}
|
||||
ImGui::TableNextColumn();
|
||||
if (ImGui::Button(_("Clone##SysDup"))) {
|
||||
ImGui::SameLine();
|
||||
float buttonInnerSize=ImGui::CalcTextSize(ICON_FA_CLONE).x;
|
||||
float buttonCount=settings.rackShowLEDs?3.0f:4.0f;
|
||||
float sideButtonSize=ImGui::GetStyle().ItemSpacing.x*buttonCount+buttonInnerSize*buttonCount+ImGui::GetStyle().FramePadding.x*2*buttonCount;
|
||||
ImGui::AlignTextToFramePadding();
|
||||
ImGui::ScrollText(ImGui::GetID(rackNameID.c_str()),sysDef->name,ImVec2(0.0f,0.0f),ImVec2(ImGui::GetContentRegionAvail().x-sideButtonSize,0),false);
|
||||
ImGui::Dummy(ImVec2(ImGui::GetContentRegionAvail().x-sideButtonSize,1.0f));
|
||||
// action buttons
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button(ICON_FA_CLONE "##SysDup")) {
|
||||
if (!e->duplicateSystem(i,sysDupCloneChannels,sysDupEnd)) {
|
||||
showError(fmt::sprintf(_("cannot clone chip! (%s)"),e->getLastError()));
|
||||
} else {
|
||||
|
|
@ -116,8 +100,11 @@ void FurnaceGUI::drawSysManager() {
|
|||
MARK_MODIFIED;
|
||||
}
|
||||
}
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip(_("Clone"));
|
||||
}
|
||||
ImGui::SameLine();
|
||||
ImGui::Button(_("Change##SysChange"));
|
||||
ImGui::Button(ICON_FA_EJECT "##SysChange");
|
||||
if (ImGui::BeginPopupContextItem("SysPickerC",ImGuiPopupFlags_MouseButtonLeft)) {
|
||||
DivSystem picked=systemPicker(false);
|
||||
if (picked!=DIV_SYSTEM_NULL) {
|
||||
|
|
@ -138,6 +125,9 @@ void FurnaceGUI::drawSysManager() {
|
|||
}
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip(_("Change"));
|
||||
}
|
||||
ImGui::SameLine();
|
||||
ImGui::BeginDisabled(e->song.systemLen<=1);
|
||||
pushDestColor();
|
||||
|
|
@ -150,35 +140,58 @@ void FurnaceGUI::drawSysManager() {
|
|||
ImGui::SetTooltip(_("Remove"));
|
||||
}
|
||||
ImGui::EndDisabled();
|
||||
ImGui::PopID();
|
||||
}
|
||||
if (e->song.systemLen<DIV_MAX_CHIPS) {
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Button(ICON_FA_PLUS "##SysAdd");
|
||||
if (ImGui::BeginPopupContextItem("SysPickerA",ImGuiPopupFlags_MouseButtonLeft)) {
|
||||
DivSystem picked=systemPicker(false);
|
||||
if (picked!=DIV_SYSTEM_NULL) {
|
||||
if (!e->addSystem(picked)) {
|
||||
showError(fmt::sprintf(_("cannot add chip! (%s)"),e->getLastError()));
|
||||
} else {
|
||||
MARK_MODIFIED;
|
||||
}
|
||||
if (e->song.autoSystem) {
|
||||
autoDetectSystem();
|
||||
}
|
||||
updateWindowTitle();
|
||||
updateROMExportAvail();
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
if (ImGui::IsKeyPressed(ImGuiKey_Escape)) {
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
ImGui::EndPopup();
|
||||
|
||||
// channel LEDs and chip config button
|
||||
float height=0;
|
||||
if (settings.rackShowLEDs) {
|
||||
height=drawSystemChannelInfo(sysDef,dispatchOff,ImGui::GetContentRegionAvail().x-(ImGui::CalcTextSize(ICON_FA_CHEVRON_DOWN).x+ImGui::GetStyle().ItemSpacing.x));
|
||||
}
|
||||
|
||||
ImGuiID openedID=ImGui::GetID("OpenSysConfig");
|
||||
bool opened=openedConfig->GetBool(openedID,false);
|
||||
ImGui::SameLine();
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_SelectableTextAlign,ImVec2(0.5f,0.5f));
|
||||
if (ImGui::Selectable(opened?(ICON_FA_CHEVRON_UP "###OpenThing"):(ICON_FA_CHEVRON_DOWN "###OpenThing"),false,0,ImVec2(0,height))) {
|
||||
opened=!opened;
|
||||
openedConfig->SetBool(openedID,opened);
|
||||
}
|
||||
ImGui::PopStyleVar();
|
||||
|
||||
if (opened) {
|
||||
ImGui::Separator();
|
||||
ImGui::Indent();
|
||||
drawSysConf(i,i,e->song.system[i],e->song.systemFlags[i],true);
|
||||
ImGui::Unindent();
|
||||
}
|
||||
}
|
||||
ImGui::EndTable();
|
||||
ImGui::EndChild();
|
||||
ImGui::PopID();
|
||||
|
||||
dispatchOff+=sysDef->channels;
|
||||
}
|
||||
|
||||
if (e->song.systemLen<DIV_MAX_CHIPS) {
|
||||
ImGui::Button(ICON_FA_PLUS "##SysAdd");
|
||||
if (ImGui::BeginPopupContextItem("SysPickerA",ImGuiPopupFlags_MouseButtonLeft)) {
|
||||
DivSystem picked=systemPicker(false);
|
||||
if (picked!=DIV_SYSTEM_NULL) {
|
||||
if (!e->addSystem(picked)) {
|
||||
showError(fmt::sprintf(_("cannot add chip! (%s)"),e->getLastError()));
|
||||
} else {
|
||||
MARK_MODIFIED;
|
||||
}
|
||||
if (e->song.autoSystem) {
|
||||
autoDetectSystem();
|
||||
}
|
||||
updateWindowTitle();
|
||||
updateROMExportAvail();
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
if (ImGui::IsKeyPressed(ImGuiKey_Escape)) {
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_SYS_MANAGER;
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
#include "guiConst.h"
|
||||
#include "misc/cpp/imgui_stdlib.h"
|
||||
#include <fmt/printf.h>
|
||||
#include <imgui.h>
|
||||
|
||||
const char* FurnaceGUI::getSystemPartNumber(DivSystem sys, DivConfig& flags) {
|
||||
switch (sys) {
|
||||
|
|
@ -295,21 +296,41 @@ const char* FurnaceGUI::getSystemPartNumber(DivSystem sys, DivConfig& flags) {
|
|||
}
|
||||
}
|
||||
|
||||
void FurnaceGUI::drawSystemChannelInfo(const DivSysDef* whichDef) {
|
||||
float FurnaceGUI::drawSystemChannelInfo(const DivSysDef* whichDef, int keyHitOffset, float tooltipWidth) {
|
||||
ImDrawList* dl=ImGui::GetWindowDrawList();
|
||||
const ImVec2 p=ImGui::GetCursorScreenPos();
|
||||
float scaler=5.0f*dpiScale;
|
||||
if (tooltipWidth<=0.0f) tooltipWidth=ImGui::GetContentRegionAvail().x;
|
||||
ImVec2 sep=ImGui::GetStyle().ItemSpacing;
|
||||
sep.x*=0.5f;
|
||||
ImVec2 ledSize=ImVec2(
|
||||
(tooltipWidth-sep.x*(whichDef->channels-1))/(float)whichDef->channels,
|
||||
settings.iconSize*dpiScale
|
||||
);
|
||||
if (ledSize.x<8.0f*dpiScale) ledSize.x=8.0f*dpiScale;
|
||||
float x=p.x, y=p.y;
|
||||
float tooltipWidth=MIN(scrW*dpiScale,400.0f*dpiScale);
|
||||
for (int i=0; i<whichDef->channels; i++) {
|
||||
dl->AddRectFilled(ImVec2(x,y),ImVec2(x+1.5f*scaler,y+1.0f*scaler),ImGui::GetColorU32(uiColors[whichDef->chanTypes[i]+GUI_COLOR_CHANNEL_FM]),scaler);
|
||||
x+=2.0f*scaler;
|
||||
if ((x+1.5f*scaler)>tooltipWidth+p.x) {
|
||||
if (x+ledSize.x-0.125>tooltipWidth+p.x) {
|
||||
x=p.x;
|
||||
y+=1.5f*scaler;
|
||||
y+=ledSize.y+sep.y;
|
||||
}
|
||||
ImVec4 color=uiColors[whichDef->chanTypes[i]+GUI_COLOR_CHANNEL_FM];
|
||||
if (keyHitOffset>=0) {
|
||||
if (e->isChannelMuted(keyHitOffset+i)) {
|
||||
color=uiColors[GUI_COLOR_CHANNEL_MUTED];
|
||||
color.x*=MIN(1.0f,0.125f+keyHit1[keyHitOffset+i]*0.875f);
|
||||
color.y*=MIN(1.0f,0.125f+keyHit1[keyHitOffset+i]*0.875f);
|
||||
color.z*=MIN(1.0f,0.125f+keyHit1[keyHitOffset+i]*0.875f);
|
||||
} else {
|
||||
color.x*=MIN(1.0f,0.125f+keyHit1[keyHitOffset+i]*0.875f);
|
||||
color.y*=MIN(1.0f,0.125f+keyHit1[keyHitOffset+i]*0.875f);
|
||||
color.z*=MIN(1.0f,0.125f+keyHit1[keyHitOffset+i]*0.875f);
|
||||
}
|
||||
}
|
||||
dl->AddRectFilled(ImVec2(x,y),ImVec2(x+ledSize.x,y+ledSize.y),ImGui::GetColorU32(color),ledSize.y);
|
||||
x+=ledSize.x+sep.x;
|
||||
}
|
||||
ImGui::Dummy(ImVec2(0,(y-p.y)+1.5f*scaler));
|
||||
ImGui::Dummy(ImVec2(tooltipWidth,(y-p.y)+ledSize.y));
|
||||
return (y-p.y)+ledSize.y;
|
||||
}
|
||||
|
||||
void FurnaceGUI::drawSystemChannelInfoText(const DivSysDef* whichDef) {
|
||||
|
|
|
|||
|
|
@ -48,6 +48,10 @@
|
|||
tutorial.popupTimer=0; \
|
||||
}
|
||||
#else
|
||||
#ifndef _WIN32
|
||||
#include "../fileutils.h"
|
||||
#include <dirent.h>
|
||||
#endif
|
||||
#define CLICK_TO_OPEN(t) ImGui::TextColored(uiColors[GUI_COLOR_ACCENT_PRIMARY],t); if (ImGui::IsItemClicked()) SDL_OpenURL(t);
|
||||
#endif
|
||||
|
||||
|
|
@ -880,6 +884,39 @@ void FurnaceGUI::drawTutorial() {
|
|||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
|
||||
#ifdef IS_MOBILE
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button(_("My config was reset!"))) {
|
||||
#ifndef _WIN32
|
||||
String configPath1=e->getConfigPath();
|
||||
makeDir("/storage/emulated/0/failedConfig");
|
||||
DIR* dir=opendir(configPath1.c_str());
|
||||
if (dir==NULL) {
|
||||
showError(fmt::sprintf("Current config path is %s\nERROR - ERROR - ERROR\n%s",configPath1,strerror(errno)));
|
||||
} else {
|
||||
struct dirent* de;
|
||||
String inPath, outPath;
|
||||
while ((de=readdir(dir))!=NULL) {
|
||||
if (de->d_type==DT_REG) {
|
||||
inPath=configPath1+"/"+de->d_name;
|
||||
outPath=String("/storage/emulated/0/failedConfig/")+String(de->d_name);
|
||||
|
||||
logV("copying %s",de->d_name);
|
||||
if (!copyFiles(inPath.c_str(),outPath.c_str())) {
|
||||
logV("ERROR!!! %s",strerror(errno));
|
||||
}
|
||||
}
|
||||
}
|
||||
closedir(dir);
|
||||
|
||||
showError(fmt::sprintf("Current config path is %s\nNow exporting last config to storage. Check it out for bug diagnosis.",configPath1));
|
||||
}
|
||||
tutorial.protoWelcome=true;
|
||||
ImGui::CloseCurrentPopup();
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
ImGui::SetWindowPos(ImVec2(
|
||||
(canvasW-ImGui::GetWindowSize().x)*0.5,
|
||||
(canvasH-ImGui::GetWindowSize().y)*0.5
|
||||
|
|
|
|||
|
|
@ -48,47 +48,10 @@ void FurnaceGUI::drawVolMeter() {
|
|||
ImRect rect=ImRect(minArea,maxArea);
|
||||
ImGuiStyle& style=ImGui::GetStyle();
|
||||
ImGui::ItemSize(ImVec2(4.0f,4.0f),style.FramePadding.y);
|
||||
ImU32 lowColor=ImGui::GetColorU32(uiColors[GUI_COLOR_VOLMETER_LOW]);
|
||||
if (ImGui::ItemAdd(rect,ImGui::GetID("volMeter"))) {
|
||||
ImGui::RenderFrame(rect.Min,rect.Max,ImGui::GetColorU32(ImGuiCol_FrameBg),true,style.FrameRounding);
|
||||
int outChans=e->getAudioDescGot().outChans;
|
||||
for (int i=0; i<outChans; i++) {
|
||||
float logPeak=(20*log10(peak[i])/36.0);
|
||||
if (logPeak==NAN) logPeak=0.0;
|
||||
if (logPeak<-1.0) logPeak=-1.0;
|
||||
if (logPeak>0.0) {
|
||||
isClipping=8;
|
||||
logPeak=0.0;
|
||||
}
|
||||
logPeak+=1.0;
|
||||
ImU32 highColor=ImGui::GetColorU32(
|
||||
ImLerp(uiColors[GUI_COLOR_VOLMETER_LOW],uiColors[GUI_COLOR_VOLMETER_HIGH],logPeak)
|
||||
);
|
||||
ImRect s;
|
||||
if (aspectRatio) {
|
||||
s=ImRect(
|
||||
ImLerp(rect.Min,rect.Max,ImVec2(0,float(i)/outChans)),
|
||||
ImLerp(rect.Min,rect.Max,ImVec2(logPeak,float(i+1)/outChans))
|
||||
);
|
||||
if (i!=(outChans-1)) s.Max.y-=dpiScale;
|
||||
if (isClipping) {
|
||||
dl->AddRectFilled(s.Min,s.Max,ImGui::GetColorU32(uiColors[GUI_COLOR_VOLMETER_PEAK]));
|
||||
} else {
|
||||
dl->AddRectFilledMultiColor(s.Min,s.Max,lowColor,highColor,highColor,lowColor);
|
||||
}
|
||||
} else {
|
||||
s=ImRect(
|
||||
ImLerp(rect.Min,rect.Max,ImVec2(float(i)/outChans,1.0-logPeak)),
|
||||
ImLerp(rect.Min,rect.Max,ImVec2(float(i+1)/outChans,1.0))
|
||||
);
|
||||
if (i!=(outChans-1)) s.Max.x-=dpiScale;
|
||||
if (isClipping) {
|
||||
dl->AddRectFilled(s.Min,s.Max,ImGui::GetColorU32(uiColors[GUI_COLOR_VOLMETER_PEAK]));
|
||||
} else {
|
||||
dl->AddRectFilledMultiColor(s.Min,s.Max,highColor,highColor,lowColor,lowColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
drawVolMeterInternal(dl,rect,peak,outChans,aspectRatio);
|
||||
if (ImGui::IsItemHovered()) {
|
||||
if (aspectRatio) {
|
||||
ImGui::SetTooltip("%.1fdB",36*((ImGui::GetMousePos().x-ImGui::GetItemRectMin().x)/(rect.Max.x-rect.Min.x)-1.0));
|
||||
|
|
@ -102,3 +65,47 @@ void FurnaceGUI::drawVolMeter() {
|
|||
if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_VOL_METER;
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
void FurnaceGUI::drawVolMeterInternal(ImDrawList* dl, ImRect rect, float* data, int chans, bool aspectRatio) {
|
||||
ImU32 lowColor=ImGui::GetColorU32(uiColors[GUI_COLOR_VOLMETER_LOW]);
|
||||
ImGuiStyle& style=ImGui::GetStyle();
|
||||
ImGui::RenderFrame(rect.Min,rect.Max,ImGui::GetColorU32(ImGuiCol_FrameBg),true,style.FrameRounding);
|
||||
int isClipping=0;
|
||||
for (int i=0; i<chans; i++) {
|
||||
float logPeak=(20*log10(data[i])/36.0);
|
||||
if (logPeak==NAN) logPeak=0.0;
|
||||
if (logPeak<-1.0) logPeak=-1.0;
|
||||
if (logPeak>0.0) {
|
||||
isClipping=8;
|
||||
logPeak=0.0;
|
||||
}
|
||||
logPeak+=1.0;
|
||||
ImU32 highColor=ImGui::GetColorU32(
|
||||
ImLerp(uiColors[GUI_COLOR_VOLMETER_LOW],uiColors[GUI_COLOR_VOLMETER_HIGH],logPeak)
|
||||
);
|
||||
ImRect s;
|
||||
if (aspectRatio) {
|
||||
s=ImRect(
|
||||
ImLerp(rect.Min,rect.Max,ImVec2(0,float(i)/chans)),
|
||||
ImLerp(rect.Min,rect.Max,ImVec2(logPeak,float(i+1)/chans))
|
||||
);
|
||||
if (i!=(chans-1)) s.Max.y-=dpiScale;
|
||||
if (isClipping) {
|
||||
dl->AddRectFilled(s.Min,s.Max,ImGui::GetColorU32(uiColors[GUI_COLOR_VOLMETER_PEAK]));
|
||||
} else {
|
||||
dl->AddRectFilledMultiColor(s.Min,s.Max,lowColor,highColor,highColor,lowColor);
|
||||
}
|
||||
} else {
|
||||
s=ImRect(
|
||||
ImLerp(rect.Min,rect.Max,ImVec2(float(i)/chans,1.0-logPeak)),
|
||||
ImLerp(rect.Min,rect.Max,ImVec2(float(i+1)/chans,1.0))
|
||||
);
|
||||
if (i!=(chans-1)) s.Max.x-=dpiScale;
|
||||
if (isClipping) {
|
||||
dl->AddRectFilled(s.Min,s.Max,ImGui::GetColorU32(uiColors[GUI_COLOR_VOLMETER_PEAK]));
|
||||
} else {
|
||||
dl->AddRectFilledMultiColor(s.Min,s.Max,highColor,highColor,lowColor,lowColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue