SHARE
TWEET

kolibrimod (tiny .mod replayer)

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