8bitbubsy

kolibrimod (small .mod replayer)

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

Adblocker detected! Please consider disabling it...

We've detected AdBlock Plus or some other adblocking software preventing Pastebin.com from fully loading.

We don't have any obnoxious sound, or popup ads, we actively block these annoying types of ads!

Please add Pastebin.com to your ad blocker whitelist or disable your adblocking software.

×