Merge branch 'master' of https://github.com/tildearrow/furnace into x1_010_bank
This commit is contained in:
commit
b326087721
Binary file not shown.
Binary file not shown.
|
@ -3112,8 +3112,9 @@ bool ImGui::VSliderScalar(const char* label, const ImVec2& size, ImGuiDataType d
|
|||
const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + size);
|
||||
const ImRect bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f));
|
||||
|
||||
const bool temp_input_allowed = (flags & ImGuiSliderFlags_NoInput) == 0;
|
||||
ItemSize(bb, style.FramePadding.y);
|
||||
if (!ItemAdd(frame_bb, id, NULL, ImGuiItemFlags_NoInertialScroll))
|
||||
if (!ItemAdd(frame_bb, id, NULL, (temp_input_allowed ? ImGuiItemFlags_Inputable : 0) | ImGuiItemFlags_NoInertialScroll))
|
||||
return false;
|
||||
|
||||
// Default format string when passing NULL
|
||||
|
@ -3122,13 +3123,29 @@ bool ImGui::VSliderScalar(const char* label, const ImVec2& size, ImGuiDataType d
|
|||
else if (data_type == ImGuiDataType_S32 && strcmp(format, "%d") != 0) // (FIXME-LEGACY: Patch old "%.0f" format string to use "%d", read function more details.)
|
||||
format = PatchFormatStringFloatToInt(format);
|
||||
|
||||
// Tabbing or CTRL-clicking on Slider turns it into an input box
|
||||
const bool hovered = ItemHoverable(frame_bb, id);
|
||||
if ((hovered && g.IO.MouseClicked[0]) || g.NavActivateId == id || g.NavActivateInputId == id)
|
||||
bool temp_input_is_active = temp_input_allowed && TempInputIsActive(id);
|
||||
if (!temp_input_is_active)
|
||||
{
|
||||
SetActiveID(id, window);
|
||||
SetFocusID(id, window);
|
||||
FocusWindow(window);
|
||||
g.ActiveIdUsingNavDirMask |= (1 << ImGuiDir_Up) | (1 << ImGuiDir_Down);
|
||||
const bool input_requested_by_tabbing = temp_input_allowed && (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_FocusedByTabbing) != 0;
|
||||
const bool clicked = (hovered && g.IO.MouseClicked[0]);
|
||||
if (input_requested_by_tabbing || clicked || g.NavActivateId == id || g.NavActivateInputId == id)
|
||||
{
|
||||
SetActiveID(id, window);
|
||||
SetFocusID(id, window);
|
||||
FocusWindow(window);
|
||||
g.ActiveIdUsingNavDirMask |= (1 << ImGuiDir_Up) | (1 << ImGuiDir_Down);
|
||||
if (temp_input_allowed && (input_requested_by_tabbing || (clicked && g.IO.KeyCtrl) || g.NavActivateInputId == id))
|
||||
temp_input_is_active = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (temp_input_is_active)
|
||||
{
|
||||
// Only clamp CTRL+Click input when ImGuiSliderFlags_AlwaysClamp is set
|
||||
const bool is_clamp_input = (flags & ImGuiSliderFlags_AlwaysClamp) != 0;
|
||||
return TempInputScalar(frame_bb, id, label, data_type, p_data, format, is_clamp_input ? p_min : NULL, is_clamp_input ? p_max : NULL);
|
||||
}
|
||||
|
||||
// Draw frame
|
||||
|
@ -3154,6 +3171,7 @@ bool ImGui::VSliderScalar(const char* label, const ImVec2& size, ImGuiDataType d
|
|||
if (label_size.x > 0.0f)
|
||||
RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label);
|
||||
|
||||
IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags);
|
||||
return value_changed;
|
||||
}
|
||||
|
||||
|
|
|
@ -121,8 +121,8 @@ ID | macro
|
|||
33 | KSR
|
||||
---|-----------------------------
|
||||
40 | operator 2 macros
|
||||
60 | operator 2 macros
|
||||
80 | operator 2 macros
|
||||
60 | operator 3 macros
|
||||
80 | operator 4 macros
|
||||
|
||||
the interpretation of duty, wave and extra macros depends on chip/instrument type:
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ because the chip lacks sample interpolation, it is recommended that you try to p
|
|||
|
||||
the QSound chip also has a small echo buffer, somewhat similar to the SNES, although with a very basic (and non-adjustable) filter. it is however possible to adjust the feedback and length of the echo buffer (the initial values can be set in the "configure chip" option in the file menu or the chip manager).
|
||||
|
||||
there are also 3 ADPCM channels, however they cannot be used in Furnace yet. they have been reserved in case this feature is added later. ADPCM samples are limited to 8012 Hz.
|
||||
there are also 3 ADPCM channels. ADPCM samples are fixed to 8012 Hz.
|
||||
|
||||
# effects
|
||||
|
||||
|
|
|
@ -178,7 +178,7 @@ bool DivConfig::loadFromFile(const char* path, bool createOnFail, bool redundanc
|
|||
logD("config does not exist");
|
||||
if (createOnFail) {
|
||||
logI("creating default config.");
|
||||
reportError(fmt::sprintf("Creating default config: %s",strerror(errno)));
|
||||
//reportError(fmt::sprintf("Creating default config: %s",strerror(errno)));
|
||||
return save(path,redundancy);
|
||||
} else {
|
||||
reportError(fmt::sprintf("COULD NOT LOAD CONFIG %s",strerror(errno)));
|
||||
|
@ -191,7 +191,7 @@ bool DivConfig::loadFromFile(const char* path, bool createOnFail, bool redundanc
|
|||
logD("config does not exist");
|
||||
if (createOnFail) {
|
||||
logI("creating default config.");
|
||||
reportError(fmt::sprintf("Creating default config: %s",strerror(errno)));
|
||||
//reportError(fmt::sprintf("Creating default config: %s",strerror(errno)));
|
||||
return save(path);
|
||||
} else {
|
||||
reportError(fmt::sprintf("COULD NOT LOAD CONFIG %s",strerror(errno)));
|
||||
|
|
|
@ -55,6 +55,10 @@ const char* DivEngine::getEffectDesc(unsigned char effect, int chan, bool notNul
|
|||
return "03xx: Portamento";
|
||||
case 0x04:
|
||||
return "04xy: Vibrato (x: speed; y: depth)";
|
||||
case 0x05:
|
||||
return "05xy: Volume slide + vibrato (compatibility only!)";
|
||||
case 0x06:
|
||||
return "06xy: Volume slide + portamento (compatibility only!)";
|
||||
case 0x07:
|
||||
return "07xy: Tremolo (x: speed; y: depth)";
|
||||
case 0x08:
|
||||
|
@ -2419,6 +2423,13 @@ void DivEngine::stepOne(int row) {
|
|||
void DivEngine::stop() {
|
||||
BUSY_BEGIN;
|
||||
freelance=false;
|
||||
if (!playing) {
|
||||
//Send midi panic
|
||||
if (output) if (output->midiOut!=NULL) {
|
||||
output->midiOut->send(TAMidiMessage(TA_MIDI_CONTROL,0x7B,0));
|
||||
logV("Midi panic sent");
|
||||
}
|
||||
}
|
||||
playing=false;
|
||||
extValuePresent=false;
|
||||
endOfSong=false; // what?
|
||||
|
|
|
@ -105,7 +105,7 @@ struct DivChannelState {
|
|||
int delayOrder, delayRow, retrigSpeed, retrigTick;
|
||||
int vibratoDepth, vibratoRate, vibratoPos, vibratoPosGiant, vibratoDir, vibratoFine;
|
||||
int tremoloDepth, tremoloRate, tremoloPos;
|
||||
unsigned char arp, arpStage, arpTicks, panL, panR, panRL, panRR;
|
||||
unsigned char arp, arpStage, arpTicks, panL, panR, panRL, panRR, lastVibrato, lastPorta;
|
||||
bool doNote, legato, portaStop, keyOn, keyOff, nowYouCanStop, stopOnOff;
|
||||
bool arpYield, delayLocked, inPorta, scheduledSlideReset, shorthandPorta, wasShorthandPorta, noteOnInhibit, resetArp;
|
||||
bool wentThroughNote, goneThroughNote;
|
||||
|
@ -146,6 +146,8 @@ struct DivChannelState {
|
|||
panR(255),
|
||||
panRL(0),
|
||||
panRR(0),
|
||||
lastVibrato(0),
|
||||
lastPorta(0),
|
||||
doNote(false),
|
||||
legato(false),
|
||||
portaStop(false),
|
||||
|
|
|
@ -23,11 +23,7 @@
|
|||
static DivPattern emptyPat;
|
||||
|
||||
DivPattern::DivPattern() {
|
||||
memset(data,-1,DIV_MAX_ROWS*DIV_MAX_COLS*sizeof(short));
|
||||
for (int i=0; i<DIV_MAX_ROWS; i++) {
|
||||
data[i][0]=0;
|
||||
data[i][1]=0;
|
||||
}
|
||||
clear();
|
||||
}
|
||||
|
||||
DivPattern* DivChannelData::getPattern(int index, bool create) {
|
||||
|
@ -93,6 +89,14 @@ void DivPattern::copyOn(DivPattern* dest) {
|
|||
memcpy(dest->data,data,sizeof(data));
|
||||
}
|
||||
|
||||
void DivPattern::clear() {
|
||||
memset(data,-1,DIV_MAX_ROWS*DIV_MAX_COLS*sizeof(short));
|
||||
for (int i=0; i<DIV_MAX_ROWS; i++) {
|
||||
data[i][0]=0;
|
||||
data[i][1]=0;
|
||||
}
|
||||
}
|
||||
|
||||
DivChannelData::DivChannelData():
|
||||
effectCols(1) {
|
||||
memset(data,0,DIV_MAX_PATTERNS*sizeof(void*));
|
||||
|
|
|
@ -24,6 +24,11 @@ struct DivPattern {
|
|||
String name;
|
||||
short data[DIV_MAX_ROWS][DIV_MAX_COLS];
|
||||
|
||||
/**
|
||||
* clear the pattern.
|
||||
*/
|
||||
void clear();
|
||||
|
||||
/**
|
||||
* copy this pattern to another.
|
||||
* @param dest the destination pattern.
|
||||
|
|
|
@ -687,6 +687,7 @@ void DivPlatformAY8910::muteChannel(int ch, bool mute) {
|
|||
void DivPlatformAY8910::forceIns() {
|
||||
for (int i=0; i<3; i++) {
|
||||
chan[i].insChanged=true;
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
immWrite(0x0b,ayEnvPeriod);
|
||||
immWrite(0x0c,ayEnvPeriod>>8);
|
||||
|
|
|
@ -29,6 +29,7 @@ const char* regCheatSheetPV1000[]={
|
|||
"CH1_Pitch", "00",
|
||||
"CH2_Pitch", "01",
|
||||
"CH3_Pitch", "02",
|
||||
"Control", "03",
|
||||
NULL
|
||||
};
|
||||
|
||||
|
@ -38,11 +39,10 @@ const char** DivPlatformPV1000::getRegisterSheet() {
|
|||
|
||||
void DivPlatformPV1000::acquire(short** buf, size_t len) {
|
||||
for (size_t h=0; h<len; h++) {
|
||||
short samp;
|
||||
samp=d65010g031_sound_tick(&d65010g031,1);
|
||||
short samp=d65010g031_sound_tick(&d65010g031,1);
|
||||
buf[0][h]=samp;
|
||||
for (int i=0; i<3; i++) {
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=(d65010g031.square[i].out<<12);
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=(d65010g031.out[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -73,17 +73,17 @@ void DivPlatformPV1000::tick(bool sysTick) {
|
|||
}
|
||||
if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
|
||||
chan[i].freq=0x3f-parent->calcFreq(chan[i].baseFreq,chan[i].pitch,chan[i].fixedArp?chan[i].baseNoteOverride:chan[i].arpOff,chan[i].fixedArp,true,0,chan[i].pitch2,chipClock,CHIP_DIVIDER);
|
||||
if (chan[i].freq<1) chan[i].freq=1;
|
||||
if (chan[i].freq<0) chan[i].freq=0;
|
||||
if (chan[i].freq>62) chan[i].freq=62;
|
||||
if (isMuted[i]) chan[i].keyOn=false;
|
||||
if (chan[i].keyOn) {
|
||||
rWrite(i,(isMuted[i] || (chan[i].outVol<=0)) ? 0 : chan[i].freq);
|
||||
rWrite(i,(isMuted[i] || (chan[i].outVol<=0)) ? 0x3f : chan[i].freq);
|
||||
chan[i].keyOn=false;
|
||||
} else if (chan[i].freqChanged && chan[i].active && !isMuted[i]) {
|
||||
rWrite(i,(isMuted[i] || (chan[i].outVol<=0)) ? 0 : chan[i].freq);
|
||||
rWrite(i,(isMuted[i] || (chan[i].outVol<=0)) ? 0x3f : chan[i].freq);
|
||||
}
|
||||
if (chan[i].keyOff) {
|
||||
rWrite(i,0);
|
||||
rWrite(i,0x3f);
|
||||
chan[i].keyOff=false;
|
||||
}
|
||||
chan[i].freqChanged=false;
|
||||
|
@ -137,6 +137,13 @@ int DivPlatformPV1000::dispatch(DivCommand c) {
|
|||
chan[c.chan].pitch=c.value;
|
||||
chan[c.chan].freqChanged=true;
|
||||
break;
|
||||
case DIV_CMD_STD_NOISE_MODE: // ring modulation
|
||||
if (c.value&1) {
|
||||
rWrite(3,3);
|
||||
} else {
|
||||
rWrite(3,2);
|
||||
}
|
||||
break;
|
||||
case DIV_CMD_NOTE_PORTA: {
|
||||
int destFreq=NOTE_PERIODIC(c.value2);
|
||||
bool return2=false;
|
||||
|
@ -224,16 +231,21 @@ unsigned char* DivPlatformPV1000::getRegisterPool() {
|
|||
}
|
||||
|
||||
int DivPlatformPV1000::getRegisterPoolSize() {
|
||||
return 3;
|
||||
return 4;
|
||||
}
|
||||
|
||||
void DivPlatformPV1000::reset() {
|
||||
memset(regPool,0,3);
|
||||
memset(regPool,0,4);
|
||||
for (int i=0; i<3; i++) {
|
||||
chan[i]=Channel();
|
||||
chan[i].std.setEngine(parent);
|
||||
}
|
||||
d65010g031_reset(&d65010g031);
|
||||
// mute
|
||||
rWrite(0,0x3f);
|
||||
rWrite(1,0x3f);
|
||||
rWrite(2,0x3f);
|
||||
rWrite(3,2);
|
||||
}
|
||||
|
||||
int DivPlatformPV1000::getOutputCount() {
|
||||
|
|
|
@ -33,7 +33,7 @@ class DivPlatformPV1000: public DivDispatch {
|
|||
DivDispatchOscBuffer* oscBuf[3];
|
||||
bool isMuted[3];
|
||||
|
||||
unsigned char regPool[3];
|
||||
unsigned char regPool[4];
|
||||
d65010g031_t d65010g031;
|
||||
friend void putDispatchChip(void*,int);
|
||||
friend void putDispatchChan(void*,int,int);
|
||||
|
|
|
@ -67,7 +67,7 @@ int d65010g031_square_tick(struct d65010g031_square_t *square, const int cycle)
|
|||
{
|
||||
if (square->period > 0)
|
||||
{
|
||||
int period = d65010g031_max(1, (0x3f - square->period));
|
||||
const int period = square->period;
|
||||
square->counter += cycle;
|
||||
while (square->counter >= period)
|
||||
{
|
||||
|
@ -82,9 +82,9 @@ int d65010g031_square_tick(struct d65010g031_square_t *square, const int cycle)
|
|||
// this is the bit I altered
|
||||
// THIS IS **NOT** THE ORIGINAL SOFTWARE! I am plainly marking it as such!
|
||||
const int d65Volumes[3]={
|
||||
3840,
|
||||
5120,
|
||||
8192
|
||||
3840, // -6dB
|
||||
5120, // -3dB
|
||||
8192 // 0dB
|
||||
};
|
||||
|
||||
int d65010g031_sound_tick(struct d65010g031_t *d65010g031, const int cycle)
|
||||
|
@ -92,7 +92,29 @@ int d65010g031_sound_tick(struct d65010g031_t *d65010g031, const int cycle)
|
|||
int out = 0;
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
out += d65010g031_square_tick(&d65010g031->square[i], cycle)?d65Volumes[i]:-d65Volumes[i];
|
||||
d65010g031->out[i] = 0;
|
||||
}
|
||||
if (d65010g031->ctrl & 2)
|
||||
{
|
||||
if (d65010g031->ctrl & 1) // ring modulation
|
||||
{
|
||||
int sout[3] = {
|
||||
d65010g031_square_tick(&d65010g031->square[0], cycle),
|
||||
d65010g031_square_tick(&d65010g031->square[1], cycle),
|
||||
d65010g031_square_tick(&d65010g031->square[2], cycle),
|
||||
};
|
||||
d65010g031->out[0] = (sout[0] ^ sout[1]) ? d65Volumes[0] : -d65Volumes[0];
|
||||
d65010g031->out[1] = (sout[1] ^ sout[2]) ? d65Volumes[1] : -d65Volumes[1];
|
||||
d65010g031->out[2] = (sout[2] ? d65Volumes[2] : -d65Volumes[2]);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
d65010g031->out[i] = d65010g031_square_tick(&d65010g031->square[i], cycle)?d65Volumes[i]:-d65Volumes[i];
|
||||
}
|
||||
}
|
||||
out = d65010g031->out[0] + d65010g031->out[1] + d65010g031->out[2];
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
@ -105,12 +127,25 @@ void d65010g031_reset(struct d65010g031_t *d65010g031)
|
|||
d65010g031->square[i].counter = 0;
|
||||
d65010g031->square[i].out = 0;
|
||||
}
|
||||
d65010g031->ctrl = 0;
|
||||
}
|
||||
|
||||
void d65010g031_write(struct d65010g031_t *d65010g031, const unsigned char a, const unsigned char d)
|
||||
{
|
||||
if (a < 3)
|
||||
switch (a)
|
||||
{
|
||||
d65010g031->square[a].period = d & 0x3f;
|
||||
case 3:
|
||||
d65010g031->ctrl = d;
|
||||
break;
|
||||
default:
|
||||
{
|
||||
const unsigned char per = (unsigned char)(~d) & 0x3f;
|
||||
if ((per == 0) && (d65010g031->square[a].period != 0))
|
||||
{
|
||||
d65010g031->square[a].out ^= 1;
|
||||
}
|
||||
d65010g031->square[a].period = per;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -54,6 +54,8 @@ struct d65010g031_square_t
|
|||
struct d65010g031_t
|
||||
{
|
||||
struct d65010g031_square_t square[3];
|
||||
signed short out[3];
|
||||
unsigned char ctrl;
|
||||
};
|
||||
|
||||
int d65010g031_square_tick(struct d65010g031_square_t *square, const int cycle);
|
||||
|
|
|
@ -680,6 +680,7 @@ void DivEngine::processRow(int i, bool afterDelay) {
|
|||
chan[i].inPorta=false;
|
||||
dispatchCmd(DivCommand(DIV_CMD_PRE_PORTA,i,false,0));
|
||||
} else {
|
||||
chan[i].lastPorta=effectVal;
|
||||
calledPorta=true;
|
||||
if (chan[i].note==chan[i].oldNote && !chan[i].inPorta && song.buggyPortaAfterSlide) {
|
||||
chan[i].portaNote=chan[i].note;
|
||||
|
@ -700,11 +701,78 @@ void DivEngine::processRow(int i, bool afterDelay) {
|
|||
}
|
||||
break;
|
||||
case 0x04: // vibrato
|
||||
if (effectVal) chan[i].lastVibrato=effectVal;
|
||||
chan[i].vibratoDepth=effectVal&15;
|
||||
chan[i].vibratoRate=effectVal>>4;
|
||||
dispatchCmd(DivCommand(DIV_CMD_HINT_VIBRATO,i,chan[i].vibratoDepth,chan[i].vibratoRate));
|
||||
dispatchCmd(DivCommand(DIV_CMD_PITCH,i,chan[i].pitch+(((chan[i].vibratoDepth*vibTable[chan[i].vibratoPos]*chan[i].vibratoFine)>>4)/15)));
|
||||
break;
|
||||
case 0x05: // vol slide + vibrato
|
||||
if (effectVal==0) {
|
||||
chan[i].vibratoDepth=0;
|
||||
chan[i].vibratoRate=0;
|
||||
} else {
|
||||
chan[i].vibratoDepth=chan[i].lastVibrato&15;
|
||||
chan[i].vibratoRate=chan[i].lastVibrato>>4;
|
||||
}
|
||||
dispatchCmd(DivCommand(DIV_CMD_HINT_VIBRATO,i,chan[i].vibratoDepth,chan[i].vibratoRate));
|
||||
dispatchCmd(DivCommand(DIV_CMD_PITCH,i,chan[i].pitch+(((chan[i].vibratoDepth*vibTable[chan[i].vibratoPos]*chan[i].vibratoFine)>>4)/15)));
|
||||
// TODO: non-0x-or-x0 value should be treated as 00
|
||||
if (effectVal!=0) {
|
||||
if ((effectVal&15)!=0) {
|
||||
chan[i].volSpeed=-(effectVal&15)*64;
|
||||
} else {
|
||||
chan[i].volSpeed=(effectVal>>4)*64;
|
||||
}
|
||||
// tremolo and vol slides are incompatible
|
||||
chan[i].tremoloDepth=0;
|
||||
chan[i].tremoloRate=0;
|
||||
} else {
|
||||
chan[i].volSpeed=0;
|
||||
}
|
||||
dispatchCmd(DivCommand(DIV_CMD_HINT_VOL_SLIDE,i,chan[i].volSpeed));
|
||||
break;
|
||||
case 0x06: // vol slide + porta
|
||||
if (effectVal==0 || chan[i].lastPorta==0) {
|
||||
chan[i].portaNote=-1;
|
||||
chan[i].portaSpeed=-1;
|
||||
dispatchCmd(DivCommand(DIV_CMD_HINT_PORTA,i,CLAMP(chan[i].portaNote,-128,127),MAX(chan[i].portaSpeed,0)));
|
||||
chan[i].inPorta=false;
|
||||
dispatchCmd(DivCommand(DIV_CMD_PRE_PORTA,i,false,0));
|
||||
} else {
|
||||
calledPorta=true;
|
||||
if (chan[i].note==chan[i].oldNote && !chan[i].inPorta && song.buggyPortaAfterSlide) {
|
||||
chan[i].portaNote=chan[i].note;
|
||||
chan[i].portaSpeed=-1;
|
||||
} else {
|
||||
chan[i].portaNote=chan[i].note;
|
||||
chan[i].portaSpeed=chan[i].lastPorta;
|
||||
chan[i].inPorta=true;
|
||||
chan[i].wasShorthandPorta=false;
|
||||
}
|
||||
dispatchCmd(DivCommand(DIV_CMD_HINT_PORTA,i,CLAMP(chan[i].portaNote,-128,127),MAX(chan[i].portaSpeed,0)));
|
||||
chan[i].portaStop=true;
|
||||
if (chan[i].keyOn) chan[i].doNote=false;
|
||||
chan[i].stopOnOff=song.stopPortaOnNoteOff; // what?!
|
||||
chan[i].scheduledSlideReset=false;
|
||||
dispatchCmd(DivCommand(DIV_CMD_PRE_PORTA,i,true,1));
|
||||
lastSlide=0x1337; // i hate this so much
|
||||
}
|
||||
// TODO: non-0x-or-x0 value should be treated as 00
|
||||
if (effectVal!=0) {
|
||||
if ((effectVal&15)!=0) {
|
||||
chan[i].volSpeed=-(effectVal&15)*64;
|
||||
} else {
|
||||
chan[i].volSpeed=(effectVal>>4)*64;
|
||||
}
|
||||
// tremolo and vol slides are incompatible
|
||||
chan[i].tremoloDepth=0;
|
||||
chan[i].tremoloRate=0;
|
||||
} else {
|
||||
chan[i].volSpeed=0;
|
||||
}
|
||||
dispatchCmd(DivCommand(DIV_CMD_HINT_VOL_SLIDE,i,chan[i].volSpeed));
|
||||
break;
|
||||
case 0x07: // tremolo
|
||||
// TODO
|
||||
// this effect is really weird. i thought it would alter the tremolo depth but turns out it's completely different
|
||||
|
@ -1148,6 +1216,10 @@ void DivEngine::nextRow() {
|
|||
doPrepareCut=false;
|
||||
break;
|
||||
}
|
||||
if (pat->data[curRow][4+(j<<1)]==0x06) {
|
||||
doPrepareCut=false;
|
||||
break;
|
||||
}
|
||||
if (pat->data[curRow][4+(j<<1)]==0xea) {
|
||||
if (pat->data[curRow][5+(j<<1)]>0) {
|
||||
doPrepareCut=false;
|
||||
|
|
|
@ -892,10 +892,10 @@ bool DivSample::resampleBlep(double r) {
|
|||
}
|
||||
}
|
||||
for (int i=0; i<finalCount; i++) {
|
||||
float result=floatData[i]+data16[i];
|
||||
float result=floatData[i]+data8[i];
|
||||
if (result<-128) result=-128;
|
||||
if (result>127) result=127;
|
||||
data16[i]=round(result);
|
||||
data8[i]=round(result);
|
||||
}
|
||||
}
|
||||
delete[] floatData;
|
||||
|
|
|
@ -1839,7 +1839,11 @@ void DivEngine::registerSystems() {
|
|||
{"Square 1", "Square 2", "Square 3"},
|
||||
{"S1", "S2", "S3"},
|
||||
{DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE},
|
||||
{DIV_INS_PV1000, DIV_INS_PV1000, DIV_INS_PV1000}
|
||||
{DIV_INS_PV1000, DIV_INS_PV1000, DIV_INS_PV1000},
|
||||
{},
|
||||
{
|
||||
{0x10, {DIV_CMD_STD_NOISE_MODE, "10xx: Set ring modulation (0: disable, 1: enable)"}}
|
||||
}
|
||||
);
|
||||
|
||||
sysDefs[DIV_SYSTEM_SFX_BEEPER_QUADTONE]=new DivSysDef(
|
||||
|
|
|
@ -1068,6 +1068,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
|
|||
|
||||
bool trailing=false;
|
||||
bool beenOneLoopAlready=false;
|
||||
bool mayWriteRate=(fmod(curSubSong->hz,1.0)<0.00001 || fmod(curSubSong->hz,1.0)>0.99999);
|
||||
int countDown=MAX(0,trailingTicks)+1;
|
||||
|
||||
for (int i=0; i<DIV_MAX_CHANS; i++) {
|
||||
|
@ -2359,6 +2360,9 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
|
|||
w->writeI(0);
|
||||
w->writeI(0);
|
||||
}
|
||||
if (mayWriteRate) {
|
||||
w->writeI(round(curSubSong->hz));
|
||||
}
|
||||
w->seek(0x34,SEEK_SET);
|
||||
w->writeI(songOff-0x34);
|
||||
if (version>=0x170) {
|
||||
|
|
|
@ -561,18 +561,32 @@ void FurnaceGUI::doAction(int what) {
|
|||
doFlip();
|
||||
break;
|
||||
case GUI_ACTION_PAT_COLLAPSE_ROWS:
|
||||
doCollapse(2);
|
||||
doCollapse(2,selStart,selEnd);
|
||||
break;
|
||||
case GUI_ACTION_PAT_EXPAND_ROWS:
|
||||
doExpand(2);
|
||||
doExpand(2,selStart,selEnd);
|
||||
break;
|
||||
case GUI_ACTION_PAT_COLLAPSE_PAT: // TODO
|
||||
case GUI_ACTION_PAT_COLLAPSE_PAT: {
|
||||
SelectionPoint selEndPat;
|
||||
selEndPat.xCoarse=e->getTotalChannelCount()-1;
|
||||
selEndPat.xFine=2+e->curPat[selEndPat.xCoarse].effectCols*2;
|
||||
selEndPat.y=e->curSubSong->patLen-1;
|
||||
doCollapse(2,SelectionPoint(0,0,0),selEndPat);
|
||||
break;
|
||||
case GUI_ACTION_PAT_EXPAND_PAT: // TODO
|
||||
}
|
||||
case GUI_ACTION_PAT_EXPAND_PAT: {
|
||||
SelectionPoint selEndPat;
|
||||
selEndPat.xCoarse=e->getTotalChannelCount()-1;
|
||||
selEndPat.xFine=2+e->curPat[selEndPat.xCoarse].effectCols*2;
|
||||
selEndPat.y=e->curSubSong->patLen-1;
|
||||
doExpand(2,SelectionPoint(0,0,0),selEndPat);
|
||||
break;
|
||||
case GUI_ACTION_PAT_COLLAPSE_SONG: // TODO
|
||||
}
|
||||
case GUI_ACTION_PAT_COLLAPSE_SONG:
|
||||
doCollapseSong(2);
|
||||
break;
|
||||
case GUI_ACTION_PAT_EXPAND_SONG: // TODO
|
||||
case GUI_ACTION_PAT_EXPAND_SONG:
|
||||
doExpandSong(2);
|
||||
break;
|
||||
case GUI_ACTION_PAT_LATCH: // TODO
|
||||
break;
|
||||
|
|
|
@ -67,6 +67,9 @@ void FurnaceGUI::prepareUndo(ActionType action) {
|
|||
e->curPat[i].getPattern(e->curOrders->ord[i][curOrder],false)->copyOn(oldPat[i]);
|
||||
}
|
||||
break;
|
||||
case GUI_UNDO_PATTERN_COLLAPSE_SONG:
|
||||
case GUI_UNDO_PATTERN_EXPAND_SONG: // TODO
|
||||
break;
|
||||
case GUI_UNDO_REPLACE: // this is handled by doReplace()
|
||||
break;
|
||||
}
|
||||
|
@ -130,6 +133,9 @@ void FurnaceGUI::makeUndo(ActionType action) {
|
|||
doPush=true;
|
||||
}
|
||||
break;
|
||||
case GUI_UNDO_PATTERN_COLLAPSE_SONG:
|
||||
case GUI_UNDO_PATTERN_EXPAND_SONG: // TODO
|
||||
break;
|
||||
case GUI_UNDO_REPLACE: // this is handled by doReplace()
|
||||
break;
|
||||
}
|
||||
|
@ -839,50 +845,56 @@ void FurnaceGUI::doFlip() {
|
|||
makeUndo(GUI_UNDO_PATTERN_FLIP);
|
||||
}
|
||||
|
||||
void FurnaceGUI::doCollapse(int divider) {
|
||||
void FurnaceGUI::doCollapse(int divider, const SelectionPoint& sStart, const SelectionPoint& sEnd) {
|
||||
if (divider<2) return;
|
||||
if (e->curSubSong->patLen<divider) {
|
||||
showError("can't collapse any further!");
|
||||
return;
|
||||
}
|
||||
|
||||
finishSelection();
|
||||
prepareUndo(GUI_UNDO_PATTERN_COLLAPSE);
|
||||
|
||||
DivPattern patBuffer;
|
||||
int iCoarse=selStart.xCoarse;
|
||||
int iFine=selStart.xFine;
|
||||
for (; iCoarse<=selEnd.xCoarse; iCoarse++) {
|
||||
int iCoarse=sStart.xCoarse;
|
||||
int iFine=sStart.xFine;
|
||||
for (; iCoarse<=sEnd.xCoarse; iCoarse++) {
|
||||
if (!e->curSubSong->chanShow[iCoarse]) continue;
|
||||
DivPattern* pat=e->curPat[iCoarse].getPattern(e->curOrders->ord[iCoarse][curOrder],true);
|
||||
for (; iFine<3+e->curPat[iCoarse].effectCols*2 && (iCoarse<selEnd.xCoarse || iFine<=selEnd.xFine); iFine++) {
|
||||
for (; iFine<3+e->curPat[iCoarse].effectCols*2 && (iCoarse<sEnd.xCoarse || iFine<=sEnd.xFine); iFine++) {
|
||||
maskOut(opMaskCollapseExpand,iFine);
|
||||
for (int j=selStart.y; j<=selEnd.y; j++) {
|
||||
for (int j=sStart.y; j<=sEnd.y; j++) {
|
||||
if (iFine==0) {
|
||||
patBuffer.data[j][0]=pat->data[j][0];
|
||||
}
|
||||
patBuffer.data[j][iFine+1]=pat->data[j][iFine+1];
|
||||
}
|
||||
for (int j=0; j<=selEnd.y-selStart.y; j++) {
|
||||
if (j*divider>=selEnd.y-selStart.y) {
|
||||
for (int j=0; j<=sEnd.y-sStart.y; j++) {
|
||||
if (j*divider>=sEnd.y-sStart.y) {
|
||||
if (iFine==0) {
|
||||
pat->data[j+selStart.y][0]=0;
|
||||
pat->data[j+selStart.y][1]=0;
|
||||
pat->data[j+sStart.y][0]=0;
|
||||
pat->data[j+sStart.y][1]=0;
|
||||
} else {
|
||||
pat->data[j+selStart.y][iFine+1]=-1;
|
||||
pat->data[j+sStart.y][iFine+1]=-1;
|
||||
}
|
||||
} else {
|
||||
if (iFine==0) {
|
||||
pat->data[j+selStart.y][0]=patBuffer.data[j*divider+selStart.y][0];
|
||||
pat->data[j+sStart.y][0]=patBuffer.data[j*divider+sStart.y][0];
|
||||
}
|
||||
pat->data[j+selStart.y][iFine+1]=patBuffer.data[j*divider+selStart.y][iFine+1];
|
||||
pat->data[j+sStart.y][iFine+1]=patBuffer.data[j*divider+sStart.y][iFine+1];
|
||||
|
||||
if (iFine==0) {
|
||||
for (int k=1; k<divider; k++) {
|
||||
if ((j*divider+k)>=selEnd.y-selStart.y) break;
|
||||
if (!(pat->data[j+selStart.y][0]==0 && pat->data[j+selStart.y][1]==0)) break;
|
||||
pat->data[j+selStart.y][0]=patBuffer.data[j*divider+selStart.y+k][0];
|
||||
pat->data[j+selStart.y][1]=patBuffer.data[j*divider+selStart.y+k][1];
|
||||
if ((j*divider+k)>=sEnd.y-sStart.y) break;
|
||||
if (!(pat->data[j+sStart.y][0]==0 && pat->data[j+sStart.y][1]==0)) break;
|
||||
pat->data[j+sStart.y][0]=patBuffer.data[j*divider+sStart.y+k][0];
|
||||
pat->data[j+sStart.y][1]=patBuffer.data[j*divider+sStart.y+k][1];
|
||||
}
|
||||
} else {
|
||||
for (int k=1; k<divider; k++) {
|
||||
if ((j*divider+k)>=selEnd.y-selStart.y) break;
|
||||
if (pat->data[j+selStart.y][iFine+1]!=-1) break;
|
||||
pat->data[j+selStart.y][iFine+1]=patBuffer.data[j*divider+selStart.y+k][iFine+1];
|
||||
if ((j*divider+k)>=sEnd.y-sStart.y) break;
|
||||
if (pat->data[j+sStart.y][iFine+1]!=-1) break;
|
||||
pat->data[j+sStart.y][iFine+1]=patBuffer.data[j*divider+sStart.y+k][iFine+1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -894,41 +906,41 @@ void FurnaceGUI::doCollapse(int divider) {
|
|||
makeUndo(GUI_UNDO_PATTERN_COLLAPSE);
|
||||
}
|
||||
|
||||
void FurnaceGUI::doExpand(int multiplier) {
|
||||
if (multiplier<1) return;
|
||||
void FurnaceGUI::doExpand(int multiplier, const SelectionPoint& sStart, const SelectionPoint& sEnd) {
|
||||
if (multiplier<2) return;
|
||||
|
||||
finishSelection();
|
||||
prepareUndo(GUI_UNDO_PATTERN_EXPAND);
|
||||
|
||||
DivPattern patBuffer;
|
||||
int iCoarse=selStart.xCoarse;
|
||||
int iFine=selStart.xFine;
|
||||
for (; iCoarse<=selEnd.xCoarse; iCoarse++) {
|
||||
int iCoarse=sStart.xCoarse;
|
||||
int iFine=sStart.xFine;
|
||||
for (; iCoarse<=sEnd.xCoarse; iCoarse++) {
|
||||
if (!e->curSubSong->chanShow[iCoarse]) continue;
|
||||
DivPattern* pat=e->curPat[iCoarse].getPattern(e->curOrders->ord[iCoarse][curOrder],true);
|
||||
for (; iFine<3+e->curPat[iCoarse].effectCols*2 && (iCoarse<selEnd.xCoarse || iFine<=selEnd.xFine); iFine++) {
|
||||
for (; iFine<3+e->curPat[iCoarse].effectCols*2 && (iCoarse<sEnd.xCoarse || iFine<=sEnd.xFine); iFine++) {
|
||||
maskOut(opMaskCollapseExpand,iFine);
|
||||
for (int j=selStart.y; j<=selEnd.y; j++) {
|
||||
for (int j=sStart.y; j<=sEnd.y; j++) {
|
||||
if (iFine==0) {
|
||||
patBuffer.data[j][0]=pat->data[j][0];
|
||||
}
|
||||
patBuffer.data[j][iFine+1]=pat->data[j][iFine+1];
|
||||
}
|
||||
for (int j=0; j<=(selEnd.y-selStart.y)*multiplier; j++) {
|
||||
if ((j+selStart.y)>=e->curSubSong->patLen) break;
|
||||
for (int j=0; j<=(sEnd.y-sStart.y)*multiplier; j++) {
|
||||
if ((j+sStart.y)>=e->curSubSong->patLen) break;
|
||||
if ((j%multiplier)!=0) {
|
||||
if (iFine==0) {
|
||||
pat->data[j+selStart.y][0]=0;
|
||||
pat->data[j+selStart.y][1]=0;
|
||||
pat->data[j+sStart.y][0]=0;
|
||||
pat->data[j+sStart.y][1]=0;
|
||||
} else {
|
||||
pat->data[j+selStart.y][iFine+1]=-1;
|
||||
pat->data[j+sStart.y][iFine+1]=-1;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (iFine==0) {
|
||||
pat->data[j+selStart.y][0]=patBuffer.data[j/multiplier+selStart.y][0];
|
||||
pat->data[j+sStart.y][0]=patBuffer.data[j/multiplier+sStart.y][0];
|
||||
}
|
||||
pat->data[j+selStart.y][iFine+1]=patBuffer.data[j/multiplier+selStart.y][iFine+1];
|
||||
pat->data[j+sStart.y][iFine+1]=patBuffer.data[j/multiplier+sStart.y][iFine+1];
|
||||
}
|
||||
}
|
||||
iFine=0;
|
||||
|
@ -937,6 +949,162 @@ void FurnaceGUI::doExpand(int multiplier) {
|
|||
makeUndo(GUI_UNDO_PATTERN_EXPAND);
|
||||
}
|
||||
|
||||
void FurnaceGUI::doCollapseSong(int divider) {
|
||||
if (divider<2) return;
|
||||
finishSelection();
|
||||
|
||||
UndoStep us;
|
||||
us.type=GUI_UNDO_PATTERN_COLLAPSE_SONG;
|
||||
|
||||
DivPattern patCopy;
|
||||
|
||||
size_t subSong=e->getCurrentSubSong();
|
||||
for (int i=0; i<e->getTotalChannelCount(); i++) {
|
||||
for (int j=0; j<DIV_MAX_PATTERNS; j++) {
|
||||
if (e->curPat[i].data[j]==NULL) continue;
|
||||
|
||||
DivPattern* pat=e->curPat[i].getPattern(j,true);
|
||||
pat->copyOn(&patCopy);
|
||||
pat->clear();
|
||||
for (int k=0; k<DIV_MAX_ROWS; k++) {
|
||||
for (int l=0; l<DIV_MAX_COLS; l++) {
|
||||
if (l==0) {
|
||||
if (!(pat->data[k/divider][0]==0 && pat->data[k/divider][1]==0)) continue;
|
||||
} else {
|
||||
if (pat->data[k/divider][l+1]!=-1) continue;
|
||||
}
|
||||
|
||||
if (l==0) {
|
||||
pat->data[k/divider][l]=patCopy.data[k][l];
|
||||
}
|
||||
pat->data[k/divider][l+1]=patCopy.data[k][l+1];
|
||||
|
||||
if (l>3 && !(l&1)) { // scale effects as needed
|
||||
switch (pat->data[k/divider][l]) {
|
||||
case 0x0d:
|
||||
pat->data[k/divider][l+1]/=divider;
|
||||
break;
|
||||
case 0x0f:
|
||||
pat->data[k/divider][l+1]=CLAMP(pat->data[k/divider][l+1]*divider,1,255);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// put undo
|
||||
for (int k=0; k<DIV_MAX_ROWS; k++) {
|
||||
for (int l=0; l<DIV_MAX_COLS; l++) {
|
||||
if (pat->data[k][l]!=patCopy.data[k][l]) {
|
||||
us.pat.push_back(UndoPatternData(subSong,i,j,k,l,patCopy.data[k][l],pat->data[k][l]));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// magic
|
||||
unsigned char* subSongInfoCopy=new unsigned char[1024];
|
||||
memcpy(subSongInfoCopy,e->curSubSong,1024);
|
||||
e->curSubSong->patLen/=divider;
|
||||
for (int i=0; i<e->curSubSong->speeds.len; i++) {
|
||||
e->curSubSong->speeds.val[i]=CLAMP(e->curSubSong->speeds.val[i]*divider,1,255);
|
||||
}
|
||||
unsigned char* newSubSongInfo=(unsigned char*)e->curSubSong;
|
||||
for (int i=0; i<1024; i++) {
|
||||
if (subSongInfoCopy[i]!=newSubSongInfo[i]) {
|
||||
us.other.push_back(UndoOtherData(GUI_UNDO_TARGET_SUBSONG,subSong,i,subSongInfoCopy[i],newSubSongInfo[i]));
|
||||
}
|
||||
}
|
||||
|
||||
if (!us.pat.empty()) {
|
||||
undoHist.push_back(us);
|
||||
redoHist.clear();
|
||||
if (undoHist.size()>settings.maxUndoSteps) undoHist.pop_front();
|
||||
}
|
||||
|
||||
if (e->isPlaying()) e->play();
|
||||
}
|
||||
|
||||
void FurnaceGUI::doExpandSong(int multiplier) {
|
||||
if (multiplier<2) return;
|
||||
if (e->curSubSong->patLen>(256/multiplier)) {
|
||||
showError("can't expand any further!");
|
||||
return;
|
||||
}
|
||||
finishSelection();
|
||||
|
||||
UndoStep us;
|
||||
us.type=GUI_UNDO_PATTERN_EXPAND_SONG;
|
||||
|
||||
DivPattern patCopy;
|
||||
|
||||
size_t subSong=e->getCurrentSubSong();
|
||||
for (int i=0; i<e->getTotalChannelCount(); i++) {
|
||||
for (int j=0; j<DIV_MAX_PATTERNS; j++) {
|
||||
if (e->curPat[i].data[j]==NULL) continue;
|
||||
|
||||
DivPattern* pat=e->curPat[i].getPattern(j,true);
|
||||
pat->copyOn(&patCopy);
|
||||
pat->clear();
|
||||
for (int k=0; k<(256/multiplier); k++) {
|
||||
for (int l=0; l<DIV_MAX_COLS; l++) {
|
||||
if (l==0) {
|
||||
if (!(pat->data[k*multiplier][0]==0 && pat->data[k*multiplier][1]==0)) continue;
|
||||
} else {
|
||||
if (pat->data[k*multiplier][l+1]!=-1) continue;
|
||||
}
|
||||
|
||||
if (l==0) {
|
||||
pat->data[k*multiplier][l]=patCopy.data[k][l];
|
||||
}
|
||||
pat->data[k*multiplier][l+1]=patCopy.data[k][l+1];
|
||||
|
||||
if (l>3 && !(l&1)) { // scale effects as needed
|
||||
switch (pat->data[k*multiplier][l]) {
|
||||
case 0x0d:
|
||||
pat->data[k*multiplier][l+1]/=multiplier;
|
||||
break;
|
||||
case 0x0f:
|
||||
pat->data[k*multiplier][l+1]=CLAMP(pat->data[k*multiplier][l+1]/multiplier,1,255);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// put undo
|
||||
for (int k=0; k<DIV_MAX_ROWS; k++) {
|
||||
for (int l=0; l<DIV_MAX_COLS; l++) {
|
||||
if (pat->data[k][l]!=patCopy.data[k][l]) {
|
||||
us.pat.push_back(UndoPatternData(subSong,i,j,k,l,patCopy.data[k][l],pat->data[k][l]));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// magic
|
||||
unsigned char* subSongInfoCopy=new unsigned char[1024];
|
||||
memcpy(subSongInfoCopy,e->curSubSong,1024);
|
||||
e->curSubSong->patLen*=multiplier;
|
||||
for (int i=0; i<e->curSubSong->speeds.len; i++) {
|
||||
e->curSubSong->speeds.val[i]=CLAMP(e->curSubSong->speeds.val[i]/multiplier,1,255);
|
||||
}
|
||||
unsigned char* newSubSongInfo=(unsigned char*)e->curSubSong;
|
||||
for (int i=0; i<1024; i++) {
|
||||
if (subSongInfoCopy[i]!=newSubSongInfo[i]) {
|
||||
us.other.push_back(UndoOtherData(GUI_UNDO_TARGET_SUBSONG,subSong,i,subSongInfoCopy[i],newSubSongInfo[i]));
|
||||
}
|
||||
}
|
||||
|
||||
if (!us.pat.empty()) {
|
||||
undoHist.push_back(us);
|
||||
redoHist.clear();
|
||||
if (undoHist.size()>settings.maxUndoSteps) undoHist.pop_front();
|
||||
}
|
||||
|
||||
if (e->isPlaying()) e->play();
|
||||
}
|
||||
|
||||
void FurnaceGUI::doDrag() {
|
||||
int len=dragEnd.xCoarse-dragStart.xCoarse+1;
|
||||
|
||||
|
@ -985,6 +1153,8 @@ void FurnaceGUI::doUndo() {
|
|||
case GUI_UNDO_PATTERN_FLIP:
|
||||
case GUI_UNDO_PATTERN_COLLAPSE:
|
||||
case GUI_UNDO_PATTERN_EXPAND:
|
||||
case GUI_UNDO_PATTERN_COLLAPSE_SONG:
|
||||
case GUI_UNDO_PATTERN_EXPAND_SONG:
|
||||
case GUI_UNDO_PATTERN_DRAG:
|
||||
case GUI_UNDO_REPLACE:
|
||||
for (UndoPatternData& i: us.pat) {
|
||||
|
@ -1005,6 +1175,22 @@ void FurnaceGUI::doUndo() {
|
|||
break;
|
||||
}
|
||||
|
||||
bool shallReplay=false;
|
||||
for (UndoOtherData& i: us.other) {
|
||||
switch (i.target) {
|
||||
case GUI_UNDO_TARGET_SONG:
|
||||
((unsigned char*)(&e->song))[i.off]=i.oldVal;
|
||||
shallReplay=true;
|
||||
break;
|
||||
case GUI_UNDO_TARGET_SUBSONG:
|
||||
if (i.subtarget<0 || i.subtarget>=(int)e->song.subsong.size()) break;
|
||||
((unsigned char*)(e->song.subsong[i.subtarget]))[i.off]=i.oldVal;
|
||||
shallReplay=true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (shallReplay && e->isPlaying()) play();
|
||||
|
||||
if (curOrder>=e->curSubSong->ordersLen) {
|
||||
curOrder=e->curSubSong->ordersLen-1;
|
||||
oldOrder=curOrder;
|
||||
|
@ -1045,6 +1231,8 @@ void FurnaceGUI::doRedo() {
|
|||
case GUI_UNDO_PATTERN_COLLAPSE:
|
||||
case GUI_UNDO_PATTERN_EXPAND:
|
||||
case GUI_UNDO_PATTERN_DRAG:
|
||||
case GUI_UNDO_PATTERN_COLLAPSE_SONG:
|
||||
case GUI_UNDO_PATTERN_EXPAND_SONG:
|
||||
case GUI_UNDO_REPLACE:
|
||||
for (UndoPatternData& i: us.pat) {
|
||||
e->changeSongP(i.subSong);
|
||||
|
@ -1065,6 +1253,22 @@ void FurnaceGUI::doRedo() {
|
|||
break;
|
||||
}
|
||||
|
||||
bool shallReplay=false;
|
||||
for (UndoOtherData& i: us.other) {
|
||||
switch (i.target) {
|
||||
case GUI_UNDO_TARGET_SONG:
|
||||
((unsigned char*)(&e->song))[i.off]=i.newVal;
|
||||
shallReplay=true;
|
||||
break;
|
||||
case GUI_UNDO_TARGET_SUBSONG:
|
||||
if (i.subtarget<0 || i.subtarget>=(int)e->song.subsong.size()) break;
|
||||
((unsigned char*)(e->song.subsong[i.subtarget]))[i.off]=i.newVal;
|
||||
shallReplay=true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (shallReplay && e->isPlaying()) play();
|
||||
|
||||
if (curOrder>=e->curSubSong->ordersLen) {
|
||||
curOrder=e->curSubSong->ordersLen-1;
|
||||
oldOrder=curOrder;
|
||||
|
|
|
@ -2842,9 +2842,23 @@ void FurnaceGUI::editOptions(bool topMenu) {
|
|||
ImGui::Separator();
|
||||
|
||||
if (ImGui::MenuItem("flip selection",BIND_FOR(GUI_ACTION_PAT_FLIP_SELECTION))) doFlip();
|
||||
if (ImGui::MenuItem("collapse",BIND_FOR(GUI_ACTION_PAT_COLLAPSE_ROWS))) doCollapse(2);
|
||||
if (ImGui::MenuItem("expand",BIND_FOR(GUI_ACTION_PAT_EXPAND_ROWS))) doExpand(2);
|
||||
if (ImGui::MenuItem("collapse",BIND_FOR(GUI_ACTION_PAT_COLLAPSE_ROWS))) doCollapse(2,selStart,selEnd);
|
||||
if (ImGui::MenuItem("expand",BIND_FOR(GUI_ACTION_PAT_EXPAND_ROWS))) doExpand(2,selStart,selEnd);
|
||||
|
||||
if (topMenu) {
|
||||
ImGui::Separator();
|
||||
if (ImGui::MenuItem("collapse pattern",BIND_FOR(GUI_ACTION_PAT_COLLAPSE_PAT))) doAction(GUI_ACTION_PAT_COLLAPSE_PAT);
|
||||
if (ImGui::MenuItem("expand pattern",BIND_FOR(GUI_ACTION_PAT_EXPAND_PAT))) doAction(GUI_ACTION_PAT_EXPAND_PAT);
|
||||
}
|
||||
}
|
||||
|
||||
if (topMenu) {
|
||||
ImGui::Separator();
|
||||
if (ImGui::MenuItem("collapse song",BIND_FOR(GUI_ACTION_PAT_COLLAPSE_SONG))) doAction(GUI_ACTION_PAT_COLLAPSE_SONG);
|
||||
if (ImGui::MenuItem("expand song",BIND_FOR(GUI_ACTION_PAT_EXPAND_SONG))) doAction(GUI_ACTION_PAT_EXPAND_SONG);
|
||||
}
|
||||
|
||||
if (!basicMode) {
|
||||
if (topMenu) {
|
||||
ImGui::Separator();
|
||||
if (ImGui::MenuItem("find/replace",BIND_FOR(GUI_ACTION_WINDOW_FIND),findOpen)) {
|
||||
|
@ -2856,16 +2870,6 @@ void FurnaceGUI::editOptions(bool topMenu) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*if (topMenu) {
|
||||
ImGui::Separator();
|
||||
ImGui::MenuItem("collapse pattern",BIND_FOR(GUI_ACTION_PAT_COLLAPSE_PAT));
|
||||
ImGui::MenuItem("expand pattern",BIND_FOR(GUI_ACTION_PAT_EXPAND_PAT));
|
||||
|
||||
ImGui::Separator();
|
||||
ImGui::MenuItem("collapse song",BIND_FOR(GUI_ACTION_PAT_COLLAPSE_SONG));
|
||||
ImGui::MenuItem("expand song",BIND_FOR(GUI_ACTION_PAT_EXPAND_SONG));
|
||||
}*/
|
||||
}
|
||||
|
||||
void FurnaceGUI::toggleMobileUI(bool enable, bool force) {
|
||||
|
@ -3245,18 +3249,18 @@ void FurnaceGUI::pointMotion(int x, int y, int xrel, int yrel) {
|
|||
// how many pixels should be visible at least at x/y dir
|
||||
#define OOB_PIXELS_SAFETY 25
|
||||
|
||||
bool FurnaceGUI::detectOutOfBoundsWindow() {
|
||||
bool FurnaceGUI::detectOutOfBoundsWindow(SDL_Rect& failing) {
|
||||
int count=SDL_GetNumVideoDisplays();
|
||||
if (count<1) {
|
||||
logW("bounds check: error %s",SDL_GetError());
|
||||
logW("bounds check: error: %s",SDL_GetError());
|
||||
return false;
|
||||
}
|
||||
|
||||
SDL_Rect rect;
|
||||
for (int i=0; i<count; i++) {
|
||||
if (SDL_GetDisplayUsableBounds(i,&rect)!=0) {
|
||||
logW("bounds check: error %s",SDL_GetError());
|
||||
return false;
|
||||
logW("bounds check: error in display %d: %s",i,SDL_GetError());
|
||||
continue;
|
||||
}
|
||||
|
||||
bool xbound=((rect.x+OOB_PIXELS_SAFETY)<=(scrX+scrW)) && ((rect.x+rect.w-OOB_PIXELS_SAFETY)>=scrX);
|
||||
|
@ -3268,6 +3272,7 @@ bool FurnaceGUI::detectOutOfBoundsWindow() {
|
|||
}
|
||||
}
|
||||
|
||||
failing=rect;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -6003,10 +6008,23 @@ bool FurnaceGUI::init() {
|
|||
|
||||
#ifndef IS_MOBILE
|
||||
// if window would spawn out of bounds, force it to be get default position
|
||||
if (!detectOutOfBoundsWindow()) {
|
||||
SDL_Rect bounds;
|
||||
if (!detectOutOfBoundsWindow(bounds)) {
|
||||
scrMax=false;
|
||||
scrX=scrConfX=SDL_WINDOWPOS_CENTERED;
|
||||
scrY=scrConfY=SDL_WINDOWPOS_CENTERED;
|
||||
|
||||
// make sure our window isn't big
|
||||
/*if (bounds.w<scrW) {
|
||||
logD("resizing width because it does not fit");
|
||||
scrW=bounds.w-OOB_PIXELS_SAFETY*2;
|
||||
if (scrW<200) scrW=200;
|
||||
}
|
||||
if (bounds.h<scrH) {
|
||||
logD("resizing height because it does not fit");
|
||||
scrH=bounds.h-OOB_PIXELS_SAFETY*2;
|
||||
if (scrH<100) scrH=100;
|
||||
}*/
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -721,6 +721,8 @@ enum NoteCtrl {
|
|||
struct SelectionPoint {
|
||||
int xCoarse, xFine;
|
||||
int y;
|
||||
SelectionPoint(int xc, int xf, int yp):
|
||||
xCoarse(xc), xFine(xf), y(yp) {}
|
||||
SelectionPoint():
|
||||
xCoarse(0), xFine(0), y(0) {}
|
||||
};
|
||||
|
@ -742,10 +744,17 @@ enum ActionType {
|
|||
GUI_UNDO_PATTERN_FLIP,
|
||||
GUI_UNDO_PATTERN_COLLAPSE,
|
||||
GUI_UNDO_PATTERN_EXPAND,
|
||||
GUI_UNDO_PATTERN_COLLAPSE_SONG,
|
||||
GUI_UNDO_PATTERN_EXPAND_SONG,
|
||||
GUI_UNDO_PATTERN_DRAG,
|
||||
GUI_UNDO_REPLACE
|
||||
};
|
||||
|
||||
enum UndoOtherTarget {
|
||||
GUI_UNDO_TARGET_SONG,
|
||||
GUI_UNDO_TARGET_SUBSONG
|
||||
};
|
||||
|
||||
struct UndoPatternData {
|
||||
int subSong, chan, pat, row, col;
|
||||
short oldVal, newVal;
|
||||
|
@ -770,6 +779,19 @@ struct UndoOrderData {
|
|||
newVal(v2) {}
|
||||
};
|
||||
|
||||
struct UndoOtherData {
|
||||
UndoOtherTarget target;
|
||||
int subtarget;
|
||||
size_t off;
|
||||
unsigned char oldVal, newVal;
|
||||
UndoOtherData(UndoOtherTarget t, int st, size_t o, unsigned char v1, unsigned char v2):
|
||||
target(t),
|
||||
subtarget(st),
|
||||
off(o),
|
||||
oldVal(v1),
|
||||
newVal(v2) {}
|
||||
};
|
||||
|
||||
struct UndoStep {
|
||||
ActionType type;
|
||||
SelectionPoint cursor, selStart, selEnd;
|
||||
|
@ -779,6 +801,7 @@ struct UndoStep {
|
|||
int oldPatLen, newPatLen;
|
||||
std::vector<UndoOrderData> ord;
|
||||
std::vector<UndoPatternData> pat;
|
||||
std::vector<UndoOtherData> other;
|
||||
};
|
||||
|
||||
// -1 = any
|
||||
|
@ -2064,8 +2087,10 @@ class FurnaceGUI {
|
|||
void doScale(float top);
|
||||
void doRandomize(int bottom, int top, bool mode);
|
||||
void doFlip();
|
||||
void doCollapse(int divider);
|
||||
void doExpand(int multiplier);
|
||||
void doCollapse(int divider, const SelectionPoint& sStart, const SelectionPoint& sEnd);
|
||||
void doExpand(int multiplier, const SelectionPoint& sStart, const SelectionPoint& sEnd);
|
||||
void doCollapseSong(int divider);
|
||||
void doExpandSong(int multiplier);
|
||||
void doUndo();
|
||||
void doRedo();
|
||||
void doFind();
|
||||
|
@ -2134,7 +2159,7 @@ class FurnaceGUI {
|
|||
void runBackupThread();
|
||||
void pushPartBlend();
|
||||
void popPartBlend();
|
||||
bool detectOutOfBoundsWindow();
|
||||
bool detectOutOfBoundsWindow(SDL_Rect& failing);
|
||||
int processEvent(SDL_Event* ev);
|
||||
bool loop();
|
||||
bool finish();
|
||||
|
|
|
@ -1464,7 +1464,7 @@ void FurnaceGUI::drawMacroEdit(FurnaceGUIMacroDesc& i, int totalFit, float avail
|
|||
if (!i.isBitfield) {
|
||||
if (settings.oldMacroVSlider) {
|
||||
ImGui::SameLine(0.0f);
|
||||
if (ImGui::VSliderInt("IMacroVScroll",ImVec2(20.0f*dpiScale,i.height*dpiScale),&i.macro->vScroll,0,(i.max-i.min)-i.macro->vZoom,"")) {
|
||||
if (ImGui::VSliderInt("IMacroVScroll",ImVec2(20.0f*dpiScale,i.height*dpiScale),&i.macro->vScroll,0,(i.max-i.min)-i.macro->vZoom,"",ImGuiSliderFlags_NoInput)) {
|
||||
if (i.macro->vScroll<0) i.macro->vScroll=0;
|
||||
if (i.macro->vScroll>((i.max-i.min)-i.macro->vZoom)) i.macro->vScroll=(i.max-i.min)-i.macro->vZoom;
|
||||
}
|
||||
|
@ -1592,7 +1592,7 @@ void FurnaceGUI::drawMacroEdit(FurnaceGUIMacroDesc& i, int totalFit, float avail
|
|||
if (CWSliderInt("##MAAR",&i.macro->val[2],0,255)) { PARAMETER
|
||||
if (i.macro->val[2]<0) i.macro->val[2]=0;
|
||||
if (i.macro->val[2]>255) i.macro->val[2]=255;
|
||||
}
|
||||
} rightClickable
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("Sustain");
|
||||
|
@ -1601,7 +1601,7 @@ void FurnaceGUI::drawMacroEdit(FurnaceGUIMacroDesc& i, int totalFit, float avail
|
|||
if (CWSliderInt("##MASL",&i.macro->val[5],0,255)) { PARAMETER
|
||||
if (i.macro->val[5]<0) i.macro->val[5]=0;
|
||||
if (i.macro->val[5]>255) i.macro->val[5]=255;
|
||||
}
|
||||
} rightClickable
|
||||
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
|
@ -1611,7 +1611,7 @@ void FurnaceGUI::drawMacroEdit(FurnaceGUIMacroDesc& i, int totalFit, float avail
|
|||
if (CWSliderInt("##MAHT",&i.macro->val[3],0,255)) { PARAMETER
|
||||
if (i.macro->val[3]<0) i.macro->val[3]=0;
|
||||
if (i.macro->val[3]>255) i.macro->val[3]=255;
|
||||
}
|
||||
} rightClickable
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("SusTime");
|
||||
|
@ -1620,7 +1620,7 @@ void FurnaceGUI::drawMacroEdit(FurnaceGUIMacroDesc& i, int totalFit, float avail
|
|||
if (CWSliderInt("##MAST",&i.macro->val[6],0,255)) { PARAMETER
|
||||
if (i.macro->val[6]<0) i.macro->val[6]=0;
|
||||
if (i.macro->val[6]>255) i.macro->val[6]=255;
|
||||
}
|
||||
} rightClickable
|
||||
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
|
@ -1630,7 +1630,7 @@ void FurnaceGUI::drawMacroEdit(FurnaceGUIMacroDesc& i, int totalFit, float avail
|
|||
if (CWSliderInt("##MADR",&i.macro->val[4],0,255)) { PARAMETER
|
||||
if (i.macro->val[4]<0) i.macro->val[4]=0;
|
||||
if (i.macro->val[4]>255) i.macro->val[4]=255;
|
||||
}
|
||||
} rightClickable
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("SusDecay");
|
||||
|
@ -1639,7 +1639,7 @@ void FurnaceGUI::drawMacroEdit(FurnaceGUIMacroDesc& i, int totalFit, float avail
|
|||
if (CWSliderInt("##MASR",&i.macro->val[7],0,255)) { PARAMETER
|
||||
if (i.macro->val[7]<0) i.macro->val[7]=0;
|
||||
if (i.macro->val[7]>255) i.macro->val[7]=255;
|
||||
}
|
||||
} rightClickable
|
||||
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
|
@ -1652,7 +1652,7 @@ void FurnaceGUI::drawMacroEdit(FurnaceGUIMacroDesc& i, int totalFit, float avail
|
|||
if (CWSliderInt("##MARR",&i.macro->val[8],0,255)) { PARAMETER
|
||||
if (i.macro->val[8]<0) i.macro->val[8]=0;
|
||||
if (i.macro->val[8]>255) i.macro->val[8]=255;
|
||||
}
|
||||
} rightClickable
|
||||
|
||||
ImGui::EndTable();
|
||||
}
|
||||
|
@ -1695,7 +1695,7 @@ void FurnaceGUI::drawMacroEdit(FurnaceGUIMacroDesc& i, int totalFit, float avail
|
|||
if (CWSliderInt("##MLSpeed",&i.macro->val[11],0,255)) { PARAMETER
|
||||
if (i.macro->val[11]<0) i.macro->val[11]=0;
|
||||
if (i.macro->val[11]>255) i.macro->val[11]=255;
|
||||
}
|
||||
} rightClickable
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("Phase");
|
||||
|
@ -1704,7 +1704,7 @@ void FurnaceGUI::drawMacroEdit(FurnaceGUIMacroDesc& i, int totalFit, float avail
|
|||
if (CWSliderInt("##MLPhase",&i.macro->val[13],0,1023)) { PARAMETER
|
||||
if (i.macro->val[13]<0) i.macro->val[13]=0;
|
||||
if (i.macro->val[13]>1023) i.macro->val[13]=1023;
|
||||
}
|
||||
} rightClickable
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("Shape");
|
||||
|
@ -1713,7 +1713,7 @@ void FurnaceGUI::drawMacroEdit(FurnaceGUIMacroDesc& i, int totalFit, float avail
|
|||
if (CWSliderInt("##MLShape",&i.macro->val[12],0,2,macroLFOShapes[i.macro->val[12]&3])) { PARAMETER
|
||||
if (i.macro->val[12]<0) i.macro->val[12]=0;
|
||||
if (i.macro->val[12]>2) i.macro->val[12]=2;
|
||||
}
|
||||
} rightClickable
|
||||
|
||||
ImGui::EndTable();
|
||||
}
|
||||
|
@ -2839,37 +2839,37 @@ void FurnaceGUI::drawInsEdit() {
|
|||
ImGui::TableNextColumn();
|
||||
op.ar&=maxArDr;
|
||||
CENTER_VSLIDER;
|
||||
P(CWVSliderScalar("##AR",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.ar,&maxArDr,&_ZERO));
|
||||
P(CWVSliderScalar("##AR",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.ar,&maxArDr,&_ZERO)); rightClickable
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
op.dr&=maxArDr;
|
||||
CENTER_VSLIDER;
|
||||
P(CWVSliderScalar("##DR",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.dr,&maxArDr,&_ZERO));
|
||||
P(CWVSliderScalar("##DR",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.dr,&maxArDr,&_ZERO)); rightClickable
|
||||
|
||||
if (settings.susPosition==0) {
|
||||
ImGui::TableNextColumn();
|
||||
op.sl&=15;
|
||||
CENTER_VSLIDER;
|
||||
P(CWVSliderScalar("##SL",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.sl,&_FIFTEEN,&_ZERO));
|
||||
P(CWVSliderScalar("##SL",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.sl,&_FIFTEEN,&_ZERO)); rightClickable
|
||||
}
|
||||
|
||||
if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPM) {
|
||||
ImGui::TableNextColumn();
|
||||
op.d2r&=31;
|
||||
CENTER_VSLIDER;
|
||||
P(CWVSliderScalar("##D2R",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.d2r,&_THIRTY_ONE,&_ZERO));
|
||||
P(CWVSliderScalar("##D2R",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.d2r,&_THIRTY_ONE,&_ZERO)); rightClickable
|
||||
}
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
op.rr&=15;
|
||||
CENTER_VSLIDER;
|
||||
P(CWVSliderScalar("##RR",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.rr,&_FIFTEEN,&_ZERO));
|
||||
P(CWVSliderScalar("##RR",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.rr,&_FIFTEEN,&_ZERO)); rightClickable
|
||||
|
||||
if (settings.susPosition==1) {
|
||||
ImGui::TableNextColumn();
|
||||
op.sl&=15;
|
||||
CENTER_VSLIDER;
|
||||
P(CWVSliderScalar("##SL",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.sl,&_FIFTEEN,&_ZERO));
|
||||
P(CWVSliderScalar("##SL",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.sl,&_FIFTEEN,&_ZERO)); rightClickable
|
||||
}
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
|
@ -2878,38 +2878,38 @@ void FurnaceGUI::drawInsEdit() {
|
|||
ImGui::TableNextColumn();
|
||||
op.tl&=maxTl;
|
||||
CENTER_VSLIDER;
|
||||
P(CWVSliderScalar("##TL",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.tl,&maxTl,&_ZERO));
|
||||
P(CWVSliderScalar("##TL",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.tl,&maxTl,&_ZERO)); rightClickable
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
CENTER_VSLIDER;
|
||||
if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPM) {
|
||||
P(CWVSliderScalar("##RS",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.rs,&_ZERO,&_THREE));
|
||||
P(CWVSliderScalar("##RS",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.rs,&_ZERO,&_THREE)); rightClickable
|
||||
} else {
|
||||
int ksl=ins->type==DIV_INS_OPLL?op.ksl:kslMap[op.ksl&3];
|
||||
if (CWVSliderInt("##KSL",ImVec2(20.0f*dpiScale,sliderHeight),&ksl,0,3)) {
|
||||
op.ksl=(ins->type==DIV_INS_OPLL?ksl:kslMap[ksl&3]);
|
||||
PARAMETER;
|
||||
}
|
||||
} rightClickable
|
||||
}
|
||||
|
||||
if (ins->type==DIV_INS_OPZ) {
|
||||
ImGui::TableNextColumn();
|
||||
CENTER_VSLIDER;
|
||||
P(CWVSliderScalar("##EGS",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.ksl,&_ZERO,&_THREE));
|
||||
P(CWVSliderScalar("##EGS",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.ksl,&_ZERO,&_THREE)); rightClickable
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
CENTER_VSLIDER;
|
||||
P(CWVSliderScalar("##REV",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.dam,&_ZERO,&_SEVEN));
|
||||
P(CWVSliderScalar("##REV",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.dam,&_ZERO,&_SEVEN)); rightClickable
|
||||
}
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
CENTER_VSLIDER;
|
||||
P(CWVSliderScalar("##MULT",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.mult,&_ZERO,&_FIFTEEN));
|
||||
P(CWVSliderScalar("##MULT",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.mult,&_ZERO,&_FIFTEEN)); rightClickable
|
||||
|
||||
if (ins->type==DIV_INS_OPZ) {
|
||||
ImGui::TableNextColumn();
|
||||
CENTER_VSLIDER;
|
||||
P(CWVSliderScalar("##FINE",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.dvb,&_ZERO,&_FIFTEEN));
|
||||
P(CWVSliderScalar("##FINE",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.dvb,&_ZERO,&_FIFTEEN)); rightClickable
|
||||
}
|
||||
|
||||
if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPM) {
|
||||
|
@ -2920,7 +2920,7 @@ void FurnaceGUI::drawInsEdit() {
|
|||
if (detune<-3) detune=-3;
|
||||
if (detune>7) detune=7;
|
||||
op.dt=detuneUnmap[settings.unsignedDetune?1:0][detune+3];
|
||||
}
|
||||
} rightClickable
|
||||
|
||||
if (ins->type!=DIV_INS_FM) {
|
||||
ImGui::TableNextColumn();
|
||||
|
@ -3169,19 +3169,19 @@ void FurnaceGUI::drawInsEdit() {
|
|||
ImGui::TableNextColumn();
|
||||
|
||||
op.ar&=maxArDr;
|
||||
P(CWVSliderScalar("##AR",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.ar,&maxArDr,&_ZERO));
|
||||
P(CWVSliderScalar("##AR",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.ar,&maxArDr,&_ZERO)); rightClickable
|
||||
|
||||
ImGui::SameLine();
|
||||
op.dr&=maxArDr;
|
||||
float textX_DR=ImGui::GetCursorPosX();
|
||||
P(CWVSliderScalar("##DR",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.dr,&maxArDr,&_ZERO));
|
||||
P(CWVSliderScalar("##DR",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.dr,&maxArDr,&_ZERO)); rightClickable
|
||||
|
||||
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));
|
||||
P(CWVSliderScalar("##SL",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.sl,&_FIFTEEN,&_ZERO)); rightClickable
|
||||
}
|
||||
|
||||
float textX_D2R=0.0f;
|
||||
|
@ -3189,19 +3189,19 @@ void FurnaceGUI::drawInsEdit() {
|
|||
ImGui::SameLine();
|
||||
op.d2r&=31;
|
||||
textX_D2R=ImGui::GetCursorPosX();
|
||||
P(CWVSliderScalar("##D2R",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.d2r,&_THIRTY_ONE,&_ZERO));
|
||||
P(CWVSliderScalar("##D2R",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.d2r,&_THIRTY_ONE,&_ZERO)); rightClickable
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
op.rr&=15;
|
||||
float textX_RR=ImGui::GetCursorPosX();
|
||||
P(CWVSliderScalar("##RR",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.rr,&_FIFTEEN,&_ZERO));
|
||||
P(CWVSliderScalar("##RR",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.rr,&_FIFTEEN,&_ZERO)); rightClickable
|
||||
|
||||
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));
|
||||
P(CWVSliderScalar("##SL",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.sl,&_FIFTEEN,&_ZERO)); rightClickable
|
||||
}
|
||||
|
||||
ImVec2 prevCurPos=ImGui::GetCursorPos();
|
||||
|
@ -3500,7 +3500,7 @@ void FurnaceGUI::drawInsEdit() {
|
|||
|
||||
ImGui::TableNextColumn();
|
||||
op.tl&=maxTl;
|
||||
P(CWVSliderScalar("##TL",ImVec2(ImGui::GetFrameHeight(),sliderHeight-((ins->type==DIV_INS_FM || ins->type==DIV_INS_OPM)?(ImGui::GetFrameHeightWithSpacing()+ImGui::CalcTextSize(FM_SHORT_NAME(FM_AM)).y+ImGui::GetStyle().ItemSpacing.y):0.0f)),ImGuiDataType_U8,&op.tl,&maxTl,&_ZERO));
|
||||
P(CWVSliderScalar("##TL",ImVec2(ImGui::GetFrameHeight(),sliderHeight-((ins->type==DIV_INS_FM || ins->type==DIV_INS_OPM)?(ImGui::GetFrameHeightWithSpacing()+ImGui::CalcTextSize(FM_SHORT_NAME(FM_AM)).y+ImGui::GetStyle().ItemSpacing.y):0.0f)),ImGuiDataType_U8,&op.tl,&maxTl,&_ZERO)); rightClickable
|
||||
|
||||
if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPM) {
|
||||
CENTER_TEXT(FM_SHORT_NAME(FM_AM));
|
||||
|
@ -4299,13 +4299,13 @@ void FurnaceGUI::drawInsEdit() {
|
|||
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
P(CWVSliderScalar("##Attack",sliderSize,ImGuiDataType_U8,&ins->c64.a,&_ZERO,&_FIFTEEN));
|
||||
P(CWVSliderScalar("##Attack",sliderSize,ImGuiDataType_U8,&ins->c64.a,&_ZERO,&_FIFTEEN)); rightClickable
|
||||
ImGui::TableNextColumn();
|
||||
P(CWVSliderScalar("##Decay",sliderSize,ImGuiDataType_U8,&ins->c64.d,&_ZERO,&_FIFTEEN));
|
||||
P(CWVSliderScalar("##Decay",sliderSize,ImGuiDataType_U8,&ins->c64.d,&_ZERO,&_FIFTEEN)); rightClickable
|
||||
ImGui::TableNextColumn();
|
||||
P(CWVSliderScalar("##Sustain",sliderSize,ImGuiDataType_U8,&ins->c64.s,&_ZERO,&_FIFTEEN));
|
||||
P(CWVSliderScalar("##Sustain",sliderSize,ImGuiDataType_U8,&ins->c64.s,&_ZERO,&_FIFTEEN)); rightClickable
|
||||
ImGui::TableNextColumn();
|
||||
P(CWVSliderScalar("##Release",sliderSize,ImGuiDataType_U8,&ins->c64.r,&_ZERO,&_FIFTEEN));
|
||||
P(CWVSliderScalar("##Release",sliderSize,ImGuiDataType_U8,&ins->c64.r,&_ZERO,&_FIFTEEN)); rightClickable
|
||||
ImGui::TableNextColumn();
|
||||
drawFMEnv(0,16-ins->c64.a,16-ins->c64.d,15-ins->c64.r,15-ins->c64.r,15-ins->c64.s,0,0,0,15,16,15,ImVec2(ImGui::GetContentRegionAvail().x,sliderSize.y),ins->type);
|
||||
|
||||
|
@ -4799,7 +4799,7 @@ void FurnaceGUI::drawInsEdit() {
|
|||
// filter
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
P(CWSliderScalar("Filter 4,3 Mode",ImGuiDataType_U8,&ins->es5506.filter.mode,&_ZERO,&_THREE,es5506FilterModes[ins->es5506.filter.mode&3])); rightClickable
|
||||
P(CWSliderScalar("Filter Mode",ImGuiDataType_U8,&ins->es5506.filter.mode,&_ZERO,&_THREE,es5506FilterModes[ins->es5506.filter.mode&3]));
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
P(CWSliderScalar("Filter K1",ImGuiDataType_U16,&ins->es5506.filter.k1,&_ZERO,&_SIXTY_FIVE_THOUSAND_FIVE_HUNDRED_THIRTY_FIVE)); rightClickable
|
||||
|
@ -4883,17 +4883,17 @@ void FurnaceGUI::drawInsEdit() {
|
|||
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
P(CWVSliderScalar("##Attack Rate",sliderSize,ImGuiDataType_U8,&ins->multipcm.ar,&_ZERO,&_FIFTEEN));
|
||||
P(CWVSliderScalar("##Attack Rate",sliderSize,ImGuiDataType_U8,&ins->multipcm.ar,&_ZERO,&_FIFTEEN)); rightClickable
|
||||
ImGui::TableNextColumn();
|
||||
P(CWVSliderScalar("##Decay 1 Rate",sliderSize,ImGuiDataType_U8,&ins->multipcm.d1r,&_ZERO,&_FIFTEEN));
|
||||
P(CWVSliderScalar("##Decay 1 Rate",sliderSize,ImGuiDataType_U8,&ins->multipcm.d1r,&_ZERO,&_FIFTEEN)); rightClickable
|
||||
ImGui::TableNextColumn();
|
||||
P(CWVSliderScalar("##Decay Level",sliderSize,ImGuiDataType_U8,&ins->multipcm.dl,&_ZERO,&_FIFTEEN));
|
||||
P(CWVSliderScalar("##Decay Level",sliderSize,ImGuiDataType_U8,&ins->multipcm.dl,&_ZERO,&_FIFTEEN)); rightClickable
|
||||
ImGui::TableNextColumn();
|
||||
P(CWVSliderScalar("##Decay 2 Rate",sliderSize,ImGuiDataType_U8,&ins->multipcm.d2r,&_ZERO,&_FIFTEEN));
|
||||
P(CWVSliderScalar("##Decay 2 Rate",sliderSize,ImGuiDataType_U8,&ins->multipcm.d2r,&_ZERO,&_FIFTEEN)); rightClickable
|
||||
ImGui::TableNextColumn();
|
||||
P(CWVSliderScalar("##Release Rate",sliderSize,ImGuiDataType_U8,&ins->multipcm.rr,&_ZERO,&_FIFTEEN));
|
||||
P(CWVSliderScalar("##Release Rate",sliderSize,ImGuiDataType_U8,&ins->multipcm.rr,&_ZERO,&_FIFTEEN)); rightClickable
|
||||
ImGui::TableNextColumn();
|
||||
P(CWVSliderScalar("##Rate Correction",sliderSize,ImGuiDataType_U8,&ins->multipcm.rc,&_ZERO,&_FIFTEEN));
|
||||
P(CWVSliderScalar("##Rate Correction",sliderSize,ImGuiDataType_U8,&ins->multipcm.rc,&_ZERO,&_FIFTEEN)); rightClickable
|
||||
ImGui::TableNextColumn();
|
||||
drawFMEnv(0,ins->multipcm.ar,ins->multipcm.d1r,ins->multipcm.d2r,ins->multipcm.rr,ins->multipcm.dl,0,0,0,127,15,15,ImVec2(ImGui::GetContentRegionAvail().x,sliderSize.y),ins->type);
|
||||
ImGui::EndTable();
|
||||
|
@ -4951,17 +4951,17 @@ void FurnaceGUI::drawInsEdit() {
|
|||
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
P(CWVSliderScalar("##Attack",sliderSize,ImGuiDataType_U8,&ins->snes.a,&_ZERO,&_FIFTEEN));
|
||||
P(CWVSliderScalar("##Attack",sliderSize,ImGuiDataType_U8,&ins->snes.a,&_ZERO,&_FIFTEEN)); rightClickable
|
||||
ImGui::TableNextColumn();
|
||||
P(CWVSliderScalar("##Decay",sliderSize,ImGuiDataType_U8,&ins->snes.d,&_ZERO,&_SEVEN));
|
||||
P(CWVSliderScalar("##Decay",sliderSize,ImGuiDataType_U8,&ins->snes.d,&_ZERO,&_SEVEN)); rightClickable
|
||||
ImGui::TableNextColumn();
|
||||
P(CWVSliderScalar("##Sustain",sliderSize,ImGuiDataType_U8,&ins->snes.s,&_ZERO,&_SEVEN));
|
||||
P(CWVSliderScalar("##Sustain",sliderSize,ImGuiDataType_U8,&ins->snes.s,&_ZERO,&_SEVEN)); rightClickable
|
||||
if (ins->snes.sus) {
|
||||
ImGui::TableNextColumn();
|
||||
P(CWVSliderScalar("##Decay2",sliderSize,ImGuiDataType_U8,&ins->snes.d2,&_ZERO,&_THIRTY_ONE));
|
||||
P(CWVSliderScalar("##Decay2",sliderSize,ImGuiDataType_U8,&ins->snes.d2,&_ZERO,&_THIRTY_ONE)); rightClickable
|
||||
}
|
||||
ImGui::TableNextColumn();
|
||||
P(CWVSliderScalar("##Release",sliderSize,ImGuiDataType_U8,&ins->snes.r,&_ZERO,&_THIRTY_ONE));
|
||||
P(CWVSliderScalar("##Release",sliderSize,ImGuiDataType_U8,&ins->snes.r,&_ZERO,&_THIRTY_ONE)); rightClickable
|
||||
ImGui::TableNextColumn();
|
||||
drawFMEnv(0,ins->snes.a+1,1+ins->snes.d*2,ins->snes.sus?ins->snes.d2:ins->snes.r,ins->snes.sus?ins->snes.r:31,(14-ins->snes.s*2),(ins->snes.r==0 || (ins->snes.sus && ins->snes.d2==0)),0,0,7,16,31,ImVec2(ImGui::GetContentRegionAvail().x,sliderSize.y),ins->type);
|
||||
|
||||
|
@ -5023,7 +5023,7 @@ void FurnaceGUI::drawInsEdit() {
|
|||
ImGui::TableNextColumn();
|
||||
unsigned char gainMax=(ins->snes.gainMode==DivInstrumentSNES::GAIN_MODE_DIRECT)?127:31;
|
||||
if (ins->snes.gain>gainMax) ins->snes.gain=gainMax;
|
||||
P(CWVSliderScalar("##Gain",sliderSize,ImGuiDataType_U8,&ins->snes.gain,&_ZERO,&gainMax));
|
||||
P(CWVSliderScalar("##Gain",sliderSize,ImGuiDataType_U8,&ins->snes.gain,&_ZERO,&gainMax)); rightClickable
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("Envelope goes here...");
|
||||
|
|
|
@ -100,7 +100,7 @@ void FurnaceGUI::drawOsc() {
|
|||
if (ImGui::VSliderFloat("##OscZoom",ImVec2(20.0f*dpiScale,ImGui::GetContentRegionAvail().y),&oscZoom,0.5,2.0)) {
|
||||
if (oscZoom<0.5) oscZoom=0.5;
|
||||
if (oscZoom>2.0) oscZoom=2.0;
|
||||
}
|
||||
} rightClickable
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("zoom: %.2fx (%.1fdB)",oscZoom,20.0*log10(oscZoom*2.0));
|
||||
}
|
||||
|
@ -111,7 +111,7 @@ void FurnaceGUI::drawOsc() {
|
|||
if (ImGui::VSliderFloat("##OscWinSize",ImVec2(20.0f*dpiScale,ImGui::GetContentRegionAvail().y),&oscWindowSize,5.0,100.0)) {
|
||||
if (oscWindowSize<5.0) oscWindowSize=5.0;
|
||||
if (oscWindowSize>100.0) oscWindowSize=100.0;
|
||||
}
|
||||
} rightClickable
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("window size: %.1fms",oscWindowSize);
|
||||
}
|
||||
|
|
|
@ -1111,23 +1111,26 @@ void FurnaceGUI::drawSampleEdit() {
|
|||
|
||||
if (sampleTex!=NULL) {
|
||||
if (updateSampleTex) {
|
||||
unsigned int* data=NULL;
|
||||
unsigned int* dataT=NULL;
|
||||
int pitch=0;
|
||||
logD("updating sample texture.");
|
||||
if (SDL_LockTexture(sampleTex,NULL,(void**)&data,&pitch)!=0) {
|
||||
if (SDL_LockTexture(sampleTex,NULL,(void**)&dataT,&pitch)!=0) {
|
||||
logE("error while locking sample texture! %s",SDL_GetError());
|
||||
} else {
|
||||
unsigned int* data=new unsigned int[sampleTexW*sampleTexH];
|
||||
|
||||
ImU32 bgColor=ImGui::GetColorU32(uiColors[GUI_COLOR_SAMPLE_BG]);
|
||||
ImU32 bgColorLoop=ImGui::GetColorU32(uiColors[GUI_COLOR_SAMPLE_LOOP]);
|
||||
ImU32 lineColor=ImGui::GetColorU32(uiColors[GUI_COLOR_SAMPLE_FG]);
|
||||
ImU32 centerLineColor=ImGui::GetColorU32(uiColors[GUI_COLOR_SAMPLE_CENTER]);
|
||||
int ij=0;
|
||||
for (int i=0; i<availY; i++) {
|
||||
for (int j=0; j<availX; j++) {
|
||||
int scaledPos=samplePos+(j*sampleZoom);
|
||||
if (sample->isLoopable() && (scaledPos>=sample->loopStart && scaledPos<=sample->loopEnd)) {
|
||||
data[i*availX+j]=bgColorLoop;
|
||||
data[ij++]=bgColorLoop;
|
||||
} else {
|
||||
data[i*availX+j]=bgColor;
|
||||
data[ij++]=bgColor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1143,11 +1146,15 @@ void FurnaceGUI::drawSampleEdit() {
|
|||
for (unsigned int i=0; i<(unsigned int)availX; i++) {
|
||||
if (xCoarse>=sample->samples) break;
|
||||
int y1, y2;
|
||||
int candMin=INT_MAX;
|
||||
int candMax=INT_MIN;
|
||||
int totalAdvance=0;
|
||||
if (sample->depth==DIV_SAMPLE_DEPTH_8BIT) {
|
||||
y1=((unsigned char)sample->data8[xCoarse]^0x80)*availY/256;
|
||||
if (candMin>sample->data8[xCoarse]) candMin=sample->data8[xCoarse];
|
||||
if (candMax<sample->data8[xCoarse]) candMax=sample->data8[xCoarse];
|
||||
} else {
|
||||
y1=((unsigned short)sample->data16[xCoarse]^0x8000)*availY/65536;
|
||||
if (candMin>sample->data16[xCoarse]) candMin=sample->data16[xCoarse];
|
||||
if (candMax<sample->data16[xCoarse]) candMax=sample->data16[xCoarse];
|
||||
}
|
||||
xFine+=xAdvanceFine;
|
||||
if (xFine>=16777216) {
|
||||
|
@ -1157,27 +1164,44 @@ void FurnaceGUI::drawSampleEdit() {
|
|||
totalAdvance+=xAdvanceCoarse;
|
||||
if (xCoarse>=sample->samples) break;
|
||||
do {
|
||||
if (xCoarse>=sample->samples) break;
|
||||
if (sample->depth==DIV_SAMPLE_DEPTH_8BIT) {
|
||||
y2=((unsigned char)sample->data8[xCoarse]^0x80)*availY/256;
|
||||
if (candMin>sample->data8[xCoarse]) candMin=sample->data8[xCoarse];
|
||||
if (candMax<sample->data8[xCoarse]) candMax=sample->data8[xCoarse];
|
||||
} else {
|
||||
y2=((unsigned short)sample->data16[xCoarse]^0x8000)*availY/65536;
|
||||
}
|
||||
if (y1>y2) {
|
||||
y2^=y1;
|
||||
y1^=y2;
|
||||
y2^=y1;
|
||||
}
|
||||
if (y1<0) y1=0;
|
||||
if (y1>=availY) y1=availY-1;
|
||||
if (y2<0) y2=0;
|
||||
if (y2>=availY) y2=availY-1;
|
||||
for (int j=y1; j<=y2; j++) {
|
||||
data[i+availX*(availY-j-1)]=lineColor;
|
||||
if (candMin>sample->data16[xCoarse]) candMin=sample->data16[xCoarse];
|
||||
if (candMax<sample->data16[xCoarse]) candMax=sample->data16[xCoarse];
|
||||
}
|
||||
if (totalAdvance>0) xCoarse++;
|
||||
} while ((totalAdvance--)>0);
|
||||
if (sample->depth==DIV_SAMPLE_DEPTH_8BIT) {
|
||||
y1=(((unsigned char)candMin^0x80)*availY)>>8;
|
||||
y2=(((unsigned char)candMax^0x80)*availY)>>8;
|
||||
} else {
|
||||
y1=(((unsigned short)candMin^0x8000)*availY)>>16;
|
||||
y2=(((unsigned short)candMax^0x8000)*availY)>>16;
|
||||
}
|
||||
if (y1>y2) {
|
||||
y2^=y1;
|
||||
y1^=y2;
|
||||
y2^=y1;
|
||||
}
|
||||
if (y1<0) y1=0;
|
||||
if (y1>=availY) y1=availY-1;
|
||||
if (y2<0) y2=0;
|
||||
if (y2>=availY) y2=availY-1;
|
||||
|
||||
const int s1=i+availX*(availY-y1-1);
|
||||
const int s2=i+availX*(availY-y2-1);
|
||||
|
||||
for (int j=s2; j<=s1; j+=availX) {
|
||||
data[j]=lineColor;
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(dataT,data,sampleTexW*sampleTexH*sizeof(unsigned int));
|
||||
SDL_UnlockTexture(sampleTex);
|
||||
delete[] data;
|
||||
}
|
||||
updateSampleTex=false;
|
||||
}
|
||||
|
|
|
@ -2304,10 +2304,12 @@ void FurnaceGUI::drawSettings() {
|
|||
UI_KEYBIND_CONFIG(GUI_ACTION_PAT_FLIP_SELECTION);
|
||||
UI_KEYBIND_CONFIG(GUI_ACTION_PAT_COLLAPSE_ROWS);
|
||||
UI_KEYBIND_CONFIG(GUI_ACTION_PAT_EXPAND_ROWS);
|
||||
UI_KEYBIND_CONFIG(GUI_ACTION_PAT_COLLAPSE_PAT);
|
||||
UI_KEYBIND_CONFIG(GUI_ACTION_PAT_EXPAND_PAT);
|
||||
UI_KEYBIND_CONFIG(GUI_ACTION_PAT_COLLAPSE_SONG);
|
||||
UI_KEYBIND_CONFIG(GUI_ACTION_PAT_EXPAND_SONG);
|
||||
UI_KEYBIND_CONFIG(GUI_ACTION_PAT_LATCH);
|
||||
|
||||
// TODO: collapse/expand pattern and song
|
||||
|
||||
KEYBIND_CONFIG_END;
|
||||
ImGui::TreePop();
|
||||
}
|
||||
|
|
|
@ -598,7 +598,7 @@ void FurnaceGUI::drawWaveEdit() {
|
|||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||
if (CWSliderFloat("##WGDuty",&waveGenDuty,0.0f,1.0f)) {
|
||||
doGenerateWave();
|
||||
}
|
||||
} rightClickable
|
||||
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
|
@ -607,7 +607,7 @@ void FurnaceGUI::drawWaveEdit() {
|
|||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||
if (CWSliderInt("##WGExp",&waveGenPower,1,8)) {
|
||||
doGenerateWave();
|
||||
}
|
||||
} rightClickable
|
||||
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
|
@ -616,7 +616,7 @@ void FurnaceGUI::drawWaveEdit() {
|
|||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||
if (CWSliderFloat("##WGXOR",&waveGenInvertPoint,0.0f,1.0f)) {
|
||||
doGenerateWave();
|
||||
}
|
||||
} rightClickable
|
||||
|
||||
ImGui::EndTable();
|
||||
}
|
||||
|
@ -636,7 +636,7 @@ void FurnaceGUI::drawWaveEdit() {
|
|||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||
if (CWSliderFloat("##WGAmp",&waveGenAmp[i],-1.0f,1.0f)) {
|
||||
doGenerateWave();
|
||||
}
|
||||
} rightClickable
|
||||
if (ImGui::IsItemClicked(ImGuiMouseButton_Middle)) {
|
||||
waveGenAmp[i]=0.0f;
|
||||
doGenerateWave();
|
||||
|
@ -647,7 +647,7 @@ void FurnaceGUI::drawWaveEdit() {
|
|||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||
if (CWSliderFloat("##WGPhase",&waveGenPhase[i],0.0f,1.0f)) {
|
||||
doGenerateWave();
|
||||
}
|
||||
} rightClickable
|
||||
if (ImGui::IsItemClicked(ImGuiMouseButton_Middle)) {
|
||||
waveGenPhase[i]=0.0f;
|
||||
doGenerateWave();
|
||||
|
@ -690,7 +690,7 @@ void FurnaceGUI::drawWaveEdit() {
|
|||
ImGui::PushID(i);
|
||||
if (CWSliderFloat("##WGTL",&waveGenTL[i],0.0f,1.0f)) {
|
||||
doGenerateWave();
|
||||
}
|
||||
} rightClickable
|
||||
ImGui::PopID();
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
|
@ -698,7 +698,7 @@ void FurnaceGUI::drawWaveEdit() {
|
|||
ImGui::PushID(i);
|
||||
if (CWSliderInt("##WGMULT",&waveGenMult[i],1,16)) {
|
||||
doGenerateWave();
|
||||
}
|
||||
} rightClickable
|
||||
ImGui::PopID();
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
|
@ -706,7 +706,7 @@ void FurnaceGUI::drawWaveEdit() {
|
|||
ImGui::PushID(i);
|
||||
if (CWSliderInt("##WGFB",&waveGenFB[i],0,7)) {
|
||||
doGenerateWave();
|
||||
}
|
||||
} rightClickable
|
||||
|
||||
ImGui::PopID();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue