Merge branch 'master' of https://github.com/tildearrow/furnace into x1_010_bank

This commit is contained in:
cam900 2023-05-02 13:46:23 +09:00
commit b326087721
28 changed files with 635 additions and 178 deletions

View file

@ -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)));

View file

@ -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?

View file

@ -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),

View file

@ -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*));

View file

@ -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.

View file

@ -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);

View file

@ -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() {

View file

@ -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);

View file

@ -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;
}
}
}

View file

@ -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);

View file

@ -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;

View file

@ -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;

View file

@ -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(

View file

@ -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) {

View file

@ -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;

View file

@ -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;

View file

@ -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

View file

@ -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();

View file

@ -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...");

View file

@ -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);
}

View file

@ -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;
}

View file

@ -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();
}

View file

@ -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();
}