daily pastebin goal
23%
SHARE
TWEET

pt2play v1.55

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