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

fc14play v1.24

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