add more vibrato shapes

This commit is contained in:
tildearrow 2024-06-24 06:24:14 -05:00
parent 55a8bb2448
commit 2877d488ca
5 changed files with 65 additions and 20 deletions

View file

@ -42,12 +42,21 @@ however, effects are continuous (unless specified), which means you only need to
- `00xy`: **Arpeggio.** this effect produces a rapid cycle between the current note, the note plus `x` semitones and the note plus `y` semitones. - `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. - `E0xx`: **Set arpeggio speed.** this sets the number of ticks between arpeggio values. default is 1.
- --- - ---
- `04xy`: **Vibrato.** changes pitch to be "wavy" with a sine LFO. `x` is the speed, while `y` is the depth. - `04xy`: **Vibrato.** makes the pitch oscillate. `x` is the speed, while `y` is the depth.
- maximum vibrato depth is ±1 semitone. - maximum vibrato depth is ±1 semitone.
- `E3xx`: **Set vibrato direction.** `xx` may be one of the following: - `E3xx`: **Set vibrato shape.** `xx` may be one of the following:
- `00`: up and down. default. - `00`: sine (default)
- `01`: up only. - `01`: sine (upper portion only)
- `02`: down only. - `02`: sine (lower portion only)
- `03`: triangle
- `04`: ramp up
- `05`: ramp down
- `06`: square
- `07`: random
- `08`: square (up)
- `09`: square (down)
- `0a`: half sine (up)
- `0b`: half sine (down)
- `E4xx`: **Set vibrato range** in 1/16th of a semitone. - `E4xx`: **Set vibrato range** in 1/16th of a semitone.
## panning ## panning

View file

@ -101,7 +101,7 @@ const char* DivEngine::getEffectDesc(unsigned char effect, int chan, bool notNul
case 0xe2: case 0xe2:
return _("E2xy: Note slide down (x: speed; y: semitones)"); return _("E2xy: Note slide down (x: speed; y: semitones)");
case 0xe3: case 0xe3:
return _("E3xx: Set vibrato shape (0: up/down; 1: up only; 2: down only)"); return _("E3xx: Set vibrato shape");
case 0xe4: case 0xe4:
return _("E4xx: Set vibrato range"); return _("E4xx: Set vibrato range");
case 0xe5: case 0xe5:

View file

@ -135,7 +135,7 @@ struct DivChannelState {
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, legatoDelay, legatoTarget, rowDelay, volMax;
int delayOrder, delayRow, retrigSpeed, retrigTick; int delayOrder, delayRow, retrigSpeed, retrigTick;
int vibratoDepth, vibratoRate, vibratoPos, vibratoPosGiant, vibratoDir, vibratoFine; int vibratoDepth, vibratoRate, vibratoPos, vibratoPosGiant, vibratoShape, vibratoFine;
int tremoloDepth, tremoloRate, tremoloPos; int tremoloDepth, tremoloRate, tremoloPos;
int sampleOff; int sampleOff;
unsigned char arp, arpStage, arpTicks, panL, panR, panRL, panRR, lastVibrato, lastPorta, cutType; unsigned char arp, arpStage, arpTicks, panL, panR, panRL, panRR, lastVibrato, lastPorta, cutType;
@ -169,7 +169,7 @@ struct DivChannelState {
vibratoRate(0), vibratoRate(0),
vibratoPos(0), vibratoPos(0),
vibratoPosGiant(0), vibratoPosGiant(0),
vibratoDir(0), vibratoShape(0),
vibratoFine(15), vibratoFine(15),
tremoloDepth(0), tremoloDepth(0),
tremoloRate(0), tremoloRate(0),

View file

@ -951,9 +951,9 @@ void DivEngine::processRow(int i, bool afterDelay) {
if (!song.brokenShortcutSlides) dispatchCmd(DivCommand(DIV_CMD_PRE_PORTA,i,false,0)); if (!song.brokenShortcutSlides) dispatchCmd(DivCommand(DIV_CMD_PRE_PORTA,i,false,0));
} }
break; break;
case 0xe3: // vibrato direction case 0xe3: // vibrato shape
chan[i].vibratoDir=effectVal; chan[i].vibratoShape=effectVal;
dispatchCmd(DivCommand(DIV_CMD_HINT_VIBRATO_SHAPE,i,chan[i].vibratoDir)); dispatchCmd(DivCommand(DIV_CMD_HINT_VIBRATO_SHAPE,i,chan[i].vibratoShape));
break; break;
case 0xe4: // vibrato fine case 0xe4: // vibrato fine
chan[i].vibratoFine=effectVal; chan[i].vibratoFine=effectVal;
@ -1579,19 +1579,55 @@ bool DivEngine::nextTick(bool noAccum, bool inhibitLowLat) {
while (chan[i].vibratoPos>=64) chan[i].vibratoPos-=64; while (chan[i].vibratoPos>=64) chan[i].vibratoPos-=64;
chan[i].vibratoPosGiant+=chan[i].vibratoRate; chan[i].vibratoPosGiant+=chan[i].vibratoRate;
while (chan[i].vibratoPos>=512) chan[i].vibratoPos-=512; while (chan[i].vibratoPosGiant>=512) chan[i].vibratoPosGiant-=512;
switch (chan[i].vibratoDir) { int vibratoOut=0;
case 1: // up switch (chan[i].vibratoShape) {
dispatchCmd(DivCommand(DIV_CMD_PITCH,i,chan[i].pitch+(MAX(0,(chan[i].vibratoDepth*vibTable[chan[i].vibratoPos]*chan[i].vibratoFine)>>4)/15))); case 1: // sine, up only
vibratoOut=MAX(0,vibTable[chan[i].vibratoPos]);
break; break;
case 2: // down case 2: // sine, down only
dispatchCmd(DivCommand(DIV_CMD_PITCH,i,chan[i].pitch+(MIN(0,(chan[i].vibratoDepth*vibTable[chan[i].vibratoPos]*chan[i].vibratoFine)>>4)/15))); vibratoOut=MIN(0,vibTable[chan[i].vibratoPos]);
break; break;
default: // both case 3: // triangle
dispatchCmd(DivCommand(DIV_CMD_PITCH,i,chan[i].pitch+(((chan[i].vibratoDepth*vibTable[chan[i].vibratoPos]*chan[i].vibratoFine)>>4)/15))); vibratoOut=(chan[i].vibratoPos&31);
if (chan[i].vibratoPos&16) {
vibratoOut=32-(chan[i].vibratoPos&31);
}
if (chan[i].vibratoPos&32) {
vibratoOut=-vibratoOut;
}
vibratoOut<<=3;
break;
case 4: // ramp up
vibratoOut=chan[i].vibratoPos<<1;
break;
case 5: // ramp down
vibratoOut=-chan[i].vibratoPos<<1;
break;
case 6: // square
vibratoOut=(chan[i].vibratoPos>=32)?-127:127;
break;
case 7: // random (TODO: use LFSR)
vibratoOut=(rand()&255)-128;
break;
case 8: // square up
vibratoOut=(chan[i].vibratoPos>=32)?0:127;
break;
case 9: // square down
vibratoOut=(chan[i].vibratoPos>=32)?0:-127;
break;
case 10: // half sine up
vibratoOut=vibTable[chan[i].vibratoPos>>1];
break;
case 11: // half sine down
vibratoOut=vibTable[32|(chan[i].vibratoPos>>1)];
break;
default: // sine
vibratoOut=vibTable[chan[i].vibratoPos];
break; break;
} }
dispatchCmd(DivCommand(DIV_CMD_PITCH,i,chan[i].pitch+(((chan[i].vibratoDepth*vibratoOut*chan[i].vibratoFine)>>4)/15)));
} }
if (chan[i].legatoDelay>0) { if (chan[i].legatoDelay>0) {
if (--chan[i].legatoDelay<1) { if (--chan[i].legatoDelay<1) {

View file

@ -155,7 +155,7 @@ void FurnaceGUI::drawDebug() {
ImGui::Text("- depth = %d",ch->vibratoDepth); ImGui::Text("- depth = %d",ch->vibratoDepth);
ImGui::Text("- rate = %d",ch->vibratoRate); ImGui::Text("- rate = %d",ch->vibratoRate);
ImGui::Text("- pos = %d",ch->vibratoPos); ImGui::Text("- pos = %d",ch->vibratoPos);
ImGui::Text("- dir = %d",ch->vibratoDir); ImGui::Text("- shape = %d",ch->vibratoShape);
ImGui::Text("- fine = %d",ch->vibratoFine); ImGui::Text("- fine = %d",ch->vibratoFine);
ImGui::PopStyleColor(); ImGui::PopStyleColor();
ImGui::PushStyleColor(ImGuiCol_Text,(ch->tremoloDepth>0)?uiColors[GUI_COLOR_MACRO_VOLUME]:uiColors[GUI_COLOR_TEXT]); ImGui::PushStyleColor(ImGuiCol_Text,(ch->tremoloDepth>0)?uiColors[GUI_COLOR_MACRO_VOLUME]:uiColors[GUI_COLOR_TEXT]);