daily pastebin goal
69%
SHARE
TWEET

pt2play v1.50

8bitbubsy Sep 29th, 2013 (edited) 1,073 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /*
  2. ** PT2PLAY v1.50 - 6th of May 2018 - https://16-bits.org
  3. ** =====================================================
  4. **               - NOT BIG ENDIAN SAFE! -  
  5. **
  6. ** Very accurate C port of ProTracker 2.3D's replayer, by
  7. ** Olav "8bitbubsy" Sorensen. Based on a ProTracker 2.3D disassembly
  8. ** using the PT1.2A source code for labels (names).
  9. ** It is NOT recommended to use pt2play with non-ProTracker .MODs.
  10. ** Also, do NOT use a lower audio rate than 32kHz! This will cause problems
  11. ** with low sample periods (high rates) and BLEP.
  12. **
  13. ** The BLEP (Band-Limited Step) and filter routines were coded by aciddose.
  14. ** This makes the replayer sound much similar to a real Amiga.
  15. **
  16. ** You need to link winmm.lib for this to compile (-lwinmm).
  17. ** Alternatively, you can wrap around your own audio callback for using
  18. ** pt2play on other platforms (read comment near bottom).
  19. **
  20. **
  21. ** pt2play.h:
  22. **
  23. ** #include <stdint.h>
  24. **
  25. ** enum
  26. ** {
  27. **     CIA_TEMPO_MODE    = 0,
  28. **     VBLANK_TEMPO_MODE = 1
  29. ** };
  30. **
  31. ** int8_t pt2play_Init(int32_t outputFreq);
  32. ** void pt2play_Close(void);
  33. ** void pt2play_PauseSong(int8_t pause);
  34. ** void pt2play_PlaySong(uint8_t *moduleData, int8_t tempoMode);
  35. ** void pt2play_SetStereoSep(uint8_t percentage);
  36. ** uint32_t pt2play_GetMixerTicks(void);
  37. */
  38.  
  39. /* == USER ADJUSTABLE SETTINGS == */
  40. #define STEREO_SEP (19)    /* --> Stereo separation in percent - 0 = mono, 100 = hard pan (like Amiga) */
  41. #define NORM_FACTOR (4.0f) /* --> Slightly increase this value if the song is too loud. Decrease if too quiet... */
  42. #define USE_HIGHPASS       /* --> 5.2Hz high-pass filter present in all Amigas - comment out for a speed-up */
  43. //#define USE_LOWPASS      /* --> 4.4kHz low-pass filter in all Amigas except A1200 - comment out for sharper sound */
  44. #define USE_BLEP           /* --> Reduces some unwanted aliasing (closer to real Amiga) - comment out to disable */
  45. //#define ENABLE_E8_EFFECT /* --> Enable E8x (Karplus-Strong) - comment out this line if E8x is used for something else */
  46. #define LED_FILTER         /* --> Process the "LED" filter - comment out to disable */
  47. #define AUDIO_BUF_LEN (4096)
  48.  
  49. #ifdef _MSC_VER
  50. #define inline __forceinline
  51. #endif
  52.  
  53. #ifndef true
  54. #define true 1
  55. #define false 0
  56. #endif
  57.  
  58. /* used for faster windows.h parsing when compiling */
  59. #ifndef WIN32_LEAN_AND_MEAN
  60. #define WIN32_LEAN_AND_MEAN
  61. #endif
  62.  
  63. #include <stdio.h>
  64. #include <stdlib.h>
  65. #include <stdint.h>
  66. #include <math.h>     /* tanf() */
  67. #include <windows.h>  /* win32 audio mixer */
  68. #include <mmsystem.h> /* win32 audio mixer */
  69.  
  70. enum
  71. {
  72.     CIA_TEMPO_MODE    = 0,
  73.     VBLANK_TEMPO_MODE = 1
  74. };
  75.  
  76. #define PAULA_PAL_CLK  3546895
  77. #define CIA_PAL_CLK    709379
  78. #define MAX_SAMPLE_LEN 131070
  79.  
  80. #ifdef USE_BLEP /* do not change these! */
  81. #define BLEP_ZC 8
  82. #define BLEP_OS 5
  83. #define BLEP_SP 5
  84. #define BLEP_NS (BLEP_ZC * BLEP_OS / BLEP_SP)
  85. #define BLEP_RNS 7
  86. #endif
  87.  
  88. /* STRUCTS */
  89.  
  90. #ifdef USE_BLEP
  91. typedef struct blep_t
  92. {
  93.     int32_t index, samplesLeft;
  94.     float buffer[BLEP_RNS + 1], lastValue;
  95. } blep_t;
  96. #endif
  97.  
  98. typedef struct ptChannel_t
  99. {
  100.     int8_t *n_start, *n_wavestart, *n_loopstart, n_index, n_volume;
  101.     int8_t n_toneportdirec, n_vibratopos, n_tremolopos, n_pattpos, n_loopcount;
  102.     uint8_t n_wavecontrol, n_glissfunk, n_sampleoffset, n_toneportspeed;
  103.     uint8_t n_vibratocmd, n_tremolocmd, n_finetune, n_funkoffset;
  104.     int16_t n_period, n_note, n_wantedperiod;
  105.     uint16_t n_cmd, n_length, n_replen;
  106. } ptChannel_t;
  107.  
  108. typedef struct paulaVoice_t
  109. {
  110.     volatile uint8_t DMA_ON;
  111.     const int8_t *SRC_DAT, *DMA_DAT;
  112.     int32_t SRC_LEN, DMA_LEN, DMA_POS;
  113.     float SRC_VOL, DELTA, FRAC, LASTDELTA, LASTFRAC, PANL, PANR;
  114. } paulaVoice_t;
  115.  
  116. #if defined(USE_HIGHPASS) || defined(USE_LOWPASS)
  117. typedef struct lossyIntegrator_t
  118. {
  119.     float buffer[2], coeff[2];
  120. } lossyIntegrator_t;
  121. #endif
  122.  
  123. #ifdef LED_FILTER
  124. typedef struct ledFilter_t
  125. {
  126.     float led[4];
  127. } ledFilter_t;
  128.  
  129. typedef struct ledFilterCoeff_t
  130. {
  131.     float led, ledFb;
  132. } ledFilterCoeff_t;
  133. #endif
  134.  
  135. /* STATIC DATA */
  136. static volatile int8_t mixingMutex, isMixing;
  137. static int8_t *SampleStarts[31], *sampleData = NULL, TempoMode, SongPosition, PBreakFlag;
  138. static int8_t DisableMixer, PBreakPosition, PattDelTime, PattDelTime2, PosJumpAssert;
  139. static uint8_t *SongDataPtr, LowMask, Counter, CurrSpeed, SetBPMFlag, SongPlaying;
  140. static uint16_t PatternPos;
  141. static int32_t soundBufferSize, emptySampleDataOffset, samplesPerTickLeft, samplesPerTick;
  142. static uint32_t PattPosOff, sampleCounter;
  143. static float f_outputFreq, *mixerBufferL = NULL, *mixerBufferR = NULL;
  144. static ptChannel_t ChanTemp[4];
  145. static paulaVoice_t AUD[4];
  146. #ifdef USE_BLEP
  147. static blep_t blep[4], blepVol[4];
  148. #endif
  149. #ifdef USE_HIGHPASS
  150. static lossyIntegrator_t filterHi;
  151. #endif
  152. #ifdef USE_LOWPASS
  153. static lossyIntegrator_t filterLo;
  154. #endif
  155. #ifdef LED_FILTER
  156. static ledFilterCoeff_t filterLEDC;
  157. static ledFilter_t filterLED;
  158. static uint8_t LEDStatus;
  159. #endif
  160.  
  161. /* TABLES */
  162. static const uint8_t FunkTable[16] =
  163. {
  164.     0x00, 0x05, 0x06, 0x07, 0x08, 0x0A, 0x0B, 0x0D,
  165.     0x10, 0x13, 0x16, 0x1A, 0x20, 0x2B, 0x40, 0x80
  166. };
  167.  
  168. static const uint8_t VibratoTable[32] =
  169. {
  170.     0x00, 0x18, 0x31, 0x4A, 0x61, 0x78, 0x8D, 0xA1,
  171.     0xB4, 0xC5, 0xD4, 0xE0, 0xEB, 0xF4, 0xFA, 0xFD,
  172.     0xFF, 0xFD, 0xFA, 0xF4, 0xEB, 0xE0, 0xD4, 0xC5,
  173.     0xB4, 0xA1, 0x8D, 0x78, 0x61, 0x4A, 0x31, 0x18
  174. };
  175.  
  176. static const int16_t PeriodTable[606] =
  177. {
  178.     856,808,762,720,678,640,604,570,538,508,480,453,
  179.     428,404,381,360,339,320,302,285,269,254,240,226,
  180.     214,202,190,180,170,160,151,143,135,127,120,113,0,
  181.     850,802,757,715,674,637,601,567,535,505,477,450,
  182.     425,401,379,357,337,318,300,284,268,253,239,225,
  183.     213,201,189,179,169,159,150,142,134,126,119,113,0,
  184.     844,796,752,709,670,632,597,563,532,502,474,447,
  185.     422,398,376,355,335,316,298,282,266,251,237,224,
  186.     211,199,188,177,167,158,149,141,133,125,118,112,0,
  187.     838,791,746,704,665,628,592,559,528,498,470,444,
  188.     419,395,373,352,332,314,296,280,264,249,235,222,
  189.     209,198,187,176,166,157,148,140,132,125,118,111,0,
  190.     832,785,741,699,660,623,588,555,524,495,467,441,
  191.     416,392,370,350,330,312,294,278,262,247,233,220,
  192.     208,196,185,175,165,156,147,139,131,124,117,110,0,
  193.     826,779,736,694,655,619,584,551,520,491,463,437,
  194.     413,390,368,347,328,309,292,276,260,245,232,219,
  195.     206,195,184,174,164,155,146,138,130,123,116,109,0,
  196.     820,774,730,689,651,614,580,547,516,487,460,434,
  197.     410,387,365,345,325,307,290,274,258,244,230,217,
  198.     205,193,183,172,163,154,145,137,129,122,115,109,0,
  199.     814,768,725,684,646,610,575,543,513,484,457,431,
  200.     407,384,363,342,323,305,288,272,256,242,228,216,
  201.     204,192,181,171,161,152,144,136,128,121,114,108,0,
  202.     907,856,808,762,720,678,640,604,570,538,508,480,
  203.     453,428,404,381,360,339,320,302,285,269,254,240,
  204.     226,214,202,190,180,170,160,151,143,135,127,120,0,
  205.     900,850,802,757,715,675,636,601,567,535,505,477,
  206.     450,425,401,379,357,337,318,300,284,268,253,238,
  207.     225,212,200,189,179,169,159,150,142,134,126,119,0,
  208.     894,844,796,752,709,670,632,597,563,532,502,474,
  209.     447,422,398,376,355,335,316,298,282,266,251,237,
  210.     223,211,199,188,177,167,158,149,141,133,125,118,0,
  211.     887,838,791,746,704,665,628,592,559,528,498,470,
  212.     444,419,395,373,352,332,314,296,280,264,249,235,
  213.     222,209,198,187,176,166,157,148,140,132,125,118,0,
  214.     881,832,785,741,699,660,623,588,555,524,494,467,
  215.     441,416,392,370,350,330,312,294,278,262,247,233,
  216.     220,208,196,185,175,165,156,147,139,131,123,117,0,
  217.     875,826,779,736,694,655,619,584,551,520,491,463,
  218.     437,413,390,368,347,328,309,292,276,260,245,232,
  219.     219,206,195,184,174,164,155,146,138,130,123,116,0,
  220.     868,820,774,730,689,651,614,580,547,516,487,460,
  221.     434,410,387,365,345,325,307,290,274,258,244,230,
  222.     217,205,193,183,172,163,154,145,137,129,122,115,0,
  223.     862,814,768,725,684,646,610,575,543,513,484,457,
  224.     431,407,384,363,342,323,305,288,272,256,242,228,
  225.     216,203,192,181,171,161,152,144,136,128,121,114,0,
  226.  
  227.     /* PT BUGFIX: overflowing arpeggio on -1 finetuned samples, add extra zeroes. */
  228.     0,0,0,0,0,0,0,0,0,0,0,0,0,0
  229. };
  230.  
  231. #ifdef USE_BLEP
  232. static const uint32_t blepData[48] =
  233. {
  234.     0x3F7FE1F1, 0x3F7FD548, 0x3F7FD6A3, 0x3F7FD4E3,
  235.     0x3F7FAD85, 0x3F7F2152, 0x3F7DBFAE, 0x3F7ACCDF,
  236.     0x3F752F1E, 0x3F6B7384, 0x3F5BFBCB, 0x3F455CF2,
  237.     0x3F26E524, 0x3F0128C4, 0x3EACC7DC, 0x3E29E86B,
  238.     0x3C1C1D29, 0xBDE4BBE6, 0xBE3AAE04, 0xBE48DEDD,
  239.     0xBE22AD7E, 0xBDB2309A, 0xBB82B620, 0x3D881411,
  240.     0x3DDADBF3, 0x3DE2C81D, 0x3DAAA01F, 0x3D1E769A,
  241.     0xBBC116D7, 0xBD1402E8, 0xBD38A069, 0xBD0C53BB,
  242.     0xBC3FFB8C, 0x3C465FD2, 0x3CEA5764, 0x3D0A51D6,
  243.     0x3CEAE2D5, 0x3C92AC5A, 0x3BE4CBF7, 0x00000000,
  244.     0x00000000, 0x00000000, 0x00000000, 0x00000000,
  245.     0x00000000, 0x00000000, 0x00000000, 0x00000000
  246. };
  247. #endif
  248.  
  249. /* MACROS */
  250.  
  251. // arithmetic shift right on signed variables macros (works properly on all platforms, though not branchless...)
  252. #if defined (__APPLE__) || defined (_WIN32)
  253. #define SAR16(x, n) ((x) >> (n))
  254. #else
  255. #define SAR16(x, n) ((x) >= 0) ? ((x) >> (n)) : (((1 << 16) - (1 << (16 - (n)))) | ((x) >> (n)))
  256. #endif
  257.  
  258. #define SWAP16(x) ((uint16_t)(((x) << 8) | ((x) >> 8)))
  259. #define PTR2WORD(x) ((uint16_t *)(x))
  260. #define LERP(x, y, z) ((x) + ((y) - (x)) * (z))
  261. #define CLAMP16(i) \
  262. { \
  263.     if ((int16_t)(i) != i) \
  264.         i = 0x7FFF ^ (i >> 31); \
  265. }
  266.  
  267. /* CIA/PAULA/FILTER/BLEP RELATED CODE */
  268.  
  269. static void SetReplayerBPM(uint8_t bpm)
  270. {
  271.     uint16_t ciaVal;
  272.     float f_hz, f_smp;
  273.  
  274.     if (f_outputFreq == 0.0f)
  275.         return;
  276.  
  277.     if (bpm < 32)
  278.         bpm = 32;
  279.  
  280.     ciaVal = (uint16_t)(1773447 / bpm); /* yes, truncate here */
  281.     f_hz   = (float)(CIA_PAL_CLK) / ciaVal;
  282.     f_smp  = f_outputFreq / f_hz;
  283.  
  284.     samplesPerTick = (int32_t)(f_smp + 0.5f);
  285. }
  286.  
  287. static void PaulaRestartDMA(uint8_t i)
  288. {
  289.     const int8_t *dat;
  290.     int32_t len;
  291.  
  292.     dat = AUD[i].SRC_DAT;
  293.     if (dat == NULL)
  294.         dat = &sampleData[emptySampleDataOffset];
  295.  
  296.     len = AUD[i].SRC_LEN;
  297.     if (len < 2)
  298.         len = 2;
  299.  
  300.     AUD[i].FRAC    = 0.0f;
  301.     AUD[i].DMA_POS = 0;
  302.     AUD[i].DMA_DAT = dat;
  303.     AUD[i].DMA_LEN = len;
  304.     AUD[i].DMA_ON  = true;
  305. }
  306.  
  307. static void PaulaSetPeriod(uint8_t i, uint16_t period)
  308. {
  309.     if (period == 0)
  310.     {
  311.         AUD[i].DELTA = 0.0f;
  312.     }
  313.     else
  314.     {
  315.         /* confirmed behavior on real Amiga */
  316.         if (period < 113)
  317.             period = 113;
  318.  
  319.         AUD[i].DELTA = ((float)(PAULA_PAL_CLK) / period) / f_outputFreq;
  320.     }
  321.  
  322.     if (AUD[i].LASTDELTA == 0.0f)
  323.         AUD[i].LASTDELTA = AUD[i].DELTA;
  324. }
  325.  
  326. static void PaulaSetVolume(uint8_t i, uint16_t vol)
  327. {
  328.     vol &= 0x007F;
  329.     if (vol > 0x40)
  330.         vol = 0x40;
  331.  
  332.     AUD[i].SRC_VOL = vol * (1.0f / 64.0f);
  333. }
  334.  
  335. static void PaulaSetLength(uint8_t i, uint16_t len)
  336. {
  337.     AUD[i].SRC_LEN = 2 * len;
  338. }
  339.  
  340. static void PaulaSetData(uint8_t i, const int8_t *src)
  341. {
  342.     if (src == NULL)
  343.         src = &sampleData[emptySampleDataOffset];
  344.  
  345.     AUD[i].SRC_DAT = src;
  346. }
  347.  
  348. #if defined(USE_HIGHPASS) || defined(USE_LOWPASS)
  349. static void calcCoeffLossyIntegrator(float sr, float hz, lossyIntegrator_t *filter)
  350. {
  351.     filter->coeff[0] = tanf((3.1415927f * hz) / sr);
  352.     filter->coeff[1] = 1.0f / (1.0f + filter->coeff[0]);
  353. }
  354.  
  355. static void clearLossyIntegrator(lossyIntegrator_t *filter)
  356. {
  357.     filter->buffer[0] = 0.0f;
  358.     filter->buffer[1] = 0.0f;
  359. }
  360.  
  361. static inline void lossyIntegrator(lossyIntegrator_t *filter, float *in, float *out)
  362. {
  363.     float output;
  364.  
  365.     /* left channel low-pass */
  366.     output = (filter->coeff[0] * in[0] + filter->buffer[0]) * filter->coeff[1];
  367.     filter->buffer[0] = filter->coeff[0] * (in[0] - output) + output + 1e-10f;
  368.     out[0] = output;
  369.  
  370.     /* right channel low-pass */
  371.     output = (filter->coeff[0] * in[1] + filter->buffer[1]) * filter->coeff[1];
  372.     filter->buffer[1] = filter->coeff[0] * (in[1] - output) + output + 1e-10f;
  373.     out[1] = output;
  374. }
  375.  
  376. static inline void lossyIntegratorHighPass(lossyIntegrator_t *filter, float *in, float *out)
  377. {
  378.     float low[2];
  379.  
  380.     lossyIntegrator(filter, in, low);
  381.  
  382.     out[0] = in[0] - low[0];
  383.     out[1] = in[1] - low[1];
  384. }
  385. #endif
  386.  
  387. #ifdef LED_FILTER
  388. static void calcCoeffLED(float sr, float hz, ledFilterCoeff_t *filter)
  389. {
  390.     if (hz < (sr / 2.0f))
  391.         filter->led = ((2.0f * 3.1415927f) * hz) / sr;
  392.     else
  393.         filter->led = 1.0f;
  394.  
  395.     filter->ledFb = 0.125f + (0.125f / (1.0f - filter->led)); /* Fb = 0.125 : Q ~= 1/sqrt(2) (Butterworth) */
  396. }
  397.  
  398. static void clearLEDFilter(ledFilter_t *filter)
  399. {
  400.     filter->led[0] = 0.0f;
  401.     filter->led[1] = 0.0f;
  402.     filter->led[2] = 0.0f;
  403.     filter->led[3] = 0.0f;
  404. }
  405.  
  406. static inline void lossyIntegratorLED(ledFilterCoeff_t filterC, ledFilter_t *filter, float *in, float *out)
  407. {
  408.     /* left channel */
  409.     filter->led[0] += (filterC.led * (in[0] - filter->led[0])
  410.         + filterC.ledFb * (filter->led[0] - filter->led[1]) + 1e-10f);
  411.     filter->led[1] += (filterC.led * (filter->led[0] - filter->led[1]) + 1e-10f);
  412.     out[0] = filter->led[1];
  413.  
  414.     /* right channel */
  415.     filter->led[2] += (filterC.led * (in[1] - filter->led[2])
  416.         + filterC.ledFb * (filter->led[2] - filter->led[3]) + 1e-10f);
  417.     filter->led[3] += (filterC.led * (filter->led[2] - filter->led[3]) + 1e-10f);
  418.     out[1] = filter->led[3];
  419. }
  420. #endif
  421.  
  422. #ifdef USE_BLEP
  423. static inline void blepAdd(blep_t *b, float offset, float amplitude)
  424. {
  425.     int8_t n;
  426.     uint32_t i;
  427.     const float *blepSrc;
  428.     float f;
  429.  
  430.     if ((offset < 0.0f) || (offset > 1.0f))
  431.         return;
  432.  
  433.     i  = (uint32_t)(offset * BLEP_SP);
  434.     blepSrc = (const float *)(blepData) + i + BLEP_OS;
  435.  
  436.     f = (offset * BLEP_SP) - i;
  437.     i = b->index;
  438.  
  439.     n = BLEP_NS;
  440.     while (n--)
  441.     {
  442.         b->buffer[i] += (amplitude * LERP(blepSrc[0], blepSrc[1], f));
  443.  
  444.         i++;
  445.         i &= BLEP_RNS;
  446.  
  447.         blepSrc += BLEP_SP;
  448.     }
  449.  
  450.     b->samplesLeft = BLEP_NS;
  451. }
  452.  
  453. static inline float blepRun(blep_t *b)
  454. {
  455.     float blepOutput;
  456.  
  457.     blepOutput = b->buffer[b->index];
  458.     b->buffer[b->index] = 0.0f;
  459.  
  460.     b->index++;
  461.     b->index &= BLEP_RNS;
  462.  
  463.     b->samplesLeft--;
  464.  
  465.     return (blepOutput);
  466. }
  467. #endif
  468.  
  469. /* REPLAYER RELATED CODE */
  470.  
  471. static void UpdateFunk(ptChannel_t *ch)
  472. {
  473.     int8_t funkspeed;
  474.  
  475.     funkspeed = ch->n_glissfunk >> 4;
  476.     if (funkspeed > 0)
  477.     {
  478.         ch->n_funkoffset += FunkTable[funkspeed];
  479.         if (ch->n_funkoffset >= 128)
  480.         {
  481.             ch->n_funkoffset = 0;
  482.  
  483.             if ((ch->n_loopstart != NULL) && (ch->n_wavestart != NULL)) /* SAFETY BUG FIX */
  484.             {
  485.                 if (++ch->n_wavestart >= (ch->n_loopstart + (ch->n_replen * 2)))
  486.                       ch->n_wavestart  =  ch->n_loopstart;
  487.  
  488.                 *ch->n_wavestart = -1 - *ch->n_wavestart;
  489.             }
  490.         }
  491.     }
  492. }
  493.  
  494. static void SetGlissControl(ptChannel_t *ch)
  495. {
  496.     ch->n_glissfunk = (ch->n_glissfunk & 0xF0) | (ch->n_cmd & 0x000F);
  497. }
  498.  
  499. static void SetVibratoControl(ptChannel_t *ch)
  500. {
  501.     ch->n_wavecontrol = (ch->n_wavecontrol & 0xF0) | (ch->n_cmd & 0x000F);
  502. }
  503.  
  504. static void SetFineTune(ptChannel_t *ch)
  505. {
  506.     ch->n_finetune = ch->n_cmd & 0x000F;
  507. }
  508.  
  509. static void JumpLoop(ptChannel_t *ch)
  510. {
  511.     if (!Counter)
  512.     {
  513.         if (!(ch->n_cmd & 0x000F))
  514.         {
  515.             ch->n_pattpos = (PatternPos / 16) & 0x00FF;
  516.         }
  517.         else
  518.         {
  519.             if (!ch->n_loopcount)
  520.             {
  521.                 ch->n_loopcount = ch->n_cmd & 0x000F;
  522.             }
  523.             else
  524.             {
  525.                 if (!--ch->n_loopcount)
  526.                     return;
  527.             }
  528.  
  529.             PBreakPosition = ch->n_pattpos;
  530.             PBreakFlag = true;
  531.         }
  532.     }
  533. }
  534.  
  535. static void SetTremoloControl(ptChannel_t *ch)
  536. {
  537.     ch->n_wavecontrol = ((ch->n_cmd & 0x000F) << 4) | (ch->n_wavecontrol & 0x0F);
  538. }
  539.  
  540. static void KarplusStrong(ptChannel_t *ch)
  541. {
  542. #ifdef ENABLE_E8_EFFECT
  543.     int8_t *smpPtr;
  544.     int16_t dat;
  545.     uint16_t len;
  546.  
  547.     smpPtr = ch->n_loopstart;
  548.     if (smpPtr != NULL) /* SAFETY BUG FIX */
  549.     {
  550.         len = ((ch->n_replen * 2) & 0xFFFF) - 1;
  551.         while (len--)
  552.         {
  553.             dat = smpPtr[1] + smpPtr[0];
  554.             dat = SAR16(dat, 1);
  555.  
  556.             *smpPtr++ = dat & 0x00FF;
  557.         }
  558.  
  559.         dat = ch->n_loopstart[0] + smpPtr[0];
  560.         dat = SAR16(dat, 1);
  561.  
  562.         *smpPtr = dat & 0x00FF;
  563.     }
  564. #else
  565.     (void)(ch);
  566. #endif
  567. }
  568.  
  569. static void DoRetrg(ptChannel_t *ch)
  570. {
  571.     PaulaSetData(ch->n_index, ch->n_start); /* n_start is increased on 9xx */
  572.     PaulaSetLength(ch->n_index, ch->n_length);
  573.     PaulaSetPeriod(ch->n_index, ch->n_period);
  574.     PaulaRestartDMA(ch->n_index);
  575.  
  576.     /* these take effect after the current DMA cycle is done */
  577.     PaulaSetData(ch->n_index, ch->n_loopstart);
  578.     PaulaSetLength(ch->n_index, ch->n_replen);
  579. }
  580.  
  581. static void RetrigNote(ptChannel_t *ch)
  582. {
  583.     if (ch->n_cmd & 0x000F)
  584.     {
  585.         if (!Counter)
  586.         {
  587.             if (ch->n_note & 0x0FFF)
  588.                 return;
  589.         }
  590.  
  591.         if (!(Counter % (ch->n_cmd & 0x000F)))
  592.             DoRetrg(ch);
  593.     }
  594. }
  595.  
  596. static void VolumeSlide(ptChannel_t *ch)
  597. {
  598.     uint8_t cmd;
  599.  
  600.     cmd = ch->n_cmd & 0x00FF;
  601.     if (!(cmd & 0xF0))
  602.     {
  603.         ch->n_volume -= (cmd & 0x0F);
  604.         if (ch->n_volume < 0)
  605.             ch->n_volume = 0;
  606.     }
  607.     else
  608.     {
  609.         ch->n_volume += (cmd >> 4);
  610.         if (ch->n_volume > 64)
  611.             ch->n_volume = 64;
  612.     }
  613. }
  614.  
  615. static void VolumeFineUp(ptChannel_t *ch)
  616. {
  617.     if (!Counter)
  618.     {
  619.         ch->n_volume += (ch->n_cmd & 0x000F);
  620.         if (ch->n_volume > 64)
  621.             ch->n_volume = 64;
  622.     }
  623. }
  624.  
  625. static void VolumeFineDown(ptChannel_t *ch)
  626. {
  627.     if (!Counter)
  628.     {
  629.         ch->n_volume -= (ch->n_cmd & 0x000F);
  630.         if (ch->n_volume < 0)
  631.             ch->n_volume = 0;
  632.     }
  633. }
  634.  
  635. static void NoteCut(ptChannel_t *ch)
  636. {
  637.     if (Counter == (ch->n_cmd & 0x000F))
  638.         ch->n_volume = 0;
  639. }
  640.  
  641. static void NoteDelay(ptChannel_t *ch)
  642. {
  643.     if (Counter == (ch->n_cmd & 0x000F))
  644.     {
  645.         if (ch->n_note & 0x0FFF)
  646.             DoRetrg(ch);
  647.     }
  648. }
  649.  
  650. static void PatternDelay(ptChannel_t *ch)
  651. {
  652.     if (!Counter)
  653.     {
  654.         if (!PattDelTime2)
  655.             PattDelTime = (ch->n_cmd & 0x000F) + 1;
  656.     }
  657. }
  658.  
  659. static void FunkIt(ptChannel_t *ch)
  660. {
  661.     if (!Counter)
  662.     {
  663.         ch->n_glissfunk = ((ch->n_cmd & 0x000F) << 4) | (ch->n_glissfunk & 0x0F);
  664.  
  665.         if (ch->n_glissfunk & 0xF0)
  666.             UpdateFunk(ch);
  667.     }
  668. }
  669.  
  670. static void PositionJump(ptChannel_t *ch)
  671. {
  672.     SongPosition   = (ch->n_cmd & 0x00FF) - 1; /* 0xFF (B00) jumps to pat 0 */
  673.     PBreakPosition = 0;
  674.     PosJumpAssert  = true;
  675. }
  676.  
  677. static void VolumeChange(ptChannel_t *ch)
  678. {
  679.     ch->n_volume = ch->n_cmd & 0x00FF;
  680.     if ((uint8_t)(ch->n_volume) > 64)
  681.         ch->n_volume = 64;
  682. }
  683.  
  684. static void PatternBreak(ptChannel_t *ch)
  685. {
  686.     PBreakPosition = (((ch->n_cmd & 0x00F0) >> 4) * 10) + (ch->n_cmd & 0x000F);
  687.     if ((uint8_t)(PBreakPosition) > 63)
  688.         PBreakPosition = 0;
  689.  
  690.     PosJumpAssert = true;
  691. }
  692.  
  693. static void SetSpeed(ptChannel_t *ch)
  694. {
  695.     if (ch->n_cmd & 0x00FF)
  696.     {
  697.         Counter = 0;
  698.  
  699.         if ((TempoMode == VBLANK_TEMPO_MODE) || ((ch->n_cmd & 0x00FF) < 32))
  700.             CurrSpeed = ch->n_cmd & 0x00FF;
  701.         else
  702.             SetBPMFlag = ch->n_cmd & 0x00FF; /* CIA doesn't refresh its registers until the next interrupt, so change it later */
  703.     }
  704. }
  705.  
  706. static void Arpeggio(ptChannel_t *ch)
  707. {
  708.     uint8_t i, dat;
  709.     const int16_t *arpPointer;
  710.  
  711.     dat = Counter % 3;
  712.     if (!dat)
  713.     {
  714.         PaulaSetPeriod(ch->n_index, ch->n_period);
  715.     }
  716.     else
  717.     {
  718.              if (dat == 1) dat = (ch->n_cmd & 0x00F0) >> 4;
  719.         else if (dat == 2) dat =  ch->n_cmd & 0x000F;
  720.  
  721.         arpPointer = &PeriodTable[37 * ch->n_finetune];
  722.         for (i = 0; i < 37; ++i)
  723.         {
  724.             if (ch->n_period >= arpPointer[i])
  725.             {
  726.                 PaulaSetPeriod(ch->n_index, arpPointer[i + dat]);
  727.                 break;
  728.             }
  729.         }
  730.     }
  731. }
  732.  
  733. static void PortaUp(ptChannel_t *ch)
  734. {
  735.     ch->n_period -= ((ch->n_cmd & 0x00FF) & LowMask);
  736.     LowMask = 0xFF;
  737.  
  738.     if ((ch->n_period & 0x0FFF) < 113)
  739.         ch->n_period = (ch->n_period & 0xF000) | 113;
  740.  
  741.     PaulaSetPeriod(ch->n_index, ch->n_period & 0x0FFF);
  742. }
  743.  
  744. static void PortaDown(ptChannel_t *ch)
  745. {
  746.     ch->n_period += ((ch->n_cmd & 0x00FF) & LowMask);
  747.     LowMask = 0xFF;
  748.  
  749.     if ((ch->n_period & 0x0FFF) > 856)
  750.         ch->n_period = (ch->n_period & 0xF000) | 856;
  751.  
  752.     PaulaSetPeriod(ch->n_index, ch->n_period & 0x0FFF);
  753. }
  754.  
  755. static void FilterOnOff(ptChannel_t *ch)
  756. {
  757. #ifdef LED_FILTER
  758.     LEDStatus = !(ch->n_cmd & 0x0001);
  759. #endif
  760. }
  761.  
  762. static void FinePortaUp(ptChannel_t *ch)
  763. {
  764.     if (!Counter)
  765.     {
  766.         LowMask = 0x0F;
  767.         PortaUp(ch);
  768.     }
  769. }
  770.  
  771. static void FinePortaDown(ptChannel_t *ch)
  772. {
  773.     if (!Counter)
  774.     {
  775.         LowMask = 0x0F;
  776.         PortaDown(ch);
  777.     }
  778. }
  779.  
  780. static void SetTonePorta(ptChannel_t *ch)
  781. {
  782.     uint8_t i;
  783.     const int16_t *portaPointer;
  784.     uint16_t note;
  785.  
  786.     note = ch->n_note & 0x0FFF;
  787.     portaPointer = &PeriodTable[37 * ch->n_finetune];
  788.  
  789.     i = 0;
  790.     for (;;)
  791.     {
  792.         /* portaPointer[36] = 0, so i=36 is safe */
  793.         if (note >= portaPointer[i])
  794.             break;
  795.  
  796.         if (++i >= 37)
  797.         {
  798.             i = 35;
  799.             break;
  800.         }
  801.     }
  802.  
  803.     if ((ch->n_finetune & 8) && i) i--;
  804.  
  805.     ch->n_wantedperiod  = portaPointer[i];
  806.     ch->n_toneportdirec = 0;
  807.  
  808.          if (ch->n_period == ch->n_wantedperiod) ch->n_wantedperiod  = 0;
  809.     else if (ch->n_period  > ch->n_wantedperiod) ch->n_toneportdirec = 1;
  810. }
  811.  
  812. static void TonePortNoChange(ptChannel_t *ch)
  813. {
  814.     uint8_t i;
  815.     const int16_t *portaPointer;
  816.  
  817.     if (ch->n_wantedperiod)
  818.     {
  819.         if (ch->n_toneportdirec)
  820.         {
  821.             ch->n_period -= ch->n_toneportspeed;
  822.             if (ch->n_period <= ch->n_wantedperiod)
  823.             {
  824.                 ch->n_period = ch->n_wantedperiod;
  825.                 ch->n_wantedperiod = 0;
  826.             }
  827.         }
  828.         else
  829.         {
  830.             ch->n_period += ch->n_toneportspeed;
  831.             if (ch->n_period >= ch->n_wantedperiod)
  832.             {
  833.                 ch->n_period = ch->n_wantedperiod;
  834.                 ch->n_wantedperiod = 0;
  835.             }
  836.         }
  837.  
  838.         if (!(ch->n_glissfunk & 0x0F))
  839.         {
  840.             PaulaSetPeriod(ch->n_index, ch->n_period);
  841.         }
  842.         else
  843.         {
  844.             portaPointer = &PeriodTable[37 * ch->n_finetune];
  845.  
  846.             i = 0;
  847.             for (;;)
  848.             {
  849.                 /* portaPointer[36] = 0, so i=36 is safe */
  850.                 if (ch->n_period >= portaPointer[i])
  851.                     break;
  852.  
  853.                 if (++i >= 37)
  854.                 {
  855.                     i = 35;
  856.                     break;
  857.                 }
  858.             }
  859.  
  860.             PaulaSetPeriod(ch->n_index, portaPointer[i]);
  861.         }
  862.     }
  863. }
  864.  
  865. static void TonePortamento(ptChannel_t *ch)
  866. {
  867.     if (ch->n_cmd & 0x00FF)
  868.     {
  869.         ch->n_toneportspeed = ch->n_cmd & 0x00FF;
  870.         ch->n_cmd &= 0xFF00;
  871.     }
  872.  
  873.     TonePortNoChange(ch);
  874. }
  875.  
  876. static void VibratoNoChange(ptChannel_t *ch)
  877. {
  878.     uint8_t vibratoTemp;
  879.     int16_t vibratoData;
  880.  
  881.     vibratoTemp = (ch->n_vibratopos / 4) & 31;
  882.     vibratoData = ch->n_wavecontrol & 3;
  883.  
  884.     if (!vibratoData)
  885.     {
  886.         vibratoData = VibratoTable[vibratoTemp];
  887.     }
  888.     else
  889.     {
  890.         if (vibratoData == 1)
  891.         {
  892.             if (ch->n_vibratopos < 0)
  893.                 vibratoData = 255 - (vibratoTemp * 8);
  894.             else
  895.                 vibratoData = vibratoTemp * 8;
  896.         }
  897.         else
  898.         {
  899.             vibratoData = 255;
  900.         }
  901.     }
  902.  
  903.     vibratoData = (vibratoData * (ch->n_vibratocmd & 0x0F)) / 128;
  904.  
  905.     if (ch->n_vibratopos < 0)
  906.         vibratoData = ch->n_period - vibratoData;
  907.     else
  908.         vibratoData = ch->n_period + vibratoData;
  909.  
  910.     PaulaSetPeriod(ch->n_index, vibratoData);
  911.  
  912.     ch->n_vibratopos += ((ch->n_vibratocmd >> 4) * 4);
  913. }
  914.  
  915. static void Vibrato(ptChannel_t *ch)
  916. {
  917.     if (ch->n_cmd & 0x00FF)
  918.     {
  919.         if (ch->n_cmd & 0x000F)
  920.             ch->n_vibratocmd = (ch->n_vibratocmd & 0xF0) | (ch->n_cmd & 0x000F);
  921.  
  922.         if (ch->n_cmd & 0x00F0)
  923.             ch->n_vibratocmd = (ch->n_cmd & 0x00F0) | (ch->n_vibratocmd & 0x0F);
  924.     }
  925.  
  926.     VibratoNoChange(ch);
  927. }
  928.  
  929. static void TonePlusVolSlide(ptChannel_t *ch)
  930. {
  931.     TonePortNoChange(ch);
  932.     VolumeSlide(ch);
  933. }
  934.  
  935. static void VibratoPlusVolSlide(ptChannel_t *ch)
  936. {
  937.     VibratoNoChange(ch);
  938.     VolumeSlide(ch);
  939. }
  940.  
  941. static void Tremolo(ptChannel_t *ch)
  942. {
  943.     int8_t tremoloTemp;
  944.     int16_t tremoloData;
  945.  
  946.     if (ch->n_cmd & 0x00FF)
  947.     {
  948.         if (ch->n_cmd & 0x000F)
  949.             ch->n_tremolocmd = (ch->n_tremolocmd & 0xF0) | (ch->n_cmd & 0x000F);
  950.  
  951.         if (ch->n_cmd & 0x00F0)
  952.             ch->n_tremolocmd = (ch->n_cmd & 0x00F0) | (ch->n_tremolocmd & 0x0F);
  953.     }
  954.  
  955.     tremoloTemp = (ch->n_tremolopos / 4) & 31;
  956.     tremoloData = (ch->n_wavecontrol >> 4) & 3;
  957.  
  958.     if (!tremoloData)
  959.     {
  960.         tremoloData = VibratoTable[tremoloTemp];
  961.     }
  962.     else
  963.     {
  964.         if (tremoloData == 1)
  965.         {
  966.             if (ch->n_vibratopos < 0) /* PT bug, should've been n_tremolopos */
  967.                 tremoloData = 255 - (tremoloTemp * 8);
  968.             else
  969.                 tremoloData = tremoloTemp * 8;
  970.         }
  971.         else
  972.         {
  973.             tremoloData = 255;
  974.         }
  975.     }
  976.  
  977.     tremoloData = (tremoloData * (ch->n_tremolocmd & 0x0F)) / 64;
  978.  
  979.     if (ch->n_tremolopos < 0)
  980.     {
  981.         tremoloData = ch->n_volume - tremoloData;
  982.         if (tremoloData < 0)
  983.             tremoloData = 0;
  984.     }
  985.     else
  986.     {
  987.         tremoloData = ch->n_volume + tremoloData;
  988.         if (tremoloData > 64)
  989.             tremoloData = 64;
  990.     }
  991.  
  992.     PaulaSetVolume(ch->n_index, tremoloData);
  993.  
  994.     ch->n_tremolopos += ((ch->n_tremolocmd >> 4) * 4);
  995. }
  996.  
  997. static void SampleOffset(ptChannel_t *ch)
  998. {
  999.     uint16_t newOffset;
  1000.  
  1001.     if (ch->n_cmd & 0x00FF)
  1002.         ch->n_sampleoffset = ch->n_cmd & 0x00FF;
  1003.  
  1004.     newOffset = ch->n_sampleoffset * 128;
  1005.     if ((ch->n_length <= 32767) && (newOffset < ch->n_length))
  1006.     {
  1007.         ch->n_length -=  newOffset;
  1008.         ch->n_start  += (newOffset * 2);
  1009.     }
  1010.     else
  1011.     {
  1012.         ch->n_length = 1; /* this must NOT be set to 0! 1 is the correct value */
  1013.     }
  1014. }
  1015.  
  1016. static void E_Commands(ptChannel_t *ch)
  1017. {
  1018.     switch ((ch->n_cmd & 0x00F0) >> 4)
  1019.     {
  1020.         case 0x00: FilterOnOff(ch);       break;
  1021.         case 0x01: FinePortaUp(ch);       break;
  1022.         case 0x02: FinePortaDown(ch);     break;
  1023.         case 0x03: SetGlissControl(ch);   break;
  1024.         case 0x04: SetVibratoControl(ch); break;
  1025.         case 0x05: SetFineTune(ch);       break;
  1026.         case 0x06: JumpLoop(ch);          break;
  1027.         case 0x07: SetTremoloControl(ch); break;
  1028.         case 0x08: KarplusStrong(ch);     break;
  1029.         case 0x09: RetrigNote(ch);        break;
  1030.         case 0x0A: VolumeFineUp(ch);      break;
  1031.         case 0x0B: VolumeFineDown(ch);    break;
  1032.         case 0x0C: NoteCut(ch);           break;
  1033.         case 0x0D: NoteDelay(ch);         break;
  1034.         case 0x0E: PatternDelay(ch);      break;
  1035.         case 0x0F: FunkIt(ch);            break;
  1036.         default:                          break;
  1037.     }
  1038. }
  1039.  
  1040. static void CheckMoreEffects(ptChannel_t *ch)
  1041. {
  1042.     switch ((ch->n_cmd & 0x0F00) >> 8)
  1043.     {
  1044.         case 0x09: SampleOffset(ch); break;
  1045.         case 0x0B: PositionJump(ch); break;
  1046.         case 0x0D: PatternBreak(ch); break;
  1047.         case 0x0E: E_Commands(ch);   break;
  1048.         case 0x0F: SetSpeed(ch);     break;
  1049.         case 0x0C: VolumeChange(ch); break;
  1050.  
  1051.         default: PaulaSetPeriod(ch->n_index, ch->n_period); break;
  1052.     }
  1053. }
  1054.  
  1055. static void CheckEffects(ptChannel_t *ch)
  1056. {
  1057.     uint8_t effect;
  1058.  
  1059.     UpdateFunk(ch);
  1060.  
  1061.     effect = (ch->n_cmd & 0x0F00) >> 8;
  1062.     if (ch->n_cmd & 0x0FFF)
  1063.     {
  1064.         switch (effect)
  1065.         {
  1066.             case 0x00: Arpeggio(ch);            break;
  1067.             case 0x01: PortaUp(ch);             break;
  1068.             case 0x02: PortaDown(ch);           break;
  1069.             case 0x03: TonePortamento(ch);      break;
  1070.             case 0x04: Vibrato(ch);             break;
  1071.             case 0x05: TonePlusVolSlide(ch);    break;
  1072.             case 0x06: VibratoPlusVolSlide(ch); break;
  1073.             case 0x0E: E_Commands(ch);          break;
  1074.             case 0x07:
  1075.                 PaulaSetPeriod(ch->n_index, ch->n_period);
  1076.                 Tremolo(ch);
  1077.             break;
  1078.             case 0x0A:
  1079.                 PaulaSetPeriod(ch->n_index, ch->n_period);
  1080.                 VolumeSlide(ch);
  1081.             break;
  1082.  
  1083.             default: PaulaSetPeriod(ch->n_index, ch->n_period); break;
  1084.         }
  1085.     }
  1086.  
  1087.     if (effect != 0x07)
  1088.         PaulaSetVolume(ch->n_index, ch->n_volume);
  1089. }
  1090.  
  1091. static void SetPeriod(ptChannel_t *ch)
  1092. {
  1093.     uint8_t i;
  1094.     uint16_t note;
  1095.  
  1096.     note = ch->n_note & 0x0FFF;
  1097.     for (i = 0; i < 37; ++i)
  1098.     {
  1099.         /* PeriodTable[36] = 0, so i=36 is safe */
  1100.         if (note >= PeriodTable[i])
  1101.             break;
  1102.     }
  1103.  
  1104.     /* BUG: yes it's 'safe' if i=37 because of padding at the end of period table */
  1105.     ch->n_period = PeriodTable[(37 * ch->n_finetune) + i];
  1106.  
  1107.     if ((ch->n_cmd & 0x0FF0) != 0x0ED0) /* no note delay */
  1108.     {
  1109.         if (!(ch->n_wavecontrol & 0x04)) ch->n_vibratopos = 0;
  1110.         if (!(ch->n_wavecontrol & 0x40)) ch->n_tremolopos = 0;
  1111.  
  1112.         PaulaSetLength(ch->n_index, ch->n_length);
  1113.         PaulaSetData(ch->n_index, ch->n_start);
  1114.  
  1115.         if (ch->n_start == NULL)
  1116.         {
  1117.             ch->n_loopstart = NULL;
  1118.             PaulaSetLength(ch->n_index, 1);
  1119.             ch->n_replen = 1;
  1120.         }
  1121.  
  1122.         PaulaSetPeriod(ch->n_index, ch->n_period);
  1123.         PaulaRestartDMA(ch->n_index);
  1124.     }
  1125.  
  1126.     CheckMoreEffects(ch);
  1127. }
  1128.  
  1129. static void PlayVoice(ptChannel_t *ch)
  1130. {
  1131.     uint8_t *dataPtr, sample, cmd;
  1132.     uint16_t sampleOffset, repeat;
  1133.  
  1134.     if (!ch->n_note && !ch->n_cmd)
  1135.         PaulaSetPeriod(ch->n_index, ch->n_period);
  1136.  
  1137.     dataPtr = &SongDataPtr[PattPosOff];
  1138.  
  1139.     ch->n_note = (dataPtr[0] << 8) | dataPtr[1];
  1140.     ch->n_cmd  = (dataPtr[2] << 8) | dataPtr[3];
  1141.  
  1142.     sample = (dataPtr[0] & 0xF0) | (dataPtr[2] >> 4);
  1143.     if ((sample >= 1) && (sample <= 31)) /* SAFETY BUG FIX: don't handle sample-numbers >31 */
  1144.     {
  1145.         sample--;
  1146.         sampleOffset = 42 + (30 * sample);
  1147.  
  1148.         ch->n_start    = SampleStarts[sample];
  1149.         ch->n_finetune = SongDataPtr[sampleOffset + 2] & 0x0F; /* SAFETY BUG FIX: mask finetune */
  1150.         ch->n_volume   = SongDataPtr[sampleOffset + 3];
  1151.         ch->n_length   = *PTR2WORD(&SongDataPtr[sampleOffset + 0]);
  1152.         ch->n_replen   = *PTR2WORD(&SongDataPtr[sampleOffset + 6]);
  1153.  
  1154.         repeat = *PTR2WORD(&SongDataPtr[sampleOffset + 4]);
  1155.         if (repeat > 0)
  1156.         {
  1157.             ch->n_loopstart = ch->n_start + (repeat * 2);
  1158.             ch->n_wavestart = ch->n_loopstart;
  1159.             ch->n_length    = repeat + ch->n_replen;
  1160.         }
  1161.         else
  1162.         {
  1163.             ch->n_loopstart = ch->n_start;
  1164.             ch->n_wavestart = ch->n_start;
  1165.         }
  1166.  
  1167.         if (ch->n_length == 0)
  1168.             ch->n_loopstart = ch->n_wavestart = &sampleData[emptySampleDataOffset]; /* dummy sample */
  1169.     }
  1170.  
  1171.     if (ch->n_note & 0x0FFF)
  1172.     {
  1173.         if ((ch->n_cmd & 0x0FF0) == 0x0E50) /* set finetune */
  1174.         {
  1175.             SetFineTune(ch);
  1176.             SetPeriod(ch);
  1177.         }
  1178.         else
  1179.         {
  1180.             cmd = (ch->n_cmd & 0x0F00) >> 8;
  1181.             if ((cmd == 0x03) || (cmd == 0x05))
  1182.             {
  1183.                 SetTonePorta(ch);
  1184.                 CheckMoreEffects(ch);
  1185.             }
  1186.             else if (cmd == 0x09)
  1187.             {
  1188.                 CheckMoreEffects(ch);
  1189.                 SetPeriod(ch);
  1190.             }
  1191.             else
  1192.             {
  1193.                 SetPeriod(ch);
  1194.             }
  1195.         }
  1196.     }
  1197.     else
  1198.     {
  1199.         CheckMoreEffects(ch);
  1200.     }
  1201.  
  1202.     PattPosOff += 4;
  1203. }
  1204.  
  1205. static void NextPosition(void)
  1206. {
  1207.     PatternPos     = PBreakPosition * 16;
  1208.     PBreakPosition = 0;
  1209.     PosJumpAssert  = false;
  1210.  
  1211.     SongPosition = (SongPosition + 1) & 0x7F;
  1212.     if (SongPosition >= SongDataPtr[950])
  1213.         SongPosition = 0;
  1214. }
  1215.  
  1216. static void tickReplayer(void) /* called (SongBPM/2.5) times a second (duration: 1000/(SongBPM/2.5) milliseconds) */
  1217. {
  1218.     uint8_t i;
  1219.  
  1220.     if (!SongPlaying)
  1221.         return;
  1222.  
  1223.     /* PT quirk: CIA refreshes its timer values on the next interrupt, so do the real tempo change here */
  1224.     if (SetBPMFlag != 0)
  1225.     {
  1226.         SetReplayerBPM(SetBPMFlag);
  1227.         SetBPMFlag = 0;
  1228.     }
  1229.  
  1230.     if (++Counter >= CurrSpeed)
  1231.     {
  1232.         Counter = 0;
  1233.  
  1234.         if (!PattDelTime2)
  1235.         {
  1236.             PattPosOff = (1084 + (SongDataPtr[952 + SongPosition] * 1024)) + PatternPos;
  1237.  
  1238.             for (i = 0; i < 4; ++i)
  1239.             {
  1240.                 PlayVoice(&ChanTemp[i]);
  1241.                 PaulaSetVolume(i, ChanTemp[i].n_volume);
  1242.  
  1243.                 /* these take effect after the current DMA cycle is done */
  1244.                 PaulaSetData(i, ChanTemp[i].n_loopstart);
  1245.                 PaulaSetLength(i, ChanTemp[i].n_replen);
  1246.             }
  1247.         }
  1248.         else
  1249.         {
  1250.             for (i = 0; i < 4; ++i)
  1251.                 CheckEffects(&ChanTemp[i]);
  1252.         }
  1253.  
  1254.         PatternPos += 16;
  1255.  
  1256.         if (PattDelTime)
  1257.         {
  1258.             PattDelTime2 = PattDelTime;
  1259.             PattDelTime  = 0;
  1260.         }
  1261.  
  1262.         if (PattDelTime2)
  1263.         {
  1264.             PattDelTime2--;
  1265.             if (PattDelTime2)
  1266.                 PatternPos -= 16;
  1267.         }
  1268.  
  1269.         if (PBreakFlag)
  1270.         {
  1271.             PBreakFlag = false;
  1272.  
  1273.             PatternPos = PBreakPosition * 16;
  1274.             PBreakPosition = 0;
  1275.         }
  1276.  
  1277.         if ((PatternPos >= 1024) || PosJumpAssert)
  1278.             NextPosition();
  1279.     }
  1280.     else
  1281.     {
  1282.         for (i = 0; i < 4; ++i)
  1283.             CheckEffects(&ChanTemp[i]);
  1284.  
  1285.         if (PosJumpAssert)
  1286.             NextPosition();
  1287.     }
  1288. }
  1289.  
  1290. static int8_t moduleInit(uint8_t *moduleData)
  1291. {
  1292.     int8_t pattNum, *songSampleData;
  1293.     uint8_t i;
  1294.     uint16_t *p;
  1295.     int32_t loopOverflow, totalSampleSize, sampleDataOffset;
  1296.     ptChannel_t *ch;
  1297.  
  1298.     if (sampleData != NULL)
  1299.     {
  1300.         free(sampleData);
  1301.         sampleData = NULL;
  1302.     }
  1303.  
  1304.     for (i = 0; i < 4; ++i)
  1305.     {
  1306.         ch = &ChanTemp[i];
  1307.  
  1308.         ch->n_index     = i;
  1309.         ch->n_start     = NULL;
  1310.         ch->n_wavestart = NULL;
  1311.         ch->n_loopstart = NULL;
  1312.     }
  1313.  
  1314.     SongDataPtr = moduleData;
  1315.  
  1316.     pattNum = 0;
  1317.     for (i = 0; i < 128; ++i)
  1318.     {
  1319.         if (SongDataPtr[952 + i] > pattNum)
  1320.             pattNum = SongDataPtr[952 + i];
  1321.     }
  1322.     pattNum++;
  1323.  
  1324.     /* first count total sample size to allocate */
  1325.     totalSampleSize = 0;
  1326.     for (i = 0; i < 31; ++i)
  1327.     {
  1328.         p = PTR2WORD(&SongDataPtr[42 + (i * 30)]);
  1329.         totalSampleSize += (SWAP16(p[0]) * 2);
  1330.     }
  1331.  
  1332.     emptySampleDataOffset = totalSampleSize;
  1333.  
  1334.     sampleData = (int8_t *)(malloc(totalSampleSize + MAX_SAMPLE_LEN));
  1335.     if (sampleData == NULL)
  1336.         return (false);
  1337.  
  1338.     /* wipe reserved sample data area */
  1339.     memset(&sampleData[emptySampleDataOffset], 0, MAX_SAMPLE_LEN);
  1340.  
  1341.     /* setup and load samples */
  1342.     songSampleData = (int8_t *)(&SongDataPtr[1084 + (pattNum * 1024)]);
  1343.  
  1344.     sampleDataOffset = 0;
  1345.     for (i = 0; i < 31; ++i)
  1346.     {
  1347.         p = PTR2WORD(&SongDataPtr[42 + (i * 30)]);
  1348.  
  1349.         /* swap bytes in words (Amiga word -> Intel word) */
  1350.         p[0] = SWAP16(p[0]); /* n_length */
  1351.         p[2] = SWAP16(p[2]); /* n_repeat */
  1352.         p[3] = SWAP16(p[3]); /* n_replen */
  1353.  
  1354.         /* set up sample pointer and load sample */
  1355.         if (p[0] == 0)
  1356.         {
  1357.             SampleStarts[i] = &sampleData[emptySampleDataOffset];
  1358.         }
  1359.         else
  1360.         {
  1361.             SampleStarts[i] = &sampleData[sampleDataOffset];
  1362.             memcpy(SampleStarts[i], songSampleData, p[0] * 2);
  1363.  
  1364.             sampleDataOffset += (p[0] * 2);
  1365.             songSampleData   += (p[0] * 2);
  1366.         }
  1367.  
  1368.         if (p[3] == 0)
  1369.             p[3] = 1; /* fix illegal loop length (f.ex. from "Fasttracker II" .MODs) */
  1370.  
  1371.         /* adjust sample length if loop was overflowing */
  1372.         if ((p[3] > 1) && (p[2] + p[3]) > p[0])
  1373.         {
  1374.             loopOverflow = (p[2] + p[3]) - p[0];
  1375.             if ((p[0] + loopOverflow) <= (MAX_SAMPLE_LEN / 2))
  1376.             {
  1377.                 p[0] += (uint16_t)(loopOverflow);
  1378.             }
  1379.             else
  1380.             {
  1381.                 p[2] = 0;
  1382.                 p[3] = 2;
  1383.             }
  1384.         }
  1385.  
  1386.         if ((p[0] >= 1) && ((p[2] + p[3]) <= 1))
  1387.         {
  1388.             /* if no loop, zero first two samples of data to prevent "beep" */
  1389.             SampleStarts[i][0] = 0;
  1390.             SampleStarts[i][1] = 0;
  1391.         }
  1392.     }
  1393.  
  1394.     return (true);
  1395. }
  1396.  
  1397. /* MIXER RELATED CODE */
  1398.  
  1399. /* these are used to create equal powered stereo separation */
  1400. static float sinApx(float x)
  1401. {
  1402.     x = x * (2.0f - x);
  1403.     return (x * 1.09742972f + x * x * 0.31678383f);
  1404. }
  1405.  
  1406. static float cosApx(float x)
  1407. {
  1408.     x = (1.0f - x) * (1.0f + x);
  1409.     return (x * 1.09742972f + x * x * 0.31678383f);
  1410. }
  1411. /* ------------------------------------------------- */
  1412.  
  1413. static void calculatePans(int8_t stereoSeparation)
  1414. {
  1415.     uint8_t scaledPanPos;
  1416.     float p;
  1417.  
  1418.     if (stereoSeparation > 100)
  1419.         stereoSeparation = 100;
  1420.  
  1421.     scaledPanPos = (stereoSeparation * 128) / 100;
  1422.  
  1423.     p = (128 - scaledPanPos) * (1.0f / 256.0f);
  1424.     AUD[0].PANL = cosApx(p);
  1425.     AUD[0].PANR = sinApx(p);
  1426.     AUD[3].PANL = cosApx(p);
  1427.     AUD[3].PANR = sinApx(p);
  1428.  
  1429.     p = (128 + scaledPanPos) * (1.0f / 256.0f);
  1430.     AUD[1].PANL = cosApx(p);
  1431.     AUD[1].PANR = sinApx(p);
  1432.     AUD[2].PANL = cosApx(p);
  1433.     AUD[2].PANR = sinApx(p);
  1434. }
  1435.  
  1436. static void mixChannels(int16_t *streamOut, int32_t numSamples)
  1437. {
  1438.     const int8_t *dataPtr;
  1439.     uint8_t i;
  1440.     int16_t *sndOut;
  1441.     uint16_t j;
  1442.     int32_t smpL, smpR;
  1443.     float tempSample, tempVolume, out_f[2];
  1444.     paulaVoice_t *v;
  1445. #ifdef USE_BLEP
  1446.     blep_t *bSmp, *bVol;
  1447. #endif
  1448.  
  1449.     memset(mixerBufferL, 0, sizeof (float) * numSamples);
  1450.     memset(mixerBufferR, 0, sizeof (float) * numSamples);
  1451.  
  1452.     for (i = 0; i < 4; ++i)
  1453.     {
  1454.         v = &AUD[i];
  1455.  
  1456. #ifdef USE_BLEP
  1457.         bSmp = &blep[i];
  1458.         bVol = &blepVol[i];
  1459. #endif
  1460.         for (j = 0; v->DMA_ON && (j < numSamples); ++j)
  1461.         {
  1462.             dataPtr = v->DMA_DAT;
  1463.             if (dataPtr == NULL)
  1464.             {
  1465.                 tempSample = 0.0f;
  1466.                 tempVolume = 0.0f;
  1467.             }
  1468.             else
  1469.             {
  1470.                 tempSample = dataPtr[v->DMA_POS] * (1.0f / 128.0f);
  1471.                 tempVolume = v->SRC_VOL;
  1472.             }
  1473.  
  1474. #ifdef USE_BLEP
  1475.             if (tempSample != bSmp->lastValue)
  1476.             {
  1477.                 if ((v->LASTDELTA > 0.0f) && (v->LASTDELTA > v->LASTFRAC))
  1478.                     blepAdd(bSmp, v->LASTFRAC / v->LASTDELTA, bSmp->lastValue - tempSample);
  1479.  
  1480.                 bSmp->lastValue = tempSample;
  1481.             }
  1482.  
  1483.             if (tempVolume != bVol->lastValue)
  1484.             {
  1485.                 blepAdd(bVol, 0.0f, bVol->lastValue - tempVolume);
  1486.                 bVol->lastValue = tempVolume;
  1487.             }
  1488.  
  1489.             if (bSmp->samplesLeft) tempSample += blepRun(bSmp);
  1490.             if (bVol->samplesLeft) tempVolume += blepRun(bVol);
  1491. #endif
  1492.  
  1493.             tempSample *= tempVolume;
  1494.  
  1495.             mixerBufferL[j] += (tempSample * v->PANL);
  1496.             mixerBufferR[j] += (tempSample * v->PANR);
  1497.  
  1498.             v->FRAC += v->DELTA;
  1499.             if (v->FRAC >= 1.0f)
  1500.             {
  1501.                 v->FRAC -= 1.0f;
  1502.  
  1503.                 v->LASTFRAC  = v->FRAC;
  1504.                 v->LASTDELTA = v->DELTA;
  1505.  
  1506.                 if (++v->DMA_POS >= v->DMA_LEN)
  1507.                 {
  1508.                     v->DMA_POS = 0;
  1509.  
  1510.                     /* re-fetch Paula register values now */
  1511.                     v->DMA_LEN = v->SRC_LEN;
  1512.                     v->DMA_DAT = v->SRC_DAT;
  1513.                 }
  1514.             }
  1515.         }
  1516.     }
  1517.  
  1518.     sndOut = streamOut;
  1519.     for (j = 0; j < numSamples; ++j)
  1520.     {
  1521.         if (!DisableMixer)
  1522.         {
  1523.             out_f[0] = mixerBufferL[j];
  1524.             out_f[1] = mixerBufferR[j];
  1525.  
  1526. #ifdef USE_LOWPASS
  1527.             lossyIntegrator(&filterLo, out_f, out_f);
  1528. #endif
  1529.  
  1530. #ifdef LED_FILTER
  1531.             if (LEDStatus)
  1532.                 lossyIntegratorLED(filterLEDC, &filterLED, out_f, out_f);
  1533. #endif
  1534.  
  1535. #ifdef USE_HIGHPASS
  1536.             lossyIntegratorHighPass(&filterHi, out_f, out_f);
  1537. #endif
  1538.  
  1539.             /* normalize amplitude */
  1540.             out_f[0] *= (32767.0f / NORM_FACTOR);
  1541.             out_f[1] *= (32767.0f / NORM_FACTOR);
  1542.  
  1543.             /* truncate to signed 32-bit integer */
  1544.             smpL = (int32_t)(out_f[0]);
  1545.             smpR = (int32_t)(out_f[1]);
  1546.  
  1547.             /* clamp to 16-bit signed range */
  1548.             CLAMP16(smpL);
  1549.             CLAMP16(smpR);
  1550.  
  1551.             /* truncate to signed 16-bit integer and store in output buffer */
  1552.             *sndOut++ = (int16_t)(smpL);
  1553.             *sndOut++ = (int16_t)(smpR);
  1554.         }
  1555.         else
  1556.         {
  1557.             *sndOut++ = 0;
  1558.             *sndOut++ = 0;
  1559.         }
  1560.     }
  1561. }
  1562.  
  1563. void pt2play_PauseSong(int8_t pause)
  1564. {
  1565.     DisableMixer = pause ? true : false;
  1566. }
  1567.  
  1568. int8_t pt2play_PlaySong(uint8_t *moduleData, int8_t tempoMode)
  1569. {
  1570.     uint8_t i;
  1571.  
  1572.     sampleCounter = 0;
  1573.  
  1574.     if (!moduleInit(moduleData))
  1575.         return (false);
  1576.  
  1577.     DisableMixer = true;
  1578.  
  1579.     memset(AUD, 0, sizeof (AUD));
  1580.     for (i = 0; i < 4; ++i)
  1581.     {
  1582.         AUD[i].DMA_DAT = NULL;
  1583.         AUD[i].SRC_DAT = NULL;
  1584.     }
  1585.  
  1586.     calculatePans(STEREO_SEP);
  1587.  
  1588. #ifdef USE_BLEP
  1589.     memset(blep,    0, sizeof (blep));
  1590.     memset(blepVol, 0, sizeof (blepVol));
  1591. #endif
  1592.  
  1593. #ifdef USE_LOWPASS
  1594.     clearLossyIntegrator(&filterLo);
  1595. #endif
  1596.  
  1597. #ifdef LED_FILTER
  1598.     clearLEDFilter(&filterLED);
  1599. #endif
  1600.  
  1601. #ifdef USE_HIGHPASS
  1602.     clearLossyIntegrator(&filterHi);
  1603. #endif
  1604.  
  1605.     CurrSpeed      = 6;
  1606.     Counter        = 0;
  1607.     SongPosition   = 0;
  1608.     PatternPos     = 0;
  1609.     PattDelTime    = 0;
  1610.     PattDelTime2   = 0;
  1611.     PBreakPosition = 0;
  1612.     PosJumpAssert  = false;
  1613.     PBreakFlag     = false;
  1614.     LowMask        = 0xFF;
  1615.     TempoMode      = tempoMode ? VBLANK_TEMPO_MODE : CIA_TEMPO_MODE;
  1616.     SongPlaying    = true;
  1617.     DisableMixer   = false;
  1618.  
  1619. #ifdef LED_FILTER
  1620.     LEDStatus = 0;
  1621. #endif
  1622.  
  1623.     return (true);
  1624. }
  1625.  
  1626. void pt2play_SetStereoSep(uint8_t percentage)
  1627. {
  1628.     calculatePans(percentage);
  1629. }
  1630.  
  1631. void pt2play_FillAudioBuffer(int16_t *buffer, int32_t samples)
  1632. {
  1633.     int32_t samplesToMix, samplesTodo;
  1634.  
  1635.     samplesToMix = samples;
  1636.     while (samplesToMix)
  1637.     {
  1638.         samplesTodo = (samplesToMix < samplesPerTickLeft) ? samplesToMix : samplesPerTickLeft;
  1639.  
  1640.         /* prevent buffer overrun (not needed on all audio APIs) */
  1641.         if (samplesTodo > soundBufferSize)
  1642.             samplesTodo = soundBufferSize;
  1643.  
  1644.         if (samplesTodo > 0)
  1645.         {
  1646.             mixChannels(buffer, samplesTodo);
  1647.             buffer += (samplesTodo * 2);
  1648.  
  1649.             samplesToMix -= samplesTodo;
  1650.             samplesPerTickLeft -= samplesTodo;
  1651.         }
  1652.         else
  1653.         {
  1654.             if (!DisableMixer)
  1655.                 tickReplayer();
  1656.  
  1657.             samplesPerTickLeft = samplesPerTick;
  1658.         }
  1659.     }
  1660.  
  1661.     sampleCounter += samples;
  1662. }
  1663.  
  1664. /* the following must be changed if you want to use another audio API than WinMM */
  1665.  
  1666. #define MIX_BUF_NUM 4
  1667.  
  1668. static int8_t *winmmBuffer = NULL;
  1669. static WAVEHDR waveBlocks[MIX_BUF_NUM];
  1670. static HWAVEOUT hWaveOut;
  1671. static WAVEFORMATEX wfx;
  1672.  
  1673. static void CALLBACK callbackWinMM(HWAVEOUT _hWaveOut, UINT uMsg,
  1674.     DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2)
  1675. {
  1676.     WAVEHDR *waveBlockHeader;
  1677.  
  1678.     /* make compiler happy! */
  1679.     (void)(dwParam2);
  1680.     (void)(dwInstance);
  1681.  
  1682.     if (uMsg == MM_WOM_DONE)
  1683.     {
  1684.         mixingMutex = true;
  1685.  
  1686.         waveBlockHeader = (WAVEHDR *)(dwParam1);
  1687.         waveOutUnprepareHeader(_hWaveOut, waveBlockHeader, sizeof (WAVEHDR));
  1688.  
  1689.         if (isMixing)
  1690.         {
  1691.             memcpy(waveBlockHeader->lpData, winmmBuffer, soundBufferSize);
  1692.             waveOutPrepareHeader(_hWaveOut, waveBlockHeader, sizeof (WAVEHDR));
  1693.             waveOutWrite(_hWaveOut, waveBlockHeader, sizeof (WAVEHDR));
  1694.  
  1695.             pt2play_FillAudioBuffer((int16_t *)(winmmBuffer), soundBufferSize / 4);
  1696.         }
  1697.  
  1698.         mixingMutex = false;
  1699.     }
  1700. }
  1701.  
  1702. static int8_t openMixer(uint32_t _outputFrequency, uint32_t _soundBufferSize)
  1703. {
  1704.     uint8_t i;
  1705.     MMRESULT r;
  1706.  
  1707.     if (!hWaveOut)
  1708.     {
  1709.         winmmBuffer = (int8_t *)(calloc(_soundBufferSize, 1));
  1710.         if (winmmBuffer == NULL)
  1711.             return (false); /* gets free'd later */
  1712.  
  1713.         wfx.nSamplesPerSec  = _outputFrequency;
  1714.         wfx.wBitsPerSample  = 16;
  1715.         wfx.nChannels       = 2;
  1716.         wfx.wFormatTag      = WAVE_FORMAT_PCM;
  1717.         wfx.nBlockAlign     = (wfx.wBitsPerSample * wfx.nChannels) / 8;
  1718.         wfx.nAvgBytesPerSec = wfx.nBlockAlign * wfx.nSamplesPerSec;
  1719.  
  1720.         r = waveOutOpen(&hWaveOut, WAVE_MAPPER, &wfx, (DWORD_PTR)(callbackWinMM), 0L, CALLBACK_FUNCTION);
  1721.         if (r != MMSYSERR_NOERROR)
  1722.             return (false);
  1723.  
  1724.         for (i = 0; i < MIX_BUF_NUM; ++i)
  1725.         {
  1726.             waveBlocks[i].dwBufferLength = _soundBufferSize;
  1727.  
  1728.             waveBlocks[i].lpData = (LPSTR)(calloc(_soundBufferSize, 1));
  1729.             if (waveBlocks[i].lpData == NULL)
  1730.                 return (false); /* gets free'd later */
  1731.  
  1732.             waveOutPrepareHeader(hWaveOut, &waveBlocks[i], sizeof (WAVEHDR));
  1733.             waveOutWrite(hWaveOut, &waveBlocks[i], sizeof (WAVEHDR));
  1734.         }
  1735.  
  1736.         return (true);
  1737.     }
  1738.  
  1739.     return (true);
  1740. }
  1741.  
  1742. static void closeMixer(void)
  1743. {
  1744.     uint8_t i;
  1745.  
  1746.     if (hWaveOut)
  1747.     {
  1748.         for (i = 0; i < MIX_BUF_NUM; ++i)
  1749.             waveOutUnprepareHeader(hWaveOut, &waveBlocks[i], sizeof (WAVEHDR));
  1750.  
  1751.         for (i = 0; i < MIX_BUF_NUM; ++i)
  1752.         {
  1753.             while (waveBlocks[i].dwFlags & WHDR_PREPARED) SleepEx(1, 1); // wait
  1754.  
  1755.             if (waveBlocks[i].lpData != NULL)
  1756.             {
  1757.                 free(waveBlocks[i].lpData);
  1758.                 waveBlocks[i].lpData = NULL;
  1759.             }
  1760.         }
  1761.  
  1762.         waveOutReset(hWaveOut);
  1763.         waveOutClose(hWaveOut);
  1764.  
  1765.         hWaveOut = 0;
  1766.  
  1767.         if (winmmBuffer != NULL)
  1768.         {
  1769.             free(winmmBuffer);
  1770.             winmmBuffer = NULL;
  1771.         }
  1772.     }
  1773. }
  1774.  
  1775. uint32_t pt2play_GetMixerTicks(void) /* returns the amount of milliseconds passed in the mixer */
  1776. {
  1777.     if (wfx.nSamplesPerSec < 1000)
  1778.         return (0);
  1779.  
  1780.     return (sampleCounter / (wfx.nSamplesPerSec / 1000));
  1781. }
  1782. /* --------------------------------------------------------------------------- */
  1783.  
  1784. void pt2play_Close(void)
  1785. {
  1786.     DisableMixer = true;
  1787.  
  1788.     if (isMixing)
  1789.     {
  1790.         isMixing = false;
  1791.         while (mixingMutex);
  1792.         closeMixer();
  1793.     }
  1794.  
  1795.     if (sampleData != NULL)
  1796.     {
  1797.         free(sampleData);
  1798.         sampleData = NULL;
  1799.     }
  1800.  
  1801.     if (mixerBufferL != NULL)
  1802.     {
  1803.         free(mixerBufferL);
  1804.         mixerBufferL = NULL;
  1805.     }
  1806.  
  1807.     if (mixerBufferR != NULL)
  1808.     {
  1809.         free(mixerBufferR);
  1810.         mixerBufferR = NULL;
  1811.     }
  1812. }
  1813.  
  1814. int8_t pt2play_Init(int32_t outputFreq)
  1815. {
  1816.     SongPlaying = false;
  1817.  
  1818.     mixerBufferL = (float *)(malloc(AUDIO_BUF_LEN * sizeof (float)));
  1819.     mixerBufferR = (float *)(malloc(AUDIO_BUF_LEN * sizeof (float)));
  1820.  
  1821.     if ((mixerBufferL == NULL) || (mixerBufferR == NULL))
  1822.     {
  1823.         pt2play_Close();
  1824.         return (false);
  1825.     }
  1826.  
  1827.     if (!openMixer(outputFreq, AUDIO_BUF_LEN))
  1828.     {
  1829.         pt2play_Close();
  1830.         return (false);
  1831.     }
  1832.  
  1833.     f_outputFreq    = (float)(outputFreq);
  1834.     soundBufferSize = AUDIO_BUF_LEN;
  1835.  
  1836.     SetReplayerBPM(125);
  1837.  
  1838. #ifdef USE_LOWPASS
  1839.     // Amiga 500 RC low-pass filter (R = 360 ohm, C = 0.1uF)
  1840.     // hz = 1 / (2pi * R * C)    = ~4421.0Hz
  1841.     calcCoeffLossyIntegrator(f_outputFreq, 4421.0f, &filterLo);
  1842. #endif
  1843.  
  1844. #ifdef LED_FILTER
  1845.     // Amiga 500 Sallen-Key "LED" filter (R1 = 10k ohm, R2 = 10k ohm, C1 = 6800pf, C2 = 3900pf)
  1846.     // hz = 1 / (2pi * root(R1 * R2 * C1 * C2))    = ~3090.5Hz
  1847.     calcCoeffLED(f_outputFreq, 3090.5f, &filterLEDC);
  1848. #endif
  1849.  
  1850. #ifdef USE_HIGHPASS
  1851.     // Amiga 500 RC high-pass filter (R = 1390 ohm, C = 22uF)
  1852.     // hz = 1 / (2pi * R * C)    = ~5.2Hz
  1853.     calcCoeffLossyIntegrator(f_outputFreq, 5.2f, &filterHi);
  1854. #endif
  1855.  
  1856.     isMixing = true;
  1857.     return (true);
  1858. }
  1859. /* END OF FILE */
RAW Paste Data
Top