8bitbubsy

kolibrimod (small .mod replayer)

Sep 11th, 2016 (edited)
1,869
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 24.70 KB | None | 0 0
  1. /* kolibrimod - small 1..99ch .MOD replayer by 8bitbubsy - 27th of February 2026 - remember to link winmm.lib!
  2. ** License: BSD-3 clause
  3. */
  4.  
  5. #define AUDIO_RATE 44100
  6. #define AUDIO_BUF_LEN 1024
  7. #define MIX_FRAC_BITS 20 /* do not increase this... */
  8. #define MIX_FRAC_SCALE (1 << MIX_FRAC_BITS)
  9. #define MIX_FRAC_MASK (MIX_FRAC_SCALE-1)
  10.  
  11. #include <assert.h>
  12. #include <stdio.h>
  13. #include <stdlib.h>
  14. #include <string.h>
  15. #include <stdint.h>
  16. #include <stdbool.h>
  17. #include <conio.h> // _getch()
  18. #include <math.h> // powf()
  19. #include <windows.h> // Sleep(), mixer stuff
  20.  
  21. #define AMIGA_STEREO_SEPARATION 25 /* percentage */
  22. #define CLAMP(x, low, high) (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x)))
  23. #define BPM_TO_SAMPLESPERTICK(bpm) ((audioFreq * 5) / (bpm * 2))
  24.  
  25. typedef struct
  26. {
  27.     uint8_t note, sample, efx, param;
  28. } note_t;
  29.  
  30. typedef struct
  31. {
  32.     bool loopFlag;
  33.     int8_t *data;
  34.     uint8_t finetune, volume;
  35.     uint32_t length, loopStart, loopLength;
  36. } sample_t;
  37.  
  38. typedef struct
  39. {
  40.     int8_t *sampleData, *swapData;
  41.     int16_t pan, volL, volR;
  42.     bool loopFlag, swapLoopFlag;
  43.     uint32_t sampleEnd, loopStart, loopLength, swapSampleEnd, swapLoopStart, swapLoopLength, oldPos, pos, frac, delta;
  44. } voice_t;
  45.  
  46. typedef struct
  47. {
  48.     bool noteFlag, sampleLoopFlag;
  49.     int8_t vol, volOut, finetune, *invLoopPtr, *sampleData, *invLoopStartPtr, E6Row, E6Cnt;
  50.     uint8_t note, efx, efx2, portaMem, vibratoDepth, vibratoSpeed, glissandoMode, lastSample;
  51.     uint8_t tremoloDepth, tremoloSpeed, vibratoPos, vibratoType, tremoloPos, tremoloType, invLoopSpeed, invLoopPos;
  52.     uint16_t period, toPeriod, periodOut;
  53.     int32_t sampleOffsetMem, sampleOffset, invLoopLen, sampleLength, sampleLoopStart, sampleLoopLength;
  54. } channel_t;
  55.  
  56. static volatile bool isMixing;
  57. static bool newPosFlag, patLoop, ptMode;
  58. static char songName[20+1];
  59. static int8_t modSpeed, pattNum, tickExtendFactor, newRow, row, *mixerBuffer;
  60. static uint8_t modOrder, restartPos, orderNum, orders[128];
  61. static uint16_t modTick, minPeriod, maxPeriod, periodTab[16][96];
  62. static int32_t pattSize, channels, audioFreq, tickSampleCounter, samplesPerTick, mixBuffer[AUDIO_BUF_LEN*2];
  63. static uint32_t period2Delta;
  64. static note_t *patterns[128], *patternPtr;
  65. static sample_t samples[31];
  66. static const uint8_t invLoopTab[16] = { 0, 5, 6, 7, 8, 10, 11, 13, 16, 19, 22, 26, 32, 43, 64, 128 };
  67. static const uint8_t arpTab[32] = { 0,1,2,0,1,2,0,1,2,0,1,2,0,1,2,0,1,2,0,1,2,0,1,2,0,1,2,0,1,2,0,1 };
  68. static const uint16_t ptPeriods[3*12] = // PT C-3..B-5 note->period table (values multiplied by 4)
  69. {
  70.     3424,3232,3048,2880,2712,2560,2416,2280,2152,2032,1920,1812,
  71.     1712,1616,1524,1440,1356,1280,1208,1140,1076,1016, 960, 904,
  72.      856, 808, 760, 720, 680, 640, 604, 572, 540, 508, 480, 452
  73. };
  74. static const uint16_t loadPeriods[8*12] = // table for period->note on load
  75. {
  76.     6848, 6464, 6096, 5760, 5424, 5120, 4832, 4560, 4304, 4064, 3840, 3624,
  77.     3424, 3232, 3048, 2880, 2712, 2560, 2416, 2280, 2152, 2032, 1920, 1812,
  78.     1712, 1616, 1524, 1440, 1356, 1280, 1208, 1140, 1076, 1016,  960,  906,
  79.      856,  808,  762,  720,  678,  640,  604,  570,  538,  508,  480,  453,
  80.      428,  404,  381,  360,  339,  320,  302,  285,  269,  254,  240,  226,
  81.      214,  202,  190,  180,  170,  160,  151,  143,  135,  127,  120,  113,
  82.      107,  101,   95,   90,   85,   80,   75,   71,   67,   63,   60,   56,
  83.       53,   50,   47,   45,   42,   40,   37,   35,   33,   31,   30,   28
  84. };
  85. static const uint16_t ft2Periods[8*12] = // FT2 C-0..B-7 note->period table (Amiga periods, some notes differ from PT)
  86. {
  87.     27392,25856,24384,23040,21696,20480,19328,18240,17216,16256,15360,14512,
  88.     13696,12928,12192,11520,10848,10240, 9664, 9120, 8608, 8128, 7680, 7256,
  89.      6848, 6464, 6096, 5760, 5424, 5120, 4832, 4560, 4304, 4064, 3840, 3628,
  90.      3424, 3232, 3048, 2880, 2712, 2560, 2416, 2280, 2152, 2032, 1920, 1814,
  91.      1712, 1616, 1524, 1440, 1356, 1280, 1208, 1140, 1076, 1016,  960,  907,
  92.       856,  808,  762,  720,  678,  640,  604,  570,  538,  508,  480,  453,
  93.       428,  404,  381,  360,  339,  320,  302,  285,  269,  254,  240,  227,
  94.       214,  202,  190,  180,  169,  160,  151,  142,  134,  127,  120,  113
  95. };
  96. static const uint8_t sinusTab[32] =
  97. {
  98.     0x00,0x18,0x31,0x4A,0x61,0x78,0x8D,0xA1,0xB4,0xC5,0xD4,0xE0,0xEB,0xF4,0xFA,0xFD,
  99.     0xFF,0xFD,0xFA,0xF4,0xEB,0xE0,0xD4,0xC5,0xB4,0xA1,0x8D,0x78,0x61,0x4A,0x31,0x18
  100. };
  101. static voice_t voice[100];
  102. static channel_t channel[100];
  103. static WAVEHDR waveBlocks[4];
  104. static HWAVEOUT hWaveOut;
  105. static WAVEFORMATEX wfx;
  106.  
  107. static void tickReplayer(void);
  108.  
  109. static uint8_t periodToNote(uint16_t period, uint8_t ftune)
  110. {
  111.     int32_t i;
  112.     for (i = 0; i < 8*12; i++) if (period >= periodTab[ftune][i]) break;
  113.     return (uint8_t)i;
  114. }
  115.  
  116. static void mixChannels(int32_t *mixPtr, uint32_t numSamples)
  117. {
  118.     voice_t *v = voice;
  119.     for (int32_t i = 0; i < channels; i++, v++)
  120.     {
  121.         if (v->sampleData == NULL || v->sampleEnd == 0) continue; // voice is not active
  122.         int32_t *currMixPtr = mixPtr;
  123.         for (uint32_t j = 0; j < numSamples; j++)
  124.         {
  125.             const int16_t sample1 = v->sampleData[v->pos];
  126.  
  127.             int16_t sample2; // read next sample point for linear interpolation
  128.             if (v->pos+1 < v->sampleEnd) // next sample point below end of sample?
  129.             {
  130.                 sample2 = v->sampleData[v->pos+1];
  131.             }
  132.             else // next sample is after sample's end (or loop), fetch correct sample point
  133.             {
  134.                 if (v->swapData == NULL) // no sample swap (common case)
  135.                     sample2 = v->loopFlag ? v->sampleData[v->loopStart] : v->sampleData[v->sampleEnd-1];
  136.                 else // sample swap
  137.                     sample2 = v->swapLoopFlag ? v->sampleData[v->swapLoopStart] : v->sampleData[v->sampleEnd-1];
  138.             }
  139.  
  140.             const int16_t sample = (sample1 << 8) + (((sample2 - sample1) * (int32_t)v->frac) >> (MIX_FRAC_BITS-8));
  141.             *currMixPtr++ += (sample * v->volL) >> 5;
  142.             *currMixPtr++ += (sample * v->volR) >> 5;
  143.             v->frac += v->delta;
  144.             v->pos += v->frac >> MIX_FRAC_BITS;
  145.             v->frac &= MIX_FRAC_MASK;
  146.  
  147.             if (v->pos >= v->sampleEnd) // end of sample?
  148.             {
  149.                 if (v->swapData == NULL) // no sample swap to do
  150.                 {
  151.                     if (v->loopFlag)
  152.                     {
  153.                         do
  154.                         {
  155.                             v->pos -= v->loopLength;
  156.                         }
  157.                         while (v->pos >= v->sampleEnd);
  158.                     }
  159.                     else
  160.                     {
  161.                         v->sampleData = NULL;
  162.                         break;
  163.                     }
  164.                 }
  165.                 else // do sample swapping
  166.                 {
  167.                     if (!v->swapLoopFlag)
  168.                     {
  169.                         v->sampleData = NULL; // illegal swap, turn off voice
  170.                         break;
  171.                     }
  172.  
  173.                     v->sampleData = v->swapData;
  174.                     v->sampleEnd = v->swapSampleEnd;
  175.                     v->loopStart = v->swapLoopStart;
  176.                     v->loopLength = v->swapLoopLength;
  177.                     v->loopFlag = v->swapLoopFlag;
  178.                     v->pos = v->loopStart;
  179.                     v->swapData = NULL; // current sample swap has finished
  180.                 }
  181.             }
  182.         }
  183.     }
  184. }
  185.  
  186. static void CALLBACK waveOutProc(HWAVEOUT _hWaveOut, UINT uMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2)
  187. {
  188.     if (uMsg != MM_WOM_DONE) return;
  189.     WAVEHDR *waveBlockHeader = (WAVEHDR *)dwParam1;
  190.     waveOutUnprepareHeader(_hWaveOut, waveBlockHeader, sizeof (WAVEHDR));
  191.  
  192.     if (!isMixing) return;
  193.     memcpy(waveBlockHeader->lpData, mixerBuffer, AUDIO_BUF_LEN * 2 * sizeof (int16_t));
  194.     waveOutPrepareHeader(_hWaveOut, waveBlockHeader, sizeof (WAVEHDR));
  195.     waveOutWrite(_hWaveOut, waveBlockHeader, sizeof (WAVEHDR));
  196.  
  197.     memset(mixBuffer, 0, AUDIO_BUF_LEN * 2 * sizeof (int32_t));
  198.  
  199.     int32_t *mixBufferPtr = mixBuffer;
  200.     int32_t samplesLeft = AUDIO_BUF_LEN;
  201.     while (samplesLeft > 0)
  202.     {
  203.         if (tickSampleCounter == 0)
  204.         {
  205.             tickReplayer();
  206.             tickSampleCounter = samplesPerTick;
  207.         }
  208.  
  209.         int32_t samplesToMix = samplesLeft;
  210.         if (samplesToMix > tickSampleCounter) samplesToMix = tickSampleCounter;
  211.  
  212.         mixChannels(mixBufferPtr, samplesToMix);
  213.         mixBufferPtr += samplesToMix * 2;
  214.         samplesLeft -= samplesToMix;
  215.         tickSampleCounter -= samplesToMix;
  216.     }
  217.  
  218.     mixBufferPtr = mixBuffer;
  219.     int16_t *streamOut = (int16_t *)mixerBuffer;
  220.     for (int32_t i = 0; i < AUDIO_BUF_LEN; i++)
  221.     {
  222.         const int32_t smpL = (*mixBufferPtr++) >> 10;
  223.         const int32_t smpR = (*mixBufferPtr++) >> 10;
  224.         *streamOut++ = (int16_t)CLAMP(smpL, INT16_MIN, INT16_MAX);
  225.         *streamOut++ = (int16_t)CLAMP(smpR, INT16_MIN, INT16_MAX);
  226.     }
  227.  
  228.     (void)dwParam2;
  229.     (void)dwInstance;
  230. }
  231.  
  232. #define ID(x) !strcmp(magic, x)
  233. static bool getNumbersOfChannels(FILE *in)
  234. {
  235.     char magic[5]; magic[4] = '\0';
  236.     fseek(in, 1080, SEEK_SET);
  237.     fread(magic, 1, 4, in);
  238.     rewind(in);
  239.  
  240.     ptMode = false;
  241.     channels = 0;
  242.     if (ID("M.K.") || ID("M!K!") || ID("NSMS") || ID("LARD") || ID("PATT")) { ptMode = true; channels = 4; } // ProTracker (or compatible)
  243.     else if (magic[1] == 'C' && magic[2] == 'H' && magic[3] == 'N') channels = magic[0] - '0'; // FT2/others
  244.     else if (magic[2] == 'C' && magic[3] == 'H') channels = ((magic[0] - '0') * 10) + (magic[1] - '0'); // FT2/others
  245.  
  246.     if (channels < 1 || channels > 99) return false;
  247.     pattSize = channels * (64 * 4);
  248.     return true;
  249. }
  250.  
  251. static void freeData(void)
  252. {
  253.     for (int32_t i = 0; i < 128; i++)
  254.     {
  255.         if (patterns[i] != NULL)
  256.         {
  257.             free(patterns[i]);
  258.             patterns[i] = NULL;
  259.         }
  260.     }
  261.  
  262.     for (int32_t i = 0; i < 31; i++)
  263.     {
  264.         if (samples[i].data != NULL)
  265.         {
  266.             free(samples[i].data);
  267.             samples[i].data = NULL;
  268.         }
  269.     }
  270. }
  271.  
  272. bool kolibrimodLoad(FILE *in, int32_t audioOutputFreq)
  273. {
  274.     freeData();
  275.     if (!getNumbersOfChannels(in)) return false;
  276.  
  277.     rewind(in);
  278.     fread(songName, 1, 20, in); songName[20] = '\0';
  279.     fseek(in, 950, SEEK_SET);
  280.     fread(&orderNum, 1, 1, in);
  281.     fread(&restartPos, 1, 1, in);
  282.     if (orderNum > 128) return false; // too many orders!
  283.  
  284.     // count number of patterns
  285.     pattNum = 0;
  286.     fseek(in, 952, SEEK_SET);
  287.     for (uint8_t i = 0; i < 128; i++)
  288.     {
  289.         orders[i] = (uint8_t)fgetc(in);
  290.         if (orders[i] > pattNum) pattNum = orders[i];
  291.     }
  292.     pattNum++;
  293.  
  294.     // read sample structs
  295.     memset(samples, 0, sizeof (samples));
  296.     fseek(in, 20, SEEK_SET);
  297.     sample_t *smp = samples;
  298.     for (int32_t i = 0; i < 31; i++, smp++)
  299.     {
  300.         fseek(in, 22, SEEK_CUR);
  301.         uint8_t bytes[8]; fread(bytes, 1, 8, in);
  302.         smp->finetune = bytes[2] & 0xF;
  303.         smp->volume = (bytes[3] > 64) ? 64 : bytes[3];
  304.         smp->length = ((bytes[0] << 8) | bytes[1]) * 2;
  305.         smp->loopStart = ((bytes[4] << 8) | bytes[5]) * 2;
  306.         smp->loopLength = ((bytes[6] << 8) | bytes[7]) * 2;
  307.         smp->loopFlag = (smp->loopStart+smp->loopLength) > 2;
  308.     }
  309.  
  310.     // load pattern data
  311.     fseek(in, 1084, SEEK_SET);
  312.     for (int32_t i = 0; i < pattNum; i++)
  313.     {
  314.         patterns[i] = (note_t *)malloc(pattSize);
  315.         if (patterns[i] == NULL) { freeData(); return false; };
  316.         note_t *p = patterns[i];
  317.         for (int32_t j = 0; j < channels*64; j++, p++)
  318.         {
  319.             uint8_t bytes[4]; fread(bytes, 1, 4, in);
  320.             uint16_t period = ((bytes[0] & 0x0F) << 8) | bytes[1];
  321.             if (ptMode && period != 0 && (period < 113 || period > 856)) // scan for extended periods
  322.                 ptMode = false;
  323.        
  324.             int32_t k = 0; // convert period to note number (0..95, 96 = none/illegal)
  325.             for (; k < 8*12; k++)
  326.                 if (period >= loadPeriods[k])
  327.                     break;
  328.             p->note = k;
  329.  
  330.             p->sample = (bytes[0] & 0xF0) | (bytes[2] >> 4);
  331.             p->efx = bytes[2] & 0xF;
  332.             p->param = bytes[3];
  333.         }
  334.     }
  335.  
  336.     // load sample data
  337.     fseek(in, 1084 + (pattSize * pattNum), SEEK_SET);
  338.     smp = samples;
  339.     for (int32_t i = 0; i < 31; i++, smp++)
  340.     {
  341.         if (smp->length == 0) continue;
  342.         smp->data = (int8_t *)malloc(smp->length);
  343.         if (smp->data == NULL) { freeData(); return false; };
  344.         fread(smp->data, 1, smp->length, in);
  345.     }
  346.  
  347.     memset(&wfx, 0, sizeof (wfx));
  348.     audioFreq = audioOutputFreq;
  349.     wfx.nSamplesPerSec = audioFreq;
  350.     wfx.wBitsPerSample = 16;
  351.     wfx.nChannels = 2;
  352.     wfx.wFormatTag = WAVE_FORMAT_PCM;
  353.     wfx.nBlockAlign = (wfx.wBitsPerSample * wfx.nChannels) / 8;
  354.     wfx.nAvgBytesPerSec = wfx.nBlockAlign * wfx.nSamplesPerSec;
  355.     mixerBuffer = (int8_t *)calloc(AUDIO_BUF_LEN * 2 * sizeof (int16_t), 1);
  356.  
  357.     waveOutOpen(&hWaveOut, WAVE_MAPPER, &wfx, (DWORD_PTR)waveOutProc, 0, CALLBACK_FUNCTION);
  358.     for (int32_t i = 0; i < 4; i++)
  359.     {
  360.         waveBlocks[i].dwBufferLength = AUDIO_BUF_LEN * 2 * sizeof (int16_t);
  361.         waveBlocks[i].lpData = (LPSTR)calloc(AUDIO_BUF_LEN * 2 * sizeof (int16_t), 1);
  362.         waveOutPrepareHeader(hWaveOut, &waveBlocks[i], sizeof (WAVEHDR));
  363.         waveOutWrite(hWaveOut, &waveBlocks[i], sizeof (WAVEHDR));
  364.     }
  365.  
  366.     // calculate finetuned period table
  367.     const int32_t noteOfs = ptMode ? (3*12) : 0;
  368.     const uint16_t *note2Period = ptMode ? ptPeriods : ft2Periods;
  369.     for (int32_t ftune = 0; ftune < 16; ftune++)
  370.     {
  371.         const float fMul = powf(2.0f, ((ftune ^ 8) - 8) / -(12.0f * 8.0f));
  372.         for (int32_t note = 0; note < 8*12; note++)
  373.         {
  374.             periodTab[ftune][note] = UINT16_MAX; // illegal note
  375.             if (!(ptMode && (note < 3*12 || note >= 6*12)))
  376.                 periodTab[ftune][note] = (uint16_t)((note2Period[note-noteOfs] * fMul) + 0.5f); // rounded
  377.         }
  378.     }
  379.  
  380.     minPeriod = ptMode ? (113 * 4) : 1;
  381.     maxPeriod = 32000-1;
  382.  
  383.     const int32_t periodClock = ptMode ? (3546895 * 4) : (3579364 * 4);
  384.     period2Delta = (uint32_t)round((periodClock / (double)audioFreq) * MIX_FRAC_SCALE);
  385.  
  386.     return true;
  387. }
  388.  
  389. bool kolibrimodPlay(void)
  390. {
  391.     memset(channel, 0, sizeof (channel));
  392.     memset(voice, 0, sizeof (voice));
  393.  
  394.     for (int32_t i = 0; i < channels; i++) // set up initial LRRL channel pannings
  395.     {
  396.         voice[i].pan = 128; // center (initial position for non-PT modules)
  397.         const int32_t panning = (AMIGA_STEREO_SEPARATION * 128) / 100;
  398.         if (ptMode)
  399.             voice[i].pan = !((i + 1) & 2) ? (128-panning) : (128+panning); // Amiga panning - LRRL
  400.     }
  401.  
  402.     modSpeed = 6;
  403.     samplesPerTick = BPM_TO_SAMPLESPERTICK(125);
  404.     tickSampleCounter = 0; // zero tick sample counter so that it will instantly initiate a tick
  405.     modTick = modSpeed-1; // don't render a tick of silence
  406.     row = newRow = modOrder = 0;
  407.     tickExtendFactor = 1; // 1 = no delay
  408.     newPosFlag = patLoop = false;
  409.     patternPtr = patterns[orders[modOrder]];
  410.     isMixing = true;
  411.     return true;
  412. }
  413.  
  414. void kolibrimodFree(void)
  415. {
  416.     isMixing = false;
  417.     for (int32_t i = 0; i < 4; i++)
  418.         waveOutUnprepareHeader(hWaveOut, &waveBlocks[i], sizeof (WAVEHDR));
  419.  
  420.     for (int32_t i = 0; i < 4; i++)
  421.     {
  422.         while (waveBlocks[i].dwFlags & WHDR_PREPARED) SleepEx(1, 1); // wait
  423.         if (waveBlocks[i].lpData != NULL) free(waveBlocks[i].lpData); waveBlocks[i].lpData = NULL;
  424.     }
  425.  
  426.     waveOutReset(hWaveOut);
  427.     waveOutClose(hWaveOut);
  428.  
  429.     if (mixerBuffer != NULL)
  430.     {
  431.         free(mixerBuffer);
  432.         mixerBuffer = NULL;
  433.     }
  434.  
  435.     freeData();
  436. }
  437.  
  438. static void triggerVoice(channel_t *c, voice_t *v)
  439. {
  440.     v->sampleData = c->sampleData;
  441.     v->loopStart = c->sampleLoopStart;
  442.     v->loopFlag = c->sampleLoopFlag;
  443.     v->sampleEnd = v->loopFlag ? (c->sampleLoopStart + c->sampleLoopLength) : c->sampleLength;
  444.     v->loopLength = c->sampleLoopLength;
  445.     v->swapData = NULL;
  446.     v->frac = 0;
  447.     c->period = c->toPeriod;
  448.  
  449.     v->pos = v->oldPos = c->sampleOffset; // 9xx sample offset * 256
  450.     if (v->pos >= v->sampleEnd)
  451.     {
  452.         if (v->loopFlag)
  453.             v->pos = v->loopStart;
  454.         else
  455.             v->sampleData = NULL; // cut voice
  456.     }
  457. }
  458.  
  459. static void portamento(channel_t *c)
  460. {
  461.     if (c->period == 0 || c->toPeriod == 0) return;
  462.  
  463.     if (c->period > c->toPeriod)
  464.     {
  465.         c->period -= c->portaMem*4;
  466.         if ((int16_t)c->period <= c->toPeriod) c->period = c->toPeriod;
  467.     }
  468.     else if (c->period < c->toPeriod)
  469.     {
  470.         c->period += c->portaMem*4;
  471.         if (c->period >= c->toPeriod) c->period = c->toPeriod;
  472.     }
  473.  
  474.     c->periodOut = c->period;
  475.     if (c->glissandoMode != 0) // semitones slide
  476.     {
  477.         const uint8_t note = periodToNote(c->periodOut, c->finetune);
  478.         if (note < 96) c->periodOut = periodTab[c->finetune][note];
  479.     }
  480. }
  481.  
  482. static uint16_t getWaveform(channel_t *c, bool tremoloFlag)
  483. {
  484.     const uint8_t type = tremoloFlag ? c->tremoloType : c->vibratoType;
  485.     uint8_t pos = ((tremoloFlag ? c->tremoloPos : c->vibratoPos) >> 2) & 0x1F;
  486.  
  487.     uint8_t data;
  488.          if (type == 0) { data = sinusTab[pos]; }
  489.     else if (type == 1) { data = pos << 3; if (c->vibratoPos >= 128) data = ~data; } // PT2/FT2 bug: always uses vibrato pos
  490.     else                { data = 255; }
  491.  
  492.     return tremoloFlag ? ((data * c->tremoloDepth) >> 6) : ((data * c->vibratoDepth) >> (7-2));
  493. }
  494.  
  495. static void vibrato(channel_t *c)
  496. {
  497.     const uint16_t data = getWaveform(c, false);
  498.     c->periodOut = c->period + ((c->vibratoPos < 128) ? data : -data);
  499.     if (modTick > 0) c->vibratoPos += c->vibratoSpeed;
  500. }
  501.  
  502. static void tremolo(channel_t *c)
  503. {
  504.     const uint16_t data = getWaveform(c, true);
  505.     c->volOut = c->vol + ((c->tremoloPos < 128) ? data : -data);
  506.     c->volOut = CLAMP(c->volOut, 0, 64);
  507.     if (modTick > 0) c->tremoloPos += c->tremoloSpeed;
  508. }
  509.  
  510. static void volumeSlide(channel_t *c)
  511. {
  512.     if (modTick == 0) return;
  513.     c->vol += (c->efx2 & 0xF0) ? (c->efx2 >> 4) : -(c->efx2 & 0xF);
  514.     c->vol = CLAMP(c->vol, 0, 64);
  515. }
  516.  
  517. static void invertLoop(channel_t *c) // ProTracker only
  518. {
  519.     if ((c->invLoopPos += invLoopTab[c->invLoopSpeed]) < 128) return;
  520.     c->invLoopPos = 0;
  521.     if (c->invLoopPtr == NULL) return;
  522.     if (++c->invLoopPtr >= c->invLoopStartPtr+c->invLoopLen) c->invLoopPtr = c->invLoopStartPtr;
  523.     *c->invLoopPtr = -1 - *c->invLoopPtr;
  524. }
  525.  
  526. static void retrigNote(channel_t *c, voice_t *v) // E9x effect
  527. {
  528.     if (c->efx2 > 0x90 && !(modTick == 0 && c->noteFlag) && !(modTick % (c->efx2 & 0xF)))
  529.     {
  530.         v->pos = v->oldPos;
  531.         v->frac = 0;
  532.     }
  533. }
  534.  
  535. static void checkEfx(void)
  536. {
  537.     uint16_t period;
  538.     channel_t *c = channel;
  539.     voice_t *v = voice;
  540.     for (int32_t i = 0; i < channels; i++, c++, v++) // do effects
  541.     {
  542.         if (ptMode && modTick > 0) invertLoop(c);
  543.  
  544.         if (c->efx != 0 || c->efx2 != 0)
  545.         {
  546.             if (modTick == 0)
  547.             {   // tick=0 effects
  548.                      if (c->efx == 0x8) { if (!ptMode) v->pan = c->efx2; }
  549.                 else if (c->efx == 0xB) { newPosFlag = true; newRow = 0; modOrder = c->efx2 - 1; }
  550.                 else if (c->efx == 0xC) { c->vol = (c->efx2 > 64) ? 64 : c->efx2; }
  551.                 else if (c->efx == 0xD) { newPosFlag = true; newRow = ((c->efx2 >> 4) * 10) + (c->efx2 & 0xF); if (newRow > 63) newRow = 0; }
  552.                 else if (c->efx == 0xE)
  553.                 {
  554.                          if ((c->efx2&0xF0)==0x10) { if (c->period > 0) { c->period -= (c->efx2 & 0xF)*4; if ((int16_t)c->period < minPeriod) c->period = minPeriod; } }
  555.                     else if ((c->efx2&0xF0)==0x20) { if (c->period > 0) { c->period += (c->efx2 & 0xF)*4; if ((int16_t)c->period > maxPeriod) c->period = maxPeriod; } }
  556.                     else if ((c->efx2&0xF0)==0x30) { c->glissandoMode = c->efx2 & 0xF; }
  557.                     else if ((c->efx2&0xF0)==0x40) { c->vibratoType = c->efx2 & 0xF; }
  558.                     else if ((c->efx2&0xF0)==0x50) { c->finetune = ptMode ? (c->efx2 & 0xF) : (c->efx2 - 8) & 0xF; }
  559.                     else if ((c->efx2&0xF0)==0x60) { if (c->efx2==0x60) c->E6Row = row; else { if (!c->E6Cnt) c->E6Cnt = c->efx2&0xF;
  560.                                                                            else if (!--c->E6Cnt) return; newRow = c->E6Row; patLoop = true; }}
  561.                     else if ((c->efx2&0xF0)==0x70) { c->tremoloType = c->efx2 & 0xF; }
  562.                     else if ((c->efx2&0xF0)==0x90) retrigNote(c, v);
  563.                     else if ((c->efx2&0xF0)==0xA0) { c->vol += c->efx2 & 0xF; if (c->vol > 64) c->vol = 64; }
  564.                     else if ((c->efx2&0xF0)==0xB0) { c->vol -= c->efx2 & 0xF; if (c->vol < 0) c->vol = 0; }
  565.                     else if ((c->efx2&0xF0)==0xE0) { tickExtendFactor = (c->efx2 & 0xF) + 1; }
  566.                     else if ((c->efx2&0xF0)==0xF0) { if (ptMode) { c->invLoopSpeed = c->efx2 & 0xF; invertLoop(c); } }
  567.                 }
  568.                 else if (c->efx == 0xF) if (c->efx2 < 0x20) { if (c->efx2) modSpeed = c->efx2; } else { samplesPerTick = BPM_TO_SAMPLESPERTICK(c->efx2); }
  569.             }
  570.             else
  571.             {   // tick>0 effects
  572.                      if (c->efx == 0x1) { if (c->period > 0) { c->period -= c->efx2*4; if ((int16_t)c->period < minPeriod) c->period = minPeriod; } }
  573.                 else if (c->efx == 0x2) { if (c->period > 0) { c->period += c->efx2*4; if ((int16_t)c->period > maxPeriod) c->period = maxPeriod; } }
  574.                 else if (c->efx == 0x3) { if (c->efx2) c->portaMem = c->efx2; portamento(c); }
  575.                 else if (c->efx == 0x4) { if (c->efx2&0xF) c->vibratoDepth = c->efx2&0xF; if (c->efx2&0xF0) c->vibratoSpeed = (c->efx2>>4)*4; vibrato(c); }
  576.                 else if (c->efx == 0x5) { portamento(c); volumeSlide(c); }
  577.                 else if (c->efx == 0x6) { vibrato(c);  volumeSlide(c); }
  578.                 else if (c->efx == 0x7) { if (c->efx2&0xF) c->tremoloDepth = c->efx2&0xF; if (c->efx2&0xF0) c->tremoloSpeed = (c->efx2>>4)*4; tremolo(c); }
  579.                 else if (c->efx == 0xE) { if ((c->efx2 & 0xF0) == 0x90) retrigNote(c, v); }
  580.                 else if (c->efx == 0xA) { volumeSlide(c); }
  581.             }
  582.         }
  583.        
  584.              if ((c->efx == 0xE) && (c->efx2 & 0xF0) == 0xC0) { if (modTick == (c->efx2 & 0xF)) c->vol = 0; }
  585.         else if ((c->efx == 0xE) && (c->efx2 & 0xF0) == 0xD0) { if (modTick == (c->efx2 & 0xF) && c->noteFlag) triggerVoice(c, v); }
  586.  
  587.         period = c->period;
  588.         if (c->efx == 0 && c->efx2 != 0 && period > 0) // do arpeggio here
  589.         {
  590.             uint8_t note = periodToNote(period, c->finetune);
  591.             if (note < 96)
  592.             {
  593.                 const uint8_t arpTick = arpTab[modTick];
  594.                      if (arpTick == 1) note += c->efx2 >> 4;
  595.                 else if (arpTick == 2) note += c->efx2 & 0xF;
  596.                 if (note > 95) note = 95;
  597.                 period = periodTab[c->finetune][note];
  598.             }
  599.         }
  600.  
  601.         // vibrato and portamento modifies the output period directly
  602.         if (c->efx != 4 && c->efx != 6 && c->efx != 3 && c->efx != 5) c->periodOut = period;
  603.         if (c->periodOut == 0) v->delta = 0; else v->delta = period2Delta / CLAMP(c->periodOut, minPeriod, maxPeriod);
  604.  
  605.         if (c->efx != 7) c->volOut = c->vol; // tremolo modifies the output volume directly
  606.         v->volL = c->volOut * (256-v->pan); // scale = vol(0..64) * pan(0..256)
  607.         v->volR = c->volOut *      v->pan;
  608.     }
  609. }
  610.  
  611. static void tickReplayer(void)
  612. {
  613.     if (++modTick >= modSpeed*tickExtendFactor)
  614.     {
  615.         modTick = 0;
  616.         tickExtendFactor = 1; // reset EEx (pattern delay). 1 = no delay
  617.  
  618.         channel_t *c = channel;
  619.         voice_t *v = voice;
  620.         for (uint8_t i = 0; i < channels; i++, c++, v++) // read pattern data
  621.         {
  622.             const note_t *note = &patternPtr[(row*channels) + i];
  623.             c->noteFlag = note->note != 96;
  624.             const uint8_t sample = note->sample;
  625.             c->efx = note->efx;
  626.             c->efx2 = note->param;
  627.             if (ptMode && (c->efx == 4 || c->efx == 6)) c->periodOut = c->period;
  628.  
  629.             const bool noteDelay = (c->efx == 0xE) && ((c->efx2 & 0xF0) == 0xD0);
  630.             const bool porta = (c->efx == 0x3 || c->efx == 0x5);
  631.  
  632.             if (sample >= 1 && sample <= 31) // sample found in pattern data
  633.             {
  634.                 sample_t *s = &samples[sample-1];
  635.                 c->finetune = s->finetune;
  636.                 c->volOut = c->vol = s->volume;
  637.                 c->sampleLength = s->length;
  638.                 c->sampleLoopStart = s->loopStart;
  639.                 c->sampleLoopLength = s->loopLength;
  640.                 c->sampleLoopFlag = s->loopFlag;
  641.                 c->sampleData = s->data;
  642.                 c->sampleOffset = 0;
  643.                 if (!ptMode) v->pan = 128; // reset panning (FT2 mode)
  644.  
  645.                 if (sample != c->lastSample && ptMode && (v->sampleData != NULL) && (!c->noteFlag || porta))
  646.                 {   // do ProTracker sample swap (if voice is active and no pattern note)
  647.                     v->swapData = c->sampleData;
  648.                     v->swapLoopStart = c->sampleLoopStart;
  649.                     v->swapLoopLength = c->sampleLoopLength;
  650.                     v->swapLoopFlag = c->sampleLoopFlag;
  651.                     v->swapSampleEnd = v->swapLoopFlag ? (c->sampleLoopStart + c->sampleLoopLength) : c->sampleLength;
  652.                 }
  653.  
  654.                 c->invLoopLen = c->sampleLoopLength;
  655.                 c->invLoopPtr = c->invLoopStartPtr = &c->sampleData[c->sampleLoopStart];
  656.                 c->lastSample = sample;
  657.             }
  658.  
  659.             if (c->efx == 0x9) // 9xx "set sample offset" efx must be handled here
  660.             {
  661.                 if (c->efx2 > 0) c->sampleOffsetMem = c->efx2 << 8;
  662.                 c->sampleOffset = c->sampleOffsetMem;
  663.             }
  664.  
  665.             if (c->noteFlag) // note found in pattern data
  666.             {
  667.                 if (c->efx == 0xE && (c->efx2 & 0xF0) == 0x50) // set-finetune efx must be handled here as well
  668.                     c->finetune = ptMode ? (c->efx2 & 0xF) : (c->efx2 - 8) & 0xF;
  669.  
  670.                 c->note = note->note;
  671.                 c->toPeriod = periodTab[c->finetune][c->note];
  672.  
  673.                 // trigger sample if no portamento (3xx and 5xy) and no note delay
  674.                 if (c->efx != 0x03 && c->efx != 0x05 && !noteDelay)
  675.                 {
  676.                     c->vibratoPos = c->tremoloPos = 0; // reset vibrato/tremolo position
  677.                     triggerVoice(c, v);
  678.                     c->periodOut = c->period = c->toPeriod; // set initial period
  679.                 }
  680.             }
  681.         }
  682.  
  683.         checkEfx();
  684.  
  685.         if (patLoop) // handle pattern loop (E6x)
  686.         {
  687.             row = newRow;
  688.             newRow = 0;
  689.             newPosFlag = patLoop = false;
  690.         }
  691.         else if (++row >= 64) newPosFlag = true; // increase row like normal
  692.     }
  693.     else checkEfx();
  694.  
  695.     if (newPosFlag) // handle position jump (Bxx), pattern break (Dxx) or end of pattern
  696.     {
  697.         row = newRow;
  698.         newRow = 0;
  699.         newPosFlag = false;
  700.         if (++modOrder >= orderNum)
  701.             modOrder = (restartPos < orderNum) ? restartPos : 0; // loop (wrap) song
  702.         patternPtr = patterns[orders[modOrder]];
  703.     }
  704. }
  705.  
  706. int main(int argc, char *argv[]) // please edit this for your own use!
  707. {
  708. #ifdef _DEBUG
  709.     FILE *f = fopen("debug.mod", "rb");
  710. #else
  711.     if (argc != 2)
  712.     {
  713.         printf("Usage: kolibrimod.exe <module>\n");
  714.         return -1;
  715.     }
  716.  
  717.     FILE *f = fopen(argv[1], "rb");
  718. #endif
  719.     if (f == NULL)
  720.     {
  721.         printf("ERROR: Can't open file!\n");
  722.         return 1;
  723.     }
  724.  
  725.     if (!kolibrimodLoad(f, AUDIO_RATE))
  726.     {
  727.         printf("ERROR: This .MOD is not supported!\n");
  728.         return 1;
  729.     }
  730.  
  731.     fclose(f);
  732.     kolibrimodPlay();
  733.  
  734.     printf("Playing \"%s\" (%dHz - %d channels)\nPress any key to stop...\n",
  735.         songName, audioFreq, channels);
  736.     while (!_getch()) Sleep(250);
  737.     kolibrimodFree();
  738.  
  739.     return 0;
  740. }
  741.  
Advertisement
Add Comment
Please, Sign In to add comment