Advertisement
8bitbubsy

kolibrimod (small .mod replayer)

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