daily pastebin goal
63%
SHARE
TWEET

fc14play v1.23

8bitbubsy Nov 17th, 2015 (edited) 590 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /*
  2. ** FC14PLAY v1.23 - 14th of October 2018 - 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 perfectly 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, 44100);
  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 from v1.22:
  29. ** - WinMM mixer has been rewritten to be safe (DON'T use syscalls in callback -MSDN)
  30. ** - Some small changes to the fc14play functions (easier to use and safer!)
  31. */
  32.  
  33. /* fc14play.h:
  34.  
  35. #ifndef __FC14PLAY_H
  36. #define __FC14PLAY_H
  37.  
  38. #include <stdint.h>
  39.  
  40. int8_t fc14play_PlaySong(const uint8_t *moduleData, uint32_t dataLength, uint32_t outputFreq);
  41. void fc14play_Close(void);
  42. void fc14play_PauseSong(int8_t flag); // true/false
  43. void fc14play_TogglePause(void);
  44. void fc14play_SetStereoSep(uint8_t percentage); // 0..100
  45. uint32_t fc14play_GetMixerTicks(void); // returns the amount of milliseconds passed in the mixer
  46.  
  47. #endif
  48. */
  49.  
  50. /* == USER ADJUSTABLE SETTINGS == */
  51. #define STEREO_SEP (19)    /* --> Initial stereo separation in percent - 0 = mono, 100 = hard pan (like Amiga) */
  52. #define NORM_FACTOR (4.0f) /* --> Slightly increase this value if the song is too loud. Decrease if too quiet... */
  53. #define USE_HIGHPASS       /* --> 5.2Hz high-pass filter present in all Amigas - comment out for a speed-up  */
  54. //#define USE_LOWPASS      /* --> 4.4kHz low-pass filter in all Amigas except A1200 - comment out for sharper sound */
  55. #define USE_BLEP           /* --> Reduces some unwanted aliasing (closer to real Amiga) - comment out for a speed-up */
  56. #define MIX_BUF_SAMPLES 4096
  57.  
  58. #ifdef _MSC_VER
  59. #define inline __forceinline
  60. #endif
  61.  
  62. #ifndef true
  63. #define true 1
  64. #define false 0
  65. #endif
  66.  
  67. #include <stdio.h>
  68. #include <stdlib.h>
  69. #include <string.h>
  70. #include <stdint.h>
  71. #include <math.h> /* tanf() */
  72.  
  73. #define PAULA_PAL_CLK 3546895
  74. #define AMIGA_VBLANK_RATE 50 /* 60 for NTSC replay speed */
  75.  
  76. #define SEQ_SIZE 13
  77. #define PAT_MAX_SIZE 64
  78. #define PAT_END_MARKER 0x49
  79. #define VOL_TAB_SIZE 64
  80. #define FREQ_TAB_SIZE 64
  81. #define NUM_SAMPLES 10
  82. #define NUM_WAVEFORMS 80
  83. #define NUM_WAVEFORMS_SMOD 47
  84.  
  85. /* BLEP CONSTANTS */
  86. #define BLEP_ZC 8
  87. #define BLEP_OS 5
  88. #define BLEP_SP 5
  89. #define BLEP_NS (BLEP_ZC * BLEP_OS / BLEP_SP)
  90. #define BLEP_RNS 7 /* RNS = (2^ > NS) - 1 */
  91.  
  92. /* STRUCTS */
  93. typedef struct blep_t
  94. {
  95.     int32_t index, samplesLeft;
  96.     float buffer[BLEP_RNS + 1], lastValue;
  97. } blep_t;
  98.  
  99. typedef struct lossyIntegrator_t
  100. {
  101.     float buffer[2], coeff[2];
  102. } lossyIntegrator_t;
  103.  
  104. typedef struct ledFilter_t
  105. {
  106.     float led[4];
  107. } ledFilter_t;
  108.  
  109. typedef struct ledFilterCoeff_t
  110. {
  111.     float led, ledFb;
  112. } ledFilterCoeff_t;
  113.  
  114. typedef struct paulaVoice_t
  115. {
  116.     volatile uint8_t DMA_ON;
  117.     const int8_t *SRC_DAT, *DMA_DAT;
  118.     int32_t SRC_LEN, DMA_LEN, DMA_POS;
  119.     float SRC_VOL, DELTA, FRAC, LASTDELTA, LASTFRAC, PANL, PANR;
  120. } paulaVoice_t;
  121.  
  122. typedef struct soundInfo_t
  123. {
  124.     /* don't change the order of these */
  125.     int8_t *data;
  126.     uint16_t length;
  127.     int8_t *repeat;
  128.     uint16_t replen;
  129. } soundInfo_t;
  130.  
  131. typedef struct fcChannel_t
  132. {
  133.     int8_t pitchBendValue, pitchBendCounter, note, noteTranspose;
  134.     int8_t soundTranspose, *loopStart, volume, periodTranspose;
  135.     uint8_t voiceIndex, *seqStartPtr, *patPtr, *freqTabPtr;
  136.     uint8_t freqSusCounter, *volTabPtr, volSusCounter, DMAWaitFrames;
  137.     uint8_t pitchBendDelay, vibratoSpeed, vibratoDepth, vibratoCounter;
  138.     uint8_t vibratoDelay, vibratoUp, volSlideSpeed, volSlideDelay;
  139.     uint8_t volSlideCounter, portaParam, portaDelay, volDelayCounter;
  140.     uint8_t volDelayLength;
  141.     int16_t portaValue;
  142.     uint16_t loopLength, freqTabPos, volTabPos, patPos;
  143.     uint32_t seqPos;
  144. } fcChannel_t;
  145.  
  146. /* STATIC DATA */
  147.  
  148. static int8_t initdone, *ptr8s_1, *ptr8s_1;
  149. static uint8_t *songData, *ptr8u_1, *ptr8u_2, spdtemp, spdtemp2, respcnt, repspd, musicPaused;
  150. static uint8_t fc14, *SEQpoint, *PATpoint, *FRQpoint, *VOLpoint, stereoSep = STEREO_SEP;
  151. static int32_t soundBufferSize, samplesPerFrameLeft, samplesPerFrame;
  152. static uint32_t audioFreq, numSequences, sampleCounter;
  153. static float *mixerBufferL, *mixerBufferR, f_outputFreq;
  154. static paulaVoice_t AUD[4];
  155. static fcChannel_t Channel[4];
  156. static soundInfo_t samples[NUM_SAMPLES + NUM_WAVEFORMS];
  157.  
  158. #ifdef USE_BLEP
  159. static blep_t blep[4], blepVol[4];
  160. #endif
  161. #ifdef USE_HIGHPASS
  162. static lossyIntegrator_t filterHi;
  163. #endif
  164. #ifdef USE_LOWPASS
  165. static lossyIntegrator_t filterLo;
  166. #endif
  167.  
  168. /* MACROS */
  169.  
  170. #define LERP(x, y, z) ((x) + ((y) - (x)) * (z))
  171. #define CLAMP(x, low, high) (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x)))
  172. #define CLAMP16(i) \
  173. { \
  174.     if ((int16_t)(i) != i) \
  175.         i = 0x7FFF ^ (i >> 31); \
  176. }
  177.  
  178. #define PTR2LONG(x) ((uint32_t *)(x))
  179. #define PTR2WORD(x) ((uint16_t *)(x))
  180. #define SWAP16(x) ((uint16_t)(((x) << 8) | ((x) >> 8)))
  181. #define SWAP32(value) \
  182. ( \
  183.     (((uint32_t)((value) & 0x000000FF)) << 24) | \
  184.     (((uint32_t)((value) & 0x0000FF00)) <<  8) | \
  185.     (((uint32_t)((value) & 0x00FF0000)) >>  8) | \
  186.     (((uint32_t)((value) & 0xFF000000)) >> 24)   \
  187. )
  188.  
  189. /* TABLES */
  190.  
  191. static uint8_t silentTable[8] = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE1 };
  192.  
  193. static const uint16_t periods[128] =
  194. {
  195.     // 1.0..1.3 periods
  196.     0x06B0, 0x0650, 0x05F4, 0x05A0, 0x054C, 0x0500, 0x04B8, 0x0474,
  197.     0x0434, 0x03F8, 0x03C0, 0x038A, 0x0358, 0x0328, 0x02FA, 0x02D0,
  198.     0x02A6, 0x0280, 0x025C, 0x023A, 0x021A, 0x01FC, 0x01E0, 0x01C5,
  199.     0x01AC, 0x0194, 0x017D, 0x0168, 0x0153, 0x0140, 0x012E, 0x011D,
  200.     0x010D, 0x00FE, 0x00F0, 0x00E2, 0x00D6, 0x00CA, 0x00BE, 0x00B4,
  201.     0x00AA, 0x00A0, 0x0097, 0x008F, 0x0087, 0x007F, 0x0078, 0x0071,
  202.     0x0071, 0x0071, 0x0071, 0x0071, 0x0071, 0x0071, 0x0071, 0x0071,
  203.     0x0071, 0x0071, 0x0071, 0x0071,
  204.  
  205.     // 1.4 periods
  206.     0x0D60, 0x0CA0, 0x0BE8, 0x0B40, 0x0A98, 0x0A00, 0x0970, 0x08E8,
  207.     0x0868, 0x07F0, 0x0780, 0x0714, 0x06B0, 0x0650, 0x05F4, 0x05A0,
  208.     0x054C, 0x0500, 0x04B8, 0x0474, 0x0434, 0x03F8, 0x03C0, 0x038A,
  209.     0x0358, 0x0328, 0x02FA, 0x02D0, 0x02A6, 0x0280, 0x025C, 0x023A,
  210.     0x021A, 0x01FC, 0x01E0, 0x01C5, 0x01AC, 0x0194, 0x017D, 0x0168,
  211.     0x0153, 0x0140, 0x012E, 0x011D, 0x010D, 0x00FE, 0x00F0, 0x00E2,
  212.     0x00D6, 0x00CA, 0x00BE, 0x00B4, 0x00AA, 0x00A0, 0x0097, 0x008F,
  213.     0x0087, 0x007F, 0x0078, 0x0071, 0x0071, 0x0071, 0x0071, 0x0071,
  214.     0x0071, 0x0071, 0x0071, 0x0071
  215. };
  216.  
  217. static const int8_t waveformDatas[1344] =
  218. {
  219.     0xC0,0xC0,0xD0,0xD8,0xE0,0xE8,0xF0,0xF8,0x00,0xF8,0xF0,0xE8,0xE0,0xD8,0xD0,0xC8,
  220.     0x3F,0x37,0x2F,0x27,0x1F,0x17,0x0F,0x07,0xFF,0x07,0x0F,0x17,0x1F,0x27,0x2F,0x37,
  221.     0xC0,0xC0,0xD0,0xD8,0xE0,0xE8,0xF0,0xF8,0x00,0xF8,0xF0,0xE8,0xE0,0xD8,0xD0,0xC8,
  222.     0xC0,0x37,0x2F,0x27,0x1F,0x17,0x0F,0x07,0xFF,0x07,0x0F,0x17,0x1F,0x27,0x2F,0x37,
  223.     0xC0,0xC0,0xD0,0xD8,0xE0,0xE8,0xF0,0xF8,0x00,0xF8,0xF0,0xE8,0xE0,0xD8,0xD0,0xC8,
  224.     0xC0,0xB8,0x2F,0x27,0x1F,0x17,0x0F,0x07,0xFF,0x07,0x0F,0x17,0x1F,0x27,0x2F,0x37,
  225.     0xC0,0xC0,0xD0,0xD8,0xE0,0xE8,0xF0,0xF8,0x00,0xF8,0xF0,0xE8,0xE0,0xD8,0xD0,0xC8,
  226.     0xC0,0xB8,0xB0,0x27,0x1F,0x17,0x0F,0x07,0xFF,0x07,0x0F,0x17,0x1F,0x27,0x2F,0x37,
  227.     0xC0,0xC0,0xD0,0xD8,0xE0,0xE8,0xF0,0xF8,0x00,0xF8,0xF0,0xE8,0xE0,0xD8,0xD0,0xC8,
  228.     0xC0,0xB8,0xB0,0xA8,0x1F,0x17,0x0F,0x07,0xFF,0x07,0x0F,0x17,0x1F,0x27,0x2F,0x37,
  229.     0xC0,0xC0,0xD0,0xD8,0xE0,0xE8,0xF0,0xF8,0x00,0xF8,0xF0,0xE8,0xE0,0xD8,0xD0,0xC8,
  230.     0xC0,0xB8,0xB0,0xA8,0xA0,0x17,0x0F,0x07,0xFF,0x07,0x0F,0x17,0x1F,0x27,0x2F,0x37,
  231.     0xC0,0xC0,0xD0,0xD8,0xE0,0xE8,0xF0,0xF8,0x00,0xF8,0xF0,0xE8,0xE0,0xD8,0xD0,0xC8,
  232.     0xC0,0xB8,0xB0,0xA8,0xA0,0x98,0x0F,0x07,0xFF,0x07,0x0F,0x17,0x1F,0x27,0x2F,0x37,
  233.     0xC0,0xC0,0xD0,0xD8,0xE0,0xE8,0xF0,0xF8,0x00,0xF8,0xF0,0xE8,0xE0,0xD8,0xD0,0xC8,
  234.     0xC0,0xB8,0xB0,0xA8,0xA0,0x98,0x90,0x07,0xFF,0x07,0x0F,0x17,0x1F,0x27,0x2F,0x37,
  235.     0xC0,0xC0,0xD0,0xD8,0xE0,0xE8,0xF0,0xF8,0x00,0xF8,0xF0,0xE8,0xE0,0xD8,0xD0,0xC8,
  236.     0xC0,0xB8,0xB0,0xA8,0xA0,0x98,0x90,0x88,0xFF,0x07,0x0F,0x17,0x1F,0x27,0x2F,0x37,
  237.     0xC0,0xC0,0xD0,0xD8,0xE0,0xE8,0xF0,0xF8,0x00,0xF8,0xF0,0xE8,0xE0,0xD8,0xD0,0xC8,
  238.     0xC0,0xB8,0xB0,0xA8,0xA0,0x98,0x90,0x88,0x80,0x07,0x0F,0x17,0x1F,0x27,0x2F,0x37,
  239.     0xC0,0xC0,0xD0,0xD8,0xE0,0xE8,0xF0,0xF8,0x00,0xF8,0xF0,0xE8,0xE0,0xD8,0xD0,0xC8,
  240.     0xC0,0xB8,0xB0,0xA8,0xA0,0x98,0x90,0x88,0x80,0x88,0x0F,0x17,0x1F,0x27,0x2F,0x37,
  241.     0xC0,0xC0,0xD0,0xD8,0xE0,0xE8,0xF0,0xF8,0x00,0xF8,0xF0,0xE8,0xE0,0xD8,0xD0,0xC8,
  242.     0xC0,0xB8,0xB0,0xA8,0xA0,0x98,0x90,0x88,0x80,0x88,0x90,0x17,0x1F,0x27,0x2F,0x37,
  243.     0xC0,0xC0,0xD0,0xD8,0xE0,0xE8,0xF0,0xF8,0x00,0xF8,0xF0,0xE8,0xE0,0xD8,0xD0,0xC8,
  244.     0xC0,0xB8,0xB0,0xA8,0xA0,0x98,0x90,0x88,0x80,0x88,0x90,0x98,0x1F,0x27,0x2F,0x37,
  245.     0xC0,0xC0,0xD0,0xD8,0xE0,0xE8,0xF0,0xF8,0x00,0xF8,0xF0,0xE8,0xE0,0xD8,0xD0,0xC8,
  246.     0xC0,0xB8,0xB0,0xA8,0xA0,0x98,0x90,0x88,0x80,0x88,0x90,0x98,0xA0,0x27,0x2F,0x37,
  247.     0xC0,0xC0,0xD0,0xD8,0xE0,0xE8,0xF0,0xF8,0x00,0xF8,0xF0,0xE8,0xE0,0xD8,0xD0,0xC8,
  248.     0xC0,0xB8,0xB0,0xA8,0xA0,0x98,0x90,0x88,0x80,0x88,0x90,0x98,0xA0,0xA8,0x2F,0x37,
  249.     0xC0,0xC0,0xD0,0xD8,0xE0,0xE8,0xF0,0xF8,0x00,0xF8,0xF0,0xE8,0xE0,0xD8,0xD0,0xC8,
  250.     0xC0,0xB8,0xB0,0xA8,0xA0,0x98,0x90,0x88,0x80,0x88,0x90,0x98,0xA0,0xA8,0xB0,0x37,
  251.     0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,
  252.     0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,
  253.     0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,
  254.     0x81,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,
  255.     0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,
  256.     0x81,0x81,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,
  257.     0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,
  258.     0x81,0x81,0x81,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,
  259.     0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,
  260.     0x81,0x81,0x81,0x81,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,
  261.     0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,
  262.     0x81,0x81,0x81,0x81,0x81,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,
  263.     0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,
  264.     0x81,0x81,0x81,0x81,0x81,0x81,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,
  265.     0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,
  266.     0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,
  267.     0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,
  268.     0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,
  269.     0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,
  270.     0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,
  271.     0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,
  272.     0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,
  273.     0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,
  274.     0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x7F,0x7F,0x7F,0x7F,0x7F,
  275.     0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,
  276.     0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x7F,0x7F,0x7F,0x7F,
  277.     0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,
  278.     0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x7F,0x7F,0x7F,
  279.     0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
  280.     0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x7F,0x7F,
  281.     0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
  282.     0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x7F,
  283.     0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,
  284.     0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,
  285.     0x80,0x80,0x80,0x80,0x80,0x80,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,
  286.     0x80,0x80,0x80,0x80,0x80,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,
  287.     0x80,0x80,0x80,0x80,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,
  288.     0x80,0x80,0x80,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,
  289.     0x80,0x80,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,
  290.     0x80,0x80,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,
  291.     0x80,0x80,0x90,0x98,0xA0,0xA8,0xB0,0xB8,0xC0,0xC8,0xD0,0xD8,0xE0,0xE8,0xF0,0xF8,
  292.     0x00,0x08,0x10,0x18,0x20,0x28,0x30,0x38,0x40,0x48,0x50,0x58,0x60,0x68,0x70,0x7F,
  293.     0x80,0x80,0xA0,0xB0,0xC0,0xD0,0xE0,0xF0,0x00,0x10,0x20,0x30,0x40,0x50,0x60,0x70,
  294.     0x45,0x45,0x79,0x7D,0x7A,0x77,0x70,0x66,0x61,0x58,0x53,0x4D,0x2C,0x20,0x18,0x12,
  295.     0x04,0xDB,0xD3,0xCD,0xC6,0xBC,0xB5,0xAE,0xA8,0xA3,0x9D,0x99,0x93,0x8E,0x8B,0x8A,
  296.     0x45,0x45,0x79,0x7D,0x7A,0x77,0x70,0x66,0x5B,0x4B,0x43,0x37,0x2C,0x20,0x18,0x12,
  297.     0x04,0xF8,0xE8,0xDB,0xCF,0xC6,0xBE,0xB0,0xA8,0xA4,0x9E,0x9A,0x95,0x94,0x8D,0x83,
  298.     0x00,0x00,0x40,0x60,0x7F,0x60,0x40,0x20,0x00,0xE0,0xC0,0xA0,0x80,0xA0,0xC0,0xE0,
  299.     0x00,0x00,0x40,0x60,0x7F,0x60,0x40,0x20,0x00,0xE0,0xC0,0xA0,0x80,0xA0,0xC0,0xE0,
  300.     0x80,0x80,0x90,0x98,0xA0,0xA8,0xB0,0xB8,0xC0,0xC8,0xD0,0xD8,0xE0,0xE8,0xF0,0xF8,
  301.     0x00,0x08,0x10,0x18,0x20,0x28,0x30,0x38,0x40,0x48,0x50,0x58,0x60,0x68,0x70,0x7F,
  302.     0x80,0x80,0xA0,0xB0,0xC0,0xD0,0xE0,0xF0,0x00,0x10,0x20,0x30,0x40,0x50,0x60,0x70
  303. };
  304.  
  305. #ifdef USE_BLEP
  306. static const uint32_t blepData[48] =
  307. {
  308.     0x3F7FE1F1, 0x3F7FD548, 0x3F7FD6A3, 0x3F7FD4E3, 0x3F7FAD85, 0x3F7F2152,
  309.     0x3F7DBFAE, 0x3F7ACCDF, 0x3F752F1E, 0x3F6B7384, 0x3F5BFBCB, 0x3F455CF2,
  310.     0x3F26E524, 0x3F0128C4, 0x3EACC7DC, 0x3E29E86B, 0x3C1C1D29, 0xBDE4BBE6,
  311.     0xBE3AAE04, 0xBE48DEDD, 0xBE22AD7E, 0xBDB2309A, 0xBB82B620, 0x3D881411,
  312.     0x3DDADBF3, 0x3DE2C81D, 0x3DAAA01F, 0x3D1E769A, 0xBBC116D7, 0xBD1402E8,
  313.     0xBD38A069, 0xBD0C53BB, 0xBC3FFB8C, 0x3C465FD2, 0x3CEA5764, 0x3D0A51D6,
  314.     0x3CEAE2D5, 0x3C92AC5A, 0x3BE4CBF7, 0x00000000, 0x00000000, 0x00000000,
  315.     0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000
  316. };
  317. #endif
  318.  
  319. static const uint8_t waveformLengths[47] =
  320. {
  321.     0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
  322.     0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
  323.     0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
  324.     0x10, 0x10, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
  325.     0x10, 0x08, 0x10, 0x10, 0x08, 0x08, 0x18
  326. };
  327.  
  328. static int8_t openMixer(uint32_t outputFreq);
  329. static void closeMixer(void);
  330.  
  331. /* CODE START */
  332.  
  333. static void PaulaTurnOffDMA(uint8_t i)
  334. {
  335.     AUD[i].DMA_ON = false;
  336. }
  337.  
  338. static void PaulaRestartDMA(uint8_t i)
  339. {
  340.     int32_t len;
  341.  
  342.     len = AUD[i].SRC_LEN;
  343.     if (len < 2)
  344.         len = 2;
  345.  
  346.     AUD[i].FRAC    = 0.0f;
  347.     AUD[i].DMA_POS = 0;
  348.     AUD[i].DMA_DAT = AUD[i].SRC_DAT;
  349.     AUD[i].DMA_LEN = len;
  350.     AUD[i].DMA_ON  = true;
  351. }
  352.  
  353. static void PaulaSetPeriod(uint8_t i, uint16_t period)
  354. {
  355.     if (period == 0)
  356.     {
  357.         AUD[i].DELTA = 0.0f;
  358.     }
  359.     else
  360.     {
  361.         /* confirmed behavior on real Amiga */
  362.         if (period < 113)
  363.             period = 113;
  364.  
  365.         AUD[i].DELTA = ((float)(PAULA_PAL_CLK) / period) / f_outputFreq;
  366.     }
  367. }
  368.  
  369. static void PaulaSetVolume(uint8_t i, uint16_t vol)
  370. {
  371.     vol &= 0x007F;
  372.     if (vol > 0x40)
  373.         vol = 0x40;
  374.  
  375.     AUD[i].SRC_VOL = vol * (1.0f / 64.0f);
  376. }
  377.  
  378. static void PaulaSetLength(uint8_t i, uint16_t len)
  379. {
  380.     AUD[i].SRC_LEN = 2 * len;
  381. }
  382.  
  383. static void PaulaSetData(uint8_t i, const int8_t *src)
  384. {
  385.     AUD[i].SRC_DAT = src;
  386. }
  387.  
  388. #if defined(USE_HIGHPASS) || defined(USE_LOWPASS)
  389. static void calcCoeffLossyIntegrator(float sr, float hz, lossyIntegrator_t *filter)
  390. {
  391.     filter->coeff[0] = tanf((3.1415927f * hz) / sr);
  392.     filter->coeff[1] = 1.0f / (1.0f + filter->coeff[0]);
  393. }
  394.  
  395. static void clearLossyIntegrator(lossyIntegrator_t *filter)
  396. {
  397.     filter->buffer[0] = 0.0f;
  398.     filter->buffer[1] = 0.0f;
  399. }
  400.  
  401. static inline void lossyIntegrator(lossyIntegrator_t *filter, float *in, float *out)
  402. {
  403.     float output;
  404.  
  405.     /* left channel low-pass */
  406.     output = (filter->coeff[0] * in[0] + filter->buffer[0]) * filter->coeff[1];
  407.     filter->buffer[0] = filter->coeff[0] * (in[0] - output) + output + 1e-10f;
  408.     out[0] = output;
  409.  
  410.     /* right channel low-pass */
  411.     output = (filter->coeff[0] * in[1] + filter->buffer[1]) * filter->coeff[1];
  412.     filter->buffer[1] = filter->coeff[0] * (in[1] - output) + output + 1e-10f;
  413.     out[1] = output;
  414. }
  415.  
  416. static inline void lossyIntegratorHighPass(lossyIntegrator_t *filter, float *in, float *out)
  417. {
  418.     float low[2];
  419.  
  420.     lossyIntegrator(filter, in, low);
  421.  
  422.     out[0] = in[0] - low[0];
  423.     out[1] = in[1] - low[1];
  424. }
  425. #endif
  426.  
  427. #ifdef USE_BLEP
  428. static inline void blepAdd(blep_t *b, float offset, float amplitude)
  429. {
  430.     int8_t n;
  431.     uint32_t i;
  432.     const float *blepSrc;
  433.     float f;
  434.  
  435.     i  = (uint32_t)(offset * BLEP_SP);
  436.     blepSrc = (const float *)(blepData) + i + BLEP_OS;
  437.  
  438.     f = (offset * BLEP_SP) - i;
  439.     i = b->index;
  440.     n = BLEP_NS;
  441.  
  442.     while (n--)
  443.     {
  444.         b->buffer[i] += (amplitude * LERP(blepSrc[0], blepSrc[1], f));
  445.         blepSrc += BLEP_SP;
  446.  
  447.         i++;
  448.         i &= BLEP_RNS;
  449.     }
  450.  
  451.     b->samplesLeft = BLEP_NS;
  452. }
  453.  
  454. static inline float blepRun(blep_t *b)
  455. {
  456.     float blepOutput;
  457.  
  458.     blepOutput = b->buffer[b->index];
  459.     b->buffer[b->index] = 0.0f;
  460.  
  461.     b->index++;
  462.     b->index &= BLEP_RNS;
  463.  
  464.     b->samplesLeft--;
  465.  
  466.     return (blepOutput);
  467. }
  468. #endif
  469.  
  470. static int8_t init_music(const uint8_t *moduleData)
  471. {
  472.     uint8_t i;
  473.  
  474.     /* "SMOD" and "FC14" */
  475.     if ((*PTR2LONG(&moduleData[0]) != 0x444F4D53) && (*PTR2LONG(&moduleData[0]) != 0x34314346))
  476.         return (false);
  477.  
  478.     fc14 = (*PTR2LONG(&moduleData[0]) == 0x34314346);
  479.  
  480.     /* setup pointers... */
  481.  
  482.     SEQpoint = (uint8_t *)(&moduleData[fc14 ? 180 : 100]);
  483.     PATpoint = (uint8_t *)(&moduleData[SWAP32(*PTR2LONG(&moduleData[8]))]);
  484.     FRQpoint = (uint8_t *)(&moduleData[SWAP32(*PTR2LONG(&moduleData[16]))]);
  485.     VOLpoint = (uint8_t *)(&moduleData[SWAP32(*PTR2LONG(&moduleData[24]))]);
  486.  
  487.     /* load samples */
  488.  
  489.     ptr8s_1 =  (int8_t *)(&moduleData[SWAP32(*PTR2LONG(&moduleData[32]))]);
  490.     ptr8u_2 = (uint8_t *)(&moduleData[40]);
  491.     for (i = 0; i < NUM_SAMPLES; ++i)
  492.     {
  493.         samples[i].data   = ptr8s_1;
  494.         samples[i].length = SWAP16(*PTR2WORD(ptr8u_2));                   ptr8u_2 += 2;
  495.         samples[i].repeat = &samples[i].data[SWAP16(*PTR2WORD(ptr8u_2))]; ptr8u_2 += 2;
  496.         samples[i].replen = SWAP16(*PTR2WORD(ptr8u_2));                   ptr8u_2 += 2;
  497.  
  498.         /* fix endless beep on non-looping samples (FC14 doesn't do this) */
  499.         if (samples[i].replen <= 1)
  500.         {
  501.             samples[i].replen = 1;
  502.             if (samples[i].length >= 1)
  503.             {
  504.                 if (*PTR2LONG(samples[i].data) != 0x504D5353) /* "SSMP" */
  505.                     *PTR2WORD(samples[i].data)  = 0;
  506.             }
  507.         }
  508.  
  509.         ptr8s_1 += ((samples[i].length * 2) + 2);
  510.     }
  511.  
  512.     /* load waveforms */
  513.  
  514.     if (fc14)
  515.     {
  516.         ptr8s_1 =  (int8_t *)(&moduleData[SWAP32(*PTR2LONG(&moduleData[36]))]);
  517.         ptr8u_2 = (uint8_t *)(&moduleData[100]);
  518.         for (i = 0; i < NUM_WAVEFORMS; ++i)
  519.         {
  520.             samples[NUM_SAMPLES + i].data   = ptr8s_1;
  521.             samples[NUM_SAMPLES + i].length = *ptr8u_2++;
  522.             samples[NUM_SAMPLES + i].repeat = &samples[NUM_SAMPLES + i].data[0];
  523.             samples[NUM_SAMPLES + i].replen = samples[NUM_SAMPLES + i].length;
  524.  
  525.             ptr8s_1 += (samples[NUM_SAMPLES + i].length * 2);
  526.         }
  527.     }
  528.     else
  529.     {
  530.         ptr8s_1 = (int8_t *)(waveformDatas);
  531.         for (i = 0; i < NUM_WAVEFORMS; ++i)
  532.         {
  533.             if (i < NUM_WAVEFORMS_SMOD)
  534.             {
  535.                 samples[NUM_SAMPLES + i].data   = ptr8s_1;
  536.                 samples[NUM_SAMPLES + i].length = waveformLengths[i];
  537.                 samples[NUM_SAMPLES + i].repeat = &samples[NUM_SAMPLES + i].data[0];
  538.                 samples[NUM_SAMPLES + i].replen = samples[NUM_SAMPLES + i].length;
  539.  
  540.                 ptr8s_1 += (samples[NUM_SAMPLES + i].length * 2);
  541.             }
  542.             else
  543.             {
  544.                 samples[NUM_SAMPLES + i].data   = NULL;
  545.                 samples[NUM_SAMPLES + i].length = 0;
  546.                 samples[NUM_SAMPLES + i].repeat = NULL;
  547.                 samples[NUM_SAMPLES + i].replen = 1;
  548.             }
  549.         }
  550.     }
  551.  
  552.     /* get number of sequences and make it a multiple of 13 (SEQ_SIZE) */
  553.     numSequences = (uint32_t)(SWAP32(*PTR2LONG(&moduleData[4])) / SEQ_SIZE) * SEQ_SIZE;
  554.  
  555.     initdone = true;
  556.     return (true);
  557. }
  558.  
  559. static void restart_song(void)
  560. {
  561.     uint8_t i;
  562.     fcChannel_t *ch;
  563.  
  564.     memset(Channel, 0, sizeof (Channel));
  565.     for (i = 0; i < 4; ++i)
  566.     {
  567.         ch = &Channel[i];
  568.  
  569.         ch->voiceIndex      = i;
  570.         ch->volTabPtr       = silentTable;
  571.         ch->freqTabPtr      = silentTable;
  572.         ch->volDelayCounter = 1;
  573.         ch->volDelayLength  = 1;
  574.         ch->pitchBendDelay  = 1;
  575.         ch->seqPos          = SEQ_SIZE; /* yes */
  576.         ch->seqStartPtr     = &SEQpoint[3 * i];
  577.         ch->patPtr          = &PATpoint[ch->seqStartPtr[0] * PAT_MAX_SIZE];
  578.         ch->noteTranspose   = (signed)(ch->seqStartPtr[1]);
  579.         ch->soundTranspose  = (signed)(ch->seqStartPtr[2]);
  580.     }
  581.  
  582.     repspd   = (SEQpoint[12] > 0) ? SEQpoint[12] : 3;
  583.     respcnt  = repspd;
  584.     spdtemp  = 0;
  585.     spdtemp2 = 0;
  586. }
  587.  
  588. static void new_note(fcChannel_t *ch)
  589. {
  590.     uint8_t *tmpSeqPtr, *tmpPatPtr, note, info;
  591.  
  592.     tmpPatPtr = &ch->patPtr[ch->patPos]; /* temp pattern pointer */
  593.  
  594.     if ((fc14 && ((*tmpPatPtr & 0x7F) == PAT_END_MARKER)) || (ch->patPos == PAT_MAX_SIZE))
  595.     {
  596.         ch->patPos = 0;
  597.         if (ch->seqPos >= numSequences)
  598.             ch->seqPos = 0;
  599.  
  600.         tmpSeqPtr = &ch->seqStartPtr[ch->seqPos];
  601.         ch->patPtr = &PATpoint[tmpSeqPtr[0] * PAT_MAX_SIZE];
  602.         ch->noteTranspose = (signed)(tmpSeqPtr[1]);
  603.         ch->soundTranspose = (signed)(tmpSeqPtr[2]);
  604.  
  605.         if (++spdtemp == 4)
  606.         {
  607.             /* we've read all channels now, let's increase the pos used for RS */
  608.  
  609.             spdtemp = 0;
  610.             if (++spdtemp2 == (numSequences / SEQ_SIZE)) /* numSequences is a multiple of SEQ_SIZE */
  611.                 spdtemp2 = 0; /* wrap sequence position */
  612.         }
  613.  
  614.         /* read current RS (replay speed. only update if non-zero) */
  615.         if (SEQpoint[(spdtemp2 * 13) + 12] != 0)
  616.         {
  617.             repspd  = SEQpoint[(spdtemp2 * 13) + 12];
  618.             respcnt = repspd;
  619.         }
  620.  
  621.         ch->seqPos += SEQ_SIZE;
  622.         tmpPatPtr = ch->patPtr; /* set new temp pattern pointer */
  623.     }
  624.  
  625.     note = tmpPatPtr[0];
  626.     info = tmpPatPtr[1];
  627.  
  628.     if (note == 0)
  629.     {
  630.         info &= 0xC0;
  631.         if (info != 0)
  632.         {
  633.             ch->portaParam = 0;
  634.             if (info & (1 << 7))
  635.                 ch->portaParam = tmpPatPtr[3];
  636.         }
  637.     }
  638.     else
  639.     {
  640.         ch->portaValue = 0;
  641.         ch->portaParam = 0;
  642.         if (info & (1 << 7))
  643.             ch->portaParam = tmpPatPtr[3];
  644.     }
  645.  
  646.     note &= 0x7F;
  647.     if (note != 0)
  648.     {
  649.         ptr8u_1 = &VOLpoint[(((tmpPatPtr[1] & 0x3F) + ch->soundTranspose) & 0x3F) * VOL_TAB_SIZE];
  650.  
  651.         ch->note            = note;
  652.         ch->volDelayLength  = ptr8u_1[0];
  653.         ch->volDelayCounter = ch->volDelayLength;
  654.         ch->freqTabPtr      = &FRQpoint[(ptr8u_1[1] & 0x3F) * FREQ_TAB_SIZE];
  655.         ch->freqTabPos      = 0;
  656.         ch->freqSusCounter  = 0;
  657.         ch->vibratoSpeed    = ptr8u_1[2];
  658.         ch->vibratoDepth    = ptr8u_1[3];
  659.         ch->vibratoDelay    = ptr8u_1[4];
  660.         ch->vibratoCounter  = ch->vibratoDepth;
  661.         ch->vibratoUp       = true; /* default initial state on new note */
  662.         ch->volTabPtr       = &ptr8u_1[5];
  663.         ch->volTabPos       = 0;
  664.         ch->volSusCounter   = 0;
  665.  
  666.         PaulaTurnOffDMA(ch->voiceIndex); /* yes, this is important */
  667.     }
  668.  
  669.     ch->patPos += 2;
  670. }
  671.  
  672. static void doFreqModulation(fcChannel_t *ch)
  673. {
  674.     uint8_t doTranspose, *tabPtr, *tmpPtr;
  675.     soundInfo_t sample;
  676.  
  677. testsustain:
  678.     if (ch->freqSusCounter > 0)
  679.     {
  680.         ch->freqSusCounter--;
  681.     }
  682.     else
  683.     {
  684.         tabPtr = &ch->freqTabPtr[ch->freqTabPos];
  685.  
  686. testeffects:
  687.         if (tabPtr[0] != 0xE1)
  688.         {
  689.             doTranspose = true;
  690.  
  691.             if (tabPtr[0] == 0xE0) /* freq pos jump */
  692.             {
  693.                 ch->freqTabPos = tabPtr[1] & 0x3F;
  694.                 tabPtr = &ch->freqTabPtr[ch->freqTabPos];
  695.             }
  696.  
  697.             if (tabPtr[0] == 0xE2) /* set waveform */
  698.             {
  699.                 if (tabPtr[1] < (NUM_SAMPLES + NUM_WAVEFORMS))
  700.                 {
  701.                     sample = samples[tabPtr[1]];
  702.  
  703.                     ch->loopStart  = sample.repeat;
  704.                     ch->loopLength = sample.replen;
  705.  
  706.                     PaulaSetData(ch->voiceIndex, sample.data);
  707.                     PaulaSetLength(ch->voiceIndex, sample.length);
  708.                     PaulaRestartDMA(ch->voiceIndex);
  709.  
  710.                     ch->DMAWaitFrames = 3;
  711.                     ch->volTabPos = 0;
  712.                     ch->volDelayCounter = 1;
  713.                 }
  714.  
  715.                 ch->freqTabPos += 2;
  716.             }
  717.             else if (tabPtr[0] == 0xE4) /* update waveform */
  718.             {
  719.                 if (tabPtr[1] < (NUM_SAMPLES + NUM_WAVEFORMS))
  720.                 {
  721.                     sample = samples[tabPtr[1]];
  722.  
  723.                     ch->loopStart  = sample.repeat;
  724.                     ch->loopLength = sample.replen;
  725.  
  726.                     PaulaSetData(ch->voiceIndex, sample.data);
  727.                     PaulaSetLength(ch->voiceIndex, sample.length);
  728.  
  729.                     ch->DMAWaitFrames = 3;
  730.                 }
  731.  
  732.                 ch->freqTabPos += 2;
  733.             }
  734.             else if (tabPtr[0] == 0xE9) /* set packed waveform */
  735.             {
  736.                 if (tabPtr[1] < (NUM_SAMPLES + NUM_WAVEFORMS))
  737.                 {
  738.                     sample = samples[tabPtr[1]];
  739.                     if (*PTR2LONG(sample.data) == 0x504D5353) /* "SSMP" */
  740.                     {
  741.                         tmpPtr = (uint8_t *)(&sample.data[4 + (tabPtr[2] * 16)]);
  742.  
  743.                         ch->loopStart  = &sample.data[(4 + 320 + *PTR2LONG(&tmpPtr[0])) + *PTR2WORD(&tmpPtr[6])];
  744.                         ch->loopLength = *PTR2WORD(&tmpPtr[8]);
  745.  
  746.                         /* fix endless beep on non-looping samples (FC14 doesn't do this) */
  747.                         if (ch->loopLength <= 1)
  748.                         {
  749.                             ch->loopLength = 1;
  750.                             if (*PTR2WORD(&tmpPtr[4]) >= 1) /* sample length */
  751.                                 *PTR2WORD(&sample.data[4 + 320 + *PTR2LONG(&tmpPtr[0])]) = 0;
  752.                         }
  753.  
  754.                         PaulaSetData(ch->voiceIndex,  &sample.data[4 + 320 + *PTR2LONG(&tmpPtr[0])]);
  755.                         PaulaSetLength(ch->voiceIndex, *PTR2WORD(&tmpPtr[4]));
  756.                         PaulaRestartDMA(ch->voiceIndex);
  757.  
  758.                         ch->DMAWaitFrames = 3;
  759.                         ch->volTabPos = 0;
  760.                         ch->volDelayCounter = 1;
  761.                     }
  762.                 }
  763.  
  764.                 ch->freqTabPos += 3;
  765.             }
  766.             else if (tabPtr[0] == 0xE7) /* new freq pos */
  767.             {
  768.                 tabPtr = &FRQpoint[(tabPtr[1] & 0x3F) * FREQ_TAB_SIZE];
  769.                 ch->freqTabPtr = tabPtr;
  770.                 ch->freqTabPos = 0;
  771.  
  772.                 goto testeffects;
  773.             }
  774.             else if (tabPtr[0] == 0xE8) /* set freq sustain */
  775.             {
  776.                 ch->freqSusCounter = tabPtr[1];
  777.  
  778.                 ch->freqTabPos += 2;
  779.                 goto testsustain;
  780.             }
  781.             else if (tabPtr[0] == 0xE3) /* set vibrato */
  782.             {
  783.                 ch->freqTabPos += 3;
  784.  
  785.                 ch->vibratoSpeed = tabPtr[1];
  786.                 ch->vibratoDepth = tabPtr[2];
  787.  
  788.                 doTranspose = false; /* don't do period transpose here */
  789.             }
  790.             else if (tabPtr[0] == 0xEA) /* set pitch bend */
  791.             {
  792.                 ch->pitchBendValue   = (signed)(tabPtr[1]);
  793.                 ch->pitchBendCounter = (signed)(tabPtr[2]);
  794.  
  795.                 ch->freqTabPos += 3;
  796.             }
  797.  
  798.             if (doTranspose)
  799.                 ch->periodTranspose = (signed)(ch->freqTabPtr[ch->freqTabPos++]);
  800.         }
  801.     }
  802. }
  803.  
  804. static void do_VOLbend(fcChannel_t *ch)
  805. {
  806.     ch->volSlideDelay = !ch->volSlideDelay;
  807.     if (ch->volSlideDelay)
  808.     {
  809.         ch->volSlideCounter--;
  810.  
  811.         ch->volume += ch->volSlideSpeed;
  812.         if (ch->volume < 0)
  813.         {
  814.             ch->volSlideCounter = 0;
  815.             ch->volume = 0;
  816.         }
  817.     }
  818. }
  819.  
  820. static void doVolModulation(fcChannel_t *ch)
  821. {
  822.     uint8_t *tabPtr;
  823.  
  824. VOLUfx:
  825.     if (ch->volSusCounter > 0)
  826.     {
  827.         ch->volSusCounter--;
  828.     }
  829.     else
  830.     {
  831.         if (ch->volSlideCounter > 0)
  832.         {
  833.             do_VOLbend(ch);
  834.         }
  835.         else
  836.         {
  837.             /* fun potential bug: ch->volDelayCounter==0 = mega delay... */
  838.             if (--ch->volDelayCounter == 0)
  839.             {
  840.                 ch->volDelayCounter = ch->volDelayLength;
  841. volu_cmd:
  842.                 tabPtr = &ch->volTabPtr[ch->volTabPos];
  843.  
  844.                 if (tabPtr[0] != 0xE1)
  845.                 {
  846.                     if (tabPtr[0] == 0xE8) /* set vol sustain */
  847.                     {
  848.                         ch->volSusCounter = tabPtr[1];
  849.                         ch->volTabPos += 2;
  850.  
  851.                         goto VOLUfx;
  852.                     }
  853.                     else if (tabPtr[0] == 0xEA) /* set vol slide */
  854.                     {
  855.                         ch->volSlideSpeed   = tabPtr[1];
  856.                         ch->volSlideCounter = tabPtr[2];
  857.  
  858.                         ch->volTabPos += 3;
  859.                         do_VOLbend(ch);
  860.                     }
  861.                     else if (tabPtr[0] == 0xE0) /* set vol pos */
  862.                     {
  863.                         if (((tabPtr[1] & 0x3F) - 5) < 0)
  864.                             ch->volTabPos = 0;
  865.                         else
  866.                             ch->volTabPos = (tabPtr[1] & 0x3F) - 5;
  867.  
  868.                         goto volu_cmd;
  869.                     }
  870.                     else
  871.                     {
  872.                         ch->volume = (signed)(ch->volTabPtr[ch->volTabPos++]);
  873.                     }
  874.                 }
  875.             }
  876.         }
  877.     }
  878. }
  879.  
  880. static void effects(fcChannel_t *ch)
  881. {
  882.     int8_t tmpNote;
  883.     int16_t tmpVibPeriod, tmpPeriod;
  884.     uint16_t tmpVibNote;
  885.  
  886.     doFreqModulation(ch);
  887.     doVolModulation(ch);
  888.  
  889.     /* get period from note and transposes... */
  890.     tmpNote = ch->periodTranspose;
  891.     if (tmpNote >= 0)
  892.     {
  893.         tmpNote += ch->note;
  894.         tmpNote += ch->noteTranspose;
  895.     }
  896.     tmpNote &= 0x7F;
  897.  
  898.     tmpPeriod = periods[tmpNote];
  899.  
  900.     /* apply vibrato to period */
  901.     if (ch->vibratoDelay > 0)
  902.     {
  903.         ch->vibratoDelay--;
  904.     }
  905.     else
  906.     {
  907.         tmpVibPeriod = ch->vibratoCounter;
  908.         if (!ch->vibratoUp)
  909.         {
  910.             tmpVibPeriod -= ch->vibratoSpeed;
  911.             if (tmpVibPeriod < 0)
  912.             {
  913.                 tmpVibPeriod  = 0;
  914.                 ch->vibratoUp = true;
  915.             }
  916.         }
  917.         else
  918.         {
  919.             tmpVibPeriod += ch->vibratoSpeed;
  920.             if (tmpVibPeriod > (ch->vibratoDepth * 2))
  921.             {
  922.                 tmpVibPeriod  = ch->vibratoDepth * 2;
  923.                 ch->vibratoUp = false;
  924.             }
  925.         }
  926.         ch->vibratoCounter = tmpVibPeriod & 0x00FF;
  927.  
  928.         tmpVibPeriod -= ch->vibratoDepth;
  929.  
  930.         tmpVibNote = tmpNote * 2;
  931.         while (tmpVibNote < (12 * 8))
  932.         {
  933.             tmpVibPeriod *= 2;
  934.             tmpVibNote   += (12 * 2);
  935.         }
  936.  
  937.         tmpPeriod += tmpVibPeriod;
  938.     }
  939.  
  940.     /* update portamento value (twice as slow on FC1.4) */
  941.     ch->portaDelay = !ch->portaDelay;
  942.     if (!fc14 || ch->portaDelay)
  943.     {
  944.         if (ch->portaParam > 0)
  945.         {
  946.             if (ch->portaParam > 0x1F)
  947.                 ch->portaValue += (ch->portaParam & 0x1F);
  948.             else
  949.                 ch->portaValue -= ch->portaParam;
  950.         }
  951.     }
  952.  
  953.     /* apply pitch bend to portamento value  */
  954.     ch->pitchBendDelay = !ch->pitchBendDelay;
  955.     if (ch->pitchBendDelay)
  956.     {
  957.         if (ch->pitchBendCounter > 0)
  958.         {
  959.             ch->pitchBendCounter--;
  960.             ch->portaValue -= ch->pitchBendValue;
  961.         }
  962.     }
  963.  
  964.     tmpPeriod += ch->portaValue;
  965.  
  966.     PaulaSetPeriod(ch->voiceIndex, CLAMP(tmpPeriod, 0x0071, fc14 ? 0x0D60 : 0x06B0));
  967.     PaulaSetVolume(ch->voiceIndex, ch->volume);
  968. }
  969.  
  970. static void play_music(void)
  971. {
  972.     uint8_t i;
  973.  
  974.     if (--respcnt == 0)
  975.     {
  976.         respcnt = repspd;
  977.  
  978.         for (i = 0; i < 4; ++i)
  979.             new_note(&Channel[i]);
  980.     }
  981.  
  982.     for (i = 0; i < 4; ++i)
  983.     {
  984.         effects(&Channel[i]);
  985.  
  986.         if (Channel[i].DMAWaitFrames > 0)
  987.         {
  988.             if (--Channel[i].DMAWaitFrames == 0)
  989.             {
  990.                 /* these take effect when the current DMA cycle is done */
  991.                 PaulaSetData(i, Channel[i].loopStart);
  992.                 PaulaSetLength(i, Channel[i].loopLength);
  993.             }
  994.         }
  995.     }
  996. }
  997.  
  998. static void mixAudio(int16_t *stream, int32_t sampleBlockLength)
  999. {
  1000.     const int8_t *dataPtr;
  1001.     uint8_t i;
  1002.     uint16_t j;
  1003.     int32_t smpL, smpR;
  1004.     float tempSample, tempVolume, out_f[2];
  1005.     paulaVoice_t *v;
  1006. #ifdef USE_BLEP
  1007.     blep_t *bSmp, *bVol;
  1008. #endif
  1009.  
  1010.     memset(mixerBufferL, 0, sizeof (float) * sampleBlockLength);
  1011.     memset(mixerBufferR, 0, sizeof (float) * sampleBlockLength);
  1012.  
  1013.     if (musicPaused)
  1014.     {
  1015.         memset(stream, 0, sampleBlockLength * sizeof (int16_t) * 2);
  1016.         return;
  1017.     }
  1018.  
  1019.     for (i = 0; i < 4; ++i)
  1020.     {
  1021.         v = &AUD[i];
  1022.  
  1023. #ifdef USE_BLEP
  1024.         bSmp = &blep[i];
  1025.         bVol = &blepVol[i];
  1026. #endif
  1027.         for (j = 0; v->DMA_ON && (j < sampleBlockLength); ++j)
  1028.         {
  1029.             dataPtr = v->DMA_DAT;
  1030.             if (dataPtr == NULL)
  1031.             {
  1032.                 tempSample = 0.0f;
  1033.                 tempVolume = 0.0f;
  1034.             }
  1035.             else
  1036.             {
  1037.                 tempSample = dataPtr[v->DMA_POS] * (1.0f / 128.0f);
  1038.                 tempVolume = v->SRC_VOL;
  1039.             }
  1040.  
  1041. #ifdef USE_BLEP
  1042.             if (tempSample != bSmp->lastValue)
  1043.             {
  1044.                 if ((v->LASTDELTA > 0.0f) && (v->LASTDELTA > v->LASTFRAC))
  1045.                     blepAdd(bSmp, v->LASTFRAC / v->LASTDELTA, bSmp->lastValue - tempSample);
  1046.  
  1047.                 bSmp->lastValue = tempSample;
  1048.             }
  1049.  
  1050.             if (tempVolume != bVol->lastValue)
  1051.             {
  1052.                 blepAdd(bVol, 0.0f, bVol->lastValue - tempVolume);
  1053.                 bVol->lastValue = tempVolume;
  1054.             }
  1055.  
  1056.             if (bSmp->samplesLeft) tempSample += blepRun(bSmp);
  1057.             if (bVol->samplesLeft) tempVolume += blepRun(bVol);
  1058. #endif
  1059.             tempSample *= tempVolume;
  1060.  
  1061.             mixerBufferL[j] += (tempSample * v->PANL);
  1062.             mixerBufferR[j] += (tempSample * v->PANR);
  1063.  
  1064.             v->FRAC += v->DELTA;
  1065.             if (v->FRAC >= 1.0f)
  1066.             {
  1067.                 v->FRAC -= 1.0f;
  1068.  
  1069.                 v->LASTFRAC  = v->FRAC;
  1070.                 v->LASTDELTA = v->DELTA;
  1071.  
  1072.                 if (++v->DMA_POS >= v->DMA_LEN)
  1073.                 {
  1074.                     v->DMA_POS = 0;
  1075.  
  1076.                     /* re-fetch Paula register values now */
  1077.                     v->DMA_LEN = v->SRC_LEN;
  1078.                     v->DMA_DAT = v->SRC_DAT;
  1079.                 }
  1080.             }
  1081.         }
  1082.     }
  1083.  
  1084.     for (j = 0; j < sampleBlockLength; ++j)
  1085.     {
  1086.         out_f[0] = mixerBufferL[j];
  1087.         out_f[1] = mixerBufferR[j];
  1088.  
  1089. #ifdef USE_LOWPASS
  1090.         lossyIntegrator(&filterLo, out_f, out_f);
  1091. #endif
  1092.  
  1093. #ifdef USE_HIGHPASS
  1094.         lossyIntegratorHighPass(&filterHi, out_f, out_f);
  1095. #endif
  1096.         /* normalize amplitude */
  1097.         out_f[0] *= (32767.0f / NORM_FACTOR);
  1098.         out_f[1] *= (32767.0f / NORM_FACTOR);
  1099.  
  1100.         /* truncate to signed 32-bit integer */
  1101.         smpL = (int32_t)(out_f[0]);
  1102.         smpR = (int32_t)(out_f[1]);
  1103.  
  1104.         /* clamp to 16-bit signed range */
  1105.         CLAMP16(smpL);
  1106.         CLAMP16(smpR);
  1107.  
  1108.         /* truncate to signed 16-bit integer and store in output buffer */
  1109.         *stream++ = (int16_t)(smpL);
  1110.         *stream++ = (int16_t)(smpR);
  1111.     }
  1112. }
  1113.  
  1114. /* these are used to create an equal powered panning */
  1115. static float sinApx(float x)
  1116. {
  1117.     x = x * (2.0f - x);
  1118.     return (x * 1.09742972f + x * x * 0.31678383f);
  1119. }
  1120.  
  1121. static float cosApx(float x)
  1122. {
  1123.     x = (1.0f - x) * (1.0f + x);
  1124.     return (x * 1.09742972f + x * x * 0.31678383f);
  1125. }
  1126. /* ------------------------------------------------- */
  1127.  
  1128. static void calculatePans(uint8_t stereoSeparation)
  1129. {
  1130.     uint8_t scaledPanPos;
  1131.     float p;
  1132.  
  1133.     if (stereoSeparation > 100)
  1134.         stereoSeparation = 100;
  1135.  
  1136.     scaledPanPos = (stereoSeparation * 128) / 100;
  1137.  
  1138.     p = (128 - scaledPanPos) * (1.0f / 256.0f);
  1139.     AUD[0].PANL = cosApx(p);
  1140.     AUD[0].PANR = sinApx(p);
  1141.     AUD[3].PANL = cosApx(p);
  1142.     AUD[3].PANR = sinApx(p);
  1143.  
  1144.     p = (128 + scaledPanPos) * (1.0f / 256.0f);
  1145.     AUD[1].PANL = cosApx(p);
  1146.     AUD[1].PANR = sinApx(p);
  1147.     AUD[2].PANL = cosApx(p);
  1148.     AUD[2].PANR = sinApx(p);
  1149. }
  1150.  
  1151. void fc14play_FillAudioBuffer(int16_t *buffer, int32_t numSamples)
  1152. {
  1153.     int32_t a, b;
  1154.  
  1155.     a = numSamples;
  1156.     while (a > 0)
  1157.     {
  1158.         if (samplesPerFrameLeft == 0)
  1159.         {
  1160.             /* new replayer tick */
  1161.             if (!musicPaused)
  1162.                 play_music();
  1163.  
  1164.             samplesPerFrameLeft = samplesPerFrame;
  1165.         }
  1166.  
  1167.         b = a;
  1168.         if (b > samplesPerFrameLeft)
  1169.             b = samplesPerFrameLeft;
  1170.  
  1171.         mixAudio(buffer, b);
  1172.         buffer += (b * 2);
  1173.  
  1174.         a -= b;
  1175.         samplesPerFrameLeft -= b;
  1176.     }
  1177.  
  1178.     sampleCounter += numSamples;
  1179. }
  1180.  
  1181. void fc14play_PauseSong(int8_t flag)
  1182. {
  1183.     musicPaused = flag ? false : true;
  1184. }
  1185.  
  1186. void fc14play_TogglePause(void)
  1187. {
  1188.     musicPaused ^= 1;
  1189. }
  1190.  
  1191. void fc14play_Close(void)
  1192. {
  1193.     closeMixer();
  1194.  
  1195.     if (mixerBufferL != NULL)
  1196.     {
  1197.         free(mixerBufferL);
  1198.         mixerBufferL = NULL;
  1199.     }
  1200.  
  1201.     if (mixerBufferR != NULL)
  1202.     {
  1203.         free(mixerBufferR);
  1204.         mixerBufferR = NULL;
  1205.     }
  1206.  
  1207.     if (songData != NULL)
  1208.     {
  1209.         free(songData);
  1210.         songData = NULL;
  1211.     }
  1212. }
  1213.  
  1214. void fc14play_SetStereoSep(uint8_t percentage)
  1215. {
  1216.     stereoSep = percentage;
  1217.     if (stereoSep > 100)
  1218.         stereoSep = 100;
  1219.  
  1220.     calculatePans(stereoSep);
  1221. }
  1222.  
  1223. uint32_t fc14play_GetMixerTicks(void) /* returns the amount of milliseconds passed in the mixer */
  1224. {
  1225.     if (audioFreq < 1000)
  1226.         return (0);
  1227.  
  1228.     return (sampleCounter / (audioFreq / 1000));
  1229. }
  1230.  
  1231. int8_t fc14play_PlaySong(const uint8_t *moduleData, uint32_t dataLength, uint32_t outputFreq)
  1232. {
  1233.     if (outputFreq == 0)
  1234.         outputFreq = 44100;
  1235.  
  1236.     musicPaused = true;
  1237.  
  1238.     fc14play_Close();
  1239.  
  1240.     sampleCounter = 0;
  1241.  
  1242.     songData = (uint8_t *)(malloc(dataLength));
  1243.     if (songData == NULL)
  1244.         return (false);
  1245.  
  1246.     memcpy(songData, moduleData, dataLength);
  1247.     if (!init_music(songData))
  1248.     {
  1249.         fc14play_Close();
  1250.         return (false);
  1251.     }
  1252.  
  1253.     mixerBufferL = (float *)(malloc(MIX_BUF_SAMPLES * sizeof (float)));
  1254.     mixerBufferR = (float *)(malloc(MIX_BUF_SAMPLES * sizeof (float)));
  1255.  
  1256.     if ((mixerBufferL == NULL) || (mixerBufferR == NULL))
  1257.     {
  1258.         fc14play_Close();
  1259.         return (false);
  1260.     }
  1261.  
  1262.     restart_song();
  1263.  
  1264.     outputFreq = CLAMP(outputFreq, 32000, 96000);
  1265.     if (!openMixer(outputFreq))
  1266.     {
  1267.         fc14play_Close();
  1268.         return (false);
  1269.     }
  1270.  
  1271.     audioFreq       = outputFreq;
  1272.     f_outputFreq    = (float)(outputFreq);
  1273.     soundBufferSize = MIX_BUF_SAMPLES;
  1274.     samplesPerFrame = (uint32_t)((f_outputFreq / AMIGA_VBLANK_RATE) + 0.5f);
  1275.  
  1276. #ifdef USE_LOWPASS
  1277.     // Amiga 500 RC low-pass filter (R = 360 ohm, C = 0.1uF)
  1278.     // hz = 1 / (2pi * R * C)    = ~4421.0Hz
  1279.     calcCoeffLossyIntegrator(f_outputFreq, 4421.0f, &filterLo);
  1280. #endif
  1281.  
  1282. #ifdef USE_HIGHPASS
  1283.     // Amiga 500 RC high-pass filter (R = 1390 ohm, C = 22uF)
  1284.     // hz = 1 / (2pi * R * C)    = ~5.2Hz
  1285.     calcCoeffLossyIntegrator(f_outputFreq, 5.2f, &filterHi);
  1286. #endif
  1287.  
  1288.     memset(AUD, 0, sizeof (AUD));
  1289.     calculatePans(stereoSep);
  1290.  
  1291. #ifdef USE_BLEP
  1292.     memset(blep,    0, sizeof (blep));
  1293.     memset(blepVol, 0, sizeof (blepVol));
  1294. #endif
  1295.  
  1296. #ifdef USE_LOWPASS
  1297.     clearLossyIntegrator(&filterLo);
  1298. #endif
  1299.  
  1300. #ifdef USE_HIGHPASS
  1301.     clearLossyIntegrator(&filterHi);
  1302. #endif
  1303.  
  1304.     musicPaused = false;
  1305.     return (true);
  1306. }
  1307.  
  1308. /* the following must be changed if you want to use another audio API than WinMM */
  1309.  
  1310. #ifndef WIN32_LEAN_AND_MEAN
  1311. #define WIN32_LEAN_AND_MEAN
  1312. #endif
  1313.  
  1314. #include <windows.h>
  1315. #include <mmsystem.h>
  1316.  
  1317. #define MIX_BUF_NUM 2
  1318.  
  1319. static volatile BOOL audioRunningFlag;
  1320. static uint8_t currBuffer;
  1321. static int16_t *mixBuffer[MIX_BUF_NUM];
  1322. static HANDLE hThread, hAudioSem;
  1323. static WAVEHDR waveBlocks[MIX_BUF_NUM];
  1324. static HWAVEOUT hWave;
  1325.  
  1326. static DWORD WINAPI mixThread(LPVOID lpParam)
  1327. {
  1328.     WAVEHDR *waveBlock;
  1329.  
  1330.     SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
  1331.  
  1332.     while (audioRunningFlag)
  1333.     {
  1334.         waveBlock = &waveBlocks[currBuffer];
  1335.         fc14play_FillAudioBuffer((int16_t *)(waveBlock->lpData), MIX_BUF_SAMPLES);
  1336.         waveOutWrite(hWave, waveBlock, sizeof (WAVEHDR));
  1337.         currBuffer = (currBuffer + 1) % MIX_BUF_NUM;
  1338.  
  1339.         /* wait for buffer fill request */
  1340.         WaitForSingleObject(hAudioSem, INFINITE);
  1341.     }
  1342.  
  1343.     (void)(lpParam); /* make compiler happy! */
  1344.  
  1345.     return (0);
  1346. }
  1347.  
  1348. static void CALLBACK waveProc(HWAVEOUT hWaveOut, UINT uMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2)
  1349. {
  1350.     if (uMsg == WOM_DONE)
  1351.         ReleaseSemaphore(hAudioSem, 1, NULL);
  1352.  
  1353.     /* make compiler happy! */
  1354.     (void)(hWaveOut);
  1355.     (void)(uMsg);
  1356.     (void)(dwInstance);
  1357.     (void)(dwParam1);
  1358.     (void)(dwParam2);
  1359. }
  1360.  
  1361. static void closeMixer(void)
  1362. {
  1363.     int32_t i;
  1364.  
  1365.     audioRunningFlag = false; /* make thread end when it's done */
  1366.  
  1367.     if (hAudioSem != NULL)
  1368.         ReleaseSemaphore(hAudioSem, 1, NULL);
  1369.  
  1370.     if (hThread != NULL)
  1371.     {
  1372.         WaitForSingleObject(hThread, INFINITE);
  1373.         CloseHandle(hThread);
  1374.         hThread = NULL;
  1375.     }
  1376.  
  1377.     if (hAudioSem != NULL)
  1378.     {
  1379.         CloseHandle(hAudioSem);
  1380.         hAudioSem = NULL;
  1381.     }
  1382.  
  1383.     if (hWave != NULL)
  1384.     {
  1385.         waveOutReset(hWave);
  1386.  
  1387.         for (i = 0; i < MIX_BUF_NUM; ++i)
  1388.         {
  1389.             if (waveBlocks[i].dwUser != 0xFFFF)
  1390.                 waveOutUnprepareHeader(hWave, &waveBlocks[i], sizeof (WAVEHDR));
  1391.         }
  1392.  
  1393.         waveOutClose(hWave);
  1394.         hWave = NULL;
  1395.     }
  1396.  
  1397.     for (i = 0; i < MIX_BUF_NUM; ++i)
  1398.     {
  1399.         if (mixBuffer[i] != NULL)
  1400.         {
  1401.             free(mixBuffer[i]);
  1402.             mixBuffer[i] = NULL;
  1403.         }
  1404.     }
  1405. }
  1406.  
  1407. static int8_t openMixer(uint32_t outputFreq)
  1408. {
  1409.     int32_t i;
  1410.     DWORD threadID;
  1411.     WAVEFORMATEX wfx;
  1412.  
  1413.     /* don't unprepare headers on error */
  1414.     for (i = 0; i < MIX_BUF_NUM; ++i)
  1415.         waveBlocks[i].dwUser = 0xFFFF;
  1416.  
  1417.     closeMixer();
  1418.  
  1419.     ZeroMemory(&wfx, sizeof (wfx));
  1420.     wfx.nSamplesPerSec  = outputFreq;
  1421.     wfx.wBitsPerSample  = 16;
  1422.     wfx.nChannels       = 2;
  1423.     wfx.wFormatTag      = WAVE_FORMAT_PCM;
  1424.     wfx.nBlockAlign     = wfx.nChannels * (wfx.wBitsPerSample / 8);
  1425.     wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
  1426.  
  1427.     samplesPerFrameLeft = 0;
  1428.     currBuffer = 0;
  1429.  
  1430.     if (waveOutOpen(&hWave, WAVE_MAPPER, &wfx, (DWORD_PTR)(&waveProc), 0, CALLBACK_FUNCTION) != MMSYSERR_NOERROR)
  1431.         goto omError;
  1432.  
  1433.     /* create semaphore for buffer fill requests */
  1434.     hAudioSem = CreateSemaphore(NULL, MIX_BUF_NUM - 1, MIX_BUF_NUM, NULL);
  1435.     if (hAudioSem == NULL)
  1436.         goto omError;
  1437.  
  1438.     /* allocate WinMM mix buffers */
  1439.     for (i = 0; i < MIX_BUF_NUM; ++i)
  1440.     {
  1441.         mixBuffer[i] = (int16_t *)(calloc(MIX_BUF_SAMPLES, wfx.nBlockAlign));
  1442.         if (mixBuffer[i] == NULL)
  1443.             goto omError;
  1444.     }
  1445.  
  1446.     /* initialize WinMM mix headers */
  1447.  
  1448.     memset(waveBlocks, 0, sizeof (waveBlocks));
  1449.     for (i = 0; i < MIX_BUF_NUM; ++i)
  1450.     {
  1451.         waveBlocks[i].lpData = (LPSTR)(mixBuffer[i]);
  1452.         waveBlocks[i].dwBufferLength = MIX_BUF_SAMPLES * wfx.nBlockAlign;
  1453.         waveBlocks[i].dwFlags = WHDR_DONE;
  1454.  
  1455.         if (waveOutPrepareHeader(hWave, &waveBlocks[i], sizeof (WAVEHDR)) != MMSYSERR_NOERROR)
  1456.             goto omError;
  1457.     }
  1458.  
  1459.     /* create main mixer thread */
  1460.     audioRunningFlag = true;
  1461.     hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)(mixThread), NULL, 0, &threadID);
  1462.     if (hThread == NULL)
  1463.         goto omError;
  1464.  
  1465.     return (TRUE);
  1466.  
  1467. omError:
  1468.     closeMixer();
  1469.     return (FALSE);
  1470. }
  1471.  
  1472. /* --------------------------------------------------------------------------- */
  1473.  
  1474. /* END OF FILE */
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top