Merge branch 'master' into preset1

This commit is contained in:
cam900 2022-06-17 09:19:17 +09:00
commit 0c1a8bc001
33 changed files with 1595 additions and 322 deletions

View File

@ -1,12 +1,13 @@
# to-do for 0.6pre1
- rewrite the system name detection function anyway
- add another FM editor layout
- add ability to move selection by dragging
- find and replace
- implement Defle slide bug when using E1xy/E2xy and repeating origin note (requires format change)
# to-do for 0.6pre2 (as this requires new data structures)
- rewrite the system name detection function anyway
- this involves the addition of a new "system" field in the song (which solves the problem)
- songs made in older versions will go through old system name detection for compatibility
- Game Boy envelope macro/sequence
- volume commands should work on Game Boy
- ability to customize `OFF`, `===` and `REL`

BIN
demos/E1M4OPL2.fur Normal file

Binary file not shown.

BIN
demos/FDS TEST.fur Normal file

Binary file not shown.

BIN
demos/Fake Gameboy.fur Normal file

Binary file not shown.

Binary file not shown.

BIN
demos/Fusion.fur Normal file

Binary file not shown.

BIN
demos/c64 ring test.fur Normal file

Binary file not shown.

BIN
demos/game boy thing.fur Normal file

Binary file not shown.

Binary file not shown.

BIN
demos/the_erfngjt.fur Normal file

Binary file not shown.

BIN
demos/thick bass test.fur Normal file

Binary file not shown.

View File

@ -1287,8 +1287,6 @@ namespace IGFD
std::sort(prFileList.begin(), prFileList.end(),
[](const std::shared_ptr<FileInfos>& a, const std::shared_ptr<FileInfos>& b) -> bool
{
if (a==NULL || b==NULL)
return false;
if (!a.use_count() || !b.use_count())
return false;
@ -1760,7 +1758,7 @@ namespace IGFD
struct stat statInfos = {};
char timebuf[100];
int result = stat(fpn.c_str(), &statInfos);
if (!result)
if (result!=-1)
{
if (vInfos->fileType != 'd')
{
@ -1781,7 +1779,11 @@ namespace IGFD
{
vInfos->fileModifDate = std::string(timebuf, len);
}
}
} else {
vInfos->fileSize=0;
vInfos->formatedFileSize = prFormatFileSize(vInfos->fileSize);
vInfos->fileModifDate="???";
}
}
}

View File

