Merge branch 'master' into preset1
This commit is contained in:
commit
39fa3d7d85
30 changed files with 3059 additions and 48 deletions
|
|
@ -92,10 +92,12 @@ bool TAMidiOut::closeDevice() {
|
|||
}
|
||||
|
||||
std::vector<String> TAMidiIn::listDevices() {
|
||||
logW("attempting to list devices of abstract TAMidiIn!");
|
||||
return std::vector<String>();
|
||||
}
|
||||
|
||||
std::vector<String> TAMidiOut::listDevices() {
|
||||
logW("attempting to list devices of abstract TAMidiOut!");
|
||||
return std::vector<String>();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2067,6 +2067,8 @@ int DivEngine::addSample() {
|
|||
sample->name=fmt::sprintf("Sample %d",sampleCount);
|
||||
song.sample.push_back(sample);
|
||||
song.sampleLen=sampleCount+1;
|
||||
sPreview.sample=-1;
|
||||
sPreview.pos=0;
|
||||
saveLock.unlock();
|
||||
renderSamples();
|
||||
BUSY_END;
|
||||
|
|
@ -2183,6 +2185,7 @@ int DivEngine::addSampleFromFile(const char* path) {
|
|||
return -1;
|
||||
#else
|
||||
SF_INFO si;
|
||||
memset(&si,0,sizeof(SF_INFO));
|
||||
SNDFILE* f=sf_open(path,SFM_READ,&si);
|
||||
if (f==NULL) {
|
||||
BUSY_END;
|
||||
|
|
@ -2200,8 +2203,22 @@ int DivEngine::addSampleFromFile(const char* path) {
|
|||
BUSY_END;
|
||||
return -1;
|
||||
}
|
||||
short* buf=new short[si.channels*si.frames];
|
||||
if (sf_readf_short(f,buf,si.frames)!=si.frames) {
|
||||
void* buf=NULL;
|
||||
sf_count_t sampleLen=sizeof(short);
|
||||
if ((si.format&SF_FORMAT_SUBMASK)==SF_FORMAT_PCM_U8) {
|
||||
logD("sample is 8-bit unsigned");
|
||||
buf=new unsigned char[si.channels*si.frames];
|
||||
sampleLen=sizeof(unsigned char);
|
||||
} else if ((si.format&SF_FORMAT_SUBMASK)==SF_FORMAT_FLOAT) {
|
||||
logD("sample is 32-bit float");
|
||||
buf=new float[si.channels*si.frames];
|
||||
sampleLen=sizeof(float);
|
||||
} else {
|
||||
logD("sample is 16-bit signed");
|
||||
buf=new short[si.channels*si.frames];
|
||||
sampleLen=sizeof(short);
|
||||
}
|
||||
if (sf_read_raw(f,buf,si.frames*si.channels*sampleLen)!=(si.frames*si.channels*sampleLen)) {
|
||||
logW("sample read size mismatch!");
|
||||
}
|
||||
DivSample* sample=new DivSample;
|
||||
|
|
@ -2215,19 +2232,41 @@ int DivEngine::addSampleFromFile(const char* path) {
|
|||
sample->depth=16;
|
||||
}
|
||||
sample->init(si.frames);
|
||||
for (int i=0; i<si.frames*si.channels; i+=si.channels) {
|
||||
int averaged=0;
|
||||
for (int j=0; j<si.channels; j++) {
|
||||
averaged+=buf[i+j];
|
||||
if ((si.format&SF_FORMAT_SUBMASK)==SF_FORMAT_PCM_U8) {
|
||||
for (int i=0; i<si.frames*si.channels; i+=si.channels) {
|
||||
int averaged=0;
|
||||
for (int j=0; j<si.channels; j++) {
|
||||
averaged+=((int)((unsigned char*)buf)[i+j])-128;
|
||||
}
|
||||
averaged/=si.channels;
|
||||
sample->data8[index++]=averaged;
|
||||
}
|
||||
averaged/=si.channels;
|
||||
if (((si.format&SF_FORMAT_SUBMASK)==SF_FORMAT_PCM_U8)) {
|
||||
sample->data8[index++]=averaged>>8;
|
||||
} else {
|
||||
delete[] (unsigned char*)buf;
|
||||
} else if ((si.format&SF_FORMAT_SUBMASK)==SF_FORMAT_FLOAT) {
|
||||
for (int i=0; i<si.frames*si.channels; i+=si.channels) {
|
||||
float averaged=0.0f;
|
||||
for (int j=0; j<si.channels; j++) {
|
||||
averaged+=((float*)buf)[i+j];
|
||||
}
|
||||
averaged/=si.channels;
|
||||
averaged*=32767.0;
|
||||
if (averaged<-32768.0) averaged=-32768.0;
|
||||
if (averaged>32767.0) averaged=32767.0;
|
||||
sample->data16[index++]=averaged;
|
||||
}
|
||||
delete[] (float*)buf;
|
||||
} else {
|
||||
for (int i=0; i<si.frames*si.channels; i+=si.channels) {
|
||||
int averaged=0;
|
||||
for (int j=0; j<si.channels; j++) {
|
||||
averaged+=((short*)buf)[i+j];
|
||||
}
|
||||
averaged/=si.channels;
|
||||
sample->data16[index++]=averaged;
|
||||
}
|
||||
delete[] (short*)buf;
|
||||
}
|
||||
delete[] buf;
|
||||
|
||||
sample->rate=si.samplerate;
|
||||
if (sample->rate<4000) sample->rate=4000;
|
||||
if (sample->rate>96000) sample->rate=96000;
|
||||
|
|
@ -2265,6 +2304,8 @@ int DivEngine::addSampleFromFile(const char* path) {
|
|||
|
||||
void DivEngine::delSample(int index) {
|
||||
BUSY_BEGIN;
|
||||
sPreview.sample=-1;
|
||||
sPreview.pos=0;
|
||||
saveLock.lock();
|
||||
if (index>=0 && index<(int)song.sample.size()) {
|
||||
delete song.sample[index];
|
||||
|
|
@ -2479,6 +2520,8 @@ bool DivEngine::moveWaveUp(int which) {
|
|||
bool DivEngine::moveSampleUp(int which) {
|
||||
if (which<1 || which>=(int)song.sample.size()) return false;
|
||||
BUSY_BEGIN;
|
||||
sPreview.sample=-1;
|
||||
sPreview.pos=0;
|
||||
DivSample* prev=song.sample[which];
|
||||
saveLock.lock();
|
||||
song.sample[which]=song.sample[which-1];
|
||||
|
|
@ -2516,6 +2559,8 @@ bool DivEngine::moveWaveDown(int which) {
|
|||
bool DivEngine::moveSampleDown(int which) {
|
||||
if (which<0 || which>=((int)song.sample.size())-1) return false;
|
||||
BUSY_BEGIN;
|
||||
sPreview.sample=-1;
|
||||
sPreview.pos=0;
|
||||
DivSample* prev=song.sample[which];
|
||||
saveLock.lock();
|
||||
song.sample[which]=song.sample[which+1];
|
||||
|
|
@ -2980,6 +3025,8 @@ bool DivEngine::initAudioBackend() {
|
|||
if (!output->midiIn->openDevice(inName)) {
|
||||
logW("could not open MIDI input device!");
|
||||
}
|
||||
} else {
|
||||
logV("no MIDI input device selected.");
|
||||
}
|
||||
}
|
||||
if (output->midiOut) {
|
||||
|
|
@ -2990,6 +3037,8 @@ bool DivEngine::initAudioBackend() {
|
|||
if (!output->midiOut->openDevice(outName)) {
|
||||
logW("could not open MIDI output device!");
|
||||
}
|
||||
} else {
|
||||
logV("no MIDI output device selected.");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ const char** DivPlatformNES::getRegisterSheet() {
|
|||
const char* DivPlatformNES::getEffectName(unsigned char effect) {
|
||||
switch (effect) {
|
||||
case 0x11:
|
||||
return "Write to delta modulation counter (0 to 7F)";
|
||||
return "11xx: Write to delta modulation counter (0 to 7F)";
|
||||
break;
|
||||
case 0x12:
|
||||
return "12xx: Set duty cycle/noise mode (pulse: 0 to 3; noise: 0 or 1)";
|
||||
|
|
|
|||
|
|
@ -51,7 +51,14 @@ bool DivSample::save(const char* path) {
|
|||
|
||||
si.channels=1;
|
||||
si.samplerate=rate;
|
||||
si.format=SF_FORMAT_PCM_16|SF_FORMAT_WAV;
|
||||
switch (depth) {
|
||||
case 8: // 8-bit
|
||||
si.format=SF_FORMAT_PCM_U8|SF_FORMAT_WAV;
|
||||
break;
|
||||
default: // 16-bit
|
||||
si.format=SF_FORMAT_PCM_16|SF_FORMAT_WAV;
|
||||
break;
|
||||
}
|
||||
|
||||
f=sf_open(path,SFM_WRITE,&si);
|
||||
|
||||
|
|
@ -77,7 +84,21 @@ bool DivSample::save(const char* path) {
|
|||
}
|
||||
sf_command(f, SFC_SET_INSTRUMENT, &inst, sizeof(inst));
|
||||
|
||||
sf_writef_short(f,data16,samples);
|
||||
switch (depth) {
|
||||
case 8: {
|
||||
// convert from signed to unsigned
|
||||
unsigned char* buf=new unsigned char[length8];
|
||||
for (size_t i=0; i<length8; i++) {
|
||||
buf[i]=data8[i]^0x80;
|
||||
}
|
||||
sf_write_raw(f,buf,length8);
|
||||
delete[] buf;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
sf_write_raw(f,data16,length16);
|
||||
break;
|
||||
}
|
||||
|
||||
sf_close(f);
|
||||
|
||||
|
|
|
|||
|
|
@ -953,13 +953,15 @@ void FurnaceGUI::doUndo() {
|
|||
DivPattern* p=e->curPat[i.chan].getPattern(i.pat,true);
|
||||
p->data[i.row][i.col]=i.oldVal;
|
||||
}
|
||||
if (!e->isPlaying() || !followPattern) {
|
||||
cursor=us.cursor;
|
||||
selStart=us.selStart;
|
||||
selEnd=us.selEnd;
|
||||
curNibble=us.nibble;
|
||||
updateScroll(cursor.y);
|
||||
setOrder(us.order);
|
||||
if (us.type!=GUI_UNDO_REPLACE) {
|
||||
if (!e->isPlaying() || !followPattern) {
|
||||
cursor=us.cursor;
|
||||
selStart=us.selStart;
|
||||
selEnd=us.selEnd;
|
||||
curNibble=us.nibble;
|
||||
updateScroll(cursor.y);
|
||||
setOrder(us.order);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
@ -1002,13 +1004,15 @@ void FurnaceGUI::doRedo() {
|
|||
DivPattern* p=e->curPat[i.chan].getPattern(i.pat,true);
|
||||
p->data[i.row][i.col]=i.newVal;
|
||||
}
|
||||
if (!e->isPlaying()) {
|
||||
cursor=us.cursor;
|
||||
selStart=us.selStart;
|
||||
selEnd=us.selEnd;
|
||||
curNibble=us.nibble;
|
||||
updateScroll(cursor.y);
|
||||
setOrder(us.order);
|
||||
if (us.type!=GUI_UNDO_REPLACE) {
|
||||
if (!e->isPlaying() || !followPattern) {
|
||||
cursor=us.cursor;
|
||||
selStart=us.selStart;
|
||||
selEnd=us.selEnd;
|
||||
curNibble=us.nibble;
|
||||
updateScroll(cursor.y);
|
||||
setOrder(us.order);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -2,7 +2,62 @@
|
|||
#include "ImGuiFileDialog.h"
|
||||
#include "../ta-log.h"
|
||||
|
||||
#ifdef USE_NFD
|
||||
#include <nfd.h>
|
||||
#else
|
||||
#include "../../extern/pfd-fixed/portable-file-dialogs.h"
|
||||
#endif
|
||||
|
||||
#ifdef USE_NFD
|
||||
struct NFDState {
|
||||
bool isSave;
|
||||
String header;
|
||||
std::vector<String> filter;
|
||||
String path;
|
||||
FileDialogSelectCallback clickCallback;
|
||||
NFDState(bool save, String h, std::vector<String> filt, String pa, FileDialogSelectCallback cc):
|
||||
isSave(save),
|
||||
header(h),
|
||||
filter(filt),
|
||||
path(pa),
|
||||
clickCallback(cc) {
|
||||
}
|
||||
};
|
||||
|
||||
// TODO: filter
|
||||
void _nfdThread(const NFDState state, std::atomic<bool>* ok, String* result) {
|
||||
nfdchar_t* out=NULL;
|
||||
nfdresult_t ret=NFD_CANCEL;
|
||||
|
||||
if (state.isSave) {
|
||||
ret=NFD_SaveDialog(NULL,state.path.c_str(),&out);
|
||||
} else {
|
||||
ret=NFD_OpenDialog(NULL,state.path.c_str(),&out);
|
||||
}
|
||||
|
||||
switch (ret) {
|
||||
case NFD_OKAY:
|
||||
if (out!=NULL) {
|
||||
(*result)=out;
|
||||
} else {
|
||||
(*result)="";
|
||||
}
|
||||
break;
|
||||
case NFD_CANCEL:
|
||||
(*result)="";
|
||||
break;
|
||||
case NFD_ERROR:
|
||||
(*result)="";
|
||||
logE("NFD error! %s\n",NFD_GetError());
|
||||
break;
|
||||
default:
|
||||
logE("NFD unknown return code %d!\n",ret);
|
||||
(*result)="";
|
||||
break;
|
||||
}
|
||||
(*ok)=true;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool FurnaceGUIFileDialog::openLoad(String header, std::vector<String> filter, const char* noSysFilter, String path, double dpiScale, FileDialogSelectCallback clickCallback) {
|
||||
if (opened) return false;
|
||||
|
|
@ -10,7 +65,12 @@ bool FurnaceGUIFileDialog::openLoad(String header, std::vector<String> filter, c
|
|||
curPath=path;
|
||||
logD("opening load file dialog with curPath %s",curPath.c_str());
|
||||
if (sysDialog) {
|
||||
#ifdef USE_NFD
|
||||
dialogOK=false;
|
||||
dialogO=new std::thread(_nfdThread,NFDState(false,header,filter,path,clickCallback),&dialogOK,&nfdResult);
|
||||
#else
|
||||
dialogO=new pfd::open_file(header,path,filter);
|
||||
#endif
|
||||
} else {
|
||||
ImGuiFileDialog::Instance()->DpiScale=dpiScale;
|
||||
ImGuiFileDialog::Instance()->OpenModal("FileDialog",header,noSysFilter,path,1,nullptr,0,clickCallback);
|
||||
|
|
@ -25,7 +85,12 @@ bool FurnaceGUIFileDialog::openSave(String header, std::vector<String> filter, c
|
|||
curPath=path;
|
||||
logD("opening save file dialog with curPath %s",curPath.c_str());
|
||||
if (sysDialog) {
|
||||
#ifdef USE_NFD
|
||||
dialogOK=false;
|
||||
dialogS=new std::thread(_nfdThread,NFDState(true,header,filter,path,NULL),&dialogOK,&nfdResult);
|
||||
#else
|
||||
dialogS=new pfd::save_file(header,path,filter);
|
||||
#endif
|
||||
} else {
|
||||
ImGuiFileDialog::Instance()->DpiScale=dpiScale;
|
||||
ImGuiFileDialog::Instance()->OpenModal("FileDialog",header,noSysFilter,path,1,nullptr,ImGuiFileDialogFlags_ConfirmOverwrite);
|
||||
|
|
@ -46,15 +111,24 @@ void FurnaceGUIFileDialog::close() {
|
|||
if (sysDialog) {
|
||||
if (saving) {
|
||||
if (dialogS!=NULL) {
|
||||
#ifdef USE_NFD
|
||||
dialogS->join();
|
||||
#endif
|
||||
delete dialogS;
|
||||
dialogS=NULL;
|
||||
}
|
||||
} else {
|
||||
if (dialogO!=NULL) {
|
||||
#ifdef USE_NFD
|
||||
dialogO->join();
|
||||
#endif
|
||||
delete dialogO;
|
||||
dialogO=NULL;
|
||||
}
|
||||
}
|
||||
#ifdef USE_NFD
|
||||
dialogOK=false;
|
||||
#endif
|
||||
} else {
|
||||
ImGuiFileDialog::Instance()->Close();
|
||||
}
|
||||
|
|
@ -63,6 +137,15 @@ void FurnaceGUIFileDialog::close() {
|
|||
|
||||
bool FurnaceGUIFileDialog::render(const ImVec2& min, const ImVec2& max) {
|
||||
if (sysDialog) {
|
||||
#ifdef USE_NFD
|
||||
if (dialogOK) {
|
||||
fileName=nfdResult;
|
||||
logD("returning %s",fileName.c_str());
|
||||
dialogOK=false;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
#else
|
||||
if (saving) {
|
||||
if (dialogS!=NULL) {
|
||||
if (dialogS->ready(0)) {
|
||||
|
|
@ -90,6 +173,7 @@ bool FurnaceGUIFileDialog::render(const ImVec2& min, const ImVec2& max) {
|
|||
}
|
||||
}
|
||||
return false;
|
||||
#endif
|
||||
} else {
|
||||
return ImGuiFileDialog::Instance()->Display("FileDialog",ImGuiWindowFlags_NoCollapse|ImGuiWindowFlags_NoMove,min,max);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,10 +3,19 @@
|
|||
#include <functional>
|
||||
#include <vector>
|
||||
|
||||
#if defined(_WIN32) || defined(__APPLE__)
|
||||
#define USE_NFD
|
||||
#endif
|
||||
|
||||
#ifdef USE_NFD
|
||||
#include <atomic>
|
||||
#include <thread>
|
||||
#else
|
||||
namespace pfd {
|
||||
class open_file;
|
||||
class save_file;
|
||||
}
|
||||
#endif
|
||||
|
||||
typedef std::function<void(const char*)> FileDialogSelectCallback;
|
||||
|
||||
|
|
@ -16,8 +25,15 @@ class FurnaceGUIFileDialog {
|
|||
bool saving;
|
||||
String curPath;
|
||||
String fileName;
|
||||
#ifdef USE_NFD
|
||||
std::thread* dialogO;
|
||||
std::thread* dialogS;
|
||||
std::atomic<bool> dialogOK;
|
||||
String nfdResult;
|
||||
#else
|
||||
pfd::open_file* dialogO;
|
||||
pfd::save_file* dialogS;
|
||||
#endif
|
||||
public:
|
||||
bool openLoad(String header, std::vector<String> filter, const char* noSysFilter, String path, double dpiScale, FileDialogSelectCallback clickCallback=NULL);
|
||||
bool openSave(String header, std::vector<String> filter, const char* noSysFilter, String path, double dpiScale);
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ int queryNote(int note, int octave) {
|
|||
}
|
||||
|
||||
bool checkCondition(int mode, int arg, int argMax, int val, bool noteMode=false) {
|
||||
const int emptyVal=noteMode?-61:-1;
|
||||
switch (mode) {
|
||||
case GUI_QUERY_IGNORE:
|
||||
return true;
|
||||
|
|
@ -51,19 +52,19 @@ bool checkCondition(int mode, int arg, int argMax, int val, bool noteMode=false)
|
|||
return (val==arg);
|
||||
break;
|
||||
case GUI_QUERY_MATCH_NOT:
|
||||
return (val!=-1 && val!=arg);
|
||||
return (val!=emptyVal && val!=arg);
|
||||
break;
|
||||
case GUI_QUERY_RANGE:
|
||||
return (val>=arg && val<=argMax);
|
||||
break;
|
||||
case GUI_QUERY_RANGE_NOT:
|
||||
return (val!=-1 && (val<arg || val>argMax) && (!noteMode || val<120));
|
||||
return (val!=emptyVal && (val<arg || val>argMax) && (!noteMode || val<120));
|
||||
break;
|
||||
case GUI_QUERY_ANY:
|
||||
return (val!=-1);
|
||||
return (val!=emptyVal);
|
||||
break;
|
||||
case GUI_QUERY_NONE:
|
||||
return (val==-1);
|
||||
return (val==emptyVal);
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
|
|
@ -189,12 +190,6 @@ void FurnaceGUI::doFind() {
|
|||
queryViewingResults=true;
|
||||
}
|
||||
|
||||
/* issues with the find and replace function:
|
||||
- doesn't mark the module as modified
|
||||
- can't undo
|
||||
- replace notes to anything starting from C-0 to lower notes will have an octave higher, so set it to replace to C-0 it will becom C-1, b_1 will become B-0 and so on
|
||||
*/
|
||||
|
||||
void FurnaceGUI::doReplace() {
|
||||
doFind();
|
||||
queryViewingResults=false;
|
||||
|
|
@ -202,6 +197,12 @@ void FurnaceGUI::doReplace() {
|
|||
bool* touched[DIV_MAX_CHANS];
|
||||
memset(touched,0,DIV_MAX_CHANS*sizeof(bool*));
|
||||
|
||||
UndoStep us;
|
||||
us.type=GUI_UNDO_REPLACE;
|
||||
|
||||
short prevVal[32];
|
||||
memset(prevVal,0,32*sizeof(short));
|
||||
|
||||
for (FurnaceGUIQueryResult& i: curQueryResults) {
|
||||
int patIndex=e->song.subsong[i.subsong]->orders.ord[i.x][i.order];
|
||||
DivPattern* p=e->song.subsong[i.subsong]->pat[i.x].getPattern(patIndex,true);
|
||||
|
|
@ -211,6 +212,9 @@ void FurnaceGUI::doReplace() {
|
|||
}
|
||||
if (touched[i.x][(patIndex<<8)|i.y]) continue;
|
||||
touched[i.x][(patIndex<<8)|i.y]=true;
|
||||
|
||||
memcpy(prevVal,p->data[i.y],32*sizeof(short));
|
||||
|
||||
if (queryReplaceNoteDo) {
|
||||
switch (queryReplaceNoteMode) {
|
||||
case GUI_QUERY_REPLACE_SET:
|
||||
|
|
@ -241,8 +245,11 @@ void FurnaceGUI::doReplace() {
|
|||
if (note>119) note=119;
|
||||
|
||||
p->data[i.y][0]=(note+60)%12;
|
||||
if (p->data[i.y][0]==0) p->data[i.y][0]=12;
|
||||
p->data[i.y][1]=(unsigned char)((note-1)/12);
|
||||
p->data[i.y][1]=(unsigned char)(((note+60)/12)-5);
|
||||
if (p->data[i.y][0]==0) {
|
||||
p->data[i.y][0]=12;
|
||||
p->data[i.y][1]=(unsigned char)(p->data[i.y][1]-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
@ -258,8 +265,11 @@ void FurnaceGUI::doReplace() {
|
|||
}
|
||||
|
||||
p->data[i.y][0]=(note+60)%12;
|
||||
if (p->data[i.y][0]==0) p->data[i.y][0]=12;
|
||||
p->data[i.y][1]=(unsigned char)((note-1)/12);
|
||||
p->data[i.y][1]=(unsigned char)(((note+60)/12)-5);
|
||||
if (p->data[i.y][0]==0) {
|
||||
p->data[i.y][0]=12;
|
||||
p->data[i.y][1]=(unsigned char)(p->data[i.y][1]-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
@ -400,6 +410,13 @@ void FurnaceGUI::doReplace() {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// issue undo step
|
||||
for (int j=0; j<32; j++) {
|
||||
if (p->data[i.y][j]!=prevVal[j]) {
|
||||
us.pat.push_back(UndoPatternData(i.subsong,i.x,patIndex,i.y,j,prevVal[j],p->data[i.y][j]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i=0; i<DIV_MAX_CHANS; i++) {
|
||||
|
|
@ -409,6 +426,13 @@ void FurnaceGUI::doReplace() {
|
|||
if (!curQueryResults.empty()) {
|
||||
MARK_MODIFIED;
|
||||
}
|
||||
|
||||
if (!us.pat.empty()) {
|
||||
printf("pusher\n");
|
||||
undoHist.push_back(us);
|
||||
redoHist.clear();
|
||||
if (undoHist.size()>settings.maxUndoSteps) undoHist.pop_front();
|
||||
}
|
||||
}
|
||||
|
||||
#define FIRST_VISIBLE(x) (x==GUI_QUERY_MATCH || x==GUI_QUERY_MATCH_NOT || x==GUI_QUERY_RANGE || x==GUI_QUERY_RANGE_NOT)
|
||||
|
|
|
|||
|
|
@ -765,16 +765,16 @@ void FurnaceGUI::drawSampleEdit() {
|
|||
float highP=sampleFilterH*100.0f;
|
||||
float resP=sampleFilterRes*100.0f;
|
||||
ImGui::Text("Cutoff:");
|
||||
if (ImGui::SliderFloat("From",&sampleFilterCutStart,0.0f,sample->rate*0.5,"%.0fHz")) {
|
||||
if (CWSliderFloat("From",&sampleFilterCutStart,0.0f,sample->rate*0.5,"%.0fHz")) {
|
||||
if (sampleFilterCutStart<0.0) sampleFilterCutStart=0.0;
|
||||
if (sampleFilterCutStart>sample->rate*0.5) sampleFilterCutStart=sample->rate*0.5;
|
||||
}
|
||||
if (ImGui::SliderFloat("To",&sampleFilterCutEnd,0.0f,sample->rate*0.5,"%.0fHz")) {
|
||||
if (CWSliderFloat("To",&sampleFilterCutEnd,0.0f,sample->rate*0.5,"%.0fHz")) {
|
||||
if (sampleFilterCutEnd<0.0) sampleFilterCutEnd=0.0;
|
||||
if (sampleFilterCutEnd>sample->rate*0.5) sampleFilterCutEnd=sample->rate*0.5;
|
||||
}
|
||||
ImGui::Separator();
|
||||
if (ImGui::SliderFloat("Resonance",&resP,0.0f,99.0f,"%.1f%%")) {
|
||||
if (CWSliderFloat("Resonance",&resP,0.0f,99.0f,"%.1f%%")) {
|
||||
sampleFilterRes=resP/100.0f;
|
||||
if (sampleFilterRes<0.0f) sampleFilterRes=0.0f;
|
||||
if (sampleFilterRes>0.99f) sampleFilterRes=0.99f;
|
||||
|
|
@ -793,17 +793,17 @@ void FurnaceGUI::drawSampleEdit() {
|
|||
sampleFilterPower=3;
|
||||
}
|
||||
ImGui::Separator();
|
||||
if (ImGui::SliderFloat("Low-pass",&lowP,0.0f,100.0f,"%.1f%%")) {
|
||||
if (CWSliderFloat("Low-pass",&lowP,0.0f,100.0f,"%.1f%%")) {
|
||||
sampleFilterL=lowP/100.0f;
|
||||
if (sampleFilterL<0.0f) sampleFilterL=0.0f;
|
||||
if (sampleFilterL>1.0f) sampleFilterL=1.0f;
|
||||
}
|
||||
if (ImGui::SliderFloat("Band-pass",&bandP,0.0f,100.0f,"%.1f%%")) {
|
||||
if (CWSliderFloat("Band-pass",&bandP,0.0f,100.0f,"%.1f%%")) {
|
||||
sampleFilterB=bandP/100.0f;
|
||||
if (sampleFilterB<0.0f) sampleFilterB=0.0f;
|
||||
if (sampleFilterB>1.0f) sampleFilterB=1.0f;
|
||||
}
|
||||
if (ImGui::SliderFloat("High-pass",&highP,0.0f,100.0f,"%.1f%%")) {
|
||||
if (CWSliderFloat("High-pass",&highP,0.0f,100.0f,"%.1f%%")) {
|
||||
sampleFilterH=highP/100.0f;
|
||||
if (sampleFilterH<0.0f) sampleFilterH=0.0f;
|
||||
if (sampleFilterH>1.0f) sampleFilterH=1.0f;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue