mirror of
https://github.com/tildearrow/furnace.git
synced 2024-11-16 01:35:07 +00:00
GUI: implement sample sel operations
plenty of them
This commit is contained in:
parent
a68dbed760
commit
2df7658fd0
3 changed files with 313 additions and 16 deletions
|
@ -179,6 +179,85 @@ bool DivSample::resize(unsigned int count) {
|
||||||
return false;
|
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 \
|
#define RESAMPLE_BEGIN \
|
||||||
if (samples<1) return true; \
|
if (samples<1) return true; \
|
||||||
int finalCount=(double)samples*(r/(double)rate); \
|
int finalCount=(double)samples*(r/(double)rate); \
|
||||||
|
|
|
@ -102,6 +102,24 @@ struct DivSample {
|
||||||
*/
|
*/
|
||||||
bool resize(unsigned int count);
|
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.
|
* change the sample rate.
|
||||||
* @warning do not attempt to resample outside of a synchronized block!
|
* @warning do not attempt to resample outside of a synchronized block!
|
||||||
|
|
|
@ -26,6 +26,19 @@
|
||||||
#include <fmt/printf.h>
|
#include <fmt/printf.h>
|
||||||
#include "guiConst.h"
|
#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() {
|
void FurnaceGUI::drawSampleEdit() {
|
||||||
if (nextWindow==GUI_WINDOW_SAMPLE_EDIT) {
|
if (nextWindow==GUI_WINDOW_SAMPLE_EDIT) {
|
||||||
sampleEditOpen=true;
|
sampleEditOpen=true;
|
||||||
|
@ -223,33 +236,214 @@ void FurnaceGUI::drawSampleEdit() {
|
||||||
}
|
}
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
ImGui::Text("(%.1fdB)",20.0*log10(amplifyVol/100.0f));
|
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; i<end; i++) {
|
||||||
|
float val=sample->data16[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; i<end; i++) {
|
||||||
|
float val=sample->data8[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::EndPopup();
|
||||||
}
|
}
|
||||||
ImGui::SameLine();
|
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; i<end; i++) {
|
||||||
|
float val=fabs((float)sample->data16[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; i<end; i++) {
|
||||||
|
float val=sample->data16[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; i<end; i++) {
|
||||||
|
float val=fabs((float)sample->data8[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; i<end; i++) {
|
||||||
|
float val=sample->data8[i]*vol;
|
||||||
|
if (val<-128) val=-128;
|
||||||
|
if (val>127) val=127;
|
||||||
|
sample->data8[i]=val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updateSampleTex=true;
|
||||||
|
|
||||||
|
e->renderSamples();
|
||||||
|
});
|
||||||
|
}
|
||||||
if (ImGui::IsItemHovered()) {
|
if (ImGui::IsItemHovered()) {
|
||||||
ImGui::SetTooltip("Normalize");
|
ImGui::SetTooltip("Normalize");
|
||||||
}
|
}
|
||||||
ImGui::SameLine();
|
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; i<end; i++) {
|
||||||
|
sample->data16[i]=0;
|
||||||
|
}
|
||||||
|
} else if (sample->depth==8) {
|
||||||
|
for (unsigned int i=start; i<end; i++) {
|
||||||
|
sample->data8[i]=0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updateSampleTex=true;
|
||||||
|
|
||||||
|
e->renderSamples();
|
||||||
|
});
|
||||||
|
}
|
||||||
if (ImGui::IsItemHovered()) {
|
if (ImGui::IsItemHovered()) {
|
||||||
ImGui::SetTooltip("Apply silence");
|
ImGui::SetTooltip("Apply silence");
|
||||||
}
|
}
|
||||||
ImGui::SameLine();
|
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::Dummy(ImVec2(4.0*dpiScale,dpiScale));
|
||||||
ImGui::SameLine();
|
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; i<end; i++) {
|
||||||
|
unsigned int ri=end-i-1+start;
|
||||||
|
if (ri<=i) break;
|
||||||
|
sample->data16[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; i<end; i++) {
|
||||||
|
unsigned int ri=end-i-1+start;
|
||||||
|
if (ri<=i) break;
|
||||||
|
sample->data8[i]^=sample->data8[ri];
|
||||||
|
sample->data8[ri]^=sample->data8[i];
|
||||||
|
sample->data8[i]^=sample->data8[ri];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updateSampleTex=true;
|
||||||
|
|
||||||
|
e->renderSamples();
|
||||||
|
});
|
||||||
|
}
|
||||||
if (ImGui::IsItemHovered()) {
|
if (ImGui::IsItemHovered()) {
|
||||||
ImGui::SetTooltip("Reverse");
|
ImGui::SetTooltip("Reverse");
|
||||||
}
|
}
|
||||||
ImGui::SameLine();
|
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; i<end; i++) {
|
||||||
|
sample->data16[i]=-sample->data16[i];
|
||||||
|
if (sample->data16[i]==-32768) sample->data16[i]=32767;
|
||||||
|
}
|
||||||
|
} else if (sample->depth==8) {
|
||||||
|
for (unsigned int i=start; i<end; i++) {
|
||||||
|
sample->data8[i]=-sample->data8[i];
|
||||||
|
if (sample->data16[i]==-128) sample->data16[i]=127;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updateSampleTex=true;
|
||||||
|
|
||||||
|
e->renderSamples();
|
||||||
|
});
|
||||||
|
}
|
||||||
if (ImGui::IsItemHovered()) {
|
if (ImGui::IsItemHovered()) {
|
||||||
ImGui::SetTooltip("Invert");
|
ImGui::SetTooltip("Invert");
|
||||||
}
|
}
|
||||||
ImGui::SameLine();
|
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; i<end; i++) {
|
||||||
|
sample->data16[i]^=0x8000;
|
||||||
|
}
|
||||||
|
} else if (sample->depth==8) {
|
||||||
|
for (unsigned int i=start; i<end; i++) {
|
||||||
|
sample->data8[i]^=0x80;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updateSampleTex=true;
|
||||||
|
|
||||||
|
e->renderSamples();
|
||||||
|
});
|
||||||
|
}
|
||||||
if (ImGui::IsItemHovered()) {
|
if (ImGui::IsItemHovered()) {
|
||||||
ImGui::SetTooltip("Signed/unsigned exchange");
|
ImGui::SetTooltip("Signed/unsigned exchange");
|
||||||
}
|
}
|
||||||
|
@ -408,16 +602,22 @@ void FurnaceGUI::drawSampleEdit() {
|
||||||
ImVec2 rectSize=ImGui::GetItemRectSize();
|
ImVec2 rectSize=ImGui::GetItemRectSize();
|
||||||
|
|
||||||
if (ImGui::IsItemClicked()) {
|
if (ImGui::IsItemClicked()) {
|
||||||
if (sample->samples>0 && (sample->depth==16 || sample->depth==8)) {
|
if (ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left)) {
|
||||||
sampleDragStart=rectMin;
|
sampleDragActive=false;
|
||||||
sampleDragAreaSize=rectSize;
|
sampleSelStart=0;
|
||||||
sampleDrag16=(sample->depth==16);
|
sampleSelEnd=sample->samples;
|
||||||
sampleDragTarget=(sample->depth==16)?((void*)sample->data16):((void*)sample->data8);
|
} else {
|
||||||
sampleDragLen=sample->samples;
|
if (sample->samples>0 && (sample->depth==16 || sample->depth==8)) {
|
||||||
sampleDragActive=true;
|
sampleDragStart=rectMin;
|
||||||
sampleSelStart=-1;
|
sampleDragAreaSize=rectSize;
|
||||||
sampleSelEnd=-1;
|
sampleDrag16=(sample->depth==16);
|
||||||
processDrags(ImGui::GetMousePos().x,ImGui::GetMousePos().y);
|
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";
|
String statusBar=sampleDragMode?"Draw":"Select";
|
||||||
|
|
Loading…
Reference in a new issue