@ -21,6 +21,26 @@
#include "../ta-log.h"
#include "taAudio.h"
String sanitizePortName(const String& name) {
#if defined(_WIN32)
// remove port number
size_t namePos=name.rfind(' ');
if (namePos!=String::npos) {
return name.substr(0,namePos);
}
return name;
#elif defined(__linux__)
// remove port location
size_t namePos=name.rfind(' ');
if (namePos!=String::npos) {
return name.substr(0,namePos);
}
return name;
#else
return name;
#endif
}
// --- IN ---
bool TAMidiInRtMidi::gather() {
@ -56,7 +76,7 @@ std::vector<String> TAMidiInRtMidi::listDevices() {
unsigned int count=port->getPortCount();
logD("got port count.");
for (unsigned int i=0; i<count; i++) {
String name=port->getPortName(i);
String name=sanitizePortName(port->getPortName(i));
if (name!="") ret.push_back(name);
}
} catch (RtMidiError& e) {
@ -75,8 +95,12 @@ bool TAMidiInRtMidi::openDevice(String name) {
try {
bool portOpen=false;
unsigned int count=port->getPortCount();
logD("finding port %s...",name);
for (unsigned int i=0; i<count; i++) {
if (port->getPortName(i)==name) {
String portName=sanitizePortName(port->getPortName(i));
logV("- %d: %s",i,portName);
if (portName==name) {
logD("opening port %d...",i);
port->openPort(i);
portOpen=true;
break;
@ -184,8 +208,12 @@ bool TAMidiOutRtMidi::openDevice(String name) {
try {
bool portOpen=false;
unsigned int count=port->getPortCount();
logD("finding port %s...",name);
for (unsigned int i=0; i<count; i++) {
if (port->getPortName(i)==name) {
String portName=sanitizePortName(port->getPortName(i));
logV("- %d: %s",i,portName);
if (portName==name) {
logD("opening port %d...",i);
port->openPort(i);
portOpen=true;
break;
@ -222,7 +250,7 @@ std::vector<String> TAMidiOutRtMidi::listDevices() {
try {
unsigned int count=port->getPortCount();
for (unsigned int i=0; i<count; i++) {
String name=port->getPortName(i);
String name=sanitizePortName(port->getPortName(i));
if (name!="") ret.push_back(name);
}
} catch (RtMidiError& e) {
@ -248,4 +276,4 @@ bool TAMidiOutRtMidi::quit() {
port=NULL;
}
return true;
}
}

View File

@ -83,7 +83,7 @@ struct DivChannelState {
int note, oldNote, lastIns, pitch, portaSpeed, portaNote;
int volume, volSpeed, cut, rowDelay, volMax;
int delayOrder, delayRow, retrigSpeed, retrigTick;
int vibratoDepth, vibratoRate, vibratoPos, vibratoDir, vibratoFine;
int vibratoDepth, vibratoRate, vibratoPos, vibratoPosGiant, vibratoDir, vibratoFine;
int tremoloDepth, tremoloRate, tremoloPos;
unsigned char arp, arpStage, arpTicks, panL, panR;
bool doNote, legato, portaStop, keyOn, keyOff, nowYouCanStop, stopOnOff;
@ -112,6 +112,7 @@ struct DivChannelState {
vibratoDepth(0),
vibratoRate(0),
vibratoPos(0),
vibratoPosGiant(0),
vibratoDir(0),
vibratoFine(15),
tremoloDepth(0),

View File

@ -306,7 +306,7 @@ void DivPlatformBubSysWSG::reset() {
for (int i=0; i<2; i++) {
chan[i]=DivPlatformBubSysWSG::Channel();
chan[i].std.setEngine(parent);
chan[i].ws.setEngine(parent);
chan[i].ws.setEngine(parent,8);
chan[i].ws.init(NULL,32,15,false);
}
if (dumpWrites) {

View File

@ -380,7 +380,7 @@ void DivPlatformMSM6258::setFlags(unsigned int flags) {
chipClock=4000000;
break;
}
rate=chipClock/128;
rate=chipClock/256;
for (int i=0; i<1; i++) {
oscBuf[i]->rate=rate;
}

View File

@ -682,6 +682,9 @@ void DivPlatformOPL::muteChannel(int ch, bool mute) {
fm.channel[outChanMap[ch]].muted=mute;
}
int ops=(slots[3][ch]!=255 && chan[ch].state.ops==4 && oplType==3)?4:2;
if (ch&1 && ch<12) {
if (chan[ch-1].fourOp) return;
}
chan[ch].fourOp=(ops==4);
update4OpMask=true;
for (int i=0; i<ops; i++) {

View File

@ -332,7 +332,7 @@ void DivPlatformSCC::reset() {
for (int i=0; i<5; i++) {
chan[i]=DivPlatformSCC::Channel();
chan[i].std.setEngine(parent);
chan[i].ws.setEngine(parent);
chan[i].ws.setEngine(parent,128);
chan[i].ws.init(NULL,32,255,false);
chan[i].vol=15;
chan[i].outVol=15;

View File

@ -347,7 +347,7 @@ int DivPlatformSwan::dispatch(DivCommand c) {
case DIV_CMD_VOLUME:
if (chan[c.chan].vol!=c.value) {
chan[c.chan].vol=c.value;
if (!chan[c.chan].std.vol.had) {
if (!chan[c.chan].std.vol.has) {
calcAndWriteOutVol(c.chan,15);
}
}

View File

@ -195,7 +195,7 @@ int DivPlatformVIC20::dispatch(DivCommand c) {
case DIV_CMD_VOLUME:
if (chan[c.chan].vol!=c.value) {
chan[c.chan].vol=c.value;
if (!chan[c.chan].std.vol.had) {
if (!chan[c.chan].std.vol.has) {
calcAndWriteOutVol(c.chan,15);
}
}

View File

@ -988,6 +988,10 @@ bool DivEngine::nextTick(bool noAccum, bool inhibitLowLat) {
if (chan[i].vibratoDepth>0) {
chan[i].vibratoPos+=chan[i].vibratoRate;
if (chan[i].vibratoPos>=64) chan[i].vibratoPos-=64;
chan[i].vibratoPosGiant+=chan[i].vibratoRate;
if (chan[i].vibratoPos>=512) chan[i].vibratoPos-=512;
switch (chan[i].vibratoDir) {
case 1: // up
dispatchCmd(DivCommand(DIV_CMD_PITCH,i,chan[i].pitch+(MAX(0,(chan[i].vibratoDepth*vibTable[chan[i].vibratoPos]*chan[i].vibratoFine)>>4)/15)));

View File

@ -243,8 +243,13 @@ void DivWaveSynth::changeWave2(int num) {
first=true;
}
void DivWaveSynth::setEngine(DivEngine* engine) {
void DivWaveSynth::setEngine(DivEngine* engine, int waveFloor) {
e=engine;
memset(wave1,waveFloor,256);
memset(wave2,waveFloor,256);
for (int i=0; i<256; i++) {
output[i]=waveFloor;
}
}
void DivWaveSynth::init(DivInstrument* which, int w, int h, bool insChanged) {

View File

@ -70,7 +70,7 @@ class DivWaveSynth {
* @param insChanged whether the instrument has changed.
*/
void init(DivInstrument* which, int width, int height, bool insChanged=false);
void setEngine(DivEngine* engine);
void setEngine(DivEngine* engine, int waveFloor=0);
DivWaveSynth():
e(NULL),
pos(0),

View File

@ -66,6 +66,8 @@ void FurnaceGUI::prepareUndo(ActionType action) {
e->curPat[i].getPattern(e->curOrders->ord[i][curOrder],false)->copyOn(oldPat[i]);
}
break;
case GUI_UNDO_REPLACE: // this is handled by doReplace()
break;
}
}
@ -126,6 +128,8 @@ void FurnaceGUI::makeUndo(ActionType action) {
doPush=true;
}
break;
case GUI_UNDO_REPLACE: // this is handled by doReplace()
break;
}
if (doPush) {
MARK_MODIFIED;
@ -943,6 +947,7 @@ void FurnaceGUI::doUndo() {
case GUI_UNDO_PATTERN_FLIP:
case GUI_UNDO_PATTERN_COLLAPSE:
case GUI_UNDO_PATTERN_EXPAND:
case GUI_UNDO_REPLACE:
for (UndoPatternData& i: us.pat) {
e->changeSongP(i.subSong);
DivPattern* p=e->curPat[i.chan].getPattern(i.pat,true);
@ -991,6 +996,7 @@ void FurnaceGUI::doRedo() {
case GUI_UNDO_PATTERN_FLIP:
case GUI_UNDO_PATTERN_COLLAPSE:
case GUI_UNDO_PATTERN_EXPAND:
case GUI_UNDO_REPLACE:
for (UndoPatternData& i: us.pat) {
e->changeSongP(i.subSong);
DivPattern* p=e->curPat[i.chan].getPattern(i.pat,true);

File diff suppressed because it is too large Load Diff

View File

@ -4105,6 +4105,7 @@ bool FurnaceGUI::init() {
#ifndef __APPLE__
if (settings.dpiScale<0.5f) {
// TODO: replace with a function to actually detect the display scaling factor as it's unreliable.
SDL_GetDisplayDPI(SDL_GetWindowDisplayIndex(sdlWin),&dpiScaleF,NULL,NULL);
dpiScale=round(dpiScaleF/96.0f);
if (dpiScale<1) dpiScale=1;
@ -4431,6 +4432,26 @@ FurnaceGUI::FurnaceGUI():
wavePreviewLen(32),
wavePreviewHeight(255),
wavePreviewInit(true),
pgSys(0),
pgAddr(0),
pgVal(0),
curQueryRangeX(false),
curQueryBackwards(false),
curQueryRangeXMin(0), curQueryRangeXMax(0),
curQueryRangeY(0),
curQueryEffectPos(0),
queryReplaceEffectCount(0),
queryReplaceEffectPos(0),
queryReplaceNoteMode(0),
queryReplaceInsMode(0),
queryReplaceVolMode(0),
queryReplaceNote(0),
queryReplaceIns(0),
queryReplaceVol(0),
queryReplaceNoteDo(false),
queryReplaceInsDo(false),
queryReplaceVolDo(false),
queryViewingResults(false),
wavePreviewOn(false),
wavePreviewKey((SDL_Scancode)0),
wavePreviewNote(0),
@ -4624,4 +4645,11 @@ FurnaceGUI::FurnaceGUI():
memset(pianoKeyHit,0,sizeof(float)*180);
memset(pianoKeyPressed,0,sizeof(bool)*180);
memset(queryReplaceEffectMode,0,sizeof(int)*8);
memset(queryReplaceEffectValMode,0,sizeof(int)*8);
memset(queryReplaceEffect,0,sizeof(int)*8);
memset(queryReplaceEffectVal,0,sizeof(int)*8);
memset(queryReplaceEffectDo,0,sizeof(bool)*8);
memset(queryReplaceEffectValDo,0,sizeof(bool)*8);
}

View File

@ -566,7 +566,8 @@ enum ActionType {
GUI_UNDO_PATTERN_INVERT_VAL,
GUI_UNDO_PATTERN_FLIP,
GUI_UNDO_PATTERN_COLLAPSE,
GUI_UNDO_PATTERN_EXPAND
GUI_UNDO_PATTERN_EXPAND,
GUI_UNDO_REPLACE
};
struct UndoPatternData {
@ -818,6 +819,7 @@ enum FurnaceGUIFindQueryModes {
enum FurnaceGUIFindQueryReplaceModes {
GUI_QUERY_REPLACE_SET=0,
GUI_QUERY_REPLACE_ADD,
GUI_QUERY_REPLACE_ADD_OVERFLOW,
GUI_QUERY_REPLACE_CLEAR,
GUI_QUERY_REPLACE_MAX
@ -855,6 +857,20 @@ struct FurnaceGUIFindQuery {
}
};
struct FurnaceGUIQueryResult {
int subsong, order, x, y;
FurnaceGUIQueryResult():
subsong(0),
order(0),
x(0),
y(0) {}
FurnaceGUIQueryResult(int ss, int o, int xPos, int yPos):
subsong(ss),
order(o),
x(xPos),
y(yPos) {}
};
class FurnaceGUI {
DivEngine* e;
@ -1170,11 +1186,31 @@ class FurnaceGUI {
int pgSys, pgAddr, pgVal;
std::vector<FurnaceGUIFindQuery> curQuery;
bool curQueryRangeX, curQueryFromStart, curQueryBackwards;
std::vector<FurnaceGUIQueryResult> curQueryResults;
bool curQueryRangeX, curQueryBackwards;
int curQueryRangeXMin, curQueryRangeXMax;
int curQueryRangeY;
int curQueryEffectPos;
int queryReplaceEffectCount;
int queryReplaceEffectPos;
int queryReplaceNoteMode;
int queryReplaceInsMode;
int queryReplaceVolMode;
int queryReplaceEffectMode[8];
int queryReplaceEffectValMode[8];
int queryReplaceNote;
int queryReplaceIns;
int queryReplaceVol;
int queryReplaceEffect[8];
int queryReplaceEffectVal[8];
bool queryReplaceNoteDo;
bool queryReplaceInsDo;
bool queryReplaceVolDo;
bool queryReplaceEffectDo[8];
bool queryReplaceEffectValDo[8];
bool queryViewingResults;
struct ActiveNote {
int chan;
int note;
@ -1456,6 +1492,8 @@ class FurnaceGUI {
void doExpand(int multiplier);
void doUndo();
void doRedo();
void doFind();
void doReplace();
void editOptions(bool topMenu);
void noteInput(int num, int key, int vol=-1);
void valueInput(int num, bool direct=false, int target=-1);
@ -1502,6 +1540,8 @@ class FurnaceGUI {
void addScroll(int amount);
void setFileName(String name);
void runBackupThread();
void pushPartBlend();
void popPartBlend();
int processEvent(SDL_Event* ev);
bool loop();
bool finish();

View File

@ -1345,6 +1345,9 @@ void FurnaceGUI::drawMacros(std::vector<FurnaceGUIMacroDesc>& macros) {
#define CENTER_VSLIDER \
ImGui::SetCursorPosX(ImGui::GetCursorPosX()+0.5f*ImGui::GetContentRegionAvail().x-10.0f*dpiScale);
#define CENTER_TEXT_20(text) \
ImGui::SetCursorPosX(ImGui::GetCursorPosX()+0.5*(20.0f*dpiScale-ImGui::CalcTextSize(text).x));
void FurnaceGUI::drawInsEdit() {
if (nextWindow==GUI_WINDOW_INS_EDIT) {
insEditOpen=true;
@ -2016,7 +2019,452 @@ void FurnaceGUI::drawInsEdit() {
ImGui::EndTable();
}
} else {
} else if (settings.fmLayout>=4 && settings.fmLayout<=6) { // alternate
int columns=2;
switch (settings.fmLayout) {
case 4: // 2x2
columns=2;
break;
case 5: // 1x4
columns=1;
break;
case 6: // 4x1
columns=opCount;
break;
}
char tempID[1024];
ImVec2 oldPadding=ImGui::GetStyle().CellPadding;
ImGui::PushStyleVar(ImGuiStyleVar_CellPadding,ImVec2(8.0f*dpiScale,4.0f*dpiScale));
if (ImGui::BeginTable("KGE93BSIEO3NOWBDJZBA",columns,ImGuiTableFlags_SizingStretchSame|ImGuiTableFlags_BordersInner)) {
for (int i=0; i<opCount; i++) {
DivInstrumentFM::Operator& op=ins->fm.op[(opCount==4 && ins->type!=DIV_INS_OPL_DRUMS)?opOrder[i]:i];
if ((settings.fmLayout!=6 && ((i+1)&1)) || i==0 || settings.fmLayout==5) ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::PushID(fmt::sprintf("op%d",i).c_str());
// push colors
if (settings.separateFMColors) {
bool mod=true;
if (ins->type==DIV_INS_OPL_DRUMS) {
mod=false;
} else if (opCount==4) {
if (ins->type==DIV_INS_OPL) {
if (opIsOutputOPL[ins->fm.alg&3][i]) mod=false;
} else {
if (opIsOutput[ins->fm.alg&7][i]) mod=false;
}
} else {
if (i==1 || (ins->type==DIV_INS_OPL && (ins->fm.alg&1))) mod=false;
}
if (mod) {
pushAccentColors(
uiColors[GUI_COLOR_FM_PRIMARY_MOD],
uiColors[GUI_COLOR_FM_SECONDARY_MOD],
uiColors[GUI_COLOR_FM_BORDER_MOD],
uiColors[GUI_COLOR_FM_BORDER_SHADOW_MOD]
);
} else {
pushAccentColors(
uiColors[GUI_COLOR_FM_PRIMARY_CAR],
uiColors[GUI_COLOR_FM_SECONDARY_CAR],
uiColors[GUI_COLOR_FM_BORDER_CAR],
uiColors[GUI_COLOR_FM_BORDER_SHADOW_CAR]
);
}
}
ImGui::Dummy(ImVec2(dpiScale,dpiScale));
if (ins->type==DIV_INS_OPL_DRUMS) {
snprintf(tempID,1024,"%s",oplDrumNames[i]);
} else if (ins->type==DIV_INS_OPL && ins->fm.opllPreset==16) {
if (i==1) {
snprintf(tempID,1024,"Envelope 2 (kick only)");
} else {
snprintf(tempID,1024,"Envelope");
}
} else {
snprintf(tempID,1024,"Operator %d",i+1);
}
CENTER_TEXT(tempID);
ImGui::TextUnformatted(tempID);
float sliderHeight=200.0f*dpiScale;
float waveWidth=140.0*dpiScale;
float waveHeight=sliderHeight-ImGui::GetFrameHeightWithSpacing()*(ins->type==DIV_INS_OPLL?4.5f:5.5f);
int maxTl=127;
if (ins->type==DIV_INS_OPLL) {
if (i==1) {
maxTl=15;
} else {
maxTl=63;
}
}
if (ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS) {
maxTl=63;
}
int maxArDr=(ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ)?31:15;
bool ssgOn=op.ssgEnv&8;
bool ksrOn=op.ksr;
bool vibOn=op.vib;
bool egtOn=op.egt;
bool susOn=op.sus; // yawn
unsigned char ssgEnv=op.ssgEnv&7;
ImGui::PushStyleVar(ImGuiStyleVar_CellPadding,oldPadding);
if (ImGui::BeginTable("opParams",4,ImGuiTableFlags_BordersInnerV)) {
ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed);
ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthFixed,waveWidth);
ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthStretch);
ImGui::TableSetupColumn("c3",ImGuiTableColumnFlags_WidthFixed);
ImGui::TableNextRow();
ImGui::TableNextColumn();
float textY=ImGui::GetCursorPosY();
CENTER_TEXT_20(FM_SHORT_NAME(FM_AR));
ImGui::TextUnformatted(FM_SHORT_NAME(FM_AR));
ImGui::TableNextColumn();
if (ins->type==DIV_INS_FM) {
ImGui::Text("SSG-EG");
} else {
ImGui::Text("Waveform");
}
ImGui::TableNextColumn();
ImGui::Text("Envelope");
ImGui::TableNextColumn();
CENTER_TEXT(FM_SHORT_NAME(FM_TL));
ImGui::Text("TL");
// A/D/S/R
ImGui::TableNextColumn();
op.ar&=maxArDr;
P(CWVSliderScalar("##AR",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.ar,&maxArDr,&_ZERO));
ImGui::SameLine();
op.dr&=maxArDr;
float textX_DR=ImGui::GetCursorPosX();
P(CWVSliderScalar("##DR",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.dr,&maxArDr,&_ZERO));
float textX_SL=0.0f;
if (settings.susPosition==0) {
ImGui::SameLine();
op.sl&=15;
textX_SL=ImGui::GetCursorPosX();
P(CWVSliderScalar("##SL",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.sl,&_FIFTEEN,&_ZERO));
}
float textX_D2R=0.0f;
if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ) {
ImGui::SameLine();
op.d2r&=31;
textX_D2R=ImGui::GetCursorPosX();
P(CWVSliderScalar("##D2R",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.d2r,&_THIRTY_ONE,&_ZERO));
}
ImGui::SameLine();
op.rr&=15;
float textX_RR=ImGui::GetCursorPosX();
P(CWVSliderScalar("##RR",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.rr,&_FIFTEEN,&_ZERO));
if (settings.susPosition==1) {
ImGui::SameLine();
op.sl&=15;
textX_SL=ImGui::GetCursorPosX();
P(CWVSliderScalar("##SL",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.sl,&_FIFTEEN,&_ZERO));
}
ImVec2 prevCurPos=ImGui::GetCursorPos();
// labels
ImGui::SetCursorPos(ImVec2(textX_DR,textY));
CENTER_TEXT_20(FM_SHORT_NAME(FM_DR));
ImGui::TextUnformatted(FM_SHORT_NAME(FM_DR));
ImGui::SetCursorPos(ImVec2(textX_SL,textY));
CENTER_TEXT_20(FM_SHORT_NAME(FM_SL));
ImGui::TextUnformatted(FM_SHORT_NAME(FM_SL));
ImGui::SetCursorPos(ImVec2(textX_RR,textY));
CENTER_TEXT_20(FM_SHORT_NAME(FM_RR));
ImGui::TextUnformatted(FM_SHORT_NAME(FM_RR));
if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ) {
ImGui::SetCursorPos(ImVec2(textX_D2R,textY));
CENTER_TEXT_20(FM_SHORT_NAME(FM_D2R));
ImGui::TextUnformatted(FM_SHORT_NAME(FM_D2R));
}
ImGui::SetCursorPos(prevCurPos);
ImGui::TableNextColumn();
switch (ins->type) {
case DIV_INS_FM: {
// SSG
ImGui::BeginDisabled(!ssgOn);
drawSSGEnv(op.ssgEnv&7,ImVec2(waveWidth,waveHeight));
ImGui::EndDisabled();
if (ImGui::Checkbox("##SSGOn",&ssgOn)) { PARAMETER
op.ssgEnv=(op.ssgEnv&7)|(ssgOn<<3);
}
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Only for OPN family chips");
}
ImGui::SameLine();
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
if (CWSliderScalar("##SSG",ImGuiDataType_U8,&ssgEnv,&_ZERO,&_SEVEN,ssgEnvTypes[ssgEnv])) { PARAMETER
op.ssgEnv=(op.ssgEnv&8)|(ssgEnv&7);
}
// params
ImGui::Separator();
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_MULT));
P(CWSliderScalar("##MULT",ImGuiDataType_U8,&op.mult,&_ZERO,&_FIFTEEN,tempID)); rightClickable
int detune=(op.dt&7)-3;
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_DT));
if (CWSliderInt("##DT",&detune,-3,4,tempID)) { PARAMETER
op.dt=detune+3;
} rightClickable
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_DT2));
P(CWSliderScalar("##DT2",ImGuiDataType_U8,&op.dt2,&_ZERO,&_THREE,tempID)); rightClickable
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Only on YM2151 (OPM)");
}
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_RS));
P(CWSliderScalar("##RS",ImGuiDataType_U8,&op.rs,&_ZERO,&_THREE,tempID)); rightClickable
break;
}
case DIV_INS_OPLL:
// waveform
drawWaveform(i==0?(ins->fm.ams&1):(ins->fm.fms&1),ins->type==DIV_INS_OPZ,ImVec2(waveWidth,waveHeight));
// params
ImGui::Separator();
if (ImGui::BeginTable("FMParamsInner",2)) {
ImGui::TableNextRow();
ImGui::TableNextColumn();
bool amOn=op.am;
if (ImGui::Checkbox(FM_NAME(FM_AM),&amOn)) { PARAMETER
op.am=amOn;
}
ImGui::TableNextColumn();
if (ImGui::Checkbox(FM_NAME(FM_KSR),&ksrOn)) { PARAMETER
op.ksr=ksrOn;
}
ImGui::TableNextRow();
ImGui::TableNextColumn();
if (ImGui::Checkbox(FM_NAME(FM_VIB),&vibOn)) { PARAMETER
op.vib=vibOn;
}
ImGui::TableNextColumn();
if (ImGui::Checkbox(FM_NAME(FM_EGS),&ssgOn)) { PARAMETER
op.ssgEnv=(op.ssgEnv&7)|(ssgOn<<3);
}
ImGui::EndTable();
}
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_MULT));
P(CWSliderScalar("##MULT",ImGuiDataType_U8,&op.mult,&_ZERO,&_FIFTEEN,tempID)); rightClickable
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_KSL));
P(CWSliderScalar("##KSL",ImGuiDataType_U8,&op.ksl,&_ZERO,&_THREE,tempID)); rightClickable
break;
case DIV_INS_OPL:
// waveform
drawWaveform(op.ws&7,ins->type==DIV_INS_OPZ,ImVec2(waveWidth,waveHeight));
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
P(CWSliderScalar("##WS",ImGuiDataType_U8,&op.ws,&_ZERO,&_SEVEN,(ins->type==DIV_INS_OPZ)?opzWaveforms[op.ws&7]:(settings.oplStandardWaveNames?oplWaveformsStandard[op.ws&7]:oplWaveforms[op.ws&7]))); rightClickable
if ((ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS) && ImGui::IsItemHovered()) {
ImGui::SetTooltip("OPL2/3 only (last 4 waveforms are OPL3 only)");
}
// params
ImGui::Separator();
if (ImGui::BeginTable("FMParamsInner",2)) {
ImGui::TableNextRow();
ImGui::TableNextColumn();
bool amOn=op.am;
if (ImGui::Checkbox(FM_NAME(FM_AM),&amOn)) { PARAMETER
op.am=amOn;
}
ImGui::TableNextColumn();
if (ImGui::Checkbox(FM_NAME(FM_KSR),&ksrOn)) { PARAMETER
op.ksr=ksrOn;
}
ImGui::TableNextRow();
ImGui::TableNextColumn();
if (ImGui::Checkbox(FM_NAME(FM_VIB),&vibOn)) { PARAMETER
op.vib=vibOn;
}
ImGui::TableNextColumn();
if (ImGui::Checkbox(FM_NAME(FM_SUS),&susOn)) { PARAMETER
op.sus=susOn;
}
ImGui::EndTable();
}
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_MULT));
P(CWSliderScalar("##MULT",ImGuiDataType_U8,&op.mult,&_ZERO,&_FIFTEEN,tempID)); rightClickable
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_KSL));
P(CWSliderScalar("##KSL",ImGuiDataType_U8,&op.ksl,&_ZERO,&_THREE,tempID)); rightClickable
break;
case DIV_INS_OPZ: {
// waveform
drawWaveform(op.ws&7,ins->type==DIV_INS_OPZ,ImVec2(waveWidth,waveHeight));
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
P(CWSliderScalar("##WS",ImGuiDataType_U8,&op.ws,&_ZERO,&_SEVEN,(ins->type==DIV_INS_OPZ)?opzWaveforms[op.ws&7]:(settings.oplStandardWaveNames?oplWaveformsStandard[op.ws&7]:oplWaveforms[op.ws&7]))); rightClickable
if ((ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS) && ImGui::IsItemHovered()) {
ImGui::SetTooltip("OPL2/3 only (last 4 waveforms are OPL3 only)");
}
// params
ImGui::Separator();
if (egtOn) {
int block=op.dt;
int freqNum=(op.mult<<4)|(op.dvb&15);
ImGui::Text("Block");
ImGui::SameLine();
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
ImVec2 cursorAlign=ImGui::GetCursorPos();
if (ImGui::InputInt("##Block",&block,1,1)) {
if (block<0) block=0;
if (block>7) block=7;
op.dt=block;
}
ImGui::Text("Freq");
ImGui::SameLine();
ImGui::SetCursorPos(ImVec2(cursorAlign.x,ImGui::GetCursorPosY()));
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
if (ImGui::InputInt("##FreqNum",&freqNum,1,16)) {
if (freqNum<0) freqNum=0;
if (freqNum>255) freqNum=255;
op.mult=freqNum>>4;
op.dvb=freqNum&15;
}
} else {
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_MULT));
P(CWSliderScalar("##MULT",ImGuiDataType_U8,&op.mult,&_ZERO,&_FIFTEEN,tempID)); rightClickable
int detune=(op.dt&7)-3;
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_DT));
if (CWSliderInt("##DT",&detune,-3,4,tempID)) { PARAMETER
op.dt=detune+3;
} rightClickable
}
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_DT2));
P(CWSliderScalar("##DT2",ImGuiDataType_U8,&op.dt2,&_ZERO,&_THREE,tempID)); rightClickable
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Only on YM2151 (OPM)");
}
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_RS));
P(CWSliderScalar("##RS",ImGuiDataType_U8,&op.rs,&_ZERO,&_THREE,tempID)); rightClickable
break;
}
default:
break;
}
ImGui::TableNextColumn();
float envHeight=sliderHeight;//-ImGui::GetStyle().ItemSpacing.y*2.0f;
if (ins->type==DIV_INS_OPZ) {
envHeight-=ImGui::GetFrameHeightWithSpacing()*2.0f;
}
drawFMEnv(op.tl&maxTl,op.ar&maxArDr,op.dr&maxArDr,(ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS || ins->type==DIV_INS_OPLL)?((op.rr&15)*2):op.d2r&31,op.rr&15,op.sl&15,op.sus,op.ssgEnv&8,ins->fm.alg,maxTl,maxArDr,ImVec2(ImGui::GetContentRegionAvail().x,envHeight),ins->type);
if (ins->type==DIV_INS_OPZ) {
ImGui::Separator();
if (ImGui::BeginTable("FMParamsInnerOPZ",2)) {
ImGui::TableNextRow();
ImGui::TableNextColumn();
if (!egtOn) {
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_FINE));
P(CWSliderScalar("##FINE",ImGuiDataType_U8,&op.dvb,&_ZERO,&_FIFTEEN,tempID)); rightClickable
}
ImGui::TableNextColumn();
bool amOn=op.am;
if (ImGui::Checkbox(FM_NAME(FM_AM),&amOn)) { PARAMETER
op.am=amOn;
}
ImGui::SameLine();
if (ImGui::Checkbox("Fixed",&egtOn)) { PARAMETER
op.egt=egtOn;
}
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_EGSHIFT));
P(CWSliderScalar("##EGShift",ImGuiDataType_U8,&op.ksl,&_ZERO,&_THREE,tempID)); rightClickable
ImGui::TableNextColumn();
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_REV));
P(CWSliderScalar("##REV",ImGuiDataType_U8,&op.dam,&_ZERO,&_SEVEN,tempID)); rightClickable
ImGui::TableNextColumn();
ImGui::EndTable();
}
}
ImGui::TableNextColumn();
op.tl&=maxTl;
P(CWVSliderScalar("##TL",ImVec2(ImGui::GetFrameHeight(),sliderHeight-(ins->type==DIV_INS_FM?(ImGui::GetFrameHeightWithSpacing()+ImGui::CalcTextSize(FM_SHORT_NAME(FM_AM)).y+ImGui::GetStyle().ItemSpacing.y):0.0f)),ImGuiDataType_U8,&op.tl,&maxTl,&_ZERO));
if (ins->type==DIV_INS_FM) {
CENTER_TEXT(FM_SHORT_NAME(FM_AM));
ImGui::TextUnformatted(FM_SHORT_NAME(FM_AM));
bool amOn=op.am;
if (ImGui::Checkbox("##AM",&amOn)) { PARAMETER
op.am=amOn;
}
}
ImGui::EndTable();
}
ImGui::PopStyleVar();
if (settings.separateFMColors) {
popAccentColors();
}
ImGui::PopID();
}
ImGui::EndTable();
}
ImGui::PopStyleVar();
} else { // classic
int columns=2;
switch (settings.fmLayout) {
case 1: // 2x2

View File

@ -25,6 +25,7 @@ const int _THREE=3;
const int _SEVEN=7;
const int _TEN=10;
const int _FIFTEEN=15;
const int _SIXTEEN=16;
const int _THIRTY_ONE=31;
const int _SIXTY_FOUR=64;
const int _ONE_HUNDRED=100;

View File

@ -27,6 +27,7 @@ extern const int _THREE;
extern const int _SEVEN;
extern const int _TEN;
extern const int _FIFTEEN;
extern const int _SIXTEEN;
extern const int _THIRTY_ONE;
extern const int _SIXTY_FOUR;
extern const int _ONE_HUNDRED;

View File

@ -17,7 +17,6 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <imgui.h>
#define _USE_MATH_DEFINES
#include "gui.h"
#include "../ta-log.h"
@ -31,6 +30,30 @@ inline float randRange(float min, float max) {
return min+((float)rand()/(float)RAND_MAX)*(max-min);
}
void _pushPartBlend(const ImDrawList* drawList, const ImDrawCmd* cmd) {
if (cmd!=NULL) {
if (cmd->UserCallbackData!=NULL) {
((FurnaceGUI*)cmd->UserCallbackData)->pushPartBlend();
}
}
}
void _popPartBlend(const ImDrawList* drawList, const ImDrawCmd* cmd) {
if (cmd!=NULL) {
if (cmd->UserCallbackData!=NULL) {
((FurnaceGUI*)cmd->UserCallbackData)->popPartBlend();
}
}
}
void FurnaceGUI::pushPartBlend() {
SDL_SetRenderDrawBlendMode(sdlRend,SDL_BLENDMODE_ADD);
}
void FurnaceGUI::popPartBlend() {
SDL_SetRenderDrawBlendMode(sdlRend,SDL_BLENDMODE_BLEND);
}
// draw a pattern row
inline void FurnaceGUI::patternRow(int i, bool isPlaying, float lineHeight, int chans, int ord, const DivPattern** patCache, bool inhibitSel) {
static char id[32];
@ -692,11 +715,14 @@ void FurnaceGUI::drawPattern() {
ImU32* color=noteGrad;
switch (i.cmd) {
case DIV_CMD_NOTE_ON:
case DIV_CMD_NOTE_ON: {
float strength=CLAMP(i.value,0,119);
partIcon=ICON_FA_ASTERISK;
life=96.0f;
life=80.0f+((i.value==DIV_NOTE_NULL)?0.0f:(strength*0.3f));
lifeSpeed=3.0f;
num=6+(strength/16);
break;
}
case DIV_CMD_LEGATO:
partIcon=ICON_FA_COG;
color=insGrad;
@ -794,7 +820,7 @@ void FurnaceGUI::drawPattern() {
float frameTime=ImGui::GetIO().DeltaTime*60.0f;
// note slides
// note slides and vibrato
ImVec2 arrowPoints[7];
if (e->isPlaying()) for (int i=0; i<chans; i++) {
if (!e->curSubSong->chanShow[i]) continue;
@ -849,11 +875,30 @@ void FurnaceGUI::drawPattern() {
}
}
}
if (ch->vibratoDepth>0) {
ImVec4 col=uiColors[GUI_COLOR_PATTERN_EFFECT_PITCH];
col.w*=0.2;
float width=patChanX[i+1]-patChanX[i];
particles.push_back(Particle(
pitchGrad,
ICON_FA_GLASS,
off.x+patChanX[i]+(width*0.5+0.5*sin(M_PI*(float)ch->vibratoPosGiant/64.0f)*width)-scrollX,
off.y+(ImGui::GetWindowHeight()*0.5f)+randRange(0,patFont->FontSize),
randRange(-4.0f,4.0f),
2.0f*(3.0f+(rand()%5)+ch->vibratoRate),
0.4f,
1.0f,
128.0f,
4.0f
));
}
}
// particle simulation
ImDrawList* fdl=ImGui::GetForegroundDrawList();
if (!particles.empty()) WAKE_UP;
fdl->AddCallback(_pushPartBlend,this);
for (size_t i=0; i<particles.size(); i++) {
Particle& part=particles[i];
if (part.update(frameTime)) {
@ -870,6 +915,7 @@ void FurnaceGUI::drawPattern() {
i--;
}
}
fdl->AddCallback(_popPartBlend,this);
}
ImGui::PopStyleColor(3);

View File

@ -1117,6 +1117,15 @@ void FurnaceGUI::drawSettings() {
if (ImGui::RadioButton("Compact (4x1)##fml3",settings.fmLayout==3)) {
settings.fmLayout=3;
}
if (ImGui::RadioButton("Alternate (2x2)##fml4",settings.fmLayout==4)) {
settings.fmLayout=4;
}
if (ImGui::RadioButton("Alternate (1x4)##fml5",settings.fmLayout==5)) {
settings.fmLayout=5;
}
if (ImGui::RadioButton("Alternate (4x1)##fml5",settings.fmLayout==6)) {
settings.fmLayout=6;
}
ImGui::Text("Position of Sustain in FM editor:");
if (ImGui::RadioButton("Between Decay and Sustain Rate##susp0",settings.susPosition==0)) {
@ -2077,7 +2086,7 @@ void FurnaceGUI::syncSettings() {
clampSetting(settings.roundedMenus,0,1);
clampSetting(settings.loadJapanese,0,1);
clampSetting(settings.loadChinese,0,1);
clampSetting(settings.fmLayout,0,3);
clampSetting(settings.fmLayout,0,6);
clampSetting(settings.susPosition,0,1);
clampSetting(settings.effectCursorDir,0,2);
clampSetting(settings.cursorPastePos,0,1);

View File

@ -30,6 +30,7 @@
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <combaseapi.h>
#include <shellapi.h>
#else
#include <unistd.h>
@ -244,6 +245,12 @@ void initParams() {
// TODO: add crash log
int main(int argc, char** argv) {
initLog();
#ifdef _WIN32
HRESULT coResult=CoInitializeEx(NULL,COINIT_MULTITHREADED);
if (coResult!=S_OK) {
logE("CoInitializeEx failed!");
}
#endif
#if !(defined(__APPLE__) || defined(_WIN32) || defined(ANDROID))
// workaround for Wayland HiDPI issue
if (getenv("SDL_VIDEODRIVER")==NULL) {
@ -447,6 +454,12 @@ int main(int argc, char** argv) {
logI("stopping engine.");
e.quit();
#ifdef _WIN32
if (coResult==S_OK || coResult==S_FALSE) {
CoUninitialize();
}
#endif
return 0;
}