aboutsummaryrefslogtreecommitdiff
path: root/sound/mods
diff options
context:
space:
mode:
Diffstat (limited to 'sound/mods')
-rw-r--r--sound/mods/module.cpp111
-rw-r--r--sound/mods/module.h6
-rw-r--r--sound/mods/protracker.cpp263
3 files changed, 281 insertions, 99 deletions
diff --git a/sound/mods/module.cpp b/sound/mods/module.cpp
index 088522bc3a..fdd20cc01f 100644
--- a/sound/mods/module.cpp
+++ b/sound/mods/module.cpp
@@ -29,6 +29,88 @@
namespace Modules {
+const int16 Module::periods[16][60] = {
+ {1712, 1616, 1524, 1440, 1356, 1280, 1208, 1140, 1076, 1016, 960 , 906,
+ 856 , 808 , 762 , 720 , 678 , 640 , 604 , 570 , 538 , 508 , 480 , 453,
+ 428 , 404 , 381 , 360 , 339 , 320 , 302 , 285 , 269 , 254 , 240 , 226,
+ 214 , 202 , 190 , 180 , 170 , 160 , 151 , 143 , 135 , 127 , 120 , 113,
+ 107 , 101 , 95 , 90 , 85 , 80 , 75 , 71 , 67 , 63 , 60 , 56 },
+ {1700, 1604, 1514, 1430, 1348, 1274, 1202, 1134, 1070, 1010, 954 , 900,
+ 850 , 802 , 757 , 715 , 674 , 637 , 601 , 567 , 535 , 505 , 477 , 450,
+ 425 , 401 , 379 , 357 , 337 , 318 , 300 , 284 , 268 , 253 , 239 , 225,
+ 213 , 201 , 189 , 179 , 169 , 159 , 150 , 142 , 134 , 126 , 119 , 113,
+ 106 , 100 , 94 , 89 , 84 , 79 , 75 , 71 , 67 , 63 , 59 , 56 },
+ {1688, 1592, 1504, 1418, 1340, 1264, 1194, 1126, 1064, 1004, 948 , 894,
+ 844 , 796 , 752 , 709 , 670 , 632 , 597 , 563 , 532 , 502 , 474 , 447,
+ 422 , 398 , 376 , 355 , 335 , 316 , 298 , 282 , 266 , 251 , 237 , 224,
+ 211 , 199 , 188 , 177 , 167 , 158 , 149 , 141 , 133 , 125 , 118 , 112,
+ 105 , 99 , 94 , 88 , 83 , 79 , 74 , 70 , 66 , 62 , 59 , 56 },
+ {1676, 1582, 1492, 1408, 1330, 1256, 1184, 1118, 1056, 996 , 940 , 888,
+ 838 , 791 , 746 , 704 , 665 , 628 , 592 , 559 , 528 , 498 , 470 , 444,
+ 419 , 395 , 373 , 352 , 332 , 314 , 296 , 280 , 264 , 249 , 235 , 222,
+ 209 , 198 , 187 , 176 , 166 , 157 , 148 , 140 , 132 , 125 , 118 , 111,
+ 104 , 99 , 93 , 88 , 83 , 78 , 74 , 70 , 66 , 62 , 59 , 55 },
+ {1664, 1570, 1482, 1398, 1320, 1246, 1176, 1110, 1048, 990 , 934 , 882,
+ 832 , 785 , 741 , 699 , 660 , 623 , 588 , 555 , 524 , 495 , 467 , 441,
+ 416 , 392 , 370 , 350 , 330 , 312 , 294 , 278 , 262 , 247 , 233 , 220,
+ 208 , 196 , 185 , 175 , 165 , 156 , 147 , 139 , 131 , 124 , 117 , 110,
+ 104 , 98 , 92 , 87 , 82 , 78 , 73 , 69 , 65 , 62 , 58 , 55 },
+ {1652, 1558, 1472, 1388, 1310, 1238, 1168, 1102, 1040, 982 , 926 , 874,
+ 826 , 779 , 736 , 694 , 655 , 619 , 584 , 551 , 520 , 491 , 463 , 437,
+ 413 , 390 , 368 , 347 , 328 , 309 , 292 , 276 , 260 , 245 , 232 , 219,
+ 206 , 195 , 184 , 174 , 164 , 155 , 146 , 138 , 130 , 123 , 116 , 109,
+ 103 , 97 , 92 , 87 , 82 , 77 , 73 , 69 , 65 , 61 , 58 , 54 },
+ {1640, 1548, 1460, 1378, 1302, 1228, 1160, 1094, 1032, 974 , 920 , 868,
+ 820 , 774 , 730 , 689 , 651 , 614 , 580 , 547 , 516 , 487 , 460 , 434,
+ 410 , 387 , 365 , 345 , 325 , 307 , 290 , 274 , 258 , 244 , 230 , 217,
+ 205 , 193 , 183 , 172 , 163 , 154 , 145 , 137 , 129 , 122 , 115 , 109,
+ 102 , 96 , 91 , 86 , 81 , 77 , 72 , 68 , 64 , 61 , 57 , 54 },
+ {1628, 1536, 1450, 1368, 1292, 1220, 1150, 1086, 1026, 968 , 914 , 862,
+ 814 , 768 , 725 , 684 , 646 , 610 , 575 , 543 , 513 , 484 , 457 , 431,
+ 407 , 384 , 363 , 342 , 323 , 305 , 288 , 272 , 256 , 242 , 228 , 216,
+ 204 , 192 , 181 , 171 , 161 , 152 , 144 , 136 , 128 , 121 , 114 , 108,
+ 102 , 96 , 90 , 85 , 80 , 76 , 72 , 68 , 64 , 60 , 57 , 54 },
+ {1814, 1712, 1616, 1524, 1440, 1356, 1280, 1208, 1140, 1076, 1016, 960,
+ 907 , 856 , 808 , 762 , 720 , 678 , 640 , 604 , 570 , 538 , 508 , 480,
+ 453 , 428 , 404 , 381 , 360 , 339 , 320 , 302 , 285 , 269 , 254 , 240,
+ 226 , 214 , 202 , 190 , 180 , 170 , 160 , 151 , 143 , 135 , 127 , 120,
+ 113 , 107 , 101 , 95 , 90 , 85 , 80 , 75 , 71 , 67 , 63 , 60 },
+ {1800, 1700, 1604, 1514, 1430, 1350, 1272, 1202, 1134, 1070, 1010, 954,
+ 900 , 850 , 802 , 757 , 715 , 675 , 636 , 601 , 567 , 535 , 505 , 477,
+ 450 , 425 , 401 , 379 , 357 , 337 , 318 , 300 , 284 , 268 , 253 , 238,
+ 225 , 212 , 200 , 189 , 179 , 169 , 159 , 150 , 142 , 134 , 126 , 119,
+ 112 , 106 , 100 , 94 , 89 , 84 , 79 , 75 , 71 , 67 , 63 , 59 },
+ {1788, 1688, 1592, 1504, 1418, 1340, 1264, 1194, 1126, 1064, 1004, 948,
+ 894 , 844 , 796 , 752 , 709 , 670 , 632 , 597 , 563 , 532 , 502 , 474,
+ 447 , 422 , 398 , 376 , 355 , 335 , 316 , 298 , 282 , 266 , 251 , 237,
+ 223 , 211 , 199 , 188 , 177 , 167 , 158 , 149 , 141 , 133 , 125 , 118,
+ 111 , 105 , 99 , 94 , 88 , 83 , 79 , 74 , 70 , 66 , 62 , 59 },
+ {1774, 1676, 1582, 1492, 1408, 1330, 1256, 1184, 1118, 1056, 996 , 940,
+ 887 , 838 , 791 , 746 , 704 , 665 , 628 , 592 , 559 , 528 , 498 , 470,
+ 444 , 419 , 395 , 373 , 352 , 332 , 314 , 296 , 280 , 264 , 249 , 235,
+ 222 , 209 , 198 , 187 , 176 , 166 , 157 , 148 , 140 , 132 , 125 , 118,
+ 111 , 104 , 99 , 93 , 88 , 83 , 78 , 74 , 70 , 66 , 62 , 59 },
+ {1762, 1664, 1570, 1482, 1398, 1320, 1246, 1176, 1110, 1048, 988 , 934,
+ 881 , 832 , 785 , 741 , 699 , 660 , 623 , 588 , 555 , 524 , 494 , 467,
+ 441 , 416 , 392 , 370 , 350 , 330 , 312 , 294 , 278 , 262 , 247 , 233,
+ 220 , 208 , 196 , 185 , 175 , 165 , 156 , 147 , 139 , 131 , 123 , 117,
+ 110 , 104 , 98 , 92 , 87 , 82 , 78 , 73 , 69 , 65 , 61 , 58 },
+ {1750, 1652, 1558, 1472, 1388, 1310, 1238, 1168, 1102, 1040, 982 , 926,
+ 875 , 826 , 779 , 736 , 694 , 655 , 619 , 584 , 551 , 520 , 491 , 463,
+ 437 , 413 , 390 , 368 , 347 , 328 , 309 , 292 , 276 , 260 , 245 , 232,
+ 219 , 206 , 195 , 184 , 174 , 164 , 155 , 146 , 138 , 130 , 123 , 116,
+ 109 , 103 , 97 , 92 , 87 , 82 , 77 , 73 , 69 , 65 , 61 , 58 },
+ {1736, 1640, 1548, 1460, 1378, 1302, 1228, 1160, 1094, 1032, 974 , 920,
+ 868 , 820 , 774 , 730 , 689 , 651 , 614 , 580 , 547 , 516 , 487 , 460,
+ 434 , 410 , 387 , 365 , 345 , 325 , 307 , 290 , 274 , 258 , 244 , 230,
+ 217 , 205 , 193 , 183 , 172 , 163 , 154 , 145 , 137 , 129 , 122 , 115,
+ 108 , 102 , 96 , 91 , 86 , 81 , 77 , 72 , 68 , 64 , 61 , 57 },
+ {1724, 1628, 1536, 1450, 1368, 1292, 1220, 1150, 1086, 1026, 968 , 914,
+ 862 , 814 , 768 , 725 , 684 , 646 , 610 , 575 , 543 , 513 , 484 , 457,
+ 431 , 407 , 384 , 363 , 342 , 323 , 305 , 288 , 272 , 256 , 242 , 228,
+ 216 , 203 , 192 , 181 , 171 , 161 , 152 , 144 , 136 , 128 , 121 , 114,
+ 108 , 101 , 96 , 90 , 85 , 80 , 76 , 72 , 68 , 64 , 60 , 57 }};
+
bool Module::load(Common::ReadStream &st) {
st.read(songname, 20);
songname[20] = '\0';
@@ -70,6 +152,7 @@ bool Module::load(Common::ReadStream &st) {
pattern[i][j][k].sample = (note & 0xf0000000) >> 24 | (note & 0x0000f000) >> 12;
pattern[i][j][k].period = (note >> 16) & 0xfff;
pattern[i][j][k].effect = note & 0xfff;
+ pattern[i][j][k].note = periodToNote((note >> 16) & 0xfff);
}
}
}
@@ -103,4 +186,32 @@ Module::~Module() {
}
}
+byte Module::periodToNote(int16 period, byte finetune) {
+ int16 diff1;
+ int16 diff2;
+
+ diff1 = ABS(periods[finetune][0] - period);
+ if (diff1 == 0)
+ return 0;
+
+ for (int i = 1; i < 60; i++) {
+ diff2 = ABS(periods[finetune][i] - period);
+ if (diff2 == 0)
+ return i;
+ else if (diff2 > diff1)
+ return i-1;
+ diff1 = diff2;
+ }
+ return 59;
+}
+
+int16 Module::noteToPeriod(byte note, byte finetune) {
+ if (finetune > 15)
+ finetune = 15;
+ if (note > 59)
+ note = 59;
+
+ return periods[finetune][note];
+}
+
} // End of namespace Modules
diff --git a/sound/mods/module.h b/sound/mods/module.h
index b62a8f47cb..c302d490b1 100644
--- a/sound/mods/module.h
+++ b/sound/mods/module.h
@@ -32,6 +32,7 @@ namespace Modules {
struct note_t {
byte sample;
+ byte note;
uint16 period;
uint16 effect;
};
@@ -67,6 +68,11 @@ public:
~Module();
bool load(Common::ReadStream &stream);
+ byte static periodToNote(int16 period, byte finetune = 0);
+ int16 static noteToPeriod(byte note, byte finetune = 0);
+
+private:
+ static const int16 periods[16][60];
};
} // End of namespace Modules
diff --git a/sound/mods/protracker.cpp b/sound/mods/protracker.cpp
index 31f2264f8a..0274551c7a 100644
--- a/sound/mods/protracker.cpp
+++ b/sound/mods/protracker.cpp
@@ -41,8 +41,6 @@ private:
int _row;
int _pos;
- int _patternDelay;
-
int _speed;
int _bpm;
@@ -59,12 +57,22 @@ private:
int _patternLoopCount;
int _patternLoopRow;
+ // For effect 0xEE - Pattern Delay
+ byte _patternDelay;
+
+ static const int16 sinetable[];
+
struct {
byte sample;
uint16 period;
double offset;
byte vol;
+ byte finetune;
+
+ // For effect 0x0 - Arpeggio
+ bool arpeggio;
+ byte arpeggioNotes[3];
// For effect 0x3 - Porta to note
uint16 portaToNote;
@@ -75,6 +83,10 @@ private:
byte vibratoPos;
byte vibratoSpeed;
byte vibratoDepth;
+
+ // For effect 0xED - Delay sample
+ byte delaySample;
+ byte delaySampleTick;
} _track[4];
public:
@@ -84,11 +96,56 @@ private:
void startPlay() { _playing = true; _end = false; }
void interrupt();
+ void doPorta(int track) {
+ if (_track[track].portaToNote && _track[track].portaToNoteSpeed) {
+ if (_track[track].period < _track[track].portaToNote) {
+ _track[track].period += _track[track].portaToNoteSpeed;
+ if (_track[track].period > _track[track].portaToNote)
+ _track[track].period = _track[track].portaToNote;
+ } else if (_track[track].period > _track[track].portaToNote) {
+ _track[track].period -= _track[track].portaToNoteSpeed;
+ if (_track[track].period < _track[track].portaToNote)
+ _track[track].period = _track[track].portaToNote;
+ }
+ }
+ }
+ void doVibrato(int track) {
+ _track[track].vibrato =
+ (_track[track].vibratoDepth * sinetable[_track[track].vibratoPos]) / 128;
+ _track[track].vibratoPos += _track[track].vibratoSpeed;
+ _track[track].vibratoPos %= 64;
+ }
+ void doVolSlide(int track, byte ex, byte ey) {
+ int vol = _track[track].vol;
+ if (ex == 0)
+ vol -= ey;
+ else if (ey == 0)
+ vol += ex;
+
+ if (vol < 0)
+ vol = 0;
+ else if (vol > 64)
+ vol = 64;
+
+ _track[track].vol = vol;
+ }
+
void updateRow();
void updateEffects();
};
+const int16 ProtrackerStream::sinetable[64] = {
+ 0, 24, 49, 74, 97, 120, 141, 161,
+ 180, 197, 212, 224, 235, 244, 250, 253,
+ 255, 253, 250, 244, 235, 224, 212, 197,
+ 180, 161, 141, 120, 97, 74, 49, 24,
+ 0, -24, -49, -74, -97, -120, -141, -161,
+ -180, -197, -212, -224, -235, -244, -250, -253,
+ -255, -253, -250, -244, -235, -224, -212, -197,
+ -180, -161, -141, -120, -97, -74, -49, -24
+};
+
ProtrackerStream::ProtrackerStream(Common::ReadStream *stream, int rate, bool stereo) :
Paula(stereo, rate, rate/50) {
_module = new Module();
@@ -111,6 +168,8 @@ ProtrackerStream::ProtrackerStream(Common::ReadStream *stream, int rate, bool st
_track[t].period = 0;
_track[t].offset = 0.0;
_track[t].vibrato = 0;
+ _track[t].delaySampleTick = 0;
+ _track[t].arpeggio = false;
}
startPlay();
@@ -118,7 +177,9 @@ ProtrackerStream::ProtrackerStream(Common::ReadStream *stream, int rate, bool st
void ProtrackerStream::updateRow() {
for (int track = 0; track < 4; track++) {
+ _track[track].arpeggio = false;
_track[track].vibrato = 0;
+ _track[track].delaySampleTick = 0;
note_t note =
_module->pattern[_module->songpos[_pos]][_row][track];
@@ -129,21 +190,36 @@ void ProtrackerStream::updateRow() {
_track[track].vibratoPos = 0;
}
_track[track].sample = note.sample;
+ _track[track].finetune = _module->sample[note.sample - 1].finetune;
_track[track].vol = _module->sample[note.sample - 1].vol;
}
+
if (note.period) {
if (effect != 3 && effect != 5) {
- _track[track].period = note.period;
+ if (_track[track].finetune)
+ _track[track].period = _module->noteToPeriod(note.note, _track[track].finetune);
+ else
+ _track[track].period = note.period;
_track[track].offset = 0.0;
}
}
int exy = note.effect & 0xff;
+ if (exy);
int ex = (note.effect >> 4) & 0xf;
int ey = note.effect & 0xf;
+ int vol;
switch (effect) {
case 0x0:
+ if (ex || ey) {
+ _track[track].arpeggio = true;
+ if (note.period) {
+ _track[track].arpeggioNotes[0] = note.note;
+ _track[track].arpeggioNotes[1] = note.note + ex;
+ _track[track].arpeggioNotes[2] = note.note + ey;
+ }
+ }
break;
case 0x1:
break;
@@ -152,7 +228,6 @@ void ProtrackerStream::updateRow() {
case 0x3:
if (note.period)
_track[track].portaToNote = note.period;
-
if (exy)
_track[track].portaToNoteSpeed = exy;
break;
@@ -163,6 +238,18 @@ void ProtrackerStream::updateRow() {
}
break;
case 0x5:
+ doPorta(track);
+ doVolSlide(track, ex, ey);
+ break;
+ case 0x6:
+ doVibrato(track);
+ doVolSlide(track, ex, ey);
+ break;
+ case 0x9: // Set sample offset
+ if (exy) {
+ _track[track].offset = exy * 256;
+ _voice[track].offset = _track[track].offset;
+ }
break;
case 0xA:
break;
@@ -180,6 +267,24 @@ void ProtrackerStream::updateRow() {
case 0xE:
switch (ex) {
+ case 0x0: // Switch filters off
+ break;
+ case 0x1: // Fine slide up
+ _track[track].period -= exy;
+ break;
+ case 0x2: // Fine slide down
+ _track[track].period += exy;
+ break;
+ case 0x5: // Set finetune
+ _track[track].finetune = ey;
+ _module->sample[_track[track].sample].finetune = ey;
+ if (note.period) {
+ if (ey)
+ _track[track].period = _module->noteToPeriod(note.note, ey);
+ else
+ _track[track].period = note.period;
+ }
+ break;
case 0x6:
if (ey == 0) {
_patternLoopRow = _row;
@@ -193,6 +298,27 @@ void ProtrackerStream::updateRow() {
break;
case 0x9:
break; // Retrigger note
+ case 0xA: // Fine volume slide up
+ vol = _track[track].vol + ey;
+ if (vol > 64)
+ vol = 64;
+ _track[track].vol = vol;
+ break;
+ case 0xB: // Fine volume slide down
+ vol = _track[track].vol - ey;
+ if (vol < 0)
+ vol = 0;
+ _track[track].vol = vol;
+ break;
+ case 0xD: // Delay sample
+ _track[track].delaySampleTick = ey;
+ _track[track].delaySample = _track[track].sample;
+ _track[track].sample = 0;
+ _track[track].vol = 0;
+ break;
+ case 0xE: // Pattern delay
+ _patternDelay = ey;
+ break;
default:
warning("Unimplemented effect %X\n", note.effect);
}
@@ -213,18 +339,6 @@ void ProtrackerStream::updateRow() {
}
void ProtrackerStream::updateEffects() {
-
- static const int16 sinetable[64] = {
- 0, 24, 49, 74, 97, 120, 141, 161,
- 180, 197, 212, 224, 235, 244, 250, 253,
- 255, 253, 250, 244, 235, 224, 212, 197,
- 180, 161, 141, 120, 97, 74, 49, 24,
- 0, -24, -49, -74, -97, -120, -141, -161,
- -180, -197, -212, -224, -235, -244, -250, -253,
- -255, -253, -250, -244, -235, -224, -212, -197,
- -180, -161, -141, -120, -97, -74, -49, -24
- };
-
for (int track = 0; track < 4; track++) {
_track[track].vibrato = 0;
@@ -237,9 +351,18 @@ void ProtrackerStream::updateEffects() {
int ex = (note.effect >> 4) & 0xf;
int ey = (note.effect) & 0xf;
- int vol;
switch (effect) {
case 0x0:
+ if (ex || ey) {
+ if (_tick == 1)
+ _track[track].period =
+ _module->noteToPeriod(_track[track].arpeggioNotes[0],
+ _track[track].finetune);
+ else
+ _track[track].period =
+ _module->noteToPeriod(_track[track].arpeggioNotes[_tick % 3],
+ _track[track].finetune);
+ }
break;
case 0x1:
_track[track].period -= exy;
@@ -248,89 +371,21 @@ void ProtrackerStream::updateEffects() {
_track[track].period += exy;
break;
case 0x3:
- if (_track[track].portaToNote && _track[track].portaToNoteSpeed) {
- if (_track[track].period < _track[track].portaToNote) {
- _track[track].period += _track[track].portaToNoteSpeed;
- if (_track[track].period > _track[track].portaToNote)
- _track[track].period = _track[track].portaToNote;
- } else if (_track[track].period > _track[track].portaToNote) {
- _track[track].period -= _track[track].portaToNoteSpeed;
- if (_track[track].period < _track[track].portaToNote)
- _track[track].period = _track[track].portaToNote;
- }
- }
+ doPorta(track);
break;
case 0x4:
- _track[track].vibrato =
- (_track[track].vibratoDepth * sinetable[_track[track].vibratoPos]) / 128;
- _track[track].vibratoPos += _track[track].vibratoSpeed;
- _track[track].vibratoPos %= 64;
+ doVibrato(track);
break;
-
case 0x5:
- if (_track[track].portaToNote
- && _track[track].portaToNoteSpeed) {
- if (_track[track].period < _track[track].portaToNote) {
- _track[track].period += _track[track].portaToNoteSpeed;
- if (_track[track].period > _track[track].portaToNote)
- _track[track].period = _track[track].portaToNote;
- } else if (_track[track].period > _track[track].portaToNote) {
- _track[track].period -= _track[track].portaToNoteSpeed;
- if (_track[track].period < _track[track].portaToNote)
- _track[track].period = _track[track].portaToNote;
- }
- }
-
- vol = _track[track].vol;
- if (ex == 0)
- vol -= ey;
- else if (ey == 0)
- vol += ex;
-
- if (vol < 0)
- vol = 0;
- else if (vol > 64)
- vol = 64;
-
- _track[track].vol = vol;
-
+ doPorta(track);
+ doVolSlide(track, ex, ey);
break;
-
case 0x6:
- _track[track].vibrato =
- (_track[track].vibratoDepth * sinetable[_track[track].vibratoPos]) / 128;
- _track[track].vibratoPos += _track[track].vibratoSpeed;
- _track[track].vibratoPos %= 64;
-
- vol = _track[track].vol;
- if (ex == 0)
- vol -= ey;
- else if (ey == 0)
- vol += ex;
-
- if (vol < 0)
- vol = 0;
- else if (vol > 64)
- vol = 64;
-
- _track[track].vol = vol;
-
+ doVibrato(track);
+ doVolSlide(track, ex, ey);
break;
-
case 0xA:
- vol = _track[track].vol;
- if (ex == 0)
- vol -= ey;
- else if (ey == 0)
- vol += ex;
-
- if (vol < 0)
- vol = 0;
- else if (vol > 64)
- vol = 64;
-
- _track[track].vol = vol;
-
+ doVolSlide(track, ex, ey);
break;
case 0xE:
@@ -341,6 +396,14 @@ void ProtrackerStream::updateEffects() {
if (ey && _tick % ey == 0)
_track[track].offset = 0.0;
break;
+ case 0xD: // Delay sample
+ if (_tick == _track[track].delaySampleTick) {
+ _track[track].sample = _track[track].delaySample;
+ _track[track].offset = 0.0;
+ if (_track[track].sample)
+ _track[track].vol = _module->sample[_track[track].sample - 1].vol;
+ }
+ break;
}
break;
}
@@ -354,6 +417,10 @@ void ProtrackerStream::interrupt(void) {
_track[track].offset = _voice[track].offset;
if (_tick == 0) {
+ if (_track[track].arpeggio) {
+ _track[track].period = _module->noteToPeriod(_track[track].arpeggioNotes[0],
+ _track[track].finetune);
+ }
if (_hasJumpToPattern) {
_hasJumpToPattern = false;
_pos = _jumpToPattern;
@@ -373,17 +440,15 @@ void ProtrackerStream::interrupt(void) {
_patternLoopRow = 0;
}
- if (_patternDelay == 0) {
- updateRow();
- } else {
- _patternDelay--;
- }
+ updateRow();
} else
updateEffects();
- _tick = (_tick + 1) % _speed;
- if (_tick == 0)
+ _tick = (_tick + 1) % (_speed + _patternDelay * _speed);
+ if (_tick == 0) {
_row++;
+ _patternDelay = 0;
+ }
for (track = 0; track < 4; track++) {
_voice[track].period = _track[track].period + _track[track].vibrato;