diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index 36e807ac..270d77b5 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -4851,6 +4851,20 @@ void* DivEngine::getDispatchChanState(int ch) { return disCont[dispatchOfChan[ch]].dispatch->getChanState(dispatchChanOfChan[ch]); } +void DivEngine::enableCommandStream(bool enable) { + cmdStreamEnabled=enable; +} + +void DivEngine::getCommandStream(std::vector& where) { + isBusy.lock(); + where.clear(); + for (DivCommand& i: cmdStream) { + where.push_back(i); + } + cmdStream.clear(); + isBusy.unlock(); +} + void DivEngine::playSub(bool preserveDrift, int goalRow) { reset(); if (preserveDrift && curOrder==0) return; @@ -4900,6 +4914,7 @@ void DivEngine::playSub(bool preserveDrift, int goalRow) { if (!preserveDrift) { ticks=1; } + cmdStream.clear(); } int DivEngine::calcBaseFreq(double clock, double divider, int note, bool period) { diff --git a/src/engine/engine.h b/src/engine/engine.h index 72c9942d..2642e73c 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -170,6 +170,7 @@ class DivEngine { bool exporting; bool halted; bool forceMono; + bool cmdStreamEnabled; int ticks, curRow, curOrder, remainingLoops, nextSpeed, divider; int cycles, clockDrift, stepPlay; int changeOrd, changePos, totalSeconds, totalTicks, totalTicksR, totalCmds, lastCmds, cmdsPerSecond, globalPitch; @@ -189,6 +190,7 @@ class DivEngine { String lastError; String warnings; std::vector audioDevs; + std::vector cmdStream; struct SamplePreview { int sample; @@ -519,6 +521,12 @@ class DivEngine { // get dispatch channel state void* getDispatchChanState(int chan); + // enable command stream dumping + void enableCommandStream(bool enable); + + // get command stream + void getCommandStream(std::vector& where); + // set the audio system. void setAudio(DivAudioEngines which); @@ -622,6 +630,7 @@ class DivEngine { exporting(false), halted(false), forceMono(false), + cmdStreamEnabled(false), ticks(0), curRow(0), curOrder(0), diff --git a/src/engine/playback.cpp b/src/engine/playback.cpp index aeea2b35..9df66230 100644 --- a/src/engine/playback.cpp +++ b/src/engine/playback.cpp @@ -132,6 +132,9 @@ int DivEngine::dispatchCmd(DivCommand c) { printf("%8d | %d: %s(%d, %d)\n",totalTicksR,c.chan,cmdName[c.cmd],c.value,c.value2); } totalCmds++; + if (cmdStreamEnabled && cmdStream.size()<2000) { + cmdStream.push_back(c); + } c.chan=dispatchChanOfChan[c.dis]; return disCont[dispatchOfChan[c.dis]].dispatch->dispatch(c); } diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index c929fc21..1cf8c24c 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -169,7 +169,9 @@ const char* pitchLabel[11]={ String getHomeDir(); -ImU32 partTest[256]; +inline float randRange(float min, float max) { + return min+((float)rand()/(float)RAND_MAX)*(max-min); +} bool Particle::update() { pos.x+=speed.x; @@ -3176,6 +3178,9 @@ void FurnaceGUI::drawPattern() { } if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) { fancyPattern=!fancyPattern; + e->enableCommandStream(fancyPattern); + e->getCommandStream(cmdStream); + cmdStream.clear(); } for (int i=0; isong.chanShow[i]) continue; @@ -3516,8 +3521,45 @@ void FurnaceGUI::drawPattern() { } if (fancyPattern) { // visualizer + e->getCommandStream(cmdStream); ImDrawList* dl=ImGui::GetWindowDrawList(); ImVec2 off=ImGui::GetWindowPos(); + + // commands + for (DivCommand& i: cmdStream) { + if (i.cmd==DIV_CMD_PITCH) continue; + //if (i.cmd==DIV_CMD_NOTE_ON) continue; + if (i.cmd==DIV_CMD_PRE_NOTE) continue; + if (i.cmd==DIV_CMD_INSTRUMENT) continue; + + float width=patChanX[i.chan+1]-patChanX[i.chan]; + float speedY=-18.0f; + int num=3; + const char* partIcon=ICON_FA_MICROCHIP; + + if (i.cmd==DIV_CMD_VOLUME) { + speedY=-18.0f-(10.0f*((float)i.value/(float)e->getMaxVolumeChan(i.chan))); + partIcon=ICON_FA_VOLUME_UP; + num=12.0f*((float)i.value/(float)e->getMaxVolumeChan(i.chan)); + } + + for (int j=0; jFontSize), + randRange(-5,5), + speedY+randRange(-5,5), + 0.6f, + 1.0f, + 255.0f, + 8.0f + )); + } + } + + // note slides ImVec2 arrowPoints[7]; for (int i=0; igetChanState(i); @@ -3528,16 +3570,16 @@ void FurnaceGUI::drawPattern() { if (e->isPlaying()) { particles.push_back(Particle( - partTest, + pitchGrad, (ch->portaNote<=ch->note)?ICON_FA_CHEVRON_DOWN:ICON_FA_CHEVRON_UP, off.x+patChanX[i]+fmod(rand(),width), off.y+fmod(rand(),MAX(1,ImGui::GetWindowHeight())), 0.0f, - (7.0f+(rand()%5)+ch->portaSpeed)*((ch->portaNote<=ch->note)?1:-1), + (7.0f+(rand()%5)+pow(ch->portaSpeed,0.7f))*((ch->portaNote<=ch->note)?1:-1), 0.0f, 1.0f, 255.0f, - 18.0f + 15.0f )); } @@ -3576,11 +3618,14 @@ void FurnaceGUI::drawPattern() { } // particle simulation + ImDrawList* fdl=ImGui::GetForegroundDrawList(); for (size_t i=0; iAddText( - part.pos, + fdl->AddText( + iconFont, + iconFont->FontSize, + ImVec2(part.pos.x-iconFont->FontSize*0.5,part.pos.y-iconFont->FontSize*0.5), part.colors[(int)part.life], part.type ); @@ -4446,6 +4491,7 @@ void FurnaceGUI::syncSettings() { settings.restartOnFlagChange=e->getConfInt("restartOnFlagChange",1); settings.statusDisplay=e->getConfInt("statusDisplay",0); settings.dpiScale=e->getConfFloat("dpiScale",0.0f); + settings.viewPrevPattern=e->getConfInt("viewPrevPattern",1); // keybinds LOAD_KEYBIND(GUI_ACTION_OPEN,FURKMOD_CMD|SDLK_o); @@ -4637,6 +4683,7 @@ void FurnaceGUI::commitSettings() { e->setConf("restartOnFlagChange",settings.restartOnFlagChange); e->setConf("statusDisplay",settings.statusDisplay); e->setConf("dpiScale",settings.dpiScale); + e->setConf("viewPrevPattern",settings.viewPrevPattern); PUT_UI_COLOR(GUI_COLOR_BACKGROUND); PUT_UI_COLOR(GUI_COLOR_FRAME_BACKGROUND); @@ -8468,7 +8515,32 @@ void FurnaceGUI::applyUISettings() { ImGui::GetStyle()=sty; for (int i=0; i<256; i++) { - partTest[i]=ImGui::GetColorU32(ImVec4(1.0f,1.0f,1.0f,(float)i/255.0f)); + ImVec4& base=uiColors[GUI_COLOR_PATTERN_EFFECT_PITCH]; + pitchGrad[i]=ImGui::GetColorU32(ImVec4(base.x,base.y,base.z,((float)i/255.0f)*base.w)); + } + for (int i=0; i<256; i++) { + ImVec4& base=uiColors[GUI_COLOR_PATTERN_ACTIVE]; + noteGrad[i]=ImGui::GetColorU32(ImVec4(base.x,base.y,base.z,((float)i/255.0f)*base.w)); + } + for (int i=0; i<256; i++) { + ImVec4& base=uiColors[GUI_COLOR_PATTERN_EFFECT_PANNING]; + panGrad[i]=ImGui::GetColorU32(ImVec4(base.x,base.y,base.z,((float)i/255.0f)*base.w)); + } + for (int i=0; i<256; i++) { + ImVec4& base=uiColors[GUI_COLOR_PATTERN_INS]; + insGrad[i]=ImGui::GetColorU32(ImVec4(base.x,base.y,base.z,((float)i/255.0f)*base.w)); + } + for (int i=0; i<256; i++) { + ImVec4& base=volColors[i/2]; + volGrad[i]=ImGui::GetColorU32(ImVec4(base.x,base.y,base.z,((float)i/255.0f)*base.w)); + } + for (int i=0; i<256; i++) { + ImVec4& base=uiColors[GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY]; + sysCmd1Grad[i]=ImGui::GetColorU32(ImVec4(base.x,base.y,base.z,((float)i/255.0f)*base.w)); + } + for (int i=0; i<256; i++) { + ImVec4& base=uiColors[GUI_COLOR_PATTERN_EFFECT_SYS_SECONDARY]; + sysCmd2Grad[i]=ImGui::GetColorU32(ImVec4(base.x,base.y,base.z,((float)i/255.0f)*base.w)); } // set to 800 for now due to problems with unifont diff --git a/src/gui/gui.h b/src/gui/gui.h index f7c9c23c..340fcde8 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -24,6 +24,7 @@ #include #include #include +#include enum FurnaceGUIColors { GUI_COLOR_BACKGROUND=0, @@ -411,6 +412,13 @@ class FurnaceGUI { ImFont* bigFont; ImVec4 uiColors[GUI_COLOR_MAX]; ImVec4 volColors[128]; + ImU32 pitchGrad[256]; + ImU32 volGrad[256]; + ImU32 noteGrad[256]; + ImU32 panGrad[256]; + ImU32 insGrad[256]; + ImU32 sysCmd1Grad[256]; + ImU32 sysCmd2Grad[256]; struct Settings { int mainFontSize, patFontSize, iconSize; @@ -444,6 +452,7 @@ class FurnaceGUI { int restartOnFlagChange; int statusDisplay; float dpiScale; + int viewPrevPattern; unsigned int maxUndoSteps; String mainFontPath; String patFontPath; @@ -483,6 +492,7 @@ class FurnaceGUI { restartOnFlagChange(1), statusDisplay(0), dpiScale(0.0f), + viewPrevPattern(1), maxUndoSteps(100), mainFontPath(""), patFontPath(""), @@ -531,7 +541,7 @@ class FurnaceGUI { note(n) {} }; std::vector activeNotes; - + std::vector cmdStream; std::vector particles; bool wavePreviewOn;