daily pastebin goal
69%
SHARE
TWEET

kolibrimod (tiny .mod replayer)

8bitbubsy Sep 11th, 2016 (edited) 433 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // kolibrimod - <500 lines ProTracker .MOD replayer by 8bitbubsy - updated 19th of March 2018
  2. // Missing effects: E3x (glissando type), E4x (vibrato type), E7x (tremolo type), E8x (Karplus-Strong)
  3. // Do not use this replayer with an audio rate lower than 32kHz! Weird things will happen.
  4. // Note: This is not optimized at all, the only focus is amount of code lines + okay accuracy
  5.  
  6. #include <stdio.h>
  7. #include <stdlib.h>
  8. #include <string.h>
  9. #include <stdint.h>
  10. #include <conio.h>   // _getch()
  11. #include <math.h>    // powf(), sinf()
  12. #include <windows.h> // Sleep(), mixer stuff
  13.  
  14. #define AUDIO_RATE 48000
  15. #define STEREO_SEP 17 /* 0 to 100% */
  16. #define MIX_BUF_NUM 4
  17. #define MIX_BUF_LEN 4096
  18. #define MAX_SAMPLES_TO_MIX (int32_t)(((AUDIO_RATE * 2.5f) / 32.0f) + 0.5f))
  19. #define LERP(x, y, z) ((x) + ((y) - (x)) * (z))
  20. #define PERIOD2RATE(x) ((x <= 0) ? 0.0f : ((3546895.0f / floorf(((x) * v->ftune) + 0.5f)) / AUDIO_RATE))
  21. #define BPM2SMPNUM(x) (int16_t)(((((AUDIO_RATE * 125.0f) / 50.0f) / (x))) + 0.5f)
  22. #define CLAMP(x, low, high) (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x)))
  23.  
  24. typedef struct
  25. {
  26.     int8_t *dat, *swapDat;
  27.     int32_t len, rep, replen, phase, oldPhase, swapLen, swapRep, swapReplen;
  28.     float vol, pan, ftune, delta, frac;
  29. } ptAud_t;
  30.  
  31. typedef struct
  32. {
  33.     int8_t vol, ftune, *invDat1, *dat, *invDat2, jmpRow, jmpCnt;
  34.     uint8_t note, smp, efx, efxDat, ofsMem, ofs, portaMem, vibDepth, vibSpeed, tremDepth, tremSpeed, vibPos, tremPos, invSpeed, invPos;
  35.     int16_t rawPeriod, period, toPeriod;
  36.     uint32_t invLen, len, rep, replen;
  37. } ptChn_t;
  38.  
  39. static volatile int8_t isMixing;
  40. static int8_t modSpeed, pattNum, modOrder, newPosFlag, modDelay, newModRow, loopFlag, modRow, *mixerBuffer, *samplePtrs[31];
  41. static uint8_t *modBuffer, invLoopTable[16] = { 0, 5, 6, 7, 8, 10, 11, 13, 16, 19, 22, 26, 32, 43, 64, 128 };
  42. static int16_t modTick, samplesLeft, samplesPerTick;
  43. static const int16_t periodTable[36] = {856,808,762,720,678,640,604,570,538,508,480,453,428,404,381,360,339,320,302,285,269,254,240,226,214,202,190,180,170,160,151,143,135,127,120,113};
  44. static int32_t modSize;
  45. static float *mixBufferL, *mixBufferR;
  46. static ptAud_t ptAud[4];
  47. static ptChn_t ptChn[4];
  48. static WAVEHDR waveBlocks[MIX_BUF_NUM];
  49. static HWAVEOUT hWaveOut;
  50. static WAVEFORMATEX wfx;
  51.  
  52. static void tickReplayer(void);
  53.  
  54. static void handleSampleEnd(ptAud_t *v, int32_t *phase2) // hopefully this gets inlined
  55. {
  56.     if (v->swapDat == NULL) { if ((v->rep + v->replen) > 2) v->phase = v->rep; else v->dat = NULL; return; } // no sample swap
  57.     v->dat     = v->swapDat;
  58.     v->len     = v->swapLen;
  59.     v->rep     = v->swapRep;
  60.     v->replen  = v->swapReplen;
  61.     v->swapDat = NULL;
  62.     v->phase   = v->rep;
  63.     *phase2    = v->rep + 1;
  64.     if ((v->swapRep + v->swapReplen) <= 2) v->dat = NULL; // illegal swap
  65. }
  66.  
  67. static void mixChannels(int16_t *stream, int16_t numSamples)
  68. {
  69.     int32_t i, s, phase2, loopEnd;
  70.     float s1_f, s2_f;
  71.     ptAud_t *v;
  72.  
  73.     memset(mixBufferL, 0, sizeof (float) * numSamples);
  74.     memset(mixBufferR, 0, sizeof (float) * numSamples);
  75.  
  76.     for (i = 0; i < 4; ++i)
  77.     {
  78.         v = &ptAud[i];
  79.         if ((v->dat == NULL) || (v->delta <= 0.0f)) continue;
  80.  
  81.         for (s = 0; s < numSamples; ++s)
  82.         {
  83.             loopEnd = v->rep + v->replen;
  84.             phase2  = v->phase + 1;
  85.  
  86.             if (loopEnd > 2)
  87.             {
  88.                 if (phase2   >= loopEnd) phase2 = v->rep;
  89.                 if (v->phase >= loopEnd) handleSampleEnd(v, &phase2);
  90.             }
  91.             else
  92.             {
  93.                 if (phase2   >= v->len) phase2 = 0;
  94.                 if (v->phase >= v->len) handleSampleEnd(v, &phase2);
  95.             }
  96.  
  97.             if ((v->dat == NULL) || (v->phase >= v->len) || (phase2 >= v->len)) break; // don't resample anymore
  98.             s1_f = v->dat[v->phase]; s2_f = v->dat[phase2];
  99.             s1_f = LERP(s1_f, s2_f, v->frac) * v->vol;
  100.  
  101.             mixBufferL[s] += (s1_f * (127.0f - v->pan));
  102.             mixBufferR[s] += (s1_f * v->pan);
  103.  
  104.             v->frac += v->delta;
  105.             if (v->frac >= 1.0f) { v->frac -= 1.0f; v->phase++; }
  106.         }
  107.     }
  108.  
  109.     for (i = 0; i < numSamples; ++i)
  110.     {
  111.         *stream++ = (int16_t)(CLAMP(mixBufferL[i] / 48.0f, -32768.0f, 32767.0f));
  112.         *stream++ = (int16_t)(CLAMP(mixBufferR[i] / 48.0f, -32768.0f, 32767.0f));
  113.     }
  114. }
  115.  
  116. static void CALLBACK waveOutProc(HWAVEOUT _hWaveOut, UINT uMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2)
  117. {
  118.     int16_t *outputStream, sampleBlock, samplesTodo;
  119.     WAVEHDR *waveBlockHeader;
  120.  
  121.     if (uMsg != MM_WOM_DONE) return;
  122.     waveBlockHeader = (WAVEHDR *)(dwParam1);
  123.     waveOutUnprepareHeader(_hWaveOut, waveBlockHeader, sizeof (WAVEHDR));
  124.  
  125.     if (!isMixing) return;
  126.     memcpy(waveBlockHeader->lpData, mixerBuffer, MIX_BUF_LEN);
  127.     waveOutPrepareHeader(_hWaveOut, waveBlockHeader, sizeof (WAVEHDR));
  128.     waveOutWrite(_hWaveOut, waveBlockHeader, sizeof (WAVEHDR));
  129.  
  130.     outputStream = (int16_t *)(mixerBuffer);
  131.     sampleBlock = MIX_BUF_LEN / 4; // /2 for stereo + /2 for 16-bit
  132.     while (sampleBlock)
  133.     {
  134.         samplesTodo = (sampleBlock < samplesLeft) ? sampleBlock : samplesLeft;
  135.         if (samplesTodo > 0)
  136.         {
  137.             mixChannels(outputStream, samplesTodo);
  138.             outputStream += (samplesTodo * 2);
  139.             sampleBlock  -=  samplesTodo;
  140.             samplesLeft  -=  samplesTodo;
  141.         }
  142.         else
  143.         {
  144.             tickReplayer();
  145.             samplesLeft = samplesPerTick;
  146.         }
  147.     }
  148. }
  149.  
  150. void kolibrimodLoad(FILE *in)
  151. {
  152.     uint8_t *ptr8, i;
  153.  
  154.     // init module
  155.     fseek(in, 0, SEEK_END);
  156.     modSize = ftell(in);
  157.     modBuffer = (uint8_t *)(malloc(modSize));
  158.     rewind(in);
  159.     fread(modBuffer, 1, modSize, in);
  160.  
  161.     for (i = 0; i < 128; ++i) // count number of patterns
  162.         if (modBuffer[952 + i] > pattNum) pattNum = modBuffer[952 + i];
  163.  
  164.     ptr8 = &modBuffer[1084 + (1024 * (pattNum + 1))];
  165.     for (i = 0; i < 31; ++i) // set sample data pointers
  166.     {
  167.         samplePtrs[i] = (int8_t *)(ptr8);
  168.         ptr8 += ((modBuffer[42 + (30 * i)] << 8) | modBuffer[(42 + (30 * i)) + 1]) * 2;
  169.     }
  170.  
  171.     // init mixer
  172.     mixerBuffer = (int8_t  *)(calloc(MIX_BUF_LEN, 1));
  173.     mixBufferL  = (float *)(malloc(sizeof (float) * MAX_SAMPLES_TO_MIX);
  174.     mixBufferR  = (float *)(malloc(sizeof (float) * MAX_SAMPLES_TO_MIX);
  175.  
  176.     memset(&wfx, 0, sizeof (wfx));
  177.     wfx.nSamplesPerSec = AUDIO_RATE;
  178.     wfx.wBitsPerSample = 16;
  179.     wfx.nChannels = 2;
  180.     wfx.wFormatTag = WAVE_FORMAT_PCM;
  181.     wfx.nBlockAlign = (wfx.wBitsPerSample * wfx.nChannels) / 8;
  182.     wfx.nAvgBytesPerSec = wfx.nBlockAlign * wfx.nSamplesPerSec;
  183.  
  184.     waveOutOpen(&hWaveOut, WAVE_MAPPER, &wfx, (DWORD_PTR)(waveOutProc), 0, CALLBACK_FUNCTION);
  185.     for (i = 0; i < MIX_BUF_NUM; ++i)
  186.     {
  187.         waveBlocks[i].dwBufferLength = MIX_BUF_LEN;
  188.         waveBlocks[i].lpData = (LPSTR)(calloc(MIX_BUF_LEN, 1));
  189.         waveOutPrepareHeader(hWaveOut, &waveBlocks[i], sizeof (WAVEHDR));
  190.         waveOutWrite(hWaveOut, &waveBlocks[i], sizeof (WAVEHDR));
  191.     }
  192. }
  193.  
  194. void kolibrimodPlay(void)
  195. {
  196.     uint8_t i;
  197.  
  198.     for (i = 0; i < 4; ++i)
  199.     {
  200.         memset(&ptChn[i], 0, sizeof (ptChn_t));
  201.         memset(&ptAud[i], 0, sizeof (ptAud_t));
  202.         ptAud[i].pan = ((i == 1) || (i == 2)) ? (63 + ((STEREO_SEP * 64) / 100.0f)) : (63 - ((STEREO_SEP * 64) / 100.0f));
  203.     }
  204.  
  205.     samplesPerTick = BPM2SMPNUM(125);
  206.     modSpeed = 6;
  207.     loopFlag = modRow = newModRow = newPosFlag = modTick = 0;
  208.     isMixing = modDelay = 1;
  209. }
  210.  
  211. void kolibrimodFree(void)
  212. {
  213.     uint8_t i;
  214.  
  215.     isMixing = 0;
  216.     for (i = 0; i < MIX_BUF_NUM; ++i)
  217.         waveOutUnprepareHeader(hWaveOut, &waveBlocks[i], sizeof (WAVEHDR));
  218.  
  219.     for (i = 0; i < MIX_BUF_NUM; ++i)
  220.     {
  221.         while (waveBlocks[i].dwFlags & WHDR_PREPARED) SleepEx(1, 1); // wait
  222.         if (waveBlocks[i].lpData != NULL) free(waveBlocks[i].lpData);
  223.     }
  224.  
  225.     waveOutReset(hWaveOut);
  226.     waveOutClose(hWaveOut);
  227.  
  228.     free(modBuffer);  free(mixerBuffer);
  229.     free(mixBufferL); free(mixBufferR);
  230. }
  231.  
  232. static void triggerVoice(ptChn_t *c, ptAud_t *v)
  233. {
  234.     v->len = c->len;
  235.     v->rep = c->rep;
  236.     v->replen = c->replen;
  237.     v->dat = c->dat;
  238.     v->ftune = powf(2.0f, c->ftune / -(12.0f * 8.0f));
  239.     v->oldPhase = v->phase = 256 * c->ofs;
  240.     c->period = c->toPeriod;
  241. }
  242.  
  243. static void porta(ptChn_t *c)
  244. {
  245.     if ((c->period <= 0) || (c->toPeriod <= 0)) return;
  246.  
  247.     if (c->period > c->toPeriod)
  248.     {
  249.         c->period -= c->portaMem;
  250.         if (c->period <= c->toPeriod) c->period = c->toPeriod;
  251.     }
  252.     else if (c->period < c->toPeriod)
  253.     {
  254.         c->period += c->portaMem;
  255.         if (c->period >= c->toPeriod) c->period = c->toPeriod;
  256.     }
  257. }
  258.  
  259. static void vibrato(ptChn_t *c, ptAud_t *v)
  260. {
  261.     if (c->period > 0)
  262.         v->delta = PERIOD2RATE(CLAMP(c->period + (int8_t)(c->vibDepth * sinf(c->vibPos * (2.0f * 3.1415926f / 64.0f))), 113, 856));
  263.     c->vibPos = (c->vibPos + c->vibSpeed) & 63;
  264. }
  265.  
  266. static void tremolo(ptChn_t *c, ptAud_t *v)
  267. {
  268.     v->vol = (float)(c->vol + (int8_t)(c->tremDepth * sinf(c->tremPos * (2.0f * 3.1415926f / 64.0f))));
  269.     v->vol = CLAMP(v->vol, 0, 64);
  270.     c->tremPos = (c->tremPos + c->tremSpeed) & 63;
  271. };
  272.  
  273. static void volslide(ptChn_t *c)
  274. {
  275.     c->vol += (c->efxDat & 0xF0) ? (c->efxDat >> 4) : -(c->efxDat & 0x0F);
  276.     c->vol = CLAMP(c->vol, 0, 64);
  277. }
  278.  
  279. static void invloop(ptChn_t *c)
  280. {
  281.     if ((c->invPos += invLoopTable[c->invSpeed]) < 128) return;
  282.  
  283.     c->invPos = 0;
  284.     if (c->invDat1 == NULL) return;
  285.  
  286.     if (++c->invDat1 >= (c->invDat2 + c->invLen))
  287.         c->invDat1  =  c->invDat2;
  288.     *c->invDat1 = -1 - *c->invDat1;
  289. }
  290.  
  291. static void checkEfx(void)
  292. {
  293.     int16_t i, period;
  294.     ptChn_t *c;
  295.     ptAud_t *v;
  296.  
  297.     for (i = 0; i < 4; ++i) // do effects
  298.     {
  299.         c = &ptChn[i];
  300.         v = &ptAud[i];
  301.  
  302.         if (modTick > 0) invloop(c);
  303.  
  304.         if (!((c->efx == 0) && (c->efxDat == 0)))
  305.         {
  306.             if (modTick == 0)
  307.             { // tick=0 effects
  308.                     if ((c->efx == 0x4) || (c->efx == 0x6)) { if (c->period > 0) v->delta = PERIOD2RATE(c->period); } // idle tick
  309.                 else if (c->efx == 0x7) v->vol = c->vol; // idle tick
  310.                 else if (c->efx == 0xB) { newPosFlag = 1; newModRow = 0; modOrder = c->efxDat - 1; }
  311.                 else if (c->efx == 0xC) c->vol = (c->efxDat > 64) ? 64 : c->efxDat;
  312.                 else if (c->efx == 0xD) { newPosFlag = 1; newModRow = ((c->efxDat >> 4) * 10) + (c->efxDat & 0x0F); if (newModRow > 63) newModRow = 0; }
  313.                 else if (c->efx == 0xE)
  314.                 {
  315.                          if ((c->efxDat & 0xF0) == 0x10) { if (c->period > 0) { c->period -= c->efxDat & 0x0F; if (c->period < 113) c->period = 113; } }
  316.                     else if ((c->efxDat & 0xF0) == 0x20) { if (c->period > 0) { c->period += c->efxDat & 0x0F; if (c->period > 856) c->period = 856; } }
  317.                     else if ((c->efxDat & 0xF0) == 0x50) c->ftune = ((c->efxDat & 0x0F) >= 8) ? ((c->efxDat & 0x0F) - 16) : (c->efxDat & 0x0F);
  318.                     else if ((c->efxDat & 0xF0) == 0x60) { if (c->efxDat == 0x60) c->jmpRow = modRow; else { if (!c->jmpCnt) c->jmpCnt = c->efxDat & 0x0F; else if (!--c->jmpCnt) return; newModRow = c->jmpRow; loopFlag = 1; }}
  319.                     else if ((c->efxDat & 0xF0) == 0xA0) { c->vol += c->efxDat & 0x0F; if (c->vol > 64) c->vol = 64; }
  320.                     else if ((c->efxDat & 0xF0) == 0xB0) { c->vol -= c->efxDat & 0x0F; if (c->vol < 0) c->vol = 0; }
  321.                     else if ((c->efxDat & 0xF0) == 0xE0) modDelay = (c->efxDat & 0x0F) + 1;
  322.                     else if ((c->efxDat & 0xF0) == 0xF0) { c->invSpeed = c->efxDat & 0x0F; invloop(c); }
  323.                 }
  324.                 else if (c->efx == 0xF) if (c->efxDat < 0x20) { if (c->efxDat) modSpeed = c->efxDat; } else { samplesPerTick = BPM2SMPNUM(c->efxDat); }
  325.             }
  326.             else
  327.             { // tick>0 effects
  328.                      if (c->efx == 0x1) { if (c->period > 0) { c->period -= c->efxDat; if (c->period < 113) c->period = 113; } }
  329.                 else if (c->efx == 0x2) { if (c->period > 0) { c->period += c->efxDat; if (c->period > 856) c->period = 856; } }
  330.                 else if (c->efx == 0x3) { if (c->efxDat) c->portaMem = c->efxDat; porta(c); }
  331.                 else if (c->efx == 0x4) { if (c->efxDat & 0x0F) c->vibDepth = (c->efxDat & 0x0F) * 2; if (c->efxDat & 0xF0) c->vibSpeed = c->efxDat >> 4; vibrato(c, v); }
  332.                 else if (c->efx == 0x5) { porta(c); volslide(c); }
  333.                 else if (c->efx == 0x6) { vibrato(c, v); volslide(c); }
  334.                 else if (c->efx == 0x7) { if (c->efxDat & 0x0F) c->tremDepth = (c->efxDat & 0x0F) * 4; if (c->efxDat & 0xF0) c->tremSpeed = c->efxDat >> 4; tremolo(c, v); }
  335.                 else if (c->efx == 0xE) { if ((c->efxDat & 0xF0) == 0x90) { if (c->efxDat == 0x90) return; if (!(modTick % (c->efxDat & 0x0F))) v->phase = v->oldPhase; }}
  336.                 else if (c->efx == 0xA) volslide(c);
  337.             }
  338.         }
  339.  
  340.              if ((c->efx == 0xE) && (c->efxDat & 0xF0) == 0xC0) { if (modTick == (c->efxDat & 0x0F)) c->vol = 0; }
  341.         else if ((c->efx == 0xE) && (c->efxDat & 0xF0) == 0xD0) { if ((c->rawPeriod >= 113) && (modTick == (c->efxDat & 0x0F))) triggerVoice(c, v); }
  342.  
  343.         period = c->period;
  344.         if ((period > 0) && (c->efx == 0) && (c->efxDat != 0)) // do arpeggio here
  345.         {
  346.                  if ((modTick % 3) == 0) period = periodTable[c->note];
  347.             else if ((modTick % 3) == 1) period = periodTable[(c->note + (c->efxDat >>   4)) % 36];
  348.             else if ((modTick % 3) == 2) period = periodTable[(c->note + (c->efxDat & 0x0F)) % 36];
  349.         }
  350.  
  351.         if ((c->efx != 4) && (c->efx != 6) && (period > 0))
  352.             v->delta = PERIOD2RATE(period); // set voice pitch
  353.  
  354.         if (c->efx != 7)
  355.             v->vol = c->vol; // set voice volume
  356.     }
  357. }
  358.  
  359. void tickReplayer(void)
  360. {
  361.     uint8_t *pattPtr, *ptr8, i, j, smp;
  362.     int16_t period;
  363.     ptChn_t *c;
  364.     ptAud_t *v;
  365.  
  366.     if (++modTick >= (modSpeed * modDelay))
  367.     {
  368.         modTick  = 0;
  369.         modDelay = 1;
  370.  
  371.         for (i = 0; i < 4; ++i) // read pattern data
  372.         {
  373.             c = &ptChn[i];
  374.             v = &ptAud[i];
  375.  
  376.             pattPtr = &modBuffer[1084 + (modBuffer[952 + modOrder] * 1024) + (modRow * 16) + (i * 4)];
  377.  
  378.             c->rawPeriod = period = (((pattPtr[0] & 0x0F) << 8) | pattPtr[1]);
  379.             c->efx = pattPtr[2] & 0x0F;
  380.             c->efxDat = pattPtr[3];
  381.  
  382.             smp = (pattPtr[0] & 0xF0) | (pattPtr[2] >> 4);
  383.             if ((smp >= 1) && (smp <= 31)) // new sample
  384.             {
  385.                 c->smp = smp - 1;
  386.                 ptr8 = &modBuffer[42 + (30 * c->smp)];
  387.                 c->ftune = ((ptr8[2] & 0x0F) >= 8) ? ((ptr8[2] & 0x0F) - 16) : (ptr8[2] & 0x0F);
  388.                 c->vol = (ptr8[3] > 64) ? 64 : ptr8[3];
  389.                 c->len = ((ptr8[0] << 8) | ptr8[1]) * 2;
  390.                 c->rep = ((ptr8[4] << 8) | ptr8[5]) * 2;
  391.                 c->replen = ((ptr8[6] << 8) | ptr8[7]) * 2;
  392.                 c->dat = samplePtrs[c->smp];
  393.  
  394.                 if (!((c->efx == 0xE) && ((c->efxDat & 0xF0) == 0xD0)))
  395.                 {
  396.                     if (v->dat) // do sample swap
  397.                     {
  398.                         v->swapDat = c->dat;
  399.                         v->swapLen = c->len;
  400.                         v->swapRep = c->rep;
  401.                         v->swapReplen = c->replen;
  402.                     }
  403.                     else
  404.                     {   // set sample like normal
  405.                         v->dat = c->dat;
  406.                         v->len = c->len;
  407.                         v->rep = c->rep;
  408.                         v->replen = c->replen;
  409.                         v->swapDat = NULL;
  410.                     }
  411.                 }
  412.  
  413.                 c->invLen = c->replen;
  414.                 c->invDat2 = c->invDat1 = (c->dat + c->rep);
  415.                 c->ofs = 0;
  416.             }
  417.  
  418.             if (c->efx == 0x9) // 9xx sample offset
  419.             {
  420.                 if (c->efxDat)
  421.                     c->ofsMem = c->efxDat;
  422.                 c->ofs = c->ofsMem;
  423.             }
  424.  
  425.             if (period > 0) // new period (note)
  426.             {
  427.                 if ((c->efx == 0xE) && ((c->efxDat & 0xF0) == 0x50))
  428.                     c->ftune = ((c->efxDat & 0x0F) >= 8) ? ((c->efxDat & 0x0F) - 16) : (c->efxDat & 0x0F);
  429.  
  430.                 for (j = 0; j < 36; ++j)
  431.                     if (period >= periodTable[j]) break;
  432.  
  433.                 if (j <= 35)
  434.                 {
  435.                     c->note = j;
  436.                     c->toPeriod = periodTable[j];
  437.  
  438.                     if (((c->efx != 0x03) && (c->efx != 0x05)) && !((c->efx == 0xE) && ((c->efxDat & 0xF0) == 0xD0)))
  439.                     {
  440.                         c->vibPos = c->tremPos = 0;
  441.                         triggerVoice(c, v);
  442.                         v->delta = PERIOD2RATE(c->period); // set voice pitch
  443.                     }
  444.                 }
  445.             }
  446.         }
  447.  
  448.         checkEfx();
  449.  
  450.         if (loopFlag)
  451.         {
  452.             modRow = newModRow;
  453.             newPosFlag = loopFlag = newModRow = 0;
  454.         }
  455.         else if (++modRow >= 64) newPosFlag = 1;
  456.     }
  457.     else checkEfx();
  458.  
  459.     if (newPosFlag)
  460.     {
  461.         modRow     = newModRow;
  462.         newPosFlag = newModRow = 0;
  463.         modOrder   = (modOrder + 1) & 0x7F;
  464.         if (modOrder >= (modBuffer[950] & 0x7F)) modOrder = 0;
  465.     }
  466. }
  467.  
  468. // please edit this for your own use!
  469. int main(int argc, char *argv[])
  470. {
  471.     FILE *in;
  472.  
  473.     if (argc != 2)
  474.     {
  475.         printf("Usage: kolibrimod.exe <module>\n");
  476.         return (-1);
  477.     }
  478.  
  479.     in = fopen(argv[1], "rb");
  480.     if (in == NULL)
  481.     {
  482.         printf("ERROR: Can't open file!\n");
  483.         return (1);
  484.     }
  485.  
  486.     kolibrimodLoad(in);
  487.     fclose(in);
  488.     kolibrimodPlay();
  489.  
  490.     printf("Playing... Press any key to stop.\n");
  491.     while (!_getch()) Sleep(100);
  492.     kolibrimodFree();
  493.  
  494.     return (0);
  495. }
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