Merge branch 'master' of https://github.com/tildearrow/furnace into k053260
This commit is contained in:
commit
523e08ed5c
35 changed files with 677 additions and 193 deletions
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -1558,7 +1558,7 @@ DivMacroInt* DivPlatformOPL::getChanMacroInt(int ch) {
|
|||
}
|
||||
|
||||
DivDispatchOscBuffer* DivPlatformOPL::getOscBuffer(int ch) {
|
||||
if (oplType==759) {
|
||||
if (oplType==759 || chipType==8950) {
|
||||
if (ch>=totalChans+1) return NULL;
|
||||
} else {
|
||||
if (ch>=totalChans) return NULL;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -151,8 +151,8 @@ void DivPlatformRF5C68::tick(bool sysTick) {
|
|||
if (s->isLoopable()) {
|
||||
loop=start+s->loopStart;
|
||||
}
|
||||
start=MIN(start,getSampleMemCapacity()-31);
|
||||
loop=MIN(loop,getSampleMemCapacity()-31);
|
||||
start=MIN(start,getSampleMemCapacity()-32);
|
||||
loop=MIN(loop,getSampleMemCapacity()-32);
|
||||
rWrite(8,keyoff); // force keyoff first
|
||||
chWrite(i,6,start>>8);
|
||||
chWrite(i,4,loop&0xff);
|
||||
|
|
@ -425,7 +425,7 @@ void DivPlatformRF5C68::renderSamples(int sysID) {
|
|||
}
|
||||
|
||||
int length=s->getLoopEndPosition(DIV_SAMPLE_DEPTH_8BIT);
|
||||
int actualLength=MIN((int)(getSampleMemCapacity()-memPos)-31,length);
|
||||
int actualLength=MIN((int)(getSampleMemCapacity()-memPos)-32,length);
|
||||
if (actualLength>0) {
|
||||
sampleOffRFC[i]=memPos;
|
||||
for (int j=0; j<actualLength; j++) {
|
||||
|
|
@ -435,8 +435,8 @@ void DivPlatformRF5C68::renderSamples(int sysID) {
|
|||
sampleMem[memPos++]=(val>0)?(val|0x80):(0-val);
|
||||
}
|
||||
// write end of sample marker
|
||||
memset(&sampleMem[memPos],0xff,31);
|
||||
memPos+=31;
|
||||
memset(&sampleMem[memPos],0xff,32);
|
||||
memPos+=32;
|
||||
}
|
||||
if (actualLength<length) {
|
||||
logW("out of RF5C68 PCM memory for sample %d!",i);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -222,7 +222,8 @@ void DivPlatformX1_010::acquire(short** buf, size_t len) {
|
|||
if (stereo) buf[1][h]=tempR;
|
||||
|
||||
for (int i=0; i<16; i++) {
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=(x1_010.voice_out(i,0)+x1_010.voice_out(i,1))>>1;
|
||||
int vo=(x1_010.voice_out(i,0)+x1_010.voice_out(i,1))<<3;
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=CLAMP(vo,-32768,32767);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -1125,25 +1193,47 @@ void DivEngine::nextRow() {
|
|||
bool wantPreNote=false;
|
||||
if (disCont[dispatchOfChan[i]].dispatch!=NULL) {
|
||||
wantPreNote=disCont[dispatchOfChan[i]].dispatch->getWantPreNote();
|
||||
if (wantPreNote) dispatchCmd(DivCommand(DIV_CMD_PRE_NOTE,i,ticks));
|
||||
if (wantPreNote) {
|
||||
int addition=0;
|
||||
for (int j=0; j<curPat[i].effectCols; j++) {
|
||||
if (pat->data[curRow][4+(j<<1)]==0xed) {
|
||||
if (pat->data[curRow][5+(j<<1)]>0) {
|
||||
addition=pat->data[curRow][5+(j<<1)];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
dispatchCmd(DivCommand(DIV_CMD_PRE_NOTE,i,ticks+addition));
|
||||
}
|
||||
}
|
||||
|
||||
if (song.oneTickCut) {
|
||||
bool doPrepareCut=true;
|
||||
int addition=0;
|
||||
|
||||
for (int j=0; j<curPat[i].effectCols; j++) {
|
||||
if (pat->data[curRow][4+(j<<1)]==0x03) {
|
||||
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;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (pat->data[curRow][4+(j<<1)]==0xed) {
|
||||
if (pat->data[curRow][5+(j<<1)]>0) {
|
||||
addition=pat->data[curRow][5+(j<<1)];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (doPrepareCut && !wantPreNote && chan[i].cut<=0) chan[i].cut=ticks;
|
||||
if (doPrepareCut && !wantPreNote && chan[i].cut<=0) chan[i].cut=ticks+addition;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -1083,6 +1083,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++) {
|
||||
|
|
@ -2399,6 +2400,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;
|
||||
}
|
||||
|
||||
|
|
@ -3838,11 +3843,11 @@ bool FurnaceGUI::loop() {
|
|||
}
|
||||
ImGui::Checkbox("loop",&vgmExportLoop);
|
||||
if (vgmExportLoop && e->song.loopModality==2) {
|
||||
ImGui::Text("trailing ticks:");
|
||||
ImGui::Text("loop trail:");
|
||||
if (ImGui::RadioButton("auto-detect",vgmExportTrailingTicks==-1)) {
|
||||
vgmExportTrailingTicks=-1;
|
||||
}
|
||||
if (ImGui::RadioButton("one loop",vgmExportTrailingTicks==-2)) {
|
||||
if (ImGui::RadioButton("add one loop",vgmExportTrailingTicks==-2)) {
|
||||
vgmExportTrailingTicks=-2;
|
||||
}
|
||||
if (ImGui::RadioButton("custom",vgmExportTrailingTicks>=0)) {
|
||||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -722,6 +722,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) {}
|
||||
};
|
||||
|
|
@ -743,10 +745,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;
|
||||
|
|
@ -771,6 +780,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;
|
||||
|
|
@ -780,6 +802,7 @@ struct UndoStep {
|
|||
int oldPatLen, newPatLen;
|
||||
std::vector<UndoOrderData> ord;
|
||||
std::vector<UndoPatternData> pat;
|
||||
std::vector<UndoOtherData> other;
|
||||
};
|
||||
|
||||
// -1 = any
|
||||
|
|
@ -2065,8 +2088,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();
|
||||
|
|
@ -2135,7 +2160,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);
|
||||
|
||||
|
|
@ -4800,7 +4800,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
|
||||
|
|
@ -4884,17 +4884,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();
|
||||
|
|
@ -4952,17 +4952,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);
|
||||
|
||||
|
|
@ -5024,7 +5024,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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -276,6 +276,8 @@ void FurnaceGUI::drawSettings() {
|
|||
ImVec2 setWindowSize=ImVec2(canvasW,canvasH);
|
||||
ImGui::SetNextWindowPos(setWindowPos);
|
||||
ImGui::SetNextWindowSize(setWindowSize);
|
||||
} else {
|
||||
ImGui::SetNextWindowSizeConstraints(ImVec2(200.0f*dpiScale,100.0f*dpiScale),ImVec2(canvasW,canvasH));
|
||||
}
|
||||
if (ImGui::Begin("Settings",&settingsOpen,ImGuiWindowFlags_NoDocking|globalWinFlags)) {
|
||||
if (!settingsOpen) {
|
||||
|
|
@ -2303,10 +2305,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…
Add table
Add a link
Reference in a new issue