Merge branch 'doc-info' of https://github.com/ElectricKeet/furnace into doc-info

This commit is contained in:
Electric Keet 2023-06-30 20:41:39 -07:00
commit ab67d30132
18 changed files with 189 additions and 99 deletions

View File

@ -3,14 +3,10 @@
- tutorial? - tutorial?
- ease-of-use improvements... ideas: - ease-of-use improvements... ideas:
- preset compat flags - preset compat flags
- setting to toggle the Choose a System screen on new project
- maybe reduced set of presets for the sake of simplicity - maybe reduced set of presets for the sake of simplicity
- a more preferable highlight/drag system - a more preferable highlight/drag system
- some speed/intuitive workflow improvements that go a long way - some speed/intuitive workflow improvements that go a long way
- Had a hard time finding the docs on github and in Furnace's folder.
- make .pdf manual out of doc/ - make .pdf manual out of doc/
- you're going too slow; please run
- break compatibility if it relieves complexity - break compatibility if it relieves complexity
- ins/wave/sample organization (folders and all)
- multi-key binds - multi-key binds
- bug fixes - bug fixes

BIN
demos/gameboy/finger.fur Normal file

Binary file not shown.

Binary file not shown.

BIN
demos/x16/keygen19.fur Normal file

Binary file not shown.

View File

