ref: 4066d83d717488204a385e8ff484d13d2c10209e
parent: cf882314685613d8ede6f8c3ac27b1af7186871c
parent: 5dca43d1a307ba6d2288c4be9ff7d3f705aaabc4
author: Sigrid Solveig Haflínudóttir <ftrvxmtrx@gmail.com>
date: Wed Jun 16 09:41:54 EDT 2021
Merge remote-tracking branch 'remotes/upstream/master'
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -10,8 +10,10 @@
"${ft2-clone_SOURCE_DIR}/src/*.c"
"${ft2-clone_SOURCE_DIR}/src/gfxdata/*.c"
"${ft2-clone_SOURCE_DIR}/src/mixer/*.c"
+ "${ft2-clone_SOURCE_DIR}/src/scopes/*.c"
"${ft2-clone_SOURCE_DIR}/src/modloaders/*.c"
"${ft2-clone_SOURCE_DIR}/src/smploaders/*.c"
+ "${ft2-clone_SOURCE_DIR}/src/libflac/*.c"
)
add_executable(ft2-clone ${ft2-clone_SRC})
@@ -26,7 +28,11 @@
target_link_libraries(ft2-clone
PRIVATE m asound pthread ${SDL2_LIBRARIES})
-target_compile_definitions(ft2-clone PRIVATE __LINUX_ALSA__)
+target_compile_definitions(ft2-clone
+ PRIVATE HAS_MIDI
+ PRIVATE __LINUX_ALSA__
+ PRIVATE HAS_LIBFLAC)
+
install(TARGETS ft2-clone
- RUNTIME DESTINATION bin )
+ RUNTIME DESTINATION bin)
--- a/LICENSES.txt
+++ b/LICENSES.txt
@@ -3,6 +3,9 @@
Source code (BSD 3-clause):
src\LICENSE.txt
+libFLAC:
+src\libflac\COPYING.txt
+
rtmidi:
src\rtmidi\LICENSE.txt
--- /dev/null
+++ b/make-linux-nomidi-noflac.sh
@@ -1,0 +1,10 @@
+#!/bin/bash
+
+rm release/other/ft2-clone &> /dev/null
+echo Compiling \(with no MIDI and no FLAC functionality\), please wait patiently...
+
+gcc -DNDEBUG src/gfxdata/*.c src/mixer/*.c src/scopes/*.c src/modloaders/*.c src/smploaders/*.c src/*.c -lSDL2 -lm -Wshadow -Winit-self -Wall -Wno-missing-field-initializers -Wno-unused-result -Wno-strict-aliasing -Wextra -Wunused -Wunreachable-code -Wswitch-default -march=native -mtune=native -O3 -o release/other/ft2-clone
+
+rm src/gfxdata/*.o src/*.o &> /dev/null
+
+echo Done. The executable can be found in \'release/other\' if everything went well.
--- a/make-linux-nomidi.sh
+++ /dev/null
@@ -1,10 +1,0 @@
-#!/bin/bash
-
-rm release/other/ft2-clone &> /dev/null
-echo Compiling \(with no MIDI functionality\), please wait patiently...
-
-gcc -DNDEBUG src/gfxdata/*.c src/mixer/*.c src/modloaders/*.c src/smploaders/*.c src/*.c -lSDL2 -lm -Wshadow -Winit-self -Wall -Wno-missing-field-initializers -Wno-unused-result -Wno-strict-aliasing -Wextra -Wunused -Wunreachable-code -Wswitch-default -march=native -mtune=native -O3 -o release/other/ft2-clone
-
-rm src/gfxdata/*.o src/*.o &> /dev/null
-
-echo Done. The executable can be found in \'release/other\' if everything went well.
--- a/make-linux.sh
+++ b/make-linux.sh
@@ -3,7 +3,7 @@
rm release/other/ft2-clone &> /dev/null
echo Compiling, please wait patiently...
-gcc -DNDEBUG -DHAS_MIDI -D__LINUX_ALSA__ src/rtmidi/*.cpp src/gfxdata/*.c src/mixer/*.c src/modloaders/*.c src/smploaders/*.c src/*.c -lSDL2 -lpthread -lasound -lstdc++ -lm -Wshadow -Winit-self -Wall -Wno-missing-field-initializers -Wno-unused-result -Wno-strict-aliasing -Wextra -Wunused -Wunreachable-code -Wswitch-default -march=native -mtune=native -O3 -o release/other/ft2-clone
+gcc -DNDEBUG -DHAS_MIDI -D__LINUX_ALSA__ -DHAS_LIBFLAC src/rtmidi/*.cpp src/gfxdata/*.c src/mixer/*.c src/scopes/*.c src/modloaders/*.c src/smploaders/*.c src/libflac/*.c src/*.c -lSDL2 -lpthread -lasound -lstdc++ -lm -Wshadow -Winit-self -Wall -Wno-missing-field-initializers -Wno-unused-result -Wno-strict-aliasing -Wextra -Wunused -Wunreachable-code -Wswitch-default -march=native -mtune=native -O3 -o release/other/ft2-clone
rm src/rtmidi/*.o src/gfxdata/*.o src/*.o &> /dev/null
--- a/make-macos.sh
+++ b/make-macos.sh
@@ -36,7 +36,7 @@
#
function compile() {
rm $1 &> /dev/null
- clang $VERBOSE $CFLAGS -F /Library/Frameworks -g0 -DNDEBUG -DHAS_MIDI -D__MACOSX_CORE__ -stdlib=libc++ src/rtmidi/*.cpp src/gfxdata/*.c src/mixer/*.c src/modloaders/*.c src/smploaders/*.c src/*.c -Winit-self -Wno-deprecated -Wextra -Wunused -mno-ms-bitfields -Wno-missing-field-initializers -Wswitch-default $LDFLAGS -L /Library/Frameworks -framework SDL2 -framework CoreMidi -framework CoreAudio -framework Cocoa -liconv -lpthread -lm -lstdc++ -o $1
+ clang $VERBOSE $CFLAGS -F /Library/Frameworks -g0 -DNDEBUG -DHAS_MIDI -D__MACOSX_CORE__ -DHAS_LIBFLAC -stdlib=libc++ src/rtmidi/*.cpp src/gfxdata/*.c src/mixer/*.c src/scopes/*.c src/modloaders/*.c src/smploaders/*.c src/libflac/*.c src/*.c -Winit-self -Wno-deprecated -Wextra -Wunused -mno-ms-bitfields -Wno-missing-field-initializers -Wswitch-default $LDFLAGS -L /Library/Frameworks -framework SDL2 -framework CoreMidi -framework CoreAudio -framework Cocoa -liconv -lpthread -lm -lstdc++ -o $1
return $?
}
--- a/release/LICENSES.txt
+++ b/release/LICENSES.txt
@@ -29,6 +29,41 @@
--------------------------------------------------------------------------------
+----------------------------------- libFLAC ------------------------------------
+--------------------------------------------------------------------------------
+
+Copyright (C) 2000-2009 Josh Coalson
+Copyright (C) 2011-2016 Xiph.Org Foundation
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+- Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+
+- Neither the name of the Xiph.org Foundation nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+--------------------------------------------------------------------------------
------------------------------------ rtmidi ------------------------------------
--------------------------------------------------------------------------------
--- a/src/ft2_about.c
+++ b/src/ft2_about.c
@@ -7,7 +7,7 @@
#include "ft2_video.h"
#include "ft2_structs.h"
-#define NUM_STARS 1750
+#define NUM_STARS 2048
#define ABOUT_SCREEN_W 626
#define ABOUT_SCREEN_H 167
#define ABOUT_LOGO_W 449
@@ -26,10 +26,12 @@
} matrix_t;
static char *customText1 = "Clone by Olav \"8bitbubsy\" S\025rensen";
-static char customText2[64];
+static char *customText2 = "www.16-bits.org";
+static char customText3[64];
-static int16_t customText1X, customText2X, customTextY;
-static int32_t lastStarScreenPos[NUM_STARS], starfieldFade, logoFade;
+static int16_t customText1Y, customText2Y, customText3Y;
+static int16_t customText1X, customText2X, customText3X;
+static int32_t lastStarScreenPos[NUM_STARS], fadeValue;
static uint32_t randSeed, frameCounter;
static float f2pi;
static vector_t starPoints[NUM_STARS], rotation;
@@ -139,9 +141,8 @@
d = 255;
d ^= 255;
- d = (d * starfieldFade) >> 8;
- int32_t r = d - 66;
+ int32_t r = d - 68;
if (r < 0)
r = 0;
@@ -164,20 +165,20 @@
rotateMatrix();
starfield();
- rotation.x += 0.00009f;
- rotation.y += 0.00007f;
- rotation.z -= 0.00005f;
+ rotation.x -= 0.00011f;
+ rotation.z += 0.00006f;
- // fade in starfield
- if (starfieldFade < 256)
- starfieldFade += 4;
-
- // fade in logo after 1 second
- if (logoFade < 256 && frameCounter++ >= VBLANK_HZ*1)
+ // fade in stuff after 1/3th of a second
+ if (fadeValue < 256 && ++frameCounter >= (int32_t)((VBLANK_HZ/3.0)+0.5))
{
- blit32Fade(91, 31, bmp.ft2AboutLogo, ABOUT_LOGO_W, ABOUT_LOGO_H, logoFade);
- textOutFade(customText1X, customTextY, PAL_FORGRND, customText1, logoFade);
- logoFade += 4;
+ blit32Fade(91, 31, bmp.ft2AboutLogo, ABOUT_LOGO_W, ABOUT_LOGO_H, fadeValue);
+ textOutFade(customText1X, customText1Y, PAL_FORGRND, customText1, fadeValue);
+ textOutFade(customText2X, customText2Y, PAL_FORGRND, customText2, fadeValue);
+ textOutFade(customText3X, customText3Y, PAL_FORGRND, customText3, fadeValue);
+
+ fadeValue += 3;
+ if (fadeValue > 256)
+ fadeValue = 256;
}
}
@@ -193,14 +194,17 @@
showPushButton(PB_EXIT_ABOUT);
- sprintf(customText2, "v%s (%s)", PROG_VER_STR, __DATE__);
+ sprintf(customText3, "v%s (%s)", PROG_VER_STR, __DATE__);
customText1X = (SCREEN_W - textWidth(customText1)) >> 1;
customText2X = (SCREEN_W-8) - textWidth(customText2);
- customTextY = 157;
- textOut(customText2X, customTextY, PAL_FORGRND, customText2);
+ customText3X = (SCREEN_W-8) - textWidth(customText3);
+ customText1Y = 157;
+ customText2Y = 157-12;
+ customText3Y = 157;
aboutInit();
- frameCounter = starfieldFade = logoFade = 0;
+ frameCounter = 0;
+ fadeValue = 0;
ui.aboutScreenShown = true;
}
--- a/src/ft2_audio.c
+++ b/src/ft2_audio.c
@@ -7,7 +7,7 @@
#include <stdint.h>
#include "ft2_header.h"
#include "ft2_config.h"
-#include "ft2_scopes.h"
+#include "scopes/ft2_scopes.h"
#include "ft2_video.h"
#include "ft2_gui.h"
#include "ft2_midi.h"
@@ -29,10 +29,10 @@
static int8_t pmpCountDiv, pmpChannels = 2;
static uint16_t smpBuffSize;
-static int32_t randSeed = INITIAL_DITHER_SEED;
-static uint32_t oldAudioFreq, tickTimeLen, tickTimeLenFrac;
-static double dAudioNormalizeMul, dPrngStateL, dPrngStateR, dPanningTab[256+1];
-static voice_t voice[MAX_VOICES * 2];
+static uint32_t oldAudioFreq, tickTimeLen, tickTimeLenFrac, randSeed = INITIAL_DITHER_SEED;
+static float fAudioNormalizeMul, fPanningTab[256+1];
+static double dAudioNormalizeMul, dPrngStateL, dPrngStateR;
+static voice_t voice[MAX_CHANNELS * 2];
static void (*sendAudSamplesFunc)(uint8_t *, uint32_t, uint8_t); // "send mixed samples" routines
// globalized
@@ -45,16 +45,13 @@
void resetCachedMixerVars(void)
{
- stmTyp *ch = stm;
- for (int32_t i = 0; i < MAX_VOICES; i++, ch++)
+ channel_t *ch = channel;
+ for (int32_t i = 0; i < MAX_CHANNELS; i++, ch++)
ch->oldFinalPeriod = -1;
voice_t *v = voice;
- for (int32_t i = 0; i < MAX_VOICES*2; i++, v++)
- {
- v->dOldHz = 0.0;
+ for (int32_t i = 0; i < MAX_CHANNELS*2; i++, v++)
v->oldDelta = 0;
- }
}
void stopVoice(int32_t i)
@@ -63,13 +60,13 @@
v = &voice[i];
memset(v, 0, sizeof (voice_t));
- v->pan = 128;
+ v->panning = 128;
// clear "fade out" voice too
- v = &voice[MAX_VOICES + i];
+ v = &voice[MAX_CHANNELS + i];
memset(v, 0, sizeof (voice_t));
- v->pan = 128;
+ v->panning = 128;
}
bool setNewAudioSettings(void) // only call this from the main input/video thread
@@ -125,8 +122,37 @@
dAmp *= 32768.0;
dAudioNormalizeMul = dAmp;
+ fAudioNormalizeMul = (float)dAmp;
}
+void decreaseMasterVol(void)
+{
+ if (config.masterVol >= 16)
+ config.masterVol -= 16;
+ else
+ config.masterVol = 0;
+
+ setAudioAmp(config.boostLevel, config.masterVol, !!(config.specialFlags & BITDEPTH_32));
+
+ // if Config -> I/O Devices is open, update master volume scrollbar
+ if (ui.configScreenShown && editor.currConfigScreen == CONFIG_SCREEN_IO_DEVICES)
+ drawScrollBar(SB_MASTERVOL_SCROLL);
+}
+
+void increaseMasterVol(void)
+{
+ if (config.masterVol < (256-16))
+ config.masterVol += 16;
+ else
+ config.masterVol = 256;
+
+ setAudioAmp(config.boostLevel, config.masterVol, !!(config.specialFlags & BITDEPTH_32));
+
+ // if Config -> I/O Devices is open, update master volume scrollbar
+ if (ui.configScreenShown && editor.currConfigScreen == CONFIG_SCREEN_IO_DEVICES)
+ drawScrollBar(SB_MASTERVOL_SCROLL);
+}
+
void setNewAudioFreq(uint32_t freq) // for song-to-WAV rendering
{
if (freq == 0)
@@ -150,25 +176,22 @@
calcReplayerVars(audio.freq);
}
-void P_SetSpeed(uint16_t bpm)
+void setMixerBPM(int32_t bpm)
{
- if (bpm == 0)
+ if (bpm < MIN_BPM || bpm > MAX_BPM)
return;
- // non-FT2 check for security
- if (bpm > MAX_BPM)
- return;
+ int32_t i = bpm - MIN_BPM;
- audio.dSamplesPerTick = audio.dSamplesPerTickTab[bpm];
- audio.samplesPerTick = (int32_t)(audio.dSamplesPerTick + 0.5);
+ audio.samplesPerTick64 = audio.samplesPerTick64Tab[i]; // fixed-point
+ audio.samplesPerTick = (audio.samplesPerTick64 + (1LL << 31)) >> 32; // rounded
- // get tick time length for audio/video sync timestamp
- const uint64_t tickTimeLen64 = audio.tickTimeTab[bpm];
- tickTimeLen = tickTimeLen64 >> 32;
- tickTimeLenFrac = tickTimeLen64 & UINT32_MAX;
+ // for audio/video sync timestamp
+ tickTimeLen = audio.tickTimeTab[i];
+ tickTimeLenFrac = audio.tickTimeFracTab[i];
- // used for calculating volume ramp length for "ticks" ramps
- audio.dRampTickMul = audio.dRampTickMulTab[bpm];
+ // for calculating volume ramp length for tick-length ramps
+ audio.fRampTickMul = audio.fRampTickMulTab[i];
}
void audioSetVolRamp(bool volRamp)
@@ -189,55 +212,53 @@
{
// same formula as FT2's panning table (with 0.0f..1.0f range)
for (int32_t i = 0; i <= 256; i++)
- dPanningTab[i] = sqrt(i * (1.0 / 256.0));
+ fPanningTab[i] = sqrtf(i / 256.0f);
}
static void voiceUpdateVolumes(int32_t i, uint8_t status)
{
- double dDestVolL, dDestVolR;
-
voice_t *v = &voice[i];
- const double dVolL = v->dVol * dPanningTab[256-v->pan];
- const double dVolR = v->dVol * dPanningTab[ v->pan];
+ const float fVolumeL = v->fVolume * fPanningTab[256-v->panning];
+ const float fVolumeR = v->fVolume * fPanningTab[ v->panning];
if (!audio.volumeRampingFlag)
{
// volume ramping is disabled
- v->dVolL = dVolL;
- v->dVolR = dVolR;
- v->volRampSamples = 0;
+ v->fVolumeL = fVolumeL;
+ v->fVolumeR = fVolumeR;
+ v->volumeRampLength = 0;
return;
}
- v->dDestVolL = dVolL;
- v->dDestVolR = dVolR;
+ v->fVolumeLTarget = fVolumeL;
+ v->fVolumeRTarget = fVolumeR;
- if (status & IS_NyTon)
+ if (status & IS_Trigger)
{
// sample is about to start, ramp out/in at the same time
// setup "fade out" voice (only if current voice volume > 0)
- if (v->dVolL > 0.0 || v->dVolR > 0.0)
+ if (v->fVolumeL > 0.0f || v->fVolumeR > 0.0f)
{
- voice_t *f = &voice[MAX_VOICES+i];
+ voice_t *f = &voice[MAX_CHANNELS+i];
*f = *v; // copy voice
- f->volRampSamples = audio.quickVolRampSamples;
+ f->volumeRampLength = audio.quickVolRampSamples;
- dDestVolL = -f->dVolL;
- dDestVolR = -f->dVolR;
+ const float fVolumeLTarget = -f->fVolumeL;
+ const float fVolumeRTarget = -f->fVolumeR;
- f->dVolDeltaL = dDestVolL * audio.dRampQuickVolMul;
- f->dVolDeltaR = dDestVolR * audio.dRampQuickVolMul;
+ f->fVolumeLDelta = fVolumeLTarget * audio.fRampQuickVolMul;
+ f->fVolumeRDelta = fVolumeRTarget * audio.fRampQuickVolMul;
f->isFadeOutVoice = true;
}
// make current voice fade in from zero when it starts
- v->dVolL = 0.0;
- v->dVolR = 0.0;
+ v->fVolumeL = 0.0f;
+ v->fVolumeR = 0.0f;
}
// ramp volume changes
@@ -248,57 +269,45 @@
*/
// if destination volume and current volume is the same (and we have no sample trigger), don't do ramp
- if (dVolL == v->dVolL && dVolR == v->dVolR && !(status & IS_NyTon))
+ if (fVolumeL == v->fVolumeL && fVolumeR == v->fVolumeR && !(status & IS_Trigger))
{
// there is no volume change
- v->volRampSamples = 0;
+ v->volumeRampLength = 0;
}
else
{
- dDestVolL = dVolL - v->dVolL;
- dDestVolR = dVolR - v->dVolR;
+ const float fVolumeLTarget = fVolumeL - v->fVolumeL;
+ const float fVolumeRTarget = fVolumeR - v->fVolumeR;
if (status & IS_QuickVol)
{
- v->volRampSamples = audio.quickVolRampSamples;
- v->dVolDeltaL = dDestVolL * audio.dRampQuickVolMul;
- v->dVolDeltaR = dDestVolR * audio.dRampQuickVolMul;
+ v->fVolumeLDelta = fVolumeLTarget * audio.fRampQuickVolMul;
+ v->fVolumeRDelta = fVolumeRTarget * audio.fRampQuickVolMul;
+ v->volumeRampLength = audio.quickVolRampSamples;
+
}
else
{
- v->volRampSamples = audio.samplesPerTick;
- v->dVolDeltaL = dDestVolL * audio.dRampTickMul;
- v->dVolDeltaR = dDestVolR * audio.dRampTickMul;
+ v->fVolumeLDelta = fVolumeLTarget * audio.fRampTickMul;
+ v->fVolumeRDelta = fVolumeRTarget * audio.fRampTickMul;
+ v->volumeRampLength = audio.samplesPerTick;
}
}
}
-static void voiceTrigger(int32_t ch, sampleTyp *s, int32_t position)
+static void voiceTrigger(int32_t ch, sample_t *s, int32_t position)
{
voice_t *v = &voice[ch];
- int32_t length = s->len;
- int32_t loopStart = s->repS;
- int32_t loopLength = s->repL;
- int32_t loopEnd = s->repS + s->repL;
- uint8_t loopType = s->typ & 3;
- const bool sampleIs16Bit = (s->typ >> 4) & 1;
+ int32_t length = s->length;
+ int32_t loopStart = s->loopStart;
+ int32_t loopLength = s->loopLength;
+ int32_t loopEnd = s->loopStart + s->loopLength;
+ uint8_t loopType = GET_LOOPTYPE(s->flags);
+ bool sample16Bit = !!(s->flags & SAMPLE_16BIT);
- if (sampleIs16Bit)
+ if (s->dataPtr == NULL || length < 1)
{
- assert(!(length & 1));
- assert(!(loopStart & 1));
- assert(!(loopLength & 1));
- assert(!(loopEnd & 1));
-
- length >>= 1;
- loopStart >>= 1;
- loopLength >>= 1;
- loopEnd >>= 1;
- }
-
- if (s->pek == NULL || length < 1)
- {
v->active = false; // shut down voice (illegal parameters)
return;
}
@@ -306,36 +315,36 @@
if (loopLength < 1) // disable loop if loopLength is below 1
loopType = 0;
- if (sampleIs16Bit)
+ if (sample16Bit)
{
- v->base16 = (const int16_t *)s->pek;
+ v->base16 = (const int16_t *)s->dataPtr;
v->revBase16 = &v->base16[loopStart + loopEnd]; // for pingpong loops
v->leftEdgeTaps16 = s->leftEdgeTapSamples16 + SINC_LEFT_TAPS;
}
else
{
- v->base8 = s->pek;
+ v->base8 = s->dataPtr;
v->revBase8 = &v->base8[loopStart + loopEnd]; // for pingpong loops
v->leftEdgeTaps8 = s->leftEdgeTapSamples8 + SINC_LEFT_TAPS;
}
v->hasLooped = false; // for sinc interpolation special case
- v->backwards = false;
+ v->samplingBackwards = false;
v->loopType = loopType;
- v->end = (loopType > 0) ? loopEnd : length;
+ v->sampleEnd = (loopType == LOOP_OFF) ? length : loopEnd;
v->loopStart = loopStart;
v->loopLength = loopLength;
- v->pos = position;
- v->posFrac = 0;
+ v->position = position;
+ v->positionFrac = 0;
// if position overflows, shut down voice (f.ex. through 9xx command)
- if (v->pos >= v->end)
+ if (v->position >= v->sampleEnd)
{
v->active = false;
return;
}
- v->mixFuncOffset = (sampleIs16Bit * 9) + (audio.interpolationType * 3) + loopType;
+ v->mixFuncOffset = (sample16Bit * 9) + (audio.interpolationType * 3) + loopType;
v->active = true;
}
@@ -342,20 +351,20 @@
void resetRampVolumes(void)
{
voice_t *v = voice;
- for (int32_t i = 0; i < song.antChn; i++, v++)
+ for (int32_t i = 0; i < song.numChannels; i++, v++)
{
- v->dVolL = v->dDestVolL;
- v->dVolR = v->dDestVolR;
- v->volRampSamples = 0;
+ v->fVolumeL = v->fVolumeLTarget;
+ v->fVolumeR = v->fVolumeRTarget;
+ v->volumeRampLength = 0;
}
}
void updateVoices(void)
{
- stmTyp *ch = stm;
+ channel_t *ch = channel;
voice_t *v = voice;
- for (int32_t i = 0; i < song.antChn; i++, ch++, v++)
+ for (int32_t i = 0; i < song.numChannels; i++, ch++, v++)
{
const uint8_t status = ch->tmpStatus = ch->status; // (tmpStatus is used for audio/video sync queue)
if (status == 0)
@@ -364,10 +373,15 @@
ch->status = 0;
if (status & IS_Vol)
- v->dVol = ch->dFinalVol;
+ {
+ v->fVolume = ch->fFinalVol;
+ const int32_t scopeVolume = (int32_t)((SCOPE_HEIGHT * ch->fFinalVol) + 0.5f); // rounded
+ v->scopeVolume = (uint8_t)scopeVolume;
+ }
+
if (status & IS_Pan)
- v->pan = ch->finalPan;
+ v->panning = ch->finalPan;
if (status & (IS_Vol + IS_Pan))
voiceUpdateVolumes(i, status);
@@ -381,33 +395,33 @@
if (ch->finalPeriod == 0) // in FT2, period 0 -> delta 0
{
- v->dOldHz = 0.0;
+ v->scopeDelta = 0;
v->oldDelta = 0;
- v->dSincLUT = gKaiserSinc;
+ v->fSincLUT = fKaiserSinc;
}
else
{
const double dHz = dPeriod2Hz(ch->finalPeriod);
- const uint64_t delta64 = (int64_t)((dHz * audio.dHz2MixDeltaMul) + 0.5); // Hz -> rounded 32.32 fixed-point
+ const uintCPUWord_t delta = v->oldDelta = (intCPUWord_t)((dHz * audio.dHz2MixDeltaMul) + 0.5); // Hz -> fixed-point delta (rounded)
- v->dOldHz = dHz;
- v->oldDelta = delta64;
-
- // decide which sinc LUT to use according to resampling ratio
- if (delta64 <= 0x130000000) // 1.1875 (32.32fp)
- v->dSincLUT = gKaiserSinc;
- else if (delta64 <= 0x180000000) // 1.5 (32.32fp)
- v->dSincLUT = gDownSample1;
+ // decide which polyphase sinc LUT to use according to resampling ratio
+ if (delta <= (uintCPUWord_t)(1.1875 * MIXER_FRAC_SCALE))
+ v->fSincLUT = fKaiserSinc;
+ else if (delta <= (uintCPUWord_t)(1.5 * MIXER_FRAC_SCALE))
+ v->fSincLUT = fDownSample1;
else
- v->dSincLUT = gDownSample2;
+ v->fSincLUT = fDownSample2;
+
+ // set scope delta
+ const double dHz2ScopeDeltaMul = SCOPE_FRAC_SCALE / (double)SCOPE_HZ;
+ v->scopeDelta = (intCPUWord_t)((dHz * dHz2ScopeDeltaMul) + 0.5); // Hz -> fixed-point delta (rounded)
}
}
v->delta = v->oldDelta;
- v->dHz = v->dOldHz;
}
- if (status & IS_NyTon)
+ if (status & IS_Trigger)
voiceTrigger(i, ch->smpPtr, ch->smpStartPos);
}
}
@@ -438,7 +452,8 @@
{
// left channel - 1-bit triangular dithering
dPrng = random32() * (0.5 / INT32_MAX); // -0.5 .. 0.5
- dOut = ((audio.dMixBufferL[i] * dAudioNormalizeMul) + dPrng) - dPrngStateL;
+ dOut = (double)audio.fMixBufferL[i] * dAudioNormalizeMul;
+ dOut = (dOut + dPrng) - dPrngStateL;
dPrngStateL = dPrng;
out32 = (int32_t)dOut;
CLAMP16(out32);
@@ -446,11 +461,16 @@
// right channel - 1-bit triangular dithering
dPrng = random32() * (0.5 / INT32_MAX); // -0.5 .. 0.5
- dOut = ((audio.dMixBufferR[i] * dAudioNormalizeMul) + dPrng) - dPrngStateR;
+ dOut = (double)audio.fMixBufferR[i] * dAudioNormalizeMul;
+ dOut = (dOut + dPrng) - dPrngStateR;
dPrngStateR = dPrng;
out32 = (int32_t)dOut;
CLAMP16(out32);
*streamPointer16++ = (int16_t)out32;
+
+ // clear what we read from the mixing buffer
+ audio.fMixBufferL[i] = 0.0f;
+ audio.fMixBufferR[i] = 0.0f;
}
(void)numAudioChannels;
@@ -465,8 +485,9 @@
for (uint32_t i = 0; i < sampleBlockLength; i++)
{
// left channel - 1-bit triangular dithering
- dPrng = random32() * (0.5 / INT32_MAX); // -0.5..0.5
- dOut = ((audio.dMixBufferL[i] * dAudioNormalizeMul) + dPrng) - dPrngStateL;
+ dPrng = random32() * (0.5 / INT32_MAX); // -0.5 .. 0.5
+ dOut = (double)audio.fMixBufferL[i] * dAudioNormalizeMul;
+ dOut = (dOut + dPrng) - dPrngStateL;
dPrngStateL = dPrng;
out32 = (int32_t)dOut;
CLAMP16(out32);
@@ -473,13 +494,18 @@
*streamPointer16++ = (int16_t)out32;
// right channel - 1-bit triangular dithering
- dPrng = random32() * (0.5 / INT32_MAX); // -0.5..0.5
- dOut = ((audio.dMixBufferR[i] * dAudioNormalizeMul) + dPrng) - dPrngStateR;
+ dPrng = random32() * (0.5 / INT32_MAX); // -0.5 .. 0.5
+ dOut = (double)audio.fMixBufferR[i] * dAudioNormalizeMul;
+ dOut = (dOut + dPrng) - dPrngStateR;
dPrngStateR = dPrng;
out32 = (int32_t)dOut;
CLAMP16(out32);
*streamPointer16++ = (int16_t)out32;
+ // clear what we read from the mixing buffer
+ audio.fMixBufferL[i] = 0.0f;
+ audio.fMixBufferR[i] = 0.0f;
+
// send zeroes to the rest of the channels
for (uint32_t j = 2; j < numAudioChannels; j++)
*streamPointer16++ = 0;
@@ -488,20 +514,22 @@
static void sendSamples32BitStereo(uint8_t *stream, uint32_t sampleBlockLength, uint8_t numAudioChannels)
{
- double dOut;
-
- float *fStreamPointer32 = (float *)stream;
+ float fOut, *fStreamPointer32 = (float *)stream;
for (uint32_t i = 0; i < sampleBlockLength; i++)
{
// left channel
- dOut = audio.dMixBufferL[i] * dAudioNormalizeMul;
- dOut = CLAMP(dOut, -1.0, 1.0);
- *fStreamPointer32++ = (float)dOut;
+ fOut = audio.fMixBufferL[i] * fAudioNormalizeMul;
+ fOut = CLAMP(fOut, -1.0f, 1.0f);
+ *fStreamPointer32++ = fOut;
// right channel
- dOut = audio.dMixBufferR[i] * dAudioNormalizeMul;
- dOut = CLAMP(dOut, -1.0, 1.0);
- *fStreamPointer32++ = (float)dOut;
+ fOut = audio.fMixBufferR[i] * fAudioNormalizeMul;
+ fOut = CLAMP(fOut, -1.0f, 1.0f);
+ *fStreamPointer32++ = fOut;
+
+ // clear what we read from the mixing buffer
+ audio.fMixBufferL[i] = 0.0f;
+ audio.fMixBufferR[i] = 0.0f;
}
(void)numAudioChannels;
@@ -509,21 +537,23 @@
static void sendSamples32BitMultiChan(uint8_t *stream, uint32_t sampleBlockLength, uint8_t numAudioChannels)
{
- double dOut;
-
- float *fStreamPointer32 = (float *)stream;
+ float fOut, *fStreamPointer32 = (float *)stream;
for (uint32_t i = 0; i < sampleBlockLength; i++)
{
// left channel
- dOut = audio.dMixBufferL[i] * dAudioNormalizeMul;
- dOut = CLAMP(dOut, -1.0, 1.0);
- *fStreamPointer32++ = (float)dOut;
+ fOut = audio.fMixBufferL[i] * fAudioNormalizeMul;
+ fOut = CLAMP(fOut, -1.0f, 1.0f);
+ *fStreamPointer32++ = fOut;
// right channel
- dOut = audio.dMixBufferR[i] * dAudioNormalizeMul;
- dOut = CLAMP(dOut, -1.0, 1.0);
- *fStreamPointer32++ = (float)dOut;
+ fOut = audio.fMixBufferR[i] * fAudioNormalizeMul;
+ fOut = CLAMP(fOut, -1.0f, 1.0f);
+ *fStreamPointer32++ = fOut;
+ // clear what we read from the mixing buffer
+ audio.fMixBufferL[i] = 0.0f;
+ audio.fMixBufferR[i] = 0.0f;
+
// send zeroes to the rest of the channels
for (uint32_t j = 2; j < numAudioChannels; j++)
*fStreamPointer32++ = 0.0f;
@@ -533,37 +563,37 @@
static void doChannelMixing(int32_t bufferPosition, int32_t samplesToMix)
{
voice_t *v = voice; // normal voices
- voice_t *r = &voice[MAX_VOICES]; // volume ramp fadeout-voices
+ voice_t *r = &voice[MAX_CHANNELS]; // volume ramp fadeout-voices
- for (int32_t i = 0; i < song.antChn; i++, v++, r++)
+ for (int32_t i = 0; i < song.numChannels; i++, v++, r++)
{
if (v->active)
{
bool centerMixFlag;
- const bool volRampFlag = v->volRampSamples > 0;
+ const bool volRampFlag = (v->volumeRampLength > 0);
if (volRampFlag)
{
- centerMixFlag = (v->dDestVolL == v->dDestVolR) && (v->dVolDeltaL == v->dVolDeltaR);
+ centerMixFlag = (v->fVolumeLTarget == v->fVolumeRTarget) && (v->fVolumeLDelta == v->fVolumeRDelta);
}
else // no volume ramping active
{
- if (v->dVolL == 0.0 && v->dVolR == 0.0)
+ if (v->fVolumeL == 0.0f && v->fVolumeR == 0.0f)
{
silenceMixRoutine(v, samplesToMix);
continue;
}
- centerMixFlag = v->dVolL == v->dVolR;
+ centerMixFlag = (v->fVolumeL == v->fVolumeR);
}
- mixFuncTab[(centerMixFlag * 36) + (volRampFlag * 18) + v->mixFuncOffset](v, bufferPosition, samplesToMix);
+ mixFuncTab[((int32_t)centerMixFlag * 36) + ((int32_t)volRampFlag * 18) + v->mixFuncOffset](v, bufferPosition, samplesToMix);
}
if (r->active) // volume ramp fadeout-voice
{
- const bool centerMixFlag = (r->dDestVolL == r->dDestVolR) && (r->dVolDeltaL == r->dVolDeltaR);
- mixFuncTab[(centerMixFlag * 36) + 18 + r->mixFuncOffset](r, bufferPosition, samplesToMix);
+ const bool centerMixFlag = (r->fVolumeLTarget == r->fVolumeRTarget) && (r->fVolumeLDelta == r->fVolumeRDelta);
+ mixFuncTab[((int32_t)centerMixFlag * 36) + 18 + r->mixFuncOffset](r, bufferPosition, samplesToMix);
}
}
}
@@ -572,9 +602,6 @@
void mixReplayerTickToBuffer(uint32_t samplesToMix, uint8_t *stream, uint8_t bitDepth)
{
assert(samplesToMix <= MAX_WAV_RENDER_SAMPLES_PER_TICK);
- memset(audio.dMixBufferL, 0, samplesToMix * sizeof (double));
- memset(audio.dMixBufferR, 0, samplesToMix * sizeof (double));
-
doChannelMixing(0, samplesToMix);
// normalize mix buffer and send to audio stream
@@ -857,13 +884,13 @@
if (songPlaying)
{
// push pattern variables to sync queue
- pattSyncData.timer = song.curReplayerTimer;
- pattSyncData.patternPos = song.curReplayerPattPos;
- pattSyncData.pattern = song.curReplayerPattNr;
+ pattSyncData.tick = song.curReplayerTick;
+ pattSyncData.row = song.curReplayerRow;
+ pattSyncData.pattNum = song.curReplayerPattNum;
pattSyncData.songPos = song.curReplayerSongPos;
- pattSyncData.speed = song.speed;
- pattSyncData.tempo = (uint8_t)song.tempo;
- pattSyncData.globalVol = (uint8_t)song.globVol;
+ pattSyncData.BPM = song.BPM;
+ pattSyncData.speed = (uint8_t)song.speed;
+ pattSyncData.globalVolume = (uint8_t)song.globalVolume;
pattSyncData.timestamp = audio.tickTime64;
pattQueuePush(pattSyncData);
}
@@ -871,24 +898,24 @@
// push channel variables to sync queue
syncedChannel_t *c = chSyncData.channels;
- stmTyp *s = stm;
+ channel_t *s = channel;
voice_t *v = voice;
- for (int32_t i = 0; i < song.antChn; i++, c++, s++, v++)
+ for (int32_t i = 0; i < song.numChannels; i++, c++, s++, v++)
{
- c->vol = s->finalVol;
- c->dHz = v->dHz;
- c->instrNr = s->instrNr;
- c->sampleNr = s->sampleNr;
+ c->scopeVolume = v->scopeVolume;
+ c->scopeDelta = v->scopeDelta;
+ c->instrNum = s->instrNum;
+ c->smpNum = s->smpNum;
c->status = s->tmpStatus;
- c->smpStartPos = (uint16_t)s->smpStartPos;
+ c->smpStartPos = s->smpStartPos;
- c->pianoNoteNr = 255; // no piano key
+ c->pianoNoteNum = 255; // no piano key
if (songPlaying && (c->status & IS_Period) && s->envSustainActive)
{
- const int32_t note = getPianoKey(s->finalPeriod, s->fineTune, s->relTonNr);
+ const int32_t note = getPianoKey(s->finalPeriod, s->finetune, s->relativeNote);
if (note >= 0 && note <= 95)
- c->pianoNoteNr = (uint8_t)note;
+ c->pianoNoteNum = (uint8_t)note;
}
}
@@ -914,8 +941,6 @@
return;
assert(len <= MAX_WAV_RENDER_SAMPLES_PER_TICK);
- memset(audio.dMixBufferL, 0, len * sizeof (double));
- memset(audio.dMixBufferR, 0, len * sizeof (double));
int32_t bufferPosition = 0;
@@ -922,10 +947,8 @@
int32_t samplesLeft = len;
while (samplesLeft > 0)
{
- if (audio.dTickSampleCounter <= 0.0)
+ if (audio.tickSampleCounter64 <= 0) // new replayer tick
{
- // new replayer tick
-
replayerBusy = true;
if (audio.volumeRampingFlag)
@@ -935,12 +958,12 @@
updateVoices();
fillVisualsSyncBuffer();
- audio.dTickSampleCounter += audio.dSamplesPerTick;
+ audio.tickSampleCounter64 += audio.samplesPerTick64;
replayerBusy = false;
}
- const int32_t remainingTick = (int32_t)ceil(audio.dTickSampleCounter);
+ const int32_t remainingTick = (audio.tickSampleCounter64 + UINT32_MAX) >> 32; // ceil (rounded upwards)
int32_t samplesToMix = samplesLeft;
if (samplesToMix > remainingTick)
@@ -950,7 +973,8 @@
bufferPosition += samplesToMix;
samplesLeft -= samplesToMix;
- audio.dTickSampleCounter -= samplesToMix;
+ audio.tickSampleCounter64 -= (int64_t)samplesToMix << 32;
+
}
// normalize mix buffer and send to audio stream
@@ -961,37 +985,41 @@
static bool setupAudioBuffers(void)
{
- const uint32_t sampleSize = sizeof (double);
+ const uint32_t sampleSize = sizeof (float);
- audio.dMixBufferLUnaligned = (double *)MALLOC_PAD(MAX_WAV_RENDER_SAMPLES_PER_TICK * sampleSize, 256);
- audio.dMixBufferRUnaligned = (double *)MALLOC_PAD(MAX_WAV_RENDER_SAMPLES_PER_TICK * sampleSize, 256);
+ audio.fMixBufferLUnaligned = (float *)MALLOC_PAD(MAX_WAV_RENDER_SAMPLES_PER_TICK * sampleSize, 256);
+ audio.fMixBufferRUnaligned = (float *)MALLOC_PAD(MAX_WAV_RENDER_SAMPLES_PER_TICK * sampleSize, 256);
- if (audio.dMixBufferLUnaligned == NULL || audio.dMixBufferRUnaligned == NULL)
+ if (audio.fMixBufferLUnaligned == NULL || audio.fMixBufferRUnaligned == NULL)
return false;
// make aligned main pointers
- audio.dMixBufferL = (double *)ALIGN_PTR(audio.dMixBufferLUnaligned, 256);
- audio.dMixBufferR = (double *)ALIGN_PTR(audio.dMixBufferRUnaligned, 256);
+ audio.fMixBufferL = (float *)ALIGN_PTR(audio.fMixBufferLUnaligned, 256);
+ audio.fMixBufferR = (float *)ALIGN_PTR(audio.fMixBufferRUnaligned, 256);
+ // clear buffers
+ memset(audio.fMixBufferL, 0, MAX_WAV_RENDER_SAMPLES_PER_TICK * sampleSize);
+ memset(audio.fMixBufferR, 0, MAX_WAV_RENDER_SAMPLES_PER_TICK * sampleSize);
+
return true;
}
static void freeAudioBuffers(void)
{
- if (audio.dMixBufferLUnaligned != NULL)
+ if (audio.fMixBufferLUnaligned != NULL)
{
- free(audio.dMixBufferLUnaligned);
- audio.dMixBufferLUnaligned = NULL;
+ free(audio.fMixBufferLUnaligned);
+ audio.fMixBufferLUnaligned = NULL;
}
- if (audio.dMixBufferRUnaligned != NULL)
+ if (audio.fMixBufferRUnaligned != NULL)
{
- free(audio.dMixBufferRUnaligned);
- audio.dMixBufferRUnaligned = NULL;
+ free(audio.fMixBufferRUnaligned);
+ audio.fMixBufferRUnaligned = NULL;
}
- audio.dMixBufferL = NULL;
- audio.dMixBufferR = NULL;
+ audio.fMixBufferL = NULL;
+ audio.fMixBufferR = NULL;
}
void updateSendAudSamplesRoutine(bool lockMixer)
@@ -1058,7 +1086,7 @@
closeAudio();
if (config.audioFreq < MIN_AUDIO_FREQ || config.audioFreq > MAX_AUDIO_FREQ)
- config.audioFreq = 48000; // set default rate
+ config.audioFreq = DEFAULT_AUDIO_FREQ;
// get audio buffer size from config special flags
@@ -1105,10 +1133,14 @@
// test if the received audio rate is compatible
+#if CPU_64BIT
if (have.freq != 44100 && have.freq != 48000 && have.freq != 96000 && have.freq != 192000)
+#else
+ if (have.freq != 44100 && have.freq != 48000)
+#endif
{
if (showErrorMsg)
- showErrorMsgBox("Couldn't open audio device:\nThe program doesn't support an audio output rate of %dHz. Sorry!", have.freq);
+ showErrorMsgBox("Couldn't open audio device:\nThis program doesn't support an audio output rate of %dHz. Sorry!", have.freq);
closeAudio();
return false;
@@ -1162,22 +1194,22 @@
showConfigScreen();
updateWavRendererSettings();
- setAudioAmp(config.boostLevel, config.masterVol, (config.specialFlags & BITDEPTH_32) ? true : false);
+ setAudioAmp(config.boostLevel, config.masterVol, !!(config.specialFlags & BITDEPTH_32));
// don't call stopVoices() in this routine
- for (int32_t i = 0; i < MAX_VOICES; i++)
+ for (int32_t i = 0; i < MAX_CHANNELS; i++)
stopVoice(i);
stopAllScopes();
- audio.dTickSampleCounter = 0.0; // zero tick sample counter so that it will instantly initiate a tick
+ audio.tickSampleCounter64 = 0; // zero tick sample counter so that it will instantly initiate a tick
calcReplayerVars(audio.freq);
- if (song.speed == 0)
- song.speed = 125;
+ if (song.BPM == 0)
+ song.BPM = 125;
- P_SetSpeed(song.speed); // this is important
+ setMixerBPM(song.BPM); // this is important
updateSendAudSamplesRoutine(false);
audio.resetSyncTickTimeFlag = true;
--- a/src/ft2_audio.h
+++ b/src/ft2_audio.h
@@ -4,6 +4,7 @@
#include <stdbool.h>
#include <SDL2/SDL.h>
#include "ft2_replayer.h"
+#include "ft2_cpu.h"
enum
{
@@ -11,13 +12,16 @@
FREQ_TABLE_AMIGA = 1,
};
+#define DEFAULT_AUDIO_FREQ 48000
+
#define MIN_AUDIO_FREQ 44100
+
+#if CPU_64BIT
#define MAX_AUDIO_FREQ 192000
+#else
+#define MAX_AUDIO_FREQ 48000
+#endif
-#define MIXER_FRAC_BITS 32
-#define MIXER_FRAC_SCALE (1ULL << MIXER_FRAC_BITS)
-#define MIXER_FRAC_MASK (MIXER_FRAC_SCALE-1)
-
#define MAX_AUDIO_DEVICES 99
// for audio/video sync queue. (2^n-1 - don't change this! Queue buffer is already BIG in size)
@@ -31,11 +35,13 @@
bool linearPeriodsFlag, rescanAudioDevicesSupported;
volatile uint8_t interpolationType;
int32_t quickVolRampSamples, inputDeviceNum, outputDeviceNum, lastWorkingAudioFreq, lastWorkingAudioBits;
- uint32_t freq, audLatencyPerfValInt, audLatencyPerfValFrac, samplesPerTick, musicTimeSpeedVal;
- uint64_t tickTime64, tickTime64Frac, tickTimeTab[MAX_BPM+1];
- double dRampQuickVolMul, dRampTickMul, dRampTickMulTab[MAX_BPM+1];
- double *dMixBufferL, *dMixBufferR, *dMixBufferLUnaligned, *dMixBufferRUnaligned, dHz2MixDeltaMul;
- double dAudioLatencyMs, dSamplesPerTick, dTickSampleCounter, dSamplesPerTickTab[MAX_BPM+1];
+ uint32_t tickTimeTab[(MAX_BPM-MIN_BPM)+1], tickTimeFracTab[(MAX_BPM-MIN_BPM)+1];
+ int64_t tickSampleCounter64, samplesPerTick64, samplesPerTick64Tab[(MAX_BPM-MIN_BPM)+1];
+ uint32_t freq, audLatencyPerfValInt, audLatencyPerfValFrac, samplesPerTick, samplesPerTickFrac, musicTimeSpeedVal;
+ uint64_t tickTime64, tickTime64Frac;
+ float fRampQuickVolMul, fRampTickMul, fRampTickMulTab[(MAX_BPM-MIN_BPM)+1];
+ float *fMixBufferL, *fMixBufferR, *fMixBufferLUnaligned, *fMixBufferRUnaligned;
+ double dHz2MixDeltaMul, dAudioLatencyMs;
SDL_AudioDeviceID dev;
uint32_t wantFreq, haveFreq, wantSamples, haveSamples, wantChannels, haveChannels;
@@ -45,24 +51,25 @@
{
const int8_t *base8, *revBase8;
const int16_t *base16, *revBase16;
- bool active, backwards, isFadeOutVoice, hasLooped;
- uint8_t mixFuncOffset, pan, loopType;
- int32_t pos, end, loopStart, loopLength, oldPeriod;
- uint32_t volRampSamples;
- uint64_t posFrac, delta, oldDelta;
+ bool active, samplingBackwards, isFadeOutVoice, hasLooped;
+ uint8_t mixFuncOffset, panning, loopType, scopeVolume;
+ int32_t position, sampleEnd, loopStart, loopLength, oldPeriod;
+ uint32_t volumeRampLength;
+ uintCPUWord_t positionFrac, delta, oldDelta, scopeDelta;
+#
// if (loopEnabled && hasLooped && samplingPos <= loopStart+SINC_LEFT_TAPS) readFixedTapsFromThisPointer();
const int8_t *leftEdgeTaps8;
const int16_t *leftEdgeTaps16;
- const double *dSincLUT;
- double dOldHz, dHz, dVol, dDestVolL, dDestVolR, dVolL, dVolR, dVolDeltaL, dVolDeltaR;
+ const float *fSincLUT;
+ float fVolume, fVolumeL, fVolumeR, fVolumeLDelta, fVolumeRDelta, fVolumeLTarget, fVolumeRTarget;
} voice_t;
typedef struct pattSyncData_t
{
- uint8_t pattern, globalVol, songPos, timer, tempo, patternPos;
- uint16_t speed;
+ uint8_t pattNum, globalVolume, songPos, tick, speed, row;
+ uint16_t BPM;
uint64_t timestamp;
} pattSyncData_t;
@@ -74,7 +81,7 @@
typedef struct chSyncData_t
{
- syncedChannel_t channels[MAX_VOICES];
+ syncedChannel_t channels[MAX_CHANNELS];
uint64_t timestamp;
} chSyncData_t;
@@ -100,11 +107,14 @@
uint64_t getChQueueTimestamp(void);
void resetSyncQueues(void);
+void decreaseMasterVol(void);
+void increaseMasterVol(void);
+
void calcPanningTable(void);
void setAudioAmp(int16_t amp, int16_t masterVol, bool bitDepth32Flag);
void setNewAudioFreq(uint32_t freq);
void setBackOldAudioFreq(void);
-void P_SetSpeed(uint16_t bpm);
+void setMixerBPM(int32_t bpm);
void audioSetVolRamp(bool volRamp);
void audioSetInterpolationType(uint8_t interpolationType);
void stopVoice(int32_t i);
--- a/src/ft2_audioselector.c
+++ b/src/ft2_audioselector.c
@@ -360,20 +360,6 @@
void setToDefaultAudioOutputDevice(void)
{
- const char *devString = SDL_GetAudioDeviceName(0, false);
- if (devString == NULL)
- {
- if (audio.currOutputDevice != NULL)
- {
- free(audio.currOutputDevice);
- audio.currOutputDevice = NULL;
- }
-
- return;
- }
-
- const uint32_t stringLen = (uint32_t)strlen(devString);
-
if (audio.currOutputDevice != NULL)
{
free(audio.currOutputDevice);
@@ -380,30 +366,20 @@
audio.currOutputDevice = NULL;
}
- audio.currOutputDevice = (char *)malloc(stringLen + 1);
- if (audio.currOutputDevice == NULL)
- return;
-
- if (stringLen > 0)
- strcpy(audio.currOutputDevice, devString);
+ /* If we have more than one device, we can't know which one
+ ** is the default (and thus not get its device name).
+ ** SDL2 ought to have a function for this!
+ */
+ if (SDL_GetNumAudioDevices(false) == 1)
+ {
+ const char *devName = SDL_GetAudioDeviceName(0, false);
+ if (devName != NULL)
+ audio.currOutputDevice = strdup(devName);
+ }
}
void setToDefaultAudioInputDevice(void)
{
- const char *devString = SDL_GetAudioDeviceName(0, true);
- if (devString == NULL)
- {
- if (audio.currInputDevice != NULL)
- {
- free(audio.currInputDevice);
- audio.currInputDevice = NULL;
- }
-
- return;
- }
-
- const uint32_t stringLen = (uint32_t)strlen(devString);
-
if (audio.currInputDevice != NULL)
{
free(audio.currInputDevice);
@@ -410,12 +386,16 @@
audio.currInputDevice = NULL;
}
- audio.currInputDevice = (char *)malloc(stringLen + 1);
- if (audio.currInputDevice == NULL)
- return;
-
- if (stringLen > 0)
- strcpy(audio.currInputDevice, devString);
+ /* If we have more than one device, we can't know which one
+ ** is the default (and thus not get its device name).
+ ** SDL2 ought to have a function for this!
+ */
+ if (SDL_GetNumAudioDevices(true) == 1)
+ {
+ const char *devName = SDL_GetAudioDeviceName(0, true);
+ if (devName != NULL)
+ audio.currInputDevice = strdup(devName);
+ }
}
void rescanAudioDevices(void)
--- a/src/ft2_config.c
+++ b/src/ft2_config.c
@@ -32,6 +32,7 @@
#include "ft2_tables.h"
#include "ft2_bmp.h"
#include "ft2_structs.h"
+#include "ft2_cpu.h"
config_t config; // globalized
@@ -65,12 +66,18 @@
return checksum;
}
-static void loadConfigFromBuffer(void)
+static void loadConfigFromBuffer(bool defaults)
{
lockMixerCallback();
memcpy(&config, configBuffer, CONFIG_FILE_SIZE);
+ if (defaults)
+ config.audioFreq = DEFAULT_AUDIO_FREQ;
+
+ if (config.audioFreq > MAX_AUDIO_FREQ)
+ config.audioFreq = MAX_AUDIO_FREQ;
+
// if Nibbles highscore checksum is incorrect, load default highscores instead
const int32_t newChecksum = calcChecksum((uint8_t *)&config.NI_HighScore, sizeof (config.NI_HighScore));
if (newChecksum != config.NI_HighScoreChecksum)
@@ -125,9 +132,9 @@
config.ptnMaxChannels = CLAMP(config.ptnMaxChannels, 0, 3);
config.ptnFont = CLAMP(config.ptnFont, 0, 3);
config.mouseType = CLAMP(config.mouseType, 0, 3);
- config.cfg_StdPalNr = CLAMP(config.cfg_StdPalNr, 0, 11);
+ config.cfg_StdPalNum = CLAMP(config.cfg_StdPalNum, 0, 11);
config.cfg_SortPriority = CLAMP(config.cfg_SortPriority, 0, 1);
- config.NI_AntPlayers = CLAMP(config.NI_AntPlayers, 0, 1);
+ config.NI_NumPlayers = CLAMP(config.NI_NumPlayers, 0, 1);
config.NI_Speed = CLAMP(config.NI_Speed, 0, 3);
config.recMIDIVolSens = CLAMP(config.recMIDIVolSens, 0, 200);
config.recMIDIChn = CLAMP(config.recMIDIChn, 1, 16);
@@ -146,8 +153,12 @@
config.recQuantRes = 16;
}
+#if CPU_64BIT
if (config.audioFreq != 44100 && config.audioFreq != 48000 && config.audioFreq != 96000 && config.audioFreq != 192000)
- config.audioFreq = 48000;
+#else
+ if (config.audioFreq != 44100 && config.audioFreq != 48000)
+#endif
+ config.audioFreq = DEFAULT_AUDIO_FREQ;
if (config.audioInputFreq <= 1) // default value from FT2 (this was cdr_Sync) - set defaults
config.audioInputFreq = INPUT_FREQ_48KHZ;
@@ -174,12 +185,12 @@
audioSetInterpolationType(config.interpolation);
audioSetVolRamp((config.specialFlags & NO_VOLRAMP_FLAG) ? false : true);
- setAudioAmp(config.boostLevel, config.masterVol, config.specialFlags & BITDEPTH_32);
+ setAudioAmp(config.boostLevel, config.masterVol, !!(config.specialFlags & BITDEPTH_32));
setMouseShape(config.mouseType);
changeLogoType(config.id_FastLogo);
changeBadgeType(config.id_TritonProd);
ui.maxVisibleChannels = (uint8_t)(2 + ((config.ptnMaxChannels + 1) * 2));
- setPal16(palTable[config.cfg_StdPalNr], true);
+ setPal16(palTable[config.cfg_StdPalNum], true);
updatePattFontPtrs();
unlockMixerCallback();
@@ -195,7 +206,7 @@
static void setDefaultConfigSettings(void)
{
memcpy(configBuffer, defConfigData, CONFIG_FILE_SIZE);
- loadConfigFromBuffer();
+ loadConfigFromBuffer(true);
}
void resetConfig(void)
@@ -320,7 +331,7 @@
return false;
}
- loadConfigFromBuffer();
+ loadConfigFromBuffer(false);
return true;
}
@@ -702,7 +713,7 @@
return;
}
- loadConfigFromBuffer();
+ loadConfigFromBuffer(false);
}
// GUI-related code
@@ -812,8 +823,10 @@
{
case 44100: tmpID = RB_CONFIG_AUDIO_44KHZ; break;
default: case 48000: tmpID = RB_CONFIG_AUDIO_48KHZ; break;
+#if CPU_64BIT
case 96000: tmpID = RB_CONFIG_AUDIO_96KHZ; break;
case 192000: tmpID = RB_CONFIG_AUDIO_192KHZ; break;
+#endif
}
radioButtons[tmpID].state = RADIOBUTTON_CHECKED;
@@ -850,7 +863,7 @@
static void setConfigLayoutCheckButtonStates(void)
{
- checkBoxes[CB_CONF_PATTSTRETCH].checked = config.ptnUnpressed;
+ checkBoxes[CB_CONF_PATTSTRETCH].checked = config.ptnStretch;
checkBoxes[CB_CONF_HEXCOUNT].checked = config.ptnHex;
checkBoxes[CB_CONF_ACCIDENTAL].checked = config.ptnAcc ? true : false;
checkBoxes[CB_CONF_SHOWZEROES].checked = config.ptnInstrZero;
@@ -857,7 +870,7 @@
checkBoxes[CB_CONF_FRAMEWORK].checked = config.ptnFrmWrk;
checkBoxes[CB_CONF_LINECOLORS].checked = config.ptnLineLight;
checkBoxes[CB_CONF_CHANNUMS].checked = config.ptnChnNumbers;
- checkBoxes[CB_CONF_SHOW_VOLCOL].checked = config.ptnS3M;
+ checkBoxes[CB_CONF_SHOW_VOLCOL].checked = config.ptnShowVolColumn;
checkBoxes[CB_CONF_SOFTWARE_MOUSE].checked = (config.specialFlags2 & HARDWARE_MOUSE) ? false : true;
showCheckBox(CB_CONF_PATTSTRETCH);
@@ -939,12 +952,12 @@
// PALETTE ENTRIES
uncheckRadioButtonGroup(RB_GROUP_CONFIG_PAL_ENTRIES);
- radioButtons[RB_CONFIG_PAL_PATTERNTEXT + cfg_ColorNr].state = RADIOBUTTON_CHECKED;
+ radioButtons[RB_CONFIG_PAL_PATTERNTEXT + cfg_ColorNum].state = RADIOBUTTON_CHECKED;
showRadioButtonGroup(RB_GROUP_CONFIG_PAL_ENTRIES);
// PALETTE PRESET
uncheckRadioButtonGroup(RB_GROUP_CONFIG_PAL_PRESET);
- switch (config.cfg_StdPalNr)
+ switch (config.cfg_StdPalNum)
{
default:
case PAL_ARCTIC: tmpID = RB_CONFIG_PAL_ARCTIC; break;
@@ -1141,9 +1154,10 @@
textOutShadow(509, 3, PAL_FORGRND, PAL_DSKTOP2, "Mixing frequency:");
textOutShadow(525, 17, PAL_FORGRND, PAL_DSKTOP2, "44100Hz");
textOutShadow(525, 31, PAL_FORGRND, PAL_DSKTOP2, "48000Hz (default)");
+#if CPU_64BIT
textOutShadow(525, 45, PAL_FORGRND, PAL_DSKTOP2, "96000Hz");
textOutShadow(525, 59, PAL_FORGRND, PAL_DSKTOP2, "192000Hz");
-
+#endif
textOutShadow(509, 76, PAL_FORGRND, PAL_DSKTOP2, "Frequency table:");
textOutShadow(525, 90, PAL_FORGRND, PAL_DSKTOP2, "Amiga freq. table");
textOutShadow(525, 104, PAL_FORGRND, PAL_DSKTOP2, "Linear freq. table");
@@ -1605,6 +1619,7 @@
setNewAudioSettings();
}
+#if CPU_64BIT
void rbConfigAudio96kHz(void)
{
config.audioFreq = 96000;
@@ -1616,6 +1631,7 @@
config.audioFreq = 192000;
setNewAudioSettings();
}
+#endif
void rbConfigAudioInput44kHz(void)
{
@@ -1638,7 +1654,7 @@
void rbConfigFreqTableAmiga(void)
{
lockMixerCallback();
- setFrqTab(false);
+ setFrequencyTable(false);
unlockMixerCallback();
}
@@ -1645,7 +1661,7 @@
void rbConfigFreqTableLinear(void)
{
lockMixerCallback();
- setFrqTab(true);
+ setFrequencyTable(true);
unlockMixerCallback();
}
@@ -1664,7 +1680,7 @@
static void redrawPatternEditor(void) // called after changing some pattern editor settings in config
{
// if the cursor was on the volume column while we turned volume column off, move it to effect type slot
- if (!config.ptnS3M && (cursor.object == CURSOR_VOL1 || cursor.object == CURSOR_VOL2))
+ if (!config.ptnShowVolColumn && (cursor.object == CURSOR_VOL1 || cursor.object == CURSOR_VOL2))
cursor.object = CURSOR_EFX0;
updateChanNums();
@@ -1673,7 +1689,7 @@
void cbConfigPattStretch(void)
{
- config.ptnUnpressed ^= 1;
+ config.ptnStretch ^= 1;
redrawPatternEditor();
}
@@ -1716,7 +1732,7 @@
void cbConfigShowVolCol(void)
{
- config.ptnS3M ^= 1;
+ config.ptnShowVolColumn ^= 1;
redrawPatternEditor();
}
@@ -2156,7 +2172,7 @@
if (config.boostLevel != (int8_t)pos + 1)
{
config.boostLevel = (int8_t)pos + 1;
- setAudioAmp(config.boostLevel, config.masterVol, config.specialFlags & BITDEPTH_32);
+ setAudioAmp(config.boostLevel, config.masterVol, !!(config.specialFlags & BITDEPTH_32));
configDrawAmp();
updateWavRendererSettings();
}
@@ -2177,7 +2193,7 @@
if (config.masterVol != (int16_t)pos)
{
config.masterVol = (int16_t)pos;
- setAudioAmp(config.boostLevel, config.masterVol, config.specialFlags & BITDEPTH_32);
+ setAudioAmp(config.boostLevel, config.masterVol, !!(config.specialFlags & BITDEPTH_32));
}
}
--- a/src/ft2_config.h
+++ b/src/ft2_config.h
@@ -4,6 +4,7 @@
#include <stdbool.h>
#include "ft2_replayer.h"
#include "ft2_palette.h"
+#include "ft2_cpu.h"
#define CFG_ID_STR "FastTracker 2.0 configuration file\x1A"
#define CONFIG_FILE_SIZE 1736
@@ -110,10 +111,11 @@
#endif
highScoreType;
+// this has some Swedish names, those variables are not used in our clone.
typedef struct config_t // exact FT2.CFG layout (with some modifications)
{
char cfgID[35];
- uint16_t ver;
+ uint16_t version;
uint32_t audioFreq; // was "BIOSSum" (never used in FT2)
int16_t utEnhet, masterVol, inputVol, inputDev;
uint8_t interpolation, internMode, stereoMode;
@@ -120,7 +122,7 @@
uint8_t specialFlags2; // was lo-byte of "sample16Bit" (was used for external audio sampling)
uint8_t dontShowAgainFlags; // was hi-byte of "sample16Bit" (was used for external audio sampling)
int16_t inEnhet, sbPort, sbDMA, sbHiDMA, sbInt, sbOutFilter;
- uint8_t true16Bit, ptnUnpressed, ptnHex, ptnInstrZero, ptnFrmWrk, ptnLineLight, ptnS3M, ptnChnNumbers;
+ uint8_t true16Bit, ptnStretch, ptnHex, ptnInstrZero, ptnFrmWrk, ptnLineLight, ptnShowVolColumn, ptnChnNumbers;
int16_t ptnLineLightStep, ptnFont, ptnAcc;
pal16 userPal[16];
uint16_t comMacro[10], volMacro[10];
@@ -146,18 +148,18 @@
uint8_t tracksPathLen;
char tracksPath[79+1];
uint8_t id_FastLogo, id_TritonProd;
- int16_t cfg_StdPalNr;
+ int16_t cfg_StdPalNum;
uint8_t cfg_AutoSave;
int16_t smpEd_SampleNote;
highScoreType NI_HighScore[10];
- int16_t NI_AntPlayers, NI_Speed;
+ int16_t NI_NumPlayers, NI_Speed;
uint8_t NI_Surround, NI_Grid, NI_Wrap;
int32_t NI_HighScoreChecksum;
- int16_t mouseType, mouseAnimType, mouseSpeed, keyLayout, boostLevel, stdEnvP[6][2][12][2];
- uint16_t stdVolEnvAnt[6], stdVolEnvSust[6], stdVolEnvRepS[6], stdVolEnvRepE[6];
- uint16_t stdPanEnvAnt[6], stdPanEnvSust[6], stdPanEnvRepS[6], stdPanEnvRepE[6];
- uint16_t stdFadeOut[6], stdVibRate[6], stdVibDepth[6], stdVibSweep[6], stdVibTyp[6];
- uint16_t stdVolEnvTyp[6], stdPanEnvTyp[6];
+ int16_t mouseType, mouseAnimType, mouseSpeed, keyLayout, boostLevel, stdEnvPoints[6][2][12][2];
+ uint16_t stdVolEnvLength[6], stdVolEnvSustain[6], stdVolEnvLoopStart[6], stdVolEnvLoopEnd[6];
+ uint16_t stdPanEnvLength[6], stdPanEnvSustain[6], stdPanEnvLoopStart[6], stdPanEnvLoopEnd[6];
+ uint16_t stdFadeout[6], stdVibRate[6], stdVibDepth[6], stdVibSweep[6], stdVibType[6];
+ uint16_t stdVolEnvFlags[6], stdPanEnvFlags[6];
int16_t antStars, ptnMaxChannels;
uint16_t sampleRates[16];
uint8_t cfg_OverwriteWarning;
@@ -216,8 +218,10 @@
void rbConfigAudioIntrpSinc(void);
void rbConfigAudio44kHz(void);
void rbConfigAudio48kHz(void);
+#if CPU_64BIT
void rbConfigAudio96kHz(void);
void rbConfigAudio192kHz(void);
+#endif
void rbConfigAudioInput44kHz(void);
void rbConfigAudioInput48kHz(void);
void rbConfigAudioInput96kHz(void);
--- /dev/null
+++ b/src/ft2_cpu.h
@@ -1,0 +1,32 @@
+#pragma once
+
+#include <stdint.h>
+
+#ifdef _WIN32
+
+#ifdef _WIN64
+#define CPU_64BIT 1
+#else
+#define CPU_64BIT 0
+#endif
+
+#else
+#include <limits.h>
+
+#if __WORDSIZE == 64
+#define CPU_64BIT 1
+#else
+#define CPU_64BIT 0
+#endif
+
+#endif
+
+#if CPU_64BIT
+#define CPU_BITS 64
+#define uintCPUWord_t uint64_t
+#define intCPUWord_t int64_t
+#else
+#define CPU_BITS 32
+#define uintCPUWord_t uint32_t
+#define intCPUWord_t int32_t
+#endif
--- a/src/ft2_diskop.c
+++ b/src/ft2_diskop.c
@@ -848,18 +848,18 @@
}
}
-static void createOverwriteText(char *name)
+void createFileOverwriteText(char *filename, char *buffer)
{
char nameTmp[128];
// read entry name to a small buffer
- const uint32_t nameLen = (uint32_t)strlen(name);
- memcpy(nameTmp, name, (nameLen >= sizeof (nameTmp)) ? sizeof (nameTmp) : (nameLen + 1));
+ const uint32_t nameLen = (uint32_t)strlen(filename);
+ memcpy(nameTmp, filename, (nameLen >= sizeof (nameTmp)) ? sizeof (nameTmp) : (nameLen + 1));
nameTmp[sizeof (nameTmp) - 1] = '\0';
trimEntryName(nameTmp, false);
- sprintf(FReq_SysReqText, "Overwrite file \"%s\"?", nameTmp);
+ sprintf(buffer, "Overwrite file \"%s\"?", nameTmp);
}
static void diskOpSave(bool checkOverwrite)
@@ -908,7 +908,7 @@
if (checkOverwrite && fileExistsAnsi(FReq_FileName))
{
- createOverwriteText(FReq_FileName);
+ createFileOverwriteText(FReq_FileName, FReq_SysReqText);
if (okBox(2, "System request", FReq_SysReqText) != 1)
return;
}
@@ -932,7 +932,7 @@
if (checkOverwrite && fileExistsAnsi(FReq_FileName))
{
- createOverwriteText(FReq_FileName);
+ createFileOverwriteText(FReq_FileName, FReq_SysReqText);
if (okBox(2, "System request", FReq_SysReqText) != 1)
return;
}
@@ -961,7 +961,7 @@
if (checkOverwrite && fileExistsAnsi(FReq_FileName))
{
- createOverwriteText(FReq_FileName);
+ createFileOverwriteText(FReq_FileName, FReq_SysReqText);
if (okBox(2, "System request", FReq_SysReqText) != 1)
return;
}
@@ -985,7 +985,7 @@
if (checkOverwrite && fileExistsAnsi(FReq_FileName))
{
- createOverwriteText(FReq_FileName);
+ createFileOverwriteText(FReq_FileName, FReq_SysReqText);
if (okBox(2, "System request", FReq_SysReqText) != 1)
return;
}
@@ -1008,7 +1008,7 @@
if (checkOverwrite && fileExistsAnsi(FReq_FileName))
{
- createOverwriteText(FReq_FileName);
+ createFileOverwriteText(FReq_FileName, FReq_SysReqText);
if (okBox(2, "System request", FReq_SysReqText) != 1)
return;
}
--- a/src/ft2_diskop.h
+++ b/src/ft2_diskop.h
@@ -82,4 +82,5 @@
void rbDiskOpSmpSaveRaw(void);
void rbDiskOpSmpSaveIff(void);
void trimEntryName(char *name, bool isDir);
+void createFileOverwriteText(char *filename, char *buffer);
bool fileExistsAnsi(char *str);
--- a/src/ft2_edit.c
+++ b/src/ft2_edit.c
@@ -33,11 +33,11 @@
static int8_t lastTranspVal;
static uint8_t lastInsMode, lastTranspMode;
static uint32_t transpDelNotes; // count of under-/overflowing notes for warning message
-static tonTyp clearNote;
+static note_t clearNote;
-static tonTyp blkCopyBuff[MAX_PATT_LEN * MAX_VOICES];
-static tonTyp ptnCopyBuff[MAX_PATT_LEN * MAX_VOICES];
-static tonTyp trackCopyBuff[MAX_PATT_LEN];
+static note_t blkCopyBuff[MAX_PATT_LEN * MAX_CHANNELS];
+static note_t ptnCopyBuff[MAX_PATT_LEN * MAX_CHANNELS];
+static note_t trackCopyBuff[MAX_PATT_LEN];
static const int8_t tickArr[16] = { 16, 8, 0, 4, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 1 };
@@ -47,7 +47,7 @@
static bool testNoteKeys(SDL_Scancode scancode)
{
const int8_t noteNum = scancodeKeyToNote(scancode);
- if (noteNum == 97)
+ if (noteNum == NOTE_OFF)
{
// inserts "note off" if editing song
if (playMode == PLAYMODE_EDIT || playMode == PLAYMODE_RECPATT || playMode == PLAYMODE_RECSONG)
@@ -55,11 +55,11 @@
if (!allocatePattern(editor.editPattern))
return true; // key pressed
- patt[editor.editPattern][(editor.pattPos * MAX_VOICES) + cursor.ch].ton = 97;
+ pattern[editor.editPattern][(editor.row * MAX_CHANNELS) + cursor.ch].note = NOTE_OFF;
- const uint16_t pattLen = pattLens[editor.editPattern];
- if (playMode == PLAYMODE_EDIT && pattLen >= 1)
- setPos(-1, (editor.pattPos + editor.ID_Add) % pattLen, true);
+ const uint16_t numRows = patternNumRows[editor.editPattern];
+ if (playMode == PLAYMODE_EDIT && numRows >= 1)
+ setPos(-1, (editor.row + editor.editRowSkip) % numRows, true);
ui.updatePatternEditor = true;
setSongModifiedFlag();
@@ -88,7 +88,6 @@
static bool testEditKeys(SDL_Scancode scancode, SDL_Keycode keycode)
{
int8_t i;
- uint8_t oldVal;
if (cursor.object == CURSOR_NOTE)
{
@@ -153,18 +152,18 @@
// insert slot data
- tonTyp *ton = &patt[editor.editPattern][(editor.pattPos * MAX_VOICES) + cursor.ch];
+ note_t *p = &pattern[editor.editPattern][(editor.row * MAX_CHANNELS) + cursor.ch];
switch (cursor.object)
{
case CURSOR_INST1:
{
- oldVal = ton->instr;
+ uint8_t oldVal = p->instr;
- ton->instr = (ton->instr & 0x0F) | (i << 4);
- if (ton->instr > MAX_INST)
- ton->instr = MAX_INST;
+ p->instr = (p->instr & 0x0F) | (i << 4);
+ if (p->instr > MAX_INST)
+ p->instr = MAX_INST;
- if (ton->instr != oldVal)
+ if (p->instr != oldVal)
setSongModifiedFlag();
}
break;
@@ -171,10 +170,10 @@
case CURSOR_INST2:
{
- oldVal = ton->instr;
- ton->instr = (ton->instr & 0xF0) | i;
+ uint8_t oldVal = p->instr;
+ p->instr = (p->instr & 0xF0) | i;
- if (ton->instr != oldVal)
+ if (p->instr != oldVal)
setSongModifiedFlag();
}
break;
@@ -181,13 +180,13 @@
case CURSOR_VOL1:
{
- oldVal = ton->vol;
+ uint8_t oldVal = p->vol;
- ton->vol = (ton->vol & 0x0F) | ((i + 1) << 4);
- if (ton->vol >= 0x51 && ton->vol <= 0x5F)
- ton->vol = 0x50;
+ p->vol = (p->vol & 0x0F) | ((i + 1) << 4);
+ if (p->vol >= 0x51 && p->vol <= 0x5F)
+ p->vol = 0x50;
- if (ton->vol != oldVal)
+ if (p->vol != oldVal)
setSongModifiedFlag();
}
break;
@@ -194,17 +193,17 @@
case CURSOR_VOL2:
{
- oldVal = ton->vol;
+ uint8_t oldVal = p->vol;
- if (ton->vol < 0x10)
- ton->vol = 0x10 + i;
+ if (p->vol < 0x10)
+ p->vol = 0x10 + i;
else
- ton->vol = (ton->vol & 0xF0) | i;
+ p->vol = (p->vol & 0xF0) | i;
- if (ton->vol >= 0x51 && ton->vol <= 0x5F)
- ton->vol = 0x50;
+ if (p->vol >= 0x51 && p->vol <= 0x5F)
+ p->vol = 0x50;
- if (ton->vol != oldVal)
+ if (p->vol != oldVal)
setSongModifiedFlag();
}
break;
@@ -211,11 +210,10 @@
case CURSOR_EFX0:
{
- oldVal = ton->effTyp;
+ uint8_t oldVal = p->efx;
- ton->effTyp = i;
-
- if (ton->effTyp != oldVal)
+ p->efx = i;
+ if (p->efx != oldVal)
setSongModifiedFlag();
}
break;
@@ -222,11 +220,10 @@
case CURSOR_EFX1:
{
- oldVal = ton->eff;
+ uint8_t oldVal = p->efxData;
- ton->eff = (ton->eff & 0x0F) | (i << 4);
-
- if (ton->eff != oldVal)
+ p->efxData = (p->efxData & 0x0F) | (i << 4);
+ if (p->efxData != oldVal)
setSongModifiedFlag();
}
break;
@@ -233,11 +230,10 @@
case CURSOR_EFX2:
{
- oldVal = ton->eff;
+ uint8_t oldVal = p->efxData;
- ton->eff = (ton->eff & 0xF0) | i;
-
- if (ton->eff != oldVal)
+ p->efxData = (p->efxData & 0xF0) | i;
+ if (p->efxData != oldVal)
setSongModifiedFlag();
}
break;
@@ -247,9 +243,9 @@
// increase row (only in edit mode)
- const int16_t pattLen = pattLens[editor.editPattern];
- if (playMode == PLAYMODE_EDIT && pattLen >= 1)
- setPos(-1, (editor.pattPos + editor.ID_Add) % pattLen, true);
+ const int16_t numRows = patternNumRows[editor.editPattern];
+ if (playMode == PLAYMODE_EDIT && numRows >= 1)
+ setPos(-1, (editor.row + editor.editRowSkip) % numRows, true);
if (i == 0) // if we inserted a zero, check if pattern is empty, for killing
killPatternIfUnused(editor.editPattern);
@@ -258,87 +254,85 @@
return true;
}
-// directly ported from the original FT2 code (fun fact: named EvulateTimeStamp() in the FT2 code)
-static void evaluateTimeStamp(int16_t *songPos, int16_t *pattNr, int16_t *pattPos, int16_t *tick)
+static void evaluateTimeStamp(int16_t *songPos, int16_t *pattNum, int16_t *row, int16_t *tick)
{
- int16_t sp = editor.songPos;
- int16_t nr = editor.editPattern;
- int16_t row = editor.pattPos;
- int16_t t = editor.tempo - editor.timer;
+ int16_t outSongPos = editor.songPos;
+ int16_t outPattern = editor.editPattern;
+ int16_t outRow = editor.row;
+ int16_t outTick = editor.speed - editor.tick;
- t = CLAMP(t, 0, editor.tempo - 1);
+ outTick = CLAMP(outTick, 0, editor.speed - 1);
// this is needed, but also breaks quantization on speed>15
- if (t > 15)
- t = 15;
+ if (outTick > 15)
+ outTick = 15;
- const int16_t pattLen = pattLens[nr];
+ const int16_t numRows = patternNumRows[outPattern];
if (config.recQuant > 0)
{
- int16_t r;
if (config.recQuantRes >= 16)
{
- t += (editor.tempo >> 1) + 1;
+ outTick += (editor.speed >> 1) + 1;
}
else
{
- r = tickArr[config.recQuantRes-1];
+ int16_t r = tickArr[config.recQuantRes-1];
+ int16_t p = outRow & (r - 1);
- int16_t p = row & (r - 1);
if (p < (r >> 1))
- row -= p;
+ outRow -= p;
else
- row = (row + r) - p;
+ outRow = (outRow + r) - p;
- t = 0;
+ outTick = 0;
}
}
- if (t > editor.tempo)
+ if (outTick > editor.speed)
{
- t -= editor.tempo;
- row++;
+ outTick -= editor.speed;
+ outRow++;
}
- if (row >= pattLen)
+ if (outRow >= numRows)
{
+ outRow = 0;
+
if (playMode == PLAYMODE_RECSONG)
- sp++;
+ outSongPos++;
- row = 0;
- if (sp >= song.len)
- sp = song.repS;
+ if (outSongPos >= song.songLength)
+ outSongPos = song.songLoopStart;
- nr = song.songTab[sp];
+ outPattern = song.orders[outSongPos];
}
- *songPos = sp;
- *pattNr = nr;
- *pattPos = row;
- *tick = t;
+ *songPos = outSongPos;
+ *pattNum = outPattern;
+ *row = outRow;
+ *tick = outTick;
}
-// directly ported from the original FT2 code - what a mess, but it works...
-void recordNote(uint8_t note, int8_t vol)
+void recordNote(uint8_t noteNum, int8_t vol) // directly ported from the original FT2 code - what a mess, but it works...
{
int8_t i;
- int16_t nr, sp, pattpos, tick;
+ int16_t pattNum, songPos, row, tick;
int32_t time;
- tonTyp *noteData;
+ note_t *p;
- const int16_t oldpattpos = editor.pattPos;
+ const int16_t oldRow = editor.row;
if (songPlaying)
{
// row quantization
- evaluateTimeStamp(&sp, &nr, &pattpos, &tick);
+ evaluateTimeStamp(&songPos, &pattNum, &row, &tick);
}
else
{
- sp = editor.songPos;
- nr = editor.editPattern;
- pattpos = editor.pattPos;
+ songPos = editor.songPos;
+ pattNum = editor.editPattern;
+ row = editor.row;
tick = 0;
}
@@ -345,7 +339,7 @@
bool editmode = (playMode == PLAYMODE_EDIT);
bool recmode = (playMode == PLAYMODE_RECSONG) || (playMode == PLAYMODE_RECPATT);
- if (note == 97)
+ if (noteNum == NOTE_OFF)
vol = 0;
int8_t c = -1;
@@ -358,7 +352,7 @@
if ((config.multiEdit && editmode) || (config.multiRec && recmode))
{
time = 0x7FFFFFFF;
- for (i = 0; i < song.antChn; i++)
+ for (i = 0; i < song.numChannels; i++)
{
if (editor.chnMode[i] && config.multiRecChn[i] && editor.keyOffTime[i] < time && editor.keyOnTab[i] == 0)
{
@@ -372,9 +366,9 @@
c = cursor.ch;
}
- for (i = 0; i < song.antChn; i++)
+ for (i = 0; i < song.numChannels; i++)
{
- if (note == editor.keyOnTab[i] && config.multiRecChn[i])
+ if (noteNum == editor.keyOnTab[i] && config.multiRecChn[i])
k = i;
}
}
@@ -388,7 +382,7 @@
if (songPlaying)
{
- for (i = 0; i < song.antChn; i++)
+ for (i = 0; i < song.numChannels; i++)
{
if (editor.keyOffTime[i] < time && editor.keyOnTab[i] == 0 && config.multiRecChn[i])
{
@@ -400,7 +394,7 @@
if (time == 0x7FFFFFFF)
{
- for (i = 0; i < song.antChn; i++)
+ for (i = 0; i < song.numChannels; i++)
{
if (editor.keyOffTime[i] < time && editor.keyOnTab[i] == 0)
{
@@ -415,9 +409,9 @@
c = cursor.ch;
}
- for (i = 0; i < song.antChn; i++)
+ for (i = 0; i < song.numChannels; i++)
{
- if (note == editor.keyOnTab[i])
+ if (noteNum == editor.keyOnTab[i])
k = i;
}
}
@@ -429,37 +423,37 @@
// play note
- editor.keyOnTab[c] = note;
+ editor.keyOnTab[c] = noteNum;
- if (pattpos >= oldpattpos) // non-FT2 fix: only do this if we didn't quantize to next row
+ if (row >= oldRow) // non-FT2 fix: only do this if we didn't quantize to next row
{
#ifdef HAS_MIDI
- playTone(c, editor.curInstr, note, vol, midi.currMIDIVibDepth, midi.currMIDIPitch);
+ playTone(c, editor.curInstr, noteNum, vol, midi.currMIDIVibDepth, midi.currMIDIPitch);
#else
- playTone(c, editor.curInstr, note, vol, 0, 0);
+ playTone(c, editor.curInstr, noteNum, vol, 0, 0);
#endif
}
if (editmode || recmode)
{
- if (allocatePattern(nr))
+ if (allocatePattern(pattNum))
{
- const int16_t pattLen = pattLens[nr];
- noteData = &patt[nr][(pattpos * MAX_VOICES) + c];
+ const int16_t numRows = patternNumRows[pattNum];
+ p = &pattern[pattNum][(row * MAX_CHANNELS) + c];
// insert data
- noteData->ton = note;
+ p->note = noteNum;
if (editor.curInstr > 0)
- noteData->instr = editor.curInstr;
+ p->instr = editor.curInstr;
if (vol >= 0)
- noteData->vol = 0x10 + vol;
+ p->vol = 0x10 + vol;
if (!recmode)
{
// increase row (only in edit mode)
- if (pattLen >= 1)
- setPos(-1, (editor.pattPos + editor.ID_Add) % pattLen, true);
+ if (numRows >= 1)
+ setPos(-1, (editor.row + editor.editRowSkip) % numRows, true);
}
else
{
@@ -466,8 +460,8 @@
// apply tick delay for note if quantization is disabled
if (!config.recQuant && tick > 0)
{
- noteData->effTyp = 0x0E;
- noteData->eff = 0xD0 + (tick & 0x0F);
+ p->efx = 0x0E;
+ p->efxData = 0xD0 + (tick & 0x0F);
}
}
@@ -486,51 +480,55 @@
if (c < 0)
return;
- editor.keyOnTab[c] = 0;
- editor.keyOffTime[c] = ++editor.keyOffNr;
+ editor.keyOffNr++;
- if (pattpos >= oldpattpos) // non-FT2 fix: only do this if we didn't quantize to next row
+ editor.keyOnTab[c] = 0;
+ editor.keyOffTime[c] = editor.keyOffNr;
+
+ if (row >= oldRow) // non-FT2 fix: only do this if we didn't quantize to next row
{
#ifdef HAS_MIDI
- playTone(c, editor.curInstr, 97, vol, midi.currMIDIVibDepth, midi.currMIDIPitch);
+ playTone(c, editor.curInstr, NOTE_OFF, vol, midi.currMIDIVibDepth, midi.currMIDIPitch);
#else
- playTone(c, editor.curInstr, 97, vol, 0, 0);
+ playTone(c, editor.curInstr, NOTE_OFF, vol, 0, 0);
#endif
}
if (config.recRelease && recmode)
{
- if (allocatePattern(nr))
+ if (allocatePattern(pattNum))
{
// insert data
- int16_t pattLen = pattLens[nr];
- noteData = &patt[nr][(pattpos * MAX_VOICES) + c];
+ int16_t numRows = patternNumRows[pattNum];
+ p = &pattern[pattNum][(row * MAX_CHANNELS) + c];
- if (noteData->ton != 0)
- pattpos++;
+ if (p->note != 0)
+ row++;
- if (pattpos >= pattLen)
+ if (row >= numRows)
{
+ row = 0;
+
if (songPlaying)
- sp++;
+ {
+ songPos++;
+ if (songPos >= song.songLength)
+ songPos = song.songLoopStart;
- if (sp >= song.len)
- sp = song.repS;
-
- nr = song.songTab[sp];
- pattpos = 0;
- pattLen = pattLens[nr];
+ pattNum = song.orders[songPos];
+ numRows = patternNumRows[pattNum];
+ }
}
- noteData = &patt[nr][(pattpos * MAX_VOICES) + c];
- noteData->ton = 97;
+ p = &pattern[pattNum][(row * MAX_CHANNELS) + c];
+ p->note = NOTE_OFF;
if (!recmode)
{
// increase row (only in edit mode)
- if (pattLen >= 1)
- setPos(-1, (editor.pattPos + editor.ID_Add) % pattLen, true);
+ if (numRows >= 1)
+ setPos(-1, (editor.row + editor.editRowSkip) % numRows, true);
}
else
{
@@ -537,8 +535,8 @@
// apply tick delay for note if quantization is disabled
if (!config.recQuant && tick > 0)
{
- noteData->effTyp = 0x0E;
- noteData->eff = 0xD0 + (tick & 0x0F);
+ p->efx = 0x0E;
+ p->efxData = 0xD0 + (tick & 0x0F);
}
}
@@ -557,28 +555,28 @@
if (playMode != PLAYMODE_EDIT && playMode != PLAYMODE_RECSONG && playMode != PLAYMODE_RECPATT)
return false; // we're not editing, test other keys
- if (patt[editor.editPattern] == NULL)
+ if (pattern[editor.editPattern] == NULL)
return true;
- tonTyp *note = &patt[editor.editPattern][(editor.pattPos * MAX_VOICES) + cursor.ch];
+ note_t *p = &pattern[editor.editPattern][(editor.row * MAX_CHANNELS) + cursor.ch];
if (keyb.leftShiftPressed)
{
// delete all
- memset(note, 0, sizeof (tonTyp));
+ p->note = p->instr = p->vol = p->efx = p->efxData = 0;
}
else if (keyb.leftCtrlPressed)
{
// delete volume column + effect
- note->vol = 0;
- note->effTyp = 0;
- note->eff = 0;
+ p->vol = 0;
+ p->efx = 0;
+ p->efxData = 0;
}
else if (keyb.leftAltPressed)
{
// delete effect
- note->effTyp = 0;
- note->eff = 0;
+ p->efx = 0;
+ p->efxData = 0;
}
else
{
@@ -585,13 +583,13 @@
if (cursor.object == CURSOR_VOL1 || cursor.object == CURSOR_VOL2)
{
// delete volume column
- note->vol = 0;
+ p->vol = 0;
}
else
{
// delete note + instrument
- note->ton = 0;
- note->instr = 0;
+ p->note = 0;
+ p->instr = 0;
}
}
@@ -598,9 +596,9 @@
killPatternIfUnused(editor.editPattern);
// increase row (only in edit mode)
- const int16_t pattLen = pattLens[editor.editPattern];
- if (playMode == PLAYMODE_EDIT && pattLen >= 1)
- setPos(-1, (editor.pattPos + editor.ID_Add) % pattLen, true);
+ const int16_t numRows = patternNumRows[editor.editPattern];
+ if (playMode == PLAYMODE_EDIT && numRows >= 1)
+ setPos(-1, (editor.row + editor.editRowSkip) % numRows, true);
ui.updatePatternEditor = true;
setSongModifiedFlag();
@@ -621,19 +619,19 @@
void writeToMacroSlot(uint8_t slot)
{
uint16_t writeVol = 0;
- uint16_t writeEff = 0;
+ uint16_t writeEfx = 0;
- if (patt[editor.editPattern] != NULL)
+ if (pattern[editor.editPattern] != NULL)
{
- tonTyp *note = &patt[editor.editPattern][(editor.pattPos * MAX_VOICES) + cursor.ch];
- writeVol = note->vol;
- writeEff = (note->effTyp << 8) | note->eff;
+ note_t *p = &pattern[editor.editPattern][(editor.row * MAX_CHANNELS) + cursor.ch];
+ writeVol = p->vol;
+ writeEfx = (p->efx << 8) | p->efxData;
}
if (cursor.object == CURSOR_VOL1 || cursor.object == CURSOR_VOL2)
config.volMacro[slot] = writeVol;
else
- config.comMacro[slot] = writeEff;
+ config.comMacro[slot] = writeEfx;
}
void writeFromMacroSlot(uint8_t slot)
@@ -643,32 +641,31 @@
if (!allocatePattern(editor.editPattern))
return;
-
- const int16_t pattLen = pattLens[editor.editPattern];
- tonTyp *note = &patt[editor.editPattern][(editor.pattPos * MAX_VOICES) + cursor.ch];
-
+
+ note_t *p = &pattern[editor.editPattern][(editor.row * MAX_CHANNELS) + cursor.ch];
if (cursor.object == CURSOR_VOL1 || cursor.object == CURSOR_VOL2)
{
- note->vol = (uint8_t)config.volMacro[slot];
+ p->vol = (uint8_t)config.volMacro[slot];
}
else
{
- uint8_t effTyp = (uint8_t)(config.comMacro[slot] >> 8);
- if (effTyp > 35)
+ uint8_t efx = (uint8_t)(config.comMacro[slot] >> 8);
+ if (efx > 35)
{
// illegal effect
- note->effTyp = 0;
- note->eff = 0;
+ p->efx = 0;
+ p->efxData = 0;
}
else
{
- note->effTyp = effTyp;
- note->eff = config.comMacro[slot] & 0xFF;
+ p->efx = efx;
+ p->efxData = config.comMacro[slot] & 0xFF;
}
}
- if (playMode == PLAYMODE_EDIT && pattLen >= 1)
- setPos(-1, (editor.pattPos + editor.ID_Add) % pattLen, true);
+ const int16_t numRows = patternNumRows[editor.editPattern];
+ if (playMode == PLAYMODE_EDIT && numRows >= 1)
+ setPos(-1, (editor.row + editor.editRowSkip) % numRows, true);
killPatternIfUnused(editor.editPattern);
@@ -681,24 +678,22 @@
if (playMode != PLAYMODE_EDIT && playMode != PLAYMODE_RECPATT && playMode != PLAYMODE_RECSONG)
return;
- const int16_t nr = editor.editPattern;
-
- tonTyp *pattPtr = patt[nr];
- if (pattPtr == NULL)
+ note_t *p = pattern[editor.editPattern];
+ if (p == NULL)
return;
- const int16_t pattPos = editor.pattPos;
- const int16_t pattLen = pattLens[nr];
+ const int16_t row = editor.row;
+ const int16_t numRows = patternNumRows[editor.editPattern];
- if (pattLen > 1)
+ if (numRows > 1)
{
- for (int32_t i = pattLen-2; i >= pattPos; i--)
- pattPtr[((i + 1) * MAX_VOICES) + cursor.ch] = pattPtr[(i * MAX_VOICES) + cursor.ch];
+ for (int32_t i = numRows-2; i >= row; i--)
+ p[((i+1) * MAX_CHANNELS) + cursor.ch] = p[(i * MAX_CHANNELS) + cursor.ch];
}
- memset(&pattPtr[(pattPos * MAX_VOICES) + cursor.ch], 0, sizeof (tonTyp));
+ memset(&p[(row * MAX_CHANNELS) + cursor.ch], 0, sizeof (note_t));
- killPatternIfUnused(nr);
+ killPatternIfUnused(editor.editPattern);
ui.updatePatternEditor = true;
setSongModifiedFlag();
@@ -709,28 +704,26 @@
if (playMode != PLAYMODE_EDIT && playMode != PLAYMODE_RECPATT && playMode != PLAYMODE_RECSONG)
return;
- const int16_t nr = editor.editPattern;
+ setPatternLen(editor.editPattern, patternNumRows[editor.editPattern] + config.recTrueInsert); // config.recTrueInsert is 0 or 1
- setPatternLen(nr, pattLens[nr] + config.recTrueInsert); // config.recTrueInsert is 0 or 1
-
- tonTyp *pattPtr = patt[nr];
- if (pattPtr != NULL)
+ note_t *p = pattern[editor.editPattern];
+ if (p != NULL)
{
- const int16_t pattPos = editor.pattPos;
- const int16_t pattLen = pattLens[nr];
+ const int16_t row = editor.row;
+ const int16_t numRows = patternNumRows[editor.editPattern];
- if (pattLen > 1)
+ if (numRows > 1)
{
- for (int32_t i = pattLen-2; i >= pattPos; i--)
+ for (int32_t i = numRows-2; i >= row; i--)
{
- for (int32_t j = 0; j < MAX_VOICES; j++)
- pattPtr[((i + 1) * MAX_VOICES) + j] = pattPtr[(i * MAX_VOICES) + j];
+ for (int32_t j = 0; j < MAX_CHANNELS; j++)
+ p[((i+1) * MAX_CHANNELS) + j] = p[(i * MAX_CHANNELS) + j];
}
}
- memset(&pattPtr[pattPos * MAX_VOICES], 0, TRACK_WIDTH);
+ memset(&p[row * MAX_CHANNELS], 0, TRACK_WIDTH);
- killPatternIfUnused(nr);
+ killPatternIfUnused(editor.editPattern);
}
ui.updatePatternEditor = true;
@@ -742,34 +735,33 @@
if (playMode != PLAYMODE_EDIT && playMode != PLAYMODE_RECPATT && playMode != PLAYMODE_RECSONG)
return;
- const int16_t nr = editor.editPattern;
- int16_t pattPos = editor.pattPos;
- const int16_t pattLen = pattLens[nr];
+ int16_t row = editor.row;
+ const int16_t numRows = patternNumRows[editor.editPattern];
- tonTyp *pattPtr = patt[editor.editPattern];
- if (pattPtr != NULL)
+ note_t *p = pattern[editor.editPattern];
+ if (p != NULL)
{
- if (pattPos > 0)
+ if (row > 0)
{
- pattPos--;
- editor.pattPos = song.pattPos = pattPos;
+ row--;
+ editor.row = song.row = row;
- for (int32_t i = pattPos; i < pattLen-1; i++)
- pattPtr[(i * MAX_VOICES) + cursor.ch] = pattPtr[((i + 1) * MAX_VOICES) + cursor.ch];
+ for (int32_t i = row; i < numRows-1; i++)
+ p[(i * MAX_CHANNELS) + cursor.ch] = p[((i+1) * MAX_CHANNELS) + cursor.ch];
- memset(&pattPtr[((pattLen - 1) * MAX_VOICES) + cursor.ch], 0, sizeof (tonTyp));
+ memset(&p[((numRows-1) * MAX_CHANNELS) + cursor.ch], 0, sizeof (note_t));
}
}
else
{
- if (pattPos > 0)
+ if (row > 0)
{
- pattPos--;
- editor.pattPos = song.pattPos = pattPos;
+ row--;
+ editor.row = song.row = row;
}
}
- killPatternIfUnused(nr);
+ killPatternIfUnused(editor.editPattern);
ui.updatePatternEditor = true;
setSongModifiedFlag();
@@ -780,40 +772,39 @@
if (playMode != PLAYMODE_EDIT && playMode != PLAYMODE_RECPATT && playMode != PLAYMODE_RECSONG)
return;
- const int16_t nr = editor.editPattern;
- int16_t pattPos = editor.pattPos;
- const int16_t pattLen = pattLens[nr];
+ int16_t row = editor.row;
+ const int16_t numRows = patternNumRows[editor.editPattern];
- tonTyp *pattPtr = patt[editor.editPattern];
- if (pattPtr != NULL)
+ note_t *p = pattern[editor.editPattern];
+ if (p != NULL)
{
- if (pattPos > 0)
+ if (row > 0)
{
- pattPos--;
- editor.pattPos = song.pattPos = pattPos;
+ row--;
+ editor.row = song.row = row;
- for (int32_t i = pattPos; i < pattLen-1; i++)
+ for (int32_t i = row; i < numRows-1; i++)
{
- for (int32_t j = 0; j < MAX_VOICES; j++)
- pattPtr[(i * MAX_VOICES) + j] = pattPtr[((i + 1) * MAX_VOICES) + j];
+ for (int32_t j = 0; j < MAX_CHANNELS; j++)
+ p[(i * MAX_CHANNELS) + j] = p[((i+1) * MAX_CHANNELS) + j];
}
- memset(&pattPtr[(pattLen - 1) * MAX_VOICES], 0, TRACK_WIDTH);
+ memset(&p[(numRows-1) * MAX_CHANNELS], 0, TRACK_WIDTH);
}
}
else
{
- if (pattPos > 0)
+ if (row > 0)
{
- pattPos--;
- editor.pattPos = song.pattPos = pattPos;
+ row--;
+ editor.row = song.row = row;
}
}
- if (config.recTrueInsert && pattLen > 1)
- setPatternLen(nr, pattLen - 1);
+ if (config.recTrueInsert && numRows > 1)
+ setPatternLen(editor.editPattern, numRows-1);
- killPatternIfUnused(nr);
+ killPatternIfUnused(editor.editPattern);
ui.updatePatternEditor = true;
setSongModifiedFlag();
@@ -823,32 +814,25 @@
static void countOverflowingNotes(uint8_t currInsOnly, uint8_t transpMode, int8_t addVal)
{
- uint8_t ton;
- uint16_t p, pattLen, ch, row;
- tonTyp *pattPtr;
-
transpDelNotes = 0;
switch (transpMode)
{
case TRANSP_TRACK:
{
- pattPtr = patt[editor.editPattern];
- if (pattPtr == NULL)
+ note_t *p = pattern[editor.editPattern];
+ if (p == NULL)
return; // empty pattern
- pattPtr += cursor.ch;
+ p += cursor.ch;
- pattLen = pattLens[editor.editPattern];
- for (row = 0; row < pattLen; row++)
+ const int32_t numRows = patternNumRows[editor.editPattern];
+ for (int32_t row = 0; row < numRows; row++, p += MAX_CHANNELS)
{
- ton = pattPtr->ton;
- if ((ton >= 1 && ton <= 96) && (!currInsOnly || pattPtr->instr == editor.curInstr))
+ if ((p->note >= 1 && p->note <= 96) && (!currInsOnly || p->instr == editor.curInstr))
{
- if ((int8_t)ton+addVal > 96 || (int8_t)ton+addVal <= 0)
+ if ((int8_t)p->note+addVal > 96 || (int8_t)p->note+addVal <= 0)
transpDelNotes++;
}
-
- pattPtr += MAX_VOICES;
}
}
break;
@@ -855,26 +839,23 @@
case TRANSP_PATT:
{
- pattPtr = patt[editor.editPattern];
- if (pattPtr == NULL)
+ note_t *p = pattern[editor.editPattern];
+ if (p == NULL)
return; // empty pattern
- pattLen = pattLens[editor.editPattern];
- for (row = 0; row < pattLen; row++)
+ const int32_t numRows = patternNumRows[editor.editPattern];
+ const int32_t pitch = MAX_CHANNELS-song.numChannels;
+
+ for (int32_t row = 0; row < numRows; row++, p += pitch)
{
- for (ch = 0; ch < song.antChn; ch++)
+ for (int32_t ch = 0; ch < song.numChannels; ch++, p++)
{
- ton = pattPtr->ton;
- if ((ton >= 1 && ton <= 96) && (!currInsOnly || pattPtr->instr == editor.curInstr))
+ if ((p->note >= 1 && p->note <= 96) && (!currInsOnly || p->instr == editor.curInstr))
{
- if ((int8_t)ton+addVal > 96 || (int8_t)ton+addVal <= 0)
+ if ((int8_t)p->note+addVal > 96 || (int8_t)p->note+addVal <= 0)
transpDelNotes++;
}
-
- pattPtr++;
}
-
- pattPtr += MAX_VOICES - song.antChn;
}
}
break;
@@ -881,28 +862,24 @@
case TRANSP_SONG:
{
- for (p = 0; p < MAX_PATTERNS; p++)
+ const int32_t pitch = MAX_CHANNELS-song.numChannels;
+ for (int32_t i = 0; i < MAX_PATTERNS; i++)
{
- pattPtr = patt[p];
- if (pattPtr == NULL)
+ note_t *p = pattern[i];
+ if (p == NULL)
continue; // empty pattern
- pattLen = pattLens[p];
- for (row = 0; row < pattLen; row++)
+ const int32_t numRows = patternNumRows[i];
+ for (int32_t row = 0; row < numRows; row++, p += pitch)
{
- for (ch = 0; ch < song.antChn; ch++)
+ for (int32_t ch = 0; ch < song.numChannels; ch++, p++)
{
- ton = pattPtr->ton;
- if ((ton >= 1 && ton <= 96) && (!currInsOnly || pattPtr->instr == editor.curInstr))
+ if ((p->note >= 1 && p->note <= 96) && (!currInsOnly || p->instr == editor.curInstr))
{
- if ((int8_t)ton+addVal > 96 || (int8_t)ton+addVal <= 0)
+ if ((int8_t)p->note+addVal > 96 || (int8_t)p->note+addVal <= 0)
transpDelNotes++;
}
-
- pattPtr++;
}
-
- pattPtr += MAX_VOICES - song.antChn;
}
}
}
@@ -913,28 +890,23 @@
if (pattMark.markY1 == pattMark.markY2)
return; // no pattern marking
- pattPtr = patt[editor.editPattern];
- if (pattPtr == NULL)
+ note_t *p = pattern[editor.editPattern];
+ if (p == NULL)
return; // empty pattern
- pattPtr += (pattMark.markY1 * MAX_VOICES) + pattMark.markX1;
+ p += (pattMark.markY1 * MAX_CHANNELS) + pattMark.markX1;
- pattLen = pattLens[editor.editPattern];
- for (row = pattMark.markY1; row < pattMark.markY2; row++)
+ const int32_t pitch = MAX_CHANNELS - ((pattMark.markX2 + 1) - pattMark.markX1);
+ for (int32_t row = pattMark.markY1; row < pattMark.markY2; row++, p += pitch)
{
- for (ch = pattMark.markX1; ch <= pattMark.markX2; ch++)
+ for (int32_t ch = pattMark.markX1; ch <= pattMark.markX2; ch++, p++)
{
- ton = pattPtr->ton;
- if ((ton >= 1 && ton <= 96) && (!currInsOnly || pattPtr->instr == editor.curInstr))
+ if ((p->note >= 1 && p->note <= 96) && (!currInsOnly || p->instr == editor.curInstr))
{
- if ((int8_t)ton+addVal > 96 || (int8_t)ton+addVal <= 0)
+ if ((int8_t)p->note+addVal > 96 || (int8_t)p->note+addVal <= 0)
transpDelNotes++;
}
-
- pattPtr++;
}
-
- pattPtr += MAX_VOICES - ((pattMark.markX2 + 1) - pattMark.markX1);
}
}
break;
@@ -946,9 +918,6 @@
void doTranspose(void)
{
char text[48];
- uint8_t ton;
- uint16_t p, pattLen, ch, row;
- tonTyp *pattPtr;
countOverflowingNotes(lastInsMode, lastTranspMode, lastTranspVal);
if (transpDelNotes > 0)
@@ -963,26 +932,24 @@
{
case TRANSP_TRACK:
{
- pattPtr = patt[editor.editPattern];
- if (pattPtr == NULL)
+ note_t *p = pattern[editor.editPattern];
+ if (p == NULL)
return; // empty pattern
- pattPtr += cursor.ch;
+ p += cursor.ch;
- pattLen = pattLens[editor.editPattern];
- for (row = 0; row < pattLen; row++)
+ const int32_t numRows = patternNumRows[editor.editPattern];
+ for (int32_t row = 0; row < numRows; row++, p += MAX_CHANNELS)
{
- ton = pattPtr->ton;
- if ((ton >= 1 && ton <= 96) && (!lastInsMode || pattPtr->instr == editor.curInstr))
+ uint8_t note = p->note;
+ if ((note >= 1 && note <= 96) && (!lastInsMode || p->instr == editor.curInstr))
{
- ton += lastTranspVal;
- if (ton > 96)
- ton = 0; // also handles underflow
+ note += lastTranspVal;
+ if (note > 96)
+ note = 0; // also handles underflow
- pattPtr->ton = ton;
+ p->note = note;
}
-
- pattPtr += MAX_VOICES;
}
}
break;
@@ -989,29 +956,27 @@
case TRANSP_PATT:
{
- pattPtr = patt[editor.editPattern];
- if (pattPtr == NULL)
+ note_t *p = pattern[editor.editPattern];
+ if (p == NULL)
return; // empty pattern
- pattLen = pattLens[editor.editPattern];
- for (row = 0; row < pattLen; row++)
+ const int32_t numRows = patternNumRows[editor.editPattern];
+ const int32_t pitch = MAX_CHANNELS - song.numChannels;
+
+ for (int32_t row = 0; row < numRows; row++, p += pitch)
{
- for (ch = 0; ch < song.antChn; ch++)
+ for (int32_t ch = 0; ch < song.numChannels; ch++, p++)
{
- ton = pattPtr->ton;
- if ((ton >= 1 && ton <= 96) && (!lastInsMode || pattPtr->instr == editor.curInstr))
+ uint8_t note = p->note;
+ if ((note >= 1 && note <= 96) && (!lastInsMode || p->instr == editor.curInstr))
{
- ton += lastTranspVal;
- if (ton > 96)
- ton = 0; // also handles underflow
+ note += lastTranspVal;
+ if (note > 96)
+ note = 0; // also handles underflow
- pattPtr->ton = ton;
+ p->note = note;
}
-
- pattPtr++;
}
-
- pattPtr += MAX_VOICES - song.antChn;
}
}
break;
@@ -1018,31 +983,28 @@
case TRANSP_SONG:
{
- for (p = 0; p < MAX_PATTERNS; p++)
+ const int32_t pitch = MAX_CHANNELS - song.numChannels;
+ for (int32_t i = 0; i < MAX_PATTERNS; i++)
{
- pattPtr = patt[p];
- if (pattPtr == NULL)
+ note_t *p = pattern[i];
+ if (p == NULL)
continue; // empty pattern
- pattLen = pattLens[p];
- for (row = 0; row < pattLen; row++)
+ const int32_t numRows = patternNumRows[i];
+ for (int32_t row = 0; row < numRows; row++, p += pitch)
{
- for (ch = 0; ch < song.antChn; ch++)
+ for (int32_t ch = 0; ch < song.numChannels; ch++, p++)
{
- ton = pattPtr->ton;
- if ((ton >= 1 && ton <= 96) && (!lastInsMode || pattPtr->instr == editor.curInstr))
+ uint8_t note = p->note;
+ if ((note >= 1 && note <= 96) && (!lastInsMode || p->instr == editor.curInstr))
{
- ton += lastTranspVal;
- if (ton > 96)
- ton = 0; // also handles underflow
+ note += lastTranspVal;
+ if (note > 96)
+ note = 0; // also handles underflow
- pattPtr->ton = ton;
+ p->note = note;
}
-
- pattPtr++;
}
-
- pattPtr += MAX_VOICES - song.antChn;
}
}
}
@@ -1053,31 +1015,27 @@
if (pattMark.markY1 == pattMark.markY2)
return; // no pattern marking
- pattPtr = patt[editor.editPattern];
- if (pattPtr == NULL)
+ note_t *p = pattern[editor.editPattern];
+ if (p == NULL)
return; // empty pattern
- pattPtr += (pattMark.markY1 * MAX_VOICES) + pattMark.markX1;
+ p += (pattMark.markY1 * MAX_CHANNELS) + pattMark.markX1;
- pattLen = pattLens[editor.editPattern];
- for (row = pattMark.markY1; row < pattMark.markY2; row++)
+ const int32_t pitch = MAX_CHANNELS - ((pattMark.markX2 + 1) - pattMark.markX1);
+ for (int32_t row = pattMark.markY1; row < pattMark.markY2; row++, p += pitch)
{
- for (ch = pattMark.markX1; ch <= pattMark.markX2; ch++)
+ for (int32_t ch = pattMark.markX1; ch <= pattMark.markX2; ch++, p++)
{
- ton = pattPtr->ton;
- if ((ton >= 1 && ton <= 96) && (!lastInsMode || pattPtr->instr == editor.curInstr))
+ uint8_t note = p->note;
+ if ((note >= 1 && note <= 96) && (!lastInsMode || p->instr == editor.curInstr))
{
- ton += lastTranspVal;
- if (ton > 96)
- ton = 0; // also handles underflow
+ note += lastTranspVal;
+ if (note > 96)
+ note = 0; // also handles underflow
- pattPtr->ton = ton;
+ p->note = note;
}
-
- pattPtr++;
}
-
- pattPtr += MAX_VOICES - ((pattMark.markX2 + 1) - pattMark.markX1);
}
}
break;
@@ -1345,15 +1303,15 @@
doTranspose();
}
-void copyNote(tonTyp *src, tonTyp *dst)
+void copyNote(note_t *src, note_t *dst)
{
if (editor.copyMaskEnable)
{
- if (editor.copyMask[0]) dst->ton = src->ton;
+ if (editor.copyMask[0]) dst->note = src->note;
if (editor.copyMask[1]) dst->instr = src->instr;
if (editor.copyMask[2]) dst->vol = src->vol;
- if (editor.copyMask[3]) dst->effTyp = src->effTyp;
- if (editor.copyMask[4]) dst->eff = src->eff;
+ if (editor.copyMask[3]) dst->efx = src->efx;
+ if (editor.copyMask[4]) dst->efxData = src->efxData;
}
else
{
@@ -1361,15 +1319,15 @@
}
}
-void pasteNote(tonTyp *src, tonTyp *dst)
+void pasteNote(note_t *src, note_t *dst)
{
if (editor.copyMaskEnable)
{
- if (editor.copyMask[0] && (src->ton != 0 || !editor.transpMask[0])) dst->ton = src->ton;
- if (editor.copyMask[1] && (src->instr != 0 || !editor.transpMask[1])) dst->instr = src->instr;
- if (editor.copyMask[2] && (src->vol != 0 || !editor.transpMask[2])) dst->vol = src->vol;
- if (editor.copyMask[3] && (src->effTyp != 0 || !editor.transpMask[3])) dst->effTyp = src->effTyp;
- if (editor.copyMask[4] && (src->eff != 0 || !editor.transpMask[4])) dst->eff = src->eff;
+ if (editor.copyMask[0] && (src->note != 0 || !editor.transpMask[0])) dst->note = src->note;
+ if (editor.copyMask[1] && (src->instr != 0 || !editor.transpMask[1])) dst->instr = src->instr;
+ if (editor.copyMask[2] && (src->vol != 0 || !editor.transpMask[2])) dst->vol = src->vol;
+ if (editor.copyMask[3] && (src->efx != 0 || !editor.transpMask[3])) dst->efx = src->efx;
+ if (editor.copyMask[4] && (src->efxData != 0 || !editor.transpMask[4])) dst->efxData = src->efxData;
}
else
{
@@ -1379,24 +1337,24 @@
void cutTrack(void)
{
- tonTyp *pattPtr = patt[editor.editPattern];
- if (pattPtr == NULL)
+ note_t *p = pattern[editor.editPattern];
+ if (p == NULL)
return;
- const int16_t pattLen = pattLens[editor.editPattern];
+ const int16_t numRows = patternNumRows[editor.editPattern];
if (config.ptnCutToBuffer)
{
- memset(trackCopyBuff, 0, MAX_PATT_LEN * sizeof (tonTyp));
- for (int16_t i = 0; i < pattLen; i++)
- copyNote(&pattPtr[(i * MAX_VOICES) + cursor.ch], &trackCopyBuff[i]);
+ memset(trackCopyBuff, 0, MAX_PATT_LEN * sizeof (note_t));
+ for (int16_t i = 0; i < numRows; i++)
+ copyNote(&p[(i * MAX_CHANNELS) + cursor.ch], &trackCopyBuff[i]);
- trkBufLen = pattLen;
+ trkBufLen = numRows;
}
pauseMusic();
- for (int16_t i = 0; i < pattLen; i++)
- pasteNote(&clearNote, &pattPtr[(i * MAX_VOICES) + cursor.ch]);
+ for (int16_t i = 0; i < numRows; i++)
+ pasteNote(&clearNote, &p[(i * MAX_CHANNELS) + cursor.ch]);
resumeMusic();
killPatternIfUnused(editor.editPattern);
@@ -1407,17 +1365,17 @@
void copyTrack(void)
{
- tonTyp *pattPtr = patt[editor.editPattern];
- if (pattPtr == NULL)
+ note_t *p = pattern[editor.editPattern];
+ if (p == NULL)
return;
- const int16_t pattLen = pattLens[editor.editPattern];
+ const int16_t numRows = patternNumRows[editor.editPattern];
- memset(trackCopyBuff, 0, MAX_PATT_LEN * sizeof (tonTyp));
- for (int16_t i = 0; i < pattLen; i++)
- copyNote(&pattPtr[(i * MAX_VOICES) + cursor.ch], &trackCopyBuff[i]);
+ memset(trackCopyBuff, 0, MAX_PATT_LEN * sizeof (note_t));
+ for (int16_t i = 0; i < numRows; i++)
+ copyNote(&p[(i * MAX_CHANNELS) + cursor.ch], &trackCopyBuff[i]);
- trkBufLen = pattLen;
+ trkBufLen = numRows;
}
void pasteTrack(void)
@@ -1425,12 +1383,12 @@
if (trkBufLen == 0 || !allocatePattern(editor.editPattern))
return;
- tonTyp *pattPtr = patt[editor.editPattern];
- const int16_t pattLen = pattLens[editor.editPattern];
+ note_t *p = pattern[editor.editPattern];
+ const int16_t numRows = patternNumRows[editor.editPattern];
pauseMusic();
- for (int16_t i = 0; i < pattLen; i++)
- pasteNote(&trackCopyBuff[i], &pattPtr[(i * MAX_VOICES) + cursor.ch]);
+ for (int16_t i = 0; i < numRows; i++)
+ pasteNote(&trackCopyBuff[i], &p[(i * MAX_CHANNELS) + cursor.ch]);
resumeMusic();
killPatternIfUnused(editor.editPattern);
@@ -1441,29 +1399,29 @@
void cutPattern(void)
{
- tonTyp *pattPtr = patt[editor.editPattern];
- if (pattPtr == NULL)
+ note_t *p = pattern[editor.editPattern];
+ if (p == NULL)
return;
- const int16_t pattLen = pattLens[editor.editPattern];
+ const int16_t numRows = patternNumRows[editor.editPattern];
if (config.ptnCutToBuffer)
{
- memset(ptnCopyBuff, 0, (MAX_PATT_LEN * MAX_VOICES) * sizeof (tonTyp));
- for (int16_t x = 0; x < song.antChn; x++)
+ memset(ptnCopyBuff, 0, (MAX_PATT_LEN * MAX_CHANNELS) * sizeof (note_t));
+ for (int16_t x = 0; x < song.numChannels; x++)
{
- for (int16_t i = 0; i < pattLen; i++)
- copyNote(&pattPtr[(i * MAX_VOICES) + x], &ptnCopyBuff[(i * MAX_VOICES) + x]);
+ for (int16_t i = 0; i < numRows; i++)
+ copyNote(&p[(i * MAX_CHANNELS) + x], &ptnCopyBuff[(i * MAX_CHANNELS) + x]);
}
- ptnBufLen = pattLen;
+ ptnBufLen = numRows;
}
pauseMusic();
- for (int16_t x = 0; x < song.antChn; x++)
+ for (int16_t x = 0; x < song.numChannels; x++)
{
- for (int16_t i = 0; i < pattLen; i++)
- pasteNote(&clearNote, &pattPtr[(i * MAX_VOICES) + x]);
+ for (int16_t i = 0; i < numRows; i++)
+ pasteNote(&clearNote, &p[(i * MAX_CHANNELS) + x]);
}
resumeMusic();
@@ -1475,20 +1433,20 @@
void copyPattern(void)
{
- tonTyp *pattPtr = patt[editor.editPattern];
- if (pattPtr == NULL)
+ note_t *p = pattern[editor.editPattern];
+ if (p == NULL)
return;
- const int16_t pattLen = pattLens[editor.editPattern];
+ const int16_t numRows = patternNumRows[editor.editPattern];
- memset(ptnCopyBuff, 0, (MAX_PATT_LEN * MAX_VOICES) * sizeof (tonTyp));
- for (int16_t x = 0; x < song.antChn; x++)
+ memset(ptnCopyBuff, 0, (MAX_PATT_LEN * MAX_CHANNELS) * sizeof (note_t));
+ for (int16_t x = 0; x < song.numChannels; x++)
{
- for (int16_t i = 0; i < pattLen; i++)
- copyNote(&pattPtr[(i * MAX_VOICES) + x], &ptnCopyBuff[(i * MAX_VOICES) + x]);
+ for (int16_t i = 0; i < numRows; i++)
+ copyNote(&p[(i * MAX_CHANNELS) + x], &ptnCopyBuff[(i * MAX_CHANNELS) + x]);
}
- ptnBufLen = pattLen;
+ ptnBufLen = numRows;
ui.updatePatternEditor = true;
}
@@ -1498,7 +1456,7 @@
if (ptnBufLen == 0)
return;
- if (pattLens[editor.editPattern] != ptnBufLen)
+ if (patternNumRows[editor.editPattern] != ptnBufLen)
{
if (okBox(1, "System request", "Change pattern length to copybuffer's length?") == 1)
setPatternLen(editor.editPattern, ptnBufLen);
@@ -1507,14 +1465,14 @@
if (!allocatePattern(editor.editPattern))
return;
- tonTyp *pattPtr = patt[editor.editPattern];
- const int16_t pattLen = pattLens[editor.editPattern];
+ note_t *p = pattern[editor.editPattern];
+ const int16_t numRows = patternNumRows[editor.editPattern];
pauseMusic();
- for (int16_t x = 0; x < song.antChn; x++)
+ for (int16_t x = 0; x < song.numChannels; x++)
{
- for (int16_t i = 0; i < pattLen; i++)
- pasteNote(&ptnCopyBuff[(i * MAX_VOICES) + x], &pattPtr[(i * MAX_VOICES) + x]);
+ for (int16_t i = 0; i < numRows; i++)
+ pasteNote(&ptnCopyBuff[(i * MAX_CHANNELS) + x], &p[(i * MAX_CHANNELS) + x]);
}
resumeMusic();
@@ -1529,8 +1487,8 @@
if (pattMark.markY1 == pattMark.markY2 || pattMark.markY1 > pattMark.markY2)
return;
- tonTyp *pattPtr = patt[editor.editPattern];
- if (pattPtr == NULL)
+ note_t *p = pattern[editor.editPattern];
+ if (p == NULL)
return;
if (config.ptnCutToBuffer)
@@ -1539,9 +1497,8 @@
{
for (int16_t y = pattMark.markY1; y < pattMark.markY2; y++)
{
- assert(x < song.antChn && y < pattLens[editor.editPattern]);
- copyNote(&pattPtr[(y * MAX_VOICES) + x],
- &blkCopyBuff[((y - pattMark.markY1) * MAX_VOICES) + (x - pattMark.markX1)]);
+ assert(x < song.numChannels && y < patternNumRows[editor.editPattern]);
+ copyNote(&p[(y * MAX_CHANNELS) + x], &blkCopyBuff[((y - pattMark.markY1) * MAX_CHANNELS) + (x - pattMark.markX1)]);
}
}
}
@@ -1550,7 +1507,7 @@
for (int16_t x = pattMark.markX1; x <= pattMark.markX2; x++)
{
for (int16_t y = pattMark.markY1; y < pattMark.markY2; y++)
- pasteNote(&clearNote, &pattPtr[(y * MAX_VOICES) + x]);
+ pasteNote(&clearNote, &p[(y * MAX_CHANNELS) + x]);
}
resumeMusic();
@@ -1569,8 +1526,8 @@
if (pattMark.markY1 == pattMark.markY2 || pattMark.markY1 > pattMark.markY2)
return;
- tonTyp *pattPtr = patt[editor.editPattern];
- if (pattPtr == NULL)
+ note_t *p = pattern[editor.editPattern];
+ if (p == NULL)
return;
for (int16_t x = pattMark.markX1; x <= pattMark.markX2; x++)
@@ -1577,9 +1534,8 @@
{
for (int16_t y = pattMark.markY1; y < pattMark.markY2; y++)
{
- assert(x < song.antChn && y < pattLens[editor.editPattern]);
- copyNote(&pattPtr[(y * MAX_VOICES) + x],
- &blkCopyBuff[((y - pattMark.markY1) * MAX_VOICES) + (x - pattMark.markX1)]);
+ assert(x < song.numChannels && y < patternNumRows[editor.editPattern]);
+ copyNote(&p[(y * MAX_CHANNELS) + x], &blkCopyBuff[((y - pattMark.markY1) * MAX_CHANNELS) + (x - pattMark.markX1)]);
}
}
@@ -1593,20 +1549,20 @@
if (!blockCopied || !allocatePattern(editor.editPattern))
return;
- const int16_t pattLen = pattLens[editor.editPattern];
+ const int16_t numRows = patternNumRows[editor.editPattern];
const int32_t xpos = cursor.ch;
- const int32_t ypos = editor.pattPos;
+ const int32_t ypos = editor.row;
int32_t j = markXSize;
- if (j+xpos >= song.antChn)
- j = song.antChn - xpos - 1;
+ if (j+xpos >= song.numChannels)
+ j = song.numChannels - xpos - 1;
int32_t k = markYSize;
- if (k+ypos >= pattLen)
- k = pattLen - ypos;
+ if (k+ypos >= numRows)
+ k = numRows-ypos;
- tonTyp *pattPtr = patt[editor.editPattern];
+ note_t *p = pattern[editor.editPattern];
pauseMusic();
for (int32_t x = xpos; x <= xpos+j; x++)
@@ -1613,8 +1569,8 @@
{
for (int32_t y = ypos; y < ypos+k; y++)
{
- assert(x < song.antChn && y < pattLen);
- pasteNote(&blkCopyBuff[((y - ypos) * MAX_VOICES) + (x - xpos)], &pattPtr[(y * MAX_VOICES) + x]);
+ assert(x < song.numChannels && y < numRows);
+ pasteNote(&blkCopyBuff[((y - ypos) * MAX_CHANNELS) + (x - xpos)], &p[(y * MAX_CHANNELS) + x]);
}
}
resumeMusic();
@@ -1625,29 +1581,24 @@
setSongModifiedFlag();
}
-static void remapInstrXY(uint16_t nr, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint8_t src, uint8_t dst)
+static void remapInstrXY(uint16_t pattNum, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint8_t src, uint8_t dst)
{
// this routine is only used sanely, so no need to check input
- tonTyp *pattPtr = patt[nr];
+ note_t *pattPtr = pattern[pattNum];
if (pattPtr == NULL)
return;
- const int32_t noteSkipLen = MAX_VOICES - ((x2 + 1) - x1);
- tonTyp *note = &pattPtr[(y1 * MAX_VOICES) + x1];
+ note_t *p = &pattPtr[(y1 * MAX_CHANNELS) + x1];
- for (uint16_t y = y1; y <= y2; y++)
+ const int32_t pitch = MAX_CHANNELS - ((x2 + 1) - x1);
+ for (uint16_t y = y1; y <= y2; y++, p += pitch)
{
- for (uint16_t x = x1; x <= x2; x++)
+ for (uint16_t x = x1; x <= x2; x++, p++)
{
- assert(x < song.antChn && y < pattLens[nr]);
- if (note->instr == src)
- note->instr = dst;
-
- note++;
+ if (p->instr == src)
+ p->instr = dst;
}
-
- note += noteSkipLen;
}
}
@@ -1675,7 +1626,7 @@
pauseMusic();
remapInstrXY(editor.editPattern,
cursor.ch, 0,
- cursor.ch, pattLens[editor.editPattern] - 1,
+ cursor.ch, patternNumRows[editor.editPattern] - 1,
editor.srcInstr, editor.curInstr);
resumeMusic();
@@ -1691,7 +1642,7 @@
pauseMusic();
remapInstrXY(editor.editPattern,
0, 0,
- (uint16_t)(song.antChn - 1), pattLens[editor.editPattern] - 1,
+ (uint16_t)(song.numChannels - 1), patternNumRows[editor.editPattern] - 1,
editor.srcInstr, editor.curInstr);
resumeMusic();
@@ -1707,11 +1658,11 @@
pauseMusic();
for (int32_t i = 0; i < MAX_PATTERNS; i++)
{
- const uint8_t pattNr = (uint8_t)i;
+ const uint8_t pattNum = (uint8_t)i;
- remapInstrXY(pattNr,
+ remapInstrXY(pattNum,
0, 0,
- (uint16_t)(song.antChn - 1), pattLens[pattNr] - 1,
+ (uint16_t)(song.numChannels - 1), patternNumRows[pattNum] - 1,
editor.srcInstr, editor.curInstr);
}
resumeMusic();
@@ -1722,22 +1673,22 @@
// "scale-fade volume" routines
-static int8_t getNoteVolume(tonTyp *note)
+static int8_t getNoteVolume(note_t *p)
{
int8_t nv, vv, ev;
- if (note->vol >= 0x10 && note->vol <= 0x50)
- vv = note->vol - 0x10;
+ if (p->vol >= 0x10 && p->vol <= 0x50)
+ vv = p->vol - 0x10;
else
vv = -1;
- if (note->effTyp == 0xC)
- ev = MIN(note->eff, 64);
+ if (p->efx == 0xC)
+ ev = MIN(p->efxData, 64);
else
ev = -1;
- if (note->instr != 0 && instr[note->instr] != NULL)
- nv = (int8_t)instr[note->instr]->samp[0].vol;
+ if (p->instr != 0 && instr[p->instr] != NULL)
+ nv = (int8_t)instr[p->instr]->smp[0].volume;
else
nv = -1;
@@ -1749,38 +1700,38 @@
return finalv;
}
-static void setNoteVolume(tonTyp *note, int8_t newVol)
+static void setNoteVolume(note_t *p, int8_t newVol)
{
if (newVol < 0)
return;
- const int8_t oldv = getNoteVolume(note);
- if (note->vol == oldv)
+ const int8_t oldv = getNoteVolume(p);
+ if (p->vol == oldv)
return; // volume is the same
- if (note->effTyp == 0x0C)
- note->eff = newVol; // Cxx effect
+ if (p->efx == 0x0C)
+ p->efxData = newVol; // Cxx effect
else
- note->vol = 0x10 + newVol; // volume column
+ p->vol = 0x10 + newVol; // volume column
}
-static void scaleNote(uint16_t ptn, int8_t ch, int16_t row, double dScale)
+static void scaleNote(uint16_t pattNum, int8_t ch, int16_t row, double dScale)
{
- if (patt[ptn] == NULL)
+ if (pattern[pattNum] == NULL)
return;
- const int16_t pattLen = pattLens[ptn];
- if (row < 0 || row >= pattLen || ch < 0 || ch >= song.antChn)
+ const int16_t numRows = patternNumRows[pattNum];
+ if (row < 0 || row >= numRows || ch < 0 || ch >= song.numChannels)
return;
- tonTyp *note = &patt[ptn][(row * MAX_VOICES) + ch];
+ note_t *p = &pattern[pattNum][(row * MAX_CHANNELS) + ch];
- int32_t vol = getNoteVolume(note);
+ int32_t vol = getNoteVolume(p);
if (vol >= 0)
{
vol = (int32_t)((vol * dScale) + 0.5); // rounded
vol = MIN(MAX(0, vol), 64);
- setNoteVolume(note, (int8_t)vol);
+ setNoteVolume(p, (int8_t)vol);
}
}
@@ -1808,7 +1759,7 @@
return false;
}
- dVolScaleFK1 = atof(val1);
+ dVolScaleFK1 = atof(val1+0);
dVolScaleFK2 = atof(val2+1);
return true;
@@ -1819,22 +1770,22 @@
if (!askForScaleFade("Volume scale-fade track (start-, end scale)"))
return;
- if (patt[editor.editPattern] == NULL)
+ if (pattern[editor.editPattern] == NULL)
return;
- const int32_t pattLen = pattLens[editor.editPattern];
+ const int32_t numRows = patternNumRows[editor.editPattern];
- double dIPy = 0.0;
- if (pattLen > 0)
- dIPy = (dVolScaleFK2 - dVolScaleFK1) / pattLen;
+ double dVolDelta = 0.0;
+ if (numRows > 0)
+ dVolDelta = (dVolScaleFK2 - dVolScaleFK1) / numRows;
double dVol = dVolScaleFK1;
pauseMusic();
- for (int16_t row = 0; row < pattLen; row++)
+ for (int16_t row = 0; row < numRows; row++)
{
scaleNote(editor.editPattern, cursor.ch, row, dVol);
- dVol += dIPy;
+ dVol += dVolDelta;
}
resumeMusic();
}
@@ -1844,24 +1795,24 @@
if (!askForScaleFade("Volume scale-fade pattern (start-, end scale)"))
return;
- if (patt[editor.editPattern] == NULL)
+ if (pattern[editor.editPattern] == NULL)
return;
- const int32_t pattLen = pattLens[editor.editPattern];
+ const int32_t numRows = patternNumRows[editor.editPattern];
- double dIPy = 0.0;
- if (pattLen > 0)
- dIPy = (dVolScaleFK2 - dVolScaleFK1) / pattLen;
+ double dVolDelta = 0.0;
+ if (numRows > 0)
+ dVolDelta = (dVolScaleFK2 - dVolScaleFK1) / numRows;
double dVol = dVolScaleFK1;
pauseMusic();
- for (int16_t row = 0; row < pattLen; row++)
+ for (int16_t row = 0; row < numRows; row++)
{
- for (int8_t ch = 0; ch < song.antChn; ch++)
+ for (int8_t ch = 0; ch < song.numChannels; ch++)
scaleNote(editor.editPattern, ch, row, dVol);
- dVol += dIPy;
+ dVol += dVolDelta;
}
resumeMusic();
}
@@ -1871,14 +1822,14 @@
if (!askForScaleFade("Volume scale-fade block (start-, end scale)"))
return;
- if (patt[editor.editPattern] == NULL || pattMark.markY1 == pattMark.markY2 || pattMark.markY1 > pattMark.markY2)
+ if (pattern[editor.editPattern] == NULL || pattMark.markY1 == pattMark.markY2 || pattMark.markY1 > pattMark.markY2)
return;
- const int32_t dy = pattMark.markY2 - pattMark.markY1;
+ const int32_t numRows = pattMark.markY2 - pattMark.markY1;
- double dIPy = 0.0;
- if (dy > 0)
- dIPy = (dVolScaleFK2 - dVolScaleFK1) / dy;
+ double dVolDelta = 0.0;
+ if (numRows > 0)
+ dVolDelta = (dVolScaleFK2 - dVolScaleFK1) / numRows;
double dVol = dVolScaleFK1;
@@ -1888,7 +1839,7 @@
for (int16_t ch = pattMark.markX1; ch <= pattMark.markX2; ch++)
scaleNote(editor.editPattern, (uint8_t)ch, row, dVol);
- dVol += dIPy;
+ dVol += dVolDelta;
}
resumeMusic();
}
--- a/src/ft2_edit.h
+++ b/src/ft2_edit.h
@@ -4,7 +4,7 @@
#include <SDL2/SDL.h>
bool handleEditKeys(SDL_Keycode keycode, SDL_Scancode scancode);
-void recordNote(uint8_t note, int8_t vol);
+void recordNote(uint8_t noteNum, int8_t vol);
void testNoteKeysRelease(SDL_Scancode scancode);
void writeToMacroSlot(uint8_t slot);
void writeFromMacroSlot(uint8_t slot);
--- a/src/ft2_events.c
+++ b/src/ft2_events.c
@@ -33,10 +33,10 @@
#include "ft2_sample_ed_features.h"
#include "ft2_structs.h"
-#define CRASH_TEXT "Oh no!\nThe Fasttracker II clone has crashed...\n\nA backup .xm was hopefully " \
+#define CRASH_TEXT "Oh no! The Fasttracker II clone has crashed...\nA backup .xm was hopefully " \
"saved to the current module directory.\n\nPlease report this bug if you can.\n" \
"Try to mention what you did before the crash happened.\n" \
- "My email can be found at the bottom of 16-bits.org."
+ "My email can be found at the bottom of www.16-bits.org."
static bool backupMadeAfterCrash;
@@ -100,7 +100,7 @@
{
if (okBoxData.active)
{
- okBoxData.returnData = okBox(okBoxData.typ, okBoxData.headline, okBoxData.text);
+ okBoxData.returnData = okBox(okBoxData.type, okBoxData.headline, okBoxData.text);
okBoxData.active = false;
}
}
--- a/src/ft2_gui.c
+++ b/src/ft2_gui.c
@@ -12,7 +12,7 @@
#include "ft2_nibbles.h"
#include "ft2_gui.h"
#include "ft2_pattern_ed.h"
-#include "ft2_scopes.h"
+#include "scopes/ft2_scopes.h"
#include "ft2_help.h"
#include "ft2_sample_ed.h"
#include "ft2_inst_ed.h"
@@ -203,7 +203,7 @@
s->thumbH = 0;
}
- setPal16(palTable[config.cfg_StdPalNr], false);
+ setPal16(palTable[config.cfg_StdPalNum], false);
seedAboutScreenRandom((uint32_t)time(NULL));
setupInitialTextBoxPointers();
setInitialTrimFlags();
@@ -1141,7 +1141,7 @@
textOutShadow(4, 64, PAL_FORGRND, PAL_DSKTOP2, "Repstart");
drawPosEdNums(song.songPos);
drawSongLength();
- drawSongRepS();
+ drawSongLoopStart();
// logo button
showPushButton(PB_LOGO);
@@ -1181,8 +1181,8 @@
textOutShadow(116, 64, PAL_FORGRND, PAL_DSKTOP2, "Add.");
textOutShadow(210, 36, PAL_FORGRND, PAL_DSKTOP2, "Ptn.");
textOutShadow(210, 50, PAL_FORGRND, PAL_DSKTOP2, "Ln.");
- drawSongBPM(song.speed);
- drawSongSpeed(song.tempo);
+ drawSongBPM(song.BPM);
+ drawSongSpeed(song.speed);
drawEditPattern(editor.editPattern);
drawPatternLength(editor.editPattern);
drawIDAdd();
@@ -1190,7 +1190,7 @@
// status bar
drawFramework(0, 77, 291, 15, FRAMEWORK_TYPE1);
textOutShadow(4, 80, PAL_FORGRND, PAL_DSKTOP2, "Global volume");
- drawGlobalVol(song.globVol);
+ drawGlobalVol(song.globalVolume);
ui.updatePosSections = true;
--- a/src/ft2_header.h
+++ b/src/ft2_header.h
@@ -8,25 +8,29 @@
#define WIN32_MEAN_AND_LEAN
#include <windows.h>
#else
-#include <limits.h> // PATH_MAX
+#include <limits.h> // also has PATH_MAX
#endif
#include "ft2_replayer.h"
-#define PROG_VER_STR "1.46"
+#define PROG_VER_STR "1.47"
// do NOT change these! It will only mess things up...
+#define FT2_VBLANK_HZ 70
+#define SCREEN_W 632
+#define SCREEN_H 400
+
/* "60Hz" ranges everywhere from 59..61Hz depending on the monitor, so with
** no vsync we will get stuttering because the rate is not perfect...
*/
#define VBLANK_HZ 60
+// 70Hz (FT2 vblank) delta -> 60Hz vblank delta (rounded)
+#define SCALE_VBLANK_DELTA(x) (int32_t)(((x) * ((double)VBLANK_HZ / FT2_VBLANK_HZ)) + 0.5)
+
// scopes must be clocked slightly higher than the nominal vblank rate
#define SCOPE_HZ 64
-#define FT2_VBLANK_HZ 70
-#define SCREEN_W 632
-#define SCREEN_H 400
/* Amount of extra bytes to allocate for every instrument sample,
** this is used for a hack for resampling interpolation to be
@@ -33,8 +37,8 @@
** branchless in the inner channel mixer loop.
** Warning: Do not change this!
*/
-#define LOOP_FIX_LEN 32
-#define SMP_DAT_OFFSET 8
+#define SMP_DAT_OFFSET 32
+#define SAMPLE_PAD_LENGTH (SMP_DAT_OFFSET+32)
#ifndef _WIN32
#define _stricmp strcasecmp
@@ -51,6 +55,14 @@
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
#define CLAMP(x, low, high) (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x)))
+#define DROUND(x) \
+ if (x < 0.0) x -= 0.5; \
+ else if (x > 0.0) x += 0.5
+
+#define FROUND(x) \
+ if (x < 0.0f) x -= 0.5f; \
+ else if (x > 0.0f) x += 0.5f
+
// fast 32-bit -> 8-bit clamp
#define CLAMP8(i) if ((int8_t)(i) != i) i = 0x7F ^ (i >> 31)
@@ -60,16 +72,33 @@
#define ALIGN_PTR(p, x) (((uintptr_t)(p) + ((x)-1)) & ~((x)-1))
#define MALLOC_PAD(size, pad) (malloc((size) + (pad)))
-#define SWAP16(value) \
+#define SWAP16(x) \
( \
- (((uint16_t)((value) & 0x00FF)) << 8) | \
- (((uint16_t)((value) & 0xFF00)) >> 8) \
+ (((uint16_t)((x) & 0x00FF)) << 8) | \
+ (((uint16_t)((x) & 0xFF00)) >> 8) \
)
-#define SWAP32(value) \
+#define SWAP32(x) \
( \
- (((uint32_t)((value) & 0x000000FF)) << 24) | \
- (((uint32_t)((value) & 0x0000FF00)) << 8) | \
- (((uint32_t)((value) & 0x00FF0000)) >> 8) | \
- (((uint32_t)((value) & 0xFF000000)) >> 24) \
+ (((uint32_t)((x) & 0x000000FF)) << 24) | \
+ (((uint32_t)((x) & 0x0000FF00)) << 8) | \
+ (((uint32_t)((x) & 0x00FF0000)) >> 8) | \
+ (((uint32_t)((x) & 0xFF000000)) >> 24) \
)
+
+#define SWAP64(x) \
+( \
+ (((x) << 56) & 0xFF00000000000000ULL) | \
+ (((x) << 40) & 0x00FF000000000000ULL) | \
+ (((x) << 24) & 0x0000FF0000000000ULL) | \
+ (((x) << 8) & 0x000000FF00000000ULL) | \
+ (((x) >> 8) & 0x00000000FF000000ULL) | \
+ (((x) >> 24) & 0x0000000000FF0000ULL) | \
+ (((x) >> 40) & 0x000000000000FF00ULL) | \
+ (((x) >> 56) & 0x00000000000000FFULL) \
+)
+
+typedef struct smpPtr_t
+{
+ int8_t *origPtr, *ptr;
+} smpPtr_t;
--- a/src/ft2_help.c
+++ b/src/ft2_help.c
@@ -26,10 +26,10 @@
#define MAX_HELP_LINES 768
#define HELP_SIZE sizeof (helpRec)
#define MAX_SUBJ 10
-#define HELP_KOL 135
-#define HELP_WIDTH (596 - HELP_KOL)
+#define HELP_COLUMN 135
+#define HELP_WIDTH (596 - HELP_COLUMN)
-static uint8_t fHlp_Nr;
+static uint8_t fHlp_Num;
static int16_t textLine, fHlp_Line, subjLen[MAX_SUBJ];
static int32_t helpBufferPos;
static helpRec *subjPtrArr[MAX_SUBJ];
@@ -101,7 +101,7 @@
return s;
}
-static void readHelp(void) // this is really messy, directly ported from Pascal code...
+static void readHelp(void) // this is a bit messy...
{
char text[256], text2[256], *s, *sEnd, *s3;
int16_t a, b, i, k;
@@ -122,7 +122,7 @@
for (int16_t subj = 0; subj < MAX_SUBJ; subj++)
{
textLine = 0;
- int16_t currKol = 0;
+ int16_t currColumn = 0;
uint8_t currColor = PAL_FORGRND;
getLine(text); s = text;
@@ -139,12 +139,12 @@
if (*(uint16_t *)s == 0x4C40) // @L - "big font"
{
- addText(&tempText[textLine], currKol, currColor, s2);
+ addText(&tempText[textLine], currColumn, currColor, s2);
s += 2;
if (*(uint16_t *)s == 0x5840) // @X - "change X position"
{
- currKol = controlCodeToNum(&s[2]);
+ currColumn = controlCodeToNum(&s[2]);
s += 5;
}
@@ -156,7 +156,7 @@
}
helpRec *t = &tempText[textLine];
- t->xPos = currKol;
+ t->xPos = currColumn;
t->color = currColor;
t->bigFont = true;
t->noLine = false;
@@ -171,13 +171,13 @@
{
if (*s == '>')
{
- addText(&tempText[textLine], currKol, currColor, s2);
+ addText(&tempText[textLine], currColumn, currColor, s2);
s++;
}
if (*(uint16_t *)s == 0x5840) // @X - "set X position (relative to help X start)"
{
- currKol = controlCodeToNum(&s[2]);
+ currColumn = controlCodeToNum(&s[2]);
s += 5;
}
@@ -191,9 +191,9 @@
s = ltrim(rtrim(s));
if (*s == '\0')
{
- addText(&tempText[textLine], currKol, currColor, s2);
+ addText(&tempText[textLine], currColumn, currColor, s2);
strcpy(s2, " ");
- addText(&tempText[textLine], currKol, currColor, s2);
+ addText(&tempText[textLine], currColumn, currColor, s2);
}
int16_t sLen = (int16_t)strlen(s);
@@ -214,7 +214,7 @@
s += 5; sLen -= 5;
s3 = &s2[strlen(s2)];
- while (textWidth(s2) + charWidth(' ') + 1 < k-currKol)
+ while (textWidth(s2) + charWidth(' ') + 1 < k-currColumn)
{
s3[0] = ' ';
s3[1] = '\0';
@@ -222,17 +222,17 @@
}
b = textWidth(s2) + 1;
- if (b < (k - currKol))
+ if (b < k-currColumn)
{
s3 = &s2[strlen(s2)];
- for (a = 0; a < k-b-currKol; a++)
+ for (a = 0; a < k-b-currColumn; a++)
s3[a] = 127; // one-pixel spacer glyph
s3[a] = '\0';
}
}
- if (textWidth(s2)+textNWidth(s,i)+2 > HELP_WIDTH-currKol)
- addText(&tempText[textLine], currKol, currColor, s2);
+ if (textWidth(s2)+textNWidth(s,i)+2 > HELP_WIDTH-currColumn)
+ addText(&tempText[textLine], currColumn, currColor, s2);
strncat(s2, s, i);
@@ -301,42 +301,42 @@
static void writeHelp(void)
{
- helpRec *pek = subjPtrArr[fHlp_Nr];
- if (pek == NULL)
+ helpRec *ptr = subjPtrArr[fHlp_Num];
+ if (ptr == NULL)
return;
for (int16_t i = 0; i < HELP_LINES; i++)
{
const int16_t k = i + fHlp_Line;
- if (k >= subjLen[fHlp_Nr])
+ if (k >= subjLen[fHlp_Num])
break;
- clearRect(HELP_KOL, 5 + (i * 11), HELP_WIDTH, 11);
+ clearRect(HELP_COLUMN, 5 + (i * 11), HELP_WIDTH, 11);
- if (pek[k].noLine)
+ if (ptr[k].noLine)
{
if (i == 0)
- bigTextOutHalf(HELP_KOL + pek[k-1].xPos, 5 + (i * 11), PAL_FORGRND, false, pek[k-1].text);
+ bigTextOutHalf(HELP_COLUMN + ptr[k-1].xPos, 5 + (i * 11), PAL_FORGRND, false, ptr[k-1].text);
}
else
{
- if (pek[k].bigFont)
+ if (ptr[k].bigFont)
{
- if (i == (HELP_LINES - 1))
+ if (i == HELP_LINES-1)
{
- bigTextOutHalf(HELP_KOL + pek[k].xPos, 5 + (i * 11), PAL_FORGRND, true, pek[k].text);
+ bigTextOutHalf(HELP_COLUMN + ptr[k].xPos, 5 + (i * 11), PAL_FORGRND, true, ptr[k].text);
return;
}
else
{
- clearRect(HELP_KOL, 5 + ((i + 1) * 11), HELP_WIDTH, 11);
- bigTextOut(HELP_KOL + pek[k].xPos, 5 + (i * 11), PAL_FORGRND, pek[k].text);
+ clearRect(HELP_COLUMN, 5 + ((i + 1) * 11), HELP_WIDTH, 11);
+ bigTextOut(HELP_COLUMN + ptr[k].xPos, 5 + (i * 11), PAL_FORGRND, ptr[k].text);
i++;
}
}
else
{
- textOut(HELP_KOL + pek[k].xPos, 5 + (i * 11), pek[k].color, pek[k].text);
+ textOut(HELP_COLUMN + ptr[k].xPos, 5 + (i * 11), ptr[k].color, ptr[k].text);
}
}
}
@@ -353,7 +353,7 @@
void helpScrollDown(void)
{
- if (fHlp_Line < subjLen[fHlp_Nr]-1)
+ if (fHlp_Line < subjLen[fHlp_Num]-1)
{
scrollBarScrollDown(SB_HELP_SCROLL, 1);
writeHelp();
@@ -388,12 +388,12 @@
showPushButton(PB_HELP_SCROLL_DOWN);
uncheckRadioButtonGroup(RB_GROUP_HELP);
- switch (fHlp_Nr)
+ switch (fHlp_Num)
{
default:
case 0: tmpID = RB_HELP_FEATURES; break;
case 1: tmpID = RB_HELP_EFFECTS; break;
- case 2: tmpID = RB_HELP_KEYBOARD; break;
+ case 2: tmpID = RB_HELP_KEYBINDINGS; break;
case 3: tmpID = RB_HELP_HOW_TO_USE_FT2; break;
case 4: tmpID = RB_HELP_FAQ; break;
case 5: tmpID = RB_HELP_KNOWN_BUGS; break;
@@ -407,7 +407,7 @@
textOutShadow(4, 4, PAL_FORGRND, PAL_DSKTOP2, "Subjects:");
textOutShadow(21, 19, PAL_FORGRND, PAL_DSKTOP2, "Features");
textOutShadow(21, 35, PAL_FORGRND, PAL_DSKTOP2, "Effects");
- textOutShadow(21, 51, PAL_FORGRND, PAL_DSKTOP2, "Keyboard");
+ textOutShadow(21, 51, PAL_FORGRND, PAL_DSKTOP2, "Keybindings");
textOutShadow(21, 67, PAL_FORGRND, PAL_DSKTOP2, "How to use FT2");
textOutShadow(21, 83, PAL_FORGRND, PAL_DSKTOP2, "Problems/FAQ");
textOutShadow(21, 99, PAL_FORGRND, PAL_DSKTOP2, "Known bugs");
@@ -435,10 +435,10 @@
static void setHelpSubject(uint8_t Nr)
{
- fHlp_Nr = Nr;
+ fHlp_Num = Nr;
fHlp_Line = 0;
- setScrollBarEnd(SB_HELP_SCROLL, subjLen[fHlp_Nr]);
+ setScrollBarEnd(SB_HELP_SCROLL, subjLen[fHlp_Num]);
setScrollBarPos(SB_HELP_SCROLL, 0, false);
}
@@ -456,9 +456,9 @@
writeHelp();
}
-void rbHelpKeyboard(void)
+void rbHelpKeybindings(void)
{
- checkRadioButton(RB_HELP_KEYBOARD);
+ checkRadioButton(RB_HELP_KEYBINDINGS);
setHelpSubject(2);
writeHelp();
}
--- a/src/ft2_help.h
+++ b/src/ft2_help.h
@@ -16,7 +16,7 @@
void windUpFTHelp(void);
void rbHelpFeatures(void);
void rbHelpEffects(void);
-void rbHelpKeyboard(void);
+void rbHelpKeybindings(void);
void rbHelpHowToUseFT2(void);
void rbHelpFAQ(void);
void rbHelpKnownBugs(void);
--- a/src/ft2_inst_ed.c
+++ b/src/ft2_inst_ed.c
@@ -12,7 +12,7 @@
#include "ft2_audio.h"
#include "ft2_pattern_ed.h"
#include "ft2_gui.h"
-#include "ft2_scopes.h"
+#include "scopes/ft2_scopes.h"
#include "ft2_sample_ed.h"
#include "ft2_mouse.h"
#include "ft2_video.h"
@@ -27,66 +27,66 @@
#pragma pack(push)
#pragma pack(1)
#endif
-typedef struct instrPATHeaderTyp_t
+typedef struct patHdr_t
{
- char id[22], copyright[60];
- uint8_t antInstr, activeVoices, antChannels;
- int16_t waveForms, masterVol;
+ char ID[22], junk1[60];
+ uint8_t numInstrs, junk2, numChannels;
+ int16_t waveforms, masterVol;
int32_t dataSize;
- char reserved1[36];
- int16_t instrNr;
+ char junk4[36];
+ int16_t junk5;
char instrName[16];
int32_t instrSize;
uint8_t layers;
- char reserved2[40];
- uint8_t layerDuplicate, layerByte;
- int32_t layerSize;
- uint8_t antSamp;
- char reserved3[40];
+ char junk6[40];
+ uint8_t junk7, junk8;
+ int32_t junk9;
+ uint8_t numSamples;
+ char junk10[40];
}
#ifdef __GNUC__
__attribute__ ((packed))
#endif
-instrPATHeaderTyp;
+patHdr_t;
-typedef struct instrPATWaveHeaderTyp_t
+typedef struct patWaveHdr_t
{
char name[7];
uint8_t fractions;
- int32_t waveSize, repS, repE;
+ int32_t sampleLength, loopStart, loopEnd;
uint16_t sampleRate;
int32_t lowFrq, highFreq, rootFrq;
- int16_t fineTune;
- uint8_t pan, envRate[6], envOfs[6], tremSweep, tremRate;
- uint8_t tremDepth, vibSweep, vibRate, vibDepth, mode;
- int16_t scaleFrq;
- uint16_t scaleFactor;
- char reserved[36];
+ int16_t finetune;
+ uint8_t panning, envRate[6], envOfs[6], tremSweep, tremRate;
+ uint8_t tremDepth, vibSweep, vibRate, vibDepth, flags;
+ int16_t junk1;
+ uint16_t junk2;
+ char junk3[36];
}
#ifdef __GNUC__
__attribute__ ((packed))
#endif
-instrPATWaveHeaderTyp;
+patWaveHdr_t;
-typedef struct instrXIHeaderTyp_t
+typedef struct xiHdr_t
{
- char sig[21], name[23], progName[20];
- uint16_t ver;
- uint8_t ta[96];
- int16_t envVP[12][2], envPP[12][2];
- uint8_t envVPAnt, envPPAnt, envVSust, envVRepS, envVRepE, envPSust, envPRepS;
- uint8_t envPRepE, envVTyp, envPTyp, vibTyp, vibSweep, vibDepth, vibRate;
- uint16_t fadeOut;
+ char ID[21], name[23], progName[20];
+ uint16_t version;
+ uint8_t note2SampleLUT[96];
+ int16_t volEnvPoints[12][2], panEnvPoints[12][2];
+ uint8_t volEnvLength, panEnvLength, volEnvSustain, volEnvLoopStart, volEnvLoopEnd, panEnvSustain, panEnvLoopStart;
+ uint8_t panEnvLoopEnd, volEnvFlags, panEnvFlags, vibType, vibSweep, vibDepth, vibRate;
+ uint16_t fadeout;
uint8_t midiOn, midiChannel;
int16_t midiProgram, midiBend;
uint8_t mute, reserved[15];
- int16_t antSamp;
- sampleHeaderTyp samp[16];
+ int16_t numSamples;
+ xmSmpHdr_t smp[16];
}
#ifdef __GNUC__
__attribute__ ((packed))
#endif
-instrXIHeaderTyp;
+xiHdr_t;
#define PIANOKEY_WHITE_W 10
#define PIANOKEY_WHITE_H 46
@@ -114,7 +114,7 @@
};
// thread data
-static uint16_t saveInstrNr;
+static uint16_t saveInstrNum;
static SDL_Thread *thread;
extern const uint16_t *note2Period; // ft2_replayer.c
@@ -122,8 +122,45 @@
void updateInstEditor(void);
void updateNewInstrument(void);
-static instrTyp *getCurDispInstr(void)
+void sanitizeInstrument(instr_t *ins)
{
+ if (ins == NULL)
+ return;
+
+ ins->midiProgram = CLAMP(ins->midiProgram, 0, 127);
+ ins->midiBend = CLAMP(ins->midiBend, 0, 36);
+
+ if (ins->midiChannel > 15) ins->midiChannel = 15;
+ if (ins->vibDepth > 0x0F) ins->vibDepth = 0x0F;
+ if (ins->vibRate > 0x3F) ins->vibRate = 0x3F;
+ if (ins->vibType > 3) ins->vibType = 0;
+
+ for (int32_t i = 0; i < 96; i++)
+ {
+ if (ins->note2SampleLUT[i] >= MAX_SMP_PER_INST)
+ ins->note2SampleLUT[i] = MAX_SMP_PER_INST-1;
+ }
+
+ if (ins->volEnvLength > 12) ins->volEnvLength = 12;
+ if (ins->volEnvLoopStart > 11) ins->volEnvLoopStart = 11;
+ if (ins->volEnvLoopEnd > 11) ins->volEnvLoopEnd = 11;
+ if (ins->volEnvSustain > 11) ins->volEnvSustain = 11;
+ if (ins->panEnvLength > 12) ins->panEnvLength = 12;
+ if (ins->panEnvLoopStart > 11) ins->panEnvLoopStart = 11;
+ if (ins->panEnvLoopEnd > 11) ins->panEnvLoopEnd = 11;
+ if (ins->panEnvSustain > 11) ins->panEnvSustain = 11;
+
+ for (int32_t i = 0; i < 12; i++)
+ {
+ if ((uint16_t)ins->volEnvPoints[i][0] > 32767) ins->volEnvPoints[i][0] = 32767;
+ if ((uint16_t)ins->panEnvPoints[i][0] > 32767) ins->panEnvPoints[i][0] = 32767;
+ if ((uint16_t)ins->volEnvPoints[i][1] > 64) ins->volEnvPoints[i][1] = 64;
+ if ((uint16_t)ins->panEnvPoints[i][1] > 63) ins->panEnvPoints[i][1] = 63;
+ }
+}
+
+static instr_t *getCurDispInstr(void)
+{
if (instr[editor.curInstr] == NULL)
return instr[131];
@@ -132,44 +169,28 @@
static int32_t SDLCALL copyInstrThread(void *ptr)
{
- bool error = false;
+ const int16_t dstIns = editor.curInstr;
+ const int16_t srcIns = editor.srcInstr;
- const int16_t destIns = editor.curInstr;
- const int16_t sourceIns = editor.srcInstr;
-
pauseAudio();
-
- freeInstr(destIns);
+ freeInstr(dstIns);
- if (instr[sourceIns] != NULL)
+ bool error = true;
+ if (instr[srcIns] != NULL)
{
- if (allocateInstr(destIns))
+ if (allocateInstr(dstIns))
{
- memcpy(instr[destIns], instr[sourceIns], sizeof (instrTyp));
+ memcpy(instr[dstIns], instr[srcIns], sizeof (instr_t));
- sampleTyp *src = instr[sourceIns]->samp;
- sampleTyp *dst = instr[destIns]->samp;
+ sample_t *srcSmp = instr[srcIns]->smp;
+ sample_t *dstSmp = instr[dstIns]->smp;
- for (int16_t i = 0; i < MAX_SMP_PER_INST; i++, src++, dst++)
+ for (int16_t i = 0; i < MAX_SMP_PER_INST; i++, srcSmp++, dstSmp++)
{
- dst->origPek = NULL;
- dst->pek = NULL;
-
- if (src->origPek != NULL)
- {
- int8_t *p = (int8_t *)malloc(src->len + LOOP_FIX_LEN);
- if (p != NULL)
- {
- dst->origPek = p;
- dst->pek = dst->origPek + SMP_DAT_OFFSET;
-
- memcpy(dst->origPek, src->origPek, src->len + LOOP_FIX_LEN);
- }
- else error = true;
- }
+ if (!cloneSample(srcSmp, dstSmp))
+ error = false;
}
}
- else error = true;
}
resumeAudio();
@@ -179,12 +200,15 @@
// do not change instrument names!
- editor.updateCurInstr = true;
- setSongModifiedFlag();
+ if (!error)
+ {
+ editor.updateCurInstr = true;
+ setSongModifiedFlag();
+ }
+
setMouseBusy(false);
return false;
-
(void)ptr;
}
@@ -211,11 +235,11 @@
lockMixerCallback();
- instrTyp *src = instr[editor.srcInstr];
- instrTyp *dst = instr[editor.curInstr];
+ instr_t *src = instr[editor.srcInstr];
+ instr_t *dst = instr[editor.curInstr];
// swap instruments
- instrTyp dstTmp = *dst;
+ instr_t dstTmp = *dst;
*dst = *src;
*src = dstTmp;
@@ -229,7 +253,7 @@
static void drawMIDICh(void)
{
- instrTyp *ins = getCurDispInstr();
+ instr_t *ins = getCurDispInstr();
assert(ins->midiChannel <= 15);
const uint8_t val = ins->midiChannel + 1;
textOutFixed(156, 132, PAL_FORGRND, PAL_DESKTOP, dec2StrTab[val]);
@@ -237,7 +261,7 @@
static void drawMIDIPrg(void)
{
- instrTyp *ins = getCurDispInstr();
+ instr_t *ins = getCurDispInstr();
assert(ins->midiProgram <= 127);
textOutFixed(149, 146, PAL_FORGRND, PAL_DESKTOP, dec3StrTab[ins->midiProgram]);
}
@@ -244,7 +268,7 @@
static void drawMIDIBend(void)
{
- instrTyp *ins = getCurDispInstr();
+ instr_t *ins = getCurDispInstr();
assert(ins->midiBend <= 36);
textOutFixed(156, 160, PAL_FORGRND, PAL_DESKTOP, dec2StrTab[ins->midiBend]);
}
@@ -287,7 +311,7 @@
void sbMidiChPos(uint32_t pos)
{
- instrTyp *ins = instr[editor.curInstr];
+ instr_t *ins = instr[editor.curInstr];
if (ins == NULL || editor.curInstr == 0)
{
setScrollBarPos(SB_INST_EXT_MIDI_CH, 0, false);
@@ -304,7 +328,7 @@
void sbMidiPrgPos(uint32_t pos)
{
- instrTyp *ins = instr[editor.curInstr];
+ instr_t *ins = instr[editor.curInstr];
if (ins == NULL || editor.curInstr == 0)
{
setScrollBarPos(SB_INST_EXT_MIDI_PRG, 0, false);
@@ -321,7 +345,7 @@
void sbMidiBendPos(uint32_t pos)
{
- instrTyp *ins = instr[editor.curInstr];
+ instr_t *ins = instr[editor.curInstr];
if (ins == NULL || editor.curInstr == 0)
{
setScrollBarPos(SB_INST_EXT_MIDI_BEND, 0, false);
@@ -374,66 +398,66 @@
static void drawVolEnvSus(void)
{
- instrTyp *ins = getCurDispInstr();
- assert(ins->envVSust < 100);
- textOutFixed(382, 206, PAL_FORGRND, PAL_DESKTOP, dec2StrTab[ins->envVSust]);
+ instr_t *ins = getCurDispInstr();
+ assert(ins->volEnvSustain < 100);
+ textOutFixed(382, 206, PAL_FORGRND, PAL_DESKTOP, dec2StrTab[ins->volEnvSustain]);
}
static void drawVolEnvRepS(void)
{
- instrTyp *ins = getCurDispInstr();
- assert(ins->envVRepS < 100);
- textOutFixed(382, 233, PAL_FORGRND, PAL_DESKTOP, dec2StrTab[ins->envVRepS]);
+ instr_t *ins = getCurDispInstr();
+ assert(ins->volEnvLoopStart < 100);
+ textOutFixed(382, 233, PAL_FORGRND, PAL_DESKTOP, dec2StrTab[ins->volEnvLoopStart]);
}
static void drawVolEnvRepE(void)
{
- instrTyp *ins = getCurDispInstr();
- assert(ins->envVRepE < 100);
- textOutFixed(382, 247, PAL_FORGRND, PAL_DESKTOP, dec2StrTab[ins->envVRepE]);
+ instr_t *ins = getCurDispInstr();
+ assert(ins->volEnvLoopEnd < 100);
+ textOutFixed(382, 247, PAL_FORGRND, PAL_DESKTOP, dec2StrTab[ins->volEnvLoopEnd]);
}
static void drawPanEnvSus(void)
{
- instrTyp *ins = getCurDispInstr();
- assert(ins->envPSust < 100);
- textOutFixed(382, 293, PAL_FORGRND, PAL_DESKTOP, dec2StrTab[ins->envPSust]);
+ instr_t *ins = getCurDispInstr();
+ assert(ins->panEnvSustain < 100);
+ textOutFixed(382, 293, PAL_FORGRND, PAL_DESKTOP, dec2StrTab[ins->panEnvSustain]);
}
static void drawPanEnvRepS(void)
{
- instrTyp *ins = getCurDispInstr();
- assert(ins->envPRepS < 100);
- textOutFixed(382, 320, PAL_FORGRND, PAL_DESKTOP, dec2StrTab[ins->envPRepS]);
+ instr_t *ins = getCurDispInstr();
+ assert(ins->panEnvLoopStart < 100);
+ textOutFixed(382, 320, PAL_FORGRND, PAL_DESKTOP, dec2StrTab[ins->panEnvLoopStart]);
}
static void drawPanEnvRepE(void)
{
- instrTyp *ins = getCurDispInstr();
- assert(ins->envPRepE < 100);
- textOutFixed(382, 334, PAL_FORGRND, PAL_DESKTOP, dec2StrTab[ins->envPRepE]);
+ instr_t *ins = getCurDispInstr();
+ assert(ins->panEnvLoopEnd < 100);
+ textOutFixed(382, 334, PAL_FORGRND, PAL_DESKTOP, dec2StrTab[ins->panEnvLoopEnd]);
}
static void drawVolume(void)
{
- sampleTyp *s;
+ sample_t *s;
if (instr[editor.curInstr] == NULL)
- s = &instr[0]->samp[0];
+ s = &instr[0]->smp[0];
else
- s = &instr[editor.curInstr]->samp[editor.curSmp];
+ s = &instr[editor.curInstr]->smp[editor.curSmp];
- hexOutBg(505, 177, PAL_FORGRND, PAL_DESKTOP, s->vol, 2);
+ hexOutBg(505, 177, PAL_FORGRND, PAL_DESKTOP, s->volume, 2);
}
static void drawPanning(void)
{
- sampleTyp *s;
+ sample_t *s;
if (instr[editor.curInstr] == NULL)
- s = &instr[0]->samp[0];
+ s = &instr[0]->smp[0];
else
- s = &instr[editor.curInstr]->samp[editor.curSmp];
+ s = &instr[editor.curInstr]->smp[editor.curSmp];
- hexOutBg(505, 191, PAL_FORGRND, PAL_DESKTOP, s->pan, 2);
+ hexOutBg(505, 191, PAL_FORGRND, PAL_DESKTOP, s->panning, 2);
}
void drawC4Rate(void)
@@ -443,9 +467,9 @@
int32_t C4Hz = 0;
if (editor.curInstr != 0)
{
- instrTyp *ins = instr[editor.curInstr];
+ instr_t *ins = instr[editor.curInstr];
if (ins != NULL)
- C4Hz = (int32_t)(getSampleC4Rate(&ins->samp[editor.curSmp]) + 0.5); // rounded
+ C4Hz = (int32_t)(getSampleC4Rate(&ins->smp[editor.curSmp]) + 0.5); // rounded
}
char str[64];
@@ -455,15 +479,15 @@
static void drawFineTune(void)
{
- sampleTyp *s;
+ sample_t *s;
if (instr[editor.curInstr] == NULL)
- s = &instr[0]->samp[0];
+ s = &instr[0]->smp[0];
else
- s = &instr[editor.curInstr]->samp[editor.curSmp];
+ s = &instr[editor.curInstr]->smp[editor.curSmp];
fillRect(491, 205, 27, 8, PAL_DESKTOP);
- int16_t ftune = s->fine;
+ int16_t ftune = s->finetune;
if (ftune == 0)
{
charOut(512, 205, PAL_FORGRND, '0');
@@ -495,7 +519,7 @@
static void drawFadeout(void)
{
- hexOutBg(498, 222, PAL_FORGRND, PAL_DESKTOP, getCurDispInstr()->fadeOut, 3);
+ hexOutBg(498, 222, PAL_FORGRND, PAL_DESKTOP, getCurDispInstr()->fadeout, 3);
}
static void drawVibSpeed(void)
@@ -513,7 +537,7 @@
hexOutBg(505, 264, PAL_FORGRND, PAL_DESKTOP, getCurDispInstr()->vibSweep, 2);
}
-static void drawRelTone(void)
+static void drawRelativeNote(void)
{
char noteChar1, noteChar2;
int8_t note2;
@@ -527,7 +551,7 @@
if (editor.curInstr == 0)
note2 = 48;
else
- note2 = 48 + instr[editor.curInstr]->samp[editor.curSmp].relTon;
+ note2 = 48 + instr[editor.curInstr]->smp[editor.curSmp].relativeNote;
const int8_t note = note2 % 12;
if (config.ptnAcc == 0)
@@ -548,7 +572,7 @@
charOutBg(616, 299, PAL_FORGRND, PAL_BCKGRND, octaChar);
}
-static void setStdVolEnvelope(instrTyp *ins, uint8_t num)
+static void setStdVolEnvelope(instr_t *ins, uint8_t num)
{
if (editor.curInstr == 0 || ins == NULL)
return;
@@ -555,23 +579,23 @@
pauseMusic();
- ins->fadeOut = config.stdFadeOut[num];
- ins->envVSust = (uint8_t)config.stdVolEnvSust[num];
- ins->envVRepS = (uint8_t)config.stdVolEnvRepS[num];
- ins->envVRepE = (uint8_t)config.stdVolEnvRepE[num];
- ins->envVPAnt = (uint8_t)config.stdVolEnvAnt[num];
- ins->envVTyp = (uint8_t)config.stdVolEnvTyp[num];
+ ins->fadeout = config.stdFadeout[num];
+ ins->volEnvSustain = (uint8_t)config.stdVolEnvSustain[num];
+ ins->volEnvLoopStart = (uint8_t)config.stdVolEnvLoopStart[num];
+ ins->volEnvLoopEnd = (uint8_t)config.stdVolEnvLoopEnd[num];
+ ins->volEnvLength = (uint8_t)config.stdVolEnvLength[num];
+ ins->volEnvFlags = (uint8_t)config.stdVolEnvFlags[num];
ins->vibRate = (uint8_t)config.stdVibRate[num];
ins->vibDepth = (uint8_t)config.stdVibDepth[num];
ins->vibSweep = (uint8_t)config.stdVibSweep[num];
- ins->vibTyp = (uint8_t)config.stdVibTyp[num];
+ ins->vibType = (uint8_t)config.stdVibType[num];
- memcpy(ins->envVP, config.stdEnvP[num][0], sizeof (int16_t) * 12 * 2);
+ memcpy(ins->volEnvPoints, config.stdEnvPoints[num][0], sizeof (int16_t) * 12 * 2);
resumeMusic();
}
-static void setStdPanEnvelope(instrTyp *ins, uint8_t num)
+static void setStdPanEnvelope(instr_t *ins, uint8_t num)
{
if (editor.curInstr == 0 || ins == NULL)
return;
@@ -578,13 +602,13 @@
pauseMusic();
- ins->envPPAnt = (uint8_t)config.stdPanEnvAnt[num];
- ins->envPSust = (uint8_t)config.stdPanEnvSust[num];
- ins->envPRepS = (uint8_t)config.stdPanEnvRepS[num];
- ins->envPRepE = (uint8_t)config.stdPanEnvRepE[num];
- ins->envPTyp = (uint8_t)config.stdPanEnvTyp[num];
+ ins->panEnvLength = (uint8_t)config.stdPanEnvLength[num];
+ ins->panEnvSustain = (uint8_t)config.stdPanEnvSustain[num];
+ ins->panEnvLoopStart = (uint8_t)config.stdPanEnvLoopStart[num];
+ ins->panEnvLoopEnd = (uint8_t)config.stdPanEnvLoopEnd[num];
+ ins->panEnvFlags = (uint8_t)config.stdPanEnvFlags[num];
- memcpy(ins->envPP, config.stdEnvP[num][1], sizeof (int16_t) * 12 * 2);
+ memcpy(ins->panEnvPoints, config.stdEnvPoints[num][1], sizeof (int16_t) * 12 * 2);
resumeMusic();
}
@@ -591,7 +615,7 @@
static void setOrStoreVolEnvPreset(uint8_t num)
{
- instrTyp *ins = instr[editor.curInstr];
+ instr_t *ins = instr[editor.curInstr];
if (ins == NULL || editor.curInstr == 0)
return;
@@ -598,18 +622,18 @@
if (mouse.rightButtonReleased)
{
// store preset
- config.stdFadeOut[num] = ins->fadeOut;
- config.stdVolEnvSust[num] = ins->envVSust;
- config.stdVolEnvRepS[num] = ins->envVRepS;
- config.stdVolEnvRepE[num] = ins->envVRepE;
- config.stdVolEnvAnt[num] = ins->envVPAnt;
- config.stdVolEnvTyp[num] = ins->envVTyp;
+ config.stdFadeout[num] = ins->fadeout;
+ config.stdVolEnvSustain[num] = ins->volEnvSustain;
+ config.stdVolEnvLoopStart[num] = ins->volEnvLoopStart;
+ config.stdVolEnvLoopEnd[num] = ins->volEnvLoopEnd;
+ config.stdVolEnvLength[num] = ins->volEnvLength;
+ config.stdVolEnvFlags[num] = ins->volEnvFlags;
config.stdVibRate[num] = ins->vibRate;
config.stdVibDepth[num] = ins->vibDepth;
config.stdVibSweep[num] = ins->vibSweep;
- config.stdVibTyp[num] = ins->vibTyp;
+ config.stdVibType[num] = ins->vibType;
- memcpy(config.stdEnvP[num][0], ins->envVP, sizeof (int16_t) * 12 * 2);
+ memcpy(config.stdEnvPoints[num][0], ins->volEnvPoints, sizeof (int16_t) * 12 * 2);
}
else if (mouse.leftButtonReleased)
{
@@ -623,7 +647,7 @@
static void setOrStorePanEnvPreset(uint8_t num)
{
- instrTyp *ins = instr[editor.curInstr];
+ instr_t *ins = instr[editor.curInstr];
if (ins == NULL || editor.curInstr == 0)
return;
@@ -630,18 +654,18 @@
if (mouse.rightButtonReleased)
{
// store preset
- config.stdFadeOut[num] = ins->fadeOut;
- config.stdPanEnvSust[num] = ins->envPSust;
- config.stdPanEnvRepS[num] = ins->envPRepS;
- config.stdPanEnvRepE[num] = ins->envPRepE;
- config.stdPanEnvAnt[num] = ins->envPPAnt;
- config.stdPanEnvTyp[num] = ins->envPTyp;
+ config.stdFadeout[num] = ins->fadeout;
+ config.stdPanEnvSustain[num] = ins->panEnvSustain;
+ config.stdPanEnvLoopStart[num] = ins->panEnvLoopStart;
+ config.stdPanEnvLoopEnd[num] = ins->panEnvLoopEnd;
+ config.stdPanEnvLength[num] = ins->panEnvLength;
+ config.stdPanEnvFlags[num] = ins->panEnvFlags;
config.stdVibRate[num] = ins->vibRate;
config.stdVibDepth[num] = ins->vibDepth;
config.stdVibSweep[num] = ins->vibSweep;
- config.stdVibTyp[num] = ins->vibTyp;
+ config.stdVibType[num] = ins->vibType;
- memcpy(config.stdEnvP[num][1], ins->envPP, sizeof (int16_t) * 12 * 2);
+ memcpy(config.stdEnvPoints[num][1], ins->panEnvPoints, sizeof (int16_t) * 12 * 2);
}
else if (mouse.leftButtonReleased)
{
@@ -725,67 +749,67 @@
setOrStorePanEnvPreset(6 - 1);
}
-void relToneOctUp(void)
+void relativeNoteOctUp(void)
{
- sampleTyp *s;
+ sample_t *s;
if (instr[editor.curInstr] == NULL || editor.curInstr == 0)
return;
- s = &instr[editor.curInstr]->samp[editor.curSmp];
- if (s->relTon <= 71-12)
- s->relTon += 12;
+ s = &instr[editor.curInstr]->smp[editor.curSmp];
+ if (s->relativeNote <= 71-12)
+ s->relativeNote += 12;
else
- s->relTon = 71;
+ s->relativeNote = 71;
- drawRelTone();
+ drawRelativeNote();
drawC4Rate();
setSongModifiedFlag();
}
-void relToneOctDown(void)
+void relativeNoteOctDown(void)
{
- sampleTyp *s;
+ sample_t *s;
if (instr[editor.curInstr] == NULL || editor.curInstr == 0)
return;
- s = &instr[editor.curInstr]->samp[editor.curSmp];
- if (s->relTon >= -48+12)
- s->relTon -= 12;
+ s = &instr[editor.curInstr]->smp[editor.curSmp];
+ if (s->relativeNote >= -48+12)
+ s->relativeNote -= 12;
else
- s->relTon = -48;
+ s->relativeNote = -48;
- drawRelTone();
+ drawRelativeNote();
drawC4Rate();
setSongModifiedFlag();
}
-void relToneUp(void)
+void relativeNoteUp(void)
{
- sampleTyp *s;
+ sample_t *s;
if (instr[editor.curInstr] == NULL || editor.curInstr == 0)
return;
- s = &instr[editor.curInstr]->samp[editor.curSmp];
- if (s->relTon < 71)
+ s = &instr[editor.curInstr]->smp[editor.curSmp];
+ if (s->relativeNote < 71)
{
- s->relTon++;
- drawRelTone();
+ s->relativeNote++;
+ drawRelativeNote();
drawC4Rate();
setSongModifiedFlag();
}
}
-void relToneDown(void)
+void relativeNoteDown(void)
{
- sampleTyp *s;
+ sample_t *s;
if (instr[editor.curInstr] == NULL || editor.curInstr == 0)
return;
- s = &instr[editor.curInstr]->samp[editor.curSmp];
- if (s->relTon > -48)
+ s = &instr[editor.curInstr]->smp[editor.curSmp];
+ if (s->relativeNote > -48)
{
- s->relTon--;
- drawRelTone();
+ s->relativeNote--;
+ drawRelativeNote();
drawC4Rate();
setSongModifiedFlag();
}
@@ -793,11 +817,11 @@
void volEnvAdd(void)
{
- instrTyp *ins = instr[editor.curInstr];
+ instr_t *ins = instr[editor.curInstr];
if (editor.curInstr == 0 || ins == NULL)
return;
- const int16_t ant = ins->envVPAnt;
+ const int16_t ant = ins->volEnvLength;
if (ant >= 12)
return;
@@ -809,37 +833,37 @@
i = 0;
}
- if (i < ant-1 && ins->envVP[i+1][0]-ins->envVP[i][0] < 2)
+ if (i < ant-1 && ins->volEnvPoints[i+1][0]-ins->volEnvPoints[i][0] < 2)
return;
- if (ins->envVP[i][0] >= 323)
+ if (ins->volEnvPoints[i][0] >= 323)
return;
for (int16_t j = ant; j > i; j--)
{
- ins->envVP[j][0] = ins->envVP[j-1][0];
- ins->envVP[j][1] = ins->envVP[j-1][1];
+ ins->volEnvPoints[j][0] = ins->volEnvPoints[j-1][0];
+ ins->volEnvPoints[j][1] = ins->volEnvPoints[j-1][1];
}
- if (ins->envVSust > i) { ins->envVSust++; drawVolEnvSus(); }
- if (ins->envVRepS > i) { ins->envVRepS++; drawVolEnvRepS(); }
- if (ins->envVRepE > i) { ins->envVRepE++; drawVolEnvRepE(); }
+ if (ins->volEnvSustain > i) { ins->volEnvSustain++; drawVolEnvSus(); }
+ if (ins->volEnvLoopStart > i) { ins->volEnvLoopStart++; drawVolEnvRepS(); }
+ if (ins->volEnvLoopEnd > i) { ins->volEnvLoopEnd++; drawVolEnvRepE(); }
if (i < ant-1)
{
- ins->envVP[i+1][0] = (ins->envVP[i][0] + ins->envVP[i+2][0]) / 2;
- ins->envVP[i+1][1] = (ins->envVP[i][1] + ins->envVP[i+2][1]) / 2;
+ ins->volEnvPoints[i+1][0] = (ins->volEnvPoints[i][0] + ins->volEnvPoints[i+2][0]) / 2;
+ ins->volEnvPoints[i+1][1] = (ins->volEnvPoints[i][1] + ins->volEnvPoints[i+2][1]) / 2;
}
else
{
- ins->envVP[i+1][0] = ins->envVP[i][0] + 10;
- ins->envVP[i+1][1] = ins->envVP[i][1];
+ ins->volEnvPoints[i+1][0] = ins->volEnvPoints[i][0] + 10;
+ ins->volEnvPoints[i+1][1] = ins->volEnvPoints[i][1];
}
- if (ins->envVP[i+1][0] > 324)
- ins->envVP[i+1][0] = 324;
+ if (ins->volEnvPoints[i+1][0] > 324)
+ ins->volEnvPoints[i+1][0] = 324;
- ins->envVPAnt++;
+ ins->volEnvLength++;
updateVolEnv = true;
setSongModifiedFlag();
@@ -847,18 +871,18 @@
void volEnvDel(void)
{
- instrTyp *ins = instr[editor.curInstr];
- if (ins == NULL || editor.curInstr == 0 || ins->envVPAnt <= 2)
+ instr_t *ins = instr[editor.curInstr];
+ if (ins == NULL || editor.curInstr == 0 || ins->volEnvLength <= 2)
return;
int16_t i = (int16_t)editor.currVolEnvPoint;
- if (i < 0 || i >= ins->envVPAnt)
+ if (i < 0 || i >= ins->volEnvLength)
return;
- for (int16_t j = i; j < ins->envVPAnt; j++)
+ for (int16_t j = i; j < ins->volEnvLength; j++)
{
- ins->envVP[j][0] = ins->envVP[j+1][0];
- ins->envVP[j][1] = ins->envVP[j+1][1];
+ ins->volEnvPoints[j][0] = ins->volEnvPoints[j+1][0];
+ ins->volEnvPoints[j][1] = ins->volEnvPoints[j+1][1];
}
bool drawSust = false;
@@ -865,25 +889,25 @@
bool drawRepS = false;
bool drawRepE = false;
- if (ins->envVSust > i) { ins->envVSust--; drawSust = true; }
- if (ins->envVRepS > i) { ins->envVRepS--; drawRepS = true; }
- if (ins->envVRepE > i) { ins->envVRepE--; drawRepE = true; }
+ if (ins->volEnvSustain > i) { ins->volEnvSustain--; drawSust = true; }
+ if (ins->volEnvLoopStart > i) { ins->volEnvLoopStart--; drawRepS = true; }
+ if (ins->volEnvLoopEnd > i) { ins->volEnvLoopEnd--; drawRepE = true; }
- ins->envVP[0][0] = 0;
- ins->envVPAnt--;
+ ins->volEnvPoints[0][0] = 0;
+ ins->volEnvLength--;
- if (ins->envVSust >= ins->envVPAnt) { ins->envVSust = ins->envVPAnt - 1; drawSust = true; }
- if (ins->envVRepS >= ins->envVPAnt) { ins->envVRepS = ins->envVPAnt - 1; drawRepS = true; }
- if (ins->envVRepE >= ins->envVPAnt) { ins->envVRepE = ins->envVPAnt - 1; drawRepE = true; }
+ if (ins->volEnvSustain >= ins->volEnvLength) { ins->volEnvSustain = ins->volEnvLength - 1; drawSust = true; }
+ if (ins->volEnvLoopStart >= ins->volEnvLength) { ins->volEnvLoopStart = ins->volEnvLength - 1; drawRepS = true; }
+ if (ins->volEnvLoopEnd >= ins->volEnvLength) { ins->volEnvLoopEnd = ins->volEnvLength - 1; drawRepE = true; }
if (drawSust) drawVolEnvSus();
if (drawRepS) drawVolEnvRepS();
if (drawRepE) drawVolEnvRepE();
- if (ins->envVPAnt == 0)
+ if (ins->volEnvLength == 0)
editor.currVolEnvPoint = 0;
- else if (editor.currVolEnvPoint >= ins->envVPAnt)
- editor.currVolEnvPoint = ins->envVPAnt-1;
+ else if (editor.currVolEnvPoint >= ins->volEnvLength)
+ editor.currVolEnvPoint = ins->volEnvLength-1;
updateVolEnv = true;
setSongModifiedFlag();
@@ -891,13 +915,13 @@
void volEnvSusUp(void)
{
- instrTyp *ins = instr[editor.curInstr];
+ instr_t *ins = instr[editor.curInstr];
if (ins == NULL || editor.curInstr == 0)
return;
- if (ins->envVSust < ins->envVPAnt-1)
+ if (ins->volEnvSustain < ins->volEnvLength-1)
{
- ins->envVSust++;
+ ins->volEnvSustain++;
drawVolEnvSus();
updateVolEnv = true;
setSongModifiedFlag();
@@ -906,13 +930,13 @@
void volEnvSusDown(void)
{
- instrTyp *ins = instr[editor.curInstr];
+ instr_t *ins = instr[editor.curInstr];
if (ins == NULL || editor.curInstr == 0)
return;
- if (ins->envVSust > 0)
+ if (ins->volEnvSustain > 0)
{
- ins->envVSust--;
+ ins->volEnvSustain--;
drawVolEnvSus();
updateVolEnv = true;
setSongModifiedFlag();
@@ -921,13 +945,13 @@
void volEnvRepSUp(void)
{
- instrTyp *ins = instr[editor.curInstr];
+ instr_t *ins = instr[editor.curInstr];
if (ins == NULL || editor.curInstr == 0)
return;
- if (ins->envVRepS < ins->envVRepE)
+ if (ins->volEnvLoopStart < ins->volEnvLoopEnd)
{
- ins->envVRepS++;
+ ins->volEnvLoopStart++;
drawVolEnvRepS();
updateVolEnv = true;
setSongModifiedFlag();
@@ -936,13 +960,13 @@
void volEnvRepSDown(void)
{
- instrTyp *ins = instr[editor.curInstr];
+ instr_t *ins = instr[editor.curInstr];
if (ins == NULL || editor.curInstr == 0)
return;
- if (ins->envVRepS > 0)
+ if (ins->volEnvLoopStart > 0)
{
- ins->envVRepS--;
+ ins->volEnvLoopStart--;
drawVolEnvRepS();
updateVolEnv = true;
setSongModifiedFlag();
@@ -951,13 +975,13 @@
void volEnvRepEUp(void)
{
- instrTyp *ins = instr[editor.curInstr];
+ instr_t *ins = instr[editor.curInstr];
if (ins == NULL || editor.curInstr == 0)
return;
- if (ins->envVRepE < ins->envVPAnt-1)
+ if (ins->volEnvLoopEnd < ins->volEnvLength-1)
{
- ins->envVRepE++;
+ ins->volEnvLoopEnd++;
drawVolEnvRepE();
updateVolEnv = true;
setSongModifiedFlag();
@@ -966,13 +990,13 @@
void volEnvRepEDown(void)
{
- instrTyp *ins = instr[editor.curInstr];
+ instr_t *ins = instr[editor.curInstr];
if (ins == NULL || editor.curInstr == 0)
return;
- if (ins->envVRepE > ins->envVRepS)
+ if (ins->volEnvLoopEnd > ins->volEnvLoopStart)
{
- ins->envVRepE--;
+ ins->volEnvLoopEnd--;
drawVolEnvRepE();
updateVolEnv = true;
setSongModifiedFlag();
@@ -981,11 +1005,11 @@
void panEnvAdd(void)
{
- instrTyp *ins = instr[editor.curInstr];
+ instr_t *ins = instr[editor.curInstr];
if (ins == NULL || editor.curInstr == 0)
return;
- const int16_t ant = ins->envPPAnt;
+ const int16_t ant = ins->panEnvLength;
if (ant >= 12)
return;
@@ -997,37 +1021,37 @@
i = 0;
}
- if (i < ant-1 && ins->envPP[i+1][0]-ins->envPP[i][0] < 2)
+ if (i < ant-1 && ins->panEnvPoints[i+1][0]-ins->panEnvPoints[i][0] < 2)
return;
- if (ins->envPP[i][0] >= 323)
+ if (ins->panEnvPoints[i][0] >= 323)
return;
for (int16_t j = ant; j > i; j--)
{
- ins->envPP[j][0] = ins->envPP[j-1][0];
- ins->envPP[j][1] = ins->envPP[j-1][1];
+ ins->panEnvPoints[j][0] = ins->panEnvPoints[j-1][0];
+ ins->panEnvPoints[j][1] = ins->panEnvPoints[j-1][1];
}
- if (ins->envPSust > i) { ins->envPSust++; drawPanEnvSus(); }
- if (ins->envPRepS > i) { ins->envPRepS++; drawPanEnvRepS(); }
- if (ins->envPRepE > i) { ins->envPRepE++; drawPanEnvRepE(); }
+ if (ins->panEnvSustain > i) { ins->panEnvSustain++; drawPanEnvSus(); }
+ if (ins->panEnvLoopStart > i) { ins->panEnvLoopStart++; drawPanEnvRepS(); }
+ if (ins->panEnvLoopEnd > i) { ins->panEnvLoopEnd++; drawPanEnvRepE(); }
if (i < ant-1)
{
- ins->envPP[i+1][0] = (ins->envPP[i][0] + ins->envPP[i+2][0]) / 2;
- ins->envPP[i+1][1] = (ins->envPP[i][1] + ins->envPP[i+2][1]) / 2;
+ ins->panEnvPoints[i+1][0] = (ins->panEnvPoints[i][0] + ins->panEnvPoints[i+2][0]) / 2;
+ ins->panEnvPoints[i+1][1] = (ins->panEnvPoints[i][1] + ins->panEnvPoints[i+2][1]) / 2;
}
else
{
- ins->envPP[i+1][0] = ins->envPP[i][0] + 10;
- ins->envPP[i+1][1] = ins->envPP[i][1];
+ ins->panEnvPoints[i+1][0] = ins->panEnvPoints[i][0] + 10;
+ ins->panEnvPoints[i+1][1] = ins->panEnvPoints[i][1];
}
- if (ins->envPP[i+1][0] > 324)
- ins->envPP[i+1][0] = 324;
+ if (ins->panEnvPoints[i+1][0] > 324)
+ ins->panEnvPoints[i+1][0] = 324;
- ins->envPPAnt++;
+ ins->panEnvLength++;
updatePanEnv = true;
setSongModifiedFlag();
@@ -1035,18 +1059,18 @@
void panEnvDel(void)
{
- instrTyp *ins = instr[editor.curInstr];
- if (ins == NULL || editor.curInstr == 0 || ins->envPPAnt <= 2)
+ instr_t *ins = instr[editor.curInstr];
+ if (ins == NULL || editor.curInstr == 0 || ins->panEnvLength <= 2)
return;
int16_t i = (int16_t)editor.currPanEnvPoint;
- if (i < 0 || i >= ins->envPPAnt)
+ if (i < 0 || i >= ins->panEnvLength)
return;
- for (int16_t j = i; j < ins->envPPAnt; j++)
+ for (int16_t j = i; j < ins->panEnvLength; j++)
{
- ins->envPP[j][0] = ins->envPP[j+1][0];
- ins->envPP[j][1] = ins->envPP[j+1][1];
+ ins->panEnvPoints[j][0] = ins->panEnvPoints[j+1][0];
+ ins->panEnvPoints[j][1] = ins->panEnvPoints[j+1][1];
}
bool drawSust = false;
@@ -1053,25 +1077,25 @@
bool drawRepS = false;
bool drawRepE = false;
- if (ins->envPSust > i) { ins->envPSust--; drawSust = true; }
- if (ins->envPRepS > i) { ins->envPRepS--; drawRepS = true; }
- if (ins->envPRepE > i) { ins->envPRepE--; drawRepE = true; }
+ if (ins->panEnvSustain > i) { ins->panEnvSustain--; drawSust = true; }
+ if (ins->panEnvLoopStart > i) { ins->panEnvLoopStart--; drawRepS = true; }
+ if (ins->panEnvLoopEnd > i) { ins->panEnvLoopEnd--; drawRepE = true; }
- ins->envPP[0][0] = 0;
- ins->envPPAnt--;
+ ins->panEnvPoints[0][0] = 0;
+ ins->panEnvLength--;
- if (ins->envPSust >= ins->envPPAnt) { ins->envPSust = ins->envPPAnt - 1; drawSust = true; }
- if (ins->envPRepS >= ins->envPPAnt) { ins->envPRepS = ins->envPPAnt - 1; drawRepS = true; }
- if (ins->envPRepE >= ins->envPPAnt) { ins->envPRepE = ins->envPPAnt - 1; drawRepE = true; }
+ if (ins->panEnvSustain >= ins->panEnvLength) { ins->panEnvSustain = ins->panEnvLength - 1; drawSust = true; }
+ if (ins->panEnvLoopStart >= ins->panEnvLength) { ins->panEnvLoopStart = ins->panEnvLength - 1; drawRepS = true; }
+ if (ins->panEnvLoopEnd >= ins->panEnvLength) { ins->panEnvLoopEnd = ins->panEnvLength - 1; drawRepE = true; }
if (drawSust) drawPanEnvSus();
if (drawRepS) drawPanEnvRepS();
if (drawRepE) drawPanEnvRepE();
- if (ins->envPPAnt == 0)
+ if (ins->panEnvLength == 0)
editor.currPanEnvPoint = 0;
- else if (editor.currPanEnvPoint >= ins->envPPAnt)
- editor.currPanEnvPoint = ins->envPPAnt-1;
+ else if (editor.currPanEnvPoint >= ins->panEnvLength)
+ editor.currPanEnvPoint = ins->panEnvLength-1;
updatePanEnv = true;
setSongModifiedFlag();
@@ -1079,13 +1103,13 @@
void panEnvSusUp(void)
{
- instrTyp *ins = instr[editor.curInstr];
+ instr_t *ins = instr[editor.curInstr];
if (ins == NULL || editor.curInstr == 0)
return;
- if (ins->envPSust < ins->envPPAnt-1)
+ if (ins->panEnvSustain < ins->panEnvLength-1)
{
- ins->envPSust++;
+ ins->panEnvSustain++;
drawPanEnvSus();
updatePanEnv = true;
setSongModifiedFlag();
@@ -1094,13 +1118,13 @@
void panEnvSusDown(void)
{
- instrTyp *ins = instr[editor.curInstr];
+ instr_t *ins = instr[editor.curInstr];
if (ins == NULL || editor.curInstr == 0)
return;
- if (ins->envPSust > 0)
+ if (ins->panEnvSustain > 0)
{
- ins->envPSust--;
+ ins->panEnvSustain--;
drawPanEnvSus();
updatePanEnv = true;
setSongModifiedFlag();
@@ -1109,13 +1133,13 @@
void panEnvRepSUp(void)
{
- instrTyp *ins = instr[editor.curInstr];
+ instr_t *ins = instr[editor.curInstr];
if (ins == NULL || editor.curInstr == 0)
return;
- if (ins->envPRepS < ins->envPRepE)
+ if (ins->panEnvLoopStart < ins->panEnvLoopEnd)
{
- ins->envPRepS++;
+ ins->panEnvLoopStart++;
drawPanEnvRepS();
updatePanEnv = true;
setSongModifiedFlag();
@@ -1124,13 +1148,13 @@
void panEnvRepSDown(void)
{
- instrTyp *ins = instr[editor.curInstr];
+ instr_t *ins = instr[editor.curInstr];
if (ins == NULL || editor.curInstr == 0)
return;
- if (ins->envPRepS > 0)
+ if (ins->panEnvLoopStart > 0)
{
- ins->envPRepS--;
+ ins->panEnvLoopStart--;
drawPanEnvRepS();
updatePanEnv = true;
setSongModifiedFlag();
@@ -1139,13 +1163,13 @@
void panEnvRepEUp(void)
{
- instrTyp *ins = instr[editor.curInstr];
+ instr_t *ins = instr[editor.curInstr];
if (ins == NULL || editor.curInstr == 0)
return;
- if (ins->envPRepE < ins->envPPAnt-1)
+ if (ins->panEnvLoopEnd < ins->panEnvLength-1)
{
- ins->envPRepE++;
+ ins->panEnvLoopEnd++;
drawPanEnvRepE();
updatePanEnv = true;
setSongModifiedFlag();
@@ -1154,13 +1178,13 @@
void panEnvRepEDown(void)
{
- instrTyp *ins = instr[editor.curInstr];
+ instr_t *ins = instr[editor.curInstr];
if (ins == NULL || editor.curInstr == 0)
return;
- if (ins->envPRepE > ins->envPRepS)
+ if (ins->panEnvLoopEnd > ins->panEnvLoopStart)
{
- ins->envPRepE--;
+ ins->panEnvLoopEnd--;
drawPanEnvRepE();
updatePanEnv = true;
setSongModifiedFlag();
@@ -1263,10 +1287,10 @@
return;
}
- sampleTyp *s = &instr[editor.curInstr]->samp[editor.curSmp];
- if (s->vol != (uint8_t)pos)
+ sample_t *s = &instr[editor.curInstr]->smp[editor.curSmp];
+ if (s->volume != (uint8_t)pos)
{
- s->vol = (uint8_t)pos;
+ s->volume = (uint8_t)pos;
drawVolume();
setSongModifiedFlag();
}
@@ -1280,10 +1304,10 @@
return;
}
- sampleTyp *s = &instr[editor.curInstr]->samp[editor.curSmp];
- if (s->pan != (uint8_t)pos)
+ sample_t *s = &instr[editor.curInstr]->smp[editor.curSmp];
+ if (s->panning != (uint8_t)pos)
{
- s->pan = (uint8_t)pos;
+ s->panning = (uint8_t)pos;
drawPanning();
setSongModifiedFlag();
}
@@ -1297,10 +1321,10 @@
return;
}
- sampleTyp *s = &instr[editor.curInstr]->samp[editor.curSmp];
- if (s->fine != (int8_t)(pos - 128))
+ sample_t *s = &instr[editor.curInstr]->smp[editor.curSmp];
+ if (s->finetune != (int8_t)(pos - 128))
{
- s->fine = (int8_t)(pos - 128);
+ s->finetune = (int8_t)(pos - 128);
drawFineTune();
drawC4Rate();
setSongModifiedFlag();
@@ -1309,7 +1333,7 @@
void setFadeoutScroll(uint32_t pos)
{
- instrTyp *ins = instr[editor.curInstr];
+ instr_t *ins = instr[editor.curInstr];
if (ins == NULL)
{
setScrollBarPos(SB_INST_FADEOUT, 0, false);
@@ -1322,9 +1346,9 @@
return;
}
- if (ins->fadeOut != (uint16_t)pos)
+ if (ins->fadeout != (uint16_t)pos)
{
- ins->fadeOut = (uint16_t)pos;
+ ins->fadeout = (uint16_t)pos;
drawFadeout();
setSongModifiedFlag();
}
@@ -1332,7 +1356,7 @@
void setVibSpeedScroll(uint32_t pos)
{
- instrTyp *ins = instr[editor.curInstr];
+ instr_t *ins = instr[editor.curInstr];
if (ins == NULL || editor.curInstr == 0)
{
setScrollBarPos(SB_INST_VIBSPEED, 0, false);
@@ -1349,7 +1373,7 @@
void setVibDepthScroll(uint32_t pos)
{
- instrTyp *ins = instr[editor.curInstr];
+ instr_t *ins = instr[editor.curInstr];
if (ins == NULL || editor.curInstr == 0)
{
setScrollBarPos(SB_INST_VIBDEPTH, 0, false);
@@ -1366,7 +1390,7 @@
void setVibSweepScroll(uint32_t pos)
{
- instrTyp *ins = instr[editor.curInstr];
+ instr_t *ins = instr[editor.curInstr];
if (ins == NULL || editor.curInstr == 0)
{
setScrollBarPos(SB_INST_VIBSWEEP, 0, false);
@@ -1386,7 +1410,7 @@
if (instr[editor.curInstr] == NULL || editor.curInstr == 0)
return;
- instr[editor.curInstr]->vibTyp = 0;
+ instr[editor.curInstr]->vibType = 0;
uncheckRadioButtonGroup(RB_GROUP_INST_WAVEFORM);
radioButtons[RB_INST_WAVE_SINE].state = RADIOBUTTON_CHECKED;
@@ -1399,7 +1423,7 @@
if (instr[editor.curInstr] == NULL || editor.curInstr == 0)
return;
- instr[editor.curInstr]->vibTyp = 1;
+ instr[editor.curInstr]->vibType = 1;
uncheckRadioButtonGroup(RB_GROUP_INST_WAVEFORM);
radioButtons[RB_INST_WAVE_SQUARE].state = RADIOBUTTON_CHECKED;
@@ -1412,7 +1436,7 @@
if (instr[editor.curInstr] == NULL || editor.curInstr == 0)
return;
- instr[editor.curInstr]->vibTyp = 2;
+ instr[editor.curInstr]->vibType = 2;
uncheckRadioButtonGroup(RB_GROUP_INST_WAVEFORM);
radioButtons[RB_INST_WAVE_RAMP_DOWN].state = RADIOBUTTON_CHECKED;
@@ -1425,7 +1449,7 @@
if (instr[editor.curInstr] == NULL || editor.curInstr == 0)
return;
- instr[editor.curInstr]->vibTyp = 3;
+ instr[editor.curInstr]->vibType = 3;
uncheckRadioButtonGroup(RB_GROUP_INST_WAVEFORM);
radioButtons[RB_INST_WAVE_RAMP_UP].state = RADIOBUTTON_CHECKED;
@@ -1442,7 +1466,7 @@
return;
}
- instr[editor.curInstr]->envVTyp ^= 1;
+ instr[editor.curInstr]->volEnvFlags ^= 1;
updateVolEnv = true;
setSongModifiedFlag();
@@ -1457,7 +1481,7 @@
return;
}
- instr[editor.curInstr]->envVTyp ^= 2;
+ instr[editor.curInstr]->volEnvFlags ^= 2;
updateVolEnv = true;
setSongModifiedFlag();
@@ -1472,7 +1496,7 @@
return;
}
- instr[editor.curInstr]->envVTyp ^= 4;
+ instr[editor.curInstr]->volEnvFlags ^= 4;
updateVolEnv = true;
setSongModifiedFlag();
@@ -1487,7 +1511,7 @@
return;
}
- instr[editor.curInstr]->envPTyp ^= 1;
+ instr[editor.curInstr]->panEnvFlags ^= 1;
updatePanEnv = true;
setSongModifiedFlag();
@@ -1502,7 +1526,7 @@
return;
}
- instr[editor.curInstr]->envPTyp ^= 2;
+ instr[editor.curInstr]->panEnvFlags ^= 2;
updatePanEnv = true;
setSongModifiedFlag();
@@ -1517,7 +1541,7 @@
return;
}
- instr[editor.curInstr]->envPTyp ^= 4;
+ instr[editor.curInstr]->panEnvFlags ^= 4;
updatePanEnv = true;
setSongModifiedFlag();
@@ -1546,7 +1570,7 @@
{
uint8_t number = 0;
if (instr[editor.curInstr] != NULL && editor.curInstr != 0)
- number = instr[editor.curInstr]->ta[note];
+ number = instr[editor.curInstr]->note2SampleLUT[note];
const uint16_t x = keyDigitXPos[key] + (octave * 77);
@@ -1633,9 +1657,9 @@
}
const uint8_t note = (octave * 12) + key;
- if (instr[editor.curInstr]->ta[note] != editor.curSmp)
+ if (instr[editor.curInstr]->note2SampleLUT[note] != editor.curSmp)
{
- instr[editor.curInstr]->ta[note] = editor.curSmp;
+ instr[editor.curInstr]->note2SampleLUT[note] = editor.curSmp;
writePianoNumber(note, key, octave);
setSongModifiedFlag();
}
@@ -1654,20 +1678,20 @@
if (chSyncData != NULL) // song is playing, use replayer channel state
{
syncedChannel_t *c = chSyncData->channels;
- for (int32_t i = 0; i < song.antChn; i++, c++)
+ for (int32_t i = 0; i < song.numChannels; i++, c++)
{
- if (c->instrNr == editor.curInstr && c->pianoNoteNr <= 95)
- newStatus[c->pianoNoteNr] = true;
+ if (c->instrNum == editor.curInstr && c->pianoNoteNum <= 95)
+ newStatus[c->pianoNoteNum] = true;
}
}
else // song is not playing (jamming from keyboard/MIDI)
{
- stmTyp *c = stm;
- for (int32_t i = 0; i < song.antChn; i++, c++)
+ channel_t *c = channel;
+ for (int32_t i = 0; i < song.numChannels; i++, c++)
{
- if (c->instrNr == editor.curInstr && c->envSustainActive)
+ if (c->instrNum == editor.curInstr && c->envSustainActive)
{
- const int32_t note = getPianoKey(c->finalPeriod, c->fineTune, c->relTonNr);
+ const int32_t note = getPianoKey(c->finalPeriod, c->finetune, c->relativeNote);
if (note >= 0 && note <= 95)
newStatus[note] = true;
}
@@ -1694,7 +1718,7 @@
}
}
-static void envelopeLine(int32_t nr, int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint8_t col)
+static void envelopeLine(int32_t envNum, int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint8_t pal)
{
y1 = CLAMP(y1, 0, 66);
y2 = CLAMP(y2, 0, 66);
@@ -1701,12 +1725,12 @@
x1 = CLAMP(x1, 0, 335);
x2 = CLAMP(x2, 0, 335);
- if (nr == 0)
+ if (envNum == 0) // volume envelope
{
y1 += 189;
y2 += 189;
}
- else
+ else // panning envelope
{
y1 += 276;
y2 += 276;
@@ -1723,7 +1747,7 @@
const uint32_t pal1 = video.palette[PAL_BLCKMRK];
const uint32_t pal2 = video.palette[PAL_BLCKTXT];
- const uint32_t pixVal = video.palette[col];
+ const uint32_t pixVal = video.palette[pal];
const int32_t pitch = sy * SCREEN_W;
uint32_t *dst32 = &video.frameBuffer[(y * SCREEN_W) + x];
@@ -1787,15 +1811,15 @@
}
}
-static void envelopePixel(int32_t nr, int16_t x, int16_t y, uint8_t col)
+static void envelopePixel(int32_t envNum, int16_t x, int16_t y, uint8_t pal)
{
- y += (nr == 0) ? 189 : 276;
- video.frameBuffer[(y * SCREEN_W) + x] = video.palette[col];
+ y += (envNum == 0) ? 189 : 276;
+ video.frameBuffer[(y * SCREEN_W) + x] = video.palette[pal];
}
-static void envelopeDot(int32_t nr, int16_t x, int16_t y)
+static void envelopeDot(int32_t envNum, int16_t x, int16_t y)
{
- y += (nr == 0) ? 189 : 276;
+ y += (envNum == 0) ? 189 : 276;
const uint32_t pixVal = video.palette[PAL_BLCKTXT];
uint32_t *dstPtr = &video.frameBuffer[(y * SCREEN_W) + x];
@@ -1810,11 +1834,11 @@
}
}
-static void envelopeVertLine(int32_t nr, int16_t x, int16_t y, uint8_t col)
+static void envelopeVertLine(int32_t envNum, int16_t x, int16_t y, uint8_t pal)
{
- y += (nr == 0) ? 189 : 276;
+ y += (envNum == 0) ? 189 : 276;
- const uint32_t pixVal1 = video.palette[col];
+ const uint32_t pixVal1 = video.palette[pal];
const uint32_t pixVal2 = video.palette[PAL_BLCKTXT];
uint32_t *dstPtr = &video.frameBuffer[(y * SCREEN_W) + x];
@@ -1827,45 +1851,46 @@
}
}
-static void writeEnvelope(int32_t nr)
+static void writeEnvelope(int32_t envNum)
{
uint8_t selected;
int16_t i, nd, sp, ls, le, (*curEnvP)[2];
- instrTyp *ins = instr[editor.curInstr];
+ instr_t *ins = instr[editor.curInstr];
// clear envelope area
- if (nr == 0)
+ if (envNum == 0)
clearRect(5, 189, 333, 67);
else
clearRect(5, 276, 333, 67);
// draw dotted x/y lines
- for (i = 0; i <= 32; i++) envelopePixel(nr, 5, 1 + i * 2, PAL_PATTEXT);
- for (i = 0; i <= 8; i++) envelopePixel(nr, 4, 1 + i * 8, PAL_PATTEXT);
- for (i = 0; i <= 162; i++) envelopePixel(nr, 8 + i * 2, 65, PAL_PATTEXT);
- for (i = 0; i <= 6; i++) envelopePixel(nr, 8 + i * 50, 66, PAL_PATTEXT);
+ for (i = 0; i <= 32; i++) envelopePixel(envNum, 5, 1 + i * 2, PAL_PATTEXT);
+ for (i = 0; i <= 8; i++) envelopePixel(envNum, 4, 1 + i * 8, PAL_PATTEXT);
+ for (i = 0; i <= 162; i++) envelopePixel(envNum, 8 + i * 2, 65, PAL_PATTEXT);
+ for (i = 0; i <= 6; i++) envelopePixel(envNum, 8 + i * 50, 66, PAL_PATTEXT);
// draw center line on pan envelope
- if (nr == 1)
- envelopeLine(nr, 8, 33, 332, 33, PAL_BLCKMRK);
+ if (envNum == 1)
+ envelopeLine(envNum, 8, 33, 332, 33, PAL_BLCKMRK);
if (ins == NULL)
return;
// collect variables
- if (nr == 0)
+
+ if (envNum == 0) // volume envelope
{
- nd = ins->envVPAnt;
- if (ins->envVTyp & 2)
- sp = ins->envVSust;
+ nd = ins->volEnvLength;
+ if (ins->volEnvFlags & ENV_SUSTAIN)
+ sp = ins->volEnvSustain;
else
sp = -1;
- if (ins->envVTyp & 4)
+ if (ins->volEnvFlags & ENV_LOOP)
{
- ls = ins->envVRepS;
- le = ins->envVRepE;
+ ls = ins->volEnvLoopStart;
+ le = ins->volEnvLoopEnd;
}
else
{
@@ -1873,21 +1898,21 @@
le = -1;
}
- curEnvP = ins->envVP;
+ curEnvP = ins->volEnvPoints;
selected = editor.currVolEnvPoint;
}
- else
+ else // panning envelope
{
- nd = ins->envPPAnt;
- if (ins->envPTyp & 2)
- sp = ins->envPSust;
+ nd = ins->panEnvLength;
+ if (ins->panEnvFlags & ENV_SUSTAIN)
+ sp = ins->panEnvSustain;
else
sp = -1;
- if (ins->envPTyp & 4)
+ if (ins->panEnvFlags & ENV_LOOP)
{
- ls = ins->envPRepS;
- le = ins->envPRepE;
+ ls = ins->panEnvLoopStart;
+ le = ins->panEnvLoopEnd;
}
else
{
@@ -1895,7 +1920,7 @@
le = -1;
}
- curEnvP = ins->envPP;
+ curEnvP = ins->panEnvPoints;
selected = editor.currPanEnvPoint;
}
@@ -1913,48 +1938,48 @@
x = CLAMP(x, 0, 324);
- if (nr == 0)
+ if (envNum == 0) // volume envelope
y = CLAMP(y, 0, 64);
- else
+ else // panning envelope
y = CLAMP(y, 0, 63);
if ((uint16_t)curEnvP[i][0] <= 324)
{
- envelopeDot(nr, 7 + x, 64 - y);
+ envelopeDot(envNum, 7 + x, 64 - y);
// draw "envelope selected" data
if (i == selected)
{
- envelopeLine(nr, 5 + x, 64 - y, 5 + x, 66 - y, PAL_BLCKTXT);
- envelopeLine(nr, 11 + x, 64 - y, 11 + x, 66 - y, PAL_BLCKTXT);
- envelopePixel(nr, 5, 65 - y, PAL_BLCKTXT);
- envelopePixel(nr, 8 + x, 65, PAL_BLCKTXT);
+ envelopeLine(envNum, 5 + x, 64 - y, 5 + x, 66 - y, PAL_BLCKTXT);
+ envelopeLine(envNum, 11 + x, 64 - y, 11 + x, 66 - y, PAL_BLCKTXT);
+ envelopePixel(envNum, 5, 65 - y, PAL_BLCKTXT);
+ envelopePixel(envNum, 8 + x, 65, PAL_BLCKTXT);
}
// draw loop start marker
if (i == ls)
{
- envelopeLine(nr, x + 6, 1, x + 10, 1, PAL_PATTEXT);
- envelopeLine(nr, x + 7, 2, x + 9, 2, PAL_PATTEXT);
- envelopeVertLine(nr, x + 8, 1, PAL_PATTEXT);
+ envelopeLine(envNum, x + 6, 1, x + 10, 1, PAL_PATTEXT);
+ envelopeLine(envNum, x + 7, 2, x + 9, 2, PAL_PATTEXT);
+ envelopeVertLine(envNum, x + 8, 1, PAL_PATTEXT);
}
// draw sustain marker
if (i == sp)
- envelopeVertLine(nr, x + 8, 1, PAL_BLCKTXT);
+ envelopeVertLine(envNum, x + 8, 1, PAL_BLCKTXT);
// draw loop end marker
if (i == le)
{
- envelopeLine(nr, x + 6, 65, x + 10, 65, PAL_PATTEXT);
- envelopeLine(nr, x + 7, 64, x + 9, 64, PAL_PATTEXT);
- envelopeVertLine(nr, x + 8, 1, PAL_PATTEXT);
+ envelopeLine(envNum, x + 6, 65, x + 10, 65, PAL_PATTEXT);
+ envelopeLine(envNum, x + 7, 64, x + 9, 64, PAL_PATTEXT);
+ envelopeVertLine(envNum, x + 8, 1, PAL_PATTEXT);
}
}
// draw envelope line
if (i > 0 && lx < x)
- envelopeLine(nr, lx + 8, 65 - ly, x + 8, 65 - y, PAL_PATTEXT);
+ envelopeLine(envNum, lx + 8, 65 - ly, x + 8, 65 - y, PAL_PATTEXT);
lx = x;
ly = y;
@@ -2010,7 +2035,7 @@
{
int16_t tick, val;
- instrTyp *ins = instr[editor.curInstr];
+ instr_t *ins = instr[editor.curInstr];
if (updateVolEnv)
{
@@ -2020,10 +2045,10 @@
tick = 0;
val = 0;
- if (ins != NULL && ins->envVPAnt > 0)
+ if (ins != NULL && ins->volEnvLength > 0)
{
- tick = ins->envVP[editor.currVolEnvPoint][0];
- val = ins->envVP[editor.currVolEnvPoint][1];
+ tick = ins->volEnvPoints[editor.currVolEnvPoint][0];
+ val = ins->volEnvPoints[editor.currVolEnvPoint][1];
}
drawVolEnvCoords(tick, val);
@@ -2037,10 +2062,10 @@
tick = 0;
val = 32;
- if (ins != NULL && ins->envPPAnt > 0)
+ if (ins != NULL && ins->panEnvLength > 0)
{
- tick = ins->envPP[editor.currPanEnvPoint][0];
- val = ins->envPP[editor.currPanEnvPoint][1];
+ tick = ins->panEnvPoints[editor.currPanEnvPoint][0];
+ val = ins->panEnvPoints[editor.currPanEnvPoint][1];
}
drawPanEnvCoords(tick, val);
@@ -2126,13 +2151,13 @@
void updateInstEditor(void)
{
uint16_t tmpID;
- sampleTyp *s;
- instrTyp *ins = getCurDispInstr();
+ sample_t *s;
+ instr_t *ins = getCurDispInstr();
if (instr[editor.curInstr] == NULL)
- s = &ins->samp[0];
+ s = &ins->smp[0];
else
- s = &ins->samp[editor.curSmp];
+ s = &ins->smp[editor.curSmp];
// update instrument editor extension
if (ui.instEditorExtShown)
@@ -2169,13 +2194,13 @@
drawVibDepth();
drawVibSweep();
drawC4Rate();
- drawRelTone();
+ drawRelativeNote();
// set scroll bars
- setScrollBarPos(SB_INST_VOL, s->vol, false);
- setScrollBarPos(SB_INST_PAN, s->pan, false);
- setScrollBarPos(SB_INST_FTUNE, 128 + s->fine, false);
- setScrollBarPos(SB_INST_FADEOUT, ins->fadeOut, false);
+ setScrollBarPos(SB_INST_VOL, s->volume, false);
+ setScrollBarPos(SB_INST_PAN, s->panning, false);
+ setScrollBarPos(SB_INST_FTUNE, 128 + s->finetune, false);
+ setScrollBarPos(SB_INST_FADEOUT, ins->fadeout, false);
setScrollBarPos(SB_INST_VIBSPEED, ins->vibRate, false);
setScrollBarPos(SB_INST_VIBDEPTH, ins->vibDepth, false);
setScrollBarPos(SB_INST_VIBSWEEP, ins->vibSweep, false);
@@ -2183,7 +2208,7 @@
// set radio buttons
uncheckRadioButtonGroup(RB_GROUP_INST_WAVEFORM);
- switch (ins->vibTyp)
+ switch (ins->vibType)
{
default:
case 0: tmpID = RB_INST_WAVE_SINE; break;
@@ -2194,18 +2219,19 @@
radioButtons[tmpID].state = RADIOBUTTON_CHECKED;
- // set check boxes
+ // set checkboxes
- checkBoxes[CB_INST_VENV].checked = (ins->envVTyp & 1) ? true : false;
- checkBoxes[CB_INST_VENV_SUS].checked = (ins->envVTyp & 2) ? true : false;
- checkBoxes[CB_INST_VENV_LOOP].checked = (ins->envVTyp & 4) ? true : false;
- checkBoxes[CB_INST_PENV].checked = (ins->envPTyp & 1) ? true : false;
- checkBoxes[CB_INST_PENV_SUS].checked = (ins->envPTyp & 2) ? true : false;
- checkBoxes[CB_INST_PENV_LOOP].checked = (ins->envPTyp & 4) ? true : false;
+ checkBoxes[CB_INST_VENV].checked = (ins->volEnvFlags & ENV_ENABLED) ? true : false;
+ checkBoxes[CB_INST_VENV_SUS].checked = (ins->volEnvFlags & ENV_SUSTAIN) ? true : false;
+ checkBoxes[CB_INST_VENV_LOOP].checked = (ins->volEnvFlags & ENV_LOOP) ? true : false;
- if (editor.currVolEnvPoint >= ins->envVPAnt) editor.currVolEnvPoint = 0;
- if (editor.currPanEnvPoint >= ins->envPPAnt) editor.currPanEnvPoint = 0;
+ checkBoxes[CB_INST_PENV].checked = (ins->panEnvFlags & ENV_ENABLED) ? true : false;
+ checkBoxes[CB_INST_PENV_SUS].checked = (ins->panEnvFlags & ENV_SUSTAIN) ? true : false;
+ checkBoxes[CB_INST_PENV_LOOP].checked = (ins->panEnvFlags & ENV_LOOP) ? true : false;
+ if (editor.currVolEnvPoint >= ins->volEnvLength) editor.currVolEnvPoint = 0;
+ if (editor.currPanEnvPoint >= ins->panEnvLength) editor.currPanEnvPoint = 0;
+
showRadioButtonGroup(RB_GROUP_INST_WAVEFORM);
drawCheckBox(CB_INST_VENV);
@@ -2257,7 +2283,7 @@
textOutShadow(342, 334, PAL_FORGRND, PAL_DSKTOP2, "End");
textOutShadow(443, 177, PAL_FORGRND, PAL_DSKTOP2, "Volume");
textOutShadow(443, 191, PAL_FORGRND, PAL_DSKTOP2, "Panning");
- textOutShadow(443, 205, PAL_FORGRND, PAL_DSKTOP2, "Tune");
+ textOutShadow(443, 205, PAL_FORGRND, PAL_DSKTOP2, "F.tune");
textOutShadow(442, 222, PAL_FORGRND, PAL_DSKTOP2, "Fadeout");
textOutShadow(442, 236, PAL_FORGRND, PAL_DSKTOP2, "Vib.speed");
textOutShadow(442, 250, PAL_FORGRND, PAL_DSKTOP2, "Vib.depth");
@@ -2363,9 +2389,9 @@
if (!ui.instEditorShown || editor.curInstr == 0 || instr[editor.curInstr] == NULL)
return false;
- instrTyp *ins = instr[editor.curInstr];
+ instr_t *ins = instr[editor.curInstr];
- uint8_t ant = ins->envVPAnt;
+ uint8_t ant = ins->volEnvLength;
if (ant > 12)
ant = 12;
@@ -2377,7 +2403,7 @@
if (my < 189 || my > 256 || mx < 7 || mx > 334)
return false;
- if (ins->envVPAnt == 0)
+ if (ins->volEnvLength == 0)
return true;
lastMouseX = mx;
@@ -2385,8 +2411,8 @@
for (uint8_t i = 0; i < ant; i++)
{
- const int32_t x = 8 + ins->envVP[i][0];
- const int32_t y = 190 + (64 - ins->envVP[i][1]);
+ const int32_t x = 8 + ins->volEnvPoints[i][0];
+ const int32_t y = 190 + (64 - ins->volEnvPoints[i][1]);
if (mx >= x-2 && mx <= x+2 && my >= y-2 && my <= y+2)
{
@@ -2404,7 +2430,7 @@
return true;
}
- if (ins->envVPAnt == 0)
+ if (ins->volEnvLength == 0)
return true;
if (mx != lastMouseX)
@@ -2418,19 +2444,19 @@
if (editor.currVolEnvPoint == ant-1)
{
- minX = ins->envVP[editor.currVolEnvPoint-1][0] + 1;
+ minX = ins->volEnvPoints[editor.currVolEnvPoint-1][0] + 1;
maxX = 324;
}
else
{
- minX = ins->envVP[editor.currVolEnvPoint-1][0] + 1;
- maxX = ins->envVP[editor.currVolEnvPoint+1][0] - 1;
+ minX = ins->volEnvPoints[editor.currVolEnvPoint-1][0] + 1;
+ maxX = ins->volEnvPoints[editor.currVolEnvPoint+1][0] - 1;
}
minX = CLAMP(minX, 0, 324);
maxX = CLAMP(maxX, 0, 324);
- ins->envVP[editor.currVolEnvPoint][0] = (int16_t)(CLAMP(mx, minX, maxX));
+ ins->volEnvPoints[editor.currVolEnvPoint][0] = (int16_t)(CLAMP(mx, minX, maxX));
updateVolEnv = true;
setSongModifiedFlag();
@@ -2444,7 +2470,7 @@
my -= saveMouseY;
my = 64 - CLAMP(my, 0, 64);
- ins->envVP[editor.currVolEnvPoint][1] = (int16_t)my;
+ ins->volEnvPoints[editor.currVolEnvPoint][1] = (int16_t)my;
updateVolEnv = true;
setSongModifiedFlag();
@@ -2460,9 +2486,9 @@
if (!ui.instEditorShown || editor.curInstr == 0 || instr[editor.curInstr] == NULL)
return false;
- instrTyp *ins = instr[editor.curInstr];
+ instr_t *ins = instr[editor.curInstr];
- uint8_t ant = ins->envPPAnt;
+ uint8_t ant = ins->panEnvLength;
if (ant > 12)
ant = 12;
@@ -2474,7 +2500,7 @@
if (my < 277 || my > 343 || mx < 7 || mx > 334)
return false;
- if (ins->envPPAnt == 0)
+ if (ins->panEnvLength == 0)
return true;
lastMouseX = mx;
@@ -2482,8 +2508,8 @@
for (uint8_t i = 0; i < ant; i++)
{
- const int32_t x = 8 + ins->envPP[i][0];
- const int32_t y = 277 + (63 - ins->envPP[i][1]);
+ const int32_t x = 8 + ins->panEnvPoints[i][0];
+ const int32_t y = 277 + (63 - ins->panEnvPoints[i][1]);
if (mx >= x-2 && mx <= x+2 && my >= y-2 && my <= y+2)
{
@@ -2501,7 +2527,7 @@
return true;
}
- if (ins->envPPAnt == 0)
+ if (ins->panEnvLength == 0)
return true;
if (mx != lastMouseX)
@@ -2515,19 +2541,19 @@
if (editor.currPanEnvPoint == ant-1)
{
- minX = ins->envPP[editor.currPanEnvPoint-1][0] + 1;
+ minX = ins->panEnvPoints[editor.currPanEnvPoint-1][0] + 1;
maxX = 324;
}
else
{
- minX = ins->envPP[editor.currPanEnvPoint-1][0] + 1;
- maxX = ins->envPP[editor.currPanEnvPoint+1][0] - 1;
+ minX = ins->panEnvPoints[editor.currPanEnvPoint-1][0] + 1;
+ maxX = ins->panEnvPoints[editor.currPanEnvPoint+1][0] - 1;
}
minX = CLAMP(minX, 0, 324);
maxX = CLAMP(maxX, 0, 324);
- ins->envPP[editor.currPanEnvPoint][0] = (int16_t)(CLAMP(mx, minX, maxX));
+ ins->panEnvPoints[editor.currPanEnvPoint][0] = (int16_t)(CLAMP(mx, minX, maxX));
updatePanEnv = true;
setSongModifiedFlag();
@@ -2541,7 +2567,7 @@
my -= saveMouseY;
my = 63 - CLAMP(my, 0, 63);
- ins->envPP[editor.currPanEnvPoint][1] = (int16_t)my;
+ ins->panEnvPoints[editor.currPanEnvPoint][1] = (int16_t)my;
updatePanEnv = true;
setSongModifiedFlag();
@@ -2578,7 +2604,7 @@
void drawInstEditorExt(void)
{
- instrTyp *ins = instr[editor.curInstr];
+ instr_t *ins = instr[editor.curInstr];
drawFramework(0, 92, 291, 17, FRAMEWORK_TYPE1);
drawFramework(0, 109, 291, 19, FRAMEWORK_TYPE1);
@@ -2870,8 +2896,8 @@
static int32_t SDLCALL saveInstrThread(void *ptr)
{
- instrXIHeaderTyp ih;
- sampleTyp *s;
+ xiHdr_t ih;
+ sample_t *s;
if (editor.tmpFilenameU == NULL)
{
@@ -2879,8 +2905,8 @@
return false;
}
- const int16_t n = getUsedSamples(saveInstrNr);
- if (n == 0 || instr[saveInstrNr] == NULL)
+ const int32_t numSamples = getUsedSamples(saveInstrNum);
+ if (numSamples == 0 || instr[saveInstrNum] == NULL)
{
okBoxThreadSafe(0, "System message", "Instrument is empty!");
return false;
@@ -2895,63 +2921,94 @@
memset(&ih, 0, sizeof (ih)); // important, also clears reserved stuff
- memcpy(ih.sig, "Extended Instrument: ", 21);
- memset(ih.name, ' ', 22);
- memcpy(ih.name, song.instrName[saveInstrNr], strlen(song.instrName[saveInstrNr]));
+ memcpy(ih.ID, "Extended Instrument: ", 21);
+ ih.version = 0x0102;
+
+ // song name
+ int32_t nameLength = (int32_t)strlen(song.instrName[saveInstrNum]);
+ if (nameLength > 22)
+ nameLength = 22;
+
+ memset(ih.name, ' ', 22); // yes, FT2 pads the name with spaces
+ if (nameLength > 0)
+ memcpy(ih.name, song.instrName[saveInstrNum], nameLength);
+
ih.name[22] = 0x1A;
- memcpy(ih.progName, PROG_NAME_STR, 20);
- ih.ver = 0x0102;
+ // program/tracker name
+ nameLength = (int32_t)strlen(PROG_NAME_STR);
+ if (nameLength > 20)
+ nameLength = 20;
+
+ memset(ih.progName, ' ', 20); // yes, FT2 pads the name with spaces
+ if (nameLength > 0)
+ memcpy(ih.progName, PROG_NAME_STR, nameLength);
+
// copy over instrument struct data to instrument header
- instrTyp *ins = instr[saveInstrNr];
- memcpy(ih.ta, ins->ta, 96);
- memcpy(ih.envVP, ins->envVP, 12*2*sizeof(int16_t));
- memcpy(ih.envPP, ins->envPP, 12*2*sizeof(int16_t));
- ih.envVPAnt = ins->envVPAnt;
- ih.envPPAnt = ins->envPPAnt;
- ih.envVSust = ins->envVSust;
- ih.envVRepS = ins->envVRepS;
- ih.envVRepE = ins->envVRepE;
- ih.envPSust = ins->envPSust;
- ih.envPRepS = ins->envPRepS;
- ih.envPRepE = ins->envPRepE;
- ih.envVTyp = ins->envVTyp;
- ih.envPTyp = ins->envPTyp;
- ih.vibTyp = ins->vibTyp;
+ instr_t *ins = instr[saveInstrNum];
+ memcpy(ih.note2SampleLUT, ins->note2SampleLUT, 96);
+ memcpy(ih.volEnvPoints, ins->volEnvPoints, 12*2*sizeof(int16_t));
+ memcpy(ih.panEnvPoints, ins->panEnvPoints, 12*2*sizeof(int16_t));
+ ih.volEnvLength = ins->volEnvLength;
+ ih.panEnvLength = ins->panEnvLength;
+ ih.volEnvSustain = ins->volEnvSustain;
+ ih.volEnvLoopStart = ins->volEnvLoopStart;
+ ih.volEnvLoopEnd = ins->volEnvLoopEnd;
+ ih.panEnvSustain = ins->panEnvSustain;
+ ih.panEnvLoopStart = ins->panEnvLoopStart;
+ ih.panEnvLoopEnd = ins->panEnvLoopEnd;
+ ih.volEnvFlags = ins->volEnvFlags;
+ ih.panEnvFlags = ins->panEnvFlags;
+ ih.vibType = ins->vibType;
ih.vibSweep = ins->vibSweep;
ih.vibDepth = ins->vibDepth;
ih.vibRate = ins->vibRate;
- ih.fadeOut = ins->fadeOut;
+ ih.fadeout = ins->fadeout;
ih.midiOn = ins->midiOn ? 1 : 0;
ih.midiChannel = ins->midiChannel;
ih.midiProgram = ins->midiProgram;
ih.midiBend = ins->midiBend;
ih.mute = ins->mute ? 1 : 0;
- ih.antSamp = n;
+ ih.numSamples = (uint16_t)numSamples;
// copy over sample struct datas to sample headers
- s = instr[saveInstrNr]->samp;
- for (int32_t i = 0; i < n; i++, s++)
+ s = instr[saveInstrNum]->smp;
+ for (int32_t i = 0; i < numSamples; i++, s++)
{
- sampleHeaderTyp *dst = &ih.samp[i];
+ xmSmpHdr_t *dst = &ih.smp[i];
- dst->len = s->len;
- dst->repS = s->repS;
- dst->repL = s->repL;
- dst->vol = s->vol;
- dst->fine = s->fine;
- dst->typ = s->typ;
- dst->pan = s->pan;
- dst->relTon = s->relTon;
+ bool sample16Bit = !!(s->flags & SAMPLE_16BIT);
- dst->nameLen = (uint8_t)strlen(s->name);
- memcpy(dst->name, s->name, 22);
+ dst->length = s->length;
+ dst->loopStart = s->loopStart;
+ dst->loopLength = s->loopLength;
- if (s->pek == NULL)
- dst->len = 0;
+ if (sample16Bit)
+ {
+ dst->length <<= 1;
+ dst->loopStart <<= 1;
+ dst->loopLength <<= 1;
+ }
+
+ dst->volume = s->volume;
+ dst->finetune = s->finetune;
+ dst->flags = s->flags;
+ dst->panning = s->panning;
+ dst->relativeNote = s->relativeNote;
+
+ dst->nameLength = (uint8_t)strlen(s->name);
+ if (dst->nameLength > 22)
+ dst->nameLength = 22;
+
+ memset(dst->name, 0, 22);
+ if (dst->nameLength > 0)
+ memcpy(dst->name, s->name, dst->nameLength);
+
+ if (s->dataPtr == NULL)
+ dst->length = 0;
}
- size_t result = fwrite(&ih, INSTR_XI_HEADER_SIZE + (ih.antSamp * sizeof (sampleHeaderTyp)), 1, f);
+ size_t result = fwrite(&ih, INSTR_XI_HEADER_SIZE + (ih.numSamples * sizeof (xmSmpHdr_t)), 1, f);
if (result != 1)
{
fclose(f);
@@ -2960,20 +3017,20 @@
}
pauseAudio();
- s = instr[saveInstrNr]->samp;
- for (int32_t i = 0; i < n; i++, s++)
+ s = instr[saveInstrNum]->smp;
+ for (int32_t i = 0; i < numSamples; i++, s++)
{
- if (s->pek != NULL && s->len > 0)
+ if (s->dataPtr != NULL && s->length > 0)
{
- restoreSample(s);
- samp2Delta(s->pek, s->len, s->typ);
+ unfixSample(s);
+ samp2Delta(s->dataPtr, s->length, s->flags);
- result = fwrite(s->pek, 1, s->len, f);
+ result = fwrite(s->dataPtr, 1, SAMPLE_LENGTH_BYTES(s), f);
- delta2Samp(s->pek, s->len, s->typ);
+ delta2Samp(s->dataPtr, s->length, s->flags);
fixSample(s);
- if (result != (size_t)s->len) // write not OK
+ if (result != (size_t)SAMPLE_LENGTH_BYTES(s)) // write not OK
{
resumeAudio();
fclose(f);
@@ -2987,19 +3044,19 @@
fclose(f);
editor.diskOpReadDir = true; // force diskop re-read
-
setMouseBusy(false);
+
return true;
(void)ptr;
}
-void saveInstr(UNICHAR *filenameU, int16_t nr)
+void saveInstr(UNICHAR *filenameU, int16_t insNum)
{
- if (nr == 0)
+ if (insNum == 0)
return;
- saveInstrNr = nr;
+ saveInstrNum = insNum;
UNICHAR_STRCPY(editor.tmpFilenameU, filenameU);
mouseAnimOn();
@@ -3015,8 +3072,8 @@
static int16_t getPATNote(int32_t freq)
{
- const double dNote = (log2(freq * (1.0 / 440000.0)) * 12.0) + 57.0;
- const int32_t note = (const int32_t)(dNote + 0.5);
+ const double dNote = (log2(freq / 440000.0) * 12.0) + 57.0;
+ const int32_t note = (const int32_t)(dNote + 0.5); // rounded
return (int16_t)note;
}
@@ -3023,17 +3080,17 @@
static int32_t SDLCALL loadInstrThread(void *ptr)
{
- int8_t *newPtr;
int16_t a, b;
- int32_t i, j;
- instrXIHeaderTyp ih;
- instrPATHeaderTyp ih_PAT;
- instrPATWaveHeaderTyp ih_PATWave;
- sampleHeaderTyp *src;
- sampleTyp *s;
- instrTyp *ins;
+ int32_t i, j, numLoadedSamples;
+ xiHdr_t xi_h;
+ patHdr_t pat_h;
+ patWaveHdr_t patWave_h;
+ xmSmpHdr_t *src;
+ sample_t *s;
+ instr_t *ins;
bool stereoWarning = false;
+ numLoadedSamples = 0;
if (editor.tmpInstrFilenameU == NULL)
{
@@ -3048,29 +3105,34 @@
return false;
}
- memset(&ih, 0, sizeof (ih));
+ memset(&xi_h, 0, sizeof (xi_h));
+ memset(&pat_h, 0, sizeof (pat_h));
+ memset(&patWave_h, 0, sizeof (patWave_h));
- fread(&ih, INSTR_XI_HEADER_SIZE, 1, f);
- if (!strncmp(ih.sig, "Extended Instrument: ", 21))
+ fread(&xi_h, INSTR_XI_HEADER_SIZE, 1, f);
+ if (!strncmp(xi_h.ID, "Extended Instrument: ", 21))
{
// XI - Extended Instrument
- if (ih.ver != 0x0101 && ih.ver != 0x0102)
+ if (xi_h.version != 0x0101 && xi_h.version != 0x0102)
{
okBoxThreadSafe(0, "System message", "Incompatible format version!");
goto loadDone;
}
- if (ih.ver == 0x0101) // not even FT2.01 can save old v1.01 .XI files, so I have no way to verify this.
+ // not even FT2.01 can save old v1.01 .XI files, so I have no way to verify this
+ if (xi_h.version == 0x0101)
{
fseek(f, -20, SEEK_CUR);
- ih.antSamp = ih.midiProgram;
- ih.midiProgram = 0;
- ih.midiBend = 0;
- ih.mute = false;
+ xi_h.numSamples = xi_h.midiProgram;
+ xi_h.midiProgram = 0;
+ xi_h.midiBend = 0;
+ xi_h.mute = false;
}
- memcpy(song.instrName[editor.curInstr], ih.name, 22);
+ numLoadedSamples = xi_h.numSamples;
+
+ memcpy(song.instrName[editor.curInstr], xi_h.name, 22);
song.instrName[editor.curInstr][22] = '\0';
pauseAudio();
@@ -3077,7 +3139,7 @@
freeInstr(editor.curInstr);
- if (ih.antSamp > 0)
+ if (xi_h.numSamples > 0)
{
if (!allocateInstr(editor.curInstr))
{
@@ -3089,69 +3151,36 @@
// copy instrument header elements to our instrument struct
ins = instr[editor.curInstr];
- memcpy(ins->ta, ih.ta, 96);
- memcpy(ins->envVP, ih.envVP, 12*2*sizeof(int16_t));
- memcpy(ins->envPP, ih.envPP, 12*2*sizeof(int16_t));
- ins->envVPAnt = ih.envVPAnt;
- ins->envPPAnt = ih.envPPAnt;
- ins->envVSust = ih.envVSust;
- ins->envVRepS = ih.envVRepS;
- ins->envVRepE = ih.envVRepE;
- ins->envPSust = ih.envPSust;
- ins->envPRepS = ih.envPRepS;
- ins->envPRepE = ih.envPRepE;
- ins->envVTyp = ih.envVTyp;
- ins->envPTyp = ih.envPTyp;
- ins->vibTyp = ih.vibTyp;
- ins->vibSweep = ih.vibSweep;
- ins->vibDepth = ih.vibDepth;
- ins->vibRate = ih.vibRate;
- ins->fadeOut = ih.fadeOut;
- ins->midiOn = (ih.midiOn == 1) ? true : false;
- ins->midiChannel = ih.midiChannel;
- ins->midiProgram = ih.midiProgram;
- ins->midiBend = ih.midiBend;
- ins->mute = (ih.mute == 1) ? true : false; // correct logic! Don't mess with this
- ins->antSamp = ih.antSamp; // used in loadInstrSample()
+ memcpy(ins->note2SampleLUT, xi_h.note2SampleLUT, 96);
+ memcpy(ins->volEnvPoints, xi_h.volEnvPoints, 12*2*sizeof(int16_t));
+ memcpy(ins->panEnvPoints, xi_h.panEnvPoints, 12*2*sizeof(int16_t));
+ ins->volEnvLength = xi_h.volEnvLength;
+ ins->panEnvLength = xi_h.panEnvLength;
+ ins->volEnvSustain = xi_h.volEnvSustain;
+ ins->volEnvLoopStart = xi_h.volEnvLoopStart;
+ ins->volEnvLoopEnd = xi_h.volEnvLoopEnd;
+ ins->panEnvSustain = xi_h.panEnvSustain;
+ ins->panEnvLoopStart = xi_h.panEnvLoopStart;
+ ins->panEnvLoopEnd = xi_h.panEnvLoopEnd;
+ ins->volEnvFlags = xi_h.volEnvFlags;
+ ins->panEnvFlags = xi_h.panEnvFlags;
+ ins->vibType = xi_h.vibType;
+ ins->vibSweep = xi_h.vibSweep;
+ ins->vibDepth = xi_h.vibDepth;
+ ins->vibRate = xi_h.vibRate;
+ ins->fadeout = xi_h.fadeout;
+ ins->midiOn = (xi_h.midiOn == 1) ? true : false;
+ ins->midiChannel = xi_h.midiChannel;
+ ins->midiProgram = xi_h.midiProgram;
+ ins->midiBend = xi_h.midiBend;
+ ins->mute = (xi_h.mute == 1) ? true : false; // correct logic! Don't mess with this
+ ins->numSamples = xi_h.numSamples; // used in loadInstrSample()
- // sanitize stuff for broken/unsupported instruments
- ins->midiProgram = CLAMP(ins->midiProgram, 0, 127);
- ins->midiBend = CLAMP(ins->midiBend, 0, 36);
-
- if (ins->midiChannel > 15) ins->midiChannel = 15;
- if (ins->vibDepth > 0x0F) ins->vibDepth = 0x0F;
- if (ins->vibRate > 0x3F) ins->vibRate = 0x3F;
- if (ins->vibTyp > 3) ins->vibTyp = 0;
-
- for (i = 0; i < 96; i++)
- {
- if (ins->ta[i] >= MAX_SMP_PER_INST)
- ins->ta[i] = MAX_SMP_PER_INST-1;
- }
-
- if (ins->envVPAnt > 12) ins->envVPAnt = 12;
- if (ins->envVRepS > 11) ins->envVRepS = 11;
- if (ins->envVRepE > 11) ins->envVRepE = 11;
- if (ins->envVSust > 11) ins->envVSust = 11;
- if (ins->envPPAnt > 12) ins->envPPAnt = 12;
- if (ins->envPRepS > 11) ins->envPRepS = 11;
- if (ins->envPRepE > 11) ins->envPRepE = 11;
- if (ins->envPSust > 11) ins->envPSust = 11;
-
- for (i = 0; i < 12; i++)
- {
- if ((uint16_t)ins->envVP[i][0] > 32767) ins->envVP[i][0] = 32767;
- if ((uint16_t)ins->envPP[i][0] > 32767) ins->envPP[i][0] = 32767;
- if ((uint16_t)ins->envVP[i][1] > 64) ins->envVP[i][1] = 64;
- if ((uint16_t)ins->envPP[i][1] > 63) ins->envPP[i][1] = 63;
-
- }
-
- int32_t sampleHeadersToRead = ih.antSamp;
+ int32_t sampleHeadersToRead = xi_h.numSamples;
if (sampleHeadersToRead > MAX_SMP_PER_INST)
sampleHeadersToRead = MAX_SMP_PER_INST;
- if (fread(ih.samp, sampleHeadersToRead * sizeof (sampleHeaderTyp), 1, f) != 1)
+ if (fread(xi_h.smp, sampleHeadersToRead * sizeof (xmSmpHdr_t), 1, f) != 1)
{
freeInstr(editor.curInstr);
resumeAudio();
@@ -3159,63 +3188,63 @@
goto loadDone;
}
- if (ih.antSamp > MAX_SMP_PER_INST)
+ if (xi_h.numSamples > MAX_SMP_PER_INST)
{
- const int32_t sampleHeadersToSkip = ih.antSamp - MAX_SMP_PER_INST;
- fseek(f, sampleHeadersToSkip * sizeof (sampleHeaderTyp), SEEK_CUR);
+ const int32_t sampleHeadersToSkip = xi_h.numSamples - MAX_SMP_PER_INST;
+ fseek(f, sampleHeadersToSkip * sizeof (xmSmpHdr_t), SEEK_CUR);
}
for (i = 0; i < sampleHeadersToRead; i++)
{
- s = &instr[editor.curInstr]->samp[i];
- src = &ih.samp[i];
+ s = &instr[editor.curInstr]->smp[i];
+ src = &xi_h.smp[i];
// copy sample header elements to our sample struct
- s->len = src->len;
- s->repS = src->repS;
- s->repL = src->repL;
- s->vol = src->vol;
- s->fine = src->fine;
- s->typ = src->typ;
- s->pan = src->pan;
- s->relTon = src->relTon;
+ s->length = src->length;
+ s->loopStart = src->loopStart;
+ s->loopLength = src->loopLength;
+ s->volume = src->volume;
+ s->finetune = src->finetune;
+ s->flags = src->flags;
+ s->panning = src->panning;
+ s->relativeNote = src->relativeNote;
memcpy(s->name, src->name, 22);
s->name[22] = '\0';
- // dst->pek is set up later
-
- // trim off spaces at end of name
- for (j = 21; j >= 0; j--)
- {
- if (s->name[j] == ' ' || s->name[j] == 0x1A)
- s->name[j] = '\0';
- else
- break;
- }
-
- // sanitize stuff broken/unsupported samples
- if (s->vol > 64)
- s->vol = 64;
-
- s->relTon = CLAMP(s->relTon, -48, 71);
+ // dst->dataPtr is set up later
}
}
- for (i = 0; i < ih.antSamp; i++)
+ for (i = 0; i < xi_h.numSamples; i++)
{
- s = &instr[editor.curInstr]->samp[i];
+ s = &instr[editor.curInstr]->smp[i];
- // if a sample has both forward loop and pingpong loop set, make it pingpong loop only (FT2 mixer behavior)
- if ((s->typ & 3) == 3)
- s->typ &= 0xFE;
-
- if (s->len > 0)
+ if (s->length <= 0)
{
- s->pek = NULL;
- s->origPek = (int8_t *)malloc(s->len + LOOP_FIX_LEN);
- if (s->origPek == NULL)
+ s->length = 0;
+ s->loopStart = 0;
+ s->loopLength = 0;
+ s->flags = 0;
+ }
+ else
+ {
+ const int32_t lengthInFile = s->length;
+ bool sample16Bit = !!(s->flags & SAMPLE_16BIT);
+ bool stereoSample = !!(s->flags & SAMPLE_STEREO);
+
+ if (sample16Bit) // we use units of samples (not bytes like in FT2)
{
+ s->length >>= 1;
+ s->loopStart >>= 1;
+ s->loopLength >>= 1;
+ }
+
+ if (s->length > MAX_SAMPLE_LEN)
+ s->length = MAX_SAMPLE_LEN;
+
+ if (!allocateSmpData(s, s->length, sample16Bit))
+ {
freeInstr(editor.curInstr);
resumeAudio();
okBoxThreadSafe(0, "System message", "Not enough memory!");
@@ -3222,9 +3251,8 @@
goto loadDone;
}
- s->pek = s->origPek + SMP_DAT_OFFSET;
-
- if (fread(s->pek, s->len, 1, f) != 1)
+ const int32_t sampleLengthInBytes = SAMPLE_LENGTH_BYTES(s);
+ if (fread(s->dataPtr, sampleLengthInBytes, 1, f) != 1)
{
freeInstr(editor.curInstr);
resumeAudio();
@@ -3232,29 +3260,23 @@
goto loadDone;
}
- delta2Samp(s->pek, s->len, s->typ); // stereo samples are handled here
+ if (sampleLengthInBytes < lengthInFile)
+ fseek(f, lengthInFile-sampleLengthInBytes, SEEK_CUR);
+ delta2Samp(s->dataPtr, s->length, s->flags); // stereo samples are handled here
+
// check if it was a stereo sample
- if (s->typ & 32)
+ if (stereoSample)
{
- s->typ &= ~32;
+ s->flags &= ~SAMPLE_STEREO;
- s->len >>= 1;
- s->repL >>= 1;
- s->repS >>= 1;
+ s->length >>= 1;
+ s->loopStart >>= 1;
+ s->loopLength >>= 1;
- newPtr = (int8_t *)realloc(s->origPek, s->len + LOOP_FIX_LEN);
- if (newPtr != NULL)
- {
- s->origPek = newPtr;
- s->pek = s->origPek + SMP_DAT_OFFSET;
- }
-
+ reallocateSmpData(s, s->length, sample16Bit);
stereoWarning = true;
}
-
- checkSampleRepeat(s);
- fixSample(s);
}
}
@@ -3264,20 +3286,22 @@
{
rewind(f);
- fread(&ih_PAT, 1, sizeof (instrPATHeaderTyp), f);
- if (!memcmp(ih_PAT.id, "GF1PATCH110\0ID#000002\0", 22))
+ fread(&pat_h, 1, sizeof (patHdr_t), f);
+ if (!memcmp(pat_h.ID, "GF1PATCH110\0ID#000002\0", 22))
{
- // PAT - Gravis Ultrasound GF1 patch
+ // PAT - Gravis Ultrasound patch
- if (ih_PAT.antSamp == 0)
- ih_PAT.antSamp = 1; // to some patch makers, 0 means 1
+ if (pat_h.numSamples == 0)
+ pat_h.numSamples = 1; // to some patch makers, 0 means 1
- if (ih_PAT.layers > 1 || ih_PAT.antSamp > MAX_SMP_PER_INST)
+ if (pat_h.layers > 1 || pat_h.numSamples > MAX_SMP_PER_INST)
{
okBoxThreadSafe(0, "System message", "Incompatible instrument!");
goto loadDone;
}
+ numLoadedSamples = pat_h.numSamples;
+
pauseAudio();
freeInstr(editor.curInstr);
@@ -3287,15 +3311,15 @@
goto loadDone;
}
- memset(song.instrName[editor.curInstr], 0, 22 + 1);
- memcpy(song.instrName[editor.curInstr], ih_PAT.instrName, 16);
+ memcpy(song.instrName[editor.curInstr], pat_h.instrName, 16);
+ song.instrName[editor.curInstr][16] = '\0';
- for (i = 0; i < ih_PAT.antSamp; i++)
+ for (i = 0; i < pat_h.numSamples; i++)
{
- s = &instr[editor.curInstr]->samp[i];
+ s = &instr[editor.curInstr]->smp[i];
ins = instr[editor.curInstr];
- if (fread(&ih_PATWave, 1, sizeof (ih_PATWave), f) != sizeof (ih_PATWave))
+ if (fread(&patWave_h, 1, sizeof (patWave_h), f) != sizeof (patWave_h))
{
freeInstr(editor.curInstr);
resumeAudio();
@@ -3303,10 +3327,22 @@
goto loadDone;
}
- s->pek = NULL;
- s->origPek = (int8_t *)malloc(ih_PATWave.waveSize + LOOP_FIX_LEN);
- if (s->origPek == NULL)
+ const int32_t lengthInFile = patWave_h.sampleLength;
+
+ bool sample16Bit = !!(patWave_h.flags & 1);
+
+ s->length = lengthInFile;
+ if (sample16Bit)
{
+ s->flags |= SAMPLE_16BIT;
+ s->length >>= 1;
+ }
+
+ if (s->length > MAX_SAMPLE_LEN)
+ s->length = MAX_SAMPLE_LEN;
+
+ if (!allocateSmpData(s, s->length, sample16Bit))
+ {
freeInstr(editor.curInstr);
resumeAudio();
okBoxThreadSafe(0, "System message", "Not enough memory!");
@@ -3313,75 +3349,54 @@
goto loadDone;
}
- s->pek = s->origPek + SMP_DAT_OFFSET;
-
if (i == 0)
{
- ins->vibSweep = ih_PATWave.vibSweep;
-
- ins->vibRate = (ih_PATWave.vibRate + 2) >> 2;
- if (ins->vibRate > 0x3F)
- ins->vibRate = 0x3F;
-
- ins->vibDepth = (ih_PATWave.vibDepth + 1) >> 1;
- if (ins->vibDepth > 0x0F)
- ins->vibDepth = 0x0F;
+ ins->vibSweep = patWave_h.vibSweep;
+ ins->vibRate = (patWave_h.vibRate + 2) >> 2; // rounded
+ ins->vibDepth = (patWave_h.vibDepth + 1) >> 1; // rounded
}
- s = &instr[editor.curInstr]->samp[i];
+ s = &instr[editor.curInstr]->smp[i];
- memcpy(s->name, ih_PATWave.name, 7);
+ memcpy(s->name, patWave_h.name, 7);
+ s->name[7] = '\0';
- s->typ = (ih_PATWave.mode & 1) << 4; // 16-bit flag
- if (ih_PATWave.mode & 4) // loop enabled?
+ if (patWave_h.flags & 4) // loop enabled?
{
- if (ih_PATWave.mode & 8)
- s->typ |= 2; // pingpong loop
+ if (patWave_h.flags & 8)
+ s->flags |= LOOP_BIDI;
else
- s->typ |= 1; // forward loop
+ s->flags |= LOOP_FWD;
}
- s->pan = ((ih_PATWave.pan << 4) & 0xF0) | (ih_PATWave.pan & 0xF);
+ s->panning = ((patWave_h.panning << 4) & 0xF0) | (patWave_h.panning & 0xF);
+ s->loopStart = patWave_h.loopStart;
+ s->loopLength = patWave_h.loopEnd - patWave_h.loopStart;
- if (s->typ & 16)
+ if (sample16Bit)
{
- ih_PATWave.waveSize &= 0xFFFFFFFE;
- ih_PATWave.repS &= 0xFFFFFFFE;
- ih_PATWave.repE &= 0xFFFFFFFE;
+ s->loopStart >>= 1;
+ s->loopLength >>= 1;
}
- s->len = ih_PATWave.waveSize;
- if (s->len > MAX_SAMPLE_LEN)
- s->len = MAX_SAMPLE_LEN;
+ const double dFreq = (1.0 + (patWave_h.finetune / 512.0)) * patWave_h.sampleRate;
+ tuneSample(s, (int32_t)(dFreq + 0.5), audio.linearPeriodsFlag);
- s->repS = ih_PATWave.repS;
- if (s->repS > s->len)
- s->repS = 0;
+ a = getPATNote(patWave_h.rootFrq) - (12 * 3);
+ s->relativeNote -= (uint8_t)a;
- s->repL = ih_PATWave.repE - ih_PATWave.repS;
- if (s->repL < 0)
- s->repL = 0;
+ a = getPATNote(patWave_h.lowFrq);
+ b = getPATNote(patWave_h.highFreq);
- if (s->repS+s->repL > s->len)
- s->repL = s->len - s->repS;
-
- const double dFreq = (1.0 + (ih_PATWave.fineTune / 512.0)) * ih_PATWave.sampleRate;
- int32_t freq = (const int32_t)(dFreq + 0.5);
- tuneSample(s, freq, audio.linearPeriodsFlag);
-
- a = s->relTon - (getPATNote(ih_PATWave.rootFrq) - (12 * 3));
- s->relTon = (uint8_t)CLAMP(a, -48, 71);
-
- a = getPATNote(ih_PATWave.lowFrq);
- b = getPATNote(ih_PATWave.highFreq);
-
a = CLAMP(a, 0, 95);
b = CLAMP(b, 0, 95);
for (j = a; j <= b; j++)
- ins->ta[j] = (uint8_t)i;
+ ins->note2SampleLUT[j] = (uint8_t)i;
- if (fread(s->pek, ih_PATWave.waveSize, 1, f) != 1)
+ const int32_t sampleLengthInBytes = SAMPLE_LENGTH_BYTES(s);
+ size_t bytesRead = fread(s->dataPtr, sampleLengthInBytes, 1, f);
+ if (bytesRead != 1)
{
freeInstr(editor.curInstr);
resumeAudio();
@@ -3389,15 +3404,16 @@
goto loadDone;
}
- if (ih_PATWave.mode & 2)
+ if (sampleLengthInBytes < lengthInFile)
+ fseek(f, lengthInFile-sampleLengthInBytes, SEEK_CUR);
+
+ if (patWave_h.flags & 2) // unsigned samples?
{
- if (s->typ & 16)
- conv16BitSample(s->pek, s->len, false);
+ if (sample16Bit)
+ conv16BitSample(s->dataPtr, s->length, false);
else
- conv8BitSample(s->pek, s->len, false);
+ conv8BitSample(s->dataPtr, s->length, false);
}
-
- fixSample(s);
}
resumeAudio();
@@ -3407,10 +3423,26 @@
loadDone:
fclose(f);
- fixInstrAndSampleNames(editor.curInstr);
+ numLoadedSamples = CLAMP(numLoadedSamples, 1, MAX_SMP_PER_INST);
+
+ ins = instr[editor.curInstr];
+ if (ins != NULL)
+ {
+ sanitizeInstrument(ins);
+ for (i = 0; i < numLoadedSamples; i++)
+ {
+ s = &ins->smp[i];
+ sanitizeSample(s);
+
+ if (s->dataPtr != NULL)
+ fixSample(s);
+ }
+
+ fixInstrAndSampleNames(editor.curInstr);
+ }
editor.updateCurInstr = true; // setMouseBusy(false) is called in the input/video thread when done
- if (ih.antSamp > MAX_SMP_PER_INST)
+ if (numLoadedSamples > MAX_SMP_PER_INST)
okBoxThreadSafe(0, "System message", "Warning: The instrument contained >16 samples. The extra samples were discarded!");
if (stereoWarning)
@@ -3417,7 +3449,6 @@
okBoxThreadSafe(0, "System message", "Warning: The instrument contained stereo sample(s). They were mixed to mono!");
return true;
-
(void)ptr;
}
--- a/src/ft2_inst_ed.h
+++ b/src/ft2_inst_ed.h
@@ -7,10 +7,9 @@
#include "ft2_unicode.h"
void drawC4Rate(void);
-
+void sanitizeInstrument(instr_t *ins);
bool fileIsInstr(UNICHAR *filenameU);
-
-void saveInstr(UNICHAR *filenameU, int16_t nr);
+void saveInstr(UNICHAR *filenameU, int16_t insNum);
void loadInstr(UNICHAR *filenameU);
void copyInstr(void); // dstInstr = srcInstr
void xchgInstr(void); // dstInstr <-> srcInstr
@@ -43,10 +42,10 @@
void panPreDef4(void);
void panPreDef5(void);
void panPreDef6(void);
-void relToneOctUp(void);
-void relToneOctDown(void);
-void relToneUp(void);
-void relToneDown(void);
+void relativeNoteOctUp(void);
+void relativeNoteOctDown(void);
+void relativeNoteUp(void);
+void relativeNoteDown(void);
void volEnvAdd(void);
void volEnvDel(void);
void volEnvSusUp(void);
--- a/src/ft2_keyboard.c
+++ b/src/ft2_keyboard.c
@@ -4,6 +4,8 @@
#endif
#include <stdint.h>
+#include <stdbool.h>
+#include <string.h>
#include "ft2_header.h"
#include "ft2_keyboard.h"
#include "ft2_gui.h"
@@ -43,7 +45,7 @@
int8_t scancodeKeyToNote(SDL_Scancode scancode)
{
if (scancode == SDL_SCANCODE_CAPSLOCK || scancode == SDL_SCANCODE_NONUSBACKSLASH)
- return 97; // key off
+ return NOTE_OFF;
// translate key to note
int8_t note = 0;
@@ -161,7 +163,7 @@
static void handleKeys(SDL_Keycode keycode, SDL_Scancode scanKey)
{
// if we're holding numpad plus but not pressing bank keys, don't check any other key
- if (keyb.numPadPlusPressed)
+ if (keyb.numPadPlusPressed && !keyb.leftCtrlPressed)
{
if (scanKey != SDL_SCANCODE_NUMLOCKCLEAR && scanKey != SDL_SCANCODE_KP_DIVIDE &&
scanKey != SDL_SCANCODE_KP_MULTIPLY && scanKey != SDL_SCANCODE_KP_MINUS)
@@ -234,23 +236,53 @@
case SDL_SCANCODE_KP_MINUS:
{
- if (keyb.numPadPlusPressed)
+ if (keyb.leftCtrlPressed) // non-FT2 feature: Decrease master volume by 16
{
- if (editor.instrBankSwapped)
- pbSetInstrBank16();
+ if (config.masterVol >= 16)
+ config.masterVol -= 16;
else
- pbSetInstrBank8();
+ config.masterVol = 0;
+
+ setAudioAmp(config.boostLevel, config.masterVol, !!(config.specialFlags & BITDEPTH_32));
+ if (ui.configScreenShown && editor.currConfigScreen == CONFIG_SCREEN_IO_DEVICES)
+ showConfigScreen();
}
else
{
- if (editor.instrBankSwapped)
- pbSetInstrBank12();
+ if (keyb.numPadPlusPressed)
+ {
+ if (editor.instrBankSwapped)
+ pbSetInstrBank16();
+ else
+ pbSetInstrBank8();
+ }
else
- pbSetInstrBank4();
+ {
+ if (editor.instrBankSwapped)
+ pbSetInstrBank12();
+ else
+ pbSetInstrBank4();
+ }
}
}
return;
+ case SDL_SCANCODE_KP_PLUS:
+ {
+ if (keyb.leftCtrlPressed) // non-FT2 feature: Increase master volume by 16
+ {
+ if (config.masterVol <= 256-16)
+ config.masterVol += 16;
+ else
+ config.masterVol = 256;
+
+ setAudioAmp(config.boostLevel, config.masterVol, !!(config.specialFlags & BITDEPTH_32));
+ if (ui.configScreenShown && editor.currConfigScreen == CONFIG_SCREEN_IO_DEVICES)
+ showConfigScreen();
+ }
+ }
+ return;
+
case SDL_SCANCODE_KP_PERIOD:
{
if (editor.curInstr > 0)
@@ -267,6 +299,7 @@
if (okBox(1, "System request", "Clear instrument?") == 1)
{
freeInstr(editor.curInstr);
+ memset(song.instrName[editor.curInstr], 0, sizeof(song.instrName[editor.curInstr]));
updateNewInstrument();
setSongModifiedFlag();
}
@@ -290,18 +323,18 @@
if (keyb.leftShiftPressed)
{
// decrease edit skip
- if (editor.ID_Add == 0)
- editor.ID_Add = 16;
+ if (editor.editRowSkip == 0)
+ editor.editRowSkip = 16;
else
- editor.ID_Add--;
+ editor.editRowSkip--;
}
else
{
// increase edit skip
- if (editor.ID_Add == 16)
- editor.ID_Add = 0;
+ if (editor.editRowSkip == 16)
+ editor.editRowSkip = 0;
else
- editor.ID_Add++;
+ editor.editRowSkip++;
}
if (!ui.nibblesShown && !ui.configScreenShown &&
@@ -459,13 +492,13 @@
{
lockAudio();
- song.pattPos = editor.ptnJumpPos[0];
- if (song.pattPos >= song.pattLen)
- song.pattPos = song.pattLen - 1;
+ song.row = editor.ptnJumpPos[0];
+ if (song.row >= song.currNumRows)
+ song.row = song.currNumRows - 1;
if (!songPlaying)
{
- editor.pattPos = (uint8_t)song.pattPos;
+ editor.row = (uint8_t)song.row;
ui.updatePatternEditor = true;
}
@@ -477,13 +510,13 @@
{
lockAudio();
- song.pattPos = editor.ptnJumpPos[1];
- if (song.pattPos >= song.pattLen)
- song.pattPos = song.pattLen - 1;
+ song.row = editor.ptnJumpPos[1];
+ if (song.row >= song.currNumRows)
+ song.row = song.currNumRows - 1;
if (!songPlaying)
{
- editor.pattPos = (uint8_t)song.pattPos;
+ editor.row = (uint8_t)song.row;
ui.updatePatternEditor = true;
}
@@ -495,13 +528,13 @@
{
lockAudio();
- song.pattPos = editor.ptnJumpPos[2];
- if (song.pattPos >= song.pattLen)
- song.pattPos = song.pattLen - 1;
+ song.row = editor.ptnJumpPos[2];
+ if (song.row >= song.currNumRows)
+ song.row = song.currNumRows - 1;
if (!songPlaying)
{
- editor.pattPos = (uint8_t)song.pattPos;
+ editor.row = (uint8_t)song.row;
ui.updatePatternEditor = true;
}
@@ -513,13 +546,13 @@
{
lockAudio();
- song.pattPos = editor.ptnJumpPos[3];
- if (song.pattPos >= song.pattLen)
- song.pattPos = song.pattLen - 1;
+ song.row = editor.ptnJumpPos[3];
+ if (song.row >= song.currNumRows)
+ song.row = song.currNumRows - 1;
if (!songPlaying)
{
- editor.pattPos = (uint8_t)song.pattPos;
+ editor.row = (uint8_t)song.row;
ui.updatePatternEditor = true;
}
@@ -585,14 +618,14 @@
if (audioWasntLocked)
lockAudio();
- if (song.pattPos >= 16)
- song.pattPos -= 16;
+ if (song.row >= 16)
+ song.row -= 16;
else
- song.pattPos = 0;
+ song.row = 0;
if (!songPlaying)
{
- editor.pattPos = (uint8_t)song.pattPos;
+ editor.row = (uint8_t)song.row;
ui.updatePatternEditor = true;
}
@@ -607,14 +640,14 @@
if (audioWasntLocked)
lockAudio();
- if (song.pattPos < (song.pattLen - 16))
- song.pattPos += 16;
+ if (song.row < song.currNumRows-16)
+ song.row += 16;
else
- song.pattPos = song.pattLen - 1;
+ song.row = song.currNumRows-1;
if (!songPlaying)
{
- editor.pattPos = (uint8_t)song.pattPos;
+ editor.row = (uint8_t)song.row;
ui.updatePatternEditor = true;
}
@@ -629,10 +662,10 @@
if (audioWasntLocked)
lockAudio();
- song.pattPos = 0;
+ song.row = 0;
if (!songPlaying)
{
- editor.pattPos = (uint8_t)song.pattPos;
+ editor.row = (uint8_t)song.row;
ui.updatePatternEditor = true;
}
@@ -647,10 +680,10 @@
if (audioWasntLocked)
lockAudio();
- song.pattPos = pattLens[song.pattNr] - 1;
+ song.row = patternNumRows[song.pattNum] - 1;
if (!songPlaying)
{
- editor.pattPos = (uint8_t)song.pattPos;
+ editor.row = (uint8_t)song.row;
ui.updatePatternEditor = true;
}
@@ -693,7 +726,7 @@
}
else if (keyb.leftShiftPressed)
{
- editor.ptnJumpPos[0] = (uint8_t)editor.pattPos;
+ editor.ptnJumpPos[0] = (uint8_t)editor.row;
return true;
}
}
@@ -708,7 +741,7 @@
}
else if (keyb.leftShiftPressed)
{
- editor.ptnJumpPos[1] = (uint8_t)editor.pattPos;
+ editor.ptnJumpPos[1] = (uint8_t)editor.row;
return true;
}
}
@@ -723,7 +756,7 @@
}
else if (keyb.leftShiftPressed)
{
- editor.ptnJumpPos[2] = (uint8_t)editor.pattPos;
+ editor.ptnJumpPos[2] = (uint8_t)editor.row;
return true;
}
}
@@ -738,7 +771,7 @@
}
else if (keyb.leftShiftPressed)
{
- editor.ptnJumpPos[3] = (uint8_t)editor.pattPos;
+ editor.ptnJumpPos[3] = (uint8_t)editor.row;
return true;
}
}
@@ -793,7 +826,7 @@
pattMark.markX1 = cursor.ch;
pattMark.markX2 = pattMark.markX1;
pattMark.markY1 = 0;
- pattMark.markY2 = pattLens[editor.editPattern];
+ pattMark.markY2 = patternNumRows[editor.editPattern];
ui.updatePatternEditor = true;
}
--- a/src/ft2_main.c
+++ b/src/ft2_main.c
@@ -22,7 +22,7 @@
#include "ft2_config.h"
#include "ft2_sample_ed.h"
#include "ft2_diskop.h"
-#include "ft2_scopes.h"
+#include "scopes/ft2_scopes.h"
#include "ft2_about.h"
#include "ft2_pattern_ed.h"
#include "ft2_module_loader.h"
@@ -180,20 +180,23 @@
setupPerfFreq();
- if (!setupAudio(CONFIG_HIDE_ERRORS))
+ if (!setupAudio(CONFIG_HIDE_ERRORS)) // can we open the audio device?
{
- // one LAST attempt (with default audio device and settings)
- config.audioFreq = 48000;
-
- // try 48kHz 16-bit audio at 1024 samples
- config.specialFlags &= ~(BITDEPTH_32 + BUFFSIZE_512 + BUFFSIZE_2048);
- config.specialFlags |= (BITDEPTH_16 + BUFFSIZE_1024);
-
+ // nope, try with the default audio device
setToDefaultAudioOutputDevice();
- if (!setupAudio(CONFIG_SHOW_ERRORS))
+
+ if (!setupAudio(CONFIG_HIDE_ERRORS)) // does it work this time?
{
- cleanUpAndExit(); // still no go...
- return 1;
+ // nope, try safe values (44.1kHz 16-bit @ 1024 samples)
+ config.audioFreq = 44100;
+ config.specialFlags &= ~(BITDEPTH_32 + BUFFSIZE_512 + BUFFSIZE_2048);
+ config.specialFlags |= (BITDEPTH_16 + BUFFSIZE_1024);
+
+ if (!setupAudio(CONFIG_SHOW_ERRORS)) // this time it surely must work?!
+ {
+ cleanUpAndExit(); // well, nope!
+ return 1;
+ }
}
}
@@ -269,10 +272,10 @@
memset(&song, 0, sizeof (song));
// used for scopes and sampling position line (sampler screen)
- for (int32_t i = 0; i < MAX_VOICES; i++)
+ for (int32_t i = 0; i < MAX_CHANNELS; i++)
{
- lastChInstr[i].instrNr = 255;
- lastChInstr[i].sampleNr = 255;
+ lastChInstr[i].instrNum = 255;
+ lastChInstr[i].smpNum = 255;
}
// now set data that must be initialized to non-zero values...
@@ -289,7 +292,7 @@
mouse.lastUsedObjectID = OBJECT_ID_NONE;
- editor.ID_Add = 1;
+ editor.editRowSkip = 1;
editor.srcInstr = 1;
editor.curInstr = 1;
editor.curOctave = 4;
--- a/src/ft2_midi.c
+++ b/src/ft2_midi.c
@@ -68,10 +68,10 @@
if (recMIDIValidChn) // real FT2 forgot to check this here..
{
- for (uint8_t i = 0; i < song.antChn; i++)
+ for (uint8_t i = 0; i < song.numChannels; i++)
{
- if (stm[i].midiVibDepth != 0 || editor.keyOnTab[i] != 0)
- stm[i].midiVibDepth = midi.currMIDIVibDepth;
+ if (channel[i].midiVibDepth != 0 || editor.keyOnTab[i] != 0)
+ channel[i].midiVibDepth = midi.currMIDIVibDepth;
}
}
@@ -88,8 +88,8 @@
midi.currMIDIPitch = pitch;
if (recMIDIValidChn)
{
- stmTyp *ch = stm;
- for (uint8_t i = 0; i < song.antChn; i++, ch++)
+ channel_t *ch = channel;
+ for (uint8_t i = 0; i < song.numChannels; i++, ch++)
{
if (ch->midiPitch != 0 || editor.keyOnTab[i] != 0)
ch->midiPitch = midi.currMIDIPitch;
@@ -214,27 +214,26 @@
return true;
}
-void recordMIDIEffect(uint8_t effTyp, uint8_t effData)
+void recordMIDIEffect(uint8_t efx, uint8_t efxData)
{
// only handle this in record mode
if (!midi.enable || (playMode != PLAYMODE_RECSONG && playMode != PLAYMODE_RECPATT))
return;
- const int16_t nr = editor.editPattern;
if (config.multiRec)
{
- tonTyp *note = &patt[nr][editor.pattPos * MAX_VOICES];
- for (int32_t i = 0; i < song.antChn; i++, note++)
+ note_t *p = &pattern[editor.editPattern][editor.row * MAX_CHANNELS];
+ for (int32_t i = 0; i < song.numChannels; i++, p++)
{
if (config.multiRecChn[i] && editor.chnMode[i])
{
- if (!allocatePattern(nr))
+ if (!allocatePattern(editor.editPattern))
return;
- if (note->effTyp == 0)
+ if (p->efx == 0)
{
- note->effTyp = effTyp;
- note->eff = effData;
+ p->efx = efx;
+ p->efxData = efxData;
setSongModifiedFlag();
}
}
@@ -242,15 +241,15 @@
}
else
{
- if (!allocatePattern(nr))
+ if (!allocatePattern(editor.editPattern))
return;
- tonTyp *note = &patt[nr][(editor.pattPos * MAX_VOICES) + cursor.ch];
- if (note->effTyp != effTyp || note->eff != effData)
+ note_t *p = &pattern[editor.editPattern][(editor.row * MAX_CHANNELS) + cursor.ch];
+ if (p->efx != efx || p->efxData != efxData)
setSongModifiedFlag();
- note->effTyp = effTyp;
- note->eff = effData;
+ p->efx = efx;
+ p->efxData = efxData;
}
}
--- a/src/ft2_midi.h
+++ b/src/ft2_midi.h
@@ -25,7 +25,7 @@
void freeMidiIn(void);
bool initMidiIn(void);
bool openMidiInDevice(uint32_t deviceID);
-void recordMIDIEffect(uint8_t effTyp, uint8_t effData);
+void recordMIDIEffect(uint8_t efx, uint8_t efxData);
bool saveMidiInputDeviceToConfig(void);
bool setMidiInputDeviceFromConfig(void);
void freeMidiInputDeviceList(void);
--- a/src/ft2_module_loader.c
+++ b/src/ft2_module_loader.c
@@ -10,7 +10,7 @@
#include <unistd.h>
#endif
#include "ft2_header.h"
-#include "ft2_scopes.h"
+#include "scopes/ft2_scopes.h"
#include "ft2_trim.h"
#include "ft2_inst_ed.h"
#include "ft2_sample_ed.h"
@@ -56,10 +56,10 @@
// globals for module loaders
volatile bool tmpLinearPeriodsFlag;
-int16_t pattLensTmp[MAX_PATTERNS];
-tonTyp *pattTmp[MAX_PATTERNS];
-instrTyp *instrTmp[1+256];
-songTyp songTmp;
+int16_t patternNumRowsTmp[MAX_PATTERNS];
+note_t *patternTmp[MAX_PATTERNS];
+instr_t *instrTmp[1+256];
+song_t songTmp;
// --------------------------
static volatile bool musicIsLoading, moduleLoaded, moduleFailedToLoad;
@@ -214,12 +214,12 @@
static void clearTmpModule(void)
{
- memset(pattTmp, 0, sizeof (pattTmp));
+ memset(patternTmp, 0, sizeof (patternTmp));
memset(instrTmp, 0, sizeof (instrTmp));
memset(&songTmp, 0, sizeof (songTmp));
for (uint32_t i = 0; i < MAX_PATTERNS; i++)
- pattLensTmp[i] = 64;
+ patternNumRowsTmp[i] = 64;
}
static int32_t SDLCALL loadMusicThread(void *ptr)
@@ -277,33 +277,33 @@
return false;
}
-bool allocateTmpPatt(int32_t nr, uint16_t rows)
+bool allocateTmpPatt(int32_t pattNum, uint16_t numRows)
{
- pattTmp[nr] = (tonTyp *)calloc((MAX_PATT_LEN * TRACK_WIDTH) + 16, 1);
- if (pattTmp[nr] == NULL)
+ patternTmp[pattNum] = (note_t *)calloc((MAX_PATT_LEN * TRACK_WIDTH) + 16, 1);
+ if (patternTmp[pattNum] == NULL)
return false;
- pattLensTmp[nr] = rows;
+ patternNumRowsTmp[pattNum] = numRows;
return true;
}
-bool allocateTmpInstr(int16_t nr)
+bool allocateTmpInstr(int16_t insNum)
{
- if (instrTmp[nr] != NULL)
+ if (instrTmp[insNum] != NULL)
return false; // already allocated
- instrTyp *p = (instrTyp *)calloc(1, sizeof (instrTyp));
- if (p == NULL)
+ instr_t *ins = (instr_t *)calloc(1, sizeof (instr_t));
+ if (ins == NULL)
return false;
- sampleTyp *s = p->samp;
+ sample_t *s = ins->smp;
for (int32_t i = 0; i < MAX_SMP_PER_INST; i++, s++)
{
- s->pan = 128;
- s->vol = 64;
+ s->panning = 128;
+ s->volume = 64;
}
- instrTmp[nr] = p;
+ instrTmp[insNum] = ins;
return true;
}
@@ -312,10 +312,10 @@
// free all patterns
for (int32_t i = 0; i < MAX_PATTERNS; i++)
{
- if (pattTmp[i] != NULL)
+ if (patternTmp[i] != NULL)
{
- free(pattTmp[i]);
- pattTmp[i] = NULL;
+ free(patternTmp[i]);
+ patternTmp[i] = NULL;
}
}
@@ -325,12 +325,9 @@
if (instrTmp[i] == NULL)
continue;
- sampleTyp *s = instrTmp[i]->samp;
+ sample_t *s = instrTmp[i]->smp;
for (int32_t j = 0; j < MAX_SMP_PER_INST; j++, s++)
- {
- if (s->origPek != NULL)
- free(s->origPek);
- }
+ freeSmpData(s);
free(instrTmp[i]);
instrTmp[i] = NULL;
@@ -337,13 +334,13 @@
}
}
-bool tmpPatternEmpty(uint16_t nr)
+bool tmpPatternEmpty(uint16_t pattNum)
{
- if (pattTmp[nr] == NULL)
+ if (patternTmp[pattNum] == NULL)
return true;
- uint8_t *scanPtr = (uint8_t *)pattTmp[nr];
- const uint32_t scanLen = pattLensTmp[nr] * TRACK_WIDTH;
+ uint8_t *scanPtr = (uint8_t *)patternTmp[pattNum];
+ const uint32_t scanLen = patternNumRowsTmp[pattNum] * TRACK_WIDTH;
for (uint32_t i = 0; i < scanLen; i++)
{
@@ -354,16 +351,16 @@
return true;
}
-void clearUnusedChannels(tonTyp *p, int16_t pattLen, int32_t antChn)
+void clearUnusedChannels(note_t *pattPtr, int16_t numRows, int32_t numChannels)
{
- if (p == NULL || antChn >= MAX_VOICES)
+ if (pattPtr == NULL || numChannels >= MAX_CHANNELS)
return;
- const int32_t width = sizeof (tonTyp) * (MAX_VOICES - antChn);
+ const int32_t width = sizeof (note_t) * (MAX_CHANNELS - numChannels);
- tonTyp *ptr = &p[antChn];
- for (int32_t i = 0; i < pattLen; i++, ptr += MAX_VOICES)
- memset(ptr, 0, width);
+ note_t *p = &pattPtr[numChannels];
+ for (int32_t i = 0; i < numRows; i++, p += MAX_CHANNELS)
+ memset(p, 0, width);
}
// called from input/video thread after the module was done loading
@@ -388,12 +385,12 @@
// copy over new pattern pointers and lengths
for (int32_t i = 0; i < MAX_PATTERNS; i++)
{
- patt[i] = pattTmp[i];
- pattLens[i] = pattLensTmp[i];
+ pattern[i] = patternTmp[i];
+ patternNumRows[i] = patternNumRowsTmp[i];
}
// copy over song struct
- memcpy(&song, &songTmp, sizeof (songTyp));
+ memcpy(&song, &songTmp, sizeof (song_t));
fixSongName();
// copy over new instruments (includes sample pointers)
@@ -404,12 +401,13 @@
if (instr[i] != NULL)
{
+ sanitizeInstrument(instr[i]);
for (int32_t j = 0; j < MAX_SMP_PER_INST; j++)
{
- sampleTyp *s = &instr[i]->samp[j];
+ sample_t *s = &instr[i]->smp[j];
- checkSampleRepeat(s);
- if (s->pek != NULL)
+ sanitizeSample(s);
+ if (s->dataPtr != NULL)
fixSample(s); // prepare sample for branchless linear interpolation
}
}
@@ -417,69 +415,67 @@
// we are the owners of the allocated memory ptrs set by the loader thread now
- if (song.antChn == 0)
- song.antChn = 2;
-
// support non-even channel numbers
- if (song.antChn & 1)
+ if (song.numChannels & 1)
{
- song.antChn++;
- if (song.antChn > MAX_VOICES)
- song.antChn = MAX_VOICES;
+ song.numChannels++;
+ if (song.numChannels > MAX_CHANNELS)
+ song.numChannels = MAX_CHANNELS;
}
- if (song.len == 0)
- song.len = 1;
+ song.numChannels = CLAMP(song.numChannels, 2, MAX_CHANNELS);
+ song.songLength = CLAMP(song.songLength, 1, MAX_ORDERS);
+ song.BPM = CLAMP(song.BPM, MIN_BPM, MAX_BPM);
+ song.initialSpeed = song.speed = CLAMP(song.speed, 1, MAX_SPEED);
- if (song.repS >= song.len)
- song.repS = 0;
+ if (song.songLoopStart >= song.songLength)
+ song.songLoopStart = 0;
- song.globVol = 64;
+ song.globalVolume = 64;
// remove overflown stuff in pattern data (FT2 doesn't do this)
for (int32_t i = 0; i < MAX_PATTERNS; i++)
{
- if (pattLens[i] <= 0)
- pattLens[i] = 64;
+ if (patternNumRows[i] <= 0)
+ patternNumRows[i] = 64;
- if (pattLens[i] > MAX_PATT_LEN)
- pattLens[i] = MAX_PATT_LEN;
+ if (patternNumRows[i] > MAX_PATT_LEN)
+ patternNumRows[i] = MAX_PATT_LEN;
- tonTyp *p = patt[i];
- if (p == NULL)
+ if (pattern[i] == NULL)
continue;
- tonTyp *note = p;
- for (int32_t j = 0; j < MAX_PATT_LEN * MAX_VOICES; j++, note++)
+ note_t *p = pattern[i];
+ for (int32_t j = 0; j < MAX_PATT_LEN * MAX_CHANNELS; j++, p++)
{
- if (note->ton > 97)
- note->ton = 0;
+ if (p->note > 97)
+ p->note = 0;
- if (note->instr > 128)
- note->instr = 0;
+ if (p->instr > 128)
+ p->instr = 0;
- if (note->effTyp > 35)
+ if (p->efx > 35)
{
- note->effTyp = 0;
- note->eff = 0;
+ p->efx = 0;
+ p->efxData = 0;
}
}
}
- setScrollBarEnd(SB_POS_ED, (song.len - 1) + 5);
+ setScrollBarEnd(SB_POS_ED, (song.songLength - 1) + 5);
setScrollBarPos(SB_POS_ED, 0, false);
resetChannels();
setPos(0, 0, true);
- P_SetSpeed(song.speed);
+ setMixerBPM(song.BPM);
editor.tmpPattern = editor.editPattern; // set kludge variable
+ editor.BPM = song.BPM;
editor.speed = song.speed;
- editor.tempo = song.tempo;
- editor.timer = song.timer;
- editor.globalVol = song.globVol;
+ editor.tick = song.tick;
+ editor.globalVolume = song.globalVolume;
- setFrqTab(tmpLinearPeriodsFlag);
+ setFrequencyTable(tmpLinearPeriodsFlag);
unlockMixerCallback();
@@ -687,6 +683,8 @@
return;
}
}
+
+ exitTextEditing();
// pass UTF8 to these tests so that we can test file ending in ASCII/ANSI
--- a/src/ft2_module_loader.h
+++ b/src/ft2_module_loader.h
@@ -5,10 +5,10 @@
#include "ft2_header.h"
#include "ft2_unicode.h"
-bool tmpPatternEmpty(uint16_t nr);
-void clearUnusedChannels(tonTyp *p, int16_t pattLen, int32_t antChn);
-bool allocateTmpInstr(int16_t nr);
-bool allocateTmpPatt(int32_t nr, uint16_t rows);
+bool tmpPatternEmpty(uint16_t pattNum);
+void clearUnusedChannels(note_t *p, int16_t numRows, int32_t numChannels);
+bool allocateTmpInstr(int16_t insNum);
+bool allocateTmpPatt(int32_t pattNum, uint16_t numRows);
void loadMusic(UNICHAR *filenameU);
bool loadMusicUnthreaded(UNICHAR *filenameU, bool autoPlay);
bool handleModuleLoadFromArg(int argc, char **argv);
@@ -19,7 +19,7 @@
extern char *supportedModExtensions[];
extern volatile bool tmpLinearPeriodsFlag;
-extern int16_t pattLensTmp[MAX_PATTERNS];
-extern tonTyp *pattTmp[MAX_PATTERNS];
-extern instrTyp *instrTmp[1+256];
-extern songTyp songTmp;
+extern int16_t patternNumRowsTmp[MAX_PATTERNS];
+extern note_t *patternTmp[MAX_PATTERNS];
+extern instr_t *instrTmp[1+256];
+extern song_t songTmp;
--- a/src/ft2_module_saver.c
+++ b/src/ft2_module_saver.c
@@ -14,16 +14,11 @@
#include "ft2_tables.h"
#include "ft2_structs.h"
-/* These savers are directly ported, so they should act identical to FT2
-** except for some very minor changes.
-*/
-
+static int8_t smpChunkBuf[1024];
+static uint8_t packedPattData[65536], modPattData[64*32*4];
static SDL_Thread *thread;
-static uint8_t packedPattData[65536];
-static uint16_t packPatt(uint8_t *writePtr, uint8_t *pattPtr, uint16_t numRows);
-
-static const char modSig[32][5] =
+static const char modIDs[32][5] =
{
"1CHN", "2CHN", "3CHN", "4CHN", "5CHN", "6CHN", "7CHN", "8CHN",
"9CHN", "10CH", "11CH", "12CH", "13CH", "14CH", "15CH", "16CH",
@@ -31,16 +26,18 @@
"25CH", "26CH", "27CH", "28CH", "29CH", "30CH", "31CH", "32CH"
};
+static uint16_t packPatt(uint8_t *writePtr, uint8_t *pattPtr, uint16_t numRows);
+
bool saveXM(UNICHAR *filenameU)
{
int16_t i, j, k, a;
size_t result;
- songHeaderTyp h;
- patternHeaderTyp ph;
- instrTyp *ins;
- instrHeaderTyp ih;
- sampleTyp *s;
- sampleHeaderTyp *dst;
+ xmHdr_t h;
+ xmPatHdr_t ph;
+ instr_t *ins;
+ xmInsHdr_t ih;
+ sample_t *s;
+ xmSmpHdr_t *dst;
FILE *f = UNICHAR_FOPEN(filenameU, "wb");
if (f == NULL)
@@ -49,39 +46,56 @@
return false;
}
- memcpy(h.sig, "Extended Module: ", 17);
- memset(h.name, ' ', 20);
- h.name[20] = 0x1A;
- memcpy(h.name, song.name, strlen(song.name));
- memcpy(h.progName, PROG_NAME_STR, 20);
- h.ver = 0x0104;
+ memcpy(h.ID, "Extended Module: ", 17);
+
+ // song name
+ int32_t nameLength = (int32_t)strlen(song.name);
+ if (nameLength > 20)
+ nameLength = 20;
+
+ memset(h.name, ' ', 20); // yes, FT2 pads the name with spaces
+ if (nameLength > 0)
+ memcpy(h.name, song.name, nameLength);
+
+ h.x1A = 0x1A;
+
+ // program/tracker name
+ nameLength = (int32_t)strlen(PROG_NAME_STR);
+ if (nameLength > 20)
+ nameLength = 20;
+
+ memset(h.progName, ' ', 20); // yes, FT2 pads the name with spaces
+ if (nameLength > 0)
+ memcpy(h.progName, PROG_NAME_STR, nameLength);
+
+ h.version = 0x0104;
h.headerSize = 20 + 256;
- h.len = song.len;
- h.repS = song.repS;
- h.antChn = (uint16_t)song.antChn;
- h.defTempo = song.tempo;
- h.defSpeed = song.speed;
+ h.numOrders = song.songLength;
+ h.songLoopStart = song.songLoopStart;
+ h.numChannels = (uint16_t)song.numChannels;
+ h.speed = song.speed;
+ h.BPM = song.BPM;
// count number of patterns
- int16_t ap = MAX_PATTERNS;
+ i = MAX_PATTERNS;
do
{
- if (patternEmpty(ap - 1))
- ap--;
+ if (patternEmpty(i-1))
+ i--;
else
break;
}
- while (ap > 0);
- h.antPtn = ap;
+ while (i > 0);
+ h.numPatterns = i;
// count number of instruments
- int16_t ai = 128;
- while (ai > 0 && getUsedSamples(ai) == 0 && song.instrName[ai][0] == '\0')
- ai--;
- h.antInstrs = ai;
+ i = 128;
+ while (i > 0 && getUsedSamples(i) == 0 && song.instrName[i][0] == '\0')
+ i--;
+ h.numInstr = i;
h.flags = audio.linearPeriodsFlag;
- memcpy(h.songTab, song.songTab, sizeof (song.songTab));
+ memcpy(h.orders, song.orders, 256);
if (fwrite(&h, sizeof (h), 1, f) != 1)
{
@@ -90,27 +104,27 @@
return false;
}
- for (i = 0; i < ap; i++)
+ for (i = 0; i < h.numPatterns; i++)
{
if (patternEmpty(i))
{
- if (patt[i] != NULL)
+ if (pattern[i] != NULL)
{
- free(patt[i]);
- patt[i] = NULL;
+ free(pattern[i]);
+ pattern[i] = NULL;
}
- pattLens[i] = 64;
+ patternNumRows[i] = 64;
}
- ph.patternHeaderSize = sizeof (patternHeaderTyp);
- ph.pattLen = pattLens[i];
- ph.typ = 0;
+ ph.headerSize = sizeof (xmPatHdr_t);
+ ph.numRows = patternNumRows[i];
+ ph.type = 0;
- if (patt[i] == NULL)
+ if (pattern[i] == NULL)
{
- ph.dataLen = 0;
- if (fwrite(&ph, ph.patternHeaderSize, 1, f) != 1)
+ ph.dataSize = 0;
+ if (fwrite(&ph, ph.headerSize, 1, f) != 1)
{
fclose(f);
okBoxThreadSafe(0, "System message", "Error saving module: general I/O error!");
@@ -119,10 +133,10 @@
}
else
{
- ph.dataLen = packPatt(packedPattData, (uint8_t *)patt[i], pattLens[i]);
+ ph.dataSize = packPatt(packedPattData, (uint8_t *)pattern[i], patternNumRows[i]);
- result = fwrite(&ph, ph.patternHeaderSize, 1, f);
- result += fwrite(packedPattData, ph.dataLen, 1, f);
+ result = fwrite(&ph, ph.headerSize, 1, f);
+ result += fwrite(packedPattData, ph.dataSize, 1, f);
if (result != 2) // write was not OK
{
@@ -135,7 +149,7 @@
memset(&ih, 0, sizeof (ih)); // important, clears reserved stuff
- for (i = 1; i <= ai; i++)
+ for (i = 1; i <= h.numInstr; i++)
{
if (instr[i] == NULL)
j = 0;
@@ -144,35 +158,40 @@
a = getUsedSamples(i);
- memset(ih.name, 0, 22);
- memcpy(ih.name, song.instrName[i], strlen(song.instrName[i]));
+ nameLength = (int32_t)strlen(song.instrName[i]);
+ if (nameLength > 22)
+ nameLength = 22;
- ih.typ = 0;
- ih.antSamp = a;
- ih.sampleSize = sizeof (sampleHeaderTyp);
+ memset(ih.name, 0, 22); // pad with zero
+ if (nameLength > 0)
+ memcpy(ih.name, song.instrName[i], nameLength);
+ ih.type = 0;
+ ih.numSamples = a;
+ ih.sampleSize = sizeof (xmSmpHdr_t);
+
if (a > 0)
{
ins = instr[j];
- memcpy(ih.ta, ins->ta, 96);
- memcpy(ih.envVP, ins->envVP, 12*2*sizeof(int16_t));
- memcpy(ih.envPP, ins->envPP, 12*2*sizeof(int16_t));
- ih.envVPAnt = ins->envVPAnt;
- ih.envPPAnt = ins->envPPAnt;
- ih.envVSust = ins->envVSust;
- ih.envVRepS = ins->envVRepS;
- ih.envVRepE = ins->envVRepE;
- ih.envPSust = ins->envPSust;
- ih.envPRepS = ins->envPRepS;
- ih.envPRepE = ins->envPRepE;
- ih.envVTyp = ins->envVTyp;
- ih.envPTyp = ins->envPTyp;
- ih.vibTyp = ins->vibTyp;
+ memcpy(ih.note2SampleLUT, ins->note2SampleLUT, 96);
+ memcpy(ih.volEnvPoints, ins->volEnvPoints, 12*2*sizeof(int16_t));
+ memcpy(ih.panEnvPoints, ins->panEnvPoints, 12*2*sizeof(int16_t));
+ ih.volEnvLength = ins->volEnvLength;
+ ih.panEnvLength = ins->panEnvLength;
+ ih.volEnvSustain = ins->volEnvSustain;
+ ih.volEnvLoopStart = ins->volEnvLoopStart;
+ ih.volEnvLoopEnd = ins->volEnvLoopEnd;
+ ih.panEnvSustain = ins->panEnvSustain;
+ ih.panEnvLoopStart = ins->panEnvLoopStart;
+ ih.panEnvLoopEnd = ins->panEnvLoopEnd;
+ ih.volEnvFlags = ins->volEnvFlags;
+ ih.panEnvFlags = ins->panEnvFlags;
+ ih.vibType = ins->vibType;
ih.vibSweep = ins->vibSweep;
ih.vibDepth = ins->vibDepth;
ih.vibRate = ins->vibRate;
- ih.fadeOut = ins->fadeOut;
+ ih.fadeout = ins->fadeout;
ih.midiOn = ins->midiOn ? 1 : 0;
ih.midiChannel = ins->midiChannel;
ih.midiProgram = ins->midiProgram;
@@ -182,26 +201,40 @@
for (k = 0; k < a; k++)
{
- s = &instr[j]->samp[k];
- dst = &ih.samp[k];
+ s = &instr[j]->smp[k];
+ dst = &ih.smp[k];
- dst->len = s->len;
- dst->repS = s->repS;
- dst->repL = s->repL;
- dst->vol = s->vol;
- dst->fine = s->fine;
- dst->typ = s->typ;
- dst->pan = s->pan;
- dst->relTon = s->relTon;
+ bool sample16Bit = !!(s->flags & SAMPLE_16BIT);
- uint8_t nameLen = (uint8_t)strlen(s->name);
+ dst->length = s->length;
+ dst->loopStart = s->loopStart;
+ dst->loopLength = s->loopLength;
- dst->nameLen = nameLen;
- memset(dst->name, ' ', 22);
- memcpy(dst->name, s->name, nameLen);
+ if (sample16Bit)
+ {
+ dst->length <<= 1;
+ dst->loopStart <<= 1;
+ dst->loopLength <<= 1;
+ }
- if (s->pek == NULL)
- dst->len = 0;
+ dst->volume = s->volume;
+ dst->finetune = s->finetune;
+ dst->flags = s->flags;
+ dst->panning = s->panning;
+ dst->relativeNote = s->relativeNote;
+
+ nameLength = (int32_t)strlen(s->name);
+ if (nameLength > 22)
+ nameLength = 22;
+
+ dst->nameLength = (uint8_t)nameLength;
+
+ memset(dst->name, ' ', 22); // yes, FT2 pads the name with spaces
+ if (nameLength > 0)
+ memcpy(dst->name, s->name, nameLength);
+
+ if (s->dataPtr == NULL)
+ dst->length = 0;
}
}
else
@@ -209,7 +242,7 @@
ih.instrSize = 22 + 11;
}
- if (fwrite(&ih, ih.instrSize + (a * sizeof (sampleHeaderTyp)), 1, f) != 1)
+ if (fwrite(&ih, ih.instrSize + (a * sizeof (xmSmpHdr_t)), 1, f) != 1)
{
fclose(f);
okBoxThreadSafe(0, "System message", "Error saving module: general I/O error!");
@@ -218,18 +251,18 @@
for (k = 1; k <= a; k++)
{
- s = &instr[j]->samp[k-1];
- if (s->pek != NULL)
+ s = &instr[j]->smp[k-1];
+ if (s->dataPtr != NULL)
{
- restoreSample(s);
- samp2Delta(s->pek, s->len, s->typ);
+ unfixSample(s);
+ samp2Delta(s->dataPtr, s->length, s->flags);
- result = fwrite(s->pek, 1, s->len, f);
+ result = fwrite(s->dataPtr, 1, SAMPLE_LENGTH_BYTES(s), f);
- delta2Samp(s->pek, s->len, s->typ);
+ delta2Samp(s->dataPtr, s->length, s->flags);
fixSample(s);
- if (result != (size_t)s->len) // write not OK
+ if (result != (size_t)SAMPLE_LENGTH_BYTES(s)) // write not OK
{
fclose(f);
okBoxThreadSafe(0, "System message", "Error saving module: general I/O error!");
@@ -251,49 +284,67 @@
static bool saveMOD(UNICHAR *filenameU)
{
- bool test, tooManyInstr, incompatEfx, noteUnderflow;
- int8_t *srcPtr, *dstPtr;
- uint8_t ton, inst, pattBuff[64*4*32];
- int16_t a, i, ap;
- int32_t j, k, l1, l2, l3, writeLen, bytesToWrite, bytesWritten;
- FILE *f;
- instrTyp *ins;
- sampleTyp *smp;
- tonTyp *t;
- songMOD31HeaderTyp hm;
+ int16_t i;
+ int32_t j, k;
+ instr_t *ins;
+ sample_t *smp;
+ modHdr_t hdr;
- tooManyInstr = false;
- incompatEfx = false;
- noteUnderflow = false;
-
if (audio.linearPeriodsFlag)
- okBoxThreadSafe(0, "System message", "Linear frequency table used!");
+ okBoxThreadSafe(0, "System message", "Warning: Amiga frequency table isn't used!");
- // sanity checking
+ int32_t songLength = song.songLength;
+ if (songLength > 128)
+ {
+ songLength = 128;
+ okBoxThreadSafe(0, "System message", "Warning: Song length is above 128!");
+ }
+
+ // calculate number of patterns referenced (max 128 orders)
+ int32_t numPatterns = 0;
+ for (i = 0; i < songLength; i++)
+ {
+ if (song.orders[i] > numPatterns)
+ numPatterns = song.orders[i];
+ }
+ numPatterns++;
- test = false;
- if (song.len > 128)
- test = true;
-
- for (i = 100; i < 256; i++)
+ if (numPatterns > 100)
{
- if (patt[i] != NULL)
- {
- test = true;
- break;
- }
+ numPatterns = 100;
+ okBoxThreadSafe(0, "System message", "Warning: Song has more than 100 patterns!");
}
- if (test) okBoxThreadSafe(0, "System message", "Too many patterns!");
+ // check if song has more than 31 instruments
for (i = 32; i <= 128; i++)
{
if (getRealUsedSamples(i) > 0)
{
- okBoxThreadSafe(0, "System message", "Too many instruments!");
+ okBoxThreadSafe(0, "System message", "Warning: Song has more than 31 instruments!");
break;
}
}
+ // check if the first 31 samples have a length above 65534 samples
+ bool test = false;
+ bool test2 = false;
+ for (i = 1; i <= 31; i++)
+ {
+ ins = instr[i];
+ if (ins == NULL)
+ continue;
+
+ smp = &ins->smp[0];
+
+ if (smp->length > 131070)
+ test = true;
+ else if (smp->length > 65534)
+ test2 = true;
+ }
+ if (test) okBoxThreadSafe(0, "System message", "Warning: Song has sample lengths that are too long for the MOD format!");
+ else if (test2) okBoxThreadSafe(0, "System message", "Warning: Song has sample lengths above 65534! Not all MOD players support this.");
+
+ // check if XM instrument features are being used
test = false;
for (i = 1; i <= 31; i++)
{
@@ -301,7 +352,7 @@
if (ins == NULL)
continue;
- smp = &ins->samp[0];
+ smp = &ins->smp[0];
j = getRealUsedSamples(i);
if (j > 1)
@@ -312,8 +363,8 @@
if (j == 1)
{
- if (smp->len > 65534 || ins->fadeOut != 0 || ins->envVTyp != 0 || ins->envPTyp != 0 ||
- (smp->typ & 3) == 2 || smp->relTon != 0 || ins->midiOn)
+ if (ins->fadeout != 0 || ins->volEnvFlags != 0 || ins->panEnvFlags != 0 || ins->vibRate > 0 ||
+ GET_LOOPTYPE(smp->flags) == LOOP_BIDI || smp->relativeNote != 0 || ins->midiOn)
{
test = true;
break;
@@ -320,125 +371,129 @@
}
}
}
- if (test) okBoxThreadSafe(0, "System message", "Incompatible instruments!");
+ if (test) okBoxThreadSafe(0, "System message", "Warning: Song is using XM instrument features!");
- for (i = 0; i < 99; i++)
+ bool tooLongPatterns = false;
+ bool tooManyInstr = false;
+ bool incompatEfx = false;
+ bool noteUnderflow = false;
+
+ for (i = 0; i < numPatterns; i++)
{
- if (patt[i] != NULL)
+ if (pattern[i] == NULL)
+ continue;
+
+ if (patternNumRows[i] < 64)
{
- if (pattLens[i] != 64)
- {
- okBoxThreadSafe(0, "System message", "Unable to convert module. (Illegal pattern length)");
- return false;
- }
+ okBoxThreadSafe(0, "System message", "Error: Pattern lengths can't be below 64! Module wasn't saved.");
+ return false;
+ }
- for (j = 0; j < 64; j++)
+ if (patternNumRows[i] > 64)
+ tooLongPatterns = true;
+
+ for (j = 0; j < 64; j++)
+ {
+ for (k = 0; k < song.numChannels; k++)
{
- for (k = 0; k < song.antChn; k++)
- {
- t = &patt[i][(j * MAX_VOICES) + k];
+ note_t *p = &pattern[i][(j * MAX_CHANNELS) + k];
- if (t->instr > 31)
- tooManyInstr = true;
+ if (p->instr > 31)
+ tooManyInstr = true;
- if (t->effTyp > 15 || t->vol != 0)
- incompatEfx = true;
+ if (p->efx > 0xF || p->vol != 0)
+ incompatEfx = true;
- // added security that wasn't present in FT2
- if (t->ton > 0 && t->ton < 10)
- noteUnderflow = true;
- }
+ // added security that wasn't present in FT2
+ if (p->note > 0 && p->note < 10)
+ noteUnderflow = true;
}
}
}
- if (tooManyInstr) okBoxThreadSafe(0, "System message", "Instrument(s) above 31 was found in pattern data!");
- if (incompatEfx) okBoxThreadSafe(0, "System message", "Incompatible effect(s) was found in pattern data!");
- if (noteUnderflow) okBoxThreadSafe(0, "System message", "Note(s) below A-0 were found in pattern data!");
- // setup header buffer
- memset(&hm, 0, sizeof (hm));
- memcpy(hm.name, song.name, sizeof (hm.name));
- hm.len = (uint8_t)song.len;
- if (hm.len > 128) hm.len = 128;
- hm.repS = (uint8_t)song.repS;
- if (hm.repS > 127) hm.repS = 0;
- memcpy(hm.songTab, song.songTab, song.len);
+ if (tooLongPatterns) okBoxThreadSafe(0, "System message", "Warning: Song has pattern lengths above 64!");
+ if (tooManyInstr) okBoxThreadSafe(0, "System message", "Warning: Patterns have instrument numbers above 31!");
+ if (incompatEfx) okBoxThreadSafe(0, "System message", "Warning: Patterns have incompatible effects!");
+ if (noteUnderflow) okBoxThreadSafe(0, "System message", "Warning: Patterns have notes below A-0!");
- // calculate number of patterns
- ap = 0;
- for (i = 0; i < song.len; i++)
- {
- if (song.songTab[i] > ap)
- ap = song.songTab[i];
- }
+ // save module now
- if (song.antChn == 4)
- memcpy(hm.sig, (ap > 64) ? "M!K!" : "M.K.", 4);
+ memset(&hdr, 0, sizeof (hdr));
+
+ // song name
+ int32_t nameLength = (int32_t)strlen(song.name);
+ if (nameLength > 20)
+ nameLength = 20;
+
+ memset(hdr.name, 0, 20); // pad with zeroes
+ if (nameLength > 0)
+ memcpy(hdr.name, song.name, nameLength);
+
+ hdr.numOrders = (uint8_t)songLength; // pre-clamped to 0..128
+
+ hdr.songLoopStart = (uint8_t)song.songLoopStart;
+ if (hdr.songLoopStart >= hdr.numOrders) // repeat-point must be lower than the song length
+ hdr.songLoopStart = 0;
+
+ memcpy(hdr.orders, song.orders, hdr.numOrders);
+
+ if (song.numChannels == 4)
+ memcpy(hdr.ID, (numPatterns > 64) ? "M!K!" : "M.K.", 4);
else
- memcpy(hm.sig, modSig[song.antChn-1], 4);
+ memcpy(hdr.ID, modIDs[song.numChannels-1], 4);
- // read sample information into header buffer
+ // fill MOD sample headers
for (i = 1; i <= 31; i++)
{
- songMODInstrHeaderTyp *modIns = &hm.instr[i-1];
+ modSmpHdr_t *modSmp = &hdr.smp[i-1];
- memcpy(modIns->name, song.instrName[i], sizeof (modIns->name));
+ nameLength = (int32_t)strlen(song.instrName[i]);
+ if (nameLength > 22)
+ nameLength = 22;
+
+ memset(modSmp->name, 0, 22); // pad with zeroes
+ if (nameLength > 0)
+ memcpy(modSmp->name, song.instrName[i], nameLength);
+
if (instr[i] != NULL && getRealUsedSamples(i) != 0)
{
- smp = &instr[i]->samp[0];
+ smp = &instr[i]->smp[0];
- l1 = smp->len >> 1;
- l2 = smp->repS >> 1;
- l3 = smp->repL >> 1;
+ int32_t length = smp->length >> 1;
+ int32_t loopStart = smp->loopStart >> 1;
+ int32_t loopLength = smp->loopLength >> 1;
- if (smp->typ & 16)
- {
- l1 >>= 1;
- l2 >>= 1;
- l3 >>= 1;
- }
+ // length/loopStart/loopLength are now in units of words
- if (l1 > 32767)
- l1 = 32767;
+ if (length > UINT16_MAX)
+ length = UINT16_MAX;
- if (l2 > l1)
- l2 = l1;
-
- if (l2+l3 > l1)
- l3 = l1 - l2;
-
- // FT2 bug-fix
- if (l3 < 1)
+ if (GET_LOOPTYPE(smp->flags) == LOOP_OFF)
{
- l2 = 0;
- l3 = 1;
+ loopStart = 0;
+ loopLength = 1;
}
-
- modIns->len = (uint16_t)(SWAP16(l1));
- modIns->fine = ((smp->fine + 128) >> 4) ^ 8;
- modIns->vol = smp->vol;
-
- if ((smp->typ & 3) == 0)
+ else // looped sample
{
- modIns->repS = 0;
- modIns->repL = SWAP16(1);
+ if (loopLength == 0) // ProTracker hates loopLengths of zero
+ loopLength = 1;
+
+ if (loopStart+loopLength > length)
+ {
+ loopStart = 0;
+ loopLength = 1;
+ }
}
- else
- {
- modIns->repS = (uint16_t)(SWAP16(l2));
- modIns->repL = (uint16_t)(SWAP16(l3));
- }
- }
- // FT2 bugfix: never allow replen being below 2 (1)
- if (SWAP16(modIns->repL) < 1)
- {
- modIns->repS = SWAP16(0);
- modIns->repL = SWAP16(1);
+ modSmp->length = (uint16_t)SWAP16(length);
+ modSmp->finetune = FINETUNE_XM2MOD(smp->finetune);
+ modSmp->volume = smp->volume;
+ modSmp->loopStart = (uint16_t)SWAP16(loopStart);
+ modSmp->loopLength = (uint16_t)SWAP16(loopLength);
}
}
- f = UNICHAR_FOPEN(filenameU, "wb");
+ FILE *f = UNICHAR_FOPEN(filenameU, "wb");
if (f == NULL)
{
okBoxThreadSafe(0, "System message", "Error opening file for saving, is it in use?");
@@ -446,7 +501,7 @@
}
// write header
- if (fwrite(&hm, 1, sizeof (hm), f) != sizeof (hm))
+ if (fwrite(&hdr, 1, sizeof (hdr), f) != sizeof (hdr))
{
okBoxThreadSafe(0, "System message", "Error saving module: general I/O error!");
goto modSaveError;
@@ -453,66 +508,66 @@
}
// write pattern data
- for (i = 0; i <= ap; i++)
+ const int32_t patternBytes = song.numChannels * 64 * 4;
+ for (i = 0; i < numPatterns; i++)
{
- if (patt[i] == NULL)
+ if (pattern[i] == NULL) // empty pattern
{
- // empty pattern
- memset(pattBuff, 0, song.antChn * (64 * 4));
+ memset(modPattData, 0, patternBytes);
}
else
{
- a = 0;
+ int32_t offs = 0;
for (j = 0; j < 64; j++)
{
- for (k = 0; k < song.antChn; k++)
+ for (k = 0; k < song.numChannels; k++)
{
- t = &patt[i][(j * MAX_VOICES) + k];
+ note_t *p = &pattern[i][(j * MAX_CHANNELS) + k];
- inst = t->instr;
- ton = t->ton;
+ uint8_t inst = p->instr;
+ uint8_t note = p->note;
// FT2 bugfix: prevent overflow
if (inst > 31)
inst = 0;
- // FT2 bugfix: convert note-off into no note
- if (ton == 97)
- ton = 0;
+ // FT2 bugfix: convert note-off into no note for MOD saving
+ if (note == NOTE_OFF)
+ note = 0;
// FT2 bugfix: clamp notes below 10 (A-0) to prevent 12-bit period overflow
- if (ton > 0 && ton < 10)
- ton = 10;
+ if (note > 0 && note < 10)
+ note = 10;
- if (ton == 0)
+ if (note == 0)
{
- pattBuff[a+0] = inst & 0xF0;
- pattBuff[a+1] = 0;
+ modPattData[offs+0] = inst & 0xF0;
+ modPattData[offs+1] = 0;
}
else
{
- pattBuff[a+0] = (inst & 0xF0) | ((amigaPeriod[ton-1] >> 8) & 0x0F);
- pattBuff[a+1] = amigaPeriod[ton-1] & 0xFF;
+ modPattData[offs+0] = (inst & 0xF0) | ((amigaPeriod[note-1] >> 8) & 0x0F);
+ modPattData[offs+1] = amigaPeriod[note-1] & 0xFF;
}
// FT2 bugfix: if effect is overflowing (0xF in .MOD), set effect and param to 0
- if (t->effTyp > 0x0F)
+ if (p->efx > 0x0F)
{
- pattBuff[a+2] = (inst & 0x0F) << 4;
- pattBuff[a+3] = 0;
+ modPattData[offs+2] = (inst & 0x0F) << 4;
+ modPattData[offs+3] = 0;
}
else
{
- pattBuff[a+2] = ((inst & 0x0F) << 4) | (t->effTyp & 0x0F);
- pattBuff[a+3] = t->eff;
+ modPattData[offs+2] = ((inst & 0x0F) << 4) | (p->efx & 0x0F);
+ modPattData[offs+3] = p->efxData;
}
- a += 4;
+ offs += 4;
}
}
}
- if (fwrite(pattBuff, 1, song.antChn * (64 * 4), f) != (size_t)(song.antChn * (64 * 4)))
+ if (fwrite(modPattData, 1, patternBytes, f) != (size_t)patternBytes)
{
okBoxThreadSafe(0, "System message", "Error saving module: general I/O error!");
goto modSaveError;
@@ -520,39 +575,38 @@
}
// write sample data
- for (i = 0; i < 31; i++)
+ for (i = 1; i <= 31; i++)
{
- if (instr[1+i] == NULL || getRealUsedSamples(1+i) == 0)
+ if (instr[i] == NULL || getRealUsedSamples(i) == 0)
continue;
- smp = &instr[1+i]->samp[0];
- if (smp->pek == NULL || smp->len <= 0)
+ smp = &instr[i]->smp[0];
+ if (smp->dataPtr == NULL || smp->length <= 0)
continue;
- restoreSample(smp);
+ modSmpHdr_t *modSmp = &hdr.smp[i-1];
- l1 = smp->len >> 1;
- if (smp->typ & 16) // 16-bit sample (convert to 8-bit)
- {
- if (l1 > 65534)
- l1 = 65534;
+ unfixSample(smp);
- // let's borrow "pattBuff" here
- dstPtr = (int8_t *)pattBuff;
+ int32_t sampleBytes = SWAP16(modSmp->length) * 2;
- writeLen = l1;
- bytesWritten = 0;
- while (bytesWritten < writeLen) // write in 8K blocks
+ if (smp->flags & SAMPLE_16BIT) // 16-bit sample (convert to 8-bit)
+ {
+ int8_t *dstPtr = (int8_t *)smpChunkBuf;
+ int32_t writeLen = sampleBytes;
+ int32_t samplesWritten = 0;
+
+ while (samplesWritten < writeLen) // write in chunks
{
- bytesToWrite = sizeof (pattBuff);
- if (bytesWritten+bytesToWrite > writeLen)
- bytesToWrite = writeLen - bytesWritten;
+ int32_t samplesToWrite = sizeof (smpChunkBuf);
+ if (samplesWritten+samplesToWrite > writeLen)
+ samplesToWrite = writeLen - samplesWritten;
- srcPtr = &smp->pek[(bytesWritten << 1) + 1]; // +1 to align to high byte
- for (j = 0; j < bytesToWrite; j++)
- dstPtr[j] = srcPtr[j << 1];
+ int16_t *srcPtr16 = (int16_t *)smp->dataPtr + samplesWritten;
+ for (j = 0; j < samplesToWrite; j++)
+ dstPtr[j] = srcPtr16[j] >> 8; // convert 16-bit to 8-bit
- if (fwrite(dstPtr, 1, bytesToWrite, f) != (size_t)bytesToWrite)
+ if (fwrite(dstPtr, 1, samplesToWrite, f) != (size_t)samplesToWrite)
{
fixSample(smp);
okBoxThreadSafe(0, "System message", "Error saving module: general I/O error!");
@@ -559,19 +613,12 @@
goto modSaveError;
}
- bytesWritten += bytesToWrite;
+ samplesWritten += samplesToWrite;
}
}
- else
+ else // 8-bit sample
{
- // 8-bit sample
-
- if (l1 > 32767)
- l1 = 32767;
-
- l1 <<= 1;
-
- if (fwrite(smp->pek, 1, l1, f) != (size_t)l1)
+ if (fwrite(smp->dataPtr, 1, sampleBytes, f) != (size_t)sampleBytes)
{
fixSample(smp);
okBoxThreadSafe(0, "System message", "Error saving module: general I/O error!");
@@ -638,10 +685,10 @@
uint16_t totalPackLen = 0;
- const int32_t pitch = sizeof (tonTyp) * (MAX_VOICES - song.antChn);
+ const int32_t pitch = sizeof (note_t) * (MAX_CHANNELS - song.numChannels);
for (int32_t row = 0; row < numRows; row++)
{
- for (int32_t chn = 0; chn < song.antChn; chn++)
+ for (int32_t chn = 0; chn < song.numChannels; chn++)
{
bytes[0] = *pattPtr++;
bytes[1] = *pattPtr++;
--- a/src/ft2_mouse.c
+++ b/src/ft2_mouse.c
@@ -8,7 +8,7 @@
#include "ft2_header.h"
#include "ft2_gui.h"
#include "ft2_video.h"
-#include "ft2_scopes.h"
+#include "scopes/ft2_scopes.h"
#include "ft2_help.h"
#include "ft2_sample_ed.h"
#include "ft2_inst_ed.h"
@@ -127,7 +127,7 @@
outX[xScale] = pixel;
}
- outX += video.xScale;
+ outX += scaleFactor;
}
}
}
@@ -383,11 +383,11 @@
if (songPlaying)
return;
- int16_t pattPos = editor.pattPos - 1;
- if (pattPos < 0)
- pattPos = pattLens[editor.editPattern] - 1;
+ int16_t row = editor.row - 1;
+ if (row < 0)
+ row = patternNumRows[editor.editPattern] - 1;
- setPos(-1, pattPos, true);
+ setPos(-1, row, true);
}
static void mouseWheelIncRow(void)
@@ -395,11 +395,11 @@
if (songPlaying)
return;
- int16_t pattPos = editor.pattPos + 1;
- if (pattPos > (pattLens[editor.editPattern] - 1))
- pattPos = 0;
+ int16_t row = editor.row + 1;
+ if (row >= patternNumRows[editor.editPattern])
+ row = 0;
- setPos(-1, pattPos, true);
+ setPos(-1, row, true);
}
void mouseWheelHandler(bool directionUp)
@@ -569,7 +569,7 @@
{
// right mouse button released after hand-editing sample data
if (instr[editor.curInstr] != NULL)
- fixSample(&instr[editor.curInstr]->samp[editor.curSmp]);
+ fixSample(&instr[editor.curInstr]->smp[editor.curSmp]);
resumeAudio();
--- a/src/ft2_nibbles.c
+++ b/src/ft2_nibbles.c
@@ -1,5 +1,3 @@
-// directly ported from FT2 source code (except some routines)
-
#include <stdint.h>
#include <stdio.h>
#include <math.h> // round()
@@ -13,7 +11,6 @@
#include "ft2_structs.h"
#define STAGES_BMP_WIDTH 530
-
#define NI_MAXLEVEL 30
static const char *NI_HelpText[] =
@@ -35,14 +32,14 @@
typedef struct
{
- int16_t antal;
+ int16_t length;
uint8_t data[8];
-} nibbleBufferTyp;
+} nibblesBuffer_t;
typedef struct
{
uint8_t x, y;
-} nibbleCrd;
+} nibblesCoord_t;
static const char nibblesCheatCode1[] = "skip", nibblesCheatCode2[] = "triton";
static char nibblesCheatBuffer[16];
@@ -51,11 +48,11 @@
static const uint8_t NI_Speeds[4] = { 12, 8, 6, 4 };
static bool NI_EternalLives;
static uint8_t NI_CheatIndex, NI_CurSpeed, NI_CurTick60Hz, NI_CurSpeed60Hz, NI_Screen[51][23], NI_Level;
-static int16_t NI_P1Dir, NI_P2Dir, NI_P1Len, NI_P2Len, NI_Number, NI_NumberX, NI_NumberY, NI_P1NoRens, NI_P2NoRens;
+static int16_t NI_P1Dir, NI_P2Dir, NI_P1Len, NI_P2Len, NI_Number, NI_NumberX, NI_NumberY, NI_P1NoClear, NI_P2NoClear;
static uint16_t NI_P1Lives, NI_P2Lives;
static int32_t NI_P1Score, NI_P2Score;
-static nibbleCrd NI_P1[256], NI_P2[256];
-static nibbleBufferTyp nibblesBuffer[2];
+static nibblesCoord_t NI_P1[256], NI_P2[256];
+static nibblesBuffer_t nibblesBuffer[2];
/* Non-FT2 feature: Check if either the Desktop or Buttons palette color
** is so close to black that the player would have troubles seeing the walls
@@ -150,29 +147,29 @@
}
}
-static void nibblesAddBuffer(int16_t nr, uint8_t typ)
+static void nibblesAddBuffer(int16_t bufNum, uint8_t value)
{
- nibbleBufferTyp *n = &nibblesBuffer[nr];
- if (n->antal < 8)
+ nibblesBuffer_t *n = &nibblesBuffer[bufNum];
+ if (n->length < 8)
{
- n->data[n->antal] = typ;
- n->antal++;
+ n->data[n->length] = value;
+ n->length++;
}
}
-static bool nibblesBufferFull(int16_t nr)
+static bool nibblesBufferFull(int16_t bufNum)
{
- return (nibblesBuffer[nr].antal > 0);
+ return (nibblesBuffer[bufNum].length > 0);
}
-static int16_t nibblesGetBuffer(int16_t nr)
+static int16_t nibblesGetBuffer(int16_t bufNum)
{
- nibbleBufferTyp *n = &nibblesBuffer[nr];
- if (n->antal > 0)
+ nibblesBuffer_t *n = &nibblesBuffer[bufNum];
+ if (n->length > 0)
{
const int16_t dataOut = n->data[0];
memmove(&n->data[0], &n->data[1], 7);
- n->antal--;
+ n->length--;
return dataOut;
}
@@ -180,10 +177,10 @@
return -1;
}
-static void nibblesGetLevel(int16_t nr)
+static void nibblesGetLevel(int16_t levelNum)
{
- const int32_t readX = 1 + ((51+2) * (nr % 10));
- const int32_t readY = 1 + ((23+2) * (nr / 10));
+ const int32_t readX = 1 + ((51+2) * (levelNum % 10));
+ const int32_t readY = 1 + ((23+2) * (levelNum / 10));
const uint8_t *stagePtr = &bmp.nibblesStages[(readY * STAGES_BMP_WIDTH) + readX];
@@ -196,12 +193,12 @@
}
}
-static void nibblesCreateLevel(int16_t nr)
+static void nibblesCreateLevel(int16_t levelNum)
{
- if (nr >= NI_MAXLEVEL)
- nr = NI_MAXLEVEL - 1;
+ if (levelNum >= NI_MAXLEVEL)
+ levelNum = NI_MAXLEVEL-1;
- nibblesGetLevel(nr);
+ nibblesGetLevel(levelNum);
int32_t x1 = 0;
int32_t x2 = 0;
@@ -233,8 +230,8 @@
}
}
- const int32_t readX = (51 + 2) * (nr % 10);
- const int32_t readY = (23 + 2) * (nr / 10);
+ const int32_t readX = (51 + 2) * (levelNum % 10);
+ const int32_t readY = (23 + 2) * (levelNum / 10);
NI_P1Dir = bmp.nibblesStages[(readY * 530) + (readX + 1)];
NI_P2Dir = bmp.nibblesStages[(readY * 530) + (readX + 0)];
@@ -241,11 +238,11 @@
NI_P1Len = 5;
NI_P2Len = 5;
- NI_P1NoRens = 0;
- NI_P2NoRens = 0;
+ NI_P1NoClear = 0;
+ NI_P2NoClear = 0;
NI_Number = 0;
- nibblesBuffer[0].antal = 0;
- nibblesBuffer[1].antal = 0;
+ nibblesBuffer[0].length = 0;
+ nibblesBuffer[1].length = 0;
for (int32_t i = 0; i < 256; i++)
{
@@ -256,10 +253,10 @@
}
}
-static void nibbleWriteLevelSprite(int16_t xOut, int16_t yOut, int16_t nr)
+static void nibbleWriteLevelSprite(int16_t xOut, int16_t yOut, int16_t levelNum)
{
- const int32_t readX = (51 + 2) * (nr % 10);
- const int32_t readY = (23 + 2) * (nr / 10);
+ const int32_t readX = (51 + 2) * (levelNum % 10);
+ const int32_t readY = (23 + 2) * (levelNum / 10);
const uint8_t *src = (const uint8_t *)&bmp.nibblesStages[(readY * 530) + readX];
uint32_t *dst = &video.frameBuffer[(yOut * SCREEN_W) + xOut];
@@ -385,7 +382,7 @@
redrawNibblesScreen();
setNibbleDot(NI_P1[0].x, NI_P1[0].y, 6);
- if (config.NI_AntPlayers == 1)
+ if (config.NI_NumPlayers == 1)
setNibbleDot(NI_P2[0].x, NI_P2[0].y, 7);
if (!config.NI_Surround)
@@ -450,7 +447,7 @@
// prevent highscore table from showing overflowing level graphics
if (NI_Level >= NI_MAXLEVEL)
- NI_Level = NI_MAXLEVEL - 1;
+ NI_Level = NI_MAXLEVEL-1;
if (NI_P1Score > config.NI_HighScore[9].score)
{
@@ -528,7 +525,7 @@
// cast to int16_t to simulate a bug in FT2
NI_P1Score += 0x10000 + (int16_t)((12 - NI_CurSpeed) * 0x2000);
- if (config.NI_AntPlayers == 1)
+ if (config.NI_NumPlayers == 1)
NI_P2Score += 0x10000;
NI_Level++;
@@ -536,7 +533,7 @@
if (NI_P1Lives < 99)
NI_P1Lives++;
- if (config.NI_AntPlayers == 1)
+ if (config.NI_NumPlayers == 1)
{
if (NI_P2Lives < 99)
NI_P2Lives++;
@@ -549,7 +546,7 @@
nibblesGenNewNumber();
}
-void moveNibblePlayers(void)
+void moveNibblesPlayers(void)
{
if (ui.sysReqShown || --NI_CurTick60Hz != 0)
return;
@@ -578,9 +575,9 @@
}
}
- memmove(&NI_P1[1], &NI_P1[0], 255 * sizeof (nibbleCrd));
- if (config.NI_AntPlayers == 1)
- memmove(&NI_P2[1], &NI_P2[0], 255 * sizeof (nibbleCrd));
+ memmove(&NI_P1[1], &NI_P1[0], 255 * sizeof (nibblesCoord_t));
+ if (config.NI_NumPlayers == 1)
+ memmove(&NI_P2[1], &NI_P2[0], 255 * sizeof (nibblesCoord_t));
switch (NI_P1Dir)
{
@@ -591,7 +588,7 @@
default: break;
}
- if (config.NI_AntPlayers == 1)
+ if (config.NI_NumPlayers == 1)
{
switch (NI_P2Dir)
{
@@ -613,7 +610,7 @@
NI_P2[0].x %= 51;
NI_P2[0].y %= 23;
- if (config.NI_AntPlayers == 1)
+ if (config.NI_NumPlayers == 1)
{
if (nibblesInvalid(NI_P1[0].x, NI_P1[0].y, NI_P1Dir) && nibblesInvalid(NI_P2[0].x, NI_P2[0].y, NI_P2Dir))
{
@@ -651,10 +648,10 @@
{
NI_P1Score += (i & 15) * 999 * (NI_Level + 1);
nibblesEraseNumber(); j = 1;
- NI_P1NoRens = NI_P1Len / 2;
+ NI_P1NoClear = NI_P1Len >> 1;
}
- if (config.NI_AntPlayers == 1)
+ if (config.NI_NumPlayers == 1)
{
i = NI_Screen[NI_P2[0].x][NI_P2[0].y];
if (i >= 16)
@@ -661,12 +658,12 @@
{
NI_P2Score += ((i & 15) * 999 * (NI_Level + 1));
nibblesEraseNumber(); j = 1;
- NI_P2NoRens = NI_P2Len / 2;
+ NI_P2NoClear = NI_P2Len >> 1;
}
}
NI_P1Score -= 17;
- if (config.NI_AntPlayers == 1)
+ if (config.NI_NumPlayers == 1)
NI_P2Score -= 17;
if (NI_P1Score < 0) NI_P1Score = 0;
@@ -674,9 +671,9 @@
if (!config.NI_Surround)
{
- if (NI_P1NoRens > 0 && NI_P1Len < 255)
+ if (NI_P1NoClear > 0 && NI_P1Len < 255)
{
- NI_P1NoRens--;
+ NI_P1NoClear--;
NI_P1Len++;
}
else
@@ -684,11 +681,11 @@
setNibbleDot(NI_P1[NI_P1Len].x, NI_P1[NI_P1Len].y, 0);
}
- if (config.NI_AntPlayers == 1)
+ if (config.NI_NumPlayers == 1)
{
- if (NI_P2NoRens > 0 && NI_P2Len < 255)
+ if (NI_P2NoClear > 0 && NI_P2Len < 255)
{
- NI_P2NoRens--;
+ NI_P2NoClear--;
NI_P2Len++;
}
else
@@ -699,7 +696,7 @@
}
setNibbleDot(NI_P1[0].x, NI_P1[0].y, 6);
- if (config.NI_AntPlayers == 1)
+ if (config.NI_NumPlayers == 1)
setNibbleDot(NI_P2[0].x, NI_P2[0].y, 5);
if (j == 1 && !config.NI_Surround)
@@ -770,7 +767,7 @@
showCheckBox(CB_NIBBLES_WRAP);
uncheckRadioButtonGroup(RB_GROUP_NIBBLES_PLAYERS);
- if (config.NI_AntPlayers == 0)
+ if (config.NI_NumPlayers == 0)
radioButtons[RB_NIBBLES_1PLAYER].state = RADIOBUTTON_CHECKED;
else
radioButtons[RB_NIBBLES_2PLAYERS].state = RADIOBUTTON_CHECKED;
@@ -821,7 +818,7 @@
return;
}
- if (config.NI_Surround && config.NI_AntPlayers == 0)
+ if (config.NI_Surround && config.NI_NumPlayers == 0)
{
okBox(0, "Nibbles message", "Surround mode is not appropriate in one-player mode.");
return;
@@ -834,8 +831,8 @@
NI_CurSpeed = NI_Speeds[config.NI_Speed];
// adjust for 70Hz -> 60Hz frames
- NI_CurSpeed60Hz = (uint8_t)round(NI_CurSpeed * ((double)VBLANK_HZ / FT2_VBLANK_HZ));
- NI_CurTick60Hz = (uint8_t)round(NI_Speeds[2] * ((double)VBLANK_HZ / FT2_VBLANK_HZ));
+ NI_CurSpeed60Hz = (uint8_t)SCALE_VBLANK_DELTA(NI_CurSpeed);
+ NI_CurTick60Hz = (uint8_t)SCALE_VBLANK_DELTA(NI_Speeds[2]);
editor.NI_Play = true;
NI_P1Score = 0;
@@ -882,13 +879,13 @@
void nibblesSet1Player(void)
{
- config.NI_AntPlayers = 0;
+ config.NI_NumPlayers = 0;
checkRadioButton(RB_NIBBLES_1PLAYER);
}
void nibblesSet2Players(void)
{
- config.NI_AntPlayers = 1;
+ config.NI_NumPlayers = 1;
checkRadioButton(RB_NIBBLES_2PLAYERS);
}
--- a/src/ft2_nibbles.h
+++ b/src/ft2_nibbles.h
@@ -5,7 +5,7 @@
#include <SDL2/SDL.h>
void nibblesKeyAdministrator(SDL_Scancode scancode);
-void moveNibblePlayers(void);
+void moveNibblesPlayers(void);
void showNibblesScreen(void);
void hideNibblesScreen(void);
void exitNibblesScreen(void);
--- a/src/ft2_palette.c
+++ b/src/ft2_palette.c
@@ -1,5 +1,6 @@
#include <stdint.h>
#include <stdbool.h>
+#include <math.h>
#include "ft2_palette.h"
#include "ft2_gui.h"
#include "ft2_config.h"
@@ -7,7 +8,7 @@
#include "ft2_palette.h"
#include "ft2_tables.h"
-uint8_t cfg_ColorNr = 0; // globalized
+uint8_t cfg_ColorNum = 0; // globalized
static uint8_t cfg_Red, cfg_Green, cfg_Blue, cfg_Contrast;
@@ -27,7 +28,7 @@
void setPal16(pal16 *p, bool redrawScreen)
{
-#define LOOP_PIN_COL_SUB 96
+#define LOOP_PIN_COL_SUB 110
#define TEXT_MARK_COLOR 0x0078D7
#define BOX_SELECT_COLOR 0x7F7F7F
@@ -89,12 +90,12 @@
uint8_t palMax(int32_t c)
{
- return (uint8_t)(CLAMP(c, 0, 63));
+ return (uint8_t)CLAMP(c, 0, 63);
}
static void drawCurrentPaletteColor(void)
{
- const uint8_t palIndex = FTC_EditOrder[cfg_ColorNr];
+ const uint8_t palIndex = FTC_EditOrder[cfg_ColorNum];
const uint8_t r = P6_TO_P8(cfg_Red);
const uint8_t g = P6_TO_P8(cfg_Green);
@@ -108,14 +109,14 @@
static void updatePaletteEditor(void)
{
- const uint8_t nr = FTC_EditOrder[cfg_ColorNr];
+ const uint8_t colorNum = FTC_EditOrder[cfg_ColorNum];
- cfg_Red = palTable[config.cfg_StdPalNr][nr].r;
- cfg_Green = palTable[config.cfg_StdPalNr][nr].g;
- cfg_Blue = palTable[config.cfg_StdPalNr][nr].b;
+ cfg_Red = palTable[config.cfg_StdPalNum][colorNum].r;
+ cfg_Green = palTable[config.cfg_StdPalNum][colorNum].g;
+ cfg_Blue = palTable[config.cfg_StdPalNum][colorNum].b;
- if (cfg_ColorNr == 4 || cfg_ColorNr == 5)
- cfg_Contrast = palContrast[config.cfg_StdPalNr][cfg_ColorNr-4];
+ if (cfg_ColorNum == 4 || cfg_ColorNum == 5)
+ cfg_Contrast = palContrast[config.cfg_StdPalNum][cfg_ColorNum-4];
else
cfg_Contrast = 0;
@@ -129,7 +130,7 @@
static void paletteDragMoved(void)
{
- if (config.cfg_StdPalNr != PAL_USER_DEFINED)
+ if (config.cfg_StdPalNum != PAL_USER_DEFINED)
{
updatePaletteEditor(); // resets colors/contrast vars
showColorErrorMsg();
@@ -136,7 +137,7 @@
return;
}
- if ((config.specialFlags2 & HARDWARE_MOUSE) && cfg_ColorNr == 3)
+ if ((config.specialFlags2 & HARDWARE_MOUSE) && cfg_ColorNum == 3)
{
updatePaletteEditor(); // resets colors/contrast vars
showMouseColorErrorMsg();
@@ -143,14 +144,14 @@
return;
}
- const uint8_t nr = FTC_EditOrder[cfg_ColorNr];
- const uint8_t p = (uint8_t)config.cfg_StdPalNr;
+ const uint8_t colorNum = FTC_EditOrder[cfg_ColorNum];
+ const uint8_t p = (uint8_t)config.cfg_StdPalNum;
- palTable[p][nr].r = cfg_Red;
- palTable[p][nr].g = cfg_Green;
- palTable[p][nr].b = cfg_Blue;
+ palTable[p][colorNum].r = cfg_Red;
+ palTable[p][colorNum].g = cfg_Green;
+ palTable[p][colorNum].b = cfg_Blue;
- if (cfg_ColorNr == 4 || cfg_ColorNr == 5)
+ if (cfg_ColorNum == 4 || cfg_ColorNum == 5)
{
double dRed = cfg_Red;
double dGreen = cfg_Green;
@@ -164,7 +165,7 @@
for (int32_t i = 0; i < 3; i++)
{
- const int32_t k = scaleOrder[i] + (cfg_ColorNr - 4) * 2;
+ const int32_t k = scaleOrder[i] + (cfg_ColorNum - 4) * 2;
double dMul = palPow((i + 1) * (1.0 / 2.0), dContrast);
@@ -173,7 +174,7 @@
palTable[p][k].b = palMax((int32_t)((dBlue * dMul) + 0.5));
}
- palContrast[p][cfg_ColorNr-4] = cfg_Contrast;
+ palContrast[p][cfg_ColorNum-4] = cfg_Contrast;
}
else
{
@@ -186,7 +187,7 @@
setScrollBarPos(SB_PAL_CONTRAST, cfg_Contrast, false);
- setPal16(palTable[config.cfg_StdPalNr], true);
+ setPal16(palTable[config.cfg_StdPalNum], true);
drawCurrentPaletteColor();
}
@@ -228,9 +229,9 @@
void configPalRDown(void)
{
- if (config.cfg_StdPalNr != PAL_USER_DEFINED)
+ if (config.cfg_StdPalNum != PAL_USER_DEFINED)
showColorErrorMsg();
- else if ((config.specialFlags2 & HARDWARE_MOUSE) && cfg_ColorNr == 3)
+ else if ((config.specialFlags2 & HARDWARE_MOUSE) && cfg_ColorNum == 3)
showMouseColorErrorMsg();
else
scrollBarScrollLeft(SB_PAL_R, 1);
@@ -238,9 +239,9 @@
void configPalRUp(void)
{
- if (config.cfg_StdPalNr != PAL_USER_DEFINED)
+ if (config.cfg_StdPalNum != PAL_USER_DEFINED)
showColorErrorMsg();
- else if ((config.specialFlags2 & HARDWARE_MOUSE) && cfg_ColorNr == 3)
+ else if ((config.specialFlags2 & HARDWARE_MOUSE) && cfg_ColorNum == 3)
showMouseColorErrorMsg();
else
scrollBarScrollRight(SB_PAL_R, 1);
@@ -248,9 +249,9 @@
void configPalGDown(void)
{
- if (config.cfg_StdPalNr != PAL_USER_DEFINED)
+ if (config.cfg_StdPalNum != PAL_USER_DEFINED)
showColorErrorMsg();
- else if ((config.specialFlags2 & HARDWARE_MOUSE) && cfg_ColorNr == 3)
+ else if ((config.specialFlags2 & HARDWARE_MOUSE) && cfg_ColorNum == 3)
showMouseColorErrorMsg();
else
scrollBarScrollLeft(SB_PAL_G, 1);
@@ -258,9 +259,9 @@
void configPalGUp(void)
{
- if (config.cfg_StdPalNr != PAL_USER_DEFINED)
+ if (config.cfg_StdPalNum != PAL_USER_DEFINED)
showColorErrorMsg();
- else if ((config.specialFlags2 & HARDWARE_MOUSE) && cfg_ColorNr == 3)
+ else if ((config.specialFlags2 & HARDWARE_MOUSE) && cfg_ColorNum == 3)
showMouseColorErrorMsg();
else
scrollBarScrollRight(SB_PAL_G, 1);
@@ -268,9 +269,9 @@
void configPalBDown(void)
{
- if (config.cfg_StdPalNr != PAL_USER_DEFINED)
+ if (config.cfg_StdPalNum != PAL_USER_DEFINED)
showColorErrorMsg();
- else if ((config.specialFlags2 & HARDWARE_MOUSE) && cfg_ColorNr == 3)
+ else if ((config.specialFlags2 & HARDWARE_MOUSE) && cfg_ColorNum == 3)
showMouseColorErrorMsg();
else
scrollBarScrollLeft(SB_PAL_B, 1);
@@ -278,9 +279,9 @@
void configPalBUp(void)
{
- if (config.cfg_StdPalNr != PAL_USER_DEFINED)
+ if (config.cfg_StdPalNum != PAL_USER_DEFINED)
showColorErrorMsg();
- else if ((config.specialFlags2 & HARDWARE_MOUSE) && cfg_ColorNr == 3)
+ else if ((config.specialFlags2 & HARDWARE_MOUSE) && cfg_ColorNum == 3)
showMouseColorErrorMsg();
else
scrollBarScrollRight(SB_PAL_B, 1);
@@ -288,9 +289,9 @@
void configPalContDown(void)
{
- if (config.cfg_StdPalNr != PAL_USER_DEFINED)
+ if (config.cfg_StdPalNum != PAL_USER_DEFINED)
showColorErrorMsg();
- else if ((config.specialFlags2 & HARDWARE_MOUSE) && cfg_ColorNr == 3)
+ else if ((config.specialFlags2 & HARDWARE_MOUSE) && cfg_ColorNum == 3)
showMouseColorErrorMsg();
else
scrollBarScrollLeft(SB_PAL_CONTRAST, 1);
@@ -298,9 +299,9 @@
void configPalContUp(void)
{
- if (config.cfg_StdPalNr != PAL_USER_DEFINED)
+ if (config.cfg_StdPalNum != PAL_USER_DEFINED)
showColorErrorMsg();
- else if ((config.specialFlags2 & HARDWARE_MOUSE) && cfg_ColorNr == 3)
+ else if ((config.specialFlags2 & HARDWARE_MOUSE) && cfg_ColorNum == 3)
showMouseColorErrorMsg();
else
scrollBarScrollRight(SB_PAL_CONTRAST, 1);
@@ -334,7 +335,7 @@
void rbConfigPalPatternText(void)
{
- cfg_ColorNr = 0;
+ cfg_ColorNum = 0;
checkRadioButton(RB_CONFIG_PAL_PATTERNTEXT);
updatePaletteEditor();
}
@@ -341,7 +342,7 @@
void rbConfigPalBlockMark(void)
{
- cfg_ColorNr = 1;
+ cfg_ColorNum = 1;
checkRadioButton(RB_CONFIG_PAL_BLOCKMARK);
updatePaletteEditor();
}
@@ -348,7 +349,7 @@
void rbConfigPalTextOnBlock(void)
{
- cfg_ColorNr = 2;
+ cfg_ColorNum = 2;
checkRadioButton(RB_CONFIG_PAL_TEXTONBLOCK);
updatePaletteEditor();
}
@@ -355,7 +356,7 @@
void rbConfigPalMouse(void)
{
- cfg_ColorNr = 3;
+ cfg_ColorNum = 3;
checkRadioButton(RB_CONFIG_PAL_MOUSE);
updatePaletteEditor();
}
@@ -362,7 +363,7 @@
void rbConfigPalDesktop(void)
{
- cfg_ColorNr = 4;
+ cfg_ColorNum = 4;
checkRadioButton(RB_CONFIG_PAL_DESKTOP);
updatePaletteEditor();
}
@@ -369,7 +370,7 @@
void rbConfigPalButttons(void)
{
- cfg_ColorNr = 5;
+ cfg_ColorNum = 5;
checkRadioButton(RB_CONFIG_PAL_BUTTONS);
updatePaletteEditor();
}
@@ -376,96 +377,96 @@
void rbConfigPalArctic(void)
{
- config.cfg_StdPalNr = PAL_ARCTIC;
+ config.cfg_StdPalNum = PAL_ARCTIC;
updatePaletteEditor();
- setPal16(palTable[config.cfg_StdPalNr], true);
+ setPal16(palTable[config.cfg_StdPalNum], true);
checkRadioButton(RB_CONFIG_PAL_ARCTIC);
}
void rbConfigPalLitheDark(void)
{
- config.cfg_StdPalNr = PAL_LITHE_DARK;
+ config.cfg_StdPalNum = PAL_LITHE_DARK;
updatePaletteEditor();
- setPal16(palTable[config.cfg_StdPalNr], true);
+ setPal16(palTable[config.cfg_StdPalNum], true);
checkRadioButton(RB_CONFIG_PAL_LITHE_DARK);
}
void rbConfigPalAuroraBorealis(void)
{
- config.cfg_StdPalNr = PAL_AURORA_BOREALIS;
+ config.cfg_StdPalNum = PAL_AURORA_BOREALIS;
updatePaletteEditor();
- setPal16(palTable[config.cfg_StdPalNr], true);
+ setPal16(palTable[config.cfg_StdPalNum], true);
checkRadioButton(RB_CONFIG_PAL_AURORA_BOREALIS);
}
void rbConfigPalRose(void)
{
- config.cfg_StdPalNr = PAL_ROSE;
+ config.cfg_StdPalNum = PAL_ROSE;
updatePaletteEditor();
- setPal16(palTable[config.cfg_StdPalNr], true);
+ setPal16(palTable[config.cfg_StdPalNum], true);
checkRadioButton(RB_CONFIG_PAL_ROSE);
}
void rbConfigPalBlues(void)
{
- config.cfg_StdPalNr = PAL_BLUES;
+ config.cfg_StdPalNum = PAL_BLUES;
updatePaletteEditor();
- setPal16(palTable[config.cfg_StdPalNr], true);
+ setPal16(palTable[config.cfg_StdPalNum], true);
checkRadioButton(RB_CONFIG_PAL_BLUES);
}
void rbConfigPalDarkMode(void)
{
- config.cfg_StdPalNr = PAL_DARK_MODE;
+ config.cfg_StdPalNum = PAL_DARK_MODE;
updatePaletteEditor();
- setPal16(palTable[config.cfg_StdPalNr], true);
+ setPal16(palTable[config.cfg_StdPalNum], true);
checkRadioButton(RB_CONFIG_PAL_DARK_MODE);
}
void rbConfigPalGold(void)
{
- config.cfg_StdPalNr = PAL_GOLD;
+ config.cfg_StdPalNum = PAL_GOLD;
updatePaletteEditor();
- setPal16(palTable[config.cfg_StdPalNr], true);
+ setPal16(palTable[config.cfg_StdPalNum], true);
checkRadioButton(RB_CONFIG_PAL_GOLD);
}
void rbConfigPalViolent(void)
{
- config.cfg_StdPalNr = PAL_VIOLENT;
+ config.cfg_StdPalNum = PAL_VIOLENT;
updatePaletteEditor();
- setPal16(palTable[config.cfg_StdPalNr], true);
+ setPal16(palTable[config.cfg_StdPalNum], true);
checkRadioButton(RB_CONFIG_PAL_VIOLENT);
}
void rbConfigPalHeavyMetal(void)
{
- config.cfg_StdPalNr = PAL_HEAVY_METAL;
+ config.cfg_StdPalNum = PAL_HEAVY_METAL;
updatePaletteEditor();
- setPal16(palTable[config.cfg_StdPalNr], true);
+ setPal16(palTable[config.cfg_StdPalNum], true);
checkRadioButton(RB_CONFIG_PAL_HEAVY_METAL);
}
void rbConfigPalWhyColors(void)
{
- config.cfg_StdPalNr = PAL_WHY_COLORS;
+ config.cfg_StdPalNum = PAL_WHY_COLORS;
updatePaletteEditor();
- setPal16(palTable[config.cfg_StdPalNr], true);
+ setPal16(palTable[config.cfg_StdPalNum], true);
checkRadioButton(RB_CONFIG_PAL_WHY_COLORS);
}
void rbConfigPalJungle(void)
{
- config.cfg_StdPalNr = PAL_JUNGLE;
+ config.cfg_StdPalNum = PAL_JUNGLE;
updatePaletteEditor();
- setPal16(palTable[config.cfg_StdPalNr], true);
+ setPal16(palTable[config.cfg_StdPalNum], true);
checkRadioButton(RB_CONFIG_PAL_JUNGLE);
}
void rbConfigPalUserDefined(void)
{
- config.cfg_StdPalNr = PAL_USER_DEFINED;
+ config.cfg_StdPalNum = PAL_USER_DEFINED;
updatePaletteEditor();
- setPal16(palTable[config.cfg_StdPalNr], true);
+ setPal16(palTable[config.cfg_StdPalNum], true);
checkRadioButton(RB_CONFIG_PAL_USER_DEFINED);
}
--- a/src/ft2_palette.h
+++ b/src/ft2_palette.h
@@ -49,8 +49,6 @@
uint8_t r, g, b;
} pal16;
-extern uint8_t cfg_ColorNr;
-
void setCustomPalColor(uint32_t color);
uint8_t palMax(int32_t c);
@@ -88,3 +86,5 @@
void rbConfigPalWhyColors(void);
void rbConfigPalJungle(void);
void rbConfigPalUserDefined(void);
+
+extern uint8_t cfg_ColorNum;
--- a/src/ft2_pattern_draw.c
+++ b/src/ft2_pattern_draw.c
@@ -14,7 +14,7 @@
#include "ft2_bmp.h"
#include "ft2_structs.h"
-static tonTyp emptyPattern[MAX_VOICES * MAX_PATT_LEN];
+static note_t emptyPattern[MAX_CHANNELS * MAX_PATT_LEN];
static const uint8_t *font4Ptr, *font5Ptr;
static const uint8_t vol2charTab1[16] = { 39, 0, 1, 2, 3, 4, 36, 52, 53, 54, 28, 31, 25, 58, 59, 22 };
@@ -36,13 +36,13 @@
static void pattCharOut(uint32_t xPos, uint32_t yPos, uint8_t chr, uint8_t fontType, uint32_t color);
static void drawEmptyNoteSmall(uint32_t xPos, uint32_t yPos, uint32_t color);
static void drawKeyOffSmall(uint32_t xPos, uint32_t yPos, uint32_t color);
-static void drawNoteSmall(uint32_t xPos, uint32_t yPos, int32_t ton, uint32_t color);
+static void drawNoteSmall(uint32_t xPos, uint32_t yPos, int32_t noteNum, uint32_t color);
static void drawEmptyNoteMedium(uint32_t xPos, uint32_t yPos, uint32_t color);
static void drawKeyOffMedium(uint32_t xPos, uint32_t yPos, uint32_t color);
-static void drawNoteMedium(uint32_t xPos, uint32_t yPos, int32_t ton, uint32_t color);
+static void drawNoteMedium(uint32_t xPos, uint32_t yPos, int32_t noteNum, uint32_t color);
static void drawEmptyNoteBig(uint32_t xPos, uint32_t yPos, uint32_t color);
static void drawKeyOffBig(uint32_t xPos, uint32_t yPos, uint32_t color);
-static void drawNoteBig(uint32_t xPos, uint32_t yPos, int32_t ton, uint32_t color);
+static void drawNoteBig(uint32_t xPos, uint32_t yPos, int32_t noteNum, uint32_t color);
void updatePattFontPtrs(void)
{
@@ -54,7 +54,7 @@
void drawPatternBorders(void)
{
// get heights/pos/rows depending on configuration
- const pattCoord2_t *pattCoord = &pattCoord2Table[config.ptnUnpressed][ui.pattChanScrollShown][ui.extended];
+ const pattCoord2_t *pattCoord = &pattCoord2Table[config.ptnStretch][ui.pattChanScrollShown][ui.extended];
// set pattern cursor Y position
editor.ptnCursorY = pattCoord->lowerRowsY - 9;
@@ -66,7 +66,7 @@
// in some configurations, there will be two empty channels to the right, fix that
if (chans == 2)
chans = 4;
- else if (chans == 10 && !config.ptnS3M)
+ else if (chans == 10 && !config.ptnShowVolColumn)
chans = 12;
assert(chans >= 2 && chans <= 12);
@@ -177,7 +177,7 @@
static void writeCursor(void)
{
- const int32_t tabOffset = (config.ptnS3M * 32) + (columnModeTab[ui.numChannelsShown-1] * 8) + cursor.object;
+ const int32_t tabOffset = (config.ptnShowVolColumn * 32) + (columnModeTab[ui.numChannelsShown-1] * 8) + cursor.object;
int32_t xPos = pattCursorXTab[tabOffset];
const int32_t width = pattCursorWTab[tabOffset];
@@ -212,7 +212,7 @@
if (pattMark.markX1 > endCh || pattMark.markX2 < startCh || pattMark.markY1 > endRow || pattMark.markY2 < startRow)
return;
- const markCoord_t *markCoord = &markCoordTable[config.ptnUnpressed][ui.pattChanScrollShown][ui.extended];
+ const markCoord_t *markCoord = &markCoordTable[config.ptnStretch][ui.pattChanScrollShown][ui.extended];
const int32_t pattYStart = markCoord->upperRowsY;
// X1
@@ -264,7 +264,7 @@
}
// kludge! (some mark situations could overwrite illegal areas)
- if (config.ptnUnpressed && ui.pattChanScrollShown)
+ if (config.ptnStretch && ui.pattChanScrollShown)
{
if (y1 == pattCoord->upperRowsY-1 || y1 == pattCoord->lowerRowsY-1)
y1++;
@@ -368,29 +368,29 @@
// DRAWING ROUTINES (WITH VOLUME COLUMN)
-static void showNoteNum(uint32_t xPos, uint32_t yPos, int16_t ton, uint32_t color)
+static void showNoteNum(uint32_t xPos, uint32_t yPos, int16_t note, uint32_t color)
{
xPos += 3;
- assert(ton >= 0 && ton <= 97);
+ assert(note >= 0 && note <= 97);
if (ui.numChannelsShown <= 4)
{
- if (ton <= 0 || ton > 97)
+ if (note <= 0 || note > 97)
drawEmptyNoteBig(xPos, yPos, color);
- else if (ton == 97)
+ else if (note == NOTE_OFF)
drawKeyOffBig(xPos, yPos, color);
else
- drawNoteBig(xPos, yPos, ton, color);
+ drawNoteBig(xPos, yPos, note, color);
}
else
{
- if (ton <= 0 || ton > 97)
+ if (note <= 0 || note > 97)
drawEmptyNoteMedium(xPos, yPos, color);
- else if (ton == 97)
+ else if (note == NOTE_OFF)
drawKeyOffMedium(xPos, yPos, color);
else
- drawNoteMedium(xPos, yPos, ton, color);
+ drawNoteMedium(xPos, yPos, note, color);
}
}
@@ -480,7 +480,7 @@
pattCharOut(xPos + charW, yPos, char2, fontType, color);
}
-static void showEfx(uint32_t xPos, uint32_t yPos, uint8_t effTyp, uint8_t eff, uint32_t color)
+static void showEfx(uint32_t xPos, uint32_t yPos, uint8_t efx, uint8_t efxData, uint32_t color)
{
uint8_t fontType, charW;
@@ -503,45 +503,45 @@
xPos += 55;
}
- pattCharOut(xPos, yPos, effTyp, fontType, color);
- pattCharOut(xPos + charW, yPos, eff >> 4, fontType, color);
- pattCharOut(xPos + (charW * 2), yPos, eff & 0x0F, fontType, color);
+ pattCharOut(xPos, yPos, efx, fontType, color);
+ pattCharOut(xPos + charW, yPos, efxData >> 4, fontType, color);
+ pattCharOut(xPos + (charW * 2), yPos, efxData & 0x0F, fontType, color);
}
// DRAWING ROUTINES (WITHOUT VOLUME COLUMN)
-static void showNoteNumNoVolColumn(uint32_t xPos, uint32_t yPos, int16_t ton, uint32_t color)
+static void showNoteNumNoVolColumn(uint32_t xPos, uint32_t yPos, int16_t note, uint32_t color)
{
xPos += 3;
- assert(ton >= 0 && ton <= 97);
+ assert(note >= 0 && note <= 97);
if (ui.numChannelsShown <= 6)
{
- if (ton <= 0 || ton > 97)
+ if (note <= 0 || note > 97)
drawEmptyNoteBig(xPos, yPos, color);
- else if (ton == 97)
+ else if (note == NOTE_OFF)
drawKeyOffBig(xPos, yPos, color);
else
- drawNoteBig(xPos, yPos, ton, color);
+ drawNoteBig(xPos, yPos, note, color);
}
else if (ui.numChannelsShown <= 8)
{
- if (ton <= 0 || ton > 97)
+ if (note <= 0 || note > 97)
drawEmptyNoteMedium(xPos, yPos, color);
- else if (ton == 97)
+ else if (note == NOTE_OFF)
drawKeyOffMedium(xPos, yPos, color);
else
- drawNoteMedium(xPos, yPos, ton, color);
+ drawNoteMedium(xPos, yPos, note, color);
}
else
{
- if (ton <= 0 || ton > 97)
+ if (note <= 0 || note > 97)
drawEmptyNoteSmall(xPos, yPos, color);
- else if (ton == 97)
+ else if (note == NOTE_OFF)
drawKeyOffSmall(xPos, yPos, color);
else
- drawNoteSmall(xPos, yPos, ton, color);
+ drawNoteSmall(xPos, yPos, note, color);
}
}
@@ -600,7 +600,7 @@
(void)color;
}
-static void showEfxNoVolColumn(uint32_t xPos, uint32_t yPos, uint8_t effTyp, uint8_t eff, uint32_t color)
+static void showEfxNoVolColumn(uint32_t xPos, uint32_t yPos, uint8_t efx, uint8_t efxData, uint32_t color)
{
uint8_t charW, fontType;
@@ -629,12 +629,12 @@
xPos += 31;
}
- pattCharOut(xPos, yPos, effTyp, fontType, color);
- pattCharOut(xPos + charW, yPos, eff >> 4, fontType, color);
- pattCharOut(xPos + (charW * 2), yPos, eff & 0x0F, fontType, color);
+ pattCharOut(xPos, yPos, efx, fontType, color);
+ pattCharOut(xPos + charW, yPos, efxData >> 4, fontType, color);
+ pattCharOut(xPos + (charW * 2), yPos, efxData & 0x0F, fontType, color);
}
-void writePattern(int32_t currRow, int32_t pattern)
+void writePattern(int32_t currRow, int32_t currPattern)
{
uint32_t noteTextColors[2];
@@ -663,8 +663,8 @@
ui.patternChannelWidth = (uint16_t)(chanWidth + 3);
// get heights/pos/rows depending on configuration
- uint32_t rowHeight = config.ptnUnpressed ? 11 : 8;
- const pattCoord_t *pattCoord = &pattCoordTable[config.ptnUnpressed][ui.pattChanScrollShown][ui.extended];
+ uint32_t rowHeight = config.ptnStretch ? 11 : 8;
+ const pattCoord_t *pattCoord = &pattCoordTable[config.ptnStretch][ui.pattChanScrollShown][ui.extended];
const int32_t midRowTextY = pattCoord->midRowTextY;
const int32_t lowerRowsTextY = pattCoord->lowerRowsTextY;
int32_t row = currRow - pattCoord->numUpperRows;
@@ -672,17 +672,15 @@
int32_t textY = pattCoord->upperRowsTextY;
const int32_t afterCurrRow = currRow + 1;
const int32_t numChannels = ui.numChannelsShown;
- tonTyp *pattPtr = patt[pattern];
- const int32_t numRows = pattLens[pattern];
+ note_t *pattPtr = pattern[currPattern];
+ const int32_t numRows = patternNumRows[currPattern];
-
-
// increment pattern data pointer by horizontal scrollbar offset/channel
if (pattPtr != NULL)
pattPtr += ui.channelOffset;
// set up function pointers for drawing
- if (config.ptnS3M)
+ if (config.ptnShowVolColumn)
{
drawNote = showNoteNum;
drawInst = showInstrNum;
@@ -709,19 +707,17 @@
drawRowNums(textY, (uint8_t)row, selectedRowFlag);
- const tonTyp *note = (pattPtr == NULL) ? emptyPattern : &pattPtr[(uint32_t)row * MAX_VOICES];
+ const note_t *p = (pattPtr == NULL) ? emptyPattern : &pattPtr[(uint32_t)row * MAX_CHANNELS];
const int32_t xWidth = ui.patternChannelWidth;
const uint32_t color = noteTextColors[selectedRowFlag];
int32_t xPos = 29;
- for (int32_t j = 0; j < numChannels; j++, note++)
+ for (int32_t j = 0; j < numChannels; j++, p++, xPos += xWidth)
{
- drawNote(xPos, textY, note->ton, color);
- drawInst(xPos, textY, note->instr, color);
- drawVolEfx(xPos, textY, note->vol, color);
- drawEfx(xPos, textY, note->effTyp, note->eff, color);
-
- xPos += xWidth;
+ drawNote(xPos, textY, p->note, color);
+ drawInst(xPos, textY, p->instr, color);
+ drawVolEfx(xPos, textY, p->vol, color);
+ drawEfx(xPos, textY, p->efx, p->efxData, color);
}
}
@@ -932,15 +928,14 @@
}
}
-static void drawNoteSmall(uint32_t xPos, uint32_t yPos, int32_t ton, uint32_t color)
+static void drawNoteSmall(uint32_t xPos, uint32_t yPos, int32_t noteNum, uint32_t color)
{
uint32_t char1, char2;
- assert(ton >= 1 && ton <= 97);
- ton--;
+ noteNum--;
- const uint8_t note = noteTab1[ton];
- const uint32_t char3 = noteTab2[ton] * FONT7_CHAR_W;
+ const uint8_t note = noteTab1[noteNum];
+ const uint32_t char3 = noteTab2[noteNum] * FONT7_CHAR_W;
if (config.ptnAcc == 0)
{
@@ -1039,14 +1034,14 @@
}
}
-static void drawNoteMedium(uint32_t xPos, uint32_t yPos, int32_t ton, uint32_t color)
+static void drawNoteMedium(uint32_t xPos, uint32_t yPos, int32_t noteNum, uint32_t color)
{
uint32_t char1, char2;
- ton--;
+ noteNum--;
- const uint8_t note = noteTab1[ton];
- const uint32_t char3 = noteTab2[ton] * FONT4_CHAR_W;
+ const uint8_t note = noteTab1[noteNum];
+ const uint32_t char3 = noteTab2[noteNum] * FONT4_CHAR_W;
if (config.ptnAcc == 0)
{
@@ -1145,14 +1140,14 @@
}
}
-static void drawNoteBig(uint32_t xPos, uint32_t yPos, int32_t ton, uint32_t color)
+static void drawNoteBig(uint32_t xPos, uint32_t yPos, int32_t noteNum, uint32_t color)
{
uint32_t char1, char2;
- ton--;
+ noteNum--;
- const uint8_t note = noteTab1[ton];
- const uint32_t char3 = noteTab2[ton] * FONT5_CHAR_W;
+ const uint8_t note = noteTab1[noteNum];
+ const uint32_t char3 = noteTab2[noteNum] * FONT5_CHAR_W;
if (config.ptnAcc == 0)
{
--- a/src/ft2_pattern_draw.h
+++ b/src/ft2_pattern_draw.h
@@ -4,5 +4,5 @@
void updatePattFontPtrs(void);
void drawPatternBorders(void);
-void writePattern(int32_t currRow, int32_t pattern);
+void writePattern(int32_t currRow, int32_t currPattern);
void pattTwoHexOut(uint32_t xPos, uint32_t yPos, uint8_t val, uint32_t color);
--- a/src/ft2_pattern_ed.c
+++ b/src/ft2_pattern_ed.c
@@ -13,7 +13,7 @@
#include "ft2_sample_ed.h"
#include "ft2_pattern_draw.h"
#include "ft2_inst_ed.h"
-#include "ft2_scopes.h"
+#include "scopes/ft2_scopes.h"
#include "ft2_diskop.h"
#include "ft2_audio.h"
#include "ft2_wav_renderer.h"
@@ -32,7 +32,7 @@
// for pattern marking w/ mouse
static int32_t lastMarkX1 = -1, lastMarkX2 = -1, lastMarkY1 = -1, lastMarkY2 = -1;
-static const uint8_t ptnAntLine[8] = { 27, 25, 20, 19, 42, 40, 31, 30 };
+static const uint8_t ptnNumRows[8] = { 27, 25, 20, 19, 42, 40, 31, 30 };
static const uint8_t ptnLineSub[8] = { 13, 12, 9, 9, 20, 19, 15, 14 };
static const uint8_t iSwitchExtW[4] = { 40, 40, 40, 39 };
static const uint8_t iSwitchExtY[8] = { 2, 2, 2, 2, 19, 19, 19, 19 };
@@ -42,13 +42,13 @@
static int32_t lastMouseX, lastMouseY;
static int32_t last_TimeH, last_TimeM, last_TimeS;
-bool allocatePattern(uint16_t nr) // for tracker use only, not in loader!
+bool allocatePattern(uint16_t pattNum) // for tracker use only, not in loader!
{
const bool audioWasntLocked = !audio.locked;
if (audioWasntLocked)
lockAudio();
- if (patt[nr] == NULL)
+ if (pattern[pattNum] == NULL)
{
/* Original FT2 allocates only the amount of rows needed, but we don't
** do that to avoid out of bondary row look-up between out-of-sync replayer
@@ -57,8 +57,8 @@
** patterns would be ~10MB.
**/
- patt[nr] = (tonTyp *)calloc((MAX_PATT_LEN * TRACK_WIDTH) + 16, 1);
- if (patt[nr] == NULL)
+ pattern[pattNum] = (note_t *)calloc((MAX_PATT_LEN * TRACK_WIDTH) + 16, 1);
+ if (pattern[pattNum] == NULL)
{
if (audioWasntLocked)
unlockAudio();
@@ -66,7 +66,7 @@
return false;
}
- song.pattLen = pattLens[nr];
+ song.currNumRows = patternNumRows[pattNum];
}
if (audioWasntLocked)
@@ -75,18 +75,18 @@
return true;
}
-void killPatternIfUnused(uint16_t nr) // for tracker use only, not in loader!
+void killPatternIfUnused(uint16_t pattNum) // for tracker use only, not in loader!
{
const bool audioWasntLocked = !audio.locked;
if (audioWasntLocked)
lockAudio();
- if (patternEmpty(nr))
+ if (patternEmpty(pattNum))
{
- if (patt[nr] != NULL)
+ if (pattern[pattNum] != NULL)
{
- free(patt[nr]);
- patt[nr] = NULL;
+ free(pattern[pattNum]);
+ pattern[pattNum] = NULL;
}
}
@@ -97,7 +97,7 @@
uint8_t getMaxVisibleChannels(void)
{
assert(config.ptnMaxChannels >= 0 && config.ptnMaxChannels <= 3);
- if (config.ptnS3M)
+ if (config.ptnShowVolColumn)
return maxVisibleChans1[config.ptnMaxChannels];
else
return maxVisibleChans2[config.ptnMaxChannels];
@@ -360,9 +360,9 @@
if (cursor.ch == 0)
{
- cursor.ch = (uint8_t)(song.antChn - 1);
+ cursor.ch = (uint8_t)(song.numChannels - 1);
if (ui.pattChanScrollShown)
- setScrollBarPos(SB_CHAN_SCROLL, song.antChn, true);
+ setScrollBarPos(SB_CHAN_SCROLL, song.numChannels, true);
}
else
{
@@ -379,7 +379,7 @@
{
cursor.object = CURSOR_NOTE;
- if (cursor.ch >= song.antChn-1)
+ if (cursor.ch >= song.numChannels-1)
{
cursor.ch = 0;
if (ui.pattChanScrollShown)
@@ -427,7 +427,7 @@
{
cursor.object--;
- if (!config.ptnS3M)
+ if (!config.ptnShowVolColumn)
{
while (cursor.object == CURSOR_VOL1 || cursor.object == CURSOR_VOL2)
cursor.object--;
@@ -446,7 +446,7 @@
{
cursor.object++;
- if (!config.ptnS3M)
+ if (!config.ptnShowVolColumn)
{
while (cursor.object == CURSOR_VOL1 || cursor.object == CURSOR_VOL2)
cursor.object++;
@@ -665,7 +665,7 @@
showInstrumentSwitcher();
drawSongLength();
- drawSongRepS();
+ drawSongLoopStart();
drawEditPattern(editor.editPattern);
drawPatternLength(editor.editPattern);
drawPosEdNums(editor.songPos);
@@ -728,11 +728,11 @@
void checkMarkLimits(void)
{
- const uint16_t limitY = pattLens[editor.editPattern];
+ const uint16_t limitY = patternNumRows[editor.editPattern];
pattMark.markY1 = CLAMP(pattMark.markY1, 0, limitY);
pattMark.markY2 = CLAMP(pattMark.markY2, 0, limitY);
- const uint16_t limitX = (uint16_t)(song.antChn - 1);
+ const uint16_t limitX = (uint16_t)(song.numChannels - 1);
pattMark.markX1 = CLAMP(pattMark.markX1, 0, limitX);
pattMark.markX2 = CLAMP(pattMark.markX2, 0, limitX);
@@ -756,8 +756,8 @@
ch = CLAMP(ch, 0, chEnd);
// in some setups there can be non-used channels to the right, do clamping
- if (ch >= song.antChn)
- ch = (int8_t)(song.antChn - 1);
+ if (ch >= song.numChannels)
+ ch = (int8_t)(song.numChannels - 1);
return ch;
}
@@ -764,19 +764,19 @@
static int16_t mouseYToRow(void) // used to get row num from mouse y (for pattern marking)
{
- const pattCoordsMouse_t *pattCoordsMouse = &pattCoordMouseTable[config.ptnUnpressed][ui.pattChanScrollShown][ui.extended];
+ const pattCoordsMouse_t *pattCoordsMouse = &pattCoordMouseTable[config.ptnStretch][ui.pattChanScrollShown][ui.extended];
// clamp mouse y to boundaries
const int16_t maxY = ui.pattChanScrollShown ? 382 : 396;
const int16_t my = (int16_t)CLAMP(mouse.y, pattCoordsMouse->upperRowsY, maxY);
- const uint8_t charHeight = config.ptnUnpressed ? 11 : 8;
+ const uint8_t charHeight = config.ptnStretch ? 11 : 8;
// test top/middle/bottom rows
if (my < pattCoordsMouse->midRowY)
{
// top rows
- int16_t row = editor.pattPos - (pattCoordsMouse->numUpperRows - ((my - pattCoordsMouse->upperRowsY) / charHeight));
+ int16_t row = editor.row - (pattCoordsMouse->numUpperRows - ((my - pattCoordsMouse->upperRowsY) / charHeight));
if (row < 0)
row = 0;
@@ -785,22 +785,22 @@
else if (my >= pattCoordsMouse->midRowY && my <= pattCoordsMouse->midRowY+10)
{
// current row (middle)
- return editor.pattPos;
+ return editor.row;
}
else
{
// bottom rows
- int16_t row = (editor.pattPos + 1) + ((my - pattCoordsMouse->lowerRowsY) / charHeight);
+ int16_t row = (editor.row + 1) + ((my - pattCoordsMouse->lowerRowsY) / charHeight);
// prevent being able to mark the next unseen row on the bottom (in some configurations)
- const uint8_t mode = (ui.extended * 4) + (config.ptnUnpressed * 2) + ui.pattChanScrollShown;
+ const uint8_t mode = (ui.extended * 4) + (config.ptnStretch * 2) + ui.pattChanScrollShown;
- const int16_t maxRow = (ptnAntLine[mode] + (editor.pattPos - ptnLineSub[mode])) - 1;
+ const int16_t maxRow = (ptnNumRows[mode] + (editor.row - ptnLineSub[mode])) - 1;
if (row > maxRow)
row = maxRow;
// clamp to pattern length
- const int16_t patternLen = pattLens[editor.editPattern];
+ const int16_t patternLen = patternNumRows[editor.editPattern];
if (row >= patternLen)
row = patternLen - 1;
@@ -897,8 +897,8 @@
if (mouse.y < y1)
{
- if (editor.pattPos > 0)
- setPos(-1, editor.pattPos - 1, true);
+ if (editor.row > 0)
+ setPos(-1, editor.row - 1, true);
forceMarking = true;
ui.updatePatternEditor = true;
@@ -905,9 +905,9 @@
}
else if (mouse.y > y2)
{
- const int16_t pattLen = pattLens[editor.editPattern];
- if (editor.pattPos < pattLen-1)
- setPos(-1, editor.pattPos + 1, true);
+ const int16_t numRows = patternNumRows[editor.editPattern];
+ if (editor.row < numRows-1)
+ setPos(-1, editor.row + 1, true);
forceMarking = true;
ui.updatePatternEditor = true;
@@ -948,10 +948,10 @@
if (audioWasntLocked)
lockAudio();
- song.pattPos = (song.pattPos - 1 + song.pattLen) % song.pattLen;
+ song.row = (song.row - 1 + song.currNumRows) % song.currNumRows;
if (!songPlaying)
{
- editor.pattPos = (uint8_t)song.pattPos;
+ editor.row = (uint8_t)song.row;
ui.updatePatternEditor = true;
}
@@ -967,12 +967,12 @@
if (songPlaying)
{
- song.timer = 2;
+ song.tick = 2;
}
else
{
- song.pattPos = (song.pattPos + 1 + song.pattLen) % song.pattLen;
- editor.pattPos = (uint8_t)song.pattPos;
+ song.row = (song.row + 1 + song.currNumRows) % song.currNumRows;
+ editor.row = (uint8_t)song.row;
ui.updatePatternEditor = true;
}
@@ -986,13 +986,13 @@
if (audioWasntLocked)
lockAudio();
- song.pattPos -= amount;
- if (song.pattPos < 0)
- song.pattPos = 0;
+ song.row -= amount;
+ if (song.row < 0)
+ song.row = 0;
if (!songPlaying)
{
- editor.pattPos = (uint8_t)song.pattPos;
+ editor.row = (uint8_t)song.row;
ui.updatePatternEditor = true;
}
@@ -1006,13 +1006,13 @@
if (audioWasntLocked)
lockAudio();
- song.pattPos += amount;
- if (song.pattPos >= song.pattLen)
- song.pattPos = song.pattLen - 1;
+ song.row += amount;
+ if (song.row >= song.currNumRows)
+ song.row = song.currNumRows - 1;
if (!songPlaying)
{
- editor.pattPos = (uint8_t)song.pattPos;
+ editor.row = (uint8_t)song.row;
ui.updatePatternEditor = true;
}
@@ -1023,30 +1023,30 @@
void keybPattMarkUp(void)
{
int8_t xPos = cursor.ch;
- int16_t pattPos = editor.pattPos;
+ int16_t row = editor.row;
if (xPos != pattMark.markX1 && xPos != pattMark.markX2)
{
pattMark.markX1 = xPos;
pattMark.markX2 = xPos;
- pattMark.markY1 = pattPos;
- pattMark.markY2 = pattPos + 1;
+ pattMark.markY1 = row;
+ pattMark.markY2 = row + 1;
}
- if (pattPos == pattMark.markY1-1)
+ if (row == pattMark.markY1-1)
{
- pattMark.markY1 = pattPos;
+ pattMark.markY1 = row;
}
- else if (pattPos == pattMark.markY2)
+ else if (row == pattMark.markY2)
{
- pattMark.markY2 = pattPos - 1;
+ pattMark.markY2 = row - 1;
}
- else if (pattPos != pattMark.markY1 && pattPos != pattMark.markY2)
+ else if (row != pattMark.markY1 && row != pattMark.markY2)
{
pattMark.markX1 = xPos;
pattMark.markX2 = xPos;
- pattMark.markY1 = pattPos;
- pattMark.markY2 = pattPos + 1;
+ pattMark.markY1 = row;
+ pattMark.markY2 = row + 1;
}
@@ -1057,30 +1057,30 @@
void keybPattMarkDown(void)
{
int8_t xPos = cursor.ch;
- int16_t pattPos = editor.pattPos;
+ int16_t row = editor.row;
if (xPos != pattMark.markX1 && xPos != pattMark.markX2)
{
pattMark.markX1 = xPos;
pattMark.markX2 = xPos;
- pattMark.markY1 = pattPos;
- pattMark.markY2 = pattPos + 1;
+ pattMark.markY1 = row;
+ pattMark.markY2 = row + 1;
}
- if (pattPos == pattMark.markY2)
+ if (row == pattMark.markY2)
{
- pattMark.markY2 = pattPos + 1;
+ pattMark.markY2 = row + 1;
}
- else if (pattPos == pattMark.markY1-1)
+ else if (row == pattMark.markY1-1)
{
- pattMark.markY1 = pattPos + 2;
+ pattMark.markY1 = row + 2;
}
- else if (pattPos != pattMark.markY1 && pattPos != pattMark.markY2)
+ else if (row != pattMark.markY1 && row != pattMark.markY2)
{
pattMark.markX1 = xPos;
pattMark.markX2 = xPos;
- pattMark.markY1 = pattPos;
- pattMark.markY2 = pattPos + 1;
+ pattMark.markY1 = row;
+ pattMark.markY2 = row + 1;
}
checkMarkLimits();
@@ -1090,12 +1090,12 @@
void keybPattMarkLeft(void)
{
int8_t xPos = cursor.ch;
- int16_t pattPos = editor.pattPos;
+ int16_t row = editor.row;
- if (pattPos != pattMark.markY1-1 && pattPos != pattMark.markY2)
+ if (row != pattMark.markY1-1 && row != pattMark.markY2)
{
- pattMark.markY1 = pattPos - 1;
- pattMark.markY2 = pattPos;
+ pattMark.markY1 = row - 1;
+ pattMark.markY2 = row;
}
if (xPos == pattMark.markX1)
@@ -1110,8 +1110,8 @@
{
pattMark.markX1 = xPos - 1;
pattMark.markX2 = xPos;
- pattMark.markY1 = pattPos - 1;
- pattMark.markY2 = pattPos;
+ pattMark.markY1 = row - 1;
+ pattMark.markY2 = row;
}
checkMarkLimits();
@@ -1121,12 +1121,12 @@
void keybPattMarkRight(void)
{
int8_t xPos = cursor.ch;
- int16_t pattPos = editor.pattPos;
+ int16_t row = editor.row;
- if (pattPos != pattMark.markY1-1 && pattPos != pattMark.markY2)
+ if (row != pattMark.markY1-1 && row != pattMark.markY2)
{
- pattMark.markY1 = pattPos - 1;
- pattMark.markY2 = pattPos;
+ pattMark.markY1 = row - 1;
+ pattMark.markY2 = row;
}
if (xPos == pattMark.markX2)
@@ -1141,8 +1141,8 @@
{
pattMark.markX1 = xPos;
pattMark.markX2 = xPos + 1;
- pattMark.markY1 = pattPos - 1;
- pattMark.markY2 = pattPos;
+ pattMark.markY1 = row - 1;
+ pattMark.markY2 = row;
}
checkMarkLimits();
@@ -1151,8 +1151,8 @@
bool loadTrack(UNICHAR *filenameU)
{
- tonTyp loadBuff[MAX_PATT_LEN];
- trackHeaderType th;
+ note_t loadBuff[MAX_PATT_LEN];
+ xtHdr_t h;
FILE *f = UNICHAR_FOPEN(filenameU, "rb");
if (f == NULL)
@@ -1161,55 +1161,56 @@
return false;
}
- uint16_t nr = editor.editPattern;
- int16_t pattLen = pattLens[nr];
-
- if (fread(&th, 1, sizeof (th), f) != sizeof (th))
+ if (fread(&h, 1, sizeof (h), f) != sizeof (h))
{
okBox(0, "System message", "General I/O error during loading! Is the file in use?");
goto trackLoadError;
}
- if (th.ver != 1)
+ if (h.version != 1)
{
okBox(0, "System message", "Incompatible format version!");
goto trackLoadError;
}
- if (th.len > MAX_PATT_LEN)
- th.len = MAX_PATT_LEN;
+ if (h.numRows > MAX_PATT_LEN)
+ h.numRows = MAX_PATT_LEN;
- if (pattLen > th.len)
- pattLen = th.len;
+ int16_t numRows = patternNumRows[editor.editPattern];
+ if (numRows > h.numRows)
+ numRows = h.numRows;
- if (fread(loadBuff, pattLen * sizeof (tonTyp), 1, f) != 1)
+ if (fread(loadBuff, numRows * sizeof (note_t), 1, f) != 1)
{
okBox(0, "System message", "General I/O error during loading! Is the file in use?");
goto trackLoadError;
}
- if (!allocatePattern(nr))
+ if (!allocatePattern(editor.editPattern))
{
okBox(0, "System message", "Not enough memory!");
goto trackLoadError;
}
- tonTyp *pattPtr = patt[nr];
-
lockMixerCallback();
- for (int32_t i = 0; i < pattLen; i++)
+ for (int32_t i = 0; i < numRows; i++)
{
- pattPtr = &patt[nr][(i * MAX_VOICES) + cursor.ch];
- *pattPtr = loadBuff[i];
+ note_t *p = &pattern[editor.editPattern][(i * MAX_CHANNELS) + cursor.ch];
- // non-FT2 security fix: remove overflown (illegal) stuff
- if (pattPtr->ton > 97)
- pattPtr->ton = 0;
+ *p = loadBuff[i];
- if (pattPtr->effTyp > 35)
+ // sanitize stuff (FT2 doesn't do this!)
+
+ if (p->note > 97)
+ p->note = 0;
+
+ if (p->instr > 128)
+ p->instr = 0;
+
+ if (p->efx > 35)
{
- pattPtr->effTyp = 0;
- pattPtr->eff = 0;
+ p->efx = 0;
+ p->efxData = 0;
}
}
unlockMixerCallback();
@@ -1231,13 +1232,11 @@
bool saveTrack(UNICHAR *filenameU)
{
- tonTyp saveBuff[MAX_PATT_LEN];
- trackHeaderType th;
+ note_t saveBuff[MAX_PATT_LEN];
+ xtHdr_t h;
- uint16_t nr = editor.editPattern;
- tonTyp *pattPtr = patt[nr];
-
- if (pattPtr == NULL)
+ note_t *p = pattern[editor.editPattern];
+ if (p == NULL)
{
okBox(0, "System message", "The current pattern is empty!");
return false;
@@ -1250,14 +1249,13 @@
return false;
}
- const int16_t pattLen = pattLens[nr];
- for (int32_t i = 0; i < pattLen; i++)
- saveBuff[i] = pattPtr[(i * MAX_VOICES) + cursor.ch];
+ h.version = 1;
+ h.numRows = patternNumRows[editor.editPattern];
- th.len = pattLen;
- th.ver = 1;
+ for (int32_t i = 0; i < h.numRows; i++)
+ saveBuff[i] = p[(i * MAX_CHANNELS) + cursor.ch];
- if (fwrite(&th, sizeof (th), 1, f) != 1)
+ if (fwrite(&h, sizeof (h), 1, f) != 1)
{
fclose(f);
okBox(0, "System message", "General I/O error during saving! Is the file in use?");
@@ -1264,7 +1262,7 @@
return false;
}
- if (fwrite(saveBuff, pattLen * sizeof (tonTyp), 1, f) != 1)
+ if (fwrite(saveBuff, h.numRows * sizeof (note_t), 1, f) != 1)
{
fclose(f);
okBox(0, "System message", "General I/O error during saving! Is the file in use?");
@@ -1277,7 +1275,7 @@
bool loadPattern(UNICHAR *filenameU)
{
- patternHeaderType th;
+ xpHdr_t h;
FILE *f = UNICHAR_FOPEN(filenameU, "rb");
if (f == NULL)
@@ -1286,37 +1284,31 @@
return false;
}
- uint16_t nr = editor.editPattern;
-
- if (!allocatePattern(nr))
+ if (!allocatePattern(editor.editPattern))
{
okBox(0, "System message", "Not enough memory!");
goto loadPattError;
}
- tonTyp *pattPtr = patt[nr];
- uint16_t pattLen = pattLens[nr];
-
- if (fread(&th, 1, sizeof (th), f) != sizeof (th))
+ if (fread(&h, 1, sizeof (h), f) != sizeof (h))
{
okBox(0, "System message", "General I/O error during loading! Is the file in use?");
goto loadPattError;
}
- if (th.ver != 1)
+ if (h.version != 1)
{
okBox(0, "System message", "Incompatible format version!");
goto loadPattError;
}
- if (th.len > MAX_PATT_LEN)
- th.len = MAX_PATT_LEN;
+ if (h.numRows > MAX_PATT_LEN)
+ h.numRows = MAX_PATT_LEN;
- pattLen = th.len;
-
lockMixerCallback();
- if (fread(pattPtr, pattLen * TRACK_WIDTH, 1, f) != 1)
+ note_t *p = pattern[editor.editPattern];
+ if (fread(p, h.numRows * TRACK_WIDTH, 1, f) != 1)
{
unlockMixerCallback();
okBox(0, "System message", "General I/O error during loading! Is the file in use?");
@@ -1323,31 +1315,35 @@
goto loadPattError;
}
- // non-FT2 security fix: remove overflown (illegal) stuff
- for (int32_t i = 0; i < pattLen; i++)
+ // sanitize data (FT2 doesn't do this!)
+ for (int32_t row = 0; row < h.numRows; row++)
{
- for (int32_t j = 0; j < MAX_VOICES; j++)
+ for (int32_t ch = 0; ch < MAX_CHANNELS; ch++)
{
- pattPtr = &patt[nr][(i * MAX_VOICES) + j];
- if (pattPtr->ton > 97)
- pattPtr->ton = 0;
+ p = &pattern[editor.editPattern][(row * MAX_CHANNELS) + ch];
- if (pattPtr->effTyp > 35)
+ if (p->note > 97)
+ p->note = 0;
+
+ if (p->instr > 128)
+ p->instr = 128;
+
+ if (p->efx > 35)
{
- pattPtr->effTyp = 0;
- pattPtr->eff = 0;
+ p->efx = 0;
+ p->efxData = 0;
}
}
}
// set new pattern length (FT2 doesn't do this, strange...)
- pattLens[nr] = pattLen;
- song.pattLen = pattLen;
- if (song.pattPos >= pattLen)
+ song.currNumRows = patternNumRows[editor.editPattern] = h.numRows;
+
+ if (song.row >= song.currNumRows)
{
- song.pattPos = pattLen-1;
+ song.row = song.currNumRows-1;
if (!songPlaying)
- editor.pattPos = song.pattPos;
+ editor.row = song.row;
}
unlockMixerCallback();
@@ -1369,12 +1365,10 @@
bool savePattern(UNICHAR *filenameU)
{
- patternHeaderType th;
+ xpHdr_t h;
- uint16_t nr = editor.editPattern;
- tonTyp *pattPtr = patt[nr];
-
- if (pattPtr == NULL)
+ note_t *p = pattern[editor.editPattern];
+ if (p == NULL)
{
okBox(0, "System message", "The current pattern is empty!");
return false;
@@ -1387,12 +1381,10 @@
return false;
}
- uint16_t pattLen = pattLens[nr];
-
- th.len = pattLen;
- th.ver = 1;
-
- if (fwrite(&th, 1, sizeof (th), f) != sizeof (th))
+ h.version = 1;
+ h.numRows = patternNumRows[editor.editPattern];
+
+ if (fwrite(&h, 1, sizeof (h), f) != sizeof (h))
{
fclose(f);
okBox(0, "System message", "General I/O error during saving! Is the file in use?");
@@ -1399,7 +1391,7 @@
return false;
}
- if (fwrite(pattPtr, pattLen * TRACK_WIDTH, 1, f) != 1)
+ if (fwrite(p, h.numRows * TRACK_WIDTH, 1, f) != 1)
{
fclose(f);
okBox(0, "System message", "General I/O error during saving! Is the file in use?");
@@ -1433,9 +1425,9 @@
ui.channelOffset = (uint8_t)pos;
- assert(song.antChn > ui.numChannelsShown);
- if (ui.channelOffset >= song.antChn-ui.numChannelsShown)
- ui.channelOffset = (uint8_t)(song.antChn-ui.numChannelsShown);
+ assert(song.numChannels > ui.numChannelsShown);
+ if (ui.channelOffset >= song.numChannels-ui.numChannelsShown)
+ ui.channelOffset = (uint8_t)(song.numChannels-ui.numChannelsShown);
if (cursor.ch >= ui.channelOffset+ui.numChannelsShown)
{
@@ -1451,26 +1443,26 @@
ui.updatePatternEditor = true;
}
-void jumpToChannel(uint8_t channel) // for ALT+q..i ALT+a..k
+void jumpToChannel(uint8_t chNr) // for ALT+q..i ALT+a..k
{
if (ui.sampleEditorShown || ui.instEditorShown)
return;
- channel %= song.antChn;
- if (cursor.ch == channel)
+ chNr %= song.numChannels;
+ if (cursor.ch == chNr)
return;
if (ui.pattChanScrollShown)
{
- assert(song.antChn > ui.numChannelsShown);
+ assert(song.numChannels > ui.numChannelsShown);
- if (channel >= ui.channelOffset+ui.numChannelsShown)
- scrollBarScrollDown(SB_CHAN_SCROLL, (channel - (ui.channelOffset + ui.numChannelsShown)) + 1);
- else if (channel < ui.channelOffset)
- scrollBarScrollUp(SB_CHAN_SCROLL, ui.channelOffset - channel);
+ if (chNr >= ui.channelOffset+ui.numChannelsShown)
+ scrollBarScrollDown(SB_CHAN_SCROLL, (chNr - (ui.channelOffset + ui.numChannelsShown)) + 1);
+ else if (chNr < ui.channelOffset)
+ scrollBarScrollUp(SB_CHAN_SCROLL, ui.channelOffset - chNr);
}
- cursor.ch = channel; // set it here since scrollBarScrollX() changes it...
+ cursor.ch = chNr; // set it here since scrollBarScrollX() changes it...
ui.updatePatternEditor = true;
}
@@ -1499,17 +1491,17 @@
void pbPosEdIns(void)
{
- if (song.len >= 255)
+ if (song.songLength >= 255)
return;
lockMixerCallback();
- const uint8_t oldPatt = song.songTab[song.songPos];
+ const uint8_t oldPatt = song.orders[song.songPos];
for (uint16_t i = 0; i < 255-song.songPos; i++)
- song.songTab[255-i] = song.songTab[254-i];
- song.songTab[song.songPos] = oldPatt;
+ song.orders[255-i] = song.orders[254-i];
+ song.orders[song.songPos] = oldPatt;
- song.len++;
+ song.songLength++;
ui.updatePosSections = true;
ui.updatePosEdScrollBar = true;
@@ -1520,7 +1512,7 @@
void pbPosEdDel(void)
{
- if (song.len <= 1)
+ if (song.songLength <= 1)
return;
lockMixerCallback();
@@ -1528,16 +1520,16 @@
if (song.songPos < 254)
{
for (uint16_t i = 0; i < 254-song.songPos; i++)
- song.songTab[song.songPos+i] = song.songTab[song.songPos+1+i];
+ song.orders[song.songPos+i] = song.orders[song.songPos+1+i];
}
- song.len--;
- if (song.repS >= song.len)
- song.repS = song.len - 1;
+ song.songLength--;
+ if (song.songLoopStart >= song.songLength)
+ song.songLoopStart = song.songLength - 1;
- if (song.songPos > song.len-1)
+ if (song.songPos > song.songLength-1)
{
- editor.songPos = song.songPos = song.len-1;
+ editor.songPos = song.songPos = song.songLength-1;
setPos(song.songPos, -1, false);
}
@@ -1550,25 +1542,25 @@
void pbPosEdPattUp(void)
{
- if (song.songTab[song.songPos] == 255)
+ if (song.orders[song.songPos] == 255)
return;
lockMixerCallback();
- if (song.songTab[song.songPos] < 255)
+ if (song.orders[song.songPos] < 255)
{
- song.songTab[song.songPos]++;
- song.pattNr = song.songTab[song.songPos];
+ song.orders[song.songPos]++;
+ song.pattNum = song.orders[song.songPos];
- song.pattLen = pattLens[song.pattNr];
- if (song.pattPos >= song.pattLen)
+ song.currNumRows = patternNumRows[song.pattNum];
+ if (song.row >= song.currNumRows)
{
- song.pattPos = song.pattLen-1;
+ song.row = song.currNumRows-1;
if (!songPlaying)
- editor.pattPos = song.pattPos;
+ editor.row = song.row;
}
if (!songPlaying)
- editor.editPattern = (uint8_t)song.pattNr;
+ editor.editPattern = (uint8_t)song.pattNum;
checkMarkLimits();
ui.updatePatternEditor = true;
@@ -1581,25 +1573,25 @@
void pbPosEdPattDown(void)
{
- if (song.songTab[song.songPos] == 0)
+ if (song.orders[song.songPos] == 0)
return;
lockMixerCallback();
- if (song.songTab[song.songPos] > 0)
+ if (song.orders[song.songPos] > 0)
{
- song.songTab[song.songPos]--;
- song.pattNr = song.songTab[song.songPos];
+ song.orders[song.songPos]--;
+ song.pattNum = song.orders[song.songPos];
- song.pattLen = pattLens[song.pattNr];
- if (song.pattPos >= song.pattLen)
+ song.currNumRows = patternNumRows[song.pattNum];
+ if (song.row >= song.currNumRows)
{
- song.pattPos = song.pattLen-1;
+ song.row = song.currNumRows-1;
if (!songPlaying)
- editor.pattPos = song.pattPos;
+ editor.row = song.row;
}
if (!songPlaying)
- editor.editPattern = (uint8_t)song.pattNr;
+ editor.editPattern = (uint8_t)song.pattNum;
checkMarkLimits();
ui.updatePatternEditor = true;
@@ -1612,7 +1604,7 @@
void pbPosEdLenUp(void)
{
- if (song.len >= 255)
+ if (song.songLength >= 255)
return;
const bool audioWasntLocked = !audio.locked;
@@ -1619,7 +1611,7 @@
if (audioWasntLocked)
lockAudio();
- song.len++;
+ song.songLength++;
ui.updatePosSections = true;
ui.updatePosEdScrollBar = true;
@@ -1631,7 +1623,7 @@
void pbPosEdLenDown(void)
{
- if (song.len <= 1)
+ if (song.songLength <= 1)
return;
const bool audioWasntLocked = !audio.locked;
@@ -1638,14 +1630,13 @@
if (audioWasntLocked)
lockAudio();
- song.len--;
+ song.songLength--;
+ if (song.songLoopStart >= song.songLength)
+ song.songLoopStart = song.songLength - 1;
- if (song.repS >= song.len)
- song.repS = song.len - 1;
-
- if (song.songPos >= song.len)
+ if (song.songPos >= song.songLength)
{
- song.songPos = song.len - 1;
+ song.songPos = song.songLength - 1;
setPos(song.songPos, -1, false);
}
@@ -1663,9 +1654,9 @@
if (audioWasntLocked)
lockAudio();
- if (song.repS < song.len-1)
+ if (song.songLoopStart < song.songLength-1)
{
- song.repS++;
+ song.songLoopStart++;
ui.updatePosSections = true;
setSongModifiedFlag();
}
@@ -1680,9 +1671,9 @@
if (audioWasntLocked)
lockAudio();
- if (song.repS > 0)
+ if (song.songLoopStart > 0)
{
- song.repS--;
+ song.songLoopStart--;
ui.updatePosSections = true;
setSongModifiedFlag();
}
@@ -1693,7 +1684,7 @@
void pbBPMUp(void)
{
- if (song.speed == 255)
+ if (song.BPM == 255)
return;
const bool audioWasntLocked = !audio.locked;
@@ -1700,16 +1691,16 @@
if (audioWasntLocked)
lockAudio();
- if (song.speed < 255)
+ if (song.BPM < 255)
{
- song.speed++;
- P_SetSpeed(song.speed);
+ song.BPM++;
+ setMixerBPM(song.BPM);
// if song is playing, the update is handled in the audio/video sync queue
if (!songPlaying)
{
- editor.speed = song.speed;
- drawSongBPM(song.speed);
+ editor.BPM = song.BPM;
+ drawSongBPM(song.BPM);
}
}
@@ -1719,7 +1710,7 @@
void pbBPMDown(void)
{
- if (song.speed == 32)
+ if (song.BPM == 32)
return;
const bool audioWasntLocked = !audio.locked;
@@ -1726,16 +1717,16 @@
if (audioWasntLocked)
lockAudio();
- if (song.speed > 32)
+ if (song.BPM > 32)
{
- song.speed--;
- P_SetSpeed(song.speed);
+ song.BPM--;
+ setMixerBPM(song.BPM);
// if song is playing, the update is handled in the audio/video sync queue
if (!songPlaying)
{
- editor.speed = song.speed;
- drawSongBPM(editor.speed);
+ editor.BPM = song.BPM;
+ drawSongBPM(editor.BPM);
}
}
@@ -1745,7 +1736,7 @@
void pbSpeedUp(void)
{
- if (song.tempo == 31)
+ if (song.speed == 31)
return;
const bool audioWasntLocked = !audio.locked;
@@ -1752,15 +1743,15 @@
if (audioWasntLocked)
lockAudio();
- if (song.tempo < 31)
+ if (song.speed < 31)
{
- song.tempo++;
+ song.speed++;
// if song is playing, the update is handled in the audio/video sync queue
if (!songPlaying)
{
- editor.tempo = song.tempo;
- drawSongSpeed(editor.tempo);
+ editor.speed = song.speed;
+ drawSongSpeed(editor.speed);
}
}
@@ -1770,7 +1761,7 @@
void pbSpeedDown(void)
{
- if (song.tempo == 0)
+ if (song.speed == 0)
return;
const bool audioWasntLocked = !audio.locked;
@@ -1777,15 +1768,15 @@
if (audioWasntLocked)
lockAudio();
- if (song.tempo > 0)
+ if (song.speed > 0)
{
- song.tempo--;
+ song.speed--;
// if song is playing, the update is handled in the audio/video sync queue
if (!songPlaying)
{
- editor.tempo = song.tempo;
- drawSongSpeed(editor.tempo);
+ editor.speed = song.speed;
+ drawSongSpeed(editor.speed);
}
}
@@ -1795,10 +1786,10 @@
void pbIncAdd(void)
{
- if (editor.ID_Add == 16)
- editor.ID_Add = 0;
+ if (editor.editRowSkip == 16)
+ editor.editRowSkip = 0;
else
- editor.ID_Add++;
+ editor.editRowSkip++;
drawIDAdd();
}
@@ -1805,10 +1796,10 @@
void pbDecAdd(void)
{
- if (editor.ID_Add == 0)
- editor.ID_Add = 16;
+ if (editor.editRowSkip == 0)
+ editor.editRowSkip = 16;
else
- editor.ID_Add--;
+ editor.editRowSkip--;
drawIDAdd();
}
@@ -1815,11 +1806,11 @@
void pbAddChan(void)
{
- if (song.antChn > 30)
+ if (song.numChannels > 30)
return;
lockMixerCallback();
- song.antChn += 2;
+ song.numChannels += 2;
hideTopScreen();
showTopLeftMainScreen(true);
@@ -1834,12 +1825,12 @@
void pbSubChan(void)
{
- if (song.antChn < 4)
+ if (song.numChannels < 4)
return;
lockMixerCallback();
- song.antChn -= 2;
+ song.numChannels -= 2;
checkMarkLimits();
@@ -1860,20 +1851,20 @@
if (audioWasntLocked)
lockAudio();
- if (song.pattNr < 255)
+ if (song.pattNum < 255)
{
- song.pattNr++;
+ song.pattNum++;
- song.pattLen = pattLens[song.pattNr];
- if (song.pattPos >= song.pattLen)
+ song.currNumRows = patternNumRows[song.pattNum];
+ if (song.row >= song.currNumRows)
{
- song.pattPos = song.pattLen-1;
+ song.row = song.currNumRows-1;
if (!songPlaying)
- editor.pattPos = song.pattPos;
+ editor.row = song.row;
}
if (!songPlaying)
- editor.editPattern = (uint8_t)song.pattNr;
+ editor.editPattern = (uint8_t)song.pattNum;
checkMarkLimits();
ui.updatePatternEditor = true;
@@ -1890,20 +1881,20 @@
if (audioWasntLocked)
lockAudio();
- if (song.pattNr > 0)
+ if (song.pattNum > 0)
{
- song.pattNr--;
+ song.pattNum--;
- song.pattLen = pattLens[song.pattNr];
- if (song.pattPos >= song.pattLen)
+ song.currNumRows = patternNumRows[song.pattNum];
+ if (song.row >= song.currNumRows)
{
- song.pattPos = song.pattLen-1;
+ song.row = song.currNumRows-1;
if (!songPlaying)
- editor.pattPos = song.pattPos;
+ editor.row = song.row;
}
if (!songPlaying)
- editor.editPattern = (uint8_t)song.pattNr;
+ editor.editPattern = (uint8_t)song.pattNum;
checkMarkLimits();
ui.updatePatternEditor = true;
@@ -1916,8 +1907,8 @@
void pbPattLenUp(void)
{
- const uint16_t pattLen = pattLens[editor.editPattern];
- if (pattLen >= 256)
+ const uint16_t numRows = patternNumRows[editor.editPattern];
+ if (numRows >= MAX_PATT_LEN)
return;
const bool audioWasntLocked = !audio.locked;
@@ -1924,8 +1915,8 @@
if (audioWasntLocked)
lockAudio();
- setPatternLen(editor.editPattern, pattLen + 1);
- checkMarkLimits();
+ song.pattNum = editor.editPattern; // kludge
+ setPatternLen(editor.editPattern, numRows+1);
ui.updatePatternEditor = true;
ui.updatePosSections = true;
@@ -1937,8 +1928,8 @@
void pbPattLenDown(void)
{
- const uint16_t pattLen = pattLens[editor.editPattern];
- if (pattLen <= 1)
+ const uint16_t numRows = patternNumRows[editor.editPattern];
+ if (numRows <= 1)
return;
const bool audioWasntLocked = !audio.locked;
@@ -1945,8 +1936,8 @@
if (audioWasntLocked)
lockAudio();
- setPatternLen(editor.editPattern, pattLen - 1);
- checkMarkLimits();
+ song.pattNum = editor.editPattern; // kludge
+ setPatternLen(editor.editPattern, numRows-1);
ui.updatePatternEditor = true;
ui.updatePosSections = true;
@@ -1958,8 +1949,8 @@
void drawPosEdNums(int16_t songPos)
{
- if (songPos >= song.len)
- songPos = song.len - 1;
+ if (songPos >= song.songLength)
+ songPos = song.songLength - 1;
// clear
if (ui.extended)
@@ -1990,12 +1981,12 @@
if (ui.extended)
{
pattTwoHexOut(8, 4 + (y * 9), (uint8_t)entry, color1);
- pattTwoHexOut(32, 4 + (y * 9), song.songTab[entry], color1);
+ pattTwoHexOut(32, 4 + (y * 9), song.orders[entry], color1);
}
else
{
pattTwoHexOut(8, 4 + (y * 8), (uint8_t)entry, color1);
- pattTwoHexOut(32, 4 + (y * 8), song.songTab[entry], color1);
+ pattTwoHexOut(32, 4 + (y * 8), song.orders[entry], color1);
}
}
@@ -2005,12 +1996,12 @@
if (ui.extended)
{
pattTwoHexOut(8, 23, (uint8_t)songPos, color2);
- pattTwoHexOut(32, 23, song.songTab[songPos], color2);
+ pattTwoHexOut(32, 23, song.orders[songPos], color2);
}
else
{
pattTwoHexOut(8, 22, (uint8_t)songPos, color2);
- pattTwoHexOut(32, 22, song.songTab[songPos], color2);
+ pattTwoHexOut(32, 22, song.orders[songPos], color2);
}
// bottom two
@@ -2017,18 +2008,18 @@
for (int16_t y = 0; y < 2; y++)
{
int16_t entry = songPos + (1 + y);
- if (entry >= song.len)
+ if (entry >= song.songLength)
break;
if (ui.extended)
{
pattTwoHexOut(8, 33 + (y * 9), (uint8_t)entry, color1);
- pattTwoHexOut(32, 33 + (y * 9), song.songTab[entry], color1);
+ pattTwoHexOut(32, 33 + (y * 9), song.orders[entry], color1);
}
else
{
pattTwoHexOut(8, 32 + (y * 8), (uint8_t)entry, color1);
- pattTwoHexOut(32, 32 + (y * 8), song.songTab[entry], color1);
+ pattTwoHexOut(32, 32 + (y * 8), song.orders[entry], color1);
}
}
}
@@ -2048,10 +2039,10 @@
y = 52;
}
- hexOutBg(x, y, PAL_FORGRND, PAL_DESKTOP, (uint8_t)song.len, 2);
+ hexOutBg(x, y, PAL_FORGRND, PAL_DESKTOP, (uint8_t)song.songLength, 2);
}
-void drawSongRepS(void)
+void drawSongLoopStart(void)
{
int16_t x, y;
@@ -2066,36 +2057,18 @@
y = 64;
}
- hexOutBg(x, y, PAL_FORGRND, PAL_DESKTOP, (uint8_t)song.repS, 2);
+ hexOutBg(x, y, PAL_FORGRND, PAL_DESKTOP, (uint8_t)song.songLoopStart, 2);
}
void drawSongBPM(uint16_t val)
{
- char str[4];
- const char *strOut;
-
if (ui.extended)
return;
- if (val <= 255)
- {
- strOut = dec3StrTab[val];
- }
- else
- {
- if (val > MAX_BPM)
- val = MAX_BPM;
+ if (val > 255)
+ val = 255;
- assert(MAX_BPM == 999);
- str[0] = '0' + (char)(val / 100);
- str[1] = '0' + ((val / 10) % 10);
- str[2] = '0' + (val % 10);
- str[3] = 0;
-
- strOut = str;
- }
-
- textOutFixed(145, 36, PAL_FORGRND, PAL_DESKTOP, strOut);
+ textOutFixed(145, 36, PAL_FORGRND, PAL_DESKTOP, dec3StrTab[val]);
}
void drawSongSpeed(uint16_t val)
@@ -2142,7 +2115,7 @@
y = 50;
}
- hexOutBg(x, y, PAL_FORGRND, PAL_DESKTOP, pattLens[editPattern], 3);
+ hexOutBg(x, y, PAL_FORGRND, PAL_DESKTOP, patternNumRows[editPattern], 3);
}
void drawGlobalVol(uint16_t val)
@@ -2156,8 +2129,8 @@
void drawIDAdd(void)
{
- assert(editor.ID_Add <= 16);
- textOutFixed(152, 64, PAL_FORGRND, PAL_DESKTOP, dec2StrTab[editor.ID_Add]);
+ assert(editor.editRowSkip <= 16);
+ textOutFixed(152, 64, PAL_FORGRND, PAL_DESKTOP, dec2StrTab[editor.editRowSkip]);
}
void resetPlaybackTime(void)
@@ -2173,10 +2146,14 @@
if (songPlaying)
{
const uint32_t ms1024 = song.musicTime64 >> 32; // milliseconds (scaled from 1000 to 1024)
-
uint32_t seconds = ms1024 >> 10;
- last_TimeH = seconds / 3600; seconds -= last_TimeH * 3600;
- last_TimeM = seconds / 60; seconds -= last_TimeM * 60;
+
+ last_TimeH = seconds / 3600;
+ seconds -= last_TimeH * 3600;
+
+ last_TimeM = seconds / 60;
+ seconds -= last_TimeM * 60;
+
last_TimeS = seconds;
}
@@ -2584,37 +2561,37 @@
{
lockMixerCallback();
- song.len = 1;
- song.repS = 0; // Bug: FT2 doesn't do this!
- song.speed = 125;
- song.tempo = 6;
+ song.songLength = 1;
+ song.songLoopStart = 0; // FT2 doesn't do this!
+ song.BPM = 125;
+ song.speed = 6;
song.songPos = 0;
- song.globVol = 64;
+ song.globalVolume = 64;
memset(song.name, 0, sizeof (song.name));
- memset(song.songTab, 0, sizeof (song.songTab));
+ memset(song.orders, 0, sizeof (song.orders));
// zero all pattern data and reset pattern lengths
freeAllPatterns();
- for (uint16_t i = 0; i < MAX_PATTERNS; i++)
- pattLens[i] = 64;
- song.pattLen = pattLens[song.pattNr];
+ for (int32_t i = 0; i < MAX_PATTERNS; i++)
+ patternNumRows[i] = 64;
+ song.currNumRows = patternNumRows[song.pattNum];
resetMusic();
- P_SetSpeed(song.speed);
+ setMixerBPM(song.BPM);
editor.songPos = song.songPos;
- editor.editPattern = song.pattNr;
+ editor.editPattern = song.pattNum;
+ editor.BPM = song.BPM;
editor.speed = song.speed;
- editor.tempo = song.tempo;
- editor.globalVol = song.globVol;
- editor.timer = 1;
+ editor.globalVolume = song.globalVolume;
+ editor.tick = 1;
resetPlaybackTime();
if (!audio.linearPeriodsFlag)
- setFrqTab(true);
+ setFrequencyTable(true);
clearPattMark();
resetWavRenderer();
@@ -2622,7 +2599,7 @@
unlockMixerCallback();
setScrollBarPos(SB_POS_ED, 0, false);
- setScrollBarEnd(SB_POS_ED, (song.len - 1) + 5);
+ setScrollBarEnd(SB_POS_ED, (song.songLength - 1) + 5);
updateWindowTitle(true);
}
@@ -2705,7 +2682,7 @@
void resetChannelOffset(void)
{
- ui.pattChanScrollShown = song.antChn > getMaxVisibleChannels();
+ ui.pattChanScrollShown = song.numChannels > getMaxVisibleChannels();
cursor.object = CURSOR_NOTE;
cursor.ch = 0;
setScrollBarPos(SB_CHAN_SCROLL, 0, true);
@@ -2717,48 +2694,46 @@
if (okBox(2, "System request", "Shrink pattern?") != 1)
return;
- uint16_t nr = editor.editPattern;
+ int16_t numRows = patternNumRows[editor.editPattern];
+ if (numRows <= 1)
+ return;
- int16_t pattLen = pattLens[nr];
- if (pattLen > 1)
- {
- lockMixerCallback();
+ lockMixerCallback();
- tonTyp *pattPtr = patt[nr];
- if (pattPtr != NULL)
+ note_t *p = pattern[editor.editPattern];
+ if (p != NULL)
+ {
+ const int32_t length = numRows >> 1;
+ for (int32_t i = 0; i < length; i++)
{
- for (int32_t i = 0; i < pattLen/2; i++)
- {
- for (int32_t j = 0; j < MAX_VOICES; j++)
- pattPtr[(i * MAX_VOICES) + j] = pattPtr[((i * 2) * MAX_VOICES) + j];
- }
+ for (int32_t j = 0; j < MAX_CHANNELS; j++)
+ p[(i * MAX_CHANNELS) + j] = p[((i*2) * MAX_CHANNELS) + j];
}
+ }
- pattLens[nr] >>= 1;
+ patternNumRows[editor.editPattern] >>= 1;
+ numRows = patternNumRows[editor.editPattern];
- if (song.pattNr == nr)
- song.pattLen = pattLens[nr];
+ if (song.pattNum == editor.editPattern)
+ song.currNumRows = numRows;
- song.pattPos >>= 1;
- if (song.pattPos >= pattLens[nr])
- song.pattPos = pattLens[nr] - 1;
+ song.row >>= 1;
+ if (song.row >= numRows)
+ song.row = numRows-1;
- editor.pattPos = song.pattPos;
+ editor.row = song.row;
- ui.updatePatternEditor = true;
- ui.updatePosSections = true;
+ ui.updatePatternEditor = true;
+ ui.updatePosSections = true;
- unlockMixerCallback();
- setSongModifiedFlag();
- }
+ unlockMixerCallback();
+ setSongModifiedFlag();
}
void expandPattern(void)
{
- uint16_t nr = editor.editPattern;
-
- int16_t pattLen = pattLens[nr];
- if (pattLen > 128)
+ int16_t numRows = patternNumRows[editor.editPattern];
+ if (numRows > 128)
{
okBox(0, "System message", "Pattern is too long to be expanded.");
}
@@ -2766,9 +2741,9 @@
{
lockMixerCallback();
- if (patt[nr] != NULL)
+ if (pattern[editor.editPattern] != NULL)
{
- tonTyp *tmpPtn = (tonTyp *)malloc((pattLen * 2) * TRACK_WIDTH);
+ note_t *tmpPtn = (note_t *)malloc((numRows * 2) * TRACK_WIDTH);
if (tmpPtn == NULL)
{
unlockMixerCallback();
@@ -2776,28 +2751,29 @@
return;
}
- for (int32_t i = 0; i < pattLen; i++)
+ for (int32_t i = 0; i < numRows; i++)
{
- for (int32_t j = 0; j < MAX_VOICES; j++)
- tmpPtn[((i * 2) * MAX_VOICES) + j] = patt[nr][(i * MAX_VOICES) + j];
+ for (int32_t j = 0; j < MAX_CHANNELS; j++)
+ tmpPtn[((i * 2) * MAX_CHANNELS) + j] = pattern[editor.editPattern][(i * MAX_CHANNELS) + j];
- memset(&tmpPtn[((i * 2) + 1) * MAX_VOICES], 0, TRACK_WIDTH);
+ memset(&tmpPtn[((i * 2) + 1) * MAX_CHANNELS], 0, TRACK_WIDTH);
}
- free(patt[nr]);
- patt[nr] = tmpPtn;
+ free(pattern[editor.editPattern]);
+ pattern[editor.editPattern] = tmpPtn;
}
- pattLens[nr] *= 2;
+ patternNumRows[editor.editPattern] *= 2;
+ numRows = patternNumRows[editor.editPattern];
- if (song.pattNr == nr)
- song.pattLen = pattLens[nr];
+ if (song.pattNum == editor.editPattern)
+ song.currNumRows = numRows;
- song.pattPos *= 2;
- if (song.pattPos >= pattLens[nr])
- song.pattPos = pattLens[nr] - 1;
+ song.row *= 2;
+ if (song.row >= numRows)
+ song.row = numRows-1;
- editor.pattPos = song.pattPos;
+ editor.row = song.row;
ui.updatePatternEditor = true;
ui.updatePosSections = true;
--- a/src/ft2_pattern_ed.h
+++ b/src/ft2_pattern_ed.h
@@ -18,15 +18,15 @@
TRANSP_BLOCK = 3
};
-typedef struct trackHeaderType_t
+typedef struct xtHdr_t
{
- uint16_t ver, len;
-} trackHeaderType;
+ uint16_t version, numRows;
+} xtHdr_t;
-typedef struct patternHeaderType_t
+typedef struct xpHdr_t
{
- uint16_t ver, len;
-} patternHeaderType;
+ uint16_t version, numRows;
+} xpHdr_t;
typedef struct pattCoord_t
{
@@ -61,8 +61,8 @@
void resetPlaybackTime(void);
-bool allocatePattern(uint16_t nr);
-void killPatternIfUnused(uint16_t nr);
+bool allocatePattern(uint16_t pattNum);
+void killPatternIfUnused(uint16_t pattNum);
uint8_t getMaxVisibleChannels(void);
void updatePatternWidth(void);
void updateAdvEdit(void);
@@ -106,7 +106,7 @@
void scrollChannelLeft(void);
void scrollChannelRight(void);
void setChannelScrollPos(uint32_t pos);
-void jumpToChannel(uint8_t channel); // for ALT+q..i ALT+a..k
+void jumpToChannel(uint8_t chNr); // for ALT+q..i ALT+a..k
void sbPosEdPos(uint32_t pos);
void pbPosEdPosUp(void);
void pbPosEdPosDown(void);
@@ -132,7 +132,7 @@
void pbPattLenDown(void);
void drawPosEdNums(int16_t songPos);
void drawSongLength(void);
-void drawSongRepS(void);
+void drawSongLoopStart(void);
void drawSongBPM(uint16_t val);
void drawSongSpeed(uint16_t val);
void drawEditPattern(uint16_t editPattern);
--- a/src/ft2_pushbuttons.c
+++ b/src/ft2_pushbuttons.c
@@ -219,7 +219,7 @@
{ 300, 382, 50, 16, 0, 0, "X-Fade", NULL, NULL, sampXFade },
{ 430, 348, 54, 16, 0, 0, "Exit", NULL, NULL, exitSampleEditor },
{ 594, 348, 35, 13, 0, 0, "Clr S.", NULL, NULL, clearSample },
- { 594, 360, 35, 13, 0, 0, "Min.", NULL, NULL, sampMin },
+ { 594, 360, 35, 13, 0, 0, "Min.", NULL, NULL, sampMinimize },
{ 594, 373, 18, 13, 2, 4, ARROW_UP_STRING, NULL, sampRepeatUp, NULL },
{ 611, 373, 18, 13, 2, 4, ARROW_DOWN_STRING, NULL, sampRepeatDown, NULL },
{ 594, 385, 18, 13, 2, 4, ARROW_UP_STRING, NULL, sampReplenUp, NULL },
@@ -228,10 +228,10 @@
// ------ SAMPLE EDITOR EXTENSION PUSHBUTTONS ------
//x, y, w, h, p, d, text #1, text #2, funcOnDown, funcOnUp
{ 3, 138, 52, 16, 0, 0, "Clr. c.bf", NULL, NULL, clearCopyBuffer },
- { 56, 138, 49, 16, 0, 0, "Conv", NULL, NULL, sampleConv },
+ { 56, 138, 49, 16, 0, 0, "Sign", NULL, NULL, sampleChangeSign },
{ 106, 138, 49, 16, 0, 0, "Echo", NULL, NULL, pbSampleEcho },
{ 3, 155, 52, 16, 0, 0, "Backw.", NULL, NULL, sampleBackwards },
- { 56, 155, 49, 16, 0, 0, "Conv W", NULL, NULL, sampleConvW },
+ { 56, 155, 49, 16, 0, 0, "B. swap", NULL, NULL, sampleByteSwap },
{ 106, 155, 49, 16, 0, 0, "Fix DC", NULL, NULL, fixDC },
{ 161, 121, 60, 16, 0, 0, "Copy ins.", NULL, NULL, copyInstr },
{ 222, 121, 66, 16, 0, 0, "Copy smp.", NULL, NULL, copySmp },
@@ -285,10 +285,10 @@
{ 606, 248, 23, 13, 1, 4, ARROW_RIGHT_STRING, NULL, vibDepthUp, NULL },
{ 521, 262, 23, 13, 1, 4, ARROW_LEFT_STRING, NULL, vibSweepDown, NULL },
{ 606, 262, 23, 13, 1, 4, ARROW_RIGHT_STRING, NULL, vibSweepUp, NULL },
- { 441, 312, 94, 16, 1, 4, "Octave up", NULL, relToneOctUp, NULL },
- { 536, 312, 93, 16, 1, 4, "Halftone up", NULL, relToneUp, NULL },
- { 441, 329, 94, 16, 1, 4, "Octave down", NULL, relToneOctDown, NULL },
- { 536, 329, 93, 16, 1, 4, "Halftone down", NULL, relToneDown, NULL },
+ { 441, 312, 94, 16, 1, 4, "Octave up", NULL, relativeNoteOctUp, NULL },
+ { 536, 312, 93, 16, 1, 4, "Halftone up", NULL, relativeNoteUp, NULL },
+ { 441, 329, 94, 16, 1, 4, "Octave down", NULL, relativeNoteOctDown, NULL },
+ { 536, 329, 93, 16, 1, 4, "Halftone down", NULL, relativeNoteDown, NULL },
// ------ INSTRUMENT EDITOR EXTENSION PUSHBUTTONS ------
//x, y, w, h, p, d, text #1, text #2, funcOnDown, funcOnUp
--- a/src/ft2_radiobuttons.c
+++ b/src/ft2_radiobuttons.c
@@ -33,7 +33,7 @@
//x, y, w, group, funcOnUp
{ 5, 18, 69, RB_GROUP_HELP, rbHelpFeatures },
{ 5, 34, 60, RB_GROUP_HELP, rbHelpEffects },
- { 5, 50, 71, RB_GROUP_HELP, rbHelpKeyboard },
+ { 5, 50, 86, RB_GROUP_HELP, rbHelpKeybindings },
{ 5, 66, 109, RB_GROUP_HELP, rbHelpHowToUseFT2 },
{ 5, 82, 101, RB_GROUP_HELP, rbHelpFAQ },
{ 5, 98, 86, RB_GROUP_HELP, rbHelpKnownBugs },
@@ -74,7 +74,7 @@
// ------ CONFIG AUDIO ------
// audio buffer size
- //x, y, w, group, funcOnUp
+ //x, y, w, group, funcOnUp
{ 390, 16, 46, RB_GROUP_CONFIG_SOUND_BUFF_SIZE, rbConfigSbs512 },
{ 390, 30, 113, RB_GROUP_CONFIG_SOUND_BUFF_SIZE, rbConfigSbs1024 },
{ 390, 44, 50, RB_GROUP_CONFIG_SOUND_BUFF_SIZE, rbConfigSbs2048 },
@@ -94,11 +94,13 @@
//x, y, w, group, funcOnUp
{ 509, 16, 66, RB_GROUP_CONFIG_AUDIO_FREQ, rbConfigAudio44kHz },
{ 509, 30, 121, RB_GROUP_CONFIG_AUDIO_FREQ, rbConfigAudio48kHz },
+#if CPU_64BIT
{ 509, 44, 66, RB_GROUP_CONFIG_AUDIO_FREQ, rbConfigAudio96kHz },
{ 509, 58, 73, RB_GROUP_CONFIG_AUDIO_FREQ, rbConfigAudio192kHz },
+#endif
// audio input frequency
- //x, y, w, group, funcOnUp
+ //x, y, w, group, funcOnUp
{ 180, 156, 60, RB_GROUP_CONFIG_AUDIO_INPUT_FREQ, rbConfigAudioInput44kHz },
{ 251, 156, 60, RB_GROUP_CONFIG_AUDIO_INPUT_FREQ, rbConfigAudioInput48kHz },
{ 322, 156, 60, RB_GROUP_CONFIG_AUDIO_INPUT_FREQ, rbConfigAudioInput96kHz },
@@ -128,7 +130,7 @@
{ 346, 145, 46, RB_GROUP_CONFIG_SCOPE, rbConfigScopeLined },
// visible pattern channels
- //x, y, w, group, funcOnUp
+ //x, y, w, group, funcOnUp
{ 257, 42, 78, RB_GROUP_CONFIG_PATTERN_CHANS, rbConfigPatt4Chans },
{ 257, 56, 78, RB_GROUP_CONFIG_PATTERN_CHANS, rbConfigPatt6Chans },
{ 257, 70, 78, RB_GROUP_CONFIG_PATTERN_CHANS, rbConfigPatt8Chans },
--- a/src/ft2_radiobuttons.h
+++ b/src/ft2_radiobuttons.h
@@ -2,6 +2,7 @@
#include <stdint.h>
#include <stdbool.h>
+#include "ft2_cpu.h"
enum // RADIOBUTTONS
{
@@ -8,7 +9,7 @@
// HELP
RB_HELP_FEATURES,
RB_HELP_EFFECTS,
- RB_HELP_KEYBOARD,
+ RB_HELP_KEYBINDINGS,
RB_HELP_HOW_TO_USE_FT2,
RB_HELP_FAQ,
RB_HELP_KNOWN_BUGS,
@@ -62,8 +63,10 @@
// AUDIO FREQUENCY
RB_CONFIG_AUDIO_44KHZ,
RB_CONFIG_AUDIO_48KHZ,
+#if CPU_64BIT
RB_CONFIG_AUDIO_96KHZ,
RB_CONFIG_AUDIO_192KHZ,
+#endif
// AUDIO INPUT FREQUENCY
RB_CONFIG_AUDIO_INPUT_44KHZ,
--- a/src/ft2_replayer.c
+++ b/src/ft2_replayer.c
@@ -15,7 +15,7 @@
#include "ft2_inst_ed.h"
#include "ft2_diskop.h"
#include "ft2_midi.h"
-#include "ft2_scopes.h"
+#include "scopes/ft2_scopes.h"
#include "ft2_mouse.h"
#include "ft2_sample_loader.h"
#include "ft2_tables.h"
@@ -29,11 +29,11 @@
static double dLogTab[768], dExp2MulTab[32];
static bool bxxOverflow;
-static tonTyp nilPatternLine[MAX_VOICES];
+static note_t nilPatternLine[MAX_CHANNELS];
-typedef void (*volKolEfxRoutine)(stmTyp *ch);
-typedef void (*volKolEfxRoutine2)(stmTyp *ch, uint8_t *volKol);
-typedef void (*efxRoutine)(stmTyp *ch, uint8_t param);
+typedef void (*volColumnEfxRoutine)(channel_t *ch);
+typedef void (*volColumnEfxRoutine2)(channel_t *ch, uint8_t *volColumnData);
+typedef void (*efxRoutine)(channel_t *ch, uint8_t param);
// globally accessed
int8_t playMode = 0;
@@ -40,11 +40,11 @@
bool songPlaying = false, audioPaused = false, musicPaused = false;
volatile bool replayerBusy = false;
const uint16_t *note2Period = NULL;
-int16_t pattLens[MAX_PATTERNS];
-stmTyp stm[MAX_VOICES];
-songTyp song;
-instrTyp *instr[132];
-tonTyp *patt[MAX_PATTERNS];
+int16_t patternNumRows[MAX_PATTERNS];
+channel_t channel[MAX_CHANNELS];
+song_t song;
+instr_t *instr[132];
+note_t *pattern[MAX_PATTERNS];
// ----------------------------------
void fixString(char *str, int32_t lastChrPos) // removes leading spaces and 0x1A chars
@@ -64,12 +64,12 @@
fixString(song.name, 19);
}
-void fixInstrAndSampleNames(int16_t nr)
+void fixInstrAndSampleNames(int16_t insNum)
{
- fixString(song.instrName[nr], 21);
- if (instr[nr] != NULL)
+ fixString(song.instrName[insNum], 21);
+ if (instr[insNum] != NULL)
{
- sampleTyp *s = instr[nr]->samp;
+ sample_t *s = instr[insNum]->smp;
for (int32_t i = 0; i < MAX_SMP_PER_INST; i++, s++)
fixString(s->name, 21);
}
@@ -81,10 +81,10 @@
if (audioWasntLocked)
lockAudio();
- memset(stm, 0, sizeof (stm));
+ memset(channel, 0, sizeof (channel));
- stmTyp *ch = stm;
- for (int32_t i = 0; i < MAX_VOICES; i++, ch++)
+ channel_t *ch = channel;
+ for (int32_t i = 0; i < MAX_CHANNELS; i++, ch++)
{
ch->instrPtr = instr[0];
ch->status = IS_Vol;
@@ -92,7 +92,7 @@
ch->outPan = 128;
ch->finalPan = 128;
- ch->stOff = !editor.chnMode[i]; // set channel mute flag from global mute flag
+ ch->channelOff = !editor.chnMode[i]; // set channel mute flag from global mute flag
}
if (audioWasntLocked)
@@ -112,7 +112,7 @@
}
// used on external sample load and during sample loading in some module formats
-void tuneSample(sampleTyp *s, const int32_t midCFreq, bool linearPeriodsFlag)
+void tuneSample(sample_t *s, const int32_t midCFreq, bool linearPeriodsFlag)
{
#define NOTE_C4 (4*12)
#define MIN_PERIOD (0)
@@ -123,7 +123,7 @@
if (midCFreq <= 0 || periodTab == NULL)
{
- s->fine = s->relTon = 0;
+ s->finetune = s->relativeNote = 0;
return;
}
@@ -131,15 +131,15 @@
if (midCFreq <= (int32_t)dGetHzFromPeriod(periodTab[MIN_PERIOD]))
{
- s->fine = -128;
- s->relTon = -48;
+ s->finetune = -128;
+ s->relativeNote = -48;
return;
}
if (midCFreq >= (int32_t)dGetHzFromPeriod(periodTab[MAX_PERIOD]))
{
- s->fine = 127;
- s->relTon = 71;
+ s->finetune = 127;
+ s->relativeNote = 71;
return;
}
@@ -149,8 +149,8 @@
{
if (midCFreq == (int32_t)dGetHzFromPeriod(periodTab[16 + (i<<4)]))
{
- s->fine = 0;
- s->relTon = i - NOTE_C4;
+ s->finetune = 0;
+ s->relativeNote = i - NOTE_C4;
return;
}
}
@@ -178,14 +178,14 @@
}
}
- s->fine = ((period & 31) - 16) << 3;
- s->relTon = (int8_t)(((period & ~31) >> 4) - NOTE_C4);
+ s->finetune = ((period & 31) - 16) << 3;
+ s->relativeNote = (int8_t)(((period & ~31) >> 4) - NOTE_C4);
}
-void setPatternLen(uint16_t nr, int16_t len)
+void setPatternLen(uint16_t pattNum, int16_t numRows)
{
- assert(nr < MAX_PATTERNS);
- if ((len < 1 || len > MAX_PATT_LEN) || len == pattLens[nr])
+ assert(pattNum < MAX_PATTERNS);
+ if ((numRows < 1 || numRows > MAX_PATT_LEN) || numRows == patternNumRows[pattNum])
return;
const bool audioWasntLocked = !audio.locked;
@@ -192,16 +192,23 @@
if (audioWasntLocked)
lockAudio();
- pattLens[nr] = len;
+ patternNumRows[pattNum] = numRows;
- if (patt[nr] != NULL)
- killPatternIfUnused(nr);
+ if (pattern[pattNum] != NULL)
+ killPatternIfUnused(pattNum);
- song.pattLen = pattLens[nr];
- if (song.pattPos >= song.pattLen)
+ // non-FT2 security
+ song.pattDelTime = 0;
+ song.pattDelTime2 = 0;
+ song.pBreakFlag = false;
+ song.posJumpFlag = false;
+ song.pBreakPos = 0;
+
+ song.currNumRows = numRows;
+ if (song.row >= song.currNumRows)
{
- song.pattPos = song.pattLen - 1;
- editor.pattPos = song.pattPos;
+ song.row = song.currNumRows - 1;
+ editor.row = song.row;
}
checkMarkLimits();
@@ -213,15 +220,15 @@
ui.updatePosSections = true;
}
-int16_t getUsedSamples(int16_t nr)
+int16_t getUsedSamples(int16_t smpNum)
{
- if (instr[nr] == NULL)
+ if (instr[smpNum] == NULL)
return 0;
- instrTyp *ins = instr[nr];
+ instr_t *ins = instr[smpNum];
int16_t i = 16 - 1;
- while (i >= 0 && ins->samp[i].pek == NULL && ins->samp[i].name[0] == '\0')
+ while (i >= 0 && ins->smp[i].dataPtr == NULL && ins->smp[i].name[0] == '\0')
i--;
/* Yes, 'i' can be -1 here, and will be set to at least 0
@@ -229,20 +236,20 @@
*/
for (int16_t j = 0; j < 96; j++)
{
- if (ins->ta[j] > i)
- i = ins->ta[j];
+ if (ins->note2SampleLUT[j] > i)
+ i = ins->note2SampleLUT[j];
}
return i+1;
}
-int16_t getRealUsedSamples(int16_t nr)
+int16_t getRealUsedSamples(int16_t smpNum)
{
- if (instr[nr] == NULL)
+ if (instr[smpNum] == NULL)
return 0;
int8_t i = 16 - 1;
- while (i >= 0 && instr[nr]->samp[i].pek == NULL)
+ while (i >= 0 && instr[smpNum]->smp[i].dataPtr == NULL)
i--;
return i+1;
@@ -253,10 +260,11 @@
if (period == 0)
return 0.0; // in FT2, a period of 0 results in 0Hz
- const uint16_t invPeriod = (12 * 192 * 4) - (uint16_t)period; // intentionally underflows (uint16_t) to be FT2-accurate
- const int32_t quotient = invPeriod / 768;
- const int32_t remainder = invPeriod % 768;
+ const uint32_t invPeriod = ((12 * 192 * 4) - period) & 0xFFFF; // mask needed for FT2 frequency quirk
+ const uint32_t quotient = invPeriod / 768;
+ const uint32_t remainder = invPeriod % 768;
+
return dLogTab[remainder] * dExp2MulTab[(14-quotient) & 31]; // x = y / 2^((14-quotient) & 31)
}
@@ -273,24 +281,24 @@
return audio.linearPeriodsFlag ? dLinearPeriod2Hz(period) : dAmigaPeriod2Hz(period);
}
-// returns *exact* FT2 C-4 voice rate (depending on finetune, relative note and linear/Amiga period mode)
-double getSampleC4Rate(sampleTyp *s)
+// returns *exact* FT2 C-4 voice rate (depending on finetune, relativeNote and linear/Amiga period mode)
+double getSampleC4Rate(sample_t *s)
{
- int32_t note = (96/2) + s->relTon;
+ int32_t note = (96/2) + s->relativeNote;
if (note >= (10*12)-1)
- return -1; // B-9 (from relTon) = illegal! (won't play in replayer)
+ return -1; // B-9 (from relativeTone) = illegal! (won't play in replayer)
- const int32_t C4Period = (note << 4) + (((int8_t)s->fine >> 3) + 16);
+ const int32_t C4Period = (note << 4) + (((int8_t)s->finetune >> 3) + 16);
const uint16_t period = audio.linearPeriodsFlag ? linearPeriods[C4Period] : amigaPeriods[C4Period];
return dPeriod2Hz(period);
}
-void setFrqTab(bool linear)
+void setFrequencyTable(bool linearPeriodsFlag)
{
pauseAudio();
- audio.linearPeriodsFlag = linear;
+ audio.linearPeriodsFlag = linearPeriodsFlag;
if (audio.linearPeriodsFlag)
note2Period = linearPeriods;
@@ -310,7 +318,7 @@
}
}
-static void retrigVolume(stmTyp *ch)
+static void retrigVolume(channel_t *ch)
{
ch->realVol = ch->oldVol;
ch->outVol = ch->oldVol;
@@ -318,7 +326,7 @@
ch->status |= IS_Vol + IS_Pan + IS_QuickVol;
}
-static void retrigEnvelopeVibrato(stmTyp *ch)
+static void retrigEnvelopeVibrato(channel_t *ch)
{
if (!(ch->waveCtrl & 0x04)) ch->vibPos = 0;
if (!(ch->waveCtrl & 0x40)) ch->tremPos = 0;
@@ -328,23 +336,23 @@
ch->envSustainActive = true;
- instrTyp *ins = ch->instrPtr;
+ instr_t *ins = ch->instrPtr;
assert(ins != NULL);
- if (ins->envVTyp & 1)
+ if (ins->volEnvFlags & ENV_ENABLED)
{
- ch->envVCnt = 65535;
- ch->envVPos = 0;
+ ch->volEnvTick = 65535;
+ ch->volEnvPos = 0;
}
- if (ins->envPTyp & 1)
+ if (ins->panEnvFlags & ENV_ENABLED)
{
- ch->envPCnt = 65535;
- ch->envPPos = 0;
+ ch->panEnvTick = 65535;
+ ch->panEnvPos = 0;
}
- ch->fadeOutSpeed = ins->fadeOut; // FT2 doesn't check if fadeout is more than 4095
- ch->fadeOutAmp = 32768;
+ ch->fadeoutSpeed = ins->fadeout; // FT2 doesn't check if fadeout is more than 4095!
+ ch->fadeoutVol = 32768;
if (ins->vibDepth > 0)
{
@@ -363,24 +371,18 @@
}
}
-void keyOff(stmTyp *ch)
+void keyOff(channel_t *ch)
{
ch->envSustainActive = false;
- instrTyp *ins = ch->instrPtr;
+ instr_t *ins = ch->instrPtr;
assert(ins != NULL);
- if (!(ins->envPTyp & 1)) // yes, FT2 does this (!). Most likely a bug?
+ if (ins->volEnvFlags & ENV_ENABLED)
{
- if (ch->envPCnt >= (uint16_t)ins->envPP[ch->envPPos][0])
- ch->envPCnt = ins->envPP[ch->envPPos][0] - 1;
+ if (ch->volEnvTick >= (uint16_t)ins->volEnvPoints[ch->volEnvPos][0])
+ ch->volEnvTick = ins->volEnvPoints[ch->volEnvPos][0] - 1;
}
-
- if (ins->envVTyp & 1)
- {
- if (ch->envVCnt >= (uint16_t)ins->envVP[ch->envVPos][0])
- ch->envVCnt = ins->envVP[ch->envVPos][0] - 1;
- }
else
{
ch->realVol = 0;
@@ -387,6 +389,12 @@
ch->outVol = 0;
ch->status |= IS_Vol + IS_QuickVol;
}
+
+ if (!(ins->panEnvFlags & ENV_ENABLED)) // What..? Probably an FT2 bug.
+ {
+ if (ch->panEnvTick >= (uint16_t)ins->panEnvPoints[ch->panEnvPos][0])
+ ch->panEnvTick = ins->panEnvPoints[ch->panEnvPos][0] - 1;
+ }
}
void calcReplayerLogTab(void)
@@ -395,7 +403,7 @@
dExp2MulTab[i] = 1.0 / exp2(i); // 1/2^i
for (int32_t i = 0; i < 768; i++)
- dLogTab[i] = 8363.0 * 256.0 * exp2(i * (1.0 / 768.0));
+ dLogTab[i] = 8363.0 * 256.0 * exp2(i / 768.0);
}
void calcReplayerVars(int32_t audioFreq)
@@ -405,19 +413,19 @@
return;
audio.dHz2MixDeltaMul = (double)MIXER_FRAC_SCALE / audioFreq;
- audio.quickVolRampSamples = (int32_t)((audioFreq / 200.0) + 0.5); // rounded
- audio.dRampQuickVolMul = 1.0 / audio.quickVolRampSamples;
+ audio.quickVolRampSamples = (int32_t)round(audioFreq / 200.0);
+ audio.fRampQuickVolMul = (float)(1.0 / audio.quickVolRampSamples);
- audio.dSamplesPerTickTab[0] = 0.0;
- audio.tickTimeTab[0] = UINT64_MAX;
- audio.dRampTickMulTab[0] = 0.0;
-
- for (int32_t i = MIN_BPM; i <= MAX_BPM; i++)
+ for (int32_t bpm = MIN_BPM; bpm <= MAX_BPM; bpm++)
{
- const double dBpmHz = i * (1.0 / 2.5); // i / 2.5
+ const int32_t i = bpm - MIN_BPM; // index for tables
+
+ const double dBpmHz = bpm / 2.5;
const double dSamplesPerTick = audioFreq / dBpmHz;
- audio.dSamplesPerTickTab[i] = dSamplesPerTick;
+ // convert to 32.32 fixed-point
+ audio.samplesPerTick64Tab[i] = (int64_t)((dSamplesPerTick * (UINT32_MAX+1.0)) + 0.5); // rounded
+
// BPM Hz -> tick length for performance counter (syncing visuals to audio)
double dTimeInt;
double dTimeFrac = modf(editor.dPerfFreq / dBpmHz, &dTimeInt);
@@ -425,11 +433,12 @@
dTimeFrac = floor((UINT32_MAX+1.0) * dTimeFrac); // fractional part (scaled to 0..2^32-1)
- audio.tickTimeTab[i] = ((uint64_t)timeInt << 32) | (uint32_t)dTimeFrac;
+ audio.tickTimeTab[i] = (uint32_t)timeInt;
+ audio.tickTimeFracTab[i] = (uint32_t)dTimeFrac;
// for calculating volume ramp length for tick-lenghted ramps
- const int32_t samplesPerTick = (int32_t)(dSamplesPerTick + 0.5); // this has to be rounded first
- audio.dRampTickMulTab[i] = 1.0 / samplesPerTick;
+ const int32_t samplesPerTickRounded = (int32_t)(dSamplesPerTick + 0.5); // must be rounded
+ audio.fRampTickMulTab[i] = (float)(1.0 / samplesPerTickRounded);
}
}
@@ -438,7 +447,7 @@
assert(note2Period != NULL);
if (period > note2Period[0])
- return -1; // out of lower range on piano
+ return -1; // outside lower range on piano
if (audio.linearPeriodsFlag)
{
@@ -449,7 +458,7 @@
return note;
}
- /* Amiga periods require a slower method...
+ /* Amiga periods require a slightly slower method...
** This is not 100% accurate for all periods, but should be faster
** than using log2() and floating-point arithmetics.
*/
@@ -478,9 +487,9 @@
return note;
}
-static void startTone(uint8_t ton, uint8_t effTyp, uint8_t eff, stmTyp *ch)
+static void startTone(uint8_t note, uint8_t efx, uint8_t efxData, channel_t *ch)
{
- if (ton == 97)
+ if (note == NOTE_OFF)
{
keyOff(ch);
return;
@@ -487,17 +496,17 @@
}
// if we came from Rxy (retrig), we didn't check note (Ton) yet
- if (ton == 0)
+ if (note == 0)
{
- ton = ch->tonNr;
- if (ton == 0)
+ note = ch->noteNum;
+ if (note == 0)
return; // if still no note, exit from routine
}
- ch->tonNr = ton;
+ ch->noteNum = note;
- assert(ch->instrNr <= 130);
- instrTyp *ins = instr[ch->instrNr];
+ assert(ch->instrNum <= 130);
+ instr_t *ins = instr[ch->instrNum];
if (ins == NULL)
ins = instr[0]; // empty instruments use this placeholder instrument
@@ -504,31 +513,30 @@
ch->instrPtr = ins;
ch->mute = ins->mute;
- if (ton > 96) // non-FT2 security (should never happen because I clamp in the patt. loader now)
- ton = 96;
+ if (note > 96) // non-FT2 security (should never happen because I clamp in the patt. loader now)
+ note = 96;
- const uint8_t smp = ins->ta[ton-1] & 0xF;
- ch->sampleNr = smp;
+ ch->smpNum = ins->note2SampleLUT[note-1] & 0xF; // FT2 doesn't AND here, but let's do it for safety
+ sample_t *s = &ins->smp[ch->smpNum];
- sampleTyp *s = &ins->samp[smp];
ch->smpPtr = s;
- ch->relTonNr = s->relTon;
+ ch->relativeNote = s->relativeNote;
- ton += ch->relTonNr;
- if (ton >= 10*12)
+ note += ch->relativeNote;
+ if (note >= 10*12)
return;
- ch->oldVol = s->vol;
- ch->oldPan = s->pan;
+ ch->oldVol = s->volume;
+ ch->oldPan = s->panning;
- if (effTyp == 0x0E && (eff & 0xF0) == 0x50)
- ch->fineTune = ((eff & 0x0F) << 4) - 128; // result is now -128..127
+ if (efx == 0xE && (efxData & 0xF0) == 0x50)
+ ch->finetune = ((efxData & 0x0F) << 4) - 128;
else
- ch->fineTune = s->fine;
+ ch->finetune = s->finetune;
- if (ton != 0)
+ if (note != 0)
{
- const uint16_t tmpTon = ((ton-1) << 4) + (((int8_t)ch->fineTune >> 3) + 16); // 0..1935
+ const uint16_t tmpTon = ((note-1) << 4) + (((int8_t)ch->finetune >> 3) + 16); // 0..1935
if (tmpTon < MAX_NOTES) // tmpTon is *always* below MAX_NOTES here, so this check is not really needed
{
assert(note2Period != NULL);
@@ -536,12 +544,12 @@
}
}
- ch->status |= IS_Period + IS_Vol + IS_Pan + IS_NyTon + IS_QuickVol;
+ ch->status |= IS_Period + IS_Vol + IS_Pan + IS_Trigger + IS_QuickVol;
- if (effTyp == 9)
+ if (efx == 9)
{
- if (eff)
- ch->smpOffset = ch->eff;
+ if (efxData > 0)
+ ch->smpOffset = ch->efxData;
ch->smpStartPos = ch->smpOffset << 8;
}
@@ -551,11 +559,11 @@
}
}
-static void volume(stmTyp *ch, uint8_t param); // volume slide
-static void vibrato2(stmTyp *ch);
-static void tonePorta(stmTyp *ch, uint8_t param);
+static void volume(channel_t *ch, uint8_t param); // volume slide
+static void vibrato2(channel_t *ch);
+static void tonePorta(channel_t *ch, uint8_t param);
-static void dummy(stmTyp *ch, uint8_t param)
+static void dummy(channel_t *ch, uint8_t param)
{
(void)ch;
(void)param;
@@ -562,7 +570,7 @@
return;
}
-static void finePortaUp(stmTyp *ch, uint8_t param)
+static void finePortaUp(channel_t *ch, uint8_t param)
{
if (param == 0)
param = ch->fPortaUpSpeed;
@@ -577,7 +585,7 @@
ch->status |= IS_Period;
}
-static void finePortaDown(stmTyp *ch, uint8_t param)
+static void finePortaDown(channel_t *ch, uint8_t param)
{
if (param == 0)
param = ch->fPortaDownSpeed;
@@ -592,42 +600,42 @@
ch->status |= IS_Period;
}
-static void setGlissCtrl(stmTyp *ch, uint8_t param)
+static void setGlissCtrl(channel_t *ch, uint8_t param)
{
ch->glissFunk = param;
}
-static void setVibratoCtrl(stmTyp *ch, uint8_t param)
+static void setVibratoCtrl(channel_t *ch, uint8_t param)
{
ch->waveCtrl = (ch->waveCtrl & 0xF0) | param;
}
-static void jumpLoop(stmTyp *ch, uint8_t param)
+static void jumpLoop(channel_t *ch, uint8_t param)
{
if (param == 0)
{
- ch->pattPos = song.pattPos & 0xFF;
+ ch->jumpToRow = song.row & 0xFF;
}
- else if (ch->loopCnt == 0)
+ else if (ch->patLoopCounter == 0)
{
- ch->loopCnt = param;
+ ch->patLoopCounter = param;
- song.pBreakPos = ch->pattPos;
+ song.pBreakPos = ch->jumpToRow;
song.pBreakFlag = true;
}
- else if (--ch->loopCnt > 0)
+ else if (--ch->patLoopCounter > 0)
{
- song.pBreakPos = ch->pattPos;
+ song.pBreakPos = ch->jumpToRow;
song.pBreakFlag = true;
}
}
-static void setTremoloCtrl(stmTyp *ch, uint8_t param)
+static void setTremoloCtrl(channel_t *ch, uint8_t param)
{
ch->waveCtrl = (param << 4) | (ch->waveCtrl & 0x0F);
}
-static void volFineUp(stmTyp *ch, uint8_t param)
+static void volFineUp(channel_t *ch, uint8_t param)
{
if (param == 0)
param = ch->fVolSlideUpSpeed;
@@ -642,7 +650,7 @@
ch->status |= IS_Vol;
}
-static void volFineDown(stmTyp *ch, uint8_t param)
+static void volFineDown(channel_t *ch, uint8_t param)
{
if (param == 0)
param = ch->fVolSlideDownSpeed;
@@ -657,7 +665,7 @@
ch->status |= IS_Vol;
}
-static void noteCut0(stmTyp *ch, uint8_t param)
+static void noteCut0(channel_t *ch, uint8_t param)
{
if (param == 0) // only a parameter of zero is handled here
{
@@ -667,7 +675,7 @@
}
}
-static void pattDelay(stmTyp *ch, uint8_t param)
+static void pattDelay(channel_t *ch, uint8_t param)
{
if (song.pattDelTime2 == 0)
song.pattDelTime = param + 1;
@@ -695,12 +703,12 @@
dummy // F
};
-static void E_Effects_TickZero(stmTyp *ch, uint8_t param)
+static void E_Effects_TickZero(channel_t *ch, uint8_t param)
{
const uint8_t efx = param >> 4;
param &= 0x0F;
- if (ch->stOff) // channel is muted, only handle some E effects
+ if (ch->channelOff) // channel is muted, only handle some E effects
{
if (efx == 0x6) jumpLoop(ch, param);
else if (efx == 0xE) pattDelay(ch, param);
@@ -711,12 +719,12 @@
EJumpTab_TickZero[efx](ch, param);
}
-static void posJump(stmTyp *ch, uint8_t param)
+static void posJump(channel_t *ch, uint8_t param)
{
if (playMode != PLAYMODE_PATT && playMode != PLAYMODE_RECPATT)
{
const int16_t pos = (int16_t)param - 1;
- if (pos < 0 || pos >= song.len)
+ if (pos < 0 || pos >= song.songLength)
bxxOverflow = true; // non-FT2 security fix...
else
song.songPos = pos;
@@ -728,10 +736,8 @@
(void)ch;
}
-static void pattBreak(stmTyp *ch, uint8_t param)
+static void pattBreak(channel_t *ch, uint8_t param)
{
- song.posJumpFlag = true;
-
param = ((param >> 4) * 10) + (param & 0x0F);
if (param <= 63)
song.pBreakPos = param;
@@ -738,66 +744,68 @@
else
song.pBreakPos = 0;
+ song.posJumpFlag = true;
+
(void)ch;
}
-static void setSpeed(stmTyp *ch, uint8_t param)
+static void setSpeed(channel_t *ch, uint8_t param)
{
if (param >= 32)
{
- song.speed = param;
- P_SetSpeed(song.speed);
+ song.BPM = param;
+ setMixerBPM(song.BPM);
}
else
{
- song.timer = song.tempo = param;
+ song.tick = song.speed = param;
}
(void)ch;
}
-static void setGlobaVol(stmTyp *ch, uint8_t param)
+static void setGlobalVolume(channel_t *ch, uint8_t param)
{
if (param > 64)
param = 64;
- song.globVol = param;
+ song.globalVolume = param;
- stmTyp *c = stm;
- for (int32_t i = 0; i < song.antChn; i++, c++) // update all voice volumes
+ channel_t *c = channel;
+ for (int32_t i = 0; i < song.numChannels; i++, c++) // update all voice volumes
c->status |= IS_Vol;
(void)ch;
}
-static void setEnvelopePos(stmTyp *ch, uint8_t param)
+static void setEnvelopePos(channel_t *ch, uint8_t param)
{
bool envUpdate;
int8_t point;
int16_t tick;
- instrTyp *ins = ch->instrPtr;
+ instr_t *ins = ch->instrPtr;
assert(ins != NULL);
// *** VOLUME ENVELOPE ***
- if (ins->envVTyp & 1)
+ if (ins->volEnvFlags & ENV_ENABLED)
{
- ch->envVCnt = param-1;
+ ch->volEnvTick = param-1;
point = 0;
envUpdate = true;
tick = param;
- if (ins->envVPAnt > 1)
+ if (ins->volEnvLength > 1)
{
point++;
- for (int32_t i = 0; i < ins->envVPAnt-1; i++)
+ for (int32_t i = 0; i < ins->volEnvLength-1; i++)
{
- if (tick < ins->envVP[point][0])
+ if (tick < ins->volEnvPoints[point][0])
{
point--;
- tick -= ins->envVP[point][0];
+ tick -= ins->volEnvPoints[point][0];
if (tick == 0)
{
envUpdate = false;
@@ -804,15 +812,18 @@
break;
}
- if (ins->envVP[point+1][0] <= ins->envVP[point][0])
+ if (ins->volEnvPoints[point+1][0] <= ins->volEnvPoints[point][0])
{
envUpdate = true;
break;
}
- ch->envVIPValue = ((ins->envVP[point+1][1] - ins->envVP[point][1]) << 16) / (ins->envVP[point+1][0] - ins->envVP[point][0]);
- ch->envVAmp = (ch->envVIPValue * (tick-1)) + (ins->envVP[point][1] << 16);
+ int32_t delta = (int8_t)((ins->volEnvPoints[point+1][1] - ins->volEnvPoints[point][1]) & 0xFF) << 16;
+ delta /= (ins->volEnvPoints[point+1][0]-ins->volEnvPoints[point][0]);
+ ch->volEnvDelta = delta;
+ ch->volEnvValue = (ch->volEnvDelta * (tick-1)) + ((int8_t)(ins->volEnvPoints[point][1] & 0xFF) << 16);
+
point++;
envUpdate = false;
@@ -828,39 +839,39 @@
if (envUpdate)
{
- ch->envVIPValue = 0;
- ch->envVAmp = ins->envVP[point][1];
+ ch->volEnvDelta = 0;
+ ch->volEnvValue = (int8_t)(ins->volEnvPoints[point][1] & 0xFF) << 16;
}
- if (point >= ins->envVPAnt)
+ if (point >= ins->volEnvLength)
{
- point = ins->envVPAnt-1;
+ point = ins->volEnvLength-1;
if (point < 0)
point = 0;
}
- ch->envVPos = point;
+ ch->volEnvPos = point;
}
// *** PANNING ENVELOPE ***
- if (ins->envVTyp & 2) // probably an FT2 bug
+ if (ins->volEnvFlags & ENV_SUSTAIN) // What..? Probably an FT2 bug!
{
- ch->envPCnt = param-1;
+ ch->panEnvTick = param-1;
point = 0;
envUpdate = true;
tick = param;
- if (ins->envPPAnt > 1)
+ if (ins->panEnvLength > 1)
{
point++;
- for (int32_t i = 0; i < ins->envPPAnt-1; i++)
+ for (int32_t i = 0; i < ins->panEnvLength-1; i++)
{
- if (tick < ins->envPP[point][0])
+ if (tick < ins->panEnvPoints[point][0])
{
point--;
- tick -= ins->envPP[point][0];
+ tick -= ins->panEnvPoints[point][0];
if (tick == 0)
{
envUpdate = false;
@@ -867,15 +878,18 @@
break;
}
- if (ins->envPP[point+1][0] <= ins->envPP[point][0])
+ if (ins->panEnvPoints[point+1][0] <= ins->panEnvPoints[point][0])
{
envUpdate = true;
break;
}
- ch->envPIPValue = ((ins->envPP[point+1][1] - ins->envPP[point][1]) << 16) / (ins->envPP[point+1][0] - ins->envPP[point][0]);
- ch->envPAmp = (ch->envPIPValue * (tick-1)) + (ins->envPP[point][1] << 16);
+ int32_t delta = (int8_t)((ins->panEnvPoints[point+1][1] - ins->panEnvPoints[point][1]) & 0xFF) << 16;
+ delta /= (ins->panEnvPoints[point+1][0]-ins->panEnvPoints[point][0]);
+ ch->panEnvDelta = delta;
+ ch->panEnvValue = (ch->panEnvDelta * (tick-1)) + ((int8_t)(ins->panEnvPoints[point][1] & 0xFF) << 16);
+
point++;
envUpdate = false;
@@ -891,18 +905,18 @@
if (envUpdate)
{
- ch->envPIPValue = 0;
- ch->envPAmp = ins->envPP[point][1];
+ ch->panEnvDelta = 0;
+ ch->panEnvValue = (int8_t)(ins->panEnvPoints[point][1] & 0xFF) << 16;
}
- if (point >= ins->envPPAnt)
+ if (point >= ins->panEnvLength)
{
- point = ins->envPPAnt-1;
+ point = ins->panEnvLength-1;
if (point < 0)
point = 0;
}
- ch->envPPos = point;
+ ch->panEnvPos = point;
}
}
@@ -924,7 +938,7 @@
pattBreak, // D
E_Effects_TickZero, // E
setSpeed, // F
- setGlobaVol, // G
+ setGlobalVolume, // G
dummy, // H
dummy, // I
dummy, // J
@@ -946,12 +960,12 @@
dummy // Z
};
-static void handleMoreEffects_TickZero(stmTyp *ch) // called even if channel is muted
+static void handleMoreEffects_TickZero(channel_t *ch) // called even if channel is muted
{
- if (ch->effTyp > 35)
+ if (ch->efx > 35)
return;
- JumpTab_TickZero[ch->effTyp](ch, ch->eff);
+ JumpTab_TickZero[ch->efx](ch, ch->efxData);
}
/* -- tick-zero volume column effects --
@@ -958,56 +972,56 @@
** 2nd parameter is used for a volume column quirk with the Rxy command (multiretrig)
*/
-static void v_SetVibSpeed(stmTyp *ch, uint8_t *volKol)
+static void v_SetVibSpeed(channel_t *ch, uint8_t *volColumnData)
{
- *volKol = (ch->volKolVol & 0x0F) << 2;
- if (*volKol != 0)
- ch->vibSpeed = *volKol;
+ *volColumnData = (ch->volColumnVol & 0x0F) << 2;
+ if (*volColumnData != 0)
+ ch->vibSpeed = *volColumnData;
}
-static void v_Volume(stmTyp *ch, uint8_t *volKol)
+static void v_Volume(channel_t *ch, uint8_t *volColumnData)
{
- *volKol -= 16;
- if (*volKol > 64) // no idea why FT2 has this check...
- *volKol = 64;
+ *volColumnData -= 16;
+ if (*volColumnData > 64) // no idea why FT2 has this check...
+ *volColumnData = 64;
- ch->outVol = ch->realVol = *volKol;
+ ch->outVol = ch->realVol = *volColumnData;
ch->status |= IS_Vol + IS_QuickVol;
}
-static void v_FineSlideDown(stmTyp *ch, uint8_t *volKol)
+static void v_FineSlideDown(channel_t *ch, uint8_t *volColumnData)
{
- *volKol = (uint8_t)(0 - (ch->volKolVol & 0x0F)) + ch->realVol;
- if ((int8_t)*volKol < 0)
- *volKol = 0;
+ *volColumnData = (uint8_t)(0 - (ch->volColumnVol & 0x0F)) + ch->realVol;
+ if ((int8_t)*volColumnData < 0)
+ *volColumnData = 0;
- ch->outVol = ch->realVol = *volKol;
+ ch->outVol = ch->realVol = *volColumnData;
ch->status |= IS_Vol;
}
-static void v_FineSlideUp(stmTyp *ch, uint8_t *volKol)
+static void v_FineSlideUp(channel_t *ch, uint8_t *volColumnData)
{
- *volKol = (ch->volKolVol & 0x0F) + ch->realVol;
- if (*volKol > 64)
- *volKol = 64;
+ *volColumnData = (ch->volColumnVol & 0x0F) + ch->realVol;
+ if (*volColumnData > 64)
+ *volColumnData = 64;
- ch->outVol = ch->realVol = *volKol;
+ ch->outVol = ch->realVol = *volColumnData;
ch->status |= IS_Vol;
}
-static void v_SetPan(stmTyp *ch, uint8_t *volKol)
+static void v_SetPan(channel_t *ch, uint8_t *volColumnData)
{
- *volKol <<= 4;
+ *volColumnData <<= 4;
- ch->outPan = *volKol;
+ ch->outPan = *volColumnData;
ch->status |= IS_Pan;
}
// -- non-tick-zero volume column effects --
-static void v_SlideDown(stmTyp *ch)
+static void v_SlideDown(channel_t *ch)
{
- uint8_t newVol = (uint8_t)(0 - (ch->volKolVol & 0x0F)) + ch->realVol;
+ uint8_t newVol = (uint8_t)(0 - (ch->volColumnVol & 0x0F)) + ch->realVol;
if ((int8_t)newVol < 0)
newVol = 0;
@@ -1015,9 +1029,9 @@
ch->status |= IS_Vol;
}
-static void v_SlideUp(stmTyp *ch)
+static void v_SlideUp(channel_t *ch)
{
- uint8_t newVol = (ch->volKolVol & 0x0F) + ch->realVol;
+ uint8_t newVol = (ch->volColumnVol & 0x0F) + ch->realVol;
if (newVol > 64)
newVol = 64;
@@ -1025,9 +1039,9 @@
ch->status |= IS_Vol;
}
-static void v_Vibrato(stmTyp *ch)
+static void v_Vibrato(channel_t *ch)
{
- const uint8_t param = ch->volKolVol & 0xF;
+ const uint8_t param = ch->volColumnVol & 0xF;
if (param > 0)
ch->vibDepth = param;
@@ -1034,9 +1048,9 @@
vibrato2(ch);
}
-static void v_PanSlideLeft(stmTyp *ch)
+static void v_PanSlideLeft(channel_t *ch)
{
- uint16_t tmp16 = (uint8_t)(0 - (ch->volKolVol & 0x0F)) + ch->outPan;
+ uint16_t tmp16 = (uint8_t)(0 - (ch->volColumnVol & 0x0F)) + ch->outPan;
if (tmp16 < 256) // includes an FT2 bug: pan-slide-left of 0 = set pan to 0
tmp16 = 0;
@@ -1044,9 +1058,9 @@
ch->status |= IS_Pan;
}
-static void v_PanSlideRight(stmTyp *ch)
+static void v_PanSlideRight(channel_t *ch)
{
- uint16_t tmp16 = (ch->volKolVol & 0x0F) + ch->outPan;
+ uint16_t tmp16 = (ch->volColumnVol & 0x0F) + ch->outPan;
if (tmp16 > 255)
tmp16 = 255;
@@ -1054,25 +1068,25 @@
ch->status |= IS_Pan;
}
-static void v_TonePorta(stmTyp *ch)
+static void v_TonePorta(channel_t *ch)
{
tonePorta(ch, 0); // the last parameter is actually not used in tonePorta()
}
-static void v_dummy(stmTyp *ch)
+static void v_dummy(channel_t *ch)
{
(void)ch;
return;
}
-static void v_dummy2(stmTyp *ch, uint8_t *volKol)
+static void v_dummy2(channel_t *ch, uint8_t *volColumnData)
{
(void)ch;
- (void)volKol;
+ (void)volColumnData;
return;
}
-static const volKolEfxRoutine VJumpTab_TickNonZero[16] =
+static const volColumnEfxRoutine VJumpTab_TickNonZero[16] =
{
v_dummy, v_dummy, v_dummy, v_dummy,
v_dummy, v_dummy, v_SlideDown, v_SlideUp,
@@ -1080,7 +1094,7 @@
v_dummy, v_PanSlideLeft, v_PanSlideRight, v_TonePorta
};
-static const volKolEfxRoutine2 VJumpTab_TickZero[16] =
+static const volColumnEfxRoutine2 VJumpTab_TickZero[16] =
{
v_dummy2, v_Volume, v_Volume, v_Volume,
v_Volume, v_Volume, v_dummy2, v_dummy2,
@@ -1088,13 +1102,13 @@
v_SetPan, v_dummy2, v_dummy2, v_dummy2
};
-static void setPan(stmTyp *ch, uint8_t param)
+static void setPan(channel_t *ch, uint8_t param)
{
ch->outPan = param;
ch->status |= IS_Pan;
}
-static void setVol(stmTyp *ch, uint8_t param)
+static void setVol(channel_t *ch, uint8_t param)
{
if (param > 64)
param = 64;
@@ -1103,7 +1117,7 @@
ch->status |= IS_Vol + IS_QuickVol;
}
-static void xFinePorta(stmTyp *ch, uint8_t param)
+static void xFinePorta(channel_t *ch, uint8_t param)
{
const uint8_t type = param >> 4;
param &= 0x0F;
@@ -1142,7 +1156,7 @@
}
}
-static void doMultiRetrig(stmTyp *ch, uint8_t param) // "param" is never used (needed for efx jumptable structure)
+static void doMultiRetrig(channel_t *ch, uint8_t param) // "param" is never used (needed for efx jumptable structure)
{
uint8_t cnt = ch->retrigCnt + 1;
if (cnt < ch->retrigSpeed)
@@ -1178,14 +1192,14 @@
ch->realVol = (uint8_t)vol;
ch->outVol = ch->realVol;
- if (ch->volKolVol >= 0x10 && ch->volKolVol <= 0x50)
+ if (ch->volColumnVol >= 0x10 && ch->volColumnVol <= 0x50)
{
- ch->outVol = ch->volKolVol - 0x10;
+ ch->outVol = ch->volColumnVol - 0x10;
ch->realVol = ch->outVol;
}
- else if (ch->volKolVol >= 0xC0 && ch->volKolVol <= 0xCF)
+ else if (ch->volColumnVol >= 0xC0 && ch->volColumnVol <= 0xCF)
{
- ch->outPan = (ch->volKolVol & 0x0F) << 4;
+ ch->outPan = (ch->volColumnVol & 0x0F) << 4;
}
startTone(0, 0, 0, ch);
@@ -1193,7 +1207,7 @@
(void)param;
}
-static void multiRetrig(stmTyp *ch, uint8_t param, uint8_t volumeColumnData)
+static void multiRetrig(channel_t *ch, uint8_t param, uint8_t volumeColumnData)
{
uint8_t tmpParam;
@@ -1213,36 +1227,36 @@
doMultiRetrig(ch, 0); // the second parameter is never used (needed for efx jumptable structure)
}
-static void handleEffects_TickZero(stmTyp *ch)
+static void handleEffects_TickZero(channel_t *ch)
{
// volume column effects
- uint8_t newVolKol = ch->volKolVol; // manipulated by vol. column effects, then used for multiretrig check (FT2 quirk)
- VJumpTab_TickZero[ch->volKolVol >> 4](ch, &newVolKol);
+ uint8_t newVolCol = ch->volColumnVol; // manipulated by vol. column effects, then used for multiretrig check (FT2 quirk)
+ VJumpTab_TickZero[ch->volColumnVol >> 4](ch, &newVolCol);
// normal effects
- const uint8_t param = ch->eff;
- if (ch->effTyp == 0 && param == 0)
+ const uint8_t param = ch->efxData;
+ if (ch->efx == 0 && param == 0)
return; // no effect
- if (ch->effTyp == 8) setPan(ch, param);
- else if (ch->effTyp == 12) setVol(ch, param);
- else if (ch->effTyp == 27) multiRetrig(ch, param, newVolKol);
- else if (ch->effTyp == 33) xFinePorta(ch, param);
+ if (ch->efx == 8) setPan(ch, param);
+ else if (ch->efx == 12) setVol(ch, param);
+ else if (ch->efx == 27) multiRetrig(ch, param, newVolCol);
+ else if (ch->efx == 33) xFinePorta(ch, param);
handleMoreEffects_TickZero(ch);
}
-static void fixTonePorta(stmTyp *ch, const tonTyp *p, uint8_t inst)
+static void fixTonePorta(channel_t *ch, const note_t *p, uint8_t inst)
{
- if (p->ton > 0)
+ if (p->note > 0)
{
- if (p->ton == 97)
+ if (p->note == NOTE_OFF)
{
keyOff(ch);
}
else
{
- const uint16_t note = (((p->ton-1) + ch->relTonNr) << 4) + (((int8_t)ch->fineTune >> 3) + 16);
+ const uint16_t note = (((p->note-1) + ch->relativeNote) << 4) + (((int8_t)ch->finetune >> 3) + 16);
if (note < MAX_NOTES)
{
assert(note2Period != NULL);
@@ -1249,11 +1263,11 @@
ch->wantPeriod = note2Period[note];
if (ch->wantPeriod == ch->realPeriod)
- ch->portaDir = 0;
+ ch->portaDirection = 0;
else if (ch->wantPeriod > ch->realPeriod)
- ch->portaDir = 1;
+ ch->portaDirection = 1;
else
- ch->portaDir = 2;
+ ch->portaDirection = 2;
}
}
}
@@ -1261,18 +1275,18 @@
if (inst > 0)
{
retrigVolume(ch);
- if (p->ton != 97)
+ if (p->note != NOTE_OFF)
retrigEnvelopeVibrato(ch);
}
}
-static void getNewNote(stmTyp *ch, const tonTyp *p)
+static void getNewNote(channel_t *ch, const note_t *p)
{
- ch->volKolVol = p->vol;
+ ch->volColumnVol = p->vol;
- if (ch->effTyp == 0)
+ if (ch->efx == 0)
{
- if (ch->eff > 0) // we have an arpeggio running, set period back
+ if (ch->efxData > 0) // we have an arpeggio running, set period back
{
ch->outPeriod = ch->realPeriod;
ch->status |= IS_Period;
@@ -1281,7 +1295,7 @@
else
{
// if we have a vibrato on previous row (ch) that ends at current row (p), set period back
- if ((ch->effTyp == 4 || ch->effTyp == 6) && (p->effTyp != 4 && p->effTyp != 6))
+ if ((ch->efx == 4 || ch->efx == 6) && (p->efx != 4 && p->efx != 6))
{
ch->outPeriod = ch->realPeriod;
ch->status |= IS_Period;
@@ -1288,11 +1302,11 @@
}
}
- ch->effTyp = p->effTyp;
- ch->eff = p->eff;
- ch->tonTyp = (p->instr << 8) | p->ton;
+ ch->efx = p->efx;
+ ch->efxData = p->efxData;
+ ch->noteData = (p->instr << 8) | p->note;
- if (ch->stOff) // channel is muted, only handle some effects
+ if (ch->channelOff) // channel is muted, only handle some effects
{
handleMoreEffects_TickZero(ch);
return;
@@ -1303,27 +1317,27 @@
if (inst > 0)
{
if (inst <= MAX_INST)
- ch->instrNr = inst;
+ ch->instrNum = inst;
else
inst = 0;
}
bool checkEfx = true;
- if (p->effTyp == 0x0E)
+ if (p->efx == 0x0E)
{
- if (p->eff >= 0xD1 && p->eff <= 0xDF)
+ if (p->efxData >= 0xD1 && p->efxData <= 0xDF)
return; // we have a note delay (ED1..EDF)
- else if (p->eff == 0x90)
+ else if (p->efxData == 0x90)
checkEfx = false;
}
if (checkEfx)
{
- if ((ch->volKolVol & 0xF0) == 0xF0) // gxx
+ if ((ch->volColumnVol & 0xF0) == 0xF0) // gxx
{
- const uint8_t volKolParam = ch->volKolVol & 0x0F;
- if (volKolParam > 0)
- ch->portaSpeed = volKolParam << 6;
+ const uint8_t volColumnData = ch->volColumnVol & 0x0F;
+ if (volColumnData > 0)
+ ch->portaSpeed = volColumnData << 6;
fixTonePorta(ch, p, inst);
handleEffects_TickZero(ch);
@@ -1330,10 +1344,10 @@
return;
}
- if (p->effTyp == 3 || p->effTyp == 5) // 3xx or 5xx
+ if (p->efx == 3 || p->efx == 5) // 3xx or 5xx
{
- if (p->effTyp != 5 && p->eff != 0)
- ch->portaSpeed = p->eff << 2;
+ if (p->efx != 5 && p->efxData != 0)
+ ch->portaSpeed = p->efxData << 2;
fixTonePorta(ch, p, inst);
handleEffects_TickZero(ch);
@@ -1340,7 +1354,7 @@
return;
}
- if (p->effTyp == 0x14 && p->eff == 0) // K00 (KeyOff - only handle tick 0 here)
+ if (p->efx == 0x14 && p->efxData == 0) // K00 (KeyOff - only handle tick 0 here)
{
keyOff(ch);
@@ -1351,7 +1365,7 @@
return;
}
- if (p->ton == 0)
+ if (p->note == 0)
{
if (inst > 0)
{
@@ -1364,15 +1378,15 @@
}
}
- if (p->ton == 97)
+ if (p->note == NOTE_OFF)
keyOff(ch);
else
- startTone(p->ton, p->effTyp, p->eff, ch);
+ startTone(p->note, p->efx, p->efxData, ch);
if (inst > 0)
{
retrigVolume(ch);
- if (p->ton != 97)
+ if (p->note != NOTE_OFF)
retrigEnvelopeVibrato(ch);
}
@@ -1379,7 +1393,7 @@
handleEffects_TickZero(ch);
}
-static void fixaEnvelopeVibrato(stmTyp *ch)
+static void updateChannel(channel_t *ch)
{
bool envInterpolateFlag, envDidInterpolate;
uint8_t envPos;
@@ -1386,9 +1400,9 @@
int16_t autoVibVal;
uint16_t autoVibAmp;
int32_t envVal;
- double dVol;
+ float fVol;
- instrTyp *ins = ch->instrPtr;
+ instr_t *ins = ch->instrPtr;
assert(ins != NULL);
// *** FADEOUT ***
@@ -1397,14 +1411,14 @@
ch->status |= IS_Vol;
// unsigned clamp + reset
- if (ch->fadeOutAmp >= ch->fadeOutSpeed)
+ if (ch->fadeoutVol >= ch->fadeoutSpeed)
{
- ch->fadeOutAmp -= ch->fadeOutSpeed;
+ ch->fadeoutVol -= ch->fadeoutSpeed;
}
else
{
- ch->fadeOutAmp = 0;
- ch->fadeOutSpeed = 0;
+ ch->fadeoutVol = 0;
+ ch->fadeoutSpeed = 0;
}
}
@@ -1412,27 +1426,27 @@
{
// *** VOLUME ENVELOPE ***
envVal = 0;
- if (ins->envVTyp & 1)
+ if (ins->volEnvFlags & ENV_ENABLED)
{
envDidInterpolate = false;
- envPos = ch->envVPos;
+ envPos = ch->volEnvPos;
- if (++ch->envVCnt == ins->envVP[envPos][0])
+ if (++ch->volEnvTick == ins->volEnvPoints[envPos][0])
{
- ch->envVAmp = ins->envVP[envPos][1] << 16;
+ ch->volEnvValue = (int8_t)(ins->volEnvPoints[envPos][1] & 0xFF) << 16;
envPos++;
- if (ins->envVTyp & 4)
+ if (ins->volEnvFlags & ENV_LOOP)
{
envPos--;
- if (envPos == ins->envVRepE)
+ if (envPos == ins->volEnvLoopEnd)
{
- if (!(ins->envVTyp & 2) || envPos != ins->envVSust || ch->envSustainActive)
+ if (!(ins->volEnvFlags & ENV_SUSTAIN) || envPos != ins->volEnvSustain || ch->envSustainActive)
{
- envPos = ins->envVRepS;
- ch->envVCnt = ins->envVP[envPos][0];
- ch->envVAmp = ins->envVP[envPos][1] << 16;
+ envPos = ins->volEnvLoopStart;
+ ch->volEnvTick = ins->volEnvPoints[envPos][0];
+ ch->volEnvValue = (int8_t)(ins->volEnvPoints[envPos][1] & 0xFF) << 16;
}
}
@@ -1439,15 +1453,15 @@
envPos++;
}
- if (envPos < ins->envVPAnt)
+ if (envPos < ins->volEnvLength)
{
envInterpolateFlag = true;
- if ((ins->envVTyp & 2) && ch->envSustainActive)
+ if ((ins->volEnvFlags & ENV_SUSTAIN) && ch->envSustainActive)
{
- if (envPos-1 == ins->envVSust)
+ if (envPos-1 == ins->volEnvSustain)
{
envPos--;
- ch->envVIPValue = 0;
+ ch->volEnvDelta = 0;
envInterpolateFlag = false;
}
}
@@ -1454,14 +1468,16 @@
if (envInterpolateFlag)
{
- ch->envVPos = envPos;
+ ch->volEnvPos = envPos;
- ch->envVIPValue = 0;
- if (ins->envVP[envPos][0] > ins->envVP[envPos-1][0])
+ ch->volEnvDelta = 0;
+ if (ins->volEnvPoints[envPos][0] > ins->volEnvPoints[envPos-1][0])
{
- ch->envVIPValue = ((ins->envVP[envPos][1] - ins->envVP[envPos-1][1]) << 16) / (ins->envVP[envPos][0] - ins->envVP[envPos-1][0]);
+ int32_t delta = (int8_t)((ins->volEnvPoints[envPos][1] - ins->volEnvPoints[envPos-1][1]) & 0xFF) << 16;
+ delta /= (ins->volEnvPoints[envPos][0]-ins->volEnvPoints[envPos-1][0]);
+ ch->volEnvDelta = delta;
- envVal = ch->envVAmp;
+ envVal = ch->volEnvValue;
envDidInterpolate = true;
}
}
@@ -1468,15 +1484,15 @@
}
else
{
- ch->envVIPValue = 0;
+ ch->volEnvDelta = 0;
}
}
if (!envDidInterpolate)
{
- ch->envVAmp += ch->envVIPValue;
+ ch->volEnvValue += ch->volEnvDelta;
- envVal = ch->envVAmp;
+ envVal = ch->volEnvValue;
if (envVal > 64<<16)
{
if (envVal > 128<<16)
@@ -1484,60 +1500,58 @@
else
envVal = 0;
- ch->envVIPValue = 0;
+ ch->volEnvDelta = 0;
}
}
- const int32_t vol = song.globVol * ch->outVol * ch->fadeOutAmp;
+ const int32_t vol = song.globalVolume * ch->outVol * ch->fadeoutVol;
- dVol = vol * (1.0 / (64.0 * 64.0 * 32768.0));
- dVol *= (int32_t)envVal * (1.0 / (64.0 * (1 << 16)));
+ fVol = vol * (1.0f / (64.0f * 64.0f * 32768.0f));
+ fVol *= (int32_t)envVal * (1.0f / (64.0f * (1 << 16))); // volume envelope value
- ch->status |= IS_Vol; // update vol every tick because vol envelope is enabled
+ ch->status |= IS_Vol; // update mixer vol every tick when vol envelope is enabled
}
else
{
- const int32_t vol = song.globVol * ch->outVol * ch->fadeOutAmp;
- dVol = vol * (1.0 / (64.0 * 64.0 * 32768.0));
+ const int32_t vol = song.globalVolume * ch->outVol * ch->fadeoutVol;
+ fVol = vol * (1.0f / (64.0f * 64.0f * 32768.0f));
}
- if (dVol > 1.0) // shouldn't happen, but just in case...
- dVol = 1.0;
-
- ch->dFinalVol = dVol;
- ch->finalVol = (uint8_t)(int32_t)((ch->dFinalVol * 255) + 0.5); // 0.0 .. 1.0 -> 0..255 rounded, used for visuals
+ /* FT2 doesn't clamp here, but it's actually important if you
+ ** move envelope points with the mouse while playing the instrument.
+ */
+ ch->fFinalVol = CLAMP(fVol, 0.0f, 1.0f);
}
else
{
- ch->dFinalVol = 0.0;
- ch->finalVol = 0;
+ ch->fFinalVol = 0.0f;
}
// *** PANNING ENVELOPE ***
envVal = 0;
- if (ins->envPTyp & 1)
+ if (ins->panEnvFlags & ENV_ENABLED)
{
envDidInterpolate = false;
- envPos = ch->envPPos;
+ envPos = ch->panEnvPos;
- if (++ch->envPCnt == ins->envPP[envPos][0])
+ if (++ch->panEnvTick == ins->panEnvPoints[envPos][0])
{
- ch->envPAmp = ins->envPP[envPos][1] << 16;
+ ch->panEnvValue = (int8_t)(ins->panEnvPoints[envPos][1] & 0xFF) << 16;
envPos++;
- if (ins->envPTyp & 4)
+ if (ins->panEnvFlags & ENV_LOOP)
{
envPos--;
- if (envPos == ins->envPRepE)
+ if (envPos == ins->panEnvLoopEnd)
{
- if (!(ins->envPTyp & 2) || envPos != ins->envPSust || ch->envSustainActive)
+ if (!(ins->panEnvFlags & ENV_SUSTAIN) || envPos != ins->panEnvSustain || ch->envSustainActive)
{
- envPos = ins->envPRepS;
+ envPos = ins->panEnvLoopStart;
- ch->envPCnt = ins->envPP[envPos][0];
- ch->envPAmp = ins->envPP[envPos][1] << 16;
+ ch->panEnvTick = ins->panEnvPoints[envPos][0];
+ ch->panEnvValue = (int8_t)(ins->panEnvPoints[envPos][1] & 0xFF) << 16;
}
}
@@ -1544,15 +1558,15 @@
envPos++;
}
- if (envPos < ins->envPPAnt)
+ if (envPos < ins->panEnvLength)
{
envInterpolateFlag = true;
- if ((ins->envPTyp & 2) && ch->envSustainActive)
+ if ((ins->panEnvFlags & ENV_SUSTAIN) && ch->envSustainActive)
{
- if (envPos-1 == ins->envPSust)
+ if (envPos-1 == ins->panEnvSustain)
{
envPos--;
- ch->envPIPValue = 0;
+ ch->panEnvDelta = 0;
envInterpolateFlag = false;
}
}
@@ -1559,14 +1573,16 @@
if (envInterpolateFlag)
{
- ch->envPPos = envPos;
+ ch->panEnvPos = envPos;
- ch->envPIPValue = 0;
- if (ins->envPP[envPos][0] > ins->envPP[envPos-1][0])
+ ch->panEnvDelta = 0;
+ if (ins->panEnvPoints[envPos][0] > ins->panEnvPoints[envPos-1][0])
{
- ch->envPIPValue = ((ins->envPP[envPos][1] - ins->envPP[envPos-1][1]) << 16) / (ins->envPP[envPos][0] - ins->envPP[envPos-1][0]);
+ int32_t delta = (int8_t)((ins->panEnvPoints[envPos][1] - ins->panEnvPoints[envPos-1][1]) & 0xFF) << 16;
+ delta /= (ins->panEnvPoints[envPos][0]-ins->panEnvPoints[envPos-1][0]);
+ ch->panEnvDelta = delta;
- envVal = ch->envPAmp;
+ envVal = ch->panEnvValue;
envDidInterpolate = true;
}
}
@@ -1573,15 +1589,15 @@
}
else
{
- ch->envPIPValue = 0;
+ ch->panEnvDelta = 0;
}
}
if (!envDidInterpolate)
{
- ch->envPAmp += ch->envPIPValue;
+ ch->panEnvValue += ch->panEnvDelta;
- envVal = ch->envPAmp;
+ envVal = ch->panEnvValue;
if (envVal > 64<<16)
{
if (envVal > 128<<16)
@@ -1589,7 +1605,7 @@
else
envVal = 0;
- ch->envPIPValue = 0;
+ ch->panEnvDelta = 0;
}
}
@@ -1597,7 +1613,7 @@
const int32_t pan = 128 - ABS(ch->outPan-128);
const int32_t panAdd = (pan * envVal) >> (16+5);
- ch->finalPan = (uint8_t)CLAMP(ch->outPan + panAdd, 0, 255);
+ ch->finalPan = (uint8_t)(ch->outPan + panAdd);
ch->status |= IS_Pan; // update pan every tick because pan envelope is enabled
}
@@ -1642,9 +1658,9 @@
#endif
ch->eVibPos += ins->vibRate;
- if (ins->vibTyp == 1) autoVibVal = (ch->eVibPos > 127) ? 64 : -64; // square
- else if (ins->vibTyp == 2) autoVibVal = (((ch->eVibPos >> 1) + 64) & 127) - 64; // ramp up
- else if (ins->vibTyp == 3) autoVibVal = ((-(ch->eVibPos >> 1) + 64) & 127) - 64; // ramp down
+ if (ins->vibType == 1) autoVibVal = (ch->eVibPos > 127) ? 64 : -64; // square
+ else if (ins->vibType == 2) autoVibVal = (((ch->eVibPos >> 1) + 64) & 127) - 64; // ramp up
+ else if (ins->vibType == 3) autoVibVal = ((-(ch->eVibPos >> 1) + 64) & 127) - 64; // ramp down
else autoVibVal = vibSineTab[ch->eVibPos]; // sine
autoVibVal <<= 2;
@@ -1677,11 +1693,11 @@
}
// for arpeggio and portamento (semitone-slide mode)
-static uint16_t relocateTon(uint16_t period, uint8_t arpNote, stmTyp *ch)
+static uint16_t relocateTon(uint16_t period, uint8_t arpNote, channel_t *ch)
{
int32_t tmpPeriod;
- const int32_t fineTune = ((int8_t)ch->fineTune >> 3) + 16;
+ const int32_t fineTune = ((int8_t)ch->finetune >> 3) + 16;
/* FT2 bug, should've been 10*12*16. Notes above B-7 (95) will have issues.
** You can only achieve such high notes by having a high relative note setting.
@@ -1711,7 +1727,7 @@
return note2Period[tmpPeriod];
}
-static void vibrato2(stmTyp *ch)
+static void vibrato2(channel_t *ch)
{
uint8_t tmpVib = (ch->vibPos >> 2) & 0x1F;
@@ -1744,11 +1760,11 @@
ch->vibPos += ch->vibSpeed;
}
-static void arp(stmTyp *ch, uint8_t param)
+static void arp(channel_t *ch, uint8_t param)
{
uint8_t note;
- const uint8_t tick = arpTab[song.timer & 0xFF]; // non-FT2 protection (we have 248 extra overflow bytes in LUT, but not more!)
+ const uint8_t tick = arpTab[song.tick & 0xFF]; // non-FT2 protection (we have 248 extra overflow bytes in LUT, but not more!)
if (tick == 0)
{
ch->outPeriod = ch->realPeriod;
@@ -1766,7 +1782,7 @@
ch->status |= IS_Period;
}
-static void portaUp(stmTyp *ch, uint8_t param)
+static void portaUp(channel_t *ch, uint8_t param)
{
if (param == 0)
param = ch->portaUpSpeed;
@@ -1781,7 +1797,7 @@
ch->status |= IS_Period;
}
-static void portaDown(stmTyp *ch, uint8_t param)
+static void portaDown(channel_t *ch, uint8_t param)
{
if (param == 0)
param = ch->portaDownSpeed;
@@ -1796,17 +1812,17 @@
ch->status |= IS_Period;
}
-static void tonePorta(stmTyp *ch, uint8_t param)
+static void tonePorta(channel_t *ch, uint8_t param)
{
- if (ch->portaDir == 0)
+ if (ch->portaDirection == 0)
return;
- if (ch->portaDir > 1)
+ if (ch->portaDirection > 1)
{
ch->realPeriod -= ch->portaSpeed;
if ((int16_t)ch->realPeriod <= (int16_t)ch->wantPeriod)
{
- ch->portaDir = 1;
+ ch->portaDirection = 1;
ch->realPeriod = ch->wantPeriod;
}
}
@@ -1815,7 +1831,7 @@
ch->realPeriod += ch->portaSpeed;
if (ch->realPeriod >= ch->wantPeriod)
{
- ch->portaDir = 1;
+ ch->portaDirection = 1;
ch->realPeriod = ch->wantPeriod;
}
}
@@ -1830,11 +1846,11 @@
(void)param;
}
-static void vibrato(stmTyp *ch, uint8_t param)
+static void vibrato(channel_t *ch, uint8_t param)
{
uint8_t tmp8;
- if (ch->eff > 0)
+ if (param > 0)
{
tmp8 = param & 0x0F;
if (tmp8 > 0)
@@ -1848,7 +1864,7 @@
vibrato2(ch);
}
-static void tonePlusVol(stmTyp *ch, uint8_t param)
+static void tonePlusVol(channel_t *ch, uint8_t param)
{
tonePorta(ch, 0); // the last parameter is actually not used in tonePorta()
volume(ch, param);
@@ -1856,7 +1872,7 @@
(void)param;
}
-static void vibratoPlusVol(stmTyp *ch, uint8_t param)
+static void vibratoPlusVol(channel_t *ch, uint8_t param)
{
vibrato2(ch);
volume(ch, param);
@@ -1864,7 +1880,7 @@
(void)param;
}
-static void tremolo(stmTyp *ch, uint8_t param)
+static void tremolo(channel_t *ch, uint8_t param)
{
uint8_t tmp8;
int16_t tremVol;
@@ -1919,7 +1935,7 @@
ch->tremPos += ch->tremSpeed;
}
-static void volume(stmTyp *ch, uint8_t param) // volume slide
+static void volume(channel_t *ch, uint8_t param) // volume slide
{
if (param == 0)
param = ch->volSlideSpeed;
@@ -1946,7 +1962,7 @@
ch->status |= IS_Vol;
}
-static void globalVolSlide(stmTyp *ch, uint8_t param)
+static void globalVolSlide(channel_t *ch, uint8_t param)
{
if (param == 0)
param = ch->globVolSlideSpeed;
@@ -1953,7 +1969,7 @@
ch->globVolSlideSpeed = param;
- uint8_t newVol = (uint8_t)song.globVol;
+ uint8_t newVol = (uint8_t)song.globalVolume;
if ((param & 0xF0) == 0)
{
newVol -= param;
@@ -1969,20 +1985,20 @@
newVol = 64;
}
- song.globVol = newVol;
+ song.globalVolume = newVol;
- stmTyp *c = stm;
- for (int32_t i = 0; i < song.antChn; i++, c++) // update all voice volumes
+ channel_t *c = channel;
+ for (int32_t i = 0; i < song.numChannels; i++, c++) // update all voice volumes
c->status |= IS_Vol;
}
-static void keyOffCmd(stmTyp *ch, uint8_t param)
+static void keyOffCmd(channel_t *ch, uint8_t param)
{
- if ((uint8_t)(song.tempo-song.timer) == (param & 31))
+ if ((uint8_t)(song.speed-song.tick) == (param & 31))
keyOff(ch);
}
-static void panningSlide(stmTyp *ch, uint8_t param)
+static void panningSlide(channel_t *ch, uint8_t param)
{
if (param == 0)
param = ch->panningSlideSpeed;
@@ -2009,7 +2025,7 @@
ch->status |= IS_Pan;
}
-static void tremor(stmTyp *ch, uint8_t param)
+static void tremor(channel_t *ch, uint8_t param)
{
if (param == 0)
param = ch->tremorSave;
@@ -2039,12 +2055,12 @@
ch->status |= IS_Vol + IS_QuickVol;
}
-static void retrigNote(stmTyp *ch, uint8_t param)
+static void retrigNote(channel_t *ch, uint8_t param)
{
if (param == 0) // E9x with a param of zero is handled in getNewNote()
return;
- if ((song.tempo-song.timer) % param == 0)
+ if ((song.speed-song.tick) % param == 0)
{
startTone(0, 0, 0, ch);
retrigEnvelopeVibrato(ch);
@@ -2051,9 +2067,9 @@
}
}
-static void noteCut(stmTyp *ch, uint8_t param)
+static void noteCut(channel_t *ch, uint8_t param)
{
- if ((uint8_t)(song.tempo-song.timer) == param)
+ if ((uint8_t)(song.speed-song.tick) == param)
{
ch->outVol = ch->realVol = 0;
ch->status |= IS_Vol + IS_QuickVol;
@@ -2060,25 +2076,25 @@
}
}
-static void noteDelay(stmTyp *ch, uint8_t param)
+static void noteDelay(channel_t *ch, uint8_t param)
{
- if ((uint8_t)(song.tempo-song.timer) == param)
+ if ((uint8_t)(song.speed-song.tick) == param)
{
- startTone(ch->tonTyp & 0xFF, 0, 0, ch);
+ startTone(ch->noteData & 0xFF, 0, 0, ch);
- if ((ch->tonTyp & 0xFF00) > 0)
+ if ((ch->noteData & 0xFF00) > 0)
retrigVolume(ch);
retrigEnvelopeVibrato(ch);
- if (ch->volKolVol >= 0x10 && ch->volKolVol <= 0x50)
+ if (ch->volColumnVol >= 0x10 && ch->volColumnVol <= 0x50)
{
- ch->outVol = ch->volKolVol - 16;
+ ch->outVol = ch->volColumnVol - 16;
ch->realVol = ch->outVol;
}
- else if (ch->volKolVol >= 0xC0 && ch->volKolVol <= 0xCF)
+ else if (ch->volColumnVol >= 0xC0 && ch->volColumnVol <= 0xCF)
{
- ch->outPan = (ch->volKolVol & 0x0F) << 4;
+ ch->outPan = (ch->volColumnVol & 0x0F) << 4;
}
}
}
@@ -2103,7 +2119,7 @@
dummy // F
};
-static void E_Effects_TickNonZero(stmTyp *ch, uint8_t param)
+static void E_Effects_TickNonZero(channel_t *ch, uint8_t param)
{
EJumpTab_TickNonZero[param >> 4](ch, param & 0xF);
}
@@ -2148,27 +2164,27 @@
dummy // Z
};
-static void handleEffects_TickNonZero(stmTyp *ch)
+static void handleEffects_TickNonZero(channel_t *ch)
{
- if (ch->stOff)
+ if (ch->channelOff)
return; // muted
// volume column effects
- VJumpTab_TickNonZero[ch->volKolVol >> 4](ch);
+ VJumpTab_TickNonZero[ch->volColumnVol >> 4](ch);
// normal effects
- if ((ch->eff == 0 && ch->effTyp == 0) || ch->effTyp > 35)
+ if ((ch->efx == 0 && ch->efxData == 0) || ch->efx > 35)
return; // no effect
- JumpTab_TickNonZero[ch->effTyp](ch, ch->eff);
+ JumpTab_TickNonZero[ch->efx](ch, ch->efxData);
}
static void getNextPos(void)
{
- if (song.timer != 1)
+ if (song.tick != 1)
return;
- song.pattPos++;
+ song.row++;
if (song.pattDelTime > 0)
{
@@ -2180,18 +2196,18 @@
{
song.pattDelTime2--;
if (song.pattDelTime2 > 0)
- song.pattPos--;
+ song.row--;
}
if (song.pBreakFlag)
{
song.pBreakFlag = false;
- song.pattPos = song.pBreakPos;
+ song.row = song.pBreakPos;
}
- if (song.pattPos >= song.pattLen || song.posJumpFlag)
+ if (song.row >= song.currNumRows || song.posJumpFlag)
{
- song.pattPos = song.pBreakPos;
+ song.row = song.pBreakPos;
song.pBreakPos = 0;
song.posJumpFlag = false;
@@ -2202,15 +2218,15 @@
song.songPos = 0;
bxxOverflow = false;
}
- else if (++song.songPos >= song.len)
+ else if (++song.songPos >= song.songLength)
{
editor.wavReachedEndFlag = true;
- song.songPos = song.repS;
+ song.songPos = song.songLoopStart;
}
assert(song.songPos <= 255);
- song.pattNr = song.songTab[song.songPos & 0xFF];
- song.pattLen = pattLens[song.pattNr & 0xFF];
+ song.pattNum = song.orders[song.songPos & 0xFF];
+ song.currNumRows = patternNumRows[song.pattNum & 0xFF];
}
}
}
@@ -2230,62 +2246,57 @@
void tickReplayer(void) // periodically called from audio callback
{
int32_t i;
- stmTyp *c;
+ channel_t *ch;
if (musicPaused || !songPlaying)
{
- c = stm;
- for (i = 0; i < song.antChn; i++, c++)
- fixaEnvelopeVibrato(c);
+ ch = channel;
+ for (i = 0; i < song.numChannels; i++, ch++)
+ updateChannel(ch);
return;
}
// for song playback counter (hh:mm:ss)
- if (song.speed >= MIN_BPM && song.speed <= MAX_BPM)
- song.musicTime64 += musicTimeTab64[song.speed];
+ if (song.BPM >= MIN_BPM && song.BPM <= MAX_BPM)
+ song.musicTime64 += musicTimeTab64[song.BPM-MIN_BPM];
bool tickZero = false;
- if (--song.timer == 0)
+ if (--song.tick == 0)
{
- song.timer = song.tempo;
+ song.tick = song.speed;
tickZero = true;
}
- song.curReplayerTimer = (uint8_t)song.timer; // for audio/video syncing (and recording)
+ song.curReplayerTick = (uint8_t)song.tick; // for audio/video syncing (and recording)
const bool readNewNote = tickZero && (song.pattDelTime2 == 0);
if (readNewNote)
{
// set audio/video syncing variables
- song.curReplayerPattPos = (uint8_t)song.pattPos;
- song.curReplayerPattNr = (uint8_t)song.pattNr;
+ song.curReplayerRow = (uint8_t)song.row;
+ song.curReplayerPattNum = (uint8_t)song.pattNum;
song.curReplayerSongPos = (uint8_t)song.songPos;
// ----------------------------------------------
- const tonTyp *pattPtr = nilPatternLine;
- if (patt[song.pattNr] != NULL)
- {
- assert(song.pattNr >= 0 && song.pattNr < MAX_PATTERNS &&
- song.pattPos >= 0 && song.pattPos < MAX_PATT_LEN);
+ const note_t *p = nilPatternLine;
+ if (pattern[song.pattNum] != NULL)
+ p = &pattern[song.pattNum][song.row * MAX_CHANNELS];
- pattPtr = &patt[song.pattNr][song.pattPos * MAX_VOICES];
- }
-
- c = stm;
- for (i = 0; i < song.antChn; i++, c++, pattPtr++)
+ ch = channel;
+ for (i = 0; i < song.numChannels; i++, ch++, p++)
{
- getNewNote(c, pattPtr);
- fixaEnvelopeVibrato(c);
+ getNewNote(ch, p);
+ updateChannel(ch);
}
}
else
{
- c = stm;
- for (i = 0; i < song.antChn; i++, c++)
+ ch = channel;
+ for (i = 0; i < song.numChannels; i++, ch++)
{
- handleEffects_TickNonZero(c);
- fixaEnvelopeVibrato(c);
+ handleEffects_TickNonZero(ch);
+ updateChannel(ch);
}
}
@@ -2298,7 +2309,7 @@
if (audioWasntLocked)
lockAudio();
- song.timer = 1;
+ song.tick = 1;
stopVoices();
if (audioWasntLocked)
@@ -2308,12 +2319,12 @@
if (!songPlaying)
{
- setScrollBarEnd(SB_POS_ED, (song.len - 1) + 5);
+ setScrollBarEnd(SB_POS_ED, (song.songLength - 1) + 5);
setScrollBarPos(SB_POS_ED, 0, false);
}
}
-void setPos(int16_t songPos, int16_t pattPos, bool resetTimer)
+void setPos(int16_t songPos, int16_t row, bool resetTimer)
{
const bool audioWasntLocked = !audio.locked;
if (audioWasntLocked)
@@ -2322,35 +2333,35 @@
if (songPos > -1)
{
song.songPos = songPos;
- if (song.len > 0 && song.songPos >= song.len)
- song.songPos = song.len - 1;
+ if (song.songLength > 0 && song.songPos >= song.songLength)
+ song.songPos = song.songLength - 1;
- song.pattNr = song.songTab[song.songPos];
- assert(song.pattNr < MAX_PATTERNS);
- song.pattLen = pattLens[song.pattNr];
+ song.pattNum = song.orders[song.songPos];
+ assert(song.pattNum < MAX_PATTERNS);
+ song.currNumRows = patternNumRows[song.pattNum];
checkMarkLimits(); // non-FT2 safety
}
- if (pattPos > -1)
+ if (row > -1)
{
- song.pattPos = pattPos;
- if (song.pattPos >= song.pattLen)
- song.pattPos = song.pattLen-1;
+ song.row = row;
+ if (song.row >= song.currNumRows)
+ song.row = song.currNumRows-1;
}
// if not playing, update local position variables
if (!songPlaying)
{
- if (pattPos > -1)
+ if (row > -1)
{
- editor.pattPos = (uint8_t)pattPos;
+ editor.row = (uint8_t)row;
ui.updatePatternEditor = true;
}
if (songPos > -1)
{
- editor.editPattern = (uint8_t)song.pattNr;
+ editor.editPattern = (uint8_t)song.pattNum;
editor.songPos = song.songPos;
ui.updatePosSections = true;
}
@@ -2357,70 +2368,71 @@
}
if (resetTimer)
- song.timer = 1;
+ song.tick = 1;
if (audioWasntLocked)
unlockAudio();
}
-void delta2Samp(int8_t *p, int32_t len, uint8_t typ)
+void delta2Samp(int8_t *p, int32_t length, uint8_t smpFlags)
{
- if (typ & 16) len >>= 1; // 16-bit
- if (typ & 32) len >>= 1; // stereo
+ bool sample16Bit = !!(smpFlags & SAMPLE_16BIT);
+ bool stereo = !!(smpFlags & SAMPLE_STEREO);
- if (typ & 32)
+ if (stereo)
{
- if (typ & 16)
+ length >>= 1;
+
+ if (sample16Bit)
{
- int16_t *p16 = (int16_t *)p;
+ int16_t *p16L = (int16_t *)p;
+ int16_t *p16R = (int16_t *)p + length;
int16_t olds16L = 0;
int16_t olds16R = 0;
- for (int32_t i = 0; i < len; i++)
+ for (int32_t i = 0; i < length; i++)
{
- const int16_t news16L = p16[i] + olds16L;
- p16[i] = news16L;
+ const int16_t news16L = p16L[i] + olds16L;
+ p16L[i] = news16L;
olds16L = news16L;
- const int16_t news16R = p16[len+i] + olds16R;
- p16[len+i] = news16R;
+ const int16_t news16R = p16R[i] + olds16R;
+ p16R[i] = news16R;
olds16R = news16R;
- const int32_t tmp32 = olds16L + olds16R;
- p16[i] = (int16_t)(tmp32 >> 1);
+ p16L[i] = (int16_t)((olds16L + olds16R) >> 1);
}
}
- else
+ else // 8-bit
{
- int8_t *p8 = (int8_t *)p;
-
+ int8_t *p8L = (int8_t *)p;
+ int8_t *p8R = (int8_t *)p + length;
int8_t olds8L = 0;
int8_t olds8R = 0;
- for (int32_t i = 0; i < len; i++)
+ for (int32_t i = 0; i < length; i++)
{
- const int8_t news8L = p8[i] + olds8L;
- p8[i] = news8L;
+ const int8_t news8L = p8L[i] + olds8L;
+ p8L[i] = news8L;
olds8L = news8L;
- const int8_t news8R = p8[len+i] + olds8R;
- p8[len+i] = news8R;
+ const int8_t news8R = p8R[i] + olds8R;
+ p8R[i] = news8R;
olds8R = news8R;
- const int16_t tmp16 = olds8L + olds8R;
- p8[i] = (int8_t)(tmp16 >> 1);
+ p8L[i] = (int8_t)((olds8L + olds8R) >> 1);
}
}
}
- else
+ else // mono (normal sample)
{
- if (typ & 16)
+ if (sample16Bit)
{
int16_t *p16 = (int16_t *)p;
int16_t olds16L = 0;
- for (int32_t i = 0; i < len; i++)
+ for (int32_t i = 0; i < length; i++)
{
const int16_t news16 = p16[i] + olds16L;
p16[i] = news16;
@@ -2427,12 +2439,12 @@
olds16L = news16;
}
}
- else
+ else // 8-bit
{
int8_t *p8 = (int8_t *)p;
int8_t olds8L = 0;
- for (int32_t i = 0; i < len; i++)
+ for (int32_t i = 0; i < length; i++)
{
const int8_t news8 = p8[i] + olds8L;
p8[i] = news8;
@@ -2442,51 +2454,48 @@
}
}
-void samp2Delta(int8_t *p, int32_t len, uint8_t typ)
+void samp2Delta(int8_t *p, int32_t length, uint8_t smpFlags)
{
- if (typ & 16)
- len >>= 1; // 16-bit
-
- if (typ & 16)
+ if (smpFlags & SAMPLE_16BIT)
{
int16_t *p16 = (int16_t *)p;
- int16_t news16 = 0;
- for (int32_t i = 0; i < len; i++)
+ int16_t newS16 = 0;
+ for (int32_t i = 0; i < length; i++)
{
- const int16_t olds16 = p16[i];
- p16[i] -= news16;
- news16 = olds16;
+ const int16_t oldS16 = p16[i];
+ p16[i] -= newS16;
+ newS16 = oldS16;
}
}
- else
+ else // 8-bit
{
int8_t *p8 = (int8_t *)p;
- int8_t news8 = 0;
- for (int32_t i = 0; i < len; i++)
+ int8_t newS8 = 0;
+ for (int32_t i = 0; i < length; i++)
{
- const int8_t olds8 = p8[i];
- p8[i] -= news8;
- news8 = olds8;
+ const int8_t oldS8 = p8[i];
+ p8[i] -= newS8;
+ newS8 = oldS8;
}
}
}
-bool allocateInstr(int16_t nr)
+bool allocateInstr(int16_t insNum)
{
- if (instr[nr] != NULL)
+ if (instr[insNum] != NULL)
return false; // already allocated
- instrTyp *p = (instrTyp *)malloc(sizeof (instrTyp));
+ instr_t *p = (instr_t *)malloc(sizeof (instr_t));
if (p == NULL)
return false;
- memset(p, 0, sizeof (instrTyp));
+ memset(p, 0, sizeof (instr_t));
for (int32_t i = 0; i < MAX_SMP_PER_INST; i++)
{
- p->samp[i].pan = 128;
- p->samp[i].vol = 64;
+ p->smp[i].panning = 128;
+ p->smp[i].volume = 64;
}
setStdEnvelope(p, 0, 3);
@@ -2495,7 +2504,7 @@
if (audioWasntLocked)
lockAudio();
- instr[nr] = p;
+ instr[insNum] = p;
if (audioWasntLocked)
unlockAudio();
@@ -2503,22 +2512,19 @@
return true;
}
-void freeInstr(int32_t nr)
+void freeInstr(int32_t insNum)
{
- if (instr[nr] == NULL)
+ if (instr[insNum] == NULL)
return; // not allocated
pauseAudio(); // channel instrument pointers are now cleared
- sampleTyp *s = instr[nr]->samp;
+ sample_t *s = instr[insNum]->smp;
for (int32_t i = 0; i < MAX_SMP_PER_INST; i++, s++) // free sample data
- {
- if (s->origPek != NULL)
- free(s->origPek);
- }
+ freeSmpData(s);
- free(instr[nr]);
- instr[nr] = NULL;
+ free(instr[insNum]);
+ instr[insNum] = NULL;
resumeAudio();
}
@@ -2530,12 +2536,9 @@
{
if (instr[i] != NULL)
{
- sampleTyp *s = instr[i]->samp;
+ sample_t *s = instr[i]->smp;
for (int32_t j = 0; j < MAX_SMP_PER_INST; j++, s++) // free sample data
- {
- if (s->origPek != NULL)
- free(s->origPek);
- }
+ freeSmpData(s);
free(instr[i]);
instr[i] = NULL;
@@ -2544,22 +2547,20 @@
resumeAudio();
}
-void freeSample(int16_t nr, int16_t nr2)
+void freeSample(int16_t insNum, int16_t smpNum)
{
- if (instr[nr] == NULL)
+ if (instr[insNum] == NULL)
return; // instrument not allocated
pauseAudio(); // voice sample pointers are now cleared
- sampleTyp *s = &instr[nr]->samp[nr2];
- if (s->origPek != NULL)
- free(s->origPek);
+ sample_t *s = &instr[insNum]->smp[smpNum];
+ freeSmpData(s);
- memset(s, 0, sizeof (sampleTyp));
+ memset(s, 0, sizeof (sample_t));
+ s->panning = 128;
+ s->volume = 64;
- s->pan = 128;
- s->vol = 64;
-
resumeAudio();
}
@@ -2568,16 +2569,16 @@
pauseAudio();
for (int32_t i = 0; i < MAX_PATTERNS; i++)
{
- if (patt[i] != NULL)
+ if (pattern[i] != NULL)
{
- free(patt[i]);
- patt[i] = NULL;
+ free(pattern[i]);
+ pattern[i] = NULL;
}
}
resumeAudio();
}
-void setStdEnvelope(instrTyp *ins, int16_t i, uint8_t typ)
+void setStdEnvelope(instr_t *ins, int16_t i, uint8_t type)
{
if (ins == NULL)
return;
@@ -2584,35 +2585,35 @@
pauseMusic();
- if (typ & 1)
+ if (type & 1)
{
- memcpy(ins->envVP, config.stdEnvP[i][0], 2*2*12);
- ins->envVPAnt = (uint8_t)config.stdVolEnvAnt[i];
- ins->envVSust = (uint8_t)config.stdVolEnvSust[i];
- ins->envVRepS = (uint8_t)config.stdVolEnvRepS[i];
- ins->envVRepE = (uint8_t)config.stdVolEnvRepE[i];
- ins->fadeOut = config.stdFadeOut[i];
+ memcpy(ins->volEnvPoints, config.stdEnvPoints[i][0], 2*2*12);
+ ins->volEnvLength = (uint8_t)config.stdVolEnvLength[i];
+ ins->volEnvSustain = (uint8_t)config.stdVolEnvSustain[i];
+ ins->volEnvLoopStart = (uint8_t)config.stdVolEnvLoopStart[i];
+ ins->volEnvLoopEnd = (uint8_t)config.stdVolEnvLoopEnd[i];
+ ins->fadeout = config.stdFadeout[i];
ins->vibRate = (uint8_t)config.stdVibRate[i];
ins->vibDepth = (uint8_t)config.stdVibDepth[i];
ins->vibSweep = (uint8_t)config.stdVibSweep[i];
- ins->vibTyp = (uint8_t)config.stdVibTyp[i];
- ins->envVTyp = (uint8_t)config.stdVolEnvTyp[i];
+ ins->vibType = (uint8_t)config.stdVibType[i];
+ ins->volEnvFlags = (uint8_t)config.stdVolEnvFlags[i];
}
- if (typ & 2)
+ if (type & 2)
{
- memcpy(ins->envPP, config.stdEnvP[i][1], 2*2*12);
- ins->envPPAnt = (uint8_t)config.stdPanEnvAnt[0];
- ins->envPSust = (uint8_t)config.stdPanEnvSust[0];
- ins->envPRepS = (uint8_t)config.stdPanEnvRepS[0];
- ins->envPRepE = (uint8_t)config.stdPanEnvRepE[0];
- ins->envPTyp = (uint8_t)config.stdPanEnvTyp[0];
+ memcpy(ins->panEnvPoints, config.stdEnvPoints[i][1], 2*2*12);
+ ins->panEnvLength = (uint8_t)config.stdPanEnvLength[0];
+ ins->panEnvSustain = (uint8_t)config.stdPanEnvSustain[0];
+ ins->panEnvLoopStart = (uint8_t)config.stdPanEnvLoopStart[0];
+ ins->panEnvLoopEnd = (uint8_t)config.stdPanEnvLoopEnd[0];
+ ins->panEnvFlags = (uint8_t)config.stdPanEnvFlags[0];
}
resumeMusic();
}
-void setNoEnvelope(instrTyp *ins)
+void setNoEnvelope(instr_t *ins)
{
if (ins == NULL)
return;
@@ -2619,36 +2620,36 @@
pauseMusic();
- memcpy(ins->envVP, config.stdEnvP[0][0], 2*2*12);
- ins->envVPAnt = (uint8_t)config.stdVolEnvAnt[0];
- ins->envVSust = (uint8_t)config.stdVolEnvSust[0];
- ins->envVRepS = (uint8_t)config.stdVolEnvRepS[0];
- ins->envVRepE = (uint8_t)config.stdVolEnvRepE[0];
- ins->envVTyp = 0;
+ memcpy(ins->volEnvPoints, config.stdEnvPoints[0][0], 2*2*12);
+ ins->volEnvLength = (uint8_t)config.stdVolEnvLength[0];
+ ins->volEnvSustain = (uint8_t)config.stdVolEnvSustain[0];
+ ins->volEnvLoopStart = (uint8_t)config.stdVolEnvLoopStart[0];
+ ins->volEnvLoopEnd = (uint8_t)config.stdVolEnvLoopEnd[0];
+ ins->volEnvFlags = 0;
- memcpy(ins->envPP, config.stdEnvP[0][1], 2*2*12);
- ins->envPPAnt = (uint8_t)config.stdPanEnvAnt[0];
- ins->envPSust = (uint8_t)config.stdPanEnvSust[0];
- ins->envPRepS = (uint8_t)config.stdPanEnvRepS[0];
- ins->envPRepE = (uint8_t)config.stdPanEnvRepE[0];
- ins->envPTyp = 0;
+ memcpy(ins->panEnvPoints, config.stdEnvPoints[0][1], 2*2*12);
+ ins->panEnvLength = (uint8_t)config.stdPanEnvLength[0];
+ ins->panEnvSustain = (uint8_t)config.stdPanEnvSustain[0];
+ ins->panEnvLoopStart = (uint8_t)config.stdPanEnvLoopStart[0];
+ ins->panEnvLoopEnd = (uint8_t)config.stdPanEnvLoopEnd[0];
+ ins->panEnvFlags = 0;
- ins->fadeOut = 0;
+ ins->fadeout = 0;
ins->vibRate = 0;
ins->vibDepth = 0;
ins->vibSweep = 0;
- ins->vibTyp = 0;
+ ins->vibType = 0;
resumeMusic();
}
-bool patternEmpty(uint16_t nr)
+bool patternEmpty(uint16_t pattNum)
{
- if (patt[nr] == NULL)
+ if (pattern[pattNum] == NULL)
return true;
- const uint8_t *scanPtr = (const uint8_t *)patt[nr];
- const uint32_t scanLen = pattLens[nr] * TRACK_WIDTH;
+ const uint8_t *scanPtr = (const uint8_t *)pattern[pattNum];
+ const uint32_t scanLen = patternNumRows[pattNum] * TRACK_WIDTH;
for (uint32_t i = 0; i < scanLen; i++)
{
@@ -2661,21 +2662,21 @@
void updateChanNums(void)
{
- assert(!(song.antChn & 1));
+ assert(!(song.numChannels & 1));
const int32_t maxChannelsShown = getMaxVisibleChannels();
- int32_t channelsShown = song.antChn;
+ int32_t channelsShown = song.numChannels;
if (channelsShown > maxChannelsShown)
channelsShown = maxChannelsShown;
ui.numChannelsShown = (uint8_t)channelsShown;
- ui.pattChanScrollShown = (song.antChn > maxChannelsShown);
+ ui.pattChanScrollShown = (song.numChannels > maxChannelsShown);
if (ui.patternEditorShown)
{
- if (ui.channelOffset > song.antChn-ui.numChannelsShown)
- setScrollBarPos(SB_CHAN_SCROLL, song.antChn - ui.numChannelsShown, true);
+ if (ui.channelOffset > song.numChannels-ui.numChannelsShown)
+ setScrollBarPos(SB_CHAN_SCROLL, song.numChannels - ui.numChannelsShown, true);
}
if (ui.pattChanScrollShown)
@@ -2687,7 +2688,7 @@
showPushButton(PB_CHAN_SCROLL_RIGHT);
}
- setScrollBarEnd(SB_CHAN_SCROLL, song.antChn);
+ setScrollBarEnd(SB_CHAN_SCROLL, song.numChannels);
setScrollBarPageLength(SB_CHAN_SCROLL, ui.numChannelsShown);
}
else
@@ -2705,51 +2706,48 @@
cursor.ch = ui.channelOffset+ui.numChannelsShown - 1;
}
-void conv8BitSample(int8_t *p, int32_t len, bool stereo)
+void conv8BitSample(int8_t *p, int32_t length, bool stereo) // changes sample sign
{
if (stereo)
{
- len /= 2;
+ length >>= 1;
- int8_t *p2 = &p[len];
- for (int32_t i = 0; i < len; i++)
+ int8_t *p2 = &p[length];
+ for (int32_t i = 0; i < length; i++)
{
const int8_t l = p[i] ^ 0x80;
const int8_t r = p2[i] ^ 0x80;
- int16_t tmp16 = l + r;
- p[i] = (int8_t)(tmp16 >> 1);
+ p[i] = (int8_t)((l + r) >> 1);
}
}
else
{
- for (int32_t i = 0; i < len; i++)
+ for (int32_t i = 0; i < length; i++)
p[i] ^= 0x80;
}
}
-void conv16BitSample(int8_t *p, int32_t len, bool stereo)
+void conv16BitSample(int8_t *p, int32_t length, bool stereo) // changes sample sign
{
int16_t *p16_1 = (int16_t *)p;
- len /= 2;
if (stereo)
{
- len /= 2;
+ length >>= 1;
- int16_t *p16_2 = (int16_t *)&p[len * 2];
- for (int32_t i = 0; i < len; i++)
+ int16_t *p16_2 = (int16_t *)p + length;
+ for (int32_t i = 0; i < length; i++)
{
const int16_t l = p16_1[i] ^ 0x8000;
const int16_t r = p16_2[i] ^ 0x8000;
- int32_t tmp32 = l + r;
- p16_1[i] = (int16_t)(tmp32 >> 1);
+ p16_1[i] = (int16_t)((l + r) >> 1);
}
}
else
{
- for (int32_t i = 0; i < len; i++)
+ for (int32_t i = 0; i < length; i++)
p16_1[i] ^= 0x8000;
}
}
@@ -2785,23 +2783,22 @@
bool setupReplayer(void)
{
for (int32_t i = 0; i < MAX_PATTERNS; i++)
- pattLens[i] = 64;
+ patternNumRows[i] = 64;
playMode = PLAYMODE_IDLE;
songPlaying = false;
// unmute all channels (must be done before resetChannels() call)
- for (int32_t i = 0; i < MAX_VOICES; i++)
+ for (int32_t i = 0; i < MAX_CHANNELS; i++)
editor.chnMode[i] = 1;
resetChannels();
- song.len = 1;
- song.antChn = 8;
- editor.speed = song.speed = 125;
- editor.tempo = song.tempo = 6;
- editor.globalVol = song.globVol = 64;
- song.initialTempo = song.tempo;
+ song.songLength = 1;
+ song.numChannels = 8;
+ editor.BPM = song.BPM = 125;
+ editor.speed = song.initialSpeed = song.speed = 6;
+ editor.globalVolume = song.globalVolume = 64;
audio.linearPeriodsFlag = true;
note2Period = linearPeriods;
@@ -2820,7 +2817,7 @@
showErrorMsgBox("Not enough memory!");
return false;
}
- instr[0]->samp[0].vol = 0;
+ instr[0]->smp[0].volume = 0;
if (!allocateInstr(130))
{
@@ -2827,7 +2824,7 @@
showErrorMsgBox("Not enough memory!");
return false;
}
- memset(instr[130], 0, sizeof (instrTyp));
+ memset(instr[130], 0, sizeof (instr_t));
if (!allocateInstr(131)) // Instr. Ed. display instrument for unallocated/empty instruments
{
@@ -2835,9 +2832,9 @@
return false;
}
- memset(instr[131], 0, sizeof (instrTyp));
+ memset(instr[131], 0, sizeof (instr_t));
for (int32_t i = 0; i < 16; i++)
- instr[131]->samp[i].pan = 128;
+ instr[131]->smp[i].panning = 128;
editor.tmpPattern = 65535; // pattern editor update/redraw kludge
return true;
@@ -2860,10 +2857,10 @@
resetPlaybackTime();
// non-FT2 fix: If song speed was 0, set it back to initial speed on play
- if (song.tempo == 0)
- song.tempo = song.initialTempo;
+ if (song.speed == 0)
+ song.speed = song.initialSpeed;
- audio.dTickSampleCounter = 0.0; // zero tick sample counter so that it will instantly initiate a tick
+ audio.tickSampleCounter64 = 0; // zero tick sample counter so that it will instantly initiate a tick
unlockMixerCallback();
@@ -2885,13 +2882,13 @@
}
else
{
- for (uint8_t i = 0; i < MAX_VOICES; i++)
- playTone(i, 0, 97, -1, 0, 0);
+ for (uint8_t i = 0; i < MAX_CHANNELS; i++)
+ playTone(i, 0, NOTE_OFF, -1, 0, 0);
}
- // if song was playing, update local pattPos (fixes certain glitches)
+ // if song was playing, update local row (fixes certain glitches)
if (songWasPlaying)
- editor.pattPos = song.pattPos;
+ editor.row = song.row;
#ifdef HAS_MIDI
midi.currMIDIVibDepth = 0;
@@ -2900,35 +2897,40 @@
memset(editor.keyOnTab, 0, sizeof (editor.keyOnTab));
+ // kludge to prevent UI from being out of sync with replayer vars on stop
+ song.songPos = editor.songPos;
+ song.row = editor.row;
+ song.pattNum = editor.editPattern;
+
ui.updatePosSections = true;
ui.updatePatternEditor = true;
// certain non-FT2 fixes
- song.timer = editor.timer = 1;
- song.globVol = editor.globalVol = 64;
+ song.tick = editor.tick = 1;
+ song.globalVolume = editor.globalVolume = 64;
ui.drawGlobVolFlag = true;
}
// from keyboard/smp. ed.
-void playTone(uint8_t stmm, uint8_t inst, uint8_t ton, int8_t vol, uint16_t midiVibDepth, uint16_t midiPitch)
+void playTone(uint8_t chNum, uint8_t insNum, uint8_t note, int8_t vol, uint16_t midiVibDepth, uint16_t midiPitch)
{
- instrTyp *ins = instr[inst];
+ instr_t *ins = instr[insNum];
if (ins == NULL)
return;
- assert(stmm < MAX_VOICES && inst <= MAX_INST && ton <= 97);
- stmTyp *ch = &stm[stmm];
+ assert(chNum < MAX_CHANNELS && insNum <= MAX_INST && note <= NOTE_OFF);
+ channel_t *ch = &channel[chNum];
// FT2 bugfix: Don't play tone if certain requirements are not met
- if (ton != 97)
+ if (note != NOTE_OFF)
{
- if (ton == 0 || ton > 96)
+ if (note == 0 || note > 96)
return;
- sampleTyp *s = &ins->samp[ins->ta[ton-1] & 0xF];
+ sample_t *s = &ins->smp[ins->note2SampleLUT[note-1] & 0xF];
- int16_t newTon = (int16_t)ton + s->relTon;
- if (s->pek == NULL || s->len == 0 || newTon <= 0 || newTon >= 12*10)
+ int16_t finalNote = (int16_t)note + s->relativeNote;
+ if (s->dataPtr == NULL || s->length == 0 || finalNote <= 0 || finalNote >= 12*10)
return;
}
// -------------------
@@ -2935,19 +2937,19 @@
lockAudio();
- if (inst != 0 && ton != 97)
+ if (insNum != 0 && note != NOTE_OFF)
{
- ch->tonTyp = (inst << 8) | (ch->tonTyp & 0xFF);
- ch->instrNr = inst;
+ ch->noteData = (insNum << 8) | (ch->noteData & 0xFF);
+ ch->instrNum = insNum;
}
- ch->tonTyp = (ch->tonTyp & 0xFF00) | ton;
- ch->effTyp = 0;
- ch->eff = 0;
+ ch->noteData = (ch->noteData & 0xFF00) | note;
+ ch->efx = 0;
+ ch->efxData = 0;
- startTone(ton, 0, 0, ch);
+ startTone(note, 0, 0, ch);
- if (ton != 97)
+ if (note != NOTE_OFF)
{
retrigVolume(ch);
retrigEnvelopeVibrato(ch);
@@ -2963,39 +2965,39 @@
ch->midiVibDepth = midiVibDepth;
ch->midiPitch = midiPitch;
- fixaEnvelopeVibrato(ch);
+ updateChannel(ch);
unlockAudio();
}
// smp. ed.
-void playSample(uint8_t stmm, uint8_t inst, uint8_t smpNr, uint8_t ton, uint16_t midiVibDepth, uint16_t midiPitch)
+void playSample(uint8_t chNum, uint8_t insNum, uint8_t smpNum, uint8_t note, uint16_t midiVibDepth, uint16_t midiPitch)
{
- if (instr[inst] == NULL)
+ if (instr[insNum] == NULL)
return;
// for sampling playback line in Smp. Ed.
- lastChInstr[stmm].instrNr = 255;
- lastChInstr[stmm].sampleNr = 255;
+ lastChInstr[chNum].instrNum = 255;
+ lastChInstr[chNum].smpNum = 255;
editor.curPlayInstr = 255;
editor.curPlaySmp = 255;
- assert(stmm < MAX_VOICES && inst <= MAX_INST && smpNr < MAX_SMP_PER_INST && ton <= 97);
- stmTyp *ch = &stm[stmm];
+ assert(chNum < MAX_CHANNELS && insNum <= MAX_INST && smpNum < MAX_SMP_PER_INST && note <= NOTE_OFF);
+ channel_t *ch = &channel[chNum];
- memcpy(&instr[130]->samp[0], &instr[inst]->samp[smpNr], sizeof (sampleTyp));
+ memcpy(&instr[130]->smp[0], &instr[insNum]->smp[smpNum], sizeof (sample_t));
- uint8_t vol = instr[inst]->samp[smpNr].vol;
+ uint8_t vol = instr[insNum]->smp[smpNum].volume;
lockAudio();
- ch->instrNr = 130;
- ch->tonTyp = (ch->instrNr << 8) | ton;
- ch->effTyp = 0;
+ ch->instrNum = 130;
+ ch->noteData = (ch->instrNum << 8) | note;
+ ch->efx = 0;
- startTone(ton, 0, 0, ch);
+ startTone(note, 0, 0, ch);
- if (ton != 97)
+ if (note != NOTE_OFF)
{
retrigVolume(ch);
retrigEnvelopeVibrato(ch);
@@ -3008,11 +3010,11 @@
ch->midiVibDepth = midiVibDepth;
ch->midiPitch = midiPitch;
- fixaEnvelopeVibrato(ch);
+ updateChannel(ch);
unlockAudio();
- while (ch->status & IS_NyTon); // wait for sample to latch in mixer
+ while (ch->status & IS_Trigger); // wait for sample to latch in mixer
// for sampling playback line in Smp. Ed.
editor.curPlayInstr = editor.curInstr;
@@ -3020,52 +3022,45 @@
}
// smp. ed.
-void playRange(uint8_t stmm, uint8_t inst, uint8_t smpNr, uint8_t ton, uint16_t midiVibDepth, uint16_t midiPitch, int32_t offs, int32_t len)
+void playRange(uint8_t chNum, uint8_t insNum, uint8_t smpNum, uint8_t note, uint16_t midiVibDepth, uint16_t midiPitch, int32_t smpOffset, int32_t length)
{
- if (instr[inst] == NULL)
+ if (instr[insNum] == NULL)
return;
// for sampling playback line in Smp. Ed.
- lastChInstr[stmm].instrNr = 255;
- lastChInstr[stmm].sampleNr = 255;
+ lastChInstr[chNum].instrNum = 255;
+ lastChInstr[chNum].smpNum = 255;
editor.curPlayInstr = 255;
editor.curPlaySmp = 255;
- assert(stmm < MAX_VOICES && inst <= MAX_INST && smpNr < MAX_SMP_PER_INST && ton <= 97);
+ assert(chNum < MAX_CHANNELS && insNum <= MAX_INST && smpNum < MAX_SMP_PER_INST && note <= NOTE_OFF);
- stmTyp *ch = &stm[stmm];
- sampleTyp *s = &instr[130]->samp[0];
+ channel_t *ch = &channel[chNum];
+ sample_t *s = &instr[130]->smp[0];
- memcpy(s, &instr[inst]->samp[smpNr], sizeof (sampleTyp));
+ memcpy(s, &instr[insNum]->smp[smpNum], sizeof (sample_t));
- uint8_t vol = instr[inst]->samp[smpNr].vol;
+ uint8_t vol = instr[insNum]->smp[smpNum].volume;
- if (s->typ & 16)
- {
- offs &= 0xFFFFFFFE;
- len &= 0xFFFFFFFE;
- }
-
lockAudio();
- s->len = offs + len;
- s->repS = 0;
- s->repL = 0;
- s->typ &= 16; // only keep 8-bit/16-bit flag (disable loop)
+ s->length = smpOffset + length;
+ s->loopStart = 0;
+ s->loopLength = 0;
+ DISABLE_LOOP(s->flags); // disable loop on sample #129 (placeholder)
- int32_t samplePlayOffset = offs;
- if (s->typ & 16)
- samplePlayOffset >>= 1;
+ int32_t samplePlayOffset = smpOffset;
- ch->instrNr = 130;
- ch->tonTyp = (ch->instrNr << 8) | ton;
- ch->effTyp = 0;
+ ch->instrNum = 130;
+ ch->noteData = (ch->instrNum << 8) | note;
+ ch->efx = 0;
+ ch->efxData = 0;
- startTone(ton, 0, 0, ch);
+ startTone(note, 0, 0, ch);
ch->smpStartPos = samplePlayOffset;
- if (ton != 97)
+ if (note != NOTE_OFF)
{
retrigVolume(ch);
retrigEnvelopeVibrato(ch);
@@ -3078,11 +3073,11 @@
ch->midiVibDepth = midiVibDepth;
ch->midiPitch = midiPitch;
- fixaEnvelopeVibrato(ch);
+ updateChannel(ch);
unlockAudio();
- while (ch->status & IS_NyTon); // wait for sample to latch in mixer
+ while (ch->status & IS_Trigger); // wait for sample to latch in mixer
// for sampling playback line in Smp. Ed.
editor.curPlayInstr = editor.curInstr;
@@ -3095,21 +3090,23 @@
if (audioWasntLocked)
lockAudio();
- stmTyp *ch = stm;
- for (int32_t i = 0; i < MAX_VOICES; i++, ch++)
+ channel_t *ch = channel;
+ for (int32_t i = 0; i < MAX_CHANNELS; i++, ch++)
{
- lastChInstr[i].sampleNr = 255;
- lastChInstr[i].instrNr = 255;
+ lastChInstr[i].smpNum = 255;
+ lastChInstr[i].instrNum = 255;
- ch->tonTyp = 0;
- ch->relTonNr = 0;
- ch->instrNr = 0;
+ ch->noteData = 0;
+ ch->relativeNote = 0;
+ ch->smpNum = 0;
+ ch->smpPtr = NULL;
+ ch->instrNum = 0;
ch->instrPtr = instr[0]; // important: set instrument pointer to instr 0 (placeholder instrument)
ch->status = IS_Vol;
ch->realVol = 0;
ch->outVol = 0;
ch->oldVol = 0;
- ch->dFinalVol = 0.0;
+ ch->fFinalVol = 0.0f;
ch->oldPan = 128;
ch->outPan = 128;
ch->finalPan = 128;
@@ -3116,8 +3113,7 @@
ch->vibDepth = 0;
ch->midiVibDepth = 0;
ch->midiPitch = 0;
- ch->smpPtr = NULL;
- ch->portaDir = 0; // FT2 bugfix: weird 3xx behavior if not used with note
+ ch->portaDirection = 0; // FT2 bugfix: weird 3xx behavior if not used with note
stopVoice(i);
}
@@ -3129,7 +3125,6 @@
stopAllScopes();
resetAudioDither();
resetCachedMixerVars();
- resetCachedScopeVars();
// wait for scope thread to finish, so that we know pointers aren't deprecated
while (editor.scopeThreadMutex);
@@ -3147,10 +3142,10 @@
if (songPlaying)
{
- song.globVol = 64;
+ song.globalVolume = 64;
- stmTyp *ch = stm;
- for (int32_t i = 0; i < song.antChn; i++, ch++)
+ channel_t *ch = channel;
+ for (int32_t i = 0; i < song.numChannels; i++, ch++)
ch->status |= IS_Vol;
}
}
@@ -3161,8 +3156,8 @@
setPos((int16_t)pos, 0, true);
// non-FT2 fix: If song speed was 0, set it back to initial speed
- if (song.tempo == 0)
- song.tempo = song.initialTempo;
+ if (song.speed == 0)
+ song.speed = song.initialSpeed;
}
void decSongPos(void)
@@ -3183,7 +3178,7 @@
void incSongPos(void)
{
- if (song.songPos == song.len-1)
+ if (song.songPos == song.songLength-1)
return;
const bool audioWasntLocked = !audio.locked;
@@ -3190,7 +3185,7 @@
if (audioWasntLocked)
lockAudio();
- if (song.songPos < song.len-1)
+ if (song.songPos < song.songLength-1)
setNewSongPos(song.songPos + 1);
if (audioWasntLocked)
@@ -3287,7 +3282,7 @@
void setSyncedReplayerVars(void)
{
- uint8_t scopeUpdateStatus[MAX_VOICES];
+ uint8_t scopeUpdateStatus[MAX_CHANNELS];
pattSyncEntry = NULL;
chSyncEntry = NULL;
@@ -3308,7 +3303,7 @@
if (chSyncEntry == NULL)
break;
- for (int32_t i = 0; i < song.antChn; i++)
+ for (int32_t i = 0; i < song.numChannels; i++)
scopeUpdateStatus[i] |= chSyncEntry->channels[i].status; // yes, OR the status
if (!chQueuePop())
@@ -3356,23 +3351,23 @@
// we have a new tick
- editor.timer = pattSyncEntry->timer;
+ editor.tick = pattSyncEntry->tick;
- if (editor.speed != pattSyncEntry->speed)
+ if (editor.BPM != pattSyncEntry->BPM)
{
- editor.speed = pattSyncEntry->speed;
+ editor.BPM = pattSyncEntry->BPM;
ui.drawBPMFlag = true;
}
- if (editor.tempo != pattSyncEntry->tempo)
+ if (editor.speed != pattSyncEntry->speed)
{
- editor.tempo = pattSyncEntry->tempo;
+ editor.speed = pattSyncEntry->speed;
ui.drawSpeedFlag = true;
}
- if (editor.globalVol != pattSyncEntry->globalVol)
+ if (editor.globalVolume != pattSyncEntry->globalVolume)
{
- editor.globalVol = pattSyncEntry->globalVol;
+ editor.globalVolume = pattSyncEntry->globalVolume;
ui.drawGlobVolFlag = true;
}
@@ -3383,15 +3378,15 @@
}
// somewhat of a kludge...
- if (editor.tmpPattern != pattSyncEntry->pattern || editor.pattPos != pattSyncEntry->patternPos)
+ if (editor.tmpPattern != pattSyncEntry->pattNum || editor.row != pattSyncEntry->row)
{
// set pattern number
- editor.editPattern = editor.tmpPattern = pattSyncEntry->pattern;
+ editor.editPattern = editor.tmpPattern = pattSyncEntry->pattNum;
checkMarkLimits();
ui.drawPattNumLenFlag = true;
// set row
- editor.pattPos = (uint8_t)pattSyncEntry->patternPos;
+ editor.row = (uint8_t)pattSyncEntry->row;
ui.updatePatternEditor = true;
}
}
--- a/src/ft2_replayer.h
+++ b/src/ft2_replayer.h
@@ -4,6 +4,7 @@
#include <stdbool.h>
#include "ft2_unicode.h"
#include "mixer/ft2_windowed_sinc.h"
+#include "ft2_cpu.h"
enum
{
@@ -10,7 +11,7 @@
// voice flags
IS_Vol = 1, // set volume
IS_Period = 2, // set resampling rate
- IS_NyTon = 4, // trigger new sample
+ IS_Trigger = 4, // trigger sample
IS_Pan = 8, // set panning
IS_QuickVol = 16, // 5ms volramp instead of tick ms
@@ -37,12 +38,15 @@
CURSOR_EFX2 = 7
};
-// DO NOT TOUCH!
-#define MIN_BPM 1
-#define MAX_BPM 999
-#define MAX_VOICES 32
-#define TRACK_WIDTH (5 * MAX_VOICES)
+// do not touch these!
+#define MIN_BPM 32
+#define MAX_BPM 255
+#define MAX_SPEED 31
+#define MAX_CHANNELS 32
+#define TRACK_WIDTH (5 * MAX_CHANNELS)
#define MAX_FRQ 32000
+#define C4_FREQ 8363
+#define NOTE_OFF 97
#define MAX_NOTES (10*12*16+16)
#define MAX_PATTERNS 256
#define MAX_PATT_LEN 256
@@ -55,6 +59,29 @@
#define MAX_SAMPLE_LEN 0x3FFFFFFF
#define PROG_NAME_STR "Fasttracker II clone"
+enum // sample flags
+{
+ LOOP_OFF = 0,
+ LOOP_FWD = 1,
+ LOOP_BIDI = 2,
+ SAMPLE_16BIT = 16,
+ SAMPLE_STEREO = 32,
+ SAMPLE_ADPCM = 64, // not an existing flag, but used by loader
+};
+
+enum // envelope flags
+{
+ ENV_ENABLED = 1,
+ ENV_SUSTAIN = 2,
+ ENV_LOOP = 4
+};
+
+#define GET_LOOPTYPE(smpFlags) ((smpFlags) & (LOOP_FWD | LOOP_BIDI))
+#define DISABLE_LOOP(smpFlags) ((smpFlags) &= ~(LOOP_FWD | LOOP_BIDI))
+#define SAMPLE_LENGTH_BYTES(smp) (smp->length << !!(smp->flags & SAMPLE_16BIT))
+#define FINETUNE_MOD2XM(f) (((uint8_t)(f) & 0x0F) << 4)
+#define FINETUNE_XM2MOD(f) ((uint8_t)(f) >> 4)
+
/* Some of the following structs MUST be packed!
** Please do NOT edit these structs unless you
** absolutely know what you are doing!
@@ -64,113 +91,112 @@
#pragma pack(push)
#pragma pack(1)
#endif
-typedef struct songHeaderTyp_t
+typedef struct xmHdr_t
{
- char sig[17], name[21], progName[20];
- uint16_t ver;
+ char ID[17], name[20], x1A, progName[20];
+ uint16_t version;
int32_t headerSize;
- uint16_t len, repS, antChn, antPtn, antInstrs, flags, defTempo, defSpeed;
- uint8_t songTab[256];
+ uint16_t numOrders, songLoopStart, numChannels, numPatterns;
+ uint16_t numInstr, flags, speed, BPM;
+ uint8_t orders[256];
}
#ifdef __GNUC__
__attribute__ ((packed))
#endif
-songHeaderTyp;
+xmHdr_t;
-typedef struct patternHeaderTyp_t
+typedef struct xmPatHdr_t
{
- int32_t patternHeaderSize;
- uint8_t typ;
- int16_t pattLen;
- uint16_t dataLen;
+ int32_t headerSize;
+ uint8_t type;
+ int16_t numRows;
+ uint16_t dataSize;
}
#ifdef __GNUC__
__attribute__ ((packed))
#endif
-patternHeaderTyp;
+xmPatHdr_t;
-typedef struct songMODInstrHeaderTyp_t
+typedef struct modSmpHdr_t
{
char name[22];
- uint16_t len;
- uint8_t fine, vol;
- uint16_t repS, repL;
+ uint16_t length;
+ uint8_t finetune, volume;
+ uint16_t loopStart, loopLength;
}
#ifdef __GNUC__
__attribute__ ((packed))
#endif
-songMODInstrHeaderTyp;
+modSmpHdr_t;
-typedef struct songMOD31HeaderTyp_t
+typedef struct modHdr_t
{
char name[20];
- songMODInstrHeaderTyp instr[31];
- uint8_t len, repS, songTab[128];
- char sig[4];
+ modSmpHdr_t smp[31];
+ uint8_t numOrders, songLoopStart, orders[128];
+ char ID[4];
}
#ifdef __GNUC__
__attribute__ ((packed))
#endif
-songMOD31HeaderTyp;
+modHdr_t;
-typedef struct sampleHeaderTyp_t
+typedef struct xmSmpHdr_t
{
- int32_t len, repS, repL;
- uint8_t vol;
- int8_t fine;
- uint8_t typ, pan;
- int8_t relTon;
- uint8_t nameLen;
+ uint32_t length, loopStart, loopLength;
+ uint8_t volume;
+ int8_t finetune;
+ uint8_t flags, panning;
+ int8_t relativeNote;
+ uint8_t nameLength; // only handled before saving (ignored under load)
char name[22];
}
#ifdef __GNUC__
__attribute__ ((packed))
#endif
-sampleHeaderTyp;
+xmSmpHdr_t;
-typedef struct instrHeaderTyp_t
+typedef struct xmInsHdr_t
{
uint32_t instrSize;
char name[22];
- uint8_t typ;
- int16_t antSamp;
+ uint8_t type;
+ int16_t numSamples;
int32_t sampleSize;
- uint8_t ta[96];
- int16_t envVP[12][2], envPP[12][2];
- uint8_t envVPAnt, envPPAnt;
- uint8_t envVSust, envVRepS, envVRepE;
- uint8_t envPSust, envPRepS, envPRepE;
- uint8_t envVTyp, envPTyp;
- uint8_t vibTyp, vibSweep, vibDepth, vibRate;
- uint16_t fadeOut;
+ uint8_t note2SampleLUT[96];
+ int16_t volEnvPoints[12][2], panEnvPoints[12][2];
+ uint8_t volEnvLength, panEnvLength;
+ uint8_t volEnvSustain, volEnvLoopStart, volEnvLoopEnd;
+ uint8_t panEnvSustain, panEnvLoopStart, panEnvLoopEnd;
+ uint8_t volEnvFlags, panEnvFlags;
+ uint8_t vibType, vibSweep, vibDepth, vibRate;
+ uint16_t fadeout;
uint8_t midiOn, midiChannel;
int16_t midiProgram, midiBend;
int8_t mute;
- uint8_t reserved[15];
- sampleHeaderTyp samp[16];
+ uint8_t junk[15];
+ xmSmpHdr_t smp[16];
}
#ifdef __GNUC__
__attribute__ ((packed))
#endif
-instrHeaderTyp;
+xmInsHdr_t;
-typedef struct tonTyp_t // must be packed on some systems, even though it consists of bytes only
+typedef struct pattNote_t // must be packed!
{
- uint8_t ton, instr, vol, effTyp, eff;
+ uint8_t note, instr, vol, efx, efxData;
}
#ifdef __GNUC__
__attribute__ ((packed))
#endif
-tonTyp;
+note_t;
typedef struct syncedChannel_t // used for audio/video sync queue (pack to save RAM)
{
- uint8_t status;
- uint8_t pianoNoteNr;
- uint8_t sampleNr, instrNr;
- uint16_t smpStartPos;
- uint8_t vol;
- double dHz;
+ uint8_t status, pianoNoteNum, smpNum, instrNum;
+ int32_t smpStartPos;
+ uint8_t scopeVolume;
+ uintCPUWord_t scopeDelta;
}
#ifdef __GNUC__
__attribute__ ((packed))
@@ -181,13 +207,13 @@
#pragma pack(pop)
#endif
-typedef struct sampleTyp_t
+typedef struct sample_t
{
char name[22+1];
- bool fixed;
- int8_t fine, relTon, *pek, *origPek;
- uint8_t vol, typ, pan;
- int32_t len, repS, repL;
+ bool isFixed;
+ int8_t finetune, relativeNote, *dataPtr, *origDataPtr;
+ uint8_t volume, flags, panning;
+ int32_t length, loopStart, loopLength;
// fix for resampling interpolation taps
int8_t leftEdgeTapSamples8[SINC_TAPS+SINC_LEFT_TAPS];
@@ -194,63 +220,62 @@
int16_t leftEdgeTapSamples16[SINC_TAPS+SINC_LEFT_TAPS];
int16_t fixedSmp[SINC_RIGHT_TAPS];
int32_t fixedPos;
-} sampleTyp;
+} sample_t;
-typedef struct instrTyp_t
+typedef struct instr_t
{
bool midiOn, mute;
- uint8_t midiChannel, ta[96];
- uint8_t envVPAnt, envPPAnt;
- uint8_t envVSust, envVRepS, envVRepE;
- uint8_t envPSust, envPRepS, envPRepE;
- uint8_t envVTyp, envPTyp;
- uint8_t vibTyp, vibSweep, vibDepth, vibRate;
- uint16_t fadeOut;
- int16_t envVP[12][2], envPP[12][2], midiProgram, midiBend;
- int16_t antSamp; // used by loader only
- sampleTyp samp[16];
-} instrTyp;
+ uint8_t midiChannel, note2SampleLUT[96];
+ uint8_t volEnvLength, panEnvLength;
+ uint8_t volEnvSustain, volEnvLoopStart, volEnvLoopEnd;
+ uint8_t panEnvSustain, panEnvLoopStart, panEnvLoopEnd;
+ uint8_t volEnvFlags, panEnvFlags;
+ uint8_t vibType, vibSweep, vibDepth, vibRate;
+ uint16_t fadeout;
+ int16_t volEnvPoints[12][2], panEnvPoints[12][2], midiProgram, midiBend;
+ int16_t numSamples; // used by loader only
+ sample_t smp[16];
+} instr_t;
-typedef struct stmTyp_t
+typedef struct channel_t
{
- bool envSustainActive, stOff, mute;
+ bool envSustainActive, channelOff, mute;
volatile uint8_t status, tmpStatus;
- int8_t relTonNr, fineTune;
- uint8_t sampleNr, instrNr, effTyp, eff, smpOffset, tremorSave, tremorPos;
- uint8_t globVolSlideSpeed, panningSlideSpeed, waveCtrl, portaDir;
+ int8_t relativeNote, finetune;
+ uint8_t smpNum, instrNum, efxData, efx, smpOffset, tremorSave, tremorPos;
+ uint8_t globVolSlideSpeed, panningSlideSpeed, waveCtrl, portaDirection;
uint8_t glissFunk, vibPos, tremPos, vibSpeed, vibDepth, tremSpeed, tremDepth;
- uint8_t pattPos, loopCnt, volSlideSpeed, fVolSlideUpSpeed, fVolSlideDownSpeed;
+ uint8_t jumpToRow, patLoopCounter, volSlideSpeed, fVolSlideUpSpeed, fVolSlideDownSpeed;
uint8_t fPortaUpSpeed, fPortaDownSpeed, ePortaUpSpeed, ePortaDownSpeed;
uint8_t portaUpSpeed, portaDownSpeed, retrigSpeed, retrigCnt, retrigVol;
- uint8_t volKolVol, tonNr, envPPos, eVibPos, envVPos, realVol, oldVol, outVol;
+ uint8_t volColumnVol, noteNum, panEnvPos, eVibPos, volEnvPos, realVol, oldVol, outVol;
uint8_t oldPan, outPan, finalPan;
int16_t midiPitch;
- uint16_t outPeriod, realPeriod, finalPeriod, tonTyp, wantPeriod, portaSpeed;
- uint16_t envVCnt, envPCnt, eVibAmp, eVibSweep;
- uint16_t fadeOutAmp, fadeOutSpeed, midiVibDepth;
- int32_t envVIPValue, envPIPValue, envVAmp, envPAmp;
+ uint16_t outPeriod, realPeriod, finalPeriod, noteData, wantPeriod, portaSpeed;
+ uint16_t volEnvTick, panEnvTick, eVibAmp, eVibSweep;
+ uint16_t fadeoutVol, fadeoutSpeed, midiVibDepth;
+ int32_t volEnvDelta, panEnvDelta, volEnvValue, panEnvValue;
int32_t oldFinalPeriod, smpStartPos;
- uint8_t finalVol; // 0..255 (for visuals)
- double dFinalVol; // 0.0 .. 1.0 (for mixer)
+ float fFinalVol; // 0.0f .. 1.0f
- sampleTyp *smpPtr;
- instrTyp *instrPtr;
-} stmTyp;
+ sample_t *smpPtr;
+ instr_t *instrPtr;
+} channel_t;
-typedef struct songTyp_t
+typedef struct song_t
{
bool pBreakFlag, posJumpFlag, isModified;
char name[20+1], instrName[1+MAX_INST][22+1];
- uint8_t curReplayerTimer, curReplayerPattPos, curReplayerSongPos, curReplayerPattNr; // used for audio/video sync queue
- uint8_t pattDelTime, pattDelTime2, pBreakPos, songTab[MAX_ORDERS];
- int16_t songPos, pattNr, pattPos, pattLen;
- int32_t antChn;
- uint16_t len, repS, speed, tempo, globVol, timer, ver, initialTempo;
+ uint8_t curReplayerTick, curReplayerRow, curReplayerSongPos, curReplayerPattNum; // used for audio/video sync queue
+ uint8_t pattDelTime, pattDelTime2, pBreakPos, orders[MAX_ORDERS];
+ int16_t songPos, pattNum, row, currNumRows;
+ uint16_t songLength, songLoopStart, BPM, speed, initialSpeed, globalVolume, tick;
+ int32_t numChannels;
uint64_t musicTime64;
-} songTyp;
+} song_t;
-double getSampleC4Rate(sampleTyp *s);
+double getSampleC4Rate(sample_t *s);
void setNewSongPos(int32_t pos);
void resetReplayerState(void);
@@ -257,12 +282,12 @@
void fixString(char *str, int32_t lastChrPos); // removes leading spaces and 0x1A chars
void fixSongName(void);
-void fixInstrAndSampleNames(int16_t nr);
+void fixInstrAndSampleNames(int16_t insNum);
void calcReplayerVars(int32_t rate);
// used on external sample load and during sample loading in some module formats
-void tuneSample(sampleTyp *s, const int32_t midCFreq, bool linearPeriodsFlag);
+void tuneSample(sample_t *s, const int32_t midCFreq, bool linearPeriodsFlag);
void calcReplayerLogTab(void);
@@ -272,10 +297,10 @@
int32_t getPianoKey(uint16_t period, int8_t finetune, int8_t relativeNote); // for piano in Instr. Ed.
-bool allocateInstr(int16_t nr);
-void freeInstr(int32_t nr);
+bool allocateInstr(int16_t insNum);
+void freeInstr(int32_t insNum);
void freeAllInstr(void);
-void freeSample(int16_t nr, int16_t nr2);
+void freeSample(int16_t insNum, int16_t smpNum);
void freeAllPatterns(void);
void updateChanNums(void);
@@ -285,28 +310,28 @@
void startPlaying(int8_t mode, int16_t row);
void stopPlaying(void);
void stopVoices(void);
-void setPos(int16_t songPos, int16_t pattPos, bool resetTimer);
+void setPos(int16_t songPos, int16_t row, bool resetTimer);
void pauseMusic(void); // stops reading pattern data
void resumeMusic(void); // starts reading pattern data
void setSongModifiedFlag(void);
void removeSongModifiedFlag(void);
-void playTone(uint8_t stmm, uint8_t inst, uint8_t ton, int8_t vol, uint16_t midiVibDepth, uint16_t midiPitch);
-void playSample(uint8_t stmm, uint8_t inst, uint8_t smpNr, uint8_t ton, uint16_t midiVibDepth, uint16_t midiPitch);
-void playRange(uint8_t stmm, uint8_t inst, uint8_t smpNr, uint8_t ton, uint16_t midiVibDepth, uint16_t midiPitch, int32_t offs, int32_t len);
-void keyOff(stmTyp *ch);
-void conv8BitSample(int8_t *p, int32_t len, bool stereo);
-void conv16BitSample(int8_t *p, int32_t len, bool stereo);
-void delta2Samp(int8_t *p, int32_t len, uint8_t typ);
-void samp2Delta(int8_t *p, int32_t len, uint8_t typ);
-void setPatternLen(uint16_t nr, int16_t len);
-void setFrqTab(bool linear);
+void playTone(uint8_t chNum, uint8_t insNum, uint8_t note, int8_t vol, uint16_t midiVibDepth, uint16_t midiPitch);
+void playSample(uint8_t chNum, uint8_t insNum, uint8_t smpNum, uint8_t note, uint16_t midiVibDepth, uint16_t midiPitch);
+void playRange(uint8_t chNum, uint8_t insNum, uint8_t smpNum, uint8_t note, uint16_t midiVibDepth, uint16_t midiPitch, int32_t smpOffset, int32_t length);
+void keyOff(channel_t *ch);
+void conv8BitSample(int8_t *p, int32_t length, bool stereo); // changes sample sign
+void conv16BitSample(int8_t *p, int32_t length, bool stereo); // changes sample sign
+void delta2Samp(int8_t *p, int32_t length, uint8_t smpFlags);
+void samp2Delta(int8_t *p, int32_t length, uint8_t smpFlags);
+void setPatternLen(uint16_t pattNum, int16_t numRows);
+void setFrequencyTable(bool linearPeriodsFlag);
void tickReplayer(void); // periodically called from audio callback
void resetChannels(void);
-bool patternEmpty(uint16_t nr);
-int16_t getUsedSamples(int16_t nr);
-int16_t getRealUsedSamples(int16_t nr);
-void setStdEnvelope(instrTyp *ins, int16_t i, uint8_t typ);
-void setNoEnvelope(instrTyp *ins);
+bool patternEmpty(uint16_t pattNum);
+int16_t getUsedSamples(int16_t smpNum);
+int16_t getRealUsedSamples(int16_t smpNum);
+void setStdEnvelope(instr_t *ins, int16_t i, uint8_t type);
+void setNoEnvelope(instr_t *ins);
void setSyncedReplayerVars(void);
void decSongPos(void);
void incSongPos(void);
@@ -324,8 +349,8 @@
extern bool songPlaying, audioPaused, musicPaused;
extern volatile bool replayerBusy;
extern const uint16_t *note2Period;
-extern int16_t pattLens[MAX_PATTERNS];
-extern stmTyp stm[MAX_VOICES];
-extern songTyp song;
-extern instrTyp *instr[132];
-extern tonTyp *patt[MAX_PATTERNS];
+extern int16_t patternNumRows[MAX_PATTERNS];
+extern channel_t channel[MAX_CHANNELS];
+extern song_t song;
+extern instr_t *instr[132];
+extern note_t *pattern[MAX_PATTERNS];
--- a/src/ft2_sample_ed.c
+++ b/src/ft2_sample_ed.c
@@ -18,7 +18,7 @@
#include "ft2_audio.h"
#include "ft2_pattern_ed.h"
#include "ft2_gui.h"
-#include "ft2_scopes.h"
+#include "scopes/ft2_scopes.h"
#include "ft2_video.h"
#include "ft2_inst_ed.h"
#include "ft2_sample_ed.h"
@@ -27,6 +27,7 @@
#include "ft2_diskop.h"
#include "ft2_keyboard.h"
#include "ft2_structs.h"
+#include "ft2_replayer.h"
#include "mixer/ft2_windowed_sinc.h" // SINC_TAPS, SINC_NEGATIVE_TAPS
static const char sharpNote1Char[12] = { 'C', 'C', 'D', 'D', 'E', 'F', 'F', 'G', 'G', 'A', 'A', 'B' };
@@ -36,12 +37,13 @@
static char smpEd_SysReqText[64];
static int8_t *smpCopyBuff;
-static bool updateLoopsOnMouseUp, writeSampleFlag;
+static bool updateLoopsOnMouseUp, writeSampleFlag, smpCopyDidCopyWholeSample;
static int32_t smpEd_OldSmpPosLine = -1;
static int32_t smpEd_ViewSize, smpEd_ScrPos, smpCopySize, smpCopyBits;
static int32_t old_Rx1, old_Rx2, old_ViewSize, old_SmpScrPos;
-static int32_t lastMouseX, lastMouseY, lastDrawX, lastDrawY, mouseXOffs, curSmpRepS, curSmpRepL;
+static int32_t lastMouseX, lastMouseY, lastDrawX, lastDrawY, mouseXOffs, curSmpLoopStart, curSmpLoopLength;
static double dScrPosScaled, dPos2ScrMul, dScr2SmpPosMul;
+static sample_t smpCopySample;
static SDL_Thread *thread;
// globals
@@ -48,100 +50,192 @@
int32_t smpEd_Rx1 = 0, smpEd_Rx2 = 0;
// allocs sample with proper alignment and padding for branchless resampling interpolation
-bool allocateTmpSmpData(sampleTyp *s, int32_t length)
+bool allocateSmpData(sample_t *s, int32_t length, bool sample16Bit)
{
- s->origPek = (int8_t *)malloc(length + LOOP_FIX_LEN);
- if (s->origPek == NULL)
+ if (sample16Bit)
+ length <<= 1;
+
+ s->origDataPtr = (int8_t *)malloc(length + SAMPLE_PAD_LENGTH);
+ if (s->origDataPtr == NULL)
{
- s->pek = NULL;
+ s->dataPtr = NULL;
return false;
}
- s->pek = s->origPek + SMP_DAT_OFFSET;
+ s->dataPtr = s->origDataPtr + SMP_DAT_OFFSET;
return true;
}
+bool allocateSmpDataPtr(smpPtr_t *sp, int32_t length, bool sample16Bit)
+{
+ if (sample16Bit)
+ length <<= 1;
+
+ int8_t *newPtr = (int8_t *)malloc(length + SAMPLE_PAD_LENGTH);
+ if (newPtr == NULL)
+ return false;
+
+ sp->origPtr = newPtr;
+
+ sp->ptr = sp->origPtr + SMP_DAT_OFFSET;
+ return true;
+}
+
// reallocs sample with proper alignment and padding for branchless resampling interpolation
-bool reallocateTmpSmpData(sampleTyp *s, int32_t length)
+bool reallocateSmpData(sample_t *s, int32_t length, bool sample16Bit)
{
- if (s->origPek == NULL)
- return allocateTmpSmpData(s, length);
+ if (s->origDataPtr == NULL)
+ return allocateSmpData(s, length, sample16Bit);
- s->origPek = (int8_t *)realloc(s->origPek, length + LOOP_FIX_LEN);
- if (s->origPek == NULL)
- {
- s->pek = NULL;
+ if (sample16Bit)
+ length <<= 1;
+
+ int8_t *newPtr = (int8_t *)realloc(s->origDataPtr, length + SAMPLE_PAD_LENGTH);
+ if (newPtr == NULL)
return false;
+
+ s->origDataPtr = newPtr;
+ s->dataPtr = s->origDataPtr + SMP_DAT_OFFSET;
+
+ return true;
+}
+
+// reallocs sample with proper alignment and padding for branchless resampling interpolation
+bool reallocateSmpDataPtr(smpPtr_t *sp, int32_t length, bool sample16Bit)
+{
+ if (sp->origPtr == NULL)
+ return allocateSmpDataPtr(sp, length, sample16Bit);
+
+ if (sample16Bit)
+ length <<= 1;
+
+ int8_t *newPtr = (int8_t *)realloc(sp->origPtr, length + SAMPLE_PAD_LENGTH);
+ if (newPtr == NULL)
+ return false;
+
+ sp->origPtr = newPtr;
+ sp->ptr = sp->origPtr + SMP_DAT_OFFSET;
+
+ return true;
+}
+
+void setSmpDataPtr(sample_t *s, smpPtr_t *sp)
+{
+ s->origDataPtr = sp->origPtr;
+ s->dataPtr = sp->ptr;
+}
+
+void freeSmpDataPtr(smpPtr_t *sp)
+{
+ if (sp->origPtr != NULL)
+ {
+ free(sp->origPtr);
+ sp->origPtr = NULL;
}
- s->pek = s->origPek + SMP_DAT_OFFSET;
+ sp->ptr = NULL;
+}
+
+void freeSmpData(sample_t *s)
+{
+ if (s->origDataPtr != NULL)
+ {
+ free(s->origDataPtr);
+ s->origDataPtr = NULL;
+ }
+
+ s->dataPtr = NULL;
+ s->isFixed = false;
+}
+
+bool cloneSample(sample_t *src, sample_t *dst)
+{
+ smpPtr_t sp;
+
+ freeSmpData(dst);
+ memcpy(dst, src, sizeof (sample_t));
+
+ dst->origDataPtr = dst->dataPtr = NULL;
+ dst->isFixed = false;
+
+ if (src->length > 0 && src->dataPtr != NULL)
+ {
+ bool sample16Bit = !!(src->flags & SAMPLE_16BIT);
+ if (!allocateSmpDataPtr(&sp, src->length, sample16Bit))
+ return false;
+
+ memcpy(sp.ptr, src->dataPtr, src->length);
+ setSmpDataPtr(dst, &sp);
+ fixSample(dst);
+ }
+
return true;
}
-sampleTyp *getCurSample(void)
+sample_t *getCurSample(void)
{
if (editor.curInstr == 0 || instr[editor.curInstr] == NULL)
return NULL;
- return &instr[editor.curInstr]->samp[editor.curSmp];
+ return &instr[editor.curInstr]->smp[editor.curSmp];
}
-void checkSampleRepeat(sampleTyp *s)
+void sanitizeSample(sample_t *s)
{
- if (s->repS < 0) s->repS = 0;
- if (s->repL < 0) s->repL = 0;
- if (s->repS > s->len) s->repS = s->len;
- if (s->repS+s->repL > s->len) s->repL = s->len - s->repS;
+ if (s == NULL)
+ return;
- if (s->repL == 0) // non-FT2 fix: disable loop if loop length is 0
+ // if a sample has both forward loop and pingpong loop set, it means pingpong loop (FT2 mixer behavior)
+ if (GET_LOOPTYPE(s->flags) == (LOOP_FWD | LOOP_BIDI))
+ s->flags &= ~LOOP_FWD; // remove forward loop flag
+
+ if (s->volume > 64)
+ s->volume = 64;
+
+ s->relativeNote = CLAMP(s->relativeNote, -48, 71);
+ s->length = CLAMP(s->length, 0, MAX_SAMPLE_LEN);
+
+ if (s->loopStart < 0 || s->loopLength <= 0 || s->loopStart+s->loopLength > s->length)
{
- s->repS = 0;
- s->typ &= ~3;
+ s->loopStart = 0;
+ s->loopLength = 0;
+ DISABLE_LOOP(s->flags);
}
}
+static int32_t myMod(int32_t a, int32_t b) // works on negative numbers!
+{
+ int32_t c = a % b;
+ return (c < 0) ? (c + b) : c;
+}
+
// modifies samples before index 0, and after loop/end (for branchless mixer interpolation (kinda))
-void fixSample(sampleTyp *s)
+void fixSample(sample_t *s)
{
int32_t pos;
bool backwards;
assert(s != NULL);
- if (s->origPek == NULL || s->pek == NULL)
+ if (s->dataPtr == NULL || s->length <= 0)
{
- s->fixed = false;
+ s->isFixed = false;
s->fixedPos = 0;
return; // empty sample
}
- const bool sample16Bit = (s->typ & 16) ? true : false;
- int16_t *ptr16 = (int16_t *)s->pek;
- uint8_t loopType = s->typ & 3;
- int32_t len = s->len;
- int32_t loopStart = s->repS;
- int32_t loopLen = s->repL;
- int32_t loopEnd = s->repS + s->repL;
+ const bool sample16Bit = !!(s->flags & SAMPLE_16BIT);
+ int16_t *ptr16 = (int16_t *)s->dataPtr;
+ uint8_t loopType = GET_LOOPTYPE(s->flags);
+ int32_t length = s->length;
+ int32_t loopStart = s->loopStart;
+ int32_t loopLength = s->loopLength;
+ int32_t loopEnd = s->loopStart + s->loopLength;
- if (sample16Bit)
- {
- len >>= 1;
- loopStart >>= 1;
- loopLen >>= 1;
- loopEnd >>= 1;
- }
-
- if (len < 1)
- {
- s->fixed = false;
- s->fixedPos = 0;
- return; // empty sample
- }
-
// treat loop as disabled if loopLen == 0 (FT2 does this)
- if (loopType != 0 && loopLen <= 0)
+ if (loopType != 0 && loopLength <= 0)
{
loopType = 0;
- loopStart = loopLen = loopEnd = 0;
+ loopStart = loopLength = loopEnd = 0;
}
/* All negative taps should be equal to the first sample point when at sampling
@@ -158,275 +252,195 @@
else
{
for (int32_t i = 0; i < SINC_LEFT_TAPS; i++)
- s->pek[i-SINC_LEFT_TAPS] = s->pek[0];
+ s->dataPtr[i-SINC_LEFT_TAPS] = s->dataPtr[0];
}
- // no loop
- if (loopType == 0)
+ if (loopType == LOOP_OFF) // no loop
{
if (sample16Bit)
{
for (int32_t i = 0; i < SINC_RIGHT_TAPS; i++)
- ptr16[len+i] = ptr16[len-1];
+ ptr16[length+i] = ptr16[length-1];
}
else
{
for (int32_t i = 0; i < SINC_RIGHT_TAPS; i++)
- s->pek[len+i] = s->pek[len-1];
+ s->dataPtr[length+i] = s->dataPtr[length-1];
}
s->fixedPos = 0; // this value is not used for non-looping samples, set to zero
-
- s->fixed = false; // no fixed samples inside actual sample data
+ s->isFixed = false; // no fixed samples inside actual sample data
return;
}
- if (s->fixed)
- return; // already fixed
-
s->fixedPos = loopEnd;
- s->fixed = true;
+ s->isFixed = true;
- // special-case for loop-lengt of 1
- if (loopLen == 1)
+ if (loopType == LOOP_FWD) // forward loop
{
if (sample16Bit)
{
- for (int32_t i = 0; i < SINC_TAPS+SINC_LEFT_TAPS; i++)
- s->leftEdgeTapSamples16[i] = ptr16[loopStart];
-
- for (int32_t i = 0; i < SINC_RIGHT_TAPS; i++)
+ // left edge (we need SINC_TAPS amount of taps starting from the center tap)
+ for (int32_t i = -SINC_LEFT_TAPS; i < SINC_TAPS; i++)
{
- s->fixedSmp[i] = ptr16[loopEnd+i];
- ptr16[loopEnd+i] = ptr16[loopStart];
+ pos = loopStart + myMod(i, loopLength);
+ s->leftEdgeTapSamples16[SINC_LEFT_TAPS+i] = ptr16[pos];
}
- }
- else
- {
- for (int32_t i = 0; i < SINC_TAPS+SINC_LEFT_TAPS; i++)
- s->leftEdgeTapSamples8[i] = s->pek[loopStart];
- for (int32_t i = 0; i < SINC_RIGHT_TAPS; i++)
- {
- s->fixedSmp[i] = s->pek[loopEnd+i];
- s->pek[loopEnd+i] = s->pek[loopStart];
- }
- }
-
- return;
- }
-
- if (loopType == 1)
- {
- // forward loop
- if (sample16Bit)
- {
- // left edge (we need SINC_LEFT_TAPS amount of extra unrolled samples)
- for (int32_t i = 0; i < SINC_TAPS+SINC_LEFT_TAPS; i++)
- {
- if (i < SINC_LEFT_TAPS) // negative taps
- {
- pos = loopEnd-i;
- if (pos <= loopStart) // XXX: Correct?
- pos += loopLen;
- }
- else // positive taps
- {
- pos = loopStart + ((i-SINC_LEFT_TAPS) % loopLen);
- }
-
- s->leftEdgeTapSamples16[i] = ptr16[pos];
- }
-
// right edge (change actual sample data since data after loop is never used)
+ pos = loopStart;
for (int32_t i = 0; i < SINC_RIGHT_TAPS; i++)
{
s->fixedSmp[i] = ptr16[loopEnd+i];
- ptr16[loopEnd+i] = ptr16[loopStart + (i % loopLen)];
+ ptr16[loopEnd+i] = ptr16[pos];
+
+ if (++pos >= loopEnd)
+ pos -= loopLength;
}
}
- else
+ else // 8-bit
{
- // left edge (we need SINC_LEFT_TAPS amount of extra unrolled samples)
- for (int32_t i = 0; i < SINC_TAPS+SINC_LEFT_TAPS; i++)
+ // left edge (we need SINC_TAPS amount of taps starting from the center tap)
+ for (int32_t i = -SINC_LEFT_TAPS; i < SINC_TAPS; i++)
{
- if (i < SINC_LEFT_TAPS) // negative taps
- {
- pos = loopEnd-i;
- if (pos <= loopStart) // XXX: Correct?
- pos += loopLen;
- }
- else // positive taps
- {
- pos = loopStart + ((i-SINC_LEFT_TAPS) % loopLen);
- }
-
- s->leftEdgeTapSamples8[i] = s->pek[pos];
+ pos = loopStart + myMod(i, loopLength);
+ s->leftEdgeTapSamples8[SINC_LEFT_TAPS+i] = s->dataPtr[pos];
}
// right edge (change actual sample data since data after loop is never used)
+ pos = loopStart;
for (int32_t i = 0; i < SINC_RIGHT_TAPS; i++)
{
- s->fixedSmp[i] = s->pek[loopEnd+i];
- s->pek[loopEnd+i] = s->pek[loopStart + (i % loopLen)];
+ s->fixedSmp[i] = s->dataPtr[loopEnd+i];
+ s->dataPtr[loopEnd+i] = s->dataPtr[pos];
+
+ if (++pos >= loopEnd)
+ pos -= loopLength;
}
}
}
- else
+ else // pingpong loop
{
- // pingpong loop
if (sample16Bit)
{
- // left edge (we need SINC_LEFT_TAPS amount of extra unrolled samples)
+ // left edge (positive taps, we need SINC_TAPS amount of taps starting from the center tap)
pos = loopStart;
backwards = false;
- for (int32_t i = 0; i < SINC_LEFT_TAPS; i++)
+ for (int32_t i = 0; i < SINC_TAPS; i++)
{
if (backwards)
{
- if (--pos < loopStart)
+ if (pos < loopStart)
{
pos = loopStart;
backwards = false;
}
}
- else
+ else if (pos >= loopEnd) // forwards
{
- if (++pos >= loopEnd)
- {
- pos = loopEnd-1;
- backwards = true;
- }
+ pos = loopEnd-1;
+ backwards = true;
}
- s->leftEdgeTapSamples16[3-i] = ptr16[pos];
- }
+ s->leftEdgeTapSamples16[SINC_LEFT_TAPS+i] = ptr16[pos];
- pos = loopStart;
- backwards = true;
- for (int32_t i = 3; i < SINC_TAPS+SINC_LEFT_TAPS; i++)
- {
if (backwards)
- {
- if (--pos < loopStart)
- {
- pos = loopStart;
- backwards = false;
- }
- }
+ pos--;
else
- {
- if (++pos >= loopEnd)
- {
- pos = loopEnd-1;
- backwards = true;
- }
- }
-
- s->leftEdgeTapSamples16[i] = ptr16[pos];
+ pos++;
}
+ // left edge (negative taps)
+ for (int32_t i = 0; i < SINC_LEFT_TAPS; i++)
+ s->leftEdgeTapSamples16[(SINC_LEFT_TAPS-1)-i] = s->leftEdgeTapSamples16[SINC_LEFT_TAPS+1+i];
+
// right edge (change actual sample data since data after loop is never used)
pos = loopEnd-1;
backwards = true;
for (int32_t i = 0; i < SINC_RIGHT_TAPS; i++)
{
- s->fixedSmp[i] = ptr16[loopEnd+i];
-
- ptr16[loopEnd+i] = ptr16[pos];
if (backwards)
{
- if (--pos < loopStart)
+ if (pos < loopStart)
{
pos = loopStart;
backwards = false;
}
}
- else
+ else if (pos >= loopEnd) // forwards
{
- if (++pos >= loopEnd)
- {
- pos = loopEnd-1;
- backwards = true;
- }
+ pos = loopEnd-1;
+ backwards = true;
}
+
+ s->fixedSmp[i] = ptr16[loopEnd+i];
+ ptr16[loopEnd+i] = ptr16[pos];
+
+ if (backwards)
+ pos--;
+ else
+ pos++;
}
}
- else
+ else // 8-bit
{
- // left edge (we need SINC_LEFT_TAPS amount of extra unrolled samples)
+ // left edge (positive taps, we need SINC_TAPS amount of taps starting from the center tap)
pos = loopStart;
backwards = false;
- for (int32_t i = 0; i < SINC_LEFT_TAPS; i++)
+ for (int32_t i = 0; i < SINC_TAPS; i++)
{
if (backwards)
{
- if (--pos < loopStart)
+ if (pos < loopStart)
{
pos = loopStart;
backwards = false;
}
}
- else
+ else if (pos >= loopEnd) // forwards
{
- if (++pos >= loopEnd)
- {
- pos = loopEnd-1;
- backwards = true;
- }
+ pos = loopEnd-1;
+ backwards = true;
}
- s->leftEdgeTapSamples8[3-i] = s->pek[pos];
- }
+ s->leftEdgeTapSamples8[SINC_LEFT_TAPS+i] = s->dataPtr[pos];
- pos = loopStart;
- backwards = true;
- for (int32_t i = 3; i < SINC_TAPS+SINC_LEFT_TAPS; i++)
- {
if (backwards)
- {
- if (--pos < loopStart)
- {
- pos = loopStart;
- backwards = false;
- }
- }
+ pos--;
else
- {
- if (++pos >= loopEnd)
- {
- pos = loopEnd-1;
- backwards = true;
- }
- }
-
- s->leftEdgeTapSamples8[i] = s->pek[pos];
+ pos++;
}
+ // left edge (negative taps)
+ for (int32_t i = 0; i < SINC_LEFT_TAPS; i++)
+ s->leftEdgeTapSamples8[(SINC_LEFT_TAPS-1)-i] = s->leftEdgeTapSamples8[SINC_LEFT_TAPS+1+i];
+
// right edge (change actual sample data since data after loop is never used)
pos = loopEnd-1;
backwards = true;
for (int32_t i = 0; i < SINC_RIGHT_TAPS; i++)
{
- s->fixedSmp[i] = s->pek[loopEnd+i];
-
- s->pek[loopEnd+i] = s->pek[pos];
if (backwards)
{
- if (--pos < loopStart)
+ if (pos < loopStart)
{
pos = loopStart;
backwards = false;
}
}
- else
+ else if (pos >= loopEnd) // forwards
{
- if (++pos >= loopEnd)
- {
- pos = loopEnd-1;
- backwards = true;
- }
+ pos = loopEnd-1;
+ backwards = true;
}
+
+ s->fixedSmp[i] = s->dataPtr[loopEnd+i];
+ s->dataPtr[loopEnd+i] = s->dataPtr[pos];
+
+ if (backwards)
+ pos--;
+ else
+ pos++;
}
}
}
@@ -433,61 +447,58 @@
}
// restores interpolation tap samples after loop/end
-void restoreSample(sampleTyp *s)
+void unfixSample(sample_t *s)
{
assert(s != NULL);
- if (s->origPek == NULL || s->pek == NULL || !s->fixed)
+ if (s->dataPtr == NULL || !s->isFixed)
return; // empty sample or not fixed (f.ex. no loop)
- if (s->typ & 16)
+ if (s->flags & SAMPLE_16BIT)
{
- // 16-bit sample
- int16_t *ptr16 = (int16_t *)s->pek + s->fixedPos;
+ int16_t *ptr16 = (int16_t *)s->dataPtr + s->fixedPos;
for (int32_t i = 0; i < SINC_RIGHT_TAPS; i++)
ptr16[i] = s->fixedSmp[i];
}
- else
+ else // 8-bit
{
- // 8-bit sample
- int8_t *ptr8 = s->pek + s->fixedPos;
+ int8_t *ptr8 = s->dataPtr + s->fixedPos;
for (int32_t i = 0; i < SINC_RIGHT_TAPS; i++)
ptr8[i] = (int8_t)s->fixedSmp[i];
}
- s->fixed = false;
+ s->isFixed = false;
}
-int16_t getSampleValue(int8_t *ptr, uint8_t typ, int32_t pos)
+double getSampleValue(int8_t *smpData, int32_t position, bool sample16Bit)
{
- assert(pos >= 0);
- if (ptr == NULL)
+ if (smpData == NULL)
return 0;
- if (typ & 16)
+ if (sample16Bit)
{
- assert(!(pos & 1));
- return *(int16_t *)&ptr[pos];
+ position <<= 1;
+ return *((int16_t *)&smpData[position]);
}
else
{
- return ptr[pos];
+ return smpData[position];
}
}
-void putSampleValue(int8_t *ptr, uint8_t typ, int32_t pos, int16_t val)
+void putSampleValue(int8_t *smpData, int32_t position, double dSample, bool sample16Bit)
{
- assert(pos >= 0);
- if (ptr == NULL)
- return;
+ DROUND(dSample);
+ int32_t sample = (int32_t)dSample;
- if (typ & 16)
+ if (sample16Bit)
{
- assert(!(pos & 1));
- *(int16_t *)&ptr[pos] = val;
+ CLAMP16(sample);
+ *((int16_t *)&smpData[position<<1]) = (int16_t)sample;
}
else
{
- ptr[pos] = (int8_t)val;
+ CLAMP8(sample);
+ smpData[position] = (int8_t)sample;
}
}
@@ -501,9 +512,10 @@
smpCopySize = 0;
smpCopyBits = 8;
+ smpCopyDidCopyWholeSample = false;
}
-int32_t getSampleMiddleCRate(sampleTyp *s)
+int32_t getSampleMiddleCRate(sample_t *s)
{
return (int32_t)(getSampleC4Rate(s) + 0.5); // rounded
}
@@ -536,7 +548,7 @@
static void updateScrPos(void)
{
- dScrPosScaled = trunc(smpEd_ScrPos * dPos2ScrMul);
+ dScrPosScaled = floor(smpEd_ScrPos * dPos2ScrMul);
}
// sample pos -> screen x pos (if outside of visible area, will return <0 or >=SCREEN_W)
@@ -545,14 +557,14 @@
if (smpEd_ViewSize <= 0)
return -1;
- sampleTyp *s = getCurSample();
+ sample_t *s = getCurSample();
if (s == NULL)
return -1;
- if (pos > s->len)
- pos = s->len;
+ if (pos > s->length)
+ pos = s->length;
- double dPos = (pos * dPos2ScrMul) + 0.5; // rounding is needed here (+ 0.5)
+ double dPos = (pos * dPos2ScrMul) + 0.5; // pre-rounding bias is needed here
dPos -= dScrPosScaled;
// this is important, or else the result can mess up in some cases
@@ -568,7 +580,7 @@
if (smpEd_ViewSize <= 0)
return 0;
- sampleTyp *s = getCurSample();
+ sample_t *s = getCurSample();
if (s == NULL)
return 0;
@@ -576,67 +588,73 @@
x = 0;
double dPos = (dScrPosScaled + x) * dScr2SmpPosMul;
+
x = (int32_t)dPos;
+ if (x > s->length)
+ x = s->length;
- if (x > s->len)
- x = s->len;
-
- if (s->typ & 16)
- x &= 0xFFFFFFFE;
-
return x;
}
-static void fixRepeatGadgets(void)
+static void hideLoopPinSprites(void)
{
- bool showLoopPins = true;
+ hideSprite(SPRITE_LEFT_LOOP_PIN);
+ hideSprite(SPRITE_RIGHT_LOOP_PIN);
+}
- sampleTyp *s = getCurSample();
- if (s == NULL || s->len <= 0 || s->pek == NULL || (s->typ & 3) == 0 || !ui.sampleEditorShown)
- showLoopPins = false;
-
- if (ui.sampleEditorShown)
+static void fixLoopGadgets(void)
+{
+ if (!ui.sampleEditorShown)
{
- // draw Repeat/Replen. numbers
- hexOutBg(536, 375, PAL_FORGRND, PAL_DESKTOP, curSmpRepS, 8);
- hexOutBg(536, 387, PAL_FORGRND, PAL_DESKTOP, curSmpRepL, 8);
+ hideLoopPinSprites();
+ return;
}
+ sample_t *s = getCurSample();
+
+ bool showLoopPins = true;
+ if (s == NULL || s->dataPtr == NULL || s->length <= 0 || GET_LOOPTYPE(s->flags) == LOOP_OFF)
+ showLoopPins = false;
+
+ // draw Repeat/Replen. numbers
+ hexOutBg(536, 375, PAL_FORGRND, PAL_DESKTOP, curSmpLoopStart, 8);
+ hexOutBg(536, 387, PAL_FORGRND, PAL_DESKTOP, curSmpLoopLength, 8);
+
if (!showLoopPins)
{
- hideSprite(SPRITE_LEFT_LOOP_PIN);
- hideSprite(SPRITE_RIGHT_LOOP_PIN);
- return;
+ hideLoopPinSprites();
}
+ else
+ {
+ // draw sample loop points
- // draw sample loop points
+ const int32_t loopStart = smpPos2Scr(curSmpLoopStart);
+ const int32_t loopEnd = smpPos2Scr(curSmpLoopStart+curSmpLoopLength);
- int32_t repS = smpPos2Scr(curSmpRepS);
- int32_t repE = smpPos2Scr(curSmpRepS+curSmpRepL);
+ // do -8 test because part of the loop sprite sticks out on the left/right
- // do -8 test because part of the loop sprite sticks out on the left/right
+ if (loopStart >= -8 && loopStart <= SAMPLE_AREA_WIDTH+8)
+ setSpritePos(SPRITE_LEFT_LOOP_PIN, (int16_t)(loopStart - 8), 174);
+ else
+ hideSprite(SPRITE_LEFT_LOOP_PIN);
- if (repS >= -8 && repS <= SAMPLE_AREA_WIDTH+8)
- setSpritePos(SPRITE_LEFT_LOOP_PIN, (int16_t)(repS - 8), 174);
- else
- hideSprite(SPRITE_LEFT_LOOP_PIN);
-
- if (repE >= -8)
- {
- if (repE <= SAMPLE_AREA_WIDTH+8)
- setSpritePos(SPRITE_RIGHT_LOOP_PIN, (int16_t)(repE - 8), 174);
+ if (loopEnd >= -8)
+ {
+ if (loopEnd <= SAMPLE_AREA_WIDTH+8)
+ setSpritePos(SPRITE_RIGHT_LOOP_PIN, (int16_t)(loopEnd - 8), 174);
+ else
+ hideSprite(SPRITE_RIGHT_LOOP_PIN);
+ }
else
+ {
hideSprite(SPRITE_RIGHT_LOOP_PIN);
+ }
}
- else
- {
- hideSprite(SPRITE_RIGHT_LOOP_PIN);
- }
}
-static void fixSampleDrag(void)
+static void fixSampleScrollbar(void)
{
- sampleTyp *s = getCurSample();
+ sample_t *s = getCurSample();
if (s == NULL)
{
setScrollBarPageLength(SB_SAMP_SCROLL, 0);
@@ -646,11 +664,11 @@
}
setScrollBarPageLength(SB_SAMP_SCROLL, smpEd_ViewSize);
- setScrollBarEnd(SB_SAMP_SCROLL, instr[editor.curInstr]->samp[editor.curSmp].len);
+ setScrollBarEnd(SB_SAMP_SCROLL, instr[editor.curInstr]->smp[editor.curSmp].length);
setScrollBarPos(SB_SAMP_SCROLL, smpEd_ScrPos, false);
}
-static bool getCopyBuffer(int32_t size)
+static bool getCopyBuffer(int32_t size, bool sample16Bit)
{
if (smpCopyBuff != NULL)
free(smpCopyBuff);
@@ -658,7 +676,7 @@
if (size > MAX_SAMPLE_LEN)
size = MAX_SAMPLE_LEN;
- smpCopyBuff = (int8_t *)malloc(size);
+ smpCopyBuff = (int8_t *)malloc(size << sample16Bit);
if (smpCopyBuff == NULL)
{
smpCopySize = 0;
@@ -671,44 +689,19 @@
static int32_t SDLCALL copySampleThread(void *ptr)
{
- bool error = false;
+ sample_t *src = &instr[editor.srcInstr]->smp[editor.srcSmp];
+ sample_t *dst = &instr[editor.curInstr]->smp[editor.curSmp];
- int16_t destIns = editor.curInstr;
- int16_t destSmp = editor.curSmp;
- int16_t sourceIns = editor.srcInstr;
- int16_t sourceSmp = editor.srcSmp;
-
pauseAudio();
- if (instr[destIns] == NULL)
- error = !allocateInstr(destIns);
+ if (instr[editor.curInstr] == NULL && !allocateInstr(editor.curInstr))
+ goto error;
- if (!error)
- {
- freeSample(destIns, destSmp);
+ if (!cloneSample(src, dst))
+ goto error;
- sampleTyp *src = &instr[sourceIns]->samp[sourceSmp];
- sampleTyp *dst = &instr[destIns]->samp[destSmp];
-
- if (instr[sourceIns] != NULL && src->origPek != NULL)
- {
- int8_t *p = (int8_t *)malloc(src->len + LOOP_FIX_LEN);
- if (p != NULL)
- {
- memcpy(dst, src, sizeof (sampleTyp));
- memcpy(p, src->origPek, src->len + LOOP_FIX_LEN);
- dst->origPek = p;
- dst->pek = dst->origPek + SMP_DAT_OFFSET;
- }
- else error = true;
- }
- }
-
resumeAudio();
- if (error)
- okBoxThreadSafe(0, "System message", "Not enough memory!");
-
editor.updateCurSmp = true;
setSongModifiedFlag();
setMouseBusy(false);
@@ -715,6 +708,11 @@
return true;
+error:
+ resumeAudio();
+ okBoxThreadSafe(0, "System message", "Not enough memory!");
+ return true;
+
(void)ptr;
}
@@ -743,11 +741,11 @@
return;
}
- sampleTyp *src = &instr[editor.curInstr]->samp[editor.srcSmp];
- sampleTyp *dst = &instr[editor.curInstr]->samp[editor.curSmp];
+ sample_t *src = &instr[editor.curInstr]->smp[editor.srcSmp];
+ sample_t *dst = &instr[editor.curInstr]->smp[editor.curSmp];
lockMixerCallback();
- const sampleTyp dstTmp = *dst;
+ const sample_t dstTmp = *dst;
*dst = *src;
*src = dstTmp;
unlockMixerCallback();
@@ -788,25 +786,21 @@
}
}
-static int8_t getScaledSample(sampleTyp *s, int32_t index) // for drawing sample waveform in zoomed-in mode
+static int32_t getScaledSample(sample_t *s, int32_t index) // for sample data viewer
{
- int8_t sample;
- int32_t tmp32;
+ int32_t tmp32, sample;
- const int32_t loopEnd = s->repS + s->repL;
+ const int32_t loopEnd = s->loopStart + s->loopLength;
- if (s->pek == NULL || index < 0 || index >= s->len)
+ if (s->dataPtr == NULL || index < 0 || index >= s->length)
return 0;
- if (s->typ & 16)
+ if (s->flags & SAMPLE_16BIT)
{
- assert(!(index & 1));
- index >>= 1;
+ int16_t *ptr16 = (int16_t *)s->dataPtr;
- int16_t *ptr16 = (int16_t *)s->pek;
-
// don't read fixed mixer interpolation samples, read the prestine ones instead
- if (index >= s->fixedPos && index < s->fixedPos+SINC_RIGHT_TAPS && s->len > loopEnd && s->fixed)
+ if (index >= s->fixedPos && index < s->fixedPos+SINC_RIGHT_TAPS && s->length > loopEnd && s->isFixed)
tmp32 = s->fixedSmp[index-s->fixedPos];
else
tmp32 = ptr16[index];
@@ -813,32 +807,30 @@
sample = (int8_t)((tmp32 * SAMPLE_AREA_HEIGHT) >> 16);
}
- else
+ else // 8-bit
{
- // don't read fixed mixer interpolation samples, read the prestine ones instead
- if (index >= s->fixedPos && index < s->fixedPos+SINC_RIGHT_TAPS && s->len > loopEnd && s->fixed)
+ if (index >= s->fixedPos && index < s->fixedPos+SINC_RIGHT_TAPS && s->length > loopEnd && s->isFixed)
tmp32 = s->fixedSmp[index-s->fixedPos];
else
- tmp32 = s->pek[index];
+ tmp32 = s->dataPtr[index];
sample = (int8_t)((tmp32 * SAMPLE_AREA_HEIGHT) >> 8);
}
- return sample;
+ return SAMPLE_AREA_Y_CENTER-sample;
}
-static void sampleLine(int16_t x1, int16_t x2, int16_t y1, int16_t y2)
+void sampleLine(int32_t x1, int32_t x2, int32_t y1, int32_t y2)
{
- int16_t d;
-
- const int16_t dx = x2 - x1;
- const int16_t ax = ABS(dx) * 2;
- const int16_t sx = SGN(dx);
- const int16_t dy = y2 - y1;
- const int16_t ay = ABS(dy) * 2;
- const int16_t sy = SGN(dy);
- int16_t x = x1;
- int16_t y = y1;
+ int32_t d;
+ const int32_t dx = x2 - x1;
+ const int32_t ax = ABS(dx) * 2;
+ const int32_t sx = SGN(dx);
+ const int32_t dy = y2 - y1;
+ const int32_t ay = ABS(dy) * 2;
+ const int32_t sy = SGN(dy);
+ int32_t x = x1;
+ int32_t y = y1;
const uint32_t pal1 = video.palette[PAL_DESKTOP];
const uint32_t pal2 = video.palette[PAL_FORGRND];
const uint32_t pixVal = video.palette[PAL_PATTEXT];
@@ -1086,11 +1078,11 @@
}
// for scanning sample data peak where loopEnd+SINC_RIGHT_TAPS is within scan range (fixed interpolation tap samples)
-static void getSpecialMinMax16(sampleTyp *s, int32_t index, int32_t scanEnd, int16_t *min16, int16_t *max16)
+static void getSpecialMinMax16(sample_t *s, int32_t index, int32_t scanEnd, int16_t *min16, int16_t *max16)
{
int16_t minVal2, maxVal2;
- const int16_t *ptr16 = (const int16_t *)s->pek;
+ const int16_t *ptr16 = (const int16_t *)s->dataPtr;
int16_t minVal = 32767;
int16_t maxVal = -32768;
@@ -1131,11 +1123,11 @@
}
// for scanning sample data peak where loopEnd+SINC_RIGHT_TAPS is within scan range (fixed interpolation tap samples)
-static void getSpecialMinMax8(sampleTyp *s, int32_t index, int32_t scanEnd, int8_t *min8, int8_t *max8)
+static void getSpecialMinMax8(sample_t *s, int32_t index, int32_t scanEnd, int8_t *min8, int8_t *max8)
{
int8_t minVal2, maxVal2;
- const int8_t *ptr8 = (const int8_t *)s->pek;
+ const int8_t *ptr8 = (const int8_t *)s->dataPtr;
int8_t minVal = 127;
int8_t maxVal = -128;
@@ -1175,12 +1167,12 @@
*max8 = maxVal;
}
-static void getSampleDataPeak(sampleTyp *s, int32_t index, int32_t numSamples, int16_t *outMin, int16_t *outMax)
+static void getSampleDataPeak(sample_t *s, int32_t index, int32_t length, int16_t *outMin, int16_t *outMax)
{
int8_t min8, max8;
int16_t min16, max16;
- if (numSamples == 0 || s->pek == NULL || s->len <= 0)
+ if (length == 0 || s->dataPtr == NULL || s->length <= 0)
{
*outMin = SAMPLE_AREA_Y_CENTER;
*outMax = SAMPLE_AREA_Y_CENTER;
@@ -1187,17 +1179,10 @@
return;
}
- if (s->typ & 16)
+ if (s->isFixed && s->length > s->loopLength+s->loopStart)
{
- assert(!(index & 1));
- index >>= 1;
- numSamples >>= 1;
- }
+ const int32_t scanEnd = index + length;
- if (s->fixed && s->len > s->repL+s->repS)
- {
- const int32_t scanEnd = index + numSamples;
-
/* If the scan area is including the fixed samples (for branchless mixer interpolation),
** do a special procedure to scan the original non-touched samples when needed.
*/
@@ -1204,16 +1189,14 @@
const bool insideRange = index >= s->fixedPos && index < s->fixedPos+SINC_RIGHT_TAPS;
if (insideRange || (index < s->fixedPos && scanEnd >= s->fixedPos))
{
- if (s->typ & 16)
+ if (s->flags & SAMPLE_16BIT)
{
- // 16-bit sample
getSpecialMinMax16(s, index, scanEnd, &min16, &max16);
*outMin = SAMPLE_AREA_Y_CENTER - ((min16 * SAMPLE_AREA_HEIGHT) >> 16);
*outMax = SAMPLE_AREA_Y_CENTER - ((max16 * SAMPLE_AREA_HEIGHT) >> 16);
}
- else
+ else // 8-bit
{
- // 8-bit sample
getSpecialMinMax8(s, index, scanEnd, &min8, &max8);
*outMin = SAMPLE_AREA_Y_CENTER - ((min8 * SAMPLE_AREA_HEIGHT) >> 8);
*outMax = SAMPLE_AREA_Y_CENTER - ((max8 * SAMPLE_AREA_HEIGHT) >> 8);
@@ -1223,18 +1206,16 @@
}
}
- if (s->typ & 16)
+ if (s->flags & SAMPLE_16BIT)
{
- // 16-bit sample
- const int16_t *smpPtr16 = (int16_t *)s->pek;
- getMinMax16(&smpPtr16[index], numSamples, &min16, &max16);
+ const int16_t *smpPtr16 = (int16_t *)s->dataPtr;
+ getMinMax16(&smpPtr16[index], length, &min16, &max16);
*outMin = SAMPLE_AREA_Y_CENTER - ((min16 * SAMPLE_AREA_HEIGHT) >> 16);
*outMax = SAMPLE_AREA_Y_CENTER - ((max16 * SAMPLE_AREA_HEIGHT) >> 16);
}
- else
+ else // 8-bit
{
- // 8-bit sample
- getMinMax8(&s->pek[index], numSamples, &min8, &max8);
+ getMinMax8(&s->dataPtr[index], length, &min8, &max8);
*outMin = SAMPLE_AREA_Y_CENTER - ((min8 * SAMPLE_AREA_HEIGHT) >> 8);
*outMax = SAMPLE_AREA_Y_CENTER - ((max8 * SAMPLE_AREA_HEIGHT) >> 8);
}
@@ -1242,8 +1223,6 @@
static void writeWaveform(void)
{
- int16_t y1, y2, min, max;
-
// clear sample data area
memset(&video.frameBuffer[174 * SCREEN_W], 0, SAMPLE_AREA_WIDTH * SAMPLE_AREA_HEIGHT * sizeof (int32_t));
@@ -1253,58 +1232,67 @@
if (instr[editor.curInstr] == NULL || smpEd_ViewSize == 0)
return;
- sampleTyp *s = &instr[editor.curInstr]->samp[editor.curSmp];
- if (s->pek == NULL || s->len == 0)
+ sample_t *s = &instr[editor.curInstr]->smp[editor.curSmp];
+ if (s->dataPtr == NULL || s->length <= 0)
return;
- y1 = SAMPLE_AREA_Y_CENTER - getScaledSample(s, scr2SmpPos(0));
-
- uint32_t viewSizeSamples = smpEd_ViewSize;
- if (s->typ & 16)
- viewSizeSamples >>= 1;
-
- if (viewSizeSamples <= SAMPLE_AREA_WIDTH)
+ if (smpEd_ViewSize <= SAMPLE_AREA_WIDTH) // zoomed in (or 1:1)
{
- // 1:1 or zoomed in
- for (int16_t x = 1; x < SAMPLE_AREA_WIDTH; x++)
+ for (int32_t x = 0; x <= SAMPLE_AREA_WIDTH; x++)
{
- y2 = SAMPLE_AREA_Y_CENTER - getScaledSample(s, scr2SmpPos(x));
- sampleLine(x - 1, x, y1, y2);
- y1 = y2;
+ int32_t currSmpPos = scr2SmpPos(x+0);
+ int32_t nextSmpPos = scr2SmpPos(x+1);
+
+ if (currSmpPos >= s->length) currSmpPos = s->length-1;
+ if (nextSmpPos >= s->length) nextSmpPos = s->length-1;
+
+ int32_t x1 = smpPos2Scr(currSmpPos);
+ int32_t x2 = smpPos2Scr(nextSmpPos);
+ int32_t y1 = getScaledSample(s, currSmpPos);
+ int32_t y2 = getScaledSample(s, nextSmpPos);
+
+ x1 = CLAMP(x1, 0, SAMPLE_AREA_WIDTH-1);
+ x2 = CLAMP(x2, 0, SAMPLE_AREA_WIDTH-1);
+
+ // kludge: sometimes the last point wouldn't reach the end of the sample window
+ if (x == SAMPLE_AREA_WIDTH)
+ x2 = SAMPLE_AREA_WIDTH-1;
+
+ sampleLine(x1, x2, y1, y2);
}
}
- else
+ else // zoomed out
{
- // zoomed out
+ const int32_t firstSamplePoint = getScaledSample(s, scr2SmpPos(0));
- int16_t oldMin = y1;
- int16_t oldMax = y1;
+ int32_t oldMin = firstSamplePoint;
+ int32_t oldMax = firstSamplePoint;
- int32_t smpNumMin = (s->typ & 16) ? 2 : 1;
for (int16_t x = 0; x < SAMPLE_AREA_WIDTH; x++)
{
- int32_t smpIdx = scr2SmpPos(x);
+ int32_t smpIdx = scr2SmpPos(x+0);
int32_t smpNum = scr2SmpPos(x+1) - smpIdx;
// prevent look-up overflow (yes, this can happen near the end of the sample)
- if (smpIdx+smpNum > s->len)
- smpNum = s->len - smpNum;
+ if (smpIdx+smpNum > s->length)
+ smpNum = s->length - smpIdx;
- if (smpNum < smpNumMin)
- smpNum = smpNumMin;
-
- getSampleDataPeak(s, smpIdx, smpNum, &min, &max);
-
- if (x != 0)
+ if (smpNum > 0)
{
- if (min > oldMax) sampleLine(x - 1, x, oldMax, min);
- if (max < oldMin) sampleLine(x - 1, x, oldMin, max);
- }
+ int16_t min, max;
+ getSampleDataPeak(s, smpIdx, smpNum, &min, &max);
- sampleLine(x, x, max, min);
+ if (x != 0)
+ {
+ if (min > oldMax) sampleLine(x-1, x, oldMax, min);
+ if (max < oldMin) sampleLine(x-1, x, oldMin, max);
+ }
- oldMin = min;
- oldMax = max;
+ sampleLine(x, x, max, min);
+
+ oldMin = min;
+ oldMax = max;
+ }
}
}
}
@@ -1312,17 +1300,17 @@
void writeSample(bool forceSmpRedraw)
{
int32_t tmpRx1, tmpRx2;
- sampleTyp *s;
+ sample_t *s;
// update sample loop points for visuals
if (instr[editor.curInstr] == NULL)
- s = &instr[0]->samp[0];
+ s = &instr[0]->smp[0];
else
- s = &instr[editor.curInstr]->samp[editor.curSmp];
+ s = &instr[editor.curInstr]->smp[editor.curSmp];
- curSmpRepS = s->repS;
- curSmpRepL = s->repL;
+ curSmpLoopStart = s->loopStart;
+ curSmpLoopLength = s->loopLength;
// exchange range variables if x1 is after x2
if (smpEd_Rx1 > smpEd_Rx2)
@@ -1333,13 +1321,13 @@
}
// clamp range
- smpEd_Rx1 = CLAMP(smpEd_Rx1, 0, s->len);
- smpEd_Rx2 = CLAMP(smpEd_Rx2, 0, s->len);
+ smpEd_Rx1 = CLAMP(smpEd_Rx1, 0, s->length);
+ smpEd_Rx2 = CLAMP(smpEd_Rx2, 0, s->length);
// sanitize sample scroll position
- if (smpEd_ScrPos+smpEd_ViewSize > s->len)
+ if (smpEd_ScrPos+smpEd_ViewSize > s->length)
{
- smpEd_ScrPos = s->len - smpEd_ViewSize;
+ smpEd_ScrPos = s->length - smpEd_ViewSize;
updateScrPos();
}
@@ -1348,9 +1336,9 @@
smpEd_ScrPos = 0;
updateScrPos();
- if (smpEd_ViewSize > s->len)
+ if (smpEd_ViewSize > s->length)
{
- smpEd_ViewSize = s->len;
+ smpEd_ViewSize = s->length;
updateViewSize();
}
}
@@ -1400,11 +1388,11 @@
old_Rx2 = smpEd_Rx2;
}
- fixRepeatGadgets();
+ fixLoopGadgets();
}
if (ui.sampleEditorShown)
- fixSampleDrag();
+ fixSampleScrollbar();
updateSampleEditor();
}
@@ -1418,8 +1406,6 @@
return;
}
- sampleTyp *s = &instr[editor.curInstr]->samp[editor.curSmp];
-
if (start < 0)
start = 0;
@@ -1428,13 +1414,6 @@
smpEd_Rx1 = scr2SmpPos(start);
smpEd_Rx2 = scr2SmpPos(end);
-
- // 2-byte align if sample is 16-bit
- if (s->typ & 16)
- {
- smpEd_Rx1 &= 0xFFFFFFFE;
- smpEd_Rx2 &= 0xFFFFFFFE;
- }
}
void updateSampleEditorSample(void)
@@ -1448,7 +1427,7 @@
if (instr[editor.curInstr] == NULL)
smpEd_ViewSize = 0;
else
- smpEd_ViewSize = instr[editor.curInstr]->samp[editor.curSmp].len;
+ smpEd_ViewSize = instr[editor.curInstr]->smp[editor.curSmp].length;
updateViewSize();
@@ -1458,8 +1437,8 @@
void updateSampleEditor(void)
{
char noteChar1, noteChar2;
- uint8_t typ;
- int32_t sampleLen;
+ uint8_t flags;
+ int32_t sampleLength;
if (!ui.sampleEditorShown)
return;
@@ -1466,18 +1445,18 @@
if (instr[editor.curInstr] == NULL)
{
- typ = 0;
- sampleLen = 0;
+ flags = 0;
+ sampleLength = 0;
}
else
{
- typ = instr[editor.curInstr]->samp[editor.curSmp].typ;
- sampleLen = instr[editor.curInstr]->samp[editor.curSmp].len;
+ flags = instr[editor.curInstr]->smp[editor.curSmp].flags;
+ sampleLength = instr[editor.curInstr]->smp[editor.curSmp].length;
}
// sample bit depth radio buttons
uncheckRadioButtonGroup(RB_GROUP_SAMPLE_DEPTH);
- if (typ & 16)
+ if (flags & SAMPLE_16BIT)
radioButtons[RB_SAMPLE_16BIT].state = RADIOBUTTON_CHECKED;
else
radioButtons[RB_SAMPLE_8BIT].state = RADIOBUTTON_CHECKED;
@@ -1485,17 +1464,15 @@
// sample loop radio buttons
uncheckRadioButtonGroup(RB_GROUP_SAMPLE_LOOP);
- if (typ & 3)
- {
- if (typ & 2)
- radioButtons[RB_SAMPLE_PINGPONG_LOOP].state = RADIOBUTTON_CHECKED;
- else
- radioButtons[RB_SAMPLE_FORWARD_LOOP].state = RADIOBUTTON_CHECKED;
- }
- else
- {
+
+ uint8_t loopType = GET_LOOPTYPE(flags);
+ if (loopType == LOOP_OFF)
radioButtons[RB_SAMPLE_NO_LOOP].state = RADIOBUTTON_CHECKED;
- }
+ else if (loopType == LOOP_FWD)
+ radioButtons[RB_SAMPLE_FORWARD_LOOP].state = RADIOBUTTON_CHECKED;
+ else
+ radioButtons[RB_SAMPLE_PINGPONG_LOOP].state = RADIOBUTTON_CHECKED;
+
showRadioButtonGroup(RB_GROUP_SAMPLE_LOOP);
// draw sample play note
@@ -1521,7 +1498,7 @@
// draw sample display/length
hexOutBg(536, 350, PAL_FORGRND, PAL_DESKTOP, smpEd_ViewSize, 8);
- hexOutBg(536, 362, PAL_FORGRND, PAL_DESKTOP, sampleLen, 8);
+ hexOutBg(536, 362, PAL_FORGRND, PAL_DESKTOP, sampleLength, 8);
}
void sampPlayNoteUp(void)
@@ -1549,15 +1526,15 @@
if (instr[editor.curInstr] == NULL)
sampleLen = 0;
else
- sampleLen = instr[editor.curInstr]->samp[editor.curSmp].len;
+ sampleLen = instr[editor.curInstr]->smp[editor.curSmp].length;
if (smpEd_ViewSize == 0 || smpEd_ViewSize == sampleLen)
return;
if (mouse.rightButtonPressed)
- scrollAmount = smpEd_ViewSize / 14; // rounded from 16 (70Hz)
+ scrollAmount = smpEd_ViewSize / SCALE_VBLANK_DELTA(16);
else
- scrollAmount = smpEd_ViewSize / 27; // rounded from 32 (70Hz)
+ scrollAmount = smpEd_ViewSize / SCALE_VBLANK_DELTA(32);
if (scrollAmount < 1)
scrollAmount = 1;
@@ -1576,15 +1553,15 @@
if (instr[editor.curInstr] == NULL)
sampleLen = 0;
else
- sampleLen = instr[editor.curInstr]->samp[editor.curSmp].len;
+ sampleLen = instr[editor.curInstr]->smp[editor.curSmp].length;
if (smpEd_ViewSize == 0 || smpEd_ViewSize == sampleLen)
return;
if (mouse.rightButtonPressed)
- scrollAmount = smpEd_ViewSize / 14; // was 16 (70Hz->60Hz)
+ scrollAmount = smpEd_ViewSize / SCALE_VBLANK_DELTA(16);
else
- scrollAmount = smpEd_ViewSize / 27; // was 32 (70Hz->60Hz)
+ scrollAmount = smpEd_ViewSize / SCALE_VBLANK_DELTA(32);
if (scrollAmount < 1)
scrollAmount = 1;
@@ -1603,12 +1580,12 @@
if (instr[editor.curInstr] == NULL)
sampleLen = 0;
else
- sampleLen = instr[editor.curInstr]->samp[editor.curSmp].len;
+ sampleLen = instr[editor.curInstr]->smp[editor.curSmp].length;
if (smpEd_ViewSize == 0 || smpEd_ViewSize == sampleLen)
return;
- smpEd_ScrPos = (int32_t)pos;
+ smpEd_ScrPos = pos;
updateScrPos();
}
@@ -1632,23 +1609,15 @@
if (editor.curInstr == 0 || instr[editor.curInstr] == NULL)
return;
- sampleTyp *s = &instr[editor.curInstr]->samp[editor.curSmp];
- if (s->pek == NULL)
+ sample_t *s = &instr[editor.curInstr]->smp[editor.curSmp];
+ if (s->dataPtr == NULL)
return;
if (smpEd_Rx1 < smpEd_Rx2)
{
smpEd_ViewSize = smpEd_Rx2 - smpEd_Rx1;
-
- if (s->typ & 16)
- {
- if (smpEd_ViewSize < 4)
- smpEd_ViewSize = 4;
- }
- else if (smpEd_ViewSize < 2)
- {
+ if (smpEd_ViewSize < 2)
smpEd_ViewSize = 2;
- }
updateViewSize();
@@ -1665,7 +1634,7 @@
{
if (editor.curInstr == 0 ||
instr[editor.curInstr] == NULL ||
- instr[editor.curInstr]->samp[editor.curSmp].pek == NULL)
+ instr[editor.curInstr]->smp[editor.curSmp].dataPtr == NULL)
{
return;
}
@@ -1678,15 +1647,14 @@
{
if (editor.curInstr == 0 ||
instr[editor.curInstr] == NULL ||
- instr[editor.curInstr]->samp[editor.curSmp].pek == NULL)
+ instr[editor.curInstr]->smp[editor.curSmp].dataPtr == NULL)
{
return;
}
- sampleTyp *s = &instr[editor.curInstr]->samp[editor.curSmp];
+ sample_t *s = &instr[editor.curInstr]->smp[editor.curSmp];
- int32_t minViewSize = (s->typ & 16) ? 4 : 2;
- if (old_ViewSize <= minViewSize)
+ if (old_ViewSize <= 2)
return;
if (step < 1)
@@ -1693,8 +1661,8 @@
step = 1;
smpEd_ViewSize = old_ViewSize - (step * 2);
- if (smpEd_ViewSize < minViewSize)
- smpEd_ViewSize = minViewSize;
+ if (smpEd_ViewSize < 2)
+ smpEd_ViewSize = 2;
updateViewSize();
@@ -1705,10 +1673,10 @@
step += tmp32;
int64_t newScrPos64 = old_SmpScrPos + step;
- if (newScrPos64+smpEd_ViewSize > s->len)
- newScrPos64 = s->len - smpEd_ViewSize;
+ if (newScrPos64+smpEd_ViewSize > s->length)
+ newScrPos64 = s->length - smpEd_ViewSize;
- smpEd_ScrPos = newScrPos64 & 0xFFFFFFFF;
+ smpEd_ScrPos = (uint32_t)newScrPos64;
updateScrPos();
}
@@ -1716,13 +1684,13 @@
{
if (editor.curInstr == 0 ||
instr[editor.curInstr] == NULL ||
- instr[editor.curInstr]->samp[editor.curSmp].pek == NULL)
+ instr[editor.curInstr]->smp[editor.curSmp].dataPtr == NULL)
{
return;
}
- sampleTyp *s = &instr[editor.curInstr]->samp[editor.curSmp];
- if (old_ViewSize == s->len)
+ sample_t *s = &instr[editor.curInstr]->smp[editor.curSmp];
+ if (old_ViewSize == s->length)
return;
if (step < 1)
@@ -1729,9 +1697,9 @@
step = 1;
int64_t newViewSize64 = (int64_t)old_ViewSize + (step * 2);
- if (newViewSize64 > s->len)
+ if (newViewSize64 > s->length)
{
- smpEd_ViewSize = s->len;
+ smpEd_ViewSize = s->length;
smpEd_ScrPos = 0;
}
else
@@ -1748,8 +1716,8 @@
if (smpEd_ScrPos < 0)
smpEd_ScrPos = 0;
- if ((smpEd_ScrPos + smpEd_ViewSize) > s->len)
- smpEd_ScrPos = s->len - smpEd_ViewSize;
+ if (smpEd_ScrPos+smpEd_ViewSize > s->length)
+ smpEd_ScrPos = s->length - smpEd_ViewSize;
}
updateViewSize();
@@ -1760,7 +1728,7 @@
{
if (editor.curInstr == 0 ||
instr[editor.curInstr] == NULL ||
- instr[editor.curInstr]->samp[editor.curSmp].pek == NULL)
+ instr[editor.curInstr]->smp[editor.curSmp].dataPtr == NULL)
{
return;
}
@@ -1772,7 +1740,7 @@
{
if (editor.curInstr == 0 ||
instr[editor.curInstr] == NULL ||
- instr[editor.curInstr]->samp[editor.curSmp].pek == NULL)
+ instr[editor.curInstr]->smp[editor.curSmp].dataPtr == NULL)
{
return;
}
@@ -1784,13 +1752,13 @@
{
if (editor.curInstr == 0 ||
instr[editor.curInstr] == NULL ||
- instr[editor.curInstr]->samp[editor.curSmp].pek == NULL)
+ instr[editor.curInstr]->smp[editor.curSmp].dataPtr == NULL)
{
return;
}
- sampleTyp *s = &instr[editor.curInstr]->samp[editor.curSmp];
- if (old_ViewSize == s->len)
+ sample_t *s = &instr[editor.curInstr]->smp[editor.curSmp];
+ if (old_ViewSize == s->length)
return;
int32_t tmp32 = old_ViewSize;
@@ -1804,12 +1772,12 @@
smpEd_ViewSize = old_ViewSize * 2;
if (smpEd_ViewSize < old_ViewSize)
{
- smpEd_ViewSize = s->len;
+ smpEd_ViewSize = s->length;
smpEd_ScrPos = 0;
}
- else if (smpEd_ViewSize+smpEd_ScrPos > s->len)
+ else if (smpEd_ViewSize+smpEd_ScrPos > s->length)
{
- smpEd_ViewSize = s->len - smpEd_ScrPos;
+ smpEd_ViewSize = s->length - smpEd_ScrPos;
}
updateViewSize();
@@ -1820,7 +1788,7 @@
{
if (editor.curInstr == 0 ||
instr[editor.curInstr] == NULL ||
- instr[editor.curInstr]->samp[editor.curSmp].pek == NULL)
+ instr[editor.curInstr]->smp[editor.curSmp].dataPtr == NULL)
{
return;
}
@@ -1828,7 +1796,7 @@
smpEd_ScrPos = 0;
updateScrPos();
- smpEd_ViewSize = instr[editor.curInstr]->samp[editor.curSmp].len;
+ smpEd_ViewSize = instr[editor.curInstr]->smp[editor.curSmp].length;
updateViewSize();
}
@@ -1836,12 +1804,12 @@
{
if (editor.curInstr == 0 ||
instr[editor.curInstr] == NULL ||
- instr[editor.curInstr]->samp[editor.curSmp].pek == NULL)
+ instr[editor.curInstr]->smp[editor.curSmp].dataPtr == NULL)
{
return;
}
- if (smpEd_Rx1 >= smpEd_Rx2)
+ if (smpEd_Rx1 == smpEd_Rx2)
{
okBox(0, "System message", "No range specified!");
return;
@@ -1879,10 +1847,18 @@
UNICHAR *filenameU = cp437ToUnichar(smpEd_SysReqText);
if (filenameU == NULL)
{
- okBox(0, "System message", "Error converting string locale!");
+ okBox(0, "System message", "Out of memory!");
return;
}
+ if (fileExistsAnsi(smpEd_SysReqText))
+ {
+ char buf[256];
+ createFileOverwriteText(smpEd_SysReqText, buf);
+ if (okBox(2, "System request", buf) != 1)
+ return;
+ }
+
saveSample(filenameU, SAVE_RANGE);
free(filenameU);
}
@@ -1889,23 +1865,23 @@
static bool cutRange(bool cropMode, int32_t r1, int32_t r2)
{
- sampleTyp *s = getCurSample();
+ sample_t *s = getCurSample();
if (s == NULL)
return false;
- assert(!(s->typ & 16) || (!(r1 & 1) && !(r2 & 1) && !(s->len & 1)));
+ bool sample16Bit = !!(s->flags & SAMPLE_16BIT);
if (!cropMode)
{
- if (editor.curInstr == 0 || s->pek == NULL || s->len == 0)
+ if (editor.curInstr == 0 || s->dataPtr == NULL || s->length == 0)
return false;
pauseAudio();
- restoreSample(s);
+ unfixSample(s);
if (config.smpCutToBuffer)
{
- if (!getCopyBuffer(r2 - r1))
+ if (!getCopyBuffer(r2-r1, sample16Bit))
{
fixSample(s);
resumeAudio();
@@ -1914,18 +1890,17 @@
return false;
}
- memcpy(smpCopyBuff, &s->pek[r1], r2 - r1);
- smpCopyBits = (s->typ & 16) ? 16 : 8;
+ memcpy(smpCopyBuff, &s->dataPtr[r1], (r2-r1) << sample16Bit);
+ smpCopyBits = sample16Bit ? 16 : 8;
}
}
- memmove(&s->pek[r1], &s->pek[r2], s->len - r2);
+ memmove(&s->dataPtr[r1 << sample16Bit], &s->dataPtr[r2 << sample16Bit], (s->length-r2) << sample16Bit);
- int32_t len = s->len - r2 + r1;
- if (len > 0)
+ int32_t length = s->length - r2+r1;
+ if (length > 0)
{
- int8_t *newPtr = (int8_t *)realloc(s->origPek, len + LOOP_FIX_LEN);
- if (newPtr == NULL)
+ if (!reallocateSmpData(s, length, sample16Bit))
{
freeSample(editor.curInstr, editor.curSmp);
editor.updateCurSmp = true;
@@ -1937,46 +1912,36 @@
return false;
}
- s->origPek = newPtr;
- s->pek = s->origPek + SMP_DAT_OFFSET;
+ s->length = length;
- s->len = len;
-
- int32_t repE = s->repS + s->repL;
- if (s->repS > r1)
+ int32_t loopEnd = s->loopStart + s->loopLength;
+ if (s->loopStart > r1)
{
- s->repS -= r2 - r1;
- if (s->repS < r1)
- s->repS = r1;
+ s->loopStart -= r2-r1;
+ if (s->loopStart < r1)
+ s->loopStart = r1;
}
- if (repE > r1)
+ if (loopEnd > r1)
{
- repE -= r2 - r1;
- if (repE < r1)
- repE = r1;
+ loopEnd -= r2-r1;
+ if (loopEnd < r1)
+ loopEnd = r1;
}
- s->repL = repE - s->repS;
- if (s->repL < 0)
- s->repL = 0;
+ s->loopLength = loopEnd - s->loopStart;
+ if (s->loopLength < 0)
+ s->loopLength = 0;
- if (s->repS+s->repL > len)
- s->repL = len - s->repS;
+ if (s->loopStart+s->loopLength > length)
+ s->loopLength = length - s->loopStart;
- // 2-byte align loop points if sample is 16-bit
- if (s->typ & 16)
+ if (s->loopLength <= 0)
{
- s->repL &= 0xFFFFFFFE;
- s->repS &= 0xFFFFFFFE;
+ s->loopStart = 0;
+ DISABLE_LOOP(s->flags);
}
- if (s->repL == 0)
- {
- s->repS = 0;
- s->typ &= ~3; // disable loop
- }
-
if (!cropMode)
fixSample(s);
}
@@ -2014,8 +1979,8 @@
void sampCut(void)
{
- sampleTyp *s = getCurSample();
- if (s == NULL || s->pek == NULL || s->len <= 0 || smpEd_Rx2 == 0 || smpEd_Rx2 < smpEd_Rx1)
+ sample_t *s = getCurSample();
+ if (s == NULL || s->dataPtr == NULL || s->length <= 0 || smpEd_Rx2 == 0 || smpEd_Rx2 < smpEd_Rx1)
return;
mouseAnimOn();
@@ -2031,22 +1996,30 @@
static int32_t SDLCALL sampCopyThread(void *ptr)
{
- sampleTyp *s = getCurSample();
- assert(s != NULL && (!(s->typ & 16) || (!(smpEd_Rx1 & 1) && !(smpEd_Rx2 & 1))));
+ sample_t *s = getCurSample();
- if (!getCopyBuffer(smpEd_Rx2 - smpEd_Rx1))
+ bool sample16Bit = !!(s->flags & SAMPLE_16BIT);
+
+ if (!getCopyBuffer(smpEd_Rx2- smpEd_Rx1, sample16Bit))
{
okBoxThreadSafe(0, "System message", "Not enough memory!");
return true;
}
- restoreSample(s);
- memcpy(smpCopyBuff, &s->pek[smpEd_Rx1], smpEd_Rx2 - smpEd_Rx1);
+ unfixSample(s);
+ memcpy(smpCopyBuff, &s->dataPtr[smpEd_Rx1 << sample16Bit], (smpEd_Rx2-smpEd_Rx1) << sample16Bit);
fixSample(s);
- smpCopyBits = (s->typ & 16) ? 16 : 8;
setMouseBusy(false);
+ // copy sample information (in case we paste over an empty sample)
+ if (smpEd_Rx1 == 0 && smpEd_Rx2 == s->length)
+ {
+ smpCopySample = *s;
+ smpCopyDidCopyWholeSample = true;
+ }
+
+ smpCopyBits = sample16Bit? 16 : 8;
return true;
(void)ptr;
@@ -2054,8 +2027,8 @@
void sampCopy(void)
{
- sampleTyp *s = getCurSample();
- if (s == NULL || s->origPek == NULL || s->len <= 0 || smpEd_Rx2 == 0 || smpEd_Rx2 < smpEd_Rx1)
+ sample_t *s = getCurSample();
+ if (s == NULL || s->dataPtr == NULL || s->length <= 0 || smpEd_Rx2 == 0 || smpEd_Rx2 < smpEd_Rx1)
return;
mouseAnimOn();
@@ -2069,10 +2042,11 @@
SDL_DetachThread(thread);
}
-static void pasteOverwrite(sampleTyp *s)
+static void pasteOverwrite(sample_t *s)
{
- int8_t *p = (int8_t *)malloc(smpCopySize + LOOP_FIX_LEN);
- if (p == NULL)
+ bool sample16Bit = (smpCopyBits == 16);
+
+ if (!reallocateSmpData(s, smpCopySize, sample16Bit))
{
okBoxThreadSafe(0, "System message", "Not enough memory!");
return;
@@ -2080,21 +2054,36 @@
pauseAudio();
- if (s->origPek != NULL)
- free(s->origPek);
+ memcpy(s->dataPtr, smpCopyBuff, smpCopySize << sample16Bit);
- memset(s, 0, sizeof (sampleTyp));
+ if (smpCopyDidCopyWholeSample)
+ {
+ sample_t *src = &smpCopySample;
+ memcpy(s->name, src->name, 23);
+ s->length = src->length;
+ s->loopStart = src->loopStart;
+ s->loopLength = src->loopLength;
+ s->volume = src->volume;
+ s->panning = src->panning;
+ s->finetune = src->finetune;
+ s->relativeNote = src->relativeNote;
+ s->flags = src->flags;
+ }
+ else
+ {
+ s->name[0] = '\0';
+ s->length = smpCopySize;
+ s->loopStart = 0;
+ s->loopLength = 0;
+ s->volume = 64;
+ s->panning = 128;
+ s->finetune = 0;
+ s->relativeNote = 0;
+ s->flags = (smpCopyBits == 16) ? SAMPLE_16BIT : 0;
+ }
- s->origPek = p;
- s->pek = p + SMP_DAT_OFFSET;
+ s->isFixed = false;
- memcpy(s->pek, smpCopyBuff, smpCopySize);
-
- s->len = smpCopySize;
- s->vol = 64;
- s->pan = 128;
- s->typ = (smpCopyBits == 16) ? 16 : 0;
-
fixSample(s);
resumeAudio();
@@ -2103,40 +2092,34 @@
setMouseBusy(false);
}
-static void pasteCopiedData(int8_t *pek, int32_t offset, int32_t length, bool smpIs16Bit)
+static void pasteCopiedData(int8_t *dataPtr, int32_t offset, int32_t length, bool sample16Bit)
{
- if (smpIs16Bit)
+ if (sample16Bit) // destination sample is 16-bits
{
- // destination sample = 16-bit
-
if (smpCopyBits == 16)
{
- // src/dst = equal bits, copy directly
- memcpy(&pek[offset], smpCopyBuff, length);
+ // src/dst bits are equal, do direct copy
+ memcpy(&dataPtr[offset<<1], smpCopyBuff, length * sizeof (int16_t));
}
else
{
- // convert copy data to 16-bit then paste
- int16_t *ptr16 = (int16_t *)&pek[offset];
- int32_t len32 = length >> 1;
-
- for (int32_t i = 0; i < len32; i++)
+ // convert copied data to 16-bit then paste
+ int16_t *ptr16 = (int16_t *)dataPtr + offset;
+ for (int32_t i = 0; i < length; i++)
ptr16[i] = smpCopyBuff[i] << 8;
}
}
- else
+ else // destination sample is 8-bits
{
- // destination sample = 8-bit
-
if (smpCopyBits == 8)
{
- // src/dst = equal bits, copy directly
- memcpy(&pek[offset], smpCopyBuff, length);
+ // src/dst bits are equal, do direct copy
+ memcpy(&dataPtr[offset], smpCopyBuff, length * sizeof (int8_t));
}
else
{
- // convert copy data to 8-bit then paste
- int8_t *ptr8 = (int8_t *)&pek[offset];
+ // convert copied data to 8-bit then paste
+ int8_t *ptr8 = (int8_t *)&dataPtr[offset];
int16_t *ptr16 = (int16_t *)smpCopyBuff;
for (int32_t i = 0; i < length; i++)
@@ -2147,6 +2130,8 @@
static int32_t SDLCALL sampPasteThread(void *ptr)
{
+ smpPtr_t sp;
+
if (instr[editor.curInstr] == NULL && !allocateInstr(editor.curInstr))
{
okBoxThreadSafe(0, "System message", "Not enough memory!");
@@ -2153,40 +2138,22 @@
return true;
}
- sampleTyp *s = getCurSample();
- if (smpEd_Rx2 == 0 || s == NULL || s->pek == NULL)
+ sample_t *s = getCurSample();
+ if (smpEd_Rx2 == 0 || s == NULL || s->dataPtr == NULL)
{
pasteOverwrite(s);
return true;
}
- bool smpIs16Bit = (s->typ >> 4) & 1;
- assert(!smpIs16Bit || (!(smpEd_Rx1 & 1) && !(smpEd_Rx2 & 1) && !(s->len & 1)));
+ bool sample16Bit = !!(s->flags & SAMPLE_16BIT);
- if (s->len+smpCopySize > MAX_SAMPLE_LEN)
+ if (s->length+smpCopySize > MAX_SAMPLE_LEN)
{
okBoxThreadSafe(0, "System message", "Not enough room in sample!");
return true;
}
- int32_t realCopyLen = smpCopySize;
-
- if (smpIs16Bit)
- {
- // destination sample is 16-bit
-
- if (smpCopyBits == 8) // copy buffer is 8-bit, multiply length by 2
- realCopyLen <<= 1;
- }
- else
- {
- // destination sample is 8-bit
-
- if (smpCopyBits == 16) // copy buffer is 16-bit, divide length by 2
- realCopyLen >>= 1;
- }
-
- int32_t newLength = s->len + realCopyLen - (smpEd_Rx2 - smpEd_Rx1);
+ int32_t newLength = s->length + smpCopySize - (smpEd_Rx2 - smpEd_Rx1);
if (newLength <= 0)
return true;
@@ -2196,65 +2163,54 @@
return true;
}
- int8_t *p = (int8_t *)malloc(newLength + LOOP_FIX_LEN);
- if (p == NULL)
+ if (!allocateSmpDataPtr(&sp, newLength, sample16Bit))
{
okBoxThreadSafe(0, "System message", "Not enough memory!");
return true;
}
- int8_t *newPek = p + SMP_DAT_OFFSET;
-
pauseAudio();
- restoreSample(s);
+ unfixSample(s);
// paste left part of original sample
if (smpEd_Rx1 > 0)
- memcpy(newPek, s->pek, smpEd_Rx1);
+ memcpy(sp.ptr, s->dataPtr, smpEd_Rx1 << sample16Bit);
// paste copied data
- pasteCopiedData(newPek, smpEd_Rx1, realCopyLen, smpIs16Bit);
+ pasteCopiedData(sp.ptr, smpEd_Rx1, smpCopySize, sample16Bit);
// paste right part of original sample
- if (smpEd_Rx2 < s->len)
- memmove(&newPek[smpEd_Rx1+realCopyLen], &s->pek[smpEd_Rx2], s->len - smpEd_Rx2);
+ if (smpEd_Rx2 < s->length)
+ memmove(&sp.ptr[(smpEd_Rx1+smpCopySize) << sample16Bit], &s->dataPtr[smpEd_Rx2 << sample16Bit], (s->length-smpEd_Rx2) << sample16Bit);
- free(s->origPek);
+ freeSmpData(s);
+ setSmpDataPtr(s, &sp);
// adjust loop points if necessary
- if (smpEd_Rx2-smpEd_Rx1 != realCopyLen)
+ if (smpEd_Rx2-smpEd_Rx1 != smpCopySize)
{
- int32_t loopAdjust = realCopyLen - (smpEd_Rx1 - smpEd_Rx2);
+ int32_t loopAdjust = smpCopySize - (smpEd_Rx1 - smpEd_Rx2);
- if (s->repS > smpEd_Rx2)
+ if (s->loopStart > smpEd_Rx2)
{
- s->repS += loopAdjust;
- s->repL -= loopAdjust;
+ s->loopStart += loopAdjust;
+ s->loopLength -= loopAdjust;
}
- if (s->repS+s->repL > smpEd_Rx2)
- s->repL += loopAdjust;
+ if (s->loopStart+s->loopLength > smpEd_Rx2)
+ s->loopLength += loopAdjust;
- if (s->repS > newLength)
+ if (s->loopStart > newLength)
{
- s->repS = 0;
- s->repL = 0;
+ s->loopStart = 0;
+ s->loopLength = 0;
}
- if (s->repS+s->repL > newLength)
- s->repL = newLength - s->repS;
-
- // align loop points if sample is 16-bit
- if (smpIs16Bit)
- {
- s->repL &= 0xFFFFFFFE;
- s->repS &= 0xFFFFFFFE;
- }
+ if (s->loopStart+s->loopLength > newLength)
+ s->loopLength = newLength - s->loopStart;
}
- s->len = newLength;
- s->origPek = p;
- s->pek = s->origPek + SMP_DAT_OFFSET;
+ s->length = newLength;
fixSample(s);
resumeAudio();
@@ -2263,15 +2219,8 @@
setMouseBusy(false);
// set new range
- smpEd_Rx2 = smpEd_Rx1 + realCopyLen;
+ smpEd_Rx2 = smpEd_Rx1 + smpCopySize;
- // align sample marking points if sample is 16-bit
- if (smpIs16Bit)
- {
- smpEd_Rx1 &= 0xFFFFFFFE;
- smpEd_Rx2 &= 0xFFFFFFFE;
- }
-
writeSampleFlag = true;
return true;
@@ -2285,8 +2234,8 @@
if (smpEd_Rx2 == 0) // no sample data marked, overwrite sample with copy buffer
{
- sampleTyp *s = getCurSample();
- if (s != NULL && s->pek != NULL)
+ sample_t *s = getCurSample();
+ if (s != NULL && s->dataPtr != NULL && s->length > 0)
{
if (okBox(2, "System request", "The current sample is not empty. Do you really want to overwrite it?") != 1)
return;
@@ -2306,16 +2255,15 @@
static int32_t SDLCALL sampCropThread(void *ptr)
{
- sampleTyp *s = getCurSample();
- assert(!(s->typ & 16) || (!(smpEd_Rx1 & 1) && !(smpEd_Rx2 & 1) && !(s->len & 1)));
+ sample_t *s = getCurSample();
int32_t r1 = smpEd_Rx1;
int32_t r2 = smpEd_Rx2;
pauseAudio();
- restoreSample(s);
+ unfixSample(s);
- if (!cutRange(true, 0, r1) || !cutRange(true, r2 - r1, s->len))
+ if (!cutRange(true, 0, r1) || !cutRange(true, r2-r1, s->length))
{
fixSample(s);
resumeAudio();
@@ -2326,18 +2274,15 @@
resumeAudio();
r1 = 0;
- r2 = s->len;
+ r2 = s->length;
- if (s->typ & 16)
- r2 &= 0xFFFFFFFE;
-
setSongModifiedFlag();
setMouseBusy(false);
smpEd_Rx1 = r1;
smpEd_Rx2 = r2;
- writeSampleFlag = true;
+ writeSampleFlag = true;
return true;
(void)ptr;
@@ -2345,12 +2290,12 @@
void sampCrop(void)
{
- sampleTyp *s = getCurSample();
- if (s == NULL || s->pek == NULL || s->len <= 0 || smpEd_Rx1 >= smpEd_Rx2)
+ sample_t *s = getCurSample();
+ if (s == NULL || s->dataPtr == NULL || s->length <= 0 || smpEd_Rx1 == smpEd_Rx2)
return;
- if (smpEd_Rx1 == 0 && smpEd_Rx2 >= s->len)
- return; // no need to crop (the whole sample is marked)
+ if (smpEd_Rx1 == 0 && smpEd_Rx2 == s->length)
+ return; // nothing to crop (the whole sample is marked)
mouseAnimOn();
thread = SDL_CreateThread(sampCropThread, NULL, NULL);
@@ -2365,20 +2310,14 @@
void sampXFade(void)
{
- int16_t c, d;
- int32_t tmp32, i, y1, y2, a, b, d1, d2, d3, dist;
- double dR, dS1, dS2, dS3, dS4;
+ int32_t y1, y2, d1, d2, d3;
- sampleTyp *s = getCurSample();
- if (s == NULL || s->pek == NULL || s->len <= 0)
+ sample_t *s = getCurSample();
+ if (s == NULL || s->dataPtr == NULL || s->length <= 0)
return;
- assert(!(s->typ & 16) || (!(smpEd_Rx1 & 1) && !(smpEd_Rx2 & 1) && !(s->len & 1)));
-
- uint8_t t = s->typ;
-
// check if the sample has the loop flag enabled
- if ((t & 3) == 0)
+ if (GET_LOOPTYPE(s->flags) == LOOP_OFF)
{
okBox(0, "System message", "X-Fade can only be used on a loop-enabled sample!");
return;
@@ -2401,20 +2340,16 @@
int32_t x1 = smpEd_Rx1;
int32_t x2 = smpEd_Rx2;
- bool is16Bit = (t & 16) ? true : false;
+ bool sample16Bit = !!(s->flags & SAMPLE_16BIT);
- if ((t & 3) >= 2)
+ if (GET_LOOPTYPE(s->flags) == LOOP_BIDI)
{
- // pingpong loop
-
- y1 = s->repS;
- if (x1 <= y1)
+ y1 = s->loopStart;
+ if (x1 <= y1) // first loop point
{
- // first loop point
-
- if (x2 <= y1 || x2 >= s->repS+s->repL)
+ if (x2 <= y1 || x2 >= s->loopStart+s->loopLength)
{
- okBox(0, "System message", "Invalid range!");
+ okBox(0, "System message", "Error: No loop point found inside marked data.");
return;
}
@@ -2425,61 +2360,59 @@
d2 = y1 - x1;
d3 = x2 - y1;
- if (d1 < 2 || d2 < 2 || d3 < 2)
+ if (d1 < 1 || d2 < 1 || d3 < 1)
{
- okBox(0, "System message", "Invalid range!");
+ okBox(0, "System message", "Invalid range! Try to mark more data.");
return;
}
- if (y1-d1 < 0 || y1+d1 >= s->len)
+ if (y1-d1 < 0 || y1+d1 >= s->length)
{
okBox(0, "System message", "Not enough sample data outside loop!");
return;
}
- if (is16Bit)
- {
- y1 >>= 1;
- d1 >>= 1;
- d2 >>= 1;
- d3 >>= 1;
- }
+ const double dD2Mul = 1.0 / d2;
+ const double dD3Mul = 1.0 / d3;
pauseAudio();
- restoreSample(s);
+ unfixSample(s);
- i = 0;
- while (i < d1)
+ for (int32_t i = 0; i < d1; i++)
{
- a = getSampleValue(s->pek, t, (y1 - i - 1) << is16Bit);
- b = getSampleValue(s->pek, t, (y1 + i) << is16Bit);
+ const int32_t aIdx = y1-i-1;
+ const int32_t bIdx = y1+i;
+ const double dI = i;
- dS1 = 1.0 - i / (double)d2; dS2 = 2.0 - dS1;
- dS3 = 1.0 - i / (double)d3; dS4 = 2.0 - dS3;
+ const double dA = getSampleValue(s->dataPtr, aIdx, sample16Bit);
+ const double dB = getSampleValue(s->dataPtr, bIdx, sample16Bit);
- tmp32 = (int32_t)round((a * dS2 + b * dS1) / (dS1 + dS2));
- c = (int16_t)tmp32;
+ if (i < d2)
+ {
+ const double dS1 = 1.0 - (dI * dD2Mul);
+ const double dS2 = 2.0 - dS1;
+ double dSample = (dA * dS2 + dB * dS1) / (dS1 + dS2);
+ putSampleValue(s->dataPtr, aIdx, dSample, sample16Bit);
+ }
- tmp32 = (int32_t)round((b * dS4 + a * dS3) / (dS3 + dS4));
- d = (int16_t)tmp32;
-
- if (i < d2) putSampleValue(s->pek, t, (y1 - i - 1) << is16Bit, c);
- if (i < d3) putSampleValue(s->pek, t, (y1 + i) << is16Bit, d);
-
- i++;
+ if (i < d3)
+ {
+ const double dS1 = 1.0 - (dI * dD3Mul);
+ const double dS2 = 2.0 - dS1;
+ double dSample = (dB * dS2 + dA * dS1) / (dS1 + dS2);
+ putSampleValue(s->dataPtr, bIdx, dSample, sample16Bit);
+ }
}
fixSample(s);
resumeAudio();
}
- else
+ else // last loop point
{
- // last loop point
-
- y1 += s->repL;
- if (x1 >= y1 || x2 <= y1 || x2 >= s->len)
+ y1 += s->loopLength;
+ if (x1 >= y1 || x2 <= y1 || x2 >= s->length)
{
- okBox(0, "System message", "Invalid range!");
+ okBox(0, "System message", "Error: No loop point found inside marked data.");
return;
}
@@ -2490,48 +2423,48 @@
d2 = y1 - x1;
d3 = x2 - y1;
- if (d1 < 2 || d2 < 2 || d3 < 2)
+ if (d1 < 1 || d2 < 1 || d3 < 1)
{
- okBox(0, "System message", "Invalid range!");
+ okBox(0, "System message", "Invalid range! Try to mark more data.");
return;
}
- if (y1-d1 < 0 || y1+d1 >= s->len)
+ if (y1-d1 < 0 || y1+d1 >= s->length)
{
okBox(0, "System message", "Not enough sample data outside loop!");
return;
}
- if (is16Bit)
- {
- y1 >>= 1;
- d1 >>= 1;
- d2 >>= 1;
- d3 >>= 1;
- }
+ const double dD2Mul = 1.0 / d2;
+ const double dD3Mul = 1.0 / d3;
pauseAudio();
- restoreSample(s);
+ unfixSample(s);
- i = 0;
- while (i < d1)
+ for (int32_t i = 0; i < d1; i++)
{
- a = getSampleValue(s->pek, t, (y1 - i - 1) << is16Bit);
- b = getSampleValue(s->pek, t, (y1 + i) << is16Bit);
+ const int32_t aIdx = y1-i-1;
+ const int32_t bIdx = y1+i;
+ const double dI = i;
- dS1 = 1.0 - i / (double)d2; dS2 = 2.0 - dS1;
- dS3 = 1.0 - i / (double)d3; dS4 = 2.0 - dS3;
+ const double dA = getSampleValue(s->dataPtr, aIdx, sample16Bit);
+ const double dB = getSampleValue(s->dataPtr, bIdx, sample16Bit);
- tmp32 = (int32_t)round((a * dS2 + b * dS1) / (dS1 + dS2));
- c = (int16_t)tmp32;
+ if (i < d2)
+ {
+ const double dS1 = 1.0 - (dI * dD2Mul);
+ const double dS2 = 2.0 - dS1;
+ double dSample = (dA * dS2 + dB * dS1) / (dS1 + dS2);
+ putSampleValue(s->dataPtr, aIdx, dSample, sample16Bit);
+ }
- tmp32 = (int32_t)round((b * dS4 + a * dS3) / (dS3 + dS4));
- d = (int16_t)tmp32;
-
- if (i < d2) putSampleValue(s->pek, t, (y1 - i - 1) << is16Bit, c);
- if (i < d3) putSampleValue(s->pek, t, (y1 + i) << is16Bit, d);
-
- i++;
+ if (i < d3)
+ {
+ const double dS1 = 1.0 - (dI * dD3Mul);
+ const double dS2 = 2.0 - dS1;
+ double dSample = (dB * dS2 + dA * dS1) / (dS1 + dS2);
+ putSampleValue(s->dataPtr, bIdx, dSample, sample16Bit);
+ }
}
fixSample(s);
@@ -2538,90 +2471,82 @@
resumeAudio();
}
}
- else
+ else // forward loop
{
- // standard loop
-
- if (x1 > s->repS)
+ if (x1 > s->loopStart)
{
- x1 -= s->repL;
- x2 -= s->repL;
+ x1 -= s->loopLength;
+ x2 -= s->loopLength;
}
- if (x1 < 0 || x2 <= x1 || x2 >= s->len)
+ if (x1 < 0 || x2 <= x1 || x2 >= s->length)
{
okBox(0, "System message", "Invalid range!");
return;
}
- i = (x2 - x1 + 1) >> 1;
- y1 = s->repS - i;
- y2 = s->repS + s->repL - i;
+ const int32_t length = x2 - x1;
- if (t & 16)
- {
- y1 &= 0xFFFFFFFE;
- y2 &= 0xFFFFFFFE;
- }
+ int32_t x = (length + 1) >> 1;
+ y1 = s->loopStart - x;
+ y2 = s->loopStart+s->loopLength - x;
- if (y1 < 0 || y2+(x2-x1) >= s->len)
+ if (y1 < 0 || y2+length >= s->length)
{
okBox(0, "System message", "Not enough sample data outside loop!");
return;
}
- d1 = x2 - x1;
- d2 = s->repS - y1;
- d3 = x2 - x1 - d2;
+ d1 = length;
+ d2 = s->loopStart - y1;
+ d3 = length - d2;
- if (y1+(x2-x1) <= s->repS || d1 == 0 || d3 == 0 || d1 > s->repL)
+ if (y1+length <= s->loopStart || d1 == 0 || d3 == 0 || d1 > s->loopLength)
{
okBox(0, "System message", "Invalid range!");
return;
}
- dR = (s->repS - i) / (double)(x2 - x1);
- dist = is16Bit ? 2 : 1;
+ const double dR = (s->loopStart - x) / (double)length;
+ const double dD1 = d1;
+ const double dD1Mul = 1.0 / d1;
+ const double dD2Mul = 1.0 / d2;
+ const double dD3Mul = 1.0 / d3;
pauseAudio();
- restoreSample(s);
+ unfixSample(s);
- i = 0;
- while (i < x2-x1)
+ for (int32_t i = 0; i < length; i++)
{
- a = getSampleValue(s->pek, t, y1 + i);
- b = getSampleValue(s->pek, t, y2 + i);
+ const int32_t aIdx = y1+i;
+ const int32_t bIdx = y2+i;
+ const double dI = i;
- dS2 = i / (double)d1;
- dS1 = 1.0 - dS2;
+ const double dA = getSampleValue(s->dataPtr, aIdx, sample16Bit);
+ const double dB = getSampleValue(s->dataPtr, bIdx, sample16Bit);
+ const double dS2 = dI * dD1Mul;
+ const double dS1 = 1.0 - dS2;
- if (y1+i < s->repS)
+ double dC, dD;
+ if (y1+i < s->loopStart)
{
- dS3 = 1.0 - (1.0 - dR) * i / d2;
- dS4 = dR * i / d2;
-
- tmp32 = (int32_t)round((a * dS3 + b * dS4) / (dS3 + dS4));
- c = (int16_t)tmp32;
-
- tmp32 = (int32_t)round((a * dS2 + b * dS1) / (dS1 + dS2));
- d = (int16_t)tmp32;
+ const double dS3 = 1.0 - (1.0 - dR) * dI * dD2Mul;
+ const double dS4 = dR * dI * dD2Mul;
+
+ dC = (dA * dS3 + dB * dS4) / (dS3 + dS4);
+ dD = (dA * dS2 + dB * dS1) / (dS1 + dS2);
}
else
{
- dS3 = 1.0 - (1.0 - dR) * (d1 - i) / d3;
- dS4 = dR * (d1 - i) / d3;
+ const double dS3 = 1.0 - (1.0 - dR) * (dD1 - dI) * dD3Mul;
+ const double dS4 = dR * (dD1 - dI) * dD3Mul;
- tmp32 = (int32_t)round((a * dS2 + b * dS1) / (dS1 + dS2));
- c = (int16_t)tmp32;
-
- tmp32 = (int32_t)round((a * dS4 + b * dS3) / (dS3 + dS4));
- d = (int16_t)tmp32;
+ dC = (dA * dS2 + dB * dS1) / (dS1 + dS2);
+ dD = (dA * dS4 + dB * dS3) / (dS3 + dS4);
}
- putSampleValue(s->pek, t, y1 + i, c);
- putSampleValue(s->pek, t, y2 + i, d);
-
- i += dist;
+ putSampleValue(s->dataPtr, aIdx, dC, sample16Bit);
+ putSampleValue(s->dataPtr, bIdx, dD, sample16Bit);
}
fixSample(s);
@@ -2634,14 +2559,14 @@
void rbSampleNoLoop(void)
{
- sampleTyp *s = getCurSample();
- if (s == NULL || s->pek == NULL || s->len <= 0)
+ sample_t *s = getCurSample();
+ if (s == NULL || s->dataPtr == NULL || s->length <= 0)
return;
lockMixerCallback();
- restoreSample(s);
+ unfixSample(s);
- s->typ &= ~3;
+ DISABLE_LOOP(s->flags);
fixSample(s);
unlockMixerCallback();
@@ -2653,18 +2578,20 @@
void rbSampleForwardLoop(void)
{
- sampleTyp *s = getCurSample();
- if (s == NULL || s->pek == NULL || s->len <= 0)
+ sample_t *s = getCurSample();
+ if (s == NULL || s->dataPtr == NULL || s->length <= 0)
return;
lockMixerCallback();
- restoreSample(s);
+ unfixSample(s);
- s->typ = (s->typ & ~3) | 1;
- if (s->repL+s->repS == 0)
+ DISABLE_LOOP(s->flags);
+ s->flags |= LOOP_FWD;
+
+ if (s->loopStart+s->loopLength == 0)
{
- s->repS = 0;
- s->repL = s->len;
+ s->loopStart = 0;
+ s->loopLength = s->length;
}
fixSample(s);
@@ -2677,18 +2604,20 @@
void rbSamplePingpongLoop(void)
{
- sampleTyp *s = getCurSample();
- if (s == NULL || s->pek == NULL || s->len <= 0)
+ sample_t *s = getCurSample();
+ if (s == NULL || s->dataPtr == NULL || s->length <= 0)
return;
lockMixerCallback();
- restoreSample(s);
+ unfixSample(s);
- s->typ = (s->typ & ~3) | 2;
- if (s->repL+s->repS == 0)
+ DISABLE_LOOP(s->flags);
+ s->flags |= LOOP_BIDI;
+
+ if (s->loopStart+s->loopLength == 0)
{
- s->repS = 0;
- s->repL = s->len;
+ s->loopStart = 0;
+ s->loopLength = s->length;
}
fixSample(s);
@@ -2701,38 +2630,27 @@
static int32_t SDLCALL convSmp8Bit(void *ptr)
{
- sampleTyp *s = getCurSample();
+ sample_t *s = getCurSample();
+ assert(s->dataPtr != NULL);
pauseAudio();
- restoreSample(s);
+ unfixSample(s);
- const int16_t *src16 = (const int16_t *)s->pek;
- int32_t newLen = s->len >> 1;
+ const int16_t *src16 = (const int16_t *)s->dataPtr;
+ for (int32_t i = 0; i < s->length; i++)
+ s->dataPtr[i] = src16[i] >> 8;
- for (int32_t i = 0; i < newLen; i++)
- s->pek[i] = src16[i] >> 8;
+ reallocateSmpData(s, s->length, false);
- assert(s->origPek != NULL);
+ s->flags &= ~SAMPLE_16BIT; // remove 16-bit flag
- int8_t *newPtr = (int8_t *)realloc(s->origPek, newLen + LOOP_FIX_LEN);
- if (newPtr != NULL)
- {
- s->origPek = newPtr;
- s->pek = s->origPek + SMP_DAT_OFFSET;
- }
-
- s->repL >>= 1;
- s->repS >>= 1;
- s->len >>= 1;
- s->typ &= ~16; // remove 16-bit flag
-
fixSample(s);
resumeAudio();
- editor.updateCurSmp = true;
setSongModifiedFlag();
setMouseBusy(false);
+ editor.updateCurSmp = true;
return true;
(void)ptr;
@@ -2740,8 +2658,8 @@
void rbSample8bit(void)
{
- sampleTyp *s = getCurSample();
- if (s == NULL || s->pek == NULL || s->len <= 0)
+ sample_t *s = getCurSample();
+ if (s == NULL || s->dataPtr == NULL || s->length <= 0)
return;
if (okBox(2, "System request", "Convert sampledata?") == 1)
@@ -2760,9 +2678,11 @@
else
{
lockMixerCallback();
- restoreSample(s);
+ unfixSample(s);
- s->typ &= ~16; // remove 16-bit flag
+ s->flags &= ~SAMPLE_16BIT; // remove 16-bit flag
+ s->length <<= 1;
+ // no need to call reallocateSmpData, number of bytes allocated is the same
fixSample(s);
unlockMixerCallback();
@@ -2775,41 +2695,30 @@
static int32_t SDLCALL convSmp16Bit(void *ptr)
{
- sampleTyp *s = getCurSample();
+ sample_t *s = getCurSample();
pauseAudio();
- restoreSample(s);
+ unfixSample(s);
- assert(s->origPek != NULL);
-
- int8_t *newPtr = (int8_t *)realloc(s->origPek, (s->len * 2) + LOOP_FIX_LEN);
- if (newPtr == NULL)
+ if (!reallocateSmpData(s, s->length, true))
{
okBoxThreadSafe(0, "System message", "Not enough memory!");
return true;
}
- else
- {
- s->origPek = newPtr;
- s->pek = s->origPek + SMP_DAT_OFFSET;
- }
- int16_t *dst16 = (int16_t *)s->pek;
- for (int32_t i = s->len-1; i >= 0; i--)
- dst16[i] = s->pek[i] << 8;
+ int16_t *dst16 = (int16_t *)s->dataPtr;
+ for (int32_t i = s->length-1; i >= 0; i--)
+ dst16[i] = s->dataPtr[i] << 8;
- s->len <<= 1;
- s->repL <<= 1;
- s->repS <<= 1;
- s->typ |= 16; // add 16-bit flag
+ s->flags |= SAMPLE_16BIT;
fixSample(s);
resumeAudio();
- editor.updateCurSmp = true;
setSongModifiedFlag();
setMouseBusy(false);
+ editor.updateCurSmp = true;
return true;
(void)ptr;
@@ -2817,8 +2726,8 @@
void rbSample16bit(void)
{
- sampleTyp *s = getCurSample();
- if (s == NULL || s->pek == NULL || s->len <= 0)
+ sample_t *s = getCurSample();
+ if (s == NULL || s->dataPtr == NULL || s->length <= 0)
return;
if (okBox(2, "System request", "Convert sampledata?") == 1)
@@ -2837,15 +2746,12 @@
else
{
lockMixerCallback();
- restoreSample(s);
+ unfixSample(s);
- s->typ |= 16; // add 16-bit flag
+ s->flags |= SAMPLE_16BIT;
+ s->length >>= 1;
+ // no need to call reallocateSmpData, number of bytes allocated is the same
- // make sure stuff is 2-byte aligned for 16-bit mode
- s->repS &= 0xFFFFFFFE;
- s->repL &= 0xFFFFFFFE;
- s->len &= 0xFFFFFFFE;
-
fixSample(s);
unlockMixerCallback();
@@ -2857,8 +2763,8 @@
void clearSample(void)
{
- sampleTyp *s = getCurSample();
- if (s == NULL || s->pek == NULL || s->len <= 0)
+ sample_t *s = getCurSample();
+ if (s == NULL || s->dataPtr == NULL || s->length <= 0)
return;
if (okBox(1, "System request", "Clear sample?") != 1)
@@ -2869,125 +2775,112 @@
setSongModifiedFlag();
}
-void sampMin(void)
+void sampMinimize(void)
{
- sampleTyp *s = getCurSample();
- if (s == NULL || s->pek == NULL || s->len <= 0)
+ sample_t *s = getCurSample();
+ if (s == NULL || s->dataPtr == NULL || s->length <= 0)
return;
- if (okBox(1, "System request", "Minimize sample?") != 1)
+ const bool hasLoop = GET_LOOPTYPE(s->flags) != LOOP_OFF;
+ if (!hasLoop)
+ {
+ okBox(0, "System message", "Only a looped sample can be minimized!");
return;
+ }
- const bool hasLoop = s->typ & 3;
- if (hasLoop && s->len > s->repS+s->repL && s->repL < s->len)
+ if (s->loopStart+s->loopLength >= s->length)
{
- lockMixerCallback();
+ okBox(0, "System message", "The sample can't be minimized any further.");
+ return;
+ }
- s->len = s->repS + s->repL;
+ if (okBox(1, "System request", "Minimize sample?") != 1)
+ return;
+
+ lockMixerCallback();
- int8_t *newPtr = (int8_t *)realloc(s->origPek, s->len + LOOP_FIX_LEN);
- if (newPtr != NULL)
- {
- s->origPek = newPtr;
- s->pek = s->origPek + SMP_DAT_OFFSET;
- }
+ s->length = s->loopStart + s->loopLength;
- // Note: we don't need to make a call to fixSample()
+ bool sample16Bit = !!(s->flags & SAMPLE_16BIT);
+ reallocateSmpData(s, s->length, sample16Bit);
+ // note: we don't need to make a call to fixSample()
- unlockMixerCallback();
+ unlockMixerCallback();
- updateSampleEditorSample();
- updateSampleEditor();
- setSongModifiedFlag();
- }
+ updateSampleEditorSample();
+ updateSampleEditor();
+ setSongModifiedFlag();
}
void sampRepeatUp(void)
{
- int32_t addVal, lenSub;
-
- sampleTyp *s = getCurSample();
- if (s == NULL || s->pek == NULL || s->len <= 0)
+ sample_t *s = getCurSample();
+ if (s == NULL || s->dataPtr == NULL || s->length <= 0)
return;
- if (s->typ & 16)
- {
- lenSub = 4;
- addVal = 2;
- }
- else
- {
- lenSub = 2;
- addVal = 1;
- }
+ int32_t loopStart = curSmpLoopStart;
+ int32_t loopLength = curSmpLoopLength;
- int32_t repS = curSmpRepS;
- int32_t repL = curSmpRepL;
+ if (loopStart < s->length-2)
+ loopStart++;
- if (repS < s->len-lenSub)
- repS += addVal;
+ if (loopStart+loopLength > s->length)
+ loopLength = s->length - loopStart;
- if (repS+repL > s->len)
- repL = s->len - repS;
+ curSmpLoopStart = loopStart;
+ curSmpLoopLength = loopLength;
- curSmpRepS = (s->typ & 16) ? (int32_t)(repS & 0xFFFFFFFE) : repS;
- curSmpRepL = (s->typ & 16) ? (int32_t)(repL & 0xFFFFFFFE) : repL;
-
- fixRepeatGadgets();
+ fixLoopGadgets();
updateLoopsOnMouseUp = true;
}
void sampRepeatDown(void)
{
- sampleTyp *s = getCurSample();
- if (s == NULL || s->pek == NULL || s->len <= 0)
+ sample_t *s = getCurSample();
+ if (s == NULL || s->dataPtr == NULL || s->length <= 0)
return;
- int32_t repS = (s->typ & 16) ? curSmpRepS-2 : curSmpRepS-1;
- if (repS < 0)
- repS = 0;
+ int32_t loopStart = curSmpLoopStart - 1;
+ if (loopStart < 0)
+ loopStart = 0;
- curSmpRepS = (s->typ & 16) ? (int32_t)(repS & 0xFFFFFFFE) : repS;
+ curSmpLoopStart = loopStart;
- fixRepeatGadgets();
+ fixLoopGadgets();
updateLoopsOnMouseUp = true;
}
void sampReplenUp(void)
{
- sampleTyp *s = getCurSample();
- if (s == NULL || s->pek == NULL || s->len <= 0)
+ sample_t *s = getCurSample();
+ if (s == NULL || s->dataPtr == NULL || s->length <= 0)
return;
- int32_t repL = (s->typ & 16) ? curSmpRepL+2 : curSmpRepL+1;
- if (curSmpRepS+repL > s->len)
- repL = s->len - curSmpRepS;
+ int32_t loopLength = curSmpLoopLength + 1;
+ if (curSmpLoopStart+loopLength > s->length)
+ loopLength = s->length - curSmpLoopStart;
- curSmpRepL = (s->typ & 16) ? (int32_t)(repL & 0xFFFFFFFE) : repL;
+ curSmpLoopLength = loopLength;
- fixRepeatGadgets();
+ fixLoopGadgets();
updateLoopsOnMouseUp = true;
}
void sampReplenDown(void)
{
- int32_t repL;
+ int32_t loopLength;
- sampleTyp *s = getCurSample();
- if (s == NULL || s->pek == NULL || s->len <= 0)
+ sample_t *s = getCurSample();
+ if (s == NULL || s->dataPtr == NULL || s->length <= 0)
return;
- if (s->typ & 16)
- repL = curSmpRepL - 2;
- else
- repL = curSmpRepL - 1;
+ loopLength = curSmpLoopLength - 1;
+ if (loopLength < 0)
+ loopLength = 0;
- if (repL < 0)
- repL = 0;
+ curSmpLoopLength = loopLength;
- curSmpRepL = (s->typ & 16) ? (int32_t)(repL & 0xFFFFFFFE) : repL;
-
- fixRepeatGadgets();
+ fixLoopGadgets();
updateLoopsOnMouseUp = true;
}
@@ -3104,7 +2997,7 @@
showScrollBar(SB_SAMP_SCROLL);
- // clear two lines that are never written to when the sampler is open
+ // clear two lines in the sample data view that are never written to when the sampler is open
hLine(0, 173, SAMPLE_AREA_WIDTH, PAL_BCKGRND);
hLine(0, 328, SAMPLE_AREA_WIDTH, PAL_BCKGRND);
@@ -3127,7 +3020,7 @@
}
}
-static void writeSmpXORLine(int32_t x)
+static void invertSamplePosLine(int32_t x)
{
if (x < 0 || x >= SCREEN_W)
return;
@@ -3141,10 +3034,10 @@
{
uint8_t ins, smp;
- assert(editor.curSmpChannel < MAX_VOICES);
+ assert(editor.curSmpChannel < MAX_CHANNELS);
lastChInstr_t *c = &lastChInstr[editor.curSmpChannel];
- if (c->instrNr == 130) // "Play Wave/Range/Display" in Smp. Ed.
+ if (c->instrNum == 130) // "Play Wave/Range/Display" in Smp. Ed.
{
ins = editor.curPlayInstr;
smp = editor.curPlaySmp;
@@ -3151,8 +3044,8 @@
}
else
{
- ins = c->instrNr;
- smp = c->sampleNr;
+ ins = c->instrNum;
+ smp = c->smpNum;
}
if (editor.curInstr == ins && editor.curSmp == smp)
@@ -3166,8 +3059,8 @@
{
if (scrPos != smpEd_OldSmpPosLine)
{
- writeSmpXORLine(smpEd_OldSmpPosLine); // remove old line
- writeSmpXORLine(scrPos); // write new line
+ invertSamplePosLine(smpEd_OldSmpPosLine); // remove old line
+ invertSamplePosLine(scrPos); // write new line
}
smpEd_OldSmpPosLine = scrPos;
@@ -3177,7 +3070,7 @@
}
if (smpEd_OldSmpPosLine != -1)
- writeSmpXORLine(smpEd_OldSmpPosLine);
+ invertSamplePosLine(smpEd_OldSmpPosLine);
smpEd_OldSmpPosLine = -1;
}
@@ -3204,61 +3097,52 @@
static void setLeftLoopPinPos(int32_t x)
{
- sampleTyp *s = getCurSample();
- if (s == NULL || s->pek == NULL || s->len <= 0)
+ sample_t *s = getCurSample();
+ if (s == NULL || s->dataPtr == NULL || s->length <= 0)
return;
- int32_t newPos = scr2SmpPos(x) - curSmpRepS;
- int32_t repS = curSmpRepS + newPos;
- int32_t repL = curSmpRepL - newPos;
+ int32_t newPos = scr2SmpPos(x) - curSmpLoopStart;
+ int32_t loopStart = curSmpLoopStart + newPos;
+ int32_t loopLength = curSmpLoopLength - newPos;
- if (repS < 0)
+ if (loopStart < 0)
{
- repL += repS;
- repS = 0;
+ loopLength += loopStart;
+ loopStart = 0;
}
- if (repL < 0)
+ if (loopLength < 0)
{
- repL = 0;
- repS = curSmpRepS + curSmpRepL;
+ loopLength = 0;
+ loopStart = curSmpLoopStart + curSmpLoopLength;
}
- if (s->typ & 16)
- {
- repS &= 0xFFFFFFFE;
- repL &= 0xFFFFFFFE;
- }
+ curSmpLoopStart = loopStart;
+ curSmpLoopLength = loopLength;
- curSmpRepS = repS;
- curSmpRepL = repL;
-
- fixRepeatGadgets();
+ fixLoopGadgets();
updateLoopsOnMouseUp = true;
}
static void setRightLoopPinPos(int32_t x)
{
- sampleTyp *s = getCurSample();
- if (s == NULL || s->pek == NULL || s->len <= 0)
+ sample_t *s = getCurSample();
+ if (s == NULL || s->dataPtr == NULL || s->length <= 0)
return;
- int32_t repL = scr2SmpPos(x) - curSmpRepS;
- if (repL < 0)
- repL = 0;
+ int32_t loopLength = scr2SmpPos(x) - curSmpLoopStart;
+ if (loopLength < 0)
+ loopLength = 0;
- if (repL+curSmpRepS > s->len)
- repL = s->len - curSmpRepS;
+ if (loopLength+curSmpLoopStart > s->length)
+ loopLength = s->length - curSmpLoopStart;
- if (repL < 0)
- repL = 0;
+ if (loopLength < 0)
+ loopLength = 0;
- if (s->typ & 16)
- repL &= 0xFFFFFFFE;
+ curSmpLoopLength = loopLength;
- curSmpRepL = repL;
-
- fixRepeatGadgets();
+ fixLoopGadgets();
updateLoopsOnMouseUp = true;
}
@@ -3266,8 +3150,8 @@
{
my -= 174; // 0..SAMPLE_AREA_HEIGHT-1
- const double dTmp = round(my * (256.0 / SAMPLE_AREA_HEIGHT));
- const int32_t tmp32 = (const int32_t)dTmp;
+ const double dTmp = my * (256.0 / SAMPLE_AREA_HEIGHT);
+ const int32_t tmp32 = (const int32_t)(dTmp + 0.5); // rounded
return 255 - CLAMP(tmp32, 0, 255);
}
@@ -3278,8 +3162,8 @@
int16_t *ptr16;
int32_t tmp32, p, vl, tvl, r, rl, rvl, start, end;
- sampleTyp *s = getCurSample();
- if (s == NULL || s->pek == NULL || s->len <= 0)
+ sample_t *s = getCurSample();
+ if (s == NULL || s->dataPtr == NULL || s->length <= 0)
return;
int32_t mx = mouse.x;
@@ -3291,12 +3175,10 @@
if (!mouseButtonHeld)
{
pauseAudio();
- restoreSample(s);
+ unfixSample(s);
editor.editSampleFlag = true;
lastDrawX = scr2SmpPos(mx);
- if (s->typ & 16)
- lastDrawX >>= 1;
lastDrawY = mouseYToSampleY(my);
@@ -3309,15 +3191,9 @@
}
if (mx != lastMouseX)
- {
p = scr2SmpPos(mx);
- if (s->typ & 16)
- p >>= 1;
- }
else
- {
p = lastDrawX;
- }
if (!keyb.leftShiftPressed && my != lastMouseY)
vl = mouseYToSampleY(my);
@@ -3344,21 +3220,17 @@
vl = tmp32;
}
- if (s->typ & 16)
+ if (s->flags & SAMPLE_16BIT)
{
- // 16-bit
+ ptr16 = (int16_t *)s->dataPtr;
- ptr16 = (int16_t *)s->pek;
-
start = p;
- end = lastDrawX+1;
-
if (start < 0)
start = 0;
- tmp32 = s->len >> 1;
- if (end > tmp32)
- end = tmp32;
+ end = lastDrawX+1;
+ if (end > s->length)
+ end = s->length;
if (p == lastDrawX)
{
@@ -3390,19 +3262,17 @@
}
}
}
- else
+ else // 8-bit
{
- // 8-bit
+ ptr8 = s->dataPtr;
- ptr8 = s->pek;
-
start = p;
if (start < 0)
start = 0;
end = lastDrawX+1;
- if (end > s->len)
- end = s->len;
+ if (end > s->length)
+ end = s->length;
if (p == lastDrawX)
{
@@ -3641,23 +3511,26 @@
{
int8_t tmp8, *ptrStart, *ptrEnd;
int16_t tmp16, *ptrStart16, *ptrEnd16;
- sampleTyp *s = getCurSample();
- if (s->typ & 16)
+ const bool sampleDataMarked = (smpEd_Rx1 != smpEd_Rx2);
+ sample_t *s = getCurSample();
+ const bool sample16Bit = !!(s->flags & SAMPLE_16BIT);
+
+ if (sample16Bit)
{
- if (smpEd_Rx1 >= smpEd_Rx2)
+ if (!sampleDataMarked)
{
- ptrStart16 = (int16_t *)s->pek;
- ptrEnd16 = (int16_t *)&s->pek[s->len-2];
+ ptrStart16 = (int16_t *)s->dataPtr;
+ ptrEnd16 = (int16_t *)s->dataPtr + (s->length-1);
}
else
{
- ptrStart16 = (int16_t *)&s->pek[smpEd_Rx1];
- ptrEnd16 = (int16_t *)&s->pek[smpEd_Rx2-2];
+ ptrStart16 = (int16_t *)s->dataPtr + smpEd_Rx1;
+ ptrEnd16 = (int16_t *)s->dataPtr + (smpEd_Rx2-1);
}
pauseAudio();
- restoreSample(s);
+ unfixSample(s);
while (ptrStart16 < ptrEnd16)
{
@@ -3671,19 +3544,19 @@
}
else
{
- if (smpEd_Rx1 >= smpEd_Rx2)
+ if (!sampleDataMarked)
{
- ptrStart = s->pek;
- ptrEnd = &s->pek[s->len-1];
+ ptrStart = s->dataPtr;
+ ptrEnd = &s->dataPtr[s->length-1];
}
else
{
- ptrStart = &s->pek[smpEd_Rx1];
- ptrEnd = &s->pek[smpEd_Rx2-1];
+ ptrStart = &s->dataPtr[smpEd_Rx1];
+ ptrEnd = &s->dataPtr[smpEd_Rx2-1];
}
pauseAudio();
- restoreSample(s);
+ unfixSample(s);
while (ptrStart < ptrEnd)
{
@@ -3698,8 +3571,8 @@
setSongModifiedFlag();
setMouseBusy(false);
- writeSampleFlag = true;
+ writeSampleFlag = true;
return true;
(void)ptr;
@@ -3707,8 +3580,8 @@
void sampleBackwards(void)
{
- sampleTyp *s = getCurSample();
- if (s == NULL || s->pek == NULL || s->len < 2)
+ sample_t *s = getCurSample();
+ if (s == NULL || s->dataPtr == NULL || s->length < 2)
return;
mouseAnimOn();
@@ -3722,30 +3595,23 @@
SDL_DetachThread(thread);
}
-static int32_t SDLCALL sampleConvThread(void *ptr)
+static int32_t SDLCALL sampleChangeSignThread(void *ptr)
{
- int8_t *ptr8;
- int16_t *ptr16;
- int32_t i, len;
- sampleTyp *s = getCurSample();
+ sample_t *s = getCurSample();
pauseAudio();
- restoreSample(s);
+ unfixSample(s);
- if (s->typ & 16)
+ if (s->flags & SAMPLE_16BIT)
{
- len = s->len / 2;
- ptr16 = (int16_t *)s->pek;
-
- for (i = 0; i < len; i++)
+ int16_t *ptr16 = (int16_t *)s->dataPtr;
+ for (int32_t i = 0; i < s->length; i++)
ptr16[i] ^= 0x8000;
}
else
{
- len = s->len;
- ptr8 = s->pek;
-
- for (i = 0; i < len; i++)
+ int8_t *ptr8 = s->dataPtr;
+ for (int32_t i = 0; i < s->length; i++)
ptr8[i] ^= 0x80;
}
@@ -3754,21 +3620,21 @@
setSongModifiedFlag();
setMouseBusy(false);
- writeSampleFlag = true;
+ writeSampleFlag = true;
return true;
(void)ptr;
}
-void sampleConv(void)
+void sampleChangeSign(void)
{
- sampleTyp *s = getCurSample();
- if (s == NULL || s->pek == NULL || s->len <= 0)
+ sample_t *s = getCurSample();
+ if (s == NULL || s->dataPtr == NULL || s->length <= 0)
return;
mouseAnimOn();
- thread = SDL_CreateThread(sampleConvThread, NULL, NULL);
+ thread = SDL_CreateThread(sampleChangeSignThread, NULL, NULL);
if (thread == NULL)
{
okBox(0, "System message", "Couldn't create thread!");
@@ -3778,17 +3644,19 @@
SDL_DetachThread(thread);
}
-static int32_t SDLCALL sampleConvWThread(void *ptr)
+static int32_t SDLCALL sampleByteSwapThread(void *ptr)
{
- sampleTyp *s = getCurSample();
+ sample_t *s = getCurSample();
pauseAudio();
- restoreSample(s);
+ unfixSample(s);
- int32_t len = s->len / 2;
- int8_t *ptr8 = s->pek;
+ int32_t length = s->length;
+ if (!(s->flags & SAMPLE_16BIT))
+ length >>= 1;
- for (int32_t i = 0; i < len; i++, ptr8 += 2)
+ int8_t *ptr8 = s->dataPtr;
+ for (int32_t i = 0; i < length; i++, ptr8 += 2)
{
const int8_t tmp = ptr8[0];
ptr8[0] = ptr8[1];
@@ -3800,21 +3668,27 @@
setSongModifiedFlag();
setMouseBusy(false);
- writeSampleFlag = true;
+ writeSampleFlag = true;
return true;
(void)ptr;
}
-void sampleConvW(void)
+void sampleByteSwap(void)
{
- sampleTyp *s = getCurSample();
- if (s == NULL || s->pek == NULL || s->len <= 0)
+ sample_t *s = getCurSample();
+ if (s == NULL || s->dataPtr == NULL || s->length <= 0)
return;
+ if (!(s->flags & SAMPLE_16BIT))
+ {
+ if (okBox(2, "System request", "Byte swapping only makes sense on a 16-bit sample. Continue?") != 1)
+ return;
+ }
+
mouseAnimOn();
- thread = SDL_CreateThread(sampleConvWThread, NULL, NULL);
+ thread = SDL_CreateThread(sampleByteSwapThread, NULL, NULL);
if (thread == NULL)
{
okBox(0, "System message", "Couldn't create thread!");
@@ -3828,30 +3702,25 @@
{
int8_t *ptr8;
int16_t *ptr16;
- int32_t i, len, smpSub, smp32;
- sampleTyp *s = getCurSample();
+ int32_t length;
- int64_t averageDC = 0;
+ const bool sampleDataMarked = (smpEd_Rx1 != smpEd_Rx2);
+ sample_t *s = getCurSample();
- if (s->typ & 16)
+ if (s->flags & SAMPLE_16BIT)
{
- if (smpEd_Rx1 >= smpEd_Rx2)
+ if (!sampleDataMarked)
{
- assert(!(s->len & 1));
-
- ptr16 = (int16_t *)s->pek;
- len = s->len >> 1;
+ ptr16 = (int16_t *)s->dataPtr;
+ length = s->length;
}
else
{
- assert(!(smpEd_Rx1 & 1));
- assert(!(smpEd_Rx2 & 1));
-
- ptr16 = (int16_t *)&s->pek[smpEd_Rx1];
- len = (smpEd_Rx2 - smpEd_Rx1) >> 1;
+ ptr16 = (int16_t *)&s->dataPtr + smpEd_Rx1;
+ length = smpEd_Rx2 - smpEd_Rx1;
}
- if (len < 0 || len > s->len>>1)
+ if (length < 0 || length > s->length)
{
setMouseBusy(false);
return true;
@@ -3858,16 +3727,17 @@
}
pauseAudio();
- restoreSample(s);
+ unfixSample(s);
- for (i = 0; i < len; i++)
+ int64_t averageDC = 0;
+ for (int32_t i = 0; i < length; i++)
averageDC += ptr16[i];
- averageDC /= len;
+ averageDC = (averageDC + (length>>1)) / length; // rounded
- smpSub = (int32_t)averageDC;
- for (i = 0; i < len; i++)
+ const int32_t smpSub = (int32_t)averageDC;
+ for (int32_t i = 0; i < length; i++)
{
- smp32 = ptr16[i] - smpSub;
+ int32_t smp32 = ptr16[i] - smpSub;
CLAMP16(smp32);
ptr16[i] = (int16_t)smp32;
}
@@ -3875,20 +3745,20 @@
fixSample(s);
resumeAudio();
}
- else
+ else // 8-bit
{
- if (smpEd_Rx1 >= smpEd_Rx2)
+ if (!sampleDataMarked)
{
- ptr8 = s->pek;
- len = s->len;
+ ptr8 = s->dataPtr;
+ length = s->length;
}
else
{
- ptr8 = &s->pek[smpEd_Rx1];
- len = smpEd_Rx2 - smpEd_Rx1;
+ ptr8 = &s->dataPtr[smpEd_Rx1];
+ length = smpEd_Rx2 - smpEd_Rx1;
}
- if (len < 0 || len > s->len)
+ if (length < 0 || length > s->length)
{
setMouseBusy(false);
return true;
@@ -3895,16 +3765,17 @@
}
pauseAudio();
- restoreSample(s);
+ unfixSample(s);
- for (i = 0; i < len; i++)
+ int64_t averageDC = 0;
+ for (int32_t i = 0; i < length; i++)
averageDC += ptr8[i];
- averageDC /= len;
+ averageDC = (averageDC + (length>>1)) / length; // rounded
- smpSub = (int32_t)averageDC;
- for (i = 0; i < len; i++)
+ const int32_t smpSub = (int32_t)averageDC;
+ for (int32_t i = 0; i < length; i++)
{
- smp32 = ptr8[i] - smpSub;
+ int32_t smp32 = ptr8[i] - smpSub;
CLAMP8(smp32);
ptr8[i] = (int8_t)smp32;
}
@@ -3913,10 +3784,10 @@
resumeAudio();
}
- writeSampleFlag = true;
setSongModifiedFlag();
setMouseBusy(false);
+ writeSampleFlag = true;
return true;
(void)ptr;
@@ -3924,9 +3795,8 @@
void fixDC(void)
{
- sampleTyp *s = getCurSample();
-
- if (s == NULL || s->pek == NULL || s->len <= 0)
+ sample_t *s = getCurSample();
+ if (s == NULL || s->dataPtr == NULL || s->length <= 0)
return;
mouseAnimOn();
@@ -3953,23 +3823,20 @@
{
updateLoopsOnMouseUp = false;
- sampleTyp *s = getCurSample();
+ sample_t *s = getCurSample();
if (s == NULL)
return;
- if (s->repS != curSmpRepS || s->repL != curSmpRepL)
+ if (s->loopStart != curSmpLoopStart || s->loopLength != curSmpLoopLength)
{
lockMixerCallback();
- restoreSample(s);
-
- setSongModifiedFlag();
-
- s->repS = curSmpRepS;
- s->repL = curSmpRepL;
-
+ unfixSample(s);
+ s->loopStart = curSmpLoopStart;
+ s->loopLength = curSmpLoopLength;
fixSample(s);
unlockMixerCallback();
+ setSongModifiedFlag();
writeSample(true);
}
}
--- a/src/ft2_sample_ed.h
+++ b/src/ft2_sample_ed.h
@@ -1,7 +1,7 @@
#pragma once
#include <stdint.h>
-#include "ft2_replayer.h"
+#include "ft2_header.h"
#define SAMPLE_AREA_HEIGHT 154
#define SAMPLE_AREA_WIDTH 632
@@ -8,18 +8,25 @@
#define SAMPLE_AREA_Y_CENTER 250
// allocs sample with proper alignment and padding for branchless resampling interpolation
-bool allocateTmpSmpData(sampleTyp *s, int32_t length);
+bool allocateSmpData(sample_t *s, int32_t length, bool sample16Bit);
+bool allocateSmpDataPtr(smpPtr_t *sp, int32_t length, bool sample16Bit);
// reallocs sample with proper alignment and padding for branchless resampling interpolation
-bool reallocateTmpSmpData(sampleTyp *s, int32_t length);
+bool reallocateSmpData(sample_t *s, int32_t length, bool sample16Bit);
+bool reallocateSmpDataPtr(smpPtr_t *sp, int32_t length, bool sample16Bit);
-sampleTyp *getCurSample(void);
-void checkSampleRepeat(sampleTyp *s);
-void fixSample(sampleTyp *s); // modifies samples before index 0, and after loop/end (for branchless mixer interpolation)
-void restoreSample(sampleTyp *s); // restores samples after loop/end
+void setSmpDataPtr(sample_t *s, smpPtr_t *sp);
+void freeSmpDataPtr(smpPtr_t *sp);
+void freeSmpData(sample_t *s);
+
+bool cloneSample(sample_t *src, sample_t *dst);
+sample_t *getCurSample(void);
+void sanitizeSample(sample_t *s);
+void fixSample(sample_t *s); // modifies samples before index 0, and after loop/end (for branchless mixer interpolation)
+void unfixSample(sample_t *s); // restores samples after loop/end
void clearSample(void);
void clearCopyBuffer(void);
-int32_t getSampleMiddleCRate(sampleTyp *s);
+int32_t getSampleMiddleCRate(sample_t *s);
int32_t getSampleRangeStart(void);
int32_t getSampleRangeEnd(void);
int32_t getSampleRangeLength(void);
@@ -50,13 +57,13 @@
void rbSamplePingpongLoop(void);
void rbSample8bit(void);
void rbSample16bit(void);
-void sampMin(void);
+void sampMinimize(void);
void sampRepeatUp(void);
void sampRepeatDown(void);
void sampReplenUp(void);
void sampReplenDown(void);
-int16_t getSampleValue(int8_t *ptr, uint8_t typ, int32_t pos);
-void putSampleValue(int8_t *ptr, uint8_t typ, int32_t pos, int16_t val);
+double getSampleValue(int8_t *smpData, int32_t position, bool sample16Bit);
+void putSampleValue(int8_t *smpData, int32_t position, double dSample, bool sample16Bit);
void writeSample(bool forceSmpRedraw);
void handleSampleDataMouseDown(bool mouseButtonHeld);
void updateSampleEditorSample(void);
@@ -72,10 +79,12 @@
void drawSampleEditorExt(void);
void handleSampleEditorExtRedrawing(void);
void sampleBackwards(void);
-void sampleConv(void);
-void sampleConvW(void);
+void sampleChangeSign(void);
+void sampleByteSwap(void);
void fixDC(void);
void smpEdStop(void);
void testSmpEdMouseUp(void);
+
+void sampleLine(int32_t x1, int32_t x2, int32_t y1, int32_t y2);
extern int32_t smpEd_Rx1, smpEd_Rx2;
--- a/src/ft2_sample_ed_features.c
+++ b/src/ft2_sample_ed_features.c
@@ -30,8 +30,9 @@
static int8_t smpEd_RelReSmp, mix_Balance = 50;
static bool echo_AddMemory, exitFlag, outOfMemory;
-static int16_t vol_StartVol = 100, vol_EndVol = 100, echo_nEcho = 1, echo_VolChange = 30;
+static int16_t echo_nEcho = 1, echo_VolChange = 30;
static int32_t echo_Distance = 0x100;
+static double dVol_StartVol = 100.0, dVol_EndVol = 100.0;
static SDL_Thread *thread;
static void pbExit(void)
@@ -81,22 +82,22 @@
static int32_t SDLCALL resampleThread(void *ptr)
{
+ smpPtr_t sp;
+
if (instr[editor.curInstr] == NULL)
return true;
- sampleTyp *s = &instr[editor.curInstr]->samp[editor.curSmp];
+ sample_t *s = &instr[editor.curInstr]->smp[editor.curSmp];
+ bool sample16Bit = !!(s->flags & SAMPLE_16BIT);
- const uint32_t mask = (s->typ & 16) ? 0xFFFFFFFE : 0xFFFFFFFF;
- const double dRatio = exp2(smpEd_RelReSmp / 12.0);
+ const double dRatio = exp2((int32_t)smpEd_RelReSmp / 12.0);
- double dNewLen = s->len * dRatio;
+ double dNewLen = s->length * dRatio;
if (dNewLen > (double)MAX_SAMPLE_LEN)
dNewLen = (double)MAX_SAMPLE_LEN;
- const uint32_t newLen = (int32_t)dNewLen & mask;
-
- int8_t *p2 = (int8_t *)malloc(newLen + LOOP_FIX_LEN);
- if (p2 == NULL)
+ const uint32_t newLen = (int32_t)floor(dNewLen);
+ if (!allocateSmpDataPtr(&sp, newLen, sample16Bit))
{
outOfMemory = true;
setMouseBusy(false);
@@ -104,8 +105,8 @@
return true;
}
- int8_t *newPtr = p2 + SMP_DAT_OFFSET;
- int8_t *p1 = s->pek;
+ int8_t *dst = sp.ptr;
+ int8_t *src = s->dataPtr;
// 32.32 fixed-point logic
const uint64_t delta64 = (const uint64_t)round((UINT32_MAX+1.0) / dRatio);
@@ -112,7 +113,7 @@
uint64_t posFrac64 = 0;
pauseAudio();
- restoreSample(s);
+ unfixSample(s);
/* Nearest-neighbor resampling (no interpolation).
**
@@ -123,58 +124,42 @@
if (newLen > 0)
{
- if (s->typ & 16)
+ if (sample16Bit)
{
- const int16_t *src16 = (const int16_t *)p1;
- int16_t *dst16 = (int16_t *)newPtr;
+ const int16_t *src16 = (const int16_t *)src;
+ int16_t *dst16 = (int16_t *)dst;
- const uint32_t resampleLen = newLen >> 1;
- for (uint32_t i = 0; i < resampleLen; i++)
+ for (uint32_t i = 0; i < newLen; i++)
{
- dst16[i] = src16[posFrac64 >> 32];
+ const uint32_t position = posFrac64 >> 32;
+ dst16[i] = src16[position];
posFrac64 += delta64;
}
}
- else
+ else // 8-bit
{
- const int8_t *src8 = p1;
- int8_t *dst8 = newPtr;
+ const int8_t *src8 = src;
+ int8_t *dst8 = dst;
for (uint32_t i = 0; i < newLen; i++)
{
- dst8[i] = src8[posFrac64 >> 32];
+ const uint32_t position = posFrac64 >> 32;
+ dst8[i] = src8[position];
posFrac64 += delta64;
}
}
}
- free(s->origPek);
+ freeSmpData(s);
+ setSmpDataPtr(s, &sp);
- s->relTon = CLAMP(s->relTon + smpEd_RelReSmp, -48, 71);
- s->len = newLen & mask;
- s->origPek = p2;
- s->pek = s->origPek + SMP_DAT_OFFSET;
- s->repS = (int32_t)(s->repS * dRatio);
- s->repL = (int32_t)(s->repL * dRatio);
- s->repS &= mask;
- s->repL &= mask;
+ s->relativeNote += smpEd_RelReSmp;
+ s->length = newLen;
+ s->loopStart = (int32_t)(s->loopStart * dRatio);
+ s->loopLength = (int32_t)(s->loopLength * dRatio);
- if (s->repS >= s->len)
- s->repS = s->len-1;
+ sanitizeSample(s);
- if (s->repS+s->repL > s->len)
- s->repL = s->len - s->repS;
-
- if (s->typ & 16)
- {
- s->len &= 0xFFFFFFFE;
- s->repS &= 0xFFFFFFFE;
- s->repL &= 0xFFFFFFFE;
- }
-
- if (s->repL <= 0)
- s->typ &= ~3; // disable loop
-
fixSample(s);
resumeAudio();
@@ -223,18 +208,17 @@
vLine(x + w - 3, y + 2, h - 4, PAL_BUTTON1);
hLine(x + 2, y + h - 3, w - 4, PAL_BUTTON1);
- sampleTyp *s = &instr[editor.curInstr]->samp[editor.curSmp];
+ sample_t *s = &instr[editor.curInstr]->smp[editor.curSmp];
- uint32_t mask = (s->typ & 16) ? 0xFFFFFFFE : 0xFFFFFFFF;
double dLenMul = exp2(smpEd_RelReSmp * (1.0 / 12.0));
- double dNewLen = s->len * dLenMul;
+ double dNewLen = s->length * dLenMul;
if (dNewLen > (double)MAX_SAMPLE_LEN)
dNewLen = (double)MAX_SAMPLE_LEN;
textOutShadow(215, 236, PAL_FORGRND, PAL_BUTTON2, "Rel. h.tones");
textOutShadow(215, 250, PAL_FORGRND, PAL_BUTTON2, "New sample size");
- hexOut(361, 250, PAL_FORGRND, (uint32_t)dNewLen & mask, 8);
+ hexOut(361, 250, PAL_FORGRND, (int32_t)dNewLen, 8);
if (smpEd_RelReSmp == 0) sign = ' ';
else if (smpEd_RelReSmp < 0) sign = '-';
@@ -326,7 +310,7 @@
if (editor.curInstr == 0 ||
instr[editor.curInstr] == NULL ||
- instr[editor.curInstr]->samp[editor.curSmp].pek == NULL)
+ instr[editor.curInstr]->smp[editor.curSmp].dataPtr == NULL)
{
return;
}
@@ -425,6 +409,8 @@
static int32_t SDLCALL createEchoThread(void *ptr)
{
+ smpPtr_t sp;
+
if (echo_nEcho < 1)
{
ui.sysReqShown = false;
@@ -431,17 +417,16 @@
return true;
}
- sampleTyp *s = &instr[editor.curInstr]->samp[editor.curSmp];
+ sample_t *s = &instr[editor.curInstr]->smp[editor.curSmp];
- int32_t readLen = s->len;
- int8_t *readPtr = s->pek;
- bool is16Bit = (s->typ & 16) ? true : false;
+ int32_t readLen = s->length;
+ int8_t *readPtr = s->dataPtr;
+ bool sample16Bit = !!(s->flags & SAMPLE_16BIT);
int32_t distance = echo_Distance * 16;
-
double dVolChange = echo_VolChange / 100.0;
// calculate real number of echoes
- double dSmp = is16Bit ? 32768.0 : 128.0;
+ double dSmp = sample16Bit ? 32768.0 : 128.0;
int32_t k = 0;
while (k++ < echo_nEcho && dSmp >= 1.0)
dSmp *= dVolChange;
@@ -458,21 +443,15 @@
if (echo_AddMemory)
{
int64_t tmp64 = (int64_t)distance * (nEchoes - 1);
- if (is16Bit)
- tmp64 <<= 1;
tmp64 += writeLen;
if (tmp64 > MAX_SAMPLE_LEN)
tmp64 = MAX_SAMPLE_LEN;
- writeLen = (int32_t)tmp64;
-
- if (is16Bit)
- writeLen &= 0xFFFFFFFE;
+ writeLen = (uint32_t)tmp64;
}
- int8_t *writePtr = (int8_t *)malloc(writeLen + LOOP_FIX_LEN);
- if (writePtr == NULL)
+ if (!allocateSmpDataPtr(&sp, writeLen, sample16Bit))
{
outOfMemory = true;
setMouseBusy(false);
@@ -481,18 +460,15 @@
}
pauseAudio();
- restoreSample(s);
+ unfixSample(s);
int32_t writeIdx = 0;
- if (is16Bit)
+ if (sample16Bit)
{
const int16_t *readPtr16 = (const int16_t *)readPtr;
- int16_t *writePtr16 = (int16_t *)&writePtr[SMP_DAT_OFFSET];
+ int16_t *writePtr16 = (int16_t *)sp.ptr;
- writeLen >>= 1;
- readLen >>= 1;
-
while (writeIdx < writeLen)
{
double dSmpOut = 0.0;
@@ -513,20 +489,16 @@
break;
}
- // rounding (faster than calling round())
- if (dSmpOut < 0.0) dSmpOut -= 0.5;
- else if (dSmpOut > 0.0) dSmpOut += 0.5;
+ DROUND(dSmpOut);
- int32_t smpOut = (int32_t)dSmpOut;
- CLAMP16(smpOut);
- writePtr16[writeIdx++] = (int16_t)smpOut;
+ int32_t smp32 = (int32_t)dSmpOut;
+ CLAMP16(smp32);
+ writePtr16[writeIdx++] = (int16_t)smp32;
}
-
- writeLen <<= 1;
}
- else
+ else // 8-bit
{
- int8_t *writePtr8 = writePtr + SMP_DAT_OFFSET;
+ int8_t *writePtr8 = sp.ptr;
while (writeIdx < writeLen)
{
double dSmpOut = 0.0;
@@ -547,51 +519,26 @@
break;
}
- // rounding (faster than calling round())
- if (dSmpOut < 0.0) dSmpOut -= 0.5;
- else if (dSmpOut > 0.0) dSmpOut += 0.5;
+ DROUND(dSmpOut);
- int32_t smpOut = (int32_t)dSmpOut;
- if (smpOut < -128) smpOut = -128;
- else if (smpOut > 127) smpOut = 127;
- writePtr8[writeIdx++] = (int8_t)smpOut;
+ int32_t smp32 = (int32_t)dSmpOut;
+ CLAMP8(smp32);
+ writePtr8[writeIdx++] = (int8_t)smp32;
}
}
- free(s->origPek);
+ freeSmpData(s);
+ setSmpDataPtr(s, &sp);
- if (stopThread)
+ if (stopThread) // we stopped before echo was done, realloc length
{
writeLen = writeIdx;
-
- int8_t *newPtr = (int8_t *)realloc(writePtr, writeIdx + LOOP_FIX_LEN);
- if (newPtr != NULL)
- {
- s->origPek = newPtr;
- s->pek = s->origPek + SMP_DAT_OFFSET;
- }
- else
- {
- if (writePtr != NULL)
- free(writePtr);
-
- s->origPek = s->pek = NULL;
- writeLen = 0;
- }
-
+ reallocateSmpData(s, writeLen, sample16Bit);
editor.updateCurSmp = true;
}
- else
- {
- s->origPek = writePtr;
- s->pek = s->origPek + SMP_DAT_OFFSET;
- }
- if (is16Bit)
- writeLen &= 0xFFFFFFFE;
+ s->length = writeLen;
- s->len = writeLen;
-
fixSample(s);
resumeAudio();
@@ -651,7 +598,7 @@
charOut(315 + (3 * 7), 226, PAL_FORGRND, '0' + (echo_nEcho % 10));
assert(echo_Distance <= 0x4000);
- hexOut(308, 240, PAL_FORGRND, (uint32_t)echo_Distance << 4, 5);
+ hexOut(308, 240, PAL_FORGRND, echo_Distance << 4, 5);
assert(echo_VolChange <= 100);
textOutFixed(312, 254, PAL_FORGRND, PAL_BUTTONS, dec3StrTab[echo_VolChange]);
@@ -816,11 +763,9 @@
void pbSampleEcho(void)
{
- uint16_t i;
-
if (editor.curInstr == 0 ||
instr[editor.curInstr] == NULL ||
- instr[editor.curInstr]->samp[editor.curSmp].pek == NULL)
+ instr[editor.curInstr]->smp[editor.curSmp].dataPtr == NULL)
{
return;
}
@@ -845,15 +790,15 @@
setScrollBarPos(1, echo_Distance, false);
setScrollBarPos(2, echo_VolChange, false);
drawCheckBox(0);
- for (i = 0; i < 8; i++) drawPushButton(i);
- for (i = 0; i < 3; i++) drawScrollBar(i);
+ for (uint16_t i = 0; i < 8; i++) drawPushButton(i);
+ for (uint16_t i = 0; i < 3; i++) drawScrollBar(i);
flipFrame();
}
hideCheckBox(0);
- for (i = 0; i < 8; i++) hidePushButton(i);
- for (i = 0; i < 3; i++) hideScrollBar(i);
+ for (uint16_t i = 0; i < 8; i++) hidePushButton(i);
+ for (uint16_t i = 0; i < 3; i++) hideScrollBar(i);
windowClose(echo_AddMemory ? false : true);
@@ -863,16 +808,21 @@
static int32_t SDLCALL mixThread(void *ptr)
{
- int8_t *destPtr, *mixPtr;
- uint8_t mixTyp, destTyp;
- int32_t destLen, mixLen;
+ smpPtr_t sp;
- int16_t destIns = editor.curInstr;
- int16_t destSmp = editor.curSmp;
+ int8_t *dstPtr, *mixPtr;
+ uint8_t mixFlags, dstFlags;
+ int32_t dstLen, mixLen;
+
+ int16_t dstIns = editor.curInstr;
+ int16_t dstSmp = editor.curSmp;
int16_t mixIns = editor.srcInstr;
int16_t mixSmp = editor.srcSmp;
- if (destIns == mixIns && destSmp == mixSmp)
+ sample_t *s = &instr[dstIns]->smp[dstSmp];
+ sample_t *sSrc = &instr[mixIns]->smp[mixSmp];
+
+ if (dstIns == mixIns && dstSmp == mixSmp)
{
setMouseBusy(false);
ui.sysReqShown = false;
@@ -883,49 +833,45 @@
{
mixLen = 0;
mixPtr = NULL;
- mixTyp = 0;
+ mixFlags = 0;
}
else
{
- mixLen = instr[mixIns]->samp[mixSmp].len;
- mixPtr = instr[mixIns]->samp[mixSmp].pek;
- mixTyp = instr[mixIns]->samp[mixSmp].typ;
+ mixLen = sSrc->length;
+ mixPtr = sSrc->dataPtr;
+ mixFlags = sSrc->flags;
if (mixPtr == NULL)
{
mixLen = 0;
- mixTyp = 0;
+ mixFlags = 0;
}
}
- if (instr[destIns] == NULL)
+ if (instr[dstIns] == NULL)
{
- destLen = 0;
- destPtr = NULL;
- destTyp = 0;
+ dstLen = 0;
+ dstPtr = NULL;
+ dstFlags = 0;
}
else
{
- destLen = instr[destIns]->samp[destSmp].len;
- destPtr = instr[destIns]->samp[destSmp].pek;
- destTyp = instr[destIns]->samp[destSmp].typ;
+ dstLen = s->length;
+ dstPtr = s->dataPtr;
+ dstFlags = s->flags;
- if (destPtr == NULL)
+ if (dstPtr == NULL)
{
- destLen = 0;
- destTyp = 0;
+ dstLen = 0;
+ dstFlags = 0;
}
}
- bool src16Bits = (mixTyp >> 4) & 1;
- bool dst16Bits = (destTyp >> 4) & 1;
+ bool src16Bits = !!(mixFlags & SAMPLE_16BIT);
+ bool dst16Bits = !!(dstFlags & SAMPLE_16BIT);
- int32_t mix8Size = src16Bits ? (mixLen >> 1) : mixLen;
- int32_t dest8Size = dst16Bits ? (destLen >> 1) : destLen;
- int32_t max8Size = (dest8Size > mix8Size) ? dest8Size : mix8Size;
- int32_t maxLen = dst16Bits ? (max8Size << 1) : max8Size;
-
- if (maxLen <= 0)
+ int32_t maxLen = (dstLen > mixLen) ? dstLen : mixLen;
+ if (maxLen == 0)
{
setMouseBusy(false);
ui.sysReqShown = false;
@@ -932,8 +878,7 @@
return true;
}
- int8_t *p = (int8_t *)calloc(maxLen + LOOP_FIX_LEN, sizeof (int8_t));
- if (p == NULL)
+ if (!allocateSmpDataPtr(&sp, maxLen, dst16Bits))
{
outOfMemory = true;
setMouseBusy(false);
@@ -940,8 +885,9 @@
ui.sysReqShown = false;
return true;
}
+ memset(sp.ptr, 0, maxLen);
- if (instr[destIns] == NULL && !allocateInstr(destIns))
+ if (instr[dstIns] == NULL && !allocateInstr(dstIns))
{
outOfMemory = true;
setMouseBusy(false);
@@ -950,65 +896,38 @@
}
pauseAudio();
+ unfixSample(s);
- restoreSample(&instr[destIns]->samp[destSmp]);
-
- // restore source sample
+ // unfix source sample
if (instr[mixIns] != NULL)
- restoreSample(&instr[mixIns]->samp[mixSmp]);
+ unfixSample(sSrc);
const double dAmp1 = mix_Balance / 100.0;
const double dAmp2 = 1.0 - dAmp1;
+ const double dSmp1ScaleMul = src16Bits ? (1.0 / 32768.0) : (1.0 / 128.0);
+ const double dSmp2ScaleMul = dst16Bits ? (1.0 / 32768.0) : (1.0 / 128.0);
+ const double dNormalizeMul = dst16Bits ? 32768.0 : 128.0;
- int8_t *destPek = p + SMP_DAT_OFFSET;
- for (int32_t i = 0; i < max8Size; i++)
+ for (int32_t i = 0; i < maxLen; i++)
{
- int32_t index16 = i << 1;
+ double dSmp1 = (i >= mixLen) ? 0.0 : (getSampleValue(mixPtr, i, src16Bits) * dSmp1ScaleMul); // -1.0 .. 0.999inf
+ double dSmp2 = (i >= dstLen) ? 0.0 : (getSampleValue(dstPtr, i, dst16Bits) * dSmp2ScaleMul); // -1.0 .. 0.999inf
- int32_t smp1 = (i >= mix8Size) ? 0 : getSampleValue(mixPtr, mixTyp, src16Bits ? index16 : i);
- int32_t smp2 = (i >= dest8Size) ? 0 : getSampleValue(destPtr, destTyp, dst16Bits ? index16 : i);
-
- if (!src16Bits) smp1 <<= 8;
- if (!dst16Bits) smp2 <<= 8;
-
- double dSmp = (smp1 * dAmp1) + (smp2 * dAmp2);
- if (!dst16Bits)
- dSmp *= 1.0 / 256.0;
-
- // rounding (faster than calling round())
- if (dSmp < 0.0) dSmp -= 0.5;
- else if (dSmp > 0.0) dSmp += 0.5;
-
- int32_t smp32 = (int32_t)dSmp;
- if (dst16Bits)
- {
- CLAMP16(smp32);
- }
- else
- {
- if (smp32 < -128) smp32 = -128;
- else if (smp32 > 127) smp32 = 127;
- }
-
- putSampleValue(destPek, destTyp, dst16Bits ? index16 : i, (int16_t)smp32);
+ const double dSmp = ((dSmp1 * dAmp1) + (dSmp2 * dAmp2)) * dNormalizeMul;
+ putSampleValue(sp.ptr, i, dSmp, dst16Bits);
}
- if (instr[destIns]->samp[destSmp].origPek != NULL)
- free(instr[destIns]->samp[destSmp].origPek);
+ freeSmpData(s);
+ setSmpDataPtr(s, &sp);
- instr[destIns]->samp[destSmp].origPek = p;
- instr[destIns]->samp[destSmp].pek = instr[destIns]->samp[destSmp].origPek + SMP_DAT_OFFSET;
- instr[destIns]->samp[destSmp].len = maxLen;
- instr[destIns]->samp[destSmp].typ = destTyp;
+ s->length = maxLen;
+ s->flags = dstFlags;
- if (dst16Bits)
- instr[destIns]->samp[destSmp].len &= 0xFFFFFFFE;
+ fixSample(s);
- fixSample(&instr[destIns]->samp[destSmp]);
-
- // fix source sample
+ // re-fix source sample again
if (instr[mixIns] != NULL)
- fixSample(&instr[mixIns]->samp[mixSmp]);
+ fixSample(sSrc);
resumeAudio();
@@ -1187,64 +1106,60 @@
static void sbSetStartVolPos(uint32_t pos)
{
- int16_t val = (int16_t)(pos - 500);
- if (val != vol_StartVol)
+ int32_t val = (int32_t)(pos - 200);
+ if (val != (int32_t)dVol_StartVol)
{
if (ABS(val) < 10) val = 0;
else if (ABS(val - 100) < 10) val = 100;
- else if (ABS(val - 200) < 10) val = 200;
- else if (ABS(val - 300) < 10) val = 300;
- else if (ABS(val - 400) < 10) val = 400;
else if (ABS(val + 100) < 10) val = -100;
- else if (ABS(val + 200) < 10) val = -200;
- else if (ABS(val + 300) < 10) val = -300;
- else if (ABS(val + 400) < 10) val = -400;
- vol_StartVol = val;
+ dVol_StartVol = (double)val;
}
}
static void sbSetEndVolPos(uint32_t pos)
{
- int16_t val = (int16_t)(pos - 500);
- if (val != vol_EndVol)
+ int32_t val = (int32_t)(pos - 200);
+ if (val != (int32_t)dVol_EndVol)
{
if (ABS(val) < 10) val = 0;
else if (ABS(val - 100) < 10) val = 100;
- else if (ABS(val - 200) < 10) val = 200;
- else if (ABS(val - 300) < 10) val = 300;
- else if (ABS(val - 400) < 10) val = 400;
else if (ABS(val + 100) < 10) val = -100;
- else if (ABS(val + 200) < 10) val = -200;
- else if (ABS(val + 300) < 10) val = -300;
- else if (ABS(val + 400) < 10) val = -400;
- vol_EndVol = val;
+ dVol_EndVol = val;
}
}
static void pbSampStartVolDown(void)
{
- if (vol_StartVol > -500)
- vol_StartVol--;
+ if (dVol_StartVol > -200.0)
+ dVol_StartVol -= 1.0;
+
+ dVol_StartVol = floor(dVol_StartVol);
}
static void pbSampStartVolUp(void)
{
- if (vol_StartVol < 500)
- vol_StartVol++;
+ if (dVol_StartVol < 200.0)
+ dVol_StartVol += 1.0;
+
+ dVol_StartVol = floor(dVol_StartVol);
}
static void pbSampEndVolDown(void)
{
- if (vol_EndVol > -500)
- vol_EndVol--;
+ if (dVol_EndVol > -200.0)
+ dVol_EndVol -= 1.0;
+
+ dVol_EndVol = floor(dVol_EndVol);
}
static void pbSampEndVolUp(void)
{
- if (vol_EndVol < 500)
- vol_EndVol++;
+ if (dVol_EndVol < 200.0)
+ dVol_EndVol += 1.0;
+
+ dVol_EndVol = floor(dVol_EndVol);
}
static int32_t SDLCALL applyVolumeThread(void *ptr)
@@ -1254,7 +1169,7 @@
if (instr[editor.curInstr] == NULL)
goto applyVolumeExit;
- sampleTyp *s = &instr[editor.curInstr]->samp[editor.curSmp];
+ sample_t *s = &instr[editor.curInstr]->smp[editor.curSmp];
if (smpEd_Rx1 < smpEd_Rx2)
{
@@ -1261,8 +1176,8 @@
x1 = smpEd_Rx1;
x2 = smpEd_Rx2;
- if (x2 > s->len)
- x2 = s->len;
+ if (x2 > s->length)
+ x2 = s->length;
if (x1 < 0)
x1 = 0;
@@ -1269,69 +1184,79 @@
if (x2 <= x1)
goto applyVolumeExit;
-
- if (s->typ & 16)
- {
- x1 &= 0xFFFFFFFE;
- x2 &= 0xFFFFFFFE;
- }
}
else
{
+ // no mark, operate on whole sample
x1 = 0;
- x2 = s->len;
+ x2 = s->length;
}
- if (s->typ & 16)
- {
- x1 >>= 1;
- x2 >>= 1;
- }
-
const int32_t len = x2 - x1;
if (len <= 0)
goto applyVolumeExit;
- const double dVol1 = vol_StartVol / 100.0;
- const double dVol2 = vol_EndVol / 100.0;
- const double dPosMul = (dVol2 - dVol1) / len;
+ bool mustInterpolate = (dVol_StartVol != dVol_EndVol);
+ const double dVol = dVol_StartVol / 100.0;
+ const double dPosMul = ((dVol_EndVol / 100.0) - dVol) / len;
pauseAudio();
- restoreSample(s);
- if (s->typ & 16)
+ unfixSample(s);
+ if (s->flags & SAMPLE_16BIT)
{
- int16_t *ptr16 = (int16_t *)s->pek + x1;
- for (int32_t i = 0; i < len; i++)
+ int16_t *ptr16 = (int16_t *)s->dataPtr + x1;
+ if (mustInterpolate)
{
- const double dAmp = dVol1 + (i * dPosMul); // linear interpolation
+ for (int32_t i = 0; i < len; i++)
+ {
+ double dSmp = (int32_t)ptr16[i] * (dVol + (i * dPosMul)); // linear interpolation
+ DROUND(dSmp);
- double dSmp = ptr16[i] * dAmp;
+ int32_t smp32 = (int32_t)dSmp;
+ CLAMP16(smp32);
+ ptr16[i] = (int16_t)smp32;
+ }
- // rounding (faster than calling round())
- if (dSmp < 0.0) dSmp -= 0.5;
- else if (dSmp > 0.0) dSmp += 0.5;
+ }
+ else // no interpolation needed
+ {
+ for (int32_t i = 0; i < len; i++)
+ {
+ double dSmp = (int32_t)ptr16[i] * dVol;
+ DROUND(dSmp);
- int32_t amp32 = (int32_t)dSmp;
- CLAMP16(amp32);
- ptr16[i] = (int16_t)amp32;
+ int32_t smp32 = (int32_t)dSmp;
+ CLAMP16(smp32);
+ ptr16[i] = (int16_t)smp32;
+ }
}
}
- else
+ else // 8-bit sample
{
- int8_t *ptr8 = s->pek + x1;
- for (int32_t i = 0; i < len; i++)
+ int8_t *ptr8 = s->dataPtr + x1;
+ if (mustInterpolate)
{
- const double dAmp = dVol1 + (i * dPosMul); // linear interpolation
+ for (int32_t i = 0; i < len; i++)
+ {
+ double dSmp = (int32_t)ptr8[i] * (dVol + (i * dPosMul)); // linear interpolation
+ DROUND(dSmp);
- double dSmp = ptr8[i] * dAmp;
+ int32_t smp32 = (int32_t)dSmp;
+ CLAMP8(smp32);
+ ptr8[i] = (int8_t)smp32;
+ }
+ }
+ else // no interpolation needed
+ {
+ for (int32_t i = 0; i < len; i++)
+ {
+ double dSmp = (int32_t)ptr8[i] * dVol;
+ DROUND(dSmp);
- // rounding (faster than calling round())
- if (dSmp < 0.0) dSmp -= 0.5;
- else if (dSmp > 0.0) dSmp += 0.5;
-
- int32_t amp32 = (int32_t)dSmp;
- CLAMP8(amp32);
- ptr8[i] = (int8_t)amp32;
+ int32_t smp32 = (int32_t)dSmp;
+ CLAMP8(smp32);
+ ptr8[i] = (int8_t)smp32;
+ }
}
}
fixSample(s);
@@ -1350,7 +1275,7 @@
static void pbApplyVolume(void)
{
- if (vol_StartVol == 100 && vol_EndVol == 100)
+ if (dVol_StartVol == 100.0 && dVol_EndVol == 100.0)
{
ui.sysReqShown = false;
return; // no volume change to be done
@@ -1374,7 +1299,7 @@
if (instr[editor.curInstr] == NULL)
goto getScaleExit;
- sampleTyp *s = &instr[editor.curInstr]->samp[editor.curSmp];
+ sample_t *s = &instr[editor.curInstr]->smp[editor.curSmp];
if (smpEd_Rx1 < smpEd_Rx2)
{
@@ -1381,8 +1306,8 @@
x1 = smpEd_Rx1;
x2 = smpEd_Rx2;
- if (x2 > s->len)
- x2 = s->len;
+ if (x2 > s->length)
+ x2 = s->length;
if (x1 < 0)
x1 = 0;
@@ -1389,37 +1314,38 @@
if (x2 <= x1)
goto getScaleExit;
-
- if (s->typ & 16)
- {
- x1 &= 0xFFFFFFFE;
- x2 &= 0xFFFFFFFE;
- }
}
else
{
// no sample marking, operate on the whole sample
x1 = 0;
- x2 = s->len;
+ x2 = s->length;
}
uint32_t len = x2 - x1;
- if (s->typ & 16)
- len >>= 1;
-
if (len <= 0)
{
- vol_StartVol = 0;
- vol_EndVol = 0;
+ dVol_StartVol = dVol_EndVol = 100.0;
goto getScaleExit;
}
- restoreSample(s);
+ double dVolChange = 100.0;
+ /* If sample is looped and the loopEnd point is inside the marked range,
+ ** we need to unfix the fixed interpolation sample before scanning,
+ ** and fix it again after we're done.
+ */
+ bool hasLoop = GET_LOOPTYPE(s->flags) != LOOP_OFF;
+ const int32_t loopEnd = s->loopStart + s->loopLength;
+ bool fixedSampleInRange = hasLoop && (x1 <= loopEnd) && (x2 >= loopEnd);
+
+ if (fixedSampleInRange)
+ unfixSample(s);
+
int32_t maxAmp = 0;
- if (s->typ & 16)
+ if (s->flags & SAMPLE_16BIT)
{
- const int16_t *ptr16 = (const int16_t *)&s->pek[x1];
+ const int16_t *ptr16 = (const int16_t *)s->dataPtr + x1;
for (uint32_t i = 0; i < len; i++)
{
const int32_t absSmp = ABS(ptr16[i]);
@@ -1426,10 +1352,13 @@
if (absSmp > maxAmp)
maxAmp = absSmp;
}
+
+ if (maxAmp > 0)
+ dVolChange = (32767.0 / maxAmp) * 100.0;
}
- else
+ else // 8-bit
{
- const int8_t *ptr8 = (const int8_t *)&s->pek[x1];
+ const int8_t *ptr8 = (const int8_t *)&s->dataPtr[x1];
for (uint32_t i = 0; i < len; i++)
{
const int32_t absSmp = ABS(ptr8[i]);
@@ -1437,25 +1366,17 @@
maxAmp = absSmp;
}
- maxAmp <<= 8;
+ if (maxAmp > 0)
+ dVolChange = (127.0 / maxAmp) * 100.0;
}
- fixSample(s);
+ if (fixedSampleInRange)
+ fixSample(s);
- if (maxAmp <= 0)
- {
- vol_StartVol = 0;
- vol_EndVol = 0;
- }
- else
- {
- int32_t vol = (100 * 32768) / maxAmp;
- if (vol > 500)
- vol = 500;
+ if (dVolChange < 100.0) // yes, this can happen...
+ dVolChange = 100.0;
- vol_StartVol = (int16_t)vol;
- vol_EndVol = (int16_t)vol;
- }
+ dVol_StartVol = dVol_EndVol = dVolChange;
getScaleExit:
setMouseBusy(false);
@@ -1484,7 +1405,7 @@
const int16_t y = 230;
const int16_t w = 301;
const int16_t h = 52;
- uint16_t val;
+ uint32_t val;
// main fill
fillRect(x + 1, y + 1, w - 2, h - 2, PAL_BUTTONS);
@@ -1506,52 +1427,75 @@
charOutShadow(282, 236, PAL_FORGRND, PAL_BUTTON2, '%');
charOutShadow(282, 250, PAL_FORGRND, PAL_BUTTON2, '%');
- if (vol_StartVol == 0) sign = ' ';
- else if (vol_StartVol < 0) sign = '-';
- else sign = '+';
+ const int32_t startVol = (int32_t)dVol_StartVol;
+ const int32_t endVol = (int32_t)dVol_EndVol;
- val = ABS(vol_StartVol);
- if (val > 99)
+ if (startVol > 200)
{
- charOut(253, 236, PAL_FORGRND, sign);
- charOut(260, 236, PAL_FORGRND, '0' + (char)(val / 100));
- charOut(267, 236, PAL_FORGRND, '0' + ((val / 10) % 10));
- charOut(274, 236, PAL_FORGRND, '0' + (val % 10));
+ charOut(253, 236, PAL_FORGRND, '>');
+ charOut(260, 236, PAL_FORGRND, '2');
+ charOut(267, 236, PAL_FORGRND, '0');
+ charOut(274, 236, PAL_FORGRND, '0');
}
- else if (val > 9)
- {
- charOut(260, 236, PAL_FORGRND, sign);
- charOut(267, 236, PAL_FORGRND, '0' + (char)(val / 10));
- charOut(274, 236, PAL_FORGRND, '0' + (val % 10));
- }
else
{
- charOut(267, 236, PAL_FORGRND, sign);
- charOut(274, 236, PAL_FORGRND, '0' + (char)val);
+ if (startVol == 0) sign = ' ';
+ else if (startVol < 0) sign = '-';
+ else sign = '+';
+
+ val = ABS(startVol);
+ if (val > 99)
+ {
+ charOut(253, 236, PAL_FORGRND, sign);
+ charOut(260, 236, PAL_FORGRND, '0' + (char)(val / 100));
+ charOut(267, 236, PAL_FORGRND, '0' + ((val / 10) % 10));
+ charOut(274, 236, PAL_FORGRND, '0' + (val % 10));
+ }
+ else if (val > 9)
+ {
+ charOut(260, 236, PAL_FORGRND, sign);
+ charOut(267, 236, PAL_FORGRND, '0' + (char)(val / 10));
+ charOut(274, 236, PAL_FORGRND, '0' + (val % 10));
+ }
+ else
+ {
+ charOut(267, 236, PAL_FORGRND, sign);
+ charOut(274, 236, PAL_FORGRND, '0' + (char)val);
+ }
}
- if (vol_EndVol == 0) sign = ' ';
- else if (vol_EndVol < 0) sign = '-';
- else sign = '+';
-
- val = ABS(vol_EndVol);
- if (val > 99)
+ if (endVol > 200)
{
- charOut(253, 250, PAL_FORGRND, sign);
- charOut(260, 250, PAL_FORGRND, '0' + (char)(val / 100));
- charOut(267, 250, PAL_FORGRND, '0' + ((val / 10) % 10));
- charOut(274, 250, PAL_FORGRND, '0' + (val % 10));
+ charOut(253, 250, PAL_FORGRND, '>');
+ charOut(260, 250, PAL_FORGRND, '2');
+ charOut(267, 250, PAL_FORGRND, '0');
+ charOut(274, 250, PAL_FORGRND, '0');
}
- else if (val > 9)
- {
- charOut(260, 250, PAL_FORGRND, sign);
- charOut(267, 250, PAL_FORGRND, '0' + (char)(val / 10));
- charOut(274, 250, PAL_FORGRND, '0' + (val % 10));
- }
else
{
- charOut(267, 250, PAL_FORGRND, sign);
- charOut(274, 250, PAL_FORGRND, '0' + (char)val);
+ if (endVol == 0) sign = ' ';
+ else if (endVol < 0) sign = '-';
+ else sign = '+';
+
+ val = ABS(endVol);
+ if (val > 99)
+ {
+ charOut(253, 250, PAL_FORGRND, sign);
+ charOut(260, 250, PAL_FORGRND, '0' + (char)(val / 100));
+ charOut(267, 250, PAL_FORGRND, '0' + ((val / 10) % 10));
+ charOut(274, 250, PAL_FORGRND, '0' + (val % 10));
+ }
+ else if (val > 9)
+ {
+ charOut(260, 250, PAL_FORGRND, sign);
+ charOut(267, 250, PAL_FORGRND, '0' + (char)(val / 10));
+ charOut(274, 250, PAL_FORGRND, '0' + (val % 10));
+ }
+ else
+ {
+ charOut(267, 250, PAL_FORGRND, sign);
+ charOut(274, 250, PAL_FORGRND, '0' + (char)val);
+ }
}
}
@@ -1653,8 +1597,8 @@
s->callbackFunc = sbSetStartVolPos;
s->visible = true;
setScrollBarPageLength(0, 1);
- setScrollBarEnd(0, 500 * 2);
- setScrollBarPos(0, 500, false);
+ setScrollBarEnd(0, 200 * 2);
+ setScrollBarPos(0, 200, false);
// volume end scrollbar
s = &scrollBars[1];
@@ -1666,8 +1610,8 @@
s->callbackFunc = sbSetEndVolPos;
s->visible = true;
setScrollBarPageLength(1, 1);
- setScrollBarEnd(1, 500 * 2);
- setScrollBarPos(1, 500, false);
+ setScrollBarEnd(1, 200 * 2);
+ setScrollBarPos(1, 200, false);
}
void pbSampleVolume(void)
@@ -1676,7 +1620,7 @@
if (editor.curInstr == 0 ||
instr[editor.curInstr] == NULL ||
- instr[editor.curInstr]->samp[editor.curSmp].pek == NULL)
+ instr[editor.curInstr]->smp[editor.curSmp].dataPtr == NULL)
{
return;
}
@@ -1701,8 +1645,12 @@
if (ui.setMouseIdle) mouseAnimOff();
drawSampleVolumeBox();
- setScrollBarPos(0, 500 + vol_StartVol, false);
- setScrollBarPos(1, 500 + vol_EndVol, false);
+
+ const int32_t startVol = (int32_t)dVol_StartVol;
+ const int32_t endVol = (int32_t)dVol_EndVol;
+
+ setScrollBarPos(0, 200 + startVol, false);
+ setScrollBarPos(1, 200 + endVol, false);
for (i = 0; i < 7; i++) drawPushButton(i);
for (i = 0; i < 2; i++) drawScrollBar(i);
--- a/src/ft2_sample_loader.c
+++ b/src/ft2_sample_loader.c
@@ -16,6 +16,10 @@
#include "ft2_diskop.h"
#include "ft2_structs.h"
+#ifdef HAS_LIBFLAC
+bool loadFLAC(FILE *f, uint32_t filesize);
+#endif
+
bool loadAIFF(FILE *f, uint32_t filesize);
bool loadIFF(FILE *f, uint32_t filesize);
bool loadRAW(FILE *f, uint32_t filesize);
@@ -26,7 +30,8 @@
FORMAT_UNKNOWN = 0,
FORMAT_IFF = 1,
FORMAT_WAV = 2,
- FORMAT_AIFF = 3
+ FORMAT_AIFF = 3,
+ FORMAT_FLAC = 4
};
// file extensions accepted by Disk Op. in sample mode
@@ -33,7 +38,7 @@
char *supportedSmpExtensions[] =
{
"iff", "raw", "wav", "snd", "smp", "sam", "aif", "pat",
- "aiff",
+ "aiff","flac",
// IMPORTANT: Remember comma after last entry above
"END_OF_LIST" // do NOT move, remove or edit this line!
@@ -43,13 +48,13 @@
bool loadAsInstrFlag, smpFilenameSet;
char *smpFilename;
uint8_t sampleSlot;
-sampleTyp tmpSmp;
+sample_t tmpSmp;
// --------------------------
static volatile bool sampleIsLoading;
static SDL_Thread *thread;
-static void freeTmpSample(sampleTyp *s);
+static void freeTmpSample(sample_t *s);
// Crude sample detection routine. These aren't always accurate detections!
static int8_t detectSample(FILE *f)
@@ -62,6 +67,9 @@
fread(D, 1, sizeof (D), f);
fseek(f, oldPos, SEEK_SET);
+ if (!memcmp("fLaC", &D[0], 4)) // XXX: Kinda lousy detection...
+ return FORMAT_FLAC;
+
if (!memcmp("FORM", &D[0], 4) && (!memcmp("8SVX", &D[8], 4) || !memcmp("16SV", &D[8], 4)))
return FORMAT_IFF;
@@ -105,6 +113,16 @@
rewind(f);
switch (format)
{
+ case FORMAT_FLAC:
+ {
+#ifdef HAS_LIBFLAC
+ sampleLoaded = loadFLAC(f, filesize);
+#else
+ loaderMsgBox("Can't load sample: Program is not compiled with FLAC support!");
+#endif
+ }
+ break;
+
case FORMAT_IFF: sampleLoaded = loadIFF(f, filesize); break;
case FORMAT_WAV: sampleLoaded = loadWAV(f, filesize); break;
case FORMAT_AIFF: sampleLoaded = loadAIFF(f, filesize); break;
@@ -116,7 +134,7 @@
goto loadError;
// sample loaded successfully!
-
+
if (!smpFilenameSet) // if we didn't set a custom sample name in the loader, set it to its filename
{
char *tmpFilename = unicharToCp437(editor.tmpFilenameU, true);
@@ -166,10 +184,13 @@
goto loadError;
}
- sampleTyp *s = &instr[editor.curInstr]->samp[sampleSlot];
+ sample_t *s = &instr[editor.curInstr]->smp[sampleSlot];
freeSample(editor.curInstr, sampleSlot);
- memcpy(s, &tmpSmp, sizeof (sampleTyp));
+ memcpy(s, &tmpSmp, sizeof (sample_t));
+
+ sanitizeSample(s);
+
fixSample(s); // prepares sample for branchless resampling interpolation
fixInstrAndSampleNames(editor.curInstr);
@@ -191,15 +212,9 @@
(void)ptr;
}
-static void freeTmpSample(sampleTyp *s)
+static void freeTmpSample(sample_t *s)
{
- if (s->origPek != NULL)
- {
- free(s->origPek);
- s->origPek = NULL;
- }
-
- s->pek = NULL;
+ freeSmpData(s);
}
void removeSampleIsLoadingFlag(void)
--- a/src/ft2_sample_loader.h
+++ b/src/ft2_sample_loader.h
@@ -23,7 +23,7 @@
extern bool loadAsInstrFlag, smpFilenameSet;
extern char *smpFilename;
extern uint8_t sampleSlot;
-extern sampleTyp tmpSmp;
+extern sample_t tmpSmp;
// --------------------------
// file extensions accepted by Disk Op. in sample mode
--- a/src/ft2_sample_saver.c
+++ b/src/ft2_sample_saver.c
@@ -52,38 +52,58 @@
static SDL_Thread *thread;
// restores modified interpolation tap samples after loopEnd (for .RAW/.IFF/.WAV samples after save)
-static void fileRestoreFixedSampleData(UNICHAR *filenameU, uint32_t sampleDataOffset, sampleTyp *s)
+static void fileRestoreFixedSampleData(UNICHAR *filenameU, uint32_t sampleDataOffset, sample_t *s)
{
- if (!s->fixed)
+ if (!s->isFixed)
return; // nothing to restore
- FILE *f = UNICHAR_FOPEN(filenameU, "r+"); // open in read+update mode
- if (f == NULL)
- return;
+ int32_t sampleFixPos = s->fixedPos;
+ int32_t sampleFixOffset = 0;
+ int32_t samplesToWrite = SINC_RIGHT_TAPS;
- const bool sample16Bit = (s->typ & 16) ? true : false;
+ if (saveRangeFlag)
+ {
+ const int32_t markStart = getSampleRangeStart();
+ const int32_t markEnd = getSampleRangeEnd();
- uint32_t fixedPos = s->fixedPos;
- if (sample16Bit)
- fixedPos *= 2;
+ if (markStart > sampleFixPos+SINC_RIGHT_TAPS || markEnd < sampleFixPos)
+ return; // nothing to do here
- if (fixedPos >= (uint32_t)s->len)
+ if (markStart > sampleFixPos)
+ {
+ sampleFixOffset += markStart-sampleFixPos;
+ samplesToWrite -= markStart-sampleFixPos;
+ }
+
+ sampleFixPos -= markStart;
+
+ if (sampleFixPos + samplesToWrite > markEnd)
+ samplesToWrite = markEnd - sampleFixPos;
+
+ if (samplesToWrite < 0 || samplesToWrite > SINC_RIGHT_TAPS || sampleFixPos < 0 || sampleFixOffset < 0 || sampleFixOffset >= SINC_RIGHT_TAPS)
+ return;
+
+ }
+
+ FILE* f = UNICHAR_FOPEN(filenameU, "r+"); // open in read+update mode
+ if (f == NULL)
return;
- uint32_t bytesToWrite = SINC_RIGHT_TAPS * (sample16Bit+1);
- if (fixedPos+bytesToWrite > (uint32_t)s->len)
- bytesToWrite = s->len - fixedPos;
+ bool sample16Bit = !!(s->flags & SAMPLE_16BIT);
+ if (sample16Bit)
+ fseek(f, sampleDataOffset + (sampleFixPos * 2), SEEK_SET);
+ else
+ fseek(f, sampleDataOffset + sampleFixPos, SEEK_SET);
- fseek(f, sampleDataOffset+fixedPos, SEEK_SET);
if (sample16Bit)
{
- fwrite(s->fixedSmp, sizeof (int16_t), bytesToWrite / 2, f);
+ fwrite(&s->fixedSmp[sampleFixOffset], sizeof (int16_t), samplesToWrite, f);
}
else
{
- for (uint32_t i = 0; i < bytesToWrite; i++)
+ for (int32_t i = 0; i < samplesToWrite; i++)
{
- int8_t fixedSmp = (int8_t)s->fixedSmp[i];
+ int8_t fixedSmp = (int8_t)s->fixedSmp[sampleFixOffset+i];
if (editor.sampleSaveMode == SMP_SAVE_MODE_WAV) // on 8-bit WAVs the sample data is unsigned
fixedSmp ^= 0x80; // signed -> unsigned
@@ -99,23 +119,25 @@
int8_t *samplePtr;
uint32_t sampleLen;
- instrTyp *ins = instr[editor.curInstr];
- if (ins == NULL || ins->samp[editor.curSmp].pek == NULL || ins->samp[editor.curSmp].len == 0)
+ instr_t *ins = instr[editor.curInstr];
+ if (ins == NULL || ins->smp[editor.curSmp].dataPtr == NULL || ins->smp[editor.curSmp].length == 0)
{
okBoxThreadSafe(0, "System message", "The sample is empty!");
return false;
}
- sampleTyp *smp = &instr[editor.curInstr]->samp[editor.curSmp];
+ sample_t *smp = &instr[editor.curInstr]->smp[editor.curSmp];
+ bool sample16Bit = !!(smp->flags & SAMPLE_16BIT);
+
if (saveRangedData)
{
- samplePtr = &smp->pek[getSampleRangeStart()];
+ samplePtr = &smp->dataPtr[getSampleRangeStart() << sample16Bit];
sampleLen = getSampleRangeLength();
}
else
{
- sampleLen = smp->len;
- samplePtr = smp->pek;
+ sampleLen = smp->length;
+ samplePtr = smp->dataPtr;
}
FILE *f = UNICHAR_FOPEN(filenameU, "wb");
@@ -135,8 +157,8 @@
fclose(f);
// restore modified interpolation tap samples after loopEnd
- const bool loopEnabled = (smp->typ & 3) ? true : false;
- if (loopEnabled && smp->len > smp->repS+smp->repL)
+ bool loopEnabled = GET_LOOPTYPE(smp->flags) != LOOP_OFF;
+ if (loopEnabled && smp->length > smp->loopStart+smp->loopLength)
fileRestoreFixedSampleData(filenameU, 0, smp);
editor.diskOpReadDir = true; // force diskop re-read
@@ -181,14 +203,14 @@
int8_t *samplePtr;
uint32_t sampleLen, smpNameLen, chunkLen;
- instrTyp *ins = instr[editor.curInstr];
- if (ins == NULL || ins->samp[editor.curSmp].pek == NULL || ins->samp[editor.curSmp].len == 0)
+ instr_t *ins = instr[editor.curInstr];
+ if (ins == NULL || ins->smp[editor.curSmp].dataPtr == NULL || ins->smp[editor.curSmp].length == 0)
{
okBoxThreadSafe(0, "System message", "The sample is empty!");
return false;
}
- sampleTyp *smp = &instr[editor.curInstr]->samp[editor.curSmp];
+ sample_t *smp = &instr[editor.curInstr]->smp[editor.curSmp];
FILE *f = UNICHAR_FOPEN(filenameU, "wb");
if (f == NULL)
@@ -197,28 +219,30 @@
return false;
}
+ bool sample16Bit = !!(smp->flags & SAMPLE_16BIT);
+
if (saveRangedData)
{
- samplePtr = &smp->pek[getSampleRangeStart()];
+ samplePtr = &smp->dataPtr[getSampleRangeStart() << sample16Bit];
sampleLen = getSampleRangeLength();
}
else
{
- sampleLen = smp->len;
- samplePtr = smp->pek;
+ sampleLen = smp->length;
+ samplePtr = smp->dataPtr;
}
// "FORM" chunk
iffWriteChunkHeader(f, "FORM", 0); // "FORM" chunk size is overwritten later
- iffWriteUint32(f, (smp->typ & 16) ? 0x31365356 : 0x38535658); // bitdepth - "16SV" (16-bit) or "8SVX" (8-bit)
+ iffWriteUint32(f, sample16Bit ? 0x31365356 : 0x38535658); // bitdepth - "16SV" (16-bit) or "8SVX" (8-bit)
// "VHDR" chunk
iffWriteChunkHeader(f, "VHDR", 20);
- if (!saveRangedData && (smp->typ & 3)) // loop enabled?
+ if (!saveRangedData && GET_LOOPTYPE(smp->flags) != LOOP_OFF)
{
- iffWriteUint32(f, smp->repS); // oneShotHiSamples
- iffWriteUint32(f, smp->repL); // repeatHiSamples
+ iffWriteUint32(f, smp->loopStart << sample16Bit); // oneShotHiSamples
+ iffWriteUint32(f, smp->loopLength << sample16Bit); // repeatHiSamples
}
else
{
@@ -235,7 +259,7 @@
iffWriteUint8(f, 1); // ctOctave (number of samples)
iffWriteUint8(f, 0); // sCompression
- iffWriteUint32(f, smp->vol * 1024); // volume (max: 65536/0x10000)
+ iffWriteUint32(f, smp->volume * 1024); // volume (max: 65536/0x10000)
// "NAME" chunk
@@ -272,7 +296,7 @@
iffWriteChunkData(f, PROG_NAME_STR, chunkLen);
// "BODY" chunk
- chunkLen = sampleLen;
+ chunkLen = sampleLen << sample16Bit;
iffWriteChunkHeader(f, "BODY", chunkLen);
const uint32_t sampleDataPos = ftell(f);
iffWriteChunkData(f, samplePtr, chunkLen);
@@ -285,8 +309,8 @@
fclose(f);
// restore modified interpolation tap samples after loopEnd
- const bool loopEnabled = (smp->typ & 3) ? true : false;
- if (loopEnabled && smp->len > smp->repS+smp->repL)
+ bool loopEnabled = GET_LOOPTYPE(smp->flags) != LOOP_OFF;
+ if (loopEnabled && smp->length > smp->loopStart+smp->loopLength)
fileRestoreFixedSampleData(filenameU, sampleDataPos, smp);
editor.diskOpReadDir = true; // force diskop re-read
@@ -304,14 +328,14 @@
samplerChunk_t samplerChunk;
mptExtraChunk_t mptExtraChunk;
- instrTyp *ins = instr[editor.curInstr];
- if (ins == NULL || ins->samp[editor.curSmp].pek == NULL || ins->samp[editor.curSmp].len == 0)
+ instr_t *ins = instr[editor.curInstr];
+ if (ins == NULL || ins->smp[editor.curSmp].dataPtr == NULL || ins->smp[editor.curSmp].length == 0)
{
okBoxThreadSafe(0, "System message", "The sample is empty!");
return false;
}
- sampleTyp *smp = &ins->samp[editor.curSmp];
+ sample_t *smp = &ins->smp[editor.curSmp];
FILE *f = UNICHAR_FOPEN(filenameU, "wb");
if (f == NULL)
@@ -320,18 +344,20 @@
return false;
}
+ bool sample16Bit = !!(smp->flags & SAMPLE_16BIT);
+
if (saveRangedData)
{
- samplePtr = &smp->pek[getSampleRangeStart()];
+ samplePtr = &smp->dataPtr[getSampleRangeStart() << sample16Bit];
sampleLen = getSampleRangeLength();
}
else
{
- sampleLen = smp->len;
- samplePtr = smp->pek;
+ sampleLen = smp->length;
+ samplePtr = smp->dataPtr;
}
- const uint8_t sampleBitDepth = (smp->typ & 16) ? 16 : 8;
+ const uint8_t sampleBitDepth = sample16Bit ? 16 : 8;
wavHeader.chunkID = 0x46464952; // "RIFF"
wavHeader.chunkSize = 0; // is filled later
@@ -345,7 +371,7 @@
wavHeader.blockAlign = (wavHeader.numChannels * sampleBitDepth) / 8;
wavHeader.bitsPerSample = sampleBitDepth;
wavHeader.subchunk2ID = 0x61746164; // "data"
- wavHeader.subchunk2Size = sampleLen;
+ wavHeader.subchunk2Size = sampleLen << sample16Bit;
// write main header
fwrite(&wavHeader, sizeof (wavHeader_t), 1, f);
@@ -354,7 +380,7 @@
const uint32_t sampleDataPos = ftell(f);
if (sampleBitDepth == 16)
{
- fwrite((int16_t *)samplePtr, sizeof (int16_t), sampleLen / 2, f);
+ fwrite((int16_t *)samplePtr, sizeof (int16_t), sampleLen, f);
}
else
{
@@ -366,7 +392,7 @@
fputc(0, f); // write pad byte if chunk size is uneven
// write "smpl" chunk if loop is enabled
- if (!saveRangedData && (smp->typ & 3))
+ if (!saveRangedData && GET_LOOPTYPE(smp->flags) != LOOP_OFF)
{
memset(&samplerChunk, 0, sizeof (samplerChunk));
@@ -375,21 +401,10 @@
samplerChunk.dwSamplePeriod = 1000000000 / wavHeader.sampleRate;
samplerChunk.dwMIDIUnityNote = 60; // 60 = MIDI middle-C
samplerChunk.cSampleLoops = 1;
- samplerChunk.loop.dwType = (smp->typ & 3) - 1; // 0 = forward, 1 = ping-pong
+ samplerChunk.loop.dwType = GET_LOOPTYPE(smp->flags)-1; // 0 = forward, 1 = ping-pong
+ samplerChunk.loop.dwStart = smp->loopStart;
+ samplerChunk.loop.dwEnd = (smp->loopStart + smp->loopLength) - 1;
- if (sampleBitDepth == 16)
- {
- // divide loop points by 2 to get samples insetad of bytes
- samplerChunk.loop.dwStart = smp->repS / 2;
- samplerChunk.loop.dwEnd = ((smp->repS + smp->repL) / 2) - 1;
- }
- else
- {
- // 8-bit sample
- samplerChunk.loop.dwStart = smp->repS;
- samplerChunk.loop.dwEnd = (smp->repS + smp->repL) - 1;
- }
-
fwrite(&samplerChunk, sizeof (samplerChunk), 1, f);
if (samplerChunk.chunkSize & 1)
fputc(0, f); // write pad byte if chunk size is uneven
@@ -403,10 +418,10 @@
mptExtraChunk.chunkID = 0x61727478; // "xtra"
mptExtraChunk.chunkSize = sizeof (mptExtraChunk) - 4 - 4;
mptExtraChunk.flags = 0x20; // set pan flag
- mptExtraChunk.defaultPan = smp->pan; // 0..255
- mptExtraChunk.defaultVolume = smp->vol * 4; // 0..256
+ mptExtraChunk.defaultPan = smp->panning; // 0..255
+ mptExtraChunk.defaultVolume = smp->volume * 4; // 0..256
mptExtraChunk.globalVolume = 64; // 0..64
- mptExtraChunk.vibratoType = ins->vibTyp; // 0..3 0 = sine, 1 = square, 2 = ramp up, 3 = ramp down
+ mptExtraChunk.vibratoType = ins->vibType; // 0..3 0 = sine, 1 = square, 2 = ramp up, 3 = ramp down
mptExtraChunk.vibratoSweep = ins->vibSweep; // 0..255
mptExtraChunk.vibratoDepth = ins->vibDepth; // 0..15
mptExtraChunk.vibratoRate= ins->vibRate; // 0..63
@@ -474,8 +489,8 @@
fclose(f);
// restore modified interpolation tap samples after loopEnd
- const bool loopEnabled = (smp->typ & 3) ? true : false;
- if (loopEnabled && smp->len > smp->repS+smp->repL)
+ bool loopEnabled = GET_LOOPTYPE(smp->flags) != LOOP_OFF;
+ if (loopEnabled && smp->length > smp->loopStart+smp->loopLength)
fileRestoreFixedSampleData(filenameU, sampleDataPos, smp);
editor.diskOpReadDir = true; // force diskop re-read
--- a/src/ft2_sampling.c
+++ b/src/ft2_sampling.c
@@ -13,28 +13,38 @@
#include "ft2_sampling.h"
#include "ft2_structs.h"
-// these may very well change after opening the audio input device
+#define STEREO_SAMPLE_HEIGHT (SAMPLE_AREA_HEIGHT/2)
+#define SAMPLE_L_CENTER (SAMPLE_AREA_Y_CENTER - (STEREO_SAMPLE_HEIGHT/2))
+#define SAMPLE_R_CENTER (SAMPLE_AREA_Y_CENTER + (STEREO_SAMPLE_HEIGHT/2))
+
+#define MONO_SAMPLE_HEIGHT SAMPLE_AREA_HEIGHT
+#define SAMPLE_CENTER SAMPLE_AREA_Y_CENTER
+
+// this number may change when the audio input device is opened (must be 2^n)
#define SAMPLING_BUFFER_SIZE 2048
+// (must be 2^n)
+#if defined(_WIN32) || defined(__APPLE__)
+#define PREVIEW_SAMPLES 2048
+#else
+#define PREVIEW_SAMPLES 8192
+#endif
+
static bool sampleInStereo;
static volatile bool drawSamplingBufferFlag, outOfMemoryFlag, noMoreRoomFlag;
-static int16_t *currWriteBuf;
-static int16_t displayBuffer1[SAMPLING_BUFFER_SIZE * 2], displayBuffer2[SAMPLING_BUFFER_SIZE * 2];
-static int32_t bytesSampled, samplingBufferBytes;
+static int16_t previewBufL[2][PREVIEW_SAMPLES], previewBufR[2][PREVIEW_SAMPLES];
+static int32_t samplesSampled, samplingBufferSize, currPreviewBufNum, oldPreviewSmpPos, currSampleLen;
static uint32_t samplingRate;
-static volatile int32_t currSampleLen;
+static sample_t *smpL, *smpR;
static SDL_AudioDeviceID recordDev;
-static int16_t rightChSmpSlot = -1;
-static void SDLCALL samplingCallback(void *userdata, Uint8 *stream, int len)
+static void SDLCALL stereoSamplingCallback(void *userdata, Uint8 *stream, int len)
{
- if (instr[editor.curInstr] == NULL || len < 0 || len > samplingBufferBytes)
+ const int32_t samples = len >> 2;
+ if (instr[editor.curInstr] == NULL || samples < 0 || samples > samplingBufferSize)
return;
- sampleTyp *s = &instr[editor.curInstr]->samp[editor.curSmp];
-
- int8_t *newPtr = (int8_t *)realloc(s->origPek, (s->len + len) + LOOP_FIX_LEN);
- if (newPtr == NULL)
+ if (!reallocateSmpData(smpL, smpL->length + samples, true) || !reallocateSmpData(smpR, smpR->length + samples, true))
{
drawSamplingBufferFlag = false;
outOfMemoryFlag = true;
@@ -41,254 +51,243 @@
return;
}
- s->origPek = newPtr;
- s->pek = s->origPek + SMP_DAT_OFFSET;
+ const int16_t *src16 = (int16_t *)stream;
+ int16_t *dst16_L = (int16_t *)smpL->dataPtr + smpL->length;
+ int16_t *dst16_R = (int16_t *)smpR->dataPtr + smpR->length;
- memcpy(&s->pek[s->len], stream, len);
+ for (int32_t i = 0; i < samples; i++)
+ {
+ dst16_L[i] = *src16++;
+ dst16_R[i] = *src16++;
+ }
- s->len += len;
- if (s->len > MAX_SAMPLE_LEN) // length overflow
+ smpL->length += samples;
+ smpR->length += samples;
+
+ if (smpL->length > MAX_SAMPLE_LEN) // length overflow
{
- s->len -= len;
+ smpL->length -= samples;
+ smpR->length -= samples;
noMoreRoomFlag = true;
return;
}
- bytesSampled += len;
- if (bytesSampled >= samplingBufferBytes)
+ currSampleLen = smpL->length;
+
+ // if we have gathared enough samples, fill the current display buffer
+
+ samplesSampled += samples;
+ if (samplesSampled >= PREVIEW_SAMPLES)
{
- bytesSampled -= samplingBufferBytes;
+ samplesSampled -= PREVIEW_SAMPLES;
- currSampleLen = s->len - samplingBufferBytes;
+ if (oldPreviewSmpPos > 0)
+ {
+ int16_t *dstL = previewBufL[currPreviewBufNum^1];
+ int16_t *dstR = previewBufR[currPreviewBufNum^1];
+ const int16_t *srcL = (int16_t *)smpL->dataPtr + oldPreviewSmpPos;
+ const int16_t *srcR = (int16_t *)smpR->dataPtr + oldPreviewSmpPos;
- // fill display buffer
- memcpy(currWriteBuf, &s->pek[currSampleLen], samplingBufferBytes);
+ memcpy(dstL, srcL, PREVIEW_SAMPLES * sizeof (int16_t));
+ memcpy(dstR, srcR, PREVIEW_SAMPLES * sizeof (int16_t));
- // swap write buffer (double-buffering)
- if (currWriteBuf == displayBuffer1)
- currWriteBuf = displayBuffer2;
- else
- currWriteBuf = displayBuffer1;
+ drawSamplingBufferFlag = true;
+ }
- drawSamplingBufferFlag = true;
+ oldPreviewSmpPos = smpL->length - PREVIEW_SAMPLES;
}
(void)userdata;
}
-void stopSampling(void)
+static void SDLCALL monoSamplingCallback(void *userdata, Uint8 *stream, int len)
{
- int8_t *newPtr;
- int16_t *dst16, *src16;
- int32_t i, len;
+ const int32_t samples = len >> 1;
+ if (instr[editor.curInstr] == NULL || samples < 0 || samples > samplingBufferSize)
+ return;
- resumeAudio();
- mouseAnimOff();
-
- SDL_CloseAudioDevice(recordDev);
- editor.samplingAudioFlag = false;
-
- sampleTyp *currSmp = NULL;
- sampleTyp *nextSmp = NULL;
-
- if (instr[editor.curInstr] != NULL)
- currSmp = &instr[editor.curInstr]->samp[editor.curSmp];
-
- if (sampleInStereo)
+ if (!reallocateSmpData(smpL, smpL->length + samples, true))
{
- // read right channel data
-
- if (currSmp->pek != NULL && rightChSmpSlot != -1)
- {
- nextSmp = &instr[editor.curInstr]->samp[rightChSmpSlot];
-
- nextSmp->origPek = (int8_t *)malloc((currSmp->len >> 1) + LOOP_FIX_LEN);
- if (nextSmp->origPek != NULL)
- {
- nextSmp->pek = nextSmp->origPek + SMP_DAT_OFFSET;
- nextSmp->len = currSmp->len >> 1;
-
- src16 = (int16_t *)currSmp->pek;
- dst16 = (int16_t *)nextSmp->pek;
-
- len = nextSmp->len >> 1;
- for (i = 0; i < len; i++)
- dst16[i] = src16[(i << 1) + 1];
- }
- else
- {
- freeSample(editor.curInstr, rightChSmpSlot);
- }
-
- currSmp->len >>= 1;
-
- // read left channel data by skipping every other sample
-
- dst16 = (int16_t *)currSmp->pek;
-
- len = currSmp->len >> 1;
- for (i = 0; i < len; i++)
- dst16[i] = dst16[i << 1];
- }
+ drawSamplingBufferFlag = false;
+ outOfMemoryFlag = true;
+ return;
}
- if (currSmp->origPek != NULL)
- {
- newPtr = (int8_t *)realloc(currSmp->origPek, currSmp->len + LOOP_FIX_LEN);
- if (newPtr != NULL)
- {
- currSmp->origPek = newPtr;
- currSmp->pek = currSmp->origPek + SMP_DAT_OFFSET;
- }
+ const int16_t *src16 = (int16_t *)stream;
+ int16_t *dst16 = (int16_t *)smpL->dataPtr + smpL->length;
+ memcpy(dst16, src16, samples * sizeof (int16_t));
- fixSample(currSmp);
- }
- else
+ smpL->length += samples;
+ if (smpL->length > MAX_SAMPLE_LEN) // length overflow
{
- freeSample(editor.curInstr, editor.curSmp);
+ smpL->length -= samples;
+ noMoreRoomFlag = true;
+ return;
}
- if (nextSmp != NULL && nextSmp->origPek != NULL)
- fixSample(nextSmp);
+ // if we have gathared enough samples, fill the current display buffer
- updateSampleEditorSample();
- editor.updateCurInstr = true;
-}
-
-static uint8_t getDispBuffPeakMono(const int16_t *smpData, int32_t smpNum)
-{
- uint32_t max = 0;
- for (int32_t i = 0; i < smpNum; i++)
+ samplesSampled += samples;
+ if (samplesSampled >= PREVIEW_SAMPLES)
{
- const int16_t smp16 = smpData[i];
+ samplesSampled -= PREVIEW_SAMPLES;
- const uint32_t smpAbs = ABS(smp16);
- if (smpAbs > max)
- max = smpAbs;
+ if (oldPreviewSmpPos > 0)
+ {
+ int16_t *dst = previewBufL[currPreviewBufNum^1];
+ const int16_t *src = (int16_t *)smpL->dataPtr + oldPreviewSmpPos;
+ memcpy(dst, src, PREVIEW_SAMPLES * sizeof (int16_t));
+
+ drawSamplingBufferFlag = true;
+ }
+
+ oldPreviewSmpPos = smpL->length - PREVIEW_SAMPLES;
}
- max = (max * SAMPLE_AREA_HEIGHT) >> 16;
- if (max > 76)
- max = 76;
+ currSampleLen = smpL->length;
- return (uint8_t)max;
+ (void)userdata;
}
-static uint8_t getDispBuffPeakLeft(const int16_t *smpData, int32_t smpNum)
+void stopSampling(void)
{
- smpNum <<= 1;
+ resumeAudio();
+ mouseAnimOff();
- uint32_t max = 0;
- for (int32_t i = 0; i < smpNum; i += 2)
- {
- const int16_t smp16 = smpData[i];
+ SDL_CloseAudioDevice(recordDev);
- const uint32_t smpAbs = ABS(smp16);
- if (smpAbs > max)
- max = smpAbs;
- }
+ if (smpL != NULL) fixSample(smpL);
+ if (smpR != NULL) fixSample(smpR);
- max = (max * SAMPLE_AREA_HEIGHT) >> (16 + 1);
- if (max > 38)
- max = 38;
+ editor.samplingAudioFlag = false;
- return (uint8_t)max;
+ updateSampleEditorSample();
+ editor.updateCurInstr = true;
}
-static uint8_t getDispBuffPeakRight(const int16_t *smpData, int32_t smpNum)
+static void getMinMax16(const int16_t *p, uint32_t position, uint32_t scanLen, int16_t *min16, int16_t *max16)
{
- smpNum <<= 1;
+ int16_t minVal = 32767;
+ int16_t maxVal = -32768;
- uint32_t max = 0;
- for (int32_t i = 0; i < smpNum; i += 2)
- {
- const int16_t smp16 = smpData[i];
+ assert(position+scanLen <= PREVIEW_SAMPLES);
- const uint32_t smpAbs = ABS(smp16);
- if (smpAbs > max)
- max = smpAbs;
+ const int16_t *ptr16 = (const int16_t *)p + position;
+ for (uint32_t i = 0; i < scanLen; i++)
+ {
+ const int16_t smp16 = ptr16[i];
+ if (smp16 < minVal) minVal = smp16;
+ if (smp16 > maxVal) maxVal = smp16;
}
- max = (max * SAMPLE_AREA_HEIGHT) >> (16 + 1);
- if (max > 38)
- max = 38;
-
- return (uint8_t)max;
+ *min16 = minVal;
+ *max16 = maxVal;
}
-static inline int32_t scrPos2SmpBufPos(int32_t x) // x = 0..SAMPLE_AREA_WIDTH
+static int32_t scr2BufPos(int32_t x)
{
- return (x * ((SAMPLING_BUFFER_SIZE << 16) / SAMPLE_AREA_WIDTH)) >> 16;
+ const double dXScaleMul = PREVIEW_SAMPLES / (double)SAMPLE_AREA_WIDTH;
+ return (int32_t)(x * dXScaleMul);
}
static void drawSamplingPreview(void)
{
- uint8_t smpAbs;
- int16_t *readBuf;
- uint16_t x;
- int32_t smpIdx, smpNum;
- uint32_t *centerPtrL, *centerPtrR;
+ int16_t min, max;
- const uint32_t pixVal = video.palette[PAL_PATTEXT];
+ // clear sample data area
+ memset(&video.frameBuffer[174 * SCREEN_W], 0, SAMPLE_AREA_WIDTH * SAMPLE_AREA_HEIGHT * sizeof (int32_t));
- // select buffer currently not being written to (double-buffering)
- if (currWriteBuf == displayBuffer1)
- readBuf = displayBuffer2;
- else
- readBuf = displayBuffer1;
-
- if (sampleInStereo)
+ if (sampleInStereo) // stereo sampling
{
- // stereo sampling
+ const int16_t *smpDataL = previewBufL[currPreviewBufNum];
+ const int16_t *smpDataR = previewBufR[currPreviewBufNum];
- const uint16_t centerL = SAMPLE_AREA_Y_CENTER - (SAMPLE_AREA_HEIGHT / 4);
- const uint16_t centerR = SAMPLE_AREA_Y_CENTER + (SAMPLE_AREA_HEIGHT / 4);
+ int32_t oldMinL = SAMPLE_L_CENTER;
+ int32_t oldMaxL = SAMPLE_L_CENTER;
+ int32_t oldMinR = SAMPLE_R_CENTER;
+ int32_t oldMaxR = SAMPLE_R_CENTER;
- centerPtrL = &video.frameBuffer[centerL*SCREEN_W];
- centerPtrR = &video.frameBuffer[centerR*SCREEN_W];
+ hLine(0, SAMPLE_L_CENTER, SAMPLE_AREA_WIDTH, PAL_DESKTOP); // draw center line
+ hLine(0, SAMPLE_R_CENTER, SAMPLE_AREA_WIDTH, PAL_DESKTOP); // draw center line
- for (x = 0; x < SAMPLE_AREA_WIDTH; x++)
+ for (int16_t x = 0; x < SAMPLE_AREA_WIDTH; x++)
{
- smpIdx = scrPos2SmpBufPos(x);
- smpNum = scrPos2SmpBufPos(x+1) - smpIdx;
+ int32_t smpIdx = scr2BufPos(x+0);
+ int32_t smpNum = scr2BufPos(x+1) - smpIdx;
- if (smpIdx+smpNum >= SAMPLING_BUFFER_SIZE)
- smpNum = SAMPLING_BUFFER_SIZE - smpIdx;
+ if (smpIdx+smpNum > PREVIEW_SAMPLES)
+ smpNum = PREVIEW_SAMPLES-smpIdx;
- // left channel samples
- smpAbs = getDispBuffPeakLeft(&readBuf[(smpIdx * 2) + 0], smpNum);
- if (smpAbs == 0)
- centerPtrL[x] = pixVal;
- else
- vLine(x, centerL - smpAbs, (smpAbs * 2) + 1, PAL_PATTEXT);
+ if (smpNum > 0)
+ {
+ // left channel
+ getMinMax16(smpDataL, smpIdx, smpNum, &min, &max);
+ min = SAMPLE_L_CENTER - ((min * STEREO_SAMPLE_HEIGHT) >> 16);
+ max = SAMPLE_L_CENTER - ((max * STEREO_SAMPLE_HEIGHT) >> 16);
- // right channel samples
- smpAbs = getDispBuffPeakRight(&readBuf[(smpIdx * 2) + 1], smpNum);
- if (smpAbs == 0)
- centerPtrR[x] = pixVal;
- else
- vLine(x, centerR - smpAbs, (smpAbs * 2) + 1, PAL_PATTEXT);
+ if (x != 0)
+ {
+ if (min > oldMaxL) sampleLine(x-1, x, oldMaxL, min);
+ if (max < oldMinL) sampleLine(x-1, x, oldMinL, max);
+ }
+
+ sampleLine(x, x, max, min);
+
+ oldMinL = min;
+ oldMaxL = max;
+
+ // right channel
+ getMinMax16(smpDataR, smpIdx, smpNum, &min, &max);
+ min = SAMPLE_R_CENTER - ((min * STEREO_SAMPLE_HEIGHT) >> 16);
+ max = SAMPLE_R_CENTER - ((max * STEREO_SAMPLE_HEIGHT) >> 16);
+
+ if (x != 0)
+ {
+ if (min > oldMaxR) sampleLine(x-1, x, oldMaxR, min);
+ if (max < oldMinR) sampleLine(x-1, x, oldMinR, max);
+ }
+
+ sampleLine(x, x, max, min);
+
+ oldMinR = min;
+ oldMaxR = max;
+ }
}
}
- else
+ else // mono sampling
{
- // mono sampling
+ const int16_t *smpData = previewBufL[currPreviewBufNum];
- centerPtrL = &video.frameBuffer[SAMPLE_AREA_Y_CENTER * SCREEN_W];
+ int32_t oldMin = SAMPLE_CENTER;
+ int32_t oldMax = SAMPLE_CENTER;
- for (x = 0; x < SAMPLE_AREA_WIDTH; x++)
+ hLine(0, SAMPLE_CENTER, SAMPLE_AREA_WIDTH, PAL_DESKTOP); // draw center line
+
+ for (int16_t x = 0; x < SAMPLE_AREA_WIDTH; x++)
{
- smpIdx = scrPos2SmpBufPos(x);
- smpNum = scrPos2SmpBufPos(x+1) - smpIdx;
+ int32_t smpIdx = scr2BufPos(x+0);
+ int32_t smpNum = scr2BufPos(x+1) - smpIdx;
- if (smpIdx+smpNum >= SAMPLING_BUFFER_SIZE)
- smpNum = SAMPLING_BUFFER_SIZE - smpIdx;
+ if (smpIdx+smpNum > PREVIEW_SAMPLES)
+ smpNum = PREVIEW_SAMPLES-smpIdx;
- smpAbs = getDispBuffPeakMono(&readBuf[smpIdx], smpNum);
- if (smpAbs == 0)
- centerPtrL[x] = pixVal;
- else
- vLine(x, SAMPLE_AREA_Y_CENTER - smpAbs, (smpAbs * 2) + 1, PAL_PATTEXT);
+ if (smpNum > 0)
+ {
+ getMinMax16(smpData, smpIdx, smpNum, &min, &max);
+ min = SAMPLE_CENTER - ((min * MONO_SAMPLE_HEIGHT) >> 16);
+ max = SAMPLE_CENTER - ((max * MONO_SAMPLE_HEIGHT) >> 16);
+
+ if (x != 0)
+ {
+ if (min > oldMax) sampleLine(x-1, x, oldMax, min);
+ if (max < oldMin) sampleLine(x-1, x, oldMin, max);
+ }
+
+ sampleLine(x, x, max, min);
+
+ oldMin = min;
+ oldMax = max;
+ }
}
}
}
@@ -315,19 +314,13 @@
{
drawSamplingBufferFlag = false;
- // clear sample data area
- memset(&video.frameBuffer[174 * SCREEN_W], 0, SAMPLE_AREA_WIDTH * SAMPLE_AREA_HEIGHT * sizeof (int32_t));
-
drawSamplingPreview();
-
- // clear and draw new sample length number
- fillRect(536, 362, 56, 10, PAL_DESKTOP);
-
- if (sampleInStereo)
- hexOut(536, 362, PAL_FORGRND, currSampleLen >> 1, 8);
- else
- hexOut(536, 362, PAL_FORGRND, currSampleLen, 8);
+ currPreviewBufNum ^= 1;
}
+
+ // clear and draw new sample length number
+ fillRect(536, 362, 56, 10, PAL_DESKTOP);
+ hexOut(536, 362, PAL_FORGRND, currSampleLen, 8);
}
void startSampling(void)
@@ -346,23 +339,20 @@
return;
sampleInStereo = (result == 2);
- samplingBufferBytes = sampleInStereo ? (SAMPLING_BUFFER_SIZE * 4) : (SAMPLING_BUFFER_SIZE * 2);
-
mouseAnimOn();
switch (config.audioInputFreq)
{
- case INPUT_FREQ_96KHZ: samplingRate = 96000; break;
- case INPUT_FREQ_44KHZ: samplingRate = 44100; break;
- default: samplingRate = 48000; break;
+ case INPUT_FREQ_44KHZ: samplingRate = 44100; break;
+ default: case INPUT_FREQ_48KHZ: samplingRate = 48000; break;
+ case INPUT_FREQ_96KHZ: samplingRate = 96000; break;
}
memset(&want, 0, sizeof (SDL_AudioSpec));
want.freq = samplingRate;
want.format = AUDIO_S16;
- want.channels = 1 + sampleInStereo;
- want.callback = samplingCallback;
- want.userdata = NULL;
+ want.channels = sampleInStereo ? 2 : 1;
+ want.callback = sampleInStereo ? stereoSamplingCallback : monoSamplingCallback;
want.samples = SAMPLING_BUFFER_SIZE;
recordDev = SDL_OpenAudioDevice(audio.currInputDevice, true, &want, &have, 0);
@@ -372,63 +362,60 @@
return;
}
+ samplingRate = have.freq;
+ samplingBufferSize = have.samples;
+
pauseAudio();
if (instr[editor.curInstr] == NULL && !allocateInstr(editor.curInstr))
{
- resumeAudio();
+ stopSampling();
okBox(0, "System message", "Not enough memory!");
return;
}
- sampleTyp *s = &instr[editor.curInstr]->samp[editor.curSmp];
+ if (sampleInStereo && editor.curSmp+1 >= MAX_SMP_PER_INST)
+ {
+ stopSampling();
+ okBox(0, "System message", "Error: No free sample slot for the right channel!");
+ return;
+ }
- // wipe current sample and prepare it
- freeSample(editor.curInstr, editor.curSmp);
- s->typ |= 16; // we always sample in 16-bit
+ smpL = &instr[editor.curInstr]->smp[editor.curSmp];
+ freeSample(editor.curInstr, editor.curSmp); // also sets pan to 128 and vol to 64
+ tuneSample(smpL, samplingRate, audio.linearPeriodsFlag);
+ smpL->flags |= SAMPLE_16BIT;
- tuneSample(s, samplingRate, audio.linearPeriodsFlag); // tune sample (relTone/finetune) to the sampling frequency we obtained
-
if (sampleInStereo)
{
- strcpy(s->name, "Left sample");
- s->pan = 0;
+ smpR = &instr[editor.curInstr]->smp[editor.curSmp+1];
+ freeSample(editor.curInstr, editor.curSmp+1); // also sets pan to 128 and vol to 64
+ tuneSample(smpR, samplingRate, audio.linearPeriodsFlag);
+ smpR->flags |= SAMPLE_16BIT;
- if (editor.curSmp+1 < MAX_SMP_PER_INST)
- rightChSmpSlot = editor.curSmp+1;
- else
- rightChSmpSlot = -1;
+ strcpy(smpL->name, "Left sample");
+ smpL->panning = 0;
- if (rightChSmpSlot != -1)
- {
- // wipe current sample and prepare it
- freeSample(editor.curInstr, rightChSmpSlot);
- sampleTyp *nextSmp = &instr[editor.curInstr]->samp[rightChSmpSlot];
-
- strcpy(nextSmp->name, "Right sample");
- nextSmp->typ |= 16; // we always sample in 16-bit
- nextSmp->pan = 255;
-
- tuneSample(nextSmp, samplingRate, audio.linearPeriodsFlag); // tune sample (relTone/finetune) to the sampling frequency we obtained
- }
+ strcpy(smpR->name, "Right sample");
+ smpR->panning = 255;
}
else
{
- strcpy(s->name, "Mono-mixed sample");
+ strcpy(smpL->name, "Mono sample");
}
+ memset(previewBufL, 0, sizeof (previewBufL));
+ memset(previewBufR, 0, sizeof (previewBufR));
+ currPreviewBufNum = 0;
+
+ samplesSampled = currSampleLen = oldPreviewSmpPos = 0;
+ noMoreRoomFlag = outOfMemoryFlag = drawSamplingBufferFlag = false;
+
updateSampleEditorSample();
updateSampleEditor();
setSongModifiedFlag();
- currWriteBuf = displayBuffer1;
- memset(displayBuffer1, 0, sizeof (displayBuffer1));
- memset(displayBuffer2, 0, sizeof (displayBuffer2));
-
editor.samplingAudioFlag = true;
- bytesSampled = 0;
- currSampleLen = 0;
-
SDL_PauseAudioDevice(recordDev, false);
#endif
}
--- a/src/ft2_scopedraw.c
+++ /dev/null
@@ -1,402 +1,0 @@
-#include "ft2_scopes.h"
-#include "ft2_scopedraw.h"
-#include "ft2_video.h"
-#include "ft2_palette.h"
-
-/* ----------------------------------------------------------------------- */
-/* SCOPE DRAWING MACROS */
-/* ----------------------------------------------------------------------- */
-
-#define SCOPE_REGS_NO_LOOP \
- const int32_t vol = s->vol; \
- const int32_t end = s->end; \
- const uint32_t delta = s->drawDelta; \
- const uint32_t color = video.palette[PAL_PATTEXT]; \
- const uint32_t width = x + w; \
- int32_t sample; \
- int32_t pos = s->pos; \
- int32_t posFrac = 0; \
-
-#define SCOPE_REGS_LOOP \
- const int32_t vol = s->vol; \
- const int32_t end = s->end; \
- const int32_t loopStart = s->loopStart; \
- const int32_t loopLength = s->loopLength; \
- const uint32_t delta = s->drawDelta; \
- const uint32_t color = video.palette[PAL_PATTEXT]; \
- const uint32_t width = x + w; \
- int32_t sample; \
- int32_t pos = s->pos; \
- int32_t posFrac = 0; \
-
-#define SCOPE_REGS_PINGPONG \
- const int32_t vol = s->vol; \
- const int32_t end = s->end; \
- const int32_t loopStart = s->loopStart; \
- const int32_t loopLength = s->loopLength; \
- const uint32_t delta = s->drawDelta; \
- const uint32_t color = video.palette[PAL_PATTEXT]; \
- const uint32_t width = x + w; \
- int32_t sample; \
- int32_t pos = s->pos; \
- int32_t posFrac = 0; \
- int32_t direction = s->direction; \
-
-#define LINED_SCOPE_REGS_NO_LOOP \
- const int32_t vol = s->vol; \
- const int32_t end = s->end; \
- const uint32_t delta = s->drawDelta; \
- const uint32_t width = (x + w) - 1; \
- int32_t sample; \
- int32_t y1, y2; \
- int32_t pos = s->pos; \
- int32_t posFrac = 0; \
-
-#define LINED_SCOPE_REGS_LOOP \
- const int32_t vol = s->vol; \
- const int32_t end = s->end; \
- const int32_t loopStart = s->loopStart; \
- const int32_t loopLength = s->loopLength; \
- const uint32_t delta = s->drawDelta; \
- const uint32_t width = (x + w) - 1; \
- int32_t sample; \
- int32_t y1, y2; \
- int32_t pos = s->pos; \
- int32_t posFrac = 0; \
-
-#define LINED_SCOPE_REGS_PINGPONG \
- const int32_t vol = s->vol; \
- const int32_t end = s->end; \
- const int32_t loopStart = s->loopStart; \
- const int32_t loopLength = s->loopLength; \
- const uint32_t delta = s->drawDelta; \
- const uint32_t width = (x + w) - 1; \
- int32_t sample; \
- int32_t y1, y2; \
- int32_t pos = s->pos; \
- int32_t posFrac = 0; \
- int32_t direction = s->direction; \
-
-#define SCOPE_GET_SMP8 \
- if (s->active) \
- { \
- assert(pos >= 0 && pos < end); \
- sample = (s->base8[pos] * vol) >> 8; \
- } \
- else \
- { \
- sample = 0; \
- } \
-
-#define SCOPE_GET_SMP16 \
- if (s->active) \
- { \
- assert(pos >= 0 && pos < end); \
- sample = (int8_t)((s->base16[pos] * vol) >> 16); \
- } \
- else \
- { \
- sample = 0; \
- } \
-
-#define SCOPE_UPDATE_DRAWPOS \
- posFrac += delta; \
- pos += posFrac >> SCOPE_DRAW_FRAC_BITS; \
- posFrac &= SCOPE_DRAW_FRAC_MASK; \
-
-#define SCOPE_UPDATE_DRAWPOS_PINGPONG \
- posFrac += delta; \
- pos += (int32_t)(posFrac >> SCOPE_DRAW_FRAC_BITS) * direction; \
- posFrac &= SCOPE_DRAW_FRAC_MASK; \
-
-#define SCOPE_DRAW_SMP \
- video.frameBuffer[((lineY - sample) * SCREEN_W) + x] = color;
-
-#define LINED_SCOPE_PREPARE_SMP8 \
- SCOPE_GET_SMP8 \
- y1 = lineY - sample; \
- SCOPE_UPDATE_DRAWPOS
-
-#define LINED_SCOPE_PREPARE_SMP16 \
- SCOPE_GET_SMP16 \
- y1 = lineY - sample; \
- SCOPE_UPDATE_DRAWPOS
-
-#define LINED_SCOPE_DRAW_SMP \
- y2 = lineY - sample; \
- scopeLine(x, y1, y2); \
- y1 = y2; \
-
-#define SCOPE_HANDLE_POS_NO_LOOP \
- if (pos >= end) \
- s->active = false; \
-
-#define SCOPE_HANDLE_POS_LOOP \
- if (pos >= end) \
- { \
- if (loopLength >= 2) \
- pos = loopStart + ((pos - end) % loopLength); \
- else \
- pos = loopStart; \
- \
- assert(pos >= loopStart && pos < end); \
- } \
-
-#define SCOPE_HANDLE_POS_PINGPONG \
- if (direction == -1 && pos < loopStart) \
- { \
- direction = 1; /* change direction to forwards */ \
- \
- if (loopLength >= 2) \
- pos = loopStart + ((loopStart - pos - 1) % loopLength); \
- else \
- pos = loopStart; \
- \
- assert(pos >= loopStart && pos < end); \
- } \
- else if (pos >= end) \
- { \
- direction = -1; /* change direction to backwards */ \
- \
- if (loopLength >= 2) \
- pos = (end - 1) - ((pos - end) % loopLength); \
- else \
- pos = end - 1; \
- \
- assert(pos >= loopStart && pos < end); \
- } \
- assert(pos >= 0); \
-
-static void scopeLine(int32_t x1, int32_t y1, int32_t y2)
-{
- const int32_t dy = y2 - y1;
- const int32_t sy = SGN(dy);
- const uint32_t color = video.palette[PAL_PATTEXT];
- const int32_t pitch = sy * SCREEN_W;
-
- uint32_t *dst32 = &video.frameBuffer[(y1 * SCREEN_W) + x1];
-
- *dst32 = color; // set first pixel
-
- int32_t ay = ABS(dy);
- if (ay <= 1)
- {
- if (ay != 0)
- dst32 += pitch;
-
- *++dst32 = color;
- return;
- }
-
- int32_t d = 1 - ay;
-
- ay <<= 1;
- while (y1 != y2)
- {
- if (d >= 0)
- {
- d -= ay;
- dst32++;
- }
-
- y1 += sy;
- d += 2;
-
- dst32 += pitch;
- *dst32 = color;
- }
-}
-
-/* ----------------------------------------------------------------------- */
-/* SCOPE DRAWING ROUTINES */
-/* ----------------------------------------------------------------------- */
-
-static void scopeDrawNoLoop_8bit(scope_t *s, uint32_t x, uint32_t lineY, uint32_t w)
-{
- SCOPE_REGS_NO_LOOP
-
- for (; x < width; x++)
- {
- SCOPE_GET_SMP8
- SCOPE_DRAW_SMP
- SCOPE_UPDATE_DRAWPOS
- SCOPE_HANDLE_POS_NO_LOOP
- }
-}
-
-static void scopeDrawLoop_8bit(scope_t *s, uint32_t x, uint32_t lineY, uint32_t w)
-{
- SCOPE_REGS_LOOP
-
- for (; x < width; x++)
- {
- SCOPE_GET_SMP8
- SCOPE_DRAW_SMP
- SCOPE_UPDATE_DRAWPOS
- SCOPE_HANDLE_POS_LOOP
- }
-}
-
-static void scopeDrawPingPong_8bit(scope_t *s, uint32_t x, uint32_t lineY, uint32_t w)
-{
- SCOPE_REGS_PINGPONG
-
- for (; x < width; x++)
- {
- SCOPE_GET_SMP8
- SCOPE_DRAW_SMP
- SCOPE_UPDATE_DRAWPOS_PINGPONG
- SCOPE_HANDLE_POS_PINGPONG
- }
-}
-
-static void scopeDrawNoLoop_16bit(scope_t *s, uint32_t x, uint32_t lineY, uint32_t w)
-{
- SCOPE_REGS_NO_LOOP
-
- for (; x < width; x++)
- {
- SCOPE_GET_SMP16
- SCOPE_DRAW_SMP
- SCOPE_UPDATE_DRAWPOS
- SCOPE_HANDLE_POS_NO_LOOP
- }
-}
-
-static void scopeDrawLoop_16bit(scope_t *s, uint32_t x, uint32_t lineY, uint32_t w)
-{
- SCOPE_REGS_LOOP
-
- for (; x < width; x++)
- {
- SCOPE_GET_SMP16
- SCOPE_DRAW_SMP
- SCOPE_UPDATE_DRAWPOS
- SCOPE_HANDLE_POS_LOOP
- }
-}
-
-static void scopeDrawPingPong_16bit(scope_t *s, uint32_t x, uint32_t lineY, uint32_t w)
-{
- SCOPE_REGS_PINGPONG
-
- for (; x < width; x++)
- {
- SCOPE_GET_SMP16
- SCOPE_DRAW_SMP
- SCOPE_UPDATE_DRAWPOS_PINGPONG
- SCOPE_HANDLE_POS_PINGPONG
- }
-}
-
-/* ----------------------------------------------------------------------- */
-/* LINED SCOPE DRAWING ROUTINES */
-/* ----------------------------------------------------------------------- */
-
-static void linedScopeDrawNoLoop_8bit(scope_t *s, uint32_t x, uint32_t lineY, uint32_t w)
-{
- LINED_SCOPE_REGS_NO_LOOP
- LINED_SCOPE_PREPARE_SMP8
- SCOPE_HANDLE_POS_NO_LOOP
-
- for (; x < width; x++)
- {
- SCOPE_GET_SMP8
- LINED_SCOPE_DRAW_SMP
- SCOPE_UPDATE_DRAWPOS
- SCOPE_HANDLE_POS_NO_LOOP
- }
-}
-
-static void linedScopeDrawLoop_8bit(scope_t *s, uint32_t x, uint32_t lineY, uint32_t w)
-{
- LINED_SCOPE_REGS_LOOP
- LINED_SCOPE_PREPARE_SMP8
- SCOPE_HANDLE_POS_LOOP
-
- for (; x < width; x++)
- {
- SCOPE_GET_SMP8
- LINED_SCOPE_DRAW_SMP
- SCOPE_UPDATE_DRAWPOS
- SCOPE_HANDLE_POS_LOOP
- }
-}
-
-static void linedScopeDrawPingPong_8bit(scope_t *s, uint32_t x, uint32_t lineY, uint32_t w)
-{
- LINED_SCOPE_REGS_PINGPONG
- LINED_SCOPE_PREPARE_SMP8
- SCOPE_HANDLE_POS_PINGPONG
-
- for (; x < width; x++)
- {
- SCOPE_GET_SMP8
- LINED_SCOPE_DRAW_SMP
- SCOPE_UPDATE_DRAWPOS_PINGPONG
- SCOPE_HANDLE_POS_PINGPONG
- }
-}
-
-static void linedScopeDrawNoLoop_16bit(scope_t *s, uint32_t x, uint32_t lineY, uint32_t w)
-{
- LINED_SCOPE_REGS_NO_LOOP
- LINED_SCOPE_PREPARE_SMP16
- SCOPE_HANDLE_POS_NO_LOOP
-
- for (; x < width; x++)
- {
- SCOPE_GET_SMP16
- LINED_SCOPE_DRAW_SMP
- SCOPE_UPDATE_DRAWPOS
- SCOPE_HANDLE_POS_NO_LOOP
- }
-}
-
-static void linedScopeDrawLoop_16bit(scope_t *s, uint32_t x, uint32_t lineY, uint32_t w)
-{
- LINED_SCOPE_REGS_LOOP
- LINED_SCOPE_PREPARE_SMP16
- SCOPE_HANDLE_POS_LOOP
-
- for (; x < width; x++)
- {
- SCOPE_GET_SMP16
- LINED_SCOPE_DRAW_SMP
- SCOPE_UPDATE_DRAWPOS
- SCOPE_HANDLE_POS_LOOP
- }
-}
-
-static void linedScopeDrawPingPong_16bit(scope_t *s, uint32_t x, uint32_t lineY, uint32_t w)
-{
- LINED_SCOPE_REGS_PINGPONG
- LINED_SCOPE_PREPARE_SMP16
- SCOPE_HANDLE_POS_PINGPONG
-
- for (; x < width; x++)
- {
- SCOPE_GET_SMP16
- LINED_SCOPE_DRAW_SMP
- SCOPE_UPDATE_DRAWPOS_PINGPONG
- SCOPE_HANDLE_POS_PINGPONG
- }
-}
-
-// -----------------------------------------------------------------------
-
-const scopeDrawRoutine scopeDrawRoutineTable[12] =
-{
- (scopeDrawRoutine)scopeDrawNoLoop_8bit,
- (scopeDrawRoutine)scopeDrawLoop_8bit,
- (scopeDrawRoutine)scopeDrawPingPong_8bit,
- (scopeDrawRoutine)scopeDrawNoLoop_16bit,
- (scopeDrawRoutine)scopeDrawLoop_16bit,
- (scopeDrawRoutine)scopeDrawPingPong_16bit,
- (scopeDrawRoutine)linedScopeDrawNoLoop_8bit,
- (scopeDrawRoutine)linedScopeDrawLoop_8bit,
- (scopeDrawRoutine)linedScopeDrawPingPong_8bit,
- (scopeDrawRoutine)linedScopeDrawNoLoop_16bit,
- (scopeDrawRoutine)linedScopeDrawLoop_16bit,
- (scopeDrawRoutine)linedScopeDrawPingPong_16bit
-};
--- a/src/ft2_scopedraw.h
+++ /dev/null
@@ -1,8 +1,0 @@
-#pragma once
-
-#include <stdint.h>
-#include "ft2_scopes.h"
-
-typedef void (*scopeDrawRoutine)(const scope_t *, uint32_t, uint32_t, uint32_t);
-
-extern const scopeDrawRoutine scopeDrawRoutineTable[12]; // ft2_scopedraw.c
--- a/src/ft2_scopes.c
+++ /dev/null
@@ -1,641 +1,0 @@
-// for finding memory leaks in debug mode with Visual Studio
-#if defined _DEBUG && defined _MSC_VER
-#include <crtdbg.h>
-#endif
-
-#include <stdint.h>
-#include <stdbool.h>
-#include <math.h> // modf()
-#ifndef _WIN32
-#include <unistd.h> // usleep()
-#endif
-#include "ft2_header.h"
-#include "ft2_events.h"
-#include "ft2_config.h"
-#include "ft2_audio.h"
-#include "ft2_gui.h"
-#include "ft2_midi.h"
-#include "ft2_bmp.h"
-#include "ft2_scopes.h"
-#include "ft2_mouse.h"
-#include "ft2_video.h"
-#include "ft2_scopedraw.h"
-#include "ft2_tables.h"
-#include "ft2_structs.h"
-
-static volatile bool scopesUpdatingFlag, scopesDisplayingFlag;
-static uint32_t scopeTimeLen, scopeTimeLenFrac;
-static uint64_t timeNext64, timeNext64Frac;
-static volatile scope_t scope[MAX_VOICES];
-static SDL_Thread *scopeThread;
-
-lastChInstr_t lastChInstr[MAX_VOICES]; // global
-
-void resetCachedScopeVars(void)
-{
- volatile scope_t *sc = scope;
- for (int32_t i = 0; i < MAX_VOICES; i++, sc++)
- {
- sc->dOldHz = -1.0;
- sc->oldDelta = 0;
- sc->oldDrawDelta = 0;
- }
-}
-
-int32_t getSamplePosition(uint8_t ch)
-{
- if (ch >= song.antChn)
- return -1;
-
- volatile scope_t *sc = &scope[ch];
-
- // cache some stuff
- volatile bool active = sc->active;
- volatile int32_t pos = sc->pos;
- volatile int32_t end = sc->end;
- volatile bool sampleIs16Bit = sc->sampleIs16Bit;
-
- if (!active || end == 0)
- return -1;
-
- if (pos >= 0 && pos < end)
- {
- if (sampleIs16Bit)
- pos <<= 1;
-
- return pos;
- }
-
- return -1; // not active or overflown
-}
-
-void stopAllScopes(void)
-{
- // wait for scopes to finish updating
- while (scopesUpdatingFlag);
-
- volatile scope_t *sc = scope;
- for (int32_t i = 0; i < MAX_VOICES; i++, sc++)
- sc->active = false;
-
- // wait for scope displaying to be done (safety)
- while (scopesDisplayingFlag);
-}
-
-// toggle mute
-static void setChannel(int32_t nr, bool on)
-{
- stmTyp *ch = &stm[nr];
-
- ch->stOff = !on;
- if (ch->stOff)
- {
- ch->effTyp = 0;
- ch->eff = 0;
- ch->realVol = 0;
- ch->outVol = 0;
- ch->oldVol = 0;
- ch->dFinalVol = 0.0;
- ch->outPan = 128;
- ch->oldPan = 128;
- ch->finalPan = 128;
- ch->status = IS_Vol;
-
- ch->envSustainActive = false; // non-FT2 bug fix for stuck piano keys
- }
-
- scope[nr].wasCleared = false;
-}
-
-static void drawScopeNumber(uint16_t scopeXOffs, uint16_t scopeYOffs, uint8_t channel, bool outline)
-{
- scopeXOffs++;
- scopeYOffs++;
- channel++;
-
- if (outline)
- {
- if (channel < 10) // one digit?
- {
- charOutOutlined(scopeXOffs, scopeYOffs, PAL_MOUSEPT, '0' + channel);
- }
- else
- {
- charOutOutlined(scopeXOffs, scopeYOffs, PAL_MOUSEPT, chDecTab1[channel]);
- charOutOutlined(scopeXOffs + 7, scopeYOffs, PAL_MOUSEPT, chDecTab2[channel]);
- }
- }
- else
- {
- if (channel < 10) // one digit?
- {
- charOut(scopeXOffs, scopeYOffs, PAL_MOUSEPT, '0' + channel);
- }
- else
- {
- charOut(scopeXOffs, scopeYOffs, PAL_MOUSEPT, chDecTab1[channel]);
- charOut(scopeXOffs + 7, scopeYOffs, PAL_MOUSEPT, chDecTab2[channel]);
- }
- }
-}
-
-static void redrawScope(int32_t ch)
-{
- int32_t i;
-
- int32_t chansPerRow = (uint32_t)song.antChn >> 1;
- int32_t chanLookup = chansPerRow - 1;
- const uint16_t *scopeLens = scopeLenTab[chanLookup];
-
- // get x,y,len for scope according to channel (we must do it this way since 'len' can differ!)
-
- uint16_t x = 2;
- uint16_t y = 94;
-
- uint16_t scopeLen = 0; // prevent compiler warning
- for (i = 0; i < song.antChn; i++)
- {
- scopeLen = scopeLens[i];
-
- if (i == chansPerRow) // did we reach end of row?
- {
- // yes, go one row down
- x = 2;
- y += 39;
- }
-
- if (i == ch)
- break;
-
- // adjust position to next channel
- x += scopeLen + 3;
- }
-
- drawFramework(x, y, scopeLen + 2, 38, FRAMEWORK_TYPE2);
-
- // draw mute graphics if channel is muted
- if (!editor.chnMode[i])
- {
- const uint16_t muteGfxLen = scopeMuteBMP_Widths[chanLookup];
- const uint16_t muteGfxX = x + ((scopeLen - muteGfxLen) >> 1);
-
- blitFastClipX(muteGfxX, y + 6, bmp.scopeMute+scopeMuteBMP_Offs[chanLookup], 162, scopeMuteBMP_Heights[chanLookup], muteGfxLen);
-
- if (config.ptnChnNumbers)
- drawScopeNumber(x + 1, y + 1, (uint8_t)i, true);
- }
-
- scope[ch].wasCleared = false;
-}
-
-void refreshScopes(void)
-{
- for (int32_t i = 0; i < MAX_VOICES; i++)
- scope[i].wasCleared = false;
-}
-
-static void channelMode(int32_t chn)
-{
- int32_t i;
-
- assert(chn < song.antChn);
-
- bool m = mouse.leftButtonPressed && !mouse.rightButtonPressed;
- bool m2 = mouse.rightButtonPressed && mouse.leftButtonPressed;
-
- if (m2)
- {
- bool test = false;
- for (i = 0; i < song.antChn; i++)
- {
- if (i != chn && !editor.chnMode[i])
- test = true;
- }
-
- if (test)
- {
- for (i = 0; i < song.antChn; i++)
- editor.chnMode[i] = true;
- }
- else
- {
- for (i = 0; i < song.antChn; i++)
- editor.chnMode[i] = (i == chn);
- }
- }
- else if (m)
- {
- editor.chnMode[chn] ^= 1;
- }
- else
- {
- if (editor.chnMode[chn])
- {
- config.multiRecChn[chn] ^= 1;
- }
- else
- {
- config.multiRecChn[chn] = true;
- editor.chnMode[chn] = true;
- m = true;
- }
- }
-
- for (i = 0; i < song.antChn; i++)
- setChannel(i, editor.chnMode[i]);
-
- if (m2)
- {
- for (i = 0; i < song.antChn; i++)
- redrawScope(i);
- }
- else
- {
- redrawScope(chn);
- }
-}
-
-bool testScopesMouseDown(void)
-{
- int32_t i;
-
- if (!ui.scopesShown)
- return false;
-
- if (mouse.y >= 95 && mouse.y <= 169 && mouse.x >= 3 && mouse.x <= 288)
- {
- if (mouse.y > 130 && mouse.y < 134)
- return true;
-
- int32_t chansPerRow = (uint32_t)song.antChn >> 1;
- const uint16_t *scopeLens = scopeLenTab[chansPerRow-1];
-
- // find out if we clicked inside a scope
- uint16_t x = 3;
- for (i = 0; i < chansPerRow; i++)
- {
- if (mouse.x >= x && mouse.x < x+scopeLens[i])
- break;
-
- x += scopeLens[i]+3;
- }
-
- if (i == chansPerRow)
- return true; // scope framework was clicked instead
-
- int32_t chanToToggle = i;
- if (mouse.y >= 134) // second row of scopes?
- chanToToggle += chansPerRow; // yes, increase lookup offset
-
- channelMode(chanToToggle);
- return true;
- }
-
- return false;
-}
-
-static void scopeTrigger(int32_t ch, const sampleTyp *s, int32_t playOffset)
-{
- scope_t tempState;
-
- volatile scope_t *sc = &scope[ch];
-
- int32_t length = s->len;
- int32_t loopStart = s->repS;
- int32_t loopLength = s->repL;
- int32_t loopEnd = s->repS + s->repL;
- uint8_t loopType = s->typ & 3;
- bool sampleIs16Bit = (s->typ >> 4) & 1;
-
- if (sampleIs16Bit)
- {
- assert(!(length & 1));
- assert(!(loopStart & 1));
- assert(!(loopLength & 1));
- assert(!(loopEnd & 1));
-
- length >>= 1;
- loopStart >>= 1;
- loopLength >>= 1;
- loopEnd >>= 1;
- }
-
- if (s->pek == NULL || length < 1)
- {
- sc->active = false; // shut down scope (illegal parameters)
- return;
- }
-
- if (loopLength < 1) // disable loop if loopLength is below 1
- loopType = 0;
-
- if (sampleIs16Bit)
- tempState.base16 = (const int16_t *)s->pek;
- else
- tempState.base8 = s->pek;
-
- tempState.sampleIs16Bit = sampleIs16Bit;
- tempState.loopType = loopType;
-
- tempState.direction = 1; // forwards
- tempState.end = (loopType > 0) ? loopEnd : length;
- tempState.loopStart = loopStart;
- tempState.loopLength = loopLength;
- tempState.pos = playOffset;
- tempState.posFrac = 0;
-
- // if position overflows (f.ex. through 9xx command), shut down scopes
- if (tempState.pos >= tempState.end)
- {
- sc->active = false;
- return;
- }
-
- // these has to be copied so that they are not lost
- tempState.wasCleared = sc->wasCleared;
- tempState.delta = sc->delta;
- tempState.oldDelta = sc->oldDelta;
- tempState.drawDelta = sc->drawDelta;
- tempState.oldDrawDelta = sc->oldDrawDelta;
- tempState.dOldHz = sc->dOldHz;
- tempState.vol = sc->vol;
-
- tempState.active = true;
-
- /* Update live scope now.
- ** In theory it -can- be written to in the middle of a cached read,
- ** then the read thread writes its own non-updated cached copy back and
- ** the trigger never happens. So far I have never seen it happen,
- ** so it's probably very rare. Yes, this is not good coding...
- */
-
- *sc = tempState;
-}
-
-static void updateScopes(void)
-{
- int32_t loopOverflowVal;
-
- scopesUpdatingFlag = true;
-
- volatile scope_t *sc = scope;
- for (int32_t i = 0; i < song.antChn; i++, sc++)
- {
- scope_t s = *sc; // cache it
- if (!s.active)
- continue; // scope is not active, no need
-
- // scope position update
-
- s.posFrac += s.delta;
- const int32_t wholeSamples = s.posFrac >> 32;
- s.posFrac &= 0xFFFFFFFF;
-
- if (s.direction == 1)
- s.pos += wholeSamples; // forwards
- else
- s.pos -= wholeSamples; // backwards
-
- // handle loop wrapping or sample end
- if (s.direction == -1 && s.pos < s.loopStart) // sampling backwards (definitely pingpong loop)
- {
- s.direction = 1; // change direction to forwards
-
- if (s.loopLength >= 2)
- s.pos = s.loopStart + ((s.loopStart - s.pos - 1) % s.loopLength);
- else
- s.pos = s.loopStart;
-
- assert(s.pos >= s.loopStart && s.pos < s.end);
- }
- else if (s.pos >= s.end)
- {
- if (s.loopLength >= 2)
- loopOverflowVal = (s.pos - s.end) % s.loopLength;
- else
- loopOverflowVal = 0;
-
- if (s.loopType == LOOP_DISABLED)
- {
- s.active = false;
- }
- else if (s.loopType == LOOP_FORWARD)
- {
- s.pos = s.loopStart + loopOverflowVal;
- assert(s.pos >= s.loopStart && s.pos < s.end);
- }
- else // pingpong loop
- {
- s.direction = -1; // change direction to backwards
- s.pos = (s.end - 1) - loopOverflowVal;
- assert(s.pos >= s.loopStart && s.pos < s.end);
- }
- }
- assert(s.pos >= 0);
-
- *sc = s; // update scope state
- }
- scopesUpdatingFlag = false;
-}
-
-void drawScopes(void)
-{
- scopesDisplayingFlag = true;
- int32_t chansPerRow = (uint32_t)song.antChn >> 1;
-
- const uint16_t *scopeLens = scopeLenTab[chansPerRow-1];
- uint16_t scopeXOffs = 3;
- uint16_t scopeYOffs = 95;
- int16_t scopeLineY = 112;
-
- for (int32_t i = 0; i < song.antChn; i++)
- {
- // if we reached the last scope on the row, go to first scope on the next row
- if (i == chansPerRow)
- {
- scopeXOffs = 3;
- scopeYOffs = 134;
- scopeLineY = 151;
- }
-
- const uint16_t scopeDrawLen = scopeLens[i];
- if (!editor.chnMode[i]) // scope muted (mute graphics blit()'ed elsewhere)
- {
- scopeXOffs += scopeDrawLen+3; // align x to next scope
- continue;
- }
-
- const scope_t s = scope[i]; // cache scope to lower thread race condition issues
- if (s.active && s.vol > 0 && !audio.locked)
- {
- // scope is active
- scope[i].wasCleared = false;
-
- // clear scope background
- clearRect(scopeXOffs, scopeYOffs, scopeDrawLen, SCOPE_HEIGHT);
-
- // draw scope
- bool linedScopesFlag = !!(config.specialFlags & LINED_SCOPES);
- scopeDrawRoutineTable[(linedScopesFlag * 6) + (s.sampleIs16Bit * 3) + s.loopType](&s, scopeXOffs, scopeLineY, scopeDrawLen);
- }
- else
- {
- // scope is inactive
- volatile scope_t *sc = &scope[i];
- if (!sc->wasCleared)
- {
- // clear scope background
- clearRect(scopeXOffs, scopeYOffs, scopeDrawLen, SCOPE_HEIGHT);
-
- // draw empty line
- hLine(scopeXOffs, scopeLineY, scopeDrawLen, PAL_PATTEXT);
-
- sc->wasCleared = true;
- }
- }
-
- // draw channel numbering (if enabled)
- if (config.ptnChnNumbers)
- drawScopeNumber(scopeXOffs, scopeYOffs, (uint8_t)i, false);
-
- // draw rec. symbol (if enabled)
- if (config.multiRecChn[i])
- blit(scopeXOffs + 1, scopeYOffs + 31, bmp.scopeRec, 13, 4);
-
- scopeXOffs += scopeDrawLen+3; // align x to next scope
- }
-
- scopesDisplayingFlag = false;
-}
-
-void drawScopeFramework(void)
-{
- drawFramework(0, 92, 291, 81, FRAMEWORK_TYPE1);
- for (int32_t i = 0; i < song.antChn; i++)
- redrawScope(i);
-}
-
-void handleScopesFromChQueue(chSyncData_t *chSyncData, uint8_t *scopeUpdateStatus)
-{
- volatile scope_t *sc = scope;
- syncedChannel_t *ch = chSyncData->channels;
- for (int32_t i = 0; i < song.antChn; i++, sc++, ch++)
- {
- const uint8_t status = scopeUpdateStatus[i];
-
- if (status & IS_Vol)
- sc->vol = ((ch->vol * SCOPE_HEIGHT) + 128) >> 8; // rounded
-
- if (status & IS_Period)
- {
- // use cached values when possible
- if (ch->dHz != sc->dOldHz)
- {
- sc->dOldHz = ch->dHz;
-
- const double dHz2ScopeDeltaMul = SCOPE_FRAC_SCALE / (double)SCOPE_HZ;
- sc->oldDelta = (int64_t)((ch->dHz * dHz2ScopeDeltaMul) + 0.5); // Hz -> 32.32fp delta (rounded)
-
- const double dRelativeHz = ch->dHz * (1.0 / (8363.0 / 2.0));
- sc->oldDrawDelta = (int32_t)((dRelativeHz * SCOPE_DRAW_FRAC_SCALE) + 0.5); // Hz -> 13.19fp draw delta (rounded)
- }
-
- sc->delta = sc->oldDelta;
- sc->drawDelta = sc->oldDrawDelta;
- }
-
- if (status & IS_NyTon)
- {
- if (instr[ch->instrNr] != NULL)
- {
- scopeTrigger(i, &instr[ch->instrNr]->samp[ch->sampleNr], ch->smpStartPos);
-
- // set some stuff used by Smp. Ed. for sampling position line
-
- if (ch->instrNr == 130 || (ch->instrNr == editor.curInstr && ch->sampleNr == editor.curSmp))
- editor.curSmpChannel = (uint8_t)i;
-
- lastChInstr[i].instrNr = ch->instrNr;
- lastChInstr[i].sampleNr = ch->sampleNr;
- }
- else
- {
- // empty instrument, shut down scope
- scope[i].active = false;
- lastChInstr[i].instrNr = 255;
- lastChInstr[i].sampleNr = 255;
- }
- }
- }
-}
-
-static int32_t SDLCALL scopeThreadFunc(void *ptr)
-{
- // this is needed for scope stability (confirmed)
- SDL_SetThreadPriority(SDL_THREAD_PRIORITY_HIGH);
-
- // set next frame time
- timeNext64 = SDL_GetPerformanceCounter() + scopeTimeLen;
- timeNext64Frac = scopeTimeLenFrac;
-
- while (editor.programRunning)
- {
- editor.scopeThreadMutex = true;
- updateScopes();
- editor.scopeThreadMutex = false;
-
- uint64_t time64 = SDL_GetPerformanceCounter();
- if (time64 < timeNext64)
- {
- time64 = timeNext64 - time64;
- if (time64 > INT32_MAX)
- time64 = INT32_MAX;
-
- const int32_t diff32 = (int32_t)time64;
-
- // convert and round to microseconds
- const int32_t time32 = (int32_t)((diff32 * editor.dPerfFreqMulMicro) + 0.5);
-
- // delay until we have reached the next frame
- if (time32 > 0)
- usleep(time32);
- }
-
- // update next tick time
- timeNext64 += scopeTimeLen;
- timeNext64Frac += scopeTimeLenFrac;
- if (timeNext64Frac > UINT32_MAX)
- {
- timeNext64Frac &= UINT32_MAX;
- timeNext64++;
- }
- }
-
- (void)ptr;
- return true;
-}
-
-bool initScopes(void)
-{
- double dInt;
-
- // calculate scope time for performance counters and split into int/frac
- double dFrac = modf(editor.dPerfFreq / SCOPE_HZ, &dInt);
-
- // integer part
- scopeTimeLen = (int32_t)dInt;
-
- // fractional part (scaled to 0..2^32-1)
- dFrac *= UINT32_MAX+1.0;
- scopeTimeLenFrac = (uint32_t)dFrac;
-
- scopeThread = SDL_CreateThread(scopeThreadFunc, NULL, NULL);
- if (scopeThread == NULL)
- {
- showErrorMsgBox("Couldn't create channel scope thread!");
- return false;
- }
-
- SDL_DetachThread(scopeThread);
- return true;
-}
--- a/src/ft2_scopes.h
+++ /dev/null
@@ -1,48 +1,0 @@
-#pragma once
-
-#include <stdint.h>
-#include <stdbool.h>
-#include "ft2_header.h"
-#include "ft2_audio.h"
-
-#define SCOPE_HEIGHT 36
-
-#define SCOPE_FRAC_BITS 32
-#define SCOPE_FRAC_SCALE (1ULL << SCOPE_FRAC_BITS)
-#define SCOPE_FRAC_MASK (SCOPE_FRAC_SCALE-1)
-
-// *absolute* max safe bits (Amiga periods, period 1), don't mess with it!
-#define SCOPE_DRAW_FRAC_BITS 19
-#define SCOPE_DRAW_FRAC_SCALE (1UL << SCOPE_DRAW_FRAC_BITS)
-#define SCOPE_DRAW_FRAC_MASK (SCOPE_DRAW_FRAC_SCALE-1)
-
-void resetCachedScopeVars(void);
-int32_t getSamplePosition(uint8_t ch);
-void stopAllScopes(void);
-void refreshScopes(void);
-bool testScopesMouseDown(void);
-void drawScopes(void);
-void drawScopeFramework(void);
-bool initScopes(void);
-
-// actual scope data
-typedef struct scope_t
-{
- volatile bool active;
- const int8_t *base8;
- const int16_t *base16;
- bool wasCleared, sampleIs16Bit;
- uint8_t loopType;
- int32_t vol, loopStart, loopLength, end, pos, direction;
- uint32_t drawDelta, oldDrawDelta;
- uint64_t delta, oldDelta, posFrac;
-
- double dOldHz;
-} scope_t;
-
-typedef struct lastChInstr_t
-{
- uint8_t sampleNr, instrNr;
-} lastChInstr_t;
-
-extern lastChInstr_t lastChInstr[MAX_VOICES];
--- a/src/ft2_structs.h
+++ b/src/ft2_structs.h
@@ -22,16 +22,16 @@
bool autoPlayOnDrop, trimThreadWasDone, throwExit, editTextFlag;
bool copyMaskEnable, diskOpReadOnOpen, samplingAudioFlag, editSampleFlag;
- bool instrBankSwapped, chnMode[MAX_VOICES], NI_Play;
+ bool instrBankSwapped, chnMode[MAX_CHANNELS], NI_Play;
uint8_t curPlayInstr, curPlaySmp, curSmpChannel, currPanEnvPoint, currVolEnvPoint;
uint8_t copyMask[5], pasteMask[5], transpMask[5], smpEd_NoteNr, instrBankOffset, sampleBankOffset;
uint8_t srcInstr, curInstr, srcSmp, curSmp, currHelpScreen, currConfigScreen, textCursorBlinkCounter;
- uint8_t keyOnTab[MAX_VOICES], ID_Add, curOctave;
+ uint8_t keyOnTab[MAX_CHANNELS], editRowSkip, curOctave;
uint8_t sampleSaveMode, moduleSaveMode, ptnJumpPos[4];
- int16_t globalVol, songPos, pattPos;
- uint16_t tmpPattern, editPattern, speed, tempo, timer, ptnCursorY;
- int32_t keyOffNr, keyOffTime[MAX_VOICES];
+ int16_t globalVolume, songPos, row;
+ uint16_t tmpPattern, editPattern, BPM, speed, tick, ptnCursorY;
+ int32_t keyOffNr, keyOffTime[MAX_CHANNELS];
uint32_t framesPassed, wavRendererTime;
double dPerfFreq, dPerfFreqMulMicro, dPerfFreqMulMs;
} editor_t;
--- a/src/ft2_sysreqs.c
+++ b/src/ft2_sysreqs.c
@@ -54,7 +54,7 @@
typedef struct quitType_t
{
const char *text;
- uint8_t typ;
+ uint8_t type;
} quitType_t;
#define QUIT_MESSAGES 11
@@ -180,7 +180,7 @@
}
// WARNING: This routine must ONLY be called from the main input/video thread!
-int16_t okBox(int16_t typ, const char *headline, const char *text)
+int16_t okBox(int16_t type, const char *headline, const char *text)
{
#define PUSHBUTTON_W 80
@@ -207,9 +207,9 @@
int16_t oldLastUsedObjectType = mouse.lastUsedObjectType;
// count number of buttons
- uint16_t knp = 0;
- while (buttonText[typ][knp][0] != '\0' && knp < 5)
- knp++;
+ uint16_t numButtons = 0;
+ while (buttonText[type][numButtons][0] != '\0' && numButtons < 5)
+ numButtons++;
uint16_t tlen = textWidth(text);
uint16_t hlen = textWidth(headline);
@@ -218,7 +218,7 @@
if (hlen > tlen)
wlen = hlen;
- uint16_t tx = (knp * 100) - 20;
+ uint16_t tx = (numButtons * 100) - 20;
if (tx > wlen)
wlen = tx;
@@ -234,7 +234,7 @@
uint16_t y = ui.extended ? SYSTEM_REQUEST_Y_EXT : SYSTEM_REQUEST_Y;
// set up buttons
- for (i = 0; i < knp; i++)
+ for (i = 0; i < numButtons; i++)
{
p = &pushButtons[i];
@@ -242,12 +242,12 @@
p->y = y + 42;
p->w = PUSHBUTTON_W;
p->h = 16;
- p->caption = buttonText[typ][i];
+ p->caption = buttonText[type][i];
p->visible = true;
}
// set up checkbox (special okBox types only!)
- if (typ >= 6 && typ <= 7)
+ if (type >= 6 && type <= 7)
{
checkBox_t *c = &checkBoxes[0];
c->x = x + 5;
@@ -256,12 +256,12 @@
c->clickAreaHeight = 12;
c->checked = false;
- if (typ == 6)
+ if (type == 6)
{
// S3M load warning
c->callbackFunc = configToggleImportWarning;
}
- else if (typ == 7)
+ else if (type == 7)
{
// "setting not yet applied"
c->callbackFunc = configToggleNotYetAppliedWarning;
@@ -312,9 +312,9 @@
keyb.ignoreCurrKeyUp = true; // don't handle key up event for any keys that were pressed
}
- for (i = 0; i < knp; i++)
+ for (i = 0; i < numButtons; i++)
{
- if (shortCut[typ][i] == inputEvent.key.keysym.sym)
+ if (shortCut[type][i] == inputEvent.key.keysym.sym)
{
returnVal = i + 1;
ui.sysReqShown = false;
@@ -327,7 +327,7 @@
{
if (mouseButtonUpLogic(inputEvent.button.button))
{
- if (typ >= 6 && typ <= 7)
+ if (type >= 6 && type <= 7)
testCheckBoxMouseRelease();
returnVal = testPushButtonMouseRelease(false) + 1;
@@ -360,8 +360,8 @@
drawWindow(wlen);
textOutShadow(headlineX, y + 4, PAL_FORGRND, PAL_BUTTON2, headline);
textOutShadow(textX, y + 24, PAL_FORGRND, PAL_BUTTON2, text);
- for (i = 0; i < knp; i++) drawPushButton(i);
- if (typ >= 6 && typ <= 7)
+ for (i = 0; i < numButtons; i++) drawPushButton(i);
+ if (type >= 6 && type <= 7)
{
drawCheckBox(0);
textOutShadow(x + 21, y + 52, PAL_FORGRND, PAL_BUTTON2, "Don't show again");
@@ -371,10 +371,10 @@
endFPSCounter();
}
- for (i = 0; i < knp; i++)
+ for (i = 0; i < numButtons; i++)
hidePushButton(i);
- if (typ >= 6 && typ <= 7)
+ if (type >= 6 && type <= 7)
hideCheckBox(0);
mouse.lastUsedObjectID = oldLastUsedObjectID;
@@ -391,7 +391,7 @@
** - This routine must ONLY be called from the main input/video thread!!
** - edText must be null-terminated
*/
-int16_t inputBox(int16_t typ, const char *headline, char *edText, uint16_t maxStrLen)
+int16_t inputBox(int16_t type, const char *headline, char *edText, uint16_t maxStrLen)
{
#define PUSHBUTTON_W 80
#define TEXTBOX_W 250
@@ -443,15 +443,15 @@
uint16_t headlineX = (SCREEN_W - wlen) >> 1;
// count number of buttons
- uint16_t knp = 0;
- while (buttonText[typ][knp][0] != '\0' && knp < 5)
- knp++;
+ uint16_t numButtons = 0;
+ while (buttonText[type][numButtons][0] != '\0' && numButtons < 5)
+ numButtons++;
uint16_t tx = TEXTBOX_W;
if (tx > wlen)
wlen = tx;
- tx = (knp * 100) - 20;
+ tx = (numButtons * 100) - 20;
if (tx > wlen)
wlen = tx;
@@ -470,13 +470,13 @@
// setup buttons
pushButton_t *p = pushButtons;
- for (i = 0; i < knp; i++, p++)
+ for (i = 0; i < numButtons; i++, p++)
{
p->w = PUSHBUTTON_W;
p->h = 16;
p->x = ((SCREEN_W - tx) >> 1) + (i * 100);
p->y = y + 42;
- p->caption = buttonText[typ][i];
+ p->caption = buttonText[type][i];
p->visible = true;
}
@@ -553,7 +553,7 @@
}
else
{
- for (i = 0; i < knp; i++)
+ for (i = 0; i < numButtons; i++)
{
if (shortCut[1][i] == inputEvent.key.keysym.sym)
{
@@ -604,7 +604,7 @@
hLine(t->x, t->y + t->h, t->w + 1, PAL_BUTTON1);
vLine(t->x + t->w, t->y, t->h, PAL_BUTTON1);
drawTextBox(0);
- for (i = 0; i < knp; i++) drawPushButton(i);
+ for (i = 0; i < numButtons; i++) drawPushButton(i);
flipFrame();
endFPSCounter();
@@ -613,7 +613,7 @@
editor.editTextFlag = false;
SDL_StopTextInput();
- for (i = 0; i < knp; i++)
+ for (i = 0; i < numButtons; i++)
hidePushButton(i);
hideTextBox(0);
@@ -630,7 +630,7 @@
}
// WARNING: This routine must NOT be called from the main input/video thread!
-int16_t okBoxThreadSafe(int16_t typ, const char *headline, const char *text)
+int16_t okBoxThreadSafe(int16_t type, const char *headline, const char *text)
{
if (!editor.mainLoopOngoing)
return 0; // main loop was not even started yet, bail out.
@@ -639,7 +639,7 @@
while (okBoxData.active)
SDL_Delay(1000 / VBLANK_HZ);
- okBoxData.typ = typ;
+ okBoxData.type = type;
okBoxData.headline = headline;
okBoxData.text = text;
okBoxData.active = true;
@@ -653,7 +653,7 @@
static bool askQuit_RandomMsg(void)
{
uint8_t msg = rand() % QUIT_MESSAGES;
- int16_t button = okBox(quitMessage[msg].typ, "System request", quitMessage[msg].text);
+ int16_t button = okBox(quitMessage[msg].type, "System request", quitMessage[msg].text);
return (button == 1) ? true : false;
}
--- a/src/ft2_sysreqs.h
+++ b/src/ft2_sysreqs.h
@@ -13,14 +13,14 @@
typedef struct okBoxData_t
{
volatile bool active;
- int16_t typ, returnData;
+ int16_t type, returnData;
const char *headline, *text;
} okBoxData_t;
-int16_t okBoxThreadSafe(int16_t typ, const char *headline, const char *text);
-int16_t okBox(int16_t typ, const char *headline, const char *text);
+int16_t okBoxThreadSafe(int16_t type, const char *headline, const char *text);
+int16_t okBox(int16_t type, const char *headline, const char *text);
int16_t quitBox(bool skipQuitMsg);
-int16_t inputBox(int16_t typ, const char *headline, char *edText, uint16_t maxStrLen);
+int16_t inputBox(int16_t type, const char *headline, char *edText, uint16_t maxStrLen);
bool askUnsavedChanges(uint8_t type);
void myLoaderMsgBoxThreadSafe(const char *fmt, ...);
--- a/src/ft2_tables.c
+++ b/src/ft2_tables.c
@@ -2,7 +2,7 @@
#include <stdbool.h>
#include "ft2_palette.h" // pal16 typedef
#include "ft2_pattern_ed.h" // pattCoord_t/pattCoord2_t/pattCoordsMouse_t/markCoord_t typedef
-#include "ft2_header.h" // MAX_VOICES
+#include "ft2_header.h" // MAX_CHANNELS
#include "ft2_config.h" // CONFIG_FILE_SIZE
#include "ft2_bmp.h"
@@ -694,7 +694,7 @@
};
// these two are for channel numbering on pattern data/scopes
-const char chDecTab1[MAX_VOICES+1] =
+const char chDecTab1[MAX_CHANNELS+1] =
{
'0', '0', '0', '0', '0', '0', '0', '0', '0', '0',
'1', '1', '1', '1', '1', '1', '1', '1', '1', '1',
@@ -702,7 +702,7 @@
'3', '3', '3'
};
-const char chDecTab2[MAX_VOICES+1] =
+const char chDecTab2[MAX_CHANNELS+1] =
{
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
@@ -872,176 +872,50 @@
/* ----------------------------------------------------------------------- */
/*
-** const double dBpmMs1024 = 1024.0 / (bpm / 2.5); // milliseconds (scaled from 1000 to 1024)
-** x = (uint64_t)floor((UINT32_MAX+1.0) * dBpmMs1024);
+** for (int32_t bpm = 32; bpm <= 255; bpm++)
+** {
+** const double dBpmMs1024 = 1024.0 / (bpm / 2.5); // milliseconds (scaled from 1000 to 1024)
+** uint64_t x = (uint64_t)floor((UINT32_MAX+1.0) * dBpmMs1024);
+** }
*/
-const uint64_t musicTimeTab64[MAX_BPM+1] =
+const uint64_t musicTimeTab64[(MAX_BPM-MIN_BPM)+1] =
{
- 0x00000000000,0xA0000000000,0x50000000000,0x35555555555,0x28000000000,0x20000000000,
- 0x1AAAAAAAAAA,0x16DB6DB6DB6,0x14000000000,0x11C71C71C71,0x10000000000,0x0E8BA2E8BA2,
- 0x0D555555555,0x0C4EC4EC4EC,0x0B6DB6DB6DB,0x0AAAAAAAAAA,0x0A000000000,0x09696969696,
- 0x08E38E38E38,0x086BCA1AF28,0x08000000000,0x079E79E79E7,0x0745D1745D1,0x06F4DE9BD37,
- 0x06AAAAAAAAA,0x06666666666,0x06276276276,0x05ED097B425,0x05B6DB6DB6D,0x058469EE584,
- 0x05555555555,0x05294A5294A,0x05000000000,0x04D9364D936,0x04B4B4B4B4B,0x04924924924,
- 0x0471C71C71C,0x045306EB3E4,0x0435E50D794,0x041A41A41A4,0x04000000000,0x03E7063E706,
- 0x03CF3CF3CF3,0x03B88EE23B8,0x03A2E8BA2E8,0x038E38E38E3,0x037A6F4DE9B,0x03677D46CEF,
- 0x03555555555,0x0343EB1A1F5,0x03333333333,0x03232323232,0x0313B13B13B,0x0304D4873EC,
- 0x02F684BDA12,0x02E8BA2E8BA,0x02DB6DB6DB6,0x02CE98B3A62,0x02C234F72C2,0x02B63CBEEA4,
- 0x02AAAAAAAAA,0x029F79B4758,0x0294A5294A5,0x028A28A28A2,0x02800000000,0x02762762762,
- 0x026C9B26C9B,0x026357E16EC,0x025A5A5A5A5,0x02519F89467,0x02492492492,0x0240E6C2B44,
- 0x0238E38E38E,0x0231188C462,0x022983759F2,0x02222222222,0x021AF286BCA,0x0213F2B3884,
- 0x020D20D20D2,0x02067B23A54,0x02000000000,0x01F9ADD3C0C,0x01F3831F383,0x01ED7E75346,
- 0x01E79E79E79,0x01E1E1E1E1E,0x01DC47711DC,0x01D6CDFA1D6,0x01D1745D174,0x01CC398730E,
- 0x01C71C71C71,0x01C21C21C21,0x01BD37A6F4D,0x01B86E1B86E,0x01B3BEA3677,0x01AF286BCA1,
- 0x01AAAAAAAAA,0x01A6449E59B,0x01A1F58D0FA,0x019DBCC4867,0x01999999999,0x01958B67EBB,
- 0x01919191919,0x018DAB7EC1D,0x0189D89D89D,0x01861861861,0x01826A439F6,0x017ECDC1CB5,
- 0x017B425ED09,0x0177C7A20E1,0x01745D1745D,0x0171024E6A1,0x016DB6DB6DB,0x016A7A5616A,
- 0x01674C59D31,0x01642C8590B,0x01611A7B961,0x015E15E15E1,0x015B1E5F752,0x015833A1583,
- 0x01555555555,0x0152832C6E0,0x014FBCDA3AC,0x014D0214D02,0x014A5294A52,0x0147AE147AE,
- 0x01451451451,0x0142850A142,0x01400000000,0x013D84F613D,0x013B13B13B1,0x0138ABF82EE,
- 0x01364D9364D,0x0133F84CFE1,0x0131ABF0B76,0x012F684BDA1,0x012D2D2D2D2,0x012AFA64E7B,
- 0x0128CFC4A33,0x0126AD1F4F3,0x01249249249,0x01227F179A5,0x012073615A2,0x011E6EFE35B,
- 0x011C71C71C7,0x011A7B9611A,0x01188C46231,0x0116A3B35FC,0x0114C1BACF9,0x0112E63A6A8,
- 0x01111111111,0x010F421E843,0x010D79435E5,0x010BB6610BB,0x0109F959C42,0x01084210842,
- 0x01069069069,0x0104E447BEC,0x01033D91D2A,0x01019C2D14E,0x01000000000,0x00FE68F1B07,
- 0x00FCD6E9E06,0x00FB49D0E22,0x00F9C18F9C1,0x00F83E0F83E,0x00F6BF3A9A3,0x00F544FB66B,
- 0x00F3CF3CF3C,0x00F25DEACAF,0x00F0F0F0F0F,0x00EF883BE20,0x00EE23B88EE,0x00ECC35458C,
- 0x00EB66FD0EB,0x00EA0EA0EA0,0x00E8BA2E8BA,0x00E76994F8C,0x00E61CC3987,0x00E4D3AA30A,
- 0x00E38E38E38,0x00E24C602D4,0x00E10E10E10,0x00DFD33C272,0x00DE9BD37A6,0x00DD67C8A60,
- 0x00DC370DC37,0x00DB0995382,0x00D9DF51B3B,0x00D8B8362E0,0x00D79435E50,0x00D673445B2,
- 0x00D55555555,0x00D43A5CD98,0x00D3224F2CD,0x00D20D20D20,0x00D0FAC687D,0x00CFEB35477,
- 0x00CEDE62433,0x00CDD442E4F,0x00CCCCCCCCC,0x00CBC7F5CF9,0x00CAC5B3F5D,0x00C9C5FD7A5,
- 0x00C8C8C8C8C,0x00C7CE0C7CE,0x00C6D5BF60E,0x00C5DFD86CD,0x00C4EC4EC4E,0x00C3FB19B8F,
- 0x00C30C30C30,0x00C21F8B86A,0x00C13521CFB,0x00C04CEB916,0x00BF66E0E5A,0x00BE82FA0BE,
- 0x00BDA12F684,0x00BCC17982F,0x00BBE3D1070,0x00BB082EC20,0x00BA2E8BA2E,0x00B956E0B95,
- 0x00B88127350,0x00B7AD58650,0x00B6DB6DB6D,0x00B60B60B60,0x00B53D2B0B5,0x00B470C67C0,
- 0x00B3A62CE98,0x00B2DD58507,0x00B21642C85,0x00B150E682C,0x00B08D3DCB0,0x00AFCB43057,
- 0x00AF0AF0AF0,0x00AE4C415C9,0x00AD8F2FBA9,0x00ACD3B68C6,0x00AC19D0AC1,0x00AB617909A,
- 0x00AAAAAAAAA,0x00A9F560A9F,0x00A94196370,0x00A88F46959,0x00A7DE6D1D6,0x00A72F05397,
- 0x00A6810A681,0x00A5D4783A0,0x00A5294A529,0x00A47F7C66C,0x00A3D70A3D7,0x00A32FEFAE6,
- 0x00A28A28A28,0x00A1E5B1133,0x00A142850A1,0x00A0A0A0A0A,0x00A00000000,0x009F609F609,
- 0x009EC27B09E,0x009E258F520,0x009D89D89D8,0x009CEF535F2,0x009C55FC177,0x009BBDCF54A,
- 0x009B26C9B26,0x009A90E7D95,0x0099FC267F0,0x0099688265A,0x0098D5F85BB,0x009844853BF,
- 0x0097B425ED0,0x009724D7614,0x00969696969,0x00960960960,0x00957D3273D,0x0094F2094F2,
- 0x009467E2519,0x0093DEBAAF9,0x0093568FA79,0x0092CF5E824,0x00924924924,0x0091C3DF33E,
- 0x00913F8BCD2,0x0090BC27CD5,0x009039B0AD1,0x008FB823EE0,0x008F377F1AD,0x008EB7BFC6E,
- 0x008E38E38E3,0x008DBAE8154,0x008D3DCB08D,0x008CC18A1DE,0x008C4623118,0x008BCB93A8A,
- 0x008B51D9AFE,0x008AD8F2FBA,0x008A60DD67C,0x0089E996D77,0x0089731D354,0x0088FD6E72B,
- 0x00888888888,0x00881469763,0x0087A10F421,0x00872E77F93,0x0086BCA1AF2,0x00864B8A7DE,
- 0x0085DB3085D,0x00856B91EDA,0x0084FCACE21,0x00848E7F95F,0x00842108421,0x0083B445250,
- 0x00834834834,0x0082DCD4A6D,0x00827223DF6,0x00820820820,0x00819EC8E95,0x0081361B751,
- 0x0080CE168A7,0x008066B893A,0x00800000000,0x007F99EB43C,0x007F3478D83,0x007ECFA73B7,
- 0x007E6B74F03,0x007E07E07E0,0x007DA4E8711,0x007D428B5A0,0x007CE0C7CE0,0x007C7F9C66B,
- 0x007C1F07C1F,0x007BBF0881E,0x007B5F9D4D1,0x007B00C4CE0,0x007AA27DB35,0x007A44C6AFC,
- 0x0079E79E79E,0x00798B03CC5,0x00792EF5657,0x0078D372078,0x00787878787,0x00781E0781E,
- 0x0077C41DF10,0x00776ABA96C,0x007711DC477,0x0076B981DAE,0x007661AA2C6,0x00760A541A8,
- 0x0075B37E875,0x00755D28580,0x00750750750,0x0074B1F5CA0,0x00745D1745D,0x007408B3DA4,
- 0x0073B4CA7C6,0x0073615A240,0x00730E61CC3,0x0072BBE072B,0x007269D5185,0x0072183EC08,
- 0x0071C71C71C,0x0071766D352,0x0071263016A,0x0070D66424A,0x00708708708,0x0070381C0E0,
- 0x006FE99E139,0x006F9B8D9A2,0x006F4DE9BD3,0x006F00B19AB,0x006EB3E4530,0x006E678108F,
- 0x006E1B86E1B,0x006DCFF504C,0x006D84CA9C1,0x006D3A06D3A,0x006CEFA8D9D,0x006CA5AFDF6,
- 0x006C5C1B170,0x006C12E9B5B,0x006BCA1AF28,0x006B81AE06B,0x006B39A22D9,0x006AF1F6A46,
- 0x006AAAAAAAA,0x006A63BD81A,0x006A1D2E6CC,0x0069D6FCB14,0x00699127966,0x00694BAE655,
- 0x00690690690,0x0068C1CCEE5,0x00687D6343E,0x00683952BA4,0x0067F59AA3B,0x0067B23A544,
- 0x00676F31219,0x00672C7E634,0x0066EA21727,0x0066A819AA0,0x00666666666,0x0066250705B,
- 0x0065E3FAE7C,0x0065A3416DE,0x006562D9FAE,0x006522C3F35,0x0064E2FEBD2,0x0064A389BFD,
- 0x00646464646,0x0064258E154,0x0063E7063E7,0x0063A8CC4D3,0x00636ADFB07,0x00632D3FD85,
- 0x0062EFEC366,0x0062B2E43DA,0x00627627627,0x006239B51A6,0x0061FD8CDC7,0x0061C1AE20F,
- 0x00618618618,0x00614ACB18E,0x00610FC5C35,0x0060D507DE1,0x00609A90E7D,0x00606060606,
- 0x00602675C8B,0x005FECD0A31,0x005FB37072D,0x005F7A54BC9,0x005F417D05F,0x005F08E8D5D,
- 0x005ED097B42,0x005E988929F,0x005E60BCC17,0x005E293205E,0x005DF1E8838,0x005DBADFC7C,
- 0x005D8417610,0x005D4D8EDEC,0x005D1745D17,0x005CE13BCA9,0x005CAB705CA,0x005C75E31B2,
- 0x005C40939A8,0x005C0B81702,0x005BD6AC328,0x005BA21378D,0x005B6DB6DB6,0x005B3995F37,
- 0x005B05B05B0,0x005AD205AD2,0x005A9E9585A,0x005A6B5F816,0x005A38633E0,0x005A05A05A0,
- 0x0059D31674C,0x0059A0C52E7,0x00596EAC283,0x00593CCB03E,0x00590B21642,0x0058D9AEEC9,
- 0x0058A873416,0x0058776E07B,0x0058469EE58,0x00581605816,0x0057E5A182B,0x0057B57291D,
- 0x00578578578,0x005755B27D8,0x00572620AE4,0x0056F6C294E,0x0056C797DD4,0x005698A033F,
- 0x005669DB463,0x00563B48C20,0x00560CE8560,0x0055DEB9B1A,0x0055B0BC84D,0x005582F0804,
- 0x00555555555,0x005527EAB60,0x0054FAB054F,0x0054CDA5E57,0x0054A0CB1B8,0x0054741FAB8,
- 0x005447A34AC,0x00541B55AF0,0x0053EF368EB,0x0053C345A0B,0x005397829CB,0x00536BED3AE,
- 0x00534085340,0x0053154A416,0x0052EA3C1D0,0x0052BF5A814,0x005294A5294,0x00526A1BD09,
- 0x00523FBE336,0x0052158C0E5,0x0051EB851EB,0x0051C1A9223,0x005197F7D73,0x00516E70FC6,
- 0x00514514514,0x00511BE1958,0x0050F2D8899,0x0050C9F8EE5,0x0050A142850,0x005078B50F9,
- 0x00505050505,0x005028140A0,0x00500000000,0x004FD813F60,0x004FB04FB04,0x004F88B2F39,
- 0x004F613D84F,0x004F39EF2A1,0x004F12C7A90,0x004EEBC6C84,0x004EC4EC4EC,0x004E9E3803E,
- 0x004E77A9AF9,0x004E514119F,0x004E2AFE0BB,0x004E04E04E0,0x004DDEE7AA5,0x004DB913EAA,
- 0x004D9364D93,0x004D6DDA40D,0x004D4873ECA,0x004D2331A84,0x004CFE133F8,0x004CD9187EC,
- 0x004CB44132D,0x004C8F8D28A,0x004C6AFC2DD,0x004C468E103,0x004C22429DF,0x004BFE19A5C,
- 0x004BDA12F68,0x004BB62E5F9,0x004B926BB0A,0x004B6ECAB9C,0x004B4B4B4B4,0x004B27ED360,
- 0x004B04B04B0,0x004AE1945BB,0x004ABE9939E,0x004A9BBEB7B,0x004A7904A79,0x004A566ADC3,
- 0x004A33F128C,0x004A119760C,0x0049EF5D57C,0x0049CD42E20,0x0049AB47D3C,0x0049896C01D,
- 0x004967AF412,0x00494611670,0x00492492492,0x00490331BD6,0x0048E1EF99F,0x0048C0CBB56,
- 0x00489FC5E69,0x00487EDE048,0x00485E13E6A,0x00483D6764A,0x00481CD8568,0x0047FC66947,
- 0x0047DC11F70,0x0047BBDA56F,0x00479BBF8D6,0x00477BC173B,0x00475BDFE37,0x00473C1AB68,
- 0x00471C71C71,0x0046FCE4EF9,0x0046DD740AA,0x0046BE1EF32,0x00469EE5846,0x00467FC799C,
- 0x004660C50EF,0x004641DDBFE,0x0046231188C,0x00460460460,0x0045E5C9D45,0x0045C74E109,
- 0x0045A8ECD7F,0x00458AA607D,0x00456C797DD,0x00454E6717D,0x0045306EB3E,0x00451290305,
- 0x0044F4CB6BB,0x0044D72044D,0x0044B98E9AA,0x00449C164C5,0x00447EB7395,0x00446171416,
- 0x00444444444,0x00442730221,0x00440A34BB1,0x0043ED51EFD,0x0043D087A10,0x0043B3D5AF9,
- 0x0043973BFC9,0x00437ABA696,0x00435E50D79,0x004341FF28C,0x004325C53EF,0x004309A2FC3,
- 0x0042ED9842E,0x0042D1A4F58,0x0042B5C8F6D,0x00429A0429A,0x00427E56710,0x004262BFB05,
- 0x0042473FCAF,0x00422BD6A49,0x00421084210,0x0041F548244,0x0041DA22928,0x0041BF13502,
- 0x0041A41A41A,0x004189374BC,0x00416E6A536,0x004153B33DA,0x00413911EFB,0x00411E864EF,
- 0x00410410410,0x0040E9AFAB9,0x0040CF6474A,0x0040B52E823,0x00409B0DBA8,0x00408102040,
- 0x0040670B453,0x00404D2964D,0x0040335C49D,0x004019A3DB2,0x00400000000,0x003FE6709FC,
- 0x003FCCF5A1E,0x003FB38EEE1,0x003F9A3C6C1,0x003F80FE03F,0x003F67D39DB,0x003F4EBD21A,
- 0x003F35BA781,0x003F1CCB89A,0x003F03F03F0,0x003EEB2880F,0x003ED274388,0x003EB9D34EC,
- 0x003EA145AD0,0x003E88CB3C9,0x003E7063E70,0x003E580F960,0x003E3FCE335,0x003E279FA8F,
- 0x003E0F83E0F,0x003DF77AC58,0x003DDF8440F,0x003DC7A03DC,0x003DAFCEA68,0x003D980F660,
- 0x003D8062670,0x003D68C7948,0x003D513ED9A,0x003D39C821A,0x003D226357E,0x003D0B1067C,
- 0x003CF3CF3CF,0x003CDC9FC32,0x003CC581E62,0x003CAE75920,0x003C977AB2B,0x003C8091348,
- 0x003C69B903C,0x003C52F20CD,0x003C3C3C3C3,0x003C25977EA,0x003C0F03C0F,0x003BF880EFE,
- 0x003BE20EF88,0x003BCBADC7F,0x003BB55D4B6,0x003B9F1D702,0x003B88EE23B,0x003B72CF539,
- 0x003B5CC0ED7,0x003B46C2DF0,0x003B30D5163,0x003B1AF780E,0x003B052A0D4,0x003AEF6CA97,
- 0x003AD9BF43A,0x003AC421CA6,0x003AAE942C0,0x003A9916572,0x003A83A83A8,0x003A6E49C4D,
- 0x003A58FAE50,0x003A43BB8A0,0x003A2E8BA2E,0x003A196B1ED,0x003A0459ED2,0x0039EF57FD1,
- 0x0039DA653E3,0x0039C5819FF,0x0039B0AD120,0x00399BE7842,0x00398730E61,0x0039728927D,
- 0x00395DF0395,0x003949660AB,0x003934EA8C2,0x0039207DADE,0x00390C1F604,0x0038F7CF93C,
- 0x0038E38E38E,0x0038CF5B404,0x0038BB369A9,0x0038A72038A,0x003893180B5,0x00387F1E038,
- 0x00386B32125,0x0038575428D,0x00384384384,0x00382FC231D,0x00381C0E070,0x00380867A92,
- 0x0037F4CF09C,0x0037E1441A8,0x0037CDC6CD1,0x0037BA57132,0x0037A6F4DE9,0x003793A0215,
- 0x00378058CD5,0x00376D1ED4B,0x003759F2298,0x003746D2BE0,0x003733C0847,0x003720BB6F4,
- 0x00370DC370D,0x0036FAD87BB,0x0036E7FA826,0x0036D529779,0x0036C2654E0,0x0036AFADF87,
- 0x00369D0369D,0x00368A6594F,0x003677D46CE,0x0036654FE4C,0x003652D7EFB,0x0036406C80D,
- 0x00362E0D8B8,0x00361BBB030,0x00360974DAD,0x0035F73B066,0x0035E50D794,0x0035D2EC270,
- 0x0035C0D7035,0x0035AECE020,0x00359CD116C,0x00358AE0358,0x003578FB523,0x0035672260C,
- 0x00355555555,0x0035439423F,0x003531DEC0D,0x00352035203,0x00350E97366,0x0034FD04F7B,
- 0x0034EB7E58A,0x0034DA034DA,0x0034C893CB3,0x0034B72FC60,0x0034A5D732A,0x0034948A05E,
- 0x00348348348,0x00347211B34,0x003460E6772,0x00344FC6750,0x00343EB1A1F,0x00342DA7F2F,
- 0x00341CA95D2,0x00340BB5D5B,0x0033FACD51D,0x0033E9EFC6E,0x0033D91D2A2,0x0033C85570F,
- 0x0033B79890C,0x0033A6E67F3,0x0033963F31A,0x003385A29DC,0x00337510B93,0x0033648979B,
- 0x0033540CD50,0x0033439AC0E,0x00333333333,0x003322D621E,0x0033128382D,0x0033023B4C3,
- 0x0032F1FD73E,0x0032E1C9F01,0x0032D1A0B6F,0x0032C181BEA,0x0032B16CFD7,0x0032A16269B,
- 0x00329161F9A,0x0032816BA3D,0x0032717F5E9,0x0032619D206,0x003251C4DFE,0x003241F693A,
- 0x00323232323,0x00322277B24,0x003212C70AA,0x00320320320,0x0031F3831F3,0x0031E3EFC91,
- 0x0031D466269,0x0031C4E62EA,0x0031B56FD83,0x0031A6031A6,0x0031969FEC2,0x0031874644B,
- 0x003177F61B3,0x003168AF66D,0x003159721ED,0x00314A3E3A8,0x00313B13B13,0x00312BF27A5,
- 0x00311CDA8D3,0x00310DCBE15,0x0030FEC66E3,0x0030EFCA2B6,0x0030E0D7107,0x0030D1ED150,
- 0x0030C30C30C,0x0030B4345B5,0x0030A5658C7,0x0030969FBBF,0x003087E2E1A,0x0030792EF56,
- 0x00306A83EF0,0x00305BE1C69,0x00304D4873E,0x00303EB7EF1,0x00303030303,0x003021B12F3,
- 0x0030133AE45,0x003004CD47B,0x002FF668518,0x002FE80BFA0,0x002FD9B8396,0x002FCB6D081,
- 0x002FBD2A5E4,0x002FAEF0347,0x002FA0BE82F,0x002F9295424,0x002F84746AE,0x002F765BF55,
- 0x002F684BDA1,0x002F5A4411C,0x002F4C4494F,0x002F3E4D5C6,0x002F305E60B,0x002F22779AA,
- 0x002F149902F,0x002F06C2925,0x002EF8F441C,0x002EEB2E09F,0x002EDD6FE3E,0x002ECFB9C86,
- 0x002EC20BB08,0x002EB465952,0x002EA6C76F6,0x002E9931383,0x002E8BA2E8B,0x002E7E1C7A0,
- 0x002E709DE54,0x002E632723A,0x002E55B82E5,0x002E4850FE8,0x002E3AF18D9,0x002E2D99D4B,
- 0x002E2049CD4,0x002E1301709,0x002E05C0B81,0x002DF8879D2,0x002DEB56194,0x002DDE2C25D,
- 0x002DD109BC6,0x002DC3EED68,0x002DB6DB6DB,0x002DA9CF7B9,0x002D9CCAF9B,0x002D8FCDE1D,
- 0x002D82D82D8,0x002D75E9D68,0x002D6902D69,0x002D5C23276,0x002D4F4AC2D,0x002D4279A2A,
- 0x002D35AFC0B,0x002D28ED16D,0x002D1C319F0,0x002D0F7D531,0x002D02D02D0,0x002CF62A26C,
- 0x002CE98B3A6,0x002CDCF361D,0x002CD062973,0x002CC3D8D4A,0x002CB756141,0x002CAADA4FD,
- 0x002C9E6581F,0x002C91F7A4A,0x002C8590B21,0x002C7930A48,0x002C6CD7764,0x002C6085218,
- 0x002C5439A0B,0x002C47F4EE0,0x002C3BB703D,0x002C2F7FDCA,0x002C234F72C,0x002C1725C09,
- 0x002C0B02C0B,0x002BFEE66D7,0x002BF2D0C15,0x002BE6C1B70,0x002BDAB948E,0x002BCEB771A,
- 0x002BC2BC2BC,0x002BB6C771E,0x002BAAD93EC,0x002B9EF18CF,0x002B9310572,0x002B8735981,
- 0x002B7B614A7,0x002B6F93690,0x002B63CBEEA,0x002B580AD60,0x002B4C5019F,0x002B409BB56,
- 0x002B34EDA31,0x002B2945DE0,0x002B1DA4610,0x002B1209270,0x002B06742B0,0x002AFAE567F,
- 0x002AEF5CD8D,0x002AE3DA78A,0x002AD85E426,0x002ACCE8313,0x002AC178402,0x002AB60E6A3,
- 0x002AAAAAAAA,0x002A9F4CFC8,0x002A93F55B0,0x002A88A3C14,0x002A7D582A7,0x002A721291E,
- 0x002A66D2F2B,0x002A5B99484,0x002A50658DC,0x002A4537BE7,0x002A3A0FD5C,0x002A2EEDCEF,
- 0x002A23D1A56,0x002A18BB547,0x002A0DAAD78,0x002A02A02A0,0x0029F79B475,0x0029EC9C2AF,
- 0x0029E1A2D05,0x0029D6AF32F,0x0029CBC14E5,0x0029C0D91E0,0x0029B5F69D7,0x0029AB19C84,
- 0x0029A0429A0,0x002995710E4,0x00298AA520B,0x00297FDECCE,0x0029751E0E8,0x00296A62E13,
- 0x00295FAD40A,0x002954FD288,0x00294A5294A,0x00293FAD80A,0x0029350DE84,0x00292A73C76,
- 0x00291FDF19B,0x0029154FDB0,0x00290AC6072,0x002900419A0
+ 0x5000000000,0x4D9364D936,0x4B4B4B4B4B,0x4924924924,0x471C71C71C,0x45306EB3E4,
+ 0x435E50D794,0x41A41A41A4,0x4000000000,0x3E7063E706,0x3CF3CF3CF3,0x3B88EE23B8,
+ 0x3A2E8BA2E8,0x38E38E38E3,0x37A6F4DE9B,0x3677D46CEF,0x3555555555,0x343EB1A1F5,
+ 0x3333333333,0x3232323232,0x313B13B13B,0x304D4873EC,0x2F684BDA12,0x2E8BA2E8BA,
+ 0x2DB6DB6DB6,0x2CE98B3A62,0x2C234F72C2,0x2B63CBEEA4,0x2AAAAAAAAA,0x29F79B4758,
+ 0x294A5294A5,0x28A28A28A2,0x2800000000,0x2762762762,0x26C9B26C9B,0x26357E16EC,
+ 0x25A5A5A5A5,0x2519F89467,0x2492492492,0x240E6C2B44,0x238E38E38E,0x231188C462,
+ 0x22983759F2,0x2222222222,0x21AF286BCA,0x213F2B3884,0x20D20D20D2,0x2067B23A54,
+ 0x2000000000,0x1F9ADD3C0C,0x1F3831F383,0x1ED7E75346,0x1E79E79E79,0x1E1E1E1E1E,
+ 0x1DC47711DC,0x1D6CDFA1D6,0x1D1745D174,0x1CC398730E,0x1C71C71C71,0x1C21C21C21,
+ 0x1BD37A6F4D,0x1B86E1B86E,0x1B3BEA3677,0x1AF286BCA1,0x1AAAAAAAAA,0x1A6449E59B,
+ 0x1A1F58D0FA,0x19DBCC4867,0x1999999999,0x1958B67EBB,0x1919191919,0x18DAB7EC1D,
+ 0x189D89D89D,0x1861861861,0x1826A439F6,0x17ECDC1CB5,0x17B425ED09,0x177C7A20E1,
+ 0x1745D1745D,0x171024E6A1,0x16DB6DB6DB,0x16A7A5616A,0x1674C59D31,0x1642C8590B,
+ 0x1611A7B961,0x15E15E15E1,0x15B1E5F752,0x15833A1583,0x1555555555,0x152832C6E0,
+ 0x14FBCDA3AC,0x14D0214D02,0x14A5294A52,0x147AE147AE,0x1451451451,0x142850A142,
+ 0x1400000000,0x13D84F613D,0x13B13B13B1,0x138ABF82EE,0x1364D9364D,0x133F84CFE1,
+ 0x131ABF0B76,0x12F684BDA1,0x12D2D2D2D2,0x12AFA64E7B,0x128CFC4A33,0x126AD1F4F3,
+ 0x1249249249,0x1227F179A5,0x12073615A2,0x11E6EFE35B,0x11C71C71C7,0x11A7B9611A,
+ 0x1188C46231,0x116A3B35FC,0x114C1BACF9,0x112E63A6A8,0x1111111111,0x10F421E843,
+ 0x10D79435E5,0x10BB6610BB,0x109F959C42,0x1084210842,0x1069069069,0x104E447BEC,
+ 0x1033D91D2A,0x1019C2D14E,0x1000000000,0x0FE68F1B07,0x0FCD6E9E06,0x0FB49D0E22,
+ 0x0F9C18F9C1,0x0F83E0F83E,0x0F6BF3A9A3,0x0F544FB66B,0x0F3CF3CF3C,0x0F25DEACAF,
+ 0x0F0F0F0F0F,0x0EF883BE20,0x0EE23B88EE,0x0ECC35458C,0x0EB66FD0EB,0x0EA0EA0EA0,
+ 0x0E8BA2E8BA,0x0E76994F8C,0x0E61CC3987,0x0E4D3AA30A,0x0E38E38E38,0x0E24C602D4,
+ 0x0E10E10E10,0x0DFD33C272,0x0DE9BD37A6,0x0DD67C8A60,0x0DC370DC37,0x0DB0995382,
+ 0x0D9DF51B3B,0x0D8B8362E0,0x0D79435E50,0x0D673445B2,0x0D55555555,0x0D43A5CD98,
+ 0x0D3224F2CD,0x0D20D20D20,0x0D0FAC687D,0x0CFEB35477,0x0CEDE62433,0x0CDD442E4F,
+ 0x0CCCCCCCCC,0x0CBC7F5CF9,0x0CAC5B3F5D,0x0C9C5FD7A5,0x0C8C8C8C8C,0x0C7CE0C7CE,
+ 0x0C6D5BF60E,0x0C5DFD86CD,0x0C4EC4EC4E,0x0C3FB19B8F,0x0C30C30C30,0x0C21F8B86A,
+ 0x0C13521CFB,0x0C04CEB916,0x0BF66E0E5A,0x0BE82FA0BE,0x0BDA12F684,0x0BCC17982F,
+ 0x0BBE3D1070,0x0BB082EC20,0x0BA2E8BA2E,0x0B956E0B95,0x0B88127350,0x0B7AD58650,
+ 0x0B6DB6DB6D,0x0B60B60B60,0x0B53D2B0B5,0x0B470C67C0,0x0B3A62CE98,0x0B2DD58507,
+ 0x0B21642C85,0x0B150E682C,0x0B08D3DCB0,0x0AFCB43057,0x0AF0AF0AF0,0x0AE4C415C9,
+ 0x0AD8F2FBA9,0x0ACD3B68C6,0x0AC19D0AC1,0x0AB617909A,0x0AAAAAAAAA,0x0A9F560A9F,
+ 0x0A94196370,0x0A88F46959,0x0A7DE6D1D6,0x0A72F05397,0x0A6810A681,0x0A5D4783A0,
+ 0x0A5294A529,0x0A47F7C66C,0x0A3D70A3D7,0x0A32FEFAE6,0x0A28A28A28,0x0A1E5B1133,
+ 0x0A142850A1,0x0A0A0A0A0A
};
--- a/src/ft2_tables.h
+++ b/src/ft2_tables.h
@@ -3,7 +3,7 @@
#include <stdint.h>
#include "ft2_palette.h" // pal16 typedef
#include "ft2_pattern_ed.h" // pattCoord_t/pattCoord2_t/pattCoordsMouse_t/markCoord_t typedef
-#include "ft2_header.h" // MAX_VOICES
+#include "ft2_header.h" // MAX_CHANNELS
#include "ft2_config.h" // CONFIG_FILE_SIZE
#define KEY2VOL_ENTRIES (signed)(sizeof (key2VolTab) / sizeof (SDL_Keycode))
@@ -37,8 +37,8 @@
extern const markCoord_t markCoordTable[2][2][2];
extern const uint8_t pattCursorXTab[2 * 4 * 8];
extern const uint8_t pattCursorWTab[2 * 4 * 8];
-extern const char chDecTab1[MAX_VOICES+1];
-extern const char chDecTab2[MAX_VOICES+1];
+extern const char chDecTab1[MAX_CHANNELS+1];
+extern const char chDecTab2[MAX_CHANNELS+1];
extern const SDL_Keycode key2VolTab[16];
extern const SDL_Keycode key2EfxTab[36];
extern const SDL_Keycode key2HexTab[16];
@@ -49,4 +49,4 @@
extern const uint8_t defConfigData[CONFIG_FILE_SIZE];
-extern const uint64_t musicTimeTab64[MAX_BPM+1];
+extern const uint64_t musicTimeTab64[(MAX_BPM-MIN_BPM)+1];
--- a/src/ft2_textboxes.c
+++ b/src/ft2_textboxes.c
@@ -727,7 +727,7 @@
void updateTextBoxPointers(void)
{
int32_t i;
- instrTyp *curIns = instr[editor.curInstr];
+ instr_t *curIns = instr[editor.curInstr];
// instrument names
for (i = 0; i < 8; i++)
@@ -742,7 +742,7 @@
else
{
for (i = 0; i < 5; i++)
- textBoxes[TB_SAMP1+i].textPtr = curIns->samp[editor.sampleBankOffset+i].name;
+ textBoxes[TB_SAMP1+i].textPtr = curIns->smp[editor.sampleBankOffset+i].name;
}
// song name
--- a/src/ft2_trim.c
+++ b/src/ft2_trim.c
@@ -10,7 +10,7 @@
#include "ft2_header.h"
#include "ft2_sample_ed.h"
#include "ft2_gui.h"
-#include "ft2_scopes.h"
+#include "scopes/ft2_scopes.h"
#include "ft2_pattern_ed.h"
#include "ft2_replayer.h"
#include "ft2_audio.h"
@@ -24,8 +24,8 @@
static uint8_t instrUsed[MAX_INST], instrOrder[MAX_INST], pattUsed[MAX_PATTERNS], pattOrder[MAX_PATTERNS];
static int16_t oldPattLens[MAX_PATTERNS], tmpPattLens[MAX_PATTERNS];
static int64_t xmSize64 = -1, xmAfterTrimSize64 = -1, spaceSaved64 = -1;
-static tonTyp *oldPatts[MAX_PATTERNS], *tmpPatt[MAX_PATTERNS];
-static instrTyp *tmpInstr[1 + MAX_INST], *tmpInst[MAX_INST]; // tmpInstr[x] = copy of instr[x] for "after trim" size calculation
+static note_t *oldPatts[MAX_PATTERNS], *tmpPatt[MAX_PATTERNS];
+static instr_t *tmpInstr[1 + MAX_INST], *tmpInst[MAX_INST]; // tmpInstr[x] = copy of instr[x] for "after trim" size calculation
static SDL_Thread *trimThread;
void pbTrimCalc(void);
@@ -52,7 +52,7 @@
{
if (instr[i] != NULL)
{
- tmpInstr[i] = (instrTyp *)malloc(sizeof (instrTyp));
+ tmpInstr[i] = (instr_t *)malloc(sizeof (instr_t));
if (tmpInstr[i] == NULL)
{
freeTmpInstruments();
@@ -70,29 +70,30 @@
{
for (int32_t i = 0; i < ap; i++)
{
- tonTyp *pattPtr = patt[i];
+ note_t *pattPtr = pattern[i];
if (pattPtr == NULL)
continue;
- const int32_t readLen = pattLens[i] * MAX_VOICES;
- for (int32_t j = 0; j < readLen; j++)
+ const int32_t readLen = patternNumRows[i] * MAX_CHANNELS;
+
+ note_t *p = pattPtr;
+ for (int32_t j = 0; j < readLen; j++, p++)
{
- tonTyp *note = &pattPtr[j];
- if (note->instr == src)
- note->instr = dst;
+ if (p->instr == src)
+ p->instr = dst;
}
}
}
-static int16_t getUsedTempSamples(uint16_t nr)
+static int16_t getUsedTempSamples(uint16_t insNum)
{
- if (tmpInstr[nr] == NULL)
+ if (tmpInstr[insNum] == NULL)
return 0;
- instrTyp *ins = tmpInstr[nr];
+ instr_t *ins = tmpInstr[insNum];
int16_t i = 16 - 1;
- while (i >= 0 && ins->samp[i].pek == NULL && ins->samp[i].name[0] == '\0')
+ while (i >= 0 && ins->smp[i].dataPtr == NULL && ins->smp[i].name[0] == '\0')
i--;
/* Yes, 'i' can be -1 here, and will be set to at least 0
@@ -100,8 +101,8 @@
**/
for (int16_t j = 0; j < 96; j++)
{
- if (ins->ta[j] > i)
- i = ins->ta[j];
+ if (ins->note2SampleLUT[j] > i)
+ i = ins->note2SampleLUT[j];
}
return i+1;
@@ -127,15 +128,21 @@
const int16_t a = getUsedTempSamples(i);
if (a > 0)
- currSize64 += INSTR_HEADER_SIZE + (a * sizeof (sampleHeaderTyp));
+ currSize64 += INSTR_HEADER_SIZE + (a * sizeof (xmSmpHdr_t));
else
currSize64 += 22+11;
- instrTyp *ins = tmpInstr[j];
+ instr_t *ins = tmpInstr[j];
for (int16_t k = 0; k < a; k++)
{
- if (ins->samp[k].pek != NULL)
- currSize64 += ins->samp[k].len;
+ sample_t *s = &ins->smp[k];
+ if (s->dataPtr != NULL && s->length > 0)
+ {
+ if (s->flags & SAMPLE_16BIT)
+ currSize64 += s->length << 1;
+ else
+ currSize64 += s->length;
+ }
}
}
@@ -144,10 +151,9 @@
static void wipeInstrUnused(bool testWipeSize, int16_t *ai, int32_t ap, int32_t antChn)
{
- uint8_t newInst;
- int16_t pattLen;
+ int16_t numRows;
int32_t i, j, k;
- tonTyp *pattPtr;
+ note_t *p;
int32_t numInsts = *ai;
@@ -157,31 +163,31 @@
{
if (testWipeSize)
{
- pattPtr = tmpPatt[i];
- pattLen = tmpPattLens[i];
+ p = tmpPatt[i];
+ numRows = tmpPattLens[i];
}
else
{
- pattPtr = patt[i];
- pattLen = pattLens[i];
+ p = pattern[i];
+ numRows = patternNumRows[i];
}
- if (pattPtr == NULL)
+ if (p == NULL)
continue;
- for (j = 0; j < pattLen; j++)
+ for (j = 0; j < numRows; j++)
{
for (k = 0; k < antChn; k++)
{
- newInst = pattPtr[(j * MAX_VOICES) + k].instr;
- if (newInst > 0 && newInst <= MAX_INST)
- instrUsed[newInst-1] = true;
+ uint8_t ins = p[(j * MAX_CHANNELS) + k].instr;
+ if (ins > 0 && ins <= MAX_INST)
+ instrUsed[ins-1] = true;
}
}
}
int16_t instToDel = 0;
- newInst = 0;
+ uint8_t newInst = 0;
int16_t newNumInsts = 0;
memset(instrOrder, 0, numInsts);
@@ -271,15 +277,15 @@
{
uint8_t newPatt;
int16_t i, *pLens;
- tonTyp **p;
+ note_t **p;
int16_t usedPatts = *ap;
memset(pattUsed, 0, usedPatts);
int16_t newUsedPatts = 0;
- for (i = 0; i < song.len; i++)
+ for (i = 0; i < song.songLength; i++)
{
- newPatt = song.songTab[i];
+ newPatt = song.orders[i];
if (newPatt < usedPatts && !pattUsed[newPatt])
{
pattUsed[newPatt] = true;
@@ -305,13 +311,13 @@
}
else
{
- p = patt;
- pLens = pattLens;
+ p = pattern;
+ pLens = patternNumRows;
}
- memcpy(oldPatts, p, usedPatts * sizeof (tonTyp *));
+ memcpy(oldPatts, p, usedPatts * sizeof (note_t *));
memcpy(oldPattLens, pLens, usedPatts * sizeof (int16_t));
- memset(p, 0, usedPatts * sizeof (tonTyp *));
+ memset(p, 0, usedPatts * sizeof (note_t *));
memset(pLens, 0, usedPatts * sizeof (int16_t));
// relocate patterns
@@ -339,17 +345,17 @@
{
for (i = 0; i < MAX_PATTERNS; i++)
{
- if (patt[i] == NULL)
- pattLens[i] = 64;
+ if (pattern[i] == NULL)
+ patternNumRows[i] = 64;
}
// reorder order list (and clear unused entries)
for (i = 0; i < 256; i++)
{
- if (i < song.len)
- song.songTab[i] = pattOrder[song.songTab[i]];
+ if (i < song.songLength)
+ song.orders[i] = pattOrder[song.orders[i]];
else
- song.songTab[i] = 0;
+ song.orders[i] = 0;
}
}
@@ -360,8 +366,8 @@
{
uint8_t smpUsed[16], smpOrder[16];
int16_t j, k, l;
- instrTyp *ins;
- sampleTyp tempSamples[16];
+ instr_t *ins;
+ sample_t tempSamples[16];
for (int16_t i = 1; i <= ai; i++)
{
@@ -389,13 +395,13 @@
memset(smpUsed, 0, l);
if (l > 0)
{
- sampleTyp *s = ins->samp;
+ sample_t *s = ins->smp;
for (j = 0; j < l; j++, s++)
{
// check if sample is referenced in instrument
for (k = 0; k < 96; k++)
{
- if (ins->ta[k] == j)
+ if (ins->note2SampleLUT[k] == j)
{
smpUsed[j] = true;
break; // sample is used
@@ -406,12 +412,10 @@
{
// sample is unused
- if (s->origPek != NULL && !testWipeSize)
- free(s->origPek);
+ if (s->dataPtr != NULL && !testWipeSize)
+ freeSmpData(s);
- memset(s, 0, sizeof (sampleTyp));
- s->origPek = NULL;
- s->pek = NULL;
+ memset(s, 0, sizeof (sample_t));
}
}
@@ -426,23 +430,23 @@
// re-order samples
- memcpy(tempSamples, ins->samp, l * sizeof (sampleTyp));
- memset(ins->samp, 0, l * sizeof (sampleTyp));
+ memcpy(tempSamples, ins->smp, l * sizeof (sample_t));
+ memset(ins->smp, 0, l * sizeof (sample_t));
for (j = 0; j < l; j++)
{
if (smpUsed[j])
- ins->samp[smpOrder[j]] = tempSamples[j];
+ ins->smp[smpOrder[j]] = tempSamples[j];
}
// re-order note->sample list
for (j = 0; j < 96; j++)
{
- newSamp = ins->ta[j];
+ newSamp = ins->note2SampleLUT[j];
if (smpUsed[newSamp])
- ins->ta[j] = smpOrder[newSamp];
+ ins->note2SampleLUT[j] = smpOrder[newSamp];
else
- ins->ta[j] = 0;
+ ins->note2SampleLUT[j] = 0;
}
}
}
@@ -451,7 +455,7 @@
static void wipeSmpDataAfterLoop(bool testWipeSize, int16_t ai)
{
int16_t l;
- instrTyp *ins;
+ instr_t *ins;
for (int16_t i = 1; i <= ai; i++)
{
@@ -476,33 +480,25 @@
l = getUsedTempSamples(i);
}
- sampleTyp *s = ins->samp;
+ sample_t *s = ins->smp;
for (int16_t j = 0; j < l; j++, s++)
{
- if (s->origPek != NULL && s->typ & 3 && s->len > 0 && s->len > s->repS+s->repL)
+ if (s->dataPtr != NULL && GET_LOOPTYPE(s->flags) != LOOP_OFF && s->length > 0 && s->length > s->loopStart+s->loopLength)
{
if (!testWipeSize)
- restoreSample(s);
+ unfixSample(s);
- s->len = s->repS + s->repL;
+ s->length = s->loopStart + s->loopLength;
if (!testWipeSize)
{
- if (s->len <= 0)
+ if (s->length <= 0)
{
- s->len = 0;
-
- free(s->origPek);
- s->origPek = NULL;
- s->pek = NULL;
+ s->length = 0;
+ freeSmpData(s);
}
else
{
- int8_t *newPtr = (int8_t *)realloc(s->origPek, s->len + LOOP_FIX_LEN);
- if (newPtr != NULL)
- {
- s->origPek = newPtr;
- s->pek = s->origPek + SMP_DAT_OFFSET;
- }
+ reallocateSmpData(s, s->length, !!(s->flags & SAMPLE_16BIT));
}
}
@@ -516,7 +512,7 @@
static void convertSamplesTo8bit(bool testWipeSize, int16_t ai)
{
int16_t k;
- instrTyp *ins;
+ instr_t *ins;
for (int16_t i = 1; i <= ai; i++)
{
@@ -541,42 +537,28 @@
k = getUsedTempSamples(i);
}
- sampleTyp *s = ins->samp;
+ sample_t *s = ins->smp;
for (int16_t j = 0; j < k; j++, s++)
{
- if (s->origPek != NULL && (s->typ & 16) && s->len > 0)
+ if (s->dataPtr != NULL && s->length > 0 && (s->flags & SAMPLE_16BIT))
{
if (testWipeSize)
{
- s->typ &= ~16;
- s->len >>= 1;
- s->repL >>= 1;
- s->repS >>= 1;
+ s->flags &= ~SAMPLE_16BIT;
}
else
{
- restoreSample(s);
+ unfixSample(s);
- assert(s->pek != NULL);
- const int16_t *src16 = (const int16_t *)s->pek;
- int8_t *dst8 = s->pek;
+ const int16_t *src16 = (const int16_t *)s->dataPtr;
+ int8_t *dst8 = s->dataPtr;
- const int32_t newLen = s->len >> 1;
- for (int32_t a = 0; a < newLen; a++)
+ for (int32_t a = 0; a < s->length; a++)
dst8[a] = src16[a] >> 8;
- s->repL >>= 1;
- s->repS >>= 1;
- s->len >>= 1;
- s->typ &= ~16;
+ s->flags &= ~SAMPLE_16BIT;
- int8_t *newPtr = (int8_t *)realloc(s->origPek, s->len + LOOP_FIX_LEN);
- if (newPtr != NULL)
- {
- s->origPek = newPtr;
- s->pek = s->origPek + SMP_DAT_OFFSET;
- }
-
+ reallocateSmpData(s, s->length, true);
fixSample(s);
}
}
@@ -584,12 +566,12 @@
}
}
-static uint16_t getPackedPattSize(tonTyp *pattern, int32_t numRows, int32_t antChn)
+static uint16_t getPackedPattSize(note_t *p, int32_t numRows, int32_t antChn)
{
- uint8_t bytes[sizeof (tonTyp)];
+ uint8_t bytes[sizeof (note_t)];
uint16_t totalPackLen = 0;
- uint8_t *pattPtr = (uint8_t *)pattern;
+ uint8_t *pattPtr = (uint8_t *)p;
uint8_t *writePtr = pattPtr;
for (int32_t row = 0; row < numRows; row++)
@@ -624,22 +606,22 @@
}
// skip unused channels
- pattPtr += sizeof (tonTyp) * (MAX_VOICES - antChn);
+ pattPtr += sizeof (note_t) * (MAX_CHANNELS - antChn);
}
return totalPackLen;
}
-static bool tmpPatternEmpty(uint16_t nr, int32_t antChn)
+static bool tmpPatternEmpty(uint16_t pattNum, int32_t numChannels)
{
- if (tmpPatt[nr] == NULL)
+ if (tmpPatt[pattNum] == NULL)
return true;
- uint8_t *scanPtr = (uint8_t *)tmpPatt[nr];
- int32_t scanLen = antChn * sizeof (tonTyp);
- int32_t pattLen = tmpPattLens[nr];
+ uint8_t *scanPtr = (uint8_t *)tmpPatt[pattNum];
+ int32_t scanLen = numChannels * sizeof (note_t);
+ int32_t numRows = tmpPattLens[pattNum];
- for (int32_t i = 0; i < pattLen; i++)
+ for (int32_t i = 0; i < numRows; i++, scanPtr += TRACK_WIDTH)
{
for (int32_t j = 0; j < scanLen; j++)
{
@@ -646,8 +628,6 @@
if (scanPtr[j] != 0)
return false;
}
-
- scanPtr += TRACK_WIDTH;
}
return true;
@@ -656,7 +636,7 @@
static int64_t calculateXMSize(void)
{
// count header size in song
- int64_t currSize64 = sizeof (songHeaderTyp);
+ int64_t currSize64 = sizeof (xmHdr_t);
// count number of patterns that would be saved
int16_t ap = MAX_PATTERNS;
@@ -677,9 +657,9 @@
// count packed pattern data size in song
for (int16_t i = 0; i < ap; i++)
{
- currSize64 += sizeof (patternHeaderTyp);
+ currSize64 += sizeof (xmPatHdr_t);
if (!patternEmpty(i))
- currSize64 += getPackedPattSize(patt[i], pattLens[i], song.antChn);
+ currSize64 += getPackedPattSize(pattern[i], patternNumRows[i], song.numChannels);
}
// count instrument and sample data size in song
@@ -693,15 +673,21 @@
const int16_t a = getUsedSamples(i);
if (a > 0)
- currSize64 += INSTR_HEADER_SIZE + (a * sizeof (sampleHeaderTyp));
+ currSize64 += INSTR_HEADER_SIZE + (a * sizeof (xmSmpHdr_t));
else
currSize64 += 22+11;
- instrTyp *ins = instr[j];
+ instr_t *ins = instr[j];
for (int16_t k = 0; k < a; k++)
{
- if (ins->samp[k].pek != NULL)
- currSize64 += ins->samp[k].len;
+ sample_t* s = &ins->smp[k];
+ if (s->dataPtr != NULL && s->length > 0)
+ {
+ if (s->flags & SAMPLE_16BIT)
+ currSize64 += s->length << 1;
+ else
+ currSize64 += s->length;
+ }
}
}
@@ -712,7 +698,7 @@
{
int16_t i, j, k;
- int32_t antChn = song.antChn;
+ int32_t numChannels = song.numChannels;
int32_t pattDataLen = 0;
int32_t newPattDataLen = 0;
int64_t bytes64 = 0;
@@ -719,8 +705,8 @@
int64_t oldInstrSize64 = 0;
// copy over temp data
- memcpy(tmpPatt, patt, sizeof (tmpPatt));
- memcpy(tmpPattLens, pattLens, sizeof (tmpPattLens));
+ memcpy(tmpPatt, pattern, sizeof (tmpPatt));
+ memcpy(tmpPattLens, patternNumRows, sizeof (tmpPattLens));
memcpy(tmpInstrName, song.instrName, sizeof (tmpInstrName));
if (!setTmpInstruments())
@@ -737,7 +723,7 @@
int16_t ap = MAX_PATTERNS;
do
{
- if (tmpPatternEmpty(ap - 1, antChn))
+ if (tmpPatternEmpty(ap - 1, numChannels))
ap--;
else
break;
@@ -763,9 +749,9 @@
{
for (i = 0; i < ap; i++)
{
- pattDataLen += sizeof (patternHeaderTyp);
- if (!tmpPatternEmpty(i, antChn))
- pattDataLen += getPackedPattSize(tmpPatt[i], tmpPattLens[i], antChn);
+ pattDataLen += sizeof (xmPatHdr_t);
+ if (!tmpPatternEmpty(i, numChannels))
+ pattDataLen += getPackedPattSize(tmpPatt[i], tmpPattLens[i], numChannels);
}
}
@@ -776,17 +762,17 @@
int16_t highestChan = -1;
for (i = 0; i < ap; i++)
{
- tonTyp *pattPtr = tmpPatt[i];
+ note_t *pattPtr = tmpPatt[i];
if (pattPtr == NULL)
continue;
- const int16_t pattLen = tmpPattLens[i];
- for (j = 0; j < pattLen; j++)
+ const int16_t numRows = tmpPattLens[i];
+ for (j = 0; j < numRows; j++)
{
- for (k = 0; k < antChn; k++)
+ for (k = 0; k < numChannels; k++)
{
- tonTyp *note = &pattPtr[(j * MAX_VOICES) + k];
- if (note->eff || note->effTyp || note->instr || note->ton || note->vol)
+ note_t *p = &pattPtr[(j * MAX_CHANNELS) + k];
+ if (p->note > 0 || p->instr > 0 || p->vol > 0 || p->efx > 0 || p->efxData > 0)
{
if (k > highestChan)
highestChan = k;
@@ -802,7 +788,7 @@
if (highestChan & 1)
highestChan++;
- antChn = (uint8_t)(CLAMP(highestChan, 2, antChn));
+ numChannels = (uint8_t)(CLAMP(highestChan, 2, numChannels));
}
}
@@ -814,9 +800,9 @@
{
for (i = 0; i < ap; i++)
{
- newPattDataLen += sizeof (patternHeaderTyp);
- if (!tmpPatternEmpty(i, antChn))
- newPattDataLen += getPackedPattSize(tmpPatt[i], tmpPattLens[i], antChn);
+ newPattDataLen += sizeof (xmPatHdr_t);
+ if (!tmpPatternEmpty(i, numChannels))
+ newPattDataLen += getPackedPattSize(tmpPatt[i], tmpPattLens[i], numChannels);
}
assert(pattDataLen >= newPattDataLen);
@@ -826,9 +812,9 @@
}
// calculate "remove unused instruments" size
- if (removeInst) wipeInstrUnused(true, &ai, ap, antChn);
+ if (removeInst) wipeInstrUnused(true, &ai, ap, numChannels);
- // calculat new instruments and samples size
+ // calculate new instruments and samples size
if (removeInst || removeSamp || removeSmpDataAfterLoop || convSmpsTo8Bit)
{
int64_t newInstrSize64 = getTempInsAndSmpSize();
@@ -889,17 +875,17 @@
int16_t highestChan = -1;
for (i = 0; i < ap; i++)
{
- tonTyp *pattPtr = patt[i];
+ note_t *pattPtr = pattern[i];
if (pattPtr == NULL)
continue;
- const int16_t pattLen = pattLens[i];
- for (j = 0; j < pattLen; j++)
+ const int16_t numRows = patternNumRows[i];
+ for (j = 0; j < numRows; j++)
{
- for (k = 0; k < song.antChn; k++)
+ for (k = 0; k < song.numChannels; k++)
{
- tonTyp *note = &pattPtr[(j * MAX_VOICES) + k];
- if (note->eff || note->effTyp || note->instr || note->ton || note->vol)
+ note_t *p = &pattPtr[(j * MAX_CHANNELS) + k];
+ if (p->note > 0 || p->vol > 0 || p->instr > 0 || p->efx > 0 || p->efxData > 0)
{
if (k > highestChan)
highestChan = k;
@@ -915,21 +901,21 @@
if (highestChan & 1)
highestChan++;
- song.antChn = (uint8_t)(CLAMP(highestChan, 2, song.antChn));
+ song.numChannels = (uint8_t)(CLAMP(highestChan, 2, song.numChannels));
}
// clear potentially unused channel data
- if (song.antChn < MAX_VOICES)
+ if (song.numChannels < MAX_CHANNELS)
{
for (i = 0; i < MAX_PATTERNS; i++)
{
- tonTyp *pattPtr = patt[i];
- if (pattPtr == NULL)
+ note_t *p = pattern[i];
+ if (p == NULL)
continue;
- const int16_t pattLen = pattLens[i];
- for (j = 0; j < pattLen; j++)
- memset(&pattPtr[(j * MAX_VOICES) + song.antChn], 0, sizeof (tonTyp) * (MAX_VOICES - song.antChn));
+ const int16_t numRows = patternNumRows[i];
+ for (j = 0; j < numRows; j++)
+ memset(&p[(j * MAX_CHANNELS) + song.numChannels], 0, sizeof (note_t) * (MAX_CHANNELS - song.numChannels));
}
}
}
@@ -940,13 +926,12 @@
// remove unused instruments
if (removeInst)
- wipeInstrUnused(false, &ai, ap, song.antChn);
+ wipeInstrUnused(false, &ai, ap, song.numChannels);
freeTmpInstruments();
editor.trimThreadWasDone = true;
return true;
-
(void)ptr;
}
@@ -953,7 +938,7 @@
void trimThreadDone(void)
{
if (removePatt)
- setPos(song.songPos, song.pattPos, false);
+ setPos(song.songPos, song.row, false);
if (removeInst)
{
@@ -971,8 +956,8 @@
{
if (ui.patternEditorShown)
{
- if (ui.channelOffset > song.antChn-ui.numChannelsShown)
- setScrollBarPos(SB_CHAN_SCROLL, song.antChn - ui.numChannelsShown, true);
+ if (ui.channelOffset > song.numChannels-ui.numChannelsShown)
+ setScrollBarPos(SB_CHAN_SCROLL, song.numChannels - ui.numChannelsShown, true);
}
if (cursor.ch >= ui.channelOffset+ui.numChannelsShown)
--- a/src/ft2_video.c
+++ b/src/ft2_video.c
@@ -20,7 +20,7 @@
#include "ft2_video.h"
#include "ft2_events.h"
#include "ft2_mouse.h"
-#include "ft2_scopes.h"
+#include "scopes/ft2_scopes.h"
#include "ft2_pattern_ed.h"
#include "ft2_pattern_draw.h"
#include "ft2_sample_ed.h"
@@ -34,6 +34,7 @@
#include "ft2_midi.h"
#include "ft2_bmp.h"
#include "ft2_structs.h"
+#include "ft2_cpu.h"
static const uint8_t textCursorData[12] =
{
@@ -158,6 +159,9 @@
void flipFrame(void)
{
+ const uint32_t windowFlags = SDL_GetWindowFlags(video.window);
+ bool minimized = (windowFlags & SDL_WINDOW_MINIMIZED) ? true : false;
+
renderSprites();
if (video.showFPSCounter)
@@ -164,9 +168,14 @@
drawFPSCounter();
SDL_UpdateTexture(video.texture, NULL, video.frameBuffer, SCREEN_W * sizeof (int32_t));
- SDL_RenderClear(video.renderer);
+
+ // SDL2 bug on Windows (?): This function consumes ever-increasing memory if the program is minimized
+ if (!minimized)
+ SDL_RenderClear(video.renderer);
+
SDL_RenderCopy(video.renderer, video.texture, NULL, NULL);
SDL_RenderPresent(video.renderer);
+
eraseSprites();
if (!video.vsync60HzPresent)
@@ -175,21 +184,19 @@
}
else
{
- uint32_t windowFlags = SDL_GetWindowFlags(video.window);
-
/* We have VSync, but it can unexpectedly get inactive in certain scenarios.
** We have to force thread sleeping (to ~60Hz) if so.
*/
#ifdef __APPLE__
// macOS: VSync gets disabled if the window is 100% covered by another window. Let's add a (crude) fix:
- if ((windowFlags & SDL_WINDOW_MINIMIZED) || !(windowFlags & SDL_WINDOW_INPUT_FOCUS))
+ if (minimized || !(windowFlags & SDL_WINDOW_INPUT_FOCUS))
waitVBL();
#elif __unix__
// *NIX: VSync gets disabled in fullscreen mode (at least on some distros/systems). Let's add a fix:
- if ((windowFlags & SDL_WINDOW_MINIMIZED) || video.fullscreen)
+ if (minimized || video.fullscreen)
waitVBL();
#else
- if (windowFlags & SDL_WINDOW_MINIMIZED)
+ if (minimized)
waitVBL();
#endif
}
@@ -267,6 +274,7 @@
// for mouse cursor creation
video.xScale = (uint32_t)round(video.renderW * (1.0 / SCREEN_W));
video.yScale = (uint32_t)round(video.renderH * (1.0 / SCREEN_H));
+
createMouseCursors();
}
@@ -850,16 +858,16 @@
songTitleTrunc[sizeof (songTitleTrunc)-1] = '\0';
if (song.isModified)
- sprintf(wndTitle, "Fasttracker II clone v%s - \"%s\" (unsaved)", PROG_VER_STR, songTitleTrunc);
+ sprintf(wndTitle, "Fasttracker II clone v%s (%d-bit) - \"%s\" (unsaved)", PROG_VER_STR, CPU_BITS, songTitleTrunc);
else
- sprintf(wndTitle, "Fasttracker II clone v%s - \"%s\"", PROG_VER_STR, songTitleTrunc);
+ sprintf(wndTitle, "Fasttracker II clone v%s (%d-bit) - \"%s\"", PROG_VER_STR, CPU_BITS, songTitleTrunc);
}
else
{
if (song.isModified)
- sprintf(wndTitle, "Fasttracker II clone v%s - \"untitled\" (unsaved)", PROG_VER_STR);
+ sprintf(wndTitle, "Fasttracker II clone v%s (%d-bit) - \"untitled\" (unsaved)", PROG_VER_STR, CPU_BITS);
else
- sprintf(wndTitle, "Fasttracker II clone v%s - \"untitled\"", PROG_VER_STR);
+ sprintf(wndTitle, "Fasttracker II clone v%s (%d-bit) - \"untitled\"", PROG_VER_STR, CPU_BITS);
}
SDL_SetWindowTitle(video.window, wndTitle);
@@ -1004,6 +1012,7 @@
if (videoDriver != NULL && strcmp("KMSDRM", videoDriver) == 0)
video.useDesktopMouseCoords = false;
+ SDL_SetRenderDrawColor(video.renderer, 0, 0, 0, SDL_ALPHA_OPAQUE);
return true;
}
@@ -1018,7 +1027,7 @@
else if (ui.nibblesShown)
{
if (editor.NI_Play)
- moveNibblePlayers();
+ moveNibblesPlayers();
}
else
{
@@ -1028,14 +1037,14 @@
if (!ui.diskOpShown)
{
- drawSongRepS();
+ drawSongLoopStart();
drawSongLength();
drawPosEdNums(editor.songPos);
drawEditPattern(editor.editPattern);
drawPatternLength(editor.editPattern);
- drawSongBPM(editor.speed);
- drawSongSpeed(editor.tempo);
- drawGlobalVol(editor.globalVol);
+ drawSongBPM(editor.BPM);
+ drawSongSpeed(editor.speed);
+ drawGlobalVol(editor.globalVolume);
if (!songPlaying || editor.wavIsRendering)
setScrollBarPos(SB_POS_ED, editor.songPos, false);
@@ -1057,7 +1066,7 @@
{
ui.updatePosEdScrollBar = false;
setScrollBarPos(SB_POS_ED, song.songPos, false);
- setScrollBarEnd(SB_POS_ED, (song.len - 1) + 5);
+ setScrollBarEnd(SB_POS_ED, (song.songLength - 1) + 5);
}
if (!ui.extended)
@@ -1124,19 +1133,19 @@
if (ui.drawBPMFlag)
{
ui.drawBPMFlag = false;
- drawSongBPM(editor.speed);
+ drawSongBPM(editor.BPM);
}
if (ui.drawSpeedFlag)
{
ui.drawSpeedFlag = false;
- drawSongSpeed(editor.tempo);
+ drawSongSpeed(editor.speed);
}
if (ui.drawGlobVolFlag)
{
ui.drawGlobVolFlag = false;
- drawGlobalVol(editor.globalVol);
+ drawGlobalVol(editor.globalVolume);
}
if (ui.drawPosEdFlag)
@@ -1164,6 +1173,6 @@
{
ui.updatePatternEditor = false;
if (ui.patternEditorShown)
- writePattern(editor.pattPos, editor.editPattern);
+ writePattern(editor.row, editor.editPattern);
}
}
--- a/src/ft2_wav_renderer.c
+++ b/src/ft2_wav_renderer.c
@@ -7,10 +7,11 @@
#include <stdint.h>
#include <stdbool.h>
#include "ft2_header.h"
+#include "ft2_audio.h"
#include "ft2_gui.h"
#include "ft2_pattern_ed.h"
#include "ft2_diskop.h"
-#include "ft2_scopes.h"
+#include "scopes/ft2_scopes.h"
#include "ft2_config.h"
#include "ft2_mouse.h"
#include "ft2_sample_ed.h"
@@ -36,10 +37,9 @@
uint32_t subchunk2ID, subchunk2Size;
} wavHeader_t;
-static char WAV_SysReqText[192];
static uint8_t WDBitDepth = 16, WDStartPos, WDStopPos, *wavRenderBuffer;
static int16_t WDAmp;
-static uint32_t WDFrequency = 48000;
+static uint32_t WDFrequency = DEFAULT_AUDIO_FREQ;
static SDL_Thread *thread;
static void updateWavRenderer(void)
@@ -125,7 +125,7 @@
void resetWavRenderer(void)
{
WDStartPos = 0;
- WDStopPos = (uint8_t)song.len - 1;
+ WDStopPos = (uint8_t)song.songLength - 1;
if (ui.wavRendererShown)
updateWavRenderer();
@@ -143,7 +143,7 @@
ui.scopesShown = false;
WDStartPos = 0;
- WDStopPos = (uint8_t)song.len - 1;
+ WDStopPos = (uint8_t)song.songLength - 1;
drawWavRenderer();
}
@@ -194,8 +194,8 @@
setAudioAmp(amp, config.masterVol, (WDBitDepth == 32));
stopVoices();
- song.globVol = 64;
- P_SetSpeed(song.speed);
+ song.globalVolume = 64;
+ setMixerBPM(song.BPM);
resetPlaybackTime();
return true;
@@ -251,12 +251,12 @@
stopPlaying();
// kludge: set speed to 6 if speed was set to 0
- if (song.tempo == 0)
- song.tempo = 6;
+ if (song.speed == 0)
+ song.speed = 6;
setBackOldAudioFreq();
- P_SetSpeed(song.speed);
- setAudioAmp(config.boostLevel, config.masterVol, config.specialFlags & BITDEPTH_32);
+ setMixerBPM(song.BPM);
+ setAudioAmp(config.boostLevel, config.masterVol, !!(config.specialFlags & BITDEPTH_32));
editor.wavIsRendering = false;
setMouseBusy(false);
@@ -264,13 +264,13 @@
static bool dump_EndOfTune(int16_t endSongPos)
{
- bool returnValue = (editor.wavReachedEndFlag && song.pattPos == 0 && song.timer == 1) || (song.tempo == 0);
+ bool returnValue = (editor.wavReachedEndFlag && song.row == 0 && song.tick == 1) || (song.speed == 0);
// 8bitbubsy: FT2 bugfix for EEx (pattern delay) on first row of a pattern
if (song.pattDelTime2 > 0)
returnValue = false;
- if (song.songPos == endSongPos && song.pattPos == 0 && song.timer == 1)
+ if (song.songPos == endSongPos && song.row == 0 && song.tick == 1)
editor.wavReachedEndFlag = true;
return returnValue;
@@ -291,12 +291,12 @@
static void updateVisuals(void)
{
- editor.editPattern = (uint8_t)song.pattNr;
- editor.pattPos = song.pattPos;
+ editor.editPattern = (uint8_t)song.pattNum;
+ editor.row = song.row;
editor.songPos = song.songPos;
+ editor.BPM = song.BPM;
editor.speed = song.speed;
- editor.tempo = song.tempo;
- editor.globalVol = song.globVol;
+ editor.globalVolume = song.globalVolume;
ui.drawPosEdFlag = true;
ui.drawPattNumLenFlag = true;
@@ -324,7 +324,7 @@
uint32_t sampleCounter = 0;
bool renderDone = false;
uint8_t tickCounter = 4;
- double dTickSampleCounter = 0.0;
+ int64_t tickSampleCounter64 = 0;
editor.wavReachedEndFlag = false;
while (!renderDone)
@@ -341,17 +341,16 @@
break;
}
- if (dTickSampleCounter <= 0.0)
+ if (tickSampleCounter64 <= 0) // new replayer tick
{
- // new replayer tick
dump_TickReplayer();
- dTickSampleCounter += audio.dSamplesPerTick;
+ tickSampleCounter64 += audio.samplesPerTick64;
}
- int32_t remainingTick = (int32_t)ceil(dTickSampleCounter);
+ int32_t remainingTick = (tickSampleCounter64 + UINT32_MAX) >> 32; // ceil (rounded upwards)
mixReplayerTickToBuffer(remainingTick, ptr8, WDBitDepth);
- dTickSampleCounter -= remainingTick;
+ tickSampleCounter64 -= (int64_t)remainingTick << 32;
remainingTick *= 2; // stereo
samplesInChunk += remainingTick;
@@ -392,24 +391,10 @@
(void)ptr;
}
-static void createOverwriteText(char *name)
-{
- char nameTmp[128];
-
- // read entry name to a small buffer
- uint32_t nameLen = (uint32_t)strlen(name);
- memcpy(nameTmp, name, (nameLen >= sizeof (nameTmp)) ? sizeof (nameTmp) : (nameLen + 1));
- nameTmp[sizeof (nameTmp) - 1] = '\0';
-
- trimEntryName(nameTmp, false);
-
- sprintf(WAV_SysReqText, "Overwrite file \"%s\"?", nameTmp);
-}
-
static void wavRender(bool checkOverwrite)
{
- WDStartPos = (uint8_t)(MAX(0, MIN(WDStartPos, song.len - 1)));
- WDStopPos = (uint8_t)(MAX(0, MIN(MAX(WDStartPos, WDStopPos), song.len - 1)));
+ WDStartPos = (uint8_t)(MAX(0, MIN(WDStartPos, song.songLength - 1)));
+ WDStopPos = (uint8_t)(MAX(0, MIN(MAX(WDStartPos, WDStopPos), song.songLength - 1)));
updateWavRenderer();
@@ -418,8 +403,9 @@
char *filename = getDiskOpFilename();
if (checkOverwrite && fileExistsAnsi(filename))
{
- createOverwriteText(filename);
- if (okBox(2, "System request", WAV_SysReqText) != 1)
+ char buf[256];
+ createFileOverwriteText(filename, buf);
+ if (okBox(2, "System request", buf) != 1)
return;
}
@@ -457,8 +443,10 @@
if (WDFrequency < MAX_WAV_RENDER_FREQ)
{
if (WDFrequency == 44100) WDFrequency = 48000;
+#if CPU_64BIT
else if (WDFrequency == 48000) WDFrequency = 96000;
else if (WDFrequency == 96000) WDFrequency = 192000;
+#endif
updateWavRenderer();
}
}
@@ -467,10 +455,13 @@
{
if (WDFrequency > MIN_WAV_RENDER_FREQ)
{
+#if CPU_64BIT
if (WDFrequency == 192000) WDFrequency = 96000;
else if (WDFrequency == 96000) WDFrequency = 48000;
else if (WDFrequency == 48000) WDFrequency = 44100;
-
+#else
+ if (WDFrequency == 48000) WDFrequency = 44100;
+#endif
updateWavRenderer();
}
}
@@ -495,11 +486,11 @@
void pbWavSongStartUp(void)
{
- if (WDStartPos >= song.len-1)
+ if (WDStartPos >= song.songLength-1)
return;
WDStartPos++;
- WDStopPos = (uint8_t)(MIN(MAX(WDStartPos, WDStopPos), song.len - 1));
+ WDStopPos = (uint8_t)(MIN(MAX(WDStartPos, WDStopPos), song.songLength - 1));
updateWavRenderer();
}
@@ -518,7 +509,7 @@
return;
WDStopPos++;
- WDStopPos = (uint8_t)(MIN(MAX(WDStartPos, WDStopPos), song.len - 1));
+ WDStopPos = (uint8_t)(MIN(MAX(WDStartPos, WDStopPos), song.songLength - 1));
updateWavRenderer();
}
@@ -528,7 +519,7 @@
return;
WDStopPos--;
- WDStopPos = (uint8_t)(MIN(MAX(WDStartPos, WDStopPos), song.len - 1));
+ WDStopPos = (uint8_t)(MIN(MAX(WDStartPos, WDStopPos), song.songLength - 1));
updateWavRenderer();
}
--- a/src/ft2_wav_renderer.h
+++ b/src/ft2_wav_renderer.h
@@ -2,9 +2,15 @@
#include <stdint.h>
#include "ft2_header.h"
+#include "ft2_cpu.h"
#define MIN_WAV_RENDER_FREQ 44100
+
+#if CPU_64BIT
#define MAX_WAV_RENDER_FREQ 192000
+#else
+#define MAX_WAV_RENDER_FREQ 48000
+#endif
#define MAX_WAV_RENDER_SAMPLES_PER_TICK (((MAX_WAV_RENDER_FREQ * 5) / 2) / MIN_BPM)
@@ -15,7 +21,6 @@
void showWavRenderer(void);
void hideWavRenderer(void);
void exitWavRenderer(void);
-void dump_RenderTick(uint32_t samplesPerTick, uint8_t *buffer);
void pbWavRender(void);
void pbWavExit(void);
void pbWavFreqUp(void);
--- a/src/helpdata/FT2.HLP
+++ b/src/helpdata/FT2.HLP
@@ -9,7 +9,7 @@
>- 12-Point Volume- & Panning Envelope.
>- Multisamples, up to 16 samples/instrument.
>- 128 instruments.
->- "Unlimited" sample length. (1GB in this clone)
+>- "Unlimited" sample length. (1GB per sample in this clone)
>- 8 octaves.
>- Variable pattern length.
>- Built in sampler/sample editor.
@@ -150,7 +150,7 @@
Syntax: 4 + Rate + Depth
Adds vibrato to the channel with a rate and speed. Set vibrato
-control (E4) can be used to change the vibrato wave form (see
+control (E4) can be used to change the vibrato waveform (see
below).
@X040@C001Tone portamento + volume slide
@@ -241,11 +241,11 @@
>@X060@C002
Syntax: E4 + Type
-This command controls the vibrato wave form.
+This command controls the vibrato waveform.
Type: 0 = Sine 1 = Ramp down 2 = Square
-If you add 4 to the type, the wave form will not be retrigged when a
+If you add 4 to the type, the waveform will not be retrigged when a
new instrument is played.
@X040@C001Set fine-tune
@@ -268,7 +268,7 @@
Syntax: E7 + Type
This command works exactly as set vibrato control, but the
-tremolo wave form will be changed instead.
+tremolo waveform will be changed instead.
@X040@C001Retrig note
>@X060@C002
@@ -377,7 +377,7 @@
END
;***************************************************************************
;***************************************************************************
-@LKeyboard
+@LKeybindings
>@X020@C002
>If you have an ambition to create music efficiently we strongly recommend
@@ -392,6 +392,11 @@
references to non-ordinary keys might be wrong.
Sh = shift key.
>
+@X040@C001Audio:
+>@X060@C002
+>Ctrl & numpad+ @T160Increase master volume by 16.
+>Ctrl & numpad- @T160Decrease master volume by 16.
+
@X040@C001Video:
>@X060@C002
Alt+Enter @T160Toggle fullscreen mode
@@ -600,14 +605,14 @@
> 1 Volume envelope
> 1 Panning envelope
> 1 Auto-vibrato definition
-> 1..16 Sample(s)
+> 1..16 sample(s)
> 1 Keyboard split definition
> 1 MIDI definition
>A Fasttracker 2 sample is:
-> 1 Volume/Panning/Fine-tune definition
-> 1 Relative tone.
-> 1 Wave form.
+> 1 Volume/Panning/Finetune definition
+> 1 Relative note
+> 1 Waveform
>@X040@C001The volume envelope:
>@X060@C002
@@ -632,10 +637,12 @@
>Same as above, except from that the vibrato is not connected to
the panning envelope.
->@X040@C001Tune:
+>@X040@C001Tune (finetune):
>@X060@C002
->The fine-tune resolution has been changed from a signed nibble
+>The finetune resolution has been changed from a signed nibble
(-8..+7) to a signed byte (-128..+127).
+>NOTE: The last 3 bits are discarded during playback, so the true step
+size is 8 instead of 1.
>@X040@C001Fadeout:
>@X060@C002
@@ -656,7 +663,7 @@
>@X040@C001Important note:
>@X060@C002
->The volume, panning, tune and relative tone is defined for EACH
+>The volume, panning, finetune and relative note is defined for EACH
SAMPLE in an instrument. All other information is defined for the
entire instrument.
@@ -688,11 +695,11 @@
@X020@C001Sample Editor:
>
->@X040@C001Play (Wave form, range, display):
+>@X040@C001Play (Waveform, range, display):
>@X060@C002
->Plays the current sample with tone display above the "stop"
+>Plays the current sample with the note displayed above the "stop"
button. Note that respect is taken to the particular sample's
-relative tone.
+relative note.
>@X040@C001Save range:
>@X060@C002
@@ -742,11 +749,11 @@
>@X060@C002
>Operates on the range (or the whole sample if no range is set).
->@X040@C001Convert:
+>@X040@C001Sign:
>@X060@C002
->Converts the entire sample from/to signed/unsigned.
+>Converts between signed/unsigned.
->@X040@C001Convert W:
+>@X040@C001B. swap (byte swap):
>@X060@C002
Swaps the byte order to/from Intel from/to Motorola standard on
the entire sample.
@@ -765,7 +772,7 @@
>@X040@C001Resample:
>@X060@C002
-Operates on the entire sample. The sample's relative tone is
+Operates on the entire sample. The sample's relative note is
changed with respect to the resampling rate.
>@X040@C001Mix sample:
@@ -823,7 +830,7 @@
>@X040@C001Scopes:
>@X060@C002
"Std." (standard) will show the sample points as pixels (like FT2).
-"Lined" will draw lines between the points, like an oscilloscope.
+"Lined" will draw interpolated samples (linear interpolation.
@X020@C001Configuration, Miscellaneous:
>
--- a/src/helpdata/ft2_help_data.h
+++ b/src/helpdata/ft2_help_data.h
@@ -3,9 +3,9 @@
#include <stdint.h>
-#define HELP_DATA_LEN 27385
+#define HELP_DATA_LEN 27622
-const uint8_t helpData[27385] =
+const uint8_t helpData[27622] =
{
0x4C,0x3B,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,
0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,
@@ -38,93 +38,94 @@
0x70,0x20,0x74,0x6F,0x20,0x31,0x36,0x20,0x73,0x61,0x6D,0x70,
0x6C,0x65,0x73,0x2F,0x69,0x6E,0x73,0x74,0x72,0x75,0x6D,0x65,
0x6E,0x74,0x2E,0x13,0x3E,0x2D,0x20,0x31,0x32,0x38,0x20,0x69,
- 0x6E,0x73,0x74,0x72,0x75,0x6D,0x65,0x6E,0x74,0x73,0x2E,0x31,
+ 0x6E,0x73,0x74,0x72,0x75,0x6D,0x65,0x6E,0x74,0x73,0x2E,0x3C,
0x3E,0x2D,0x20,0x22,0x55,0x6E,0x6C,0x69,0x6D,0x69,0x74,0x65,
0x64,0x22,0x20,0x73,0x61,0x6D,0x70,0x6C,0x65,0x20,0x6C,0x65,
- 0x6E,0x67,0x74,0x68,0x2E,0x20,0x28,0x31,0x47,0x42,0x20,0x69,
- 0x6E,0x20,0x74,0x68,0x69,0x73,0x20,0x63,0x6C,0x6F,0x6E,0x65,
- 0x29,0x0D,0x3E,0x2D,0x20,0x38,0x20,0x6F,0x63,0x74,0x61,0x76,
- 0x65,0x73,0x2E,0x1B,0x3E,0x2D,0x20,0x56,0x61,0x72,0x69,0x61,
- 0x62,0x6C,0x65,0x20,0x70,0x61,0x74,0x74,0x65,0x72,0x6E,0x20,
- 0x6C,0x65,0x6E,0x67,0x74,0x68,0x2E,0x22,0x3E,0x2D,0x20,0x42,
- 0x75,0x69,0x6C,0x74,0x20,0x69,0x6E,0x20,0x73,0x61,0x6D,0x70,
- 0x6C,0x65,0x72,0x2F,0x73,0x61,0x6D,0x70,0x6C,0x65,0x20,0x65,
- 0x64,0x69,0x74,0x6F,0x72,0x2E,0x16,0x3E,0x2D,0x20,0x55,0x70,
- 0x20,0x74,0x6F,0x20,0x32,0x35,0x36,0x20,0x70,0x61,0x74,0x74,
- 0x65,0x72,0x6E,0x73,0x2E,0x19,0x3E,0x2D,0x20,0x53,0x6F,0x6E,
- 0x67,0x20,0x6C,0x65,0x6E,0x67,0x74,0x68,0x20,0x75,0x70,0x20,
- 0x74,0x6F,0x20,0x32,0x35,0x36,0x2E,0x25,0x3E,0x2D,0x20,0x4E,
- 0x65,0x77,0x20,0x76,0x6F,0x6C,0x75,0x6D,0x65,0x2F,0x70,0x61,
- 0x6E,0x6E,0x69,0x6E,0x67,0x2F,0x76,0x69,0x62,0x72,0x61,0x74,
- 0x6F,0x20,0x63,0x6F,0x6C,0x75,0x6D,0x6E,0x2E,0x0F,0x3E,0x2D,
- 0x20,0x53,0x6F,0x6E,0x67,0x20,0x65,0x64,0x69,0x74,0x6F,0x72,
- 0x2E,0x19,0x3E,0x2D,0x20,0x46,0x75,0x6C,0x6C,0x20,0x73,0x63,
- 0x72,0x65,0x65,0x6E,0x20,0x65,0x64,0x69,0x74,0x20,0x6D,0x6F,
- 0x64,0x65,0x2E,0x1F,0x3E,0x2D,0x20,0x49,0x6D,0x70,0x72,0x6F,
- 0x76,0x65,0x64,0x20,0x65,0x64,0x69,0x74,0x69,0x6E,0x67,0x20,
- 0x66,0x61,0x63,0x69,0x6C,0x69,0x74,0x69,0x65,0x73,0x2E,0x00,
- 0x3C,0x40,0x58,0x30,0x34,0x30,0x40,0x43,0x30,0x30,0x31,0x54,
- 0x68,0x65,0x20,0x46,0x54,0x32,0x20,0x63,0x6C,0x6F,0x6E,0x65,
- 0x20,0x73,0x75,0x70,0x70,0x6F,0x72,0x74,0x73,0x20,0x74,0x68,
- 0x65,0x20,0x66,0x6F,0x6C,0x6C,0x6F,0x77,0x69,0x6E,0x67,0x20,
- 0x66,0x69,0x6C,0x65,0x20,0x66,0x6F,0x72,0x6D,0x61,0x74,0x73,
- 0x3A,0x00,0x12,0x40,0x58,0x30,0x34,0x30,0x40,0x43,0x30,0x30,
- 0x31,0x4D,0x6F,0x64,0x75,0x6C,0x65,0x73,0x3A,0x0B,0x3E,0x40,
- 0x58,0x30,0x36,0x30,0x40,0x43,0x30,0x30,0x32,0x32,0x3E,0x2D,
- 0x20,0x53,0x74,0x61,0x6E,0x64,0x61,0x72,0x64,0x20,0x6D,0x6F,
- 0x64,0x75,0x6C,0x65,0x73,0x20,0x28,0x31,0x35,0x2F,0x33,0x31,
- 0x20,0x73,0x61,0x6D,0x70,0x6C,0x65,0x73,0x29,0x2E,0x20,0x28,
- 0x4D,0x4F,0x44,0x2C,0x4E,0x53,0x54,0x2C,0x53,0x54,0x4B,0x29,
- 0x23,0x3E,0x2D,0x20,0x46,0x61,0x73,0x74,0x74,0x72,0x61,0x63,
- 0x6B,0x65,0x72,0x20,0x49,0x49,0x20,0x6D,0x6F,0x64,0x75,0x6C,
- 0x65,0x73,0x2E,0x20,0x28,0x58,0x4D,0x2C,0x4D,0x4F,0x44,0x29,
- 0x21,0x3E,0x2D,0x20,0x46,0x61,0x73,0x74,0x74,0x72,0x61,0x63,
- 0x6B,0x65,0x72,0x20,0x6D,0x6F,0x64,0x75,0x6C,0x65,0x73,0x2E,
- 0x20,0x28,0x4D,0x4F,0x44,0x2F,0x46,0x53,0x54,0x29,0x00,0x32,
- 0x40,0x58,0x30,0x34,0x30,0x40,0x43,0x30,0x30,0x31,0x45,0x78,
- 0x70,0x65,0x72,0x69,0x6D,0x65,0x6E,0x74,0x61,0x6C,0x20,0x28,
- 0x69,0x6D,0x70,0x65,0x72,0x66,0x65,0x63,0x74,0x29,0x20,0x6D,
- 0x6F,0x64,0x75,0x6C,0x65,0x20,0x73,0x75,0x70,0x70,0x6F,0x72,
- 0x74,0x3A,0x0B,0x3E,0x40,0x58,0x30,0x36,0x30,0x40,0x43,0x30,
- 0x30,0x32,0x22,0x3E,0x2D,0x20,0x53,0x63,0x72,0x65,0x61,0x6D,
- 0x20,0x54,0x72,0x61,0x63,0x6B,0x65,0x72,0x20,0x33,0x20,0x6D,
- 0x6F,0x64,0x75,0x6C,0x65,0x73,0x2E,0x20,0x28,0x53,0x33,0x4D,
- 0x29,0x22,0x3E,0x2D,0x20,0x53,0x63,0x72,0x65,0x61,0x6D,0x20,
- 0x54,0x72,0x61,0x63,0x6B,0x65,0x72,0x20,0x32,0x20,0x6D,0x6F,
- 0x64,0x75,0x6C,0x65,0x73,0x2E,0x20,0x28,0x53,0x54,0x4D,0x29,
- 0x29,0x3E,0x2D,0x20,0x44,0x49,0x47,0x49,0x20,0x42,0x6F,0x6F,
- 0x73,0x74,0x65,0x72,0x20,0x28,0x6E,0x6F,0x6E,0x2D,0x50,0x72,
- 0x6F,0x29,0x20,0x6D,0x6F,0x64,0x75,0x6C,0x65,0x73,0x2E,0x20,
- 0x28,0x44,0x49,0x47,0x49,0x29,0x00,0x12,0x40,0x58,0x30,0x34,
- 0x30,0x40,0x43,0x30,0x30,0x31,0x53,0x61,0x6D,0x70,0x6C,0x65,
- 0x73,0x3A,0x0B,0x3E,0x40,0x58,0x30,0x36,0x30,0x40,0x43,0x30,
- 0x30,0x32,0x22,0x3E,0x2D,0x20,0x47,0x72,0x61,0x76,0x69,0x73,
- 0x20,0x55,0x6C,0x74,0x72,0x61,0x73,0x6F,0x75,0x6E,0x64,0x20,
- 0x50,0x61,0x74,0x63,0x68,0x65,0x73,0x2C,0x20,0x50,0x41,0x54,
- 0x2E,0x33,0x3E,0x2D,0x20,0x53,0x4D,0x50,0x2F,0x53,0x41,0x4D,
- 0x2F,0x52,0x41,0x57,0x2F,0x53,0x4E,0x44,0x20,0x64,0x61,0x74,
- 0x61,0x20,0x66,0x69,0x6C,0x65,0x73,0x2C,0x20,0x73,0x69,0x67,
- 0x6E,0x65,0x64,0x20,0x61,0x6E,0x64,0x20,0x75,0x6E,0x73,0x69,
- 0x67,0x6E,0x65,0x64,0x2E,0x0D,0x3E,0x2D,0x20,0x57,0x41,0x56,
- 0x20,0x66,0x69,0x6C,0x65,0x73,0x2E,0x0D,0x3E,0x2D,0x20,0x41,
- 0x6D,0x69,0x67,0x61,0x20,0x49,0x46,0x46,0x2E,0x0E,0x3E,0x2D,
- 0x20,0x41,0x70,0x70,0x6C,0x65,0x20,0x41,0x49,0x46,0x46,0x2E,
- 0x00,0x32,0x40,0x58,0x30,0x34,0x30,0x40,0x43,0x30,0x30,0x31,
- 0x46,0x54,0x32,0x20,0x69,0x6E,0x74,0x72,0x6F,0x64,0x75,0x63,
- 0x65,0x73,0x20,0x73,0x65,0x76,0x65,0x72,0x61,0x6C,0x20,0x6E,
- 0x65,0x77,0x20,0x66,0x69,0x6C,0x65,0x20,0x66,0x6F,0x72,0x6D,
- 0x61,0x74,0x73,0x3A,0x0B,0x3E,0x40,0x58,0x30,0x36,0x30,0x40,
- 0x43,0x30,0x30,0x32,0x1C,0x3E,0x2D,0x20,0x58,0x4D,0x20,0x20,
- 0x40,0x54,0x31,0x31,0x30,0x45,0x78,0x74,0x65,0x6E,0x64,0x65,
- 0x64,0x20,0x6D,0x6F,0x64,0x75,0x6C,0x65,0x2E,0x20,0x3E,0x2D,
- 0x20,0x58,0x49,0x20,0x20,0x40,0x54,0x31,0x31,0x30,0x45,0x78,
- 0x74,0x65,0x6E,0x64,0x65,0x64,0x20,0x69,0x6E,0x73,0x74,0x72,
- 0x75,0x6D,0x65,0x6E,0x74,0x2E,0x1D,0x3E,0x2D,0x20,0x58,0x50,
- 0x20,0x20,0x40,0x54,0x31,0x31,0x30,0x45,0x78,0x74,0x65,0x6E,
- 0x64,0x65,0x64,0x20,0x70,0x61,0x74,0x74,0x65,0x72,0x6E,0x2E,
- 0x1B,0x3E,0x2D,0x20,0x58,0x54,0x20,0x20,0x40,0x54,0x31,0x31,
- 0x30,0x45,0x78,0x74,0x65,0x6E,0x64,0x65,0x64,0x20,0x74,0x72,
- 0x61,0x63,0x6B,0x2E,0x00,0x03,0x45,0x4E,0x44,0x4C,0x3B,0x2A,
+ 0x6E,0x67,0x74,0x68,0x2E,0x20,0x28,0x31,0x47,0x42,0x20,0x70,
+ 0x65,0x72,0x20,0x73,0x61,0x6D,0x70,0x6C,0x65,0x20,0x69,0x6E,
+ 0x20,0x74,0x68,0x69,0x73,0x20,0x63,0x6C,0x6F,0x6E,0x65,0x29,
+ 0x0D,0x3E,0x2D,0x20,0x38,0x20,0x6F,0x63,0x74,0x61,0x76,0x65,
+ 0x73,0x2E,0x1B,0x3E,0x2D,0x20,0x56,0x61,0x72,0x69,0x61,0x62,
+ 0x6C,0x65,0x20,0x70,0x61,0x74,0x74,0x65,0x72,0x6E,0x20,0x6C,
+ 0x65,0x6E,0x67,0x74,0x68,0x2E,0x22,0x3E,0x2D,0x20,0x42,0x75,
+ 0x69,0x6C,0x74,0x20,0x69,0x6E,0x20,0x73,0x61,0x6D,0x70,0x6C,
+ 0x65,0x72,0x2F,0x73,0x61,0x6D,0x70,0x6C,0x65,0x20,0x65,0x64,
+ 0x69,0x74,0x6F,0x72,0x2E,0x16,0x3E,0x2D,0x20,0x55,0x70,0x20,
+ 0x74,0x6F,0x20,0x32,0x35,0x36,0x20,0x70,0x61,0x74,0x74,0x65,
+ 0x72,0x6E,0x73,0x2E,0x19,0x3E,0x2D,0x20,0x53,0x6F,0x6E,0x67,
+ 0x20,0x6C,0x65,0x6E,0x67,0x74,0x68,0x20,0x75,0x70,0x20,0x74,
+ 0x6F,0x20,0x32,0x35,0x36,0x2E,0x25,0x3E,0x2D,0x20,0x4E,0x65,
+ 0x77,0x20,0x76,0x6F,0x6C,0x75,0x6D,0x65,0x2F,0x70,0x61,0x6E,
+ 0x6E,0x69,0x6E,0x67,0x2F,0x76,0x69,0x62,0x72,0x61,0x74,0x6F,
+ 0x20,0x63,0x6F,0x6C,0x75,0x6D,0x6E,0x2E,0x0F,0x3E,0x2D,0x20,
+ 0x53,0x6F,0x6E,0x67,0x20,0x65,0x64,0x69,0x74,0x6F,0x72,0x2E,
+ 0x19,0x3E,0x2D,0x20,0x46,0x75,0x6C,0x6C,0x20,0x73,0x63,0x72,
+ 0x65,0x65,0x6E,0x20,0x65,0x64,0x69,0x74,0x20,0x6D,0x6F,0x64,
+ 0x65,0x2E,0x1F,0x3E,0x2D,0x20,0x49,0x6D,0x70,0x72,0x6F,0x76,
+ 0x65,0x64,0x20,0x65,0x64,0x69,0x74,0x69,0x6E,0x67,0x20,0x66,
+ 0x61,0x63,0x69,0x6C,0x69,0x74,0x69,0x65,0x73,0x2E,0x00,0x3C,
+ 0x40,0x58,0x30,0x34,0x30,0x40,0x43,0x30,0x30,0x31,0x54,0x68,
+ 0x65,0x20,0x46,0x54,0x32,0x20,0x63,0x6C,0x6F,0x6E,0x65,0x20,
+ 0x73,0x75,0x70,0x70,0x6F,0x72,0x74,0x73,0x20,0x74,0x68,0x65,
+ 0x20,0x66,0x6F,0x6C,0x6C,0x6F,0x77,0x69,0x6E,0x67,0x20,0x66,
+ 0x69,0x6C,0x65,0x20,0x66,0x6F,0x72,0x6D,0x61,0x74,0x73,0x3A,
+ 0x00,0x12,0x40,0x58,0x30,0x34,0x30,0x40,0x43,0x30,0x30,0x31,
+ 0x4D,0x6F,0x64,0x75,0x6C,0x65,0x73,0x3A,0x0B,0x3E,0x40,0x58,
+ 0x30,0x36,0x30,0x40,0x43,0x30,0x30,0x32,0x32,0x3E,0x2D,0x20,
+ 0x53,0x74,0x61,0x6E,0x64,0x61,0x72,0x64,0x20,0x6D,0x6F,0x64,
+ 0x75,0x6C,0x65,0x73,0x20,0x28,0x31,0x35,0x2F,0x33,0x31,0x20,
+ 0x73,0x61,0x6D,0x70,0x6C,0x65,0x73,0x29,0x2E,0x20,0x28,0x4D,
+ 0x4F,0x44,0x2C,0x4E,0x53,0x54,0x2C,0x53,0x54,0x4B,0x29,0x23,
+ 0x3E,0x2D,0x20,0x46,0x61,0x73,0x74,0x74,0x72,0x61,0x63,0x6B,
+ 0x65,0x72,0x20,0x49,0x49,0x20,0x6D,0x6F,0x64,0x75,0x6C,0x65,
+ 0x73,0x2E,0x20,0x28,0x58,0x4D,0x2C,0x4D,0x4F,0x44,0x29,0x21,
+ 0x3E,0x2D,0x20,0x46,0x61,0x73,0x74,0x74,0x72,0x61,0x63,0x6B,
+ 0x65,0x72,0x20,0x6D,0x6F,0x64,0x75,0x6C,0x65,0x73,0x2E,0x20,
+ 0x28,0x4D,0x4F,0x44,0x2F,0x46,0x53,0x54,0x29,0x00,0x32,0x40,
+ 0x58,0x30,0x34,0x30,0x40,0x43,0x30,0x30,0x31,0x45,0x78,0x70,
+ 0x65,0x72,0x69,0x6D,0x65,0x6E,0x74,0x61,0x6C,0x20,0x28,0x69,
+ 0x6D,0x70,0x65,0x72,0x66,0x65,0x63,0x74,0x29,0x20,0x6D,0x6F,
+ 0x64,0x75,0x6C,0x65,0x20,0x73,0x75,0x70,0x70,0x6F,0x72,0x74,
+ 0x3A,0x0B,0x3E,0x40,0x58,0x30,0x36,0x30,0x40,0x43,0x30,0x30,
+ 0x32,0x22,0x3E,0x2D,0x20,0x53,0x63,0x72,0x65,0x61,0x6D,0x20,
+ 0x54,0x72,0x61,0x63,0x6B,0x65,0x72,0x20,0x33,0x20,0x6D,0x6F,
+ 0x64,0x75,0x6C,0x65,0x73,0x2E,0x20,0x28,0x53,0x33,0x4D,0x29,
+ 0x22,0x3E,0x2D,0x20,0x53,0x63,0x72,0x65,0x61,0x6D,0x20,0x54,
+ 0x72,0x61,0x63,0x6B,0x65,0x72,0x20,0x32,0x20,0x6D,0x6F,0x64,
+ 0x75,0x6C,0x65,0x73,0x2E,0x20,0x28,0x53,0x54,0x4D,0x29,0x29,
+ 0x3E,0x2D,0x20,0x44,0x49,0x47,0x49,0x20,0x42,0x6F,0x6F,0x73,
+ 0x74,0x65,0x72,0x20,0x28,0x6E,0x6F,0x6E,0x2D,0x50,0x72,0x6F,
+ 0x29,0x20,0x6D,0x6F,0x64,0x75,0x6C,0x65,0x73,0x2E,0x20,0x28,
+ 0x44,0x49,0x47,0x49,0x29,0x00,0x12,0x40,0x58,0x30,0x34,0x30,
+ 0x40,0x43,0x30,0x30,0x31,0x53,0x61,0x6D,0x70,0x6C,0x65,0x73,
+ 0x3A,0x0B,0x3E,0x40,0x58,0x30,0x36,0x30,0x40,0x43,0x30,0x30,
+ 0x32,0x22,0x3E,0x2D,0x20,0x47,0x72,0x61,0x76,0x69,0x73,0x20,
+ 0x55,0x6C,0x74,0x72,0x61,0x73,0x6F,0x75,0x6E,0x64,0x20,0x50,
+ 0x61,0x74,0x63,0x68,0x65,0x73,0x2C,0x20,0x50,0x41,0x54,0x2E,
+ 0x33,0x3E,0x2D,0x20,0x53,0x4D,0x50,0x2F,0x53,0x41,0x4D,0x2F,
+ 0x52,0x41,0x57,0x2F,0x53,0x4E,0x44,0x20,0x64,0x61,0x74,0x61,
+ 0x20,0x66,0x69,0x6C,0x65,0x73,0x2C,0x20,0x73,0x69,0x67,0x6E,
+ 0x65,0x64,0x20,0x61,0x6E,0x64,0x20,0x75,0x6E,0x73,0x69,0x67,
+ 0x6E,0x65,0x64,0x2E,0x0D,0x3E,0x2D,0x20,0x57,0x41,0x56,0x20,
+ 0x66,0x69,0x6C,0x65,0x73,0x2E,0x0D,0x3E,0x2D,0x20,0x41,0x6D,
+ 0x69,0x67,0x61,0x20,0x49,0x46,0x46,0x2E,0x0E,0x3E,0x2D,0x20,
+ 0x41,0x70,0x70,0x6C,0x65,0x20,0x41,0x49,0x46,0x46,0x2E,0x00,
+ 0x32,0x40,0x58,0x30,0x34,0x30,0x40,0x43,0x30,0x30,0x31,0x46,
+ 0x54,0x32,0x20,0x69,0x6E,0x74,0x72,0x6F,0x64,0x75,0x63,0x65,
+ 0x73,0x20,0x73,0x65,0x76,0x65,0x72,0x61,0x6C,0x20,0x6E,0x65,
+ 0x77,0x20,0x66,0x69,0x6C,0x65,0x20,0x66,0x6F,0x72,0x6D,0x61,
+ 0x74,0x73,0x3A,0x0B,0x3E,0x40,0x58,0x30,0x36,0x30,0x40,0x43,
+ 0x30,0x30,0x32,0x1C,0x3E,0x2D,0x20,0x58,0x4D,0x20,0x20,0x40,
+ 0x54,0x31,0x31,0x30,0x45,0x78,0x74,0x65,0x6E,0x64,0x65,0x64,
+ 0x20,0x6D,0x6F,0x64,0x75,0x6C,0x65,0x2E,0x20,0x3E,0x2D,0x20,
+ 0x58,0x49,0x20,0x20,0x40,0x54,0x31,0x31,0x30,0x45,0x78,0x74,
+ 0x65,0x6E,0x64,0x65,0x64,0x20,0x69,0x6E,0x73,0x74,0x72,0x75,
+ 0x6D,0x65,0x6E,0x74,0x2E,0x1D,0x3E,0x2D,0x20,0x58,0x50,0x20,
+ 0x20,0x40,0x54,0x31,0x31,0x30,0x45,0x78,0x74,0x65,0x6E,0x64,
+ 0x65,0x64,0x20,0x70,0x61,0x74,0x74,0x65,0x72,0x6E,0x2E,0x1B,
+ 0x3E,0x2D,0x20,0x58,0x54,0x20,0x20,0x40,0x54,0x31,0x31,0x30,
+ 0x45,0x78,0x74,0x65,0x6E,0x64,0x65,0x64,0x20,0x74,0x72,0x61,
+ 0x63,0x6B,0x2E,0x00,0x03,0x45,0x4E,0x44,0x4C,0x3B,0x2A,0x2A,
0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,
0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,
0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,
@@ -131,1447 +132,1467 @@
0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,
0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,
0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,
- 0x2A,0x2A,0x4C,0x3B,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,
+ 0x2A,0x4C,0x3B,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,
0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,
0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,
0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,
0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,
0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,
- 0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x09,0x40,0x4C,0x45,0x66,
- 0x66,0x65,0x63,0x74,0x73,0x00,0x18,0x40,0x58,0x30,0x34,0x30,
- 0x40,0x43,0x30,0x30,0x31,0x53,0x68,0x6F,0x72,0x74,0x20,0x73,
- 0x75,0x6D,0x6D,0x61,0x72,0x79,0x3A,0x0B,0x3E,0x40,0x58,0x30,
- 0x36,0x30,0x40,0x43,0x30,0x30,0x32,0x0B,0x3E,0x30,0x20,0x41,
- 0x72,0x70,0x65,0x67,0x67,0x69,0x6F,0x10,0x3E,0x31,0x20,0x50,
- 0x6F,0x72,0x74,0x61,0x6D,0x65,0x6E,0x74,0x6F,0x20,0x75,0x70,
- 0x12,0x3E,0x32,0x20,0x50,0x6F,0x72,0x74,0x61,0x6D,0x65,0x6E,
- 0x74,0x6F,0x20,0x64,0x6F,0x77,0x6E,0x12,0x3E,0x33,0x20,0x54,
- 0x6F,0x6E,0x65,0x20,0x70,0x6F,0x72,0x74,0x61,0x6D,0x65,0x6E,
- 0x74,0x6F,0x0A,0x3E,0x34,0x20,0x56,0x69,0x62,0x72,0x61,0x74,
- 0x6F,0x1C,0x3E,0x35,0x20,0x50,0x6F,0x72,0x74,0x61,0x6D,0x65,
- 0x6E,0x74,0x6F,0x20,0x2B,0x20,0x56,0x6F,0x6C,0x75,0x6D,0x65,
- 0x20,0x73,0x6C,0x69,0x64,0x65,0x19,0x3E,0x36,0x20,0x56,0x69,
- 0x62,0x72,0x61,0x74,0x6F,0x20,0x2B,0x20,0x56,0x6F,0x6C,0x75,
- 0x6D,0x65,0x20,0x73,0x6C,0x69,0x64,0x65,0x0A,0x3E,0x37,0x20,
- 0x54,0x72,0x65,0x6D,0x6F,0x6C,0x6F,0x17,0x3E,0x38,0x20,0x53,
- 0x65,0x74,0x20,0x70,0x61,0x6E,0x6E,0x69,0x6E,0x67,0x20,0x70,
- 0x6F,0x73,0x69,0x74,0x69,0x6F,0x6E,0x10,0x3E,0x39,0x20,0x53,
- 0x61,0x6D,0x70,0x6C,0x65,0x20,0x6F,0x66,0x66,0x73,0x65,0x74,
- 0x0F,0x3E,0x41,0x20,0x56,0x6F,0x6C,0x75,0x6D,0x65,0x20,0x73,
- 0x6C,0x69,0x64,0x65,0x10,0x3E,0x42,0x20,0x50,0x6F,0x73,0x69,
- 0x74,0x69,0x6F,0x6E,0x20,0x6A,0x75,0x6D,0x70,0x0D,0x3E,0x43,
- 0x20,0x53,0x65,0x74,0x20,0x76,0x6F,0x6C,0x75,0x6D,0x65,0x10,
- 0x3E,0x44,0x20,0x50,0x61,0x74,0x74,0x65,0x72,0x6E,0x20,0x62,
- 0x72,0x65,0x61,0x6B,0x04,0x3E,0x45,0x20,0x2B,0x23,0x3E,0x40,
- 0x58,0x30,0x38,0x30,0x30,0x20,0x46,0x69,0x6C,0x74,0x65,0x72,
- 0x20,0x6F,0x6E,0x2F,0x6F,0x66,0x66,0x20,0x28,0x41,0x6D,0x69,
- 0x67,0x61,0x20,0x6F,0x6E,0x6C,0x79,0x21,0x29,0x15,0x3E,0x31,
- 0x20,0x46,0x69,0x6E,0x65,0x20,0x70,0x6F,0x72,0x74,0x61,0x6D,
- 0x65,0x6E,0x74,0x6F,0x20,0x75,0x70,0x17,0x3E,0x32,0x20,0x46,
- 0x69,0x6E,0x65,0x20,0x70,0x6F,0x72,0x74,0x61,0x6D,0x65,0x6E,
- 0x74,0x6F,0x20,0x64,0x6F,0x77,0x6E,0x18,0x3E,0x33,0x20,0x53,
- 0x65,0x74,0x20,0x67,0x6C,0x69,0x73,0x73,0x61,0x6E,0x64,0x6F,
- 0x20,0x63,0x6F,0x6E,0x74,0x72,0x6F,0x6C,0x16,0x3E,0x34,0x20,
- 0x53,0x65,0x74,0x20,0x76,0x69,0x62,0x72,0x61,0x74,0x6F,0x20,
- 0x63,0x6F,0x6E,0x74,0x72,0x6F,0x6C,0x10,0x3E,0x35,0x20,0x53,
- 0x65,0x74,0x20,0x66,0x69,0x6E,0x65,0x2D,0x74,0x75,0x6E,0x65,
- 0x0C,0x3E,0x36,0x20,0x4A,0x75,0x6D,0x70,0x20,0x6C,0x6F,0x6F,
- 0x70,0x16,0x3E,0x37,0x20,0x53,0x65,0x74,0x20,0x74,0x72,0x65,
- 0x6D,0x6F,0x6C,0x6F,0x20,0x63,0x6F,0x6E,0x74,0x72,0x6F,0x6C,
- 0x09,0x3E,0x38,0x20,0x55,0x6E,0x75,0x73,0x65,0x64,0x0E,0x3E,
- 0x39,0x20,0x52,0x65,0x74,0x72,0x69,0x67,0x20,0x6E,0x6F,0x74,
- 0x65,0x17,0x3E,0x41,0x20,0x46,0x69,0x6E,0x65,0x20,0x76,0x6F,
- 0x6C,0x75,0x6D,0x65,0x20,0x73,0x6C,0x69,0x64,0x65,0x20,0x75,
- 0x70,0x19,0x3E,0x42,0x20,0x46,0x69,0x6E,0x65,0x20,0x76,0x6F,
- 0x6C,0x75,0x6D,0x65,0x20,0x73,0x6C,0x69,0x64,0x65,0x20,0x64,
- 0x6F,0x77,0x6E,0x0B,0x3E,0x43,0x20,0x4E,0x6F,0x74,0x65,0x20,
- 0x63,0x75,0x74,0x0D,0x3E,0x44,0x20,0x4E,0x6F,0x74,0x65,0x20,
- 0x64,0x65,0x6C,0x61,0x79,0x10,0x3E,0x45,0x20,0x50,0x61,0x74,
- 0x74,0x65,0x72,0x6E,0x20,0x64,0x65,0x6C,0x61,0x79,0x1D,0x3E,
- 0x46,0x20,0x46,0x75,0x6E,0x6B,0x20,0x69,0x74,0x21,0x20,0x28,
- 0x4E,0x6F,0x74,0x20,0x69,0x6D,0x70,0x6C,0x65,0x6D,0x65,0x6E,
- 0x74,0x65,0x64,0x29,0x06,0x3E,0x40,0x58,0x30,0x36,0x30,0x0B,
- 0x46,0x20,0x53,0x65,0x74,0x20,0x73,0x70,0x65,0x65,0x64,0x14,
- 0x3E,0x47,0x20,0x53,0x65,0x74,0x20,0x67,0x6C,0x6F,0x62,0x61,
- 0x6C,0x20,0x76,0x6F,0x6C,0x75,0x6D,0x65,0x16,0x3E,0x48,0x20,
- 0x47,0x6C,0x6F,0x62,0x61,0x6C,0x20,0x76,0x6F,0x6C,0x75,0x6D,
- 0x65,0x20,0x73,0x6C,0x69,0x64,0x65,0x0A,0x3E,0x4B,0x20,0x4B,
- 0x65,0x79,0x20,0x6F,0x66,0x66,0x18,0x3E,0x4C,0x20,0x53,0x65,
- 0x74,0x20,0x65,0x6E,0x76,0x65,0x6C,0x6F,0x70,0x65,0x20,0x70,
- 0x6F,0x73,0x69,0x74,0x69,0x6F,0x6E,0x10,0x3E,0x50,0x20,0x50,
- 0x61,0x6E,0x6E,0x69,0x6E,0x67,0x20,0x73,0x6C,0x69,0x64,0x65,
- 0x14,0x3E,0x52,0x20,0x4D,0x75,0x6C,0x74,0x69,0x20,0x72,0x65,
- 0x74,0x72,0x69,0x67,0x20,0x6E,0x6F,0x74,0x65,0x09,0x3E,0x54,
- 0x20,0x54,0x72,0x65,0x6D,0x6F,0x72,0x04,0x3E,0x58,0x20,0x2B,
- 0x20,0x3E,0x40,0x58,0x30,0x38,0x30,0x31,0x20,0x45,0x78,0x74,
- 0x72,0x61,0x20,0x66,0x69,0x6E,0x65,0x20,0x70,0x6F,0x72,0x74,
- 0x61,0x6D,0x65,0x6E,0x74,0x6F,0x20,0x75,0x70,0x1D,0x3E,0x32,
- 0x20,0x45,0x78,0x74,0x72,0x61,0x20,0x66,0x69,0x6E,0x65,0x20,
- 0x70,0x6F,0x72,0x74,0x61,0x6D,0x65,0x6E,0x74,0x6F,0x20,0x64,
- 0x6F,0x77,0x6E,0x00,0x18,0x40,0x58,0x30,0x34,0x30,0x40,0x43,
- 0x30,0x30,0x31,0x56,0x6F,0x6C,0x75,0x6D,0x65,0x20,0x63,0x6F,
- 0x6C,0x75,0x6D,0x6E,0x3A,0x0B,0x3E,0x40,0x58,0x30,0x36,0x30,
- 0x40,0x43,0x30,0x30,0x32,0x17,0x30,0x30,0x2E,0x2E,0x34,0x30,
- 0x20,0x40,0x54,0x31,0x36,0x30,0x53,0x65,0x74,0x20,0x76,0x6F,
- 0x6C,0x75,0x6D,0x65,0x2E,0x01,0x3E,0x1A,0x3E,0x2D,0x20,0x40,
- 0x54,0x31,0x36,0x30,0x56,0x6F,0x6C,0x75,0x6D,0x65,0x20,0x73,
- 0x6C,0x69,0x64,0x65,0x20,0x64,0x6F,0x77,0x6E,0x2E,0x18,0x3E,
- 0x2B,0x20,0x40,0x54,0x31,0x36,0x30,0x56,0x6F,0x6C,0x75,0x6D,
- 0x65,0x20,0x73,0x6C,0x69,0x64,0x65,0x20,0x75,0x70,0x2E,0x35,
- 0x3E,0x44,0x20,0x40,0x54,0x31,0x36,0x30,0x46,0x69,0x6E,0x65,
+ 0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x09,0x40,0x4C,0x45,0x66,0x66,
+ 0x65,0x63,0x74,0x73,0x00,0x18,0x40,0x58,0x30,0x34,0x30,0x40,
+ 0x43,0x30,0x30,0x31,0x53,0x68,0x6F,0x72,0x74,0x20,0x73,0x75,
+ 0x6D,0x6D,0x61,0x72,0x79,0x3A,0x0B,0x3E,0x40,0x58,0x30,0x36,
+ 0x30,0x40,0x43,0x30,0x30,0x32,0x0B,0x3E,0x30,0x20,0x41,0x72,
+ 0x70,0x65,0x67,0x67,0x69,0x6F,0x10,0x3E,0x31,0x20,0x50,0x6F,
+ 0x72,0x74,0x61,0x6D,0x65,0x6E,0x74,0x6F,0x20,0x75,0x70,0x12,
+ 0x3E,0x32,0x20,0x50,0x6F,0x72,0x74,0x61,0x6D,0x65,0x6E,0x74,
+ 0x6F,0x20,0x64,0x6F,0x77,0x6E,0x12,0x3E,0x33,0x20,0x54,0x6F,
+ 0x6E,0x65,0x20,0x70,0x6F,0x72,0x74,0x61,0x6D,0x65,0x6E,0x74,
+ 0x6F,0x0A,0x3E,0x34,0x20,0x56,0x69,0x62,0x72,0x61,0x74,0x6F,
+ 0x1C,0x3E,0x35,0x20,0x50,0x6F,0x72,0x74,0x61,0x6D,0x65,0x6E,
+ 0x74,0x6F,0x20,0x2B,0x20,0x56,0x6F,0x6C,0x75,0x6D,0x65,0x20,
+ 0x73,0x6C,0x69,0x64,0x65,0x19,0x3E,0x36,0x20,0x56,0x69,0x62,
+ 0x72,0x61,0x74,0x6F,0x20,0x2B,0x20,0x56,0x6F,0x6C,0x75,0x6D,
+ 0x65,0x20,0x73,0x6C,0x69,0x64,0x65,0x0A,0x3E,0x37,0x20,0x54,
+ 0x72,0x65,0x6D,0x6F,0x6C,0x6F,0x17,0x3E,0x38,0x20,0x53,0x65,
+ 0x74,0x20,0x70,0x61,0x6E,0x6E,0x69,0x6E,0x67,0x20,0x70,0x6F,
+ 0x73,0x69,0x74,0x69,0x6F,0x6E,0x10,0x3E,0x39,0x20,0x53,0x61,
+ 0x6D,0x70,0x6C,0x65,0x20,0x6F,0x66,0x66,0x73,0x65,0x74,0x0F,
+ 0x3E,0x41,0x20,0x56,0x6F,0x6C,0x75,0x6D,0x65,0x20,0x73,0x6C,
+ 0x69,0x64,0x65,0x10,0x3E,0x42,0x20,0x50,0x6F,0x73,0x69,0x74,
+ 0x69,0x6F,0x6E,0x20,0x6A,0x75,0x6D,0x70,0x0D,0x3E,0x43,0x20,
+ 0x53,0x65,0x74,0x20,0x76,0x6F,0x6C,0x75,0x6D,0x65,0x10,0x3E,
+ 0x44,0x20,0x50,0x61,0x74,0x74,0x65,0x72,0x6E,0x20,0x62,0x72,
+ 0x65,0x61,0x6B,0x04,0x3E,0x45,0x20,0x2B,0x23,0x3E,0x40,0x58,
+ 0x30,0x38,0x30,0x30,0x20,0x46,0x69,0x6C,0x74,0x65,0x72,0x20,
+ 0x6F,0x6E,0x2F,0x6F,0x66,0x66,0x20,0x28,0x41,0x6D,0x69,0x67,
+ 0x61,0x20,0x6F,0x6E,0x6C,0x79,0x21,0x29,0x15,0x3E,0x31,0x20,
+ 0x46,0x69,0x6E,0x65,0x20,0x70,0x6F,0x72,0x74,0x61,0x6D,0x65,
+ 0x6E,0x74,0x6F,0x20,0x75,0x70,0x17,0x3E,0x32,0x20,0x46,0x69,
+ 0x6E,0x65,0x20,0x70,0x6F,0x72,0x74,0x61,0x6D,0x65,0x6E,0x74,
+ 0x6F,0x20,0x64,0x6F,0x77,0x6E,0x18,0x3E,0x33,0x20,0x53,0x65,
+ 0x74,0x20,0x67,0x6C,0x69,0x73,0x73,0x61,0x6E,0x64,0x6F,0x20,
+ 0x63,0x6F,0x6E,0x74,0x72,0x6F,0x6C,0x16,0x3E,0x34,0x20,0x53,
+ 0x65,0x74,0x20,0x76,0x69,0x62,0x72,0x61,0x74,0x6F,0x20,0x63,
+ 0x6F,0x6E,0x74,0x72,0x6F,0x6C,0x10,0x3E,0x35,0x20,0x53,0x65,
+ 0x74,0x20,0x66,0x69,0x6E,0x65,0x2D,0x74,0x75,0x6E,0x65,0x0C,
+ 0x3E,0x36,0x20,0x4A,0x75,0x6D,0x70,0x20,0x6C,0x6F,0x6F,0x70,
+ 0x16,0x3E,0x37,0x20,0x53,0x65,0x74,0x20,0x74,0x72,0x65,0x6D,
+ 0x6F,0x6C,0x6F,0x20,0x63,0x6F,0x6E,0x74,0x72,0x6F,0x6C,0x09,
+ 0x3E,0x38,0x20,0x55,0x6E,0x75,0x73,0x65,0x64,0x0E,0x3E,0x39,
+ 0x20,0x52,0x65,0x74,0x72,0x69,0x67,0x20,0x6E,0x6F,0x74,0x65,
+ 0x17,0x3E,0x41,0x20,0x46,0x69,0x6E,0x65,0x20,0x76,0x6F,0x6C,
+ 0x75,0x6D,0x65,0x20,0x73,0x6C,0x69,0x64,0x65,0x20,0x75,0x70,
+ 0x19,0x3E,0x42,0x20,0x46,0x69,0x6E,0x65,0x20,0x76,0x6F,0x6C,
+ 0x75,0x6D,0x65,0x20,0x73,0x6C,0x69,0x64,0x65,0x20,0x64,0x6F,
+ 0x77,0x6E,0x0B,0x3E,0x43,0x20,0x4E,0x6F,0x74,0x65,0x20,0x63,
+ 0x75,0x74,0x0D,0x3E,0x44,0x20,0x4E,0x6F,0x74,0x65,0x20,0x64,
+ 0x65,0x6C,0x61,0x79,0x10,0x3E,0x45,0x20,0x50,0x61,0x74,0x74,
+ 0x65,0x72,0x6E,0x20,0x64,0x65,0x6C,0x61,0x79,0x1D,0x3E,0x46,
+ 0x20,0x46,0x75,0x6E,0x6B,0x20,0x69,0x74,0x21,0x20,0x28,0x4E,
+ 0x6F,0x74,0x20,0x69,0x6D,0x70,0x6C,0x65,0x6D,0x65,0x6E,0x74,
+ 0x65,0x64,0x29,0x06,0x3E,0x40,0x58,0x30,0x36,0x30,0x0B,0x46,
+ 0x20,0x53,0x65,0x74,0x20,0x73,0x70,0x65,0x65,0x64,0x14,0x3E,
+ 0x47,0x20,0x53,0x65,0x74,0x20,0x67,0x6C,0x6F,0x62,0x61,0x6C,
+ 0x20,0x76,0x6F,0x6C,0x75,0x6D,0x65,0x16,0x3E,0x48,0x20,0x47,
+ 0x6C,0x6F,0x62,0x61,0x6C,0x20,0x76,0x6F,0x6C,0x75,0x6D,0x65,
+ 0x20,0x73,0x6C,0x69,0x64,0x65,0x0A,0x3E,0x4B,0x20,0x4B,0x65,
+ 0x79,0x20,0x6F,0x66,0x66,0x18,0x3E,0x4C,0x20,0x53,0x65,0x74,
+ 0x20,0x65,0x6E,0x76,0x65,0x6C,0x6F,0x70,0x65,0x20,0x70,0x6F,
+ 0x73,0x69,0x74,0x69,0x6F,0x6E,0x10,0x3E,0x50,0x20,0x50,0x61,
+ 0x6E,0x6E,0x69,0x6E,0x67,0x20,0x73,0x6C,0x69,0x64,0x65,0x14,
+ 0x3E,0x52,0x20,0x4D,0x75,0x6C,0x74,0x69,0x20,0x72,0x65,0x74,
+ 0x72,0x69,0x67,0x20,0x6E,0x6F,0x74,0x65,0x09,0x3E,0x54,0x20,
+ 0x54,0x72,0x65,0x6D,0x6F,0x72,0x04,0x3E,0x58,0x20,0x2B,0x20,
+ 0x3E,0x40,0x58,0x30,0x38,0x30,0x31,0x20,0x45,0x78,0x74,0x72,
+ 0x61,0x20,0x66,0x69,0x6E,0x65,0x20,0x70,0x6F,0x72,0x74,0x61,
+ 0x6D,0x65,0x6E,0x74,0x6F,0x20,0x75,0x70,0x1D,0x3E,0x32,0x20,
+ 0x45,0x78,0x74,0x72,0x61,0x20,0x66,0x69,0x6E,0x65,0x20,0x70,
+ 0x6F,0x72,0x74,0x61,0x6D,0x65,0x6E,0x74,0x6F,0x20,0x64,0x6F,
+ 0x77,0x6E,0x00,0x18,0x40,0x58,0x30,0x34,0x30,0x40,0x43,0x30,
+ 0x30,0x31,0x56,0x6F,0x6C,0x75,0x6D,0x65,0x20,0x63,0x6F,0x6C,
+ 0x75,0x6D,0x6E,0x3A,0x0B,0x3E,0x40,0x58,0x30,0x36,0x30,0x40,
+ 0x43,0x30,0x30,0x32,0x17,0x30,0x30,0x2E,0x2E,0x34,0x30,0x20,
+ 0x40,0x54,0x31,0x36,0x30,0x53,0x65,0x74,0x20,0x76,0x6F,0x6C,
+ 0x75,0x6D,0x65,0x2E,0x01,0x3E,0x1A,0x3E,0x2D,0x20,0x40,0x54,
+ 0x31,0x36,0x30,0x56,0x6F,0x6C,0x75,0x6D,0x65,0x20,0x73,0x6C,
+ 0x69,0x64,0x65,0x20,0x64,0x6F,0x77,0x6E,0x2E,0x18,0x3E,0x2B,
+ 0x20,0x40,0x54,0x31,0x36,0x30,0x56,0x6F,0x6C,0x75,0x6D,0x65,
+ 0x20,0x73,0x6C,0x69,0x64,0x65,0x20,0x75,0x70,0x2E,0x35,0x3E,
+ 0x44,0x20,0x40,0x54,0x31,0x36,0x30,0x46,0x69,0x6E,0x65,0x20,
+ 0x76,0x6F,0x6C,0x75,0x6D,0x65,0x20,0x73,0x6C,0x69,0x64,0x65,
+ 0x20,0x64,0x6F,0x77,0x6E,0x2E,0x20,0x28,0x49,0x6E,0x64,0x69,
+ 0x63,0x61,0x74,0x65,0x64,0x20,0x62,0x79,0x20,0x73,0x79,0x6D,
+ 0x62,0x6F,0x6C,0x29,0x33,0x3E,0x55,0x20,0x40,0x54,0x31,0x36,
+ 0x30,0x46,0x69,0x6E,0x65,0x20,0x76,0x6F,0x6C,0x75,0x6D,0x65,
+ 0x20,0x73,0x6C,0x69,0x64,0x65,0x20,0x75,0x70,0x2E,0x20,0x28,
+ 0x49,0x6E,0x64,0x69,0x63,0x61,0x74,0x65,0x64,0x20,0x62,0x79,
+ 0x20,0x73,0x79,0x6D,0x62,0x6F,0x6C,0x29,0x1A,0x3E,0x53,0x20,
+ 0x40,0x54,0x31,0x36,0x30,0x53,0x65,0x74,0x20,0x76,0x69,0x62,
+ 0x72,0x61,0x74,0x6F,0x20,0x73,0x70,0x65,0x65,0x64,0x2E,0x10,
+ 0x3E,0x56,0x20,0x40,0x54,0x31,0x36,0x30,0x56,0x69,0x62,0x72,
+ 0x61,0x74,0x6F,0x2E,0x1D,0x3E,0x50,0x20,0x40,0x54,0x31,0x36,
+ 0x30,0x53,0x65,0x74,0x20,0x70,0x61,0x6E,0x6E,0x69,0x6E,0x67,
+ 0x20,0x70,0x6F,0x73,0x69,0x74,0x69,0x6F,0x6E,0x2E,0x32,0x3E,
+ 0x52,0x20,0x40,0x54,0x31,0x36,0x30,0x50,0x61,0x6E,0x6E,0x69,
+ 0x6E,0x67,0x20,0x73,0x6C,0x69,0x64,0x65,0x20,0x72,0x69,0x67,
+ 0x68,0x74,0x2E,0x20,0x28,0x49,0x6E,0x64,0x69,0x63,0x61,0x74,
+ 0x65,0x64,0x20,0x62,0x79,0x20,0x73,0x79,0x6D,0x62,0x6F,0x6C,
+ 0x29,0x31,0x3E,0x4C,0x20,0x40,0x54,0x31,0x36,0x30,0x50,0x61,
+ 0x6E,0x6E,0x69,0x6E,0x67,0x20,0x73,0x6C,0x69,0x64,0x65,0x20,
+ 0x6C,0x65,0x66,0x74,0x2E,0x20,0x28,0x49,0x6E,0x64,0x69,0x63,
+ 0x61,0x74,0x65,0x64,0x20,0x62,0x79,0x20,0x73,0x79,0x6D,0x62,
+ 0x6F,0x6C,0x29,0x18,0x3E,0x4D,0x20,0x40,0x54,0x31,0x36,0x30,
+ 0x54,0x6F,0x6E,0x65,0x20,0x70,0x6F,0x72,0x74,0x61,0x6D,0x65,
+ 0x6E,0x74,0x6F,0x2E,0x00,0x00,0x1B,0x40,0x4C,0x40,0x58,0x30,
+ 0x30,0x30,0x44,0x65,0x74,0x61,0x69,0x6C,0x65,0x64,0x20,0x69,
+ 0x6E,0x66,0x6F,0x72,0x6D,0x61,0x74,0x69,0x6F,0x6E,0x00,0x12,
+ 0x40,0x58,0x30,0x34,0x30,0x40,0x43,0x30,0x30,0x31,0x41,0x72,
+ 0x70,0x65,0x67,0x67,0x69,0x6F,0x0B,0x3E,0x40,0x58,0x30,0x36,
+ 0x30,0x40,0x43,0x30,0x30,0x32,0x27,0x53,0x79,0x6E,0x74,0x61,
+ 0x78,0x3A,0x20,0x30,0x20,0x2B,0x20,0x31,0x73,0x74,0x20,0x68,
+ 0x61,0x6C,0x66,0x74,0x6F,0x6E,0x65,0x20,0x2B,0x20,0x32,0x6E,
+ 0x64,0x20,0x68,0x61,0x6C,0x66,0x74,0x6F,0x6E,0x65,0x00,0x0D,
+ 0x45,0x78,0x2E,0x3A,0x20,0x43,0x2D,0x31,0x20,0x20,0x30,0x33,
+ 0x37,0x00,0x16,0x3E,0x31,0x30,0x20,0x50,0x6C,0x61,0x79,0x73,
+ 0x20,0x43,0x2D,0x31,0x20,0x74,0x69,0x63,0x6B,0x20,0x23,0x31,
+ 0x2E,0x26,0x3E,0x32,0x30,0x20,0x50,0x6C,0x61,0x79,0x73,0x20,
+ 0x43,0x2D,0x31,0x20,0x2B,0x20,0x33,0x20,0x4E,0x6F,0x74,0x65,
+ 0x73,0x20,0x3D,0x20,0x44,0x23,0x31,0x20,0x74,0x69,0x63,0x6B,
+ 0x20,0x23,0x32,0x2E,0x26,0x3E,0x33,0x30,0x20,0x50,0x6C,0x61,
+ 0x79,0x73,0x20,0x43,0x2D,0x31,0x20,0x2B,0x20,0x37,0x20,0x4E,
+ 0x6F,0x74,0x65,0x73,0x20,0x3D,0x20,0x47,0x2D,0x31,0x20,0x74,
+ 0x69,0x63,0x6B,0x20,0x23,0x33,0x2E,0x0B,0x3E,0x34,0x30,0x20,
+ 0x47,0x6F,0x74,0x6F,0x20,0x31,0x30,0x00,0x1C,0x40,0x58,0x30,
+ 0x34,0x30,0x40,0x43,0x30,0x30,0x31,0x50,0x6F,0x72,0x74,0x61,
+ 0x6D,0x65,0x6E,0x74,0x6F,0x20,0x75,0x70,0x2F,0x64,0x6F,0x77,
+ 0x6E,0x0B,0x3E,0x40,0x58,0x30,0x36,0x30,0x40,0x43,0x30,0x30,
+ 0x32,0x18,0x53,0x79,0x6E,0x74,0x61,0x78,0x3A,0x20,0x28,0x31,
+ 0x20,0x6F,0x72,0x20,0x32,0x29,0x20,0x2B,0x20,0x53,0x70,0x65,
+ 0x65,0x64,0x00,0x40,0x50,0x6F,0x72,0x74,0x61,0x6D,0x65,0x6E,
+ 0x74,0x6F,0x20,0x69,0x73,0x20,0x75,0x73,0x65,0x64,0x20,0x74,
+ 0x6F,0x20,0x73,0x6C,0x69,0x64,0x65,0x20,0x74,0x68,0x65,0x20,
+ 0x73,0x61,0x6D,0x70,0x6C,0x65,0x20,0x70,0x69,0x74,0x63,0x68,
+ 0x20,0x75,0x70,0x20,0x6F,0x72,0x20,0x64,0x6F,0x77,0x6E,0x2E,
+ 0x20,0x54,0x68,0x69,0x73,0x20,0x69,0x73,0x42,0x64,0x6F,0x6E,
+ 0x65,0x20,0x75,0x73,0x69,0x6E,0x67,0x20,0x74,0x68,0x65,0x20,
+ 0x70,0x65,0x72,0x69,0x6F,0x64,0x20,0x76,0x61,0x6C,0x75,0x65,
+ 0x2E,0x20,0x49,0x66,0x20,0x41,0x6D,0x69,0x67,0x61,0x20,0x66,
+ 0x72,0x65,0x71,0x75,0x65,0x6E,0x63,0x79,0x20,0x74,0x61,0x62,
+ 0x6C,0x65,0x20,0x69,0x73,0x20,0x75,0x73,0x65,0x64,0x2C,0x20,
+ 0x74,0x68,0x65,0x40,0x73,0x6C,0x69,0x64,0x69,0x6E,0x67,0x20,
+ 0x77,0x69,0x6C,0x6C,0x20,0x62,0x65,0x20,0x6E,0x6F,0x6E,0x2D,
+ 0x6C,0x69,0x6E,0x65,0x61,0x72,0x20,0x28,0x74,0x68,0x65,0x20,
+ 0x73,0x70,0x65,0x65,0x64,0x20,0x64,0x65,0x70,0x65,0x6E,0x64,
+ 0x73,0x20,0x6F,0x6E,0x20,0x74,0x68,0x65,0x20,0x66,0x72,0x65,
+ 0x71,0x75,0x65,0x6E,0x63,0x79,0x29,0x2E,0x00,0x19,0x40,0x58,
+ 0x30,0x34,0x30,0x40,0x43,0x30,0x30,0x31,0x54,0x6F,0x6E,0x65,
+ 0x20,0x70,0x6F,0x72,0x74,0x61,0x6D,0x65,0x6E,0x74,0x6F,0x0B,
+ 0x3E,0x40,0x58,0x30,0x36,0x30,0x40,0x43,0x30,0x30,0x32,0x11,
+ 0x53,0x79,0x6E,0x74,0x61,0x78,0x3A,0x20,0x33,0x20,0x2B,0x20,
+ 0x53,0x70,0x65,0x65,0x64,0x00,0x40,0x54,0x68,0x69,0x73,0x20,
+ 0x63,0x6F,0x6D,0x6D,0x61,0x6E,0x64,0x20,0x69,0x73,0x20,0x75,
+ 0x73,0x65,0x64,0x20,0x74,0x6F,0x67,0x65,0x74,0x68,0x65,0x72,
+ 0x20,0x77,0x69,0x74,0x68,0x20,0x61,0x20,0x6E,0x6F,0x74,0x65,
+ 0x2C,0x20,0x61,0x6E,0x64,0x20,0x77,0x69,0x6C,0x6C,0x20,0x73,
+ 0x6C,0x69,0x64,0x65,0x20,0x74,0x6F,0x20,0x69,0x74,0x73,0x43,
+ 0x66,0x72,0x65,0x71,0x75,0x65,0x6E,0x63,0x79,0x2E,0x20,0x49,
+ 0x66,0x20,0x67,0x6C,0x69,0x73,0x73,0x61,0x6E,0x64,0x6F,0x20,
+ 0x28,0x45,0x33,0x29,0x20,0x69,0x73,0x20,0x75,0x73,0x65,0x64,
+ 0x2C,0x20,0x74,0x68,0x65,0x20,0x66,0x72,0x65,0x71,0x75,0x65,
+ 0x6E,0x63,0x79,0x20,0x77,0x69,0x6C,0x6C,0x20,0x62,0x65,0x20,
+ 0x72,0x6F,0x75,0x6E,0x64,0x65,0x64,0x18,0x74,0x6F,0x20,0x74,
+ 0x68,0x65,0x20,0x6E,0x65,0x61,0x72,0x65,0x73,0x74,0x20,0x68,
+ 0x61,0x6C,0x66,0x74,0x6F,0x6E,0x65,0x2E,0x00,0x11,0x40,0x58,
+ 0x30,0x34,0x30,0x40,0x43,0x30,0x30,0x31,0x56,0x69,0x62,0x72,
+ 0x61,0x74,0x6F,0x0B,0x3E,0x40,0x58,0x30,0x36,0x30,0x40,0x43,
+ 0x30,0x30,0x32,0x18,0x53,0x79,0x6E,0x74,0x61,0x78,0x3A,0x20,
+ 0x34,0x20,0x2B,0x20,0x52,0x61,0x74,0x65,0x20,0x2B,0x20,0x44,
+ 0x65,0x70,0x74,0x68,0x00,0x3E,0x41,0x64,0x64,0x73,0x20,0x76,
+ 0x69,0x62,0x72,0x61,0x74,0x6F,0x20,0x74,0x6F,0x20,0x74,0x68,
+ 0x65,0x20,0x63,0x68,0x61,0x6E,0x6E,0x65,0x6C,0x20,0x77,0x69,
+ 0x74,0x68,0x20,0x61,0x20,0x72,0x61,0x74,0x65,0x20,0x61,0x6E,
+ 0x64,0x20,0x73,0x70,0x65,0x65,0x64,0x2E,0x20,0x53,0x65,0x74,
+ 0x20,0x76,0x69,0x62,0x72,0x61,0x74,0x6F,0x3C,0x63,0x6F,0x6E,
+ 0x74,0x72,0x6F,0x6C,0x20,0x28,0x45,0x34,0x29,0x20,0x63,0x61,
+ 0x6E,0x20,0x62,0x65,0x20,0x75,0x73,0x65,0x64,0x20,0x74,0x6F,
+ 0x20,0x63,0x68,0x61,0x6E,0x67,0x65,0x20,0x74,0x68,0x65,0x20,
+ 0x76,0x69,0x62,0x72,0x61,0x74,0x6F,0x20,0x77,0x61,0x76,0x65,
+ 0x66,0x6F,0x72,0x6D,0x20,0x28,0x73,0x65,0x65,0x07,0x62,0x65,
+ 0x6C,0x6F,0x77,0x29,0x2E,0x00,0x28,0x40,0x58,0x30,0x34,0x30,
+ 0x40,0x43,0x30,0x30,0x31,0x54,0x6F,0x6E,0x65,0x20,0x70,0x6F,
+ 0x72,0x74,0x61,0x6D,0x65,0x6E,0x74,0x6F,0x20,0x2B,0x20,0x76,
+ 0x6F,0x6C,0x75,0x6D,0x65,0x20,0x73,0x6C,0x69,0x64,0x65,0x0B,
+ 0x3E,0x40,0x58,0x30,0x36,0x30,0x40,0x43,0x30,0x30,0x32,0x11,
+ 0x53,0x79,0x6E,0x74,0x61,0x78,0x3A,0x20,0x35,0x20,0x2B,0x20,
+ 0x53,0x70,0x65,0x65,0x64,0x00,0x40,0x54,0x68,0x69,0x73,0x20,
+ 0x63,0x6F,0x6D,0x6D,0x61,0x6E,0x64,0x20,0x77,0x69,0x6C,0x6C,
+ 0x20,0x65,0x78,0x65,0x63,0x75,0x74,0x65,0x20,0x62,0x6F,0x74,
+ 0x68,0x20,0x74,0x6F,0x6E,0x65,0x20,0x70,0x6F,0x72,0x74,0x61,
+ 0x6D,0x65,0x6E,0x74,0x6F,0x20,0x61,0x6E,0x64,0x20,0x76,0x6F,
+ 0x6C,0x75,0x6D,0x65,0x20,0x73,0x6C,0x69,0x64,0x65,0x2E,0x27,
+ 0x54,0x68,0x65,0x20,0x73,0x70,0x65,0x65,0x64,0x20,0x69,0x73,
+ 0x20,0x75,0x73,0x65,0x64,0x20,0x66,0x6F,0x72,0x20,0x74,0x68,
+ 0x65,0x20,0x76,0x6F,0x6C,0x75,0x6D,0x65,0x20,0x73,0x6C,0x69,
+ 0x64,0x65,0x2E,0x00,0x20,0x40,0x58,0x30,0x34,0x30,0x40,0x43,
+ 0x30,0x30,0x31,0x56,0x69,0x62,0x72,0x61,0x74,0x6F,0x20,0x2B,
0x20,0x76,0x6F,0x6C,0x75,0x6D,0x65,0x20,0x73,0x6C,0x69,0x64,
- 0x65,0x20,0x64,0x6F,0x77,0x6E,0x2E,0x20,0x28,0x49,0x6E,0x64,
- 0x69,0x63,0x61,0x74,0x65,0x64,0x20,0x62,0x79,0x20,0x73,0x79,
- 0x6D,0x62,0x6F,0x6C,0x29,0x33,0x3E,0x55,0x20,0x40,0x54,0x31,
- 0x36,0x30,0x46,0x69,0x6E,0x65,0x20,0x76,0x6F,0x6C,0x75,0x6D,
- 0x65,0x20,0x73,0x6C,0x69,0x64,0x65,0x20,0x75,0x70,0x2E,0x20,
- 0x28,0x49,0x6E,0x64,0x69,0x63,0x61,0x74,0x65,0x64,0x20,0x62,
- 0x79,0x20,0x73,0x79,0x6D,0x62,0x6F,0x6C,0x29,0x1A,0x3E,0x53,
- 0x20,0x40,0x54,0x31,0x36,0x30,0x53,0x65,0x74,0x20,0x76,0x69,
- 0x62,0x72,0x61,0x74,0x6F,0x20,0x73,0x70,0x65,0x65,0x64,0x2E,
- 0x10,0x3E,0x56,0x20,0x40,0x54,0x31,0x36,0x30,0x56,0x69,0x62,
- 0x72,0x61,0x74,0x6F,0x2E,0x1D,0x3E,0x50,0x20,0x40,0x54,0x31,
- 0x36,0x30,0x53,0x65,0x74,0x20,0x70,0x61,0x6E,0x6E,0x69,0x6E,
- 0x67,0x20,0x70,0x6F,0x73,0x69,0x74,0x69,0x6F,0x6E,0x2E,0x32,
- 0x3E,0x52,0x20,0x40,0x54,0x31,0x36,0x30,0x50,0x61,0x6E,0x6E,
- 0x69,0x6E,0x67,0x20,0x73,0x6C,0x69,0x64,0x65,0x20,0x72,0x69,
- 0x67,0x68,0x74,0x2E,0x20,0x28,0x49,0x6E,0x64,0x69,0x63,0x61,
- 0x74,0x65,0x64,0x20,0x62,0x79,0x20,0x73,0x79,0x6D,0x62,0x6F,
- 0x6C,0x29,0x31,0x3E,0x4C,0x20,0x40,0x54,0x31,0x36,0x30,0x50,
- 0x61,0x6E,0x6E,0x69,0x6E,0x67,0x20,0x73,0x6C,0x69,0x64,0x65,
- 0x20,0x6C,0x65,0x66,0x74,0x2E,0x20,0x28,0x49,0x6E,0x64,0x69,
- 0x63,0x61,0x74,0x65,0x64,0x20,0x62,0x79,0x20,0x73,0x79,0x6D,
- 0x62,0x6F,0x6C,0x29,0x18,0x3E,0x4D,0x20,0x40,0x54,0x31,0x36,
- 0x30,0x54,0x6F,0x6E,0x65,0x20,0x70,0x6F,0x72,0x74,0x61,0x6D,
- 0x65,0x6E,0x74,0x6F,0x2E,0x00,0x00,0x1B,0x40,0x4C,0x40,0x58,
- 0x30,0x30,0x30,0x44,0x65,0x74,0x61,0x69,0x6C,0x65,0x64,0x20,
- 0x69,0x6E,0x66,0x6F,0x72,0x6D,0x61,0x74,0x69,0x6F,0x6E,0x00,
- 0x12,0x40,0x58,0x30,0x34,0x30,0x40,0x43,0x30,0x30,0x31,0x41,
- 0x72,0x70,0x65,0x67,0x67,0x69,0x6F,0x0B,0x3E,0x40,0x58,0x30,
- 0x36,0x30,0x40,0x43,0x30,0x30,0x32,0x27,0x53,0x79,0x6E,0x74,
- 0x61,0x78,0x3A,0x20,0x30,0x20,0x2B,0x20,0x31,0x73,0x74,0x20,
- 0x68,0x61,0x6C,0x66,0x74,0x6F,0x6E,0x65,0x20,0x2B,0x20,0x32,
- 0x6E,0x64,0x20,0x68,0x61,0x6C,0x66,0x74,0x6F,0x6E,0x65,0x00,
- 0x0D,0x45,0x78,0x2E,0x3A,0x20,0x43,0x2D,0x31,0x20,0x20,0x30,
- 0x33,0x37,0x00,0x16,0x3E,0x31,0x30,0x20,0x50,0x6C,0x61,0x79,
- 0x73,0x20,0x43,0x2D,0x31,0x20,0x74,0x69,0x63,0x6B,0x20,0x23,
- 0x31,0x2E,0x26,0x3E,0x32,0x30,0x20,0x50,0x6C,0x61,0x79,0x73,
- 0x20,0x43,0x2D,0x31,0x20,0x2B,0x20,0x33,0x20,0x4E,0x6F,0x74,
- 0x65,0x73,0x20,0x3D,0x20,0x44,0x23,0x31,0x20,0x74,0x69,0x63,
- 0x6B,0x20,0x23,0x32,0x2E,0x26,0x3E,0x33,0x30,0x20,0x50,0x6C,
- 0x61,0x79,0x73,0x20,0x43,0x2D,0x31,0x20,0x2B,0x20,0x37,0x20,
- 0x4E,0x6F,0x74,0x65,0x73,0x20,0x3D,0x20,0x47,0x2D,0x31,0x20,
- 0x74,0x69,0x63,0x6B,0x20,0x23,0x33,0x2E,0x0B,0x3E,0x34,0x30,
- 0x20,0x47,0x6F,0x74,0x6F,0x20,0x31,0x30,0x00,0x1C,0x40,0x58,
- 0x30,0x34,0x30,0x40,0x43,0x30,0x30,0x31,0x50,0x6F,0x72,0x74,
- 0x61,0x6D,0x65,0x6E,0x74,0x6F,0x20,0x75,0x70,0x2F,0x64,0x6F,
- 0x77,0x6E,0x0B,0x3E,0x40,0x58,0x30,0x36,0x30,0x40,0x43,0x30,
- 0x30,0x32,0x18,0x53,0x79,0x6E,0x74,0x61,0x78,0x3A,0x20,0x28,
- 0x31,0x20,0x6F,0x72,0x20,0x32,0x29,0x20,0x2B,0x20,0x53,0x70,
- 0x65,0x65,0x64,0x00,0x40,0x50,0x6F,0x72,0x74,0x61,0x6D,0x65,
- 0x6E,0x74,0x6F,0x20,0x69,0x73,0x20,0x75,0x73,0x65,0x64,0x20,
- 0x74,0x6F,0x20,0x73,0x6C,0x69,0x64,0x65,0x20,0x74,0x68,0x65,
- 0x20,0x73,0x61,0x6D,0x70,0x6C,0x65,0x20,0x70,0x69,0x74,0x63,
- 0x68,0x20,0x75,0x70,0x20,0x6F,0x72,0x20,0x64,0x6F,0x77,0x6E,
- 0x2E,0x20,0x54,0x68,0x69,0x73,0x20,0x69,0x73,0x42,0x64,0x6F,
- 0x6E,0x65,0x20,0x75,0x73,0x69,0x6E,0x67,0x20,0x74,0x68,0x65,
- 0x20,0x70,0x65,0x72,0x69,0x6F,0x64,0x20,0x76,0x61,0x6C,0x75,
- 0x65,0x2E,0x20,0x49,0x66,0x20,0x41,0x6D,0x69,0x67,0x61,0x20,
- 0x66,0x72,0x65,0x71,0x75,0x65,0x6E,0x63,0x79,0x20,0x74,0x61,
- 0x62,0x6C,0x65,0x20,0x69,0x73,0x20,0x75,0x73,0x65,0x64,0x2C,
- 0x20,0x74,0x68,0x65,0x40,0x73,0x6C,0x69,0x64,0x69,0x6E,0x67,
- 0x20,0x77,0x69,0x6C,0x6C,0x20,0x62,0x65,0x20,0x6E,0x6F,0x6E,
- 0x2D,0x6C,0x69,0x6E,0x65,0x61,0x72,0x20,0x28,0x74,0x68,0x65,
- 0x20,0x73,0x70,0x65,0x65,0x64,0x20,0x64,0x65,0x70,0x65,0x6E,
- 0x64,0x73,0x20,0x6F,0x6E,0x20,0x74,0x68,0x65,0x20,0x66,0x72,
- 0x65,0x71,0x75,0x65,0x6E,0x63,0x79,0x29,0x2E,0x00,0x19,0x40,
- 0x58,0x30,0x34,0x30,0x40,0x43,0x30,0x30,0x31,0x54,0x6F,0x6E,
- 0x65,0x20,0x70,0x6F,0x72,0x74,0x61,0x6D,0x65,0x6E,0x74,0x6F,
- 0x0B,0x3E,0x40,0x58,0x30,0x36,0x30,0x40,0x43,0x30,0x30,0x32,
- 0x11,0x53,0x79,0x6E,0x74,0x61,0x78,0x3A,0x20,0x33,0x20,0x2B,
- 0x20,0x53,0x70,0x65,0x65,0x64,0x00,0x40,0x54,0x68,0x69,0x73,
- 0x20,0x63,0x6F,0x6D,0x6D,0x61,0x6E,0x64,0x20,0x69,0x73,0x20,
- 0x75,0x73,0x65,0x64,0x20,0x74,0x6F,0x67,0x65,0x74,0x68,0x65,
- 0x72,0x20,0x77,0x69,0x74,0x68,0x20,0x61,0x20,0x6E,0x6F,0x74,
- 0x65,0x2C,0x20,0x61,0x6E,0x64,0x20,0x77,0x69,0x6C,0x6C,0x20,
- 0x73,0x6C,0x69,0x64,0x65,0x20,0x74,0x6F,0x20,0x69,0x74,0x73,
- 0x43,0x66,0x72,0x65,0x71,0x75,0x65,0x6E,0x63,0x79,0x2E,0x20,
- 0x49,0x66,0x20,0x67,0x6C,0x69,0x73,0x73,0x61,0x6E,0x64,0x6F,
- 0x20,0x28,0x45,0x33,0x29,0x20,0x69,0x73,0x20,0x75,0x73,0x65,
- 0x64,0x2C,0x20,0x74,0x68,0x65,0x20,0x66,0x72,0x65,0x71,0x75,
- 0x65,0x6E,0x63,0x79,0x20,0x77,0x69,0x6C,0x6C,0x20,0x62,0x65,
- 0x20,0x72,0x6F,0x75,0x6E,0x64,0x65,0x64,0x18,0x74,0x6F,0x20,
- 0x74,0x68,0x65,0x20,0x6E,0x65,0x61,0x72,0x65,0x73,0x74,0x20,
- 0x68,0x61,0x6C,0x66,0x74,0x6F,0x6E,0x65,0x2E,0x00,0x11,0x40,
- 0x58,0x30,0x34,0x30,0x40,0x43,0x30,0x30,0x31,0x56,0x69,0x62,
- 0x72,0x61,0x74,0x6F,0x0B,0x3E,0x40,0x58,0x30,0x36,0x30,0x40,
- 0x43,0x30,0x30,0x32,0x18,0x53,0x79,0x6E,0x74,0x61,0x78,0x3A,
- 0x20,0x34,0x20,0x2B,0x20,0x52,0x61,0x74,0x65,0x20,0x2B,0x20,
- 0x44,0x65,0x70,0x74,0x68,0x00,0x3E,0x41,0x64,0x64,0x73,0x20,
- 0x76,0x69,0x62,0x72,0x61,0x74,0x6F,0x20,0x74,0x6F,0x20,0x74,
- 0x68,0x65,0x20,0x63,0x68,0x61,0x6E,0x6E,0x65,0x6C,0x20,0x77,
- 0x69,0x74,0x68,0x20,0x61,0x20,0x72,0x61,0x74,0x65,0x20,0x61,
- 0x6E,0x64,0x20,0x73,0x70,0x65,0x65,0x64,0x2E,0x20,0x53,0x65,
- 0x74,0x20,0x76,0x69,0x62,0x72,0x61,0x74,0x6F,0x3D,0x63,0x6F,
- 0x6E,0x74,0x72,0x6F,0x6C,0x20,0x28,0x45,0x34,0x29,0x20,0x63,
- 0x61,0x6E,0x20,0x62,0x65,0x20,0x75,0x73,0x65,0x64,0x20,0x74,
- 0x6F,0x20,0x63,0x68,0x61,0x6E,0x67,0x65,0x20,0x74,0x68,0x65,
- 0x20,0x76,0x69,0x62,0x72,0x61,0x74,0x6F,0x20,0x77,0x61,0x76,
- 0x65,0x20,0x66,0x6F,0x72,0x6D,0x20,0x28,0x73,0x65,0x65,0x07,
- 0x62,0x65,0x6C,0x6F,0x77,0x29,0x2E,0x00,0x28,0x40,0x58,0x30,
- 0x34,0x30,0x40,0x43,0x30,0x30,0x31,0x54,0x6F,0x6E,0x65,0x20,
- 0x70,0x6F,0x72,0x74,0x61,0x6D,0x65,0x6E,0x74,0x6F,0x20,0x2B,
- 0x20,0x76,0x6F,0x6C,0x75,0x6D,0x65,0x20,0x73,0x6C,0x69,0x64,
0x65,0x0B,0x3E,0x40,0x58,0x30,0x36,0x30,0x40,0x43,0x30,0x30,
- 0x32,0x11,0x53,0x79,0x6E,0x74,0x61,0x78,0x3A,0x20,0x35,0x20,
- 0x2B,0x20,0x53,0x70,0x65,0x65,0x64,0x00,0x40,0x54,0x68,0x69,
+ 0x32,0x11,0x53,0x79,0x6E,0x74,0x61,0x78,0x3A,0x20,0x36,0x20,
+ 0x2B,0x20,0x53,0x70,0x65,0x65,0x64,0x00,0x3C,0x54,0x68,0x69,
0x73,0x20,0x63,0x6F,0x6D,0x6D,0x61,0x6E,0x64,0x20,0x77,0x69,
0x6C,0x6C,0x20,0x65,0x78,0x65,0x63,0x75,0x74,0x65,0x20,0x62,
- 0x6F,0x74,0x68,0x20,0x74,0x6F,0x6E,0x65,0x20,0x70,0x6F,0x72,
- 0x74,0x61,0x6D,0x65,0x6E,0x74,0x6F,0x20,0x61,0x6E,0x64,0x20,
- 0x76,0x6F,0x6C,0x75,0x6D,0x65,0x20,0x73,0x6C,0x69,0x64,0x65,
- 0x2E,0x27,0x54,0x68,0x65,0x20,0x73,0x70,0x65,0x65,0x64,0x20,
- 0x69,0x73,0x20,0x75,0x73,0x65,0x64,0x20,0x66,0x6F,0x72,0x20,
- 0x74,0x68,0x65,0x20,0x76,0x6F,0x6C,0x75,0x6D,0x65,0x20,0x73,
- 0x6C,0x69,0x64,0x65,0x2E,0x00,0x20,0x40,0x58,0x30,0x34,0x30,
- 0x40,0x43,0x30,0x30,0x31,0x56,0x69,0x62,0x72,0x61,0x74,0x6F,
- 0x20,0x2B,0x20,0x76,0x6F,0x6C,0x75,0x6D,0x65,0x20,0x73,0x6C,
- 0x69,0x64,0x65,0x0B,0x3E,0x40,0x58,0x30,0x36,0x30,0x40,0x43,
- 0x30,0x30,0x32,0x11,0x53,0x79,0x6E,0x74,0x61,0x78,0x3A,0x20,
- 0x36,0x20,0x2B,0x20,0x53,0x70,0x65,0x65,0x64,0x00,0x3C,0x54,
- 0x68,0x69,0x73,0x20,0x63,0x6F,0x6D,0x6D,0x61,0x6E,0x64,0x20,
- 0x77,0x69,0x6C,0x6C,0x20,0x65,0x78,0x65,0x63,0x75,0x74,0x65,
- 0x20,0x62,0x6F,0x74,0x68,0x20,0x76,0x69,0x62,0x72,0x61,0x74,
- 0x6F,0x20,0x61,0x6E,0x64,0x20,0x76,0x6F,0x6C,0x75,0x6D,0x65,
- 0x20,0x73,0x6C,0x69,0x64,0x65,0x2E,0x20,0x54,0x68,0x65,0x23,
- 0x73,0x70,0x65,0x65,0x64,0x20,0x69,0x73,0x20,0x75,0x73,0x65,
- 0x64,0x20,0x66,0x6F,0x72,0x20,0x74,0x68,0x65,0x20,0x76,0x6F,
- 0x6C,0x75,0x6D,0x65,0x20,0x73,0x6C,0x69,0x64,0x65,0x2E,0x00,
- 0x11,0x40,0x58,0x30,0x34,0x30,0x40,0x43,0x30,0x30,0x31,0x54,
- 0x72,0x65,0x6D,0x6F,0x6C,0x6F,0x0B,0x3E,0x40,0x58,0x30,0x36,
- 0x30,0x40,0x43,0x30,0x30,0x32,0x18,0x53,0x79,0x6E,0x74,0x61,
- 0x78,0x3A,0x20,0x37,0x20,0x2B,0x20,0x52,0x61,0x74,0x65,0x20,
- 0x2B,0x20,0x44,0x65,0x70,0x74,0x68,0x00,0x41,0x54,0x72,0x65,
- 0x6D,0x6F,0x6C,0x6F,0x20,0x61,0x64,0x64,0x73,0x20,0x76,0x69,
- 0x62,0x72,0x61,0x74,0x6F,0x20,0x74,0x6F,0x20,0x74,0x68,0x65,
- 0x20,0x63,0x75,0x72,0x72,0x65,0x6E,0x74,0x20,0x76,0x6F,0x6C,
- 0x75,0x6D,0x65,0x2E,0x20,0x54,0x68,0x65,0x20,0x73,0x79,0x6E,
- 0x74,0x61,0x78,0x20,0x69,0x73,0x20,0x65,0x78,0x61,0x63,0x74,
- 0x6C,0x79,0x1B,0x61,0x73,0x20,0x66,0x6F,0x72,0x20,0x74,0x68,
- 0x65,0x20,0x76,0x69,0x62,0x72,0x61,0x74,0x6F,0x20,0x63,0x6F,
- 0x6D,0x6D,0x61,0x6E,0x64,0x2E,0x00,0x1E,0x40,0x58,0x30,0x34,
- 0x30,0x40,0x43,0x30,0x30,0x31,0x53,0x65,0x74,0x20,0x70,0x61,
- 0x6E,0x6E,0x69,0x6E,0x67,0x20,0x70,0x6F,0x73,0x69,0x74,0x69,
- 0x6F,0x6E,0x0B,0x3E,0x40,0x58,0x30,0x36,0x30,0x40,0x43,0x30,
- 0x30,0x32,0x14,0x53,0x79,0x6E,0x74,0x61,0x78,0x3A,0x20,0x38,
- 0x20,0x2B,0x20,0x50,0x6F,0x73,0x69,0x74,0x69,0x6F,0x6E,0x00,
- 0x3E,0x53,0x65,0x74,0x73,0x20,0x74,0x68,0x65,0x20,0x70,0x61,
- 0x6E,0x6E,0x69,0x6E,0x67,0x20,0x70,0x6F,0x73,0x69,0x74,0x69,
- 0x6F,0x6E,0x20,0x66,0x6F,0x72,0x20,0x74,0x68,0x65,0x20,0x63,
- 0x68,0x61,0x6E,0x6E,0x65,0x6C,0x2E,0x20,0x24,0x30,0x30,0x20,
- 0x69,0x73,0x20,0x74,0x68,0x65,0x20,0x6C,0x65,0x66,0x74,0x6D,
- 0x6F,0x73,0x74,0x3F,0x70,0x6F,0x73,0x69,0x74,0x69,0x6F,0x6E,
- 0x20,0x61,0x6E,0x64,0x20,0x24,0x46,0x46,0x20,0x74,0x68,0x65,
- 0x20,0x72,0x69,0x67,0x68,0x74,0x6D,0x6F,0x73,0x74,0x2E,0x20,
- 0x4E,0x6F,0x74,0x65,0x20,0x74,0x68,0x61,0x74,0x20,0x73,0x6F,
- 0x6D,0x65,0x20,0x73,0x6F,0x75,0x6E,0x64,0x20,0x63,0x61,0x72,
- 0x64,0x73,0x20,0x28,0x65,0x78,0x2E,0x30,0x47,0x55,0x53,0x29,
- 0x20,0x63,0x61,0x6E,0x27,0x74,0x20,0x75,0x73,0x65,0x20,0x61,
- 0x73,0x20,0x6D,0x61,0x6E,0x79,0x20,0x61,0x73,0x20,0x32,0x35,
- 0x36,0x20,0x70,0x61,0x6E,0x6E,0x69,0x6E,0x67,0x20,0x70,0x6F,
- 0x73,0x69,0x74,0x69,0x6F,0x6E,0x73,0x2E,0x00,0x17,0x40,0x58,
- 0x30,0x34,0x30,0x40,0x43,0x30,0x30,0x31,0x53,0x61,0x6D,0x70,
- 0x6C,0x65,0x20,0x6F,0x66,0x66,0x73,0x65,0x74,0x0B,0x3E,0x40,
- 0x58,0x30,0x36,0x30,0x40,0x43,0x30,0x30,0x32,0x12,0x53,0x79,
- 0x6E,0x74,0x61,0x78,0x3A,0x20,0x39,0x20,0x2B,0x20,0x4F,0x66,
- 0x66,0x73,0x65,0x74,0x00,0x41,0x54,0x68,0x69,0x73,0x20,0x63,
- 0x6F,0x6D,0x6D,0x61,0x6E,0x64,0x20,0x73,0x68,0x6F,0x75,0x6C,
- 0x64,0x20,0x62,0x65,0x20,0x75,0x73,0x65,0x64,0x20,0x74,0x6F,
- 0x67,0x65,0x74,0x68,0x65,0x72,0x20,0x77,0x69,0x74,0x68,0x20,
- 0x61,0x20,0x6E,0x6F,0x74,0x65,0x2E,0x20,0x54,0x68,0x65,0x20,
- 0x73,0x61,0x6D,0x70,0x6C,0x65,0x20,0x77,0x69,0x6C,0x6C,0x2D,
- 0x62,0x65,0x20,0x70,0x6C,0x61,0x79,0x65,0x64,0x20,0x66,0x72,
- 0x6F,0x6D,0x20,0x28,0x4F,0x66,0x66,0x73,0x65,0x74,0x2A,0x24,
- 0x31,0x30,0x30,0x29,0x20,0x69,0x6E,0x73,0x74,0x65,0x61,0x64,
- 0x20,0x6F,0x66,0x20,0x7A,0x65,0x72,0x6F,0x2E,0x00,0x16,0x40,
- 0x58,0x30,0x34,0x30,0x40,0x43,0x30,0x30,0x31,0x56,0x6F,0x6C,
- 0x75,0x6D,0x65,0x20,0x73,0x6C,0x69,0x64,0x65,0x0B,0x3E,0x40,
- 0x58,0x30,0x36,0x30,0x40,0x43,0x30,0x30,0x32,0x21,0x53,0x79,
- 0x6E,0x74,0x61,0x78,0x3A,0x20,0x41,0x20,0x2B,0x20,0x55,0x70,
- 0x20,0x73,0x70,0x65,0x65,0x64,0x20,0x2B,0x20,0x44,0x6F,0x77,
- 0x6E,0x20,0x73,0x70,0x65,0x65,0x64,0x00,0x3D,0x53,0x6C,0x69,
- 0x64,0x65,0x73,0x20,0x74,0x68,0x65,0x20,0x63,0x75,0x72,0x72,
- 0x65,0x6E,0x74,0x20,0x76,0x6F,0x6C,0x75,0x6D,0x65,0x20,0x75,
- 0x70,0x20,0x6F,0x72,0x20,0x64,0x6F,0x77,0x6E,0x2E,0x20,0x45,
- 0x69,0x74,0x68,0x65,0x72,0x20,0x75,0x70,0x20,0x73,0x70,0x65,
- 0x65,0x64,0x20,0x6F,0x72,0x20,0x64,0x6F,0x77,0x6E,0x15,0x73,
- 0x70,0x65,0x65,0x64,0x20,0x73,0x68,0x6F,0x75,0x6C,0x64,0x20,
- 0x62,0x65,0x20,0x7A,0x65,0x72,0x6F,0x2E,0x00,0x17,0x40,0x58,
- 0x30,0x34,0x30,0x40,0x43,0x30,0x30,0x31,0x50,0x6F,0x73,0x69,
- 0x74,0x69,0x6F,0x6E,0x20,0x6A,0x75,0x6D,0x70,0x0B,0x3E,0x40,
- 0x58,0x30,0x36,0x30,0x40,0x43,0x30,0x30,0x32,0x14,0x53,0x79,
- 0x6E,0x74,0x61,0x78,0x3A,0x20,0x42,0x20,0x2B,0x20,0x50,0x6F,
- 0x73,0x69,0x74,0x69,0x6F,0x6E,0x00,0x41,0x54,0x68,0x69,0x73,
- 0x20,0x63,0x6F,0x6D,0x6D,0x61,0x6E,0x64,0x20,0x77,0x69,0x6C,
- 0x6C,0x20,0x6A,0x75,0x6D,0x70,0x20,0x74,0x6F,0x20,0x74,0x68,
- 0x65,0x20,0x73,0x65,0x6C,0x65,0x63,0x74,0x65,0x64,0x20,0x73,
- 0x6F,0x6E,0x67,0x20,0x70,0x6F,0x73,0x69,0x74,0x69,0x6F,0x6E,
- 0x20,0x61,0x6E,0x64,0x20,0x70,0x6C,0x61,0x79,0x20,0x74,0x68,
- 0x65,0x1B,0x70,0x61,0x74,0x74,0x65,0x72,0x6E,0x20,0x66,0x72,
- 0x6F,0x6D,0x20,0x74,0x68,0x65,0x20,0x62,0x65,0x67,0x69,0x6E,
- 0x6E,0x69,0x6E,0x67,0x2E,0x00,0x14,0x40,0x58,0x30,0x34,0x30,
- 0x40,0x43,0x30,0x30,0x31,0x53,0x65,0x74,0x20,0x76,0x6F,0x6C,
- 0x75,0x6D,0x65,0x0B,0x3E,0x40,0x58,0x30,0x36,0x30,0x40,0x43,
- 0x30,0x30,0x32,0x12,0x53,0x79,0x6E,0x74,0x61,0x78,0x3A,0x20,
- 0x43,0x20,0x2B,0x20,0x56,0x6F,0x6C,0x75,0x6D,0x65,0x00,0x3E,
- 0x53,0x65,0x74,0x73,0x20,0x74,0x68,0x65,0x20,0x63,0x75,0x72,
- 0x72,0x65,0x6E,0x74,0x20,0x76,0x6F,0x6C,0x75,0x6D,0x65,0x2E,
- 0x20,0x54,0x68,0x65,0x20,0x76,0x6F,0x6C,0x75,0x6D,0x65,0x20,
- 0x73,0x68,0x6F,0x75,0x6C,0x64,0x20,0x6E,0x6F,0x74,0x20,0x62,
- 0x65,0x20,0x67,0x72,0x65,0x61,0x74,0x65,0x72,0x20,0x74,0x68,
- 0x61,0x6E,0x04,0x24,0x34,0x30,0x2E,0x00,0x17,0x40,0x58,0x30,
- 0x34,0x30,0x40,0x43,0x30,0x30,0x31,0x50,0x61,0x74,0x74,0x65,
- 0x72,0x6E,0x20,0x62,0x72,0x65,0x61,0x6B,0x0B,0x3E,0x40,0x58,
- 0x30,0x36,0x30,0x40,0x43,0x30,0x30,0x32,0x1C,0x53,0x79,0x6E,
- 0x74,0x61,0x78,0x3A,0x20,0x44,0x20,0x2B,0x20,0x50,0x61,0x74,
- 0x74,0x65,0x72,0x6E,0x2D,0x70,0x6F,0x73,0x69,0x74,0x69,0x6F,
- 0x6E,0x00,0x3C,0x54,0x68,0x69,0x73,0x20,0x63,0x6F,0x6D,0x6D,
- 0x61,0x6E,0x64,0x20,0x77,0x69,0x6C,0x6C,0x20,0x6A,0x75,0x6D,
- 0x70,0x20,0x74,0x6F,0x20,0x74,0x68,0x65,0x20,0x6E,0x65,0x78,
- 0x74,0x20,0x70,0x61,0x74,0x74,0x65,0x72,0x6E,0x20,0x61,0x6E,
- 0x64,0x20,0x70,0x6C,0x61,0x79,0x20,0x66,0x72,0x6F,0x6D,0x20,
- 0x74,0x68,0x65,0x13,0x73,0x70,0x65,0x63,0x69,0x66,0x69,0x65,
- 0x64,0x20,0x70,0x6F,0x73,0x69,0x74,0x69,0x6F,0x6E,0x2E,0x00,
- 0x22,0x40,0x58,0x30,0x34,0x30,0x40,0x43,0x30,0x30,0x31,0x53,
- 0x65,0x74,0x20,0x66,0x69,0x6C,0x74,0x65,0x72,0x20,0x28,0x41,
- 0x6D,0x69,0x67,0x61,0x20,0x6F,0x6E,0x6C,0x79,0x21,0x29,0x0B,
- 0x3E,0x40,0x58,0x30,0x36,0x30,0x40,0x43,0x30,0x30,0x32,0x13,
- 0x53,0x79,0x6E,0x74,0x61,0x78,0x3A,0x20,0x45,0x30,0x20,0x2B,
- 0x20,0x53,0x74,0x61,0x74,0x75,0x73,0x00,0x38,0x55,0x73,0x65,
- 0x20,0x45,0x30,0x30,0x20,0x61,0x6E,0x64,0x20,0x79,0x6F,0x75,
- 0x72,0x20,0x74,0x75,0x6E,0x65,0x20,0x77,0x69,0x6C,0x6C,0x20,
- 0x73,0x6F,0x75,0x6E,0x64,0x20,0x72,0x65,0x61,0x6C,0x6C,0x79,
- 0x20,0x62,0x61,0x64,0x20,0x6F,0x6E,0x20,0x61,0x6E,0x20,0x41,
- 0x6D,0x69,0x67,0x61,0x21,0x00,0x21,0x40,0x58,0x30,0x34,0x30,
- 0x40,0x43,0x30,0x30,0x31,0x46,0x69,0x6E,0x65,0x20,0x70,0x6F,
- 0x72,0x74,0x61,0x6D,0x65,0x6E,0x74,0x6F,0x20,0x75,0x70,0x2F,
- 0x64,0x6F,0x77,0x6E,0x0B,0x3E,0x40,0x58,0x30,0x36,0x30,0x40,
- 0x43,0x30,0x30,0x32,0x19,0x53,0x79,0x6E,0x74,0x61,0x78,0x3A,
- 0x20,0x45,0x28,0x31,0x20,0x6F,0x72,0x20,0x32,0x29,0x20,0x2B,
- 0x20,0x53,0x70,0x65,0x65,0x64,0x00,0x3F,0x54,0x68,0x69,0x73,
- 0x20,0x63,0x6F,0x6D,0x6D,0x61,0x6E,0x64,0x20,0x77,0x6F,0x72,
- 0x6B,0x73,0x20,0x61,0x73,0x20,0x70,0x6F,0x72,0x74,0x61,0x6D,
- 0x65,0x6E,0x74,0x6F,0x20,0x75,0x70,0x2F,0x64,0x6F,0x77,0x6E,
- 0x2C,0x20,0x62,0x75,0x74,0x20,0x69,0x74,0x20,0x6F,0x6E,0x6C,
- 0x79,0x20,0x73,0x6C,0x69,0x64,0x65,0x73,0x20,0x75,0x70,0x05,
- 0x6F,0x6E,0x63,0x65,0x2E,0x00,0x1F,0x40,0x58,0x30,0x34,0x30,
- 0x40,0x43,0x30,0x30,0x31,0x53,0x65,0x74,0x20,0x67,0x6C,0x69,
- 0x73,0x73,0x61,0x6E,0x64,0x6F,0x20,0x63,0x6F,0x6E,0x74,0x72,
- 0x6F,0x6C,0x0B,0x3E,0x40,0x58,0x30,0x36,0x30,0x40,0x43,0x30,
- 0x30,0x32,0x13,0x53,0x79,0x6E,0x74,0x61,0x78,0x3A,0x20,0x45,
- 0x33,0x20,0x2B,0x20,0x53,0x74,0x61,0x74,0x75,0x73,0x00,0x41,
- 0x49,0x66,0x20,0x53,0x74,0x61,0x74,0x75,0x73,0x20,0x69,0x73,
- 0x20,0x3D,0x31,0x2C,0x20,0x74,0x68,0x65,0x20,0x66,0x72,0x65,
- 0x71,0x75,0x65,0x6E,0x63,0x79,0x20,0x77,0x68,0x65,0x6E,0x20,
- 0x75,0x73,0x69,0x6E,0x67,0x20,0x74,0x6F,0x6E,0x65,0x20,0x70,
- 0x6F,0x72,0x74,0x61,0x6D,0x65,0x6E,0x74,0x6F,0x20,0x77,0x69,
- 0x6C,0x6C,0x20,0x62,0x65,0x20,0x72,0x6F,0x75,0x6E,0x64,0x65,
- 0x64,0x20,0x74,0x6F,0x20,0x74,0x68,0x65,0x20,0x6E,0x65,0x61,
- 0x72,0x65,0x73,0x74,0x20,0x68,0x61,0x6C,0x66,0x74,0x6F,0x6E,
- 0x65,0x2E,0x00,0x1D,0x40,0x58,0x30,0x34,0x30,0x40,0x43,0x30,
- 0x30,0x31,0x53,0x65,0x74,0x20,0x76,0x69,0x62,0x72,0x61,0x74,
- 0x6F,0x20,0x63,0x6F,0x6E,0x74,0x72,0x6F,0x6C,0x0B,0x3E,0x40,
- 0x58,0x30,0x36,0x30,0x40,0x43,0x30,0x30,0x32,0x11,0x53,0x79,
- 0x6E,0x74,0x61,0x78,0x3A,0x20,0x45,0x34,0x20,0x2B,0x20,0x54,
- 0x79,0x70,0x65,0x00,0x2C,0x54,0x68,0x69,0x73,0x20,0x63,0x6F,
- 0x6D,0x6D,0x61,0x6E,0x64,0x20,0x63,0x6F,0x6E,0x74,0x72,0x6F,
- 0x6C,0x73,0x20,0x74,0x68,0x65,0x20,0x76,0x69,0x62,0x72,0x61,
- 0x74,0x6F,0x20,0x77,0x61,0x76,0x65,0x20,0x66,0x6F,0x72,0x6D,
- 0x2E,0x00,0x33,0x54,0x79,0x70,0x65,0x3A,0x20,0x30,0x20,0x3D,
- 0x20,0x53,0x69,0x6E,0x65,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
- 0x31,0x20,0x3D,0x20,0x52,0x61,0x6D,0x70,0x20,0x64,0x6F,0x77,
- 0x6E,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x32,0x20,0x3D,0x20,
- 0x53,0x71,0x75,0x61,0x72,0x65,0x00,0x44,0x49,0x66,0x20,0x79,
- 0x6F,0x75,0x20,0x61,0x64,0x64,0x20,0x34,0x20,0x74,0x6F,0x20,
- 0x74,0x68,0x65,0x20,0x74,0x79,0x70,0x65,0x2C,0x20,0x74,0x68,
- 0x65,0x20,0x77,0x61,0x76,0x65,0x20,0x66,0x6F,0x72,0x6D,0x20,
- 0x77,0x69,0x6C,0x6C,0x20,0x6E,0x6F,0x74,0x20,0x62,0x65,0x20,
- 0x72,0x65,0x74,0x72,0x69,0x67,0x67,0x65,0x64,0x20,0x77,0x68,
- 0x65,0x6E,0x20,0x61,0x19,0x6E,0x65,0x77,0x20,0x69,0x6E,0x73,
- 0x74,0x72,0x75,0x6D,0x65,0x6E,0x74,0x20,0x69,0x73,0x20,0x70,
- 0x6C,0x61,0x79,0x65,0x64,0x2E,0x00,0x17,0x40,0x58,0x30,0x34,
- 0x30,0x40,0x43,0x30,0x30,0x31,0x53,0x65,0x74,0x20,0x66,0x69,
- 0x6E,0x65,0x2D,0x74,0x75,0x6E,0x65,0x0B,0x3E,0x40,0x58,0x30,
- 0x36,0x30,0x40,0x43,0x30,0x30,0x32,0x11,0x53,0x79,0x6E,0x74,
- 0x61,0x78,0x3A,0x20,0x45,0x35,0x20,0x2B,0x20,0x54,0x75,0x6E,
- 0x65,0x00,0x3F,0x54,0x68,0x69,0x73,0x20,0x63,0x6F,0x6D,0x6D,
- 0x61,0x6E,0x64,0x20,0x73,0x68,0x6F,0x75,0x6C,0x64,0x20,0x62,
- 0x65,0x20,0x75,0x73,0x65,0x64,0x20,0x74,0x6F,0x67,0x65,0x74,
- 0x68,0x65,0x72,0x20,0x77,0x69,0x74,0x68,0x20,0x61,0x20,0x6E,
- 0x6F,0x74,0x65,0x2E,0x20,0x49,0x74,0x20,0x77,0x69,0x6C,0x6C,
- 0x20,0x63,0x61,0x75,0x73,0x65,0x44,0x61,0x6E,0x6F,0x74,0x68,
- 0x65,0x72,0x20,0x66,0x69,0x6E,0x65,0x2D,0x74,0x75,0x6E,0x65,
- 0x20,0x76,0x61,0x6C,0x75,0x65,0x20,0x74,0x6F,0x20,0x62,0x65,
- 0x20,0x75,0x73,0x65,0x64,0x2E,0x20,0x49,0x74,0x20,0x73,0x65,
- 0x65,0x6D,0x73,0x20,0x71,0x75,0x69,0x74,0x65,0x20,0x75,0x6E,
- 0x75,0x73,0x61,0x62,0x6C,0x65,0x20,0x74,0x6F,0x20,0x6D,0x65,
- 0x2E,0x2E,0x2E,0x00,0x16,0x40,0x58,0x30,0x34,0x30,0x40,0x43,
- 0x30,0x30,0x31,0x50,0x61,0x74,0x74,0x65,0x72,0x6E,0x20,0x6C,
- 0x6F,0x6F,0x70,0x0B,0x3E,0x40,0x58,0x30,0x36,0x30,0x40,0x43,
- 0x30,0x30,0x32,0x12,0x53,0x79,0x6E,0x74,0x61,0x78,0x3A,0x20,
- 0x45,0x36,0x20,0x2B,0x20,0x43,0x6F,0x75,0x6E,0x74,0x00,0x45,
- 0x49,0x66,0x20,0x63,0x6F,0x75,0x6E,0x74,0x20,0x69,0x73,0x20,
- 0x7A,0x65,0x72,0x6F,0x2C,0x20,0x74,0x68,0x65,0x20,0x62,0x65,
- 0x67,0x69,0x6E,0x6E,0x69,0x6E,0x67,0x20,0x6F,0x66,0x20,0x74,
- 0x68,0x65,0x20,0x6C,0x6F,0x6F,0x70,0x20,0x77,0x69,0x6C,0x6C,
- 0x20,0x62,0x65,0x20,0x73,0x70,0x65,0x63,0x69,0x66,0x69,0x65,
- 0x64,0x2E,0x20,0x57,0x68,0x65,0x6E,0x20,0x61,0x40,0x6E,0x6F,
- 0x6E,0x2D,0x7A,0x65,0x72,0x6F,0x20,0x76,0x61,0x6C,0x75,0x65,
- 0x20,0x69,0x73,0x20,0x75,0x73,0x65,0x64,0x2C,0x20,0x74,0x68,
- 0x65,0x20,0x70,0x61,0x74,0x74,0x65,0x72,0x6E,0x20,0x77,0x69,
- 0x6C,0x6C,0x20,0x62,0x65,0x20,0x6C,0x6F,0x6F,0x70,0x65,0x64,
- 0x20,0x66,0x72,0x6F,0x6D,0x20,0x74,0x68,0x65,0x20,0x6C,0x6F,
- 0x6F,0x70,0x06,0x73,0x74,0x61,0x72,0x74,0x2E,0x00,0x1D,0x40,
+ 0x6F,0x74,0x68,0x20,0x76,0x69,0x62,0x72,0x61,0x74,0x6F,0x20,
+ 0x61,0x6E,0x64,0x20,0x76,0x6F,0x6C,0x75,0x6D,0x65,0x20,0x73,
+ 0x6C,0x69,0x64,0x65,0x2E,0x20,0x54,0x68,0x65,0x23,0x73,0x70,
+ 0x65,0x65,0x64,0x20,0x69,0x73,0x20,0x75,0x73,0x65,0x64,0x20,
+ 0x66,0x6F,0x72,0x20,0x74,0x68,0x65,0x20,0x76,0x6F,0x6C,0x75,
+ 0x6D,0x65,0x20,0x73,0x6C,0x69,0x64,0x65,0x2E,0x00,0x11,0x40,
+ 0x58,0x30,0x34,0x30,0x40,0x43,0x30,0x30,0x31,0x54,0x72,0x65,
+ 0x6D,0x6F,0x6C,0x6F,0x0B,0x3E,0x40,0x58,0x30,0x36,0x30,0x40,
+ 0x43,0x30,0x30,0x32,0x18,0x53,0x79,0x6E,0x74,0x61,0x78,0x3A,
+ 0x20,0x37,0x20,0x2B,0x20,0x52,0x61,0x74,0x65,0x20,0x2B,0x20,
+ 0x44,0x65,0x70,0x74,0x68,0x00,0x41,0x54,0x72,0x65,0x6D,0x6F,
+ 0x6C,0x6F,0x20,0x61,0x64,0x64,0x73,0x20,0x76,0x69,0x62,0x72,
+ 0x61,0x74,0x6F,0x20,0x74,0x6F,0x20,0x74,0x68,0x65,0x20,0x63,
+ 0x75,0x72,0x72,0x65,0x6E,0x74,0x20,0x76,0x6F,0x6C,0x75,0x6D,
+ 0x65,0x2E,0x20,0x54,0x68,0x65,0x20,0x73,0x79,0x6E,0x74,0x61,
+ 0x78,0x20,0x69,0x73,0x20,0x65,0x78,0x61,0x63,0x74,0x6C,0x79,
+ 0x1B,0x61,0x73,0x20,0x66,0x6F,0x72,0x20,0x74,0x68,0x65,0x20,
+ 0x76,0x69,0x62,0x72,0x61,0x74,0x6F,0x20,0x63,0x6F,0x6D,0x6D,
+ 0x61,0x6E,0x64,0x2E,0x00,0x1E,0x40,0x58,0x30,0x34,0x30,0x40,
+ 0x43,0x30,0x30,0x31,0x53,0x65,0x74,0x20,0x70,0x61,0x6E,0x6E,
+ 0x69,0x6E,0x67,0x20,0x70,0x6F,0x73,0x69,0x74,0x69,0x6F,0x6E,
+ 0x0B,0x3E,0x40,0x58,0x30,0x36,0x30,0x40,0x43,0x30,0x30,0x32,
+ 0x14,0x53,0x79,0x6E,0x74,0x61,0x78,0x3A,0x20,0x38,0x20,0x2B,
+ 0x20,0x50,0x6F,0x73,0x69,0x74,0x69,0x6F,0x6E,0x00,0x3E,0x53,
+ 0x65,0x74,0x73,0x20,0x74,0x68,0x65,0x20,0x70,0x61,0x6E,0x6E,
+ 0x69,0x6E,0x67,0x20,0x70,0x6F,0x73,0x69,0x74,0x69,0x6F,0x6E,
+ 0x20,0x66,0x6F,0x72,0x20,0x74,0x68,0x65,0x20,0x63,0x68,0x61,
+ 0x6E,0x6E,0x65,0x6C,0x2E,0x20,0x24,0x30,0x30,0x20,0x69,0x73,
+ 0x20,0x74,0x68,0x65,0x20,0x6C,0x65,0x66,0x74,0x6D,0x6F,0x73,
+ 0x74,0x3F,0x70,0x6F,0x73,0x69,0x74,0x69,0x6F,0x6E,0x20,0x61,
+ 0x6E,0x64,0x20,0x24,0x46,0x46,0x20,0x74,0x68,0x65,0x20,0x72,
+ 0x69,0x67,0x68,0x74,0x6D,0x6F,0x73,0x74,0x2E,0x20,0x4E,0x6F,
+ 0x74,0x65,0x20,0x74,0x68,0x61,0x74,0x20,0x73,0x6F,0x6D,0x65,
+ 0x20,0x73,0x6F,0x75,0x6E,0x64,0x20,0x63,0x61,0x72,0x64,0x73,
+ 0x20,0x28,0x65,0x78,0x2E,0x30,0x47,0x55,0x53,0x29,0x20,0x63,
+ 0x61,0x6E,0x27,0x74,0x20,0x75,0x73,0x65,0x20,0x61,0x73,0x20,
+ 0x6D,0x61,0x6E,0x79,0x20,0x61,0x73,0x20,0x32,0x35,0x36,0x20,
+ 0x70,0x61,0x6E,0x6E,0x69,0x6E,0x67,0x20,0x70,0x6F,0x73,0x69,
+ 0x74,0x69,0x6F,0x6E,0x73,0x2E,0x00,0x17,0x40,0x58,0x30,0x34,
+ 0x30,0x40,0x43,0x30,0x30,0x31,0x53,0x61,0x6D,0x70,0x6C,0x65,
+ 0x20,0x6F,0x66,0x66,0x73,0x65,0x74,0x0B,0x3E,0x40,0x58,0x30,
+ 0x36,0x30,0x40,0x43,0x30,0x30,0x32,0x12,0x53,0x79,0x6E,0x74,
+ 0x61,0x78,0x3A,0x20,0x39,0x20,0x2B,0x20,0x4F,0x66,0x66,0x73,
+ 0x65,0x74,0x00,0x41,0x54,0x68,0x69,0x73,0x20,0x63,0x6F,0x6D,
+ 0x6D,0x61,0x6E,0x64,0x20,0x73,0x68,0x6F,0x75,0x6C,0x64,0x20,
+ 0x62,0x65,0x20,0x75,0x73,0x65,0x64,0x20,0x74,0x6F,0x67,0x65,
+ 0x74,0x68,0x65,0x72,0x20,0x77,0x69,0x74,0x68,0x20,0x61,0x20,
+ 0x6E,0x6F,0x74,0x65,0x2E,0x20,0x54,0x68,0x65,0x20,0x73,0x61,
+ 0x6D,0x70,0x6C,0x65,0x20,0x77,0x69,0x6C,0x6C,0x2D,0x62,0x65,
+ 0x20,0x70,0x6C,0x61,0x79,0x65,0x64,0x20,0x66,0x72,0x6F,0x6D,
+ 0x20,0x28,0x4F,0x66,0x66,0x73,0x65,0x74,0x2A,0x24,0x31,0x30,
+ 0x30,0x29,0x20,0x69,0x6E,0x73,0x74,0x65,0x61,0x64,0x20,0x6F,
+ 0x66,0x20,0x7A,0x65,0x72,0x6F,0x2E,0x00,0x16,0x40,0x58,0x30,
+ 0x34,0x30,0x40,0x43,0x30,0x30,0x31,0x56,0x6F,0x6C,0x75,0x6D,
+ 0x65,0x20,0x73,0x6C,0x69,0x64,0x65,0x0B,0x3E,0x40,0x58,0x30,
+ 0x36,0x30,0x40,0x43,0x30,0x30,0x32,0x21,0x53,0x79,0x6E,0x74,
+ 0x61,0x78,0x3A,0x20,0x41,0x20,0x2B,0x20,0x55,0x70,0x20,0x73,
+ 0x70,0x65,0x65,0x64,0x20,0x2B,0x20,0x44,0x6F,0x77,0x6E,0x20,
+ 0x73,0x70,0x65,0x65,0x64,0x00,0x3D,0x53,0x6C,0x69,0x64,0x65,
+ 0x73,0x20,0x74,0x68,0x65,0x20,0x63,0x75,0x72,0x72,0x65,0x6E,
+ 0x74,0x20,0x76,0x6F,0x6C,0x75,0x6D,0x65,0x20,0x75,0x70,0x20,
+ 0x6F,0x72,0x20,0x64,0x6F,0x77,0x6E,0x2E,0x20,0x45,0x69,0x74,
+ 0x68,0x65,0x72,0x20,0x75,0x70,0x20,0x73,0x70,0x65,0x65,0x64,
+ 0x20,0x6F,0x72,0x20,0x64,0x6F,0x77,0x6E,0x15,0x73,0x70,0x65,
+ 0x65,0x64,0x20,0x73,0x68,0x6F,0x75,0x6C,0x64,0x20,0x62,0x65,
+ 0x20,0x7A,0x65,0x72,0x6F,0x2E,0x00,0x17,0x40,0x58,0x30,0x34,
+ 0x30,0x40,0x43,0x30,0x30,0x31,0x50,0x6F,0x73,0x69,0x74,0x69,
+ 0x6F,0x6E,0x20,0x6A,0x75,0x6D,0x70,0x0B,0x3E,0x40,0x58,0x30,
+ 0x36,0x30,0x40,0x43,0x30,0x30,0x32,0x14,0x53,0x79,0x6E,0x74,
+ 0x61,0x78,0x3A,0x20,0x42,0x20,0x2B,0x20,0x50,0x6F,0x73,0x69,
+ 0x74,0x69,0x6F,0x6E,0x00,0x41,0x54,0x68,0x69,0x73,0x20,0x63,
+ 0x6F,0x6D,0x6D,0x61,0x6E,0x64,0x20,0x77,0x69,0x6C,0x6C,0x20,
+ 0x6A,0x75,0x6D,0x70,0x20,0x74,0x6F,0x20,0x74,0x68,0x65,0x20,
+ 0x73,0x65,0x6C,0x65,0x63,0x74,0x65,0x64,0x20,0x73,0x6F,0x6E,
+ 0x67,0x20,0x70,0x6F,0x73,0x69,0x74,0x69,0x6F,0x6E,0x20,0x61,
+ 0x6E,0x64,0x20,0x70,0x6C,0x61,0x79,0x20,0x74,0x68,0x65,0x1B,
+ 0x70,0x61,0x74,0x74,0x65,0x72,0x6E,0x20,0x66,0x72,0x6F,0x6D,
+ 0x20,0x74,0x68,0x65,0x20,0x62,0x65,0x67,0x69,0x6E,0x6E,0x69,
+ 0x6E,0x67,0x2E,0x00,0x14,0x40,0x58,0x30,0x34,0x30,0x40,0x43,
+ 0x30,0x30,0x31,0x53,0x65,0x74,0x20,0x76,0x6F,0x6C,0x75,0x6D,
+ 0x65,0x0B,0x3E,0x40,0x58,0x30,0x36,0x30,0x40,0x43,0x30,0x30,
+ 0x32,0x12,0x53,0x79,0x6E,0x74,0x61,0x78,0x3A,0x20,0x43,0x20,
+ 0x2B,0x20,0x56,0x6F,0x6C,0x75,0x6D,0x65,0x00,0x3E,0x53,0x65,
+ 0x74,0x73,0x20,0x74,0x68,0x65,0x20,0x63,0x75,0x72,0x72,0x65,
+ 0x6E,0x74,0x20,0x76,0x6F,0x6C,0x75,0x6D,0x65,0x2E,0x20,0x54,
+ 0x68,0x65,0x20,0x76,0x6F,0x6C,0x75,0x6D,0x65,0x20,0x73,0x68,
+ 0x6F,0x75,0x6C,0x64,0x20,0x6E,0x6F,0x74,0x20,0x62,0x65,0x20,
+ 0x67,0x72,0x65,0x61,0x74,0x65,0x72,0x20,0x74,0x68,0x61,0x6E,
+ 0x04,0x24,0x34,0x30,0x2E,0x00,0x17,0x40,0x58,0x30,0x34,0x30,
+ 0x40,0x43,0x30,0x30,0x31,0x50,0x61,0x74,0x74,0x65,0x72,0x6E,
+ 0x20,0x62,0x72,0x65,0x61,0x6B,0x0B,0x3E,0x40,0x58,0x30,0x36,
+ 0x30,0x40,0x43,0x30,0x30,0x32,0x1C,0x53,0x79,0x6E,0x74,0x61,
+ 0x78,0x3A,0x20,0x44,0x20,0x2B,0x20,0x50,0x61,0x74,0x74,0x65,
+ 0x72,0x6E,0x2D,0x70,0x6F,0x73,0x69,0x74,0x69,0x6F,0x6E,0x00,
+ 0x3C,0x54,0x68,0x69,0x73,0x20,0x63,0x6F,0x6D,0x6D,0x61,0x6E,
+ 0x64,0x20,0x77,0x69,0x6C,0x6C,0x20,0x6A,0x75,0x6D,0x70,0x20,
+ 0x74,0x6F,0x20,0x74,0x68,0x65,0x20,0x6E,0x65,0x78,0x74,0x20,
+ 0x70,0x61,0x74,0x74,0x65,0x72,0x6E,0x20,0x61,0x6E,0x64,0x20,
+ 0x70,0x6C,0x61,0x79,0x20,0x66,0x72,0x6F,0x6D,0x20,0x74,0x68,
+ 0x65,0x13,0x73,0x70,0x65,0x63,0x69,0x66,0x69,0x65,0x64,0x20,
+ 0x70,0x6F,0x73,0x69,0x74,0x69,0x6F,0x6E,0x2E,0x00,0x22,0x40,
0x58,0x30,0x34,0x30,0x40,0x43,0x30,0x30,0x31,0x53,0x65,0x74,
- 0x20,0x74,0x72,0x65,0x6D,0x6F,0x6C,0x6F,0x20,0x63,0x6F,0x6E,
- 0x74,0x72,0x6F,0x6C,0x0B,0x3E,0x40,0x58,0x30,0x36,0x30,0x40,
- 0x43,0x30,0x30,0x32,0x11,0x53,0x79,0x6E,0x74,0x61,0x78,0x3A,
- 0x20,0x45,0x37,0x20,0x2B,0x20,0x54,0x79,0x70,0x65,0x00,0x3A,
- 0x54,0x68,0x69,0x73,0x20,0x63,0x6F,0x6D,0x6D,0x61,0x6E,0x64,
- 0x20,0x77,0x6F,0x72,0x6B,0x73,0x20,0x65,0x78,0x61,0x63,0x74,
- 0x6C,0x79,0x20,0x61,0x73,0x20,0x73,0x65,0x74,0x20,0x76,0x69,
- 0x62,0x72,0x61,0x74,0x6F,0x20,0x63,0x6F,0x6E,0x74,0x72,0x6F,
- 0x6C,0x2C,0x20,0x62,0x75,0x74,0x20,0x74,0x68,0x65,0x2A,0x74,
- 0x72,0x65,0x6D,0x6F,0x6C,0x6F,0x20,0x77,0x61,0x76,0x65,0x20,
- 0x66,0x6F,0x72,0x6D,0x20,0x77,0x69,0x6C,0x6C,0x20,0x62,0x65,
- 0x20,0x63,0x68,0x61,0x6E,0x67,0x65,0x64,0x20,0x69,0x6E,0x73,
- 0x74,0x65,0x61,0x64,0x2E,0x00,0x15,0x40,0x58,0x30,0x34,0x30,
- 0x40,0x43,0x30,0x30,0x31,0x52,0x65,0x74,0x72,0x69,0x67,0x20,
- 0x6E,0x6F,0x74,0x65,0x0B,0x3E,0x40,0x58,0x30,0x36,0x30,0x40,
- 0x43,0x30,0x30,0x32,0x15,0x53,0x79,0x6E,0x74,0x61,0x78,0x3A,
- 0x20,0x45,0x39,0x20,0x2B,0x20,0x49,0x6E,0x74,0x65,0x72,0x76,
- 0x61,0x6C,0x00,0x2D,0x52,0x65,0x74,0x72,0x69,0x67,0x73,0x20,
- 0x74,0x68,0x65,0x20,0x6E,0x6F,0x74,0x65,0x20,0x77,0x69,0x74,
- 0x68,0x20,0x74,0x68,0x65,0x20,0x73,0x70,0x65,0x63,0x69,0x66,
- 0x69,0x65,0x64,0x20,0x69,0x6E,0x74,0x65,0x72,0x76,0x61,0x6C,
- 0x2E,0x00,0x23,0x40,0x58,0x30,0x34,0x30,0x40,0x43,0x30,0x30,
- 0x31,0x46,0x69,0x6E,0x65,0x20,0x76,0x6F,0x6C,0x75,0x6D,0x65,
- 0x20,0x73,0x6C,0x69,0x64,0x65,0x20,0x75,0x70,0x2F,0x64,0x6F,
+ 0x20,0x66,0x69,0x6C,0x74,0x65,0x72,0x20,0x28,0x41,0x6D,0x69,
+ 0x67,0x61,0x20,0x6F,0x6E,0x6C,0x79,0x21,0x29,0x0B,0x3E,0x40,
+ 0x58,0x30,0x36,0x30,0x40,0x43,0x30,0x30,0x32,0x13,0x53,0x79,
+ 0x6E,0x74,0x61,0x78,0x3A,0x20,0x45,0x30,0x20,0x2B,0x20,0x53,
+ 0x74,0x61,0x74,0x75,0x73,0x00,0x38,0x55,0x73,0x65,0x20,0x45,
+ 0x30,0x30,0x20,0x61,0x6E,0x64,0x20,0x79,0x6F,0x75,0x72,0x20,
+ 0x74,0x75,0x6E,0x65,0x20,0x77,0x69,0x6C,0x6C,0x20,0x73,0x6F,
+ 0x75,0x6E,0x64,0x20,0x72,0x65,0x61,0x6C,0x6C,0x79,0x20,0x62,
+ 0x61,0x64,0x20,0x6F,0x6E,0x20,0x61,0x6E,0x20,0x41,0x6D,0x69,
+ 0x67,0x61,0x21,0x00,0x21,0x40,0x58,0x30,0x34,0x30,0x40,0x43,
+ 0x30,0x30,0x31,0x46,0x69,0x6E,0x65,0x20,0x70,0x6F,0x72,0x74,
+ 0x61,0x6D,0x65,0x6E,0x74,0x6F,0x20,0x75,0x70,0x2F,0x64,0x6F,
0x77,0x6E,0x0B,0x3E,0x40,0x58,0x30,0x36,0x30,0x40,0x43,0x30,
0x30,0x32,0x19,0x53,0x79,0x6E,0x74,0x61,0x78,0x3A,0x20,0x45,
- 0x28,0x41,0x20,0x6F,0x72,0x20,0x42,0x29,0x20,0x2B,0x20,0x53,
- 0x70,0x65,0x65,0x64,0x00,0x44,0x54,0x68,0x69,0x73,0x20,0x63,
+ 0x28,0x31,0x20,0x6F,0x72,0x20,0x32,0x29,0x20,0x2B,0x20,0x53,
+ 0x70,0x65,0x65,0x64,0x00,0x3F,0x54,0x68,0x69,0x73,0x20,0x63,
0x6F,0x6D,0x6D,0x61,0x6E,0x64,0x20,0x77,0x6F,0x72,0x6B,0x73,
- 0x20,0x61,0x73,0x20,0x74,0x68,0x65,0x20,0x75,0x73,0x75,0x61,
- 0x6C,0x20,0x76,0x6F,0x6C,0x75,0x6D,0x65,0x20,0x73,0x6C,0x69,
- 0x64,0x65,0x2C,0x20,0x62,0x75,0x74,0x20,0x69,0x74,0x20,0x77,
- 0x69,0x6C,0x6C,0x20,0x6F,0x6E,0x6C,0x79,0x20,0x73,0x6C,0x69,
- 0x64,0x65,0x05,0x6F,0x6E,0x63,0x65,0x2E,0x00,0x12,0x40,0x58,
- 0x30,0x34,0x30,0x40,0x43,0x30,0x30,0x31,0x4E,0x6F,0x74,0x65,
- 0x20,0x63,0x75,0x74,0x0B,0x3E,0x40,0x58,0x30,0x36,0x30,0x40,
+ 0x20,0x61,0x73,0x20,0x70,0x6F,0x72,0x74,0x61,0x6D,0x65,0x6E,
+ 0x74,0x6F,0x20,0x75,0x70,0x2F,0x64,0x6F,0x77,0x6E,0x2C,0x20,
+ 0x62,0x75,0x74,0x20,0x69,0x74,0x20,0x6F,0x6E,0x6C,0x79,0x20,
+ 0x73,0x6C,0x69,0x64,0x65,0x73,0x20,0x75,0x70,0x05,0x6F,0x6E,
+ 0x63,0x65,0x2E,0x00,0x1F,0x40,0x58,0x30,0x34,0x30,0x40,0x43,
+ 0x30,0x30,0x31,0x53,0x65,0x74,0x20,0x67,0x6C,0x69,0x73,0x73,
+ 0x61,0x6E,0x64,0x6F,0x20,0x63,0x6F,0x6E,0x74,0x72,0x6F,0x6C,
+ 0x0B,0x3E,0x40,0x58,0x30,0x36,0x30,0x40,0x43,0x30,0x30,0x32,
+ 0x13,0x53,0x79,0x6E,0x74,0x61,0x78,0x3A,0x20,0x45,0x33,0x20,
+ 0x2B,0x20,0x53,0x74,0x61,0x74,0x75,0x73,0x00,0x41,0x49,0x66,
+ 0x20,0x53,0x74,0x61,0x74,0x75,0x73,0x20,0x69,0x73,0x20,0x3D,
+ 0x31,0x2C,0x20,0x74,0x68,0x65,0x20,0x66,0x72,0x65,0x71,0x75,
+ 0x65,0x6E,0x63,0x79,0x20,0x77,0x68,0x65,0x6E,0x20,0x75,0x73,
+ 0x69,0x6E,0x67,0x20,0x74,0x6F,0x6E,0x65,0x20,0x70,0x6F,0x72,
+ 0x74,0x61,0x6D,0x65,0x6E,0x74,0x6F,0x20,0x77,0x69,0x6C,0x6C,
+ 0x20,0x62,0x65,0x20,0x72,0x6F,0x75,0x6E,0x64,0x65,0x64,0x20,
+ 0x74,0x6F,0x20,0x74,0x68,0x65,0x20,0x6E,0x65,0x61,0x72,0x65,
+ 0x73,0x74,0x20,0x68,0x61,0x6C,0x66,0x74,0x6F,0x6E,0x65,0x2E,
+ 0x00,0x1D,0x40,0x58,0x30,0x34,0x30,0x40,0x43,0x30,0x30,0x31,
+ 0x53,0x65,0x74,0x20,0x76,0x69,0x62,0x72,0x61,0x74,0x6F,0x20,
+ 0x63,0x6F,0x6E,0x74,0x72,0x6F,0x6C,0x0B,0x3E,0x40,0x58,0x30,
+ 0x36,0x30,0x40,0x43,0x30,0x30,0x32,0x11,0x53,0x79,0x6E,0x74,
+ 0x61,0x78,0x3A,0x20,0x45,0x34,0x20,0x2B,0x20,0x54,0x79,0x70,
+ 0x65,0x00,0x2B,0x54,0x68,0x69,0x73,0x20,0x63,0x6F,0x6D,0x6D,
+ 0x61,0x6E,0x64,0x20,0x63,0x6F,0x6E,0x74,0x72,0x6F,0x6C,0x73,
+ 0x20,0x74,0x68,0x65,0x20,0x76,0x69,0x62,0x72,0x61,0x74,0x6F,
+ 0x20,0x77,0x61,0x76,0x65,0x66,0x6F,0x72,0x6D,0x2E,0x00,0x33,
+ 0x54,0x79,0x70,0x65,0x3A,0x20,0x30,0x20,0x3D,0x20,0x53,0x69,
+ 0x6E,0x65,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x31,0x20,0x3D,
+ 0x20,0x52,0x61,0x6D,0x70,0x20,0x64,0x6F,0x77,0x6E,0x20,0x20,
+ 0x20,0x20,0x20,0x20,0x20,0x32,0x20,0x3D,0x20,0x53,0x71,0x75,
+ 0x61,0x72,0x65,0x00,0x43,0x49,0x66,0x20,0x79,0x6F,0x75,0x20,
+ 0x61,0x64,0x64,0x20,0x34,0x20,0x74,0x6F,0x20,0x74,0x68,0x65,
+ 0x20,0x74,0x79,0x70,0x65,0x2C,0x20,0x74,0x68,0x65,0x20,0x77,
+ 0x61,0x76,0x65,0x66,0x6F,0x72,0x6D,0x20,0x77,0x69,0x6C,0x6C,
+ 0x20,0x6E,0x6F,0x74,0x20,0x62,0x65,0x20,0x72,0x65,0x74,0x72,
+ 0x69,0x67,0x67,0x65,0x64,0x20,0x77,0x68,0x65,0x6E,0x20,0x61,
+ 0x19,0x6E,0x65,0x77,0x20,0x69,0x6E,0x73,0x74,0x72,0x75,0x6D,
+ 0x65,0x6E,0x74,0x20,0x69,0x73,0x20,0x70,0x6C,0x61,0x79,0x65,
+ 0x64,0x2E,0x00,0x17,0x40,0x58,0x30,0x34,0x30,0x40,0x43,0x30,
+ 0x30,0x31,0x53,0x65,0x74,0x20,0x66,0x69,0x6E,0x65,0x2D,0x74,
+ 0x75,0x6E,0x65,0x0B,0x3E,0x40,0x58,0x30,0x36,0x30,0x40,0x43,
+ 0x30,0x30,0x32,0x11,0x53,0x79,0x6E,0x74,0x61,0x78,0x3A,0x20,
+ 0x45,0x35,0x20,0x2B,0x20,0x54,0x75,0x6E,0x65,0x00,0x3F,0x54,
+ 0x68,0x69,0x73,0x20,0x63,0x6F,0x6D,0x6D,0x61,0x6E,0x64,0x20,
+ 0x73,0x68,0x6F,0x75,0x6C,0x64,0x20,0x62,0x65,0x20,0x75,0x73,
+ 0x65,0x64,0x20,0x74,0x6F,0x67,0x65,0x74,0x68,0x65,0x72,0x20,
+ 0x77,0x69,0x74,0x68,0x20,0x61,0x20,0x6E,0x6F,0x74,0x65,0x2E,
+ 0x20,0x49,0x74,0x20,0x77,0x69,0x6C,0x6C,0x20,0x63,0x61,0x75,
+ 0x73,0x65,0x44,0x61,0x6E,0x6F,0x74,0x68,0x65,0x72,0x20,0x66,
+ 0x69,0x6E,0x65,0x2D,0x74,0x75,0x6E,0x65,0x20,0x76,0x61,0x6C,
+ 0x75,0x65,0x20,0x74,0x6F,0x20,0x62,0x65,0x20,0x75,0x73,0x65,
+ 0x64,0x2E,0x20,0x49,0x74,0x20,0x73,0x65,0x65,0x6D,0x73,0x20,
+ 0x71,0x75,0x69,0x74,0x65,0x20,0x75,0x6E,0x75,0x73,0x61,0x62,
+ 0x6C,0x65,0x20,0x74,0x6F,0x20,0x6D,0x65,0x2E,0x2E,0x2E,0x00,
+ 0x16,0x40,0x58,0x30,0x34,0x30,0x40,0x43,0x30,0x30,0x31,0x50,
+ 0x61,0x74,0x74,0x65,0x72,0x6E,0x20,0x6C,0x6F,0x6F,0x70,0x0B,
+ 0x3E,0x40,0x58,0x30,0x36,0x30,0x40,0x43,0x30,0x30,0x32,0x12,
+ 0x53,0x79,0x6E,0x74,0x61,0x78,0x3A,0x20,0x45,0x36,0x20,0x2B,
+ 0x20,0x43,0x6F,0x75,0x6E,0x74,0x00,0x45,0x49,0x66,0x20,0x63,
+ 0x6F,0x75,0x6E,0x74,0x20,0x69,0x73,0x20,0x7A,0x65,0x72,0x6F,
+ 0x2C,0x20,0x74,0x68,0x65,0x20,0x62,0x65,0x67,0x69,0x6E,0x6E,
+ 0x69,0x6E,0x67,0x20,0x6F,0x66,0x20,0x74,0x68,0x65,0x20,0x6C,
+ 0x6F,0x6F,0x70,0x20,0x77,0x69,0x6C,0x6C,0x20,0x62,0x65,0x20,
+ 0x73,0x70,0x65,0x63,0x69,0x66,0x69,0x65,0x64,0x2E,0x20,0x57,
+ 0x68,0x65,0x6E,0x20,0x61,0x40,0x6E,0x6F,0x6E,0x2D,0x7A,0x65,
+ 0x72,0x6F,0x20,0x76,0x61,0x6C,0x75,0x65,0x20,0x69,0x73,0x20,
+ 0x75,0x73,0x65,0x64,0x2C,0x20,0x74,0x68,0x65,0x20,0x70,0x61,
+ 0x74,0x74,0x65,0x72,0x6E,0x20,0x77,0x69,0x6C,0x6C,0x20,0x62,
+ 0x65,0x20,0x6C,0x6F,0x6F,0x70,0x65,0x64,0x20,0x66,0x72,0x6F,
+ 0x6D,0x20,0x74,0x68,0x65,0x20,0x6C,0x6F,0x6F,0x70,0x06,0x73,
+ 0x74,0x61,0x72,0x74,0x2E,0x00,0x1D,0x40,0x58,0x30,0x34,0x30,
+ 0x40,0x43,0x30,0x30,0x31,0x53,0x65,0x74,0x20,0x74,0x72,0x65,
+ 0x6D,0x6F,0x6C,0x6F,0x20,0x63,0x6F,0x6E,0x74,0x72,0x6F,0x6C,
+ 0x0B,0x3E,0x40,0x58,0x30,0x36,0x30,0x40,0x43,0x30,0x30,0x32,
+ 0x11,0x53,0x79,0x6E,0x74,0x61,0x78,0x3A,0x20,0x45,0x37,0x20,
+ 0x2B,0x20,0x54,0x79,0x70,0x65,0x00,0x3A,0x54,0x68,0x69,0x73,
+ 0x20,0x63,0x6F,0x6D,0x6D,0x61,0x6E,0x64,0x20,0x77,0x6F,0x72,
+ 0x6B,0x73,0x20,0x65,0x78,0x61,0x63,0x74,0x6C,0x79,0x20,0x61,
+ 0x73,0x20,0x73,0x65,0x74,0x20,0x76,0x69,0x62,0x72,0x61,0x74,
+ 0x6F,0x20,0x63,0x6F,0x6E,0x74,0x72,0x6F,0x6C,0x2C,0x20,0x62,
+ 0x75,0x74,0x20,0x74,0x68,0x65,0x29,0x74,0x72,0x65,0x6D,0x6F,
+ 0x6C,0x6F,0x20,0x77,0x61,0x76,0x65,0x66,0x6F,0x72,0x6D,0x20,
+ 0x77,0x69,0x6C,0x6C,0x20,0x62,0x65,0x20,0x63,0x68,0x61,0x6E,
+ 0x67,0x65,0x64,0x20,0x69,0x6E,0x73,0x74,0x65,0x61,0x64,0x2E,
+ 0x00,0x15,0x40,0x58,0x30,0x34,0x30,0x40,0x43,0x30,0x30,0x31,
+ 0x52,0x65,0x74,0x72,0x69,0x67,0x20,0x6E,0x6F,0x74,0x65,0x0B,
+ 0x3E,0x40,0x58,0x30,0x36,0x30,0x40,0x43,0x30,0x30,0x32,0x15,
+ 0x53,0x79,0x6E,0x74,0x61,0x78,0x3A,0x20,0x45,0x39,0x20,0x2B,
+ 0x20,0x49,0x6E,0x74,0x65,0x72,0x76,0x61,0x6C,0x00,0x2D,0x52,
+ 0x65,0x74,0x72,0x69,0x67,0x73,0x20,0x74,0x68,0x65,0x20,0x6E,
+ 0x6F,0x74,0x65,0x20,0x77,0x69,0x74,0x68,0x20,0x74,0x68,0x65,
+ 0x20,0x73,0x70,0x65,0x63,0x69,0x66,0x69,0x65,0x64,0x20,0x69,
+ 0x6E,0x74,0x65,0x72,0x76,0x61,0x6C,0x2E,0x00,0x23,0x40,0x58,
+ 0x30,0x34,0x30,0x40,0x43,0x30,0x30,0x31,0x46,0x69,0x6E,0x65,
+ 0x20,0x76,0x6F,0x6C,0x75,0x6D,0x65,0x20,0x73,0x6C,0x69,0x64,
+ 0x65,0x20,0x75,0x70,0x2F,0x64,0x6F,0x77,0x6E,0x0B,0x3E,0x40,
+ 0x58,0x30,0x36,0x30,0x40,0x43,0x30,0x30,0x32,0x19,0x53,0x79,
+ 0x6E,0x74,0x61,0x78,0x3A,0x20,0x45,0x28,0x41,0x20,0x6F,0x72,
+ 0x20,0x42,0x29,0x20,0x2B,0x20,0x53,0x70,0x65,0x65,0x64,0x00,
+ 0x44,0x54,0x68,0x69,0x73,0x20,0x63,0x6F,0x6D,0x6D,0x61,0x6E,
+ 0x64,0x20,0x77,0x6F,0x72,0x6B,0x73,0x20,0x61,0x73,0x20,0x74,
+ 0x68,0x65,0x20,0x75,0x73,0x75,0x61,0x6C,0x20,0x76,0x6F,0x6C,
+ 0x75,0x6D,0x65,0x20,0x73,0x6C,0x69,0x64,0x65,0x2C,0x20,0x62,
+ 0x75,0x74,0x20,0x69,0x74,0x20,0x77,0x69,0x6C,0x6C,0x20,0x6F,
+ 0x6E,0x6C,0x79,0x20,0x73,0x6C,0x69,0x64,0x65,0x05,0x6F,0x6E,
+ 0x63,0x65,0x2E,0x00,0x12,0x40,0x58,0x30,0x34,0x30,0x40,0x43,
+ 0x30,0x30,0x31,0x4E,0x6F,0x74,0x65,0x20,0x63,0x75,0x74,0x0B,
+ 0x3E,0x40,0x58,0x30,0x36,0x30,0x40,0x43,0x30,0x30,0x32,0x11,
+ 0x53,0x79,0x6E,0x74,0x61,0x78,0x3A,0x20,0x45,0x43,0x20,0x2B,
+ 0x20,0x54,0x69,0x63,0x6B,0x00,0x43,0x43,0x75,0x74,0x73,0x20,
+ 0x74,0x68,0x65,0x20,0x6E,0x6F,0x74,0x65,0x20,0x61,0x74,0x20,
+ 0x74,0x68,0x65,0x20,0x73,0x70,0x65,0x63,0x69,0x66,0x69,0x65,
+ 0x64,0x20,0x74,0x69,0x63,0x6B,0x2E,0x20,0x4E,0x6F,0x74,0x65,
+ 0x20,0x74,0x68,0x61,0x74,0x20,0x69,0x74,0x20,0x77,0x69,0x6C,
+ 0x6C,0x20,0x6F,0x6E,0x6C,0x79,0x20,0x73,0x65,0x74,0x20,0x74,
+ 0x68,0x65,0x34,0x76,0x6F,0x6C,0x75,0x6D,0x65,0x20,0x74,0x6F,
+ 0x20,0x7A,0x65,0x72,0x6F,0x2C,0x20,0x61,0x6E,0x64,0x20,0x74,
+ 0x68,0x65,0x20,0x73,0x61,0x6D,0x70,0x6C,0x65,0x20,0x77,0x69,
+ 0x6C,0x6C,0x20,0x73,0x74,0x69,0x6C,0x6C,0x20,0x62,0x65,0x20,
+ 0x70,0x6C,0x61,0x79,0x65,0x64,0x2E,0x00,0x14,0x40,0x58,0x30,
+ 0x34,0x30,0x40,0x43,0x30,0x30,0x31,0x4E,0x6F,0x74,0x65,0x20,
+ 0x64,0x65,0x6C,0x61,0x79,0x0B,0x3E,0x40,0x58,0x30,0x36,0x30,
+ 0x40,0x43,0x30,0x30,0x32,0x12,0x53,0x79,0x6E,0x74,0x61,0x78,
+ 0x3A,0x20,0x45,0x44,0x20,0x2B,0x20,0x54,0x69,0x63,0x6B,0x73,
+ 0x00,0x3E,0x54,0x68,0x69,0x73,0x20,0x63,0x6F,0x6D,0x6D,0x61,
+ 0x6E,0x64,0x20,0x77,0x69,0x6C,0x6C,0x20,0x64,0x65,0x6C,0x61,
+ 0x79,0x20,0x74,0x68,0x65,0x20,0x6E,0x6F,0x74,0x65,0x20,0x74,
+ 0x68,0x65,0x20,0x73,0x65,0x6C,0x65,0x63,0x74,0x65,0x64,0x20,
+ 0x6E,0x75,0x6D,0x62,0x65,0x72,0x20,0x6F,0x66,0x20,0x74,0x69,
+ 0x63,0x6B,0x73,0x2E,0x00,0x17,0x40,0x58,0x30,0x34,0x30,0x40,
+ 0x43,0x30,0x30,0x31,0x50,0x61,0x74,0x74,0x65,0x72,0x6E,0x20,
+ 0x64,0x65,0x6C,0x61,0x79,0x0B,0x3E,0x40,0x58,0x30,0x36,0x30,
+ 0x40,0x43,0x30,0x30,0x32,0x12,0x53,0x79,0x6E,0x74,0x61,0x78,
+ 0x3A,0x20,0x45,0x45,0x20,0x2B,0x20,0x4E,0x6F,0x74,0x65,0x73,
+ 0x00,0x41,0x54,0x68,0x69,0x73,0x20,0x63,0x6F,0x6D,0x6D,0x61,
+ 0x6E,0x64,0x20,0x77,0x69,0x6C,0x6C,0x20,0x64,0x65,0x6C,0x61,
+ 0x79,0x20,0x74,0x68,0x65,0x20,0x70,0x61,0x74,0x74,0x65,0x72,
+ 0x6E,0x20,0x74,0x68,0x65,0x20,0x73,0x65,0x6C,0x65,0x63,0x74,
+ 0x65,0x64,0x20,0x6E,0x75,0x6D,0x62,0x65,0x72,0x20,0x6F,0x66,
+ 0x20,0x6E,0x6F,0x74,0x65,0x73,0x2E,0x00,0x13,0x40,0x58,0x30,
+ 0x34,0x30,0x40,0x43,0x30,0x30,0x31,0x53,0x65,0x74,0x20,0x73,
+ 0x70,0x65,0x65,0x64,0x0B,0x3E,0x40,0x58,0x30,0x36,0x30,0x40,
0x43,0x30,0x30,0x32,0x11,0x53,0x79,0x6E,0x74,0x61,0x78,0x3A,
- 0x20,0x45,0x43,0x20,0x2B,0x20,0x54,0x69,0x63,0x6B,0x00,0x43,
- 0x43,0x75,0x74,0x73,0x20,0x74,0x68,0x65,0x20,0x6E,0x6F,0x74,
- 0x65,0x20,0x61,0x74,0x20,0x74,0x68,0x65,0x20,0x73,0x70,0x65,
- 0x63,0x69,0x66,0x69,0x65,0x64,0x20,0x74,0x69,0x63,0x6B,0x2E,
- 0x20,0x4E,0x6F,0x74,0x65,0x20,0x74,0x68,0x61,0x74,0x20,0x69,
- 0x74,0x20,0x77,0x69,0x6C,0x6C,0x20,0x6F,0x6E,0x6C,0x79,0x20,
- 0x73,0x65,0x74,0x20,0x74,0x68,0x65,0x34,0x76,0x6F,0x6C,0x75,
- 0x6D,0x65,0x20,0x74,0x6F,0x20,0x7A,0x65,0x72,0x6F,0x2C,0x20,
- 0x61,0x6E,0x64,0x20,0x74,0x68,0x65,0x20,0x73,0x61,0x6D,0x70,
- 0x6C,0x65,0x20,0x77,0x69,0x6C,0x6C,0x20,0x73,0x74,0x69,0x6C,
- 0x6C,0x20,0x62,0x65,0x20,0x70,0x6C,0x61,0x79,0x65,0x64,0x2E,
- 0x00,0x14,0x40,0x58,0x30,0x34,0x30,0x40,0x43,0x30,0x30,0x31,
- 0x4E,0x6F,0x74,0x65,0x20,0x64,0x65,0x6C,0x61,0x79,0x0B,0x3E,
- 0x40,0x58,0x30,0x36,0x30,0x40,0x43,0x30,0x30,0x32,0x12,0x53,
- 0x79,0x6E,0x74,0x61,0x78,0x3A,0x20,0x45,0x44,0x20,0x2B,0x20,
- 0x54,0x69,0x63,0x6B,0x73,0x00,0x3E,0x54,0x68,0x69,0x73,0x20,
- 0x63,0x6F,0x6D,0x6D,0x61,0x6E,0x64,0x20,0x77,0x69,0x6C,0x6C,
- 0x20,0x64,0x65,0x6C,0x61,0x79,0x20,0x74,0x68,0x65,0x20,0x6E,
- 0x6F,0x74,0x65,0x20,0x74,0x68,0x65,0x20,0x73,0x65,0x6C,0x65,
- 0x63,0x74,0x65,0x64,0x20,0x6E,0x75,0x6D,0x62,0x65,0x72,0x20,
- 0x6F,0x66,0x20,0x74,0x69,0x63,0x6B,0x73,0x2E,0x00,0x17,0x40,
- 0x58,0x30,0x34,0x30,0x40,0x43,0x30,0x30,0x31,0x50,0x61,0x74,
- 0x74,0x65,0x72,0x6E,0x20,0x64,0x65,0x6C,0x61,0x79,0x0B,0x3E,
- 0x40,0x58,0x30,0x36,0x30,0x40,0x43,0x30,0x30,0x32,0x12,0x53,
- 0x79,0x6E,0x74,0x61,0x78,0x3A,0x20,0x45,0x45,0x20,0x2B,0x20,
- 0x4E,0x6F,0x74,0x65,0x73,0x00,0x41,0x54,0x68,0x69,0x73,0x20,
- 0x63,0x6F,0x6D,0x6D,0x61,0x6E,0x64,0x20,0x77,0x69,0x6C,0x6C,
- 0x20,0x64,0x65,0x6C,0x61,0x79,0x20,0x74,0x68,0x65,0x20,0x70,
- 0x61,0x74,0x74,0x65,0x72,0x6E,0x20,0x74,0x68,0x65,0x20,0x73,
- 0x65,0x6C,0x65,0x63,0x74,0x65,0x64,0x20,0x6E,0x75,0x6D,0x62,
- 0x65,0x72,0x20,0x6F,0x66,0x20,0x6E,0x6F,0x74,0x65,0x73,0x2E,
- 0x00,0x13,0x40,0x58,0x30,0x34,0x30,0x40,0x43,0x30,0x30,0x31,
- 0x53,0x65,0x74,0x20,0x73,0x70,0x65,0x65,0x64,0x0B,0x3E,0x40,
- 0x58,0x30,0x36,0x30,0x40,0x43,0x30,0x30,0x32,0x11,0x53,0x79,
- 0x6E,0x74,0x61,0x78,0x3A,0x20,0x46,0x20,0x2B,0x20,0x56,0x61,
- 0x6C,0x75,0x65,0x00,0x42,0x54,0x68,0x69,0x73,0x20,0x63,0x6F,
- 0x6D,0x6D,0x61,0x6E,0x64,0x20,0x77,0x69,0x6C,0x6C,0x20,0x73,
- 0x65,0x74,0x20,0x74,0x68,0x65,0x20,0x73,0x70,0x65,0x65,0x64,
- 0x20,0x6F,0x72,0x20,0x42,0x50,0x4D,0x20,0x76,0x61,0x6C,0x75,
- 0x65,0x20,0x6F,0x66,0x20,0x74,0x68,0x65,0x20,0x73,0x6F,0x6E,
- 0x67,0x2E,0x20,0x49,0x66,0x20,0x76,0x61,0x6C,0x75,0x65,0x3F,
- 0x69,0x73,0x20,0x6C,0x65,0x73,0x73,0x20,0x74,0x68,0x61,0x6E,
- 0x20,0x24,0x32,0x30,0x2C,0x20,0x74,0x68,0x65,0x20,0x73,0x70,
- 0x65,0x65,0x64,0x20,0x77,0x69,0x6C,0x6C,0x20,0x62,0x65,0x20,
- 0x63,0x68,0x61,0x6E,0x67,0x65,0x64,0x2E,0x20,0x4F,0x74,0x68,
- 0x65,0x72,0x77,0x69,0x73,0x65,0x2C,0x20,0x74,0x68,0x65,0x20,
- 0x42,0x50,0x4D,0x16,0x76,0x61,0x6C,0x75,0x65,0x20,0x77,0x69,
- 0x6C,0x6C,0x20,0x62,0x65,0x20,0x63,0x68,0x61,0x6E,0x67,0x65,
- 0x64,0x2E,0x00,0x1B,0x40,0x58,0x30,0x34,0x30,0x40,0x43,0x30,
- 0x30,0x31,0x53,0x65,0x74,0x20,0x67,0x6C,0x6F,0x62,0x61,0x6C,
- 0x20,0x76,0x6F,0x6C,0x75,0x6D,0x65,0x0B,0x3E,0x40,0x58,0x30,
- 0x36,0x30,0x40,0x43,0x30,0x30,0x32,0x12,0x53,0x79,0x6E,0x74,
- 0x61,0x78,0x3A,0x20,0x47,0x20,0x2B,0x20,0x76,0x6F,0x6C,0x75,
- 0x6D,0x65,0x00,0x42,0x53,0x65,0x74,0x73,0x20,0x74,0x68,0x65,
+ 0x20,0x46,0x20,0x2B,0x20,0x56,0x61,0x6C,0x75,0x65,0x00,0x42,
+ 0x54,0x68,0x69,0x73,0x20,0x63,0x6F,0x6D,0x6D,0x61,0x6E,0x64,
+ 0x20,0x77,0x69,0x6C,0x6C,0x20,0x73,0x65,0x74,0x20,0x74,0x68,
+ 0x65,0x20,0x73,0x70,0x65,0x65,0x64,0x20,0x6F,0x72,0x20,0x42,
+ 0x50,0x4D,0x20,0x76,0x61,0x6C,0x75,0x65,0x20,0x6F,0x66,0x20,
+ 0x74,0x68,0x65,0x20,0x73,0x6F,0x6E,0x67,0x2E,0x20,0x49,0x66,
+ 0x20,0x76,0x61,0x6C,0x75,0x65,0x3F,0x69,0x73,0x20,0x6C,0x65,
+ 0x73,0x73,0x20,0x74,0x68,0x61,0x6E,0x20,0x24,0x32,0x30,0x2C,
+ 0x20,0x74,0x68,0x65,0x20,0x73,0x70,0x65,0x65,0x64,0x20,0x77,
+ 0x69,0x6C,0x6C,0x20,0x62,0x65,0x20,0x63,0x68,0x61,0x6E,0x67,
+ 0x65,0x64,0x2E,0x20,0x4F,0x74,0x68,0x65,0x72,0x77,0x69,0x73,
+ 0x65,0x2C,0x20,0x74,0x68,0x65,0x20,0x42,0x50,0x4D,0x16,0x76,
+ 0x61,0x6C,0x75,0x65,0x20,0x77,0x69,0x6C,0x6C,0x20,0x62,0x65,
+ 0x20,0x63,0x68,0x61,0x6E,0x67,0x65,0x64,0x2E,0x00,0x1B,0x40,
+ 0x58,0x30,0x34,0x30,0x40,0x43,0x30,0x30,0x31,0x53,0x65,0x74,
0x20,0x67,0x6C,0x6F,0x62,0x61,0x6C,0x20,0x76,0x6F,0x6C,0x75,
- 0x6D,0x65,0x2E,0x20,0x54,0x68,0x65,0x20,0x76,0x6F,0x6C,0x75,
- 0x6D,0x65,0x20,0x73,0x68,0x6F,0x75,0x6C,0x64,0x20,0x6E,0x6F,
- 0x74,0x20,0x62,0x65,0x20,0x67,0x72,0x65,0x61,0x74,0x65,0x72,
- 0x20,0x74,0x68,0x61,0x6E,0x20,0x24,0x34,0x30,0x2E,0x00,0x1D,
- 0x40,0x58,0x30,0x34,0x30,0x40,0x43,0x30,0x30,0x31,0x47,0x6C,
- 0x6F,0x62,0x61,0x6C,0x20,0x76,0x6F,0x6C,0x75,0x6D,0x65,0x20,
- 0x73,0x6C,0x69,0x64,0x65,0x0B,0x3E,0x40,0x58,0x30,0x36,0x30,
- 0x40,0x43,0x30,0x30,0x32,0x21,0x53,0x79,0x6E,0x74,0x61,0x78,
- 0x3A,0x20,0x48,0x20,0x2B,0x20,0x55,0x70,0x20,0x73,0x70,0x65,
- 0x65,0x64,0x20,0x2B,0x20,0x44,0x6F,0x77,0x6E,0x20,0x73,0x70,
- 0x65,0x65,0x64,0x00,0x3D,0x54,0x68,0x69,0x73,0x20,0x63,0x6F,
- 0x6D,0x6D,0x61,0x6E,0x64,0x20,0x77,0x6F,0x72,0x6B,0x73,0x20,
- 0x65,0x78,0x61,0x63,0x74,0x6C,0x79,0x20,0x61,0x73,0x20,0x76,
- 0x6F,0x6C,0x75,0x6D,0x65,0x20,0x73,0x6C,0x69,0x64,0x65,0x2C,
- 0x20,0x62,0x75,0x74,0x20,0x69,0x74,0x20,0x73,0x6C,0x69,0x64,
- 0x65,0x73,0x20,0x74,0x68,0x65,0x16,0x67,0x6C,0x6F,0x62,0x61,
- 0x6C,0x20,0x76,0x6F,0x6C,0x75,0x6D,0x65,0x20,0x69,0x6E,0x73,
- 0x74,0x65,0x61,0x64,0x2E,0x00,0x11,0x40,0x58,0x30,0x34,0x30,
- 0x40,0x43,0x30,0x30,0x31,0x4B,0x65,0x79,0x20,0x6F,0x66,0x66,
+ 0x6D,0x65,0x0B,0x3E,0x40,0x58,0x30,0x36,0x30,0x40,0x43,0x30,
+ 0x30,0x32,0x12,0x53,0x79,0x6E,0x74,0x61,0x78,0x3A,0x20,0x47,
+ 0x20,0x2B,0x20,0x76,0x6F,0x6C,0x75,0x6D,0x65,0x00,0x42,0x53,
+ 0x65,0x74,0x73,0x20,0x74,0x68,0x65,0x20,0x67,0x6C,0x6F,0x62,
+ 0x61,0x6C,0x20,0x76,0x6F,0x6C,0x75,0x6D,0x65,0x2E,0x20,0x54,
+ 0x68,0x65,0x20,0x76,0x6F,0x6C,0x75,0x6D,0x65,0x20,0x73,0x68,
+ 0x6F,0x75,0x6C,0x64,0x20,0x6E,0x6F,0x74,0x20,0x62,0x65,0x20,
+ 0x67,0x72,0x65,0x61,0x74,0x65,0x72,0x20,0x74,0x68,0x61,0x6E,
+ 0x20,0x24,0x34,0x30,0x2E,0x00,0x1D,0x40,0x58,0x30,0x34,0x30,
+ 0x40,0x43,0x30,0x30,0x31,0x47,0x6C,0x6F,0x62,0x61,0x6C,0x20,
+ 0x76,0x6F,0x6C,0x75,0x6D,0x65,0x20,0x73,0x6C,0x69,0x64,0x65,
0x0B,0x3E,0x40,0x58,0x30,0x36,0x30,0x40,0x43,0x30,0x30,0x32,
- 0x10,0x53,0x79,0x6E,0x74,0x61,0x78,0x3A,0x20,0x4B,0x20,0x2B,
- 0x20,0x54,0x69,0x63,0x6B,0x00,0x3C,0x54,0x68,0x69,0x73,0x20,
- 0x63,0x6F,0x6D,0x6D,0x61,0x6E,0x64,0x20,0x77,0x69,0x6C,0x6C,
- 0x20,0x74,0x72,0x69,0x67,0x67,0x65,0x72,0x20,0x61,0x20,0x22,
- 0x4B,0x65,0x79,0x20,0x6F,0x66,0x66,0x22,0x20,0x61,0x74,0x20,
- 0x74,0x68,0x65,0x20,0x73,0x70,0x65,0x63,0x69,0x66,0x69,0x65,
- 0x64,0x20,0x74,0x69,0x63,0x6B,0x2E,0x00,0x1F,0x40,0x58,0x30,
- 0x34,0x30,0x40,0x43,0x30,0x30,0x31,0x53,0x65,0x74,0x20,0x65,
- 0x6E,0x76,0x65,0x6C,0x6F,0x70,0x65,0x20,0x70,0x6F,0x73,0x69,
- 0x74,0x69,0x6F,0x6E,0x0B,0x3E,0x40,0x58,0x30,0x36,0x30,0x40,
- 0x43,0x30,0x30,0x32,0x14,0x53,0x79,0x6E,0x74,0x61,0x78,0x3A,
- 0x20,0x4C,0x20,0x2B,0x20,0x50,0x6F,0x73,0x69,0x74,0x69,0x6F,
- 0x6E,0x00,0x3E,0x43,0x68,0x61,0x6E,0x67,0x65,0x73,0x20,0x74,
- 0x68,0x65,0x20,0x65,0x6E,0x76,0x65,0x6C,0x6F,0x70,0x65,0x20,
- 0x70,0x6F,0x73,0x69,0x74,0x69,0x6F,0x6E,0x2E,0x20,0x4D,0x61,
- 0x67,0x6E,0x75,0x73,0x20,0x74,0x6F,0x6C,0x64,0x20,0x6D,0x65,
- 0x20,0x74,0x68,0x61,0x74,0x20,0x69,0x74,0x20,0x77,0x6F,0x75,
- 0x6C,0x64,0x20,0x62,0x65,0x0C,0x76,0x65,0x72,0x79,0x20,0x75,
- 0x73,0x61,0x62,0x6C,0x65,0x2E,0x00,0x17,0x40,0x58,0x30,0x34,
- 0x30,0x40,0x43,0x30,0x30,0x31,0x50,0x61,0x6E,0x6E,0x69,0x6E,
- 0x67,0x20,0x73,0x6C,0x69,0x64,0x65,0x0B,0x3E,0x40,0x58,0x30,
- 0x36,0x30,0x40,0x43,0x30,0x30,0x32,0x24,0x53,0x79,0x6E,0x74,
- 0x61,0x78,0x3A,0x20,0x50,0x20,0x2B,0x20,0x52,0x69,0x67,0x68,
- 0x74,0x20,0x73,0x70,0x65,0x65,0x64,0x20,0x2B,0x20,0x4C,0x65,
- 0x66,0x74,0x20,0x73,0x70,0x65,0x65,0x64,0x00,0x42,0x54,0x68,
- 0x69,0x73,0x20,0x63,0x6F,0x6D,0x6D,0x61,0x6E,0x64,0x20,0x73,
- 0x6C,0x69,0x64,0x65,0x73,0x20,0x74,0x68,0x65,0x20,0x70,0x61,
- 0x6E,0x6E,0x69,0x6E,0x67,0x20,0x70,0x6F,0x73,0x69,0x74,0x69,
- 0x6F,0x6E,0x2E,0x20,0x49,0x74,0x20,0x77,0x6F,0x72,0x6B,0x73,
- 0x20,0x6C,0x69,0x6B,0x65,0x20,0x74,0x68,0x65,0x20,0x76,0x6F,
- 0x6C,0x75,0x6D,0x65,0x3C,0x73,0x6C,0x69,0x64,0x65,0x2E,0x20,
- 0x4E,0x6F,0x74,0x65,0x20,0x74,0x68,0x61,0x74,0x20,0x73,0x6F,
- 0x6D,0x65,0x20,0x73,0x6F,0x75,0x6E,0x64,0x20,0x63,0x61,0x72,
- 0x64,0x73,0x20,0x6D,0x61,0x79,0x20,0x6E,0x6F,0x74,0x20,0x68,
- 0x61,0x6E,0x64,0x6C,0x65,0x20,0x32,0x35,0x36,0x20,0x70,0x61,
- 0x6E,0x6E,0x69,0x6E,0x67,0x0A,0x70,0x6F,0x73,0x69,0x74,0x69,
- 0x6F,0x6E,0x73,0x2E,0x00,0x16,0x40,0x58,0x30,0x34,0x30,0x40,
- 0x43,0x30,0x30,0x31,0x4D,0x75,0x6C,0x74,0x69,0x20,0x72,0x65,
- 0x74,0x72,0x69,0x67,0x0B,0x3E,0x40,0x58,0x30,0x36,0x30,0x40,
- 0x43,0x30,0x30,0x32,0x24,0x53,0x79,0x6E,0x74,0x61,0x78,0x3A,
- 0x20,0x52,0x20,0x2B,0x20,0x56,0x6F,0x6C,0x75,0x6D,0x65,0x20,
- 0x63,0x68,0x61,0x6E,0x67,0x65,0x20,0x2B,0x20,0x49,0x6E,0x74,
- 0x65,0x72,0x76,0x61,0x6C,0x00,0x32,0x54,0x68,0x69,0x73,0x20,
- 0x69,0x73,0x20,0x61,0x6E,0x20,0x65,0x78,0x74,0x65,0x6E,0x64,
- 0x65,0x64,0x20,0x76,0x65,0x72,0x73,0x69,0x6F,0x6E,0x20,0x6F,
- 0x66,0x20,0x74,0x68,0x65,0x20,0x72,0x65,0x74,0x72,0x69,0x67,
- 0x20,0x63,0x6F,0x6D,0x6D,0x61,0x6E,0x64,0x2E,0x00,0x0E,0x56,
- 0x6F,0x6C,0x75,0x6D,0x65,0x20,0x63,0x68,0x61,0x6E,0x67,0x65,
- 0x3A,0x1F,0x3E,0x40,0x58,0x31,0x30,0x30,0x30,0x20,0x3D,0x20,
- 0x4E,0x6F,0x6E,0x65,0x20,0x20,0x40,0x54,0x33,0x30,0x30,0x38,
- 0x20,0x3D,0x20,0x55,0x6E,0x75,0x73,0x65,0x64,0x16,0x3E,0x31,
- 0x20,0x3D,0x20,0x2D,0x31,0x20,0x20,0x20,0x20,0x40,0x54,0x33,
- 0x30,0x30,0x39,0x20,0x3D,0x20,0x2B,0x31,0x16,0x3E,0x32,0x20,
- 0x3D,0x20,0x2D,0x32,0x20,0x20,0x20,0x20,0x40,0x54,0x33,0x30,
- 0x30,0x41,0x20,0x3D,0x20,0x2B,0x32,0x16,0x3E,0x33,0x20,0x3D,
- 0x20,0x2D,0x34,0x20,0x20,0x20,0x20,0x40,0x54,0x33,0x30,0x30,
- 0x42,0x20,0x3D,0x20,0x2B,0x34,0x16,0x3E,0x34,0x20,0x3D,0x20,
- 0x2D,0x38,0x20,0x20,0x20,0x20,0x40,0x54,0x33,0x30,0x30,0x43,
- 0x20,0x3D,0x20,0x2B,0x38,0x17,0x3E,0x35,0x20,0x3D,0x20,0x2D,
- 0x31,0x36,0x20,0x20,0x20,0x40,0x54,0x33,0x30,0x30,0x44,0x20,
- 0x3D,0x20,0x2B,0x31,0x36,0x18,0x3E,0x36,0x20,0x3D,0x20,0x2A,
- 0x32,0x2F,0x33,0x20,0x20,0x40,0x54,0x33,0x30,0x30,0x45,0x20,
- 0x3D,0x20,0x2A,0x33,0x2F,0x32,0x16,0x3E,0x37,0x20,0x3D,0x20,
- 0x2A,0x31,0x2F,0x32,0x20,0x20,0x40,0x54,0x33,0x30,0x30,0x46,
- 0x20,0x3D,0x20,0x2A,0x32,0x00,0x10,0x40,0x58,0x30,0x34,0x30,
- 0x40,0x43,0x30,0x30,0x31,0x54,0x72,0x65,0x6D,0x6F,0x72,0x0B,
- 0x3E,0x40,0x58,0x30,0x36,0x30,0x40,0x43,0x30,0x30,0x32,0x1E,
- 0x53,0x79,0x6E,0x74,0x61,0x78,0x3A,0x20,0x54,0x20,0x2B,0x20,
- 0x4F,0x6E,0x20,0x74,0x69,0x6D,0x65,0x20,0x2B,0x20,0x4F,0x66,
- 0x66,0x20,0x74,0x69,0x6D,0x65,0x00,0x3E,0x54,0x68,0x69,0x73,
- 0x20,0x77,0x65,0x69,0x72,0x64,0x20,0x63,0x6F,0x6D,0x6D,0x61,
- 0x6E,0x64,0x20,0x77,0x69,0x6C,0x6C,0x20,0x73,0x65,0x74,0x20,
- 0x74,0x68,0x65,0x20,0x76,0x6F,0x6C,0x75,0x6D,0x65,0x20,0x74,
- 0x6F,0x20,0x7A,0x65,0x72,0x6F,0x20,0x64,0x75,0x72,0x69,0x6E,
- 0x67,0x20,0x6F,0x66,0x66,0x20,0x74,0x69,0x6D,0x65,0x36,0x6E,
- 0x75,0x6D,0x62,0x65,0x72,0x20,0x6F,0x66,0x20,0x74,0x69,0x63,
- 0x6B,0x73,0x2E,0x20,0x49,0x74,0x20,0x69,0x73,0x20,0x69,0x6E,
- 0x63,0x6C,0x75,0x64,0x65,0x64,0x20,0x66,0x6F,0x72,0x20,0x53,
- 0x54,0x4D,0x20,0x63,0x6F,0x6D,0x70,0x61,0x74,0x69,0x62,0x69,
- 0x6C,0x69,0x74,0x79,0x2E,0x00,0x27,0x40,0x58,0x30,0x34,0x30,
- 0x40,0x43,0x30,0x30,0x31,0x45,0x78,0x74,0x72,0x61,0x20,0x66,
- 0x69,0x6E,0x65,0x20,0x70,0x6F,0x72,0x74,0x61,0x6D,0x65,0x6E,
- 0x74,0x6F,0x20,0x75,0x70,0x2F,0x64,0x6F,0x77,0x6E,0x0B,0x3E,
- 0x40,0x58,0x30,0x36,0x30,0x40,0x43,0x30,0x30,0x32,0x19,0x53,
- 0x79,0x6E,0x74,0x61,0x78,0x3A,0x20,0x58,0x28,0x31,0x20,0x6F,
- 0x72,0x20,0x32,0x29,0x20,0x2B,0x20,0x53,0x70,0x65,0x65,0x64,
+ 0x21,0x53,0x79,0x6E,0x74,0x61,0x78,0x3A,0x20,0x48,0x20,0x2B,
+ 0x20,0x55,0x70,0x20,0x73,0x70,0x65,0x65,0x64,0x20,0x2B,0x20,
+ 0x44,0x6F,0x77,0x6E,0x20,0x73,0x70,0x65,0x65,0x64,0x00,0x3D,
+ 0x54,0x68,0x69,0x73,0x20,0x63,0x6F,0x6D,0x6D,0x61,0x6E,0x64,
+ 0x20,0x77,0x6F,0x72,0x6B,0x73,0x20,0x65,0x78,0x61,0x63,0x74,
+ 0x6C,0x79,0x20,0x61,0x73,0x20,0x76,0x6F,0x6C,0x75,0x6D,0x65,
+ 0x20,0x73,0x6C,0x69,0x64,0x65,0x2C,0x20,0x62,0x75,0x74,0x20,
+ 0x69,0x74,0x20,0x73,0x6C,0x69,0x64,0x65,0x73,0x20,0x74,0x68,
+ 0x65,0x16,0x67,0x6C,0x6F,0x62,0x61,0x6C,0x20,0x76,0x6F,0x6C,
+ 0x75,0x6D,0x65,0x20,0x69,0x6E,0x73,0x74,0x65,0x61,0x64,0x2E,
+ 0x00,0x11,0x40,0x58,0x30,0x34,0x30,0x40,0x43,0x30,0x30,0x31,
+ 0x4B,0x65,0x79,0x20,0x6F,0x66,0x66,0x0B,0x3E,0x40,0x58,0x30,
+ 0x36,0x30,0x40,0x43,0x30,0x30,0x32,0x10,0x53,0x79,0x6E,0x74,
+ 0x61,0x78,0x3A,0x20,0x4B,0x20,0x2B,0x20,0x54,0x69,0x63,0x6B,
0x00,0x3C,0x54,0x68,0x69,0x73,0x20,0x63,0x6F,0x6D,0x6D,0x61,
- 0x6E,0x64,0x20,0x77,0x6F,0x72,0x6B,0x73,0x20,0x61,0x73,0x20,
- 0x66,0x69,0x6E,0x65,0x20,0x70,0x6F,0x72,0x74,0x61,0x6D,0x65,
- 0x6E,0x74,0x6F,0x20,0x75,0x70,0x2F,0x64,0x6F,0x77,0x6E,0x2C,
- 0x20,0x62,0x75,0x74,0x20,0x74,0x68,0x65,0x20,0x73,0x70,0x65,
- 0x65,0x64,0x18,0x77,0x69,0x6C,0x6C,0x20,0x62,0x65,0x20,0x64,
- 0x69,0x76,0x69,0x64,0x65,0x64,0x20,0x62,0x79,0x20,0x66,0x6F,
- 0x75,0x72,0x2E,0x00,0x03,0x45,0x4E,0x44,0x4C,0x3B,0x2A,0x2A,
+ 0x6E,0x64,0x20,0x77,0x69,0x6C,0x6C,0x20,0x74,0x72,0x69,0x67,
+ 0x67,0x65,0x72,0x20,0x61,0x20,0x22,0x4B,0x65,0x79,0x20,0x6F,
+ 0x66,0x66,0x22,0x20,0x61,0x74,0x20,0x74,0x68,0x65,0x20,0x73,
+ 0x70,0x65,0x63,0x69,0x66,0x69,0x65,0x64,0x20,0x74,0x69,0x63,
+ 0x6B,0x2E,0x00,0x1F,0x40,0x58,0x30,0x34,0x30,0x40,0x43,0x30,
+ 0x30,0x31,0x53,0x65,0x74,0x20,0x65,0x6E,0x76,0x65,0x6C,0x6F,
+ 0x70,0x65,0x20,0x70,0x6F,0x73,0x69,0x74,0x69,0x6F,0x6E,0x0B,
+ 0x3E,0x40,0x58,0x30,0x36,0x30,0x40,0x43,0x30,0x30,0x32,0x14,
+ 0x53,0x79,0x6E,0x74,0x61,0x78,0x3A,0x20,0x4C,0x20,0x2B,0x20,
+ 0x50,0x6F,0x73,0x69,0x74,0x69,0x6F,0x6E,0x00,0x3E,0x43,0x68,
+ 0x61,0x6E,0x67,0x65,0x73,0x20,0x74,0x68,0x65,0x20,0x65,0x6E,
+ 0x76,0x65,0x6C,0x6F,0x70,0x65,0x20,0x70,0x6F,0x73,0x69,0x74,
+ 0x69,0x6F,0x6E,0x2E,0x20,0x4D,0x61,0x67,0x6E,0x75,0x73,0x20,
+ 0x74,0x6F,0x6C,0x64,0x20,0x6D,0x65,0x20,0x74,0x68,0x61,0x74,
+ 0x20,0x69,0x74,0x20,0x77,0x6F,0x75,0x6C,0x64,0x20,0x62,0x65,
+ 0x0C,0x76,0x65,0x72,0x79,0x20,0x75,0x73,0x61,0x62,0x6C,0x65,
+ 0x2E,0x00,0x17,0x40,0x58,0x30,0x34,0x30,0x40,0x43,0x30,0x30,
+ 0x31,0x50,0x61,0x6E,0x6E,0x69,0x6E,0x67,0x20,0x73,0x6C,0x69,
+ 0x64,0x65,0x0B,0x3E,0x40,0x58,0x30,0x36,0x30,0x40,0x43,0x30,
+ 0x30,0x32,0x24,0x53,0x79,0x6E,0x74,0x61,0x78,0x3A,0x20,0x50,
+ 0x20,0x2B,0x20,0x52,0x69,0x67,0x68,0x74,0x20,0x73,0x70,0x65,
+ 0x65,0x64,0x20,0x2B,0x20,0x4C,0x65,0x66,0x74,0x20,0x73,0x70,
+ 0x65,0x65,0x64,0x00,0x42,0x54,0x68,0x69,0x73,0x20,0x63,0x6F,
+ 0x6D,0x6D,0x61,0x6E,0x64,0x20,0x73,0x6C,0x69,0x64,0x65,0x73,
+ 0x20,0x74,0x68,0x65,0x20,0x70,0x61,0x6E,0x6E,0x69,0x6E,0x67,
+ 0x20,0x70,0x6F,0x73,0x69,0x74,0x69,0x6F,0x6E,0x2E,0x20,0x49,
+ 0x74,0x20,0x77,0x6F,0x72,0x6B,0x73,0x20,0x6C,0x69,0x6B,0x65,
+ 0x20,0x74,0x68,0x65,0x20,0x76,0x6F,0x6C,0x75,0x6D,0x65,0x3C,
+ 0x73,0x6C,0x69,0x64,0x65,0x2E,0x20,0x4E,0x6F,0x74,0x65,0x20,
+ 0x74,0x68,0x61,0x74,0x20,0x73,0x6F,0x6D,0x65,0x20,0x73,0x6F,
+ 0x75,0x6E,0x64,0x20,0x63,0x61,0x72,0x64,0x73,0x20,0x6D,0x61,
+ 0x79,0x20,0x6E,0x6F,0x74,0x20,0x68,0x61,0x6E,0x64,0x6C,0x65,
+ 0x20,0x32,0x35,0x36,0x20,0x70,0x61,0x6E,0x6E,0x69,0x6E,0x67,
+ 0x0A,0x70,0x6F,0x73,0x69,0x74,0x69,0x6F,0x6E,0x73,0x2E,0x00,
+ 0x16,0x40,0x58,0x30,0x34,0x30,0x40,0x43,0x30,0x30,0x31,0x4D,
+ 0x75,0x6C,0x74,0x69,0x20,0x72,0x65,0x74,0x72,0x69,0x67,0x0B,
+ 0x3E,0x40,0x58,0x30,0x36,0x30,0x40,0x43,0x30,0x30,0x32,0x24,
+ 0x53,0x79,0x6E,0x74,0x61,0x78,0x3A,0x20,0x52,0x20,0x2B,0x20,
+ 0x56,0x6F,0x6C,0x75,0x6D,0x65,0x20,0x63,0x68,0x61,0x6E,0x67,
+ 0x65,0x20,0x2B,0x20,0x49,0x6E,0x74,0x65,0x72,0x76,0x61,0x6C,
+ 0x00,0x32,0x54,0x68,0x69,0x73,0x20,0x69,0x73,0x20,0x61,0x6E,
+ 0x20,0x65,0x78,0x74,0x65,0x6E,0x64,0x65,0x64,0x20,0x76,0x65,
+ 0x72,0x73,0x69,0x6F,0x6E,0x20,0x6F,0x66,0x20,0x74,0x68,0x65,
+ 0x20,0x72,0x65,0x74,0x72,0x69,0x67,0x20,0x63,0x6F,0x6D,0x6D,
+ 0x61,0x6E,0x64,0x2E,0x00,0x0E,0x56,0x6F,0x6C,0x75,0x6D,0x65,
+ 0x20,0x63,0x68,0x61,0x6E,0x67,0x65,0x3A,0x1F,0x3E,0x40,0x58,
+ 0x31,0x30,0x30,0x30,0x20,0x3D,0x20,0x4E,0x6F,0x6E,0x65,0x20,
+ 0x20,0x40,0x54,0x33,0x30,0x30,0x38,0x20,0x3D,0x20,0x55,0x6E,
+ 0x75,0x73,0x65,0x64,0x16,0x3E,0x31,0x20,0x3D,0x20,0x2D,0x31,
+ 0x20,0x20,0x20,0x20,0x40,0x54,0x33,0x30,0x30,0x39,0x20,0x3D,
+ 0x20,0x2B,0x31,0x16,0x3E,0x32,0x20,0x3D,0x20,0x2D,0x32,0x20,
+ 0x20,0x20,0x20,0x40,0x54,0x33,0x30,0x30,0x41,0x20,0x3D,0x20,
+ 0x2B,0x32,0x16,0x3E,0x33,0x20,0x3D,0x20,0x2D,0x34,0x20,0x20,
+ 0x20,0x20,0x40,0x54,0x33,0x30,0x30,0x42,0x20,0x3D,0x20,0x2B,
+ 0x34,0x16,0x3E,0x34,0x20,0x3D,0x20,0x2D,0x38,0x20,0x20,0x20,
+ 0x20,0x40,0x54,0x33,0x30,0x30,0x43,0x20,0x3D,0x20,0x2B,0x38,
+ 0x17,0x3E,0x35,0x20,0x3D,0x20,0x2D,0x31,0x36,0x20,0x20,0x20,
+ 0x40,0x54,0x33,0x30,0x30,0x44,0x20,0x3D,0x20,0x2B,0x31,0x36,
+ 0x18,0x3E,0x36,0x20,0x3D,0x20,0x2A,0x32,0x2F,0x33,0x20,0x20,
+ 0x40,0x54,0x33,0x30,0x30,0x45,0x20,0x3D,0x20,0x2A,0x33,0x2F,
+ 0x32,0x16,0x3E,0x37,0x20,0x3D,0x20,0x2A,0x31,0x2F,0x32,0x20,
+ 0x20,0x40,0x54,0x33,0x30,0x30,0x46,0x20,0x3D,0x20,0x2A,0x32,
+ 0x00,0x10,0x40,0x58,0x30,0x34,0x30,0x40,0x43,0x30,0x30,0x31,
+ 0x54,0x72,0x65,0x6D,0x6F,0x72,0x0B,0x3E,0x40,0x58,0x30,0x36,
+ 0x30,0x40,0x43,0x30,0x30,0x32,0x1E,0x53,0x79,0x6E,0x74,0x61,
+ 0x78,0x3A,0x20,0x54,0x20,0x2B,0x20,0x4F,0x6E,0x20,0x74,0x69,
+ 0x6D,0x65,0x20,0x2B,0x20,0x4F,0x66,0x66,0x20,0x74,0x69,0x6D,
+ 0x65,0x00,0x3E,0x54,0x68,0x69,0x73,0x20,0x77,0x65,0x69,0x72,
+ 0x64,0x20,0x63,0x6F,0x6D,0x6D,0x61,0x6E,0x64,0x20,0x77,0x69,
+ 0x6C,0x6C,0x20,0x73,0x65,0x74,0x20,0x74,0x68,0x65,0x20,0x76,
+ 0x6F,0x6C,0x75,0x6D,0x65,0x20,0x74,0x6F,0x20,0x7A,0x65,0x72,
+ 0x6F,0x20,0x64,0x75,0x72,0x69,0x6E,0x67,0x20,0x6F,0x66,0x66,
+ 0x20,0x74,0x69,0x6D,0x65,0x36,0x6E,0x75,0x6D,0x62,0x65,0x72,
+ 0x20,0x6F,0x66,0x20,0x74,0x69,0x63,0x6B,0x73,0x2E,0x20,0x49,
+ 0x74,0x20,0x69,0x73,0x20,0x69,0x6E,0x63,0x6C,0x75,0x64,0x65,
+ 0x64,0x20,0x66,0x6F,0x72,0x20,0x53,0x54,0x4D,0x20,0x63,0x6F,
+ 0x6D,0x70,0x61,0x74,0x69,0x62,0x69,0x6C,0x69,0x74,0x79,0x2E,
+ 0x00,0x27,0x40,0x58,0x30,0x34,0x30,0x40,0x43,0x30,0x30,0x31,
+ 0x45,0x78,0x74,0x72,0x61,0x20,0x66,0x69,0x6E,0x65,0x20,0x70,
+ 0x6F,0x72,0x74,0x61,0x6D,0x65,0x6E,0x74,0x6F,0x20,0x75,0x70,
+ 0x2F,0x64,0x6F,0x77,0x6E,0x0B,0x3E,0x40,0x58,0x30,0x36,0x30,
+ 0x40,0x43,0x30,0x30,0x32,0x19,0x53,0x79,0x6E,0x74,0x61,0x78,
+ 0x3A,0x20,0x58,0x28,0x31,0x20,0x6F,0x72,0x20,0x32,0x29,0x20,
+ 0x2B,0x20,0x53,0x70,0x65,0x65,0x64,0x00,0x3C,0x54,0x68,0x69,
+ 0x73,0x20,0x63,0x6F,0x6D,0x6D,0x61,0x6E,0x64,0x20,0x77,0x6F,
+ 0x72,0x6B,0x73,0x20,0x61,0x73,0x20,0x66,0x69,0x6E,0x65,0x20,
+ 0x70,0x6F,0x72,0x74,0x61,0x6D,0x65,0x6E,0x74,0x6F,0x20,0x75,
+ 0x70,0x2F,0x64,0x6F,0x77,0x6E,0x2C,0x20,0x62,0x75,0x74,0x20,
+ 0x74,0x68,0x65,0x20,0x73,0x70,0x65,0x65,0x64,0x18,0x77,0x69,
+ 0x6C,0x6C,0x20,0x62,0x65,0x20,0x64,0x69,0x76,0x69,0x64,0x65,
+ 0x64,0x20,0x62,0x79,0x20,0x66,0x6F,0x75,0x72,0x2E,0x00,0x03,
+ 0x45,0x4E,0x44,0x4C,0x3B,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,
0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,
0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,
0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,
0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,
0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,
+ 0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x4C,0x3B,0x2A,0x2A,
0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,
- 0x2A,0x4C,0x3B,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,
0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,
0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,
0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,
0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,
0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,
- 0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x0A,0x40,0x4C,0x4B,0x65,0x79,
- 0x62,0x6F,0x61,0x72,0x64,0x00,0x0B,0x3E,0x40,0x58,0x30,0x32,
- 0x30,0x40,0x43,0x30,0x30,0x32,0x4A,0x3E,0x49,0x66,0x20,0x79,
- 0x6F,0x75,0x20,0x68,0x61,0x76,0x65,0x20,0x61,0x6E,0x20,0x61,
- 0x6D,0x62,0x69,0x74,0x69,0x6F,0x6E,0x20,0x74,0x6F,0x20,0x63,
- 0x72,0x65,0x61,0x74,0x65,0x20,0x6D,0x75,0x73,0x69,0x63,0x20,
- 0x65,0x66,0x66,0x69,0x63,0x69,0x65,0x6E,0x74,0x6C,0x79,0x20,
- 0x77,0x65,0x20,0x73,0x74,0x72,0x6F,0x6E,0x67,0x6C,0x79,0x20,
- 0x72,0x65,0x63,0x6F,0x6D,0x6D,0x65,0x6E,0x64,0x44,0x74,0x68,
- 0x61,0x74,0x20,0x79,0x6F,0x75,0x20,0x6C,0x65,0x61,0x72,0x6E,
- 0x20,0x41,0x4C,0x4C,0x20,0x74,0x68,0x65,0x20,0x6B,0x65,0x79,
- 0x62,0x6F,0x61,0x72,0x64,0x20,0x66,0x75,0x6E,0x63,0x74,0x69,
- 0x6F,0x6E,0x73,0x2E,0x20,0x4D,0x61,0x6E,0x79,0x20,0x6F,0x66,
- 0x20,0x74,0x68,0x65,0x6D,0x20,0x61,0x72,0x65,0x20,0x74,0x68,
- 0x65,0x20,0x73,0x61,0x6D,0x65,0x45,0x66,0x72,0x6F,0x6D,0x20,
- 0x46,0x61,0x73,0x74,0x74,0x72,0x61,0x63,0x6B,0x65,0x72,0x20,
- 0x31,0x20,0x61,0x6E,0x64,0x20,0x50,0x72,0x6F,0x54,0x72,0x61,
- 0x63,0x6B,0x65,0x72,0x20,0x74,0x6F,0x20,0x65,0x6E,0x73,0x75,
- 0x72,0x65,0x20,0x74,0x68,0x61,0x74,0x20,0x79,0x6F,0x75,0x20,
- 0x66,0x65,0x65,0x6C,0x20,0x63,0x6F,0x6D,0x66,0x6F,0x72,0x74,
- 0x61,0x62,0x6C,0x65,0x2E,0x75,0x73,0x69,0x6E,0x67,0x20,0x74,
- 0x68,0x69,0x73,0x20,0x70,0x72,0x6F,0x67,0x72,0x61,0x6D,0x20,
- 0x66,0x72,0x6F,0x6D,0x20,0x74,0x68,0x65,0x20,0x76,0x65,0x72,
- 0x79,0x20,0x66,0x69,0x72,0x73,0x74,0x20,0x6D,0x69,0x6E,0x75,
- 0x74,0x65,0x2E,0x01,0x3E,0x0B,0x3E,0x40,0x58,0x30,0x32,0x30,
- 0x40,0x43,0x30,0x30,0x31,0x26,0x3E,0x59,0x6F,0x75,0x20,0x73,
- 0x68,0x6F,0x75,0x6C,0x64,0x20,0x62,0x65,0x20,0x61,0x77,0x61,
- 0x72,0x65,0x20,0x6F,0x66,0x20,0x74,0x68,0x65,0x20,0x66,0x61,
- 0x63,0x74,0x20,0x74,0x68,0x61,0x74,0x3A,0x01,0x3E,0x48,0x3E,
- 0x40,0x43,0x30,0x30,0x32,0x54,0x68,0x69,0x73,0x20,0x68,0x65,
- 0x6C,0x70,0x20,0x74,0x65,0x78,0x74,0x20,0x69,0x73,0x20,0x77,
- 0x72,0x69,0x74,0x74,0x65,0x6E,0x20,0x75,0x73,0x69,0x6E,0x67,
- 0x20,0x61,0x20,0x53,0x77,0x65,0x64,0x69,0x73,0x68,0x20,0x6B,
- 0x65,0x79,0x62,0x6F,0x61,0x72,0x64,0x2E,0x20,0x54,0x68,0x65,
- 0x72,0x65,0x66,0x6F,0x72,0x65,0x20,0x73,0x6F,0x6D,0x65,0x2F,
- 0x72,0x65,0x66,0x65,0x72,0x65,0x6E,0x63,0x65,0x73,0x20,0x74,
- 0x6F,0x20,0x6E,0x6F,0x6E,0x2D,0x6F,0x72,0x64,0x69,0x6E,0x61,
- 0x72,0x79,0x20,0x6B,0x65,0x79,0x73,0x20,0x6D,0x69,0x67,0x68,
- 0x74,0x20,0x62,0x65,0x20,0x77,0x72,0x6F,0x6E,0x67,0x2E,0x0F,
- 0x53,0x68,0x20,0x3D,0x20,0x73,0x68,0x69,0x66,0x74,0x20,0x6B,
- 0x65,0x79,0x2E,0x01,0x3E,0x10,0x40,0x58,0x30,0x34,0x30,0x40,
- 0x43,0x30,0x30,0x31,0x56,0x69,0x64,0x65,0x6F,0x3A,0x0B,0x3E,
- 0x40,0x58,0x30,0x36,0x30,0x40,0x43,0x30,0x30,0x32,0x25,0x41,
- 0x6C,0x74,0x2B,0x45,0x6E,0x74,0x65,0x72,0x20,0x40,0x54,0x31,
- 0x36,0x30,0x54,0x6F,0x67,0x67,0x6C,0x65,0x20,0x66,0x75,0x6C,
- 0x6C,0x73,0x63,0x72,0x65,0x65,0x6E,0x20,0x6D,0x6F,0x64,0x65,
- 0x01,0x3E,0x2C,0x3E,0x28,0x4F,0x72,0x20,0x22,0x4C,0x65,0x66,
- 0x74,0x20,0x43,0x74,0x72,0x6C,0x20,0x2B,0x20,0x4C,0x65,0x66,
- 0x74,0x20,0x43,0x6F,0x6D,0x6D,0x61,0x6E,0x64,0x20,0x2B,0x20,
- 0x46,0x22,0x20,0x6F,0x6E,0x20,0x4D,0x61,0x63,0x73,0x29,0x00,
- 0x17,0x40,0x58,0x30,0x34,0x30,0x40,0x43,0x30,0x30,0x31,0x43,
- 0x75,0x72,0x73,0x6F,0x72,0x20,0x6D,0x6F,0x76,0x65,0x73,0x3A,
- 0x0B,0x3E,0x40,0x58,0x30,0x36,0x30,0x40,0x43,0x30,0x30,0x32,
- 0x1D,0x46,0x39,0x2E,0x2E,0x46,0x31,0x32,0x20,0x40,0x54,0x31,
- 0x36,0x30,0x4A,0x75,0x6D,0x70,0x20,0x69,0x6E,0x20,0x70,0x61,
- 0x74,0x74,0x65,0x72,0x6E,0x2E,0x32,0x3E,0x43,0x74,0x72,0x6C,
- 0x2B,0x46,0x39,0x2E,0x2E,0x46,0x31,0x32,0x20,0x40,0x54,0x31,
- 0x36,0x30,0x50,0x61,0x74,0x74,0x65,0x72,0x6E,0x2D,0x70,0x6C,
- 0x61,0x79,0x20,0x66,0x72,0x6F,0x6D,0x20,0x46,0x39,0x2E,0x2E,
- 0x46,0x31,0x32,0x20,0x6C,0x69,0x6E,0x65,0x2E,0x2F,0x3E,0x53,
- 0x68,0x2B,0x46,0x39,0x2E,0x2E,0x46,0x31,0x32,0x20,0x40,0x54,
- 0x31,0x36,0x30,0x53,0x74,0x6F,0x72,0x65,0x20,0x63,0x75,0x72,
- 0x72,0x65,0x6E,0x74,0x20,0x6C,0x69,0x6E,0x65,0x20,0x69,0x6E,
- 0x20,0x46,0x39,0x2E,0x2E,0x46,0x31,0x32,0x2E,0x24,0x3E,0x50,
- 0x61,0x67,0x65,0x55,0x70,0x20,0x20,0x40,0x54,0x31,0x36,0x30,
- 0x4A,0x75,0x6D,0x70,0x20,0x31,0x36,0x2D,0x6C,0x69,0x6E,0x65,
- 0x73,0x20,0x75,0x70,0x77,0x61,0x72,0x64,0x73,0x2E,0x27,0x3E,
- 0x50,0x61,0x67,0x65,0x44,0x6F,0x77,0x6E,0x20,0x40,0x54,0x31,
- 0x36,0x30,0x4A,0x75,0x6D,0x70,0x20,0x31,0x36,0x2D,0x6C,0x69,
- 0x6E,0x65,0x73,0x20,0x64,0x6F,0x77,0x6E,0x77,0x61,0x72,0x64,
- 0x73,0x2E,0x1B,0x3E,0x48,0x6F,0x6D,0x65,0x20,0x20,0x40,0x54,
- 0x31,0x36,0x30,0x4A,0x75,0x6D,0x70,0x20,0x74,0x6F,0x20,0x6C,
- 0x69,0x6E,0x65,0x20,0x30,0x2E,0x1D,0x3E,0x45,0x6E,0x64,0x20,
- 0x20,0x40,0x54,0x31,0x36,0x30,0x4A,0x75,0x6D,0x70,0x20,0x74,
- 0x6F,0x20,0x6C,0x61,0x73,0x74,0x20,0x6C,0x69,0x6E,0x65,0x2E,
- 0x1E,0x3E,0x54,0x61,0x62,0x20,0x20,0x40,0x54,0x31,0x36,0x30,
- 0x4A,0x75,0x6D,0x70,0x20,0x74,0x6F,0x20,0x6E,0x65,0x78,0x74,
- 0x20,0x74,0x72,0x61,0x63,0x6B,0x2E,0x33,0x3E,0x41,0x6C,0x74,
- 0x2B,0x51,0x2E,0x2E,0x49,0x20,0x40,0x54,0x31,0x36,0x30,0x4A,
- 0x75,0x6D,0x70,0x20,0x74,0x6F,0x20,0x74,0x72,0x61,0x63,0x6B,
- 0x20,0x28,0x30,0x2E,0x2E,0x37,0x29,0x20,0x4D,0x4F,0x44,0x20,
- 0x4E,0x2D,0x43,0x68,0x61,0x6E,0x6E,0x65,0x6C,0x73,0x2E,0x34,
- 0x3E,0x41,0x6C,0x74,0x2B,0x41,0x2E,0x2E,0x4B,0x20,0x40,0x54,
- 0x31,0x36,0x30,0x4A,0x75,0x6D,0x70,0x20,0x74,0x6F,0x20,0x74,
- 0x72,0x61,0x63,0x6B,0x20,0x28,0x38,0x2E,0x2E,0x31,0x35,0x29,
- 0x20,0x4D,0x4F,0x44,0x20,0x4E,0x2D,0x43,0x68,0x61,0x6E,0x6E,
- 0x65,0x6C,0x73,0x2E,0x00,0x19,0x40,0x58,0x30,0x34,0x30,0x40,
- 0x43,0x30,0x30,0x31,0x43,0x75,0x74,0x2F,0x43,0x6F,0x70,0x79,
- 0x2F,0x50,0x61,0x73,0x74,0x65,0x3A,0x0B,0x3E,0x40,0x58,0x30,
- 0x36,0x30,0x40,0x43,0x30,0x30,0x32,0x34,0x44,0x65,0x6C,0x65,
- 0x74,0x65,0x20,0x20,0x40,0x54,0x31,0x36,0x30,0x44,0x65,0x6C,
- 0x65,0x74,0x65,0x20,0x6E,0x6F,0x74,0x65,0x20,0x6F,0x72,0x20,
- 0x76,0x6F,0x6C,0x75,0x6D,0x65,0x20,0x63,0x6F,0x6C,0x75,0x6D,
- 0x6E,0x20,0x61,0x74,0x20,0x63,0x75,0x72,0x73,0x6F,0x72,0x2E,
- 0x39,0x3E,0x53,0x68,0x2B,0x44,0x65,0x6C,0x65,0x74,0x65,0x20,
- 0x40,0x54,0x31,0x36,0x30,0x44,0x65,0x6C,0x65,0x74,0x65,0x20,
- 0x6E,0x6F,0x74,0x65,0x2C,0x20,0x76,0x6F,0x6C,0x75,0x6D,0x65,
- 0x20,0x61,0x6E,0x64,0x20,0x65,0x66,0x66,0x65,0x63,0x74,0x20,
- 0x61,0x74,0x20,0x63,0x75,0x72,0x73,0x6F,0x72,0x2E,0x35,0x3E,
- 0x43,0x74,0x72,0x6C,0x2B,0x44,0x65,0x6C,0x65,0x74,0x65,0x20,
- 0x40,0x54,0x31,0x36,0x30,0x44,0x65,0x6C,0x65,0x74,0x65,0x20,
- 0x76,0x6F,0x6C,0x75,0x6D,0x65,0x20,0x61,0x6E,0x64,0x20,0x65,
- 0x66,0x66,0x65,0x63,0x74,0x20,0x61,0x74,0x20,0x63,0x75,0x72,
- 0x73,0x6F,0x72,0x2E,0x29,0x3E,0x41,0x6C,0x74,0x2B,0x44,0x65,
- 0x6C,0x65,0x74,0x65,0x20,0x40,0x54,0x31,0x36,0x30,0x44,0x65,
- 0x6C,0x65,0x74,0x65,0x20,0x65,0x66,0x66,0x65,0x63,0x74,0x20,
- 0x61,0x74,0x20,0x63,0x75,0x72,0x73,0x6F,0x72,0x2E,0x24,0x3E,
- 0x49,0x6E,0x73,0x65,0x72,0x74,0x20,0x20,0x40,0x54,0x31,0x36,
- 0x30,0x49,0x6E,0x73,0x65,0x72,0x74,0x20,0x6E,0x6F,0x74,0x65,
- 0x20,0x61,0x74,0x20,0x63,0x75,0x72,0x73,0x6F,0x72,0x2E,0x27,
- 0x3E,0x53,0x68,0x2B,0x49,0x6E,0x73,0x65,0x72,0x74,0x20,0x20,
- 0x40,0x54,0x31,0x36,0x30,0x49,0x6E,0x73,0x65,0x72,0x74,0x20,
- 0x6C,0x69,0x6E,0x65,0x20,0x61,0x74,0x20,0x63,0x75,0x72,0x73,
- 0x6F,0x72,0x2E,0x25,0x3E,0x42,0x61,0x63,0x6B,0x73,0x70,0x61,
- 0x63,0x65,0x20,0x40,0x54,0x31,0x36,0x30,0x44,0x65,0x6C,0x65,
- 0x74,0x65,0x20,0x70,0x72,0x65,0x76,0x69,0x6F,0x75,0x73,0x20,
- 0x6E,0x6F,0x74,0x65,0x2E,0x28,0x3E,0x53,0x68,0x2B,0x42,0x61,
- 0x63,0x6B,0x73,0x70,0x61,0x63,0x65,0x20,0x40,0x54,0x31,0x36,
- 0x30,0x44,0x65,0x6C,0x65,0x74,0x65,0x20,0x70,0x72,0x65,0x76,
- 0x69,0x6F,0x75,0x73,0x20,0x6C,0x69,0x6E,0x65,0x2E,0x1C,0x3E,
- 0x41,0x6C,0x74,0x2B,0x43,0x75,0x72,0x73,0x6F,0x72,0x20,0x40,
- 0x54,0x31,0x36,0x30,0x4D,0x61,0x72,0x6B,0x20,0x62,0x6C,0x6F,
- 0x63,0x6B,0x2E,0x16,0x3E,0x53,0x68,0x2B,0x46,0x33,0x20,0x40,
- 0x54,0x31,0x36,0x30,0x43,0x75,0x74,0x20,0x74,0x72,0x61,0x63,
- 0x6B,0x2E,0x17,0x3E,0x53,0x68,0x2B,0x46,0x34,0x20,0x40,0x54,
- 0x31,0x36,0x30,0x43,0x6F,0x70,0x79,0x20,0x74,0x72,0x61,0x63,
- 0x6B,0x2E,0x18,0x3E,0x53,0x68,0x2B,0x46,0x35,0x20,0x40,0x54,
- 0x31,0x36,0x30,0x50,0x61,0x73,0x74,0x65,0x20,0x74,0x72,0x61,
- 0x63,0x6B,0x2E,0x1A,0x3E,0x43,0x74,0x72,0x6C,0x2B,0x46,0x33,
- 0x20,0x40,0x54,0x31,0x36,0x30,0x43,0x75,0x74,0x20,0x70,0x61,
- 0x74,0x74,0x65,0x72,0x6E,0x2E,0x1B,0x3E,0x43,0x74,0x72,0x6C,
- 0x2B,0x46,0x34,0x20,0x40,0x54,0x31,0x36,0x30,0x43,0x6F,0x70,
- 0x79,0x20,0x70,0x61,0x74,0x74,0x65,0x72,0x6E,0x2E,0x1C,0x3E,
- 0x43,0x74,0x72,0x6C,0x2B,0x46,0x35,0x20,0x40,0x54,0x31,0x36,
- 0x30,0x50,0x61,0x73,0x74,0x65,0x20,0x70,0x61,0x74,0x74,0x65,
- 0x72,0x6E,0x2E,0x17,0x3E,0x41,0x6C,0x74,0x2B,0x46,0x33,0x20,
- 0x40,0x54,0x31,0x36,0x30,0x43,0x75,0x74,0x20,0x62,0x6C,0x6F,
- 0x63,0x6B,0x2E,0x18,0x3E,0x41,0x6C,0x74,0x2B,0x46,0x34,0x20,
- 0x40,0x54,0x31,0x36,0x30,0x43,0x6F,0x70,0x79,0x20,0x62,0x6C,
- 0x6F,0x63,0x6B,0x2E,0x19,0x3E,0x41,0x6C,0x74,0x2B,0x46,0x35,
- 0x20,0x40,0x54,0x31,0x36,0x30,0x50,0x61,0x73,0x74,0x65,0x20,
- 0x62,0x6C,0x6F,0x63,0x6B,0x2E,0x20,0x3E,0x41,0x6C,0x74,0x2B,
- 0x43,0x20,0x20,0x40,0x54,0x31,0x36,0x30,0x4D,0x61,0x72,0x6B,
- 0x20,0x63,0x75,0x72,0x72,0x65,0x6E,0x74,0x20,0x74,0x72,0x61,
- 0x63,0x6B,0x2E,0x00,0x18,0x40,0x58,0x30,0x34,0x30,0x40,0x43,
- 0x30,0x30,0x31,0x4D,0x69,0x73,0x63,0x65,0x6C,0x6C,0x61,0x6E,
- 0x65,0x6F,0x75,0x73,0x3A,0x0B,0x3E,0x40,0x58,0x30,0x36,0x30,
- 0x40,0x43,0x30,0x30,0x32,0x1C,0x52,0x69,0x67,0x68,0x74,0x20,
- 0x63,0x74,0x72,0x6C,0x2E,0x20,0x20,0x40,0x54,0x31,0x36,0x30,
- 0x50,0x6C,0x61,0x79,0x20,0x73,0x6F,0x6E,0x67,0x2E,0x1D,0x3E,
- 0x41,0x6C,0x74,0x20,0x47,0x72,0x20,0x20,0x20,0x20,0x40,0x54,
- 0x31,0x36,0x30,0x50,0x6C,0x61,0x79,0x20,0x70,0x61,0x74,0x74,
- 0x65,0x72,0x6E,0x2E,0x22,0x3E,0x52,0x69,0x67,0x68,0x74,0x20,
- 0x73,0x68,0x69,0x66,0x74,0x20,0x20,0x40,0x54,0x31,0x36,0x30,
- 0x52,0x65,0x63,0x6F,0x72,0x64,0x20,0x70,0x61,0x74,0x74,0x65,
- 0x72,0x6E,0x2E,0x19,0x3E,0x53,0x70,0x61,0x63,0x65,0x20,0x20,
- 0x20,0x20,0x40,0x54,0x31,0x36,0x30,0x53,0x74,0x6F,0x70,0x2F,
- 0x45,0x64,0x69,0x74,0x2E,0x1B,0x3E,0x46,0x31,0x2E,0x2E,0x46,
- 0x37,0x20,0x40,0x54,0x31,0x36,0x30,0x53,0x65,0x6C,0x65,0x63,
- 0x74,0x20,0x6F,0x63,0x74,0x61,0x76,0x65,0x2E,0x27,0x3E,0x4B,
- 0x65,0x79,0x20,0x62,0x65,0x6C,0x6F,0x77,0x20,0x45,0x73,0x63,
+ 0x2A,0x0D,0x40,0x4C,0x4B,0x65,0x79,0x62,0x69,0x6E,0x64,0x69,
+ 0x6E,0x67,0x73,0x00,0x0B,0x3E,0x40,0x58,0x30,0x32,0x30,0x40,
+ 0x43,0x30,0x30,0x32,0x4A,0x3E,0x49,0x66,0x20,0x79,0x6F,0x75,
+ 0x20,0x68,0x61,0x76,0x65,0x20,0x61,0x6E,0x20,0x61,0x6D,0x62,
+ 0x69,0x74,0x69,0x6F,0x6E,0x20,0x74,0x6F,0x20,0x63,0x72,0x65,
+ 0x61,0x74,0x65,0x20,0x6D,0x75,0x73,0x69,0x63,0x20,0x65,0x66,
+ 0x66,0x69,0x63,0x69,0x65,0x6E,0x74,0x6C,0x79,0x20,0x77,0x65,
+ 0x20,0x73,0x74,0x72,0x6F,0x6E,0x67,0x6C,0x79,0x20,0x72,0x65,
+ 0x63,0x6F,0x6D,0x6D,0x65,0x6E,0x64,0x44,0x74,0x68,0x61,0x74,
+ 0x20,0x79,0x6F,0x75,0x20,0x6C,0x65,0x61,0x72,0x6E,0x20,0x41,
+ 0x4C,0x4C,0x20,0x74,0x68,0x65,0x20,0x6B,0x65,0x79,0x62,0x6F,
+ 0x61,0x72,0x64,0x20,0x66,0x75,0x6E,0x63,0x74,0x69,0x6F,0x6E,
+ 0x73,0x2E,0x20,0x4D,0x61,0x6E,0x79,0x20,0x6F,0x66,0x20,0x74,
+ 0x68,0x65,0x6D,0x20,0x61,0x72,0x65,0x20,0x74,0x68,0x65,0x20,
+ 0x73,0x61,0x6D,0x65,0x45,0x66,0x72,0x6F,0x6D,0x20,0x46,0x61,
+ 0x73,0x74,0x74,0x72,0x61,0x63,0x6B,0x65,0x72,0x20,0x31,0x20,
+ 0x61,0x6E,0x64,0x20,0x50,0x72,0x6F,0x54,0x72,0x61,0x63,0x6B,
+ 0x65,0x72,0x20,0x74,0x6F,0x20,0x65,0x6E,0x73,0x75,0x72,0x65,
+ 0x20,0x74,0x68,0x61,0x74,0x20,0x79,0x6F,0x75,0x20,0x66,0x65,
+ 0x65,0x6C,0x20,0x63,0x6F,0x6D,0x66,0x6F,0x72,0x74,0x61,0x62,
+ 0x6C,0x65,0x2E,0x75,0x73,0x69,0x6E,0x67,0x20,0x74,0x68,0x69,
+ 0x73,0x20,0x70,0x72,0x6F,0x67,0x72,0x61,0x6D,0x20,0x66,0x72,
+ 0x6F,0x6D,0x20,0x74,0x68,0x65,0x20,0x76,0x65,0x72,0x79,0x20,
+ 0x66,0x69,0x72,0x73,0x74,0x20,0x6D,0x69,0x6E,0x75,0x74,0x65,
+ 0x2E,0x01,0x3E,0x0B,0x3E,0x40,0x58,0x30,0x32,0x30,0x40,0x43,
+ 0x30,0x30,0x31,0x26,0x3E,0x59,0x6F,0x75,0x20,0x73,0x68,0x6F,
+ 0x75,0x6C,0x64,0x20,0x62,0x65,0x20,0x61,0x77,0x61,0x72,0x65,
+ 0x20,0x6F,0x66,0x20,0x74,0x68,0x65,0x20,0x66,0x61,0x63,0x74,
+ 0x20,0x74,0x68,0x61,0x74,0x3A,0x01,0x3E,0x48,0x3E,0x40,0x43,
+ 0x30,0x30,0x32,0x54,0x68,0x69,0x73,0x20,0x68,0x65,0x6C,0x70,
+ 0x20,0x74,0x65,0x78,0x74,0x20,0x69,0x73,0x20,0x77,0x72,0x69,
+ 0x74,0x74,0x65,0x6E,0x20,0x75,0x73,0x69,0x6E,0x67,0x20,0x61,
+ 0x20,0x53,0x77,0x65,0x64,0x69,0x73,0x68,0x20,0x6B,0x65,0x79,
+ 0x62,0x6F,0x61,0x72,0x64,0x2E,0x20,0x54,0x68,0x65,0x72,0x65,
+ 0x66,0x6F,0x72,0x65,0x20,0x73,0x6F,0x6D,0x65,0x2F,0x72,0x65,
+ 0x66,0x65,0x72,0x65,0x6E,0x63,0x65,0x73,0x20,0x74,0x6F,0x20,
+ 0x6E,0x6F,0x6E,0x2D,0x6F,0x72,0x64,0x69,0x6E,0x61,0x72,0x79,
+ 0x20,0x6B,0x65,0x79,0x73,0x20,0x6D,0x69,0x67,0x68,0x74,0x20,
+ 0x62,0x65,0x20,0x77,0x72,0x6F,0x6E,0x67,0x2E,0x0F,0x53,0x68,
+ 0x20,0x3D,0x20,0x73,0x68,0x69,0x66,0x74,0x20,0x6B,0x65,0x79,
+ 0x2E,0x01,0x3E,0x10,0x40,0x58,0x30,0x34,0x30,0x40,0x43,0x30,
+ 0x30,0x31,0x41,0x75,0x64,0x69,0x6F,0x3A,0x0B,0x3E,0x40,0x58,
+ 0x30,0x36,0x30,0x40,0x43,0x30,0x30,0x32,0x32,0x3E,0x43,0x74,
+ 0x72,0x6C,0x20,0x26,0x20,0x6E,0x75,0x6D,0x70,0x61,0x64,0x2B,
0x20,0x40,0x54,0x31,0x36,0x30,0x49,0x6E,0x63,0x72,0x65,0x61,
- 0x73,0x65,0x20,0x63,0x75,0x72,0x73,0x6F,0x72,0x61,0x64,0x64,
- 0x2E,0x22,0x3E,0x53,0x68,0x2B,0x28,0x31,0x2F,0x32,0x29,0x20,
- 0x40,0x54,0x31,0x36,0x30,0x44,0x65,0x63,0x72,0x65,0x61,0x73,
- 0x65,0x20,0x63,0x75,0x72,0x73,0x6F,0x72,0x61,0x64,0x64,0x2E,
- 0x29,0x3E,0x43,0x61,0x70,0x73,0x4C,0x6F,0x63,0x6B,0x20,0x6F,
- 0x72,0x20,0x3C,0x3E,0x20,0x40,0x54,0x31,0x36,0x30,0x45,0x6E,
- 0x74,0x65,0x72,0x20,0x4B,0x65,0x79,0x6F,0x66,0x66,0x2D,0x22,
- 0x6E,0x6F,0x74,0x65,0x22,0x2E,0x25,0x3E,0x53,0x68,0x2B,0x4C,
- 0x65,0x66,0x74,0x20,0x40,0x54,0x31,0x36,0x30,0x49,0x6E,0x63,
- 0x72,0x65,0x61,0x73,0x65,0x20,0x73,0x6F,0x6E,0x67,0x20,0x70,
- 0x6F,0x73,0x69,0x74,0x69,0x6F,0x6E,0x2E,0x26,0x3E,0x53,0x68,
- 0x2B,0x52,0x69,0x67,0x68,0x74,0x20,0x40,0x54,0x31,0x36,0x30,
- 0x44,0x65,0x63,0x72,0x65,0x61,0x73,0x65,0x20,0x73,0x6F,0x6E,
- 0x67,0x20,0x70,0x6F,0x73,0x69,0x74,0x69,0x6F,0x6E,0x2E,0x28,
- 0x3E,0x43,0x74,0x72,0x6C,0x2B,0x4C,0x65,0x66,0x74,0x20,0x40,
+ 0x73,0x65,0x20,0x6D,0x61,0x73,0x74,0x65,0x72,0x20,0x76,0x6F,
+ 0x6C,0x75,0x6D,0x65,0x20,0x62,0x79,0x20,0x31,0x36,0x2E,0x32,
+ 0x3E,0x43,0x74,0x72,0x6C,0x20,0x26,0x20,0x6E,0x75,0x6D,0x70,
+ 0x61,0x64,0x2D,0x20,0x40,0x54,0x31,0x36,0x30,0x44,0x65,0x63,
+ 0x72,0x65,0x61,0x73,0x65,0x20,0x6D,0x61,0x73,0x74,0x65,0x72,
+ 0x20,0x76,0x6F,0x6C,0x75,0x6D,0x65,0x20,0x62,0x79,0x20,0x31,
+ 0x36,0x2E,0x00,0x10,0x40,0x58,0x30,0x34,0x30,0x40,0x43,0x30,
+ 0x30,0x31,0x56,0x69,0x64,0x65,0x6F,0x3A,0x0B,0x3E,0x40,0x58,
+ 0x30,0x36,0x30,0x40,0x43,0x30,0x30,0x32,0x25,0x41,0x6C,0x74,
+ 0x2B,0x45,0x6E,0x74,0x65,0x72,0x20,0x40,0x54,0x31,0x36,0x30,
+ 0x54,0x6F,0x67,0x67,0x6C,0x65,0x20,0x66,0x75,0x6C,0x6C,0x73,
+ 0x63,0x72,0x65,0x65,0x6E,0x20,0x6D,0x6F,0x64,0x65,0x01,0x3E,
+ 0x2C,0x3E,0x28,0x4F,0x72,0x20,0x22,0x4C,0x65,0x66,0x74,0x20,
+ 0x43,0x74,0x72,0x6C,0x20,0x2B,0x20,0x4C,0x65,0x66,0x74,0x20,
+ 0x43,0x6F,0x6D,0x6D,0x61,0x6E,0x64,0x20,0x2B,0x20,0x46,0x22,
+ 0x20,0x6F,0x6E,0x20,0x4D,0x61,0x63,0x73,0x29,0x00,0x17,0x40,
+ 0x58,0x30,0x34,0x30,0x40,0x43,0x30,0x30,0x31,0x43,0x75,0x72,
+ 0x73,0x6F,0x72,0x20,0x6D,0x6F,0x76,0x65,0x73,0x3A,0x0B,0x3E,
+ 0x40,0x58,0x30,0x36,0x30,0x40,0x43,0x30,0x30,0x32,0x1D,0x46,
+ 0x39,0x2E,0x2E,0x46,0x31,0x32,0x20,0x40,0x54,0x31,0x36,0x30,
+ 0x4A,0x75,0x6D,0x70,0x20,0x69,0x6E,0x20,0x70,0x61,0x74,0x74,
+ 0x65,0x72,0x6E,0x2E,0x32,0x3E,0x43,0x74,0x72,0x6C,0x2B,0x46,
+ 0x39,0x2E,0x2E,0x46,0x31,0x32,0x20,0x40,0x54,0x31,0x36,0x30,
+ 0x50,0x61,0x74,0x74,0x65,0x72,0x6E,0x2D,0x70,0x6C,0x61,0x79,
+ 0x20,0x66,0x72,0x6F,0x6D,0x20,0x46,0x39,0x2E,0x2E,0x46,0x31,
+ 0x32,0x20,0x6C,0x69,0x6E,0x65,0x2E,0x2F,0x3E,0x53,0x68,0x2B,
+ 0x46,0x39,0x2E,0x2E,0x46,0x31,0x32,0x20,0x40,0x54,0x31,0x36,
+ 0x30,0x53,0x74,0x6F,0x72,0x65,0x20,0x63,0x75,0x72,0x72,0x65,
+ 0x6E,0x74,0x20,0x6C,0x69,0x6E,0x65,0x20,0x69,0x6E,0x20,0x46,
+ 0x39,0x2E,0x2E,0x46,0x31,0x32,0x2E,0x24,0x3E,0x50,0x61,0x67,
+ 0x65,0x55,0x70,0x20,0x20,0x40,0x54,0x31,0x36,0x30,0x4A,0x75,
+ 0x6D,0x70,0x20,0x31,0x36,0x2D,0x6C,0x69,0x6E,0x65,0x73,0x20,
+ 0x75,0x70,0x77,0x61,0x72,0x64,0x73,0x2E,0x27,0x3E,0x50,0x61,
+ 0x67,0x65,0x44,0x6F,0x77,0x6E,0x20,0x40,0x54,0x31,0x36,0x30,
+ 0x4A,0x75,0x6D,0x70,0x20,0x31,0x36,0x2D,0x6C,0x69,0x6E,0x65,
+ 0x73,0x20,0x64,0x6F,0x77,0x6E,0x77,0x61,0x72,0x64,0x73,0x2E,
+ 0x1B,0x3E,0x48,0x6F,0x6D,0x65,0x20,0x20,0x40,0x54,0x31,0x36,
+ 0x30,0x4A,0x75,0x6D,0x70,0x20,0x74,0x6F,0x20,0x6C,0x69,0x6E,
+ 0x65,0x20,0x30,0x2E,0x1D,0x3E,0x45,0x6E,0x64,0x20,0x20,0x40,
+ 0x54,0x31,0x36,0x30,0x4A,0x75,0x6D,0x70,0x20,0x74,0x6F,0x20,
+ 0x6C,0x61,0x73,0x74,0x20,0x6C,0x69,0x6E,0x65,0x2E,0x1E,0x3E,
+ 0x54,0x61,0x62,0x20,0x20,0x40,0x54,0x31,0x36,0x30,0x4A,0x75,
+ 0x6D,0x70,0x20,0x74,0x6F,0x20,0x6E,0x65,0x78,0x74,0x20,0x74,
+ 0x72,0x61,0x63,0x6B,0x2E,0x33,0x3E,0x41,0x6C,0x74,0x2B,0x51,
+ 0x2E,0x2E,0x49,0x20,0x40,0x54,0x31,0x36,0x30,0x4A,0x75,0x6D,
+ 0x70,0x20,0x74,0x6F,0x20,0x74,0x72,0x61,0x63,0x6B,0x20,0x28,
+ 0x30,0x2E,0x2E,0x37,0x29,0x20,0x4D,0x4F,0x44,0x20,0x4E,0x2D,
+ 0x43,0x68,0x61,0x6E,0x6E,0x65,0x6C,0x73,0x2E,0x34,0x3E,0x41,
+ 0x6C,0x74,0x2B,0x41,0x2E,0x2E,0x4B,0x20,0x40,0x54,0x31,0x36,
+ 0x30,0x4A,0x75,0x6D,0x70,0x20,0x74,0x6F,0x20,0x74,0x72,0x61,
+ 0x63,0x6B,0x20,0x28,0x38,0x2E,0x2E,0x31,0x35,0x29,0x20,0x4D,
+ 0x4F,0x44,0x20,0x4E,0x2D,0x43,0x68,0x61,0x6E,0x6E,0x65,0x6C,
+ 0x73,0x2E,0x00,0x19,0x40,0x58,0x30,0x34,0x30,0x40,0x43,0x30,
+ 0x30,0x31,0x43,0x75,0x74,0x2F,0x43,0x6F,0x70,0x79,0x2F,0x50,
+ 0x61,0x73,0x74,0x65,0x3A,0x0B,0x3E,0x40,0x58,0x30,0x36,0x30,
+ 0x40,0x43,0x30,0x30,0x32,0x34,0x44,0x65,0x6C,0x65,0x74,0x65,
+ 0x20,0x20,0x40,0x54,0x31,0x36,0x30,0x44,0x65,0x6C,0x65,0x74,
+ 0x65,0x20,0x6E,0x6F,0x74,0x65,0x20,0x6F,0x72,0x20,0x76,0x6F,
+ 0x6C,0x75,0x6D,0x65,0x20,0x63,0x6F,0x6C,0x75,0x6D,0x6E,0x20,
+ 0x61,0x74,0x20,0x63,0x75,0x72,0x73,0x6F,0x72,0x2E,0x39,0x3E,
+ 0x53,0x68,0x2B,0x44,0x65,0x6C,0x65,0x74,0x65,0x20,0x40,0x54,
+ 0x31,0x36,0x30,0x44,0x65,0x6C,0x65,0x74,0x65,0x20,0x6E,0x6F,
+ 0x74,0x65,0x2C,0x20,0x76,0x6F,0x6C,0x75,0x6D,0x65,0x20,0x61,
+ 0x6E,0x64,0x20,0x65,0x66,0x66,0x65,0x63,0x74,0x20,0x61,0x74,
+ 0x20,0x63,0x75,0x72,0x73,0x6F,0x72,0x2E,0x35,0x3E,0x43,0x74,
+ 0x72,0x6C,0x2B,0x44,0x65,0x6C,0x65,0x74,0x65,0x20,0x40,0x54,
+ 0x31,0x36,0x30,0x44,0x65,0x6C,0x65,0x74,0x65,0x20,0x76,0x6F,
+ 0x6C,0x75,0x6D,0x65,0x20,0x61,0x6E,0x64,0x20,0x65,0x66,0x66,
+ 0x65,0x63,0x74,0x20,0x61,0x74,0x20,0x63,0x75,0x72,0x73,0x6F,
+ 0x72,0x2E,0x29,0x3E,0x41,0x6C,0x74,0x2B,0x44,0x65,0x6C,0x65,
+ 0x74,0x65,0x20,0x40,0x54,0x31,0x36,0x30,0x44,0x65,0x6C,0x65,
+ 0x74,0x65,0x20,0x65,0x66,0x66,0x65,0x63,0x74,0x20,0x61,0x74,
+ 0x20,0x63,0x75,0x72,0x73,0x6F,0x72,0x2E,0x24,0x3E,0x49,0x6E,
+ 0x73,0x65,0x72,0x74,0x20,0x20,0x40,0x54,0x31,0x36,0x30,0x49,
+ 0x6E,0x73,0x65,0x72,0x74,0x20,0x6E,0x6F,0x74,0x65,0x20,0x61,
+ 0x74,0x20,0x63,0x75,0x72,0x73,0x6F,0x72,0x2E,0x27,0x3E,0x53,
+ 0x68,0x2B,0x49,0x6E,0x73,0x65,0x72,0x74,0x20,0x20,0x40,0x54,
+ 0x31,0x36,0x30,0x49,0x6E,0x73,0x65,0x72,0x74,0x20,0x6C,0x69,
+ 0x6E,0x65,0x20,0x61,0x74,0x20,0x63,0x75,0x72,0x73,0x6F,0x72,
+ 0x2E,0x25,0x3E,0x42,0x61,0x63,0x6B,0x73,0x70,0x61,0x63,0x65,
+ 0x20,0x40,0x54,0x31,0x36,0x30,0x44,0x65,0x6C,0x65,0x74,0x65,
+ 0x20,0x70,0x72,0x65,0x76,0x69,0x6F,0x75,0x73,0x20,0x6E,0x6F,
+ 0x74,0x65,0x2E,0x28,0x3E,0x53,0x68,0x2B,0x42,0x61,0x63,0x6B,
+ 0x73,0x70,0x61,0x63,0x65,0x20,0x40,0x54,0x31,0x36,0x30,0x44,
+ 0x65,0x6C,0x65,0x74,0x65,0x20,0x70,0x72,0x65,0x76,0x69,0x6F,
+ 0x75,0x73,0x20,0x6C,0x69,0x6E,0x65,0x2E,0x1C,0x3E,0x41,0x6C,
+ 0x74,0x2B,0x43,0x75,0x72,0x73,0x6F,0x72,0x20,0x40,0x54,0x31,
+ 0x36,0x30,0x4D,0x61,0x72,0x6B,0x20,0x62,0x6C,0x6F,0x63,0x6B,
+ 0x2E,0x16,0x3E,0x53,0x68,0x2B,0x46,0x33,0x20,0x40,0x54,0x31,
+ 0x36,0x30,0x43,0x75,0x74,0x20,0x74,0x72,0x61,0x63,0x6B,0x2E,
+ 0x17,0x3E,0x53,0x68,0x2B,0x46,0x34,0x20,0x40,0x54,0x31,0x36,
+ 0x30,0x43,0x6F,0x70,0x79,0x20,0x74,0x72,0x61,0x63,0x6B,0x2E,
+ 0x18,0x3E,0x53,0x68,0x2B,0x46,0x35,0x20,0x40,0x54,0x31,0x36,
+ 0x30,0x50,0x61,0x73,0x74,0x65,0x20,0x74,0x72,0x61,0x63,0x6B,
+ 0x2E,0x1A,0x3E,0x43,0x74,0x72,0x6C,0x2B,0x46,0x33,0x20,0x40,
+ 0x54,0x31,0x36,0x30,0x43,0x75,0x74,0x20,0x70,0x61,0x74,0x74,
+ 0x65,0x72,0x6E,0x2E,0x1B,0x3E,0x43,0x74,0x72,0x6C,0x2B,0x46,
+ 0x34,0x20,0x40,0x54,0x31,0x36,0x30,0x43,0x6F,0x70,0x79,0x20,
+ 0x70,0x61,0x74,0x74,0x65,0x72,0x6E,0x2E,0x1C,0x3E,0x43,0x74,
+ 0x72,0x6C,0x2B,0x46,0x35,0x20,0x40,0x54,0x31,0x36,0x30,0x50,
+ 0x61,0x73,0x74,0x65,0x20,0x70,0x61,0x74,0x74,0x65,0x72,0x6E,
+ 0x2E,0x17,0x3E,0x41,0x6C,0x74,0x2B,0x46,0x33,0x20,0x40,0x54,
+ 0x31,0x36,0x30,0x43,0x75,0x74,0x20,0x62,0x6C,0x6F,0x63,0x6B,
+ 0x2E,0x18,0x3E,0x41,0x6C,0x74,0x2B,0x46,0x34,0x20,0x40,0x54,
+ 0x31,0x36,0x30,0x43,0x6F,0x70,0x79,0x20,0x62,0x6C,0x6F,0x63,
+ 0x6B,0x2E,0x19,0x3E,0x41,0x6C,0x74,0x2B,0x46,0x35,0x20,0x40,
+ 0x54,0x31,0x36,0x30,0x50,0x61,0x73,0x74,0x65,0x20,0x62,0x6C,
+ 0x6F,0x63,0x6B,0x2E,0x20,0x3E,0x41,0x6C,0x74,0x2B,0x43,0x20,
+ 0x20,0x40,0x54,0x31,0x36,0x30,0x4D,0x61,0x72,0x6B,0x20,0x63,
+ 0x75,0x72,0x72,0x65,0x6E,0x74,0x20,0x74,0x72,0x61,0x63,0x6B,
+ 0x2E,0x00,0x18,0x40,0x58,0x30,0x34,0x30,0x40,0x43,0x30,0x30,
+ 0x31,0x4D,0x69,0x73,0x63,0x65,0x6C,0x6C,0x61,0x6E,0x65,0x6F,
+ 0x75,0x73,0x3A,0x0B,0x3E,0x40,0x58,0x30,0x36,0x30,0x40,0x43,
+ 0x30,0x30,0x32,0x1C,0x52,0x69,0x67,0x68,0x74,0x20,0x63,0x74,
+ 0x72,0x6C,0x2E,0x20,0x20,0x40,0x54,0x31,0x36,0x30,0x50,0x6C,
+ 0x61,0x79,0x20,0x73,0x6F,0x6E,0x67,0x2E,0x1D,0x3E,0x41,0x6C,
+ 0x74,0x20,0x47,0x72,0x20,0x20,0x20,0x20,0x40,0x54,0x31,0x36,
+ 0x30,0x50,0x6C,0x61,0x79,0x20,0x70,0x61,0x74,0x74,0x65,0x72,
+ 0x6E,0x2E,0x22,0x3E,0x52,0x69,0x67,0x68,0x74,0x20,0x73,0x68,
+ 0x69,0x66,0x74,0x20,0x20,0x40,0x54,0x31,0x36,0x30,0x52,0x65,
+ 0x63,0x6F,0x72,0x64,0x20,0x70,0x61,0x74,0x74,0x65,0x72,0x6E,
+ 0x2E,0x19,0x3E,0x53,0x70,0x61,0x63,0x65,0x20,0x20,0x20,0x20,
+ 0x40,0x54,0x31,0x36,0x30,0x53,0x74,0x6F,0x70,0x2F,0x45,0x64,
+ 0x69,0x74,0x2E,0x1B,0x3E,0x46,0x31,0x2E,0x2E,0x46,0x37,0x20,
+ 0x40,0x54,0x31,0x36,0x30,0x53,0x65,0x6C,0x65,0x63,0x74,0x20,
+ 0x6F,0x63,0x74,0x61,0x76,0x65,0x2E,0x27,0x3E,0x4B,0x65,0x79,
+ 0x20,0x62,0x65,0x6C,0x6F,0x77,0x20,0x45,0x73,0x63,0x20,0x40,
0x54,0x31,0x36,0x30,0x49,0x6E,0x63,0x72,0x65,0x61,0x73,0x65,
- 0x20,0x70,0x61,0x74,0x74,0x65,0x72,0x6E,0x20,0x6E,0x75,0x6D,
- 0x62,0x65,0x72,0x2E,0x29,0x3E,0x43,0x74,0x72,0x6C,0x2B,0x52,
+ 0x20,0x63,0x75,0x72,0x73,0x6F,0x72,0x61,0x64,0x64,0x2E,0x22,
+ 0x3E,0x53,0x68,0x2B,0x28,0x31,0x2F,0x32,0x29,0x20,0x40,0x54,
+ 0x31,0x36,0x30,0x44,0x65,0x63,0x72,0x65,0x61,0x73,0x65,0x20,
+ 0x63,0x75,0x72,0x73,0x6F,0x72,0x61,0x64,0x64,0x2E,0x29,0x3E,
+ 0x43,0x61,0x70,0x73,0x4C,0x6F,0x63,0x6B,0x20,0x6F,0x72,0x20,
+ 0x3C,0x3E,0x20,0x40,0x54,0x31,0x36,0x30,0x45,0x6E,0x74,0x65,
+ 0x72,0x20,0x4B,0x65,0x79,0x6F,0x66,0x66,0x2D,0x22,0x6E,0x6F,
+ 0x74,0x65,0x22,0x2E,0x25,0x3E,0x53,0x68,0x2B,0x4C,0x65,0x66,
+ 0x74,0x20,0x40,0x54,0x31,0x36,0x30,0x49,0x6E,0x63,0x72,0x65,
+ 0x61,0x73,0x65,0x20,0x73,0x6F,0x6E,0x67,0x20,0x70,0x6F,0x73,
+ 0x69,0x74,0x69,0x6F,0x6E,0x2E,0x26,0x3E,0x53,0x68,0x2B,0x52,
0x69,0x67,0x68,0x74,0x20,0x40,0x54,0x31,0x36,0x30,0x44,0x65,
- 0x63,0x72,0x65,0x61,0x73,0x65,0x20,0x70,0x61,0x74,0x74,0x65,
- 0x72,0x6E,0x20,0x6E,0x75,0x6D,0x62,0x65,0x72,0x2E,0x00,0x2C,
- 0x40,0x58,0x30,0x34,0x30,0x40,0x43,0x30,0x30,0x31,0x4D,0x69,
- 0x73,0x63,0x65,0x6C,0x6C,0x61,0x6E,0x65,0x6F,0x75,0x73,0x20,
- 0x28,0x6F,0x6E,0x20,0x61,0x20,0x4D,0x61,0x63,0x20,0x6B,0x65,
- 0x79,0x62,0x6F,0x61,0x72,0x64,0x29,0x3A,0x0B,0x3E,0x40,0x58,
- 0x30,0x36,0x30,0x40,0x43,0x30,0x30,0x32,0x1E,0x52,0x69,0x67,
- 0x68,0x74,0x20,0x63,0x6F,0x6D,0x6D,0x61,0x6E,0x64,0x20,0x20,
- 0x40,0x54,0x32,0x34,0x30,0x50,0x6C,0x61,0x79,0x20,0x73,0x6F,
- 0x6E,0x67,0x2E,0x32,0x3E,0x52,0x69,0x67,0x68,0x74,0x20,0x61,
- 0x6C,0x74,0x20,0x28,0x6F,0x72,0x20,0x6C,0x65,0x66,0x74,0x20,
- 0x63,0x6F,0x6D,0x6D,0x61,0x6E,0x64,0x29,0x20,0x20,0x20,0x20,
- 0x40,0x54,0x32,0x34,0x30,0x50,0x6C,0x61,0x79,0x20,0x70,0x61,
- 0x74,0x74,0x65,0x72,0x6E,0x2E,0x22,0x3E,0x52,0x69,0x67,0x68,
- 0x74,0x20,0x73,0x68,0x69,0x66,0x74,0x20,0x20,0x40,0x54,0x32,
- 0x34,0x30,0x52,0x65,0x63,0x6F,0x72,0x64,0x20,0x70,0x61,0x74,
- 0x74,0x65,0x72,0x6E,0x2E,0x00,0x1B,0x40,0x58,0x30,0x34,0x30,
- 0x40,0x43,0x30,0x30,0x31,0x57,0x69,0x6E,0x64,0x6F,0x77,0x20,
- 0x73,0x77,0x69,0x74,0x63,0x68,0x69,0x6E,0x67,0x3A,0x0B,0x3E,
- 0x40,0x58,0x30,0x36,0x30,0x40,0x43,0x30,0x30,0x32,0x05,0x43,
- 0x74,0x72,0x6C,0x2B,0x16,0x3E,0x41,0x20,0x40,0x54,0x31,0x36,
- 0x30,0x41,0x64,0x76,0x61,0x6E,0x63,0x65,0x64,0x20,0x65,0x64,
- 0x69,0x74,0x2E,0x0E,0x3E,0x42,0x20,0x40,0x54,0x31,0x36,0x30,
- 0x41,0x62,0x6F,0x75,0x74,0x2E,0x16,0x3E,0x43,0x20,0x40,0x54,
- 0x31,0x36,0x30,0x43,0x6F,0x6E,0x66,0x69,0x67,0x75,0x72,0x61,
- 0x74,0x69,0x6F,0x6E,0x2E,0x18,0x3E,0x44,0x20,0x40,0x54,0x31,
- 0x36,0x30,0x44,0x69,0x73,0x6B,0x20,0x6F,0x70,0x65,0x72,0x61,
- 0x74,0x69,0x6F,0x6E,0x73,0x2E,0x20,0x3E,0x45,0x20,0x40,0x54,
- 0x31,0x36,0x30,0x53,0x61,0x6D,0x70,0x6C,0x65,0x20,0x65,0x64,
- 0x69,0x74,0x6F,0x72,0x20,0x65,0x78,0x74,0x65,0x6E,0x73,0x69,
- 0x6F,0x6E,0x2E,0x0D,0x3E,0x48,0x20,0x40,0x54,0x31,0x36,0x30,
- 0x48,0x65,0x6C,0x70,0x2E,0x1A,0x3E,0x49,0x20,0x40,0x54,0x31,
- 0x36,0x30,0x49,0x6E,0x73,0x74,0x72,0x75,0x6D,0x65,0x6E,0x74,
- 0x20,0x65,0x64,0x69,0x74,0x6F,0x72,0x2E,0x2B,0x3E,0x4D,0x20,
- 0x40,0x54,0x31,0x36,0x30,0x49,0x6E,0x73,0x74,0x72,0x75,0x6D,
- 0x65,0x6E,0x74,0x20,0x65,0x64,0x69,0x74,0x6F,0x72,0x20,0x65,
- 0x78,0x74,0x65,0x6E,0x73,0x69,0x6F,0x6E,0x2E,0x20,0x28,0x4D,
- 0x49,0x44,0x49,0x29,0x10,0x3E,0x4E,0x20,0x40,0x54,0x31,0x36,
- 0x30,0x4E,0x69,0x62,0x62,0x6C,0x65,0x73,0x2E,0x10,0x3E,0x50,
- 0x20,0x40,0x54,0x31,0x36,0x30,0x50,0x61,0x74,0x74,0x65,0x72,
- 0x6E,0x2E,0x0D,0x3E,0x52,0x20,0x40,0x54,0x31,0x36,0x30,0x54,
- 0x72,0x69,0x6D,0x2E,0x16,0x3E,0x53,0x20,0x40,0x54,0x31,0x36,
+ 0x63,0x72,0x65,0x61,0x73,0x65,0x20,0x73,0x6F,0x6E,0x67,0x20,
+ 0x70,0x6F,0x73,0x69,0x74,0x69,0x6F,0x6E,0x2E,0x28,0x3E,0x43,
+ 0x74,0x72,0x6C,0x2B,0x4C,0x65,0x66,0x74,0x20,0x40,0x54,0x31,
+ 0x36,0x30,0x49,0x6E,0x63,0x72,0x65,0x61,0x73,0x65,0x20,0x70,
+ 0x61,0x74,0x74,0x65,0x72,0x6E,0x20,0x6E,0x75,0x6D,0x62,0x65,
+ 0x72,0x2E,0x29,0x3E,0x43,0x74,0x72,0x6C,0x2B,0x52,0x69,0x67,
+ 0x68,0x74,0x20,0x40,0x54,0x31,0x36,0x30,0x44,0x65,0x63,0x72,
+ 0x65,0x61,0x73,0x65,0x20,0x70,0x61,0x74,0x74,0x65,0x72,0x6E,
+ 0x20,0x6E,0x75,0x6D,0x62,0x65,0x72,0x2E,0x00,0x2C,0x40,0x58,
+ 0x30,0x34,0x30,0x40,0x43,0x30,0x30,0x31,0x4D,0x69,0x73,0x63,
+ 0x65,0x6C,0x6C,0x61,0x6E,0x65,0x6F,0x75,0x73,0x20,0x28,0x6F,
+ 0x6E,0x20,0x61,0x20,0x4D,0x61,0x63,0x20,0x6B,0x65,0x79,0x62,
+ 0x6F,0x61,0x72,0x64,0x29,0x3A,0x0B,0x3E,0x40,0x58,0x30,0x36,
+ 0x30,0x40,0x43,0x30,0x30,0x32,0x1E,0x52,0x69,0x67,0x68,0x74,
+ 0x20,0x63,0x6F,0x6D,0x6D,0x61,0x6E,0x64,0x20,0x20,0x40,0x54,
+ 0x32,0x34,0x30,0x50,0x6C,0x61,0x79,0x20,0x73,0x6F,0x6E,0x67,
+ 0x2E,0x32,0x3E,0x52,0x69,0x67,0x68,0x74,0x20,0x61,0x6C,0x74,
+ 0x20,0x28,0x6F,0x72,0x20,0x6C,0x65,0x66,0x74,0x20,0x63,0x6F,
+ 0x6D,0x6D,0x61,0x6E,0x64,0x29,0x20,0x20,0x20,0x20,0x40,0x54,
+ 0x32,0x34,0x30,0x50,0x6C,0x61,0x79,0x20,0x70,0x61,0x74,0x74,
+ 0x65,0x72,0x6E,0x2E,0x22,0x3E,0x52,0x69,0x67,0x68,0x74,0x20,
+ 0x73,0x68,0x69,0x66,0x74,0x20,0x20,0x40,0x54,0x32,0x34,0x30,
+ 0x52,0x65,0x63,0x6F,0x72,0x64,0x20,0x70,0x61,0x74,0x74,0x65,
+ 0x72,0x6E,0x2E,0x00,0x1B,0x40,0x58,0x30,0x34,0x30,0x40,0x43,
+ 0x30,0x30,0x31,0x57,0x69,0x6E,0x64,0x6F,0x77,0x20,0x73,0x77,
+ 0x69,0x74,0x63,0x68,0x69,0x6E,0x67,0x3A,0x0B,0x3E,0x40,0x58,
+ 0x30,0x36,0x30,0x40,0x43,0x30,0x30,0x32,0x05,0x43,0x74,0x72,
+ 0x6C,0x2B,0x16,0x3E,0x41,0x20,0x40,0x54,0x31,0x36,0x30,0x41,
+ 0x64,0x76,0x61,0x6E,0x63,0x65,0x64,0x20,0x65,0x64,0x69,0x74,
+ 0x2E,0x0E,0x3E,0x42,0x20,0x40,0x54,0x31,0x36,0x30,0x41,0x62,
+ 0x6F,0x75,0x74,0x2E,0x16,0x3E,0x43,0x20,0x40,0x54,0x31,0x36,
+ 0x30,0x43,0x6F,0x6E,0x66,0x69,0x67,0x75,0x72,0x61,0x74,0x69,
+ 0x6F,0x6E,0x2E,0x18,0x3E,0x44,0x20,0x40,0x54,0x31,0x36,0x30,
+ 0x44,0x69,0x73,0x6B,0x20,0x6F,0x70,0x65,0x72,0x61,0x74,0x69,
+ 0x6F,0x6E,0x73,0x2E,0x20,0x3E,0x45,0x20,0x40,0x54,0x31,0x36,
0x30,0x53,0x61,0x6D,0x70,0x6C,0x65,0x20,0x65,0x64,0x69,0x74,
- 0x6F,0x72,0x2E,0x12,0x3E,0x54,0x20,0x40,0x54,0x31,0x36,0x30,
- 0x54,0x72,0x61,0x6E,0x73,0x70,0x6F,0x73,0x65,0x2E,0x23,0x3E,
- 0x58,0x20,0x40,0x54,0x31,0x36,0x30,0x4D,0x61,0x69,0x6E,0x20,
- 0x73,0x63,0x72,0x65,0x65,0x6E,0x2E,0x20,0x28,0x61,0x6C,0x6D,
- 0x6F,0x73,0x74,0x20,0x61,0x6C,0x74,0x2B,0x58,0x29,0x27,0x3E,
- 0x5A,0x20,0x40,0x54,0x31,0x36,0x30,0x46,0x75,0x6C,0x6C,0x20,
- 0x73,0x63,0x72,0x65,0x65,0x6E,0x20,0x65,0x64,0x69,0x74,0x2E,
- 0x20,0x28,0x5A,0x20,0x66,0x6F,0x72,0x20,0x73,0x69,0x5A,0x65,
- 0x3F,0x29,0x19,0x3E,0x31,0x20,0x40,0x54,0x31,0x36,0x30,0x43,
+ 0x6F,0x72,0x20,0x65,0x78,0x74,0x65,0x6E,0x73,0x69,0x6F,0x6E,
+ 0x2E,0x0D,0x3E,0x48,0x20,0x40,0x54,0x31,0x36,0x30,0x48,0x65,
+ 0x6C,0x70,0x2E,0x1A,0x3E,0x49,0x20,0x40,0x54,0x31,0x36,0x30,
+ 0x49,0x6E,0x73,0x74,0x72,0x75,0x6D,0x65,0x6E,0x74,0x20,0x65,
+ 0x64,0x69,0x74,0x6F,0x72,0x2E,0x2B,0x3E,0x4D,0x20,0x40,0x54,
+ 0x31,0x36,0x30,0x49,0x6E,0x73,0x74,0x72,0x75,0x6D,0x65,0x6E,
+ 0x74,0x20,0x65,0x64,0x69,0x74,0x6F,0x72,0x20,0x65,0x78,0x74,
+ 0x65,0x6E,0x73,0x69,0x6F,0x6E,0x2E,0x20,0x28,0x4D,0x49,0x44,
+ 0x49,0x29,0x10,0x3E,0x4E,0x20,0x40,0x54,0x31,0x36,0x30,0x4E,
+ 0x69,0x62,0x62,0x6C,0x65,0x73,0x2E,0x10,0x3E,0x50,0x20,0x40,
+ 0x54,0x31,0x36,0x30,0x50,0x61,0x74,0x74,0x65,0x72,0x6E,0x2E,
+ 0x0D,0x3E,0x52,0x20,0x40,0x54,0x31,0x36,0x30,0x54,0x72,0x69,
+ 0x6D,0x2E,0x16,0x3E,0x53,0x20,0x40,0x54,0x31,0x36,0x30,0x53,
+ 0x61,0x6D,0x70,0x6C,0x65,0x20,0x65,0x64,0x69,0x74,0x6F,0x72,
+ 0x2E,0x12,0x3E,0x54,0x20,0x40,0x54,0x31,0x36,0x30,0x54,0x72,
+ 0x61,0x6E,0x73,0x70,0x6F,0x73,0x65,0x2E,0x23,0x3E,0x58,0x20,
+ 0x40,0x54,0x31,0x36,0x30,0x4D,0x61,0x69,0x6E,0x20,0x73,0x63,
+ 0x72,0x65,0x65,0x6E,0x2E,0x20,0x28,0x61,0x6C,0x6D,0x6F,0x73,
+ 0x74,0x20,0x61,0x6C,0x74,0x2B,0x58,0x29,0x27,0x3E,0x5A,0x20,
+ 0x40,0x54,0x31,0x36,0x30,0x46,0x75,0x6C,0x6C,0x20,0x73,0x63,
+ 0x72,0x65,0x65,0x6E,0x20,0x65,0x64,0x69,0x74,0x2E,0x20,0x28,
+ 0x5A,0x20,0x66,0x6F,0x72,0x20,0x73,0x69,0x5A,0x65,0x3F,0x29,
+ 0x19,0x3E,0x31,0x20,0x40,0x54,0x31,0x36,0x30,0x43,0x6F,0x6E,
+ 0x66,0x69,0x67,0x75,0x72,0x61,0x74,0x69,0x6F,0x6E,0x20,0x23,
+ 0x31,0x2E,0x19,0x3E,0x32,0x20,0x40,0x54,0x31,0x36,0x30,0x43,
0x6F,0x6E,0x66,0x69,0x67,0x75,0x72,0x61,0x74,0x69,0x6F,0x6E,
- 0x20,0x23,0x31,0x2E,0x19,0x3E,0x32,0x20,0x40,0x54,0x31,0x36,
+ 0x20,0x23,0x32,0x2E,0x19,0x3E,0x33,0x20,0x40,0x54,0x31,0x36,
0x30,0x43,0x6F,0x6E,0x66,0x69,0x67,0x75,0x72,0x61,0x74,0x69,
- 0x6F,0x6E,0x20,0x23,0x32,0x2E,0x19,0x3E,0x33,0x20,0x40,0x54,
+ 0x6F,0x6E,0x20,0x23,0x33,0x2E,0x19,0x3E,0x34,0x20,0x40,0x54,
0x31,0x36,0x30,0x43,0x6F,0x6E,0x66,0x69,0x67,0x75,0x72,0x61,
- 0x74,0x69,0x6F,0x6E,0x20,0x23,0x33,0x2E,0x19,0x3E,0x34,0x20,
- 0x40,0x54,0x31,0x36,0x30,0x43,0x6F,0x6E,0x66,0x69,0x67,0x75,
- 0x72,0x61,0x74,0x69,0x6F,0x6E,0x20,0x23,0x34,0x2E,0x00,0x2D,
- 0x40,0x58,0x30,0x34,0x30,0x40,0x43,0x30,0x30,0x31,0x49,0x6E,
- 0x73,0x74,0x72,0x75,0x6D,0x65,0x6E,0x74,0x20,0x73,0x65,0x6C,
- 0x65,0x63,0x74,0x20,0x28,0x4E,0x75,0x6D,0x65,0x72,0x69,0x63,
- 0x20,0x6B,0x65,0x79,0x70,0x61,0x64,0x29,0x3A,0x0B,0x3E,0x40,
- 0x58,0x30,0x36,0x30,0x40,0x43,0x30,0x30,0x32,0x28,0x54,0x6F,
- 0x70,0x20,0x34,0x20,0x6B,0x65,0x79,0x73,0x20,0x40,0x54,0x31,
- 0x36,0x30,0x53,0x65,0x6C,0x65,0x63,0x74,0x20,0x69,0x6E,0x73,
- 0x74,0x72,0x75,0x6D,0x65,0x6E,0x74,0x20,0x62,0x6C,0x6F,0x63,
- 0x6B,0x2E,0x32,0x3E,0x27,0x2B,0x27,0x20,0x2B,0x54,0x6F,0x70,
- 0x20,0x34,0x20,0x6B,0x65,0x79,0x73,0x20,0x40,0x54,0x31,0x36,
- 0x30,0x53,0x65,0x6C,0x65,0x63,0x74,0x20,0x69,0x6E,0x73,0x74,
- 0x72,0x75,0x6D,0x65,0x6E,0x74,0x20,0x62,0x6C,0x6F,0x63,0x6B,
- 0x20,0x2B,0x20,0x34,0x2E,0x23,0x3E,0x45,0x6E,0x74,0x65,0x72,
- 0x20,0x40,0x54,0x31,0x36,0x30,0x53,0x65,0x6C,0x65,0x63,0x74,
- 0x20,0x69,0x6E,0x73,0x74,0x72,0x75,0x6D,0x65,0x6E,0x74,0x20,
- 0x62,0x61,0x6E,0x6B,0x2E,0x1D,0x3E,0x30,0x20,0x40,0x54,0x31,
- 0x36,0x30,0x53,0x65,0x6C,0x65,0x63,0x74,0x20,0x6E,0x6F,0x20,
- 0x69,0x6E,0x73,0x74,0x72,0x75,0x6D,0x65,0x6E,0x74,0x2E,0x26,
- 0x3E,0x31,0x2E,0x2E,0x38,0x20,0x40,0x54,0x31,0x36,0x30,0x53,
+ 0x74,0x69,0x6F,0x6E,0x20,0x23,0x34,0x2E,0x00,0x2D,0x40,0x58,
+ 0x30,0x34,0x30,0x40,0x43,0x30,0x30,0x31,0x49,0x6E,0x73,0x74,
+ 0x72,0x75,0x6D,0x65,0x6E,0x74,0x20,0x73,0x65,0x6C,0x65,0x63,
+ 0x74,0x20,0x28,0x4E,0x75,0x6D,0x65,0x72,0x69,0x63,0x20,0x6B,
+ 0x65,0x79,0x70,0x61,0x64,0x29,0x3A,0x0B,0x3E,0x40,0x58,0x30,
+ 0x36,0x30,0x40,0x43,0x30,0x30,0x32,0x28,0x54,0x6F,0x70,0x20,
+ 0x34,0x20,0x6B,0x65,0x79,0x73,0x20,0x40,0x54,0x31,0x36,0x30,
+ 0x53,0x65,0x6C,0x65,0x63,0x74,0x20,0x69,0x6E,0x73,0x74,0x72,
+ 0x75,0x6D,0x65,0x6E,0x74,0x20,0x62,0x6C,0x6F,0x63,0x6B,0x2E,
+ 0x32,0x3E,0x27,0x2B,0x27,0x20,0x2B,0x54,0x6F,0x70,0x20,0x34,
+ 0x20,0x6B,0x65,0x79,0x73,0x20,0x40,0x54,0x31,0x36,0x30,0x53,
0x65,0x6C,0x65,0x63,0x74,0x20,0x69,0x6E,0x73,0x74,0x72,0x75,
- 0x6D,0x65,0x6E,0x74,0x20,0x69,0x6E,0x20,0x62,0x6C,0x6F,0x63,
- 0x6B,0x2E,0x19,0x3E,0x2C,0x20,0x40,0x54,0x31,0x36,0x30,0x43,
- 0x6C,0x65,0x61,0x72,0x20,0x69,0x6E,0x73,0x74,0x72,0x75,0x6D,
- 0x65,0x6E,0x74,0x2E,0x18,0x3E,0x53,0x68,0x2B,0x2C,0x20,0x40,
- 0x54,0x31,0x36,0x30,0x43,0x6C,0x65,0x61,0x72,0x20,0x73,0x61,
- 0x6D,0x70,0x6C,0x65,0x2E,0x27,0x3E,0x53,0x68,0x2B,0x55,0x70,
- 0x20,0x40,0x54,0x31,0x36,0x30,0x53,0x65,0x6C,0x65,0x63,0x74,
- 0x20,0x70,0x72,0x65,0x76,0x69,0x6F,0x75,0x73,0x20,0x69,0x6E,
- 0x73,0x74,0x72,0x75,0x6D,0x65,0x6E,0x74,0x2E,0x25,0x3E,0x53,
- 0x68,0x2B,0x44,0x6F,0x77,0x6E,0x20,0x40,0x54,0x31,0x36,0x30,
- 0x53,0x65,0x6C,0x65,0x63,0x74,0x20,0x6E,0x65,0x78,0x74,0x20,
- 0x69,0x6E,0x73,0x74,0x72,0x75,0x6D,0x65,0x6E,0x74,0x2E,0x00,
- 0x1F,0x40,0x58,0x30,0x34,0x30,0x40,0x43,0x30,0x30,0x31,0x43,
- 0x6F,0x6D,0x6D,0x61,0x6E,0x64,0x2F,0x56,0x6F,0x6C,0x75,0x6D,
- 0x65,0x20,0x6D,0x61,0x63,0x72,0x6F,0x3A,0x0B,0x3E,0x40,0x58,
- 0x30,0x36,0x30,0x40,0x43,0x30,0x30,0x32,0x2D,0x41,0x6C,0x74,
- 0x2B,0x31,0x2E,0x2E,0x30,0x20,0x40,0x54,0x31,0x36,0x30,0x57,
- 0x72,0x69,0x74,0x65,0x20,0x63,0x6F,0x6D,0x6D,0x61,0x6E,0x64,
- 0x2F,0x76,0x6F,0x6C,0x75,0x6D,0x65,0x20,0x61,0x74,0x20,0x63,
- 0x75,0x72,0x73,0x6F,0x72,0x2E,0x30,0x3E,0x53,0x68,0x2B,0x41,
- 0x6C,0x74,0x2B,0x31,0x2E,0x2E,0x30,0x20,0x40,0x54,0x31,0x36,
- 0x30,0x52,0x65,0x61,0x64,0x20,0x63,0x6F,0x6D,0x6D,0x61,0x6E,
- 0x64,0x2F,0x76,0x6F,0x6C,0x75,0x6D,0x65,0x20,0x61,0x74,0x20,
- 0x63,0x75,0x72,0x73,0x6F,0x72,0x2E,0x00,0x1C,0x40,0x58,0x30,
- 0x34,0x30,0x40,0x43,0x30,0x30,0x31,0x53,0x63,0x61,0x6C,0x65,
- 0x2D,0x66,0x61,0x64,0x65,0x20,0x76,0x6F,0x6C,0x75,0x6D,0x65,
- 0x3A,0x0B,0x3E,0x40,0x58,0x30,0x36,0x30,0x40,0x43,0x30,0x30,
- 0x32,0x25,0x53,0x68,0x2B,0x56,0x20,0x40,0x54,0x31,0x36,0x30,
- 0x53,0x63,0x61,0x6C,0x65,0x2D,0x66,0x61,0x64,0x65,0x20,0x76,
- 0x6F,0x6C,0x75,0x6D,0x65,0x20,0x69,0x6E,0x20,0x74,0x72,0x61,
- 0x63,0x6B,0x2E,0x2A,0x3E,0x43,0x74,0x72,0x6C,0x2B,0x56,0x20,
- 0x40,0x54,0x31,0x36,0x30,0x53,0x63,0x61,0x6C,0x65,0x2D,0x66,
- 0x61,0x64,0x65,0x20,0x76,0x6F,0x6C,0x75,0x6D,0x65,0x20,0x69,
- 0x6E,0x20,0x70,0x61,0x74,0x74,0x65,0x72,0x6E,0x2E,0x27,0x3E,
- 0x41,0x6C,0x74,0x2B,0x56,0x20,0x40,0x54,0x31,0x36,0x30,0x53,
- 0x63,0x61,0x6C,0x65,0x2D,0x66,0x61,0x64,0x65,0x20,0x76,0x6F,
- 0x6C,0x75,0x6D,0x65,0x20,0x69,0x6E,0x20,0x62,0x6C,0x6F,0x63,
- 0x6B,0x2E,0x00,0x14,0x40,0x58,0x30,0x34,0x30,0x40,0x43,0x30,
- 0x30,0x31,0x54,0x72,0x61,0x6E,0x73,0x70,0x6F,0x73,0x65,0x3A,
- 0x0B,0x3E,0x40,0x58,0x30,0x36,0x30,0x40,0x43,0x30,0x30,0x32,
- 0x36,0x53,0x68,0x2B,0x46,0x37,0x20,0x40,0x54,0x31,0x36,0x30,
- 0x54,0x72,0x61,0x6E,0x73,0x70,0x6F,0x73,0x65,0x20,0x63,0x75,
- 0x72,0x72,0x65,0x6E,0x74,0x20,0x69,0x6E,0x73,0x74,0x72,0x75,
- 0x6D,0x65,0x6E,0x74,0x20,0x69,0x6E,0x20,0x74,0x72,0x61,0x63,
- 0x6B,0x20,0x64,0x6F,0x77,0x6E,0x2E,0x35,0x3E,0x53,0x68,0x2B,
+ 0x6D,0x65,0x6E,0x74,0x20,0x62,0x6C,0x6F,0x63,0x6B,0x20,0x2B,
+ 0x20,0x34,0x2E,0x23,0x3E,0x45,0x6E,0x74,0x65,0x72,0x20,0x40,
+ 0x54,0x31,0x36,0x30,0x53,0x65,0x6C,0x65,0x63,0x74,0x20,0x69,
+ 0x6E,0x73,0x74,0x72,0x75,0x6D,0x65,0x6E,0x74,0x20,0x62,0x61,
+ 0x6E,0x6B,0x2E,0x1D,0x3E,0x30,0x20,0x40,0x54,0x31,0x36,0x30,
+ 0x53,0x65,0x6C,0x65,0x63,0x74,0x20,0x6E,0x6F,0x20,0x69,0x6E,
+ 0x73,0x74,0x72,0x75,0x6D,0x65,0x6E,0x74,0x2E,0x26,0x3E,0x31,
+ 0x2E,0x2E,0x38,0x20,0x40,0x54,0x31,0x36,0x30,0x53,0x65,0x6C,
+ 0x65,0x63,0x74,0x20,0x69,0x6E,0x73,0x74,0x72,0x75,0x6D,0x65,
+ 0x6E,0x74,0x20,0x69,0x6E,0x20,0x62,0x6C,0x6F,0x63,0x6B,0x2E,
+ 0x19,0x3E,0x2C,0x20,0x40,0x54,0x31,0x36,0x30,0x43,0x6C,0x65,
+ 0x61,0x72,0x20,0x69,0x6E,0x73,0x74,0x72,0x75,0x6D,0x65,0x6E,
+ 0x74,0x2E,0x18,0x3E,0x53,0x68,0x2B,0x2C,0x20,0x40,0x54,0x31,
+ 0x36,0x30,0x43,0x6C,0x65,0x61,0x72,0x20,0x73,0x61,0x6D,0x70,
+ 0x6C,0x65,0x2E,0x27,0x3E,0x53,0x68,0x2B,0x55,0x70,0x20,0x40,
+ 0x54,0x31,0x36,0x30,0x53,0x65,0x6C,0x65,0x63,0x74,0x20,0x70,
+ 0x72,0x65,0x76,0x69,0x6F,0x75,0x73,0x20,0x69,0x6E,0x73,0x74,
+ 0x72,0x75,0x6D,0x65,0x6E,0x74,0x2E,0x25,0x3E,0x53,0x68,0x2B,
+ 0x44,0x6F,0x77,0x6E,0x20,0x40,0x54,0x31,0x36,0x30,0x53,0x65,
+ 0x6C,0x65,0x63,0x74,0x20,0x6E,0x65,0x78,0x74,0x20,0x69,0x6E,
+ 0x73,0x74,0x72,0x75,0x6D,0x65,0x6E,0x74,0x2E,0x00,0x1F,0x40,
+ 0x58,0x30,0x34,0x30,0x40,0x43,0x30,0x30,0x31,0x43,0x6F,0x6D,
+ 0x6D,0x61,0x6E,0x64,0x2F,0x56,0x6F,0x6C,0x75,0x6D,0x65,0x20,
+ 0x6D,0x61,0x63,0x72,0x6F,0x3A,0x0B,0x3E,0x40,0x58,0x30,0x36,
+ 0x30,0x40,0x43,0x30,0x30,0x32,0x2D,0x41,0x6C,0x74,0x2B,0x31,
+ 0x2E,0x2E,0x30,0x20,0x40,0x54,0x31,0x36,0x30,0x57,0x72,0x69,
+ 0x74,0x65,0x20,0x63,0x6F,0x6D,0x6D,0x61,0x6E,0x64,0x2F,0x76,
+ 0x6F,0x6C,0x75,0x6D,0x65,0x20,0x61,0x74,0x20,0x63,0x75,0x72,
+ 0x73,0x6F,0x72,0x2E,0x30,0x3E,0x53,0x68,0x2B,0x41,0x6C,0x74,
+ 0x2B,0x31,0x2E,0x2E,0x30,0x20,0x40,0x54,0x31,0x36,0x30,0x52,
+ 0x65,0x61,0x64,0x20,0x63,0x6F,0x6D,0x6D,0x61,0x6E,0x64,0x2F,
+ 0x76,0x6F,0x6C,0x75,0x6D,0x65,0x20,0x61,0x74,0x20,0x63,0x75,
+ 0x72,0x73,0x6F,0x72,0x2E,0x00,0x1C,0x40,0x58,0x30,0x34,0x30,
+ 0x40,0x43,0x30,0x30,0x31,0x53,0x63,0x61,0x6C,0x65,0x2D,0x66,
+ 0x61,0x64,0x65,0x20,0x76,0x6F,0x6C,0x75,0x6D,0x65,0x3A,0x0B,
+ 0x3E,0x40,0x58,0x30,0x36,0x30,0x40,0x43,0x30,0x30,0x32,0x25,
+ 0x53,0x68,0x2B,0x56,0x20,0x40,0x54,0x31,0x36,0x30,0x53,0x63,
+ 0x61,0x6C,0x65,0x2D,0x66,0x61,0x64,0x65,0x20,0x76,0x6F,0x6C,
+ 0x75,0x6D,0x65,0x20,0x69,0x6E,0x20,0x74,0x72,0x61,0x63,0x6B,
+ 0x2E,0x2A,0x3E,0x43,0x74,0x72,0x6C,0x2B,0x56,0x20,0x40,0x54,
+ 0x31,0x36,0x30,0x53,0x63,0x61,0x6C,0x65,0x2D,0x66,0x61,0x64,
+ 0x65,0x20,0x76,0x6F,0x6C,0x75,0x6D,0x65,0x20,0x69,0x6E,0x20,
+ 0x70,0x61,0x74,0x74,0x65,0x72,0x6E,0x2E,0x27,0x3E,0x41,0x6C,
+ 0x74,0x2B,0x56,0x20,0x40,0x54,0x31,0x36,0x30,0x53,0x63,0x61,
+ 0x6C,0x65,0x2D,0x66,0x61,0x64,0x65,0x20,0x76,0x6F,0x6C,0x75,
+ 0x6D,0x65,0x20,0x69,0x6E,0x20,0x62,0x6C,0x6F,0x63,0x6B,0x2E,
+ 0x00,0x14,0x40,0x58,0x30,0x34,0x30,0x40,0x43,0x30,0x30,0x31,
+ 0x54,0x72,0x61,0x6E,0x73,0x70,0x6F,0x73,0x65,0x3A,0x0B,0x3E,
+ 0x40,0x58,0x30,0x36,0x30,0x40,0x43,0x30,0x30,0x32,0x36,0x53,
+ 0x68,0x2B,0x46,0x37,0x20,0x40,0x54,0x31,0x36,0x30,0x54,0x72,
+ 0x61,0x6E,0x73,0x70,0x6F,0x73,0x65,0x20,0x63,0x75,0x72,0x72,
+ 0x65,0x6E,0x74,0x20,0x69,0x6E,0x73,0x74,0x72,0x75,0x6D,0x65,
+ 0x6E,0x74,0x20,0x69,0x6E,0x20,0x74,0x72,0x61,0x63,0x6B,0x20,
+ 0x64,0x6F,0x77,0x6E,0x2E,0x35,0x3E,0x53,0x68,0x2B,0x46,0x38,
+ 0x20,0x40,0x54,0x31,0x36,0x30,0x54,0x72,0x61,0x6E,0x73,0x70,
+ 0x6F,0x73,0x65,0x20,0x63,0x75,0x72,0x72,0x65,0x6E,0x74,0x20,
+ 0x69,0x6E,0x73,0x74,0x72,0x75,0x6D,0x65,0x6E,0x74,0x20,0x69,
+ 0x6E,0x20,0x74,0x72,0x61,0x63,0x6B,0x20,0x75,0x70,0x2E,0x3B,
+ 0x3E,0x43,0x74,0x72,0x6C,0x2B,0x46,0x37,0x20,0x40,0x54,0x31,
+ 0x36,0x30,0x54,0x72,0x61,0x6E,0x73,0x70,0x6F,0x73,0x65,0x20,
+ 0x63,0x75,0x72,0x72,0x65,0x6E,0x74,0x20,0x69,0x6E,0x73,0x74,
+ 0x72,0x75,0x6D,0x65,0x6E,0x74,0x20,0x69,0x6E,0x20,0x70,0x61,
+ 0x74,0x74,0x65,0x72,0x6E,0x20,0x64,0x6F,0x77,0x6E,0x2E,0x39,
+ 0x3E,0x43,0x74,0x72,0x6C,0x2B,0x46,0x38,0x20,0x40,0x54,0x31,
+ 0x36,0x30,0x54,0x72,0x61,0x6E,0x73,0x70,0x6F,0x73,0x65,0x20,
+ 0x63,0x75,0x72,0x72,0x65,0x6E,0x74,0x20,0x69,0x6E,0x73,0x74,
+ 0x72,0x75,0x6D,0x65,0x6E,0x74,0x20,0x69,0x6E,0x20,0x70,0x61,
+ 0x74,0x74,0x65,0x72,0x6E,0x20,0x75,0x70,0x2E,0x38,0x3E,0x41,
+ 0x6C,0x74,0x2B,0x46,0x37,0x20,0x40,0x54,0x31,0x36,0x30,0x54,
+ 0x72,0x61,0x6E,0x73,0x70,0x6F,0x73,0x65,0x20,0x63,0x75,0x72,
+ 0x72,0x65,0x6E,0x74,0x20,0x69,0x6E,0x73,0x74,0x72,0x75,0x6D,
+ 0x65,0x6E,0x74,0x20,0x69,0x6E,0x20,0x62,0x6C,0x6F,0x63,0x6B,
+ 0x20,0x64,0x6F,0x77,0x6E,0x2E,0x36,0x3E,0x41,0x6C,0x74,0x2B,
0x46,0x38,0x20,0x40,0x54,0x31,0x36,0x30,0x54,0x72,0x61,0x6E,
0x73,0x70,0x6F,0x73,0x65,0x20,0x63,0x75,0x72,0x72,0x65,0x6E,
0x74,0x20,0x69,0x6E,0x73,0x74,0x72,0x75,0x6D,0x65,0x6E,0x74,
- 0x20,0x69,0x6E,0x20,0x74,0x72,0x61,0x63,0x6B,0x20,0x75,0x70,
- 0x2E,0x3B,0x3E,0x43,0x74,0x72,0x6C,0x2B,0x46,0x37,0x20,0x40,
- 0x54,0x31,0x36,0x30,0x54,0x72,0x61,0x6E,0x73,0x70,0x6F,0x73,
- 0x65,0x20,0x63,0x75,0x72,0x72,0x65,0x6E,0x74,0x20,0x69,0x6E,
- 0x73,0x74,0x72,0x75,0x6D,0x65,0x6E,0x74,0x20,0x69,0x6E,0x20,
- 0x70,0x61,0x74,0x74,0x65,0x72,0x6E,0x20,0x64,0x6F,0x77,0x6E,
- 0x2E,0x39,0x3E,0x43,0x74,0x72,0x6C,0x2B,0x46,0x38,0x20,0x40,
- 0x54,0x31,0x36,0x30,0x54,0x72,0x61,0x6E,0x73,0x70,0x6F,0x73,
- 0x65,0x20,0x63,0x75,0x72,0x72,0x65,0x6E,0x74,0x20,0x69,0x6E,
- 0x73,0x74,0x72,0x75,0x6D,0x65,0x6E,0x74,0x20,0x69,0x6E,0x20,
- 0x70,0x61,0x74,0x74,0x65,0x72,0x6E,0x20,0x75,0x70,0x2E,0x38,
- 0x3E,0x41,0x6C,0x74,0x2B,0x46,0x37,0x20,0x40,0x54,0x31,0x36,
- 0x30,0x54,0x72,0x61,0x6E,0x73,0x70,0x6F,0x73,0x65,0x20,0x63,
- 0x75,0x72,0x72,0x65,0x6E,0x74,0x20,0x69,0x6E,0x73,0x74,0x72,
- 0x75,0x6D,0x65,0x6E,0x74,0x20,0x69,0x6E,0x20,0x62,0x6C,0x6F,
- 0x63,0x6B,0x20,0x64,0x6F,0x77,0x6E,0x2E,0x36,0x3E,0x41,0x6C,
- 0x74,0x2B,0x46,0x38,0x20,0x40,0x54,0x31,0x36,0x30,0x54,0x72,
- 0x61,0x6E,0x73,0x70,0x6F,0x73,0x65,0x20,0x63,0x75,0x72,0x72,
- 0x65,0x6E,0x74,0x20,0x69,0x6E,0x73,0x74,0x72,0x75,0x6D,0x65,
- 0x6E,0x74,0x20,0x69,0x6E,0x20,0x62,0x6C,0x6F,0x63,0x6B,0x20,
- 0x75,0x70,0x2E,0x34,0x3E,0x53,0x68,0x2B,0x46,0x31,0x20,0x40,
- 0x54,0x31,0x36,0x30,0x54,0x72,0x61,0x6E,0x73,0x70,0x6F,0x73,
- 0x65,0x20,0x61,0x6C,0x6C,0x20,0x69,0x6E,0x73,0x74,0x72,0x75,
- 0x6D,0x65,0x6E,0x74,0x73,0x20,0x69,0x6E,0x20,0x74,0x72,0x61,
- 0x63,0x6B,0x20,0x64,0x6F,0x77,0x6E,0x2E,0x32,0x3E,0x53,0x68,
+ 0x20,0x69,0x6E,0x20,0x62,0x6C,0x6F,0x63,0x6B,0x20,0x75,0x70,
+ 0x2E,0x34,0x3E,0x53,0x68,0x2B,0x46,0x31,0x20,0x40,0x54,0x31,
+ 0x36,0x30,0x54,0x72,0x61,0x6E,0x73,0x70,0x6F,0x73,0x65,0x20,
+ 0x61,0x6C,0x6C,0x20,0x69,0x6E,0x73,0x74,0x72,0x75,0x6D,0x65,
+ 0x6E,0x74,0x73,0x20,0x69,0x6E,0x20,0x74,0x72,0x61,0x63,0x6B,
+ 0x20,0x64,0x6F,0x77,0x6E,0x2E,0x32,0x3E,0x53,0x68,0x2B,0x46,
+ 0x32,0x20,0x40,0x54,0x31,0x36,0x30,0x54,0x72,0x61,0x6E,0x73,
+ 0x70,0x6F,0x73,0x65,0x20,0x61,0x6C,0x6C,0x20,0x69,0x6E,0x73,
+ 0x74,0x72,0x75,0x6D,0x65,0x6E,0x74,0x73,0x20,0x69,0x6E,0x20,
+ 0x74,0x72,0x61,0x63,0x6B,0x20,0x75,0x70,0x2E,0x38,0x3E,0x43,
+ 0x74,0x72,0x6C,0x2B,0x46,0x31,0x20,0x40,0x54,0x31,0x36,0x30,
+ 0x54,0x72,0x61,0x6E,0x73,0x70,0x6F,0x73,0x65,0x20,0x61,0x6C,
+ 0x6C,0x20,0x69,0x6E,0x73,0x74,0x72,0x75,0x6D,0x65,0x6E,0x74,
+ 0x73,0x20,0x69,0x6E,0x20,0x70,0x61,0x74,0x74,0x65,0x72,0x6E,
+ 0x20,0x64,0x6F,0x77,0x6E,0x2E,0x36,0x3E,0x43,0x74,0x72,0x6C,
0x2B,0x46,0x32,0x20,0x40,0x54,0x31,0x36,0x30,0x54,0x72,0x61,
0x6E,0x73,0x70,0x6F,0x73,0x65,0x20,0x61,0x6C,0x6C,0x20,0x69,
0x6E,0x73,0x74,0x72,0x75,0x6D,0x65,0x6E,0x74,0x73,0x20,0x69,
- 0x6E,0x20,0x74,0x72,0x61,0x63,0x6B,0x20,0x75,0x70,0x2E,0x38,
- 0x3E,0x43,0x74,0x72,0x6C,0x2B,0x46,0x31,0x20,0x40,0x54,0x31,
- 0x36,0x30,0x54,0x72,0x61,0x6E,0x73,0x70,0x6F,0x73,0x65,0x20,
- 0x61,0x6C,0x6C,0x20,0x69,0x6E,0x73,0x74,0x72,0x75,0x6D,0x65,
- 0x6E,0x74,0x73,0x20,0x69,0x6E,0x20,0x70,0x61,0x74,0x74,0x65,
- 0x72,0x6E,0x20,0x64,0x6F,0x77,0x6E,0x2E,0x36,0x3E,0x43,0x74,
- 0x72,0x6C,0x2B,0x46,0x32,0x20,0x40,0x54,0x31,0x36,0x30,0x54,
- 0x72,0x61,0x6E,0x73,0x70,0x6F,0x73,0x65,0x20,0x61,0x6C,0x6C,
- 0x20,0x69,0x6E,0x73,0x74,0x72,0x75,0x6D,0x65,0x6E,0x74,0x73,
- 0x20,0x69,0x6E,0x20,0x70,0x61,0x74,0x74,0x65,0x72,0x6E,0x20,
- 0x75,0x70,0x2E,0x35,0x3E,0x41,0x6C,0x74,0x2B,0x46,0x31,0x20,
- 0x40,0x54,0x31,0x36,0x30,0x54,0x72,0x61,0x6E,0x73,0x70,0x6F,
- 0x73,0x65,0x20,0x61,0x6C,0x6C,0x20,0x69,0x6E,0x73,0x74,0x72,
- 0x75,0x6D,0x65,0x6E,0x74,0x73,0x20,0x69,0x6E,0x20,0x62,0x6C,
- 0x6F,0x63,0x6B,0x20,0x64,0x6F,0x77,0x6E,0x2E,0x33,0x3E,0x41,
- 0x6C,0x74,0x2B,0x46,0x32,0x20,0x40,0x54,0x31,0x36,0x30,0x54,
- 0x72,0x61,0x6E,0x73,0x70,0x6F,0x73,0x65,0x20,0x61,0x6C,0x6C,
- 0x20,0x69,0x6E,0x73,0x74,0x72,0x75,0x6D,0x65,0x6E,0x74,0x73,
- 0x20,0x69,0x6E,0x20,0x62,0x6C,0x6F,0x63,0x6B,0x20,0x75,0x70,
- 0x2E,0x01,0x3E,0x18,0x40,0x58,0x30,0x34,0x30,0x40,0x43,0x30,
- 0x30,0x31,0x53,0x61,0x6D,0x70,0x6C,0x65,0x20,0x65,0x64,0x69,
- 0x74,0x6F,0x72,0x3A,0x0B,0x3E,0x40,0x58,0x30,0x36,0x30,0x40,
- 0x43,0x30,0x30,0x32,0x1A,0x41,0x6C,0x74,0x2F,0x43,0x74,0x72,
- 0x6C,0x2B,0x41,0x20,0x40,0x54,0x31,0x36,0x30,0x52,0x61,0x6E,
- 0x67,0x65,0x20,0x61,0x6C,0x6C,0x2E,0x17,0x3E,0x41,0x6C,0x74,
- 0x2B,0x53,0x20,0x40,0x54,0x31,0x36,0x30,0x53,0x68,0x6F,0x77,
- 0x20,0x72,0x61,0x6E,0x67,0x65,0x2E,0x15,0x3E,0x41,0x6C,0x74,
- 0x2B,0x5A,0x20,0x40,0x54,0x31,0x36,0x30,0x5A,0x6F,0x6F,0x6D,
- 0x20,0x6F,0x75,0x74,0x2E,0x1A,0x3E,0x41,0x6C,0x74,0x2B,0x58,
- 0x20,0x6F,0x72,0x20,0x44,0x65,0x6C,0x65,0x74,0x65,0x20,0x40,
- 0x54,0x31,0x36,0x30,0x43,0x75,0x74,0x2E,0x16,0x3E,0x41,0x6C,
- 0x74,0x2F,0x43,0x74,0x72,0x6C,0x2B,0x43,0x20,0x40,0x54,0x31,
- 0x36,0x30,0x43,0x6F,0x70,0x79,0x2E,0x17,0x3E,0x41,0x6C,0x74,
- 0x2F,0x43,0x74,0x72,0x6C,0x2B,0x56,0x20,0x40,0x54,0x31,0x36,
- 0x30,0x50,0x61,0x73,0x74,0x65,0x2E,0x11,0x3E,0x41,0x6C,0x74,
- 0x2B,0x52,0x20,0x40,0x54,0x31,0x36,0x30,0x43,0x72,0x6F,0x70,
- 0x2E,0x2A,0x3E,0x4D,0x6F,0x75,0x73,0x65,0x20,0x77,0x68,0x65,
- 0x65,0x6C,0x20,0x40,0x54,0x31,0x36,0x30,0x5A,0x6F,0x6F,0x6D,
- 0x20,0x73,0x61,0x6D,0x70,0x6C,0x65,0x20,0x64,0x61,0x74,0x61,
- 0x20,0x69,0x6E,0x2F,0x6F,0x75,0x74,0x2E,0x00,0x21,0x40,0x58,
- 0x30,0x34,0x30,0x40,0x43,0x30,0x30,0x31,0x4E,0x6F,0x74,0x65,
- 0x20,0x66,0x6F,0x72,0x20,0x4D,0x61,0x63,0x20,0x6B,0x65,0x79,
- 0x62,0x6F,0x61,0x72,0x64,0x73,0x3A,0x0B,0x3E,0x40,0x58,0x30,
- 0x36,0x30,0x40,0x43,0x30,0x30,0x32,0x3A,0x55,0x73,0x65,0x20,
- 0x6C,0x65,0x66,0x74,0x20,0x63,0x74,0x72,0x6C,0x2E,0x20,0x66,
- 0x6F,0x72,0x20,0x41,0x2F,0x58,0x2F,0x43,0x2F,0x56,0x20,0x28,
- 0x6D,0x61,0x72,0x6B,0x20,0x61,0x6C,0x6C,0x2F,0x63,0x75,0x74,
- 0x2F,0x63,0x6F,0x70,0x79,0x2F,0x70,0x61,0x73,0x74,0x65,0x29,
- 0x20,0x6B,0x65,0x79,0x73,0x2E,0x4B,0x3E,0x54,0x68,0x69,0x73,
- 0x20,0x61,0x70,0x70,0x6C,0x69,0x65,0x73,0x20,0x74,0x6F,0x20,
- 0x74,0x68,0x65,0x20,0x73,0x61,0x6D,0x70,0x6C,0x65,0x20,0x65,
- 0x64,0x69,0x74,0x6F,0x72,0x20,0x28,0x41,0x2F,0x43,0x2F,0x56,
- 0x20,0x6F,0x6E,0x6C,0x79,0x29,0x20,0x61,0x6E,0x64,0x20,0x74,
- 0x65,0x78,0x74,0x20,0x6D,0x61,0x72,0x6B,0x69,0x6E,0x67,0x20,
- 0x69,0x6E,0x20,0x74,0x68,0x65,0x20,0x55,0x49,0x2E,0x00,0x03,
- 0x45,0x4E,0x44,0x4C,0x3B,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,
+ 0x6E,0x20,0x70,0x61,0x74,0x74,0x65,0x72,0x6E,0x20,0x75,0x70,
+ 0x2E,0x35,0x3E,0x41,0x6C,0x74,0x2B,0x46,0x31,0x20,0x40,0x54,
+ 0x31,0x36,0x30,0x54,0x72,0x61,0x6E,0x73,0x70,0x6F,0x73,0x65,
+ 0x20,0x61,0x6C,0x6C,0x20,0x69,0x6E,0x73,0x74,0x72,0x75,0x6D,
+ 0x65,0x6E,0x74,0x73,0x20,0x69,0x6E,0x20,0x62,0x6C,0x6F,0x63,
+ 0x6B,0x20,0x64,0x6F,0x77,0x6E,0x2E,0x33,0x3E,0x41,0x6C,0x74,
+ 0x2B,0x46,0x32,0x20,0x40,0x54,0x31,0x36,0x30,0x54,0x72,0x61,
+ 0x6E,0x73,0x70,0x6F,0x73,0x65,0x20,0x61,0x6C,0x6C,0x20,0x69,
+ 0x6E,0x73,0x74,0x72,0x75,0x6D,0x65,0x6E,0x74,0x73,0x20,0x69,
+ 0x6E,0x20,0x62,0x6C,0x6F,0x63,0x6B,0x20,0x75,0x70,0x2E,0x01,
+ 0x3E,0x18,0x40,0x58,0x30,0x34,0x30,0x40,0x43,0x30,0x30,0x31,
+ 0x53,0x61,0x6D,0x70,0x6C,0x65,0x20,0x65,0x64,0x69,0x74,0x6F,
+ 0x72,0x3A,0x0B,0x3E,0x40,0x58,0x30,0x36,0x30,0x40,0x43,0x30,
+ 0x30,0x32,0x1A,0x41,0x6C,0x74,0x2F,0x43,0x74,0x72,0x6C,0x2B,
+ 0x41,0x20,0x40,0x54,0x31,0x36,0x30,0x52,0x61,0x6E,0x67,0x65,
+ 0x20,0x61,0x6C,0x6C,0x2E,0x17,0x3E,0x41,0x6C,0x74,0x2B,0x53,
+ 0x20,0x40,0x54,0x31,0x36,0x30,0x53,0x68,0x6F,0x77,0x20,0x72,
+ 0x61,0x6E,0x67,0x65,0x2E,0x15,0x3E,0x41,0x6C,0x74,0x2B,0x5A,
+ 0x20,0x40,0x54,0x31,0x36,0x30,0x5A,0x6F,0x6F,0x6D,0x20,0x6F,
+ 0x75,0x74,0x2E,0x1A,0x3E,0x41,0x6C,0x74,0x2B,0x58,0x20,0x6F,
+ 0x72,0x20,0x44,0x65,0x6C,0x65,0x74,0x65,0x20,0x40,0x54,0x31,
+ 0x36,0x30,0x43,0x75,0x74,0x2E,0x16,0x3E,0x41,0x6C,0x74,0x2F,
+ 0x43,0x74,0x72,0x6C,0x2B,0x43,0x20,0x40,0x54,0x31,0x36,0x30,
+ 0x43,0x6F,0x70,0x79,0x2E,0x17,0x3E,0x41,0x6C,0x74,0x2F,0x43,
+ 0x74,0x72,0x6C,0x2B,0x56,0x20,0x40,0x54,0x31,0x36,0x30,0x50,
+ 0x61,0x73,0x74,0x65,0x2E,0x11,0x3E,0x41,0x6C,0x74,0x2B,0x52,
+ 0x20,0x40,0x54,0x31,0x36,0x30,0x43,0x72,0x6F,0x70,0x2E,0x2A,
+ 0x3E,0x4D,0x6F,0x75,0x73,0x65,0x20,0x77,0x68,0x65,0x65,0x6C,
+ 0x20,0x40,0x54,0x31,0x36,0x30,0x5A,0x6F,0x6F,0x6D,0x20,0x73,
+ 0x61,0x6D,0x70,0x6C,0x65,0x20,0x64,0x61,0x74,0x61,0x20,0x69,
+ 0x6E,0x2F,0x6F,0x75,0x74,0x2E,0x00,0x21,0x40,0x58,0x30,0x34,
+ 0x30,0x40,0x43,0x30,0x30,0x31,0x4E,0x6F,0x74,0x65,0x20,0x66,
+ 0x6F,0x72,0x20,0x4D,0x61,0x63,0x20,0x6B,0x65,0x79,0x62,0x6F,
+ 0x61,0x72,0x64,0x73,0x3A,0x0B,0x3E,0x40,0x58,0x30,0x36,0x30,
+ 0x40,0x43,0x30,0x30,0x32,0x3A,0x55,0x73,0x65,0x20,0x6C,0x65,
+ 0x66,0x74,0x20,0x63,0x74,0x72,0x6C,0x2E,0x20,0x66,0x6F,0x72,
+ 0x20,0x41,0x2F,0x58,0x2F,0x43,0x2F,0x56,0x20,0x28,0x6D,0x61,
+ 0x72,0x6B,0x20,0x61,0x6C,0x6C,0x2F,0x63,0x75,0x74,0x2F,0x63,
+ 0x6F,0x70,0x79,0x2F,0x70,0x61,0x73,0x74,0x65,0x29,0x20,0x6B,
+ 0x65,0x79,0x73,0x2E,0x4B,0x3E,0x54,0x68,0x69,0x73,0x20,0x61,
+ 0x70,0x70,0x6C,0x69,0x65,0x73,0x20,0x74,0x6F,0x20,0x74,0x68,
+ 0x65,0x20,0x73,0x61,0x6D,0x70,0x6C,0x65,0x20,0x65,0x64,0x69,
+ 0x74,0x6F,0x72,0x20,0x28,0x41,0x2F,0x43,0x2F,0x56,0x20,0x6F,
+ 0x6E,0x6C,0x79,0x29,0x20,0x61,0x6E,0x64,0x20,0x74,0x65,0x78,
+ 0x74,0x20,0x6D,0x61,0x72,0x6B,0x69,0x6E,0x67,0x20,0x69,0x6E,
+ 0x20,0x74,0x68,0x65,0x20,0x55,0x49,0x2E,0x00,0x03,0x45,0x4E,
+ 0x44,0x4C,0x3B,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,
0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,
0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,
0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,
0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,
0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,
- 0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x4C,0x3B,0x2A,0x2A,
+ 0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x4C,0x3B,0x2A,0x2A,0x2A,0x2A,
0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,
0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,
0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,
0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,
0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,
- 0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,
- 0x2A,0x1B,0x40,0x4C,0x48,0x6F,0x77,0x20,0x74,0x6F,0x20,0x75,
- 0x73,0x65,0x20,0x46,0x61,0x73,0x74,0x74,0x72,0x61,0x63,0x6B,
- 0x65,0x72,0x20,0x49,0x49,0x0B,0x3E,0x40,0x58,0x30,0x34,0x30,
- 0x40,0x43,0x30,0x30,0x32,0x40,0x3E,0x41,0x6C,0x6C,0x20,0x22,
- 0x6E,0x6F,0x74,0x2D,0x74,0x6F,0x6F,0x2D,0x74,0x72,0x69,0x76,
- 0x69,0x61,0x6C,0x22,0x20,0x66,0x75,0x6E,0x63,0x74,0x69,0x6F,
- 0x6E,0x73,0x20,0x61,0x72,0x65,0x20,0x70,0x72,0x65,0x73,0x65,
- 0x6E,0x74,0x65,0x64,0x20,0x62,0x65,0x6C,0x6F,0x77,0x20,0x28,
- 0x6F,0x72,0x64,0x65,0x72,0x65,0x64,0x20,0x69,0x6E,0x22,0x77,
- 0x69,0x6E,0x64,0x6F,0x77,0x73,0x29,0x20,0x77,0x69,0x74,0x68,
- 0x20,0x61,0x20,0x73,0x68,0x6F,0x72,0x74,0x20,0x64,0x65,0x73,
- 0x63,0x72,0x69,0x70,0x74,0x69,0x6F,0x6E,0x2E,0x00,0x17,0x3E,
- 0x40,0x58,0x30,0x32,0x30,0x40,0x43,0x30,0x30,0x31,0x4D,0x61,
- 0x69,0x6E,0x20,0x73,0x63,0x72,0x65,0x65,0x6E,0x3A,0x01,0x3E,
- 0x22,0x3E,0x40,0x58,0x30,0x34,0x30,0x40,0x43,0x30,0x30,0x31,
- 0x42,0x50,0x4D,0x20,0x28,0x42,0x65,0x61,0x74,0x73,0x20,0x70,
- 0x65,0x72,0x20,0x6D,0x69,0x6E,0x75,0x74,0x65,0x29,0x3A,0x0B,
- 0x3E,0x40,0x58,0x30,0x36,0x30,0x40,0x43,0x30,0x30,0x32,0x40,
- 0x54,0x68,0x65,0x20,0x42,0x50,0x4D,0x20,0x73,0x65,0x74,0x74,
- 0x69,0x6E,0x67,0x20,0x64,0x65,0x66,0x69,0x6E,0x65,0x73,0x20,
- 0x68,0x6F,0x77,0x20,0x66,0x61,0x73,0x74,0x20,0x28,0x74,0x69,
- 0x63,0x6B,0x73,0x2F,0x73,0x65,0x63,0x6F,0x6E,0x64,0x29,0x20,
- 0x74,0x68,0x65,0x20,0x6D,0x75,0x73,0x69,0x63,0x20,0x70,0x6C,
- 0x61,0x79,0x65,0x72,0x1C,0x77,0x69,0x6C,0x6C,0x20,0x72,0x75,
- 0x6E,0x2E,0x20,0x31,0x32,0x35,0x20,0x42,0x50,0x4D,0x20,0x3C,
- 0x2D,0x3E,0x20,0x35,0x30,0x20,0x48,0x7A,0x2E,0x28,0x3E,0x4E,
- 0x75,0x6D,0x62,0x65,0x72,0x20,0x6F,0x66,0x20,0x70,0x6C,0x61,
- 0x79,0x65,0x72,0x20,0x74,0x69,0x63,0x6B,0x73,0x2F,0x73,0x65,
- 0x63,0x6F,0x6E,0x64,0x20,0x3D,0x20,0x42,0x50,0x4D,0x2A,0x32,
- 0x2F,0x35,0x00,0x16,0x3E,0x40,0x58,0x30,0x34,0x30,0x40,0x43,
- 0x30,0x30,0x31,0x53,0x70,0x64,0x2C,0x20,0x53,0x70,0x65,0x65,
- 0x64,0x3A,0x0B,0x3E,0x40,0x58,0x30,0x36,0x30,0x40,0x43,0x30,
- 0x30,0x32,0x2C,0x53,0x70,0x65,0x65,0x64,0x20,0x3D,0x20,0x6E,
- 0x75,0x6D,0x62,0x65,0x72,0x20,0x6F,0x66,0x20,0x70,0x6C,0x61,
- 0x79,0x65,0x72,0x20,0x74,0x69,0x63,0x6B,0x73,0x2F,0x70,0x61,
- 0x74,0x74,0x65,0x72,0x6E,0x20,0x6C,0x69,0x6E,0x65,0x2E,0x00,
- 0x0F,0x3E,0x40,0x58,0x30,0x34,0x30,0x40,0x43,0x30,0x30,0x31,
- 0x41,0x64,0x64,0x3A,0x0B,0x3E,0x40,0x58,0x30,0x36,0x30,0x40,
- 0x43,0x30,0x30,0x32,0x3E,0x22,0x41,0x64,0x64,0x22,0x20,0x69,
- 0x73,0x20,0x74,0x68,0x65,0x20,0x6E,0x75,0x6D,0x62,0x65,0x72,
- 0x20,0x6F,0x66,0x20,0x70,0x61,0x74,0x74,0x65,0x72,0x6E,0x20,
- 0x6C,0x69,0x6E,0x65,0x73,0x20,0x74,0x68,0x65,0x20,0x63,0x75,
- 0x72,0x73,0x6F,0x72,0x20,0x6A,0x75,0x6D,0x70,0x73,0x20,0x77,
- 0x68,0x65,0x6E,0x20,0x79,0x6F,0x75,0x0C,0x65,0x64,0x69,0x74,
- 0x20,0x61,0x20,0x6E,0x6F,0x74,0x65,0x2E,0x00,0x0F,0x3E,0x40,
- 0x58,0x30,0x34,0x30,0x40,0x43,0x30,0x30,0x31,0x50,0x74,0x6E,
- 0x3A,0x0B,0x3E,0x40,0x58,0x30,0x36,0x30,0x40,0x43,0x30,0x30,
- 0x32,0x1B,0x54,0x68,0x65,0x20,0x63,0x75,0x72,0x72,0x65,0x6E,
- 0x74,0x20,0x70,0x61,0x74,0x74,0x65,0x72,0x6E,0x20,0x6E,0x75,
- 0x6D,0x62,0x65,0x72,0x2E,0x00,0x0E,0x3E,0x40,0x58,0x30,0x34,
- 0x30,0x40,0x43,0x30,0x30,0x31,0x4C,0x6E,0x3A,0x0B,0x3E,0x40,
- 0x58,0x30,0x36,0x30,0x40,0x43,0x30,0x30,0x32,0x43,0x54,0x68,
- 0x65,0x20,0x6E,0x75,0x6D,0x62,0x65,0x72,0x20,0x6F,0x66,0x20,
- 0x6C,0x69,0x6E,0x65,0x73,0x20,0x66,0x6F,0x72,0x20,0x74,0x68,
- 0x65,0x20,0x63,0x75,0x72,0x72,0x65,0x6E,0x74,0x20,0x70,0x61,
- 0x74,0x74,0x65,0x72,0x6E,0x2E,0x20,0x55,0x70,0x20,0x74,0x6F,
- 0x20,0x24,0x31,0x30,0x30,0x20,0x6C,0x69,0x6E,0x65,0x73,0x2E,
- 0x20,0x4E,0x6F,0x74,0x65,0x40,0x74,0x68,0x61,0x74,0x20,0x46,
- 0x54,0x32,0x20,0x77,0x6F,0x6E,0x27,0x74,0x20,0x77,0x61,0x72,
- 0x6E,0x20,0x79,0x6F,0x75,0x20,0x69,0x66,0x20,0x79,0x6F,0x75,
- 0x20,0x64,0x65,0x63,0x72,0x65,0x61,0x73,0x65,0x20,0x74,0x68,
- 0x69,0x73,0x20,0x76,0x61,0x6C,0x75,0x65,0x2E,0x20,0x54,0x68,
- 0x65,0x20,0x6E,0x6F,0x74,0x65,0x73,0x20,0x61,0x74,0x37,0x74,
- 0x68,0x65,0x20,0x62,0x6F,0x74,0x74,0x6F,0x6D,0x20,0x6C,0x69,
- 0x6E,0x65,0x20,0x77,0x69,0x6C,0x6C,0x20,0x62,0x65,0x20,0x74,
- 0x68,0x72,0x6F,0x77,0x6E,0x20,0x6F,0x75,0x74,0x20,0x74,0x6F,
- 0x20,0x74,0x68,0x65,0x20,0x62,0x69,0x6E,0x61,0x72,0x79,0x20,
- 0x73,0x70,0x61,0x63,0x65,0x2E,0x00,0x10,0x3E,0x40,0x58,0x30,
- 0x34,0x30,0x40,0x43,0x30,0x30,0x31,0x45,0x78,0x70,0x64,0x3A,
+ 0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x1B,
+ 0x40,0x4C,0x48,0x6F,0x77,0x20,0x74,0x6F,0x20,0x75,0x73,0x65,
+ 0x20,0x46,0x61,0x73,0x74,0x74,0x72,0x61,0x63,0x6B,0x65,0x72,
+ 0x20,0x49,0x49,0x0B,0x3E,0x40,0x58,0x30,0x34,0x30,0x40,0x43,
+ 0x30,0x30,0x32,0x40,0x3E,0x41,0x6C,0x6C,0x20,0x22,0x6E,0x6F,
+ 0x74,0x2D,0x74,0x6F,0x6F,0x2D,0x74,0x72,0x69,0x76,0x69,0x61,
+ 0x6C,0x22,0x20,0x66,0x75,0x6E,0x63,0x74,0x69,0x6F,0x6E,0x73,
+ 0x20,0x61,0x72,0x65,0x20,0x70,0x72,0x65,0x73,0x65,0x6E,0x74,
+ 0x65,0x64,0x20,0x62,0x65,0x6C,0x6F,0x77,0x20,0x28,0x6F,0x72,
+ 0x64,0x65,0x72,0x65,0x64,0x20,0x69,0x6E,0x22,0x77,0x69,0x6E,
+ 0x64,0x6F,0x77,0x73,0x29,0x20,0x77,0x69,0x74,0x68,0x20,0x61,
+ 0x20,0x73,0x68,0x6F,0x72,0x74,0x20,0x64,0x65,0x73,0x63,0x72,
+ 0x69,0x70,0x74,0x69,0x6F,0x6E,0x2E,0x00,0x17,0x3E,0x40,0x58,
+ 0x30,0x32,0x30,0x40,0x43,0x30,0x30,0x31,0x4D,0x61,0x69,0x6E,
+ 0x20,0x73,0x63,0x72,0x65,0x65,0x6E,0x3A,0x01,0x3E,0x22,0x3E,
+ 0x40,0x58,0x30,0x34,0x30,0x40,0x43,0x30,0x30,0x31,0x42,0x50,
+ 0x4D,0x20,0x28,0x42,0x65,0x61,0x74,0x73,0x20,0x70,0x65,0x72,
+ 0x20,0x6D,0x69,0x6E,0x75,0x74,0x65,0x29,0x3A,0x0B,0x3E,0x40,
+ 0x58,0x30,0x36,0x30,0x40,0x43,0x30,0x30,0x32,0x40,0x54,0x68,
+ 0x65,0x20,0x42,0x50,0x4D,0x20,0x73,0x65,0x74,0x74,0x69,0x6E,
+ 0x67,0x20,0x64,0x65,0x66,0x69,0x6E,0x65,0x73,0x20,0x68,0x6F,
+ 0x77,0x20,0x66,0x61,0x73,0x74,0x20,0x28,0x74,0x69,0x63,0x6B,
+ 0x73,0x2F,0x73,0x65,0x63,0x6F,0x6E,0x64,0x29,0x20,0x74,0x68,
+ 0x65,0x20,0x6D,0x75,0x73,0x69,0x63,0x20,0x70,0x6C,0x61,0x79,
+ 0x65,0x72,0x1C,0x77,0x69,0x6C,0x6C,0x20,0x72,0x75,0x6E,0x2E,
+ 0x20,0x31,0x32,0x35,0x20,0x42,0x50,0x4D,0x20,0x3C,0x2D,0x3E,
+ 0x20,0x35,0x30,0x20,0x48,0x7A,0x2E,0x28,0x3E,0x4E,0x75,0x6D,
+ 0x62,0x65,0x72,0x20,0x6F,0x66,0x20,0x70,0x6C,0x61,0x79,0x65,
+ 0x72,0x20,0x74,0x69,0x63,0x6B,0x73,0x2F,0x73,0x65,0x63,0x6F,
+ 0x6E,0x64,0x20,0x3D,0x20,0x42,0x50,0x4D,0x2A,0x32,0x2F,0x35,
+ 0x00,0x16,0x3E,0x40,0x58,0x30,0x34,0x30,0x40,0x43,0x30,0x30,
+ 0x31,0x53,0x70,0x64,0x2C,0x20,0x53,0x70,0x65,0x65,0x64,0x3A,
0x0B,0x3E,0x40,0x58,0x30,0x36,0x30,0x40,0x43,0x30,0x30,0x32,
- 0x44,0x45,0x78,0x70,0x61,0x6E,0x64,0x20,0x70,0x61,0x74,0x74,
- 0x65,0x72,0x6E,0x2E,0x20,0x49,0x6E,0x73,0x65,0x72,0x74,0x73,
- 0x20,0x61,0x20,0x62,0x6C,0x61,0x6E,0x6B,0x20,0x6C,0x69,0x6E,
- 0x65,0x20,0x61,0x66,0x74,0x65,0x72,0x20,0x65,0x61,0x63,0x68,
- 0x20,0x70,0x61,0x74,0x74,0x65,0x72,0x6E,0x20,0x6C,0x69,0x6E,
- 0x65,0x2E,0x20,0x55,0x73,0x65,0x66,0x75,0x6C,0x3C,0x69,0x66,
- 0x20,0x79,0x6F,0x75,0x20,0x77,0x61,0x6E,0x74,0x20,0x74,0x6F,
- 0x20,0x63,0x6F,0x6E,0x76,0x65,0x72,0x74,0x20,0x61,0x20,0x70,
- 0x61,0x74,0x74,0x65,0x72,0x6E,0x20,0x74,0x68,0x61,0x74,0x20,
- 0x72,0x75,0x6E,0x73,0x20,0x69,0x6E,0x20,0x73,0x70,0x65,0x65,
- 0x64,0x20,0x32,0x2A,0x78,0x20,0x74,0x6F,0x20,0x61,0x1D,0x70,
- 0x61,0x74,0x74,0x65,0x72,0x6E,0x20,0x74,0x68,0x61,0x74,0x20,
- 0x72,0x75,0x6E,0x73,0x20,0x69,0x6E,0x20,0x73,0x70,0x65,0x65,
- 0x64,0x20,0x78,0x2E,0x00,0x10,0x3E,0x40,0x58,0x30,0x34,0x30,
- 0x40,0x43,0x30,0x30,0x31,0x53,0x68,0x6E,0x6B,0x3A,0x0B,0x3E,
- 0x40,0x58,0x30,0x36,0x30,0x40,0x43,0x30,0x30,0x32,0x2E,0x53,
- 0x68,0x72,0x69,0x6E,0x6B,0x20,0x70,0x61,0x74,0x74,0x65,0x72,
- 0x6E,0x2E,0x20,0x44,0x65,0x6C,0x65,0x74,0x65,0x73,0x20,0x61,
- 0x6C,0x6C,0x20,0x6F,0x64,0x64,0x20,0x70,0x61,0x74,0x74,0x65,
- 0x72,0x6E,0x20,0x6C,0x69,0x6E,0x65,0x73,0x2E,0x00,0x2A,0x3E,
- 0x40,0x58,0x30,0x34,0x30,0x40,0x43,0x30,0x30,0x31,0x54,0x68,
- 0x65,0x20,0x69,0x6E,0x73,0x74,0x72,0x75,0x6D,0x65,0x6E,0x74,
- 0x2F,0x73,0x61,0x6D,0x70,0x6C,0x65,0x20,0x73,0x65,0x6C,0x65,
- 0x63,0x74,0x6F,0x72,0x3A,0x0B,0x3E,0x40,0x58,0x30,0x36,0x30,
- 0x40,0x43,0x30,0x30,0x32,0x3A,0x54,0x68,0x65,0x20,0x69,0x6E,
- 0x73,0x74,0x72,0x75,0x6D,0x65,0x6E,0x74,0x20,0x74,0x68,0x61,
- 0x74,0x20,0x68,0x61,0x73,0x20,0x61,0x20,0x6D,0x61,0x72,0x6B,
- 0x20,0x6F,0x6E,0x20,0x69,0x74,0x27,0x73,0x20,0x6E,0x61,0x6D,
- 0x65,0x20,0x73,0x74,0x72,0x69,0x6E,0x67,0x2C,0x20,0x69,0x73,
- 0x20,0x74,0x68,0x65,0x17,0x64,0x65,0x73,0x74,0x69,0x6E,0x61,
- 0x74,0x69,0x6F,0x6E,0x20,0x69,0x6E,0x73,0x74,0x72,0x75,0x6D,
- 0x65,0x6E,0x74,0x2E,0x3D,0x3E,0x54,0x68,0x65,0x20,0x69,0x6E,
- 0x73,0x74,0x72,0x75,0x6D,0x65,0x6E,0x74,0x20,0x74,0x68,0x61,
- 0x74,0x20,0x68,0x61,0x73,0x20,0x61,0x20,0x6D,0x61,0x72,0x6B,
- 0x20,0x6F,0x6E,0x20,0x69,0x74,0x27,0x73,0x20,0x6E,0x75,0x6D,
- 0x62,0x65,0x72,0x2C,0x20,0x69,0x73,0x20,0x74,0x68,0x65,0x20,
- 0x73,0x6F,0x75,0x72,0x63,0x65,0x0B,0x69,0x6E,0x73,0x74,0x72,
- 0x75,0x6D,0x65,0x6E,0x74,0x2E,0x1F,0x3E,0x54,0x68,0x65,0x20,
- 0x73,0x61,0x6D,0x65,0x20,0x67,0x6F,0x65,0x73,0x20,0x66,0x6F,
- 0x72,0x20,0x74,0x68,0x65,0x20,0x73,0x61,0x6D,0x70,0x6C,0x65,
- 0x73,0x2E,0x42,0x3E,0x59,0x6F,0x75,0x20,0x63,0x68,0x61,0x6E,
- 0x67,0x65,0x20,0x74,0x68,0x65,0x20,0x6E,0x61,0x6D,0x65,0x20,
- 0x6F,0x6E,0x20,0x61,0x6E,0x20,0x69,0x6E,0x73,0x74,0x72,0x75,
- 0x6D,0x65,0x6E,0x74,0x2F,0x73,0x61,0x6D,0x70,0x6C,0x65,0x20,
- 0x62,0x79,0x20,0x63,0x6C,0x69,0x63,0x6B,0x69,0x6E,0x67,0x20,
- 0x74,0x68,0x65,0x20,0x72,0x69,0x67,0x68,0x74,0x07,0x62,0x75,
- 0x74,0x74,0x6F,0x6E,0x2E,0x00,0x12,0x3E,0x40,0x58,0x30,0x32,
- 0x30,0x40,0x43,0x30,0x30,0x31,0x53,0x63,0x6F,0x70,0x65,0x73,
- 0x3A,0x0B,0x3E,0x40,0x58,0x30,0x36,0x30,0x40,0x43,0x30,0x30,
- 0x32,0x22,0x3E,0x4C,0x65,0x66,0x74,0x20,0x62,0x75,0x74,0x74,
- 0x6F,0x6E,0x3A,0x20,0x54,0x75,0x72,0x6E,0x20,0x63,0x68,0x61,
- 0x6E,0x6E,0x65,0x6C,0x20,0x6F,0x6E,0x2F,0x6F,0x66,0x66,0x2E,
- 0x35,0x3E,0x52,0x69,0x67,0x68,0x74,0x20,0x62,0x75,0x74,0x74,
- 0x6F,0x6E,0x3A,0x20,0x54,0x75,0x72,0x6E,0x20,0x63,0x68,0x61,
- 0x6E,0x6E,0x65,0x6C,0x20,0x6D,0x75,0x6C,0x74,0x69,0x2D,0x72,
- 0x65,0x63,0x6F,0x72,0x64,0x2F,0x65,0x64,0x69,0x74,0x20,0x6F,
- 0x6E,0x2F,0x6F,0x66,0x66,0x2E,0x42,0x3E,0x4C,0x65,0x66,0x74,
- 0x2B,0x72,0x69,0x67,0x68,0x74,0x20,0x62,0x75,0x74,0x74,0x6F,
- 0x6E,0x3A,0x20,0x54,0x75,0x72,0x6E,0x20,0x61,0x6C,0x6C,0x20,
- 0x63,0x68,0x61,0x6E,0x6E,0x65,0x6C,0x73,0x20,0x6F,0x66,0x66,
- 0x20,0x65,0x78,0x63,0x65,0x70,0x74,0x20,0x74,0x68,0x65,0x20,
- 0x73,0x65,0x6C,0x65,0x63,0x74,0x65,0x64,0x20,0x6F,0x6E,0x65,
- 0x2E,0x00,0x1C,0x40,0x58,0x30,0x32,0x30,0x40,0x43,0x30,0x30,
- 0x31,0x49,0x6E,0x73,0x74,0x72,0x75,0x6D,0x65,0x6E,0x74,0x20,
- 0x45,0x64,0x69,0x74,0x6F,0x72,0x3A,0x01,0x3E,0x22,0x3E,0x40,
- 0x58,0x30,0x34,0x30,0x40,0x43,0x30,0x30,0x31,0x57,0x68,0x61,
- 0x74,0x20,0x69,0x73,0x20,0x61,0x6E,0x20,0x69,0x6E,0x73,0x74,
- 0x72,0x75,0x6D,0x65,0x6E,0x74,0x3F,0x3A,0x0B,0x3E,0x40,0x58,
- 0x30,0x36,0x30,0x40,0x43,0x30,0x30,0x32,0x1E,0x41,0x20,0x46,
+ 0x2C,0x53,0x70,0x65,0x65,0x64,0x20,0x3D,0x20,0x6E,0x75,0x6D,
+ 0x62,0x65,0x72,0x20,0x6F,0x66,0x20,0x70,0x6C,0x61,0x79,0x65,
+ 0x72,0x20,0x74,0x69,0x63,0x6B,0x73,0x2F,0x70,0x61,0x74,0x74,
+ 0x65,0x72,0x6E,0x20,0x6C,0x69,0x6E,0x65,0x2E,0x00,0x0F,0x3E,
+ 0x40,0x58,0x30,0x34,0x30,0x40,0x43,0x30,0x30,0x31,0x41,0x64,
+ 0x64,0x3A,0x0B,0x3E,0x40,0x58,0x30,0x36,0x30,0x40,0x43,0x30,
+ 0x30,0x32,0x3E,0x22,0x41,0x64,0x64,0x22,0x20,0x69,0x73,0x20,
+ 0x74,0x68,0x65,0x20,0x6E,0x75,0x6D,0x62,0x65,0x72,0x20,0x6F,
+ 0x66,0x20,0x70,0x61,0x74,0x74,0x65,0x72,0x6E,0x20,0x6C,0x69,
+ 0x6E,0x65,0x73,0x20,0x74,0x68,0x65,0x20,0x63,0x75,0x72,0x73,
+ 0x6F,0x72,0x20,0x6A,0x75,0x6D,0x70,0x73,0x20,0x77,0x68,0x65,
+ 0x6E,0x20,0x79,0x6F,0x75,0x0C,0x65,0x64,0x69,0x74,0x20,0x61,
+ 0x20,0x6E,0x6F,0x74,0x65,0x2E,0x00,0x0F,0x3E,0x40,0x58,0x30,
+ 0x34,0x30,0x40,0x43,0x30,0x30,0x31,0x50,0x74,0x6E,0x3A,0x0B,
+ 0x3E,0x40,0x58,0x30,0x36,0x30,0x40,0x43,0x30,0x30,0x32,0x1B,
+ 0x54,0x68,0x65,0x20,0x63,0x75,0x72,0x72,0x65,0x6E,0x74,0x20,
+ 0x70,0x61,0x74,0x74,0x65,0x72,0x6E,0x20,0x6E,0x75,0x6D,0x62,
+ 0x65,0x72,0x2E,0x00,0x0E,0x3E,0x40,0x58,0x30,0x34,0x30,0x40,
+ 0x43,0x30,0x30,0x31,0x4C,0x6E,0x3A,0x0B,0x3E,0x40,0x58,0x30,
+ 0x36,0x30,0x40,0x43,0x30,0x30,0x32,0x43,0x54,0x68,0x65,0x20,
+ 0x6E,0x75,0x6D,0x62,0x65,0x72,0x20,0x6F,0x66,0x20,0x6C,0x69,
+ 0x6E,0x65,0x73,0x20,0x66,0x6F,0x72,0x20,0x74,0x68,0x65,0x20,
+ 0x63,0x75,0x72,0x72,0x65,0x6E,0x74,0x20,0x70,0x61,0x74,0x74,
+ 0x65,0x72,0x6E,0x2E,0x20,0x55,0x70,0x20,0x74,0x6F,0x20,0x24,
+ 0x31,0x30,0x30,0x20,0x6C,0x69,0x6E,0x65,0x73,0x2E,0x20,0x4E,
+ 0x6F,0x74,0x65,0x40,0x74,0x68,0x61,0x74,0x20,0x46,0x54,0x32,
+ 0x20,0x77,0x6F,0x6E,0x27,0x74,0x20,0x77,0x61,0x72,0x6E,0x20,
+ 0x79,0x6F,0x75,0x20,0x69,0x66,0x20,0x79,0x6F,0x75,0x20,0x64,
+ 0x65,0x63,0x72,0x65,0x61,0x73,0x65,0x20,0x74,0x68,0x69,0x73,
+ 0x20,0x76,0x61,0x6C,0x75,0x65,0x2E,0x20,0x54,0x68,0x65,0x20,
+ 0x6E,0x6F,0x74,0x65,0x73,0x20,0x61,0x74,0x37,0x74,0x68,0x65,
+ 0x20,0x62,0x6F,0x74,0x74,0x6F,0x6D,0x20,0x6C,0x69,0x6E,0x65,
+ 0x20,0x77,0x69,0x6C,0x6C,0x20,0x62,0x65,0x20,0x74,0x68,0x72,
+ 0x6F,0x77,0x6E,0x20,0x6F,0x75,0x74,0x20,0x74,0x6F,0x20,0x74,
+ 0x68,0x65,0x20,0x62,0x69,0x6E,0x61,0x72,0x79,0x20,0x73,0x70,
+ 0x61,0x63,0x65,0x2E,0x00,0x10,0x3E,0x40,0x58,0x30,0x34,0x30,
+ 0x40,0x43,0x30,0x30,0x31,0x45,0x78,0x70,0x64,0x3A,0x0B,0x3E,
+ 0x40,0x58,0x30,0x36,0x30,0x40,0x43,0x30,0x30,0x32,0x44,0x45,
+ 0x78,0x70,0x61,0x6E,0x64,0x20,0x70,0x61,0x74,0x74,0x65,0x72,
+ 0x6E,0x2E,0x20,0x49,0x6E,0x73,0x65,0x72,0x74,0x73,0x20,0x61,
+ 0x20,0x62,0x6C,0x61,0x6E,0x6B,0x20,0x6C,0x69,0x6E,0x65,0x20,
+ 0x61,0x66,0x74,0x65,0x72,0x20,0x65,0x61,0x63,0x68,0x20,0x70,
+ 0x61,0x74,0x74,0x65,0x72,0x6E,0x20,0x6C,0x69,0x6E,0x65,0x2E,
+ 0x20,0x55,0x73,0x65,0x66,0x75,0x6C,0x3C,0x69,0x66,0x20,0x79,
+ 0x6F,0x75,0x20,0x77,0x61,0x6E,0x74,0x20,0x74,0x6F,0x20,0x63,
+ 0x6F,0x6E,0x76,0x65,0x72,0x74,0x20,0x61,0x20,0x70,0x61,0x74,
+ 0x74,0x65,0x72,0x6E,0x20,0x74,0x68,0x61,0x74,0x20,0x72,0x75,
+ 0x6E,0x73,0x20,0x69,0x6E,0x20,0x73,0x70,0x65,0x65,0x64,0x20,
+ 0x32,0x2A,0x78,0x20,0x74,0x6F,0x20,0x61,0x1D,0x70,0x61,0x74,
+ 0x74,0x65,0x72,0x6E,0x20,0x74,0x68,0x61,0x74,0x20,0x72,0x75,
+ 0x6E,0x73,0x20,0x69,0x6E,0x20,0x73,0x70,0x65,0x65,0x64,0x20,
+ 0x78,0x2E,0x00,0x10,0x3E,0x40,0x58,0x30,0x34,0x30,0x40,0x43,
+ 0x30,0x30,0x31,0x53,0x68,0x6E,0x6B,0x3A,0x0B,0x3E,0x40,0x58,
+ 0x30,0x36,0x30,0x40,0x43,0x30,0x30,0x32,0x2E,0x53,0x68,0x72,
+ 0x69,0x6E,0x6B,0x20,0x70,0x61,0x74,0x74,0x65,0x72,0x6E,0x2E,
+ 0x20,0x44,0x65,0x6C,0x65,0x74,0x65,0x73,0x20,0x61,0x6C,0x6C,
+ 0x20,0x6F,0x64,0x64,0x20,0x70,0x61,0x74,0x74,0x65,0x72,0x6E,
+ 0x20,0x6C,0x69,0x6E,0x65,0x73,0x2E,0x00,0x2A,0x3E,0x40,0x58,
+ 0x30,0x34,0x30,0x40,0x43,0x30,0x30,0x31,0x54,0x68,0x65,0x20,
+ 0x69,0x6E,0x73,0x74,0x72,0x75,0x6D,0x65,0x6E,0x74,0x2F,0x73,
+ 0x61,0x6D,0x70,0x6C,0x65,0x20,0x73,0x65,0x6C,0x65,0x63,0x74,
+ 0x6F,0x72,0x3A,0x0B,0x3E,0x40,0x58,0x30,0x36,0x30,0x40,0x43,
+ 0x30,0x30,0x32,0x3A,0x54,0x68,0x65,0x20,0x69,0x6E,0x73,0x74,
+ 0x72,0x75,0x6D,0x65,0x6E,0x74,0x20,0x74,0x68,0x61,0x74,0x20,
+ 0x68,0x61,0x73,0x20,0x61,0x20,0x6D,0x61,0x72,0x6B,0x20,0x6F,
+ 0x6E,0x20,0x69,0x74,0x27,0x73,0x20,0x6E,0x61,0x6D,0x65,0x20,
+ 0x73,0x74,0x72,0x69,0x6E,0x67,0x2C,0x20,0x69,0x73,0x20,0x74,
+ 0x68,0x65,0x17,0x64,0x65,0x73,0x74,0x69,0x6E,0x61,0x74,0x69,
+ 0x6F,0x6E,0x20,0x69,0x6E,0x73,0x74,0x72,0x75,0x6D,0x65,0x6E,
+ 0x74,0x2E,0x3D,0x3E,0x54,0x68,0x65,0x20,0x69,0x6E,0x73,0x74,
+ 0x72,0x75,0x6D,0x65,0x6E,0x74,0x20,0x74,0x68,0x61,0x74,0x20,
+ 0x68,0x61,0x73,0x20,0x61,0x20,0x6D,0x61,0x72,0x6B,0x20,0x6F,
+ 0x6E,0x20,0x69,0x74,0x27,0x73,0x20,0x6E,0x75,0x6D,0x62,0x65,
+ 0x72,0x2C,0x20,0x69,0x73,0x20,0x74,0x68,0x65,0x20,0x73,0x6F,
+ 0x75,0x72,0x63,0x65,0x0B,0x69,0x6E,0x73,0x74,0x72,0x75,0x6D,
+ 0x65,0x6E,0x74,0x2E,0x1F,0x3E,0x54,0x68,0x65,0x20,0x73,0x61,
+ 0x6D,0x65,0x20,0x67,0x6F,0x65,0x73,0x20,0x66,0x6F,0x72,0x20,
+ 0x74,0x68,0x65,0x20,0x73,0x61,0x6D,0x70,0x6C,0x65,0x73,0x2E,
+ 0x42,0x3E,0x59,0x6F,0x75,0x20,0x63,0x68,0x61,0x6E,0x67,0x65,
+ 0x20,0x74,0x68,0x65,0x20,0x6E,0x61,0x6D,0x65,0x20,0x6F,0x6E,
+ 0x20,0x61,0x6E,0x20,0x69,0x6E,0x73,0x74,0x72,0x75,0x6D,0x65,
+ 0x6E,0x74,0x2F,0x73,0x61,0x6D,0x70,0x6C,0x65,0x20,0x62,0x79,
+ 0x20,0x63,0x6C,0x69,0x63,0x6B,0x69,0x6E,0x67,0x20,0x74,0x68,
+ 0x65,0x20,0x72,0x69,0x67,0x68,0x74,0x07,0x62,0x75,0x74,0x74,
+ 0x6F,0x6E,0x2E,0x00,0x12,0x3E,0x40,0x58,0x30,0x32,0x30,0x40,
+ 0x43,0x30,0x30,0x31,0x53,0x63,0x6F,0x70,0x65,0x73,0x3A,0x0B,
+ 0x3E,0x40,0x58,0x30,0x36,0x30,0x40,0x43,0x30,0x30,0x32,0x22,
+ 0x3E,0x4C,0x65,0x66,0x74,0x20,0x62,0x75,0x74,0x74,0x6F,0x6E,
+ 0x3A,0x20,0x54,0x75,0x72,0x6E,0x20,0x63,0x68,0x61,0x6E,0x6E,
+ 0x65,0x6C,0x20,0x6F,0x6E,0x2F,0x6F,0x66,0x66,0x2E,0x35,0x3E,
+ 0x52,0x69,0x67,0x68,0x74,0x20,0x62,0x75,0x74,0x74,0x6F,0x6E,
+ 0x3A,0x20,0x54,0x75,0x72,0x6E,0x20,0x63,0x68,0x61,0x6E,0x6E,
+ 0x65,0x6C,0x20,0x6D,0x75,0x6C,0x74,0x69,0x2D,0x72,0x65,0x63,
+ 0x6F,0x72,0x64,0x2F,0x65,0x64,0x69,0x74,0x20,0x6F,0x6E,0x2F,
+ 0x6F,0x66,0x66,0x2E,0x42,0x3E,0x4C,0x65,0x66,0x74,0x2B,0x72,
+ 0x69,0x67,0x68,0x74,0x20,0x62,0x75,0x74,0x74,0x6F,0x6E,0x3A,
+ 0x20,0x54,0x75,0x72,0x6E,0x20,0x61,0x6C,0x6C,0x20,0x63,0x68,
+ 0x61,0x6E,0x6E,0x65,0x6C,0x73,0x20,0x6F,0x66,0x66,0x20,0x65,
+ 0x78,0x63,0x65,0x70,0x74,0x20,0x74,0x68,0x65,0x20,0x73,0x65,
+ 0x6C,0x65,0x63,0x74,0x65,0x64,0x20,0x6F,0x6E,0x65,0x2E,0x00,
+ 0x1C,0x40,0x58,0x30,0x32,0x30,0x40,0x43,0x30,0x30,0x31,0x49,
+ 0x6E,0x73,0x74,0x72,0x75,0x6D,0x65,0x6E,0x74,0x20,0x45,0x64,
+ 0x69,0x74,0x6F,0x72,0x3A,0x01,0x3E,0x22,0x3E,0x40,0x58,0x30,
+ 0x34,0x30,0x40,0x43,0x30,0x30,0x31,0x57,0x68,0x61,0x74,0x20,
+ 0x69,0x73,0x20,0x61,0x6E,0x20,0x69,0x6E,0x73,0x74,0x72,0x75,
+ 0x6D,0x65,0x6E,0x74,0x3F,0x3A,0x0B,0x3E,0x40,0x58,0x30,0x36,
+ 0x30,0x40,0x43,0x30,0x30,0x32,0x1E,0x41,0x20,0x46,0x61,0x73,
+ 0x74,0x74,0x72,0x61,0x63,0x6B,0x65,0x72,0x20,0x32,0x20,0x69,
+ 0x6E,0x73,0x74,0x72,0x75,0x6D,0x65,0x6E,0x74,0x20,0x69,0x73,
+ 0x3A,0x15,0x3E,0x20,0x20,0x20,0x31,0x20,0x56,0x6F,0x6C,0x75,
+ 0x6D,0x65,0x20,0x65,0x6E,0x76,0x65,0x6C,0x6F,0x70,0x65,0x16,
+ 0x3E,0x20,0x20,0x20,0x31,0x20,0x50,0x61,0x6E,0x6E,0x69,0x6E,
+ 0x67,0x20,0x65,0x6E,0x76,0x65,0x6C,0x6F,0x70,0x65,0x1D,0x3E,
+ 0x20,0x20,0x20,0x31,0x20,0x41,0x75,0x74,0x6F,0x2D,0x76,0x69,
+ 0x62,0x72,0x61,0x74,0x6F,0x20,0x64,0x65,0x66,0x69,0x6E,0x69,
+ 0x74,0x69,0x6F,0x6E,0x13,0x3E,0x20,0x20,0x20,0x31,0x2E,0x2E,
+ 0x31,0x36,0x20,0x73,0x61,0x6D,0x70,0x6C,0x65,0x28,0x73,0x29,
+ 0x1F,0x3E,0x20,0x20,0x20,0x31,0x20,0x4B,0x65,0x79,0x62,0x6F,
+ 0x61,0x72,0x64,0x20,0x73,0x70,0x6C,0x69,0x74,0x20,0x64,0x65,
+ 0x66,0x69,0x6E,0x69,0x74,0x69,0x6F,0x6E,0x15,0x3E,0x20,0x20,
+ 0x20,0x31,0x20,0x4D,0x49,0x44,0x49,0x20,0x64,0x65,0x66,0x69,
+ 0x6E,0x69,0x74,0x69,0x6F,0x6E,0x00,0x1B,0x3E,0x41,0x20,0x46,
0x61,0x73,0x74,0x74,0x72,0x61,0x63,0x6B,0x65,0x72,0x20,0x32,
- 0x20,0x69,0x6E,0x73,0x74,0x72,0x75,0x6D,0x65,0x6E,0x74,0x20,
- 0x69,0x73,0x3A,0x15,0x3E,0x20,0x20,0x20,0x31,0x20,0x56,0x6F,
- 0x6C,0x75,0x6D,0x65,0x20,0x65,0x6E,0x76,0x65,0x6C,0x6F,0x70,
- 0x65,0x16,0x3E,0x20,0x20,0x20,0x31,0x20,0x50,0x61,0x6E,0x6E,
- 0x69,0x6E,0x67,0x20,0x65,0x6E,0x76,0x65,0x6C,0x6F,0x70,0x65,
- 0x1D,0x3E,0x20,0x20,0x20,0x31,0x20,0x41,0x75,0x74,0x6F,0x2D,
- 0x76,0x69,0x62,0x72,0x61,0x74,0x6F,0x20,0x64,0x65,0x66,0x69,
- 0x6E,0x69,0x74,0x69,0x6F,0x6E,0x13,0x3E,0x20,0x20,0x20,0x31,
- 0x2E,0x2E,0x31,0x36,0x20,0x53,0x61,0x6D,0x70,0x6C,0x65,0x28,
- 0x73,0x29,0x1F,0x3E,0x20,0x20,0x20,0x31,0x20,0x4B,0x65,0x79,
- 0x62,0x6F,0x61,0x72,0x64,0x20,0x73,0x70,0x6C,0x69,0x74,0x20,
- 0x64,0x65,0x66,0x69,0x6E,0x69,0x74,0x69,0x6F,0x6E,0x15,0x3E,
- 0x20,0x20,0x20,0x31,0x20,0x4D,0x49,0x44,0x49,0x20,0x64,0x65,
- 0x66,0x69,0x6E,0x69,0x74,0x69,0x6F,0x6E,0x00,0x1B,0x3E,0x41,
- 0x20,0x46,0x61,0x73,0x74,0x74,0x72,0x61,0x63,0x6B,0x65,0x72,
- 0x20,0x32,0x20,0x73,0x61,0x6D,0x70,0x6C,0x65,0x20,0x69,0x73,
- 0x3A,0x29,0x3E,0x20,0x20,0x20,0x31,0x20,0x56,0x6F,0x6C,0x75,
- 0x6D,0x65,0x2F,0x50,0x61,0x6E,0x6E,0x69,0x6E,0x67,0x2F,0x46,
- 0x69,0x6E,0x65,0x2D,0x74,0x75,0x6E,0x65,0x20,0x64,0x65,0x66,
- 0x69,0x6E,0x69,0x74,0x69,0x6F,0x6E,0x14,0x3E,0x20,0x20,0x20,
- 0x31,0x20,0x52,0x65,0x6C,0x61,0x74,0x69,0x76,0x65,0x20,0x74,
- 0x6F,0x6E,0x65,0x2E,0x10,0x3E,0x20,0x20,0x20,0x31,0x20,0x57,
- 0x61,0x76,0x65,0x20,0x66,0x6F,0x72,0x6D,0x2E,0x00,0x1F,0x3E,
- 0x40,0x58,0x30,0x34,0x30,0x40,0x43,0x30,0x30,0x31,0x54,0x68,
- 0x65,0x20,0x76,0x6F,0x6C,0x75,0x6D,0x65,0x20,0x65,0x6E,0x76,
- 0x65,0x6C,0x6F,0x70,0x65,0x3A,0x0B,0x3E,0x40,0x58,0x30,0x36,
- 0x30,0x40,0x43,0x30,0x30,0x32,0x40,0x3E,0x41,0x6E,0x20,0x69,
- 0x6E,0x73,0x74,0x72,0x75,0x6D,0x65,0x6E,0x74,0x27,0x73,0x20,
- 0x76,0x6F,0x6C,0x75,0x6D,0x65,0x20,0x69,0x73,0x20,0x64,0x65,
- 0x66,0x69,0x6E,0x65,0x64,0x20,0x62,0x79,0x20,0x69,0x74,0x73,
- 0x20,0x65,0x6E,0x76,0x65,0x6C,0x6F,0x70,0x65,0x20,0x63,0x75,
- 0x72,0x76,0x65,0x2E,0x20,0x49,0x66,0x20,0x74,0x68,0x65,0x3E,
- 0x69,0x6E,0x73,0x74,0x72,0x75,0x6D,0x65,0x6E,0x74,0x20,0x68,
- 0x61,0x73,0x20,0x61,0x20,0x73,0x75,0x73,0x74,0x61,0x69,0x6E,
- 0x20,0x70,0x6F,0x69,0x6E,0x74,0x2C,0x20,0x74,0x68,0x65,0x20,
- 0x65,0x6E,0x76,0x65,0x6C,0x6F,0x70,0x65,0x20,0x77,0x69,0x6C,
- 0x6C,0x20,0x73,0x74,0x6F,0x70,0x20,0x61,0x74,0x20,0x74,0x68,
- 0x61,0x74,0x42,0x70,0x6F,0x69,0x6E,0x74,0x20,0x75,0x6E,0x74,
- 0x69,0x6C,0x20,0x61,0x20,0x6B,0x65,0x79,0x2D,0x6F,0x66,0x66,
- 0x20,0x6E,0x6F,0x74,0x65,0x20,0x68,0x61,0x73,0x20,0x62,0x65,
- 0x65,0x6E,0x20,0x70,0x6C,0x61,0x79,0x65,0x64,0x2E,0x20,0x57,
- 0x68,0x65,0x6E,0x20,0x61,0x20,0x6B,0x65,0x79,0x2D,0x6F,0x66,
- 0x66,0x20,0x6E,0x6F,0x74,0x65,0x20,0x69,0x73,0x1D,0x70,0x6C,
- 0x61,0x79,0x65,0x64,0x2C,0x20,0x74,0x68,0x65,0x20,0x22,0x66,
- 0x61,0x64,0x65,0x6F,0x75,0x74,0x22,0x20,0x62,0x65,0x67,0x69,
- 0x6E,0x73,0x2E,0x44,0x3E,0x4F,0x6E,0x65,0x20,0x70,0x69,0x78,
- 0x65,0x6C,0x20,0x69,0x6E,0x20,0x74,0x68,0x65,0x20,0x65,0x6E,
- 0x76,0x65,0x6C,0x6F,0x70,0x65,0x20,0x77,0x69,0x6E,0x64,0x6F,
- 0x77,0x20,0x63,0x6F,0x72,0x72,0x65,0x73,0x70,0x6F,0x6E,0x64,
- 0x73,0x20,0x74,0x6F,0x20,0x6F,0x6E,0x65,0x20,0x70,0x6C,0x61,
- 0x79,0x65,0x72,0x2D,0x74,0x69,0x63,0x6B,0x2E,0x20,0x49,0x66,
- 0x3C,0x74,0x68,0x65,0x20,0x42,0x50,0x4D,0x20,0x69,0x73,0x20,
- 0x31,0x32,0x35,0x2C,0x20,0x79,0x6F,0x75,0x27,0x6C,0x6C,0x20,
- 0x63,0x6F,0x6E,0x73,0x75,0x6D,0x65,0x20,0x35,0x30,0x20,0x70,
- 0x69,0x78,0x65,0x6C,0x2F,0x73,0x65,0x63,0x6F,0x6E,0x64,0x2E,
- 0x20,0x54,0x68,0x65,0x20,0x77,0x69,0x6E,0x64,0x6F,0x77,0x27,
- 0x73,0x1A,0x22,0x73,0x69,0x7A,0x65,0x22,0x20,0x69,0x73,0x20,
- 0x61,0x62,0x6F,0x75,0x74,0x20,0x36,0x20,0x73,0x65,0x63,0x6F,
- 0x6E,0x64,0x73,0x2E,0x3E,0x3E,0x49,0x66,0x20,0x79,0x6F,0x75,
- 0x20,0x70,0x72,0x65,0x73,0x73,0x20,0x74,0x68,0x65,0x20,0x72,
- 0x69,0x67,0x68,0x74,0x20,0x6D,0x6F,0x75,0x73,0x65,0x20,0x62,
- 0x75,0x74,0x74,0x6F,0x6E,0x20,0x61,0x74,0x20,0x74,0x68,0x65,
- 0x20,0x70,0x72,0x65,0x64,0x65,0x66,0x69,0x6E,0x65,0x20,0x62,
- 0x75,0x74,0x74,0x6F,0x6E,0x73,0x2C,0x3F,0x79,0x6F,0x75,0x27,
- 0x6C,0x6C,0x20,0x73,0x74,0x6F,0x72,0x65,0x20,0x74,0x68,0x65,
- 0x20,0x63,0x75,0x72,0x72,0x65,0x6E,0x74,0x20,0x65,0x6E,0x76,
- 0x65,0x6C,0x6F,0x70,0x65,0x20,0x69,0x6E,0x74,0x6F,0x20,0x74,
- 0x68,0x61,0x74,0x20,0x70,0x72,0x65,0x64,0x65,0x66,0x69,0x6E,
- 0x65,0x20,0x63,0x65,0x6C,0x6C,0x2E,0x20,0x54,0x68,0x65,0x30,
- 0x70,0x72,0x65,0x64,0x65,0x66,0x69,0x6E,0x65,0x73,0x20,0x61,
- 0x72,0x65,0x20,0x73,0x74,0x6F,0x72,0x65,0x64,0x20,0x69,0x6E,
- 0x20,0x74,0x68,0x65,0x20,0x63,0x6F,0x6E,0x66,0x69,0x67,0x75,
- 0x72,0x61,0x74,0x69,0x6F,0x6E,0x20,0x66,0x69,0x6C,0x65,0x2E,
- 0x43,0x3E,0x50,0x72,0x65,0x64,0x65,0x66,0x69,0x6E,0x65,0x20,
- 0x6E,0x75,0x6D,0x62,0x65,0x72,0x20,0x31,0x20,0x69,0x73,0x20,
- 0x74,0x68,0x65,0x20,0x64,0x65,0x66,0x61,0x75,0x6C,0x74,0x20,
- 0x65,0x6E,0x76,0x65,0x6C,0x6F,0x70,0x65,0x2E,0x20,0x54,0x68,
- 0x69,0x73,0x20,0x6D,0x65,0x61,0x6E,0x73,0x20,0x74,0x68,0x61,
- 0x74,0x20,0x69,0x66,0x20,0x79,0x6F,0x75,0x42,0x6C,0x6F,0x61,
- 0x64,0x20,0x61,0x20,0x73,0x61,0x6D,0x70,0x6C,0x65,0x2C,0x20,
- 0x69,0x74,0x20,0x77,0x69,0x6C,0x6C,0x20,0x67,0x65,0x74,0x20,
- 0x61,0x6C,0x6C,0x20,0x65,0x6E,0x76,0x65,0x6C,0x6F,0x70,0x65,
- 0x20,0x69,0x6E,0x66,0x6F,0x72,0x6D,0x61,0x74,0x69,0x6F,0x6E,
- 0x20,0x66,0x72,0x6F,0x6D,0x20,0x70,0x72,0x65,0x64,0x65,0x66,
- 0x69,0x6E,0x65,0x20,0x6E,0x75,0x6D,0x62,0x65,0x72,0x20,0x31,
- 0x2C,0x20,0x69,0x6E,0x63,0x6C,0x75,0x64,0x69,0x6E,0x67,0x20,
- 0x74,0x68,0x65,0x20,0x76,0x69,0x62,0x72,0x61,0x74,0x6F,0x2E,
- 0x42,0x3E,0x4E,0x6F,0x74,0x65,0x20,0x74,0x68,0x61,0x74,0x20,
- 0x69,0x66,0x20,0x79,0x6F,0x75,0x20,0x74,0x75,0x72,0x6E,0x20,
- 0x74,0x68,0x65,0x20,0x76,0x6F,0x6C,0x75,0x6D,0x65,0x2D,0x65,
- 0x6E,0x76,0x65,0x6C,0x6F,0x70,0x65,0x20,0x6F,0x66,0x66,0x2C,
- 0x20,0x79,0x6F,0x75,0x20,0x64,0x6F,0x6E,0x27,0x74,0x20,0x74,
- 0x75,0x72,0x6E,0x20,0x74,0x68,0x65,0x0C,0x76,0x69,0x62,0x72,
- 0x61,0x74,0x6F,0x20,0x6F,0x66,0x66,0x2E,0x00,0x20,0x3E,0x40,
- 0x58,0x30,0x34,0x30,0x40,0x43,0x30,0x30,0x31,0x54,0x68,0x65,
- 0x20,0x70,0x61,0x6E,0x6E,0x69,0x6E,0x67,0x20,0x65,0x6E,0x76,
- 0x65,0x6C,0x6F,0x70,0x65,0x3A,0x0B,0x3E,0x40,0x58,0x30,0x36,
- 0x30,0x40,0x43,0x30,0x30,0x32,0x40,0x3E,0x53,0x61,0x6D,0x65,
- 0x20,0x61,0x73,0x20,0x61,0x62,0x6F,0x76,0x65,0x2C,0x20,0x65,
- 0x78,0x63,0x65,0x70,0x74,0x20,0x66,0x72,0x6F,0x6D,0x20,0x74,
- 0x68,0x61,0x74,0x20,0x74,0x68,0x65,0x20,0x76,0x69,0x62,0x72,
- 0x61,0x74,0x6F,0x20,0x69,0x73,0x20,0x6E,0x6F,0x74,0x20,0x63,
- 0x6F,0x6E,0x6E,0x65,0x63,0x74,0x65,0x64,0x20,0x74,0x6F,0x15,
- 0x74,0x68,0x65,0x20,0x70,0x61,0x6E,0x6E,0x69,0x6E,0x67,0x20,
- 0x65,0x6E,0x76,0x65,0x6C,0x6F,0x70,0x65,0x2E,0x00,0x10,0x3E,
- 0x40,0x58,0x30,0x34,0x30,0x40,0x43,0x30,0x30,0x31,0x54,0x75,
- 0x6E,0x65,0x3A,0x0B,0x3E,0x40,0x58,0x30,0x36,0x30,0x40,0x43,
- 0x30,0x30,0x32,0x3F,0x3E,0x54,0x68,0x65,0x20,0x66,0x69,0x6E,
- 0x65,0x2D,0x74,0x75,0x6E,0x65,0x20,0x72,0x65,0x73,0x6F,0x6C,
- 0x75,0x74,0x69,0x6F,0x6E,0x20,0x68,0x61,0x73,0x20,0x62,0x65,
- 0x65,0x6E,0x20,0x63,0x68,0x61,0x6E,0x67,0x65,0x64,0x20,0x66,
- 0x72,0x6F,0x6D,0x20,0x61,0x20,0x73,0x69,0x67,0x6E,0x65,0x64,
- 0x20,0x6E,0x69,0x62,0x62,0x6C,0x65,0x27,0x28,0x2D,0x38,0x2E,
- 0x2E,0x2B,0x37,0x29,0x20,0x74,0x6F,0x20,0x61,0x20,0x73,0x69,
- 0x67,0x6E,0x65,0x64,0x20,0x62,0x79,0x74,0x65,0x20,0x28,0x2D,
- 0x31,0x32,0x38,0x2E,0x2E,0x2B,0x31,0x32,0x37,0x29,0x2E,0x00,
- 0x13,0x3E,0x40,0x58,0x30,0x34,0x30,0x40,0x43,0x30,0x30,0x31,
- 0x46,0x61,0x64,0x65,0x6F,0x75,0x74,0x3A,0x0B,0x3E,0x40,0x58,
- 0x30,0x36,0x30,0x40,0x43,0x30,0x30,0x32,0x1B,0x3E,0x54,0x68,
- 0x69,0x73,0x20,0x69,0x73,0x20,0x74,0x68,0x65,0x20,0x66,0x61,
- 0x64,0x65,0x6F,0x75,0x74,0x20,0x73,0x70,0x65,0x65,0x64,0x2E,
- 0x00,0x19,0x3E,0x40,0x58,0x30,0x34,0x30,0x40,0x43,0x30,0x30,
- 0x31,0x56,0x69,0x62,0x72,0x61,0x74,0x6F,0x20,0x73,0x77,0x65,
- 0x65,0x70,0x3A,0x0B,0x3E,0x40,0x58,0x30,0x36,0x30,0x40,0x43,
- 0x30,0x30,0x32,0x3E,0x3E,0x54,0x68,0x69,0x73,0x20,0x69,0x73,
- 0x20,0x74,0x68,0x65,0x20,0x74,0x69,0x6D,0x65,0x20,0x28,0x69,
- 0x6E,0x20,0x70,0x6C,0x61,0x79,0x65,0x72,0x20,0x74,0x69,0x63,
- 0x6B,0x73,0x29,0x20,0x74,0x68,0x61,0x74,0x20,0x77,0x69,0x6C,
- 0x6C,0x20,0x62,0x79,0x70,0x61,0x73,0x73,0x20,0x75,0x6E,0x74,
- 0x69,0x6C,0x20,0x74,0x68,0x65,0x2D,0x61,0x75,0x74,0x6F,0x2D,
- 0x76,0x69,0x62,0x72,0x61,0x74,0x6F,0x20,0x77,0x69,0x6C,0x6C,
- 0x20,0x72,0x65,0x61,0x63,0x68,0x20,0x69,0x74,0x27,0x73,0x20,
- 0x66,0x69,0x6E,0x61,0x6C,0x20,0x61,0x6D,0x70,0x6C,0x69,0x74,
- 0x75,0x64,0x65,0x2E,0x00,0x1E,0x3E,0x40,0x58,0x30,0x34,0x30,
- 0x40,0x43,0x30,0x30,0x31,0x54,0x68,0x65,0x20,0x70,0x69,0x61,
- 0x6E,0x6F,0x20,0x6B,0x65,0x79,0x62,0x6F,0x61,0x72,0x64,0x3A,
+ 0x20,0x73,0x61,0x6D,0x70,0x6C,0x65,0x20,0x69,0x73,0x3A,0x28,
+ 0x3E,0x20,0x20,0x20,0x31,0x20,0x56,0x6F,0x6C,0x75,0x6D,0x65,
+ 0x2F,0x50,0x61,0x6E,0x6E,0x69,0x6E,0x67,0x2F,0x46,0x69,0x6E,
+ 0x65,0x74,0x75,0x6E,0x65,0x20,0x64,0x65,0x66,0x69,0x6E,0x69,
+ 0x74,0x69,0x6F,0x6E,0x13,0x3E,0x20,0x20,0x20,0x31,0x20,0x52,
+ 0x65,0x6C,0x61,0x74,0x69,0x76,0x65,0x20,0x6E,0x6F,0x74,0x65,
+ 0x0E,0x3E,0x20,0x20,0x20,0x31,0x20,0x57,0x61,0x76,0x65,0x66,
+ 0x6F,0x72,0x6D,0x00,0x1F,0x3E,0x40,0x58,0x30,0x34,0x30,0x40,
+ 0x43,0x30,0x30,0x31,0x54,0x68,0x65,0x20,0x76,0x6F,0x6C,0x75,
+ 0x6D,0x65,0x20,0x65,0x6E,0x76,0x65,0x6C,0x6F,0x70,0x65,0x3A,
0x0B,0x3E,0x40,0x58,0x30,0x36,0x30,0x40,0x43,0x30,0x30,0x32,
- 0x3F,0x3E,0x54,0x68,0x65,0x20,0x70,0x69,0x61,0x6E,0x6F,0x20,
- 0x6B,0x65,0x79,0x62,0x6F,0x61,0x72,0x64,0x20,0x64,0x65,0x66,
- 0x69,0x6E,0x65,0x73,0x20,0x74,0x68,0x65,0x20,0x6B,0x65,0x79,
- 0x20,0x73,0x70,0x6C,0x69,0x74,0x20,0x66,0x6F,0x72,0x20,0x61,
- 0x6E,0x20,0x69,0x6E,0x73,0x74,0x72,0x75,0x6D,0x65,0x6E,0x74,
- 0x2E,0x20,0x54,0x6F,0x3F,0x63,0x68,0x61,0x6E,0x67,0x65,0x20,
- 0x74,0x68,0x65,0x20,0x6B,0x65,0x79,0x20,0x73,0x70,0x6C,0x69,
- 0x74,0x2C,0x20,0x63,0x68,0x6F,0x6F,0x73,0x65,0x20,0x61,0x20,
- 0x73,0x61,0x6D,0x70,0x6C,0x65,0x20,0x77,0x69,0x74,0x68,0x69,
- 0x6E,0x20,0x74,0x68,0x65,0x20,0x69,0x6E,0x73,0x74,0x72,0x75,
- 0x6D,0x65,0x6E,0x74,0x20,0x61,0x6E,0x64,0x1C,0x74,0x68,0x65,
- 0x6E,0x20,0x22,0x64,0x72,0x61,0x77,0x22,0x20,0x6F,0x6E,0x20,
- 0x74,0x68,0x65,0x20,0x6B,0x65,0x79,0x62,0x6F,0x61,0x72,0x64,
- 0x2E,0x42,0x3E,0x54,0x68,0x65,0x20,0x6E,0x6F,0x74,0x65,0x73,
- 0x20,0x70,0x6C,0x61,0x79,0x65,0x64,0x20,0x77,0x69,0x74,0x68,
- 0x20,0x74,0x68,0x65,0x20,0x63,0x75,0x72,0x72,0x65,0x6E,0x74,
- 0x20,0x69,0x6E,0x73,0x74,0x72,0x75,0x6D,0x65,0x6E,0x74,0x20,
- 0x61,0x72,0x65,0x20,0x69,0x6E,0x64,0x69,0x63,0x61,0x74,0x65,
- 0x64,0x20,0x6F,0x6E,0x20,0x74,0x68,0x65,0x09,0x6B,0x65,0x79,
- 0x62,0x6F,0x61,0x72,0x64,0x2E,0x00,0x1A,0x3E,0x40,0x58,0x30,
- 0x34,0x30,0x40,0x43,0x30,0x30,0x31,0x49,0x6D,0x70,0x6F,0x72,
- 0x74,0x61,0x6E,0x74,0x20,0x6E,0x6F,0x74,0x65,0x3A,0x0B,0x3E,
- 0x40,0x58,0x30,0x36,0x30,0x40,0x43,0x30,0x30,0x32,0x40,0x3E,
- 0x54,0x68,0x65,0x20,0x76,0x6F,0x6C,0x75,0x6D,0x65,0x2C,0x20,
- 0x70,0x61,0x6E,0x6E,0x69,0x6E,0x67,0x2C,0x20,0x74,0x75,0x6E,
- 0x65,0x20,0x61,0x6E,0x64,0x20,0x72,0x65,0x6C,0x61,0x74,0x69,
- 0x76,0x65,0x20,0x74,0x6F,0x6E,0x65,0x20,0x69,0x73,0x20,0x64,
- 0x65,0x66,0x69,0x6E,0x65,0x64,0x20,0x66,0x6F,0x72,0x20,0x45,
- 0x41,0x43,0x48,0x41,0x53,0x41,0x4D,0x50,0x4C,0x45,0x20,0x69,
- 0x6E,0x20,0x61,0x6E,0x20,0x69,0x6E,0x73,0x74,0x72,0x75,0x6D,
- 0x65,0x6E,0x74,0x2E,0x20,0x41,0x6C,0x6C,0x20,0x6F,0x74,0x68,
- 0x65,0x72,0x20,0x69,0x6E,0x66,0x6F,0x72,0x6D,0x61,0x74,0x69,
- 0x6F,0x6E,0x20,0x69,0x73,0x20,0x64,0x65,0x66,0x69,0x6E,0x65,
- 0x64,0x20,0x66,0x6F,0x72,0x20,0x74,0x68,0x65,0x12,0x65,0x6E,
- 0x74,0x69,0x72,0x65,0x20,0x69,0x6E,0x73,0x74,0x72,0x75,0x6D,
- 0x65,0x6E,0x74,0x2E,0x00,0x31,0x40,0x58,0x30,0x32,0x30,0x40,
- 0x43,0x30,0x30,0x31,0x49,0x6E,0x73,0x74,0x72,0x75,0x6D,0x65,
- 0x6E,0x74,0x20,0x45,0x64,0x69,0x74,0x6F,0x72,0x20,0x45,0x78,
- 0x74,0x65,0x6E,0x73,0x69,0x6F,0x6E,0x3A,0x20,0x28,0x49,0x2E,
- 0x45,0x2E,0x45,0x78,0x74,0x2E,0x29,0x01,0x3E,0x10,0x3E,0x40,
- 0x58,0x30,0x34,0x30,0x40,0x43,0x30,0x30,0x31,0x4D,0x49,0x44,
- 0x49,0x3A,0x0B,0x3E,0x40,0x58,0x30,0x36,0x30,0x40,0x43,0x30,
- 0x30,0x32,0x28,0x3E,0x27,0x70,0x2E,0x27,0x20,0x73,0x74,0x61,
- 0x6E,0x64,0x73,0x20,0x66,0x6F,0x72,0x20,0x22,0x70,0x72,0x6F,
- 0x67,0x72,0x61,0x6D,0x22,0x20,0x28,0x69,0x6E,0x73,0x74,0x72,
- 0x75,0x6D,0x65,0x6E,0x74,0x29,0x2E,0x40,0x3E,0x53,0x65,0x76,
- 0x65,0x72,0x61,0x6C,0x20,0x69,0x6E,0x73,0x74,0x72,0x75,0x6D,
- 0x65,0x6E,0x74,0x73,0x20,0x63,0x61,0x6E,0x20,0x68,0x61,0x76,
- 0x65,0x20,0x74,0x68,0x65,0x20,0x73,0x61,0x6D,0x65,0x20,0x74,
- 0x72,0x61,0x6E,0x73,0x6D,0x69,0x74,0x20,0x63,0x68,0x61,0x6E,
- 0x6E,0x65,0x6C,0x20,0x62,0x75,0x74,0x20,0x77,0x69,0x74,0x68,
- 0x33,0x64,0x69,0x66,0x66,0x65,0x72,0x65,0x6E,0x74,0x20,0x70,
- 0x72,0x6F,0x67,0x72,0x61,0x6D,0x73,0x2E,0x20,0x46,0x54,0x32,
- 0x20,0x63,0x68,0x61,0x6E,0x67,0x65,0x73,0x20,0x74,0x68,0x65,
- 0x20,0x70,0x72,0x6F,0x67,0x72,0x61,0x6D,0x73,0x20,0x6F,0x6E,
- 0x20,0x74,0x68,0x65,0x43,0x4D,0x49,0x44,0x49,0x2D,0x63,0x68,
- 0x61,0x6E,0x6E,0x65,0x6C,0x73,0x20,0x69,0x6E,0x73,0x74,0x61,
- 0x6E,0x74,0x6C,0x79,0x20,0x64,0x75,0x72,0x69,0x6E,0x67,0x20,
- 0x70,0x6C,0x61,0x79,0x20,0x69,0x66,0x20,0x64,0x69,0x66,0x66,
+ 0x40,0x3E,0x41,0x6E,0x20,0x69,0x6E,0x73,0x74,0x72,0x75,0x6D,
+ 0x65,0x6E,0x74,0x27,0x73,0x20,0x76,0x6F,0x6C,0x75,0x6D,0x65,
+ 0x20,0x69,0x73,0x20,0x64,0x65,0x66,0x69,0x6E,0x65,0x64,0x20,
+ 0x62,0x79,0x20,0x69,0x74,0x73,0x20,0x65,0x6E,0x76,0x65,0x6C,
+ 0x6F,0x70,0x65,0x20,0x63,0x75,0x72,0x76,0x65,0x2E,0x20,0x49,
+ 0x66,0x20,0x74,0x68,0x65,0x3E,0x69,0x6E,0x73,0x74,0x72,0x75,
+ 0x6D,0x65,0x6E,0x74,0x20,0x68,0x61,0x73,0x20,0x61,0x20,0x73,
+ 0x75,0x73,0x74,0x61,0x69,0x6E,0x20,0x70,0x6F,0x69,0x6E,0x74,
+ 0x2C,0x20,0x74,0x68,0x65,0x20,0x65,0x6E,0x76,0x65,0x6C,0x6F,
+ 0x70,0x65,0x20,0x77,0x69,0x6C,0x6C,0x20,0x73,0x74,0x6F,0x70,
+ 0x20,0x61,0x74,0x20,0x74,0x68,0x61,0x74,0x42,0x70,0x6F,0x69,
+ 0x6E,0x74,0x20,0x75,0x6E,0x74,0x69,0x6C,0x20,0x61,0x20,0x6B,
+ 0x65,0x79,0x2D,0x6F,0x66,0x66,0x20,0x6E,0x6F,0x74,0x65,0x20,
+ 0x68,0x61,0x73,0x20,0x62,0x65,0x65,0x6E,0x20,0x70,0x6C,0x61,
+ 0x79,0x65,0x64,0x2E,0x20,0x57,0x68,0x65,0x6E,0x20,0x61,0x20,
+ 0x6B,0x65,0x79,0x2D,0x6F,0x66,0x66,0x20,0x6E,0x6F,0x74,0x65,
+ 0x20,0x69,0x73,0x1D,0x70,0x6C,0x61,0x79,0x65,0x64,0x2C,0x20,
+ 0x74,0x68,0x65,0x20,0x22,0x66,0x61,0x64,0x65,0x6F,0x75,0x74,
+ 0x22,0x20,0x62,0x65,0x67,0x69,0x6E,0x73,0x2E,0x44,0x3E,0x4F,
+ 0x6E,0x65,0x20,0x70,0x69,0x78,0x65,0x6C,0x20,0x69,0x6E,0x20,
+ 0x74,0x68,0x65,0x20,0x65,0x6E,0x76,0x65,0x6C,0x6F,0x70,0x65,
+ 0x20,0x77,0x69,0x6E,0x64,0x6F,0x77,0x20,0x63,0x6F,0x72,0x72,
+ 0x65,0x73,0x70,0x6F,0x6E,0x64,0x73,0x20,0x74,0x6F,0x20,0x6F,
+ 0x6E,0x65,0x20,0x70,0x6C,0x61,0x79,0x65,0x72,0x2D,0x74,0x69,
+ 0x63,0x6B,0x2E,0x20,0x49,0x66,0x3C,0x74,0x68,0x65,0x20,0x42,
+ 0x50,0x4D,0x20,0x69,0x73,0x20,0x31,0x32,0x35,0x2C,0x20,0x79,
+ 0x6F,0x75,0x27,0x6C,0x6C,0x20,0x63,0x6F,0x6E,0x73,0x75,0x6D,
+ 0x65,0x20,0x35,0x30,0x20,0x70,0x69,0x78,0x65,0x6C,0x2F,0x73,
+ 0x65,0x63,0x6F,0x6E,0x64,0x2E,0x20,0x54,0x68,0x65,0x20,0x77,
+ 0x69,0x6E,0x64,0x6F,0x77,0x27,0x73,0x1A,0x22,0x73,0x69,0x7A,
+ 0x65,0x22,0x20,0x69,0x73,0x20,0x61,0x62,0x6F,0x75,0x74,0x20,
+ 0x36,0x20,0x73,0x65,0x63,0x6F,0x6E,0x64,0x73,0x2E,0x3E,0x3E,
+ 0x49,0x66,0x20,0x79,0x6F,0x75,0x20,0x70,0x72,0x65,0x73,0x73,
+ 0x20,0x74,0x68,0x65,0x20,0x72,0x69,0x67,0x68,0x74,0x20,0x6D,
+ 0x6F,0x75,0x73,0x65,0x20,0x62,0x75,0x74,0x74,0x6F,0x6E,0x20,
+ 0x61,0x74,0x20,0x74,0x68,0x65,0x20,0x70,0x72,0x65,0x64,0x65,
+ 0x66,0x69,0x6E,0x65,0x20,0x62,0x75,0x74,0x74,0x6F,0x6E,0x73,
+ 0x2C,0x3F,0x79,0x6F,0x75,0x27,0x6C,0x6C,0x20,0x73,0x74,0x6F,
+ 0x72,0x65,0x20,0x74,0x68,0x65,0x20,0x63,0x75,0x72,0x72,0x65,
+ 0x6E,0x74,0x20,0x65,0x6E,0x76,0x65,0x6C,0x6F,0x70,0x65,0x20,
+ 0x69,0x6E,0x74,0x6F,0x20,0x74,0x68,0x61,0x74,0x20,0x70,0x72,
+ 0x65,0x64,0x65,0x66,0x69,0x6E,0x65,0x20,0x63,0x65,0x6C,0x6C,
+ 0x2E,0x20,0x54,0x68,0x65,0x30,0x70,0x72,0x65,0x64,0x65,0x66,
+ 0x69,0x6E,0x65,0x73,0x20,0x61,0x72,0x65,0x20,0x73,0x74,0x6F,
+ 0x72,0x65,0x64,0x20,0x69,0x6E,0x20,0x74,0x68,0x65,0x20,0x63,
+ 0x6F,0x6E,0x66,0x69,0x67,0x75,0x72,0x61,0x74,0x69,0x6F,0x6E,
+ 0x20,0x66,0x69,0x6C,0x65,0x2E,0x43,0x3E,0x50,0x72,0x65,0x64,
+ 0x65,0x66,0x69,0x6E,0x65,0x20,0x6E,0x75,0x6D,0x62,0x65,0x72,
+ 0x20,0x31,0x20,0x69,0x73,0x20,0x74,0x68,0x65,0x20,0x64,0x65,
+ 0x66,0x61,0x75,0x6C,0x74,0x20,0x65,0x6E,0x76,0x65,0x6C,0x6F,
+ 0x70,0x65,0x2E,0x20,0x54,0x68,0x69,0x73,0x20,0x6D,0x65,0x61,
+ 0x6E,0x73,0x20,0x74,0x68,0x61,0x74,0x20,0x69,0x66,0x20,0x79,
+ 0x6F,0x75,0x42,0x6C,0x6F,0x61,0x64,0x20,0x61,0x20,0x73,0x61,
+ 0x6D,0x70,0x6C,0x65,0x2C,0x20,0x69,0x74,0x20,0x77,0x69,0x6C,
+ 0x6C,0x20,0x67,0x65,0x74,0x20,0x61,0x6C,0x6C,0x20,0x65,0x6E,
+ 0x76,0x65,0x6C,0x6F,0x70,0x65,0x20,0x69,0x6E,0x66,0x6F,0x72,
+ 0x6D,0x61,0x74,0x69,0x6F,0x6E,0x20,0x66,0x72,0x6F,0x6D,0x20,
+ 0x70,0x72,0x65,0x64,0x65,0x66,0x69,0x6E,0x65,0x20,0x6E,0x75,
+ 0x6D,0x62,0x65,0x72,0x20,0x31,0x2C,0x20,0x69,0x6E,0x63,0x6C,
+ 0x75,0x64,0x69,0x6E,0x67,0x20,0x74,0x68,0x65,0x20,0x76,0x69,
+ 0x62,0x72,0x61,0x74,0x6F,0x2E,0x42,0x3E,0x4E,0x6F,0x74,0x65,
+ 0x20,0x74,0x68,0x61,0x74,0x20,0x69,0x66,0x20,0x79,0x6F,0x75,
+ 0x20,0x74,0x75,0x72,0x6E,0x20,0x74,0x68,0x65,0x20,0x76,0x6F,
+ 0x6C,0x75,0x6D,0x65,0x2D,0x65,0x6E,0x76,0x65,0x6C,0x6F,0x70,
+ 0x65,0x20,0x6F,0x66,0x66,0x2C,0x20,0x79,0x6F,0x75,0x20,0x64,
+ 0x6F,0x6E,0x27,0x74,0x20,0x74,0x75,0x72,0x6E,0x20,0x74,0x68,
+ 0x65,0x0C,0x76,0x69,0x62,0x72,0x61,0x74,0x6F,0x20,0x6F,0x66,
+ 0x66,0x2E,0x00,0x20,0x3E,0x40,0x58,0x30,0x34,0x30,0x40,0x43,
+ 0x30,0x30,0x31,0x54,0x68,0x65,0x20,0x70,0x61,0x6E,0x6E,0x69,
+ 0x6E,0x67,0x20,0x65,0x6E,0x76,0x65,0x6C,0x6F,0x70,0x65,0x3A,
+ 0x0B,0x3E,0x40,0x58,0x30,0x36,0x30,0x40,0x43,0x30,0x30,0x32,
+ 0x40,0x3E,0x53,0x61,0x6D,0x65,0x20,0x61,0x73,0x20,0x61,0x62,
+ 0x6F,0x76,0x65,0x2C,0x20,0x65,0x78,0x63,0x65,0x70,0x74,0x20,
+ 0x66,0x72,0x6F,0x6D,0x20,0x74,0x68,0x61,0x74,0x20,0x74,0x68,
+ 0x65,0x20,0x76,0x69,0x62,0x72,0x61,0x74,0x6F,0x20,0x69,0x73,
+ 0x20,0x6E,0x6F,0x74,0x20,0x63,0x6F,0x6E,0x6E,0x65,0x63,0x74,
+ 0x65,0x64,0x20,0x74,0x6F,0x15,0x74,0x68,0x65,0x20,0x70,0x61,
+ 0x6E,0x6E,0x69,0x6E,0x67,0x20,0x65,0x6E,0x76,0x65,0x6C,0x6F,
+ 0x70,0x65,0x2E,0x00,0x1B,0x3E,0x40,0x58,0x30,0x34,0x30,0x40,
+ 0x43,0x30,0x30,0x31,0x54,0x75,0x6E,0x65,0x20,0x28,0x66,0x69,
+ 0x6E,0x65,0x74,0x75,0x6E,0x65,0x29,0x3A,0x0B,0x3E,0x40,0x58,
+ 0x30,0x36,0x30,0x40,0x43,0x30,0x30,0x32,0x3E,0x3E,0x54,0x68,
+ 0x65,0x20,0x66,0x69,0x6E,0x65,0x74,0x75,0x6E,0x65,0x20,0x72,
+ 0x65,0x73,0x6F,0x6C,0x75,0x74,0x69,0x6F,0x6E,0x20,0x68,0x61,
+ 0x73,0x20,0x62,0x65,0x65,0x6E,0x20,0x63,0x68,0x61,0x6E,0x67,
+ 0x65,0x64,0x20,0x66,0x72,0x6F,0x6D,0x20,0x61,0x20,0x73,0x69,
+ 0x67,0x6E,0x65,0x64,0x20,0x6E,0x69,0x62,0x62,0x6C,0x65,0x27,
+ 0x28,0x2D,0x38,0x2E,0x2E,0x2B,0x37,0x29,0x20,0x74,0x6F,0x20,
+ 0x61,0x20,0x73,0x69,0x67,0x6E,0x65,0x64,0x20,0x62,0x79,0x74,
+ 0x65,0x20,0x28,0x2D,0x31,0x32,0x38,0x2E,0x2E,0x2B,0x31,0x32,
+ 0x37,0x29,0x2E,0x46,0x3E,0x4E,0x4F,0x54,0x45,0x3A,0x20,0x54,
+ 0x68,0x65,0x20,0x6C,0x61,0x73,0x74,0x20,0x33,0x20,0x62,0x69,
+ 0x74,0x73,0x20,0x61,0x72,0x65,0x20,0x64,0x69,0x73,0x63,0x61,
+ 0x72,0x64,0x65,0x64,0x20,0x64,0x75,0x72,0x69,0x6E,0x67,0x20,
+ 0x70,0x6C,0x61,0x79,0x62,0x61,0x63,0x6B,0x2C,0x20,0x73,0x6F,
+ 0x20,0x74,0x68,0x65,0x20,0x74,0x72,0x75,0x65,0x20,0x73,0x74,
+ 0x65,0x70,0x17,0x73,0x69,0x7A,0x65,0x20,0x69,0x73,0x20,0x38,
+ 0x20,0x69,0x6E,0x73,0x74,0x65,0x61,0x64,0x20,0x6F,0x66,0x20,
+ 0x31,0x2E,0x00,0x13,0x3E,0x40,0x58,0x30,0x34,0x30,0x40,0x43,
+ 0x30,0x30,0x31,0x46,0x61,0x64,0x65,0x6F,0x75,0x74,0x3A,0x0B,
+ 0x3E,0x40,0x58,0x30,0x36,0x30,0x40,0x43,0x30,0x30,0x32,0x1B,
+ 0x3E,0x54,0x68,0x69,0x73,0x20,0x69,0x73,0x20,0x74,0x68,0x65,
+ 0x20,0x66,0x61,0x64,0x65,0x6F,0x75,0x74,0x20,0x73,0x70,0x65,
+ 0x65,0x64,0x2E,0x00,0x19,0x3E,0x40,0x58,0x30,0x34,0x30,0x40,
+ 0x43,0x30,0x30,0x31,0x56,0x69,0x62,0x72,0x61,0x74,0x6F,0x20,
+ 0x73,0x77,0x65,0x65,0x70,0x3A,0x0B,0x3E,0x40,0x58,0x30,0x36,
+ 0x30,0x40,0x43,0x30,0x30,0x32,0x3E,0x3E,0x54,0x68,0x69,0x73,
+ 0x20,0x69,0x73,0x20,0x74,0x68,0x65,0x20,0x74,0x69,0x6D,0x65,
+ 0x20,0x28,0x69,0x6E,0x20,0x70,0x6C,0x61,0x79,0x65,0x72,0x20,
+ 0x74,0x69,0x63,0x6B,0x73,0x29,0x20,0x74,0x68,0x61,0x74,0x20,
+ 0x77,0x69,0x6C,0x6C,0x20,0x62,0x79,0x70,0x61,0x73,0x73,0x20,
+ 0x75,0x6E,0x74,0x69,0x6C,0x20,0x74,0x68,0x65,0x2D,0x61,0x75,
+ 0x74,0x6F,0x2D,0x76,0x69,0x62,0x72,0x61,0x74,0x6F,0x20,0x77,
+ 0x69,0x6C,0x6C,0x20,0x72,0x65,0x61,0x63,0x68,0x20,0x69,0x74,
+ 0x27,0x73,0x20,0x66,0x69,0x6E,0x61,0x6C,0x20,0x61,0x6D,0x70,
+ 0x6C,0x69,0x74,0x75,0x64,0x65,0x2E,0x00,0x1E,0x3E,0x40,0x58,
+ 0x30,0x34,0x30,0x40,0x43,0x30,0x30,0x31,0x54,0x68,0x65,0x20,
+ 0x70,0x69,0x61,0x6E,0x6F,0x20,0x6B,0x65,0x79,0x62,0x6F,0x61,
+ 0x72,0x64,0x3A,0x0B,0x3E,0x40,0x58,0x30,0x36,0x30,0x40,0x43,
+ 0x30,0x30,0x32,0x3F,0x3E,0x54,0x68,0x65,0x20,0x70,0x69,0x61,
+ 0x6E,0x6F,0x20,0x6B,0x65,0x79,0x62,0x6F,0x61,0x72,0x64,0x20,
+ 0x64,0x65,0x66,0x69,0x6E,0x65,0x73,0x20,0x74,0x68,0x65,0x20,
+ 0x6B,0x65,0x79,0x20,0x73,0x70,0x6C,0x69,0x74,0x20,0x66,0x6F,
+ 0x72,0x20,0x61,0x6E,0x20,0x69,0x6E,0x73,0x74,0x72,0x75,0x6D,
+ 0x65,0x6E,0x74,0x2E,0x20,0x54,0x6F,0x3F,0x63,0x68,0x61,0x6E,
+ 0x67,0x65,0x20,0x74,0x68,0x65,0x20,0x6B,0x65,0x79,0x20,0x73,
+ 0x70,0x6C,0x69,0x74,0x2C,0x20,0x63,0x68,0x6F,0x6F,0x73,0x65,
+ 0x20,0x61,0x20,0x73,0x61,0x6D,0x70,0x6C,0x65,0x20,0x77,0x69,
+ 0x74,0x68,0x69,0x6E,0x20,0x74,0x68,0x65,0x20,0x69,0x6E,0x73,
+ 0x74,0x72,0x75,0x6D,0x65,0x6E,0x74,0x20,0x61,0x6E,0x64,0x1C,
+ 0x74,0x68,0x65,0x6E,0x20,0x22,0x64,0x72,0x61,0x77,0x22,0x20,
+ 0x6F,0x6E,0x20,0x74,0x68,0x65,0x20,0x6B,0x65,0x79,0x62,0x6F,
+ 0x61,0x72,0x64,0x2E,0x42,0x3E,0x54,0x68,0x65,0x20,0x6E,0x6F,
+ 0x74,0x65,0x73,0x20,0x70,0x6C,0x61,0x79,0x65,0x64,0x20,0x77,
+ 0x69,0x74,0x68,0x20,0x74,0x68,0x65,0x20,0x63,0x75,0x72,0x72,
+ 0x65,0x6E,0x74,0x20,0x69,0x6E,0x73,0x74,0x72,0x75,0x6D,0x65,
+ 0x6E,0x74,0x20,0x61,0x72,0x65,0x20,0x69,0x6E,0x64,0x69,0x63,
+ 0x61,0x74,0x65,0x64,0x20,0x6F,0x6E,0x20,0x74,0x68,0x65,0x09,
+ 0x6B,0x65,0x79,0x62,0x6F,0x61,0x72,0x64,0x2E,0x00,0x1A,0x3E,
+ 0x40,0x58,0x30,0x34,0x30,0x40,0x43,0x30,0x30,0x31,0x49,0x6D,
+ 0x70,0x6F,0x72,0x74,0x61,0x6E,0x74,0x20,0x6E,0x6F,0x74,0x65,
+ 0x3A,0x0B,0x3E,0x40,0x58,0x30,0x36,0x30,0x40,0x43,0x30,0x30,
+ 0x32,0x44,0x3E,0x54,0x68,0x65,0x20,0x76,0x6F,0x6C,0x75,0x6D,
+ 0x65,0x2C,0x20,0x70,0x61,0x6E,0x6E,0x69,0x6E,0x67,0x2C,0x20,
+ 0x66,0x69,0x6E,0x65,0x74,0x75,0x6E,0x65,0x20,0x61,0x6E,0x64,
+ 0x20,0x72,0x65,0x6C,0x61,0x74,0x69,0x76,0x65,0x20,0x6E,0x6F,
+ 0x74,0x65,0x20,0x69,0x73,0x20,0x64,0x65,0x66,0x69,0x6E,0x65,
+ 0x64,0x20,0x66,0x6F,0x72,0x20,0x45,0x41,0x43,0x48,0x41,0x53,
+ 0x41,0x4D,0x50,0x4C,0x45,0x20,0x69,0x6E,0x20,0x61,0x6E,0x20,
+ 0x69,0x6E,0x73,0x74,0x72,0x75,0x6D,0x65,0x6E,0x74,0x2E,0x20,
+ 0x41,0x6C,0x6C,0x20,0x6F,0x74,0x68,0x65,0x72,0x20,0x69,0x6E,
+ 0x66,0x6F,0x72,0x6D,0x61,0x74,0x69,0x6F,0x6E,0x20,0x69,0x73,
+ 0x20,0x64,0x65,0x66,0x69,0x6E,0x65,0x64,0x20,0x66,0x6F,0x72,
+ 0x20,0x74,0x68,0x65,0x12,0x65,0x6E,0x74,0x69,0x72,0x65,0x20,
+ 0x69,0x6E,0x73,0x74,0x72,0x75,0x6D,0x65,0x6E,0x74,0x2E,0x00,
+ 0x31,0x40,0x58,0x30,0x32,0x30,0x40,0x43,0x30,0x30,0x31,0x49,
+ 0x6E,0x73,0x74,0x72,0x75,0x6D,0x65,0x6E,0x74,0x20,0x45,0x64,
+ 0x69,0x74,0x6F,0x72,0x20,0x45,0x78,0x74,0x65,0x6E,0x73,0x69,
+ 0x6F,0x6E,0x3A,0x20,0x28,0x49,0x2E,0x45,0x2E,0x45,0x78,0x74,
+ 0x2E,0x29,0x01,0x3E,0x10,0x3E,0x40,0x58,0x30,0x34,0x30,0x40,
+ 0x43,0x30,0x30,0x31,0x4D,0x49,0x44,0x49,0x3A,0x0B,0x3E,0x40,
+ 0x58,0x30,0x36,0x30,0x40,0x43,0x30,0x30,0x32,0x28,0x3E,0x27,
+ 0x70,0x2E,0x27,0x20,0x73,0x74,0x61,0x6E,0x64,0x73,0x20,0x66,
+ 0x6F,0x72,0x20,0x22,0x70,0x72,0x6F,0x67,0x72,0x61,0x6D,0x22,
+ 0x20,0x28,0x69,0x6E,0x73,0x74,0x72,0x75,0x6D,0x65,0x6E,0x74,
+ 0x29,0x2E,0x40,0x3E,0x53,0x65,0x76,0x65,0x72,0x61,0x6C,0x20,
+ 0x69,0x6E,0x73,0x74,0x72,0x75,0x6D,0x65,0x6E,0x74,0x73,0x20,
+ 0x63,0x61,0x6E,0x20,0x68,0x61,0x76,0x65,0x20,0x74,0x68,0x65,
+ 0x20,0x73,0x61,0x6D,0x65,0x20,0x74,0x72,0x61,0x6E,0x73,0x6D,
+ 0x69,0x74,0x20,0x63,0x68,0x61,0x6E,0x6E,0x65,0x6C,0x20,0x62,
+ 0x75,0x74,0x20,0x77,0x69,0x74,0x68,0x33,0x64,0x69,0x66,0x66,
0x65,0x72,0x65,0x6E,0x74,0x20,0x70,0x72,0x6F,0x67,0x72,0x61,
- 0x6D,0x73,0x20,0x61,0x72,0x65,0x20,0x75,0x73,0x65,0x64,0x2E,
- 0x3E,0x44,0x69,0x66,0x66,0x65,0x72,0x65,0x6E,0x74,0x20,0x70,
- 0x72,0x6F,0x67,0x72,0x61,0x6D,0x73,0x20,0x63,0x61,0x6E,0x6E,
- 0x6F,0x74,0x20,0x62,0x65,0x20,0x70,0x6C,0x61,0x79,0x65,0x64,
- 0x20,0x61,0x74,0x20,0x74,0x68,0x65,0x20,0x73,0x61,0x6D,0x65,
- 0x20,0x63,0x68,0x61,0x6E,0x6E,0x65,0x6C,0x20,0x61,0x74,0x20,
- 0x74,0x68,0x65,0x11,0x73,0x61,0x6D,0x65,0x20,0x74,0x69,0x6D,
- 0x65,0x20,0x74,0x68,0x6F,0x75,0x67,0x68,0x2E,0x44,0x3E,0x49,
- 0x66,0x20,0x79,0x6F,0x75,0x20,0x63,0x68,0x61,0x6E,0x67,0x65,
- 0x20,0x74,0x68,0x69,0x73,0x20,0x76,0x61,0x6C,0x75,0x65,0x2C,
- 0x20,0x74,0x68,0x65,0x20,0x70,0x72,0x6F,0x67,0x72,0x61,0x6D,
- 0x20,0x6E,0x75,0x6D,0x62,0x65,0x72,0x20,0x77,0x69,0x6C,0x6C,
- 0x20,0x62,0x65,0x20,0x74,0x72,0x61,0x6E,0x73,0x6D,0x69,0x74,
- 0x74,0x65,0x64,0x20,0x74,0x6F,0x1C,0x74,0x68,0x65,0x20,0x73,
- 0x79,0x6E,0x74,0x68,0x65,0x73,0x69,0x7A,0x65,0x72,0x20,0x69,
- 0x6D,0x6D,0x65,0x64,0x69,0x61,0x74,0x65,0x6C,0x79,0x2E,0x3E,
- 0x3E,0x53,0x6F,0x6D,0x65,0x20,0x73,0x79,0x6E,0x74,0x68,0x65,
- 0x73,0x69,0x7A,0x65,0x72,0x73,0x20,0x74,0x72,0x61,0x6E,0x73,
- 0x6D,0x69,0x74,0x20,0x70,0x72,0x6F,0x67,0x72,0x61,0x6D,0x20,
- 0x63,0x68,0x61,0x6E,0x67,0x65,0x20,0x69,0x6E,0x66,0x6F,0x72,
- 0x6D,0x61,0x74,0x69,0x6F,0x6E,0x2E,0x20,0x49,0x66,0x20,0x74,
- 0x68,0x65,0x43,0x63,0x75,0x72,0x72,0x65,0x6E,0x74,0x20,0x69,
- 0x6E,0x73,0x74,0x72,0x75,0x6D,0x65,0x6E,0x74,0x20,0x69,0x6E,
- 0x20,0x46,0x54,0x32,0x20,0x69,0x73,0x20,0x61,0x20,0x4D,0x49,
- 0x44,0x49,0x2D,0x69,0x6E,0x73,0x74,0x72,0x2E,0x20,0x77,0x69,
- 0x74,0x68,0x20,0x74,0x68,0x65,0x20,0x73,0x61,0x6D,0x65,0x20,
- 0x63,0x68,0x61,0x6E,0x6E,0x65,0x6C,0x20,0x61,0x73,0x3F,0x74,
- 0x68,0x65,0x20,0x72,0x65,0x63,0x65,0x69,0x76,0x65,0x64,0x20,
+ 0x6D,0x73,0x2E,0x20,0x46,0x54,0x32,0x20,0x63,0x68,0x61,0x6E,
+ 0x67,0x65,0x73,0x20,0x74,0x68,0x65,0x20,0x70,0x72,0x6F,0x67,
+ 0x72,0x61,0x6D,0x73,0x20,0x6F,0x6E,0x20,0x74,0x68,0x65,0x43,
+ 0x4D,0x49,0x44,0x49,0x2D,0x63,0x68,0x61,0x6E,0x6E,0x65,0x6C,
+ 0x73,0x20,0x69,0x6E,0x73,0x74,0x61,0x6E,0x74,0x6C,0x79,0x20,
+ 0x64,0x75,0x72,0x69,0x6E,0x67,0x20,0x70,0x6C,0x61,0x79,0x20,
+ 0x69,0x66,0x20,0x64,0x69,0x66,0x66,0x65,0x72,0x65,0x6E,0x74,
+ 0x20,0x70,0x72,0x6F,0x67,0x72,0x61,0x6D,0x73,0x20,0x61,0x72,
+ 0x65,0x20,0x75,0x73,0x65,0x64,0x2E,0x3E,0x44,0x69,0x66,0x66,
+ 0x65,0x72,0x65,0x6E,0x74,0x20,0x70,0x72,0x6F,0x67,0x72,0x61,
+ 0x6D,0x73,0x20,0x63,0x61,0x6E,0x6E,0x6F,0x74,0x20,0x62,0x65,
+ 0x20,0x70,0x6C,0x61,0x79,0x65,0x64,0x20,0x61,0x74,0x20,0x74,
+ 0x68,0x65,0x20,0x73,0x61,0x6D,0x65,0x20,0x63,0x68,0x61,0x6E,
+ 0x6E,0x65,0x6C,0x20,0x61,0x74,0x20,0x74,0x68,0x65,0x11,0x73,
+ 0x61,0x6D,0x65,0x20,0x74,0x69,0x6D,0x65,0x20,0x74,0x68,0x6F,
+ 0x75,0x67,0x68,0x2E,0x44,0x3E,0x49,0x66,0x20,0x79,0x6F,0x75,
+ 0x20,0x63,0x68,0x61,0x6E,0x67,0x65,0x20,0x74,0x68,0x69,0x73,
+ 0x20,0x76,0x61,0x6C,0x75,0x65,0x2C,0x20,0x74,0x68,0x65,0x20,
+ 0x70,0x72,0x6F,0x67,0x72,0x61,0x6D,0x20,0x6E,0x75,0x6D,0x62,
+ 0x65,0x72,0x20,0x77,0x69,0x6C,0x6C,0x20,0x62,0x65,0x20,0x74,
+ 0x72,0x61,0x6E,0x73,0x6D,0x69,0x74,0x74,0x65,0x64,0x20,0x74,
+ 0x6F,0x1C,0x74,0x68,0x65,0x20,0x73,0x79,0x6E,0x74,0x68,0x65,
+ 0x73,0x69,0x7A,0x65,0x72,0x20,0x69,0x6D,0x6D,0x65,0x64,0x69,
+ 0x61,0x74,0x65,0x6C,0x79,0x2E,0x3E,0x3E,0x53,0x6F,0x6D,0x65,
+ 0x20,0x73,0x79,0x6E,0x74,0x68,0x65,0x73,0x69,0x7A,0x65,0x72,
+ 0x73,0x20,0x74,0x72,0x61,0x6E,0x73,0x6D,0x69,0x74,0x20,0x70,
+ 0x72,0x6F,0x67,0x72,0x61,0x6D,0x20,0x63,0x68,0x61,0x6E,0x67,
+ 0x65,0x20,0x69,0x6E,0x66,0x6F,0x72,0x6D,0x61,0x74,0x69,0x6F,
+ 0x6E,0x2E,0x20,0x49,0x66,0x20,0x74,0x68,0x65,0x43,0x63,0x75,
+ 0x72,0x72,0x65,0x6E,0x74,0x20,0x69,0x6E,0x73,0x74,0x72,0x75,
+ 0x6D,0x65,0x6E,0x74,0x20,0x69,0x6E,0x20,0x46,0x54,0x32,0x20,
+ 0x69,0x73,0x20,0x61,0x20,0x4D,0x49,0x44,0x49,0x2D,0x69,0x6E,
+ 0x73,0x74,0x72,0x2E,0x20,0x77,0x69,0x74,0x68,0x20,0x74,0x68,
+ 0x65,0x20,0x73,0x61,0x6D,0x65,0x20,0x63,0x68,0x61,0x6E,0x6E,
+ 0x65,0x6C,0x20,0x61,0x73,0x3F,0x74,0x68,0x65,0x20,0x72,0x65,
+ 0x63,0x65,0x69,0x76,0x65,0x64,0x20,0x70,0x72,0x6F,0x67,0x72,
+ 0x61,0x6D,0x20,0x63,0x68,0x61,0x6E,0x67,0x65,0x2C,0x20,0x69,
+ 0x74,0x27,0x73,0x20,0x4D,0x49,0x44,0x49,0x2D,0x70,0x72,0x6F,
+ 0x67,0x72,0x61,0x6D,0x20,0x77,0x69,0x6C,0x6C,0x20,0x62,0x65,
+ 0x20,0x63,0x68,0x61,0x6E,0x67,0x65,0x64,0x2E,0x40,0x3E,0x49,
+ 0x66,0x20,0x79,0x6F,0x75,0x72,0x20,0x73,0x79,0x6E,0x74,0x68,
+ 0x65,0x73,0x69,0x7A,0x65,0x72,0x20,0x64,0x6F,0x65,0x73,0x6E,
+ 0x27,0x74,0x20,0x74,0x72,0x61,0x6E,0x73,0x6D,0x69,0x74,0x20,
0x70,0x72,0x6F,0x67,0x72,0x61,0x6D,0x20,0x63,0x68,0x61,0x6E,
- 0x67,0x65,0x2C,0x20,0x69,0x74,0x27,0x73,0x20,0x4D,0x49,0x44,
- 0x49,0x2D,0x70,0x72,0x6F,0x67,0x72,0x61,0x6D,0x20,0x77,0x69,
- 0x6C,0x6C,0x20,0x62,0x65,0x20,0x63,0x68,0x61,0x6E,0x67,0x65,
- 0x64,0x2E,0x40,0x3E,0x49,0x66,0x20,0x79,0x6F,0x75,0x72,0x20,
- 0x73,0x79,0x6E,0x74,0x68,0x65,0x73,0x69,0x7A,0x65,0x72,0x20,
- 0x64,0x6F,0x65,0x73,0x6E,0x27,0x74,0x20,0x74,0x72,0x61,0x6E,
- 0x73,0x6D,0x69,0x74,0x20,0x70,0x72,0x6F,0x67,0x72,0x61,0x6D,
- 0x20,0x63,0x68,0x61,0x6E,0x67,0x65,0x2C,0x20,0x74,0x68,0x65,
- 0x72,0x65,0x27,0x73,0x20,0x6E,0x6F,0x3E,0x70,0x6F,0x69,0x6E,
- 0x74,0x20,0x69,0x6E,0x20,0x63,0x68,0x61,0x6E,0x67,0x69,0x6E,
- 0x67,0x20,0x69,0x74,0x20,0x6F,0x6E,0x20,0x74,0x68,0x65,0x20,
- 0x73,0x79,0x6E,0x74,0x68,0x65,0x73,0x69,0x7A,0x65,0x72,0x2C,
- 0x20,0x64,0x6F,0x20,0x69,0x74,0x20,0x69,0x6E,0x20,0x46,0x54,
- 0x32,0x20,0x69,0x6E,0x73,0x74,0x65,0x61,0x64,0x2E,0x00,0x18,
- 0x3E,0x40,0x58,0x30,0x34,0x30,0x40,0x43,0x30,0x30,0x31,0x42,
- 0x65,0x6E,0x64,0x65,0x72,0x20,0x72,0x61,0x6E,0x67,0x65,0x3A,
- 0x0B,0x3E,0x40,0x58,0x30,0x36,0x30,0x40,0x43,0x30,0x30,0x32,
- 0x38,0x3E,0x54,0x68,0x69,0x73,0x20,0x76,0x61,0x6C,0x75,0x65,
- 0x20,0x64,0x65,0x66,0x69,0x6E,0x65,0x73,0x20,0x68,0x6F,0x77,
- 0x20,0x6D,0x61,0x6E,0x79,0x20,0x6E,0x6F,0x74,0x65,0x73,0x20,
- 0x74,0x68,0x65,0x20,0x69,0x6E,0x73,0x74,0x72,0x75,0x6D,0x65,
- 0x6E,0x74,0x20,0x6F,0x6E,0x20,0x74,0x68,0x65,0x37,0x73,0x79,
- 0x6E,0x74,0x68,0x65,0x73,0x69,0x7A,0x65,0x72,0x20,0x63,0x61,
- 0x6E,0x20,0x62,0x65,0x20,0x70,0x69,0x74,0x63,0x68,0x62,0x65,
- 0x6E,0x64,0x65,0x64,0x2E,0x20,0x46,0x54,0x32,0x20,0x75,0x73,
- 0x65,0x73,0x20,0x74,0x68,0x69,0x73,0x20,0x76,0x61,0x6C,0x75,
- 0x65,0x20,0x66,0x6F,0x72,0x37,0x74,0x72,0x61,0x6E,0x73,0x6D,
- 0x69,0x74,0x74,0x69,0x6E,0x67,0x20,0x74,0x68,0x65,0x20,0x70,
- 0x6F,0x72,0x74,0x61,0x6D,0x65,0x6E,0x74,0x6F,0x20,0x75,0x70,
- 0x2F,0x64,0x6F,0x77,0x6E,0x20,0x61,0x6E,0x64,0x20,0x74,0x6F,
- 0x6E,0x65,0x2D,0x70,0x6F,0x72,0x74,0x61,0x6D,0x65,0x6E,0x74,
- 0x6F,0x13,0x63,0x6F,0x6D,0x6D,0x61,0x6E,0x64,0x73,0x20,0x63,
- 0x6F,0x72,0x72,0x65,0x63,0x74,0x6C,0x79,0x2E,0x45,0x3E,0x54,
- 0x68,0x65,0x20,0x4D,0x49,0x44,0x49,0x2D,0x70,0x69,0x74,0x63,
- 0x68,0x62,0x65,0x6E,0x64,0x20,0x77,0x6F,0x72,0x6B,0x73,0x20,
- 0x63,0x6F,0x72,0x72,0x65,0x63,0x74,0x6C,0x79,0x20,0x6F,0x6E,
- 0x6C,0x79,0x20,0x77,0x69,0x74,0x68,0x20,0x6C,0x69,0x6E,0x65,
- 0x61,0x72,0x20,0x66,0x72,0x65,0x71,0x75,0x65,0x6E,0x63,0x79,
- 0x20,0x74,0x61,0x62,0x6C,0x65,0x2E,0x00,0x18,0x40,0x58,0x30,
- 0x32,0x30,0x40,0x43,0x30,0x30,0x31,0x53,0x61,0x6D,0x70,0x6C,
- 0x65,0x20,0x45,0x64,0x69,0x74,0x6F,0x72,0x3A,0x01,0x3E,0x2C,
- 0x3E,0x40,0x58,0x30,0x34,0x30,0x40,0x43,0x30,0x30,0x31,0x50,
- 0x6C,0x61,0x79,0x20,0x28,0x57,0x61,0x76,0x65,0x20,0x66,0x6F,
- 0x72,0x6D,0x2C,0x20,0x72,0x61,0x6E,0x67,0x65,0x2C,0x20,0x64,
- 0x69,0x73,0x70,0x6C,0x61,0x79,0x29,0x3A,0x0B,0x3E,0x40,0x58,
- 0x30,0x36,0x30,0x40,0x43,0x30,0x30,0x32,0x3C,0x3E,0x50,0x6C,
- 0x61,0x79,0x73,0x20,0x74,0x68,0x65,0x20,0x63,0x75,0x72,0x72,
- 0x65,0x6E,0x74,0x20,0x73,0x61,0x6D,0x70,0x6C,0x65,0x20,0x77,
- 0x69,0x74,0x68,0x20,0x74,0x6F,0x6E,0x65,0x20,0x64,0x69,0x73,
- 0x70,0x6C,0x61,0x79,0x20,0x61,0x62,0x6F,0x76,0x65,0x20,0x74,
+ 0x67,0x65,0x2C,0x20,0x74,0x68,0x65,0x72,0x65,0x27,0x73,0x20,
+ 0x6E,0x6F,0x3E,0x70,0x6F,0x69,0x6E,0x74,0x20,0x69,0x6E,0x20,
+ 0x63,0x68,0x61,0x6E,0x67,0x69,0x6E,0x67,0x20,0x69,0x74,0x20,
+ 0x6F,0x6E,0x20,0x74,0x68,0x65,0x20,0x73,0x79,0x6E,0x74,0x68,
+ 0x65,0x73,0x69,0x7A,0x65,0x72,0x2C,0x20,0x64,0x6F,0x20,0x69,
+ 0x74,0x20,0x69,0x6E,0x20,0x46,0x54,0x32,0x20,0x69,0x6E,0x73,
+ 0x74,0x65,0x61,0x64,0x2E,0x00,0x18,0x3E,0x40,0x58,0x30,0x34,
+ 0x30,0x40,0x43,0x30,0x30,0x31,0x42,0x65,0x6E,0x64,0x65,0x72,
+ 0x20,0x72,0x61,0x6E,0x67,0x65,0x3A,0x0B,0x3E,0x40,0x58,0x30,
+ 0x36,0x30,0x40,0x43,0x30,0x30,0x32,0x38,0x3E,0x54,0x68,0x69,
+ 0x73,0x20,0x76,0x61,0x6C,0x75,0x65,0x20,0x64,0x65,0x66,0x69,
+ 0x6E,0x65,0x73,0x20,0x68,0x6F,0x77,0x20,0x6D,0x61,0x6E,0x79,
+ 0x20,0x6E,0x6F,0x74,0x65,0x73,0x20,0x74,0x68,0x65,0x20,0x69,
+ 0x6E,0x73,0x74,0x72,0x75,0x6D,0x65,0x6E,0x74,0x20,0x6F,0x6E,
+ 0x20,0x74,0x68,0x65,0x37,0x73,0x79,0x6E,0x74,0x68,0x65,0x73,
+ 0x69,0x7A,0x65,0x72,0x20,0x63,0x61,0x6E,0x20,0x62,0x65,0x20,
+ 0x70,0x69,0x74,0x63,0x68,0x62,0x65,0x6E,0x64,0x65,0x64,0x2E,
+ 0x20,0x46,0x54,0x32,0x20,0x75,0x73,0x65,0x73,0x20,0x74,0x68,
+ 0x69,0x73,0x20,0x76,0x61,0x6C,0x75,0x65,0x20,0x66,0x6F,0x72,
+ 0x37,0x74,0x72,0x61,0x6E,0x73,0x6D,0x69,0x74,0x74,0x69,0x6E,
+ 0x67,0x20,0x74,0x68,0x65,0x20,0x70,0x6F,0x72,0x74,0x61,0x6D,
+ 0x65,0x6E,0x74,0x6F,0x20,0x75,0x70,0x2F,0x64,0x6F,0x77,0x6E,
+ 0x20,0x61,0x6E,0x64,0x20,0x74,0x6F,0x6E,0x65,0x2D,0x70,0x6F,
+ 0x72,0x74,0x61,0x6D,0x65,0x6E,0x74,0x6F,0x13,0x63,0x6F,0x6D,
+ 0x6D,0x61,0x6E,0x64,0x73,0x20,0x63,0x6F,0x72,0x72,0x65,0x63,
+ 0x74,0x6C,0x79,0x2E,0x45,0x3E,0x54,0x68,0x65,0x20,0x4D,0x49,
+ 0x44,0x49,0x2D,0x70,0x69,0x74,0x63,0x68,0x62,0x65,0x6E,0x64,
+ 0x20,0x77,0x6F,0x72,0x6B,0x73,0x20,0x63,0x6F,0x72,0x72,0x65,
+ 0x63,0x74,0x6C,0x79,0x20,0x6F,0x6E,0x6C,0x79,0x20,0x77,0x69,
+ 0x74,0x68,0x20,0x6C,0x69,0x6E,0x65,0x61,0x72,0x20,0x66,0x72,
+ 0x65,0x71,0x75,0x65,0x6E,0x63,0x79,0x20,0x74,0x61,0x62,0x6C,
+ 0x65,0x2E,0x00,0x18,0x40,0x58,0x30,0x32,0x30,0x40,0x43,0x30,
+ 0x30,0x31,0x53,0x61,0x6D,0x70,0x6C,0x65,0x20,0x45,0x64,0x69,
+ 0x74,0x6F,0x72,0x3A,0x01,0x3E,0x2B,0x3E,0x40,0x58,0x30,0x34,
+ 0x30,0x40,0x43,0x30,0x30,0x31,0x50,0x6C,0x61,0x79,0x20,0x28,
+ 0x57,0x61,0x76,0x65,0x66,0x6F,0x72,0x6D,0x2C,0x20,0x72,0x61,
+ 0x6E,0x67,0x65,0x2C,0x20,0x64,0x69,0x73,0x70,0x6C,0x61,0x79,
+ 0x29,0x3A,0x0B,0x3E,0x40,0x58,0x30,0x36,0x30,0x40,0x43,0x30,
+ 0x30,0x32,0x42,0x3E,0x50,0x6C,0x61,0x79,0x73,0x20,0x74,0x68,
+ 0x65,0x20,0x63,0x75,0x72,0x72,0x65,0x6E,0x74,0x20,0x73,0x61,
+ 0x6D,0x70,0x6C,0x65,0x20,0x77,0x69,0x74,0x68,0x20,0x74,0x68,
+ 0x65,0x20,0x6E,0x6F,0x74,0x65,0x20,0x64,0x69,0x73,0x70,0x6C,
+ 0x61,0x79,0x65,0x64,0x20,0x61,0x62,0x6F,0x76,0x65,0x20,0x74,
0x68,0x65,0x20,0x22,0x73,0x74,0x6F,0x70,0x22,0x3D,0x62,0x75,
0x74,0x74,0x6F,0x6E,0x2E,0x20,0x4E,0x6F,0x74,0x65,0x20,0x74,
0x68,0x61,0x74,0x20,0x72,0x65,0x73,0x70,0x65,0x63,0x74,0x20,
@@ -1578,7 +1599,7 @@
0x69,0x73,0x20,0x74,0x61,0x6B,0x65,0x6E,0x20,0x74,0x6F,0x20,
0x74,0x68,0x65,0x20,0x70,0x61,0x72,0x74,0x69,0x63,0x75,0x6C,
0x61,0x72,0x20,0x73,0x61,0x6D,0x70,0x6C,0x65,0x27,0x73,0x0E,
- 0x72,0x65,0x6C,0x61,0x74,0x69,0x76,0x65,0x20,0x74,0x6F,0x6E,
+ 0x72,0x65,0x6C,0x61,0x74,0x69,0x76,0x65,0x20,0x6E,0x6F,0x74,
0x65,0x2E,0x00,0x16,0x3E,0x40,0x58,0x30,0x34,0x30,0x40,0x43,
0x30,0x30,0x31,0x53,0x61,0x76,0x65,0x20,0x72,0x61,0x6E,0x67,
0x65,0x3A,0x0B,0x3E,0x40,0x58,0x30,0x36,0x30,0x40,0x43,0x30,
@@ -1689,543 +1710,542 @@
0x61,0x6E,0x67,0x65,0x20,0x28,0x6F,0x72,0x20,0x74,0x68,0x65,
0x20,0x77,0x68,0x6F,0x6C,0x65,0x20,0x73,0x61,0x6D,0x70,0x6C,
0x65,0x20,0x69,0x66,0x20,0x6E,0x6F,0x20,0x72,0x61,0x6E,0x67,
- 0x65,0x20,0x69,0x73,0x20,0x73,0x65,0x74,0x29,0x2E,0x00,0x13,
- 0x3E,0x40,0x58,0x30,0x34,0x30,0x40,0x43,0x30,0x30,0x31,0x43,
- 0x6F,0x6E,0x76,0x65,0x72,0x74,0x3A,0x0B,0x3E,0x40,0x58,0x30,
- 0x36,0x30,0x40,0x43,0x30,0x30,0x32,0x34,0x3E,0x43,0x6F,0x6E,
- 0x76,0x65,0x72,0x74,0x73,0x20,0x74,0x68,0x65,0x20,0x65,0x6E,
- 0x74,0x69,0x72,0x65,0x20,0x73,0x61,0x6D,0x70,0x6C,0x65,0x20,
- 0x66,0x72,0x6F,0x6D,0x2F,0x74,0x6F,0x20,0x73,0x69,0x67,0x6E,
- 0x65,0x64,0x2F,0x75,0x6E,0x73,0x69,0x67,0x6E,0x65,0x64,0x2E,
- 0x00,0x15,0x3E,0x40,0x58,0x30,0x34,0x30,0x40,0x43,0x30,0x30,
- 0x31,0x43,0x6F,0x6E,0x76,0x65,0x72,0x74,0x20,0x57,0x3A,0x0B,
- 0x3E,0x40,0x58,0x30,0x36,0x30,0x40,0x43,0x30,0x30,0x32,0x3F,
- 0x53,0x77,0x61,0x70,0x73,0x20,0x74,0x68,0x65,0x20,0x62,0x79,
- 0x74,0x65,0x20,0x6F,0x72,0x64,0x65,0x72,0x20,0x74,0x6F,0x2F,
- 0x66,0x72,0x6F,0x6D,0x20,0x49,0x6E,0x74,0x65,0x6C,0x20,0x66,
- 0x72,0x6F,0x6D,0x2F,0x74,0x6F,0x20,0x4D,0x6F,0x74,0x6F,0x72,
- 0x6F,0x6C,0x61,0x20,0x73,0x74,0x61,0x6E,0x64,0x61,0x72,0x64,
- 0x20,0x6F,0x6E,0x12,0x74,0x68,0x65,0x20,0x65,0x6E,0x74,0x69,
- 0x72,0x65,0x20,0x73,0x61,0x6D,0x70,0x6C,0x65,0x2E,0x44,0x59,
- 0x6F,0x75,0x27,0x6C,0x6C,0x20,0x6E,0x65,0x65,0x64,0x20,0x74,
- 0x68,0x69,0x73,0x20,0x66,0x75,0x6E,0x63,0x74,0x69,0x6F,0x6E,
- 0x20,0x69,0x66,0x20,0x79,0x6F,0x75,0x20,0x69,0x6D,0x70,0x6F,
- 0x72,0x74,0x20,0x31,0x36,0x2D,0x62,0x69,0x74,0x20,0x73,0x61,
- 0x6D,0x70,0x6C,0x65,0x73,0x20,0x77,0x69,0x74,0x68,0x20,0x4D,
- 0x6F,0x74,0x6F,0x72,0x6F,0x6C,0x61,0x2D,0x62,0x79,0x74,0x65,
- 0x2D,0x6F,0x72,0x64,0x65,0x72,0x69,0x6E,0x67,0x20,0x28,0x66,
- 0x2E,0x65,0x78,0x2E,0x20,0x4B,0x75,0x72,0x7A,0x77,0x65,0x69,
- 0x6C,0x20,0x4B,0x32,0x30,0x30,0x30,0x20,0x73,0x61,0x6D,0x70,
- 0x6C,0x65,0x73,0x2E,0x29,0x00,0x10,0x3E,0x40,0x58,0x30,0x34,
- 0x30,0x40,0x43,0x30,0x30,0x31,0x45,0x63,0x68,0x6F,0x3A,0x0B,
- 0x3E,0x40,0x58,0x30,0x36,0x30,0x40,0x43,0x30,0x30,0x32,0x1E,
- 0x4F,0x70,0x65,0x72,0x61,0x74,0x65,0x73,0x20,0x6F,0x6E,0x20,
- 0x74,0x68,0x65,0x20,0x65,0x6E,0x74,0x69,0x72,0x65,0x20,0x73,
- 0x61,0x6D,0x70,0x6C,0x65,0x2E,0x00,0x12,0x3E,0x40,0x58,0x30,
- 0x34,0x30,0x40,0x43,0x30,0x30,0x31,0x46,0x69,0x78,0x20,0x44,
- 0x43,0x3A,0x0B,0x3E,0x40,0x58,0x30,0x36,0x30,0x40,0x43,0x30,
- 0x30,0x32,0x3D,0x41,0x74,0x74,0x65,0x6D,0x70,0x74,0x73,0x20,
- 0x74,0x6F,0x20,0x63,0x65,0x6E,0x74,0x65,0x72,0x20,0x61,0x20,
- 0x73,0x61,0x6D,0x70,0x6C,0x65,0x20,0x74,0x68,0x61,0x74,0x20,
- 0x68,0x61,0x73,0x20,0x75,0x6E,0x77,0x61,0x6E,0x74,0x65,0x64,
- 0x20,0x44,0x43,0x20,0x6F,0x66,0x66,0x73,0x65,0x74,0x2F,0x62,
- 0x69,0x61,0x73,0x2E,0x43,0x50,0x6C,0x65,0x61,0x73,0x65,0x20,
- 0x6E,0x6F,0x74,0x65,0x20,0x74,0x68,0x61,0x74,0x20,0x69,0x74,
- 0x20,0x69,0x73,0x20,0x75,0x73,0x69,0x6E,0x67,0x20,0x61,0x20,
- 0x63,0x72,0x75,0x64,0x65,0x20,0x61,0x6C,0x67,0x6F,0x72,0x69,
- 0x74,0x68,0x6D,0x2C,0x20,0x73,0x6F,0x20,0x69,0x74,0x20,0x63,
- 0x61,0x6E,0x20,0x73,0x6F,0x6D,0x65,0x74,0x69,0x6D,0x65,0x73,
- 0x22,0x66,0x61,0x69,0x6C,0x20,0x64,0x65,0x70,0x65,0x6E,0x64,
- 0x69,0x6E,0x67,0x20,0x6F,0x6E,0x20,0x74,0x68,0x65,0x20,0x73,
- 0x61,0x6D,0x70,0x6C,0x65,0x20,0x64,0x61,0x74,0x61,0x2E,0x00,
- 0x14,0x3E,0x40,0x58,0x30,0x34,0x30,0x40,0x43,0x30,0x30,0x31,
- 0x52,0x65,0x73,0x61,0x6D,0x70,0x6C,0x65,0x3A,0x0B,0x3E,0x40,
- 0x58,0x30,0x36,0x30,0x40,0x43,0x30,0x30,0x32,0x3C,0x4F,0x70,
- 0x65,0x72,0x61,0x74,0x65,0x73,0x20,0x6F,0x6E,0x20,0x74,0x68,
- 0x65,0x20,0x65,0x6E,0x74,0x69,0x72,0x65,0x20,0x73,0x61,0x6D,
- 0x70,0x6C,0x65,0x2E,0x20,0x54,0x68,0x65,0x20,0x73,0x61,0x6D,
- 0x70,0x6C,0x65,0x27,0x73,0x20,0x72,0x65,0x6C,0x61,0x74,0x69,
- 0x76,0x65,0x20,0x74,0x6F,0x6E,0x65,0x20,0x69,0x73,0x2C,0x63,
- 0x68,0x61,0x6E,0x67,0x65,0x64,0x20,0x77,0x69,0x74,0x68,0x20,
- 0x72,0x65,0x73,0x70,0x65,0x63,0x74,0x20,0x74,0x6F,0x20,0x74,
- 0x68,0x65,0x20,0x72,0x65,0x73,0x61,0x6D,0x70,0x6C,0x69,0x6E,
- 0x67,0x20,0x72,0x61,0x74,0x65,0x2E,0x00,0x16,0x3E,0x40,0x58,
- 0x30,0x34,0x30,0x40,0x43,0x30,0x30,0x31,0x4D,0x69,0x78,0x20,
- 0x73,0x61,0x6D,0x70,0x6C,0x65,0x3A,0x0B,0x3E,0x40,0x58,0x30,
- 0x36,0x30,0x40,0x43,0x30,0x30,0x32,0x35,0x3E,0x4D,0x69,0x78,
- 0x65,0x73,0x20,0x74,0x68,0x65,0x20,0x73,0x6F,0x75,0x72,0x63,
- 0x65,0x20,0x77,0x69,0x74,0x68,0x20,0x74,0x68,0x65,0x20,0x64,
- 0x65,0x73,0x74,0x69,0x6E,0x61,0x74,0x69,0x6F,0x6E,0x20,0x74,
- 0x6F,0x20,0x74,0x68,0x65,0x20,0x73,0x6F,0x75,0x72,0x63,0x65,
- 0x2E,0x00,0x15,0x3E,0x40,0x58,0x30,0x34,0x30,0x40,0x43,0x30,
- 0x30,0x31,0x44,0x72,0x61,0x77,0x20,0x6D,0x6F,0x64,0x65,0x3A,
+ 0x65,0x20,0x69,0x73,0x20,0x73,0x65,0x74,0x29,0x2E,0x00,0x10,
+ 0x3E,0x40,0x58,0x30,0x34,0x30,0x40,0x43,0x30,0x30,0x31,0x53,
+ 0x69,0x67,0x6E,0x3A,0x0B,0x3E,0x40,0x58,0x30,0x36,0x30,0x40,
+ 0x43,0x30,0x30,0x32,0x22,0x3E,0x43,0x6F,0x6E,0x76,0x65,0x72,
+ 0x74,0x73,0x20,0x62,0x65,0x74,0x77,0x65,0x65,0x6E,0x20,0x73,
+ 0x69,0x67,0x6E,0x65,0x64,0x2F,0x75,0x6E,0x73,0x69,0x67,0x6E,
+ 0x65,0x64,0x2E,0x00,0x1F,0x3E,0x40,0x58,0x30,0x34,0x30,0x40,
+ 0x43,0x30,0x30,0x31,0x42,0x2E,0x20,0x73,0x77,0x61,0x70,0x20,
+ 0x28,0x62,0x79,0x74,0x65,0x20,0x73,0x77,0x61,0x70,0x29,0x3A,
0x0B,0x3E,0x40,0x58,0x30,0x36,0x30,0x40,0x43,0x30,0x30,0x32,
- 0x40,0x42,0x79,0x20,0x70,0x72,0x65,0x73,0x73,0x69,0x6E,0x67,
- 0x20,0x74,0x68,0x65,0x20,0x72,0x69,0x67,0x68,0x74,0x20,0x6D,
- 0x6F,0x75,0x73,0x65,0x20,0x62,0x75,0x74,0x74,0x6F,0x6E,0x20,
- 0x69,0x6E,0x20,0x74,0x68,0x65,0x20,0x73,0x61,0x6D,0x70,0x6C,
- 0x65,0x20,0x77,0x69,0x6E,0x64,0x6F,0x77,0x2C,0x20,0x79,0x6F,
- 0x75,0x20,0x63,0x61,0x6E,0x1D,0x64,0x72,0x61,0x77,0x20,0x79,
- 0x6F,0x75,0x72,0x20,0x77,0x61,0x76,0x65,0x66,0x6F,0x72,0x6D,
- 0x73,0x20,0x6D,0x61,0x6E,0x75,0x61,0x6C,0x6C,0x79,0x2E,0x00,
- 0x18,0x40,0x58,0x30,0x32,0x30,0x40,0x43,0x30,0x30,0x31,0x43,
- 0x6F,0x6E,0x66,0x69,0x67,0x75,0x72,0x61,0x74,0x69,0x6F,0x6E,
- 0x3A,0x01,0x3E,0x15,0x3E,0x40,0x58,0x30,0x34,0x30,0x40,0x43,
- 0x30,0x30,0x31,0x41,0x75,0x74,0x6F,0x20,0x73,0x61,0x76,0x65,
+ 0x3F,0x53,0x77,0x61,0x70,0x73,0x20,0x74,0x68,0x65,0x20,0x62,
+ 0x79,0x74,0x65,0x20,0x6F,0x72,0x64,0x65,0x72,0x20,0x74,0x6F,
+ 0x2F,0x66,0x72,0x6F,0x6D,0x20,0x49,0x6E,0x74,0x65,0x6C,0x20,
+ 0x66,0x72,0x6F,0x6D,0x2F,0x74,0x6F,0x20,0x4D,0x6F,0x74,0x6F,
+ 0x72,0x6F,0x6C,0x61,0x20,0x73,0x74,0x61,0x6E,0x64,0x61,0x72,
+ 0x64,0x20,0x6F,0x6E,0x12,0x74,0x68,0x65,0x20,0x65,0x6E,0x74,
+ 0x69,0x72,0x65,0x20,0x73,0x61,0x6D,0x70,0x6C,0x65,0x2E,0x44,
+ 0x59,0x6F,0x75,0x27,0x6C,0x6C,0x20,0x6E,0x65,0x65,0x64,0x20,
+ 0x74,0x68,0x69,0x73,0x20,0x66,0x75,0x6E,0x63,0x74,0x69,0x6F,
+ 0x6E,0x20,0x69,0x66,0x20,0x79,0x6F,0x75,0x20,0x69,0x6D,0x70,
+ 0x6F,0x72,0x74,0x20,0x31,0x36,0x2D,0x62,0x69,0x74,0x20,0x73,
+ 0x61,0x6D,0x70,0x6C,0x65,0x73,0x20,0x77,0x69,0x74,0x68,0x20,
+ 0x4D,0x6F,0x74,0x6F,0x72,0x6F,0x6C,0x61,0x2D,0x62,0x79,0x74,
+ 0x65,0x2D,0x6F,0x72,0x64,0x65,0x72,0x69,0x6E,0x67,0x20,0x28,
+ 0x66,0x2E,0x65,0x78,0x2E,0x20,0x4B,0x75,0x72,0x7A,0x77,0x65,
+ 0x69,0x6C,0x20,0x4B,0x32,0x30,0x30,0x30,0x20,0x73,0x61,0x6D,
+ 0x70,0x6C,0x65,0x73,0x2E,0x29,0x00,0x10,0x3E,0x40,0x58,0x30,
+ 0x34,0x30,0x40,0x43,0x30,0x30,0x31,0x45,0x63,0x68,0x6F,0x3A,
+ 0x0B,0x3E,0x40,0x58,0x30,0x36,0x30,0x40,0x43,0x30,0x30,0x32,
+ 0x1E,0x4F,0x70,0x65,0x72,0x61,0x74,0x65,0x73,0x20,0x6F,0x6E,
+ 0x20,0x74,0x68,0x65,0x20,0x65,0x6E,0x74,0x69,0x72,0x65,0x20,
+ 0x73,0x61,0x6D,0x70,0x6C,0x65,0x2E,0x00,0x12,0x3E,0x40,0x58,
+ 0x30,0x34,0x30,0x40,0x43,0x30,0x30,0x31,0x46,0x69,0x78,0x20,
+ 0x44,0x43,0x3A,0x0B,0x3E,0x40,0x58,0x30,0x36,0x30,0x40,0x43,
+ 0x30,0x30,0x32,0x3D,0x41,0x74,0x74,0x65,0x6D,0x70,0x74,0x73,
+ 0x20,0x74,0x6F,0x20,0x63,0x65,0x6E,0x74,0x65,0x72,0x20,0x61,
+ 0x20,0x73,0x61,0x6D,0x70,0x6C,0x65,0x20,0x74,0x68,0x61,0x74,
+ 0x20,0x68,0x61,0x73,0x20,0x75,0x6E,0x77,0x61,0x6E,0x74,0x65,
+ 0x64,0x20,0x44,0x43,0x20,0x6F,0x66,0x66,0x73,0x65,0x74,0x2F,
+ 0x62,0x69,0x61,0x73,0x2E,0x43,0x50,0x6C,0x65,0x61,0x73,0x65,
+ 0x20,0x6E,0x6F,0x74,0x65,0x20,0x74,0x68,0x61,0x74,0x20,0x69,
+ 0x74,0x20,0x69,0x73,0x20,0x75,0x73,0x69,0x6E,0x67,0x20,0x61,
+ 0x20,0x63,0x72,0x75,0x64,0x65,0x20,0x61,0x6C,0x67,0x6F,0x72,
+ 0x69,0x74,0x68,0x6D,0x2C,0x20,0x73,0x6F,0x20,0x69,0x74,0x20,
+ 0x63,0x61,0x6E,0x20,0x73,0x6F,0x6D,0x65,0x74,0x69,0x6D,0x65,
+ 0x73,0x22,0x66,0x61,0x69,0x6C,0x20,0x64,0x65,0x70,0x65,0x6E,
+ 0x64,0x69,0x6E,0x67,0x20,0x6F,0x6E,0x20,0x74,0x68,0x65,0x20,
+ 0x73,0x61,0x6D,0x70,0x6C,0x65,0x20,0x64,0x61,0x74,0x61,0x2E,
+ 0x00,0x14,0x3E,0x40,0x58,0x30,0x34,0x30,0x40,0x43,0x30,0x30,
+ 0x31,0x52,0x65,0x73,0x61,0x6D,0x70,0x6C,0x65,0x3A,0x0B,0x3E,
+ 0x40,0x58,0x30,0x36,0x30,0x40,0x43,0x30,0x30,0x32,0x3C,0x4F,
+ 0x70,0x65,0x72,0x61,0x74,0x65,0x73,0x20,0x6F,0x6E,0x20,0x74,
+ 0x68,0x65,0x20,0x65,0x6E,0x74,0x69,0x72,0x65,0x20,0x73,0x61,
+ 0x6D,0x70,0x6C,0x65,0x2E,0x20,0x54,0x68,0x65,0x20,0x73,0x61,
+ 0x6D,0x70,0x6C,0x65,0x27,0x73,0x20,0x72,0x65,0x6C,0x61,0x74,
+ 0x69,0x76,0x65,0x20,0x6E,0x6F,0x74,0x65,0x20,0x69,0x73,0x2C,
+ 0x63,0x68,0x61,0x6E,0x67,0x65,0x64,0x20,0x77,0x69,0x74,0x68,
+ 0x20,0x72,0x65,0x73,0x70,0x65,0x63,0x74,0x20,0x74,0x6F,0x20,
+ 0x74,0x68,0x65,0x20,0x72,0x65,0x73,0x61,0x6D,0x70,0x6C,0x69,
+ 0x6E,0x67,0x20,0x72,0x61,0x74,0x65,0x2E,0x00,0x16,0x3E,0x40,
+ 0x58,0x30,0x34,0x30,0x40,0x43,0x30,0x30,0x31,0x4D,0x69,0x78,
+ 0x20,0x73,0x61,0x6D,0x70,0x6C,0x65,0x3A,0x0B,0x3E,0x40,0x58,
+ 0x30,0x36,0x30,0x40,0x43,0x30,0x30,0x32,0x35,0x3E,0x4D,0x69,
+ 0x78,0x65,0x73,0x20,0x74,0x68,0x65,0x20,0x73,0x6F,0x75,0x72,
+ 0x63,0x65,0x20,0x77,0x69,0x74,0x68,0x20,0x74,0x68,0x65,0x20,
+ 0x64,0x65,0x73,0x74,0x69,0x6E,0x61,0x74,0x69,0x6F,0x6E,0x20,
+ 0x74,0x6F,0x20,0x74,0x68,0x65,0x20,0x73,0x6F,0x75,0x72,0x63,
+ 0x65,0x2E,0x00,0x15,0x3E,0x40,0x58,0x30,0x34,0x30,0x40,0x43,
+ 0x30,0x30,0x31,0x44,0x72,0x61,0x77,0x20,0x6D,0x6F,0x64,0x65,
0x3A,0x0B,0x3E,0x40,0x58,0x30,0x36,0x30,0x40,0x43,0x30,0x30,
- 0x32,0x43,0x49,0x66,0x20,0x74,0x68,0x65,0x20,0x61,0x75,0x74,
- 0x6F,0x20,0x73,0x61,0x76,0x65,0x20,0x69,0x73,0x20,0x6F,0x6E,
- 0x2C,0x20,0x46,0x54,0x32,0x20,0x77,0x69,0x6C,0x6C,0x20,0x75,
- 0x70,0x64,0x61,0x74,0x65,0x20,0x74,0x68,0x65,0x20,0x63,0x6F,
- 0x6E,0x66,0x69,0x67,0x75,0x72,0x61,0x74,0x69,0x6F,0x6E,0x20,
- 0x66,0x69,0x6C,0x65,0x20,0x77,0x68,0x65,0x6E,0x15,0x79,0x6F,
- 0x75,0x20,0x65,0x78,0x69,0x74,0x20,0x74,0x68,0x65,0x20,0x70,
- 0x72,0x6F,0x67,0x72,0x61,0x6D,0x2E,0x00,0x25,0x40,0x58,0x30,
- 0x32,0x30,0x40,0x43,0x30,0x30,0x31,0x43,0x6F,0x6E,0x66,0x69,
- 0x67,0x75,0x72,0x61,0x74,0x69,0x6F,0x6E,0x2C,0x20,0x49,0x2F,
- 0x4F,0x20,0x64,0x65,0x76,0x69,0x63,0x65,0x73,0x3A,0x01,0x3E,
- 0x19,0x3E,0x40,0x58,0x30,0x34,0x30,0x40,0x43,0x30,0x30,0x31,
- 0x49,0x6E,0x74,0x65,0x72,0x70,0x6F,0x6C,0x61,0x74,0x69,0x6F,
- 0x6E,0x3A,0x0B,0x3E,0x40,0x58,0x30,0x36,0x30,0x40,0x43,0x30,
- 0x30,0x32,0x35,0x53,0x65,0x6C,0x65,0x63,0x74,0x73,0x20,0x77,
- 0x68,0x61,0x74,0x20,0x74,0x79,0x70,0x65,0x20,0x6F,0x66,0x20,
- 0x72,0x65,0x73,0x61,0x6D,0x70,0x6C,0x69,0x6E,0x67,0x20,0x69,
- 0x6E,0x74,0x65,0x72,0x70,0x6F,0x6C,0x61,0x74,0x69,0x6F,0x6E,
- 0x20,0x74,0x6F,0x20,0x75,0x73,0x65,0x2E,0x45,0x22,0x4E,0x6F,
- 0x6E,0x65,0x22,0x20,0x75,0x73,0x65,0x73,0x20,0x6E,0x6F,0x20,
- 0x69,0x6E,0x74,0x65,0x72,0x70,0x6F,0x6C,0x61,0x74,0x69,0x6F,
- 0x6E,0x20,0x28,0x6E,0x65,0x61,0x72,0x65,0x73,0x74,0x20,0x6E,
- 0x65,0x69,0x67,0x68,0x62,0x6F,0x72,0x29,0x2C,0x20,0x77,0x68,
- 0x69,0x63,0x68,0x20,0x77,0x69,0x6C,0x6C,0x20,0x72,0x65,0x73,
- 0x75,0x6C,0x74,0x20,0x69,0x6E,0x49,0x61,0x6C,0x69,0x61,0x73,
- 0x69,0x6E,0x67,0x20,0x28,0x6E,0x6F,0x69,0x73,0x65,0x29,0x20,
- 0x69,0x6E,0x20,0x74,0x68,0x65,0x20,0x73,0x6F,0x75,0x6E,0x64,
- 0x2E,0x20,0x22,0x4C,0x69,0x6E,0x65,0x61,0x72,0x22,0x20,0x69,
- 0x73,0x20,0x77,0x68,0x61,0x74,0x20,0x72,0x65,0x61,0x6C,0x20,
- 0x46,0x54,0x32,0x20,0x75,0x73,0x65,0x73,0x2C,0x20,0x77,0x68,
- 0x69,0x63,0x68,0x20,0x69,0x73,0x20,0x61,0x47,0x6D,0x65,0x64,
- 0x69,0x6F,0x63,0x72,0x65,0x20,0x69,0x6E,0x74,0x65,0x72,0x70,
- 0x6F,0x6C,0x61,0x74,0x69,0x6F,0x6E,0x20,0x74,0x79,0x70,0x65,
- 0x2E,0x20,0x22,0x57,0x69,0x6E,0x64,0x6F,0x77,0x65,0x64,0x2D,
- 0x73,0x69,0x6E,0x63,0x22,0x20,0x69,0x73,0x20,0x74,0x68,0x65,
- 0x20,0x72,0x65,0x63,0x6F,0x6D,0x6D,0x65,0x6E,0x64,0x65,0x64,
- 0x20,0x73,0x65,0x74,0x74,0x69,0x6E,0x67,0x48,0x66,0x6F,0x72,
- 0x20,0x74,0x68,0x65,0x20,0x62,0x65,0x73,0x74,0x20,0x61,0x75,
- 0x64,0x69,0x6F,0x20,0x71,0x75,0x61,0x6C,0x69,0x74,0x79,0x2C,
- 0x20,0x61,0x6C,0x74,0x68,0x6F,0x75,0x67,0x68,0x20,0x69,0x74,
- 0x20,0x6D,0x61,0x79,0x20,0x73,0x6F,0x6D,0x65,0x74,0x69,0x6D,
- 0x65,0x73,0x20,0x73,0x6F,0x75,0x6E,0x64,0x20,0x74,0x6F,0x6F,
- 0x20,0x66,0x69,0x6C,0x74,0x65,0x72,0x65,0x64,0x2A,0x6F,0x6E,
- 0x20,0x6C,0x6F,0x77,0x2D,0x71,0x75,0x61,0x6C,0x69,0x74,0x79,
- 0x20,0x73,0x61,0x6D,0x70,0x6C,0x65,0x73,0x20,0x28,0x66,0x2E,
- 0x65,0x78,0x2E,0x20,0x41,0x6D,0x69,0x67,0x61,0x20,0x4D,0x4F,
- 0x44,0x73,0x29,0x2E,0x00,0x1A,0x3E,0x40,0x58,0x30,0x34,0x30,
- 0x40,0x43,0x30,0x30,0x31,0x56,0x6F,0x6C,0x75,0x6D,0x65,0x20,
- 0x72,0x61,0x6D,0x70,0x69,0x6E,0x67,0x3A,0x0B,0x3E,0x40,0x58,
- 0x30,0x36,0x30,0x40,0x43,0x30,0x30,0x32,0x3B,0x45,0x6E,0x61,
- 0x62,0x6C,0x65,0x73,0x20,0x74,0x68,0x65,0x20,0x61,0x6E,0x74,
- 0x69,0x2D,0x63,0x6C,0x69,0x63,0x6B,0x20,0x73,0x79,0x73,0x74,
- 0x65,0x6D,0x20,0x69,0x6E,0x20,0x74,0x68,0x65,0x20,0x61,0x75,
- 0x64,0x69,0x6F,0x20,0x6D,0x69,0x78,0x65,0x72,0x20,0x28,0x46,
- 0x54,0x32,0x2E,0x30,0x38,0x2B,0x29,0x2E,0x3B,0x50,0x6C,0x65,
- 0x61,0x73,0x65,0x20,0x6E,0x6F,0x74,0x65,0x20,0x74,0x68,0x61,
- 0x74,0x20,0x6F,0x72,0x69,0x67,0x69,0x6E,0x61,0x6C,0x20,0x46,
- 0x54,0x32,0x20,0x63,0x61,0x6E,0x27,0x74,0x20,0x6C,0x6F,0x61,
- 0x64,0x20,0x74,0x68,0x69,0x73,0x20,0x63,0x6F,0x6E,0x66,0x69,
- 0x67,0x20,0x65,0x6E,0x74,0x72,0x79,0x2C,0x0B,0x63,0x6C,0x6F,
- 0x6E,0x65,0x20,0x6F,0x6E,0x6C,0x79,0x2E,0x00,0x19,0x3E,0x40,
- 0x58,0x30,0x34,0x30,0x40,0x43,0x30,0x30,0x31,0x41,0x6D,0x70,
- 0x6C,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x3A,0x0B,
- 0x3E,0x40,0x58,0x30,0x36,0x30,0x40,0x43,0x30,0x30,0x32,0x46,
- 0x41,0x6D,0x70,0x6C,0x69,0x66,0x69,0x65,0x73,0x20,0x74,0x68,
- 0x65,0x20,0x76,0x6F,0x6C,0x75,0x6D,0x65,0x20,0x77,0x68,0x65,
- 0x6E,0x20,0x6D,0x69,0x78,0x69,0x6E,0x67,0x2E,0x20,0x49,0x66,
- 0x20,0x79,0x6F,0x75,0x20,0x73,0x65,0x74,0x20,0x74,0x68,0x69,
- 0x73,0x20,0x6F,0x6E,0x65,0x20,0x74,0x6F,0x6F,0x20,0x68,0x69,
- 0x67,0x68,0x2C,0x20,0x79,0x6F,0x75,0x27,0x6C,0x6C,0x3A,0x67,
- 0x65,0x74,0x20,0x64,0x69,0x73,0x74,0x6F,0x72,0x74,0x69,0x6F,
- 0x6E,0x2E,0x20,0x33,0x32,0x58,0x20,0x65,0x71,0x75,0x61,0x6C,
- 0x73,0x20,0x66,0x75,0x6C,0x6C,0x20,0x61,0x6D,0x70,0x6C,0x69,
- 0x74,0x75,0x64,0x65,0x20,0x66,0x6F,0x72,0x20,0x6F,0x6E,0x65,
- 0x20,0x63,0x68,0x61,0x6E,0x6E,0x65,0x6C,0x2E,0x00,0x1B,0x3E,
- 0x40,0x58,0x30,0x34,0x30,0x40,0x43,0x30,0x30,0x31,0x46,0x72,
- 0x65,0x71,0x75,0x65,0x6E,0x63,0x79,0x20,0x74,0x61,0x62,0x6C,
+ 0x32,0x40,0x42,0x79,0x20,0x70,0x72,0x65,0x73,0x73,0x69,0x6E,
+ 0x67,0x20,0x74,0x68,0x65,0x20,0x72,0x69,0x67,0x68,0x74,0x20,
+ 0x6D,0x6F,0x75,0x73,0x65,0x20,0x62,0x75,0x74,0x74,0x6F,0x6E,
+ 0x20,0x69,0x6E,0x20,0x74,0x68,0x65,0x20,0x73,0x61,0x6D,0x70,
+ 0x6C,0x65,0x20,0x77,0x69,0x6E,0x64,0x6F,0x77,0x2C,0x20,0x79,
+ 0x6F,0x75,0x20,0x63,0x61,0x6E,0x1D,0x64,0x72,0x61,0x77,0x20,
+ 0x79,0x6F,0x75,0x72,0x20,0x77,0x61,0x76,0x65,0x66,0x6F,0x72,
+ 0x6D,0x73,0x20,0x6D,0x61,0x6E,0x75,0x61,0x6C,0x6C,0x79,0x2E,
+ 0x00,0x18,0x40,0x58,0x30,0x32,0x30,0x40,0x43,0x30,0x30,0x31,
+ 0x43,0x6F,0x6E,0x66,0x69,0x67,0x75,0x72,0x61,0x74,0x69,0x6F,
+ 0x6E,0x3A,0x01,0x3E,0x15,0x3E,0x40,0x58,0x30,0x34,0x30,0x40,
+ 0x43,0x30,0x30,0x31,0x41,0x75,0x74,0x6F,0x20,0x73,0x61,0x76,
0x65,0x3A,0x0B,0x3E,0x40,0x58,0x30,0x36,0x30,0x40,0x43,0x30,
- 0x30,0x32,0x40,0x54,0x68,0x65,0x20,0x6C,0x69,0x6E,0x65,0x61,
- 0x72,0x20,0x66,0x72,0x65,0x71,0x75,0x65,0x6E,0x63,0x79,0x20,
- 0x74,0x61,0x62,0x6C,0x65,0x20,0x6D,0x61,0x6B,0x65,0x73,0x20,
- 0x61,0x6C,0x6C,0x20,0x70,0x69,0x74,0x63,0x68,0x20,0x62,0x65,
- 0x6E,0x64,0x73,0x20,0x72,0x75,0x6E,0x20,0x69,0x6E,0x20,0x63,
- 0x6F,0x6E,0x73,0x74,0x61,0x6E,0x74,0x3F,0x73,0x70,0x65,0x65,
- 0x64,0x2C,0x20,0x69,0x6E,0x64,0x65,0x70,0x65,0x6E,0x64,0x65,
- 0x6E,0x74,0x20,0x6F,0x66,0x20,0x74,0x68,0x65,0x20,0x63,0x75,
- 0x72,0x72,0x65,0x6E,0x74,0x20,0x66,0x72,0x65,0x71,0x75,0x65,
- 0x6E,0x63,0x79,0x2E,0x20,0x49,0x66,0x20,0x79,0x6F,0x75,0x20,
- 0x73,0x77,0x69,0x74,0x63,0x68,0x20,0x74,0x68,0x69,0x73,0x41,
- 0x6F,0x6E,0x65,0x2C,0x20,0x6F,0x6E,0x20,0x61,0x20,0x66,0x69,
- 0x6E,0x69,0x73,0x68,0x65,0x64,0x20,0x73,0x6F,0x6E,0x67,0x2C,
- 0x20,0x69,0x74,0x20,0x6D,0x69,0x67,0x68,0x74,0x20,0x73,0x6F,
- 0x75,0x6E,0x64,0x20,0x73,0x74,0x72,0x61,0x6E,0x67,0x65,0x20,
- 0x69,0x66,0x20,0x74,0x68,0x65,0x20,0x73,0x6F,0x75,0x6E,0x64,
- 0x20,0x75,0x73,0x65,0x73,0x0D,0x70,0x6F,0x72,0x74,0x61,0x6D,
- 0x65,0x6E,0x74,0x6F,0x65,0x73,0x2E,0x00,0x20,0x40,0x58,0x30,
- 0x32,0x30,0x40,0x43,0x30,0x30,0x31,0x43,0x6F,0x6E,0x66,0x69,
- 0x67,0x75,0x72,0x61,0x74,0x69,0x6F,0x6E,0x2C,0x20,0x4C,0x61,
- 0x79,0x6F,0x75,0x74,0x3A,0x01,0x3E,0x29,0x3E,0x40,0x58,0x30,
- 0x34,0x30,0x40,0x43,0x30,0x30,0x31,0x50,0x61,0x74,0x74,0x65,
- 0x72,0x6E,0x20,0x6C,0x61,0x79,0x6F,0x75,0x74,0x2C,0x20,0x68,
- 0x65,0x78,0x20,0x6E,0x75,0x6D,0x62,0x65,0x72,0x69,0x6E,0x67,
- 0x3A,0x0B,0x3E,0x40,0x58,0x30,0x36,0x30,0x40,0x43,0x30,0x30,
- 0x32,0x41,0x49,0x66,0x20,0x79,0x6F,0x75,0x20,0x75,0x73,0x65,
- 0x20,0x70,0x61,0x74,0x74,0x65,0x72,0x6E,0x73,0x20,0x74,0x68,
- 0x61,0x74,0x20,0x61,0x72,0x65,0x20,0x6C,0x6F,0x6E,0x67,0x65,
- 0x72,0x20,0x74,0x68,0x61,0x6E,0x20,0x39,0x39,0x20,0x6C,0x69,
- 0x6E,0x65,0x73,0x2C,0x20,0x79,0x6F,0x75,0x20,0x73,0x68,0x6F,
- 0x75,0x6C,0x64,0x20,0x75,0x73,0x65,0x45,0x68,0x65,0x78,0x20,
- 0x63,0x6F,0x75,0x6E,0x74,0x69,0x6E,0x67,0x20,0x73,0x69,0x6E,
- 0x63,0x65,0x20,0x74,0x68,0x65,0x72,0x65,0x20,0x61,0x72,0x65,
- 0x20,0x6F,0x6E,0x6C,0x79,0x20,0x32,0x20,0x64,0x69,0x67,0x69,
- 0x74,0x73,0x20,0x69,0x6E,0x20,0x74,0x68,0x65,0x20,0x6C,0x69,
- 0x6E,0x65,0x20,0x6E,0x75,0x6D,0x62,0x65,0x72,0x20,0x63,0x6F,
- 0x6C,0x75,0x6D,0x6E,0x2E,0x00,0x12,0x3E,0x40,0x58,0x30,0x34,
- 0x30,0x40,0x43,0x30,0x30,0x31,0x53,0x63,0x6F,0x70,0x65,0x73,
- 0x3A,0x0B,0x3E,0x40,0x58,0x30,0x36,0x30,0x40,0x43,0x30,0x30,
- 0x32,0x43,0x22,0x53,0x74,0x64,0x2E,0x22,0x20,0x28,0x73,0x74,
- 0x61,0x6E,0x64,0x61,0x72,0x64,0x29,0x20,0x77,0x69,0x6C,0x6C,
- 0x20,0x73,0x68,0x6F,0x77,0x20,0x74,0x68,0x65,0x20,0x73,0x61,
- 0x6D,0x70,0x6C,0x65,0x20,0x70,0x6F,0x69,0x6E,0x74,0x73,0x20,
- 0x61,0x73,0x20,0x70,0x69,0x78,0x65,0x6C,0x73,0x20,0x28,0x6C,
- 0x69,0x6B,0x65,0x20,0x46,0x54,0x32,0x29,0x2E,0x41,0x22,0x4C,
- 0x69,0x6E,0x65,0x64,0x22,0x20,0x77,0x69,0x6C,0x6C,0x20,0x64,
- 0x72,0x61,0x77,0x20,0x6C,0x69,0x6E,0x65,0x73,0x20,0x62,0x65,
- 0x74,0x77,0x65,0x65,0x6E,0x20,0x74,0x68,0x65,0x20,0x70,0x6F,
- 0x69,0x6E,0x74,0x73,0x2C,0x20,0x6C,0x69,0x6B,0x65,0x20,0x61,
- 0x6E,0x20,0x6F,0x73,0x63,0x69,0x6C,0x6C,0x6F,0x73,0x63,0x6F,
- 0x70,0x65,0x2E,0x00,0x27,0x40,0x58,0x30,0x32,0x30,0x40,0x43,
- 0x30,0x30,0x31,0x43,0x6F,0x6E,0x66,0x69,0x67,0x75,0x72,0x61,
- 0x74,0x69,0x6F,0x6E,0x2C,0x20,0x4D,0x69,0x73,0x63,0x65,0x6C,
- 0x6C,0x61,0x6E,0x65,0x6F,0x75,0x73,0x3A,0x01,0x3E,0x15,0x3E,
- 0x40,0x58,0x30,0x34,0x30,0x40,0x43,0x30,0x30,0x31,0x56,0x53,
- 0x79,0x6E,0x63,0x20,0x6F,0x66,0x66,0x3A,0x0B,0x3E,0x40,0x58,
- 0x30,0x36,0x30,0x40,0x43,0x30,0x30,0x32,0x3F,0x54,0x65,0x6C,
- 0x6C,0x73,0x20,0x74,0x68,0x65,0x20,0x70,0x72,0x6F,0x67,0x72,
- 0x61,0x6D,0x20,0x74,0x6F,0x20,0x6E,0x6F,0x74,0x20,0x75,0x73,
- 0x65,0x20,0x56,0x53,0x79,0x6E,0x63,0x20,0x66,0x6F,0x72,0x20,
- 0x76,0x69,0x64,0x65,0x6F,0x2E,0x20,0x49,0x66,0x20,0x79,0x6F,
- 0x75,0x72,0x20,0x6D,0x6F,0x6E,0x69,0x74,0x6F,0x72,0x27,0x73,
- 0x40,0x72,0x65,0x66,0x72,0x65,0x73,0x68,0x20,0x72,0x61,0x74,
- 0x65,0x20,0x69,0x73,0x20,0x6E,0x6F,0x74,0x20,0x36,0x30,0x48,
- 0x7A,0x20,0x28,0x6F,0x72,0x20,0x35,0x39,0x48,0x7A,0x29,0x2C,
- 0x20,0x74,0x68,0x65,0x6E,0x20,0x56,0x53,0x79,0x6E,0x63,0x20,
- 0x69,0x73,0x20,0x61,0x6C,0x77,0x61,0x79,0x73,0x20,0x6F,0x66,
- 0x66,0x20,0x66,0x6F,0x72,0x45,0x74,0x68,0x69,0x73,0x20,0x70,
- 0x72,0x6F,0x67,0x72,0x61,0x6D,0x2E,0x20,0x4E,0x6F,0x74,0x20,
- 0x68,0x61,0x76,0x69,0x6E,0x67,0x20,0x56,0x53,0x79,0x6E,0x63,
- 0x20,0x77,0x69,0x6C,0x6C,0x20,0x72,0x65,0x73,0x75,0x6C,0x74,
- 0x20,0x69,0x6E,0x20,0x6C,0x65,0x73,0x73,0x20,0x69,0x6E,0x70,
- 0x75,0x74,0x2F,0x76,0x69,0x64,0x65,0x6F,0x20,0x64,0x65,0x6C,
- 0x61,0x79,0x2C,0x1E,0x62,0x75,0x74,0x20,0x61,0x6C,0x73,0x6F,
- 0x20,0x70,0x6F,0x74,0x65,0x6E,0x74,0x69,0x61,0x6C,0x20,0x73,
- 0x74,0x75,0x74,0x74,0x65,0x72,0x69,0x6E,0x67,0x2E,0x00,0x15,
- 0x3E,0x40,0x58,0x30,0x34,0x30,0x40,0x43,0x30,0x30,0x31,0x53,
- 0x74,0x72,0x65,0x74,0x63,0x68,0x65,0x64,0x3A,0x0B,0x3E,0x40,
- 0x58,0x30,0x36,0x30,0x40,0x43,0x30,0x30,0x32,0x4A,0x4D,0x61,
- 0x6B,0x65,0x73,0x20,0x66,0x75,0x6C,0x6C,0x73,0x63,0x72,0x65,
- 0x65,0x6E,0x20,0x6D,0x6F,0x64,0x65,0x20,0x63,0x6F,0x6D,0x70,
- 0x6C,0x65,0x74,0x65,0x6C,0x79,0x20,0x73,0x74,0x72,0x65,0x74,
- 0x63,0x68,0x20,0x6F,0x75,0x74,0x20,0x74,0x68,0x65,0x20,0x69,
- 0x6D,0x61,0x67,0x65,0x2E,0x20,0x54,0x68,0x69,0x73,0x20,0x63,
- 0x61,0x6E,0x20,0x72,0x65,0x73,0x75,0x6C,0x74,0x20,0x69,0x6E,
- 0x4E,0x61,0x6C,0x69,0x61,0x73,0x69,0x6E,0x67,0x20,0x28,0x75,
- 0x6E,0x65,0x76,0x65,0x6E,0x20,0x70,0x69,0x78,0x65,0x6C,0x20,
- 0x77,0x69,0x64,0x74,0x68,0x73,0x29,0x20,0x69,0x66,0x20,0x74,
- 0x68,0x65,0x20,0x61,0x73,0x70,0x65,0x63,0x74,0x20,0x72,0x61,
- 0x74,0x69,0x6F,0x20,0x6F,0x66,0x20,0x74,0x68,0x65,0x20,0x73,
- 0x63,0x72,0x65,0x65,0x6E,0x20,0x69,0x73,0x20,0x6E,0x6F,0x74,
- 0x20,0x31,0x36,0x3A,0x31,0x30,0x2E,0x52,0x54,0x68,0x65,0x20,
- 0x22,0x50,0x69,0x78,0x65,0x6C,0x20,0x66,0x69,0x6C,0x74,0x65,
- 0x72,0x22,0x20,0x73,0x65,0x74,0x74,0x69,0x6E,0x67,0x20,0x63,
- 0x61,0x6E,0x20,0x68,0x65,0x6C,0x70,0x20,0x77,0x69,0x74,0x68,
- 0x20,0x74,0x68,0x69,0x73,0x2C,0x20,0x62,0x75,0x74,0x20,0x69,
- 0x74,0x20,0x6D,0x61,0x6B,0x65,0x73,0x20,0x74,0x68,0x65,0x20,
- 0x69,0x6D,0x61,0x67,0x65,0x20,0x6C,0x6F,0x6F,0x6B,0x20,0x62,
- 0x6C,0x75,0x72,0x72,0x79,0x2E,0x01,0x20,0x18,0x3E,0x40,0x58,
- 0x30,0x34,0x30,0x40,0x43,0x30,0x30,0x31,0x50,0x69,0x78,0x65,
- 0x6C,0x20,0x66,0x69,0x6C,0x74,0x65,0x72,0x3A,0x0B,0x3E,0x40,
- 0x58,0x30,0x36,0x30,0x40,0x43,0x30,0x30,0x32,0x52,0x41,0x70,
- 0x70,0x6C,0x69,0x65,0x73,0x20,0x61,0x6E,0x20,0x61,0x6E,0x74,
- 0x69,0x2D,0x61,0x6C,0x69,0x61,0x73,0x69,0x6E,0x67,0x20,0x73,
- 0x75,0x62,0x70,0x69,0x78,0x65,0x6C,0x20,0x66,0x69,0x6C,0x74,
- 0x65,0x72,0x20,0x74,0x68,0x61,0x74,0x20,0x69,0x73,0x20,0x75,
- 0x73,0x65,0x64,0x20,0x77,0x68,0x65,0x6E,0x20,0x74,0x68,0x65,
- 0x20,0x77,0x69,0x6E,0x64,0x6F,0x77,0x20,0x69,0x73,0x20,0x75,
- 0x70,0x73,0x63,0x61,0x6C,0x65,0x64,0x2E,0x3B,0x50,0x6C,0x65,
- 0x61,0x73,0x65,0x20,0x6B,0x65,0x65,0x70,0x20,0x69,0x6E,0x20,
- 0x6D,0x69,0x6E,0x64,0x20,0x74,0x68,0x61,0x74,0x20,0x74,0x68,
- 0x69,0x73,0x20,0x77,0x69,0x6C,0x6C,0x20,0x6D,0x61,0x6B,0x65,
- 0x20,0x70,0x69,0x78,0x65,0x6C,0x73,0x20,0x6C,0x6F,0x6F,0x6B,
- 0x20,0x62,0x6C,0x75,0x72,0x72,0x79,0x2E,0x00,0x23,0x40,0x58,
- 0x30,0x32,0x30,0x40,0x43,0x30,0x30,0x31,0x41,0x64,0x76,0x61,
- 0x6E,0x63,0x65,0x64,0x20,0x65,0x64,0x69,0x74,0x20,0x66,0x75,
- 0x6E,0x63,0x74,0x69,0x6F,0x6E,0x73,0x3A,0x20,0x01,0x3E,0x1E,
- 0x3E,0x40,0x58,0x30,0x34,0x30,0x40,0x43,0x30,0x30,0x31,0x43,
- 0x6F,0x70,0x79,0x2F,0x50,0x61,0x73,0x74,0x65,0x20,0x6D,0x61,
- 0x73,0x6B,0x69,0x6E,0x67,0x3A,0x0B,0x3E,0x40,0x58,0x30,0x36,
- 0x30,0x40,0x43,0x30,0x30,0x32,0x37,0x54,0x68,0x65,0x20,0x6D,
- 0x61,0x73,0x6B,0x69,0x6E,0x67,0x20,0x69,0x73,0x20,0x75,0x73,
- 0x65,0x64,0x20,0x66,0x6F,0x72,0x20,0x63,0x6F,0x70,0x79,0x69,
- 0x6E,0x67,0x2F,0x70,0x61,0x73,0x74,0x69,0x6E,0x67,0x20,0x6F,
- 0x6E,0x6C,0x79,0x20,0x70,0x61,0x72,0x74,0x73,0x20,0x6F,0x66,
- 0x20,0x61,0x46,0x22,0x6E,0x6F,0x74,0x65,0x2D,0x63,0x65,0x6C,
- 0x6C,0x22,0x2E,0x20,0x54,0x68,0x65,0x20,0x64,0x69,0x66,0x66,
- 0x65,0x72,0x65,0x6E,0x74,0x20,0x70,0x61,0x72,0x74,0x73,0x20,
- 0x6F,0x66,0x20,0x61,0x20,0x22,0x6E,0x6F,0x74,0x65,0x2D,0x63,
- 0x65,0x6C,0x6C,0x22,0x20,0x69,0x73,0x20,0x4E,0x6F,0x74,0x65,
- 0x2C,0x20,0x49,0x6E,0x73,0x74,0x72,0x2E,0x20,0x6E,0x72,0x2E,
- 0x2C,0x20,0x56,0x6F,0x6C,0x75,0x6D,0x65,0x2C,0x20,0x45,0x66,
- 0x66,0x65,0x63,0x74,0x20,0x6E,0x72,0x20,0x26,0x20,0x45,0x66,
- 0x66,0x65,0x63,0x74,0x20,0x64,0x61,0x74,0x61,0x2E,0x34,0x3E,
- 0x41,0x73,0x20,0x79,0x6F,0x75,0x20,0x63,0x61,0x6E,0x20,0x73,
- 0x65,0x65,0x20,0x69,0x6E,0x20,0x74,0x68,0x65,0x20,0x77,0x69,
- 0x6E,0x64,0x6F,0x77,0x20,0x74,0x68,0x65,0x72,0x65,0x20,0x61,
- 0x72,0x65,0x20,0x33,0x20,0x63,0x6F,0x6C,0x75,0x6D,0x6E,0x73,
- 0x20,0x6F,0x66,0x3D,0x22,0x65,0x6E,0x61,0x62,0x6C,0x65,0x2F,
- 0x64,0x69,0x73,0x61,0x62,0x6C,0x65,0x20,0x62,0x75,0x74,0x74,
- 0x6F,0x6E,0x73,0x22,0x20,0x77,0x68,0x69,0x63,0x68,0x20,0x68,
- 0x61,0x73,0x20,0x74,0x68,0x65,0x20,0x6C,0x65,0x74,0x74,0x65,
- 0x72,0x73,0x20,0x43,0x2C,0x50,0x20,0x26,0x20,0x54,0x20,0x61,
- 0x62,0x6F,0x76,0x65,0x2E,0x45,0x3E,0x43,0x20,0x6D,0x65,0x61,
- 0x6E,0x73,0x20,0x63,0x6F,0x70,0x79,0x2C,0x20,0x69,0x74,0x20,
- 0x63,0x6F,0x6E,0x74,0x72,0x6F,0x6C,0x73,0x20,0x77,0x68,0x69,
- 0x63,0x68,0x20,0x70,0x61,0x72,0x74,0x73,0x20,0x74,0x68,0x61,
- 0x74,0x20,0x67,0x6F,0x65,0x73,0x20,0x69,0x6E,0x74,0x6F,0x20,
- 0x74,0x68,0x65,0x20,0x63,0x6F,0x70,0x79,0x62,0x75,0x66,0x66,
- 0x65,0x72,0x2E,0x3E,0x3E,0x50,0x20,0x6D,0x65,0x61,0x6E,0x73,
- 0x20,0x70,0x61,0x73,0x74,0x65,0x20,0x61,0x6E,0x64,0x20,0x63,
- 0x6F,0x6E,0x74,0x72,0x6F,0x6C,0x73,0x20,0x77,0x68,0x69,0x63,
- 0x68,0x20,0x70,0x61,0x72,0x74,0x73,0x20,0x74,0x68,0x61,0x74,
- 0x20,0x67,0x6F,0x65,0x73,0x20,0x6F,0x75,0x74,0x20,0x66,0x72,
- 0x6F,0x6D,0x20,0x74,0x68,0x65,0x0B,0x63,0x6F,0x70,0x79,0x62,
- 0x75,0x66,0x66,0x65,0x72,0x2E,0x45,0x3E,0x54,0x20,0x6D,0x65,
- 0x61,0x6E,0x73,0x20,0x74,0x72,0x61,0x6E,0x73,0x70,0x61,0x72,
- 0x65,0x6E,0x63,0x79,0x2E,0x20,0x49,0x66,0x20,0x69,0x74,0x27,
- 0x73,0x20,0x65,0x6E,0x61,0x62,0x6C,0x65,0x64,0x2C,0x20,0x74,
- 0x68,0x65,0x20,0x70,0x61,0x73,0x74,0x69,0x6E,0x67,0x20,0x64,
- 0x6F,0x65,0x73,0x6E,0x27,0x74,0x20,0x6F,0x76,0x65,0x72,0x77,
- 0x72,0x69,0x74,0x65,0x3D,0x64,0x61,0x74,0x61,0x20,0x77,0x69,
- 0x74,0x68,0x20,0x6E,0x69,0x6C,0x2D,0x69,0x6E,0x66,0x6F,0x72,
- 0x6D,0x61,0x74,0x69,0x6F,0x6E,0x2C,0x20,0x6F,0x6E,0x6C,0x79,
- 0x20,0x77,0x69,0x74,0x68,0x20,0x61,0x20,0x6E,0x6F,0x74,0x65,
- 0x20,0x6F,0x72,0x20,0x61,0x20,0x6E,0x75,0x6D,0x62,0x65,0x72,
- 0x20,0x3C,0x3E,0x20,0x30,0x2E,0x01,0x3E,0x40,0x3E,0x54,0x68,
- 0x65,0x20,0x63,0x75,0x74,0x20,0x66,0x75,0x6E,0x63,0x74,0x69,
- 0x6F,0x6E,0x73,0x20,0x77,0x6F,0x72,0x6B,0x73,0x20,0x6C,0x69,
- 0x6B,0x65,0x20,0x70,0x61,0x73,0x74,0x69,0x6E,0x67,0x20,0x77,
- 0x69,0x74,0x68,0x20,0x7A,0x65,0x72,0x6F,0x2D,0x64,0x61,0x74,
- 0x61,0x2E,0x20,0x54,0x68,0x69,0x73,0x20,0x6D,0x65,0x61,0x6E,
- 0x73,0x3B,0x74,0x68,0x61,0x74,0x20,0x74,0x68,0x65,0x20,0x63,
- 0x75,0x74,0x74,0x69,0x6E,0x67,0x20,0x69,0x73,0x20,0x63,0x6F,
- 0x6E,0x74,0x72,0x6F,0x6C,0x6C,0x65,0x64,0x20,0x77,0x69,0x74,
- 0x68,0x20,0x50,0x2D,0x63,0x6F,0x6C,0x75,0x6D,0x6E,0x20,0x28,
- 0x6F,0x72,0x20,0x54,0x2D,0x63,0x6F,0x6C,0x75,0x6D,0x6E,0x29,
- 0x2E,0x3C,0x3E,0x57,0x68,0x65,0x6E,0x20,0x79,0x6F,0x75,0x20,
- 0x63,0x6F,0x70,0x79,0x20,0x64,0x61,0x74,0x61,0x20,0x77,0x69,
- 0x74,0x68,0x20,0x6D,0x61,0x73,0x6B,0x69,0x6E,0x67,0x2C,0x20,
- 0x74,0x68,0x65,0x20,0x64,0x69,0x73,0x61,0x62,0x6C,0x65,0x64,
- 0x20,0x70,0x61,0x72,0x74,0x73,0x20,0x61,0x72,0x65,0x20,0x6E,
- 0x6F,0x74,0x43,0x63,0x6C,0x65,0x61,0x72,0x65,0x64,0x20,0x69,
- 0x6E,0x20,0x74,0x68,0x65,0x20,0x63,0x6F,0x70,0x79,0x62,0x75,
- 0x66,0x66,0x65,0x72,0x2E,0x20,0x28,0x4D,0x61,0x6B,0x69,0x6E,
- 0x67,0x20,0x69,0x74,0x20,0x70,0x6F,0x73,0x73,0x69,0x62,0x6C,
- 0x65,0x20,0x74,0x6F,0x20,0x63,0x6F,0x6C,0x6C,0x65,0x63,0x74,
- 0x20,0x64,0x61,0x74,0x61,0x20,0x66,0x72,0x6F,0x6D,0x27,0x73,
- 0x65,0x76,0x65,0x72,0x61,0x6C,0x20,0x6C,0x6F,0x63,0x61,0x74,
- 0x69,0x6F,0x6E,0x73,0x20,0x69,0x6E,0x74,0x6F,0x20,0x74,0x68,
- 0x65,0x20,0x63,0x6F,0x70,0x79,0x62,0x75,0x66,0x66,0x65,0x72,
- 0x2E,0x29,0x00,0x03,0x45,0x4E,0x44,0x4C,0x3B,0x2A,0x2A,0x2A,
+ 0x30,0x32,0x43,0x49,0x66,0x20,0x74,0x68,0x65,0x20,0x61,0x75,
+ 0x74,0x6F,0x20,0x73,0x61,0x76,0x65,0x20,0x69,0x73,0x20,0x6F,
+ 0x6E,0x2C,0x20,0x46,0x54,0x32,0x20,0x77,0x69,0x6C,0x6C,0x20,
+ 0x75,0x70,0x64,0x61,0x74,0x65,0x20,0x74,0x68,0x65,0x20,0x63,
+ 0x6F,0x6E,0x66,0x69,0x67,0x75,0x72,0x61,0x74,0x69,0x6F,0x6E,
+ 0x20,0x66,0x69,0x6C,0x65,0x20,0x77,0x68,0x65,0x6E,0x15,0x79,
+ 0x6F,0x75,0x20,0x65,0x78,0x69,0x74,0x20,0x74,0x68,0x65,0x20,
+ 0x70,0x72,0x6F,0x67,0x72,0x61,0x6D,0x2E,0x00,0x25,0x40,0x58,
+ 0x30,0x32,0x30,0x40,0x43,0x30,0x30,0x31,0x43,0x6F,0x6E,0x66,
+ 0x69,0x67,0x75,0x72,0x61,0x74,0x69,0x6F,0x6E,0x2C,0x20,0x49,
+ 0x2F,0x4F,0x20,0x64,0x65,0x76,0x69,0x63,0x65,0x73,0x3A,0x01,
+ 0x3E,0x19,0x3E,0x40,0x58,0x30,0x34,0x30,0x40,0x43,0x30,0x30,
+ 0x31,0x49,0x6E,0x74,0x65,0x72,0x70,0x6F,0x6C,0x61,0x74,0x69,
+ 0x6F,0x6E,0x3A,0x0B,0x3E,0x40,0x58,0x30,0x36,0x30,0x40,0x43,
+ 0x30,0x30,0x32,0x35,0x53,0x65,0x6C,0x65,0x63,0x74,0x73,0x20,
+ 0x77,0x68,0x61,0x74,0x20,0x74,0x79,0x70,0x65,0x20,0x6F,0x66,
+ 0x20,0x72,0x65,0x73,0x61,0x6D,0x70,0x6C,0x69,0x6E,0x67,0x20,
+ 0x69,0x6E,0x74,0x65,0x72,0x70,0x6F,0x6C,0x61,0x74,0x69,0x6F,
+ 0x6E,0x20,0x74,0x6F,0x20,0x75,0x73,0x65,0x2E,0x45,0x22,0x4E,
+ 0x6F,0x6E,0x65,0x22,0x20,0x75,0x73,0x65,0x73,0x20,0x6E,0x6F,
+ 0x20,0x69,0x6E,0x74,0x65,0x72,0x70,0x6F,0x6C,0x61,0x74,0x69,
+ 0x6F,0x6E,0x20,0x28,0x6E,0x65,0x61,0x72,0x65,0x73,0x74,0x20,
+ 0x6E,0x65,0x69,0x67,0x68,0x62,0x6F,0x72,0x29,0x2C,0x20,0x77,
+ 0x68,0x69,0x63,0x68,0x20,0x77,0x69,0x6C,0x6C,0x20,0x72,0x65,
+ 0x73,0x75,0x6C,0x74,0x20,0x69,0x6E,0x49,0x61,0x6C,0x69,0x61,
+ 0x73,0x69,0x6E,0x67,0x20,0x28,0x6E,0x6F,0x69,0x73,0x65,0x29,
+ 0x20,0x69,0x6E,0x20,0x74,0x68,0x65,0x20,0x73,0x6F,0x75,0x6E,
+ 0x64,0x2E,0x20,0x22,0x4C,0x69,0x6E,0x65,0x61,0x72,0x22,0x20,
+ 0x69,0x73,0x20,0x77,0x68,0x61,0x74,0x20,0x72,0x65,0x61,0x6C,
+ 0x20,0x46,0x54,0x32,0x20,0x75,0x73,0x65,0x73,0x2C,0x20,0x77,
+ 0x68,0x69,0x63,0x68,0x20,0x69,0x73,0x20,0x61,0x47,0x6D,0x65,
+ 0x64,0x69,0x6F,0x63,0x72,0x65,0x20,0x69,0x6E,0x74,0x65,0x72,
+ 0x70,0x6F,0x6C,0x61,0x74,0x69,0x6F,0x6E,0x20,0x74,0x79,0x70,
+ 0x65,0x2E,0x20,0x22,0x57,0x69,0x6E,0x64,0x6F,0x77,0x65,0x64,
+ 0x2D,0x73,0x69,0x6E,0x63,0x22,0x20,0x69,0x73,0x20,0x74,0x68,
+ 0x65,0x20,0x72,0x65,0x63,0x6F,0x6D,0x6D,0x65,0x6E,0x64,0x65,
+ 0x64,0x20,0x73,0x65,0x74,0x74,0x69,0x6E,0x67,0x48,0x66,0x6F,
+ 0x72,0x20,0x74,0x68,0x65,0x20,0x62,0x65,0x73,0x74,0x20,0x61,
+ 0x75,0x64,0x69,0x6F,0x20,0x71,0x75,0x61,0x6C,0x69,0x74,0x79,
+ 0x2C,0x20,0x61,0x6C,0x74,0x68,0x6F,0x75,0x67,0x68,0x20,0x69,
+ 0x74,0x20,0x6D,0x61,0x79,0x20,0x73,0x6F,0x6D,0x65,0x74,0x69,
+ 0x6D,0x65,0x73,0x20,0x73,0x6F,0x75,0x6E,0x64,0x20,0x74,0x6F,
+ 0x6F,0x20,0x66,0x69,0x6C,0x74,0x65,0x72,0x65,0x64,0x2A,0x6F,
+ 0x6E,0x20,0x6C,0x6F,0x77,0x2D,0x71,0x75,0x61,0x6C,0x69,0x74,
+ 0x79,0x20,0x73,0x61,0x6D,0x70,0x6C,0x65,0x73,0x20,0x28,0x66,
+ 0x2E,0x65,0x78,0x2E,0x20,0x41,0x6D,0x69,0x67,0x61,0x20,0x4D,
+ 0x4F,0x44,0x73,0x29,0x2E,0x00,0x1A,0x3E,0x40,0x58,0x30,0x34,
+ 0x30,0x40,0x43,0x30,0x30,0x31,0x56,0x6F,0x6C,0x75,0x6D,0x65,
+ 0x20,0x72,0x61,0x6D,0x70,0x69,0x6E,0x67,0x3A,0x0B,0x3E,0x40,
+ 0x58,0x30,0x36,0x30,0x40,0x43,0x30,0x30,0x32,0x3B,0x45,0x6E,
+ 0x61,0x62,0x6C,0x65,0x73,0x20,0x74,0x68,0x65,0x20,0x61,0x6E,
+ 0x74,0x69,0x2D,0x63,0x6C,0x69,0x63,0x6B,0x20,0x73,0x79,0x73,
+ 0x74,0x65,0x6D,0x20,0x69,0x6E,0x20,0x74,0x68,0x65,0x20,0x61,
+ 0x75,0x64,0x69,0x6F,0x20,0x6D,0x69,0x78,0x65,0x72,0x20,0x28,
+ 0x46,0x54,0x32,0x2E,0x30,0x38,0x2B,0x29,0x2E,0x3B,0x50,0x6C,
+ 0x65,0x61,0x73,0x65,0x20,0x6E,0x6F,0x74,0x65,0x20,0x74,0x68,
+ 0x61,0x74,0x20,0x6F,0x72,0x69,0x67,0x69,0x6E,0x61,0x6C,0x20,
+ 0x46,0x54,0x32,0x20,0x63,0x61,0x6E,0x27,0x74,0x20,0x6C,0x6F,
+ 0x61,0x64,0x20,0x74,0x68,0x69,0x73,0x20,0x63,0x6F,0x6E,0x66,
+ 0x69,0x67,0x20,0x65,0x6E,0x74,0x72,0x79,0x2C,0x0B,0x63,0x6C,
+ 0x6F,0x6E,0x65,0x20,0x6F,0x6E,0x6C,0x79,0x2E,0x00,0x19,0x3E,
+ 0x40,0x58,0x30,0x34,0x30,0x40,0x43,0x30,0x30,0x31,0x41,0x6D,
+ 0x70,0x6C,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x3A,
+ 0x0B,0x3E,0x40,0x58,0x30,0x36,0x30,0x40,0x43,0x30,0x30,0x32,
+ 0x46,0x41,0x6D,0x70,0x6C,0x69,0x66,0x69,0x65,0x73,0x20,0x74,
+ 0x68,0x65,0x20,0x76,0x6F,0x6C,0x75,0x6D,0x65,0x20,0x77,0x68,
+ 0x65,0x6E,0x20,0x6D,0x69,0x78,0x69,0x6E,0x67,0x2E,0x20,0x49,
+ 0x66,0x20,0x79,0x6F,0x75,0x20,0x73,0x65,0x74,0x20,0x74,0x68,
+ 0x69,0x73,0x20,0x6F,0x6E,0x65,0x20,0x74,0x6F,0x6F,0x20,0x68,
+ 0x69,0x67,0x68,0x2C,0x20,0x79,0x6F,0x75,0x27,0x6C,0x6C,0x3A,
+ 0x67,0x65,0x74,0x20,0x64,0x69,0x73,0x74,0x6F,0x72,0x74,0x69,
+ 0x6F,0x6E,0x2E,0x20,0x33,0x32,0x58,0x20,0x65,0x71,0x75,0x61,
+ 0x6C,0x73,0x20,0x66,0x75,0x6C,0x6C,0x20,0x61,0x6D,0x70,0x6C,
+ 0x69,0x74,0x75,0x64,0x65,0x20,0x66,0x6F,0x72,0x20,0x6F,0x6E,
+ 0x65,0x20,0x63,0x68,0x61,0x6E,0x6E,0x65,0x6C,0x2E,0x00,0x1B,
+ 0x3E,0x40,0x58,0x30,0x34,0x30,0x40,0x43,0x30,0x30,0x31,0x46,
+ 0x72,0x65,0x71,0x75,0x65,0x6E,0x63,0x79,0x20,0x74,0x61,0x62,
+ 0x6C,0x65,0x3A,0x0B,0x3E,0x40,0x58,0x30,0x36,0x30,0x40,0x43,
+ 0x30,0x30,0x32,0x40,0x54,0x68,0x65,0x20,0x6C,0x69,0x6E,0x65,
+ 0x61,0x72,0x20,0x66,0x72,0x65,0x71,0x75,0x65,0x6E,0x63,0x79,
+ 0x20,0x74,0x61,0x62,0x6C,0x65,0x20,0x6D,0x61,0x6B,0x65,0x73,
+ 0x20,0x61,0x6C,0x6C,0x20,0x70,0x69,0x74,0x63,0x68,0x20,0x62,
+ 0x65,0x6E,0x64,0x73,0x20,0x72,0x75,0x6E,0x20,0x69,0x6E,0x20,
+ 0x63,0x6F,0x6E,0x73,0x74,0x61,0x6E,0x74,0x3F,0x73,0x70,0x65,
+ 0x65,0x64,0x2C,0x20,0x69,0x6E,0x64,0x65,0x70,0x65,0x6E,0x64,
+ 0x65,0x6E,0x74,0x20,0x6F,0x66,0x20,0x74,0x68,0x65,0x20,0x63,
+ 0x75,0x72,0x72,0x65,0x6E,0x74,0x20,0x66,0x72,0x65,0x71,0x75,
+ 0x65,0x6E,0x63,0x79,0x2E,0x20,0x49,0x66,0x20,0x79,0x6F,0x75,
+ 0x20,0x73,0x77,0x69,0x74,0x63,0x68,0x20,0x74,0x68,0x69,0x73,
+ 0x41,0x6F,0x6E,0x65,0x2C,0x20,0x6F,0x6E,0x20,0x61,0x20,0x66,
+ 0x69,0x6E,0x69,0x73,0x68,0x65,0x64,0x20,0x73,0x6F,0x6E,0x67,
+ 0x2C,0x20,0x69,0x74,0x20,0x6D,0x69,0x67,0x68,0x74,0x20,0x73,
+ 0x6F,0x75,0x6E,0x64,0x20,0x73,0x74,0x72,0x61,0x6E,0x67,0x65,
+ 0x20,0x69,0x66,0x20,0x74,0x68,0x65,0x20,0x73,0x6F,0x75,0x6E,
+ 0x64,0x20,0x75,0x73,0x65,0x73,0x0D,0x70,0x6F,0x72,0x74,0x61,
+ 0x6D,0x65,0x6E,0x74,0x6F,0x65,0x73,0x2E,0x00,0x20,0x40,0x58,
+ 0x30,0x32,0x30,0x40,0x43,0x30,0x30,0x31,0x43,0x6F,0x6E,0x66,
+ 0x69,0x67,0x75,0x72,0x61,0x74,0x69,0x6F,0x6E,0x2C,0x20,0x4C,
+ 0x61,0x79,0x6F,0x75,0x74,0x3A,0x01,0x3E,0x29,0x3E,0x40,0x58,
+ 0x30,0x34,0x30,0x40,0x43,0x30,0x30,0x31,0x50,0x61,0x74,0x74,
+ 0x65,0x72,0x6E,0x20,0x6C,0x61,0x79,0x6F,0x75,0x74,0x2C,0x20,
+ 0x68,0x65,0x78,0x20,0x6E,0x75,0x6D,0x62,0x65,0x72,0x69,0x6E,
+ 0x67,0x3A,0x0B,0x3E,0x40,0x58,0x30,0x36,0x30,0x40,0x43,0x30,
+ 0x30,0x32,0x41,0x49,0x66,0x20,0x79,0x6F,0x75,0x20,0x75,0x73,
+ 0x65,0x20,0x70,0x61,0x74,0x74,0x65,0x72,0x6E,0x73,0x20,0x74,
+ 0x68,0x61,0x74,0x20,0x61,0x72,0x65,0x20,0x6C,0x6F,0x6E,0x67,
+ 0x65,0x72,0x20,0x74,0x68,0x61,0x6E,0x20,0x39,0x39,0x20,0x6C,
+ 0x69,0x6E,0x65,0x73,0x2C,0x20,0x79,0x6F,0x75,0x20,0x73,0x68,
+ 0x6F,0x75,0x6C,0x64,0x20,0x75,0x73,0x65,0x45,0x68,0x65,0x78,
+ 0x20,0x63,0x6F,0x75,0x6E,0x74,0x69,0x6E,0x67,0x20,0x73,0x69,
+ 0x6E,0x63,0x65,0x20,0x74,0x68,0x65,0x72,0x65,0x20,0x61,0x72,
+ 0x65,0x20,0x6F,0x6E,0x6C,0x79,0x20,0x32,0x20,0x64,0x69,0x67,
+ 0x69,0x74,0x73,0x20,0x69,0x6E,0x20,0x74,0x68,0x65,0x20,0x6C,
+ 0x69,0x6E,0x65,0x20,0x6E,0x75,0x6D,0x62,0x65,0x72,0x20,0x63,
+ 0x6F,0x6C,0x75,0x6D,0x6E,0x2E,0x00,0x12,0x3E,0x40,0x58,0x30,
+ 0x34,0x30,0x40,0x43,0x30,0x30,0x31,0x53,0x63,0x6F,0x70,0x65,
+ 0x73,0x3A,0x0B,0x3E,0x40,0x58,0x30,0x36,0x30,0x40,0x43,0x30,
+ 0x30,0x32,0x43,0x22,0x53,0x74,0x64,0x2E,0x22,0x20,0x28,0x73,
+ 0x74,0x61,0x6E,0x64,0x61,0x72,0x64,0x29,0x20,0x77,0x69,0x6C,
+ 0x6C,0x20,0x73,0x68,0x6F,0x77,0x20,0x74,0x68,0x65,0x20,0x73,
+ 0x61,0x6D,0x70,0x6C,0x65,0x20,0x70,0x6F,0x69,0x6E,0x74,0x73,
+ 0x20,0x61,0x73,0x20,0x70,0x69,0x78,0x65,0x6C,0x73,0x20,0x28,
+ 0x6C,0x69,0x6B,0x65,0x20,0x46,0x54,0x32,0x29,0x2E,0x3D,0x22,
+ 0x4C,0x69,0x6E,0x65,0x64,0x22,0x20,0x77,0x69,0x6C,0x6C,0x20,
+ 0x64,0x72,0x61,0x77,0x20,0x69,0x6E,0x74,0x65,0x72,0x70,0x6F,
+ 0x6C,0x61,0x74,0x65,0x64,0x20,0x73,0x61,0x6D,0x70,0x6C,0x65,
+ 0x73,0x20,0x28,0x6C,0x69,0x6E,0x65,0x61,0x72,0x20,0x69,0x6E,
+ 0x74,0x65,0x72,0x70,0x6F,0x6C,0x61,0x74,0x69,0x6F,0x6E,0x2E,
+ 0x00,0x27,0x40,0x58,0x30,0x32,0x30,0x40,0x43,0x30,0x30,0x31,
+ 0x43,0x6F,0x6E,0x66,0x69,0x67,0x75,0x72,0x61,0x74,0x69,0x6F,
+ 0x6E,0x2C,0x20,0x4D,0x69,0x73,0x63,0x65,0x6C,0x6C,0x61,0x6E,
+ 0x65,0x6F,0x75,0x73,0x3A,0x01,0x3E,0x15,0x3E,0x40,0x58,0x30,
+ 0x34,0x30,0x40,0x43,0x30,0x30,0x31,0x56,0x53,0x79,0x6E,0x63,
+ 0x20,0x6F,0x66,0x66,0x3A,0x0B,0x3E,0x40,0x58,0x30,0x36,0x30,
+ 0x40,0x43,0x30,0x30,0x32,0x3F,0x54,0x65,0x6C,0x6C,0x73,0x20,
+ 0x74,0x68,0x65,0x20,0x70,0x72,0x6F,0x67,0x72,0x61,0x6D,0x20,
+ 0x74,0x6F,0x20,0x6E,0x6F,0x74,0x20,0x75,0x73,0x65,0x20,0x56,
+ 0x53,0x79,0x6E,0x63,0x20,0x66,0x6F,0x72,0x20,0x76,0x69,0x64,
+ 0x65,0x6F,0x2E,0x20,0x49,0x66,0x20,0x79,0x6F,0x75,0x72,0x20,
+ 0x6D,0x6F,0x6E,0x69,0x74,0x6F,0x72,0x27,0x73,0x40,0x72,0x65,
+ 0x66,0x72,0x65,0x73,0x68,0x20,0x72,0x61,0x74,0x65,0x20,0x69,
+ 0x73,0x20,0x6E,0x6F,0x74,0x20,0x36,0x30,0x48,0x7A,0x20,0x28,
+ 0x6F,0x72,0x20,0x35,0x39,0x48,0x7A,0x29,0x2C,0x20,0x74,0x68,
+ 0x65,0x6E,0x20,0x56,0x53,0x79,0x6E,0x63,0x20,0x69,0x73,0x20,
+ 0x61,0x6C,0x77,0x61,0x79,0x73,0x20,0x6F,0x66,0x66,0x20,0x66,
+ 0x6F,0x72,0x45,0x74,0x68,0x69,0x73,0x20,0x70,0x72,0x6F,0x67,
+ 0x72,0x61,0x6D,0x2E,0x20,0x4E,0x6F,0x74,0x20,0x68,0x61,0x76,
+ 0x69,0x6E,0x67,0x20,0x56,0x53,0x79,0x6E,0x63,0x20,0x77,0x69,
+ 0x6C,0x6C,0x20,0x72,0x65,0x73,0x75,0x6C,0x74,0x20,0x69,0x6E,
+ 0x20,0x6C,0x65,0x73,0x73,0x20,0x69,0x6E,0x70,0x75,0x74,0x2F,
+ 0x76,0x69,0x64,0x65,0x6F,0x20,0x64,0x65,0x6C,0x61,0x79,0x2C,
+ 0x1E,0x62,0x75,0x74,0x20,0x61,0x6C,0x73,0x6F,0x20,0x70,0x6F,
+ 0x74,0x65,0x6E,0x74,0x69,0x61,0x6C,0x20,0x73,0x74,0x75,0x74,
+ 0x74,0x65,0x72,0x69,0x6E,0x67,0x2E,0x00,0x15,0x3E,0x40,0x58,
+ 0x30,0x34,0x30,0x40,0x43,0x30,0x30,0x31,0x53,0x74,0x72,0x65,
+ 0x74,0x63,0x68,0x65,0x64,0x3A,0x0B,0x3E,0x40,0x58,0x30,0x36,
+ 0x30,0x40,0x43,0x30,0x30,0x32,0x4A,0x4D,0x61,0x6B,0x65,0x73,
+ 0x20,0x66,0x75,0x6C,0x6C,0x73,0x63,0x72,0x65,0x65,0x6E,0x20,
+ 0x6D,0x6F,0x64,0x65,0x20,0x63,0x6F,0x6D,0x70,0x6C,0x65,0x74,
+ 0x65,0x6C,0x79,0x20,0x73,0x74,0x72,0x65,0x74,0x63,0x68,0x20,
+ 0x6F,0x75,0x74,0x20,0x74,0x68,0x65,0x20,0x69,0x6D,0x61,0x67,
+ 0x65,0x2E,0x20,0x54,0x68,0x69,0x73,0x20,0x63,0x61,0x6E,0x20,
+ 0x72,0x65,0x73,0x75,0x6C,0x74,0x20,0x69,0x6E,0x4E,0x61,0x6C,
+ 0x69,0x61,0x73,0x69,0x6E,0x67,0x20,0x28,0x75,0x6E,0x65,0x76,
+ 0x65,0x6E,0x20,0x70,0x69,0x78,0x65,0x6C,0x20,0x77,0x69,0x64,
+ 0x74,0x68,0x73,0x29,0x20,0x69,0x66,0x20,0x74,0x68,0x65,0x20,
+ 0x61,0x73,0x70,0x65,0x63,0x74,0x20,0x72,0x61,0x74,0x69,0x6F,
+ 0x20,0x6F,0x66,0x20,0x74,0x68,0x65,0x20,0x73,0x63,0x72,0x65,
+ 0x65,0x6E,0x20,0x69,0x73,0x20,0x6E,0x6F,0x74,0x20,0x31,0x36,
+ 0x3A,0x31,0x30,0x2E,0x52,0x54,0x68,0x65,0x20,0x22,0x50,0x69,
+ 0x78,0x65,0x6C,0x20,0x66,0x69,0x6C,0x74,0x65,0x72,0x22,0x20,
+ 0x73,0x65,0x74,0x74,0x69,0x6E,0x67,0x20,0x63,0x61,0x6E,0x20,
+ 0x68,0x65,0x6C,0x70,0x20,0x77,0x69,0x74,0x68,0x20,0x74,0x68,
+ 0x69,0x73,0x2C,0x20,0x62,0x75,0x74,0x20,0x69,0x74,0x20,0x6D,
+ 0x61,0x6B,0x65,0x73,0x20,0x74,0x68,0x65,0x20,0x69,0x6D,0x61,
+ 0x67,0x65,0x20,0x6C,0x6F,0x6F,0x6B,0x20,0x62,0x6C,0x75,0x72,
+ 0x72,0x79,0x2E,0x01,0x20,0x18,0x3E,0x40,0x58,0x30,0x34,0x30,
+ 0x40,0x43,0x30,0x30,0x31,0x50,0x69,0x78,0x65,0x6C,0x20,0x66,
+ 0x69,0x6C,0x74,0x65,0x72,0x3A,0x0B,0x3E,0x40,0x58,0x30,0x36,
+ 0x30,0x40,0x43,0x30,0x30,0x32,0x52,0x41,0x70,0x70,0x6C,0x69,
+ 0x65,0x73,0x20,0x61,0x6E,0x20,0x61,0x6E,0x74,0x69,0x2D,0x61,
+ 0x6C,0x69,0x61,0x73,0x69,0x6E,0x67,0x20,0x73,0x75,0x62,0x70,
+ 0x69,0x78,0x65,0x6C,0x20,0x66,0x69,0x6C,0x74,0x65,0x72,0x20,
+ 0x74,0x68,0x61,0x74,0x20,0x69,0x73,0x20,0x75,0x73,0x65,0x64,
+ 0x20,0x77,0x68,0x65,0x6E,0x20,0x74,0x68,0x65,0x20,0x77,0x69,
+ 0x6E,0x64,0x6F,0x77,0x20,0x69,0x73,0x20,0x75,0x70,0x73,0x63,
+ 0x61,0x6C,0x65,0x64,0x2E,0x3B,0x50,0x6C,0x65,0x61,0x73,0x65,
+ 0x20,0x6B,0x65,0x65,0x70,0x20,0x69,0x6E,0x20,0x6D,0x69,0x6E,
+ 0x64,0x20,0x74,0x68,0x61,0x74,0x20,0x74,0x68,0x69,0x73,0x20,
+ 0x77,0x69,0x6C,0x6C,0x20,0x6D,0x61,0x6B,0x65,0x20,0x70,0x69,
+ 0x78,0x65,0x6C,0x73,0x20,0x6C,0x6F,0x6F,0x6B,0x20,0x62,0x6C,
+ 0x75,0x72,0x72,0x79,0x2E,0x00,0x23,0x40,0x58,0x30,0x32,0x30,
+ 0x40,0x43,0x30,0x30,0x31,0x41,0x64,0x76,0x61,0x6E,0x63,0x65,
+ 0x64,0x20,0x65,0x64,0x69,0x74,0x20,0x66,0x75,0x6E,0x63,0x74,
+ 0x69,0x6F,0x6E,0x73,0x3A,0x20,0x01,0x3E,0x1E,0x3E,0x40,0x58,
+ 0x30,0x34,0x30,0x40,0x43,0x30,0x30,0x31,0x43,0x6F,0x70,0x79,
+ 0x2F,0x50,0x61,0x73,0x74,0x65,0x20,0x6D,0x61,0x73,0x6B,0x69,
+ 0x6E,0x67,0x3A,0x0B,0x3E,0x40,0x58,0x30,0x36,0x30,0x40,0x43,
+ 0x30,0x30,0x32,0x37,0x54,0x68,0x65,0x20,0x6D,0x61,0x73,0x6B,
+ 0x69,0x6E,0x67,0x20,0x69,0x73,0x20,0x75,0x73,0x65,0x64,0x20,
+ 0x66,0x6F,0x72,0x20,0x63,0x6F,0x70,0x79,0x69,0x6E,0x67,0x2F,
+ 0x70,0x61,0x73,0x74,0x69,0x6E,0x67,0x20,0x6F,0x6E,0x6C,0x79,
+ 0x20,0x70,0x61,0x72,0x74,0x73,0x20,0x6F,0x66,0x20,0x61,0x46,
+ 0x22,0x6E,0x6F,0x74,0x65,0x2D,0x63,0x65,0x6C,0x6C,0x22,0x2E,
+ 0x20,0x54,0x68,0x65,0x20,0x64,0x69,0x66,0x66,0x65,0x72,0x65,
+ 0x6E,0x74,0x20,0x70,0x61,0x72,0x74,0x73,0x20,0x6F,0x66,0x20,
+ 0x61,0x20,0x22,0x6E,0x6F,0x74,0x65,0x2D,0x63,0x65,0x6C,0x6C,
+ 0x22,0x20,0x69,0x73,0x20,0x4E,0x6F,0x74,0x65,0x2C,0x20,0x49,
+ 0x6E,0x73,0x74,0x72,0x2E,0x20,0x6E,0x72,0x2E,0x2C,0x20,0x56,
+ 0x6F,0x6C,0x75,0x6D,0x65,0x2C,0x20,0x45,0x66,0x66,0x65,0x63,
+ 0x74,0x20,0x6E,0x72,0x20,0x26,0x20,0x45,0x66,0x66,0x65,0x63,
+ 0x74,0x20,0x64,0x61,0x74,0x61,0x2E,0x34,0x3E,0x41,0x73,0x20,
+ 0x79,0x6F,0x75,0x20,0x63,0x61,0x6E,0x20,0x73,0x65,0x65,0x20,
+ 0x69,0x6E,0x20,0x74,0x68,0x65,0x20,0x77,0x69,0x6E,0x64,0x6F,
+ 0x77,0x20,0x74,0x68,0x65,0x72,0x65,0x20,0x61,0x72,0x65,0x20,
+ 0x33,0x20,0x63,0x6F,0x6C,0x75,0x6D,0x6E,0x73,0x20,0x6F,0x66,
+ 0x3D,0x22,0x65,0x6E,0x61,0x62,0x6C,0x65,0x2F,0x64,0x69,0x73,
+ 0x61,0x62,0x6C,0x65,0x20,0x62,0x75,0x74,0x74,0x6F,0x6E,0x73,
+ 0x22,0x20,0x77,0x68,0x69,0x63,0x68,0x20,0x68,0x61,0x73,0x20,
+ 0x74,0x68,0x65,0x20,0x6C,0x65,0x74,0x74,0x65,0x72,0x73,0x20,
+ 0x43,0x2C,0x50,0x20,0x26,0x20,0x54,0x20,0x61,0x62,0x6F,0x76,
+ 0x65,0x2E,0x45,0x3E,0x43,0x20,0x6D,0x65,0x61,0x6E,0x73,0x20,
+ 0x63,0x6F,0x70,0x79,0x2C,0x20,0x69,0x74,0x20,0x63,0x6F,0x6E,
+ 0x74,0x72,0x6F,0x6C,0x73,0x20,0x77,0x68,0x69,0x63,0x68,0x20,
+ 0x70,0x61,0x72,0x74,0x73,0x20,0x74,0x68,0x61,0x74,0x20,0x67,
+ 0x6F,0x65,0x73,0x20,0x69,0x6E,0x74,0x6F,0x20,0x74,0x68,0x65,
+ 0x20,0x63,0x6F,0x70,0x79,0x62,0x75,0x66,0x66,0x65,0x72,0x2E,
+ 0x3E,0x3E,0x50,0x20,0x6D,0x65,0x61,0x6E,0x73,0x20,0x70,0x61,
+ 0x73,0x74,0x65,0x20,0x61,0x6E,0x64,0x20,0x63,0x6F,0x6E,0x74,
+ 0x72,0x6F,0x6C,0x73,0x20,0x77,0x68,0x69,0x63,0x68,0x20,0x70,
+ 0x61,0x72,0x74,0x73,0x20,0x74,0x68,0x61,0x74,0x20,0x67,0x6F,
+ 0x65,0x73,0x20,0x6F,0x75,0x74,0x20,0x66,0x72,0x6F,0x6D,0x20,
+ 0x74,0x68,0x65,0x0B,0x63,0x6F,0x70,0x79,0x62,0x75,0x66,0x66,
+ 0x65,0x72,0x2E,0x45,0x3E,0x54,0x20,0x6D,0x65,0x61,0x6E,0x73,
+ 0x20,0x74,0x72,0x61,0x6E,0x73,0x70,0x61,0x72,0x65,0x6E,0x63,
+ 0x79,0x2E,0x20,0x49,0x66,0x20,0x69,0x74,0x27,0x73,0x20,0x65,
+ 0x6E,0x61,0x62,0x6C,0x65,0x64,0x2C,0x20,0x74,0x68,0x65,0x20,
+ 0x70,0x61,0x73,0x74,0x69,0x6E,0x67,0x20,0x64,0x6F,0x65,0x73,
+ 0x6E,0x27,0x74,0x20,0x6F,0x76,0x65,0x72,0x77,0x72,0x69,0x74,
+ 0x65,0x3D,0x64,0x61,0x74,0x61,0x20,0x77,0x69,0x74,0x68,0x20,
+ 0x6E,0x69,0x6C,0x2D,0x69,0x6E,0x66,0x6F,0x72,0x6D,0x61,0x74,
+ 0x69,0x6F,0x6E,0x2C,0x20,0x6F,0x6E,0x6C,0x79,0x20,0x77,0x69,
+ 0x74,0x68,0x20,0x61,0x20,0x6E,0x6F,0x74,0x65,0x20,0x6F,0x72,
+ 0x20,0x61,0x20,0x6E,0x75,0x6D,0x62,0x65,0x72,0x20,0x3C,0x3E,
+ 0x20,0x30,0x2E,0x01,0x3E,0x40,0x3E,0x54,0x68,0x65,0x20,0x63,
+ 0x75,0x74,0x20,0x66,0x75,0x6E,0x63,0x74,0x69,0x6F,0x6E,0x73,
+ 0x20,0x77,0x6F,0x72,0x6B,0x73,0x20,0x6C,0x69,0x6B,0x65,0x20,
+ 0x70,0x61,0x73,0x74,0x69,0x6E,0x67,0x20,0x77,0x69,0x74,0x68,
+ 0x20,0x7A,0x65,0x72,0x6F,0x2D,0x64,0x61,0x74,0x61,0x2E,0x20,
+ 0x54,0x68,0x69,0x73,0x20,0x6D,0x65,0x61,0x6E,0x73,0x3B,0x74,
+ 0x68,0x61,0x74,0x20,0x74,0x68,0x65,0x20,0x63,0x75,0x74,0x74,
+ 0x69,0x6E,0x67,0x20,0x69,0x73,0x20,0x63,0x6F,0x6E,0x74,0x72,
+ 0x6F,0x6C,0x6C,0x65,0x64,0x20,0x77,0x69,0x74,0x68,0x20,0x50,
+ 0x2D,0x63,0x6F,0x6C,0x75,0x6D,0x6E,0x20,0x28,0x6F,0x72,0x20,
+ 0x54,0x2D,0x63,0x6F,0x6C,0x75,0x6D,0x6E,0x29,0x2E,0x3C,0x3E,
+ 0x57,0x68,0x65,0x6E,0x20,0x79,0x6F,0x75,0x20,0x63,0x6F,0x70,
+ 0x79,0x20,0x64,0x61,0x74,0x61,0x20,0x77,0x69,0x74,0x68,0x20,
+ 0x6D,0x61,0x73,0x6B,0x69,0x6E,0x67,0x2C,0x20,0x74,0x68,0x65,
+ 0x20,0x64,0x69,0x73,0x61,0x62,0x6C,0x65,0x64,0x20,0x70,0x61,
+ 0x72,0x74,0x73,0x20,0x61,0x72,0x65,0x20,0x6E,0x6F,0x74,0x43,
+ 0x63,0x6C,0x65,0x61,0x72,0x65,0x64,0x20,0x69,0x6E,0x20,0x74,
+ 0x68,0x65,0x20,0x63,0x6F,0x70,0x79,0x62,0x75,0x66,0x66,0x65,
+ 0x72,0x2E,0x20,0x28,0x4D,0x61,0x6B,0x69,0x6E,0x67,0x20,0x69,
+ 0x74,0x20,0x70,0x6F,0x73,0x73,0x69,0x62,0x6C,0x65,0x20,0x74,
+ 0x6F,0x20,0x63,0x6F,0x6C,0x6C,0x65,0x63,0x74,0x20,0x64,0x61,
+ 0x74,0x61,0x20,0x66,0x72,0x6F,0x6D,0x27,0x73,0x65,0x76,0x65,
+ 0x72,0x61,0x6C,0x20,0x6C,0x6F,0x63,0x61,0x74,0x69,0x6F,0x6E,
+ 0x73,0x20,0x69,0x6E,0x74,0x6F,0x20,0x74,0x68,0x65,0x20,0x63,
+ 0x6F,0x70,0x79,0x62,0x75,0x66,0x66,0x65,0x72,0x2E,0x29,0x00,
+ 0x03,0x45,0x4E,0x44,0x4C,0x3B,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,
0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,
0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,
0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,
0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,
0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,
+ 0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x4C,0x3B,0x2A,
0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,
- 0x4C,0x3B,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,
0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,
0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,
0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,
0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,
0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,
- 0x2A,0x2A,0x2A,0x2A,0x2A,0x0E,0x40,0x4C,0x50,0x72,0x6F,0x62,
- 0x6C,0x65,0x6D,0x73,0x2F,0x46,0x41,0x51,0x06,0x3E,0x40,0x58,
- 0x30,0x32,0x30,0x2A,0x3E,0x40,0x43,0x30,0x30,0x31,0x51,0x3A,
- 0x20,0x48,0x6F,0x77,0x20,0x63,0x61,0x6E,0x20,0x49,0x20,0x74,
- 0x6F,0x67,0x67,0x6C,0x65,0x20,0x66,0x75,0x6C,0x6C,0x73,0x63,
- 0x72,0x65,0x65,0x6E,0x20,0x6D,0x6F,0x64,0x65,0x3F,0x37,0x3E,
- 0x40,0x43,0x30,0x30,0x32,0x41,0x3A,0x20,0x50,0x72,0x65,0x73,
- 0x73,0x20,0x41,0x6C,0x74,0x2B,0x45,0x6E,0x74,0x65,0x72,0x20,
- 0x28,0x43,0x74,0x72,0x6C,0x2B,0x43,0x6D,0x64,0x2B,0x46,0x20,
- 0x61,0x6C,0x73,0x6F,0x20,0x77,0x6F,0x72,0x6B,0x73,0x20,0x6F,
- 0x6E,0x20,0x4D,0x61,0x63,0x29,0x06,0x3E,0x40,0x58,0x30,0x32,
- 0x30,0x45,0x3E,0x40,0x43,0x30,0x30,0x31,0x51,0x3A,0x20,0x48,
- 0x6F,0x77,0x20,0x63,0x61,0x6E,0x20,0x49,0x20,0x6D,0x61,0x6B,
- 0x65,0x20,0x66,0x75,0x6C,0x6C,0x73,0x63,0x72,0x65,0x65,0x6E,
- 0x20,0x6D,0x6F,0x64,0x65,0x20,0x73,0x74,0x72,0x65,0x74,0x63,
- 0x68,0x20,0x6F,0x75,0x74,0x20,0x74,0x68,0x65,0x20,0x77,0x68,
- 0x6F,0x6C,0x65,0x20,0x73,0x63,0x72,0x65,0x65,0x6E,0x3F,0x37,
- 0x3E,0x40,0x43,0x30,0x30,0x32,0x41,0x3A,0x20,0x45,0x6E,0x61,
- 0x62,0x6C,0x65,0x20,0x22,0x53,0x74,0x72,0x65,0x74,0x63,0x68,
- 0x65,0x64,0x22,0x20,0x69,0x6E,0x20,0x43,0x6F,0x6E,0x66,0x69,
- 0x67,0x20,0x2D,0x3E,0x20,0x4D,0x69,0x73,0x63,0x65,0x6C,0x6C,
- 0x61,0x6E,0x65,0x6F,0x75,0x73,0x2E,0x4E,0x3E,0x40,0x58,0x30,
- 0x33,0x35,0x54,0x68,0x69,0x73,0x20,0x77,0x69,0x6C,0x6C,0x20,
- 0x72,0x65,0x73,0x75,0x6C,0x74,0x20,0x69,0x6E,0x20,0x75,0x6E,
- 0x65,0x76,0x65,0x6E,0x20,0x70,0x69,0x78,0x65,0x6C,0x20,0x77,
- 0x69,0x64,0x74,0x68,0x73,0x2E,0x20,0x49,0x66,0x20,0x79,0x6F,
- 0x75,0x20,0x77,0x61,0x6E,0x74,0x20,0x74,0x6F,0x20,0x66,0x69,
- 0x78,0x20,0x74,0x68,0x69,0x73,0x2C,0x20,0x65,0x6E,0x61,0x62,
- 0x6C,0x65,0x3D,0x22,0x50,0x69,0x78,0x65,0x6C,0x20,0x66,0x69,
- 0x6C,0x74,0x65,0x72,0x22,0x20,0x28,0x74,0x68,0x6F,0x75,0x67,
- 0x68,0x20,0x74,0x68,0x69,0x73,0x20,0x77,0x69,0x6C,0x6C,0x20,
- 0x6D,0x61,0x6B,0x65,0x20,0x74,0x68,0x65,0x20,0x69,0x6D,0x61,
- 0x67,0x65,0x20,0x6C,0x6F,0x6F,0x6B,0x20,0x62,0x6C,0x75,0x72,
- 0x72,0x79,0x29,0x2E,0x06,0x3E,0x40,0x58,0x30,0x32,0x30,0x27,
- 0x3E,0x40,0x43,0x30,0x30,0x31,0x51,0x3A,0x20,0x49,0x20,0x63,
- 0x61,0x6E,0x27,0x74,0x20,0x75,0x73,0x65,0x20,0x41,0x6C,0x74,
- 0x2B,0x46,0x34,0x20,0x61,0x6E,0x64,0x20,0x41,0x6C,0x74,0x2B,
- 0x46,0x35,0x21,0x4E,0x3E,0x40,0x43,0x30,0x30,0x32,0x41,0x3A,
- 0x20,0x57,0x69,0x6E,0x64,0x6F,0x77,0x73,0x3A,0x20,0x49,0x66,
- 0x20,0x79,0x6F,0x75,0x20,0x68,0x61,0x76,0x65,0x20,0x47,0x65,
- 0x46,0x6F,0x72,0x63,0x65,0x20,0x45,0x78,0x70,0x65,0x72,0x69,
- 0x65,0x6E,0x63,0x65,0x20,0x69,0x6E,0x73,0x74,0x61,0x6C,0x6C,
- 0x65,0x64,0x2C,0x20,0x79,0x6F,0x75,0x20,0x6E,0x65,0x65,0x64,
- 0x20,0x74,0x6F,0x20,0x63,0x68,0x61,0x6E,0x67,0x65,0x2B,0x3E,
- 0x40,0x58,0x30,0x33,0x35,0x74,0x68,0x65,0x20,0x6B,0x65,0x79,
- 0x62,0x69,0x6E,0x64,0x69,0x6E,0x67,0x73,0x20,0x69,0x6E,0x20,
- 0x69,0x74,0x73,0x20,0x73,0x65,0x74,0x74,0x69,0x6E,0x67,0x73,
- 0x20,0x70,0x61,0x67,0x65,0x2E,0x57,0x3E,0x6D,0x61,0x63,0x4F,
- 0x53,0x2F,0x4F,0x53,0x20,0x58,0x3A,0x20,0x43,0x68,0x61,0x6E,
- 0x67,0x65,0x20,0x41,0x6C,0x74,0x2B,0x46,0x34,0x2F,0x41,0x6C,
- 0x74,0x2B,0x46,0x35,0x20,0x6B,0x65,0x79,0x73,0x20,0x69,0x6E,
- 0x20,0x74,0x68,0x65,0x20,0x4F,0x53,0x20,0x74,0x6F,0x20,0x73,
- 0x6F,0x6D,0x65,0x74,0x68,0x69,0x6E,0x67,0x20,0x65,0x6C,0x73,
- 0x65,0x2E,0x20,0x41,0x6C,0x73,0x6F,0x20,0x66,0x6F,0x72,0x20,
- 0x47,0x4E,0x55,0x2F,0x4C,0x69,0x6E,0x75,0x78,0x2E,0x06,0x3E,
- 0x40,0x58,0x30,0x32,0x30,0x2B,0x3E,0x40,0x43,0x30,0x30,0x31,
- 0x51,0x3A,0x20,0x54,0x68,0x65,0x20,0x6D,0x6F,0x75,0x73,0x65,
- 0x20,0x63,0x75,0x72,0x73,0x6F,0x72,0x20,0x69,0x73,0x20,0x64,
- 0x65,0x6C,0x61,0x79,0x65,0x64,0x2F,0x6C,0x61,0x67,0x67,0x79,
- 0x21,0x44,0x3E,0x40,0x43,0x30,0x30,0x32,0x41,0x3A,0x20,0x4D,
- 0x61,0x6B,0x65,0x20,0x73,0x75,0x72,0x65,0x20,0x22,0x53,0x6F,
- 0x66,0x74,0x77,0x61,0x72,0x65,0x20,0x6D,0x6F,0x75,0x73,0x65,
- 0x22,0x20,0x69,0x73,0x20,0x64,0x69,0x73,0x61,0x62,0x6C,0x65,
- 0x64,0x20,0x69,0x6E,0x20,0x43,0x6F,0x6E,0x66,0x69,0x67,0x20,
- 0x2D,0x3E,0x20,0x4C,0x61,0x79,0x6F,0x75,0x74,0x2E,0x4B,0x3E,
- 0x40,0x58,0x30,0x33,0x35,0x41,0x6C,0x74,0x65,0x72,0x6E,0x61,
- 0x74,0x69,0x76,0x65,0x6C,0x79,0x2C,0x20,0x79,0x6F,0x75,0x20,
- 0x63,0x61,0x6E,0x20,0x65,0x6E,0x61,0x62,0x6C,0x65,0x20,0x22,
- 0x56,0x53,0x79,0x6E,0x63,0x20,0x6F,0x66,0x66,0x22,0x20,0x69,
+ 0x2A,0x2A,0x0E,0x40,0x4C,0x50,0x72,0x6F,0x62,0x6C,0x65,0x6D,
+ 0x73,0x2F,0x46,0x41,0x51,0x06,0x3E,0x40,0x58,0x30,0x32,0x30,
+ 0x2A,0x3E,0x40,0x43,0x30,0x30,0x31,0x51,0x3A,0x20,0x48,0x6F,
+ 0x77,0x20,0x63,0x61,0x6E,0x20,0x49,0x20,0x74,0x6F,0x67,0x67,
+ 0x6C,0x65,0x20,0x66,0x75,0x6C,0x6C,0x73,0x63,0x72,0x65,0x65,
+ 0x6E,0x20,0x6D,0x6F,0x64,0x65,0x3F,0x37,0x3E,0x40,0x43,0x30,
+ 0x30,0x32,0x41,0x3A,0x20,0x50,0x72,0x65,0x73,0x73,0x20,0x41,
+ 0x6C,0x74,0x2B,0x45,0x6E,0x74,0x65,0x72,0x20,0x28,0x43,0x74,
+ 0x72,0x6C,0x2B,0x43,0x6D,0x64,0x2B,0x46,0x20,0x61,0x6C,0x73,
+ 0x6F,0x20,0x77,0x6F,0x72,0x6B,0x73,0x20,0x6F,0x6E,0x20,0x4D,
+ 0x61,0x63,0x29,0x06,0x3E,0x40,0x58,0x30,0x32,0x30,0x45,0x3E,
+ 0x40,0x43,0x30,0x30,0x31,0x51,0x3A,0x20,0x48,0x6F,0x77,0x20,
+ 0x63,0x61,0x6E,0x20,0x49,0x20,0x6D,0x61,0x6B,0x65,0x20,0x66,
+ 0x75,0x6C,0x6C,0x73,0x63,0x72,0x65,0x65,0x6E,0x20,0x6D,0x6F,
+ 0x64,0x65,0x20,0x73,0x74,0x72,0x65,0x74,0x63,0x68,0x20,0x6F,
+ 0x75,0x74,0x20,0x74,0x68,0x65,0x20,0x77,0x68,0x6F,0x6C,0x65,
+ 0x20,0x73,0x63,0x72,0x65,0x65,0x6E,0x3F,0x37,0x3E,0x40,0x43,
+ 0x30,0x30,0x32,0x41,0x3A,0x20,0x45,0x6E,0x61,0x62,0x6C,0x65,
+ 0x20,0x22,0x53,0x74,0x72,0x65,0x74,0x63,0x68,0x65,0x64,0x22,
+ 0x20,0x69,0x6E,0x20,0x43,0x6F,0x6E,0x66,0x69,0x67,0x20,0x2D,
+ 0x3E,0x20,0x4D,0x69,0x73,0x63,0x65,0x6C,0x6C,0x61,0x6E,0x65,
+ 0x6F,0x75,0x73,0x2E,0x4E,0x3E,0x40,0x58,0x30,0x33,0x35,0x54,
+ 0x68,0x69,0x73,0x20,0x77,0x69,0x6C,0x6C,0x20,0x72,0x65,0x73,
+ 0x75,0x6C,0x74,0x20,0x69,0x6E,0x20,0x75,0x6E,0x65,0x76,0x65,
+ 0x6E,0x20,0x70,0x69,0x78,0x65,0x6C,0x20,0x77,0x69,0x64,0x74,
+ 0x68,0x73,0x2E,0x20,0x49,0x66,0x20,0x79,0x6F,0x75,0x20,0x77,
+ 0x61,0x6E,0x74,0x20,0x74,0x6F,0x20,0x66,0x69,0x78,0x20,0x74,
+ 0x68,0x69,0x73,0x2C,0x20,0x65,0x6E,0x61,0x62,0x6C,0x65,0x3D,
+ 0x22,0x50,0x69,0x78,0x65,0x6C,0x20,0x66,0x69,0x6C,0x74,0x65,
+ 0x72,0x22,0x20,0x28,0x74,0x68,0x6F,0x75,0x67,0x68,0x20,0x74,
+ 0x68,0x69,0x73,0x20,0x77,0x69,0x6C,0x6C,0x20,0x6D,0x61,0x6B,
+ 0x65,0x20,0x74,0x68,0x65,0x20,0x69,0x6D,0x61,0x67,0x65,0x20,
+ 0x6C,0x6F,0x6F,0x6B,0x20,0x62,0x6C,0x75,0x72,0x72,0x79,0x29,
+ 0x2E,0x06,0x3E,0x40,0x58,0x30,0x32,0x30,0x27,0x3E,0x40,0x43,
+ 0x30,0x30,0x31,0x51,0x3A,0x20,0x49,0x20,0x63,0x61,0x6E,0x27,
+ 0x74,0x20,0x75,0x73,0x65,0x20,0x41,0x6C,0x74,0x2B,0x46,0x34,
+ 0x20,0x61,0x6E,0x64,0x20,0x41,0x6C,0x74,0x2B,0x46,0x35,0x21,
+ 0x4E,0x3E,0x40,0x43,0x30,0x30,0x32,0x41,0x3A,0x20,0x57,0x69,
+ 0x6E,0x64,0x6F,0x77,0x73,0x3A,0x20,0x49,0x66,0x20,0x79,0x6F,
+ 0x75,0x20,0x68,0x61,0x76,0x65,0x20,0x47,0x65,0x46,0x6F,0x72,
+ 0x63,0x65,0x20,0x45,0x78,0x70,0x65,0x72,0x69,0x65,0x6E,0x63,
+ 0x65,0x20,0x69,0x6E,0x73,0x74,0x61,0x6C,0x6C,0x65,0x64,0x2C,
+ 0x20,0x79,0x6F,0x75,0x20,0x6E,0x65,0x65,0x64,0x20,0x74,0x6F,
+ 0x20,0x63,0x68,0x61,0x6E,0x67,0x65,0x2B,0x3E,0x40,0x58,0x30,
+ 0x33,0x35,0x74,0x68,0x65,0x20,0x6B,0x65,0x79,0x62,0x69,0x6E,
+ 0x64,0x69,0x6E,0x67,0x73,0x20,0x69,0x6E,0x20,0x69,0x74,0x73,
+ 0x20,0x73,0x65,0x74,0x74,0x69,0x6E,0x67,0x73,0x20,0x70,0x61,
+ 0x67,0x65,0x2E,0x57,0x3E,0x6D,0x61,0x63,0x4F,0x53,0x2F,0x4F,
+ 0x53,0x20,0x58,0x3A,0x20,0x43,0x68,0x61,0x6E,0x67,0x65,0x20,
+ 0x41,0x6C,0x74,0x2B,0x46,0x34,0x2F,0x41,0x6C,0x74,0x2B,0x46,
+ 0x35,0x20,0x6B,0x65,0x79,0x73,0x20,0x69,0x6E,0x20,0x74,0x68,
+ 0x65,0x20,0x4F,0x53,0x20,0x74,0x6F,0x20,0x73,0x6F,0x6D,0x65,
+ 0x74,0x68,0x69,0x6E,0x67,0x20,0x65,0x6C,0x73,0x65,0x2E,0x20,
+ 0x41,0x6C,0x73,0x6F,0x20,0x66,0x6F,0x72,0x20,0x47,0x4E,0x55,
+ 0x2F,0x4C,0x69,0x6E,0x75,0x78,0x2E,0x06,0x3E,0x40,0x58,0x30,
+ 0x32,0x30,0x2B,0x3E,0x40,0x43,0x30,0x30,0x31,0x51,0x3A,0x20,
+ 0x54,0x68,0x65,0x20,0x6D,0x6F,0x75,0x73,0x65,0x20,0x63,0x75,
+ 0x72,0x73,0x6F,0x72,0x20,0x69,0x73,0x20,0x64,0x65,0x6C,0x61,
+ 0x79,0x65,0x64,0x2F,0x6C,0x61,0x67,0x67,0x79,0x21,0x44,0x3E,
+ 0x40,0x43,0x30,0x30,0x32,0x41,0x3A,0x20,0x4D,0x61,0x6B,0x65,
+ 0x20,0x73,0x75,0x72,0x65,0x20,0x22,0x53,0x6F,0x66,0x74,0x77,
+ 0x61,0x72,0x65,0x20,0x6D,0x6F,0x75,0x73,0x65,0x22,0x20,0x69,
+ 0x73,0x20,0x64,0x69,0x73,0x61,0x62,0x6C,0x65,0x64,0x20,0x69,
0x6E,0x20,0x43,0x6F,0x6E,0x66,0x69,0x67,0x20,0x2D,0x3E,0x20,
- 0x4D,0x69,0x73,0x63,0x65,0x6C,0x6C,0x61,0x6E,0x65,0x6F,0x75,
- 0x73,0x2E,0x46,0x3E,0x54,0x68,0x69,0x73,0x20,0x68,0x6F,0x77,
- 0x65,0x76,0x65,0x72,0x2C,0x20,0x77,0x69,0x6C,0x6C,0x20,0x69,
- 0x6E,0x74,0x72,0x6F,0x64,0x75,0x63,0x65,0x20,0x73,0x74,0x75,
- 0x74,0x74,0x65,0x72,0x69,0x6E,0x67,0x20,0x62,0x65,0x63,0x61,
- 0x75,0x73,0x65,0x20,0x74,0x68,0x65,0x20,0x72,0x65,0x6E,0x64,
- 0x65,0x72,0x69,0x6E,0x67,0x20,0x72,0x61,0x74,0x65,0x20,0x69,
- 0x73,0x22,0x3E,0x6E,0x6F,0x74,0x20,0x65,0x78,0x61,0x63,0x74,
- 0x20,0x74,0x6F,0x20,0x79,0x6F,0x75,0x72,0x20,0x6D,0x6F,0x6E,
- 0x69,0x74,0x6F,0x72,0x27,0x73,0x20,0x72,0x61,0x74,0x65,0x2E,
- 0x06,0x3E,0x40,0x58,0x30,0x32,0x30,0x33,0x3E,0x40,0x43,0x30,
- 0x30,0x31,0x51,0x3A,0x20,0x57,0x69,0x6C,0x6C,0x20,0x79,0x6F,
- 0x75,0x20,0x69,0x6D,0x70,0x6C,0x65,0x6D,0x65,0x6E,0x74,0x20,
- 0x4D,0x49,0x44,0x49,0x20,0x6F,0x75,0x74,0x20,0x66,0x75,0x6E,
- 0x63,0x74,0x69,0x6F,0x6E,0x61,0x6C,0x69,0x74,0x79,0x3F,0x4D,
- 0x3E,0x40,0x43,0x30,0x30,0x32,0x41,0x3A,0x20,0x4E,0x6F,0x2C,
- 0x20,0x73,0x6F,0x72,0x72,0x79,0x2E,0x20,0x54,0x68,0x69,0x73,
- 0x20,0x69,0x73,0x20,0x76,0x65,0x72,0x79,0x20,0x64,0x69,0x66,
- 0x66,0x69,0x63,0x75,0x6C,0x74,0x20,0x74,0x6F,0x20,0x69,0x6D,
- 0x70,0x6C,0x65,0x6D,0x65,0x6E,0x74,0x20,0x63,0x6F,0x72,0x72,
- 0x65,0x63,0x74,0x6C,0x79,0x20,0x77,0x68,0x65,0x6E,0x20,0x68,
- 0x61,0x76,0x69,0x6E,0x67,0x3C,0x3E,0x40,0x58,0x30,0x33,0x35,
- 0x68,0x69,0x67,0x68,0x65,0x72,0x20,0x61,0x75,0x64,0x69,0x6F,
- 0x20,0x62,0x75,0x66,0x66,0x65,0x72,0x20,0x73,0x69,0x7A,0x65,
- 0x73,0x20,0x28,0x62,0x75,0x66,0x66,0x65,0x72,0x65,0x64,0x20,
- 0x72,0x65,0x70,0x6C,0x61,0x79,0x65,0x72,0x20,0x74,0x69,0x63,
- 0x6B,0x73,0x29,0x2E,0x2E,0x2E,0x06,0x3E,0x40,0x58,0x30,0x32,
- 0x30,0x30,0x3E,0x40,0x43,0x30,0x30,0x31,0x51,0x3A,0x20,0x57,
- 0x68,0x65,0x72,0x65,0x20,0x69,0x73,0x20,0x74,0x68,0x65,0x20,
- 0x63,0x6F,0x6E,0x66,0x69,0x67,0x75,0x72,0x61,0x74,0x69,0x6F,
- 0x6E,0x20,0x66,0x69,0x6C,0x65,0x20,0x73,0x74,0x6F,0x72,0x65,
- 0x64,0x3F,0x3F,0x3E,0x40,0x43,0x30,0x30,0x32,0x41,0x3A,0x20,
- 0x57,0x69,0x6E,0x64,0x6F,0x77,0x73,0x3A,0x20,0x5C,0x55,0x73,
- 0x65,0x72,0x73,0x5C,0x55,0x53,0x45,0x52,0x5C,0x41,0x70,0x70,
- 0x44,0x61,0x74,0x61,0x5C,0x52,0x6F,0x61,0x6D,0x69,0x6E,0x67,
- 0x5C,0x46,0x54,0x32,0x20,0x63,0x6C,0x6F,0x6E,0x65,0x5C,0x46,
- 0x54,0x32,0x2E,0x43,0x46,0x47,0x45,0x3E,0x40,0x58,0x30,0x33,
- 0x35,0x4F,0x53,0x20,0x58,0x3A,0x20,0x2F,0x55,0x73,0x65,0x72,
- 0x73,0x2F,0x55,0x53,0x45,0x52,0x2F,0x4C,0x69,0x62,0x72,0x61,
- 0x72,0x79,0x2F,0x41,0x70,0x70,0x6C,0x69,0x63,0x61,0x74,0x69,
- 0x6F,0x6E,0x20,0x53,0x75,0x70,0x70,0x6F,0x72,0x74,0x2F,0x46,
- 0x54,0x32,0x20,0x63,0x6C,0x6F,0x6E,0x65,0x2F,0x46,0x54,0x32,
- 0x2E,0x43,0x46,0x47,0x2F,0x47,0x4E,0x55,0x2F,0x4C,0x69,0x6E,
- 0x75,0x78,0x3A,0x20,0x2F,0x68,0x6F,0x6D,0x65,0x2F,0x55,0x53,
- 0x45,0x52,0x2F,0x2E,0x63,0x6F,0x6E,0x66,0x69,0x67,0x2F,0x46,
- 0x54,0x32,0x20,0x63,0x6C,0x6F,0x6E,0x65,0x2F,0x46,0x54,0x32,
- 0x2E,0x43,0x46,0x47,0x01,0x3E,0x48,0x49,0x74,0x20,0x77,0x69,
- 0x6C,0x6C,0x20,0x62,0x65,0x20,0x73,0x74,0x6F,0x72,0x65,0x64,
- 0x20,0x69,0x6E,0x20,0x74,0x68,0x65,0x20,0x70,0x72,0x6F,0x67,
- 0x72,0x61,0x6D,0x20,0x64,0x69,0x72,0x65,0x63,0x74,0x6F,0x72,
- 0x79,0x20,0x69,0x66,0x20,0x74,0x68,0x65,0x20,0x70,0x61,0x74,
- 0x68,0x20,0x63,0x6F,0x75,0x6C,0x64,0x6E,0x27,0x74,0x20,0x62,
- 0x65,0x20,0x75,0x73,0x65,0x64,0x2E,0x4D,0x49,0x66,0x20,0x79,
- 0x6F,0x75,0x20,0x70,0x75,0x74,0x20,0x74,0x68,0x65,0x20,0x63,
- 0x6F,0x6E,0x66,0x69,0x67,0x75,0x72,0x61,0x74,0x69,0x6F,0x6E,
- 0x20,0x66,0x69,0x6C,0x65,0x20,0x69,0x6E,0x20,0x74,0x68,0x65,
- 0x20,0x70,0x72,0x6F,0x67,0x72,0x61,0x6D,0x20,0x64,0x69,0x72,
- 0x65,0x63,0x74,0x6F,0x72,0x79,0x2C,0x20,0x69,0x74,0x20,0x77,
- 0x69,0x6C,0x6C,0x20,0x72,0x65,0x61,0x64,0x20,0x74,0x68,0x61,
- 0x74,0x4A,0x6F,0x6E,0x65,0x20,0x61,0x6E,0x64,0x20,0x6E,0x6F,
- 0x74,0x20,0x61,0x74,0x74,0x65,0x6D,0x70,0x74,0x20,0x74,0x6F,
- 0x20,0x63,0x72,0x65,0x61,0x74,0x65,0x20,0x63,0x6F,0x6E,0x66,
- 0x69,0x67,0x20,0x64,0x69,0x72,0x73,0x20,0x66,0x6F,0x72,0x20,
- 0x74,0x68,0x65,0x20,0x4F,0x53,0x20,0x75,0x73,0x65,0x72,0x2E,
- 0x20,0x28,0x70,0x6F,0x72,0x74,0x61,0x62,0x6C,0x65,0x20,0x6D,
- 0x6F,0x64,0x65,0x29,0x06,0x3E,0x40,0x58,0x30,0x32,0x30,0x42,
- 0x3E,0x40,0x43,0x30,0x30,0x31,0x51,0x3A,0x20,0x43,0x61,0x6E,
- 0x20,0x74,0x68,0x65,0x20,0x63,0x6C,0x6F,0x6E,0x65,0x20,0x72,
- 0x65,0x61,0x64,0x20,0x46,0x54,0x32,0x2E,0x43,0x46,0x47,0x20,
- 0x66,0x72,0x6F,0x6D,0x20,0x72,0x65,0x61,0x6C,0x20,0x46,0x54,
- 0x32,0x2C,0x20,0x61,0x6E,0x64,0x20,0x76,0x69,0x63,0x65,0x20,
- 0x76,0x65,0x72,0x73,0x61,0x3F,0x4C,0x3E,0x40,0x43,0x30,0x30,
- 0x32,0x41,0x3A,0x20,0x59,0x65,0x73,0x2C,0x20,0x69,0x74,0x20,
- 0x73,0x68,0x6F,0x75,0x6C,0x64,0x20,0x77,0x6F,0x72,0x6B,0x20,
- 0x6A,0x75,0x73,0x74,0x20,0x66,0x69,0x6E,0x65,0x2E,0x20,0x50,
- 0x75,0x74,0x20,0x69,0x74,0x20,0x69,0x6E,0x20,0x74,0x68,0x65,
- 0x20,0x64,0x69,0x72,0x65,0x63,0x74,0x6F,0x72,0x79,0x20,0x73,
- 0x68,0x6F,0x77,0x6E,0x20,0x61,0x62,0x6F,0x76,0x65,0x2E,0x06,
- 0x3E,0x40,0x58,0x30,0x32,0x30,0x52,0x3E,0x40,0x43,0x30,0x30,
- 0x31,0x51,0x3A,0x20,0x53,0x6D,0x70,0x2E,0x20,0x45,0x64,0x2E,
- 0x3A,0x20,0x57,0x68,0x69,0x6C,0x65,0x20,0x7A,0x6F,0x6F,0x6D,
- 0x69,0x6E,0x67,0x20,0x69,0x6E,0x2C,0x20,0x49,0x20,0x73,0x6F,
- 0x6D,0x65,0x74,0x69,0x6D,0x65,0x73,0x20,0x63,0x61,0x6E,0x27,
- 0x74,0x20,0x6D,0x61,0x72,0x6B,0x20,0x74,0x68,0x65,0x20,0x6C,
- 0x61,0x73,0x74,0x20,0x73,0x61,0x6D,0x70,0x6C,0x65,0x20,0x70,
- 0x6F,0x69,0x6E,0x74,0x21,0x47,0x3E,0x40,0x43,0x30,0x30,0x32,
- 0x41,0x3A,0x20,0x54,0x68,0x69,0x73,0x20,0x69,0x73,0x20,0x6E,
- 0x6F,0x72,0x6D,0x61,0x6C,0x2E,0x20,0x54,0x68,0x69,0x73,0x20,
- 0x69,0x73,0x20,0x61,0x20,0x6C,0x69,0x6D,0x69,0x74,0x61,0x74,
- 0x69,0x6F,0x6E,0x20,0x69,0x6E,0x20,0x74,0x68,0x65,0x20,0x6E,
- 0x61,0x74,0x75,0x72,0x65,0x20,0x6F,0x66,0x20,0x73,0x63,0x61,
- 0x6C,0x69,0x6E,0x67,0x2E,0x06,0x3E,0x40,0x58,0x30,0x32,0x30,
- 0x17,0x3E,0x40,0x43,0x30,0x30,0x31,0x51,0x3A,0x20,0x49,0x20,
- 0x66,0x6F,0x75,0x6E,0x64,0x20,0x61,0x20,0x62,0x75,0x67,0x21,
- 0x4C,0x3E,0x40,0x43,0x30,0x30,0x32,0x41,0x3A,0x20,0x50,0x6C,
- 0x65,0x61,0x73,0x65,0x20,0x73,0x65,0x6E,0x64,0x20,0x6D,0x65,
- 0x20,0x61,0x20,0x6D,0x61,0x69,0x6C,0x20,0x28,0x66,0x6F,0x75,
- 0x6E,0x64,0x20,0x61,0x74,0x20,0x31,0x36,0x2D,0x62,0x69,0x74,
- 0x73,0x2E,0x6F,0x72,0x67,0x29,0x20,0x61,0x6E,0x64,0x20,0x74,
- 0x72,0x79,0x20,0x74,0x6F,0x20,0x65,0x78,0x70,0x6C,0x61,0x69,
- 0x6E,0x20,0x69,0x74,0x2E,0x00,0x03,0x45,0x4E,0x44,0x4C,0x3B,
+ 0x4C,0x61,0x79,0x6F,0x75,0x74,0x2E,0x4B,0x3E,0x40,0x58,0x30,
+ 0x33,0x35,0x41,0x6C,0x74,0x65,0x72,0x6E,0x61,0x74,0x69,0x76,
+ 0x65,0x6C,0x79,0x2C,0x20,0x79,0x6F,0x75,0x20,0x63,0x61,0x6E,
+ 0x20,0x65,0x6E,0x61,0x62,0x6C,0x65,0x20,0x22,0x56,0x53,0x79,
+ 0x6E,0x63,0x20,0x6F,0x66,0x66,0x22,0x20,0x69,0x6E,0x20,0x43,
+ 0x6F,0x6E,0x66,0x69,0x67,0x20,0x2D,0x3E,0x20,0x4D,0x69,0x73,
+ 0x63,0x65,0x6C,0x6C,0x61,0x6E,0x65,0x6F,0x75,0x73,0x2E,0x46,
+ 0x3E,0x54,0x68,0x69,0x73,0x20,0x68,0x6F,0x77,0x65,0x76,0x65,
+ 0x72,0x2C,0x20,0x77,0x69,0x6C,0x6C,0x20,0x69,0x6E,0x74,0x72,
+ 0x6F,0x64,0x75,0x63,0x65,0x20,0x73,0x74,0x75,0x74,0x74,0x65,
+ 0x72,0x69,0x6E,0x67,0x20,0x62,0x65,0x63,0x61,0x75,0x73,0x65,
+ 0x20,0x74,0x68,0x65,0x20,0x72,0x65,0x6E,0x64,0x65,0x72,0x69,
+ 0x6E,0x67,0x20,0x72,0x61,0x74,0x65,0x20,0x69,0x73,0x22,0x3E,
+ 0x6E,0x6F,0x74,0x20,0x65,0x78,0x61,0x63,0x74,0x20,0x74,0x6F,
+ 0x20,0x79,0x6F,0x75,0x72,0x20,0x6D,0x6F,0x6E,0x69,0x74,0x6F,
+ 0x72,0x27,0x73,0x20,0x72,0x61,0x74,0x65,0x2E,0x06,0x3E,0x40,
+ 0x58,0x30,0x32,0x30,0x33,0x3E,0x40,0x43,0x30,0x30,0x31,0x51,
+ 0x3A,0x20,0x57,0x69,0x6C,0x6C,0x20,0x79,0x6F,0x75,0x20,0x69,
+ 0x6D,0x70,0x6C,0x65,0x6D,0x65,0x6E,0x74,0x20,0x4D,0x49,0x44,
+ 0x49,0x20,0x6F,0x75,0x74,0x20,0x66,0x75,0x6E,0x63,0x74,0x69,
+ 0x6F,0x6E,0x61,0x6C,0x69,0x74,0x79,0x3F,0x4D,0x3E,0x40,0x43,
+ 0x30,0x30,0x32,0x41,0x3A,0x20,0x4E,0x6F,0x2C,0x20,0x73,0x6F,
+ 0x72,0x72,0x79,0x2E,0x20,0x54,0x68,0x69,0x73,0x20,0x69,0x73,
+ 0x20,0x76,0x65,0x72,0x79,0x20,0x64,0x69,0x66,0x66,0x69,0x63,
+ 0x75,0x6C,0x74,0x20,0x74,0x6F,0x20,0x69,0x6D,0x70,0x6C,0x65,
+ 0x6D,0x65,0x6E,0x74,0x20,0x63,0x6F,0x72,0x72,0x65,0x63,0x74,
+ 0x6C,0x79,0x20,0x77,0x68,0x65,0x6E,0x20,0x68,0x61,0x76,0x69,
+ 0x6E,0x67,0x3C,0x3E,0x40,0x58,0x30,0x33,0x35,0x68,0x69,0x67,
+ 0x68,0x65,0x72,0x20,0x61,0x75,0x64,0x69,0x6F,0x20,0x62,0x75,
+ 0x66,0x66,0x65,0x72,0x20,0x73,0x69,0x7A,0x65,0x73,0x20,0x28,
+ 0x62,0x75,0x66,0x66,0x65,0x72,0x65,0x64,0x20,0x72,0x65,0x70,
+ 0x6C,0x61,0x79,0x65,0x72,0x20,0x74,0x69,0x63,0x6B,0x73,0x29,
+ 0x2E,0x2E,0x2E,0x06,0x3E,0x40,0x58,0x30,0x32,0x30,0x30,0x3E,
+ 0x40,0x43,0x30,0x30,0x31,0x51,0x3A,0x20,0x57,0x68,0x65,0x72,
+ 0x65,0x20,0x69,0x73,0x20,0x74,0x68,0x65,0x20,0x63,0x6F,0x6E,
+ 0x66,0x69,0x67,0x75,0x72,0x61,0x74,0x69,0x6F,0x6E,0x20,0x66,
+ 0x69,0x6C,0x65,0x20,0x73,0x74,0x6F,0x72,0x65,0x64,0x3F,0x3F,
+ 0x3E,0x40,0x43,0x30,0x30,0x32,0x41,0x3A,0x20,0x57,0x69,0x6E,
+ 0x64,0x6F,0x77,0x73,0x3A,0x20,0x5C,0x55,0x73,0x65,0x72,0x73,
+ 0x5C,0x55,0x53,0x45,0x52,0x5C,0x41,0x70,0x70,0x44,0x61,0x74,
+ 0x61,0x5C,0x52,0x6F,0x61,0x6D,0x69,0x6E,0x67,0x5C,0x46,0x54,
+ 0x32,0x20,0x63,0x6C,0x6F,0x6E,0x65,0x5C,0x46,0x54,0x32,0x2E,
+ 0x43,0x46,0x47,0x45,0x3E,0x40,0x58,0x30,0x33,0x35,0x4F,0x53,
+ 0x20,0x58,0x3A,0x20,0x2F,0x55,0x73,0x65,0x72,0x73,0x2F,0x55,
+ 0x53,0x45,0x52,0x2F,0x4C,0x69,0x62,0x72,0x61,0x72,0x79,0x2F,
+ 0x41,0x70,0x70,0x6C,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,
+ 0x53,0x75,0x70,0x70,0x6F,0x72,0x74,0x2F,0x46,0x54,0x32,0x20,
+ 0x63,0x6C,0x6F,0x6E,0x65,0x2F,0x46,0x54,0x32,0x2E,0x43,0x46,
+ 0x47,0x2F,0x47,0x4E,0x55,0x2F,0x4C,0x69,0x6E,0x75,0x78,0x3A,
+ 0x20,0x2F,0x68,0x6F,0x6D,0x65,0x2F,0x55,0x53,0x45,0x52,0x2F,
+ 0x2E,0x63,0x6F,0x6E,0x66,0x69,0x67,0x2F,0x46,0x54,0x32,0x20,
+ 0x63,0x6C,0x6F,0x6E,0x65,0x2F,0x46,0x54,0x32,0x2E,0x43,0x46,
+ 0x47,0x01,0x3E,0x48,0x49,0x74,0x20,0x77,0x69,0x6C,0x6C,0x20,
+ 0x62,0x65,0x20,0x73,0x74,0x6F,0x72,0x65,0x64,0x20,0x69,0x6E,
+ 0x20,0x74,0x68,0x65,0x20,0x70,0x72,0x6F,0x67,0x72,0x61,0x6D,
+ 0x20,0x64,0x69,0x72,0x65,0x63,0x74,0x6F,0x72,0x79,0x20,0x69,
+ 0x66,0x20,0x74,0x68,0x65,0x20,0x70,0x61,0x74,0x68,0x20,0x63,
+ 0x6F,0x75,0x6C,0x64,0x6E,0x27,0x74,0x20,0x62,0x65,0x20,0x75,
+ 0x73,0x65,0x64,0x2E,0x4D,0x49,0x66,0x20,0x79,0x6F,0x75,0x20,
+ 0x70,0x75,0x74,0x20,0x74,0x68,0x65,0x20,0x63,0x6F,0x6E,0x66,
+ 0x69,0x67,0x75,0x72,0x61,0x74,0x69,0x6F,0x6E,0x20,0x66,0x69,
+ 0x6C,0x65,0x20,0x69,0x6E,0x20,0x74,0x68,0x65,0x20,0x70,0x72,
+ 0x6F,0x67,0x72,0x61,0x6D,0x20,0x64,0x69,0x72,0x65,0x63,0x74,
+ 0x6F,0x72,0x79,0x2C,0x20,0x69,0x74,0x20,0x77,0x69,0x6C,0x6C,
+ 0x20,0x72,0x65,0x61,0x64,0x20,0x74,0x68,0x61,0x74,0x4A,0x6F,
+ 0x6E,0x65,0x20,0x61,0x6E,0x64,0x20,0x6E,0x6F,0x74,0x20,0x61,
+ 0x74,0x74,0x65,0x6D,0x70,0x74,0x20,0x74,0x6F,0x20,0x63,0x72,
+ 0x65,0x61,0x74,0x65,0x20,0x63,0x6F,0x6E,0x66,0x69,0x67,0x20,
+ 0x64,0x69,0x72,0x73,0x20,0x66,0x6F,0x72,0x20,0x74,0x68,0x65,
+ 0x20,0x4F,0x53,0x20,0x75,0x73,0x65,0x72,0x2E,0x20,0x28,0x70,
+ 0x6F,0x72,0x74,0x61,0x62,0x6C,0x65,0x20,0x6D,0x6F,0x64,0x65,
+ 0x29,0x06,0x3E,0x40,0x58,0x30,0x32,0x30,0x42,0x3E,0x40,0x43,
+ 0x30,0x30,0x31,0x51,0x3A,0x20,0x43,0x61,0x6E,0x20,0x74,0x68,
+ 0x65,0x20,0x63,0x6C,0x6F,0x6E,0x65,0x20,0x72,0x65,0x61,0x64,
+ 0x20,0x46,0x54,0x32,0x2E,0x43,0x46,0x47,0x20,0x66,0x72,0x6F,
+ 0x6D,0x20,0x72,0x65,0x61,0x6C,0x20,0x46,0x54,0x32,0x2C,0x20,
+ 0x61,0x6E,0x64,0x20,0x76,0x69,0x63,0x65,0x20,0x76,0x65,0x72,
+ 0x73,0x61,0x3F,0x4C,0x3E,0x40,0x43,0x30,0x30,0x32,0x41,0x3A,
+ 0x20,0x59,0x65,0x73,0x2C,0x20,0x69,0x74,0x20,0x73,0x68,0x6F,
+ 0x75,0x6C,0x64,0x20,0x77,0x6F,0x72,0x6B,0x20,0x6A,0x75,0x73,
+ 0x74,0x20,0x66,0x69,0x6E,0x65,0x2E,0x20,0x50,0x75,0x74,0x20,
+ 0x69,0x74,0x20,0x69,0x6E,0x20,0x74,0x68,0x65,0x20,0x64,0x69,
+ 0x72,0x65,0x63,0x74,0x6F,0x72,0x79,0x20,0x73,0x68,0x6F,0x77,
+ 0x6E,0x20,0x61,0x62,0x6F,0x76,0x65,0x2E,0x06,0x3E,0x40,0x58,
+ 0x30,0x32,0x30,0x52,0x3E,0x40,0x43,0x30,0x30,0x31,0x51,0x3A,
+ 0x20,0x53,0x6D,0x70,0x2E,0x20,0x45,0x64,0x2E,0x3A,0x20,0x57,
+ 0x68,0x69,0x6C,0x65,0x20,0x7A,0x6F,0x6F,0x6D,0x69,0x6E,0x67,
+ 0x20,0x69,0x6E,0x2C,0x20,0x49,0x20,0x73,0x6F,0x6D,0x65,0x74,
+ 0x69,0x6D,0x65,0x73,0x20,0x63,0x61,0x6E,0x27,0x74,0x20,0x6D,
+ 0x61,0x72,0x6B,0x20,0x74,0x68,0x65,0x20,0x6C,0x61,0x73,0x74,
+ 0x20,0x73,0x61,0x6D,0x70,0x6C,0x65,0x20,0x70,0x6F,0x69,0x6E,
+ 0x74,0x21,0x47,0x3E,0x40,0x43,0x30,0x30,0x32,0x41,0x3A,0x20,
+ 0x54,0x68,0x69,0x73,0x20,0x69,0x73,0x20,0x6E,0x6F,0x72,0x6D,
+ 0x61,0x6C,0x2E,0x20,0x54,0x68,0x69,0x73,0x20,0x69,0x73,0x20,
+ 0x61,0x20,0x6C,0x69,0x6D,0x69,0x74,0x61,0x74,0x69,0x6F,0x6E,
+ 0x20,0x69,0x6E,0x20,0x74,0x68,0x65,0x20,0x6E,0x61,0x74,0x75,
+ 0x72,0x65,0x20,0x6F,0x66,0x20,0x73,0x63,0x61,0x6C,0x69,0x6E,
+ 0x67,0x2E,0x06,0x3E,0x40,0x58,0x30,0x32,0x30,0x17,0x3E,0x40,
+ 0x43,0x30,0x30,0x31,0x51,0x3A,0x20,0x49,0x20,0x66,0x6F,0x75,
+ 0x6E,0x64,0x20,0x61,0x20,0x62,0x75,0x67,0x21,0x4C,0x3E,0x40,
+ 0x43,0x30,0x30,0x32,0x41,0x3A,0x20,0x50,0x6C,0x65,0x61,0x73,
+ 0x65,0x20,0x73,0x65,0x6E,0x64,0x20,0x6D,0x65,0x20,0x61,0x20,
+ 0x6D,0x61,0x69,0x6C,0x20,0x28,0x66,0x6F,0x75,0x6E,0x64,0x20,
+ 0x61,0x74,0x20,0x31,0x36,0x2D,0x62,0x69,0x74,0x73,0x2E,0x6F,
+ 0x72,0x67,0x29,0x20,0x61,0x6E,0x64,0x20,0x74,0x72,0x79,0x20,
+ 0x74,0x6F,0x20,0x65,0x78,0x70,0x6C,0x61,0x69,0x6E,0x20,0x69,
+ 0x74,0x2E,0x00,0x03,0x45,0x4E,0x44,0x4C,0x3B,0x2A,0x2A,0x2A,
0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,
0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,
0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,
@@ -2232,64 +2252,63 @@
0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,
0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,
0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,
- 0x2A,0x2A,0x2A,0x4C,0x3B,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,
+ 0x4C,0x3B,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,
0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,
0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,
0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,
0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,
0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,
- 0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x0C,0x40,0x4C,0x4B,
- 0x6E,0x6F,0x77,0x6E,0x20,0x62,0x75,0x67,0x73,0x06,0x3E,0x40,
- 0x58,0x30,0x31,0x30,0x2C,0x3E,0x40,0x43,0x30,0x30,0x31,0x57,
- 0x41,0x56,0x20,0x65,0x78,0x70,0x6F,0x72,0x74,0x69,0x6E,0x67,
- 0x20,0x28,0x72,0x65,0x6E,0x64,0x65,0x72,0x69,0x6E,0x67,0x20,
- 0x73,0x6F,0x6E,0x67,0x20,0x74,0x6F,0x20,0x57,0x41,0x56,0x29,
- 0x3A,0x01,0x3E,0x50,0x3E,0x40,0x43,0x30,0x30,0x32,0x2D,0x20,
- 0x53,0x6F,0x6E,0x67,0x73,0x20,0x74,0x68,0x61,0x74,0x20,0x6A,
- 0x75,0x6D,0x70,0x20,0x62,0x61,0x63,0x6B,0x20,0x74,0x6F,0x20,
- 0x61,0x20,0x70,0x72,0x65,0x76,0x69,0x6F,0x75,0x73,0x20,0x70,
- 0x61,0x74,0x74,0x65,0x72,0x6E,0x20,0x77,0x69,0x6C,0x6C,0x20,
- 0x72,0x65,0x6E,0x64,0x65,0x72,0x20,0x66,0x6F,0x72,0x65,0x76,
- 0x65,0x72,0x20,0x61,0x6E,0x64,0x20,0x65,0x76,0x65,0x72,0x2C,
- 0x50,0x61,0x6E,0x64,0x20,0x79,0x6F,0x75,0x20,0x6E,0x65,0x65,
- 0x64,0x20,0x74,0x6F,0x20,0x70,0x72,0x65,0x73,0x73,0x20,0x61,
- 0x20,0x6B,0x65,0x79,0x20,0x6F,0x72,0x20,0x63,0x6C,0x69,0x63,
- 0x6B,0x20,0x74,0x68,0x65,0x20,0x6D,0x6F,0x75,0x73,0x65,0x20,
- 0x74,0x6F,0x20,0x61,0x62,0x6F,0x72,0x74,0x20,0x74,0x68,0x65,
- 0x20,0x72,0x65,0x6E,0x64,0x65,0x72,0x20,0x77,0x68,0x65,0x6E,
- 0x20,0x79,0x6F,0x75,0x20,0x77,0x61,0x6E,0x74,0x06,0x69,0x74,
- 0x20,0x74,0x6F,0x2E,0x06,0x3E,0x40,0x58,0x30,0x31,0x30,0x0C,
- 0x3E,0x40,0x43,0x30,0x30,0x31,0x56,0x69,0x64,0x65,0x6F,0x3A,
- 0x06,0x3E,0x40,0x43,0x30,0x30,0x32,0x50,0x3E,0x40,0x58,0x30,
- 0x31,0x30,0x2D,0x20,0x46,0x75,0x6C,0x6C,0x73,0x63,0x72,0x65,
- 0x65,0x6E,0x20,0x6D,0x6F,0x64,0x65,0x20,0x63,0x61,0x6E,0x20,
- 0x62,0x65,0x20,0x75,0x6E,0x62,0x65,0x61,0x72,0x61,0x62,0x6C,
- 0x79,0x20,0x73,0x6C,0x6F,0x77,0x20,0x6F,0x6E,0x20,0x61,0x20,
- 0x52,0x61,0x73,0x70,0x62,0x65,0x72,0x72,0x79,0x20,0x50,0x69,
- 0x20,0x28,0x65,0x76,0x65,0x6E,0x20,0x6F,0x6E,0x20,0x52,0x50,
- 0x69,0x20,0x34,0x29,0x01,0x3E,0x52,0x3E,0x40,0x58,0x30,0x31,
- 0x30,0x2D,0x20,0x4E,0x6F,0x74,0x20,0x61,0x20,0x62,0x75,0x67,
- 0x2C,0x20,0x62,0x75,0x74,0x20,0x69,0x66,0x20,0x79,0x6F,0x75,
- 0x72,0x20,0x6D,0x6F,0x6E,0x69,0x74,0x6F,0x72,0x27,0x73,0x20,
- 0x72,0x65,0x66,0x72,0x65,0x73,0x68,0x20,0x72,0x61,0x74,0x65,
- 0x20,0x69,0x73,0x20,0x6E,0x6F,0x74,0x20,0x73,0x65,0x74,0x20,
- 0x74,0x6F,0x20,0x36,0x30,0x48,0x7A,0x20,0x28,0x6F,0x72,0x20,
- 0x35,0x39,0x48,0x7A,0x29,0x4F,0x3E,0x40,0x58,0x30,0x32,0x31,
- 0x79,0x6F,0x75,0x20,0x6D,0x61,0x79,0x20,0x65,0x78,0x70,0x65,
- 0x72,0x69,0x65,0x6E,0x63,0x65,0x20,0x76,0x69,0x73,0x75,0x61,
- 0x6C,0x20,0x73,0x74,0x75,0x74,0x74,0x65,0x72,0x69,0x6E,0x67,
- 0x20,0x62,0x65,0x63,0x61,0x75,0x73,0x65,0x20,0x56,0x53,0x79,
- 0x6E,0x63,0x20,0x77,0x69,0x6C,0x6C,0x20,0x6E,0x6F,0x74,0x20,
- 0x62,0x65,0x20,0x75,0x73,0x65,0x64,0x20,0x74,0x68,0x65,0x6E,
- 0x2E,0x51,0x49,0x20,0x68,0x69,0x67,0x68,0x6C,0x79,0x20,0x72,
- 0x65,0x63,0x6F,0x6D,0x6D,0x65,0x6E,0x64,0x20,0x72,0x75,0x6E,
- 0x6E,0x69,0x6E,0x67,0x20,0x79,0x6F,0x75,0x72,0x20,0x6D,0x6F,
- 0x6E,0x69,0x74,0x6F,0x72,0x20,0x61,0x74,0x20,0x36,0x30,0x48,
- 0x7A,0x20,0x69,0x66,0x20,0x79,0x6F,0x75,0x27,0x72,0x65,0x20,
- 0x61,0x20,0x68,0x61,0x72,0x64,0x63,0x6F,0x72,0x65,0x20,0x75,
- 0x73,0x65,0x72,0x20,0x6F,0x66,0x20,0x74,0x68,0x69,0x73,0x08,
- 0x70,0x72,0x6F,0x67,0x72,0x61,0x6D,0x2E,0x00,0x03,0x45,0x4E,
- 0x44
+ 0x2A,0x2A,0x2A,0x2A,0x2A,0x0C,0x40,0x4C,0x4B,0x6E,0x6F,0x77,
+ 0x6E,0x20,0x62,0x75,0x67,0x73,0x06,0x3E,0x40,0x58,0x30,0x31,
+ 0x30,0x2C,0x3E,0x40,0x43,0x30,0x30,0x31,0x57,0x41,0x56,0x20,
+ 0x65,0x78,0x70,0x6F,0x72,0x74,0x69,0x6E,0x67,0x20,0x28,0x72,
+ 0x65,0x6E,0x64,0x65,0x72,0x69,0x6E,0x67,0x20,0x73,0x6F,0x6E,
+ 0x67,0x20,0x74,0x6F,0x20,0x57,0x41,0x56,0x29,0x3A,0x01,0x3E,
+ 0x50,0x3E,0x40,0x43,0x30,0x30,0x32,0x2D,0x20,0x53,0x6F,0x6E,
+ 0x67,0x73,0x20,0x74,0x68,0x61,0x74,0x20,0x6A,0x75,0x6D,0x70,
+ 0x20,0x62,0x61,0x63,0x6B,0x20,0x74,0x6F,0x20,0x61,0x20,0x70,
+ 0x72,0x65,0x76,0x69,0x6F,0x75,0x73,0x20,0x70,0x61,0x74,0x74,
+ 0x65,0x72,0x6E,0x20,0x77,0x69,0x6C,0x6C,0x20,0x72,0x65,0x6E,
+ 0x64,0x65,0x72,0x20,0x66,0x6F,0x72,0x65,0x76,0x65,0x72,0x20,
+ 0x61,0x6E,0x64,0x20,0x65,0x76,0x65,0x72,0x2C,0x50,0x61,0x6E,
+ 0x64,0x20,0x79,0x6F,0x75,0x20,0x6E,0x65,0x65,0x64,0x20,0x74,
+ 0x6F,0x20,0x70,0x72,0x65,0x73,0x73,0x20,0x61,0x20,0x6B,0x65,
+ 0x79,0x20,0x6F,0x72,0x20,0x63,0x6C,0x69,0x63,0x6B,0x20,0x74,
+ 0x68,0x65,0x20,0x6D,0x6F,0x75,0x73,0x65,0x20,0x74,0x6F,0x20,
+ 0x61,0x62,0x6F,0x72,0x74,0x20,0x74,0x68,0x65,0x20,0x72,0x65,
+ 0x6E,0x64,0x65,0x72,0x20,0x77,0x68,0x65,0x6E,0x20,0x79,0x6F,
+ 0x75,0x20,0x77,0x61,0x6E,0x74,0x06,0x69,0x74,0x20,0x74,0x6F,
+ 0x2E,0x06,0x3E,0x40,0x58,0x30,0x31,0x30,0x0C,0x3E,0x40,0x43,
+ 0x30,0x30,0x31,0x56,0x69,0x64,0x65,0x6F,0x3A,0x06,0x3E,0x40,
+ 0x43,0x30,0x30,0x32,0x50,0x3E,0x40,0x58,0x30,0x31,0x30,0x2D,
+ 0x20,0x46,0x75,0x6C,0x6C,0x73,0x63,0x72,0x65,0x65,0x6E,0x20,
+ 0x6D,0x6F,0x64,0x65,0x20,0x63,0x61,0x6E,0x20,0x62,0x65,0x20,
+ 0x75,0x6E,0x62,0x65,0x61,0x72,0x61,0x62,0x6C,0x79,0x20,0x73,
+ 0x6C,0x6F,0x77,0x20,0x6F,0x6E,0x20,0x61,0x20,0x52,0x61,0x73,
+ 0x70,0x62,0x65,0x72,0x72,0x79,0x20,0x50,0x69,0x20,0x28,0x65,
+ 0x76,0x65,0x6E,0x20,0x6F,0x6E,0x20,0x52,0x50,0x69,0x20,0x34,
+ 0x29,0x01,0x3E,0x52,0x3E,0x40,0x58,0x30,0x31,0x30,0x2D,0x20,
+ 0x4E,0x6F,0x74,0x20,0x61,0x20,0x62,0x75,0x67,0x2C,0x20,0x62,
+ 0x75,0x74,0x20,0x69,0x66,0x20,0x79,0x6F,0x75,0x72,0x20,0x6D,
+ 0x6F,0x6E,0x69,0x74,0x6F,0x72,0x27,0x73,0x20,0x72,0x65,0x66,
+ 0x72,0x65,0x73,0x68,0x20,0x72,0x61,0x74,0x65,0x20,0x69,0x73,
+ 0x20,0x6E,0x6F,0x74,0x20,0x73,0x65,0x74,0x20,0x74,0x6F,0x20,
+ 0x36,0x30,0x48,0x7A,0x20,0x28,0x6F,0x72,0x20,0x35,0x39,0x48,
+ 0x7A,0x29,0x4F,0x3E,0x40,0x58,0x30,0x32,0x31,0x79,0x6F,0x75,
+ 0x20,0x6D,0x61,0x79,0x20,0x65,0x78,0x70,0x65,0x72,0x69,0x65,
+ 0x6E,0x63,0x65,0x20,0x76,0x69,0x73,0x75,0x61,0x6C,0x20,0x73,
+ 0x74,0x75,0x74,0x74,0x65,0x72,0x69,0x6E,0x67,0x20,0x62,0x65,
+ 0x63,0x61,0x75,0x73,0x65,0x20,0x56,0x53,0x79,0x6E,0x63,0x20,
+ 0x77,0x69,0x6C,0x6C,0x20,0x6E,0x6F,0x74,0x20,0x62,0x65,0x20,
+ 0x75,0x73,0x65,0x64,0x20,0x74,0x68,0x65,0x6E,0x2E,0x51,0x49,
+ 0x20,0x68,0x69,0x67,0x68,0x6C,0x79,0x20,0x72,0x65,0x63,0x6F,
+ 0x6D,0x6D,0x65,0x6E,0x64,0x20,0x72,0x75,0x6E,0x6E,0x69,0x6E,
+ 0x67,0x20,0x79,0x6F,0x75,0x72,0x20,0x6D,0x6F,0x6E,0x69,0x74,
+ 0x6F,0x72,0x20,0x61,0x74,0x20,0x36,0x30,0x48,0x7A,0x20,0x69,
+ 0x66,0x20,0x79,0x6F,0x75,0x27,0x72,0x65,0x20,0x61,0x20,0x68,
+ 0x61,0x72,0x64,0x63,0x6F,0x72,0x65,0x20,0x75,0x73,0x65,0x72,
+ 0x20,0x6F,0x66,0x20,0x74,0x68,0x69,0x73,0x08,0x70,0x72,0x6F,
+ 0x67,0x72,0x61,0x6D,0x2E,0x00,0x03,0x45,0x4E,0x44
};
#endif
--- /dev/null
+++ b/src/libflac/COPYING.txt
@@ -1,0 +1,29 @@
+Copyright (C) 2000-2009 Josh Coalson
+Copyright (C) 2011-2016 Xiph.Org Foundation
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+- Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+
+- Neither the name of the Xiph.org Foundation nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--- /dev/null
+++ b/src/libflac/FLAC/callback.h
@@ -1,0 +1,185 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2004-2009 Josh Coalson
+ * Copyright (C) 2011-2016 Xiph.Org Foundation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__CALLBACK_H
+#define FLAC__CALLBACK_H
+
+#include "ordinals.h"
+#include <stdlib.h> /* for size_t */
+
+/** \file include/FLAC/callback.h
+ *
+ * \brief
+ * This module defines the structures for describing I/O callbacks
+ * to the other FLAC interfaces.
+ *
+ * See the detailed documentation for callbacks in the
+ * \link flac_callbacks callbacks \endlink module.
+ */
+
+/** \defgroup flac_callbacks FLAC/callback.h: I/O callback structures
+ * \ingroup flac
+ *
+ * \brief
+ * This module defines the structures for describing I/O callbacks
+ * to the other FLAC interfaces.
+ *
+ * The purpose of the I/O callback functions is to create a common way
+ * for the metadata interfaces to handle I/O.
+ *
+ * Originally the metadata interfaces required filenames as the way of
+ * specifying FLAC files to operate on. This is problematic in some
+ * environments so there is an additional option to specify a set of
+ * callbacks for doing I/O on the FLAC file, instead of the filename.
+ *
+ * In addition to the callbacks, a FLAC__IOHandle type is defined as an
+ * opaque structure for a data source.
+ *
+ * The callback function prototypes are similar (but not identical) to the
+ * stdio functions fread, fwrite, fseek, ftell, feof, and fclose. If you use
+ * stdio streams to implement the callbacks, you can pass fread, fwrite, and
+ * fclose anywhere a FLAC__IOCallback_Read, FLAC__IOCallback_Write, or
+ * FLAC__IOCallback_Close is required, and a FILE* anywhere a FLAC__IOHandle
+ * is required. \warning You generally CANNOT directly use fseek or ftell
+ * for FLAC__IOCallback_Seek or FLAC__IOCallback_Tell since on most systems
+ * these use 32-bit offsets and FLAC requires 64-bit offsets to deal with
+ * large files. You will have to find an equivalent function (e.g. ftello),
+ * or write a wrapper. The same is true for feof() since this is usually
+ * implemented as a macro, not as a function whose address can be taken.
+ *
+ * \{
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** This is the opaque handle type used by the callbacks. Typically
+ * this is a \c FILE* or address of a file descriptor.
+ */
+typedef void* FLAC__IOHandle;
+
+/** Signature for the read callback.
+ * The signature and semantics match POSIX fread() implementations
+ * and can generally be used interchangeably.
+ *
+ * \param ptr The address of the read buffer.
+ * \param size The size of the records to be read.
+ * \param nmemb The number of records to be read.
+ * \param handle The handle to the data source.
+ * \retval size_t
+ * The number of records read.
+ */
+typedef size_t (*FLAC__IOCallback_Read) (void *ptr, size_t size, size_t nmemb, FLAC__IOHandle handle);
+
+/** Signature for the write callback.
+ * The signature and semantics match POSIX fwrite() implementations
+ * and can generally be used interchangeably.
+ *
+ * \param ptr The address of the write buffer.
+ * \param size The size of the records to be written.
+ * \param nmemb The number of records to be written.
+ * \param handle The handle to the data source.
+ * \retval size_t
+ * The number of records written.
+ */
+typedef size_t (*FLAC__IOCallback_Write) (const void *ptr, size_t size, size_t nmemb, FLAC__IOHandle handle);
+
+/** Signature for the seek callback.
+ * The signature and semantics mostly match POSIX fseek() WITH ONE IMPORTANT
+ * EXCEPTION: the offset is a 64-bit type whereas fseek() is generally 'long'
+ * and 32-bits wide.
+ *
+ * \param handle The handle to the data source.
+ * \param offset The new position, relative to \a whence
+ * \param whence \c SEEK_SET, \c SEEK_CUR, or \c SEEK_END
+ * \retval int
+ * \c 0 on success, \c -1 on error.
+ */
+typedef int (*FLAC__IOCallback_Seek) (FLAC__IOHandle handle, FLAC__int64 offset, int whence);
+
+/** Signature for the tell callback.
+ * The signature and semantics mostly match POSIX ftell() WITH ONE IMPORTANT
+ * EXCEPTION: the offset is a 64-bit type whereas ftell() is generally 'long'
+ * and 32-bits wide.
+ *
+ * \param handle The handle to the data source.
+ * \retval FLAC__int64
+ * The current position on success, \c -1 on error.
+ */
+typedef FLAC__int64 (*FLAC__IOCallback_Tell) (FLAC__IOHandle handle);
+
+/** Signature for the EOF callback.
+ * The signature and semantics mostly match POSIX feof() but WATCHOUT:
+ * on many systems, feof() is a macro, so in this case a wrapper function
+ * must be provided instead.
+ *
+ * \param handle The handle to the data source.
+ * \retval int
+ * \c 0 if not at end of file, nonzero if at end of file.
+ */
+typedef int (*FLAC__IOCallback_Eof) (FLAC__IOHandle handle);
+
+/** Signature for the close callback.
+ * The signature and semantics match POSIX fclose() implementations
+ * and can generally be used interchangeably.
+ *
+ * \param handle The handle to the data source.
+ * \retval int
+ * \c 0 on success, \c EOF on error.
+ */
+typedef int (*FLAC__IOCallback_Close) (FLAC__IOHandle handle);
+
+/** A structure for holding a set of callbacks.
+ * Each FLAC interface that requires a FLAC__IOCallbacks structure will
+ * describe which of the callbacks are required. The ones that are not
+ * required may be set to NULL.
+ *
+ * If the seek requirement for an interface is optional, you can signify that
+ * a data source is not seekable by setting the \a seek field to \c NULL.
+ */
+typedef struct {
+ FLAC__IOCallback_Read read;
+ FLAC__IOCallback_Write write;
+ FLAC__IOCallback_Seek seek;
+ FLAC__IOCallback_Tell tell;
+ FLAC__IOCallback_Eof eof;
+ FLAC__IOCallback_Close close;
+} FLAC__IOCallbacks;
+
+/* \} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
+++ b/src/libflac/FLAC/export.h
@@ -1,0 +1,70 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000-2009 Josh Coalson
+ * Copyright (C) 2011-2016 Xiph.Org Foundation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__EXPORT_H
+#define FLAC__EXPORT_H
+
+/** \file include/FLAC/export.h
+ *
+ * \brief
+ * This module contains #defines and symbols for exporting function
+ * calls, and providing version information and compiled-in features.
+ *
+ * See the \link flac_export export \endlink module.
+ */
+
+/** \defgroup flac_export FLAC/export.h: export symbols
+ * \ingroup flac
+ *
+ * \brief
+ * This module contains #defines and symbols for exporting function
+ * calls, and providing version information and compiled-in features.
+ *
+ * If you are compiling with MSVC and will link to the static library
+ * (libFLAC.lib) you should define FLAC__NO_DLL in your project to
+ * make sure the symbols are exported properly.
+ *
+ * \{
+ */
+
+#define FLAC_API
+
+/** These #defines will mirror the libtool-based library version number, see
+ * http://www.gnu.org/software/libtool/manual/libtool.html#Libtool-versioning
+ */
+#define FLAC_API_VERSION_CURRENT 11
+#define FLAC_API_VERSION_REVISION 0 /**< see above */
+#define FLAC_API_VERSION_AGE 3 /**< see above */
+
+/* \} */
+
+#endif
--- /dev/null
+++ b/src/libflac/FLAC/format.h
@@ -1,0 +1,1025 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000-2009 Josh Coalson
+ * Copyright (C) 2011-2016 Xiph.Org Foundation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__FORMAT_H
+#define FLAC__FORMAT_H
+
+#include "export.h"
+#include "ordinals.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \file include/FLAC/format.h
+ *
+ * \brief
+ * This module contains structure definitions for the representation
+ * of FLAC format components in memory. These are the basic
+ * structures used by the rest of the interfaces.
+ *
+ * See the detailed documentation in the
+ * \link flac_format format \endlink module.
+ */
+
+/** \defgroup flac_format FLAC/format.h: format components
+ * \ingroup flac
+ *
+ * \brief
+ * This module contains structure definitions for the representation
+ * of FLAC format components in memory. These are the basic
+ * structures used by the rest of the interfaces.
+ *
+ * First, you should be familiar with the
+ * <A HREF="../format.html">FLAC format</A>. Many of the values here
+ * follow directly from the specification. As a user of libFLAC, the
+ * interesting parts really are the structures that describe the frame
+ * header and metadata blocks.
+ *
+ * The format structures here are very primitive, designed to store
+ * information in an efficient way. Reading information from the
+ * structures is easy but creating or modifying them directly is
+ * more complex. For the most part, as a user of a library, editing
+ * is not necessary; however, for metadata blocks it is, so there are
+ * convenience functions provided in the \link flac_metadata metadata
+ * module \endlink to simplify the manipulation of metadata blocks.
+ *
+ * \note
+ * It's not the best convention, but symbols ending in _LEN are in bits
+ * and _LENGTH are in bytes. _LENGTH symbols are \#defines instead of
+ * global variables because they are usually used when declaring byte
+ * arrays and some compilers require compile-time knowledge of array
+ * sizes when declared on the stack.
+ *
+ * \{
+ */
+
+
+/*
+ Most of the values described in this file are defined by the FLAC
+ format specification. There is nothing to tune here.
+*/
+
+/** The largest legal metadata type code. */
+#define FLAC__MAX_METADATA_TYPE_CODE (126u)
+
+/** The minimum block size, in samples, permitted by the format. */
+#define FLAC__MIN_BLOCK_SIZE (16u)
+
+/** The maximum block size, in samples, permitted by the format. */
+#define FLAC__MAX_BLOCK_SIZE (65535u)
+
+/** The maximum block size, in samples, permitted by the FLAC subset for
+ * sample rates up to 48kHz. */
+#define FLAC__SUBSET_MAX_BLOCK_SIZE_48000HZ (4608u)
+
+/** The maximum number of channels permitted by the format. */
+#define FLAC__MAX_CHANNELS (8u)
+
+/** The minimum sample resolution permitted by the format. */
+#define FLAC__MIN_BITS_PER_SAMPLE (4u)
+
+/** The maximum sample resolution permitted by the format. */
+#define FLAC__MAX_BITS_PER_SAMPLE (32u)
+
+/** The maximum sample resolution permitted by libFLAC.
+ *
+ * \warning
+ * FLAC__MAX_BITS_PER_SAMPLE is the limit of the FLAC format. However,
+ * the reference encoder/decoder is currently limited to 24 bits because
+ * of prevalent 32-bit math, so make sure and use this value when
+ * appropriate.
+ */
+#define FLAC__REFERENCE_CODEC_MAX_BITS_PER_SAMPLE (24u)
+
+/** The maximum sample rate permitted by the format. The value is
+ * ((2 ^ 16) - 1) * 10; see <A HREF="../format.html">FLAC format</A>
+ * as to why.
+ */
+#define FLAC__MAX_SAMPLE_RATE (655350u)
+
+/** The maximum LPC order permitted by the format. */
+#define FLAC__MAX_LPC_ORDER (32u)
+
+/** The maximum LPC order permitted by the FLAC subset for sample rates
+ * up to 48kHz. */
+#define FLAC__SUBSET_MAX_LPC_ORDER_48000HZ (12u)
+
+/** The minimum quantized linear predictor coefficient precision
+ * permitted by the format.
+ */
+#define FLAC__MIN_QLP_COEFF_PRECISION (5u)
+
+/** The maximum quantized linear predictor coefficient precision
+ * permitted by the format.
+ */
+#define FLAC__MAX_QLP_COEFF_PRECISION (15u)
+
+/** The maximum order of the fixed predictors permitted by the format. */
+#define FLAC__MAX_FIXED_ORDER (4u)
+
+/** The maximum Rice partition order permitted by the format. */
+#define FLAC__MAX_RICE_PARTITION_ORDER (15u)
+
+/** The maximum Rice partition order permitted by the FLAC Subset. */
+#define FLAC__SUBSET_MAX_RICE_PARTITION_ORDER (8u)
+
+/** The version string of the release, stamped onto the libraries and binaries.
+ *
+ * \note
+ * This does not correspond to the shared library version number, which
+ * is used to determine binary compatibility.
+ */
+extern FLAC_API const char *FLAC__VERSION_STRING;
+
+/** The vendor string inserted by the encoder into the VORBIS_COMMENT block.
+ * This is a NUL-terminated ASCII string; when inserted into the
+ * VORBIS_COMMENT the trailing null is stripped.
+ */
+extern FLAC_API const char *FLAC__VENDOR_STRING;
+
+/** The byte string representation of the beginning of a FLAC stream. */
+extern FLAC_API const FLAC__byte FLAC__STREAM_SYNC_STRING[4]; /* = "fLaC" */
+
+/** The 32-bit integer big-endian representation of the beginning of
+ * a FLAC stream.
+ */
+extern FLAC_API const uint32_t FLAC__STREAM_SYNC; /* = 0x664C6143 */
+
+/** The length of the FLAC signature in bits. */
+extern FLAC_API const uint32_t FLAC__STREAM_SYNC_LEN; /* = 32 bits */
+
+/** The length of the FLAC signature in bytes. */
+#define FLAC__STREAM_SYNC_LENGTH (4u)
+
+
+/*****************************************************************************
+ *
+ * Subframe structures
+ *
+ *****************************************************************************/
+
+/*****************************************************************************/
+
+/** An enumeration of the available entropy coding methods. */
+typedef enum {
+ FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE = 0,
+ /**< Residual is coded by partitioning into contexts, each with it's own
+ * 4-bit Rice parameter. */
+
+ FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2 = 1
+ /**< Residual is coded by partitioning into contexts, each with it's own
+ * 5-bit Rice parameter. */
+} FLAC__EntropyCodingMethodType;
+
+/** Maps a FLAC__EntropyCodingMethodType to a C string.
+ *
+ * Using a FLAC__EntropyCodingMethodType as the index to this array will
+ * give the string equivalent. The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__EntropyCodingMethodTypeString[];
+
+
+/** Contents of a Rice partitioned residual
+ */
+typedef struct {
+
+ uint32_t *parameters;
+ /**< The Rice parameters for each context. */
+
+ uint32_t *raw_bits;
+ /**< Widths for escape-coded partitions. Will be non-zero for escaped
+ * partitions and zero for unescaped partitions.
+ */
+
+ uint32_t capacity_by_order;
+ /**< The capacity of the \a parameters and \a raw_bits arrays
+ * specified as an order, i.e. the number of array elements
+ * allocated is 2 ^ \a capacity_by_order.
+ */
+} FLAC__EntropyCodingMethod_PartitionedRiceContents;
+
+/** Header for a Rice partitioned residual. (c.f. <A HREF="../format.html#partitioned_rice">format specification</A>)
+ */
+typedef struct {
+
+ uint32_t order;
+ /**< The partition order, i.e. # of contexts = 2 ^ \a order. */
+
+ const FLAC__EntropyCodingMethod_PartitionedRiceContents *contents;
+ /**< The context's Rice parameters and/or raw bits. */
+
+} FLAC__EntropyCodingMethod_PartitionedRice;
+
+extern FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN; /**< == 4 (bits) */
+extern FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN; /**< == 4 (bits) */
+extern FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_PARAMETER_LEN; /**< == 5 (bits) */
+extern FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_RAW_LEN; /**< == 5 (bits) */
+
+extern FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER;
+/**< == (1<<FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN)-1 */
+extern FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_ESCAPE_PARAMETER;
+/**< == (1<<FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_PARAMETER_LEN)-1 */
+
+/** Header for the entropy coding method. (c.f. <A HREF="../format.html#residual">format specification</A>)
+ */
+typedef struct {
+ FLAC__EntropyCodingMethodType type;
+ union {
+ FLAC__EntropyCodingMethod_PartitionedRice partitioned_rice;
+ } data;
+} FLAC__EntropyCodingMethod;
+
+extern FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_TYPE_LEN; /**< == 2 (bits) */
+
+/*****************************************************************************/
+
+/** An enumeration of the available subframe types. */
+typedef enum {
+ FLAC__SUBFRAME_TYPE_CONSTANT = 0, /**< constant signal */
+ FLAC__SUBFRAME_TYPE_VERBATIM = 1, /**< uncompressed signal */
+ FLAC__SUBFRAME_TYPE_FIXED = 2, /**< fixed polynomial prediction */
+ FLAC__SUBFRAME_TYPE_LPC = 3 /**< linear prediction */
+} FLAC__SubframeType;
+
+/** Maps a FLAC__SubframeType to a C string.
+ *
+ * Using a FLAC__SubframeType as the index to this array will
+ * give the string equivalent. The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__SubframeTypeString[];
+
+
+/** CONSTANT subframe. (c.f. <A HREF="../format.html#subframe_constant">format specification</A>)
+ */
+typedef struct {
+ FLAC__int32 value; /**< The constant signal value. */
+} FLAC__Subframe_Constant;
+
+
+/** VERBATIM subframe. (c.f. <A HREF="../format.html#subframe_verbatim">format specification</A>)
+ */
+typedef struct {
+ const FLAC__int32 *data; /**< A pointer to verbatim signal. */
+} FLAC__Subframe_Verbatim;
+
+
+/** FIXED subframe. (c.f. <A HREF="../format.html#subframe_fixed">format specification</A>)
+ */
+typedef struct {
+ FLAC__EntropyCodingMethod entropy_coding_method;
+ /**< The residual coding method. */
+
+ uint32_t order;
+ /**< The polynomial order. */
+
+ FLAC__int32 warmup[FLAC__MAX_FIXED_ORDER];
+ /**< Warmup samples to prime the predictor, length == order. */
+
+ const FLAC__int32 *residual;
+ /**< The residual signal, length == (blocksize minus order) samples. */
+} FLAC__Subframe_Fixed;
+
+
+/** LPC subframe. (c.f. <A HREF="../format.html#subframe_lpc">format specification</A>)
+ */
+typedef struct {
+ FLAC__EntropyCodingMethod entropy_coding_method;
+ /**< The residual coding method. */
+
+ uint32_t order;
+ /**< The FIR order. */
+
+ uint32_t qlp_coeff_precision;
+ /**< Quantized FIR filter coefficient precision in bits. */
+
+ int quantization_level;
+ /**< The qlp coeff shift needed. */
+
+ FLAC__int32 qlp_coeff[FLAC__MAX_LPC_ORDER];
+ /**< FIR filter coefficients. */
+
+ FLAC__int32 warmup[FLAC__MAX_LPC_ORDER];
+ /**< Warmup samples to prime the predictor, length == order. */
+
+ const FLAC__int32 *residual;
+ /**< The residual signal, length == (blocksize minus order) samples. */
+} FLAC__Subframe_LPC;
+
+extern FLAC_API const uint32_t FLAC__SUBFRAME_LPC_QLP_COEFF_PRECISION_LEN; /**< == 4 (bits) */
+extern FLAC_API const uint32_t FLAC__SUBFRAME_LPC_QLP_SHIFT_LEN; /**< == 5 (bits) */
+
+
+/** FLAC subframe structure. (c.f. <A HREF="../format.html#subframe">format specification</A>)
+ */
+typedef struct {
+ FLAC__SubframeType type;
+ union {
+ FLAC__Subframe_Constant constant;
+ FLAC__Subframe_Fixed fixed;
+ FLAC__Subframe_LPC lpc;
+ FLAC__Subframe_Verbatim verbatim;
+ } data;
+ uint32_t wasted_bits;
+} FLAC__Subframe;
+
+/** == 1 (bit)
+ *
+ * This used to be a zero-padding bit (hence the name
+ * FLAC__SUBFRAME_ZERO_PAD_LEN) but is now a reserved bit. It still has a
+ * mandatory value of \c 0 but in the future may take on the value \c 0 or \c 1
+ * to mean something else.
+ */
+extern FLAC_API const uint32_t FLAC__SUBFRAME_ZERO_PAD_LEN;
+extern FLAC_API const uint32_t FLAC__SUBFRAME_TYPE_LEN; /**< == 6 (bits) */
+extern FLAC_API const uint32_t FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN; /**< == 1 (bit) */
+
+extern FLAC_API const uint32_t FLAC__SUBFRAME_TYPE_CONSTANT_BYTE_ALIGNED_MASK; /**< = 0x00 */
+extern FLAC_API const uint32_t FLAC__SUBFRAME_TYPE_VERBATIM_BYTE_ALIGNED_MASK; /**< = 0x02 */
+extern FLAC_API const uint32_t FLAC__SUBFRAME_TYPE_FIXED_BYTE_ALIGNED_MASK; /**< = 0x10 */
+extern FLAC_API const uint32_t FLAC__SUBFRAME_TYPE_LPC_BYTE_ALIGNED_MASK; /**< = 0x40 */
+
+/*****************************************************************************/
+
+
+/*****************************************************************************
+ *
+ * Frame structures
+ *
+ *****************************************************************************/
+
+/** An enumeration of the available channel assignments. */
+typedef enum {
+ FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT = 0, /**< independent channels */
+ FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE = 1, /**< left+side stereo */
+ FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE = 2, /**< right+side stereo */
+ FLAC__CHANNEL_ASSIGNMENT_MID_SIDE = 3 /**< mid+side stereo */
+} FLAC__ChannelAssignment;
+
+/** Maps a FLAC__ChannelAssignment to a C string.
+ *
+ * Using a FLAC__ChannelAssignment as the index to this array will
+ * give the string equivalent. The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__ChannelAssignmentString[];
+
+/** An enumeration of the possible frame numbering methods. */
+typedef enum {
+ FLAC__FRAME_NUMBER_TYPE_FRAME_NUMBER, /**< number contains the frame number */
+ FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER /**< number contains the sample number of first sample in frame */
+} FLAC__FrameNumberType;
+
+/** Maps a FLAC__FrameNumberType to a C string.
+ *
+ * Using a FLAC__FrameNumberType as the index to this array will
+ * give the string equivalent. The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__FrameNumberTypeString[];
+
+
+/** FLAC frame header structure. (c.f. <A HREF="../format.html#frame_header">format specification</A>)
+ */
+typedef struct {
+ uint32_t blocksize;
+ /**< The number of samples per subframe. */
+
+ uint32_t sample_rate;
+ /**< The sample rate in Hz. */
+
+ uint32_t channels;
+ /**< The number of channels (== number of subframes). */
+
+ FLAC__ChannelAssignment channel_assignment;
+ /**< The channel assignment for the frame. */
+
+ uint32_t bits_per_sample;
+ /**< The sample resolution. */
+
+ FLAC__FrameNumberType number_type;
+ /**< The numbering scheme used for the frame. As a convenience, the
+ * decoder will always convert a frame number to a sample number because
+ * the rules are complex. */
+
+ union {
+ FLAC__uint32 frame_number;
+ FLAC__uint64 sample_number;
+ } number;
+ /**< The frame number or sample number of first sample in frame;
+ * use the \a number_type value to determine which to use. */
+
+ FLAC__uint8 crc;
+ /**< CRC-8 (polynomial = x^8 + x^2 + x^1 + x^0, initialized with 0)
+ * of the raw frame header bytes, meaning everything before the CRC byte
+ * including the sync code.
+ */
+} FLAC__FrameHeader;
+
+extern FLAC_API const uint32_t FLAC__FRAME_HEADER_SYNC; /**< == 0x3ffe; the frame header sync code */
+extern FLAC_API const uint32_t FLAC__FRAME_HEADER_SYNC_LEN; /**< == 14 (bits) */
+extern FLAC_API const uint32_t FLAC__FRAME_HEADER_RESERVED_LEN; /**< == 1 (bits) */
+extern FLAC_API const uint32_t FLAC__FRAME_HEADER_BLOCKING_STRATEGY_LEN; /**< == 1 (bits) */
+extern FLAC_API const uint32_t FLAC__FRAME_HEADER_BLOCK_SIZE_LEN; /**< == 4 (bits) */
+extern FLAC_API const uint32_t FLAC__FRAME_HEADER_SAMPLE_RATE_LEN; /**< == 4 (bits) */
+extern FLAC_API const uint32_t FLAC__FRAME_HEADER_CHANNEL_ASSIGNMENT_LEN; /**< == 4 (bits) */
+extern FLAC_API const uint32_t FLAC__FRAME_HEADER_BITS_PER_SAMPLE_LEN; /**< == 3 (bits) */
+extern FLAC_API const uint32_t FLAC__FRAME_HEADER_ZERO_PAD_LEN; /**< == 1 (bit) */
+extern FLAC_API const uint32_t FLAC__FRAME_HEADER_CRC_LEN; /**< == 8 (bits) */
+
+
+/** FLAC frame footer structure. (c.f. <A HREF="../format.html#frame_footer">format specification</A>)
+ */
+typedef struct {
+ FLAC__uint16 crc;
+ /**< CRC-16 (polynomial = x^16 + x^15 + x^2 + x^0, initialized with
+ * 0) of the bytes before the crc, back to and including the frame header
+ * sync code.
+ */
+} FLAC__FrameFooter;
+
+extern FLAC_API const uint32_t FLAC__FRAME_FOOTER_CRC_LEN; /**< == 16 (bits) */
+
+
+/** FLAC frame structure. (c.f. <A HREF="../format.html#frame">format specification</A>)
+ */
+typedef struct {
+ FLAC__FrameHeader header;
+ FLAC__Subframe subframes[FLAC__MAX_CHANNELS];
+ FLAC__FrameFooter footer;
+} FLAC__Frame;
+
+/*****************************************************************************/
+
+
+/*****************************************************************************
+ *
+ * Meta-data structures
+ *
+ *****************************************************************************/
+
+/** An enumeration of the available metadata block types. */
+typedef enum {
+
+ FLAC__METADATA_TYPE_STREAMINFO = 0,
+ /**< <A HREF="../format.html#metadata_block_streaminfo">STREAMINFO</A> block */
+
+ FLAC__METADATA_TYPE_PADDING = 1,
+ /**< <A HREF="../format.html#metadata_block_padding">PADDING</A> block */
+
+ FLAC__METADATA_TYPE_APPLICATION = 2,
+ /**< <A HREF="../format.html#metadata_block_application">APPLICATION</A> block */
+
+ FLAC__METADATA_TYPE_SEEKTABLE = 3,
+ /**< <A HREF="../format.html#metadata_block_seektable">SEEKTABLE</A> block */
+
+ FLAC__METADATA_TYPE_VORBIS_COMMENT = 4,
+ /**< <A HREF="../format.html#metadata_block_vorbis_comment">VORBISCOMMENT</A> block (a.k.a. FLAC tags) */
+
+ FLAC__METADATA_TYPE_CUESHEET = 5,
+ /**< <A HREF="../format.html#metadata_block_cuesheet">CUESHEET</A> block */
+
+ FLAC__METADATA_TYPE_PICTURE = 6,
+ /**< <A HREF="../format.html#metadata_block_picture">PICTURE</A> block */
+
+ FLAC__METADATA_TYPE_UNDEFINED = 7,
+ /**< marker to denote beginning of undefined type range; this number will increase as new metadata types are added */
+
+ FLAC__MAX_METADATA_TYPE = FLAC__MAX_METADATA_TYPE_CODE,
+ /**< No type will ever be greater than this. There is not enough room in the protocol block. */
+} FLAC__MetadataType;
+
+/** Maps a FLAC__MetadataType to a C string.
+ *
+ * Using a FLAC__MetadataType as the index to this array will
+ * give the string equivalent. The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__MetadataTypeString[];
+
+
+/** FLAC STREAMINFO structure. (c.f. <A HREF="../format.html#metadata_block_streaminfo">format specification</A>)
+ */
+typedef struct {
+ uint32_t min_blocksize, max_blocksize;
+ uint32_t min_framesize, max_framesize;
+ uint32_t sample_rate;
+ uint32_t channels;
+ uint32_t bits_per_sample;
+ FLAC__uint64 total_samples;
+ FLAC__byte md5sum[16];
+} FLAC__StreamMetadata_StreamInfo;
+
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN; /**< == 16 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN; /**< == 16 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN; /**< == 24 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN; /**< == 24 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN; /**< == 20 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN; /**< == 3 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN; /**< == 5 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN; /**< == 36 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_MD5SUM_LEN; /**< == 128 (bits) */
+
+/** The total stream length of the STREAMINFO block in bytes. */
+#define FLAC__STREAM_METADATA_STREAMINFO_LENGTH (34u)
+
+/** FLAC PADDING structure. (c.f. <A HREF="../format.html#metadata_block_padding">format specification</A>)
+ */
+typedef struct {
+ int dummy;
+ /**< Conceptually this is an empty struct since we don't store the
+ * padding bytes. Empty structs are not allowed by some C compilers,
+ * hence the dummy.
+ */
+} FLAC__StreamMetadata_Padding;
+
+
+/** FLAC APPLICATION structure. (c.f. <A HREF="../format.html#metadata_block_application">format specification</A>)
+ */
+typedef struct {
+ FLAC__byte id[4];
+ FLAC__byte *data;
+} FLAC__StreamMetadata_Application;
+
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_APPLICATION_ID_LEN; /**< == 32 (bits) */
+
+/** SeekPoint structure used in SEEKTABLE blocks. (c.f. <A HREF="../format.html#seekpoint">format specification</A>)
+ */
+typedef struct {
+ FLAC__uint64 sample_number;
+ /**< The sample number of the target frame. */
+
+ FLAC__uint64 stream_offset;
+ /**< The offset, in bytes, of the target frame with respect to
+ * beginning of the first frame. */
+
+ uint32_t frame_samples;
+ /**< The number of samples in the target frame. */
+} FLAC__StreamMetadata_SeekPoint;
+
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_SEEKPOINT_SAMPLE_NUMBER_LEN; /**< == 64 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_SEEKPOINT_STREAM_OFFSET_LEN; /**< == 64 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_SEEKPOINT_FRAME_SAMPLES_LEN; /**< == 16 (bits) */
+
+/** The total stream length of a seek point in bytes. */
+#define FLAC__STREAM_METADATA_SEEKPOINT_LENGTH (18u)
+
+/** The value used in the \a sample_number field of
+ * FLAC__StreamMetadataSeekPoint used to indicate a placeholder
+ * point (== 0xffffffffffffffff).
+ */
+extern FLAC_API const FLAC__uint64 FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER;
+
+
+/** FLAC SEEKTABLE structure. (c.f. <A HREF="../format.html#metadata_block_seektable">format specification</A>)
+ *
+ * \note From the format specification:
+ * - The seek points must be sorted by ascending sample number.
+ * - Each seek point's sample number must be the first sample of the
+ * target frame.
+ * - Each seek point's sample number must be unique within the table.
+ * - Existence of a SEEKTABLE block implies a correct setting of
+ * total_samples in the stream_info block.
+ * - Behavior is undefined when more than one SEEKTABLE block is
+ * present in a stream.
+ */
+typedef struct {
+ uint32_t num_points;
+ FLAC__StreamMetadata_SeekPoint *points;
+} FLAC__StreamMetadata_SeekTable;
+
+
+/** Vorbis comment entry structure used in VORBIS_COMMENT blocks. (c.f. <A HREF="../format.html#metadata_block_vorbis_comment">format specification</A>)
+ *
+ * For convenience, the APIs maintain a trailing NUL character at the end of
+ * \a entry which is not counted toward \a length, i.e.
+ * \code strlen(entry) == length \endcode
+ */
+typedef struct {
+ FLAC__uint32 length;
+ FLAC__byte *entry;
+} FLAC__StreamMetadata_VorbisComment_Entry;
+
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN; /**< == 32 (bits) */
+
+
+/** FLAC VORBIS_COMMENT structure. (c.f. <A HREF="../format.html#metadata_block_vorbis_comment">format specification</A>)
+ */
+typedef struct {
+ FLAC__StreamMetadata_VorbisComment_Entry vendor_string;
+ FLAC__uint32 num_comments;
+ FLAC__StreamMetadata_VorbisComment_Entry *comments;
+} FLAC__StreamMetadata_VorbisComment;
+
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN; /**< == 32 (bits) */
+
+
+/** FLAC CUESHEET track index structure. (See the
+ * <A HREF="../format.html#cuesheet_track_index">format specification</A> for
+ * the full description of each field.)
+ */
+typedef struct {
+ FLAC__uint64 offset;
+ /**< Offset in samples, relative to the track offset, of the index
+ * point.
+ */
+
+ FLAC__byte number;
+ /**< The index point number. */
+} FLAC__StreamMetadata_CueSheet_Index;
+
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN; /**< == 64 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN; /**< == 8 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN; /**< == 3*8 (bits) */
+
+
+/** FLAC CUESHEET track structure. (See the
+ * <A HREF="../format.html#cuesheet_track">format specification</A> for
+ * the full description of each field.)
+ */
+typedef struct {
+ FLAC__uint64 offset;
+ /**< Track offset in samples, relative to the beginning of the FLAC audio stream. */
+
+ FLAC__byte number;
+ /**< The track number. */
+
+ char isrc[13];
+ /**< Track ISRC. This is a 12-digit alphanumeric code plus a trailing \c NUL byte */
+
+ uint32_t type:1;
+ /**< The track type: 0 for audio, 1 for non-audio. */
+
+ uint32_t pre_emphasis:1;
+ /**< The pre-emphasis flag: 0 for no pre-emphasis, 1 for pre-emphasis. */
+
+ FLAC__byte num_indices;
+ /**< The number of track index points. */
+
+ FLAC__StreamMetadata_CueSheet_Index *indices;
+ /**< NULL if num_indices == 0, else pointer to array of index points. */
+
+} FLAC__StreamMetadata_CueSheet_Track;
+
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN; /**< == 64 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN; /**< == 8 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN; /**< == 12*8 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN; /**< == 1 (bit) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN; /**< == 1 (bit) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN; /**< == 6+13*8 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN; /**< == 8 (bits) */
+
+
+/** FLAC CUESHEET structure. (See the
+ * <A HREF="../format.html#metadata_block_cuesheet">format specification</A>
+ * for the full description of each field.)
+ */
+typedef struct {
+ char media_catalog_number[129];
+ /**< Media catalog number, in ASCII printable characters 0x20-0x7e. In
+ * general, the media catalog number may be 0 to 128 bytes long; any
+ * unused characters should be right-padded with NUL characters.
+ */
+
+ FLAC__uint64 lead_in;
+ /**< The number of lead-in samples. */
+
+ FLAC__bool is_cd;
+ /**< \c true if CUESHEET corresponds to a Compact Disc, else \c false. */
+
+ uint32_t num_tracks;
+ /**< The number of tracks. */
+
+ FLAC__StreamMetadata_CueSheet_Track *tracks;
+ /**< NULL if num_tracks == 0, else pointer to array of tracks. */
+
+} FLAC__StreamMetadata_CueSheet;
+
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN; /**< == 128*8 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN; /**< == 64 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN; /**< == 1 (bit) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN; /**< == 7+258*8 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN; /**< == 8 (bits) */
+
+
+/** An enumeration of the PICTURE types (see FLAC__StreamMetadataPicture and id3 v2.4 APIC tag). */
+typedef enum {
+ FLAC__STREAM_METADATA_PICTURE_TYPE_OTHER = 0, /**< Other */
+ FLAC__STREAM_METADATA_PICTURE_TYPE_FILE_ICON_STANDARD = 1, /**< 32x32 pixels 'file icon' (PNG only) */
+ FLAC__STREAM_METADATA_PICTURE_TYPE_FILE_ICON = 2, /**< Other file icon */
+ FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER = 3, /**< Cover (front) */
+ FLAC__STREAM_METADATA_PICTURE_TYPE_BACK_COVER = 4, /**< Cover (back) */
+ FLAC__STREAM_METADATA_PICTURE_TYPE_LEAFLET_PAGE = 5, /**< Leaflet page */
+ FLAC__STREAM_METADATA_PICTURE_TYPE_MEDIA = 6, /**< Media (e.g. label side of CD) */
+ FLAC__STREAM_METADATA_PICTURE_TYPE_LEAD_ARTIST = 7, /**< Lead artist/lead performer/soloist */
+ FLAC__STREAM_METADATA_PICTURE_TYPE_ARTIST = 8, /**< Artist/performer */
+ FLAC__STREAM_METADATA_PICTURE_TYPE_CONDUCTOR = 9, /**< Conductor */
+ FLAC__STREAM_METADATA_PICTURE_TYPE_BAND = 10, /**< Band/Orchestra */
+ FLAC__STREAM_METADATA_PICTURE_TYPE_COMPOSER = 11, /**< Composer */
+ FLAC__STREAM_METADATA_PICTURE_TYPE_LYRICIST = 12, /**< Lyricist/text writer */
+ FLAC__STREAM_METADATA_PICTURE_TYPE_RECORDING_LOCATION = 13, /**< Recording Location */
+ FLAC__STREAM_METADATA_PICTURE_TYPE_DURING_RECORDING = 14, /**< During recording */
+ FLAC__STREAM_METADATA_PICTURE_TYPE_DURING_PERFORMANCE = 15, /**< During performance */
+ FLAC__STREAM_METADATA_PICTURE_TYPE_VIDEO_SCREEN_CAPTURE = 16, /**< Movie/video screen capture */
+ FLAC__STREAM_METADATA_PICTURE_TYPE_FISH = 17, /**< A bright coloured fish */
+ FLAC__STREAM_METADATA_PICTURE_TYPE_ILLUSTRATION = 18, /**< Illustration */
+ FLAC__STREAM_METADATA_PICTURE_TYPE_BAND_LOGOTYPE = 19, /**< Band/artist logotype */
+ FLAC__STREAM_METADATA_PICTURE_TYPE_PUBLISHER_LOGOTYPE = 20, /**< Publisher/Studio logotype */
+ FLAC__STREAM_METADATA_PICTURE_TYPE_UNDEFINED
+} FLAC__StreamMetadata_Picture_Type;
+
+/** Maps a FLAC__StreamMetadata_Picture_Type to a C string.
+ *
+ * Using a FLAC__StreamMetadata_Picture_Type as the index to this array
+ * will give the string equivalent. The contents should not be
+ * modified.
+ */
+extern FLAC_API const char * const FLAC__StreamMetadata_Picture_TypeString[];
+
+/** FLAC PICTURE structure. (See the
+ * <A HREF="../format.html#metadata_block_picture">format specification</A>
+ * for the full description of each field.)
+ */
+typedef struct {
+ FLAC__StreamMetadata_Picture_Type type;
+ /**< The kind of picture stored. */
+
+ char *mime_type;
+ /**< Picture data's MIME type, in ASCII printable characters
+ * 0x20-0x7e, NUL terminated. For best compatibility with players,
+ * use picture data of MIME type \c image/jpeg or \c image/png. A
+ * MIME type of '-->' is also allowed, in which case the picture
+ * data should be a complete URL. In file storage, the MIME type is
+ * stored as a 32-bit length followed by the ASCII string with no NUL
+ * terminator, but is converted to a plain C string in this structure
+ * for convenience.
+ */
+
+ FLAC__byte *description;
+ /**< Picture's description in UTF-8, NUL terminated. In file storage,
+ * the description is stored as a 32-bit length followed by the UTF-8
+ * string with no NUL terminator, but is converted to a plain C string
+ * in this structure for convenience.
+ */
+
+ FLAC__uint32 width;
+ /**< Picture's width in pixels. */
+
+ FLAC__uint32 height;
+ /**< Picture's height in pixels. */
+
+ FLAC__uint32 depth;
+ /**< Picture's color depth in bits-per-pixel. */
+
+ FLAC__uint32 colors;
+ /**< For indexed palettes (like GIF), picture's number of colors (the
+ * number of palette entries), or \c 0 for non-indexed (i.e. 2^depth).
+ */
+
+ FLAC__uint32 data_length;
+ /**< Length of binary picture data in bytes. */
+
+ FLAC__byte *data;
+ /**< Binary picture data. */
+
+} FLAC__StreamMetadata_Picture;
+
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_TYPE_LEN; /**< == 32 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN; /**< == 32 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN; /**< == 32 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN; /**< == 32 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN; /**< == 32 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN; /**< == 32 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_COLORS_LEN; /**< == 32 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN; /**< == 32 (bits) */
+
+
+/** Structure that is used when a metadata block of unknown type is loaded.
+ * The contents are opaque. The structure is used only internally to
+ * correctly handle unknown metadata.
+ */
+typedef struct {
+ FLAC__byte *data;
+} FLAC__StreamMetadata_Unknown;
+
+
+/** FLAC metadata block structure. (c.f. <A HREF="../format.html#metadata_block">format specification</A>)
+ */
+typedef struct {
+ FLAC__MetadataType type;
+ /**< The type of the metadata block; used determine which member of the
+ * \a data union to dereference. If type >= FLAC__METADATA_TYPE_UNDEFINED
+ * then \a data.unknown must be used. */
+
+ FLAC__bool is_last;
+ /**< \c true if this metadata block is the last, else \a false */
+
+ uint32_t length;
+ /**< Length, in bytes, of the block data as it appears in the stream. */
+
+ union {
+ FLAC__StreamMetadata_StreamInfo stream_info;
+ FLAC__StreamMetadata_Padding padding;
+ FLAC__StreamMetadata_Application application;
+ FLAC__StreamMetadata_SeekTable seek_table;
+ FLAC__StreamMetadata_VorbisComment vorbis_comment;
+ FLAC__StreamMetadata_CueSheet cue_sheet;
+ FLAC__StreamMetadata_Picture picture;
+ FLAC__StreamMetadata_Unknown unknown;
+ } data;
+ /**< Polymorphic block data; use the \a type value to determine which
+ * to use. */
+} FLAC__StreamMetadata;
+
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_IS_LAST_LEN; /**< == 1 (bit) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_TYPE_LEN; /**< == 7 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_LENGTH_LEN; /**< == 24 (bits) */
+
+/** The total stream length of a metadata block header in bytes. */
+#define FLAC__STREAM_METADATA_HEADER_LENGTH (4u)
+
+/*****************************************************************************/
+
+
+/*****************************************************************************
+ *
+ * Utility functions
+ *
+ *****************************************************************************/
+
+/** Tests that a sample rate is valid for FLAC.
+ *
+ * \param sample_rate The sample rate to test for compliance.
+ * \retval FLAC__bool
+ * \c true if the given sample rate conforms to the specification, else
+ * \c false.
+ */
+FLAC_API FLAC__bool FLAC__format_sample_rate_is_valid(uint32_t sample_rate);
+
+/** Tests that a blocksize at the given sample rate is valid for the FLAC
+ * subset.
+ *
+ * \param blocksize The blocksize to test for compliance.
+ * \param sample_rate The sample rate is needed, since the valid subset
+ * blocksize depends on the sample rate.
+ * \retval FLAC__bool
+ * \c true if the given blocksize conforms to the specification for the
+ * subset at the given sample rate, else \c false.
+ */
+FLAC_API FLAC__bool FLAC__format_blocksize_is_subset(uint32_t blocksize, uint32_t sample_rate);
+
+/** Tests that a sample rate is valid for the FLAC subset. The subset rules
+ * for valid sample rates are slightly more complex since the rate has to
+ * be expressible completely in the frame header.
+ *
+ * \param sample_rate The sample rate to test for compliance.
+ * \retval FLAC__bool
+ * \c true if the given sample rate conforms to the specification for the
+ * subset, else \c false.
+ */
+FLAC_API FLAC__bool FLAC__format_sample_rate_is_subset(uint32_t sample_rate);
+
+/** Check a Vorbis comment entry name to see if it conforms to the Vorbis
+ * comment specification.
+ *
+ * Vorbis comment names must be composed only of characters from
+ * [0x20-0x3C,0x3E-0x7D].
+ *
+ * \param name A NUL-terminated string to be checked.
+ * \assert
+ * \code name != NULL \endcode
+ * \retval FLAC__bool
+ * \c false if entry name is illegal, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__format_vorbiscomment_entry_name_is_legal(const char *name);
+
+/** Check a Vorbis comment entry value to see if it conforms to the Vorbis
+ * comment specification.
+ *
+ * Vorbis comment values must be valid UTF-8 sequences.
+ *
+ * \param value A string to be checked.
+ * \param length A the length of \a value in bytes. May be
+ * \c (uint32_t)(-1) to indicate that \a value is a plain
+ * UTF-8 NUL-terminated string.
+ * \assert
+ * \code value != NULL \endcode
+ * \retval FLAC__bool
+ * \c false if entry name is illegal, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__format_vorbiscomment_entry_value_is_legal(const FLAC__byte *value, uint32_t length);
+
+/** Check a Vorbis comment entry to see if it conforms to the Vorbis
+ * comment specification.
+ *
+ * Vorbis comment entries must be of the form 'name=value', and 'name' and
+ * 'value' must be legal according to
+ * FLAC__format_vorbiscomment_entry_name_is_legal() and
+ * FLAC__format_vorbiscomment_entry_value_is_legal() respectively.
+ *
+ * \param entry An entry to be checked.
+ * \param length The length of \a entry in bytes.
+ * \assert
+ * \code value != NULL \endcode
+ * \retval FLAC__bool
+ * \c false if entry name is illegal, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__format_vorbiscomment_entry_is_legal(const FLAC__byte *entry, uint32_t length);
+
+/** Check a seek table to see if it conforms to the FLAC specification.
+ * See the format specification for limits on the contents of the
+ * seek table.
+ *
+ * \param seek_table A pointer to a seek table to be checked.
+ * \assert
+ * \code seek_table != NULL \endcode
+ * \retval FLAC__bool
+ * \c false if seek table is illegal, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__format_seektable_is_legal(const FLAC__StreamMetadata_SeekTable *seek_table);
+
+/** Sort a seek table's seek points according to the format specification.
+ * This includes a "unique-ification" step to remove duplicates, i.e.
+ * seek points with identical \a sample_number values. Duplicate seek
+ * points are converted into placeholder points and sorted to the end of
+ * the table.
+ *
+ * \param seek_table A pointer to a seek table to be sorted.
+ * \assert
+ * \code seek_table != NULL \endcode
+ * \retval uint32_t
+ * The number of duplicate seek points converted into placeholders.
+ */
+FLAC_API uint32_t FLAC__format_seektable_sort(FLAC__StreamMetadata_SeekTable *seek_table);
+
+/** Check a cue sheet to see if it conforms to the FLAC specification.
+ * See the format specification for limits on the contents of the
+ * cue sheet.
+ *
+ * \param cue_sheet A pointer to an existing cue sheet to be checked.
+ * \param check_cd_da_subset If \c true, check CUESHEET against more
+ * stringent requirements for a CD-DA (audio) disc.
+ * \param violation Address of a pointer to a string. If there is a
+ * violation, a pointer to a string explanation of the
+ * violation will be returned here. \a violation may be
+ * \c NULL if you don't need the returned string. Do not
+ * free the returned string; it will always point to static
+ * data.
+ * \assert
+ * \code cue_sheet != NULL \endcode
+ * \retval FLAC__bool
+ * \c false if cue sheet is illegal, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__format_cuesheet_is_legal(const FLAC__StreamMetadata_CueSheet *cue_sheet, FLAC__bool check_cd_da_subset, const char **violation);
+
+/** Check picture data to see if it conforms to the FLAC specification.
+ * See the format specification for limits on the contents of the
+ * PICTURE block.
+ *
+ * \param picture A pointer to existing picture data to be checked.
+ * \param violation Address of a pointer to a string. If there is a
+ * violation, a pointer to a string explanation of the
+ * violation will be returned here. \a violation may be
+ * \c NULL if you don't need the returned string. Do not
+ * free the returned string; it will always point to static
+ * data.
+ * \assert
+ * \code picture != NULL \endcode
+ * \retval FLAC__bool
+ * \c false if picture data is illegal, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__format_picture_is_legal(const FLAC__StreamMetadata_Picture *picture, const char **violation);
+
+/* \} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
+++ b/src/libflac/FLAC/metadata.h
@@ -1,0 +1,2182 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2001-2009 Josh Coalson
+ * Copyright (C) 2011-2016 Xiph.Org Foundation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__METADATA_H
+#define FLAC__METADATA_H
+
+#include <sys/types.h> /* for off_t */
+#include "export.h"
+#include "callback.h"
+#include "format.h"
+
+/* --------------------------------------------------------------------
+ (For an example of how all these routines are used, see the source
+ code for the unit tests in src/test_libFLAC/metadata_*.c, or
+ metaflac in src/metaflac/)
+ ------------------------------------------------------------------*/
+
+/** \file include/FLAC/metadata.h
+ *
+ * \brief
+ * This module provides functions for creating and manipulating FLAC
+ * metadata blocks in memory, and three progressively more powerful
+ * interfaces for traversing and editing metadata in FLAC files.
+ *
+ * See the detailed documentation for each interface in the
+ * \link flac_metadata metadata \endlink module.
+ */
+
+/** \defgroup flac_metadata FLAC/metadata.h: metadata interfaces
+ * \ingroup flac
+ *
+ * \brief
+ * This module provides functions for creating and manipulating FLAC
+ * metadata blocks in memory, and three progressively more powerful
+ * interfaces for traversing and editing metadata in native FLAC files.
+ * Note that currently only the Chain interface (level 2) supports Ogg
+ * FLAC files, and it is read-only i.e. no writing back changed
+ * metadata to file.
+ *
+ * There are three metadata interfaces of increasing complexity:
+ *
+ * Level 0:
+ * Read-only access to the STREAMINFO, VORBIS_COMMENT, CUESHEET, and
+ * PICTURE blocks.
+ *
+ * Level 1:
+ * Read-write access to all metadata blocks. This level is write-
+ * efficient in most cases (more on this below), and uses less memory
+ * than level 2.
+ *
+ * Level 2:
+ * Read-write access to all metadata blocks. This level is write-
+ * efficient in all cases, but uses more memory since all metadata for
+ * the whole file is read into memory and manipulated before writing
+ * out again.
+ *
+ * What do we mean by efficient? Since FLAC metadata appears at the
+ * beginning of the file, when writing metadata back to a FLAC file
+ * it is possible to grow or shrink the metadata such that the entire
+ * file must be rewritten. However, if the size remains the same during
+ * changes or PADDING blocks are utilized, only the metadata needs to be
+ * overwritten, which is much faster.
+ *
+ * Efficient means the whole file is rewritten at most one time, and only
+ * when necessary. Level 1 is not efficient only in the case that you
+ * cause more than one metadata block to grow or shrink beyond what can
+ * be accommodated by padding. In this case you should probably use level
+ * 2, which allows you to edit all the metadata for a file in memory and
+ * write it out all at once.
+ *
+ * All levels know how to skip over and not disturb an ID3v2 tag at the
+ * front of the file.
+ *
+ * All levels access files via their filenames. In addition, level 2
+ * has additional alternative read and write functions that take an I/O
+ * handle and callbacks, for situations where access by filename is not
+ * possible.
+ *
+ * In addition to the three interfaces, this module defines functions for
+ * creating and manipulating various metadata objects in memory. As we see
+ * from the Format module, FLAC metadata blocks in memory are very primitive
+ * structures for storing information in an efficient way. Reading
+ * information from the structures is easy but creating or modifying them
+ * directly is more complex. The metadata object routines here facilitate
+ * this by taking care of the consistency and memory management drudgery.
+ *
+ * Unless you will be using the level 1 or 2 interfaces to modify existing
+ * metadata however, you will not probably not need these.
+ *
+ * From a dependency standpoint, none of the encoders or decoders require
+ * the metadata module. This is so that embedded users can strip out the
+ * metadata module from libFLAC to reduce the size and complexity.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/** \defgroup flac_metadata_level0 FLAC/metadata.h: metadata level 0 interface
+ * \ingroup flac_metadata
+ *
+ * \brief
+ * The level 0 interface consists of individual routines to read the
+ * STREAMINFO, VORBIS_COMMENT, CUESHEET, and PICTURE blocks, requiring
+ * only a filename.
+ *
+ * They try to skip any ID3v2 tag at the head of the file.
+ *
+ * \{
+ */
+
+/** Read the STREAMINFO metadata block of the given FLAC file. This function
+ * will try to skip any ID3v2 tag at the head of the file.
+ *
+ * \param filename The path to the FLAC file to read.
+ * \param streaminfo A pointer to space for the STREAMINFO block. Since
+ * FLAC__StreamMetadata is a simple structure with no
+ * memory allocation involved, you pass the address of
+ * an existing structure. It need not be initialized.
+ * \assert
+ * \code filename != NULL \endcode
+ * \code streaminfo != NULL \endcode
+ * \retval FLAC__bool
+ * \c true if a valid STREAMINFO block was read from \a filename. Returns
+ * \c false if there was a memory allocation error, a file decoder error,
+ * or the file contained no STREAMINFO block. (A memory allocation error
+ * is possible because this function must set up a file decoder.)
+ */
+FLAC_API FLAC__bool FLAC__metadata_get_streaminfo(const char *filename, FLAC__StreamMetadata *streaminfo);
+
+/** Read the VORBIS_COMMENT metadata block of the given FLAC file. This
+ * function will try to skip any ID3v2 tag at the head of the file.
+ *
+ * \param filename The path to the FLAC file to read.
+ * \param tags The address where the returned pointer will be
+ * stored. The \a tags object must be deleted by
+ * the caller using FLAC__metadata_object_delete().
+ * \assert
+ * \code filename != NULL \endcode
+ * \code tags != NULL \endcode
+ * \retval FLAC__bool
+ * \c true if a valid VORBIS_COMMENT block was read from \a filename,
+ * and \a *tags will be set to the address of the metadata structure.
+ * Returns \c false if there was a memory allocation error, a file
+ * decoder error, or the file contained no VORBIS_COMMENT block, and
+ * \a *tags will be set to \c NULL.
+ */
+FLAC_API FLAC__bool FLAC__metadata_get_tags(const char *filename, FLAC__StreamMetadata **tags);
+
+/** Read the CUESHEET metadata block of the given FLAC file. This
+ * function will try to skip any ID3v2 tag at the head of the file.
+ *
+ * \param filename The path to the FLAC file to read.
+ * \param cuesheet The address where the returned pointer will be
+ * stored. The \a cuesheet object must be deleted by
+ * the caller using FLAC__metadata_object_delete().
+ * \assert
+ * \code filename != NULL \endcode
+ * \code cuesheet != NULL \endcode
+ * \retval FLAC__bool
+ * \c true if a valid CUESHEET block was read from \a filename,
+ * and \a *cuesheet will be set to the address of the metadata
+ * structure. Returns \c false if there was a memory allocation
+ * error, a file decoder error, or the file contained no CUESHEET
+ * block, and \a *cuesheet will be set to \c NULL.
+ */
+FLAC_API FLAC__bool FLAC__metadata_get_cuesheet(const char *filename, FLAC__StreamMetadata **cuesheet);
+
+/** Read a PICTURE metadata block of the given FLAC file. This
+ * function will try to skip any ID3v2 tag at the head of the file.
+ * Since there can be more than one PICTURE block in a file, this
+ * function takes a number of parameters that act as constraints to
+ * the search. The PICTURE block with the largest area matching all
+ * the constraints will be returned, or \a *picture will be set to
+ * \c NULL if there was no such block.
+ *
+ * \param filename The path to the FLAC file to read.
+ * \param picture The address where the returned pointer will be
+ * stored. The \a picture object must be deleted by
+ * the caller using FLAC__metadata_object_delete().
+ * \param type The desired picture type. Use \c -1 to mean
+ * "any type".
+ * \param mime_type The desired MIME type, e.g. "image/jpeg". The
+ * string will be matched exactly. Use \c NULL to
+ * mean "any MIME type".
+ * \param description The desired description. The string will be
+ * matched exactly. Use \c NULL to mean "any
+ * description".
+ * \param max_width The maximum width in pixels desired. Use
+ * \c (uint32_t)(-1) to mean "any width".
+ * \param max_height The maximum height in pixels desired. Use
+ * \c (uint32_t)(-1) to mean "any height".
+ * \param max_depth The maximum color depth in bits-per-pixel desired.
+ * Use \c (uint32_t)(-1) to mean "any depth".
+ * \param max_colors The maximum number of colors desired. Use
+ * \c (uint32_t)(-1) to mean "any number of colors".
+ * \assert
+ * \code filename != NULL \endcode
+ * \code picture != NULL \endcode
+ * \retval FLAC__bool
+ * \c true if a valid PICTURE block was read from \a filename,
+ * and \a *picture will be set to the address of the metadata
+ * structure. Returns \c false if there was a memory allocation
+ * error, a file decoder error, or the file contained no PICTURE
+ * block, and \a *picture will be set to \c NULL.
+ */
+FLAC_API FLAC__bool FLAC__metadata_get_picture(const char *filename, FLAC__StreamMetadata **picture, FLAC__StreamMetadata_Picture_Type type, const char *mime_type, const FLAC__byte *description, uint32_t max_width, uint32_t max_height, uint32_t max_depth, uint32_t max_colors);
+
+/* \} */
+
+
+/** \defgroup flac_metadata_level1 FLAC/metadata.h: metadata level 1 interface
+ * \ingroup flac_metadata
+ *
+ * \brief
+ * The level 1 interface provides read-write access to FLAC file metadata and
+ * operates directly on the FLAC file.
+ *
+ * The general usage of this interface is:
+ *
+ * - Create an iterator using FLAC__metadata_simple_iterator_new()
+ * - Attach it to a file using FLAC__metadata_simple_iterator_init() and check
+ * the exit code. Call FLAC__metadata_simple_iterator_is_writable() to
+ * see if the file is writable, or only read access is allowed.
+ * - Use FLAC__metadata_simple_iterator_next() and
+ * FLAC__metadata_simple_iterator_prev() to traverse the blocks.
+ * This is does not read the actual blocks themselves.
+ * FLAC__metadata_simple_iterator_next() is relatively fast.
+ * FLAC__metadata_simple_iterator_prev() is slower since it needs to search
+ * forward from the front of the file.
+ * - Use FLAC__metadata_simple_iterator_get_block_type() or
+ * FLAC__metadata_simple_iterator_get_block() to access the actual data at
+ * the current iterator position. The returned object is yours to modify
+ * and free.
+ * - Use FLAC__metadata_simple_iterator_set_block() to write a modified block
+ * back. You must have write permission to the original file. Make sure to
+ * read the whole comment to FLAC__metadata_simple_iterator_set_block()
+ * below.
+ * - Use FLAC__metadata_simple_iterator_insert_block_after() to add new blocks.
+ * Use the object creation functions from
+ * \link flac_metadata_object here \endlink to generate new objects.
+ * - Use FLAC__metadata_simple_iterator_delete_block() to remove the block
+ * currently referred to by the iterator, or replace it with padding.
+ * - Destroy the iterator with FLAC__metadata_simple_iterator_delete() when
+ * finished.
+ *
+ * \note
+ * The FLAC file remains open the whole time between
+ * FLAC__metadata_simple_iterator_init() and
+ * FLAC__metadata_simple_iterator_delete(), so make sure you are not altering
+ * the file during this time.
+ *
+ * \note
+ * Do not modify the \a is_last, \a length, or \a type fields of returned
+ * FLAC__StreamMetadata objects. These are managed automatically.
+ *
+ * \note
+ * If any of the modification functions
+ * (FLAC__metadata_simple_iterator_set_block(),
+ * FLAC__metadata_simple_iterator_delete_block(),
+ * FLAC__metadata_simple_iterator_insert_block_after(), etc.) return \c false,
+ * you should delete the iterator as it may no longer be valid.
+ *
+ * \{
+ */
+
+struct FLAC__Metadata_SimpleIterator;
+/** The opaque structure definition for the level 1 iterator type.
+ * See the
+ * \link flac_metadata_level1 metadata level 1 module \endlink
+ * for a detailed description.
+ */
+typedef struct FLAC__Metadata_SimpleIterator FLAC__Metadata_SimpleIterator;
+
+/** Status type for FLAC__Metadata_SimpleIterator.
+ *
+ * The iterator's current status can be obtained by calling FLAC__metadata_simple_iterator_status().
+ */
+typedef enum {
+
+ FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK = 0,
+ /**< The iterator is in the normal OK state */
+
+ FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT,
+ /**< The data passed into a function violated the function's usage criteria */
+
+ FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ERROR_OPENING_FILE,
+ /**< The iterator could not open the target file */
+
+ FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_A_FLAC_FILE,
+ /**< The iterator could not find the FLAC signature at the start of the file */
+
+ FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_WRITABLE,
+ /**< The iterator tried to write to a file that was not writable */
+
+ FLAC__METADATA_SIMPLE_ITERATOR_STATUS_BAD_METADATA,
+ /**< The iterator encountered input that does not conform to the FLAC metadata specification */
+
+ FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR,
+ /**< The iterator encountered an error while reading the FLAC file */
+
+ FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR,
+ /**< The iterator encountered an error while seeking in the FLAC file */
+
+ FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR,
+ /**< The iterator encountered an error while writing the FLAC file */
+
+ FLAC__METADATA_SIMPLE_ITERATOR_STATUS_RENAME_ERROR,
+ /**< The iterator encountered an error renaming the FLAC file */
+
+ FLAC__METADATA_SIMPLE_ITERATOR_STATUS_UNLINK_ERROR,
+ /**< The iterator encountered an error removing the temporary file */
+
+ FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR,
+ /**< Memory allocation failed */
+
+ FLAC__METADATA_SIMPLE_ITERATOR_STATUS_INTERNAL_ERROR
+ /**< The caller violated an assertion or an unexpected error occurred */
+
+} FLAC__Metadata_SimpleIteratorStatus;
+
+/** Maps a FLAC__Metadata_SimpleIteratorStatus to a C string.
+ *
+ * Using a FLAC__Metadata_SimpleIteratorStatus as the index to this array
+ * will give the string equivalent. The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__Metadata_SimpleIteratorStatusString[];
+
+
+/** Create a new iterator instance.
+ *
+ * \retval FLAC__Metadata_SimpleIterator*
+ * \c NULL if there was an error allocating memory, else the new instance.
+ */
+FLAC_API FLAC__Metadata_SimpleIterator *FLAC__metadata_simple_iterator_new(void);
+
+/** Free an iterator instance. Deletes the object pointed to by \a iterator.
+ *
+ * \param iterator A pointer to an existing iterator.
+ * \assert
+ * \code iterator != NULL \endcode
+ */
+FLAC_API void FLAC__metadata_simple_iterator_delete(FLAC__Metadata_SimpleIterator *iterator);
+
+/** Get the current status of the iterator. Call this after a function
+ * returns \c false to get the reason for the error. Also resets the status
+ * to FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK.
+ *
+ * \param iterator A pointer to an existing iterator.
+ * \assert
+ * \code iterator != NULL \endcode
+ * \retval FLAC__Metadata_SimpleIteratorStatus
+ * The current status of the iterator.
+ */
+FLAC_API FLAC__Metadata_SimpleIteratorStatus FLAC__metadata_simple_iterator_status(FLAC__Metadata_SimpleIterator *iterator);
+
+/** Initialize the iterator to point to the first metadata block in the
+ * given FLAC file.
+ *
+ * \param iterator A pointer to an existing iterator.
+ * \param filename The path to the FLAC file.
+ * \param read_only If \c true, the FLAC file will be opened
+ * in read-only mode; if \c false, the FLAC
+ * file will be opened for edit even if no
+ * edits are performed.
+ * \param preserve_file_stats If \c true, the owner and modification
+ * time will be preserved even if the FLAC
+ * file is written to.
+ * \assert
+ * \code iterator != NULL \endcode
+ * \code filename != NULL \endcode
+ * \retval FLAC__bool
+ * \c false if a memory allocation error occurs, the file can't be
+ * opened, or another error occurs, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_simple_iterator_init(FLAC__Metadata_SimpleIterator *iterator, const char *filename, FLAC__bool read_only, FLAC__bool preserve_file_stats);
+
+/** Returns \c true if the FLAC file is writable. If \c false, calls to
+ * FLAC__metadata_simple_iterator_set_block() and
+ * FLAC__metadata_simple_iterator_insert_block_after() will fail.
+ *
+ * \param iterator A pointer to an existing iterator.
+ * \assert
+ * \code iterator != NULL \endcode
+ * \retval FLAC__bool
+ * See above.
+ */
+FLAC_API FLAC__bool FLAC__metadata_simple_iterator_is_writable(const FLAC__Metadata_SimpleIterator *iterator);
+
+/** Moves the iterator forward one metadata block, returning \c false if
+ * already at the end.
+ *
+ * \param iterator A pointer to an existing initialized iterator.
+ * \assert
+ * \code iterator != NULL \endcode
+ * \a iterator has been successfully initialized with
+ * FLAC__metadata_simple_iterator_init()
+ * \retval FLAC__bool
+ * \c false if already at the last metadata block of the chain, else
+ * \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_simple_iterator_next(FLAC__Metadata_SimpleIterator *iterator);
+
+/** Moves the iterator backward one metadata block, returning \c false if
+ * already at the beginning.
+ *
+ * \param iterator A pointer to an existing initialized iterator.
+ * \assert
+ * \code iterator != NULL \endcode
+ * \a iterator has been successfully initialized with
+ * FLAC__metadata_simple_iterator_init()
+ * \retval FLAC__bool
+ * \c false if already at the first metadata block of the chain, else
+ * \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_simple_iterator_prev(FLAC__Metadata_SimpleIterator *iterator);
+
+/** Returns a flag telling if the current metadata block is the last.
+ *
+ * \param iterator A pointer to an existing initialized iterator.
+ * \assert
+ * \code iterator != NULL \endcode
+ * \a iterator has been successfully initialized with
+ * FLAC__metadata_simple_iterator_init()
+ * \retval FLAC__bool
+ * \c true if the current metadata block is the last in the file,
+ * else \c false.
+ */
+FLAC_API FLAC__bool FLAC__metadata_simple_iterator_is_last(const FLAC__Metadata_SimpleIterator *iterator);
+
+/** Get the offset of the metadata block at the current position. This
+ * avoids reading the actual block data which can save time for large
+ * blocks.
+ *
+ * \param iterator A pointer to an existing initialized iterator.
+ * \assert
+ * \code iterator != NULL \endcode
+ * \a iterator has been successfully initialized with
+ * FLAC__metadata_simple_iterator_init()
+ * \retval off_t
+ * The offset of the metadata block at the current iterator position.
+ * This is the byte offset relative to the beginning of the file of
+ * the current metadata block's header.
+ */
+FLAC_API off_t FLAC__metadata_simple_iterator_get_block_offset(const FLAC__Metadata_SimpleIterator *iterator);
+
+/** Get the type of the metadata block at the current position. This
+ * avoids reading the actual block data which can save time for large
+ * blocks.
+ *
+ * \param iterator A pointer to an existing initialized iterator.
+ * \assert
+ * \code iterator != NULL \endcode
+ * \a iterator has been successfully initialized with
+ * FLAC__metadata_simple_iterator_init()
+ * \retval FLAC__MetadataType
+ * The type of the metadata block at the current iterator position.
+ */
+FLAC_API FLAC__MetadataType FLAC__metadata_simple_iterator_get_block_type(const FLAC__Metadata_SimpleIterator *iterator);
+
+/** Get the length of the metadata block at the current position. This
+ * avoids reading the actual block data which can save time for large
+ * blocks.
+ *
+ * \param iterator A pointer to an existing initialized iterator.
+ * \assert
+ * \code iterator != NULL \endcode
+ * \a iterator has been successfully initialized with
+ * FLAC__metadata_simple_iterator_init()
+ * \retval uint32_t
+ * The length of the metadata block at the current iterator position.
+ * The is same length as that in the
+ * <a href="http://xiph.org/flac/format.html#metadata_block_header">metadata block header</a>,
+ * i.e. the length of the metadata body that follows the header.
+ */
+FLAC_API uint32_t FLAC__metadata_simple_iterator_get_block_length(const FLAC__Metadata_SimpleIterator *iterator);
+
+/** Get the application ID of the \c APPLICATION block at the current
+ * position. This avoids reading the actual block data which can save
+ * time for large blocks.
+ *
+ * \param iterator A pointer to an existing initialized iterator.
+ * \param id A pointer to a buffer of at least \c 4 bytes where
+ * the ID will be stored.
+ * \assert
+ * \code iterator != NULL \endcode
+ * \code id != NULL \endcode
+ * \a iterator has been successfully initialized with
+ * FLAC__metadata_simple_iterator_init()
+ * \retval FLAC__bool
+ * \c true if the ID was successfully read, else \c false, in which
+ * case you should check FLAC__metadata_simple_iterator_status() to
+ * find out why. If the status is
+ * \c FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT, then the
+ * current metadata block is not an \c APPLICATION block. Otherwise
+ * if the status is
+ * \c FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR or
+ * \c FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR, an I/O error
+ * occurred and the iterator can no longer be used.
+ */
+FLAC_API FLAC__bool FLAC__metadata_simple_iterator_get_application_id(FLAC__Metadata_SimpleIterator *iterator, FLAC__byte *id);
+
+/** Get the metadata block at the current position. You can modify the
+ * block but must use FLAC__metadata_simple_iterator_set_block() to
+ * write it back to the FLAC file.
+ *
+ * You must call FLAC__metadata_object_delete() on the returned object
+ * when you are finished with it.
+ *
+ * \param iterator A pointer to an existing initialized iterator.
+ * \assert
+ * \code iterator != NULL \endcode
+ * \a iterator has been successfully initialized with
+ * FLAC__metadata_simple_iterator_init()
+ * \retval FLAC__StreamMetadata*
+ * The current metadata block, or \c NULL if there was a memory
+ * allocation error.
+ */
+FLAC_API FLAC__StreamMetadata *FLAC__metadata_simple_iterator_get_block(FLAC__Metadata_SimpleIterator *iterator);
+
+/** Write a block back to the FLAC file. This function tries to be
+ * as efficient as possible; how the block is actually written is
+ * shown by the following:
+ *
+ * Existing block is a STREAMINFO block and the new block is a
+ * STREAMINFO block: the new block is written in place. Make sure
+ * you know what you're doing when changing the values of a
+ * STREAMINFO block.
+ *
+ * Existing block is a STREAMINFO block and the new block is a
+ * not a STREAMINFO block: this is an error since the first block
+ * must be a STREAMINFO block. Returns \c false without altering the
+ * file.
+ *
+ * Existing block is not a STREAMINFO block and the new block is a
+ * STREAMINFO block: this is an error since there may be only one
+ * STREAMINFO block. Returns \c false without altering the file.
+ *
+ * Existing block and new block are the same length: the existing
+ * block will be replaced by the new block, written in place.
+ *
+ * Existing block is longer than new block: if use_padding is \c true,
+ * the existing block will be overwritten in place with the new
+ * block followed by a PADDING block, if possible, to make the total
+ * size the same as the existing block. Remember that a padding
+ * block requires at least four bytes so if the difference in size
+ * between the new block and existing block is less than that, the
+ * entire file will have to be rewritten, using the new block's
+ * exact size. If use_padding is \c false, the entire file will be
+ * rewritten, replacing the existing block by the new block.
+ *
+ * Existing block is shorter than new block: if use_padding is \c true,
+ * the function will try and expand the new block into the following
+ * PADDING block, if it exists and doing so won't shrink the PADDING
+ * block to less than 4 bytes. If there is no following PADDING
+ * block, or it will shrink to less than 4 bytes, or use_padding is
+ * \c false, the entire file is rewritten, replacing the existing block
+ * with the new block. Note that in this case any following PADDING
+ * block is preserved as is.
+ *
+ * After writing the block, the iterator will remain in the same
+ * place, i.e. pointing to the new block.
+ *
+ * \param iterator A pointer to an existing initialized iterator.
+ * \param block The block to set.
+ * \param use_padding See above.
+ * \assert
+ * \code iterator != NULL \endcode
+ * \a iterator has been successfully initialized with
+ * FLAC__metadata_simple_iterator_init()
+ * \code block != NULL \endcode
+ * \retval FLAC__bool
+ * \c true if successful, else \c false.
+ */
+FLAC_API FLAC__bool FLAC__metadata_simple_iterator_set_block(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block, FLAC__bool use_padding);
+
+/** This is similar to FLAC__metadata_simple_iterator_set_block()
+ * except that instead of writing over an existing block, it appends
+ * a block after the existing block. \a use_padding is again used to
+ * tell the function to try an expand into following padding in an
+ * attempt to avoid rewriting the entire file.
+ *
+ * This function will fail and return \c false if given a STREAMINFO
+ * block.
+ *
+ * After writing the block, the iterator will be pointing to the
+ * new block.
+ *
+ * \param iterator A pointer to an existing initialized iterator.
+ * \param block The block to set.
+ * \param use_padding See above.
+ * \assert
+ * \code iterator != NULL \endcode
+ * \a iterator has been successfully initialized with
+ * FLAC__metadata_simple_iterator_init()
+ * \code block != NULL \endcode
+ * \retval FLAC__bool
+ * \c true if successful, else \c false.
+ */
+FLAC_API FLAC__bool FLAC__metadata_simple_iterator_insert_block_after(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block, FLAC__bool use_padding);
+
+/** Deletes the block at the current position. This will cause the
+ * entire FLAC file to be rewritten, unless \a use_padding is \c true,
+ * in which case the block will be replaced by an equal-sized PADDING
+ * block. The iterator will be left pointing to the block before the
+ * one just deleted.
+ *
+ * You may not delete the STREAMINFO block.
+ *
+ * \param iterator A pointer to an existing initialized iterator.
+ * \param use_padding See above.
+ * \assert
+ * \code iterator != NULL \endcode
+ * \a iterator has been successfully initialized with
+ * FLAC__metadata_simple_iterator_init()
+ * \retval FLAC__bool
+ * \c true if successful, else \c false.
+ */
+FLAC_API FLAC__bool FLAC__metadata_simple_iterator_delete_block(FLAC__Metadata_SimpleIterator *iterator, FLAC__bool use_padding);
+
+/* \} */
+
+
+/** \defgroup flac_metadata_level2 FLAC/metadata.h: metadata level 2 interface
+ * \ingroup flac_metadata
+ *
+ * \brief
+ * The level 2 interface provides read-write access to FLAC file metadata;
+ * all metadata is read into memory, operated on in memory, and then written
+ * to file, which is more efficient than level 1 when editing multiple blocks.
+ *
+ * Currently Ogg FLAC is supported for read only, via
+ * FLAC__metadata_chain_read_ogg() but a subsequent
+ * FLAC__metadata_chain_write() will fail.
+ *
+ * The general usage of this interface is:
+ *
+ * - Create a new chain using FLAC__metadata_chain_new(). A chain is a
+ * linked list of FLAC metadata blocks.
+ * - Read all metadata into the chain from a FLAC file using
+ * FLAC__metadata_chain_read() or FLAC__metadata_chain_read_ogg() and
+ * check the status.
+ * - Optionally, consolidate the padding using
+ * FLAC__metadata_chain_merge_padding() or
+ * FLAC__metadata_chain_sort_padding().
+ * - Create a new iterator using FLAC__metadata_iterator_new()
+ * - Initialize the iterator to point to the first element in the chain
+ * using FLAC__metadata_iterator_init()
+ * - Traverse the chain using FLAC__metadata_iterator_next and
+ * FLAC__metadata_iterator_prev().
+ * - Get a block for reading or modification using
+ * FLAC__metadata_iterator_get_block(). The pointer to the object
+ * inside the chain is returned, so the block is yours to modify.
+ * Changes will be reflected in the FLAC file when you write the
+ * chain. You can also add and delete blocks (see functions below).
+ * - When done, write out the chain using FLAC__metadata_chain_write().
+ * Make sure to read the whole comment to the function below.
+ * - Delete the chain using FLAC__metadata_chain_delete().
+ *
+ * \note
+ * Even though the FLAC file is not open while the chain is being
+ * manipulated, you must not alter the file externally during
+ * this time. The chain assumes the FLAC file will not change
+ * between the time of FLAC__metadata_chain_read()/FLAC__metadata_chain_read_ogg()
+ * and FLAC__metadata_chain_write().
+ *
+ * \note
+ * Do not modify the is_last, length, or type fields of returned
+ * FLAC__StreamMetadata objects. These are managed automatically.
+ *
+ * \note
+ * The metadata objects returned by FLAC__metadata_iterator_get_block()
+ * are owned by the chain; do not FLAC__metadata_object_delete() them.
+ * In the same way, blocks passed to FLAC__metadata_iterator_set_block()
+ * become owned by the chain and they will be deleted when the chain is
+ * deleted.
+ *
+ * \{
+ */
+
+struct FLAC__Metadata_Chain;
+/** The opaque structure definition for the level 2 chain type.
+ */
+typedef struct FLAC__Metadata_Chain FLAC__Metadata_Chain;
+
+struct FLAC__Metadata_Iterator;
+/** The opaque structure definition for the level 2 iterator type.
+ */
+typedef struct FLAC__Metadata_Iterator FLAC__Metadata_Iterator;
+
+typedef enum {
+ FLAC__METADATA_CHAIN_STATUS_OK = 0,
+ /**< The chain is in the normal OK state */
+
+ FLAC__METADATA_CHAIN_STATUS_ILLEGAL_INPUT,
+ /**< The data passed into a function violated the function's usage criteria */
+
+ FLAC__METADATA_CHAIN_STATUS_ERROR_OPENING_FILE,
+ /**< The chain could not open the target file */
+
+ FLAC__METADATA_CHAIN_STATUS_NOT_A_FLAC_FILE,
+ /**< The chain could not find the FLAC signature at the start of the file */
+
+ FLAC__METADATA_CHAIN_STATUS_NOT_WRITABLE,
+ /**< The chain tried to write to a file that was not writable */
+
+ FLAC__METADATA_CHAIN_STATUS_BAD_METADATA,
+ /**< The chain encountered input that does not conform to the FLAC metadata specification */
+
+ FLAC__METADATA_CHAIN_STATUS_READ_ERROR,
+ /**< The chain encountered an error while reading the FLAC file */
+
+ FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR,
+ /**< The chain encountered an error while seeking in the FLAC file */
+
+ FLAC__METADATA_CHAIN_STATUS_WRITE_ERROR,
+ /**< The chain encountered an error while writing the FLAC file */
+
+ FLAC__METADATA_CHAIN_STATUS_RENAME_ERROR,
+ /**< The chain encountered an error renaming the FLAC file */
+
+ FLAC__METADATA_CHAIN_STATUS_UNLINK_ERROR,
+ /**< The chain encountered an error removing the temporary file */
+
+ FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR,
+ /**< Memory allocation failed */
+
+ FLAC__METADATA_CHAIN_STATUS_INTERNAL_ERROR,
+ /**< The caller violated an assertion or an unexpected error occurred */
+
+ FLAC__METADATA_CHAIN_STATUS_INVALID_CALLBACKS,
+ /**< One or more of the required callbacks was NULL */
+
+ FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH,
+ /**< FLAC__metadata_chain_write() was called on a chain read by
+ * FLAC__metadata_chain_read_with_callbacks()/FLAC__metadata_chain_read_ogg_with_callbacks(),
+ * or
+ * FLAC__metadata_chain_write_with_callbacks()/FLAC__metadata_chain_write_with_callbacks_and_tempfile()
+ * was called on a chain read by
+ * FLAC__metadata_chain_read()/FLAC__metadata_chain_read_ogg().
+ * Matching read/write methods must always be used. */
+
+ FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL
+ /**< FLAC__metadata_chain_write_with_callbacks() was called when the
+ * chain write requires a tempfile; use
+ * FLAC__metadata_chain_write_with_callbacks_and_tempfile() instead.
+ * Or, FLAC__metadata_chain_write_with_callbacks_and_tempfile() was
+ * called when the chain write does not require a tempfile; use
+ * FLAC__metadata_chain_write_with_callbacks() instead.
+ * Always check FLAC__metadata_chain_check_if_tempfile_needed()
+ * before writing via callbacks. */
+
+} FLAC__Metadata_ChainStatus;
+
+/** Maps a FLAC__Metadata_ChainStatus to a C string.
+ *
+ * Using a FLAC__Metadata_ChainStatus as the index to this array
+ * will give the string equivalent. The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__Metadata_ChainStatusString[];
+
+/*********** FLAC__Metadata_Chain ***********/
+
+/** Create a new chain instance.
+ *
+ * \retval FLAC__Metadata_Chain*
+ * \c NULL if there was an error allocating memory, else the new instance.
+ */
+FLAC_API FLAC__Metadata_Chain *FLAC__metadata_chain_new(void);
+
+/** Free a chain instance. Deletes the object pointed to by \a chain.
+ *
+ * \param chain A pointer to an existing chain.
+ * \assert
+ * \code chain != NULL \endcode
+ */
+FLAC_API void FLAC__metadata_chain_delete(FLAC__Metadata_Chain *chain);
+
+/** Get the current status of the chain. Call this after a function
+ * returns \c false to get the reason for the error. Also resets the
+ * status to FLAC__METADATA_CHAIN_STATUS_OK.
+ *
+ * \param chain A pointer to an existing chain.
+ * \assert
+ * \code chain != NULL \endcode
+ * \retval FLAC__Metadata_ChainStatus
+ * The current status of the chain.
+ */
+FLAC_API FLAC__Metadata_ChainStatus FLAC__metadata_chain_status(FLAC__Metadata_Chain *chain);
+
+/** Read all metadata from a FLAC file into the chain.
+ *
+ * \param chain A pointer to an existing chain.
+ * \param filename The path to the FLAC file to read.
+ * \assert
+ * \code chain != NULL \endcode
+ * \code filename != NULL \endcode
+ * \retval FLAC__bool
+ * \c true if a valid list of metadata blocks was read from
+ * \a filename, else \c false. On failure, check the status with
+ * FLAC__metadata_chain_status().
+ */
+FLAC_API FLAC__bool FLAC__metadata_chain_read(FLAC__Metadata_Chain *chain, const char *filename);
+
+/** Read all metadata from an Ogg FLAC file into the chain.
+ *
+ * \note Ogg FLAC metadata data writing is not supported yet and
+ * FLAC__metadata_chain_write() will fail.
+ *
+ * \param chain A pointer to an existing chain.
+ * \param filename The path to the Ogg FLAC file to read.
+ * \assert
+ * \code chain != NULL \endcode
+ * \code filename != NULL \endcode
+ * \retval FLAC__bool
+ * \c true if a valid list of metadata blocks was read from
+ * \a filename, else \c false. On failure, check the status with
+ * FLAC__metadata_chain_status().
+ */
+FLAC_API FLAC__bool FLAC__metadata_chain_read_ogg(FLAC__Metadata_Chain *chain, const char *filename);
+
+/** Read all metadata from a FLAC stream into the chain via I/O callbacks.
+ *
+ * The \a handle need only be open for reading, but must be seekable.
+ * The equivalent minimum stdio fopen() file mode is \c "r" (or \c "rb"
+ * for Windows).
+ *
+ * \param chain A pointer to an existing chain.
+ * \param handle The I/O handle of the FLAC stream to read. The
+ * handle will NOT be closed after the metadata is read;
+ * that is the duty of the caller.
+ * \param callbacks
+ * A set of callbacks to use for I/O. The mandatory
+ * callbacks are \a read, \a seek, and \a tell.
+ * \assert
+ * \code chain != NULL \endcode
+ * \retval FLAC__bool
+ * \c true if a valid list of metadata blocks was read from
+ * \a handle, else \c false. On failure, check the status with
+ * FLAC__metadata_chain_status().
+ */
+FLAC_API FLAC__bool FLAC__metadata_chain_read_with_callbacks(FLAC__Metadata_Chain *chain, FLAC__IOHandle handle, FLAC__IOCallbacks callbacks);
+
+/** Read all metadata from an Ogg FLAC stream into the chain via I/O callbacks.
+ *
+ * The \a handle need only be open for reading, but must be seekable.
+ * The equivalent minimum stdio fopen() file mode is \c "r" (or \c "rb"
+ * for Windows).
+ *
+ * \note Ogg FLAC metadata data writing is not supported yet and
+ * FLAC__metadata_chain_write() will fail.
+ *
+ * \param chain A pointer to an existing chain.
+ * \param handle The I/O handle of the Ogg FLAC stream to read. The
+ * handle will NOT be closed after the metadata is read;
+ * that is the duty of the caller.
+ * \param callbacks
+ * A set of callbacks to use for I/O. The mandatory
+ * callbacks are \a read, \a seek, and \a tell.
+ * \assert
+ * \code chain != NULL \endcode
+ * \retval FLAC__bool
+ * \c true if a valid list of metadata blocks was read from
+ * \a handle, else \c false. On failure, check the status with
+ * FLAC__metadata_chain_status().
+ */
+FLAC_API FLAC__bool FLAC__metadata_chain_read_ogg_with_callbacks(FLAC__Metadata_Chain *chain, FLAC__IOHandle handle, FLAC__IOCallbacks callbacks);
+
+/** Checks if writing the given chain would require the use of a
+ * temporary file, or if it could be written in place.
+ *
+ * Under certain conditions, padding can be utilized so that writing
+ * edited metadata back to the FLAC file does not require rewriting the
+ * entire file. If rewriting is required, then a temporary workfile is
+ * required. When writing metadata using callbacks, you must check
+ * this function to know whether to call
+ * FLAC__metadata_chain_write_with_callbacks() or
+ * FLAC__metadata_chain_write_with_callbacks_and_tempfile(). When
+ * writing with FLAC__metadata_chain_write(), the temporary file is
+ * handled internally.
+ *
+ * \param chain A pointer to an existing chain.
+ * \param use_padding
+ * Whether or not padding will be allowed to be used
+ * during the write. The value of \a use_padding given
+ * here must match the value later passed to
+ * FLAC__metadata_chain_write_with_callbacks() or
+ * FLAC__metadata_chain_write_with_callbacks_with_tempfile().
+ * \assert
+ * \code chain != NULL \endcode
+ * \retval FLAC__bool
+ * \c true if writing the current chain would require a tempfile, or
+ * \c false if metadata can be written in place.
+ */
+FLAC_API FLAC__bool FLAC__metadata_chain_check_if_tempfile_needed(FLAC__Metadata_Chain *chain, FLAC__bool use_padding);
+
+/** Write all metadata out to the FLAC file. This function tries to be as
+ * efficient as possible; how the metadata is actually written is shown by
+ * the following:
+ *
+ * If the current chain is the same size as the existing metadata, the new
+ * data is written in place.
+ *
+ * If the current chain is longer than the existing metadata, and
+ * \a use_padding is \c true, and the last block is a PADDING block of
+ * sufficient length, the function will truncate the final padding block
+ * so that the overall size of the metadata is the same as the existing
+ * metadata, and then just rewrite the metadata. Otherwise, if not all of
+ * the above conditions are met, the entire FLAC file must be rewritten.
+ * If you want to use padding this way it is a good idea to call
+ * FLAC__metadata_chain_sort_padding() first so that you have the maximum
+ * amount of padding to work with, unless you need to preserve ordering
+ * of the PADDING blocks for some reason.
+ *
+ * If the current chain is shorter than the existing metadata, and
+ * \a use_padding is \c true, and the final block is a PADDING block, the padding
+ * is extended to make the overall size the same as the existing data. If
+ * \a use_padding is \c true and the last block is not a PADDING block, a new
+ * PADDING block is added to the end of the new data to make it the same
+ * size as the existing data (if possible, see the note to
+ * FLAC__metadata_simple_iterator_set_block() about the four byte limit)
+ * and the new data is written in place. If none of the above apply or
+ * \a use_padding is \c false, the entire FLAC file is rewritten.
+ *
+ * If \a preserve_file_stats is \c true, the owner and modification time will
+ * be preserved even if the FLAC file is written.
+ *
+ * For this write function to be used, the chain must have been read with
+ * FLAC__metadata_chain_read()/FLAC__metadata_chain_read_ogg(), not
+ * FLAC__metadata_chain_read_with_callbacks()/FLAC__metadata_chain_read_ogg_with_callbacks().
+ *
+ * \param chain A pointer to an existing chain.
+ * \param use_padding See above.
+ * \param preserve_file_stats See above.
+ * \assert
+ * \code chain != NULL \endcode
+ * \retval FLAC__bool
+ * \c true if the write succeeded, else \c false. On failure,
+ * check the status with FLAC__metadata_chain_status().
+ */
+FLAC_API FLAC__bool FLAC__metadata_chain_write(FLAC__Metadata_Chain *chain, FLAC__bool use_padding, FLAC__bool preserve_file_stats);
+
+/** Write all metadata out to a FLAC stream via callbacks.
+ *
+ * (See FLAC__metadata_chain_write() for the details on how padding is
+ * used to write metadata in place if possible.)
+ *
+ * The \a handle must be open for updating and be seekable. The
+ * equivalent minimum stdio fopen() file mode is \c "r+" (or \c "r+b"
+ * for Windows).
+ *
+ * For this write function to be used, the chain must have been read with
+ * FLAC__metadata_chain_read_with_callbacks()/FLAC__metadata_chain_read_ogg_with_callbacks(),
+ * not FLAC__metadata_chain_read()/FLAC__metadata_chain_read_ogg().
+ * Also, FLAC__metadata_chain_check_if_tempfile_needed() must have returned
+ * \c false.
+ *
+ * \param chain A pointer to an existing chain.
+ * \param use_padding See FLAC__metadata_chain_write()
+ * \param handle The I/O handle of the FLAC stream to write. The
+ * handle will NOT be closed after the metadata is
+ * written; that is the duty of the caller.
+ * \param callbacks A set of callbacks to use for I/O. The mandatory
+ * callbacks are \a write and \a seek.
+ * \assert
+ * \code chain != NULL \endcode
+ * \retval FLAC__bool
+ * \c true if the write succeeded, else \c false. On failure,
+ * check the status with FLAC__metadata_chain_status().
+ */
+FLAC_API FLAC__bool FLAC__metadata_chain_write_with_callbacks(FLAC__Metadata_Chain *chain, FLAC__bool use_padding, FLAC__IOHandle handle, FLAC__IOCallbacks callbacks);
+
+/** Write all metadata out to a FLAC stream via callbacks.
+ *
+ * (See FLAC__metadata_chain_write() for the details on how padding is
+ * used to write metadata in place if possible.)
+ *
+ * This version of the write-with-callbacks function must be used when
+ * FLAC__metadata_chain_check_if_tempfile_needed() returns true. In
+ * this function, you must supply an I/O handle corresponding to the
+ * FLAC file to edit, and a temporary handle to which the new FLAC
+ * file will be written. It is the caller's job to move this temporary
+ * FLAC file on top of the original FLAC file to complete the metadata
+ * edit.
+ *
+ * The \a handle must be open for reading and be seekable. The
+ * equivalent minimum stdio fopen() file mode is \c "r" (or \c "rb"
+ * for Windows).
+ *
+ * The \a temp_handle must be open for writing. The
+ * equivalent minimum stdio fopen() file mode is \c "w" (or \c "wb"
+ * for Windows). It should be an empty stream, or at least positioned
+ * at the start-of-file (in which case it is the caller's duty to
+ * truncate it on return).
+ *
+ * For this write function to be used, the chain must have been read with
+ * FLAC__metadata_chain_read_with_callbacks()/FLAC__metadata_chain_read_ogg_with_callbacks(),
+ * not FLAC__metadata_chain_read()/FLAC__metadata_chain_read_ogg().
+ * Also, FLAC__metadata_chain_check_if_tempfile_needed() must have returned
+ * \c true.
+ *
+ * \param chain A pointer to an existing chain.
+ * \param use_padding See FLAC__metadata_chain_write()
+ * \param handle The I/O handle of the original FLAC stream to read.
+ * The handle will NOT be closed after the metadata is
+ * written; that is the duty of the caller.
+ * \param callbacks A set of callbacks to use for I/O on \a handle.
+ * The mandatory callbacks are \a read, \a seek, and
+ * \a eof.
+ * \param temp_handle The I/O handle of the FLAC stream to write. The
+ * handle will NOT be closed after the metadata is
+ * written; that is the duty of the caller.
+ * \param temp_callbacks
+ * A set of callbacks to use for I/O on temp_handle.
+ * The only mandatory callback is \a write.
+ * \assert
+ * \code chain != NULL \endcode
+ * \retval FLAC__bool
+ * \c true if the write succeeded, else \c false. On failure,
+ * check the status with FLAC__metadata_chain_status().
+ */
+FLAC_API FLAC__bool FLAC__metadata_chain_write_with_callbacks_and_tempfile(FLAC__Metadata_Chain *chain, FLAC__bool use_padding, FLAC__IOHandle handle, FLAC__IOCallbacks callbacks, FLAC__IOHandle temp_handle, FLAC__IOCallbacks temp_callbacks);
+
+/** Merge adjacent PADDING blocks into a single block.
+ *
+ * \note This function does not write to the FLAC file, it only
+ * modifies the chain.
+ *
+ * \warning Any iterator on the current chain will become invalid after this
+ * call. You should delete the iterator and get a new one.
+ *
+ * \param chain A pointer to an existing chain.
+ * \assert
+ * \code chain != NULL \endcode
+ */
+FLAC_API void FLAC__metadata_chain_merge_padding(FLAC__Metadata_Chain *chain);
+
+/** This function will move all PADDING blocks to the end on the metadata,
+ * then merge them into a single block.
+ *
+ * \note This function does not write to the FLAC file, it only
+ * modifies the chain.
+ *
+ * \warning Any iterator on the current chain will become invalid after this
+ * call. You should delete the iterator and get a new one.
+ *
+ * \param chain A pointer to an existing chain.
+ * \assert
+ * \code chain != NULL \endcode
+ */
+FLAC_API void FLAC__metadata_chain_sort_padding(FLAC__Metadata_Chain *chain);
+
+
+/*********** FLAC__Metadata_Iterator ***********/
+
+/** Create a new iterator instance.
+ *
+ * \retval FLAC__Metadata_Iterator*
+ * \c NULL if there was an error allocating memory, else the new instance.
+ */
+FLAC_API FLAC__Metadata_Iterator *FLAC__metadata_iterator_new(void);
+
+/** Free an iterator instance. Deletes the object pointed to by \a iterator.
+ *
+ * \param iterator A pointer to an existing iterator.
+ * \assert
+ * \code iterator != NULL \endcode
+ */
+FLAC_API void FLAC__metadata_iterator_delete(FLAC__Metadata_Iterator *iterator);
+
+/** Initialize the iterator to point to the first metadata block in the
+ * given chain.
+ *
+ * \param iterator A pointer to an existing iterator.
+ * \param chain A pointer to an existing and initialized (read) chain.
+ * \assert
+ * \code iterator != NULL \endcode
+ * \code chain != NULL \endcode
+ */
+FLAC_API void FLAC__metadata_iterator_init(FLAC__Metadata_Iterator *iterator, FLAC__Metadata_Chain *chain);
+
+/** Moves the iterator forward one metadata block, returning \c false if
+ * already at the end.
+ *
+ * \param iterator A pointer to an existing initialized iterator.
+ * \assert
+ * \code iterator != NULL \endcode
+ * \a iterator has been successfully initialized with
+ * FLAC__metadata_iterator_init()
+ * \retval FLAC__bool
+ * \c false if already at the last metadata block of the chain, else
+ * \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_iterator_next(FLAC__Metadata_Iterator *iterator);
+
+/** Moves the iterator backward one metadata block, returning \c false if
+ * already at the beginning.
+ *
+ * \param iterator A pointer to an existing initialized iterator.
+ * \assert
+ * \code iterator != NULL \endcode
+ * \a iterator has been successfully initialized with
+ * FLAC__metadata_iterator_init()
+ * \retval FLAC__bool
+ * \c false if already at the first metadata block of the chain, else
+ * \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_iterator_prev(FLAC__Metadata_Iterator *iterator);
+
+/** Get the type of the metadata block at the current position.
+ *
+ * \param iterator A pointer to an existing initialized iterator.
+ * \assert
+ * \code iterator != NULL \endcode
+ * \a iterator has been successfully initialized with
+ * FLAC__metadata_iterator_init()
+ * \retval FLAC__MetadataType
+ * The type of the metadata block at the current iterator position.
+ */
+FLAC_API FLAC__MetadataType FLAC__metadata_iterator_get_block_type(const FLAC__Metadata_Iterator *iterator);
+
+/** Get the metadata block at the current position. You can modify
+ * the block in place but must write the chain before the changes
+ * are reflected to the FLAC file. You do not need to call
+ * FLAC__metadata_iterator_set_block() to reflect the changes;
+ * the pointer returned by FLAC__metadata_iterator_get_block()
+ * points directly into the chain.
+ *
+ * \warning
+ * Do not call FLAC__metadata_object_delete() on the returned object;
+ * to delete a block use FLAC__metadata_iterator_delete_block().
+ *
+ * \param iterator A pointer to an existing initialized iterator.
+ * \assert
+ * \code iterator != NULL \endcode
+ * \a iterator has been successfully initialized with
+ * FLAC__metadata_iterator_init()
+ * \retval FLAC__StreamMetadata*
+ * The current metadata block.
+ */
+FLAC_API FLAC__StreamMetadata *FLAC__metadata_iterator_get_block(FLAC__Metadata_Iterator *iterator);
+
+/** Set the metadata block at the current position, replacing the existing
+ * block. The new block passed in becomes owned by the chain and it will be
+ * deleted when the chain is deleted.
+ *
+ * \param iterator A pointer to an existing initialized iterator.
+ * \param block A pointer to a metadata block.
+ * \assert
+ * \code iterator != NULL \endcode
+ * \a iterator has been successfully initialized with
+ * FLAC__metadata_iterator_init()
+ * \code block != NULL \endcode
+ * \retval FLAC__bool
+ * \c false if the conditions in the above description are not met, or
+ * a memory allocation error occurs, otherwise \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_iterator_set_block(FLAC__Metadata_Iterator *iterator, FLAC__StreamMetadata *block);
+
+/** Removes the current block from the chain. If \a replace_with_padding is
+ * \c true, the block will instead be replaced with a padding block of equal
+ * size. You can not delete the STREAMINFO block. The iterator will be
+ * left pointing to the block before the one just "deleted", even if
+ * \a replace_with_padding is \c true.
+ *
+ * \param iterator A pointer to an existing initialized iterator.
+ * \param replace_with_padding See above.
+ * \assert
+ * \code iterator != NULL \endcode
+ * \a iterator has been successfully initialized with
+ * FLAC__metadata_iterator_init()
+ * \retval FLAC__bool
+ * \c false if the conditions in the above description are not met,
+ * otherwise \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_iterator_delete_block(FLAC__Metadata_Iterator *iterator, FLAC__bool replace_with_padding);
+
+/** Insert a new block before the current block. You cannot insert a block
+ * before the first STREAMINFO block. You cannot insert a STREAMINFO block
+ * as there can be only one, the one that already exists at the head when you
+ * read in a chain. The chain takes ownership of the new block and it will be
+ * deleted when the chain is deleted. The iterator will be left pointing to
+ * the new block.
+ *
+ * \param iterator A pointer to an existing initialized iterator.
+ * \param block A pointer to a metadata block to insert.
+ * \assert
+ * \code iterator != NULL \endcode
+ * \a iterator has been successfully initialized with
+ * FLAC__metadata_iterator_init()
+ * \retval FLAC__bool
+ * \c false if the conditions in the above description are not met, or
+ * a memory allocation error occurs, otherwise \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_iterator_insert_block_before(FLAC__Metadata_Iterator *iterator, FLAC__StreamMetadata *block);
+
+/** Insert a new block after the current block. You cannot insert a STREAMINFO
+ * block as there can be only one, the one that already exists at the head when
+ * you read in a chain. The chain takes ownership of the new block and it will
+ * be deleted when the chain is deleted. The iterator will be left pointing to
+ * the new block.
+ *
+ * \param iterator A pointer to an existing initialized iterator.
+ * \param block A pointer to a metadata block to insert.
+ * \assert
+ * \code iterator != NULL \endcode
+ * \a iterator has been successfully initialized with
+ * FLAC__metadata_iterator_init()
+ * \retval FLAC__bool
+ * \c false if the conditions in the above description are not met, or
+ * a memory allocation error occurs, otherwise \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_iterator_insert_block_after(FLAC__Metadata_Iterator *iterator, FLAC__StreamMetadata *block);
+
+/* \} */
+
+
+/** \defgroup flac_metadata_object FLAC/metadata.h: metadata object methods
+ * \ingroup flac_metadata
+ *
+ * \brief
+ * This module contains methods for manipulating FLAC metadata objects.
+ *
+ * Since many are variable length we have to be careful about the memory
+ * management. We decree that all pointers to data in the object are
+ * owned by the object and memory-managed by the object.
+ *
+ * Use the FLAC__metadata_object_new() and FLAC__metadata_object_delete()
+ * functions to create all instances. When using the
+ * FLAC__metadata_object_set_*() functions to set pointers to data, set
+ * \a copy to \c true to have the function make it's own copy of the data, or
+ * to \c false to give the object ownership of your data. In the latter case
+ * your pointer must be freeable by free() and will be free()d when the object
+ * is FLAC__metadata_object_delete()d. It is legal to pass a null pointer as
+ * the data pointer to a FLAC__metadata_object_set_*() function as long as
+ * the length argument is 0 and the \a copy argument is \c false.
+ *
+ * The FLAC__metadata_object_new() and FLAC__metadata_object_clone() function
+ * will return \c NULL in the case of a memory allocation error, otherwise a new
+ * object. The FLAC__metadata_object_set_*() functions return \c false in the
+ * case of a memory allocation error.
+ *
+ * We don't have the convenience of C++ here, so note that the library relies
+ * on you to keep the types straight. In other words, if you pass, for
+ * example, a FLAC__StreamMetadata* that represents a STREAMINFO block to
+ * FLAC__metadata_object_application_set_data(), you will get an assertion
+ * failure.
+ *
+ * For convenience the FLAC__metadata_object_vorbiscomment_*() functions
+ * maintain a trailing NUL on each Vorbis comment entry. This is not counted
+ * toward the length or stored in the stream, but it can make working with plain
+ * comments (those that don't contain embedded-NULs in the value) easier.
+ * Entries passed into these functions have trailing NULs added if missing, and
+ * returned entries are guaranteed to have a trailing NUL.
+ *
+ * The FLAC__metadata_object_vorbiscomment_*() functions that take a Vorbis
+ * comment entry/name/value will first validate that it complies with the Vorbis
+ * comment specification and return false if it does not.
+ *
+ * There is no need to recalculate the length field on metadata blocks you
+ * have modified. They will be calculated automatically before they are
+ * written back to a file.
+ *
+ * \{
+ */
+
+
+/** Create a new metadata object instance of the given type.
+ *
+ * The object will be "empty"; i.e. values and data pointers will be \c 0,
+ * with the exception of FLAC__METADATA_TYPE_VORBIS_COMMENT, which will have
+ * the vendor string set (but zero comments).
+ *
+ * Do not pass in a value greater than or equal to
+ * \a FLAC__METADATA_TYPE_UNDEFINED unless you really know what you're
+ * doing.
+ *
+ * \param type Type of object to create
+ * \retval FLAC__StreamMetadata*
+ * \c NULL if there was an error allocating memory or the type code is
+ * greater than FLAC__MAX_METADATA_TYPE_CODE, else the new instance.
+ */
+FLAC_API FLAC__StreamMetadata *FLAC__metadata_object_new(FLAC__MetadataType type);
+
+/** Create a copy of an existing metadata object.
+ *
+ * The copy is a "deep" copy, i.e. dynamically allocated data within the
+ * object is also copied. The caller takes ownership of the new block and
+ * is responsible for freeing it with FLAC__metadata_object_delete().
+ *
+ * \param object Pointer to object to copy.
+ * \assert
+ * \code object != NULL \endcode
+ * \retval FLAC__StreamMetadata*
+ * \c NULL if there was an error allocating memory, else the new instance.
+ */
+FLAC_API FLAC__StreamMetadata *FLAC__metadata_object_clone(const FLAC__StreamMetadata *object);
+
+/** Free a metadata object. Deletes the object pointed to by \a object.
+ *
+ * The delete is a "deep" delete, i.e. dynamically allocated data within the
+ * object is also deleted.
+ *
+ * \param object A pointer to an existing object.
+ * \assert
+ * \code object != NULL \endcode
+ */
+FLAC_API void FLAC__metadata_object_delete(FLAC__StreamMetadata *object);
+
+/** Compares two metadata objects.
+ *
+ * The compare is "deep", i.e. dynamically allocated data within the
+ * object is also compared.
+ *
+ * \param block1 A pointer to an existing object.
+ * \param block2 A pointer to an existing object.
+ * \assert
+ * \code block1 != NULL \endcode
+ * \code block2 != NULL \endcode
+ * \retval FLAC__bool
+ * \c true if objects are identical, else \c false.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_is_equal(const FLAC__StreamMetadata *block1, const FLAC__StreamMetadata *block2);
+
+/** Sets the application data of an APPLICATION block.
+ *
+ * If \a copy is \c true, a copy of the data is stored; otherwise, the object
+ * takes ownership of the pointer. The existing data will be freed if this
+ * function is successful, otherwise the original data will remain if \a copy
+ * is \c true and malloc() fails.
+ *
+ * \note It is safe to pass a const pointer to \a data if \a copy is \c true.
+ *
+ * \param object A pointer to an existing APPLICATION object.
+ * \param data A pointer to the data to set.
+ * \param length The length of \a data in bytes.
+ * \param copy See above.
+ * \assert
+ * \code object != NULL \endcode
+ * \code object->type == FLAC__METADATA_TYPE_APPLICATION \endcode
+ * \code (data != NULL && length > 0) ||
+ * (data == NULL && length == 0 && copy == false) \endcode
+ * \retval FLAC__bool
+ * \c false if \a copy is \c true and malloc() fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_application_set_data(FLAC__StreamMetadata *object, FLAC__byte *data, uint32_t length, FLAC__bool copy);
+
+/** Resize the seekpoint array.
+ *
+ * If the size shrinks, elements will truncated; if it grows, new placeholder
+ * points will be added to the end.
+ *
+ * \param object A pointer to an existing SEEKTABLE object.
+ * \param new_num_points The desired length of the array; may be \c 0.
+ * \assert
+ * \code object != NULL \endcode
+ * \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode
+ * \code (object->data.seek_table.points == NULL && object->data.seek_table.num_points == 0) ||
+ * (object->data.seek_table.points != NULL && object->data.seek_table.num_points > 0) \endcode
+ * \retval FLAC__bool
+ * \c false if memory allocation error, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_resize_points(FLAC__StreamMetadata *object, uint32_t new_num_points);
+
+/** Set a seekpoint in a seektable.
+ *
+ * \param object A pointer to an existing SEEKTABLE object.
+ * \param point_num Index into seekpoint array to set.
+ * \param point The point to set.
+ * \assert
+ * \code object != NULL \endcode
+ * \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode
+ * \code object->data.seek_table.num_points > point_num \endcode
+ */
+FLAC_API void FLAC__metadata_object_seektable_set_point(FLAC__StreamMetadata *object, uint32_t point_num, FLAC__StreamMetadata_SeekPoint point);
+
+/** Insert a seekpoint into a seektable.
+ *
+ * \param object A pointer to an existing SEEKTABLE object.
+ * \param point_num Index into seekpoint array to set.
+ * \param point The point to set.
+ * \assert
+ * \code object != NULL \endcode
+ * \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode
+ * \code object->data.seek_table.num_points >= point_num \endcode
+ * \retval FLAC__bool
+ * \c false if memory allocation error, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_insert_point(FLAC__StreamMetadata *object, uint32_t point_num, FLAC__StreamMetadata_SeekPoint point);
+
+/** Delete a seekpoint from a seektable.
+ *
+ * \param object A pointer to an existing SEEKTABLE object.
+ * \param point_num Index into seekpoint array to set.
+ * \assert
+ * \code object != NULL \endcode
+ * \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode
+ * \code object->data.seek_table.num_points > point_num \endcode
+ * \retval FLAC__bool
+ * \c false if memory allocation error, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_delete_point(FLAC__StreamMetadata *object, uint32_t point_num);
+
+/** Check a seektable to see if it conforms to the FLAC specification.
+ * See the format specification for limits on the contents of the
+ * seektable.
+ *
+ * \param object A pointer to an existing SEEKTABLE object.
+ * \assert
+ * \code object != NULL \endcode
+ * \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode
+ * \retval FLAC__bool
+ * \c false if seek table is illegal, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_is_legal(const FLAC__StreamMetadata *object);
+
+/** Append a number of placeholder points to the end of a seek table.
+ *
+ * \note
+ * As with the other ..._seektable_template_... functions, you should
+ * call FLAC__metadata_object_seektable_template_sort() when finished
+ * to make the seek table legal.
+ *
+ * \param object A pointer to an existing SEEKTABLE object.
+ * \param num The number of placeholder points to append.
+ * \assert
+ * \code object != NULL \endcode
+ * \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode
+ * \retval FLAC__bool
+ * \c false if memory allocation fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_placeholders(FLAC__StreamMetadata *object, uint32_t num);
+
+/** Append a specific seek point template to the end of a seek table.
+ *
+ * \note
+ * As with the other ..._seektable_template_... functions, you should
+ * call FLAC__metadata_object_seektable_template_sort() when finished
+ * to make the seek table legal.
+ *
+ * \param object A pointer to an existing SEEKTABLE object.
+ * \param sample_number The sample number of the seek point template.
+ * \assert
+ * \code object != NULL \endcode
+ * \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode
+ * \retval FLAC__bool
+ * \c false if memory allocation fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_point(FLAC__StreamMetadata *object, FLAC__uint64 sample_number);
+
+/** Append specific seek point templates to the end of a seek table.
+ *
+ * \note
+ * As with the other ..._seektable_template_... functions, you should
+ * call FLAC__metadata_object_seektable_template_sort() when finished
+ * to make the seek table legal.
+ *
+ * \param object A pointer to an existing SEEKTABLE object.
+ * \param sample_numbers An array of sample numbers for the seek points.
+ * \param num The number of seek point templates to append.
+ * \assert
+ * \code object != NULL \endcode
+ * \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode
+ * \retval FLAC__bool
+ * \c false if memory allocation fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_points(FLAC__StreamMetadata *object, FLAC__uint64 sample_numbers[], uint32_t num);
+
+/** Append a set of evenly-spaced seek point templates to the end of a
+ * seek table.
+ *
+ * \note
+ * As with the other ..._seektable_template_... functions, you should
+ * call FLAC__metadata_object_seektable_template_sort() when finished
+ * to make the seek table legal.
+ *
+ * \param object A pointer to an existing SEEKTABLE object.
+ * \param num The number of placeholder points to append.
+ * \param total_samples The total number of samples to be encoded;
+ * the seekpoints will be spaced approximately
+ * \a total_samples / \a num samples apart.
+ * \assert
+ * \code object != NULL \endcode
+ * \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode
+ * \code total_samples > 0 \endcode
+ * \retval FLAC__bool
+ * \c false if memory allocation fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_spaced_points(FLAC__StreamMetadata *object, uint32_t num, FLAC__uint64 total_samples);
+
+/** Append a set of evenly-spaced seek point templates to the end of a
+ * seek table.
+ *
+ * \note
+ * As with the other ..._seektable_template_... functions, you should
+ * call FLAC__metadata_object_seektable_template_sort() when finished
+ * to make the seek table legal.
+ *
+ * \param object A pointer to an existing SEEKTABLE object.
+ * \param samples The number of samples apart to space the placeholder
+ * points. The first point will be at sample \c 0, the
+ * second at sample \a samples, then 2*\a samples, and
+ * so on. As long as \a samples and \a total_samples
+ * are greater than \c 0, there will always be at least
+ * one seekpoint at sample \c 0.
+ * \param total_samples The total number of samples to be encoded;
+ * the seekpoints will be spaced
+ * \a samples samples apart.
+ * \assert
+ * \code object != NULL \endcode
+ * \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode
+ * \code samples > 0 \endcode
+ * \code total_samples > 0 \endcode
+ * \retval FLAC__bool
+ * \c false if memory allocation fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_spaced_points_by_samples(FLAC__StreamMetadata *object, uint32_t samples, FLAC__uint64 total_samples);
+
+/** Sort a seek table's seek points according to the format specification,
+ * removing duplicates.
+ *
+ * \param object A pointer to a seek table to be sorted.
+ * \param compact If \c false, behaves like FLAC__format_seektable_sort().
+ * If \c true, duplicates are deleted and the seek table is
+ * shrunk appropriately; the number of placeholder points
+ * present in the seek table will be the same after the call
+ * as before.
+ * \assert
+ * \code object != NULL \endcode
+ * \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode
+ * \retval FLAC__bool
+ * \c false if realloc() fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_sort(FLAC__StreamMetadata *object, FLAC__bool compact);
+
+/** Sets the vendor string in a VORBIS_COMMENT block.
+ *
+ * For convenience, a trailing NUL is added to the entry if it doesn't have
+ * one already.
+ *
+ * If \a copy is \c true, a copy of the entry is stored; otherwise, the object
+ * takes ownership of the \c entry.entry pointer.
+ *
+ * \note If this function returns \c false, the caller still owns the
+ * pointer.
+ *
+ * \param object A pointer to an existing VORBIS_COMMENT object.
+ * \param entry The entry to set the vendor string to.
+ * \param copy See above.
+ * \assert
+ * \code object != NULL \endcode
+ * \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode
+ * \code (entry.entry != NULL && entry.length > 0) ||
+ * (entry.entry == NULL && entry.length == 0) \endcode
+ * \retval FLAC__bool
+ * \c false if memory allocation fails or \a entry does not comply with the
+ * Vorbis comment specification, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_set_vendor_string(FLAC__StreamMetadata *object, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy);
+
+/** Resize the comment array.
+ *
+ * If the size shrinks, elements will truncated; if it grows, new empty
+ * fields will be added to the end.
+ *
+ * \param object A pointer to an existing VORBIS_COMMENT object.
+ * \param new_num_comments The desired length of the array; may be \c 0.
+ * \assert
+ * \code object != NULL \endcode
+ * \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode
+ * \code (object->data.vorbis_comment.comments == NULL && object->data.vorbis_comment.num_comments == 0) ||
+ * (object->data.vorbis_comment.comments != NULL && object->data.vorbis_comment.num_comments > 0) \endcode
+ * \retval FLAC__bool
+ * \c false if memory allocation fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_resize_comments(FLAC__StreamMetadata *object, uint32_t new_num_comments);
+
+/** Sets a comment in a VORBIS_COMMENT block.
+ *
+ * For convenience, a trailing NUL is added to the entry if it doesn't have
+ * one already.
+ *
+ * If \a copy is \c true, a copy of the entry is stored; otherwise, the object
+ * takes ownership of the \c entry.entry pointer.
+ *
+ * \note If this function returns \c false, the caller still owns the
+ * pointer.
+ *
+ * \param object A pointer to an existing VORBIS_COMMENT object.
+ * \param comment_num Index into comment array to set.
+ * \param entry The entry to set the comment to.
+ * \param copy See above.
+ * \assert
+ * \code object != NULL \endcode
+ * \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode
+ * \code comment_num < object->data.vorbis_comment.num_comments \endcode
+ * \code (entry.entry != NULL && entry.length > 0) ||
+ * (entry.entry == NULL && entry.length == 0) \endcode
+ * \retval FLAC__bool
+ * \c false if memory allocation fails or \a entry does not comply with the
+ * Vorbis comment specification, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_set_comment(FLAC__StreamMetadata *object, uint32_t comment_num, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy);
+
+/** Insert a comment in a VORBIS_COMMENT block at the given index.
+ *
+ * For convenience, a trailing NUL is added to the entry if it doesn't have
+ * one already.
+ *
+ * If \a copy is \c true, a copy of the entry is stored; otherwise, the object
+ * takes ownership of the \c entry.entry pointer.
+ *
+ * \note If this function returns \c false, the caller still owns the
+ * pointer.
+ *
+ * \param object A pointer to an existing VORBIS_COMMENT object.
+ * \param comment_num The index at which to insert the comment. The comments
+ * at and after \a comment_num move right one position.
+ * To append a comment to the end, set \a comment_num to
+ * \c object->data.vorbis_comment.num_comments .
+ * \param entry The comment to insert.
+ * \param copy See above.
+ * \assert
+ * \code object != NULL \endcode
+ * \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode
+ * \code object->data.vorbis_comment.num_comments >= comment_num \endcode
+ * \code (entry.entry != NULL && entry.length > 0) ||
+ * (entry.entry == NULL && entry.length == 0 && copy == false) \endcode
+ * \retval FLAC__bool
+ * \c false if memory allocation fails or \a entry does not comply with the
+ * Vorbis comment specification, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_insert_comment(FLAC__StreamMetadata *object, uint32_t comment_num, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy);
+
+/** Appends a comment to a VORBIS_COMMENT block.
+ *
+ * For convenience, a trailing NUL is added to the entry if it doesn't have
+ * one already.
+ *
+ * If \a copy is \c true, a copy of the entry is stored; otherwise, the object
+ * takes ownership of the \c entry.entry pointer.
+ *
+ * \note If this function returns \c false, the caller still owns the
+ * pointer.
+ *
+ * \param object A pointer to an existing VORBIS_COMMENT object.
+ * \param entry The comment to insert.
+ * \param copy See above.
+ * \assert
+ * \code object != NULL \endcode
+ * \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode
+ * \code (entry.entry != NULL && entry.length > 0) ||
+ * (entry.entry == NULL && entry.length == 0 && copy == false) \endcode
+ * \retval FLAC__bool
+ * \c false if memory allocation fails or \a entry does not comply with the
+ * Vorbis comment specification, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_append_comment(FLAC__StreamMetadata *object, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy);
+
+/** Replaces comments in a VORBIS_COMMENT block with a new one.
+ *
+ * For convenience, a trailing NUL is added to the entry if it doesn't have
+ * one already.
+ *
+ * Depending on the value of \a all, either all or just the first comment
+ * whose field name(s) match the given entry's name will be replaced by the
+ * given entry. If no comments match, \a entry will simply be appended.
+ *
+ * If \a copy is \c true, a copy of the entry is stored; otherwise, the object
+ * takes ownership of the \c entry.entry pointer.
+ *
+ * \note If this function returns \c false, the caller still owns the
+ * pointer.
+ *
+ * \param object A pointer to an existing VORBIS_COMMENT object.
+ * \param entry The comment to insert.
+ * \param all If \c true, all comments whose field name matches
+ * \a entry's field name will be removed, and \a entry will
+ * be inserted at the position of the first matching
+ * comment. If \c false, only the first comment whose
+ * field name matches \a entry's field name will be
+ * replaced with \a entry.
+ * \param copy See above.
+ * \assert
+ * \code object != NULL \endcode
+ * \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode
+ * \code (entry.entry != NULL && entry.length > 0) ||
+ * (entry.entry == NULL && entry.length == 0 && copy == false) \endcode
+ * \retval FLAC__bool
+ * \c false if memory allocation fails or \a entry does not comply with the
+ * Vorbis comment specification, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_replace_comment(FLAC__StreamMetadata *object, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool all, FLAC__bool copy);
+
+/** Delete a comment in a VORBIS_COMMENT block at the given index.
+ *
+ * \param object A pointer to an existing VORBIS_COMMENT object.
+ * \param comment_num The index of the comment to delete.
+ * \assert
+ * \code object != NULL \endcode
+ * \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode
+ * \code object->data.vorbis_comment.num_comments > comment_num \endcode
+ * \retval FLAC__bool
+ * \c false if realloc() fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_delete_comment(FLAC__StreamMetadata *object, uint32_t comment_num);
+
+/** Creates a Vorbis comment entry from NUL-terminated name and value strings.
+ *
+ * On return, the filled-in \a entry->entry pointer will point to malloc()ed
+ * memory and shall be owned by the caller. For convenience the entry will
+ * have a terminating NUL.
+ *
+ * \param entry A pointer to a Vorbis comment entry. The entry's
+ * \c entry pointer should not point to allocated
+ * memory as it will be overwritten.
+ * \param field_name The field name in ASCII, \c NUL terminated.
+ * \param field_value The field value in UTF-8, \c NUL terminated.
+ * \assert
+ * \code entry != NULL \endcode
+ * \code field_name != NULL \endcode
+ * \code field_value != NULL \endcode
+ * \retval FLAC__bool
+ * \c false if malloc() fails, or if \a field_name or \a field_value does
+ * not comply with the Vorbis comment specification, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(FLAC__StreamMetadata_VorbisComment_Entry *entry, const char *field_name, const char *field_value);
+
+/** Splits a Vorbis comment entry into NUL-terminated name and value strings.
+ *
+ * The returned pointers to name and value will be allocated by malloc()
+ * and shall be owned by the caller.
+ *
+ * \param entry An existing Vorbis comment entry.
+ * \param field_name The address of where the returned pointer to the
+ * field name will be stored.
+ * \param field_value The address of where the returned pointer to the
+ * field value will be stored.
+ * \assert
+ * \code (entry.entry != NULL && entry.length > 0) \endcode
+ * \code memchr(entry.entry, '=', entry.length) != NULL \endcode
+ * \code field_name != NULL \endcode
+ * \code field_value != NULL \endcode
+ * \retval FLAC__bool
+ * \c false if memory allocation fails or \a entry does not comply with the
+ * Vorbis comment specification, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_entry_to_name_value_pair(const FLAC__StreamMetadata_VorbisComment_Entry entry, char **field_name, char **field_value);
+
+/** Check if the given Vorbis comment entry's field name matches the given
+ * field name.
+ *
+ * \param entry An existing Vorbis comment entry.
+ * \param field_name The field name to check.
+ * \param field_name_length The length of \a field_name, not including the
+ * terminating \c NUL.
+ * \assert
+ * \code (entry.entry != NULL && entry.length > 0) \endcode
+ * \retval FLAC__bool
+ * \c true if the field names match, else \c false
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_entry_matches(const FLAC__StreamMetadata_VorbisComment_Entry entry, const char *field_name, uint32_t field_name_length);
+
+/** Find a Vorbis comment with the given field name.
+ *
+ * The search begins at entry number \a offset; use an offset of 0 to
+ * search from the beginning of the comment array.
+ *
+ * \param object A pointer to an existing VORBIS_COMMENT object.
+ * \param offset The offset into the comment array from where to start
+ * the search.
+ * \param field_name The field name of the comment to find.
+ * \assert
+ * \code object != NULL \endcode
+ * \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode
+ * \code field_name != NULL \endcode
+ * \retval int
+ * The offset in the comment array of the first comment whose field
+ * name matches \a field_name, or \c -1 if no match was found.
+ */
+FLAC_API int FLAC__metadata_object_vorbiscomment_find_entry_from(const FLAC__StreamMetadata *object, uint32_t offset, const char *field_name);
+
+/** Remove first Vorbis comment matching the given field name.
+ *
+ * \param object A pointer to an existing VORBIS_COMMENT object.
+ * \param field_name The field name of comment to delete.
+ * \assert
+ * \code object != NULL \endcode
+ * \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode
+ * \retval int
+ * \c -1 for memory allocation error, \c 0 for no matching entries,
+ * \c 1 for one matching entry deleted.
+ */
+FLAC_API int FLAC__metadata_object_vorbiscomment_remove_entry_matching(FLAC__StreamMetadata *object, const char *field_name);
+
+/** Remove all Vorbis comments matching the given field name.
+ *
+ * \param object A pointer to an existing VORBIS_COMMENT object.
+ * \param field_name The field name of comments to delete.
+ * \assert
+ * \code object != NULL \endcode
+ * \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode
+ * \retval int
+ * \c -1 for memory allocation error, \c 0 for no matching entries,
+ * else the number of matching entries deleted.
+ */
+FLAC_API int FLAC__metadata_object_vorbiscomment_remove_entries_matching(FLAC__StreamMetadata *object, const char *field_name);
+
+/** Create a new CUESHEET track instance.
+ *
+ * The object will be "empty"; i.e. values and data pointers will be \c 0.
+ *
+ * \retval FLAC__StreamMetadata_CueSheet_Track*
+ * \c NULL if there was an error allocating memory, else the new instance.
+ */
+FLAC_API FLAC__StreamMetadata_CueSheet_Track *FLAC__metadata_object_cuesheet_track_new(void);
+
+/** Create a copy of an existing CUESHEET track object.
+ *
+ * The copy is a "deep" copy, i.e. dynamically allocated data within the
+ * object is also copied. The caller takes ownership of the new object and
+ * is responsible for freeing it with
+ * FLAC__metadata_object_cuesheet_track_delete().
+ *
+ * \param object Pointer to object to copy.
+ * \assert
+ * \code object != NULL \endcode
+ * \retval FLAC__StreamMetadata_CueSheet_Track*
+ * \c NULL if there was an error allocating memory, else the new instance.
+ */
+FLAC_API FLAC__StreamMetadata_CueSheet_Track *FLAC__metadata_object_cuesheet_track_clone(const FLAC__StreamMetadata_CueSheet_Track *object);
+
+/** Delete a CUESHEET track object
+ *
+ * \param object A pointer to an existing CUESHEET track object.
+ * \assert
+ * \code object != NULL \endcode
+ */
+FLAC_API void FLAC__metadata_object_cuesheet_track_delete(FLAC__StreamMetadata_CueSheet_Track *object);
+
+/** Resize a track's index point array.
+ *
+ * If the size shrinks, elements will truncated; if it grows, new blank
+ * indices will be added to the end.
+ *
+ * \param object A pointer to an existing CUESHEET object.
+ * \param track_num The index of the track to modify. NOTE: this is not
+ * necessarily the same as the track's \a number field.
+ * \param new_num_indices The desired length of the array; may be \c 0.
+ * \assert
+ * \code object != NULL \endcode
+ * \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode
+ * \code object->data.cue_sheet.num_tracks > track_num \endcode
+ * \code (object->data.cue_sheet.tracks[track_num].indices == NULL && object->data.cue_sheet.tracks[track_num].num_indices == 0) ||
+ * (object->data.cue_sheet.tracks[track_num].indices != NULL && object->data.cue_sheet.tracks[track_num].num_indices > 0) \endcode
+ * \retval FLAC__bool
+ * \c false if memory allocation error, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_resize_indices(FLAC__StreamMetadata *object, uint32_t track_num, uint32_t new_num_indices);
+
+/** Insert an index point in a CUESHEET track at the given index.
+ *
+ * \param object A pointer to an existing CUESHEET object.
+ * \param track_num The index of the track to modify. NOTE: this is not
+ * necessarily the same as the track's \a number field.
+ * \param index_num The index into the track's index array at which to
+ * insert the index point. NOTE: this is not necessarily
+ * the same as the index point's \a number field. The
+ * indices at and after \a index_num move right one
+ * position. To append an index point to the end, set
+ * \a index_num to
+ * \c object->data.cue_sheet.tracks[track_num].num_indices .
+ * \param index The index point to insert.
+ * \assert
+ * \code object != NULL \endcode
+ * \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode
+ * \code object->data.cue_sheet.num_tracks > track_num \endcode
+ * \code object->data.cue_sheet.tracks[track_num].num_indices >= index_num \endcode
+ * \retval FLAC__bool
+ * \c false if realloc() fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_insert_index(FLAC__StreamMetadata *object, uint32_t track_num, uint32_t index_num, FLAC__StreamMetadata_CueSheet_Index index);
+
+/** Insert a blank index point in a CUESHEET track at the given index.
+ *
+ * A blank index point is one in which all field values are zero.
+ *
+ * \param object A pointer to an existing CUESHEET object.
+ * \param track_num The index of the track to modify. NOTE: this is not
+ * necessarily the same as the track's \a number field.
+ * \param index_num The index into the track's index array at which to
+ * insert the index point. NOTE: this is not necessarily
+ * the same as the index point's \a number field. The
+ * indices at and after \a index_num move right one
+ * position. To append an index point to the end, set
+ * \a index_num to
+ * \c object->data.cue_sheet.tracks[track_num].num_indices .
+ * \assert
+ * \code object != NULL \endcode
+ * \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode
+ * \code object->data.cue_sheet.num_tracks > track_num \endcode
+ * \code object->data.cue_sheet.tracks[track_num].num_indices >= index_num \endcode
+ * \retval FLAC__bool
+ * \c false if realloc() fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_insert_blank_index(FLAC__StreamMetadata *object, uint32_t track_num, uint32_t index_num);
+
+/** Delete an index point in a CUESHEET track at the given index.
+ *
+ * \param object A pointer to an existing CUESHEET object.
+ * \param track_num The index into the track array of the track to
+ * modify. NOTE: this is not necessarily the same
+ * as the track's \a number field.
+ * \param index_num The index into the track's index array of the index
+ * to delete. NOTE: this is not necessarily the same
+ * as the index's \a number field.
+ * \assert
+ * \code object != NULL \endcode
+ * \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode
+ * \code object->data.cue_sheet.num_tracks > track_num \endcode
+ * \code object->data.cue_sheet.tracks[track_num].num_indices > index_num \endcode
+ * \retval FLAC__bool
+ * \c false if realloc() fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_delete_index(FLAC__StreamMetadata *object, uint32_t track_num, uint32_t index_num);
+
+/** Resize the track array.
+ *
+ * If the size shrinks, elements will truncated; if it grows, new blank
+ * tracks will be added to the end.
+ *
+ * \param object A pointer to an existing CUESHEET object.
+ * \param new_num_tracks The desired length of the array; may be \c 0.
+ * \assert
+ * \code object != NULL \endcode
+ * \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode
+ * \code (object->data.cue_sheet.tracks == NULL && object->data.cue_sheet.num_tracks == 0) ||
+ * (object->data.cue_sheet.tracks != NULL && object->data.cue_sheet.num_tracks > 0) \endcode
+ * \retval FLAC__bool
+ * \c false if memory allocation error, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_resize_tracks(FLAC__StreamMetadata *object, uint32_t new_num_tracks);
+
+/** Sets a track in a CUESHEET block.
+ *
+ * If \a copy is \c true, a copy of the track is stored; otherwise, the object
+ * takes ownership of the \a track pointer.
+ *
+ * \param object A pointer to an existing CUESHEET object.
+ * \param track_num Index into track array to set. NOTE: this is not
+ * necessarily the same as the track's \a number field.
+ * \param track The track to set the track to. You may safely pass in
+ * a const pointer if \a copy is \c true.
+ * \param copy See above.
+ * \assert
+ * \code object != NULL \endcode
+ * \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode
+ * \code track_num < object->data.cue_sheet.num_tracks \endcode
+ * \code (track->indices != NULL && track->num_indices > 0) ||
+ * (track->indices == NULL && track->num_indices == 0) \endcode
+ * \retval FLAC__bool
+ * \c false if \a copy is \c true and malloc() fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_set_track(FLAC__StreamMetadata *object, uint32_t track_num, FLAC__StreamMetadata_CueSheet_Track *track, FLAC__bool copy);
+
+/** Insert a track in a CUESHEET block at the given index.
+ *
+ * If \a copy is \c true, a copy of the track is stored; otherwise, the object
+ * takes ownership of the \a track pointer.
+ *
+ * \param object A pointer to an existing CUESHEET object.
+ * \param track_num The index at which to insert the track. NOTE: this
+ * is not necessarily the same as the track's \a number
+ * field. The tracks at and after \a track_num move right
+ * one position. To append a track to the end, set
+ * \a track_num to \c object->data.cue_sheet.num_tracks .
+ * \param track The track to insert. You may safely pass in a const
+ * pointer if \a copy is \c true.
+ * \param copy See above.
+ * \assert
+ * \code object != NULL \endcode
+ * \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode
+ * \code object->data.cue_sheet.num_tracks >= track_num \endcode
+ * \retval FLAC__bool
+ * \c false if \a copy is \c true and malloc() fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_insert_track(FLAC__StreamMetadata *object, uint32_t track_num, FLAC__StreamMetadata_CueSheet_Track *track, FLAC__bool copy);
+
+/** Insert a blank track in a CUESHEET block at the given index.
+ *
+ * A blank track is one in which all field values are zero.
+ *
+ * \param object A pointer to an existing CUESHEET object.
+ * \param track_num The index at which to insert the track. NOTE: this
+ * is not necessarily the same as the track's \a number
+ * field. The tracks at and after \a track_num move right
+ * one position. To append a track to the end, set
+ * \a track_num to \c object->data.cue_sheet.num_tracks .
+ * \assert
+ * \code object != NULL \endcode
+ * \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode
+ * \code object->data.cue_sheet.num_tracks >= track_num \endcode
+ * \retval FLAC__bool
+ * \c false if \a copy is \c true and malloc() fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_insert_blank_track(FLAC__StreamMetadata *object, uint32_t track_num);
+
+/** Delete a track in a CUESHEET block at the given index.
+ *
+ * \param object A pointer to an existing CUESHEET object.
+ * \param track_num The index into the track array of the track to
+ * delete. NOTE: this is not necessarily the same
+ * as the track's \a number field.
+ * \assert
+ * \code object != NULL \endcode
+ * \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode
+ * \code object->data.cue_sheet.num_tracks > track_num \endcode
+ * \retval FLAC__bool
+ * \c false if realloc() fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_delete_track(FLAC__StreamMetadata *object, uint32_t track_num);
+
+/** Check a cue sheet to see if it conforms to the FLAC specification.
+ * See the format specification for limits on the contents of the
+ * cue sheet.
+ *
+ * \param object A pointer to an existing CUESHEET object.
+ * \param check_cd_da_subset If \c true, check CUESHEET against more
+ * stringent requirements for a CD-DA (audio) disc.
+ * \param violation Address of a pointer to a string. If there is a
+ * violation, a pointer to a string explanation of the
+ * violation will be returned here. \a violation may be
+ * \c NULL if you don't need the returned string. Do not
+ * free the returned string; it will always point to static
+ * data.
+ * \assert
+ * \code object != NULL \endcode
+ * \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode
+ * \retval FLAC__bool
+ * \c false if cue sheet is illegal, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_is_legal(const FLAC__StreamMetadata *object, FLAC__bool check_cd_da_subset, const char **violation);
+
+/** Calculate and return the CDDB/freedb ID for a cue sheet. The function
+ * assumes the cue sheet corresponds to a CD; the result is undefined
+ * if the cuesheet's is_cd bit is not set.
+ *
+ * \param object A pointer to an existing CUESHEET object.
+ * \assert
+ * \code object != NULL \endcode
+ * \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode
+ * \retval FLAC__uint32
+ * The unsigned integer representation of the CDDB/freedb ID
+ */
+FLAC_API FLAC__uint32 FLAC__metadata_object_cuesheet_calculate_cddb_id(const FLAC__StreamMetadata *object);
+
+/** Sets the MIME type of a PICTURE block.
+ *
+ * If \a copy is \c true, a copy of the string is stored; otherwise, the object
+ * takes ownership of the pointer. The existing string will be freed if this
+ * function is successful, otherwise the original string will remain if \a copy
+ * is \c true and malloc() fails.
+ *
+ * \note It is safe to pass a const pointer to \a mime_type if \a copy is \c true.
+ *
+ * \param object A pointer to an existing PICTURE object.
+ * \param mime_type A pointer to the MIME type string. The string must be
+ * ASCII characters 0x20-0x7e, NUL-terminated. No validation
+ * is done.
+ * \param copy See above.
+ * \assert
+ * \code object != NULL \endcode
+ * \code object->type == FLAC__METADATA_TYPE_PICTURE \endcode
+ * \code (mime_type != NULL) \endcode
+ * \retval FLAC__bool
+ * \c false if \a copy is \c true and malloc() fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_picture_set_mime_type(FLAC__StreamMetadata *object, char *mime_type, FLAC__bool copy);
+
+/** Sets the description of a PICTURE block.
+ *
+ * If \a copy is \c true, a copy of the string is stored; otherwise, the object
+ * takes ownership of the pointer. The existing string will be freed if this
+ * function is successful, otherwise the original string will remain if \a copy
+ * is \c true and malloc() fails.
+ *
+ * \note It is safe to pass a const pointer to \a description if \a copy is \c true.
+ *
+ * \param object A pointer to an existing PICTURE object.
+ * \param description A pointer to the description string. The string must be
+ * valid UTF-8, NUL-terminated. No validation is done.
+ * \param copy See above.
+ * \assert
+ * \code object != NULL \endcode
+ * \code object->type == FLAC__METADATA_TYPE_PICTURE \endcode
+ * \code (description != NULL) \endcode
+ * \retval FLAC__bool
+ * \c false if \a copy is \c true and malloc() fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_picture_set_description(FLAC__StreamMetadata *object, FLAC__byte *description, FLAC__bool copy);
+
+/** Sets the picture data of a PICTURE block.
+ *
+ * If \a copy is \c true, a copy of the data is stored; otherwise, the object
+ * takes ownership of the pointer. Also sets the \a data_length field of the
+ * metadata object to what is passed in as the \a length parameter. The
+ * existing data will be freed if this function is successful, otherwise the
+ * original data and data_length will remain if \a copy is \c true and
+ * malloc() fails.
+ *
+ * \note It is safe to pass a const pointer to \a data if \a copy is \c true.
+ *
+ * \param object A pointer to an existing PICTURE object.
+ * \param data A pointer to the data to set.
+ * \param length The length of \a data in bytes.
+ * \param copy See above.
+ * \assert
+ * \code object != NULL \endcode
+ * \code object->type == FLAC__METADATA_TYPE_PICTURE \endcode
+ * \code (data != NULL && length > 0) ||
+ * (data == NULL && length == 0 && copy == false) \endcode
+ * \retval FLAC__bool
+ * \c false if \a copy is \c true and malloc() fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_picture_set_data(FLAC__StreamMetadata *object, FLAC__byte *data, FLAC__uint32 length, FLAC__bool copy);
+
+/** Check a PICTURE block to see if it conforms to the FLAC specification.
+ * See the format specification for limits on the contents of the
+ * PICTURE block.
+ *
+ * \param object A pointer to existing PICTURE block to be checked.
+ * \param violation Address of a pointer to a string. If there is a
+ * violation, a pointer to a string explanation of the
+ * violation will be returned here. \a violation may be
+ * \c NULL if you don't need the returned string. Do not
+ * free the returned string; it will always point to static
+ * data.
+ * \assert
+ * \code object != NULL \endcode
+ * \code object->type == FLAC__METADATA_TYPE_PICTURE \endcode
+ * \retval FLAC__bool
+ * \c false if PICTURE block is illegal, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_picture_is_legal(const FLAC__StreamMetadata *object, const char **violation);
+
+/* \} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
+++ b/src/libflac/FLAC/ordinals.h
@@ -1,0 +1,85 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000-2009 Josh Coalson
+ * Copyright (C) 2011-2016 Xiph.Org Foundation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__ORDINALS_H
+#define FLAC__ORDINALS_H
+
+#if defined(_MSC_VER) && _MSC_VER < 1600
+
+/* Microsoft Visual Studio earlier than the 2010 version did not provide
+ * the 1999 ISO C Standard header file <stdint.h>.
+ */
+
+typedef signed __int8 FLAC__int8;
+typedef signed __int16 FLAC__int16;
+typedef signed __int32 FLAC__int32;
+typedef signed __int64 FLAC__int64;
+typedef unsigned __int8 FLAC__uint8;
+typedef unsigned __int16 FLAC__uint16;
+typedef unsigned __int32 FLAC__uint32;
+typedef unsigned __int64 FLAC__uint64;
+
+#else
+
+/* For MSVC 2010 and everything else which provides <stdint.h>. */
+
+#include <stdint.h>
+
+typedef int8_t FLAC__int8;
+typedef uint8_t FLAC__uint8;
+
+typedef int16_t FLAC__int16;
+typedef int32_t FLAC__int32;
+typedef int64_t FLAC__int64;
+typedef uint16_t FLAC__uint16;
+typedef uint32_t FLAC__uint32;
+typedef uint64_t FLAC__uint64;
+
+#endif
+
+typedef int FLAC__bool;
+
+typedef FLAC__uint8 FLAC__byte;
+
+
+#ifdef true
+#undef true
+#endif
+#ifdef false
+#undef false
+#endif
+#ifndef __cplusplus
+#define true 1
+#define false 0
+#endif
+
+#endif
--- /dev/null
+++ b/src/libflac/FLAC/stream_decoder.h
@@ -1,0 +1,1559 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000-2009 Josh Coalson
+ * Copyright (C) 2011-2016 Xiph.Org Foundation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__STREAM_DECODER_H
+#define FLAC__STREAM_DECODER_H
+
+#include <stdio.h> /* for FILE */
+#include "export.h"
+#include "format.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/** \file include/FLAC/stream_decoder.h
+ *
+ * \brief
+ * This module contains the functions which implement the stream
+ * decoder.
+ *
+ * See the detailed documentation in the
+ * \link flac_stream_decoder stream decoder \endlink module.
+ */
+
+/** \defgroup flac_decoder FLAC/ \*_decoder.h: decoder interfaces
+ * \ingroup flac
+ *
+ * \brief
+ * This module describes the decoder layers provided by libFLAC.
+ *
+ * The stream decoder can be used to decode complete streams either from
+ * the client via callbacks, or directly from a file, depending on how
+ * it is initialized. When decoding via callbacks, the client provides
+ * callbacks for reading FLAC data and writing decoded samples, and
+ * handling metadata and errors. If the client also supplies seek-related
+ * callback, the decoder function for sample-accurate seeking within the
+ * FLAC input is also available. When decoding from a file, the client
+ * needs only supply a filename or open \c FILE* and write/metadata/error
+ * callbacks; the rest of the callbacks are supplied internally. For more
+ * info see the \link flac_stream_decoder stream decoder \endlink module.
+ */
+
+/** \defgroup flac_stream_decoder FLAC/stream_decoder.h: stream decoder interface
+ * \ingroup flac_decoder
+ *
+ * \brief
+ * This module contains the functions which implement the stream
+ * decoder.
+ *
+ * The stream decoder can decode native FLAC, and optionally Ogg FLAC
+ * (check FLAC_API_SUPPORTS_OGG_FLAC) streams and files.
+ *
+ * The basic usage of this decoder is as follows:
+ * - The program creates an instance of a decoder using
+ * FLAC__stream_decoder_new().
+ * - The program overrides the default settings using
+ * FLAC__stream_decoder_set_*() functions.
+ * - The program initializes the instance to validate the settings and
+ * prepare for decoding using
+ * - FLAC__stream_decoder_init_stream() or FLAC__stream_decoder_init_FILE()
+ * or FLAC__stream_decoder_init_file() for native FLAC,
+ * - FLAC__stream_decoder_init_ogg_stream() or FLAC__stream_decoder_init_ogg_FILE()
+ * or FLAC__stream_decoder_init_ogg_file() for Ogg FLAC
+ * - The program calls the FLAC__stream_decoder_process_*() functions
+ * to decode data, which subsequently calls the callbacks.
+ * - The program finishes the decoding with FLAC__stream_decoder_finish(),
+ * which flushes the input and output and resets the decoder to the
+ * uninitialized state.
+ * - The instance may be used again or deleted with
+ * FLAC__stream_decoder_delete().
+ *
+ * In more detail, the program will create a new instance by calling
+ * FLAC__stream_decoder_new(), then call FLAC__stream_decoder_set_*()
+ * functions to override the default decoder options, and call
+ * one of the FLAC__stream_decoder_init_*() functions.
+ *
+ * There are three initialization functions for native FLAC, one for
+ * setting up the decoder to decode FLAC data from the client via
+ * callbacks, and two for decoding directly from a FLAC file.
+ *
+ * For decoding via callbacks, use FLAC__stream_decoder_init_stream().
+ * You must also supply several callbacks for handling I/O. Some (like
+ * seeking) are optional, depending on the capabilities of the input.
+ *
+ * For decoding directly from a file, use FLAC__stream_decoder_init_FILE()
+ * or FLAC__stream_decoder_init_file(). Then you must only supply an open
+ * \c FILE* or filename and fewer callbacks; the decoder will handle
+ * the other callbacks internally.
+ *
+ * There are three similarly-named init functions for decoding from Ogg
+ * FLAC streams. Check \c FLAC_API_SUPPORTS_OGG_FLAC to find out if the
+ * library has been built with Ogg support.
+ *
+ * Once the decoder is initialized, your program will call one of several
+ * functions to start the decoding process:
+ *
+ * - FLAC__stream_decoder_process_single() - Tells the decoder to process at
+ * most one metadata block or audio frame and return, calling either the
+ * metadata callback or write callback, respectively, once. If the decoder
+ * loses sync it will return with only the error callback being called.
+ * - FLAC__stream_decoder_process_until_end_of_metadata() - Tells the decoder
+ * to process the stream from the current location and stop upon reaching
+ * the first audio frame. The client will get one metadata, write, or error
+ * callback per metadata block, audio frame, or sync error, respectively.
+ * - FLAC__stream_decoder_process_until_end_of_stream() - Tells the decoder
+ * to process the stream from the current location until the read callback
+ * returns FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM or
+ * FLAC__STREAM_DECODER_READ_STATUS_ABORT. The client will get one metadata,
+ * write, or error callback per metadata block, audio frame, or sync error,
+ * respectively.
+ *
+ * When the decoder has finished decoding (normally or through an abort),
+ * the instance is finished by calling FLAC__stream_decoder_finish(), which
+ * ensures the decoder is in the correct state and frees memory. Then the
+ * instance may be deleted with FLAC__stream_decoder_delete() or initialized
+ * again to decode another stream.
+ *
+ * Seeking is exposed through the FLAC__stream_decoder_seek_absolute() method.
+ * At any point after the stream decoder has been initialized, the client can
+ * call this function to seek to an exact sample within the stream.
+ * Subsequently, the first time the write callback is called it will be
+ * passed a (possibly partial) block starting at that sample.
+ *
+ * If the client cannot seek via the callback interface provided, but still
+ * has another way of seeking, it can flush the decoder using
+ * FLAC__stream_decoder_flush() and start feeding data from the new position
+ * through the read callback.
+ *
+ * The stream decoder also provides MD5 signature checking. If this is
+ * turned on before initialization, FLAC__stream_decoder_finish() will
+ * report when the decoded MD5 signature does not match the one stored
+ * in the STREAMINFO block. MD5 checking is automatically turned off
+ * (until the next FLAC__stream_decoder_reset()) if there is no signature
+ * in the STREAMINFO block or when a seek is attempted.
+ *
+ * The FLAC__stream_decoder_set_metadata_*() functions deserve special
+ * attention. By default, the decoder only calls the metadata_callback for
+ * the STREAMINFO block. These functions allow you to tell the decoder
+ * explicitly which blocks to parse and return via the metadata_callback
+ * and/or which to skip. Use a FLAC__stream_decoder_set_metadata_respond_all(),
+ * FLAC__stream_decoder_set_metadata_ignore() ... or FLAC__stream_decoder_set_metadata_ignore_all(),
+ * FLAC__stream_decoder_set_metadata_respond() ... sequence to exactly specify
+ * which blocks to return. Remember that metadata blocks can potentially
+ * be big (for example, cover art) so filtering out the ones you don't
+ * use can reduce the memory requirements of the decoder. Also note the
+ * special forms FLAC__stream_decoder_set_metadata_respond_application(id)
+ * and FLAC__stream_decoder_set_metadata_ignore_application(id) for
+ * filtering APPLICATION blocks based on the application ID.
+ *
+ * STREAMINFO and SEEKTABLE blocks are always parsed and used internally, but
+ * they still can legally be filtered from the metadata_callback.
+ *
+ * \note
+ * The "set" functions may only be called when the decoder is in the
+ * state FLAC__STREAM_DECODER_UNINITIALIZED, i.e. after
+ * FLAC__stream_decoder_new() or FLAC__stream_decoder_finish(), but
+ * before FLAC__stream_decoder_init_*(). If this is the case they will
+ * return \c true, otherwise \c false.
+ *
+ * \note
+ * FLAC__stream_decoder_finish() resets all settings to the constructor
+ * defaults, including the callbacks.
+ *
+ * \{
+ */
+
+
+/** State values for a FLAC__StreamDecoder
+ *
+ * The decoder's state can be obtained by calling FLAC__stream_decoder_get_state().
+ */
+typedef enum {
+
+ FLAC__STREAM_DECODER_SEARCH_FOR_METADATA = 0,
+ /**< The decoder is ready to search for metadata. */
+
+ FLAC__STREAM_DECODER_READ_METADATA,
+ /**< The decoder is ready to or is in the process of reading metadata. */
+
+ FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC,
+ /**< The decoder is ready to or is in the process of searching for the
+ * frame sync code.
+ */
+
+ FLAC__STREAM_DECODER_READ_FRAME,
+ /**< The decoder is ready to or is in the process of reading a frame. */
+
+ FLAC__STREAM_DECODER_END_OF_STREAM,
+ /**< The decoder has reached the end of the stream. */
+
+ FLAC__STREAM_DECODER_OGG_ERROR,
+ /**< An error occurred in the underlying Ogg layer. */
+
+ FLAC__STREAM_DECODER_SEEK_ERROR,
+ /**< An error occurred while seeking. The decoder must be flushed
+ * with FLAC__stream_decoder_flush() or reset with
+ * FLAC__stream_decoder_reset() before decoding can continue.
+ */
+
+ FLAC__STREAM_DECODER_ABORTED,
+ /**< The decoder was aborted by the read or write callback. */
+
+ FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR,
+ /**< An error occurred allocating memory. The decoder is in an invalid
+ * state and can no longer be used.
+ */
+
+ FLAC__STREAM_DECODER_UNINITIALIZED
+ /**< The decoder is in the uninitialized state; one of the
+ * FLAC__stream_decoder_init_*() functions must be called before samples
+ * can be processed.
+ */
+
+} FLAC__StreamDecoderState;
+
+/** Maps a FLAC__StreamDecoderState to a C string.
+ *
+ * Using a FLAC__StreamDecoderState as the index to this array
+ * will give the string equivalent. The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__StreamDecoderStateString[];
+
+
+/** Possible return values for the FLAC__stream_decoder_init_*() functions.
+ */
+typedef enum {
+
+ FLAC__STREAM_DECODER_INIT_STATUS_OK = 0,
+ /**< Initialization was successful. */
+
+ FLAC__STREAM_DECODER_INIT_STATUS_UNSUPPORTED_CONTAINER,
+ /**< The library was not compiled with support for the given container
+ * format.
+ */
+
+ FLAC__STREAM_DECODER_INIT_STATUS_INVALID_CALLBACKS,
+ /**< A required callback was not supplied. */
+
+ FLAC__STREAM_DECODER_INIT_STATUS_MEMORY_ALLOCATION_ERROR,
+ /**< An error occurred allocating memory. */
+
+ FLAC__STREAM_DECODER_INIT_STATUS_ERROR_OPENING_FILE,
+ /**< fopen() failed in FLAC__stream_decoder_init_file() or
+ * FLAC__stream_decoder_init_ogg_file(). */
+
+ FLAC__STREAM_DECODER_INIT_STATUS_ALREADY_INITIALIZED
+ /**< FLAC__stream_decoder_init_*() was called when the decoder was
+ * already initialized, usually because
+ * FLAC__stream_decoder_finish() was not called.
+ */
+
+} FLAC__StreamDecoderInitStatus;
+
+/** Maps a FLAC__StreamDecoderInitStatus to a C string.
+ *
+ * Using a FLAC__StreamDecoderInitStatus as the index to this array
+ * will give the string equivalent. The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__StreamDecoderInitStatusString[];
+
+
+/** Return values for the FLAC__StreamDecoder read callback.
+ */
+typedef enum {
+
+ FLAC__STREAM_DECODER_READ_STATUS_CONTINUE,
+ /**< The read was OK and decoding can continue. */
+
+ FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM,
+ /**< The read was attempted while at the end of the stream. Note that
+ * the client must only return this value when the read callback was
+ * called when already at the end of the stream. Otherwise, if the read
+ * itself moves to the end of the stream, the client should still return
+ * the data and \c FLAC__STREAM_DECODER_READ_STATUS_CONTINUE, and then on
+ * the next read callback it should return
+ * \c FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM with a byte count
+ * of \c 0.
+ */
+
+ FLAC__STREAM_DECODER_READ_STATUS_ABORT
+ /**< An unrecoverable error occurred. The decoder will return from the process call. */
+
+} FLAC__StreamDecoderReadStatus;
+
+/** Maps a FLAC__StreamDecoderReadStatus to a C string.
+ *
+ * Using a FLAC__StreamDecoderReadStatus as the index to this array
+ * will give the string equivalent. The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__StreamDecoderReadStatusString[];
+
+
+/** Return values for the FLAC__StreamDecoder seek callback.
+ */
+typedef enum {
+
+ FLAC__STREAM_DECODER_SEEK_STATUS_OK,
+ /**< The seek was OK and decoding can continue. */
+
+ FLAC__STREAM_DECODER_SEEK_STATUS_ERROR,
+ /**< An unrecoverable error occurred. The decoder will return from the process call. */
+
+ FLAC__STREAM_DECODER_SEEK_STATUS_UNSUPPORTED
+ /**< Client does not support seeking. */
+
+} FLAC__StreamDecoderSeekStatus;
+
+/** Maps a FLAC__StreamDecoderSeekStatus to a C string.
+ *
+ * Using a FLAC__StreamDecoderSeekStatus as the index to this array
+ * will give the string equivalent. The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__StreamDecoderSeekStatusString[];
+
+
+/** Return values for the FLAC__StreamDecoder tell callback.
+ */
+typedef enum {
+
+ FLAC__STREAM_DECODER_TELL_STATUS_OK,
+ /**< The tell was OK and decoding can continue. */
+
+ FLAC__STREAM_DECODER_TELL_STATUS_ERROR,
+ /**< An unrecoverable error occurred. The decoder will return from the process call. */
+
+ FLAC__STREAM_DECODER_TELL_STATUS_UNSUPPORTED
+ /**< Client does not support telling the position. */
+
+} FLAC__StreamDecoderTellStatus;
+
+/** Maps a FLAC__StreamDecoderTellStatus to a C string.
+ *
+ * Using a FLAC__StreamDecoderTellStatus as the index to this array
+ * will give the string equivalent. The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__StreamDecoderTellStatusString[];
+
+
+/** Return values for the FLAC__StreamDecoder length callback.
+ */
+typedef enum {
+
+ FLAC__STREAM_DECODER_LENGTH_STATUS_OK,
+ /**< The length call was OK and decoding can continue. */
+
+ FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR,
+ /**< An unrecoverable error occurred. The decoder will return from the process call. */
+
+ FLAC__STREAM_DECODER_LENGTH_STATUS_UNSUPPORTED
+ /**< Client does not support reporting the length. */
+
+} FLAC__StreamDecoderLengthStatus;
+
+/** Maps a FLAC__StreamDecoderLengthStatus to a C string.
+ *
+ * Using a FLAC__StreamDecoderLengthStatus as the index to this array
+ * will give the string equivalent. The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__StreamDecoderLengthStatusString[];
+
+
+/** Return values for the FLAC__StreamDecoder write callback.
+ */
+typedef enum {
+
+ FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE,
+ /**< The write was OK and decoding can continue. */
+
+ FLAC__STREAM_DECODER_WRITE_STATUS_ABORT
+ /**< An unrecoverable error occurred. The decoder will return from the process call. */
+
+} FLAC__StreamDecoderWriteStatus;
+
+/** Maps a FLAC__StreamDecoderWriteStatus to a C string.
+ *
+ * Using a FLAC__StreamDecoderWriteStatus as the index to this array
+ * will give the string equivalent. The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__StreamDecoderWriteStatusString[];
+
+
+/** Possible values passed back to the FLAC__StreamDecoder error callback.
+ * \c FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC is the generic catch-
+ * all. The rest could be caused by bad sync (false synchronization on
+ * data that is not the start of a frame) or corrupted data. The error
+ * itself is the decoder's best guess at what happened assuming a correct
+ * sync. For example \c FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER
+ * could be caused by a correct sync on the start of a frame, but some
+ * data in the frame header was corrupted. Or it could be the result of
+ * syncing on a point the stream that looked like the starting of a frame
+ * but was not. \c FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM
+ * could be because the decoder encountered a valid frame made by a future
+ * version of the encoder which it cannot parse, or because of a false
+ * sync making it appear as though an encountered frame was generated by
+ * a future encoder.
+ */
+typedef enum {
+
+ FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC,
+ /**< An error in the stream caused the decoder to lose synchronization. */
+
+ FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER,
+ /**< The decoder encountered a corrupted frame header. */
+
+ FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH,
+ /**< The frame's data did not match the CRC in the footer. */
+
+ FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM
+ /**< The decoder encountered reserved fields in use in the stream. */
+
+} FLAC__StreamDecoderErrorStatus;
+
+/** Maps a FLAC__StreamDecoderErrorStatus to a C string.
+ *
+ * Using a FLAC__StreamDecoderErrorStatus as the index to this array
+ * will give the string equivalent. The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__StreamDecoderErrorStatusString[];
+
+
+/***********************************************************************
+ *
+ * class FLAC__StreamDecoder
+ *
+ ***********************************************************************/
+
+struct FLAC__StreamDecoderProtected;
+struct FLAC__StreamDecoderPrivate;
+/** The opaque structure definition for the stream decoder type.
+ * See the \link flac_stream_decoder stream decoder module \endlink
+ * for a detailed description.
+ */
+typedef struct {
+ struct FLAC__StreamDecoderProtected *protected_; /* avoid the C++ keyword 'protected' */
+ struct FLAC__StreamDecoderPrivate *private_; /* avoid the C++ keyword 'private' */
+} FLAC__StreamDecoder;
+
+/** Signature for the read callback.
+ *
+ * A function pointer matching this signature must be passed to
+ * FLAC__stream_decoder_init*_stream(). The supplied function will be
+ * called when the decoder needs more input data. The address of the
+ * buffer to be filled is supplied, along with the number of bytes the
+ * buffer can hold. The callback may choose to supply less data and
+ * modify the byte count but must be careful not to overflow the buffer.
+ * The callback then returns a status code chosen from
+ * FLAC__StreamDecoderReadStatus.
+ *
+ * Here is an example of a read callback for stdio streams:
+ * \code
+ * FLAC__StreamDecoderReadStatus read_cb(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data)
+ * {
+ * FILE *file = ((MyClientData*)client_data)->file;
+ * if(*bytes > 0) {
+ * *bytes = fread(buffer, sizeof(FLAC__byte), *bytes, file);
+ * if(ferror(file))
+ * return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
+ * else if(*bytes == 0)
+ * return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
+ * else
+ * return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
+ * }
+ * else
+ * return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
+ * }
+ * \endcode
+ *
+ * \note In general, FLAC__StreamDecoder functions which change the
+ * state should not be called on the \a decoder while in the callback.
+ *
+ * \param decoder The decoder instance calling the callback.
+ * \param buffer A pointer to a location for the callee to store
+ * data to be decoded.
+ * \param bytes A pointer to the size of the buffer. On entry
+ * to the callback, it contains the maximum number
+ * of bytes that may be stored in \a buffer. The
+ * callee must set it to the actual number of bytes
+ * stored (0 in case of error or end-of-stream) before
+ * returning.
+ * \param client_data The callee's client data set through
+ * FLAC__stream_decoder_init_*().
+ * \retval FLAC__StreamDecoderReadStatus
+ * The callee's return status. Note that the callback should return
+ * \c FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM if and only if
+ * zero bytes were read and there is no more data to be read.
+ */
+typedef FLAC__StreamDecoderReadStatus (*FLAC__StreamDecoderReadCallback)(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data);
+
+/** Signature for the seek callback.
+ *
+ * A function pointer matching this signature may be passed to
+ * FLAC__stream_decoder_init*_stream(). The supplied function will be
+ * called when the decoder needs to seek the input stream. The decoder
+ * will pass the absolute byte offset to seek to, 0 meaning the
+ * beginning of the stream.
+ *
+ * Here is an example of a seek callback for stdio streams:
+ * \code
+ * FLAC__StreamDecoderSeekStatus seek_cb(const FLAC__StreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data)
+ * {
+ * FILE *file = ((MyClientData*)client_data)->file;
+ * if(file == stdin)
+ * return FLAC__STREAM_DECODER_SEEK_STATUS_UNSUPPORTED;
+ * else if(fseeko(file, (off_t)absolute_byte_offset, SEEK_SET) < 0)
+ * return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR;
+ * else
+ * return FLAC__STREAM_DECODER_SEEK_STATUS_OK;
+ * }
+ * \endcode
+ *
+ * \note In general, FLAC__StreamDecoder functions which change the
+ * state should not be called on the \a decoder while in the callback.
+ *
+ * \param decoder The decoder instance calling the callback.
+ * \param absolute_byte_offset The offset from the beginning of the stream
+ * to seek to.
+ * \param client_data The callee's client data set through
+ * FLAC__stream_decoder_init_*().
+ * \retval FLAC__StreamDecoderSeekStatus
+ * The callee's return status.
+ */
+typedef FLAC__StreamDecoderSeekStatus (*FLAC__StreamDecoderSeekCallback)(const FLAC__StreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data);
+
+/** Signature for the tell callback.
+ *
+ * A function pointer matching this signature may be passed to
+ * FLAC__stream_decoder_init*_stream(). The supplied function will be
+ * called when the decoder wants to know the current position of the
+ * stream. The callback should return the byte offset from the
+ * beginning of the stream.
+ *
+ * Here is an example of a tell callback for stdio streams:
+ * \code
+ * FLAC__StreamDecoderTellStatus tell_cb(const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data)
+ * {
+ * FILE *file = ((MyClientData*)client_data)->file;
+ * off_t pos;
+ * if(file == stdin)
+ * return FLAC__STREAM_DECODER_TELL_STATUS_UNSUPPORTED;
+ * else if((pos = ftello(file)) < 0)
+ * return FLAC__STREAM_DECODER_TELL_STATUS_ERROR;
+ * else {
+ * *absolute_byte_offset = (FLAC__uint64)pos;
+ * return FLAC__STREAM_DECODER_TELL_STATUS_OK;
+ * }
+ * }
+ * \endcode
+ *
+ * \note In general, FLAC__StreamDecoder functions which change the
+ * state should not be called on the \a decoder while in the callback.
+ *
+ * \param decoder The decoder instance calling the callback.
+ * \param absolute_byte_offset A pointer to storage for the current offset
+ * from the beginning of the stream.
+ * \param client_data The callee's client data set through
+ * FLAC__stream_decoder_init_*().
+ * \retval FLAC__StreamDecoderTellStatus
+ * The callee's return status.
+ */
+typedef FLAC__StreamDecoderTellStatus (*FLAC__StreamDecoderTellCallback)(const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data);
+
+/** Signature for the length callback.
+ *
+ * A function pointer matching this signature may be passed to
+ * FLAC__stream_decoder_init*_stream(). The supplied function will be
+ * called when the decoder wants to know the total length of the stream
+ * in bytes.
+ *
+ * Here is an example of a length callback for stdio streams:
+ * \code
+ * FLAC__StreamDecoderLengthStatus length_cb(const FLAC__StreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data)
+ * {
+ * FILE *file = ((MyClientData*)client_data)->file;
+ * struct stat filestats;
+ *
+ * if(file == stdin)
+ * return FLAC__STREAM_DECODER_LENGTH_STATUS_UNSUPPORTED;
+ * else if(fstat(fileno(file), &filestats) != 0)
+ * return FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR;
+ * else {
+ * *stream_length = (FLAC__uint64)filestats.st_size;
+ * return FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
+ * }
+ * }
+ * \endcode
+ *
+ * \note In general, FLAC__StreamDecoder functions which change the
+ * state should not be called on the \a decoder while in the callback.
+ *
+ * \param decoder The decoder instance calling the callback.
+ * \param stream_length A pointer to storage for the length of the stream
+ * in bytes.
+ * \param client_data The callee's client data set through
+ * FLAC__stream_decoder_init_*().
+ * \retval FLAC__StreamDecoderLengthStatus
+ * The callee's return status.
+ */
+typedef FLAC__StreamDecoderLengthStatus (*FLAC__StreamDecoderLengthCallback)(const FLAC__StreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data);
+
+/** Signature for the EOF callback.
+ *
+ * A function pointer matching this signature may be passed to
+ * FLAC__stream_decoder_init*_stream(). The supplied function will be
+ * called when the decoder needs to know if the end of the stream has
+ * been reached.
+ *
+ * Here is an example of a EOF callback for stdio streams:
+ * FLAC__bool eof_cb(const FLAC__StreamDecoder *decoder, void *client_data)
+ * \code
+ * {
+ * FILE *file = ((MyClientData*)client_data)->file;
+ * return feof(file)? true : false;
+ * }
+ * \endcode
+ *
+ * \note In general, FLAC__StreamDecoder functions which change the
+ * state should not be called on the \a decoder while in the callback.
+ *
+ * \param decoder The decoder instance calling the callback.
+ * \param client_data The callee's client data set through
+ * FLAC__stream_decoder_init_*().
+ * \retval FLAC__bool
+ * \c true if the currently at the end of the stream, else \c false.
+ */
+typedef FLAC__bool (*FLAC__StreamDecoderEofCallback)(const FLAC__StreamDecoder *decoder, void *client_data);
+
+/** Signature for the write callback.
+ *
+ * A function pointer matching this signature must be passed to one of
+ * the FLAC__stream_decoder_init_*() functions.
+ * The supplied function will be called when the decoder has decoded a
+ * single audio frame. The decoder will pass the frame metadata as well
+ * as an array of pointers (one for each channel) pointing to the
+ * decoded audio.
+ *
+ * \note In general, FLAC__StreamDecoder functions which change the
+ * state should not be called on the \a decoder while in the callback.
+ *
+ * \param decoder The decoder instance calling the callback.
+ * \param frame The description of the decoded frame. See
+ * FLAC__Frame.
+ * \param buffer An array of pointers to decoded channels of data.
+ * Each pointer will point to an array of signed
+ * samples of length \a frame->header.blocksize.
+ * Channels will be ordered according to the FLAC
+ * specification; see the documentation for the
+ * <A HREF="../format.html#frame_header">frame header</A>.
+ * \param client_data The callee's client data set through
+ * FLAC__stream_decoder_init_*().
+ * \retval FLAC__StreamDecoderWriteStatus
+ * The callee's return status.
+ */
+typedef FLAC__StreamDecoderWriteStatus (*FLAC__StreamDecoderWriteCallback)(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data);
+
+/** Signature for the metadata callback.
+ *
+ * A function pointer matching this signature must be passed to one of
+ * the FLAC__stream_decoder_init_*() functions.
+ * The supplied function will be called when the decoder has decoded a
+ * metadata block. In a valid FLAC file there will always be one
+ * \c STREAMINFO block, followed by zero or more other metadata blocks.
+ * These will be supplied by the decoder in the same order as they
+ * appear in the stream and always before the first audio frame (i.e.
+ * write callback). The metadata block that is passed in must not be
+ * modified, and it doesn't live beyond the callback, so you should make
+ * a copy of it with FLAC__metadata_object_clone() if you will need it
+ * elsewhere. Since metadata blocks can potentially be large, by
+ * default the decoder only calls the metadata callback for the
+ * \c STREAMINFO block; you can instruct the decoder to pass or filter
+ * other blocks with FLAC__stream_decoder_set_metadata_*() calls.
+ *
+ * \note In general, FLAC__StreamDecoder functions which change the
+ * state should not be called on the \a decoder while in the callback.
+ *
+ * \param decoder The decoder instance calling the callback.
+ * \param metadata The decoded metadata block.
+ * \param client_data The callee's client data set through
+ * FLAC__stream_decoder_init_*().
+ */
+typedef void (*FLAC__StreamDecoderMetadataCallback)(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data);
+
+/** Signature for the error callback.
+ *
+ * A function pointer matching this signature must be passed to one of
+ * the FLAC__stream_decoder_init_*() functions.
+ * The supplied function will be called whenever an error occurs during
+ * decoding.
+ *
+ * \note In general, FLAC__StreamDecoder functions which change the
+ * state should not be called on the \a decoder while in the callback.
+ *
+ * \param decoder The decoder instance calling the callback.
+ * \param status The error encountered by the decoder.
+ * \param client_data The callee's client data set through
+ * FLAC__stream_decoder_init_*().
+ */
+typedef void (*FLAC__StreamDecoderErrorCallback)(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data);
+
+
+/***********************************************************************
+ *
+ * Class constructor/destructor
+ *
+ ***********************************************************************/
+
+/** Create a new stream decoder instance. The instance is created with
+ * default settings; see the individual FLAC__stream_decoder_set_*()
+ * functions for each setting's default.
+ *
+ * \retval FLAC__StreamDecoder*
+ * \c NULL if there was an error allocating memory, else the new instance.
+ */
+FLAC_API FLAC__StreamDecoder *FLAC__stream_decoder_new(void);
+
+/** Free a decoder instance. Deletes the object pointed to by \a decoder.
+ *
+ * \param decoder A pointer to an existing decoder.
+ * \assert
+ * \code decoder != NULL \endcode
+ */
+FLAC_API void FLAC__stream_decoder_delete(FLAC__StreamDecoder *decoder);
+
+
+/***********************************************************************
+ *
+ * Public class method prototypes
+ *
+ ***********************************************************************/
+
+/** Set the serial number for the FLAC stream within the Ogg container.
+ * The default behavior is to use the serial number of the first Ogg
+ * page. Setting a serial number here will explicitly specify which
+ * stream is to be decoded.
+ *
+ * \note
+ * This does not need to be set for native FLAC decoding.
+ *
+ * \default \c use serial number of first page
+ * \param decoder A decoder instance to set.
+ * \param serial_number See above.
+ * \assert
+ * \code decoder != NULL \endcode
+ * \retval FLAC__bool
+ * \c false if the decoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_decoder_set_ogg_serial_number(FLAC__StreamDecoder *decoder, long serial_number);
+
+/** Set the "MD5 signature checking" flag. If \c true, the decoder will
+ * compute the MD5 signature of the unencoded audio data while decoding
+ * and compare it to the signature from the STREAMINFO block, if it
+ * exists, during FLAC__stream_decoder_finish().
+ *
+ * MD5 signature checking will be turned off (until the next
+ * FLAC__stream_decoder_reset()) if there is no signature in the
+ * STREAMINFO block or when a seek is attempted.
+ *
+ * Clients that do not use the MD5 check should leave this off to speed
+ * up decoding.
+ *
+ * \default \c false
+ * \param decoder A decoder instance to set.
+ * \param value Flag value (see above).
+ * \assert
+ * \code decoder != NULL \endcode
+ * \retval FLAC__bool
+ * \c false if the decoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_decoder_set_md5_checking(FLAC__StreamDecoder *decoder, FLAC__bool value);
+
+/** Direct the decoder to pass on all metadata blocks of type \a type.
+ *
+ * \default By default, only the \c STREAMINFO block is returned via the
+ * metadata callback.
+ * \param decoder A decoder instance to set.
+ * \param type See above.
+ * \assert
+ * \code decoder != NULL \endcode
+ * \a type is valid
+ * \retval FLAC__bool
+ * \c false if the decoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_respond(FLAC__StreamDecoder *decoder, FLAC__MetadataType type);
+
+/** Direct the decoder to pass on all APPLICATION metadata blocks of the
+ * given \a id.
+ *
+ * \default By default, only the \c STREAMINFO block is returned via the
+ * metadata callback.
+ * \param decoder A decoder instance to set.
+ * \param id See above.
+ * \assert
+ * \code decoder != NULL \endcode
+ * \code id != NULL \endcode
+ * \retval FLAC__bool
+ * \c false if the decoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_respond_application(FLAC__StreamDecoder *decoder, const FLAC__byte id[4]);
+
+/** Direct the decoder to pass on all metadata blocks of any type.
+ *
+ * \default By default, only the \c STREAMINFO block is returned via the
+ * metadata callback.
+ * \param decoder A decoder instance to set.
+ * \assert
+ * \code decoder != NULL \endcode
+ * \retval FLAC__bool
+ * \c false if the decoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_respond_all(FLAC__StreamDecoder *decoder);
+
+/** Direct the decoder to filter out all metadata blocks of type \a type.
+ *
+ * \default By default, only the \c STREAMINFO block is returned via the
+ * metadata callback.
+ * \param decoder A decoder instance to set.
+ * \param type See above.
+ * \assert
+ * \code decoder != NULL \endcode
+ * \a type is valid
+ * \retval FLAC__bool
+ * \c false if the decoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_ignore(FLAC__StreamDecoder *decoder, FLAC__MetadataType type);
+
+/** Direct the decoder to filter out all APPLICATION metadata blocks of
+ * the given \a id.
+ *
+ * \default By default, only the \c STREAMINFO block is returned via the
+ * metadata callback.
+ * \param decoder A decoder instance to set.
+ * \param id See above.
+ * \assert
+ * \code decoder != NULL \endcode
+ * \code id != NULL \endcode
+ * \retval FLAC__bool
+ * \c false if the decoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_ignore_application(FLAC__StreamDecoder *decoder, const FLAC__byte id[4]);
+
+/** Direct the decoder to filter out all metadata blocks of any type.
+ *
+ * \default By default, only the \c STREAMINFO block is returned via the
+ * metadata callback.
+ * \param decoder A decoder instance to set.
+ * \assert
+ * \code decoder != NULL \endcode
+ * \retval FLAC__bool
+ * \c false if the decoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_ignore_all(FLAC__StreamDecoder *decoder);
+
+/** Get the current decoder state.
+ *
+ * \param decoder A decoder instance to query.
+ * \assert
+ * \code decoder != NULL \endcode
+ * \retval FLAC__StreamDecoderState
+ * The current decoder state.
+ */
+FLAC_API FLAC__StreamDecoderState FLAC__stream_decoder_get_state(const FLAC__StreamDecoder *decoder);
+
+/** Get the current decoder state as a C string.
+ *
+ * \param decoder A decoder instance to query.
+ * \assert
+ * \code decoder != NULL \endcode
+ * \retval const char *
+ * The decoder state as a C string. Do not modify the contents.
+ */
+FLAC_API const char *FLAC__stream_decoder_get_resolved_state_string(const FLAC__StreamDecoder *decoder);
+
+/** Get the "MD5 signature checking" flag.
+ * This is the value of the setting, not whether or not the decoder is
+ * currently checking the MD5 (remember, it can be turned off automatically
+ * by a seek). When the decoder is reset the flag will be restored to the
+ * value returned by this function.
+ *
+ * \param decoder A decoder instance to query.
+ * \assert
+ * \code decoder != NULL \endcode
+ * \retval FLAC__bool
+ * See above.
+ */
+FLAC_API FLAC__bool FLAC__stream_decoder_get_md5_checking(const FLAC__StreamDecoder *decoder);
+
+/** Get the total number of samples in the stream being decoded.
+ * Will only be valid after decoding has started and will contain the
+ * value from the \c STREAMINFO block. A value of \c 0 means "unknown".
+ *
+ * \param decoder A decoder instance to query.
+ * \assert
+ * \code decoder != NULL \endcode
+ * \retval uint32_t
+ * See above.
+ */
+FLAC_API FLAC__uint64 FLAC__stream_decoder_get_total_samples(const FLAC__StreamDecoder *decoder);
+
+/** Get the current number of channels in the stream being decoded.
+ * Will only be valid after decoding has started and will contain the
+ * value from the most recently decoded frame header.
+ *
+ * \param decoder A decoder instance to query.
+ * \assert
+ * \code decoder != NULL \endcode
+ * \retval uint32_t
+ * See above.
+ */
+FLAC_API uint32_t FLAC__stream_decoder_get_channels(const FLAC__StreamDecoder *decoder);
+
+/** Get the current channel assignment in the stream being decoded.
+ * Will only be valid after decoding has started and will contain the
+ * value from the most recently decoded frame header.
+ *
+ * \param decoder A decoder instance to query.
+ * \assert
+ * \code decoder != NULL \endcode
+ * \retval FLAC__ChannelAssignment
+ * See above.
+ */
+FLAC_API FLAC__ChannelAssignment FLAC__stream_decoder_get_channel_assignment(const FLAC__StreamDecoder *decoder);
+
+/** Get the current sample resolution in the stream being decoded.
+ * Will only be valid after decoding has started and will contain the
+ * value from the most recently decoded frame header.
+ *
+ * \param decoder A decoder instance to query.
+ * \assert
+ * \code decoder != NULL \endcode
+ * \retval uint32_t
+ * See above.
+ */
+FLAC_API uint32_t FLAC__stream_decoder_get_bits_per_sample(const FLAC__StreamDecoder *decoder);
+
+/** Get the current sample rate in Hz of the stream being decoded.
+ * Will only be valid after decoding has started and will contain the
+ * value from the most recently decoded frame header.
+ *
+ * \param decoder A decoder instance to query.
+ * \assert
+ * \code decoder != NULL \endcode
+ * \retval uint32_t
+ * See above.
+ */
+FLAC_API uint32_t FLAC__stream_decoder_get_sample_rate(const FLAC__StreamDecoder *decoder);
+
+/** Get the current blocksize of the stream being decoded.
+ * Will only be valid after decoding has started and will contain the
+ * value from the most recently decoded frame header.
+ *
+ * \param decoder A decoder instance to query.
+ * \assert
+ * \code decoder != NULL \endcode
+ * \retval uint32_t
+ * See above.
+ */
+FLAC_API uint32_t FLAC__stream_decoder_get_blocksize(const FLAC__StreamDecoder *decoder);
+
+/** Returns the decoder's current read position within the stream.
+ * The position is the byte offset from the start of the stream.
+ * Bytes before this position have been fully decoded. Note that
+ * there may still be undecoded bytes in the decoder's read FIFO.
+ * The returned position is correct even after a seek.
+ *
+ * \warning This function currently only works for native FLAC,
+ * not Ogg FLAC streams.
+ *
+ * \param decoder A decoder instance to query.
+ * \param position Address at which to return the desired position.
+ * \assert
+ * \code decoder != NULL \endcode
+ * \code position != NULL \endcode
+ * \retval FLAC__bool
+ * \c true if successful, \c false if the stream is not native FLAC,
+ * or there was an error from the 'tell' callback or it returned
+ * \c FLAC__STREAM_DECODER_TELL_STATUS_UNSUPPORTED.
+ */
+FLAC_API FLAC__bool FLAC__stream_decoder_get_decode_position(const FLAC__StreamDecoder *decoder, FLAC__uint64 *position);
+
+/** Initialize the decoder instance to decode native FLAC streams.
+ *
+ * This flavor of initialization sets up the decoder to decode from a
+ * native FLAC stream. I/O is performed via callbacks to the client.
+ * For decoding from a plain file via filename or open FILE*,
+ * FLAC__stream_decoder_init_file() and FLAC__stream_decoder_init_FILE()
+ * provide a simpler interface.
+ *
+ * This function should be called after FLAC__stream_decoder_new() and
+ * FLAC__stream_decoder_set_*() but before any of the
+ * FLAC__stream_decoder_process_*() functions. Will set and return the
+ * decoder state, which will be FLAC__STREAM_DECODER_SEARCH_FOR_METADATA
+ * if initialization succeeded.
+ *
+ * \param decoder An uninitialized decoder instance.
+ * \param read_callback See FLAC__StreamDecoderReadCallback. This
+ * pointer must not be \c NULL.
+ * \param seek_callback See FLAC__StreamDecoderSeekCallback. This
+ * pointer may be \c NULL if seeking is not
+ * supported. If \a seek_callback is not \c NULL then a
+ * \a tell_callback, \a length_callback, and \a eof_callback must also be supplied.
+ * Alternatively, a dummy seek callback that just
+ * returns \c FLAC__STREAM_DECODER_SEEK_STATUS_UNSUPPORTED
+ * may also be supplied, all though this is slightly
+ * less efficient for the decoder.
+ * \param tell_callback See FLAC__StreamDecoderTellCallback. This
+ * pointer may be \c NULL if not supported by the client. If
+ * \a seek_callback is not \c NULL then a
+ * \a tell_callback must also be supplied.
+ * Alternatively, a dummy tell callback that just
+ * returns \c FLAC__STREAM_DECODER_TELL_STATUS_UNSUPPORTED
+ * may also be supplied, all though this is slightly
+ * less efficient for the decoder.
+ * \param length_callback See FLAC__StreamDecoderLengthCallback. This
+ * pointer may be \c NULL if not supported by the client. If
+ * \a seek_callback is not \c NULL then a
+ * \a length_callback must also be supplied.
+ * Alternatively, a dummy length callback that just
+ * returns \c FLAC__STREAM_DECODER_LENGTH_STATUS_UNSUPPORTED
+ * may also be supplied, all though this is slightly
+ * less efficient for the decoder.
+ * \param eof_callback See FLAC__StreamDecoderEofCallback. This
+ * pointer may be \c NULL if not supported by the client. If
+ * \a seek_callback is not \c NULL then a
+ * \a eof_callback must also be supplied.
+ * Alternatively, a dummy length callback that just
+ * returns \c false
+ * may also be supplied, all though this is slightly
+ * less efficient for the decoder.
+ * \param write_callback See FLAC__StreamDecoderWriteCallback. This
+ * pointer must not be \c NULL.
+ * \param metadata_callback See FLAC__StreamDecoderMetadataCallback. This
+ * pointer may be \c NULL if the callback is not
+ * desired.
+ * \param error_callback See FLAC__StreamDecoderErrorCallback. This
+ * pointer must not be \c NULL.
+ * \param client_data This value will be supplied to callbacks in their
+ * \a client_data argument.
+ * \assert
+ * \code decoder != NULL \endcode
+ * \retval FLAC__StreamDecoderInitStatus
+ * \c FLAC__STREAM_DECODER_INIT_STATUS_OK if initialization was successful;
+ * see FLAC__StreamDecoderInitStatus for the meanings of other return values.
+ */
+FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_stream(
+ FLAC__StreamDecoder *decoder,
+ FLAC__StreamDecoderReadCallback read_callback,
+ FLAC__StreamDecoderSeekCallback seek_callback,
+ FLAC__StreamDecoderTellCallback tell_callback,
+ FLAC__StreamDecoderLengthCallback length_callback,
+ FLAC__StreamDecoderEofCallback eof_callback,
+ FLAC__StreamDecoderWriteCallback write_callback,
+ FLAC__StreamDecoderMetadataCallback metadata_callback,
+ FLAC__StreamDecoderErrorCallback error_callback,
+ void *client_data
+);
+
+/** Initialize the decoder instance to decode Ogg FLAC streams.
+ *
+ * This flavor of initialization sets up the decoder to decode from a
+ * FLAC stream in an Ogg container. I/O is performed via callbacks to the
+ * client. For decoding from a plain file via filename or open FILE*,
+ * FLAC__stream_decoder_init_ogg_file() and FLAC__stream_decoder_init_ogg_FILE()
+ * provide a simpler interface.
+ *
+ * This function should be called after FLAC__stream_decoder_new() and
+ * FLAC__stream_decoder_set_*() but before any of the
+ * FLAC__stream_decoder_process_*() functions. Will set and return the
+ * decoder state, which will be FLAC__STREAM_DECODER_SEARCH_FOR_METADATA
+ * if initialization succeeded.
+ *
+ * \note Support for Ogg FLAC in the library is optional. If this
+ * library has been built without support for Ogg FLAC, this function
+ * will return \c FLAC__STREAM_DECODER_INIT_STATUS_UNSUPPORTED_CONTAINER.
+ *
+ * \param decoder An uninitialized decoder instance.
+ * \param read_callback See FLAC__StreamDecoderReadCallback. This
+ * pointer must not be \c NULL.
+ * \param seek_callback See FLAC__StreamDecoderSeekCallback. This
+ * pointer may be \c NULL if seeking is not
+ * supported. If \a seek_callback is not \c NULL then a
+ * \a tell_callback, \a length_callback, and \a eof_callback must also be supplied.
+ * Alternatively, a dummy seek callback that just
+ * returns \c FLAC__STREAM_DECODER_SEEK_STATUS_UNSUPPORTED
+ * may also be supplied, all though this is slightly
+ * less efficient for the decoder.
+ * \param tell_callback See FLAC__StreamDecoderTellCallback. This
+ * pointer may be \c NULL if not supported by the client. If
+ * \a seek_callback is not \c NULL then a
+ * \a tell_callback must also be supplied.
+ * Alternatively, a dummy tell callback that just
+ * returns \c FLAC__STREAM_DECODER_TELL_STATUS_UNSUPPORTED
+ * may also be supplied, all though this is slightly
+ * less efficient for the decoder.
+ * \param length_callback See FLAC__StreamDecoderLengthCallback. This
+ * pointer may be \c NULL if not supported by the client. If
+ * \a seek_callback is not \c NULL then a
+ * \a length_callback must also be supplied.
+ * Alternatively, a dummy length callback that just
+ * returns \c FLAC__STREAM_DECODER_LENGTH_STATUS_UNSUPPORTED
+ * may also be supplied, all though this is slightly
+ * less efficient for the decoder.
+ * \param eof_callback See FLAC__StreamDecoderEofCallback. This
+ * pointer may be \c NULL if not supported by the client. If
+ * \a seek_callback is not \c NULL then a
+ * \a eof_callback must also be supplied.
+ * Alternatively, a dummy length callback that just
+ * returns \c false
+ * may also be supplied, all though this is slightly
+ * less efficient for the decoder.
+ * \param write_callback See FLAC__StreamDecoderWriteCallback. This
+ * pointer must not be \c NULL.
+ * \param metadata_callback See FLAC__StreamDecoderMetadataCallback. This
+ * pointer may be \c NULL if the callback is not
+ * desired.
+ * \param error_callback See FLAC__StreamDecoderErrorCallback. This
+ * pointer must not be \c NULL.
+ * \param client_data This value will be supplied to callbacks in their
+ * \a client_data argument.
+ * \assert
+ * \code decoder != NULL \endcode
+ * \retval FLAC__StreamDecoderInitStatus
+ * \c FLAC__STREAM_DECODER_INIT_STATUS_OK if initialization was successful;
+ * see FLAC__StreamDecoderInitStatus for the meanings of other return values.
+ */
+FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_ogg_stream(
+ FLAC__StreamDecoder *decoder,
+ FLAC__StreamDecoderReadCallback read_callback,
+ FLAC__StreamDecoderSeekCallback seek_callback,
+ FLAC__StreamDecoderTellCallback tell_callback,
+ FLAC__StreamDecoderLengthCallback length_callback,
+ FLAC__StreamDecoderEofCallback eof_callback,
+ FLAC__StreamDecoderWriteCallback write_callback,
+ FLAC__StreamDecoderMetadataCallback metadata_callback,
+ FLAC__StreamDecoderErrorCallback error_callback,
+ void *client_data
+);
+
+/** Initialize the decoder instance to decode native FLAC files.
+ *
+ * This flavor of initialization sets up the decoder to decode from a
+ * plain native FLAC file. For non-stdio streams, you must use
+ * FLAC__stream_decoder_init_stream() and provide callbacks for the I/O.
+ *
+ * This function should be called after FLAC__stream_decoder_new() and
+ * FLAC__stream_decoder_set_*() but before any of the
+ * FLAC__stream_decoder_process_*() functions. Will set and return the
+ * decoder state, which will be FLAC__STREAM_DECODER_SEARCH_FOR_METADATA
+ * if initialization succeeded.
+ *
+ * \param decoder An uninitialized decoder instance.
+ * \param file An open FLAC file. The file should have been
+ * opened with mode \c "rb" and rewound. The file
+ * becomes owned by the decoder and should not be
+ * manipulated by the client while decoding.
+ * Unless \a file is \c stdin, it will be closed
+ * when FLAC__stream_decoder_finish() is called.
+ * Note however that seeking will not work when
+ * decoding from \c stdin since it is not seekable.
+ * \param write_callback See FLAC__StreamDecoderWriteCallback. This
+ * pointer must not be \c NULL.
+ * \param metadata_callback See FLAC__StreamDecoderMetadataCallback. This
+ * pointer may be \c NULL if the callback is not
+ * desired.
+ * \param error_callback See FLAC__StreamDecoderErrorCallback. This
+ * pointer must not be \c NULL.
+ * \param client_data This value will be supplied to callbacks in their
+ * \a client_data argument.
+ * \assert
+ * \code decoder != NULL \endcode
+ * \code file != NULL \endcode
+ * \retval FLAC__StreamDecoderInitStatus
+ * \c FLAC__STREAM_DECODER_INIT_STATUS_OK if initialization was successful;
+ * see FLAC__StreamDecoderInitStatus for the meanings of other return values.
+ */
+FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_FILE(
+ FLAC__StreamDecoder *decoder,
+ FILE *file,
+ FLAC__StreamDecoderWriteCallback write_callback,
+ FLAC__StreamDecoderMetadataCallback metadata_callback,
+ FLAC__StreamDecoderErrorCallback error_callback,
+ void *client_data
+);
+
+/** Initialize the decoder instance to decode Ogg FLAC files.
+ *
+ * This flavor of initialization sets up the decoder to decode from a
+ * plain Ogg FLAC file. For non-stdio streams, you must use
+ * FLAC__stream_decoder_init_ogg_stream() and provide callbacks for the I/O.
+ *
+ * This function should be called after FLAC__stream_decoder_new() and
+ * FLAC__stream_decoder_set_*() but before any of the
+ * FLAC__stream_decoder_process_*() functions. Will set and return the
+ * decoder state, which will be FLAC__STREAM_DECODER_SEARCH_FOR_METADATA
+ * if initialization succeeded.
+ *
+ * \note Support for Ogg FLAC in the library is optional. If this
+ * library has been built without support for Ogg FLAC, this function
+ * will return \c FLAC__STREAM_DECODER_INIT_STATUS_UNSUPPORTED_CONTAINER.
+ *
+ * \param decoder An uninitialized decoder instance.
+ * \param file An open FLAC file. The file should have been
+ * opened with mode \c "rb" and rewound. The file
+ * becomes owned by the decoder and should not be
+ * manipulated by the client while decoding.
+ * Unless \a file is \c stdin, it will be closed
+ * when FLAC__stream_decoder_finish() is called.
+ * Note however that seeking will not work when
+ * decoding from \c stdin since it is not seekable.
+ * \param write_callback See FLAC__StreamDecoderWriteCallback. This
+ * pointer must not be \c NULL.
+ * \param metadata_callback See FLAC__StreamDecoderMetadataCallback. This
+ * pointer may be \c NULL if the callback is not
+ * desired.
+ * \param error_callback See FLAC__StreamDecoderErrorCallback. This
+ * pointer must not be \c NULL.
+ * \param client_data This value will be supplied to callbacks in their
+ * \a client_data argument.
+ * \assert
+ * \code decoder != NULL \endcode
+ * \code file != NULL \endcode
+ * \retval FLAC__StreamDecoderInitStatus
+ * \c FLAC__STREAM_DECODER_INIT_STATUS_OK if initialization was successful;
+ * see FLAC__StreamDecoderInitStatus for the meanings of other return values.
+ */
+FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_ogg_FILE(
+ FLAC__StreamDecoder *decoder,
+ FILE *file,
+ FLAC__StreamDecoderWriteCallback write_callback,
+ FLAC__StreamDecoderMetadataCallback metadata_callback,
+ FLAC__StreamDecoderErrorCallback error_callback,
+ void *client_data
+);
+
+/** Initialize the decoder instance to decode native FLAC files.
+ *
+ * This flavor of initialization sets up the decoder to decode from a plain
+ * native FLAC file. If POSIX fopen() semantics are not sufficient, (for
+ * example, with Unicode filenames on Windows), you must use
+ * FLAC__stream_decoder_init_FILE(), or FLAC__stream_decoder_init_stream()
+ * and provide callbacks for the I/O.
+ *
+ * This function should be called after FLAC__stream_decoder_new() and
+ * FLAC__stream_decoder_set_*() but before any of the
+ * FLAC__stream_decoder_process_*() functions. Will set and return the
+ * decoder state, which will be FLAC__STREAM_DECODER_SEARCH_FOR_METADATA
+ * if initialization succeeded.
+ *
+ * \param decoder An uninitialized decoder instance.
+ * \param filename The name of the file to decode from. The file will
+ * be opened with fopen(). Use \c NULL to decode from
+ * \c stdin. Note that \c stdin is not seekable.
+ * \param write_callback See FLAC__StreamDecoderWriteCallback. This
+ * pointer must not be \c NULL.
+ * \param metadata_callback See FLAC__StreamDecoderMetadataCallback. This
+ * pointer may be \c NULL if the callback is not
+ * desired.
+ * \param error_callback See FLAC__StreamDecoderErrorCallback. This
+ * pointer must not be \c NULL.
+ * \param client_data This value will be supplied to callbacks in their
+ * \a client_data argument.
+ * \assert
+ * \code decoder != NULL \endcode
+ * \retval FLAC__StreamDecoderInitStatus
+ * \c FLAC__STREAM_DECODER_INIT_STATUS_OK if initialization was successful;
+ * see FLAC__StreamDecoderInitStatus for the meanings of other return values.
+ */
+FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_file(
+ FLAC__StreamDecoder *decoder,
+ const char *filename,
+ FLAC__StreamDecoderWriteCallback write_callback,
+ FLAC__StreamDecoderMetadataCallback metadata_callback,
+ FLAC__StreamDecoderErrorCallback error_callback,
+ void *client_data
+);
+
+/** Initialize the decoder instance to decode Ogg FLAC files.
+ *
+ * This flavor of initialization sets up the decoder to decode from a plain
+ * Ogg FLAC file. If POSIX fopen() semantics are not sufficient, (for
+ * example, with Unicode filenames on Windows), you must use
+ * FLAC__stream_decoder_init_ogg_FILE(), or FLAC__stream_decoder_init_ogg_stream()
+ * and provide callbacks for the I/O.
+ *
+ * This function should be called after FLAC__stream_decoder_new() and
+ * FLAC__stream_decoder_set_*() but before any of the
+ * FLAC__stream_decoder_process_*() functions. Will set and return the
+ * decoder state, which will be FLAC__STREAM_DECODER_SEARCH_FOR_METADATA
+ * if initialization succeeded.
+ *
+ * \note Support for Ogg FLAC in the library is optional. If this
+ * library has been built without support for Ogg FLAC, this function
+ * will return \c FLAC__STREAM_DECODER_INIT_STATUS_UNSUPPORTED_CONTAINER.
+ *
+ * \param decoder An uninitialized decoder instance.
+ * \param filename The name of the file to decode from. The file will
+ * be opened with fopen(). Use \c NULL to decode from
+ * \c stdin. Note that \c stdin is not seekable.
+ * \param write_callback See FLAC__StreamDecoderWriteCallback. This
+ * pointer must not be \c NULL.
+ * \param metadata_callback See FLAC__StreamDecoderMetadataCallback. This
+ * pointer may be \c NULL if the callback is not
+ * desired.
+ * \param error_callback See FLAC__StreamDecoderErrorCallback. This
+ * pointer must not be \c NULL.
+ * \param client_data This value will be supplied to callbacks in their
+ * \a client_data argument.
+ * \assert
+ * \code decoder != NULL \endcode
+ * \retval FLAC__StreamDecoderInitStatus
+ * \c FLAC__STREAM_DECODER_INIT_STATUS_OK if initialization was successful;
+ * see FLAC__StreamDecoderInitStatus for the meanings of other return values.
+ */
+FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_ogg_file(
+ FLAC__StreamDecoder *decoder,
+ const char *filename,
+ FLAC__StreamDecoderWriteCallback write_callback,
+ FLAC__StreamDecoderMetadataCallback metadata_callback,
+ FLAC__StreamDecoderErrorCallback error_callback,
+ void *client_data
+);
+
+/** Finish the decoding process.
+ * Flushes the decoding buffer, releases resources, resets the decoder
+ * settings to their defaults, and returns the decoder state to
+ * FLAC__STREAM_DECODER_UNINITIALIZED.
+ *
+ * In the event of a prematurely-terminated decode, it is not strictly
+ * necessary to call this immediately before FLAC__stream_decoder_delete()
+ * but it is good practice to match every FLAC__stream_decoder_init_*()
+ * with a FLAC__stream_decoder_finish().
+ *
+ * \param decoder An uninitialized decoder instance.
+ * \assert
+ * \code decoder != NULL \endcode
+ * \retval FLAC__bool
+ * \c false if MD5 checking is on AND a STREAMINFO block was available
+ * AND the MD5 signature in the STREAMINFO block was non-zero AND the
+ * signature does not match the one computed by the decoder; else
+ * \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_decoder_finish(FLAC__StreamDecoder *decoder);
+
+/** Flush the stream input.
+ * The decoder's input buffer will be cleared and the state set to
+ * \c FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC. This will also turn
+ * off MD5 checking.
+ *
+ * \param decoder A decoder instance.
+ * \assert
+ * \code decoder != NULL \endcode
+ * \retval FLAC__bool
+ * \c true if successful, else \c false if a memory allocation
+ * error occurs (in which case the state will be set to
+ * \c FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR).
+ */
+FLAC_API FLAC__bool FLAC__stream_decoder_flush(FLAC__StreamDecoder *decoder);
+
+/** Reset the decoding process.
+ * The decoder's input buffer will be cleared and the state set to
+ * \c FLAC__STREAM_DECODER_SEARCH_FOR_METADATA. This is similar to
+ * FLAC__stream_decoder_finish() except that the settings are
+ * preserved; there is no need to call FLAC__stream_decoder_init_*()
+ * before decoding again. MD5 checking will be restored to its original
+ * setting.
+ *
+ * If the decoder is seekable, or was initialized with
+ * FLAC__stream_decoder_init*_FILE() or FLAC__stream_decoder_init*_file(),
+ * the decoder will also attempt to seek to the beginning of the file.
+ * If this rewind fails, this function will return \c false. It follows
+ * that FLAC__stream_decoder_reset() cannot be used when decoding from
+ * \c stdin.
+ *
+ * If the decoder was initialized with FLAC__stream_encoder_init*_stream()
+ * and is not seekable (i.e. no seek callback was provided or the seek
+ * callback returns \c FLAC__STREAM_DECODER_SEEK_STATUS_UNSUPPORTED), it
+ * is the duty of the client to start feeding data from the beginning of
+ * the stream on the next FLAC__stream_decoder_process_*() call.
+ *
+ * \param decoder A decoder instance.
+ * \assert
+ * \code decoder != NULL \endcode
+ * \retval FLAC__bool
+ * \c true if successful, else \c false if a memory allocation occurs
+ * (in which case the state will be set to
+ * \c FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR) or a seek error
+ * occurs (the state will be unchanged).
+ */
+FLAC_API FLAC__bool FLAC__stream_decoder_reset(FLAC__StreamDecoder *decoder);
+
+/** Decode one metadata block or audio frame.
+ * This version instructs the decoder to decode a either a single metadata
+ * block or a single frame and stop, unless the callbacks return a fatal
+ * error or the read callback returns
+ * \c FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM.
+ *
+ * As the decoder needs more input it will call the read callback.
+ * Depending on what was decoded, the metadata or write callback will be
+ * called with the decoded metadata block or audio frame.
+ *
+ * Unless there is a fatal read error or end of stream, this function
+ * will return once one whole frame is decoded. In other words, if the
+ * stream is not synchronized or points to a corrupt frame header, the
+ * decoder will continue to try and resync until it gets to a valid
+ * frame, then decode one frame, then return. If the decoder points to
+ * a frame whose frame CRC in the frame footer does not match the
+ * computed frame CRC, this function will issue a
+ * FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH error to the
+ * error callback, and return, having decoded one complete, although
+ * corrupt, frame. (Such corrupted frames are sent as silence of the
+ * correct length to the write callback.)
+ *
+ * \param decoder An initialized decoder instance.
+ * \assert
+ * \code decoder != NULL \endcode
+ * \retval FLAC__bool
+ * \c false if any fatal read, write, or memory allocation error
+ * occurred (meaning decoding must stop), else \c true; for more
+ * information about the decoder, check the decoder state with
+ * FLAC__stream_decoder_get_state().
+ */
+FLAC_API FLAC__bool FLAC__stream_decoder_process_single(FLAC__StreamDecoder *decoder);
+
+/** Decode until the end of the metadata.
+ * This version instructs the decoder to decode from the current position
+ * and continue until all the metadata has been read, or until the
+ * callbacks return a fatal error or the read callback returns
+ * \c FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM.
+ *
+ * As the decoder needs more input it will call the read callback.
+ * As each metadata block is decoded, the metadata callback will be called
+ * with the decoded metadata.
+ *
+ * \param decoder An initialized decoder instance.
+ * \assert
+ * \code decoder != NULL \endcode
+ * \retval FLAC__bool
+ * \c false if any fatal read, write, or memory allocation error
+ * occurred (meaning decoding must stop), else \c true; for more
+ * information about the decoder, check the decoder state with
+ * FLAC__stream_decoder_get_state().
+ */
+FLAC_API FLAC__bool FLAC__stream_decoder_process_until_end_of_metadata(FLAC__StreamDecoder *decoder);
+
+/** Decode until the end of the stream.
+ * This version instructs the decoder to decode from the current position
+ * and continue until the end of stream (the read callback returns
+ * \c FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM), or until the
+ * callbacks return a fatal error.
+ *
+ * As the decoder needs more input it will call the read callback.
+ * As each metadata block and frame is decoded, the metadata or write
+ * callback will be called with the decoded metadata or frame.
+ *
+ * \param decoder An initialized decoder instance.
+ * \assert
+ * \code decoder != NULL \endcode
+ * \retval FLAC__bool
+ * \c false if any fatal read, write, or memory allocation error
+ * occurred (meaning decoding must stop), else \c true; for more
+ * information about the decoder, check the decoder state with
+ * FLAC__stream_decoder_get_state().
+ */
+FLAC_API FLAC__bool FLAC__stream_decoder_process_until_end_of_stream(FLAC__StreamDecoder *decoder);
+
+/** Skip one audio frame.
+ * This version instructs the decoder to 'skip' a single frame and stop,
+ * unless the callbacks return a fatal error or the read callback returns
+ * \c FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM.
+ *
+ * The decoding flow is the same as what occurs when
+ * FLAC__stream_decoder_process_single() is called to process an audio
+ * frame, except that this function does not decode the parsed data into
+ * PCM or call the write callback. The integrity of the frame is still
+ * checked the same way as in the other process functions.
+ *
+ * This function will return once one whole frame is skipped, in the
+ * same way that FLAC__stream_decoder_process_single() will return once
+ * one whole frame is decoded.
+ *
+ * This function can be used in more quickly determining FLAC frame
+ * boundaries when decoding of the actual data is not needed, for
+ * example when an application is separating a FLAC stream into frames
+ * for editing or storing in a container. To do this, the application
+ * can use FLAC__stream_decoder_skip_single_frame() to quickly advance
+ * to the next frame, then use
+ * FLAC__stream_decoder_get_decode_position() to find the new frame
+ * boundary.
+ *
+ * This function should only be called when the stream has advanced
+ * past all the metadata, otherwise it will return \c false.
+ *
+ * \param decoder An initialized decoder instance not in a metadata
+ * state.
+ * \assert
+ * \code decoder != NULL \endcode
+ * \retval FLAC__bool
+ * \c false if any fatal read, write, or memory allocation error
+ * occurred (meaning decoding must stop), or if the decoder
+ * is in the FLAC__STREAM_DECODER_SEARCH_FOR_METADATA or
+ * FLAC__STREAM_DECODER_READ_METADATA state, else \c true; for more
+ * information about the decoder, check the decoder state with
+ * FLAC__stream_decoder_get_state().
+ */
+FLAC_API FLAC__bool FLAC__stream_decoder_skip_single_frame(FLAC__StreamDecoder *decoder);
+
+/** Flush the input and seek to an absolute sample.
+ * Decoding will resume at the given sample. Note that because of
+ * this, the next write callback may contain a partial block. The
+ * client must support seeking the input or this function will fail
+ * and return \c false. Furthermore, if the decoder state is
+ * \c FLAC__STREAM_DECODER_SEEK_ERROR, then the decoder must be flushed
+ * with FLAC__stream_decoder_flush() or reset with
+ * FLAC__stream_decoder_reset() before decoding can continue.
+ *
+ * \param decoder A decoder instance.
+ * \param sample The target sample number to seek to.
+ * \assert
+ * \code decoder != NULL \endcode
+ * \retval FLAC__bool
+ * \c true if successful, else \c false.
+ */
+FLAC_API FLAC__bool FLAC__stream_decoder_seek_absolute(FLAC__StreamDecoder *decoder, FLAC__uint64 sample);
+
+/* \} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
+++ b/src/libflac/NOTE.txt
@@ -1,0 +1,4 @@
+8bitbubsy:
+This is a cut down and modified version of libFLAC v1.3.3.
+I have removed stuff I don't want, and only left the decoder in. Please don't
+use this outside of the FT2 clone project!
--- /dev/null
+++ b/src/libflac/bitmath.c
@@ -1,0 +1,69 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2001-2009 Josh Coalson
+ * Copyright (C) 2011-2016 Xiph.Org Foundation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "private/bitmath.h"
+
+/* An example of what FLAC__bitmath_silog2() computes:
+ *
+ * silog2(-10) = 5
+ * silog2(- 9) = 5
+ * silog2(- 8) = 4
+ * silog2(- 7) = 4
+ * silog2(- 6) = 4
+ * silog2(- 5) = 4
+ * silog2(- 4) = 3
+ * silog2(- 3) = 3
+ * silog2(- 2) = 2
+ * silog2(- 1) = 2
+ * silog2( 0) = 0
+ * silog2( 1) = 2
+ * silog2( 2) = 3
+ * silog2( 3) = 3
+ * silog2( 4) = 4
+ * silog2( 5) = 4
+ * silog2( 6) = 4
+ * silog2( 7) = 4
+ * silog2( 8) = 5
+ * silog2( 9) = 5
+ * silog2( 10) = 5
+ */
+uint32_t FLAC__bitmath_silog2(FLAC__int64 v)
+{
+ if(v == 0)
+ return 0;
+
+ if(v == -1)
+ return 2;
+
+ v = (v < 0) ? (-(v+1)) : v;
+ return FLAC__bitmath_ilog2_wide(v)+2;
+}
--- /dev/null
+++ b/src/libflac/bitreader.c
@@ -1,0 +1,914 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000-2009 Josh Coalson
+ * Copyright (C) 2011-2018 Xiph.Org Foundation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include "private/bitmath.h"
+#include "private/bitreader.h"
+#include "private/crc.h"
+#include "private/macros.h"
+#include "share/compat.h"
+#include "share/endswap.h"
+
+/* Things should be fastest when this matches the machine word size */
+/* WATCHOUT: if you change this you must also change the following #defines down to COUNT_ZERO_MSBS2 below to match */
+/* WATCHOUT: there are a few places where the code will not work unless brword is >= 32 bits wide */
+/* also, some sections currently only have fast versions for 4 or 8 bytes per word */
+
+#if (ENABLE_64_BIT_WORDS == 0)
+
+typedef FLAC__uint32 brword;
+#define FLAC__BYTES_PER_WORD 4 /* sizeof brword */
+#define FLAC__BITS_PER_WORD 32
+#define FLAC__WORD_ALL_ONES ((FLAC__uint32)0xffffffff)
+/* SWAP_BE_WORD_TO_HOST swaps bytes in a brword (which is always big-endian) if necessary to match host byte order */
+#define SWAP_BE_WORD_TO_HOST(x) ENDSWAP_32(x)
+/* counts the # of zero MSBs in a word */
+#define COUNT_ZERO_MSBS(word) FLAC__clz_uint32(word)
+#define COUNT_ZERO_MSBS2(word) FLAC__clz2_uint32(word)
+
+#else
+
+typedef FLAC__uint64 brword;
+#define FLAC__BYTES_PER_WORD 8 /* sizeof brword */
+#define FLAC__BITS_PER_WORD 64
+#define FLAC__WORD_ALL_ONES ((FLAC__uint64)FLAC__U64L(0xffffffffffffffff))
+/* SWAP_BE_WORD_TO_HOST swaps bytes in a brword (which is always big-endian) if necessary to match host byte order */
+#define SWAP_BE_WORD_TO_HOST(x) ENDSWAP_64(x)
+/* counts the # of zero MSBs in a word */
+#define COUNT_ZERO_MSBS(word) FLAC__clz_uint64(word)
+#define COUNT_ZERO_MSBS2(word) FLAC__clz2_uint64(word)
+
+#endif
+
+/*
+ * This should be at least twice as large as the largest number of words
+ * required to represent any 'number' (in any encoding) you are going to
+ * read. With FLAC this is on the order of maybe a few hundred bits.
+ * If the buffer is smaller than that, the decoder won't be able to read
+ * in a whole number that is in a variable length encoding (e.g. Rice).
+ * But to be practical it should be at least 1K bytes.
+ *
+ * Increase this number to decrease the number of read callbacks, at the
+ * expense of using more memory. Or decrease for the reverse effect,
+ * keeping in mind the limit from the first paragraph. The optimal size
+ * also depends on the CPU cache size and other factors; some twiddling
+ * may be necessary to squeeze out the best performance.
+ */
+static const uint32_t FLAC__BITREADER_DEFAULT_CAPACITY = 65536u / FLAC__BITS_PER_WORD; /* in words */
+
+struct FLAC__BitReader {
+ /* any partially-consumed word at the head will stay right-justified as bits are consumed from the left */
+ /* any incomplete word at the tail will be left-justified, and bytes from the read callback are added on the right */
+ brword *buffer;
+ uint32_t capacity; /* in words */
+ uint32_t words; /* # of completed words in buffer */
+ uint32_t bytes; /* # of bytes in incomplete word at buffer[words] */
+ uint32_t consumed_words; /* #words ... */
+ uint32_t consumed_bits; /* ... + (#bits of head word) already consumed from the front of buffer */
+ uint32_t read_crc16; /* the running frame CRC */
+ uint32_t crc16_offset; /* the number of words in the current buffer that should not be CRC'd */
+ uint32_t crc16_align; /* the number of bits in the current consumed word that should not be CRC'd */
+ FLAC__BitReaderReadCallback read_callback;
+ void *client_data;
+};
+
+static inline void crc16_update_word_(FLAC__BitReader *br, brword word)
+{
+ register uint32_t crc = br->read_crc16;
+
+ for( ; br->crc16_align < FLAC__BITS_PER_WORD; br->crc16_align += 8)
+ crc = FLAC__CRC16_UPDATE((uint32_t)((word >> (FLAC__BITS_PER_WORD-8-br->crc16_align)) & 0xff), crc);
+
+ br->read_crc16 = crc;
+ br->crc16_align = 0;
+}
+
+static inline void crc16_update_block_(FLAC__BitReader *br)
+{
+ if(br->consumed_words > br->crc16_offset && br->crc16_align)
+ crc16_update_word_(br, br->buffer[br->crc16_offset++]);
+
+#if FLAC__BYTES_PER_WORD == 4
+ br->read_crc16 = FLAC__crc16_update_words32(br->buffer + br->crc16_offset, br->consumed_words - br->crc16_offset, (FLAC__uint16)br->read_crc16);
+#elif FLAC__BYTES_PER_WORD == 8
+ br->read_crc16 = FLAC__crc16_update_words64(br->buffer + br->crc16_offset, br->consumed_words - br->crc16_offset, br->read_crc16);
+#else
+ unsigned i;
+
+ for(i = br->crc16_offset; i < br->consumed_words; i++)
+ crc16_update_word_(br, br->buffer[i]);
+#endif
+
+ br->crc16_offset = 0;
+}
+
+static FLAC__bool bitreader_read_from_client_(FLAC__BitReader *br)
+{
+ uint32_t start, end;
+ size_t bytes;
+ FLAC__byte *target;
+
+ /* first shift the unconsumed buffer data toward the front as much as possible */
+ if(br->consumed_words > 0) {
+ crc16_update_block_(br); /* CRC consumed words */
+
+ start = br->consumed_words;
+ end = br->words + (br->bytes? 1:0);
+ memmove(br->buffer, br->buffer+start, FLAC__BYTES_PER_WORD * (end - start));
+
+ br->words -= start;
+ br->consumed_words = 0;
+ }
+
+ /*
+ * set the target for reading, taking into account word alignment and endianness
+ */
+ bytes = (br->capacity - br->words) * FLAC__BYTES_PER_WORD - br->bytes;
+ if(bytes == 0)
+ return false; /* no space left, buffer is too small; see note for FLAC__BITREADER_DEFAULT_CAPACITY */
+ target = ((FLAC__byte*)(br->buffer+br->words)) + br->bytes;
+
+ /* before reading, if the existing reader looks like this (say brword is 32 bits wide)
+ * bitstream : 11 22 33 44 55 br->words=1 br->bytes=1 (partial tail word is left-justified)
+ * buffer[BE]: 11 22 33 44 55 ?? ?? ?? (shown laid out as bytes sequentially in memory)
+ * buffer[LE]: 44 33 22 11 ?? ?? ?? 55 (?? being don't-care)
+ * ^^-------target, bytes=3
+ * on LE machines, have to byteswap the odd tail word so nothing is
+ * overwritten:
+ */
+ if(br->bytes)
+ br->buffer[br->words] = SWAP_BE_WORD_TO_HOST(br->buffer[br->words]);
+
+ /* now it looks like:
+ * bitstream : 11 22 33 44 55 br->words=1 br->bytes=1
+ * buffer[BE]: 11 22 33 44 55 ?? ?? ??
+ * buffer[LE]: 44 33 22 11 55 ?? ?? ??
+ * ^^-------target, bytes=3
+ */
+
+ /* read in the data; note that the callback may return a smaller number of bytes */
+ if(!br->read_callback(target, &bytes, br->client_data))
+ return false;
+
+ /* after reading bytes 66 77 88 99 AA BB CC DD EE FF from the client:
+ * bitstream : 11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF
+ * buffer[BE]: 11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF ??
+ * buffer[LE]: 44 33 22 11 55 66 77 88 99 AA BB CC DD EE FF ??
+ * now have to byteswap on LE machines:
+ */
+ end = (br->words*FLAC__BYTES_PER_WORD + br->bytes + (uint32_t)bytes + (FLAC__BYTES_PER_WORD-1)) / FLAC__BYTES_PER_WORD;
+ for(start = br->words; start < end; start++)
+ br->buffer[start] = SWAP_BE_WORD_TO_HOST(br->buffer[start]);
+
+ /* now it looks like:
+ * bitstream : 11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF
+ * buffer[BE]: 11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF ??
+ * buffer[LE]: 44 33 22 11 88 77 66 55 CC BB AA 99 ?? FF EE DD
+ * finally we'll update the reader values:
+ */
+ end = br->words*FLAC__BYTES_PER_WORD + br->bytes + (uint32_t)bytes;
+ br->words = end / FLAC__BYTES_PER_WORD;
+ br->bytes = end % FLAC__BYTES_PER_WORD;
+
+ return true;
+}
+
+/***********************************************************************
+ *
+ * Class constructor/destructor
+ *
+ ***********************************************************************/
+
+FLAC__BitReader *FLAC__bitreader_new(void)
+{
+ FLAC__BitReader *br = calloc(1, sizeof(FLAC__BitReader));
+
+ /* calloc() implies:
+ memset(br, 0, sizeof(FLAC__BitReader));
+ br->buffer = 0;
+ br->capacity = 0;
+ br->words = br->bytes = 0;
+ br->consumed_words = br->consumed_bits = 0;
+ br->read_callback = 0;
+ br->client_data = 0;
+ */
+ return br;
+}
+
+void FLAC__bitreader_delete(FLAC__BitReader *br)
+{
+ FLAC__bitreader_free(br);
+ free(br);
+}
+
+/***********************************************************************
+ *
+ * Public class methods
+ *
+ ***********************************************************************/
+
+FLAC__bool FLAC__bitreader_init(FLAC__BitReader *br, FLAC__BitReaderReadCallback rcb, void *cd)
+{
+ br->words = br->bytes = 0;
+ br->consumed_words = br->consumed_bits = 0;
+ br->capacity = FLAC__BITREADER_DEFAULT_CAPACITY;
+ br->buffer = malloc(sizeof(brword) * br->capacity);
+ if(br->buffer == 0)
+ return false;
+ br->read_callback = rcb;
+ br->client_data = cd;
+
+ return true;
+}
+
+void FLAC__bitreader_free(FLAC__BitReader *br)
+{
+ if(0 != br->buffer)
+ free(br->buffer);
+ br->buffer = 0;
+ br->capacity = 0;
+ br->words = br->bytes = 0;
+ br->consumed_words = br->consumed_bits = 0;
+ br->read_callback = 0;
+ br->client_data = 0;
+}
+
+FLAC__bool FLAC__bitreader_clear(FLAC__BitReader *br)
+{
+ br->words = br->bytes = 0;
+ br->consumed_words = br->consumed_bits = 0;
+ return true;
+}
+
+void FLAC__bitreader_dump(const FLAC__BitReader *br, FILE *out)
+{
+ uint32_t i, j;
+ if(br == 0) {
+ fprintf(out, "bitreader is NULL\n");
+ }
+ else {
+ fprintf(out, "bitreader: capacity=%u words=%u bytes=%u consumed: words=%u, bits=%u\n", br->capacity, br->words, br->bytes, br->consumed_words, br->consumed_bits);
+
+ for(i = 0; i < br->words; i++) {
+ fprintf(out, "%08X: ", i);
+ for(j = 0; j < FLAC__BITS_PER_WORD; j++)
+ if(i < br->consumed_words || (i == br->consumed_words && j < br->consumed_bits))
+ fprintf(out, ".");
+ else
+ fprintf(out, "%01d", br->buffer[i] & ((brword)1 << (FLAC__BITS_PER_WORD-j-1)) ? 1:0);
+ fprintf(out, "\n");
+ }
+ if(br->bytes > 0) {
+ fprintf(out, "%08X: ", i);
+ for(j = 0; j < br->bytes*8; j++)
+ if(i < br->consumed_words || (i == br->consumed_words && j < br->consumed_bits))
+ fprintf(out, ".");
+ else
+ fprintf(out, "%01d", br->buffer[i] & ((brword)1 << (br->bytes*8-j-1)) ? 1:0);
+ fprintf(out, "\n");
+ }
+ }
+}
+
+void FLAC__bitreader_reset_read_crc16(FLAC__BitReader *br, FLAC__uint16 seed)
+{
+ br->read_crc16 = (uint32_t)seed;
+ br->crc16_offset = br->consumed_words;
+ br->crc16_align = br->consumed_bits;
+}
+
+FLAC__uint16 FLAC__bitreader_get_read_crc16(FLAC__BitReader *br)
+{
+ /* CRC consumed words up to here */
+ crc16_update_block_(br);
+
+ /* CRC any tail bytes in a partially-consumed word */
+ if(br->consumed_bits) {
+ const brword tail = br->buffer[br->consumed_words];
+ for( ; br->crc16_align < br->consumed_bits; br->crc16_align += 8)
+ br->read_crc16 = FLAC__CRC16_UPDATE((uint32_t)((tail >> (FLAC__BITS_PER_WORD-8-br->crc16_align)) & 0xff), br->read_crc16);
+ }
+ return (FLAC__uint16)br->read_crc16;
+}
+
+inline FLAC__bool FLAC__bitreader_is_consumed_byte_aligned(const FLAC__BitReader *br)
+{
+ return ((br->consumed_bits & 7) == 0);
+}
+
+inline uint32_t FLAC__bitreader_bits_left_for_byte_alignment(const FLAC__BitReader *br)
+{
+ return 8 - (br->consumed_bits & 7);
+}
+
+inline uint32_t FLAC__bitreader_get_input_bits_unconsumed(const FLAC__BitReader *br)
+{
+ return (br->words-br->consumed_words)*FLAC__BITS_PER_WORD + br->bytes*8 - br->consumed_bits;
+}
+
+FLAC__bool FLAC__bitreader_read_raw_uint32(FLAC__BitReader *br, FLAC__uint32 *val, uint32_t bits)
+{
+ if(bits == 0) { /* OPT: investigate if this can ever happen, maybe change to assertion */
+ *val = 0;
+ return true;
+ }
+
+ while((br->words-br->consumed_words)*FLAC__BITS_PER_WORD + br->bytes*8 - br->consumed_bits < bits) {
+ if(!bitreader_read_from_client_(br))
+ return false;
+ }
+ if(br->consumed_words < br->words) { /* if we've not consumed up to a partial tail word... */
+ /* OPT: taking out the consumed_bits==0 "else" case below might make things faster if less code allows the compiler to inline this function */
+ if(br->consumed_bits) {
+ /* this also works when consumed_bits==0, it's just a little slower than necessary for that case */
+ const uint32_t n = FLAC__BITS_PER_WORD - br->consumed_bits;
+ const brword word = br->buffer[br->consumed_words];
+ if(bits < n) {
+ *val = (FLAC__uint32)((word & (FLAC__WORD_ALL_ONES >> br->consumed_bits)) >> (n-bits)); /* The result has <= 32 non-zero bits */
+ br->consumed_bits += bits;
+ return true;
+ }
+ /* (FLAC__BITS_PER_WORD - br->consumed_bits <= bits) ==> (FLAC__WORD_ALL_ONES >> br->consumed_bits) has no more than 'bits' non-zero bits */
+ *val = (FLAC__uint32)(word & (FLAC__WORD_ALL_ONES >> br->consumed_bits));
+ bits -= n;
+ br->consumed_words++;
+ br->consumed_bits = 0;
+ if(bits) { /* if there are still bits left to read, there have to be less than 32 so they will all be in the next word */
+ *val <<= bits;
+ *val |= (FLAC__uint32)(br->buffer[br->consumed_words] >> (FLAC__BITS_PER_WORD-bits));
+ br->consumed_bits = bits;
+ }
+ return true;
+ }
+ else { /* br->consumed_bits == 0 */
+ const brword word = br->buffer[br->consumed_words];
+ if(bits < FLAC__BITS_PER_WORD) {
+ *val = (FLAC__uint32)(word >> (FLAC__BITS_PER_WORD-bits));
+ br->consumed_bits = bits;
+ return true;
+ }
+ /* at this point bits == FLAC__BITS_PER_WORD == 32; because of previous assertions, it can't be larger */
+ *val = (FLAC__uint32)word;
+ br->consumed_words++;
+ return true;
+ }
+ }
+ else {
+ /* in this case we're starting our read at a partial tail word;
+ * the reader has guaranteed that we have at least 'bits' bits
+ * available to read, which makes this case simpler.
+ */
+ /* OPT: taking out the consumed_bits==0 "else" case below might make things faster if less code allows the compiler to inline this function */
+ if(br->consumed_bits) {
+ /* this also works when consumed_bits==0, it's just a little slower than necessary for that case */
+ *val = (FLAC__uint32)((br->buffer[br->consumed_words] & (FLAC__WORD_ALL_ONES >> br->consumed_bits)) >> (FLAC__BITS_PER_WORD-br->consumed_bits-bits));
+ br->consumed_bits += bits;
+ return true;
+ }
+ else {
+ *val = (FLAC__uint32)(br->buffer[br->consumed_words] >> (FLAC__BITS_PER_WORD-bits));
+ br->consumed_bits += bits;
+ return true;
+ }
+ }
+}
+
+FLAC__bool FLAC__bitreader_read_raw_int32(FLAC__BitReader *br, FLAC__int32 *val, uint32_t bits)
+{
+ FLAC__uint32 uval, mask;
+ /* OPT: inline raw uint32 code here, or make into a macro if possible in the .h file */
+ if(!FLAC__bitreader_read_raw_uint32(br, &uval, bits))
+ return false;
+ /* sign-extend *val assuming it is currently bits wide. */
+ /* From: https://graphics.stanford.edu/~seander/bithacks.html#FixedSignExtend */
+ mask = 1u << (bits - 1);
+ *val = (uval ^ mask) - mask;
+ return true;
+}
+
+FLAC__bool FLAC__bitreader_read_raw_uint64(FLAC__BitReader *br, FLAC__uint64 *val, uint32_t bits)
+{
+ FLAC__uint32 hi, lo;
+
+ if(bits > 32) {
+ if(!FLAC__bitreader_read_raw_uint32(br, &hi, bits-32))
+ return false;
+ if(!FLAC__bitreader_read_raw_uint32(br, &lo, 32))
+ return false;
+ *val = hi;
+ *val <<= 32;
+ *val |= lo;
+ }
+ else {
+ if(!FLAC__bitreader_read_raw_uint32(br, &lo, bits))
+ return false;
+ *val = lo;
+ }
+ return true;
+}
+
+inline FLAC__bool FLAC__bitreader_read_uint32_little_endian(FLAC__BitReader *br, FLAC__uint32 *val)
+{
+ FLAC__uint32 x8, x32 = 0;
+
+ /* this doesn't need to be that fast as currently it is only used for vorbis comments */
+
+ if(!FLAC__bitreader_read_raw_uint32(br, &x32, 8))
+ return false;
+
+ if(!FLAC__bitreader_read_raw_uint32(br, &x8, 8))
+ return false;
+ x32 |= (x8 << 8);
+
+ if(!FLAC__bitreader_read_raw_uint32(br, &x8, 8))
+ return false;
+ x32 |= (x8 << 16);
+
+ if(!FLAC__bitreader_read_raw_uint32(br, &x8, 8))
+ return false;
+ x32 |= (x8 << 24);
+
+ *val = x32;
+ return true;
+}
+
+FLAC__bool FLAC__bitreader_skip_bits_no_crc(FLAC__BitReader *br, uint32_t bits)
+{
+ /*
+ * OPT: a faster implementation is possible but probably not that useful
+ * since this is only called a couple of times in the metadata readers.
+ */
+
+ if(bits > 0) {
+ const uint32_t n = br->consumed_bits & 7;
+ uint32_t m;
+ FLAC__uint32 x;
+
+ if(n != 0) {
+ m = flac_min(8-n, bits);
+ if(!FLAC__bitreader_read_raw_uint32(br, &x, m))
+ return false;
+ bits -= m;
+ }
+ m = bits / 8;
+ if(m > 0) {
+ if(!FLAC__bitreader_skip_byte_block_aligned_no_crc(br, m))
+ return false;
+ bits %= 8;
+ }
+ if(bits > 0) {
+ if(!FLAC__bitreader_read_raw_uint32(br, &x, bits))
+ return false;
+ }
+ }
+
+ return true;
+}
+
+FLAC__bool FLAC__bitreader_skip_byte_block_aligned_no_crc(FLAC__BitReader *br, uint32_t nvals)
+{
+ FLAC__uint32 x;
+
+ /* step 1: skip over partial head word to get word aligned */
+ while(nvals && br->consumed_bits) { /* i.e. run until we read 'nvals' bytes or we hit the end of the head word */
+ if(!FLAC__bitreader_read_raw_uint32(br, &x, 8))
+ return false;
+ nvals--;
+ }
+ if(0 == nvals)
+ return true;
+ /* step 2: skip whole words in chunks */
+ while(nvals >= FLAC__BYTES_PER_WORD) {
+ if(br->consumed_words < br->words) {
+ br->consumed_words++;
+ nvals -= FLAC__BYTES_PER_WORD;
+ }
+ else if(!bitreader_read_from_client_(br))
+ return false;
+ }
+ /* step 3: skip any remainder from partial tail bytes */
+ while(nvals) {
+ if(!FLAC__bitreader_read_raw_uint32(br, &x, 8))
+ return false;
+ nvals--;
+ }
+
+ return true;
+}
+
+FLAC__bool FLAC__bitreader_read_byte_block_aligned_no_crc(FLAC__BitReader *br, FLAC__byte *val, uint32_t nvals)
+{
+ FLAC__uint32 x;
+
+ /* step 1: read from partial head word to get word aligned */
+ while(nvals && br->consumed_bits) { /* i.e. run until we read 'nvals' bytes or we hit the end of the head word */
+ if(!FLAC__bitreader_read_raw_uint32(br, &x, 8))
+ return false;
+ *val++ = (FLAC__byte)x;
+ nvals--;
+ }
+ if(0 == nvals)
+ return true;
+ /* step 2: read whole words in chunks */
+ while(nvals >= FLAC__BYTES_PER_WORD) {
+ if(br->consumed_words < br->words) {
+ const brword word = br->buffer[br->consumed_words++];
+#if FLAC__BYTES_PER_WORD == 4
+ val[0] = (FLAC__byte)(word >> 24);
+ val[1] = (FLAC__byte)(word >> 16);
+ val[2] = (FLAC__byte)(word >> 8);
+ val[3] = (FLAC__byte)word;
+#elif FLAC__BYTES_PER_WORD == 8
+ val[0] = (FLAC__byte)(word >> 56);
+ val[1] = (FLAC__byte)(word >> 48);
+ val[2] = (FLAC__byte)(word >> 40);
+ val[3] = (FLAC__byte)(word >> 32);
+ val[4] = (FLAC__byte)(word >> 24);
+ val[5] = (FLAC__byte)(word >> 16);
+ val[6] = (FLAC__byte)(word >> 8);
+ val[7] = (FLAC__byte)word;
+#else
+ for(x = 0; x < FLAC__BYTES_PER_WORD; x++)
+ val[x] = (FLAC__byte)(word >> (8*(FLAC__BYTES_PER_WORD-x-1)));
+#endif
+ val += FLAC__BYTES_PER_WORD;
+ nvals -= FLAC__BYTES_PER_WORD;
+ }
+ else if(!bitreader_read_from_client_(br))
+ return false;
+ }
+ /* step 3: read any remainder from partial tail bytes */
+ while(nvals) {
+ if(!FLAC__bitreader_read_raw_uint32(br, &x, 8))
+ return false;
+ *val++ = (FLAC__byte)x;
+ nvals--;
+ }
+
+ return true;
+}
+
+FLAC__bool FLAC__bitreader_read_unary_unsigned(FLAC__BitReader *br, uint32_t *val)
+{
+ uint32_t i;
+
+ *val = 0;
+ while(1) {
+ while(br->consumed_words < br->words) { /* if we've not consumed up to a partial tail word... */
+ brword b = br->buffer[br->consumed_words] << br->consumed_bits;
+ if(b) {
+ i = COUNT_ZERO_MSBS(b);
+ *val += i;
+ i++;
+ br->consumed_bits += i;
+ if(br->consumed_bits >= FLAC__BITS_PER_WORD) { /* faster way of testing if(br->consumed_bits == FLAC__BITS_PER_WORD) */
+ br->consumed_words++;
+ br->consumed_bits = 0;
+ }
+ return true;
+ }
+ else {
+ *val += FLAC__BITS_PER_WORD - br->consumed_bits;
+ br->consumed_words++;
+ br->consumed_bits = 0;
+ /* didn't find stop bit yet, have to keep going... */
+ }
+ }
+ /* at this point we've eaten up all the whole words; have to try
+ * reading through any tail bytes before calling the read callback.
+ * this is a repeat of the above logic adjusted for the fact we
+ * don't have a whole word. note though if the client is feeding
+ * us data a byte at a time (unlikely), br->consumed_bits may not
+ * be zero.
+ */
+ if(br->bytes*8 > br->consumed_bits) {
+ const uint32_t end = br->bytes * 8;
+ brword b = (br->buffer[br->consumed_words] & (FLAC__WORD_ALL_ONES << (FLAC__BITS_PER_WORD-end))) << br->consumed_bits;
+ if(b) {
+ i = COUNT_ZERO_MSBS(b);
+ *val += i;
+ i++;
+ br->consumed_bits += i;
+ return true;
+ }
+ else {
+ *val += end - br->consumed_bits;
+ br->consumed_bits = end;
+ /* didn't find stop bit yet, have to keep going... */
+ }
+ }
+ if(!bitreader_read_from_client_(br))
+ return false;
+ }
+}
+
+FLAC__bool FLAC__bitreader_read_rice_signed(FLAC__BitReader *br, int *val, uint32_t parameter)
+{
+ FLAC__uint32 lsbs = 0, msbs = 0;
+ uint32_t uval;
+
+ /* read the unary MSBs and end bit */
+ if(!FLAC__bitreader_read_unary_unsigned(br, &msbs))
+ return false;
+
+ /* read the binary LSBs */
+ if(!FLAC__bitreader_read_raw_uint32(br, &lsbs, parameter))
+ return false;
+
+ /* compose the value */
+ uval = (msbs << parameter) | lsbs;
+ if(uval & 1)
+ *val = -((int)(uval >> 1)) - 1;
+ else
+ *val = (int)(uval >> 1);
+
+ return true;
+}
+
+/* this is by far the most heavily used reader call. it ain't pretty but it's fast */
+FLAC__bool FLAC__bitreader_read_rice_signed_block(FLAC__BitReader *br, int vals[], uint32_t nvals, uint32_t parameter)
+{
+ /* try and get br->consumed_words and br->consumed_bits into register;
+ * must remember to flush them back to *br before calling other
+ * bitreader functions that use them, and before returning */
+ uint32_t cwords, words, lsbs, msbs, x, y;
+ uint32_t ucbits; /* keep track of the number of unconsumed bits in word */
+ brword b;
+ int *val, *end;
+
+ val = vals;
+ end = vals + nvals;
+
+ if(parameter == 0) {
+ while(val < end) {
+ /* read the unary MSBs and end bit */
+ if(!FLAC__bitreader_read_unary_unsigned(br, &msbs))
+ return false;
+
+ *val++ = (int)(msbs >> 1) ^ -(int)(msbs & 1);
+ }
+
+ return true;
+ }
+
+ cwords = br->consumed_words;
+ words = br->words;
+
+ /* if we've not consumed up to a partial tail word... */
+ if(cwords >= words) {
+ x = 0;
+ goto process_tail;
+ }
+
+ ucbits = FLAC__BITS_PER_WORD - br->consumed_bits;
+ b = br->buffer[cwords] << br->consumed_bits; /* keep unconsumed bits aligned to left */
+
+ while(val < end) {
+ /* read the unary MSBs and end bit */
+ x = y = COUNT_ZERO_MSBS2(b);
+ if(x == FLAC__BITS_PER_WORD) {
+ x = ucbits;
+ do {
+ /* didn't find stop bit yet, have to keep going... */
+ cwords++;
+ if (cwords >= words)
+ goto incomplete_msbs;
+ b = br->buffer[cwords];
+ y = COUNT_ZERO_MSBS2(b);
+ x += y;
+ } while(y == FLAC__BITS_PER_WORD);
+ }
+ b <<= y;
+ b <<= 1; /* account for stop bit */
+ ucbits = (ucbits - x - 1) % FLAC__BITS_PER_WORD;
+ msbs = x;
+
+ /* read the binary LSBs */
+ x = (FLAC__uint32)(b >> (FLAC__BITS_PER_WORD - parameter)); /* parameter < 32, so we can cast to 32-bit uint32_t */
+ if(parameter <= ucbits) {
+ ucbits -= parameter;
+ b <<= parameter;
+ } else {
+ /* there are still bits left to read, they will all be in the next word */
+ cwords++;
+ if (cwords >= words)
+ goto incomplete_lsbs;
+ b = br->buffer[cwords];
+ ucbits += FLAC__BITS_PER_WORD - parameter;
+ x |= (FLAC__uint32)(b >> ucbits);
+ b <<= FLAC__BITS_PER_WORD - ucbits;
+ }
+ lsbs = x;
+
+ /* compose the value */
+ x = (msbs << parameter) | lsbs;
+ *val++ = (int)(x >> 1) ^ -(int)(x & 1);
+
+ continue;
+
+ /* at this point we've eaten up all the whole words */
+process_tail:
+ do {
+ if(0) {
+incomplete_msbs:
+ br->consumed_bits = 0;
+ br->consumed_words = cwords;
+ }
+
+ /* read the unary MSBs and end bit */
+ if(!FLAC__bitreader_read_unary_unsigned(br, &msbs))
+ return false;
+ msbs += x;
+ x = ucbits = 0;
+
+ if(0) {
+incomplete_lsbs:
+ br->consumed_bits = 0;
+ br->consumed_words = cwords;
+ }
+
+ /* read the binary LSBs */
+ if(!FLAC__bitreader_read_raw_uint32(br, &lsbs, parameter - ucbits))
+ return false;
+ lsbs = x | lsbs;
+
+ /* compose the value */
+ x = (msbs << parameter) | lsbs;
+ *val++ = (int)(x >> 1) ^ -(int)(x & 1);
+ x = 0;
+
+ cwords = br->consumed_words;
+ words = br->words;
+ ucbits = FLAC__BITS_PER_WORD - br->consumed_bits;
+ b = br->buffer[cwords] << br->consumed_bits;
+ } while(cwords >= words && val < end);
+ }
+
+ if(ucbits == 0 && cwords < words) {
+ /* don't leave the head word with no unconsumed bits */
+ cwords++;
+ ucbits = FLAC__BITS_PER_WORD;
+ }
+
+ br->consumed_bits = FLAC__BITS_PER_WORD - ucbits;
+ br->consumed_words = cwords;
+
+ return true;
+}
+
+/* on return, if *val == 0xffffffff then the utf-8 sequence was invalid, but the return value will be true */
+FLAC__bool FLAC__bitreader_read_utf8_uint32(FLAC__BitReader *br, FLAC__uint32 *val, FLAC__byte *raw, uint32_t *rawlen)
+{
+ FLAC__uint32 v = 0;
+ FLAC__uint32 x;
+ uint32_t i;
+
+ if(!FLAC__bitreader_read_raw_uint32(br, &x, 8))
+ return false;
+ if(raw)
+ raw[(*rawlen)++] = (FLAC__byte)x;
+ if(!(x & 0x80)) { /* 0xxxxxxx */
+ v = x;
+ i = 0;
+ }
+ else if(x & 0xC0 && !(x & 0x20)) { /* 110xxxxx */
+ v = x & 0x1F;
+ i = 1;
+ }
+ else if(x & 0xE0 && !(x & 0x10)) { /* 1110xxxx */
+ v = x & 0x0F;
+ i = 2;
+ }
+ else if(x & 0xF0 && !(x & 0x08)) { /* 11110xxx */
+ v = x & 0x07;
+ i = 3;
+ }
+ else if(x & 0xF8 && !(x & 0x04)) { /* 111110xx */
+ v = x & 0x03;
+ i = 4;
+ }
+ else if(x & 0xFC && !(x & 0x02)) { /* 1111110x */
+ v = x & 0x01;
+ i = 5;
+ }
+ else {
+ *val = 0xffffffff;
+ return true;
+ }
+ for( ; i; i--) {
+ if(!FLAC__bitreader_read_raw_uint32(br, &x, 8))
+ return false;
+ if(raw)
+ raw[(*rawlen)++] = (FLAC__byte)x;
+ if(!(x & 0x80) || (x & 0x40)) { /* 10xxxxxx */
+ *val = 0xffffffff;
+ return true;
+ }
+ v <<= 6;
+ v |= (x & 0x3F);
+ }
+ *val = v;
+ return true;
+}
+
+/* on return, if *val == 0xffffffffffffffff then the utf-8 sequence was invalid, but the return value will be true */
+FLAC__bool FLAC__bitreader_read_utf8_uint64(FLAC__BitReader *br, FLAC__uint64 *val, FLAC__byte *raw, uint32_t *rawlen)
+{
+ FLAC__uint64 v = 0;
+ FLAC__uint32 x;
+ uint32_t i;
+
+ if(!FLAC__bitreader_read_raw_uint32(br, &x, 8))
+ return false;
+ if(raw)
+ raw[(*rawlen)++] = (FLAC__byte)x;
+ if(!(x & 0x80)) { /* 0xxxxxxx */
+ v = x;
+ i = 0;
+ }
+ else if(x & 0xC0 && !(x & 0x20)) { /* 110xxxxx */
+ v = x & 0x1F;
+ i = 1;
+ }
+ else if(x & 0xE0 && !(x & 0x10)) { /* 1110xxxx */
+ v = x & 0x0F;
+ i = 2;
+ }
+ else if(x & 0xF0 && !(x & 0x08)) { /* 11110xxx */
+ v = x & 0x07;
+ i = 3;
+ }
+ else if(x & 0xF8 && !(x & 0x04)) { /* 111110xx */
+ v = x & 0x03;
+ i = 4;
+ }
+ else if(x & 0xFC && !(x & 0x02)) { /* 1111110x */
+ v = x & 0x01;
+ i = 5;
+ }
+ else if(x & 0xFE && !(x & 0x01)) { /* 11111110 */
+ v = 0;
+ i = 6;
+ }
+ else {
+ *val = FLAC__U64L(0xffffffffffffffff);
+ return true;
+ }
+ for( ; i; i--) {
+ if(!FLAC__bitreader_read_raw_uint32(br, &x, 8))
+ return false;
+ if(raw)
+ raw[(*rawlen)++] = (FLAC__byte)x;
+ if(!(x & 0x80) || (x & 0x40)) { /* 10xxxxxx */
+ *val = FLAC__U64L(0xffffffffffffffff);
+ return true;
+ }
+ v <<= 6;
+ v |= (x & 0x3F);
+ }
+ *val = v;
+ return true;
+}
+
+/* These functions are declared inline in this file but are also callable as
+ * externs from elsewhere.
+ * According to the C99 spec, section 6.7.4, simply providing a function
+ * prototype in a header file without 'inline' and making the function inline
+ * in this file should be sufficient.
+ * Unfortunately, the Microsoft VS compiler doesn't pick them up externally. To
+ * fix that we add extern declarations here.
+ */
+extern FLAC__bool FLAC__bitreader_is_consumed_byte_aligned(const FLAC__BitReader *br);
+extern uint32_t FLAC__bitreader_bits_left_for_byte_alignment(const FLAC__BitReader *br);
+extern uint32_t FLAC__bitreader_get_input_bits_unconsumed(const FLAC__BitReader *br);
+extern FLAC__bool FLAC__bitreader_read_uint32_little_endian(FLAC__BitReader *br, FLAC__uint32 *val);
--- /dev/null
+++ b/src/libflac/crc.c
@@ -1,0 +1,410 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000-2009 Josh Coalson
+ * Copyright (C) 2011-2018 Xiph.Org Foundation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "private/crc.h"
+
+/* CRC-8, poly = x^8 + x^2 + x^1 + x^0, init = 0 */
+
+FLAC__uint8 const FLAC__crc8_table[256] = {
+ 0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15,
+ 0x38, 0x3F, 0x36, 0x31, 0x24, 0x23, 0x2A, 0x2D,
+ 0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65,
+ 0x48, 0x4F, 0x46, 0x41, 0x54, 0x53, 0x5A, 0x5D,
+ 0xE0, 0xE7, 0xEE, 0xE9, 0xFC, 0xFB, 0xF2, 0xF5,
+ 0xD8, 0xDF, 0xD6, 0xD1, 0xC4, 0xC3, 0xCA, 0xCD,
+ 0x90, 0x97, 0x9E, 0x99, 0x8C, 0x8B, 0x82, 0x85,
+ 0xA8, 0xAF, 0xA6, 0xA1, 0xB4, 0xB3, 0xBA, 0xBD,
+ 0xC7, 0xC0, 0xC9, 0xCE, 0xDB, 0xDC, 0xD5, 0xD2,
+ 0xFF, 0xF8, 0xF1, 0xF6, 0xE3, 0xE4, 0xED, 0xEA,
+ 0xB7, 0xB0, 0xB9, 0xBE, 0xAB, 0xAC, 0xA5, 0xA2,
+ 0x8F, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9D, 0x9A,
+ 0x27, 0x20, 0x29, 0x2E, 0x3B, 0x3C, 0x35, 0x32,
+ 0x1F, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0D, 0x0A,
+ 0x57, 0x50, 0x59, 0x5E, 0x4B, 0x4C, 0x45, 0x42,
+ 0x6F, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7D, 0x7A,
+ 0x89, 0x8E, 0x87, 0x80, 0x95, 0x92, 0x9B, 0x9C,
+ 0xB1, 0xB6, 0xBF, 0xB8, 0xAD, 0xAA, 0xA3, 0xA4,
+ 0xF9, 0xFE, 0xF7, 0xF0, 0xE5, 0xE2, 0xEB, 0xEC,
+ 0xC1, 0xC6, 0xCF, 0xC8, 0xDD, 0xDA, 0xD3, 0xD4,
+ 0x69, 0x6E, 0x67, 0x60, 0x75, 0x72, 0x7B, 0x7C,
+ 0x51, 0x56, 0x5F, 0x58, 0x4D, 0x4A, 0x43, 0x44,
+ 0x19, 0x1E, 0x17, 0x10, 0x05, 0x02, 0x0B, 0x0C,
+ 0x21, 0x26, 0x2F, 0x28, 0x3D, 0x3A, 0x33, 0x34,
+ 0x4E, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5C, 0x5B,
+ 0x76, 0x71, 0x78, 0x7F, 0x6A, 0x6D, 0x64, 0x63,
+ 0x3E, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2C, 0x2B,
+ 0x06, 0x01, 0x08, 0x0F, 0x1A, 0x1D, 0x14, 0x13,
+ 0xAE, 0xA9, 0xA0, 0xA7, 0xB2, 0xB5, 0xBC, 0xBB,
+ 0x96, 0x91, 0x98, 0x9F, 0x8A, 0x8D, 0x84, 0x83,
+ 0xDE, 0xD9, 0xD0, 0xD7, 0xC2, 0xC5, 0xCC, 0xCB,
+ 0xE6, 0xE1, 0xE8, 0xEF, 0xFA, 0xFD, 0xF4, 0xF3
+};
+
+/* CRC-16, poly = x^16 + x^15 + x^2 + x^0, init = 0 */
+
+FLAC__uint16 const FLAC__crc16_table[8][256] = {
+ { 0x0000, 0x8005, 0x800f, 0x000a, 0x801b, 0x001e, 0x0014, 0x8011,
+ 0x8033, 0x0036, 0x003c, 0x8039, 0x0028, 0x802d, 0x8027, 0x0022,
+ 0x8063, 0x0066, 0x006c, 0x8069, 0x0078, 0x807d, 0x8077, 0x0072,
+ 0x0050, 0x8055, 0x805f, 0x005a, 0x804b, 0x004e, 0x0044, 0x8041,
+ 0x80c3, 0x00c6, 0x00cc, 0x80c9, 0x00d8, 0x80dd, 0x80d7, 0x00d2,
+ 0x00f0, 0x80f5, 0x80ff, 0x00fa, 0x80eb, 0x00ee, 0x00e4, 0x80e1,
+ 0x00a0, 0x80a5, 0x80af, 0x00aa, 0x80bb, 0x00be, 0x00b4, 0x80b1,
+ 0x8093, 0x0096, 0x009c, 0x8099, 0x0088, 0x808d, 0x8087, 0x0082,
+ 0x8183, 0x0186, 0x018c, 0x8189, 0x0198, 0x819d, 0x8197, 0x0192,
+ 0x01b0, 0x81b5, 0x81bf, 0x01ba, 0x81ab, 0x01ae, 0x01a4, 0x81a1,
+ 0x01e0, 0x81e5, 0x81ef, 0x01ea, 0x81fb, 0x01fe, 0x01f4, 0x81f1,
+ 0x81d3, 0x01d6, 0x01dc, 0x81d9, 0x01c8, 0x81cd, 0x81c7, 0x01c2,
+ 0x0140, 0x8145, 0x814f, 0x014a, 0x815b, 0x015e, 0x0154, 0x8151,
+ 0x8173, 0x0176, 0x017c, 0x8179, 0x0168, 0x816d, 0x8167, 0x0162,
+ 0x8123, 0x0126, 0x012c, 0x8129, 0x0138, 0x813d, 0x8137, 0x0132,
+ 0x0110, 0x8115, 0x811f, 0x011a, 0x810b, 0x010e, 0x0104, 0x8101,
+ 0x8303, 0x0306, 0x030c, 0x8309, 0x0318, 0x831d, 0x8317, 0x0312,
+ 0x0330, 0x8335, 0x833f, 0x033a, 0x832b, 0x032e, 0x0324, 0x8321,
+ 0x0360, 0x8365, 0x836f, 0x036a, 0x837b, 0x037e, 0x0374, 0x8371,
+ 0x8353, 0x0356, 0x035c, 0x8359, 0x0348, 0x834d, 0x8347, 0x0342,
+ 0x03c0, 0x83c5, 0x83cf, 0x03ca, 0x83db, 0x03de, 0x03d4, 0x83d1,
+ 0x83f3, 0x03f6, 0x03fc, 0x83f9, 0x03e8, 0x83ed, 0x83e7, 0x03e2,
+ 0x83a3, 0x03a6, 0x03ac, 0x83a9, 0x03b8, 0x83bd, 0x83b7, 0x03b2,
+ 0x0390, 0x8395, 0x839f, 0x039a, 0x838b, 0x038e, 0x0384, 0x8381,
+ 0x0280, 0x8285, 0x828f, 0x028a, 0x829b, 0x029e, 0x0294, 0x8291,
+ 0x82b3, 0x02b6, 0x02bc, 0x82b9, 0x02a8, 0x82ad, 0x82a7, 0x02a2,
+ 0x82e3, 0x02e6, 0x02ec, 0x82e9, 0x02f8, 0x82fd, 0x82f7, 0x02f2,
+ 0x02d0, 0x82d5, 0x82df, 0x02da, 0x82cb, 0x02ce, 0x02c4, 0x82c1,
+ 0x8243, 0x0246, 0x024c, 0x8249, 0x0258, 0x825d, 0x8257, 0x0252,
+ 0x0270, 0x8275, 0x827f, 0x027a, 0x826b, 0x026e, 0x0264, 0x8261,
+ 0x0220, 0x8225, 0x822f, 0x022a, 0x823b, 0x023e, 0x0234, 0x8231,
+ 0x8213, 0x0216, 0x021c, 0x8219, 0x0208, 0x820d, 0x8207, 0x0202 },
+
+ { 0x0000, 0x8603, 0x8c03, 0x0a00, 0x9803, 0x1e00, 0x1400, 0x9203,
+ 0xb003, 0x3600, 0x3c00, 0xba03, 0x2800, 0xae03, 0xa403, 0x2200,
+ 0xe003, 0x6600, 0x6c00, 0xea03, 0x7800, 0xfe03, 0xf403, 0x7200,
+ 0x5000, 0xd603, 0xdc03, 0x5a00, 0xc803, 0x4e00, 0x4400, 0xc203,
+ 0x4003, 0xc600, 0xcc00, 0x4a03, 0xd800, 0x5e03, 0x5403, 0xd200,
+ 0xf000, 0x7603, 0x7c03, 0xfa00, 0x6803, 0xee00, 0xe400, 0x6203,
+ 0xa000, 0x2603, 0x2c03, 0xaa00, 0x3803, 0xbe00, 0xb400, 0x3203,
+ 0x1003, 0x9600, 0x9c00, 0x1a03, 0x8800, 0x0e03, 0x0403, 0x8200,
+ 0x8006, 0x0605, 0x0c05, 0x8a06, 0x1805, 0x9e06, 0x9406, 0x1205,
+ 0x3005, 0xb606, 0xbc06, 0x3a05, 0xa806, 0x2e05, 0x2405, 0xa206,
+ 0x6005, 0xe606, 0xec06, 0x6a05, 0xf806, 0x7e05, 0x7405, 0xf206,
+ 0xd006, 0x5605, 0x5c05, 0xda06, 0x4805, 0xce06, 0xc406, 0x4205,
+ 0xc005, 0x4606, 0x4c06, 0xca05, 0x5806, 0xde05, 0xd405, 0x5206,
+ 0x7006, 0xf605, 0xfc05, 0x7a06, 0xe805, 0x6e06, 0x6406, 0xe205,
+ 0x2006, 0xa605, 0xac05, 0x2a06, 0xb805, 0x3e06, 0x3406, 0xb205,
+ 0x9005, 0x1606, 0x1c06, 0x9a05, 0x0806, 0x8e05, 0x8405, 0x0206,
+ 0x8009, 0x060a, 0x0c0a, 0x8a09, 0x180a, 0x9e09, 0x9409, 0x120a,
+ 0x300a, 0xb609, 0xbc09, 0x3a0a, 0xa809, 0x2e0a, 0x240a, 0xa209,
+ 0x600a, 0xe609, 0xec09, 0x6a0a, 0xf809, 0x7e0a, 0x740a, 0xf209,
+ 0xd009, 0x560a, 0x5c0a, 0xda09, 0x480a, 0xce09, 0xc409, 0x420a,
+ 0xc00a, 0x4609, 0x4c09, 0xca0a, 0x5809, 0xde0a, 0xd40a, 0x5209,
+ 0x7009, 0xf60a, 0xfc0a, 0x7a09, 0xe80a, 0x6e09, 0x6409, 0xe20a,
+ 0x2009, 0xa60a, 0xac0a, 0x2a09, 0xb80a, 0x3e09, 0x3409, 0xb20a,
+ 0x900a, 0x1609, 0x1c09, 0x9a0a, 0x0809, 0x8e0a, 0x840a, 0x0209,
+ 0x000f, 0x860c, 0x8c0c, 0x0a0f, 0x980c, 0x1e0f, 0x140f, 0x920c,
+ 0xb00c, 0x360f, 0x3c0f, 0xba0c, 0x280f, 0xae0c, 0xa40c, 0x220f,
+ 0xe00c, 0x660f, 0x6c0f, 0xea0c, 0x780f, 0xfe0c, 0xf40c, 0x720f,
+ 0x500f, 0xd60c, 0xdc0c, 0x5a0f, 0xc80c, 0x4e0f, 0x440f, 0xc20c,
+ 0x400c, 0xc60f, 0xcc0f, 0x4a0c, 0xd80f, 0x5e0c, 0x540c, 0xd20f,
+ 0xf00f, 0x760c, 0x7c0c, 0xfa0f, 0x680c, 0xee0f, 0xe40f, 0x620c,
+ 0xa00f, 0x260c, 0x2c0c, 0xaa0f, 0x380c, 0xbe0f, 0xb40f, 0x320c,
+ 0x100c, 0x960f, 0x9c0f, 0x1a0c, 0x880f, 0x0e0c, 0x040c, 0x820f },
+
+ { 0x0000, 0x8017, 0x802b, 0x003c, 0x8053, 0x0044, 0x0078, 0x806f,
+ 0x80a3, 0x00b4, 0x0088, 0x809f, 0x00f0, 0x80e7, 0x80db, 0x00cc,
+ 0x8143, 0x0154, 0x0168, 0x817f, 0x0110, 0x8107, 0x813b, 0x012c,
+ 0x01e0, 0x81f7, 0x81cb, 0x01dc, 0x81b3, 0x01a4, 0x0198, 0x818f,
+ 0x8283, 0x0294, 0x02a8, 0x82bf, 0x02d0, 0x82c7, 0x82fb, 0x02ec,
+ 0x0220, 0x8237, 0x820b, 0x021c, 0x8273, 0x0264, 0x0258, 0x824f,
+ 0x03c0, 0x83d7, 0x83eb, 0x03fc, 0x8393, 0x0384, 0x03b8, 0x83af,
+ 0x8363, 0x0374, 0x0348, 0x835f, 0x0330, 0x8327, 0x831b, 0x030c,
+ 0x8503, 0x0514, 0x0528, 0x853f, 0x0550, 0x8547, 0x857b, 0x056c,
+ 0x05a0, 0x85b7, 0x858b, 0x059c, 0x85f3, 0x05e4, 0x05d8, 0x85cf,
+ 0x0440, 0x8457, 0x846b, 0x047c, 0x8413, 0x0404, 0x0438, 0x842f,
+ 0x84e3, 0x04f4, 0x04c8, 0x84df, 0x04b0, 0x84a7, 0x849b, 0x048c,
+ 0x0780, 0x8797, 0x87ab, 0x07bc, 0x87d3, 0x07c4, 0x07f8, 0x87ef,
+ 0x8723, 0x0734, 0x0708, 0x871f, 0x0770, 0x8767, 0x875b, 0x074c,
+ 0x86c3, 0x06d4, 0x06e8, 0x86ff, 0x0690, 0x8687, 0x86bb, 0x06ac,
+ 0x0660, 0x8677, 0x864b, 0x065c, 0x8633, 0x0624, 0x0618, 0x860f,
+ 0x8a03, 0x0a14, 0x0a28, 0x8a3f, 0x0a50, 0x8a47, 0x8a7b, 0x0a6c,
+ 0x0aa0, 0x8ab7, 0x8a8b, 0x0a9c, 0x8af3, 0x0ae4, 0x0ad8, 0x8acf,
+ 0x0b40, 0x8b57, 0x8b6b, 0x0b7c, 0x8b13, 0x0b04, 0x0b38, 0x8b2f,
+ 0x8be3, 0x0bf4, 0x0bc8, 0x8bdf, 0x0bb0, 0x8ba7, 0x8b9b, 0x0b8c,
+ 0x0880, 0x8897, 0x88ab, 0x08bc, 0x88d3, 0x08c4, 0x08f8, 0x88ef,
+ 0x8823, 0x0834, 0x0808, 0x881f, 0x0870, 0x8867, 0x885b, 0x084c,
+ 0x89c3, 0x09d4, 0x09e8, 0x89ff, 0x0990, 0x8987, 0x89bb, 0x09ac,
+ 0x0960, 0x8977, 0x894b, 0x095c, 0x8933, 0x0924, 0x0918, 0x890f,
+ 0x0f00, 0x8f17, 0x8f2b, 0x0f3c, 0x8f53, 0x0f44, 0x0f78, 0x8f6f,
+ 0x8fa3, 0x0fb4, 0x0f88, 0x8f9f, 0x0ff0, 0x8fe7, 0x8fdb, 0x0fcc,
+ 0x8e43, 0x0e54, 0x0e68, 0x8e7f, 0x0e10, 0x8e07, 0x8e3b, 0x0e2c,
+ 0x0ee0, 0x8ef7, 0x8ecb, 0x0edc, 0x8eb3, 0x0ea4, 0x0e98, 0x8e8f,
+ 0x8d83, 0x0d94, 0x0da8, 0x8dbf, 0x0dd0, 0x8dc7, 0x8dfb, 0x0dec,
+ 0x0d20, 0x8d37, 0x8d0b, 0x0d1c, 0x8d73, 0x0d64, 0x0d58, 0x8d4f,
+ 0x0cc0, 0x8cd7, 0x8ceb, 0x0cfc, 0x8c93, 0x0c84, 0x0cb8, 0x8caf,
+ 0x8c63, 0x0c74, 0x0c48, 0x8c5f, 0x0c30, 0x8c27, 0x8c1b, 0x0c0c },
+
+ { 0x0000, 0x9403, 0xa803, 0x3c00, 0xd003, 0x4400, 0x7800, 0xec03,
+ 0x2003, 0xb400, 0x8800, 0x1c03, 0xf000, 0x6403, 0x5803, 0xcc00,
+ 0x4006, 0xd405, 0xe805, 0x7c06, 0x9005, 0x0406, 0x3806, 0xac05,
+ 0x6005, 0xf406, 0xc806, 0x5c05, 0xb006, 0x2405, 0x1805, 0x8c06,
+ 0x800c, 0x140f, 0x280f, 0xbc0c, 0x500f, 0xc40c, 0xf80c, 0x6c0f,
+ 0xa00f, 0x340c, 0x080c, 0x9c0f, 0x700c, 0xe40f, 0xd80f, 0x4c0c,
+ 0xc00a, 0x5409, 0x6809, 0xfc0a, 0x1009, 0x840a, 0xb80a, 0x2c09,
+ 0xe009, 0x740a, 0x480a, 0xdc09, 0x300a, 0xa409, 0x9809, 0x0c0a,
+ 0x801d, 0x141e, 0x281e, 0xbc1d, 0x501e, 0xc41d, 0xf81d, 0x6c1e,
+ 0xa01e, 0x341d, 0x081d, 0x9c1e, 0x701d, 0xe41e, 0xd81e, 0x4c1d,
+ 0xc01b, 0x5418, 0x6818, 0xfc1b, 0x1018, 0x841b, 0xb81b, 0x2c18,
+ 0xe018, 0x741b, 0x481b, 0xdc18, 0x301b, 0xa418, 0x9818, 0x0c1b,
+ 0x0011, 0x9412, 0xa812, 0x3c11, 0xd012, 0x4411, 0x7811, 0xec12,
+ 0x2012, 0xb411, 0x8811, 0x1c12, 0xf011, 0x6412, 0x5812, 0xcc11,
+ 0x4017, 0xd414, 0xe814, 0x7c17, 0x9014, 0x0417, 0x3817, 0xac14,
+ 0x6014, 0xf417, 0xc817, 0x5c14, 0xb017, 0x2414, 0x1814, 0x8c17,
+ 0x803f, 0x143c, 0x283c, 0xbc3f, 0x503c, 0xc43f, 0xf83f, 0x6c3c,
+ 0xa03c, 0x343f, 0x083f, 0x9c3c, 0x703f, 0xe43c, 0xd83c, 0x4c3f,
+ 0xc039, 0x543a, 0x683a, 0xfc39, 0x103a, 0x8439, 0xb839, 0x2c3a,
+ 0xe03a, 0x7439, 0x4839, 0xdc3a, 0x3039, 0xa43a, 0x983a, 0x0c39,
+ 0x0033, 0x9430, 0xa830, 0x3c33, 0xd030, 0x4433, 0x7833, 0xec30,
+ 0x2030, 0xb433, 0x8833, 0x1c30, 0xf033, 0x6430, 0x5830, 0xcc33,
+ 0x4035, 0xd436, 0xe836, 0x7c35, 0x9036, 0x0435, 0x3835, 0xac36,
+ 0x6036, 0xf435, 0xc835, 0x5c36, 0xb035, 0x2436, 0x1836, 0x8c35,
+ 0x0022, 0x9421, 0xa821, 0x3c22, 0xd021, 0x4422, 0x7822, 0xec21,
+ 0x2021, 0xb422, 0x8822, 0x1c21, 0xf022, 0x6421, 0x5821, 0xcc22,
+ 0x4024, 0xd427, 0xe827, 0x7c24, 0x9027, 0x0424, 0x3824, 0xac27,
+ 0x6027, 0xf424, 0xc824, 0x5c27, 0xb024, 0x2427, 0x1827, 0x8c24,
+ 0x802e, 0x142d, 0x282d, 0xbc2e, 0x502d, 0xc42e, 0xf82e, 0x6c2d,
+ 0xa02d, 0x342e, 0x082e, 0x9c2d, 0x702e, 0xe42d, 0xd82d, 0x4c2e,
+ 0xc028, 0x542b, 0x682b, 0xfc28, 0x102b, 0x8428, 0xb828, 0x2c2b,
+ 0xe02b, 0x7428, 0x4828, 0xdc2b, 0x3028, 0xa42b, 0x982b, 0x0c28 },
+
+ { 0x0000, 0x807b, 0x80f3, 0x0088, 0x81e3, 0x0198, 0x0110, 0x816b,
+ 0x83c3, 0x03b8, 0x0330, 0x834b, 0x0220, 0x825b, 0x82d3, 0x02a8,
+ 0x8783, 0x07f8, 0x0770, 0x870b, 0x0660, 0x861b, 0x8693, 0x06e8,
+ 0x0440, 0x843b, 0x84b3, 0x04c8, 0x85a3, 0x05d8, 0x0550, 0x852b,
+ 0x8f03, 0x0f78, 0x0ff0, 0x8f8b, 0x0ee0, 0x8e9b, 0x8e13, 0x0e68,
+ 0x0cc0, 0x8cbb, 0x8c33, 0x0c48, 0x8d23, 0x0d58, 0x0dd0, 0x8dab,
+ 0x0880, 0x88fb, 0x8873, 0x0808, 0x8963, 0x0918, 0x0990, 0x89eb,
+ 0x8b43, 0x0b38, 0x0bb0, 0x8bcb, 0x0aa0, 0x8adb, 0x8a53, 0x0a28,
+ 0x9e03, 0x1e78, 0x1ef0, 0x9e8b, 0x1fe0, 0x9f9b, 0x9f13, 0x1f68,
+ 0x1dc0, 0x9dbb, 0x9d33, 0x1d48, 0x9c23, 0x1c58, 0x1cd0, 0x9cab,
+ 0x1980, 0x99fb, 0x9973, 0x1908, 0x9863, 0x1818, 0x1890, 0x98eb,
+ 0x9a43, 0x1a38, 0x1ab0, 0x9acb, 0x1ba0, 0x9bdb, 0x9b53, 0x1b28,
+ 0x1100, 0x917b, 0x91f3, 0x1188, 0x90e3, 0x1098, 0x1010, 0x906b,
+ 0x92c3, 0x12b8, 0x1230, 0x924b, 0x1320, 0x935b, 0x93d3, 0x13a8,
+ 0x9683, 0x16f8, 0x1670, 0x960b, 0x1760, 0x971b, 0x9793, 0x17e8,
+ 0x1540, 0x953b, 0x95b3, 0x15c8, 0x94a3, 0x14d8, 0x1450, 0x942b,
+ 0xbc03, 0x3c78, 0x3cf0, 0xbc8b, 0x3de0, 0xbd9b, 0xbd13, 0x3d68,
+ 0x3fc0, 0xbfbb, 0xbf33, 0x3f48, 0xbe23, 0x3e58, 0x3ed0, 0xbeab,
+ 0x3b80, 0xbbfb, 0xbb73, 0x3b08, 0xba63, 0x3a18, 0x3a90, 0xbaeb,
+ 0xb843, 0x3838, 0x38b0, 0xb8cb, 0x39a0, 0xb9db, 0xb953, 0x3928,
+ 0x3300, 0xb37b, 0xb3f3, 0x3388, 0xb2e3, 0x3298, 0x3210, 0xb26b,
+ 0xb0c3, 0x30b8, 0x3030, 0xb04b, 0x3120, 0xb15b, 0xb1d3, 0x31a8,
+ 0xb483, 0x34f8, 0x3470, 0xb40b, 0x3560, 0xb51b, 0xb593, 0x35e8,
+ 0x3740, 0xb73b, 0xb7b3, 0x37c8, 0xb6a3, 0x36d8, 0x3650, 0xb62b,
+ 0x2200, 0xa27b, 0xa2f3, 0x2288, 0xa3e3, 0x2398, 0x2310, 0xa36b,
+ 0xa1c3, 0x21b8, 0x2130, 0xa14b, 0x2020, 0xa05b, 0xa0d3, 0x20a8,
+ 0xa583, 0x25f8, 0x2570, 0xa50b, 0x2460, 0xa41b, 0xa493, 0x24e8,
+ 0x2640, 0xa63b, 0xa6b3, 0x26c8, 0xa7a3, 0x27d8, 0x2750, 0xa72b,
+ 0xad03, 0x2d78, 0x2df0, 0xad8b, 0x2ce0, 0xac9b, 0xac13, 0x2c68,
+ 0x2ec0, 0xaebb, 0xae33, 0x2e48, 0xaf23, 0x2f58, 0x2fd0, 0xafab,
+ 0x2a80, 0xaafb, 0xaa73, 0x2a08, 0xab63, 0x2b18, 0x2b90, 0xabeb,
+ 0xa943, 0x2938, 0x29b0, 0xa9cb, 0x28a0, 0xa8db, 0xa853, 0x2828 },
+
+ { 0x0000, 0xf803, 0x7003, 0x8800, 0xe006, 0x1805, 0x9005, 0x6806,
+ 0x4009, 0xb80a, 0x300a, 0xc809, 0xa00f, 0x580c, 0xd00c, 0x280f,
+ 0x8012, 0x7811, 0xf011, 0x0812, 0x6014, 0x9817, 0x1017, 0xe814,
+ 0xc01b, 0x3818, 0xb018, 0x481b, 0x201d, 0xd81e, 0x501e, 0xa81d,
+ 0x8021, 0x7822, 0xf022, 0x0821, 0x6027, 0x9824, 0x1024, 0xe827,
+ 0xc028, 0x382b, 0xb02b, 0x4828, 0x202e, 0xd82d, 0x502d, 0xa82e,
+ 0x0033, 0xf830, 0x7030, 0x8833, 0xe035, 0x1836, 0x9036, 0x6835,
+ 0x403a, 0xb839, 0x3039, 0xc83a, 0xa03c, 0x583f, 0xd03f, 0x283c,
+ 0x8047, 0x7844, 0xf044, 0x0847, 0x6041, 0x9842, 0x1042, 0xe841,
+ 0xc04e, 0x384d, 0xb04d, 0x484e, 0x2048, 0xd84b, 0x504b, 0xa848,
+ 0x0055, 0xf856, 0x7056, 0x8855, 0xe053, 0x1850, 0x9050, 0x6853,
+ 0x405c, 0xb85f, 0x305f, 0xc85c, 0xa05a, 0x5859, 0xd059, 0x285a,
+ 0x0066, 0xf865, 0x7065, 0x8866, 0xe060, 0x1863, 0x9063, 0x6860,
+ 0x406f, 0xb86c, 0x306c, 0xc86f, 0xa069, 0x586a, 0xd06a, 0x2869,
+ 0x8074, 0x7877, 0xf077, 0x0874, 0x6072, 0x9871, 0x1071, 0xe872,
+ 0xc07d, 0x387e, 0xb07e, 0x487d, 0x207b, 0xd878, 0x5078, 0xa87b,
+ 0x808b, 0x7888, 0xf088, 0x088b, 0x608d, 0x988e, 0x108e, 0xe88d,
+ 0xc082, 0x3881, 0xb081, 0x4882, 0x2084, 0xd887, 0x5087, 0xa884,
+ 0x0099, 0xf89a, 0x709a, 0x8899, 0xe09f, 0x189c, 0x909c, 0x689f,
+ 0x4090, 0xb893, 0x3093, 0xc890, 0xa096, 0x5895, 0xd095, 0x2896,
+ 0x00aa, 0xf8a9, 0x70a9, 0x88aa, 0xe0ac, 0x18af, 0x90af, 0x68ac,
+ 0x40a3, 0xb8a0, 0x30a0, 0xc8a3, 0xa0a5, 0x58a6, 0xd0a6, 0x28a5,
+ 0x80b8, 0x78bb, 0xf0bb, 0x08b8, 0x60be, 0x98bd, 0x10bd, 0xe8be,
+ 0xc0b1, 0x38b2, 0xb0b2, 0x48b1, 0x20b7, 0xd8b4, 0x50b4, 0xa8b7,
+ 0x00cc, 0xf8cf, 0x70cf, 0x88cc, 0xe0ca, 0x18c9, 0x90c9, 0x68ca,
+ 0x40c5, 0xb8c6, 0x30c6, 0xc8c5, 0xa0c3, 0x58c0, 0xd0c0, 0x28c3,
+ 0x80de, 0x78dd, 0xf0dd, 0x08de, 0x60d8, 0x98db, 0x10db, 0xe8d8,
+ 0xc0d7, 0x38d4, 0xb0d4, 0x48d7, 0x20d1, 0xd8d2, 0x50d2, 0xa8d1,
+ 0x80ed, 0x78ee, 0xf0ee, 0x08ed, 0x60eb, 0x98e8, 0x10e8, 0xe8eb,
+ 0xc0e4, 0x38e7, 0xb0e7, 0x48e4, 0x20e2, 0xd8e1, 0x50e1, 0xa8e2,
+ 0x00ff, 0xf8fc, 0x70fc, 0x88ff, 0xe0f9, 0x18fa, 0x90fa, 0x68f9,
+ 0x40f6, 0xb8f5, 0x30f5, 0xc8f6, 0xa0f0, 0x58f3, 0xd0f3, 0x28f0 },
+
+ { 0x0000, 0x8113, 0x8223, 0x0330, 0x8443, 0x0550, 0x0660, 0x8773,
+ 0x8883, 0x0990, 0x0aa0, 0x8bb3, 0x0cc0, 0x8dd3, 0x8ee3, 0x0ff0,
+ 0x9103, 0x1010, 0x1320, 0x9233, 0x1540, 0x9453, 0x9763, 0x1670,
+ 0x1980, 0x9893, 0x9ba3, 0x1ab0, 0x9dc3, 0x1cd0, 0x1fe0, 0x9ef3,
+ 0xa203, 0x2310, 0x2020, 0xa133, 0x2640, 0xa753, 0xa463, 0x2570,
+ 0x2a80, 0xab93, 0xa8a3, 0x29b0, 0xaec3, 0x2fd0, 0x2ce0, 0xadf3,
+ 0x3300, 0xb213, 0xb123, 0x3030, 0xb743, 0x3650, 0x3560, 0xb473,
+ 0xbb83, 0x3a90, 0x39a0, 0xb8b3, 0x3fc0, 0xbed3, 0xbde3, 0x3cf0,
+ 0xc403, 0x4510, 0x4620, 0xc733, 0x4040, 0xc153, 0xc263, 0x4370,
+ 0x4c80, 0xcd93, 0xcea3, 0x4fb0, 0xc8c3, 0x49d0, 0x4ae0, 0xcbf3,
+ 0x5500, 0xd413, 0xd723, 0x5630, 0xd143, 0x5050, 0x5360, 0xd273,
+ 0xdd83, 0x5c90, 0x5fa0, 0xdeb3, 0x59c0, 0xd8d3, 0xdbe3, 0x5af0,
+ 0x6600, 0xe713, 0xe423, 0x6530, 0xe243, 0x6350, 0x6060, 0xe173,
+ 0xee83, 0x6f90, 0x6ca0, 0xedb3, 0x6ac0, 0xebd3, 0xe8e3, 0x69f0,
+ 0xf703, 0x7610, 0x7520, 0xf433, 0x7340, 0xf253, 0xf163, 0x7070,
+ 0x7f80, 0xfe93, 0xfda3, 0x7cb0, 0xfbc3, 0x7ad0, 0x79e0, 0xf8f3,
+ 0x0803, 0x8910, 0x8a20, 0x0b33, 0x8c40, 0x0d53, 0x0e63, 0x8f70,
+ 0x8080, 0x0193, 0x02a3, 0x83b0, 0x04c3, 0x85d0, 0x86e0, 0x07f3,
+ 0x9900, 0x1813, 0x1b23, 0x9a30, 0x1d43, 0x9c50, 0x9f60, 0x1e73,
+ 0x1183, 0x9090, 0x93a0, 0x12b3, 0x95c0, 0x14d3, 0x17e3, 0x96f0,
+ 0xaa00, 0x2b13, 0x2823, 0xa930, 0x2e43, 0xaf50, 0xac60, 0x2d73,
+ 0x2283, 0xa390, 0xa0a0, 0x21b3, 0xa6c0, 0x27d3, 0x24e3, 0xa5f0,
+ 0x3b03, 0xba10, 0xb920, 0x3833, 0xbf40, 0x3e53, 0x3d63, 0xbc70,
+ 0xb380, 0x3293, 0x31a3, 0xb0b0, 0x37c3, 0xb6d0, 0xb5e0, 0x34f3,
+ 0xcc00, 0x4d13, 0x4e23, 0xcf30, 0x4843, 0xc950, 0xca60, 0x4b73,
+ 0x4483, 0xc590, 0xc6a0, 0x47b3, 0xc0c0, 0x41d3, 0x42e3, 0xc3f0,
+ 0x5d03, 0xdc10, 0xdf20, 0x5e33, 0xd940, 0x5853, 0x5b63, 0xda70,
+ 0xd580, 0x5493, 0x57a3, 0xd6b0, 0x51c3, 0xd0d0, 0xd3e0, 0x52f3,
+ 0x6e03, 0xef10, 0xec20, 0x6d33, 0xea40, 0x6b53, 0x6863, 0xe970,
+ 0xe680, 0x6793, 0x64a3, 0xe5b0, 0x62c3, 0xe3d0, 0xe0e0, 0x61f3,
+ 0xff00, 0x7e13, 0x7d23, 0xfc30, 0x7b43, 0xfa50, 0xf960, 0x7873,
+ 0x7783, 0xf690, 0xf5a0, 0x74b3, 0xf3c0, 0x72d3, 0x71e3, 0xf0f0 },
+
+ { 0x0000, 0x1006, 0x200c, 0x300a, 0x4018, 0x501e, 0x6014, 0x7012,
+ 0x8030, 0x9036, 0xa03c, 0xb03a, 0xc028, 0xd02e, 0xe024, 0xf022,
+ 0x8065, 0x9063, 0xa069, 0xb06f, 0xc07d, 0xd07b, 0xe071, 0xf077,
+ 0x0055, 0x1053, 0x2059, 0x305f, 0x404d, 0x504b, 0x6041, 0x7047,
+ 0x80cf, 0x90c9, 0xa0c3, 0xb0c5, 0xc0d7, 0xd0d1, 0xe0db, 0xf0dd,
+ 0x00ff, 0x10f9, 0x20f3, 0x30f5, 0x40e7, 0x50e1, 0x60eb, 0x70ed,
+ 0x00aa, 0x10ac, 0x20a6, 0x30a0, 0x40b2, 0x50b4, 0x60be, 0x70b8,
+ 0x809a, 0x909c, 0xa096, 0xb090, 0xc082, 0xd084, 0xe08e, 0xf088,
+ 0x819b, 0x919d, 0xa197, 0xb191, 0xc183, 0xd185, 0xe18f, 0xf189,
+ 0x01ab, 0x11ad, 0x21a7, 0x31a1, 0x41b3, 0x51b5, 0x61bf, 0x71b9,
+ 0x01fe, 0x11f8, 0x21f2, 0x31f4, 0x41e6, 0x51e0, 0x61ea, 0x71ec,
+ 0x81ce, 0x91c8, 0xa1c2, 0xb1c4, 0xc1d6, 0xd1d0, 0xe1da, 0xf1dc,
+ 0x0154, 0x1152, 0x2158, 0x315e, 0x414c, 0x514a, 0x6140, 0x7146,
+ 0x8164, 0x9162, 0xa168, 0xb16e, 0xc17c, 0xd17a, 0xe170, 0xf176,
+ 0x8131, 0x9137, 0xa13d, 0xb13b, 0xc129, 0xd12f, 0xe125, 0xf123,
+ 0x0101, 0x1107, 0x210d, 0x310b, 0x4119, 0x511f, 0x6115, 0x7113,
+ 0x8333, 0x9335, 0xa33f, 0xb339, 0xc32b, 0xd32d, 0xe327, 0xf321,
+ 0x0303, 0x1305, 0x230f, 0x3309, 0x431b, 0x531d, 0x6317, 0x7311,
+ 0x0356, 0x1350, 0x235a, 0x335c, 0x434e, 0x5348, 0x6342, 0x7344,
+ 0x8366, 0x9360, 0xa36a, 0xb36c, 0xc37e, 0xd378, 0xe372, 0xf374,
+ 0x03fc, 0x13fa, 0x23f0, 0x33f6, 0x43e4, 0x53e2, 0x63e8, 0x73ee,
+ 0x83cc, 0x93ca, 0xa3c0, 0xb3c6, 0xc3d4, 0xd3d2, 0xe3d8, 0xf3de,
+ 0x8399, 0x939f, 0xa395, 0xb393, 0xc381, 0xd387, 0xe38d, 0xf38b,
+ 0x03a9, 0x13af, 0x23a5, 0x33a3, 0x43b1, 0x53b7, 0x63bd, 0x73bb,
+ 0x02a8, 0x12ae, 0x22a4, 0x32a2, 0x42b0, 0x52b6, 0x62bc, 0x72ba,
+ 0x8298, 0x929e, 0xa294, 0xb292, 0xc280, 0xd286, 0xe28c, 0xf28a,
+ 0x82cd, 0x92cb, 0xa2c1, 0xb2c7, 0xc2d5, 0xd2d3, 0xe2d9, 0xf2df,
+ 0x02fd, 0x12fb, 0x22f1, 0x32f7, 0x42e5, 0x52e3, 0x62e9, 0x72ef,
+ 0x8267, 0x9261, 0xa26b, 0xb26d, 0xc27f, 0xd279, 0xe273, 0xf275,
+ 0x0257, 0x1251, 0x225b, 0x325d, 0x424f, 0x5249, 0x6243, 0x7245,
+ 0x0202, 0x1204, 0x220e, 0x3208, 0x421a, 0x521c, 0x6216, 0x7210,
+ 0x8232, 0x9234, 0xa23e, 0xb238, 0xc22a, 0xd22c, 0xe226, 0xf220 }
+};
+
+FLAC__uint8 FLAC__crc8(const FLAC__byte *data, uint32_t len)
+{
+ FLAC__uint8 crc = 0;
+
+ while(len--)
+ crc = FLAC__crc8_table[crc ^ *data++];
+
+ return crc;
+}
+
+FLAC__uint16 FLAC__crc16(const FLAC__byte *data, uint32_t len)
+{
+ FLAC__uint16 crc = 0;
+
+ while(len >= 8){
+ crc ^= data[0] << 8 | data[1];
+
+ crc = FLAC__crc16_table[7][crc >> 8] ^ FLAC__crc16_table[6][crc & 0xFF] ^
+ FLAC__crc16_table[5][data[2] ] ^ FLAC__crc16_table[4][data[3] ] ^
+ FLAC__crc16_table[3][data[4] ] ^ FLAC__crc16_table[2][data[5] ] ^
+ FLAC__crc16_table[1][data[6] ] ^ FLAC__crc16_table[0][data[7] ];
+
+ data += 8;
+ len -= 8;
+ }
+
+ while(len--)
+ crc = (crc<<8) ^ FLAC__crc16_table[0][(crc>>8) ^ *data++];
+
+ return crc;
+}
+
+FLAC__uint16 FLAC__crc16_update_words32(const FLAC__uint32 *words, uint32_t len, FLAC__uint16 crc)
+{
+ while (len >= 2) {
+ crc ^= words[0] >> 16;
+
+ crc = FLAC__crc16_table[7][crc >> 8 ] ^ FLAC__crc16_table[6][crc & 0xFF ] ^
+ FLAC__crc16_table[5][(words[0] >> 8) & 0xFF] ^ FLAC__crc16_table[4][ words[0] & 0xFF] ^
+ FLAC__crc16_table[3][ words[1] >> 24 ] ^ FLAC__crc16_table[2][(words[1] >> 16) & 0xFF] ^
+ FLAC__crc16_table[1][(words[1] >> 8) & 0xFF] ^ FLAC__crc16_table[0][ words[1] & 0xFF];
+
+ words += 2;
+ len -= 2;
+ }
+
+ if (len) {
+ crc ^= words[0] >> 16;
+
+ crc = FLAC__crc16_table[3][crc >> 8 ] ^ FLAC__crc16_table[2][crc & 0xFF ] ^
+ FLAC__crc16_table[1][(words[0] >> 8) & 0xFF] ^ FLAC__crc16_table[0][words[0] & 0xFF];
+ }
+
+ return crc;
+}
+
+FLAC__uint16 FLAC__crc16_update_words64(const FLAC__uint64 *words, uint32_t len, FLAC__uint16 crc)
+{
+ while (len--) {
+ crc ^= words[0] >> 48;
+
+ crc = FLAC__crc16_table[7][crc >> 8 ] ^ FLAC__crc16_table[6][crc & 0xFF ] ^
+ FLAC__crc16_table[5][(words[0] >> 40) & 0xFF] ^ FLAC__crc16_table[4][(words[0] >> 32) & 0xFF] ^
+ FLAC__crc16_table[3][(words[0] >> 24) & 0xFF] ^ FLAC__crc16_table[2][(words[0] >> 16) & 0xFF] ^
+ FLAC__crc16_table[1][(words[0] >> 8) & 0xFF] ^ FLAC__crc16_table[0][ words[0] & 0xFF];
+
+ words++;
+ }
+
+ return crc;
+}
--- /dev/null
+++ b/src/libflac/fixed.c
@@ -1,0 +1,100 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000-2009 Josh Coalson
+ * Copyright (C) 2011-2016 Xiph.Org Foundation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <math.h>
+#include <string.h>
+#include "share/compat.h"
+#include "private/bitmath.h"
+#include "private/fixed.h"
+#include "private/macros.h"
+
+#ifdef local_abs
+#undef local_abs
+#endif
+#define local_abs(x) ((uint32_t)((x)<0? -(x) : (x)))
+
+void FLAC__fixed_compute_residual(const FLAC__int32 data[], uint32_t data_len, uint32_t order, FLAC__int32 residual[])
+{
+ const int idata_len = (int)data_len;
+ int i;
+
+ switch(order) {
+ case 0:
+ memcpy(residual, data, sizeof(residual[0])*data_len);
+ break;
+ case 1:
+ for(i = 0; i < idata_len; i++)
+ residual[i] = data[i] - data[i-1];
+ break;
+ case 2:
+ for(i = 0; i < idata_len; i++)
+ residual[i] = data[i] - 2*data[i-1] + data[i-2];
+ break;
+ case 3:
+ for(i = 0; i < idata_len; i++)
+ residual[i] = data[i] - 3*data[i-1] + 3*data[i-2] - data[i-3];
+ break;
+ case 4:
+ for(i = 0; i < idata_len; i++)
+ residual[i] = data[i] - 4*data[i-1] + 6*data[i-2] - 4*data[i-3] + data[i-4];
+ break;
+ default: break;
+ }
+}
+
+void FLAC__fixed_restore_signal(const FLAC__int32 residual[], uint32_t data_len, uint32_t order, FLAC__int32 data[])
+{
+ int i, idata_len = (int)data_len;
+
+ switch(order) {
+ case 0:
+ memcpy(data, residual, sizeof(residual[0])*data_len);
+ break;
+ case 1:
+ for(i = 0; i < idata_len; i++)
+ data[i] = residual[i] + data[i-1];
+ break;
+ case 2:
+ for(i = 0; i < idata_len; i++)
+ data[i] = residual[i] + 2*data[i-1] - data[i-2];
+ break;
+ case 3:
+ for(i = 0; i < idata_len; i++)
+ data[i] = residual[i] + 3*data[i-1] - 3*data[i-2] + data[i-3];
+ break;
+ case 4:
+ for(i = 0; i < idata_len; i++)
+ data[i] = residual[i] + 4*data[i-1] - 6*data[i-2] + 4*data[i-3] - data[i-4];
+ break;
+ default: break;
+ }
+}
--- /dev/null
+++ b/src/libflac/format.c
@@ -1,0 +1,566 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000-2009 Josh Coalson
+ * Copyright (C) 2011-2016 Xiph.Org Foundation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h> /* for qsort() */
+#include <string.h> /* for memset() */
+#include "FLAC/format.h"
+#include "share/alloc.h"
+#include "share/compat.h"
+#include "private/format.h"
+#include "private/macros.h"
+
+/* PACKAGE_VERSION should come from configure */
+FLAC_API const char *FLAC__VERSION_STRING = "1.3.3";
+
+FLAC_API const char *FLAC__VENDOR_STRING = "reference libFLAC " "1.3.3" " 20190804";
+
+FLAC_API const FLAC__byte FLAC__STREAM_SYNC_STRING[4] = { 'f','L','a','C' };
+FLAC_API const uint32_t FLAC__STREAM_SYNC = 0x664C6143;
+FLAC_API const uint32_t FLAC__STREAM_SYNC_LEN = 32; /* bits */
+
+FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN = 16; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN = 16; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN = 24; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN = 24; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN = 20; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN = 3; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN = 5; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN = 36; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_MD5SUM_LEN = 128; /* bits */
+
+FLAC_API const uint32_t FLAC__STREAM_METADATA_APPLICATION_ID_LEN = 32; /* bits */
+
+FLAC_API const uint32_t FLAC__STREAM_METADATA_SEEKPOINT_SAMPLE_NUMBER_LEN = 64; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_SEEKPOINT_STREAM_OFFSET_LEN = 64; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_SEEKPOINT_FRAME_SAMPLES_LEN = 16; /* bits */
+
+FLAC_API const FLAC__uint64 FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER = FLAC__U64L(0xffffffffffffffff);
+
+FLAC_API const uint32_t FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN = 32; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN = 32; /* bits */
+
+FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN = 64; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN = 8; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN = 3*8; /* bits */
+
+FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN = 64; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN = 8; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN = 12*8; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN = 1; /* bit */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN = 1; /* bit */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN = 6+13*8; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN = 8; /* bits */
+
+FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN = 128*8; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN = 64; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN = 1; /* bit */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN = 7+258*8; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN = 8; /* bits */
+
+FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_TYPE_LEN = 32; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN = 32; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN = 32; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN = 32; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN = 32; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN = 32; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_COLORS_LEN = 32; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN = 32; /* bits */
+
+FLAC_API const uint32_t FLAC__STREAM_METADATA_IS_LAST_LEN = 1; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_TYPE_LEN = 7; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_LENGTH_LEN = 24; /* bits */
+
+FLAC_API const uint32_t FLAC__FRAME_HEADER_SYNC = 0x3ffe;
+FLAC_API const uint32_t FLAC__FRAME_HEADER_SYNC_LEN = 14; /* bits */
+FLAC_API const uint32_t FLAC__FRAME_HEADER_RESERVED_LEN = 1; /* bits */
+FLAC_API const uint32_t FLAC__FRAME_HEADER_BLOCKING_STRATEGY_LEN = 1; /* bits */
+FLAC_API const uint32_t FLAC__FRAME_HEADER_BLOCK_SIZE_LEN = 4; /* bits */
+FLAC_API const uint32_t FLAC__FRAME_HEADER_SAMPLE_RATE_LEN = 4; /* bits */
+FLAC_API const uint32_t FLAC__FRAME_HEADER_CHANNEL_ASSIGNMENT_LEN = 4; /* bits */
+FLAC_API const uint32_t FLAC__FRAME_HEADER_BITS_PER_SAMPLE_LEN = 3; /* bits */
+FLAC_API const uint32_t FLAC__FRAME_HEADER_ZERO_PAD_LEN = 1; /* bits */
+FLAC_API const uint32_t FLAC__FRAME_HEADER_CRC_LEN = 8; /* bits */
+
+FLAC_API const uint32_t FLAC__FRAME_FOOTER_CRC_LEN = 16; /* bits */
+
+FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_TYPE_LEN = 2; /* bits */
+FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN = 4; /* bits */
+FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN = 4; /* bits */
+FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_PARAMETER_LEN = 5; /* bits */
+FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_RAW_LEN = 5; /* bits */
+
+FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER = 15; /* == (1<<FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN)-1 */
+FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_ESCAPE_PARAMETER = 31; /* == (1<<FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_PARAMETER_LEN)-1 */
+
+FLAC_API const char * const FLAC__EntropyCodingMethodTypeString[] = {
+ "PARTITIONED_RICE",
+ "PARTITIONED_RICE2"
+};
+
+FLAC_API const uint32_t FLAC__SUBFRAME_LPC_QLP_COEFF_PRECISION_LEN = 4; /* bits */
+FLAC_API const uint32_t FLAC__SUBFRAME_LPC_QLP_SHIFT_LEN = 5; /* bits */
+
+FLAC_API const uint32_t FLAC__SUBFRAME_ZERO_PAD_LEN = 1; /* bits */
+FLAC_API const uint32_t FLAC__SUBFRAME_TYPE_LEN = 6; /* bits */
+FLAC_API const uint32_t FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN = 1; /* bits */
+
+FLAC_API const uint32_t FLAC__SUBFRAME_TYPE_CONSTANT_BYTE_ALIGNED_MASK = 0x00;
+FLAC_API const uint32_t FLAC__SUBFRAME_TYPE_VERBATIM_BYTE_ALIGNED_MASK = 0x02;
+FLAC_API const uint32_t FLAC__SUBFRAME_TYPE_FIXED_BYTE_ALIGNED_MASK = 0x10;
+FLAC_API const uint32_t FLAC__SUBFRAME_TYPE_LPC_BYTE_ALIGNED_MASK = 0x40;
+
+FLAC_API const char * const FLAC__SubframeTypeString[] = {
+ "CONSTANT",
+ "VERBATIM",
+ "FIXED",
+ "LPC"
+};
+
+FLAC_API const char * const FLAC__ChannelAssignmentString[] = {
+ "INDEPENDENT",
+ "LEFT_SIDE",
+ "RIGHT_SIDE",
+ "MID_SIDE"
+};
+
+FLAC_API const char * const FLAC__FrameNumberTypeString[] = {
+ "FRAME_NUMBER_TYPE_FRAME_NUMBER",
+ "FRAME_NUMBER_TYPE_SAMPLE_NUMBER"
+};
+
+FLAC_API const char * const FLAC__MetadataTypeString[] = {
+ "STREAMINFO",
+ "PADDING",
+ "APPLICATION",
+ "SEEKTABLE",
+ "VORBIS_COMMENT",
+ "CUESHEET",
+ "PICTURE"
+};
+
+FLAC_API const char * const FLAC__StreamMetadata_Picture_TypeString[] = {
+ "Other",
+ "32x32 pixels 'file icon' (PNG only)",
+ "Other file icon",
+ "Cover (front)",
+ "Cover (back)",
+ "Leaflet page",
+ "Media (e.g. label side of CD)",
+ "Lead artist/lead performer/soloist",
+ "Artist/performer",
+ "Conductor",
+ "Band/Orchestra",
+ "Composer",
+ "Lyricist/text writer",
+ "Recording Location",
+ "During recording",
+ "During performance",
+ "Movie/video screen capture",
+ "A bright coloured fish",
+ "Illustration",
+ "Band/artist logotype",
+ "Publisher/Studio logotype"
+};
+
+FLAC_API FLAC__bool FLAC__format_sample_rate_is_valid(uint32_t sample_rate)
+{
+ if(sample_rate == 0 || sample_rate > FLAC__MAX_SAMPLE_RATE) {
+ return false;
+ }
+ else
+ return true;
+}
+
+FLAC_API FLAC__bool FLAC__format_blocksize_is_subset(uint32_t blocksize, uint32_t sample_rate)
+{
+ if(blocksize > 16384)
+ return false;
+ else if(sample_rate <= 48000 && blocksize > 4608)
+ return false;
+ else
+ return true;
+}
+
+FLAC_API FLAC__bool FLAC__format_sample_rate_is_subset(uint32_t sample_rate)
+{
+ if(
+ !FLAC__format_sample_rate_is_valid(sample_rate) ||
+ (
+ sample_rate >= (1u << 16) &&
+ !(sample_rate % 1000 == 0 || sample_rate % 10 == 0)
+ )
+ ) {
+ return false;
+ }
+ else
+ return true;
+}
+
+/* @@@@ add to unit tests; it is already indirectly tested by the metadata_object tests */
+FLAC_API FLAC__bool FLAC__format_seektable_is_legal(const FLAC__StreamMetadata_SeekTable *seek_table)
+{
+ uint32_t i;
+ FLAC__uint64 prev_sample_number = 0;
+ FLAC__bool got_prev = false;
+
+ for(i = 0; i < seek_table->num_points; i++) {
+ if(got_prev) {
+ if(
+ seek_table->points[i].sample_number != FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER &&
+ seek_table->points[i].sample_number <= prev_sample_number
+ )
+ return false;
+ }
+ prev_sample_number = seek_table->points[i].sample_number;
+ got_prev = true;
+ }
+
+ return true;
+}
+
+/* used as the sort predicate for qsort() */
+static int seekpoint_compare_(const FLAC__StreamMetadata_SeekPoint *l, const FLAC__StreamMetadata_SeekPoint *r)
+{
+ /* we don't just 'return l->sample_number - r->sample_number' since the result (FLAC__int64) might overflow an 'int' */
+ if(l->sample_number == r->sample_number)
+ return 0;
+ else if(l->sample_number < r->sample_number)
+ return -1;
+ else
+ return 1;
+}
+
+/* @@@@ add to unit tests; it is already indirectly tested by the metadata_object tests */
+FLAC_API uint32_t FLAC__format_seektable_sort(FLAC__StreamMetadata_SeekTable *seek_table)
+{
+ uint32_t i, j;
+ FLAC__bool first;
+
+ if (seek_table->num_points == 0)
+ return 0;
+
+ /* sort the seekpoints */
+ qsort(seek_table->points, seek_table->num_points, sizeof(FLAC__StreamMetadata_SeekPoint), (int (*)(const void *, const void *))seekpoint_compare_);
+
+ /* uniquify the seekpoints */
+ first = true;
+ for(i = j = 0; i < seek_table->num_points; i++) {
+ if(seek_table->points[i].sample_number != FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER) {
+ if(!first) {
+ if(seek_table->points[i].sample_number == seek_table->points[j-1].sample_number)
+ continue;
+ }
+ }
+ first = false;
+ seek_table->points[j++] = seek_table->points[i];
+ }
+
+ for(i = j; i < seek_table->num_points; i++) {
+ seek_table->points[i].sample_number = FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER;
+ seek_table->points[i].stream_offset = 0;
+ seek_table->points[i].frame_samples = 0;
+ }
+
+ return j;
+}
+
+/*
+ * also disallows non-shortest-form encodings, c.f.
+ * http://www.unicode.org/versions/corrigendum1.html
+ * and a more clear explanation at the end of this section:
+ * http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+ */
+static uint32_t utf8len_(const FLAC__byte *utf8)
+{
+ if ((utf8[0] & 0x80) == 0) {
+ return 1;
+ }
+ else if ((utf8[0] & 0xE0) == 0xC0 && (utf8[1] & 0xC0) == 0x80) {
+ if ((utf8[0] & 0xFE) == 0xC0) /* overlong sequence check */
+ return 0;
+ return 2;
+ }
+ else if ((utf8[0] & 0xF0) == 0xE0 && (utf8[1] & 0xC0) == 0x80 && (utf8[2] & 0xC0) == 0x80) {
+ if (utf8[0] == 0xE0 && (utf8[1] & 0xE0) == 0x80) /* overlong sequence check */
+ return 0;
+ /* illegal surrogates check (U+D800...U+DFFF and U+FFFE...U+FFFF) */
+ if (utf8[0] == 0xED && (utf8[1] & 0xE0) == 0xA0) /* D800-DFFF */
+ return 0;
+ if (utf8[0] == 0xEF && utf8[1] == 0xBF && (utf8[2] & 0xFE) == 0xBE) /* FFFE-FFFF */
+ return 0;
+ return 3;
+ }
+ else if ((utf8[0] & 0xF8) == 0xF0 && (utf8[1] & 0xC0) == 0x80 && (utf8[2] & 0xC0) == 0x80 && (utf8[3] & 0xC0) == 0x80) {
+ if (utf8[0] == 0xF0 && (utf8[1] & 0xF0) == 0x80) /* overlong sequence check */
+ return 0;
+ return 4;
+ }
+ else if ((utf8[0] & 0xFC) == 0xF8 && (utf8[1] & 0xC0) == 0x80 && (utf8[2] & 0xC0) == 0x80 && (utf8[3] & 0xC0) == 0x80 && (utf8[4] & 0xC0) == 0x80) {
+ if (utf8[0] == 0xF8 && (utf8[1] & 0xF8) == 0x80) /* overlong sequence check */
+ return 0;
+ return 5;
+ }
+ else if ((utf8[0] & 0xFE) == 0xFC && (utf8[1] & 0xC0) == 0x80 && (utf8[2] & 0xC0) == 0x80 && (utf8[3] & 0xC0) == 0x80 && (utf8[4] & 0xC0) == 0x80 && (utf8[5] & 0xC0) == 0x80) {
+ if (utf8[0] == 0xFC && (utf8[1] & 0xFC) == 0x80) /* overlong sequence check */
+ return 0;
+ return 6;
+ }
+ else {
+ return 0;
+ }
+}
+
+FLAC_API FLAC__bool FLAC__format_vorbiscomment_entry_name_is_legal(const char *name)
+{
+ char c;
+ for(c = *name; c; c = *(++name))
+ if(c < 0x20 || c == 0x3d || c > 0x7d)
+ return false;
+ return true;
+}
+
+FLAC_API FLAC__bool FLAC__format_vorbiscomment_entry_value_is_legal(const FLAC__byte *value, uint32_t length)
+{
+ if(length == (uint32_t)(-1)) {
+ while(*value) {
+ uint32_t n = utf8len_(value);
+ if(n == 0)
+ return false;
+ value += n;
+ }
+ }
+ else {
+ const FLAC__byte *end = value + length;
+ while(value < end) {
+ uint32_t n = utf8len_(value);
+ if(n == 0)
+ return false;
+ value += n;
+ }
+ if(value != end)
+ return false;
+ }
+ return true;
+}
+
+FLAC_API FLAC__bool FLAC__format_vorbiscomment_entry_is_legal(const FLAC__byte *entry, uint32_t length)
+{
+ const FLAC__byte *s, *end;
+
+ for(s = entry, end = s + length; s < end && *s != '='; s++) {
+ if(*s < 0x20 || *s > 0x7D)
+ return false;
+ }
+ if(s == end)
+ return false;
+
+ s++; /* skip '=' */
+
+ while(s < end) {
+ uint32_t n = utf8len_(s);
+ if(n == 0)
+ return false;
+ s += n;
+ }
+ if(s != end)
+ return false;
+
+ return true;
+}
+
+/* @@@@ add to unit tests; it is already indirectly tested by the metadata_object tests */
+FLAC_API FLAC__bool FLAC__format_cuesheet_is_legal(const FLAC__StreamMetadata_CueSheet *cue_sheet, FLAC__bool check_cd_da_subset, const char **violation)
+{
+ uint32_t i, j;
+
+ if(check_cd_da_subset) {
+ if(cue_sheet->lead_in < 2 * 44100) {
+ if(violation) *violation = "CD-DA cue sheet must have a lead-in length of at least 2 seconds";
+ return false;
+ }
+ if(cue_sheet->lead_in % 588 != 0) {
+ if(violation) *violation = "CD-DA cue sheet lead-in length must be evenly divisible by 588 samples";
+ return false;
+ }
+ }
+
+ if(cue_sheet->num_tracks == 0) {
+ if(violation) *violation = "cue sheet must have at least one track (the lead-out)";
+ return false;
+ }
+
+ if(check_cd_da_subset && cue_sheet->tracks[cue_sheet->num_tracks-1].number != 170) {
+ if(violation) *violation = "CD-DA cue sheet must have a lead-out track number 170 (0xAA)";
+ return false;
+ }
+
+ for(i = 0; i < cue_sheet->num_tracks; i++) {
+ if(cue_sheet->tracks[i].number == 0) {
+ if(violation) *violation = "cue sheet may not have a track number 0";
+ return false;
+ }
+
+ if(check_cd_da_subset) {
+ if(!((cue_sheet->tracks[i].number >= 1 && cue_sheet->tracks[i].number <= 99) || cue_sheet->tracks[i].number == 170)) {
+ if(violation) *violation = "CD-DA cue sheet track number must be 1-99 or 170";
+ return false;
+ }
+ }
+
+ if(check_cd_da_subset && cue_sheet->tracks[i].offset % 588 != 0) {
+ if(violation) {
+ if(i == cue_sheet->num_tracks-1) /* the lead-out track... */
+ *violation = "CD-DA cue sheet lead-out offset must be evenly divisible by 588 samples";
+ else
+ *violation = "CD-DA cue sheet track offset must be evenly divisible by 588 samples";
+ }
+ return false;
+ }
+
+ if(i < cue_sheet->num_tracks - 1) {
+ if(cue_sheet->tracks[i].num_indices == 0) {
+ if(violation) *violation = "cue sheet track must have at least one index point";
+ return false;
+ }
+
+ if(cue_sheet->tracks[i].indices[0].number > 1) {
+ if(violation) *violation = "cue sheet track's first index number must be 0 or 1";
+ return false;
+ }
+ }
+
+ for(j = 0; j < cue_sheet->tracks[i].num_indices; j++) {
+ if(check_cd_da_subset && cue_sheet->tracks[i].indices[j].offset % 588 != 0) {
+ if(violation) *violation = "CD-DA cue sheet track index offset must be evenly divisible by 588 samples";
+ return false;
+ }
+
+ if(j > 0) {
+ if(cue_sheet->tracks[i].indices[j].number != cue_sheet->tracks[i].indices[j-1].number + 1) {
+ if(violation) *violation = "cue sheet track index numbers must increase by 1";
+ return false;
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+/* @@@@ add to unit tests; it is already indirectly tested by the metadata_object tests */
+FLAC_API FLAC__bool FLAC__format_picture_is_legal(const FLAC__StreamMetadata_Picture *picture, const char **violation)
+{
+ char *p;
+ FLAC__byte *b;
+
+ for(p = picture->mime_type; *p; p++) {
+ if(*p < 0x20 || *p > 0x7e) {
+ if(violation) *violation = "MIME type string must contain only printable ASCII characters (0x20-0x7e)";
+ return false;
+ }
+ }
+
+ for(b = picture->description; *b; ) {
+ uint32_t n = utf8len_(b);
+ if(n == 0) {
+ if(violation) *violation = "description string must be valid UTF-8";
+ return false;
+ }
+ b += n;
+ }
+
+ return true;
+}
+
+/*
+ * These routines are private to libFLAC
+ */
+uint32_t FLAC__format_get_max_rice_partition_order(uint32_t blocksize, uint32_t predictor_order)
+{
+ return
+ FLAC__format_get_max_rice_partition_order_from_blocksize_limited_max_and_predictor_order(
+ FLAC__format_get_max_rice_partition_order_from_blocksize(blocksize),
+ blocksize,
+ predictor_order
+ );
+}
+
+uint32_t FLAC__format_get_max_rice_partition_order_from_blocksize(uint32_t blocksize)
+{
+ uint32_t max_rice_partition_order = 0;
+ while(!(blocksize & 1)) {
+ max_rice_partition_order++;
+ blocksize >>= 1;
+ }
+ return flac_min(FLAC__MAX_RICE_PARTITION_ORDER, max_rice_partition_order);
+}
+
+uint32_t FLAC__format_get_max_rice_partition_order_from_blocksize_limited_max_and_predictor_order(uint32_t limit, uint32_t blocksize, uint32_t predictor_order)
+{
+ uint32_t max_rice_partition_order = limit;
+
+ while(max_rice_partition_order > 0 && (blocksize >> max_rice_partition_order) <= predictor_order)
+ max_rice_partition_order--;
+
+ return max_rice_partition_order;
+}
+
+void FLAC__format_entropy_coding_method_partitioned_rice_contents_init(FLAC__EntropyCodingMethod_PartitionedRiceContents *object)
+{
+ object->parameters = 0;
+ object->raw_bits = 0;
+ object->capacity_by_order = 0;
+}
+
+void FLAC__format_entropy_coding_method_partitioned_rice_contents_clear(FLAC__EntropyCodingMethod_PartitionedRiceContents *object)
+{
+ if(0 != object->parameters)
+ free(object->parameters);
+ if(0 != object->raw_bits)
+ free(object->raw_bits);
+ FLAC__format_entropy_coding_method_partitioned_rice_contents_init(object);
+}
+
+FLAC__bool FLAC__format_entropy_coding_method_partitioned_rice_contents_ensure_size(FLAC__EntropyCodingMethod_PartitionedRiceContents *object, uint32_t max_partition_order)
+{
+ if(object->capacity_by_order < max_partition_order) {
+ if(0 == (object->parameters = safe_realloc_(object->parameters, sizeof(uint32_t)*(1ULL << max_partition_order))))
+ return false;
+ if(0 == (object->raw_bits = safe_realloc_(object->raw_bits, sizeof(uint32_t)*(1ULL << max_partition_order))))
+ return false;
+ memset(object->raw_bits, 0, sizeof(uint32_t)*(1ULL << max_partition_order));
+ object->capacity_by_order = max_partition_order;
+ }
+
+ return true;
+}
--- /dev/null
+++ b/src/libflac/lpc.c
@@ -1,0 +1,1233 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000-2009 Josh Coalson
+ * Copyright (C) 2011-2016 Xiph.Org Foundation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <math.h>
+#include "FLAC/format.h"
+#include "share/compat.h"
+#include "private/bitmath.h"
+#include "private/lpc.h"
+#include "private/macros.h"
+
+/* OPT: #undef'ing this may improve the speed on some architectures */
+#define FLAC__LPC_UNROLLED_FILTER_LOOPS
+
+#if defined(_MSC_VER) && (_MSC_VER < 1800)
+#include <float.h>
+static inline long int lround(double x) {
+ return (long)(x + _copysign(0.5, x));
+}
+#endif
+
+void FLAC__lpc_window_data(const FLAC__int32 in[], const FLAC__real window[], FLAC__real out[], uint32_t data_len)
+{
+ uint32_t i;
+ for(i = 0; i < data_len; i++)
+ out[i] = in[i] * window[i];
+}
+
+void FLAC__lpc_compute_autocorrelation(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[])
+{
+ /*
+ * this version tends to run faster because of better data locality
+ * ('data_len' is usually much larger than 'lag')
+ */
+ FLAC__real d;
+ uint32_t sample, coeff;
+ const uint32_t limit = data_len - lag;
+
+ for(coeff = 0; coeff < lag; coeff++)
+ autoc[coeff] = 0.0;
+ for(sample = 0; sample <= limit; sample++) {
+ d = data[sample];
+ for(coeff = 0; coeff < lag; coeff++)
+ autoc[coeff] += d * data[sample+coeff];
+ }
+ for(; sample < data_len; sample++) {
+ d = data[sample];
+ for(coeff = 0; coeff < data_len - sample; coeff++)
+ autoc[coeff] += d * data[sample+coeff];
+ }
+}
+
+void FLAC__lpc_compute_lp_coefficients(const FLAC__real autoc[], uint32_t *max_order, FLAC__real lp_coeff[][FLAC__MAX_LPC_ORDER], double error[])
+{
+ uint32_t i, j;
+ double r, err, lpc[FLAC__MAX_LPC_ORDER];
+
+ err = autoc[0];
+
+ for(i = 0; i < *max_order; i++) {
+ /* Sum up this iteration's reflection coefficient. */
+ r = -autoc[i+1];
+ for(j = 0; j < i; j++)
+ r -= lpc[j] * autoc[i-j];
+ r /= err;
+
+ /* Update LPC coefficients and total error. */
+ lpc[i]=r;
+ for(j = 0; j < (i>>1); j++) {
+ double tmp = lpc[j];
+ lpc[j] += r * lpc[i-1-j];
+ lpc[i-1-j] += r * tmp;
+ }
+ if(i & 1)
+ lpc[j] += lpc[j] * r;
+
+ err *= (1.0 - r * r);
+
+ /* save this order */
+ for(j = 0; j <= i; j++)
+ lp_coeff[i][j] = (FLAC__real)(-lpc[j]); /* negate FIR filter coeff to get predictor coeff */
+ error[i] = err;
+
+ /* see SF bug https://sourceforge.net/p/flac/bugs/234/ */
+ if(err == 0.0) {
+ *max_order = i+1;
+ return;
+ }
+ }
+}
+
+int FLAC__lpc_quantize_coefficients(const FLAC__real lp_coeff[], uint32_t order, uint32_t precision, FLAC__int32 qlp_coeff[], int *shift)
+{
+ uint32_t i;
+ double cmax;
+ FLAC__int32 qmax, qmin;
+
+ /* drop one bit for the sign; from here on out we consider only |lp_coeff[i]| */
+ precision--;
+ qmax = 1 << precision;
+ qmin = -qmax;
+ qmax--;
+
+ /* calc cmax = max( |lp_coeff[i]| ) */
+ cmax = 0.0;
+ for(i = 0; i < order; i++) {
+ const double d = fabs(lp_coeff[i]);
+ if(d > cmax)
+ cmax = d;
+ }
+
+ if(cmax <= 0.0) {
+ /* => coefficients are all 0, which means our constant-detect didn't work */
+ return 2;
+ }
+ else {
+ const int max_shiftlimit = (1 << (FLAC__SUBFRAME_LPC_QLP_SHIFT_LEN-1)) - 1;
+ const int min_shiftlimit = -max_shiftlimit - 1;
+ int log2cmax;
+
+ (void)frexp(cmax, &log2cmax);
+ log2cmax--;
+ *shift = (int)precision - log2cmax - 1;
+
+ if(*shift > max_shiftlimit)
+ *shift = max_shiftlimit;
+ else if(*shift < min_shiftlimit)
+ return 1;
+ }
+
+ if(*shift >= 0) {
+ double error = 0.0;
+ FLAC__int32 q;
+ for(i = 0; i < order; i++) {
+ error += lp_coeff[i] * (1 << *shift);
+ q = lround(error);
+
+ if(q > qmax)
+ q = qmax;
+ else if(q < qmin)
+ q = qmin;
+ error -= q;
+ qlp_coeff[i] = q;
+ }
+ }
+ /* negative shift is very rare but due to design flaw, negative shift is
+ * not allowed in the decoder, so it must be handled specially by scaling
+ * down coeffs
+ */
+ else {
+ const int nshift = -(*shift);
+ double error = 0.0;
+ FLAC__int32 q;
+
+ for(i = 0; i < order; i++) {
+ error += lp_coeff[i] / (1 << nshift);
+ q = lround(error);
+ if(q > qmax)
+ q = qmax;
+ else if(q < qmin)
+ q = qmin;
+ error -= q;
+ qlp_coeff[i] = q;
+ }
+ *shift = 0;
+ }
+
+ return 0;
+}
+
+#if defined(_MSC_VER)
+// silence MSVC warnings about __restrict modifier
+#pragma warning ( disable : 4028 )
+#endif
+
+void FLAC__lpc_compute_residual_from_qlp_coefficients(const FLAC__int32 * flac_restrict data, uint32_t data_len, const FLAC__int32 * flac_restrict qlp_coeff, uint32_t order, int lp_quantization, FLAC__int32 * flac_restrict residual)
+#if !defined(FLAC__LPC_UNROLLED_FILTER_LOOPS)
+{
+ FLAC__int64 sumo;
+ uint32_t i, j;
+ FLAC__int32 sum;
+ const FLAC__int32 *history;
+
+ FLAC__ASSERT(order > 0);
+
+ for(i = 0; i < data_len; i++) {
+ sumo = 0;
+ sum = 0;
+ history = data;
+ for(j = 0; j < order; j++) {
+ sum += qlp_coeff[j] * (*(--history));
+ sumo += (FLAC__int64)qlp_coeff[j] * (FLAC__int64)(*history);
+ if(sumo > 2147483647ll || sumo < -2147483648ll)
+ fprintf(stderr,"FLAC__lpc_compute_residual_from_qlp_coefficients: OVERFLOW, i=%u, j=%u, c=%d, d=%d, sumo=%" PRId64 "\n",i,j,qlp_coeff[j],*history,sumo);
+ }
+ *(residual++) = *(data++) - (sum >> lp_quantization);
+ }
+}
+#else /* fully unrolled version for normal use */
+{
+ int i;
+ FLAC__int32 sum;
+
+ /*
+ * We do unique versions up to 12th order since that's the subset limit.
+ * Also they are roughly ordered to match frequency of occurrence to
+ * minimize branching.
+ */
+ if(order <= 12) {
+ if(order > 8) {
+ if(order > 10) {
+ if(order == 12) {
+ for(i = 0; i < (int)data_len; i++) {
+ sum = 0;
+ sum += qlp_coeff[11] * data[i-12];
+ sum += qlp_coeff[10] * data[i-11];
+ sum += qlp_coeff[9] * data[i-10];
+ sum += qlp_coeff[8] * data[i-9];
+ sum += qlp_coeff[7] * data[i-8];
+ sum += qlp_coeff[6] * data[i-7];
+ sum += qlp_coeff[5] * data[i-6];
+ sum += qlp_coeff[4] * data[i-5];
+ sum += qlp_coeff[3] * data[i-4];
+ sum += qlp_coeff[2] * data[i-3];
+ sum += qlp_coeff[1] * data[i-2];
+ sum += qlp_coeff[0] * data[i-1];
+ residual[i] = data[i] - (sum >> lp_quantization);
+ }
+ }
+ else { /* order == 11 */
+ for(i = 0; i < (int)data_len; i++) {
+ sum = 0;
+ sum += qlp_coeff[10] * data[i-11];
+ sum += qlp_coeff[9] * data[i-10];
+ sum += qlp_coeff[8] * data[i-9];
+ sum += qlp_coeff[7] * data[i-8];
+ sum += qlp_coeff[6] * data[i-7];
+ sum += qlp_coeff[5] * data[i-6];
+ sum += qlp_coeff[4] * data[i-5];
+ sum += qlp_coeff[3] * data[i-4];
+ sum += qlp_coeff[2] * data[i-3];
+ sum += qlp_coeff[1] * data[i-2];
+ sum += qlp_coeff[0] * data[i-1];
+ residual[i] = data[i] - (sum >> lp_quantization);
+ }
+ }
+ }
+ else {
+ if(order == 10) {
+ for(i = 0; i < (int)data_len; i++) {
+ sum = 0;
+ sum += qlp_coeff[9] * data[i-10];
+ sum += qlp_coeff[8] * data[i-9];
+ sum += qlp_coeff[7] * data[i-8];
+ sum += qlp_coeff[6] * data[i-7];
+ sum += qlp_coeff[5] * data[i-6];
+ sum += qlp_coeff[4] * data[i-5];
+ sum += qlp_coeff[3] * data[i-4];
+ sum += qlp_coeff[2] * data[i-3];
+ sum += qlp_coeff[1] * data[i-2];
+ sum += qlp_coeff[0] * data[i-1];
+ residual[i] = data[i] - (sum >> lp_quantization);
+ }
+ }
+ else { /* order == 9 */
+ for(i = 0; i < (int)data_len; i++) {
+ sum = 0;
+ sum += qlp_coeff[8] * data[i-9];
+ sum += qlp_coeff[7] * data[i-8];
+ sum += qlp_coeff[6] * data[i-7];
+ sum += qlp_coeff[5] * data[i-6];
+ sum += qlp_coeff[4] * data[i-5];
+ sum += qlp_coeff[3] * data[i-4];
+ sum += qlp_coeff[2] * data[i-3];
+ sum += qlp_coeff[1] * data[i-2];
+ sum += qlp_coeff[0] * data[i-1];
+ residual[i] = data[i] - (sum >> lp_quantization);
+ }
+ }
+ }
+ }
+ else if(order > 4) {
+ if(order > 6) {
+ if(order == 8) {
+ for(i = 0; i < (int)data_len; i++) {
+ sum = 0;
+ sum += qlp_coeff[7] * data[i-8];
+ sum += qlp_coeff[6] * data[i-7];
+ sum += qlp_coeff[5] * data[i-6];
+ sum += qlp_coeff[4] * data[i-5];
+ sum += qlp_coeff[3] * data[i-4];
+ sum += qlp_coeff[2] * data[i-3];
+ sum += qlp_coeff[1] * data[i-2];
+ sum += qlp_coeff[0] * data[i-1];
+ residual[i] = data[i] - (sum >> lp_quantization);
+ }
+ }
+ else { /* order == 7 */
+ for(i = 0; i < (int)data_len; i++) {
+ sum = 0;
+ sum += qlp_coeff[6] * data[i-7];
+ sum += qlp_coeff[5] * data[i-6];
+ sum += qlp_coeff[4] * data[i-5];
+ sum += qlp_coeff[3] * data[i-4];
+ sum += qlp_coeff[2] * data[i-3];
+ sum += qlp_coeff[1] * data[i-2];
+ sum += qlp_coeff[0] * data[i-1];
+ residual[i] = data[i] - (sum >> lp_quantization);
+ }
+ }
+ }
+ else {
+ if(order == 6) {
+ for(i = 0; i < (int)data_len; i++) {
+ sum = 0;
+ sum += qlp_coeff[5] * data[i-6];
+ sum += qlp_coeff[4] * data[i-5];
+ sum += qlp_coeff[3] * data[i-4];
+ sum += qlp_coeff[2] * data[i-3];
+ sum += qlp_coeff[1] * data[i-2];
+ sum += qlp_coeff[0] * data[i-1];
+ residual[i] = data[i] - (sum >> lp_quantization);
+ }
+ }
+ else { /* order == 5 */
+ for(i = 0; i < (int)data_len; i++) {
+ sum = 0;
+ sum += qlp_coeff[4] * data[i-5];
+ sum += qlp_coeff[3] * data[i-4];
+ sum += qlp_coeff[2] * data[i-3];
+ sum += qlp_coeff[1] * data[i-2];
+ sum += qlp_coeff[0] * data[i-1];
+ residual[i] = data[i] - (sum >> lp_quantization);
+ }
+ }
+ }
+ }
+ else {
+ if(order > 2) {
+ if(order == 4) {
+ for(i = 0; i < (int)data_len; i++) {
+ sum = 0;
+ sum += qlp_coeff[3] * data[i-4];
+ sum += qlp_coeff[2] * data[i-3];
+ sum += qlp_coeff[1] * data[i-2];
+ sum += qlp_coeff[0] * data[i-1];
+ residual[i] = data[i] - (sum >> lp_quantization);
+ }
+ }
+ else { /* order == 3 */
+ for(i = 0; i < (int)data_len; i++) {
+ sum = 0;
+ sum += qlp_coeff[2] * data[i-3];
+ sum += qlp_coeff[1] * data[i-2];
+ sum += qlp_coeff[0] * data[i-1];
+ residual[i] = data[i] - (sum >> lp_quantization);
+ }
+ }
+ }
+ else {
+ if(order == 2) {
+ for(i = 0; i < (int)data_len; i++) {
+ sum = 0;
+ sum += qlp_coeff[1] * data[i-2];
+ sum += qlp_coeff[0] * data[i-1];
+ residual[i] = data[i] - (sum >> lp_quantization);
+ }
+ }
+ else { /* order == 1 */
+ for(i = 0; i < (int)data_len; i++)
+ residual[i] = data[i] - ((qlp_coeff[0] * data[i-1]) >> lp_quantization);
+ }
+ }
+ }
+ }
+ else { /* order > 12 */
+ for(i = 0; i < (int)data_len; i++) {
+ sum = 0;
+ switch(order) {
+ default:
+ case 32: sum += qlp_coeff[31] * data[i-32]; /* Falls through. */
+ case 31: sum += qlp_coeff[30] * data[i-31]; /* Falls through. */
+ case 30: sum += qlp_coeff[29] * data[i-30]; /* Falls through. */
+ case 29: sum += qlp_coeff[28] * data[i-29]; /* Falls through. */
+ case 28: sum += qlp_coeff[27] * data[i-28]; /* Falls through. */
+ case 27: sum += qlp_coeff[26] * data[i-27]; /* Falls through. */
+ case 26: sum += qlp_coeff[25] * data[i-26]; /* Falls through. */
+ case 25: sum += qlp_coeff[24] * data[i-25]; /* Falls through. */
+ case 24: sum += qlp_coeff[23] * data[i-24]; /* Falls through. */
+ case 23: sum += qlp_coeff[22] * data[i-23]; /* Falls through. */
+ case 22: sum += qlp_coeff[21] * data[i-22]; /* Falls through. */
+ case 21: sum += qlp_coeff[20] * data[i-21]; /* Falls through. */
+ case 20: sum += qlp_coeff[19] * data[i-20]; /* Falls through. */
+ case 19: sum += qlp_coeff[18] * data[i-19]; /* Falls through. */
+ case 18: sum += qlp_coeff[17] * data[i-18]; /* Falls through. */
+ case 17: sum += qlp_coeff[16] * data[i-17]; /* Falls through. */
+ case 16: sum += qlp_coeff[15] * data[i-16]; /* Falls through. */
+ case 15: sum += qlp_coeff[14] * data[i-15]; /* Falls through. */
+ case 14: sum += qlp_coeff[13] * data[i-14]; /* Falls through. */
+ case 13: sum += qlp_coeff[12] * data[i-13];
+ sum += qlp_coeff[11] * data[i-12];
+ sum += qlp_coeff[10] * data[i-11];
+ sum += qlp_coeff[ 9] * data[i-10];
+ sum += qlp_coeff[ 8] * data[i- 9];
+ sum += qlp_coeff[ 7] * data[i- 8];
+ sum += qlp_coeff[ 6] * data[i- 7];
+ sum += qlp_coeff[ 5] * data[i- 6];
+ sum += qlp_coeff[ 4] * data[i- 5];
+ sum += qlp_coeff[ 3] * data[i- 4];
+ sum += qlp_coeff[ 2] * data[i- 3];
+ sum += qlp_coeff[ 1] * data[i- 2];
+ sum += qlp_coeff[ 0] * data[i- 1];
+ }
+ residual[i] = data[i] - (sum >> lp_quantization);
+ }
+ }
+}
+#endif
+
+void FLAC__lpc_compute_residual_from_qlp_coefficients_wide(const FLAC__int32 * flac_restrict data, uint32_t data_len, const FLAC__int32 * flac_restrict qlp_coeff, uint32_t order, int lp_quantization, FLAC__int32 * flac_restrict residual)
+#if !defined(FLAC__LPC_UNROLLED_FILTER_LOOPS)
+{
+ uint32_t i, j;
+ FLAC__int64 sum;
+ const FLAC__int32 *history;
+
+ FLAC__ASSERT(order > 0);
+
+ for(i = 0; i < data_len; i++) {
+ sum = 0;
+ history = data;
+ for(j = 0; j < order; j++)
+ sum += (FLAC__int64)qlp_coeff[j] * (FLAC__int64)(*(--history));
+ if(FLAC__bitmath_silog2(sum >> lp_quantization) > 32) {
+ fprintf(stderr,"FLAC__lpc_compute_residual_from_qlp_coefficients_wide: OVERFLOW, i=%u, sum=%" PRId64 "\n", i, (sum >> lp_quantization));
+ break;
+ }
+ if(FLAC__bitmath_silog2((FLAC__int64)(*data) - (sum >> lp_quantization)) > 32) {
+ fprintf(stderr,"FLAC__lpc_compute_residual_from_qlp_coefficients_wide: OVERFLOW, i=%u, data=%d, sum=%" PRId64 ", residual=%" PRId64 "\n", i, *data, (int64_t)(sum >> lp_quantization), ((FLAC__int64)(*data) - (sum >> lp_quantization)));
+ break;
+ }
+ *(residual++) = *(data++) - (FLAC__int32)(sum >> lp_quantization);
+ }
+}
+#else /* fully unrolled version for normal use */
+{
+ int i;
+ FLAC__int64 sum;
+
+ /*
+ * We do unique versions up to 12th order since that's the subset limit.
+ * Also they are roughly ordered to match frequency of occurrence to
+ * minimize branching.
+ */
+ if(order <= 12) {
+ if(order > 8) {
+ if(order > 10) {
+ if(order == 12) {
+ for(i = 0; i < (int)data_len; i++) {
+ sum = 0;
+ sum += qlp_coeff[11] * (FLAC__int64)data[i-12];
+ sum += qlp_coeff[10] * (FLAC__int64)data[i-11];
+ sum += qlp_coeff[9] * (FLAC__int64)data[i-10];
+ sum += qlp_coeff[8] * (FLAC__int64)data[i-9];
+ sum += qlp_coeff[7] * (FLAC__int64)data[i-8];
+ sum += qlp_coeff[6] * (FLAC__int64)data[i-7];
+ sum += qlp_coeff[5] * (FLAC__int64)data[i-6];
+ sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
+ sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+ sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+ sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+ sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+ residual[i] = data[i] - (FLAC__int32)(sum >> lp_quantization);
+ }
+ }
+ else { /* order == 11 */
+ for(i = 0; i < (int)data_len; i++) {
+ sum = 0;
+ sum += qlp_coeff[10] * (FLAC__int64)data[i-11];
+ sum += qlp_coeff[9] * (FLAC__int64)data[i-10];
+ sum += qlp_coeff[8] * (FLAC__int64)data[i-9];
+ sum += qlp_coeff[7] * (FLAC__int64)data[i-8];
+ sum += qlp_coeff[6] * (FLAC__int64)data[i-7];
+ sum += qlp_coeff[5] * (FLAC__int64)data[i-6];
+ sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
+ sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+ sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+ sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+ sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+ residual[i] = data[i] - (FLAC__int32)(sum >> lp_quantization);
+ }
+ }
+ }
+ else {
+ if(order == 10) {
+ for(i = 0; i < (int)data_len; i++) {
+ sum = 0;
+ sum += qlp_coeff[9] * (FLAC__int64)data[i-10];
+ sum += qlp_coeff[8] * (FLAC__int64)data[i-9];
+ sum += qlp_coeff[7] * (FLAC__int64)data[i-8];
+ sum += qlp_coeff[6] * (FLAC__int64)data[i-7];
+ sum += qlp_coeff[5] * (FLAC__int64)data[i-6];
+ sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
+ sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+ sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+ sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+ sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+ residual[i] = data[i] - (FLAC__int32)(sum >> lp_quantization);
+ }
+ }
+ else { /* order == 9 */
+ for(i = 0; i < (int)data_len; i++) {
+ sum = 0;
+ sum += qlp_coeff[8] * (FLAC__int64)data[i-9];
+ sum += qlp_coeff[7] * (FLAC__int64)data[i-8];
+ sum += qlp_coeff[6] * (FLAC__int64)data[i-7];
+ sum += qlp_coeff[5] * (FLAC__int64)data[i-6];
+ sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
+ sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+ sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+ sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+ sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+ residual[i] = data[i] - (FLAC__int32)(sum >> lp_quantization);
+ }
+ }
+ }
+ }
+ else if(order > 4) {
+ if(order > 6) {
+ if(order == 8) {
+ for(i = 0; i < (int)data_len; i++) {
+ sum = 0;
+ sum += qlp_coeff[7] * (FLAC__int64)data[i-8];
+ sum += qlp_coeff[6] * (FLAC__int64)data[i-7];
+ sum += qlp_coeff[5] * (FLAC__int64)data[i-6];
+ sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
+ sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+ sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+ sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+ sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+ residual[i] = data[i] - (FLAC__int32)(sum >> lp_quantization);
+ }
+ }
+ else { /* order == 7 */
+ for(i = 0; i < (int)data_len; i++) {
+ sum = 0;
+ sum += qlp_coeff[6] * (FLAC__int64)data[i-7];
+ sum += qlp_coeff[5] * (FLAC__int64)data[i-6];
+ sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
+ sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+ sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+ sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+ sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+ residual[i] = data[i] - (FLAC__int32)(sum >> lp_quantization);
+ }
+ }
+ }
+ else {
+ if(order == 6) {
+ for(i = 0; i < (int)data_len; i++) {
+ sum = 0;
+ sum += qlp_coeff[5] * (FLAC__int64)data[i-6];
+ sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
+ sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+ sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+ sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+ sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+ residual[i] = data[i] - (FLAC__int32)(sum >> lp_quantization);
+ }
+ }
+ else { /* order == 5 */
+ for(i = 0; i < (int)data_len; i++) {
+ sum = 0;
+ sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
+ sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+ sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+ sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+ sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+ residual[i] = data[i] - (FLAC__int32)(sum >> lp_quantization);
+ }
+ }
+ }
+ }
+ else {
+ if(order > 2) {
+ if(order == 4) {
+ for(i = 0; i < (int)data_len; i++) {
+ sum = 0;
+ sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+ sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+ sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+ sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+ residual[i] = data[i] - (FLAC__int32)(sum >> lp_quantization);
+ }
+ }
+ else { /* order == 3 */
+ for(i = 0; i < (int)data_len; i++) {
+ sum = 0;
+ sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+ sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+ sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+ residual[i] = data[i] - (FLAC__int32)(sum >> lp_quantization);
+ }
+ }
+ }
+ else {
+ if(order == 2) {
+ for(i = 0; i < (int)data_len; i++) {
+ sum = 0;
+ sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+ sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+ residual[i] = data[i] - (FLAC__int32)(sum >> lp_quantization);
+ }
+ }
+ else { /* order == 1 */
+ for(i = 0; i < (int)data_len; i++)
+ residual[i] = data[i] - (FLAC__int32)((qlp_coeff[0] * (FLAC__int64)data[i-1]) >> lp_quantization);
+ }
+ }
+ }
+ }
+ else { /* order > 12 */
+ for(i = 0; i < (int)data_len; i++) {
+ sum = 0;
+ switch(order) {
+ default:
+ case 32: sum += qlp_coeff[31] * (FLAC__int64)data[i-32]; /* Falls through. */
+ case 31: sum += qlp_coeff[30] * (FLAC__int64)data[i-31]; /* Falls through. */
+ case 30: sum += qlp_coeff[29] * (FLAC__int64)data[i-30]; /* Falls through. */
+ case 29: sum += qlp_coeff[28] * (FLAC__int64)data[i-29]; /* Falls through. */
+ case 28: sum += qlp_coeff[27] * (FLAC__int64)data[i-28]; /* Falls through. */
+ case 27: sum += qlp_coeff[26] * (FLAC__int64)data[i-27]; /* Falls through. */
+ case 26: sum += qlp_coeff[25] * (FLAC__int64)data[i-26]; /* Falls through. */
+ case 25: sum += qlp_coeff[24] * (FLAC__int64)data[i-25]; /* Falls through. */
+ case 24: sum += qlp_coeff[23] * (FLAC__int64)data[i-24]; /* Falls through. */
+ case 23: sum += qlp_coeff[22] * (FLAC__int64)data[i-23]; /* Falls through. */
+ case 22: sum += qlp_coeff[21] * (FLAC__int64)data[i-22]; /* Falls through. */
+ case 21: sum += qlp_coeff[20] * (FLAC__int64)data[i-21]; /* Falls through. */
+ case 20: sum += qlp_coeff[19] * (FLAC__int64)data[i-20]; /* Falls through. */
+ case 19: sum += qlp_coeff[18] * (FLAC__int64)data[i-19]; /* Falls through. */
+ case 18: sum += qlp_coeff[17] * (FLAC__int64)data[i-18]; /* Falls through. */
+ case 17: sum += qlp_coeff[16] * (FLAC__int64)data[i-17]; /* Falls through. */
+ case 16: sum += qlp_coeff[15] * (FLAC__int64)data[i-16]; /* Falls through. */
+ case 15: sum += qlp_coeff[14] * (FLAC__int64)data[i-15]; /* Falls through. */
+ case 14: sum += qlp_coeff[13] * (FLAC__int64)data[i-14]; /* Falls through. */
+ case 13: sum += qlp_coeff[12] * (FLAC__int64)data[i-13];
+ sum += qlp_coeff[11] * (FLAC__int64)data[i-12];
+ sum += qlp_coeff[10] * (FLAC__int64)data[i-11];
+ sum += qlp_coeff[ 9] * (FLAC__int64)data[i-10];
+ sum += qlp_coeff[ 8] * (FLAC__int64)data[i- 9];
+ sum += qlp_coeff[ 7] * (FLAC__int64)data[i- 8];
+ sum += qlp_coeff[ 6] * (FLAC__int64)data[i- 7];
+ sum += qlp_coeff[ 5] * (FLAC__int64)data[i- 6];
+ sum += qlp_coeff[ 4] * (FLAC__int64)data[i- 5];
+ sum += qlp_coeff[ 3] * (FLAC__int64)data[i- 4];
+ sum += qlp_coeff[ 2] * (FLAC__int64)data[i- 3];
+ sum += qlp_coeff[ 1] * (FLAC__int64)data[i- 2];
+ sum += qlp_coeff[ 0] * (FLAC__int64)data[i- 1];
+ }
+ residual[i] = data[i] - (FLAC__int32)(sum >> lp_quantization);
+ }
+ }
+}
+#endif
+
+void FLAC__lpc_restore_signal(const FLAC__int32 * flac_restrict residual, uint32_t data_len, const FLAC__int32 * flac_restrict qlp_coeff, uint32_t order, int lp_quantization, FLAC__int32 * flac_restrict data)
+#if !defined(FLAC__LPC_UNROLLED_FILTER_LOOPS)
+{
+ FLAC__int64 sumo;
+ uint32_t i, j;
+ FLAC__int32 sum;
+ const FLAC__int32 *r = residual, *history;
+
+ FLAC__ASSERT(order > 0);
+
+ for(i = 0; i < data_len; i++) {
+ sumo = 0;
+ sum = 0;
+ history = data;
+ for(j = 0; j < order; j++) {
+ sum += qlp_coeff[j] * (*(--history));
+ sumo += (FLAC__int64)qlp_coeff[j] * (FLAC__int64)(*history);
+ if(sumo > 2147483647ll || sumo < -2147483648ll)
+ fprintf(stderr,"FLAC__lpc_restore_signal: OVERFLOW, i=%u, j=%u, c=%d, d=%d, sumo=%" PRId64 "\n",i,j,qlp_coeff[j],*history,sumo);
+ }
+ *(data++) = *(r++) + (sum >> lp_quantization);
+ }
+}
+#else /* fully unrolled version for normal use */
+{
+ int i;
+ FLAC__int32 sum;
+
+ /*
+ * We do unique versions up to 12th order since that's the subset limit.
+ * Also they are roughly ordered to match frequency of occurrence to
+ * minimize branching.
+ */
+ if(order <= 12) {
+ if(order > 8) {
+ if(order > 10) {
+ if(order == 12) {
+ for(i = 0; i < (int)data_len; i++) {
+ sum = 0;
+ sum += qlp_coeff[11] * data[i-12];
+ sum += qlp_coeff[10] * data[i-11];
+ sum += qlp_coeff[9] * data[i-10];
+ sum += qlp_coeff[8] * data[i-9];
+ sum += qlp_coeff[7] * data[i-8];
+ sum += qlp_coeff[6] * data[i-7];
+ sum += qlp_coeff[5] * data[i-6];
+ sum += qlp_coeff[4] * data[i-5];
+ sum += qlp_coeff[3] * data[i-4];
+ sum += qlp_coeff[2] * data[i-3];
+ sum += qlp_coeff[1] * data[i-2];
+ sum += qlp_coeff[0] * data[i-1];
+ data[i] = residual[i] + (sum >> lp_quantization);
+ }
+ }
+ else { /* order == 11 */
+ for(i = 0; i < (int)data_len; i++) {
+ sum = 0;
+ sum += qlp_coeff[10] * data[i-11];
+ sum += qlp_coeff[9] * data[i-10];
+ sum += qlp_coeff[8] * data[i-9];
+ sum += qlp_coeff[7] * data[i-8];
+ sum += qlp_coeff[6] * data[i-7];
+ sum += qlp_coeff[5] * data[i-6];
+ sum += qlp_coeff[4] * data[i-5];
+ sum += qlp_coeff[3] * data[i-4];
+ sum += qlp_coeff[2] * data[i-3];
+ sum += qlp_coeff[1] * data[i-2];
+ sum += qlp_coeff[0] * data[i-1];
+ data[i] = residual[i] + (sum >> lp_quantization);
+ }
+ }
+ }
+ else {
+ if(order == 10) {
+ for(i = 0; i < (int)data_len; i++) {
+ sum = 0;
+ sum += qlp_coeff[9] * data[i-10];
+ sum += qlp_coeff[8] * data[i-9];
+ sum += qlp_coeff[7] * data[i-8];
+ sum += qlp_coeff[6] * data[i-7];
+ sum += qlp_coeff[5] * data[i-6];
+ sum += qlp_coeff[4] * data[i-5];
+ sum += qlp_coeff[3] * data[i-4];
+ sum += qlp_coeff[2] * data[i-3];
+ sum += qlp_coeff[1] * data[i-2];
+ sum += qlp_coeff[0] * data[i-1];
+ data[i] = residual[i] + (sum >> lp_quantization);
+ }
+ }
+ else { /* order == 9 */
+ for(i = 0; i < (int)data_len; i++) {
+ sum = 0;
+ sum += qlp_coeff[8] * data[i-9];
+ sum += qlp_coeff[7] * data[i-8];
+ sum += qlp_coeff[6] * data[i-7];
+ sum += qlp_coeff[5] * data[i-6];
+ sum += qlp_coeff[4] * data[i-5];
+ sum += qlp_coeff[3] * data[i-4];
+ sum += qlp_coeff[2] * data[i-3];
+ sum += qlp_coeff[1] * data[i-2];
+ sum += qlp_coeff[0] * data[i-1];
+ data[i] = residual[i] + (sum >> lp_quantization);
+ }
+ }
+ }
+ }
+ else if(order > 4) {
+ if(order > 6) {
+ if(order == 8) {
+ for(i = 0; i < (int)data_len; i++) {
+ sum = 0;
+ sum += qlp_coeff[7] * data[i-8];
+ sum += qlp_coeff[6] * data[i-7];
+ sum += qlp_coeff[5] * data[i-6];
+ sum += qlp_coeff[4] * data[i-5];
+ sum += qlp_coeff[3] * data[i-4];
+ sum += qlp_coeff[2] * data[i-3];
+ sum += qlp_coeff[1] * data[i-2];
+ sum += qlp_coeff[0] * data[i-1];
+ data[i] = residual[i] + (sum >> lp_quantization);
+ }
+ }
+ else { /* order == 7 */
+ for(i = 0; i < (int)data_len; i++) {
+ sum = 0;
+ sum += qlp_coeff[6] * data[i-7];
+ sum += qlp_coeff[5] * data[i-6];
+ sum += qlp_coeff[4] * data[i-5];
+ sum += qlp_coeff[3] * data[i-4];
+ sum += qlp_coeff[2] * data[i-3];
+ sum += qlp_coeff[1] * data[i-2];
+ sum += qlp_coeff[0] * data[i-1];
+ data[i] = residual[i] + (sum >> lp_quantization);
+ }
+ }
+ }
+ else {
+ if(order == 6) {
+ for(i = 0; i < (int)data_len; i++) {
+ sum = 0;
+ sum += qlp_coeff[5] * data[i-6];
+ sum += qlp_coeff[4] * data[i-5];
+ sum += qlp_coeff[3] * data[i-4];
+ sum += qlp_coeff[2] * data[i-3];
+ sum += qlp_coeff[1] * data[i-2];
+ sum += qlp_coeff[0] * data[i-1];
+ data[i] = residual[i] + (sum >> lp_quantization);
+ }
+ }
+ else { /* order == 5 */
+ for(i = 0; i < (int)data_len; i++) {
+ sum = 0;
+ sum += qlp_coeff[4] * data[i-5];
+ sum += qlp_coeff[3] * data[i-4];
+ sum += qlp_coeff[2] * data[i-3];
+ sum += qlp_coeff[1] * data[i-2];
+ sum += qlp_coeff[0] * data[i-1];
+ data[i] = residual[i] + (sum >> lp_quantization);
+ }
+ }
+ }
+ }
+ else {
+ if(order > 2) {
+ if(order == 4) {
+ for(i = 0; i < (int)data_len; i++) {
+ sum = 0;
+ sum += qlp_coeff[3] * data[i-4];
+ sum += qlp_coeff[2] * data[i-3];
+ sum += qlp_coeff[1] * data[i-2];
+ sum += qlp_coeff[0] * data[i-1];
+ data[i] = residual[i] + (sum >> lp_quantization);
+ }
+ }
+ else { /* order == 3 */
+ for(i = 0; i < (int)data_len; i++) {
+ sum = 0;
+ sum += qlp_coeff[2] * data[i-3];
+ sum += qlp_coeff[1] * data[i-2];
+ sum += qlp_coeff[0] * data[i-1];
+ data[i] = residual[i] + (sum >> lp_quantization);
+ }
+ }
+ }
+ else {
+ if(order == 2) {
+ for(i = 0; i < (int)data_len; i++) {
+ sum = 0;
+ sum += qlp_coeff[1] * data[i-2];
+ sum += qlp_coeff[0] * data[i-1];
+ data[i] = residual[i] + (sum >> lp_quantization);
+ }
+ }
+ else { /* order == 1 */
+ for(i = 0; i < (int)data_len; i++)
+ data[i] = residual[i] + ((qlp_coeff[0] * data[i-1]) >> lp_quantization);
+ }
+ }
+ }
+ }
+ else { /* order > 12 */
+ for(i = 0; i < (int)data_len; i++) {
+ sum = 0;
+ switch(order) {
+ default:
+ case 32: sum += qlp_coeff[31] * data[i-32]; /* Falls through. */
+ case 31: sum += qlp_coeff[30] * data[i-31]; /* Falls through. */
+ case 30: sum += qlp_coeff[29] * data[i-30]; /* Falls through. */
+ case 29: sum += qlp_coeff[28] * data[i-29]; /* Falls through. */
+ case 28: sum += qlp_coeff[27] * data[i-28]; /* Falls through. */
+ case 27: sum += qlp_coeff[26] * data[i-27]; /* Falls through. */
+ case 26: sum += qlp_coeff[25] * data[i-26]; /* Falls through. */
+ case 25: sum += qlp_coeff[24] * data[i-25]; /* Falls through. */
+ case 24: sum += qlp_coeff[23] * data[i-24]; /* Falls through. */
+ case 23: sum += qlp_coeff[22] * data[i-23]; /* Falls through. */
+ case 22: sum += qlp_coeff[21] * data[i-22]; /* Falls through. */
+ case 21: sum += qlp_coeff[20] * data[i-21]; /* Falls through. */
+ case 20: sum += qlp_coeff[19] * data[i-20]; /* Falls through. */
+ case 19: sum += qlp_coeff[18] * data[i-19]; /* Falls through. */
+ case 18: sum += qlp_coeff[17] * data[i-18]; /* Falls through. */
+ case 17: sum += qlp_coeff[16] * data[i-17]; /* Falls through. */
+ case 16: sum += qlp_coeff[15] * data[i-16]; /* Falls through. */
+ case 15: sum += qlp_coeff[14] * data[i-15]; /* Falls through. */
+ case 14: sum += qlp_coeff[13] * data[i-14]; /* Falls through. */
+ case 13: sum += qlp_coeff[12] * data[i-13];
+ sum += qlp_coeff[11] * data[i-12];
+ sum += qlp_coeff[10] * data[i-11];
+ sum += qlp_coeff[ 9] * data[i-10];
+ sum += qlp_coeff[ 8] * data[i- 9];
+ sum += qlp_coeff[ 7] * data[i- 8];
+ sum += qlp_coeff[ 6] * data[i- 7];
+ sum += qlp_coeff[ 5] * data[i- 6];
+ sum += qlp_coeff[ 4] * data[i- 5];
+ sum += qlp_coeff[ 3] * data[i- 4];
+ sum += qlp_coeff[ 2] * data[i- 3];
+ sum += qlp_coeff[ 1] * data[i- 2];
+ sum += qlp_coeff[ 0] * data[i- 1];
+ }
+ data[i] = residual[i] + (sum >> lp_quantization);
+ }
+ }
+}
+#endif
+
+void FLAC__lpc_restore_signal_wide(const FLAC__int32 * flac_restrict residual, uint32_t data_len, const FLAC__int32 * flac_restrict qlp_coeff, uint32_t order, int lp_quantization, FLAC__int32 * flac_restrict data)
+#if !defined(FLAC__LPC_UNROLLED_FILTER_LOOPS)
+{
+ uint32_t i, j;
+ FLAC__int64 sum;
+ const FLAC__int32 *r = residual, *history;
+
+ FLAC__ASSERT(order > 0);
+
+ for(i = 0; i < data_len; i++) {
+ sum = 0;
+ history = data;
+ for(j = 0; j < order; j++)
+ sum += (FLAC__int64)qlp_coeff[j] * (FLAC__int64)(*(--history));
+ if(FLAC__bitmath_silog2(sum >> lp_quantization) > 32) {
+ fprintf(stderr,"FLAC__lpc_restore_signal_wide: OVERFLOW, i=%u, sum=%" PRId64 "\n", i, (sum >> lp_quantization));
+ break;
+ }
+ if(FLAC__bitmath_silog2((FLAC__int64)(*r) + (sum >> lp_quantization)) > 32) {
+ fprintf(stderr,"FLAC__lpc_restore_signal_wide: OVERFLOW, i=%u, residual=%d, sum=%" PRId64 ", data=%" PRId64 "\n", i, *r, (sum >> lp_quantization), ((FLAC__int64)(*r) + (sum >> lp_quantization)));
+ break;
+ }
+ *(data++) = *(r++) + (FLAC__int32)(sum >> lp_quantization);
+ }
+}
+#else /* fully unrolled version for normal use */
+{
+ int i;
+ FLAC__int64 sum;
+
+ /*
+ * We do unique versions up to 12th order since that's the subset limit.
+ * Also they are roughly ordered to match frequency of occurrence to
+ * minimize branching.
+ */
+ if(order <= 12) {
+ if(order > 8) {
+ if(order > 10) {
+ if(order == 12) {
+ for(i = 0; i < (int)data_len; i++) {
+ sum = 0;
+ sum += qlp_coeff[11] * (FLAC__int64)data[i-12];
+ sum += qlp_coeff[10] * (FLAC__int64)data[i-11];
+ sum += qlp_coeff[9] * (FLAC__int64)data[i-10];
+ sum += qlp_coeff[8] * (FLAC__int64)data[i-9];
+ sum += qlp_coeff[7] * (FLAC__int64)data[i-8];
+ sum += qlp_coeff[6] * (FLAC__int64)data[i-7];
+ sum += qlp_coeff[5] * (FLAC__int64)data[i-6];
+ sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
+ sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+ sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+ sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+ sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+ data[i] = residual[i] + (FLAC__int32)(sum >> lp_quantization);
+ }
+ }
+ else { /* order == 11 */
+ for(i = 0; i < (int)data_len; i++) {
+ sum = 0;
+ sum += qlp_coeff[10] * (FLAC__int64)data[i-11];
+ sum += qlp_coeff[9] * (FLAC__int64)data[i-10];
+ sum += qlp_coeff[8] * (FLAC__int64)data[i-9];
+ sum += qlp_coeff[7] * (FLAC__int64)data[i-8];
+ sum += qlp_coeff[6] * (FLAC__int64)data[i-7];
+ sum += qlp_coeff[5] * (FLAC__int64)data[i-6];
+ sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
+ sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+ sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+ sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+ sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+ data[i] = residual[i] + (FLAC__int32)(sum >> lp_quantization);
+ }
+ }
+ }
+ else {
+ if(order == 10) {
+ for(i = 0; i < (int)data_len; i++) {
+ sum = 0;
+ sum += qlp_coeff[9] * (FLAC__int64)data[i-10];
+ sum += qlp_coeff[8] * (FLAC__int64)data[i-9];
+ sum += qlp_coeff[7] * (FLAC__int64)data[i-8];
+ sum += qlp_coeff[6] * (FLAC__int64)data[i-7];
+ sum += qlp_coeff[5] * (FLAC__int64)data[i-6];
+ sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
+ sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+ sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+ sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+ sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+ data[i] = residual[i] + (FLAC__int32)(sum >> lp_quantization);
+ }
+ }
+ else { /* order == 9 */
+ for(i = 0; i < (int)data_len; i++) {
+ sum = 0;
+ sum += qlp_coeff[8] * (FLAC__int64)data[i-9];
+ sum += qlp_coeff[7] * (FLAC__int64)data[i-8];
+ sum += qlp_coeff[6] * (FLAC__int64)data[i-7];
+ sum += qlp_coeff[5] * (FLAC__int64)data[i-6];
+ sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
+ sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+ sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+ sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+ sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+ data[i] = residual[i] + (FLAC__int32)(sum >> lp_quantization);
+ }
+ }
+ }
+ }
+ else if(order > 4) {
+ if(order > 6) {
+ if(order == 8) {
+ for(i = 0; i < (int)data_len; i++) {
+ sum = 0;
+ sum += qlp_coeff[7] * (FLAC__int64)data[i-8];
+ sum += qlp_coeff[6] * (FLAC__int64)data[i-7];
+ sum += qlp_coeff[5] * (FLAC__int64)data[i-6];
+ sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
+ sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+ sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+ sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+ sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+ data[i] = residual[i] + (FLAC__int32)(sum >> lp_quantization);
+ }
+ }
+ else { /* order == 7 */
+ for(i = 0; i < (int)data_len; i++) {
+ sum = 0;
+ sum += qlp_coeff[6] * (FLAC__int64)data[i-7];
+ sum += qlp_coeff[5] * (FLAC__int64)data[i-6];
+ sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
+ sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+ sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+ sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+ sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+ data[i] = residual[i] + (FLAC__int32)(sum >> lp_quantization);
+ }
+ }
+ }
+ else {
+ if(order == 6) {
+ for(i = 0; i < (int)data_len; i++) {
+ sum = 0;
+ sum += qlp_coeff[5] * (FLAC__int64)data[i-6];
+ sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
+ sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+ sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+ sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+ sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+ data[i] = residual[i] + (FLAC__int32)(sum >> lp_quantization);
+ }
+ }
+ else { /* order == 5 */
+ for(i = 0; i < (int)data_len; i++) {
+ sum = 0;
+ sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
+ sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+ sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+ sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+ sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+ data[i] = residual[i] + (FLAC__int32)(sum >> lp_quantization);
+ }
+ }
+ }
+ }
+ else {
+ if(order > 2) {
+ if(order == 4) {
+ for(i = 0; i < (int)data_len; i++) {
+ sum = 0;
+ sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+ sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+ sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+ sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+ data[i] = residual[i] + (FLAC__int32)(sum >> lp_quantization);
+ }
+ }
+ else { /* order == 3 */
+ for(i = 0; i < (int)data_len; i++) {
+ sum = 0;
+ sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+ sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+ sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+ data[i] = residual[i] + (FLAC__int32)(sum >> lp_quantization);
+ }
+ }
+ }
+ else {
+ if(order == 2) {
+ for(i = 0; i < (int)data_len; i++) {
+ sum = 0;
+ sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+ sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+ data[i] = residual[i] + (FLAC__int32)(sum >> lp_quantization);
+ }
+ }
+ else { /* order == 1 */
+ for(i = 0; i < (int)data_len; i++)
+ data[i] = residual[i] + (FLAC__int32)((qlp_coeff[0] * (FLAC__int64)data[i-1]) >> lp_quantization);
+ }
+ }
+ }
+ }
+ else { /* order > 12 */
+ for(i = 0; i < (int)data_len; i++) {
+ sum = 0;
+ switch(order) {
+ default:
+ case 32: sum += qlp_coeff[31] * (FLAC__int64)data[i-32]; /* Falls through. */
+ case 31: sum += qlp_coeff[30] * (FLAC__int64)data[i-31]; /* Falls through. */
+ case 30: sum += qlp_coeff[29] * (FLAC__int64)data[i-30]; /* Falls through. */
+ case 29: sum += qlp_coeff[28] * (FLAC__int64)data[i-29]; /* Falls through. */
+ case 28: sum += qlp_coeff[27] * (FLAC__int64)data[i-28]; /* Falls through. */
+ case 27: sum += qlp_coeff[26] * (FLAC__int64)data[i-27]; /* Falls through. */
+ case 26: sum += qlp_coeff[25] * (FLAC__int64)data[i-26]; /* Falls through. */
+ case 25: sum += qlp_coeff[24] * (FLAC__int64)data[i-25]; /* Falls through. */
+ case 24: sum += qlp_coeff[23] * (FLAC__int64)data[i-24]; /* Falls through. */
+ case 23: sum += qlp_coeff[22] * (FLAC__int64)data[i-23]; /* Falls through. */
+ case 22: sum += qlp_coeff[21] * (FLAC__int64)data[i-22]; /* Falls through. */
+ case 21: sum += qlp_coeff[20] * (FLAC__int64)data[i-21]; /* Falls through. */
+ case 20: sum += qlp_coeff[19] * (FLAC__int64)data[i-20]; /* Falls through. */
+ case 19: sum += qlp_coeff[18] * (FLAC__int64)data[i-19]; /* Falls through. */
+ case 18: sum += qlp_coeff[17] * (FLAC__int64)data[i-18]; /* Falls through. */
+ case 17: sum += qlp_coeff[16] * (FLAC__int64)data[i-17]; /* Falls through. */
+ case 16: sum += qlp_coeff[15] * (FLAC__int64)data[i-16]; /* Falls through. */
+ case 15: sum += qlp_coeff[14] * (FLAC__int64)data[i-15]; /* Falls through. */
+ case 14: sum += qlp_coeff[13] * (FLAC__int64)data[i-14]; /* Falls through. */
+ case 13: sum += qlp_coeff[12] * (FLAC__int64)data[i-13];
+ sum += qlp_coeff[11] * (FLAC__int64)data[i-12];
+ sum += qlp_coeff[10] * (FLAC__int64)data[i-11];
+ sum += qlp_coeff[ 9] * (FLAC__int64)data[i-10];
+ sum += qlp_coeff[ 8] * (FLAC__int64)data[i- 9];
+ sum += qlp_coeff[ 7] * (FLAC__int64)data[i- 8];
+ sum += qlp_coeff[ 6] * (FLAC__int64)data[i- 7];
+ sum += qlp_coeff[ 5] * (FLAC__int64)data[i- 6];
+ sum += qlp_coeff[ 4] * (FLAC__int64)data[i- 5];
+ sum += qlp_coeff[ 3] * (FLAC__int64)data[i- 4];
+ sum += qlp_coeff[ 2] * (FLAC__int64)data[i- 3];
+ sum += qlp_coeff[ 1] * (FLAC__int64)data[i- 2];
+ sum += qlp_coeff[ 0] * (FLAC__int64)data[i- 1];
+ }
+ data[i] = residual[i] + (FLAC__int32)(sum >> lp_quantization);
+ }
+ }
+}
+#endif
+
+#if defined(_MSC_VER)
+#pragma warning ( default : 4028 )
+#endif
+
+double FLAC__lpc_compute_expected_bits_per_residual_sample(double lpc_error, uint32_t total_samples)
+{
+ double error_scale;
+
+ error_scale = 0.5 / (double)total_samples;
+
+ return FLAC__lpc_compute_expected_bits_per_residual_sample_with_error_scale(lpc_error, error_scale);
+}
+
+double FLAC__lpc_compute_expected_bits_per_residual_sample_with_error_scale(double lpc_error, double error_scale)
+{
+ if(lpc_error > 0.0) {
+ double bps = (double)0.5 * log(error_scale * lpc_error) / M_LN2;
+ if(bps >= 0.0)
+ return bps;
+ else
+ return 0.0;
+ }
+ else if(lpc_error < 0.0) { /* error should not be negative but can happen due to inadequate floating-point resolution */
+ return 1e32;
+ }
+ else {
+ return 0.0;
+ }
+}
+
+uint32_t FLAC__lpc_compute_best_order(const double lpc_error[], uint32_t max_order, uint32_t total_samples, uint32_t overhead_bits_per_order)
+{
+ uint32_t order, indx, best_index; /* 'index' the index into lpc_error; index==order-1 since lpc_error[0] is for order==1, lpc_error[1] is for order==2, etc */
+ double bits, best_bits, error_scale;
+
+ error_scale = 0.5 / (double)total_samples;
+
+ best_index = 0;
+ best_bits = (uint32_t)(-1);
+
+ for(indx = 0, order = 1; indx < max_order; indx++, order++) {
+ bits = FLAC__lpc_compute_expected_bits_per_residual_sample_with_error_scale(lpc_error[indx], error_scale) * (double)(total_samples - order) + (double)(order * overhead_bits_per_order);
+ if(bits < best_bits) {
+ best_index = indx;
+ best_bits = bits;
+ }
+ }
+
+ return best_index+1; /* +1 since indx of lpc_error[] is order-1 */
+}
--- /dev/null
+++ b/src/libflac/md5.c
@@ -1,0 +1,479 @@
+#include <stdlib.h> /* for malloc() */
+#include <string.h> /* for memcpy() */
+
+#include "private/md5.h"
+#include "share/alloc.h"
+#include "share/compat.h"
+#include "share/endswap.h"
+
+/*
+ * This code implements the MD5 message-digest algorithm.
+ * The algorithm is due to Ron Rivest. This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * To compute the message digest of a chunk of bytes, declare an
+ * MD5Context structure, pass it to MD5Init, call MD5Update as
+ * needed on buffers full of bytes, and then call MD5Final, which
+ * will fill a supplied 16-byte array with the digest.
+ *
+ * Changed so as no longer to depend on Colin Plumb's `usual.h' header
+ * definitions; now uses stuff from dpkg's config.h.
+ * - Ian Jackson <ijackson@nyx.cs.du.edu>.
+ * Still in the public domain.
+ *
+ * Josh Coalson: made some changes to integrate with libFLAC.
+ * Still in the public domain.
+ */
+
+/* The four core functions - F1 is optimized somewhat */
+
+/* #define F1(x, y, z) (x & y | ~x & z) */
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) F1(z, x, y)
+#define F3(x, y, z) (x ^ y ^ z)
+#define F4(x, y, z) (y ^ (x | ~z))
+
+/* This is the central step in the MD5 algorithm. */
+#define MD5STEP(f,w,x,y,z,in,s) \
+ (w += f(x,y,z) + in, w = (w<<s | w>>(32-s)) + x)
+
+/*
+ * The core of the MD5 algorithm, this alters an existing MD5 hash to
+ * reflect the addition of 16 longwords of new data. MD5Update blocks
+ * the data and converts bytes into longwords for this routine.
+ */
+static void FLAC__MD5Transform(FLAC__uint32 buf[4], FLAC__uint32 const in[16])
+{
+ register FLAC__uint32 a, b, c, d;
+
+ a = buf[0];
+ b = buf[1];
+ c = buf[2];
+ d = buf[3];
+
+ MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
+ MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
+ MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
+ MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
+ MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
+ MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
+ MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
+ MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
+ MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
+ MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
+ MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
+ MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
+ MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
+ MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
+ MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
+ MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
+
+ MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
+ MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
+ MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
+ MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
+ MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
+ MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
+ MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
+ MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
+ MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
+ MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
+ MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
+ MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
+ MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
+ MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
+ MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
+ MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
+
+ MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
+ MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
+ MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
+ MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
+ MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
+ MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
+ MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
+ MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
+ MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
+ MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
+ MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
+ MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
+ MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
+ MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
+ MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
+ MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
+
+ MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
+ MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
+ MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
+ MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
+ MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
+ MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
+ MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
+ MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
+ MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
+ MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
+ MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
+ MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
+ MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
+ MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
+ MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
+ MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
+
+ buf[0] += a;
+ buf[1] += b;
+ buf[2] += c;
+ buf[3] += d;
+}
+
+#define byteSwap(buf, words)
+#define byteSwapX16(buf)
+
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+static void FLAC__MD5Update(FLAC__MD5Context *ctx, FLAC__byte const *buf, uint32_t len)
+{
+ FLAC__uint32 t;
+
+ /* Update byte count */
+
+ t = ctx->bytes[0];
+ if ((ctx->bytes[0] = t + len) < t)
+ ctx->bytes[1]++; /* Carry from low to high */
+
+ t = 64 - (t & 0x3f); /* Space available in ctx->in (at least 1) */
+ if (t > len) {
+ memcpy((FLAC__byte *)ctx->in + 64 - t, buf, len);
+ return;
+ }
+ /* First chunk is an odd size */
+ memcpy((FLAC__byte *)ctx->in + 64 - t, buf, t);
+ byteSwapX16(ctx->in);
+ FLAC__MD5Transform(ctx->buf, ctx->in);
+ buf += t;
+ len -= t;
+
+ /* Process data in 64-byte chunks */
+ while (len >= 64) {
+ memcpy(ctx->in, buf, 64);
+ byteSwapX16(ctx->in);
+ FLAC__MD5Transform(ctx->buf, ctx->in);
+ buf += 64;
+ len -= 64;
+ }
+
+ /* Handle any remaining bytes of data. */
+ memcpy(ctx->in, buf, len);
+}
+
+/*
+ * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
+ * initialization constants.
+ */
+void FLAC__MD5Init(FLAC__MD5Context *ctx)
+{
+ ctx->buf[0] = 0x67452301;
+ ctx->buf[1] = 0xefcdab89;
+ ctx->buf[2] = 0x98badcfe;
+ ctx->buf[3] = 0x10325476;
+
+ ctx->bytes[0] = 0;
+ ctx->bytes[1] = 0;
+
+ ctx->internal_buf.p8 = 0;
+ ctx->capacity = 0;
+}
+
+/*
+ * Final wrapup - pad to 64-byte boundary with the bit pattern
+ * 1 0* (64-bit count of bits processed, MSB-first)
+ */
+void FLAC__MD5Final(FLAC__byte digest[16], FLAC__MD5Context *ctx)
+{
+ int count = ctx->bytes[0] & 0x3f; /* Number of bytes in ctx->in */
+ FLAC__byte *p = (FLAC__byte *)ctx->in + count;
+
+ /* Set the first char of padding to 0x80. There is always room. */
+ *p++ = 0x80;
+
+ /* Bytes of padding needed to make 56 bytes (-8..55) */
+ count = 56 - 1 - count;
+
+ if (count < 0) { /* Padding forces an extra block */
+ memset(p, 0, count + 8);
+ byteSwapX16(ctx->in);
+ FLAC__MD5Transform(ctx->buf, ctx->in);
+ p = (FLAC__byte *)ctx->in;
+ count = 56;
+ }
+ memset(p, 0, count);
+ byteSwap(ctx->in, 14);
+
+ /* Append length in bits and transform */
+ ctx->in[14] = ctx->bytes[0] << 3;
+ ctx->in[15] = ctx->bytes[1] << 3 | ctx->bytes[0] >> 29;
+ FLAC__MD5Transform(ctx->buf, ctx->in);
+
+ byteSwap(ctx->buf, 4);
+ memcpy(digest, ctx->buf, 16);
+ if (0 != ctx->internal_buf.p8) {
+ free(ctx->internal_buf.p8);
+ ctx->internal_buf.p8 = 0;
+ ctx->capacity = 0;
+ }
+ memset(ctx, 0, sizeof(*ctx)); /* In case it's sensitive */
+}
+
+/*
+ * Convert the incoming audio signal to a byte stream
+ */
+static void format_input_(FLAC__multibyte *mbuf, const FLAC__int32 * const signal[], uint32_t channels, uint32_t samples, uint32_t bytes_per_sample)
+{
+ FLAC__byte *buf_ = mbuf->p8;
+ FLAC__int16 *buf16 = mbuf->p16;
+ FLAC__int32 *buf32 = mbuf->p32;
+ FLAC__int32 a_word;
+ uint32_t channel, sample;
+
+ /* Storage in the output buffer, buf, is little endian. */
+
+#define BYTES_CHANNEL_SELECTOR(bytes, channels) (bytes * 100 + channels)
+
+ /* First do the most commonly used combinations. */
+ switch (BYTES_CHANNEL_SELECTOR (bytes_per_sample, channels)) {
+ /* One byte per sample. */
+ case (BYTES_CHANNEL_SELECTOR (1, 1)):
+ for (sample = 0; sample < samples; sample++)
+ *buf_++ = (FLAC__byte)signal[0][sample];
+ return;
+
+ case (BYTES_CHANNEL_SELECTOR (1, 2)):
+ for (sample = 0; sample < samples; sample++) {
+ *buf_++ = (FLAC__byte)signal[0][sample];
+ *buf_++ = (FLAC__byte)signal[1][sample];
+ }
+ return;
+
+ case (BYTES_CHANNEL_SELECTOR (1, 4)):
+ for (sample = 0; sample < samples; sample++) {
+ *buf_++ = (FLAC__byte)signal[0][sample];
+ *buf_++ = (FLAC__byte)signal[1][sample];
+ *buf_++ = (FLAC__byte)signal[2][sample];
+ *buf_++ = (FLAC__byte)signal[3][sample];
+ }
+ return;
+
+ case (BYTES_CHANNEL_SELECTOR (1, 6)):
+ for (sample = 0; sample < samples; sample++) {
+ *buf_++ = (FLAC__byte)signal[0][sample];
+ *buf_++ = (FLAC__byte)signal[1][sample];
+ *buf_++ = (FLAC__byte)signal[2][sample];
+ *buf_++ = (FLAC__byte)signal[3][sample];
+ *buf_++ = (FLAC__byte)signal[4][sample];
+ *buf_++ = (FLAC__byte)signal[5][sample];
+ }
+ return;
+
+ case (BYTES_CHANNEL_SELECTOR (1, 8)):
+ for (sample = 0; sample < samples; sample++) {
+ *buf_++ = (FLAC__byte)signal[0][sample];
+ *buf_++ = (FLAC__byte)signal[1][sample];
+ *buf_++ = (FLAC__byte)signal[2][sample];
+ *buf_++ = (FLAC__byte)signal[3][sample];
+ *buf_++ = (FLAC__byte)signal[4][sample];
+ *buf_++ = (FLAC__byte)signal[5][sample];
+ *buf_++ = (FLAC__byte)signal[6][sample];
+ *buf_++ = (FLAC__byte)signal[7][sample];
+ }
+ return;
+
+ /* Two bytes per sample. */
+ case (BYTES_CHANNEL_SELECTOR (2, 1)):
+ for (sample = 0; sample < samples; sample++)
+ *buf16++ = (FLAC__int16)H2LE_16(signal[0][sample]);
+ return;
+
+ case (BYTES_CHANNEL_SELECTOR (2, 2)):
+ for (sample = 0; sample < samples; sample++) {
+ *buf16++ = (FLAC__int16)H2LE_16(signal[0][sample]);
+ *buf16++ = (FLAC__int16)H2LE_16(signal[1][sample]);
+ }
+ return;
+
+ case (BYTES_CHANNEL_SELECTOR (2, 4)):
+ for (sample = 0; sample < samples; sample++) {
+ *buf16++ = (FLAC__int16)H2LE_16(signal[0][sample]);
+ *buf16++ = (FLAC__int16)H2LE_16(signal[1][sample]);
+ *buf16++ = (FLAC__int16)H2LE_16(signal[2][sample]);
+ *buf16++ = (FLAC__int16)H2LE_16(signal[3][sample]);
+ }
+ return;
+
+ case (BYTES_CHANNEL_SELECTOR (2, 6)):
+ for (sample = 0; sample < samples; sample++) {
+ *buf16++ = (FLAC__int16)H2LE_16(signal[0][sample]);
+ *buf16++ = (FLAC__int16)H2LE_16(signal[1][sample]);
+ *buf16++ = (FLAC__int16)H2LE_16(signal[2][sample]);
+ *buf16++ = (FLAC__int16)H2LE_16(signal[3][sample]);
+ *buf16++ = (FLAC__int16)H2LE_16(signal[4][sample]);
+ *buf16++ = (FLAC__int16)H2LE_16(signal[5][sample]);
+ }
+ return;
+
+ case (BYTES_CHANNEL_SELECTOR (2, 8)):
+ for (sample = 0; sample < samples; sample++) {
+ *buf16++ = (FLAC__int16)H2LE_16(signal[0][sample]);
+ *buf16++ = (FLAC__int16)H2LE_16(signal[1][sample]);
+ *buf16++ = (FLAC__int16)H2LE_16(signal[2][sample]);
+ *buf16++ = (FLAC__int16)H2LE_16(signal[3][sample]);
+ *buf16++ = (FLAC__int16)H2LE_16(signal[4][sample]);
+ *buf16++ = (FLAC__int16)H2LE_16(signal[5][sample]);
+ *buf16++ = (FLAC__int16)H2LE_16(signal[6][sample]);
+ *buf16++ = (FLAC__int16)H2LE_16(signal[7][sample]);
+ }
+ return;
+
+ /* Three bytes per sample. */
+ case (BYTES_CHANNEL_SELECTOR (3, 1)):
+ for (sample = 0; sample < samples; sample++) {
+ a_word = signal[0][sample];
+ *buf_++ = (FLAC__byte)a_word; a_word >>= 8;
+ *buf_++ = (FLAC__byte)a_word; a_word >>= 8;
+ *buf_++ = (FLAC__byte)a_word;
+ }
+ return;
+
+ case (BYTES_CHANNEL_SELECTOR (3, 2)):
+ for (sample = 0; sample < samples; sample++) {
+ a_word = signal[0][sample];
+ *buf_++ = (FLAC__byte)a_word; a_word >>= 8;
+ *buf_++ = (FLAC__byte)a_word; a_word >>= 8;
+ *buf_++ = (FLAC__byte)a_word;
+ a_word = signal[1][sample];
+ *buf_++ = (FLAC__byte)a_word; a_word >>= 8;
+ *buf_++ = (FLAC__byte)a_word; a_word >>= 8;
+ *buf_++ = (FLAC__byte)a_word;
+ }
+ return;
+
+ /* Four bytes per sample. */
+ case (BYTES_CHANNEL_SELECTOR (4, 1)):
+ for (sample = 0; sample < samples; sample++)
+ *buf32++ = H2LE_32(signal[0][sample]);
+ return;
+
+ case (BYTES_CHANNEL_SELECTOR (4, 2)):
+ for (sample = 0; sample < samples; sample++) {
+ *buf32++ = H2LE_32(signal[0][sample]);
+ *buf32++ = H2LE_32(signal[1][sample]);
+ }
+ return;
+
+ case (BYTES_CHANNEL_SELECTOR (4, 4)):
+ for (sample = 0; sample < samples; sample++) {
+ *buf32++ = H2LE_32(signal[0][sample]);
+ *buf32++ = H2LE_32(signal[1][sample]);
+ *buf32++ = H2LE_32(signal[2][sample]);
+ *buf32++ = H2LE_32(signal[3][sample]);
+ }
+ return;
+
+ case (BYTES_CHANNEL_SELECTOR (4, 6)):
+ for (sample = 0; sample < samples; sample++) {
+ *buf32++ = H2LE_32(signal[0][sample]);
+ *buf32++ = H2LE_32(signal[1][sample]);
+ *buf32++ = H2LE_32(signal[2][sample]);
+ *buf32++ = H2LE_32(signal[3][sample]);
+ *buf32++ = H2LE_32(signal[4][sample]);
+ *buf32++ = H2LE_32(signal[5][sample]);
+ }
+ return;
+
+ case (BYTES_CHANNEL_SELECTOR (4, 8)):
+ for (sample = 0; sample < samples; sample++) {
+ *buf32++ = H2LE_32(signal[0][sample]);
+ *buf32++ = H2LE_32(signal[1][sample]);
+ *buf32++ = H2LE_32(signal[2][sample]);
+ *buf32++ = H2LE_32(signal[3][sample]);
+ *buf32++ = H2LE_32(signal[4][sample]);
+ *buf32++ = H2LE_32(signal[5][sample]);
+ *buf32++ = H2LE_32(signal[6][sample]);
+ *buf32++ = H2LE_32(signal[7][sample]);
+ }
+ return;
+
+ default:
+ break;
+ }
+
+ /* General version. */
+ switch (bytes_per_sample) {
+ case 1:
+ for (sample = 0; sample < samples; sample++)
+ for (channel = 0; channel < channels; channel++)
+ *buf_++ = (FLAC__byte)signal[channel][sample];
+ return;
+
+ case 2:
+ for (sample = 0; sample < samples; sample++)
+ for (channel = 0; channel < channels; channel++)
+ *buf16++ = (FLAC__int16)H2LE_16(signal[channel][sample]);
+ return;
+
+ case 3:
+ for (sample = 0; sample < samples; sample++)
+ for (channel = 0; channel < channels; channel++) {
+ a_word = signal[channel][sample];
+ *buf_++ = (FLAC__byte)a_word; a_word >>= 8;
+ *buf_++ = (FLAC__byte)a_word; a_word >>= 8;
+ *buf_++ = (FLAC__byte)a_word;
+ }
+ return;
+
+ case 4:
+ for (sample = 0; sample < samples; sample++)
+ for (channel = 0; channel < channels; channel++)
+ *buf32++ = H2LE_32(signal[channel][sample]);
+ return;
+
+ default:
+ break;
+ }
+}
+
+/*
+ * Convert the incoming audio signal to a byte stream and FLAC__MD5Update it.
+ */
+FLAC__bool FLAC__MD5Accumulate(FLAC__MD5Context *ctx, const FLAC__int32 * const signal[], uint32_t channels, uint32_t samples, uint32_t bytes_per_sample)
+{
+ const size_t bytes_needed = (size_t)channels * (size_t)samples * (size_t)bytes_per_sample;
+
+ /* overflow check */
+ if ((size_t)channels > SIZE_MAX / (size_t)bytes_per_sample)
+ return false;
+ if ((size_t)channels * (size_t)bytes_per_sample > SIZE_MAX / (size_t)samples)
+ return false;
+
+ if (ctx->capacity < bytes_needed) {
+ if (0 == (ctx->internal_buf.p8 = safe_realloc_(ctx->internal_buf.p8, bytes_needed))) {
+ if (0 == (ctx->internal_buf.p8 = safe_malloc_(bytes_needed))) {
+ ctx->capacity = 0;
+ return false;
+ }
+ }
+ ctx->capacity = bytes_needed;
+ }
+
+ format_input_(&ctx->internal_buf, signal, channels, samples, bytes_per_sample);
+
+ FLAC__MD5Update(ctx, ctx->internal_buf.p8, (uint32_t)bytes_needed);
+
+ return true;
+}
--- /dev/null
+++ b/src/libflac/memory.c
@@ -1,0 +1,175 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2001-2009 Josh Coalson
+ * Copyright (C) 2011-2016 Xiph.Org Foundation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdint.h>
+#include "private/memory.h"
+#include "share/compat.h"
+#include "share/alloc.h"
+
+void *FLAC__memory_alloc_aligned(size_t bytes, void **aligned_address)
+{
+ void *x;
+
+ x = safe_malloc_(bytes);
+ *aligned_address = x;
+
+ return x;
+}
+
+FLAC__bool FLAC__memory_alloc_aligned_int32_array(size_t elements, FLAC__int32 **unaligned_pointer, FLAC__int32 **aligned_pointer)
+{
+ FLAC__int32 *pu; /* unaligned pointer */
+ union { /* union needed to comply with C99 pointer aliasing rules */
+ FLAC__int32 *pa; /* aligned pointer */
+ void *pv; /* aligned pointer alias */
+ } u;
+
+ if(elements > SIZE_MAX / sizeof(*pu)) /* overflow check */
+ return false;
+
+ pu = FLAC__memory_alloc_aligned(sizeof(*pu) * elements, &u.pv);
+ if(0 == pu) {
+ return false;
+ }
+ else {
+ if(*unaligned_pointer != 0)
+ free(*unaligned_pointer);
+ *unaligned_pointer = pu;
+ *aligned_pointer = u.pa;
+ return true;
+ }
+}
+
+FLAC__bool FLAC__memory_alloc_aligned_uint32_array(size_t elements, FLAC__uint32 **unaligned_pointer, FLAC__uint32 **aligned_pointer)
+{
+ FLAC__uint32 *pu; /* unaligned pointer */
+ union { /* union needed to comply with C99 pointer aliasing rules */
+ FLAC__uint32 *pa; /* aligned pointer */
+ void *pv; /* aligned pointer alias */
+ } u;
+
+ if(elements > SIZE_MAX / sizeof(*pu)) /* overflow check */
+ return false;
+
+ pu = FLAC__memory_alloc_aligned(sizeof(*pu) * elements, &u.pv);
+ if(0 == pu) {
+ return false;
+ }
+ else {
+ if(*unaligned_pointer != 0)
+ free(*unaligned_pointer);
+ *unaligned_pointer = pu;
+ *aligned_pointer = u.pa;
+ return true;
+ }
+}
+
+FLAC__bool FLAC__memory_alloc_aligned_uint64_array(size_t elements, FLAC__uint64 **unaligned_pointer, FLAC__uint64 **aligned_pointer)
+{
+ FLAC__uint64 *pu; /* unaligned pointer */
+ union { /* union needed to comply with C99 pointer aliasing rules */
+ FLAC__uint64 *pa; /* aligned pointer */
+ void *pv; /* aligned pointer alias */
+ } u;
+
+ if(elements > SIZE_MAX / sizeof(*pu)) /* overflow check */
+ return false;
+
+ pu = FLAC__memory_alloc_aligned(sizeof(*pu) * elements, &u.pv);
+ if(0 == pu) {
+ return false;
+ }
+ else {
+ if(*unaligned_pointer != 0)
+ free(*unaligned_pointer);
+ *unaligned_pointer = pu;
+ *aligned_pointer = u.pa;
+ return true;
+ }
+}
+
+FLAC__bool FLAC__memory_alloc_aligned_unsigned_array(size_t elements, uint32_t **unaligned_pointer, uint32_t **aligned_pointer)
+{
+ uint32_t *pu; /* unaligned pointer */
+ union { /* union needed to comply with C99 pointer aliasing rules */
+ uint32_t *pa; /* aligned pointer */
+ void *pv; /* aligned pointer alias */
+ } u;
+
+ if(elements > SIZE_MAX / sizeof(*pu)) /* overflow check */
+ return false;
+
+ pu = FLAC__memory_alloc_aligned(sizeof(*pu) * elements, &u.pv);
+ if(0 == pu) {
+ return false;
+ }
+ else {
+ if(*unaligned_pointer != 0)
+ free(*unaligned_pointer);
+ *unaligned_pointer = pu;
+ *aligned_pointer = u.pa;
+ return true;
+ }
+}
+
+FLAC__bool FLAC__memory_alloc_aligned_real_array(size_t elements, FLAC__real **unaligned_pointer, FLAC__real **aligned_pointer)
+{
+ FLAC__real *pu; /* unaligned pointer */
+ union { /* union needed to comply with C99 pointer aliasing rules */
+ FLAC__real *pa; /* aligned pointer */
+ void *pv; /* aligned pointer alias */
+ } u;
+
+ if(elements > SIZE_MAX / sizeof(*pu)) /* overflow check */
+ return false;
+
+ pu = FLAC__memory_alloc_aligned(sizeof(*pu) * elements, &u.pv);
+ if(0 == pu) {
+ return false;
+ }
+ else {
+ if(*unaligned_pointer != 0)
+ free(*unaligned_pointer);
+ *unaligned_pointer = pu;
+ *aligned_pointer = u.pa;
+ return true;
+ }
+}
+
+void *safe_malloc_mul_2op_p(size_t size1, size_t size2)
+{
+ if(!size1 || !size2)
+ return malloc(1); /* malloc(0) is undefined; FLAC src convention is to always allocate */
+ if(size1 > SIZE_MAX / size2)
+ return 0;
+ return malloc(size1*size2);
+}
--- /dev/null
+++ b/src/libflac/metadata_iterators.c
@@ -1,0 +1,3147 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2001-2009 Josh Coalson
+ * Copyright (C) 2011-2016 Xiph.Org Foundation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+
+#include <sys/stat.h> /* for stat(), maybe chmod() */
+
+#include "private/metadata.h"
+
+#include "FLAC/stream_decoder.h"
+#include "share/alloc.h"
+#include "share/compat.h"
+#include "share/macros.h"
+#include "share/safe_str.h"
+#include "private/macros.h"
+#include "private/memory.h"
+
+// 8bb: hide POSIX warnings
+#ifdef _MSC_VER
+#pragma warning(disable: 4996)
+#endif
+
+/* Alias the first (in share/alloc.h) to the second (in src/libFLAC/memory.c). */
+#define safe_malloc_mul_2op_ safe_malloc_mul_2op_p
+
+/****************************************************************************
+ *
+ * Local function declarations
+ *
+ ***************************************************************************/
+
+static void pack_uint32_(FLAC__uint32 val, FLAC__byte *b, uint32_t bytes);
+static void pack_uint32_little_endian_(FLAC__uint32 val, FLAC__byte *b, uint32_t bytes);
+static void pack_uint64_(FLAC__uint64 val, FLAC__byte *b, uint32_t bytes);
+static FLAC__uint32 unpack_uint32_(FLAC__byte *b, uint32_t bytes);
+static FLAC__uint32 unpack_uint32_little_endian_(FLAC__byte *b, uint32_t bytes);
+static FLAC__uint64 unpack_uint64_(FLAC__byte *b, uint32_t bytes);
+
+static FLAC__bool read_metadata_block_header_(FLAC__Metadata_SimpleIterator *iterator);
+static FLAC__bool read_metadata_block_data_(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block);
+static FLAC__bool read_metadata_block_header_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__bool *is_last, FLAC__MetadataType *type, uint32_t *length);
+static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Seek seek_cb, FLAC__StreamMetadata *block);
+static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_streaminfo_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_StreamInfo *block);
+static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_padding_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Seek seek_cb, FLAC__StreamMetadata_Padding *block, uint32_t block_length);
+static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_application_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_Application *block, uint32_t block_length);
+static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_seektable_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_SeekTable *block, uint32_t block_length);
+static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_vorbis_comment_entry_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_VorbisComment_Entry *entry, uint32_t max_length);
+static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_vorbis_comment_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Seek seek_cb, FLAC__StreamMetadata_VorbisComment *block, uint32_t block_length);
+static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_cuesheet_track_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_CueSheet_Track *track);
+static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_cuesheet_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_CueSheet *block);
+static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_picture_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_Picture *block);
+static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_unknown_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_Unknown *block, uint32_t block_length);
+
+static FLAC__bool write_metadata_block_header_(FILE *file, FLAC__Metadata_SimpleIteratorStatus *status, const FLAC__StreamMetadata *block);
+static FLAC__bool write_metadata_block_data_(FILE *file, FLAC__Metadata_SimpleIteratorStatus *status, const FLAC__StreamMetadata *block);
+static FLAC__bool write_metadata_block_header_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata *block);
+static FLAC__bool write_metadata_block_data_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata *block);
+static FLAC__bool write_metadata_block_data_streaminfo_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_StreamInfo *block);
+static FLAC__bool write_metadata_block_data_padding_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Padding *block, uint32_t block_length);
+static FLAC__bool write_metadata_block_data_application_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Application *block, uint32_t block_length);
+static FLAC__bool write_metadata_block_data_seektable_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_SeekTable *block);
+static FLAC__bool write_metadata_block_data_vorbis_comment_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_VorbisComment *block);
+static FLAC__bool write_metadata_block_data_cuesheet_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_CueSheet *block);
+static FLAC__bool write_metadata_block_data_picture_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Picture *block);
+static FLAC__bool write_metadata_block_data_unknown_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Unknown *block, uint32_t block_length);
+
+static FLAC__bool write_metadata_block_stationary_(FLAC__Metadata_SimpleIterator *iterator, const FLAC__StreamMetadata *block);
+static FLAC__bool write_metadata_block_stationary_with_padding_(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block, uint32_t padding_length, FLAC__bool padding_is_last);
+static FLAC__bool rewrite_whole_file_(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block, FLAC__bool append);
+
+static void simple_iterator_push_(FLAC__Metadata_SimpleIterator *iterator);
+static FLAC__bool simple_iterator_pop_(FLAC__Metadata_SimpleIterator *iterator);
+
+static uint32_t seek_to_first_metadata_block_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Seek seek_cb);
+static uint32_t seek_to_first_metadata_block_(FILE *f);
+
+static FLAC__bool simple_iterator_copy_file_prefix_(FLAC__Metadata_SimpleIterator *iterator, FILE **tempfile, char **tempfilename, FLAC__bool append);
+static FLAC__bool simple_iterator_copy_file_postfix_(FLAC__Metadata_SimpleIterator *iterator, FILE **tempfile, char **tempfilename, int fixup_is_last_code, FLAC__off_t fixup_is_last_flag_offset, FLAC__bool backup);
+
+static FLAC__bool copy_n_bytes_from_file_(FILE *file, FILE *tempfile, FLAC__off_t bytes, FLAC__Metadata_SimpleIteratorStatus *status);
+static FLAC__bool copy_n_bytes_from_file_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOHandle temp_handle, FLAC__IOCallback_Write temp_write_cb, FLAC__off_t bytes, FLAC__Metadata_SimpleIteratorStatus *status);
+static FLAC__bool copy_remaining_bytes_from_file_(FILE *file, FILE *tempfile, FLAC__Metadata_SimpleIteratorStatus *status);
+static FLAC__bool copy_remaining_bytes_from_file_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Eof eof_cb, FLAC__IOHandle temp_handle, FLAC__IOCallback_Write temp_write_cb, FLAC__Metadata_SimpleIteratorStatus *status);
+
+static FLAC__bool open_tempfile_(const char *filename, const char *tempfile_path_prefix, FILE **tempfile, char **tempfilename, FLAC__Metadata_SimpleIteratorStatus *status);
+static FLAC__bool transport_tempfile_(const char *filename, FILE **tempfile, char **tempfilename, FLAC__Metadata_SimpleIteratorStatus *status);
+static void cleanup_tempfile_(FILE **tempfile, char **tempfilename);
+
+static FLAC__bool get_file_stats_(const char *filename, struct flac_stat_s *stats);
+static void set_file_stats_(const char *filename, struct flac_stat_s *stats);
+
+static int fseek_wrapper_(FLAC__IOHandle handle, FLAC__int64 offset, int whence);
+static FLAC__int64 ftell_wrapper_(FLAC__IOHandle handle);
+
+static FLAC__Metadata_ChainStatus get_equivalent_status_(FLAC__Metadata_SimpleIteratorStatus status);
+
+
+#ifdef FLAC__VALGRIND_TESTING
+static size_t local__fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)
+{
+ size_t ret = fwrite(ptr, size, nmemb, stream);
+ if(!ferror(stream))
+ fflush(stream);
+ return ret;
+}
+#else
+#define local__fwrite fwrite
+#endif
+
+/****************************************************************************
+ *
+ * Level 0 implementation
+ *
+ ***************************************************************************/
+
+static FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data);
+static void metadata_callback_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data);
+static void error_callback_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data);
+
+typedef struct {
+ FLAC__bool got_error;
+ FLAC__StreamMetadata *object;
+} level0_client_data;
+
+static FLAC__StreamMetadata *get_one_metadata_block_(const char *filename, FLAC__MetadataType type)
+{
+ level0_client_data cd;
+ FLAC__StreamDecoder *decoder;
+
+ cd.got_error = false;
+ cd.object = 0;
+
+ decoder = FLAC__stream_decoder_new();
+
+ if(0 == decoder)
+ return 0;
+
+ FLAC__stream_decoder_set_md5_checking(decoder, false);
+ FLAC__stream_decoder_set_metadata_ignore_all(decoder);
+ FLAC__stream_decoder_set_metadata_respond(decoder, type);
+
+ if(FLAC__stream_decoder_init_file(decoder, filename, write_callback_, metadata_callback_, error_callback_, &cd) != FLAC__STREAM_DECODER_INIT_STATUS_OK || cd.got_error) {
+ (void)FLAC__stream_decoder_finish(decoder);
+ FLAC__stream_decoder_delete(decoder);
+ return 0;
+ }
+
+ if(!FLAC__stream_decoder_process_until_end_of_metadata(decoder) || cd.got_error) {
+ (void)FLAC__stream_decoder_finish(decoder);
+ FLAC__stream_decoder_delete(decoder);
+ if(0 != cd.object)
+ FLAC__metadata_object_delete(cd.object);
+ return 0;
+ }
+
+ (void)FLAC__stream_decoder_finish(decoder);
+ FLAC__stream_decoder_delete(decoder);
+
+ return cd.object;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_get_streaminfo(const char *filename, FLAC__StreamMetadata *streaminfo)
+{
+ FLAC__StreamMetadata *object;
+
+ object = get_one_metadata_block_(filename, FLAC__METADATA_TYPE_STREAMINFO);
+
+ if (object) {
+ /* can just copy the contents since STREAMINFO has no internal structure */
+ *streaminfo = *object;
+ FLAC__metadata_object_delete(object);
+ return true;
+ }
+ else {
+ return false;
+ }
+}
+
+FLAC_API FLAC__bool FLAC__metadata_get_tags(const char *filename, FLAC__StreamMetadata **tags)
+{
+ *tags = get_one_metadata_block_(filename, FLAC__METADATA_TYPE_VORBIS_COMMENT);
+
+ return 0 != *tags;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_get_cuesheet(const char *filename, FLAC__StreamMetadata **cuesheet)
+{
+ *cuesheet = get_one_metadata_block_(filename, FLAC__METADATA_TYPE_CUESHEET);
+
+ return 0 != *cuesheet;
+}
+
+FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data)
+{
+ (void)decoder, (void)frame, (void)buffer, (void)client_data;
+
+ return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
+}
+
+void metadata_callback_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data)
+{
+ level0_client_data *cd = (level0_client_data *)client_data;
+ (void)decoder;
+
+ /*
+ * we assume we only get here when the one metadata block we were
+ * looking for was passed to us
+ */
+ if(!cd->got_error && 0 == cd->object) {
+ if(0 == (cd->object = FLAC__metadata_object_clone(metadata)))
+ cd->got_error = true;
+ }
+}
+
+void error_callback_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
+{
+ level0_client_data *cd = (level0_client_data *)client_data;
+ (void)decoder;
+
+ if(status != FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC)
+ cd->got_error = true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_get_picture(const char *filename, FLAC__StreamMetadata **picture, FLAC__StreamMetadata_Picture_Type type, const char *mime_type, const FLAC__byte *description, uint32_t max_width, uint32_t max_height, uint32_t max_depth, uint32_t max_colors)
+{
+ FLAC__Metadata_SimpleIterator *it;
+ FLAC__uint64 max_area_seen = 0;
+ FLAC__uint64 max_depth_seen = 0;
+
+ *picture = 0;
+
+ it = FLAC__metadata_simple_iterator_new();
+ if(0 == it)
+ return false;
+ if(!FLAC__metadata_simple_iterator_init(it, filename, /*read_only=*/true, /*preserve_file_stats=*/true)) {
+ FLAC__metadata_simple_iterator_delete(it);
+ return false;
+ }
+ do {
+ if(FLAC__metadata_simple_iterator_get_block_type(it) == FLAC__METADATA_TYPE_PICTURE) {
+ FLAC__StreamMetadata *obj = FLAC__metadata_simple_iterator_get_block(it);
+ FLAC__uint64 area = (FLAC__uint64)obj->data.picture.width * (FLAC__uint64)obj->data.picture.height;
+ /* check constraints */
+ if(
+ (type == (FLAC__StreamMetadata_Picture_Type)(-1) || type == obj->data.picture.type) &&
+ (mime_type == 0 || !strcmp(mime_type, obj->data.picture.mime_type)) &&
+ (description == 0 || !strcmp((const char *)description, (const char *)obj->data.picture.description)) &&
+ obj->data.picture.width <= max_width &&
+ obj->data.picture.height <= max_height &&
+ obj->data.picture.depth <= max_depth &&
+ obj->data.picture.colors <= max_colors &&
+ (area > max_area_seen || (area == max_area_seen && obj->data.picture.depth > max_depth_seen))
+ ) {
+ if(*picture)
+ FLAC__metadata_object_delete(*picture);
+ *picture = obj;
+ max_area_seen = area;
+ max_depth_seen = obj->data.picture.depth;
+ }
+ else {
+ FLAC__metadata_object_delete(obj);
+ }
+ }
+ } while(FLAC__metadata_simple_iterator_next(it));
+
+ FLAC__metadata_simple_iterator_delete(it);
+
+ return (0 != *picture);
+}
+
+
+/****************************************************************************
+ *
+ * Level 1 implementation
+ *
+ ***************************************************************************/
+
+#define SIMPLE_ITERATOR_MAX_PUSH_DEPTH (1+4)
+/* 1 for initial offset, +4 for our own personal use */
+
+struct FLAC__Metadata_SimpleIterator {
+ FILE *file;
+ char *filename, *tempfile_path_prefix;
+ struct flac_stat_s stats;
+ FLAC__bool has_stats;
+ FLAC__bool is_writable;
+ FLAC__Metadata_SimpleIteratorStatus status;
+ FLAC__off_t offset[SIMPLE_ITERATOR_MAX_PUSH_DEPTH];
+ FLAC__off_t first_offset; /* this is the offset to the STREAMINFO block */
+ uint32_t depth;
+ /* this is the metadata block header of the current block we are pointing to: */
+ FLAC__bool is_last;
+ FLAC__MetadataType type;
+ uint32_t length;
+};
+
+FLAC_API const char * const FLAC__Metadata_SimpleIteratorStatusString[] = {
+ "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK",
+ "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT",
+ "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ERROR_OPENING_FILE",
+ "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_A_FLAC_FILE",
+ "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_WRITABLE",
+ "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_BAD_METADATA",
+ "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR",
+ "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR",
+ "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR",
+ "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_RENAME_ERROR",
+ "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_UNLINK_ERROR",
+ "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR",
+ "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_INTERNAL_ERROR"
+};
+
+
+FLAC_API FLAC__Metadata_SimpleIterator *FLAC__metadata_simple_iterator_new(void)
+{
+ FLAC__Metadata_SimpleIterator *iterator = calloc(1, sizeof(FLAC__Metadata_SimpleIterator));
+
+ if(0 != iterator) {
+ iterator->file = 0;
+ iterator->filename = 0;
+ iterator->tempfile_path_prefix = 0;
+ iterator->has_stats = false;
+ iterator->is_writable = false;
+ iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
+ iterator->first_offset = iterator->offset[0] = -1;
+ iterator->depth = 0;
+ }
+
+ return iterator;
+}
+
+static void simple_iterator_free_guts_(FLAC__Metadata_SimpleIterator *iterator)
+{
+ if(0 != iterator->file) {
+ fclose(iterator->file);
+ iterator->file = 0;
+ if(iterator->has_stats)
+ set_file_stats_(iterator->filename, &iterator->stats);
+ }
+ if(0 != iterator->filename) {
+ free(iterator->filename);
+ iterator->filename = 0;
+ }
+ if(0 != iterator->tempfile_path_prefix) {
+ free(iterator->tempfile_path_prefix);
+ iterator->tempfile_path_prefix = 0;
+ }
+}
+
+FLAC_API void FLAC__metadata_simple_iterator_delete(FLAC__Metadata_SimpleIterator *iterator)
+{
+ simple_iterator_free_guts_(iterator);
+ free(iterator);
+}
+
+FLAC_API FLAC__Metadata_SimpleIteratorStatus FLAC__metadata_simple_iterator_status(FLAC__Metadata_SimpleIterator *iterator)
+{
+ FLAC__Metadata_SimpleIteratorStatus status;
+
+ status = iterator->status;
+ iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
+ return status;
+}
+
+static FLAC__bool simple_iterator_prime_input_(FLAC__Metadata_SimpleIterator *iterator, FLAC__bool read_only)
+{
+ uint32_t ret;
+
+ if(read_only || 0 == (iterator->file = flac_fopen(iterator->filename, "r+b"))) {
+ iterator->is_writable = false;
+ if(read_only || errno == EACCES) {
+ if(0 == (iterator->file = flac_fopen(iterator->filename, "rb"))) {
+ iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ERROR_OPENING_FILE;
+ return false;
+ }
+ }
+ else {
+ iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ERROR_OPENING_FILE;
+ return false;
+ }
+ }
+ else {
+ iterator->is_writable = true;
+ }
+
+ ret = seek_to_first_metadata_block_(iterator->file);
+ switch(ret) {
+ case 0:
+ iterator->depth = 0;
+ iterator->first_offset = iterator->offset[iterator->depth] = ftello(iterator->file);
+ return read_metadata_block_header_(iterator);
+ case 1:
+ iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+ return false;
+ case 2:
+ iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
+ return false;
+ case 3:
+ iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_A_FLAC_FILE;
+ return false;
+ default:
+ return false;
+ }
+}
+
+FLAC_API FLAC__bool FLAC__metadata_simple_iterator_init(FLAC__Metadata_SimpleIterator *iterator, const char *filename, FLAC__bool read_only, FLAC__bool preserve_file_stats)
+{
+ const char *tempfile_path_prefix = 0; /*@@@ search for comments near 'flac_rename(...)' for what it will take to finish implementing this */
+
+ simple_iterator_free_guts_(iterator);
+
+ if(!read_only && preserve_file_stats)
+ iterator->has_stats = get_file_stats_(filename, &iterator->stats);
+
+ if(0 == (iterator->filename = strdup(filename))) {
+ iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
+ return false;
+ }
+ if(0 != tempfile_path_prefix && 0 == (iterator->tempfile_path_prefix = strdup(tempfile_path_prefix))) {
+ iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
+ return false;
+ }
+
+ return simple_iterator_prime_input_(iterator, read_only);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_simple_iterator_is_writable(const FLAC__Metadata_SimpleIterator *iterator)
+{
+ return iterator->is_writable;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_simple_iterator_next(FLAC__Metadata_SimpleIterator *iterator)
+{
+ if(iterator->is_last)
+ return false;
+
+ if(0 != fseeko(iterator->file, iterator->length, SEEK_CUR)) {
+ iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
+ return false;
+ }
+
+ iterator->offset[iterator->depth] = ftello(iterator->file);
+
+ return read_metadata_block_header_(iterator);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_simple_iterator_prev(FLAC__Metadata_SimpleIterator *iterator)
+{
+ FLAC__off_t this_offset;
+
+ if(iterator->offset[iterator->depth] == iterator->first_offset)
+ return false;
+
+ if(0 != fseeko(iterator->file, iterator->first_offset, SEEK_SET)) {
+ iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
+ return false;
+ }
+ this_offset = iterator->first_offset;
+ if(!read_metadata_block_header_(iterator))
+ return false;
+
+ /* we ignore any error from ftello() and catch it in fseeko() */
+ while(ftello(iterator->file) + (FLAC__off_t)iterator->length < iterator->offset[iterator->depth]) {
+ if(0 != fseeko(iterator->file, iterator->length, SEEK_CUR)) {
+ iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
+ return false;
+ }
+ this_offset = ftello(iterator->file);
+ if(!read_metadata_block_header_(iterator))
+ return false;
+ }
+
+ iterator->offset[iterator->depth] = this_offset;
+
+ return true;
+}
+
+/*@@@@add to tests*/
+FLAC_API FLAC__bool FLAC__metadata_simple_iterator_is_last(const FLAC__Metadata_SimpleIterator *iterator)
+{
+ return iterator->is_last;
+}
+
+/*@@@@add to tests*/
+FLAC_API off_t FLAC__metadata_simple_iterator_get_block_offset(const FLAC__Metadata_SimpleIterator *iterator)
+{
+ return (off_t)iterator->offset[iterator->depth];
+}
+
+FLAC_API FLAC__MetadataType FLAC__metadata_simple_iterator_get_block_type(const FLAC__Metadata_SimpleIterator *iterator)
+{
+ return iterator->type;
+}
+
+/*@@@@add to tests*/
+FLAC_API uint32_t FLAC__metadata_simple_iterator_get_block_length(const FLAC__Metadata_SimpleIterator *iterator)
+{
+ return iterator->length;
+}
+
+/*@@@@add to tests*/
+FLAC_API FLAC__bool FLAC__metadata_simple_iterator_get_application_id(FLAC__Metadata_SimpleIterator *iterator, FLAC__byte *id)
+{
+ const uint32_t id_bytes = FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8;
+
+ if(iterator->type != FLAC__METADATA_TYPE_APPLICATION) {
+ iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT;
+ return false;
+ }
+
+ if(fread(id, 1, id_bytes, iterator->file) != id_bytes) {
+ iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+ return false;
+ }
+
+ /* back up */
+ if(0 != fseeko(iterator->file, -((int)id_bytes), SEEK_CUR)) {
+ iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
+ return false;
+ }
+
+ return true;
+}
+
+FLAC_API FLAC__StreamMetadata *FLAC__metadata_simple_iterator_get_block(FLAC__Metadata_SimpleIterator *iterator)
+{
+ FLAC__StreamMetadata *block = FLAC__metadata_object_new(iterator->type);
+
+ if(0 != block) {
+ block->is_last = iterator->is_last;
+ block->length = iterator->length;
+
+ if(!read_metadata_block_data_(iterator, block)) {
+ FLAC__metadata_object_delete(block);
+ return 0;
+ }
+
+ /* back up to the beginning of the block data to stay consistent */
+ if(0 != fseeko(iterator->file, iterator->offset[iterator->depth] + FLAC__STREAM_METADATA_HEADER_LENGTH, SEEK_SET)) {
+ iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
+ FLAC__metadata_object_delete(block);
+ return 0;
+ }
+ }
+ else
+ iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
+
+ return block;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_simple_iterator_set_block(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block, FLAC__bool use_padding)
+{
+ FLAC__bool ret;
+
+ if(!iterator->is_writable) {
+ iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_WRITABLE;
+ return false;
+ }
+
+ if(iterator->type == FLAC__METADATA_TYPE_STREAMINFO || block->type == FLAC__METADATA_TYPE_STREAMINFO) {
+ if(iterator->type != block->type) {
+ iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT;
+ return false;
+ }
+ }
+
+ block->is_last = iterator->is_last;
+
+ if(iterator->length == block->length)
+ return write_metadata_block_stationary_(iterator, block);
+ else if(iterator->length > block->length) {
+ if(use_padding && iterator->length >= FLAC__STREAM_METADATA_HEADER_LENGTH + block->length) {
+ ret = write_metadata_block_stationary_with_padding_(iterator, block, iterator->length - FLAC__STREAM_METADATA_HEADER_LENGTH - block->length, block->is_last);
+ return ret;
+ }
+ else {
+ ret = rewrite_whole_file_(iterator, block, /*append=*/false);
+ return ret;
+ }
+ }
+ else /* iterator->length < block->length */ {
+ uint32_t padding_leftover = 0;
+ FLAC__bool padding_is_last = false;
+ if(use_padding) {
+ /* first see if we can even use padding */
+ if(iterator->is_last) {
+ use_padding = false;
+ }
+ else {
+ const uint32_t extra_padding_bytes_required = block->length - iterator->length;
+ simple_iterator_push_(iterator);
+ if(!FLAC__metadata_simple_iterator_next(iterator)) {
+ (void)simple_iterator_pop_(iterator);
+ return false;
+ }
+ if(iterator->type != FLAC__METADATA_TYPE_PADDING) {
+ use_padding = false;
+ }
+ else {
+ if(FLAC__STREAM_METADATA_HEADER_LENGTH + iterator->length == extra_padding_bytes_required) {
+ padding_leftover = 0;
+ block->is_last = iterator->is_last;
+ }
+ else if(iterator->length < extra_padding_bytes_required)
+ use_padding = false;
+ else {
+ padding_leftover = FLAC__STREAM_METADATA_HEADER_LENGTH + iterator->length - extra_padding_bytes_required;
+ padding_is_last = iterator->is_last;
+ block->is_last = false;
+ }
+ }
+ if(!simple_iterator_pop_(iterator))
+ return false;
+ }
+ }
+ if(use_padding) {
+ if(padding_leftover == 0) {
+ ret = write_metadata_block_stationary_(iterator, block);
+ return ret;
+ }
+ else {
+ ret = write_metadata_block_stationary_with_padding_(iterator, block, padding_leftover - FLAC__STREAM_METADATA_HEADER_LENGTH, padding_is_last);
+ return ret;
+ }
+ }
+ else {
+ ret = rewrite_whole_file_(iterator, block, /*append=*/false);
+ return ret;
+ }
+ }
+}
+
+FLAC_API FLAC__bool FLAC__metadata_simple_iterator_insert_block_after(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block, FLAC__bool use_padding)
+{
+ uint32_t padding_leftover = 0;
+ FLAC__bool padding_is_last = false;
+
+ FLAC__bool ret;
+
+ if(!iterator->is_writable) {
+ iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_WRITABLE;
+ return false;
+ }
+
+ if(block->type == FLAC__METADATA_TYPE_STREAMINFO) {
+ iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT;
+ return false;
+ }
+
+ block->is_last = iterator->is_last;
+
+ if(use_padding) {
+ /* first see if we can even use padding */
+ if(iterator->is_last) {
+ use_padding = false;
+ }
+ else {
+ simple_iterator_push_(iterator);
+ if(!FLAC__metadata_simple_iterator_next(iterator)) {
+ (void)simple_iterator_pop_(iterator);
+ return false;
+ }
+ if(iterator->type != FLAC__METADATA_TYPE_PADDING) {
+ use_padding = false;
+ }
+ else {
+ if(iterator->length == block->length) {
+ padding_leftover = 0;
+ block->is_last = iterator->is_last;
+ }
+ else if(iterator->length < FLAC__STREAM_METADATA_HEADER_LENGTH + block->length)
+ use_padding = false;
+ else {
+ padding_leftover = iterator->length - block->length;
+ padding_is_last = iterator->is_last;
+ block->is_last = false;
+ }
+ }
+ if(!simple_iterator_pop_(iterator))
+ return false;
+ }
+ }
+ if(use_padding) {
+ /* move to the next block, which is suitable padding */
+ if(!FLAC__metadata_simple_iterator_next(iterator))
+ return false;
+ if(padding_leftover == 0) {
+ ret = write_metadata_block_stationary_(iterator, block);
+ return ret;
+ }
+ else {
+ ret = write_metadata_block_stationary_with_padding_(iterator, block, padding_leftover - FLAC__STREAM_METADATA_HEADER_LENGTH, padding_is_last);
+ return ret;
+ }
+ }
+ else {
+ ret = rewrite_whole_file_(iterator, block, /*append=*/true);
+ return ret;
+ }
+}
+
+FLAC_API FLAC__bool FLAC__metadata_simple_iterator_delete_block(FLAC__Metadata_SimpleIterator *iterator, FLAC__bool use_padding)
+{
+ FLAC__bool ret;
+
+ if(!iterator->is_writable) {
+ iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_WRITABLE;
+ return false;
+ }
+
+ if(iterator->type == FLAC__METADATA_TYPE_STREAMINFO) {
+ iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT;
+ return false;
+ }
+
+ if(use_padding) {
+ FLAC__StreamMetadata *padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING);
+ if(0 == padding) {
+ iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
+ return false;
+ }
+ padding->length = iterator->length;
+ if(!FLAC__metadata_simple_iterator_set_block(iterator, padding, false)) {
+ FLAC__metadata_object_delete(padding);
+ return false;
+ }
+ FLAC__metadata_object_delete(padding);
+ if(!FLAC__metadata_simple_iterator_prev(iterator))
+ return false;
+ return true;
+ }
+ else {
+ ret = rewrite_whole_file_(iterator, 0, /*append=*/false);
+ return ret;
+ }
+}
+
+
+
+/****************************************************************************
+ *
+ * Level 2 implementation
+ *
+ ***************************************************************************/
+
+
+typedef struct FLAC__Metadata_Node {
+ FLAC__StreamMetadata *data;
+ struct FLAC__Metadata_Node *prev, *next;
+} FLAC__Metadata_Node;
+
+struct FLAC__Metadata_Chain {
+ char *filename; /* will be NULL if using callbacks */
+ FLAC__bool is_ogg;
+ FLAC__Metadata_Node *head;
+ FLAC__Metadata_Node *tail;
+ uint32_t nodes;
+ FLAC__Metadata_ChainStatus status;
+ FLAC__off_t first_offset, last_offset;
+ /*
+ * This is the length of the chain initially read from the FLAC file.
+ * it is used to compare against the current length to decide whether
+ * or not the whole file has to be rewritten.
+ */
+ FLAC__off_t initial_length;
+ /* @@@ hacky, these are currently only needed by ogg reader */
+ FLAC__IOHandle handle;
+ FLAC__IOCallback_Read read_cb;
+};
+
+struct FLAC__Metadata_Iterator {
+ FLAC__Metadata_Chain *chain;
+ FLAC__Metadata_Node *current;
+};
+
+FLAC_API const char * const FLAC__Metadata_ChainStatusString[] = {
+ "FLAC__METADATA_CHAIN_STATUS_OK",
+ "FLAC__METADATA_CHAIN_STATUS_ILLEGAL_INPUT",
+ "FLAC__METADATA_CHAIN_STATUS_ERROR_OPENING_FILE",
+ "FLAC__METADATA_CHAIN_STATUS_NOT_A_FLAC_FILE",
+ "FLAC__METADATA_CHAIN_STATUS_NOT_WRITABLE",
+ "FLAC__METADATA_CHAIN_STATUS_BAD_METADATA",
+ "FLAC__METADATA_CHAIN_STATUS_READ_ERROR",
+ "FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR",
+ "FLAC__METADATA_CHAIN_STATUS_WRITE_ERROR",
+ "FLAC__METADATA_CHAIN_STATUS_RENAME_ERROR",
+ "FLAC__METADATA_CHAIN_STATUS_UNLINK_ERROR",
+ "FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR",
+ "FLAC__METADATA_CHAIN_STATUS_INTERNAL_ERROR",
+ "FLAC__METADATA_CHAIN_STATUS_INVALID_CALLBACKS",
+ "FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH",
+ "FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL"
+};
+
+
+static FLAC__Metadata_Node *node_new_(void)
+{
+ return calloc(1, sizeof(FLAC__Metadata_Node));
+}
+
+static void node_delete_(FLAC__Metadata_Node *node)
+{
+ if(0 != node->data)
+ FLAC__metadata_object_delete(node->data);
+ free(node);
+}
+
+static void chain_init_(FLAC__Metadata_Chain *chain)
+{
+ chain->filename = 0;
+ chain->is_ogg = false;
+ chain->head = chain->tail = 0;
+ chain->nodes = 0;
+ chain->status = FLAC__METADATA_CHAIN_STATUS_OK;
+ chain->initial_length = 0;
+ chain->read_cb = 0;
+}
+
+static void chain_clear_(FLAC__Metadata_Chain *chain)
+{
+ FLAC__Metadata_Node *node, *next;
+
+ for(node = chain->head; node; ) {
+ next = node->next;
+ node_delete_(node);
+ node = next;
+ }
+
+ if(0 != chain->filename)
+ free(chain->filename);
+
+ chain_init_(chain);
+}
+
+static void chain_append_node_(FLAC__Metadata_Chain *chain, FLAC__Metadata_Node *node)
+{
+ node->next = node->prev = 0;
+ node->data->is_last = true;
+ if(0 != chain->tail)
+ chain->tail->data->is_last = false;
+
+ if(0 == chain->head)
+ chain->head = node;
+ else {
+ chain->tail->next = node;
+ node->prev = chain->tail;
+ }
+ chain->tail = node;
+ chain->nodes++;
+}
+
+static void chain_remove_node_(FLAC__Metadata_Chain *chain, FLAC__Metadata_Node *node)
+{
+ if(node == chain->head)
+ chain->head = node->next;
+ else
+ node->prev->next = node->next;
+
+ if(node == chain->tail)
+ chain->tail = node->prev;
+ else
+ node->next->prev = node->prev;
+
+ if(0 != chain->tail)
+ chain->tail->data->is_last = true;
+
+ chain->nodes--;
+}
+
+static void chain_delete_node_(FLAC__Metadata_Chain *chain, FLAC__Metadata_Node *node)
+{
+ chain_remove_node_(chain, node);
+ node_delete_(node);
+}
+
+static FLAC__off_t chain_calculate_length_(FLAC__Metadata_Chain *chain)
+{
+ const FLAC__Metadata_Node *node;
+ FLAC__off_t length = 0;
+ for(node = chain->head; node; node = node->next)
+ length += (FLAC__STREAM_METADATA_HEADER_LENGTH + node->data->length);
+ return length;
+}
+
+static void iterator_insert_node_(FLAC__Metadata_Iterator *iterator, FLAC__Metadata_Node *node)
+{
+ node->data->is_last = false;
+
+ node->prev = iterator->current->prev;
+ node->next = iterator->current;
+
+ if(0 == node->prev)
+ iterator->chain->head = node;
+ else
+ node->prev->next = node;
+
+ iterator->current->prev = node;
+
+ iterator->chain->nodes++;
+}
+
+static void iterator_insert_node_after_(FLAC__Metadata_Iterator *iterator, FLAC__Metadata_Node *node)
+{
+ iterator->current->data->is_last = false;
+
+ node->prev = iterator->current;
+ node->next = iterator->current->next;
+
+ if(0 == node->next)
+ iterator->chain->tail = node;
+ else
+ node->next->prev = node;
+
+ node->prev->next = node;
+
+ iterator->chain->tail->data->is_last = true;
+
+ iterator->chain->nodes++;
+}
+
+/* return true iff node and node->next are both padding */
+static FLAC__bool chain_merge_adjacent_padding_(FLAC__Metadata_Chain *chain, FLAC__Metadata_Node *node)
+{
+ if(node->data->type == FLAC__METADATA_TYPE_PADDING && 0 != node->next && node->next->data->type == FLAC__METADATA_TYPE_PADDING) {
+ const uint32_t growth = FLAC__STREAM_METADATA_HEADER_LENGTH + node->next->data->length;
+ node->data->length += growth; /* new block size can be greater than max metadata block size, but it'll be fixed later in chain_prepare_for_write_() */
+
+ chain_delete_node_(chain, node->next);
+ return true;
+ }
+ else
+ return false;
+}
+
+/* Returns the new length of the chain, or 0 if there was an error. */
+/* WATCHOUT: This can get called multiple times before a write, so
+ * it should still work when this happens.
+ */
+/* WATCHOUT: Make sure to also update the logic in
+ * FLAC__metadata_chain_check_if_tempfile_needed() if the logic here changes.
+ */
+static FLAC__off_t chain_prepare_for_write_(FLAC__Metadata_Chain *chain, FLAC__bool use_padding)
+{
+ FLAC__off_t current_length = chain_calculate_length_(chain);
+
+ if(use_padding) {
+ /* if the metadata shrank and the last block is padding, we just extend the last padding block */
+ if(current_length < chain->initial_length && chain->tail->data->type == FLAC__METADATA_TYPE_PADDING) {
+ const FLAC__off_t delta = chain->initial_length - current_length;
+ chain->tail->data->length += (uint32_t)delta;
+ current_length += delta;
+ }
+ /* if the metadata shrank more than 4 bytes then there's room to add another padding block */
+ else if(current_length + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH <= chain->initial_length) {
+ FLAC__StreamMetadata *padding;
+ FLAC__Metadata_Node *node;
+ if(0 == (padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING))) {
+ chain->status = FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR;
+ return 0;
+ }
+ padding->length = (uint32_t)(chain->initial_length - (FLAC__STREAM_METADATA_HEADER_LENGTH + current_length));
+ if(0 == (node = node_new_())) {
+ FLAC__metadata_object_delete(padding);
+ chain->status = FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR;
+ return 0;
+ }
+ node->data = padding;
+ chain_append_node_(chain, node);
+ current_length = chain_calculate_length_(chain);
+ }
+ /* if the metadata grew but the last block is padding, try cutting the padding to restore the original length so we don't have to rewrite the whole file */
+ else if(current_length > chain->initial_length) {
+ const FLAC__off_t delta = current_length - chain->initial_length;
+ if(chain->tail->data->type == FLAC__METADATA_TYPE_PADDING) {
+ /* if the delta is exactly the size of the last padding block, remove the padding block */
+ if((FLAC__off_t)chain->tail->data->length + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH == delta) {
+ chain_delete_node_(chain, chain->tail);
+ current_length = chain_calculate_length_(chain);
+ }
+ /* if there is at least 'delta' bytes of padding, trim the padding down */
+ else if((FLAC__off_t)chain->tail->data->length >= delta) {
+ chain->tail->data->length -= (uint32_t)delta;
+ current_length -= delta;
+ }
+ }
+ }
+ }
+
+ /* check sizes of all metadata blocks; reduce padding size if necessary */
+ {
+ FLAC__Metadata_Node *node;
+ for (node = chain->head; node; node = node->next) {
+ if(node->data->length >= (1u << FLAC__STREAM_METADATA_LENGTH_LEN)) {
+ if(node->data->type == FLAC__METADATA_TYPE_PADDING) {
+ node->data->length = (1u << FLAC__STREAM_METADATA_LENGTH_LEN) - 1;
+ current_length = chain_calculate_length_(chain);
+ } else {
+ chain->status = FLAC__METADATA_CHAIN_STATUS_BAD_METADATA;
+ return 0;
+ }
+ }
+ }
+ }
+
+ return current_length;
+}
+
+static FLAC__bool chain_read_cb_(FLAC__Metadata_Chain *chain, FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Seek seek_cb, FLAC__IOCallback_Tell tell_cb)
+{
+ FLAC__Metadata_Node *node;
+
+ /* we assume we're already at the beginning of the file */
+
+ switch(seek_to_first_metadata_block_cb_(handle, read_cb, seek_cb)) {
+ case 0:
+ break;
+ case 1:
+ chain->status = FLAC__METADATA_CHAIN_STATUS_READ_ERROR;
+ return false;
+ case 2:
+ chain->status = FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR;
+ return false;
+ case 3:
+ chain->status = FLAC__METADATA_CHAIN_STATUS_NOT_A_FLAC_FILE;
+ return false;
+ default:
+ return false;
+ }
+
+ {
+ FLAC__int64 pos = tell_cb(handle);
+ if(pos < 0) {
+ chain->status = FLAC__METADATA_CHAIN_STATUS_READ_ERROR;
+ return false;
+ }
+ chain->first_offset = (FLAC__off_t)pos;
+ }
+
+ {
+ FLAC__bool is_last;
+ FLAC__MetadataType type;
+ uint32_t length;
+
+ do {
+ node = node_new_();
+ if(0 == node) {
+ chain->status = FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR;
+ return false;
+ }
+
+ if(!read_metadata_block_header_cb_(handle, read_cb, &is_last, &type, &length)) {
+ node_delete_(node);
+ chain->status = FLAC__METADATA_CHAIN_STATUS_READ_ERROR;
+ return false;
+ }
+
+ node->data = FLAC__metadata_object_new(type);
+ if(0 == node->data) {
+ node_delete_(node);
+ chain->status = FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR;
+ return false;
+ }
+
+ node->data->is_last = is_last;
+ node->data->length = length;
+
+ chain->status = get_equivalent_status_(read_metadata_block_data_cb_(handle, read_cb, seek_cb, node->data));
+ if(chain->status != FLAC__METADATA_CHAIN_STATUS_OK) {
+ node_delete_(node);
+ return false;
+ }
+ chain_append_node_(chain, node);
+ } while(!is_last);
+ }
+
+ {
+ FLAC__int64 pos = tell_cb(handle);
+ if(pos < 0) {
+ chain->status = FLAC__METADATA_CHAIN_STATUS_READ_ERROR;
+ return false;
+ }
+ chain->last_offset = (FLAC__off_t)pos;
+ }
+
+ chain->initial_length = chain_calculate_length_(chain);
+
+ return true;
+}
+
+static FLAC__StreamDecoderReadStatus chain_read_ogg_read_cb_(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data)
+{
+ FLAC__Metadata_Chain *chain = (FLAC__Metadata_Chain*)client_data;
+ (void)decoder;
+ if(*bytes > 0 && chain->status == FLAC__METADATA_CHAIN_STATUS_OK) {
+ *bytes = chain->read_cb(buffer, sizeof(FLAC__byte), *bytes, chain->handle);
+ if(*bytes == 0)
+ return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
+ else
+ return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
+ }
+ else
+ return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
+}
+
+static FLAC__StreamDecoderWriteStatus chain_read_ogg_write_cb_(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data)
+{
+ (void)decoder, (void)frame, (void)buffer, (void)client_data;
+ return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+}
+
+static void chain_read_ogg_metadata_cb_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data)
+{
+ FLAC__Metadata_Chain *chain = (FLAC__Metadata_Chain*)client_data;
+ FLAC__Metadata_Node *node;
+
+ (void)decoder;
+
+ node = node_new_();
+ if(0 == node) {
+ chain->status = FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+
+ node->data = FLAC__metadata_object_clone(metadata);
+ if(0 == node->data) {
+ node_delete_(node);
+ chain->status = FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+
+ chain_append_node_(chain, node);
+}
+
+static void chain_read_ogg_error_cb_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
+{
+ FLAC__Metadata_Chain *chain = (FLAC__Metadata_Chain*)client_data;
+ (void)decoder, (void)status;
+ chain->status = FLAC__METADATA_CHAIN_STATUS_INTERNAL_ERROR; /*@@@ maybe needs better error code */
+}
+
+static FLAC__bool chain_read_ogg_cb_(FLAC__Metadata_Chain *chain, FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb)
+{
+ FLAC__StreamDecoder *decoder;
+
+ /* we assume we're already at the beginning of the file */
+
+ chain->handle = handle;
+ chain->read_cb = read_cb;
+ if(0 == (decoder = FLAC__stream_decoder_new())) {
+ chain->status = FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR;
+ return false;
+ }
+ FLAC__stream_decoder_set_metadata_respond_all(decoder);
+ if(FLAC__stream_decoder_init_ogg_stream(decoder, chain_read_ogg_read_cb_, /*seek_callback=*/0, /*tell_callback=*/0, /*length_callback=*/0, /*eof_callback=*/0, chain_read_ogg_write_cb_, chain_read_ogg_metadata_cb_, chain_read_ogg_error_cb_, chain) != FLAC__STREAM_DECODER_INIT_STATUS_OK) {
+ FLAC__stream_decoder_delete(decoder);
+ chain->status = FLAC__METADATA_CHAIN_STATUS_INTERNAL_ERROR; /*@@@ maybe needs better error code */
+ return false;
+ }
+
+ chain->first_offset = 0; /*@@@ wrong; will need to be set correctly to implement metadata writing for Ogg FLAC */
+
+ if(!FLAC__stream_decoder_process_until_end_of_metadata(decoder))
+ chain->status = FLAC__METADATA_CHAIN_STATUS_INTERNAL_ERROR; /*@@@ maybe needs better error code */
+ if(chain->status != FLAC__METADATA_CHAIN_STATUS_OK) {
+ FLAC__stream_decoder_delete(decoder);
+ return false;
+ }
+
+ FLAC__stream_decoder_delete(decoder);
+
+ chain->last_offset = 0; /*@@@ wrong; will need to be set correctly to implement metadata writing for Ogg FLAC */
+
+ chain->initial_length = chain_calculate_length_(chain);
+
+ return true;
+}
+
+static FLAC__bool chain_rewrite_metadata_in_place_cb_(FLAC__Metadata_Chain *chain, FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, FLAC__IOCallback_Seek seek_cb)
+{
+ FLAC__Metadata_Node *node;
+
+ if(0 != seek_cb(handle, chain->first_offset, SEEK_SET)) {
+ chain->status = FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR;
+ return false;
+ }
+
+ for(node = chain->head; node; node = node->next) {
+ if(!write_metadata_block_header_cb_(handle, write_cb, node->data)) {
+ chain->status = FLAC__METADATA_CHAIN_STATUS_WRITE_ERROR;
+ return false;
+ }
+ if(!write_metadata_block_data_cb_(handle, write_cb, node->data)) {
+ chain->status = FLAC__METADATA_CHAIN_STATUS_WRITE_ERROR;
+ return false;
+ }
+ }
+
+ chain->status = FLAC__METADATA_CHAIN_STATUS_OK;
+ return true;
+}
+
+static FLAC__bool chain_rewrite_metadata_in_place_(FLAC__Metadata_Chain *chain)
+{
+ FILE *file;
+ FLAC__bool ret;
+
+ if(0 == (file = flac_fopen(chain->filename, "r+b"))) {
+ chain->status = FLAC__METADATA_CHAIN_STATUS_ERROR_OPENING_FILE;
+ return false;
+ }
+
+ /* chain_rewrite_metadata_in_place_cb_() sets chain->status for us */
+ ret = chain_rewrite_metadata_in_place_cb_(chain, (FLAC__IOHandle)file, (FLAC__IOCallback_Write)fwrite, fseek_wrapper_);
+
+ fclose(file);
+
+ return ret;
+}
+
+static FLAC__bool chain_rewrite_file_(FLAC__Metadata_Chain *chain, const char *tempfile_path_prefix)
+{
+ FILE *f, *tempfile = NULL;
+ char *tempfilename;
+ FLAC__Metadata_SimpleIteratorStatus status;
+ const FLAC__Metadata_Node *node;
+
+ /* copy the file prefix (data up to first metadata block */
+ if(0 == (f = flac_fopen(chain->filename, "rb"))) {
+ chain->status = FLAC__METADATA_CHAIN_STATUS_ERROR_OPENING_FILE;
+ return false;
+ }
+ if(!open_tempfile_(chain->filename, tempfile_path_prefix, &tempfile, &tempfilename, &status)) {
+ chain->status = get_equivalent_status_(status);
+ goto err;
+ }
+ if(!copy_n_bytes_from_file_(f, tempfile, chain->first_offset, &status)) {
+ chain->status = get_equivalent_status_(status);
+ goto err;
+ }
+
+ /* write the metadata */
+ for(node = chain->head; node; node = node->next) {
+ if(!write_metadata_block_header_(tempfile, &status, node->data)) {
+ chain->status = get_equivalent_status_(status);
+ goto err;
+ }
+ if(!write_metadata_block_data_(tempfile, &status, node->data)) {
+ chain->status = get_equivalent_status_(status);
+ goto err;
+ }
+ }
+ /*FLAC__ASSERT(fflush(), ftello() == chain->last_offset);*/
+
+ /* copy the file postfix (everything after the metadata) */
+ if(0 != fseeko(f, chain->last_offset, SEEK_SET)) {
+ chain->status = FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR;
+ goto err;
+ }
+ if(!copy_remaining_bytes_from_file_(f, tempfile, &status)) {
+ chain->status = get_equivalent_status_(status);
+ goto err;
+ }
+
+ /* move the tempfile on top of the original */
+ (void)fclose(f);
+ if(!transport_tempfile_(chain->filename, &tempfile, &tempfilename, &status))
+ return false;
+
+ return true;
+
+err:
+ (void)fclose(f);
+ cleanup_tempfile_(&tempfile, &tempfilename);
+ return false;
+}
+
+/* assumes 'handle' is already at beginning of file */
+static FLAC__bool chain_rewrite_file_cb_(FLAC__Metadata_Chain *chain, FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Seek seek_cb, FLAC__IOCallback_Eof eof_cb, FLAC__IOHandle temp_handle, FLAC__IOCallback_Write temp_write_cb)
+{
+ FLAC__Metadata_SimpleIteratorStatus status;
+ const FLAC__Metadata_Node *node;
+
+ /* copy the file prefix (data up to first metadata block */
+ if(!copy_n_bytes_from_file_cb_(handle, read_cb, temp_handle, temp_write_cb, chain->first_offset, &status)) {
+ chain->status = get_equivalent_status_(status);
+ return false;
+ }
+
+ /* write the metadata */
+ for(node = chain->head; node; node = node->next) {
+ if(!write_metadata_block_header_cb_(temp_handle, temp_write_cb, node->data)) {
+ chain->status = FLAC__METADATA_CHAIN_STATUS_WRITE_ERROR;
+ return false;
+ }
+ if(!write_metadata_block_data_cb_(temp_handle, temp_write_cb, node->data)) {
+ chain->status = FLAC__METADATA_CHAIN_STATUS_WRITE_ERROR;
+ return false;
+ }
+ }
+
+ /* copy the file postfix (everything after the metadata) */
+ if(0 != seek_cb(handle, chain->last_offset, SEEK_SET)) {
+ chain->status = FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR;
+ return false;
+ }
+ if(!copy_remaining_bytes_from_file_cb_(handle, read_cb, eof_cb, temp_handle, temp_write_cb, &status)) {
+ chain->status = get_equivalent_status_(status);
+ return false;
+ }
+
+ return true;
+}
+
+FLAC_API FLAC__Metadata_Chain *FLAC__metadata_chain_new(void)
+{
+ FLAC__Metadata_Chain *chain = calloc(1, sizeof(FLAC__Metadata_Chain));
+
+ if(0 != chain)
+ chain_init_(chain);
+
+ return chain;
+}
+
+FLAC_API void FLAC__metadata_chain_delete(FLAC__Metadata_Chain *chain)
+{
+ chain_clear_(chain);
+
+ free(chain);
+}
+
+FLAC_API FLAC__Metadata_ChainStatus FLAC__metadata_chain_status(FLAC__Metadata_Chain *chain)
+{
+ FLAC__Metadata_ChainStatus status;
+
+ status = chain->status;
+ chain->status = FLAC__METADATA_CHAIN_STATUS_OK;
+ return status;
+}
+
+static FLAC__bool chain_read_(FLAC__Metadata_Chain *chain, const char *filename, FLAC__bool is_ogg)
+{
+ FILE *file;
+ FLAC__bool ret;
+
+ chain_clear_(chain);
+
+ if(0 == (chain->filename = strdup(filename))) {
+ chain->status = FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR;
+ return false;
+ }
+
+ chain->is_ogg = is_ogg;
+
+ if(0 == (file = flac_fopen(filename, "rb"))) {
+ chain->status = FLAC__METADATA_CHAIN_STATUS_ERROR_OPENING_FILE;
+ return false;
+ }
+
+ /* the function also sets chain->status for us */
+ ret = is_ogg?
+ chain_read_ogg_cb_(chain, file, (FLAC__IOCallback_Read)fread) :
+ chain_read_cb_(chain, file, (FLAC__IOCallback_Read)fread, fseek_wrapper_, ftell_wrapper_)
+ ;
+
+ fclose(file);
+
+ return ret;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_chain_read(FLAC__Metadata_Chain *chain, const char *filename)
+{
+ return chain_read_(chain, filename, /*is_ogg=*/false);
+}
+
+/*@@@@add to tests*/
+FLAC_API FLAC__bool FLAC__metadata_chain_read_ogg(FLAC__Metadata_Chain *chain, const char *filename)
+{
+ return chain_read_(chain, filename, /*is_ogg=*/true);
+}
+
+static FLAC__bool chain_read_with_callbacks_(FLAC__Metadata_Chain *chain, FLAC__IOHandle handle, FLAC__IOCallbacks callbacks, FLAC__bool is_ogg)
+{
+ FLAC__bool ret;
+
+ chain_clear_(chain);
+
+ if (0 == callbacks.read || 0 == callbacks.seek || 0 == callbacks.tell) {
+ chain->status = FLAC__METADATA_CHAIN_STATUS_INVALID_CALLBACKS;
+ return false;
+ }
+
+ chain->is_ogg = is_ogg;
+
+ /* rewind */
+ if(0 != callbacks.seek(handle, 0, SEEK_SET)) {
+ chain->status = FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR;
+ return false;
+ }
+
+ /* the function also sets chain->status for us */
+ ret = is_ogg?
+ chain_read_ogg_cb_(chain, handle, callbacks.read) :
+ chain_read_cb_(chain, handle, callbacks.read, callbacks.seek, callbacks.tell)
+ ;
+
+ return ret;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_chain_read_with_callbacks(FLAC__Metadata_Chain *chain, FLAC__IOHandle handle, FLAC__IOCallbacks callbacks)
+{
+ return chain_read_with_callbacks_(chain, handle, callbacks, /*is_ogg=*/false);
+}
+
+/*@@@@add to tests*/
+FLAC_API FLAC__bool FLAC__metadata_chain_read_ogg_with_callbacks(FLAC__Metadata_Chain *chain, FLAC__IOHandle handle, FLAC__IOCallbacks callbacks)
+{
+ return chain_read_with_callbacks_(chain, handle, callbacks, /*is_ogg=*/true);
+}
+
+typedef enum {
+ LBS_NONE = 0,
+ LBS_SIZE_CHANGED,
+ LBS_BLOCK_ADDED,
+ LBS_BLOCK_REMOVED
+} LastBlockState;
+
+FLAC_API FLAC__bool FLAC__metadata_chain_check_if_tempfile_needed(FLAC__Metadata_Chain *chain, FLAC__bool use_padding)
+{
+ /* This does all the same checks that are in chain_prepare_for_write_()
+ * but doesn't actually alter the chain. Make sure to update the logic
+ * here if chain_prepare_for_write_() changes.
+ */
+ FLAC__off_t current_length;
+ LastBlockState lbs_state = LBS_NONE;
+ uint32_t lbs_size = 0;
+
+ current_length = chain_calculate_length_(chain);
+
+ if(use_padding) {
+ const FLAC__Metadata_Node * const node = chain->tail;
+ /* if the metadata shrank and the last block is padding, we just extend the last padding block */
+ if(current_length < chain->initial_length && node->data->type == FLAC__METADATA_TYPE_PADDING) {
+ lbs_state = LBS_SIZE_CHANGED;
+ lbs_size = (uint32_t)(node->data->length + (chain->initial_length - current_length));
+ }
+ /* if the metadata shrank more than 4 bytes then there's room to add another padding block */
+ else if(current_length + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH <= chain->initial_length) {
+ lbs_state = LBS_BLOCK_ADDED;
+ lbs_size = (uint32_t)(chain->initial_length - (current_length + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH));
+ }
+ /* if the metadata grew but the last block is padding, try cutting the padding to restore the original length so we don't have to rewrite the whole file */
+ else if(current_length > chain->initial_length) {
+ const FLAC__off_t delta = current_length - chain->initial_length;
+ if(node->data->type == FLAC__METADATA_TYPE_PADDING) {
+ /* if the delta is exactly the size of the last padding block, remove the padding block */
+ if((FLAC__off_t)node->data->length + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH == delta) {
+ lbs_state = LBS_BLOCK_REMOVED;
+ lbs_size = 0;
+ }
+ /* if there is at least 'delta' bytes of padding, trim the padding down */
+ else if((FLAC__off_t)node->data->length >= delta) {
+ lbs_state = LBS_SIZE_CHANGED;
+ lbs_size = (uint32_t)(node->data->length - delta);
+ }
+ }
+ }
+ }
+
+ current_length = 0;
+ /* check sizes of all metadata blocks; reduce padding size if necessary */
+ {
+ const FLAC__Metadata_Node *node;
+ for(node = chain->head; node; node = node->next) {
+ uint32_t block_len = node->data->length;
+ if(node == chain->tail) {
+ if(lbs_state == LBS_BLOCK_REMOVED)
+ continue;
+ else if(lbs_state == LBS_SIZE_CHANGED)
+ block_len = lbs_size;
+ }
+ if(block_len >= (1u << FLAC__STREAM_METADATA_LENGTH_LEN)) {
+ if(node->data->type == FLAC__METADATA_TYPE_PADDING)
+ block_len = (1u << FLAC__STREAM_METADATA_LENGTH_LEN) - 1;
+ else
+ return false /* the return value doesn't matter */;
+ }
+ current_length += (FLAC__STREAM_METADATA_HEADER_LENGTH + block_len);
+ }
+
+ if(lbs_state == LBS_BLOCK_ADDED) {
+ /* test added padding block */
+ uint32_t block_len = lbs_size;
+ if(block_len >= (1u << FLAC__STREAM_METADATA_LENGTH_LEN))
+ block_len = (1u << FLAC__STREAM_METADATA_LENGTH_LEN) - 1;
+ current_length += (FLAC__STREAM_METADATA_HEADER_LENGTH + block_len);
+ }
+ }
+
+ return (current_length != chain->initial_length);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_chain_write(FLAC__Metadata_Chain *chain, FLAC__bool use_padding, FLAC__bool preserve_file_stats)
+{
+ struct flac_stat_s stats;
+ const char *tempfile_path_prefix = 0;
+ FLAC__off_t current_length;
+
+ if (chain->is_ogg) { /* cannot write back to Ogg FLAC yet */
+ chain->status = FLAC__METADATA_CHAIN_STATUS_INTERNAL_ERROR;
+ return false;
+ }
+
+ if (0 == chain->filename) {
+ chain->status = FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH;
+ return false;
+ }
+
+ current_length = chain_prepare_for_write_(chain, use_padding);
+
+ /* a return value of 0 means there was an error; chain->status is already set */
+ if (0 == current_length)
+ return false;
+
+ if(preserve_file_stats)
+ get_file_stats_(chain->filename, &stats);
+
+ if(current_length == chain->initial_length) {
+ if(!chain_rewrite_metadata_in_place_(chain))
+ return false;
+ }
+ else {
+ if(!chain_rewrite_file_(chain, tempfile_path_prefix))
+ return false;
+
+ /* recompute lengths and offsets */
+ {
+ const FLAC__Metadata_Node *node;
+ chain->initial_length = current_length;
+ chain->last_offset = chain->first_offset;
+ for(node = chain->head; node; node = node->next)
+ chain->last_offset += (FLAC__STREAM_METADATA_HEADER_LENGTH + node->data->length);
+ }
+ }
+
+ if(preserve_file_stats)
+ set_file_stats_(chain->filename, &stats);
+
+ return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_chain_write_with_callbacks(FLAC__Metadata_Chain *chain, FLAC__bool use_padding, FLAC__IOHandle handle, FLAC__IOCallbacks callbacks)
+{
+ FLAC__off_t current_length;
+
+ if (chain->is_ogg) { /* cannot write back to Ogg FLAC yet */
+ chain->status = FLAC__METADATA_CHAIN_STATUS_INTERNAL_ERROR;
+ return false;
+ }
+
+ if (0 != chain->filename) {
+ chain->status = FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH;
+ return false;
+ }
+
+ if (0 == callbacks.write || 0 == callbacks.seek) {
+ chain->status = FLAC__METADATA_CHAIN_STATUS_INVALID_CALLBACKS;
+ return false;
+ }
+
+ if (FLAC__metadata_chain_check_if_tempfile_needed(chain, use_padding)) {
+ chain->status = FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL;
+ return false;
+ }
+
+ current_length = chain_prepare_for_write_(chain, use_padding);
+
+ /* a return value of 0 means there was an error; chain->status is already set */
+ if (0 == current_length)
+ return false;
+
+ return chain_rewrite_metadata_in_place_cb_(chain, handle, callbacks.write, callbacks.seek);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_chain_write_with_callbacks_and_tempfile(FLAC__Metadata_Chain *chain, FLAC__bool use_padding, FLAC__IOHandle handle, FLAC__IOCallbacks callbacks, FLAC__IOHandle temp_handle, FLAC__IOCallbacks temp_callbacks)
+{
+ FLAC__off_t current_length;
+
+ if (chain->is_ogg) { /* cannot write back to Ogg FLAC yet */
+ chain->status = FLAC__METADATA_CHAIN_STATUS_INTERNAL_ERROR;
+ return false;
+ }
+
+ if (0 != chain->filename) {
+ chain->status = FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH;
+ return false;
+ }
+
+ if (0 == callbacks.read || 0 == callbacks.seek || 0 == callbacks.eof) {
+ chain->status = FLAC__METADATA_CHAIN_STATUS_INVALID_CALLBACKS;
+ return false;
+ }
+ if (0 == temp_callbacks.write) {
+ chain->status = FLAC__METADATA_CHAIN_STATUS_INVALID_CALLBACKS;
+ return false;
+ }
+
+ if (!FLAC__metadata_chain_check_if_tempfile_needed(chain, use_padding)) {
+ chain->status = FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL;
+ return false;
+ }
+
+ current_length = chain_prepare_for_write_(chain, use_padding);
+
+ /* a return value of 0 means there was an error; chain->status is already set */
+ if (0 == current_length)
+ return false;
+
+ /* rewind */
+ if(0 != callbacks.seek(handle, 0, SEEK_SET)) {
+ chain->status = FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR;
+ return false;
+ }
+
+ if(!chain_rewrite_file_cb_(chain, handle, callbacks.read, callbacks.seek, callbacks.eof, temp_handle, temp_callbacks.write))
+ return false;
+
+ /* recompute lengths and offsets */
+ {
+ const FLAC__Metadata_Node *node;
+ chain->initial_length = current_length;
+ chain->last_offset = chain->first_offset;
+ for(node = chain->head; node; node = node->next)
+ chain->last_offset += (FLAC__STREAM_METADATA_HEADER_LENGTH + node->data->length);
+ }
+
+ return true;
+}
+
+FLAC_API void FLAC__metadata_chain_merge_padding(FLAC__Metadata_Chain *chain)
+{
+ FLAC__Metadata_Node *node;
+
+ for(node = chain->head; node; ) {
+ if(!chain_merge_adjacent_padding_(chain, node))
+ node = node->next;
+ }
+}
+
+FLAC_API void FLAC__metadata_chain_sort_padding(FLAC__Metadata_Chain *chain)
+{
+ FLAC__Metadata_Node *node, *save;
+ uint32_t i;
+
+ /*
+ * Don't try and be too smart... this simple algo is good enough for
+ * the small number of nodes that we deal with.
+ */
+ for(i = 0, node = chain->head; i < chain->nodes; i++) {
+ if(node->data->type == FLAC__METADATA_TYPE_PADDING) {
+ save = node->next;
+ chain_remove_node_(chain, node);
+ chain_append_node_(chain, node);
+ node = save;
+ }
+ else {
+ node = node->next;
+ }
+ }
+
+ FLAC__metadata_chain_merge_padding(chain);
+}
+
+
+FLAC_API FLAC__Metadata_Iterator *FLAC__metadata_iterator_new(void)
+{
+ FLAC__Metadata_Iterator *iterator = calloc(1, sizeof(FLAC__Metadata_Iterator));
+
+ /* calloc() implies:
+ iterator->current = 0;
+ iterator->chain = 0;
+ */
+
+ return iterator;
+}
+
+FLAC_API void FLAC__metadata_iterator_delete(FLAC__Metadata_Iterator *iterator)
+{
+ free(iterator);
+}
+
+FLAC_API void FLAC__metadata_iterator_init(FLAC__Metadata_Iterator *iterator, FLAC__Metadata_Chain *chain)
+{
+ iterator->chain = chain;
+ iterator->current = chain->head;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_iterator_next(FLAC__Metadata_Iterator *iterator)
+{
+ if(0 == iterator->current || 0 == iterator->current->next)
+ return false;
+
+ iterator->current = iterator->current->next;
+ return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_iterator_prev(FLAC__Metadata_Iterator *iterator)
+{
+ if(0 == iterator->current || 0 == iterator->current->prev)
+ return false;
+
+ iterator->current = iterator->current->prev;
+ return true;
+}
+
+FLAC_API FLAC__MetadataType FLAC__metadata_iterator_get_block_type(const FLAC__Metadata_Iterator *iterator)
+{
+ return iterator->current->data->type;
+}
+
+FLAC_API FLAC__StreamMetadata *FLAC__metadata_iterator_get_block(FLAC__Metadata_Iterator *iterator)
+{
+ return iterator->current->data;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_iterator_set_block(FLAC__Metadata_Iterator *iterator, FLAC__StreamMetadata *block)
+{
+ return FLAC__metadata_iterator_delete_block(iterator, false) && FLAC__metadata_iterator_insert_block_after(iterator, block);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_iterator_delete_block(FLAC__Metadata_Iterator *iterator, FLAC__bool replace_with_padding)
+{
+ FLAC__Metadata_Node *save;
+
+ if(0 == iterator->current->prev) {
+ return false;
+ }
+
+ save = iterator->current->prev;
+
+ if(replace_with_padding) {
+ FLAC__metadata_object_delete_data(iterator->current->data);
+ iterator->current->data->type = FLAC__METADATA_TYPE_PADDING;
+ }
+ else {
+ chain_delete_node_(iterator->chain, iterator->current);
+ }
+
+ iterator->current = save;
+ return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_iterator_insert_block_before(FLAC__Metadata_Iterator *iterator, FLAC__StreamMetadata *block)
+{
+ FLAC__Metadata_Node *node;
+
+ if(block->type == FLAC__METADATA_TYPE_STREAMINFO)
+ return false;
+
+ if(0 == iterator->current->prev) {
+ return false;
+ }
+
+ if(0 == (node = node_new_()))
+ return false;
+
+ node->data = block;
+ iterator_insert_node_(iterator, node);
+ iterator->current = node;
+ return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_iterator_insert_block_after(FLAC__Metadata_Iterator *iterator, FLAC__StreamMetadata *block)
+{
+ FLAC__Metadata_Node *node;
+
+ if(block->type == FLAC__METADATA_TYPE_STREAMINFO)
+ return false;
+
+ if(0 == (node = node_new_()))
+ return false;
+
+ node->data = block;
+ iterator_insert_node_after_(iterator, node);
+ iterator->current = node;
+ return true;
+}
+
+
+/****************************************************************************
+ *
+ * Local function definitions
+ *
+ ***************************************************************************/
+
+void pack_uint32_(FLAC__uint32 val, FLAC__byte *b, uint32_t bytes)
+{
+ uint32_t i;
+
+ b += bytes;
+
+ for(i = 0; i < bytes; i++) {
+ *(--b) = (FLAC__byte)(val & 0xff);
+ val >>= 8;
+ }
+}
+
+void pack_uint32_little_endian_(FLAC__uint32 val, FLAC__byte *b, uint32_t bytes)
+{
+ uint32_t i;
+
+ for(i = 0; i < bytes; i++) {
+ *(b++) = (FLAC__byte)(val & 0xff);
+ val >>= 8;
+ }
+}
+
+void pack_uint64_(FLAC__uint64 val, FLAC__byte *b, uint32_t bytes)
+{
+ uint32_t i;
+
+ b += bytes;
+
+ for(i = 0; i < bytes; i++) {
+ *(--b) = (FLAC__byte)(val & 0xff);
+ val >>= 8;
+ }
+}
+
+FLAC__uint32 unpack_uint32_(FLAC__byte *b, uint32_t bytes)
+{
+ FLAC__uint32 ret = 0;
+ uint32_t i;
+
+ for(i = 0; i < bytes; i++)
+ ret = (ret << 8) | (FLAC__uint32)(*b++);
+
+ return ret;
+}
+
+FLAC__uint32 unpack_uint32_little_endian_(FLAC__byte *b, uint32_t bytes)
+{
+ FLAC__uint32 ret = 0;
+ uint32_t i;
+
+ b += bytes;
+
+ for(i = 0; i < bytes; i++)
+ ret = (ret << 8) | (FLAC__uint32)(*--b);
+
+ return ret;
+}
+
+FLAC__uint64 unpack_uint64_(FLAC__byte *b, uint32_t bytes)
+{
+ FLAC__uint64 ret = 0;
+ uint32_t i;
+
+ for(i = 0; i < bytes; i++)
+ ret = (ret << 8) | (FLAC__uint64)(*b++);
+
+ return ret;
+}
+
+FLAC__bool read_metadata_block_header_(FLAC__Metadata_SimpleIterator *iterator)
+{
+ if(!read_metadata_block_header_cb_((FLAC__IOHandle)iterator->file, (FLAC__IOCallback_Read)fread, &iterator->is_last, &iterator->type, &iterator->length)) {
+ iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+ return false;
+ }
+
+ return true;
+}
+
+FLAC__bool read_metadata_block_data_(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block)
+{
+ iterator->status = read_metadata_block_data_cb_((FLAC__IOHandle)iterator->file, (FLAC__IOCallback_Read)fread, fseek_wrapper_, block);
+
+ return (iterator->status == FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK);
+}
+
+FLAC__bool read_metadata_block_header_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__bool *is_last, FLAC__MetadataType *type, uint32_t *length)
+{
+ FLAC__byte raw_header[FLAC__STREAM_METADATA_HEADER_LENGTH];
+
+ if(read_cb(raw_header, 1, FLAC__STREAM_METADATA_HEADER_LENGTH, handle) != FLAC__STREAM_METADATA_HEADER_LENGTH)
+ return false;
+
+ *is_last = raw_header[0] & 0x80? true : false;
+ *type = (FLAC__MetadataType)(raw_header[0] & 0x7f);
+ *length = unpack_uint32_(raw_header + 1, 3);
+
+ /* Note that we don't check:
+ * if(iterator->type >= FLAC__METADATA_TYPE_UNDEFINED)
+ * we just will read in an opaque block
+ */
+
+ return true;
+}
+
+FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Seek seek_cb, FLAC__StreamMetadata *block)
+{
+ switch(block->type) {
+ case FLAC__METADATA_TYPE_STREAMINFO:
+ return read_metadata_block_data_streaminfo_cb_(handle, read_cb, &block->data.stream_info);
+ case FLAC__METADATA_TYPE_PADDING:
+ return read_metadata_block_data_padding_cb_(handle, seek_cb, &block->data.padding, block->length);
+ case FLAC__METADATA_TYPE_APPLICATION:
+ return read_metadata_block_data_application_cb_(handle, read_cb, &block->data.application, block->length);
+ case FLAC__METADATA_TYPE_SEEKTABLE:
+ return read_metadata_block_data_seektable_cb_(handle, read_cb, &block->data.seek_table, block->length);
+ case FLAC__METADATA_TYPE_VORBIS_COMMENT:
+ return read_metadata_block_data_vorbis_comment_cb_(handle, read_cb, seek_cb, &block->data.vorbis_comment, block->length);
+ case FLAC__METADATA_TYPE_CUESHEET:
+ return read_metadata_block_data_cuesheet_cb_(handle, read_cb, &block->data.cue_sheet);
+ case FLAC__METADATA_TYPE_PICTURE:
+ return read_metadata_block_data_picture_cb_(handle, read_cb, &block->data.picture);
+ default:
+ return read_metadata_block_data_unknown_cb_(handle, read_cb, &block->data.unknown, block->length);
+ }
+}
+
+FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_streaminfo_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_StreamInfo *block)
+{
+ FLAC__byte buffer[FLAC__STREAM_METADATA_STREAMINFO_LENGTH], *b;
+
+ if(read_cb(buffer, 1, FLAC__STREAM_METADATA_STREAMINFO_LENGTH, handle) != FLAC__STREAM_METADATA_STREAMINFO_LENGTH)
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+
+ b = buffer;
+
+ /* we are using hardcoded numbers for simplicity but we should
+ * probably eventually write a bit-level unpacker and use the
+ * _STREAMINFO_ constants.
+ */
+ block->min_blocksize = unpack_uint32_(b, 2); b += 2;
+ block->max_blocksize = unpack_uint32_(b, 2); b += 2;
+ block->min_framesize = unpack_uint32_(b, 3); b += 3;
+ block->max_framesize = unpack_uint32_(b, 3); b += 3;
+ block->sample_rate = (unpack_uint32_(b, 2) << 4) | ((uint32_t)(b[2] & 0xf0) >> 4);
+ block->channels = (uint32_t)((b[2] & 0x0e) >> 1) + 1;
+ block->bits_per_sample = ((((uint32_t)(b[2] & 0x01)) << 4) | (((uint32_t)(b[3] & 0xf0)) >> 4)) + 1;
+ block->total_samples = (((FLAC__uint64)(b[3] & 0x0f)) << 32) | unpack_uint64_(b+4, 4);
+ memcpy(block->md5sum, b+8, 16);
+
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
+}
+
+FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_padding_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Seek seek_cb, FLAC__StreamMetadata_Padding *block, uint32_t block_length)
+{
+ (void)block; /* nothing to do; we don't care about reading the padding bytes */
+
+ if(0 != seek_cb(handle, block_length, SEEK_CUR))
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
+
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
+}
+
+FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_application_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_Application *block, uint32_t block_length)
+{
+ const uint32_t id_bytes = FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8;
+
+ if(read_cb(block->id, 1, id_bytes, handle) != id_bytes)
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+
+ if(block_length < id_bytes)
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+
+ block_length -= id_bytes;
+
+ if(block_length == 0) {
+ block->data = 0;
+ }
+ else {
+ if(0 == (block->data = malloc(block_length)))
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
+
+ if(read_cb(block->data, 1, block_length, handle) != block_length)
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+ }
+
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
+}
+
+FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_seektable_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_SeekTable *block, uint32_t block_length)
+{
+ uint32_t i;
+ FLAC__byte buffer[FLAC__STREAM_METADATA_SEEKPOINT_LENGTH];
+
+ block->num_points = block_length / FLAC__STREAM_METADATA_SEEKPOINT_LENGTH;
+
+ if(block->num_points == 0)
+ block->points = 0;
+ else if(0 == (block->points = safe_malloc_mul_2op_p(block->num_points, /*times*/sizeof(FLAC__StreamMetadata_SeekPoint))))
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
+
+ for(i = 0; i < block->num_points; i++) {
+ if(read_cb(buffer, 1, FLAC__STREAM_METADATA_SEEKPOINT_LENGTH, handle) != FLAC__STREAM_METADATA_SEEKPOINT_LENGTH)
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+ /* some MAGIC NUMBERs here */
+ block->points[i].sample_number = unpack_uint64_(buffer, 8);
+ block->points[i].stream_offset = unpack_uint64_(buffer+8, 8);
+ block->points[i].frame_samples = unpack_uint32_(buffer+16, 2);
+ }
+
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
+}
+
+FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_vorbis_comment_entry_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_VorbisComment_Entry *entry, uint32_t max_length)
+{
+ const uint32_t entry_length_len = FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN / 8;
+ FLAC__byte buffer[4]; /* magic number is asserted below */
+
+ if(max_length < entry_length_len)
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_BAD_METADATA;
+
+ max_length -= entry_length_len;
+ if(read_cb(buffer, 1, entry_length_len, handle) != entry_length_len)
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+ entry->length = unpack_uint32_little_endian_(buffer, entry_length_len);
+ if(max_length < entry->length) {
+ entry->length = 0;
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_BAD_METADATA;
+ } else max_length -= entry->length;
+
+ if(0 != entry->entry)
+ free(entry->entry);
+
+ if(entry->length == 0) {
+ entry->entry = 0;
+ }
+ else {
+ if(0 == (entry->entry = safe_malloc_add_2op_(entry->length, /*+*/1)))
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
+
+ if(read_cb(entry->entry, 1, entry->length, handle) != entry->length)
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+
+ entry->entry[entry->length] = '\0';
+ }
+
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
+}
+
+FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_vorbis_comment_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Seek seek_cb, FLAC__StreamMetadata_VorbisComment *block, uint32_t block_length)
+{
+ uint32_t i;
+ FLAC__Metadata_SimpleIteratorStatus status;
+ const uint32_t num_comments_len = FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN / 8;
+ FLAC__byte buffer[4]; /* magic number is asserted below */
+
+ status = read_metadata_block_data_vorbis_comment_entry_cb_(handle, read_cb, &(block->vendor_string), block_length);
+ if(block_length >= 4)
+ block_length -= 4;
+ if(status == FLAC__METADATA_SIMPLE_ITERATOR_STATUS_BAD_METADATA)
+ goto skip;
+ else if(status != FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK)
+ return status;
+ block_length -= block->vendor_string.length;
+
+ if(block_length < num_comments_len) goto skip; else block_length -= num_comments_len;
+ if(read_cb(buffer, 1, num_comments_len, handle) != num_comments_len)
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+ block->num_comments = unpack_uint32_little_endian_(buffer, num_comments_len);
+
+ if(block->num_comments == 0) {
+ block->comments = 0;
+ }
+ else if(0 == (block->comments = calloc(block->num_comments, sizeof(FLAC__StreamMetadata_VorbisComment_Entry)))) {
+ block->num_comments = 0;
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
+ }
+
+ for(i = 0; i < block->num_comments; i++) {
+ status = read_metadata_block_data_vorbis_comment_entry_cb_(handle, read_cb, block->comments + i, block_length);
+ if(block_length >= 4) block_length -= 4;
+ if(status == FLAC__METADATA_SIMPLE_ITERATOR_STATUS_BAD_METADATA) {
+ block->num_comments = i;
+ goto skip;
+ }
+ else if(status != FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK) return status;
+ block_length -= block->comments[i].length;
+ }
+
+ skip:
+ if(block_length > 0) {
+ /* bad metadata */
+ if(0 != seek_cb(handle, block_length, SEEK_CUR))
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
+ }
+
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
+}
+
+FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_cuesheet_track_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_CueSheet_Track *track)
+{
+ uint32_t i, len;
+ FLAC__byte buffer[32]; /* asserted below that this is big enough */
+
+ len = FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN / 8;
+ if(read_cb(buffer, 1, len, handle) != len)
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+ track->offset = unpack_uint64_(buffer, len);
+
+ len = FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN / 8;
+ if(read_cb(buffer, 1, len, handle) != len)
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+ track->number = (FLAC__byte)unpack_uint32_(buffer, len);
+
+ len = FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN / 8;
+ if(read_cb(track->isrc, 1, len, handle) != len)
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+
+ len = (FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN) / 8;
+ if(read_cb(buffer, 1, len, handle) != len)
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+ track->type = buffer[0] >> 7;
+ track->pre_emphasis = (buffer[0] >> 6) & 1;
+
+ len = FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN / 8;
+ if(read_cb(buffer, 1, len, handle) != len)
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+ track->num_indices = (FLAC__byte)unpack_uint32_(buffer, len);
+
+ if(track->num_indices == 0) {
+ track->indices = 0;
+ }
+ else if(0 == (track->indices = calloc(track->num_indices, sizeof(FLAC__StreamMetadata_CueSheet_Index))))
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
+
+ for(i = 0; i < track->num_indices; i++) {
+ len = FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN / 8;
+ if(read_cb(buffer, 1, len, handle) != len)
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+ track->indices[i].offset = unpack_uint64_(buffer, len);
+
+ len = FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN / 8;
+ if(read_cb(buffer, 1, len, handle) != len)
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+ track->indices[i].number = (FLAC__byte)unpack_uint32_(buffer, len);
+
+ len = FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN / 8;
+ if(read_cb(buffer, 1, len, handle) != len)
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+ }
+
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
+}
+
+FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_cuesheet_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_CueSheet *block)
+{
+ uint32_t i, len;
+ FLAC__Metadata_SimpleIteratorStatus status;
+ FLAC__byte buffer[1024]; /* MSVC needs a constant expression so we put a magic number and assert */
+
+ len = FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN / 8;
+ if(read_cb(block->media_catalog_number, 1, len, handle) != len)
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+
+ len = FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN / 8;
+ if(read_cb(buffer, 1, len, handle) != len)
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+ block->lead_in = unpack_uint64_(buffer, len);
+
+ len = (FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN + FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN) / 8;
+ if(read_cb(buffer, 1, len, handle) != len)
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+ block->is_cd = buffer[0]&0x80? true : false;
+
+ len = FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN / 8;
+ if(read_cb(buffer, 1, len, handle) != len)
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+ block->num_tracks = unpack_uint32_(buffer, len);
+
+ if(block->num_tracks == 0) {
+ block->tracks = 0;
+ }
+ else if(0 == (block->tracks = calloc(block->num_tracks, sizeof(FLAC__StreamMetadata_CueSheet_Track))))
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
+
+ for(i = 0; i < block->num_tracks; i++) {
+ if(FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK != (status = read_metadata_block_data_cuesheet_track_cb_(handle, read_cb, block->tracks + i)))
+ return status;
+ }
+
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
+}
+
+static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_picture_cstring_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__byte **data, FLAC__uint32 *length, FLAC__uint32 length_len)
+{
+ FLAC__byte buffer[sizeof(FLAC__uint32)];
+
+ length_len /= 8; /* convert to bytes */
+
+ if(read_cb(buffer, 1, length_len, handle) != length_len)
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+ *length = unpack_uint32_(buffer, length_len);
+
+ if(0 != *data)
+ free(*data);
+
+ if(0 == (*data = safe_malloc_add_2op_(*length, /*+*/1)))
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
+
+ if(*length > 0) {
+ if(read_cb(*data, 1, *length, handle) != *length)
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+ }
+
+ (*data)[*length] = '\0';
+
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
+}
+
+FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_picture_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_Picture *block)
+{
+ FLAC__Metadata_SimpleIteratorStatus status;
+ FLAC__byte buffer[4]; /* asserted below that this is big enough */
+ FLAC__uint32 len;
+
+ len = FLAC__STREAM_METADATA_PICTURE_TYPE_LEN / 8;
+ if(read_cb(buffer, 1, len, handle) != len)
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+ block->type = (FLAC__StreamMetadata_Picture_Type)unpack_uint32_(buffer, len);
+
+ if((status = read_metadata_block_data_picture_cstring_cb_(handle, read_cb, (FLAC__byte**)(&(block->mime_type)), &len, FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN)) != FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK)
+ return status;
+
+ if((status = read_metadata_block_data_picture_cstring_cb_(handle, read_cb, &(block->description), &len, FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN)) != FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK)
+ return status;
+
+ len = FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN / 8;
+ if(read_cb(buffer, 1, len, handle) != len)
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+ block->width = unpack_uint32_(buffer, len);
+
+ len = FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN / 8;
+ if(read_cb(buffer, 1, len, handle) != len)
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+ block->height = unpack_uint32_(buffer, len);
+
+ len = FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN / 8;
+ if(read_cb(buffer, 1, len, handle) != len)
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+ block->depth = unpack_uint32_(buffer, len);
+
+ len = FLAC__STREAM_METADATA_PICTURE_COLORS_LEN / 8;
+ if(read_cb(buffer, 1, len, handle) != len)
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+ block->colors = unpack_uint32_(buffer, len);
+
+ /* for convenience we use read_metadata_block_data_picture_cstring_cb_() even though it adds an extra terminating NUL we don't use */
+ if((status = read_metadata_block_data_picture_cstring_cb_(handle, read_cb, &(block->data), &(block->data_length), FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN)) != FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK)
+ return status;
+
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
+}
+
+FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_unknown_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_Unknown *block, uint32_t block_length)
+{
+ if(block_length == 0) {
+ block->data = 0;
+ }
+ else {
+ if(0 == (block->data = malloc(block_length)))
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
+
+ if(read_cb(block->data, 1, block_length, handle) != block_length)
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+ }
+
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
+}
+
+FLAC__bool write_metadata_block_header_(FILE *file, FLAC__Metadata_SimpleIteratorStatus *status, const FLAC__StreamMetadata *block)
+{
+ if(!write_metadata_block_header_cb_((FLAC__IOHandle)file, (FLAC__IOCallback_Write)fwrite, block)) {
+ *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
+ return false;
+ }
+
+ return true;
+}
+
+FLAC__bool write_metadata_block_data_(FILE *file, FLAC__Metadata_SimpleIteratorStatus *status, const FLAC__StreamMetadata *block)
+{
+ if (write_metadata_block_data_cb_((FLAC__IOHandle)file, (FLAC__IOCallback_Write)fwrite, block)) {
+ *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
+ return true;
+ }
+ else {
+ *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
+ return false;
+ }
+}
+
+FLAC__bool write_metadata_block_header_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata *block)
+{
+ FLAC__byte buffer[FLAC__STREAM_METADATA_HEADER_LENGTH];
+
+ /* double protection */
+ if(block->length >= (1u << FLAC__STREAM_METADATA_LENGTH_LEN))
+ return false;
+
+ buffer[0] = (block->is_last? 0x80 : 0) | (FLAC__byte)block->type;
+ pack_uint32_(block->length, buffer + 1, 3);
+
+ if(write_cb(buffer, 1, FLAC__STREAM_METADATA_HEADER_LENGTH, handle) != FLAC__STREAM_METADATA_HEADER_LENGTH)
+ return false;
+
+ return true;
+}
+
+FLAC__bool write_metadata_block_data_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata *block)
+{
+ switch(block->type) {
+ case FLAC__METADATA_TYPE_STREAMINFO:
+ return write_metadata_block_data_streaminfo_cb_(handle, write_cb, &block->data.stream_info);
+ case FLAC__METADATA_TYPE_PADDING:
+ return write_metadata_block_data_padding_cb_(handle, write_cb, &block->data.padding, block->length);
+ case FLAC__METADATA_TYPE_APPLICATION:
+ return write_metadata_block_data_application_cb_(handle, write_cb, &block->data.application, block->length);
+ case FLAC__METADATA_TYPE_SEEKTABLE:
+ return write_metadata_block_data_seektable_cb_(handle, write_cb, &block->data.seek_table);
+ case FLAC__METADATA_TYPE_VORBIS_COMMENT:
+ return write_metadata_block_data_vorbis_comment_cb_(handle, write_cb, &block->data.vorbis_comment);
+ case FLAC__METADATA_TYPE_CUESHEET:
+ return write_metadata_block_data_cuesheet_cb_(handle, write_cb, &block->data.cue_sheet);
+ case FLAC__METADATA_TYPE_PICTURE:
+ return write_metadata_block_data_picture_cb_(handle, write_cb, &block->data.picture);
+ default:
+ return write_metadata_block_data_unknown_cb_(handle, write_cb, &block->data.unknown, block->length);
+ }
+}
+
+FLAC__bool write_metadata_block_data_streaminfo_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_StreamInfo *block)
+{
+ FLAC__byte buffer[FLAC__STREAM_METADATA_STREAMINFO_LENGTH];
+ const uint32_t channels1 = block->channels - 1;
+ const uint32_t bps1 = block->bits_per_sample - 1;
+
+ /* we are using hardcoded numbers for simplicity but we should
+ * probably eventually write a bit-level packer and use the
+ * _STREAMINFO_ constants.
+ */
+ pack_uint32_(block->min_blocksize, buffer, 2);
+ pack_uint32_(block->max_blocksize, buffer+2, 2);
+ pack_uint32_(block->min_framesize, buffer+4, 3);
+ pack_uint32_(block->max_framesize, buffer+7, 3);
+ buffer[10] = (block->sample_rate >> 12) & 0xff;
+ buffer[11] = (block->sample_rate >> 4) & 0xff;
+ buffer[12] = (FLAC__byte)(((block->sample_rate & 0x0f) << 4) | (channels1 << 1) | (bps1 >> 4));
+ buffer[13] = (FLAC__byte)(((bps1 & 0x0f) << 4) | ((block->total_samples >> 32) & 0x0f));
+ pack_uint32_((FLAC__uint32)block->total_samples, buffer+14, 4);
+ memcpy(buffer+18, block->md5sum, 16);
+
+ if(write_cb(buffer, 1, FLAC__STREAM_METADATA_STREAMINFO_LENGTH, handle) != FLAC__STREAM_METADATA_STREAMINFO_LENGTH)
+ return false;
+
+ return true;
+}
+
+FLAC__bool write_metadata_block_data_padding_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Padding *block, uint32_t block_length)
+{
+ uint32_t i, n = block_length;
+ FLAC__byte buffer[1024];
+
+ (void)block;
+
+ memset(buffer, 0, 1024);
+
+ for(i = 0; i < n/1024; i++)
+ if(write_cb(buffer, 1, 1024, handle) != 1024)
+ return false;
+
+ n %= 1024;
+
+ if(write_cb(buffer, 1, n, handle) != n)
+ return false;
+
+ return true;
+}
+
+FLAC__bool write_metadata_block_data_application_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Application *block, uint32_t block_length)
+{
+ const uint32_t id_bytes = FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8;
+
+ if(write_cb(block->id, 1, id_bytes, handle) != id_bytes)
+ return false;
+
+ block_length -= id_bytes;
+
+ if(write_cb(block->data, 1, block_length, handle) != block_length)
+ return false;
+
+ return true;
+}
+
+FLAC__bool write_metadata_block_data_seektable_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_SeekTable *block)
+{
+ uint32_t i;
+ FLAC__byte buffer[FLAC__STREAM_METADATA_SEEKPOINT_LENGTH];
+
+ for(i = 0; i < block->num_points; i++) {
+ /* some MAGIC NUMBERs here */
+ pack_uint64_(block->points[i].sample_number, buffer, 8);
+ pack_uint64_(block->points[i].stream_offset, buffer+8, 8);
+ pack_uint32_(block->points[i].frame_samples, buffer+16, 2);
+ if(write_cb(buffer, 1, FLAC__STREAM_METADATA_SEEKPOINT_LENGTH, handle) != FLAC__STREAM_METADATA_SEEKPOINT_LENGTH)
+ return false;
+ }
+
+ return true;
+}
+
+FLAC__bool write_metadata_block_data_vorbis_comment_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_VorbisComment *block)
+{
+ uint32_t i;
+ const uint32_t entry_length_len = FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN / 8;
+ const uint32_t num_comments_len = FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN / 8;
+ FLAC__byte buffer[4]; /* magic number is asserted below */
+
+ pack_uint32_little_endian_(block->vendor_string.length, buffer, entry_length_len);
+ if(write_cb(buffer, 1, entry_length_len, handle) != entry_length_len)
+ return false;
+ if(write_cb(block->vendor_string.entry, 1, block->vendor_string.length, handle) != block->vendor_string.length)
+ return false;
+
+ pack_uint32_little_endian_(block->num_comments, buffer, num_comments_len);
+ if(write_cb(buffer, 1, num_comments_len, handle) != num_comments_len)
+ return false;
+
+ for(i = 0; i < block->num_comments; i++) {
+ pack_uint32_little_endian_(block->comments[i].length, buffer, entry_length_len);
+ if(write_cb(buffer, 1, entry_length_len, handle) != entry_length_len)
+ return false;
+ if(write_cb(block->comments[i].entry, 1, block->comments[i].length, handle) != block->comments[i].length)
+ return false;
+ }
+
+ return true;
+}
+
+FLAC__bool write_metadata_block_data_cuesheet_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_CueSheet *block)
+{
+ uint32_t i, j, len;
+ FLAC__byte buffer[1024]; /* asserted below that this is big enough */
+
+ len = FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN / 8;
+ if(write_cb(block->media_catalog_number, 1, len, handle) != len)
+ return false;
+
+ len = FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN / 8;
+ pack_uint64_(block->lead_in, buffer, len);
+ if(write_cb(buffer, 1, len, handle) != len)
+ return false;
+
+ len = (FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN + FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN) / 8;
+ memset(buffer, 0, len);
+ if(block->is_cd)
+ buffer[0] |= 0x80;
+ if(write_cb(buffer, 1, len, handle) != len)
+ return false;
+
+ len = FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN / 8;
+ pack_uint32_(block->num_tracks, buffer, len);
+ if(write_cb(buffer, 1, len, handle) != len)
+ return false;
+
+ for(i = 0; i < block->num_tracks; i++) {
+ FLAC__StreamMetadata_CueSheet_Track *track = block->tracks + i;
+
+ len = FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN / 8;
+ pack_uint64_(track->offset, buffer, len);
+ if(write_cb(buffer, 1, len, handle) != len)
+ return false;
+
+ len = FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN / 8;
+ pack_uint32_(track->number, buffer, len);
+ if(write_cb(buffer, 1, len, handle) != len)
+ return false;
+
+ len = FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN / 8;
+ if(write_cb(track->isrc, 1, len, handle) != len)
+ return false;
+
+ len = (FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN) / 8;
+ memset(buffer, 0, len);
+ buffer[0] = (FLAC__byte)((track->type << 7) | (track->pre_emphasis << 6));
+ if(write_cb(buffer, 1, len, handle) != len)
+ return false;
+
+ len = FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN / 8;
+ pack_uint32_(track->num_indices, buffer, len);
+ if(write_cb(buffer, 1, len, handle) != len)
+ return false;
+
+ for(j = 0; j < track->num_indices; j++) {
+ FLAC__StreamMetadata_CueSheet_Index *indx = track->indices + j;
+
+ len = FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN / 8;
+ pack_uint64_(indx->offset, buffer, len);
+ if(write_cb(buffer, 1, len, handle) != len)
+ return false;
+
+ len = FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN / 8;
+ pack_uint32_(indx->number, buffer, len);
+ if(write_cb(buffer, 1, len, handle) != len)
+ return false;
+
+ len = FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN / 8;
+ memset(buffer, 0, len);
+ if(write_cb(buffer, 1, len, handle) != len)
+ return false;
+ }
+ }
+
+ return true;
+}
+
+FLAC__bool write_metadata_block_data_picture_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Picture *block)
+{
+ uint32_t len;
+ size_t slen;
+ FLAC__byte buffer[4]; /* magic number is asserted below */
+
+ len = FLAC__STREAM_METADATA_PICTURE_TYPE_LEN/8;
+ pack_uint32_(block->type, buffer, len);
+ if(write_cb(buffer, 1, len, handle) != len)
+ return false;
+
+ len = FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN/8;
+ slen = strlen(block->mime_type);
+ pack_uint32_((FLAC__uint32)slen, buffer, len);
+ if(write_cb(buffer, 1, len, handle) != len)
+ return false;
+ if(write_cb(block->mime_type, 1, slen, handle) != slen)
+ return false;
+
+ len = FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN/8;
+ slen = strlen((const char *)block->description);
+ pack_uint32_((FLAC__uint32)slen, buffer, len);
+ if(write_cb(buffer, 1, len, handle) != len)
+ return false;
+ if(write_cb(block->description, 1, slen, handle) != slen)
+ return false;
+
+ len = FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN/8;
+ pack_uint32_(block->width, buffer, len);
+ if(write_cb(buffer, 1, len, handle) != len)
+ return false;
+
+ len = FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN/8;
+ pack_uint32_(block->height, buffer, len);
+ if(write_cb(buffer, 1, len, handle) != len)
+ return false;
+
+ len = FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN/8;
+ pack_uint32_(block->depth, buffer, len);
+ if(write_cb(buffer, 1, len, handle) != len)
+ return false;
+
+ len = FLAC__STREAM_METADATA_PICTURE_COLORS_LEN/8;
+ pack_uint32_(block->colors, buffer, len);
+ if(write_cb(buffer, 1, len, handle) != len)
+ return false;
+
+ len = FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN/8;
+ pack_uint32_(block->data_length, buffer, len);
+ if(write_cb(buffer, 1, len, handle) != len)
+ return false;
+ if(write_cb(block->data, 1, block->data_length, handle) != block->data_length)
+ return false;
+
+ return true;
+}
+
+FLAC__bool write_metadata_block_data_unknown_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Unknown *block, uint32_t block_length)
+{
+ if(write_cb(block->data, 1, block_length, handle) != block_length)
+ return false;
+
+ return true;
+}
+
+FLAC__bool write_metadata_block_stationary_(FLAC__Metadata_SimpleIterator *iterator, const FLAC__StreamMetadata *block)
+{
+ if(0 != fseeko(iterator->file, iterator->offset[iterator->depth], SEEK_SET)) {
+ iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
+ return false;
+ }
+
+ if(!write_metadata_block_header_(iterator->file, &iterator->status, block))
+ return false;
+
+ if(!write_metadata_block_data_(iterator->file, &iterator->status, block))
+ return false;
+
+ if(0 != fseeko(iterator->file, iterator->offset[iterator->depth], SEEK_SET)) {
+ iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
+ return false;
+ }
+
+ return read_metadata_block_header_(iterator);
+}
+
+FLAC__bool write_metadata_block_stationary_with_padding_(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block, uint32_t padding_length, FLAC__bool padding_is_last)
+{
+ FLAC__StreamMetadata *padding;
+
+ if(0 != fseeko(iterator->file, iterator->offset[iterator->depth], SEEK_SET)) {
+ iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
+ return false;
+ }
+
+ block->is_last = false;
+
+ if(!write_metadata_block_header_(iterator->file, &iterator->status, block))
+ return false;
+
+ if(!write_metadata_block_data_(iterator->file, &iterator->status, block))
+ return false;
+
+ if(0 == (padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING)))
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
+
+ padding->is_last = padding_is_last;
+ padding->length = padding_length;
+
+ if(!write_metadata_block_header_(iterator->file, &iterator->status, padding)) {
+ FLAC__metadata_object_delete(padding);
+ return false;
+ }
+
+ if(!write_metadata_block_data_(iterator->file, &iterator->status, padding)) {
+ FLAC__metadata_object_delete(padding);
+ return false;
+ }
+
+ FLAC__metadata_object_delete(padding);
+
+ if(0 != fseeko(iterator->file, iterator->offset[iterator->depth], SEEK_SET)) {
+ iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
+ return false;
+ }
+
+ return read_metadata_block_header_(iterator);
+}
+
+FLAC__bool rewrite_whole_file_(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block, FLAC__bool append)
+{
+ FILE *tempfile = NULL;
+ char *tempfilename = NULL;
+ int fixup_is_last_code = 0; /* 0 => no need to change any is_last flags */
+ FLAC__off_t fixup_is_last_flag_offset = -1;
+
+ if(iterator->is_last) {
+ if(append) {
+ fixup_is_last_code = 1; /* 1 => clear the is_last flag at the following offset */
+ fixup_is_last_flag_offset = iterator->offset[iterator->depth];
+ }
+ else if(0 == block) {
+ simple_iterator_push_(iterator);
+ if(!FLAC__metadata_simple_iterator_prev(iterator)) {
+ (void)simple_iterator_pop_(iterator);
+ return false;
+ }
+ fixup_is_last_code = -1; /* -1 => set the is_last the flag at the following offset */
+ fixup_is_last_flag_offset = iterator->offset[iterator->depth];
+ if(!simple_iterator_pop_(iterator))
+ return false;
+ }
+ }
+
+ if(!simple_iterator_copy_file_prefix_(iterator, &tempfile, &tempfilename, append))
+ return false;
+
+ if(0 != block) {
+ if(!write_metadata_block_header_(tempfile, &iterator->status, block)) {
+ cleanup_tempfile_(&tempfile, &tempfilename);
+ return false;
+ }
+
+ if(!write_metadata_block_data_(tempfile, &iterator->status, block)) {
+ cleanup_tempfile_(&tempfile, &tempfilename);
+ return false;
+ }
+ }
+
+ if(!simple_iterator_copy_file_postfix_(iterator, &tempfile, &tempfilename, fixup_is_last_code, fixup_is_last_flag_offset, block==0))
+ return false;
+
+ if(append)
+ return FLAC__metadata_simple_iterator_next(iterator);
+
+ return true;
+}
+
+void simple_iterator_push_(FLAC__Metadata_SimpleIterator *iterator)
+{
+ iterator->offset[iterator->depth+1] = iterator->offset[iterator->depth];
+ iterator->depth++;
+}
+
+FLAC__bool simple_iterator_pop_(FLAC__Metadata_SimpleIterator *iterator)
+{
+ iterator->depth--;
+ if(0 != fseeko(iterator->file, iterator->offset[iterator->depth], SEEK_SET)) {
+ iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
+ return false;
+ }
+
+ return read_metadata_block_header_(iterator);
+}
+
+/* return meanings:
+ * 0: ok
+ * 1: read error
+ * 2: seek error
+ * 3: not a FLAC file
+ */
+uint32_t seek_to_first_metadata_block_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Seek seek_cb)
+{
+ FLAC__byte buffer[4];
+ size_t n;
+ uint32_t i;
+
+ /* skip any id3v2 tag */
+ errno = 0;
+ n = read_cb(buffer, 1, 4, handle);
+ if(errno)
+ return 1;
+ else if(n != 4)
+ return 3;
+ else if(0 == memcmp(buffer, "ID3", 3)) {
+ uint32_t tag_length = 0;
+
+ /* skip to the tag length */
+ if(seek_cb(handle, 2, SEEK_CUR) < 0)
+ return 2;
+
+ /* read the length */
+ for(i = 0; i < 4; i++) {
+ if(read_cb(buffer, 1, 1, handle) < 1 || buffer[0] & 0x80)
+ return 1;
+ tag_length <<= 7;
+ tag_length |= (buffer[0] & 0x7f);
+ }
+
+ /* skip the rest of the tag */
+ if(seek_cb(handle, tag_length, SEEK_CUR) < 0)
+ return 2;
+
+ /* read the stream sync code */
+ errno = 0;
+ n = read_cb(buffer, 1, 4, handle);
+ if(errno)
+ return 1;
+ else if(n != 4)
+ return 3;
+ }
+
+ /* check for the fLaC signature */
+ if(0 == memcmp(FLAC__STREAM_SYNC_STRING, buffer, FLAC__STREAM_SYNC_LENGTH))
+ return 0;
+ else
+ return 3;
+}
+
+uint32_t seek_to_first_metadata_block_(FILE *f)
+{
+ return seek_to_first_metadata_block_cb_((FLAC__IOHandle)f, (FLAC__IOCallback_Read)fread, fseek_wrapper_);
+}
+
+FLAC__bool simple_iterator_copy_file_prefix_(FLAC__Metadata_SimpleIterator *iterator, FILE **tempfile, char **tempfilename, FLAC__bool append)
+{
+ const FLAC__off_t offset_end = append? iterator->offset[iterator->depth] + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH + (FLAC__off_t)iterator->length : iterator->offset[iterator->depth];
+
+ if(0 != fseeko(iterator->file, 0, SEEK_SET)) {
+ iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
+ return false;
+ }
+ if(!open_tempfile_(iterator->filename, iterator->tempfile_path_prefix, tempfile, tempfilename, &iterator->status)) {
+ cleanup_tempfile_(tempfile, tempfilename);
+ return false;
+ }
+ if(!copy_n_bytes_from_file_(iterator->file, *tempfile, offset_end, &iterator->status)) {
+ cleanup_tempfile_(tempfile, tempfilename);
+ return false;
+ }
+
+ return true;
+}
+
+FLAC__bool simple_iterator_copy_file_postfix_(FLAC__Metadata_SimpleIterator *iterator, FILE **tempfile, char **tempfilename, int fixup_is_last_code, FLAC__off_t fixup_is_last_flag_offset, FLAC__bool backup)
+{
+ FLAC__off_t save_offset = iterator->offset[iterator->depth];
+
+ if(0 != fseeko(iterator->file, save_offset + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH + (FLAC__off_t)iterator->length, SEEK_SET)) {
+ cleanup_tempfile_(tempfile, tempfilename);
+ iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
+ return false;
+ }
+ if(!copy_remaining_bytes_from_file_(iterator->file, *tempfile, &iterator->status)) {
+ cleanup_tempfile_(tempfile, tempfilename);
+ return false;
+ }
+
+ if(fixup_is_last_code != 0) {
+ /*
+ * if code == 1, it means a block was appended to the end so
+ * we have to clear the is_last flag of the previous block
+ * if code == -1, it means the last block was deleted so
+ * we have to set the is_last flag of the previous block
+ */
+ /* MAGIC NUMBERs here; we know the is_last flag is the high bit of the byte at this location */
+ FLAC__byte x;
+ if(0 != fseeko(*tempfile, fixup_is_last_flag_offset, SEEK_SET)) {
+ cleanup_tempfile_(tempfile, tempfilename);
+ iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
+ return false;
+ }
+ if(fread(&x, 1, 1, *tempfile) != 1) {
+ cleanup_tempfile_(tempfile, tempfilename);
+ iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+ return false;
+ }
+ if(fixup_is_last_code > 0) {
+ x &= 0x7f;
+ }
+ else {
+ x |= 0x80;
+ }
+ if(0 != fseeko(*tempfile, fixup_is_last_flag_offset, SEEK_SET)) {
+ cleanup_tempfile_(tempfile, tempfilename);
+ iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
+ return false;
+ }
+ if(local__fwrite(&x, 1, 1, *tempfile) != 1) {
+ cleanup_tempfile_(tempfile, tempfilename);
+ iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
+ return false;
+ }
+ }
+
+ (void)fclose(iterator->file);
+
+ if(!transport_tempfile_(iterator->filename, tempfile, tempfilename, &iterator->status))
+ return false;
+
+ if(iterator->has_stats)
+ set_file_stats_(iterator->filename, &iterator->stats);
+
+ if(!simple_iterator_prime_input_(iterator, !iterator->is_writable))
+ return false;
+ if(backup) {
+ while(iterator->offset[iterator->depth] + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH + (FLAC__off_t)iterator->length < save_offset)
+ if(!FLAC__metadata_simple_iterator_next(iterator))
+ return false;
+ return true;
+ }
+ else {
+ /* move the iterator to it's original block faster by faking a push, then doing a pop_ */
+ iterator->offset[0] = save_offset;
+ iterator->depth++;
+ return simple_iterator_pop_(iterator);
+ }
+}
+
+FLAC__bool copy_n_bytes_from_file_(FILE *file, FILE *tempfile, FLAC__off_t bytes, FLAC__Metadata_SimpleIteratorStatus *status)
+{
+ FLAC__byte buffer[8192];
+ size_t n;
+
+ while(bytes > 0) {
+ n = flac_min(sizeof(buffer), (size_t)bytes);
+ if(fread(buffer, 1, n, file) != n) {
+ *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+ return false;
+ }
+ if(local__fwrite(buffer, 1, n, tempfile) != n) {
+ *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
+ return false;
+ }
+ bytes -= n;
+ }
+
+ return true;
+}
+
+FLAC__bool copy_n_bytes_from_file_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOHandle temp_handle, FLAC__IOCallback_Write temp_write_cb, FLAC__off_t bytes, FLAC__Metadata_SimpleIteratorStatus *status)
+{
+ FLAC__byte buffer[8192];
+ size_t n;
+
+ while(bytes > 0) {
+ n = flac_min(sizeof(buffer), (size_t)bytes);
+ if(read_cb(buffer, 1, n, handle) != n) {
+ *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+ return false;
+ }
+ if(temp_write_cb(buffer, 1, n, temp_handle) != n) {
+ *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
+ return false;
+ }
+ bytes -= n;
+ }
+
+ return true;
+}
+
+FLAC__bool copy_remaining_bytes_from_file_(FILE *file, FILE *tempfile, FLAC__Metadata_SimpleIteratorStatus *status)
+{
+ FLAC__byte buffer[8192];
+ size_t n;
+
+ while(!feof(file)) {
+ n = fread(buffer, 1, sizeof(buffer), file);
+ if(n == 0 && !feof(file)) {
+ *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+ return false;
+ }
+ if(n > 0 && local__fwrite(buffer, 1, n, tempfile) != n) {
+ *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
+ return false;
+ }
+ }
+
+ return true;
+}
+
+FLAC__bool copy_remaining_bytes_from_file_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Eof eof_cb, FLAC__IOHandle temp_handle, FLAC__IOCallback_Write temp_write_cb, FLAC__Metadata_SimpleIteratorStatus *status)
+{
+ FLAC__byte buffer[8192];
+ size_t n;
+
+ while(!eof_cb(handle)) {
+ n = read_cb(buffer, 1, sizeof(buffer), handle);
+ if(n == 0 && !eof_cb(handle)) {
+ *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+ return false;
+ }
+ if(n > 0 && temp_write_cb(buffer, 1, n, temp_handle) != n) {
+ *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static int
+local_snprintf(char *str, size_t size, const char *fmt, ...)
+{
+ va_list va;
+ int rc;
+
+#if defined _MSC_VER
+ if (size == 0)
+ return 1024;
+#endif
+
+ va_start (va, fmt);
+
+#if defined _MSC_VER
+ rc = vsnprintf_s (str, size, _TRUNCATE, fmt, va);
+ if (rc < 0)
+ rc = (int)(size - 1);
+#elif defined __MINGW32__
+ rc = __mingw_vsnprintf (str, size, fmt, va);
+#else
+ rc = vsnprintf (str, size, fmt, va);
+#endif
+ va_end (va);
+
+ return rc;
+}
+
+FLAC__bool open_tempfile_(const char *filename, const char *tempfile_path_prefix, FILE **tempfile, char **tempfilename, FLAC__Metadata_SimpleIteratorStatus *status)
+{
+ static const char *tempfile_suffix = ".metadata_edit";
+ if(0 == tempfile_path_prefix) {
+ size_t dest_len = strlen(filename) + strlen(tempfile_suffix) + 1;
+ if(0 == (*tempfilename = safe_malloc_(dest_len))) {
+ *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
+ return false;
+ }
+ local_snprintf(*tempfilename, dest_len, "%s%s", filename, tempfile_suffix);
+ }
+ else {
+ const char *p = strrchr(filename, '/');
+ size_t dest_len;
+ if(0 == p)
+ p = filename;
+ else
+ p++;
+
+ dest_len = strlen(tempfile_path_prefix) + strlen(p) + strlen(tempfile_suffix) + 2;
+
+ if(0 == (*tempfilename = safe_malloc_(dest_len))) {
+ *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
+ return false;
+ }
+ local_snprintf(*tempfilename, dest_len, "%s/%s%s", tempfile_path_prefix, p, tempfile_suffix);
+ }
+
+ if(0 == (*tempfile = flac_fopen(*tempfilename, "w+b"))) {
+ *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ERROR_OPENING_FILE;
+ return false;
+ }
+
+ return true;
+}
+
+FLAC__bool transport_tempfile_(const char *filename, FILE **tempfile, char **tempfilename, FLAC__Metadata_SimpleIteratorStatus *status)
+{
+ (void)fclose(*tempfile);
+ *tempfile = 0;
+
+#if defined _MSC_VER || defined __BORLANDC__ || defined __MINGW32__ || defined __EMX__
+ /* on some flavors of windows, flac_rename() will fail if the destination already exists */
+ if(flac_unlink(filename) < 0) {
+ cleanup_tempfile_(tempfile, tempfilename);
+ *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_UNLINK_ERROR;
+ return false;
+ }
+#endif
+
+ /*@@@ to fully support the tempfile_path_prefix we need to update this piece to actually copy across filesystems instead of just flac_rename(): */
+ if(0 != flac_rename(*tempfilename, filename)) {
+ cleanup_tempfile_(tempfile, tempfilename);
+ *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_RENAME_ERROR;
+ return false;
+ }
+
+ cleanup_tempfile_(tempfile, tempfilename);
+
+ return true;
+}
+
+void cleanup_tempfile_(FILE **tempfile, char **tempfilename)
+{
+ if(0 != *tempfile) {
+ (void)fclose(*tempfile);
+ *tempfile = 0;
+ }
+
+ if(0 != *tempfilename) {
+ (void)flac_unlink(*tempfilename);
+ free(*tempfilename);
+ *tempfilename = 0;
+ }
+}
+
+FLAC__bool get_file_stats_(const char *filename, struct flac_stat_s *stats)
+{
+ return (0 == flac_stat(filename, stats));
+}
+
+void set_file_stats_(const char *filename, struct flac_stat_s *stats)
+{
+ struct utimbuf srctime;
+
+ srctime.actime = stats->st_atime;
+ srctime.modtime = stats->st_mtime;
+ (void)flac_chmod(filename, stats->st_mode);
+ (void)flac_utime(filename, &srctime);
+#if !defined _MSC_VER && !defined __BORLANDC__ && !defined __MINGW32__
+ FLAC_CHECK_RETURN(chown(filename, stats->st_uid, -1));
+ FLAC_CHECK_RETURN(chown(filename, -1, stats->st_gid));
+#endif
+}
+
+int fseek_wrapper_(FLAC__IOHandle handle, FLAC__int64 offset, int whence)
+{
+ return fseeko((FILE*)handle, (FLAC__off_t)offset, whence);
+}
+
+FLAC__int64 ftell_wrapper_(FLAC__IOHandle handle)
+{
+ return ftello((FILE*)handle);
+}
+
+FLAC__Metadata_ChainStatus get_equivalent_status_(FLAC__Metadata_SimpleIteratorStatus status)
+{
+ switch(status) {
+ case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK:
+ return FLAC__METADATA_CHAIN_STATUS_OK;
+ case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT:
+ return FLAC__METADATA_CHAIN_STATUS_ILLEGAL_INPUT;
+ case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ERROR_OPENING_FILE:
+ return FLAC__METADATA_CHAIN_STATUS_ERROR_OPENING_FILE;
+ case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_A_FLAC_FILE:
+ return FLAC__METADATA_CHAIN_STATUS_NOT_A_FLAC_FILE;
+ case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_WRITABLE:
+ return FLAC__METADATA_CHAIN_STATUS_NOT_WRITABLE;
+ case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_BAD_METADATA:
+ return FLAC__METADATA_CHAIN_STATUS_BAD_METADATA;
+ case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR:
+ return FLAC__METADATA_CHAIN_STATUS_READ_ERROR;
+ case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR:
+ return FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR;
+ case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR:
+ return FLAC__METADATA_CHAIN_STATUS_WRITE_ERROR;
+ case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_RENAME_ERROR:
+ return FLAC__METADATA_CHAIN_STATUS_RENAME_ERROR;
+ case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_UNLINK_ERROR:
+ return FLAC__METADATA_CHAIN_STATUS_UNLINK_ERROR;
+ case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR:
+ return FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR;
+ case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_INTERNAL_ERROR:
+ default:
+ return FLAC__METADATA_CHAIN_STATUS_INTERNAL_ERROR;
+ }
+}
--- /dev/null
+++ b/src/libflac/metadata_object.c
@@ -1,0 +1,1588 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2001-2009 Josh Coalson
+ * Copyright (C) 2011-2016 Xiph.Org Foundation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "private/metadata.h"
+#include "private/memory.h"
+
+#include "share/alloc.h"
+#include "share/compat.h"
+
+// 8bb: hide POSIX warnings
+#ifdef _MSC_VER
+#pragma warning(disable: 4996)
+#endif
+
+/* Alias the first (in share/alloc.h) to the second (in src/libFLAC/memory.c). */
+#define safe_malloc_mul_2op_ safe_malloc_mul_2op_p
+
+
+/****************************************************************************
+ *
+ * Local routines
+ *
+ ***************************************************************************/
+
+/* copy bytes:
+ * from = NULL && bytes = 0
+ * to <- NULL
+ * from != NULL && bytes > 0
+ * to <- copy of from
+ * else ASSERT
+ * malloc error leaves 'to' unchanged
+ */
+static FLAC__bool copy_bytes_(FLAC__byte **to, const FLAC__byte *from, uint32_t bytes)
+{
+ if (bytes > 0 && from != NULL) {
+ FLAC__byte *x;
+ if ((x = safe_malloc_(bytes)) == NULL)
+ return false;
+ memcpy(x, from, bytes);
+ *to = x;
+ }
+ else {
+ *to = 0;
+ }
+ return true;
+}
+
+/* reallocate entry to 1 byte larger and add a terminating NUL */
+/* realloc() failure leaves entry unchanged */
+static FLAC__bool ensure_null_terminated_(FLAC__byte **entry, uint32_t length)
+{
+ FLAC__byte *x = safe_realloc_add_2op_(*entry, length, /*+*/1);
+ if (x != NULL) {
+ x[length] = '\0';
+ *entry = x;
+ return true;
+ }
+ else
+ return false;
+}
+
+/* copies the NUL-terminated C-string 'from' to '*to', leaving '*to'
+ * unchanged if malloc fails, free()ing the original '*to' if it
+ * succeeds and the original '*to' was not NULL
+ */
+static FLAC__bool copy_cstring_(char **to, const char *from)
+{
+ char *copy = strdup(from);
+ if (copy) {
+ free(*to);
+ *to = copy;
+ return true;
+ }
+ else
+ return false;
+}
+
+static FLAC__bool copy_vcentry_(FLAC__StreamMetadata_VorbisComment_Entry *to, const FLAC__StreamMetadata_VorbisComment_Entry *from)
+{
+ to->length = from->length;
+ if (from->entry == 0) {
+ to->entry = 0;
+ }
+ else {
+ FLAC__byte *x;
+ if ((x = safe_malloc_add_2op_(from->length, /*+*/1)) == NULL)
+ return false;
+ memcpy(x, from->entry, from->length);
+ x[from->length] = '\0';
+ to->entry = x;
+ }
+ return true;
+}
+
+static FLAC__bool copy_track_(FLAC__StreamMetadata_CueSheet_Track *to, const FLAC__StreamMetadata_CueSheet_Track *from)
+{
+ memcpy(to, from, sizeof(FLAC__StreamMetadata_CueSheet_Track));
+ if (from->indices == 0) {
+ }
+ else {
+ FLAC__StreamMetadata_CueSheet_Index *x;
+ if ((x = safe_malloc_mul_2op_p(from->num_indices, /*times*/sizeof(FLAC__StreamMetadata_CueSheet_Index))) == NULL)
+ return false;
+ memcpy(x, from->indices, from->num_indices * sizeof(FLAC__StreamMetadata_CueSheet_Index));
+ to->indices = x;
+ }
+ return true;
+}
+
+static void seektable_calculate_length_(FLAC__StreamMetadata *object)
+{
+ object->length = object->data.seek_table.num_points * FLAC__STREAM_METADATA_SEEKPOINT_LENGTH;
+}
+
+static FLAC__StreamMetadata_SeekPoint *seekpoint_array_new_(uint32_t num_points)
+{
+ FLAC__StreamMetadata_SeekPoint *object_array;
+
+ object_array = safe_malloc_mul_2op_p(num_points, /*times*/sizeof(FLAC__StreamMetadata_SeekPoint));
+
+ if (object_array != NULL) {
+ uint32_t i;
+ for (i = 0; i < num_points; i++) {
+ object_array[i].sample_number = FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER;
+ object_array[i].stream_offset = 0;
+ object_array[i].frame_samples = 0;
+ }
+ }
+
+ return object_array;
+}
+
+static void vorbiscomment_calculate_length_(FLAC__StreamMetadata *object)
+{
+ uint32_t i;
+
+ object->length = (FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN) / 8;
+ object->length += object->data.vorbis_comment.vendor_string.length;
+ object->length += (FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN) / 8;
+ for (i = 0; i < object->data.vorbis_comment.num_comments; i++) {
+ object->length += (FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN / 8);
+ object->length += object->data.vorbis_comment.comments[i].length;
+ }
+}
+
+static FLAC__StreamMetadata_VorbisComment_Entry *vorbiscomment_entry_array_new_(uint32_t num_comments)
+{
+ return safe_calloc_(num_comments, sizeof(FLAC__StreamMetadata_VorbisComment_Entry));
+}
+
+static void vorbiscomment_entry_array_delete_(FLAC__StreamMetadata_VorbisComment_Entry *object_array, uint32_t num_comments)
+{
+ uint32_t i;
+
+ for (i = 0; i < num_comments; i++)
+ free(object_array[i].entry);
+
+ free(object_array);
+}
+
+static FLAC__StreamMetadata_VorbisComment_Entry *vorbiscomment_entry_array_copy_(const FLAC__StreamMetadata_VorbisComment_Entry *object_array, uint32_t num_comments)
+{
+ FLAC__StreamMetadata_VorbisComment_Entry *return_array;
+
+ return_array = vorbiscomment_entry_array_new_(num_comments);
+
+ if (return_array != NULL) {
+ uint32_t i;
+
+ for (i = 0; i < num_comments; i++) {
+ if (!copy_vcentry_(return_array+i, object_array+i)) {
+ vorbiscomment_entry_array_delete_(return_array, num_comments);
+ return 0;
+ }
+ }
+ }
+
+ return return_array;
+}
+
+static FLAC__bool vorbiscomment_set_entry_(FLAC__StreamMetadata *object, FLAC__StreamMetadata_VorbisComment_Entry *dest, const FLAC__StreamMetadata_VorbisComment_Entry *src, FLAC__bool copy)
+{
+ FLAC__byte *save;
+
+ save = dest->entry;
+
+ if (src->entry != NULL) {
+ if (copy) {
+ /* do the copy first so that if we fail we leave the dest object untouched */
+ if (!copy_vcentry_(dest, src))
+ return false;
+ }
+ else {
+ /* we have to make sure that the string we're taking over is null-terminated */
+
+ /*
+ * Stripping the const from src->entry is OK since we're taking
+ * ownership of the pointer. This is a hack around a deficiency
+ * in the API where the same function is used for 'copy' and
+ * 'own', but the source entry is a const pointer. If we were
+ * precise, the 'own' flavor would be a separate function with a
+ * non-const source pointer. But it's not, so we hack away.
+ */
+ if (!ensure_null_terminated_((FLAC__byte**)(&src->entry), src->length))
+ return false;
+ *dest = *src;
+ }
+ }
+ else {
+ /* the src is null */
+ *dest = *src;
+ }
+
+ free(save);
+
+ vorbiscomment_calculate_length_(object);
+ return true;
+}
+
+static int vorbiscomment_find_entry_from_(const FLAC__StreamMetadata *object, uint32_t offset, const char *field_name, uint32_t field_name_length)
+{
+ uint32_t i;
+
+ for (i = offset; i < object->data.vorbis_comment.num_comments; i++) {
+ if (FLAC__metadata_object_vorbiscomment_entry_matches(object->data.vorbis_comment.comments[i], field_name, field_name_length))
+ return (int)i;
+ }
+
+ return -1;
+}
+
+static void cuesheet_calculate_length_(FLAC__StreamMetadata *object)
+{
+ uint32_t i;
+
+ object->length = (
+ FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN +
+ FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN +
+ FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN +
+ FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN +
+ FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN
+ ) / 8;
+
+ object->length += object->data.cue_sheet.num_tracks * (
+ FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN +
+ FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN +
+ FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN +
+ FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN +
+ FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN +
+ FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN +
+ FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN
+ ) / 8;
+
+ for (i = 0; i < object->data.cue_sheet.num_tracks; i++) {
+ object->length += object->data.cue_sheet.tracks[i].num_indices * (
+ FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN +
+ FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN +
+ FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN
+ ) / 8;
+ }
+}
+
+static FLAC__StreamMetadata_CueSheet_Index *cuesheet_track_index_array_new_(uint32_t num_indices)
+{
+ return safe_calloc_(num_indices, sizeof(FLAC__StreamMetadata_CueSheet_Index));
+}
+
+static FLAC__StreamMetadata_CueSheet_Track *cuesheet_track_array_new_(uint32_t num_tracks)
+{
+ return safe_calloc_(num_tracks, sizeof(FLAC__StreamMetadata_CueSheet_Track));
+}
+
+static void cuesheet_track_array_delete_(FLAC__StreamMetadata_CueSheet_Track *object_array, uint32_t num_tracks)
+{
+ uint32_t i;
+
+ for (i = 0; i < num_tracks; i++) {
+ if (object_array[i].indices != 0) {
+ free(object_array[i].indices);
+ }
+ }
+
+ free(object_array);
+}
+
+static FLAC__StreamMetadata_CueSheet_Track *cuesheet_track_array_copy_(const FLAC__StreamMetadata_CueSheet_Track *object_array, uint32_t num_tracks)
+{
+ FLAC__StreamMetadata_CueSheet_Track *return_array;
+
+ return_array = cuesheet_track_array_new_(num_tracks);
+
+ if (return_array != NULL) {
+ uint32_t i;
+
+ for (i = 0; i < num_tracks; i++) {
+ if (!copy_track_(return_array+i, object_array+i)) {
+ cuesheet_track_array_delete_(return_array, num_tracks);
+ return 0;
+ }
+ }
+ }
+
+ return return_array;
+}
+
+static FLAC__bool cuesheet_set_track_(FLAC__StreamMetadata *object, FLAC__StreamMetadata_CueSheet_Track *dest, const FLAC__StreamMetadata_CueSheet_Track *src, FLAC__bool copy)
+{
+ FLAC__StreamMetadata_CueSheet_Index *save;
+
+ save = dest->indices;
+
+ /* do the copy first so that if we fail we leave the object untouched */
+ if (copy) {
+ if (!copy_track_(dest, src))
+ return false;
+ }
+ else {
+ *dest = *src;
+ }
+
+ free(save);
+
+ cuesheet_calculate_length_(object);
+ return true;
+}
+
+
+/****************************************************************************
+ *
+ * Metadata object routines
+ *
+ ***************************************************************************/
+
+FLAC_API FLAC__StreamMetadata *FLAC__metadata_object_new(FLAC__MetadataType type)
+{
+ FLAC__StreamMetadata *object;
+
+ if (type > FLAC__MAX_METADATA_TYPE)
+ return 0;
+
+ object = calloc(1, sizeof(FLAC__StreamMetadata));
+ if (object != NULL) {
+ object->is_last = false;
+ object->type = type;
+ switch(type) {
+ case FLAC__METADATA_TYPE_STREAMINFO:
+ object->length = FLAC__STREAM_METADATA_STREAMINFO_LENGTH;
+ break;
+ case FLAC__METADATA_TYPE_PADDING:
+ /* calloc() took care of this for us:
+ object->length = 0;
+ */
+ break;
+ case FLAC__METADATA_TYPE_APPLICATION:
+ object->length = FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8;
+ /* calloc() took care of this for us:
+ object->data.application.data = 0;
+ */
+ break;
+ case FLAC__METADATA_TYPE_SEEKTABLE:
+ /* calloc() took care of this for us:
+ object->length = 0;
+ object->data.seek_table.num_points = 0;
+ object->data.seek_table.points = 0;
+ */
+ break;
+ case FLAC__METADATA_TYPE_VORBIS_COMMENT:
+ object->data.vorbis_comment.vendor_string.length = (uint32_t)strlen(FLAC__VENDOR_STRING);
+ if (!copy_bytes_(&object->data.vorbis_comment.vendor_string.entry, (const FLAC__byte*)FLAC__VENDOR_STRING, object->data.vorbis_comment.vendor_string.length+1)) {
+ free(object);
+ return 0;
+ }
+ vorbiscomment_calculate_length_(object);
+ break;
+ case FLAC__METADATA_TYPE_CUESHEET:
+ cuesheet_calculate_length_(object);
+ break;
+ case FLAC__METADATA_TYPE_PICTURE:
+ object->length = (
+ FLAC__STREAM_METADATA_PICTURE_TYPE_LEN +
+ FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN + /* empty mime_type string */
+ FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN + /* empty description string */
+ FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN +
+ FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN +
+ FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN +
+ FLAC__STREAM_METADATA_PICTURE_COLORS_LEN +
+ FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN +
+ 0 /* no data */
+ ) / 8;
+ object->data.picture.type = FLAC__STREAM_METADATA_PICTURE_TYPE_OTHER;
+ object->data.picture.mime_type = 0;
+ object->data.picture.description = 0;
+ /* calloc() took care of this for us:
+ object->data.picture.width = 0;
+ object->data.picture.height = 0;
+ object->data.picture.depth = 0;
+ object->data.picture.colors = 0;
+ object->data.picture.data_length = 0;
+ object->data.picture.data = 0;
+ */
+ /* now initialize mime_type and description with empty strings to make things easier on the client */
+ if (!copy_cstring_(&object->data.picture.mime_type, "")) {
+ free(object);
+ return 0;
+ }
+ if (!copy_cstring_((char**)(&object->data.picture.description), "")) {
+ free(object->data.picture.mime_type);
+ free(object);
+ return 0;
+ }
+ break;
+ default:
+ /* calloc() took care of this for us:
+ object->length = 0;
+ object->data.unknown.data = 0;
+ */
+ break;
+ }
+ }
+
+ return object;
+}
+
+FLAC_API FLAC__StreamMetadata *FLAC__metadata_object_clone(const FLAC__StreamMetadata *object)
+{
+ FLAC__StreamMetadata *to;
+
+ if ((to = FLAC__metadata_object_new(object->type)) != NULL) {
+ to->is_last = object->is_last;
+ to->type = object->type;
+ to->length = object->length;
+ switch(to->type) {
+ case FLAC__METADATA_TYPE_STREAMINFO:
+ memcpy(&to->data.stream_info, &object->data.stream_info, sizeof(FLAC__StreamMetadata_StreamInfo));
+ break;
+ case FLAC__METADATA_TYPE_PADDING:
+ break;
+ case FLAC__METADATA_TYPE_APPLICATION:
+ if (to->length < FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8) { /* underflow check */
+ FLAC__metadata_object_delete(to);
+ return 0;
+ }
+ memcpy(&to->data.application.id, &object->data.application.id, FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8);
+ if (!copy_bytes_(&to->data.application.data, object->data.application.data, object->length - FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8)) {
+ FLAC__metadata_object_delete(to);
+ return 0;
+ }
+ break;
+ case FLAC__METADATA_TYPE_SEEKTABLE:
+ to->data.seek_table.num_points = object->data.seek_table.num_points;
+ if (to->data.seek_table.num_points > UINT32_MAX / sizeof(FLAC__StreamMetadata_SeekPoint)) { /* overflow check */
+ FLAC__metadata_object_delete(to);
+ return 0;
+ }
+ if (!copy_bytes_((FLAC__byte**)&to->data.seek_table.points, (FLAC__byte*)object->data.seek_table.points, object->data.seek_table.num_points * sizeof(FLAC__StreamMetadata_SeekPoint))) {
+ FLAC__metadata_object_delete(to);
+ return 0;
+ }
+ break;
+ case FLAC__METADATA_TYPE_VORBIS_COMMENT:
+ if (to->data.vorbis_comment.vendor_string.entry != NULL) {
+ free(to->data.vorbis_comment.vendor_string.entry);
+ to->data.vorbis_comment.vendor_string.entry = 0;
+ }
+ if (!copy_vcentry_(&to->data.vorbis_comment.vendor_string, &object->data.vorbis_comment.vendor_string)) {
+ FLAC__metadata_object_delete(to);
+ return 0;
+ }
+ if (object->data.vorbis_comment.num_comments == 0) {
+ to->data.vorbis_comment.comments = 0;
+ }
+ else {
+ to->data.vorbis_comment.comments = vorbiscomment_entry_array_copy_(object->data.vorbis_comment.comments, object->data.vorbis_comment.num_comments);
+ if (to->data.vorbis_comment.comments == NULL) {
+ to->data.vorbis_comment.num_comments = 0;
+ FLAC__metadata_object_delete(to);
+ return 0;
+ }
+ }
+ to->data.vorbis_comment.num_comments = object->data.vorbis_comment.num_comments;
+ break;
+ case FLAC__METADATA_TYPE_CUESHEET:
+ memcpy(&to->data.cue_sheet, &object->data.cue_sheet, sizeof(FLAC__StreamMetadata_CueSheet));
+ if (object->data.cue_sheet.num_tracks == 0) {
+ }
+ else {
+ to->data.cue_sheet.tracks = cuesheet_track_array_copy_(object->data.cue_sheet.tracks, object->data.cue_sheet.num_tracks);
+ if (to->data.cue_sheet.tracks == NULL) {
+ FLAC__metadata_object_delete(to);
+ return 0;
+ }
+ }
+ break;
+ case FLAC__METADATA_TYPE_PICTURE:
+ to->data.picture.type = object->data.picture.type;
+ if (!copy_cstring_(&to->data.picture.mime_type, object->data.picture.mime_type)) {
+ FLAC__metadata_object_delete(to);
+ return 0;
+ }
+ if (!copy_cstring_((char**)(&to->data.picture.description), (const char*)object->data.picture.description)) {
+ FLAC__metadata_object_delete(to);
+ return 0;
+ }
+ to->data.picture.width = object->data.picture.width;
+ to->data.picture.height = object->data.picture.height;
+ to->data.picture.depth = object->data.picture.depth;
+ to->data.picture.colors = object->data.picture.colors;
+ to->data.picture.data_length = object->data.picture.data_length;
+ if (!copy_bytes_((&to->data.picture.data), object->data.picture.data, object->data.picture.data_length)) {
+ FLAC__metadata_object_delete(to);
+ return 0;
+ }
+ break;
+ default:
+ if (!copy_bytes_(&to->data.unknown.data, object->data.unknown.data, object->length)) {
+ FLAC__metadata_object_delete(to);
+ return 0;
+ }
+ break;
+ }
+ }
+
+ return to;
+}
+
+void FLAC__metadata_object_delete_data(FLAC__StreamMetadata *object)
+{
+ switch(object->type) {
+ case FLAC__METADATA_TYPE_STREAMINFO:
+ case FLAC__METADATA_TYPE_PADDING:
+ break;
+ case FLAC__METADATA_TYPE_APPLICATION:
+ if (object->data.application.data != NULL) {
+ free(object->data.application.data);
+ object->data.application.data = NULL;
+ }
+ break;
+ case FLAC__METADATA_TYPE_SEEKTABLE:
+ if (object->data.seek_table.points != NULL) {
+ free(object->data.seek_table.points);
+ object->data.seek_table.points = NULL;
+ }
+ break;
+ case FLAC__METADATA_TYPE_VORBIS_COMMENT:
+ if (object->data.vorbis_comment.vendor_string.entry != NULL) {
+ free(object->data.vorbis_comment.vendor_string.entry);
+ object->data.vorbis_comment.vendor_string.entry = 0;
+ }
+ if (object->data.vorbis_comment.comments != NULL) {
+ vorbiscomment_entry_array_delete_(object->data.vorbis_comment.comments, object->data.vorbis_comment.num_comments);
+ object->data.vorbis_comment.comments = NULL;
+ object->data.vorbis_comment.num_comments = 0;
+ }
+ break;
+ case FLAC__METADATA_TYPE_CUESHEET:
+ if (object->data.cue_sheet.tracks != NULL) {
+ cuesheet_track_array_delete_(object->data.cue_sheet.tracks, object->data.cue_sheet.num_tracks);
+ object->data.cue_sheet.tracks = NULL;
+ object->data.cue_sheet.num_tracks = 0;
+ }
+ break;
+ case FLAC__METADATA_TYPE_PICTURE:
+ if (object->data.picture.mime_type != NULL) {
+ free(object->data.picture.mime_type);
+ object->data.picture.mime_type = NULL;
+ }
+ if (object->data.picture.description != NULL) {
+ free(object->data.picture.description);
+ object->data.picture.description = NULL;
+ }
+ if (object->data.picture.data != NULL) {
+ free(object->data.picture.data);
+ object->data.picture.data = NULL;
+ }
+ break;
+ default:
+ if (object->data.unknown.data != NULL) {
+ free(object->data.unknown.data);
+ object->data.unknown.data = NULL;
+ }
+ break;
+ }
+}
+
+FLAC_API void FLAC__metadata_object_delete(FLAC__StreamMetadata *object)
+{
+ FLAC__metadata_object_delete_data(object);
+ free(object);
+}
+
+static FLAC__bool compare_block_data_streaminfo_(const FLAC__StreamMetadata_StreamInfo *block1, const FLAC__StreamMetadata_StreamInfo *block2)
+{
+ if (block1->min_blocksize != block2->min_blocksize)
+ return false;
+ if (block1->max_blocksize != block2->max_blocksize)
+ return false;
+ if (block1->min_framesize != block2->min_framesize)
+ return false;
+ if (block1->max_framesize != block2->max_framesize)
+ return false;
+ if (block1->sample_rate != block2->sample_rate)
+ return false;
+ if (block1->channels != block2->channels)
+ return false;
+ if (block1->bits_per_sample != block2->bits_per_sample)
+ return false;
+ if (block1->total_samples != block2->total_samples)
+ return false;
+ if (memcmp(block1->md5sum, block2->md5sum, 16) != 0)
+ return false;
+ return true;
+}
+
+static FLAC__bool compare_block_data_application_(const FLAC__StreamMetadata_Application *block1, const FLAC__StreamMetadata_Application *block2, uint32_t block_length)
+{
+ if (memcmp(block1->id, block2->id, sizeof(block1->id)) != 0)
+ return false;
+ if (block1->data != NULL && block2->data != NULL)
+ return memcmp(block1->data, block2->data, block_length - sizeof(block1->id)) == 0;
+ else
+ return block1->data == block2->data;
+}
+
+static FLAC__bool compare_block_data_seektable_(const FLAC__StreamMetadata_SeekTable *block1, const FLAC__StreamMetadata_SeekTable *block2)
+{
+ uint32_t i;
+
+ if (block1->num_points != block2->num_points)
+ return false;
+
+ if (block1->points != NULL && block2->points != NULL) {
+ for (i = 0; i < block1->num_points; i++) {
+ if (block1->points[i].sample_number != block2->points[i].sample_number)
+ return false;
+ if (block1->points[i].stream_offset != block2->points[i].stream_offset)
+ return false;
+ if (block1->points[i].frame_samples != block2->points[i].frame_samples)
+ return false;
+ }
+ return true;
+ }
+ else
+ return block1->points == block2->points;
+}
+
+static FLAC__bool compare_block_data_vorbiscomment_(const FLAC__StreamMetadata_VorbisComment *block1, const FLAC__StreamMetadata_VorbisComment *block2)
+{
+ uint32_t i;
+
+ if (block1->vendor_string.length != block2->vendor_string.length)
+ return false;
+
+ if (block1->vendor_string.entry != NULL && block2->vendor_string.entry != NULL) {
+ if (memcmp(block1->vendor_string.entry, block2->vendor_string.entry, block1->vendor_string.length) != 0)
+ return false;
+ }
+ else if (block1->vendor_string.entry != block2->vendor_string.entry)
+ return false;
+
+ if (block1->num_comments != block2->num_comments)
+ return false;
+
+ for (i = 0; i < block1->num_comments; i++) {
+ if (block1->comments[i].entry != NULL && block2->comments[i].entry != NULL) {
+ if (memcmp(block1->comments[i].entry, block2->comments[i].entry, block1->comments[i].length) != 0)
+ return false;
+ }
+ else if (block1->comments[i].entry != block2->comments[i].entry)
+ return false;
+ }
+ return true;
+}
+
+static FLAC__bool compare_block_data_cuesheet_(const FLAC__StreamMetadata_CueSheet *block1, const FLAC__StreamMetadata_CueSheet *block2)
+{
+ uint32_t i, j;
+
+ if (strcmp(block1->media_catalog_number, block2->media_catalog_number) != 0)
+ return false;
+
+ if (block1->lead_in != block2->lead_in)
+ return false;
+
+ if (block1->is_cd != block2->is_cd)
+ return false;
+
+ if (block1->num_tracks != block2->num_tracks)
+ return false;
+
+ if (block1->tracks != NULL && block2->tracks != NULL) {
+ for (i = 0; i < block1->num_tracks; i++) {
+ if (block1->tracks[i].offset != block2->tracks[i].offset)
+ return false;
+ if (block1->tracks[i].number != block2->tracks[i].number)
+ return false;
+ if (memcmp(block1->tracks[i].isrc, block2->tracks[i].isrc, sizeof(block1->tracks[i].isrc)) != 0)
+ return false;
+ if (block1->tracks[i].type != block2->tracks[i].type)
+ return false;
+ if (block1->tracks[i].pre_emphasis != block2->tracks[i].pre_emphasis)
+ return false;
+ if (block1->tracks[i].num_indices != block2->tracks[i].num_indices)
+ return false;
+ if (block1->tracks[i].indices != NULL && block2->tracks[i].indices != NULL) {
+ for (j = 0; j < block1->tracks[i].num_indices; j++) {
+ if (block1->tracks[i].indices[j].offset != block2->tracks[i].indices[j].offset)
+ return false;
+ if (block1->tracks[i].indices[j].number != block2->tracks[i].indices[j].number)
+ return false;
+ }
+ }
+ else if (block1->tracks[i].indices != block2->tracks[i].indices)
+ return false;
+ }
+ }
+ else if (block1->tracks != block2->tracks)
+ return false;
+ return true;
+}
+
+static FLAC__bool compare_block_data_picture_(const FLAC__StreamMetadata_Picture *block1, const FLAC__StreamMetadata_Picture *block2)
+{
+ if (block1->type != block2->type)
+ return false;
+ if (block1->mime_type != block2->mime_type && (block1->mime_type == 0 || block2->mime_type == 0 || strcmp(block1->mime_type, block2->mime_type)))
+ return false;
+ if (block1->description != block2->description && (block1->description == 0 || block2->description == 0 || strcmp((const char *)block1->description, (const char *)block2->description)))
+ return false;
+ if (block1->width != block2->width)
+ return false;
+ if (block1->height != block2->height)
+ return false;
+ if (block1->depth != block2->depth)
+ return false;
+ if (block1->colors != block2->colors)
+ return false;
+ if (block1->data_length != block2->data_length)
+ return false;
+ if (block1->data != block2->data && (block1->data == NULL || block2->data == NULL || memcmp(block1->data, block2->data, block1->data_length)))
+ return false;
+ return true;
+}
+
+static FLAC__bool compare_block_data_unknown_(const FLAC__StreamMetadata_Unknown *block1, const FLAC__StreamMetadata_Unknown *block2, uint32_t block_length)
+{
+ if (block1->data != NULL && block2->data != NULL)
+ return memcmp(block1->data, block2->data, block_length) == 0;
+ else
+ return block1->data == block2->data;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_is_equal(const FLAC__StreamMetadata *block1, const FLAC__StreamMetadata *block2)
+{
+ if (block1->type != block2->type) {
+ return false;
+ }
+ if (block1->is_last != block2->is_last) {
+ return false;
+ }
+ if (block1->length != block2->length) {
+ return false;
+ }
+ switch(block1->type) {
+ case FLAC__METADATA_TYPE_STREAMINFO:
+ return compare_block_data_streaminfo_(&block1->data.stream_info, &block2->data.stream_info);
+ case FLAC__METADATA_TYPE_PADDING:
+ return true; /* we don't compare the padding guts */
+ case FLAC__METADATA_TYPE_APPLICATION:
+ return compare_block_data_application_(&block1->data.application, &block2->data.application, block1->length);
+ case FLAC__METADATA_TYPE_SEEKTABLE:
+ return compare_block_data_seektable_(&block1->data.seek_table, &block2->data.seek_table);
+ case FLAC__METADATA_TYPE_VORBIS_COMMENT:
+ return compare_block_data_vorbiscomment_(&block1->data.vorbis_comment, &block2->data.vorbis_comment);
+ case FLAC__METADATA_TYPE_CUESHEET:
+ return compare_block_data_cuesheet_(&block1->data.cue_sheet, &block2->data.cue_sheet);
+ case FLAC__METADATA_TYPE_PICTURE:
+ return compare_block_data_picture_(&block1->data.picture, &block2->data.picture);
+ default:
+ return compare_block_data_unknown_(&block1->data.unknown, &block2->data.unknown, block1->length);
+ }
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_application_set_data(FLAC__StreamMetadata *object, FLAC__byte *data, uint32_t length, FLAC__bool copy)
+{
+ FLAC__byte *save;
+
+ save = object->data.application.data;
+
+ /* do the copy first so that if we fail we leave the object untouched */
+ if (copy) {
+ if (!copy_bytes_(&object->data.application.data, data, length))
+ return false;
+ }
+ else {
+ object->data.application.data = data;
+ }
+
+ free(save);
+
+ object->length = FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8 + length;
+ return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_resize_points(FLAC__StreamMetadata *object, uint32_t new_num_points)
+{
+ if (object->data.seek_table.points == 0) {
+ if (new_num_points == 0)
+ return true;
+ else if ((object->data.seek_table.points = seekpoint_array_new_(new_num_points)) == 0)
+ return false;
+ }
+ else {
+ const size_t old_size = object->data.seek_table.num_points * sizeof(FLAC__StreamMetadata_SeekPoint);
+ const size_t new_size = new_num_points * sizeof(FLAC__StreamMetadata_SeekPoint);
+
+ /* overflow check */
+ if (new_num_points > UINT32_MAX / sizeof(FLAC__StreamMetadata_SeekPoint))
+ return false;
+
+ if (new_size == 0) {
+ free(object->data.seek_table.points);
+ object->data.seek_table.points = 0;
+ }
+ else if ((object->data.seek_table.points = safe_realloc_(object->data.seek_table.points, new_size)) == NULL)
+ return false;
+
+ /* if growing, set new elements to placeholders */
+ if (new_size > old_size) {
+ uint32_t i;
+ for (i = object->data.seek_table.num_points; i < new_num_points; i++) {
+ object->data.seek_table.points[i].sample_number = FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER;
+ object->data.seek_table.points[i].stream_offset = 0;
+ object->data.seek_table.points[i].frame_samples = 0;
+ }
+ }
+ }
+
+ object->data.seek_table.num_points = new_num_points;
+
+ seektable_calculate_length_(object);
+ return true;
+}
+
+FLAC_API void FLAC__metadata_object_seektable_set_point(FLAC__StreamMetadata *object, uint32_t point_num, FLAC__StreamMetadata_SeekPoint point)
+{
+ object->data.seek_table.points[point_num] = point;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_insert_point(FLAC__StreamMetadata *object, uint32_t point_num, FLAC__StreamMetadata_SeekPoint point)
+{
+ int i;
+
+ if (!FLAC__metadata_object_seektable_resize_points(object, object->data.seek_table.num_points+1))
+ return false;
+
+ /* move all points >= point_num forward one space */
+ for (i = (int)object->data.seek_table.num_points-1; i > (int)point_num; i--)
+ object->data.seek_table.points[i] = object->data.seek_table.points[i-1];
+
+ FLAC__metadata_object_seektable_set_point(object, point_num, point);
+ seektable_calculate_length_(object);
+ return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_delete_point(FLAC__StreamMetadata *object, uint32_t point_num)
+{
+ uint32_t i;
+
+ /* move all points > point_num backward one space */
+ for (i = point_num; i < object->data.seek_table.num_points-1; i++)
+ object->data.seek_table.points[i] = object->data.seek_table.points[i+1];
+
+ return FLAC__metadata_object_seektable_resize_points(object, object->data.seek_table.num_points-1);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_is_legal(const FLAC__StreamMetadata *object)
+{
+ return FLAC__format_seektable_is_legal(&object->data.seek_table);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_placeholders(FLAC__StreamMetadata *object, uint32_t num)
+{
+ if (num > 0)
+ /* WATCHOUT: we rely on the fact that growing the array adds PLACEHOLDERS at the end */
+ return FLAC__metadata_object_seektable_resize_points(object, object->data.seek_table.num_points + num);
+ else
+ return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_point(FLAC__StreamMetadata *object, FLAC__uint64 sample_number)
+{
+ FLAC__StreamMetadata_SeekTable *seek_table;
+
+ seek_table = &object->data.seek_table;
+
+ if (!FLAC__metadata_object_seektable_resize_points(object, seek_table->num_points + 1))
+ return false;
+
+ seek_table->points[seek_table->num_points - 1].sample_number = sample_number;
+ seek_table->points[seek_table->num_points - 1].stream_offset = 0;
+ seek_table->points[seek_table->num_points - 1].frame_samples = 0;
+
+ return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_points(FLAC__StreamMetadata *object, FLAC__uint64 sample_numbers[], uint32_t num)
+{
+ if (num > 0) {
+ FLAC__StreamMetadata_SeekTable *seek_table = &object->data.seek_table;
+ uint32_t i, j;
+
+ i = seek_table->num_points;
+
+ if (!FLAC__metadata_object_seektable_resize_points(object, seek_table->num_points + num))
+ return false;
+
+ for (j = 0; j < num; i++, j++) {
+ seek_table->points[i].sample_number = sample_numbers[j];
+ seek_table->points[i].stream_offset = 0;
+ seek_table->points[i].frame_samples = 0;
+ }
+ }
+
+ return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_spaced_points(FLAC__StreamMetadata *object, uint32_t num, FLAC__uint64 total_samples)
+{
+ if (num > 0 && total_samples > 0) {
+ FLAC__StreamMetadata_SeekTable *seek_table = &object->data.seek_table;
+ uint32_t i, j;
+
+ i = seek_table->num_points;
+
+ if (!FLAC__metadata_object_seektable_resize_points(object, seek_table->num_points + num))
+ return false;
+
+ for (j = 0; j < num; i++, j++) {
+ seek_table->points[i].sample_number = total_samples * (FLAC__uint64)j / (FLAC__uint64)num;
+ seek_table->points[i].stream_offset = 0;
+ seek_table->points[i].frame_samples = 0;
+ }
+ }
+
+ return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_spaced_points_by_samples(FLAC__StreamMetadata *object, uint32_t samples, FLAC__uint64 total_samples)
+{
+ if (samples > 0 && total_samples > 0) {
+ FLAC__StreamMetadata_SeekTable *seek_table = &object->data.seek_table;
+ uint32_t i, j;
+ FLAC__uint64 num, sample;
+
+ num = 1 + total_samples / samples; /* 1+ for the first sample at 0 */
+ /* now account for the fact that we don't place a seekpoint at "total_samples" since samples are number from 0: */
+ if (total_samples % samples == 0)
+ num--;
+
+ /* Put a strict upper bound on the number of allowed seek points. */
+ if (num > 32768) {
+ /* Set the bound and recalculate samples accordingly. */
+ num = 32768;
+ samples = (uint32_t)(total_samples / num);
+ }
+
+ i = seek_table->num_points;
+
+ if (!FLAC__metadata_object_seektable_resize_points(object, seek_table->num_points + (uint32_t)num))
+ return false;
+
+ sample = 0;
+ for (j = 0; j < num; i++, j++, sample += samples) {
+ seek_table->points[i].sample_number = sample;
+ seek_table->points[i].stream_offset = 0;
+ seek_table->points[i].frame_samples = 0;
+ }
+ }
+
+ return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_sort(FLAC__StreamMetadata *object, FLAC__bool compact)
+{
+ uint32_t unique;
+
+ unique = FLAC__format_seektable_sort(&object->data.seek_table);
+
+ return !compact || FLAC__metadata_object_seektable_resize_points(object, unique);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_set_vendor_string(FLAC__StreamMetadata *object, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy)
+{
+ if (!FLAC__format_vorbiscomment_entry_value_is_legal(entry.entry, entry.length))
+ return false;
+ return vorbiscomment_set_entry_(object, &object->data.vorbis_comment.vendor_string, &entry, copy);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_resize_comments(FLAC__StreamMetadata *object, uint32_t new_num_comments)
+{
+ if (object->data.vorbis_comment.comments == NULL) {
+ if (new_num_comments == 0)
+ return true;
+ else if ((object->data.vorbis_comment.comments = vorbiscomment_entry_array_new_(new_num_comments)) == NULL)
+ return false;
+ }
+ else {
+ const size_t old_size = object->data.vorbis_comment.num_comments * sizeof(FLAC__StreamMetadata_VorbisComment_Entry);
+ const size_t new_size = new_num_comments * sizeof(FLAC__StreamMetadata_VorbisComment_Entry);
+
+ /* overflow check */
+ if (new_num_comments > UINT32_MAX / sizeof(FLAC__StreamMetadata_VorbisComment_Entry))
+ return false;
+
+ /* if shrinking, free the truncated entries */
+ if (new_num_comments < object->data.vorbis_comment.num_comments) {
+ uint32_t i;
+ for (i = new_num_comments; i < object->data.vorbis_comment.num_comments; i++)
+ if (object->data.vorbis_comment.comments[i].entry != NULL)
+ free(object->data.vorbis_comment.comments[i].entry);
+ }
+
+ if (new_size == 0) {
+ free(object->data.vorbis_comment.comments);
+ object->data.vorbis_comment.comments = 0;
+ }
+ else {
+ FLAC__StreamMetadata_VorbisComment_Entry *oldptr = object->data.vorbis_comment.comments;
+ if ((object->data.vorbis_comment.comments = realloc(object->data.vorbis_comment.comments, new_size)) == NULL) {
+ vorbiscomment_entry_array_delete_(oldptr, object->data.vorbis_comment.num_comments);
+ object->data.vorbis_comment.num_comments = 0;
+ return false;
+ }
+ }
+
+ /* if growing, zero all the length/pointers of new elements */
+ if (new_size > old_size)
+ memset(object->data.vorbis_comment.comments + object->data.vorbis_comment.num_comments, 0, new_size - old_size);
+ }
+
+ object->data.vorbis_comment.num_comments = new_num_comments;
+
+ vorbiscomment_calculate_length_(object);
+ return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_set_comment(FLAC__StreamMetadata *object, uint32_t comment_num, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy)
+{
+ if (!FLAC__format_vorbiscomment_entry_is_legal(entry.entry, entry.length))
+ return false;
+ return vorbiscomment_set_entry_(object, &object->data.vorbis_comment.comments[comment_num], &entry, copy);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_insert_comment(FLAC__StreamMetadata *object, uint32_t comment_num, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy)
+{
+ FLAC__StreamMetadata_VorbisComment *vc;
+
+ if (!FLAC__format_vorbiscomment_entry_is_legal(entry.entry, entry.length))
+ return false;
+
+ vc = &object->data.vorbis_comment;
+
+ if (!FLAC__metadata_object_vorbiscomment_resize_comments(object, vc->num_comments+1))
+ return false;
+
+ /* move all comments >= comment_num forward one space */
+ memmove(&vc->comments[comment_num+1], &vc->comments[comment_num], sizeof(FLAC__StreamMetadata_VorbisComment_Entry)*(vc->num_comments-1-comment_num));
+ vc->comments[comment_num].length = 0;
+ vc->comments[comment_num].entry = 0;
+
+ return FLAC__metadata_object_vorbiscomment_set_comment(object, comment_num, entry, copy);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_append_comment(FLAC__StreamMetadata *object, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy)
+{
+ return FLAC__metadata_object_vorbiscomment_insert_comment(object, object->data.vorbis_comment.num_comments, entry, copy);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_replace_comment(FLAC__StreamMetadata *object, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool all, FLAC__bool copy)
+{
+ if (!FLAC__format_vorbiscomment_entry_is_legal(entry.entry, entry.length))
+ return false;
+
+ {
+ int i;
+ size_t field_name_length;
+ const FLAC__byte *eq = (FLAC__byte*)memchr(entry.entry, '=', entry.length);
+
+ if (eq == NULL)
+ return false; /* double protection */
+
+ field_name_length = eq-entry.entry;
+
+ i = vorbiscomment_find_entry_from_(object, 0, (const char *)entry.entry, (uint32_t)field_name_length);
+ if (i >= 0) {
+ uint32_t indx = (uint32_t)i;
+ if (!FLAC__metadata_object_vorbiscomment_set_comment(object, indx, entry, copy))
+ return false;
+ entry = object->data.vorbis_comment.comments[indx];
+ indx++; /* skip over replaced comment */
+ if (all && indx < object->data.vorbis_comment.num_comments) {
+ i = vorbiscomment_find_entry_from_(object, indx, (const char *)entry.entry, (uint32_t)field_name_length);
+ while (i >= 0) {
+ indx = (uint32_t)i;
+ if (!FLAC__metadata_object_vorbiscomment_delete_comment(object, indx))
+ return false;
+ if (indx < object->data.vorbis_comment.num_comments)
+ i = vorbiscomment_find_entry_from_(object, indx, (const char *)entry.entry, (uint32_t)field_name_length);
+ else
+ i = -1;
+ }
+ }
+ return true;
+ }
+ else
+ return FLAC__metadata_object_vorbiscomment_append_comment(object, entry, copy);
+ }
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_delete_comment(FLAC__StreamMetadata *object, uint32_t comment_num)
+{
+ FLAC__StreamMetadata_VorbisComment *vc;
+
+ vc = &object->data.vorbis_comment;
+
+ /* free the comment at comment_num */
+ free(vc->comments[comment_num].entry);
+
+ /* move all comments > comment_num backward one space */
+ memmove(&vc->comments[comment_num], &vc->comments[comment_num+1], sizeof(FLAC__StreamMetadata_VorbisComment_Entry)*(vc->num_comments-comment_num-1));
+ vc->comments[vc->num_comments-1].length = 0;
+ vc->comments[vc->num_comments-1].entry = 0;
+
+ return FLAC__metadata_object_vorbiscomment_resize_comments(object, vc->num_comments-1);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(FLAC__StreamMetadata_VorbisComment_Entry *entry, const char *field_name, const char *field_value)
+{
+ if (!FLAC__format_vorbiscomment_entry_name_is_legal(field_name))
+ return false;
+ if (!FLAC__format_vorbiscomment_entry_value_is_legal((const FLAC__byte *)field_value, (uint32_t)(-1)))
+ return false;
+
+ {
+ const size_t nn = strlen(field_name);
+ const size_t nv = strlen(field_value);
+ entry->length = (FLAC__uint32)(nn + 1 /*=*/ + nv);
+ if ((entry->entry = safe_malloc_add_4op_(nn, /*+*/1, /*+*/nv, /*+*/1)) == NULL)
+ return false;
+ memcpy(entry->entry, field_name, nn);
+ entry->entry[nn] = '=';
+ memcpy(entry->entry+nn+1, field_value, nv);
+ entry->entry[entry->length] = '\0';
+ }
+
+ return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_entry_to_name_value_pair(const FLAC__StreamMetadata_VorbisComment_Entry entry, char **field_name, char **field_value)
+{
+ if (!FLAC__format_vorbiscomment_entry_is_legal(entry.entry, entry.length))
+ return false;
+
+ {
+ const FLAC__byte *eq = (FLAC__byte*)memchr(entry.entry, '=', entry.length);
+ const size_t nn = eq-entry.entry;
+ const size_t nv = entry.length-nn-1; /* -1 for the '=' */
+
+ if (eq == NULL)
+ return false; /* double protection */
+ if ((*field_name = safe_malloc_add_2op_(nn, /*+*/1)) == NULL)
+ return false;
+ if ((*field_value = safe_malloc_add_2op_(nv, /*+*/1)) == NULL) {
+ free(*field_name);
+ return false;
+ }
+ memcpy(*field_name, entry.entry, nn);
+ memcpy(*field_value, entry.entry+nn+1, nv);
+ (*field_name)[nn] = '\0';
+ (*field_value)[nv] = '\0';
+ }
+
+ return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_entry_matches(const FLAC__StreamMetadata_VorbisComment_Entry entry, const char *field_name, uint32_t field_name_length)
+{
+ const FLAC__byte *eq = (FLAC__byte*)memchr(entry.entry, '=', entry.length);
+ return (eq != NULL && (uint32_t)(eq-entry.entry) == field_name_length && FLAC__STRNCASECMP(field_name, (const char *)entry.entry, field_name_length) == 0);
+}
+
+FLAC_API int FLAC__metadata_object_vorbiscomment_find_entry_from(const FLAC__StreamMetadata *object, uint32_t offset, const char *field_name)
+{
+ return vorbiscomment_find_entry_from_(object, offset, field_name, (uint32_t)strlen(field_name));
+}
+
+FLAC_API int FLAC__metadata_object_vorbiscomment_remove_entry_matching(FLAC__StreamMetadata *object, const char *field_name)
+{
+ const uint32_t field_name_length = (const uint32_t)strlen(field_name);
+ uint32_t i;
+
+ for (i = 0; i < object->data.vorbis_comment.num_comments; i++) {
+ if (FLAC__metadata_object_vorbiscomment_entry_matches(object->data.vorbis_comment.comments[i], field_name, field_name_length)) {
+ if (!FLAC__metadata_object_vorbiscomment_delete_comment(object, i))
+ return -1;
+ else
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+FLAC_API int FLAC__metadata_object_vorbiscomment_remove_entries_matching(FLAC__StreamMetadata *object, const char *field_name)
+{
+ FLAC__bool ok = true;
+ uint32_t matching = 0;
+ const uint32_t field_name_length = (const uint32_t)strlen(field_name);
+ int i;
+
+ /* must delete from end to start otherwise it will interfere with our iteration */
+ for (i = (int)object->data.vorbis_comment.num_comments - 1; ok && i >= 0; i--) {
+ if (FLAC__metadata_object_vorbiscomment_entry_matches(object->data.vorbis_comment.comments[i], field_name, field_name_length)) {
+ matching++;
+ ok &= FLAC__metadata_object_vorbiscomment_delete_comment(object, (uint32_t)i);
+ }
+ }
+
+ return ok? (int)matching : -1;
+}
+
+FLAC_API FLAC__StreamMetadata_CueSheet_Track *FLAC__metadata_object_cuesheet_track_new(void)
+{
+ return calloc(1, sizeof(FLAC__StreamMetadata_CueSheet_Track));
+}
+
+FLAC_API FLAC__StreamMetadata_CueSheet_Track *FLAC__metadata_object_cuesheet_track_clone(const FLAC__StreamMetadata_CueSheet_Track *object)
+{
+ FLAC__StreamMetadata_CueSheet_Track *to;
+
+ if ((to = FLAC__metadata_object_cuesheet_track_new()) != NULL) {
+ if (!copy_track_(to, object)) {
+ FLAC__metadata_object_cuesheet_track_delete(to);
+ return 0;
+ }
+ }
+
+ return to;
+}
+
+void FLAC__metadata_object_cuesheet_track_delete_data(FLAC__StreamMetadata_CueSheet_Track *object)
+{
+ if (object->indices != NULL) {
+ free(object->indices);
+ }
+}
+
+FLAC_API void FLAC__metadata_object_cuesheet_track_delete(FLAC__StreamMetadata_CueSheet_Track *object)
+{
+ FLAC__metadata_object_cuesheet_track_delete_data(object);
+ free(object);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_resize_indices(FLAC__StreamMetadata *object, uint32_t track_num, uint32_t new_num_indices)
+{
+ FLAC__StreamMetadata_CueSheet_Track *track;
+
+ track = &object->data.cue_sheet.tracks[track_num];
+
+ if (track->indices == NULL) {
+ if (new_num_indices == 0)
+ return true;
+ else if ((track->indices = cuesheet_track_index_array_new_(new_num_indices)) == NULL)
+ return false;
+ }
+ else {
+ const size_t old_size = track->num_indices * sizeof(FLAC__StreamMetadata_CueSheet_Index);
+ const size_t new_size = new_num_indices * sizeof(FLAC__StreamMetadata_CueSheet_Index);
+
+ /* overflow check */
+ if (new_num_indices > UINT32_MAX / sizeof(FLAC__StreamMetadata_CueSheet_Index))
+ return false;
+
+ if (new_size == 0) {
+ free(track->indices);
+ track->indices = 0;
+ }
+ else if ((track->indices = safe_realloc_(track->indices, new_size)) == NULL)
+ return false;
+
+ /* if growing, zero all the lengths/pointers of new elements */
+ if (new_size > old_size)
+ memset(track->indices + track->num_indices, 0, new_size - old_size);
+ }
+
+ track->num_indices = (FLAC__byte)new_num_indices;
+
+ cuesheet_calculate_length_(object);
+ return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_insert_index(FLAC__StreamMetadata *object, uint32_t track_num, uint32_t index_num, FLAC__StreamMetadata_CueSheet_Index indx)
+{
+ FLAC__StreamMetadata_CueSheet_Track *track;
+
+ track = &object->data.cue_sheet.tracks[track_num];
+
+ if (!FLAC__metadata_object_cuesheet_track_resize_indices(object, track_num, track->num_indices+1))
+ return false;
+
+ /* move all indices >= index_num forward one space */
+ memmove(&track->indices[index_num+1], &track->indices[index_num], sizeof(FLAC__StreamMetadata_CueSheet_Index)*(track->num_indices-1-index_num));
+
+ track->indices[index_num] = indx;
+ cuesheet_calculate_length_(object);
+ return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_insert_blank_index(FLAC__StreamMetadata *object, uint32_t track_num, uint32_t index_num)
+{
+ FLAC__StreamMetadata_CueSheet_Index indx;
+ memset(&indx, 0, sizeof(indx));
+ return FLAC__metadata_object_cuesheet_track_insert_index(object, track_num, index_num, indx);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_delete_index(FLAC__StreamMetadata *object, uint32_t track_num, uint32_t index_num)
+{
+ FLAC__StreamMetadata_CueSheet_Track *track;
+
+ track = &object->data.cue_sheet.tracks[track_num];
+
+ /* move all indices > index_num backward one space */
+ memmove(&track->indices[index_num], &track->indices[index_num+1], sizeof(FLAC__StreamMetadata_CueSheet_Index)*(track->num_indices-index_num-1));
+
+ FLAC__metadata_object_cuesheet_track_resize_indices(object, track_num, track->num_indices-1);
+ cuesheet_calculate_length_(object);
+ return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_resize_tracks(FLAC__StreamMetadata *object, uint32_t new_num_tracks)
+{
+ if (object->data.cue_sheet.tracks == NULL) {
+ if (new_num_tracks == 0)
+ return true;
+ else if ((object->data.cue_sheet.tracks = cuesheet_track_array_new_(new_num_tracks)) == NULL)
+ return false;
+ }
+ else {
+ const size_t old_size = object->data.cue_sheet.num_tracks * sizeof(FLAC__StreamMetadata_CueSheet_Track);
+ const size_t new_size = new_num_tracks * sizeof(FLAC__StreamMetadata_CueSheet_Track);
+
+ /* overflow check */
+ if (new_num_tracks > UINT32_MAX / sizeof(FLAC__StreamMetadata_CueSheet_Track))
+ return false;
+
+ /* if shrinking, free the truncated entries */
+ if (new_num_tracks < object->data.cue_sheet.num_tracks) {
+ uint32_t i;
+ for (i = new_num_tracks; i < object->data.cue_sheet.num_tracks; i++)
+ free(object->data.cue_sheet.tracks[i].indices);
+ }
+
+ if (new_size == 0) {
+ free(object->data.cue_sheet.tracks);
+ object->data.cue_sheet.tracks = 0;
+ }
+ else if ((object->data.cue_sheet.tracks = safe_realloc_(object->data.cue_sheet.tracks, new_size)) == NULL)
+ return false;
+
+ /* if growing, zero all the lengths/pointers of new elements */
+ if (new_size > old_size)
+ memset(object->data.cue_sheet.tracks + object->data.cue_sheet.num_tracks, 0, new_size - old_size);
+ }
+
+ object->data.cue_sheet.num_tracks = new_num_tracks;
+
+ cuesheet_calculate_length_(object);
+ return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_set_track(FLAC__StreamMetadata *object, uint32_t track_num, FLAC__StreamMetadata_CueSheet_Track *track, FLAC__bool copy)
+{
+ return cuesheet_set_track_(object, object->data.cue_sheet.tracks + track_num, track, copy);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_insert_track(FLAC__StreamMetadata *object, uint32_t track_num, FLAC__StreamMetadata_CueSheet_Track *track, FLAC__bool copy)
+{
+ FLAC__StreamMetadata_CueSheet *cs;
+
+ cs = &object->data.cue_sheet;
+
+ if (!FLAC__metadata_object_cuesheet_resize_tracks(object, cs->num_tracks+1))
+ return false;
+
+ /* move all tracks >= track_num forward one space */
+ memmove(&cs->tracks[track_num+1], &cs->tracks[track_num], sizeof(FLAC__StreamMetadata_CueSheet_Track)*(cs->num_tracks-1-track_num));
+ cs->tracks[track_num].num_indices = 0;
+ cs->tracks[track_num].indices = 0;
+
+ return FLAC__metadata_object_cuesheet_set_track(object, track_num, track, copy);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_insert_blank_track(FLAC__StreamMetadata *object, uint32_t track_num)
+{
+ FLAC__StreamMetadata_CueSheet_Track track;
+ memset(&track, 0, sizeof(track));
+ return FLAC__metadata_object_cuesheet_insert_track(object, track_num, &track, /*copy=*/false);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_delete_track(FLAC__StreamMetadata *object, uint32_t track_num)
+{
+ FLAC__StreamMetadata_CueSheet *cs;
+
+ cs = &object->data.cue_sheet;
+
+ /* free the track at track_num */
+ free(cs->tracks[track_num].indices);
+
+ /* move all tracks > track_num backward one space */
+ memmove(&cs->tracks[track_num], &cs->tracks[track_num+1], sizeof(FLAC__StreamMetadata_CueSheet_Track)*(cs->num_tracks-track_num-1));
+ cs->tracks[cs->num_tracks-1].num_indices = 0;
+ cs->tracks[cs->num_tracks-1].indices = 0;
+
+ return FLAC__metadata_object_cuesheet_resize_tracks(object, cs->num_tracks-1);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_is_legal(const FLAC__StreamMetadata *object, FLAC__bool check_cd_da_subset, const char **violation)
+{
+ return FLAC__format_cuesheet_is_legal(&object->data.cue_sheet, check_cd_da_subset, violation);
+}
+
+static FLAC__uint64 get_index_01_offset_(const FLAC__StreamMetadata_CueSheet *cs, uint32_t track)
+{
+ if (track >= (cs->num_tracks-1) || cs->tracks[track].num_indices < 1)
+ return 0;
+ else if (cs->tracks[track].indices[0].number == 1)
+ return cs->tracks[track].indices[0].offset + cs->tracks[track].offset + cs->lead_in;
+ else if (cs->tracks[track].num_indices < 2)
+ return 0;
+ else if (cs->tracks[track].indices[1].number == 1)
+ return cs->tracks[track].indices[1].offset + cs->tracks[track].offset + cs->lead_in;
+ else
+ return 0;
+}
+
+static FLAC__uint32 cddb_add_digits_(FLAC__uint32 x)
+{
+ FLAC__uint32 n = 0;
+ while (x) {
+ n += (x%10);
+ x /= 10;
+ }
+ return n;
+}
+
+/*@@@@add to tests*/
+FLAC_API FLAC__uint32 FLAC__metadata_object_cuesheet_calculate_cddb_id(const FLAC__StreamMetadata *object)
+{
+ const FLAC__StreamMetadata_CueSheet *cs;
+
+ cs = &object->data.cue_sheet;
+
+ if (cs->num_tracks < 2) /* need at least one real track and the lead-out track */
+ return 0;
+
+ {
+ FLAC__uint32 i, length, sum = 0;
+ for (i = 0; i < (cs->num_tracks-1); i++) /* -1 to avoid counting the lead-out */
+ sum += cddb_add_digits_((FLAC__uint32)(get_index_01_offset_(cs, i) / 44100));
+ length = (FLAC__uint32)((cs->tracks[cs->num_tracks-1].offset+cs->lead_in) / 44100) - (FLAC__uint32)(get_index_01_offset_(cs, 0) / 44100);
+
+ return (sum % 0xFF) << 24 | length << 8 | (FLAC__uint32)(cs->num_tracks-1);
+ }
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_picture_set_mime_type(FLAC__StreamMetadata *object, char *mime_type, FLAC__bool copy)
+{
+ char *old;
+ size_t old_length, new_length;
+
+ old = object->data.picture.mime_type;
+ old_length = old? strlen(old) : 0;
+ new_length = strlen(mime_type);
+
+ /* do the copy first so that if we fail we leave the object untouched */
+ if (copy) {
+ if (new_length >= SIZE_MAX) /* overflow check */
+ return false;
+ if (!copy_bytes_((FLAC__byte**)(&object->data.picture.mime_type), (FLAC__byte*)mime_type, (uint32_t)(new_length+1)))
+ return false;
+ }
+ else {
+ object->data.picture.mime_type = mime_type;
+ }
+
+ free(old);
+
+ object->length -= (uint32_t)old_length;
+ object->length += (uint32_t)new_length;
+ return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_picture_set_description(FLAC__StreamMetadata *object, FLAC__byte *description, FLAC__bool copy)
+{
+ FLAC__byte *old;
+ size_t old_length, new_length;
+
+ old = object->data.picture.description;
+ old_length = old? strlen((const char *)old) : 0;
+ new_length = strlen((const char *)description);
+
+ /* do the copy first so that if we fail we leave the object untouched */
+ if (copy) {
+ if (new_length >= SIZE_MAX) /* overflow check */
+ return false;
+ if (!copy_bytes_(&object->data.picture.description, description, (uint32_t)(new_length+1)))
+ return false;
+ }
+ else {
+ object->data.picture.description = description;
+ }
+
+ free(old);
+
+ object->length -= (uint32_t)old_length;
+ object->length += (uint32_t)new_length;
+ return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_picture_set_data(FLAC__StreamMetadata *object, FLAC__byte *data, FLAC__uint32 length, FLAC__bool copy)
+{
+ FLAC__byte *old;
+
+ old = object->data.picture.data;
+
+ /* do the copy first so that if we fail we leave the object untouched */
+ if (copy) {
+ if (!copy_bytes_(&object->data.picture.data, data, length))
+ return false;
+ }
+ else {
+ object->data.picture.data = data;
+ }
+
+ free(old);
+
+ object->length -= object->data.picture.data_length;
+ object->data.picture.data_length = length;
+ object->length += length;
+ return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_picture_is_legal(const FLAC__StreamMetadata *object, const char **violation)
+{
+ return FLAC__format_picture_is_legal(&object->data.picture, violation);
+}
--- /dev/null
+++ b/src/libflac/private/bitmath.h
@@ -1,0 +1,205 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2001-2009 Josh Coalson
+ * Copyright (C) 2011-2016 Xiph.Org Foundation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__PRIVATE__BITMATH_H
+#define FLAC__PRIVATE__BITMATH_H
+
+#include "../FLAC/ordinals.h"
+
+#include "../share/compat.h"
+
+#if defined(_MSC_VER)
+#include <intrin.h> /* for _BitScanReverse* */
+#endif
+
+/* Will never be emitted for MSVC, GCC, Intel compilers */
+static inline uint32_t FLAC__clz_soft_uint32(FLAC__uint32 word)
+{
+ static const uint8_t byte_to_unary_table[] = {
+ 8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ };
+
+ return word > 0xffffff ? byte_to_unary_table[word >> 24] :
+ word > 0xffff ? byte_to_unary_table[word >> 16] + 8 :
+ word > 0xff ? byte_to_unary_table[word >> 8] + 16 :
+ byte_to_unary_table[word] + 24;
+}
+
+static inline uint32_t FLAC__clz_uint32(FLAC__uint32 v)
+{
+/* Never used with input 0 */
+#if defined(__INTEL_COMPILER)
+ return _bit_scan_reverse(v) ^ 31U;
+#elif defined(__GNUC__) && (__GNUC__ >= 4 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4))
+/* This will translate either to (bsr ^ 31U), clz , ctlz, cntlz, lzcnt depending on
+ * -march= setting or to a software routine in exotic machines. */
+ return __builtin_clz(v);
+#elif defined(_MSC_VER)
+ {
+ DWORD idx;
+ _BitScanReverse(&idx, v);
+ return (uint32_t)(idx ^ 31U);
+ }
+#else
+ return FLAC__clz_soft_uint32(v);
+#endif
+}
+
+/* Used when 64-bit bsr/clz is unavailable; can use 32-bit bsr/clz when possible */
+static inline uint32_t FLAC__clz_soft_uint64(FLAC__uint64 word)
+{
+ return (FLAC__uint32)(word>>32) ? FLAC__clz_uint32((FLAC__uint32)(word>>32)) :
+ FLAC__clz_uint32((FLAC__uint32)word) + 32;
+}
+
+static inline uint32_t FLAC__clz_uint64(FLAC__uint64 v)
+{
+ /* Never used with input 0 */
+#if defined(__GNUC__) && (__GNUC__ >= 4 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4))
+ return __builtin_clzll(v);
+#elif (defined(__INTEL_COMPILER) || defined(_MSC_VER)) && (defined(_M_IA64) || defined(_M_X64))
+ {
+ DWORD idx;
+ _BitScanReverse64(&idx, v);
+ return (uint32_t)(idx ^ 63U);
+ }
+#else
+ return FLAC__clz_soft_uint64(v);
+#endif
+}
+
+/* These two functions work with input 0 */
+static inline uint32_t FLAC__clz2_uint32(FLAC__uint32 v)
+{
+ if (!v)
+ return 32;
+ return FLAC__clz_uint32(v);
+}
+
+static inline uint32_t FLAC__clz2_uint64(FLAC__uint64 v)
+{
+ if (!v)
+ return 64;
+ return FLAC__clz_uint64(v);
+}
+
+/* An example of what FLAC__bitmath_ilog2() computes:
+ *
+ * ilog2( 0) = assertion failure
+ * ilog2( 1) = 0
+ * ilog2( 2) = 1
+ * ilog2( 3) = 1
+ * ilog2( 4) = 2
+ * ilog2( 5) = 2
+ * ilog2( 6) = 2
+ * ilog2( 7) = 2
+ * ilog2( 8) = 3
+ * ilog2( 9) = 3
+ * ilog2(10) = 3
+ * ilog2(11) = 3
+ * ilog2(12) = 3
+ * ilog2(13) = 3
+ * ilog2(14) = 3
+ * ilog2(15) = 3
+ * ilog2(16) = 4
+ * ilog2(17) = 4
+ * ilog2(18) = 4
+ */
+
+static inline uint32_t FLAC__bitmath_ilog2(FLAC__uint32 v)
+{
+#if defined(__INTEL_COMPILER)
+ return _bit_scan_reverse(v);
+#elif defined(_MSC_VER)
+ {
+ DWORD idx;
+ _BitScanReverse(&idx, v);
+ return (uint32_t)idx;
+ }
+#else
+ return FLAC__clz_uint32(v) ^ 31U;
+#endif
+}
+
+static inline uint32_t FLAC__bitmath_ilog2_wide(FLAC__uint64 v)
+{
+#if defined(__GNUC__) && (__GNUC__ >= 4 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4))
+ return __builtin_clzll(v) ^ 63U;
+/* Sorry, only supported in x64/Itanium.. and both have fast FPU which makes integer-only encoder pointless */
+#elif (defined(__INTEL_COMPILER) || defined(_MSC_VER)) && (defined(_M_IA64) || defined(_M_X64))
+ {
+ DWORD idx;
+ _BitScanReverse64(&idx, v);
+ return (uint32_t)idx;
+ }
+#else
+/* Brain-damaged compilers will use the fastest possible way that is,
+ de Bruijn sequences (http://supertech.csail.mit.edu/papers/debruijn.pdf)
+ (C) Timothy B. Terriberry (tterribe@xiph.org) 2001-2009 CC0 (Public domain).
+*/
+ {
+ static const uint8_t DEBRUIJN_IDX64[64]={
+ 0, 1, 2, 7, 3,13, 8,19, 4,25,14,28, 9,34,20,40,
+ 5,17,26,38,15,46,29,48,10,31,35,54,21,50,41,57,
+ 63, 6,12,18,24,27,33,39,16,37,45,47,30,53,49,56,
+ 62,11,23,32,36,44,52,55,61,22,43,51,60,42,59,58
+ };
+ v|= v>>1;
+ v|= v>>2;
+ v|= v>>4;
+ v|= v>>8;
+ v|= v>>16;
+ v|= v>>32;
+ v= (v>>1)+1;
+ return DEBRUIJN_IDX64[v*FLAC__U64L(0x218A392CD3D5DBF)>>58&0x3F];
+ }
+#endif
+}
+
+uint32_t FLAC__bitmath_silog2(FLAC__int64 v);
+
+#endif
--- /dev/null
+++ b/src/libflac/private/bitreader.h
@@ -1,0 +1,90 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000-2009 Josh Coalson
+ * Copyright (C) 2011-2016 Xiph.Org Foundation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__PRIVATE__BITREADER_H
+#define FLAC__PRIVATE__BITREADER_H
+
+#include <stdio.h> /* for FILE */
+#include "../FLAC/ordinals.h"
+
+/*
+ * opaque structure definition
+ */
+struct FLAC__BitReader;
+typedef struct FLAC__BitReader FLAC__BitReader;
+
+typedef FLAC__bool (*FLAC__BitReaderReadCallback)(FLAC__byte buffer[], size_t *bytes, void *client_data);
+
+/*
+ * construction, deletion, initialization, etc functions
+ */
+FLAC__BitReader *FLAC__bitreader_new(void);
+void FLAC__bitreader_delete(FLAC__BitReader *br);
+FLAC__bool FLAC__bitreader_init(FLAC__BitReader *br, FLAC__BitReaderReadCallback rcb, void *cd);
+void FLAC__bitreader_free(FLAC__BitReader *br); /* does not 'free(br)' */
+FLAC__bool FLAC__bitreader_clear(FLAC__BitReader *br);
+void FLAC__bitreader_dump(const FLAC__BitReader *br, FILE *out);
+
+/*
+ * CRC functions
+ */
+void FLAC__bitreader_reset_read_crc16(FLAC__BitReader *br, FLAC__uint16 seed);
+FLAC__uint16 FLAC__bitreader_get_read_crc16(FLAC__BitReader *br);
+
+/*
+ * info functions
+ */
+FLAC__bool FLAC__bitreader_is_consumed_byte_aligned(const FLAC__BitReader *br);
+uint32_t FLAC__bitreader_bits_left_for_byte_alignment(const FLAC__BitReader *br);
+uint32_t FLAC__bitreader_get_input_bits_unconsumed(const FLAC__BitReader *br);
+
+/*
+ * read functions
+ */
+
+FLAC__bool FLAC__bitreader_read_raw_uint32(FLAC__BitReader *br, FLAC__uint32 *val, uint32_t bits);
+FLAC__bool FLAC__bitreader_read_raw_int32(FLAC__BitReader *br, FLAC__int32 *val, uint32_t bits);
+FLAC__bool FLAC__bitreader_read_raw_uint64(FLAC__BitReader *br, FLAC__uint64 *val, uint32_t bits);
+FLAC__bool FLAC__bitreader_read_uint32_little_endian(FLAC__BitReader *br, FLAC__uint32 *val); /*only for bits=32*/
+FLAC__bool FLAC__bitreader_skip_bits_no_crc(FLAC__BitReader *br, uint32_t bits); /* WATCHOUT: does not CRC the skipped data! */ /*@@@@ add to unit tests */
+FLAC__bool FLAC__bitreader_skip_byte_block_aligned_no_crc(FLAC__BitReader *br, uint32_t nvals); /* WATCHOUT: does not CRC the read data! */
+FLAC__bool FLAC__bitreader_read_byte_block_aligned_no_crc(FLAC__BitReader *br, FLAC__byte *val, uint32_t nvals); /* WATCHOUT: does not CRC the read data! */
+FLAC__bool FLAC__bitreader_read_unary_unsigned(FLAC__BitReader *br, uint32_t *val);
+FLAC__bool FLAC__bitreader_read_rice_signed(FLAC__BitReader *br, int *val, uint32_t parameter);
+FLAC__bool FLAC__bitreader_read_rice_signed_block(FLAC__BitReader *br, int vals[], uint32_t nvals, uint32_t parameter);
+#if 0 /* UNUSED */
+FLAC__bool FLAC__bitreader_read_golomb_signed(FLAC__BitReader *br, int *val, uint32_t parameter);
+FLAC__bool FLAC__bitreader_read_golomb_unsigned(FLAC__BitReader *br, uint32_t *val, uint32_t parameter);
+#endif
+FLAC__bool FLAC__bitreader_read_utf8_uint32(FLAC__BitReader *br, FLAC__uint32 *val, FLAC__byte *raw, uint32_t *rawlen);
+FLAC__bool FLAC__bitreader_read_utf8_uint64(FLAC__BitReader *br, FLAC__uint64 *val, FLAC__byte *raw, uint32_t *rawlen);
+#endif
--- /dev/null
+++ b/src/libflac/private/crc.h
@@ -1,0 +1,60 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000-2009 Josh Coalson
+ * Copyright (C) 2011-2018 Xiph.Org Foundation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__PRIVATE__CRC_H
+#define FLAC__PRIVATE__CRC_H
+
+#include "../FLAC/ordinals.h"
+
+/* 8 bit CRC generator, MSB shifted first
+** polynomial = x^8 + x^2 + x^1 + x^0
+** init = 0
+*/
+FLAC__uint8 FLAC__crc8(const FLAC__byte *data, uint32_t len);
+
+/* 16 bit CRC generator, MSB shifted first
+** polynomial = x^16 + x^15 + x^2 + x^0
+** init = 0
+*/
+extern FLAC__uint16 const FLAC__crc16_table[8][256];
+
+#define FLAC__CRC16_UPDATE(data, crc) ((((crc)<<8) & 0xffff) ^ FLAC__crc16_table[0][((crc)>>8) ^ (data)])
+/* this alternate may be faster on some systems/compilers */
+#if 0
+#define FLAC__CRC16_UPDATE(data, crc) ((((crc)<<8) ^ FLAC__crc16_table[0][((crc)>>8) ^ (data)]) & 0xffff)
+#endif
+
+FLAC__uint16 FLAC__crc16(const FLAC__byte *data, uint32_t len);
+FLAC__uint16 FLAC__crc16_update_words32(const FLAC__uint32 *words, uint32_t len, FLAC__uint16 crc);
+FLAC__uint16 FLAC__crc16_update_words64(const FLAC__uint64 *words, uint32_t len, FLAC__uint16 crc);
+
+#endif
--- /dev/null
+++ b/src/libflac/private/fixed.h
@@ -1,0 +1,82 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000-2009 Josh Coalson
+ * Copyright (C) 2011-2016 Xiph.Org Foundation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__PRIVATE__FIXED_H
+#define FLAC__PRIVATE__FIXED_H
+
+#include "../private/float.h"
+#include "../FLAC/format.h"
+
+/*
+ * FLAC__fixed_compute_best_predictor()
+ * --------------------------------------------------------------------
+ * Compute the best fixed predictor and the expected bits-per-sample
+ * of the residual signal for each order. The _wide() version uses
+ * 64-bit integers which is statistically necessary when bits-per-
+ * sample + log2(blocksize) > 30
+ *
+ * IN data[0,data_len-1]
+ * IN data_len
+ * OUT residual_bits_per_sample[0,FLAC__MAX_FIXED_ORDER]
+ */
+uint32_t FLAC__fixed_compute_best_predictor(const FLAC__int32 data[], uint32_t data_len, float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]);
+uint32_t FLAC__fixed_compute_best_predictor_wide(const FLAC__int32 data[], uint32_t data_len, float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]);
+
+/*
+ * FLAC__fixed_compute_residual()
+ * --------------------------------------------------------------------
+ * Compute the residual signal obtained from sutracting the predicted
+ * signal from the original.
+ *
+ * IN data[-order,data_len-1] original signal (NOTE THE INDICES!)
+ * IN data_len length of original signal
+ * IN order <= FLAC__MAX_FIXED_ORDER fixed-predictor order
+ * OUT residual[0,data_len-1] residual signal
+ */
+void FLAC__fixed_compute_residual(const FLAC__int32 data[], uint32_t data_len, uint32_t order, FLAC__int32 residual[]);
+
+/*
+ * FLAC__fixed_restore_signal()
+ * --------------------------------------------------------------------
+ * Restore the original signal by summing the residual and the
+ * predictor.
+ *
+ * IN residual[0,data_len-1] residual signal
+ * IN data_len length of original signal
+ * IN order <= FLAC__MAX_FIXED_ORDER fixed-predictor order
+ * *** IMPORTANT: the caller must pass in the historical samples:
+ * IN data[-order,-1] previously-reconstructed historical samples
+ * OUT data[0,data_len-1] original signal
+ */
+void FLAC__fixed_restore_signal(const FLAC__int32 residual[], uint32_t data_len, uint32_t order, FLAC__int32 data[]);
+
+#endif
--- /dev/null
+++ b/src/libflac/private/float.h
@@ -1,0 +1,46 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2004-2009 Josh Coalson
+ * Copyright (C) 2011-2016 Xiph.Org Foundation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__PRIVATE__FLOAT_H
+#define FLAC__PRIVATE__FLOAT_H
+
+#include "../FLAC/ordinals.h"
+
+/*
+ * FLAC__real is the basic floating point type used in LPC analysis.
+ *
+ * WATCHOUT: changing FLAC__real will change the signatures of many
+ * functions that have assembly language equivalents and break them.
+ */
+typedef float FLAC__real;
+
+#endif
--- /dev/null
+++ b/src/libflac/private/format.h
@@ -1,0 +1,45 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000-2009 Josh Coalson
+ * Copyright (C) 2011-2016 Xiph.Org Foundation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__PRIVATE__FORMAT_H
+#define FLAC__PRIVATE__FORMAT_H
+
+#include "../FLAC/format.h"
+
+uint32_t FLAC__format_get_max_rice_partition_order(uint32_t blocksize, uint32_t predictor_order);
+uint32_t FLAC__format_get_max_rice_partition_order_from_blocksize(uint32_t blocksize);
+uint32_t FLAC__format_get_max_rice_partition_order_from_blocksize_limited_max_and_predictor_order(uint32_t limit, uint32_t blocksize, uint32_t predictor_order);
+void FLAC__format_entropy_coding_method_partitioned_rice_contents_init(FLAC__EntropyCodingMethod_PartitionedRiceContents *object);
+void FLAC__format_entropy_coding_method_partitioned_rice_contents_clear(FLAC__EntropyCodingMethod_PartitionedRiceContents *object);
+FLAC__bool FLAC__format_entropy_coding_method_partitioned_rice_contents_ensure_size(FLAC__EntropyCodingMethod_PartitionedRiceContents *object, uint32_t max_partition_order);
+
+#endif
--- /dev/null
+++ b/src/libflac/private/lpc.h
@@ -1,0 +1,258 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000-2009 Josh Coalson
+ * Copyright (C) 2011-2016 Xiph.Org Foundation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__PRIVATE__LPC_H
+#define FLAC__PRIVATE__LPC_H
+
+#include "../private/float.h"
+#include "../FLAC/format.h"
+
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+
+/*
+ * FLAC__lpc_window_data()
+ * --------------------------------------------------------------------
+ * Applies the given window to the data.
+ * OPT: asm implementation
+ *
+ * IN in[0,data_len-1]
+ * IN window[0,data_len-1]
+ * OUT out[0,lag-1]
+ * IN data_len
+ */
+void FLAC__lpc_window_data(const FLAC__int32 in[], const FLAC__real window[], FLAC__real out[], uint32_t data_len);
+
+/*
+ * FLAC__lpc_compute_autocorrelation()
+ * --------------------------------------------------------------------
+ * Compute the autocorrelation for lags between 0 and lag-1.
+ * Assumes data[] outside of [0,data_len-1] == 0.
+ * Asserts that lag > 0.
+ *
+ * IN data[0,data_len-1]
+ * IN data_len
+ * IN 0 < lag <= data_len
+ * OUT autoc[0,lag-1]
+ */
+void FLAC__lpc_compute_autocorrelation(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[]);
+#ifndef FLAC__NO_ASM
+# ifdef FLAC__CPU_IA32
+# ifdef FLAC__HAS_NASM
+void FLAC__lpc_compute_autocorrelation_asm_ia32(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[]);
+void FLAC__lpc_compute_autocorrelation_asm_ia32_sse_lag_4_old(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[]);
+void FLAC__lpc_compute_autocorrelation_asm_ia32_sse_lag_8_old(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[]);
+void FLAC__lpc_compute_autocorrelation_asm_ia32_sse_lag_12_old(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[]);
+void FLAC__lpc_compute_autocorrelation_asm_ia32_sse_lag_16_old(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[]);
+# endif
+# endif
+# if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN
+# ifdef FLAC__SSE_SUPPORTED
+void FLAC__lpc_compute_autocorrelation_intrin_sse_lag_4_old(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[]);
+void FLAC__lpc_compute_autocorrelation_intrin_sse_lag_8_old(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[]);
+void FLAC__lpc_compute_autocorrelation_intrin_sse_lag_12_old(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[]);
+void FLAC__lpc_compute_autocorrelation_intrin_sse_lag_16_old(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[]);
+void FLAC__lpc_compute_autocorrelation_intrin_sse_lag_4_new(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[]);
+void FLAC__lpc_compute_autocorrelation_intrin_sse_lag_8_new(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[]);
+void FLAC__lpc_compute_autocorrelation_intrin_sse_lag_12_new(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[]);
+void FLAC__lpc_compute_autocorrelation_intrin_sse_lag_16_new(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[]);
+# endif
+# endif
+#if defined(FLAC__CPU_PPC64) && defined(FLAC__USE_VSX)
+#ifdef FLAC__HAS_TARGET_POWER9
+void FLAC__lpc_compute_autocorrelation_intrin_power9_vsx_lag_4(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[]);
+void FLAC__lpc_compute_autocorrelation_intrin_power9_vsx_lag_8(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[]);
+void FLAC__lpc_compute_autocorrelation_intrin_power9_vsx_lag_12(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[]);
+void FLAC__lpc_compute_autocorrelation_intrin_power9_vsx_lag_16(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[]);
+#endif
+#ifdef FLAC__HAS_TARGET_POWER8
+void FLAC__lpc_compute_autocorrelation_intrin_power8_vsx_lag_4(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[]);
+void FLAC__lpc_compute_autocorrelation_intrin_power8_vsx_lag_8(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[]);
+void FLAC__lpc_compute_autocorrelation_intrin_power8_vsx_lag_12(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[]);
+void FLAC__lpc_compute_autocorrelation_intrin_power8_vsx_lag_16(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[]);
+#endif
+#endif
+#endif
+
+/*
+ * FLAC__lpc_compute_lp_coefficients()
+ * --------------------------------------------------------------------
+ * Computes LP coefficients for orders 1..max_order.
+ * Do not call if autoc[0] == 0.0. This means the signal is zero
+ * and there is no point in calculating a predictor.
+ *
+ * IN autoc[0,max_order] autocorrelation values
+ * IN 0 < max_order <= FLAC__MAX_LPC_ORDER max LP order to compute
+ * OUT lp_coeff[0,max_order-1][0,max_order-1] LP coefficients for each order
+ * *** IMPORTANT:
+ * *** lp_coeff[0,max_order-1][max_order,FLAC__MAX_LPC_ORDER-1] are untouched
+ * OUT error[0,max_order-1] error for each order (more
+ * specifically, the variance of
+ * the error signal times # of
+ * samples in the signal)
+ *
+ * Example: if max_order is 9, the LP coefficients for order 9 will be
+ * in lp_coeff[8][0,8], the LP coefficients for order 8 will be
+ * in lp_coeff[7][0,7], etc.
+ */
+void FLAC__lpc_compute_lp_coefficients(const FLAC__real autoc[], uint32_t *max_order, FLAC__real lp_coeff[][FLAC__MAX_LPC_ORDER], double error[]);
+
+/*
+ * FLAC__lpc_quantize_coefficients()
+ * --------------------------------------------------------------------
+ * Quantizes the LP coefficients. NOTE: precision + bits_per_sample
+ * must be less than 32 (sizeof(FLAC__int32)*8).
+ *
+ * IN lp_coeff[0,order-1] LP coefficients
+ * IN order LP order
+ * IN FLAC__MIN_QLP_COEFF_PRECISION < precision
+ * desired precision (in bits, including sign
+ * bit) of largest coefficient
+ * OUT qlp_coeff[0,order-1] quantized coefficients
+ * OUT shift # of bits to shift right to get approximated
+ * LP coefficients. NOTE: could be negative.
+ * RETURN 0 => quantization OK
+ * 1 => coefficients require too much shifting for *shift to
+ * fit in the LPC subframe header. 'shift' is unset.
+ * 2 => coefficients are all zero, which is bad. 'shift' is
+ * unset.
+ */
+int FLAC__lpc_quantize_coefficients(const FLAC__real lp_coeff[], uint32_t order, uint32_t precision, FLAC__int32 qlp_coeff[], int *shift);
+
+/*
+ * FLAC__lpc_compute_residual_from_qlp_coefficients()
+ * --------------------------------------------------------------------
+ * Compute the residual signal obtained from sutracting the predicted
+ * signal from the original.
+ *
+ * IN data[-order,data_len-1] original signal (NOTE THE INDICES!)
+ * IN data_len length of original signal
+ * IN qlp_coeff[0,order-1] quantized LP coefficients
+ * IN order > 0 LP order
+ * IN lp_quantization quantization of LP coefficients in bits
+ * OUT residual[0,data_len-1] residual signal
+ */
+void FLAC__lpc_compute_residual_from_qlp_coefficients(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]);
+void FLAC__lpc_compute_residual_from_qlp_coefficients_wide(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]);
+#ifndef FLAC__NO_ASM
+# ifdef FLAC__CPU_IA32
+# ifdef FLAC__HAS_NASM
+void FLAC__lpc_compute_residual_from_qlp_coefficients_asm_ia32(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]);
+void FLAC__lpc_compute_residual_from_qlp_coefficients_asm_ia32_mmx(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]);
+void FLAC__lpc_compute_residual_from_qlp_coefficients_wide_asm_ia32(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]);
+# endif
+# endif
+# if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN
+# ifdef FLAC__SSE2_SUPPORTED
+void FLAC__lpc_compute_residual_from_qlp_coefficients_16_intrin_sse2(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]);
+void FLAC__lpc_compute_residual_from_qlp_coefficients_intrin_sse2(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]);
+# endif
+# ifdef FLAC__SSE4_1_SUPPORTED
+void FLAC__lpc_compute_residual_from_qlp_coefficients_intrin_sse41(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]);
+void FLAC__lpc_compute_residual_from_qlp_coefficients_wide_intrin_sse41(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]);
+# endif
+# ifdef FLAC__AVX2_SUPPORTED
+void FLAC__lpc_compute_residual_from_qlp_coefficients_16_intrin_avx2(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]);
+void FLAC__lpc_compute_residual_from_qlp_coefficients_intrin_avx2(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]);
+void FLAC__lpc_compute_residual_from_qlp_coefficients_wide_intrin_avx2(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]);
+# endif
+# endif
+#endif
+
+#endif /* !defined FLAC__INTEGER_ONLY_LIBRARY */
+
+/*
+ * FLAC__lpc_restore_signal()
+ * --------------------------------------------------------------------
+ * Restore the original signal by summing the residual and the
+ * predictor.
+ *
+ * IN residual[0,data_len-1] residual signal
+ * IN data_len length of original signal
+ * IN qlp_coeff[0,order-1] quantized LP coefficients
+ * IN order > 0 LP order
+ * IN lp_quantization quantization of LP coefficients in bits
+ * *** IMPORTANT: the caller must pass in the historical samples:
+ * IN data[-order,-1] previously-reconstructed historical samples
+ * OUT data[0,data_len-1] original signal
+ */
+void FLAC__lpc_restore_signal(const FLAC__int32 residual[], uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 data[]);
+void FLAC__lpc_restore_signal_wide(const FLAC__int32 residual[], uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 data[]);
+#ifndef FLAC__NO_ASM
+# ifdef FLAC__CPU_IA32
+# ifdef FLAC__HAS_NASM
+void FLAC__lpc_restore_signal_asm_ia32(const FLAC__int32 residual[], uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 data[]);
+void FLAC__lpc_restore_signal_asm_ia32_mmx(const FLAC__int32 residual[], uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 data[]);
+void FLAC__lpc_restore_signal_wide_asm_ia32(const FLAC__int32 residual[], uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 data[]);
+# endif /* FLAC__HAS_NASM */
+# endif /* FLAC__CPU_IA32 */
+# if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN
+# ifdef FLAC__SSE4_1_SUPPORTED
+void FLAC__lpc_restore_signal_intrin_sse41(const FLAC__int32 residual[], uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 data[]);
+void FLAC__lpc_restore_signal_16_intrin_sse41(const FLAC__int32 residual[], uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 data[]);
+void FLAC__lpc_restore_signal_wide_intrin_sse41(const FLAC__int32 residual[], uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 data[]);
+# endif
+# endif
+#endif /* FLAC__NO_ASM */
+
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+
+/*
+ * FLAC__lpc_compute_expected_bits_per_residual_sample()
+ * --------------------------------------------------------------------
+ * Compute the expected number of bits per residual signal sample
+ * based on the LP error (which is related to the residual variance).
+ *
+ * IN lpc_error >= 0.0 error returned from calculating LP coefficients
+ * IN total_samples > 0 # of samples in residual signal
+ * RETURN expected bits per sample
+ */
+double FLAC__lpc_compute_expected_bits_per_residual_sample(double lpc_error, uint32_t total_samples);
+double FLAC__lpc_compute_expected_bits_per_residual_sample_with_error_scale(double lpc_error, double error_scale);
+
+/*
+ * FLAC__lpc_compute_best_order()
+ * --------------------------------------------------------------------
+ * Compute the best order from the array of signal errors returned
+ * during coefficient computation.
+ *
+ * IN lpc_error[0,max_order-1] >= 0.0 error returned from calculating LP coefficients
+ * IN max_order > 0 max LP order
+ * IN total_samples > 0 # of samples in residual signal
+ * IN overhead_bits_per_order # of bits overhead for each increased LP order
+ * (includes warmup sample size and quantized LP coefficient)
+ * RETURN [1,max_order] best order
+ */
+uint32_t FLAC__lpc_compute_best_order(const double lpc_error[], uint32_t max_order, uint32_t total_samples, uint32_t overhead_bits_per_order);
+
+#endif /* !defined FLAC__INTEGER_ONLY_LIBRARY */
+
+#endif
--- /dev/null
+++ b/src/libflac/private/macros.h
@@ -1,0 +1,72 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2012-2016 Xiph.org Foundation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__PRIVATE__MACROS_H
+#define FLAC__PRIVATE__MACROS_H
+
+#if defined(__GNUC__) && (__GNUC__ > 4 || ( __GNUC__ == 4 && __GNUC_MINOR__ >= 3))
+
+#define flac_max(a,b) \
+ ({ __typeof__ (a) _a = (a); \
+ __typeof__ (b) _b = (b); \
+ _a > _b ? _a : _b; })
+
+#define MIN_PASTE(A,B) A##B
+#define MIN_IMPL(A,B,L) ({ \
+ __typeof__(A) MIN_PASTE(__a,L) = (A); \
+ __typeof__(B) MIN_PASTE(__b,L) = (B); \
+ MIN_PASTE(__a,L) < MIN_PASTE(__b,L) ? MIN_PASTE(__a,L) : MIN_PASTE(__b,L); \
+ })
+
+#define flac_min(A,B) MIN_IMPL(A,B,__COUNTER__)
+
+/* Whatever other unix that has sys/param.h */
+#elif defined(HAVE_SYS_PARAM_H)
+#include <sys/param.h>
+#define flac_max(a,b) MAX(a,b)
+#define flac_min(a,b) MIN(a,b)
+
+/* Windows VS has them in stdlib.h.. XXX:Untested */
+#elif defined(_MSC_VER)
+#include <stdlib.h>
+#define flac_max(a,b) __max(a,b)
+#define flac_min(a,b) __min(a,b)
+#endif
+
+#ifndef flac_min
+#define flac_min(x,y) ((x) <= (y) ? (x) : (y))
+#endif
+
+#ifndef flac_max
+#define flac_max(x,y) ((x) >= (y) ? (x) : (y))
+#endif
+
+#endif
--- /dev/null
+++ b/src/libflac/private/md5.h
@@ -1,0 +1,50 @@
+#ifndef FLAC__PRIVATE__MD5_H
+#define FLAC__PRIVATE__MD5_H
+
+/*
+ * This is the header file for the MD5 message-digest algorithm.
+ * The algorithm is due to Ron Rivest. This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * To compute the message digest of a chunk of bytes, declare an
+ * MD5Context structure, pass it to MD5Init, call MD5Update as
+ * needed on buffers full of bytes, and then call MD5Final, which
+ * will fill a supplied 16-byte array with the digest.
+ *
+ * Changed so as no longer to depend on Colin Plumb's `usual.h'
+ * header definitions; now uses stuff from dpkg's config.h
+ * - Ian Jackson <ijackson@nyx.cs.du.edu>.
+ * Still in the public domain.
+ *
+ * Josh Coalson: made some changes to integrate with libFLAC.
+ * Still in the public domain, with no warranty.
+ */
+
+#include "../FLAC/ordinals.h"
+
+typedef union {
+ FLAC__byte *p8;
+ FLAC__int16 *p16;
+ FLAC__int32 *p32;
+} FLAC__multibyte;
+
+typedef struct {
+ FLAC__uint32 in[16];
+ FLAC__uint32 buf[4];
+ FLAC__uint32 bytes[2];
+ FLAC__multibyte internal_buf;
+ size_t capacity;
+} FLAC__MD5Context;
+
+void FLAC__MD5Init(FLAC__MD5Context *context);
+void FLAC__MD5Final(FLAC__byte digest[16], FLAC__MD5Context *context);
+
+FLAC__bool FLAC__MD5Accumulate(FLAC__MD5Context *ctx, const FLAC__int32 * const signal[], uint32_t channels, uint32_t samples, uint32_t bytes_per_sample);
+
+#endif
--- /dev/null
+++ b/src/libflac/private/memory.h
@@ -1,0 +1,55 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2001-2009 Josh Coalson
+ * Copyright (C) 2011-2016 Xiph.Org Foundation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__PRIVATE__MEMORY_H
+#define FLAC__PRIVATE__MEMORY_H
+
+
+#include <stdlib.h> /* for size_t */
+
+#include "../private/float.h"
+#include "../FLAC/ordinals.h" /* for FLAC__bool */
+
+/* Returns the unaligned address returned by malloc.
+ * Use free() on this address to deallocate.
+ */
+void *FLAC__memory_alloc_aligned(size_t bytes, void **aligned_address);
+FLAC__bool FLAC__memory_alloc_aligned_int32_array(size_t elements, FLAC__int32 **unaligned_pointer, FLAC__int32 **aligned_pointer);
+FLAC__bool FLAC__memory_alloc_aligned_uint32_array(size_t elements, FLAC__uint32 **unaligned_pointer, FLAC__uint32 **aligned_pointer);
+FLAC__bool FLAC__memory_alloc_aligned_uint64_array(size_t elements, FLAC__uint64 **unaligned_pointer, FLAC__uint64 **aligned_pointer);
+FLAC__bool FLAC__memory_alloc_aligned_unsigned_array(size_t elements, uint32_t **unaligned_pointer, uint32_t **aligned_pointer);
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+FLAC__bool FLAC__memory_alloc_aligned_real_array(size_t elements, FLAC__real **unaligned_pointer, FLAC__real **aligned_pointer);
+#endif
+void *safe_malloc_mul_2op_p(size_t size1, size_t size2);
+
+#endif
--- /dev/null
+++ b/src/libflac/private/metadata.h
@@ -1,0 +1,46 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2002-2009 Josh Coalson
+ * Copyright (C) 2011-2016 Xiph.Org Foundation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__PRIVATE__METADATA_H
+#define FLAC__PRIVATE__METADATA_H
+
+#include "../FLAC/metadata.h"
+
+/* WATCHOUT: all malloc()ed data in the block is free()ed; this may not
+ * be a consistent state (e.g. PICTURE) or equivalent to the initial
+ * state after FLAC__metadata_object_new()
+ */
+void FLAC__metadata_object_delete_data(FLAC__StreamMetadata *object);
+
+void FLAC__metadata_object_cuesheet_track_delete_data(FLAC__StreamMetadata_CueSheet_Track *object);
+
+#endif
--- /dev/null
+++ b/src/libflac/private/window.h
@@ -1,0 +1,70 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2006-2009 Josh Coalson
+ * Copyright (C) 2011-2016 Xiph.Org Foundation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__PRIVATE__WINDOW_H
+#define FLAC__PRIVATE__WINDOW_H
+
+#include "../private/float.h"
+#include "../FLAC/format.h"
+
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+
+/*
+ * FLAC__window_*()
+ * --------------------------------------------------------------------
+ * Calculates window coefficients according to different apodization
+ * functions.
+ *
+ * OUT window[0,L-1]
+ * IN L (number of points in window)
+ */
+void FLAC__window_bartlett(FLAC__real *window, const FLAC__int32 L);
+void FLAC__window_bartlett_hann(FLAC__real *window, const FLAC__int32 L);
+void FLAC__window_blackman(FLAC__real *window, const FLAC__int32 L);
+void FLAC__window_blackman_harris_4term_92db_sidelobe(FLAC__real *window, const FLAC__int32 L);
+void FLAC__window_connes(FLAC__real *window, const FLAC__int32 L);
+void FLAC__window_flattop(FLAC__real *window, const FLAC__int32 L);
+void FLAC__window_gauss(FLAC__real *window, const FLAC__int32 L, const FLAC__real stddev); /* 0.0 < stddev <= 0.5 */
+void FLAC__window_hamming(FLAC__real *window, const FLAC__int32 L);
+void FLAC__window_hann(FLAC__real *window, const FLAC__int32 L);
+void FLAC__window_kaiser_bessel(FLAC__real *window, const FLAC__int32 L);
+void FLAC__window_nuttall(FLAC__real *window, const FLAC__int32 L);
+void FLAC__window_rectangle(FLAC__real *window, const FLAC__int32 L);
+void FLAC__window_triangle(FLAC__real *window, const FLAC__int32 L);
+void FLAC__window_tukey(FLAC__real *window, const FLAC__int32 L, const FLAC__real p);
+void FLAC__window_partial_tukey(FLAC__real *window, const FLAC__int32 L, const FLAC__real p, const FLAC__real start, const FLAC__real end);
+void FLAC__window_punchout_tukey(FLAC__real *window, const FLAC__int32 L, const FLAC__real p, const FLAC__real start, const FLAC__real end);
+void FLAC__window_welch(FLAC__real *window, const FLAC__int32 L);
+
+#endif /* !defined FLAC__INTEGER_ONLY_LIBRARY */
+
+#endif
--- /dev/null
+++ b/src/libflac/protected/stream_decoder.h
@@ -1,0 +1,60 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000-2009 Josh Coalson
+ * Copyright (C) 2011-2016 Xiph.Org Foundation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__PROTECTED__STREAM_DECODER_H
+#define FLAC__PROTECTED__STREAM_DECODER_H
+
+#include "../FLAC/stream_decoder.h"
+
+typedef struct FLAC__StreamDecoderProtected {
+ FLAC__StreamDecoderState state;
+ FLAC__StreamDecoderInitStatus initstate;
+ uint32_t channels;
+ FLAC__ChannelAssignment channel_assignment;
+ uint32_t bits_per_sample;
+ uint32_t sample_rate; /* in Hz */
+ uint32_t blocksize; /* in samples (per channel) */
+ FLAC__bool md5_checking; /* if true, generate MD5 signature of decoded data and compare against signature in the STREAMINFO metadata block */
+
+} FLAC__StreamDecoderProtected;
+
+/*
+ * return the number of input bytes consumed
+ */
+uint32_t FLAC__stream_decoder_get_input_bytes_unconsumed(const FLAC__StreamDecoder *decoder);
+
+/*
+ * return client_data from decoder
+ */
+FLAC_API void *get_client_data_from_decoder(FLAC__StreamDecoder *decoder);
+
+#endif
--- /dev/null
+++ b/src/libflac/share/alloc.h
@@ -1,0 +1,213 @@
+/* alloc - Convenience routines for safely allocating memory
+ * Copyright (C) 2007-2009 Josh Coalson
+ * Copyright (C) 2011-2016 Xiph.Org Foundation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__SHARE__ALLOC_H
+#define FLAC__SHARE__ALLOC_H
+
+/* WATCHOUT: for c++ you may have to #define __STDC_LIMIT_MACROS 1 real early
+ * before #including this file, otherwise SIZE_MAX might not be defined
+ */
+
+#include <limits.h> /* for SIZE_MAX */
+#include <stdint.h> /* for SIZE_MAX in case limits.h didn't get it */
+#include <stdlib.h> /* for size_t, malloc(), etc */
+#include "../share/compat.h"
+
+#ifndef SIZE_MAX
+# ifndef SIZE_T_MAX
+# ifdef _MSC_VER
+# ifdef _WIN64
+# define SIZE_T_MAX FLAC__U64L(0xffffffffffffffff)
+# else
+# define SIZE_T_MAX 0xffffffff
+# endif
+# else
+# error
+# endif
+# endif
+# define SIZE_MAX SIZE_T_MAX
+#endif
+
+/* avoid malloc()ing 0 bytes, see:
+ * https://www.securecoding.cert.org/confluence/display/seccode/MEM04-A.+Do+not+make+assumptions+about+the+result+of+allocating+0+bytes?focusedCommentId=5407003
+*/
+static inline void *safe_malloc_(size_t size)
+{
+ /* malloc(0) is undefined; FLAC src convention is to always allocate */
+ if(!size)
+ size++;
+ return malloc(size);
+}
+
+static inline void *safe_calloc_(size_t nmemb, size_t size)
+{
+ if(!nmemb || !size)
+ return malloc(1); /* malloc(0) is undefined; FLAC src convention is to always allocate */
+ return calloc(nmemb, size);
+}
+
+/*@@@@ there's probably a better way to prevent overflows when allocating untrusted sums but this works for now */
+
+static inline void *safe_malloc_add_2op_(size_t size1, size_t size2)
+{
+ size2 += size1;
+ if(size2 < size1)
+ return 0;
+ return safe_malloc_(size2);
+}
+
+static inline void *safe_malloc_add_3op_(size_t size1, size_t size2, size_t size3)
+{
+ size2 += size1;
+ if(size2 < size1)
+ return 0;
+ size3 += size2;
+ if(size3 < size2)
+ return 0;
+ return safe_malloc_(size3);
+}
+
+static inline void *safe_malloc_add_4op_(size_t size1, size_t size2, size_t size3, size_t size4)
+{
+ size2 += size1;
+ if(size2 < size1)
+ return 0;
+ size3 += size2;
+ if(size3 < size2)
+ return 0;
+ size4 += size3;
+ if(size4 < size3)
+ return 0;
+ return safe_malloc_(size4);
+}
+
+void *safe_malloc_mul_2op_(size_t size1, size_t size2) ;
+
+static inline void *safe_malloc_mul_3op_(size_t size1, size_t size2, size_t size3)
+{
+ if(!size1 || !size2 || !size3)
+ return malloc(1); /* malloc(0) is undefined; FLAC src convention is to always allocate */
+ if(size1 > SIZE_MAX / size2)
+ return 0;
+ size1 *= size2;
+ if(size1 > SIZE_MAX / size3)
+ return 0;
+ return malloc(size1*size3);
+}
+
+/* size1*size2 + size3 */
+static inline void *safe_malloc_mul2add_(size_t size1, size_t size2, size_t size3)
+{
+ if(!size1 || !size2)
+ return safe_malloc_(size3);
+ if(size1 > SIZE_MAX / size2)
+ return 0;
+ return safe_malloc_add_2op_(size1*size2, size3);
+}
+
+/* size1 * (size2 + size3) */
+static inline void *safe_malloc_muladd2_(size_t size1, size_t size2, size_t size3)
+{
+ if(!size1 || (!size2 && !size3))
+ return malloc(1); /* malloc(0) is undefined; FLAC src convention is to always allocate */
+ size2 += size3;
+ if(size2 < size3)
+ return 0;
+ if(size1 > SIZE_MAX / size2)
+ return 0;
+ return malloc(size1*size2);
+}
+
+static inline void *safe_realloc_(void *ptr, size_t size)
+{
+ void *oldptr = ptr;
+ void *newptr = realloc(ptr, size);
+ if(size > 0 && newptr == 0)
+ free(oldptr);
+ return newptr;
+}
+static inline void *safe_realloc_add_2op_(void *ptr, size_t size1, size_t size2)
+{
+ size2 += size1;
+ if(size2 < size1) {
+ free(ptr);
+ return 0;
+ }
+ return realloc(ptr, size2);
+}
+
+static inline void *safe_realloc_add_3op_(void *ptr, size_t size1, size_t size2, size_t size3)
+{
+ size2 += size1;
+ if(size2 < size1)
+ return 0;
+ size3 += size2;
+ if(size3 < size2)
+ return 0;
+ return realloc(ptr, size3);
+}
+
+static inline void *safe_realloc_add_4op_(void *ptr, size_t size1, size_t size2, size_t size3, size_t size4)
+{
+ size2 += size1;
+ if(size2 < size1)
+ return 0;
+ size3 += size2;
+ if(size3 < size2)
+ return 0;
+ size4 += size3;
+ if(size4 < size3)
+ return 0;
+ return realloc(ptr, size4);
+}
+
+static inline void *safe_realloc_mul_2op_(void *ptr, size_t size1, size_t size2)
+{
+ if(!size1 || !size2)
+ return realloc(ptr, 0); /* preserve POSIX realloc(ptr, 0) semantics */
+ if(size1 > SIZE_MAX / size2)
+ return 0;
+ return safe_realloc_(ptr, size1*size2);
+}
+
+/* size1 * (size2 + size3) */
+static inline void *safe_realloc_muladd2_(void *ptr, size_t size1, size_t size2, size_t size3)
+{
+ if(!size1 || (!size2 && !size3))
+ return realloc(ptr, 0); /* preserve POSIX realloc(ptr, 0) semantics */
+ size2 += size3;
+ if(size2 < size3)
+ return 0;
+ return safe_realloc_mul_2op_(ptr, size1, size2);
+}
+
+#endif
--- /dev/null
+++ b/src/libflac/share/compat.h
@@ -1,0 +1,205 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2012-2016 Xiph.org Foundation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* This is the preferred location of all CPP hackery to make $random_compiler
+ * work like something approaching a C99 (or maybe more accurately GNU99)
+ * compiler.
+ *
+ * It is assumed that this header will be included after "config.h".
+ */
+
+#ifndef FLAC__SHARE__COMPAT_H
+#define FLAC__SHARE__COMPAT_H
+
+#if defined _WIN32 && !defined __CYGWIN__
+/* where MSVC puts unlink() */
+# include <io.h>
+#else
+# include <unistd.h>
+#endif
+
+#if defined _MSC_VER || defined __BORLANDC__ || defined __MINGW32__
+#include <sys/types.h> /* for off_t */
+#define FLAC__off_t __int64 /* use this instead of off_t to fix the 2 GB limit */
+#if !defined __MINGW32__
+#define fseeko _fseeki64
+#define ftello _ftelli64
+#else /* MinGW */
+#if !defined(HAVE_FSEEKO)
+#define fseeko fseeko64
+#define ftello ftello64
+#endif
+#endif
+#else
+#define FLAC__off_t off_t
+#endif
+
+#if HAVE_INTTYPES_H
+#define __STDC_FORMAT_MACROS
+#include <inttypes.h>
+#endif
+
+#if defined(_MSC_VER)
+#define strtoll _strtoi64
+#define strtoull _strtoui64
+#endif
+
+#if defined(_MSC_VER) && !defined(__cplusplus)
+#define inline __inline
+#endif
+
+#if defined __INTEL_COMPILER || (defined _MSC_VER && defined _WIN64)
+/* MSVS generates VERY slow 32-bit code with __restrict */
+#define flac_restrict __restrict
+#elif defined __GNUC__
+#define flac_restrict __restrict__
+#else
+#define flac_restrict
+#endif
+
+#define FLAC__U64L(x) x##ULL
+
+#if defined _MSC_VER || defined __MINGW32__
+#define FLAC__STRCASECMP _stricmp
+#define FLAC__STRNCASECMP _strnicmp
+#elif defined __BORLANDC__
+#define FLAC__STRCASECMP stricmp
+#define FLAC__STRNCASECMP strnicmp
+#else
+#define FLAC__STRCASECMP strcasecmp
+#define FLAC__STRNCASECMP strncasecmp
+#endif
+
+#if defined _MSC_VER || defined __MINGW32__ || defined __EMX__
+#include <io.h> /* for _setmode(), chmod() */
+#include <fcntl.h> /* for _O_BINARY */
+#else
+#include <unistd.h> /* for chown(), unlink() */
+#endif
+
+#if defined _MSC_VER || defined __BORLANDC__ || defined __MINGW32__
+#if defined __BORLANDC__
+#include <utime.h> /* for utime() */
+#else
+#include <sys/utime.h> /* for utime() */
+#endif
+#else
+#include <sys/types.h> /* some flavors of BSD (like OS X) require this to get time_t */
+#include <utime.h> /* for utime() */
+#endif
+
+#if defined _MSC_VER
+# if _MSC_VER >= 1800
+# include <inttypes.h>
+# elif _MSC_VER >= 1600
+/* Visual Studio 2010 has decent C99 support */
+# include <stdint.h>
+# define PRIu64 "llu"
+# define PRId64 "lld"
+# define PRIx64 "llx"
+# else
+# include <limits.h>
+# ifndef UINT32_MAX
+# define UINT32_MAX _UI32_MAX
+# endif
+# define PRIu64 "I64u"
+# define PRId64 "I64d"
+# define PRIx64 "I64x"
+# endif
+#endif /* defined _MSC_VER */
+
+#ifdef _WIN32
+/* All char* strings are in UTF-8 format. Added to support Unicode files on Windows */
+
+#include "../share/win_utf8_io.h"
+#define flac_printf printf_utf8
+#define flac_fprintf fprintf_utf8
+#define flac_vfprintf vfprintf_utf8
+
+#include "../share/windows_unicode_filenames.h"
+#define flac_fopen flac_internal_fopen_utf8
+#define flac_chmod flac_internal_chmod_utf8
+#define flac_utime flac_internal_utime_utf8
+#define flac_unlink flac_internal_unlink_utf8
+#define flac_rename flac_internal_rename_utf8
+#define flac_stat flac_internal_stat64_utf8
+
+#else
+
+#define flac_printf printf
+#define flac_fprintf fprintf
+#define flac_vfprintf vfprintf
+
+#define flac_fopen fopen
+#define flac_chmod chmod
+#define flac_utime utime
+#define flac_unlink unlink
+#define flac_rename rename
+#define flac_stat stat
+
+#endif
+
+#ifdef _WIN32
+#define flac_stat_s __stat64 /* stat struct */
+#define flac_fstat _fstat64
+#else
+#define flac_stat_s stat /* stat struct */
+#define flac_fstat fstat
+#endif
+
+#ifdef ANDROID
+#include <limits.h>
+#endif
+
+#ifndef M_LN2
+#define M_LN2 0.69314718055994530942
+#endif
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
+/* FLAC needs to compile and work correctly on systems with a normal ISO C99
+ * snprintf as well as Microsoft Visual Studio which has an non-standards
+ * conformant snprint_s function.
+ *
+ * This function wraps the MS version to behave more like the ISO version.
+ */
+#include <stdarg.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+int flac_snprintf(char *str, size_t size, const char *fmt, ...);
+int flac_vsnprintf(char *str, size_t size, const char *fmt, va_list va);
+#ifdef __cplusplus
+};
+#endif
+
+#endif /* FLAC__SHARE__COMPAT_H */
--- /dev/null
+++ b/src/libflac/share/endswap.h
@@ -1,0 +1,84 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2012-2016 Xiph.org Foundation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* It is assumed that this header will be included after "config.h". */
+
+#if HAVE_BSWAP32 /* GCC and Clang */
+
+/* GCC prior to 4.8 didn't provide bswap16 on x86_64 */
+#if ! HAVE_BSWAP16
+static inline unsigned short __builtin_bswap16(unsigned short a)
+{
+ return (a<<8)|(a>>8);
+}
+#endif
+
+#define ENDSWAP_16(x) (__builtin_bswap16 (x))
+#define ENDSWAP_32(x) (__builtin_bswap32 (x))
+#define ENDSWAP_64(x) (__builtin_bswap64 (x))
+
+#elif defined _MSC_VER /* Windows */
+
+#include <stdlib.h>
+
+#define ENDSWAP_16(x) (_byteswap_ushort (x))
+#define ENDSWAP_32(x) (_byteswap_ulong (x))
+#define ENDSWAP_64(x) (_byteswap_uint64 (x))
+
+#elif defined HAVE_BYTESWAP_H /* Linux */
+
+#include <byteswap.h>
+
+#define ENDSWAP_16(x) (bswap_16 (x))
+#define ENDSWAP_32(x) (bswap_32 (x))
+#define ENDSWAP_64(x) (bswap_64 (x))
+
+#else
+
+#define ENDSWAP_16(x) ((((x) >> 8) & 0xFF) | (((x) & 0xFF) << 8))
+#define ENDSWAP_32(x) ((((x) >> 24) & 0xFF) | (((x) >> 8) & 0xFF00) | (((x) & 0xFF00) << 8) | (((x) & 0xFF) << 24))
+#define ENDSWAP_64(x) ((ENDSWAP_32(((x) >> 32) & 0xFFFFFFFF)) | (ENDSWAP_32((x) & 0xFFFFFFFF) << 32))
+
+#endif
+
+
+/* Host to little-endian byte swapping (for MD5 calculation) */
+#if CPU_IS_BIG_ENDIAN
+
+#define H2LE_16(x) ENDSWAP_16 (x)
+#define H2LE_32(x) ENDSWAP_32 (x)
+
+#else
+
+#define H2LE_16(x) (x)
+#define H2LE_32(x) (x)
+
+#endif
--- /dev/null
+++ b/src/libflac/share/macros.h
@@ -1,0 +1,45 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2013-2016 Xiph.org Foundation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <errno.h>
+
+/* FLAC_CHECK_RETURN : Check the return value of the provided function and
+ * print an error message if it fails (ie returns a value < 0).
+ *
+ * Ideally, a library should not print anything, but this macro is only used
+ * for things that extremely unlikely to fail, like `chown` to a previoulsy
+ * saved `uid`.
+ */
+
+#define FLAC_CHECK_RETURN(x) \
+ { if ((x) < 0) \
+ fprintf (stderr, "%s : %s\n", #x, strerror (errno)) ; \
+ }
--- /dev/null
+++ b/src/libflac/share/safe_str.h
@@ -1,0 +1,69 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2013-2016 Xiph.org Foundation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* Safe string handling functions to replace things like strcpy, strncpy,
+ * strcat, strncat etc.
+ * All of these functions guarantee a correctly NUL terminated string but
+ * the string may be truncated if the destination buffer was too short.
+ */
+
+#ifndef FLAC__SHARE_SAFE_STR_H
+#define FLAC__SHARE_SAFE_STR_H
+
+static inline char *
+safe_strncat(char *dest, const char *src, size_t dest_size)
+{
+ char * ret;
+
+ if (dest_size < 1)
+ return dest;
+
+ ret = strncat(dest, src, dest_size - strlen (dest));
+ dest [dest_size - 1] = 0;
+
+ return ret;
+}
+
+static inline char *
+safe_strncpy(char *dest, const char *src, size_t dest_size)
+{
+ char * ret;
+
+ if (dest_size < 1)
+ return dest;
+
+ ret = strncpy(dest, src, dest_size);
+ dest [dest_size - 1] = 0;
+
+ return ret;
+}
+
+#endif /* FLAC__SHARE_SAFE_STR_H */
--- /dev/null
+++ b/src/libflac/share/utf8.h
@@ -1,0 +1,25 @@
+#ifndef SHARE__UTF8_H
+#define SHARE__UTF8_H
+
+/*
+ * Convert a string between UTF-8 and the locale's charset.
+ * Invalid bytes are replaced by '#', and characters that are
+ * not available in the target encoding are replaced by '?'.
+ *
+ * If the locale's charset is not set explicitly then it is
+ * obtained using nl_langinfo(CODESET), where available, the
+ * environment variable CHARSET, or assumed to be US-ASCII.
+ *
+ * Return value of conversion functions:
+ *
+ * -1 : memory allocation failed
+ * 0 : data was converted exactly
+ * 1 : valid data was converted approximately (using '?')
+ * 2 : input was invalid (but still converted, using '#')
+ * 3 : unknown encoding (but still converted, using '?')
+ */
+
+int utf8_encode(const char *from, char **to);
+int utf8_decode(const char *from, char **to);
+
+#endif
--- /dev/null
+++ b/src/libflac/share/win_utf8_io.h
@@ -1,0 +1,62 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2013-2016 Xiph.Org Foundation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifdef _WIN32
+
+#ifndef flac__win_utf8_io_h
+#define flac__win_utf8_io_h
+
+#include <stdio.h>
+#include <stdarg.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+size_t strlen_utf8(const char *str);
+int win_get_console_width(void);
+
+int get_utf8_argv(int *argc, char ***argv);
+
+int printf_utf8(const char *format, ...);
+int fprintf_utf8(FILE *stream, const char *format, ...);
+int vfprintf_utf8(FILE *stream, const char *format, va_list argptr);
+
+#define WIN32_MEAN_AND_LEAN
+#include <windows.h>
+HANDLE WINAPI CreateFile_utf8(const char *lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif
+#endif
--- /dev/null
+++ b/src/libflac/share/windows_unicode_filenames.h
@@ -1,0 +1,63 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2013-2016 Xiph.Org Foundation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifdef _WIN32
+
+#ifndef flac__windows_unicode_filenames_h
+#define flac__windows_unicode_filenames_h
+
+#include <stdio.h>
+#include <sys/stat.h>
+#include <sys/utime.h>
+#include "../FLAC/ordinals.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void flac_internal_set_utf8_filenames(FLAC__bool flag);
+FLAC__bool flac_internal_get_utf8_filenames(void);
+#define flac_set_utf8_filenames flac_internal_set_utf8_filenames
+#define flac_get_utf8_filenames flac_internal_get_utf8_filenames
+
+FILE* flac_internal_fopen_utf8(const char *filename, const char *mode);
+int flac_internal_stat64_utf8(const char *path, struct __stat64 *buffer);
+int flac_internal_chmod_utf8(const char *filename, int pmode);
+int flac_internal_utime_utf8(const char *filename, struct utimbuf *times);
+int flac_internal_unlink_utf8(const char *filename);
+int flac_internal_rename_utf8(const char *oldname, const char *newname);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif
+#endif
--- /dev/null
+++ b/src/libflac/stream_decoder.c
@@ -1,0 +1,2951 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000-2009 Josh Coalson
+ * Copyright (C) 2011-2016 Xiph.Org Foundation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// 8bb: hide POSIX warnings
+#ifdef _MSC_VER
+#pragma warning(disable: 4996)
+#endif
+
+#include <stdio.h>
+#include <stdlib.h> /* for malloc() */
+#include <string.h> /* for memset/memcpy() */
+#include <sys/stat.h> /* for stat() */
+#include <sys/types.h> /* for off_t */
+#include "share/compat.h"
+#include "share/alloc.h"
+#include "protected/stream_decoder.h"
+#include "private/bitreader.h"
+#include "private/bitmath.h"
+#include "private/crc.h"
+#include "private/fixed.h"
+#include "private/format.h"
+#include "private/lpc.h"
+#include "private/md5.h"
+#include "private/memory.h"
+#include "private/macros.h"
+
+/***********************************************************************
+ *
+ * Private static data
+ *
+ ***********************************************************************/
+
+static const FLAC__byte ID3V2_TAG_[3] = { 'I', 'D', '3' };
+
+/***********************************************************************
+ *
+ * Private class method prototypes
+ *
+ ***********************************************************************/
+
+static void set_defaults_(FLAC__StreamDecoder *decoder);
+static FILE *get_binary_stdin_(void);
+static FLAC__bool allocate_output_(FLAC__StreamDecoder *decoder, uint32_t size, uint32_t channels);
+static FLAC__bool has_id_filtered_(FLAC__StreamDecoder *decoder, FLAC__byte *id);
+static FLAC__bool find_metadata_(FLAC__StreamDecoder *decoder);
+static FLAC__bool read_metadata_(FLAC__StreamDecoder *decoder);
+static FLAC__bool read_metadata_streaminfo_(FLAC__StreamDecoder *decoder, FLAC__bool is_last, uint32_t length);
+static FLAC__bool read_metadata_seektable_(FLAC__StreamDecoder *decoder, FLAC__bool is_last, uint32_t length);
+static FLAC__bool read_metadata_vorbiscomment_(FLAC__StreamDecoder *decoder, FLAC__StreamMetadata_VorbisComment *obj, uint32_t length);
+static FLAC__bool read_metadata_cuesheet_(FLAC__StreamDecoder *decoder, FLAC__StreamMetadata_CueSheet *obj);
+static FLAC__bool read_metadata_picture_(FLAC__StreamDecoder *decoder, FLAC__StreamMetadata_Picture *obj);
+static FLAC__bool skip_id3v2_tag_(FLAC__StreamDecoder *decoder);
+static FLAC__bool frame_sync_(FLAC__StreamDecoder *decoder);
+static FLAC__bool read_frame_(FLAC__StreamDecoder *decoder, FLAC__bool *got_a_frame, FLAC__bool do_full_decode);
+static FLAC__bool read_frame_header_(FLAC__StreamDecoder *decoder);
+static FLAC__bool read_subframe_(FLAC__StreamDecoder *decoder, uint32_t channel, uint32_t bps, FLAC__bool do_full_decode);
+static FLAC__bool read_subframe_constant_(FLAC__StreamDecoder *decoder, uint32_t channel, uint32_t bps, FLAC__bool do_full_decode);
+static FLAC__bool read_subframe_fixed_(FLAC__StreamDecoder *decoder, uint32_t channel, uint32_t bps, const uint32_t order, FLAC__bool do_full_decode);
+static FLAC__bool read_subframe_lpc_(FLAC__StreamDecoder *decoder, uint32_t channel, uint32_t bps, const uint32_t order, FLAC__bool do_full_decode);
+static FLAC__bool read_subframe_verbatim_(FLAC__StreamDecoder *decoder, uint32_t channel, uint32_t bps, FLAC__bool do_full_decode);
+static FLAC__bool read_residual_partitioned_rice_(FLAC__StreamDecoder *decoder, uint32_t predictor_order, uint32_t partition_order, FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents, FLAC__int32 *residual, FLAC__bool is_extended);
+static FLAC__bool read_zero_padding_(FLAC__StreamDecoder *decoder);
+static FLAC__bool read_callback_(FLAC__byte buffer[], size_t *bytes, void *client_data);
+static FLAC__StreamDecoderWriteStatus write_audio_frame_to_client_(FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[]);
+static void send_error_to_client_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status);
+static FLAC__bool seek_to_absolute_sample_(FLAC__StreamDecoder *decoder, FLAC__uint64 stream_length, FLAC__uint64 target_sample);
+static FLAC__StreamDecoderReadStatus file_read_callback_(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data);
+static FLAC__StreamDecoderSeekStatus file_seek_callback_(const FLAC__StreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data);
+static FLAC__StreamDecoderTellStatus file_tell_callback_(const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data);
+static FLAC__StreamDecoderLengthStatus file_length_callback_(const FLAC__StreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data);
+static FLAC__bool file_eof_callback_(const FLAC__StreamDecoder *decoder, void *client_data);
+
+/***********************************************************************
+ *
+ * Private class data
+ *
+ ***********************************************************************/
+
+typedef struct FLAC__StreamDecoderPrivate {
+ FLAC__bool is_ogg;
+ FLAC__StreamDecoderReadCallback read_callback;
+ FLAC__StreamDecoderSeekCallback seek_callback;
+ FLAC__StreamDecoderTellCallback tell_callback;
+ FLAC__StreamDecoderLengthCallback length_callback;
+ FLAC__StreamDecoderEofCallback eof_callback;
+ FLAC__StreamDecoderWriteCallback write_callback;
+ FLAC__StreamDecoderMetadataCallback metadata_callback;
+ FLAC__StreamDecoderErrorCallback error_callback;
+ /* generic 32-bit datapath: */
+ void (*local_lpc_restore_signal)(const FLAC__int32 residual[], uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 data[]);
+ /* generic 64-bit datapath: */
+ void (*local_lpc_restore_signal_64bit)(const FLAC__int32 residual[], uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 data[]);
+ /* for use when the signal is <= 16 bits-per-sample, or <= 15 bits-per-sample on a side channel (which requires 1 extra bit): */
+ void (*local_lpc_restore_signal_16bit)(const FLAC__int32 residual[], uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 data[]);
+ void *client_data;
+ FILE *file; /* only used if FLAC__stream_decoder_init_file()/FLAC__stream_decoder_init_file() called, else NULL */
+ FLAC__BitReader *input;
+ FLAC__int32 *output[FLAC__MAX_CHANNELS];
+ FLAC__int32 *residual[FLAC__MAX_CHANNELS]; /* WATCHOUT: these are the aligned pointers; the real pointers that should be free()'d are residual_unaligned[] below */
+ FLAC__EntropyCodingMethod_PartitionedRiceContents partitioned_rice_contents[FLAC__MAX_CHANNELS];
+ uint32_t output_capacity, output_channels;
+ FLAC__uint32 fixed_block_size, next_fixed_block_size;
+ FLAC__uint64 samples_decoded;
+ FLAC__bool has_stream_info, has_seek_table;
+ FLAC__StreamMetadata stream_info;
+ FLAC__StreamMetadata seek_table;
+ FLAC__bool metadata_filter[128]; /* MAGIC number 128 == total number of metadata block types == 1 << 7 */
+ FLAC__byte *metadata_filter_ids;
+ size_t metadata_filter_ids_count, metadata_filter_ids_capacity; /* units for both are IDs, not bytes */
+ FLAC__Frame frame;
+ FLAC__bool cached; /* true if there is a byte in lookahead */
+ FLAC__byte header_warmup[2]; /* contains the sync code and reserved bits */
+ FLAC__byte lookahead; /* temp storage when we need to look ahead one byte in the stream */
+ /* unaligned (original) pointers to allocated data */
+ FLAC__int32 *residual_unaligned[FLAC__MAX_CHANNELS];
+ FLAC__bool do_md5_checking; /* initially gets protected_->md5_checking but is turned off after a seek or if the metadata has a zero MD5 */
+ FLAC__bool internal_reset_hack; /* used only during init() so we can call reset to set up the decoder without rewinding the input */
+ FLAC__bool is_seeking;
+ FLAC__MD5Context md5context;
+ FLAC__byte computed_md5sum[16]; /* this is the sum we computed from the decoded data */
+ /* (the rest of these are only used for seeking) */
+ FLAC__Frame last_frame; /* holds the info of the last frame we seeked to */
+ FLAC__uint64 first_frame_offset; /* hint to the seek routine of where in the stream the first audio frame starts */
+ FLAC__uint64 target_sample;
+ uint32_t unparseable_frame_count; /* used to tell whether we're decoding a future version of FLAC or just got a bad sync */
+ FLAC__bool got_a_frame; /* hack needed in Ogg FLAC seek routine to check when process_single() actually writes a frame */
+} FLAC__StreamDecoderPrivate;
+
+/***********************************************************************
+ *
+ * Public static class data
+ *
+ ***********************************************************************/
+
+FLAC_API const char * const FLAC__StreamDecoderStateString[] = {
+ "FLAC__STREAM_DECODER_SEARCH_FOR_METADATA",
+ "FLAC__STREAM_DECODER_READ_METADATA",
+ "FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC",
+ "FLAC__STREAM_DECODER_READ_FRAME",
+ "FLAC__STREAM_DECODER_END_OF_STREAM",
+ "FLAC__STREAM_DECODER_OGG_ERROR",
+ "FLAC__STREAM_DECODER_SEEK_ERROR",
+ "FLAC__STREAM_DECODER_ABORTED",
+ "FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR",
+ "FLAC__STREAM_DECODER_UNINITIALIZED"
+};
+
+FLAC_API const char * const FLAC__StreamDecoderInitStatusString[] = {
+ "FLAC__STREAM_DECODER_INIT_STATUS_OK",
+ "FLAC__STREAM_DECODER_INIT_STATUS_UNSUPPORTED_CONTAINER",
+ "FLAC__STREAM_DECODER_INIT_STATUS_INVALID_CALLBACKS",
+ "FLAC__STREAM_DECODER_INIT_STATUS_MEMORY_ALLOCATION_ERROR",
+ "FLAC__STREAM_DECODER_INIT_STATUS_ERROR_OPENING_FILE",
+ "FLAC__STREAM_DECODER_INIT_STATUS_ALREADY_INITIALIZED"
+};
+
+FLAC_API const char * const FLAC__StreamDecoderReadStatusString[] = {
+ "FLAC__STREAM_DECODER_READ_STATUS_CONTINUE",
+ "FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM",
+ "FLAC__STREAM_DECODER_READ_STATUS_ABORT"
+};
+
+FLAC_API const char * const FLAC__StreamDecoderSeekStatusString[] = {
+ "FLAC__STREAM_DECODER_SEEK_STATUS_OK",
+ "FLAC__STREAM_DECODER_SEEK_STATUS_ERROR",
+ "FLAC__STREAM_DECODER_SEEK_STATUS_UNSUPPORTED"
+};
+
+FLAC_API const char * const FLAC__StreamDecoderTellStatusString[] = {
+ "FLAC__STREAM_DECODER_TELL_STATUS_OK",
+ "FLAC__STREAM_DECODER_TELL_STATUS_ERROR",
+ "FLAC__STREAM_DECODER_TELL_STATUS_UNSUPPORTED"
+};
+
+FLAC_API const char * const FLAC__StreamDecoderLengthStatusString[] = {
+ "FLAC__STREAM_DECODER_LENGTH_STATUS_OK",
+ "FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR",
+ "FLAC__STREAM_DECODER_LENGTH_STATUS_UNSUPPORTED"
+};
+
+FLAC_API const char * const FLAC__StreamDecoderWriteStatusString[] = {
+ "FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE",
+ "FLAC__STREAM_DECODER_WRITE_STATUS_ABORT"
+};
+
+FLAC_API const char * const FLAC__StreamDecoderErrorStatusString[] = {
+ "FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC",
+ "FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER",
+ "FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH",
+ "FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM"
+};
+
+/***********************************************************************
+ *
+ * Class constructor/destructor
+ *
+ ***********************************************************************/
+FLAC_API FLAC__StreamDecoder *FLAC__stream_decoder_new(void)
+{
+ FLAC__StreamDecoder *decoder;
+ uint32_t i;
+
+ decoder = calloc(1, sizeof(FLAC__StreamDecoder));
+ if(decoder == 0) {
+ return 0;
+ }
+
+ decoder->protected_ = calloc(1, sizeof(FLAC__StreamDecoderProtected));
+ if(decoder->protected_ == 0) {
+ free(decoder);
+ return 0;
+ }
+
+ decoder->private_ = calloc(1, sizeof(FLAC__StreamDecoderPrivate));
+ if(decoder->private_ == 0) {
+ free(decoder->protected_);
+ free(decoder);
+ return 0;
+ }
+
+ decoder->private_->input = FLAC__bitreader_new();
+ if(decoder->private_->input == 0) {
+ free(decoder->private_);
+ free(decoder->protected_);
+ free(decoder);
+ return 0;
+ }
+
+ decoder->private_->metadata_filter_ids_capacity = 16;
+ if(0 == (decoder->private_->metadata_filter_ids = malloc((FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8) * decoder->private_->metadata_filter_ids_capacity))) {
+ FLAC__bitreader_delete(decoder->private_->input);
+ free(decoder->private_);
+ free(decoder->protected_);
+ free(decoder);
+ return 0;
+ }
+
+ for(i = 0; i < FLAC__MAX_CHANNELS; i++) {
+ decoder->private_->output[i] = 0;
+ decoder->private_->residual_unaligned[i] = decoder->private_->residual[i] = 0;
+ }
+
+ decoder->private_->output_capacity = 0;
+ decoder->private_->output_channels = 0;
+ decoder->private_->has_seek_table = false;
+
+ for(i = 0; i < FLAC__MAX_CHANNELS; i++)
+ FLAC__format_entropy_coding_method_partitioned_rice_contents_init(&decoder->private_->partitioned_rice_contents[i]);
+
+ decoder->private_->file = 0;
+
+ set_defaults_(decoder);
+
+ decoder->protected_->state = FLAC__STREAM_DECODER_UNINITIALIZED;
+
+ return decoder;
+}
+
+FLAC_API void FLAC__stream_decoder_delete(FLAC__StreamDecoder *decoder)
+{
+ uint32_t i;
+
+ if (decoder == NULL)
+ return ;
+
+ (void)FLAC__stream_decoder_finish(decoder);
+
+ if(0 != decoder->private_->metadata_filter_ids)
+ free(decoder->private_->metadata_filter_ids);
+
+ FLAC__bitreader_delete(decoder->private_->input);
+
+ for(i = 0; i < FLAC__MAX_CHANNELS; i++)
+ FLAC__format_entropy_coding_method_partitioned_rice_contents_clear(&decoder->private_->partitioned_rice_contents[i]);
+
+ free(decoder->private_);
+ free(decoder->protected_);
+ free(decoder);
+}
+
+/***********************************************************************
+ *
+ * Public class methods
+ *
+ ***********************************************************************/
+
+static FLAC__StreamDecoderInitStatus init_stream_internal_(
+ FLAC__StreamDecoder *decoder,
+ FLAC__StreamDecoderReadCallback read_callback,
+ FLAC__StreamDecoderSeekCallback seek_callback,
+ FLAC__StreamDecoderTellCallback tell_callback,
+ FLAC__StreamDecoderLengthCallback length_callback,
+ FLAC__StreamDecoderEofCallback eof_callback,
+ FLAC__StreamDecoderWriteCallback write_callback,
+ FLAC__StreamDecoderMetadataCallback metadata_callback,
+ FLAC__StreamDecoderErrorCallback error_callback,
+ void *client_data,
+ FLAC__bool is_ogg
+)
+{
+ if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED)
+ return FLAC__STREAM_DECODER_INIT_STATUS_ALREADY_INITIALIZED;
+
+ if(is_ogg)
+ return FLAC__STREAM_DECODER_INIT_STATUS_UNSUPPORTED_CONTAINER;
+
+ if(
+ 0 == read_callback ||
+ 0 == write_callback ||
+ 0 == error_callback ||
+ (seek_callback && (0 == tell_callback || 0 == length_callback || 0 == eof_callback))
+ )
+ return FLAC__STREAM_DECODER_INIT_STATUS_INVALID_CALLBACKS;
+
+ decoder->private_->local_lpc_restore_signal = FLAC__lpc_restore_signal;
+ decoder->private_->local_lpc_restore_signal_64bit = FLAC__lpc_restore_signal_wide;
+ decoder->private_->local_lpc_restore_signal_16bit = FLAC__lpc_restore_signal;
+
+ /* from here on, errors are fatal */
+
+ if(!FLAC__bitreader_init(decoder->private_->input, read_callback_, decoder)) {
+ decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+ return FLAC__STREAM_DECODER_INIT_STATUS_MEMORY_ALLOCATION_ERROR;
+ }
+
+ decoder->private_->read_callback = read_callback;
+ decoder->private_->seek_callback = seek_callback;
+ decoder->private_->tell_callback = tell_callback;
+ decoder->private_->length_callback = length_callback;
+ decoder->private_->eof_callback = eof_callback;
+ decoder->private_->write_callback = write_callback;
+ decoder->private_->metadata_callback = metadata_callback;
+ decoder->private_->error_callback = error_callback;
+ decoder->private_->client_data = client_data;
+ decoder->private_->fixed_block_size = decoder->private_->next_fixed_block_size = 0;
+ decoder->private_->samples_decoded = 0;
+ decoder->private_->has_stream_info = false;
+ decoder->private_->cached = false;
+
+ decoder->private_->do_md5_checking = decoder->protected_->md5_checking;
+ decoder->private_->is_seeking = false;
+
+ decoder->private_->internal_reset_hack = true; /* so the following reset does not try to rewind the input */
+ if(!FLAC__stream_decoder_reset(decoder)) {
+ /* above call sets the state for us */
+ return FLAC__STREAM_DECODER_INIT_STATUS_MEMORY_ALLOCATION_ERROR;
+ }
+
+ return FLAC__STREAM_DECODER_INIT_STATUS_OK;
+}
+
+FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_stream(
+ FLAC__StreamDecoder *decoder,
+ FLAC__StreamDecoderReadCallback read_callback,
+ FLAC__StreamDecoderSeekCallback seek_callback,
+ FLAC__StreamDecoderTellCallback tell_callback,
+ FLAC__StreamDecoderLengthCallback length_callback,
+ FLAC__StreamDecoderEofCallback eof_callback,
+ FLAC__StreamDecoderWriteCallback write_callback,
+ FLAC__StreamDecoderMetadataCallback metadata_callback,
+ FLAC__StreamDecoderErrorCallback error_callback,
+ void *client_data
+)
+{
+ return init_stream_internal_(
+ decoder,
+ read_callback,
+ seek_callback,
+ tell_callback,
+ length_callback,
+ eof_callback,
+ write_callback,
+ metadata_callback,
+ error_callback,
+ client_data,
+ /*is_ogg=*/false
+ );
+}
+
+FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_ogg_stream(
+ FLAC__StreamDecoder *decoder,
+ FLAC__StreamDecoderReadCallback read_callback,
+ FLAC__StreamDecoderSeekCallback seek_callback,
+ FLAC__StreamDecoderTellCallback tell_callback,
+ FLAC__StreamDecoderLengthCallback length_callback,
+ FLAC__StreamDecoderEofCallback eof_callback,
+ FLAC__StreamDecoderWriteCallback write_callback,
+ FLAC__StreamDecoderMetadataCallback metadata_callback,
+ FLAC__StreamDecoderErrorCallback error_callback,
+ void *client_data
+)
+{
+ return init_stream_internal_(
+ decoder,
+ read_callback,
+ seek_callback,
+ tell_callback,
+ length_callback,
+ eof_callback,
+ write_callback,
+ metadata_callback,
+ error_callback,
+ client_data,
+ /*is_ogg=*/true
+ );
+}
+
+static FLAC__StreamDecoderInitStatus init_FILE_internal_(
+ FLAC__StreamDecoder *decoder,
+ FILE *file,
+ FLAC__StreamDecoderWriteCallback write_callback,
+ FLAC__StreamDecoderMetadataCallback metadata_callback,
+ FLAC__StreamDecoderErrorCallback error_callback,
+ void *client_data,
+ FLAC__bool is_ogg
+)
+{
+ if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED)
+ return decoder->protected_->initstate = FLAC__STREAM_DECODER_INIT_STATUS_ALREADY_INITIALIZED;
+
+ if(0 == write_callback || 0 == error_callback)
+ return decoder->protected_->initstate = FLAC__STREAM_DECODER_INIT_STATUS_INVALID_CALLBACKS;
+
+ /*
+ * To make sure that our file does not go unclosed after an error, we
+ * must assign the FILE pointer before any further error can occur in
+ * this routine.
+ */
+ if(file == stdin)
+ file = get_binary_stdin_(); /* just to be safe */
+
+ decoder->private_->file = file;
+
+ return init_stream_internal_(
+ decoder,
+ file_read_callback_,
+ decoder->private_->file == stdin? 0: file_seek_callback_,
+ decoder->private_->file == stdin? 0: file_tell_callback_,
+ decoder->private_->file == stdin? 0: file_length_callback_,
+ file_eof_callback_,
+ write_callback,
+ metadata_callback,
+ error_callback,
+ client_data,
+ is_ogg
+ );
+}
+
+FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_FILE(
+ FLAC__StreamDecoder *decoder,
+ FILE *file,
+ FLAC__StreamDecoderWriteCallback write_callback,
+ FLAC__StreamDecoderMetadataCallback metadata_callback,
+ FLAC__StreamDecoderErrorCallback error_callback,
+ void *client_data
+)
+{
+ return init_FILE_internal_(decoder, file, write_callback, metadata_callback, error_callback, client_data, /*is_ogg=*/false);
+}
+
+FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_ogg_FILE(
+ FLAC__StreamDecoder *decoder,
+ FILE *file,
+ FLAC__StreamDecoderWriteCallback write_callback,
+ FLAC__StreamDecoderMetadataCallback metadata_callback,
+ FLAC__StreamDecoderErrorCallback error_callback,
+ void *client_data
+)
+{
+ return init_FILE_internal_(decoder, file, write_callback, metadata_callback, error_callback, client_data, /*is_ogg=*/true);
+}
+
+static FLAC__StreamDecoderInitStatus init_file_internal_(
+ FLAC__StreamDecoder *decoder,
+ const char *filename,
+ FLAC__StreamDecoderWriteCallback write_callback,
+ FLAC__StreamDecoderMetadataCallback metadata_callback,
+ FLAC__StreamDecoderErrorCallback error_callback,
+ void *client_data,
+ FLAC__bool is_ogg
+)
+{
+ FILE *file;
+
+ /*
+ * To make sure that our file does not go unclosed after an error, we
+ * have to do the same entrance checks here that are later performed
+ * in FLAC__stream_decoder_init_FILE() before the FILE* is assigned.
+ */
+ if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED)
+ return decoder->protected_->initstate = FLAC__STREAM_DECODER_INIT_STATUS_ALREADY_INITIALIZED;
+
+ if(0 == write_callback || 0 == error_callback)
+ return decoder->protected_->initstate = FLAC__STREAM_DECODER_INIT_STATUS_INVALID_CALLBACKS;
+
+ file = filename? flac_fopen(filename, "rb") : stdin;
+
+ if(0 == file)
+ return FLAC__STREAM_DECODER_INIT_STATUS_ERROR_OPENING_FILE;
+
+ return init_FILE_internal_(decoder, file, write_callback, metadata_callback, error_callback, client_data, is_ogg);
+}
+
+FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_file(
+ FLAC__StreamDecoder *decoder,
+ const char *filename,
+ FLAC__StreamDecoderWriteCallback write_callback,
+ FLAC__StreamDecoderMetadataCallback metadata_callback,
+ FLAC__StreamDecoderErrorCallback error_callback,
+ void *client_data
+)
+{
+ return init_file_internal_(decoder, filename, write_callback, metadata_callback, error_callback, client_data, /*is_ogg=*/false);
+}
+
+FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_ogg_file(
+ FLAC__StreamDecoder *decoder,
+ const char *filename,
+ FLAC__StreamDecoderWriteCallback write_callback,
+ FLAC__StreamDecoderMetadataCallback metadata_callback,
+ FLAC__StreamDecoderErrorCallback error_callback,
+ void *client_data
+)
+{
+ return init_file_internal_(decoder, filename, write_callback, metadata_callback, error_callback, client_data, /*is_ogg=*/true);
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_finish(FLAC__StreamDecoder *decoder)
+{
+ FLAC__bool md5_failed = false;
+ uint32_t i;
+
+ if(decoder->protected_->state == FLAC__STREAM_DECODER_UNINITIALIZED)
+ return true;
+
+ /* see the comment in FLAC__stream_decoder_reset() as to why we
+ * always call FLAC__MD5Final()
+ */
+ FLAC__MD5Final(decoder->private_->computed_md5sum, &decoder->private_->md5context);
+
+ free(decoder->private_->seek_table.data.seek_table.points);
+ decoder->private_->seek_table.data.seek_table.points = 0;
+ decoder->private_->has_seek_table = false;
+
+ FLAC__bitreader_free(decoder->private_->input);
+ for(i = 0; i < FLAC__MAX_CHANNELS; i++) {
+ /* WATCHOUT:
+ * FLAC__lpc_restore_signal_asm_ia32_mmx() and ..._intrin_sseN()
+ * require that the output arrays have a buffer of up to 3 zeroes
+ * in front (at negative indices) for alignment purposes;
+ * we use 4 to keep the data well-aligned.
+ */
+ if(0 != decoder->private_->output[i]) {
+ free(decoder->private_->output[i]-4);
+ decoder->private_->output[i] = 0;
+ }
+ if(0 != decoder->private_->residual_unaligned[i]) {
+ free(decoder->private_->residual_unaligned[i]);
+ decoder->private_->residual_unaligned[i] = decoder->private_->residual[i] = 0;
+ }
+ }
+ decoder->private_->output_capacity = 0;
+ decoder->private_->output_channels = 0;
+
+ if(0 != decoder->private_->file) {
+ if(decoder->private_->file != stdin)
+ fclose(decoder->private_->file);
+ decoder->private_->file = 0;
+ }
+
+ if(decoder->private_->do_md5_checking) {
+ if(memcmp(decoder->private_->stream_info.data.stream_info.md5sum, decoder->private_->computed_md5sum, 16))
+ md5_failed = true;
+ }
+ decoder->private_->is_seeking = false;
+
+ set_defaults_(decoder);
+
+ decoder->protected_->state = FLAC__STREAM_DECODER_UNINITIALIZED;
+
+ return !md5_failed;
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_set_ogg_serial_number(FLAC__StreamDecoder *decoder, long value)
+{
+ if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED)
+ return false;
+
+ (void)value;
+ return false;
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_set_md5_checking(FLAC__StreamDecoder *decoder, FLAC__bool value)
+{
+ if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED)
+ return false;
+ decoder->protected_->md5_checking = value;
+ return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_respond(FLAC__StreamDecoder *decoder, FLAC__MetadataType type)
+{
+ /* double protection */
+ if((uint32_t)type > FLAC__MAX_METADATA_TYPE_CODE)
+ return false;
+ if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED)
+ return false;
+ decoder->private_->metadata_filter[type] = true;
+ if(type == FLAC__METADATA_TYPE_APPLICATION)
+ decoder->private_->metadata_filter_ids_count = 0;
+ return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_respond_application(FLAC__StreamDecoder *decoder, const FLAC__byte id[4])
+{
+ if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED)
+ return false;
+
+ if(decoder->private_->metadata_filter[FLAC__METADATA_TYPE_APPLICATION])
+ return true;
+
+ if(decoder->private_->metadata_filter_ids_count == decoder->private_->metadata_filter_ids_capacity) {
+ if(0 == (decoder->private_->metadata_filter_ids = safe_realloc_mul_2op_(decoder->private_->metadata_filter_ids, decoder->private_->metadata_filter_ids_capacity, /*times*/2))) {
+ decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+ return false;
+ }
+ decoder->private_->metadata_filter_ids_capacity *= 2;
+ }
+
+ memcpy(decoder->private_->metadata_filter_ids + decoder->private_->metadata_filter_ids_count * (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8), id, (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8));
+ decoder->private_->metadata_filter_ids_count++;
+
+ return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_respond_all(FLAC__StreamDecoder *decoder)
+{
+ uint32_t i;
+ if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED)
+ return false;
+ for(i = 0; i < sizeof(decoder->private_->metadata_filter) / sizeof(decoder->private_->metadata_filter[0]); i++)
+ decoder->private_->metadata_filter[i] = true;
+ decoder->private_->metadata_filter_ids_count = 0;
+ return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_ignore(FLAC__StreamDecoder *decoder, FLAC__MetadataType type)
+{
+ /* double protection */
+ if((uint32_t)type > FLAC__MAX_METADATA_TYPE_CODE)
+ return false;
+ if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED)
+ return false;
+ decoder->private_->metadata_filter[type] = false;
+ if(type == FLAC__METADATA_TYPE_APPLICATION)
+ decoder->private_->metadata_filter_ids_count = 0;
+ return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_ignore_application(FLAC__StreamDecoder *decoder, const FLAC__byte id[4])
+{
+ if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED)
+ return false;
+
+ if(!decoder->private_->metadata_filter[FLAC__METADATA_TYPE_APPLICATION])
+ return true;
+
+ if(decoder->private_->metadata_filter_ids_count == decoder->private_->metadata_filter_ids_capacity) {
+ if(0 == (decoder->private_->metadata_filter_ids = safe_realloc_mul_2op_(decoder->private_->metadata_filter_ids, decoder->private_->metadata_filter_ids_capacity, /*times*/2))) {
+ decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+ return false;
+ }
+ decoder->private_->metadata_filter_ids_capacity *= 2;
+ }
+
+ memcpy(decoder->private_->metadata_filter_ids + decoder->private_->metadata_filter_ids_count * (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8), id, (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8));
+ decoder->private_->metadata_filter_ids_count++;
+
+ return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_ignore_all(FLAC__StreamDecoder *decoder)
+{
+ if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED)
+ return false;
+ memset(decoder->private_->metadata_filter, 0, sizeof(decoder->private_->metadata_filter));
+ decoder->private_->metadata_filter_ids_count = 0;
+ return true;
+}
+
+FLAC_API FLAC__StreamDecoderState FLAC__stream_decoder_get_state(const FLAC__StreamDecoder *decoder)
+{
+ return decoder->protected_->state;
+}
+
+FLAC_API const char *FLAC__stream_decoder_get_resolved_state_string(const FLAC__StreamDecoder *decoder)
+{
+ return FLAC__StreamDecoderStateString[decoder->protected_->state];
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_get_md5_checking(const FLAC__StreamDecoder *decoder)
+{
+ return decoder->protected_->md5_checking;
+}
+
+FLAC_API FLAC__uint64 FLAC__stream_decoder_get_total_samples(const FLAC__StreamDecoder *decoder)
+{
+ return decoder->private_->has_stream_info? decoder->private_->stream_info.data.stream_info.total_samples : 0;
+}
+
+FLAC_API uint32_t FLAC__stream_decoder_get_channels(const FLAC__StreamDecoder *decoder)
+{
+ return decoder->protected_->channels;
+}
+
+FLAC_API FLAC__ChannelAssignment FLAC__stream_decoder_get_channel_assignment(const FLAC__StreamDecoder *decoder)
+{
+ return decoder->protected_->channel_assignment;
+}
+
+FLAC_API uint32_t FLAC__stream_decoder_get_bits_per_sample(const FLAC__StreamDecoder *decoder)
+{
+ return decoder->protected_->bits_per_sample;
+}
+
+FLAC_API uint32_t FLAC__stream_decoder_get_sample_rate(const FLAC__StreamDecoder *decoder)
+{
+ return decoder->protected_->sample_rate;
+}
+
+FLAC_API uint32_t FLAC__stream_decoder_get_blocksize(const FLAC__StreamDecoder *decoder)
+{
+ return decoder->protected_->blocksize;
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_get_decode_position(const FLAC__StreamDecoder *decoder, FLAC__uint64 *position)
+{
+ if(0 == decoder->private_->tell_callback)
+ return false;
+ if(decoder->private_->tell_callback(decoder, position, decoder->private_->client_data) != FLAC__STREAM_DECODER_TELL_STATUS_OK)
+ return false;
+ /* should never happen since all FLAC frames and metadata blocks are byte aligned, but check just in case */
+ if(!FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input))
+ return false;
+ *position -= FLAC__stream_decoder_get_input_bytes_unconsumed(decoder);
+ return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_flush(FLAC__StreamDecoder *decoder)
+{
+ if(!decoder->private_->internal_reset_hack && decoder->protected_->state == FLAC__STREAM_DECODER_UNINITIALIZED)
+ return false;
+
+ decoder->private_->samples_decoded = 0;
+ decoder->private_->do_md5_checking = false;
+
+ if(!FLAC__bitreader_clear(decoder->private_->input)) {
+ decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+ return false;
+ }
+ decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+
+ return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_reset(FLAC__StreamDecoder *decoder)
+{
+ if(!FLAC__stream_decoder_flush(decoder)) {
+ /* above call sets the state for us */
+ return false;
+ }
+
+ /* Rewind if necessary. If FLAC__stream_decoder_init() is calling us,
+ * (internal_reset_hack) don't try to rewind since we are already at
+ * the beginning of the stream and don't want to fail if the input is
+ * not seekable.
+ */
+ if(!decoder->private_->internal_reset_hack) {
+ if(decoder->private_->file == stdin)
+ return false; /* can't rewind stdin, reset fails */
+ if(decoder->private_->seek_callback && decoder->private_->seek_callback(decoder, 0, decoder->private_->client_data) == FLAC__STREAM_DECODER_SEEK_STATUS_ERROR)
+ return false; /* seekable and seek fails, reset fails */
+ }
+ else
+ decoder->private_->internal_reset_hack = false;
+
+ decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_METADATA;
+
+ decoder->private_->has_stream_info = false;
+
+ free(decoder->private_->seek_table.data.seek_table.points);
+ decoder->private_->seek_table.data.seek_table.points = 0;
+ decoder->private_->has_seek_table = false;
+
+ decoder->private_->do_md5_checking = decoder->protected_->md5_checking;
+ /*
+ * This goes in reset() and not flush() because according to the spec, a
+ * fixed-blocksize stream must stay that way through the whole stream.
+ */
+ decoder->private_->fixed_block_size = decoder->private_->next_fixed_block_size = 0;
+
+ /* We initialize the FLAC__MD5Context even though we may never use it. This
+ * is because md5 checking may be turned on to start and then turned off if
+ * a seek occurs. So we init the context here and finalize it in
+ * FLAC__stream_decoder_finish() to make sure things are always cleaned up
+ * properly.
+ */
+ FLAC__MD5Init(&decoder->private_->md5context);
+
+ decoder->private_->first_frame_offset = 0;
+ decoder->private_->unparseable_frame_count = 0;
+
+ return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_process_single(FLAC__StreamDecoder *decoder)
+{
+ FLAC__bool got_a_frame;
+
+ while(1) {
+ switch(decoder->protected_->state) {
+ case FLAC__STREAM_DECODER_SEARCH_FOR_METADATA:
+ if(!find_metadata_(decoder))
+ return false; /* above function sets the status for us */
+ break;
+ case FLAC__STREAM_DECODER_READ_METADATA:
+ if(!read_metadata_(decoder))
+ return false; /* above function sets the status for us */
+ else
+ return true;
+ case FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC:
+ if(!frame_sync_(decoder))
+ return true; /* above function sets the status for us */
+ break;
+ case FLAC__STREAM_DECODER_READ_FRAME:
+ if(!read_frame_(decoder, &got_a_frame, /*do_full_decode=*/true))
+ return false; /* above function sets the status for us */
+ if(got_a_frame)
+ return true; /* above function sets the status for us */
+ break;
+ case FLAC__STREAM_DECODER_END_OF_STREAM:
+ case FLAC__STREAM_DECODER_ABORTED:
+ return true;
+ default:
+ return false;
+ }
+ }
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_process_until_end_of_metadata(FLAC__StreamDecoder *decoder)
+{
+ while(1) {
+ switch(decoder->protected_->state) {
+ case FLAC__STREAM_DECODER_SEARCH_FOR_METADATA:
+ if(!find_metadata_(decoder))
+ return false; /* above function sets the status for us */
+ break;
+ case FLAC__STREAM_DECODER_READ_METADATA:
+ if(!read_metadata_(decoder))
+ return false; /* above function sets the status for us */
+ break;
+ case FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC:
+ case FLAC__STREAM_DECODER_READ_FRAME:
+ case FLAC__STREAM_DECODER_END_OF_STREAM:
+ case FLAC__STREAM_DECODER_ABORTED:
+ return true;
+ default:
+ return false;
+ }
+ }
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_process_until_end_of_stream(FLAC__StreamDecoder *decoder)
+{
+ FLAC__bool dummy;
+
+ while(1) {
+ switch(decoder->protected_->state) {
+ case FLAC__STREAM_DECODER_SEARCH_FOR_METADATA:
+ if(!find_metadata_(decoder))
+ return false; /* above function sets the status for us */
+ break;
+ case FLAC__STREAM_DECODER_READ_METADATA:
+ if(!read_metadata_(decoder))
+ return false; /* above function sets the status for us */
+ break;
+ case FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC:
+ if(!frame_sync_(decoder))
+ return true; /* above function sets the status for us */
+ break;
+ case FLAC__STREAM_DECODER_READ_FRAME:
+ if(!read_frame_(decoder, &dummy, /*do_full_decode=*/true))
+ return false; /* above function sets the status for us */
+ break;
+ case FLAC__STREAM_DECODER_END_OF_STREAM:
+ case FLAC__STREAM_DECODER_ABORTED:
+ return true;
+ default:
+ return false;
+ }
+ }
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_skip_single_frame(FLAC__StreamDecoder *decoder)
+{
+ FLAC__bool got_a_frame;
+
+ while(1) {
+ switch(decoder->protected_->state) {
+ case FLAC__STREAM_DECODER_SEARCH_FOR_METADATA:
+ case FLAC__STREAM_DECODER_READ_METADATA:
+ return false; /* above function sets the status for us */
+ case FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC:
+ if(!frame_sync_(decoder))
+ return true; /* above function sets the status for us */
+ break;
+ case FLAC__STREAM_DECODER_READ_FRAME:
+ if(!read_frame_(decoder, &got_a_frame, /*do_full_decode=*/false))
+ return false; /* above function sets the status for us */
+ if(got_a_frame)
+ return true; /* above function sets the status for us */
+ break;
+ case FLAC__STREAM_DECODER_END_OF_STREAM:
+ case FLAC__STREAM_DECODER_ABORTED:
+ return true;
+ default:
+ return false;
+ }
+ }
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_seek_absolute(FLAC__StreamDecoder *decoder, FLAC__uint64 sample)
+{
+ FLAC__uint64 length;
+
+ if(
+ decoder->protected_->state != FLAC__STREAM_DECODER_SEARCH_FOR_METADATA &&
+ decoder->protected_->state != FLAC__STREAM_DECODER_READ_METADATA &&
+ decoder->protected_->state != FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC &&
+ decoder->protected_->state != FLAC__STREAM_DECODER_READ_FRAME &&
+ decoder->protected_->state != FLAC__STREAM_DECODER_END_OF_STREAM
+ )
+ return false;
+
+ if(0 == decoder->private_->seek_callback)
+ return false;
+
+ if(FLAC__stream_decoder_get_total_samples(decoder) > 0 && sample >= FLAC__stream_decoder_get_total_samples(decoder))
+ return false;
+
+ decoder->private_->is_seeking = true;
+
+ /* turn off md5 checking if a seek is attempted */
+ decoder->private_->do_md5_checking = false;
+
+ /* get the file length (currently our algorithm needs to know the length so it's also an error to get FLAC__STREAM_DECODER_LENGTH_STATUS_UNSUPPORTED) */
+ if(decoder->private_->length_callback(decoder, &length, decoder->private_->client_data) != FLAC__STREAM_DECODER_LENGTH_STATUS_OK) {
+ decoder->private_->is_seeking = false;
+ return false;
+ }
+
+ /* if we haven't finished processing the metadata yet, do that so we have the STREAMINFO, SEEK_TABLE, and first_frame_offset */
+ if(
+ decoder->protected_->state == FLAC__STREAM_DECODER_SEARCH_FOR_METADATA ||
+ decoder->protected_->state == FLAC__STREAM_DECODER_READ_METADATA
+ ) {
+ if(!FLAC__stream_decoder_process_until_end_of_metadata(decoder)) {
+ /* above call sets the state for us */
+ decoder->private_->is_seeking = false;
+ return false;
+ }
+ /* check this again in case we didn't know total_samples the first time */
+ if(FLAC__stream_decoder_get_total_samples(decoder) > 0 && sample >= FLAC__stream_decoder_get_total_samples(decoder)) {
+ decoder->private_->is_seeking = false;
+ return false;
+ }
+ }
+
+ {
+ const FLAC__bool ok = seek_to_absolute_sample_(decoder, length, sample);
+ decoder->private_->is_seeking = false;
+ return ok;
+ }
+}
+
+/***********************************************************************
+ *
+ * Protected class methods
+ *
+ ***********************************************************************/
+
+uint32_t FLAC__stream_decoder_get_input_bytes_unconsumed(const FLAC__StreamDecoder *decoder)
+{
+ return FLAC__bitreader_get_input_bits_unconsumed(decoder->private_->input) / 8;
+}
+
+/***********************************************************************
+ *
+ * Private class methods
+ *
+ ***********************************************************************/
+
+void set_defaults_(FLAC__StreamDecoder *decoder)
+{
+ decoder->private_->is_ogg = false;
+ decoder->private_->read_callback = 0;
+ decoder->private_->seek_callback = 0;
+ decoder->private_->tell_callback = 0;
+ decoder->private_->length_callback = 0;
+ decoder->private_->eof_callback = 0;
+ decoder->private_->write_callback = 0;
+ decoder->private_->metadata_callback = 0;
+ decoder->private_->error_callback = 0;
+ decoder->private_->client_data = 0;
+
+ memset(decoder->private_->metadata_filter, 0, sizeof(decoder->private_->metadata_filter));
+ decoder->private_->metadata_filter[FLAC__METADATA_TYPE_STREAMINFO] = true;
+ decoder->private_->metadata_filter_ids_count = 0;
+
+ decoder->protected_->md5_checking = false;
+}
+
+/*
+ * This will forcibly set stdin to binary mode (for OSes that require it)
+ */
+FILE *get_binary_stdin_(void)
+{
+ /* if something breaks here it is probably due to the presence or
+ * absence of an underscore before the identifiers 'setmode',
+ * 'fileno', and/or 'O_BINARY'; check your system header files.
+ */
+#if defined _MSC_VER || defined __MINGW32__
+ _setmode(_fileno(stdin), _O_BINARY);
+#elif defined __EMX__
+ setmode(fileno(stdin), O_BINARY);
+#endif
+
+ return stdin;
+}
+
+FLAC__bool allocate_output_(FLAC__StreamDecoder *decoder, uint32_t size, uint32_t channels)
+{
+ uint32_t i;
+ FLAC__int32 *tmp;
+
+ if(size <= decoder->private_->output_capacity && channels <= decoder->private_->output_channels)
+ return true;
+
+ /* simply using realloc() is not practical because the number of channels may change mid-stream */
+
+ for(i = 0; i < FLAC__MAX_CHANNELS; i++) {
+ if(0 != decoder->private_->output[i]) {
+ free(decoder->private_->output[i]-4);
+ decoder->private_->output[i] = 0;
+ }
+ if(0 != decoder->private_->residual_unaligned[i]) {
+ free(decoder->private_->residual_unaligned[i]);
+ decoder->private_->residual_unaligned[i] = decoder->private_->residual[i] = 0;
+ }
+ }
+
+ for(i = 0; i < channels; i++) {
+ /* WATCHOUT:
+ * FLAC__lpc_restore_signal_asm_ia32_mmx() and ..._intrin_sseN()
+ * require that the output arrays have a buffer of up to 3 zeroes
+ * in front (at negative indices) for alignment purposes;
+ * we use 4 to keep the data well-aligned.
+ */
+ tmp = safe_malloc_muladd2_(sizeof(FLAC__int32), /*times (*/size, /*+*/4/*)*/);
+ if(tmp == 0) {
+ decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+ return false;
+ }
+ memset(tmp, 0, sizeof(FLAC__int32)*4);
+ decoder->private_->output[i] = tmp + 4;
+
+ if(!FLAC__memory_alloc_aligned_int32_array(size, &decoder->private_->residual_unaligned[i], &decoder->private_->residual[i])) {
+ decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+ return false;
+ }
+ }
+
+ decoder->private_->output_capacity = size;
+ decoder->private_->output_channels = channels;
+
+ return true;
+}
+
+FLAC__bool has_id_filtered_(FLAC__StreamDecoder *decoder, FLAC__byte *id)
+{
+ size_t i;
+
+ for(i = 0; i < decoder->private_->metadata_filter_ids_count; i++)
+ if(0 == memcmp(decoder->private_->metadata_filter_ids + i * (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8), id, (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8)))
+ return true;
+
+ return false;
+}
+
+FLAC__bool find_metadata_(FLAC__StreamDecoder *decoder)
+{
+ FLAC__uint32 x;
+ uint32_t i, id;
+ FLAC__bool first = true;
+
+ for(i = id = 0; i < 4; ) {
+ if(decoder->private_->cached) {
+ x = (FLAC__uint32)decoder->private_->lookahead;
+ decoder->private_->cached = false;
+ }
+ else {
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 8))
+ return false; /* read_callback_ sets the state for us */
+ }
+ if(x == FLAC__STREAM_SYNC_STRING[i]) {
+ first = true;
+ i++;
+ id = 0;
+ continue;
+ }
+
+ if(id >= 3)
+ return false;
+
+ if(x == ID3V2_TAG_[id]) {
+ id++;
+ i = 0;
+ if(id == 3) {
+ if(!skip_id3v2_tag_(decoder))
+ return false; /* skip_id3v2_tag_ sets the state for us */
+ }
+ continue;
+ }
+ id = 0;
+ if(x == 0xff) { /* MAGIC NUMBER for the first 8 frame sync bits */
+ decoder->private_->header_warmup[0] = (FLAC__byte)x;
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 8))
+ return false; /* read_callback_ sets the state for us */
+
+ /* we have to check if we just read two 0xff's in a row; the second may actually be the beginning of the sync code */
+ /* else we have to check if the second byte is the end of a sync code */
+ if(x == 0xff) { /* MAGIC NUMBER for the first 8 frame sync bits */
+ decoder->private_->lookahead = (FLAC__byte)x;
+ decoder->private_->cached = true;
+ }
+ else if(x >> 1 == 0x7c) { /* MAGIC NUMBER for the last 6 sync bits and reserved 7th bit */
+ decoder->private_->header_warmup[1] = (FLAC__byte)x;
+ decoder->protected_->state = FLAC__STREAM_DECODER_READ_FRAME;
+ return true;
+ }
+ }
+ i = 0;
+ if(first) {
+ send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC);
+ first = false;
+ }
+ }
+
+ decoder->protected_->state = FLAC__STREAM_DECODER_READ_METADATA;
+ return true;
+}
+
+FLAC__bool read_metadata_(FLAC__StreamDecoder *decoder)
+{
+ FLAC__bool is_last;
+ FLAC__uint32 i, x, type, length;
+
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_IS_LAST_LEN))
+ return false; /* read_callback_ sets the state for us */
+ is_last = x? true : false;
+
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &type, FLAC__STREAM_METADATA_TYPE_LEN))
+ return false; /* read_callback_ sets the state for us */
+
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &length, FLAC__STREAM_METADATA_LENGTH_LEN))
+ return false; /* read_callback_ sets the state for us */
+
+ if(type == FLAC__METADATA_TYPE_STREAMINFO) {
+ if(!read_metadata_streaminfo_(decoder, is_last, length))
+ return false;
+
+ decoder->private_->has_stream_info = true;
+ if(0 == memcmp(decoder->private_->stream_info.data.stream_info.md5sum, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16))
+ decoder->private_->do_md5_checking = false;
+ if(!decoder->private_->is_seeking && decoder->private_->metadata_filter[FLAC__METADATA_TYPE_STREAMINFO] && decoder->private_->metadata_callback)
+ decoder->private_->metadata_callback(decoder, &decoder->private_->stream_info, decoder->private_->client_data);
+ }
+ else if(type == FLAC__METADATA_TYPE_SEEKTABLE) {
+ /* just in case we already have a seek table, and reading the next one fails: */
+ decoder->private_->has_seek_table = false;
+
+ if(!read_metadata_seektable_(decoder, is_last, length))
+ return false;
+
+ decoder->private_->has_seek_table = true;
+ if(!decoder->private_->is_seeking && decoder->private_->metadata_filter[FLAC__METADATA_TYPE_SEEKTABLE] && decoder->private_->metadata_callback)
+ decoder->private_->metadata_callback(decoder, &decoder->private_->seek_table, decoder->private_->client_data);
+ }
+ else {
+ FLAC__bool skip_it = !decoder->private_->metadata_filter[type];
+ uint32_t real_length = length;
+ FLAC__StreamMetadata block;
+
+ memset(&block, 0, sizeof(block));
+ block.is_last = is_last;
+ block.type = (FLAC__MetadataType)type;
+ block.length = length;
+
+ if(type == FLAC__METADATA_TYPE_APPLICATION) {
+ if(!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, block.data.application.id, FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8))
+ return false; /* read_callback_ sets the state for us */
+
+ if(real_length < FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8) { /* underflow check */
+ decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;/*@@@@@@ maybe wrong error? need to resync?*/
+ return false;
+ }
+
+ real_length -= FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8;
+
+ if(decoder->private_->metadata_filter_ids_count > 0 && has_id_filtered_(decoder, block.data.application.id))
+ skip_it = !skip_it;
+ }
+
+ if(skip_it) {
+ if(!FLAC__bitreader_skip_byte_block_aligned_no_crc(decoder->private_->input, real_length))
+ return false; /* read_callback_ sets the state for us */
+ }
+ else {
+ FLAC__bool ok = true;
+ switch(type) {
+ case FLAC__METADATA_TYPE_PADDING:
+ /* skip the padding bytes */
+ if(!FLAC__bitreader_skip_byte_block_aligned_no_crc(decoder->private_->input, real_length))
+ ok = false; /* read_callback_ sets the state for us */
+ break;
+ case FLAC__METADATA_TYPE_APPLICATION:
+ /* remember, we read the ID already */
+ if(real_length > 0) {
+ if(0 == (block.data.application.data = malloc(real_length))) {
+ decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+ ok = false;
+ }
+ else if(!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, block.data.application.data, real_length))
+ ok = false; /* read_callback_ sets the state for us */
+ }
+ else
+ block.data.application.data = 0;
+ break;
+ case FLAC__METADATA_TYPE_VORBIS_COMMENT:
+ if(!read_metadata_vorbiscomment_(decoder, &block.data.vorbis_comment, real_length))
+ ok = false;
+ break;
+ case FLAC__METADATA_TYPE_CUESHEET:
+ if(!read_metadata_cuesheet_(decoder, &block.data.cue_sheet))
+ ok = false;
+ break;
+ case FLAC__METADATA_TYPE_PICTURE:
+ if(!read_metadata_picture_(decoder, &block.data.picture))
+ ok = false;
+ break;
+ case FLAC__METADATA_TYPE_STREAMINFO:
+ case FLAC__METADATA_TYPE_SEEKTABLE:
+ break;
+ default:
+ if(real_length > 0) {
+ if(0 == (block.data.unknown.data = malloc(real_length))) {
+ decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+ ok = false;
+ }
+ else if(!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, block.data.unknown.data, real_length))
+ ok = false; /* read_callback_ sets the state for us */
+ }
+ else
+ block.data.unknown.data = 0;
+ break;
+ }
+ if(ok && !decoder->private_->is_seeking && decoder->private_->metadata_callback)
+ decoder->private_->metadata_callback(decoder, &block, decoder->private_->client_data);
+
+ /* now we have to free any malloc()ed data in the block */
+ switch(type) {
+ case FLAC__METADATA_TYPE_PADDING:
+ break;
+ case FLAC__METADATA_TYPE_APPLICATION:
+ if(0 != block.data.application.data)
+ free(block.data.application.data);
+ break;
+ case FLAC__METADATA_TYPE_VORBIS_COMMENT:
+ if(0 != block.data.vorbis_comment.vendor_string.entry)
+ free(block.data.vorbis_comment.vendor_string.entry);
+ if(block.data.vorbis_comment.num_comments > 0)
+ for(i = 0; i < block.data.vorbis_comment.num_comments; i++)
+ if(0 != block.data.vorbis_comment.comments[i].entry)
+ free(block.data.vorbis_comment.comments[i].entry);
+ if(0 != block.data.vorbis_comment.comments)
+ free(block.data.vorbis_comment.comments);
+ break;
+ case FLAC__METADATA_TYPE_CUESHEET:
+ if(block.data.cue_sheet.num_tracks > 0)
+ for(i = 0; i < block.data.cue_sheet.num_tracks; i++)
+ if(0 != block.data.cue_sheet.tracks[i].indices)
+ free(block.data.cue_sheet.tracks[i].indices);
+ if(0 != block.data.cue_sheet.tracks)
+ free(block.data.cue_sheet.tracks);
+ break;
+ case FLAC__METADATA_TYPE_PICTURE:
+ if(0 != block.data.picture.mime_type)
+ free(block.data.picture.mime_type);
+ if(0 != block.data.picture.description)
+ free(block.data.picture.description);
+ if(0 != block.data.picture.data)
+ free(block.data.picture.data);
+ break;
+ case FLAC__METADATA_TYPE_STREAMINFO:
+ case FLAC__METADATA_TYPE_SEEKTABLE:
+ default:
+ if(0 != block.data.unknown.data)
+ free(block.data.unknown.data);
+ break;
+ }
+
+ if(!ok) /* anything that unsets "ok" should also make sure decoder->protected_->state is updated */
+ return false;
+ }
+ }
+
+ if(is_last) {
+ /* if this fails, it's OK, it's just a hint for the seek routine */
+ if(!FLAC__stream_decoder_get_decode_position(decoder, &decoder->private_->first_frame_offset))
+ decoder->private_->first_frame_offset = 0;
+ decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+ }
+
+ return true;
+}
+
+FLAC__bool read_metadata_streaminfo_(FLAC__StreamDecoder *decoder, FLAC__bool is_last, uint32_t length)
+{
+ FLAC__uint32 x;
+ uint32_t bits, used_bits = 0;
+
+ decoder->private_->stream_info.type = FLAC__METADATA_TYPE_STREAMINFO;
+ decoder->private_->stream_info.is_last = is_last;
+ decoder->private_->stream_info.length = length;
+
+ bits = FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN;
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, bits))
+ return false; /* read_callback_ sets the state for us */
+ decoder->private_->stream_info.data.stream_info.min_blocksize = x;
+ used_bits += bits;
+
+ bits = FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN;
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN))
+ return false; /* read_callback_ sets the state for us */
+ decoder->private_->stream_info.data.stream_info.max_blocksize = x;
+ used_bits += bits;
+
+ bits = FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN;
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN))
+ return false; /* read_callback_ sets the state for us */
+ decoder->private_->stream_info.data.stream_info.min_framesize = x;
+ used_bits += bits;
+
+ bits = FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN;
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN))
+ return false; /* read_callback_ sets the state for us */
+ decoder->private_->stream_info.data.stream_info.max_framesize = x;
+ used_bits += bits;
+
+ bits = FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN;
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN))
+ return false; /* read_callback_ sets the state for us */
+ decoder->private_->stream_info.data.stream_info.sample_rate = x;
+ used_bits += bits;
+
+ bits = FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN;
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN))
+ return false; /* read_callback_ sets the state for us */
+ decoder->private_->stream_info.data.stream_info.channels = x+1;
+ used_bits += bits;
+
+ bits = FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN;
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN))
+ return false; /* read_callback_ sets the state for us */
+ decoder->private_->stream_info.data.stream_info.bits_per_sample = x+1;
+ used_bits += bits;
+
+ bits = FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN;
+ if(!FLAC__bitreader_read_raw_uint64(decoder->private_->input, &decoder->private_->stream_info.data.stream_info.total_samples, FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN))
+ return false; /* read_callback_ sets the state for us */
+ used_bits += bits;
+
+ if(!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, decoder->private_->stream_info.data.stream_info.md5sum, 16))
+ return false; /* read_callback_ sets the state for us */
+ used_bits += 16*8;
+
+ /* skip the rest of the block */
+ length -= (used_bits / 8);
+ if(!FLAC__bitreader_skip_byte_block_aligned_no_crc(decoder->private_->input, length))
+ return false; /* read_callback_ sets the state for us */
+
+ return true;
+}
+
+FLAC__bool read_metadata_seektable_(FLAC__StreamDecoder *decoder, FLAC__bool is_last, uint32_t length)
+{
+ FLAC__uint32 i, x;
+ FLAC__uint64 xx;
+
+ decoder->private_->seek_table.type = FLAC__METADATA_TYPE_SEEKTABLE;
+ decoder->private_->seek_table.is_last = is_last;
+ decoder->private_->seek_table.length = length;
+
+ decoder->private_->seek_table.data.seek_table.num_points = length / FLAC__STREAM_METADATA_SEEKPOINT_LENGTH;
+
+ /* use realloc since we may pass through here several times (e.g. after seeking) */
+ if(0 == (decoder->private_->seek_table.data.seek_table.points = safe_realloc_mul_2op_(decoder->private_->seek_table.data.seek_table.points, decoder->private_->seek_table.data.seek_table.num_points, /*times*/sizeof(FLAC__StreamMetadata_SeekPoint)))) {
+ decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+ return false;
+ }
+ for(i = 0; i < decoder->private_->seek_table.data.seek_table.num_points; i++) {
+ if(!FLAC__bitreader_read_raw_uint64(decoder->private_->input, &xx, FLAC__STREAM_METADATA_SEEKPOINT_SAMPLE_NUMBER_LEN))
+ return false; /* read_callback_ sets the state for us */
+ decoder->private_->seek_table.data.seek_table.points[i].sample_number = xx;
+
+ if(!FLAC__bitreader_read_raw_uint64(decoder->private_->input, &xx, FLAC__STREAM_METADATA_SEEKPOINT_STREAM_OFFSET_LEN))
+ return false; /* read_callback_ sets the state for us */
+ decoder->private_->seek_table.data.seek_table.points[i].stream_offset = xx;
+
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_SEEKPOINT_FRAME_SAMPLES_LEN))
+ return false; /* read_callback_ sets the state for us */
+ decoder->private_->seek_table.data.seek_table.points[i].frame_samples = x;
+ }
+ length -= (decoder->private_->seek_table.data.seek_table.num_points * FLAC__STREAM_METADATA_SEEKPOINT_LENGTH);
+ /* if there is a partial point left, skip over it */
+ if(length > 0) {
+ /*@@@ do a send_error_to_client_() here? there's an argument for either way */
+ if(!FLAC__bitreader_skip_byte_block_aligned_no_crc(decoder->private_->input, length))
+ return false; /* read_callback_ sets the state for us */
+ }
+
+ return true;
+}
+
+FLAC__bool read_metadata_vorbiscomment_(FLAC__StreamDecoder *decoder, FLAC__StreamMetadata_VorbisComment *obj, uint32_t length)
+{
+ FLAC__uint32 i;
+
+ /* read vendor string */
+ if (length >= 8) {
+ length -= 8; /* vendor string length + num comments entries alone take 8 bytes */
+ if (!FLAC__bitreader_read_uint32_little_endian(decoder->private_->input, &obj->vendor_string.length))
+ return false; /* read_callback_ sets the state for us */
+ if (obj->vendor_string.length > 0) {
+ if (length < obj->vendor_string.length) {
+ obj->vendor_string.length = 0;
+ obj->vendor_string.entry = 0;
+ goto skip;
+ }
+ else
+ length -= obj->vendor_string.length;
+ if (0 == (obj->vendor_string.entry = safe_malloc_add_2op_(obj->vendor_string.length, /*+*/1))) {
+ decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+ return false;
+ }
+ if (!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, obj->vendor_string.entry, obj->vendor_string.length))
+ return false; /* read_callback_ sets the state for us */
+ obj->vendor_string.entry[obj->vendor_string.length] = '\0';
+ }
+ else
+ obj->vendor_string.entry = 0;
+
+ /* read num comments */
+ if (!FLAC__bitreader_read_uint32_little_endian(decoder->private_->input, &obj->num_comments))
+ return false; /* read_callback_ sets the state for us */
+
+ /* read comments */
+ if (obj->num_comments > 100000) {
+ /* Possibly malicious file. */
+ obj->num_comments = 0;
+ return false;
+ }
+ if (obj->num_comments > 0) {
+ if (0 == (obj->comments = safe_malloc_mul_2op_p(obj->num_comments, /*times*/sizeof(FLAC__StreamMetadata_VorbisComment_Entry)))) {
+ obj->num_comments = 0;
+ decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+ return false;
+ }
+ for (i = 0; i < obj->num_comments; i++) {
+ /* Initialize here just to make sure. */
+ obj->comments[i].length = 0;
+ obj->comments[i].entry = 0;
+
+ if (length < 4) {
+ obj->num_comments = i;
+ goto skip;
+ }
+ else
+ length -= 4;
+ if (!FLAC__bitreader_read_uint32_little_endian(decoder->private_->input, &obj->comments[i].length)) {
+ obj->num_comments = i;
+ return false; /* read_callback_ sets the state for us */
+ }
+ if (obj->comments[i].length > 0) {
+ if (length < obj->comments[i].length) {
+ obj->num_comments = i;
+ goto skip;
+ }
+ else
+ length -= obj->comments[i].length;
+ if (0 == (obj->comments[i].entry = safe_malloc_add_2op_(obj->comments[i].length, /*+*/1))) {
+ decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+ obj->num_comments = i;
+ return false;
+ }
+ memset (obj->comments[i].entry, 0, obj->comments[i].length) ;
+ if (!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, obj->comments[i].entry, obj->comments[i].length)) {
+ /* Current i-th entry is bad, so we delete it. */
+ free (obj->comments[i].entry) ;
+ obj->comments[i].entry = NULL ;
+ obj->num_comments = i;
+ goto skip;
+ }
+ obj->comments[i].entry[obj->comments[i].length] = '\0';
+ }
+ else
+ obj->comments[i].entry = 0;
+ }
+ }
+ }
+
+ skip:
+ if (length > 0) {
+ /* length > 0 can only happen on files with invalid data in comments */
+ if(obj->num_comments < 1) {
+ free(obj->comments);
+ obj->comments = NULL;
+ }
+ if(!FLAC__bitreader_skip_byte_block_aligned_no_crc(decoder->private_->input, length))
+ return false; /* read_callback_ sets the state for us */
+ }
+
+ return true;
+}
+
+FLAC__bool read_metadata_cuesheet_(FLAC__StreamDecoder *decoder, FLAC__StreamMetadata_CueSheet *obj)
+{
+ FLAC__uint32 i, j, x;
+
+ memset(obj, 0, sizeof(FLAC__StreamMetadata_CueSheet));
+
+ if(!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, (FLAC__byte*)obj->media_catalog_number, FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN/8))
+ return false; /* read_callback_ sets the state for us */
+
+ if(!FLAC__bitreader_read_raw_uint64(decoder->private_->input, &obj->lead_in, FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN))
+ return false; /* read_callback_ sets the state for us */
+
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN))
+ return false; /* read_callback_ sets the state for us */
+ obj->is_cd = x? true : false;
+
+ if(!FLAC__bitreader_skip_bits_no_crc(decoder->private_->input, FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN))
+ return false; /* read_callback_ sets the state for us */
+
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN))
+ return false; /* read_callback_ sets the state for us */
+ obj->num_tracks = x;
+
+ if(obj->num_tracks > 0) {
+ if(0 == (obj->tracks = safe_calloc_(obj->num_tracks, sizeof(FLAC__StreamMetadata_CueSheet_Track)))) {
+ decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+ return false;
+ }
+ for(i = 0; i < obj->num_tracks; i++) {
+ FLAC__StreamMetadata_CueSheet_Track *track = &obj->tracks[i];
+ if(!FLAC__bitreader_read_raw_uint64(decoder->private_->input, &track->offset, FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN))
+ return false; /* read_callback_ sets the state for us */
+
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN))
+ return false; /* read_callback_ sets the state for us */
+ track->number = (FLAC__byte)x;
+
+ if(!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, (FLAC__byte*)track->isrc, FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN/8))
+ return false; /* read_callback_ sets the state for us */
+
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN))
+ return false; /* read_callback_ sets the state for us */
+ track->type = x;
+
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN))
+ return false; /* read_callback_ sets the state for us */
+ track->pre_emphasis = x;
+
+ if(!FLAC__bitreader_skip_bits_no_crc(decoder->private_->input, FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN))
+ return false; /* read_callback_ sets the state for us */
+
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN))
+ return false; /* read_callback_ sets the state for us */
+ track->num_indices = (FLAC__byte)x;
+
+ if(track->num_indices > 0) {
+ if(0 == (track->indices = safe_calloc_(track->num_indices, sizeof(FLAC__StreamMetadata_CueSheet_Index)))) {
+ decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+ return false;
+ }
+ for(j = 0; j < track->num_indices; j++) {
+ FLAC__StreamMetadata_CueSheet_Index *indx = &track->indices[j];
+ if(!FLAC__bitreader_read_raw_uint64(decoder->private_->input, &indx->offset, FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN))
+ return false; /* read_callback_ sets the state for us */
+
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN))
+ return false; /* read_callback_ sets the state for us */
+ indx->number = (FLAC__byte)x;
+
+ if(!FLAC__bitreader_skip_bits_no_crc(decoder->private_->input, FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN))
+ return false; /* read_callback_ sets the state for us */
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+FLAC__bool read_metadata_picture_(FLAC__StreamDecoder *decoder, FLAC__StreamMetadata_Picture *obj)
+{
+ FLAC__uint32 x;
+
+ /* read type */
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_PICTURE_TYPE_LEN))
+ return false; /* read_callback_ sets the state for us */
+ obj->type = x;
+
+ /* read MIME type */
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN))
+ return false; /* read_callback_ sets the state for us */
+ if(0 == (obj->mime_type = safe_malloc_add_2op_(x, /*+*/1))) {
+ decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+ return false;
+ }
+ if(x > 0) {
+ if(!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, (FLAC__byte*)obj->mime_type, x))
+ return false; /* read_callback_ sets the state for us */
+ }
+ obj->mime_type[x] = '\0';
+
+ /* read description */
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN))
+ return false; /* read_callback_ sets the state for us */
+ if(0 == (obj->description = safe_malloc_add_2op_(x, /*+*/1))) {
+ decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+ return false;
+ }
+ if(x > 0) {
+ if(!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, obj->description, x))
+ return false; /* read_callback_ sets the state for us */
+ }
+ obj->description[x] = '\0';
+
+ /* read width */
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &obj->width, FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN))
+ return false; /* read_callback_ sets the state for us */
+
+ /* read height */
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &obj->height, FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN))
+ return false; /* read_callback_ sets the state for us */
+
+ /* read depth */
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &obj->depth, FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN))
+ return false; /* read_callback_ sets the state for us */
+
+ /* read colors */
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &obj->colors, FLAC__STREAM_METADATA_PICTURE_COLORS_LEN))
+ return false; /* read_callback_ sets the state for us */
+
+ /* read data */
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &(obj->data_length), FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN))
+ return false; /* read_callback_ sets the state for us */
+ if(0 == (obj->data = safe_malloc_(obj->data_length))) {
+ decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+ return false;
+ }
+ if(obj->data_length > 0) {
+ if(!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, obj->data, obj->data_length))
+ return false; /* read_callback_ sets the state for us */
+ }
+
+ return true;
+}
+
+FLAC__bool skip_id3v2_tag_(FLAC__StreamDecoder *decoder)
+{
+ FLAC__uint32 x;
+ uint32_t i, skip;
+
+ /* skip the version and flags bytes */
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 24))
+ return false; /* read_callback_ sets the state for us */
+ /* get the size (in bytes) to skip */
+ skip = 0;
+ for(i = 0; i < 4; i++) {
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 8))
+ return false; /* read_callback_ sets the state for us */
+ skip <<= 7;
+ skip |= (x & 0x7f);
+ }
+ /* skip the rest of the tag */
+ if(!FLAC__bitreader_skip_byte_block_aligned_no_crc(decoder->private_->input, skip))
+ return false; /* read_callback_ sets the state for us */
+ return true;
+}
+
+FLAC__bool frame_sync_(FLAC__StreamDecoder *decoder)
+{
+ FLAC__uint32 x;
+ FLAC__bool first = true;
+
+ /* If we know the total number of samples in the stream, stop if we've read that many. */
+ /* This will stop us, for example, from wasting time trying to sync on an ID3V1 tag. */
+ if(FLAC__stream_decoder_get_total_samples(decoder) > 0) {
+ if(decoder->private_->samples_decoded >= FLAC__stream_decoder_get_total_samples(decoder)) {
+ decoder->protected_->state = FLAC__STREAM_DECODER_END_OF_STREAM;
+ return true;
+ }
+ }
+
+ /* make sure we're byte aligned */
+ if(!FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input)) {
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__bitreader_bits_left_for_byte_alignment(decoder->private_->input)))
+ return false; /* read_callback_ sets the state for us */
+ }
+
+ while(1) {
+ if(decoder->private_->cached) {
+ x = (FLAC__uint32)decoder->private_->lookahead;
+ decoder->private_->cached = false;
+ }
+ else {
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 8))
+ return false; /* read_callback_ sets the state for us */
+ }
+ if(x == 0xff) { /* MAGIC NUMBER for the first 8 frame sync bits */
+ decoder->private_->header_warmup[0] = (FLAC__byte)x;
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 8))
+ return false; /* read_callback_ sets the state for us */
+
+ /* we have to check if we just read two 0xff's in a row; the second may actually be the beginning of the sync code */
+ /* else we have to check if the second byte is the end of a sync code */
+ if(x == 0xff) { /* MAGIC NUMBER for the first 8 frame sync bits */
+ decoder->private_->lookahead = (FLAC__byte)x;
+ decoder->private_->cached = true;
+ }
+ else if(x >> 1 == 0x7c) { /* MAGIC NUMBER for the last 6 sync bits and reserved 7th bit */
+ decoder->private_->header_warmup[1] = (FLAC__byte)x;
+ decoder->protected_->state = FLAC__STREAM_DECODER_READ_FRAME;
+ return true;
+ }
+ }
+ if(first) {
+ send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC);
+ first = false;
+ }
+ }
+
+ return true;
+}
+
+FLAC__bool read_frame_(FLAC__StreamDecoder *decoder, FLAC__bool *got_a_frame, FLAC__bool do_full_decode)
+{
+ uint32_t channel;
+ uint32_t i;
+ FLAC__int32 mid, side;
+ uint32_t frame_crc; /* the one we calculate from the input stream */
+ FLAC__uint32 x;
+
+ *got_a_frame = false;
+
+ /* init the CRC */
+ frame_crc = 0;
+ frame_crc = FLAC__CRC16_UPDATE(decoder->private_->header_warmup[0], frame_crc);
+ frame_crc = FLAC__CRC16_UPDATE(decoder->private_->header_warmup[1], frame_crc);
+ FLAC__bitreader_reset_read_crc16(decoder->private_->input, (FLAC__uint16)frame_crc);
+
+ if(!read_frame_header_(decoder))
+ return false;
+ if(decoder->protected_->state == FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC) /* means we didn't sync on a valid header */
+ return true;
+ if(!allocate_output_(decoder, decoder->private_->frame.header.blocksize, decoder->private_->frame.header.channels))
+ return false;
+ for(channel = 0; channel < decoder->private_->frame.header.channels; channel++) {
+ /*
+ * first figure the correct bits-per-sample of the subframe
+ */
+ uint32_t bps = decoder->private_->frame.header.bits_per_sample;
+ switch(decoder->private_->frame.header.channel_assignment) {
+ case FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT:
+ /* no adjustment needed */
+ break;
+ case FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE:
+ if(channel == 1)
+ bps++;
+ break;
+ case FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE:
+ if(channel == 0)
+ bps++;
+ break;
+ case FLAC__CHANNEL_ASSIGNMENT_MID_SIDE:
+ if(channel == 1)
+ bps++;
+ break;
+ default: break;
+ }
+ /*
+ * now read it
+ */
+ if(!read_subframe_(decoder, channel, bps, do_full_decode))
+ return false;
+ if(decoder->protected_->state == FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC) /* means bad sync or got corruption */
+ return true;
+ }
+ if(!read_zero_padding_(decoder))
+ return false;
+ if(decoder->protected_->state == FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC) /* means bad sync or got corruption (i.e. "zero bits" were not all zeroes) */
+ return true;
+
+ /*
+ * Read the frame CRC-16 from the footer and check
+ */
+ frame_crc = FLAC__bitreader_get_read_crc16(decoder->private_->input);
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__FRAME_FOOTER_CRC_LEN))
+ return false; /* read_callback_ sets the state for us */
+ if(frame_crc == x) {
+ if(do_full_decode) {
+ /* Undo any special channel coding */
+ switch(decoder->private_->frame.header.channel_assignment) {
+ case FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT:
+ /* do nothing */
+ break;
+ case FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE:
+ for(i = 0; i < decoder->private_->frame.header.blocksize; i++)
+ decoder->private_->output[1][i] = decoder->private_->output[0][i] - decoder->private_->output[1][i];
+ break;
+ case FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE:
+ for(i = 0; i < decoder->private_->frame.header.blocksize; i++)
+ decoder->private_->output[0][i] += decoder->private_->output[1][i];
+ break;
+ case FLAC__CHANNEL_ASSIGNMENT_MID_SIDE:
+ for(i = 0; i < decoder->private_->frame.header.blocksize; i++) {
+ mid = decoder->private_->output[0][i];
+ side = decoder->private_->output[1][i];
+ mid = ((uint32_t) mid) << 1;
+ mid |= (side & 1); /* i.e. if 'side' is odd... */
+ decoder->private_->output[0][i] = (mid + side) >> 1;
+ decoder->private_->output[1][i] = (mid - side) >> 1;
+ }
+ break;
+ default: break;
+ }
+ }
+ }
+ else {
+ /* Bad frame, emit error and zero the output signal */
+ send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH);
+ if(do_full_decode) {
+ for(channel = 0; channel < decoder->private_->frame.header.channels; channel++) {
+ memset(decoder->private_->output[channel], 0, sizeof(FLAC__int32) * decoder->private_->frame.header.blocksize);
+ }
+ }
+ }
+
+ *got_a_frame = true;
+
+ /* we wait to update fixed_block_size until here, when we're sure we've got a proper frame and hence a correct blocksize */
+ if(decoder->private_->next_fixed_block_size)
+ decoder->private_->fixed_block_size = decoder->private_->next_fixed_block_size;
+
+ /* put the latest values into the public section of the decoder instance */
+ decoder->protected_->channels = decoder->private_->frame.header.channels;
+ decoder->protected_->channel_assignment = decoder->private_->frame.header.channel_assignment;
+ decoder->protected_->bits_per_sample = decoder->private_->frame.header.bits_per_sample;
+ decoder->protected_->sample_rate = decoder->private_->frame.header.sample_rate;
+ decoder->protected_->blocksize = decoder->private_->frame.header.blocksize;
+ decoder->private_->samples_decoded = decoder->private_->frame.header.number.sample_number + decoder->private_->frame.header.blocksize;
+
+ /* write it */
+ if(do_full_decode) {
+ if(write_audio_frame_to_client_(decoder, &decoder->private_->frame, (const FLAC__int32 * const *)decoder->private_->output) != FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE) {
+ decoder->protected_->state = FLAC__STREAM_DECODER_ABORTED;
+ return false;
+ }
+ }
+
+ decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+ return true;
+}
+
+FLAC__bool read_frame_header_(FLAC__StreamDecoder *decoder)
+{
+ FLAC__uint32 x;
+ FLAC__uint64 xx;
+ uint32_t i, blocksize_hint = 0, sample_rate_hint = 0;
+ FLAC__byte crc8, raw_header[16]; /* MAGIC NUMBER based on the maximum frame header size, including CRC */
+ uint32_t raw_header_len;
+ FLAC__bool is_unparseable = false;
+
+ /* init the raw header with the saved bits from synchronization */
+ raw_header[0] = decoder->private_->header_warmup[0];
+ raw_header[1] = decoder->private_->header_warmup[1];
+ raw_header_len = 2;
+
+ /* check to make sure that reserved bit is 0 */
+ if(raw_header[1] & 0x02) /* MAGIC NUMBER */
+ is_unparseable = true;
+
+ /*
+ * Note that along the way as we read the header, we look for a sync
+ * code inside. If we find one it would indicate that our original
+ * sync was bad since there cannot be a sync code in a valid header.
+ *
+ * Three kinds of things can go wrong when reading the frame header:
+ * 1) We may have sync'ed incorrectly and not landed on a frame header.
+ * If we don't find a sync code, it can end up looking like we read
+ * a valid but unparseable header, until getting to the frame header
+ * CRC. Even then we could get a false positive on the CRC.
+ * 2) We may have sync'ed correctly but on an unparseable frame (from a
+ * future encoder).
+ * 3) We may be on a damaged frame which appears valid but unparseable.
+ *
+ * For all these reasons, we try and read a complete frame header as
+ * long as it seems valid, even if unparseable, up until the frame
+ * header CRC.
+ */
+
+ /*
+ * read in the raw header as bytes so we can CRC it, and parse it on the way
+ */
+ for(i = 0; i < 2; i++) {
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 8))
+ return false; /* read_callback_ sets the state for us */
+ if(x == 0xff) { /* MAGIC NUMBER for the first 8 frame sync bits */
+ /* if we get here it means our original sync was erroneous since the sync code cannot appear in the header */
+ decoder->private_->lookahead = (FLAC__byte)x;
+ decoder->private_->cached = true;
+ send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER);
+ decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+ return true;
+ }
+ raw_header[raw_header_len++] = (FLAC__byte)x;
+ }
+
+ switch(x = raw_header[2] >> 4) {
+ case 0:
+ is_unparseable = true;
+ break;
+ case 1:
+ decoder->private_->frame.header.blocksize = 192;
+ break;
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ decoder->private_->frame.header.blocksize = 576 << (x-2);
+ break;
+ case 6:
+ case 7:
+ blocksize_hint = x;
+ break;
+ case 8:
+ case 9:
+ case 10:
+ case 11:
+ case 12:
+ case 13:
+ case 14:
+ case 15:
+ decoder->private_->frame.header.blocksize = 256 << (x-8);
+ break;
+ default:
+ break;
+ }
+
+ switch(x = raw_header[2] & 0x0f) {
+ case 0:
+ if(decoder->private_->has_stream_info)
+ decoder->private_->frame.header.sample_rate = decoder->private_->stream_info.data.stream_info.sample_rate;
+ else
+ is_unparseable = true;
+ break;
+ case 1:
+ decoder->private_->frame.header.sample_rate = 88200;
+ break;
+ case 2:
+ decoder->private_->frame.header.sample_rate = 176400;
+ break;
+ case 3:
+ decoder->private_->frame.header.sample_rate = 192000;
+ break;
+ case 4:
+ decoder->private_->frame.header.sample_rate = 8000;
+ break;
+ case 5:
+ decoder->private_->frame.header.sample_rate = 16000;
+ break;
+ case 6:
+ decoder->private_->frame.header.sample_rate = 22050;
+ break;
+ case 7:
+ decoder->private_->frame.header.sample_rate = 24000;
+ break;
+ case 8:
+ decoder->private_->frame.header.sample_rate = 32000;
+ break;
+ case 9:
+ decoder->private_->frame.header.sample_rate = 44100;
+ break;
+ case 10:
+ decoder->private_->frame.header.sample_rate = 48000;
+ break;
+ case 11:
+ decoder->private_->frame.header.sample_rate = 96000;
+ break;
+ case 12:
+ case 13:
+ case 14:
+ sample_rate_hint = x;
+ break;
+ case 15:
+ send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER);
+ decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+ return true;
+ default:
+ break;
+ }
+
+ x = (uint32_t)(raw_header[3] >> 4);
+ if(x & 8) {
+ decoder->private_->frame.header.channels = 2;
+ switch(x & 7) {
+ case 0:
+ decoder->private_->frame.header.channel_assignment = FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE;
+ break;
+ case 1:
+ decoder->private_->frame.header.channel_assignment = FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE;
+ break;
+ case 2:
+ decoder->private_->frame.header.channel_assignment = FLAC__CHANNEL_ASSIGNMENT_MID_SIDE;
+ break;
+ default:
+ is_unparseable = true;
+ break;
+ }
+ }
+ else {
+ decoder->private_->frame.header.channels = (uint32_t)x + 1;
+ decoder->private_->frame.header.channel_assignment = FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT;
+ }
+
+ switch(x = (uint32_t)(raw_header[3] & 0x0e) >> 1) {
+ case 0:
+ if(decoder->private_->has_stream_info)
+ decoder->private_->frame.header.bits_per_sample = decoder->private_->stream_info.data.stream_info.bits_per_sample;
+ else
+ is_unparseable = true;
+ break;
+ case 1:
+ decoder->private_->frame.header.bits_per_sample = 8;
+ break;
+ case 2:
+ decoder->private_->frame.header.bits_per_sample = 12;
+ break;
+ case 4:
+ decoder->private_->frame.header.bits_per_sample = 16;
+ break;
+ case 5:
+ decoder->private_->frame.header.bits_per_sample = 20;
+ break;
+ case 6:
+ decoder->private_->frame.header.bits_per_sample = 24;
+ break;
+ case 3:
+ case 7:
+ is_unparseable = true;
+ break;
+ default:
+ break;
+ }
+
+ /* check to make sure that reserved bit is 0 */
+ if(raw_header[3] & 0x01) /* MAGIC NUMBER */
+ is_unparseable = true;
+
+ /* read the frame's starting sample number (or frame number as the case may be) */
+ if(
+ raw_header[1] & 0x01 ||
+ /*@@@ this clause is a concession to the old way of doing variable blocksize; the only known implementation is flake and can probably be removed without inconveniencing anyone */
+ (decoder->private_->has_stream_info && decoder->private_->stream_info.data.stream_info.min_blocksize != decoder->private_->stream_info.data.stream_info.max_blocksize)
+ ) { /* variable blocksize */
+ if(!FLAC__bitreader_read_utf8_uint64(decoder->private_->input, &xx, raw_header, &raw_header_len))
+ return false; /* read_callback_ sets the state for us */
+ if(xx == FLAC__U64L(0xffffffffffffffff)) { /* i.e. non-UTF8 code... */
+ decoder->private_->lookahead = raw_header[raw_header_len-1]; /* back up as much as we can */
+ decoder->private_->cached = true;
+ send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER);
+ decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+ return true;
+ }
+ decoder->private_->frame.header.number_type = FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER;
+ decoder->private_->frame.header.number.sample_number = xx;
+ }
+ else { /* fixed blocksize */
+ if(!FLAC__bitreader_read_utf8_uint32(decoder->private_->input, &x, raw_header, &raw_header_len))
+ return false; /* read_callback_ sets the state for us */
+ if(x == 0xffffffff) { /* i.e. non-UTF8 code... */
+ decoder->private_->lookahead = raw_header[raw_header_len-1]; /* back up as much as we can */
+ decoder->private_->cached = true;
+ send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER);
+ decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+ return true;
+ }
+ decoder->private_->frame.header.number_type = FLAC__FRAME_NUMBER_TYPE_FRAME_NUMBER;
+ decoder->private_->frame.header.number.frame_number = x;
+ }
+
+ if(blocksize_hint) {
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 8))
+ return false; /* read_callback_ sets the state for us */
+ raw_header[raw_header_len++] = (FLAC__byte)x;
+ if(blocksize_hint == 7) {
+ FLAC__uint32 _x;
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &_x, 8))
+ return false; /* read_callback_ sets the state for us */
+ raw_header[raw_header_len++] = (FLAC__byte)_x;
+ x = (x << 8) | _x;
+ }
+ decoder->private_->frame.header.blocksize = x+1;
+ }
+
+ if(sample_rate_hint) {
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 8))
+ return false; /* read_callback_ sets the state for us */
+ raw_header[raw_header_len++] = (FLAC__byte)x;
+ if(sample_rate_hint != 12) {
+ FLAC__uint32 _x;
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &_x, 8))
+ return false; /* read_callback_ sets the state for us */
+ raw_header[raw_header_len++] = (FLAC__byte)_x;
+ x = (x << 8) | _x;
+ }
+ if(sample_rate_hint == 12)
+ decoder->private_->frame.header.sample_rate = x*1000;
+ else if(sample_rate_hint == 13)
+ decoder->private_->frame.header.sample_rate = x;
+ else
+ decoder->private_->frame.header.sample_rate = x*10;
+ }
+
+ /* read the CRC-8 byte */
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 8))
+ return false; /* read_callback_ sets the state for us */
+ crc8 = (FLAC__byte)x;
+
+ if(FLAC__crc8(raw_header, raw_header_len) != crc8) {
+ send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER);
+ decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+ return true;
+ }
+
+ /* calculate the sample number from the frame number if needed */
+ decoder->private_->next_fixed_block_size = 0;
+ if(decoder->private_->frame.header.number_type == FLAC__FRAME_NUMBER_TYPE_FRAME_NUMBER) {
+ x = decoder->private_->frame.header.number.frame_number;
+ decoder->private_->frame.header.number_type = FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER;
+ if(decoder->private_->fixed_block_size)
+ decoder->private_->frame.header.number.sample_number = (FLAC__uint64)decoder->private_->fixed_block_size * (FLAC__uint64)x;
+ else if(decoder->private_->has_stream_info) {
+ if(decoder->private_->stream_info.data.stream_info.min_blocksize == decoder->private_->stream_info.data.stream_info.max_blocksize) {
+ decoder->private_->frame.header.number.sample_number = (FLAC__uint64)decoder->private_->stream_info.data.stream_info.min_blocksize * (FLAC__uint64)x;
+ decoder->private_->next_fixed_block_size = decoder->private_->stream_info.data.stream_info.max_blocksize;
+ }
+ else
+ is_unparseable = true;
+ }
+ else if(x == 0) {
+ decoder->private_->frame.header.number.sample_number = 0;
+ decoder->private_->next_fixed_block_size = decoder->private_->frame.header.blocksize;
+ }
+ else {
+ /* can only get here if the stream has invalid frame numbering and no STREAMINFO, so assume it's not the last (possibly short) frame */
+ decoder->private_->frame.header.number.sample_number = (FLAC__uint64)decoder->private_->frame.header.blocksize * (FLAC__uint64)x;
+ }
+ }
+
+ if(is_unparseable) {
+ send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM);
+ decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+ return true;
+ }
+
+ return true;
+}
+
+FLAC__bool read_subframe_(FLAC__StreamDecoder *decoder, uint32_t channel, uint32_t bps, FLAC__bool do_full_decode)
+{
+ FLAC__uint32 x;
+ FLAC__bool wasted_bits;
+ uint32_t i;
+
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 8)) /* MAGIC NUMBER */
+ return false; /* read_callback_ sets the state for us */
+
+ wasted_bits = (x & 1);
+ x &= 0xfe;
+
+ if(wasted_bits) {
+ uint32_t u;
+ if(!FLAC__bitreader_read_unary_unsigned(decoder->private_->input, &u))
+ return false; /* read_callback_ sets the state for us */
+ decoder->private_->frame.subframes[channel].wasted_bits = u+1;
+ if (decoder->private_->frame.subframes[channel].wasted_bits >= bps)
+ return false;
+ bps -= decoder->private_->frame.subframes[channel].wasted_bits;
+ }
+ else
+ decoder->private_->frame.subframes[channel].wasted_bits = 0;
+
+ /*
+ * Lots of magic numbers here
+ */
+ if(x & 0x80) {
+ send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC);
+ decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+ return true;
+ }
+ else if(x == 0) {
+ if(!read_subframe_constant_(decoder, channel, bps, do_full_decode))
+ return false;
+ }
+ else if(x == 2) {
+ if(!read_subframe_verbatim_(decoder, channel, bps, do_full_decode))
+ return false;
+ }
+ else if(x < 16) {
+ send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM);
+ decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+ return true;
+ }
+ else if(x <= 24) {
+ if(!read_subframe_fixed_(decoder, channel, bps, (x>>1)&7, do_full_decode))
+ return false;
+ if(decoder->protected_->state == FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC) /* means bad sync or got corruption */
+ return true;
+ }
+ else if(x < 64) {
+ send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM);
+ decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+ return true;
+ }
+ else {
+ if(!read_subframe_lpc_(decoder, channel, bps, ((x>>1)&31)+1, do_full_decode))
+ return false;
+ if(decoder->protected_->state == FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC) /* means bad sync or got corruption */
+ return true;
+ }
+
+ if(wasted_bits && do_full_decode) {
+ x = decoder->private_->frame.subframes[channel].wasted_bits;
+ for(i = 0; i < decoder->private_->frame.header.blocksize; i++) {
+ uint32_t val = decoder->private_->output[channel][i];
+ decoder->private_->output[channel][i] = (val << x);
+ }
+ }
+
+ return true;
+}
+
+FLAC__bool read_subframe_constant_(FLAC__StreamDecoder *decoder, uint32_t channel, uint32_t bps, FLAC__bool do_full_decode)
+{
+ FLAC__Subframe_Constant *subframe = &decoder->private_->frame.subframes[channel].data.constant;
+ FLAC__int32 x;
+ uint32_t i;
+ FLAC__int32 *output = decoder->private_->output[channel];
+
+ decoder->private_->frame.subframes[channel].type = FLAC__SUBFRAME_TYPE_CONSTANT;
+
+ if(!FLAC__bitreader_read_raw_int32(decoder->private_->input, &x, bps))
+ return false; /* read_callback_ sets the state for us */
+
+ subframe->value = x;
+
+ /* decode the subframe */
+ if(do_full_decode) {
+ for(i = 0; i < decoder->private_->frame.header.blocksize; i++)
+ output[i] = x;
+ }
+
+ return true;
+}
+
+FLAC__bool read_subframe_fixed_(FLAC__StreamDecoder *decoder, uint32_t channel, uint32_t bps, const uint32_t order, FLAC__bool do_full_decode)
+{
+ FLAC__Subframe_Fixed *subframe = &decoder->private_->frame.subframes[channel].data.fixed;
+ FLAC__int32 i32;
+ FLAC__uint32 u32;
+ uint32_t u;
+
+ decoder->private_->frame.subframes[channel].type = FLAC__SUBFRAME_TYPE_FIXED;
+
+ subframe->residual = decoder->private_->residual[channel];
+ subframe->order = order;
+
+ /* read warm-up samples */
+ for(u = 0; u < order; u++) {
+ if(!FLAC__bitreader_read_raw_int32(decoder->private_->input, &i32, bps))
+ return false; /* read_callback_ sets the state for us */
+ subframe->warmup[u] = i32;
+ }
+
+ /* read entropy coding method info */
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &u32, FLAC__ENTROPY_CODING_METHOD_TYPE_LEN))
+ return false; /* read_callback_ sets the state for us */
+ subframe->entropy_coding_method.type = (FLAC__EntropyCodingMethodType)u32;
+ switch(subframe->entropy_coding_method.type) {
+ case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE:
+ case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2:
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &u32, FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN))
+ return false; /* read_callback_ sets the state for us */
+ if(decoder->private_->frame.header.blocksize >> u32 < order) {
+ send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC);
+ decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+ return true;
+ }
+ subframe->entropy_coding_method.data.partitioned_rice.order = u32;
+ subframe->entropy_coding_method.data.partitioned_rice.contents = &decoder->private_->partitioned_rice_contents[channel];
+ break;
+ default:
+ send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM);
+ decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+ return true;
+ }
+
+ /* read residual */
+ switch(subframe->entropy_coding_method.type) {
+ case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE:
+ case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2:
+ if(!read_residual_partitioned_rice_(decoder, order, subframe->entropy_coding_method.data.partitioned_rice.order, &decoder->private_->partitioned_rice_contents[channel], decoder->private_->residual[channel], /*is_extended=*/subframe->entropy_coding_method.type == FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2))
+ return false;
+ break;
+ default:
+ break;
+ }
+
+ /* decode the subframe */
+ if(do_full_decode) {
+ memcpy(decoder->private_->output[channel], subframe->warmup, sizeof(FLAC__int32) * order);
+ FLAC__fixed_restore_signal(decoder->private_->residual[channel], decoder->private_->frame.header.blocksize-order, order, decoder->private_->output[channel]+order);
+ }
+
+ return true;
+}
+
+FLAC__bool read_subframe_lpc_(FLAC__StreamDecoder *decoder, uint32_t channel, uint32_t bps, const uint32_t order, FLAC__bool do_full_decode)
+{
+ FLAC__Subframe_LPC *subframe = &decoder->private_->frame.subframes[channel].data.lpc;
+ FLAC__int32 i32;
+ FLAC__uint32 u32;
+ uint32_t u;
+
+ decoder->private_->frame.subframes[channel].type = FLAC__SUBFRAME_TYPE_LPC;
+
+ subframe->residual = decoder->private_->residual[channel];
+ subframe->order = order;
+
+ /* read warm-up samples */
+ for(u = 0; u < order; u++) {
+ if(!FLAC__bitreader_read_raw_int32(decoder->private_->input, &i32, bps))
+ return false; /* read_callback_ sets the state for us */
+ subframe->warmup[u] = i32;
+ }
+
+ /* read qlp coeff precision */
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &u32, FLAC__SUBFRAME_LPC_QLP_COEFF_PRECISION_LEN))
+ return false; /* read_callback_ sets the state for us */
+ if(u32 == (1u << FLAC__SUBFRAME_LPC_QLP_COEFF_PRECISION_LEN) - 1) {
+ send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC);
+ decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+ return true;
+ }
+ subframe->qlp_coeff_precision = u32+1;
+
+ /* read qlp shift */
+ if(!FLAC__bitreader_read_raw_int32(decoder->private_->input, &i32, FLAC__SUBFRAME_LPC_QLP_SHIFT_LEN))
+ return false; /* read_callback_ sets the state for us */
+ if(i32 < 0) {
+ send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC);
+ decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+ return true;
+ }
+ subframe->quantization_level = i32;
+
+ /* read quantized lp coefficiencts */
+ for(u = 0; u < order; u++) {
+ if(!FLAC__bitreader_read_raw_int32(decoder->private_->input, &i32, subframe->qlp_coeff_precision))
+ return false; /* read_callback_ sets the state for us */
+ subframe->qlp_coeff[u] = i32;
+ }
+
+ /* read entropy coding method info */
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &u32, FLAC__ENTROPY_CODING_METHOD_TYPE_LEN))
+ return false; /* read_callback_ sets the state for us */
+ subframe->entropy_coding_method.type = (FLAC__EntropyCodingMethodType)u32;
+ switch(subframe->entropy_coding_method.type) {
+ case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE:
+ case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2:
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &u32, FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN))
+ return false; /* read_callback_ sets the state for us */
+ if(decoder->private_->frame.header.blocksize >> u32 < order) {
+ send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC);
+ decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+ return true;
+ }
+ subframe->entropy_coding_method.data.partitioned_rice.order = u32;
+ subframe->entropy_coding_method.data.partitioned_rice.contents = &decoder->private_->partitioned_rice_contents[channel];
+ break;
+ default:
+ send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM);
+ decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+ return true;
+ }
+
+ /* read residual */
+ switch(subframe->entropy_coding_method.type) {
+ case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE:
+ case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2:
+ if(!read_residual_partitioned_rice_(decoder, order, subframe->entropy_coding_method.data.partitioned_rice.order, &decoder->private_->partitioned_rice_contents[channel], decoder->private_->residual[channel], /*is_extended=*/subframe->entropy_coding_method.type == FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2))
+ return false;
+ break;
+ default:
+ break;
+ }
+
+ /* decode the subframe */
+ if(do_full_decode) {
+ memcpy(decoder->private_->output[channel], subframe->warmup, sizeof(FLAC__int32) * order);
+ if(bps + subframe->qlp_coeff_precision + FLAC__bitmath_ilog2(order) <= 32)
+ if(bps <= 16 && subframe->qlp_coeff_precision <= 16)
+ decoder->private_->local_lpc_restore_signal_16bit(decoder->private_->residual[channel], decoder->private_->frame.header.blocksize-order, subframe->qlp_coeff, order, subframe->quantization_level, decoder->private_->output[channel]+order);
+ else
+ decoder->private_->local_lpc_restore_signal(decoder->private_->residual[channel], decoder->private_->frame.header.blocksize-order, subframe->qlp_coeff, order, subframe->quantization_level, decoder->private_->output[channel]+order);
+ else
+ decoder->private_->local_lpc_restore_signal_64bit(decoder->private_->residual[channel], decoder->private_->frame.header.blocksize-order, subframe->qlp_coeff, order, subframe->quantization_level, decoder->private_->output[channel]+order);
+ }
+
+ return true;
+}
+
+FLAC__bool read_subframe_verbatim_(FLAC__StreamDecoder *decoder, uint32_t channel, uint32_t bps, FLAC__bool do_full_decode)
+{
+ FLAC__Subframe_Verbatim *subframe = &decoder->private_->frame.subframes[channel].data.verbatim;
+ FLAC__int32 x, *residual = decoder->private_->residual[channel];
+ uint32_t i;
+
+ decoder->private_->frame.subframes[channel].type = FLAC__SUBFRAME_TYPE_VERBATIM;
+
+ subframe->data = residual;
+
+ for(i = 0; i < decoder->private_->frame.header.blocksize; i++) {
+ if(!FLAC__bitreader_read_raw_int32(decoder->private_->input, &x, bps))
+ return false; /* read_callback_ sets the state for us */
+ residual[i] = x;
+ }
+
+ /* decode the subframe */
+ if(do_full_decode)
+ memcpy(decoder->private_->output[channel], subframe->data, sizeof(FLAC__int32) * decoder->private_->frame.header.blocksize);
+
+ return true;
+}
+
+FLAC__bool read_residual_partitioned_rice_(FLAC__StreamDecoder *decoder, uint32_t predictor_order, uint32_t partition_order, FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents, FLAC__int32 *residual, FLAC__bool is_extended)
+{
+ FLAC__uint32 rice_parameter;
+ int i;
+ uint32_t partition, sample, u;
+ const uint32_t partitions = 1u << partition_order;
+ const uint32_t partition_samples = partition_order > 0? decoder->private_->frame.header.blocksize >> partition_order : decoder->private_->frame.header.blocksize - predictor_order;
+ const uint32_t plen = is_extended? FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_PARAMETER_LEN : FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN;
+ const uint32_t pesc = is_extended? FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_ESCAPE_PARAMETER : FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER;
+
+ if(!FLAC__format_entropy_coding_method_partitioned_rice_contents_ensure_size(partitioned_rice_contents, flac_max(6u, partition_order))) {
+ decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+ return false;
+ }
+
+ sample = 0;
+ for(partition = 0; partition < partitions; partition++) {
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &rice_parameter, plen))
+ return false; /* read_callback_ sets the state for us */
+ partitioned_rice_contents->parameters[partition] = rice_parameter;
+ if(rice_parameter < pesc) {
+ partitioned_rice_contents->raw_bits[partition] = 0;
+ u = (partition_order == 0 || partition > 0)? partition_samples : partition_samples - predictor_order;
+ if(!FLAC__bitreader_read_rice_signed_block(decoder->private_->input, residual + sample, u, rice_parameter))
+ return false; /* read_callback_ sets the state for us */
+ sample += u;
+ }
+ else {
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &rice_parameter, FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_RAW_LEN))
+ return false; /* read_callback_ sets the state for us */
+ partitioned_rice_contents->raw_bits[partition] = rice_parameter;
+ for(u = (partition_order == 0 || partition > 0)? 0 : predictor_order; u < partition_samples; u++, sample++) {
+ if(!FLAC__bitreader_read_raw_int32(decoder->private_->input, &i, rice_parameter))
+ return false; /* read_callback_ sets the state for us */
+ residual[sample] = i;
+ }
+ }
+ }
+
+ return true;
+}
+
+FLAC__bool read_zero_padding_(FLAC__StreamDecoder *decoder)
+{
+ if(!FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input)) {
+ FLAC__uint32 zero = 0;
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &zero, FLAC__bitreader_bits_left_for_byte_alignment(decoder->private_->input)))
+ return false; /* read_callback_ sets the state for us */
+ if(zero != 0) {
+ send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC);
+ decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+ }
+ }
+ return true;
+}
+
+FLAC__bool read_callback_(FLAC__byte buffer[], size_t *bytes, void *client_data)
+{
+ FLAC__StreamDecoder *decoder = (FLAC__StreamDecoder *)client_data;
+
+ if(
+ decoder->private_->eof_callback && decoder->private_->eof_callback(decoder, decoder->private_->client_data)
+ ) {
+ *bytes = 0;
+ decoder->protected_->state = FLAC__STREAM_DECODER_END_OF_STREAM;
+ return false;
+ }
+ else if(*bytes > 0) {
+ /* While seeking, it is possible for our seek to land in the
+ * middle of audio data that looks exactly like a frame header
+ * from a future version of an encoder. When that happens, our
+ * error callback will get an
+ * FLAC__STREAM_DECODER_UNPARSEABLE_STREAM and increment its
+ * unparseable_frame_count. But there is a remote possibility
+ * that it is properly synced at such a "future-codec frame",
+ * so to make sure, we wait to see many "unparseable" errors in
+ * a row before bailing out.
+ */
+ if(decoder->private_->is_seeking && decoder->private_->unparseable_frame_count > 20) {
+ decoder->protected_->state = FLAC__STREAM_DECODER_ABORTED;
+ return false;
+ }
+ else {
+ const FLAC__StreamDecoderReadStatus status =
+ decoder->private_->read_callback(decoder, buffer, bytes, decoder->private_->client_data)
+ ;
+ if(status == FLAC__STREAM_DECODER_READ_STATUS_ABORT) {
+ decoder->protected_->state = FLAC__STREAM_DECODER_ABORTED;
+ return false;
+ }
+ else if(*bytes == 0) {
+ if(
+ status == FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM ||
+ (
+ decoder->private_->eof_callback && decoder->private_->eof_callback(decoder, decoder->private_->client_data)
+ )
+ ) {
+ decoder->protected_->state = FLAC__STREAM_DECODER_END_OF_STREAM;
+ return false;
+ }
+ else
+ return true;
+ }
+ else
+ return true;
+ }
+ }
+ else {
+ /* abort to avoid a deadlock */
+ decoder->protected_->state = FLAC__STREAM_DECODER_ABORTED;
+ return false;
+ }
+ /* [1] @@@ HACK NOTE: The end-of-stream checking has to be hacked around
+ * for Ogg FLAC. This is because the ogg decoder aspect can lose sync
+ * and at the same time hit the end of the stream (for example, seeking
+ * to a point that is after the beginning of the last Ogg page). There
+ * is no way to report an Ogg sync loss through the callbacks (see note
+ * in read_callback_ogg_aspect_()) so it returns CONTINUE with *bytes==0.
+ * So to keep the decoder from stopping at this point we gate the call
+ * to the eof_callback and let the Ogg decoder aspect set the
+ * end-of-stream state when it is needed.
+ */
+}
+
+FLAC__StreamDecoderWriteStatus write_audio_frame_to_client_(FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[])
+{
+ if(decoder->private_->is_seeking) {
+ FLAC__uint64 this_frame_sample = frame->header.number.sample_number;
+ FLAC__uint64 next_frame_sample = this_frame_sample + (FLAC__uint64)frame->header.blocksize;
+ FLAC__uint64 target_sample = decoder->private_->target_sample;
+
+ decoder->private_->last_frame = *frame; /* save the frame */
+ if(this_frame_sample <= target_sample && target_sample < next_frame_sample) { /* we hit our target frame */
+ uint32_t delta = (uint32_t)(target_sample - this_frame_sample);
+ /* kick out of seek mode */
+ decoder->private_->is_seeking = false;
+ /* shift out the samples before target_sample */
+ if(delta > 0) {
+ uint32_t channel;
+ const FLAC__int32 *newbuffer[FLAC__MAX_CHANNELS];
+ for(channel = 0; channel < frame->header.channels; channel++)
+ newbuffer[channel] = buffer[channel] + delta;
+ decoder->private_->last_frame.header.blocksize -= delta;
+ decoder->private_->last_frame.header.number.sample_number += (FLAC__uint64)delta;
+ /* write the relevant samples */
+ return decoder->private_->write_callback(decoder, &decoder->private_->last_frame, newbuffer, decoder->private_->client_data);
+ }
+ else {
+ /* write the relevant samples */
+ return decoder->private_->write_callback(decoder, frame, buffer, decoder->private_->client_data);
+ }
+ }
+ else {
+ return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
+ }
+ }
+ else {
+ /*
+ * If we never got STREAMINFO, turn off MD5 checking to save
+ * cycles since we don't have a sum to compare to anyway
+ */
+ if(!decoder->private_->has_stream_info)
+ decoder->private_->do_md5_checking = false;
+ if(decoder->private_->do_md5_checking) {
+ if(!FLAC__MD5Accumulate(&decoder->private_->md5context, buffer, frame->header.channels, frame->header.blocksize, (frame->header.bits_per_sample+7) / 8))
+ return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+ }
+ return decoder->private_->write_callback(decoder, frame, buffer, decoder->private_->client_data);
+ }
+}
+
+void send_error_to_client_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status)
+{
+ if(!decoder->private_->is_seeking)
+ decoder->private_->error_callback(decoder, status, decoder->private_->client_data);
+ else if(status == FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM)
+ decoder->private_->unparseable_frame_count++;
+}
+
+FLAC__bool seek_to_absolute_sample_(FLAC__StreamDecoder *decoder, FLAC__uint64 stream_length, FLAC__uint64 target_sample)
+{
+ FLAC__uint64 first_frame_offset = decoder->private_->first_frame_offset, lower_bound, upper_bound, lower_bound_sample, upper_bound_sample, this_frame_sample;
+ FLAC__int64 pos = -1;
+ int i;
+ uint32_t approx_bytes_per_frame;
+ FLAC__bool first_seek = true;
+ const FLAC__uint64 total_samples = FLAC__stream_decoder_get_total_samples(decoder);
+ const uint32_t min_blocksize = decoder->private_->stream_info.data.stream_info.min_blocksize;
+ const uint32_t max_blocksize = decoder->private_->stream_info.data.stream_info.max_blocksize;
+ const uint32_t max_framesize = decoder->private_->stream_info.data.stream_info.max_framesize;
+ const uint32_t min_framesize = decoder->private_->stream_info.data.stream_info.min_framesize;
+ /* take these from the current frame in case they've changed mid-stream */
+ uint32_t channels = FLAC__stream_decoder_get_channels(decoder);
+ uint32_t bps = FLAC__stream_decoder_get_bits_per_sample(decoder);
+ const FLAC__StreamMetadata_SeekTable *seek_table = decoder->private_->has_seek_table? &decoder->private_->seek_table.data.seek_table : 0;
+
+ /* use values from stream info if we didn't decode a frame */
+ if(channels == 0)
+ channels = decoder->private_->stream_info.data.stream_info.channels;
+ if(bps == 0)
+ bps = decoder->private_->stream_info.data.stream_info.bits_per_sample;
+
+ /* we are just guessing here */
+ if(max_framesize > 0)
+ approx_bytes_per_frame = (max_framesize + min_framesize) / 2 + 1;
+ /*
+ * Check if it's a known fixed-blocksize stream. Note that though
+ * the spec doesn't allow zeroes in the STREAMINFO block, we may
+ * never get a STREAMINFO block when decoding so the value of
+ * min_blocksize might be zero.
+ */
+ else if(min_blocksize == max_blocksize && min_blocksize > 0) {
+ /* note there are no () around 'bps/8' to keep precision up since it's an integer calculation */
+ approx_bytes_per_frame = min_blocksize * channels * bps/8 + 64;
+ }
+ else
+ approx_bytes_per_frame = 4096 * channels * bps/8 + 64;
+
+ /*
+ * First, we set an upper and lower bound on where in the
+ * stream we will search. For now we assume the worst case
+ * scenario, which is our best guess at the beginning of
+ * the first frame and end of the stream.
+ */
+ lower_bound = first_frame_offset;
+ lower_bound_sample = 0;
+ upper_bound = stream_length;
+ upper_bound_sample = total_samples > 0 ? total_samples : target_sample /*estimate it*/;
+
+ /*
+ * Now we refine the bounds if we have a seektable with
+ * suitable points. Note that according to the spec they
+ * must be ordered by ascending sample number.
+ *
+ * Note: to protect against invalid seek tables we will ignore points
+ * that have frame_samples==0 or sample_number>=total_samples
+ */
+ if(seek_table) {
+ FLAC__uint64 new_lower_bound = lower_bound;
+ FLAC__uint64 new_upper_bound = upper_bound;
+ FLAC__uint64 new_lower_bound_sample = lower_bound_sample;
+ FLAC__uint64 new_upper_bound_sample = upper_bound_sample;
+
+ /* find the closest seek point <= target_sample, if it exists */
+ for(i = (int)seek_table->num_points - 1; i >= 0; i--) {
+ if(
+ seek_table->points[i].sample_number != FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER &&
+ seek_table->points[i].frame_samples > 0 && /* defense against bad seekpoints */
+ (total_samples <= 0 || seek_table->points[i].sample_number < total_samples) && /* defense against bad seekpoints */
+ seek_table->points[i].sample_number <= target_sample
+ )
+ break;
+ }
+ if(i >= 0) { /* i.e. we found a suitable seek point... */
+ new_lower_bound = first_frame_offset + seek_table->points[i].stream_offset;
+ new_lower_bound_sample = seek_table->points[i].sample_number;
+ }
+
+ /* find the closest seek point > target_sample, if it exists */
+ for(i = 0; i < (int)seek_table->num_points; i++) {
+ if(
+ seek_table->points[i].sample_number != FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER &&
+ seek_table->points[i].frame_samples > 0 && /* defense against bad seekpoints */
+ (total_samples <= 0 || seek_table->points[i].sample_number < total_samples) && /* defense against bad seekpoints */
+ seek_table->points[i].sample_number > target_sample
+ )
+ break;
+ }
+ if(i < (int)seek_table->num_points) { /* i.e. we found a suitable seek point... */
+ new_upper_bound = first_frame_offset + seek_table->points[i].stream_offset;
+ new_upper_bound_sample = seek_table->points[i].sample_number;
+ }
+ /* final protection against unsorted seek tables; keep original values if bogus */
+ if(new_upper_bound >= new_lower_bound) {
+ lower_bound = new_lower_bound;
+ upper_bound = new_upper_bound;
+ lower_bound_sample = new_lower_bound_sample;
+ upper_bound_sample = new_upper_bound_sample;
+ }
+ }
+
+ /* there are 2 insidious ways that the following equality occurs, which
+ * we need to fix:
+ * 1) total_samples is 0 (unknown) and target_sample is 0
+ * 2) total_samples is 0 (unknown) and target_sample happens to be
+ * exactly equal to the last seek point in the seek table; this
+ * means there is no seek point above it, and upper_bound_samples
+ * remains equal to the estimate (of target_samples) we made above
+ * in either case it does not hurt to move upper_bound_sample up by 1
+ */
+ if(upper_bound_sample == lower_bound_sample)
+ upper_bound_sample++;
+
+ decoder->private_->target_sample = target_sample;
+ while(1) {
+ /* check if the bounds are still ok */
+ if (lower_bound_sample >= upper_bound_sample || lower_bound > upper_bound) {
+ decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR;
+ return false;
+ }
+ pos = (FLAC__int64)lower_bound + (FLAC__int64)((double)(target_sample - lower_bound_sample) / (double)(upper_bound_sample - lower_bound_sample) * (double)(upper_bound - lower_bound)) - approx_bytes_per_frame;
+ if(pos >= (FLAC__int64)upper_bound)
+ pos = (FLAC__int64)upper_bound - 1;
+ if(pos < (FLAC__int64)lower_bound)
+ pos = (FLAC__int64)lower_bound;
+ if(decoder->private_->seek_callback(decoder, (FLAC__uint64)pos, decoder->private_->client_data) != FLAC__STREAM_DECODER_SEEK_STATUS_OK) {
+ decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR;
+ return false;
+ }
+ if(!FLAC__stream_decoder_flush(decoder)) {
+ /* above call sets the state for us */
+ return false;
+ }
+ /* Now we need to get a frame. First we need to reset our
+ * unparseable_frame_count; if we get too many unparseable
+ * frames in a row, the read callback will return
+ * FLAC__STREAM_DECODER_READ_STATUS_ABORT, causing
+ * FLAC__stream_decoder_process_single() to return false.
+ */
+ decoder->private_->unparseable_frame_count = 0;
+ if(!FLAC__stream_decoder_process_single(decoder) ||
+ decoder->protected_->state == FLAC__STREAM_DECODER_ABORTED) {
+ decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR;
+ return false;
+ }
+ /* our write callback will change the state when it gets to the target frame */
+ /* actually, we could have got_a_frame if our decoder is at FLAC__STREAM_DECODER_END_OF_STREAM so we need to check for that also */
+ if(!decoder->private_->is_seeking)
+ break;
+
+ this_frame_sample = decoder->private_->last_frame.header.number.sample_number;
+
+ if (0 == decoder->private_->samples_decoded || (this_frame_sample + decoder->private_->last_frame.header.blocksize >= upper_bound_sample && !first_seek)) {
+ if (pos == (FLAC__int64)lower_bound) {
+ /* can't move back any more than the first frame, something is fatally wrong */
+ decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR;
+ return false;
+ }
+ /* our last move backwards wasn't big enough, try again */
+ approx_bytes_per_frame = approx_bytes_per_frame? approx_bytes_per_frame * 2 : 16;
+ continue;
+ }
+ /* allow one seek over upper bound, so we can get a correct upper_bound_sample for streams with unknown total_samples */
+ first_seek = false;
+
+ /* make sure we are not seeking in corrupted stream */
+ if (this_frame_sample < lower_bound_sample) {
+ decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR;
+ return false;
+ }
+
+ /* we need to narrow the search */
+ if(target_sample < this_frame_sample) {
+ upper_bound_sample = this_frame_sample + decoder->private_->last_frame.header.blocksize;
+/*@@@@@@ what will decode position be if at end of stream? */
+ if(!FLAC__stream_decoder_get_decode_position(decoder, &upper_bound)) {
+ decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR;
+ return false;
+ }
+ approx_bytes_per_frame = (uint32_t)(2 * (upper_bound - pos) / 3 + 16);
+ }
+ else { /* target_sample >= this_frame_sample + this frame's blocksize */
+ lower_bound_sample = this_frame_sample + decoder->private_->last_frame.header.blocksize;
+ if(!FLAC__stream_decoder_get_decode_position(decoder, &lower_bound)) {
+ decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR;
+ return false;
+ }
+ approx_bytes_per_frame = (uint32_t)(2 * (lower_bound - pos) / 3 + 16);
+ }
+ }
+
+ return true;
+}
+
+FLAC__StreamDecoderReadStatus file_read_callback_(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data)
+{
+ (void)client_data;
+
+ if(*bytes > 0) {
+ *bytes = fread(buffer, sizeof(FLAC__byte), *bytes, decoder->private_->file);
+ if(ferror(decoder->private_->file))
+ return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
+ else if(*bytes == 0)
+ return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
+ else
+ return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
+ }
+ else
+ return FLAC__STREAM_DECODER_READ_STATUS_ABORT; /* abort to avoid a deadlock */
+}
+
+FLAC__StreamDecoderSeekStatus file_seek_callback_(const FLAC__StreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data)
+{
+ (void)client_data;
+
+ if(decoder->private_->file == stdin)
+ return FLAC__STREAM_DECODER_SEEK_STATUS_UNSUPPORTED;
+ else if(fseeko(decoder->private_->file, (FLAC__off_t)absolute_byte_offset, SEEK_SET) < 0)
+ return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR;
+ else
+ return FLAC__STREAM_DECODER_SEEK_STATUS_OK;
+}
+
+FLAC__StreamDecoderTellStatus file_tell_callback_(const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data)
+{
+ FLAC__off_t pos;
+ (void)client_data;
+
+ if(decoder->private_->file == stdin)
+ return FLAC__STREAM_DECODER_TELL_STATUS_UNSUPPORTED;
+ else if((pos = ftello(decoder->private_->file)) < 0)
+ return FLAC__STREAM_DECODER_TELL_STATUS_ERROR;
+ else {
+ *absolute_byte_offset = (FLAC__uint64)pos;
+ return FLAC__STREAM_DECODER_TELL_STATUS_OK;
+ }
+}
+
+FLAC__StreamDecoderLengthStatus file_length_callback_(const FLAC__StreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data)
+{
+ struct flac_stat_s filestats;
+ (void)client_data;
+
+ if(decoder->private_->file == stdin)
+ return FLAC__STREAM_DECODER_LENGTH_STATUS_UNSUPPORTED;
+ else if(flac_fstat(fileno(decoder->private_->file), &filestats) != 0)
+ return FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR;
+ else {
+ *stream_length = (FLAC__uint64)filestats.st_size;
+ return FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
+ }
+}
+
+FLAC__bool file_eof_callback_(const FLAC__StreamDecoder *decoder, void *client_data)
+{
+ (void)client_data;
+
+ return feof(decoder->private_->file)? true : false;
+}
+
+void *get_client_data_from_decoder(FLAC__StreamDecoder *decoder)
+{
+ return decoder->private_->client_data;
+}
--- /dev/null
+++ b/src/libflac/window.c
@@ -1,0 +1,272 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2006-2009 Josh Coalson
+ * Copyright (C) 2011-2016 Xiph.Org Foundation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <math.h>
+#include "share/compat.h"
+#include "FLAC/format.h"
+#include "private/window.h"
+
+void FLAC__window_bartlett(FLAC__real *window, const FLAC__int32 L)
+{
+ const FLAC__int32 N = L - 1;
+ FLAC__int32 n;
+
+ if (L & 1) {
+ for (n = 0; n <= N/2; n++)
+ window[n] = 2.0f * n / (float)N;
+ for (; n <= N; n++)
+ window[n] = 2.0f - 2.0f * n / (float)N;
+ }
+ else {
+ for (n = 0; n <= L/2-1; n++)
+ window[n] = 2.0f * n / (float)N;
+ for (; n <= N; n++)
+ window[n] = 2.0f - 2.0f * n / (float)N;
+ }
+}
+
+void FLAC__window_bartlett_hann(FLAC__real *window, const FLAC__int32 L)
+{
+ const FLAC__int32 N = L - 1;
+ FLAC__int32 n;
+
+ for (n = 0; n < L; n++)
+ window[n] = (FLAC__real)(0.62f - 0.48f * fabs((float)n/(float)N-0.5f) - 0.38f * cos(2.0f * M_PI * ((float)n/(float)N)));
+}
+
+void FLAC__window_blackman(FLAC__real *window, const FLAC__int32 L)
+{
+ const FLAC__int32 N = L - 1;
+ FLAC__int32 n;
+
+ for (n = 0; n < L; n++)
+ window[n] = (FLAC__real)(0.42f - 0.5f * cos(2.0f * M_PI * n / N) + 0.08f * cos(4.0f * M_PI * n / N));
+}
+
+/* 4-term -92dB side-lobe */
+void FLAC__window_blackman_harris_4term_92db_sidelobe(FLAC__real *window, const FLAC__int32 L)
+{
+ const FLAC__int32 N = L - 1;
+ FLAC__int32 n;
+
+ for (n = 0; n <= N; n++)
+ window[n] = (FLAC__real)(0.35875f - 0.48829f * cos(2.0f * M_PI * n / N) + 0.14128f * cos(4.0f * M_PI * n / N) - 0.01168f * cos(6.0f * M_PI * n / N));
+}
+
+void FLAC__window_connes(FLAC__real *window, const FLAC__int32 L)
+{
+ const FLAC__int32 N = L - 1;
+ const double N2 = (double)N / 2.;
+ FLAC__int32 n;
+
+ for (n = 0; n <= N; n++) {
+ double k = ((double)n - N2) / N2;
+ k = 1.0f - k * k;
+ window[n] = (FLAC__real)(k * k);
+ }
+}
+
+void FLAC__window_flattop(FLAC__real *window, const FLAC__int32 L)
+{
+ const FLAC__int32 N = L - 1;
+ FLAC__int32 n;
+
+ for (n = 0; n < L; n++)
+ window[n] = (FLAC__real)(0.21557895f - 0.41663158f * cos(2.0f * M_PI * n / N) + 0.277263158f * cos(4.0f * M_PI * n / N) - 0.083578947f * cos(6.0f * M_PI * n / N) + 0.006947368f * cos(8.0f * M_PI * n / N));
+}
+
+void FLAC__window_gauss(FLAC__real *window, const FLAC__int32 L, const FLAC__real stddev)
+{
+ const FLAC__int32 N = L - 1;
+ const double N2 = (double)N / 2.;
+ FLAC__int32 n;
+
+ for (n = 0; n <= N; n++) {
+ const double k = ((double)n - N2) / (stddev * N2);
+ window[n] = (FLAC__real)exp(-0.5f * k * k);
+ }
+}
+
+void FLAC__window_hamming(FLAC__real *window, const FLAC__int32 L)
+{
+ const FLAC__int32 N = L - 1;
+ FLAC__int32 n;
+
+ for (n = 0; n < L; n++)
+ window[n] = (FLAC__real)(0.54f - 0.46f * cos(2.0f * M_PI * n / N));
+}
+
+void FLAC__window_hann(FLAC__real *window, const FLAC__int32 L)
+{
+ const FLAC__int32 N = L - 1;
+ FLAC__int32 n;
+
+ for (n = 0; n < L; n++)
+ window[n] = (FLAC__real)(0.5f - 0.5f * cos(2.0f * M_PI * n / N));
+}
+
+void FLAC__window_kaiser_bessel(FLAC__real *window, const FLAC__int32 L)
+{
+ const FLAC__int32 N = L - 1;
+ FLAC__int32 n;
+
+ for (n = 0; n < L; n++)
+ window[n] = (FLAC__real)(0.402f - 0.498f * cos(2.0f * M_PI * n / N) + 0.098f * cos(4.0f * M_PI * n / N) - 0.001f * cos(6.0f * M_PI * n / N));
+}
+
+void FLAC__window_nuttall(FLAC__real *window, const FLAC__int32 L)
+{
+ const FLAC__int32 N = L - 1;
+ FLAC__int32 n;
+
+ for (n = 0; n < L; n++)
+ window[n] = (FLAC__real)(0.3635819f - 0.4891775f*cos(2.0f*M_PI*n/N) + 0.1365995f*cos(4.0f*M_PI*n/N) - 0.0106411f*cos(6.0f*M_PI*n/N));
+}
+
+void FLAC__window_rectangle(FLAC__real *window, const FLAC__int32 L)
+{
+ FLAC__int32 n;
+
+ for (n = 0; n < L; n++)
+ window[n] = 1.0f;
+}
+
+void FLAC__window_triangle(FLAC__real *window, const FLAC__int32 L)
+{
+ FLAC__int32 n;
+
+ if (L & 1) {
+ for (n = 1; n <= (L+1)/2; n++)
+ window[n-1] = 2.0f * n / ((float)L + 1.0f);
+ for (; n <= L; n++)
+ window[n-1] = (float)(2 * (L - n + 1)) / ((float)L + 1.0f);
+ }
+ else {
+ for (n = 1; n <= L/2; n++)
+ window[n-1] = 2.0f * n / ((float)L + 1.0f);
+ for (; n <= L; n++)
+ window[n-1] = (float)(2 * (L - n + 1)) / ((float)L + 1.0f);
+ }
+}
+
+void FLAC__window_tukey(FLAC__real *window, const FLAC__int32 L, const FLAC__real p)
+{
+ if (p <= 0.0)
+ FLAC__window_rectangle(window, L);
+ else if (p >= 1.0)
+ FLAC__window_hann(window, L);
+ else {
+ const FLAC__int32 Np = (FLAC__int32)(p / 2.0f * L) - 1;
+ FLAC__int32 n;
+ /* start with rectangle... */
+ FLAC__window_rectangle(window, L);
+ /* ...replace ends with hann */
+ if (Np > 0) {
+ for (n = 0; n <= Np; n++) {
+ window[n] = (FLAC__real)(0.5f - 0.5f * cos(M_PI * n / Np));
+ window[L-Np-1+n] = (FLAC__real)(0.5f - 0.5f * cos(M_PI * (n+Np) / Np));
+ }
+ }
+ }
+}
+
+void FLAC__window_partial_tukey(FLAC__real *window, const FLAC__int32 L, const FLAC__real p, const FLAC__real start, const FLAC__real end)
+{
+ const FLAC__int32 start_n = (FLAC__int32)(start * L);
+ const FLAC__int32 end_n = (FLAC__int32)(end * L);
+ const FLAC__int32 N = end_n - start_n;
+ FLAC__int32 Np, n, i;
+
+ if (p <= 0.0f)
+ FLAC__window_partial_tukey(window, L, 0.05f, start, end);
+ else if (p >= 1.0f)
+ FLAC__window_partial_tukey(window, L, 0.95f, start, end);
+ else {
+
+ Np = (FLAC__int32)(p / 2.0f * N);
+
+ for (n = 0; n < start_n && n < L; n++)
+ window[n] = 0.0f;
+ for (i = 1; n < (start_n+Np) && n < L; n++, i++)
+ window[n] = (FLAC__real)(0.5f - 0.5f * cos(M_PI * i / Np));
+ for (; n < (end_n-Np) && n < L; n++)
+ window[n] = 1.0f;
+ for (i = Np; n < end_n && n < L; n++, i--)
+ window[n] = (FLAC__real)(0.5f - 0.5f * cos(M_PI * i / Np));
+ for (; n < L; n++)
+ window[n] = 0.0f;
+ }
+}
+
+void FLAC__window_punchout_tukey(FLAC__real *window, const FLAC__int32 L, const FLAC__real p, const FLAC__real start, const FLAC__real end)
+{
+ const FLAC__int32 start_n = (FLAC__int32)(start * L);
+ const FLAC__int32 end_n = (FLAC__int32)(end * L);
+ FLAC__int32 Ns, Ne, n, i;
+
+ if (p <= 0.0f)
+ FLAC__window_punchout_tukey(window, L, 0.05f, start, end);
+ else if (p >= 1.0f)
+ FLAC__window_punchout_tukey(window, L, 0.95f, start, end);
+ else {
+
+ Ns = (FLAC__int32)(p / 2.0f * start_n);
+ Ne = (FLAC__int32)(p / 2.0f * (L - end_n));
+
+ for (n = 0, i = 1; n < Ns && n < L; n++, i++)
+ window[n] = (FLAC__real)(0.5f - 0.5f * cos(M_PI * i / Ns));
+ for (; n < start_n-Ns && n < L; n++)
+ window[n] = 1.0f;
+ for (i = Ns; n < start_n && n < L; n++, i--)
+ window[n] = (FLAC__real)(0.5f - 0.5f * cos(M_PI * i / Ns));
+ for (; n < end_n && n < L; n++)
+ window[n] = 0.0f;
+ for (i = 1; n < end_n+Ne && n < L; n++, i++)
+ window[n] = (FLAC__real)(0.5f - 0.5f * cos(M_PI * i / Ne));
+ for (; n < L - (Ne) && n < L; n++)
+ window[n] = 1.0f;
+ for (i = Ne; n < L; n++, i--)
+ window[n] = (FLAC__real)(0.5f - 0.5f * cos(M_PI * i / Ne));
+ }
+}
+
+void FLAC__window_welch(FLAC__real *window, const FLAC__int32 L)
+{
+ const FLAC__int32 N = L - 1;
+ const double N2 = (double)N / 2.;
+ FLAC__int32 n;
+
+ for (n = 0; n <= N; n++) {
+ const double k = ((double)n - N2) / N2;
+ window[n] = (FLAC__real)(1.0f - k * k);
+ }
+}
--- /dev/null
+++ b/src/libflac/windows_unicode_filenames.c
@@ -1,0 +1,194 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2013-2016 Xiph.Org Foundation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifdef _WIN32
+
+#define WIN32_MEAN_AND_LEAN
+#include <io.h>
+#include <windows.h>
+#include "share/windows_unicode_filenames.h"
+
+/* convert UTF-8 back to WCHAR. Caller is responsible for freeing memory */
+static wchar_t *wchar_from_utf8(const char *str)
+{
+ wchar_t *widestr;
+ int len;
+
+ if (!str)
+ return NULL;
+ if ((len = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0)) == 0)
+ return NULL;
+ if ((widestr = (wchar_t *)malloc(len*sizeof(wchar_t))) == NULL)
+ return NULL;
+ if (MultiByteToWideChar(CP_UTF8, 0, str, -1, widestr, len) == 0) {
+ free(widestr);
+ widestr = NULL;
+ }
+
+ return widestr;
+}
+
+
+static FLAC__bool utf8_filenames = false;
+
+
+void flac_internal_set_utf8_filenames(FLAC__bool flag)
+{
+ utf8_filenames = flag ? true : false;
+}
+
+FLAC__bool flac_internal_get_utf8_filenames(void)
+{
+ return utf8_filenames;
+}
+
+/* file functions */
+
+FILE* flac_internal_fopen_utf8(const char *filename, const char *mode)
+{
+ if (!utf8_filenames) {
+ return fopen(filename, mode);
+ } else {
+ wchar_t *wname = NULL;
+ wchar_t *wmode = NULL;
+ FILE *f = NULL;
+
+ do {
+ wname = wchar_from_utf8(filename);
+ if (!wname) break;
+ wmode = wchar_from_utf8(mode);
+ if (!wmode) break;
+ f = _wfopen(wname, wmode);
+ } while(0);
+
+ free(wname);
+ free(wmode);
+
+ return f;
+ }
+}
+
+int flac_internal_stat64_utf8(const char *path, struct __stat64 *buffer)
+{
+ if (!utf8_filenames) {
+ return _stat64(path, buffer);
+ } else {
+ wchar_t *wpath;
+ int ret;
+
+ wpath = wchar_from_utf8(path);
+ if (!wpath) return -1;
+ ret = _wstat64(wpath, buffer);
+ free(wpath);
+
+ return ret;
+ }
+}
+
+int flac_internal_chmod_utf8(const char *filename, int pmode)
+{
+ if (!utf8_filenames) {
+ return _chmod(filename, pmode);
+ } else {
+ wchar_t *wname;
+ int ret;
+
+ wname = wchar_from_utf8(filename);
+ if (!wname) return -1;
+ ret = _wchmod(wname, pmode);
+ free(wname);
+
+ return ret;
+ }
+}
+
+int flac_internal_utime_utf8(const char *filename, struct utimbuf *times)
+{
+ if (!utf8_filenames) {
+ return utime(filename, times);
+ } else {
+ wchar_t *wname;
+ struct __utimbuf64 ut;
+ int ret;
+
+ wname = wchar_from_utf8(filename);
+ if (!wname) return -1;
+ ut.actime = times->actime;
+ ut.modtime = times->modtime;
+ ret = _wutime64(wname, &ut);
+ free(wname);
+
+ return ret;
+ }
+}
+
+int flac_internal_unlink_utf8(const char *filename)
+{
+ if (!utf8_filenames) {
+ return _unlink(filename);
+ } else {
+ wchar_t *wname;
+ int ret;
+
+ wname = wchar_from_utf8(filename);
+ if (!wname) return -1;
+ ret = _wunlink(wname);
+ free(wname);
+
+ return ret;
+ }
+}
+
+int flac_internal_rename_utf8(const char *oldname, const char *newname)
+{
+ if (!utf8_filenames) {
+ return rename(oldname, newname);
+ } else {
+ wchar_t *wold = NULL;
+ wchar_t *wnew = NULL;
+ int ret = -1;
+
+ do {
+ wold = wchar_from_utf8(oldname);
+ if (!wold) break;
+ wnew = wchar_from_utf8(newname);
+ if (!wnew) break;
+ ret = _wrename(wold, wnew);
+ } while(0);
+
+ free(wold);
+ free(wnew);
+
+ return ret;
+ }
+}
+
+#endif
--- a/src/mixer/ft2_center_mix.c
+++ b/src/mixer/ft2_center_mix.c
@@ -1,6 +1,7 @@
#include <stdint.h>
#include <stdbool.h>
#include "ft2_mix_macros.h"
+#include "../ft2_cpu.h"
/* Check out ft2_mix.c for comments on how this works.
** These are duplicates for center-mixing (slightly faster when it can be used).
@@ -13,10 +14,10 @@
void centerMix8bNoLoop(voice_t *v, uint32_t bufferPos, uint32_t numSamples)
{
const int8_t *base, *smpPtr;
- double dSample, *dMixBufferL, *dMixBufferR;
- int32_t pos;
+ float fSample, *fMixBufferL, *fMixBufferR;
+ int32_t position;
uint32_t i, samplesToMix, samplesLeft;
- uint64_t posFrac;
+ uintCPUWord_t positionFrac;
GET_VOL_MONO
GET_MIXER_VARS
@@ -55,10 +56,10 @@
void centerMix8bLoop(voice_t *v, uint32_t bufferPos, uint32_t numSamples)
{
const int8_t *base, *smpPtr;
- double dSample, *dMixBufferL, *dMixBufferR;
- int32_t pos;
+ float fSample, *fMixBufferL, *fMixBufferR;
+ int32_t position;
uint32_t i, samplesToMix, samplesLeft;
- uint64_t posFrac;
+ uintCPUWord_t positionFrac;
GET_VOL_MONO
GET_MIXER_VARS
@@ -97,10 +98,10 @@
void centerMix8bBidiLoop(voice_t *v, uint32_t bufferPos, uint32_t numSamples)
{
const int8_t *base, *revBase, *smpPtr;
- double dSample, *dMixBufferL, *dMixBufferR;
- int32_t pos;
+ float fSample, *fMixBufferL, *fMixBufferR;
+ int32_t position;
uint32_t i, samplesToMix, samplesLeft;
- uint64_t posFrac, tmpDelta;
+ uintCPUWord_t positionFrac, tmpDelta;
GET_VOL_MONO
GET_MIXER_VARS
@@ -141,10 +142,10 @@
void centerMix8bNoLoopSIntrp(voice_t *v, uint32_t bufferPos, uint32_t numSamples)
{
const int8_t *base, *smpPtr;
- double dSample, *dMixBufferL, *dMixBufferR;
- int32_t pos;
+ float fSample, *fMixBufferL, *fMixBufferR;
+ int32_t position;
uint32_t i, samplesToMix, samplesLeft;
- uint64_t posFrac;
+ uintCPUWord_t positionFrac;
GET_VOL_MONO
GET_MIXER_VARS
@@ -184,10 +185,10 @@
{
const int8_t *base, *smpPtr;
int8_t *smpTapPtr;
- double dSample, *dMixBufferL, *dMixBufferR;
- int32_t pos;
+ float fSample, *fMixBufferL, *fMixBufferR;
+ int32_t position;
uint32_t i, samplesToMix, samplesLeft;
- uint64_t posFrac;
+ uintCPUWord_t positionFrac;
GET_VOL_MONO
GET_MIXER_VARS
@@ -251,10 +252,10 @@
{
const int8_t *base, *revBase, *smpPtr;
int8_t *smpTapPtr;
- double dSample, *dMixBufferL, *dMixBufferR;
- int32_t pos;
+ float fSample, *fMixBufferL, *fMixBufferR;
+ int32_t position;
uint32_t i, samplesToMix, samplesLeft;
- uint64_t posFrac, tmpDelta;
+ uintCPUWord_t positionFrac, tmpDelta;
GET_VOL_MONO
GET_MIXER_VARS
@@ -320,10 +321,10 @@
void centerMix8bNoLoopLIntrp(voice_t *v, uint32_t bufferPos, uint32_t numSamples)
{
const int8_t *base, *smpPtr;
- double dSample, *dMixBufferL, *dMixBufferR;
- int32_t pos;
+ float fSample, *fMixBufferL, *fMixBufferR;
+ int32_t position;
uint32_t i, samplesToMix, samplesLeft;
- uint64_t posFrac;
+ uintCPUWord_t positionFrac;
GET_VOL_MONO
GET_MIXER_VARS
@@ -362,10 +363,10 @@
void centerMix8bLoopLIntrp(voice_t *v, uint32_t bufferPos, uint32_t numSamples)
{
const int8_t *base, *smpPtr;
- double dSample, *dMixBufferL, *dMixBufferR;
- int32_t pos;
+ float fSample, *fMixBufferL, *fMixBufferR;
+ int32_t position;
uint32_t i, samplesToMix, samplesLeft;
- uint64_t posFrac;
+ uintCPUWord_t positionFrac;
GET_VOL_MONO
GET_MIXER_VARS
@@ -404,10 +405,10 @@
void centerMix8bBidiLoopLIntrp(voice_t *v, uint32_t bufferPos, uint32_t numSamples)
{
const int8_t *base, *revBase, *smpPtr;
- double dSample, *dMixBufferL, *dMixBufferR;
- int32_t pos;
+ float fSample, *fMixBufferL, *fMixBufferR;
+ int32_t position;
uint32_t i, samplesToMix, samplesLeft;
- uint64_t posFrac, tmpDelta;
+ uintCPUWord_t positionFrac, tmpDelta;
GET_VOL_MONO
GET_MIXER_VARS
@@ -448,11 +449,11 @@
void centerMix8bRampNoLoop(voice_t *v, uint32_t bufferPos, uint32_t numSamples)
{
const int8_t *base, *smpPtr;
- double dSample, *dMixBufferL, *dMixBufferR;
- int32_t pos;
- double dVolLDelta, dVolL;
+ float fSample, *fMixBufferL, *fMixBufferR;
+ int32_t position;
+ float fVolumeLDelta, fVolumeL;
uint32_t i, samplesToMix, samplesLeft;
- uint64_t posFrac;
+ uintCPUWord_t positionFrac;
GET_VOL_MONO_RAMP
GET_MIXER_VARS_MONO_RAMP
@@ -498,11 +499,11 @@
void centerMix8bRampLoop(voice_t *v, uint32_t bufferPos, uint32_t numSamples)
{
const int8_t *base, *smpPtr;
- double dSample, *dMixBufferL, *dMixBufferR;
- int32_t pos;
- double dVolLDelta, dVolL;
+ float fSample, *fMixBufferL, *fMixBufferR;
+ int32_t position;
+ float fVolumeLDelta, fVolumeL;
uint32_t i, samplesToMix, samplesLeft;
- uint64_t posFrac;
+ uintCPUWord_t positionFrac;
GET_VOL_MONO_RAMP
GET_MIXER_VARS_MONO_RAMP
@@ -548,11 +549,11 @@
void centerMix8bRampBidiLoop(voice_t *v, uint32_t bufferPos, uint32_t numSamples)
{
const int8_t *base, *revBase, *smpPtr;
- double dSample, *dMixBufferL, *dMixBufferR;
- int32_t pos;
- double dVolLDelta, dVolL;
+ float fSample, *fMixBufferL, *fMixBufferR;
+ int32_t position;
+ float fVolumeLDelta, fVolumeL;
uint32_t i, samplesToMix, samplesLeft;
- uint64_t posFrac, tmpDelta;
+ uintCPUWord_t positionFrac, tmpDelta;
GET_VOL_MONO_RAMP
GET_MIXER_VARS_MONO_RAMP
@@ -600,11 +601,11 @@
void centerMix8bRampNoLoopSIntrp(voice_t *v, uint32_t bufferPos, uint32_t numSamples)
{
const int8_t *base, *smpPtr;
- double dSample, *dMixBufferL, *dMixBufferR;
- int32_t pos;
- double dVolLDelta, dVolL;
+ float fSample, *fMixBufferL, *fMixBufferR;
+ int32_t position;
+ float fVolumeLDelta, fVolumeL;
uint32_t i, samplesToMix, samplesLeft;
- uint64_t posFrac;
+ uintCPUWord_t positionFrac;
GET_VOL_MONO_RAMP
GET_MIXER_VARS_MONO_RAMP
@@ -651,11 +652,11 @@
{
const int8_t *base, *smpPtr;
int8_t *smpTapPtr;
- double dSample, *dMixBufferL, *dMixBufferR;
- int32_t pos;
- double dVolLDelta, dVolL;
+ float fSample, *fMixBufferL, *fMixBufferR;
+ int32_t position;
+ float fVolumeLDelta, fVolumeL;
uint32_t i, samplesToMix, samplesLeft;
- uint64_t posFrac;
+ uintCPUWord_t positionFrac;
GET_VOL_MONO_RAMP
GET_MIXER_VARS_MONO_RAMP
@@ -731,11 +732,11 @@
{
const int8_t *base, *revBase, *smpPtr;
int8_t *smpTapPtr;
- double dSample, *dMixBufferL, *dMixBufferR;
- int32_t pos;
- double dVolLDelta, dVolL;
+ float fSample, *fMixBufferL, *fMixBufferR;
+ int32_t position;
+ float fVolumeLDelta, fVolumeL;
uint32_t i, samplesToMix, samplesLeft;
- uint64_t posFrac, tmpDelta;
+ uintCPUWord_t positionFrac, tmpDelta;
GET_VOL_MONO_RAMP
GET_MIXER_VARS_MONO_RAMP
@@ -812,11 +813,11 @@
void centerMix8bRampNoLoopLIntrp(voice_t *v, uint32_t bufferPos, uint32_t numSamples)
{
const int8_t *base, *smpPtr;
- double dSample, *dMixBufferL, *dMixBufferR;
- int32_t pos;
- double dVolLDelta, dVolL;
+ float fSample, *fMixBufferL, *fMixBufferR;
+ int32_t position;
+ float fVolumeLDelta, fVolumeL;
uint32_t i, samplesToMix, samplesLeft;
- uint64_t posFrac;
+ uintCPUWord_t positionFrac;
GET_VOL_MONO_RAMP
GET_MIXER_VARS_MONO_RAMP
@@ -862,11 +863,11 @@
void centerMix8bRampLoopLIntrp(voice_t *v, uint32_t bufferPos, uint32_t numSamples)
{
const int8_t *base, *smpPtr;
- double dSample, *dMixBufferL, *dMixBufferR;
- int32_t pos;
- double dVolLDelta, dVolL;
+ float fSample, *fMixBufferL, *fMixBufferR;
+ int32_t position;
+ float fVolumeLDelta, fVolumeL;
uint32_t i, samplesToMix, samplesLeft;
- uint64_t posFrac;
+ uintCPUWord_t positionFrac;
GET_VOL_MONO_RAMP
GET_MIXER_VARS_MONO_RAMP
@@ -912,11 +913,11 @@
void centerMix8bRampBidiLoopLIntrp(voice_t *v, uint32_t bufferPos, uint32_t numSamples)
{
const int8_t *base, *revBase, *smpPtr;
- double dSample, *dMixBufferL, *dMixBufferR;
- int32_t pos;
- double dVolLDelta, dVolL;
+ float fSample, *fMixBufferL, *fMixBufferR;
+ int32_t position;
+ float fVolumeLDelta, fVolumeL;
uint32_t i, samplesToMix, samplesLeft;
- uint64_t posFrac, tmpDelta;
+ uintCPUWord_t positionFrac, tmpDelta;
GET_VOL_MONO_RAMP
GET_MIXER_VARS_MONO_RAMP
@@ -968,10 +969,10 @@
void centerMix16bNoLoop(voice_t *v, uint32_t bufferPos, uint32_t numSamples)
{
const int16_t *base, *smpPtr;
- double dSample, *dMixBufferL, *dMixBufferR;
- int32_t pos;
+ float fSample, *fMixBufferL, *fMixBufferR;
+ int32_t position;
uint32_t i, samplesToMix, samplesLeft;
- uint64_t posFrac;
+ uintCPUWord_t positionFrac;
GET_VOL_MONO
GET_MIXER_VARS
@@ -1010,10 +1011,10 @@
void centerMix16bLoop(voice_t *v, uint32_t bufferPos, uint32_t numSamples)
{
const int16_t *base, *smpPtr;
- double dSample, *dMixBufferL, *dMixBufferR;
- int32_t pos;
+ float fSample, *fMixBufferL, *fMixBufferR;
+ int32_t position;
uint32_t i, samplesToMix, samplesLeft;
- uint64_t posFrac;
+ uintCPUWord_t positionFrac;
GET_VOL_MONO
GET_MIXER_VARS
@@ -1052,10 +1053,10 @@
void centerMix16bBidiLoop(voice_t *v, uint32_t bufferPos, uint32_t numSamples)
{
const int16_t *base, *revBase, *smpPtr;
- double dSample, *dMixBufferL, *dMixBufferR;
- int32_t pos;
+ float fSample, *fMixBufferL, *fMixBufferR;
+ int32_t position;
uint32_t i, samplesToMix, samplesLeft;
- uint64_t posFrac, tmpDelta;
+ uintCPUWord_t positionFrac, tmpDelta;
GET_VOL_MONO
GET_MIXER_VARS
@@ -1096,10 +1097,10 @@
void centerMix16bNoLoopSIntrp(voice_t *v, uint32_t bufferPos, uint32_t numSamples)
{
const int16_t *base, *smpPtr;
- double dSample, *dMixBufferL, *dMixBufferR;
- int32_t pos;
+ float fSample, *fMixBufferL, *fMixBufferR;
+ int32_t position;
uint32_t i, samplesToMix, samplesLeft;
- uint64_t posFrac;
+ uintCPUWord_t positionFrac;
GET_VOL_MONO
GET_MIXER_VARS
@@ -1139,10 +1140,10 @@
{
const int16_t *base, *smpPtr;
int16_t *smpTapPtr;
- double dSample, *dMixBufferL, *dMixBufferR;
- int32_t pos;
+ float fSample, *fMixBufferL, *fMixBufferR;
+ int32_t position;
uint32_t i, samplesToMix, samplesLeft;
- uint64_t posFrac;
+ uintCPUWord_t positionFrac;
GET_VOL_MONO
GET_MIXER_VARS
@@ -1206,10 +1207,10 @@
{
const int16_t *base, *revBase, *smpPtr;
int16_t *smpTapPtr;
- double dSample, *dMixBufferL, *dMixBufferR;
- int32_t pos;
+ float fSample, *fMixBufferL, *fMixBufferR;
+ int32_t position;
uint32_t i, samplesToMix, samplesLeft;
- uint64_t posFrac, tmpDelta;
+ uintCPUWord_t positionFrac, tmpDelta;
GET_VOL_MONO
GET_MIXER_VARS
@@ -1274,10 +1275,10 @@
void centerMix16bNoLoopLIntrp(voice_t *v, uint32_t bufferPos, uint32_t numSamples)
{
const int16_t *base, *smpPtr;
- double dSample, *dMixBufferL, *dMixBufferR;
- int32_t pos;
+ float fSample, *fMixBufferL, *fMixBufferR;
+ int32_t position;
uint32_t i, samplesToMix, samplesLeft;
- uint64_t posFrac;
+ uintCPUWord_t positionFrac;
GET_VOL_MONO
GET_MIXER_VARS
@@ -1316,10 +1317,10 @@
void centerMix16bLoopLIntrp(voice_t *v, uint32_t bufferPos, uint32_t numSamples)
{
const int16_t *base, *smpPtr;
- double dSample, *dMixBufferL, *dMixBufferR;
- int32_t pos;
+ float fSample, *fMixBufferL, *fMixBufferR;
+ int32_t position;
uint32_t i, samplesToMix, samplesLeft;
- uint64_t posFrac;
+ uintCPUWord_t positionFrac;
GET_VOL_MONO
GET_MIXER_VARS
@@ -1358,10 +1359,10 @@
void centerMix16bBidiLoopLIntrp(voice_t *v, uint32_t bufferPos, uint32_t numSamples)
{
const int16_t *base, *revBase, *smpPtr;
- double dSample, *dMixBufferL, *dMixBufferR;
- int32_t pos;
+ float fSample, *fMixBufferL, *fMixBufferR;
+ int32_t position;
uint32_t i, samplesToMix, samplesLeft;
- uint64_t posFrac, tmpDelta;
+ uintCPUWord_t positionFrac, tmpDelta;
GET_VOL_MONO
GET_MIXER_VARS
@@ -1403,11 +1404,11 @@
void centerMix16bRampNoLoop(voice_t *v, uint32_t bufferPos, uint32_t numSamples)
{
const int16_t *base, *smpPtr;
- double dSample, *dMixBufferL, *dMixBufferR;
- int32_t pos;
- double dVolLDelta, dVolL;
+ float fSample, *fMixBufferL, *fMixBufferR;
+ int32_t position;
+ float fVolumeLDelta, fVolumeL;
uint32_t i, samplesToMix, samplesLeft;
- uint64_t posFrac;
+ uintCPUWord_t positionFrac;
GET_VOL_MONO_RAMP
GET_MIXER_VARS_MONO_RAMP
@@ -1453,11 +1454,11 @@
void centerMix16bRampLoop(voice_t *v, uint32_t bufferPos, uint32_t numSamples)
{
const int16_t *base, *smpPtr;
- double dSample, *dMixBufferL, *dMixBufferR;
- int32_t pos;
- double dVolLDelta, dVolL;
+ float fSample, *fMixBufferL, *fMixBufferR;
+ int32_t position;
+ float fVolumeLDelta, fVolumeL;
uint32_t i, samplesToMix, samplesLeft;
- uint64_t posFrac;
+ uintCPUWord_t positionFrac;
GET_VOL_MONO_RAMP
GET_MIXER_VARS_MONO_RAMP
@@ -1503,11 +1504,11 @@
void centerMix16bRampBidiLoop(voice_t *v, uint32_t bufferPos, uint32_t numSamples)
{
const int16_t *base, *revBase, *smpPtr;
- double dSample, *dMixBufferL, *dMixBufferR;
- int32_t pos;
- double dVolLDelta, dVolL;
+ float fSample, *fMixBufferL, *fMixBufferR;
+ int32_t position;
+ float fVolumeLDelta, fVolumeL;
uint32_t i, samplesToMix, samplesLeft;
- uint64_t posFrac, tmpDelta;
+ uintCPUWord_t positionFrac, tmpDelta;
GET_VOL_MONO_RAMP
GET_MIXER_VARS_MONO_RAMP
@@ -1555,11 +1556,11 @@
void centerMix16bRampNoLoopSIntrp(voice_t *v, uint32_t bufferPos, uint32_t numSamples)
{
const int16_t *base, *smpPtr;
- double dSample, *dMixBufferL, *dMixBufferR;
- int32_t pos;
- double dVolLDelta, dVolL;
+ float fSample, *fMixBufferL, *fMixBufferR;
+ int32_t position;
+ float fVolumeLDelta, fVolumeL;
uint32_t i, samplesToMix, samplesLeft;
- uint64_t posFrac;
+ uintCPUWord_t positionFrac;
GET_VOL_MONO_RAMP
GET_MIXER_VARS_MONO_RAMP
@@ -1606,11 +1607,11 @@
{
const int16_t *base, *smpPtr;
int16_t *smpTapPtr;
- double dSample, *dMixBufferL, *dMixBufferR;
- int32_t pos;
- double dVolLDelta, dVolL;
+ float fSample, *fMixBufferL, *fMixBufferR;
+ int32_t position;
+ float fVolumeLDelta, fVolumeL;
uint32_t i, samplesToMix, samplesLeft;
- uint64_t posFrac;
+ uintCPUWord_t positionFrac;
GET_VOL_MONO_RAMP
GET_MIXER_VARS_MONO_RAMP
@@ -1686,11 +1687,11 @@
{
const int16_t *base, *revBase, *smpPtr;
int16_t *smpTapPtr;
- double dSample, *dMixBufferL, *dMixBufferR;
- int32_t pos;
- double dVolLDelta, dVolL;
+ float fSample, *fMixBufferL, *fMixBufferR;
+ int32_t position;
+ float fVolumeLDelta, fVolumeL;
uint32_t i, samplesToMix, samplesLeft;
- uint64_t posFrac, tmpDelta;
+ uintCPUWord_t positionFrac, tmpDelta;
GET_VOL_MONO_RAMP
GET_MIXER_VARS_MONO_RAMP
@@ -1767,11 +1768,11 @@
void centerMix16bRampNoLoopLIntrp(voice_t *v, uint32_t bufferPos, uint32_t numSamples)
{
const int16_t *base, *smpPtr;
- double dSample, *dMixBufferL, *dMixBufferR;
- int32_t pos;
- double dVolLDelta, dVolL;
+ float fSample, *fMixBufferL, *fMixBufferR;
+ int32_t position;
+ float fVolumeLDelta, fVolumeL;
uint32_t i, samplesToMix, samplesLeft;
- uint64_t posFrac;
+ uintCPUWord_t positionFrac;
GET_VOL_MONO_RAMP
GET_MIXER_VARS_MONO_RAMP
@@ -1817,11 +1818,11 @@
void centerMix16bRampLoopLIntrp(voice_t *v, uint32_t bufferPos, uint32_t numSamples)
{
const int16_t *base, *smpPtr;
- double dSample, *dMixBufferL, *dMixBufferR;
- int32_t pos;
- double dVolLDelta, dVolL;
+ float fSample, *fMixBufferL, *fMixBufferR;
+ int32_t position;
+ float fVolumeLDelta, fVolumeL;
uint32_t i, samplesToMix, samplesLeft;
- uint64_t posFrac;
+ uintCPUWord_t positionFrac;
GET_VOL_MONO_RAMP
GET_MIXER_VARS_MONO_RAMP
@@ -1867,11 +1868,11 @@
void centerMix16bRampBidiLoopLIntrp(voice_t *v, uint32_t bufferPos, uint32_t numSamples)
{
const int16_t *base, *revBase, *smpPtr;
- double dSample, *dMixBufferL, *dMixBufferR;
- int32_t pos;
- double dVolLDelta, dVolL;
+ float fSample, *fMixBufferL, *fMixBufferR;
+ int32_t position;
+ float fVolumeLDelta, fVolumeL;
uint32_t i, samplesToMix, samplesLeft;
- uint64_t posFrac, tmpDelta;
+ uintCPUWord_t positionFrac, tmpDelta;
GET_VOL_MONO_RAMP
GET_MIXER_VARS_MONO_RAMP
--- a/src/mixer/ft2_mix.c
+++ b/src/mixer/ft2_mix.c
@@ -3,16 +3,17 @@
#include "ft2_mix.h"
#include "ft2_mix_macros.h"
#include "ft2_center_mix.h"
+#include "../ft2_cpu.h"
/*
-** ------------ double-precision floating-point audio channel mixer ------------
-** (Note: Mixing macros can be found in ft2_mix_macros.h)
+** ------------ 32-bit floating-point audio channel mixer ------------
+** (Note: Mixing macros can be found in ft2_mix_macros.h)
**
** Specifications:
-** - Either no interpolation, 2-tap linear interpolation (FT2) or 8-tap windowed-sinc interpolation
-** - Linear volume ramping, matching FT2 (can be turned off)
-** - 32.32 fixed-point logic for resampling delta
-** - 64-bit doube-precision logic for mixing and interpolation
+** - No interpolation, 2-tap linear interpolation (FT2) or 8-tap windowed-sinc interpolation
+** - FT2-styled linear volume ramping (can be turned off)
+** - 32.32 (16.16 if 32-bit CPU) fixed-point precision for resampling delta/position
+** - 32-bit floating-point precision for mixing and interpolation
**
** This file has separate routines for EVERY possible sampling variation:
** Interpolation none/sinc/linear, volumeramp on/off, 8-bit, 16-bit, no loop, loop, bidi.
@@ -34,10 +35,10 @@
static void mix8bNoLoop(voice_t *v, uint32_t bufferPos, uint32_t numSamples)
{
const int8_t *base, *smpPtr;
- double dSample, *dMixBufferL, *dMixBufferR;
- int32_t pos;
+ float fSample, *fMixBufferL, *fMixBufferR;
+ int32_t position;
uint32_t i, samplesToMix, samplesLeft;
- uint64_t posFrac;
+ uintCPUWord_t positionFrac;
GET_VOL
GET_MIXER_VARS
@@ -76,10 +77,10 @@
static void mix8bLoop(voice_t *v, uint32_t bufferPos, uint32_t numSamples)
{
const int8_t *base, *smpPtr;
- double dSample, *dMixBufferL, *dMixBufferR;
- int32_t pos;
+ float fSample, *fMixBufferL, *fMixBufferR;
+ int32_t position;
uint32_t i, samplesToMix, samplesLeft;
- uint64_t posFrac;
+ uintCPUWord_t positionFrac;
GET_VOL
GET_MIXER_VARS
@@ -118,10 +119,10 @@
static void mix8bBidiLoop(voice_t *v, uint32_t bufferPos, uint32_t numSamples)
{
const int8_t *base, *revBase, *smpPtr;
- double dSample, *dMixBufferL, *dMixBufferR;
- int32_t pos;
+ float fSample, *fMixBufferL, *fMixBufferR;
+ int32_t position;
uint32_t i, samplesToMix, samplesLeft;
- uint64_t posFrac, tmpDelta;
+ uintCPUWord_t positionFrac, tmpDelta;
GET_VOL
GET_MIXER_VARS
@@ -161,10 +162,10 @@
static void mix8bNoLoopSIntrp(voice_t *v, uint32_t bufferPos, uint32_t numSamples)
{
const int8_t *base, *smpPtr;
- double dSample, *dMixBufferL, *dMixBufferR;
- int32_t pos;
+ float fSample, *fMixBufferL, *fMixBufferR;
+ int32_t position;
uint32_t i, samplesToMix, samplesLeft;
- uint64_t posFrac;
+ uintCPUWord_t positionFrac;
GET_VOL
GET_MIXER_VARS
@@ -204,10 +205,10 @@
{
const int8_t *base, *smpPtr;
int8_t *smpTapPtr;
- double dSample, *dMixBufferL, *dMixBufferR;
- int32_t pos;
+ float fSample, *fMixBufferL, *fMixBufferR;
+ int32_t position;
uint32_t i, samplesToMix, samplesLeft;
- uint64_t posFrac;
+ uintCPUWord_t positionFrac;
GET_VOL
GET_MIXER_VARS
@@ -271,10 +272,10 @@
{
const int8_t *base, *revBase, *smpPtr;
int8_t *smpTapPtr;
- double dSample, *dMixBufferL, *dMixBufferR;
- int32_t pos;
+ float fSample, *fMixBufferL, *fMixBufferR;
+ int32_t position;
uint32_t i, samplesToMix, samplesLeft;
- uint64_t posFrac, tmpDelta;
+ uintCPUWord_t positionFrac, tmpDelta;
GET_VOL
GET_MIXER_VARS
@@ -339,10 +340,10 @@
static void mix8bNoLoopLIntrp(voice_t *v, uint32_t bufferPos, uint32_t numSamples)
{
const int8_t *base, *smpPtr;
- double dSample, *dMixBufferL, *dMixBufferR;
- int32_t pos;
+ float fSample, *fMixBufferL, *fMixBufferR;
+ int32_t position;
uint32_t i, samplesToMix, samplesLeft;
- uint64_t posFrac;
+ uintCPUWord_t positionFrac;
GET_VOL
GET_MIXER_VARS
@@ -381,10 +382,10 @@
static void mix8bLoopLIntrp(voice_t *v, uint32_t bufferPos, uint32_t numSamples)
{
const int8_t *base, *smpPtr;
- double dSample, *dMixBufferL, *dMixBufferR;
- int32_t pos;
+ float fSample, *fMixBufferL, *fMixBufferR;
+ int32_t position;
uint32_t i, samplesToMix, samplesLeft;
- uint64_t posFrac;
+ uintCPUWord_t positionFrac;
GET_VOL
GET_MIXER_VARS
@@ -423,10 +424,10 @@
static void mix8bBidiLoopLIntrp(voice_t *v, uint32_t bufferPos, uint32_t numSamples)
{
const int8_t *base, *revBase, *smpPtr;
- double dSample, *dMixBufferL, *dMixBufferR;
- int32_t pos;
+ float fSample, *fMixBufferL, *fMixBufferR;
+ int32_t position;
uint32_t i, samplesToMix, samplesLeft;
- uint64_t posFrac, tmpDelta;
+ uintCPUWord_t positionFrac, tmpDelta;
GET_VOL
GET_MIXER_VARS
@@ -467,11 +468,11 @@
static void mix8bRampNoLoop(voice_t *v, uint32_t bufferPos, uint32_t numSamples)
{
const int8_t *base, *smpPtr;
- double dSample, *dMixBufferL, *dMixBufferR;
- int32_t pos;
- double dVolLDelta, dVolRDelta, dVolL, dVolR;
+ float fSample, *fMixBufferL, *fMixBufferR;
+ int32_t position;
+ float fVolumeLDelta, fVolumeRDelta, fVolumeL, fVolumeR;
uint32_t i, samplesToMix, samplesLeft;
- uint64_t posFrac;
+ uintCPUWord_t positionFrac;
GET_VOL_RAMP
GET_MIXER_VARS_RAMP
@@ -517,11 +518,11 @@
static void mix8bRampLoop(voice_t *v, uint32_t bufferPos, uint32_t numSamples)
{
const int8_t *base, *smpPtr;
- double dSample, *dMixBufferL, *dMixBufferR;
- int32_t pos;
- double dVolLDelta, dVolRDelta, dVolL, dVolR;
+ float fSample, *fMixBufferL, *fMixBufferR;
+ int32_t position;
+ float fVolumeLDelta, fVolumeRDelta, fVolumeL, fVolumeR;
uint32_t i, samplesToMix, samplesLeft;
- uint64_t posFrac;
+ uintCPUWord_t positionFrac;
GET_VOL_RAMP
GET_MIXER_VARS_RAMP
@@ -567,11 +568,11 @@
static void mix8bRampBidiLoop(voice_t *v, uint32_t bufferPos, uint32_t numSamples)
{
const int8_t *base, *revBase, *smpPtr;
- double dSample, *dMixBufferL, *dMixBufferR;
- int32_t pos;
- double dVolLDelta, dVolRDelta, dVolL, dVolR;
+ float fSample, *fMixBufferL, *fMixBufferR;
+ int32_t position;
+ float fVolumeLDelta, fVolumeRDelta, fVolumeL, fVolumeR;
uint32_t i, samplesToMix, samplesLeft;
- uint64_t posFrac, tmpDelta;
+ uintCPUWord_t positionFrac, tmpDelta;
GET_VOL_RAMP
GET_MIXER_VARS_RAMP
@@ -619,11 +620,11 @@
static void mix8bRampNoLoopSIntrp(voice_t *v, uint32_t bufferPos, uint32_t numSamples)
{
const int8_t *base, *smpPtr;
- double dSample, *dMixBufferL, *dMixBufferR;
- int32_t pos;
- double dVolLDelta, dVolRDelta, dVolL, dVolR;
+ float fSample, *fMixBufferL, *fMixBufferR;
+ int32_t position;
+ float fVolumeLDelta, fVolumeRDelta, fVolumeL, fVolumeR;
uint32_t i, samplesToMix, samplesLeft;
- uint64_t posFrac;
+ uintCPUWord_t positionFrac;
GET_VOL_RAMP
GET_MIXER_VARS_RAMP
@@ -670,11 +671,11 @@
{
const int8_t *base, *smpPtr;
int8_t *smpTapPtr;
- double dSample, *dMixBufferL, *dMixBufferR;
- int32_t pos;
- double dVolLDelta, dVolRDelta, dVolL, dVolR;
+ float fSample, *fMixBufferL, *fMixBufferR;
+ int32_t position;
+ float fVolumeLDelta, fVolumeRDelta, fVolumeL, fVolumeR;
uint32_t i, samplesToMix, samplesLeft;
- uint64_t posFrac;
+ uintCPUWord_t positionFrac;
GET_VOL_RAMP
GET_MIXER_VARS_RAMP
@@ -750,11 +751,11 @@
{
const int8_t *base, *revBase, *smpPtr;
int8_t *smpTapPtr;
- double dSample, *dMixBufferL, *dMixBufferR;
- int32_t pos;
- double dVolLDelta, dVolRDelta, dVolL, dVolR;
+ float fSample, *fMixBufferL, *fMixBufferR;
+ int32_t position;
+ float fVolumeLDelta, fVolumeRDelta, fVolumeL, fVolumeR;
uint32_t i, samplesToMix, samplesLeft;
- uint64_t posFrac, tmpDelta;
+ uintCPUWord_t positionFrac, tmpDelta;
GET_VOL_RAMP
GET_MIXER_VARS_RAMP
@@ -831,11 +832,11 @@
static void mix8bRampNoLoopLIntrp(voice_t *v, uint32_t bufferPos, uint32_t numSamples)
{
const int8_t *base, *smpPtr;
- double dSample, *dMixBufferL, *dMixBufferR;
- int32_t pos;
- double dVolLDelta, dVolRDelta, dVolL, dVolR;
+ float fSample, *fMixBufferL, *fMixBufferR;
+ int32_t position;
+ float fVolumeLDelta, fVolumeRDelta, fVolumeL, fVolumeR;
uint32_t i, samplesToMix, samplesLeft;
- uint64_t posFrac;
+ uintCPUWord_t positionFrac;
GET_VOL_RAMP
GET_MIXER_VARS_RAMP
@@ -881,11 +882,11 @@
static void mix8bRampLoopLIntrp(voice_t *v, uint32_t bufferPos, uint32_t numSamples)
{
const int8_t *base, *smpPtr;
- double dSample, *dMixBufferL, *dMixBufferR;
- int32_t pos;
- double dVolLDelta, dVolRDelta, dVolL, dVolR;
+ float fSample, *fMixBufferL, *fMixBufferR;
+ int32_t position;
+ float fVolumeLDelta, fVolumeRDelta, fVolumeL, fVolumeR;
uint32_t i, samplesToMix, samplesLeft;
- uint64_t posFrac;
+ uintCPUWord_t positionFrac;
GET_VOL_RAMP
GET_MIXER_VARS_RAMP
@@ -931,11 +932,11 @@
static void mix8bRampBidiLoopLIntrp(voice_t *v, uint32_t bufferPos, uint32_t numSamples)
{
const int8_t *base, *revBase, *smpPtr;
- double dSample, *dMixBufferL, *dMixBufferR;
- int32_t pos;
- double dVolLDelta, dVolRDelta, dVolL, dVolR;
+ float fSample, *fMixBufferL, *fMixBufferR;
+ int32_t position;
+ float fVolumeLDelta, fVolumeRDelta, fVolumeL, fVolumeR;
uint32_t i, samplesToMix, samplesLeft;
- uint64_t posFrac, tmpDelta;
+ uintCPUWord_t positionFrac, tmpDelta;
GET_VOL_RAMP
GET_MIXER_VARS_RAMP
@@ -987,10 +988,10 @@
static void mix16bNoLoop(voice_t *v, uint32_t bufferPos, uint32_t numSamples)
{
const int16_t *base, *smpPtr;
- double dSample, *dMixBufferL, *dMixBufferR;
- int32_t pos;
+ float fSample, *fMixBufferL, *fMixBufferR;
+ int32_t position;
uint32_t i, samplesToMix, samplesLeft;
- uint64_t posFrac;
+ uintCPUWord_t positionFrac;
GET_VOL
GET_MIXER_VARS
@@ -1029,10 +1030,10 @@
static void mix16bLoop(voice_t *v, uint32_t bufferPos, uint32_t numSamples)
{
const int16_t *base, *smpPtr;
- double dSample, *dMixBufferL, *dMixBufferR;
- int32_t pos;
+ float fSample, *fMixBufferL, *fMixBufferR;
+ int32_t position;
uint32_t i, samplesToMix, samplesLeft;
- uint64_t posFrac;
+ uintCPUWord_t positionFrac;
GET_VOL
GET_MIXER_VARS
@@ -1071,10 +1072,10 @@
static void mix16bBidiLoop(voice_t *v, uint32_t bufferPos, uint32_t numSamples)
{
const int16_t *base, *revBase, *smpPtr;
- double dSample, *dMixBufferL, *dMixBufferR;
- int32_t pos;
+ float fSample, *fMixBufferL, *fMixBufferR;
+ int32_t position;
uint32_t i, samplesToMix, samplesLeft;
- uint64_t posFrac, tmpDelta;
+ uintCPUWord_t positionFrac, tmpDelta;
GET_VOL
GET_MIXER_VARS
@@ -1115,10 +1116,10 @@
static void mix16bNoLoopSIntrp(voice_t *v, uint32_t bufferPos, uint32_t numSamples)
{
const int16_t *base, *smpPtr;
- double dSample, *dMixBufferL, *dMixBufferR;
- int32_t pos;
+ float fSample, *fMixBufferL, *fMixBufferR;
+ int32_t position;
uint32_t i, samplesToMix, samplesLeft;
- uint64_t posFrac;
+ uintCPUWord_t positionFrac;
GET_VOL
GET_MIXER_VARS
@@ -1158,10 +1159,10 @@
{
const int16_t *base, *smpPtr;
int16_t *smpTapPtr;
- double dSample, *dMixBufferL, *dMixBufferR;
- int32_t pos;
+ float fSample, *fMixBufferL, *fMixBufferR;
+ int32_t position;
uint32_t i, samplesToMix, samplesLeft;
- uint64_t posFrac;
+ uintCPUWord_t positionFrac;
GET_VOL
GET_MIXER_VARS
@@ -1225,10 +1226,10 @@
{
const int16_t *base, *revBase, *smpPtr;
int16_t *smpTapPtr;
- double dSample, *dMixBufferL, *dMixBufferR;
- int32_t pos;
+ float fSample, *fMixBufferL, *fMixBufferR;
+ int32_t position;
uint32_t i, samplesToMix, samplesLeft;
- uint64_t posFrac, tmpDelta;
+ uintCPUWord_t positionFrac, tmpDelta;
GET_VOL
GET_MIXER_VARS
@@ -1293,10 +1294,10 @@
static void mix16bNoLoopLIntrp(voice_t *v, uint32_t bufferPos, uint32_t numSamples)
{
const int16_t *base, *smpPtr;
- double dSample, *dMixBufferL, *dMixBufferR;
- int32_t pos;
+ float fSample, *fMixBufferL, *fMixBufferR;
+ int32_t position;
uint32_t i, samplesToMix, samplesLeft;
- uint64_t posFrac;
+ uintCPUWord_t positionFrac;
GET_VOL
GET_MIXER_VARS
@@ -1335,10 +1336,10 @@
static void mix16bLoopLIntrp(voice_t *v, uint32_t bufferPos, uint32_t numSamples)
{
const int16_t *base, *smpPtr;
- double dSample, *dMixBufferL, *dMixBufferR;
- int32_t pos;
+ float fSample, *fMixBufferL, *fMixBufferR;
+ int32_t position;
uint32_t i, samplesToMix, samplesLeft;
- uint64_t posFrac;
+ uintCPUWord_t positionFrac;
GET_VOL
GET_MIXER_VARS
@@ -1377,10 +1378,10 @@
static void mix16bBidiLoopLIntrp(voice_t *v, uint32_t bufferPos, uint32_t numSamples)
{
const int16_t *base, *revBase, *smpPtr;
- double dSample, *dMixBufferL, *dMixBufferR;
- int32_t pos;
+ float fSample, *fMixBufferL, *fMixBufferR;
+ int32_t position;
uint32_t i, samplesToMix, samplesLeft;
- uint64_t posFrac, tmpDelta;
+ uintCPUWord_t positionFrac, tmpDelta;
GET_VOL
GET_MIXER_VARS
@@ -1421,11 +1422,11 @@
static void mix16bRampNoLoop(voice_t *v, uint32_t bufferPos, uint32_t numSamples)
{
const int16_t *base, *smpPtr;
- double dSample, *dMixBufferL, *dMixBufferR;
- int32_t pos;
- double dVolLDelta, dVolRDelta, dVolL, dVolR;
+ float fSample, *fMixBufferL, *fMixBufferR;
+ int32_t position;
+ float fVolumeLDelta, fVolumeRDelta, fVolumeL, fVolumeR;
uint32_t i, samplesToMix, samplesLeft;
- uint64_t posFrac;
+ uintCPUWord_t positionFrac;
GET_VOL_RAMP
GET_MIXER_VARS_RAMP
@@ -1471,11 +1472,11 @@
static void mix16bRampLoop(voice_t *v, uint32_t bufferPos, uint32_t numSamples)
{
const int16_t *base, *smpPtr;
- double dSample, *dMixBufferL, *dMixBufferR;
- int32_t pos;
- double dVolLDelta, dVolRDelta, dVolL, dVolR;
+ float fSample, *fMixBufferL, *fMixBufferR;
+ int32_t position;
+ float fVolumeLDelta, fVolumeRDelta, fVolumeL, fVolumeR;
uint32_t i, samplesToMix, samplesLeft;
- uint64_t posFrac;
+ uintCPUWord_t positionFrac;
GET_VOL_RAMP
GET_MIXER_VARS_RAMP
@@ -1521,11 +1522,11 @@
static void mix16bRampBidiLoop(voice_t *v, uint32_t bufferPos, uint32_t numSamples)
{
const int16_t *base, *revBase, *smpPtr;
- double dSample, *dMixBufferL, *dMixBufferR;
- int32_t pos;
- double dVolLDelta, dVolRDelta, dVolL, dVolR;
+ float fSample, *fMixBufferL, *fMixBufferR;
+ int32_t position;
+ float fVolumeLDelta, fVolumeRDelta, fVolumeL, fVolumeR;
uint32_t i, samplesToMix, samplesLeft;
- uint64_t posFrac, tmpDelta;
+ uintCPUWord_t positionFrac, tmpDelta;
GET_VOL_RAMP
GET_MIXER_VARS_RAMP
@@ -1573,11 +1574,11 @@
static void mix16bRampNoLoopSIntrp(voice_t *v, uint32_t bufferPos, uint32_t numSamples)
{
const int16_t *base, *smpPtr;
- double dSample, *dMixBufferL, *dMixBufferR;
- int32_t pos;
- double dVolLDelta, dVolRDelta, dVolL, dVolR;
+ float fSample, *fMixBufferL, *fMixBufferR;
+ int32_t position;
+ float fVolumeLDelta, fVolumeRDelta, fVolumeL, fVolumeR;
uint32_t i, samplesToMix, samplesLeft;
- uint64_t posFrac;
+ uintCPUWord_t positionFrac;
GET_VOL_RAMP
GET_MIXER_VARS_RAMP
@@ -1624,11 +1625,11 @@
{
const int16_t *base, *smpPtr;
int16_t *smpTapPtr;
- double dSample, *dMixBufferL, *dMixBufferR;
- int32_t pos;
- double dVolLDelta, dVolRDelta, dVolL, dVolR;
+ float fSample, *fMixBufferL, *fMixBufferR;
+ int32_t position;
+ float fVolumeLDelta, fVolumeRDelta, fVolumeL, fVolumeR;
uint32_t i, samplesToMix, samplesLeft;
- uint64_t posFrac;
+ uintCPUWord_t positionFrac;
GET_VOL_RAMP
GET_MIXER_VARS_RAMP
@@ -1704,11 +1705,11 @@
{
const int16_t *base, *revBase, *smpPtr;
int16_t *smpTapPtr;
- double dSample, *dMixBufferL, *dMixBufferR;
- int32_t pos;
- double dVolLDelta, dVolRDelta, dVolL, dVolR;
+ float fSample, *fMixBufferL, *fMixBufferR;
+ int32_t position;
+ float fVolumeLDelta, fVolumeRDelta, fVolumeL, fVolumeR;
uint32_t i, samplesToMix, samplesLeft;
- uint64_t posFrac, tmpDelta;
+ uintCPUWord_t positionFrac, tmpDelta;
GET_VOL_RAMP
GET_MIXER_VARS_RAMP
@@ -1785,11 +1786,11 @@
static void mix16bRampNoLoopLIntrp(voice_t *v, uint32_t bufferPos, uint32_t numSamples)
{
const int16_t *base, *smpPtr;
- double dSample, *dMixBufferL, *dMixBufferR;
- int32_t pos;
- double dVolLDelta, dVolRDelta, dVolL, dVolR;
+ float fSample, *fMixBufferL, *fMixBufferR;
+ int32_t position;
+ float fVolumeLDelta, fVolumeRDelta, fVolumeL, fVolumeR;
uint32_t i, samplesToMix, samplesLeft;
- uint64_t posFrac;
+ uintCPUWord_t positionFrac;
GET_VOL_RAMP
GET_MIXER_VARS_RAMP
@@ -1835,11 +1836,11 @@
static void mix16bRampLoopLIntrp(voice_t *v, uint32_t bufferPos, uint32_t numSamples)
{
const int16_t *base, *smpPtr;
- double dSample, *dMixBufferL, *dMixBufferR;
- int32_t pos;
- double dVolLDelta, dVolRDelta, dVolL, dVolR;
+ float fSample, *fMixBufferL, *fMixBufferR;
+ int32_t position;
+ float fVolumeLDelta, fVolumeRDelta, fVolumeL, fVolumeR;
uint32_t i, samplesToMix, samplesLeft;
- uint64_t posFrac;
+ uintCPUWord_t positionFrac;
GET_VOL_RAMP
GET_MIXER_VARS_RAMP
@@ -1885,11 +1886,11 @@
static void mix16bRampBidiLoopLIntrp(voice_t *v, uint32_t bufferPos, uint32_t numSamples)
{
const int16_t *base, *revBase, *smpPtr;
- double dSample, *dMixBufferL, *dMixBufferR;
- int32_t pos;
- double dVolLDelta, dVolRDelta, dVolL, dVolR;
+ float fSample, *fMixBufferL, *fMixBufferR;
+ int32_t position;
+ float fVolumeLDelta, fVolumeRDelta, fVolumeL, fVolumeR;
uint32_t i, samplesToMix, samplesLeft;
- uint64_t posFrac, tmpDelta;
+ uintCPUWord_t positionFrac, tmpDelta;
GET_VOL_RAMP
GET_MIXER_VARS_RAMP
--- a/src/mixer/ft2_mix.h
+++ b/src/mixer/ft2_mix.h
@@ -1,7 +1,16 @@
#pragma once
#include <stdint.h>
-#include "../ft2_audio.h"
+#include "../ft2_cpu.h"
+
+#if CPU_64BIT
+#define MIXER_FRAC_BITS 32
+#else
+#define MIXER_FRAC_BITS 16
+#endif
+
+#define MIXER_FRAC_SCALE ((intCPUWord_t)1 << MIXER_FRAC_BITS)
+#define MIXER_FRAC_MASK (MIXER_FRAC_SCALE-1)
typedef void (*mixFunc)(void *, uint32_t, uint32_t);
--- a/src/mixer/ft2_mix_macros.h
+++ b/src/mixer/ft2_mix_macros.h
@@ -1,6 +1,5 @@
#pragma once
-#include <assert.h>
#include "../ft2_audio.h"
#include "ft2_windowed_sinc.h"
@@ -9,88 +8,89 @@
/* ----------------------------------------------------------------------- */
#define GET_VOL \
- const double dVolL = v->dVolL; \
- const double dVolR = v->dVolR; \
+ const float fVolumeL = v->fVolumeL; \
+ const float fVolumeR = v->fVolumeR;
#define GET_VOL_MONO \
- const double dVolL = v->dVolL; \
+ const float fVolumeL = v->fVolumeL;
#define GET_VOL_RAMP \
- dVolL = v->dVolL; \
- dVolR = v->dVolR; \
+ fVolumeL = v->fVolumeL; \
+ fVolumeR = v->fVolumeR;
#define GET_VOL_MONO_RAMP \
- dVolL = v->dVolL; \
+ fVolumeL = v->fVolumeL;
#define SET_VOL_BACK \
- v->dVolL = dVolL; \
- v->dVolR = dVolR; \
+ v->fVolumeL = fVolumeL; \
+ v->fVolumeR = fVolumeR;
#define SET_VOL_BACK_MONO \
- v->dVolL = v->dVolR = dVolL; \
+ v->fVolumeL = fVolumeL; \
+ v->fVolumeR = fVolumeL;
#define GET_MIXER_VARS \
- const uint64_t delta = v->delta; \
- dMixBufferL = audio.dMixBufferL + bufferPos; \
- dMixBufferR = audio.dMixBufferR + bufferPos; \
- pos = v->pos; \
- posFrac = v->posFrac; \
+ const uintCPUWord_t delta = v->delta; \
+ fMixBufferL = audio.fMixBufferL + bufferPos; \
+ fMixBufferR = audio.fMixBufferR + bufferPos; \
+ position = v->position; \
+ positionFrac = v->positionFrac;
#define GET_MIXER_VARS_RAMP \
- const uint64_t delta = v->delta; \
- dMixBufferL = audio.dMixBufferL + bufferPos; \
- dMixBufferR = audio.dMixBufferR + bufferPos; \
- dVolLDelta = v->dVolDeltaL; \
- dVolRDelta = v->dVolDeltaR; \
- pos = v->pos; \
- posFrac = v->posFrac; \
+ const uintCPUWord_t delta = v->delta; \
+ fMixBufferL = audio.fMixBufferL + bufferPos; \
+ fMixBufferR = audio.fMixBufferR + bufferPos; \
+ fVolumeLDelta = v->fVolumeLDelta; \
+ fVolumeRDelta = v->fVolumeRDelta; \
+ position = v->position; \
+ positionFrac = v->positionFrac;
#define GET_MIXER_VARS_MONO_RAMP \
- const uint64_t delta = v->delta; \
- dMixBufferL = audio.dMixBufferL + bufferPos; \
- dMixBufferR = audio.dMixBufferR + bufferPos; \
- dVolLDelta = v->dVolDeltaL; \
- pos = v->pos; \
- posFrac = v->posFrac; \
+ const uintCPUWord_t delta = v->delta; \
+ fMixBufferL = audio.fMixBufferL + bufferPos; \
+ fMixBufferR = audio.fMixBufferR + bufferPos; \
+ fVolumeLDelta = v->fVolumeLDelta; \
+ position = v->position; \
+ positionFrac = v->positionFrac;
#define PREPARE_TAP_FIX8 \
const int8_t *loopStartPtr = &v->base8[v->loopStart]; \
- const int8_t *leftEdgePtr = loopStartPtr+SINC_LEFT_TAPS; \
+ const int8_t *leftEdgePtr = loopStartPtr+SINC_LEFT_TAPS;
#define PREPARE_TAP_FIX16 \
const int16_t *loopStartPtr = &v->base16[v->loopStart]; \
- const int16_t *leftEdgePtr = loopStartPtr+SINC_LEFT_TAPS; \
+ const int16_t *leftEdgePtr = loopStartPtr+SINC_LEFT_TAPS;
#define SET_BASE8 \
base = v->base8; \
- smpPtr = base + pos; \
+ smpPtr = base + position;
#define SET_BASE16 \
base = v->base16; \
- smpPtr = base + pos; \
+ smpPtr = base + position;
#define SET_BASE8_BIDI \
base = v->base8; \
- revBase = v->revBase8; \
+ revBase = v->revBase8;
#define SET_BASE16_BIDI \
base = v->base16; \
- revBase = v->revBase16; \
+ revBase = v->revBase16;
#define INC_POS \
- posFrac += delta; \
- smpPtr += posFrac >> MIXER_FRAC_BITS; \
- posFrac &= MIXER_FRAC_MASK; \
+ positionFrac += delta; \
+ smpPtr += positionFrac >> MIXER_FRAC_BITS; \
+ positionFrac &= MIXER_FRAC_MASK;
#define INC_POS_BIDI \
- posFrac += deltaLo; \
- smpPtr += posFrac >> MIXER_FRAC_BITS; \
+ positionFrac += deltaLo; \
+ smpPtr += positionFrac >> MIXER_FRAC_BITS; \
smpPtr += deltaHi; \
- posFrac &= MIXER_FRAC_MASK; \
+ positionFrac &= MIXER_FRAC_MASK;
#define SET_BACK_MIXER_POS \
- v->posFrac = posFrac; \
- v->pos = pos; \
+ v->positionFrac = positionFrac; \
+ v->position = position;
/* ----------------------------------------------------------------------- */
/* SAMPLE RENDERING MACROS */
@@ -97,72 +97,66 @@
/* ----------------------------------------------------------------------- */
#define VOLUME_RAMPING \
- dVolL += dVolLDelta; \
- dVolR += dVolRDelta; \
+ fVolumeL += fVolumeLDelta; \
+ fVolumeR += fVolumeRDelta;
#define VOLUME_RAMPING_MONO \
- dVolL += dVolLDelta; \
+ fVolumeL += fVolumeLDelta;
#define RENDER_8BIT_SMP \
- assert(smpPtr >= base && smpPtr < base+v->end); \
- dSample = *smpPtr * (1.0 / 128.0); \
- *dMixBufferL++ += dSample * dVolL; \
- *dMixBufferR++ += dSample * dVolR; \
+ fSample = *smpPtr * (1.0f / 128.0f); \
+ *fMixBufferL++ += fSample * fVolumeL; \
+ *fMixBufferR++ += fSample * fVolumeR;
#define RENDER_8BIT_SMP_MONO \
- assert(smpPtr >= base && smpPtr < base+v->end); \
- dSample = (*smpPtr * (1.0 / 128.0)) * dVolL; \
- *dMixBufferL++ += dSample; \
- *dMixBufferR++ += dSample; \
+ fSample = (*smpPtr * (1.0f / 128.0f)) * fVolumeL; \
+ *fMixBufferL++ += fSample; \
+ *fMixBufferR++ += fSample;
#define RENDER_16BIT_SMP \
- assert(smpPtr >= base && smpPtr < base+v->end); \
- dSample = *smpPtr * (1.0 / 32768.0); \
- *dMixBufferL++ += dSample * dVolL; \
- *dMixBufferR++ += dSample * dVolR; \
+ fSample = *smpPtr * (1.0f / 32768.0f); \
+ *fMixBufferL++ += fSample * fVolumeL; \
+ *fMixBufferR++ += fSample * fVolumeR;
#define RENDER_16BIT_SMP_MONO \
- assert(smpPtr >= base && smpPtr < base+v->end); \
- dSample = (*smpPtr * (1.0 / 32768.0)) * dVolL; \
- *dMixBufferL++ += dSample; \
- *dMixBufferR++ += dSample; \
+ fSample = (*smpPtr * (1.0f / 32768.0f)) * fVolumeL; \
+ *fMixBufferL++ += fSample; \
+ *fMixBufferR++ += fSample;
// 2-tap linear interpolation (like FT2)
+/* 8bitbubsy: It may look like we are potentially going out of bounds while looking up the sample points,
+** but the sample data has a fixed sample after the end (sampleEnd/loopEnd).
+*/
+
#define LINEAR_INTERPOLATION(s, f, scale) \
{ \
- /* uint32_t -> int32_t for less SIMD overhead when doing int->double conversion */ \
- const int32_t frac = (uint32_t)(f) >> 1; /* (2^32)-1 -> (2^31)-1 */ \
- \
- const double dFrac = (double)(frac * (1.0 / (INT32_MAX+1.0))); /* 0.0 .. 0.999999999 */ \
- dSample = ((s[0] + (s[1]-s[0]) * dFrac)) * (1.0 / scale); \
-} \
+ const int32_t frac = (uint32_t)(f) >> 1; /* uint32 -> int32 range, faster int->float conv. (x86/x86_64) */ \
+ const float fFrac = frac * (1.0f / (MIXER_FRAC_SCALE/2)); /* 0.0f .. 0.9999999f */ \
+ fSample = ((s[0] + (s[1]-s[0]) * fFrac)) * (1.0f / scale); \
+}
#define RENDER_8BIT_SMP_LINTRP \
- assert(smpPtr >= base && smpPtr < base+v->end); \
- LINEAR_INTERPOLATION(smpPtr, posFrac, 128) \
- *dMixBufferL++ += dSample * dVolL; \
- *dMixBufferR++ += dSample * dVolR; \
+ LINEAR_INTERPOLATION(smpPtr, positionFrac, 128) \
+ *fMixBufferL++ += fSample * fVolumeL; \
+ *fMixBufferR++ += fSample * fVolumeR;
#define RENDER_8BIT_SMP_MONO_LINTRP \
- assert(smpPtr >= base && smpPtr < base+v->end); \
- LINEAR_INTERPOLATION(smpPtr, posFrac, 128) \
- dSample *= dVolL; \
- *dMixBufferL++ += dSample; \
- *dMixBufferR++ += dSample; \
+ LINEAR_INTERPOLATION(smpPtr, positionFrac, 128) \
+ fSample *= fVolumeL; \
+ *fMixBufferL++ += fSample; \
+ *fMixBufferR++ += fSample;
#define RENDER_16BIT_SMP_LINTRP \
- assert(smpPtr >= base && smpPtr < base+v->end); \
- LINEAR_INTERPOLATION(smpPtr, posFrac, 32768) \
- *dMixBufferL++ += dSample * dVolL; \
- *dMixBufferR++ += dSample * dVolR; \
+ LINEAR_INTERPOLATION(smpPtr, positionFrac, 32768) \
+ *fMixBufferL++ += fSample * fVolumeL; \
+ *fMixBufferR++ += fSample * fVolumeR;
#define RENDER_16BIT_SMP_MONO_LINTRP \
- assert(smpPtr >= base && smpPtr < base+v->end); \
- LINEAR_INTERPOLATION(smpPtr, posFrac, 32768) \
- dSample *= dVolL; \
- *dMixBufferL++ += dSample; \
- *dMixBufferR++ += dSample; \
+ LINEAR_INTERPOLATION(smpPtr, positionFrac, 32768) \
+ fSample *= fVolumeL; \
+ *fMixBufferL++ += fSample; \
+ *fMixBufferR++ += fSample;
// 8-tap windowed-sinc interpolation (better quality, through LUT: mixer/ft2_windowed_sinc.c)
@@ -176,8 +170,8 @@
#define WINDOWED_SINC_INTERPOLATION(s, f, scale) \
{ \
- const double *t = v->dSincLUT + (((uint32_t)f >> SINC_FSHIFT) & SINC_FMASK); \
- dSample = ((s[-3] * t[0]) + \
+ const float *t = v->fSincLUT + (((uint32_t)(f) >> SINC_FSHIFT) & SINC_FMASK); \
+ fSample = ((s[-3] * t[0]) + \
(s[-2] * t[1]) + \
(s[-1] * t[2]) + \
( s[0] * t[3]) + \
@@ -184,34 +178,30 @@
( s[1] * t[4]) + \
( s[2] * t[5]) + \
( s[3] * t[6]) + \
- ( s[4] * t[7])) * (1.0 / scale); \
-} \
+ ( s[4] * t[7])) * (1.0f / scale); \
+}
#define RENDER_8BIT_SMP_SINTRP \
- assert(smpPtr >= base && smpPtr < base+v->end); \
- WINDOWED_SINC_INTERPOLATION(smpPtr, posFrac, 128) \
- *dMixBufferL++ += dSample * dVolL; \
- *dMixBufferR++ += dSample * dVolR; \
+ WINDOWED_SINC_INTERPOLATION(smpPtr, positionFrac, 128) \
+ *fMixBufferL++ += fSample * fVolumeL; \
+ *fMixBufferR++ += fSample * fVolumeR;
#define RENDER_8BIT_SMP_MONO_SINTRP \
- assert(smpPtr >= base && smpPtr < base+v->end); \
- WINDOWED_SINC_INTERPOLATION(smpPtr, posFrac, 128) \
- dSample *= dVolL; \
- *dMixBufferL++ += dSample; \
- *dMixBufferR++ += dSample; \
+ WINDOWED_SINC_INTERPOLATION(smpPtr, positionFrac, 128) \
+ fSample *= fVolumeL; \
+ *fMixBufferL++ += fSample; \
+ *fMixBufferR++ += fSample;
#define RENDER_16BIT_SMP_SINTRP \
- assert(smpPtr >= base && smpPtr < base+v->end); \
- WINDOWED_SINC_INTERPOLATION(smpPtr, posFrac, 32768) \
- *dMixBufferL++ += dSample * dVolL; \
- *dMixBufferR++ += dSample * dVolR; \
+ WINDOWED_SINC_INTERPOLATION(smpPtr, positionFrac, 32768) \
+ *fMixBufferL++ += fSample * fVolumeL; \
+ *fMixBufferR++ += fSample * fVolumeR;
#define RENDER_16BIT_SMP_MONO_SINTRP \
- assert(smpPtr >= base && smpPtr < base+v->end); \
- WINDOWED_SINC_INTERPOLATION(smpPtr, posFrac, 32768) \
- dSample *= dVolL; \
- *dMixBufferL++ += dSample; \
- *dMixBufferR++ += dSample; \
+ WINDOWED_SINC_INTERPOLATION(smpPtr, positionFrac, 32768) \
+ fSample *= fVolumeL; \
+ *fMixBufferL++ += fSample; \
+ *fMixBufferR++ += fSample;
/* Special left-edge case mixers to get proper tap data after one loop cycle.
** These are only used with sinc interpolation on looped samples.
@@ -218,71 +208,76 @@
*/
#define RENDER_8BIT_SMP_SINTRP_TAP_FIX \
- assert(smpPtr >= base && smpPtr < base+v->end); \
smpTapPtr = (smpPtr <= leftEdgePtr) ? (int8_t *)&v->leftEdgeTaps8[(int32_t)(smpPtr-loopStartPtr)] : (int8_t *)smpPtr; \
- WINDOWED_SINC_INTERPOLATION(smpTapPtr, posFrac, 128) \
- *dMixBufferL++ += dSample * dVolL; \
- *dMixBufferR++ += dSample * dVolR; \
+ WINDOWED_SINC_INTERPOLATION(smpTapPtr, positionFrac, 128) \
+ *fMixBufferL++ += fSample * fVolumeL; \
+ *fMixBufferR++ += fSample * fVolumeR;
#define RENDER_8BIT_SMP_MONO_SINTRP_TAP_FIX \
- assert(smpPtr >= base && smpPtr < base+v->end); \
smpTapPtr = (smpPtr <= leftEdgePtr) ? (int8_t *)&v->leftEdgeTaps8[(int32_t)(smpPtr-loopStartPtr)] : (int8_t *)smpPtr; \
- WINDOWED_SINC_INTERPOLATION(smpTapPtr, posFrac, 128) \
- dSample *= dVolL; \
- *dMixBufferL++ += dSample; \
- *dMixBufferR++ += dSample; \
+ WINDOWED_SINC_INTERPOLATION(smpTapPtr, positionFrac, 128) \
+ fSample *= fVolumeL; \
+ *fMixBufferL++ += fSample; \
+ *fMixBufferR++ += fSample;
#define RENDER_16BIT_SMP_SINTRP_TAP_FIX \
- assert(smpPtr >= base && smpPtr < base+v->end); \
smpTapPtr = (smpPtr <= leftEdgePtr) ? (int16_t *)&v->leftEdgeTaps16[(int32_t)(smpPtr-loopStartPtr)] : (int16_t *)smpPtr; \
- WINDOWED_SINC_INTERPOLATION(smpTapPtr, posFrac, 32768) \
- *dMixBufferL++ += dSample * dVolL; \
- *dMixBufferR++ += dSample * dVolR; \
+ WINDOWED_SINC_INTERPOLATION(smpTapPtr, positionFrac, 32768) \
+ *fMixBufferL++ += fSample * fVolumeL; \
+ *fMixBufferR++ += fSample * fVolumeR;
#define RENDER_16BIT_SMP_MONO_SINTRP_TAP_FIX \
- assert(smpPtr >= base && smpPtr < base+v->end); \
smpTapPtr = (smpPtr <= leftEdgePtr) ? (int16_t *)&v->leftEdgeTaps16[(int32_t)(smpPtr-loopStartPtr)] : (int16_t *)smpPtr; \
- WINDOWED_SINC_INTERPOLATION(smpTapPtr, posFrac, 32768) \
- dSample *= dVolL; \
- *dMixBufferL++ += dSample; \
- *dMixBufferR++ += dSample; \
+ WINDOWED_SINC_INTERPOLATION(smpTapPtr, positionFrac, 32768) \
+ fSample *= fVolumeL; \
+ *fMixBufferL++ += fSample; \
+ *fMixBufferR++ += fSample;
/* ----------------------------------------------------------------------- */
/* SAMPLES-TO-MIX LIMITING MACROS */
/* ----------------------------------------------------------------------- */
+#if CPU_64BIT
+#define LIMIT_NUM
+#else
+#define LIMIT_NUM if (i > (1<<(32-MIXER_FRAC_BITS))-1) i = (1<<(32-MIXER_FRAC_BITS))-1;
+#endif
+
#define LIMIT_MIX_NUM \
- i = (v->end - 1) - pos; \
- const uint64_t tmp64 = ((uint64_t)i << 32) | ((uint32_t)posFrac ^ 0xFFFFFFFF); \
+ samplesToMix = INT32_MAX; \
+ if (v->delta != 0) \
+ { \
+ i = (v->sampleEnd - 1) - position; \
+ LIMIT_NUM \
+ const uintCPUWord_t dividend = ((uintCPUWord_t)i << MIXER_FRAC_BITS) | ((uint32_t)positionFrac ^ MIXER_FRAC_MASK); \
+ samplesToMix = (uint32_t)(dividend / (uintCPUWord_t)v->delta) + 1; \
+ } \
\
- samplesToMix = (uint32_t)(tmp64 / (uint64_t)v->delta) + 1; /* this can be slow on 32-bit systems... */ \
if (samplesToMix > samplesLeft) \
- samplesToMix = samplesLeft; \
+ samplesToMix = samplesLeft;
#define START_BIDI \
- if (v->backwards) \
+ if (v->samplingBackwards) \
{ \
tmpDelta = 0 - delta; \
- assert(pos >= v->loopStart && pos < v->end); \
- pos = ~pos; \
- smpPtr = revBase + pos; \
- posFrac ^= MIXER_FRAC_MASK; \
+ position = ~position; \
+ smpPtr = revBase + position; \
+ positionFrac ^= MIXER_FRAC_MASK; \
} \
else \
{ \
tmpDelta = delta; \
- assert(pos >= 0 && pos < v->end); \
- smpPtr = base + pos; \
+ smpPtr = base + position; \
} \
\
- const int32_t deltaHi = (int64_t)tmpDelta >> MIXER_FRAC_BITS; \
- const uint32_t deltaLo = tmpDelta & MIXER_FRAC_MASK; \
+ const int32_t deltaHi = (intCPUWord_t)tmpDelta >> MIXER_FRAC_BITS; \
+ const uint32_t deltaLo = tmpDelta & MIXER_FRAC_MASK;
#define LIMIT_MIX_NUM_RAMP \
- if (v->volRampSamples == 0) \
+ if (v->volumeRampLength == 0) \
{ \
- dVolLDelta = 0.0; \
- dVolRDelta = 0.0; \
+ fVolumeLDelta = 0.0; \
+ fVolumeRDelta = 0.0; \
\
if (v->isFadeOutVoice) \
{ \
@@ -292,16 +287,16 @@
} \
else \
{ \
- if (samplesToMix > v->volRampSamples) \
- samplesToMix = v->volRampSamples; \
+ if (samplesToMix > v->volumeRampLength) \
+ samplesToMix = v->volumeRampLength; \
\
- v->volRampSamples -= samplesToMix; \
- } \
+ v->volumeRampLength -= samplesToMix; \
+ }
#define LIMIT_MIX_NUM_MONO_RAMP \
- if (v->volRampSamples == 0) \
+ if (v->volumeRampLength == 0) \
{ \
- dVolLDelta = 0.0; \
+ fVolumeLDelta = 0.0; \
if (v->isFadeOutVoice) \
{ \
v->active = false; /* volume ramp fadeout-voice is done, shut it down */ \
@@ -310,55 +305,54 @@
} \
else \
{ \
- if (samplesToMix > v->volRampSamples) \
- samplesToMix = v->volRampSamples; \
+ if (samplesToMix > v->volumeRampLength) \
+ samplesToMix = v->volumeRampLength; \
\
- v->volRampSamples -= samplesToMix; \
- } \
+ v->volumeRampLength -= samplesToMix; \
+ }
#define HANDLE_SAMPLE_END \
- pos = (int32_t)(smpPtr - base); \
- if (pos >= v->end) \
+ position = (int32_t)(smpPtr - base); \
+ if (position >= v->sampleEnd) \
{ \
v->active = false; \
return; \
- } \
+ }
#define WRAP_LOOP \
- pos = (int32_t)(smpPtr - base); \
- if (pos >= v->end) \
+ position = (int32_t)(smpPtr - base); \
+ if (position >= v->sampleEnd) \
{ \
do \
{ \
- pos -= v->loopLength; \
+ position -= v->loopLength; \
} \
- while (pos >= v->end); \
+ while (position >= v->sampleEnd); \
\
- smpPtr = base + pos; \
+ smpPtr = base + position; \
\
v->hasLooped = true; \
- } \
+ }
#define WRAP_BIDI_LOOP \
- if (pos >= v->end) \
+ if (position >= v->sampleEnd) \
{ \
do \
{ \
- pos -= v->loopLength; \
- v->backwards ^= 1; \
+ position -= v->loopLength; \
+ v->samplingBackwards ^= 1; \
} \
- while (pos >= v->end); \
+ while (position >= v->sampleEnd); \
v->hasLooped = true; \
- } \
+ }
#define END_BIDI \
- if (v->backwards) \
+ if (v->samplingBackwards) \
{ \
- posFrac ^= MIXER_FRAC_MASK; \
- pos = ~(int32_t)(smpPtr - revBase); \
+ positionFrac ^= MIXER_FRAC_MASK; \
+ position = ~(int32_t)(smpPtr - revBase); \
} \
else \
{ \
- pos = (int32_t)(smpPtr - base); \
- } \
-
+ position = (int32_t)(smpPtr - base); \
+ }
--- a/src/mixer/ft2_silence_mix.c
+++ b/src/mixer/ft2_silence_mix.c
@@ -1,22 +1,23 @@
#include <stdint.h>
#include "../ft2_audio.h"
+#include "../ft2_cpu.h"
// used for the audio channel mixer when voice volume is zero
void silenceMixRoutine(voice_t *v, int32_t numSamples)
{
- const uint64_t newPos = v->delta * (uint64_t)numSamples;
- const uint32_t addPos = (uint32_t)(newPos >> MIXER_FRAC_BITS);
- uint64_t addFrac = newPos & MIXER_FRAC_MASK;
+ const uint64_t samplesToMix = (uint64_t)v->delta * (uint32_t)numSamples; // fixed-point
- addFrac += v->posFrac;
- int32_t pos = v->pos + addPos + (uint32_t)(addFrac >> MIXER_FRAC_BITS);
- uint64_t posFrac = addFrac & MIXER_FRAC_MASK;
+ const uint32_t samples = (uint32_t)(samplesToMix >> MIXER_FRAC_BITS);
+ const uintCPUWord_t samplesFrac = (samplesToMix & MIXER_FRAC_MASK) + v->positionFrac;
- if (pos < v->end) // we haven't reached the sample's end yet
+ uint32_t position = v->position + samples + (uint32_t)(samplesFrac >> MIXER_FRAC_BITS);
+ uintCPUWord_t positionFrac = samplesFrac & MIXER_FRAC_MASK;
+
+ if (position < (unsigned)v->sampleEnd) // we haven't reached the sample's end yet
{
- v->posFrac = posFrac;
- v->pos = pos;
+ v->positionFrac = positionFrac;
+ v->position = position;
return;
}
@@ -31,28 +32,28 @@
if (v->loopType == LOOP_FORWARD)
{
if (v->loopLength >= 2)
- pos = v->loopStart + ((pos - v->end) % v->loopLength);
+ position = v->loopStart + ((position - v->sampleEnd) % v->loopLength);
else
- pos = v->loopStart;
+ position = v->loopStart;
}
else // pingpong loop
{
if (v->loopLength >= 2)
{
- const int32_t overflow = pos - v->end;
- const int32_t cycles = overflow / v->loopLength;
- const int32_t phase = overflow % v->loopLength;
+ const uint32_t overflow = position - v->sampleEnd;
+ const uint32_t cycles = overflow / v->loopLength;
+ const uint32_t phase = overflow % v->loopLength;
- pos = v->loopStart + phase;
- v->backwards ^= !(cycles & 1);
+ position = v->loopStart + phase;
+ v->samplingBackwards ^= !(cycles & 1);
}
else
{
- pos = v->loopStart;
+ position = v->loopStart;
}
}
v->hasLooped = true;
- v->posFrac = posFrac;
- v->pos = pos;
+ v->positionFrac = positionFrac;
+ v->position = position;
}
--- a/src/mixer/ft2_windowed_sinc.c
+++ b/src/mixer/ft2_windowed_sinc.c
@@ -1,3 +1,9 @@
+/* Code taken from the OpenMPT project, which has a BSD
+** license which is compatible with this project.
+**
+** The code has been slightly modified.
+*/
+
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
@@ -5,16 +11,10 @@
#include "ft2_windowed_sinc.h"
// globalized
-double *gKaiserSinc = NULL;
-double *gDownSample1 = NULL;
-double *gDownSample2 = NULL;
+float *fKaiserSinc = NULL;
+float *fDownSample1 = NULL;
+float *fDownSample2 = NULL;
-/* Code taken from the OpenMPT project, which has a BSD
-** license which is compatible with this this project.
-**
-** The code has been slightly modified.
-*/
-
static double Izero(double y) // Compute Bessel function Izero(y) using a series approximation
{
double s = 1.0, ds = 1.0, d = 0.0;
@@ -32,7 +32,7 @@
return s;
}
-static void getSinc(double *dLUTPtr, const double beta, const double cutoff)
+static void getSinc(float *fLUTPtr, const double beta, const double cutoff)
{
const double izeroBeta = Izero(beta);
const double kPi = 4.0 * atan(1.0) * cutoff; // M_PI can't be trusted
@@ -56,23 +56,22 @@
dSinc = sin(xPi) * Izero(beta * sqrt(1.0 - x * x * xMul)) / (izeroBeta * xPi); // Kaiser window
}
- dLUTPtr[i] = dSinc * cutoff;
+ fLUTPtr[i] = (float)(dSinc * cutoff);
}
}
bool calcWindowedSincTables(void)
{
- gKaiserSinc = (double *)malloc(SINC_LUT_LEN * sizeof (double));
- gDownSample1 = (double *)malloc(SINC_LUT_LEN * sizeof (double));
- gDownSample2 = (double *)malloc(SINC_LUT_LEN * sizeof (double));
+ fKaiserSinc = (float *)malloc(SINC_LUT_LEN * sizeof (float));
+ fDownSample1 = (float *)malloc(SINC_LUT_LEN * sizeof (float));
+ fDownSample2 = (float *)malloc(SINC_LUT_LEN * sizeof (float));
- if (gKaiserSinc == NULL || gDownSample1 == NULL || gDownSample2 == NULL)
+ if (fKaiserSinc == NULL || fDownSample1 == NULL || fDownSample2 == NULL)
return false;
- // OpenMPT parameters
- getSinc(gKaiserSinc, 9.6377, 0.97);
- getSinc(gDownSample1, 8.5, 0.5);
- getSinc(gDownSample2, 2.7625, 0.425);
+ getSinc(fKaiserSinc, 9.6377, 0.97);
+ getSinc(fDownSample1, 8.5, 0.5);
+ getSinc(fDownSample2, 2.7625, 0.425);
return true;
}
@@ -79,21 +78,21 @@
void freeWindowedSincTables(void)
{
- if (gKaiserSinc != NULL)
+ if (fKaiserSinc != NULL)
{
- free(gKaiserSinc);
- gKaiserSinc = NULL;
+ free(fKaiserSinc);
+ fKaiserSinc = NULL;
}
- if (gDownSample1 != NULL)
+ if (fDownSample1 != NULL)
{
- free(gDownSample1);
- gDownSample1 = NULL;
+ free(fDownSample1);
+ fDownSample1 = NULL;
}
- if (gDownSample2 != NULL)
+ if (fDownSample2 != NULL)
{
- free(gDownSample2);
- gDownSample2 = NULL;
+ free(fDownSample2);
+ fDownSample2 = NULL;
}
}
--- a/src/mixer/ft2_windowed_sinc.h
+++ b/src/mixer/ft2_windowed_sinc.h
@@ -2,15 +2,12 @@
#include <stdint.h>
#include <stdbool.h>
+#include "ft2_mix.h"
-#ifndef MIXER_FRAC_BITS
-#define MIXER_FRAC_BITS 32
-#endif
+// if you change this, also change SINC_PHASES_BITS (>8192 gives very little improvement)
+#define SINC_PHASES 8192
+#define SINC_PHASES_BITS 13 /* log2(SINC_PHASES) */
-// if you change this, also change SINC_PHASES_BITS (>4096 makes little sense)
-#define SINC_PHASES 4096
-#define SINC_PHASES_BITS 12 /* log2(SINC_PHASES) */
-
// don't change these!
#define SINC_TAPS 8
@@ -19,6 +16,7 @@
#define SINC_FSHIFT (MIXER_FRAC_BITS-(SINC_PHASES_BITS+SINC_TAPS_BITS))
#define SINC_FMASK ((SINC_TAPS*SINC_PHASES)-SINC_TAPS)
+#define SINC_CENTER_TAP (SINC_TAPS/2)
#define SINC_LEFT_TAPS ((SINC_TAPS/2)-1)
#define SINC_RIGHT_TAPS (SINC_TAPS/2)
@@ -25,9 +23,9 @@
// for LUT calculation
#define SINC_MID_TAP ((SINC_TAPS/2)*SINC_PHASES)
-extern double *gKaiserSinc;
-extern double *gDownSample1;
-extern double *gDownSample2;
+extern float *fKaiserSinc;
+extern float *fDownSample1;
+extern float *fDownSample2;
bool calcWindowedSincTables(void);
void freeWindowedSincTables(void);
--- a/src/modloaders/ft2_load_digi.c
+++ b/src/modloaders/ft2_load_digi.c
@@ -1,4 +1,8 @@
-// DIGI Booster (non-Pro) module loader
+/* DIGI Booster (non-Pro) module loader
+**
+** Note: Data sanitation is done in the last stage
+** of module loading, so you don't need to do that here.
+*/
#include <stdio.h>
#include <stdint.h>
@@ -13,15 +17,15 @@
#pragma pack(push)
#pragma pack(1)
#endif
-typedef struct digiHeaderTyp_t
+typedef struct digiHdr_t
{
- char sig[20];
+ char ID[20];
char verStr[4];
- uint8_t ver;
+ uint8_t version;
uint8_t numChannels;
uint8_t packedPatternsFlag;
char reserved[19];
- uint8_t numPats;
+ uint8_t numPatterns;
uint8_t numOrders;
uint8_t orders[128];
uint32_t smpLength[31];
@@ -35,58 +39,58 @@
#ifdef __GNUC__
__attribute__ ((packed))
#endif
-digiHeaderTyp;
+digiHdr_t;
#ifdef _MSC_VER
#pragma pack(pop)
#endif
-static void readPatternNote(FILE *f, tonTyp *ton);
+static void readPatternNote(FILE *f, note_t *p);
bool loadDIGI(FILE *f, uint32_t filesize)
{
int16_t i, j, k;
- tonTyp *ton;
- sampleTyp *s;
- digiHeaderTyp h_DIGI;
+ sample_t *s;
+ digiHdr_t hdr;
tmpLinearPeriodsFlag = false; // use Amiga periods
- if (filesize < sizeof (h_DIGI))
+ if (filesize < sizeof (hdr))
{
loaderMsgBox("Error: This file is either not a module, or is not supported.");
return false;
}
- memset(&h_DIGI, 0, sizeof (digiHeaderTyp));
- if (fread(&h_DIGI, 1, sizeof (h_DIGI), f) != sizeof (h_DIGI))
+ memset(&hdr, 0, sizeof (hdr));
+ if (fread(&hdr, 1, sizeof (hdr), f) != sizeof (hdr))
{
loaderMsgBox("Error: This file is either not a module, or is not supported.");
return false;
}
- if (h_DIGI.numChannels < 1 || h_DIGI.numChannels > 8)
+ if (hdr.numChannels < 1 || hdr.numChannels > 8)
{
loaderMsgBox("Error: This file is either not a module, or is not supported.");
return false;
}
- h_DIGI.numOrders++;
- h_DIGI.numPats++;
+ hdr.numOrders++;
+ hdr.numPatterns++;
- if (h_DIGI.numOrders < 1 || h_DIGI.numOrders > 128)
+ if (hdr.numOrders < 1 || hdr.numOrders > 128)
{
loaderMsgBox("Error: This file is either not a module, or is not supported.");
return false;
}
- songTmp.antChn = h_DIGI.numChannels;
- songTmp.len = h_DIGI.numOrders;
- songTmp.initialTempo = songTmp.tempo = 6;
- songTmp.speed = 125;
- memcpy(songTmp.songTab, h_DIGI.orders, 128);
+ memcpy(songTmp.orders, hdr.orders, 128);
+ songTmp.numChannels = hdr.numChannels;
+ songTmp.songLength = hdr.numOrders;
+ songTmp.BPM = 125;
+ songTmp.speed = 6;
+
// load pattern data
- for (i = 0; i < h_DIGI.numPats; i++)
+ for (i = 0; i < hdr.numPatterns; i++)
{
if (!allocateTmpPatt(i, 64))
{
@@ -94,7 +98,7 @@
return false;
}
- if (h_DIGI.packedPatternsFlag)
+ if (hdr.packedPatternsFlag)
{
uint16_t pattSize;
uint8_t bitMasks[64];
@@ -105,61 +109,58 @@
for (j = 0; j < 64; j++)
{
uint8_t bit = 128;
- for (k = 0; k < songTmp.antChn; k++, bit >>= 1)
+ for (k = 0; k < songTmp.numChannels; k++, bit >>= 1)
{
- ton = &pattTmp[i][(j * MAX_VOICES) + k];
+ note_t *p = &patternTmp[i][(j * MAX_CHANNELS) + k];
if (bitMasks[j] & bit)
- readPatternNote(f, ton);
+ readPatternNote(f, p);
}
}
}
else
{
- for (j = 0; j < songTmp.antChn; j++)
+ for (j = 0; j < songTmp.numChannels; j++)
{
for (k = 0; k < 64; k++)
- {
- ton = &pattTmp[i][(k * MAX_VOICES) + j];
- readPatternNote(f, ton);
- }
+ readPatternNote(f, &patternTmp[i][(k * MAX_CHANNELS) + j]);
}
}
if (tmpPatternEmpty(i))
{
- if (pattTmp[i] != NULL)
+ if (patternTmp[i] != NULL)
{
- free(pattTmp[i]);
- pattTmp[i] = NULL;
+ free(patternTmp[i]);
+ patternTmp[i] = NULL;
}
}
}
// pattern command handling
- for (i = 0; i < h_DIGI.numPats; i++)
+ for (i = 0; i < hdr.numPatterns; i++)
{
- if (pattTmp[i] == NULL)
+ if (patternTmp[i] == NULL)
continue;
for (j = 0; j < 64; j++)
{
- for (k = 0; k < songTmp.antChn; k++)
+ for (k = 0; k < songTmp.numChannels; k++)
{
- ton = &pattTmp[i][(j * MAX_VOICES) + k];
+ note_t *p = &patternTmp[i][(j * MAX_CHANNELS) + k];
- if (ton->effTyp == 0x8) // Robot effect (not supported)
+ if (p->efx == 0x8) // Robot effect (not supported)
{
- ton->effTyp = 0;
- ton->eff = 0;
+ p->efx = 0;
+ p->efxData = 0;
}
- else if (ton->effTyp == 0xE)
+ else if (p->efx == 0xE)
{
- switch (ton->eff >> 4)
+ switch (p->efxData >> 4)
{
- case 0x3: ton->effTyp = ton->eff = 0; break; // backwards play (not supported)
- case 0x4: ton->eff = 0xC0; break; // stop sample (convert to EC0)
- case 0x8: ton->effTyp = ton->eff = 0; break; // high sample offset (not supported)
- case 0x9: ton->effTyp = ton->eff = 0; break; // retrace (not supported)
+ case 0x3: p->efx = p->efxData = 0; break; // backwards play (not supported)
+ case 0x4: p->efxData = 0xC0; break; // stop sample (convert to EC0)
+ case 0x8: p->efx = p->efxData = 0; break; // high sample offset (not supported)
+ case 0x9: p->efx = p->efxData = 0; break; // retrace (not supported)
default: break;
}
}
@@ -170,8 +171,8 @@
// load sample data
for (i = 0; i < 31; i++)
{
- memcpy(songTmp.instrName[1+i], h_DIGI.smpName[i], 22);
- if (h_DIGI.smpLength[i] == 0)
+ memcpy(songTmp.instrName[1+i], hdr.smpName[i], 22);
+ if (hdr.smpLength[i] == 0)
continue;
if (!allocateTmpInstr(1+i))
@@ -182,56 +183,53 @@
setNoEnvelope(instrTmp[1+i]);
- s = &instrTmp[1+i]->samp[0];
- memcpy(s->name, h_DIGI.smpName[i], 22);
+ s = &instrTmp[1+i]->smp[0];
+ memcpy(s->name, hdr.smpName[i], 22);
- s->len = SWAP32(h_DIGI.smpLength[i]);
- s->fine = 8 * ((2 * ((h_DIGI.smpFinetune[i] & 0xF) ^ 8)) - 16);
- s->vol = h_DIGI.smpVolume[i];
- s->repS = SWAP32(h_DIGI.smpLoopStart[i]);
- s->repL = SWAP32(h_DIGI.smpLoopLength[i]);
+ s->length = SWAP32(hdr.smpLength[i]);
+ s->finetune = FINETUNE_MOD2XM(hdr.smpFinetune[i]);
+ s->volume = hdr.smpVolume[i];
+ s->loopStart = SWAP32(hdr.smpLoopStart[i]);
+ s->loopLength = SWAP32(hdr.smpLoopLength[i]);
- if (s->vol > 64)
- s->vol = 64;
+ if (s->loopLength < 2)
+ s->loopLength = 2;
- if (s->repL < 2)
- s->repL = 2;
-
// fix overflown loop
- if (s->repS+s->repL > s->len)
+ if (s->loopStart+s->loopLength > s->length)
{
- if (s->repS >= s->len)
+ if (s->loopStart >= s->length)
{
- s->repS = 0;
- s->repL = 0;
+ s->loopStart = 0;
+ s->loopLength = 0;
}
else
{
- s->repL = s->len - s->repS;
+ s->loopLength = s->length - s->loopStart;
}
}
- if (s->repS+s->repL > 2)
+ if (s->loopStart+s->loopLength > 2)
{
- s->typ = 1; // enable loop
+ s->flags |= LOOP_FWD; // enable loop
}
else
{
- s->repS = 0;
- s->repL = 0;
+ s->loopStart = 0;
+ s->loopLength = 0;
}
- if (!allocateTmpSmpData(s, s->len))
+ if (!allocateSmpData(s, s->length, false))
{
loaderMsgBox("Not enough memory!");
return false;
}
- int32_t bytesRead = (int32_t)fread(s->pek, 1, s->len, f);
- if (bytesRead < s->len)
+ int32_t bytesRead = (int32_t)fread(s->dataPtr, 1, s->length, f);
+ if (bytesRead < s->length)
{
- int32_t bytesToClear = s->len - bytesRead;
- memset(&s->pek[bytesRead], 0, bytesToClear);
+ int32_t bytesToClear = s->length - bytesRead;
+ memset(&s->dataPtr[bytesRead], 0, bytesToClear);
}
}
@@ -238,7 +236,7 @@
return true;
}
-static void readPatternNote(FILE *f, tonTyp *ton)
+static void readPatternNote(FILE *f, note_t *p)
{
uint8_t bytes[4];
fread(bytes, 1, 4, f);
@@ -249,12 +247,12 @@
{
if (period >= ptPeriods[i])
{
- ton->ton = 1 + (3*12) + i;
+ p->note = 1 + (3*12) + i;
break;
}
}
- ton->instr = (bytes[0] & 0xF0) | (bytes[2] >> 4);
- ton->effTyp = bytes[2] & 0x0F;
- ton->eff = bytes[3];
+ p->instr = (bytes[0] & 0xF0) | (bytes[2] >> 4);
+ p->efx = bytes[2] & 0x0F;
+ p->efxData = bytes[3];
}
--- a/src/modloaders/ft2_load_mod.c
+++ b/src/modloaders/ft2_load_mod.c
@@ -1,4 +1,8 @@
-// NoiseTracker/ProTracker (or compatible) MOD loader
+/* NoiseTracker/ProTracker (or compatible) MOD loader
+**
+** Note: Data sanitation is done in the last stage
+** of module loading, so you don't need to do that here.
+*/
#include <stdio.h>
#include <stdint.h>
@@ -27,27 +31,26 @@
{
uint8_t bytes[4], modFormat, numChannels;
int16_t i, j, k;
- uint16_t a, b, period;
- tonTyp *ton;
- sampleTyp *s;
- songMOD31HeaderTyp h_MOD31;
+ uint16_t a, b;
+ sample_t *s;
+ modHdr_t hdr;
tmpLinearPeriodsFlag = false; // use Amiga periods
- if (filesize < sizeof (h_MOD31))
+ if (filesize < sizeof (hdr))
{
loaderMsgBox("Error: This file is either not a module, or is not supported.");
return false;
}
- memset(&h_MOD31, 0, sizeof (songMOD31HeaderTyp));
- if (fread(&h_MOD31, 1, sizeof (h_MOD31), f) != sizeof (h_MOD31))
+ memset(&hdr, 0, sizeof (hdr));
+ if (fread(&hdr, 1, sizeof (hdr), f) != sizeof (hdr))
{
loaderMsgBox("Error: This file is either not a module, or is not supported.");
return false;
}
- modFormat = getModType(&numChannels, h_MOD31.sig);
+ modFormat = getModType(&numChannels, hdr.ID);
if (modFormat == FORMAT_UNKNOWN)
{
loaderMsgBox("Error: This file is either not a module, or is not supported.");
@@ -54,38 +57,35 @@
return false;
}
- bool hasMoreThan32Chans = numChannels > 32;
+ if (modFormat == FORMAT_MK && hdr.numOrders == 129)
+ hdr.numOrders = 127; // fixes a specific copy of beatwave.mod (FIXME: Do we want to keep this hack?)
- songTmp.antChn = hasMoreThan32Chans ? 32 : numChannels;
- songTmp.len = h_MOD31.len;
- songTmp.repS = h_MOD31.repS;
- songTmp.initialTempo = songTmp.tempo = 6;
- songTmp.speed = 125;
-
- memcpy(songTmp.songTab, h_MOD31.songTab, 128);
-
- if (modFormat == FORMAT_MK && songTmp.len == 129)
- songTmp.len = 127; // fixes a specific copy of beatwave.mod (FIXME: Do we want to keep this hack?)
-
- if (songTmp.repS >= songTmp.len)
- songTmp.repS = 0;
-
- if (songTmp.antChn == 0 || songTmp.len < 1 || songTmp.len > 128)
+ if (numChannels == 0 || hdr.numOrders < 1 || hdr.numOrders > 128)
{
loaderMsgBox("Error: This file is either not a module, or is not supported.");
return false;
}
+ bool tooManyChannels = numChannels > MAX_CHANNELS;
+
+ songTmp.numChannels = tooManyChannels ? MAX_CHANNELS : numChannels;
+ songTmp.songLength = hdr.numOrders;
+ songTmp.songLoopStart = hdr.songLoopStart;
+ songTmp.BPM = 125;
+ songTmp.speed = 6;
+
+ memcpy(songTmp.orders, hdr.orders, 128);
+
for (a = 0; a < 31; a++)
{
- songMODInstrHeaderTyp *smp = &h_MOD31.instr[a];
+ modSmpHdr_t *modSmp = &hdr.smp[a];
// copy over sample name if format isn't "His Master's Noisetracker" (junk sample names)
if (modFormat != FORMAT_HMNT)
- memcpy(songTmp.instrName[1+a], smp->name, 22);
+ memcpy(songTmp.instrName[1+a], modSmp->name, 22);
}
- memcpy(songTmp.name, h_MOD31.name, 20);
+ memcpy(songTmp.name, hdr.name, 20);
// count number of patterns
b = 0;
@@ -92,10 +92,10 @@
for (a = 0; a < 128; a++)
{
if (modFormat == FORMAT_FLT8)
- songTmp.songTab[a] >>= 1;
+ songTmp.orders[a] >>= 1;
- if (songTmp.songTab[a] > b)
- b = songTmp.songTab[a];
+ if (songTmp.orders[a] > b)
+ b = songTmp.orders[a];
}
b++;
@@ -114,30 +114,30 @@
for (j = 0; j < 64; j++)
{
- for (k = 0; k < songTmp.antChn; k++)
+ for (k = 0; k < songTmp.numChannels; k++)
{
- ton = &pattTmp[a][(j * MAX_VOICES) + k];
+ note_t *p = &patternTmp[a][(j * MAX_CHANNELS) + k];
fread(bytes, 1, 4, f);
// period to note
- period = ((bytes[0] & 0x0F) << 8) | bytes[1];
+ uint16_t period = ((bytes[0] & 0x0F) << 8) | bytes[1];
for (i = 0; i < 8*12; i++)
{
if (period >= amigaPeriod[i])
{
- ton->ton = (uint8_t)i + 1;
+ p->note = (uint8_t)i + 1;
break;
}
}
- ton->instr = (bytes[0] & 0xF0) | (bytes[2] >> 4);
- ton->effTyp = bytes[2] & 0x0F;
- ton->eff = bytes[3];
+ p->instr = (bytes[0] & 0xF0) | (bytes[2] >> 4);
+ p->efx = bytes[2] & 0x0F;
+ p->efxData = bytes[3];
}
- if (hasMoreThan32Chans)
+ if (tooManyChannels)
{
- int32_t remainingChans = numChannels-songTmp.antChn;
+ int32_t remainingChans = numChannels-songTmp.numChannels;
fseek(f, remainingChans*4, SEEK_CUR);
}
}
@@ -144,10 +144,10 @@
if (tmpPatternEmpty(a))
{
- if (pattTmp[a] != NULL)
+ if (patternTmp[a] != NULL)
{
- free(pattTmp[a]);
- pattTmp[a] = NULL;
+ free(patternTmp[a]);
+ patternTmp[a] = NULL;
}
}
}
@@ -167,7 +167,7 @@
for (a = 0; a < b*2; a++)
{
- int32_t pattern = a >> 1;
+ int32_t pattNum = a >> 1;
int32_t chnOffset = (a & 1) * 4;
for (j = 0; j < 64; j++)
@@ -174,23 +174,23 @@
{
for (k = 0; k < 4; k++)
{
- ton = &pattTmp[pattern][(j * MAX_VOICES) + (k+chnOffset)];
+ note_t *p = &patternTmp[pattNum][(j * MAX_CHANNELS) + (k+chnOffset)];
fread(bytes, 1, 4, f);
// period to note
- period = ((bytes[0] & 0x0F) << 8) | bytes[1];
+ uint16_t period = ((bytes[0] & 0x0F) << 8) | bytes[1];
for (i = 0; i < 8*12; i++)
{
if (period >= amigaPeriod[i])
{
- ton->ton = (uint8_t)i + 1;
+ p->note = (uint8_t)i + 1;
break;
}
}
- ton->instr = (bytes[0] & 0xF0) | (bytes[2] >> 4);
- ton->effTyp = bytes[2] & 0x0F;
- ton->eff = bytes[3];
+ p->instr = (bytes[0] & 0xF0) | (bytes[2] >> 4);
+ p->efx = bytes[2] & 0x0F;
+ p->efxData = bytes[3];
}
}
}
@@ -199,10 +199,10 @@
{
if (tmpPatternEmpty(a))
{
- if (pattTmp[a] != NULL)
+ if (patternTmp[a] != NULL)
{
- free(pattTmp[a]);
- pattTmp[a] = NULL;
+ free(patternTmp[a]);
+ patternTmp[a] = NULL;
}
}
}
@@ -211,52 +211,52 @@
// pattern command conversion
for (a = 0; a < b; a++)
{
- if (pattTmp[a] == NULL)
+ if (patternTmp[a] == NULL)
continue;
for (j = 0; j < 64; j++)
{
- for (k = 0; k < songTmp.antChn; k++)
+ for (k = 0; k < songTmp.numChannels; k++)
{
- ton = &pattTmp[a][(j * MAX_VOICES) + k];
+ note_t *p = &patternTmp[a][(j * MAX_CHANNELS) + k];
- if (ton->effTyp == 0xC)
+ if (p->efx == 0xC)
{
- if (ton->eff > 64)
- ton->eff = 64;
+ if (p->efxData > 64)
+ p->efxData = 64;
}
- else if (ton->effTyp == 0x1)
+ else if (p->efx == 0x1)
{
- if (ton->eff == 0)
- ton->effTyp = 0;
+ if (p->efxData == 0)
+ p->efx = 0;
}
- else if (ton->effTyp == 0x2)
+ else if (p->efx == 0x2)
{
- if (ton->eff == 0)
- ton->effTyp = 0;
+ if (p->efxData == 0)
+ p->efx = 0;
}
- else if (ton->effTyp == 0x5)
+ else if (p->efx == 0x5)
{
- if (ton->eff == 0)
- ton->effTyp = 0x3;
+ if (p->efxData == 0)
+ p->efx = 0x3;
}
- else if (ton->effTyp == 0x6)
+ else if (p->efx == 0x6)
{
- if (ton->eff == 0)
- ton->effTyp = 0x4;
+ if (p->efxData == 0)
+ p->efx = 0x4;
}
- else if (ton->effTyp == 0xA)
+ else if (p->efx == 0xA)
{
- if (ton->eff == 0)
- ton->effTyp = 0;
+ if (p->efxData == 0)
+ p->efx = 0;
}
- else if (ton->effTyp == 0xE)
+ else if (p->efx == 0xE)
{
// check if certain E commands are empty
- if (ton->eff == 0x10 || ton->eff == 0x20 || ton->eff == 0xA0 || ton->eff == 0xB0)
+ if (p->efxData == 0x10 || p->efxData == 0x20 || p->efxData == 0xA0 || p->efxData == 0xB0)
{
- ton->effTyp = 0;
- ton->eff = 0;
+ p->efx = 0;
+ p->efxData = 0;
}
}
@@ -263,24 +263,24 @@
if (modFormat == FORMAT_NT || modFormat == FORMAT_HMNT)
{
// any Dxx == D00 in NT/HMNT
- if (ton->effTyp == 0xD)
- ton->eff = 0;
+ if (p->efx == 0xD)
+ p->efxData = 0;
// effect F with param 0x00 does nothing in NT/HMNT
- if (ton->effTyp == 0xF && ton->eff == 0)
- ton->effTyp = 0;
+ if (p->efx == 0xF && p->efxData == 0)
+ p->efx = 0;
}
else if (modFormat == FORMAT_FLT4 || modFormat == FORMAT_FLT8) // Startrekker
{
- if (ton->effTyp == 0xE) // remove unsupported "assembly macros" command
+ if (p->efx == 0xE) // remove unsupported "assembly macros" command
{
- ton->effTyp = 0;
- ton->eff = 0;
+ p->efx = 0;
+ p->efxData = 0;
}
// Startrekker is always in vblank mode, and limits speed to 0x1F
- if (ton->effTyp == 0xF && ton->eff > 0x1F)
- ton->eff = 0x1F;
+ if (p->efx == 0xF && p->efxData > 0x1F)
+ p->efxData = 0x1F;
}
}
}
@@ -288,7 +288,7 @@
for (a = 0; a < 31; a++)
{
- if (h_MOD31.instr[a].len == 0)
+ if (hdr.smp[a].length == 0)
continue;
if (!allocateTmpInstr(1+a))
@@ -299,7 +299,7 @@
setNoEnvelope(instrTmp[1+a]);
- s = &instrTmp[1+a]->samp[0];
+ s = &instrTmp[1+a]->smp[0];
// copy over sample name if format isn't "His Master's Noisetracker" (junk sample names)
if (modFormat != FORMAT_HMNT)
@@ -306,65 +306,62 @@
memcpy(s->name, songTmp.instrName[1+a], 22);
if (modFormat == FORMAT_HMNT) // finetune in "His Master's NoiseTracker" is different
- h_MOD31.instr[a].fine = (uint8_t)((-h_MOD31.instr[a].fine & 0x1F) >> 1); // one more bit of precision, + inverted
+ hdr.smp[a].finetune = (uint8_t)((-hdr.smp[a].finetune & 0x1F) >> 1); // one more bit of precision, + inverted
- s->len = 2 * SWAP16(h_MOD31.instr[a].len);
- s->fine = 8 * ((2 * ((h_MOD31.instr[a].fine & 0xF) ^ 8)) - 16);
- s->vol = h_MOD31.instr[a].vol;
- s->repS = 2 * SWAP16(h_MOD31.instr[a].repS);
- s->repL = 2 * SWAP16(h_MOD31.instr[a].repL);
+ s->length = 2 * SWAP16(hdr.smp[a].length);
+ s->finetune = FINETUNE_MOD2XM(hdr.smp[a].finetune);
+ s->volume = hdr.smp[a].volume;
+ s->loopStart = 2 * SWAP16(hdr.smp[a].loopStart);
+ s->loopLength = 2 * SWAP16(hdr.smp[a].loopLength);
- if (s->vol > 64)
- s->vol = 64;
+ if (s->loopLength < 2)
+ s->loopLength = 2;
- if (s->repL < 2)
- s->repL = 2;
-
// fix for poorly converted STK (< v2.5) -> PT/NT modules (FIXME: Worth keeping or not?)
- if (s->repL > 2 && s->repS+s->repL > s->len)
+ if (s->loopLength > 2 && s->loopStart+s->loopLength > s->length)
{
- if ((s->repS>>1)+s->repL <= s->len)
- s->repS >>= 1;
+ if ((s->loopStart >> 1) + s->loopLength <= s->length)
+ s->loopStart >>= 1;
}
// fix overflown loop
- if (s->repS+s->repL > s->len)
+ if (s->loopStart+s->loopLength > s->length)
{
- if (s->repS >= s->len)
+ if (s->loopStart >= s->length)
{
- s->repS = 0;
- s->repL = 0;
+ s->loopStart = 0;
+ s->loopLength = 0;
}
else
{
- s->repL = s->len - s->repS;
+ s->loopLength = s->length - s->loopStart;
}
}
- if (s->repS+s->repL > 2)
- s->typ = 1; // enable loop
+ if (s->loopStart+s->loopLength > 2)
+ s->flags |= LOOP_FWD; // enable loop
- if (!allocateTmpSmpData(s, s->len))
+ if (!allocateSmpData(s, s->length, false))
{
loaderMsgBox("Not enough memory!");
return false;
}
- int32_t bytesRead = (int32_t)fread(s->pek, 1, s->len, f);
- if (bytesRead < s->len)
+ int32_t bytesRead = (int32_t)fread(s->dataPtr, 1, s->length, f);
+ if (bytesRead < s->length)
{
- int32_t bytesToClear = s->len - bytesRead;
- memset(&s->pek[bytesRead], 0, bytesToClear);
+ int32_t bytesToClear = s->length - bytesRead;
+ memset(&s->dataPtr[bytesRead], 0, bytesToClear);
}
- if (s->typ == 0) // clear repL and repS on non-looping samples...
+ if (GET_LOOPTYPE(s->flags) == LOOP_OFF) // clear loopLength and loopStart on non-looping samples...
{
- s->repL = 0;
- s->repS = 0;
+ s->loopLength = 0;
+ s->loopStart = 0;
}
}
- if (hasMoreThan32Chans)
+ if (tooManyChannels)
loaderMsgBox("Warning: Module contains >32 channels. The extra channels will be discarded!");
return true;
--- a/src/modloaders/ft2_load_s3m.c
+++ b/src/modloaders/ft2_load_s3m.c
@@ -1,4 +1,8 @@
-// Scream Tracker 3 (or compatible) S3M loader
+/* Scream Tracker 3 (or compatible) S3M loader
+**
+** Note: Data sanitation is done in the last stage
+** of module loading, so you don't need to do that here.
+*/
#include <stdio.h>
#include <stdint.h>
@@ -13,38 +17,36 @@
#pragma pack(push)
#pragma pack(1)
#endif
-typedef struct songS3MinstrHeaderTyp_t
+typedef struct s3mSmpHdr_t
{
- uint8_t typ;
- char dosName[12];
- uint8_t memSegH;
- uint16_t memSeg;
- int32_t len, repS, repE;
- uint8_t vol, dsk, pack, flags;
- int32_t c2Spd, res1;
- uint16_t gusPos;
- uint8_t res2[6];
- char name[28], id[4];
+ uint8_t type, junk1[12], offsetInFileH;
+ uint16_t offsetInFile;
+ int32_t length, loopStart, loopEnd;
+ uint8_t volume, junk2, packFlag, flags;
+ int32_t midCFreq, junk3;
+ uint16_t junk4;
+ uint8_t junk5[6];
+ char name[28], ID[4];
}
#ifdef __GNUC__
__attribute__ ((packed))
#endif
-songS3MinstrHeaderTyp;
+s3mSmpHdr_t;
-typedef struct songS3MHeaderTyp_t
+typedef struct s3mHdr_t
{
char name[28];
- uint8_t id1a, typ;
- uint16_t res1;
- int16_t songTabLen, antInstr, antPatt;
- uint16_t flags, trackerID, ver;
- char id[4];
- uint8_t globalVol, defSpeed, defTempo, masterVol, res2[12], chanType[32];
+ uint8_t junk1, type;
+ uint16_t junk2;
+ int16_t numOrders, numSamples, numPatterns;
+ uint16_t flags, junk3, version;
+ char ID[4];
+ uint8_t junk4, speed, BPM, junk5, junk6[12], chnSettings[32];
}
#ifdef __GNUC__
__attribute__ ((packed))
#endif
-songS3MHeaderTyp;
+s3mHdr_t;
#ifdef _MSC_VER
#pragma pack(pop)
#endif
@@ -55,117 +57,111 @@
bool loadS3M(FILE *f, uint32_t filesize)
{
- uint8_t ha[2048];
uint8_t alastnfo[32], alastefx[32], alastvibnfo[32], s3mLastGInstr[32];
- uint8_t typ;
- int16_t ai, ap, ver, ii, kk, tmp;
- uint16_t ptnOfs[256];
- int32_t i, j, k, len;
- tonTyp ton;
- sampleTyp *s;
- songS3MHeaderTyp h_S3M;
- songS3MinstrHeaderTyp h_S3MInstr;
+ int16_t ii, kk, tmp;
+ int32_t patternOffsets[256], sampleOffsets[256], j, k;
+ note_t tmpNote;
+ sample_t *s;
+ s3mHdr_t hdr;
+ s3mSmpHdr_t smpHdr;
tmpLinearPeriodsFlag = false; // use Amiga periods
- if (filesize < sizeof (h_S3M))
+ if (filesize < sizeof (hdr))
{
loaderMsgBox("Error: This file is either not a module, or is not supported.");
return false;
}
- memset(&h_S3M, 0, sizeof (h_S3M));
- if (fread(&h_S3M, 1, sizeof (h_S3M), f) != sizeof (h_S3M))
+ memset(&hdr, 0, sizeof (hdr));
+ if (fread(&hdr, 1, sizeof (hdr), f) != sizeof (hdr))
{
loaderMsgBox("Error: This file is either not a module, or is not supported.");
return false;
}
- if (h_S3M.antInstr > MAX_INST || h_S3M.songTabLen > 256 || h_S3M.antPatt > 256 ||
- h_S3M.typ != 16 || h_S3M.ver < 1 || h_S3M.ver > 2)
+ if (hdr.numSamples > MAX_INST || hdr.numOrders > MAX_ORDERS || hdr.numPatterns > MAX_PATTERNS ||
+ hdr.type != 16 || hdr.version < 1 || hdr.version > 2)
{
loaderMsgBox("Error loading .s3m: Incompatible module!");
return false;
}
- memset(songTmp.songTab, 255, sizeof (songTmp.songTab));
- if (fread(songTmp.songTab, h_S3M.songTabLen, 1, f) != 1)
+ memset(songTmp.orders, 255, 256); // pad by 255
+ if (fread(songTmp.orders, hdr.numOrders, 1, f) != 1)
{
loaderMsgBox("General I/O error during loading! Is the file in use?");
return false;
}
- songTmp.len = h_S3M.songTabLen;
+ songTmp.songLength = hdr.numOrders;
// remove pattern separators (254)
k = 0;
j = 0;
- for (i = 0; i < songTmp.len; i++)
+ for (int32_t i = 0; i < songTmp.songLength; i++)
{
- if (songTmp.songTab[i] != 254)
- songTmp.songTab[j++] = songTmp.songTab[i];
+ if (songTmp.orders[i] != 254)
+ songTmp.orders[j++] = songTmp.orders[i];
else
k++;
}
- if (k <= songTmp.len)
- songTmp.len -= (uint16_t)k;
+ if (k <= songTmp.songLength)
+ songTmp.songLength -= (uint16_t)k;
else
- songTmp.len = 1;
+ songTmp.songLength = 1;
- for (i = 1; i < songTmp.len; i++)
+ for (int32_t i = 1; i < songTmp.songLength; i++)
{
- if (songTmp.songTab[i] == 255)
+ if (songTmp.orders[i] == 255)
{
- songTmp.len = (uint16_t)i;
+ songTmp.songLength = (uint16_t)i;
break;
}
}
// clear unused song table entries
- if (songTmp.len < 255)
- memset(&songTmp.songTab[songTmp.len], 0, 255-songTmp.len);
+ if (songTmp.songLength < 255)
+ memset(&songTmp.orders[songTmp.songLength], 0, 255-songTmp.songLength);
- songTmp.speed = h_S3M.defTempo;
- if (songTmp.speed < 32)
- songTmp.speed = 32;
+ memcpy(songTmp.name, hdr.name, 20);
- songTmp.tempo = h_S3M.defSpeed;
- if (songTmp.tempo == 0)
- songTmp.tempo = 6;
+ songTmp.BPM = hdr.BPM;
+ songTmp.speed = hdr.speed;
- if (songTmp.tempo > 31)
- songTmp.tempo = 31;
-
- songTmp.initialTempo = songTmp.tempo;
- memcpy(songTmp.name, h_S3M.name, 20);
-
- ap = h_S3M.antPatt;
- ai = h_S3M.antInstr;
- ver = h_S3M.ver;
-
- k = 31;
- while (k >= 0 && h_S3M.chanType[k] >= 16) k--;
- songTmp.antChn = (k + 2) & 254;
-
- if (fread(ha, ai*2, 1, f) != 1)
+ // load sample offsets
+ for (int32_t i = 0; i < hdr.numSamples; i++)
{
- loaderMsgBox("General I/O error during loading! Is the file in use?");
- return false;
+ uint16_t offset;
+ if (fread(&offset, 2, 1, f) != 1)
+ {
+ loaderMsgBox("General I/O error during loading! Is the file in use?");
+ return false;
+ }
+
+ sampleOffsets[i] = offset << 4;
}
- if (fread(ptnOfs, ap*2, 1, f) != 1)
+ // load pattern offsets
+ for (int32_t i = 0; i < hdr.numPatterns; i++)
{
- loaderMsgBox("General I/O error during loading! Is the file in use?");
- return false;
+ uint16_t offset;
+ if (fread(&offset, 2, 1, f) != 1)
+ {
+ loaderMsgBox("General I/O error during loading! Is the file in use?");
+ return false;
+ }
+
+ patternOffsets[i] = offset << 4;
}
// *** PATTERNS ***
k = 0;
- for (i = 0; i < ap; i++)
+ for (int32_t i = 0; i < hdr.numPatterns; i++)
{
- if (ptnOfs[i] == 0)
+ if (patternOffsets[i] == 0)
continue; // empty pattern
memset(alastnfo, 0, sizeof (alastnfo));
@@ -173,7 +169,7 @@
memset(alastvibnfo, 0, sizeof (alastvibnfo));
memset(s3mLastGInstr, 0, sizeof (s3mLastGInstr));
- fseek(f, ptnOfs[i] << 4, SEEK_SET);
+ fseek(f, patternOffsets[i], SEEK_SET);
if (feof(f))
continue;
@@ -198,69 +194,69 @@
while (k < j && kk < 64)
{
- typ = pattBuff[k++];
+ uint8_t bits = pattBuff[k++];
- if (typ == 0)
+ if (bits == 0)
{
kk++;
}
else
{
- ii = typ & 31;
+ ii = bits & 31;
- memset(&ton, 0, sizeof (ton));
+ memset(&tmpNote, 0, sizeof (tmpNote));
// note and sample
- if (typ & 32)
+ if (bits & 32)
{
- ton.ton = pattBuff[k++];
- ton.instr = pattBuff[k++];
+ tmpNote.note = pattBuff[k++];
+ tmpNote.instr = pattBuff[k++];
- if (ton.instr > MAX_INST)
- ton.instr = 0;
+ if (tmpNote.instr > MAX_INST)
+ tmpNote.instr = 0;
- if (ton.ton == 254) ton.ton = 97;
- else if (ton.ton == 255) ton.ton = 0;
+ if (tmpNote.note == 254) tmpNote.note = NOTE_OFF;
+ else if (tmpNote.note == 255) tmpNote.note = 0;
else
{
- ton.ton = 1 + (ton.ton & 0xF) + (ton.ton >> 4) * 12;
- if (ton.ton > 96)
- ton.ton = 0;
+ tmpNote.note = 1 + (tmpNote.note & 0xF) + (tmpNote.note >> 4) * 12;
+ if (tmpNote.note > 96)
+ tmpNote.note = 0;
}
}
// volume column
- if (typ & 64)
+ if (bits & 64)
{
- ton.vol = pattBuff[k++];
+ tmpNote.vol = pattBuff[k++];
- if (ton.vol <= 64)
- ton.vol += 0x10;
+ if (tmpNote.vol <= 64)
+ tmpNote.vol += 0x10;
else
- ton.vol = 0;
+ tmpNote.vol = 0;
}
// effect
- if (typ & 128)
+ if (bits & 128)
{
- ton.effTyp = pattBuff[k++];
- ton.eff = pattBuff[k++];
+ tmpNote.efx = pattBuff[k++];
+ tmpNote.efxData = pattBuff[k++];
- if (ton.eff > 0)
+ if (tmpNote.efxData > 0)
{
- alastnfo[ii] = ton.eff;
- if (ton.effTyp == 8 || ton.effTyp == 21)
- alastvibnfo[ii] = ton.eff; // H/U
+ alastnfo[ii] = tmpNote.efxData;
+ if (tmpNote.efx == 8 || tmpNote.efx == 21)
+ alastvibnfo[ii] = tmpNote.efxData; // H/U
}
// in ST3, a lot of effects directly share the same memory!
- if (ton.eff == 0 && ton.effTyp != 7) // G
+ if (tmpNote.efxData == 0 && tmpNote.efx != 7) // G
{
- uint8_t efx = ton.effTyp;
+ uint8_t efx = tmpNote.efx;
if (efx == 8 || efx == 21) // H/U
- ton.eff = alastvibnfo[ii];
+ tmpNote.efxData = alastvibnfo[ii];
else if ((efx >= 4 && efx <= 12) || (efx >= 17 && efx <= 19)) // D/E/F/I/J/K/L/Q/R/S
- ton.eff = alastnfo[ii];
+ tmpNote.efxData = alastnfo[ii];
/* If effect data is zero and effect type was the same as last one, clear out
** data if it's not J or S (those have no memory in the equivalent XM effects).
@@ -267,57 +263,57 @@
** Also goes for extra fine pitch slides and fine volume slides,
** since they get converted to other effects.
*/
- if (efx == alastefx[ii] && ton.effTyp != 10 && ton.effTyp != 19) // J/S
+ if (efx == alastefx[ii] && tmpNote.efx != 10 && tmpNote.efx != 19) // J/S
{
- uint8_t nfo = ton.eff;
+ uint8_t nfo = tmpNote.efxData;
bool extraFinePitchSlides = (efx == 5 || efx == 6) && ((nfo & 0xF0) == 0xE0);
bool fineVolSlides = (efx == 4 || efx == 11) &&
((nfo > 0xF0) || (((nfo & 0xF) == 0xF) && ((nfo & 0xF0) > 0)));
if (!extraFinePitchSlides && !fineVolSlides)
- ton.eff = 0;
+ tmpNote.efxData = 0;
}
}
- if (ton.effTyp > 0)
- alastefx[ii] = ton.effTyp;
+ if (tmpNote.efx > 0)
+ alastefx[ii] = tmpNote.efx;
- switch (ton.effTyp)
+ switch (tmpNote.efx)
{
case 1: // A
{
- ton.effTyp = 0xF;
- if (ton.eff == 0)
+ tmpNote.efx = 0xF;
+ if (tmpNote.efxData == 0)
{
- ton.effTyp = 0;
- ton.eff = 0;
+ tmpNote.efx = 0;
+ tmpNote.efxData = 0;
}
- else if (ton.eff > 0x1F)
+ else if (tmpNote.efxData > 0x1F)
{
- ton.eff = 0x1F;
+ tmpNote.efxData = 0x1F;
}
}
break;
- case 2: ton.effTyp = 0xB; break; // B
- case 3: ton.effTyp = 0xD; break; // C
+ case 2: tmpNote.efx = 0xB; break; // B
+ case 3: tmpNote.efx = 0xD; break; // C
case 4: // D
{
- if (ton.eff > 0xF0) // fine slide up
+ if (tmpNote.efxData > 0xF0) // fine slide up
{
- ton.effTyp = 0xE;
- ton.eff = 0xB0 | (ton.eff & 0xF);
+ tmpNote.efx = 0xE;
+ tmpNote.efxData = 0xB0 | (tmpNote.efxData & 0xF);
}
- else if ((ton.eff & 0x0F) == 0x0F && (ton.eff & 0xF0) > 0) // fine slide down
+ else if ((tmpNote.efxData & 0x0F) == 0x0F && (tmpNote.efxData & 0xF0) > 0) // fine slide down
{
- ton.effTyp = 0xE;
- ton.eff = 0xA0 | (ton.eff >> 4);
+ tmpNote.efx = 0xE;
+ tmpNote.efxData = 0xA0 | (tmpNote.efxData >> 4);
}
else
{
- ton.effTyp = 0xA;
- if (ton.eff & 0x0F) // on D/K, last nybble has first priority in ST3
- ton.eff &= 0x0F;
+ tmpNote.efx = 0xA;
+ if (tmpNote.efxData & 0x0F) // on D/K, last nybble has first priority in ST3
+ tmpNote.efxData &= 0x0F;
}
}
break;
@@ -325,32 +321,32 @@
case 5: // E
case 6: // F
{
- if ((ton.eff & 0xF0) >= 0xE0)
+ if ((tmpNote.efxData & 0xF0) >= 0xE0)
{
// convert to fine slide
- if ((ton.eff & 0xF0) == 0xE0)
+ if ((tmpNote.efxData & 0xF0) == 0xE0)
tmp = 0x21;
else
tmp = 0xE;
- ton.eff &= 0x0F;
+ tmpNote.efxData &= 0x0F;
- if (ton.effTyp == 0x05)
- ton.eff |= 0x20;
+ if (tmpNote.efx == 0x05)
+ tmpNote.efxData |= 0x20;
else
- ton.eff |= 0x10;
+ tmpNote.efxData |= 0x10;
- ton.effTyp = (uint8_t)tmp;
+ tmpNote.efx = (uint8_t)tmp;
- if (ton.effTyp == 0x21 && ton.eff == 0)
+ if (tmpNote.efx == 0x21 && tmpNote.efxData == 0)
{
- ton.effTyp = 0;
+ tmpNote.efx = 0;
}
}
else
{
// convert to normal 1xx/2xx slide
- ton.effTyp = 7 - ton.effTyp;
+ tmpNote.efx = 7 - tmpNote.efx;
}
}
break;
@@ -357,98 +353,98 @@
case 7: // G
{
- ton.effTyp = 0x03;
+ tmpNote.efx = 0x03;
// fix illegal slides (to new instruments)
- if (ton.instr != 0 && ton.instr != s3mLastGInstr[ii])
- ton.instr = s3mLastGInstr[ii];
+ if (tmpNote.instr != 0 && tmpNote.instr != s3mLastGInstr[ii])
+ tmpNote.instr = s3mLastGInstr[ii];
}
break;
case 11: // K
{
- if (ton.eff > 0xF0) // fine slide up
+ if (tmpNote.efxData > 0xF0) // fine slide up
{
- ton.effTyp = 0xE;
- ton.eff = 0xB0 | (ton.eff & 0xF);
+ tmpNote.efx = 0xE;
+ tmpNote.efxData = 0xB0 | (tmpNote.efxData & 0xF);
// if volume column is unoccupied, set to vibrato
- if (ton.vol == 0)
- ton.vol = 0xB0;
+ if (tmpNote.vol == 0)
+ tmpNote.vol = 0xB0;
}
- else if ((ton.eff & 0x0F) == 0x0F && (ton.eff & 0xF0) > 0) // fine slide down
+ else if ((tmpNote.efxData & 0x0F) == 0x0F && (tmpNote.efxData & 0xF0) > 0) // fine slide down
{
- ton.effTyp = 0xE;
- ton.eff = 0xA0 | (ton.eff >> 4);
+ tmpNote.efx = 0xE;
+ tmpNote.efxData = 0xA0 | (tmpNote.efxData >> 4);
// if volume column is unoccupied, set to vibrato
- if (ton.vol == 0)
- ton.vol = 0xB0;
+ if (tmpNote.vol == 0)
+ tmpNote.vol = 0xB0;
}
else
{
- ton.effTyp = 0x6;
- if (ton.eff & 0x0F) // on D/K, last nybble has first priority in ST3
- ton.eff &= 0x0F;
+ tmpNote.efx = 0x6;
+ if (tmpNote.efxData & 0x0F) // on D/K, last nybble has first priority in ST3
+ tmpNote.efxData &= 0x0F;
}
}
break;
- case 8: ton.effTyp = 0x04; break; // H
- case 9: ton.effTyp = 0x1D; break; // I
- case 10: ton.effTyp = 0x00; break; // J
- case 12: ton.effTyp = 0x05; break; // L
- case 15: ton.effTyp = 0x09; break; // O
- case 17: ton.effTyp = 0x1B; break; // Q
- case 18: ton.effTyp = 0x07; break; // R
+ case 8: tmpNote.efx = 0x04; break; // H
+ case 9: tmpNote.efx = 0x1D; break; // I
+ case 10: tmpNote.efx = 0x00; break; // J
+ case 12: tmpNote.efx = 0x05; break; // L
+ case 15: tmpNote.efx = 0x09; break; // O
+ case 17: tmpNote.efx = 0x1B; break; // Q
+ case 18: tmpNote.efx = 0x07; break; // R
case 19: // S
{
- ton.effTyp = 0xE;
- tmp = ton.eff >> 4;
- ton.eff &= 0x0F;
+ tmpNote.efx = 0xE;
+ tmp = tmpNote.efxData >> 4;
+ tmpNote.efxData &= 0x0F;
- if (tmp == 0x1) ton.eff |= 0x30;
- else if (tmp == 0x2) ton.eff |= 0x50;
- else if (tmp == 0x3) ton.eff |= 0x40;
- else if (tmp == 0x4) ton.eff |= 0x70;
+ if (tmp == 0x1) tmpNote.efxData |= 0x30;
+ else if (tmp == 0x2) tmpNote.efxData |= 0x50;
+ else if (tmp == 0x3) tmpNote.efxData |= 0x40;
+ else if (tmp == 0x4) tmpNote.efxData |= 0x70;
// ignore S8x becuase it's not compatible with FT2 panning
- else if (tmp == 0xB) ton.eff |= 0x60;
+ else if (tmp == 0xB) tmpNote.efxData |= 0x60;
else if (tmp == 0xC) // Note Cut
{
- ton.eff |= 0xC0;
- if (ton.eff == 0xC0)
+ tmpNote.efxData |= 0xC0;
+ if (tmpNote.efxData == 0xC0)
{
// EC0 does nothing in ST3 but cuts voice in FT2, remove effect
- ton.effTyp = 0;
- ton.eff = 0;
+ tmpNote.efx = 0;
+ tmpNote.efxData = 0;
}
}
else if (tmp == 0xD) // Note Delay
{
- ton.eff |= 0xD0;
- if (ton.ton == 0 || ton.ton == 97)
+ tmpNote.efxData |= 0xD0;
+ if (tmpNote.note == 0 || tmpNote.note == NOTE_OFF)
{
// EDx without a note does nothing in ST3 but retrigs in FT2, remove effect
- ton.effTyp = 0;
- ton.eff = 0;
+ tmpNote.efx = 0;
+ tmpNote.efxData = 0;
}
- else if (ton.eff == 0xD0)
+ else if (tmpNote.efxData == 0xD0)
{
// ED0 prevents note/smp/vol from updating in ST3, remove everything
- ton.ton = 0;
- ton.instr = 0;
- ton.vol = 0;
- ton.effTyp = 0;
- ton.eff = 0;
+ tmpNote.note = 0;
+ tmpNote.instr = 0;
+ tmpNote.vol = 0;
+ tmpNote.efx = 0;
+ tmpNote.efxData = 0;
}
}
- else if (tmp == 0xE) ton.eff |= 0xE0;
- else if (tmp == 0xF) ton.eff |= 0xF0;
+ else if (tmp == 0xE) tmpNote.efxData |= 0xE0;
+ else if (tmp == 0xF) tmpNote.efxData |= 0xF0;
else
{
- ton.effTyp = 0;
- ton.eff = 0;
+ tmpNote.efx = 0;
+ tmpNote.efxData = 0;
}
}
break;
@@ -455,11 +451,11 @@
case 20: // T
{
- ton.effTyp = 0x0F;
- if (ton.eff < 0x21) // Txx with a value lower than 33 (0x21) does nothing in ST3, remove effect
+ tmpNote.efx = 0x0F;
+ if (tmpNote.efxData < 0x21) // Txx with a value lower than 33 (0x21) does nothing in ST3, remove effect
{
- ton.effTyp = 0;
- ton.eff = 0;
+ tmpNote.efx = 0;
+ tmpNote.efxData = 0;
}
}
break;
@@ -466,12 +462,12 @@
case 22: // V
{
- ton.effTyp = 0x10;
- if (ton.eff > 0x40)
+ tmpNote.efx = 0x10;
+ if (tmpNote.efxData > 0x40)
{
// Vxx > 0x40 does nothing in ST3
- ton.effTyp = 0;
- ton.eff = 0;
+ tmpNote.efx = 0;
+ tmpNote.efxData = 0;
}
}
break;
@@ -478,26 +474,26 @@
default:
{
- ton.effTyp = 0;
- ton.eff = 0;
+ tmpNote.efx = 0;
+ tmpNote.efxData = 0;
}
break;
}
}
- if (ton.instr != 0 && ton.effTyp != 0x3)
- s3mLastGInstr[ii] = ton.instr;
+ if (tmpNote.instr != 0 && tmpNote.efx != 0x3)
+ s3mLastGInstr[ii] = tmpNote.instr;
- pattTmp[i][(kk * MAX_VOICES) + ii] = ton;
+ patternTmp[i][(kk * MAX_CHANNELS) + ii] = tmpNote;
}
}
if (tmpPatternEmpty((uint16_t)i))
{
- if (pattTmp[i] != NULL)
+ if (patternTmp[i] != NULL)
{
- free(pattTmp[i]);
- pattTmp[i] = NULL;
+ free(patternTmp[i]);
+ patternTmp[i] = NULL;
}
}
}
@@ -506,32 +502,34 @@
// *** SAMPLES ***
bool adlibInsWarn = false;
-
- memcpy(ptnOfs, ha, 512);
- for (i = 0; i < ai; i++)
+ for (int32_t i = 0; i < hdr.numSamples; i++)
{
- fseek(f, ptnOfs[i] << 4, SEEK_SET);
+ if (sampleOffsets[i] == 0)
+ continue;
- if (fread(&h_S3MInstr, 1, sizeof (h_S3MInstr), f) != sizeof (h_S3MInstr))
+ fseek(f, sampleOffsets[i], SEEK_SET);
+
+ if (fread(&smpHdr, 1, sizeof (smpHdr), f) != sizeof (smpHdr))
{
loaderMsgBox("Not enough memory!");
return false;
}
- memcpy(songTmp.instrName[1+i], h_S3MInstr.name, 22);
+ memcpy(songTmp.instrName[1+i], smpHdr.name, 22);
- if (h_S3MInstr.typ == 2)
+ if (smpHdr.type == 2)
{
adlibInsWarn = true;
}
- else if (h_S3MInstr.typ == 1)
+ else if (smpHdr.type == 1)
{
- if ((h_S3MInstr.flags & (255-1-2-4)) != 0 || h_S3MInstr.pack != 0)
+ int32_t offsetInFile = ((smpHdr.offsetInFileH << 16) | smpHdr.offsetInFile) << 4;
+ if ((smpHdr.flags & (255-1-2-4)) != 0 || smpHdr.packFlag != 0)
{
loaderMsgBox("Error loading .s3m: Incompatible module!");
return false;
}
- else if (h_S3MInstr.memSeg > 0 && h_S3MInstr.len > 0)
+ else if (offsetInFile > 0 && smpHdr.length > 0)
{
if (!allocateTmpInstr((int16_t)(1 + i)))
{
@@ -540,90 +538,86 @@
}
setNoEnvelope(instrTmp[1 + i]);
- s = &instrTmp[1+i]->samp[0];
+ s = &instrTmp[1+i]->smp[0];
+ if (smpHdr.midCFreq > 65535) // ST3 (and OpenMPT) does this
+ smpHdr.midCFreq = 65535;
+
+ memcpy(s->name, smpHdr.name, 22);
+
// non-FT2: fixes "miracle man.s3m" and other broken S3Ms
- if ((h_S3MInstr.memSeg<<4)+h_S3MInstr.len > (int32_t)filesize)
- h_S3MInstr.len = filesize - (h_S3MInstr.memSeg << 4);
+ if (offsetInFile+smpHdr.length > (int32_t)filesize)
+ smpHdr.length = filesize - offsetInFile;
- len = h_S3MInstr.len;
+ bool hasLoop = !!(smpHdr.flags & 1);
+ bool stereoSample = !!(smpHdr.flags & 2);
+ bool sample16Bit = !!(smpHdr.flags & 4);
- bool hasLoop = h_S3MInstr.flags & 1;
- bool stereoSample = (h_S3MInstr.flags >> 1) & 1;
- bool is16Bit = (h_S3MInstr.flags >> 2) & 1;
-
- if (is16Bit) // 16-bit
- len <<= 1;
+ if (stereoSample)
+ smpHdr.length <<= 1;
- if (stereoSample) // stereo
- len <<= 1;
+ int32_t lengthInFile = smpHdr.length;
- if (!allocateTmpSmpData(s, len))
+ s->length = smpHdr.length;
+ s->volume = smpHdr.volume;
+ s->loopStart = smpHdr.loopStart;
+ s->loopLength = smpHdr.loopEnd - smpHdr.loopStart;
+
+ tuneSample(s, smpHdr.midCFreq, tmpLinearPeriodsFlag);
+
+ if (sample16Bit)
{
+ s->flags |= SAMPLE_16BIT;
+ lengthInFile <<= 1;
+ }
+
+ if (!allocateSmpData(s, s->length, sample16Bit))
+ {
loaderMsgBox("Not enough memory!");
return false;
}
- memcpy(s->name, h_S3MInstr.name, 21);
-
- if (h_S3MInstr.c2Spd > 65535) // ST3 (and OpenMPT) does this
- h_S3MInstr.c2Spd = 65535;
-
- s->len = h_S3MInstr.len;
- s->vol = h_S3MInstr.vol;
- s->repS = h_S3MInstr.repS;
- s->repL = h_S3MInstr.repE - h_S3MInstr.repS;
-
- tuneSample(s, h_S3MInstr.c2Spd, tmpLinearPeriodsFlag);
-
- if (s->vol > 64)
- s->vol = 64;
-
- if (s->repL <= 2 || s->repS+s->repL > s->len || s->repL == 0)
+ if (s->loopLength <= 1 || s->loopStart+s->loopLength > s->length || s->loopLength == 0)
{
- s->repS = 0;
- s->repL = 0;
+ s->loopStart = 0;
+ s->loopLength = 0;
hasLoop = false;
}
- s->typ = hasLoop + (is16Bit << 4);
+ if (hasLoop)
+ s->flags |= LOOP_FWD;
- fseek(f, h_S3MInstr.memSeg << 4, SEEK_SET);
+ fseek(f, offsetInFile, SEEK_SET);
- if (ver == 1)
+ if (hdr.version == 1)
{
- fseek(f, len, SEEK_CUR); // sample not supported
+ fseek(f, lengthInFile, SEEK_CUR); // sample not supported
}
else
{
- if (fread(s->pek, len, 1, f) != 1)
+ if (fread(s->dataPtr, SAMPLE_LENGTH_BYTES(s), 1, f) != 1)
{
loaderMsgBox("General I/O error during loading! Is the file in use?");
return false;
}
- if (is16Bit)
- {
- conv16BitSample(s->pek, len, stereoSample);
-
- s->len <<= 1;
- s->repS <<= 1;
- s->repL <<= 1;
- }
+ if (sample16Bit)
+ conv16BitSample(s->dataPtr, s->length, stereoSample);
else
- {
- conv8BitSample(s->pek, len, stereoSample);
- }
+ conv8BitSample(s->dataPtr, s->length, stereoSample);
// if stereo sample: reduce memory footprint after sample was downmixed to mono
if (stereoSample)
- reallocateTmpSmpData(s, s->len);
+ {
+ s->length >>= 1;
+ reallocateSmpData(s, s->length, sample16Bit);
+ }
}
}
}
}
- songTmp.antChn = countS3MChannels(ap);
+ songTmp.numChannels = countS3MChannels(hdr.numPatterns);
if (adlibInsWarn)
loaderMsgBox("Warning: The module contains unsupported AdLib instruments!");
@@ -639,15 +633,15 @@
int32_t channels = 0;
for (int32_t i = 0; i < antPtn; i++)
{
- if (pattTmp[i] == NULL)
+ if (patternTmp[i] == NULL)
continue;
- tonTyp *ton = pattTmp[i];
+ note_t *p = patternTmp[i];
for (int32_t j = 0; j < 64; j++)
{
- for (int32_t k = 0; k < MAX_VOICES; k++, ton++)
+ for (int32_t k = 0; k < MAX_CHANNELS; k++, p++)
{
- if (ton->eff == 0 && ton->effTyp == 0 && ton->instr == 0 && ton->ton == 0 && ton->vol == 0)
+ if (p->note == 0 && p->instr == 0 && p->vol == 0 && p->efx == 0 && p->efxData == 0)
continue;
if (k > channels)
--- a/src/modloaders/ft2_load_stk.c
+++ b/src/modloaders/ft2_load_stk.c
@@ -1,4 +1,8 @@
-// Ultimate SoundTracker (or compatible) STK loader
+/* Ultimate SoundTracker (or compatible) STK loader
+**
+** Note: Data sanitation is done in the last stage
+** of module loading, so you don't need to do that here.
+*/
#include <stdio.h>
#include <stdint.h>
@@ -13,16 +17,16 @@
#pragma pack(push)
#pragma pack(1)
#endif
-typedef struct songMOD15HeaderTyp_t
+typedef struct stkHdr_t
{
char name[20];
- songMODInstrHeaderTyp instr[15];
- uint8_t len, CIAVal, songTab[128];
+ modSmpHdr_t smp[15];
+ uint8_t numOrders, CIAVal, orders[128];
}
#ifdef __GNUC__
__attribute__ ((packed))
#endif
-songMOD15HeaderTyp;
+stkHdr_t;
#ifdef _MSC_VER
#pragma pack(pop)
#endif
@@ -31,10 +35,9 @@
{
uint8_t bytes[4];
int16_t i, j, k;
- uint16_t a, b, period;
- tonTyp *ton;
- sampleTyp *s;
- songMOD15HeaderTyp h_MOD15;
+ uint16_t a, b;
+ sample_t *s;
+ stkHdr_t h;
tmpLinearPeriodsFlag = false; // use Amiga periods
@@ -41,69 +44,70 @@
bool veryLateSTKVerFlag = false; // "DFJ SoundTracker III" nad later
bool lateSTKVerFlag = false; // "TJC SoundTracker II" and later
- if (filesize < sizeof (h_MOD15))
+ if (filesize < sizeof (h))
{
loaderMsgBox("Error: This file is either not a module, or is not supported.");
return false;
}
- memset(&h_MOD15, 0, sizeof (songMOD15HeaderTyp));
- if (fread(&h_MOD15, 1, sizeof (h_MOD15), f) != sizeof (h_MOD15))
+ memset(&h, 0, sizeof (stkHdr_t));
+ if (fread(&h, 1, sizeof (h), f) != sizeof (h))
{
loaderMsgBox("Error: This file is either not a module, or is not supported.");
return false;
}
- if (h_MOD15.CIAVal == 0) // a CIA value of 0 results in 120
- h_MOD15.CIAVal = 120;
+ if (h.CIAVal == 0) // a CIA value of 0 results in 120
+ h.CIAVal = 120;
- songTmp.antChn = 4;
- songTmp.len = h_MOD15.len;
- songTmp.speed = 125;
- songTmp.initialTempo = songTmp.tempo = 6;
- memcpy(songTmp.songTab, h_MOD15.songTab, 128);
-
- if (songTmp.len < 1 || songTmp.len > 128 || h_MOD15.CIAVal > 220)
+ if (h.numOrders < 1 || h.numOrders > 128 || h.CIAVal > 220)
{
loaderMsgBox("Error: This file is either not a module, or is not supported.");
return false;
}
+ memcpy(songTmp.orders, h.orders, 128);
+
+ songTmp.numChannels = 4;
+ songTmp.songLength = h.numOrders;
+ songTmp.BPM = 125;
+ songTmp.speed = 6;
+
for (a = 0; a < 15; a++)
{
- songMODInstrHeaderTyp *smp = &h_MOD15.instr[a];
- memcpy(songTmp.instrName[1+a], smp->name, 22);
+ modSmpHdr_t *modSmp = &h.smp[a];
+ memcpy(songTmp.instrName[1+a], modSmp->name, 22);
/* Only late versions of Ultimate SoundTracker supports samples larger than 9999 bytes.
** If found, we know for sure that this is a late STK module.
*/
- const int32_t sampleLen = 2*SWAP16(smp->len);
+ const int32_t sampleLen = 2*SWAP16(modSmp->length);
if (sampleLen > 9999)
lateSTKVerFlag = true;
}
// jjk55.mod by Jesper Kyd has a bogus STK tempo value that should be ignored (hackish!)
- if (!strcmp("jjk55", h_MOD15.name))
- h_MOD15.CIAVal = 120;
+ if (!strcmp("jjk55", h.name))
+ h.CIAVal = 120;
- if (h_MOD15.CIAVal != 120) // 120 is a special case and means 50Hz (125BPM)
+ if (h.CIAVal != 120) // 120 is a special case and means 50Hz (125BPM)
{
// convert UST tempo to BPM
- uint16_t ciaPeriod = (240 - h_MOD15.CIAVal) * 122;
+ uint16_t ciaPeriod = (240 - h.CIAVal) * 122;
double dHz = 709379.0 / ciaPeriod;
int32_t BPM = (int32_t)((dHz * 2.5) + 0.5);
- songTmp.speed = (uint16_t)BPM;
+ songTmp.BPM = (uint16_t)BPM;
}
- memcpy(songTmp.name, h_MOD15.name, 20);
+ memcpy(songTmp.name, h.name, 20);
// count number of patterns
b = 0;
for (a = 0; a < 128; a++)
{
- if (songTmp.songTab[a] > b)
- b = songTmp.songTab[a];
+ if (songTmp.orders[a] > b)
+ b = songTmp.orders[a];
}
b++;
@@ -117,9 +121,9 @@
for (j = 0; j < 64; j++)
{
- for (k = 0; k < songTmp.antChn; k++)
+ for (k = 0; k < songTmp.numChannels; k++)
{
- ton = &pattTmp[a][(j * MAX_VOICES) + k];
+ note_t *p = &patternTmp[a][(j * MAX_CHANNELS) + k];
if (fread(bytes, 1, 4, f) != 4)
{
@@ -128,27 +132,27 @@
}
// period to note
- period = ((bytes[0] & 0x0F) << 8) | bytes[1];
+ uint16_t period = ((bytes[0] & 0x0F) << 8) | bytes[1];
for (i = 0; i < 3*12; i++)
{
if (period >= ptPeriods[i])
{
- ton->ton = 1 + (3*12) + (uint8_t)i;
+ p->note = 1 + (3*12) + (uint8_t)i;
break;
}
}
- ton->instr = (bytes[0] & 0xF0) | (bytes[2] >> 4);
- ton->effTyp = bytes[2] & 0x0F;
- ton->eff = bytes[3];
+ p->instr = (bytes[0] & 0xF0) | (bytes[2] >> 4);
+ p->efx = bytes[2] & 0x0F;
+ p->efxData = bytes[3];
- if (ton->effTyp == 0xC || ton->effTyp == 0xD || ton->effTyp == 0xE)
+ if (p->efx == 0xC || p->efx == 0xD || p->efx == 0xE)
{
// "TJC SoundTracker II" and later
lateSTKVerFlag = true;
}
- if (ton->effTyp == 0xF)
+ if (p->efx == 0xF)
{
// "DFJ SoundTracker III" and later
lateSTKVerFlag = true;
@@ -155,43 +159,43 @@
veryLateSTKVerFlag = true;
}
- if (ton->effTyp == 0xC)
+ if (p->efx == 0xC)
{
- if (ton->eff > 64)
- ton->eff = 64;
+ if (p->efxData > 64)
+ p->efxData = 64;
}
- else if (ton->effTyp == 0x1)
+ else if (p->efx == 0x1)
{
- if (ton->eff == 0)
- ton->effTyp = 0;
+ if (p->efxData == 0)
+ p->efxData = 0;
}
- else if (ton->effTyp == 0x2)
+ else if (p->efx == 0x2)
{
- if (ton->eff == 0)
- ton->effTyp = 0;
+ if (p->efxData == 0)
+ p->efxData = 0;
}
- else if (ton->effTyp == 0x5)
+ else if (p->efx == 0x5)
{
- if (ton->eff == 0)
- ton->effTyp = 0x3;
+ if (p->efxData == 0)
+ p->efxData = 0x3;
}
- else if (ton->effTyp == 0x6)
+ else if (p->efx == 0x6)
{
- if (ton->eff == 0)
- ton->effTyp = 0x4;
+ if (p->efxData == 0)
+ p->efxData = 0x4;
}
- else if (ton->effTyp == 0xA)
+ else if (p->efx == 0xA)
{
- if (ton->eff == 0)
- ton->effTyp = 0;
+ if (p->efxData == 0)
+ p->efxData = 0;
}
- else if (ton->effTyp == 0xE)
+ else if (p->efx == 0xE)
{
// check if certain E commands are empty
- if (ton->eff == 0x10 || ton->eff == 0x20 || ton->eff == 0xA0 || ton->eff == 0xB0)
+ if (p->efxData == 0x10 || p->efxData == 0x20 || p->efxData == 0xA0 || p->efxData == 0xB0)
{
- ton->effTyp = 0;
- ton->eff = 0;
+ p->efx = 0;
+ p->efxData = 0;
}
}
}
@@ -199,10 +203,10 @@
if (tmpPatternEmpty(a))
{
- if (pattTmp[a] != NULL)
+ if (patternTmp[a] != NULL)
{
- free(pattTmp[a]);
- pattTmp[a] = NULL;
+ free(patternTmp[a]);
+ patternTmp[a] = NULL;
}
}
}
@@ -210,14 +214,14 @@
// pattern command conversion for non-PT formats
for (a = 0; a < b; a++)
{
- if (pattTmp[a] == NULL)
+ if (patternTmp[a] == NULL)
continue;
for (j = 0; j < 64; j++)
{
- for (k = 0; k < songTmp.antChn; k++)
+ for (k = 0; k < songTmp.numChannels; k++)
{
- ton = &pattTmp[a][(j * MAX_VOICES) + k];
+ note_t *p = &patternTmp[a][(j * MAX_CHANNELS) + k];
// convert STK effects to PT effects
@@ -225,24 +229,24 @@
{
// old SoundTracker 1.x commands
- if (ton->effTyp == 1)
+ if (p->efx == 1)
{
// arpeggio
- ton->effTyp = 0;
+ p->efx = 0;
}
- else if (ton->effTyp == 2)
+ else if (p->efx == 2)
{
// pitch slide
- if (ton->eff & 0xF0)
+ if (p->efxData & 0xF0)
{
// pitch slide down
- ton->effTyp = 2;
- ton->eff >>= 4;
+ p->efx = 2;
+ p->efxData >>= 4;
}
- else if (ton->eff & 0x0F)
+ else if (p->efxData & 0x0F)
{
// pitch slide up
- ton->effTyp = 1;
+ p->efx = 1;
}
}
}
@@ -250,24 +254,24 @@
{
// "DFJ SoundTracker II" or later
- if (ton->effTyp == 0xD)
+ if (p->efx == 0xD)
{
if (veryLateSTKVerFlag) // "DFJ SoundTracker III" or later
{
// pattern break w/ no param (param must be cleared to fix some songs)
- ton->eff = 0;
+ p->efxData = 0;
}
else
{
// volume slide
- ton->effTyp = 0xA;
+ p->efx = 0xA;
}
}
}
// effect F with param 0x00 does nothing in UST/STK (I think)
- if (ton->effTyp == 0xF && ton->eff == 0)
- ton->effTyp = 0;
+ if (p->efx == 0xF && p->efxData == 0)
+ p->efx = 0;
}
}
}
@@ -274,7 +278,7 @@
for (a = 0; a < 15; a++)
{
- if (h_MOD15.instr[a].len == 0)
+ if (h.smp[a].length == 0)
continue;
if (!allocateTmpInstr(1+a))
@@ -285,64 +289,60 @@
setNoEnvelope(instrTmp[1+a]);
- s = &instrTmp[1+a]->samp[0];
- s->vol = h_MOD15.instr[a].vol;
+ s = &instrTmp[1+a]->smp[0];
+ s->volume = h.smp[a].volume;
+ s->length = 2 * SWAP16(h.smp[a].length);
+ s->loopStart = SWAP16(h.smp[a].loopStart); // in STK, loopStart = bytes, not words
+ s->loopLength = 2 * SWAP16(h.smp[a].loopLength);
- s->len = 2 * SWAP16(h_MOD15.instr[a].len);
- s->repS = SWAP16(h_MOD15.instr[a].repS); // in STK, loopStart = bytes, not words
- s->repL = 2 * SWAP16(h_MOD15.instr[a].repL);
+ if (s->loopLength < 2)
+ s->loopLength = 2;
- if (s->vol > 64)
- s->vol = 64;
-
- if (s->repL < 2)
- s->repL = 2;
-
// fix overflown loop
- if (s->repS+s->repL > s->len)
+ if (s->loopStart+s->loopLength > s->length)
{
- if (s->repS >= s->len)
+ if (s->loopStart >= s->length)
{
- s->repS = 0;
- s->repL = 0;
+ s->loopStart = 0;
+ s->loopLength = 0;
}
else
{
- s->repL = s->len - s->repS;
+ s->loopLength = s->length - s->loopStart;
}
}
- if (s->repS+s->repL > 2)
+ if (s->loopStart+s->loopLength > 2)
{
- s->typ = 1; // enable loop
+ s->flags |= LOOP_FWD; // enable loop
}
else
{
- s->repL = 0;
- s->repS = 0;
+ s->loopLength = 0;
+ s->loopStart = 0;
}
/* In STK, only the loop area of a looped sample is played.
** Skip loading of eventual data present before loop start.
*/
- if (s->repS > 0 && s->repL < s->len)
+ if (s->loopStart > 0 && s->loopLength < s->length)
{
- s->len -= s->repS;
- fseek(f, s->repS, SEEK_CUR);
- s->repS = 0;
+ s->length -= s->loopStart;
+ fseek(f, s->loopStart, SEEK_CUR);
+ s->loopStart = 0;
}
- if (!allocateTmpSmpData(s, s->len))
+ if (!allocateSmpData(s, s->length, false))
{
loaderMsgBox("Not enough memory!");
return false;
}
- int32_t bytesRead = (int32_t)fread(s->pek, 1, s->len, f);
- if (bytesRead < s->len)
+ int32_t bytesRead = (int32_t)fread(s->dataPtr, 1, s->length, f);
+ if (bytesRead < s->length)
{
- int32_t bytesToClear = s->len - bytesRead;
- memset(&s->pek[bytesRead], 0, bytesToClear);
+ int32_t bytesToClear = s->length - bytesRead;
+ memset(&s->dataPtr[bytesRead], 0, bytesToClear);
}
}
--- a/src/modloaders/ft2_load_stm.c
+++ b/src/modloaders/ft2_load_stm.c
@@ -1,4 +1,8 @@
-// Scream Tracker 2 STM loader
+/* Scream Tracker 2 STM loader
+**
+** Note: Data sanitation is done in the last stage
+** of module loading, so you don't need to do that here.
+*/
#include <stdio.h>
#include <stdint.h>
@@ -13,98 +17,92 @@
#pragma pack(push)
#pragma pack(1)
#endif
-typedef struct songSTMinstrHeaderTyp_t
+typedef struct stmSmpHdr_t
{
char name[12];
- uint8_t nul, insDisk;
- uint16_t reserved1, len, repS, repE;
- uint8_t vol, reserved2;
- uint16_t rate;
- int32_t reserved3;
+ uint8_t nul, junk1;
+ uint16_t junk2, length, loopStart, loopEnd;
+ uint8_t volume, junk3;
+ uint16_t midCFreq;
+ int32_t junk4;
uint16_t paraLen;
}
#ifdef __GNUC__
__attribute__ ((packed))
#endif
-songSTMinstrHeaderTyp;
+stmSmpHdr_t;
-typedef struct songSTMHeaderTyp_t
+typedef struct stmHdr_t
{
char name[20], sig[8];
- uint8_t id1a, typ;
+ uint8_t x1A, type;
uint8_t verMajor, verMinor;
- uint8_t tempo, ap, vol, reserved[13];
- songSTMinstrHeaderTyp instr[31];
- uint8_t songTab[128];
+ uint8_t tempo, numPatterns, volume, reserved[13];
+ stmSmpHdr_t smp[31];
+ uint8_t orders[128];
}
#ifdef __GNUC__
__attribute__ ((packed))
#endif
-songSTMHeaderTyp;
+stmHdr_t;
#ifdef _MSC_VER
#pragma pack(pop)
#endif
-static const uint8_t stmEff[16] = { 0, 0, 11, 0, 10, 2, 1, 3, 4, 7, 0, 5, 6, 0, 0, 0 };
+static const uint8_t stmEfx[16] = { 0, 0, 11, 0, 10, 2, 1, 3, 4, 7, 0, 5, 6, 0, 0, 0 };
+static uint8_t pattBuff[64*4*4];
-static uint8_t stmTempoToBPM(uint8_t tempo);
+static uint16_t stmTempoToBPM(uint8_t tempo);
bool loadSTM(FILE *f, uint32_t filesize)
{
- uint8_t typ, tempo, pattBuff[1024];
- int16_t i, j, k, ap, tmp;
- uint16_t a;
- tonTyp *ton;
- sampleTyp *s;
- songSTMHeaderTyp h_STM;
+ int16_t i, j, k;
+ stmHdr_t hdr;
tmpLinearPeriodsFlag = false; // use Amiga periods
- if (filesize < sizeof (h_STM))
+ if (filesize < sizeof (hdr))
{
loaderMsgBox("Error: This file is either not a module, or is not supported.");
return false;
}
- if (fread(&h_STM, 1, sizeof (h_STM), f) != sizeof (h_STM))
+ if (fread(&hdr, 1, sizeof (hdr), f) != sizeof (hdr))
{
loaderMsgBox("Error: This file is either not a module, or is not supported.");
return false;
}
- if (h_STM.verMinor == 0 || h_STM.typ != 2)
+ if (hdr.verMinor == 0 || hdr.type != 2)
{
loaderMsgBox("Error loading STM: Incompatible module!");
return false;
}
- songTmp.antChn = 4;
- memcpy(songTmp.songTab, h_STM.songTab, 128);
+ songTmp.numChannels = 4;
+ memcpy(songTmp.orders, hdr.orders, 128);
i = 0;
- while (i < 128 && songTmp.songTab[i] < 99) i++;
- songTmp.len = i + (i == 0);
+ while (i < 128 && songTmp.orders[i] < 99)
+ i++;
+ songTmp.songLength = i + (i == 0);
- if (songTmp.len < 255)
- memset(&songTmp.songTab[songTmp.len], 0, 256 - songTmp.len);
+ if (songTmp.songLength < 255)
+ memset(&songTmp.orders[songTmp.songLength], 0, 256 - songTmp.songLength);
- memcpy(songTmp.name, h_STM.name, 20);
+ memcpy(songTmp.name, hdr.name, 20);
- tempo = h_STM.tempo;
- if (h_STM.verMinor < 21)
+ uint8_t tempo = hdr.tempo;
+ if (hdr.verMinor < 21)
tempo = ((tempo / 10) << 4) + (tempo % 10);
if (tempo == 0)
tempo = 96;
- songTmp.initialTempo = songTmp.tempo = CLAMP(h_STM.tempo >> 4, 1, 31);
- songTmp.speed = stmTempoToBPM(tempo);
+ songTmp.BPM = stmTempoToBPM(tempo);
+ songTmp.speed = hdr.tempo >> 4;
- if (h_STM.verMinor > 10)
- songTmp.globVol = MIN(h_STM.vol, 64);
-
- ap = h_STM.ap;
- for (i = 0; i < ap; i++)
+ for (i = 0; i < hdr.numPatterns; i++)
{
if (!allocateTmpPatt(i, 64))
{
@@ -118,76 +116,75 @@
return false;
}
- a = 0;
+ uint8_t *pattPtr = pattBuff;
for (j = 0; j < 64; j++)
{
- for (k = 0; k < 4; k++)
+ for (k = 0; k < 4; k++, pattPtr += 4)
{
- ton = &pattTmp[i][(j * MAX_VOICES) + k];
+ note_t *p = &patternTmp[i][(j * MAX_CHANNELS) + k];
- if (pattBuff[a] == 254)
+ if (pattPtr[0] == 254)
{
- ton->ton = 97;
+ p->note = NOTE_OFF;
}
- else if (pattBuff[a] < 96)
+ else if (pattPtr[0] < 96)
{
- ton->ton = (12 * (pattBuff[a] >> 4)) + (25 + (pattBuff[a] & 0x0F));
- if (ton->ton > 96)
- ton->ton = 0;
+ p->note = (12 * (pattPtr[0] >> 4)) + (25 + (pattPtr[0] & 0x0F));
+ if (p->note > 96)
+ p->note = 0;
}
else
{
- ton->ton = 0;
+ p->note = 0;
}
- ton->instr = pattBuff[a + 1] >> 3;
- typ = (pattBuff[a + 1] & 7) + ((pattBuff[a + 2] & 0xF0) >> 1);
- if (typ <= 64)
- ton->vol = typ + 0x10;
+ p->instr = pattPtr[1] >> 3;
- ton->eff = pattBuff[a + 3];
+ uint8_t vol = (pattPtr[1] & 7) + ((pattPtr[2] & 0xF0) >> 1);
+ if (vol <= 64)
+ p->vol = 0x10 + vol;
- tmp = pattBuff[a + 2] & 0x0F;
- if (tmp == 1)
+ p->efxData = pattPtr[3];
+
+ uint8_t efx = pattPtr[2] & 0x0F;
+ if (efx == 1)
{
- ton->effTyp = 15;
+ p->efx = 15;
- if (h_STM.verMinor < 21)
- ton->eff = ((ton->eff / 10) << 4) + (ton->eff % 10);
+ if (hdr.verMinor < 21)
+ p->efxData = ((p->efxData / 10) << 4) + (p->efxData % 10);
- ton->eff >>= 4;
+ p->efxData >>= 4;
}
- else if (tmp == 3)
+ else if (efx == 3)
{
- ton->effTyp = 13;
- ton->eff = 0;
+ p->efx = 13;
+ p->efxData = 0;
}
- else if (tmp == 2 || (tmp >= 4 && tmp <= 12))
+ else if (efx == 2 || (efx >= 4 && efx <= 12))
{
- ton->effTyp = stmEff[tmp];
- if (ton->effTyp == 0xA)
+ p->efx = stmEfx[efx];
+ if (p->efx == 0xA)
{
- if (ton->eff & 0x0F)
- ton->eff &= 0x0F;
+ if (p->efxData & 0x0F)
+ p->efxData &= 0x0F;
else
- ton->eff &= 0xF0;
+ p->efxData &= 0xF0;
}
}
else
{
- ton->eff = 0;
+ p->efxData = 0;
}
-
- a += 4;
}
}
if (tmpPatternEmpty(i))
{
- if (pattTmp[i] != NULL)
+ if (patternTmp[i] != NULL)
{
- free(pattTmp[i]);
- pattTmp[i] = NULL;
+ free(patternTmp[i]);
+ patternTmp[i] = NULL;
}
}
}
@@ -194,47 +191,43 @@
for (i = 0; i < 31; i++)
{
- memcpy(&songTmp.instrName[1+i], h_STM.instr[i].name, 12);
+ memcpy(&songTmp.instrName[1+i], hdr.smp[i].name, 12);
- if (h_STM.instr[i].len != 0 && h_STM.instr[i].reserved1 != 0)
+ if (hdr.smp[i].length > 0)
{
allocateTmpInstr(1 + i);
setNoEnvelope(instrTmp[i]);
- s = &instrTmp[1+i]->samp[0];
+ sample_t *s = &instrTmp[1+i]->smp[0];
- if (!allocateTmpSmpData(s, h_STM.instr[i].len))
+ if (!allocateSmpData(s, hdr.smp[i].length, false))
{
loaderMsgBox("Not enough memory!");
return false;
}
- s->len = h_STM.instr[i].len;
- s->vol = h_STM.instr[i].vol;
- s->repS = h_STM.instr[i].repS;
- s->repL = h_STM.instr[i].repE - h_STM.instr[i].repS;
+ s->length = hdr.smp[i].length;
+ s->volume = hdr.smp[i].volume;
+ s->loopStart = hdr.smp[i].loopStart;
+ s->loopLength = hdr.smp[i].loopEnd - hdr.smp[i].loopStart;
- memcpy(s->name, h_STM.instr[i].name, 12);
- tuneSample(s, h_STM.instr[i].rate, tmpLinearPeriodsFlag);
+ memcpy(s->name, hdr.smp[i].name, 12);
+ tuneSample(s, hdr.smp[i].midCFreq, tmpLinearPeriodsFlag);
- if (s->repS < s->len && h_STM.instr[i].repE > s->repS && h_STM.instr[i].repE != 0xFFFF)
+ if (s->loopStart < s->length && hdr.smp[i].loopEnd > s->loopStart && hdr.smp[i].loopEnd != 0xFFFF)
{
- if (s->repS+s->repL > s->len)
- s->repL = s->len - s->repS;
+ if (s->loopStart+s->loopLength > s->length)
+ s->loopLength = s->length - s->loopStart;
- s->typ = 1; // enable loop
+ s->flags |= LOOP_FWD; // enable loop
}
else
{
- s->repS = 0;
- s->repL = 0;
- s->typ = 0;
+ s->loopStart = 0;
+ s->loopLength = 0;
}
- if (s->vol > 64)
- s->vol = 64;
-
- if (fread(s->pek, s->len, 1, f) != 1)
+ if (fread(s->dataPtr, s->length, 1, f) != 1)
{
loaderMsgBox("General I/O error during loading! Possibly corrupt module?");
return false;
@@ -245,7 +238,7 @@
return true;
}
-static uint8_t stmTempoToBPM(uint8_t tempo) // ported from original ST2.3 replayer code
+static uint16_t stmTempoToBPM(uint8_t tempo) // ported from original ST2.3 replayer code
{
const uint8_t slowdowns[16] = { 140, 50, 25, 15, 10, 7, 6, 4, 3, 3, 2, 2, 2, 2, 1, 1 };
uint16_t hz = 50;
@@ -252,6 +245,6 @@
hz -= ((slowdowns[tempo >> 4] * (tempo & 15)) >> 4); // can and will underflow
- const uint32_t bpm = (hz << 1) + (hz >> 1); // BPM = hz * 2.5
- return (uint8_t)CLAMP(bpm, 32, 255); // result can be slightly off, but close enough...
+ const uint16_t bpm = (hz << 1) + (hz >> 1); // BPM = hz * 2.5
+ return bpm; // result can be slightly off, but close enough...
}
--- a/src/modloaders/ft2_load_xm.c
+++ b/src/modloaders/ft2_load_xm.c
@@ -1,4 +1,8 @@
-// Fasttracker II (or compatible) XM loader
+/* Fasttracker II (or compatible) XM loader
+**
+** Note: Data sanitation is done in the last stage
+** of module loading, so you don't need to do that here.
+*/
#include <stdio.h>
#include <stdint.h>
@@ -20,14 +24,13 @@
static bool loadInstrHeader(FILE *f, uint16_t i);
static bool loadInstrSample(FILE *f, uint16_t i);
static void unpackPatt(uint8_t *dst, uint8_t *src, uint16_t len, int32_t antChn);
-static bool loadPatterns(FILE *f, uint16_t antPtn);
+static bool loadPatterns(FILE *f, uint16_t antPtn, uint16_t xmVersion);
static void unpackPatt(uint8_t *dst, uint8_t *src, uint16_t len, int32_t antChn);
-static void sanitizeInstrument(instrTyp *ins);
+static void loadADPCMSample(FILE *f, sample_t *s); // ModPlug Tracker
bool loadXM(FILE *f, uint32_t filesize)
{
- uint16_t i;
- songHeaderTyp h;
+ xmHdr_t h;
if (filesize < sizeof (h))
{
@@ -41,31 +44,31 @@
return false;
}
- if (h.ver < 0x0102 || h.ver > 0x0104)
+ if (h.version < 0x0102 || h.version > 0x0104)
{
- loaderMsgBox("Error loading XM: Unsupported file version (v%01X.%02X).", (h.ver >> 8) & 15, h.ver & 0xFF);
+ loaderMsgBox("Error loading XM: Unsupported file version (v%01X.%02X).", (h.version >> 8) & 15, h.version & 0xFF);
return false;
}
- if (h.len > MAX_ORDERS)
+ if (h.numOrders > MAX_ORDERS)
{
loaderMsgBox("Error loading XM: The song has more than 256 orders!");
return false;
}
- if (h.antPtn > MAX_PATTERNS)
+ if (h.numPatterns > MAX_PATTERNS)
{
loaderMsgBox("Error loading XM: The song has more than 256 patterns!");
return false;
}
- if (h.antChn == 0)
+ if (h.numChannels == 0)
{
loaderMsgBox("Error loading XM: This file is corrupt.");
return false;
}
- if (h.antInstrs > 256) // if >128 instruments, we fake-load up to 128 extra instruments and discard them
+ if (h.numInstr > 256) // if >128 instruments, we fake-load up to 128 extra instruments and discard them
{
loaderMsgBox("Error loading XM: This file is corrupt.");
return false;
@@ -79,52 +82,48 @@
}
memcpy(songTmp.name, h.name, 20);
+ songTmp.name[20] = '\0';
- songTmp.len = h.len;
- songTmp.repS = h.repS;
- songTmp.antChn = (uint8_t)h.antChn;
- songTmp.speed = h.defSpeed;
- songTmp.tempo = h.defTempo;
- songTmp.ver = h.ver;
+ songTmp.songLength = h.numOrders;
+ songTmp.songLoopStart = h.songLoopStart;
+ songTmp.numChannels = (uint8_t)h.numChannels;
+ songTmp.BPM = h.BPM;
+ songTmp.speed = h.speed;
tmpLinearPeriodsFlag = h.flags & 1;
- // non-FT2: clamp to max numbers that are okay for GUI
- songTmp.speed = CLAMP(songTmp.speed, 1, 999);
- songTmp.initialTempo = songTmp.tempo = CLAMP(songTmp.tempo, 1, 99);
-
- if (songTmp.len == 0)
- songTmp.len = 1; // songTmp.songTab is already empty
+ if (songTmp.songLength == 0)
+ songTmp.songLength = 1; // songTmp.songTab is already empty
else
- memcpy(songTmp.songTab, h.songTab, songTmp.len);
+ memcpy(songTmp.orders, h.orders, songTmp.songLength);
// some strange XMs have the order list padded with 0xFF, remove them!
for (int16_t j = 255; j >= 0; j--)
{
- if (songTmp.songTab[j] != 0xFF)
+ if (songTmp.orders[j] != 0xFF)
break;
- if (songTmp.len > j)
- songTmp.len = j;
+ if (songTmp.songLength > j)
+ songTmp.songLength = j;
}
// even though XM supports 256 orders, FT2 supports only 255...
- if (songTmp.len > 0xFF)
- songTmp.len = 0xFF;
+ if (songTmp.songLength > 255)
+ songTmp.songLength = 255;
- if (songTmp.ver < 0x0104)
+ if (h.version < 0x0104)
{
// XM v1.02 and XM v1.03
- for (i = 1; i <= h.antInstrs; i++)
+ for (uint16_t i = 1; i <= h.numInstr; i++)
{
if (!loadInstrHeader(f, i))
return false;
}
- if (!loadPatterns(f, h.antPtn))
+ if (!loadPatterns(f, h.numPatterns, h.version))
return false;
- for (i = 1; i <= h.antInstrs; i++)
+ for (uint16_t i = 1; i <= h.numInstr; i++)
{
if (!loadInstrSample(f, i))
return false;
@@ -134,10 +133,10 @@
{
// XM v1.04 (latest version)
- if (!loadPatterns(f, h.antPtn))
+ if (!loadPatterns(f, h.numPatterns, h.version))
return false;
- for (i = 1; i <= h.antInstrs; i++)
+ for (uint16_t i = 1; i <= h.numInstr; i++)
{
if (!loadInstrHeader(f, i))
return false;
@@ -148,9 +147,9 @@
}
// if we temporarily loaded more than 128 instruments, clear the extra allocated memory
- if (h.antInstrs > MAX_INST)
+ if (h.numInstr > MAX_INST)
{
- for (i = MAX_INST+1; i <= h.antInstrs; i++)
+ for (int32_t i = MAX_INST+1; i <= h.numInstr; i++)
{
if (instrTmp[i] != NULL)
{
@@ -165,22 +164,22 @@
** back to max 16 in the headers before loading is done.
*/
bool instrHasMoreThan16Samples = false;
- for (i = 1; i <= MAX_INST; i++)
+ for (int32_t i = 1; i <= MAX_INST; i++)
{
- if (instrTmp[i] != NULL && instrTmp[i]->antSamp > MAX_SMP_PER_INST)
+ if (instrTmp[i] != NULL && instrTmp[i]->numSamples > MAX_SMP_PER_INST)
{
instrHasMoreThan16Samples = true;
- instrTmp[i]->antSamp = MAX_SMP_PER_INST;
+ instrTmp[i]->numSamples = MAX_SMP_PER_INST;
}
}
- if (songTmp.antChn > MAX_VOICES)
+ if (songTmp.numChannels > MAX_CHANNELS)
{
- songTmp.antChn = MAX_VOICES;
+ songTmp.numChannels = MAX_CHANNELS;
loaderMsgBox("Warning: Module contains >32 channels. The extra channels will be discarded!");
}
- if (h.antInstrs > MAX_INST)
+ if (h.numInstr > MAX_INST)
loaderMsgBox("Warning: Module contains >128 instruments. The extra instruments will be discarded!");
if (instrHasMoreThan16Samples)
@@ -191,37 +190,35 @@
static bool loadInstrHeader(FILE *f, uint16_t i)
{
- uint8_t j;
uint32_t readSize;
- instrHeaderTyp ih;
- instrTyp *ins;
- sampleHeaderTyp *src;
- sampleTyp *s;
+ xmInsHdr_t ih;
+ instr_t *ins;
+ xmSmpHdr_t *src;
+ sample_t *s;
memset(extraSampleLengths, 0, sizeof (extraSampleLengths));
memset(&ih, 0, sizeof (ih));
- fread(&ih.instrSize, 4, 1, f);
- readSize = ih.instrSize;
+ fread(&readSize, 4, 1, f);
+ fseek(f, -4, SEEK_CUR);
// yes, some XMs can have a header size of 0, and it usually means 263 bytes (INSTR_HEADER_SIZE)
if (readSize == 0 || readSize > INSTR_HEADER_SIZE)
readSize = INSTR_HEADER_SIZE;
- if (readSize < 4)
+ if ((int32_t)readSize < 0)
{
- loaderMsgBox("Error loading XM: This file is corrupt (or not supported)!");
+ loaderMsgBox("Error loading XM: This file is corrupt!");
return false;
}
- // load instrument data into temp buffer
- fread(ih.name, readSize-4, 1, f); // -4 = skip ih.instrSize
+ fread(&ih, readSize, 1, f); // read instrument header
// FT2 bugfix: skip instrument header data if instrSize is above INSTR_HEADER_SIZE
if (ih.instrSize > INSTR_HEADER_SIZE)
fseek(f, ih.instrSize-INSTR_HEADER_SIZE, SEEK_CUR);
- if (ih.antSamp < 0 || ih.antSamp > 32)
+ if (ih.numSamples < 0 || ih.numSamples > 32)
{
loaderMsgBox("Error loading XM: This file is corrupt (or not supported)!");
return false;
@@ -230,7 +227,7 @@
if (i <= MAX_INST) // copy over instrument names
memcpy(songTmp.instrName[i], ih.name, 22);
- if (ih.antSamp > 0)
+ if (ih.numSamples > 0 && ih.numSamples <= 32)
{
if (!allocateTmpInstr(i))
{
@@ -241,38 +238,36 @@
// copy instrument header elements to our instrument struct
ins = instrTmp[i];
- memcpy(ins->ta, ih.ta, 96);
- memcpy(ins->envVP, ih.envVP, 12*2*sizeof(int16_t));
- memcpy(ins->envPP, ih.envPP, 12*2*sizeof(int16_t));
- ins->envVPAnt = ih.envVPAnt;
- ins->envPPAnt = ih.envPPAnt;
- ins->envVSust = ih.envVSust;
- ins->envVRepS = ih.envVRepS;
- ins->envVRepE = ih.envVRepE;
- ins->envPSust = ih.envPSust;
- ins->envPRepS = ih.envPRepS;
- ins->envPRepE = ih.envPRepE;
- ins->envVTyp = ih.envVTyp;
- ins->envPTyp = ih.envPTyp;
- ins->vibTyp = ih.vibTyp;
+ memcpy(ins->note2SampleLUT, ih.note2SampleLUT, 96);
+ memcpy(ins->volEnvPoints, ih.volEnvPoints, 12*2*sizeof(int16_t));
+ memcpy(ins->panEnvPoints, ih.panEnvPoints, 12*2*sizeof(int16_t));
+ ins->volEnvLength = ih.volEnvLength;
+ ins->panEnvLength = ih.panEnvLength;
+ ins->volEnvSustain = ih.volEnvSustain;
+ ins->volEnvLoopStart = ih.volEnvLoopStart;
+ ins->volEnvLoopEnd = ih.volEnvLoopEnd;
+ ins->panEnvSustain = ih.panEnvSustain;
+ ins->panEnvLoopStart = ih.panEnvLoopStart;
+ ins->panEnvLoopEnd = ih.panEnvLoopEnd;
+ ins->volEnvFlags = ih.volEnvFlags;
+ ins->panEnvFlags = ih.panEnvFlags;
+ ins->vibType = ih.vibType;
ins->vibSweep = ih.vibSweep;
ins->vibDepth = ih.vibDepth;
ins->vibRate = ih.vibRate;
- ins->fadeOut = ih.fadeOut;
+ ins->fadeout = ih.fadeout;
ins->midiOn = (ih.midiOn == 1) ? true : false;
ins->midiChannel = ih.midiChannel;
ins->midiProgram = ih.midiProgram;
ins->midiBend = ih.midiBend;
ins->mute = (ih.mute == 1) ? true : false; // correct logic, don't change this!
- ins->antSamp = ih.antSamp; // used in loadInstrSample()
+ ins->numSamples = ih.numSamples; // used in loadInstrSample()
- sanitizeInstrument(ins);
-
- int32_t sampleHeadersToRead = ih.antSamp;
+ int32_t sampleHeadersToRead = ih.numSamples;
if (sampleHeadersToRead > MAX_SMP_PER_INST)
sampleHeadersToRead = MAX_SMP_PER_INST;
- if (fread(ih.samp, sampleHeadersToRead * sizeof (sampleHeaderTyp), 1, f) != 1)
+ if (fread(ih.smp, sampleHeadersToRead * sizeof (xmSmpHdr_t), 1, f) != 1)
{
loaderMsgBox("General I/O error during loading!");
return false;
@@ -279,40 +274,41 @@
}
// if instrument contains more than 16 sample headers (unsupported), skip them
- if (ih.antSamp > MAX_SMP_PER_INST) // can only be 0..32 at this point
+ if (ih.numSamples > MAX_SMP_PER_INST) // can only be 0..32 at this point
{
- const int32_t samplesToSkip = ih.antSamp-MAX_SMP_PER_INST;
- for (j = 0; j < samplesToSkip; j++)
+ const int32_t samplesToSkip = ih.numSamples-MAX_SMP_PER_INST;
+ for (int32_t j = 0; j < samplesToSkip; j++)
{
fread(&extraSampleLengths[j], 4, 1, f); // used for skipping data in loadInstrSample()
- fseek(f, sizeof (sampleHeaderTyp)-4, SEEK_CUR);
+ fseek(f, sizeof (xmSmpHdr_t)-4, SEEK_CUR);
}
}
- for (j = 0; j < sampleHeadersToRead; j++)
+ for (int32_t j = 0; j < sampleHeadersToRead; j++)
{
- s = &instrTmp[i]->samp[j];
- src = &ih.samp[j];
+ s = &instrTmp[i]->smp[j];
+ src = &ih.smp[j];
// copy sample header elements to our sample struct
- s->len = src->len;
- s->repS = src->repS;
- s->repL = src->repL;
- s->vol = src->vol;
- s->fine = src->fine;
- s->typ = src->typ;
- s->pan = src->pan;
- s->relTon = src->relTon;
- memcpy(s->name, src->name, 22);
+ s->length = src->length;
+ s->loopStart = src->loopStart;
+ s->loopLength = src->loopLength;
+ s->volume = src->volume;
+ s->finetune = src->finetune;
+ s->flags = src->flags;
+ s->panning = src->panning;
+ s->relativeNote = src->relativeNote;
- // dst->pek is set up later
+ /* If the sample is 8-bit mono and nameLength (reserved) is 0xAD,
+ ** then this is a 4-bit ADPCM compressed sample (ModPlug Tracker).
+ */
+ if (src->nameLength == 0xAD && !(src->flags & (SAMPLE_16BIT | SAMPLE_STEREO)))
+ s->flags |= SAMPLE_ADPCM;
- // sanitize stuff broken/unsupported samples (FT2 doesn't do this, but we do!)
- if (s->vol > 64)
- s->vol = 64;
+ memcpy(s->name, src->name, 22);
- s->relTon = CLAMP(s->relTon, -48, 71);
+ // dst->dataPtr is set up later
}
}
@@ -324,18 +320,18 @@
if (instrTmp[i] == NULL)
return true; // empty instrument, let's just pretend it got loaded successfully
- uint16_t k = instrTmp[i]->antSamp;
+ uint16_t k = instrTmp[i]->numSamples;
if (k > MAX_SMP_PER_INST)
k = MAX_SMP_PER_INST;
- sampleTyp *s = instrTmp[i]->samp;
+ sample_t *s = instrTmp[i]->smp;
if (i > MAX_INST) // insNum > 128, just skip sample data
{
for (uint16_t j = 0; j < k; j++, s++)
{
- if (s->len > 0)
- fseek(f, s->len, SEEK_CUR);
+ if (s->length > 0)
+ fseek(f, s->length, SEEK_CUR);
}
}
else
@@ -342,72 +338,72 @@
{
for (uint16_t j = 0; j < k; j++, s++)
{
- // FT2: a sample with both forward loop and pingpong loop set results in pingpong
- if ((s->typ & 3) == 3)
- s->typ &= 0xFE; // remove forward loop flag
-
- int32_t l = s->len;
- if (l <= 0)
+ if (s->length <= 0)
{
- s->len = 0;
- s->repL = 0;
- s->repS = 0;
-
- if (s->typ & 32) // remove stereo flag if present
- s->typ &= ~32;
+ s->length = 0;
+ s->loopStart = 0;
+ s->loopLength = 0;
+ s->flags = 0;
}
else
{
- int32_t bytesToSkip = 0;
- if (l > MAX_SAMPLE_LEN)
+ const int32_t lengthInFile = s->length;
+
+ bool sample16Bit = !!(s->flags & SAMPLE_16BIT);
+ bool stereoSample = !!(s->flags & SAMPLE_STEREO);
+ bool adpcmSample = !!(s->flags & SAMPLE_ADPCM); // ModPlug Tracker
+
+ if (sample16Bit) // we use units of samples (not bytes like in FT2)
{
- bytesToSkip = l - MAX_SAMPLE_LEN;
- l = MAX_SAMPLE_LEN;
+ s->length >>= 1;
+ s->loopStart >>= 1;
+ s->loopLength >>= 1;
}
- if (!allocateTmpSmpData(s, l))
+ if (s->length > MAX_SAMPLE_LEN)
+ s->length = MAX_SAMPLE_LEN;
+
+ if (!allocateSmpData(s, s->length, sample16Bit))
{
loaderMsgBox("Not enough memory!");
return false;
}
- const int32_t bytesRead = (int32_t)fread(s->pek, 1, l, f);
- if (bytesRead < l)
+ if (adpcmSample)
{
- const int32_t bytesToClear = l - bytesRead;
- memset(&s->pek[bytesRead], 0, bytesToClear);
+ loadADPCMSample(f, s);
}
+ else
+ {
+ const int32_t sampleLengthInBytes = SAMPLE_LENGTH_BYTES(s);
+ fread(s->dataPtr, 1, sampleLengthInBytes, f);
- if (bytesToSkip > 0)
- fseek(f, bytesToSkip, SEEK_CUR);
+ if (sampleLengthInBytes < lengthInFile)
+ fseek(f, lengthInFile-sampleLengthInBytes, SEEK_CUR);
- delta2Samp(s->pek, l, s->typ);
+ delta2Samp(s->dataPtr, s->length, s->flags);
- if (s->typ & 32) // stereo sample - already downmixed to mono in delta2samp()
- {
- s->typ &= ~32; // remove stereo flag
+ if (stereoSample) // stereo sample - already downmixed to mono in delta2samp()
+ {
+ s->length >>= 1;
+ s->loopStart >>= 1;
+ s->loopLength >>= 1;
- s->len >>= 1;
- s->repL >>= 1;
- s->repS >>= 1;
-
- reallocateTmpSmpData(s, s->len); // dealloc unused memory
+ reallocateSmpData(s, s->length, sample16Bit); // dealloc unused memory
+ }
}
}
- // NON-FT2 FIX: Align to 2-byte if 16-bit sample
- if (s->typ & 16)
- {
- s->repL &= 0xFFFFFFFE;
- s->repS &= 0xFFFFFFFE;
- s->len &= 0xFFFFFFFE;
- }
+ // remove stereo flag if present (already handled)
+ if (s->flags & SAMPLE_STEREO)
+ s->flags &= ~SAMPLE_STEREO;
}
}
- if (instrTmp[i]->antSamp > MAX_SMP_PER_INST)
+ // skip sample headers if we have more than 16 samples in instrument
+ if (instrTmp[i]->numSamples > MAX_SMP_PER_INST)
{
- const int32_t samplesToSkip = instrTmp[i]->antSamp-MAX_SMP_PER_INST;
+ const int32_t samplesToSkip = instrTmp[i]->numSamples-MAX_SMP_PER_INST;
for (i = 0; i < samplesToSkip; i++)
{
if (extraSampleLengths[i] > 0)
@@ -418,80 +414,80 @@
return true;
}
-static bool loadPatterns(FILE *f, uint16_t antPtn)
+static bool loadPatterns(FILE *f, uint16_t antPtn, uint16_t xmVersion)
{
uint8_t tmpLen;
- patternHeaderTyp ph;
+ xmPatHdr_t ph;
bool pattLenWarn = false;
for (uint16_t i = 0; i < antPtn; i++)
{
- if (fread(&ph.patternHeaderSize, 4, 1, f) != 1)
+ if (fread(&ph.headerSize, 4, 1, f) != 1)
goto pattCorrupt;
- if (fread(&ph.typ, 1, 1, f) != 1)
+ if (fread(&ph.type, 1, 1, f) != 1)
goto pattCorrupt;
- ph.pattLen = 0;
- if (songTmp.ver == 0x0102)
+ ph.numRows = 0;
+ if (xmVersion == 0x0102)
{
if (fread(&tmpLen, 1, 1, f) != 1)
goto pattCorrupt;
- if (fread(&ph.dataLen, 2, 1, f) != 1)
+ if (fread(&ph.dataSize, 2, 1, f) != 1)
goto pattCorrupt;
- ph.pattLen = tmpLen + 1; // +1 in v1.02
+ ph.numRows = tmpLen + 1; // +1 in v1.02
- if (ph.patternHeaderSize > 8)
- fseek(f, ph.patternHeaderSize - 8, SEEK_CUR);
+ if (ph.headerSize > 8)
+ fseek(f, ph.headerSize - 8, SEEK_CUR);
}
else
{
- if (fread(&ph.pattLen, 2, 1, f) != 1)
+ if (fread(&ph.numRows, 2, 1, f) != 1)
goto pattCorrupt;
- if (fread(&ph.dataLen, 2, 1, f) != 1)
+ if (fread(&ph.dataSize, 2, 1, f) != 1)
goto pattCorrupt;
- if (ph.patternHeaderSize > 9)
- fseek(f, ph.patternHeaderSize - 9, SEEK_CUR);
+ if (ph.headerSize > 9)
+ fseek(f, ph.headerSize - 9, SEEK_CUR);
}
if (feof(f))
goto pattCorrupt;
- pattLensTmp[i] = ph.pattLen;
- if (pattLensTmp[i] > MAX_PATT_LEN)
+ patternNumRowsTmp[i] = ph.numRows;
+ if (patternNumRowsTmp[i] > MAX_PATT_LEN)
{
- pattLensTmp[i] = MAX_PATT_LEN;
+ patternNumRowsTmp[i] = MAX_PATT_LEN;
pattLenWarn = true;
}
- if (ph.dataLen > 0)
+ if (ph.dataSize > 0)
{
- if (!allocateTmpPatt(i, pattLensTmp[i]))
+ if (!allocateTmpPatt(i, patternNumRowsTmp[i]))
{
loaderMsgBox("Not enough memory!");
return false;
}
- if (fread(packedPattData, 1, ph.dataLen, f) != ph.dataLen)
+ if (fread(packedPattData, 1, ph.dataSize, f) != ph.dataSize)
goto pattCorrupt;
- unpackPatt((uint8_t *)pattTmp[i], packedPattData, pattLensTmp[i], songTmp.antChn);
- clearUnusedChannels(pattTmp[i], pattLensTmp[i], songTmp.antChn);
+ unpackPatt((uint8_t *)patternTmp[i], packedPattData, patternNumRowsTmp[i], songTmp.numChannels);
+ clearUnusedChannels(patternTmp[i], patternNumRowsTmp[i], songTmp.numChannels);
}
if (tmpPatternEmpty(i))
{
- if (pattTmp[i] != NULL)
+ if (patternTmp[i] != NULL)
{
- free(pattTmp[i]);
- pattTmp[i] = NULL;
+ free(patternTmp[i]);
+ patternTmp[i] = NULL;
}
- pattLensTmp[i] = 64;
+ patternNumRowsTmp[i] = 64;
}
}
@@ -512,14 +508,14 @@
if (dst == NULL)
return;
- const int32_t srcEnd = len * (sizeof (tonTyp) * antChn);
+ const int32_t srcEnd = len * (sizeof (note_t) * antChn);
int32_t srcIdx = 0;
int32_t numChannels = antChn;
- if (numChannels > MAX_VOICES)
- numChannels = MAX_VOICES;
+ if (numChannels > MAX_CHANNELS)
+ numChannels = MAX_CHANNELS;
- const int32_t pitch = sizeof (tonTyp) * (MAX_VOICES - antChn);
+ const int32_t pitch = sizeof (note_t) * (MAX_CHANNELS - antChn);
for (int32_t i = 0; i < len; i++)
{
for (j = 0; j < numChannels; j++)
@@ -545,7 +541,7 @@
*dst++ = *src++;
}
- srcIdx += sizeof (tonTyp);
+ srcIdx += sizeof (note_t);
}
// if more than 32 channels, skip rest of the channels for this row
@@ -571,45 +567,32 @@
src++;
}
- srcIdx += sizeof (tonTyp);
+ srcIdx += sizeof (note_t);
}
// if song has <32 channels, align pointer to next row (skip unused channels)
- if (antChn < MAX_VOICES)
+ if (antChn < MAX_CHANNELS)
dst += pitch;
}
}
-static void sanitizeInstrument(instrTyp *ins) // FT2 doesn't do this, but we do!
+static void loadADPCMSample(FILE *f, sample_t *s) // ModPlug Tracker
{
- ins->midiProgram = CLAMP(ins->midiProgram, 0, 127);
- ins->midiBend = CLAMP(ins->midiBend, 0, 36);
+ int8_t deltaLUT[16];
+ fread(deltaLUT, 1, 16, f);
- if (ins->midiChannel > 15) ins->midiChannel = 15;
- if (ins->vibDepth > 0x0F) ins->vibDepth = 0x0F;
- if (ins->vibRate > 0x3F) ins->vibRate = 0x3F;
- if (ins->vibTyp > 3) ins->vibTyp = 0;
+ int8_t *dataPtr = s->dataPtr;
+ const int32_t dataLength = (s->length + 1) / 2;
- for (int32_t i = 0; i < 96; i++)
+ int8_t currSample = 0;
+ for (int32_t i = 0; i < dataLength; i++)
{
- if (ins->ta[i] >= MAX_SMP_PER_INST)
- ins->ta[i] = MAX_SMP_PER_INST-1;
- }
+ const uint8_t nibbles = (uint8_t)fgetc(f);
- if (ins->envVPAnt > 12) ins->envVPAnt = 12;
- if (ins->envVRepS > 11) ins->envVRepS = 11;
- if (ins->envVRepE > 11) ins->envVRepE = 11;
- if (ins->envVSust > 11) ins->envVSust = 11;
- if (ins->envPPAnt > 12) ins->envPPAnt = 12;
- if (ins->envPRepS > 11) ins->envPRepS = 11;
- if (ins->envPRepE > 11) ins->envPRepE = 11;
- if (ins->envPSust > 11) ins->envPSust = 11;
+ currSample += deltaLUT[nibbles & 0x0F];
+ *dataPtr++ = currSample;
- for (int32_t i= 0; i < 12; i++)
- {
- if ((uint16_t)ins->envVP[i][0] > 32767) ins->envVP[i][0] = 32767;
- if ((uint16_t)ins->envPP[i][0] > 32767) ins->envPP[i][0] = 32767;
- if ((uint16_t)ins->envVP[i][1] > 64) ins->envVP[i][1] = 64;
- if ((uint16_t)ins->envPP[i][1] > 63) ins->envPP[i][1] = 63;
+ currSample += deltaLUT[nibbles >> 4];
+ *dataPtr++ = currSample;
}
}
--- a/src/rtmidi/rtmidi_c.cpp
+++ b/src/rtmidi/rtmidi_c.cpp
@@ -3,6 +3,11 @@
#include "rtmidi_c.h"
#include "RtMidi.h"
+// 8bb: hide POSIX warnings
+#ifdef _MSC_VER
+#pragma warning(disable: 4996)
+#endif
+
/* Compile-time assertions that will break if the enums are changed in
* the future without synchronizing them properly. If you get (g++)
* "error: ‘StaticAssert<b>::StaticAssert() [with bool b = false]’ is
@@ -128,7 +133,7 @@
} catch (const RtMidiError & err) {
device->ok = false;
device->msg = err.what ();
- return -1;
+ return (unsigned int)-1;
}
}
--- /dev/null
+++ b/src/scopes/ft2_scope_macros.h
@@ -1,0 +1,256 @@
+#pragma once
+
+#include <stdint.h>
+#include "ft2_scopes.h"
+
+/* ----------------------------------------------------------------------- */
+/* SCOPE DRAWING MACROS */
+/* ----------------------------------------------------------------------- */
+
+#define SCOPE_REGS_NO_LOOP \
+ const int32_t volume = s->volume; \
+ const int32_t sampleEnd = s->sampleEnd; \
+ const uint32_t delta = (uint32_t)(s->delta >> (SCOPE_FRAC_BITS-10)); \
+ const uint32_t color = video.palette[PAL_PATTEXT]; \
+ const uint32_t width = x + w; \
+ int32_t sample; \
+ int32_t position = s->position; \
+ uint32_t positionFrac = 0;
+
+#define SCOPE_REGS_LOOP \
+ const int32_t volume = s->volume; \
+ const int32_t sampleEnd = s->sampleEnd; \
+ const int32_t loopStart = s->loopStart; \
+ const int32_t loopLength = s->loopLength; \
+ const uint32_t delta = (uint32_t)(s->delta >> (SCOPE_FRAC_BITS-10)); \
+ const uint32_t color = video.palette[PAL_PATTEXT]; \
+ const uint32_t width = x + w; \
+ int32_t sample; \
+ int32_t position = s->position; \
+ uint32_t positionFrac = 0;
+
+#define SCOPE_REGS_PINGPONG \
+ const int32_t volume = s->volume; \
+ const int32_t sampleEnd = s->sampleEnd; \
+ const int32_t loopStart = s->loopStart; \
+ const int32_t loopLength = s->loopLength; \
+ const uint32_t delta = (uint32_t)(s->delta >> (SCOPE_FRAC_BITS-10)); \
+ const uint32_t color = video.palette[PAL_PATTEXT]; \
+ const uint32_t width = x + w; \
+ int32_t sample; \
+ int32_t position = s->position; \
+ uint32_t positionFrac = 0; \
+ int32_t direction = s->direction;
+
+#define LINED_SCOPE_REGS_NO_LOOP \
+ const int32_t volume = s->volume; \
+ const int32_t sampleEnd = s->sampleEnd; \
+ const uint32_t delta = (uint32_t)(s->delta >> (SCOPE_FRAC_BITS-10)); \
+ const uint32_t width = (x + w) - 1; \
+ int32_t sample, sample2; \
+ int32_t y1, y2; \
+ int32_t position = s->position; \
+ uint32_t positionFrac = 0;
+
+#define LINED_SCOPE_REGS_LOOP \
+ const int32_t volume = s->volume; \
+ const int32_t sampleEnd = s->sampleEnd; \
+ const int32_t loopStart = s->loopStart; \
+ const int32_t loopLength = s->loopLength; \
+ const uint32_t delta = (uint32_t)(s->delta >> (SCOPE_FRAC_BITS-10)); \
+ const uint32_t width = (x + w) - 1; \
+ int32_t sample, sample2; \
+ int32_t y1, y2; \
+ int32_t position = s->position; \
+ uint32_t positionFrac = 0;
+
+#define LINED_SCOPE_REGS_PINGPONG \
+ const int32_t volume = s->volume; \
+ const int32_t sampleEnd = s->sampleEnd; \
+ const int32_t loopStart = s->loopStart; \
+ const int32_t loopLength = s->loopLength; \
+ const uint32_t delta = (uint32_t)(s->delta >> (SCOPE_FRAC_BITS-10)); \
+ const uint32_t width = (x + w) - 1; \
+ int32_t sample, sample2; \
+ int32_t y1, y2; \
+ int32_t position = s->position; \
+ uint32_t positionFrac = 0; \
+ int32_t direction = s->direction;
+
+/* Note: Sample data already has a fixed tap samples at the end of the sample,
+** so that an out-of-bounds read is OK and reads the correct interpolation tap.
+*/
+
+#define COLLECT_LERP_SAMPLES8 \
+ sample = s->base8[position+0] << 8; \
+ sample2 = s->base8[position+1] << 8;
+
+#define COLLECT_LERP_SAMPLES16 \
+ sample = s->base16[position+0]; \
+ sample2 = s->base16[position+1];
+
+#define DO_LERP \
+ const int32_t frac = (uint32_t)positionFrac >> 1; /* 0..32767 */ \
+ sample2 -= sample; \
+ sample2 = (sample2 * frac) >> 15; \
+ sample += sample2; \
+
+#define DO_LERP_BIDI \
+ int32_t frac = (uint32_t)positionFrac >> 1; /* 0..32767 */ \
+ if (direction == -1) frac ^= 32767; /* negate frac */ \
+ sample2 -= sample; \
+ sample2 = (sample2 * frac) >> 15; \
+ sample += sample2;
+
+#define GET_LERP_SMP8 \
+ COLLECT_LERP_SAMPLES8 \
+ DO_LERP
+
+#define GET_LERP_SMP16 \
+ COLLECT_LERP_SAMPLES16 \
+ DO_LERP
+
+#define GET_LERP_SMP8_BIDI \
+ COLLECT_LERP_SAMPLES8 \
+ DO_LERP_BIDI
+
+#define GET_LERP_SMP16_BIDI \
+ COLLECT_LERP_SAMPLES16 \
+ DO_LERP_BIDI
+
+#define SCOPE_GET_SMP8 \
+ if (s->active) \
+ sample = (s->base8[position] * volume) >> 8; \
+ else \
+ sample = 0;
+
+#define SCOPE_GET_SMP16 \
+ if (s->active) \
+ sample = (s->base16[position] * volume) >> 16; \
+ else \
+ sample = 0;
+
+#define SCOPE_GET_LERP_SMP8 \
+ if (s->active) \
+ { \
+ GET_LERP_SMP8 \
+ sample = (sample * volume) >> 16; \
+ } \
+ else \
+ { \
+ sample = 0; \
+ }
+
+#define SCOPE_GET_LERP_SMP16 \
+ if (s->active) \
+ { \
+ GET_LERP_SMP16 \
+ sample = (sample * volume) >> 16; \
+ } \
+ else \
+ { \
+ sample = 0; \
+ }
+
+#define SCOPE_GET_LERP_SMP8_BIDI \
+ if (s->active) \
+ { \
+ GET_LERP_SMP8_BIDI \
+ sample = (sample * volume) >> 16; \
+ } \
+ else \
+ { \
+ sample = 0; \
+ }
+
+#define SCOPE_GET_LERP_SMP16_BIDI \
+ if (s->active) \
+ { \
+ GET_LERP_SMP16_BIDI \
+ sample = (sample * volume) >> 16; \
+ } \
+ else \
+ { \
+ sample = 0; \
+ }
+
+#define SCOPE_UPDATE_DRAWPOS \
+ positionFrac += delta; \
+ position += positionFrac >> 16; \
+ positionFrac &= 0xFFFF;
+
+#define SCOPE_UPDATE_DRAWPOS_PINGPONG \
+ positionFrac += delta; \
+ position += (int32_t)(positionFrac >> 16) * direction; \
+ positionFrac &= 0xFFFF;
+
+#define SCOPE_DRAW_SMP \
+ video.frameBuffer[((lineY - sample) * SCREEN_W) + x] = color;
+
+#define LINED_SCOPE_PREPARE_SMP8 \
+ SCOPE_GET_SMP8 \
+ y1 = lineY - sample; \
+ SCOPE_UPDATE_DRAWPOS
+
+#define LINED_SCOPE_PREPARE_SMP16 \
+ SCOPE_GET_SMP16 \
+ y1 = lineY - sample; \
+ SCOPE_UPDATE_DRAWPOS
+
+#define LINED_SCOPE_PREPARE_LERP_SMP8 \
+ SCOPE_GET_LERP_SMP8 \
+ y1 = lineY - sample; \
+ SCOPE_UPDATE_DRAWPOS
+
+#define LINED_SCOPE_PREPARE_LERP_SMP16 \
+ SCOPE_GET_LERP_SMP16 \
+ y1 = lineY - sample; \
+ SCOPE_UPDATE_DRAWPOS
+
+#define LINED_SCOPE_PREPARE_LERP_SMP8_BIDI \
+ SCOPE_GET_LERP_SMP8_BIDI \
+ y1 = lineY - sample; \
+ SCOPE_UPDATE_DRAWPOS
+
+#define LINED_SCOPE_PREPARE_LERP_SMP16_BIDI \
+ SCOPE_GET_LERP_SMP16_BIDI \
+ y1 = lineY - sample; \
+ SCOPE_UPDATE_DRAWPOS
+
+#define LINED_SCOPE_DRAW_SMP \
+ y2 = lineY - sample; \
+ scopeLine(x, y1, y2); \
+ y1 = y2; \
+
+#define SCOPE_HANDLE_POS_NO_LOOP \
+ if (position >= sampleEnd) \
+ s->active = false;
+
+#define SCOPE_HANDLE_POS_LOOP \
+ if (position >= sampleEnd) \
+ { \
+ if (loopLength >= 2) \
+ position = loopStart + ((position - sampleEnd) % loopLength); \
+ else \
+ position = loopStart; \
+ }
+
+#define SCOPE_HANDLE_POS_PINGPONG \
+ if (direction == -1 && position < loopStart) \
+ { \
+ direction = 1; /* change direction to forwards */ \
+ \
+ if (loopLength >= 2) \
+ position = loopStart + ((loopStart - position - 1) % loopLength); \
+ else \
+ position = loopStart; \
+ } \
+ else if (position >= sampleEnd) \
+ { \
+ direction = -1; /* change direction to backwards */ \
+ \
+ if (loopLength >= 2) \
+ position = (sampleEnd - 1) - ((position - sampleEnd) % loopLength); \
+ else \
+ position = sampleEnd - 1; \
+ }
--- /dev/null
+++ b/src/scopes/ft2_scopedraw.c
@@ -1,0 +1,244 @@
+#include "../ft2_video.h"
+#include "../ft2_palette.h"
+#include "ft2_scopes.h"
+#include "ft2_scopedraw.h"
+#include "ft2_scope_macros.h"
+#include "../ft2_cpu.h"
+
+static void scopeLine(int32_t x1, int32_t y1, int32_t y2);
+
+/* ----------------------------------------------------------------------- */
+/* SCOPE DRAWING ROUTINES */
+/* ----------------------------------------------------------------------- */
+
+static void scopeDrawNoLoop_8bit(scope_t *s, uint32_t x, uint32_t lineY, uint32_t w)
+{
+ SCOPE_REGS_NO_LOOP
+
+ for (; x < width; x++)
+ {
+ SCOPE_GET_SMP8
+ SCOPE_DRAW_SMP
+ SCOPE_UPDATE_DRAWPOS
+ SCOPE_HANDLE_POS_NO_LOOP
+ }
+}
+
+static void scopeDrawLoop_8bit(scope_t *s, uint32_t x, uint32_t lineY, uint32_t w)
+{
+ SCOPE_REGS_LOOP
+
+ for (; x < width; x++)
+ {
+ SCOPE_GET_SMP8
+ SCOPE_DRAW_SMP
+ SCOPE_UPDATE_DRAWPOS
+ SCOPE_HANDLE_POS_LOOP
+ }
+}
+
+static void scopeDrawPingPong_8bit(scope_t *s, uint32_t x, uint32_t lineY, uint32_t w)
+{
+ SCOPE_REGS_PINGPONG
+
+ for (; x < width; x++)
+ {
+ SCOPE_GET_SMP8
+ SCOPE_DRAW_SMP
+ SCOPE_UPDATE_DRAWPOS_PINGPONG
+ SCOPE_HANDLE_POS_PINGPONG
+ }
+}
+
+static void scopeDrawNoLoop_16bit(scope_t *s, uint32_t x, uint32_t lineY, uint32_t w)
+{
+ SCOPE_REGS_NO_LOOP
+
+ for (; x < width; x++)
+ {
+ SCOPE_GET_SMP16
+ SCOPE_DRAW_SMP
+ SCOPE_UPDATE_DRAWPOS
+ SCOPE_HANDLE_POS_NO_LOOP
+ }
+}
+
+static void scopeDrawLoop_16bit(scope_t *s, uint32_t x, uint32_t lineY, uint32_t w)
+{
+ SCOPE_REGS_LOOP
+
+ for (; x < width; x++)
+ {
+ SCOPE_GET_SMP16
+ SCOPE_DRAW_SMP
+ SCOPE_UPDATE_DRAWPOS
+ SCOPE_HANDLE_POS_LOOP
+ }
+}
+
+static void scopeDrawPingPong_16bit(scope_t *s, uint32_t x, uint32_t lineY, uint32_t w)
+{
+ SCOPE_REGS_PINGPONG
+
+ for (; x < width; x++)
+ {
+ SCOPE_GET_SMP16
+ SCOPE_DRAW_SMP
+ SCOPE_UPDATE_DRAWPOS_PINGPONG
+ SCOPE_HANDLE_POS_PINGPONG
+ }
+}
+
+/* ----------------------------------------------------------------------- */
+/* INTERPOLATED SCOPE DRAWING ROUTINES */
+/* ----------------------------------------------------------------------- */
+
+static void linedScopeDrawNoLoop_8bit(scope_t *s, uint32_t x, uint32_t lineY, uint32_t w)
+{
+ LINED_SCOPE_REGS_NO_LOOP
+ LINED_SCOPE_PREPARE_LERP_SMP8
+ SCOPE_HANDLE_POS_NO_LOOP
+
+ for (; x < width; x++)
+ {
+ SCOPE_GET_LERP_SMP8
+ LINED_SCOPE_DRAW_SMP
+ SCOPE_UPDATE_DRAWPOS
+ SCOPE_HANDLE_POS_NO_LOOP
+ }
+}
+
+static void linedScopeDrawLoop_8bit(scope_t *s, uint32_t x, uint32_t lineY, uint32_t w)
+{
+ LINED_SCOPE_REGS_LOOP
+ LINED_SCOPE_PREPARE_LERP_SMP8
+ SCOPE_HANDLE_POS_LOOP
+
+ for (; x < width; x++)
+ {
+ SCOPE_GET_LERP_SMP8
+ LINED_SCOPE_DRAW_SMP
+ SCOPE_UPDATE_DRAWPOS
+ SCOPE_HANDLE_POS_LOOP
+ }
+}
+
+static void linedScopeDrawPingPong_8bit(scope_t *s, uint32_t x, uint32_t lineY, uint32_t w)
+{
+ LINED_SCOPE_REGS_PINGPONG
+ LINED_SCOPE_PREPARE_LERP_SMP8_BIDI
+ SCOPE_HANDLE_POS_PINGPONG
+
+ for (; x < width; x++)
+ {
+ SCOPE_GET_LERP_SMP8_BIDI
+ LINED_SCOPE_DRAW_SMP
+ SCOPE_UPDATE_DRAWPOS_PINGPONG
+ SCOPE_HANDLE_POS_PINGPONG
+ }
+}
+
+static void linedScopeDrawNoLoop_16bit(scope_t *s, uint32_t x, uint32_t lineY, uint32_t w)
+{
+ LINED_SCOPE_REGS_NO_LOOP
+ LINED_SCOPE_PREPARE_LERP_SMP16
+ SCOPE_HANDLE_POS_NO_LOOP
+
+ for (; x < width; x++)
+ {
+ SCOPE_GET_LERP_SMP16
+ LINED_SCOPE_DRAW_SMP
+ SCOPE_UPDATE_DRAWPOS
+ SCOPE_HANDLE_POS_NO_LOOP
+ }
+}
+
+static void linedScopeDrawLoop_16bit(scope_t *s, uint32_t x, uint32_t lineY, uint32_t w)
+{
+ LINED_SCOPE_REGS_LOOP
+ LINED_SCOPE_PREPARE_LERP_SMP16
+ SCOPE_HANDLE_POS_LOOP
+
+ for (; x < width; x++)
+ {
+ SCOPE_GET_LERP_SMP16
+ LINED_SCOPE_DRAW_SMP
+ SCOPE_UPDATE_DRAWPOS
+ SCOPE_HANDLE_POS_LOOP
+ }
+}
+
+static void linedScopeDrawPingPong_16bit(scope_t *s, uint32_t x, uint32_t lineY, uint32_t w)
+{
+ LINED_SCOPE_REGS_PINGPONG
+ LINED_SCOPE_PREPARE_LERP_SMP16_BIDI
+ SCOPE_HANDLE_POS_PINGPONG
+
+ for (; x < width; x++)
+ {
+ SCOPE_GET_LERP_SMP16_BIDI
+ LINED_SCOPE_DRAW_SMP
+ SCOPE_UPDATE_DRAWPOS_PINGPONG
+ SCOPE_HANDLE_POS_PINGPONG
+ }
+}
+
+// -----------------------------------------------------------------------
+
+static void scopeLine(int32_t x1, int32_t y1, int32_t y2)
+{
+ const int32_t dy = y2 - y1;
+ const int32_t sy = SGN(dy);
+ const uint32_t color = video.palette[PAL_PATTEXT];
+ const int32_t pitch = sy * SCREEN_W;
+
+ uint32_t *dst32 = &video.frameBuffer[(y1 * SCREEN_W) + x1];
+
+ *dst32 = color; // set first pixel
+
+ int32_t ay = ABS(dy);
+ if (ay <= 1)
+ {
+ if (ay != 0)
+ dst32 += pitch;
+
+ *++dst32 = color;
+ return;
+ }
+
+ int32_t d = 1 - ay;
+
+ ay <<= 1;
+ while (y1 != y2)
+ {
+ if (d >= 0)
+ {
+ d -= ay;
+ dst32++;
+ }
+
+ y1 += sy;
+ d += 2;
+
+ dst32 += pitch;
+ *dst32 = color;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+const scopeDrawRoutine scopeDrawRoutineTable[12] =
+{
+ (scopeDrawRoutine)scopeDrawNoLoop_8bit,
+ (scopeDrawRoutine)scopeDrawLoop_8bit,
+ (scopeDrawRoutine)scopeDrawPingPong_8bit,
+ (scopeDrawRoutine)scopeDrawNoLoop_16bit,
+ (scopeDrawRoutine)scopeDrawLoop_16bit,
+ (scopeDrawRoutine)scopeDrawPingPong_16bit,
+ (scopeDrawRoutine)linedScopeDrawNoLoop_8bit,
+ (scopeDrawRoutine)linedScopeDrawLoop_8bit,
+ (scopeDrawRoutine)linedScopeDrawPingPong_8bit,
+ (scopeDrawRoutine)linedScopeDrawNoLoop_16bit,
+ (scopeDrawRoutine)linedScopeDrawLoop_16bit,
+ (scopeDrawRoutine)linedScopeDrawPingPong_16bit
+};
--- /dev/null
+++ b/src/scopes/ft2_scopedraw.h
@@ -1,0 +1,8 @@
+#pragma once
+
+#include <stdint.h>
+#include "ft2_scopes.h"
+
+typedef void (*scopeDrawRoutine)(const scope_t *, uint32_t, uint32_t, uint32_t);
+
+extern const scopeDrawRoutine scopeDrawRoutineTable[12]; // ft2_scopedraw.c
--- /dev/null
+++ b/src/scopes/ft2_scopes.c
@@ -1,0 +1,587 @@
+// for finding memory leaks in debug mode with Visual Studio
+#if defined _DEBUG && defined _MSC_VER
+#include <crtdbg.h>
+#endif
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <math.h> // modf()
+#ifndef _WIN32
+#include <unistd.h> // usleep()
+#endif
+#include "../ft2_header.h"
+#include "../ft2_events.h"
+#include "../ft2_config.h"
+#include "../ft2_audio.h"
+#include "../ft2_gui.h"
+#include "../ft2_midi.h"
+#include "../ft2_bmp.h"
+#include "../ft2_mouse.h"
+#include "../ft2_video.h"
+#include "../ft2_tables.h"
+#include "../ft2_structs.h"
+#include "ft2_scopes.h"
+#include "ft2_scopedraw.h"
+
+static volatile bool scopesUpdatingFlag, scopesDisplayingFlag;
+static uint32_t scopeTimeLen, scopeTimeLenFrac;
+static uint64_t timeNext64, timeNext64Frac;
+static volatile scope_t scope[MAX_CHANNELS];
+static SDL_Thread *scopeThread;
+
+lastChInstr_t lastChInstr[MAX_CHANNELS]; // global
+
+int32_t getSamplePosition(uint8_t ch)
+{
+ if (ch >= song.numChannels)
+ return -1;
+
+ volatile scope_t *sc = &scope[ch];
+
+ // cache some stuff
+ volatile bool active = sc->active;
+ volatile int32_t position = sc->position;
+ volatile int32_t sampleEnd = sc->sampleEnd;
+
+ if (!active || sampleEnd == 0)
+ return -1;
+
+ if (position >= 0 && position < sampleEnd)
+ return position;
+
+ return -1; // not active or overflown
+}
+
+void stopAllScopes(void)
+{
+ // wait for scopes to finish updating
+ while (scopesUpdatingFlag);
+
+ volatile scope_t *sc = scope;
+ for (int32_t i = 0; i < MAX_CHANNELS; i++, sc++)
+ sc->active = false;
+
+ // wait for scope displaying to be done (safety)
+ while (scopesDisplayingFlag);
+}
+
+// toggle mute
+static void setChannel(int32_t chNr, bool on)
+{
+ channel_t *ch = &channel[chNr];
+
+ ch->channelOff = !on;
+ if (ch->channelOff)
+ {
+ ch->efx = 0;
+ ch->efxData = 0;
+ ch->realVol = 0;
+ ch->outVol = 0;
+ ch->oldVol = 0;
+ ch->fFinalVol = 0.0f;
+ ch->outPan = 128;
+ ch->oldPan = 128;
+ ch->finalPan = 128;
+ ch->status = IS_Vol;
+
+ ch->envSustainActive = false; // non-FT2 bug fix for stuck piano keys
+ }
+
+ scope[chNr].wasCleared = false;
+}
+
+static void drawScopeNumber(uint16_t scopeXOffs, uint16_t scopeYOffs, uint8_t chNr, bool outline)
+{
+ scopeXOffs++;
+ scopeYOffs++;
+ chNr++;
+
+ if (outline)
+ {
+ if (chNr < 10) // one digit?
+ {
+ charOutOutlined(scopeXOffs, scopeYOffs, PAL_MOUSEPT, '0' + chNr);
+ }
+ else
+ {
+ charOutOutlined(scopeXOffs, scopeYOffs, PAL_MOUSEPT, chDecTab1[chNr]);
+ charOutOutlined(scopeXOffs + 7, scopeYOffs, PAL_MOUSEPT, chDecTab2[chNr]);
+ }
+ }
+ else
+ {
+ if (chNr < 10) // one digit?
+ {
+ charOut(scopeXOffs, scopeYOffs, PAL_MOUSEPT, '0' + chNr);
+ }
+ else
+ {
+ charOut(scopeXOffs, scopeYOffs, PAL_MOUSEPT, chDecTab1[chNr]);
+ charOut(scopeXOffs + 7, scopeYOffs, PAL_MOUSEPT, chDecTab2[chNr]);
+ }
+ }
+}
+
+static void redrawScope(int32_t ch)
+{
+ int32_t i;
+
+ int32_t chansPerRow = (uint32_t)song.numChannels >> 1;
+ int32_t chanLookup = chansPerRow - 1;
+ const uint16_t *scopeLens = scopeLenTab[chanLookup];
+
+ // get x,y,len for scope according to channel (we must do it this way since 'len' can differ!)
+
+ uint16_t x = 2;
+ uint16_t y = 94;
+
+ uint16_t scopeLen = 0; // prevent compiler warning
+ for (i = 0; i < song.numChannels; i++)
+ {
+ scopeLen = scopeLens[i];
+
+ if (i == chansPerRow) // did we reach end of row?
+ {
+ // yes, go one row down
+ x = 2;
+ y += 39;
+ }
+
+ if (i == ch)
+ break;
+
+ // adjust position to next channel
+ x += scopeLen + 3;
+ }
+
+ drawFramework(x, y, scopeLen + 2, 38, FRAMEWORK_TYPE2);
+
+ // draw mute graphics if channel is muted
+ if (!editor.chnMode[i])
+ {
+ const uint16_t muteGfxLen = scopeMuteBMP_Widths[chanLookup];
+ const uint16_t muteGfxX = x + ((scopeLen - muteGfxLen) >> 1);
+
+ blitFastClipX(muteGfxX, y + 6, bmp.scopeMute+scopeMuteBMP_Offs[chanLookup], 162, scopeMuteBMP_Heights[chanLookup], muteGfxLen);
+
+ if (config.ptnChnNumbers)
+ drawScopeNumber(x + 1, y + 1, (uint8_t)i, true);
+ }
+
+ scope[ch].wasCleared = false;
+}
+
+void refreshScopes(void)
+{
+ for (int32_t i = 0; i < MAX_CHANNELS; i++)
+ scope[i].wasCleared = false;
+}
+
+static void channelMode(int32_t chn)
+{
+ int32_t i;
+
+ assert(chn < song.numChannels);
+
+ bool m = mouse.leftButtonPressed && !mouse.rightButtonPressed;
+ bool m2 = mouse.rightButtonPressed && mouse.leftButtonPressed;
+
+ if (m2)
+ {
+ bool test = false;
+ for (i = 0; i < song.numChannels; i++)
+ {
+ if (i != chn && !editor.chnMode[i])
+ test = true;
+ }
+
+ if (test)
+ {
+ for (i = 0; i < song.numChannels; i++)
+ editor.chnMode[i] = true;
+ }
+ else
+ {
+ for (i = 0; i < song.numChannels; i++)
+ editor.chnMode[i] = (i == chn);
+ }
+ }
+ else if (m)
+ {
+ editor.chnMode[chn] ^= 1;
+ }
+ else
+ {
+ if (editor.chnMode[chn])
+ {
+ config.multiRecChn[chn] ^= 1;
+ }
+ else
+ {
+ config.multiRecChn[chn] = true;
+ editor.chnMode[chn] = true;
+ m = true;
+ }
+ }
+
+ for (i = 0; i < song.numChannels; i++)
+ setChannel(i, editor.chnMode[i]);
+
+ if (m2)
+ {
+ for (i = 0; i < song.numChannels; i++)
+ redrawScope(i);
+ }
+ else
+ {
+ redrawScope(chn);
+ }
+}
+
+bool testScopesMouseDown(void)
+{
+ int32_t i;
+
+ if (!ui.scopesShown)
+ return false;
+
+ if (mouse.y >= 95 && mouse.y <= 169 && mouse.x >= 3 && mouse.x <= 288)
+ {
+ if (mouse.y > 130 && mouse.y < 134)
+ return true;
+
+ int32_t chansPerRow = (uint32_t)song.numChannels >> 1;
+ const uint16_t *scopeLens = scopeLenTab[chansPerRow-1];
+
+ // find out if we clicked inside a scope
+ uint16_t x = 3;
+ for (i = 0; i < chansPerRow; i++)
+ {
+ if (mouse.x >= x && mouse.x < x+scopeLens[i])
+ break;
+
+ x += scopeLens[i]+3;
+ }
+
+ if (i == chansPerRow)
+ return true; // scope framework was clicked instead
+
+ int32_t chanToToggle = i;
+ if (mouse.y >= 134) // second row of scopes?
+ chanToToggle += chansPerRow; // yes, increase lookup offset
+
+ channelMode(chanToToggle);
+ return true;
+ }
+
+ return false;
+}
+
+static void scopeTrigger(int32_t ch, const sample_t *s, int32_t playOffset)
+{
+ volatile scope_t tempState;
+ volatile scope_t *sc = &scope[ch];
+
+ int32_t length = s->length;
+ int32_t loopStart = s->loopStart;
+ int32_t loopLength = s->loopLength;
+ int32_t loopEnd = s->loopStart + s->loopLength;
+ uint8_t loopType = GET_LOOPTYPE(s->flags);
+ bool sample16Bit = !!(s->flags & SAMPLE_16BIT);
+
+ if (s->dataPtr == NULL || length < 1)
+ {
+ sc->active = false; // shut down scope (illegal parameters)
+ return;
+ }
+
+ tempState = *sc; // get copy of current scope state
+
+ if (loopLength < 1) // disable loop if loopLength is below 1
+ loopType = 0;
+
+ if (sample16Bit)
+ tempState.base16 = (const int16_t *)s->dataPtr;
+ else
+ tempState.base8 = s->dataPtr;
+
+ tempState.sample16Bit = sample16Bit;
+ tempState.loopType = loopType;
+ tempState.direction = 1; // forwards
+ tempState.sampleEnd = (loopType == LOOP_OFF) ? length : loopEnd;
+ tempState.loopStart = loopStart;
+ tempState.loopLength = loopLength;
+ tempState.position = playOffset;
+ tempState.positionFrac = 0;
+
+ // if position overflows (f.ex. through 9xx command), shut down scopes
+ if (tempState.position >= tempState.sampleEnd)
+ {
+ sc->active = false;
+ return;
+ }
+
+ tempState.active = true;
+
+ /* Update live scope now.
+ ** In theory it -can- be written to in the middle of a cached read,
+ ** then the read thread writes its own non-updated cached copy back and
+ ** the trigger never happens. So far I have never seen it happen,
+ ** so it's probably very rare. Yes, this is not good coding...
+ */
+
+ *sc = tempState; // set new scope state
+}
+
+static void updateScopes(void)
+{
+ scopesUpdatingFlag = true;
+
+ volatile scope_t *sc = scope;
+ for (int32_t i = 0; i < song.numChannels; i++, sc++)
+ {
+ volatile scope_t s = *sc; // get copy of current scope state
+ if (!s.active)
+ continue; // scope is not active
+
+ // scope position update
+
+ s.positionFrac += s.delta;
+ const uint32_t wholeSamples = (uint32_t)(s.positionFrac >> SCOPE_FRAC_BITS);
+ s.positionFrac &= SCOPE_FRAC_MASK;
+
+ if (s.direction == 1)
+ s.position += wholeSamples; // forwards
+ else
+ s.position -= wholeSamples; // backwards
+
+ // handle loop wrapping or sample end
+ if (s.direction == -1 && s.position < s.loopStart) // sampling backwards (definitely pingpong loop)
+ {
+ s.direction = 1; // change direction to forwards
+
+ if (s.loopLength >= 2)
+ s.position = s.loopStart + ((s.loopStart - s.position - 1) % s.loopLength);
+ else
+ s.position = s.loopStart;
+
+ assert(s.position >= s.loopStart && s.position < s.sampleEnd);
+ }
+ else if (s.position >= s.sampleEnd)
+ {
+ uint32_t loopOverflowVal;
+
+ if (s.loopLength >= 2)
+ loopOverflowVal = (s.position - s.sampleEnd) % s.loopLength;
+ else
+ loopOverflowVal = 0;
+
+ if (s.loopType == LOOP_DISABLED)
+ {
+ s.active = false;
+ }
+ else if (s.loopType == LOOP_FORWARD)
+ {
+ s.position = s.loopStart + loopOverflowVal;
+ assert(s.position >= s.loopStart && s.position < s.sampleEnd);
+ }
+ else // pingpong loop
+ {
+ s.direction = -1; // change direction to backwards
+ s.position = (s.sampleEnd - 1) - loopOverflowVal;
+ assert(s.position >= s.loopStart && s.position < s.sampleEnd);
+ }
+ }
+ assert(s.position >= 0);
+
+ *sc = s; // set new scope state
+ }
+ scopesUpdatingFlag = false;
+}
+
+void drawScopes(void)
+{
+ scopesDisplayingFlag = true;
+ int32_t chansPerRow = (uint32_t)song.numChannels >> 1;
+
+ const uint16_t *scopeLens = scopeLenTab[chansPerRow-1];
+ uint16_t scopeXOffs = 3;
+ uint16_t scopeYOffs = 95;
+ int16_t scopeLineY = 112;
+
+ for (int32_t i = 0; i < song.numChannels; i++)
+ {
+ // if we reached the last scope on the row, go to first scope on the next row
+ if (i == chansPerRow)
+ {
+ scopeXOffs = 3;
+ scopeYOffs = 134;
+ scopeLineY = 151;
+ }
+
+ const uint16_t scopeDrawLen = scopeLens[i];
+ if (!editor.chnMode[i]) // scope muted (mute graphics blit()'ed elsewhere)
+ {
+ scopeXOffs += scopeDrawLen+3; // align x to next scope
+ continue;
+ }
+
+ const scope_t s = scope[i]; // cache scope to lower thread race condition issues
+ if (s.active && s.volume > 0 && !audio.locked)
+ {
+ // scope is active
+ scope[i].wasCleared = false;
+
+ // clear scope background
+ clearRect(scopeXOffs, scopeYOffs, scopeDrawLen, SCOPE_HEIGHT);
+
+ // draw scope
+ bool linedScopesFlag = !!(config.specialFlags & LINED_SCOPES);
+ scopeDrawRoutineTable[(linedScopesFlag * 6) + (s.sample16Bit * 3) + s.loopType](&s, scopeXOffs, scopeLineY, scopeDrawLen);
+ }
+ else
+ {
+ // scope is inactive
+ volatile scope_t *sc = &scope[i];
+ if (!sc->wasCleared)
+ {
+ // clear scope background
+ clearRect(scopeXOffs, scopeYOffs, scopeDrawLen, SCOPE_HEIGHT);
+
+ // draw empty line
+ hLine(scopeXOffs, scopeLineY, scopeDrawLen, PAL_PATTEXT);
+
+ sc->wasCleared = true;
+ }
+ }
+
+ // draw channel numbering (if enabled)
+ if (config.ptnChnNumbers)
+ drawScopeNumber(scopeXOffs, scopeYOffs, (uint8_t)i, false);
+
+ // draw rec. symbol (if enabled)
+ if (config.multiRecChn[i])
+ blit(scopeXOffs + 1, scopeYOffs + 31, bmp.scopeRec, 13, 4);
+
+ scopeXOffs += scopeDrawLen+3; // align x to next scope
+ }
+
+ scopesDisplayingFlag = false;
+}
+
+void drawScopeFramework(void)
+{
+ drawFramework(0, 92, 291, 81, FRAMEWORK_TYPE1);
+ for (int32_t i = 0; i < song.numChannels; i++)
+ redrawScope(i);
+}
+
+void handleScopesFromChQueue(chSyncData_t *chSyncData, uint8_t *scopeUpdateStatus)
+{
+ volatile scope_t *sc = scope;
+ syncedChannel_t *ch = chSyncData->channels;
+ for (int32_t i = 0; i < song.numChannels; i++, sc++, ch++)
+ {
+ const uint8_t status = scopeUpdateStatus[i];
+
+ if (status & IS_Vol)
+ sc->volume = ch->scopeVolume;
+
+ if (status & IS_Period)
+ sc->delta = ch->scopeDelta;
+
+ if (status & IS_Trigger)
+ {
+ if (instr[ch->instrNum] != NULL)
+ {
+ scopeTrigger(i, &instr[ch->instrNum]->smp[ch->smpNum], ch->smpStartPos);
+
+ // set some stuff used by Smp. Ed. for sampling position line
+
+ if (ch->instrNum == 130 || (ch->instrNum == editor.curInstr && ch->smpNum == editor.curSmp))
+ editor.curSmpChannel = (uint8_t)i;
+
+ lastChInstr[i].instrNum = ch->instrNum;
+ lastChInstr[i].smpNum = ch->smpNum;
+ }
+ else
+ {
+ // empty instrument, shut down scope
+ scope[i].active = false;
+ lastChInstr[i].instrNum = 255;
+ lastChInstr[i].smpNum = 255;
+ }
+ }
+ }
+}
+
+static int32_t SDLCALL scopeThreadFunc(void *ptr)
+{
+ // this is needed for scope stability (confirmed)
+ SDL_SetThreadPriority(SDL_THREAD_PRIORITY_HIGH);
+
+ // set next frame time
+ timeNext64 = SDL_GetPerformanceCounter() + scopeTimeLen;
+ timeNext64Frac = scopeTimeLenFrac;
+
+ while (editor.programRunning)
+ {
+ editor.scopeThreadMutex = true;
+ updateScopes();
+ editor.scopeThreadMutex = false;
+
+ uint64_t time64 = SDL_GetPerformanceCounter();
+ if (time64 < timeNext64)
+ {
+ time64 = timeNext64 - time64;
+ if (time64 > INT32_MAX)
+ time64 = INT32_MAX;
+
+ const int32_t diff32 = (int32_t)time64;
+
+ // convert and round to microseconds
+ const int32_t time32 = (int32_t)((diff32 * editor.dPerfFreqMulMicro) + 0.5);
+
+ // delay until we have reached the next frame
+ if (time32 > 0)
+ usleep(time32);
+ }
+
+ // update next tick time
+ timeNext64 += scopeTimeLen;
+ timeNext64Frac += scopeTimeLenFrac;
+ if (timeNext64Frac > UINT32_MAX)
+ {
+ timeNext64Frac &= UINT32_MAX;
+ timeNext64++;
+ }
+ }
+
+ (void)ptr;
+ return true;
+}
+
+bool initScopes(void)
+{
+ double dInt;
+
+ // calculate scope time for performance counters and split into int/frac
+ double dFrac = modf(editor.dPerfFreq / SCOPE_HZ, &dInt);
+
+ // integer part
+ scopeTimeLen = (int32_t)dInt;
+
+ // fractional part (scaled to 0..2^32-1)
+ dFrac *= UINT32_MAX+1.0;
+ scopeTimeLenFrac = (uint32_t)dFrac;
+
+ scopeThread = SDL_CreateThread(scopeThreadFunc, NULL, NULL);
+ if (scopeThread == NULL)
+ {
+ showErrorMsgBox("Couldn't create channel scope thread!");
+ return false;
+ }
+
+ SDL_DetachThread(scopeThread);
+ return true;
+}
--- /dev/null
+++ b/src/scopes/ft2_scopes.h
@@ -1,0 +1,49 @@
+#pragma once
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "../ft2_header.h"
+#include "../ft2_audio.h"
+#include "../ft2_cpu.h"
+
+#define SCOPE_HEIGHT 36
+
+#if CPU_64BIT
+#define SCOPE_FRAC_BITS 32
+#else
+/* Max safe amount of fracbits for uint32_t on scopes @ 64Hz.
+** Since the scopes deltas are always high'ish, 13-bit
+** fractional precision is OK.
+*/
+#define SCOPE_FRAC_BITS 13
+#endif
+
+#define SCOPE_FRAC_SCALE ((intCPUWord_t)1 << SCOPE_FRAC_BITS)
+#define SCOPE_FRAC_MASK (SCOPE_FRAC_SCALE-1)
+
+int32_t getSamplePosition(uint8_t ch);
+void stopAllScopes(void);
+void refreshScopes(void);
+bool testScopesMouseDown(void);
+void drawScopes(void);
+void drawScopeFramework(void);
+bool initScopes(void);
+
+// actual scope data
+typedef struct scope_t
+{
+ volatile bool active;
+ const int8_t *base8;
+ const int16_t *base16;
+ bool wasCleared, sample16Bit;
+ uint8_t loopType;
+ int32_t volume, direction, loopStart, loopLength, sampleEnd, position;
+ uintCPUWord_t delta, positionFrac;
+} scope_t;
+
+typedef struct lastChInstr_t
+{
+ uint8_t smpNum, instrNum;
+} lastChInstr_t;
+
+extern lastChInstr_t lastChInstr[MAX_CHANNELS];
--- a/src/smploaders/ft2_load_aiff.c
+++ b/src/smploaders/ft2_load_aiff.c
@@ -1,4 +1,9 @@
-// Apple AIFF sample loader
+/* Apple AIFF sample loader
+**
+** Note: Vol/loop sanitation is done in the last stage
+** of sample loading, so you don't need to do that here.
+** Do NOT close the file handle!
+*/
#include <stdio.h>
#include <stdint.h>
@@ -9,7 +14,7 @@
#include "../ft2_sysreqs.h"
#include "../ft2_sample_loader.h"
-static int32_t getAIFFRate(uint8_t *in);
+static int32_t getAIFFSampleRate(uint8_t *in);
static bool aiffIsStereo(FILE *f); // only ran on files that are confirmed to be AIFFs
bool loadAIFF(FILE *f, uint32_t filesize)
@@ -17,20 +22,16 @@
char compType[4];
int8_t *audioDataS8;
uint8_t sampleRateBytes[10], *audioDataU8;
- int16_t *audioDataS16, *audioDataS16_2, smp16;
+ int16_t *audioDataS16, smp16;
uint16_t numChannels, bitDepth;
- int32_t smp32, *audioDataS32;
+ int32_t *audioDataS32;
uint32_t i, blockName, blockSize;
uint32_t offset, len32;
+ sample_t *s = &tmpSmp;
fseek(f, 8, SEEK_SET);
fread(compType, 1, 4, f);
rewind(f);
- if (!memcmp(compType, "AIFC", 4))
- {
- loaderMsgBox("Error loading sample: This AIFF type (AIFC) is not supported!");
- return false;
- }
if (filesize < 12)
{
@@ -97,25 +98,37 @@
return false;
}
- if (bitDepth != 8 && bitDepth != 16 && bitDepth != 24 && bitDepth != 32)
- {
- loaderMsgBox("Error loading sample: Unsupported bitdepth!");
- return false;
- }
-
// read compression type (if present)
+ bool signedSample = true;
+ bool floatSample = false;
if (commLen > 18)
{
fread(&compType, 1, 4, f);
- if (memcmp(compType, "NONE", 4) != 0)
+
+ if (!memcmp(compType, "raw ", 4))
{
- loaderMsgBox("Error loading sample: The sample is not supported or is invalid!");
+ signedSample = false;
+ }
+ else if (!memcmp(compType, "FL32", 4) || !memcmp(compType, "fl32", 4) || !memcmp(compType, "FL64", 4) || !memcmp(compType, "fl64", 4))
+ {
+ floatSample = true;
+ }
+ else
+ {
+ loaderMsgBox("Error loading sample: Unsupported AIFF type!");
return false;
}
}
- uint32_t sampleRate = getAIFFRate(sampleRateBytes);
+ if (bitDepth != 8 && bitDepth != 16 && bitDepth != 24 && bitDepth != 32 &&
+ !(floatSample && bitDepth == 64) && !(floatSample && bitDepth == 32))
+ {
+ loaderMsgBox("Error loading sample: Unsupported AIFF type!");
+ return false;
+ }
+ uint32_t sampleRate = getAIFFSampleRate(sampleRateBytes);
+
// sample data chunk
fseek(f, ssndPtr, SEEK_SET);
@@ -132,8 +145,6 @@
ssndLen -= 8; // don't include offset and blockSize datas
uint32_t sampleLength = ssndLen;
- if (sampleLength > MAX_SAMPLE_LEN)
- sampleLength = MAX_SAMPLE_LEN;
int16_t stereoSampleLoadMode = -1;
if (aiffIsStereo(f))
@@ -141,23 +152,26 @@
// read sample data
- if (bitDepth == 8)
+ if (!floatSample && bitDepth == 8) // 8-BIT INTEGER SAMPLE
{
- // 8-BIT SIGNED PCM
-
- if (!allocateTmpSmpData(&tmpSmp, sampleLength))
+ if (!allocateSmpData(s, sampleLength, false))
{
loaderMsgBox("Not enough memory!");
return false;
}
- if (fread(tmpSmp.pek, sampleLength, 1, f) != 1)
+ if (fread(s->dataPtr, sampleLength, 1, f) != 1)
{
loaderMsgBox("General I/O error during loading! Is the file in use?");
return false;
}
- audioDataS8 = (int8_t *)tmpSmp.pek;
+ audioDataS8 = (int8_t *)s->dataPtr;
+ if (!signedSample)
+ {
+ for (i = 0; i < sampleLength; i++)
+ audioDataS8[i] ^= 0x80;
+ }
// stereo conversion
if (numChannels == 2)
@@ -199,25 +213,23 @@
}
}
}
- else if (bitDepth == 16)
+ else if (!floatSample && bitDepth == 16) // 16-BIT INTEGER SAMPLE
{
- // 16-BIT SIGNED PCM
-
- sampleLength /= 2;
- if (!allocateTmpSmpData(&tmpSmp, sampleLength*2))
+ sampleLength /= sizeof (int16_t);
+ if (!allocateSmpData(s, sampleLength * sizeof (int16_t), false))
{
loaderMsgBox("Not enough memory!");
return false;
}
- if (fread(tmpSmp.pek, sampleLength, 2, f) != 2)
+ if (fread(s->dataPtr, sampleLength, sizeof (int16_t), f) != sizeof (int16_t))
{
loaderMsgBox("General I/O error during loading! Is the file in use?");
return false;
}
- // fix endianness
- audioDataS16 = (int16_t *)tmpSmp.pek;
+ // change endianness
+ audioDataS16 = (int16_t *)s->dataPtr;
for (i = 0; i < sampleLength; i++)
audioDataS16[i] = SWAP16(audioDataS16[i]);
@@ -251,7 +263,7 @@
len32 = sampleLength - 1;
for (i = 0; i < len32; i++)
{
- smp32 = (audioDataS16[(i * 2) + 0] + audioDataS16[(i * 2) + 1]) >> 1;
+ int32_t smp32 = (audioDataS16[(i * 2) + 0] + audioDataS16[(i * 2) + 1]) >> 1;
audioDataS16[i] = (int16_t)smp32;
}
@@ -261,30 +273,27 @@
}
}
- sampleLength *= 2;
- tmpSmp.typ |= 16;
+ s->flags |= SAMPLE_16BIT;
}
- else if (bitDepth == 24)
+ else if (!floatSample && bitDepth == 24) // 24-BIT INTEGER SAMPLE
{
- // 24-BIT SIGNED PCM
-
sampleLength /= 3;
- if (!allocateTmpSmpData(&tmpSmp, (sampleLength * 4) * 2))
+ if (!allocateSmpData(s, sampleLength * sizeof (int32_t), false))
{
loaderMsgBox("Not enough memory!");
return false;
}
- if (fread(&tmpSmp.pek[sampleLength], sampleLength, 3, f) != 3)
+ if (fread(&s->dataPtr[sampleLength], sampleLength, 3, f) != 3)
{
loaderMsgBox("General I/O error during loading! Is the file in use?");
return false;
}
- audioDataS32 = (int32_t *)tmpSmp.pek;
+ audioDataS32 = (int32_t *)s->dataPtr;
// convert to 32-bit
- audioDataU8 = (uint8_t *)tmpSmp.pek + sampleLength;
+ audioDataU8 = (uint8_t *)s->dataPtr + sampleLength;
for (i = 0; i < sampleLength; i++)
{
audioDataS32[i] = (audioDataU8[0] << 24) | (audioDataU8[1] << 16) | (audioDataU8[2] << 8);
@@ -336,36 +345,29 @@
normalizeSigned32Bit(audioDataS32, sampleLength);
- // downscale to 16-bit (ultra fast method!)
+ audioDataS16 = (int16_t *)s->dataPtr;
+ for (i = 0; i < sampleLength; i++)
+ audioDataS16[i] = audioDataS32[i] >> 16;
- audioDataS16 = (int16_t *)tmpSmp.pek;
- audioDataS16_2 = (int16_t *)tmpSmp.pek + 1; // yes, this is aligned to words
-
- for (i = 0; i < sampleLength; i++, audioDataS16_2++)
- audioDataS16[i] = audioDataS16_2[i];
-
- sampleLength *= 2;
- tmpSmp.typ |= 16;
+ s->flags |= SAMPLE_16BIT;
}
- else if (bitDepth == 32)
+ else if (!floatSample && bitDepth == 32) // 32-BIT INTEGER SAMPLE
{
- // 32-BIT SIGNED PCM
-
- sampleLength /= 4;
- if (!allocateTmpSmpData(&tmpSmp, sampleLength * 4))
+ sampleLength /= sizeof (int32_t);
+ if (!allocateSmpData(s, sampleLength * sizeof (int32_t), false))
{
loaderMsgBox("Not enough memory!");
return false;
}
- if (fread(tmpSmp.pek, sampleLength, 4, f) != 4)
+ if (fread(s->dataPtr, sampleLength, sizeof (int32_t), f) != sizeof (int32_t))
{
loaderMsgBox("General I/O error during loading! Is the file in use?");
return false;
}
- // fix endianness
- audioDataS32 = (int32_t *)tmpSmp.pek;
+ // change endianness
+ audioDataS32 = (int32_t *)s->dataPtr;
for (i = 0; i < sampleLength; i++)
audioDataS32[i] = SWAP32(audioDataS32[i]);
@@ -414,42 +416,188 @@
normalizeSigned32Bit(audioDataS32, sampleLength);
- // downscale to 16-bit (ultra fast method!)
+ audioDataS16 = (int16_t *)s->dataPtr;
+ for (i = 0; i < sampleLength; i++)
+ audioDataS16[i] = audioDataS32[i] >> 16;
- audioDataS16 = (int16_t *)tmpSmp.pek;
- audioDataS16_2 = (int16_t *)tmpSmp.pek + 1; // yes, this is aligned to words
+ s->flags |= SAMPLE_16BIT;
+ }
+ else if (floatSample && bitDepth == 32) // 32-BIT FLOAT SAMPLE
+ {
+ sampleLength /= sizeof (float);
+ if (!allocateSmpData(s, sampleLength * sizeof (float), false))
+ {
+ loaderMsgBox("Not enough memory!");
+ return false;
+ }
- for (i = 0; i < sampleLength; i++, audioDataS16_2++)
- audioDataS16[i] = audioDataS16_2[i];
+ if (fread(s->dataPtr, sampleLength, sizeof (float), f) != sizeof (float))
+ {
+ loaderMsgBox("General I/O error during loading! Is the file in use?");
+ return false;
+ }
- sampleLength *= 2;
- tmpSmp.typ |= 16;
+ // change endianness
+ audioDataS32 = (int32_t *)s->dataPtr;
+ for (i = 0; i < sampleLength; i++)
+ audioDataS32[i] = SWAP32(audioDataS32[i]);
+
+ float *fAudioDataFloat = (float *)s->dataPtr;
+
+ // stereo conversion
+ if (numChannels == 2)
+ {
+ sampleLength /= 2;
+ switch (stereoSampleLoadMode)
+ {
+ case STEREO_SAMPLE_READ_LEFT:
+ {
+ // remove right channel data
+ for (i = 1; i < sampleLength; i++)
+ fAudioDataFloat[i] = fAudioDataFloat[(i * 2) + 0];
+ }
+ break;
+
+ case STEREO_SAMPLE_READ_RIGHT:
+ {
+ // remove left channel data
+ len32 = sampleLength - 1;
+ for (i = 0; i < len32; i++)
+ fAudioDataFloat[i] = fAudioDataFloat[(i * 2) + 1];
+
+ fAudioDataFloat[i] = 0.0f;
+ }
+ break;
+
+ default:
+ case STEREO_SAMPLE_CONVERT:
+ {
+ // mix stereo to mono
+ len32 = sampleLength - 1;
+ for (i = 0; i < len32; i++)
+ fAudioDataFloat[i] = (fAudioDataFloat[(i * 2) + 0] + fAudioDataFloat[(i * 2) + 1]) * 0.5f;
+
+ fAudioDataFloat[i] = 0.0f;
+ }
+ break;
+ }
+ }
+
+ normalize32BitFloatToSigned16Bit(fAudioDataFloat, sampleLength);
+
+ int16_t *ptr16 = (int16_t *)s->dataPtr;
+ for (i = 0; i < sampleLength; i++)
+ {
+ const int32_t smp32 = (const int32_t)fAudioDataFloat[i];
+ ptr16[i] = (int16_t)smp32;
+ }
+
+ s->flags |= SAMPLE_16BIT;
}
+ else if (floatSample && bitDepth == 64) // 64-BIT FLOAT SAMPLE
+ {
+ sampleLength /= sizeof (double);
+ if (!allocateSmpData(s, sampleLength * sizeof (double), false))
+ {
+ loaderMsgBox("Not enough memory!");
+ return false;
+ }
- reallocateTmpSmpData(&tmpSmp, sampleLength); // readjust memory needed
+ if (fread(s->dataPtr, sampleLength, sizeof (double), f) != sizeof (double))
+ {
+ loaderMsgBox("General I/O error during loading! Is the file in use?");
+ return false;
+ }
- tmpSmp.len = sampleLength;
- tmpSmp.vol = 64;
- tmpSmp.pan = 128;
+ // change endianness
+ int64_t *audioDataS64 = (int64_t *)s->dataPtr;
+ for (i = 0; i < sampleLength; i++)
+ audioDataS64[i] = SWAP64(audioDataS64[i]);
- tuneSample(&tmpSmp, sampleRate, audio.linearPeriodsFlag);
+ double *dAudioDataDouble = (double *)s->dataPtr;
+ // stereo conversion
+ if (numChannels == 2)
+ {
+ sampleLength /= 2;
+ switch (stereoSampleLoadMode)
+ {
+ case STEREO_SAMPLE_READ_LEFT:
+ {
+ // remove right channel data
+ for (i = 1; i < sampleLength; i++)
+ dAudioDataDouble[i] = dAudioDataDouble[(i * 2) + 0];
+ }
+ break;
+
+ case STEREO_SAMPLE_READ_RIGHT:
+ {
+ // remove left channel data
+ len32 = sampleLength - 1;
+ for (i = 0; i < len32; i++)
+ dAudioDataDouble[i] = dAudioDataDouble[(i * 2) + 1];
+
+ dAudioDataDouble[i] = 0.0;
+ }
+ break;
+
+ default:
+ case STEREO_SAMPLE_CONVERT:
+ {
+ // mix stereo to mono
+ len32 = sampleLength - 1;
+ for (i = 0; i < len32; i++)
+ dAudioDataDouble[i] = (dAudioDataDouble[(i * 2) + 0] + dAudioDataDouble[(i * 2) + 1]) * 0.5;
+
+ dAudioDataDouble[i] = 0.0;
+ }
+ break;
+ }
+ }
+
+ normalize64BitFloatToSigned16Bit(dAudioDataDouble, sampleLength);
+
+ int16_t *ptr16 = (int16_t *)s->dataPtr;
+ for (i = 0; i < sampleLength; i++)
+ {
+ const int32_t smp32 = (const int32_t)dAudioDataDouble[i];
+ ptr16[i] = (int16_t)smp32;
+ }
+
+ s->flags |= SAMPLE_16BIT;
+ }
+
+ if (sampleLength > MAX_SAMPLE_LEN)
+ sampleLength = MAX_SAMPLE_LEN;
+
+ bool sample16Bit = !!(s->flags & SAMPLE_16BIT);
+ reallocateSmpData(s, sampleLength, sample16Bit); // readjust memory needed
+
+ s->length = sampleLength;
+ s->volume = 64;
+ s->panning = 128;
+
+ tuneSample(s, sampleRate, audio.linearPeriodsFlag);
+
return true;
}
-static int32_t getAIFFRate(uint8_t *in)
+static int32_t getAIFFSampleRate(uint8_t *in)
{
- int32_t exp = (int32_t)(((in[0] & 0x7F) << 8) | in[1]);
- uint32_t lo = (in[2] << 24) | (in[3] << 16) | (in[4] << 8) | in[5];
- uint32_t hi = (in[6] << 24) | (in[7] << 16) | (in[8] << 8) | in[9];
+ uint32_t mantissa = (in[2] << 24) | (in[3] << 16) | (in[4] << 8) | in[5];
+ uint8_t exp = 30 - in[1];
- if (exp == 0 && lo == 0 && hi == 0)
- return 0;
+ uint32_t lastMantissa = 0;
+ while (exp--)
+ {
+ lastMantissa = mantissa;
+ mantissa >>= 1;
+ }
- exp -= 16383;
+ if (lastMantissa & 1)
+ mantissa++;
- double dOut = ldexp(lo, -31 + exp) + ldexp(hi, -63 + exp);
- return (int32_t)(dOut + 0.5); // rounded
+ return mantissa;
}
static bool aiffIsStereo(FILE *f) // only ran on files that are confirmed to be AIFFs
--- /dev/null
+++ b/src/smploaders/ft2_load_flac.c
@@ -1,0 +1,431 @@
+/* FLAC sample loader
+**
+** Note: Vol/loop sanitation is done in the last stage
+** of sample loading, so you don't need to do that here.
+** Do NOT close the file handle!
+*/
+
+#ifdef HAS_LIBFLAC
+
+// hide POSIX warning for fileno()
+#ifdef _MSC_VER
+#pragma warning(disable: 4996)
+#endif
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdbool.h>
+#ifndef _WIN32
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#endif
+#include "../ft2_header.h"
+#include "../ft2_audio.h"
+#include "../ft2_sample_ed.h"
+#include "../ft2_sysreqs.h"
+#include "../ft2_sample_loader.h"
+#include "../libflac/FLAC/stream_decoder.h"
+
+static bool sample16Bit;
+static int16_t stereoSampleLoadMode = -1;
+static uint32_t numChannels, bitDepth, sampleLength, sampleRate, samplesRead;
+static sample_t *s;
+
+static FLAC__StreamDecoderReadStatus read_callback(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data);
+static FLAC__StreamDecoderSeekStatus seek_callback(const FLAC__StreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data);
+static FLAC__StreamDecoderTellStatus tell_callback(const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data);
+static FLAC__StreamDecoderLengthStatus length_callback(const FLAC__StreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data);
+static FLAC__bool eof_callback(const FLAC__StreamDecoder *decoder, void *client_data);
+static void metadata_callback(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data);
+static FLAC__StreamDecoderWriteStatus write_callback(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 *const buffer[], void *client_data);
+static void error_callback(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data);
+
+bool loadFLAC(FILE *f, uint32_t filesize)
+{
+ s = &tmpSmp;
+
+ s->volume = 64;
+ s->panning = 128;
+
+ numChannels = 0;
+ bitDepth = 0;
+ sampleLength = 0;
+ sampleRate = 0;
+ samplesRead = 0;
+
+ FLAC__StreamDecoder *decoder = FLAC__stream_decoder_new();
+ if (decoder == NULL)
+ {
+ loaderMsgBox("Error loading sample: Unable to allocate FLAC decoder!");
+ goto error;
+ }
+
+ FLAC__stream_decoder_set_metadata_respond_all(decoder);
+
+ FLAC__StreamDecoderInitStatus initStatus =
+ FLAC__stream_decoder_init_stream
+ (
+ decoder,
+ read_callback, seek_callback,
+ tell_callback, length_callback,
+ eof_callback, write_callback,
+ metadata_callback, error_callback,
+ f
+ );
+
+ if (initStatus != FLAC__STREAM_DECODER_INIT_STATUS_OK)
+ {
+ loaderMsgBox("Error loading sample: Unable to initialize FLAC decoder!");
+ goto error;
+ }
+
+ if (!FLAC__stream_decoder_process_until_end_of_stream(decoder))
+ {
+ loaderMsgBox("Error loading sample: Unable to decode FLAC!");
+ goto error;
+ }
+
+ FLAC__stream_decoder_finish(decoder);
+ FLAC__stream_decoder_delete(decoder);
+
+ tuneSample(s, sampleRate, audio.linearPeriodsFlag);
+
+ return true;
+
+error:
+ if (decoder != NULL) FLAC__stream_decoder_delete(decoder);
+
+ return false;
+
+ (void)filesize;
+}
+
+static FLAC__StreamDecoderReadStatus read_callback(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data)
+{
+ FILE *file = (FILE *)client_data;
+ if (*bytes > 0)
+ {
+ *bytes = fread(buffer, sizeof (FLAC__byte), *bytes, file);
+ if (ferror(file))
+ return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
+ else if (*bytes == 0)
+ return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
+ else
+ return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
+ }
+ else
+ {
+ return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
+ }
+
+ (void)decoder;
+}
+
+static FLAC__StreamDecoderSeekStatus seek_callback(const FLAC__StreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data)
+{
+ FILE *file = (FILE *)client_data;
+
+ if (absolute_byte_offset > INT32_MAX)
+ return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR;
+
+ if (fseek(file, (int32_t)absolute_byte_offset, SEEK_SET) < 0)
+ return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR;
+ else
+ return FLAC__STREAM_DECODER_SEEK_STATUS_OK;
+
+ (void)decoder;
+}
+
+static FLAC__StreamDecoderTellStatus tell_callback(const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data)
+{
+ FILE *file = (FILE *)client_data;
+ int32_t pos = ftell(file);
+
+ if (pos < 0)
+ {
+ return FLAC__STREAM_DECODER_TELL_STATUS_ERROR;
+ }
+ else
+ {
+ *absolute_byte_offset = (FLAC__uint64)pos;
+ return FLAC__STREAM_DECODER_TELL_STATUS_OK;
+ }
+
+ (void)decoder;
+}
+
+static FLAC__StreamDecoderLengthStatus length_callback(const FLAC__StreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data)
+{
+ FILE *file = (FILE *)client_data;
+ struct stat filestats;
+
+ if (fstat(fileno(file), &filestats) != 0)
+ {
+ return FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR;
+ }
+ else
+ {
+ *stream_length = (FLAC__uint64)filestats.st_size;
+ return FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
+ }
+
+ (void)decoder;
+}
+
+static FLAC__bool eof_callback(const FLAC__StreamDecoder *decoder, void *client_data)
+{
+ FILE *file = (FILE *)client_data;
+ return feof(file) ? true : false;
+
+ (void)decoder;
+}
+
+static void metadata_callback(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data)
+{
+ if (metadata->type == FLAC__METADATA_TYPE_STREAMINFO && metadata->data.stream_info.total_samples != 0)
+ {
+ bitDepth = metadata->data.stream_info.bits_per_sample;
+ numChannels = metadata->data.stream_info.channels;
+ sampleRate = metadata->data.stream_info.sample_rate;
+
+ sample16Bit = (bitDepth != 8);
+
+ int64_t tmp64 = metadata->data.stream_info.total_samples;
+ if (tmp64 > MAX_SAMPLE_LEN)
+ tmp64 = MAX_SAMPLE_LEN;
+
+ sampleLength = (uint32_t)tmp64;
+
+ s->length = sampleLength;
+ if (sample16Bit)
+ s->flags |= SAMPLE_16BIT;
+
+ stereoSampleLoadMode = -1;
+ if (numChannels == 2)
+ stereoSampleLoadMode = loaderSysReq(5, "System request", "This is a stereo sample...");
+ }
+
+ // check for RIFF chunks (loop/vol/pan information)
+ else if (metadata->type == FLAC__METADATA_TYPE_APPLICATION && !memcmp(metadata->data.application.id, "riff", 4))
+ {
+ const uint8_t *data = (const uint8_t *)metadata->data.application.data;
+
+ uint32_t chunkID = *(uint32_t *)data; data += 4;
+ uint32_t chunkLen = *(uint32_t *)data; data += 4;
+
+ if (chunkID == 0x61727478 && chunkLen >= 8) // "xtra"
+ {
+ uint32_t xtraFlags = *(uint32_t *)data; data += 4;
+
+ // panning (0..256)
+ if (xtraFlags & 0x20) // set panning flag
+ {
+ uint16_t tmpPan = *(uint16_t *)data;
+ if (tmpPan > 255)
+ tmpPan = 255;
+
+ s->panning = (uint8_t)tmpPan;
+ }
+ data += 2;
+
+ // volume (0..256)
+ uint16_t tmpVol = *(uint16_t *)data;
+ if (tmpVol > 256)
+ tmpVol = 256;
+
+ s->volume = (uint8_t)((tmpVol + 2) / 4); // 0..256 -> 0..64 (rounded)
+ }
+
+ if (chunkID == 0x6C706D73 && chunkLen > 52) // "smpl"
+ {
+ data += 28; // seek to first wanted byte
+
+ uint32_t numLoops = *(uint32_t *)data; data += 4;
+ if (numLoops == 1)
+ {
+ data += 4+4; // skip "samplerData" and "identifier"
+
+ uint32_t loopType = *(uint32_t *)data; data += 4;
+ uint32_t loopStart = *(uint32_t *)data; data += 4;
+ uint32_t loopEnd = *(uint32_t *)data; data += 4;
+
+ s->loopStart = loopStart;
+ s->loopLength = (loopEnd+1) - loopStart;
+ s->flags |= (loopType == 0) ? LOOP_FWD : LOOP_BIDI;
+ }
+ }
+ }
+
+ else if (metadata->type == FLAC__METADATA_TYPE_VORBIS_COMMENT)
+ {
+ uint32_t tmpSampleRate = 0, loopStart = 0, loopLength = 0;
+ for (uint32_t i = 0; i < metadata->data.vorbis_comment.num_comments; i++)
+ {
+ const char *tag = (const char *)metadata->data.vorbis_comment.comments[i].entry;
+ uint32_t length = metadata->data.vorbis_comment.comments[i].length;
+
+ if (length > 6 && !memcmp(tag, "TITLE=", 6))
+ {
+ length -= 6;
+ if (length > 22)
+ length = 22;
+
+ memcpy(s->name, &tag[6], length);
+ s->name[22] = '\0';
+
+ smpFilenameSet = true;
+ }
+
+ // the following tags haven't been tested!
+ else if (length > 11 && !memcmp(tag, "SAMPLERATE=", 11))
+ {
+ tmpSampleRate = atoi(&tag[11]);
+ }
+ else if (length > 10 && !memcmp(tag, "LOOPSTART=", 10))
+ {
+ loopLength = atoi(&tag[10]);
+ }
+ else if (length > 11 && !memcmp(tag, "LOOPLENGTH=", 11))
+ {
+ loopLength = atoi(&tag[11]);
+ }
+
+ if (loopLength > 0)
+ {
+ s->loopStart = loopLength;
+ s->loopLength = loopStart;
+
+ DISABLE_LOOP(s->flags);
+ s->flags |= LOOP_FWD;
+ }
+
+ if (tmpSampleRate > 0)
+ sampleRate = tmpSampleRate;
+ }
+ }
+
+ (void)client_data;
+ (void)decoder;
+}
+
+static FLAC__StreamDecoderWriteStatus write_callback(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 *const buffer[], void *client_data)
+{
+ if (sampleLength == 0 || numChannels == 0)
+ {
+ loaderMsgBox("Error loading sample: The sample is empty or corrupt!");
+ return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+ }
+
+ if (numChannels > 2)
+ {
+ loaderMsgBox("Error loading sample: Only mono/stereo FLACs are supported!");
+ return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+ }
+
+ if (bitDepth != 8 && bitDepth != 16 && bitDepth != 24)
+ {
+ loaderMsgBox("Error loading sample: Only FLACs with a bitdepth of 8/16/24 are supported!");
+ return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+ }
+
+ if (frame->header.number.sample_number == 0)
+ {
+ if (!allocateSmpData(s, sampleLength, sample16Bit))
+ {
+ loaderMsgBox("Error loading sample: Out of memory!");
+ return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+ }
+
+ samplesRead = 0;
+ }
+
+ uint32_t blockSize = frame->header.blocksize;
+
+ const uint32_t samplesAllocated = sampleLength;
+ if (samplesRead+blockSize > samplesAllocated)
+ blockSize = samplesAllocated-samplesRead;
+
+ if (stereoSampleLoadMode == STEREO_SAMPLE_CONVERT) // mix to mono
+ {
+ const int32_t *src32_L = buffer[0];
+ const int32_t *src32_R = buffer[1];
+
+ switch (bitDepth)
+ {
+ case 8:
+ {
+ int8_t *dst8 = s->dataPtr + samplesRead;
+ for (uint32_t i = 0; i < blockSize; i++)
+ dst8[i] = (int8_t)((src32_L[i] + src32_R[i]) >> 1);
+ }
+ break;
+
+ case 16:
+ {
+ int16_t *dst16 = (int16_t *)s->dataPtr + samplesRead;
+ for (uint32_t i = 0; i < blockSize; i++)
+ dst16[i] = (int16_t)((src32_L[i] + src32_R[i]) >> 1);
+ }
+ break;
+
+ case 24:
+ {
+ int16_t *dst16 = (int16_t *)s->dataPtr + samplesRead;
+ for (uint32_t i = 0; i < blockSize; i++)
+ dst16[i] = (int16_t)((src32_L[i] + src32_R[i]) >> (16+1));
+ }
+ break;
+
+ default: break;
+ }
+ }
+ else // mono sample
+ {
+ const int32_t *src32 = (stereoSampleLoadMode == STEREO_SAMPLE_READ_RIGHT) ? buffer[1] : buffer[0];
+
+ switch (bitDepth)
+ {
+ case 8:
+ {
+ int8_t *dst8 = s->dataPtr + samplesRead;
+ for (uint32_t i = 0; i < blockSize; i++)
+ dst8[i] = (int8_t)src32[i];
+ }
+ break;
+
+ case 16:
+ {
+ int16_t *dst16 = (int16_t *)s->dataPtr + samplesRead;
+ for (uint32_t i = 0; i < blockSize; i++)
+ dst16[i] = (int16_t)src32[i];
+ }
+ break;
+
+ case 24:
+ {
+ int16_t *dst16 = (int16_t *)s->dataPtr + samplesRead;
+ for (uint32_t i = 0; i < blockSize; i++)
+ dst16[i] = (int16_t)(src32[i] >> 8);
+ }
+ break;
+
+ default: break;
+ }
+ }
+
+ samplesRead += blockSize;
+ return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
+
+ (void)client_data;
+ (void)decoder;
+}
+
+static void error_callback(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
+{
+ (void)status;
+ (void)decoder;
+ (void)client_data;
+}
+
+#endif
--- a/src/smploaders/ft2_load_iff.c
+++ b/src/smploaders/ft2_load_iff.c
@@ -1,4 +1,9 @@
-// IFF (Amiga/FT2) sample loader
+/* IFF (Amiga/FT2) sample loader
+**
+** Note: Vol/loop sanitation is done in the last stage
+** of sample loading, so you don't need to do that here.
+** Do NOT close the file handle!
+*/
#include <stdio.h>
#include <stdint.h>
@@ -12,7 +17,8 @@
bool loadIFF(FILE *f, uint32_t filesize)
{
char hdr[4+1];
- uint32_t sampleLength, sampleVol, sampleLoopStart, sampleLoopLength, sampleRate;
+ uint32_t length, volume, loopStart, loopLength, sampleRate;
+ sample_t *s = &tmpSmp;
if (filesize < 12)
{
@@ -23,7 +29,7 @@
fseek(f, 8, SEEK_SET);
fread(hdr, 1, 4, f);
hdr[4] = '\0';
- bool is16Bit = !strncmp(hdr, "16SV", 4);
+ bool sample16Bit = !strncmp(hdr, "16SV", 4);
uint32_t vhdrPtr = 0, vhdrLen = 0;
uint32_t bodyPtr = 0, bodyLen = 0;
@@ -82,8 +88,8 @@
bodyLen = filesize - bodyPtr;
fseek(f, vhdrPtr, SEEK_SET);
- fread(&sampleLoopStart, 4, 1, f); sampleLoopStart = SWAP32(sampleLoopStart);
- fread(&sampleLoopLength, 4, 1, f); sampleLoopLength = SWAP32(sampleLoopLength);
+ fread(&loopStart, 4, 1, f); loopStart = SWAP32(loopStart);
+ fread(&loopLength, 4, 1, f); loopLength = SWAP32(loopLength);
fseek(f, 4, SEEK_CUR);
fread(&sampleRate, 2, 1, f); sampleRate = SWAP16(sampleRate);
fseek(f, 1, SEEK_CUR);
@@ -94,83 +100,61 @@
return false;
}
- fread(&sampleVol, 4, 1, f); sampleVol = SWAP32(sampleVol);
- if (sampleVol > 65535)
- sampleVol = 65535;
+ fread(&volume, 4, 1, f); volume = SWAP32(volume);
+ if (volume > 65535)
+ volume = 65535;
- sampleVol = (sampleVol + 512) / 1024; // rounded
+ volume = (volume + 512) / 1024; // rounded
- sampleLength = bodyLen;
- if (sampleLength > MAX_SAMPLE_LEN)
- sampleLength = MAX_SAMPLE_LEN;
-
- if (sampleLoopStart >= MAX_SAMPLE_LEN || sampleLoopLength > MAX_SAMPLE_LEN)
+ length = bodyLen;
+ if (sample16Bit)
{
- sampleLoopStart = 0;
- sampleLoopLength = 0;
+ length >>= 1;
+ loopStart >>= 1;
+ loopLength >>= 1;
}
- if (sampleLoopStart+sampleLoopLength > sampleLength)
- {
- sampleLoopStart = 0;
- sampleLoopLength = 0;
- }
+ s->length = length;
+ if (s->length > MAX_SAMPLE_LEN)
+ s->length = MAX_SAMPLE_LEN;
- if (sampleLoopStart > sampleLength-2)
+ if (!allocateSmpData(s, length, sample16Bit))
{
- sampleLoopStart = 0;
- sampleLoopLength = 0;
- }
-
- if (!allocateTmpSmpData(&tmpSmp, sampleLength))
- {
loaderMsgBox("Not enough memory!");
return false;
}
fseek(f, bodyPtr, SEEK_SET);
- if (fread(tmpSmp.pek, sampleLength, 1, f) != 1)
+ if (fread(s->dataPtr, length << sample16Bit, 1, f) != 1)
{
loaderMsgBox("General I/O error during loading! Is the file in use?");
return false;
}
- tmpSmp.len = sampleLength;
+ s->loopStart = loopStart;
+ s->loopLength = loopLength;
- if (sampleLoopLength > 2)
- {
- tmpSmp.repS = sampleLoopStart;
- tmpSmp.repL = sampleLoopLength;
- tmpSmp.typ |= 1;
- }
+ if (s->loopLength > 0)
+ s->flags |= LOOP_FWD;
- if (is16Bit)
- {
- tmpSmp.len &= 0xFFFFFFFE;
- tmpSmp.repS &= 0xFFFFFFFE;
- tmpSmp.repL &= 0xFFFFFFFE;
- tmpSmp.typ |= 16;
- }
+ if (sample16Bit)
+ s->flags |= SAMPLE_16BIT;
- tmpSmp.vol = (uint8_t)sampleVol;
- tmpSmp.pan = 128;
+ s->volume = (uint8_t)volume;
+ s->panning = 128;
- tuneSample(&tmpSmp, sampleRate, audio.linearPeriodsFlag);
+ tuneSample(s, sampleRate, audio.linearPeriodsFlag);
// set name
if (namePtr != 0 && nameLen > 0)
{
fseek(f, namePtr, SEEK_SET);
- if (nameLen > 21)
- {
- fread(tmpSmp.name, 1, 21, f);
- tmpSmp.name[21] = '\0';
- }
- else
- {
- memset(tmpSmp.name, 0, 22);
- fread(tmpSmp.name, 1, nameLen, f);
- }
+
+ if (nameLen > 22)
+ nameLen = 22;
+
+ fread(s->name, 1, nameLen, f);
+ s->name[22] = '\0';
smpFilenameSet = true;
}
--- a/src/smploaders/ft2_load_raw.c
+++ b/src/smploaders/ft2_load_raw.c
@@ -1,4 +1,7 @@
-// RAW (header-less) sample loader
+/* RAW (header-less) sample loader
+**
+** Note: Do NOT close the file handle!
+*/
#include <stdio.h>
#include <stdint.h>
@@ -10,21 +13,23 @@
bool loadRAW(FILE *f, uint32_t filesize)
{
- if (!allocateTmpSmpData(&tmpSmp, filesize))
+ sample_t *s = &tmpSmp;
+
+ if (!allocateSmpData(s, filesize, false))
{
loaderMsgBox("Not enough memory!");
return false;
}
- if (fread(tmpSmp.pek, filesize, 1, f) != 1)
+ if (fread(s->dataPtr, filesize, 1, f) != 1)
{
okBoxThreadSafe(0, "System message", "General I/O error during loading! Is the file in use?");
return false;
}
- tmpSmp.len = filesize;
- tmpSmp.vol = 64;
- tmpSmp.pan = 128;
+ s->length = filesize;
+ s->volume = 64;
+ s->panning = 128;
return true;
}
--- a/src/smploaders/ft2_load_wav.c
+++ b/src/smploaders/ft2_load_wav.c
@@ -1,4 +1,9 @@
-// WAV sample loader
+/* WAV sample loader
+**
+** Note: Vol/loop sanitation is done in the last stage
+** of sample loading, so you don't need to do that here.
+** Do NOT close the file handle!
+*/
#include <stdio.h>
#include <stdint.h>
@@ -20,7 +25,7 @@
bool loadWAV(FILE *f, uint32_t filesize)
{
uint8_t *audioDataU8;
- int16_t *audioDataS16, *audioDataS16_2, *ptr16;
+ int16_t *audioDataS16, *ptr16;
uint16_t audioFormat, numChannels, bitsPerSample;
int32_t *audioDataS32;
uint32_t i, sampleRate, sampleLength;
@@ -27,6 +32,7 @@
uint32_t len32;
float *fAudioDataFloat;
double *dAudioDataDouble;
+ sample_t *s = &tmpSmp;
if (filesize < 12)
{
@@ -172,9 +178,6 @@
// ---- READ SAMPLE DATA ----
fseek(f, dataPtr, SEEK_SET);
- if (sampleLength > MAX_SAMPLE_LEN)
- sampleLength = MAX_SAMPLE_LEN;
-
int16_t stereoSampleLoadMode = -1;
if (wavIsStereo(f))
stereoSampleLoadMode = loaderSysReq(5, "System request", "This is a stereo sample...");
@@ -181,19 +184,19 @@
if (bitsPerSample == 8) // 8-BIT INTEGER SAMPLE
{
- if (!allocateTmpSmpData(&tmpSmp, sampleLength))
+ if (!allocateSmpData(s, sampleLength, false))
{
loaderMsgBox("Not enough memory!");
return false;
}
- if (fread(tmpSmp.pek, sampleLength, 1, f) != 1)
+ if (fread(s->dataPtr, sampleLength, 1, f) != 1)
{
loaderMsgBox("General I/O error during loading! Is the file in use?");
return false;
}
- audioDataU8 = (uint8_t *)tmpSmp.pek;
+ audioDataU8 = (uint8_t *)s->dataPtr;
// stereo conversion
if (numChannels == 2)
@@ -236,24 +239,24 @@
// convert from unsigned to signed
for (i = 0; i < sampleLength; i++)
- tmpSmp.pek[i] ^= 0x80;
+ s->dataPtr[i] ^= 0x80;
}
else if (bitsPerSample == 16) // 16-BIT INTEGER SAMPLE
{
sampleLength /= 2;
- if (!allocateTmpSmpData(&tmpSmp, sampleLength*2))
+ if (!allocateSmpData(s, sampleLength, true))
{
loaderMsgBox("Not enough memory!");
return false;
}
- if (fread(tmpSmp.pek, sampleLength, 2, f) != 2)
+ if (fread(s->dataPtr, sampleLength, 2, f) != 2)
{
loaderMsgBox("General I/O error during loading! Is the file in use?");
return false;
}
- audioDataS16 = (int16_t *)tmpSmp.pek;
+ audioDataS16 = (int16_t *)s->dataPtr;
// stereo conversion
if (numChannels == 2)
@@ -298,28 +301,27 @@
}
}
- sampleLength *= 2;
- tmpSmp.typ |= 16; // 16-bit
+ s->flags |= SAMPLE_16BIT;
}
else if (bitsPerSample == 24) // 24-BIT INTEGER SAMPLE
{
sampleLength /= 3;
- if (!allocateTmpSmpData(&tmpSmp, (sampleLength * 4) * 2))
+ if (!allocateSmpData(s, sampleLength * sizeof (int32_t), false))
{
loaderMsgBox("Not enough memory!");
return false;
}
- if (fread(&tmpSmp.pek[sampleLength], sampleLength, 3, f) != 3)
+ if (fread(&s->dataPtr[sampleLength], sampleLength, 3, f) != 3)
{
loaderMsgBox("General I/O error during loading! Is the file in use?");
return false;
}
- audioDataS32 = (int32_t *)tmpSmp.pek;
+ audioDataS32 = (int32_t *)s->dataPtr;
// convert to 32-bit
- audioDataU8 = (uint8_t *)tmpSmp.pek + sampleLength;
+ audioDataU8 = (uint8_t *)s->dataPtr + sampleLength;
for (i = 0; i < sampleLength; i++)
{
audioDataS32[i] = (audioDataU8[2] << 24) | (audioDataU8[1] << 16) | (audioDataU8[0] << 8);
@@ -373,33 +375,28 @@
normalizeSigned32Bit(audioDataS32, sampleLength);
- // downscale to 16-bit (ultra fast method!)
+ ptr16 = (int16_t *)s->dataPtr;
+ for (i = 0; i < sampleLength; i++)
+ ptr16[i] = audioDataS32[i] >> 16;
- audioDataS16 = (int16_t *)tmpSmp.pek;
- audioDataS16_2 = (int16_t *)tmpSmp.pek + 1; // yes, this is aligned to words
-
- for (i = 0; i < sampleLength; i++, audioDataS16_2++)
- audioDataS16[i] = audioDataS16_2[i];
-
- sampleLength *= 2;
- tmpSmp.typ |= 16; // 16-bit
+ s->flags |= SAMPLE_16BIT;
}
else if (audioFormat == WAV_FORMAT_PCM && bitsPerSample == 32) // 32-BIT INTEGER SAMPLE
{
- sampleLength /= 4;
- if (!allocateTmpSmpData(&tmpSmp, sampleLength * 4))
+ sampleLength /= sizeof (int32_t);
+ if (!allocateSmpData(s, sampleLength * sizeof (int32_t), false))
{
loaderMsgBox("Not enough memory!");
return false;
}
- if (fread(tmpSmp.pek, sampleLength, 4, f) != 4)
+ if (fread(s->dataPtr, sampleLength, sizeof (int32_t), f) != sizeof (int32_t))
{
loaderMsgBox("General I/O error during loading! Is the file in use?");
return false;
}
- audioDataS32 = (int32_t *)tmpSmp.pek;
+ audioDataS32 = (int32_t *)s->dataPtr;
// stereo conversion
if (numChannels == 2)
@@ -448,33 +445,28 @@
normalizeSigned32Bit(audioDataS32, sampleLength);
- // downscale to 16-bit (ultra fast method!)
+ ptr16 = (int16_t *)s->dataPtr;
+ for (i = 0; i < sampleLength; i++)
+ ptr16[i] = audioDataS32[i] >> 16;
- audioDataS16 = (int16_t *)tmpSmp.pek;
- audioDataS16_2 = (int16_t *)tmpSmp.pek + 1; // yes, this is aligned to words
-
- for (i = 0; i < sampleLength; i++, audioDataS16_2++)
- audioDataS16[i] = audioDataS16_2[i];
-
- sampleLength *= 2;
- tmpSmp.typ |= 16; // 16-bit
+ s->flags |= SAMPLE_16BIT;
}
else if (audioFormat == WAV_FORMAT_IEEE_FLOAT && bitsPerSample == 32) // 32-BIT FLOATING POINT SAMPLE
{
- sampleLength /= 4;
- if (!allocateTmpSmpData(&tmpSmp, sampleLength * 4))
+ sampleLength /= sizeof (float);
+ if (!allocateSmpData(s, sampleLength * sizeof (float), false))
{
loaderMsgBox("Not enough memory!");
return false;
}
- if (fread(tmpSmp.pek, sampleLength, 4, f) != 4)
+ if (fread(s->dataPtr, sampleLength, sizeof (float), f) != sizeof (float))
{
loaderMsgBox("General I/O error during loading! Is the file in use?");
return false;
}
- fAudioDataFloat = (float *)tmpSmp.pek;
+ fAudioDataFloat = (float *)s->dataPtr;
// stereo conversion
if (numChannels == 2)
@@ -517,29 +509,31 @@
normalize32BitFloatToSigned16Bit(fAudioDataFloat, sampleLength);
- ptr16 = (int16_t *)tmpSmp.pek;
+ ptr16 = (int16_t *)s->dataPtr;
for (i = 0; i < sampleLength; i++)
- ptr16[i] = (int16_t)fAudioDataFloat[i]; // should use SIMD if available
+ {
+ const int32_t smp32 = (const int32_t)fAudioDataFloat[i];
+ ptr16[i] = (int16_t)smp32;
+ }
- sampleLength *= 2;
- tmpSmp.typ |= 16; // 16-bit
+ s->flags |= SAMPLE_16BIT;
}
else if (audioFormat == WAV_FORMAT_IEEE_FLOAT && bitsPerSample == 64) // 64-BIT FLOATING POINT SAMPLE
{
- sampleLength /= 8;
- if (!allocateTmpSmpData(&tmpSmp, sampleLength * 8))
+ sampleLength /= sizeof (double);
+ if (!allocateSmpData(s, sampleLength * sizeof (double), false))
{
loaderMsgBox("Not enough memory!");
return false;
}
- if (fread(tmpSmp.pek, sampleLength, 8, f) != 8)
+ if (fread(s->dataPtr, sampleLength, sizeof (double), f) != sizeof (double))
{
loaderMsgBox("General I/O error during loading! Is the file in use?");
return false;
}
- dAudioDataDouble = (double *)tmpSmp.pek;
+ dAudioDataDouble = (double *)s->dataPtr;
// stereo conversion
if (numChannels == 2)
@@ -582,22 +576,28 @@
normalize64BitFloatToSigned16Bit(dAudioDataDouble, sampleLength);
- ptr16 = (int16_t *)tmpSmp.pek;
+ ptr16 = (int16_t *)s->dataPtr;
for (i = 0; i < sampleLength; i++)
- ptr16[i] = (int16_t)dAudioDataDouble[i]; // should use SIMD if available
+ {
+ const int32_t smp32 = (const int32_t)dAudioDataDouble[i];
+ ptr16[i] = (int16_t)smp32;
+ }
- sampleLength *= 2;
- tmpSmp.typ |= 16; // 16-bit
+ s->flags |= SAMPLE_16BIT;
}
- reallocateTmpSmpData(&tmpSmp, sampleLength); // readjust memory needed
+ if (sampleLength > MAX_SAMPLE_LEN)
+ sampleLength = MAX_SAMPLE_LEN;
- tuneSample(&tmpSmp, sampleRate, audio.linearPeriodsFlag);
+ bool sample16Bit = !!(s->flags & SAMPLE_16BIT);
+ reallocateSmpData(s, sampleLength, sample16Bit); // readjust memory needed
- tmpSmp.vol = 64;
- tmpSmp.pan = 128;
- tmpSmp.len = sampleLength;
+ tuneSample(s, sampleRate, audio.linearPeriodsFlag);
+ s->volume = 64;
+ s->panning = 128;
+ s->length = sampleLength;
+
// ---- READ "smpl" chunk ----
if (smplPtr != 0 && smplLen > 52)
{
@@ -612,19 +612,14 @@
fread(&loopType, 4, 1, f);
fread(&loopStart, 4, 1, f);
- fread(&loopEnd, 4, 1, f); loopEnd++;
+ fread(&loopEnd, 4, 1, f);
- if (tmpSmp.typ & 16)
- {
- loopStart *= 2;
- loopEnd *= 2;
- }
-
+ loopEnd++;
if (loopEnd <= sampleLength)
{
- tmpSmp.repS = loopStart;
- tmpSmp.repL = loopEnd - loopStart;
- tmpSmp.typ |= (loopType == 0) ? 1 : 2;
+ s->loopStart = loopStart;
+ s->loopLength = loopEnd - loopStart;
+ s->flags |= (loopType == 0) ? LOOP_FWD : LOOP_BIDI;
}
}
}
@@ -646,7 +641,7 @@
if (tmpPan > 255)
tmpPan = 255;
- tmpSmp.pan = (uint8_t)tmpPan;
+ s->panning = (uint8_t)tmpPan;
}
else
{
@@ -659,7 +654,7 @@
if (tmpVol > 256)
tmpVol = 256;
- tmpSmp.vol = (uint8_t)((tmpVol + 2) / 4); // 0..256 -> 0..64 (rounded)
+ s->volume = (uint8_t)((tmpVol + 2) / 4); // 0..256 -> 0..64 (rounded)
}
// ---------------------------
@@ -667,20 +662,11 @@
if (inamPtr != 0 && inamLen > 0)
{
fseek(f, inamPtr, SEEK_SET);
+ if (inamLen > 22)
+ inamLen = 22;
- uint32_t len = 22;
- if (len > inamLen)
- len = inamLen;
-
- memset(tmpSmp.name, 0, sizeof (tmpSmp.name));
- for (i = 0; i < len; i++)
- {
- char chr = (char)fgetc(f);
- if (chr == '\0')
- break;
-
- tmpSmp.name[i] = chr;
- }
+ fread(s->name, 1, inamLen, f);
+ s->name[22] = '\0';
smpFilenameSet = true;
}
--- a/vs2019_project/ft2-clone/ft2-clone.vcxproj
+++ b/vs2019_project/ft2-clone/ft2-clone.vcxproj
@@ -92,7 +92,7 @@
<Optimization>MaxSpeed</Optimization>
<AdditionalIncludeDirectories>
</AdditionalIncludeDirectories>
- <PreprocessorDefinitions>__WINDOWS_MM__;NDEBUG;WIN32;_CRT_SECURE_NO_WARNINGS;HAS_MIDI</PreprocessorDefinitions>
+ <PreprocessorDefinitions>__WINDOWS_MM__;NDEBUG;WIN32;_CRT_SECURE_NO_WARNINGS;HAS_MIDI;HAS_LIBFLAC</PreprocessorDefinitions>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<IntrinsicFunctions>true</IntrinsicFunctions>
<StringPooling>true</StringPooling>
@@ -100,7 +100,6 @@
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
<FunctionLevelLinking>true</FunctionLevelLinking>
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
- <FloatingPointModel>Fast</FloatingPointModel>
<OmitFramePointers>true</OmitFramePointers>
<BufferSecurityCheck>false</BufferSecurityCheck>
<EnableEnhancedInstructionSet>StreamingSIMDExtensions2</EnableEnhancedInstructionSet>
@@ -108,6 +107,7 @@
<InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
<TreatWChar_tAsBuiltInType>false</TreatWChar_tAsBuiltInType>
<RuntimeTypeInfo>false</RuntimeTypeInfo>
+ <FloatingPointModel>Fast</FloatingPointModel>
</ClCompile>
<Link>
<AdditionalLibraryDirectories>
@@ -142,7 +142,7 @@
<Optimization>MaxSpeed</Optimization>
<AdditionalIncludeDirectories>
</AdditionalIncludeDirectories>
- <PreprocessorDefinitions>__WINDOWS_MM__;NDEBUG;WIN32;_CRT_SECURE_NO_WARNINGS;HAS_MIDI</PreprocessorDefinitions>
+ <PreprocessorDefinitions>__WINDOWS_MM__;NDEBUG;WIN32;_CRT_SECURE_NO_WARNINGS;HAS_MIDI;HAS_LIBFLAC</PreprocessorDefinitions>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<IntrinsicFunctions>true</IntrinsicFunctions>
<StringPooling>true</StringPooling>
@@ -149,7 +149,6 @@
<MinimalRebuild>false</MinimalRebuild>
<FunctionLevelLinking>true</FunctionLevelLinking>
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
- <FloatingPointModel>Fast</FloatingPointModel>
<OmitFramePointers>true</OmitFramePointers>
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
<InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
@@ -157,6 +156,7 @@
<DebugInformationFormat>None</DebugInformationFormat>
<TreatWChar_tAsBuiltInType>false</TreatWChar_tAsBuiltInType>
<RuntimeTypeInfo>false</RuntimeTypeInfo>
+ <FloatingPointModel>Fast</FloatingPointModel>
</ClCompile>
<Link>
<AdditionalLibraryDirectories>
@@ -199,11 +199,11 @@
<WarningLevel>Level4</WarningLevel>
<AdditionalIncludeDirectories>
</AdditionalIncludeDirectories>
- <PreprocessorDefinitions>__WINDOWS_MM__;_CRTDBG_MAP_ALLOC;DEBUG;_DEBUG;WIN32;_CRT_SECURE_NO_WARNINGS;HAS_MIDI</PreprocessorDefinitions>
- <FloatingPointModel>Fast</FloatingPointModel>
+ <PreprocessorDefinitions>__WINDOWS_MM__;_CRTDBG_MAP_ALLOC;DEBUG;_DEBUG;WIN32;_CRT_SECURE_NO_WARNINGS;HAS_MIDI;HAS_LIBFLAC</PreprocessorDefinitions>
<EnableEnhancedInstructionSet>StreamingSIMDExtensions2</EnableEnhancedInstructionSet>
<TreatWChar_tAsBuiltInType>false</TreatWChar_tAsBuiltInType>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
+ <FloatingPointModel>Fast</FloatingPointModel>
</ClCompile>
<Link>
<AdditionalLibraryDirectories>
@@ -238,13 +238,13 @@
<WarningLevel>Level4</WarningLevel>
<AdditionalIncludeDirectories>
</AdditionalIncludeDirectories>
- <PreprocessorDefinitions>__WINDOWS_MM__;_CRTDBG_MAP_ALLOC;DEBUG;_DEBUG;WIN32;_CRT_SECURE_NO_WARNINGS;HAS_MIDI</PreprocessorDefinitions>
- <FloatingPointModel>Fast</FloatingPointModel>
+ <PreprocessorDefinitions>__WINDOWS_MM__;_CRTDBG_MAP_ALLOC;DEBUG;_DEBUG;WIN32;_CRT_SECURE_NO_WARNINGS;HAS_MIDI;HAS_LIBFLAC</PreprocessorDefinitions>
<StringPooling>
</StringPooling>
<OmitFramePointers>false</OmitFramePointers>
<TreatWChar_tAsBuiltInType>false</TreatWChar_tAsBuiltInType>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
+ <FloatingPointModel>Fast</FloatingPointModel>
</ClCompile>
<Link>
<AdditionalLibraryDirectories>
@@ -318,8 +318,6 @@
<ClCompile Include="..\..\src\ft2_sample_ed.c" />
<ClCompile Include="..\..\src\ft2_sample_loader.c" />
<ClCompile Include="..\..\src\ft2_sample_saver.c" />
- <ClCompile Include="..\..\src\ft2_scopedraw.c" />
- <ClCompile Include="..\..\src\ft2_scopes.c" />
<ClCompile Include="..\..\src\ft2_scrollbars.c" />
<ClCompile Include="..\..\src\ft2_structs.c" />
<ClCompile Include="..\..\src\ft2_sysreqs.c" />
@@ -338,6 +336,19 @@
<ClCompile Include="..\..\src\gfxdata\ft2_bmp_instr.c" />
<ClCompile Include="..\..\src\gfxdata\ft2_bmp_looppins.c" />
<ClCompile Include="..\..\src\gfxdata\ft2_bmp_scopes.c" />
+ <ClCompile Include="..\..\src\libflac\bitmath.c" />
+ <ClCompile Include="..\..\src\libflac\bitreader.c" />
+ <ClCompile Include="..\..\src\libflac\crc.c" />
+ <ClCompile Include="..\..\src\libflac\fixed.c" />
+ <ClCompile Include="..\..\src\libflac\format.c" />
+ <ClCompile Include="..\..\src\libflac\lpc.c" />
+ <ClCompile Include="..\..\src\libflac\md5.c" />
+ <ClCompile Include="..\..\src\libflac\memory.c" />
+ <ClCompile Include="..\..\src\libflac\metadata_iterators.c" />
+ <ClCompile Include="..\..\src\libflac\metadata_object.c" />
+ <ClCompile Include="..\..\src\libflac\stream_decoder.c" />
+ <ClCompile Include="..\..\src\libflac\window.c" />
+ <ClCompile Include="..\..\src\libflac\windows_unicode_filenames.c" />
<ClCompile Include="..\..\src\mixer\ft2_windowed_sinc.c" />
<ClCompile Include="..\..\src\mixer\ft2_mix.c" />
<ClCompile Include="..\..\src\mixer\ft2_center_mix.c" />
@@ -359,12 +370,11 @@
<ExceptionHandling Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Sync</ExceptionHandling>
<ExceptionHandling Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Sync</ExceptionHandling>
<ExceptionHandling Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Sync</ExceptionHandling>
- <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">4245;4996;4267</DisableSpecificWarnings>
- <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Release|x64'">4245;4996;4267</DisableSpecificWarnings>
- <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">4245;4996;4267</DisableSpecificWarnings>
- <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">4245;4996;4267</DisableSpecificWarnings>
</ClCompile>
+ <ClCompile Include="..\..\src\scopes\ft2_scopedraw.c" />
+ <ClCompile Include="..\..\src\scopes\ft2_scopes.c" />
<ClCompile Include="..\..\src\smploaders\ft2_load_aiff.c" />
+ <ClCompile Include="..\..\src\smploaders\ft2_load_flac.c" />
<ClCompile Include="..\..\src\smploaders\ft2_load_iff.c" />
<ClCompile Include="..\..\src\smploaders\ft2_load_raw.c" />
<ClCompile Include="..\..\src\smploaders\ft2_load_wav.c" />
@@ -376,6 +386,7 @@
<ClInclude Include="..\..\src\ft2_bmp.h" />
<ClInclude Include="..\..\src\ft2_checkboxes.h" />
<ClInclude Include="..\..\src\ft2_config.h" />
+ <ClInclude Include="..\..\src\ft2_cpu.h" />
<ClInclude Include="..\..\src\ft2_diskop.h" />
<ClInclude Include="..\..\src\ft2_edit.h" />
<ClInclude Include="..\..\src\ft2_events.h" />
@@ -402,7 +413,6 @@
<ClInclude Include="..\..\src\ft2_sample_loader.h" />
<ClInclude Include="..\..\src\ft2_sample_saver.h" />
<ClInclude Include="..\..\src\ft2_scopedraw.h" />
- <ClInclude Include="..\..\src\ft2_scopes.h" />
<ClInclude Include="..\..\src\ft2_scrollbars.h" />
<ClInclude Include="..\..\src\ft2_structs.h" />
<ClInclude Include="..\..\src\ft2_sysreqs.h" />
@@ -419,6 +429,9 @@
<ClInclude Include="..\..\src\mixer\ft2_silence_mix.h" />
<ClInclude Include="..\..\src\rtmidi\RtMidi.h" />
<ClInclude Include="..\..\src\rtmidi\rtmidi_c.h" />
+ <ClInclude Include="..\..\src\scopes\ft2_scopedraw.h" />
+ <ClInclude Include="..\..\src\scopes\ft2_scopes.h" />
+ <ClInclude Include="..\..\src\scopes\ft2_scope_macros.h" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="..\..\src\ft2-clone.rc" />
--- a/vs2019_project/ft2-clone/ft2-clone.vcxproj.filters
+++ b/vs2019_project/ft2-clone/ft2-clone.vcxproj.filters
@@ -11,7 +11,6 @@
<ClCompile Include="..\..\src\ft2_edit.c" />
<ClCompile Include="..\..\src\ft2_events.c" />
<ClCompile Include="..\..\src\ft2_gui.c" />
- <ClCompile Include="..\..\src\ft2_help.c" />
<ClCompile Include="..\..\src\ft2_inst_ed.c" />
<ClCompile Include="..\..\src\ft2_keyboard.c" />
<ClCompile Include="..\..\src\ft2_main.c" />
@@ -31,8 +30,6 @@
<ClCompile Include="..\..\src\ft2_sample_loader.c" />
<ClCompile Include="..\..\src\ft2_sample_saver.c" />
<ClCompile Include="..\..\src\ft2_sampling.c" />
- <ClCompile Include="..\..\src\ft2_scopedraw.c" />
- <ClCompile Include="..\..\src\ft2_scopes.c" />
<ClCompile Include="..\..\src\ft2_scrollbars.c" />
<ClCompile Include="..\..\src\ft2_structs.c" />
<ClCompile Include="..\..\src\ft2_sysreqs.c" />
@@ -49,31 +46,31 @@
<Filter>rtmidi</Filter>
</ClCompile>
<ClCompile Include="..\..\src\gfxdata\ft2_bmp_fonts.c">
- <Filter>graphics</Filter>
+ <Filter>libflac\graphics</Filter>
</ClCompile>
<ClCompile Include="..\..\src\gfxdata\ft2_bmp_gui.c">
- <Filter>graphics</Filter>
+ <Filter>libflac\graphics</Filter>
</ClCompile>
<ClCompile Include="..\..\src\gfxdata\ft2_bmp_instr.c">
- <Filter>graphics</Filter>
+ <Filter>libflac\graphics</Filter>
</ClCompile>
<ClCompile Include="..\..\src\gfxdata\ft2_bmp_logo.c">
- <Filter>graphics</Filter>
+ <Filter>libflac\graphics</Filter>
</ClCompile>
<ClCompile Include="..\..\src\gfxdata\ft2_bmp_looppins.c">
- <Filter>graphics</Filter>
+ <Filter>libflac\graphics</Filter>
</ClCompile>
<ClCompile Include="..\..\src\gfxdata\ft2_bmp_midi.c">
- <Filter>graphics</Filter>
+ <Filter>libflac\graphics</Filter>
</ClCompile>
<ClCompile Include="..\..\src\gfxdata\ft2_bmp_mouse.c">
- <Filter>graphics</Filter>
+ <Filter>libflac\graphics</Filter>
</ClCompile>
<ClCompile Include="..\..\src\gfxdata\ft2_bmp_nibbles.c">
- <Filter>graphics</Filter>
+ <Filter>libflac\graphics</Filter>
</ClCompile>
<ClCompile Include="..\..\src\gfxdata\ft2_bmp_scopes.c">
- <Filter>graphics</Filter>
+ <Filter>libflac\graphics</Filter>
</ClCompile>
<ClCompile Include="..\..\src\mixer\ft2_mix.c">
<Filter>mixer</Filter>
@@ -117,6 +114,55 @@
<ClCompile Include="..\..\src\smploaders\ft2_load_wav.c">
<Filter>smploaders</Filter>
</ClCompile>
+ <ClCompile Include="..\..\src\smploaders\ft2_load_flac.c">
+ <Filter>smploaders</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\src\libflac\bitmath.c">
+ <Filter>libflac</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\src\libflac\bitreader.c">
+ <Filter>libflac</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\src\libflac\crc.c">
+ <Filter>libflac</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\src\libflac\fixed.c">
+ <Filter>libflac</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\src\libflac\format.c">
+ <Filter>libflac</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\src\libflac\lpc.c">
+ <Filter>libflac</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\src\libflac\md5.c">
+ <Filter>libflac</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\src\libflac\memory.c">
+ <Filter>libflac</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\src\libflac\metadata_iterators.c">
+ <Filter>libflac</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\src\libflac\metadata_object.c">
+ <Filter>libflac</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\src\libflac\stream_decoder.c">
+ <Filter>libflac</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\src\libflac\window.c">
+ <Filter>libflac</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\src\ft2_help.c" />
+ <ClCompile Include="..\..\src\libflac\windows_unicode_filenames.c">
+ <Filter>libflac</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\src\scopes\ft2_scopedraw.c">
+ <Filter>scopes</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\src\scopes\ft2_scopes.c">
+ <Filter>scopes</Filter>
+ </ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\src\rtmidi\RtMidi.h">
@@ -221,9 +267,6 @@
<ClInclude Include="..\..\src\ft2_scopedraw.h">
<Filter>headers</Filter>
</ClInclude>
- <ClInclude Include="..\..\src\ft2_scopes.h">
- <Filter>headers</Filter>
- </ClInclude>
<ClInclude Include="..\..\src\ft2_scrollbars.h">
<Filter>headers</Filter>
</ClInclude>
@@ -266,14 +309,23 @@
<ClInclude Include="..\..\src\mixer\ft2_windowed_sinc.h">
<Filter>mixer</Filter>
</ClInclude>
+ <ClInclude Include="..\..\src\scopes\ft2_scope_macros.h">
+ <Filter>scopes</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\src\scopes\ft2_scopedraw.h">
+ <Filter>scopes</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\src\scopes\ft2_scopes.h">
+ <Filter>scopes</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\src\ft2_cpu.h">
+ <Filter>headers</Filter>
+ </ClInclude>
</ItemGroup>
<ItemGroup>
<Filter Include="headers">
<UniqueIdentifier>{559f399e-331e-4688-8a7d-328ca6739456}</UniqueIdentifier>
</Filter>
- <Filter Include="graphics">
- <UniqueIdentifier>{c6fad604-509b-4072-b181-d47835f08428}</UniqueIdentifier>
- </Filter>
<Filter Include="mixer">
<UniqueIdentifier>{5c40c417-c4bb-4cf2-b71b-c557bf0a86cd}</UniqueIdentifier>
</Filter>
@@ -285,6 +337,15 @@
</Filter>
<Filter Include="rtmidi">
<UniqueIdentifier>{95e882a1-e589-4684-a3cb-48e0a1d073aa}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="libflac">
+ <UniqueIdentifier>{13e9047f-28ee-414f-9e23-4ad54deb281e}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="scopes">
+ <UniqueIdentifier>{8ac888cf-e1a5-4633-bcca-240a8eae2e23}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="libflac\graphics">
+ <UniqueIdentifier>{c6fad604-509b-4072-b181-d47835f08428}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>