mirror of
https://github.com/tildearrow/furnace.git
synced 2024-11-01 18:42:40 +00:00
add effects for quick legato
This commit is contained in:
parent
beacfcf849
commit
415a8297fe
5 changed files with 60 additions and 4 deletions
|
@ -34,6 +34,11 @@ however, effects are continuous, which means you only need to type it once and t
|
|||
- `E2xy`: **Note slide down.** `x` is the speed, while `y` is how many semitones to slide down.
|
||||
- ---
|
||||
- `EAxx`: **Toggle legato.** while on, new notes instantly change the pitch of the currently playing sound instead of starting it over.
|
||||
- `E6xy`: **Quick legato (compatibility).** transposes note by `y` semitones after `x` ticks.
|
||||
- if `x` is between 0 and 7, it transposes up.
|
||||
- if `x` is between 8 and F, it transposes down.
|
||||
- `E8xy`: **Quick legato up**. transposes note up by `y` semitones after `x` ticks.
|
||||
- `E9xy`: **Quick legato down**. transposes note down by `y` semitones after `x` ticks.
|
||||
- `00xy`: **Arpeggio.** this effect produces a rapid cycle between the current note, the note plus `x` semitones and the note plus `y` semitones.
|
||||
- `E0xx`: **Set arpeggio speed.** this sets the number of ticks between arpeggio values. default is 1.
|
||||
- ---
|
||||
|
|
|
@ -105,8 +105,14 @@ const char* DivEngine::getEffectDesc(unsigned char effect, int chan, bool notNul
|
|||
return "E4xx: Set vibrato range";
|
||||
case 0xe5:
|
||||
return "E5xx: Set pitch (80: center)";
|
||||
case 0xe6:
|
||||
return "E6xy: Quick legato (x: time (0-7 up; 8-F down); y: semitones)";
|
||||
case 0xe7:
|
||||
return "E7xx: Macro release";
|
||||
case 0xe8:
|
||||
return "E8xy: Quick legato up (x: time; y: semitones)";
|
||||
case 0xe9:
|
||||
return "E9xy: Quick legato down (x: time; y: semitones)";
|
||||
case 0xea:
|
||||
return "EAxx: Legato";
|
||||
case 0xeb:
|
||||
|
|
|
@ -100,7 +100,7 @@ enum DivMIDIModes {
|
|||
struct DivChannelState {
|
||||
std::vector<DivDelayedCommand> delayed;
|
||||
int note, oldNote, lastIns, pitch, portaSpeed, portaNote;
|
||||
int volume, volSpeed, cut, rowDelay, volMax;
|
||||
int volume, volSpeed, cut, legatoDelay, legatoTarget, rowDelay, volMax;
|
||||
int delayOrder, delayRow, retrigSpeed, retrigTick;
|
||||
int vibratoDepth, vibratoRate, vibratoPos, vibratoPosGiant, vibratoDir, vibratoFine;
|
||||
int tremoloDepth, tremoloRate, tremoloPos;
|
||||
|
@ -123,6 +123,8 @@ struct DivChannelState {
|
|||
volume(0x7f00),
|
||||
volSpeed(0),
|
||||
cut(-1),
|
||||
legatoDelay(-1),
|
||||
legatoTarget(0),
|
||||
rowDelay(0),
|
||||
volMax(0),
|
||||
delayOrder(0),
|
||||
|
|
|
@ -956,6 +956,21 @@ void DivEngine::processRow(int i, bool afterDelay) {
|
|||
dispatchCmd(DivCommand(DIV_CMD_PITCH,i,chan[i].pitch+(((chan[i].vibratoDepth*vibTable[chan[i].vibratoPos]*chan[i].vibratoFine)>>4)/15)));
|
||||
dispatchCmd(DivCommand(DIV_CMD_HINT_PITCH,i,chan[i].pitch));
|
||||
break;
|
||||
case 0xe6: // Delayed legato
|
||||
// why does this have to follow FamiTracker verbatim
|
||||
// couldn't you do better?
|
||||
if ((effectVal&15)!=0) {
|
||||
chan[i].legatoDelay=(((effectVal&0xf0)>>4)&7)+1;
|
||||
if (effectVal&128) {
|
||||
chan[i].legatoTarget=-(effectVal&15);
|
||||
} else {
|
||||
chan[i].legatoTarget=(effectVal&15);
|
||||
}
|
||||
} else {
|
||||
chan[i].legatoDelay=-1;
|
||||
chan[i].legatoTarget=0;
|
||||
}
|
||||
break;
|
||||
case 0xe7: // delayed macro release
|
||||
// "Bruh"
|
||||
if (effectVal>0 && (song.delayBehavior==2 || effectVal<nextSpeed)) {
|
||||
|
@ -963,6 +978,25 @@ void DivEngine::processRow(int i, bool afterDelay) {
|
|||
chan[i].cutType=2;
|
||||
}
|
||||
break;
|
||||
case 0xe8: // delayed legato up
|
||||
// see? you COULD do better!
|
||||
if ((effectVal&15)!=0) {
|
||||
chan[i].legatoDelay=((effectVal&0xf0)>>4)+1;
|
||||
chan[i].legatoTarget=(effectVal&15);
|
||||
} else {
|
||||
chan[i].legatoDelay=-1;
|
||||
chan[i].legatoTarget=0;
|
||||
}
|
||||
break;
|
||||
case 0xe9: // delayed legato down
|
||||
if ((effectVal&15)!=0) {
|
||||
chan[i].legatoDelay=((effectVal&0xf0)>>4)+1;
|
||||
chan[i].legatoTarget=-(effectVal&15);
|
||||
} else {
|
||||
chan[i].legatoDelay=-1;
|
||||
chan[i].legatoTarget=0;
|
||||
}
|
||||
break;
|
||||
case 0xea: // legato mode
|
||||
chan[i].legato=effectVal;
|
||||
break;
|
||||
|
@ -1539,6 +1573,15 @@ bool DivEngine::nextTick(bool noAccum, bool inhibitLowLat) {
|
|||
break;
|
||||
}
|
||||
}
|
||||
if (chan[i].legatoDelay>0) {
|
||||
if (--chan[i].legatoDelay<1) {
|
||||
chan[i].note+=chan[i].legatoTarget;
|
||||
dispatchCmd(DivCommand(DIV_CMD_LEGATO,i,chan[i].note));
|
||||
dispatchCmd(DivCommand(DIV_CMD_HINT_LEGATO,i,chan[i].note));
|
||||
chan[i].legatoDelay=-1;
|
||||
chan[i].legatoTarget=0;
|
||||
}
|
||||
}
|
||||
if (!song.noSlidesOnFirstTick || !firstTick) {
|
||||
if ((chan[i].keyOn || chan[i].keyOff) && chan[i].portaSpeed>0) {
|
||||
if (dispatchCmd(DivCommand(DIV_CMD_NOTE_PORTA,i,chan[i].portaSpeed*(song.linearPitch==2?song.pitchSlideSpeed:1),chan[i].portaNote))==2 && chan[i].portaStop && song.targetResetsSlides) {
|
||||
|
|
|
@ -489,10 +489,10 @@ const FurnaceGUIColors fxColors[256]={
|
|||
GUI_COLOR_PATTERN_EFFECT_MISC, // E3
|
||||
GUI_COLOR_PATTERN_EFFECT_MISC, // E4
|
||||
GUI_COLOR_PATTERN_EFFECT_PITCH, // E5
|
||||
GUI_COLOR_PATTERN_EFFECT_INVALID, // E6
|
||||
GUI_COLOR_PATTERN_EFFECT_MISC, // E6
|
||||
GUI_COLOR_PATTERN_EFFECT_TIME, // E7
|
||||
GUI_COLOR_PATTERN_EFFECT_INVALID, // E8
|
||||
GUI_COLOR_PATTERN_EFFECT_INVALID, // E9
|
||||
GUI_COLOR_PATTERN_EFFECT_MISC, // E8
|
||||
GUI_COLOR_PATTERN_EFFECT_MISC, // E9
|
||||
GUI_COLOR_PATTERN_EFFECT_MISC, // EA
|
||||
GUI_COLOR_PATTERN_EFFECT_MISC, // EB
|
||||
GUI_COLOR_PATTERN_EFFECT_TIME, // EC
|
||||
|
|
Loading…
Reference in a new issue