@ -19,4 +19,4 @@ furthermore, it has some PCM and LFO!
- when LFO is enabled, channel 2 is muted and its output is passed to channel 1's frequency. - when LFO is enabled, channel 2 is muted and its output is passed to channel 1's frequency.
- `13xx`: **set LFO speed.** - `13xx`: **set LFO speed.**
- `17xx`: **toggle PCM mode.** - `17xx`: **toggle PCM mode.**
- _this effect is here for compatibility reasons;_ it is otherwise recommended to use Sample type instruments (which automatically enable PCM mode when used). - _this effect is here for compatibility reasons_; it is otherwise recommended to use Sample type instruments (which automatically enable PCM mode when used).

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -160,6 +160,7 @@ bool TAMidiInRtMidi::quit() {
bool TAMidiOutRtMidi::send(const TAMidiMessage& what) { bool TAMidiOutRtMidi::send(const TAMidiMessage& what) {
if (!isOpen) return false; if (!isOpen) return false;
if (!isWorking) return false;
if (what.type<0x80) return false; if (what.type<0x80) return false;
size_t len=0; size_t len=0;
switch (what.type&0xf0) { switch (what.type&0xf0) {
@ -190,6 +191,7 @@ bool TAMidiOutRtMidi::send(const TAMidiMessage& what) {
port->sendMessage(what.sysExData.get(),len); port->sendMessage(what.sysExData.get(),len);
} catch (RtMidiError& e) { } catch (RtMidiError& e) {
logE("MIDI output error! %s",e.what()); logE("MIDI output error! %s",e.what());
isWorking=false;
return false; return false;
} }
return true; return true;
@ -209,6 +211,7 @@ bool TAMidiOutRtMidi::send(const TAMidiMessage& what) {
port->sendMessage((const unsigned char*)&what.type,len); port->sendMessage((const unsigned char*)&what.type,len);
} catch (RtMidiError& e) { } catch (RtMidiError& e) {
logE("MIDI output error! %s",e.what()); logE("MIDI output error! %s",e.what());
isWorking=false;
return false; return false;
} }
return true; return true;
@ -237,17 +240,20 @@ bool TAMidiOutRtMidi::openDevice(String name) {
} }
isOpen=portOpen; isOpen=portOpen;
if (!portOpen) logW("could not find MIDI out device..."); if (!portOpen) logW("could not find MIDI out device...");
isWorking=true;
return portOpen; return portOpen;
} catch (RtMidiError& e) { } catch (RtMidiError& e) {
logW("could not open MIDI out device! %s",e.what()); logW("could not open MIDI out device! %s",e.what());
return false; return false;
} }
isWorking=true;
return true; return true;
} }
bool TAMidiOutRtMidi::closeDevice() { bool TAMidiOutRtMidi::closeDevice() {
if (port==NULL) return false; if (port==NULL) return false;
if (!isOpen) return false; if (!isOpen) return false;
isWorking=false;
try { try {
port->closePort(); port->closePort();
} catch (RtMidiError& e) { } catch (RtMidiError& e) {

View File

@ -38,7 +38,7 @@ class TAMidiInRtMidi: public TAMidiIn {
class TAMidiOutRtMidi: public TAMidiOut { class TAMidiOutRtMidi: public TAMidiOut {
RtMidiOut* port; RtMidiOut* port;
bool isOpen; bool isOpen, isWorking;
public: public:
bool send(const TAMidiMessage& what); bool send(const TAMidiMessage& what);
bool isDeviceOpen(); bool isDeviceOpen();
@ -49,5 +49,6 @@ class TAMidiOutRtMidi: public TAMidiOut {
bool init(); bool init();
TAMidiOutRtMidi(): TAMidiOutRtMidi():
port(NULL), port(NULL),
isOpen(false) {} isOpen(false),
isWorking(false) {}
}; };

View File

@ -423,7 +423,7 @@ const void* DivPlatformSegaPCM::getSampleMem(int index) {
} }
size_t DivPlatformSegaPCM::getSampleMemCapacity(int index) { size_t DivPlatformSegaPCM::getSampleMemCapacity(int index) {
return index == 0 ? 16777216 : 0; return index == 0 ? 2097152 : 0;
} }
size_t DivPlatformSegaPCM::getSampleMemUsage(int index) { size_t DivPlatformSegaPCM::getSampleMemUsage(int index) {
@ -465,7 +465,7 @@ void DivPlatformSegaPCM::reset() {
void DivPlatformSegaPCM::renderSamples(int sysID) { void DivPlatformSegaPCM::renderSamples(int sysID) {
size_t memPos=0; size_t memPos=0;
memset(sampleMem,0,16777216); memset(sampleMem,0,2097152);
memset(sampleLoaded,0,256*sizeof(bool)); memset(sampleLoaded,0,256*sizeof(bool));
memset(sampleOffSegaPCM,0,256*sizeof(unsigned int)); memset(sampleOffSegaPCM,0,256*sizeof(unsigned int));
memset(sampleEndSegaPCM,0,256); memset(sampleEndSegaPCM,0,256);
@ -482,7 +482,7 @@ void DivPlatformSegaPCM::renderSamples(int sysID) {
} }
logV("- sample %d will be at %x with length %x",i,memPos,alignedSize); logV("- sample %d will be at %x with length %x",i,memPos,alignedSize);
sampleLoaded[i]=true; sampleLoaded[i]=true;
if (memPos>=16777216) break; if (memPos>=2097152) break;
sampleOffSegaPCM[i]=memPos; sampleOffSegaPCM[i]=memPos;
for (unsigned int j=0; j<alignedSize; j++) { for (unsigned int j=0; j<alignedSize; j++) {
if (j>=sample->samples) { if (j>=sample->samples) {
@ -491,10 +491,10 @@ void DivPlatformSegaPCM::renderSamples(int sysID) {
sampleMem[memPos++]=((unsigned char)sample->data8[j]+0x80); sampleMem[memPos++]=((unsigned char)sample->data8[j]+0x80);
} }
sampleEndSegaPCM[i]=((memPos+0xff)>>8)-1; sampleEndSegaPCM[i]=((memPos+0xff)>>8)-1;
if (memPos>=16777216) break; if (memPos>=2097152) break;
} }
logV(" and it ends in %d",sampleEndSegaPCM[i]); logV(" and it ends in %d",sampleEndSegaPCM[i]);
if (memPos>=16777216) break; if (memPos>=2097152) break;
} }
sampleMemLen=memPos; sampleMemLen=memPos;
} }
@ -522,10 +522,10 @@ int DivPlatformSegaPCM::init(DivEngine* p, int channels, int sugRate, const DivC
isMuted[i]=false; isMuted[i]=false;
oscBuf[i]=new DivDispatchOscBuffer; oscBuf[i]=new DivDispatchOscBuffer;
} }
sampleMem=new unsigned char[16777216]; sampleMem=new unsigned char[2097152];
pcm.set_bank(segapcm_device::BANK_12M|segapcm_device::BANK_MASKF8); pcm.set_bank(segapcm_device::BANK_12M|segapcm_device::BANK_MASKF8);
pcm.set_read([this](unsigned int addr) -> unsigned char { pcm.set_read([this](unsigned int addr) -> unsigned char {
return sampleMem[addr&0xffffff]; return sampleMem[addr&0x1fffff];
}); });
setFlags(flags); setFlags(flags);
reset(); reset();

View File

@ -1691,6 +1691,10 @@ void DivEngine::runMidiTime(int totalCycles) {
} }
void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsigned int size) { void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsigned int size) {
if (!size) {
logW("nextBuf called with size 0!");
return;
}
lastLoopPos=-1; lastLoopPos=-1;
if (out!=NULL) { if (out!=NULL) {

View File

@ -497,6 +497,15 @@ bool FurnaceGUI::InvCheckbox(const char* label, bool* value) {
return false; return false;
} }
void FurnaceGUI::sameLineMaybe(float width) {
if (width<0.0f) width=ImGui::GetFrameHeight();
logV("sameLineMaybe: %f %f",ImGui::GetContentRegionAvail().x,width);
ImGui::SameLine();
if (ImGui::GetContentRegionAvail().x<width) ImGui::NewLine();
}
const char* FurnaceGUI::getSystemName(DivSystem which) { const char* FurnaceGUI::getSystemName(DivSystem which) {
/* /*
if (settings.chipNames) { if (settings.chipNames) {
@ -5076,8 +5085,25 @@ bool FurnaceGUI::loop() {
newSongQuery=""; newSongQuery="";
newSongFirstFrame=true; newSongFirstFrame=true;
displayNew=false; displayNew=false;
if (settings.newSongBehavior==1) {
e->createNewFromDefaults();
undoHist.clear();
redoHist.clear();
curFileName="";
modified=false;
curNibble=false;
orderNibble=false;
orderCursor=-1;
samplePos=0;
updateSampleTex=true;
selStart=SelectionPoint();
selEnd=SelectionPoint();
cursor=SelectionPoint();
updateWindowTitle();
} else {
ImGui::OpenPopup("New Song"); ImGui::OpenPopup("New Song");
} }
}
if (displayEditString) { if (displayEditString) {
ImGui::OpenPopup("EditString"); ImGui::OpenPopup("EditString");

View File

@ -1508,6 +1508,7 @@ class FurnaceGUI {
int renderClearPos; int renderClearPos;
int insertBehavior; int insertBehavior;
int pullDeleteRow; int pullDeleteRow;
int newSongBehavior;
unsigned int maxUndoSteps; unsigned int maxUndoSteps;
String mainFontPath; String mainFontPath;
String patFontPath; String patFontPath;
@ -1659,6 +1660,7 @@ class FurnaceGUI {
renderClearPos(0), renderClearPos(0),
insertBehavior(1), insertBehavior(1),
pullDeleteRow(1), pullDeleteRow(1),
newSongBehavior(0),
maxUndoSteps(100), maxUndoSteps(100),
mainFontPath(""), mainFontPath(""),
patFontPath(""), patFontPath(""),
@ -2089,6 +2091,8 @@ class FurnaceGUI {
void pushWarningColor(bool warnCond, bool errorCond=false); void pushWarningColor(bool warnCond, bool errorCond=false);
void popWarningColor(); void popWarningColor();
void sameLineMaybe(float width=-1.0f);
float calcBPM(const DivGroovePattern& speeds, float hz, int vN, int vD); float calcBPM(const DivGroovePattern& speeds, float hz, int vN, int vD);
void patternRow(int i, bool isPlaying, float lineHeight, int chans, int ord, const DivPattern** patCache, bool inhibitSel); void patternRow(int i, bool isPlaying, float lineHeight, int chans, int ord, const DivPattern** patCache, bool inhibitSel);

View File

@ -59,79 +59,79 @@ const char* opllVariants[4]={
const char* opllInsNames[4][17]={ const char* opllInsNames[4][17]={
/* YM2413 */ { /* YM2413 */ {
"User", "User",
"Violin", "1. Violin",
"Guitar", "2. Guitar",
"Piano", "3. Piano",
"Flute", "4. Flute",
"Clarinet", "5. Clarinet",
"Oboe", "6. Oboe",
"Trumpet", "7. Trumpet",
"Organ", "8. Organ",
"Horn", "9. Horn",
"Synth", "10. Synth",
"Harpsichord", "11. Harpsichord",
"Vibraphone", "12. Vibraphone",
"Synth Bass", "13. Synth Bass",
"Acoustic Bass", "14. Acoustic Bass",
"Electric Guitar", "15. Electric Guitar",
"Drums" "Drums"
}, },
/* YMF281 */ { /* YMF281 */ {
"User", "User",
"Electric String", "1. Electric String",
"Bow wow", "2. Bow wow",
"Electric Guitar", "3. Electric Guitar",
"Organ", "4. Organ",
"Clarinet", "5. Clarinet",
"Saxophone", "6. Saxophone",
"Trumpet", "7. Trumpet",
"Street Organ", "8. Street Organ",
"Synth Brass", "9. Synth Brass",
"Electric Piano", "10. Electric Piano",
"Bass", "11. Bass",
"Vibraphone", "12. Vibraphone",
"Chime", "13. Chime",
"Tom Tom II", "14. Tom Tom II",
"Noise", "15. Noise",
"Drums" "Drums"
}, },
/* YM2423 */ { /* YM2423 */ {
"User", "User",
"Strings", "1. Strings",
"Guitar", "2. Guitar",
"Electric Guitar", "3. Electric Guitar",
"Electric Piano", "4. Electric Piano",
"Flute", "5. Flute",
"Marimba", "6. Marimba",
"Trumpet", "7. Trumpet",
"Harmonica", "8. Harmonica",
"Tuba", "9. Tuba",
"Synth Brass", "10. Synth Brass",
"Short Saw", "11. Short Saw",
"Vibraphone", "12. Vibraphone",
"Electric Guitar 2", "13. Electric Guitar 2",
"Synth Bass", "14. Synth Bass",
"Sitar", "15. Sitar",
"Drums" "Drums"
}, },
// stolen from FamiTracker // stolen from FamiTracker
/* VRC7 */ { /* VRC7 */ {
"User", "User",
"Bell", "1. Bell",
"Guitar", "2. Guitar",
"Piano", "3. Piano",
"Flute", "4. Flute",
"Clarinet", "5. Clarinet",
"Rattling Bell", "6. Rattling Bell",
"Trumpet", "7. Trumpet",
"Reed Organ", "8. Reed Organ",
"Soft Bell", "9. Soft Bell",
"Xylophone", "10. Xylophone",
"Vibraphone", "11. Vibraphone",
"Brass", "12. Brass",
"Bass Guitar", "13. Bass Guitar",
"Synth", "14. Synth",
"Chorus", "15. Chorus",
"Drums" "Drums"
} }
}; };

View File

@ -200,6 +200,9 @@ void FurnaceGUI::drawSampleEdit() {
SAMPLE_WARN(warnLoopPos,"QSound: loop cannot be longer than 32767 samples"); SAMPLE_WARN(warnLoopPos,"QSound: loop cannot be longer than 32767 samples");
} }
} }
if (sample->samples>65535) {
SAMPLE_WARN(warnLength,"QSound: maximum sample length is 65535");
}
break; break;
case DIV_SYSTEM_NES: case DIV_SYSTEM_NES:
if (sample->loop) { if (sample->loop) {
@ -207,11 +210,17 @@ void FurnaceGUI::drawSampleEdit() {
SAMPLE_WARN(warnLoopPos,"NES: loop point ignored on DPCM (may only loop entire sample)"); SAMPLE_WARN(warnLoopPos,"NES: loop point ignored on DPCM (may only loop entire sample)");
} }
} }
if (sample->samples>32648) {
SAMPLE_WARN(warnLength,"NES: maximum DPCM sample length is 32648");
}
break; break;
case DIV_SYSTEM_X1_010: case DIV_SYSTEM_X1_010:
if (sample->loop) { if (sample->loop) {
SAMPLE_WARN(warnLoop,"X1-010: samples can't loop"); SAMPLE_WARN(warnLoop,"X1-010: samples can't loop");
} }
if (sample->samples>131072) {
SAMPLE_WARN(warnLength,"X1-010: maximum sample length is 131072");
}
break; break;
case DIV_SYSTEM_GA20: case DIV_SYSTEM_GA20:
if (sample->loop) { if (sample->loop) {
@ -235,9 +244,12 @@ void FurnaceGUI::drawSampleEdit() {
if (sample->loop) { if (sample->loop) {
SAMPLE_WARN(warnLoop,"YM2610: ADPCM-A samples can't loop"); SAMPLE_WARN(warnLoop,"YM2610: ADPCM-A samples can't loop");
if (sample->loopStart!=0 || sample->loopEnd!=(int)(sample->samples)) { if (sample->loopStart!=0 || sample->loopEnd!=(int)(sample->samples)) {
SAMPLE_WARN(warnLoopPos,"YM2608: loop point ignored on ADPCM-B (may only loop entire sample)"); SAMPLE_WARN(warnLoopPos,"YM2610: loop point ignored on ADPCM-B (may only loop entire sample)");
} }
} }
if (sample->samples>2097152) {
SAMPLE_WARN(warnLength,"YM2610: maximum ADPCM-A sample length is 2097152");
}
break; break;
case DIV_SYSTEM_AMIGA: case DIV_SYSTEM_AMIGA:
if (sample->loop) { if (sample->loop) {
@ -245,10 +257,28 @@ void FurnaceGUI::drawSampleEdit() {
SAMPLE_WARN(warnLoopPos,"Amiga: loop must be a multiple of 2"); SAMPLE_WARN(warnLoopPos,"Amiga: loop must be a multiple of 2");
} }
} }
if (sample->samples>131070) {
SAMPLE_WARN(warnLength,"Amiga: maximum sample length is 131070");
}
break;
case DIV_SYSTEM_SEGAPCM:
case DIV_SYSTEM_SEGAPCM_COMPAT:
if (sample->samples>65280) {
SAMPLE_WARN(warnLength,"SegaPCM: maximum sample length is 65280");
}
break; break;
default: default:
break; break;
} }
if (e->song.system[i]!=DIV_SYSTEM_PCM_DAC) {
if (e->song.system[i]==DIV_SYSTEM_ES5506) {
if (sample->loopMode==DIV_SAMPLE_LOOP_BACKWARD) {
SAMPLE_WARN(warnLoopMode,"ES5506: backward loop mode isn't supported");
}
} else if (sample->loopMode!=DIV_SAMPLE_LOOP_FORWARD) {
SAMPLE_WARN(warnLoopMode,"backward/ping-pong only supported in Generic PCM DAC\nping-pong also on ES5506");
}
}
// chips grid // chips grid
DivDispatch* dispatch=e->getDispatch(i); DivDispatch* dispatch=e->getDispatch(i);
@ -514,6 +544,9 @@ void FurnaceGUI::drawSampleEdit() {
} }
ImGui::EndCombo(); ImGui::EndCombo();
} }
if (ImGui::IsItemHovered() && !warnLoopMode.empty()) {
ImGui::SetTooltip("%s",warnLoopMode.c_str());
}
popWarningColor(); popWarningColor();
pushWarningColor(!warnLoopPos.empty()); pushWarningColor(!warnLoopPos.empty());
@ -682,7 +715,7 @@ void FurnaceGUI::drawSampleEdit() {
if (ImGui::IsItemHovered()) { if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Edit mode: Select"); ImGui::SetTooltip("Edit mode: Select");
} }
ImGui::SameLine(); sameLineMaybe();
pushToggleColors(sampleDragMode); pushToggleColors(sampleDragMode);
if (ImGui::Button(ICON_FA_PENCIL "##SDraw")) { if (ImGui::Button(ICON_FA_PENCIL "##SDraw")) {
sampleDragMode=true; sampleDragMode=true;
@ -692,9 +725,9 @@ void FurnaceGUI::drawSampleEdit() {
ImGui::SetTooltip("Edit mode: Draw"); ImGui::SetTooltip("Edit mode: Draw");
} }
ImGui::BeginDisabled(sample->depth!=DIV_SAMPLE_DEPTH_8BIT && sample->depth!=DIV_SAMPLE_DEPTH_16BIT); ImGui::BeginDisabled(sample->depth!=DIV_SAMPLE_DEPTH_8BIT && sample->depth!=DIV_SAMPLE_DEPTH_16BIT);
ImGui::SameLine(); sameLineMaybe();
ImGui::Dummy(ImVec2(4.0*dpiScale,dpiScale)); ImGui::Dummy(ImVec2(4.0*dpiScale,dpiScale));
ImGui::SameLine(); sameLineMaybe();
ImGui::Button(ICON_FA_ARROWS_H "##SResize"); ImGui::Button(ICON_FA_ARROWS_H "##SResize");
if (ImGui::IsItemClicked()) { if (ImGui::IsItemClicked()) {
resizeSize=sample->samples; resizeSize=sample->samples;
@ -729,7 +762,7 @@ void FurnaceGUI::drawSampleEdit() {
} else { } else {
resizeSize=sample->samples; resizeSize=sample->samples;
} }
ImGui::SameLine(); sameLineMaybe();
ImGui::Button(ICON_FA_EXPAND "##SResample"); ImGui::Button(ICON_FA_EXPAND "##SResample");
if (ImGui::IsItemClicked()) { if (ImGui::IsItemClicked()) {
resampleTarget=targetRate; resampleTarget=targetRate;
@ -786,14 +819,14 @@ void FurnaceGUI::drawSampleEdit() {
} }
ImGui::SameLine(); ImGui::SameLine();
ImGui::Dummy(ImVec2(4.0*dpiScale,dpiScale)); ImGui::Dummy(ImVec2(4.0*dpiScale,dpiScale));
ImGui::SameLine(); sameLineMaybe();
if (ImGui::Button(ICON_FA_UNDO "##SUndo")) { if (ImGui::Button(ICON_FA_UNDO "##SUndo")) {
doUndoSample(); doUndoSample();
} }
if (ImGui::IsItemHovered()) { if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Undo"); ImGui::SetTooltip("Undo");
} }
ImGui::SameLine(); sameLineMaybe();
if (ImGui::Button(ICON_FA_REPEAT "##SRedo")) { if (ImGui::Button(ICON_FA_REPEAT "##SRedo")) {
doRedoSample(); doRedoSample();
} }
@ -802,7 +835,7 @@ void FurnaceGUI::drawSampleEdit() {
} }
ImGui::SameLine(); ImGui::SameLine();
ImGui::Dummy(ImVec2(4.0*dpiScale,dpiScale)); ImGui::Dummy(ImVec2(4.0*dpiScale,dpiScale));
ImGui::SameLine(); sameLineMaybe();
ImGui::Button(ICON_FA_VOLUME_UP "##SAmplify"); ImGui::Button(ICON_FA_VOLUME_UP "##SAmplify");
if (ImGui::IsItemHovered()) { if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Amplify"); ImGui::SetTooltip("Amplify");
@ -850,28 +883,28 @@ void FurnaceGUI::drawSampleEdit() {
} }
ImGui::EndPopup(); ImGui::EndPopup();
} }
ImGui::SameLine(); sameLineMaybe();
if (ImGui::Button(ICON_FA_ARROWS_V "##SNormalize")) { if (ImGui::Button(ICON_FA_ARROWS_V "##SNormalize")) {
doAction(GUI_ACTION_SAMPLE_NORMALIZE); doAction(GUI_ACTION_SAMPLE_NORMALIZE);
} }
if (ImGui::IsItemHovered()) { if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Normalize"); ImGui::SetTooltip("Normalize");
} }
ImGui::SameLine(); sameLineMaybe();
if (ImGui::Button(ICON_FA_ARROW_UP "##SFadeIn")) { if (ImGui::Button(ICON_FA_ARROW_UP "##SFadeIn")) {
doAction(GUI_ACTION_SAMPLE_FADE_IN); doAction(GUI_ACTION_SAMPLE_FADE_IN);
} }
if (ImGui::IsItemHovered()) { if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Fade in"); ImGui::SetTooltip("Fade in");
} }
ImGui::SameLine(); sameLineMaybe();
if (ImGui::Button(ICON_FA_ARROW_DOWN "##SFadeOut")) { if (ImGui::Button(ICON_FA_ARROW_DOWN "##SFadeOut")) {
doAction(GUI_ACTION_SAMPLE_FADE_OUT); doAction(GUI_ACTION_SAMPLE_FADE_OUT);
} }
if (ImGui::IsItemHovered()) { if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Fade out"); ImGui::SetTooltip("Fade out");
} }
ImGui::SameLine(); sameLineMaybe();
ImGui::Button(ICON_FA_ADJUST "##SInsertSilence"); ImGui::Button(ICON_FA_ADJUST "##SInsertSilence");
if (ImGui::IsItemHovered()) { if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Insert silence"); ImGui::SetTooltip("Insert silence");
@ -902,21 +935,21 @@ void FurnaceGUI::drawSampleEdit() {
} }
ImGui::EndPopup(); ImGui::EndPopup();
} }
ImGui::SameLine(); sameLineMaybe();
if (ImGui::Button(ICON_FA_ERASER "##SSilence")) { if (ImGui::Button(ICON_FA_ERASER "##SSilence")) {
doAction(GUI_ACTION_SAMPLE_SILENCE); doAction(GUI_ACTION_SAMPLE_SILENCE);
} }
if (ImGui::IsItemHovered()) { if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Apply silence"); ImGui::SetTooltip("Apply silence");
} }
ImGui::SameLine(); sameLineMaybe();
if (ImGui::Button(ICON_FA_TIMES "##SDelete")) { if (ImGui::Button(ICON_FA_TIMES "##SDelete")) {
doAction(GUI_ACTION_SAMPLE_DELETE); doAction(GUI_ACTION_SAMPLE_DELETE);
} }
if (ImGui::IsItemHovered()) { if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Delete"); ImGui::SetTooltip("Delete");
} }
ImGui::SameLine(); sameLineMaybe();
if (ImGui::Button(ICON_FA_CROP "##STrim")) { if (ImGui::Button(ICON_FA_CROP "##STrim")) {
doAction(GUI_ACTION_SAMPLE_TRIM); doAction(GUI_ACTION_SAMPLE_TRIM);
} }
@ -925,28 +958,28 @@ void FurnaceGUI::drawSampleEdit() {
} }
ImGui::SameLine(); ImGui::SameLine();
ImGui::Dummy(ImVec2(4.0*dpiScale,dpiScale)); ImGui::Dummy(ImVec2(4.0*dpiScale,dpiScale));
ImGui::SameLine(); sameLineMaybe();
if (ImGui::Button(ICON_FA_BACKWARD "##SReverse")) { if (ImGui::Button(ICON_FA_BACKWARD "##SReverse")) {
doAction(GUI_ACTION_SAMPLE_REVERSE); doAction(GUI_ACTION_SAMPLE_REVERSE);
} }
if (ImGui::IsItemHovered()) { if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Reverse"); ImGui::SetTooltip("Reverse");
} }
ImGui::SameLine(); sameLineMaybe();
if (ImGui::Button(ICON_FA_SORT_AMOUNT_ASC "##SInvert")) { if (ImGui::Button(ICON_FA_SORT_AMOUNT_ASC "##SInvert")) {
doAction(GUI_ACTION_SAMPLE_INVERT); doAction(GUI_ACTION_SAMPLE_INVERT);
} }
if (ImGui::IsItemHovered()) { if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Invert"); ImGui::SetTooltip("Invert");
} }
ImGui::SameLine(); sameLineMaybe();
if (ImGui::Button(ICON_FA_LEVEL_DOWN "##SSign")) { if (ImGui::Button(ICON_FA_LEVEL_DOWN "##SSign")) {
doAction(GUI_ACTION_SAMPLE_SIGN); doAction(GUI_ACTION_SAMPLE_SIGN);
} }
if (ImGui::IsItemHovered()) { if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Signed/unsigned exchange"); ImGui::SetTooltip("Signed/unsigned exchange");
} }
ImGui::SameLine(); sameLineMaybe();
ImGui::Button(ICON_FA_INDUSTRY "##SFilter"); ImGui::Button(ICON_FA_INDUSTRY "##SFilter");
if (ImGui::IsItemHovered()) { if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Apply filter"); ImGui::SetTooltip("Apply filter");
@ -1062,21 +1095,21 @@ void FurnaceGUI::drawSampleEdit() {
ImGui::EndDisabled(); ImGui::EndDisabled();
ImGui::SameLine(); ImGui::SameLine();
ImGui::Dummy(ImVec2(4.0*dpiScale,dpiScale)); ImGui::Dummy(ImVec2(4.0*dpiScale,dpiScale));
ImGui::SameLine(); sameLineMaybe();
if (ImGui::Button(ICON_FA_PLAY "##PreviewSample")) { if (ImGui::Button(ICON_FA_PLAY "##PreviewSample")) {
e->previewSample(curSample); e->previewSample(curSample);
} }
if (ImGui::IsItemHovered()) { if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Preview sample"); ImGui::SetTooltip("Preview sample");
} }
ImGui::SameLine(); sameLineMaybe();
if (ImGui::Button(ICON_FA_STOP "##StopSample")) { if (ImGui::Button(ICON_FA_STOP "##StopSample")) {
e->stopSamplePreview(); e->stopSamplePreview();
} }
if (ImGui::IsItemHovered()) { if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Stop sample preview"); ImGui::SetTooltip("Stop sample preview");
} }
ImGui::SameLine(); sameLineMaybe();
if (ImGui::Button(ICON_FA_UPLOAD "##MakeIns")) { if (ImGui::Button(ICON_FA_UPLOAD "##MakeIns")) {
doAction(GUI_ACTION_SAMPLE_MAKE_INS); doAction(GUI_ACTION_SAMPLE_MAKE_INS);
} }
@ -1084,7 +1117,7 @@ void FurnaceGUI::drawSampleEdit() {
ImGui::SetTooltip("Create instrument from sample"); ImGui::SetTooltip("Create instrument from sample");
} }
ImGui::SameLine(); sameLineMaybe(ImGui::CalcTextSize("Zoom").x+150.0f*dpiScale+ImGui::CalcTextSize("100%").x);
double zoomPercent=100.0/sampleZoom; double zoomPercent=100.0/sampleZoom;
bool checkZoomLimit=false; bool checkZoomLimit=false;
ImGui::Text("Zoom"); ImGui::Text("Zoom");
@ -1702,7 +1735,16 @@ void FurnaceGUI::drawSampleEdit() {
ImGui::TableNextColumn(); ImGui::TableNextColumn();
ImGui::TextUnformatted(statusBar2.c_str()); ImGui::TextUnformatted(statusBar2.c_str());
ImGui::TableNextColumn(); ImGui::TableNextColumn();
if (!warnLength.empty()) {
ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_WARNING]);
ImGui::TextUnformatted(statusBar3.c_str()); ImGui::TextUnformatted(statusBar3.c_str());
ImGui::PopStyleColor();
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("%s",warnLength.c_str());
}
} else {
ImGui::TextUnformatted(statusBar3.c_str());
}
ImGui::EndTable(); ImGui::EndTable();
} }

