1 /******************************************************************************* 2 3 MIT License 4 5 Copyright (c) 2018 rombankzero 6 7 Permission is hereby granted, free of charge, to any person obtaining a copy 8 of this software and associated documentation files (the "Software"), to deal 9 in the Software without restriction, including without limitation the rights 10 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 copies of the Software, and to permit persons to whom the Software is 12 furnished to do so, subject to the following conditions: 13 14 The above copyright notice and this permission notice shall be included in all 15 copies or substantial portions of the Software. 16 17 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 SOFTWARE. 24 25 *******************************************************************************/ 26 27 // Translated to D by Guillaume Piolat Copyright 2021. 28 module audioformats.pocketmod; 29 30 nothrow: 31 @nogc: 32 33 enum POCKETMOD_MAX_CHANNELS = 32; 34 enum POCKETMOD_MAX_SAMPLES = 31; 35 36 struct _pocketmod_sample 37 { 38 byte* data; /* Sample data buffer */ 39 uint length; /* Data length (in bytes) */ 40 } 41 42 struct _pocketmod_chan 43 { 44 ubyte dirty; /* Pitch/volume dirty flags */ 45 ubyte sample; /* Sample number (0..31) */ 46 ubyte volume; /* Base volume without tremolo (0..64) */ 47 ubyte balance; /* Stereo balance (0..255) */ 48 ushort period; /* Note period (113..856) */ 49 ushort delayed; /* Delayed note period (113..856) */ 50 ushort target; /* Target period (for tone portamento) */ 51 ubyte finetune; /* Note finetune (0..15) */ 52 ubyte loop_count; /* E6x loop counter */ 53 ubyte loop_line; /* E6x target line */ 54 ubyte lfo_step; /* Vibrato/tremolo LFO step counter */ 55 ubyte[2] lfo_type; /* LFO type for vibrato/tremolo */ 56 ubyte effect; /* Current effect (0x0..0xf or 0xe0..0xef) */ 57 ubyte param; /* Raw effect parameter value */ 58 ubyte param3; /* Parameter memory for 3xx */ 59 ubyte param4; /* Parameter memory for 4xy */ 60 ubyte param7; /* Parameter memory for 7xy */ 61 ubyte param9; /* Parameter memory for 9xx */ 62 ubyte paramE1; /* Parameter memory for E1x */ 63 ubyte paramE2; /* Parameter memory for E2x */ 64 ubyte paramEA; /* Parameter memory for EAx */ 65 ubyte paramEB; /* Parameter memory for EBx */ 66 ubyte real_volume; /* Volume (with tremolo adjustment) */ 67 float position; /* Position in sample data buffer */ 68 float increment; /* Position increment per output sample */ 69 } 70 71 struct pocketmod_context 72 { 73 /* Read-only song data */ 74 _pocketmod_sample[POCKETMOD_MAX_SAMPLES] samples; 75 ubyte *source; /* Pointer to source MOD data */ 76 ubyte *order; /* Pattern order table */ 77 ubyte *patterns; /* Start of pattern data */ 78 ubyte length; /* Patterns in the order (1..128) */ 79 ubyte reset; /* Pattern to loop back to (0..127) */ 80 ubyte num_patterns; /* Patterns in the file (1..128) */ 81 ubyte num_samples; /* Sample count (15 or 31) */ 82 ubyte num_channels; /* Channel count (1..32) */ 83 84 /* Timing variables */ 85 int samples_per_second; /* Sample rate (set by user) */ 86 int ticks_per_line; /* A.K.A. song speed (initially 6) */ 87 float samples_per_tick; /* Depends on sample rate and BPM */ 88 89 /* Loop detection state */ 90 ubyte[16] visited; /* Bit mask of previously visited patterns */ 91 int loop_count; /* How many times the song has looped */ 92 93 /* Render state */ 94 _pocketmod_chan[POCKETMOD_MAX_CHANNELS] channels; 95 ubyte pattern_delay;/* EEx pattern delay counter */ 96 uint lfo_rng; /* RNG used for the random LFO waveform */ 97 98 /* Position in song (from least to most granular) */ 99 byte pattern; /* Current pattern in order */ 100 byte line; /* Current line in pattern */ 101 short tick; /* Current tick in line */ 102 float sample; /* Current sample in tick */ 103 } 104 105 /* Memorize a parameter unless the new value is zero */ 106 void POCKETMOD_MEM_ubyte(ref ubyte dst, ubyte src) 107 { 108 dst = src ? src : dst; 109 } 110 111 void POCKETMOD_MEM_ushort(ref ushort dst, ushort src) 112 { 113 dst = src ? src : dst; 114 } 115 116 void POCKETMOD_MEM2(ref ubyte dst, ubyte src) 117 { 118 dst = ((src & 0x0f) ? (src & 0x0f) : (dst & 0x0f)) 119 | ((src & 0xf0) ? (src & 0xf0) : (dst & 0xf0)); 120 } 121 122 /* Shortcut to sample metadata (sample must be nonzero) */ 123 ubyte* POCKETMOD_SAMPLE(pocketmod_context *c, int sample) 124 { 125 return ((c).source + 12 + 30 * (sample)); 126 } 127 128 /* Channel dirty flags */ 129 enum POCKETMOD_PITCH = 0x01; 130 enum POCKETMOD_VOLUME = 0x02; 131 132 /* The size of one sample in bytes */ 133 enum int POCKETMOD_SAMPLE_SIZE = 8; 134 135 /* Finetune adjustment table. Three octaves for each finetune setting. */ 136 static immutable byte[36][16] _pocketmod_finetune = [ 137 [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 138 [ -6, -6, -5, -5, -4, -3, -3, -3, -3, -3, -3, -3, -3, -3, -2, -3, -2, -2, -2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0], 139 [-12,-12,-10,-11, -8, -8, -7, -7, -6, -6, -6, -6, -6, -6, -5, -5, -4, -4, -4, -3, -3, -3, -3, -2, -3, -3, -2, -3, -3, -2, -2, -2, -2, -2, -2, -1], 140 [-18,-17,-16,-16,-13,-12,-12,-11,-10,-10,-10, -9, -9, -9, -8, -8, -7, -6, -6, -5, -5, -5, -5, -4, -5, -4, -3, -4, -4, -3, -3, -3, -3, -2, -2, -2], 141 [-24,-23,-21,-21,-18,-17,-16,-15,-14,-13,-13,-12,-12,-12,-11,-10, -9, -8, -8, -7, -7, -7, -7, -6, -6, -6, -5, -5, -5, -4, -4, -4, -4, -3, -3, -3], 142 [-30,-29,-26,-26,-23,-21,-20,-19,-18,-17,-17,-16,-15,-14,-13,-13,-11,-11,-10, -9, -9, -9, -8, -7, -8, -7, -6, -6, -6, -5, -5, -5, -5, -4, -4, -4], 143 [-36,-34,-32,-31,-27,-26,-24,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-11,-10,-10, -9, -9, -9, -7, -8, -7, -6, -6, -6, -6, -5, -5, -4], 144 [-42,-40,-37,-36,-32,-30,-29,-27,-25,-24,-23,-22,-21,-20,-18,-18,-16,-15,-14,-13,-13,-12,-12,-10,-10,-10, -9, -9, -9, -8, -7, -7, -7, -6, -6, -5], 145 [ 51, 48, 46, 42, 42, 38, 36, 34, 32, 30, 24, 27, 25, 24, 23, 21, 21, 19, 18, 17, 16, 15, 14, 14, 12, 12, 12, 10, 10, 10, 9, 8, 8, 8, 7, 7], 146 [ 44, 42, 40, 37, 37, 35, 32, 31, 29, 27, 25, 24, 22, 21, 20, 19, 18, 17, 16, 15, 15, 14, 13, 12, 11, 10, 10, 9, 9, 9, 8, 7, 7, 7, 6, 6], 147 [ 38, 36, 34, 32, 31, 30, 28, 27, 25, 24, 22, 21, 19, 18, 17, 16, 16, 15, 14, 13, 13, 12, 11, 11, 9, 9, 9, 8, 7, 7, 7, 6, 6, 6, 5, 5], 148 [ 31, 30, 29, 26, 26, 25, 24, 22, 21, 20, 18, 17, 16, 15, 14, 13, 13, 12, 12, 11, 11, 10, 9, 9, 8, 7, 8, 7, 6, 6, 6, 5, 5, 5, 5, 5], 149 [ 25, 24, 23, 21, 21, 20, 19, 18, 17, 16, 14, 14, 13, 12, 11, 10, 11, 10, 10, 9, 9, 8, 7, 7, 6, 6, 6, 5, 5, 5, 5, 4, 4, 4, 3, 4], 150 [ 19, 18, 17, 16, 16, 15, 15, 14, 13, 12, 11, 10, 9, 9, 9, 8, 8, 18, 7, 7, 7, 6, 5, 6, 5, 4, 5, 4, 4, 4, 4, 3, 3, 3, 3, 3], 151 [ 12, 12, 12, 10, 11, 11, 10, 10, 9, 8, 7, 7, 6, 6, 6, 5, 6, 5, 5, 5, 5, 4, 4, 4, 3, 3, 3, 3, 2, 3, 3, 2, 2, 2, 2, 2], 152 [ 6, 6, 6, 5, 6, 6, 6, 5, 5, 5, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1] 153 ]; 154 155 /* Min/max helper functions */ 156 int _pocketmod_min(int x, int y) 157 { 158 return x < y ? x : y; 159 } 160 161 int _pocketmod_max(int x, int y) 162 { 163 return x > y ? x : y; 164 } 165 166 /* Clamp a volume value to the 0..64 range */ 167 int _pocketmod_clamp_volume(int x) 168 { 169 x = _pocketmod_max(x, 0x00); 170 x = _pocketmod_min(x, 0x40); 171 return x; 172 } 173 174 /* Zero out a block of memory */ 175 void _pocketmod_zero(void *data, size_t size) 176 { 177 char* byte_ = cast(char*) data; 178 char* end = byte_ + size; 179 while (byte_ != end) { *byte_++ = 0; } 180 } 181 182 /* Convert a period (at finetune = 0) to a note index in 0..35 */ 183 int _pocketmod_period_to_note(int period) 184 { 185 switch (period) { 186 case 856: return 0; case 808: return 1; case 762: return 2; 187 case 720: return 3; case 678: return 4; case 640: return 5; 188 case 604: return 6; case 570: return 7; case 538: return 8; 189 case 508: return 9; case 480: return 10; case 453: return 11; 190 case 428: return 12; case 404: return 13; case 381: return 14; 191 case 360: return 15; case 339: return 16; case 320: return 17; 192 case 302: return 18; case 285: return 19; case 269: return 20; 193 case 254: return 21; case 240: return 22; case 226: return 23; 194 case 214: return 24; case 202: return 25; case 190: return 26; 195 case 180: return 27; case 170: return 28; case 160: return 29; 196 case 151: return 30; case 143: return 31; case 135: return 32; 197 case 127: return 33; case 120: return 34; case 113: return 35; 198 default: return 0; 199 } 200 } 201 202 /* Table-based sine wave oscillator */ 203 int _pocketmod_sin(int step) 204 { 205 /* round(sin(x * pi / 32) * 255) for x in 0..15 */ 206 static immutable ubyte[16] sin = [ 207 0x00, 0x19, 0x32, 0x4a, 0x62, 0x78, 0x8e, 0xa2, 208 0xb4, 0xc5, 0xd4, 0xe0, 0xec, 0xf4, 0xfa, 0xfe 209 ]; 210 int x = sin[step & 0x0f]; 211 x = (step & 0x1f) < 0x10 ? x : 0xff - x; 212 return step < 0x20 ? x : -x; 213 } 214 215 /* Oscillators for vibrato/tremolo effects */ 216 int _pocketmod_lfo(pocketmod_context *c, _pocketmod_chan *ch, int step) 217 { 218 switch (ch.lfo_type[ch.effect == 7] & 3) { 219 case 0: return _pocketmod_sin(step & 0x3f); /* Sine */ 220 case 1: return 0xff - ((step & 0x3f) << 3); /* Saw */ 221 case 2: return (step & 0x3f) < 0x20 ? 0xff : -0xff; /* Square */ 222 case 3: return (c.lfo_rng & 0x1ff) - 0xff; /* Random */ 223 default: return 0; /* Hush little compiler */ 224 } 225 } 226 227 void _pocketmod_update_pitch(pocketmod_context *c, _pocketmod_chan *ch) 228 { 229 /* Don't do anything if the period is zero */ 230 ch.increment = 0.0f; 231 if (ch.period) { 232 float period = ch.period; 233 234 /* Apply vibrato (if active) */ 235 if (ch.effect == 0x4 || ch.effect == 0x6) { 236 int step = (ch.param4 >> 4) * ch.lfo_step; 237 int rate = ch.param4 & 0x0f; 238 period += _pocketmod_lfo(c, ch, step) * rate / 128.0f; 239 240 /* Apply arpeggio (if active) */ 241 } else if (ch.effect == 0x0 && ch.param) { 242 static immutable float[16] arpeggio = [ /* 2^(X/12) for X in 0..15 */ 243 1.000000f, 1.059463f, 1.122462f, 1.189207f, 244 1.259921f, 1.334840f, 1.414214f, 1.498307f, 245 1.587401f, 1.681793f, 1.781797f, 1.887749f, 246 2.000000f, 2.118926f, 2.244924f, 2.378414f 247 ]; 248 int step = (ch.param >> ((2 - c.tick % 3) << 2)) & 0x0f; 249 period /= arpeggio[step]; 250 } 251 252 /* Calculate sample buffer position increment */ 253 ch.increment = 3546894.6f / (period * c.samples_per_second); 254 } 255 256 /* Clear the pitch dirty flag */ 257 ch.dirty &= ~POCKETMOD_PITCH; 258 } 259 260 void _pocketmod_update_volume(pocketmod_context *c, _pocketmod_chan *ch) 261 { 262 int volume = ch.volume; 263 if (ch.effect == 0x7) { 264 int step = ch.lfo_step * (ch.param7 >> 4); 265 volume += _pocketmod_lfo(c, ch, step) * (ch.param7 & 0x0f) >> 6; 266 } 267 ch.real_volume = cast(ubyte) _pocketmod_clamp_volume(volume); 268 ch.dirty &= ~POCKETMOD_VOLUME; 269 } 270 271 void _pocketmod_pitch_slide(_pocketmod_chan *ch, int amount) 272 { 273 int max = 856 + _pocketmod_finetune[ch.finetune][ 0]; 274 int min = 113 + _pocketmod_finetune[ch.finetune][35]; 275 ch.period += amount; 276 ch.period = cast(ushort) _pocketmod_max(ch.period, min); 277 ch.period = cast(ushort) _pocketmod_min(ch.period, max); 278 ch.dirty |= POCKETMOD_PITCH; 279 } 280 281 void _pocketmod_volume_slide(_pocketmod_chan *ch, int param) 282 { 283 /* Undocumented quirk: If both x and y are nonzero, then the value of x */ 284 /* takes precedence. (Yes, there are songs that rely on this behavior.) */ 285 int change = (param & 0xf0) ? (param >> 4) : -(param & 0x0f); 286 ch.volume = cast(ubyte) _pocketmod_clamp_volume(ch.volume + change); 287 ch.dirty |= POCKETMOD_VOLUME; 288 } 289 290 /** 291 Returns the amount of remaining (mono) samples/frames in the 292 currently playing pattern. 293 */ 294 int pocketmod_count_remaining_samples(pocketmod_context *c) { 295 ubyte[4]* data; 296 int i, pos; 297 298 int result = 0; 299 int lineEnd = 64; 300 301 int iTicksPerLine = c.ticks_per_line; 302 float iSamplesPerTick = c.samples_per_tick; 303 304 /* For every (remaining) line in this current pattern */ 305 for(int line = c.line; line < 64; line++) { 306 /* Find the pattern data for the current line */ 307 pos = (c.order[c.pattern] * 64 + line) * c.num_channels * 4; 308 data = cast(ubyte[4]*) (c.patterns + pos); 309 for (i = 0; i < c.num_channels; i++) { 310 /* Decode columns */ 311 int effect = ((data[i][2] & 0x0f) << 8) | data[i][3]; 312 313 /* Memorize effect parameter values */ 314 _pocketmod_chan *ch = &c.channels[i]; 315 ch.effect = cast(ubyte) ( (effect >> 8) != 0xe ? (effect >> 8) : (effect >> 4) ); 316 ch.param = (effect >> 8) != 0xe ? (effect & 0xff) : (effect & 0x0f); 317 switch (ch.effect) { 318 /* Dxy: Pattern break */ 319 case 0xD: 320 // Our pattern jumps *after* decoding the data where the break is on. 321 return result+cast(int)(cast(float)iTicksPerLine*iSamplesPerTick); 322 323 /* E6x: Pattern loop */ 324 case 0xE6: 325 if (ch.param) { 326 if (!ch.loop_count) { 327 lineEnd = ch.loop_line; 328 } else if (--ch.loop_count) { 329 lineEnd = ch.loop_line; 330 } 331 } 332 break; 333 334 /* Fxx: Set speed */ 335 case 0xF: 336 if (ch.param != 0) { 337 if (ch.param < 0x20) { 338 iTicksPerLine = ch.param; 339 } else { 340 float rate = c.samples_per_second; 341 iSamplesPerTick = rate / (0.4f * ch.param); 342 } 343 } 344 break; 345 default: break; 346 } 347 } 348 349 result += cast(int)(cast(float)iTicksPerLine*iSamplesPerTick); 350 } 351 return result; 352 } 353 354 void _pocketmod_next_line(pocketmod_context *c) 355 { 356 ubyte[4]* data; 357 int i, pos, pattern_break = -1; 358 359 /* When entering a new pattern order index, mark it as "visited" */ 360 if (c.line == 0) 361 { 362 c.visited[c.pattern >> 3] |= 1 << (c.pattern & 7); 363 } 364 365 /* Move to the next pattern if this was the last line */ 366 if (++c.line == 64) 367 { 368 if (++c.pattern == c.length) 369 { 370 c.pattern = c.reset; 371 } 372 c.line = 0; 373 } 374 375 /* Find the pattern data for the current line */ 376 pos = (c.order[c.pattern] * 64 + c.line) * c.num_channels * 4; 377 data = cast(ubyte[4]*) (c.patterns + pos); 378 for (i = 0; i < c.num_channels; i++) 379 { 380 381 /* Decode columns */ 382 int sample = (data[i][0] & 0xf0) | (data[i][2] >> 4); 383 int period = ((data[i][0] & 0x0f) << 8) | data[i][1]; 384 int effect = ((data[i][2] & 0x0f) << 8) | data[i][3]; 385 386 /* Memorize effect parameter values */ 387 _pocketmod_chan *ch = &c.channels[i]; 388 ch.effect = cast(ubyte) ( (effect >> 8) != 0xe ? (effect >> 8) : (effect >> 4) ); 389 ch.param = (effect >> 8) != 0xe ? (effect & 0xff) : (effect & 0x0f); 390 391 /* Set sample */ 392 if (sample) { 393 if (sample <= POCKETMOD_MAX_SAMPLES) { 394 ubyte *sample_data = POCKETMOD_SAMPLE(c, sample); 395 ch.sample = cast(ubyte)sample; 396 ch.finetune = sample_data[2] & 0x0f; 397 ch.volume = cast(ubyte)_pocketmod_min(sample_data[3], 0x40); 398 if (ch.effect != 0xED) { 399 ch.dirty |= POCKETMOD_VOLUME; 400 } 401 } else { 402 ch.sample = 0; 403 } 404 } 405 406 /* Set note */ 407 if (period) { 408 int note = _pocketmod_period_to_note(period); 409 period += _pocketmod_finetune[ch.finetune][note]; 410 if (ch.effect != 0x3) { 411 if (ch.effect != 0xED) { 412 ch.period = cast(ushort) period; 413 ch.dirty |= POCKETMOD_PITCH; 414 ch.position = 0.0f; 415 ch.lfo_step = 0; 416 } else { 417 ch.delayed = cast(ushort) period; 418 } 419 } 420 } 421 422 /* Handle pattern effects */ 423 switch (ch.effect) { 424 425 /* Memorize parameters */ 426 case 0x3: POCKETMOD_MEM_ubyte(ch.param3, ch.param); goto case 0x5; /* Fall through */ 427 case 0x5: POCKETMOD_MEM_ushort(ch.target, cast(ushort)period); break; 428 case 0x4: POCKETMOD_MEM2(ch.param4, ch.param); break; 429 case 0x7: POCKETMOD_MEM2(ch.param7, ch.param); break; 430 case 0xE1: POCKETMOD_MEM_ubyte(ch.paramE1, ch.param); break; 431 case 0xE2: POCKETMOD_MEM_ubyte(ch.paramE2, ch.param); break; 432 case 0xEA: POCKETMOD_MEM_ubyte(ch.paramEA, ch.param); break; 433 case 0xEB: POCKETMOD_MEM_ubyte(ch.paramEB, ch.param); break; 434 435 /* 8xx: Set stereo balance (nonstandard) */ 436 case 0x8: { 437 ch.balance = ch.param; 438 } break; 439 440 /* 9xx: Set sample offset */ 441 case 0x9: { 442 if (period != 0 || sample != 0) { 443 ch.param9 = ch.param ? ch.param : ch.param9; 444 ch.position = ch.param9 << 8; 445 } 446 } break; 447 448 /* Bxx: Jump to pattern */ 449 case 0xB: { 450 c.pattern = ch.param < c.length ? ch.param : 0; 451 c.line = -1; 452 } break; 453 454 /* Cxx: Set volume */ 455 case 0xC: { 456 ch.volume = cast(ubyte)_pocketmod_clamp_volume(ch.param); 457 ch.dirty |= POCKETMOD_VOLUME; 458 } break; 459 460 /* Dxy: Pattern break */ 461 case 0xD: { 462 pattern_break = (ch.param >> 4) * 10 + (ch.param & 15); 463 } break; 464 465 /* E4x: Set vibrato waveform */ 466 case 0xE4: { 467 ch.lfo_type[0] = ch.param; 468 } break; 469 470 /* E5x: Set sample finetune */ 471 case 0xE5: { 472 ch.finetune = ch.param; 473 ch.dirty |= POCKETMOD_PITCH; 474 } break; 475 476 /* E6x: Pattern loop */ 477 case 0xE6: { 478 if (ch.param) { 479 if (!ch.loop_count) { 480 ch.loop_count = ch.param; 481 c.line = ch.loop_line; 482 } else if (--ch.loop_count) { 483 c.line = ch.loop_line; 484 } 485 } else { 486 ch.loop_line = cast(ubyte)(c.line - 1); 487 } 488 } break; 489 490 /* E7x: Set tremolo waveform */ 491 case 0xE7: { 492 ch.lfo_type[1] = ch.param; 493 } break; 494 495 /* E8x: Set stereo balance (nonstandard) */ 496 case 0xE8: { 497 ch.balance = cast(ubyte)(ch.param << 4); 498 } break; 499 500 /* EEx: Pattern delay */ 501 case 0xEE: { 502 c.pattern_delay = ch.param; 503 } break; 504 505 /* Fxx: Set speed */ 506 case 0xF: { 507 if (ch.param != 0) { 508 if (ch.param < 0x20) { 509 c.ticks_per_line = ch.param; 510 } else { 511 float rate = c.samples_per_second; 512 c.samples_per_tick = rate / (0.4f * ch.param); 513 } 514 } 515 } break; 516 517 default: break; 518 } 519 } 520 521 /* Pattern breaks are handled here, so that only one jump happens even */ 522 /* when multiple Dxy commands appear on the same line. (You guessed it: */ 523 /* There are songs that rely on this behavior!) */ 524 if (pattern_break != -1) { 525 c.line = cast(byte)( (pattern_break < 64 ? pattern_break : 0) - 1 ); 526 if (++c.pattern == c.length) { 527 c.pattern = c.reset; 528 } 529 } 530 } 531 532 void _pocketmod_next_tick(pocketmod_context *c) 533 { 534 int i; 535 536 /* Move to the next line if this was the last tick */ 537 if (++c.tick == c.ticks_per_line) { 538 if (c.pattern_delay > 0) { 539 c.pattern_delay--; 540 } else { 541 _pocketmod_next_line(c); 542 } 543 c.tick = 0; 544 } 545 546 /* Make per-tick adjustments for all channels */ 547 for (i = 0; i < c.num_channels; i++) { 548 _pocketmod_chan *ch = &c.channels[i]; 549 int param = ch.param; 550 551 /* Advance the LFO random number generator */ 552 c.lfo_rng = 0x0019660d * c.lfo_rng + 0x3c6ef35f; 553 554 /* Handle effects that may happen on any tick of a line */ 555 switch (ch.effect) { 556 557 /* 0xy: Arpeggio */ 558 case 0x0: { 559 ch.dirty |= POCKETMOD_PITCH; 560 } break; 561 562 /* E9x: Retrigger note every x ticks */ 563 case 0xE9: { 564 if (!(param && c.tick % param)) { 565 ch.position = 0.0f; 566 ch.lfo_step = 0; 567 } 568 } break; 569 570 /* ECx: Cut note after x ticks */ 571 case 0xEC: { 572 if (c.tick == param) { 573 ch.volume = 0; 574 ch.dirty |= POCKETMOD_VOLUME; 575 } 576 } break; 577 578 /* EDx: Delay note for x ticks */ 579 case 0xED: { 580 if (c.tick == param && ch.sample) { 581 ch.dirty |= POCKETMOD_VOLUME | POCKETMOD_PITCH; 582 ch.period = ch.delayed; 583 ch.position = 0.0f; 584 ch.lfo_step = 0; 585 } 586 } break; 587 588 default: break; 589 } 590 591 /* Handle effects that only happen on the first tick of a line */ 592 if (c.tick == 0) { 593 switch (ch.effect) { 594 case 0xE1: _pocketmod_pitch_slide(ch, -cast(int)ch.paramE1); break; 595 case 0xE2: _pocketmod_pitch_slide(ch, cast(int)ch.paramE2); break; 596 case 0xEA: _pocketmod_volume_slide(ch, ch.paramEA << 4); break; 597 case 0xEB: _pocketmod_volume_slide(ch, ch.paramEB & 15); break; 598 default: break; 599 } 600 601 /* Handle effects that are not applied on the first tick of a line */ 602 } else { 603 switch (ch.effect) { 604 605 /* 1xx: Portamento up */ 606 case 0x1: { 607 _pocketmod_pitch_slide(ch, -param); 608 } break; 609 610 /* 2xx: Portamento down */ 611 case 0x2: { 612 _pocketmod_pitch_slide(ch, +param); 613 } break; 614 615 /* 5xy: Volume slide + tone portamento */ 616 case 0x5: { 617 _pocketmod_volume_slide(ch, param); 618 goto case 0x3; 619 } 620 621 /* 3xx: Tone portamento */ 622 case 0x3: { 623 int rate = ch.param3; 624 int order = ch.period < ch.target; 625 int closer = ch.period + (order ? rate : -rate); 626 int new_order = closer < ch.target; 627 ch.period = cast(ushort)(new_order == order ? closer : ch.target); 628 ch.dirty |= POCKETMOD_PITCH; 629 } break; 630 631 /* 6xy: Volume slide + vibrato */ 632 case 0x6: { 633 _pocketmod_volume_slide(ch, param); 634 goto case 0x4; 635 } 636 637 /* 4xy: Vibrato */ 638 case 0x4: { 639 ch.lfo_step++; 640 ch.dirty |= POCKETMOD_PITCH; 641 } break; 642 643 /* 7xy: Tremolo */ 644 case 0x7: { 645 ch.lfo_step++; 646 ch.dirty |= POCKETMOD_VOLUME; 647 } break; 648 649 /* Axy: Volume slide */ 650 case 0xA: { 651 _pocketmod_volume_slide(ch, param); 652 } break; 653 654 default: break; 655 } 656 } 657 658 /* Update channel volume/pitch if either is out of date */ 659 if (ch.dirty & POCKETMOD_VOLUME) { _pocketmod_update_volume(c, ch); } 660 if (ch.dirty & POCKETMOD_PITCH) { _pocketmod_update_pitch(c, ch); } 661 } 662 } 663 664 void _pocketmod_render_channel(pocketmod_context *c, 665 _pocketmod_chan *chan, 666 float *output, 667 int samples_to_write) 668 { 669 /* Gather some loop data */ 670 _pocketmod_sample *sample = &c.samples[chan.sample - 1]; 671 ubyte *data = POCKETMOD_SAMPLE(c, chan.sample); 672 const int loop_start = ((data[4] << 8) | data[5]) << 1; 673 const int loop_length = ((data[6] << 8) | data[7]) << 1; 674 const int loop_end = loop_length > 2 ? loop_start + loop_length : 0xffffff; 675 const float sample_end = 1 + _pocketmod_min(loop_end, sample.length); 676 677 /* Calculate left/right levels */ 678 const float volume = chan.real_volume / cast(float) (128 * 64 * 4); 679 const float level_l = volume * (1.0f - chan.balance / 255.0f); 680 const float level_r = volume * (0.0f + chan.balance / 255.0f); 681 682 /* Write samples */ 683 int i, num; 684 do { 685 686 /* Calculate how many samples we can write in one go */ 687 num = cast(int)( (sample_end - chan.position) / chan.increment ); 688 num = _pocketmod_min(num, samples_to_write); 689 690 /* Resample and write 'num' samples */ 691 for (i = 0; i < num; i++) 692 { 693 int x0 = cast(int)(chan.position); 694 version(AF_LINEAR) { 695 int x1 = x0 + 1 - loop_length * (x0 + 1 >= loop_end); 696 float t = chan.position - x0; 697 float s = (1.0f - t) * sample.data[x0] + t * sample.data[x1]; 698 } else { 699 float s = sample.data[x0]; 700 } 701 702 chan.position += chan.increment; 703 *output++ += level_l * s; 704 *output++ += level_r * s; 705 } 706 707 /* Rewind the sample when reaching the loop point */ 708 if (chan.position >= loop_end) 709 { 710 chan.position -= loop_length; 711 /* Cut the sample if the end is reached */ 712 } 713 else if (chan.position >= sample.length) 714 { 715 chan.position = -1.0f; 716 break; 717 } 718 719 samples_to_write -= num; 720 } while (num > 0); 721 } 722 723 // Modification: can be called without a context, for probing file format. 724 int _pocketmod_ident(pocketmod_context *c, ubyte *data, int size) 725 { 726 int i, j; 727 728 /* 31-instrument files are at least 1084 bytes long */ 729 if (size >= 1084) 730 { 731 732 /* The format tag is located at offset 1080 */ 733 ubyte *tag = data + 1080; 734 735 /* List of recognized format tags (possibly incomplete) */ 736 static struct Format_Tag 737 { 738 char[5] name; 739 char channels; 740 } 741 742 static immutable Format_Tag[40] tags = 743 [ 744 /* TODO: FLT8 intentionally omitted because I haven't been able */ 745 /* to find a specimen to test its funky pattern pairing format */ 746 Format_Tag("M.K.", 4), Format_Tag("M!K!", 4), Format_Tag("FLT4", 4), Format_Tag("4CHN", 4), 747 Format_Tag("OKTA", 8), Format_Tag("OCTA", 8), Format_Tag("CD81", 8), Format_Tag("FA08", 8), 748 Format_Tag("1CHN", 1), Format_Tag("2CHN", 2), Format_Tag("3CHN", 3), Format_Tag("4CHN", 4), 749 Format_Tag("5CHN", 5), Format_Tag("6CHN", 6), Format_Tag("7CHN", 7), Format_Tag("8CHN", 8), 750 Format_Tag("9CHN", 9), Format_Tag("10CH", 10), Format_Tag("11CH", 11), Format_Tag("12CH", 12), 751 Format_Tag("13CH", 13), Format_Tag("14CH", 14), Format_Tag("15CH", 15), Format_Tag("16CH", 16), 752 Format_Tag("17CH", 17), Format_Tag("18CH", 18), Format_Tag("19CH", 19), Format_Tag("20CH", 20), 753 Format_Tag("21CH", 21), Format_Tag("22CH", 22), Format_Tag("23CH", 23), Format_Tag("24CH", 24), 754 Format_Tag("25CH", 25), Format_Tag("26CH", 26), Format_Tag("27CH", 27), Format_Tag("28CH", 28), 755 Format_Tag("29CH", 29), Format_Tag("30CH", 30), Format_Tag("31CH", 31), Format_Tag("32CH", 32) 756 ]; 757 758 /* Check the format tag to determine if this is a 31-sample MOD */ 759 for (i = 0; i < cast(int) (tags.length); i++) 760 { 761 if (tags[i].name[0] == tag[0] && tags[i].name[1] == tag[1] 762 && tags[i].name[2] == tag[2] && tags[i].name[3] == tag[3]) 763 { 764 if (c) 765 { 766 c.num_channels = tags[i].channels; 767 c.length = data[950]; 768 c.reset = data[951]; 769 c.order = &data[952]; 770 c.patterns = &data[1084]; 771 c.num_samples = 31; 772 } 773 return 1; 774 } 775 } 776 } 777 778 /* A 15-instrument MOD has to be at least 600 bytes long */ 779 if (size < 600) { 780 return 0; 781 } 782 783 /* Check that the song title only contains ASCII bytes (or null) */ 784 for (i = 0; i < 20; i++) { 785 if (data[i] != '\0' && (data[i] < ' ' || data[i] > '~')) { 786 return 0; 787 } 788 } 789 790 /* Check that sample names only contain ASCII bytes (or null) */ 791 for (i = 0; i < 15; i++) { 792 for (j = 0; j < 22; j++) { 793 char chr = data[20 + i * 30 + j]; 794 if (chr != '\0' && (chr < ' ' || chr > '~')) { 795 return 0; 796 } 797 } 798 } 799 800 /* It looks like we have an older 15-instrument MOD */ 801 if (c) 802 { 803 c.length = data[470]; 804 c.reset = data[471]; 805 c.order = &data[472]; 806 c.patterns = &data[600]; 807 c.num_samples = 15; 808 c.num_channels = 4; 809 } 810 return 1; 811 } 812 813 int pocketmod_init(pocketmod_context *c, const void *data, int size, int rate) 814 { 815 int i, remaining, header_bytes, pattern_bytes; 816 ubyte*byte_ = cast(ubyte*) c; 817 byte *sample_data; 818 819 /* Check that arguments look more or less sane */ 820 if (!c || !data || rate <= 0 || size <= 0) { 821 return 0; 822 } 823 824 /* Zero out the whole context and identify the MOD type */ 825 _pocketmod_zero(c, pocketmod_context.sizeof); 826 c.source = cast(ubyte*) data; 827 if (!_pocketmod_ident(c, c.source, size)) { 828 return 0; 829 } 830 831 /* Check that we are compiled with support for enough channels */ 832 if (c.num_channels > POCKETMOD_MAX_CHANNELS) { 833 return 0; 834 } 835 836 /* Check that we have enough sample slots for this file */ 837 if (POCKETMOD_MAX_SAMPLES < 31) { 838 byte_ = cast(ubyte*) data + 20; 839 for (i = 0; i < c.num_samples; i++) { 840 uint length = 2 * ((byte_[22] << 8) | byte_[23]); 841 if (i >= POCKETMOD_MAX_SAMPLES && length > 2) { 842 return 0; /* Can't fit this sample */ 843 } 844 byte_ += 30; 845 } 846 } 847 848 /* Check that the song length is in valid range (1..128) */ 849 if (c.length == 0 || c.length > 128) { 850 return 0; 851 } 852 853 /* Make sure that the reset pattern doesn't take us out of bounds */ 854 if (c.reset >= c.length) { 855 c.reset = 0; 856 } 857 858 /* Count how many patterns there are in the file */ 859 c.num_patterns = 0; 860 for (i = 0; i < 128 && c.order[i] < 128; i++) { 861 c.num_patterns = cast(ubyte) _pocketmod_max(c.num_patterns, c.order[i]); 862 } 863 pattern_bytes = 256 * c.num_channels * ++c.num_patterns; 864 header_bytes = cast(int) (cast(char*) c.patterns - cast(char*) data); 865 866 /* Check that each pattern in the order is within file bounds */ 867 for (i = 0; i < c.length; i++) { 868 if (header_bytes + 256 * c.num_channels * c.order[i] > size) { 869 return 0; /* Reading this pattern would be a buffer over-read! */ 870 } 871 } 872 873 /* Check that the pattern data doesn't extend past the end of the file */ 874 if (header_bytes + pattern_bytes > size) { 875 return 0; 876 } 877 878 /* Load sample payload data, truncating ones that extend outside the file */ 879 remaining = size - header_bytes - pattern_bytes; 880 sample_data = cast(byte*) data + header_bytes + pattern_bytes; 881 for (i = 0; i < c.num_samples; i++) 882 { 883 ubyte *data2 = POCKETMOD_SAMPLE(c, i + 1); 884 uint length = ((data2[0] << 8) | data2[1]) << 1; 885 _pocketmod_sample *sample = &c.samples[i]; 886 sample.data = sample_data; 887 sample.length = _pocketmod_min(length > 2 ? length : 0, remaining); 888 sample_data += sample.length; 889 remaining -= sample.length; 890 } 891 892 /* Set up ProTracker default panning for all channels */ 893 for (i = 0; i < c.num_channels; i++) { 894 c.channels[i].balance = 0x80 + ((((i + 1) >> 1) & 1) ? 0x20 : -0x20); 895 } 896 897 /* Prepare to render from the start */ 898 c.ticks_per_line = 6; 899 c.samples_per_second = rate; 900 c.samples_per_tick = rate / 50.0f; 901 c.lfo_rng = 0xbadc0de; 902 c.line = -1; 903 c.tick = cast(ushort)(c.ticks_per_line - 1); 904 _pocketmod_next_tick(c); 905 return 1; 906 } 907 908 int pocketmod_render(pocketmod_context *c, void *buffer, int buffer_size) 909 { 910 int i, samples_rendered = 0; 911 int samples_remaining = buffer_size / POCKETMOD_SAMPLE_SIZE; 912 if (c && buffer) 913 { 914 float[2]* output = cast(float[2]*) buffer; 915 while (samples_remaining > 0) { 916 917 /* Calculate the number of samples left in this tick */ 918 int num = cast(int) (c.samples_per_tick - c.sample); 919 num = _pocketmod_min(num + !num, samples_remaining); 920 921 /* Render and mix 'num' samples from each channel */ 922 _pocketmod_zero(output, num * POCKETMOD_SAMPLE_SIZE); 923 for (i = 0; i < c.num_channels; i++) { 924 _pocketmod_chan *chan = &c.channels[i]; 925 if (chan.sample != 0 && chan.position >= 0.0f) { 926 _pocketmod_render_channel(c, chan, (*output).ptr, num); 927 } 928 } 929 samples_remaining -= num; 930 samples_rendered += num; 931 output += num; 932 933 /* Advance song position by 'num' samples */ 934 if ((c.sample += num) >= c.samples_per_tick) { 935 c.sample -= c.samples_per_tick; 936 _pocketmod_next_tick(c); 937 938 /* Stop if a new pattern was reached */ 939 if (c.line == 0 && c.tick == 0) { 940 941 /* Increment loop counter as needed */ 942 if (c.visited[c.pattern >> 3] & (1 << (c.pattern & 7))) { 943 _pocketmod_zero(c.visited.ptr, (c.visited).sizeof); 944 c.loop_count++; 945 } 946 break; 947 } 948 } 949 } 950 } 951 return samples_rendered * POCKETMOD_SAMPLE_SIZE; 952 } 953 954 bool pocketmod_seek(pocketmod_context* c, int pattern, int row, int tick) 955 { 956 // NOTE: This is untested. 957 c.line = cast(byte)row; 958 c.pattern = cast(byte)pattern; 959 c.tick = cast(short)tick; 960 c.sample = 0; 961 return true; // TODO check that the pattern exist, the row exist, and the tick exist. Else return false. 962 } 963 964 int pocketmod_loop_count(pocketmod_context *c) 965 { 966 return c.loop_count; 967 } 968