SHARE
TWEET

pt2play v1.56

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