Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/trackmod/trackmod.c

    r43dd72b7 r7e69e0e  
    4040
    4141#include "macros.h"
    42 #include "protracker.h"
    4342#include "trackmod.h"
    44 #include "xm.h"
    4543
    4644/** Tunables */
     
    5452        base_clock = 8363 * 428,
    5553        /** Maximum sample volume */
    56         vol_max = 64,
    57         /** Minimum period */
    58         period_min = 113,
    59         /** Maxium period */
    60         period_max = 856
     54        vol_max = 63,
     55        /** Default TPR */
     56        def_tpr = 6,
     57        /** Default BPM */
     58        def_bpm = 125
    6159};
    6260
    63 /** Table for finetune computation.
    64   *
    65   * Finetune is a number ft in [-8 .. 7]. The pitch should be adjusted by
    66   * ft/8 semitones. To adjust pitch by 1/8 semitone down we can mutiply the
    67   * 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,  9507
    76 };
    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,457
    85 };
    86 
    8761static size_t trackmod_get_next_ord_idx(trackmod_modplay_t *);
    8862
     
    9670}
    9771
    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 */
     76static 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 */
     85trackmod_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 */
     94void trackmod_module_destroy(trackmod_module_t *module)
    10395{
    10496        size_t i;
    10597
    106         for (i = 0; i < instr->samples; i++)
    107                 trackmod_sample_destroy(&instr->sample[i]);
    108 }
    109 
    110 /** Destroy pattern.
    111  *
    112  * @param pattern Pattern
    113  */
    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 module
    122  */
    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 Module
    131  */
    132 void trackmod_module_destroy(trackmod_module_t *module)
    133 {
    134         size_t i;
    135 
    13698        /* 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);
    141103        }
    142104
     
    152114}
    153115
    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 
    167116/** Return current pattern.
    168117 *
     
    188137    size_t row, size_t channel, trackmod_cell_t *cell)
    189138{
    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)
    220149 *
    221150 * @param modplay Module playback
     
    227156{
    228157        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];
    280162        chan->smp_pos = 0;
    281163        chan->lsmp = 0;
    282 
     164        chan->period = cell->period;
    283165        chan->volume = modplay->chan[i].sample->def_vol;
    284 }
    285 
    286 /** Process keyoff note
    287  *
    288  * @param modplay Module playback
    289  * @param i       Channel number
    290  * @param cell    Cell
    291  */
    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;
    300166}
    301167
     
    309175    uint8_t param)
    310176{
    311         modplay->chan[chan].volume = param % (vol_max + 1);
     177        modplay->chan[chan].volume = param & vol_max;
    312178}
    313179
     
    323189        size_t next_idx;
    324190        trackmod_pattern_t *next_pat;
    325         unsigned row;
    326 
    327         /* Strangely the parameter is BCD */
    328         row = (param >> 4) * 10 + (param & 0xf);
    329191
    330192        next_idx = trackmod_get_next_ord_idx(modplay);
     
    332194
    333195        modplay->pat_break = true;
    334         modplay->pat_break_row = row % next_pat->rows;
     196        modplay->pat_break_row = param % next_pat->rows;
    335197}
    336198
     
    350212}
    351213
    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.
    502215 *
    503216 * @param modplay Module playback
     
    505218 * @param cell    Cell
    506219 */
    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 playback
    541  * @param chan    Channel number
    542  * @param cell    Cell
    543  */
    544220static void trackmod_process_effect(trackmod_modplay_t *modplay, size_t chan,
    545221    trackmod_cell_t *cell)
    546222{
    547223        uint8_t param8;
    548         uint8_t param4;
    549224
    550225        param8 = cell->effect & 0xff;
    551226
    552227        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;
    565228        case 0xc00:
    566229                trackmod_effect_set_volume(modplay, chan, param8);
     
    575238                break;
    576239        }
    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         }
    594240}
    595241
     
    603249    trackmod_cell_t *cell)
    604250{
    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)
    610252                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
    616254        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;
    620255}
    621256
     
    632267        pattern = trackmod_cur_pattern(modplay);
    633268
    634         if (modplay->debug)
    635                 printf("%02zx: ", modplay->row);
    636 
    637269        for (i = 0; i < modplay->module->channels; i++) {
    638270                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);
    646273                trackmod_process_cell(modplay, i, &cell);
    647274        }
     
    662289        ord_idx = modplay->ord_idx + 1;
    663290        if (ord_idx >= modplay->module->ord_list_len)
    664                 ord_idx = modplay->module->restart_pos;
     291                ord_idx = 0; /* XXX */
    665292
    666293        return ord_idx;
     
    686313}
    687314
    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                         else
    728                                 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 
    740315/** Advance to next row.
    741316 *
     
    745320{
    746321        trackmod_pattern_t *pattern;
    747 
    748         /* Clear effect state at end of row */
    749         trackmod_clear_effects(modplay);
    750322
    751323        pattern = trackmod_cur_pattern(modplay);
     
    756328                trackmod_next_pattern(modplay);
    757329
    758         trackmod_process_tick(modplay);
    759330        trackmod_process_row(modplay);
    760331}
     
    770341        if (modplay->tick >= modplay->tpr)
    771342                trackmod_next_row(modplay);
    772         else
    773                 trackmod_process_tick(modplay);
    774343}
    775344
     
    797366        modplay->smp = 0;
    798367
    799         modplay->tpr = module->def_tpr;
    800         modplay->bpm = module->def_bpm;
     368        modplay->tpr = def_tpr;
     369        modplay->bpm = def_bpm;
    801370
    802371        modplay->chan = calloc(module->channels,
     
    805374                goto error;
    806375
    807         trackmod_process_tick(modplay);
    808376        trackmod_process_row(modplay);
    809377
     
    848416}
    849417
    850 /** Get sample frame.
    851  *
    852  * Get frame at the specified sample position.
    853  *
    854  * @param sample Sample
    855  * @param pos    Position (frame index)
    856  * @return       Frame value
    857  */
    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 
    873418/** Advance sample position to next frame.
    874419 *
     
    877422static void chan_smp_next_frame(trackmod_chan_t *chan)
    878423{
    879         chan->lsmp = trackmod_sample_get_frame(chan->sample, chan->smp_pos);
     424        chan->lsmp = chan->sample->data[chan->smp_pos];
    880425        ++chan->smp_pos;
    881426
    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 */
    887429                if (chan->smp_pos >= chan->sample->length) {
    888430                        chan->sample = NULL;
    889431                        chan->smp_pos = 0;
    890432                }
    891                 break;
    892         case tl_forward_loop:
    893                 /** Forward loop */
     433        } else {
     434                /** Looping */
    894435                if (chan->smp_pos >= chan->sample->loop_start +
    895436                    chan->sample->loop_len) {
     
    914455        trackmod_chan_t *chan = &modplay->chan[cidx];
    915456
    916         if (chan->sample == NULL || chan->period == 0)
     457        if (chan->sample == NULL)
    917458                return 0;
    918459
     
    923464         */
    924465        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;
    927468
    928469        period = (int)chan->period;
Note: See TracChangeset for help on using the changeset viewer.