SHARE
TWEET

pt2play v1.57

8bitbubsy Sep 29th, 2013 (edited) 1,557 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /*
  2. ** pt2play v1.57 - 8th of November 2019 - 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. **
  10. ** The BLEP (Band-Limited Step) and filter routines were coded by aciddose.
  11. ** This makes the replayer sound much closer to a real Amiga.
  12. **
  13. ** You need to link winmm.lib for this to compile (-lwinmm).
  14. ** Alternatively, you can change out the mixer functions at the bottom with
  15. ** your own for your OS.
  16. **
  17. ** Example of pt2play usage:
  18. ** #include "pt2play.h"
  19. ** #include "songdata.h"
  20. **
  21. ** pt2play_PlaySong(songData, songDataLength, CIA_TEMPO_MODE, 48000);
  22. ** mainLoop();
  23. ** pt2play_Close();
  24. **
  25. ** To turn a song into an include file like in the example, you can use my win32
  26. ** bin2h tool from here: https://16-bits.org/etc/bin2h.zip
  27. **
  28. ** Changes in v1.57:
  29. ** - Audio signal phase is now inverted on output, like on A500/1200.
  30. **   This can actually change the bass response depending on your speaker elements.
  31. **   In my case, on Sennheiser HD598, I get deeper bass (same as on my Amigas).
  32. ** - All filters (low-pass, "LED", high-pass) have been hand-tweaked to better
  33. **   match A500 and A1200 from intensive testing and waveform comparison.
  34. **   Naturally, the analog filters vary from unit to unit because of component
  35. **   tolerance and aging components, but I am quite confident that this is a
  36. **   closer match than before anyway.
  37. ** - Added audio mixer dithering
  38. **
  39. ** Changes in v1.56:
  40. ** - Fixed EDx (Note Delay) not working
  41. ** - Minor code cleanup
  42. **
  43. ** Changes in v1.55:
  44. ** - Mixer is now using double-precision instead of single-precision accuracy.
  45. **
  46. ** Changes in v1.54:
  47. ** - Code cleanup (uses the "bool" type now, spaces -> tabs, comment style change)
  48. **
  49. ** Changes in v1.53:
  50. ** - Some code cleanup
  51. ** - Small optimziation to audio mixer
  52. **
  53. ** Changes in v1.52:
  54. ** - Added a function to retrieve song name
  55. **
  56. ** Changes in v1.51:
  57. ** - WinMM mixer has been rewritten to be safe (don't use syscalls in callback)
  58. ** - Some small changes to the pt2play functions (easier to use and safer!)
  59. */
  60.  
  61. /* pt2play.h:
  62.  
  63. #pragma once
  64.  
  65. #include <stdint.h>
  66. #include <stdbool.h>
  67.  
  68. enum
  69. {
  70.     CIA_TEMPO_MODE = 0, // default
  71.     VBLANK_TEMPO_MODE = 1
  72. };
  73.  
  74. bool pt2play_PlaySong(const uint8_t *moduleData, uint32_t dataLength, int8_t tempoMode, uint32_t audioFreq);
  75. void pt2play_Close(void);
  76. void pt2play_PauseSong(bool flag); // true/false
  77. void pt2play_TogglePause(void);
  78. void pt2play_SetStereoSep(uint8_t percentage); // 0..100
  79. char *pt2play_GetSongName(void); // max 20 chars (21 with '\0'), string is in latin1
  80. uint32_t pt2play_GetMixerTicks(void); // returns the amount of milliseconds of mixed audio (not realtime)
  81. */
  82.  
  83. // == USER ADJUSTABLE SETTINGS ==
  84. #define STEREO_SEP (20)    /* --> Stereo separation in percent - 0 = mono, 100 = hard pan (like Amiga) */
  85. #define USE_HIGHPASS       /* --> ~5Hz HP filter present in all Amigas - comment out for a tiny speed-up */
  86. //#define USE_LOWPASS      /* --> ~5kHz LP filter present in all Amigas except A1200 - comment out for sharper sound (and tiny speed-up) */
  87. #define USE_BLEP           /* --> Reduces some aliasing in the sound (closer to real Amiga) - comment out for a speed-up */
  88. //#define ENABLE_E8_EFFECT /* --> Enable E8x (Karplus-Strong) - comment out this line if E8x is used for something else */
  89. #define LED_FILTER         /* --> Process the Amiga "LED" filter - comment out to disable */
  90. #define MIX_BUF_SAMPLES 4096
  91.  
  92. #ifdef _MSC_VER
  93. #define inline __forceinline
  94. #endif
  95.  
  96. #include <stdio.h>
  97. #include <stdlib.h>
  98. #include <string.h>
  99. #include <stdint.h>
  100. #include <stdbool.h>
  101. #include <math.h> // tan()
  102.  
  103. enum
  104. {
  105.     CIA_TEMPO_MODE = 0,
  106.     VBLANK_TEMPO_MODE = 1
  107. };
  108.  
  109. // main crystal oscillator
  110. #define AMIGA_PAL_XTAL_HZ 28375160
  111.  
  112. #define PAULA_PAL_CLK (AMIGA_PAL_XTAL_HZ / 8)
  113. #define CIA_PAL_CLK (AMIGA_PAL_XTAL_HZ / 40)
  114.  
  115. #define MAX_SAMPLE_LEN 131070
  116. #define AMIGA_VOICES 4
  117.  
  118. #define INITIAL_DITHER_SEED 0x12345000
  119. #define DENORMAL_OFFSET 1e-10
  120.  
  121. #ifdef USE_BLEP // do not change these!
  122. #define BLEP_ZC 8
  123. #define BLEP_OS 5
  124. #define BLEP_SP 5
  125. #define BLEP_NS (BLEP_ZC * BLEP_OS / BLEP_SP)
  126. #define BLEP_RNS 7
  127. #endif
  128.  
  129. #ifdef USE_BLEP
  130. typedef struct blep_t
  131. {
  132.     int32_t index, samplesLeft;
  133.     double dBuffer[BLEP_RNS + 1], dLastValue;
  134. } blep_t;
  135. #endif
  136.  
  137. typedef struct ptChannel_t
  138. {
  139.     int8_t *n_start, *n_wavestart, *n_loopstart, n_index, n_volume;
  140.     int8_t n_toneportdirec, n_vibratopos, n_tremolopos, n_pattpos, n_loopcount;
  141.     uint8_t n_wavecontrol, n_glissfunk, n_sampleoffset, n_toneportspeed;
  142.     uint8_t n_vibratocmd, n_tremolocmd, n_finetune, n_funkoffset;
  143.     int16_t n_period, n_note, n_wantedperiod;
  144.     uint16_t n_cmd, n_length, n_replen;
  145. } ptChannel_t;
  146.  
  147. typedef struct paulaVoice_t
  148. {
  149.     volatile bool active;
  150.     const int8_t *data, *newData;
  151.     int32_t length, newLength, pos;
  152.     double dVolume, dDelta, dPhase, dPanL, dPanR;
  153. #ifdef USE_BLEP
  154.     double dLastDelta, dLastPhase;
  155. #endif
  156. } paulaVoice_t;
  157.  
  158. #if defined(USE_HIGHPASS) || defined(USE_LOWPASS)
  159. typedef struct lossyIntegrator_t
  160. {
  161.     double dBuffer[2], b0, b1;
  162. } lossyIntegrator_t;
  163. #endif
  164.  
  165. #ifdef LED_FILTER
  166. typedef struct ledFilter_t
  167. {
  168.     double dLed[4];
  169. } ledFilter_t;
  170.  
  171. typedef struct ledFilterCoeff_t
  172. {
  173.     double dLed, dLedFb;
  174. } ledFilterCoeff_t;
  175. #endif
  176.  
  177. static char songName[20 + 1];
  178. static volatile bool musicPaused, SongPlaying;
  179. static bool PBreakFlag, PosJumpAssert;
  180. static int8_t *SampleStarts[31], *SampleData, TempoMode, SongPosition;
  181. static int8_t PBreakPosition, PattDelTime, PattDelTime2;
  182. static uint8_t SetBPMFlag, *SongDataPtr, LowMask, Counter, CurrSpeed, stereoSep = STEREO_SEP;
  183. static uint16_t oldPeriod, PatternPos, bpmTab[256-32];
  184. static int32_t soundBufferSize, audioRate, EmptySampleOffset, samplesPerTickLeft, samplesPerTick;
  185. static int32_t randSeed = INITIAL_DITHER_SEED;
  186. static uint32_t PattPosOff, sampleCounter;
  187. static double oldVoiceDelta, dAudioRate, dPeriodToDeltaDiv, *dMixerBufferL, *dMixerBufferR;
  188. static ptChannel_t ChanTemp[AMIGA_VOICES];
  189. static paulaVoice_t paula[AMIGA_VOICES];
  190. #ifdef USE_BLEP
  191. static blep_t blep[AMIGA_VOICES], blepVol[AMIGA_VOICES];
  192. #endif
  193. #ifdef USE_HIGHPASS
  194. static lossyIntegrator_t filterHi;
  195. #endif
  196. #ifdef USE_LOWPASS
  197. static lossyIntegrator_t filterLo;
  198. #endif
  199. #ifdef LED_FILTER
  200. static ledFilterCoeff_t filterLEDC;
  201. static ledFilter_t filterLED;
  202. static uint8_t LEDStatus;
  203. #endif
  204.  
  205. static const uint8_t FunkTable[16] =
  206. {
  207.     0x00, 0x05, 0x06, 0x07, 0x08, 0x0A, 0x0B, 0x0D,
  208.     0x10, 0x13, 0x16, 0x1A, 0x20, 0x2B, 0x40, 0x80
  209. };
  210.  
  211. static const uint8_t VibratoTable[32] =
  212. {
  213.     0x00, 0x18, 0x31, 0x4A, 0x61, 0x78, 0x8D, 0xA1,
  214.     0xB4, 0xC5, 0xD4, 0xE0, 0xEB, 0xF4, 0xFA, 0xFD,
  215.     0xFF, 0xFD, 0xFA, 0xF4, 0xEB, 0xE0, 0xD4, 0xC5,
  216.     0xB4, 0xA1, 0x8D, 0x78, 0x61, 0x4A, 0x31, 0x18
  217. };
  218.  
  219. static const int16_t PeriodTable[606] =
  220. {
  221.     856,808,762,720,678,640,604,570,538,508,480,453,
  222.     428,404,381,360,339,320,302,285,269,254,240,226,
  223.     214,202,190,180,170,160,151,143,135,127,120,113,0,
  224.     850,802,757,715,674,637,601,567,535,505,477,450,
  225.     425,401,379,357,337,318,300,284,268,253,239,225,
  226.     213,201,189,179,169,159,150,142,134,126,119,113,0,
  227.     844,796,752,709,670,632,597,563,532,502,474,447,
  228.     422,398,376,355,335,316,298,282,266,251,237,224,
  229.     211,199,188,177,167,158,149,141,133,125,118,112,0,
  230.     838,791,746,704,665,628,592,559,528,498,470,444,
  231.     419,395,373,352,332,314,296,280,264,249,235,222,
  232.     209,198,187,176,166,157,148,140,132,125,118,111,0,
  233.     832,785,741,699,660,623,588,555,524,495,467,441,
  234.     416,392,370,350,330,312,294,278,262,247,233,220,
  235.     208,196,185,175,165,156,147,139,131,124,117,110,0,
  236.     826,779,736,694,655,619,584,551,520,491,463,437,
  237.     413,390,368,347,328,309,292,276,260,245,232,219,
  238.     206,195,184,174,164,155,146,138,130,123,116,109,0,
  239.     820,774,730,689,651,614,580,547,516,487,460,434,
  240.     410,387,365,345,325,307,290,274,258,244,230,217,
  241.     205,193,183,172,163,154,145,137,129,122,115,109,0,
  242.     814,768,725,684,646,610,575,543,513,484,457,431,
  243.     407,384,363,342,323,305,288,272,256,242,228,216,
  244.     204,192,181,171,161,152,144,136,128,121,114,108,0,
  245.     907,856,808,762,720,678,640,604,570,538,508,480,
  246.     453,428,404,381,360,339,320,302,285,269,254,240,
  247.     226,214,202,190,180,170,160,151,143,135,127,120,0,
  248.     900,850,802,757,715,675,636,601,567,535,505,477,
  249.     450,425,401,379,357,337,318,300,284,268,253,238,
  250.     225,212,200,189,179,169,159,150,142,134,126,119,0,
  251.     894,844,796,752,709,670,632,597,563,532,502,474,
  252.     447,422,398,376,355,335,316,298,282,266,251,237,
  253.     223,211,199,188,177,167,158,149,141,133,125,118,0,
  254.     887,838,791,746,704,665,628,592,559,528,498,470,
  255.     444,419,395,373,352,332,314,296,280,264,249,235,
  256.     222,209,198,187,176,166,157,148,140,132,125,118,0,
  257.     881,832,785,741,699,660,623,588,555,524,494,467,
  258.     441,416,392,370,350,330,312,294,278,262,247,233,
  259.     220,208,196,185,175,165,156,147,139,131,123,117,0,
  260.     875,826,779,736,694,655,619,584,551,520,491,463,
  261.     437,413,390,368,347,328,309,292,276,260,245,232,
  262.     219,206,195,184,174,164,155,146,138,130,123,116,0,
  263.     868,820,774,730,689,651,614,580,547,516,487,460,
  264.     434,410,387,365,345,325,307,290,274,258,244,230,
  265.     217,205,193,183,172,163,154,145,137,129,122,115,0,
  266.     862,814,768,725,684,646,610,575,543,513,484,457,
  267.     431,407,384,363,342,323,305,288,272,256,242,228,
  268.     216,203,192,181,171,161,152,144,136,128,121,114,0,
  269.  
  270.     // PT BUGFIX: overflowing arpeggio on -1 finetuned samples, add extra zeroes.
  271.     0,0,0,0,0,0,0,0,0,0,0,0,0,0
  272. };
  273.  
  274. #ifdef USE_BLEP
  275.  
  276. /* Why this table is not represented as readable float (double) numbers:
  277. ** Accurate float (double) representation in string format requires at least 14 digits and normalized
  278. ** (scientific) notation, notwithstanding compiler issues with precision or rounding error.
  279. ** Also, don't touch this table ever, just keep it exactly identical! */
  280.  
  281. // TODO: get a proper double-precision table. This one is converted from float
  282. static const uint64_t dBlepData[48] =
  283. {
  284.     0x3FEFFC3E20000000, 0x3FEFFAA900000000, 0x3FEFFAD460000000, 0x3FEFFA9C60000000,
  285.     0x3FEFF5B0A0000000, 0x3FEFE42A40000000, 0x3FEFB7F5C0000000, 0x3FEF599BE0000000,
  286.     0x3FEEA5E3C0000000, 0x3FED6E7080000000, 0x3FEB7F7960000000, 0x3FE8AB9E40000000,
  287.     0x3FE4DCA480000000, 0x3FE0251880000000, 0x3FD598FB80000000, 0x3FC53D0D60000000,
  288.     0x3F8383A520000000, 0xBFBC977CC0000000, 0xBFC755C080000000, 0xBFC91BDBA0000000,
  289.     0xBFC455AFC0000000, 0xBFB6461340000000, 0xBF7056C400000000, 0x3FB1028220000000,
  290.     0x3FBB5B7E60000000, 0x3FBC5903A0000000, 0x3FB55403E0000000, 0x3FA3CED340000000,
  291.     0xBF7822DAE0000000, 0xBFA2805D00000000, 0xBFA7140D20000000, 0xBFA18A7760000000,
  292.     0xBF87FF7180000000, 0x3F88CBFA40000000, 0x3F9D4AEC80000000, 0x3FA14A3AC0000000,
  293.     0x3F9D5C5AA0000000, 0x3F92558B40000000, 0x3F7C997EE0000000, 0x0000000000000000,
  294.     0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
  295.     0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000
  296. };
  297. #endif
  298.  
  299. #define SWAP16(x) ((uint16_t)(((x) << 8) | ((x) >> 8)))
  300. #define PTR2WORD(x) ((uint16_t *)(x))
  301. #define LERP(x, y, z) ((x) + ((y) - (x)) * (z))
  302. #define CLAMP(x, low, high) (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x)))
  303. #define CLAMP16(i) if ((int16_t)i != i) i = 0x7FFF ^ (i >> 31);
  304.  
  305. static bool openMixer(uint32_t audioFreq);
  306. static void closeMixer(void);
  307.  
  308. // CODE START
  309.  
  310. static void paulaStartDMA(uint8_t i)
  311. {
  312.     const int8_t *data;
  313.     int32_t length;
  314.     paulaVoice_t *v = &paula[i];
  315.  
  316.     data = v->newData;
  317.     if (data == NULL)
  318.         data = &SampleData[EmptySampleOffset];
  319.  
  320.     length = v->newLength;
  321.     if (length < 2)
  322.         length = 2;
  323.  
  324.     v->dPhase = 0.0;
  325.     v->pos = 0;
  326.     v->data = data;
  327.     v->length = length;
  328.     v->active = true;
  329. }
  330.  
  331. static void paulaSetPeriod(uint8_t i, uint16_t period)
  332. {
  333.     paulaVoice_t *v = &paula[i];
  334.  
  335.     if (period == 0)
  336.     {
  337.         v->dDelta = 0.0f;
  338.         return;
  339.     }
  340.  
  341.     // confirmed Paula behavior
  342.     if (period < 113)
  343.         period = 113;
  344.  
  345.     if (period == oldPeriod)
  346.     {
  347.         v->dDelta = oldVoiceDelta;
  348.     }
  349.     else
  350.     {
  351.         oldPeriod = period;
  352.         v->dDelta = dPeriodToDeltaDiv / period;
  353.         oldVoiceDelta = v->dDelta;
  354.     }
  355.  
  356. #ifdef USE_BLEP
  357.     if (v->dLastDelta == 0.0)
  358.         v->dLastDelta = v->dDelta;
  359. #endif
  360. }
  361.  
  362. static void paulaSetVolume(uint8_t i, uint16_t vol)
  363. {
  364.     vol &= 127;
  365.     if (vol > 64)
  366.         vol = 64;
  367.  
  368.     paula[i].dVolume = vol * (1.0 / 64.0);
  369. }
  370.  
  371. static void paulaSetLength(uint8_t i, uint16_t len)
  372. {
  373.     paula[i].newLength = len * 2;
  374. }
  375.  
  376. static void paulaSetData(uint8_t i, const int8_t *src)
  377. {
  378.     if (src == NULL)
  379.         src = &SampleData[EmptySampleOffset];
  380.  
  381.     paula[i].newData = src;
  382. }
  383.  
  384. #if defined(USE_HIGHPASS) || defined(USE_LOWPASS)
  385. static void calcCoeffLossyIntegrator(double dSr, double dHz, lossyIntegrator_t *filter)
  386. {
  387.     double dOmega = ((2.0 * M_PI) * dHz) / dSr;
  388.     filter->b0 = 1.0 / (1.0 + (1.0 / dOmega));
  389.     filter->b1 = 1.0 - filter->b0;
  390. }
  391.  
  392. static void clearLossyIntegrator(lossyIntegrator_t *filter)
  393. {
  394.     filter->dBuffer[0] = 0.0; // L
  395.     filter->dBuffer[1] = 0.0; // R
  396. }
  397.  
  398. static inline void lossyIntegrator(lossyIntegrator_t *filter, double *dIn, double *dOut)
  399. {
  400.     /* Low-pass filter implementation taken from:
  401.     ** https://bel.fi/alankila/modguide/interpolate.txt */
  402.  
  403.     // left channel low-pass
  404.     filter->dBuffer[0] = (filter->b0 * dIn[0]) + (filter->b1 * filter->dBuffer[0]) + DENORMAL_OFFSET;
  405.     dOut[0] = filter->dBuffer[0];
  406.  
  407.     // right channel low-pass
  408.     filter->dBuffer[1] = (filter->b0 * dIn[1]) + (filter->b1 * filter->dBuffer[1]) + DENORMAL_OFFSET;
  409.     dOut[1] = filter->dBuffer[1];
  410. }
  411.  
  412. static inline void lossyIntegratorHighPass(lossyIntegrator_t *filter, double *dIn, double *dOut)
  413. {
  414.     double dLow[2];
  415.  
  416.     lossyIntegrator(filter, dIn, dLow);
  417.  
  418.     dOut[0] = dIn[0] - dLow[0]; // left channel high-pass
  419.     dOut[1] = dIn[1] - dLow[1]; // right channel high-pass
  420. }
  421. #endif
  422.  
  423. #ifdef LED_FILTER
  424. static void calcCoeffLED(double dSr, double dHz, ledFilterCoeff_t *filter)
  425. {
  426.     static double dFb = 0.125;
  427.  
  428. #ifndef NO_FILTER_FINETUNING
  429.     /* 8bitbubsy: makes the filter curve sound (and look) much closer to the real deal.
  430.     ** This has been tested against both an A500 and A1200. */
  431.     dFb *= 0.62;
  432. #endif
  433.  
  434.     if (dHz < dSr/2.0)
  435.         filter->dLed = ((2.0 * M_PI) * dHz) / dSr;
  436.     else
  437.         filter->dLed = 1.0;
  438.  
  439.     filter->dLedFb = dFb + (dFb / (1.0 - filter->dLed)); // Q ~= 1/sqrt(2) (Butterworth)
  440. }
  441.  
  442. static void clearLEDFilter(ledFilter_t *filter)
  443. {
  444.     filter->dLed[0] = 0.0; // L
  445.     filter->dLed[1] = 0.0;
  446.     filter->dLed[2] = 0.0; // R
  447.     filter->dLed[3] = 0.0;
  448. }
  449.  
  450. static inline void lossyIntegratorLED(ledFilterCoeff_t filterC, ledFilter_t *filter, double *dIn, double *dOut)
  451. {
  452.     // left channel LED filter
  453.     filter->dLed[0] += (filterC.dLed * (dIn[0] - filter->dLed[0])
  454.         + filterC.dLedFb * (filter->dLed[0] - filter->dLed[1]) + DENORMAL_OFFSET);
  455.     filter->dLed[1] += (filterC.dLed * (filter->dLed[0] - filter->dLed[1]) + DENORMAL_OFFSET);
  456.     dOut[0] = filter->dLed[1];
  457.  
  458.     // right channel LED filter
  459.     filter->dLed[2] += (filterC.dLed * (dIn[1] - filter->dLed[2])
  460.         + filterC.dLedFb * (filter->dLed[2] - filter->dLed[3]) + DENORMAL_OFFSET);
  461.     filter->dLed[3] += (filterC.dLed * (filter->dLed[2] - filter->dLed[3]) + DENORMAL_OFFSET);
  462.     dOut[1] = filter->dLed[3];
  463. }
  464. #endif
  465.  
  466. #ifdef USE_BLEP
  467. static inline void blepAdd(blep_t *b, double dOffset, double dAmplitude)
  468. {
  469.     int8_t n;
  470.     int32_t i;
  471.     const double *dBlepSrc;
  472.     double f;
  473.  
  474.     f = dOffset * BLEP_SP;
  475.  
  476.     i = (int32_t)f; // get integer part of f
  477.     dBlepSrc = (const double *)dBlepData + i + BLEP_OS;
  478.     f -= i; // remove integer part from f
  479.  
  480.     i = b->index;
  481.  
  482.     n = BLEP_NS;
  483.     while (n--)
  484.     {
  485.         b->dBuffer[i] += (dAmplitude * LERP(dBlepSrc[0], dBlepSrc[1], f));
  486.         i = (i + 1) & BLEP_RNS;
  487.         dBlepSrc += BLEP_SP;
  488.     }
  489.  
  490.     b->samplesLeft = BLEP_NS;
  491. }
  492.  
  493. static inline double blepRun(blep_t *b)
  494. {
  495.     double fBlepOutput;
  496.  
  497.     fBlepOutput = b->dBuffer[b->index];
  498.     b->dBuffer[b->index] = 0.0;
  499.  
  500.     b->index = (b->index + 1) & BLEP_RNS;
  501.  
  502.     b->samplesLeft--;
  503.     return fBlepOutput;
  504. }
  505. #endif
  506.  
  507. static void SetReplayerBPM(uint8_t bpm)
  508. {
  509.     if (bpm < 32)
  510.         return;
  511.  
  512.     samplesPerTick = bpmTab[bpm-32];
  513. }
  514.  
  515. static void UpdateFunk(ptChannel_t *ch)
  516. {
  517.     int8_t funkspeed;
  518.  
  519.     funkspeed = ch->n_glissfunk >> 4;
  520.     if (funkspeed == 0)
  521.         return;
  522.  
  523.     ch->n_funkoffset += FunkTable[funkspeed];
  524.     if (ch->n_funkoffset >= 128)
  525.     {
  526.         ch->n_funkoffset = 0;
  527.  
  528.         if (ch->n_loopstart != NULL && ch->n_wavestart != NULL) // SAFETY BUG FIX
  529.         {
  530.             if (++ch->n_wavestart >= ch->n_loopstart+(ch->n_replen *2))
  531.                 ch->n_wavestart = ch->n_loopstart;
  532.  
  533.             *ch->n_wavestart = -1 - *ch->n_wavestart;
  534.         }
  535.     }
  536. }
  537.  
  538. static void SetGlissControl(ptChannel_t *ch)
  539. {
  540.     ch->n_glissfunk = (ch->n_glissfunk & 0xF0) | (ch->n_cmd & 0x0F);
  541. }
  542.  
  543. static void SetVibratoControl(ptChannel_t *ch)
  544. {
  545.     ch->n_wavecontrol = (ch->n_wavecontrol & 0xF0) | (ch->n_cmd & 0x0F);
  546. }
  547.  
  548. static void SetFineTune(ptChannel_t *ch)
  549. {
  550.     ch->n_finetune = ch->n_cmd & 0xF;
  551. }
  552.  
  553. static void JumpLoop(ptChannel_t *ch)
  554. {
  555.     if (Counter == 0)
  556.     {
  557.         if ((ch->n_cmd & 0xF) == 0)
  558.         {
  559.             ch->n_pattpos = (PatternPos / 16) & 0xFF;
  560.         }
  561.         else
  562.         {
  563.             if (ch->n_loopcount == 0)
  564.             {
  565.                 ch->n_loopcount = ch->n_cmd & 0xF;
  566.             }
  567.             else
  568.             {
  569.                 if (--ch->n_loopcount == 0)
  570.                     return;
  571.             }
  572.  
  573.             PBreakPosition = ch->n_pattpos;
  574.             PBreakFlag = true;
  575.         }
  576.     }
  577. }
  578.  
  579. static void SetTremoloControl(ptChannel_t *ch)
  580. {
  581.     ch->n_wavecontrol = ((ch->n_cmd & 0xF) << 4) | (ch->n_wavecontrol & 0xF);
  582. }
  583.  
  584. static void KarplusStrong(ptChannel_t *ch)
  585. {
  586. #ifdef ENABLE_E8_EFFECT
  587.     int8_t *smpPtr;
  588.     uint16_t len;
  589.  
  590.     smpPtr = ch->n_loopstart;
  591.     if (smpPtr != NULL) // SAFETY BUG FIX
  592.     {
  593.         len = ((ch->n_replen * 2) & 0xFFFF) - 1;
  594.         while (len--)
  595.             *smpPtr++ = (int8_t)((smpPtr[1] + smpPtr[0]) >> 1);
  596.  
  597.         *smpPtr = (int8_t)((ch->n_loopstart[0] + smpPtr[0]) >> 1);
  598.     }
  599. #else
  600.     (void)(ch);
  601. #endif
  602. }
  603.  
  604. static void DoRetrg(ptChannel_t *ch)
  605. {
  606.     paulaSetData(ch->n_index, ch->n_start); // n_start is increased on 9xx
  607.     paulaSetLength(ch->n_index, ch->n_length);
  608.     paulaSetPeriod(ch->n_index, ch->n_period);
  609.     paulaStartDMA(ch->n_index);
  610.  
  611.     // these take effect after the current cycle is done
  612.     paulaSetData(ch->n_index, ch->n_loopstart);
  613.     paulaSetLength(ch->n_index, ch->n_replen);
  614. }
  615.  
  616. static void RetrigNote(ptChannel_t *ch)
  617. {
  618.     if ((ch->n_cmd & 0xF) > 0)
  619.     {
  620.         if (Counter == 0 && (ch->n_note & 0xFFF) > 0)
  621.                 return;
  622.  
  623.         if (Counter % (ch->n_cmd & 0xF) == 0)
  624.             DoRetrg(ch);
  625.     }
  626. }
  627.  
  628. static void VolumeSlide(ptChannel_t *ch)
  629. {
  630.     uint8_t cmd = ch->n_cmd & 0xFF;
  631.  
  632.     if ((cmd & 0xF0) == 0)
  633.     {
  634.         ch->n_volume -= cmd & 0xF;
  635.         if (ch->n_volume < 0)
  636.             ch->n_volume = 0;
  637.     }
  638.     else
  639.     {
  640.         ch->n_volume += cmd >> 4;
  641.         if (ch->n_volume > 64)
  642.             ch->n_volume = 64;
  643.     }
  644. }
  645.  
  646. static void VolumeFineUp(ptChannel_t *ch)
  647. {
  648.     if (Counter == 0)
  649.     {
  650.         ch->n_volume += ch->n_cmd & 0xF;
  651.         if (ch->n_volume > 64)
  652.             ch->n_volume = 64;
  653.     }
  654. }
  655.  
  656. static void VolumeFineDown(ptChannel_t *ch)
  657. {
  658.     if (Counter == 0)
  659.     {
  660.         ch->n_volume -= ch->n_cmd & 0xF;
  661.         if (ch->n_volume < 0)
  662.             ch->n_volume = 0;
  663.     }
  664. }
  665.  
  666. static void NoteCut(ptChannel_t *ch)
  667. {
  668.     if (Counter == (ch->n_cmd & 0xF))
  669.         ch->n_volume = 0;
  670. }
  671.  
  672. static void NoteDelay(ptChannel_t *ch)
  673. {
  674.     if (Counter == (ch->n_cmd & 0xF) && (ch->n_note & 0xFFF) > 0)
  675.         DoRetrg(ch);
  676. }
  677.  
  678. static void PatternDelay(ptChannel_t *ch)
  679. {
  680.     if (Counter == 0 && PattDelTime2 == 0)
  681.         PattDelTime = (ch->n_cmd & 0xF) + 1;
  682. }
  683.  
  684. static void FunkIt(ptChannel_t *ch)
  685. {
  686.     if (Counter == 0)
  687.     {
  688.         ch->n_glissfunk = ((ch->n_cmd & 0xF) << 4) | (ch->n_glissfunk & 0xF);
  689.         if ((ch->n_glissfunk & 0xF0) > 0)
  690.             UpdateFunk(ch);
  691.     }
  692. }
  693.  
  694. static void PositionJump(ptChannel_t *ch)
  695. {
  696.     SongPosition = (ch->n_cmd & 0xFF) - 1; // 0xFF (B00) jumps to pat 0
  697.     PBreakPosition = 0;
  698.     PosJumpAssert = true;
  699. }
  700.  
  701. static void VolumeChange(ptChannel_t *ch)
  702. {
  703.     ch->n_volume = ch->n_cmd & 0xFF;
  704.  
  705.     // unsigned comparison is important here
  706.     if ((uint8_t)ch->n_volume > 64)
  707.         ch->n_volume = 64;
  708. }
  709.  
  710. static void PatternBreak(ptChannel_t *ch)
  711. {
  712.     PBreakPosition = (((ch->n_cmd & 0xF0) >> 4) * 10) + (ch->n_cmd & 0x0F);
  713.  
  714.     // unsigned comparison is important here
  715.     if ((uint8_t)PBreakPosition > 63)
  716.         PBreakPosition = 0;
  717.  
  718.     PosJumpAssert = true;
  719. }
  720.  
  721. static void SetSpeed(ptChannel_t *ch)
  722. {
  723.     if ((ch->n_cmd & 0xFF) > 0)
  724.     {
  725.         Counter = 0;
  726.  
  727.         if (TempoMode == VBLANK_TEMPO_MODE || (ch->n_cmd & 0xFF) < 32)
  728.             CurrSpeed = ch->n_cmd & 0xFF;
  729.         else
  730.             SetBPMFlag = ch->n_cmd & 0xFF; // CIA doesn't refresh its registers until the next interrupt, so change it later
  731.     }
  732. }
  733.  
  734. static void Arpeggio(ptChannel_t *ch)
  735. {
  736.     uint8_t dat;
  737.     const int16_t *arpPointer;
  738.  
  739.     dat = Counter % 3;
  740.     if (dat == 0)
  741.     {
  742.         paulaSetPeriod(ch->n_index, ch->n_period);
  743.     }
  744.     else
  745.     {
  746.              if (dat == 1) dat = (ch->n_cmd & 0xF0) >> 4;
  747.         else if (dat == 2) dat =  ch->n_cmd & 0x0F;
  748.  
  749.         arpPointer = &PeriodTable[ch->n_finetune * 37];
  750.         for (uint8_t i = 0; i < 37; i++)
  751.         {
  752.             if (ch->n_period >= arpPointer[i])
  753.             {
  754.                 paulaSetPeriod(ch->n_index, arpPointer[i+dat]);
  755.                 break;
  756.             }
  757.         }
  758.     }
  759. }
  760.  
  761. static void PortaUp(ptChannel_t *ch)
  762. {
  763.     ch->n_period -= (ch->n_cmd & 0xFF) & LowMask;
  764.     LowMask = 0xFF;
  765.  
  766.     if ((ch->n_period & 0xFFF) < 113)
  767.         ch->n_period = (ch->n_period & 0xF000) | 113;
  768.  
  769.     paulaSetPeriod(ch->n_index, ch->n_period & 0xFFF);
  770. }
  771.  
  772. static void PortaDown(ptChannel_t *ch)
  773. {
  774.     ch->n_period += (ch->n_cmd & 0xFF) & LowMask;
  775.     LowMask = 0xFF;
  776.  
  777.     if ((ch->n_period & 0xFFF) > 856)
  778.         ch->n_period = (ch->n_period & 0xF000) | 856;
  779.  
  780.     paulaSetPeriod(ch->n_index, ch->n_period & 0xFFF);
  781. }
  782.  
  783. static void FilterOnOff(ptChannel_t *ch)
  784. {
  785. #ifdef LED_FILTER
  786.     LEDStatus = !(ch->n_cmd & 1);
  787. #else
  788.     (void)ch;
  789. #endif
  790. }
  791.  
  792. static void FinePortaUp(ptChannel_t *ch)
  793. {
  794.     if (Counter == 0)
  795.     {
  796.         LowMask = 0xF;
  797.         PortaUp(ch);
  798.     }
  799. }
  800.  
  801. static void FinePortaDown(ptChannel_t *ch)
  802. {
  803.     if (Counter == 0)
  804.     {
  805.         LowMask = 0xF;
  806.         PortaDown(ch);
  807.     }
  808. }
  809.  
  810. static void SetTonePorta(ptChannel_t *ch)
  811. {
  812.     uint8_t i;
  813.     const int16_t *portaPointer;
  814.     uint16_t note;
  815.  
  816.     note = ch->n_note & 0xFFF;
  817.     portaPointer = &PeriodTable[ch->n_finetune * 37];
  818.  
  819.     i = 0;
  820.     while (true)
  821.     {
  822.         // portaPointer[36] = 0, so i=36 is safe
  823.         if (note >= portaPointer[i])
  824.             break;
  825.  
  826.         if (++i >= 37)
  827.         {
  828.             i = 35;
  829.             break;
  830.         }
  831.     }
  832.  
  833.     if ((ch->n_finetune & 8) && i > 0)
  834.         i--;
  835.  
  836.     ch->n_wantedperiod  = portaPointer[i];
  837.     ch->n_toneportdirec = 0;
  838.  
  839.          if (ch->n_period == ch->n_wantedperiod) ch->n_wantedperiod = 0;
  840.     else if (ch->n_period > ch->n_wantedperiod) ch->n_toneportdirec = 1;
  841. }
  842.  
  843. static void TonePortNoChange(ptChannel_t *ch)
  844. {
  845.     uint8_t i;
  846.     const int16_t *portaPointer;
  847.  
  848.     if (ch->n_wantedperiod <= 0)
  849.         return;
  850.  
  851.     if (ch->n_toneportdirec > 0)
  852.     {
  853.         ch->n_period -= ch->n_toneportspeed;
  854.         if (ch->n_period <= ch->n_wantedperiod)
  855.         {
  856.             ch->n_period = ch->n_wantedperiod;
  857.             ch->n_wantedperiod = 0;
  858.         }
  859.     }
  860.     else
  861.     {
  862.         ch->n_period += ch->n_toneportspeed;
  863.         if (ch->n_period >= ch->n_wantedperiod)
  864.         {
  865.             ch->n_period = ch->n_wantedperiod;
  866.             ch->n_wantedperiod = 0;
  867.         }
  868.     }
  869.  
  870.     if ((ch->n_glissfunk & 0xF) == 0)
  871.     {
  872.         paulaSetPeriod(ch->n_index, ch->n_period);
  873.     }
  874.     else
  875.     {
  876.         portaPointer = &PeriodTable[ch->n_finetune * 37];
  877.  
  878.         i = 0;
  879.         while (true)
  880.         {
  881.             // portaPointer[36] = 0, so i=36 is safe
  882.             if (ch->n_period >= portaPointer[i])
  883.                 break;
  884.  
  885.             if (++i >= 37)
  886.             {
  887.                 i = 35;
  888.                 break;
  889.             }
  890.         }
  891.  
  892.         paulaSetPeriod(ch->n_index, portaPointer[i]);
  893.     }
  894. }
  895.  
  896. static void TonePortamento(ptChannel_t *ch)
  897. {
  898.     if ((ch->n_cmd & 0xFF) > 0)
  899.     {
  900.         ch->n_toneportspeed = ch->n_cmd & 0xFF;
  901.         ch->n_cmd &= 0xFF00;
  902.     }
  903.  
  904.     TonePortNoChange(ch);
  905. }
  906.  
  907. static void VibratoNoChange(ptChannel_t *ch)
  908. {
  909.     uint8_t vibratoTemp;
  910.     int16_t vibratoData;
  911.  
  912.     vibratoTemp = (ch->n_vibratopos / 4) & 31;
  913.     vibratoData = ch->n_wavecontrol & 3;
  914.  
  915.     if (vibratoData == 0)
  916.     {
  917.         vibratoData = VibratoTable[vibratoTemp];
  918.     }
  919.     else
  920.     {
  921.         if (vibratoData == 1)
  922.         {
  923.             if (ch->n_vibratopos < 0)
  924.                 vibratoData = 255 - (vibratoTemp * 8);
  925.             else
  926.                 vibratoData = vibratoTemp * 8;
  927.         }
  928.         else
  929.         {
  930.             vibratoData = 255;
  931.         }
  932.     }
  933.  
  934.     vibratoData = (vibratoData * (ch->n_vibratocmd & 0xF)) / 128;
  935.  
  936.     if (ch->n_vibratopos < 0)
  937.         vibratoData = ch->n_period - vibratoData;
  938.     else
  939.         vibratoData = ch->n_period + vibratoData;
  940.  
  941.     paulaSetPeriod(ch->n_index, vibratoData);
  942.  
  943.     ch->n_vibratopos += ((ch->n_vibratocmd >> 4) * 4);
  944. }
  945.  
  946. static void Vibrato(ptChannel_t *ch)
  947. {
  948.     if ((ch->n_cmd & 0xFF) > 0)
  949.     {
  950.         if ((ch->n_cmd & 0x0F) > 0)
  951.             ch->n_vibratocmd = (ch->n_vibratocmd & 0xF0) | (ch->n_cmd & 0x0F);
  952.  
  953.         if ((ch->n_cmd & 0xF0) > 0)
  954.             ch->n_vibratocmd = (ch->n_cmd & 0xF0) | (ch->n_vibratocmd & 0x0F);
  955.     }
  956.  
  957.     VibratoNoChange(ch);
  958. }
  959.  
  960. static void TonePlusVolSlide(ptChannel_t *ch)
  961. {
  962.     TonePortNoChange(ch);
  963.     VolumeSlide(ch);
  964. }
  965.  
  966. static void VibratoPlusVolSlide(ptChannel_t *ch)
  967. {
  968.     VibratoNoChange(ch);
  969.     VolumeSlide(ch);
  970. }
  971.  
  972. static void Tremolo(ptChannel_t *ch)
  973. {
  974.     int8_t tremoloTemp;
  975.     int16_t tremoloData;
  976.  
  977.     if ((ch->n_cmd & 0xFF) > 0)
  978.     {
  979.         if ((ch->n_cmd & 0x0F) > 0)
  980.             ch->n_tremolocmd = (ch->n_tremolocmd & 0xF0) | (ch->n_cmd & 0x0F);
  981.  
  982.         if ((ch->n_cmd & 0xF0) > 0)
  983.             ch->n_tremolocmd = (ch->n_cmd & 0xF0) | (ch->n_tremolocmd & 0x0F);
  984.     }
  985.  
  986.     tremoloTemp = (ch->n_tremolopos / 4) & 31;
  987.     tremoloData = (ch->n_wavecontrol >> 4) & 3;
  988.  
  989.     if (tremoloData == 0)
  990.     {
  991.         tremoloData = VibratoTable[tremoloTemp];
  992.     }
  993.     else
  994.     {
  995.         if (tremoloData == 1)
  996.         {
  997.             if (ch->n_vibratopos < 0) // PT bug, should've been n_tremolopos
  998.                 tremoloData = 255 - (tremoloTemp * 8);
  999.             else
  1000.                 tremoloData = tremoloTemp * 8;
  1001.         }
  1002.         else
  1003.         {
  1004.             tremoloData = 255;
  1005.         }
  1006.     }
  1007.  
  1008.     tremoloData = (tremoloData * (ch->n_tremolocmd & 0xF)) / 64;
  1009.  
  1010.     if (ch->n_tremolopos < 0)
  1011.     {
  1012.         tremoloData = ch->n_volume - tremoloData;
  1013.         if (tremoloData < 0)
  1014.             tremoloData = 0;
  1015.     }
  1016.     else
  1017.     {
  1018.         tremoloData = ch->n_volume + tremoloData;
  1019.         if (tremoloData > 64)
  1020.             tremoloData = 64;
  1021.     }
  1022.  
  1023.     paulaSetVolume(ch->n_index, tremoloData);
  1024.  
  1025.     ch->n_tremolopos += ((ch->n_tremolocmd >> 4) * 4);
  1026. }
  1027.  
  1028. static void SampleOffset(ptChannel_t *ch)
  1029. {
  1030.     uint16_t newOffset;
  1031.  
  1032.     if ((ch->n_cmd & 0xFF) > 0)
  1033.         ch->n_sampleoffset = ch->n_cmd & 0xFF;
  1034.  
  1035.     newOffset = ch->n_sampleoffset * 128;
  1036.     if (ch->n_length <= 32767 && newOffset < ch->n_length)
  1037.     {
  1038.         ch->n_length -= newOffset;
  1039.         ch->n_start += newOffset * 2;
  1040.     }
  1041.     else
  1042.     {
  1043.         ch->n_length = 1; // this must NOT be set to 0! 1 is the correct value
  1044.     }
  1045. }
  1046.  
  1047. static void E_Commands(ptChannel_t *ch)
  1048. {
  1049.     switch ((ch->n_cmd & 0xF0) >> 4)
  1050.     {
  1051.         case 0x0: FilterOnOff(ch);       break;
  1052.         case 0x1: FinePortaUp(ch);       break;
  1053.         case 0x2: FinePortaDown(ch);     break;
  1054.         case 0x3: SetGlissControl(ch);   break;
  1055.         case 0x4: SetVibratoControl(ch); break;
  1056.         case 0x5: SetFineTune(ch);       break;
  1057.         case 0x6: JumpLoop(ch);          break;
  1058.         case 0x7: SetTremoloControl(ch); break;
  1059.         case 0x8: KarplusStrong(ch);     break;
  1060.         case 0x9: RetrigNote(ch);        break;
  1061.         case 0xA: VolumeFineUp(ch);      break;
  1062.         case 0xB: VolumeFineDown(ch);    break;
  1063.         case 0xC: NoteCut(ch);           break;
  1064.         case 0xD: NoteDelay(ch);         break;
  1065.         case 0xE: PatternDelay(ch);      break;
  1066.         case 0xF: FunkIt(ch);            break;
  1067.         default: break;
  1068.     }
  1069. }
  1070.  
  1071. static void CheckMoreEffects(ptChannel_t *ch)
  1072. {
  1073.     switch ((ch->n_cmd & 0xF00) >> 8)
  1074.     {
  1075.         case 0x9: SampleOffset(ch); break;
  1076.         case 0xB: PositionJump(ch); break;
  1077.         case 0xD: PatternBreak(ch); break;
  1078.         case 0xE: E_Commands(ch);   break;
  1079.         case 0xF: SetSpeed(ch);     break;
  1080.         case 0xC: VolumeChange(ch); break;
  1081.  
  1082.         default: paulaSetPeriod(ch->n_index, ch->n_period); break;
  1083.     }
  1084. }
  1085.  
  1086. static void CheckEffects(ptChannel_t *ch)
  1087. {
  1088.     uint8_t effect;
  1089.  
  1090.     UpdateFunk(ch);
  1091.  
  1092.     effect = (ch->n_cmd & 0xF00) >> 8;
  1093.     if ((ch->n_cmd & 0xFFF) > 0)
  1094.     {
  1095.         switch (effect)
  1096.         {
  1097.             case 0x0: Arpeggio(ch);            break;
  1098.             case 0x1: PortaUp(ch);             break;
  1099.             case 0x2: PortaDown(ch);           break;
  1100.             case 0x3: TonePortamento(ch);      break;
  1101.             case 0x4: Vibrato(ch);             break;
  1102.             case 0x5: TonePlusVolSlide(ch);    break;
  1103.             case 0x6: VibratoPlusVolSlide(ch); break;
  1104.             case 0xE: E_Commands(ch);          break;
  1105.             case 0x7:
  1106.                 paulaSetPeriod(ch->n_index, ch->n_period);
  1107.                 Tremolo(ch);
  1108.             break;
  1109.             case 0xA:
  1110.                 paulaSetPeriod(ch->n_index, ch->n_period);
  1111.                 VolumeSlide(ch);
  1112.             break;
  1113.  
  1114.             default: paulaSetPeriod(ch->n_index, ch->n_period); break;
  1115.         }
  1116.     }
  1117.  
  1118.     if (effect != 0x7)
  1119.         paulaSetVolume(ch->n_index, ch->n_volume);
  1120. }
  1121.  
  1122. static void SetPeriod(ptChannel_t *ch)
  1123. {
  1124.     uint8_t i;
  1125.     uint16_t note;
  1126.  
  1127.     note = ch->n_note & 0xFFF;
  1128.     for (i = 0; i < 37; i++)
  1129.     {
  1130.         // PeriodTable[36] = 0, so i=36 is safe
  1131.         if (note >= PeriodTable[i])
  1132.             break;
  1133.     }
  1134.  
  1135.     // BUG: yes it's 'safe' if i=37 because of padding at the end of period table
  1136.     ch->n_period = PeriodTable[(ch->n_finetune * 37) + i];
  1137.  
  1138.     if ((ch->n_cmd & 0xFF0) != 0xED0) // no note delay
  1139.     {
  1140.         if ((ch->n_wavecontrol & 0x04) == 0) ch->n_vibratopos = 0;
  1141.         if ((ch->n_wavecontrol & 0x40) == 0) ch->n_tremolopos = 0;
  1142.  
  1143.         paulaSetLength(ch->n_index, ch->n_length);
  1144.         paulaSetData(ch->n_index, ch->n_start);
  1145.  
  1146.         if (ch->n_start == NULL)
  1147.         {
  1148.             ch->n_loopstart = NULL;
  1149.             paulaSetLength(ch->n_index, 1);
  1150.             ch->n_replen = 1;
  1151.         }
  1152.  
  1153.         paulaSetPeriod(ch->n_index, ch->n_period);
  1154.         paulaStartDMA(ch->n_index);
  1155.     }
  1156.  
  1157.     CheckMoreEffects(ch);
  1158. }
  1159.  
  1160. static void PlayVoice(ptChannel_t *ch)
  1161. {
  1162.     uint8_t *dataPtr, sample, cmd;
  1163.     uint16_t sampleOffset, repeat;
  1164.  
  1165.     if (ch->n_note == 0 && ch->n_cmd == 0)
  1166.         paulaSetPeriod(ch->n_index, ch->n_period);
  1167.  
  1168.     dataPtr = &SongDataPtr[PattPosOff];
  1169.  
  1170.     ch->n_note = (dataPtr[0] << 8) | dataPtr[1];
  1171.     ch->n_cmd  = (dataPtr[2] << 8) | dataPtr[3];
  1172.  
  1173.     sample = (dataPtr[0] & 0xF0) | (dataPtr[2] >> 4);
  1174.     if (sample >= 1 && sample <= 31) // SAFETY BUG FIX: don't handle sample-numbers >31
  1175.     {
  1176.         sample--;
  1177.         sampleOffset = 42 + (30 * sample);
  1178.  
  1179.         ch->n_start = SampleStarts[sample];
  1180.         ch->n_finetune = SongDataPtr[sampleOffset + 2] & 0xF; // SAFETY BUG FIX: mask finetune
  1181.         ch->n_volume = SongDataPtr[sampleOffset + 3];
  1182.         ch->n_length = *PTR2WORD(&SongDataPtr[sampleOffset + 0]);
  1183.         ch->n_replen = *PTR2WORD(&SongDataPtr[sampleOffset + 6]);
  1184.  
  1185.         repeat = *PTR2WORD(&SongDataPtr[sampleOffset + 4]);
  1186.         if (repeat > 0)
  1187.         {
  1188.             ch->n_loopstart = ch->n_start + (repeat * 2);
  1189.             ch->n_wavestart = ch->n_loopstart;
  1190.             ch->n_length = repeat + ch->n_replen;
  1191.         }
  1192.         else
  1193.         {
  1194.             ch->n_loopstart = ch->n_start;
  1195.             ch->n_wavestart = ch->n_start;
  1196.         }
  1197.  
  1198.         // non-PT2 quirk
  1199.         if (ch->n_length == 0)
  1200.             ch->n_loopstart = ch->n_wavestart = &SampleData[EmptySampleOffset]; // dummy sample
  1201.     }
  1202.  
  1203.     if ((ch->n_note & 0xFFF) > 0)
  1204.     {
  1205.         if ((ch->n_cmd & 0xFF0) == 0xE50) // set finetune
  1206.         {
  1207.             SetFineTune(ch);
  1208.             SetPeriod(ch);
  1209.         }
  1210.         else
  1211.         {
  1212.             cmd = (ch->n_cmd & 0xF00) >> 8;
  1213.             if (cmd == 3 || cmd == 5)
  1214.             {
  1215.                 SetTonePorta(ch);
  1216.                 CheckMoreEffects(ch);
  1217.             }
  1218.             else if (cmd == 9)
  1219.             {
  1220.                 CheckMoreEffects(ch);
  1221.                 SetPeriod(ch);
  1222.             }
  1223.             else
  1224.             {
  1225.                 SetPeriod(ch);
  1226.             }
  1227.         }
  1228.     }
  1229.     else
  1230.     {
  1231.         CheckMoreEffects(ch);
  1232.     }
  1233.  
  1234.     PattPosOff += 4;
  1235. }
  1236.  
  1237. static void NextPosition(void)
  1238. {
  1239.     PatternPos = PBreakPosition * 16;
  1240.     PBreakPosition = 0;
  1241.     PosJumpAssert = false;
  1242.  
  1243.     SongPosition = (SongPosition + 1) & 0x7F;
  1244.     if (SongPosition >= SongDataPtr[950])
  1245.         SongPosition = 0;
  1246. }
  1247.  
  1248. static void tickReplayer(void)
  1249. {
  1250.     uint8_t i;
  1251.  
  1252.     if (!SongPlaying)
  1253.         return;
  1254.  
  1255.     // PT quirk: CIA refreshes its timer values on the next interrupt, so do the real tempo change here
  1256.     if (SetBPMFlag != 0)
  1257.     {
  1258.         SetReplayerBPM(SetBPMFlag);
  1259.         SetBPMFlag = 0;
  1260.     }
  1261.  
  1262.     Counter++;
  1263.     if (Counter >= CurrSpeed)
  1264.     {
  1265.         Counter = 0;
  1266.  
  1267.         if (PattDelTime2 == 0)
  1268.         {
  1269.             PattPosOff = (1084 + (SongDataPtr[952 + SongPosition] * 1024)) + PatternPos;
  1270.  
  1271.             for (i = 0; i < AMIGA_VOICES; i++)
  1272.             {
  1273.                 PlayVoice(&ChanTemp[i]);
  1274.                 paulaSetVolume(i, ChanTemp[i].n_volume);
  1275.  
  1276.                 // these take effect after the current cycle is done
  1277.                 paulaSetData(i, ChanTemp[i].n_loopstart);
  1278.                 paulaSetLength(i, ChanTemp[i].n_replen);
  1279.             }
  1280.         }
  1281.         else
  1282.         {
  1283.             for (i = 0; i < AMIGA_VOICES; i++)
  1284.                 CheckEffects(&ChanTemp[i]);
  1285.         }
  1286.  
  1287.         PatternPos += 16;
  1288.  
  1289.         if (PattDelTime > 0)
  1290.         {
  1291.             PattDelTime2 = PattDelTime;
  1292.             PattDelTime = 0;
  1293.         }
  1294.  
  1295.         if (PattDelTime2 > 0)
  1296.         {
  1297.             if (--PattDelTime2 > 0)
  1298.                 PatternPos -= 16;
  1299.         }
  1300.  
  1301.         if (PBreakFlag)
  1302.         {
  1303.             PBreakFlag = false;
  1304.  
  1305.             PatternPos = PBreakPosition * 16;
  1306.             PBreakPosition = 0;
  1307.         }
  1308.  
  1309.         if (PatternPos >= 1024 || PosJumpAssert)
  1310.             NextPosition();
  1311.     }
  1312.     else
  1313.     {
  1314.         for (i = 0; i < AMIGA_VOICES; i++)
  1315.             CheckEffects(&ChanTemp[i]);
  1316.  
  1317.         if (PosJumpAssert)
  1318.             NextPosition();
  1319.     }
  1320. }
  1321.  
  1322. static int8_t moduleInit(const uint8_t *moduleData, uint32_t dataLength)
  1323. {
  1324.     int8_t pattNum, *songSampleData;
  1325.     uint8_t i;
  1326.     uint16_t *p;
  1327.     int32_t loopOverflowVal, totalSampleSize, sampleDataOffset;
  1328.     ptChannel_t *ch;
  1329.  
  1330.     if (SampleData != NULL)
  1331.     {
  1332.         free(SampleData);
  1333.         SampleData = NULL;
  1334.     }
  1335.  
  1336.     for (i = 0; i < AMIGA_VOICES; i++)
  1337.     {
  1338.         ch = &ChanTemp[i];
  1339.  
  1340.         ch->n_index = i;
  1341.         ch->n_start = NULL;
  1342.         ch->n_wavestart = NULL;
  1343.         ch->n_loopstart = NULL;
  1344.     }
  1345.  
  1346.     SongDataPtr = (uint8_t *)malloc(dataLength);
  1347.     if (SongDataPtr == NULL)
  1348.         return false;
  1349.  
  1350.     memcpy(SongDataPtr, moduleData, dataLength);
  1351.  
  1352.     memcpy(songName, SongDataPtr, 20);
  1353.     songName[20] = '\0';
  1354.  
  1355.     pattNum = 0;
  1356.     for (i = 0; i < 128; i++)
  1357.     {
  1358.         if (SongDataPtr[952+i] > pattNum)
  1359.             pattNum = SongDataPtr[952+i];
  1360.     }
  1361.     pattNum++;
  1362.  
  1363.     // first count total sample size to allocate
  1364.     totalSampleSize = 0;
  1365.     for (i = 0; i < 31; i++)
  1366.     {
  1367.         p = PTR2WORD(&SongDataPtr[42 + (i * 30)]);
  1368.         totalSampleSize += (SWAP16(p[0]) * 2);
  1369.     }
  1370.  
  1371.     EmptySampleOffset = totalSampleSize;
  1372.  
  1373.     SampleData = (int8_t *)malloc(totalSampleSize + MAX_SAMPLE_LEN);
  1374.     if (SampleData == NULL)
  1375.         return false;
  1376.  
  1377.     // wipe reserved sample data area
  1378.     memset(&SampleData[EmptySampleOffset], 0, MAX_SAMPLE_LEN);
  1379.  
  1380.     // setup and load samples
  1381.     songSampleData = (int8_t *)&SongDataPtr[1084 + (pattNum * 1024)];
  1382.  
  1383.     sampleDataOffset = 0;
  1384.     for (i = 0; i < 31; i++)
  1385.     {
  1386.         p = PTR2WORD(&SongDataPtr[42 + (i * 30)]);
  1387.  
  1388.         // swap bytes in words (Amiga word -> Intel word)
  1389.         p[0] = SWAP16(p[0]); // n_length
  1390.         p[2] = SWAP16(p[2]); // n_repeat
  1391.         p[3] = SWAP16(p[3]); // n_replen
  1392.  
  1393.         // set up sample pointer and load sample
  1394.         if (p[0] == 0)
  1395.         {
  1396.             SampleStarts[i] = &SampleData[EmptySampleOffset];
  1397.         }
  1398.         else
  1399.         {
  1400.             SampleStarts[i] = &SampleData[sampleDataOffset];
  1401.             memcpy(SampleStarts[i], songSampleData, p[0] * 2);
  1402.  
  1403.             sampleDataOffset += p[0] * 2;
  1404.             songSampleData += p[0] * 2;
  1405.         }
  1406.  
  1407.         if (p[3] == 0)
  1408.             p[3] = 1; // fix illegal loop length (f.ex. from "Fasttracker II" .MODs)
  1409.  
  1410.         // adjust sample length if loop was overflowing
  1411.         if (p[3] > 1 && p[2]+p[3] > p[0])
  1412.         {
  1413.             loopOverflowVal = (p[2] + p[3]) - p[0];
  1414.             if ((p[0] + loopOverflowVal) <= MAX_SAMPLE_LEN/2)
  1415.             {
  1416.                 p[0] += (uint16_t)loopOverflowVal;
  1417.             }
  1418.             else
  1419.             {
  1420.                 p[2] = 0;
  1421.                 p[3] = 2;
  1422.             }
  1423.         }
  1424.  
  1425.         if (p[0] >= 1 && p[2]+p[3] <= 1)
  1426.         {
  1427.             // if no loop, zero first two samples of data to prevent "beep"
  1428.             SampleStarts[i][0] = 0;
  1429.             SampleStarts[i][1] = 0;
  1430.         }
  1431.     }
  1432.  
  1433.     return true;
  1434. }
  1435.  
  1436. // MIXER RELATED CODE
  1437.  
  1438. // these are used to create equal powered stereo separation
  1439. static double sinApx(double fX)
  1440. {
  1441.     fX = fX * (2.0 - fX);
  1442.     return fX * 1.09742972 + fX * fX * 0.31678383;
  1443. }
  1444.  
  1445. static double cosApx(double fX)
  1446. {
  1447.     fX = (1.0 - fX) * (1.0 + fX);
  1448.     return fX * 1.09742972 + fX * fX * 0.31678383;
  1449. }
  1450. // -------------------------------------------------
  1451.  
  1452. static void calculatePans(int8_t stereoSeparation)
  1453. {
  1454.     uint8_t scaledPanPos;
  1455.     double p;
  1456.  
  1457.     if (stereoSeparation > 100)
  1458.         stereoSeparation = 100;
  1459.  
  1460.     scaledPanPos = (stereoSeparation * 128) / 100;
  1461.  
  1462.     p = (128 - scaledPanPos) * (1.0 / 256.0);
  1463.     paula[0].dPanL = cosApx(p);
  1464.     paula[0].dPanR = sinApx(p);
  1465.     paula[3].dPanL = cosApx(p);
  1466.     paula[3].dPanR = sinApx(p);
  1467.  
  1468.     p = (128 + scaledPanPos) * (1.0 / 256.0);
  1469.     paula[1].dPanL = cosApx(p);
  1470.     paula[1].dPanR = sinApx(p);
  1471.     paula[2].dPanL = cosApx(p);
  1472.     paula[2].dPanR = sinApx(p);
  1473. }
  1474.  
  1475. static void resetDitherSeed(void)
  1476. {
  1477.     randSeed = INITIAL_DITHER_SEED;
  1478. }
  1479.  
  1480. // Delphi/Pascal LCG Random() (without limit). Suitable for 32-bit random numbers
  1481. static inline int32_t random32(void)
  1482. {
  1483.     randSeed = randSeed * 134775813 + 1;
  1484.     return randSeed;
  1485. }
  1486.  
  1487. static void mixAudio(int16_t *stream, int32_t sampleBlockLength)
  1488. {
  1489.     int32_t i, j, smp32;
  1490.     double dDither, dSample, dVolume, dOut[2];
  1491.     paulaVoice_t *v;
  1492. #ifdef USE_BLEP
  1493.     blep_t *bSmp, *bVol;
  1494. #endif
  1495.  
  1496.     memset(dMixerBufferL, 0, sampleBlockLength * sizeof (double));
  1497.     memset(dMixerBufferR, 0, sampleBlockLength * sizeof (double));
  1498.  
  1499.     if (musicPaused)
  1500.     {
  1501.         memset(stream, 0, sampleBlockLength * (sizeof (int16_t) * 2));
  1502.         return;
  1503.     }
  1504.  
  1505.     for (i = 0; i < AMIGA_VOICES; i++)
  1506.     {
  1507.         v = &paula[i];
  1508.         if (!v->active)
  1509.             continue;
  1510.  
  1511. #ifdef USE_BLEP
  1512.         bSmp = &blep[i];
  1513.         bVol = &blepVol[i];
  1514. #endif
  1515.         for (j = 0; j < sampleBlockLength; j++)
  1516.         {
  1517.             dSample = v->data[v->pos] * (1.0 / 128.0);
  1518.             dVolume = v->dVolume;
  1519.  
  1520. #ifdef USE_BLEP
  1521.             if (dSample != bSmp->dLastValue)
  1522.             {
  1523.                 if (v->dLastDelta > 0.0 && v->dLastDelta > v->dLastPhase)
  1524.                     blepAdd(bSmp, v->dLastPhase / v->dLastDelta, bSmp->dLastValue - dSample);
  1525.  
  1526.                 bSmp->dLastValue = dSample;
  1527.             }
  1528.  
  1529.             if (dVolume != bVol->dLastValue)
  1530.             {
  1531.                 blepAdd(bVol, 0.0, bVol->dLastValue - dVolume);
  1532.                 bVol->dLastValue = dVolume;
  1533.             }
  1534.  
  1535.             if (bSmp->samplesLeft > 0) dSample += blepRun(bSmp);
  1536.             if (bVol->samplesLeft > 0) dVolume += blepRun(bVol);
  1537. #endif
  1538.             dSample *= dVolume;
  1539.  
  1540.             dMixerBufferL[j] += dSample * v->dPanL;
  1541.             dMixerBufferR[j] += dSample * v->dPanR;
  1542.  
  1543.             v->dPhase += v->dDelta;
  1544.             if (v->dPhase >= 1.0)
  1545.             {
  1546.                 v->dPhase -= 1.0;
  1547. #ifdef USE_BLEP
  1548.                 v->dLastPhase = v->dPhase;
  1549.                 v->dLastDelta = v->dDelta;
  1550. #endif
  1551.                 if (++v->pos >= v->length)
  1552.                 {
  1553.                     v->pos = 0;
  1554.  
  1555.                     // re-fetch Paula register values now
  1556.                     v->length = v->newLength;
  1557.                     v->data = v->newData;
  1558.                 }
  1559.             }
  1560.         }
  1561.     }
  1562.  
  1563.     for (i = 0; i < sampleBlockLength; i++)
  1564.     {
  1565.         dOut[0] = dMixerBufferL[i];
  1566.         dOut[1] = dMixerBufferR[i];
  1567.  
  1568. #ifdef USE_LOWPASS
  1569.         lossyIntegrator(&filterLo, dOut, dOut);
  1570. #endif
  1571.  
  1572. #ifdef LED_FILTER
  1573.         if (LEDStatus)
  1574.             lossyIntegratorLED(filterLEDC, &filterLED, dOut, dOut);
  1575. #endif
  1576.  
  1577. #ifdef USE_HIGHPASS
  1578.         lossyIntegratorHighPass(&filterHi, dOut, dOut);
  1579. #endif
  1580.  
  1581.         // normalize and flip phase (A500/A1200 has an inverted audio signal)
  1582.         dOut[0] *= -((INT16_MAX+1.0) / AMIGA_VOICES);
  1583.         dOut[1] *= -((INT16_MAX+1.0) / AMIGA_VOICES);
  1584.  
  1585.         // apply 0.5-bit dither
  1586.         dDither = random32() * (0.5 / (INT32_MAX+1.0)); // -0.5..0.5
  1587.         dOut[0] += dDither;
  1588.         dDither = random32() * (0.5 / (INT32_MAX+1.0));
  1589.         dOut[1] += dDither;
  1590.  
  1591.         smp32 = (int32_t)dOut[0];
  1592.         CLAMP16(smp32);
  1593.         *stream++ = (int16_t)smp32;
  1594.  
  1595.         smp32 = (int32_t)dOut[1];
  1596.         CLAMP16(smp32);
  1597.         *stream++ = (int16_t)smp32;
  1598.     }
  1599. }
  1600.  
  1601. void pt2play_PauseSong(bool flag)
  1602. {
  1603.     musicPaused = flag;
  1604. }
  1605.  
  1606. void pt2play_TogglePause(void)
  1607. {
  1608.     musicPaused ^= 1;
  1609. }
  1610.  
  1611. void pt2play_Close(void)
  1612. {
  1613.     closeMixer();
  1614.  
  1615.     if (SampleData != NULL)
  1616.     {
  1617.         free(SampleData);
  1618.         SampleData = NULL;
  1619.     }
  1620.  
  1621.     if (dMixerBufferL != NULL)
  1622.     {
  1623.         free(dMixerBufferL);
  1624.         dMixerBufferL = NULL;
  1625.     }
  1626.  
  1627.     if (dMixerBufferR != NULL)
  1628.     {
  1629.         free(dMixerBufferR);
  1630.         dMixerBufferR = NULL;
  1631.     }
  1632.  
  1633.     if (SongDataPtr != NULL)
  1634.     {
  1635.         free(SongDataPtr);
  1636.         SongDataPtr = NULL;
  1637.     }
  1638. }
  1639.  
  1640. bool pt2play_PlaySong(const uint8_t *moduleData, uint32_t dataLength, int8_t tempoMode, uint32_t audioFreq)
  1641. {
  1642.     if (audioFreq == 0)
  1643.         audioFreq = 44100;
  1644.  
  1645.     musicPaused = true;
  1646.  
  1647.     pt2play_Close();
  1648.     memset(songName, 0, sizeof (songName));
  1649.  
  1650.     oldPeriod = 0;
  1651.     oldVoiceDelta = 0.0;
  1652.     sampleCounter = 0;
  1653.     SongPlaying = false;
  1654.  
  1655.     dMixerBufferL = (double *)malloc(MIX_BUF_SAMPLES * sizeof (double));
  1656.     dMixerBufferR = (double *)malloc(MIX_BUF_SAMPLES * sizeof (double));
  1657.  
  1658.     if (dMixerBufferL == NULL || dMixerBufferR == NULL)
  1659.     {
  1660.         pt2play_Close();
  1661.         return false;
  1662.     }
  1663.  
  1664.     // rates below 32kHz will mess up the BLEP synthesis
  1665.     audioFreq = CLAMP(audioFreq, 32000, 96000);
  1666.  
  1667.     audioRate = audioFreq;
  1668.     dAudioRate = (double)audioRate;
  1669.     dPeriodToDeltaDiv = (double)PAULA_PAL_CLK / dAudioRate;
  1670.     soundBufferSize = MIX_BUF_SAMPLES;
  1671.  
  1672.     SetReplayerBPM(125);
  1673.  
  1674. #ifdef USE_LOWPASS
  1675.     // Amiga 500 rev6 RC low-pass filter (~4420.97Hz, 580Hz added to better match A500)
  1676.     calcCoeffLossyIntegrator(dAudioRate, 4420.97 + 580.0, &filterLo);
  1677. #endif
  1678.  
  1679. #ifdef LED_FILTER
  1680.     // Amiga Sallen-Key "LED" filter (~3090.5Hz, 300Hz subtracted to better match A500/A1200)
  1681.     calcCoeffLED(dAudioRate, 3090.53 - 300.0, &filterLEDC);
  1682. #endif
  1683.  
  1684. #ifdef USE_HIGHPASS
  1685.     // Amiga RC high-pass filter (~5.20Hz, 1.5Hz added to better match A500/A1200)
  1686.     calcCoeffLossyIntegrator(dAudioRate, 5.20 + 1.5, &filterHi);
  1687. #endif
  1688.  
  1689.     if (!moduleInit(moduleData, dataLength))
  1690.     {
  1691.         pt2play_Close();
  1692.         return false;
  1693.     }
  1694.  
  1695.     memset(paula, 0, sizeof (paula));
  1696.     calculatePans(stereoSep);
  1697.  
  1698. #ifdef USE_BLEP
  1699.     memset(blep, 0, sizeof (blep));
  1700.     memset(blepVol, 0, sizeof (blepVol));
  1701. #endif
  1702.  
  1703. #ifdef USE_LOWPASS
  1704.     clearLossyIntegrator(&filterLo);
  1705. #endif
  1706.  
  1707. #ifdef LED_FILTER
  1708.     clearLEDFilter(&filterLED);
  1709. #endif
  1710.  
  1711. #ifdef USE_HIGHPASS
  1712.     clearLossyIntegrator(&filterHi);
  1713. #endif
  1714.  
  1715.     resetDitherSeed();
  1716.  
  1717.     CurrSpeed = 6;
  1718.     Counter = 0;
  1719.     SongPosition = 0;
  1720.     PatternPos = 0;
  1721.     PattDelTime = 0;
  1722.     PattDelTime2 = 0;
  1723.     PBreakPosition = 0;
  1724.     PosJumpAssert = false;
  1725.     PBreakFlag = false;
  1726.     LowMask = 0xFF;
  1727.     TempoMode = tempoMode ? VBLANK_TEMPO_MODE : CIA_TEMPO_MODE;
  1728.     SongPlaying = true;
  1729.     musicPaused = false;
  1730.  
  1731. #ifdef LED_FILTER
  1732.     LEDStatus = 0;
  1733. #endif
  1734.  
  1735.     if (!openMixer(audioRate))
  1736.     {
  1737.         pt2play_Close();
  1738.         return false;
  1739.     }
  1740.  
  1741.     musicPaused = false;
  1742.     return true;
  1743. }
  1744.  
  1745. void pt2play_SetStereoSep(uint8_t percentage)
  1746. {
  1747.     stereoSep = percentage;
  1748.     if (stereoSep > 100)
  1749.         stereoSep = 100;
  1750.  
  1751.     calculatePans(stereoSep);
  1752. }
  1753.  
  1754. char *pt2play_GetSongName(void)
  1755. {
  1756.     return songName;
  1757. }
  1758.  
  1759. uint32_t pt2play_GetMixerTicks(void)
  1760. {
  1761.     if (audioRate < 1000)
  1762.         return 0;
  1763.  
  1764.     return sampleCounter / (audioRate / 1000);
  1765. }
  1766.  
  1767. static void pt2play_FillAudioBuffer(int16_t *buffer, int32_t samples)
  1768. {
  1769.     int32_t a, b;
  1770.  
  1771.     a = samples;
  1772.     while (a > 0)
  1773.     {
  1774.         if (samplesPerTickLeft == 0)
  1775.         {
  1776.             if (!musicPaused)
  1777.                 tickReplayer();
  1778.  
  1779.             samplesPerTickLeft = samplesPerTick;
  1780.         }
  1781.  
  1782.         b = a;
  1783.         if (b > samplesPerTickLeft)
  1784.             b = samplesPerTickLeft;
  1785.  
  1786.         mixAudio(buffer, b);
  1787.         buffer += (uint32_t)b * 2;
  1788.  
  1789.         a -= b;
  1790.         samplesPerTickLeft -= b;
  1791.     }
  1792.  
  1793.     sampleCounter += samples;
  1794. }
  1795.  
  1796. // the following must be changed if you want to use another audio API than WinMM
  1797.  
  1798. #ifndef WIN32_LEAN_AND_MEAN
  1799. #define WIN32_LEAN_AND_MEAN
  1800. #endif
  1801.  
  1802. #include <windows.h>
  1803. #include <mmsystem.h>
  1804.  
  1805. #define MIX_BUF_NUM 2
  1806.  
  1807. static volatile BOOL audioRunningFlag;
  1808. static uint8_t currBuffer;
  1809. static int16_t *mixBuffer[MIX_BUF_NUM];
  1810. static HANDLE hThread, hAudioSem;
  1811. static WAVEHDR waveBlocks[MIX_BUF_NUM];
  1812. static HWAVEOUT hWave;
  1813.  
  1814. static DWORD WINAPI mixThread(LPVOID lpParam)
  1815. {
  1816.     WAVEHDR *waveBlock;
  1817.  
  1818.     (void)lpParam;
  1819.  
  1820.     SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
  1821.  
  1822.     while (audioRunningFlag)
  1823.     {
  1824.         waveBlock = &waveBlocks[currBuffer];
  1825.         pt2play_FillAudioBuffer((int16_t *)waveBlock->lpData, MIX_BUF_SAMPLES);
  1826.         waveOutWrite(hWave, waveBlock, sizeof (WAVEHDR));
  1827.         currBuffer = (currBuffer + 1) % MIX_BUF_NUM;
  1828.  
  1829.         // wait for buffer fill request
  1830.         WaitForSingleObject(hAudioSem, INFINITE);
  1831.     }
  1832.  
  1833.     return 0;
  1834. }
  1835.  
  1836. static void CALLBACK waveProc(HWAVEOUT hWaveOut, UINT uMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2)
  1837. {
  1838.     (void)hWaveOut;
  1839.     (void)uMsg;
  1840.     (void)dwInstance;
  1841.     (void)dwParam1;
  1842.     (void)dwParam2;
  1843.  
  1844.     if (uMsg == WOM_DONE)
  1845.         ReleaseSemaphore(hAudioSem, 1, NULL);
  1846. }
  1847.  
  1848. static void closeMixer(void)
  1849. {
  1850.     int32_t i;
  1851.  
  1852.     audioRunningFlag = false; // make thread end when it's done
  1853.  
  1854.     if (hAudioSem != NULL)
  1855.         ReleaseSemaphore(hAudioSem, 1, NULL);
  1856.  
  1857.     if (hThread != NULL)
  1858.     {
  1859.         WaitForSingleObject(hThread, INFINITE);
  1860.         CloseHandle(hThread);
  1861.         hThread = NULL;
  1862.     }
  1863.  
  1864.     if (hAudioSem != NULL)
  1865.     {
  1866.         CloseHandle(hAudioSem);
  1867.         hAudioSem = NULL;
  1868.     }
  1869.  
  1870.     if (hWave != NULL)
  1871.     {
  1872.         waveOutReset(hWave);
  1873.  
  1874.         for (i = 0; i < MIX_BUF_NUM; i++)
  1875.         {
  1876.             if (waveBlocks[i].dwUser != 0xFFFF)
  1877.                 waveOutUnprepareHeader(hWave, &waveBlocks[i], sizeof (WAVEHDR));
  1878.         }
  1879.  
  1880.         waveOutClose(hWave);
  1881.         hWave = NULL;
  1882.     }
  1883.  
  1884.     for (i = 0; i < MIX_BUF_NUM; i++)
  1885.     {
  1886.         if (mixBuffer[i] != NULL)
  1887.         {
  1888.             free(mixBuffer[i]);
  1889.             mixBuffer[i] = NULL;
  1890.         }
  1891.     }
  1892. }
  1893.  
  1894. static uint16_t bpm2SmpsPerTick(uint32_t bpm, uint32_t audioFreq)
  1895. {
  1896.     uint32_t ciaVal;
  1897.     double dFreqMul;
  1898.  
  1899.     if (bpm == 0)
  1900.         return 0;
  1901.  
  1902.     ciaVal = (uint32_t)(1773447 / bpm); // yes, PT truncates here
  1903.     dFreqMul = ciaVal * (1.0 / CIA_PAL_CLK);
  1904.  
  1905.     return (uint16_t)((audioFreq * dFreqMul) + 0.5);
  1906. }
  1907.  
  1908. static bool openMixer(uint32_t audioFreq)
  1909. {
  1910.     int32_t i;
  1911.     DWORD threadID;
  1912.     WAVEFORMATEX wfx;
  1913.  
  1914.     // don't unprepare headers on error
  1915.     for (i = 0; i < MIX_BUF_NUM; i++)
  1916.         waveBlocks[i].dwUser = 0xFFFF;
  1917.  
  1918.     closeMixer();
  1919.  
  1920.     ZeroMemory(&wfx, sizeof (wfx));
  1921.     wfx.nSamplesPerSec = audioFreq;
  1922.     wfx.wBitsPerSample = 16;
  1923.     wfx.nChannels = 2;
  1924.     wfx.wFormatTag = WAVE_FORMAT_PCM;
  1925.     wfx.nBlockAlign = wfx.nChannels * (wfx.wBitsPerSample / 8);
  1926.     wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
  1927.  
  1928.     samplesPerTickLeft = 0;
  1929.     currBuffer = 0;
  1930.  
  1931.     if (waveOutOpen(&hWave, WAVE_MAPPER, &wfx, (DWORD_PTR)&waveProc, 0, CALLBACK_FUNCTION) != MMSYSERR_NOERROR)
  1932.         goto omError;
  1933.  
  1934.     // create semaphore for buffer fill requests
  1935.     hAudioSem = CreateSemaphore(NULL, MIX_BUF_NUM - 1, MIX_BUF_NUM, NULL);
  1936.     if (hAudioSem == NULL)
  1937.         goto omError;
  1938.  
  1939.     // allocate WinMM mix buffers
  1940.     for (i = 0; i < MIX_BUF_NUM; i++)
  1941.     {
  1942.         mixBuffer[i] = (int16_t *)calloc(MIX_BUF_SAMPLES, wfx.nBlockAlign);
  1943.         if (mixBuffer[i] == NULL)
  1944.             goto omError;
  1945.     }
  1946.  
  1947.     // initialize WinMM mix headers
  1948.     memset(waveBlocks, 0, sizeof (waveBlocks));
  1949.     for (i = 0; i < MIX_BUF_NUM; i++)
  1950.     {
  1951.         waveBlocks[i].lpData = (LPSTR)mixBuffer[i];
  1952.         waveBlocks[i].dwBufferLength = MIX_BUF_SAMPLES * wfx.nBlockAlign;
  1953.         waveBlocks[i].dwFlags = WHDR_DONE;
  1954.  
  1955.         if (waveOutPrepareHeader(hWave, &waveBlocks[i], sizeof (WAVEHDR)) != MMSYSERR_NOERROR)
  1956.             goto omError;
  1957.     }
  1958.  
  1959.     // create main mixer thread
  1960.     audioRunningFlag = true;
  1961.     hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)mixThread, NULL, 0, &threadID);
  1962.     if (hThread == NULL)
  1963.         goto omError;
  1964.  
  1965.     for (i = 32; i <= 255; i++)
  1966.         bpmTab[i-32] = bpm2SmpsPerTick(i, audioFreq);
  1967.  
  1968.     return TRUE;
  1969.  
  1970. omError:
  1971.     closeMixer();
  1972.     return FALSE;
  1973. }
  1974. // ---------------------------------------------------------------------------
  1975.  
  1976. // END OF FILE
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