View File

@ -508,6 +508,14 @@ void FurnaceGUI::drawSettings() {
settings.alwaysPlayIntro=3; settings.alwaysPlayIntro=3;
} }
ImGui::Text("When creating new song:");
if (ImGui::RadioButton("Display system preset selector##NSB0",settings.newSongBehavior==0)) {
settings.newSongBehavior=0;
}
if (ImGui::RadioButton("Start with initial system##NSB1",settings.newSongBehavior==1)) {
settings.newSongBehavior=1;
}
ImGui::Separator(); ImGui::Separator();
if (CWSliderFloat("Double-click time (seconds)",&settings.doubleClickTime,0.02,1.0,"%.2f")) { if (CWSliderFloat("Double-click time (seconds)",&settings.doubleClickTime,0.02,1.0,"%.2f")) {
@ -2757,6 +2765,7 @@ void FurnaceGUI::syncSettings() {
settings.renderClearPos=e->getConfInt("renderClearPos",0); settings.renderClearPos=e->getConfInt("renderClearPos",0);
settings.insertBehavior=e->getConfInt("insertBehavior",1); settings.insertBehavior=e->getConfInt("insertBehavior",1);
settings.pullDeleteRow=e->getConfInt("pullDeleteRow",1); settings.pullDeleteRow=e->getConfInt("pullDeleteRow",1);
settings.newSongBehavior=e->getConfInt("newSongBehavior",0);
clampSetting(settings.mainFontSize,2,96); clampSetting(settings.mainFontSize,2,96);
clampSetting(settings.patFontSize,2,96); clampSetting(settings.patFontSize,2,96);
@ -2882,6 +2891,7 @@ void FurnaceGUI::syncSettings() {
clampSetting(settings.renderClearPos,0,1); clampSetting(settings.renderClearPos,0,1);
clampSetting(settings.insertBehavior,0,1); clampSetting(settings.insertBehavior,0,1);
clampSetting(settings.pullDeleteRow,0,1); clampSetting(settings.pullDeleteRow,0,1);
clampSetting(settings.newSongBehavior,0,1);
if (settings.exportLoops<0.0) settings.exportLoops=0.0; if (settings.exportLoops<0.0) settings.exportLoops=0.0;
if (settings.exportFadeOut<0.0) settings.exportFadeOut=0.0; if (settings.exportFadeOut<0.0) settings.exportFadeOut=0.0;
@ -3103,6 +3113,7 @@ void FurnaceGUI::commitSettings() {
e->setConf("renderClearPos",settings.renderClearPos); e->setConf("renderClearPos",settings.renderClearPos);
e->setConf("insertBehavior",settings.insertBehavior); e->setConf("insertBehavior",settings.insertBehavior);
e->setConf("pullDeleteRow",settings.pullDeleteRow); e->setConf("pullDeleteRow",settings.pullDeleteRow);
e->setConf("newSongBehavior",settings.newSongBehavior);
// colors // colors
for (int i=0; i<GUI_COLOR_MAX; i++) { for (int i=0; i<GUI_COLOR_MAX; i++) {