mirror of
https://github.com/tildearrow/furnace.git
synced 2024-11-23 21:15:11 +00:00
sample editor workkkkkkk
This commit is contained in:
parent
c59c176de2
commit
689ed3bf65
9 changed files with 221 additions and 7 deletions
|
@ -19,6 +19,7 @@
|
|||
|
||||
#include "dataErrors.h"
|
||||
#include "song.h"
|
||||
#include <functional>
|
||||
#define _USE_MATH_DEFINES
|
||||
#include "engine.h"
|
||||
#include "instrument.h"
|
||||
|
@ -2275,6 +2276,12 @@ bool DivEngine::switchMaster() {
|
|||
return true;
|
||||
}
|
||||
|
||||
void DivEngine::synchronized(const std::function<void()>& what) {
|
||||
isBusy.lock();
|
||||
what();
|
||||
isBusy.unlock();
|
||||
}
|
||||
|
||||
TAAudioDesc& DivEngine::getAudioDescWant() {
|
||||
return want;
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "safeWriter.h"
|
||||
#include "../audio/taAudio.h"
|
||||
#include "blip_buf.h"
|
||||
#include <functional>
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
#include <map>
|
||||
|
@ -244,7 +245,6 @@ class DivEngine {
|
|||
bool perSystemEffect(int ch, unsigned char effect, unsigned char effectVal);
|
||||
bool perSystemPostEffect(int ch, unsigned char effect, unsigned char effectVal);
|
||||
void recalcChans();
|
||||
void renderSamples();
|
||||
void reset();
|
||||
void playSub(bool preserveDrift, int goalRow=0);
|
||||
|
||||
|
@ -587,6 +587,9 @@ class DivEngine {
|
|||
// get register cheatsheet
|
||||
const char** getRegisterSheet(int sys);
|
||||
|
||||
// UNSAFE render samples - only execute when locked
|
||||
void renderSamples();
|
||||
|
||||
// public render samples
|
||||
void renderSamplesP();
|
||||
|
||||
|
@ -614,6 +617,9 @@ class DivEngine {
|
|||
// switch master
|
||||
bool switchMaster();
|
||||
|
||||
// perform secure/sync operation
|
||||
void synchronized(const std::function<void()>& what);
|
||||
|
||||
// get audio desc want
|
||||
TAAudioDesc& getAudioDescWant();
|
||||
|
||||
|
|
|
@ -149,6 +149,35 @@ bool DivSample::init(unsigned int count) {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool DivSample::resize(unsigned int count) {
|
||||
if (depth==8) {
|
||||
if (data8!=NULL) {
|
||||
signed char* oldData8=data8;
|
||||
data8=NULL;
|
||||
initInternal(8,count);
|
||||
memcpy(data8,oldData8,MIN(count,samples));
|
||||
delete[] oldData8;
|
||||
} else {
|
||||
initInternal(8,count);
|
||||
}
|
||||
samples=count;
|
||||
return true;
|
||||
} else if (depth==16) {
|
||||
if (data16!=NULL) {
|
||||
short* oldData16=data16;
|
||||
data16=NULL;
|
||||
initInternal(16,count);
|
||||
memcpy(data16,oldData16,sizeof(short)*MIN(count,samples));
|
||||
delete[] oldData16;
|
||||
} else {
|
||||
initInternal(16,count);
|
||||
}
|
||||
samples=count;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void DivSample::render() {
|
||||
// step 1: convert to 16-bit if needed
|
||||
if (depth!=16) {
|
||||
|
|
|
@ -76,6 +76,14 @@ struct DivSample {
|
|||
*/
|
||||
bool init(unsigned int count);
|
||||
|
||||
/**
|
||||
* resize sample data. make sure the sample has been initialized before doing so.
|
||||
* @warning do not attempt to resize a sample outside of a synchronized block!
|
||||
* @param count number of samples.
|
||||
* @return whether it was successful.
|
||||
*/
|
||||
bool resize(unsigned int count);
|
||||
|
||||
/**
|
||||
* initialize the rest of sample formats for this sample.
|
||||
*/
|
||||
|
|
|
@ -7096,7 +7096,15 @@ FurnaceGUI::FurnaceGUI():
|
|||
randomMode(false),
|
||||
oldOrdersLen(0),
|
||||
sampleZoom(1.0),
|
||||
samplePos(0) {
|
||||
samplePos(0),
|
||||
resizeSize(1024),
|
||||
resampleTarget(32000),
|
||||
resampleStrat(5),
|
||||
amplifyVol(100.0),
|
||||
sampleSelStart(-1),
|
||||
sampleSelEnd(-1),
|
||||
sampleDragActive(false),
|
||||
sampleDragMode(false) {
|
||||
|
||||
// octave 1
|
||||
/*
|
||||
|
|
|
@ -738,6 +738,12 @@ class FurnaceGUI {
|
|||
// sample editor specific
|
||||
double sampleZoom;
|
||||
int samplePos;
|
||||
int resizeSize;
|
||||
double resampleTarget;
|
||||
int resampleStrat;
|
||||
float amplifyVol;
|
||||
int sampleSelStart, sampleSelEnd;
|
||||
bool sampleDragActive, sampleDragMode;
|
||||
|
||||
// visualizer
|
||||
float keyHit[DIV_MAX_CHANS];
|
||||
|
|
|
@ -112,4 +112,13 @@ const char* sampleDepths[17]={
|
|||
NULL,
|
||||
NULL,
|
||||
"16-bit PCM"
|
||||
};
|
||||
|
||||
const char* resampleStrats[]={
|
||||
"none",
|
||||
"linear",
|
||||
"cubic spline",
|
||||
"blep synthesis",
|
||||
"sinc",
|
||||
"best possible"
|
||||
};
|
|
@ -24,4 +24,5 @@ extern const char* noteNames[180];
|
|||
extern const char* noteNamesG[180];
|
||||
extern const char* pitchLabel[11];
|
||||
extern const char* insTypes[];
|
||||
extern const char* sampleDepths[17];
|
||||
extern const char* sampleDepths[17];
|
||||
extern const char* resampleStrats[];
|
|
@ -50,7 +50,10 @@ void FurnaceGUI::drawSampleEdit() {
|
|||
if (ImGui::BeginTable("SampleProps",4,ImGuiTableFlags_SizingStretchSame)) {
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
if (ImGui::BeginCombo("Type",sampleType.c_str())) {
|
||||
ImGui::Text("Type");
|
||||
ImGui::SameLine();
|
||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||
if (ImGui::BeginCombo("##SampleType",sampleType.c_str())) {
|
||||
for (int i=0; i<17; i++) {
|
||||
if (sampleDepths[i]==NULL) continue;
|
||||
if (ImGui::Selectable(sampleDepths[i])) {
|
||||
|
@ -66,13 +69,19 @@ void FurnaceGUI::drawSampleEdit() {
|
|||
}
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
if (ImGui::InputInt("Rate (Hz)",&sample->rate,10,200)) {
|
||||
ImGui::Text("Rate (Hz)");
|
||||
ImGui::SameLine();
|
||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||
if (ImGui::InputInt("##SampleRate",&sample->rate,10,200)) {
|
||||
if (sample->rate<100) sample->rate=100;
|
||||
if (sample->rate>96000) sample->rate=96000;
|
||||
}
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
if (ImGui::InputInt("Pitch of C-4 (Hz)",&sample->centerRate,10,200)) {
|
||||
ImGui::Text("C-4 (Hz)");
|
||||
ImGui::SameLine();
|
||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||
if (ImGui::InputInt("##SampleCenter",&sample->centerRate,10,200)) {
|
||||
if (sample->centerRate<100) sample->centerRate=100;
|
||||
if (sample->centerRate>65535) sample->centerRate=65535;
|
||||
}
|
||||
|
@ -89,6 +98,7 @@ void FurnaceGUI::drawSampleEdit() {
|
|||
}
|
||||
if (doLoop) {
|
||||
ImGui::SameLine();
|
||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||
if (ImGui::InputInt("##LoopPosition",&sample->loopStart,1,10)) {
|
||||
if (sample->loopStart<0 || sample->loopStart>=(int)sample->samples) {
|
||||
sample->loopStart=0;
|
||||
|
@ -123,6 +133,133 @@ void FurnaceGUI::drawSampleEdit() {
|
|||
}*/
|
||||
ImGui::Separator();
|
||||
|
||||
ImGui::Button(ICON_FA_I_CURSOR "##SSelect");
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Edit mode: Select");
|
||||
}
|
||||
ImGui::SameLine();
|
||||
ImGui::Button(ICON_FA_PENCIL "##SDraw");
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Edit mode: Draw");
|
||||
}
|
||||
ImGui::SameLine();
|
||||
ImGui::Dummy(ImVec2(4.0*dpiScale,dpiScale));
|
||||
ImGui::SameLine();
|
||||
ImGui::Button(ICON_FA_ARROWS_H "##SResize");
|
||||
if (ImGui::IsItemClicked()) {
|
||||
resizeSize=sample->samples;
|
||||
}
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Resize");
|
||||
}
|
||||
if (ImGui::BeginPopupContextItem("SResizeOpt",ImGuiPopupFlags_MouseButtonLeft)) {
|
||||
if (ImGui::InputInt("Samples",&resizeSize,1,64)) {
|
||||
if (resizeSize<0) resizeSize=0;
|
||||
if (resizeSize>16777215) resizeSize=16777215;
|
||||
}
|
||||
if (ImGui::Button("Resize")) {
|
||||
e->synchronized([this,sample]() {
|
||||
sample->resize(resizeSize);
|
||||
e->renderSamples();
|
||||
});
|
||||
updateSampleTex=true;
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
ImGui::EndPopup();
|
||||
} else {
|
||||
resizeSize=sample->samples;
|
||||
}
|
||||
ImGui::SameLine();
|
||||
ImGui::Button(ICON_FA_EXPAND "##SResample");
|
||||
if (ImGui::IsItemClicked()) {
|
||||
resampleTarget=sample->rate;
|
||||
}
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Resample");
|
||||
}
|
||||
if (ImGui::BeginPopupContextItem("SResampleOpt",ImGuiPopupFlags_MouseButtonLeft)) {
|
||||
ImGui::Text("Rate");
|
||||
if (ImGui::InputDouble("##SRRate",&resampleTarget,1.0,50.0,"%g")) {
|
||||
if (resampleTarget<0) resampleTarget=0;
|
||||
if (resampleTarget>96000) resampleTarget=96000;
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("0.5x")) {
|
||||
resampleTarget*=0.5;
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("==")) {
|
||||
resampleTarget=sample->rate;
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("2.0x")) {
|
||||
resampleTarget*=2.0;
|
||||
}
|
||||
double factor=resampleTarget/(double)sample->rate;
|
||||
if (ImGui::InputDouble("Factor",&factor,0.125,0.5,"%g")) {
|
||||
resampleTarget=(double)sample->rate*factor;
|
||||
if (resampleTarget<0) resampleTarget=0;
|
||||
if (resampleTarget>96000) resampleTarget=96000;
|
||||
}
|
||||
ImGui::Combo("Filter",&resampleStrat,resampleStrats,6);
|
||||
ImGui::Button("Resample");
|
||||
ImGui::EndPopup();
|
||||
} else {
|
||||
resampleTarget=sample->rate;
|
||||
}
|
||||
ImGui::SameLine();
|
||||
ImGui::Dummy(ImVec2(4.0*dpiScale,dpiScale));
|
||||
ImGui::SameLine();
|
||||
ImGui::Button(ICON_FA_VOLUME_UP "##SAmplify");
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Amplify");
|
||||
}
|
||||
if (ImGui::BeginPopupContextItem("SAmplifyOpt",ImGuiPopupFlags_MouseButtonLeft)) {
|
||||
ImGui::Text("Volume");
|
||||
if (ImGui::InputFloat("##SRVolume",&lifyVol,10.0,50.0,"%g%%")) {
|
||||
if (amplifyVol<0) amplifyVol=0;
|
||||
if (amplifyVol>10000) amplifyVol=10000;
|
||||
}
|
||||
ImGui::SameLine();
|
||||
ImGui::Text("(%.1fdB)",20.0*log10(amplifyVol/100.0f));
|
||||
ImGui::Button("Apply");
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
ImGui::SameLine();
|
||||
ImGui::Button(ICON_FA_ARROWS_V "##SNormalize");
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Normalize");
|
||||
}
|
||||
ImGui::SameLine();
|
||||
ImGui::Button(ICON_FA_ERASER "##SSilence");
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Apply silence");
|
||||
}
|
||||
ImGui::SameLine();
|
||||
ImGui::Dummy(ImVec2(4.0*dpiScale,dpiScale));
|
||||
ImGui::SameLine();
|
||||
ImGui::Button(ICON_FA_BACKWARD "##SReverse");
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Reverse");
|
||||
}
|
||||
ImGui::SameLine();
|
||||
ImGui::Button(ICON_FA_SORT_AMOUNT_ASC "##SInvert");
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Invert");
|
||||
}
|
||||
ImGui::SameLine();
|
||||
ImGui::Button(ICON_FA_LEVEL_DOWN "##SSign");
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Signed/unsigned exchange");
|
||||
}
|
||||
ImGui::SameLine();
|
||||
ImGui::Button(ICON_FA_INDUSTRY "##SFilter");
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Apply filter");
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
ImVec2 avail=ImGui::GetContentRegionAvail();
|
||||
avail.y-=ImGui::GetFontSize()+ImGui::GetStyle().ItemSpacing.y;
|
||||
int availX=avail.x;
|
||||
|
@ -193,7 +330,10 @@ void FurnaceGUI::drawSampleEdit() {
|
|||
updateSampleTex=false;
|
||||
}
|
||||
|
||||
ImGui::Image(sampleTex,avail);
|
||||
ImGui::ImageButton(sampleTex,avail,ImVec2(0,0),ImVec2(1,1),0);
|
||||
if (ImGui::IsItemClicked()) {
|
||||
printf("drawing\n");
|
||||
}
|
||||
|
||||
ImGui::Text("A workaround! Pretty cool huh?");
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue