Advertisement
8bitbubsy

fc14play v1.29

Nov 17th, 2015
2,215
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 39.88 KB | None | 0 0
  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
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement