8bitbubsy

kolibrimod (tiny .mod replayer)

Sep 11th, 2016
900
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /* kolibrimod - tiny 1..99ch .MOD replayer by 8bitbubsy - 6th of July 2020 - remember to link winmm.lib!
  2. ** Missing effects: E4x (vibrato type), E7x (tremolo type)
  3. ** Note: This is not very optimized, the main focus is amount of code lines + okay replayer accuracy.
  4. ** License: WTFPL (www.wtfpl.net)
  5. */
  6.  
  7. #include <stdio.h>
  8. #include <stdlib.h>
  9. #include <string.h>
  10. #include <stdint.h>
  11. #include <stdbool.h>
  12. #include <conio.h> // _getch()
  13. #include <math.h> // ceil(),log2()
  14. #include <windows.h> // Sleep(), mixer stuff
  15.  
  16. #define AUDIO_RATE 48000 /* 44100 or 48000 only! */
  17. #define OVERSAMPLE_FACTOR 16 /* 2^n, must not be less than 4 (ruins sample looping) */
  18.  
  19. #define MIX_BUF_NUM 4
  20. #define MIX_BUF_LEN 4096
  21. #define MAX_VOICES 99
  22. #define MAX_NOTES 96
  23. #define FRAC_BITS 28 /* absolute max safe bits! */
  24. #define FRAC_SCALE (1UL << FRAC_BITS)
  25. #define FRAC_MASK (FRAC_SCALE-1)
  26. #define PT_BASE_CLK (3546895*4) /* ProTracker (middle-C = ~8287.14Hz) */
  27. #define PT_MIN_PERIOD (113*4)
  28. #define PT_MAX_PERIOD (856*4)
  29. #define BASE_CLK (8363*1712) /* FT2 and other trackers (middle-C = 8363.00Hz) */
  30. #define MIN_PERIOD (28*4)
  31. #define MAX_PERIOD (6848*4)
  32. #define ABSOLUTE_MIN_PERIOD (27*4) /* period 28 at finetune 7 */
  33. #define BPM2SAMPLES_PER_TICK(x) (audioFreq / ((x) / 2.5))
  34. #define CLAMP(x, low, high) (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x)))
  35. #define CLAMP16(i) if ((int16_t)(i) != i) i = 0x7FFF ^ (i >> 31)
  36. #define PERIOD2DELTA(p) (int32_t)(((dBaseClk / (p)) * dHz2DeltaMul) + 0.5)
  37. #define ADJUST_PERIOD(p, f) (int32_t)((((p) * 4) * fPeriodMulTab[f]) + 0.5f)
  38.  
  39. typedef struct
  40. {
  41.     int8_t *sampleData, *swapData;
  42.     int16_t panL, panR, volL, volR;
  43.     bool loopFlag, swapLoopFlag;
  44.     uint32_t sampleEnd, loopStart, swapSampleEnd, swapLoopStart, oldPos, pos;
  45.     uint32_t frac, delta;
  46. } voice_t;
  47.  
  48. typedef struct
  49. {
  50.     int8_t vol, volOut, ftune, *invLoopPtr, *sampleData, *invLoopStartPtr, E6Row, E6Cnt;
  51.     uint8_t note, efx, efx2, portaMem, vibratoDepth, vibratoSpeed, glissandoMode;
  52.     uint8_t tremoloDepth, tremoloSpeed, vibratoPos, tremoloPos, invLoopSpeed, invLoopPos;
  53.     uint16_t rawPeriod, period, toPeriod;
  54.     int32_t sampleOffsetMem, sampleOffset, invLoopLen, sampleLen, loopStart, loopLen, periodOut;
  55. } channel_t;
  56.  
  57. static volatile bool isMixing;
  58. static bool newPosFlag, patLoop, ptMode;
  59. static char songName[20+1];
  60. static int8_t smpShift, modSpeed, pattNum, tickExtendFactor, newRow, row, *mixerBuffer, *sampleDataPointers[31];
  61. static uint8_t *modData, order, *pattPtr;
  62. static uint16_t modTick, minPeriod = PT_MIN_PERIOD, maxPeriod = PT_MAX_PERIOD;
  63. static int32_t pattSize, channels, audioFreq, mixBuffer[(MIX_BUF_LEN*OVERSAMPLE_FACTOR)/2];
  64. static double dBaseClk = PT_BASE_CLK, dHz2DeltaMul, dSamplesPerTick, dTickSampleCounter;
  65. static const uint8_t invLoopTab[16] = { 0, 5, 6, 7, 8, 10, 11, 13, 16, 19, 22, 26, 32, 43, 64, 128 };
  66. static const int16_t periodTab[MAX_NOTES] =
  67. {
  68.     6848, 6464, 6096, 5760, 5424, 5120, 4832, 4560, 4304, 4064, 3840, 3624,
  69.     3424, 3232, 3048, 2880, 2712, 2560, 2416, 2280, 2152, 2032, 1920, 1812,
  70.     1712, 1616, 1524, 1440, 1356, 1280, 1208, 1140, 1076, 1016,  960,  906,
  71.      856,  808,  762,  720,  678,  640,  604,  570,  538,  508,  480,  453,
  72.      428,  404,  381,  360,  339,  320,  302,  285,  269,  254,  240,  226,
  73.      214,  202,  190,  180,  170,  160,  151,  143,  135,  127,  120,  113,
  74.      107,  101,   95,   90,   85,   80,   75,   71,   67,   63,   60,   56,
  75.       53,   50,   47,   45,   42,   40,   37,   35,   33,   31,   30,   28
  76. };
  77. static const int16_t sinusTab[64] =
  78. {
  79.      0x00,  0x18,  0x31,  0x4A,  0x61,  0x78,  0x8D,  0xA1,  0xB4,  0xC5,  0xD4,  0xE0,  0xEB,  0xF4,  0xFA,  0xFD,
  80.      0xFF,  0xFD,  0xFA,  0xF4,  0xEB,  0xE0,  0xD4,  0xC5,  0xB4,  0xA1,  0x8D,  0x78,  0x61,  0x4A,  0x31,  0x18,
  81.     -0x00, -0x18, -0x31, -0x4A, -0x61, -0x78, -0x8D, -0xA1, -0xB4, -0xC5, -0xD4, -0xE0, -0xEB, -0xF4, -0xFA, -0xFD,
  82.     -0xFF, -0xFD, -0xFA, -0xF4, -0xEB, -0xE0, -0xD4, -0xC5, -0xB4, -0xA1, -0x8D, -0x78, -0x61, -0x4A, -0x31, -0x18
  83. };
  84. static const float fPeriodMulTab[16] = // finetune 0..15
  85. {
  86.     1.000000f, 0.992806f, 0.985663f, 0.978572f, 0.971532f, 0.964542f, 0.957603f, 0.950714f,
  87.     1.059463f, 1.051841f, 1.044274f, 1.036761f, 1.029302f, 1.021897f, 1.014545f, 1.007246f
  88. };
  89. static voice_t voice[MAX_VOICES];
  90. static channel_t channel[MAX_VOICES];
  91. static WAVEHDR waveBlocks[MIX_BUF_NUM];
  92. static HWAVEOUT hWaveOut;
  93. static WAVEFORMATEX wfx;
  94.  
  95. static void tickReplayer(void);
  96.  
  97. static uint8_t periodToNote(int32_t period, int32_t finetune)
  98. {
  99.     const float fMul = 4.0f * fPeriodMulTab[finetune];
  100.     int32_t i;
  101.     if (period == 0) return MAX_NOTES;
  102.     for (i = 0; i < MAX_NOTES; i++) if (period >= (int32_t)(periodTab[i]*fMul)) break;
  103.     return (uint8_t)i;
  104. }
  105.  
  106. static void mixChannels(int16_t *audioOutPtr, int32_t numSamples)
  107. {
  108.     memset(mixBuffer, 0, numSamples * (sizeof (int32_t) * OVERSAMPLE_FACTOR * 2));
  109.  
  110.     voice_t *v = voice;
  111.     const int32_t samplesToMix = numSamples * OVERSAMPLE_FACTOR;
  112.     for (int32_t i = 0; i < channels; i++, v++)
  113.     {
  114.         if (v->sampleData == NULL || v->sampleEnd <= 0) continue; // voice is not active
  115.         int32_t *mixPtr = mixBuffer;
  116.         const uint32_t delta = v->delta;
  117.         const int16_t volL = v->volL;
  118.         const int16_t volR = v->volR;
  119.         for (int32_t j = 0; j < samplesToMix; j++)
  120.         {
  121.             if (v->pos >= v->sampleEnd) // XXX: this needs optimization...
  122.             {
  123.                 if (v->swapData == NULL)
  124.                 { // multi-step deltas never happen (oversampling), so we don't need to handle overflow samples
  125.                     if (v->loopFlag) { v->pos = v->loopStart; } else { v->sampleData = NULL; break; }
  126.                 }
  127.                 else
  128.                 { // do sample swapping
  129.                     if (!v->swapLoopFlag) { v->sampleData = NULL; break; } // illegal swap
  130.                     v->sampleData = v->swapData;
  131.                     v->sampleEnd = v->swapSampleEnd;
  132.                     v->loopStart = v->swapLoopStart;
  133.                     v->loopFlag = v->swapLoopFlag;
  134.                     v->swapData = NULL; // turn off sample swap
  135.                     v->pos = v->loopStart;
  136.                 }
  137.             }
  138.  
  139.             const int8_t smp8 = v->sampleData[v->pos];
  140.             (*mixPtr++) += smp8 * volL; // (-128..127)*(0..16384) = -2097152..2080768
  141.             (*mixPtr++) += smp8 * volR;
  142.             v->frac += delta;
  143.             v->pos += v->frac >> FRAC_BITS;
  144.             v->frac &= FRAC_MASK;
  145.         }
  146.     }
  147.  
  148.     const int32_t *mixBufferPtr = mixBuffer;
  149.     for (int32_t i = 0; i < numSamples; i++)
  150.     {
  151.         int64_t avg64L = 0, avg64R = 0; // get average L/R sample from N oversampled samples
  152.         for (int32_t j = 0; j < OVERSAMPLE_FACTOR; j++)
  153.         {
  154.             avg64L += *mixBufferPtr++;
  155.             avg64R += *mixBufferPtr++;
  156.         }
  157.  
  158.         int32_t smpL = (int32_t)(avg64L >> smpShift);
  159.         int32_t smpR = (int32_t)(avg64R >> smpShift);
  160.  
  161.         CLAMP16(smpL);
  162.         CLAMP16(smpR);
  163.  
  164.         *audioOutPtr++ = (int16_t)smpL;
  165.         *audioOutPtr++ = (int16_t)smpR;
  166.     }
  167. }
  168.  
  169. static void CALLBACK waveOutProc(HWAVEOUT _hWaveOut, UINT uMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2)
  170. {
  171.     if (uMsg != MM_WOM_DONE) return;
  172.     WAVEHDR *waveBlockHeader = (WAVEHDR *)dwParam1;
  173.     waveOutUnprepareHeader(_hWaveOut, waveBlockHeader, sizeof (WAVEHDR));
  174.  
  175.     if (!isMixing) return;
  176.     memcpy(waveBlockHeader->lpData, mixerBuffer, MIX_BUF_LEN);
  177.     waveOutPrepareHeader(_hWaveOut, waveBlockHeader, sizeof (WAVEHDR));
  178.     waveOutWrite(_hWaveOut, waveBlockHeader, sizeof (WAVEHDR));
  179.  
  180.     int16_t *streamOut = (int16_t *)mixerBuffer;
  181.     int32_t samplesLeft = MIX_BUF_LEN / 4;
  182.     while (samplesLeft > 0)
  183.     {
  184.         if (dTickSampleCounter <= 0.0)
  185.         {
  186.             tickReplayer();
  187.             dTickSampleCounter += dSamplesPerTick;
  188.         }
  189.  
  190.         const int32_t remainingTick = (int32_t)ceil(dTickSampleCounter);
  191.         int32_t samplesToMix = samplesLeft;
  192.         if (samplesToMix > remainingTick) samplesToMix = remainingTick;
  193.  
  194.         mixChannels(streamOut, samplesToMix);
  195.         streamOut += samplesToMix * 2;
  196.         samplesLeft -= samplesToMix;
  197.         dTickSampleCounter -= samplesToMix;
  198.     }
  199.  
  200.     (void)dwParam2;
  201.     (void)dwInstance;
  202. }
  203.  
  204. static bool getNumbersOfChannels(FILE *in)
  205. {
  206.     char magic[5]; magic[4] = '\0';
  207.     fseek(in, 1080, SEEK_SET);
  208.     fread(magic, 1, 4, in);
  209.     rewind(in);
  210.  
  211.     ptMode = false;
  212.     channels = 0;
  213.     if (!strcmp(magic, "M.K.") || !strcmp(magic, "M!K!")) { ptMode = true; channels = 4; } // ProTracker (or compatible)
  214.     else if (magic[1] == 'C' && magic[2] == 'H' && magic[3] == 'N') channels = magic[0] - '0'; // FT2/others
  215.     else if (magic[2] == 'C' && magic[3] == 'H') channels = ((magic[0] - '0') * 10) + (magic[1] - '0'); // FT2/others
  216.  
  217.     if (channels < 1 || channels > 99) return false;
  218.     pattSize = channels * (64 * 4);
  219.     return true;
  220. }
  221.  
  222. bool kolibrimodLoad(FILE *in, int32_t audioOutputFreq)
  223. {
  224.     uint8_t *ptr8;
  225.     int32_t modFilesize;
  226.  
  227.     if (modData != NULL) return false;
  228.     if (!getNumbersOfChannels(in)) return false;
  229.  
  230.     fseek(in, 0, SEEK_END);
  231.     modFilesize = ftell(in);
  232.     modData = (uint8_t *)malloc(modFilesize);
  233.     rewind(in);
  234.     fread(modData, 1, modFilesize, in);
  235.     memcpy(songName, modData, 20); songName[20] = '\0';
  236.     if (modData[950] > 128) return false; // too many orders!
  237.  
  238.     // count number of patterns
  239.     for (uint8_t i = 0; i < 128; i++)
  240.         if (modData[952 + i] > pattNum) pattNum = modData[952 + i];
  241.     pattNum++;
  242.  
  243.     // set sample data pointers
  244.     ptr8 = &modData[1084 + (pattSize * pattNum)];
  245.     for (uint8_t i = 0; i < 31; i++)
  246.     {
  247.         sampleDataPointers[i] = (int8_t *)ptr8;
  248.         ptr8 += ((modData[42 + (30 * i)] << 8) | modData[(42 + (30 * i)) + 1]) * 2;
  249.     }
  250.  
  251.     ptr8 = &modData[1084]; // disable ptMode if some conditions are met
  252.     for (int32_t i = 0; ptMode && i < pattNum*channels*64; i++, ptr8 += 4)
  253.     {
  254.         const uint16_t period = (((ptr8[0] & 0x0F) << 8) | ptr8[1])*4;
  255.         if (period > 0 && (period < PT_MIN_PERIOD || period > PT_MAX_PERIOD)) // scan for extended periods
  256.         {
  257.             ptMode = false;
  258.             break;
  259.         }
  260.     }
  261.  
  262.     if (!ptMode) // set FT2 base clock and period range
  263.     {
  264.         dBaseClk = BASE_CLK;
  265.         minPeriod = MIN_PERIOD;
  266.         maxPeriod = MAX_PERIOD;
  267.     }
  268.  
  269.     memset(&wfx, 0, sizeof (wfx));
  270.     audioFreq = audioOutputFreq;
  271.     wfx.nSamplesPerSec = audioFreq;
  272.     wfx.wBitsPerSample = 16;
  273.     wfx.nChannels = 2;
  274.     wfx.wFormatTag = WAVE_FORMAT_PCM;
  275.     wfx.nBlockAlign = (wfx.wBitsPerSample * wfx.nChannels) / 8;
  276.     wfx.nAvgBytesPerSec = wfx.nBlockAlign * wfx.nSamplesPerSec;
  277.     mixerBuffer = (int8_t *)calloc(MIX_BUF_LEN, 1);
  278.  
  279.     waveOutOpen(&hWaveOut, WAVE_MAPPER, &wfx, (DWORD_PTR)waveOutProc, 0, CALLBACK_FUNCTION);
  280.     for (uint8_t i = 0; i < MIX_BUF_NUM; i++)
  281.     {
  282.         waveBlocks[i].dwBufferLength = MIX_BUF_LEN;
  283.         waveBlocks[i].lpData = (LPSTR)calloc(MIX_BUF_LEN, 1);
  284.         waveOutPrepareHeader(hWaveOut, &waveBlocks[i], sizeof (WAVEHDR));
  285.         waveOutWrite(hWaveOut, &waveBlocks[i], sizeof (WAVEHDR));
  286.     }
  287.  
  288.     dHz2DeltaMul = (double)FRAC_SCALE / (audioOutputFreq * OVERSAMPLE_FACTOR);
  289.     smpShift = (int8_t)log2(OVERSAMPLE_FACTOR * (1 << (6+1)));
  290.     return true;
  291. }
  292.  
  293. bool kolibrimodPlay(void)
  294. {
  295.     if (modData == NULL) return false; // no module loaded
  296.  
  297.     memset(channel, 0, sizeof (channel));
  298.     memset(voice, 0, sizeof (voice));
  299.  
  300.     for (int32_t i = 0; i < channels; i++) // set up initial LRRL channel pannings
  301.     {
  302.         voice[i].panR = !((i + 1) & 2) ? 103 : 153; // 25% stereo separation (LRRL..)
  303.         voice[i].panL = 256 - voice[i].panR;
  304.     }
  305.  
  306.     dSamplesPerTick = BPM2SAMPLES_PER_TICK(125);
  307.     dTickSampleCounter = 0.0; // zero tick sample counter so that it will instantly initiate a tick
  308.     modSpeed = 6;
  309.     modTick = modSpeed-1; // don't render a tick of silence
  310.     row = newRow = order = 0;
  311.     tickExtendFactor = 1; // 1 = no delay
  312.     newPosFlag = patLoop = false;
  313.     isMixing = true;
  314.     pattPtr = &modData[1084 + (modData[952+order] * pattSize)];
  315.     return true;
  316. }
  317.  
  318. void kolibrimodFree(void)
  319. {
  320.     isMixing = false;
  321.     for (int32_t i = 0; i < MIX_BUF_NUM; i++)
  322.         waveOutUnprepareHeader(hWaveOut, &waveBlocks[i], sizeof (WAVEHDR));
  323.  
  324.     for (int32_t i = 0; i < MIX_BUF_NUM; i++)
  325.     {
  326.         while (waveBlocks[i].dwFlags & WHDR_PREPARED) SleepEx(1, 1); // wait
  327.         if (waveBlocks[i].lpData != NULL) free(waveBlocks[i].lpData); waveBlocks[i].lpData = NULL;
  328.     }
  329.  
  330.     waveOutReset(hWaveOut);
  331.     waveOutClose(hWaveOut);
  332.  
  333.     if (modData != NULL) free(modData); modData = NULL;
  334.     if (mixerBuffer != NULL) free(mixerBuffer); mixerBuffer = NULL;
  335. }
  336.  
  337. static void triggerVoice(channel_t *c, voice_t *v)
  338. {
  339.     v->sampleData = c->sampleData;
  340.     v->loopStart = c->loopStart;
  341.     v->loopFlag = (c->loopStart + c->loopLen) > 2;
  342.     v->sampleEnd = v->loopFlag ? (c->loopStart + c->loopLen) : c->sampleLen;
  343.     v->swapData = NULL;
  344.     v->frac = 0;
  345.     v->pos = v->oldPos = c->sampleOffset; // 9xx sample offset * 256
  346.     c->period = c->toPeriod;
  347. }
  348.  
  349. static void portamento(channel_t *c)
  350. {
  351.     if (c->period == 0 || c->toPeriod == 0) return;
  352.  
  353.     if (c->period > c->toPeriod)
  354.     {
  355.         c->period -= c->portaMem*4;
  356.         if ((int16_t)c->period <= c->toPeriod) c->period = c->toPeriod;
  357.     }
  358.     else if (c->period < c->toPeriod)
  359.     {
  360.         c->period += c->portaMem*4;
  361.         if (c->period >= c->toPeriod) c->period = c->toPeriod;
  362.     }
  363.  
  364.     c->periodOut = c->period;
  365.     if (c->glissandoMode != 0) // semitones slide
  366.     {
  367.         const uint8_t note = periodToNote(c->periodOut, c->ftune);
  368.         if (note < MAX_NOTES) c->periodOut = ADJUST_PERIOD(periodTab[note], c->ftune);
  369.     }
  370. }
  371.  
  372. static void vibrato(channel_t *c)
  373. {
  374.     uint16_t newPeriod = c->period + ((c->vibratoDepth * sinusTab[c->vibratoPos]) >> (8-2));
  375.     if ((int16_t)newPeriod < 0) newPeriod = 0;
  376.     c->periodOut = newPeriod;
  377.     if (modTick > 0) c->vibratoPos = (c->vibratoPos + c->vibratoSpeed) & 63;
  378. }
  379.  
  380. static void tremolo(channel_t *c)
  381. {
  382.     c->volOut = c->vol + ((c->tremoloDepth * sinusTab[c->tremoloPos]) >> 8);
  383.     c->volOut = CLAMP(c->volOut, 0, 64);
  384.     if (modTick > 0) c->tremoloPos = (c->tremoloPos + c->tremoloSpeed) & 63;
  385. }
  386.  
  387. static void volumeSlide(channel_t *c)
  388. {
  389.     if (modTick == 0) return;
  390.     c->vol += (c->efx2 & 0xF0) ? (c->efx2 >> 4) : -(c->efx2 & 0xF);
  391.     c->vol = CLAMP(c->vol, 0, 64);
  392. }
  393.  
  394. static void invertLoop(channel_t *c) // ProTracker only
  395. {
  396.     if (!ptMode || (c->invLoopPos += invLoopTab[c->invLoopSpeed]) < 128) return;
  397.     c->invLoopPos = 0;
  398.     if (c->invLoopPtr == NULL) return;
  399.     if (++c->invLoopPtr >= c->invLoopStartPtr+c->invLoopLen) c->invLoopPtr = c->invLoopStartPtr;
  400.     *c->invLoopPtr = -1 - *c->invLoopPtr;
  401. }
  402.  
  403. static void checkEfx(void)
  404. {
  405.     int16_t period;
  406.     channel_t *c = channel;
  407.     voice_t *v = voice;
  408.     for (int32_t i = 0; i < channels; i++, c++, v++) // do effects
  409.     {
  410.         if (modTick > 0) invertLoop(c);
  411.  
  412.         if (c->efx != 0 || c->efx2 != 0)
  413.         {
  414.             if (c->efx == 0x4) { if (c->efx2 & 0xF) c->vibratoDepth = (c->efx2 & 0xF)*2; if (c->efx2 & 0xF0) c->vibratoSpeed = c->efx2>>4; vibrato(c); }
  415.             if (c->efx == 0x7) { if (c->efx2 & 0xF) c->tremoloDepth = (c->efx2 & 0xF)*4; if (c->efx2 & 0xF0) c->tremoloSpeed = c->efx2>>4; tremolo(c); }
  416.             if (c->efx == 0x6) { vibrato(c); volumeSlide(c); }
  417.  
  418.             if (modTick == 0)
  419.             {   // tick=0 effects
  420.                      if (c->efx == 0x8) { if (!ptMode) { v->panR = c->efx2; v->panL = 256-c->efx2; } }
  421.                 else if (c->efx == 0xB) { newPosFlag = true; newRow = 0; order = c->efx2 - 1; }
  422.                 else if (c->efx == 0xC) { c->vol = (c->efx2 > 64) ? 64 : c->efx2; }
  423.                 else if (c->efx == 0xD) { newPosFlag = true; newRow = ((c->efx2 >> 4) * 10) + (c->efx2 & 0xF); if (newRow > 63) newRow = 0; }
  424.                 else if (c->efx == 0xE)
  425.                 {
  426.                          if ((c->efx2&0xF0)==0x10) { if (c->period > 0) { c->period -= (c->efx2 & 0xF)*4; if ((int16_t)c->period < minPeriod) c->period = minPeriod; } }
  427.                     else if ((c->efx2&0xF0)==0x20) { if (c->period > 0) { c->period += (c->efx2 & 0xF)*4; if (c->period > maxPeriod) c->period = maxPeriod; } }
  428.                     else if ((c->efx2&0xF0)==0x30) { c->glissandoMode = c->efx2 & 0xF; }
  429.                     else if ((c->efx2&0xF0)==0x50) { c->ftune = ptMode ? (c->efx2 & 0xF) : (c->efx2 - 8) & 0xF; }
  430.                     else if ((c->efx2&0xF0)==0x60) { if (c->efx2==0x60) c->E6Row = row; else { if (!c->E6Cnt) c->E6Cnt = c->efx2&0xF;
  431.                                                                            else if (!--c->E6Cnt) return; newRow = c->E6Row; patLoop = true; }}
  432.                     else if ((c->efx2&0xF0)==0xA0) { c->vol += c->efx2 & 0xF; if (c->vol > 64) c->vol = 64; }
  433.                     else if ((c->efx2&0xF0)==0xB0) { c->vol -= c->efx2 & 0xF; if (c->vol < 0) c->vol = 0; }
  434.                     else if ((c->efx2&0xF0)==0xE0) { tickExtendFactor = (c->efx2 & 0xF) + 1; }
  435.                     else if ((c->efx2&0xF0)==0xF0) { c->invLoopSpeed = c->efx2 & 0xF; invertLoop(c); }
  436.                 }
  437.                 else if (c->efx == 0xF) if (c->efx2 < 0x20) { if (c->efx2) modSpeed = c->efx2; } else { dSamplesPerTick = BPM2SAMPLES_PER_TICK(c->efx2); }
  438.             }
  439.             else
  440.             {   // tick>0 effects
  441.                      if (c->efx == 0x1) { if (c->period > 0) { c->period -= c->efx2*4; if ((int16_t)c->period < minPeriod) c->period = minPeriod; } }
  442.                 else if (c->efx == 0x2) { if (c->period > 0) { c->period += c->efx2*4; if (c->period > maxPeriod) c->period = maxPeriod; } }
  443.                 else if (c->efx == 0x3) { if (c->efx2) c->portaMem = c->efx2; portamento(c); }
  444.                 else if (c->efx == 0x5) { portamento(c); volumeSlide(c); }
  445.                 else if (c->efx == 0xE) { if ((c->efx2 & 0xF0) == 0x90) { if (c->efx2 == 0x90) return; if (!(modTick % (c->efx2 & 0xF))) v->pos = v->oldPos; }}
  446.                 else if (c->efx == 0xA) { volumeSlide(c); }
  447.             }
  448.         }
  449.        
  450.              if ((c->efx == 0xE) && (c->efx2 & 0xF0) == 0xC0) { if (modTick == (c->efx2 & 0xF)) c->vol = 0; }
  451.         else if ((c->efx == 0xE) && (c->efx2 & 0xF0) == 0xD0) { if (c->rawPeriod > 0 && modTick == (c->efx2 & 0xF)) triggerVoice(c, v); }
  452.  
  453.         period = c->period;
  454.         if (c->efx == 0 && c->efx2 != 0 && period > 0) // do arpeggio here
  455.         {
  456.             uint8_t note = periodToNote(period, c->ftune);
  457.             if (note < MAX_NOTES)
  458.             {
  459.                 const uint8_t arpTick = modTick % 3;
  460.                      if (arpTick == 1) note += c->efx2 >> 4;
  461.                 else if (arpTick == 2) note += c->efx2 & 0xF;
  462.                 if (note > MAX_NOTES-1) note = MAX_NOTES-1;
  463.                 period = ADJUST_PERIOD(periodTab[note], c->ftune);
  464.             }
  465.         }
  466.  
  467.         // vibrato and portamento modifies the output period directly
  468.         if (c->efx != 4 && c->efx != 6 && c->efx != 3 && c->efx != 5) c->periodOut = period;
  469.         if (c->periodOut < ABSOLUTE_MIN_PERIOD) c->periodOut = ABSOLUTE_MIN_PERIOD; // needed for mixer safety
  470.         if (c->periodOut > 0) v->delta = PERIOD2DELTA(c->periodOut); // set voice rate
  471.  
  472.         // tremolo modifies the output volume directly
  473.         if (c->efx != 7) c->volOut = c->vol;
  474.  
  475.         v->volL = c->volOut * v->panL; // (0..64)*(0..256) = 0..16384
  476.         v->volR = c->volOut * v->panR;
  477.     }
  478. }
  479.  
  480. static void tickReplayer(void)
  481. {
  482.     if (++modTick >= modSpeed*tickExtendFactor)
  483.     {
  484.         modTick = 0;
  485.         tickExtendFactor = 1; // reset EEx (pattern delay). 1 = no delay
  486.  
  487.         channel_t *c = channel;
  488.         voice_t *v = voice;
  489.         for (uint8_t i = 0; i < channels; i++, c++, v++) // read pattern data
  490.         {
  491.             const uint8_t *readPtr = &pattPtr[(row*channels*4) + (i*4)];
  492.             int16_t period = c->rawPeriod = (((readPtr[0] & 0xF) << 8) | readPtr[1])*4;
  493.             c->efx = readPtr[2] & 0xF;
  494.             c->efx2 = readPtr[3];
  495.  
  496.             const bool noteDelay = (c->efx == 0xE) && ((c->efx2 & 0xF0) == 0xD0);
  497.             const bool porta = (c->efx == 0x3 || c->efx == 0x5);
  498.  
  499.             const uint8_t smp = (readPtr[0] & 0xF0) | (readPtr[2] >> 4);
  500.             if (smp >= 1 && smp <= 31) // sample found in pattern data
  501.             {
  502.                 const uint8_t *ptr8 = &modData[42 + (30*(smp-1))];
  503.                 c->ftune = ptr8[2] & 0xF;
  504.                 c->volOut = c->vol = (ptr8[3] > 64) ? 64 : ptr8[3];
  505.                 c->sampleLen = ((ptr8[0] << 8) | ptr8[1]) * 2;
  506.                 c->loopStart = ((ptr8[4] << 8) | ptr8[5]) * 2;
  507.                 c->loopLen = ((ptr8[6] << 8) | ptr8[7]) * 2;
  508.                 c->sampleData = sampleDataPointers[smp-1];
  509.                 c->sampleOffset = 0;
  510.  
  511.                 if (ptMode && v->sampleData && (!period || porta))
  512.                 {   // do ProTracker sample swap (if voice is active and no pattern note)
  513.                     v->swapData = c->sampleData;
  514.                     v->swapLoopStart = c->loopStart;
  515.                     v->swapLoopFlag = (c->loopStart + c->loopLen) > 2;
  516.                     v->swapSampleEnd = v->swapLoopFlag ? (c->loopStart + c->loopLen) : c->sampleLen;
  517.                 }
  518.  
  519.                 c->invLoopLen = c->loopLen;
  520.                 c->invLoopPtr = c->invLoopStartPtr = c->sampleData + c->loopStart;
  521.             }
  522.  
  523.             if (c->efx == 0x9) // 9xx "set sample offset" efx must be handled here
  524.             {
  525.                 if (c->efx2 > 0) c->sampleOffsetMem = c->efx2 << 8;
  526.                 c->sampleOffset = c->sampleOffsetMem;
  527.             }
  528.  
  529.             if (period > 0) // note found in pattern data
  530.             {
  531.                 if (c->efx == 0xE && (c->efx2 & 0xF0) == 0x50) // finetune efx must be handled here as well
  532.                     c->ftune = ptMode ? (c->efx2 & 0xF) : (c->efx2 - 8) & 0xF;
  533.  
  534.                 const uint8_t note = periodToNote(period, 0);
  535.                 if (note < MAX_NOTES) // note was found in period table
  536.                 {
  537.                     c->note = note;
  538.                     c->toPeriod = ADJUST_PERIOD(periodTab[note], c->ftune);
  539.                     // trigger sample if no portamento (3xx and 5xy) and no note delay
  540.                     if (c->efx != 0x03 && c->efx != 0x05 && !noteDelay)
  541.                     {
  542.                         c->vibratoPos = c->tremoloPos = 0; // reset vibrato/tremolo position
  543.                         triggerVoice(c, v);
  544.                         c->periodOut = c->period; // set initial period
  545.                     }
  546.                 }
  547.             }
  548.         }
  549.  
  550.         checkEfx();
  551.  
  552.         if (patLoop) // handle pattern loop (E6x)
  553.         {
  554.             row = newRow;
  555.             newRow = 0;
  556.             newPosFlag = patLoop = false;
  557.         }
  558.         else if (++row >= 64) newPosFlag = true; // increase row like normal
  559.     }
  560.     else checkEfx();
  561.  
  562.     if (newPosFlag) // handle position jump (Bxx), pattern break (Dxx) or end of pattern
  563.     {
  564.         row = newRow;
  565.         newRow = 0;
  566.         newPosFlag = false;
  567.         if (++order >= modData[950]) order = (modData[951] < modData[950]) ? modData[951] : 0; // loop (wrap) song
  568.         pattPtr = &modData[1084 + (modData[952+order] * pattSize)];
  569.     }
  570. }
  571.  
  572. int main(int argc, char *argv[]) // please edit this for your own use!
  573. {
  574.     FILE *f;
  575.  
  576. #ifdef _DEBUG
  577.     f = fopen("debug.mod", "rb");
  578. #else
  579.     if (argc != 2)
  580.     {
  581.         printf("Usage: kolibrimod.exe <module>\n");
  582.         return -1;
  583.     }
  584.  
  585.     f = fopen(argv[1], "rb");
  586. #endif
  587.     if (f == NULL)
  588.     {
  589.         printf("ERROR: Can't open file!\n");
  590.         return 1;
  591.     }
  592.  
  593.     if (!kolibrimodLoad(f, AUDIO_RATE))
  594.     {
  595.         printf("ERROR: This .MOD is not supported!\n");
  596.         return 1;
  597.     }
  598.  
  599.     fclose(f);
  600.     kolibrimodPlay();
  601.  
  602.     printf("Playing \"%s\" (%dHz - %d channels - %dx oversampling)\nPress any key to stop...\n",
  603.         songName, audioFreq, channels, OVERSAMPLE_FACTOR);
  604.     while (!_getch()) Sleep(250);
  605.     kolibrimodFree();
  606.  
  607.     return 0;
  608. }
RAW Paste Data