From 2df7658fd0ee00d5d67aef6ea7a8dd1f2bff5b7e Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 21 Mar 2022 02:43:52 -0500 Subject: [PATCH] GUI: implement sample sel operations plenty of them --- src/engine/sample.cpp | 79 ++++++++++++++ src/engine/sample.h | 18 ++++ src/gui/sampleEdit.cpp | 232 ++++++++++++++++++++++++++++++++++++++--- 3 files changed, 313 insertions(+), 16 deletions(-) diff --git a/src/engine/sample.cpp b/src/engine/sample.cpp index 8b0c78e5..be9c5029 100644 --- a/src/engine/sample.cpp +++ b/src/engine/sample.cpp @@ -179,6 +179,85 @@ bool DivSample::resize(unsigned int count) { return false; } +bool DivSample::strip(unsigned int begin, unsigned int end) { + if (begin>samples) begin=samples; + if (end>samples) end=samples; + int count=samples-(end-begin); + if (count<=0) return resize(0); + if (depth==8) { + if (data8!=NULL) { + signed char* oldData8=data8; + data8=NULL; + initInternal(8,count); + if (begin>0) { + memcpy(data8,oldData8,begin); + } + if (samples-end>0) { + memcpy(data8+begin,oldData8+end,samples-end); + } + delete[] oldData8; + } else { + // do nothing + return true; + } + samples=count; + return true; + } else if (depth==16) { + if (data16!=NULL) { + short* oldData16=data16; + data16=NULL; + initInternal(16,count); + if (begin>0) { + memcpy(data16,oldData16,sizeof(short)*begin); + } + if (samples-end>0) { + memcpy(&(data16[begin]),&(oldData16[end]),sizeof(short)*(samples-end)); + } + delete[] oldData16; + } else { + // do nothing + return true; + } + samples=count; + return true; + } + return false; +} + +bool DivSample::trim(unsigned int begin, unsigned int end) { + int count=end-begin; + if (count==0) return true; + if (begin==0 && end==samples) return true; + if (depth==8) { + if (data8!=NULL) { + signed char* oldData8=data8; + data8=NULL; + initInternal(8,count); + memcpy(data8,oldData8+begin,count); + delete[] oldData8; + } else { + // do nothing + return true; + } + samples=count; + return true; + } else if (depth==16) { + if (data16!=NULL) { + short* oldData16=data16; + data16=NULL; + initInternal(16,count); + memcpy(data16,&(oldData16[begin]),sizeof(short)*count); + delete[] oldData16; + } else { + // do nothing + return true; + } + samples=count; + return true; + } + return false; +} + #define RESAMPLE_BEGIN \ if (samples<1) return true; \ int finalCount=(double)samples*(r/(double)rate); \ diff --git a/src/engine/sample.h b/src/engine/sample.h index 4737a00d..7e4d76be 100644 --- a/src/engine/sample.h +++ b/src/engine/sample.h @@ -102,6 +102,24 @@ struct DivSample { */ bool resize(unsigned int count); + /** + * remove part of the sample data. + * @warning do not attempt to strip a sample outside of a synchronized block! + * @param start the beginning. + * @param end the end. + * @return whether it was successful. + */ + bool strip(unsigned int begin, unsigned int end); + + /** + * clip the sample data to specified boundaries. + * @warning do not attempt to trim a sample outside of a synchronized block! + * @param start the beginning. + * @param end the end. + * @return whether it was successful. + */ + bool trim(unsigned int begin, unsigned int end); + /** * change the sample rate. * @warning do not attempt to resample outside of a synchronized block! diff --git a/src/gui/sampleEdit.cpp b/src/gui/sampleEdit.cpp index 429273f6..19062189 100644 --- a/src/gui/sampleEdit.cpp +++ b/src/gui/sampleEdit.cpp @@ -26,6 +26,19 @@ #include #include "guiConst.h" +#define SAMPLE_OP_BEGIN \ + unsigned int start=0; \ + unsigned int end=sample->samples; \ + if (sampleSelStart!=-1 && sampleSelEnd!=-1 && sampleSelStart!=sampleSelEnd) { \ + start=sampleSelStart; \ + end=sampleSelEnd; \ + if (start>end) { \ + start^=end; \ + end^=start; \ + start^=end; \ + } \ + } \ + void FurnaceGUI::drawSampleEdit() { if (nextWindow==GUI_WINDOW_SAMPLE_EDIT) { sampleEditOpen=true; @@ -223,33 +236,214 @@ void FurnaceGUI::drawSampleEdit() { } ImGui::SameLine(); ImGui::Text("(%.1fdB)",20.0*log10(amplifyVol/100.0f)); - ImGui::Button("Apply"); + if (ImGui::Button("Apply")) { + e->synchronized([this,sample]() { + SAMPLE_OP_BEGIN; + float vol=amplifyVol/100.0f; + + if (sample->depth==16) { + for (unsigned int i=start; idata16[i]*vol; + if (val<-32768) val=-32768; + if (val>32767) val=32767; + sample->data16[i]=val; + } + } else if (sample->depth==8) { + for (unsigned int i=start; idata8[i]*vol; + if (val<-128) val=-128; + if (val>127) val=127; + sample->data8[i]=val; + } + } + + updateSampleTex=true; + + e->renderSamples(); + }); + ImGui::CloseCurrentPopup(); + } ImGui::EndPopup(); } ImGui::SameLine(); - ImGui::Button(ICON_FA_ARROWS_V "##SNormalize"); + if (ImGui::Button(ICON_FA_ARROWS_V "##SNormalize")) { + e->synchronized([this,sample]() { + SAMPLE_OP_BEGIN; + float maxVal=0.0f; + + if (sample->depth==16) { + for (unsigned int i=start; idata16[i]/32767.0f); + if (val>maxVal) maxVal=val; + } + if (maxVal>1.0f) maxVal=1.0f; + if (maxVal>0.0f) { + float vol=1.0f/maxVal; + for (unsigned int i=start; idata16[i]*vol; + if (val<-32768) val=-32768; + if (val>32767) val=32767; + sample->data16[i]=val; + } + } + } else if (sample->depth==8) { + for (unsigned int i=start; idata8[i]/127.0f); + if (val>maxVal) maxVal=val; + } + if (maxVal>1.0f) maxVal=1.0f; + if (maxVal>0.0f) { + float vol=1.0f/maxVal; + for (unsigned int i=start; idata8[i]*vol; + if (val<-128) val=-128; + if (val>127) val=127; + sample->data8[i]=val; + } + } + } + + updateSampleTex=true; + + e->renderSamples(); + }); + } if (ImGui::IsItemHovered()) { ImGui::SetTooltip("Normalize"); } ImGui::SameLine(); - ImGui::Button(ICON_FA_ERASER "##SSilence"); + if (ImGui::Button(ICON_FA_ERASER "##SSilence")) { + e->synchronized([this,sample]() { + SAMPLE_OP_BEGIN; + + if (sample->depth==16) { + for (unsigned int i=start; idata16[i]=0; + } + } else if (sample->depth==8) { + for (unsigned int i=start; idata8[i]=0; + } + } + + updateSampleTex=true; + + e->renderSamples(); + }); + } if (ImGui::IsItemHovered()) { ImGui::SetTooltip("Apply silence"); } ImGui::SameLine(); + if (ImGui::Button(ICON_FA_TIMES "##SDelete")) { + e->synchronized([this,sample]() { + SAMPLE_OP_BEGIN; + + sample->strip(start,end); + updateSampleTex=true; + + e->renderSamples(); + }); + sampleSelStart=-1; + sampleSelEnd=-1; + } + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("Delete"); + } + ImGui::SameLine(); + if (ImGui::Button(ICON_FA_CROP "##STrim")) { + e->synchronized([this,sample]() { + SAMPLE_OP_BEGIN; + + sample->trim(start,end); + updateSampleTex=true; + + e->renderSamples(); + }); + sampleSelStart=-1; + sampleSelEnd=-1; + } + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("Trim"); + } + ImGui::SameLine(); ImGui::Dummy(ImVec2(4.0*dpiScale,dpiScale)); ImGui::SameLine(); - ImGui::Button(ICON_FA_BACKWARD "##SReverse"); + if (ImGui::Button(ICON_FA_BACKWARD "##SReverse")) { + e->synchronized([this,sample]() { + SAMPLE_OP_BEGIN; + + if (sample->depth==16) { + for (unsigned int i=start; idata16[i]^=sample->data16[ri]; + sample->data16[ri]^=sample->data16[i]; + sample->data16[i]^=sample->data16[ri]; + } + } else if (sample->depth==8) { + for (unsigned int i=start; idata8[i]^=sample->data8[ri]; + sample->data8[ri]^=sample->data8[i]; + sample->data8[i]^=sample->data8[ri]; + } + } + + updateSampleTex=true; + + e->renderSamples(); + }); + } if (ImGui::IsItemHovered()) { ImGui::SetTooltip("Reverse"); } ImGui::SameLine(); - ImGui::Button(ICON_FA_SORT_AMOUNT_ASC "##SInvert"); + if (ImGui::Button(ICON_FA_SORT_AMOUNT_ASC "##SInvert")) { + e->synchronized([this,sample]() { + SAMPLE_OP_BEGIN; + + if (sample->depth==16) { + for (unsigned int i=start; idata16[i]=-sample->data16[i]; + if (sample->data16[i]==-32768) sample->data16[i]=32767; + } + } else if (sample->depth==8) { + for (unsigned int i=start; idata8[i]=-sample->data8[i]; + if (sample->data16[i]==-128) sample->data16[i]=127; + } + } + + updateSampleTex=true; + + e->renderSamples(); + }); + } if (ImGui::IsItemHovered()) { ImGui::SetTooltip("Invert"); } ImGui::SameLine(); - ImGui::Button(ICON_FA_LEVEL_DOWN "##SSign"); + if (ImGui::Button(ICON_FA_LEVEL_DOWN "##SSign")) { + e->synchronized([this,sample]() { + SAMPLE_OP_BEGIN; + + if (sample->depth==16) { + for (unsigned int i=start; idata16[i]^=0x8000; + } + } else if (sample->depth==8) { + for (unsigned int i=start; idata8[i]^=0x80; + } + } + + updateSampleTex=true; + + e->renderSamples(); + }); + } if (ImGui::IsItemHovered()) { ImGui::SetTooltip("Signed/unsigned exchange"); } @@ -408,16 +602,22 @@ void FurnaceGUI::drawSampleEdit() { ImVec2 rectSize=ImGui::GetItemRectSize(); if (ImGui::IsItemClicked()) { - if (sample->samples>0 && (sample->depth==16 || sample->depth==8)) { - sampleDragStart=rectMin; - sampleDragAreaSize=rectSize; - sampleDrag16=(sample->depth==16); - sampleDragTarget=(sample->depth==16)?((void*)sample->data16):((void*)sample->data8); - sampleDragLen=sample->samples; - sampleDragActive=true; - sampleSelStart=-1; - sampleSelEnd=-1; - processDrags(ImGui::GetMousePos().x,ImGui::GetMousePos().y); + if (ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left)) { + sampleDragActive=false; + sampleSelStart=0; + sampleSelEnd=sample->samples; + } else { + if (sample->samples>0 && (sample->depth==16 || sample->depth==8)) { + sampleDragStart=rectMin; + sampleDragAreaSize=rectSize; + sampleDrag16=(sample->depth==16); + sampleDragTarget=(sample->depth==16)?((void*)sample->data16):((void*)sample->data8); + sampleDragLen=sample->samples; + sampleDragActive=true; + sampleSelStart=-1; + sampleSelEnd=-1; + processDrags(ImGui::GetMousePos().x,ImGui::GetMousePos().y); + } } } String statusBar=sampleDragMode?"Draw":"Select";