Need a unique gift idea?
A Pastebin account makes a great Christmas gift
SHARE
TWEET

pt2play v1.53

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