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