SHARE
TWEET

kolibrimod (tiny .mod replayer)

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