diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index 7ae0a8d33..ed784f173 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -2131,6 +2131,7 @@ void DivEngine::previewSample(int sample, int note, int pStart, int pEnd) { if (rate<100) rate=100; blip_set_rates(samp_bb,rate,got.rate); samp_prevSample=0; + sPreview.rate=rate; sPreview.pos=(sPreview.pBegin>=0)?sPreview.pBegin:0; sPreview.sample=sample; sPreview.wave=-1; @@ -2164,6 +2165,7 @@ void DivEngine::previewWave(int wave, int note) { if (rate<100) rate=100; blip_set_rates(samp_bb,rate,got.rate); samp_prevSample=0; + sPreview.rate=rate; sPreview.pos=0; sPreview.sample=-1; sPreview.wave=wave; @@ -2179,6 +2181,18 @@ void DivEngine::stopWavePreview() { BUSY_END; } +bool DivEngine::isPreviewingSample() { + return (sPreview.sample>=0 && sPreview.sample<(int)song.sample.size()); +} + +int DivEngine::getSamplePreviewPos() { + return sPreview.pos; +} + +double DivEngine::getSamplePreviewRate() { + return sPreview.rate; +} + String DivEngine::getConfigPath() { return configPath; } diff --git a/src/engine/engine.h b/src/engine/engine.h index 4561ba920..3a03c4278 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -387,12 +387,14 @@ class DivEngine { DivSystem sysFileMapDMF[256]; struct SamplePreview { + double rate; int sample; int wave; int pos; int pBegin, pEnd; bool dir; SamplePreview(): + rate(0.0), sample(-1), wave(-1), pos(0), @@ -601,6 +603,11 @@ class DivEngine { // reset playback state void syncReset(); + // sample preview query + bool isPreviewingSample(); + int getSamplePreviewPos(); + double getSamplePreviewRate(); + // trigger sample preview void previewSample(int sample, int note=-1, int pStart=-1, int pEnd=-1); void stopSamplePreview(); diff --git a/src/gui/doAction.cpp b/src/gui/doAction.cpp index 41771dd44..31d0ff48c 100644 --- a/src/gui/doAction.cpp +++ b/src/gui/doAction.cpp @@ -822,6 +822,7 @@ void FurnaceGUI::doAction(int what) { case GUI_ACTION_SAMPLE_CUT: { if (curSample<0 || curSample>=(int)e->song.sample.size()) break; DivSample* sample=e->song.sample[curSample]; + if (sample->depth!=DIV_SAMPLE_DEPTH_8BIT && sample->depth!=DIV_SAMPLE_DEPTH_16BIT) break; SAMPLE_OP_BEGIN; if (end-start<1) break; @@ -866,6 +867,7 @@ void FurnaceGUI::doAction(int what) { if (curSample<0 || curSample>=(int)e->song.sample.size()) break; if (sampleClipboard==NULL || sampleClipboardLen<1) break; DivSample* sample=e->song.sample[curSample]; + if (sample->depth!=DIV_SAMPLE_DEPTH_8BIT && sample->depth!=DIV_SAMPLE_DEPTH_16BIT) break; sample->prepareUndo(true); int pos=(sampleSelStart==-1 || sampleSelStart==sampleSelEnd)?sample->samples:sampleSelStart; if (pos>=(int)sample->samples) pos=sample->samples-1; @@ -896,6 +898,7 @@ void FurnaceGUI::doAction(int what) { if (curSample<0 || curSample>=(int)e->song.sample.size()) break; if (sampleClipboard==NULL || sampleClipboardLen<1) break; DivSample* sample=e->song.sample[curSample]; + if (sample->depth!=DIV_SAMPLE_DEPTH_8BIT && sample->depth!=DIV_SAMPLE_DEPTH_16BIT) break; sample->prepareUndo(true); int pos=(sampleSelStart==-1 || sampleSelStart==sampleSelEnd)?0:sampleSelStart; if (pos>=(int)sample->samples) pos=sample->samples-1; @@ -926,6 +929,7 @@ void FurnaceGUI::doAction(int what) { if (curSample<0 || curSample>=(int)e->song.sample.size()) break; if (sampleClipboard==NULL || sampleClipboardLen<1) break; DivSample* sample=e->song.sample[curSample]; + if (sample->depth!=DIV_SAMPLE_DEPTH_8BIT && sample->depth!=DIV_SAMPLE_DEPTH_16BIT) break; sample->prepareUndo(true); int pos=(sampleSelStart==-1 || sampleSelStart==sampleSelEnd)?0:sampleSelStart; if (pos>=(int)sample->samples) pos=sample->samples-1; @@ -981,6 +985,7 @@ void FurnaceGUI::doAction(int what) { case GUI_ACTION_SAMPLE_NORMALIZE: { if (curSample<0 || curSample>=(int)e->song.sample.size()) break; DivSample* sample=e->song.sample[curSample]; + if (sample->depth!=DIV_SAMPLE_DEPTH_8BIT && sample->depth!=DIV_SAMPLE_DEPTH_16BIT) break; sample->prepareUndo(true); e->lockEngine([this,sample]() { SAMPLE_OP_BEGIN; @@ -1028,6 +1033,7 @@ void FurnaceGUI::doAction(int what) { case GUI_ACTION_SAMPLE_FADE_IN: { if (curSample<0 || curSample>=(int)e->song.sample.size()) break; DivSample* sample=e->song.sample[curSample]; + if (sample->depth!=DIV_SAMPLE_DEPTH_8BIT && sample->depth!=DIV_SAMPLE_DEPTH_16BIT) break; sample->prepareUndo(true); e->lockEngine([this,sample]() { SAMPLE_OP_BEGIN; @@ -1058,6 +1064,7 @@ void FurnaceGUI::doAction(int what) { case GUI_ACTION_SAMPLE_FADE_OUT: { if (curSample<0 || curSample>=(int)e->song.sample.size()) break; DivSample* sample=e->song.sample[curSample]; + if (sample->depth!=DIV_SAMPLE_DEPTH_8BIT && sample->depth!=DIV_SAMPLE_DEPTH_16BIT) break; sample->prepareUndo(true); e->lockEngine([this,sample]() { SAMPLE_OP_BEGIN; @@ -1092,6 +1099,7 @@ void FurnaceGUI::doAction(int what) { case GUI_ACTION_SAMPLE_SILENCE: { if (curSample<0 || curSample>=(int)e->song.sample.size()) break; DivSample* sample=e->song.sample[curSample]; + if (sample->depth!=DIV_SAMPLE_DEPTH_8BIT && sample->depth!=DIV_SAMPLE_DEPTH_16BIT) break; sample->prepareUndo(true); e->lockEngine([this,sample]() { SAMPLE_OP_BEGIN; @@ -1116,6 +1124,7 @@ void FurnaceGUI::doAction(int what) { case GUI_ACTION_SAMPLE_DELETE: { if (curSample<0 || curSample>=(int)e->song.sample.size()) break; DivSample* sample=e->song.sample[curSample]; + if (sample->depth!=DIV_SAMPLE_DEPTH_8BIT && sample->depth!=DIV_SAMPLE_DEPTH_16BIT) break; sample->prepareUndo(true); e->lockEngine([this,sample]() { SAMPLE_OP_BEGIN; @@ -1133,6 +1142,7 @@ void FurnaceGUI::doAction(int what) { case GUI_ACTION_SAMPLE_TRIM: { if (curSample<0 || curSample>=(int)e->song.sample.size()) break; DivSample* sample=e->song.sample[curSample]; + if (sample->depth!=DIV_SAMPLE_DEPTH_8BIT && sample->depth!=DIV_SAMPLE_DEPTH_16BIT) break; sample->prepareUndo(true); e->lockEngine([this,sample]() { SAMPLE_OP_BEGIN; @@ -1150,6 +1160,7 @@ void FurnaceGUI::doAction(int what) { case GUI_ACTION_SAMPLE_REVERSE: { if (curSample<0 || curSample>=(int)e->song.sample.size()) break; DivSample* sample=e->song.sample[curSample]; + if (sample->depth!=DIV_SAMPLE_DEPTH_8BIT && sample->depth!=DIV_SAMPLE_DEPTH_16BIT) break; sample->prepareUndo(true); e->lockEngine([this,sample]() { SAMPLE_OP_BEGIN; @@ -1182,6 +1193,7 @@ void FurnaceGUI::doAction(int what) { case GUI_ACTION_SAMPLE_INVERT: { if (curSample<0 || curSample>=(int)e->song.sample.size()) break; DivSample* sample=e->song.sample[curSample]; + if (sample->depth!=DIV_SAMPLE_DEPTH_8BIT && sample->depth!=DIV_SAMPLE_DEPTH_16BIT) break; sample->prepareUndo(true); e->lockEngine([this,sample]() { SAMPLE_OP_BEGIN; @@ -1208,6 +1220,7 @@ void FurnaceGUI::doAction(int what) { case GUI_ACTION_SAMPLE_SIGN: { if (curSample<0 || curSample>=(int)e->song.sample.size()) break; DivSample* sample=e->song.sample[curSample]; + if (sample->depth!=DIV_SAMPLE_DEPTH_8BIT && sample->depth!=DIV_SAMPLE_DEPTH_16BIT) break; sample->prepareUndo(true); e->lockEngine([this,sample]() { SAMPLE_OP_BEGIN; diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 4c7850adf..035d7faa3 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -2134,18 +2134,20 @@ void FurnaceGUI::processDrags(int dragX, int dragY) { if (x1>=(int)sampleDragLen) x1=sampleDragLen-1; double y=0.5-double(dragY-sampleDragStart.y)/sampleDragAreaSize.y; if (sampleDragMode) { // draw - if (sampleDrag16) { - int val=y*65536; - if (val<-32768) val=-32768; - if (val>32767) val=32767; - for (int i=x; i<=x1; i++) ((short*)sampleDragTarget)[i]=val; - } else { - int val=y*256; - if (val<-128) val=-128; - if (val>127) val=127; - for (int i=x; i<=x1; i++) ((signed char*)sampleDragTarget)[i]=val; + if (sampleDragTarget) { + if (sampleDrag16) { + int val=y*65536; + if (val<-32768) val=-32768; + if (val>32767) val=32767; + for (int i=x; i<=x1; i++) ((short*)sampleDragTarget)[i]=val; + } else { + int val=y*256; + if (val<-128) val=-128; + if (val>127) val=127; + for (int i=x; i<=x1; i++) ((signed char*)sampleDragTarget)[i]=val; + } + updateSampleTex=true; } - updateSampleTex=true; } else { // select if (sampleSelStart<0) { sampleSelStart=x; @@ -2836,7 +2838,7 @@ void FurnaceGUI::pointDown(int x, int y, int button) { } void FurnaceGUI::pointUp(int x, int y, int button) { - if (macroDragActive || macroLoopDragActive || waveDragActive || (sampleDragActive && sampleDragMode)) { + if (macroDragActive || macroLoopDragActive || waveDragActive || (sampleDragActive && sampleDragMode && sampleDragTarget)) { MARK_MODIFIED; } if (macroDragActive && macroDragLineMode && !macroDragMouseMoved) { diff --git a/src/gui/sampleEdit.cpp b/src/gui/sampleEdit.cpp index 5188e0734..9ba9893ca 100644 --- a/src/gui/sampleEdit.cpp +++ b/src/gui/sampleEdit.cpp @@ -178,8 +178,6 @@ void FurnaceGUI::drawSampleEdit() { */ ImGui::Separator(); - ImGui::BeginDisabled(sample->depth!=DIV_SAMPLE_DEPTH_8BIT && sample->depth!=DIV_SAMPLE_DEPTH_16BIT); - pushToggleColors(!sampleDragMode); if (ImGui::Button(ICON_FA_I_CURSOR "##SSelect")) { sampleDragMode=false; @@ -197,6 +195,7 @@ void FurnaceGUI::drawSampleEdit() { if (ImGui::IsItemHovered()) { ImGui::SetTooltip("Edit mode: Draw"); } + ImGui::BeginDisabled(sample->depth!=DIV_SAMPLE_DEPTH_8BIT && sample->depth!=DIV_SAMPLE_DEPTH_16BIT); ImGui::SameLine(); ImGui::Dummy(ImVec2(4.0*dpiScale,dpiScale)); ImGui::SameLine(); @@ -564,6 +563,7 @@ void FurnaceGUI::drawSampleEdit() { } ImGui::EndPopup(); } + ImGui::EndDisabled(); ImGui::SameLine(); ImGui::Dummy(ImVec2(4.0*dpiScale,dpiScale)); ImGui::SameLine(); @@ -736,8 +736,6 @@ void FurnaceGUI::drawSampleEdit() { */ ImGui::Separator(); - ImGui::BeginDisabled(sample->depth!=DIV_SAMPLE_DEPTH_8BIT && sample->depth!=DIV_SAMPLE_DEPTH_16BIT); - pushToggleColors(!sampleDragMode); if (ImGui::Button(ICON_FA_I_CURSOR "##SSelect")) { sampleDragMode=false; @@ -755,6 +753,7 @@ void FurnaceGUI::drawSampleEdit() { if (ImGui::IsItemHovered()) { ImGui::SetTooltip("Edit mode: Draw"); } + ImGui::BeginDisabled(sample->depth!=DIV_SAMPLE_DEPTH_8BIT && sample->depth!=DIV_SAMPLE_DEPTH_16BIT); ImGui::SameLine(); ImGui::Dummy(ImVec2(7.0*dpiScale,dpiScale)); ImGui::SameLine(); @@ -1129,6 +1128,8 @@ void FurnaceGUI::drawSampleEdit() { ImGui::SetTooltip("Trim"); } + ImGui::EndDisabled(); + if (ImGui::Button(ICON_FA_PLAY "##PreviewSample")) { e->previewSample(curSample); } @@ -1308,11 +1309,23 @@ void FurnaceGUI::drawSampleEdit() { sampleSelStart=0; sampleSelEnd=sample->samples; } else { - if (sample->samples>0 && (sample->depth==DIV_SAMPLE_DEPTH_16BIT || sample->depth==DIV_SAMPLE_DEPTH_8BIT)) { + if (sample->samples>0) { sampleDragStart=rectMin; sampleDragAreaSize=rectSize; - sampleDrag16=(sample->depth==DIV_SAMPLE_DEPTH_16BIT); - sampleDragTarget=(sample->depth==DIV_SAMPLE_DEPTH_16BIT)?((void*)sample->data16):((void*)sample->data8); + switch (sample->depth) { + case DIV_SAMPLE_DEPTH_8BIT: + sampleDrag16=false; + sampleDragTarget=(void*)sample->data8; + break; + case DIV_SAMPLE_DEPTH_16BIT: + sampleDrag16=true; + sampleDragTarget=(void*)sample->data16; + break; + default: + sampleDrag16=true; + sampleDragTarget=NULL; + break; + } sampleDragLen=sample->samples; sampleDragActive=true; sampleSelStart=-1; @@ -1328,12 +1341,15 @@ void FurnaceGUI::drawSampleEdit() { } if (ImGui::BeginPopup("SRightClick",ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_AlwaysAutoResize)) { + ImGui::BeginDisabled(sample->depth!=DIV_SAMPLE_DEPTH_8BIT && sample->depth!=DIV_SAMPLE_DEPTH_16BIT); if (ImGui::MenuItem("cut",BIND_FOR(GUI_ACTION_SAMPLE_CUT))) { doAction(GUI_ACTION_SAMPLE_CUT); } + ImGui::EndDisabled(); if (ImGui::MenuItem("copy",BIND_FOR(GUI_ACTION_SAMPLE_COPY))) { doAction(GUI_ACTION_SAMPLE_COPY); } + ImGui::BeginDisabled(sample->depth!=DIV_SAMPLE_DEPTH_8BIT && sample->depth!=DIV_SAMPLE_DEPTH_16BIT); if (ImGui::MenuItem("paste",BIND_FOR(GUI_ACTION_SAMPLE_PASTE))) { doAction(GUI_ACTION_SAMPLE_PASTE); } @@ -1343,6 +1359,7 @@ void FurnaceGUI::drawSampleEdit() { if (ImGui::MenuItem("paste (mix)",BIND_FOR(GUI_ACTION_SAMPLE_PASTE_MIX))) { doAction(GUI_ACTION_SAMPLE_PASTE_MIX); } + ImGui::EndDisabled(); if (ImGui::MenuItem("select all",BIND_FOR(GUI_ACTION_SAMPLE_SELECT_ALL))) { doAction(GUI_ACTION_SAMPLE_SELECT_ALL); } @@ -1368,7 +1385,11 @@ void FurnaceGUI::drawSampleEdit() { end^=start; start^=end; } - statusBar+=fmt::sprintf(" (%d-%d)",start,end); + if (start==end) { + statusBar+=fmt::sprintf(" (%d)",start); + } else { + statusBar+=fmt::sprintf(" (%d-%d: %d samples)",start,end,end-start); + } drawSelection=true; } } @@ -1420,6 +1441,10 @@ void FurnaceGUI::drawSampleEdit() { } } + if (e->isPreviewingSample()) { + statusBar+=fmt::sprintf(" | %.2fHz",e->getSamplePreviewRate()); + } + if (drawSelection) { int start=sampleSelStart; int end=sampleSelEnd; @@ -1464,11 +1489,9 @@ void FurnaceGUI::drawSampleEdit() { } } - if (sample->depth!=DIV_SAMPLE_DEPTH_8BIT && sample->depth!=DIV_SAMPLE_DEPTH_16BIT) { + if (sample->depth!=DIV_SAMPLE_DEPTH_8BIT && sample->depth!=DIV_SAMPLE_DEPTH_16BIT && sampleDragMode) { statusBar="Non-8/16-bit samples cannot be edited without prior conversion."; } - - ImGui::EndDisabled(); ImGui::SetCursorPosY(ImGui::GetCursorPosY()+ImGui::GetStyle().ScrollbarSize); ImGui::Text("%s",statusBar.c_str());