G2A Many GEOs
SHARE
TWEET

fc14play v1.29

8bitbubsy Nov 17th, 2015 (edited) 982 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /*
  2. ** fc14play v1.29 - 17th of February 2019 - https://16-bits.org
  3. ** ============================================================
  4. **                 - NOT BIG ENDIAN SAFE! -
  5. **
  6. ** Very accurate C port of Future Composer 1.4's replayer,
  7. ** by Olav "8bitbubsy" Sørensen, using a FC1.4 disassembly (its supplied replayer code was buggy).
  8. ** Works correctly with v1.0..v1.3 modules as well.
  9. **
  10. ** The BLEP (Band-Limited Step) and filter routines were coded by aciddose.
  11. ** This makes the replayer sound much similar 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 fc14play usage:
  18. ** #include "fc14play.h"
  19. ** #include "songdata.h"
  20. **
  21. ** fc14play_PlaySong(songData, songDataLength, 48000);
  22. ** mainLoop();
  23. ** fc14play_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.29:
  29. ** - Added fc14play_SetMasterVol() and fc14play_GetMasterVol()
  30. **
  31. ** Changes in v1.28:
  32. ** - Audio mixer has been slightly optimized
  33. ** - Audio dithering has been improved (rectangular -> triangular)
  34. **
  35. ** Changes in v1.27:
  36. ** - Audio signal phase is now inverted on output, like on A500/1200.
  37. **   This can actually change the bass response depending on your speaker elements.
  38. **   In my case, on Sennheiser HD598, I get deeper bass (same as on my Amigas).
  39. ** - All filters (low-pass, high-pass) have been hand-tweaked to better
  40. **   match A500 and A1200 from intensive testing and waveform comparison.
  41. **   Naturally, the analog filters vary from unit to unit because of component
  42. **   tolerance and aging components, but I am quite confident that this is a
  43. **   closer match than before anyway.
  44. ** - Added audio mixer dithering
  45. **
  46. ** Changes in v1.26a:
  47. ** - Code cleanup
  48. **
  49. ** Changes in v1.26:
  50. ** - Removed the "DMA Wait" stuff, this is not needed in the way I do things.
  51. **   This actually fixes "double kickdrum" in tristar-scoopex.fc.
  52. ** - Mixer is now using double-precision instead of single-precision accuracy.
  53. **
  54. ** Changes in v1.25:
  55. ** - Code cleanup (uses the "bool" type now, spaces -> tabs, comment style change)
  56. **
  57. ** Changes in v1.24:
  58. ** - Some code cleanup
  59. ** - Small optimziation to audio mixer
  60. **
  61. ** Changes in v1.23:
  62. ** - WinMM mixer has been rewritten to be safe (DON'T use syscalls in callback -MSDN)
  63. ** - Some small changes to the fc14play functions (easier to use and safer!)
  64. */
  65.  
  66. /* fc14play.h:
  67.  
  68. #pragma once
  69.  
  70. #include <stdint.h>
  71. #include <stdbool.h>
  72.  
  73. bool fc14play_PlaySong(const uint8_t *moduleData, uint32_t dataLength, uint32_t audioFreq);
  74. void fc14play_Close(void);
  75. void fc14play_PauseSong(bool flag); // true/false
  76. void fc14play_TogglePause(void);
  77. void fc14play_SetStereoSep(uint8_t percentage); // 0..100
  78. uint32_t fc14play_GetMixerTicks(void); // returns the amount of milliseconds of mixed audio (not realtime)
  79. */
  80.  
  81. // == USER ADJUSTABLE SETTINGS ==
  82. #define STEREO_SEP (20)    /* --> Stereo separation in percent - 0 = mono, 100 = hard pan (like Amiga) */
  83. #define USE_HIGHPASS       /* --> ~5Hz HP filter present in all Amigas - comment out for a tiny speed-up */
  84. //#define USE_LOWPASS      /* --> ~5kHz LP filter present in all Amigas except A1200 - comment out for sharper sound (and tiny speed-up) */
  85. #define USE_BLEP           /* --> Reduces some aliasing in the sound (closer to real Amiga) - comment out for a speed-up */
  86. #define MIX_BUF_SAMPLES 4096
  87.  
  88. #ifdef _MSC_VER
  89. #define inline __forceinline
  90. #endif
  91.  
  92. #include <stdio.h>
  93. #include <stdlib.h>
  94. #include <string.h>
  95. #include <stdint.h>
  96. #include <stdbool.h>
  97. #include <math.h> // tan()
  98.  
  99. // main crystal oscillator
  100. // main crystal oscillator
  101. #define AMIGA_PAL_XTAL_HZ 28375160
  102.  
  103. #define PAULA_PAL_CLK (AMIGA_PAL_XTAL_HZ / 8)
  104. #define CIA_PAL_CLK (AMIGA_PAL_XTAL_HZ / 40)
  105. #define AMIGA_PAL_VBLANK_HZ 50
  106.  
  107. #define AMIGA_VOICES 4
  108.  
  109. #define INITIAL_DITHER_SEED 0x12345000
  110. #define DENORMAL_OFFSET 1e-10
  111.  
  112. #define SEQ_SIZE 13
  113. #define PAT_END_MARKER 0x49
  114. #define NUM_SAMPLES 10
  115. #define NUM_WAVEFORMS 80
  116. #define NUM_WAVEFORMS_SMOD 47
  117.  
  118. #define BLEP_ZC 8
  119. #define BLEP_OS 5
  120. #define BLEP_SP 5
  121. #define BLEP_NS (BLEP_ZC * BLEP_OS / BLEP_SP)
  122. #define BLEP_RNS 7 // RNS = (2^ > NS) - 1
  123.  
  124. #ifdef USE_BLEP
  125. typedef struct blep_t
  126. {
  127.     int32_t index, samplesLeft;
  128.     double dBuffer[BLEP_RNS + 1], dLastValue;
  129. } blep_t;
  130. #endif
  131.  
  132. typedef struct paulaVoice_t
  133. {
  134.     volatile bool active;
  135.     const int8_t *data, *newData;
  136.     int32_t length, newLength, pos;
  137.     double dVolume, dDelta, dPhase, dPanL, dPanR;
  138. #ifdef USE_BLEP
  139.     double dDeltaMul, dLastDelta, dLastPhase, dLastDeltaMul;
  140. #endif
  141. } paulaVoice_t;
  142.  
  143. #if defined(USE_HIGHPASS) || defined(USE_LOWPASS)
  144. typedef struct lossyIntegrator_t
  145. {
  146.     double dBuffer[2], b0, b1;
  147. } lossyIntegrator_t;
  148. #endif
  149.  
  150. typedef struct soundInfo_t // do not touch!
  151. {
  152.     int8_t *data;
  153.     uint16_t length;
  154.     int8_t *repeat;
  155.     uint16_t replen;
  156. } soundInfo_t;
  157.  
  158. typedef struct fcChannel_t
  159. {
  160.     bool vibratoUp, portaDelay, pitchBendDelay, volSlideDelay;
  161.     int8_t pitchBendValue, pitchBendCounter, note, noteTranspose;
  162.     int8_t soundTranspose, *loopStart, volume, periodTranspose;
  163.     const uint8_t *freqTabPtr, *volTabPtr;
  164.     uint8_t voiceIndex, *seqStartPtr, *patPtr;
  165.     uint8_t freqSusCounter, volSusCounter;
  166.     uint8_t vibratoSpeed, vibratoDepth, vibratoCounter;
  167.     uint8_t vibratoDelay, volSlideSpeed;
  168.     uint8_t volSlideCounter, portaParam, volDelayCounter;
  169.     uint8_t volDelayLength;
  170.     int16_t portaValue;
  171.     uint16_t loopLength, freqTabPos, volTabPos, patPos;
  172.     uint32_t seqPos;
  173. } fcChannel_t;
  174.  
  175. static volatile bool musicPaused;
  176. static bool fc14;
  177. static int8_t *ptr8s_1, *ptr8s_1;
  178. static uint8_t *songData, *ptr8u_1, *ptr8u_2, spdtemp, spdtemp2, respcnt, repspd;
  179. static uint8_t *SEQpoint, *PATpoint, *FRQpoint, *VOLpoint, stereoSep = STEREO_SEP;
  180. static uint16_t oldPeriod;
  181. static int32_t soundBufferSize, samplesPerFrameLeft, samplesPerFrame;
  182. static int32_t randSeed = INITIAL_DITHER_SEED, masterVol = 256;
  183. static uint32_t audioRate, numSequences, sampleCounter;
  184. static double oldVoiceDelta, *dMixerBufferL, *dMixerBufferR, dAudioRate, dPeriodToDeltaDiv;
  185. static double dPrngStateL, dPrngStateR;
  186. static paulaVoice_t paula[AMIGA_VOICES];
  187. static fcChannel_t Channel[AMIGA_VOICES];
  188. static soundInfo_t samples[NUM_SAMPLES + NUM_WAVEFORMS];
  189. #ifdef USE_BLEP
  190. static double dOldVoiceDeltaMul;
  191. static blep_t blep[AMIGA_VOICES], blepVol[AMIGA_VOICES];
  192. #endif
  193. #ifdef USE_HIGHPASS
  194. static lossyIntegrator_t filterHi;
  195. #endif
  196. #ifdef USE_LOWPASS
  197. static lossyIntegrator_t filterLo;
  198. #endif
  199.  
  200. #define LERP(x, y, z) ((x) + ((y) - (x)) * (z))
  201. #define CLAMP(x, low, high) (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x)))
  202. #define CLAMP16(i) if ((int16_t)(i) != i) i = 0x7FFF ^ (i >> 31);
  203. #define PTR2LONG(x) ((uint32_t *)(x))
  204. #define PTR2WORD(x) ((uint16_t *)(x))
  205. #define SWAP16(x) ((uint16_t)(((x) << 8) | ((x) >> 8)))
  206. #define SWAP32(value) \
  207. ( \
  208.     (((uint32_t)((value) & 0x000000FF)) << 24) | \
  209.     (((uint32_t)((value) & 0x0000FF00)) <<  8) | \
  210.     (((uint32_t)((value) & 0x00FF0000)) >>  8) | \
  211.     (((uint32_t)((value) & 0xFF000000)) >> 24)   \
  212. )
  213.  
  214. static const uint8_t silentTable[8] = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE1 };
  215.  
  216. static const uint16_t periods[128] =
  217. {
  218.     // 1.0..1.3 periods
  219.     0x06B0,0x0650,0x05F4,0x05A0,0x054C,0x0500,0x04B8,0x0474,0x0434,0x03F8,0x03C0,0x038A,
  220.     0x0358,0x0328,0x02FA,0x02D0,0x02A6,0x0280,0x025C,0x023A,0x021A,0x01FC,0x01E0,0x01C5,
  221.     0x01AC,0x0194,0x017D,0x0168,0x0153,0x0140,0x012E,0x011D,0x010D,0x00FE,0x00F0,0x00E2,
  222.     0x00D6,0x00CA,0x00BE,0x00B4,0x00AA,0x00A0,0x0097,0x008F,0x0087,0x007F,0x0078,0x0071,
  223.     0x0071,0x0071,0x0071,0x0071,0x0071,0x0071,0x0071,0x0071,0x0071,0x0071,0x0071,0x0071,
  224.  
  225.     // 1.4 periods (one extra octave)
  226.     0x0D60,0x0CA0,0x0BE8,0x0B40,0x0A98,0x0A00,0x0970,0x08E8,0x0868,0x07F0,0x0780,0x0714,
  227.     0x06B0,0x0650,0x05F4,0x05A0,0x054C,0x0500,0x04B8,0x0474,0x0434,0x03F8,0x03C0,0x038A,
  228.     0x0358,0x0328,0x02FA,0x02D0,0x02A6,0x0280,0x025C,0x023A,0x021A,0x01FC,0x01E0,0x01C5,
  229.     0x01AC,0x0194,0x017D,0x0168,0x0153,0x0140,0x012E,0x011D,0x010D,0x00FE,0x00F0,0x00E2,
  230.     0x00D6,0x00CA,0x00BE,0x00B4,0x00AA,0x00A0,0x0097,0x008F,0x0087,0x007F,0x0078,0x0071,
  231.     0x0071,0x0071,0x0071,0x0071,0x0071,0x0071,0x0071,0x0071
  232. };
  233.  
  234. static const int8_t waveformDatas[1344] =
  235. {
  236.     0xC0,0xC0,0xD0,0xD8,0xE0,0xE8,0xF0,0xF8,0x00,0xF8,0xF0,0xE8,0xE0,0xD8,0xD0,0xC8,
  237.     0x3F,0x37,0x2F,0x27,0x1F,0x17,0x0F,0x07,0xFF,0x07,0x0F,0x17,0x1F,0x27,0x2F,0x37,
  238.     0xC0,0xC0,0xD0,0xD8,0xE0,0xE8,0xF0,0xF8,0x00,0xF8,0xF0,0xE8,0xE0,0xD8,0xD0,0xC8,
  239.     0xC0,0x37,0x2F,0x27,0x1F,0x17,0x0F,0x07,0xFF,0x07,0x0F,0x17,0x1F,0x27,0x2F,0x37,
  240.     0xC0,0xC0,0xD0,0xD8,0xE0,0xE8,0xF0,0xF8,0x00,0xF8,0xF0,0xE8,0xE0,0xD8,0xD0,0xC8,
  241.     0xC0,0xB8,0x2F,0x27,0x1F,0x17,0x0F,0x07,0xFF,0x07,0x0F,0x17,0x1F,0x27,0x2F,0x37,
  242.     0xC0,0xC0,0xD0,0xD8,0xE0,0xE8,0xF0,0xF8,0x00,0xF8,0xF0,0xE8,0xE0,0xD8,0xD0,0xC8,
  243.     0xC0,0xB8,0xB0,0x27,0x1F,0x17,0x0F,0x07,0xFF,0x07,0x0F,0x17,0x1F,0x27,0x2F,0x37,
  244.     0xC0,0xC0,0xD0,0xD8,0xE0,0xE8,0xF0,0xF8,0x00,0xF8,0xF0,0xE8,0xE0,0xD8,0xD0,0xC8,
  245.     0xC0,0xB8,0xB0,0xA8,0x1F,0x17,0x0F,0x07,0xFF,0x07,0x0F,0x17,0x1F,0x27,0x2F,0x37,
  246.     0xC0,0xC0,0xD0,0xD8,0xE0,0xE8,0xF0,0xF8,0x00,0xF8,0xF0,0xE8,0xE0,0xD8,0xD0,0xC8,
  247.     0xC0,0xB8,0xB0,0xA8,0xA0,0x17,0x0F,0x07,0xFF,0x07,0x0F,0x17,0x1F,0x27,0x2F,0x37,
  248.     0xC0,0xC0,0xD0,0xD8,0xE0,0xE8,0xF0,0xF8,0x00,0xF8,0xF0,0xE8,0xE0,0xD8,0xD0,0xC8,
  249.     0xC0,0xB8,0xB0,0xA8,0xA0,0x98,0x0F,0x07,0xFF,0x07,0x0F,0x17,0x1F,0x27,0x2F,0x37,
  250.     0xC0,0xC0,0xD0,0xD8,0xE0,0xE8,0xF0,0xF8,0x00,0xF8,0xF0,0xE8,0xE0,0xD8,0xD0,0xC8,
  251.     0xC0,0xB8,0xB0,0xA8,0xA0,0x98,0x90,0x07,0xFF,0x07,0x0F,0x17,0x1F,0x27,0x2F,0x37,
  252.     0xC0,0xC0,0xD0,0xD8,0xE0,0xE8,0xF0,0xF8,0x00,0xF8,0xF0,0xE8,0xE0,0xD8,0xD0,0xC8,
  253.     0xC0,0xB8,0xB0,0xA8,0xA0,0x98,0x90,0x88,0xFF,0x07,0x0F,0x17,0x1F,0x27,0x2F,0x37,
  254.     0xC0,0xC0,0xD0,0xD8,0xE0,0xE8,0xF0,0xF8,0x00,0xF8,0xF0,0xE8,0xE0,0xD8,0xD0,0xC8,
  255.     0xC0,0xB8,0xB0,0xA8,0xA0,0x98,0x90,0x88,0x80,0x07,0x0F,0x17,0x1F,0x27,0x2F,0x37,
  256.     0xC0,0xC0,0xD0,0xD8,0xE0,0xE8,0xF0,0xF8,0x00,0xF8,0xF0,0xE8,0xE0,0xD8,0xD0,0xC8,
  257.     0xC0,0xB8,0xB0,0xA8,0xA0,0x98,0x90,0x88,0x80,0x88,0x0F,0x17,0x1F,0x27,0x2F,0x37,
  258.     0xC0,0xC0,0xD0,0xD8,0xE0,0xE8,0xF0,0xF8,0x00,0xF8,0xF0,0xE8,0xE0,0xD8,0xD0,0xC8,
  259.     0xC0,0xB8,0xB0,0xA8,0xA0,0x98,0x90,0x88,0x80,0x88,0x90,0x17,0x1F,0x27,0x2F,0x37,
  260.     0xC0,0xC0,0xD0,0xD8,0xE0,0xE8,0xF0,0xF8,0x00,0xF8,0xF0,0xE8,0xE0,0xD8,0xD0,0xC8,
  261.     0xC0,0xB8,0xB0,0xA8,0xA0,0x98,0x90,0x88,0x80,0x88,0x90,0x98,0x1F,0x27,0x2F,0x37,
  262.     0xC0,0xC0,0xD0,0xD8,0xE0,0xE8,0xF0,0xF8,0x00,0xF8,0xF0,0xE8,0xE0,0xD8,0xD0,0xC8,
  263.     0xC0,0xB8,0xB0,0xA8,0xA0,0x98,0x90,0x88,0x80,0x88,0x90,0x98,0xA0,0x27,0x2F,0x37,
  264.     0xC0,0xC0,0xD0,0xD8,0xE0,0xE8,0xF0,0xF8,0x00,0xF8,0xF0,0xE8,0xE0,0xD8,0xD0,0xC8,
  265.     0xC0,0xB8,0xB0,0xA8,0xA0,0x98,0x90,0x88,0x80,0x88,0x90,0x98,0xA0,0xA8,0x2F,0x37,
  266.     0xC0,0xC0,0xD0,0xD8,0xE0,0xE8,0xF0,0xF8,0x00,0xF8,0xF0,0xE8,0xE0,0xD8,0xD0,0xC8,
  267.     0xC0,0xB8,0xB0,0xA8,0xA0,0x98,0x90,0x88,0x80,0x88,0x90,0x98,0xA0,0xA8,0xB0,0x37,
  268.     0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,
  269.     0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,
  270.     0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,
  271.     0x81,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,
  272.     0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,
  273.     0x81,0x81,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,
  274.     0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,
  275.     0x81,0x81,0x81,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,
  276.     0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,
  277.     0x81,0x81,0x81,0x81,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,
  278.     0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,
  279.     0x81,0x81,0x81,0x81,0x81,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,
  280.     0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,
  281.     0x81,0x81,0x81,0x81,0x81,0x81,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,
  282.     0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,
  283.     0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,
  284.     0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,
  285.     0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,
  286.     0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,
  287.     0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,
  288.     0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,
  289.     0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,
  290.     0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,
  291.     0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x7F,0x7F,0x7F,0x7F,0x7F,
  292.     0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,
  293.     0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x7F,0x7F,0x7F,0x7F,
  294.     0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,
  295.     0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x7F,0x7F,0x7F,
  296.     0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
  297.     0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x7F,0x7F,
  298.     0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
  299.     0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x7F,
  300.     0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,
  301.     0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,
  302.     0x80,0x80,0x80,0x80,0x80,0x80,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,
  303.     0x80,0x80,0x80,0x80,0x80,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,
  304.     0x80,0x80,0x80,0x80,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,
  305.     0x80,0x80,0x80,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,
  306.     0x80,0x80,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,
  307.     0x80,0x80,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,
  308.     0x80,0x80,0x90,0x98,0xA0,0xA8,0xB0,0xB8,0xC0,0xC8,0xD0,0xD8,0xE0,0xE8,0xF0,0xF8,
  309.     0x00,0x08,0x10,0x18,0x20,0x28,0x30,0x38,0x40,0x48,0x50,0x58,0x60,0x68,0x70,0x7F,
  310.     0x80,0x80,0xA0,0xB0,0xC0,0xD0,0xE0,0xF0,0x00,0x10,0x20,0x30,0x40,0x50,0x60,0x70,
  311.     0x45,0x45,0x79,0x7D,0x7A,0x77,0x70,0x66,0x61,0x58,0x53,0x4D,0x2C,0x20,0x18,0x12,
  312.     0x04,0xDB,0xD3,0xCD,0xC6,0xBC,0xB5,0xAE,0xA8,0xA3,0x9D,0x99,0x93,0x8E,0x8B,0x8A,
  313.     0x45,0x45,0x79,0x7D,0x7A,0x77,0x70,0x66,0x5B,0x4B,0x43,0x37,0x2C,0x20,0x18,0x12,
  314.     0x04,0xF8,0xE8,0xDB,0xCF,0xC6,0xBE,0xB0,0xA8,0xA4,0x9E,0x9A,0x95,0x94,0x8D,0x83,
  315.     0x00,0x00,0x40,0x60,0x7F,0x60,0x40,0x20,0x00,0xE0,0xC0,0xA0,0x80,0xA0,0xC0,0xE0,
  316.     0x00,0x00,0x40,0x60,0x7F,0x60,0x40,0x20,0x00,0xE0,0xC0,0xA0,0x80,0xA0,0xC0,0xE0,
  317.     0x80,0x80,0x90,0x98,0xA0,0xA8,0xB0,0xB8,0xC0,0xC8,0xD0,0xD8,0xE0,0xE8,0xF0,0xF8,
  318.     0x00,0x08,0x10,0x18,0x20,0x28,0x30,0x38,0x40,0x48,0x50,0x58,0x60,0x68,0x70,0x7F,
  319.     0x80,0x80,0xA0,0xB0,0xC0,0xD0,0xE0,0xF0,0x00,0x10,0x20,0x30,0x40,0x50,0x60,0x70
  320. };
  321.  
  322. #ifdef USE_BLEP
  323.  
  324. /* Why this table is not represented as readable float (double) numbers:
  325. ** Accurate float (double) representation in string format requires at least 14 digits and normalized
  326. ** (scientific) notation, notwithstanding compiler issues with precision or rounding error.
  327. ** Also, don't touch this table ever, just keep it exactly identical! */
  328.  
  329. // TODO: get a proper double-precision table. This one is converted from float
  330. static const uint64_t dBlepData[48] =
  331. {
  332.     0x3FEFFC3E20000000, 0x3FEFFAA900000000, 0x3FEFFAD460000000, 0x3FEFFA9C60000000,
  333.     0x3FEFF5B0A0000000, 0x3FEFE42A40000000, 0x3FEFB7F5C0000000, 0x3FEF599BE0000000,
  334.     0x3FEEA5E3C0000000, 0x3FED6E7080000000, 0x3FEB7F7960000000, 0x3FE8AB9E40000000,
  335.     0x3FE4DCA480000000, 0x3FE0251880000000, 0x3FD598FB80000000, 0x3FC53D0D60000000,
  336.     0x3F8383A520000000, 0xBFBC977CC0000000, 0xBFC755C080000000, 0xBFC91BDBA0000000,
  337.     0xBFC455AFC0000000, 0xBFB6461340000000, 0xBF7056C400000000, 0x3FB1028220000000,
  338.     0x3FBB5B7E60000000, 0x3FBC5903A0000000, 0x3FB55403E0000000, 0x3FA3CED340000000,
  339.     0xBF7822DAE0000000, 0xBFA2805D00000000, 0xBFA7140D20000000, 0xBFA18A7760000000,
  340.     0xBF87FF7180000000, 0x3F88CBFA40000000, 0x3F9D4AEC80000000, 0x3FA14A3AC0000000,
  341.     0x3F9D5C5AA0000000, 0x3F92558B40000000, 0x3F7C997EE0000000, 0x0000000000000000,
  342.     0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
  343.     0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000
  344. };
  345. #endif
  346.  
  347. static const uint8_t waveformLengths[47] =
  348. {
  349.     0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
  350.     0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
  351.     0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
  352.     0x10, 0x10, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
  353.     0x10, 0x08, 0x10, 0x10, 0x08, 0x08, 0x18
  354. };
  355.  
  356. static bool openMixer(uint32_t audioFreq);
  357. static void closeMixer(void);
  358.  
  359. // CODE START
  360.  
  361. static void paulaStopDMA(uint8_t i)
  362. {
  363.     paula[i].active = false;
  364. }
  365.  
  366. static void paulaStartDMA(uint8_t i)
  367. {
  368.     paulaVoice_t *v = &paula[i];
  369.  
  370.     v->dPhase = 0.0;
  371.     v->pos = 0;
  372.     v->data = v->newData;
  373.     v->length = v->newLength;
  374.     v->active = true;
  375. }
  376.  
  377. static void paulaSetPeriod(uint8_t i, uint16_t period)
  378. {
  379.     paulaVoice_t *v = &paula[i];
  380.  
  381.     if (period == 0)
  382.     {
  383.         v->dDelta = 0.0; // confirmed behavior on real Amiga
  384. #ifdef USE_BLEP
  385.         v->dDeltaMul = 1.0;
  386. #endif
  387.         return;
  388.     }
  389.  
  390.     if (period < 113)
  391.         period = 113; // confirmed behavior on real Amiga
  392.  
  393.     // if the new period was the same as the previous period, use cached deltas
  394.     if (period == oldPeriod)
  395.     {
  396.         v->dDelta = oldVoiceDelta;
  397. #ifdef USE_BLEP
  398.         v->dDeltaMul = dOldVoiceDeltaMul;
  399. #endif
  400.     }
  401.     else
  402.     {
  403.         oldPeriod = period;
  404.         v->dDelta = dPeriodToDeltaDiv / period;
  405.         oldVoiceDelta = v->dDelta;
  406.  
  407. #ifdef USE_BLEP
  408.         v->dDeltaMul = 1.0 / v->dDelta;
  409.         dOldVoiceDeltaMul = v->dDeltaMul;
  410. #endif
  411.     }
  412.  
  413. #ifdef USE_BLEP
  414.     if (v->dLastDelta == 0.0)
  415.         v->dLastDelta = v->dDelta;
  416.    
  417.     if (v->dLastDeltaMul == 0.0)
  418.         v->dLastDeltaMul = v->dDeltaMul;
  419. #endif
  420. }
  421.  
  422. static void paulaSetVolume(uint8_t i, uint16_t vol)
  423. {
  424.     vol &= 127;
  425.     if (vol > 64)
  426.         vol = 64;
  427.  
  428.     paula[i].dVolume = vol * (1.0 / 64.0);
  429. }
  430.  
  431. static void paulaSetLength(uint8_t i, uint16_t len)
  432. {
  433.     paula[i].newLength = len * 2;
  434. }
  435.  
  436. static void paulaSetData(uint8_t i, const int8_t *src)
  437. {
  438.     paula[i].newData = src;
  439. }
  440.  
  441. #if defined(USE_HIGHPASS) || defined(USE_LOWPASS)
  442. static void calcCoeffLossyIntegrator(double dSr, double dHz, lossyIntegrator_t *filter)
  443. {
  444.     double dOmega = ((2.0 * M_PI) * dHz) / dSr;
  445.     filter->b0 = 1.0 / (1.0 + (1.0 / dOmega));
  446.     filter->b1 = 1.0 - filter->b0;
  447. }
  448.  
  449. static void clearLossyIntegrator(lossyIntegrator_t *filter)
  450. {
  451.     filter->dBuffer[0] = 0.0; // L
  452.     filter->dBuffer[1] = 0.0; // R
  453. }
  454.  
  455. static inline void lossyIntegrator(lossyIntegrator_t *filter, double *dIn, double *dOut)
  456. {
  457.     /* Low-pass filter implementation taken from:
  458.     ** https://bel.fi/alankila/modguide/interpolate.txt */
  459.  
  460.     // left channel low-pass
  461.     filter->dBuffer[0] = (filter->b0 * dIn[0]) + (filter->b1 * filter->dBuffer[0]) + DENORMAL_OFFSET;
  462.     dOut[0] = filter->dBuffer[0];
  463.  
  464.     // right channel low-pass
  465.     filter->dBuffer[1] = (filter->b0 * dIn[1]) + (filter->b1 * filter->dBuffer[1]) + DENORMAL_OFFSET;
  466.     dOut[1] = filter->dBuffer[1];
  467. }
  468.  
  469. static inline void lossyIntegratorHighPass(lossyIntegrator_t *filter, double *dIn, double *dOut)
  470. {
  471.     double dLow[2];
  472.  
  473.     lossyIntegrator(filter, dIn, dLow);
  474.  
  475.     dOut[0] = dIn[0] - dLow[0]; // left channel high-pass
  476.     dOut[1] = dIn[1] - dLow[1]; // right channel high-pass
  477. }
  478. #endif
  479.  
  480. #ifdef USE_BLEP
  481. void blepAdd(blep_t *b, double dOffset, double dAmplitude)
  482. {
  483.     int8_t n;
  484.     int32_t i;
  485.     const double *dBlepSrc;
  486.     double f;
  487.  
  488.     f = dOffset * BLEP_SP;
  489.  
  490.     i = (int32_t)f; // get integer part of f
  491.     dBlepSrc = (const double *)dBlepData + i + BLEP_OS;
  492.     f -= i; // remove integer part from f
  493.  
  494.     i = b->index;
  495.  
  496.     n = BLEP_NS;
  497.     while (n--)
  498.     {
  499.         b->dBuffer[i] += (dAmplitude * LERP(dBlepSrc[0], dBlepSrc[1], f));
  500.         i = (i + 1) & BLEP_RNS;
  501.         dBlepSrc += BLEP_SP;
  502.     }
  503.  
  504.     b->samplesLeft = BLEP_NS;
  505. }
  506.  
  507. /* 8bitbubsy: simplified, faster version of blepAdd for blep'ing voice volume.
  508. ** Result is identical! (confirmed with binary comparison)
  509. */
  510. void blepVolAdd(blep_t *b, double dAmplitude)
  511. {
  512.     int8_t n;
  513.     int32_t i;
  514.     const double *dBlepSrc;
  515.  
  516.     dBlepSrc = (const double *)dBlepData + BLEP_OS;
  517.  
  518.     i = b->index;
  519.  
  520.     n = BLEP_NS;
  521.     while (n--)
  522.     {
  523.         b->dBuffer[i] += dAmplitude * (*dBlepSrc);
  524.         i = (i + 1) & BLEP_RNS;
  525.         dBlepSrc += BLEP_SP;
  526.     }
  527.  
  528.     b->samplesLeft = BLEP_NS;
  529. }
  530.  
  531. double blepRun(blep_t *b)
  532. {
  533.     double fBlepOutput;
  534.  
  535.     fBlepOutput = b->dBuffer[b->index];
  536.     b->dBuffer[b->index] = 0.0;
  537.  
  538.     b->index = (b->index + 1) & BLEP_RNS;
  539.  
  540.     b->samplesLeft--;
  541.     return fBlepOutput;
  542. }
  543. #endif
  544.  
  545. static bool init_music(const uint8_t *moduleData)
  546. {
  547.     uint8_t i;
  548.     soundInfo_t *s;
  549.  
  550.     fc14 = (*PTR2LONG(&moduleData[0]) == 0x34314346); // "FC14"
  551.  
  552.     if (*PTR2LONG(&moduleData[0]) != 0x444F4D53 && !fc14) // "SMOD"
  553.         return false;
  554.  
  555.     // setup pointers...
  556.  
  557.     SEQpoint = (uint8_t *)&moduleData[fc14 ? 180 : 100];
  558.     PATpoint = (uint8_t *)&moduleData[SWAP32(*PTR2LONG(&moduleData[8]))];
  559.     FRQpoint = (uint8_t *)&moduleData[SWAP32(*PTR2LONG(&moduleData[16]))];
  560.     VOLpoint = (uint8_t *)&moduleData[SWAP32(*PTR2LONG(&moduleData[24]))];
  561.    
  562.     // load samples
  563.  
  564.     ptr8s_1 =  (int8_t *)&moduleData[SWAP32(*PTR2LONG(&moduleData[32]))];
  565.     ptr8u_2 = (uint8_t *)&moduleData[40];
  566.  
  567.     for (i = 0; i < NUM_SAMPLES; i++)
  568.     {
  569.         samples[i].data = ptr8s_1;
  570.         samples[i].length = SWAP16(*PTR2WORD(ptr8u_2)); ptr8u_2 += 2;
  571.         samples[i].repeat = &samples[i].data[SWAP16(*PTR2WORD(ptr8u_2))]; ptr8u_2 += 2;
  572.         samples[i].replen = SWAP16(*PTR2WORD(ptr8u_2)); ptr8u_2 += 2;
  573.  
  574.         // fix endless beep on non-looping samples (FC14 doesn't do this)
  575.         if (samples[i].replen <= 1)
  576.         {
  577.             samples[i].replen = 1;
  578.             if (samples[i].length >= 1)
  579.             {
  580.                 if (*PTR2LONG(samples[i].data) != 0x504D5353) // "SSMP"
  581.                     *PTR2WORD(samples[i].data) = 0;
  582.             }
  583.         }
  584.  
  585.         ptr8s_1 += (samples[i].length * 2) + 2;
  586.     }
  587.  
  588.     // load waveforms
  589.  
  590.     if (fc14)
  591.     {
  592.         ptr8s_1 = (int8_t *)&moduleData[SWAP32(*PTR2LONG(&moduleData[36]))];
  593.         ptr8u_2 = (uint8_t *)&moduleData[100];
  594.  
  595.         for (i = 0; i < NUM_WAVEFORMS; i++)
  596.         {
  597.             s = &samples[NUM_SAMPLES + i];
  598.  
  599.             s->data = ptr8s_1;
  600.             s->length = *ptr8u_2++;
  601.             s->repeat = ptr8s_1;
  602.             s->replen = s->length;
  603.  
  604.             ptr8s_1 += s->length * 2;
  605.         }
  606.     }
  607.     else
  608.     {
  609.         ptr8s_1 = (int8_t *)waveformDatas;
  610.         for (i = 0; i < NUM_WAVEFORMS; i++)
  611.         {
  612.             s = &samples[NUM_SAMPLES + i];
  613.  
  614.             if (i < NUM_WAVEFORMS_SMOD)
  615.             {
  616.                 s->data = ptr8s_1;
  617.                 s->length = waveformLengths[i];
  618.                 s->repeat = s->data;
  619.                 s->replen = s->length;
  620.  
  621.                 ptr8s_1 += s->length * 2;
  622.             }
  623.             else
  624.             {
  625.                 s->data = NULL;
  626.                 s->length = 0;
  627.                 s->repeat = NULL;
  628.                 s->replen = 1;
  629.             }
  630.         }
  631.     }
  632.  
  633.     // get number of sequences and make it a multiple of 13 (SEQ_SIZE)
  634.     numSequences = (uint32_t)(SWAP32(*PTR2LONG(&moduleData[4])) / SEQ_SIZE) * SEQ_SIZE;
  635.  
  636.     return true;
  637. }
  638.  
  639. static void restart_song(void)
  640. {
  641.     fcChannel_t *ch;
  642.  
  643.     memset(Channel, 0, sizeof (Channel));
  644.     for (uint8_t i = 0; i < AMIGA_VOICES; i++)
  645.     {
  646.         ch = &Channel[i];
  647.  
  648.         ch->voiceIndex = i;
  649.         ch->volTabPtr = silentTable;
  650.         ch->freqTabPtr = silentTable;
  651.         ch->volDelayCounter = 1;
  652.         ch->volDelayLength = 1;
  653.         ch->pitchBendDelay = true;
  654.         ch->seqPos = SEQ_SIZE; // yes
  655.         ch->seqStartPtr = &SEQpoint[3 * i];
  656.         ch->patPtr = &PATpoint[ch->seqStartPtr[0] << 6];
  657.         ch->noteTranspose = (int8_t)ch->seqStartPtr[1];
  658.         ch->soundTranspose = (int8_t)ch->seqStartPtr[2];
  659.     }
  660.  
  661.     repspd = (SEQpoint[12] > 0) ? SEQpoint[12] : 3;
  662.     respcnt = repspd;
  663.     spdtemp = 0;
  664.     spdtemp2 = 0;
  665. }
  666.  
  667. static void new_note(fcChannel_t *ch)
  668. {
  669.     uint8_t *tmpSeqPtr, *tmpPatPtr, note, info;
  670.  
  671.     tmpPatPtr = &ch->patPtr[ch->patPos]; // temp pattern pointer
  672.  
  673.     if ((fc14 && (*tmpPatPtr & 0x7F) == PAT_END_MARKER) || ch->patPos == 64)
  674.     {
  675.         ch->patPos = 0;
  676.         if (ch->seqPos >= numSequences)
  677.             ch->seqPos = 0;
  678.  
  679.         tmpSeqPtr = &ch->seqStartPtr[ch->seqPos];
  680.         ch->patPtr = &PATpoint[tmpSeqPtr[0] << 6];
  681.  
  682.         ch->noteTranspose = (int8_t)tmpSeqPtr[1];
  683.         ch->soundTranspose = (int8_t)tmpSeqPtr[2];
  684.  
  685.         if (++spdtemp == 4)
  686.         {
  687.             spdtemp = 0;
  688.  
  689.             // we've read all channels now, let's increase the pos used for RS
  690.             if (++spdtemp2 == numSequences/SEQ_SIZE) // numSequences is a multiple of SEQ_SIZE
  691.                 spdtemp2 = 0; // wrap sequence position
  692.         }
  693.  
  694.         // read current RS (replay speed. only update if non-zero)
  695.         if (SEQpoint[(spdtemp2 * 13) + 12] != 0)
  696.         {
  697.             repspd = SEQpoint[(spdtemp2 * 13) + 12];
  698.             respcnt = repspd;
  699.         }
  700.  
  701.         ch->seqPos += SEQ_SIZE;
  702.         tmpPatPtr = ch->patPtr; // set new temp pattern pointer
  703.     }
  704.  
  705.     note = tmpPatPtr[0];
  706.     info = tmpPatPtr[1];
  707.  
  708.     if (note == 0)
  709.     {
  710.         info &= 0xC0;
  711.         if (info != 0)
  712.         {
  713.             ch->portaParam = 0;
  714.             if (info & (1 << 7))
  715.                 ch->portaParam = tmpPatPtr[3];
  716.         }
  717.     }
  718.     else
  719.     {
  720.         ch->portaValue = 0;
  721.         ch->portaParam = 0;
  722.  
  723.         if (info & (1 << 7))
  724.             ch->portaParam = tmpPatPtr[3];
  725.     }
  726.  
  727.     note &= 0x7F;
  728.     if (note != 0)
  729.     {
  730.         ptr8u_1 = &VOLpoint[((tmpPatPtr[1] & 0x3F) + ch->soundTranspose) << 6];
  731.  
  732.         ch->note = note;
  733.         ch->volDelayLength = ptr8u_1[0];
  734.         ch->volDelayCounter = ch->volDelayLength;
  735.         ch->freqTabPtr = &FRQpoint[ptr8u_1[1] << 6];
  736.         ch->freqTabPos = 0;
  737.         ch->freqSusCounter = 0;
  738.         ch->vibratoSpeed = ptr8u_1[2];
  739.         ch->vibratoDepth = ptr8u_1[3];
  740.         ch->vibratoDelay = ptr8u_1[4];
  741.         ch->vibratoCounter = ch->vibratoDepth;
  742.         ch->vibratoUp = true; // default initial state on new note
  743.         ch->volTabPtr = &ptr8u_1[5];
  744.         ch->volTabPos = 0;
  745.         ch->volSusCounter = 0;
  746.  
  747.         paulaStopDMA(ch->voiceIndex); // yes, this is important
  748.     }
  749.  
  750.     ch->patPos += 2;
  751. }
  752.  
  753. static void doFreqModulation(fcChannel_t *ch)
  754. {
  755.     bool doTranspose;
  756.     uint8_t *tmpPtr;
  757.     const uint8_t *tabPtr;
  758.     soundInfo_t *sample;
  759.  
  760. testsustain:
  761.     if (ch->freqSusCounter > 0)
  762.     {
  763.         ch->freqSusCounter--;
  764.     }
  765.     else
  766.     {
  767.         tabPtr = &ch->freqTabPtr[ch->freqTabPos];
  768.  
  769. testeffects:
  770.         if (tabPtr[0] != 0xE1)
  771.         {
  772.             doTranspose = true;
  773.  
  774.             if (tabPtr[0] == 0xE0) // freq pos jump
  775.             {
  776.                 ch->freqTabPos = tabPtr[1] & 0x3F;
  777.                 tabPtr = &ch->freqTabPtr[ch->freqTabPos];
  778.             }
  779.  
  780.             if (tabPtr[0] == 0xE2) // set waveform
  781.             {
  782.                 if (tabPtr[1] < NUM_SAMPLES+NUM_WAVEFORMS)
  783.                 {
  784.                     sample = &samples[tabPtr[1]];
  785.  
  786.                     ch->loopStart = sample->repeat;
  787.                     ch->loopLength = sample->replen;
  788.  
  789.                     paulaSetData(ch->voiceIndex, sample->data);
  790.                     paulaSetLength(ch->voiceIndex, sample->length);
  791.                     paulaStartDMA(ch->voiceIndex);
  792.  
  793.                     ch->volTabPos = 0;
  794.                     ch->volDelayCounter = 1;
  795.                 }
  796.  
  797.                 ch->freqTabPos += 2;
  798.             }
  799.             else if (tabPtr[0] == 0xE4) // update waveform
  800.             {
  801.                 if (tabPtr[1] < NUM_SAMPLES+NUM_WAVEFORMS)
  802.                 {
  803.                     sample = &samples[tabPtr[1]];
  804.  
  805.                     ch->loopStart = sample->repeat;
  806.                     ch->loopLength = sample->replen;
  807.  
  808.                     paulaSetData(ch->voiceIndex, sample->data);
  809.                     paulaSetLength(ch->voiceIndex, sample->length);
  810.                 }
  811.  
  812.                 ch->freqTabPos += 2;
  813.             }
  814.             else if (tabPtr[0] == 0xE9) // set packed waveform
  815.             {
  816.                 if (tabPtr[1] < NUM_SAMPLES+NUM_WAVEFORMS)
  817.                 {
  818.                     sample = &samples[tabPtr[1]];
  819.                     if (*PTR2LONG(sample->data) == 0x504D5353) // "SSMP"
  820.                     {
  821.                         tmpPtr = (uint8_t *)&sample->data[4 + (tabPtr[2] * 16)];
  822.  
  823.                         ch->loopStart = &sample->data[(4 + 320 + *PTR2LONG(&tmpPtr[0])) + *PTR2WORD(&tmpPtr[6])];
  824.                         ch->loopLength = *PTR2WORD(&tmpPtr[8]);
  825.  
  826.                         // fix endless beep on non-looping samples (FC14 doesn't do this)
  827.                         if (ch->loopLength <= 1)
  828.                         {
  829.                             ch->loopLength = 1;
  830.                             if (*PTR2WORD(&tmpPtr[4]) >= 1) // sample length
  831.                                 *PTR2WORD(&sample->data[4 + 320 + *PTR2LONG(&tmpPtr[0])]) = 0;
  832.                         }
  833.  
  834.                         paulaSetData(ch->voiceIndex,  &sample->data[4 + 320 + *PTR2LONG(&tmpPtr[0])]);
  835.                         paulaSetLength(ch->voiceIndex, *PTR2WORD(&tmpPtr[4]));
  836.                         paulaStartDMA(ch->voiceIndex);
  837.  
  838.                         ch->volTabPos = 0;
  839.                         ch->volDelayCounter = 1;
  840.                     }
  841.                 }
  842.  
  843.                 ch->freqTabPos += 3;
  844.             }
  845.             else if (tabPtr[0] == 0xE7) // new freq pos
  846.             {
  847.                 tabPtr = &FRQpoint[(tabPtr[1] & 0x3F) << 6];
  848.  
  849.                 ch->freqTabPtr = tabPtr;
  850.                 ch->freqTabPos = 0;
  851.  
  852.                 goto testeffects;
  853.             }
  854.             else if (tabPtr[0] == 0xE8) // set freq sustain
  855.             {
  856.                 ch->freqSusCounter = tabPtr[1];
  857.  
  858.                 ch->freqTabPos += 2;
  859.                 goto testsustain;
  860.             }
  861.             else if (tabPtr[0] == 0xE3) // set vibrato
  862.             {
  863.                 ch->freqTabPos += 3;
  864.  
  865.                 ch->vibratoSpeed = tabPtr[1];
  866.                 ch->vibratoDepth = tabPtr[2];
  867.  
  868.                 doTranspose = false; // don't do period transpose here
  869.             }
  870.             else if (tabPtr[0] == 0xEA) // set pitch bend
  871.             {
  872.                 ch->pitchBendValue = (int8_t)tabPtr[1];
  873.                 ch->pitchBendCounter = (int8_t)tabPtr[2];
  874.  
  875.                 ch->freqTabPos += 3;
  876.             }
  877.  
  878.             if (doTranspose)
  879.                 ch->periodTranspose = (int8_t)ch->freqTabPtr[ch->freqTabPos++];
  880.         }
  881.     }
  882. }
  883.  
  884. static void do_VOLbend(fcChannel_t *ch)
  885. {
  886.     ch->volSlideDelay = !ch->volSlideDelay;
  887.     if (ch->volSlideDelay)
  888.     {
  889.         ch->volSlideCounter--;
  890.  
  891.         ch->volume += ch->volSlideSpeed;
  892.         if (ch->volume < 0)
  893.         {
  894.             ch->volSlideCounter = 0;
  895.             ch->volume = 0;
  896.         }
  897.     }
  898. }
  899.  
  900. static void doVolModulation(fcChannel_t *ch)
  901. {
  902.     const uint8_t *tabPtr;
  903.  
  904. VOLUfx:
  905.     if (ch->volSusCounter > 0)
  906.     {
  907.         ch->volSusCounter--;
  908.     }
  909.     else
  910.     {
  911.         if (ch->volSlideCounter > 0)
  912.         {
  913.             do_VOLbend(ch);
  914.         }
  915.         else
  916.         {
  917.             if (--ch->volDelayCounter == 0)
  918.             {
  919.                 ch->volDelayCounter = ch->volDelayLength;
  920. volu_cmd:
  921.                 tabPtr = &ch->volTabPtr[ch->volTabPos];
  922.  
  923.                 if (tabPtr[0] != 0xE1)
  924.                 {
  925.                     if (tabPtr[0] == 0xE8) // set vol sustain
  926.                     {
  927.                         ch->volSusCounter = tabPtr[1];
  928.                         ch->volTabPos += 2;
  929.  
  930.                         goto VOLUfx;
  931.                     }
  932.                     else if (tabPtr[0] == 0xEA) // set vol slide
  933.                     {
  934.                         ch->volSlideSpeed = tabPtr[1];
  935.                         ch->volSlideCounter = tabPtr[2];
  936.  
  937.                         ch->volTabPos += 3;
  938.                         do_VOLbend(ch);
  939.                     }
  940.                     else if (tabPtr[0] == 0xE0) // set vol pos
  941.                     {
  942.                         if ((int8_t)(tabPtr[1] & 0x3F)-5 < 0)
  943.                             ch->volTabPos = 0;
  944.                         else
  945.                             ch->volTabPos = (tabPtr[1] & 0x3F) - 5;
  946.  
  947.                         goto volu_cmd;
  948.                     }
  949.                     else
  950.                     {
  951.                         ch->volume = (int8_t)ch->volTabPtr[ch->volTabPos++];
  952.                     }
  953.                 }
  954.             }
  955.         }
  956.     }
  957. }
  958.  
  959. static void effects(fcChannel_t *ch)
  960. {
  961.     int8_t tmpNote;
  962.     int16_t tmpVibPeriod, tmpPeriod;
  963.     uint16_t tmpVibNote;
  964.  
  965.     doFreqModulation(ch);
  966.     doVolModulation(ch);
  967.  
  968.     // get period from note and transposes...
  969.     tmpNote = ch->periodTranspose;
  970.     if (tmpNote >= 0)
  971.     {
  972.         tmpNote += ch->note;
  973.         tmpNote += ch->noteTranspose;
  974.     }
  975.     tmpNote &= 0x7F;
  976.  
  977.     tmpPeriod = periods[tmpNote];
  978.  
  979.     // apply vibrato to period
  980.     if (ch->vibratoDelay > 0)
  981.     {
  982.         ch->vibratoDelay--;
  983.     }
  984.     else
  985.     {
  986.         tmpVibPeriod = ch->vibratoCounter;
  987.         if (!ch->vibratoUp)
  988.         {
  989.             tmpVibPeriod -= ch->vibratoSpeed;
  990.             if (tmpVibPeriod < 0)
  991.             {
  992.                 tmpVibPeriod = 0;
  993.                 ch->vibratoUp = true;
  994.             }
  995.         }
  996.         else
  997.         {
  998.             tmpVibPeriod += ch->vibratoSpeed;
  999.             if (tmpVibPeriod > ch->vibratoDepth*2)
  1000.             {
  1001.                 tmpVibPeriod = ch->vibratoDepth*2;
  1002.                 ch->vibratoUp = false;
  1003.             }
  1004.         }
  1005.         ch->vibratoCounter = tmpVibPeriod & 0xFF;
  1006.  
  1007.         tmpVibPeriod -= ch->vibratoDepth;
  1008.  
  1009.         tmpVibNote = tmpNote * 2;
  1010.         while (tmpVibNote < 12*8)
  1011.         {
  1012.             tmpVibPeriod *= 2;
  1013.             tmpVibNote += 12*2;
  1014.         }
  1015.  
  1016.         tmpPeriod += tmpVibPeriod;
  1017.     }
  1018.  
  1019.     // update portamento value (twice as slow on FC1.4)
  1020.     ch->portaDelay = !ch->portaDelay;
  1021.     if (!fc14 || ch->portaDelay)
  1022.     {
  1023.         if (ch->portaParam > 0)
  1024.         {
  1025.             if (ch->portaParam > 0x1F)
  1026.                 ch->portaValue += ch->portaParam & 0x1F;
  1027.             else
  1028.                 ch->portaValue -= ch->portaParam;
  1029.         }
  1030.     }
  1031.  
  1032.     // apply pitch bend to portamento value
  1033.     ch->pitchBendDelay = !ch->pitchBendDelay;
  1034.     if (ch->pitchBendDelay)
  1035.     {
  1036.         if (ch->pitchBendCounter > 0)
  1037.         {
  1038.             ch->pitchBendCounter--;
  1039.             ch->portaValue -= ch->pitchBendValue;
  1040.         }
  1041.     }
  1042.  
  1043.     tmpPeriod += ch->portaValue;
  1044.     tmpPeriod = CLAMP(tmpPeriod, 0x0071, fc14 ? 0x0D60 : 0x06B0);
  1045.  
  1046.     paulaSetPeriod(ch->voiceIndex, tmpPeriod);
  1047.     paulaSetVolume(ch->voiceIndex, ch->volume);
  1048. }
  1049.  
  1050. static void play_music(void)
  1051. {
  1052.     uint8_t i;
  1053.  
  1054.     if (--respcnt == 0)
  1055.     {
  1056.         respcnt = repspd;
  1057.         for (i = 0; i < AMIGA_VOICES; i++)
  1058.             new_note(&Channel[i]);
  1059.     }
  1060.  
  1061.     for (i = 0; i < AMIGA_VOICES; i++)
  1062.     {
  1063.         effects(&Channel[i]);
  1064.  
  1065.         // these take effect when the current DMA cycle is done
  1066.         paulaSetData(i, Channel[i].loopStart);
  1067.         paulaSetLength(i, Channel[i].loopLength);
  1068.     }
  1069. }
  1070.  
  1071. static void resetAudioDithering(void)
  1072. {
  1073.     randSeed = INITIAL_DITHER_SEED;
  1074.     dPrngStateL = 0.0;
  1075.     dPrngStateR = 0.0;
  1076. }
  1077.  
  1078. // Delphi/Pascal LCG Random() (without limit). Suitable for 32-bit random numbers
  1079. static inline int32_t random32(void)
  1080. {
  1081.     randSeed = randSeed * 134775813 + 1;
  1082.     return randSeed;
  1083. }
  1084.  
  1085. static void mixAudio(int16_t *stream, int32_t sampleBlockLength)
  1086. {
  1087.     int32_t i, j, smp32;
  1088.     double dPrng, dSample, dVolume, dOut[2];
  1089.     paulaVoice_t *v;
  1090. #ifdef USE_BLEP
  1091.     blep_t *bSmp, *bVol;
  1092. #endif
  1093.  
  1094.     memset(dMixerBufferL, 0, sizeof (double) * sampleBlockLength);
  1095.     memset(dMixerBufferR, 0, sizeof (double) * sampleBlockLength);
  1096.  
  1097.     if (musicPaused)
  1098.     {
  1099.         memset(stream, 0, sampleBlockLength * (sizeof (int16_t) * 2));
  1100.         return;
  1101.     }
  1102.  
  1103.     v = paula;
  1104.     for (i = 0; i < AMIGA_VOICES; i++, v++)
  1105.     {
  1106.         if (!v->active || v->length < 2 || v->data == NULL)
  1107.             continue;
  1108.  
  1109. #ifdef USE_BLEP
  1110.         bSmp = &blep[i];
  1111.         bVol = &blepVol[i];
  1112. #endif
  1113.         for (j = 0; j < sampleBlockLength; j++)
  1114.         {
  1115.             dSample = v->data[v->pos] * (1.0 / 128.0);
  1116.             dVolume = v->dVolume;
  1117.  
  1118. #ifdef USE_BLEP
  1119.             if (dSample != bSmp->dLastValue)
  1120.             {
  1121.                 if (v->dLastDelta > v->dLastPhase)
  1122.                 {
  1123.                     // div->mul trick: v->dLastDeltaMul is 1.0 / v->dLastDelta
  1124.                     blepAdd(bSmp, v->dLastPhase * v->dLastDeltaMul, bSmp->dLastValue - dSample);
  1125.                 }
  1126.  
  1127.                 bSmp->dLastValue = dSample;
  1128.             }
  1129.  
  1130.             if (dVolume != bVol->dLastValue)
  1131.             {
  1132.                 blepVolAdd(bVol, bVol->dLastValue - dVolume);
  1133.                 bVol->dLastValue = dVolume;
  1134.             }
  1135.  
  1136.             if (bSmp->samplesLeft > 0) dSample += blepRun(bSmp);
  1137.             if (bVol->samplesLeft > 0) dVolume += blepRun(bVol);
  1138. #endif
  1139.             dSample *= dVolume;
  1140.  
  1141.             dMixerBufferL[j] += dSample * v->dPanL;
  1142.             dMixerBufferR[j] += dSample * v->dPanR;
  1143.  
  1144.             v->dPhase += v->dDelta;
  1145.             if (v->dPhase >= 1.0)
  1146.             {
  1147.                 v->dPhase -= 1.0;
  1148. #ifdef USE_BLEP
  1149.                 v->dLastPhase = v->dPhase;
  1150.                 v->dLastDelta = v->dDelta;
  1151.                 v->dLastDeltaMul = v->dDeltaMul;
  1152. #endif
  1153.                 if (++v->pos >= v->length)
  1154.                 {
  1155.                     v->pos = 0;
  1156.  
  1157.                     // re-fetch Paula register values now
  1158.                     v->length = v->newLength;
  1159.                     v->data = v->newData;
  1160.                 }
  1161.             }
  1162.         }
  1163.     }
  1164.  
  1165.     for (i = 0; i < sampleBlockLength; i++)
  1166.     {
  1167.         dOut[0] = dMixerBufferL[i];
  1168.         dOut[1] = dMixerBufferR[i];
  1169.  
  1170. #ifdef USE_LOWPASS
  1171.         lossyIntegrator(&filterLo, dOut, dOut);
  1172. #endif
  1173.  
  1174. #ifdef USE_HIGHPASS
  1175.         lossyIntegratorHighPass(&filterHi, dOut, dOut);
  1176. #endif
  1177.  
  1178.         // normalize and flip phase (A500/A1200 has an inverted audio signal)
  1179.         dOut[0] *= -(INT16_MAX / AMIGA_VOICES);
  1180.         dOut[1] *= -(INT16_MAX / AMIGA_VOICES);
  1181.  
  1182.         // left channel - 1-bit triangular dithering (high-pass filtered)
  1183.         dPrng = random32() * (0.5 / INT32_MAX); // -0.5..0.5
  1184.         dOut[0] = (dOut[0] + dPrng) - dPrngStateL;
  1185.         dPrngStateL = dPrng;
  1186.         smp32 = (int32_t)dOut[0];
  1187.         smp32 = (smp32 * masterVol) >> 8;
  1188.         CLAMP16(smp32);
  1189.         *stream++ = (int16_t)smp32;
  1190.  
  1191.         // right channel - 1-bit triangular dithering (high-pass filtered)
  1192.         dPrng = random32() * (0.5 / INT32_MAX); // -0.5..0.5
  1193.         dOut[1] = (dOut[1] + dPrng) - dPrngStateR;
  1194.         dPrngStateR = dPrng;
  1195.         smp32 = (int32_t)dOut[1];
  1196.         smp32 = (smp32 * masterVol) >> 8;
  1197.         CLAMP16(smp32);
  1198.         *stream++ = (int16_t)smp32;
  1199.     }
  1200. }
  1201.  
  1202. // these are used to create an equal powered panning
  1203. static double sinApx(double fX)
  1204. {
  1205.     fX = fX * (2.0 - fX);
  1206.     return fX * 1.09742972 + fX * fX * 0.31678383;
  1207. }
  1208.  
  1209. static double cosApx(double fX)
  1210. {
  1211.     fX = (1.0 - fX) * (1.0 + fX);
  1212.     return fX * 1.09742972 + fX * fX * 0.31678383;
  1213. }
  1214. // -------------------------------------------------
  1215.  
  1216. static void calculatePans(uint8_t stereoSeparation)
  1217. {
  1218.     uint8_t scaledPanPos;
  1219.     double p;
  1220.  
  1221.     if (stereoSeparation > 100)
  1222.         stereoSeparation = 100;
  1223.  
  1224.     scaledPanPos = (stereoSeparation * 128) / 100;
  1225.  
  1226.     p = (128 - scaledPanPos) * (1.0 / 256.0);
  1227.     paula[0].dPanL = cosApx(p);
  1228.     paula[0].dPanR = sinApx(p);
  1229.     paula[3].dPanL = cosApx(p);
  1230.     paula[3].dPanR = sinApx(p);
  1231.  
  1232.     p = (128 + scaledPanPos) * (1.0 / 256.0);
  1233.     paula[1].dPanL = cosApx(p);
  1234.     paula[1].dPanR = sinApx(p);
  1235.     paula[2].dPanL = cosApx(p);
  1236.     paula[2].dPanR = sinApx(p);
  1237. }
  1238.  
  1239. void fc14play_FillAudioBuffer(int16_t *buffer, int32_t numSamples)
  1240. {
  1241.     int32_t a, b;
  1242.  
  1243.     a = numSamples;
  1244.     while (a > 0)
  1245.     {
  1246.         if (samplesPerFrameLeft == 0)
  1247.         {
  1248.             if (!musicPaused)
  1249.                 play_music();
  1250.  
  1251.             samplesPerFrameLeft = samplesPerFrame;
  1252.         }
  1253.  
  1254.         b = a;
  1255.         if (b > samplesPerFrameLeft)
  1256.             b = samplesPerFrameLeft;
  1257.  
  1258.         mixAudio(buffer, b);
  1259.         buffer += (uint32_t)b * 2;
  1260.  
  1261.         a -= b;
  1262.         samplesPerFrameLeft -= b;
  1263.     }
  1264.  
  1265.     sampleCounter += numSamples;
  1266. }
  1267.  
  1268. void fc14play_PauseSong(bool flag)
  1269. {
  1270.     musicPaused = flag;
  1271. }
  1272.  
  1273. void fc14play_TogglePause(void)
  1274. {
  1275.     musicPaused ^= 1;
  1276. }
  1277.  
  1278. void fc14play_Close(void)
  1279. {
  1280.     closeMixer();
  1281.  
  1282.     if (dMixerBufferL != NULL)
  1283.     {
  1284.         free(dMixerBufferL);
  1285.         dMixerBufferL = NULL;
  1286.     }
  1287.  
  1288.     if (dMixerBufferR != NULL)
  1289.     {
  1290.         free(dMixerBufferR);
  1291.         dMixerBufferR = NULL;
  1292.     }
  1293.  
  1294.     if (songData != NULL)
  1295.     {
  1296.         free(songData);
  1297.         songData = NULL;
  1298.     }
  1299. }
  1300.  
  1301. void fc14play_SetStereoSep(uint8_t percentage)
  1302. {
  1303.     stereoSep = percentage;
  1304.     if (stereoSep > 100)
  1305.         stereoSep = 100;
  1306.  
  1307.     calculatePans(stereoSep);
  1308. }
  1309.  
  1310. void fc14play_SetMasterVol(uint16_t vol)
  1311. {
  1312.     masterVol = CLAMP(vol, 0, 256);
  1313. }
  1314.  
  1315. uint16_t fc14play_GetMasterVol(void)
  1316. {
  1317.     return (uint16_t)masterVol;
  1318. }
  1319.  
  1320. uint32_t fc14play_GetMixerTicks(void)
  1321. {
  1322.     if (audioRate < 1000)
  1323.         return 0;
  1324.  
  1325.     return sampleCounter / (audioRate / 1000);
  1326. }
  1327.  
  1328. bool fc14play_PlaySong(const uint8_t *moduleData, uint32_t dataLength, uint32_t audioFreq)
  1329. {
  1330.     if (audioFreq == 0)
  1331.         audioFreq = 44100;
  1332.  
  1333.     musicPaused = true;
  1334.  
  1335.     fc14play_Close();
  1336.  
  1337.     oldPeriod = 0;
  1338.     oldVoiceDelta = 0.0;
  1339.     sampleCounter = 0;
  1340.  
  1341.     songData = (uint8_t *)malloc(dataLength);
  1342.     if (songData == NULL)
  1343.         return false;
  1344.  
  1345.     memcpy(songData, moduleData, dataLength);
  1346.     if (!init_music(songData))
  1347.     {
  1348.         fc14play_Close();
  1349.         return false;
  1350.     }
  1351.  
  1352.     dMixerBufferL = (double *)malloc(MIX_BUF_SAMPLES * sizeof (double));
  1353.     dMixerBufferR = (double *)malloc(MIX_BUF_SAMPLES * sizeof (double));
  1354.  
  1355.     if (dMixerBufferL == NULL || dMixerBufferR == NULL)
  1356.     {
  1357.         fc14play_Close();
  1358.         return false;
  1359.     }
  1360.  
  1361.     restart_song();
  1362.  
  1363.     // rates below 32kHz will mess up the BLEP synthesis
  1364.     audioFreq = CLAMP(audioFreq, 32000, 96000);
  1365.  
  1366.     if (!openMixer(audioFreq))
  1367.     {
  1368.         fc14play_Close();
  1369.         return false;
  1370.     }
  1371.  
  1372.     audioRate = audioFreq;
  1373.     dAudioRate = (double)audioFreq;
  1374.     dPeriodToDeltaDiv = (double)PAULA_PAL_CLK / dAudioRate;
  1375.     soundBufferSize = MIX_BUF_SAMPLES;
  1376.     samplesPerFrame = (uint32_t)round(dAudioRate / AMIGA_PAL_VBLANK_HZ);
  1377.  
  1378. #ifdef USE_LOWPASS
  1379.     // Amiga 500 rev6 RC low-pass filter (~4420.97Hz, 580Hz added to better match A500)
  1380.     calcCoeffLossyIntegrator(dAudioRate, 4420.97 + 580.0, &filterLo);
  1381. #endif
  1382.  
  1383. #ifdef USE_HIGHPASS
  1384.     // Amiga RC high-pass filter (~5.20Hz, 1.5Hz added to better match A500/A1200)
  1385.     calcCoeffLossyIntegrator(dAudioRate, 5.20 + 1.5, &filterHi);
  1386. #endif
  1387.  
  1388.     memset(paula, 0, sizeof (paula));
  1389.     calculatePans(stereoSep);
  1390.  
  1391. #ifdef USE_BLEP
  1392.     memset(blep, 0, sizeof (blep));
  1393.     memset(blepVol, 0, sizeof (blepVol));
  1394. #endif
  1395.  
  1396. #ifdef USE_LOWPASS
  1397.     clearLossyIntegrator(&filterLo);
  1398. #endif
  1399.  
  1400. #ifdef USE_HIGHPASS
  1401.     clearLossyIntegrator(&filterHi);
  1402. #endif
  1403.  
  1404.     resetAudioDithering();
  1405.  
  1406.     musicPaused = false;
  1407.     return true;
  1408. }
  1409.  
  1410. // the following must be changed if you want to use another audio API than WinMM
  1411.  
  1412. #ifndef WIN32_LEAN_AND_MEAN
  1413. #define WIN32_LEAN_AND_MEAN
  1414. #endif
  1415.  
  1416. #include <windows.h>
  1417. #include <mmsystem.h>
  1418.  
  1419. #define MIX_BUF_NUM 2
  1420.  
  1421. static volatile BOOL audioRunningFlag;
  1422. static uint8_t currBuffer;
  1423. static int16_t *mixBuffer[MIX_BUF_NUM];
  1424. static HANDLE hThread, hAudioSem;
  1425. static WAVEHDR waveBlocks[MIX_BUF_NUM];
  1426. static HWAVEOUT hWave;
  1427.  
  1428. static DWORD WINAPI mixThread(LPVOID lpParam)
  1429. {
  1430.     WAVEHDR *waveBlock;
  1431.  
  1432.     (void)lpParam;
  1433.  
  1434.     SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
  1435.  
  1436.     while (audioRunningFlag)
  1437.     {
  1438.         waveBlock = &waveBlocks[currBuffer];
  1439.         fc14play_FillAudioBuffer((int16_t *)waveBlock->lpData, MIX_BUF_SAMPLES);
  1440.         waveOutWrite(hWave, waveBlock, sizeof (WAVEHDR));
  1441.         currBuffer = (currBuffer + 1) % MIX_BUF_NUM;
  1442.  
  1443.         // wait for buffer fill request
  1444.         WaitForSingleObject(hAudioSem, INFINITE);
  1445.     }
  1446.  
  1447.     return 0;
  1448. }
  1449.  
  1450. static void CALLBACK waveProc(HWAVEOUT hWaveOut, UINT uMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2)
  1451. {
  1452.     // make compiler happy!
  1453.     (void)hWaveOut;
  1454.     (void)uMsg;
  1455.     (void)dwInstance;
  1456.     (void)dwParam1;
  1457.     (void)dwParam2;
  1458.  
  1459.     if (uMsg == WOM_DONE)
  1460.         ReleaseSemaphore(hAudioSem, 1, NULL);
  1461. }
  1462.  
  1463. static void closeMixer(void)
  1464. {
  1465.     int32_t i;
  1466.  
  1467.     audioRunningFlag = false; // make thread end when it's done
  1468.  
  1469.     if (hAudioSem != NULL)
  1470.         ReleaseSemaphore(hAudioSem, 1, NULL);
  1471.  
  1472.     if (hThread != NULL)
  1473.     {
  1474.         WaitForSingleObject(hThread, INFINITE);
  1475.         CloseHandle(hThread);
  1476.         hThread = NULL;
  1477.     }
  1478.  
  1479.     if (hAudioSem != NULL)
  1480.     {
  1481.         CloseHandle(hAudioSem);
  1482.         hAudioSem = NULL;
  1483.     }
  1484.  
  1485.     if (hWave != NULL)
  1486.     {
  1487.         waveOutReset(hWave);
  1488.  
  1489.         for (i = 0; i < MIX_BUF_NUM; i++)
  1490.         {
  1491.             if (waveBlocks[i].dwUser != 0xFFFF)
  1492.                 waveOutUnprepareHeader(hWave, &waveBlocks[i], sizeof (WAVEHDR));
  1493.         }
  1494.  
  1495.         waveOutClose(hWave);
  1496.         hWave = NULL;
  1497.     }
  1498.  
  1499.     for (i = 0; i < MIX_BUF_NUM; i++)
  1500.     {
  1501.         if (mixBuffer[i] != NULL)
  1502.         {
  1503.             free(mixBuffer[i]);
  1504.             mixBuffer[i] = NULL;
  1505.         }
  1506.     }
  1507. }
  1508.  
  1509. static bool openMixer(uint32_t audioFreq)
  1510. {
  1511.     int32_t i;
  1512.     DWORD threadID;
  1513.     WAVEFORMATEX wfx;
  1514.  
  1515.     // don't unprepare headers on error
  1516.     for (i = 0; i < MIX_BUF_NUM; i++)
  1517.         waveBlocks[i].dwUser = 0xFFFF;
  1518.  
  1519.     closeMixer();
  1520.  
  1521.     ZeroMemory(&wfx, sizeof (wfx));
  1522.     wfx.nSamplesPerSec = audioFreq;
  1523.     wfx.wBitsPerSample = 16;
  1524.     wfx.nChannels = 2;
  1525.     wfx.wFormatTag = WAVE_FORMAT_PCM;
  1526.     wfx.nBlockAlign = wfx.nChannels * (wfx.wBitsPerSample / 8);
  1527.     wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
  1528.  
  1529.     samplesPerFrameLeft = 0;
  1530.     currBuffer = 0;
  1531.  
  1532.     if (waveOutOpen(&hWave, WAVE_MAPPER, &wfx, (DWORD_PTR)&waveProc, 0, CALLBACK_FUNCTION) != MMSYSERR_NOERROR)
  1533.         goto omError;
  1534.  
  1535.     // create semaphore for buffer fill requests
  1536.     hAudioSem = CreateSemaphore(NULL, MIX_BUF_NUM - 1, MIX_BUF_NUM, NULL);
  1537.     if (hAudioSem == NULL)
  1538.         goto omError;
  1539.  
  1540.     // allocate WinMM mix buffers
  1541.     for (i = 0; i < MIX_BUF_NUM; i++)
  1542.     {
  1543.         mixBuffer[i] = (int16_t *)calloc(MIX_BUF_SAMPLES, wfx.nBlockAlign);
  1544.         if (mixBuffer[i] == NULL)
  1545.             goto omError;
  1546.     }
  1547.  
  1548.     // initialize WinMM mix headers
  1549.  
  1550.     memset(waveBlocks, 0, sizeof (waveBlocks));
  1551.     for (i = 0; i < MIX_BUF_NUM; i++)
  1552.     {
  1553.         waveBlocks[i].lpData = (LPSTR)mixBuffer[i];
  1554.         waveBlocks[i].dwBufferLength = MIX_BUF_SAMPLES * wfx.nBlockAlign;
  1555.         waveBlocks[i].dwFlags = WHDR_DONE;
  1556.  
  1557.         if (waveOutPrepareHeader(hWave, &waveBlocks[i], sizeof (WAVEHDR)) != MMSYSERR_NOERROR)
  1558.             goto omError;
  1559.     }
  1560.  
  1561.     // create main mixer thread
  1562.     audioRunningFlag = true;
  1563.     hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)mixThread, NULL, 0, &threadID);
  1564.     if (hThread == NULL)
  1565.         goto omError;
  1566.  
  1567.     return TRUE;
  1568.  
  1569. omError:
  1570.     closeMixer();
  1571.     return FALSE;
  1572. }
  1573.  
  1574. // ---------------------------------------------------------------------------
  1575.  
  1576. // END OF FILE
RAW Paste Data
Ledger Nano X - The secure hardware wallet
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