mirror of
https://github.com/tildearrow/furnace.git
synced 2025-01-07 16:12:31 +00:00
effects for controlling volume slides
This commit is contained in:
parent
f0f0b7fcd6
commit
629667d460
5 changed files with 31 additions and 10 deletions
|
@ -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.
|
||||
- `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.
|
||||
- tremolo is downward only.
|
||||
- maximum tremolo depth is -60 volume steps.
|
||||
|
|
|
@ -98,6 +98,10 @@ const char* DivEngine::getEffectDesc(unsigned char effect, int chan, bool notNul
|
|||
break;
|
||||
case 0xc0: case 0xc1: case 0xc2: case 0xc3:
|
||||
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:
|
||||
|
@ -2110,6 +2114,7 @@ void DivEngine::reset() {
|
|||
chan[i]=DivChannelState();
|
||||
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].volTop=chan[i].volMax;
|
||||
if (song.linearPitch==0) chan[i].vibratoFine=4;
|
||||
}
|
||||
extValue=0;
|
||||
|
|
|
@ -133,7 +133,7 @@ struct DivAudioExportOptions {
|
|||
struct DivChannelState {
|
||||
std::vector<DivDelayedCommand> delayed;
|
||||
int note, oldNote, lastIns, pitch, portaSpeed, portaNote;
|
||||
int volume, volSpeed, cut, volCut, legatoDelay, legatoTarget, rowDelay, volMax;
|
||||
int volume, volSpeed, cut, volCut, legatoDelay, legatoTarget, rowDelay, volMax, volBottom, volTop;
|
||||
int delayOrder, delayRow, retrigSpeed, retrigTick;
|
||||
int vibratoDepth, vibratoRate, vibratoPos, vibratoPosGiant, vibratoShape, vibratoFine;
|
||||
int tremoloDepth, tremoloRate, tremoloPos;
|
||||
|
@ -163,6 +163,8 @@ struct DivChannelState {
|
|||
legatoTarget(0),
|
||||
rowDelay(0),
|
||||
volMax(0),
|
||||
volBottom(0),
|
||||
volTop(0),
|
||||
delayOrder(0),
|
||||
delayRow(0),
|
||||
retrigSpeed(0),
|
||||
|
|
|
@ -932,6 +932,14 @@ void DivEngine::processRow(int i, bool afterDelay) {
|
|||
clockDrift=0;
|
||||
subticks=0;
|
||||
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;
|
||||
|
@ -1095,13 +1103,13 @@ void DivEngine::processRow(int i, bool afterDelay) {
|
|||
break;
|
||||
case 0xf8: // single volume ramp up
|
||||
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_HINT_VOLUME,i,chan[i].volume>>8));
|
||||
break;
|
||||
case 0xf9: // single volume ramp down
|
||||
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_HINT_VOLUME,i,chan[i].volume>>8));
|
||||
break;
|
||||
|
@ -1588,19 +1596,19 @@ bool DivEngine::nextTick(bool noAccum, bool inhibitLowLat) {
|
|||
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].volSpeed;
|
||||
if (chan[i].volume>chan[i].volMax) {
|
||||
chan[i].volume=chan[i].volMax;
|
||||
if (chan[i].volume>chan[i].volTop) {
|
||||
chan[i].volume=chan[i].volTop;
|
||||
chan[i].volSpeed=0;
|
||||
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_HINT_VOL_SLIDE,i,0));
|
||||
} else if (chan[i].volume<0) {
|
||||
} else if (chan[i].volume<chan[i].volBottom) {
|
||||
chan[i].volSpeed=0;
|
||||
dispatchCmd(DivCommand(DIV_CMD_HINT_VOL_SLIDE,i,0));
|
||||
if (song.legacyVolumeSlides) {
|
||||
chan[i].volume=chan[i].volMax+1;
|
||||
chan[i].volume=chan[i].volTop+1;
|
||||
} 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_HINT_VOLUME,i,chan[i].volume>>8));
|
||||
|
|
|
@ -478,8 +478,8 @@ 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_VOLUME, // D8
|
||||
GUI_COLOR_PATTERN_EFFECT_VOLUME, // D9
|
||||
GUI_COLOR_PATTERN_EFFECT_INVALID,
|
||||
GUI_COLOR_PATTERN_EFFECT_INVALID,
|
||||
GUI_COLOR_PATTERN_EFFECT_VOLUME, // DC
|
||||
|
|
Loading…
Reference in a new issue