Merge branch 'master' of https://github.com/tildearrow/furnace into ymf278b
This commit is contained in:
commit
80faf6cf41
Binary file not shown.
|
@ -1,36 +0,0 @@
|
||||||
# basic mode
|
|
||||||
|
|
||||||
Furnace comes with a "basic mode" that can be toggled through the "settings" menu. it disables certain features in Furnace that may look intimidating or confusing for newcomers. if you find that a certain feature of Furnace is missing, see if this setting is enabled or not.
|
|
||||||
|
|
||||||
among the features that cannot be accessed in this mode are:
|
|
||||||
|
|
||||||
### edit menu
|
|
||||||
- paste special
|
|
||||||
- operation masking
|
|
||||||
- input latch
|
|
||||||
- find and replace
|
|
||||||
|
|
||||||
### speed window
|
|
||||||
- virtual tempo
|
|
||||||
- divider
|
|
||||||
- song length
|
|
||||||
|
|
||||||
### song info window
|
|
||||||
- manual system naming
|
|
||||||
- tuning options
|
|
||||||
|
|
||||||
### pattern right-click menu
|
|
||||||
- gradient/fade
|
|
||||||
- scale
|
|
||||||
- randomize
|
|
||||||
- invert values
|
|
||||||
- flip selection
|
|
||||||
- collapse
|
|
||||||
- expand
|
|
||||||
|
|
||||||
### other windows
|
|
||||||
- mixer
|
|
||||||
- grooves
|
|
||||||
- channels
|
|
||||||
- pattern manager
|
|
||||||
- compatibility flags
|
|
|
@ -15,6 +15,12 @@ however, effects are continuous (unless specified), which means you only need to
|
||||||
- `F8xx`: **Single tick volume slide up.** adds `x` to volume on first tick only.
|
- `F8xx`: **Single tick volume slide up.** adds `x` to volume on first tick only.
|
||||||
- `F9xx`: **Single tick volume slide down.** subtracts `x` from volume on first tick only.
|
- `F9xx`: **Single tick volume slide down.** subtracts `x` from volume on first tick only.
|
||||||
- ---
|
- ---
|
||||||
|
- `D8xx`: **Set volume slide bottom boundary.**
|
||||||
|
- the default is 0.
|
||||||
|
- `D9xx`: **Set volume slide top boundary.**
|
||||||
|
- the default is the channel's maximum volume.
|
||||||
|
- `DCxx`: **Delayed mute.** sets volume to 0 after `xx` ticks.
|
||||||
|
- ---
|
||||||
- `07xy`: **Tremolo.** changes volume to be "wavy" with a sine LFO. `x` is the speed. `y` is the depth.
|
- `07xy`: **Tremolo.** changes volume to be "wavy" with a sine LFO. `x` is the speed. `y` is the depth.
|
||||||
- tremolo is downward only.
|
- tremolo is downward only.
|
||||||
- maximum tremolo depth is -60 volume steps.
|
- maximum tremolo depth is -60 volume steps.
|
||||||
|
|
|
@ -255,6 +255,7 @@ size | description
|
||||||
| - 0xdf: YM2612 XGM extended - 13 channels (UNAVAILABLE)
|
| - 0xdf: YM2612 XGM extended - 13 channels (UNAVAILABLE)
|
||||||
| - 0xe0: QSound - 19 channels
|
| - 0xe0: QSound - 19 channels
|
||||||
| - 0xe1: PS1 - 24 channels (UNAVAILABLE)
|
| - 0xe1: PS1 - 24 channels (UNAVAILABLE)
|
||||||
|
| - 0xe2: C64 (6581) with PCM - 4 channels (UNAVAILABLE)
|
||||||
| - 0xf0: SID2 - 3 channels
|
| - 0xf0: SID2 - 3 channels
|
||||||
| - 0xf1: 5E01 - 5 channels
|
| - 0xf1: 5E01 - 5 channels
|
||||||
| - 0xfc: Pong - 1 channel
|
| - 0xfc: Pong - 1 channel
|
||||||
|
|
|
@ -98,6 +98,12 @@ const char* DivEngine::getEffectDesc(unsigned char effect, int chan, bool notNul
|
||||||
break;
|
break;
|
||||||
case 0xc0: case 0xc1: case 0xc2: case 0xc3:
|
case 0xc0: case 0xc1: case 0xc2: case 0xc3:
|
||||||
return _("Cxxx: Set tick rate (hz)");
|
return _("Cxxx: Set tick rate (hz)");
|
||||||
|
case 0xd8:
|
||||||
|
return _("D8xx: Set volume slide bottom boundary");
|
||||||
|
case 0xd9:
|
||||||
|
return _("D9xx: Set volume slide top boundary");
|
||||||
|
case 0xdc:
|
||||||
|
return _("DCxx: Delayed mute");
|
||||||
case 0xe0:
|
case 0xe0:
|
||||||
return _("E0xx: Set arp speed");
|
return _("E0xx: Set arp speed");
|
||||||
case 0xe1:
|
case 0xe1:
|
||||||
|
@ -2108,6 +2114,7 @@ void DivEngine::reset() {
|
||||||
chan[i]=DivChannelState();
|
chan[i]=DivChannelState();
|
||||||
if (i<chans) chan[i].volMax=(disCont[dispatchOfChan[i]].dispatch->dispatch(DivCommand(DIV_CMD_GET_VOLMAX,dispatchChanOfChan[i]))<<8)|0xff;
|
if (i<chans) chan[i].volMax=(disCont[dispatchOfChan[i]].dispatch->dispatch(DivCommand(DIV_CMD_GET_VOLMAX,dispatchChanOfChan[i]))<<8)|0xff;
|
||||||
chan[i].volume=chan[i].volMax;
|
chan[i].volume=chan[i].volMax;
|
||||||
|
chan[i].volTop=chan[i].volMax;
|
||||||
if (song.linearPitch==0) chan[i].vibratoFine=4;
|
if (song.linearPitch==0) chan[i].vibratoFine=4;
|
||||||
}
|
}
|
||||||
extValue=0;
|
extValue=0;
|
||||||
|
|
|
@ -133,7 +133,7 @@ struct DivAudioExportOptions {
|
||||||
struct DivChannelState {
|
struct DivChannelState {
|
||||||
std::vector<DivDelayedCommand> delayed;
|
std::vector<DivDelayedCommand> delayed;
|
||||||
int note, oldNote, lastIns, pitch, portaSpeed, portaNote;
|
int note, oldNote, lastIns, pitch, portaSpeed, portaNote;
|
||||||
int volume, volSpeed, cut, legatoDelay, legatoTarget, rowDelay, volMax;
|
int volume, volSpeed, cut, volCut, legatoDelay, legatoTarget, rowDelay, volMax, volBottom, volTop;
|
||||||
int delayOrder, delayRow, retrigSpeed, retrigTick;
|
int delayOrder, delayRow, retrigSpeed, retrigTick;
|
||||||
int vibratoDepth, vibratoRate, vibratoPos, vibratoPosGiant, vibratoShape, vibratoFine;
|
int vibratoDepth, vibratoRate, vibratoPos, vibratoPosGiant, vibratoShape, vibratoFine;
|
||||||
int tremoloDepth, tremoloRate, tremoloPos;
|
int tremoloDepth, tremoloRate, tremoloPos;
|
||||||
|
@ -158,10 +158,13 @@ struct DivChannelState {
|
||||||
volume(0x7f00),
|
volume(0x7f00),
|
||||||
volSpeed(0),
|
volSpeed(0),
|
||||||
cut(-1),
|
cut(-1),
|
||||||
|
volCut(-1),
|
||||||
legatoDelay(-1),
|
legatoDelay(-1),
|
||||||
legatoTarget(0),
|
legatoTarget(0),
|
||||||
rowDelay(0),
|
rowDelay(0),
|
||||||
volMax(0),
|
volMax(0),
|
||||||
|
volBottom(0),
|
||||||
|
volTop(0),
|
||||||
delayOrder(0),
|
delayOrder(0),
|
||||||
delayRow(0),
|
delayRow(0),
|
||||||
retrigSpeed(0),
|
retrigSpeed(0),
|
||||||
|
|
|
@ -1077,8 +1077,24 @@ bool DivEngine::loadXM(unsigned char* file, size_t len) {
|
||||||
p->data[j][effectCol[k]++]=0x0c;
|
p->data[j][effectCol[k]++]=0x0c;
|
||||||
p->data[j][effectCol[k]++]=(effectVal&15);
|
p->data[j][effectCol[k]++]=(effectVal&15);
|
||||||
break;
|
break;
|
||||||
|
case 0xa: // vol slide up (fine)
|
||||||
|
volSlideStatus[k]=((effectVal&15)<<4)|0xf;
|
||||||
|
volSlideStatusChanged[k]=true;
|
||||||
|
if (hasNote || hasIns) {
|
||||||
|
volSlideStatusChanged[k]=true;
|
||||||
|
}
|
||||||
|
volSliding[k]=true;
|
||||||
|
break;
|
||||||
|
case 0xb: // vol slide down (fine)
|
||||||
|
volSlideStatus[k]=0xf0|(effectVal&15);
|
||||||
|
volSlideStatusChanged[k]=true;
|
||||||
|
if (hasNote || hasIns) {
|
||||||
|
volSlideStatusChanged[k]=true;
|
||||||
|
}
|
||||||
|
volSliding[k]=true;
|
||||||
|
break;
|
||||||
case 0xc:
|
case 0xc:
|
||||||
p->data[j][effectCol[k]++]=0xec;
|
p->data[j][effectCol[k]++]=0xdc;
|
||||||
p->data[j][effectCol[k]++]=MAX(1,effectVal&15);
|
p->data[j][effectCol[k]++]=MAX(1,effectVal&15);
|
||||||
break;
|
break;
|
||||||
case 0xd:
|
case 0xd:
|
||||||
|
|
|
@ -948,6 +948,20 @@ void DivEngine::processRow(int i, bool afterDelay) {
|
||||||
clockDrift=0;
|
clockDrift=0;
|
||||||
subticks=0;
|
subticks=0;
|
||||||
break;
|
break;
|
||||||
|
case 0xd8: // vol slide bottom
|
||||||
|
chan[i].volBottom=(effectVal<<8)|0xff;
|
||||||
|
if (chan[i].volBottom>chan[i].volMax) chan[i].volBottom=chan[i].volMax;
|
||||||
|
break;
|
||||||
|
case 0xd9: // vol slide top
|
||||||
|
chan[i].volTop=(effectVal<<8)|0xff;
|
||||||
|
if (chan[i].volTop>chan[i].volMax) chan[i].volTop=chan[i].volMax;
|
||||||
|
break;
|
||||||
|
case 0xdc: // delayed mute
|
||||||
|
if (effectVal>0 && (song.delayBehavior==2 || effectVal<nextSpeed)) {
|
||||||
|
chan[i].volCut=effectVal+1;
|
||||||
|
chan[i].cutType=0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case 0xe0: // arp speed
|
case 0xe0: // arp speed
|
||||||
if (effectVal>0) {
|
if (effectVal>0) {
|
||||||
curSubSong->arpLen=effectVal;
|
curSubSong->arpLen=effectVal;
|
||||||
|
@ -1105,13 +1119,13 @@ void DivEngine::processRow(int i, bool afterDelay) {
|
||||||
break;
|
break;
|
||||||
case 0xf8: // single volume ramp up
|
case 0xf8: // single volume ramp up
|
||||||
chan[i].volSpeed=0; // add compat flag?
|
chan[i].volSpeed=0; // add compat flag?
|
||||||
chan[i].volume=MIN(chan[i].volume+effectVal*256,chan[i].volMax);
|
chan[i].volume=MIN(chan[i].volume+effectVal*256,chan[i].volTop);
|
||||||
dispatchCmd(DivCommand(DIV_CMD_VOLUME,i,chan[i].volume>>8));
|
dispatchCmd(DivCommand(DIV_CMD_VOLUME,i,chan[i].volume>>8));
|
||||||
dispatchCmd(DivCommand(DIV_CMD_HINT_VOLUME,i,chan[i].volume>>8));
|
dispatchCmd(DivCommand(DIV_CMD_HINT_VOLUME,i,chan[i].volume>>8));
|
||||||
break;
|
break;
|
||||||
case 0xf9: // single volume ramp down
|
case 0xf9: // single volume ramp down
|
||||||
chan[i].volSpeed=0; // add compat flag?
|
chan[i].volSpeed=0; // add compat flag?
|
||||||
chan[i].volume=MAX(chan[i].volume-effectVal*256,0);
|
chan[i].volume=MAX(chan[i].volume-effectVal*256,chan[i].volBottom);
|
||||||
dispatchCmd(DivCommand(DIV_CMD_VOLUME,i,chan[i].volume>>8));
|
dispatchCmd(DivCommand(DIV_CMD_VOLUME,i,chan[i].volume>>8));
|
||||||
dispatchCmd(DivCommand(DIV_CMD_HINT_VOLUME,i,chan[i].volume>>8));
|
dispatchCmd(DivCommand(DIV_CMD_HINT_VOLUME,i,chan[i].volume>>8));
|
||||||
break;
|
break;
|
||||||
|
@ -1598,19 +1612,19 @@ bool DivEngine::nextTick(bool noAccum, bool inhibitLowLat) {
|
||||||
if (chan[i].volSpeed!=0) {
|
if (chan[i].volSpeed!=0) {
|
||||||
chan[i].volume=(chan[i].volume&0xff)|(dispatchCmd(DivCommand(DIV_CMD_GET_VOLUME,i))<<8);
|
chan[i].volume=(chan[i].volume&0xff)|(dispatchCmd(DivCommand(DIV_CMD_GET_VOLUME,i))<<8);
|
||||||
chan[i].volume+=chan[i].volSpeed;
|
chan[i].volume+=chan[i].volSpeed;
|
||||||
if (chan[i].volume>chan[i].volMax) {
|
if (chan[i].volume>chan[i].volTop) {
|
||||||
chan[i].volume=chan[i].volMax;
|
chan[i].volume=chan[i].volTop;
|
||||||
chan[i].volSpeed=0;
|
chan[i].volSpeed=0;
|
||||||
dispatchCmd(DivCommand(DIV_CMD_HINT_VOLUME,i,chan[i].volume>>8));
|
dispatchCmd(DivCommand(DIV_CMD_HINT_VOLUME,i,chan[i].volume>>8));
|
||||||
dispatchCmd(DivCommand(DIV_CMD_VOLUME,i,chan[i].volume>>8));
|
dispatchCmd(DivCommand(DIV_CMD_VOLUME,i,chan[i].volume>>8));
|
||||||
dispatchCmd(DivCommand(DIV_CMD_HINT_VOL_SLIDE,i,0));
|
dispatchCmd(DivCommand(DIV_CMD_HINT_VOL_SLIDE,i,0));
|
||||||
} else if (chan[i].volume<0) {
|
} else if (chan[i].volume<chan[i].volBottom) {
|
||||||
chan[i].volSpeed=0;
|
chan[i].volSpeed=0;
|
||||||
dispatchCmd(DivCommand(DIV_CMD_HINT_VOL_SLIDE,i,0));
|
dispatchCmd(DivCommand(DIV_CMD_HINT_VOL_SLIDE,i,0));
|
||||||
if (song.legacyVolumeSlides) {
|
if (song.legacyVolumeSlides) {
|
||||||
chan[i].volume=chan[i].volMax+1;
|
chan[i].volume=chan[i].volTop+1;
|
||||||
} else {
|
} else {
|
||||||
chan[i].volume=0;
|
chan[i].volume=chan[i].volBottom;
|
||||||
}
|
}
|
||||||
dispatchCmd(DivCommand(DIV_CMD_VOLUME,i,chan[i].volume>>8));
|
dispatchCmd(DivCommand(DIV_CMD_VOLUME,i,chan[i].volume>>8));
|
||||||
dispatchCmd(DivCommand(DIV_CMD_HINT_VOLUME,i,chan[i].volume>>8));
|
dispatchCmd(DivCommand(DIV_CMD_HINT_VOLUME,i,chan[i].volume>>8));
|
||||||
|
@ -1628,7 +1642,6 @@ bool DivEngine::nextTick(bool noAccum, bool inhibitLowLat) {
|
||||||
if (chan[i].panSpeed!=0) {
|
if (chan[i].panSpeed!=0) {
|
||||||
int newPanL=chan[i].panL;
|
int newPanL=chan[i].panL;
|
||||||
int newPanR=chan[i].panR;
|
int newPanR=chan[i].panR;
|
||||||
logV("panSpeed: %d",chan[i].panSpeed);
|
|
||||||
if (chan[i].panSpeed>0) { // right
|
if (chan[i].panSpeed>0) { // right
|
||||||
if (newPanR>=0xff) {
|
if (newPanR>=0xff) {
|
||||||
newPanL-=chan[i].panSpeed;
|
newPanL-=chan[i].panSpeed;
|
||||||
|
@ -1798,6 +1811,15 @@ bool DivEngine::nextTick(bool noAccum, bool inhibitLowLat) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// volume cut/mute
|
||||||
|
if (chan[i].volCut>0) {
|
||||||
|
if (--chan[i].volCut<1) {
|
||||||
|
chan[i].volume=0;
|
||||||
|
dispatchCmd(DivCommand(DIV_CMD_VOLUME,i,chan[i].volume>>8));
|
||||||
|
dispatchCmd(DivCommand(DIV_CMD_HINT_VOLUME,i,chan[i].volume>>8));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// arpeggio
|
// arpeggio
|
||||||
if (chan[i].resetArp) {
|
if (chan[i].resetArp) {
|
||||||
dispatchCmd(DivCommand(DIV_CMD_LEGATO,i,chan[i].note));
|
dispatchCmd(DivCommand(DIV_CMD_LEGATO,i,chan[i].note));
|
||||||
|
|
|
@ -478,11 +478,11 @@ const FurnaceGUIColors fxColors[256]={
|
||||||
GUI_COLOR_PATTERN_EFFECT_INVALID,
|
GUI_COLOR_PATTERN_EFFECT_INVALID,
|
||||||
GUI_COLOR_PATTERN_EFFECT_INVALID,
|
GUI_COLOR_PATTERN_EFFECT_INVALID,
|
||||||
GUI_COLOR_PATTERN_EFFECT_INVALID,
|
GUI_COLOR_PATTERN_EFFECT_INVALID,
|
||||||
|
GUI_COLOR_PATTERN_EFFECT_VOLUME, // D8
|
||||||
|
GUI_COLOR_PATTERN_EFFECT_VOLUME, // D9
|
||||||
GUI_COLOR_PATTERN_EFFECT_INVALID,
|
GUI_COLOR_PATTERN_EFFECT_INVALID,
|
||||||
GUI_COLOR_PATTERN_EFFECT_INVALID,
|
GUI_COLOR_PATTERN_EFFECT_INVALID,
|
||||||
GUI_COLOR_PATTERN_EFFECT_INVALID,
|
GUI_COLOR_PATTERN_EFFECT_VOLUME, // DC
|
||||||
GUI_COLOR_PATTERN_EFFECT_INVALID,
|
|
||||||
GUI_COLOR_PATTERN_EFFECT_INVALID,
|
|
||||||
GUI_COLOR_PATTERN_EFFECT_INVALID,
|
GUI_COLOR_PATTERN_EFFECT_INVALID,
|
||||||
GUI_COLOR_PATTERN_EFFECT_INVALID,
|
GUI_COLOR_PATTERN_EFFECT_INVALID,
|
||||||
GUI_COLOR_PATTERN_EFFECT_MISC, // DF
|
GUI_COLOR_PATTERN_EFFECT_MISC, // DF
|
||||||
|
|
Loading…
Reference in a new issue