Changes in uspace/lib/trackmod/trackmod.c [43dd72b7:7e69e0e] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/trackmod/trackmod.c
r43dd72b7 r7e69e0e 40 40 41 41 #include "macros.h" 42 #include "protracker.h"43 42 #include "trackmod.h" 44 #include "xm.h"45 43 46 44 /** Tunables */ … … 54 52 base_clock = 8363 * 428, 55 53 /** Maximum sample volume */ 56 vol_max = 6 4,57 /** Minimum period*/58 period_min = 113,59 /** Maxium period*/60 period_max = 85654 vol_max = 63, 55 /** Default TPR */ 56 def_tpr = 6, 57 /** Default BPM */ 58 def_bpm = 125 61 59 }; 62 60 63 /** Table for finetune computation.64 *65 * Finetune is a number ft in [-8 .. 7]. The pitch should be adjusted by66 * ft/8 semitones. To adjust pitch by 1/8 semitone down we can mutiply the67 * period by 2^(1/12/8) =. 1.0072, one semitone up: 2^-(1/12/8) =. 0.9928,68 * to adjust by ft/8 semitones, multiply by 2^(-ft/12/8).69 *70 * finetune_factor[ft] := 10000 * 2^(-ft/12/8)71 * res_period = clip(period * fineture_factor[ft+8] / 10000)72 */73 static unsigned finetune_factor[16] = {74 10595, 10518, 10443, 10368, 10293, 10219, 10145, 10072,75 10000, 9928, 9857, 9786, 9715, 9645, 9576, 950776 };77 78 static unsigned period_table[12 * 8] = {79 907,900,894,887,881,875,868,862,856,850,844,838,832,826,820,814,80 808,802,796,791,785,779,774,768,762,757,752,746,741,736,730,725,81 720,715,709,704,699,694,689,684,678,675,670,665,660,655,651,646,82 640,636,632,628,623,619,614,610,604,601,597,592,588,584,580,575,83 570,567,563,559,555,551,547,543,538,535,532,528,524,520,516,513,84 508,505,502,498,494,491,487,484,480,477,474,470,467,463,460,45785 };86 87 61 static size_t trackmod_get_next_ord_idx(trackmod_modplay_t *); 88 62 … … 96 70 } 97 71 98 /** Destroy instrument. 99 * 100 * @param instr Intrument 101 */ 102 static void trackmod_instr_destroy(trackmod_instr_t *instr) 72 /** Destroy pattern. 73 * 74 * @param pattern Pattern 75 */ 76 static void trackmod_pattern_destroy(trackmod_pattern_t *pattern) 77 { 78 free(pattern->data); 79 } 80 81 /** Create new empty module structure. 82 * 83 * @return New module 84 */ 85 trackmod_module_t *trackmod_module_new(void) 86 { 87 return calloc(1, sizeof(trackmod_module_t)); 88 } 89 90 /** Destroy module. 91 * 92 * @param module Module 93 */ 94 void trackmod_module_destroy(trackmod_module_t *module) 103 95 { 104 96 size_t i; 105 97 106 for (i = 0; i < instr->samples; i++)107 trackmod_sample_destroy(&instr->sample[i]);108 }109 110 /** Destroy pattern.111 *112 * @param pattern Pattern113 */114 static void trackmod_pattern_destroy(trackmod_pattern_t *pattern)115 {116 free(pattern->data);117 }118 119 /** Create new empty module structure.120 *121 * @return New module122 */123 trackmod_module_t *trackmod_module_new(void)124 {125 return calloc(1, sizeof(trackmod_module_t));126 }127 128 /** Destroy module.129 *130 * @param module Module131 */132 void trackmod_module_destroy(trackmod_module_t *module)133 {134 size_t i;135 136 98 /* Destroy samples */ 137 if (module-> instr!= NULL) {138 for (i = 0; i < module-> instrs; i++)139 trackmod_ instr_destroy(&module->instr[i]);140 free(module-> instr);99 if (module->sample != NULL) { 100 for (i = 0; i < module->samples; i++) 101 trackmod_sample_destroy(&module->sample[i]); 102 free(module->sample); 141 103 } 142 104 … … 152 114 } 153 115 154 int trackmod_module_load(char *fname, trackmod_module_t **rmodule)155 {156 int rc;157 158 rc = trackmod_xm_load(fname, rmodule);159 if (rc == EOK)160 return EOK;161 162 rc = trackmod_protracker_load(fname, rmodule);163 return rc;164 }165 166 167 116 /** Return current pattern. 168 117 * … … 188 137 size_t row, size_t channel, trackmod_cell_t *cell) 189 138 { 190 *cell = pattern->data[row * pattern->channels + channel]; 191 } 192 193 /** Compute floor(a / b), and the remainder. 194 * 195 * Unlike standard integer division this rounds towars negative infinity, 196 * not towards zero. 197 * 198 * @param a Dividend 199 * @param b Divisor 200 * @param quot Place to store 'quotient' (floor (a/b)) 201 * @param rem Place to store 'remainder' (a - floor(a/b) * b) 202 */ 203 static void divmod_floor(int a, int b, int *quot, int *rem) 204 { 205 if (b < 0) { 206 a = -a; 207 b = -b; 208 } 209 210 if (a >= 0) { 211 *quot = a / b; 212 *rem = a % b; 213 } else { 214 *quot = - (-a + (b - 1)) / b; 215 *rem = a - (*quot * b); 216 } 217 } 218 219 /** Process note (period) 139 uint32_t code; 140 141 code = pattern->data[row * pattern->channels + channel]; 142 cell->period = (code >> (4 * 4)) & 0xfff; 143 cell->sample = (((code >> (7 * 4)) & 0xf) << 4) | 144 ((code >> (3 * 4)) & 0xf); 145 cell->effect = code & 0xfff; 146 } 147 148 /** Process note (period, sample index) 220 149 * 221 150 * @param modplay Module playback … … 227 156 { 228 157 trackmod_chan_t *chan = &modplay->chan[i]; 229 int period; 230 int pitch; 231 int octave; 232 int opitch; 233 234 if (chan->sample == NULL) 235 return; 236 237 if (cell->period == 0) { 238 pitch = 8 * (cell->note + chan->sample->rel_note) + 239 chan->sample->finetune; 240 divmod_floor(pitch, 8 * 12, &octave, &opitch); 241 242 if (octave >= 0) 243 period = period_table[opitch] * 8 / (1 << octave); 244 else 245 period = period_table[opitch] * 8 * (1 << (-octave)); 246 } else { 247 period = cell->period; 248 period = period * 249 finetune_factor[chan->sample->finetune + 8] / 10000; 250 if (period > period_max) 251 period = period_max; 252 if (period < period_min) 253 period = period_min; 254 } 255 256 chan->period_new = period; 257 } 258 259 /** Process instrument number (this is what triggers the note playback) 260 * 261 * @param modplay Module playback 262 * @param i Channel number 263 * @param cell Cell 264 */ 265 static void trackmod_process_instr(trackmod_modplay_t *modplay, size_t i, 266 trackmod_cell_t *cell) 267 { 268 trackmod_chan_t *chan = &modplay->chan[i]; 269 trackmod_instr_t *instr; 270 size_t iidx; 271 size_t sidx; 272 273 if (cell->instr == 0) 274 return; 275 276 iidx = (cell->instr - 1) % modplay->module->instrs; 277 instr = &modplay->module->instr[iidx]; 278 sidx = instr->key_smp[cell->note] % instr->samples; 279 chan->sample = &instr->sample[sidx]; 158 size_t smpidx; 159 160 smpidx = (cell->sample - 1) % modplay->module->samples; 161 chan->sample = &modplay->module->sample[smpidx]; 280 162 chan->smp_pos = 0; 281 163 chan->lsmp = 0; 282 164 chan->period = cell->period; 283 165 chan->volume = modplay->chan[i].sample->def_vol; 284 }285 286 /** Process keyoff note287 *288 * @param modplay Module playback289 * @param i Channel number290 * @param cell Cell291 */292 static void trackmod_process_keyoff_note(trackmod_modplay_t *modplay, size_t i)293 {294 trackmod_chan_t *chan = &modplay->chan[i];295 296 chan->sample = NULL;297 chan->period = 0;298 chan->smp_pos = 0;299 chan->lsmp = 0;300 166 } 301 167 … … 309 175 uint8_t param) 310 176 { 311 modplay->chan[chan].volume = param % (vol_max + 1);177 modplay->chan[chan].volume = param & vol_max; 312 178 } 313 179 … … 323 189 size_t next_idx; 324 190 trackmod_pattern_t *next_pat; 325 unsigned row;326 327 /* Strangely the parameter is BCD */328 row = (param >> 4) * 10 + (param & 0xf);329 191 330 192 next_idx = trackmod_get_next_ord_idx(modplay); … … 332 194 333 195 modplay->pat_break = true; 334 modplay->pat_break_row = row% next_pat->rows;196 modplay->pat_break_row = param % next_pat->rows; 335 197 } 336 198 … … 350 212 } 351 213 352 /** Process Fine volume slide down effect. 353 * 354 * @param modplay Module playback 355 * @param chan Channel number 356 * @param param Effect parameter 357 */ 358 static void trackmod_effect_fine_vol_slide_down(trackmod_modplay_t *modplay, 359 size_t chan, uint8_t param) 360 { 361 int nv; 362 363 nv = modplay->chan[chan].volume - param; 364 if (nv < 0) 365 nv = 0; 366 modplay->chan[chan].volume = nv; 367 } 368 369 /** Process Fine volume slide up effect. 370 * 371 * @param modplay Module playback 372 * @param chan Channel number 373 * @param param Effect parameter 374 */ 375 static void trackmod_effect_fine_vol_slide_up(trackmod_modplay_t *modplay, 376 size_t chan, uint8_t param) 377 { 378 int nv; 379 380 nv = modplay->chan[chan].volume + param; 381 if (nv > vol_max) 382 nv = vol_max; 383 modplay->chan[chan].volume = nv; 384 } 385 386 /** Process Volume slide effect. 387 * 388 * @param modplay Module playback 389 * @param chan Channel number 390 * @param param Effect parameter 391 */ 392 static void trackmod_effect_vol_slide(trackmod_modplay_t *modplay, 393 size_t chan, uint8_t param) 394 { 395 if ((param & 0xf0) != 0) 396 modplay->chan[chan].vol_slide = param >> 4; 397 else 398 modplay->chan[chan].vol_slide = -(int)(param & 0xf); 399 } 400 401 /** Process Volume slide down effect. 402 * 403 * @param modplay Module playback 404 * @param chan Channel number 405 * @param param Effect parameter 406 */ 407 static void trackmod_effect_vol_slide_down(trackmod_modplay_t *modplay, 408 size_t chan, uint8_t param4) 409 { 410 modplay->chan[chan].vol_slide = -(int)param4; 411 } 412 413 /** Process Volume slide up effect. 414 * 415 * @param modplay Module playback 416 * @param chan Channel number 417 * @param param Effect parameter 418 */ 419 static void trackmod_effect_vol_slide_up(trackmod_modplay_t *modplay, 420 size_t chan, uint8_t param4) 421 { 422 modplay->chan[chan].vol_slide = param4; 423 } 424 425 /** Process Fine portamento down effect. 426 * 427 * @param modplay Module playback 428 * @param chan Channel number 429 * @param param Effect parameter 430 */ 431 static void trackmod_effect_fine_porta_down(trackmod_modplay_t *modplay, 432 size_t chan, uint8_t param) 433 { 434 int np; 435 436 np = modplay->chan[chan].period + param; 437 if (np > period_max) 438 np = period_max; 439 modplay->chan[chan].period = np; 440 } 441 442 /** Process Fine portamento up effect. 443 * 444 * @param modplay Module playback 445 * @param chan Channel number 446 * @param param Effect parameter 447 */ 448 static void trackmod_effect_fine_porta_up(trackmod_modplay_t *modplay, 449 size_t chan, uint8_t param) 450 { 451 int np; 452 453 np = modplay->chan[chan].period - param; 454 if (np < period_min) 455 np = period_min; 456 modplay->chan[chan].period = np; 457 } 458 459 /** Process Portamento down effect. 460 * 461 * @param modplay Module playback 462 * @param chan Channel number 463 * @param param Effect parameter 464 */ 465 static void trackmod_effect_porta_down(trackmod_modplay_t *modplay, 466 size_t chan, uint8_t param) 467 { 468 modplay->chan[chan].portamento = -(int)param; 469 } 470 471 /** Process Portamento up effect. 472 * 473 * @param modplay Module playback 474 * @param chan Channel number 475 * @param param Effect parameter 476 */ 477 static void trackmod_effect_porta_up(trackmod_modplay_t *modplay, 478 size_t chan, uint8_t param) 479 { 480 modplay->chan[chan].portamento = param; 481 } 482 483 /** Process Tone portamento effect. 484 * 485 * @param modplay Module playback 486 * @param chan Channel number 487 * @param param Effect parameter 488 */ 489 static void trackmod_effect_tone_porta(trackmod_modplay_t *modplay, 490 size_t chan, uint8_t param) 491 { 492 /* Set up tone portamento effect */ 493 modplay->chan[chan].portamento = param; 494 if (modplay->chan[chan].period_new != 0) 495 modplay->chan[chan].period_tgt = modplay->chan[chan].period_new; 496 497 /* Prevent going directly to new period */ 498 modplay->chan[chan].period_new = 0; 499 } 500 501 /** Process volume column. 214 /** Process effect. 502 215 * 503 216 * @param modplay Module playback … … 505 218 * @param cell Cell 506 219 */ 507 static void trackmod_process_volume(trackmod_modplay_t *modplay, size_t chan,508 trackmod_cell_t *cell)509 {510 uint8_t param4;511 512 if (cell->volume >= 0x10 && cell->volume <= 0x10 + vol_max)513 trackmod_effect_set_volume(modplay, chan, cell->volume - 0x10);514 515 param4 = cell->volume & 0xf;516 517 switch (cell->volume & 0xf0) {518 case 0x60:519 trackmod_effect_vol_slide_down(modplay, chan, param4);520 break;521 case 0x70:522 trackmod_effect_vol_slide_up(modplay, chan, param4);523 break;524 case 0x80:525 trackmod_effect_fine_vol_slide_down(modplay, chan, param4);526 break;527 case 0x90:528 trackmod_effect_fine_vol_slide_up(modplay, chan, param4);529 break;530 case 0xf0:531 trackmod_effect_tone_porta(modplay, chan, param4 << 4);532 break;533 default:534 break;535 }536 }537 538 /** Process effect.539 *540 * @param modplay Module playback541 * @param chan Channel number542 * @param cell Cell543 */544 220 static void trackmod_process_effect(trackmod_modplay_t *modplay, size_t chan, 545 221 trackmod_cell_t *cell) 546 222 { 547 223 uint8_t param8; 548 uint8_t param4;549 224 550 225 param8 = cell->effect & 0xff; 551 226 552 227 switch (cell->effect & 0xf00) { 553 case 0x100:554 trackmod_effect_porta_up(modplay, chan, param8);555 break;556 case 0x200:557 trackmod_effect_porta_down(modplay, chan, param8);558 break;559 case 0x300:560 trackmod_effect_tone_porta(modplay, chan, param8);561 break;562 case 0xa00:563 trackmod_effect_vol_slide(modplay, chan, param8);564 break;565 228 case 0xc00: 566 229 trackmod_effect_set_volume(modplay, chan, param8); … … 575 238 break; 576 239 } 577 578 param4 = cell->effect & 0xf;579 580 switch (cell->effect & 0xff0) {581 case 0xe10:582 trackmod_effect_fine_porta_up(modplay, chan, param4);583 break;584 case 0xe20:585 trackmod_effect_fine_porta_down(modplay, chan, param4);586 break;587 case 0xea0:588 trackmod_effect_fine_vol_slide_up(modplay, chan, param4);589 break;590 case 0xeb0:591 trackmod_effect_fine_vol_slide_down(modplay, chan, param4);592 break;593 }594 240 } 595 241 … … 603 249 trackmod_cell_t *cell) 604 250 { 605 modplay->chan[chan].period_new = 0; 606 607 trackmod_process_instr(modplay, chan, cell); 608 609 if (cell->period != 0 || (cell->note != 0 && cell->note != keyoff_note)) { 251 if (cell->period != 0 && cell->sample != 0) 610 252 trackmod_process_note(modplay, chan, cell); 611 } else if (cell->note == keyoff_note && cell->instr == 0) { 612 trackmod_process_keyoff_note(modplay, chan); 613 } 614 615 trackmod_process_volume(modplay, chan, cell); 253 616 254 trackmod_process_effect(modplay, chan, cell); 617 618 if (modplay->chan[chan].period_new != 0)619 modplay->chan[chan].period = modplay->chan[chan].period_new;620 255 } 621 256 … … 632 267 pattern = trackmod_cur_pattern(modplay); 633 268 634 if (modplay->debug)635 printf("%02zx: ", modplay->row);636 637 269 for (i = 0; i < modplay->module->channels; i++) { 638 270 trackmod_pattern_get_cell(pattern, modplay->row, i, &cell); 639 640 if (modplay->debug) { 641 printf("%4d %02x %02x %03x |", cell.period ? 642 cell.period : cell.note, cell.instr, 643 cell.volume, cell.effect); 644 } 645 271 if (modplay->debug) 272 printf("%4d %02x %03x |", cell.period, cell.sample, cell.effect); 646 273 trackmod_process_cell(modplay, i, &cell); 647 274 } … … 662 289 ord_idx = modplay->ord_idx + 1; 663 290 if (ord_idx >= modplay->module->ord_list_len) 664 ord_idx = modplay->module->restart_pos;291 ord_idx = 0; /* XXX */ 665 292 666 293 return ord_idx; … … 686 313 } 687 314 688 /** Clear effects at end of row. */689 static void trackmod_clear_effects(trackmod_modplay_t *modplay)690 {691 size_t i;692 693 for (i = 0; i < modplay->module->channels; i++) {694 modplay->chan[i].vol_slide = 0;695 modplay->chan[i].portamento = 0;696 }697 }698 699 /** Process effects at beginning of tick. */700 static void trackmod_process_tick(trackmod_modplay_t *modplay)701 {702 trackmod_chan_t *chan;703 size_t i;704 int nv;705 int np;706 707 for (i = 0; i < modplay->module->channels; i++) {708 chan = &modplay->chan[i];709 710 /* Volume slides */711 nv = (int)chan->volume + chan->vol_slide;712 if (nv < 0)713 nv = 0;714 if (nv > vol_max)715 nv = vol_max;716 717 chan->volume = nv;718 719 /* Portamentos */720 if (chan->period_tgt == 0) {721 /* Up or down portamento */722 np = (int)chan->period - chan->portamento;723 } else {724 /* Tone portamento */725 if (chan->period_tgt < chan->period)726 np = max((int)chan->period_tgt, (int)chan->period - chan->portamento);727 else728 np = min((int)chan->period_tgt, (int)chan->period + chan->portamento);729 }730 731 /* if (np < period_min)732 np = period_min;733 if (np > period_max)734 np = period_max;735 */736 modplay->chan[i].period = np;737 }738 }739 740 315 /** Advance to next row. 741 316 * … … 745 320 { 746 321 trackmod_pattern_t *pattern; 747 748 /* Clear effect state at end of row */749 trackmod_clear_effects(modplay);750 322 751 323 pattern = trackmod_cur_pattern(modplay); … … 756 328 trackmod_next_pattern(modplay); 757 329 758 trackmod_process_tick(modplay);759 330 trackmod_process_row(modplay); 760 331 } … … 770 341 if (modplay->tick >= modplay->tpr) 771 342 trackmod_next_row(modplay); 772 else773 trackmod_process_tick(modplay);774 343 } 775 344 … … 797 366 modplay->smp = 0; 798 367 799 modplay->tpr = module->def_tpr;800 modplay->bpm = module->def_bpm;368 modplay->tpr = def_tpr; 369 modplay->bpm = def_bpm; 801 370 802 371 modplay->chan = calloc(module->channels, … … 805 374 goto error; 806 375 807 trackmod_process_tick(modplay);808 376 trackmod_process_row(modplay); 809 377 … … 848 416 } 849 417 850 /** Get sample frame.851 *852 * Get frame at the specified sample position.853 *854 * @param sample Sample855 * @param pos Position (frame index)856 * @return Frame value857 */858 int trackmod_sample_get_frame(trackmod_sample_t *sample, size_t pos)859 {860 int8_t *i8p;861 int16_t *i16p;862 863 if (sample->bytes_smp == 1) {864 i8p = (int8_t *)sample->data;865 return i8p[pos];866 } else {867 /* chan->sample->bytes_smp == 2 */868 i16p = (int16_t *)sample->data;869 return i16p[pos] / 256; /* XXX Retain full precision */870 }871 }872 873 418 /** Advance sample position to next frame. 874 419 * … … 877 422 static void chan_smp_next_frame(trackmod_chan_t *chan) 878 423 { 879 chan->lsmp = trackmod_sample_get_frame(chan->sample, chan->smp_pos);424 chan->lsmp = chan->sample->data[chan->smp_pos]; 880 425 ++chan->smp_pos; 881 426 882 switch (chan->sample->loop_type) { 883 case tl_pingpong_loop: 884 /** XXX Pingpong loop */ 885 case tl_no_loop: 886 /* No loop */ 427 if (chan->sample->loop_len == 0) { 428 /* No looping */ 887 429 if (chan->smp_pos >= chan->sample->length) { 888 430 chan->sample = NULL; 889 431 chan->smp_pos = 0; 890 432 } 891 break; 892 case tl_forward_loop: 893 /** Forward loop */ 433 } else { 434 /** Looping */ 894 435 if (chan->smp_pos >= chan->sample->loop_start + 895 436 chan->sample->loop_len) { … … 914 455 trackmod_chan_t *chan = &modplay->chan[cidx]; 915 456 916 if (chan->sample == NULL || chan->period == 0)457 if (chan->sample == NULL) 917 458 return 0; 918 459 … … 923 464 */ 924 465 sl = (int)chan->lsmp * amp_factor * chan->volume / vol_max; 925 sn = (int) trackmod_sample_get_frame(chan->sample, chan->smp_pos)*926 amp_factor *chan->volume / vol_max;466 sn = (int)chan->sample->data[chan->smp_pos] * amp_factor * 467 chan->volume / vol_max; 927 468 928 469 period = (int)chan->period;
Note:
See TracChangeset
for help on using the changeset viewer.