Changeset 43dd72b7 in mainline


Ignore:
Timestamp:
2014-10-13T17:31:01Z (10 years ago)
Author:
Jiri Svoboda <jiri@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
affbdde
Parents:
18cc83c
Message:

Trackmod update: XM file format, new effects, etc.

Location:
uspace
Files:
3 added
8 edited

Legend:

Unmodified
Added
Removed
  • uspace/app/modplay/modplay.c

    r18cc83c r43dd72b7  
    4040#include <stdio.h>
    4141#include <stdlib.h>
    42 #include <protracker.h>
    4342#include <trackmod.h>
    4443
     
    8887        con = console_init(stdin, stdout);
    8988
    90         rc = trackmod_protracker_load(argv[1], &mod);
     89        rc = trackmod_module_load(argv[1], &mod);
    9190        if (rc != EOK) {
    9291                printf("Error loading %s.\n", argv[1]);
  • uspace/lib/c/include/stddef.h

    r18cc83c r43dd72b7  
    4242#endif
    4343
     44#define offsetof(type,member) ((size_t) &(((type *) 0)->member))
    4445
    4546#endif
  • uspace/lib/trackmod/Makefile

    r18cc83c r43dd72b7  
    3232SOURCES = \
    3333        protracker.c \
    34         trackmod.c
     34        trackmod.c \
     35        xm.c
    3536
    3637include $(USPACE_PREFIX)/Makefile.common
  • uspace/lib/trackmod/protracker.c

    r18cc83c r43dd72b7  
    113113}
    114114
     115
     116/** Decode pattern cell.
     117 *
     118 * @param pattern Pattern
     119 * @param row     Row number
     120 * @param channel Channel number
     121 * @param cell    Place to store decoded cell
     122 */
     123static void protracker_decode_cell(uint32_t cdata, trackmod_cell_t *cell)
     124{
     125        uint32_t code;
     126
     127        code = uint32_t_be2host(cdata);
     128        cell->period = (code >> (4 * 4)) & 0xfff;
     129        cell->instr = (((code >> (7 * 4)) & 0xf) << 4) |
     130            ((code >> (3 * 4)) & 0xf);
     131        cell->effect = code & 0xfff;
     132}
     133
     134/** Load Protracker patterns.
     135 *
     136 * @param f      File to read from
     137 * @param module Module being loaded to
     138 * @return       EOK on success, ENOMEM if out of memory, EIO on I/O error.
     139 */
     140static int protracker_load_patterns(FILE *f, trackmod_module_t *module)
     141{
     142        size_t cells;
     143        size_t i, j;
     144        int rc;
     145        size_t nread;
     146        uint32_t *buf = NULL;
     147
     148        cells = module->channels * protracker_pattern_rows;
     149        buf = calloc(sizeof(uint32_t), cells);
     150
     151        if (buf == NULL) {
     152                rc = ENOMEM;
     153                goto error;
     154        }
     155
     156        for (i = 0; i < module->patterns; i++) {
     157                module->pattern[i].rows = protracker_pattern_rows;
     158                module->pattern[i].channels = module->channels;
     159                module->pattern[i].data = calloc(sizeof(trackmod_cell_t), cells);
     160                if (module->pattern[i].data == NULL) {
     161                        rc = ENOMEM;
     162                        goto error;
     163                }
     164
     165                nread = fread(buf, sizeof(uint32_t), cells, f);
     166                if (nread != cells) {
     167                        printf("Error reading pattern.\n");
     168                        rc = EIO;
     169                        goto error;
     170                }
     171
     172                /* Decode cells */
     173                for (j = 0; j < cells; j++) {
     174                        protracker_decode_cell(buf[j],
     175                            &module->pattern[i].data[j]);
     176                }
     177        }
     178
     179        free(buf);
     180        return EOK;
     181error:
     182        free(buf);
     183        return rc;
     184}
     185
     186/** Load protracker samples.
     187 *
     188 * @param f      File being read from
     189 * @param sample Sample header
     190 * @param module Module being loaded to
     191 * @return       EOk on success, ENOMEM if out of memory, EIO on I/O error.
     192 */
     193static int protracker_load_samples(FILE *f, protracker_smp_t *smp,
     194    trackmod_module_t *module)
     195{
     196        int rc;
     197        size_t i;
     198        uint8_t ftval;
     199        size_t nread;
     200        trackmod_sample_t *sample;
     201
     202        for (i = 0; i < module->instrs; i++) {
     203                module->instr[i].samples = 1;
     204                module->instr[i].sample = calloc(1, sizeof(trackmod_sample_t));
     205                if (module->instr[i].sample == NULL) {
     206                        printf("Error allocating sample.\n");
     207                        rc = ENOMEM;
     208                        goto error;
     209                }
     210
     211                sample = &module->instr[i].sample[0];
     212                sample->length =
     213                    uint16_t_be2host(smp[i].length) * 2;
     214                sample->bytes_smp = 1;
     215                sample->data = calloc(1, sample->length);
     216                if (sample->data == NULL) {
     217                        printf("Error allocating sample.\n");
     218                        rc = ENOMEM;
     219                        goto error;
     220                }
     221
     222                nread = fread(sample->data, 1, sample->length, f);
     223                if (nread != sample->length) {
     224                        printf("Error reading sample.\n");
     225                        rc = EIO;
     226                        goto error;
     227                }
     228
     229                sample->def_vol = smp[i].def_vol;
     230
     231                sample->loop_start =
     232                    uint16_t_be2host(smp[i].loop_start) * 2;
     233                sample->loop_len =
     234                    uint16_t_be2host(smp[i].loop_len) * 2;
     235                if (sample->loop_len <= 2)
     236                        sample->loop_type = tl_no_loop;
     237                else
     238                        sample->loop_type = tl_forward_loop;
     239
     240                /* Finetune is a 4-bit signed value. */
     241                ftval = smp[i].finetune & 0x0f;
     242                sample->finetune =
     243                        (ftval & 0x8) ? (ftval & 0x7) - 8 : ftval;
     244        }
     245
     246        return EOK;
     247error:
     248        return rc;
     249}
     250
    115251/** Load protracker module.
    116252 *
     
    128264        protracker_order_list_t *order_list;
    129265        protracker_smp_t *sample;
    130         size_t nread;
    131266        size_t samples;
    132267        size_t channels;
    133268        size_t patterns;
    134         size_t cells;
    135         size_t i, j;
     269        size_t i;
     270        size_t nread;
    136271        int rc;
    137272
     
    192327        module->channels = channels;
    193328
    194         module->samples = samples;
    195         module->sample = calloc(sizeof(trackmod_sample_t), samples);
    196         if (module->sample == NULL) {
     329        module->instrs = samples;
     330        module->instr = calloc(sizeof(trackmod_instr_t), samples);
     331        if (module->instr == NULL) {
    197332                printf("Out of memory.\n");
    198333                rc = ENOMEM;
     
    221356        }
    222357
     358        /* The 'mark' byte may or may not contain a valid restart position */
     359        if (order_list->mark < order_list->order_list_len) {
     360                module->restart_pos = order_list->mark;
     361        }
     362
    223363        /* Load patterns */
    224 
    225         cells = channels * protracker_pattern_rows;
    226 
    227         for (i = 0; i < patterns; i++) {
    228                 module->pattern[i].rows = protracker_pattern_rows;
    229                 module->pattern[i].channels = channels;
    230                 module->pattern[i].data = calloc(sizeof(uint32_t), cells);
    231 
    232                 nread = fread(module->pattern[i].data,
    233                     sizeof(uint32_t), cells, f);
    234                 if (nread != cells) {
    235                         printf("Error reading pattern.\n");
    236                         rc = EIO;
    237                         goto error;
    238                 }
    239 
    240                 /* Convert byte order */
    241                 for (j = 0; j < cells; j++) {
    242                         module->pattern[i].data[j] = uint32_t_be2host(
    243                             module->pattern[i].data[j]);
    244                 }
    245         }
     364        rc = protracker_load_patterns(f, module);
     365        if (rc != EOK)
     366                goto error;
    246367
    247368        /* Load samples */
    248         for (i = 0; i < samples; i++) {
    249                 module->sample[i].length =
    250                     uint16_t_be2host(sample[i].length) * 2;
    251                 module->sample[i].data = calloc(1, module->sample[i].length);
    252                 if (module->sample[i].data == NULL) {
    253                         printf("Error allocating sample.\n");
    254                         rc = ENOMEM;
    255                         goto error;
    256                 }
    257 
    258                 nread = fread(module->sample[i].data, 1, module->sample[i].length,
    259                         f);
    260                 if (nread != module->sample[i].length) {
    261                         printf("Error reading sample.\n");
    262                         rc = EIO;
    263                         goto error;
    264                 }
    265 
    266                 module->sample[i].def_vol = sample[i].def_vol;
    267                 module->sample[i].loop_start =
    268                     uint16_t_be2host(sample[i].loop_start) * 2;
    269                 module->sample[i].loop_len =
    270                     uint16_t_be2host(sample[i].loop_len) * 2;
    271                 if (module->sample[i].loop_len <= 2)
    272                         module->sample[i].loop_len = 0;
    273         }
     369        rc = protracker_load_samples(f, sample, module);
     370        if (rc != EOK)
     371                goto error;
    274372
    275373        (void) fclose(f);
     374
     375        module->def_bpm = protracker_def_bpm;
     376        module->def_tpr = protracker_def_tpr;
    276377
    277378        *rmodule = module;
  • uspace/lib/trackmod/trackmod.c

    r18cc83c r43dd72b7  
    4040
    4141#include "macros.h"
     42#include "protracker.h"
    4243#include "trackmod.h"
     44#include "xm.h"
    4345
    4446/** Tunables */
     
    5254        base_clock = 8363 * 428,
    5355        /** Maximum sample volume */
    54         vol_max = 63,
    55         /** Default TPR */
    56         def_tpr = 6,
    57         /** Default BPM */
    58         def_bpm = 125
     56        vol_max = 64,
     57        /** Minimum period */
     58        period_min = 113,
     59        /** Maxium period */
     60        period_max = 856
    5961};
    6062
     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  */
     73static unsigned finetune_factor[16] = {
     74        10595, 10518, 10443, 10368, 10293, 10219, 10145, 10072,
     75        10000,  9928,  9857,  9786,  9715,  9645,  9576,  9507
     76};
     77
     78static 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
    6187static size_t trackmod_get_next_ord_idx(trackmod_modplay_t *);
    6288
     
    7096}
    7197
     98/** Destroy instrument.
     99 *
     100 * @param instr Intrument
     101 */
     102static void trackmod_instr_destroy(trackmod_instr_t *instr)
     103{
     104        size_t i;
     105
     106        for (i = 0; i < instr->samples; i++)
     107                trackmod_sample_destroy(&instr->sample[i]);
     108}
     109
    72110/** Destroy pattern.
    73111 *
     
    97135
    98136        /* Destroy samples */
    99         if (module->sample != NULL) {
    100                 for (i = 0; i < module->samples; i++)
    101                         trackmod_sample_destroy(&module->sample[i]);
    102                 free(module->sample);
     137        if (module->instr != NULL) {
     138                for (i = 0; i < module->instrs; i++)
     139                        trackmod_instr_destroy(&module->instr[i]);
     140                free(module->instr);
    103141        }
    104142
     
    114152}
    115153
     154int 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
    116167/** Return current pattern.
    117168 *
     
    137188    size_t row, size_t channel, trackmod_cell_t *cell)
    138189{
    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)
     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 */
     203static 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)
    149220 *
    150221 * @param modplay Module playback
     
    156227{
    157228        trackmod_chan_t *chan = &modplay->chan[i];
    158         size_t smpidx;
    159 
    160         smpidx = (cell->sample - 1) % modplay->module->samples;
    161         chan->sample = &modplay->module->sample[smpidx];
     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 */
     265static 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];
    162280        chan->smp_pos = 0;
    163281        chan->lsmp = 0;
    164         chan->period = cell->period;
     282
    165283        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 */
     292static 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;
    166300}
    167301
     
    175309    uint8_t param)
    176310{
    177         modplay->chan[chan].volume = param & vol_max;
     311        modplay->chan[chan].volume = param % (vol_max + 1);
    178312}
    179313
     
    189323        size_t next_idx;
    190324        trackmod_pattern_t *next_pat;
     325        unsigned row;
     326
     327        /* Strangely the parameter is BCD */
     328        row = (param >> 4) * 10 + (param & 0xf);
    191329
    192330        next_idx = trackmod_get_next_ord_idx(modplay);
     
    194332
    195333        modplay->pat_break = true;
    196         modplay->pat_break_row = param % next_pat->rows;
     334        modplay->pat_break_row = row % next_pat->rows;
    197335}
    198336
     
    212350}
    213351
     352/** Process Fine volume slide down effect.
     353 *
     354 * @param modplay Module playback
     355 * @param chan    Channel number
     356 * @param param   Effect parameter
     357 */
     358static 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 */
     375static 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 */
     392static 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 */
     407static 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 */
     419static 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 */
     431static 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 */
     448static 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 */
     465static 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 */
     477static 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 */
     489static 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.
     502 *
     503 * @param modplay Module playback
     504 * @param chan    Channel number
     505 * @param cell    Cell
     506 */
     507static 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
    214538/** Process effect.
    215539 *
     
    222546{
    223547        uint8_t param8;
     548        uint8_t param4;
    224549
    225550        param8 = cell->effect & 0xff;
    226551
    227552        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;
    228565        case 0xc00:
    229566                trackmod_effect_set_volume(modplay, chan, param8);
     
    238575                break;
    239576        }
     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        }
    240594}
    241595
     
    249603    trackmod_cell_t *cell)
    250604{
    251         if (cell->period != 0 && cell->sample != 0)
     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)) {
    252610                trackmod_process_note(modplay, chan, cell);
    253 
     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);
    254616        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;
    255620}
    256621
     
    267632        pattern = trackmod_cur_pattern(modplay);
    268633
     634        if (modplay->debug)
     635                printf("%02zx: ", modplay->row);
     636
    269637        for (i = 0; i < modplay->module->channels; i++) {
    270638                trackmod_pattern_get_cell(pattern, modplay->row, i, &cell);
    271                 if (modplay->debug)
    272                         printf("%4d %02x %03x |", cell.period, cell.sample, cell.effect);
     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
    273646                trackmod_process_cell(modplay, i, &cell);
    274647        }
     
    289662        ord_idx = modplay->ord_idx + 1;
    290663        if (ord_idx >= modplay->module->ord_list_len)
    291                 ord_idx = 0; /* XXX */
     664                ord_idx = modplay->module->restart_pos;
    292665
    293666        return ord_idx;
     
    313686}
    314687
     688/** Clear effects at end of row. */
     689static 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. */
     700static 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
    315740/** Advance to next row.
    316741 *
     
    320745{
    321746        trackmod_pattern_t *pattern;
     747
     748        /* Clear effect state at end of row */
     749        trackmod_clear_effects(modplay);
    322750
    323751        pattern = trackmod_cur_pattern(modplay);
     
    328756                trackmod_next_pattern(modplay);
    329757
     758        trackmod_process_tick(modplay);
    330759        trackmod_process_row(modplay);
    331760}
     
    341770        if (modplay->tick >= modplay->tpr)
    342771                trackmod_next_row(modplay);
     772        else
     773                trackmod_process_tick(modplay);
    343774}
    344775
     
    366797        modplay->smp = 0;
    367798
    368         modplay->tpr = def_tpr;
    369         modplay->bpm = def_bpm;
     799        modplay->tpr = module->def_tpr;
     800        modplay->bpm = module->def_bpm;
    370801
    371802        modplay->chan = calloc(module->channels,
     
    374805                goto error;
    375806
     807        trackmod_process_tick(modplay);
    376808        trackmod_process_row(modplay);
    377809
     
    416848}
    417849
     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 */
     858int 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
    418873/** Advance sample position to next frame.
    419874 *
     
    422877static void chan_smp_next_frame(trackmod_chan_t *chan)
    423878{
    424         chan->lsmp = chan->sample->data[chan->smp_pos];
     879        chan->lsmp = trackmod_sample_get_frame(chan->sample, chan->smp_pos);
    425880        ++chan->smp_pos;
    426881
    427         if (chan->sample->loop_len == 0) {
    428                 /* No looping */
     882        switch (chan->sample->loop_type) {
     883        case tl_pingpong_loop:
     884                /** XXX Pingpong loop */
     885        case tl_no_loop:
     886                /* No loop */
    429887                if (chan->smp_pos >= chan->sample->length) {
    430888                        chan->sample = NULL;
    431889                        chan->smp_pos = 0;
    432890                }
    433         } else {
    434                 /** Looping */
     891                break;
     892        case tl_forward_loop:
     893                /** Forward loop */
    435894                if (chan->smp_pos >= chan->sample->loop_start +
    436895                    chan->sample->loop_len) {
     
    455914        trackmod_chan_t *chan = &modplay->chan[cidx];
    456915
    457         if (chan->sample == NULL)
     916        if (chan->sample == NULL || chan->period == 0)
    458917                return 0;
    459918
     
    464923         */
    465924        sl = (int)chan->lsmp * amp_factor * chan->volume / vol_max;
    466         sn = (int)chan->sample->data[chan->smp_pos] * amp_factor *
    467             chan->volume / vol_max;
     925        sn = (int)trackmod_sample_get_frame(chan->sample, chan->smp_pos) *
     926            amp_factor * chan->volume / vol_max;
    468927
    469928        period = (int)chan->period;
  • uspace/lib/trackmod/trackmod.h

    r18cc83c r43dd72b7  
    4040
    4141extern trackmod_module_t *trackmod_module_new(void);
     42extern int trackmod_module_load(char *, trackmod_module_t **);
    4243extern void trackmod_module_destroy(trackmod_module_t *);
    4344extern int trackmod_modplay_create(trackmod_module_t *, unsigned,
     
    4546extern void trackmod_modplay_destroy(trackmod_modplay_t *);
    4647extern void trackmod_modplay_get_samples(trackmod_modplay_t *, void *, size_t);
     48extern int trackmod_sample_get_frame(trackmod_sample_t *, size_t);
    4749
    4850#endif
  • uspace/lib/trackmod/types/protracker.h

    r18cc83c r43dd72b7  
    4747        protracker_olist_len = 128,
    4848        /** Number of rows in a pattern */
    49         protracker_pattern_rows = 64
     49        protracker_pattern_rows = 64,
     50        /** Default TPR */
     51        protracker_def_tpr = 6,
     52        /** Default BPM */
     53        protracker_def_bpm = 125
    5054};
    5155
  • uspace/lib/trackmod/types/trackmod.h

    r18cc83c r43dd72b7  
    4141#include <stdint.h>
    4242
     43enum {
     44        max_key = 96,
     45        keyoff_note = 97
     46};
     47
     48typedef enum {
     49        /** No loop */
     50        tl_no_loop,
     51        /** Forward loop */
     52        tl_forward_loop,
     53        /** Pingpong loop */
     54        tl_pingpong_loop
     55} trackmod_looptype_t;
     56
    4357/** Sample */
    4458typedef struct {
    4559        /** Length in frames */
    4660        size_t length;
     61        /** Bytes per sample */
     62        size_t bytes_smp;
    4763        /** Sample data */
    48         int8_t *data;
     64        void *data;
     65        /** Loop type */
     66        trackmod_looptype_t loop_type;
    4967        /** Loop start position in frames */
    5068        size_t loop_start;
    51         /** Loop length in frames or 0 - no looping */
     69        /** Loop length in frames (> 0) */
    5270        size_t loop_len;
    5371        /** Default volume (0..63) */
    5472        uint8_t def_vol;
     73        /** Relative note */
     74        int rel_note;
     75        /** Finetune value (-8..7) in 1/8 semitones */
     76        int finetune;
    5577} trackmod_sample_t;
     78
     79/** Instrument */
     80typedef struct {
     81        /** Number of samples */
     82        size_t samples;
     83        /** Samples */
     84        trackmod_sample_t *sample;
     85        /** Sample index for each key */
     86        int key_smp[max_key];
     87} trackmod_instr_t;
     88
     89/** Pattern cell */
     90typedef struct {
     91        /** Note */
     92        unsigned note;
     93        /** Sample period */
     94        unsigned period;
     95        /** Instrument number */
     96        unsigned instr;
     97        /** Volume */
     98        uint8_t volume;
     99        /** Effect */
     100        uint16_t effect;
     101} trackmod_cell_t;
    56102
    57103/** Pattern */
     
    62108        size_t channels;
    63109        /** Pattern data */
    64         uint32_t *data;
     110        trackmod_cell_t *data;
    65111} trackmod_pattern_t;
    66112
     
    70116        size_t channels;
    71117        /** Number of samples */
    72         size_t samples;
    73         /** Samples */
    74         trackmod_sample_t *sample;
     118        size_t instrs;
     119        /** Instruments */
     120        trackmod_instr_t *instr;
    75121        /** Number of patterns */
    76122        size_t patterns;
     
    81127        /** Order list */
    82128        size_t *ord_list;
     129        /** Restart pos */
     130        size_t restart_pos;
     131        /** Default BPM */
     132        unsigned def_bpm;
     133        /** Default TPR */
     134        unsigned def_tpr;
    83135} trackmod_module_t;
    84136
     
    92144        /** Sample position (clock ticks within frame) */
    93145        size_t smp_clk;
    94         /** Period */
     146        /** Current period */
    95147        unsigned period;
     148        /** Period after note was processed, zero if no note */
     149        unsigned period_new;
    96150        /** Volume */
    97151        uint8_t volume;
     152        /** Volume slide amount */
     153        int vol_slide;
     154        /** Portamento amount (positive for tone and up portamento,
     155          * negative for down portamento. */
     156        int portamento;
     157        /** Tone portamento target period. */
     158        unsigned period_tgt;
    98159} trackmod_chan_t;
    99160
     
    132193} trackmod_modplay_t;
    133194
    134 /** Pattern cell (decoded) */
    135 typedef struct {
    136         /** Sample period */
    137         unsigned period;
    138         /** Sample number */
    139         unsigned sample;
    140         /** Effect */
    141         unsigned effect;
    142 } trackmod_cell_t;
    143 
    144195#endif
    145196
Note: See TracChangeset for help on using the changeset viewer.