summaryrefslogtreecommitdiffstats
path: root/lib/rbcodec/codecs
diff options
context:
space:
mode:
Diffstat (limited to 'lib/rbcodec/codecs')
-rw-r--r--lib/rbcodec/codecs/SOURCES2
-rw-r--r--lib/rbcodec/codecs/aac.c67
-rw-r--r--lib/rbcodec/codecs/alac.c73
-rw-r--r--lib/rbcodec/codecs/atrac3_oma.c11
-rw-r--r--lib/rbcodec/codecs/atrac3_rm.c3
-rw-r--r--lib/rbcodec/codecs/cRSID/C64/C64.c198
-rw-r--r--lib/rbcodec/codecs/cRSID/C64/CIA.c93
-rw-r--r--lib/rbcodec/codecs/cRSID/C64/CPU.c423
-rw-r--r--lib/rbcodec/codecs/cRSID/C64/MEM.c132
-rw-r--r--lib/rbcodec/codecs/cRSID/C64/SID.c276
-rw-r--r--lib/rbcodec/codecs/cRSID/C64/SID.h824
-rw-r--r--lib/rbcodec/codecs/cRSID/C64/VIC.c64
-rw-r--r--lib/rbcodec/codecs/cRSID/C64/libcRSIDc64.h172
-rw-r--r--lib/rbcodec/codecs/cRSID/README.rockbox19
-rw-r--r--lib/rbcodec/codecs/cRSID/README.txt39
-rw-r--r--lib/rbcodec/codecs/cRSID/SOURCES1
-rw-r--r--lib/rbcodec/codecs/cRSID/cRSID.make16
-rw-r--r--lib/rbcodec/codecs/cRSID/host/audio.c62
-rw-r--r--lib/rbcodec/codecs/cRSID/host/file.c60
-rw-r--r--lib/rbcodec/codecs/cRSID/libcRSID.c134
-rw-r--r--lib/rbcodec/codecs/cRSID/libcRSID.h59
-rw-r--r--lib/rbcodec/codecs/codecs.h32
-rw-r--r--lib/rbcodec/codecs/codecs.make5
-rw-r--r--lib/rbcodec/codecs/demac/libdemac/udiv32_arm.S2
-rw-r--r--lib/rbcodec/codecs/demac/libdemac/vector_math16_armv6.h26
-rw-r--r--lib/rbcodec/codecs/libatrac/atrac3.c12
-rw-r--r--lib/rbcodec/codecs/libatrac/atrac3.h2
-rw-r--r--lib/rbcodec/codecs/libfaad/common.h22
-rw-r--r--lib/rbcodec/codecs/libfaad/decoder.c6
-rw-r--r--lib/rbcodec/codecs/libfaad/specrec.c8
-rw-r--r--lib/rbcodec/codecs/libffmpegFLAC/decoder.c19
-rw-r--r--lib/rbcodec/codecs/libgme/blip_buffer.c2
-rw-r--r--lib/rbcodec/codecs/libm4a/demux.c178
-rw-r--r--lib/rbcodec/codecs/libm4a/m4a.c203
-rw-r--r--lib/rbcodec/codecs/libm4a/m4a.h18
-rw-r--r--lib/rbcodec/codecs/libmusepack/mpc_decoder.c2
-rw-r--r--lib/rbcodec/codecs/libopus/ogg/framing.c5
-rw-r--r--lib/rbcodec/codecs/libopus/silk/NLSF2A.c2
-rw-r--r--lib/rbcodec/codecs/libtta/filter_arm.S4
-rw-r--r--lib/rbcodec/codecs/mpa.c182
-rw-r--r--lib/rbcodec/codecs/sid.c1308
41 files changed, 3111 insertions, 1655 deletions
diff --git a/lib/rbcodec/codecs/SOURCES b/lib/rbcodec/codecs/SOURCES
index 78b7b97498..44b79087fe 100644
--- a/lib/rbcodec/codecs/SOURCES
+++ b/lib/rbcodec/codecs/SOURCES
@@ -17,7 +17,6 @@ atrac3_rm.c
atrac3_oma.c
mpc.c
wma.c
-sid.c
ape.c
asap.c
aac.c
@@ -43,6 +42,7 @@ nsf.c
sgc.c
vgm.c
#if MEMORYSIZE > 2
+sid.c
kss.c
#endif
aac_bsf.c
diff --git a/lib/rbcodec/codecs/aac.c b/lib/rbcodec/codecs/aac.c
index c00946f227..67cfd09ded 100644
--- a/lib/rbcodec/codecs/aac.c
+++ b/lib/rbcodec/codecs/aac.c
@@ -28,7 +28,7 @@
CODEC_HEADER
/* The maximum buffer size handled by faad. 12 bytes are required by libfaad
- * as headroom (see libfaad/bits.c). FAAD_BYTE_BUFFER_SIZE bytes are buffered
+ * as headroom (see libfaad/bits.c). FAAD_BYTE_BUFFER_SIZE bytes are buffered
* for each frame. */
#define FAAD_BYTE_BUFFER_SIZE (2048-12)
@@ -56,13 +56,13 @@ enum codec_status codec_run(void)
size_t n;
demux_res_t demux_res;
stream_t input_stream;
- uint32_t sound_samples_done;
+ uint64_t sound_samples_done;
uint32_t elapsed_time;
int file_offset;
int framelength;
int lead_trim = 0;
unsigned int frame_samples;
- unsigned int i;
+ uint32_t i;
unsigned char* buffer;
NeAACDecFrameInfo frame_info;
NeAACDecHandle decoder;
@@ -92,7 +92,7 @@ enum codec_status codec_run(void)
stream_create(&input_stream,ci);
- ci->seek_buffer(ci->id3->first_frame_offset);
+ ci->seek_buffer(0);
/* if qtmovie_read returns successfully, the stream is up to
* the movie data, which can be used directly by the decoder */
@@ -129,30 +129,30 @@ enum codec_status codec_run(void)
#endif
i = 0;
-
- if (file_offset > 0) {
+
+ if (param) {
+ elapsed_time = param;
+ action = CODEC_ACTION_SEEK_TIME;
+ } else if (file_offset > 0) {
/* Resume the desired (byte) position. Important: When resuming SBR
- * upsampling files the resulting sound_samples_done must be expanded
+ * upsampling files the resulting sound_samples_done must be expanded
* by a factor of 2. This is done via using sbr_fac. */
if (m4a_seek_raw(&demux_res, &input_stream, file_offset,
- &sound_samples_done, (int*) &i)) {
+ &sound_samples_done, &i, &seek_idx)) {
sound_samples_done *= sbr_fac;
} else {
sound_samples_done = 0;
}
NeAACDecPostSeekReset(decoder, i);
elapsed_time = sound_samples_done * 1000LL / ci->id3->frequency;
- } else if (param) {
- elapsed_time = param;
- action = CODEC_ACTION_SEEK_TIME;
} else {
elapsed_time = 0;
sound_samples_done = 0;
}
ci->set_elapsed(elapsed_time);
-
- if (i == 0)
+
+ if (i == 0)
{
lead_trim = ci->id3->lead_trim;
}
@@ -168,46 +168,43 @@ enum codec_status codec_run(void)
/* Deal with any pending seek requests */
if (action == CODEC_ACTION_SEEK_TIME) {
/* Seek to the desired time position. Important: When seeking in SBR
- * upsampling files the seek_time must be divided by 2 when calling
- * m4a_seek and the resulting sound_samples_done must be expanded
+ * upsampling files the seek_time must be divided by 2 when calling
+ * m4a_seek and the resulting sound_samples_done must be expanded
* by a factor 2. This is done via using sbr_fac. */
if (m4a_seek(&demux_res, &input_stream,
- (param/10/sbr_fac)*(ci->id3->frequency/100),
- &sound_samples_done, (int*) &i)) {
+ (uint64_t) param * ci->id3->frequency / sbr_fac / 1000ULL,
+ &sound_samples_done, &i, &seek_idx)) {
sound_samples_done *= sbr_fac;
elapsed_time = sound_samples_done * 1000LL / ci->id3->frequency;
ci->set_elapsed(elapsed_time);
- seek_idx = 0;
- if (i == 0)
+ if (i == 0)
{
lead_trim = ci->id3->lead_trim;
}
}
NeAACDecPostSeekReset(decoder, i);
ci->seek_complete();
+ if (i >= demux_res.num_sample_byte_sizes)
+ break;
}
action = CODEC_ACTION_NULL;
/* There can be gaps between chunks, so skip ahead if needed. It
- * doesn't seem to happen much, but it probably means that a
+ * doesn't seem to happen much, but it probably means that a
* "proper" file can have chunks out of order. Why one would want
- * that an good question (but files with gaps do exist, so who
- * knows?), so we don't support that - for now, at least.
+ * that an good question (but files with gaps do exist, so who
+ * knows?), and we might not properly support it.
+ * Metadata can also be placed after audio data so skip back if needed.
*/
file_offset = m4a_check_sample_offset(&demux_res, i, &seek_idx);
- if (file_offset > ci->curpos)
+ if (file_offset > 0 && file_offset != ci->curpos)
{
- ci->advance_buffer(file_offset - ci->curpos);
+ ci->seek_buffer(file_offset);
}
- else if (file_offset == 0)
- {
- LOGF("AAC: get_sample_offset error\n");
- return CODEC_ERROR;
- }
-
+
/* Request the required number of bytes from the input buffer */
buffer=ci->request_buffer(&n, FAAD_BYTE_BUFFER_SIZE);
@@ -217,7 +214,11 @@ enum codec_status codec_run(void)
/* NeAACDecDecode may sometimes return NULL without setting error. */
if (ret == NULL || frame_info.error > 0) {
LOGF("FAAD: decode error '%s'\n", NeAACDecGetErrorMessage(frame_info.error));
- return CODEC_ERROR;
+
+ // In files with gaps between chunks and reduced lookup_table we can't properly detect all gaps
+ // in m4a_check_sample_offset. So just ignore decode errors till next chunk present in lookup_table
+ if (file_offset > 0)
+ return CODEC_ERROR;
}
/* Advance codec buffer (no need to call set_offset because of this) */
@@ -225,7 +226,7 @@ enum codec_status codec_run(void)
/* Output the audio */
ci->yield();
-
+
frame_samples = frame_info.samples >> 1;
if (empty_first_frame)
@@ -244,7 +245,7 @@ enum codec_status codec_run(void)
/* Gather number of samples for the decoded frame. */
framelength = frame_samples - lead_trim;
-
+
if (i == demux_res.num_sample_byte_sizes - 1)
{
// Size of the last frame
diff --git a/lib/rbcodec/codecs/alac.c b/lib/rbcodec/codecs/alac.c
index 903ea2850e..34f447df47 100644
--- a/lib/rbcodec/codecs/alac.c
+++ b/lib/rbcodec/codecs/alac.c
@@ -25,12 +25,18 @@
CODEC_HEADER
-/* The maximum buffer size handled. This amount of bytes is buffered for each
+/* The maximum buffer size handled. This amount of bytes is buffered for each
* frame. */
#define ALAC_BYTE_BUFFER_SIZE 32768
static int32_t outputbuffer[ALAC_MAX_CHANNELS][ALAC_BLOCKSIZE] IBSS_ATTR;
+static void set_elapsed_samples(uint32_t samplesdone)
+{
+ uint32_t elapsedtime = (uint64_t)samplesdone * 1000ULL / ci->id3->frequency;
+ ci->set_elapsed(elapsedtime);
+}
+
/* this is the codec entry point */
enum codec_status codec_main(enum codec_entry_call_reason reason)
{
@@ -49,13 +55,16 @@ enum codec_status codec_run(void)
size_t n;
demux_res_t demux_res;
stream_t input_stream;
- uint32_t samplesdone;
- uint32_t elapsedtime;
+ uint64_t samplesdone;
int samplesdecoded;
- unsigned int i;
+ uint32_t i;
unsigned char* buffer;
alac_file alac;
intptr_t param;
+ unsigned long resume_time;
+ uint32_t resume_offset;
+ unsigned int did_resume;
+ uint32_t lookup_table_idx = 0;
/* Clean and initialize decoder structures */
memset(&demux_res , 0, sizeof(demux_res));
@@ -71,10 +80,10 @@ enum codec_status codec_run(void)
stream_create(&input_stream,ci);
- /* Read resume info before calling qtmovie_read. */
- elapsedtime = ci->id3->elapsed;
- samplesdone = ci->id3->offset;
-
+ /* Save resume info because qtmovie_read() can modify it. */
+ resume_time = ci->id3->elapsed;
+ resume_offset = ci->id3->offset;
+
/* if qtmovie_read returns successfully, the stream is up to
* the movie data, which can be used directly by the decoder */
if (!qtmovie_read(&input_stream, &demux_res)) {
@@ -84,28 +93,24 @@ enum codec_status codec_run(void)
/* initialise the sound converter */
alac_set_info(&alac, demux_res.codecdata);
-
- /* Set i for first frame, seek to desired sample position for resuming. */
- i=0;
-
- if (elapsedtime || samplesdone) {
- if (samplesdone) {
- samplesdone =
- (uint32_t)((uint64_t)samplesdone*ci->id3->frequency /
- (ci->id3->bitrate*128));
- }
- else {
- samplesdone = (elapsedtime/10) * (ci->id3->frequency/100);
- }
- if (!m4a_seek(&demux_res, &input_stream, samplesdone,
- &samplesdone, (int*) &i)) {
- samplesdone = 0;
- }
+ if (resume_time)
+ did_resume = m4a_seek(&demux_res, &input_stream,
+ (uint64_t)resume_time * ci->id3->frequency / 1000ULL,
+ &samplesdone, &i, &lookup_table_idx);
+ else if (resume_offset)
+ did_resume = m4a_seek_raw(&demux_res, &input_stream, resume_offset,
+ &samplesdone, &i, &lookup_table_idx);
+ else
+ did_resume = 0;
+
+ /* Start from the beginning if we did not resume. */
+ if (!did_resume) {
+ i = 0;
+ samplesdone = 0;
}
- elapsedtime = samplesdone * 1000LL / ci->id3->frequency;
- ci->set_elapsed(elapsedtime);
+ set_elapsed_samples(samplesdone);
/* The main decoding loop */
while (i < demux_res.num_sample_byte_sizes) {
@@ -117,12 +122,13 @@ enum codec_status codec_run(void)
/* Deal with any pending seek requests */
if (action == CODEC_ACTION_SEEK_TIME) {
if (m4a_seek(&demux_res, &input_stream,
- (param/10) * (ci->id3->frequency/100),
- &samplesdone, (int *)&i)) {
- elapsedtime=samplesdone*1000LL/ci->id3->frequency;
- }
- ci->set_elapsed(elapsedtime);
+ (uint64_t)param * ci->id3->frequency / 1000ULL,
+ &samplesdone, &i, &lookup_table_idx))
+ set_elapsed_samples(samplesdone);
+
ci->seek_complete();
+ if (i >= demux_res.num_sample_byte_sizes)
+ break;
}
/* Request the required number of bytes from the input buffer */
@@ -140,8 +146,7 @@ enum codec_status codec_run(void)
/* Update the elapsed-time indicator */
samplesdone+=samplesdecoded;
- elapsedtime=samplesdone*1000LL/ci->id3->frequency;
- ci->set_elapsed(elapsedtime);
+ set_elapsed_samples(samplesdone);
i++;
}
diff --git a/lib/rbcodec/codecs/atrac3_oma.c b/lib/rbcodec/codecs/atrac3_oma.c
index d394fffdcb..2b212ad5f8 100644
--- a/lib/rbcodec/codecs/atrac3_oma.c
+++ b/lib/rbcodec/codecs/atrac3_oma.c
@@ -23,7 +23,6 @@
#include "logf.h"
#include "codeclib.h"
-#include "inttypes.h"
#include "libatrac/atrac3.h"
CODEC_HEADER
@@ -66,12 +65,16 @@ enum codec_status codec_run(void)
ci->configure(DSP_SET_FREQUENCY, ci->id3->frequency);
ci->configure(DSP_SET_SAMPLE_DEPTH, 17); /* Remark: atrac3 uses s15.0 by default, s15.2 was hacked. */
- ci->configure(DSP_SET_STEREO_MODE, ci->id3->channels == 1 ?
+ const uint8_t channels = 2;
+ ci->configure(DSP_SET_STEREO_MODE, channels == 1 ?
STEREO_MONO : STEREO_NONINTERLEAVED);
ci->seek_buffer(0);
- res = atrac3_decode_init(&q, ci->id3);
+ /* fake the atrac3 extradata (wav format, makes stream copy to wav work) */
+ /* ATRAC3 expects and extra-data size of 14 bytes for wav format, and *
+ * looks for that in the id3v2buf. */
+ res = atrac3_decode_init(&q, ci->id3, channels, 14);
if(res < 0) {
DEBUGF("failed to initialize OMA atrac decoder\n");
return CODEC_ERROR;
@@ -143,7 +146,7 @@ enum codec_status codec_run(void)
if(datasize)
ci->pcmbuf_insert(q.outSamples, q.outSamples + 1024,
- q.samples_per_frame / ci->id3->channels);
+ q.samples_per_frame / channels);
elapsed += (FRAMESIZE * 8) / BITRATE;
ci->set_elapsed(elapsed);
diff --git a/lib/rbcodec/codecs/atrac3_rm.c b/lib/rbcodec/codecs/atrac3_rm.c
index af38b79fc4..b365dac926 100644
--- a/lib/rbcodec/codecs/atrac3_rm.c
+++ b/lib/rbcodec/codecs/atrac3_rm.c
@@ -22,7 +22,6 @@
#include <string.h>
#include "codeclib.h"
-#include "inttypes.h"
#include "libatrac/atrac3.h"
CODEC_HEADER
@@ -109,7 +108,7 @@ enum codec_status codec_run(void)
scrambling_unit_size = h * (fs + packet_header_size);
spn = h * fs / sps;
- res = atrac3_decode_init(&q, ci->id3);
+ res = atrac3_decode_init(&q, ci->id3, rmctx.nb_channels, rmctx.extradata_size);
if(res < 0) {
DEBUGF("failed to initialize RM atrac decoder\n");
return CODEC_ERROR;
diff --git a/lib/rbcodec/codecs/cRSID/C64/C64.c b/lib/rbcodec/codecs/cRSID/C64/C64.c
new file mode 100644
index 0000000000..f8e7a9a116
--- /dev/null
+++ b/lib/rbcodec/codecs/cRSID/C64/C64.c
@@ -0,0 +1,198 @@
+
+//C64 emulation (SID-playback related)
+
+
+#include "../libcRSID.h"
+#include "libcRSIDc64.h"
+
+#include "MEM.c"
+#include "CPU.c"
+#include "CIA.c"
+#include "VIC.c"
+#include "SID.c"
+
+
+cRSID_C64instance* cRSID_createC64 (cRSID_C64instance* C64, unsigned short samplerate) { //init a basic PAL C64 instance
+ if(samplerate) C64->SampleRate = samplerate;
+ else C64->SampleRate = samplerate = 44100;
+ C64->SampleClockRatio = (985248<<4)/samplerate; //shifting (multiplication) enhances SampleClockRatio precision
+ C64->Attenuation = 26;
+ C64->CPU.C64 = C64;
+ cRSID_createSIDchip ( C64, &C64->SID[1], 8580, 0xD400 ); //default C64 setup with only 1 SID and 2 CIAs and 1 VIC
+ cRSID_createCIAchip ( C64, &C64->CIA[1], 0xDC00 );
+ cRSID_createCIAchip ( C64, &C64->CIA[2], 0xDD00 );
+ cRSID_createVICchip ( C64, &C64->VIC, 0xD000 );
+ //if(C64->RealSIDmode) {
+ cRSID_setROMcontent ( C64 );
+ //}
+ cRSID_initC64(C64);
+ return C64;
+}
+
+
+void cRSID_setC64 (cRSID_C64instance* C64) { //set hardware-parameters (Models, SIDs) for playback of loaded SID-tune
+ enum C64clocks { C64_PAL_CPUCLK=985248, C64_NTSC_CPUCLK=1022727 };
+ enum C64scanlines { C64_PAL_SCANLINES = 312, C64_NTSC_SCANLINES = 263 };
+ enum C64scanlineCycles { C64_PAL_SCANLINE_CYCLES = 63, C64_NTSC_SCANLINE_CYCLES = 65 };
+ //enum C64framerates { PAL_FRAMERATE = 50, NTSC_FRAMERATE = 60 }; //Hz
+
+ static const unsigned int CPUspeeds[] = { C64_NTSC_CPUCLK, C64_PAL_CPUCLK };
+ static const unsigned short ScanLines[] = { C64_NTSC_SCANLINES, C64_PAL_SCANLINES };
+ static const unsigned char ScanLineCycles[] = { C64_NTSC_SCANLINE_CYCLES, C64_PAL_SCANLINE_CYCLES };
+ //unsigned char FrameRates[] = { NTSC_FRAMERATE, PAL_FRAMERATE };
+
+ static const short Attenuations[]={0,26,43,137}; //increase for 2SID (to 43) and 3SID (to 137)
+ short SIDmodel;
+ unsigned char SIDchipCount;
+
+
+ C64->VideoStandard = ( (C64->SIDheader->ModelFormatStandard & 0x0C) >> 2 ) != 2;
+ if (C64->SampleRate==0) C64->SampleRate = 44100;
+ C64->CPUfrequency = CPUspeeds[C64->VideoStandard];
+ C64->SampleClockRatio = ( C64->CPUfrequency << 4 ) / C64->SampleRate; //shifting (multiplication) enhances SampleClockRatio precision
+
+ C64->VIC.RasterLines = ScanLines[C64->VideoStandard];
+ C64->VIC.RasterRowCycles = ScanLineCycles[C64->VideoStandard];
+ C64->FrameCycles = C64->VIC.RasterLines * C64->VIC.RasterRowCycles; ///C64->SampleRate / PAL_FRAMERATE; //1x speed tune with VIC Vertical-blank timing
+
+ C64->PrevRasterLine=-1; //so if $d012 is set once only don't disturb FrameCycleCnt
+
+ C64->SID[1].ChipModel = (C64->SIDheader->ModelFormatStandard&0x30) >= 0x20? 8580:6581;
+
+ SIDmodel = C64->SIDheader->ModelFormatStandard & 0xC0;
+ if (SIDmodel) SIDmodel = (SIDmodel >= 0x80) ? 8580:6581; else SIDmodel = C64->SID[1].ChipModel;
+ cRSID_createSIDchip ( C64, &C64->SID[2], SIDmodel, 0xD000 + C64->SIDheader->SID2baseAddress*16 );
+
+ SIDmodel = C64->SIDheader->ModelFormatStandardH & 0x03;
+ if (SIDmodel) SIDmodel = (SIDmodel >= 0x02) ? 8580:6581; else SIDmodel = C64->SID[1].ChipModel;
+ cRSID_createSIDchip ( C64, &C64->SID[3], SIDmodel, 0xD000 + C64->SIDheader->SID3baseAddress*16 );
+
+ SIDchipCount = 1 + (C64->SID[2].BaseAddress > 0) + (C64->SID[3].BaseAddress > 0);
+ C64->Attenuation = Attenuations[SIDchipCount];
+}
+
+
+void cRSID_initC64 (cRSID_C64instance* C64) { //C64 Reset
+ cRSID_initSIDchip( &C64->SID[1] );
+ cRSID_initCIAchip( &C64->CIA[1] ); cRSID_initCIAchip( &C64->CIA[2] );
+ cRSID_initMem(C64);
+ cRSID_initCPU( &C64->CPU, (cRSID_readMemC64(C64,0xFFFD)<<8) + cRSID_readMemC64(C64,0xFFFC) );
+ C64->IRQ = C64->NMI = 0;
+}
+
+
+int cRSID_emulateC64 (cRSID_C64instance *C64) {
+ static unsigned char InstructionCycles;
+ static int Output;
+
+
+ //Cycle-based part of emulations:
+
+
+ while (C64->SampleCycleCnt <= C64->SampleClockRatio) {
+
+ if (!C64->RealSIDmode) {
+ if (C64->FrameCycleCnt >= C64->FrameCycles) {
+ C64->FrameCycleCnt -= C64->FrameCycles;
+ if (C64->Finished) { //some tunes (e.g. Barbarian, A-Maze-Ing) doesn't always finish in 1 frame
+ cRSID_initCPU ( &C64->CPU, C64->PlayAddress ); //(PSID docs say bank-register should always be set for each call's region)
+ C64->Finished=0; //C64->SampleCycleCnt=0; //PSID workaround for some tunes (e.g. Galdrumway):
+ if (C64->TimerSource==0) C64->IObankRD[0xD019] = 0x81; //always simulate to player-calls that VIC-IRQ happened
+ else C64->IObankRD[0xDC0D] = 0x83; //always simulate to player-calls that CIA TIMERA/TIMERB-IRQ happened
+ }}
+ if (C64->Finished==0) {
+ if ( (InstructionCycles = cRSID_emulateCPU()) >= 0xFE ) { InstructionCycles=6; C64->Finished=1; }
+ }
+ else InstructionCycles=7; //idle between player-calls
+ C64->FrameCycleCnt += InstructionCycles;
+ C64->IObankRD[0xDC04] += InstructionCycles; //very simple CIA1 TimerA simulation for PSID (e.g. Delta-Mix_E-Load_loader)
+ }
+
+ else { //RealSID emulations:
+ if ( cRSID_handleCPUinterrupts(&C64->CPU) ) { C64->Finished=0; InstructionCycles=7; }
+ else if (C64->Finished==0) {
+ if ( (InstructionCycles = cRSID_emulateCPU()) >= 0xFE ) {
+ InstructionCycles=6; C64->Finished=1;
+ }
+ }
+ else InstructionCycles=7; //idle between IRQ-calls
+ C64->IRQ = C64->NMI = 0; //prepare for collecting IRQ sources
+ C64->IRQ |= cRSID_emulateCIA (&C64->CIA[1], InstructionCycles);
+ C64->NMI |= cRSID_emulateCIA (&C64->CIA[2], InstructionCycles);
+ C64->IRQ |= cRSID_emulateVIC (&C64->VIC, InstructionCycles);
+ }
+
+ C64->SampleCycleCnt += (InstructionCycles<<4);
+
+ cRSID_emulateADSRs (&C64->SID[1], InstructionCycles);
+ if ( C64->SID[2].BaseAddress != 0 ) cRSID_emulateADSRs (&C64->SID[2], InstructionCycles);
+ if ( C64->SID[3].BaseAddress != 0 ) cRSID_emulateADSRs (&C64->SID[3], InstructionCycles);
+
+ }
+ C64->SampleCycleCnt -= C64->SampleClockRatio;
+
+
+ //Samplerate-based part of emulations:
+
+
+ if (!C64->RealSIDmode) { //some PSID tunes use CIA TOD-clock (e.g. Kawasaki Synthesizer Demo)
+ --C64->TenthSecondCnt;
+ if (C64->TenthSecondCnt <= 0) {
+ C64->TenthSecondCnt = C64->SampleRate / 10;
+ ++(C64->IObankRD[0xDC08]);
+ if(C64->IObankRD[0xDC08]>=10) {
+ C64->IObankRD[0xDC08]=0; ++(C64->IObankRD[0xDC09]);
+ //if(C64->IObankRD[0xDC09]%
+ }
+ }
+ }
+
+ Output = cRSID_emulateWaves (&C64->SID[1]);
+ if ( C64->SID[2].BaseAddress != 0 ) Output += cRSID_emulateWaves (&C64->SID[2]);
+ if ( C64->SID[3].BaseAddress != 0 ) Output += cRSID_emulateWaves (&C64->SID[3]);
+
+ return Output;
+}
+
+
+static inline short cRSID_playPSIDdigi(cRSID_C64instance* C64) {
+ enum PSIDdigiSpecs { DIGI_VOLUME = 1200 }; //80 };
+ static unsigned char PlaybackEnabled=0, NybbleCounter=0, RepeatCounter=0, Shifts;
+ static unsigned short SampleAddress, RatePeriod;
+ static short Output=0;
+ static int PeriodCounter;
+
+ if (C64->IObankWR[0xD41D]) {
+ PlaybackEnabled = (C64->IObankWR[0xD41D] >= 0xFE);
+ PeriodCounter = 0; NybbleCounter = 0;
+ SampleAddress = C64->IObankWR[0xD41E] + (C64->IObankWR[0xD41F]<<8);
+ RepeatCounter = C64->IObankWR[0xD43F];
+ }
+ C64->IObankWR[0xD41D] = 0;
+
+ if (PlaybackEnabled) {
+ RatePeriod = C64->IObankWR[0xD45D] + (C64->IObankWR[0xD45E]<<8);
+ if (RatePeriod) PeriodCounter += C64->CPUfrequency / RatePeriod;
+ if ( PeriodCounter >= C64->SampleRate ) {
+ PeriodCounter -= C64->SampleRate;
+
+ if ( SampleAddress < C64->IObankWR[0xD43D] + (C64->IObankWR[0xD43E]<<8) ) {
+ if (NybbleCounter) {
+ Shifts = C64->IObankWR[0xD47D] ? 4:0;
+ ++SampleAddress;
+ }
+ else Shifts = C64->IObankWR[0xD47D] ? 0:4;
+ Output = ( ( (C64->RAMbank[SampleAddress]>>Shifts) & 0xF) - 8 ) * DIGI_VOLUME; //* (C64->IObankWR[0xD418]&0xF);
+ NybbleCounter^=1;
+ }
+ else if (RepeatCounter) {
+ SampleAddress = C64->IObankWR[0xD47F] + (C64->IObankWR[0xD47E]<<8);
+ RepeatCounter--;
+ }
+
+ }
+ }
+
+ return Output;
+}
+
diff --git a/lib/rbcodec/codecs/cRSID/C64/CIA.c b/lib/rbcodec/codecs/cRSID/C64/CIA.c
new file mode 100644
index 0000000000..b562417480
--- /dev/null
+++ b/lib/rbcodec/codecs/cRSID/C64/CIA.c
@@ -0,0 +1,93 @@
+
+//cRSID CIA emulation
+
+
+void cRSID_createCIAchip (cRSID_C64instance* C64, cRSID_CIAinstance* CIA, unsigned short baseaddress) {
+ CIA->C64 = C64;
+ CIA->ChipModel = 0;
+ CIA->BaseAddress = baseaddress;
+ CIA->BasePtrWR = &C64->IObankWR[baseaddress]; CIA->BasePtrRD = &C64->IObankRD[baseaddress];
+ cRSID_initCIAchip(CIA);
+}
+
+
+void cRSID_initCIAchip (cRSID_CIAinstance* CIA) {
+ unsigned char i;
+ for (i=0; i<0x10; ++i) CIA->BasePtrWR[i] = CIA->BasePtrRD[i] = 0x00;
+}
+
+
+static inline char cRSID_emulateCIA (cRSID_CIAinstance* CIA, char cycles) {
+ static int Tmp;
+
+ enum CIAregisters { PORTA=0, PORTB=1, DDRA=2, DDRB=3,
+ TIMERAL=4, TIMERAH=5, TIMERBL=6, TIMERBH=7, //Write:Set Timer-latch, Read: read Timer
+ TOD_TENTHSECONDS=8, TOD_SECONDS=9, TOD_MINUTES=0xA, TOD_HOURS=0xB,
+ SERIAL_DATA=0xC, INTERRUPTS=0xD, CONTROLA=0xE, CONTROLB=0xF };
+
+ enum InterruptBitVal { INTERRUPT_HAPPENED=0x80, SET_OR_CLEAR_FLAGS=0x80, //(Read or Write operation determines which one:)
+ FLAGn=0x10, SERIALPORT=0x08, ALARM=0x04, TIMERB=0x02, TIMERA=0x01 }; //flags/masks of interrupt-sources
+
+ enum ControlAbitVal { ENABLE_TIMERA=0x01, PORTB6_TIMERA=0x02, TOGGLED_PORTB6=0x04, ONESHOT_TIMERA=0x08,
+ FORCELOADA_STROBE=0x10, TIMERA_FROM_CNT=0x20, SERIALPORT_IS_OUTPUT=0x40, TIMEOFDAY_50Hz=0x80 };
+
+ enum ControlBbitVal { ENABLE_TIMERB=0x01, PORTB7_TIMERB=0x02, TOGGLED_PORTB7=0x04, ONESHOT_TIMERB=0x08,
+ FORCELOADB_STROBE=0x10, TIMERB_FROM_CPUCLK=0x00, TIMERB_FROM_CNT=0x20, TIMERB_FROM_TIMERA=0x40,
+ TIMERB_FROM_TIMERA_AND_CNT = 0x60, TIMEOFDAY_WRITE_SETS_ALARM = 0x80 };
+
+ //TimerA
+ if (CIA->BasePtrWR[CONTROLA] & FORCELOADA_STROBE) { //force latch into counter (strobe-input)
+ CIA->BasePtrRD[TIMERAH] = CIA->BasePtrWR[TIMERAH]; CIA->BasePtrRD[TIMERAL] = CIA->BasePtrWR[TIMERAL];
+ }
+ else if ( (CIA->BasePtrWR[CONTROLA] & (ENABLE_TIMERA|TIMERA_FROM_CNT)) == ENABLE_TIMERA ) { //Enabled, counts Phi2
+ Tmp = ( (CIA->BasePtrRD[TIMERAH]<<8) + CIA->BasePtrRD[TIMERAL] ) - cycles; //count timer
+ if (Tmp <= 0) { //Timer counted down
+ Tmp += (CIA->BasePtrWR[TIMERAH]<<8) + CIA->BasePtrWR[TIMERAL]; //reload timer
+ if (CIA->BasePtrWR[CONTROLA] & ONESHOT_TIMERA) CIA->BasePtrWR[CONTROLA] &= ~ENABLE_TIMERA; //disable if one-shot
+ CIA->BasePtrRD[INTERRUPTS] |= TIMERA;
+ if (CIA->BasePtrWR[INTERRUPTS] & TIMERA) { //generate interrupt if mask allows
+ CIA->BasePtrRD[INTERRUPTS] |= INTERRUPT_HAPPENED;
+ }
+ }
+ CIA->BasePtrRD[TIMERAH] = (Tmp >> 8); CIA->BasePtrRD[TIMERAL] = Tmp & 0xFF;
+ }
+ CIA->BasePtrWR[CONTROLA] &= ~FORCELOADA_STROBE; //strobe is edge-sensitive
+ CIA->BasePtrRD[CONTROLA] = CIA->BasePtrWR[CONTROLA]; //control-registers are readable
+
+ //TimerB
+ if (CIA->BasePtrWR[CONTROLB] & FORCELOADB_STROBE) { //force latch into counter (strobe-input)
+ CIA->BasePtrRD[TIMERBH] = CIA->BasePtrWR[TIMERBH]; CIA->BasePtrRD[TIMERBL] = CIA->BasePtrWR[TIMERBL];
+ } //what about clocking TimerB by TimerA? (maybe not used in any music)
+ else if ( (CIA->BasePtrWR[CONTROLB] & (ENABLE_TIMERB|TIMERB_FROM_TIMERA)) == ENABLE_TIMERB ) { //Enabled, counts Phi2
+ Tmp = ( (CIA->BasePtrRD[TIMERBH]<<8) + CIA->BasePtrRD[TIMERBL] ) - cycles;//count timer
+ if (Tmp <= 0) { //Timer counted down
+ Tmp += (CIA->BasePtrWR[TIMERBH]<<8) + CIA->BasePtrWR[TIMERBL]; //reload timer
+ if (CIA->BasePtrWR[CONTROLB] & ONESHOT_TIMERB) CIA->BasePtrWR[CONTROLB] &= ~ENABLE_TIMERB; //disable if one-shot
+ CIA->BasePtrRD[INTERRUPTS] |= TIMERB;
+ if (CIA->BasePtrWR[INTERRUPTS] & TIMERB) { //generate interrupt if mask allows
+ CIA->BasePtrRD[INTERRUPTS] |= INTERRUPT_HAPPENED;
+ }
+ }
+ CIA->BasePtrRD[TIMERBH] = (Tmp >> 8); CIA->BasePtrRD[TIMERBL] = Tmp & 0xFF;
+ }
+ CIA->BasePtrWR[CONTROLB] &= ~FORCELOADB_STROBE; //strobe is edge-sensitive
+ CIA->BasePtrRD[CONTROLB] = CIA->BasePtrWR[CONTROLB]; //control-registers are readable
+
+ return (CIA->BasePtrRD[INTERRUPTS] & INTERRUPT_HAPPENED);
+}
+
+
+static inline void cRSID_writeCIAIRQmask (cRSID_CIAinstance* CIA, unsigned char value) {
+ if (value&0x80) CIA->BasePtrWR[0xD] |= (value&0x1F);
+ else CIA->BasePtrWR[0xD] &= ~(value&0x1F);
+}
+
+
+static inline void cRSID_acknowledgeCIAIRQ (cRSID_CIAinstance* CIA) {
+ CIA->BasePtrRD[0xD] = 0x00; //reading a CIA interrupt-register clears its read-part and IRQ-flag
+}
+
+
+//static inline void cRSID_writeCIARWreg () {
+ //mirroring write-latch to read-latch for Readable-Writeable registers?
+//}
diff --git a/lib/rbcodec/codecs/cRSID/C64/CPU.c b/lib/rbcodec/codecs/cRSID/C64/CPU.c
new file mode 100644
index 0000000000..692e666f8a
--- /dev/null
+++ b/lib/rbcodec/codecs/cRSID/C64/CPU.c
@@ -0,0 +1,423 @@
+
+//cRSID CPU-emulation
+
+
+void cRSID_initCPU (cRSID_CPUinstance* CPU, unsigned short mempos) {
+ CPU->PC = mempos; CPU->A = 0; CPU->X = 0; CPU->Y = 0; CPU->ST = 0x04; CPU->SP = 0xFF; CPU->PrevNMI = 0;
+}
+
+
+unsigned char cRSID_emulateCPU (void) { //the CPU emulation for SID/PRG playback (ToDo: CIA/VIC-IRQ/NMI/RESET vectors, BCD-mode)
+
+ enum StatusFlagBitValues { N=0x80, V=0x40, B=0x10, D=0x08, I=0x04, Z=0x02, C=0x01 };
+
+ static const unsigned char FlagSwitches[]={0x01,0x21,0x04,0x24,0x00,0x40,0x08,0x28}, BranchFlags[]={0x80,0x40,0x01,0x02};
+
+
+ static cRSID_C64instance* const C64 = &cRSID_C64; //could be a parameter but function-call is faster this way if only 1 main CPU exists
+ static cRSID_CPUinstance* const CPU = &C64->CPU;
+
+ static char Cycles, SamePage;
+ static unsigned char IR, ST, X, Y;
+ static short int A, SP, T;
+ static unsigned int PC, Addr, PrevPC;
+
+
+ inline void loadReg (void) { PC = CPU->PC; SP = CPU->SP; ST = CPU->ST; A = CPU->A; X = CPU->X; Y = CPU->Y; }
+ inline void storeReg (void) { CPU->PC = PC; CPU->SP = SP; CPU->ST = ST; CPU->A = A; CPU->X = X; CPU->Y = Y; }
+
+ inline unsigned char rd (register unsigned short address) {
+ static unsigned char value;
+ value = *cRSID_getMemReadPtr(address);
+ if (C64->RealSIDmode) {
+ if ( C64->RAMbank[1] & 3 ) {
+ if (address==0xDC0D) { cRSID_acknowledgeCIAIRQ( &C64->CIA[1] ); }
+ else if (address==0xDD0D) { cRSID_acknowledgeCIAIRQ( &C64->CIA[2] ); }
+ }
+ }
+ return value;
+ }
+
+ inline void wr (register unsigned short address, register unsigned char data) {
+ *cRSID_getMemWritePtr(address)=data;
+ if ( C64->RealSIDmode && (C64->RAMbank[1] & 3) ) {
+ //if(data&1) { //only writing 1 to $d019 bit0 would acknowledge, not any value (but RMW instructions write $d019 back before mod.)
+ if (address==0xD019) { cRSID_acknowledgeVICrasterIRQ( &C64->VIC ); }
+ //}
+ }
+ }
+
+ inline void wr2 (register unsigned short address, register unsigned char data) { //PSID-hack specific memory-write
+ static int Tmp;
+ *cRSID_getMemWritePtr(address)=data;
+ if ( C64->RAMbank[1] & 3 ) {
+ if (C64->RealSIDmode) {
+ if (address==0xDC0D) cRSID_writeCIAIRQmask( &C64->CIA[1], data );
+ else if (address==0xDD0D) cRSID_writeCIAIRQmask( &C64->CIA[2], data );
+ else if (address==0xDD0C) C64->IObankRD[address]=data; //mirror WR to RD (e.g. Wonderland_XIII_tune_1.sid)
+ //#ifdef CRSID_PLATFORM_PC //just for info displayer
+ // else if (address==0xDC05 || address==0xDC04) C64->FrameCycles = ( (C64->IObankWR[0xDC04] + (C64->IObankWR[0xDC05]<<8)) );
+ //#endif
+ else if(address==0xD019 && data&1) { //only writing 1 to $d019 bit0 would acknowledge
+ cRSID_acknowledgeVICrasterIRQ( &C64->VIC );
+ }
+ }
+
+ else {
+ switch (address) {
+ case 0xDC05: case 0xDC04:
+ if (C64->TimerSource ) { //dynamic CIA-setting (Galway/Rubicon workaround)
+ C64->FrameCycles = ( (C64->IObankWR[0xDC04] + (C64->IObankWR[0xDC05]<<8)) ); //<< 4) / C64->SampleClockRatio;
+ }
+ break;
+ case 0xDC08: C64->IObankRD[0xDC08] = data; break; //refresh TOD-clock
+ case 0xDC09: C64->IObankRD[0xDC09] = data; break; //refresh TOD-clock
+ case 0xD012: //dynamic VIC IRQ-rasterline setting (Microprose Soccer V1 workaround)
+ if (C64->PrevRasterLine>=0) { //was $d012 set before? (or set only once?)
+ if (C64->IObankWR[0xD012] != C64->PrevRasterLine) {
+ Tmp = C64->IObankWR[0xD012] - C64->PrevRasterLine;
+ if (Tmp<0) Tmp += C64->VIC.RasterLines;
+ C64->FrameCycleCnt = C64->FrameCycles - Tmp * C64->VIC.RasterRowCycles;
+ }
+ }
+ C64->PrevRasterLine = C64->IObankWR[0xD012];
+ break;
+ }
+ }
+
+ }
+ }
+
+
+ inline void addrModeImmediate (void) { ++PC; Addr=PC; Cycles=2; } //imm.
+ inline void addrModeZeropage (void) { ++PC; Addr=rd(PC); Cycles=3; } //zp
+ inline void addrModeAbsolute (void) { ++PC; Addr = rd(PC); ++PC; Addr += rd(PC)<<8; Cycles=4; } //abs
+ inline void addrModeZeropageXindexed (void) { ++PC; Addr = (rd(PC) + X) & 0xFF; Cycles=4; } //zp,x (with zeropage-wraparound of 6502)
+ inline void addrModeZeropageYindexed (void) { ++PC; Addr = (rd(PC) + Y) & 0xFF; Cycles=4; } //zp,y (with zeropage-wraparound of 6502)
+
+ inline void addrModeXindexed (void) { // abs,x (only STA is 5 cycles, others are 4 if page not crossed, RMW:7)
+ ++PC; Addr = rd(PC) + X; ++PC; SamePage = (Addr <= 0xFF); Addr += rd(PC)<<8; Cycles=5;
+ }
+
+ inline void addrModeYindexed (void) { // abs,y (only STA is 5 cycles, others are 4 if page not crossed, RMW:7)
+ ++PC; Addr = rd(PC) + Y; ++PC; SamePage = (Addr <= 0xFF); Addr += rd(PC)<<8; Cycles=5;
+ }
+
+ inline void addrModeIndirectYindexed (void) { // (zp),y (only STA is 6 cycles, others are 5 if page not crossed, RMW:8)
+ ++PC; Addr = rd(rd(PC)) + Y; SamePage = (Addr <= 0xFF); Addr += rd( (rd(PC)+1)&0xFF ) << 8; Cycles=6;
+ }
+
+ inline void addrModeXindexedIndirect (void) { // (zp,x)
+ ++PC; Addr = ( rd(rd(PC)+X)&0xFF ) + ( ( rd(rd(PC)+X+1)&0xFF ) << 8 ); Cycles=6;
+ }
+
+
+ inline void clrC (void) { ST &= ~C; } //clear Carry-flag
+ inline void setC (unsigned char expr) { ST &= ~C; ST |= (expr!=0); } //set Carry-flag if expression is not zero
+ inline void clrNZC (void) { ST &= ~(N|Z|C); } //clear flags
+ inline void clrNVZC (void) { ST &= ~(N|V|Z|C); } //clear flags
+ inline void setNZbyA (void) { ST &= ~(N|Z); ST |= ((!A)<<1) | (A&N); } //set Negative-flag and Zero-flag based on result in Accumulator
+ inline void setNZbyT (void) { T&=0xFF; ST &= ~(N|Z); ST |= ((!T)<<1) | (T&N); }
+ inline void setNZbyX (void) { ST &= ~(N|Z); ST |= ((!X)<<1) | (X&N); } //set Negative-flag and Zero-flag based on result in X-register
+ inline void setNZbyY (void) { ST &= ~(N|Z); ST |= ((!Y)<<1) | (Y&N); } //set Negative-flag and Zero-flag based on result in Y-register
+ inline void setNZbyM (void) { ST &= ~(N|Z); ST |= ((!rd(Addr))<<1) | (rd(Addr)&N); } //set Negative-flag and Zero-flag based on result at Memory-Address
+ inline void setNZCbyAdd (void) { ST &= ~(N|Z|C); ST |= (A&N)|(A>255); A&=0xFF; ST|=(!A)<<1; } //after increase/addition
+ inline void setVbyAdd (unsigned char M) { ST &= ~V; ST |= ( (~(T^M)) & (T^A) & N ) >> 1; } //calculate V-flag from A and T (previous A) and input2 (Memory)
+ inline void setNZCbySub (signed short* obj) { ST &= ~(N|Z|C); ST |= (*obj&N) | (*obj>=0); *obj&=0xFF; ST |= ((!(*obj))<<1); }
+
+ inline void push (unsigned char value) { C64->RAMbank[0x100+SP] = value; --SP; SP&=0xFF; } //push a value to stack
+ inline unsigned char pop (void) { ++SP; SP&=0xFF; return C64->RAMbank[0x100+SP]; } //pop a value from stack
+
+
+ loadReg(); PrevPC=PC;
+ IR = rd(PC); Cycles=2; SamePage=0; //'Cycles': ensure smallest 6510 runtime (for implied/register instructions)
+
+
+ if(IR&1) { //nybble2: 1/5/9/D:accu.instructions, 3/7/B/F:illegal opcodes
+
+ switch ( (IR & 0x1F) >> 1 ) { //value-forming to cause jump-table //PC wraparound not handled inside to save codespace
+ case 0: case 1: addrModeXindexedIndirect(); break; //(zp,x)
+ case 2: case 3: addrModeZeropage(); break;
+ case 4: case 5: addrModeImmediate(); break;
+ case 6: case 7: addrModeAbsolute(); break;
+ case 8: case 9: addrModeIndirectYindexed(); break; //(zp),y (5..6 cycles, 8 for R-M-W)
+ case 0xA: addrModeZeropageXindexed(); break; //zp,x
+ case 0xB: if ((IR&0xC0)!=0x80) addrModeZeropageXindexed(); //zp,x for illegal opcodes
+ else addrModeZeropageYindexed(); //zp,y for LAX/SAX illegal opcodes
+ break;
+ case 0xC: case 0xD: addrModeYindexed(); break;
+ case 0xE: addrModeXindexed(); break;
+ case 0xF: if ((IR&0xC0)!=0x80) addrModeXindexed(); //abs,x for illegal opcodes
+ else addrModeYindexed(); //abs,y for LAX/SAX illegal opcodes
+ break;
+ }
+ Addr&=0xFFFF;
+
+ switch ( (IR & 0xE0) >> 5 ) { //value-forming to cause gapless case-values and faster jump-table creation from switch-case
+
+ case 0: if ( (IR&0x1F) != 0xB ) { //ORA / SLO(ASO)=ASL+ORA
+ if ( (IR&3) == 3 ) { clrNZC(); setC(rd(Addr)>=N); wr( Addr, rd(Addr)<<1 ); Cycles+=2; } //for SLO
+ else Cycles -= SamePage;
+ A |= rd(Addr); setNZbyA(); //ORA
+ }
+ else { A&=rd(Addr); setNZbyA(); setC(A>=N); } //ANC (AND+Carry=bit7)
+ break;
+
+ case 1: if ( (IR&0x1F) != 0xB ) { //AND / RLA (ROL+AND)
+ if ( (IR&3) == 3 ) { //for RLA
+ T = (rd(Addr)<<1) + (ST&C); clrNZC(); setC(T>255); T&=0xFF; wr(Addr,T); Cycles+=2;
+ }
+ else Cycles -= SamePage;
+ A &= rd(Addr); setNZbyA(); //AND
+ }
+ else { A&=rd(Addr); setNZbyA(); setC(A>=N); } //ANC (AND+Carry=bit7)
+ break;
+
+ case 2: if ( (IR&0x1F) != 0xB ) { //EOR / SRE(LSE)=LSR+EOR
+ if ( (IR&3) == 3 ) { clrNZC(); setC(rd(Addr)&1); wr(Addr,rd(Addr)>>1); Cycles+=2; } //for SRE
+ else Cycles -= SamePage;
+ A ^= rd(Addr); setNZbyA(); //EOR
+ }
+ else { A&=rd(Addr); setC(A&1); A>>=1; A&=0xFF; setNZbyA(); } //ALR(ASR)=(AND+LSR)
+ break;
+
+ case 3: if ( (IR&0x1F) != 0xB ) { //RRA (ROR+ADC) / ADC
+ if( (IR&3) == 3 ) { //for RRA
+ T = (rd(Addr)>>1) + ((ST&C)<<7); clrNZC(); setC(T&1); wr(Addr,T); Cycles+=2;
+ }
+ else Cycles -= SamePage;
+ T=A; A += rd(Addr)+(ST&C); setNZCbyAdd(); setVbyAdd(rd(Addr)); //ADC
+ }
+ else { // ARR (AND+ROR, bit0 not going to C, but C and bit7 get exchanged.)
+ A &= rd(Addr); T += rd(Addr) + (ST&C);
+ clrNVZC(); setC(T>255); setVbyAdd(rd(Addr)); //V-flag set by intermediate ADC mechanism: (A&mem)+mem
+ T=A; A = (A>>1) + ((ST&C)<<7); setC(T>=N); setNZbyA();
+ }
+ break;
+
+ case 4: if ( (IR&0x1F) == 0xB ) { A = X & rd(Addr); setNZbyA(); } //XAA (TXA+AND), highly unstable on real 6502!
+ else if ( (IR&0x1F) == 0x1B ) { SP = A&X; wr( Addr, SP&((Addr>>8)+1) ); } //TAS(SHS) (SP=A&X, mem=S&H} - unstable on real 6502
+ else { wr2( Addr, A & (((IR&3)==3)? X:0xFF) ); } //STA / SAX (at times same as AHX/SHX/SHY) (illegal)
+ break;
+
+ case 5: if ( (IR&0x1F) != 0x1B ) { A=rd(Addr); if((IR&3)==3) X=A; } //LDA / LAX (illegal, used by my 1 rasterline player) (LAX #imm is unstable on C64)
+ else { A=X=SP = rd(Addr) & SP; } //LAS(LAR)
+ setNZbyA(); Cycles -= SamePage;
+ break;
+
+ case 6: if( (IR&0x1F) != 0xB ) { // CMP / DCP(DEC+CMP)
+ if ( (IR&3) == 3 ) { wr(Addr,rd(Addr)-1); Cycles+=2;} //DCP
+ else Cycles -= SamePage;
+ T = A-rd(Addr);
+ }
+ else { X = T = (A&X) - rd(Addr); } //SBX(AXS) //SBX (AXS) (CMP+DEX at the same time)
+ setNZCbySub(&T);
+ break;
+
+ case 7: if( (IR&3)==3 && (IR&0x1F)!=0xB ) { wr( Addr, rd(Addr)+1 ); Cycles+=2; } //ISC(ISB)=INC+SBC / SBC
+ else Cycles -= SamePage;
+ T=A; A -= rd(Addr) + !(ST&C);
+ setNZCbySub(&A); setVbyAdd(~rd(Addr));
+ break;
+ }
+ }
+
+
+ else if (IR&2) { //nybble2: 2:illegal/LDX, 6:A/X/INC/DEC, A:Accu-shift/reg.transfer/NOP, E:shift/X/INC/DEC
+
+ switch (IR & 0x1F) { //Addressing modes
+ case 2: addrModeImmediate(); break;
+ case 6: addrModeZeropage(); break;
+ case 0xE: addrModeAbsolute(); break;
+ case 0x16: if ( (IR&0xC0) != 0x80 ) addrModeZeropageXindexed(); //zp,x
+ else addrModeZeropageYindexed(); //zp,y
+ break;
+ case 0x1E: if ( (IR&0xC0) != 0x80 ) addrModeXindexed(); //abs,x
+ else addrModeYindexed(); //abs,y
+ break;
+ }
+ Addr&=0xFFFF;
+
+ switch ( (IR & 0xE0) >> 5 ) {
+
+ case 0: clrC(); case 1:
+ if((IR&0xF)==0xA) { A = (A<<1) + (ST&C); setNZCbyAdd(); } //ASL/ROL (Accu)
+ else { T = (rd(Addr)<<1) + (ST&C); setC(T>255); setNZbyT(); wr(Addr,T); Cycles+=2; } //RMW (Read-Write-Modify)
+ break;
+
+ case 2: clrC(); case 3:
+ if((IR&0xF)==0xA) { T=A; A=(A>>1)+((ST&C)<<7); setC(T&1); A&=0xFF; setNZbyA(); } //LSR/ROR (Accu)
+ else { T = (rd(Addr)>>1) + ((ST&C)<<7); setC(rd(Addr)&1); setNZbyT(); wr(Addr,T); Cycles+=2; } //memory (RMW)
+ break;
+
+ case 4: if (IR&4) {wr2(Addr,X);} //STX
+ else if(IR&0x10) SP=X; //TXS
+ else { A=X; setNZbyA(); } //TXA
+ break;
+
+ case 5: if ( (IR&0xF) != 0xA ) { X=rd(Addr); Cycles -= SamePage; } //LDX
+ else if (IR & 0x10) X=SP; //TSX
+ else X=A; //TAX
+ setNZbyX();
+ break;
+
+ case 6: if (IR&4) { wr(Addr,rd(Addr)-1); setNZbyM(); Cycles+=2; } //DEC
+ else { --X; setNZbyX(); } //DEX
+ break;
+
+ case 7: if (IR&4) { wr(Addr,rd(Addr)+1); setNZbyM(); Cycles+=2; } //INC/NOP
+ break;
+ }
+ }
+
+
+ else if ( (IR & 0xC) == 8 ) { //nybble2: 8:register/statusflag
+ if ( IR&0x10 ) {
+ if ( IR == 0x98 ) { A=Y; setNZbyA(); } //TYA
+ else { //CLC/SEC/CLI/SEI/CLV/CLD/SED
+ if (FlagSwitches[IR>>5] & 0x20) ST |= (FlagSwitches[IR>>5] & 0xDF);
+ else ST &= ~( FlagSwitches[IR>>5] & 0xDF );
+ }
+ }
+ else {
+ switch ( (IR & 0xF0) >> 5 ) {
+ case 0: push(ST); Cycles=3; break; //PHP
+ case 1: ST=pop(); Cycles=4; break; //PLP
+ case 2: push(A); Cycles=3; break; //PHA
+ case 3: A=pop(); setNZbyA(); Cycles=4; break; //PLA
+ case 4: --Y; setNZbyY(); break; //DEY
+ case 5: Y=A; setNZbyY(); break; //TAY
+ case 6: ++Y; setNZbyY(); break; //INY
+ case 7: ++X; setNZbyX(); break; //INX
+ }
+ }
+ }
+
+
+ else { //nybble2: 0: control/branch/Y/compare 4: Y/compare C:Y/compare/JMP
+
+ if ( (IR&0x1F) == 0x10 ) { //BPL/BMI/BVC/BVS/BCC/BCS/BNE/BEQ relative branch
+ ++PC;
+ T=rd(PC); if (T & 0x80) T-=0x100;
+ if (IR & 0x20) {
+ if (ST & BranchFlags[IR>>6]) { PC+=T; Cycles=3; }
+ }
+ else {
+ if ( !(ST & BranchFlags[IR>>6]) ) { PC+=T; Cycles=3; } //plus 1 cycle if page is crossed?
+ }
+ }
+
+ else { //nybble2: 0:Y/control/Y/compare 4:Y/compare C:Y/compare/JMP
+ switch (IR&0x1F) { //Addressing modes
+ case 0: addrModeImmediate(); break; //imm. (or abs.low for JSR/BRK)
+ case 4: addrModeZeropage(); break;
+ case 0xC: addrModeAbsolute(); break;
+ case 0x14: addrModeZeropageXindexed(); break; //zp,x
+ case 0x1C: addrModeXindexed(); break; //abs,x
+ }
+ Addr&=0xFFFF;
+
+ switch ( (IR & 0xE0) >> 5 ) {
+
+ case 0: if( !(IR&4) ) { //BRK / NOP-absolute/abs,x/zp/zp,x
+ push((PC+2-1)>>8); push((PC+2-1)&0xFF); push(ST|B); ST |= I; //BRK
+ PC = rd(0xFFFE) + (rd(0xFFFF)<<8) - 1; Cycles=7;
+ }
+ else if (IR == 0x1C) Cycles -= SamePage; //NOP abs,x
+ break;
+
+ case 1: if (IR & 0xF) { //BIT / NOP-abs,x/zp,x
+ if ( !(IR&0x10) ) { ST &= 0x3D; ST |= (rd(Addr)&0xC0) | ( (!(A&rd(Addr))) << 1 ); } //BIT
+ else if (IR == 0x3C) Cycles -= SamePage; //NOP abs,x
+ }
+ else { //JSR
+ push((PC+2-1)>>8); push((PC+2-1)&0xFF);
+ PC=rd(Addr)+rd(Addr+1)*256-1; Cycles=6;
+ }
+ break;
+
+ case 2: if (IR & 0xF) { //JMP / NOP-abs,x/zp/zp,x
+ if (IR == 0x4C) { //JMP
+ PC = Addr-1; Cycles=3;
+ rd(Addr+1); //a read from jump-address highbyte is used in some tunes with jmp DD0C (e.g. Wonderland_XIII_tune_1.sid)
+ //if (Addr==PrevPC) {storeReg(); C64->Returned=1; return 0xFF;} //turn self-jump mainloop (after init) into idle time
+ }
+ else if (IR==0x5C) Cycles -= SamePage; //NOP abs,x
+ }
+ else { //RTI
+ ST=pop(); T=pop(); PC = (pop()<<8) + T - 1; Cycles=6;
+ if (C64->Returned && SP>=0xFF) { ++PC; storeReg(); return 0xFE; }
+ }
+ break;
+
+ case 3: if (IR & 0xF) { //JMP() (indirect) / NOP-abs,x/zp/zp,x
+ if (IR == 0x6C) { //JMP() (indirect)
+ PC = rd( (Addr&0xFF00) + ((Addr+1)&0xFF) ); //(with highbyte-wraparound bug)
+ PC = (PC<<8) + rd(Addr) - 1; Cycles=5;
+ }
+ else if (IR == 0x7C) Cycles -= SamePage; //NOP abs,x
+ }
+ else { //RTS
+ if (SP>=0xFF) {storeReg(); C64->Returned=1; return 0xFF;} //Init returns, provide idle-time between IRQs
+ T=pop(); PC = (pop()<<8) + T; Cycles=6;
+ }
+ break;
+
+ case 4: if (IR & 4) { wr2( Addr, Y ); } //STY / NOP #imm
+ break;
+
+ case 5: Y=rd(Addr); setNZbyY(); Cycles -= SamePage; //LDY
+ break;
+
+ case 6: if ( !(IR&0x10) ) { //CPY / NOP abs,x/zp,x
+ T=Y-rd(Addr); setNZCbySub(&T); //CPY
+ }
+ else if (IR==0xDC) Cycles -= SamePage; //NOP abs,x
+ break;
+
+ case 7: if ( !(IR&0x10) ) { //CPX / NOP abs,x/zp,x
+ T=X-rd(Addr); setNZCbySub(&T); //CPX
+ }
+ else if (IR==0xFC) Cycles -= SamePage; //NOP abs,x
+ break;
+ }
+ }
+ }
+
+
+ ++PC; //PC&=0xFFFF;
+
+ storeReg();
+
+
+ if (!C64->RealSIDmode) { //substitute KERNAL IRQ-return in PSID (e.g. Microprose Soccer)
+ if ( (C64->RAMbank[1]&3)>1 && PrevPC<0xE000 && (PC==0xEA31 || PC==0xEA81 || PC==0xEA7E) ) return 0xFE;
+ }
+
+
+ return Cycles;
+}
+
+
+
+ //handle entering into IRQ and NMI interrupt
+static inline char cRSID_handleCPUinterrupts (cRSID_CPUinstance* CPU) {
+ enum StatusFlagBitValues { B=0x10, I=0x04 };
+ inline void push (unsigned char value) { CPU->C64->RAMbank[0x100+CPU->SP] = value; --CPU->SP; CPU->SP&=0xFF; } //push a value to stack
+
+ if (CPU->C64->NMI > CPU->PrevNMI) { //if IRQ and NMI at the same time, NMI is serviced first
+ push(CPU->PC>>8); push(CPU->PC&0xFF); push(CPU->ST); CPU->ST |= I;
+ CPU->PC = *cRSID_getMemReadPtr(0xFFFA) + (*cRSID_getMemReadPtr(0xFFFB)<<8); //NMI-vector
+ CPU->PrevNMI = CPU->C64->NMI;
+ return 1;
+ }
+ else if ( CPU->C64->IRQ && !(CPU->ST&I) ) {
+ push(CPU->PC>>8); push(CPU->PC&0xFF); push(CPU->ST); CPU->ST |= I;
+ CPU->PC = *cRSID_getMemReadPtr(0xFFFE) + (*cRSID_getMemReadPtr(0xFFFF)<<8); //maskable IRQ-vector
+ CPU->PrevNMI = CPU->C64->NMI;
+ return 1;
+ }
+ CPU->PrevNMI = CPU->C64->NMI; //prepare for NMI edge-detection
+
+ return 0;
+}
diff --git a/lib/rbcodec/codecs/cRSID/C64/MEM.c b/lib/rbcodec/codecs/cRSID/C64/MEM.c
new file mode 100644
index 0000000000..5be0fc47db
--- /dev/null
+++ b/lib/rbcodec/codecs/cRSID/C64/MEM.c
@@ -0,0 +1,132 @@
+
+//Emulation of C64 memories and memory bus (PLA & MUXes)
+
+
+static inline unsigned char* cRSID_getMemReadPtr (register unsigned short address) {
+ //cRSID_C64instance* const C64 = &cRSID_C64; //for faster (?) operation we use a global object as memory
+ if (address<0xA000) return &cRSID_C64.RAMbank[address];
+ else if ( 0xD000<=address && address<0xE000 && (cRSID_C64.RAMbank[1]&3) ) {
+ if (0xD400 <= address && address < 0xD419) return &cRSID_C64.IObankWR[address]; //emulate bitfading aka SID-read of last written reg (e.g. Lift Off ROR $D400,x)
+ return &cRSID_C64.IObankRD[address];
+ }
+ else if ( (address<0xC000 && (cRSID_C64.RAMbank[1]&3)==3)
+ || (0xE000<=address && (cRSID_C64.RAMbank[1]&2)) ) return &cRSID_C64.ROMbanks[address];
+ return &cRSID_C64.RAMbank[address];
+}
+
+static inline unsigned char* cRSID_getMemReadPtrC64 (cRSID_C64instance* C64, register unsigned short address) {
+ if (address<0xA000) return &C64->RAMbank[address];
+ else if ( 0xD000<=address && address<0xE000 && (C64->RAMbank[1]&3) ) {
+ if (0xD400 <= address && address < 0xD419) return &cRSID_C64.IObankWR[address]; //emulate peculiar SID-read (e.g. Lift Off)
+ return &C64->IObankRD[address];
+ }
+ else if ( (address<0xC000 && (C64->RAMbank[1]&3)==3)
+ || (0xE000<=address && (C64->RAMbank[1]&2)) ) return &C64->ROMbanks[address];
+ return &C64->RAMbank[address];
+}
+
+
+static inline unsigned char* cRSID_getMemWritePtr (register unsigned short address) {
+ //cRSID_C64instance* const C64 = &cRSID_C64; //for faster (?) operation we use a global object as memory
+ if (address<0xD000 || 0xE000<=address) return &cRSID_C64.RAMbank[address];
+ else if ( cRSID_C64.RAMbank[1]&3 ) { //handle SID-mirrors! (CJ in the USA workaround (writing above $d420, except SID2/SID3))
+ if (0xD420 <= address && address < 0xD800) { //CIA/VIC mirrors needed?
+ if ( !(cRSID_C64.PSIDdigiMode && 0xD418 <= address && address < 0xD500)
+ && !(cRSID_C64.SID[2].BaseAddress <= address && address < cRSID_C64.SID[2].BaseAddress+0x20)
+ && !(cRSID_C64.SID[3].BaseAddress <= address && address < cRSID_C64.SID[3].BaseAddress+0x20) ) {
+ return &cRSID_C64.IObankWR[ 0xD400 + (address&0x1F) ]; //write to $D400..D41F if not in SID2/SID3 address-space
+ }
+ else return &cRSID_C64.IObankWR[address];
+ }
+ else return &cRSID_C64.IObankWR[address];
+ }
+ return &cRSID_C64.RAMbank[address];
+}
+
+
+static inline unsigned char* cRSID_getMemWritePtrC64 (cRSID_C64instance* C64, register unsigned short address) {
+ if (address<0xD000 || 0xE000<=address) return &C64->RAMbank[address];
+ else if ( C64->RAMbank[1]&3 ) { //handle SID-mirrors! (CJ in the USA workaround (writing above $d420, except SID2/SID3/PSIDdigi))
+ if (0xD420 <= address && address < 0xD800) { //CIA/VIC mirrors needed?
+ if ( !(cRSID_C64.PSIDdigiMode && 0xD418 <= address && address < 0xD500)
+ && !(C64->SID[2].BaseAddress <= address && address < C64->SID[2].BaseAddress+0x20)
+ && !(C64->SID[3].BaseAddress <= address && address < C64->SID[3].BaseAddress+0x20) ) {
+ return &C64->IObankWR[ 0xD400 + (address&0x1F) ]; //write to $D400..D41F if not in SID2/SID3 address-space
+ }
+ else return &C64->IObankWR[address];
+ }
+ else return &C64->IObankWR[address];
+ }
+ return &C64->RAMbank[address];
+}
+
+
+static inline unsigned char cRSID_readMem (register unsigned short address) {
+ return *cRSID_getMemReadPtr(address);
+}
+
+static inline unsigned char cRSID_readMemC64 (cRSID_C64instance* C64, register unsigned short address) {
+ return *cRSID_getMemReadPtrC64(C64,address);
+}
+
+
+static inline void cRSID_writeMem (register unsigned short address, register unsigned char data) {
+ *cRSID_getMemWritePtr(address)=data;
+}
+
+static inline void cRSID_writeMemC64 (cRSID_C64instance* C64, register unsigned short address, register unsigned char data) {
+ *cRSID_getMemWritePtrC64(C64,address)=data;
+}
+
+
+void cRSID_setROMcontent (cRSID_C64instance* C64) { //fill KERNAL/BASIC-ROM areas with content needed for SID-playback
+ int i;
+ static const unsigned char ROM_IRQreturnCode[9] = {0xAD,0x0D,0xDC,0x68,0xA8,0x68,0xAA,0x68,0x40}; //CIA1-acknowledge IRQ-return
+ static const unsigned char ROM_NMIstartCode[5] = {0x78,0x6c,0x18,0x03,0x40}; //SEI and jmp($0318)
+ static const unsigned char ROM_IRQBRKstartCode[19] = { //Full IRQ-return (handling BRK with the same RAM vector as IRQ)
+ 0x48,0x8A,0x48,0x98,0x48,0xBA,0xBD,0x04,0x01,0x29,0x10,0xEA,0xEA,0xEA,0xEA,0xEA,0x6C,0x14,0x03
+ };
+
+ for (i=0xA000; i<0x10000; ++i) C64->ROMbanks[i] = 0x60; //RTS (at least return if some unsupported call is made to ROM)
+ for (i=0xEA31; i<0xEA7E; ++i) C64->ROMbanks[i] = 0xEA; //NOP (full IRQ-return leading to simple IRQ-return without other tasks)
+ for (i=0; i<9; ++i) C64->ROMbanks [0xEA7E + i] = ROM_IRQreturnCode[i];
+ for (i=0; i<4; ++i) C64->ROMbanks [0xFE43 + i] = ROM_NMIstartCode[i];
+ for (i=0; i<19; ++i) C64->ROMbanks[0xFF48 + i] = ROM_IRQBRKstartCode[i];
+
+ C64->ROMbanks[0xFFFB] = 0xFE; C64->ROMbanks[0xFFFA] = 0x43; //ROM NMI-vector
+ C64->ROMbanks[0xFFFF] = 0xFF; C64->ROMbanks[0xFFFE] = 0x48; //ROM IRQ-vector
+
+ //copy KERNAL & BASIC ROM contents into the RAM under them? (So PSIDs that don't select bank correctly will work better.)
+ for (i=0xA000; i<0x10000; ++i) C64->RAMbank[i]=C64->ROMbanks[i];
+}
+
+
+void cRSID_initMem (cRSID_C64instance* C64) { //set default values that normally KERNEL ensures after startup/reset (only SID-playback related)
+ static int i;
+
+ //data required by both PSID and RSID (according to HVSC SID_file_format.txt):
+ cRSID_writeMemC64( C64, 0x02A6, C64->VideoStandard ); //$02A6 should be pre-set to: 0:NTSC / 1:PAL
+ cRSID_writeMemC64( C64, 0x0001, 0x37 ); //initialize bank-reg. (ROM-banks and IO enabled)
+
+ //if (C64->ROMbanks[0xE000]==0) { //wasn't a KERNAL-ROM loaded? (e.g. PSID)
+ cRSID_writeMemC64( C64, 0x00CB, 0x40 ); //Some tunes might check for keypress here (e.g. Master Blaster Intro)
+ //if(C64->RealSIDmode) {
+ cRSID_writeMemC64( C64, 0x0315, 0xEA ); cRSID_writeMemC64( C64, 0x0314, 0x31 ); //IRQ
+ cRSID_writeMemC64( C64, 0x0319, 0xEA/*0xFE*/ ); cRSID_writeMemC64( C64, 0x0318, 0x81/*0x47*/ ); //NMI
+ //}
+
+ for (i=0xD000; i<0xD7FF; ++i) C64->IObankRD[i] = C64->IObankWR[i] = 0; //initialize the whole IO area for a known base-state
+ if(C64->RealSIDmode) {C64->IObankWR[0xD012] = 0x37; C64->IObankWR[0xD011] = 0x8B;} //else C64->IObankWR[0xD012] = 0;
+ //C64->IObankWR[0xD019] = 0; //PSID: rasterrow: any value <= $FF, IRQ:enable later if there is VIC-timingsource
+
+ C64->IObankRD[0xDC00]=0x10; C64->IObankRD[0xDC01]=0xFF; //Imitate CIA1 keyboard/joy port, some tunes check if buttons are not pressed
+ if (C64->VideoStandard) { C64->IObankWR[0xDC04]=0x24; C64->IObankWR[0xDC05]=0x40; } //initialize CIAs
+ else { C64->IObankWR[0xDC04]=0x95; C64->IObankWR[0xDC05]=0x42; }
+ if(C64->RealSIDmode) C64->IObankWR[0xDC0D] = 0x81; //Reset-default, but for PSID CIA1 TimerA IRQ should be enabled anyway if SID is CIA-timed
+ C64->IObankWR[0xDC0E] = 0x01; //some tunes (and PSID doc) expect already running CIA (Reset-default)
+ C64->IObankWR[0xDC0F] = 0x00; //All counters other than CIA1 TimerA should be disabled and set to 0xFF for PSID:
+ C64->IObankWR[0xDD04] = C64->IObankWR[0xDD05] = 0xFF; //C64->IObankWR[0xDD0E] = C64->IObank[0xDD0F] = 0x00;
+ //}
+
+}
+
diff --git a/lib/rbcodec/codecs/cRSID/C64/SID.c b/lib/rbcodec/codecs/cRSID/C64/SID.c
new file mode 100644
index 0000000000..22b07c15da
--- /dev/null
+++ b/lib/rbcodec/codecs/cRSID/C64/SID.c
@@ -0,0 +1,276 @@
+
+//cRSID SID emulation engine
+
+
+void cRSID_createSIDchip (cRSID_C64instance* C64, cRSID_SIDinstance* SID, unsigned short model, unsigned short baseaddress) {
+ SID->C64 = C64;
+ SID->ChipModel = model;
+ if( baseaddress>=0xD400 && (baseaddress<0xD800 || (0xDE00<=baseaddress && baseaddress<=0xDFE0)) ) { //check valid address, avoid Color-RAM
+ SID->BaseAddress = baseaddress; SID->BasePtr = &C64->IObankWR[baseaddress];
+ }
+ else { SID->BaseAddress=0x0000; SID->BasePtr = NULL; }
+ cRSID_initSIDchip(SID);
+}
+
+
+void cRSID_initSIDchip (cRSID_SIDinstance* SID) {
+ static unsigned char Channel;
+ for (Channel = 0; Channel < 21; Channel+=7) {
+ SID->ADSRstate[Channel] = 0; SID->RateCounter[Channel] = 0;
+ SID->EnvelopeCounter[Channel] = 0; SID->ExponentCounter[Channel] = 0;
+ SID->PhaseAccu[Channel] = 0; SID->PrevPhaseAccu[Channel] = 0;
+ SID->NoiseLFSR[Channel] = 0x7FFFFF;
+ SID->PrevWavGenOut[Channel] = 0; SID->PrevWavData[Channel] = 0;
+ }
+ SID->SyncSourceMSBrise = 0; SID->RingSourceMSB = 0;
+ SID->PrevLowPass = SID->PrevBandPass = SID->PrevVolume = 0;
+}
+
+
+void cRSID_emulateADSRs (cRSID_SIDinstance *SID, char cycles) {
+
+ enum ADSRstateBits { GATE_BITVAL=0x01, ATTACK_BITVAL=0x80, DECAYSUSTAIN_BITVAL=0x40, HOLDZEROn_BITVAL=0x10 };
+
+ static const short ADSRprescalePeriods[16] = {
+ 9, 32, 63, 95, 149, 220, 267, 313, 392, 977, 1954, 3126, 3907, 11720, 19532, 31251
+ };
+ static const unsigned char ADSRexponentPeriods[256] = {
+ 1, 30, 30, 30, 30, 30, 30, 16, 16, 16, 16, 16, 16, 16, 16,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 4, 4, 4, 4, 4, //pos0:1 pos6:30 pos14:16 pos26:8
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 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, 2, 2, 2, 2, 2, 2, 2, 1, 1, //pos54:4 //pos93: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,
+ 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,
+ 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
+ };
+
+ static unsigned char Channel, PrevGate, AD, SR;
+ static unsigned short PrescalePeriod;
+ static unsigned char *ChannelPtr, *ADSRstatePtr, *EnvelopeCounterPtr, *ExponentCounterPtr;
+ static unsigned short *RateCounterPtr;
+
+
+ for (Channel=0; Channel<21; Channel+=7) {
+
+ ChannelPtr=&SID->BasePtr[Channel]; AD=ChannelPtr[5]; SR=ChannelPtr[6];
+ ADSRstatePtr = &(SID->ADSRstate[Channel]);
+ RateCounterPtr = &(SID->RateCounter[Channel]);
+ EnvelopeCounterPtr = &(SID->EnvelopeCounter[Channel]);
+ ExponentCounterPtr = &(SID->ExponentCounter[Channel]);
+
+ PrevGate = (*ADSRstatePtr & GATE_BITVAL);
+ if ( PrevGate != (ChannelPtr[4] & GATE_BITVAL) ) { //gatebit-change?
+ if (PrevGate) *ADSRstatePtr &= ~ (GATE_BITVAL | ATTACK_BITVAL | DECAYSUSTAIN_BITVAL); //falling edge
+ else *ADSRstatePtr = (GATE_BITVAL | ATTACK_BITVAL | DECAYSUSTAIN_BITVAL | HOLDZEROn_BITVAL); //rising edge
+ }
+
+ if (*ADSRstatePtr & ATTACK_BITVAL) PrescalePeriod = ADSRprescalePeriods[ AD >> 4 ];
+ else if (*ADSRstatePtr & DECAYSUSTAIN_BITVAL) PrescalePeriod = ADSRprescalePeriods[ AD & 0x0F ];
+ else PrescalePeriod = ADSRprescalePeriods[ SR & 0x0F ];
+
+ *RateCounterPtr += cycles; if (*RateCounterPtr >= 0x8000) *RateCounterPtr -= 0x8000; //*RateCounterPtr &= 0x7FFF; //can wrap around (ADSR delay-bug: short 1st frame)
+
+ if (PrescalePeriod <= *RateCounterPtr && *RateCounterPtr < PrescalePeriod+cycles) { //ratecounter shot (matches rateperiod) (in genuine SID ratecounter is LFSR)
+ *RateCounterPtr -= PrescalePeriod; //reset rate-counter on period-match
+ if ( (*ADSRstatePtr & ATTACK_BITVAL) || ++(*ExponentCounterPtr) == ADSRexponentPeriods[*EnvelopeCounterPtr] ) {
+ *ExponentCounterPtr = 0;
+ if (*ADSRstatePtr & HOLDZEROn_BITVAL) {
+ if (*ADSRstatePtr & ATTACK_BITVAL) {
+ ++(*EnvelopeCounterPtr);
+ if (*EnvelopeCounterPtr==0xFF) *ADSRstatePtr &= ~ATTACK_BITVAL;
+ }
+ else if ( !(*ADSRstatePtr & DECAYSUSTAIN_BITVAL) || *EnvelopeCounterPtr != (SR&0xF0)+(SR>>4) ) {
+ --(*EnvelopeCounterPtr); //resid adds 1 cycle delay, we omit that mechanism here
+ if (*EnvelopeCounterPtr==0) *ADSRstatePtr &= ~HOLDZEROn_BITVAL;
+ }}}}}
+
+}
+
+
+
+int cRSID_emulateWaves (cRSID_SIDinstance *SID) {
+
+ enum SIDspecs { CHANNELS=3+1, VOLUME_MAX=0xF, D418_DIGI_VOLUME=2 }; //digi-channel is counted too
+ enum WaveFormBits { NOISE_BITVAL=0x80, PULSE_BITVAL=0x40, SAW_BITVAL=0x20, TRI_BITVAL=0x10 };
+ enum ControlBits { TEST_BITVAL=0x08, RING_BITVAL=0x04, SYNC_BITVAL=0x02, GATE_BITVAL=0x01 };
+ enum FilterBits { OFF3_BITVAL=0x80, HIGHPASS_BITVAL=0x40, BANDPASS_BITVAL=0x20, LOWPASS_BITVAL=0x10 };
+
+ #include "SID.h"
+ static const unsigned char FilterSwitchVal[] = {1,1,1,1,1,1,1,2,2,2,2,2,2,2,4};
+
+ static char MainVolume;
+ static unsigned char Channel, WF, TestBit, Envelope, FilterSwitchReso, VolumeBand;
+ static unsigned int Utmp, PhaseAccuStep, MSB, WavGenOut, PW;
+ static int Tmp, Feedback, Steepness, PulsePeak;
+ static int FilterInput, Cutoff, Resonance, FilterOutput, NonFilted, Output;
+ static unsigned char *ChannelPtr;
+ static int *PhaseAccuPtr;
+
+
+ inline unsigned short combinedWF( const unsigned char* WFarray, unsigned short oscval) {
+ static unsigned char Pitch;
+ static unsigned short Filt;
+ if (SID->ChipModel==6581 && WFarray!=PulseTriangle) oscval &= 0x7FFF;
+ Pitch = ChannelPtr[1] ? ChannelPtr[1] : 1; //avoid division by zero
+ Filt = 0x7777 + (0x8888/Pitch);
+ SID->PrevWavData[Channel] = ( WFarray[oscval>>4]*Filt + SID->PrevWavData[Channel]*(0xFFFF-Filt) ) >> 16;
+ return SID->PrevWavData[Channel] << 8;
+ }
+
+
+ FilterInput = NonFilted = 0;
+ FilterSwitchReso = SID->BasePtr[0x17]; VolumeBand=SID->BasePtr[0x18];
+
+
+ //Waveform-generator //(phase accumulator and waveform-selector)
+
+
+ for (Channel=0; Channel<21; Channel+=7) {
+ ChannelPtr=&(SID->BasePtr[Channel]);
+
+ WF = ChannelPtr[4]; TestBit = ( (WF & TEST_BITVAL) != 0 );
+ PhaseAccuPtr = &(SID->PhaseAccu[Channel]);
+
+
+ PhaseAccuStep = ( (ChannelPtr[1]<<8) + ChannelPtr[0] ) * SID->C64->SampleClockRatio;
+ if (TestBit || ((WF & SYNC_BITVAL) && SID->SyncSourceMSBrise)) *PhaseAccuPtr = 0;
+ else { //stepping phase-accumulator (oscillator)
+ *PhaseAccuPtr += PhaseAccuStep;
+ if (*PhaseAccuPtr >= 0x10000000) *PhaseAccuPtr -= 0x10000000;
+ }
+ *PhaseAccuPtr &= 0xFFFFFFF;
+ MSB = *PhaseAccuPtr & 0x8000000;
+ SID->SyncSourceMSBrise = (MSB > (SID->PrevPhaseAccu[Channel] & 0x8000000)) ? 1 : 0;
+
+
+ if (WF & NOISE_BITVAL) { //noise waveform
+ Tmp = SID->NoiseLFSR[Channel]; //clock LFSR all time if clockrate exceeds observable at given samplerate (last term):
+ if ( ((*PhaseAccuPtr & 0x1000000) != (SID->PrevPhaseAccu[Channel] & 0x1000000)) || PhaseAccuStep >= 0x1000000 ) {
+ Feedback = ( (Tmp & 0x400000) ^ ((Tmp & 0x20000) << 5) ) != 0;
+ Tmp = ( (Tmp << 1) | Feedback|TestBit ) & 0x7FFFFF; //TEST-bit turns all bits in noise LFSR to 1 (on real SID slowly, in approx. 8000 microseconds ~ 300 samples)
+ SID->NoiseLFSR[Channel] = Tmp;
+ } //we simply zero output when other waveform is mixed with noise. On real SID LFSR continuously gets filled by zero and locks up. ($C1 waveform with pw<8 can keep it for a while.)
+ WavGenOut = (WF & 0x70) ? 0 : ((Tmp & 0x100000) >> 5) | ((Tmp & 0x40000) >> 4) | ((Tmp & 0x4000) >> 1) | ((Tmp & 0x800) << 1)
+ | ((Tmp & 0x200) << 2) | ((Tmp & 0x20) << 5) | ((Tmp & 0x04) << 7) | ((Tmp & 0x01) << 8);
+ }
+
+ else if (WF & PULSE_BITVAL) { //simple pulse
+ PW = ( ((ChannelPtr[3]&0xF) << 8) + ChannelPtr[2] ) << 4; //PW=0000..FFF0 from SID-register
+ Utmp = (int) (PhaseAccuStep >> 13); if (0 < PW && PW < Utmp) PW = Utmp; //Too thin pulsewidth? Correct...
+ Utmp ^= 0xFFFF; if (PW > Utmp) PW = Utmp; //Too thin pulsewidth? Correct it to a value representable at the current samplerate
+ Utmp = *PhaseAccuPtr >> 12;
+
+ if ( (WF&0xF0) == PULSE_BITVAL ) { //simple pulse, most often used waveform, make it sound as clean as possible (by making it trapezoid)
+ Steepness = (PhaseAccuStep>=4096) ? 0xFFFFFFF/PhaseAccuStep : 0xFFFF; //rising/falling-edge steepness (add/sub at samples)
+ if (TestBit) WavGenOut = 0xFFFF;
+ else if (Utmp<PW) { //rising edge (interpolation)
+ PulsePeak = (0xFFFF-PW) * Steepness; //very thin pulses don't make a full swing between 0 and max but make a little spike
+ if (PulsePeak>0xFFFF) PulsePeak=0xFFFF; //but adequately thick trapezoid pulses reach the maximum level
+ Tmp = PulsePeak - (PW-Utmp)*Steepness; //draw the slope from the peak
+ WavGenOut = (Tmp<0)? 0:Tmp; //but stop at 0-level
+ }
+ else { //falling edge (interpolation)
+ PulsePeak = PW*Steepness; //very thin pulses don't make a full swing between 0 and max but make a little spike
+ if (PulsePeak>0xFFFF) PulsePeak=0xFFFF; //adequately thick trapezoid pulses reach the maximum level
+ Tmp = (0xFFFF-Utmp)*Steepness - PulsePeak; //draw the slope from the peak
+ WavGenOut = (Tmp>=0)? 0xFFFF:Tmp; //but stop at max-level
+ }}
+
+ else { //combined pulse
+ WavGenOut = (Utmp >= PW || TestBit) ? 0xFFFF:0;
+ if (WF & TRI_BITVAL) {
+ if (WF & SAW_BITVAL) { //pulse+saw+triangle (waveform nearly identical to tri+saw)
+ if (WavGenOut) WavGenOut = combinedWF( PulseSawTriangle, Utmp);
+ }
+ else { //pulse+triangle
+ Tmp = *PhaseAccuPtr ^ ( (WF&RING_BITVAL)? SID->RingSourceMSB : 0 );
+ if (WavGenOut) WavGenOut = combinedWF( PulseTriangle, Tmp >> 12);
+ }}
+ else if (WF & SAW_BITVAL) { //pulse+saw
+ if(WavGenOut) WavGenOut = combinedWF( PulseSawtooth, Utmp);
+ }}
+ }
+
+ else if (WF & SAW_BITVAL) { //sawtooth
+ WavGenOut = *PhaseAccuPtr >> 12; //saw (this row would be enough for simple but aliased-at-high-pitch saw)
+ if (WF & TRI_BITVAL) WavGenOut = combinedWF( SawTriangle, WavGenOut); //saw+triangle
+ else { //simple cleaned (bandlimited) saw
+ Steepness = (PhaseAccuStep>>4)/288; if(Steepness==0) Steepness=1; //avoid division by zero in next steps
+ WavGenOut += (WavGenOut * Steepness) >> 16; //1st half (rising edge) of asymmetric triangle-like saw waveform
+ if (WavGenOut>0xFFFF) WavGenOut = 0xFFFF - ( ((WavGenOut-0x10000)<<16) / Steepness ); //2nd half (falling edge, reciprocal steepness)
+ }}
+
+ else if (WF & TRI_BITVAL) { //triangle (this waveform has no harsh edges, so it doesn't suffer from strong aliasing at high pitches)
+ Tmp = *PhaseAccuPtr ^ ( WF&RING_BITVAL? SID->RingSourceMSB : 0 );
+ WavGenOut = ( Tmp ^ (Tmp&0x8000000? 0xFFFFFFF:0) ) >> 11;
+ }
+
+
+ WavGenOut &= 0xFFFF;
+ if (WF&0xF0) SID->PrevWavGenOut[Channel] = WavGenOut; //emulate waveform 00 floating wave-DAC (utilized by SounDemon digis)
+ else WavGenOut = SID->PrevWavGenOut[Channel]; //(on real SID waveform00 decays, we just simply keep the value to avoid clicks)
+ SID->PrevPhaseAccu[Channel] = *PhaseAccuPtr;
+ SID->RingSourceMSB = MSB;
+
+ //routing the channel signal to either the filter or the unfiltered master output depending on filter-switch SID-registers
+ Envelope = SID->ChipModel==8580 ? SID->EnvelopeCounter[Channel] : ADSR_DAC_6581[SID->EnvelopeCounter[Channel]];
+ if (FilterSwitchReso & FilterSwitchVal[Channel]) {
+ FilterInput += ( ((int)WavGenOut-0x8000) * Envelope ) >> 8;
+ }
+ else if ( Channel!=14 || !(VolumeBand & OFF3_BITVAL) ) {
+ NonFilted += ( ((int)WavGenOut-0x8000) * Envelope ) >> 8;
+ }
+
+ }
+ //update readable SID1-registers (some SID tunes might use 3rd channel ENV3/OSC3 value as control)
+ SID->C64->IObankRD[SID->BaseAddress+0x1B] = WavGenOut>>8; //OSC3, ENV3 (some players rely on it, unfortunately even for timing)
+ SID->C64->IObankRD[SID->BaseAddress+0x1C] = SID->EnvelopeCounter[14]; //Envelope
+
+
+ //Filter
+
+
+ Cutoff = (SID->BasePtr[0x16] << 3) + (SID->BasePtr[0x15] & 7);
+ Resonance = FilterSwitchReso >> 4;
+ if (SID->ChipModel == 8580) {
+ Cutoff = CutoffMul8580_44100Hz[Cutoff];
+ Resonance = Resonances8580[Resonance];
+ }
+ else { //6581
+ Cutoff += (FilterInput*105)>>16; if (Cutoff>0x7FF) Cutoff=0x7FF; else if (Cutoff<0) Cutoff=0; //MOSFET-VCR control-voltage-modulation
+ Cutoff = CutoffMul6581_44100Hz[Cutoff]; //(resistance-modulation aka 6581 filter distortion) emulation
+ Resonance = Resonances6581[Resonance];
+ }
+
+ FilterOutput=0;
+ Tmp = FilterInput + ((SID->PrevBandPass * Resonance)>>12) + SID->PrevLowPass;
+ if (VolumeBand & HIGHPASS_BITVAL) FilterOutput -= Tmp;
+ Tmp = SID->PrevBandPass - ( (Tmp * Cutoff) >> 12 );
+ SID->PrevBandPass = Tmp;
+ if (VolumeBand & BANDPASS_BITVAL) FilterOutput -= Tmp;
+ Tmp = SID->PrevLowPass + ( (Tmp * Cutoff) >> 12 );
+ SID->PrevLowPass = Tmp;
+ if (VolumeBand & LOWPASS_BITVAL) FilterOutput += Tmp;
+
+
+ //Output stage
+ //For $D418 volume-register digi playback: an AC / DC separation for $D418 value at low (20Hz or so) cutoff-frequency,
+ //sending AC (highpass) value to a 4th 'digi' channel mixed to the master output, and set ONLY the DC (lowpass) value to the volume-control.
+ //This solved 2 issues: Thanks to the lowpass filtering of the volume-control, SID tunes where digi is played together with normal SID channels,
+ //won't sound distorted anymore, and the volume-clicks disappear when setting SID-volume. (This is useful for fade-in/out tunes like Hades Nebula, where clicking ruins the intro.)
+ if (SID->C64->RealSIDmode) {
+ Tmp = (signed int) ( (VolumeBand&0xF) << 12 );
+ NonFilted += (Tmp - SID->PrevVolume) * D418_DIGI_VOLUME; //highpass is digi, adding it to output must be before digifilter-code
+ SID->PrevVolume += (Tmp - SID->PrevVolume) >> 10; //arithmetic shift amount determines digi lowpass-frequency
+ MainVolume = SID->PrevVolume >> 12; //lowpass is main volume
+ }
+ else MainVolume = VolumeBand & 0xF;
+
+ Output = ((NonFilted+FilterOutput) * MainVolume) / ( (CHANNELS*VOLUME_MAX) + SID->C64->Attenuation );
+
+ return Output; // master output
+
+}
+
diff --git a/lib/rbcodec/codecs/cRSID/C64/SID.h b/lib/rbcodec/codecs/cRSID/C64/SID.h
new file mode 100644
index 0000000000..3e0e866171
--- /dev/null
+++ b/lib/rbcodec/codecs/cRSID/C64/SID.h
@@ -0,0 +1,824 @@
+
+//SID-tables: combined waveform,etc. (Keep them static because they're included locally inside the wave-generator function.)
+
+
+static const unsigned char ADSR_DAC_6581[] = {
+ 0x00,0x02,0x03,0x04,0x05,0x06,0x07,0x09,0x09,0x0B,0x0B,0x0D,0x0D,0x0F,0x10,0x12,
+ 0x11,0x13,0x14,0x15,0x16,0x17,0x18,0x1A,0x1A,0x1C,0x1C,0x1E,0x1E,0x20,0x21,0x23, //used at output of ADSR envelope generator
+ 0x21,0x23,0x24,0x25,0x26,0x27,0x28,0x2A,0x2A,0x2C,0x2C,0x2E,0x2E,0x30,0x31,0x33, //(not used for wave-generator because of 8bit-only resolution)
+ 0x32,0x34,0x35,0x36,0x37,0x38,0x39,0x3B,0x3B,0x3D,0x3D,0x3F,0x3F,0x41,0x42,0x44,
+ 0x40,0x42,0x42,0x44,0x44,0x46,0x47,0x49,0x49,0x4A,0x4B,0x4D,0x4D,0x4F,0x50,0x52,
+ 0x51,0x53,0x53,0x55,0x55,0x57,0x58,0x5A,0x5A,0x5B,0x5C,0x5E,0x5E,0x60,0x61,0x63,
+ 0x61,0x62,0x63,0x65,0x65,0x67,0x68,0x6A,0x69,0x6B,0x6C,0x6E,0x6E,0x70,0x71,0x73,
+ 0x72,0x73,0x74,0x76,0x76,0x78,0x79,0x7B,0x7A,0x7C,0x7D,0x7F,0x7F,0x81,0x82,0x84,
+ 0x7B,0x7D,0x7E,0x80,0x80,0x82,0x83,0x85,0x84,0x86,0x87,0x89,0x89,0x8B,0x8C,0x8D,
+ 0x8C,0x8E,0x8F,0x91,0x91,0x93,0x94,0x96,0x95,0x97,0x98,0x9A,0x9A,0x9C,0x9D,0x9E,
+ 0x9C,0x9E,0x9F,0xA1,0xA1,0xA3,0xA4,0xA5,0xA5,0xA7,0xA8,0xAA,0xAA,0xAC,0xAC,0xAE,
+ 0xAD,0xAF,0xB0,0xB2,0xB2,0xB4,0xB5,0xB6,0xB6,0xB8,0xB9,0xBB,0xBB,0xBD,0xBD,0xBF,
+ 0xBB,0xBD,0xBE,0xC0,0xC0,0xC2,0xC2,0xC4,0xC4,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCD,
+ 0xCC,0xCE,0xCF,0xD1,0xD1,0xD3,0xD3,0xD5,0xD5,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDE,
+ 0xDC,0xDE,0xDF,0xE1,0xE1,0xE3,0xE3,0xE5,0xE5,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xEE,
+ 0xED,0xEF,0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFF
+};
+
+
+static const unsigned short Resonances8580[] = { //generated by curvegen.c
+// 0 1 2 3 4 5 6 7 8 9 A B C D E F
+ 0x16A0,0x14BF,0x1306,0x1172,0x1000,0x0EAC,0x0D74,0x0C56,0x0B50,0x0A5F,0x0983,0x08B9,0x0800,0x0756,0x06BA,0x062B
+ //0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE8, 0xD5, 0xC5, 0xB3, 0xA4, 0x97, 0x8A, 0x80, 0x77, 0x6E, 0x66 <- calculated then refined manually to sound best
+};
+
+static const unsigned short Resonances6581[] = { //generated by curvegen.c
+// 0 1 2 3 4 5 6 7 8 9 A B C D E F
+ 0x168F,0x168F,0x168F,0x168F,0x168F,0x168F,0x1555,0x1249,0x1000,0x0E38,0x0CCC,0x0BA2,0x0AAA,0x09D8,0x0924,0x0888
+ //0xFF, 0xFE, 0xFD, 0xFC, 0xFB, 0xF9, 0xF6, 0xF2, 0xEC, 0xE4, 0xCD, 0xBA, 0xAB, 0x9E, 0x92, 0x86 <- calculated then refined manually to sound best
+};
+
+
+static const unsigned short CutoffMul8580_44100Hz[] = { //generated by curvegen.c
+0x006,0x00A,0x00D,0x011,0x014,0x018,0x01B,0x01F,0x022,0x026,0x029,0x02D,0x030,0x034,0x037,0x03B,
+0x03E,0x041,0x045,0x048,0x04C,0x04F,0x053,0x056,0x059,0x05D,0x060,0x064,0x067,0x06B,0x06E,0x071,
+0x075,0x078,0x07C,0x07F,0x082,0x086,0x089,0x08D,0x090,0x093,0x097,0x09A,0x09D,0x0A1,0x0A4,0x0A7,
+0x0AB,0x0AE,0x0B2,0x0B5,0x0B8,0x0BC,0x0BF,0x0C2,0x0C6,0x0C9,0x0CC,0x0D0,0x0D3,0x0D6,0x0D9,0x0DD,
+0x0E0,0x0E3,0x0E7,0x0EA,0x0ED,0x0F1,0x0F4,0x0F7,0x0FA,0x0FE,0x101,0x104,0x108,0x10B,0x10E,0x111,
+0x115,0x118,0x11B,0x11E,0x122,0x125,0x128,0x12B,0x12F,0x132,0x135,0x138,0x13C,0x13F,0x142,0x145,
+0x149,0x14C,0x14F,0x152,0x155,0x159,0x15C,0x15F,0x162,0x165,0x169,0x16C,0x16F,0x172,0x175,0x178,
+0x17C,0x17F,0x182,0x185,0x188,0x18B,0x18F,0x192,0x195,0x198,0x19B,0x19E,0x1A2,0x1A5,0x1A8,0x1AB,
+0x1AE,0x1B1,0x1B4,0x1B7,0x1BB,0x1BE,0x1C1,0x1C4,0x1C7,0x1CA,0x1CD,0x1D0,0x1D3,0x1D7,0x1DA,0x1DD,
+0x1E0,0x1E3,0x1E6,0x1E9,0x1EC,0x1EF,0x1F2,0x1F5,0x1F9,0x1FC,0x1FF,0x202,0x205,0x208,0x20B,0x20E,
+0x211,0x214,0x217,0x21A,0x21D,0x220,0x223,0x226,0x229,0x22C,0x22F,0x232,0x235,0x238,0x23B,0x23E,
+0x241,0x244,0x247,0x24A,0x24D,0x250,0x253,0x256,0x259,0x25C,0x25F,0x262,0x265,0x268,0x26B,0x26E,
+0x271,0x274,0x277,0x27A,0x27D,0x280,0x283,0x286,0x289,0x28C,0x28F,0x292,0x295,0x297,0x29A,0x29D,
+0x2A0,0x2A3,0x2A6,0x2A9,0x2AC,0x2AF,0x2B2,0x2B5,0x2B8,0x2BB,0x2BD,0x2C0,0x2C3,0x2C6,0x2C9,0x2CC,
+0x2CF,0x2D2,0x2D5,0x2D7,0x2DA,0x2DD,0x2E0,0x2E3,0x2E6,0x2E9,0x2EB,0x2EE,0x2F1,0x2F4,0x2F7,0x2FA,
+0x2FD,0x2FF,0x302,0x305,0x308,0x30B,0x30E,0x310,0x313,0x316,0x319,0x31C,0x31F,0x321,0x324,0x327,
+0x32A,0x32D,0x32F,0x332,0x335,0x338,0x33B,0x33D,0x340,0x343,0x346,0x349,0x34B,0x34E,0x351,0x354,
+0x356,0x359,0x35C,0x35F,0x362,0x364,0x367,0x36A,0x36D,0x36F,0x372,0x375,0x378,0x37A,0x37D,0x380,
+0x382,0x385,0x388,0x38B,0x38D,0x390,0x393,0x396,0x398,0x39B,0x39E,0x3A0,0x3A3,0x3A6,0x3A8,0x3AB,
+0x3AE,0x3B1,0x3B3,0x3B6,0x3B9,0x3BB,0x3BE,0x3C1,0x3C3,0x3C6,0x3C9,0x3CB,0x3CE,0x3D1,0x3D3,0x3D6,
+0x3D9,0x3DB,0x3DE,0x3E1,0x3E3,0x3E6,0x3E9,0x3EB,0x3EE,0x3F1,0x3F3,0x3F6,0x3F8,0x3FB,0x3FE,0x400,
+0x403,0x406,0x408,0x40B,0x40D,0x410,0x413,0x415,0x418,0x41A,0x41D,0x420,0x422,0x425,0x427,0x42A,
+0x42D,0x42F,0x432,0x434,0x437,0x439,0x43C,0x43F,0x441,0x444,0x446,0x449,0x44B,0x44E,0x451,0x453,
+0x456,0x458,0x45B,0x45D,0x460,0x462,0x465,0x467,0x46A,0x46D,0x46F,0x472,0x474,0x477,0x479,0x47C,
+0x47E,0x481,0x483,0x486,0x488,0x48B,0x48D,0x490,0x492,0x495,0x497,0x49A,0x49C,0x49F,0x4A1,0x4A4,
+0x4A6,0x4A9,0x4AB,0x4AE,0x4B0,0x4B3,0x4B5,0x4B8,0x4BA,0x4BC,0x4BF,0x4C1,0x4C4,0x4C6,0x4C9,0x4CB,
+0x4CE,0x4D0,0x4D3,0x4D5,0x4D7,0x4DA,0x4DC,0x4DF,0x4E1,0x4E4,0x4E6,0x4E8,0x4EB,0x4ED,0x4F0,0x4F2,
+0x4F5,0x4F7,0x4F9,0x4FC,0x4FE,0x501,0x503,0x505,0x508,0x50A,0x50D,0x50F,0x511,0x514,0x516,0x519,
+0x51B,0x51D,0x520,0x522,0x524,0x527,0x529,0x52C,0x52E,0x530,0x533,0x535,0x537,0x53A,0x53C,0x53E,
+0x541,0x543,0x546,0x548,0x54A,0x54D,0x54F,0x551,0x554,0x556,0x558,0x55B,0x55D,0x55F,0x562,0x564,
+0x566,0x568,0x56B,0x56D,0x56F,0x572,0x574,0x576,0x579,0x57B,0x57D,0x580,0x582,0x584,0x586,0x589,
+0x58B,0x58D,0x590,0x592,0x594,0x596,0x599,0x59B,0x59D,0x5A0,0x5A2,0x5A4,0x5A6,0x5A9,0x5AB,0x5AD,
+0x5AF,0x5B2,0x5B4,0x5B6,0x5B8,0x5BB,0x5BD,0x5BF,0x5C1,0x5C4,0x5C6,0x5C8,0x5CA,0x5CD,0x5CF,0x5D1,
+0x5D3,0x5D5,0x5D8,0x5DA,0x5DC,0x5DE,0x5E1,0x5E3,0x5E5,0x5E7,0x5E9,0x5EC,0x5EE,0x5F0,0x5F2,0x5F4,
+0x5F7,0x5F9,0x5FB,0x5FD,0x5FF,0x602,0x604,0x606,0x608,0x60A,0x60C,0x60F,0x611,0x613,0x615,0x617,
+0x619,0x61C,0x61E,0x620,0x622,0x624,0x626,0x629,0x62B,0x62D,0x62F,0x631,0x633,0x635,0x638,0x63A,
+0x63C,0x63E,0x640,0x642,0x644,0x646,0x649,0x64B,0x64D,0x64F,0x651,0x653,0x655,0x657,0x65A,0x65C,
+0x65E,0x660,0x662,0x664,0x666,0x668,0x66A,0x66C,0x66F,0x671,0x673,0x675,0x677,0x679,0x67B,0x67D,
+0x67F,0x681,0x683,0x685,0x688,0x68A,0x68C,0x68E,0x690,0x692,0x694,0x696,0x698,0x69A,0x69C,0x69E,
+0x6A0,0x6A2,0x6A4,0x6A6,0x6A8,0x6AB,0x6AD,0x6AF,0x6B1,0x6B3,0x6B5,0x6B7,0x6B9,0x6BB,0x6BD,0x6BF,
+0x6C1,0x6C3,0x6C5,0x6C7,0x6C9,0x6CB,0x6CD,0x6CF,0x6D1,0x6D3,0x6D5,0x6D7,0x6D9,0x6DB,0x6DD,0x6DF,
+0x6E1,0x6E3,0x6E5,0x6E7,0x6E9,0x6EB,0x6ED,0x6EF,0x6F1,0x6F3,0x6F5,0x6F7,0x6F9,0x6FB,0x6FD,0x6FF,
+0x701,0x703,0x705,0x707,0x709,0x70B,0x70C,0x70E,0x710,0x712,0x714,0x716,0x718,0x71A,0x71C,0x71E,
+0x720,0x722,0x724,0x726,0x728,0x72A,0x72C,0x72E,0x72F,0x731,0x733,0x735,0x737,0x739,0x73B,0x73D,
+0x73F,0x741,0x743,0x745,0x746,0x748,0x74A,0x74C,0x74E,0x750,0x752,0x754,0x756,0x758,0x759,0x75B,
+0x75D,0x75F,0x761,0x763,0x765,0x767,0x769,0x76A,0x76C,0x76E,0x770,0x772,0x774,0x776,0x778,0x779,
+0x77B,0x77D,0x77F,0x781,0x783,0x785,0x786,0x788,0x78A,0x78C,0x78E,0x790,0x791,0x793,0x795,0x797,
+0x799,0x79B,0x79D,0x79E,0x7A0,0x7A2,0x7A4,0x7A6,0x7A7,0x7A9,0x7AB,0x7AD,0x7AF,0x7B1,0x7B2,0x7B4,
+0x7B6,0x7B8,0x7BA,0x7BB,0x7BD,0x7BF,0x7C1,0x7C3,0x7C4,0x7C6,0x7C8,0x7CA,0x7CC,0x7CD,0x7CF,0x7D1,
+0x7D3,0x7D5,0x7D6,0x7D8,0x7DA,0x7DC,0x7DE,0x7DF,0x7E1,0x7E3,0x7E5,0x7E6,0x7E8,0x7EA,0x7EC,0x7ED,
+0x7EF,0x7F1,0x7F3,0x7F5,0x7F6,0x7F8,0x7FA,0x7FC,0x7FD,0x7FF,0x801,0x803,0x804,0x806,0x808,0x80A,
+0x80B,0x80D,0x80F,0x810,0x812,0x814,0x816,0x817,0x819,0x81B,0x81D,0x81E,0x820,0x822,0x823,0x825,
+0x827,0x829,0x82A,0x82C,0x82E,0x82F,0x831,0x833,0x835,0x836,0x838,0x83A,0x83B,0x83D,0x83F,0x841,
+0x842,0x844,0x846,0x847,0x849,0x84B,0x84C,0x84E,0x850,0x851,0x853,0x855,0x856,0x858,0x85A,0x85B,
+0x85D,0x85F,0x860,0x862,0x864,0x865,0x867,0x869,0x86A,0x86C,0x86E,0x86F,0x871,0x873,0x874,0x876,
+0x878,0x879,0x87B,0x87D,0x87E,0x880,0x881,0x883,0x885,0x886,0x888,0x88A,0x88B,0x88D,0x88F,0x890,
+0x892,0x893,0x895,0x897,0x898,0x89A,0x89C,0x89D,0x89F,0x8A0,0x8A2,0x8A4,0x8A5,0x8A7,0x8A8,0x8AA,
+0x8AC,0x8AD,0x8AF,0x8B0,0x8B2,0x8B4,0x8B5,0x8B7,0x8B8,0x8BA,0x8BC,0x8BD,0x8BF,0x8C0,0x8C2,0x8C4,
+0x8C5,0x8C7,0x8C8,0x8CA,0x8CB,0x8CD,0x8CF,0x8D0,0x8D2,0x8D3,0x8D5,0x8D6,0x8D8,0x8DA,0x8DB,0x8DD,
+0x8DE,0x8E0,0x8E1,0x8E3,0x8E4,0x8E6,0x8E8,0x8E9,0x8EB,0x8EC,0x8EE,0x8EF,0x8F1,0x8F2,0x8F4,0x8F5,
+0x8F7,0x8F9,0x8FA,0x8FC,0x8FD,0x8FF,0x900,0x902,0x903,0x905,0x906,0x908,0x909,0x90B,0x90C,0x90E,
+0x90F,0x911,0x912,0x914,0x916,0x917,0x919,0x91A,0x91C,0x91D,0x91F,0x920,0x922,0x923,0x925,0x926,
+0x928,0x929,0x92B,0x92C,0x92E,0x92F,0x931,0x932,0x934,0x935,0x936,0x938,0x939,0x93B,0x93C,0x93E,
+0x93F,0x941,0x942,0x944,0x945,0x947,0x948,0x94A,0x94B,0x94D,0x94E,0x950,0x951,0x952,0x954,0x955,
+0x957,0x958,0x95A,0x95B,0x95D,0x95E,0x960,0x961,0x962,0x964,0x965,0x967,0x968,0x96A,0x96B,0x96D,
+0x96E,0x96F,0x971,0x972,0x974,0x975,0x977,0x978,0x979,0x97B,0x97C,0x97E,0x97F,0x981,0x982,0x983,
+0x985,0x986,0x988,0x989,0x98A,0x98C,0x98D,0x98F,0x990,0x992,0x993,0x994,0x996,0x997,0x999,0x99A,
+0x99B,0x99D,0x99E,0x9A0,0x9A1,0x9A2,0x9A4,0x9A5,0x9A6,0x9A8,0x9A9,0x9AB,0x9AC,0x9AD,0x9AF,0x9B0,
+0x9B2,0x9B3,0x9B4,0x9B6,0x9B7,0x9B8,0x9BA,0x9BB,0x9BD,0x9BE,0x9BF,0x9C1,0x9C2,0x9C3,0x9C5,0x9C6,
+0x9C7,0x9C9,0x9CA,0x9CC,0x9CD,0x9CE,0x9D0,0x9D1,0x9D2,0x9D4,0x9D5,0x9D6,0x9D8,0x9D9,0x9DA,0x9DC,
+0x9DD,0x9DE,0x9E0,0x9E1,0x9E2,0x9E4,0x9E5,0x9E6,0x9E8,0x9E9,0x9EA,0x9EC,0x9ED,0x9EE,0x9F0,0x9F1,
+0x9F2,0x9F4,0x9F5,0x9F6,0x9F8,0x9F9,0x9FA,0x9FC,0x9FD,0x9FE,0xA00,0xA01,0xA02,0xA04,0xA05,0xA06,
+0xA07,0xA09,0xA0A,0xA0B,0xA0D,0xA0E,0xA0F,0xA11,0xA12,0xA13,0xA14,0xA16,0xA17,0xA18,0xA1A,0xA1B,
+0xA1C,0xA1D,0xA1F,0xA20,0xA21,0xA23,0xA24,0xA25,0xA26,0xA28,0xA29,0xA2A,0xA2C,0xA2D,0xA2E,0xA2F,
+0xA31,0xA32,0xA33,0xA34,0xA36,0xA37,0xA38,0xA3A,0xA3B,0xA3C,0xA3D,0xA3F,0xA40,0xA41,0xA42,0xA44,
+0xA45,0xA46,0xA47,0xA49,0xA4A,0xA4B,0xA4C,0xA4E,0xA4F,0xA50,0xA51,0xA53,0xA54,0xA55,0xA56,0xA58,
+0xA59,0xA5A,0xA5B,0xA5C,0xA5E,0xA5F,0xA60,0xA61,0xA63,0xA64,0xA65,0xA66,0xA67,0xA69,0xA6A,0xA6B,
+0xA6C,0xA6E,0xA6F,0xA70,0xA71,0xA72,0xA74,0xA75,0xA76,0xA77,0xA79,0xA7A,0xA7B,0xA7C,0xA7D,0xA7F,
+0xA80,0xA81,0xA82,0xA83,0xA85,0xA86,0xA87,0xA88,0xA89,0xA8B,0xA8C,0xA8D,0xA8E,0xA8F,0xA91,0xA92,
+0xA93,0xA94,0xA95,0xA96,0xA98,0xA99,0xA9A,0xA9B,0xA9C,0xA9E,0xA9F,0xAA0,0xAA1,0xAA2,0xAA3,0xAA5,
+0xAA6,0xAA7,0xAA8,0xAA9,0xAAA,0xAAC,0xAAD,0xAAE,0xAAF,0xAB0,0xAB1,0xAB3,0xAB4,0xAB5,0xAB6,0xAB7,
+0xAB8,0xAB9,0xABB,0xABC,0xABD,0xABE,0xABF,0xAC0,0xAC2,0xAC3,0xAC4,0xAC5,0xAC6,0xAC7,0xAC8,0xACA,
+0xACB,0xACC,0xACD,0xACE,0xACF,0xAD0,0xAD1,0xAD3,0xAD4,0xAD5,0xAD6,0xAD7,0xAD8,0xAD9,0xADB,0xADC,
+0xADD,0xADE,0xADF,0xAE0,0xAE1,0xAE2,0xAE3,0xAE5,0xAE6,0xAE7,0xAE8,0xAE9,0xAEA,0xAEB,0xAEC,0xAEE,
+0xAEF,0xAF0,0xAF1,0xAF2,0xAF3,0xAF4,0xAF5,0xAF6,0xAF7,0xAF9,0xAFA,0xAFB,0xAFC,0xAFD,0xAFE,0xAFF,
+0xB00,0xB01,0xB02,0xB04,0xB05,0xB06,0xB07,0xB08,0xB09,0xB0A,0xB0B,0xB0C,0xB0D,0xB0E,0xB0F,0xB11,
+0xB12,0xB13,0xB14,0xB15,0xB16,0xB17,0xB18,0xB19,0xB1A,0xB1B,0xB1C,0xB1D,0xB1E,0xB20,0xB21,0xB22,
+0xB23,0xB24,0xB25,0xB26,0xB27,0xB28,0xB29,0xB2A,0xB2B,0xB2C,0xB2D,0xB2E,0xB2F,0xB30,0xB32,0xB33,
+0xB34,0xB35,0xB36,0xB37,0xB38,0xB39,0xB3A,0xB3B,0xB3C,0xB3D,0xB3E,0xB3F,0xB40,0xB41,0xB42,0xB43,
+0xB44,0xB45,0xB46,0xB47,0xB48,0xB49,0xB4B,0xB4C,0xB4D,0xB4E,0xB4F,0xB50,0xB51,0xB52,0xB53,0xB54,
+0xB55,0xB56,0xB57,0xB58,0xB59,0xB5A,0xB5B,0xB5C,0xB5D,0xB5E,0xB5F,0xB60,0xB61,0xB62,0xB63,0xB64,
+0xB65,0xB66,0xB67,0xB68,0xB69,0xB6A,0xB6B,0xB6C,0xB6D,0xB6E,0xB6F,0xB70,0xB71,0xB72,0xB73,0xB74,
+0xB75,0xB76,0xB77,0xB78,0xB79,0xB7A,0xB7B,0xB7C,0xB7D,0xB7E,0xB7F,0xB80,0xB81,0xB82,0xB83,0xB84,
+0xB85,0xB86,0xB87,0xB88,0xB89,0xB8A,0xB8B,0xB8C,0xB8D,0xB8E,0xB8F,0xB8F,0xB90,0xB91,0xB92,0xB93,
+0xB94,0xB95,0xB96,0xB97,0xB98,0xB99,0xB9A,0xB9B,0xB9C,0xB9D,0xB9E,0xB9F,0xBA0,0xBA1,0xBA2,0xBA3,
+0xBA4,0xBA5,0xBA6,0xBA7,0xBA7,0xBA8,0xBA9,0xBAA,0xBAB,0xBAC,0xBAD,0xBAE,0xBAF,0xBB0,0xBB1,0xBB2,
+0xBB3,0xBB4,0xBB5,0xBB6,0xBB7,0xBB8,0xBB8,0xBB9,0xBBA,0xBBB,0xBBC,0xBBD,0xBBE,0xBBF,0xBC0,0xBC1,
+0xBC2,0xBC3,0xBC4,0xBC5,0xBC5,0xBC6,0xBC7,0xBC8,0xBC9,0xBCA,0xBCB,0xBCC,0xBCD,0xBCE,0xBCF,0xBD0,
+0xBD1,0xBD1,0xBD2,0xBD3,0xBD4,0xBD5,0xBD6,0xBD7,0xBD8,0xBD9,0xBDA,0xBDB,0xBDB,0xBDC,0xBDD,0xBDE,
+0xBDF,0xBE0,0xBE1,0xBE2,0xBE3,0xBE4,0xBE4,0xBE5,0xBE6,0xBE7,0xBE8,0xBE9,0xBEA,0xBEB,0xBEC,0xBED,
+0xBED,0xBEE,0xBEF,0xBF0,0xBF1,0xBF2,0xBF3,0xBF4,0xBF5,0xBF5,0xBF6,0xBF7,0xBF8,0xBF9,0xBFA,0xBFB,
+0xBFC,0xBFC,0xBFD,0xBFE,0xBFF,0xC00,0xC01,0xC02,0xC03,0xC03,0xC04,0xC05,0xC06,0xC07,0xC08,0xC09,
+0xC0A,0xC0A,0xC0B,0xC0C,0xC0D,0xC0E,0xC0F,0xC10,0xC10,0xC11,0xC12,0xC13,0xC14,0xC15,0xC16,0xC16,
+0xC17,0xC18,0xC19,0xC1A,0xC1B,0xC1C,0xC1C,0xC1D,0xC1E,0xC1F,0xC20,0xC21,0xC21,0xC22,0xC23,0xC24,
+0xC25,0xC26,0xC27,0xC27,0xC28,0xC29,0xC2A,0xC2B,0xC2C,0xC2C,0xC2D,0xC2E,0xC2F,0xC30,0xC31,0xC31,
+0xC32,0xC33,0xC34,0xC35,0xC36,0xC36,0xC37,0xC38,0xC39,0xC3A,0xC3B,0xC3B,0xC3C,0xC3D,0xC3E,0xC3F,
+0xC3F,0xC40,0xC41,0xC42,0xC43,0xC44,0xC44,0xC45,0xC46,0xC47,0xC48,0xC48,0xC49,0xC4A,0xC4B,0xC4C,
+0xC4D,0xC4D,0xC4E,0xC4F,0xC50,0xC51,0xC51,0xC52,0xC53,0xC54,0xC55,0xC55,0xC56,0xC57,0xC58,0xC59,
+0xC59,0xC5A,0xC5B,0xC5C,0xC5D,0xC5D,0xC5E,0xC5F,0xC60,0xC61,0xC61,0xC62,0xC63,0xC64,0xC64,0xC65,
+0xC66,0xC67,0xC68,0xC68,0xC69,0xC6A,0xC6B,0xC6C,0xC6C,0xC6D,0xC6E,0xC6F,0xC6F,0xC70,0xC71,0xC72,
+0xC73,0xC73,0xC74,0xC75,0xC76,0xC76,0xC77,0xC78,0xC79,0xC7A,0xC7A,0xC7B,0xC7C,0xC7D,0xC7D,0xC7E,
+0xC7F,0xC80,0xC80,0xC81,0xC82,0xC83,0xC83,0xC84,0xC85,0xC86,0xC87,0xC87,0xC88,0xC89,0xC8A,0xC8A,
+0xC8B,0xC8C,0xC8D,0xC8D,0xC8E,0xC8F,0xC90,0xC90,0xC91,0xC92,0xC93,0xC93,0xC94,0xC95,0xC96,0xC96,
+0xC97,0xC98,0xC99,0xC99,0xC9A,0xC9B,0xC9C,0xC9C,0xC9D,0xC9E,0xC9F,0xC9F,0xCA0,0xCA1,0xCA1,0xCA2,
+0xCA3,0xCA4,0xCA4,0xCA5,0xCA6,0xCA7,0xCA7,0xCA8,0xCA9,0xCAA,0xCAA,0xCAB,0xCAC,0xCAC,0xCAD,0xCAE,
+0xCAF,0xCAF,0xCB0,0xCB1,0xCB2,0xCB2,0xCB3,0xCB4,0xCB4,0xCB5,0xCB6,0xCB7,0xCB7,0xCB8,0xCB9,0xCB9,
+0xCBA,0xCBB,0xCBC,0xCBC,0xCBD,0xCBE,0xCBE,0xCBF,0xCC0,0xCC1,0xCC1,0xCC2,0xCC3,0xCC3,0xCC4,0xCC5,
+0xCC6,0xCC6,0xCC7,0xCC8,0xCC8,0xCC9,0xCCA,0xCCA,0xCCB,0xCCC,0xCCD,0xCCD,0xCCE,0xCCF,0xCCF,0xCD0,
+0xCD1,0xCD1,0xCD2,0xCD3,0xCD4,0xCD4,0xCD5,0xCD6,0xCD6,0xCD7,0xCD8,0xCD8,0xCD9,0xCDA,0xCDA,0xCDB,
+0xCDC,0xCDC,0xCDD,0xCDE,0xCDF,0xCDF,0xCE0,0xCE1,0xCE1,0xCE2,0xCE3,0xCE3,0xCE4,0xCE5,0xCE5,0xCE6,
+0xCE7,0xCE7,0xCE8,0xCE9,0xCE9,0xCEA,0xCEB,0xCEB,0xCEC,0xCED,0xCED,0xCEE,0xCEF,0xCEF,0xCF0,0xCF1,
+0xCF1,0xCF2,0xCF3,0xCF3,0xCF4,0xCF5,0xCF5,0xCF6,0xCF7,0xCF7,0xCF8,0xCF9,0xCF9,0xCFA,0xCFB,0xCFB,
+0xCFC,0xCFD,0xCFD,0xCFE,0xCFF,0xCFF,0xD00,0xD01,0xD01,0xD02,0xD03,0xD03,0xD04,0xD05,0xD05,0xD06,
+0xD07,0xD07,0xD08,0xD09,0xD09,0xD0A,0xD0A,0xD0B,0xD0C,0xD0C,0xD0D,0xD0E,0xD0E,0xD0F,0xD10,0xD10,
+0xD11,0xD12,0xD12,0xD13,0xD13,0xD14,0xD15,0xD15,0xD16,0xD17,0xD17,0xD18,0xD19,0xD19,0xD1A,0xD1A,
+0xD1B,0xD1C,0xD1C,0xD1D,0xD1E,0xD1E,0xD1F,0xD1F,0xD20,0xD21,0xD21,0xD22,0xD23,0xD23,0xD24,0xD25,
+0xD25,0xD26,0xD26,0xD27,0xD28,0xD28,0xD29,0xD29,0xD2A,0xD2B,0xD2B,0xD2C,0xD2D,0xD2D,0xD2E,0xD2E,
+0xD2F,0xD30,0xD30,0xD31,0xD32,0xD32,0xD33,0xD33,0xD34,0xD35,0xD35,0xD36,0xD36,0xD37,0xD38,0xD38
+};
+
+static const unsigned short CutoffMul6581_44100Hz[] = { //generated by curvegen.c
+0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,
+0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,
+0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,
+0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,
+0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,
+0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,
+0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,
+0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,
+0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,
+0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,
+0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,
+0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,0x081,
+0x081,0x086,0x08B,0x08F,0x094,0x099,0x09D,0x0A2,0x0A6,0x0AB,0x0B0,0x0B4,0x0B9,0x0BE,0x0C2,0x0C7,
+0x0CB,0x0D0,0x0D5,0x0D9,0x0DE,0x0E2,0x0E7,0x0EB,0x0F0,0x0F5,0x0F9,0x0FE,0x102,0x107,0x10B,0x110,
+0x114,0x119,0x11D,0x122,0x126,0x12B,0x12F,0x134,0x138,0x13D,0x141,0x146,0x14A,0x14F,0x153,0x157,
+0x15C,0x160,0x165,0x169,0x16E,0x172,0x176,0x17B,0x17F,0x183,0x188,0x18C,0x191,0x195,0x199,0x19E,
+0x1A2,0x1A6,0x1AB,0x1AF,0x1B3,0x1B8,0x1BC,0x1C0,0x1C5,0x1C9,0x1CD,0x1D2,0x1D6,0x1DA,0x1DE,0x1E3,
+0x1E7,0x1EB,0x1EF,0x1F4,0x1F8,0x1FC,0x200,0x205,0x209,0x20D,0x211,0x215,0x21A,0x21E,0x222,0x226,
+0x22A,0x22F,0x233,0x237,0x23B,0x23F,0x243,0x248,0x24C,0x250,0x254,0x258,0x25C,0x260,0x265,0x269,
+0x26D,0x271,0x275,0x279,0x27D,0x281,0x285,0x289,0x28D,0x292,0x296,0x29A,0x29E,0x2A2,0x2A6,0x2AA,
+0x2AE,0x2B2,0x2B6,0x2BA,0x2BE,0x2C2,0x2C6,0x2CA,0x2CE,0x2D2,0x2D6,0x2DA,0x2DE,0x2E2,0x2E6,0x2EA,
+0x2EE,0x2F2,0x2F6,0x2FA,0x2FD,0x301,0x305,0x309,0x30D,0x311,0x315,0x319,0x31D,0x321,0x325,0x328,
+0x32C,0x330,0x334,0x338,0x33C,0x340,0x344,0x347,0x34B,0x34F,0x353,0x357,0x35B,0x35E,0x362,0x366,
+0x36A,0x36E,0x371,0x375,0x379,0x37D,0x381,0x384,0x388,0x38C,0x390,0x393,0x397,0x39B,0x39F,0x3A2,
+0x3A6,0x3AA,0x3AE,0x3B1,0x3B5,0x3B9,0x3BD,0x3C0,0x3C4,0x3C8,0x3CB,0x3CF,0x3D3,0x3D6,0x3DA,0x3DE,
+0x3E1,0x3E5,0x3E9,0x3EC,0x3F0,0x3F4,0x3F7,0x3FB,0x3FF,0x402,0x406,0x409,0x40D,0x411,0x414,0x418,
+0x41B,0x41F,0x423,0x426,0x42A,0x42D,0x431,0x435,0x438,0x43C,0x43F,0x443,0x446,0x44A,0x44D,0x451,
+0x455,0x458,0x45C,0x45F,0x463,0x466,0x46A,0x46D,0x471,0x474,0x478,0x47B,0x47F,0x482,0x486,0x489,
+0x48C,0x490,0x493,0x497,0x49A,0x49E,0x4A1,0x4A5,0x4A8,0x4AB,0x4AF,0x4B2,0x4B6,0x4B9,0x4BD,0x4C0,
+0x4C3,0x4C7,0x4CA,0x4CE,0x4D1,0x4D4,0x4D8,0x4DB,0x4DE,0x4E2,0x4E5,0x4E8,0x4EC,0x4EF,0x4F3,0x4F6,
+0x4F9,0x4FD,0x500,0x503,0x507,0x50A,0x50D,0x510,0x514,0x517,0x51A,0x51E,0x521,0x524,0x528,0x52B,
+0x52E,0x531,0x535,0x538,0x53B,0x53E,0x542,0x545,0x548,0x54B,0x54F,0x552,0x555,0x558,0x55B,0x55F,
+0x562,0x565,0x568,0x56C,0x56F,0x572,0x575,0x578,0x57B,0x57F,0x582,0x585,0x588,0x58B,0x58F,0x592,
+0x595,0x598,0x59B,0x59E,0x5A1,0x5A5,0x5A8,0x5AB,0x5AE,0x5B1,0x5B4,0x5B7,0x5BA,0x5BD,0x5C1,0x5C4,
+0x5C7,0x5CA,0x5CD,0x5D0,0x5D3,0x5D6,0x5D9,0x5DC,0x5DF,0x5E2,0x5E5,0x5E9,0x5EC,0x5EF,0x5F2,0x5F5,
+0x5F8,0x5FB,0x5FE,0x601,0x604,0x607,0x60A,0x60D,0x610,0x613,0x616,0x619,0x61C,0x61F,0x622,0x625,
+0x628,0x62B,0x62E,0x631,0x634,0x637,0x63A,0x63D,0x640,0x643,0x645,0x648,0x64B,0x64E,0x651,0x654,
+0x657,0x65A,0x65D,0x660,0x663,0x666,0x669,0x66B,0x66E,0x671,0x674,0x677,0x67A,0x67D,0x680,0x682,
+0x685,0x688,0x68B,0x68E,0x691,0x694,0x696,0x699,0x69C,0x69F,0x6A2,0x6A5,0x6A7,0x6AA,0x6AD,0x6B0,
+0x6B3,0x6B6,0x6B8,0x6BB,0x6BE,0x6C1,0x6C4,0x6C6,0x6C9,0x6CC,0x6CF,0x6D2,0x6D4,0x6D7,0x6DA,0x6DD,
+0x6DF,0x6E2,0x6E5,0x6E8,0x6EA,0x6ED,0x6F0,0x6F3,0x6F5,0x6F8,0x6FB,0x6FE,0x700,0x703,0x706,0x708,
+0x70B,0x70E,0x711,0x713,0x716,0x719,0x71B,0x71E,0x721,0x723,0x726,0x729,0x72B,0x72E,0x731,0x733,
+0x736,0x739,0x73B,0x73E,0x741,0x743,0x746,0x749,0x74B,0x74E,0x750,0x753,0x756,0x758,0x75B,0x75E,
+0x760,0x763,0x765,0x768,0x76B,0x76D,0x770,0x772,0x775,0x778,0x77A,0x77D,0x77F,0x782,0x784,0x787,
+0x78A,0x78C,0x78F,0x791,0x794,0x796,0x799,0x79B,0x79E,0x7A0,0x7A3,0x7A5,0x7A8,0x7AB,0x7AD,0x7B0,
+0x7B2,0x7B5,0x7B7,0x7BA,0x7BC,0x7BF,0x7C1,0x7C4,0x7C6,0x7C9,0x7CB,0x7CE,0x7D0,0x7D2,0x7D5,0x7D7,
+0x7DA,0x7DC,0x7DF,0x7E1,0x7E4,0x7E6,0x7E9,0x7EB,0x7ED,0x7F0,0x7F2,0x7F5,0x7F7,0x7FA,0x7FC,0x7FF,
+0x801,0x803,0x806,0x808,0x80B,0x80D,0x80F,0x812,0x814,0x817,0x819,0x81B,0x81E,0x820,0x823,0x825,
+0x827,0x82A,0x82C,0x82E,0x831,0x833,0x835,0x838,0x83A,0x83D,0x83F,0x841,0x844,0x846,0x848,0x84B,
+0x84D,0x84F,0x852,0x854,0x856,0x858,0x85B,0x85D,0x85F,0x862,0x864,0x866,0x869,0x86B,0x86D,0x86F,
+0x872,0x874,0x876,0x879,0x87B,0x87D,0x87F,0x882,0x884,0x886,0x888,0x88B,0x88D,0x88F,0x892,0x894,
+0x896,0x898,0x89A,0x89D,0x89F,0x8A1,0x8A3,0x8A6,0x8A8,0x8AA,0x8AC,0x8AE,0x8B1,0x8B3,0x8B5,0x8B7,
+0x8BA,0x8BC,0x8BE,0x8C0,0x8C2,0x8C4,0x8C7,0x8C9,0x8CB,0x8CD,0x8CF,0x8D2,0x8D4,0x8D6,0x8D8,0x8DA,
+0x8DC,0x8DF,0x8E1,0x8E3,0x8E5,0x8E7,0x8E9,0x8EB,0x8EE,0x8F0,0x8F2,0x8F4,0x8F6,0x8F8,0x8FA,0x8FC,
+0x8FF,0x901,0x903,0x905,0x907,0x909,0x90B,0x90D,0x90F,0x912,0x914,0x916,0x918,0x91A,0x91C,0x91E,
+0x920,0x922,0x924,0x926,0x928,0x92B,0x92D,0x92F,0x931,0x933,0x935,0x937,0x939,0x93B,0x93D,0x93F,
+0x941,0x943,0x945,0x947,0x949,0x94B,0x94D,0x94F,0x951,0x953,0x955,0x957,0x959,0x95B,0x95D,0x95F,
+0x961,0x963,0x965,0x967,0x969,0x96B,0x96D,0x96F,0x971,0x973,0x975,0x977,0x979,0x97B,0x97D,0x97F,
+0x981,0x983,0x985,0x987,0x989,0x98B,0x98D,0x98F,0x991,0x993,0x995,0x997,0x999,0x99B,0x99C,0x99E,
+0x9A0,0x9A2,0x9A4,0x9A6,0x9A8,0x9AA,0x9AC,0x9AE,0x9B0,0x9B2,0x9B3,0x9B5,0x9B7,0x9B9,0x9BB,0x9BD,
+0x9BF,0x9C1,0x9C3,0x9C5,0x9C6,0x9C8,0x9CA,0x9CC,0x9CE,0x9D0,0x9D2,0x9D4,0x9D5,0x9D7,0x9D9,0x9DB,
+0x9DD,0x9DF,0x9E1,0x9E2,0x9E4,0x9E6,0x9E8,0x9EA,0x9EC,0x9ED,0x9EF,0x9F1,0x9F3,0x9F5,0x9F7,0x9F8,
+0x9FA,0x9FC,0x9FE,0xA00,0xA02,0xA03,0xA05,0xA07,0xA09,0xA0B,0xA0C,0xA0E,0xA10,0xA12,0xA14,0xA15,
+0xA17,0xA19,0xA1B,0xA1C,0xA1E,0xA20,0xA22,0xA24,0xA25,0xA27,0xA29,0xA2B,0xA2C,0xA2E,0xA30,0xA32,
+0xA33,0xA35,0xA37,0xA39,0xA3A,0xA3C,0xA3E,0xA40,0xA41,0xA43,0xA45,0xA47,0xA48,0xA4A,0xA4C,0xA4E,
+0xA4F,0xA51,0xA53,0xA54,0xA56,0xA58,0xA5A,0xA5B,0xA5D,0xA5F,0xA60,0xA62,0xA64,0xA65,0xA67,0xA69,
+0xA6B,0xA6C,0xA6E,0xA70,0xA71,0xA73,0xA75,0xA76,0xA78,0xA7A,0xA7B,0xA7D,0xA7F,0xA80,0xA82,0xA84,
+0xA85,0xA87,0xA89,0xA8A,0xA8C,0xA8E,0xA8F,0xA91,0xA92,0xA94,0xA96,0xA97,0xA99,0xA9B,0xA9C,0xA9E,
+0xAA0,0xAA1,0xAA3,0xAA4,0xAA6,0xAA8,0xAA9,0xAAB,0xAAC,0xAAE,0xAB0,0xAB1,0xAB3,0xAB5,0xAB6,0xAB8,
+0xAB9,0xABB,0xABC,0xABE,0xAC0,0xAC1,0xAC3,0xAC4,0xAC6,0xAC8,0xAC9,0xACB,0xACC,0xACE,0xACF,0xAD1,
+0xAD3,0xAD4,0xAD6,0xAD7,0xAD9,0xADA,0xADC,0xADE,0xADF,0xAE1,0xAE2,0xAE4,0xAE5,0xAE7,0xAE8,0xAEA,
+0xAEB,0xAED,0xAEE,0xAF0,0xAF2,0xAF3,0xAF5,0xAF6,0xAF8,0xAF9,0xAFB,0xAFC,0xAFE,0xAFF,0xB01,0xB02,
+0xB04,0xB05,0xB07,0xB08,0xB0A,0xB0B,0xB0D,0xB0E,0xB10,0xB11,0xB13,0xB14,0xB16,0xB17,0xB19,0xB1A,
+0xB1C,0xB1D,0xB1F,0xB20,0xB22,0xB23,0xB24,0xB26,0xB27,0xB29,0xB2A,0xB2C,0xB2D,0xB2F,0xB30,0xB32,
+0xB33,0xB35,0xB36,0xB37,0xB39,0xB3A,0xB3C,0xB3D,0xB3F,0xB40,0xB42,0xB43,0xB44,0xB46,0xB47,0xB49,
+0xB4A,0xB4C,0xB4D,0xB4E,0xB50,0xB51,0xB53,0xB54,0xB55,0xB57,0xB58,0xB5A,0xB5B,0xB5C,0xB5E,0xB5F,
+0xB61,0xB62,0xB63,0xB65,0xB66,0xB68,0xB69,0xB6A,0xB6C,0xB6D,0xB6F,0xB70,0xB71,0xB73,0xB74,0xB75,
+0xB77,0xB78,0xB7A,0xB7B,0xB7C,0xB7E,0xB7F,0xB80,0xB82,0xB83,0xB84,0xB86,0xB87,0xB89,0xB8A,0xB8B,
+0xB8D,0xB8E,0xB8F,0xB91,0xB92,0xB93,0xB95,0xB96,0xB97,0xB99,0xB9A,0xB9B,0xB9D,0xB9E,0xB9F,0xBA1,
+0xBA2,0xBA3,0xBA5,0xBA6,0xBA7,0xBA8,0xBAA,0xBAB,0xBAC,0xBAE,0xBAF,0xBB0,0xBB2,0xBB3,0xBB4,0xBB6,
+0xBB7,0xBB8,0xBB9,0xBBB,0xBBC,0xBBD,0xBBF,0xBC0,0xBC1,0xBC2,0xBC4,0xBC5,0xBC6,0xBC8,0xBC9,0xBCA,
+0xBCB,0xBCD,0xBCE,0xBCF,0xBD0,0xBD2,0xBD3,0xBD4,0xBD5,0xBD7,0xBD8,0xBD9,0xBDB,0xBDC,0xBDD,0xBDE,
+0xBE0,0xBE1,0xBE2,0xBE3,0xBE4,0xBE6,0xBE7,0xBE8,0xBE9,0xBEB,0xBEC,0xBED,0xBEE,0xBF0,0xBF1,0xBF2,
+0xBF3,0xBF5,0xBF6,0xBF7,0xBF8,0xBF9,0xBFB,0xBFC,0xBFD,0xBFE,0xBFF,0xC01,0xC02,0xC03,0xC04,0xC05,
+0xC07,0xC08,0xC09,0xC0A,0xC0B,0xC0D,0xC0E,0xC0F,0xC10,0xC11,0xC13,0xC14,0xC15,0xC16,0xC17,0xC19,
+0xC1A,0xC1B,0xC1C,0xC1D,0xC1E,0xC20,0xC21,0xC22,0xC23,0xC24,0xC25,0xC27,0xC28,0xC29,0xC2A,0xC2B,
+0xC2C,0xC2E,0xC2F,0xC30,0xC31,0xC32,0xC33,0xC34,0xC36,0xC37,0xC38,0xC39,0xC3A,0xC3B,0xC3C,0xC3E,
+0xC3F,0xC40,0xC41,0xC42,0xC43,0xC44,0xC46,0xC47,0xC48,0xC49,0xC4A,0xC4B,0xC4C,0xC4D,0xC4F,0xC50,
+0xC51,0xC52,0xC53,0xC54,0xC55,0xC56,0xC57,0xC59,0xC5A,0xC5B,0xC5C,0xC5D,0xC5E,0xC5F,0xC60,0xC61,
+0xC62,0xC63,0xC65,0xC66,0xC67,0xC68,0xC69,0xC6A,0xC6B,0xC6C,0xC6D,0xC6E,0xC6F,0xC71,0xC72,0xC73,
+0xC74,0xC75,0xC76,0xC77,0xC78,0xC79,0xC7A,0xC7B,0xC7C,0xC7D,0xC7E,0xC7F,0xC81,0xC82,0xC83,0xC84,
+0xC85,0xC86,0xC87,0xC88,0xC89,0xC8A,0xC8B,0xC8C,0xC8D,0xC8E,0xC8F,0xC90,0xC91,0xC92,0xC93,0xC94,
+0xC95,0xC96,0xC97,0xC99,0xC9A,0xC9B,0xC9C,0xC9D,0xC9E,0xC9F,0xCA0,0xCA1,0xCA2,0xCA3,0xCA4,0xCA5,
+0xCA6,0xCA7,0xCA8,0xCA9,0xCAA,0xCAB,0xCAC,0xCAD,0xCAE,0xCAF,0xCB0,0xCB1,0xCB2,0xCB3,0xCB4,0xCB5,
+0xCB6,0xCB7,0xCB8,0xCB9,0xCBA,0xCBB,0xCBC,0xCBD,0xCBE,0xCBF,0xCC0,0xCC1,0xCC2,0xCC3,0xCC4,0xCC5,
+0xCC6,0xCC7,0xCC8,0xCC9,0xCCA,0xCCA,0xCCB,0xCCC,0xCCD,0xCCE,0xCCF,0xCD0,0xCD1,0xCD2,0xCD3,0xCD4,
+0xCD5,0xCD6,0xCD7,0xCD8,0xCD9,0xCDA,0xCDB,0xCDC,0xCDD,0xCDE,0xCDF,0xCE0,0xCE0,0xCE1,0xCE2,0xCE3,
+0xCE4,0xCE5,0xCE6,0xCE7,0xCE8,0xCE9,0xCEA,0xCEB,0xCEC,0xCED,0xCEE,0xCEF,0xCEF,0xCF0,0xCF1,0xCF2,
+0xCF3,0xCF4,0xCF5,0xCF6,0xCF7,0xCF8,0xCF9,0xCFA,0xCFA,0xCFB,0xCFC,0xCFD,0xCFE,0xCFF,0xD00,0xD01,
+0xD02,0xD03,0xD04,0xD04,0xD05,0xD06,0xD07,0xD08,0xD09,0xD0A,0xD0B,0xD0C,0xD0D,0xD0D,0xD0E,0xD0F,
+0xD10,0xD11,0xD12,0xD13,0xD14,0xD15,0xD15,0xD16,0xD17,0xD18,0xD19,0xD1A,0xD1B,0xD1C,0xD1C,0xD1D,
+0xD1E,0xD1F,0xD20,0xD21,0xD22,0xD23,0xD23,0xD24,0xD25,0xD26,0xD27,0xD28,0xD29,0xD29,0xD2A,0xD2B,
+0xD2C,0xD2D,0xD2E,0xD2F,0xD2F,0xD30,0xD31,0xD32,0xD33,0xD34,0xD34,0xD35,0xD36,0xD37,0xD38,0xD39,
+0xD3A,0xD3A,0xD3B,0xD3C,0xD3D,0xD3E,0xD3F,0xD3F,0xD40,0xD41,0xD42,0xD43,0xD44,0xD44,0xD45,0xD46,
+0xD47,0xD48,0xD48,0xD49,0xD4A,0xD4B,0xD4C,0xD4D,0xD4D,0xD4E,0xD4F,0xD50,0xD51,0xD51,0xD52,0xD53,
+0xD54,0xD55,0xD55,0xD56,0xD57,0xD58,0xD59,0xD5A,0xD5A,0xD5B,0xD5C,0xD5D,0xD5D,0xD5E,0xD5F,0xD60,
+0xD61,0xD61,0xD62,0xD63,0xD64,0xD65,0xD65,0xD66,0xD67,0xD68,0xD69,0xD69,0xD6A,0xD6B,0xD6C,0xD6C,
+0xD6D,0xD6E,0xD6F,0xD70,0xD70,0xD71,0xD72,0xD73,0xD73,0xD74,0xD75,0xD76,0xD77,0xD77,0xD78,0xD79,
+0xD7A,0xD7A,0xD7B,0xD7C,0xD7D,0xD7D,0xD7E,0xD7F,0xD80,0xD80,0xD81,0xD82,0xD83,0xD83,0xD84,0xD85,
+0xD86,0xD86,0xD87,0xD88,0xD89,0xD89,0xD8A,0xD8B,0xD8C,0xD8C,0xD8D,0xD8E,0xD8F,0xD8F,0xD90,0xD91,
+0xD92,0xD92,0xD93,0xD94,0xD94,0xD95,0xD96,0xD97,0xD97,0xD98,0xD99,0xD9A,0xD9A,0xD9B,0xD9C,0xD9C,
+0xD9D,0xD9E,0xD9F,0xD9F,0xDA0,0xDA1,0xDA1,0xDA2,0xDA3,0xDA4,0xDA4,0xDA5,0xDA6,0xDA6,0xDA7,0xDA8,
+0xDA9,0xDA9,0xDAA,0xDAB,0xDAB,0xDAC,0xDAD,0xDAE,0xDAE,0xDAF,0xDB0,0xDB0,0xDB1,0xDB2,0xDB2,0xDB3,
+0xDB4,0xDB5,0xDB5,0xDB6,0xDB7,0xDB7,0xDB8,0xDB9,0xDB9,0xDBA,0xDBB,0xDBB,0xDBC,0xDBD,0xDBD,0xDBE,
+0xDBF,0xDC0,0xDC0,0xDC1,0xDC2,0xDC2,0xDC3,0xDC4,0xDC4,0xDC5,0xDC6,0xDC6,0xDC7,0xDC8,0xDC8,0xDC9,
+0xDCA,0xDCA,0xDCB,0xDCC,0xDCC,0xDCD,0xDCE,0xDCE,0xDCF,0xDD0,0xDD0,0xDD1,0xDD2,0xDD2,0xDD3,0xDD4,
+0xDD4,0xDD5,0xDD6,0xDD6,0xDD7,0xDD8,0xDD8,0xDD9,0xDD9,0xDDA,0xDDB,0xDDB,0xDDC,0xDDD,0xDDD,0xDDE,
+0xDDF,0xDDF,0xDE0,0xDE1,0xDE1,0xDE2,0xDE2,0xDE3,0xDE4,0xDE4,0xDE5,0xDE6,0xDE6,0xDE7,0xDE8,0xDE8,
+0xDE9,0xDE9,0xDEA,0xDEB,0xDEB,0xDEC,0xDED,0xDED,0xDEE,0xDEE,0xDEF,0xDF0,0xDF0,0xDF1,0xDF2,0xDF2,
+0xDF3,0xDF3,0xDF4,0xDF5,0xDF5,0xDF6,0xDF7,0xDF7,0xDF8,0xDF8,0xDF9,0xDFA,0xDFA,0xDFB,0xDFB,0xDFC,
+0xDFD,0xDFD,0xDFE,0xDFE,0xDFF,0xE00,0xE00,0xE01,0xE02,0xE02,0xE03,0xE03,0xE04,0xE05,0xE05,0xE06,
+0xE06,0xE07,0xE08,0xE08,0xE09,0xE09,0xE0A,0xE0A,0xE0B,0xE0C,0xE0C,0xE0D,0xE0D,0xE0E,0xE0F,0xE0F,
+0xE10,0xE10,0xE11,0xE12,0xE12,0xE13,0xE13,0xE14,0xE14,0xE15,0xE16,0xE16,0xE17,0xE17,0xE18,0xE18,
+0xE19,0xE1A,0xE1A,0xE1B,0xE1B,0xE1C,0xE1C,0xE1D,0xE1E,0xE1E,0xE1F,0xE1F,0xE20,0xE20,0xE21,0xE22,
+0xE22,0xE23,0xE23,0xE24,0xE24,0xE25,0xE26,0xE26,0xE27,0xE27,0xE28,0xE28,0xE29,0xE29,0xE2A,0xE2B,
+0xE2B,0xE2C,0xE2C,0xE2D,0xE2D,0xE2E,0xE2E,0xE2F,0xE30,0xE30,0xE31,0xE31,0xE32,0xE32,0xE33,0xE33,
+0xE34,0xE34,0xE35,0xE36,0xE36,0xE37,0xE37,0xE38,0xE38,0xE39,0xE39,0xE3A,0xE3A,0xE3B,0xE3B,0xE3C,
+0xE3C,0xE3D,0xE3E,0xE3E,0xE3F,0xE3F,0xE40,0xE40,0xE41,0xE41,0xE42,0xE42,0xE43,0xE43,0xE44,0xE44
+};
+
+
+static const unsigned char SawTriangle [] = {
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x03,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x07,0x07,0x07,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x03,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0E,0x0E,0x0E,0x0E,0x0F,0x0F,0x0F,0x0F,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x03,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x07,0x07,0x07,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x03,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1C,0x1C,0x1C,0x1C,0x1C,0x1C,0x1C,0x1C,0x1E,0x1E,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x03,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x07,0x07,0x07,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x03,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0E,0x0E,0x0E,0x0E,0x0F,0x0F,0x0F,0x1F,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x03,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x07,0x07,0x07,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x03,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3E,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x03,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x07,0x07,0x07,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x03,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0E,0x0E,0x0E,0x0E,0x0F,0x0F,0x0F,0x0F,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x03,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x07,0x07,0x07,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x03,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1C,0x1C,0x1C,0x1C,0x1C,0x1C,0x1C,0x1C,0x1E,0x1E,0x1F,0x1F,0x1F,0x1F,0x3F,0x3F,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x03,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x07,0x07,0x07,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x03,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0E,0x0E,0x0E,0x0E,0x0F,0x0F,0x1F,0x1F,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x83,0x83,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x87,0x87,0x87,0x8F,
+ 0xC0,0xE0,0xE0,0xC0,0xC0,0xE0,0xE0,0xE0,0xE0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xE0,0xE0,0xC0,0xC0,0xC0,0xC0,0xC0,0xE0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,
+ 0xC0,0xE0,0xE0,0xC0,0xC0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xC0,0xE0,0xC0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,
+ 0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,
+ 0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE3,0xE3,
+ 0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,
+ 0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF1,
+ 0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,
+ 0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
+};
+
+static const unsigned char PulseTriangle [] = { //can be substituted by PulseSaw with mirroring the upper half (like with triangle-waveform)
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1C,0x00,0x3C,0x3F,0x3F,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0C,0x5E,0x5F,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x40,0x40,0x60,0x60,0x6F,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x40,0x00,0x00,0x00,0x40,0x40,0x40,0x40,0x60,0x40,0x40,0x60,0x60,0x60,0x60,0x70,0x77,
+ 0x00,0x00,0x00,0x00,0x00,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x60,0x60,0x60,0x40,0x40,0x40,0x60,0x60,0x60,0x60,0x70,0x60,0x60,0x60,0x70,0x70,0x70,0x78,0x7B,
+ 0x60,0x60,0x60,0x70,0x60,0x70,0x70,0x70,0x70,0x70,0x70,0x78,0x78,0x78,0x78,0x7C,0x78,0x78,0x78,0x7C,0x78,0x7C,0x7C,0x7E,0x7C,0x7E,0x7E,0x7F,0x7F,0x7F,0x7F,0x7F,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x80,0x80,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x8E,0x9F,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x80,0x80,0x80,0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0x00,0x00,0x00,0x80,0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xAF,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xA0,0xA0,0xA0,0xA0,0xB7,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xA0,0x80,0x80,0x80,0x80,0x80,0x80,0xA0,0xA0,0xA0,0xA0,0xA0,0xB0,0xA0,0xB0,0xB0,0xBB,
+ 0xA0,0xA0,0xA0,0xA0,0xA0,0xA0,0xB0,0xB0,0xA0,0xB0,0xB0,0xB8,0xB0,0xB8,0xB8,0xBC,0xB0,0xB8,0xB8,0xB8,0xB8,0xBC,0xBC,0xBE,0xBC,0xBC,0xBE,0xBF,0xBE,0xBF,0xBF,0xBF,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xC0,0xC0,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xC0,0x80,0x80,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,
+ 0x80,0x80,0x80,0xC0,0x80,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xCF,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0xC0,0xC0,0xC0,0x80,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,
+ 0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xD7,
+ 0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xD0,0xD0,0xD9,
+ 0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xD0,0xC0,0xD0,0xD0,0xD0,0xD0,0xD8,0xD8,0xDC,0xD0,0xD0,0xD8,0xD8,0xD8,0xDC,0xDC,0xDE,0xDC,0xDC,0xDE,0xDF,0xDE,0xDF,0xDF,0xDF,
+ 0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xE0,0xC0,0xE0,0xE0,0xE0,
+ 0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xE0,0xC0,0xC0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE7,
+ 0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE8,
+ 0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE8,0xEC,0xE0,0xE0,0xE0,0xE8,0xE8,0xE8,0xEC,0xEE,0xEC,0xEC,0xEC,0xEE,0xEE,0xEF,0xEF,0xEF,
+ 0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xF0,0xF0,0xF0,0xE0,0xE0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,
+ 0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF4,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF4,0xF0,0xF4,0xF4,0xF6,0xF6,0xF7,0xF7,0xF7,
+ 0xF0,0xF0,0xF0,0xF8,0xF0,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xFA,0xFA,0xFB,0xFB,0xFB,
+ 0xF8,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFD,0xFD,0xFD,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFC,0xFD,0xFD,0xFD,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xF8,
+ 0xFB,0xFB,0xFB,0xFA,0xFA,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF0,0xF0,0xF0,0xF0,0xF0,
+ 0xF7,0xF7,0xF7,0xF6,0xF6,0xF4,0xF4,0xF0,0xF4,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF4,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,
+ 0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xE0,0xE0,0xF0,0xF0,0xF0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,
+ 0xEF,0xEF,0xEF,0xEE,0xEE,0xEC,0xEC,0xE8,0xEE,0xEC,0xE8,0xE8,0xE8,0xE0,0xE0,0xE0,0xEC,0xE8,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,
+ 0xE8,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,
+ 0xE7,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xC0,0xC0,0xE0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,
+ 0xE0,0xE0,0xE0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,
+ 0xDF,0xDF,0xDF,0xDE,0xDF,0xDE,0xDC,0xDC,0xDE,0xDC,0xDC,0xD8,0xD8,0xD8,0xD0,0xD0,0xDC,0xD8,0xD8,0xD0,0xD0,0xD0,0xD0,0xC0,0xD0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,
+ 0xD9,0xD0,0xD0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,
+ 0xD7,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,
+ 0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0x80,0xC0,0xC0,0xC0,0x80,0x80,0x80,0x80,0x80,
+ 0xCF,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0x80,0xC0,0x80,0x80,0x80,
+ 0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0x80,0x80,0xC0,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0xC0,0xC0,0xC0,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0xBF,0xBF,0xBF,0xBE,0xBF,0xBE,0xBC,0xBC,0xBE,0xBC,0xBC,0xB8,0xB8,0xB8,0xB8,0xB0,0xBC,0xB8,0xB8,0xB0,0xB8,0xB0,0xB0,0xB0,0xB0,0xB0,0xA0,0xA0,0xA0,0xA0,0xA0,0xA0,
+ 0xBB,0xB0,0xB0,0xA0,0xB0,0xA0,0xA0,0xA0,0xA0,0xA0,0xA0,0x80,0x80,0x80,0x80,0x80,0xA0,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0xB7,0xB0,0xA0,0xA0,0xA0,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0xAF,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x00,0x80,0x00,0x00,0x00,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x00,0x00,0x80,0x80,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x80,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x9F,0x9E,0x88,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x00,0x00,0x00,
+ 0x80,0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x80,0x80,0x80,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x7F,0x7F,0x7F,0x7F,0x7F,0x7E,0x7E,0x7C,0x7E,0x7C,0x7C,0x78,0x7C,0x78,0x78,0x78,0x7C,0x78,0x78,0x78,0x78,0x70,0x70,0x70,0x78,0x70,0x70,0x60,0x70,0x60,0x60,0x60,
+ 0x7B,0x78,0x70,0x70,0x70,0x60,0x60,0x60,0x70,0x60,0x60,0x60,0x60,0x40,0x40,0x40,0x60,0x60,0x60,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x00,0x40,0x00,0x00,0x00,
+ 0x77,0x70,0x60,0x60,0x60,0x60,0x40,0x40,0x60,0x40,0x40,0x40,0x40,0x00,0x00,0x00,0x40,0x40,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x6F,0x64,0x60,0x40,0x40,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x5F,0x5E,0x4C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x3F,0x3F,0x3E,0x00,0x1C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+};
+
+static const unsigned char PulseSawtooth [] = {
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x07,0x1F,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0F,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x17,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3B,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3D,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3F,0x00,0x0C,0x1C,0x3F,0x1E,0x3F,0x3F,0x3F,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0B,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0A,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x5E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x5F,0x00,0x00,0x00,0x5F,0x0C,0x5F,0x5F,0x5F,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x47,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x43,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x65,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x6E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x6F,0x00,0x40,0x40,0x6F,0x40,0x6F,0x6F,0x6F,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x63,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x61,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x40,0x00,0x40,0x40,0x70,0x00,0x00,0x40,0x40,0x40,0x40,0x40,0x70,0x40,0x60,0x60,0x77,0x60,0x77,0x77,0x77,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x60,0x00,0x40,0x40,0x60,0x40,0x60,0x60,0x79,
+ 0x00,0x40,0x40,0x40,0x40,0x40,0x40,0x60,0x40,0x40,0x40,0x60,0x60,0x60,0x60,0x78,0x40,0x60,0x60,0x60,0x60,0x60,0x60,0x78,0x60,0x70,0x70,0x78,0x70,0x79,0x7B,0x7B,
+ 0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x70,0x60,0x60,0x60,0x70,0x60,0x70,0x70,0x7C,0x60,0x70,0x70,0x70,0x70,0x70,0x70,0x7C,0x70,0x78,0x78,0x7C,0x78,0x7C,0x7C,0x7D,
+ 0x70,0x78,0x78,0x78,0x78,0x78,0x78,0x7C,0x78,0x7C,0x7C,0x7E,0x7C,0x7E,0x7E,0x7E,0x7C,0x7C,0x7C,0x7E,0x7E,0x7F,0x7F,0x7F,0x7E,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0xFF,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x8F,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x87,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x83,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x8D,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x00,0x80,0x80,0x8E,0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x8F,0x80,0x80,0x80,0x9F,0x80,0x9F,0x9F,0x9F,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x00,0x80,0x80,0x87,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x83,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x80,0x80,0x80,0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x81,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x84,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x87,0x80,0x80,0x80,0x87,0x80,0x8F,0xAF,0xAF,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x80,
+ 0x00,0x00,0x00,0x80,0x00,0x00,0x80,0x80,0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x83,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x81,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xA0,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xA0,0x80,0x80,0x80,0xA0,0x80,0xA3,0xB7,0xB7,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xB1,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xB0,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xB0,0x80,0xA0,0xA0,0xB0,0xA0,0xB8,0xB9,0xBB,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xA0,0x80,0x80,0x80,0xA0,0x80,0xA0,0xA0,0xB8,0x80,0xA0,0xA0,0xA0,0xA0,0xA0,0xA0,0xB8,0xA0,0xB0,0xB0,0xB8,0xB0,0xBC,0xBC,0xBD,
+ 0xA0,0xB0,0xB0,0xB0,0xB0,0xB8,0xB8,0xBC,0xB0,0xB8,0xB8,0xBC,0xB8,0xBC,0xBE,0xBE,0xB8,0xBC,0xBC,0xBE,0xBC,0xBE,0xBE,0xBF,0xBE,0xBF,0xBF,0xBF,0xBF,0xBF,0xBF,0xBF,
+ 0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x81,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xC7,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xC0,0xC3,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xC0,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xC0,0x80,0x80,0x80,0xC0,0x80,0xC0,0xC0,0xC1,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xC0,0x80,0x80,0x80,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC7,0xC0,0xC0,0xC0,0xC7,0xC0,0xCF,0xCF,0xCF,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xC0,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xC0,0x80,0x80,0x80,0x80,0x80,0x80,0xC0,0xC0,0x80,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC3,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xC0,0x80,0x80,0x80,0xC0,0x80,0xC0,0xC0,0xC0,0x80,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC1,
+ 0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC1,0xC7,0xD7,
+ 0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,
+ 0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xD0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xD0,0xC0,0xC0,0xC0,0xD0,0xC0,0xD0,0xD8,0xDB,
+ 0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xD8,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xD8,0xC0,0xC0,0xC0,0xD8,0xD0,0xD8,0xD8,0xDD,
+ 0xC0,0xC0,0xC0,0xD0,0xC0,0xD0,0xD0,0xDC,0xD0,0xD8,0xD8,0xDC,0xD8,0xDC,0xDC,0xDE,0xD8,0xDC,0xDC,0xDE,0xDC,0xDE,0xDE,0xDF,0xDE,0xDF,0xDF,0xDF,0xDF,0xDF,0xDF,0xDF,
+ 0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,
+ 0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xE3,
+ 0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xE0,0xC0,0xC0,0xC0,0xE0,0xC0,0xE0,0xE0,0xE1,
+ 0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xE0,0xC0,0xC0,0xC0,0xE0,0xE0,0xE0,0xE0,0xE0,0xC0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE1,0xE3,0xE7,
+ 0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xE0,0xC0,0xC0,0xC0,0xE0,0xC0,0xE0,0xE0,0xE0,0xC0,0xC0,0xC0,0xE0,0xC0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,
+ 0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xEB,
+ 0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE8,0xE0,0xE8,0xE8,0xED,
+ 0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xEC,0xE0,0xE0,0xE0,0xEC,0xE8,0xEC,0xEC,0xEE,0xE8,0xE8,0xE8,0xEC,0xEC,0xEE,0xEE,0xEF,0xEC,0xEF,0xEF,0xEF,0xEF,0xEF,0xEF,0xEF,
+ 0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xF0,
+ 0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xF0,0xE0,0xE0,0xE0,0xF0,0xE0,0xF0,0xF0,0xF0,0xE0,0xE0,0xE0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF3,
+ 0xE0,0xE0,0xE0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF5,
+ 0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF4,0xF4,0xF6,0xF0,0xF0,0xF0,0xF4,0xF0,0xF4,0xF6,0xF7,0xF4,0xF6,0xF6,0xF7,0xF7,0xF7,0xF7,0xF7,
+ 0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF8,0xF0,0xF0,0xF0,0xF0,0xF0,0xF8,0xF8,0xF8,0xF0,0xF0,0xF0,0xF8,0xF0,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF9,
+ 0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xFA,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xFB,0xF8,0xFA,0xFA,0xFB,0xFB,0xFB,0xFB,0xFB,
+ 0xF8,0xF8,0xF8,0xFC,0xF8,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFD,0xFC,0xFC,0xFC,0xFD,0xFD,0xFD,0xFD,0xFD,
+ 0xFC,0xFC,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
+};
+
+static const unsigned char PulseSawTriangle [] = {
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1F,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x70,0x60,0x20,0x70,0x70,0x70,0x70,0x70,0x78,0x78,0x78,0x7C,0x7C,0x7E,0x7E,0x7F,0x7F,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x1E,0x3F,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x8C,0x9F,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x80,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x80,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0x00,0x00,0x80,0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xCF,
+ 0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,
+ 0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,
+ 0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,
+ 0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xE0,0xC0,0xC0,0xC0,0xC0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE3,
+ 0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,
+ 0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,
+ 0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,
+ 0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFE,0xFE,0xFE,0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
+};
+
diff --git a/lib/rbcodec/codecs/cRSID/C64/VIC.c b/lib/rbcodec/codecs/cRSID/C64/VIC.c
new file mode 100644
index 0000000000..1f9f736bbe
--- /dev/null
+++ b/lib/rbcodec/codecs/cRSID/C64/VIC.c
@@ -0,0 +1,64 @@
+
+//VIC-II emulation
+
+
+void cRSID_createVICchip (cRSID_C64instance* C64, cRSID_VICinstance* VIC, unsigned short baseaddress) {
+ VIC->C64 = C64;
+ VIC->ChipModel = 0;
+ VIC->BaseAddress = baseaddress;
+ VIC->BasePtrWR = &C64->IObankWR[baseaddress]; VIC->BasePtrRD = &C64->IObankRD[baseaddress];
+ cRSID_initVICchip (VIC);
+}
+
+
+void cRSID_initVICchip (cRSID_VICinstance* VIC) {
+ unsigned char i;
+ for (i=0; i<0x3F; ++i) VIC->BasePtrWR[i] = VIC->BasePtrRD[i] = 0x00;
+ VIC->RowCycleCnt=0;
+}
+
+
+static inline char cRSID_emulateVIC (cRSID_VICinstance* VIC, char cycles) {
+
+ unsigned short RasterRow;
+
+ enum VICregisters { CONTROL = 0x11, RASTERROWL = 0x12, INTERRUPT = 0x19, INTERRUPT_ENABLE = 0x1A };
+
+ enum ControlBitVal { RASTERROWMSB = 0x80, DISPLAY_ENABLE = 0x10, ROWS = 0x08, YSCROLL_MASK = 0x07 };
+
+ enum InterruptBitVal { VIC_IRQ = 0x80, RASTERROW_MATCH_IRQ = 0x01 };
+
+
+ VIC->RowCycleCnt += cycles;
+ if (VIC->RowCycleCnt >= VIC->RasterRowCycles) {
+ VIC->RowCycleCnt -= VIC->RasterRowCycles;
+
+ RasterRow = ( (VIC->BasePtrRD[CONTROL]&RASTERROWMSB) << 1 ) + VIC->BasePtrRD[RASTERROWL];
+ ++RasterRow; if (RasterRow >= VIC->RasterLines) RasterRow = 0;
+ VIC->BasePtrRD[CONTROL] = ( VIC->BasePtrRD[CONTROL] & ~RASTERROWMSB ) | ((RasterRow&0x100)>>1);
+ VIC->BasePtrRD[RASTERROWL] = RasterRow & 0xFF;
+
+ if (VIC->BasePtrWR[INTERRUPT_ENABLE] & RASTERROW_MATCH_IRQ) {
+ if ( RasterRow == ( (VIC->BasePtrWR[CONTROL]&RASTERROWMSB) << 1 ) + VIC->BasePtrWR[RASTERROWL] ) {
+ VIC->BasePtrRD[INTERRUPT] |= VIC_IRQ | RASTERROW_MATCH_IRQ;
+ }
+ }
+
+ }
+
+ return VIC->BasePtrRD[INTERRUPT] & VIC_IRQ;
+}
+
+
+static inline void cRSID_acknowledgeVICrasterIRQ (cRSID_VICinstance* VIC) {
+ enum VICregisters { INTERRUPT = 0x19 };
+ enum InterruptBitVal { VIC_IRQ = 0x80, RASTERROW_MATCH_IRQ = 0x01 };
+ //An 1 is to be written into the IRQ-flag (bit0) of $d019 to clear it and deassert IRQ signal
+ //if (VIC->BasePtrWR[INTERRUPT] & RASTERROW_MATCH_IRQ) { //acknowledge raster-interrupt by writing to $d019 bit0?
+ //But oftentimes INC/LSR/etc. RMW commands are used to acknowledge VIC IRQ, they work on real
+ //CPU because it writes the unmodified original value itself to memory before writing the modified there
+ VIC->BasePtrWR[INTERRUPT] &= ~RASTERROW_MATCH_IRQ; //prepare for next acknowledge-detection
+ VIC->BasePtrRD[INTERRUPT] &= ~(VIC_IRQ | RASTERROW_MATCH_IRQ); //remove IRQ flag and state
+ //}
+}
+
diff --git a/lib/rbcodec/codecs/cRSID/C64/libcRSIDc64.h b/lib/rbcodec/codecs/cRSID/C64/libcRSIDc64.h
new file mode 100644
index 0000000000..5100680768
--- /dev/null
+++ b/lib/rbcodec/codecs/cRSID/C64/libcRSIDc64.h
@@ -0,0 +1,172 @@
+// cRSID lightweight RealSID (integer-only) library-header (with API-calls) by Hermit (Mihaly Horvath)
+
+#ifndef LIBCRSIDC64_HEADER
+#define LIBCRSIDC64_HEADER //used to prevent double inclusion of this header-file
+
+typedef struct cRSID_CPUinstance cRSID_CPUinstance;
+typedef struct cRSID_SIDinstance cRSID_SIDinstance;
+typedef struct cRSID_CIAinstance cRSID_CIAinstance;
+typedef struct cRSID_VICinstance cRSID_VICinstance;
+
+
+//Internal functions
+
+// C64/C64.c
+cRSID_C64instance* cRSID_createC64 (cRSID_C64instance* C64, unsigned short samplerate);
+void cRSID_setC64 (cRSID_C64instance* C64); //configure hardware (SIDs) for SID-tune
+void cRSID_initC64 (cRSID_C64instance* C64); //hard-reset
+int cRSID_emulateC64 (cRSID_C64instance* C64);
+static inline short cRSID_playPSIDdigi (cRSID_C64instance* C64);
+// C64/MEM.c
+static inline unsigned char* cRSID_getMemReadPtr (register unsigned short address); //for global cSID_C64 fast-access
+static inline unsigned char* cRSID_getMemReadPtrC64 (cRSID_C64instance* C64, register unsigned short address); //maybe slower
+static inline unsigned char* cRSID_getMemWritePtr (register unsigned short address); //for global cSID_C64 fast-access
+static inline unsigned char* cRSID_getMemWritePtrC64 (cRSID_C64instance* C64, register unsigned short address); //maybe slower
+static inline unsigned char cRSID_readMem (register unsigned short address); //for global cSID_C64 fast-access
+static inline unsigned char cRSID_readMemC64 (cRSID_C64instance* C64, register unsigned short address); //maybe slower
+static inline void cRSID_writeMem (register unsigned short address, register unsigned char data); //for global cSID_C64 fast-access
+static inline void cRSID_writeMemC64 (cRSID_C64instance* C64, register unsigned short address, register unsigned char data); //maybe slower
+void cRSID_setROMcontent (cRSID_C64instance* C64); //KERNAL, BASIC
+void cRSID_initMem (cRSID_C64instance* C64);
+// C64/CPU.c
+void cRSID_initCPU (cRSID_CPUinstance* CPU, unsigned short mempos);
+unsigned char cRSID_emulateCPU (void); //direct instances inside for hopefully faster operation
+static inline char cRSID_handleCPUinterrupts (cRSID_CPUinstance* CPU);
+// C64/SID.c
+void cRSID_createSIDchip (cRSID_C64instance* C64, cRSID_SIDinstance* SID, unsigned short model, unsigned short baseaddress);
+void cRSID_initSIDchip (cRSID_SIDinstance* SID);
+void cRSID_emulateADSRs (cRSID_SIDinstance *SID, char cycles);
+int cRSID_emulateWaves (cRSID_SIDinstance* SID);
+// C64/CIA.c
+void cRSID_createCIAchip (cRSID_C64instance* C64, cRSID_CIAinstance* CIA, unsigned short baseaddress);
+void cRSID_initCIAchip (cRSID_CIAinstance* CIA);
+static inline char cRSID_emulateCIA (cRSID_CIAinstance* CIA, char cycles);
+static inline void cRSID_writeCIAIRQmask (cRSID_CIAinstance* CIA, unsigned char value);
+static inline void cRSID_acknowledgeCIAIRQ (cRSID_CIAinstance* CIA);
+// C64/VIC.c
+void cRSID_createVICchip (cRSID_C64instance* C64, cRSID_VICinstance* VIC, unsigned short baseaddress);
+void cRSID_initVICchip (cRSID_VICinstance* VIC);
+static inline char cRSID_emulateVIC (cRSID_VICinstance* VIC, char cycles);
+static inline void cRSID_acknowledgeVICrasterIRQ (cRSID_VICinstance* VIC);
+
+// host/file.c
+#ifdef CRSID_PLATFORM_PC
+int cRSID_loadSIDfile (unsigned char* SIDfileData, char* filename, int maxlen); //load SID-file to a memory location (and return size)
+#endif
+// host/audio.c
+#ifdef CRSID_PLATFORM_PC
+void* cRSID_initSound (cRSID_C64instance* C64, unsigned short samplerate, unsigned short buflen);
+void cRSID_startSound (void);
+void cRSID_stopSound (void);
+void cRSID_closeSound (void);
+void cRSID_generateSound (cRSID_C64instance* C64, unsigned char* buf, unsigned short len);
+#endif
+
+
+struct cRSID_CPUinstance {
+ cRSID_C64instance* C64; //reference to the containing C64
+ unsigned int PC;
+ short int A, SP;
+ unsigned char X, Y, ST; //STATUS-flags: N V - B D I Z C
+ unsigned char PrevNMI; //used for NMI leading edge detection
+};
+
+
+struct cRSID_SIDinstance {
+ //SID-chip data:
+ cRSID_C64instance* C64; //reference to the containing C64
+ unsigned short ChipModel; //values: 8580 / 6581
+ unsigned short BaseAddress; //SID-baseaddress location in C64-memory (IO)
+ unsigned char* BasePtr; //SID-baseaddress location in host's memory
+ //ADSR-related:
+ unsigned char ADSRstate[15];
+ unsigned short RateCounter[15];
+ unsigned char EnvelopeCounter[15];
+ unsigned char ExponentCounter[15];
+ //Wave-related:
+ int PhaseAccu[15]; //28bit precision instead of 24bit
+ int PrevPhaseAccu[15]; //(integerized ClockRatio fractionals, WebSID has similar solution)
+ unsigned char SyncSourceMSBrise;
+ unsigned int RingSourceMSB;
+ unsigned int NoiseLFSR[15];
+ unsigned int PrevWavGenOut[15];
+ unsigned char PrevWavData[15];
+ //Filter-related:
+ int PrevLowPass;
+ int PrevBandPass;
+ //Output-stage:
+ signed int PrevVolume; //lowpass-filtered version of Volume-band register
+};
+
+
+struct cRSID_CIAinstance {
+ cRSID_C64instance* C64; //reference to the containing C64
+ char ChipModel; //old or new CIA? (have 1 cycle difference in cases)
+ unsigned short BaseAddress; //CIA-baseaddress location in C64-memory (IO)
+ unsigned char* BasePtrWR; //CIA-baseaddress location in host's memory for writing
+ unsigned char* BasePtrRD; //CIA-baseaddress location in host's memory for reading
+};
+
+
+struct cRSID_VICinstance {
+ cRSID_C64instance* C64; //reference to the containing C64
+ char ChipModel; //(timing differences between models?)
+ unsigned short BaseAddress; //VIC-baseaddress location in C64-memory (IO)
+ unsigned char* BasePtrWR; //VIC-baseaddress location in host's memory for writing
+ unsigned char* BasePtrRD; //VIC-baseaddress location in host's memory for reading
+ unsigned short RasterLines;
+ unsigned char RasterRowCycles;
+ unsigned char RowCycleCnt;
+};
+
+
+struct cRSID_C64instance {
+ //platform-related:
+ unsigned short SampleRate;
+ //C64-machine related:
+ unsigned char VideoStandard; //0:NTSC, 1:PAL (based on the SID-header field)
+ unsigned int CPUfrequency;
+ unsigned short SampleClockRatio; //ratio of CPU-clock and samplerate
+ //SID-file related:
+ union {
+ cRSID_SIDheader* SIDheader;
+ char* SIDfileData;
+ };
+ unsigned short Attenuation;
+ char RealSIDmode;
+ char PSIDdigiMode;
+ unsigned char SubTune;
+ unsigned short LoadAddress;
+ unsigned short InitAddress;
+ unsigned short PlayAddress;
+ unsigned short EndAddress;
+ char TimerSource; //for current subtune, 0:VIC, 1:CIA (as in SID-header)
+ //PSID-playback related:
+ //char CIAisSet; //for dynamic CIA setting from player-routine (RealSID substitution)
+ int FrameCycles;
+ int FrameCycleCnt; //this is a substitution in PSID-mode for CIA/VIC counters
+ short PrevRasterLine;
+ short SampleCycleCnt;
+ short TenthSecondCnt;
+ char Finished;
+ char Returned;
+ unsigned char IRQ; //collected IRQ line from devices
+ unsigned char NMI; //collected NMI line from devices
+
+ //Hardware-elements:
+ cRSID_CPUinstance CPU;
+ cRSID_SIDinstance SID[CRSID_SIDCOUNT_MAX+1];
+ cRSID_CIAinstance CIA[CRSID_CIACOUNT+1];
+ cRSID_VICinstance VIC;
+ //Overlapping system memories, which one is read/written in an address region depends on CPU-port bankselect-bits)
+ //Address $00 and $01 - data-direction and data-register of port built into CPU (used as bank-selection) (overriding RAM on C64)
+ unsigned char RAMbank[0x10100]; //$0000..$FFFF RAM (and RAM under IO/ROM/CPUport)
+ unsigned char IObankWR[0x10100]; //$D000..$DFFF IO-RAM (registers) to write (VIC/SID/CIA/ColorRAM/IOexpansion)
+ unsigned char IObankRD[0x10100]; //$D000..$DFFF IO-RAM (registers) to read from (VIC/SID/CIA/ColorRAM/IOexpansion)
+ unsigned char ROMbanks[0x10100]; //$1000..$1FFF/$9000..$9FFF (CHARGEN), $A000..$BFFF (BASIC), $E000..$FFFF (KERNAL)
+};
+
+cRSID_C64instance cRSID_C64; //the only global object (for faster & simpler access than with struct-pointers, in some places)
+
+
+#endif //LIBCRSIDC64_HEADER
diff --git a/lib/rbcodec/codecs/cRSID/README.rockbox b/lib/rbcodec/codecs/cRSID/README.rockbox
new file mode 100644
index 0000000000..b95151aa09
--- /dev/null
+++ b/lib/rbcodec/codecs/cRSID/README.rockbox
@@ -0,0 +1,19 @@
+Some notes about cRSID usage in Rockbox
+by Ninja (Wolfram Sang) in 2023
+
+The cRSID codebase is from v1.0. The only change made was a separation of the
+cRSID header into a public and private one, so it could be compiled as a
+library. You can find it as a separate commit in the git repository. This
+likely needs to be updated whenever a newer version of cRSID shall be used.
+
+Currently, newer versions of cRSID are available but they have been discarded.
+v1.1 mainly adds a high quality playback mode using 7x oversampling. This is
+too much for a Sansa Clip. Because the old playback mode still exists, it might
+be possible to add a runtime option to let the user choose. As a first step
+however, it was decided to give the user a working codec without having to deal
+with options. v1.2 mainly adds a SDL-based GUI player, no bigger changes in SID
+emulation. Staying with v1.0 also keeps the codec size significantly lower
+(~50KB for v1.0 vs ~90KB for v1.2 on the Sansa Clip).
+
+cRSID Releases can be found here:
+https://csdb.dk/search/?seinsel=releases&search=crsid
diff --git a/lib/rbcodec/codecs/cRSID/README.txt b/lib/rbcodec/codecs/cRSID/README.txt
new file mode 100644
index 0000000000..3a806b65ed
--- /dev/null
+++ b/lib/rbcodec/codecs/cRSID/README.txt
@@ -0,0 +1,39 @@
+ cRSID by Hermit (Mihaly Horvath) - Year 2022
+ --------------------------------------------
+
+This is a serious integer-only update (rewrite) to my cSID and cSID-light
+commandline SID-players, aiming for an ongoing inclusion into RockBox,
+as per a request by Ninja earlier at CSDb. He will do the integration.
+
+The name now contains the 'R' because now a RealSID-like environment-mode
+(CIA, VIC, IRQ, NMI) is supported more-or-less ('RealSIDmode' in source).
+There are still many RSID tunes that are not played properly, mainly
+the tricky ones which use DC04 or DD0C as jump-addresses or RTI placeholders,
+like for example 'Hi Fi Sky', and other modern digi tunes.
+I don't feel like debugging these complex tunes now...
+PSID-only playback has improved a lot since cSID-light-1.1,
+and now many PlaySID-digis are supported as well if that still matters.
+
+The CPU and ADSR went through serious timing improvements,
+it's now can be called cycle-exact, and hardrestarts and delaybugs are now
+simulated well, no missed notes, whatever.
+
+This release also contains shared and static library forms for better
+inclusion in other SID-playback projects (like FlexSID for example).
+I completely eliminated global variables and definitions, except a
+'cRSID_c64' instance which is for faster access of struct members.
+(Emulated C64 memory accesses are made to this for faster operation.)
+
+More info (the API for the library) is seen in the 'libcRSID.h' file.
+
+It has been tried already on a SanDisk RockBox device and tunes not
+containing digis are already played on it fine. Tunes with 2SID/3SID or
+digis however are too much for the player (38MHz..192MHz ARM) at this form.
+So maybe the code will be optimized by eliminating overheads of structs,
+pointers, optimizing function-calls, inlining, and by other possible means.
+
+Hopefully in the near future the outdated TinySID engine will be replaced
+in the RockBox source-tree...
+
+License is still WTF: Do what the fuck you want with this code, but
+ it would be nice mentioning me as the original author.
diff --git a/lib/rbcodec/codecs/cRSID/SOURCES b/lib/rbcodec/codecs/cRSID/SOURCES
new file mode 100644
index 0000000000..203c9dfbd1
--- /dev/null
+++ b/lib/rbcodec/codecs/cRSID/SOURCES
@@ -0,0 +1 @@
+libcRSID.c
diff --git a/lib/rbcodec/codecs/cRSID/cRSID.make b/lib/rbcodec/codecs/cRSID/cRSID.make
new file mode 100644
index 0000000000..2d5acb8b20
--- /dev/null
+++ b/lib/rbcodec/codecs/cRSID/cRSID.make
@@ -0,0 +1,16 @@
+# __________ __ ___.
+# Open \______ \ ____ ____ | | _\_ |__ _______ ___
+# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+# \/ \/ \/ \/ \/
+
+# cRSID
+CRSID := $(CODECDIR)/cRSID.a
+CRSID_SRC := $(call preprocess, $(RBCODECLIB_DIR)/codecs/cRSID/SOURCES)
+CRSID_OBJ := $(call c2obj, $(CRSID_SRC))
+OTHER_SRC += $(CRSID_SRC)
+
+$(CRSID): $(CRSID_OBJ)
+ $(SILENT)$(shell rm -f $@)
+ $(call PRINTS,AR $(@F))$(AR) rcs $@ $^ >/dev/null
diff --git a/lib/rbcodec/codecs/cRSID/host/audio.c b/lib/rbcodec/codecs/cRSID/host/audio.c
new file mode 100644
index 0000000000..2cfd5dac0b
--- /dev/null
+++ b/lib/rbcodec/codecs/cRSID/host/audio.c
@@ -0,0 +1,62 @@
+
+#ifdef CRSID_PLATFORM_PC
+
+#include <SDL/SDL.h>
+
+
+void cRSID_soundCallback(void* userdata, unsigned char *buf, int len) {
+ cRSID_generateSound( (cRSID_C64instance*)userdata, buf, len );
+}
+
+
+void* cRSID_initSound(cRSID_C64instance* C64, unsigned short samplerate, unsigned short buflen) {
+ static SDL_AudioSpec soundspec;
+ if ( SDL_Init(SDL_INIT_AUDIO) < 0 ) {
+ fprintf(stderr, "Couldn't initialize SDL: %s\n",SDL_GetError()); return NULL;
+ }
+ soundspec.freq=samplerate; soundspec.channels=1; soundspec.format=AUDIO_S16;
+ soundspec.samples=buflen; soundspec.userdata=C64; soundspec.callback=cRSID_soundCallback;
+ if ( SDL_OpenAudio(&soundspec, NULL) < 0 ) {
+ fprintf(stderr, "Couldn't open audio: %s\n", SDL_GetError()); return NULL;
+ }
+ return (void*)&soundspec;
+}
+
+
+void cRSID_closeSound (void) {
+ SDL_PauseAudio(1); SDL_CloseAudio();
+}
+
+
+void cRSID_startSound (void) {
+ SDL_PauseAudio(0);
+}
+
+
+void cRSID_stopSound (void) {
+ SDL_PauseAudio(1);
+}
+
+
+void cRSID_generateSound(cRSID_C64instance* C64instance, unsigned char *buf, unsigned short len) {
+ static unsigned short i;
+ static int Output;
+ for(i=0;i<len;i+=2) {
+ Output=cRSID_generateSample(C64instance); //cRSID_emulateC64(C64instance);
+ //if (Output>=32767) Output=32767; else if (Output<=-32768) Output=-32768; //saturation logic on overflow
+ buf[i]=Output&0xFF; buf[i+1]=Output>>8;
+ }
+}
+
+
+#endif
+
+
+signed short cRSID_generateSample (cRSID_C64instance* C64) { //call this from custom buffer-filler
+ static int Output;
+ Output=cRSID_emulateC64(C64);
+ if (C64->PSIDdigiMode) Output += cRSID_playPSIDdigi(C64);
+ if (Output>=32767) Output=32767; else if (Output<=-32768) Output=-32768; //saturation logic on overflow
+ return (signed short) Output;
+}
+
diff --git a/lib/rbcodec/codecs/cRSID/host/file.c b/lib/rbcodec/codecs/cRSID/host/file.c
new file mode 100644
index 0000000000..c87f37ebb4
--- /dev/null
+++ b/lib/rbcodec/codecs/cRSID/host/file.c
@@ -0,0 +1,60 @@
+
+
+#ifdef CRSID_PLATFORM_PC
+
+int cRSID_loadSIDfile (unsigned char* SIDfileData, char* filename, int maxlen) {
+ static signed short Data;
+ static signed int SizeCnt;
+ static FILE *SIDfile;
+
+ if ( (SIDfile=fopen(filename,"rb")) == NULL ) return CRSID_ERROR_LOAD;
+
+ SizeCnt=0;
+
+ while ( (Data=fgetc(SIDfile)) != EOF ) {
+ if (SizeCnt >= maxlen) return CRSID_ERROR_LOAD;
+ SIDfileData[SizeCnt] = Data; SizeCnt++;
+ }
+
+ fclose(SIDfile);
+ return SizeCnt;
+}
+
+#endif
+
+
+cRSID_SIDheader* cRSID_processSIDfile(cRSID_C64instance* C64, unsigned char* filedata, int filesize) {
+ int i;
+ unsigned short SIDdataOffset;
+ cRSID_SIDheader* SIDheader;
+ static const char MagicStringPSID[]="PSID";
+ //static const char MagicStringRSID[]="RSID";
+
+ C64->SIDheader = SIDheader = (cRSID_SIDheader*) filedata;
+
+ for (i=0x0000; i < 0xA000; ++i) C64->RAMbank[i]=0; //fresh start (maybe some bugged SIDs want 0 at certain RAM-locations)
+ for (i=0xC000; i < 0xD000; ++i) C64->RAMbank[i]=0;
+
+ if ( SIDheader->MagicString[0] != 'P' && SIDheader->MagicString[0] != 'R' ) return NULL;
+ for (i=1; i < (int)(sizeof(MagicStringPSID)-1); ++i) { if (SIDheader->MagicString[i] != MagicStringPSID[i]) return NULL; }
+ C64->RealSIDmode = ( SIDheader->MagicString[0] == 'R' );
+
+ if (SIDheader->LoadAddressH==0 && SIDheader->LoadAddressH==0) { //load-address taken from first 2 bytes of the C64 PRG
+ C64->LoadAddress = (filedata[SIDheader->HeaderSize+1]<<8) + (filedata[SIDheader->HeaderSize+0]);
+ SIDdataOffset = SIDheader->HeaderSize+2;
+ }
+ else { //load-adress taken from SID-header
+ C64->LoadAddress = (SIDheader->LoadAddressH<<8) + (SIDheader->LoadAddressL);
+ SIDdataOffset = SIDheader->HeaderSize;
+ }
+
+ for (i=SIDdataOffset; i<filesize; ++i) C64->RAMbank [ C64->LoadAddress + (i-SIDdataOffset) ] = filedata[i];
+
+ i = C64->LoadAddress + (filesize-SIDdataOffset);
+ C64->EndAddress = (i<0x10000) ? i : 0xFFFF;
+
+ C64->PSIDdigiMode = ( !C64->RealSIDmode && (SIDheader->ModelFormatStandard & 2) );
+
+ return C64->SIDheader;
+}
+
diff --git a/lib/rbcodec/codecs/cRSID/libcRSID.c b/lib/rbcodec/codecs/cRSID/libcRSID.c
new file mode 100644
index 0000000000..f7ef713e12
--- /dev/null
+++ b/lib/rbcodec/codecs/cRSID/libcRSID.c
@@ -0,0 +1,134 @@
+// cRSID lightweight (integer-only) RealSID library (with API-calls) by Hermit (Mihaly Horvath), Year 2022
+// License: WTF - do what the fuck you want with the code, but please mention me as the original author
+
+#include <stdlib.h>
+//#include <stdint.h>
+#ifdef CRSID_PLATFORM_PC
+ #include <stdio.h>
+#endif
+
+#include "libcRSID.h"
+
+#include "C64/C64.c"
+#include "host/file.c"
+#include "host/audio.c"
+
+
+cRSID_C64instance* cRSID_init (unsigned short samplerate, unsigned short buflen) {
+ static cRSID_C64instance* C64 = &cRSID_C64;
+
+ C64 = cRSID_createC64 (C64, samplerate);
+#ifdef CRSID_PLATFORM_PC
+ if ( cRSID_initSound (C64, samplerate,buflen) == NULL) return NULL;
+#else
+ if (buflen) return C64; //this is here just to eliminate unused 'buflen' variable warning
+#endif
+
+ return C64;
+}
+
+
+void cRSID_initSIDtune (cRSID_C64instance* C64, cRSID_SIDheader* SIDheader, char subtune) { //subtune: 1..255
+ static const unsigned char PowersOf2[] = {0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};
+ unsigned int InitTimeout=10000000; //allowed instructions, value should be selected to allow for long-running memory-copiers in init-routines (e.g. Synth Sample)
+
+ if (subtune==0) subtune = 1;
+ else if (subtune > SIDheader->SubtuneAmount) subtune = SIDheader->SubtuneAmount;
+ C64->SubTune = subtune;
+
+ cRSID_setC64(C64); cRSID_initC64(C64); //cRSID_writeMemC64(C64,0xD418,0xF); //set C64 hardware and init (reset) it
+
+ //determine init-address:
+ C64->InitAddress = ((SIDheader->InitAddressH)<<8) + (SIDheader->InitAddressL); //get info from BASIC-startupcode for some tunes
+ if (C64->RAMbank[1] == 0x37) { //are there SIDs with routine under IO area? some PSIDs don't set bank-registers themselves
+ if ( (0xA000 <= C64->InitAddress && C64->InitAddress < 0xC000)
+ || (C64->LoadAddress < 0xC000 && C64->EndAddress >= 0xA000) ) C64->RAMbank[1] = 0x36;
+ else if (C64->InitAddress >= 0xE000 || C64->EndAddress >=0xE000) C64->RAMbank[1] = 0x35;
+ }
+ cRSID_initCPU( &C64->CPU, C64->InitAddress ); //prepare init-routine call
+ C64->CPU.A = subtune - 1;
+
+ if (!C64->RealSIDmode) {
+ //call init-routine:
+ for (InitTimeout=10000000; InitTimeout>0; InitTimeout--) { if ( cRSID_emulateCPU()>=0xFE ) break; } //give error when timed out?
+ }
+
+ //determine timing-source, if CIA, replace FrameCycles previouisly set to VIC-timing
+ if (subtune>32) C64->TimerSource = C64->SIDheader->SubtuneTimeSources[0] & 0x80; //subtunes above 32 should use subtune32's timing
+ else C64->TimerSource = C64->SIDheader->SubtuneTimeSources[(32-subtune)>>3] & PowersOf2[(subtune-1)&7];
+ if (C64->TimerSource || C64->IObankWR[0xDC05]!=0x40 || C64->IObankWR[0xDC04]!=0x24) { //CIA1-timing (probably multispeed tune)
+ C64->FrameCycles = ( ( C64->IObankWR[0xDC04] + (C64->IObankWR[0xDC05]<<8) ) ); //<< 4) / C64->ClockRatio;
+ C64->TimerSource = 1; //if init-routine changed DC04 or DC05, assume CIA-timing
+ }
+
+ //determine playaddress:
+ C64->PlayAddress = (SIDheader->PlayAddressH<<8) + SIDheader->PlayAddressL;
+ if (C64->PlayAddress) { //normal play-address called with JSR
+ if (C64->RAMbank[1] == 0x37) { //are there SIDs with routine under IO area?
+ if (0xA000 <= C64->PlayAddress && C64->PlayAddress < 0xC000) C64->RAMbank[1] = 0x36;
+ }
+ else if (C64->PlayAddress >= 0xE000) C64->RAMbank[1] = 0x35; //player under KERNAL (e.g. Crystal Kingdom Dizzy)
+ }
+ else { //IRQ-playaddress for multispeed-tunes set by init-routine (some tunes turn off KERNAL ROM but doesn't set IRQ-vector!)
+ C64->PlayAddress = (C64->RAMbank[1] & 3) < 2 ? cRSID_readMemC64(C64,0xFFFE) + (cRSID_readMemC64(C64,0xFFFF)<<8) //for PSID
+ : cRSID_readMemC64(C64,0x314) + (cRSID_readMemC64(C64,0x315)<<8);
+ if (C64->PlayAddress==0) { //if 0, still try with RSID-mode fallback
+ cRSID_initCPU( &C64->CPU, C64->PlayAddress ); //point CPU to play-routine
+ C64->Finished=1; C64->Returned=1; return;
+ }
+ }
+
+ if (!C64->RealSIDmode) { //prepare (PSID) play-routine playback:
+ cRSID_initCPU( &C64->CPU, C64->PlayAddress ); //point CPU to play-routine
+ C64->FrameCycleCnt=0; C64->Finished=1; C64->SampleCycleCnt=0; //C64->CIAisSet=0;
+ }
+ else { C64->Finished=0; C64->Returned=0; }
+
+}
+
+
+#ifdef CRSID_PLATFORM_PC
+
+
+char cRSID_playSIDfile(cRSID_C64instance* C64, char* filename, char subtune) {
+ static cRSID_SIDheader* SIDheader;
+
+ SIDheader = cRSID_loadSIDtune(C64,filename);
+ if (SIDheader==NULL) return CRSID_ERROR_LOAD;
+
+ cRSID_initSIDtune (C64 , SIDheader , subtune);
+ cRSID_playSIDtune ();
+
+ return CRSID_STATUS_OK;
+}
+
+
+cRSID_SIDheader* cRSID_loadSIDtune(cRSID_C64instance* C64, char* filename) {
+ enum SIDspecs { CRSID_FILESIZE_MAX = 100000 };
+ int FileSize;
+ static unsigned char SIDfileData [CRSID_FILESIZE_MAX]; //use memset?
+
+ FileSize = cRSID_loadSIDfile( SIDfileData, filename, CRSID_FILESIZE_MAX);
+ if ( FileSize == CRSID_ERROR_LOAD ) return NULL;
+
+ return cRSID_processSIDfile ( C64, SIDfileData, FileSize );
+}
+
+
+void cRSID_close() {
+ cRSID_closeSound();
+}
+
+
+void cRSID_playSIDtune (void) {
+ cRSID_startSound();
+}
+
+
+void cRSID_pauseSIDtune (void) {
+ cRSID_stopSound();
+}
+
+
+#endif
+
diff --git a/lib/rbcodec/codecs/cRSID/libcRSID.h b/lib/rbcodec/codecs/cRSID/libcRSID.h
new file mode 100644
index 0000000000..18dadc4a58
--- /dev/null
+++ b/lib/rbcodec/codecs/cRSID/libcRSID.h
@@ -0,0 +1,59 @@
+// cRSID lightweight RealSID (integer-only) library-header (with API-calls) by Hermit (Mihaly Horvath)
+
+#ifndef LIBCRSID_HEADER
+#define LIBCRSID_HEADER //used to prevent double inclusion of this header-file
+
+
+enum cRSID_Specifications { CRSID_SIDCOUNT_MAX=3, CRSID_CIACOUNT=2 };
+enum cRSID_StatusCodes { CRSID_STATUS_OK=0, CRSID_ERROR_INIT=-1, CRSID_ERROR_LOAD=-2 };
+
+
+typedef struct cRSID_SIDheader cRSID_SIDheader;
+typedef struct cRSID_C64instance cRSID_C64instance;
+
+
+extern cRSID_C64instance cRSID_C64; //the only global object (for faster & simpler access than with struct-pointers, in some places)
+
+
+// Main API functions (mainly in libcRSID.c)
+cRSID_C64instance* cRSID_init (unsigned short samplerate, unsigned short buflen); //init emulation objects and sound
+#ifdef CRSID_PLATFORM_PC
+char cRSID_playSIDfile (cRSID_C64instance* C64, char* filename, char subtune); //simple single-call SID playback
+cRSID_SIDheader* cRSID_loadSIDtune (cRSID_C64instance* C64, char* filename); //load and process SID-filedata to C64 memory
+void cRSID_playSIDtune (void); //start/continue playback (enable playing audio-buffer)
+void cRSID_pauseSIDtune (void); //pause playback (enable playing audio-buffer)
+void cRSID_close (void); //close sound etc.
+#endif
+cRSID_SIDheader* cRSID_processSIDfile (cRSID_C64instance* C64, unsigned char* filedata, int filesize); //in host/file.c, copy SID-data to C64 memory
+void cRSID_initSIDtune (cRSID_C64instance* C64, cRSID_SIDheader* SIDheader, char subtune); //init tune/subtune
+signed short cRSID_generateSample (cRSID_C64instance* C64); //in host/audio.c, calculate a single sample
+
+
+struct cRSID_SIDheader { //Offset: default/info:
+ unsigned char MagicString[4]; //$00 - "PSID" or "RSID" (RSID must provide Reset-circumstances & CIA/VIC-interrupts)
+ unsigned char VersionH00; //$04
+ unsigned char Version; //$05 - 1 for PSID v1, 2..4 for PSID v2..4 or RSID v2..4 (3/4 has 2SID/3SID support)
+ unsigned char HeaderSizeH00; //$06
+ unsigned char HeaderSize; //$07 - $76 for v1, $7C for v2..4
+ unsigned char LoadAddressH,LoadAddressL; //$08 - if 0 it's a PRG and its loadaddress is used (RSID: 0, PRG-loadaddress>=$07E8)
+ unsigned char InitAddressH,InitAddressL; //$0A - if 0 it's taken from load-address (but should be set) (RSID: don't point to ROM, 0 if BASICflag set)
+ unsigned char PlayAddressH,PlayAddressL; //$0C - if 0 play-routine-call is set by the initializer (always true for RSID)
+ unsigned char SubtuneAmountH00; //$0E
+ unsigned char SubtuneAmount; //$0F - 1..256
+ unsigned char DefaultSubtuneH00; //$10
+ unsigned char DefaultSubtune; //$11 - 1..256 (optional, defaults to 1)
+ unsigned char SubtuneTimeSources[4]; //$12 - 0:Vsync / 1:CIA1 (for PSID) (LSB is subtune1, MSB above 32) , always 0 for RSID
+ char Title[32]; //$16 - strings are using 1252 codepage
+ char Author[32]; //$36
+ char ReleaseInfo[32]; //$56
+ //SID v2 additions: (if SID2/SID3 model is set to unknown, they're set to the same model as SID1)
+ unsigned char ModelFormatStandardH; //$76 - bit9&8/7&6/5&4: SID3/2/1 model (00:?,01:6581,10:8580,11:both), bit3&2:VideoStandard..
+ unsigned char ModelFormatStandard; //$77 ..(01:PAL,10:NTSC,11:both), bit1:(0:C64,1:PlaySIDsamples/RSID_BASICflag), bit0:(0:builtin-player,1:MUS)
+ unsigned char RelocStartPage; //$78 - v2NG specific, if 0 the SID doesn't write outside its data-range, if $FF there's no place for driver
+ unsigned char RelocFreePages; //$79 - size of area from RelocStartPage for driver-relocation (RSID: must not contain ROM or 0..$3FF)
+ unsigned char SID2baseAddress; //$7A - (SID2BASE-$d000)/16 //SIDv3-relevant, only $42..$FE values are valid ($d420..$DFE0), else no SID2
+ unsigned char SID3baseAddress; //$7B - (SID3BASE-$d000)/16 //SIDv4-relevant, only $42..$FE values are valid ($d420..$DFE0), else no SID3
+}; //music-program follows right after the header
+
+
+#endif //LIBCRSID_HEADER
diff --git a/lib/rbcodec/codecs/codecs.h b/lib/rbcodec/codecs/codecs.h
index 6048e5012c..18416afba8 100644
--- a/lib/rbcodec/codecs/codecs.h
+++ b/lib/rbcodec/codecs/codecs.h
@@ -60,6 +60,10 @@
#ifdef ROCKBOX_HAS_LOGF
#undef LOGF
#define LOGF ci->logf
+#elif defined(LOGF_ENABLE)
+#include "logf.h"
+#undef LOGF
+#define LOGF logf
#else
#define LOGF(...)
#endif
@@ -71,13 +75,12 @@
/* magic for encoder codecs */
#define CODEC_ENC_MAGIC 0x52454E43 /* RENC */
-/* increase this every time the api struct changes */
-#define CODEC_API_VERSION 48
-
-/* update this to latest version if a change to the api struct breaks
- backwards compatibility (and please take the opportunity to sort in any
- new function which are "waiting" at the end of the function table) */
-#define CODEC_MIN_API_VERSION 48
+/*
+ * Increment this whenever a change breaks the codec ABI,
+ * when this happens please take the opportunity to sort in
+ * any new functions "waiting" at the end of the list.
+ */
+#define CODEC_API_VERSION 50
/* reasons for calling codec main entrypoint */
enum codec_entry_call_reason {
@@ -228,6 +231,7 @@ struct codec_header {
enum codec_status(*entry_point)(enum codec_entry_call_reason reason);
enum codec_status(*run_proc)(void);
struct codec_api **api;
+ size_t api_size;
void * rec_extension[]; /* extension for encoders */
};
@@ -241,15 +245,16 @@ extern unsigned char plugin_end_addr[];
const struct codec_header __header \
__attribute__ ((section (".header")))= { \
{ CODEC_MAGIC, TARGET_ID, CODEC_API_VERSION, \
- plugin_start_addr, plugin_end_addr }, codec_start, \
- codec_run, &ci };
+ plugin_start_addr, plugin_end_addr }, \
+ codec_start, codec_run, &ci, sizeof(struct codec_api) };
/* encoders */
#define CODEC_ENC_HEADER \
const struct codec_header __header \
__attribute__ ((section (".header")))= { \
{ CODEC_ENC_MAGIC, TARGET_ID, CODEC_API_VERSION, \
- plugin_start_addr, plugin_end_addr }, codec_start, \
- codec_run, &ci, { enc_callback } };
+ plugin_start_addr, plugin_end_addr }, \
+ codec_start, codec_run, &ci, sizeof(struct codec_api), \
+ { enc_callback } };
#else /* def SIMULATOR */
/* decoders */
@@ -257,13 +262,14 @@ extern unsigned char plugin_end_addr[];
const struct codec_header __header \
__attribute__((visibility("default"))) = { \
{ CODEC_MAGIC, TARGET_ID, CODEC_API_VERSION, NULL, NULL }, \
- codec_start, codec_run, &ci };
+ codec_start, codec_run, &ci, sizeof(struct codec_api) };
/* encoders */
#define CODEC_ENC_HEADER \
const struct codec_header __header \
__attribute__((visibility("default"))) = { \
{ CODEC_ENC_MAGIC, TARGET_ID, CODEC_API_VERSION, NULL, NULL }, \
- codec_start, codec_run, &ci, { enc_callback } };
+ codec_start, codec_run, &ci, sizeof(struct codec_api), \
+ { enc_callback } };
#endif /* SIMULATOR */
#endif /* CODEC */
diff --git a/lib/rbcodec/codecs/codecs.make b/lib/rbcodec/codecs/codecs.make
index 5f3ccb52b8..27ba73ab3c 100644
--- a/lib/rbcodec/codecs/codecs.make
+++ b/lib/rbcodec/codecs/codecs.make
@@ -65,6 +65,9 @@ include $(RBCODECLIB_DIR)/codecs/libgme/libvgm.make
include $(RBCODECLIB_DIR)/codecs/libgme/libkss.make
include $(RBCODECLIB_DIR)/codecs/libgme/libemu2413.make
include $(RBCODECLIB_DIR)/codecs/libopus/libopus.make
+ifneq ($(MEMORYSIZE),2)
+include $(RBCODECLIB_DIR)/codecs/cRSID/cRSID.make
+endif
# set CODECFLAGS per codec lib, since gcc takes the last -Ox and the last
# in a -ffoo -fno-foo pair, there is no need to filter them out
@@ -101,6 +104,7 @@ $(WAVPACKLIB) : CODECFLAGS += -O1
$(WMALIB) : CODECFLAGS += -O2
$(WMAPROLIB) : CODECFLAGS += -O1
$(WMAVOICELIB) : CODECFLAGS += -O1
+$(CRSID) : CODECFLAGS += -O3
# fine-tuning of CODECFLAGS per cpu arch
ifeq ($(ARCH),arch_arm)
@@ -192,6 +196,7 @@ $(CODECDIR)/sgc.codec : $(CODECDIR)/libsgc.a $(CODECDIR)/libemu2413.a
$(CODECDIR)/vgm.codec : $(CODECDIR)/libvgm.a $(CODECDIR)/libemu2413.a
$(CODECDIR)/kss.codec : $(CODECDIR)/libkss.a $(CODECDIR)/libemu2413.a
$(CODECDIR)/opus.codec : $(CODECDIR)/libopus.a $(TLSFLIB)
+$(CODECDIR)/sid.codec : $(CODECDIR)/cRSID.a
$(CODECDIR)/aac_bsf.codec : $(CODECDIR)/libfaad.a
$(CODECS): $(CODEC_LIBS) # this must be last in codec dependency list
diff --git a/lib/rbcodec/codecs/demac/libdemac/udiv32_arm.S b/lib/rbcodec/codecs/demac/libdemac/udiv32_arm.S
index 7b851659bd..1d19160a91 100644
--- a/lib/rbcodec/codecs/demac/libdemac/udiv32_arm.S
+++ b/lib/rbcodec/codecs/demac/libdemac/udiv32_arm.S
@@ -225,7 +225,7 @@ udiv32_arm:
mov \inv, \divisor, lsl \bits
add \neg, pc, \inv, lsr #25
cmp \inv, #1<<31
- ldrhib \inv, [\neg, #.L_udiv_est_table-.-64]
+ ldrbhi \inv, [\neg, #.L_udiv_est_table-.-64]
bls 20f
subs \bits, \bits, #7
rsb \neg, \divisor, #0
diff --git a/lib/rbcodec/codecs/demac/libdemac/vector_math16_armv6.h b/lib/rbcodec/codecs/demac/libdemac/vector_math16_armv6.h
index 8d27331b62..ad5eed60fb 100644
--- a/lib/rbcodec/codecs/demac/libdemac/vector_math16_armv6.h
+++ b/lib/rbcodec/codecs/demac/libdemac/vector_math16_armv6.h
@@ -45,6 +45,7 @@ static inline int32_t vector_sp_add(int16_t* v1, int16_t* f2, int16_t* s2)
#endif
asm volatile (
+ BEGIN_ARM_ASM_SYNTAX_UNIFIED
#if ORDER > 32
"mov %[res], #0 \n"
#endif
@@ -117,7 +118,7 @@ static inline int32_t vector_sp_add(int16_t* v1, int16_t* f2, int16_t* s2)
"smladx %[res], r1, r2, %[res] \n"
#if ORDER > 32
"subs %[cnt], %[cnt], #1 \n"
- "ldmneia %[f2]!, {r2,r4} \n"
+ "ldmiane %[f2]!, {r2,r4} \n"
"sadd16 r0, r0, r7 \n"
"sadd16 r1, r1, r5 \n"
"strd r0, [%[v1]], #8 \n"
@@ -172,8 +173,8 @@ static inline int32_t vector_sp_add(int16_t* v1, int16_t* f2, int16_t* s2)
"smlad %[res], r3, r5, %[res] \n"
#if ORDER > 32
"subs %[cnt], %[cnt], #1 \n"
- "ldrned r4, [%[f2]], #8 \n"
- "ldrned r0, [%[v1], #8] \n"
+ "ldrdne r4, [%[f2]], #8 \n"
+ "ldrdne r0, [%[v1], #8] \n"
"sadd16 r2, r2, r6 \n"
"sadd16 r3, r3, r7 \n"
"strd r2, [%[v1]], #8 \n"
@@ -185,6 +186,7 @@ static inline int32_t vector_sp_add(int16_t* v1, int16_t* f2, int16_t* s2)
#endif
"99: \n"
+ END_ARM_ASM_SYNTAX_UNIFIED
: /* outputs */
#if ORDER > 32
[cnt]"+r"(cnt),
@@ -214,6 +216,7 @@ static inline int32_t vector_sp_sub(int16_t* v1, int16_t* f2, int16_t* s2)
#endif
asm volatile (
+ BEGIN_ARM_ASM_SYNTAX_UNIFIED
#if ORDER > 32
"mov %[res], #0 \n"
#endif
@@ -286,7 +289,7 @@ static inline int32_t vector_sp_sub(int16_t* v1, int16_t* f2, int16_t* s2)
"smladx %[res], r1, r2, %[res] \n"
#if ORDER > 32
"subs %[cnt], %[cnt], #1 \n"
- "ldmneia %[f2]!, {r2,r4} \n"
+ "ldmiane %[f2]!, {r2,r4} \n"
"ssub16 r0, r0, r7 \n"
"ssub16 r1, r1, r5 \n"
"strd r0, [%[v1]], #8 \n"
@@ -341,8 +344,8 @@ static inline int32_t vector_sp_sub(int16_t* v1, int16_t* f2, int16_t* s2)
"smlad %[res], r3, r5, %[res] \n"
#if ORDER > 32
"subs %[cnt], %[cnt], #1 \n"
- "ldrned r4, [%[f2]], #8 \n"
- "ldrned r0, [%[v1], #8] \n"
+ "ldrdne r4, [%[f2]], #8 \n"
+ "ldrdne r0, [%[v1], #8] \n"
"ssub16 r2, r2, r6 \n"
"ssub16 r3, r3, r7 \n"
"strd r2, [%[v1]], #8 \n"
@@ -354,6 +357,7 @@ static inline int32_t vector_sp_sub(int16_t* v1, int16_t* f2, int16_t* s2)
#endif
"99: \n"
+ END_ARM_ASM_SYNTAX_UNIFIED
: /* outputs */
#if ORDER > 32
[cnt]"+r"(cnt),
@@ -381,6 +385,7 @@ static inline int32_t scalarproduct(int16_t* v1, int16_t* v2)
#endif
asm volatile (
+ BEGIN_ARM_ASM_SYNTAX_UNIFIED
#if ORDER > 32
"mov %[res], #0 \n"
#endif
@@ -421,10 +426,10 @@ static inline int32_t scalarproduct(int16_t* v1, int16_t* v2)
"pkhtb r1, r7, r4 \n"
#if ORDER > 32
"subs %[cnt], %[cnt], #1 \n"
- "ldrned r6, [%[v2]], #8 \n"
+ "ldrdne r6, [%[v2]], #8 \n"
"smladx %[res], r2, r1, %[res] \n"
"pkhtb r2, r4, r5 \n"
- "ldrned r0, [%[v1]], #8 \n"
+ "ldrdne r0, [%[v1]], #8 \n"
"smladx %[res], r3, r2, %[res] \n"
"bne 1b \n"
#else
@@ -461,9 +466,9 @@ static inline int32_t scalarproduct(int16_t* v1, int16_t* v2)
"ldrd r4, [%[v2]], #8 \n"
"smlad %[res], r1, r6, %[res] \n"
"subs %[cnt], %[cnt], #1 \n"
- "ldrned r0, [%[v1]], #8 \n"
+ "ldrdne r0, [%[v1]], #8 \n"
"smlad %[res], r2, r7, %[res] \n"
- "ldrned r6, [%[v2]], #8 \n"
+ "ldrdne r6, [%[v2]], #8 \n"
"smlad %[res], r3, r4, %[res] \n"
"bne 1b \n"
#else
@@ -474,6 +479,7 @@ static inline int32_t scalarproduct(int16_t* v1, int16_t* v2)
#endif
"99: \n"
+ END_ARM_ASM_SYNTAX_UNIFIED
: /* outputs */
#if ORDER > 32
[cnt]"+r"(cnt),
diff --git a/lib/rbcodec/codecs/libatrac/atrac3.c b/lib/rbcodec/codecs/libatrac/atrac3.c
index bb52dd4cf0..f0098258b3 100644
--- a/lib/rbcodec/codecs/libatrac/atrac3.c
+++ b/lib/rbcodec/codecs/libatrac/atrac3.c
@@ -1156,8 +1156,8 @@ int atrac3_decode_frame(unsigned long block_align, ATRAC3Context *q,
* Atrac3 initialization
*
* @param rmctx pointer to the RMContext
- */
-int atrac3_decode_init(ATRAC3Context *q, struct mp3entry *id3)
+ */
+int atrac3_decode_init(ATRAC3Context *q, struct mp3entry *id3, uint16_t channels, uint32_t extradata_size)
{
int i;
uint8_t *edata_ptr = (uint8_t*)&id3->id3v2buf;
@@ -1168,14 +1168,14 @@ int atrac3_decode_init(ATRAC3Context *q, struct mp3entry *id3)
/* Take data from the RM container. */
q->sample_rate = id3->frequency;
- q->channels = id3->channels;
+ q->channels = channels;
q->bit_rate = id3->bitrate * 1000;
q->bits_per_frame = id3->bytesperframe * 8;
q->bytes_per_frame = id3->bytesperframe;
/* Take care of the codec-specific extradata. */
- if (id3->extradata_size == 14) {
+ if (extradata_size == 14) {
/* Parse the extradata, WAV format */
DEBUGF("[0-1] %d\n",rm_get_uint16le(&edata_ptr[0])); /* Unknown value always 1 */
q->samples_per_channel = rm_get_uint32le(&edata_ptr[2]);
@@ -1200,7 +1200,7 @@ int atrac3_decode_init(ATRAC3Context *q, struct mp3entry *id3)
return -1;
}
- } else if (id3->extradata_size == 10) {
+ } else if (extradata_size == 10) {
/* Parse the extradata, RM format. */
q->atrac3version = rm_get_uint32be(&edata_ptr[0]);
q->samples_per_frame = rm_get_uint16be(&edata_ptr[4]);
@@ -1239,7 +1239,7 @@ int atrac3_decode_init(ATRAC3Context *q, struct mp3entry *id3)
return -1;
}
- if (id3->channels <= 0 || id3->channels > 2 ) {
+ if (channels <= 0 || channels > 2 ) {
DEBUGF("Channel configuration error!\n");
return -1;
}
diff --git a/lib/rbcodec/codecs/libatrac/atrac3.h b/lib/rbcodec/codecs/libatrac/atrac3.h
index 64086b6411..912924cf6c 100644
--- a/lib/rbcodec/codecs/libatrac/atrac3.h
+++ b/lib/rbcodec/codecs/libatrac/atrac3.h
@@ -107,7 +107,7 @@ typedef struct {
//@}
} ATRAC3Context;
-int atrac3_decode_init(ATRAC3Context *q, struct mp3entry *id3);
+int atrac3_decode_init(ATRAC3Context *q, struct mp3entry *id3, uint16_t channels, uint32_t extradata_size);
int atrac3_decode_frame(unsigned long block_align, ATRAC3Context *q,
int *data_size, const uint8_t *buf, int buf_size);
diff --git a/lib/rbcodec/codecs/libfaad/common.h b/lib/rbcodec/codecs/libfaad/common.h
index c5eaa0aa51..3b45f46ff0 100644
--- a/lib/rbcodec/codecs/libfaad/common.h
+++ b/lib/rbcodec/codecs/libfaad/common.h
@@ -35,22 +35,6 @@ extern "C" {
#include "faad_config.h"
#include "codeclib.h"
-extern struct codec_api* ci;
-
-#if defined(DEBUG) || defined(SIMULATOR)
-#undef DEBUGF
-#define DEBUGF ci->debugf
-#else
-#define DEBUGF(...)
-#endif
-
-#ifdef ROCKBOX_HAS_LOGF
-#undef LOGF
-#define LOGF ci->logf
-#else
-#define LOGF(...)
-#endif
-
#if (CONFIG_CPU == MCF5250)
/* Enough IRAM but performance suffers with ICODE_ATTR. */
#define IBSS_ATTR_FAAD_LARGE_IRAM IBSS_ATTR
@@ -82,7 +66,7 @@ extern struct codec_api* ci;
#endif
/* Used to allocate several SBR + PS arrays and variables statically. */
-//#define FAAD_STATIC_ALLOC
+#define FAAD_STATIC_ALLOC
#define INLINE __inline
#if 0 //defined(_WIN32) && !defined(_WIN32_WCE)
@@ -151,9 +135,11 @@ extern struct codec_api* ci;
#undef ERROR_RESILIENCE
#endif
-#if CODEC_SIZE >= 0x80000
+#ifdef CODEC_AAC_SBR_DEC
#define SBR_DEC
//#define SBR_LOW_POWER /* Does not work yet in rockbox. */
+#endif
+#if CODEC_SIZE >= 0x80000
#define PS_DEC
#endif
diff --git a/lib/rbcodec/codecs/libfaad/decoder.c b/lib/rbcodec/codecs/libfaad/decoder.c
index d68d093b0b..533de50d5b 100644
--- a/lib/rbcodec/codecs/libfaad/decoder.c
+++ b/lib/rbcodec/codecs/libfaad/decoder.c
@@ -247,6 +247,7 @@ int32_t NEAACDECAPI NeAACDecInit(NeAACDecHandle hDecoder, uint8_t *buffer,
if ((hDecoder == NULL) || (samplerate == NULL) || (channels == NULL))
return -1;
+ adts.old_format = hDecoder->config.useOldADTSFormat;
hDecoder->sf_index = get_sr_index(hDecoder->config.defSampleRate);
hDecoder->object_type = hDecoder->config.defObjectType;
*samplerate = get_sample_rate(hDecoder->sf_index);
@@ -277,12 +278,9 @@ int32_t NEAACDECAPI NeAACDecInit(NeAACDecHandle hDecoder, uint8_t *buffer,
bits = bit2byte(faad_get_processed_bits(&ld));
/* Check if an ADTS header is present */
- } else if (faad_showbits(&ld, 12) == 0xfff) {
+ } else if (adts_frame(&adts, &ld) == 0) {
hDecoder->adts_header_present = 1;
- adts.old_format = hDecoder->config.useOldADTSFormat;
- adts_frame(&adts, &ld);
-
hDecoder->sf_index = adts.sf_index;
hDecoder->object_type = adts.profile + 1;
diff --git a/lib/rbcodec/codecs/libfaad/specrec.c b/lib/rbcodec/codecs/libfaad/specrec.c
index 200239bddc..02deb298b9 100644
--- a/lib/rbcodec/codecs/libfaad/specrec.c
+++ b/lib/rbcodec/codecs/libfaad/specrec.c
@@ -850,9 +850,13 @@ uint8_t reconstruct_single_channel(NeAACDecHandle hDecoder, ic_stream *ics,
#if (defined(PS_DEC) || defined(DRM_PS))
if ((hDecoder->ps_used[hDecoder->fr_ch_ele] == 0))
{
- uint8_t ele = hDecoder->fr_ch_ele;
uint8_t ch = sce->channel;
- uint16_t frame_size = (hDecoder->sbr_alloced[ele]) ? 2 : 1;
+ uint16_t frame_size =
+#ifdef SBR_DEC
+ (hDecoder->sbr_alloced[hDecoder->fr_ch_ele]) ? 2 : 1;
+#else
+ 1;
+#endif
frame_size *= hDecoder->frameLength*sizeof(real_t);
memcpy(hDecoder->time_out[ch+1], hDecoder->time_out[ch], frame_size);
diff --git a/lib/rbcodec/codecs/libffmpegFLAC/decoder.c b/lib/rbcodec/codecs/libffmpegFLAC/decoder.c
index 5e6aab36f4..1b091dbf83 100644
--- a/lib/rbcodec/codecs/libffmpegFLAC/decoder.c
+++ b/lib/rbcodec/codecs/libffmpegFLAC/decoder.c
@@ -182,8 +182,8 @@ static int decode_residuals(FLACContext *s, int32_t *decoded, int pred_order)
return 0;
}
-static int decode_subframe_fixed(FLACContext *s, int32_t* decoded, int pred_order, int bps) ICODE_ATTR_FLAC;
-static int decode_subframe_fixed(FLACContext *s, int32_t* decoded, int pred_order, int bps)
+//static int decode_subframe_fixed(FLACContext *s, int32_t* decoded, int pred_order, int bps) ICODE_ATTR_FLAC;
+int decode_subframe_fixed(FLACContext *s, int32_t* decoded, int pred_order, int bps)
{
const int blocksize = s->blocksize;
unsigned a, b, c, d;
@@ -198,28 +198,33 @@ static int decode_subframe_fixed(FLACContext *s, int32_t* decoded, int pred_orde
if (decode_residuals(s, decoded, pred_order) < 0)
return -4;
- a = decoded[pred_order-1];
- b = a - decoded[pred_order-2];
- c = b - decoded[pred_order-2] + decoded[pred_order-3];
- d = c - decoded[pred_order-2] + 2U*decoded[pred_order-3] - decoded[pred_order-4];
-
switch(pred_order)
{
case 0:
break;
case 1:
+ a = decoded[pred_order-1];
for (i = pred_order; i < blocksize; i++)
decoded[i] = a += decoded[i];
break;
case 2:
+ a = decoded[pred_order-1];
+ b = a - decoded[pred_order-2];
for (i = pred_order; i < blocksize; i++)
decoded[i] = a += b += decoded[i];
break;
case 3:
+ a = decoded[pred_order-1];
+ b = a - decoded[pred_order-2];
+ c = b - decoded[pred_order-2] + decoded[pred_order-3];
for (i = pred_order; i < blocksize; i++)
decoded[i] = a += b += c += decoded[i];
break;
case 4:
+ a = decoded[pred_order-1];
+ b = a - decoded[pred_order-2];
+ c = b - decoded[pred_order-2] + decoded[pred_order-3];
+ d = c - decoded[pred_order-2] + 2U*decoded[pred_order-3] - decoded[pred_order-4];
for (i = pred_order; i < blocksize; i++)
decoded[i] = a += b += c += d += decoded[i];
break;
diff --git a/lib/rbcodec/codecs/libgme/blip_buffer.c b/lib/rbcodec/codecs/libgme/blip_buffer.c
index ba0a6558d2..9aaa9d2482 100644
--- a/lib/rbcodec/codecs/libgme/blip_buffer.c
+++ b/lib/rbcodec/codecs/libgme/blip_buffer.c
@@ -53,7 +53,9 @@ void Blip_clear( struct Blip_Buffer* this )
this->reader_accum_ = 0;
this->modified = false;
+#if 0 // this is redundant as buffer is static and triggers -Waddress
if ( this->buffer_ )
+#endif
{
int count = (entire_buffer ? this->buffer_size_ : Blip_samples_avail( this ));
memset( this->buffer_, 0, (count + blip_buffer_extra_) * sizeof (delta_t) );
diff --git a/lib/rbcodec/codecs/libm4a/demux.c b/lib/rbcodec/codecs/libm4a/demux.c
index 3bf46efec6..2b56759b9c 100644
--- a/lib/rbcodec/codecs/libm4a/demux.c
+++ b/lib/rbcodec/codecs/libm4a/demux.c
@@ -29,6 +29,8 @@
*
*/
+//#define DEBUG
+
#include <string.h>
#include <inttypes.h>
#include <stdlib.h>
@@ -54,22 +56,13 @@ typedef struct
/* chunk handlers */
static void read_chunk_ftyp(qtmovie_t *qtmovie, size_t chunk_len)
{
- fourcc_t type;
size_t size_remaining = chunk_len - 8;
- type = stream_read_uint32(qtmovie->stream);
+ // filetype (supported ignore case values: m4a, m4b, mp42, 3gp6, qt, isom)
+ char filetype[4];
+ stream_read(qtmovie->stream, 4, filetype);
size_remaining-=4;
- if ((type != MAKEFOURCC('M','4','A',' ')) &&
- (type != MAKEFOURCC('m','4','a',' ')) &&
- (type != MAKEFOURCC('M','4','B',' ')) &&
- (type != MAKEFOURCC('m','p','4','2')) &&
- (type != MAKEFOURCC('3','g','p','6')) &&
- (type != MAKEFOURCC('q','t',' ',' ')) &&
- (type != MAKEFOURCC('i','s','o','m')))
- {
- DEBUGF("not M4A file\n");
- return;
- }
+
/* minor_ver = */ stream_read_uint32(qtmovie->stream);
size_remaining-=4;
@@ -349,6 +342,7 @@ static bool read_chunk_stts(qtmovie_t *qtmovie, size_t chunk_len)
static bool read_chunk_stsz(qtmovie_t *qtmovie, size_t chunk_len)
{
size_t size_remaining = chunk_len - 8;
+ uint32_t numsizes, i;
/* version */
stream_read_uint8(qtmovie->stream);
@@ -369,9 +363,38 @@ static bool read_chunk_stsz(qtmovie_t *qtmovie, size_t chunk_len)
}
size_remaining -= 4;
- qtmovie->res->num_sample_byte_sizes = stream_read_uint32(qtmovie->stream);
+ numsizes = stream_read_uint32(qtmovie->stream);
size_remaining -= 4;
+ /* Because this table can be really large and is only used to improve seek
+ * accuracy, it's optional. In that case the seek code will fall back to a
+ * less accurate seek method. */
+ qtmovie->res->num_sample_byte_sizes = numsizes;
+ if (numsizes * sizeof(uint32_t) < CODEC_SIZE * 1 / 2)
+ qtmovie->res->sample_byte_sizes = malloc(numsizes * sizeof(uint32_t));
+ else
+ qtmovie->res->sample_byte_sizes = NULL;
+
+ if (qtmovie->res->sample_byte_sizes)
+ {
+ for (i = 0; i < numsizes; ++i)
+ {
+ qtmovie->res->sample_byte_sizes[i] =
+ stream_read_uint32(qtmovie->stream);
+ size_remaining -= 4;
+ }
+
+ if (size_remaining)
+ {
+ DEBUGF("extra bytes after stsz\n");
+ }
+ }
+ else
+ {
+ qtmovie->res->sample_byte_sizes_offset = stream_tell(qtmovie->stream);
+ DEBUGF("stsz too large: %u, save sample_byte_sizes_offset\n", numsizes);
+ }
+
if (size_remaining)
{
stream_skip(qtmovie->stream, size_remaining);
@@ -382,7 +405,6 @@ static bool read_chunk_stsz(qtmovie_t *qtmovie, size_t chunk_len)
static bool read_chunk_stsc(qtmovie_t *qtmovie, size_t chunk_len)
{
- unsigned int i;
uint32_t numentries;
size_t size_remaining = chunk_len - 8;
@@ -394,43 +416,29 @@ static bool read_chunk_stsc(qtmovie_t *qtmovie, size_t chunk_len)
size_remaining -= 4;
qtmovie->res->num_sample_to_chunks = numentries;
- qtmovie->res->sample_to_chunk = malloc(numentries * sizeof(sample_to_chunk_t));
-
- if (!qtmovie->res->sample_to_chunk)
- {
- DEBUGF("stsc too large\n");
- return false;
- }
-
- for (i = 0; i < numentries; i++)
- {
- qtmovie->res->sample_to_chunk[i].first_chunk =
- stream_read_uint32(qtmovie->stream);
- qtmovie->res->sample_to_chunk[i].num_samples =
- stream_read_uint32(qtmovie->stream);
- stream_read_uint32(qtmovie->stream);
- size_remaining -= 12;
- }
-
+ qtmovie->res->sample_to_chunk_offset = stream_tell(qtmovie->stream);
if (size_remaining)
{
- DEBUGF("ehm, size remianing?\n");
stream_skip(qtmovie->stream, size_remaining);
}
return true;
}
+static void stream_read_sample_to_chunk(stream_t *stream, uint32_t *first_chunk, uint32_t *num_samples)
+{
+ (*first_chunk) = stream_read_uint32(stream);
+ (*num_samples) = stream_read_uint32(stream);
+ stream_skip(stream, 4);
+}
+
static bool read_chunk_stco(qtmovie_t *qtmovie, size_t chunk_len)
{
uint32_t i, k, old_i;
uint32_t numentries;
- uint32_t idx = 0;
uint32_t frame;
- uint32_t offset;
- uint32_t old_first;
- uint32_t new_first;
- uint32_t old_frame;
+ uint32_t old_first, new_first;
+ uint32_t old_frame, new_frame;
size_t size_remaining = chunk_len - 8;
/* version + flags */
@@ -439,9 +447,25 @@ static bool read_chunk_stco(qtmovie_t *qtmovie, size_t chunk_len)
numentries = stream_read_uint32(qtmovie->stream);
size_remaining -= 4;
-
- qtmovie->res->num_lookup_table = numentries;
- qtmovie->res->lookup_table = malloc(numentries * sizeof(*qtmovie->res->lookup_table));
+
+ uint8_t accuracy_divider = 1;
+ uint32_t fit_numentries = numentries;
+ while (true)
+ {
+ qtmovie->res->lookup_table = malloc(fit_numentries * sizeof(*qtmovie->res->lookup_table));
+
+ if (qtmovie->res->lookup_table || (++accuracy_divider == 0))
+ {
+ break;
+ }
+ else
+ {
+ // we failed to alloc memory for lookup table, so reduce seek accuracy and try again
+ fit_numentries = numentries / accuracy_divider;
+ }
+ }
+ DEBUGF("lookup_table numentries %d, fit_numentries %d\n", numentries, fit_numentries);
+ qtmovie->res->num_lookup_table = fit_numentries;
if (!qtmovie->res->lookup_table)
{
@@ -449,10 +473,14 @@ static bool read_chunk_stco(qtmovie_t *qtmovie, size_t chunk_len)
return false;
}
- /* read first offset */
- offset = stream_read_uint32(qtmovie->stream);
- size_remaining -= 4;
-
+ // Reading sample_byte_sizes data on seek can lead to additional re-buffering.
+ // So skip it if we have good enough seek accuracy via lookup_table (3000 ms)
+ if (qtmovie->res->sample_byte_sizes_offset && ci->id3->length / fit_numentries <= 3000)
+ {
+ qtmovie->res->sample_byte_sizes_offset = 0;
+ DEBUGF("lookup_table seek accuracy %ld ms, ignoring sample_byte_sizes_offset \n", ci->id3->length / fit_numentries);
+ }
+
/* Build up lookup table. The lookup table contains the sample index and
* byte position in the file for each chunk. This table is used to seek
* and resume (see m4a_seek() and m4a_seek_raw() in libm4a/m4a.c) and
@@ -464,22 +492,39 @@ static bool read_chunk_stco(qtmovie_t *qtmovie, size_t chunk_len)
* accepted to be able to avoid allocation of the large sample_byte_size[]
* table. This reduces the memory consumption by a factor of 2 or even
* more. */
+ uint32_t idx = 0;
+ for (i = 0; i < numentries; ++i)
+ {
+ if (i % accuracy_divider == 0)
+ {
+ qtmovie->res->lookup_table[idx++].offset = stream_read_uint32(qtmovie->stream);
+ }
+ else
+ {
+ stream_skip(qtmovie->stream, 4);
+ }
+ size_remaining -= 4;
+ }
+
+ idx = 0;
i = 1;
old_i = 1;
frame = 0;
- old_first = qtmovie->res->sample_to_chunk[0].first_chunk;
- old_frame = qtmovie->res->sample_to_chunk[0].num_samples;
- new_first = qtmovie->res->sample_to_chunk[1].first_chunk;
- for (k = 1; k < numentries; ++k)
+
+ int32_t current_offset = stream_tell(qtmovie->stream);
+ stream_seek(qtmovie->stream, qtmovie->res->sample_to_chunk_offset);
+ stream_read_sample_to_chunk(qtmovie->stream, &old_first, &old_frame);
+ stream_read_sample_to_chunk(qtmovie->stream, &new_first, &new_frame);
+ for (k = 1; k < numentries + 1; ++k)
{
for (; i < qtmovie->res->num_sample_to_chunks; ++i)
{
if (i > old_i)
{
/* Only access sample_to_chunk[] if new data is required. */
- old_first = qtmovie->res->sample_to_chunk[i-1].first_chunk;
- old_frame = qtmovie->res->sample_to_chunk[i-1].num_samples;
- new_first = qtmovie->res->sample_to_chunk[i ].first_chunk;
+ old_first = new_first;
+ old_frame = new_frame;
+ stream_read_sample_to_chunk(qtmovie->stream, &new_first, &new_frame);
old_i = i;
}
@@ -488,21 +533,19 @@ static bool read_chunk_stco(qtmovie_t *qtmovie, size_t chunk_len)
frame += (new_first - old_first) * old_frame;
}
- frame += (k - old_first) * old_frame;
-
- qtmovie->res->lookup_table[idx].sample = frame;
- qtmovie->res->lookup_table[idx].offset = offset;
- idx++;
-
- frame -= (k - old_first) * old_frame;
-
- offset = stream_read_uint32(qtmovie->stream);
- size_remaining -= 4;
+
+ if ((k-1) % accuracy_divider == 0)
+ {
+ qtmovie->res->lookup_table[idx++].sample = frame + (k - old_first) * old_frame;
+ }
+ }
+ /* zero-terminate sample if it wasn't calculated */
+ if (idx < fit_numentries)
+ {
+ qtmovie->res->lookup_table[idx].sample = 0;
}
- /* zero-terminate the lookup table */
- qtmovie->res->lookup_table[idx].sample = 0;
- qtmovie->res->lookup_table[idx].offset = 0;
+ stream_seek(qtmovie->stream, current_offset);
if (size_remaining)
{
DEBUGF("ehm, size remianing?\n");
@@ -816,7 +859,8 @@ int qtmovie_read(stream_t *file, demux_res_t *demux_res)
break;
default:
//DEBUGF("(top) unknown chunk id: %c%c%c%c\n",SPLITFOURCC(chunk_id));
- return 0;
+ stream_skip(qtmovie.stream, chunk_len - 8);
+ break;
}
}
diff --git a/lib/rbcodec/codecs/libm4a/m4a.c b/lib/rbcodec/codecs/libm4a/m4a.c
index 5fe778ac03..ecae2ad633 100644
--- a/lib/rbcodec/codecs/libm4a/m4a.c
+++ b/lib/rbcodec/codecs/libm4a/m4a.c
@@ -23,6 +23,13 @@
#include <inttypes.h>
#include "m4a.h"
+#undef DEBUGF
+#if defined(DEBUG)
+#define DEBUGF stream->ci->debugf
+#else
+#define DEBUGF(...)
+#endif
+
/* Implementation of the stream.h functions used by libalac */
#define _Swap32(v) do { \
@@ -107,96 +114,145 @@ void stream_create(stream_t *stream,struct codec_api* ci)
/* Check if there is a dedicated byte position contained for the given frame.
* Return this byte position in case of success or return -1. This allows to
- * skip empty samples.
- * During standard playback the search result (index i) will always increase.
+ * skip empty samples.
+ * During standard playback the search result (index i) will always increase.
* Therefor we save this index and let the caller set this value again as start
- * index when calling m4a_check_sample_offset() for the next frame. This
+ * index when calling m4a_check_sample_offset() for the next frame. This
* reduces the overall loop count significantly. */
int m4a_check_sample_offset(demux_res_t *demux_res, uint32_t frame, uint32_t *start)
{
uint32_t i = *start;
- for (i=0; i<demux_res->num_lookup_table; ++i)
+ for (;i < demux_res->num_lookup_table; ++i)
{
- if (demux_res->lookup_table[i].sample > frame ||
- demux_res->lookup_table[i].offset == 0)
- return -1;
- if (demux_res->lookup_table[i].sample == frame)
+ if (demux_res->lookup_table[i].sample > frame)
break;
+
+ if (demux_res->lookup_table[i].sample == frame)
+ {
+ *start = i;
+ return demux_res->lookup_table[i].offset;
+ }
}
*start = i;
- return demux_res->lookup_table[i].offset;
+ return -1;
}
-/* Find the exact or preceding frame in lookup_table[]. Return both frame
- * and byte position of this match. */
-static void gather_offset(demux_res_t *demux_res, uint32_t *frame, uint32_t *offset)
+/* Seek to desired sound sample location. Return 1 on success (and modify
+ * sound_samples_done and current_sample), 0 if failed. */
+unsigned int m4a_seek(demux_res_t* demux_res, stream_t* stream,
+ uint64_t sound_sample_loc, uint64_t* sound_samples_done,
+ uint32_t* current_sample, uint32_t* lookup_table_idx)
{
- uint32_t i = 0;
- for (i=0; i<demux_res->num_lookup_table; ++i)
+ uint32_t i, sample_i;
+ uint32_t time, time_cnt, time_dur;
+ uint32_t chunk, chunk_first_sample;
+ uint32_t offset;
+ uint64_t sound_sample_i;
+ time_to_sample_t *tts_tab = demux_res->time_to_sample;
+ sample_offset_t *tco_tab = demux_res->lookup_table;
+ uint32_t *tsz_tab = demux_res->sample_byte_sizes;
+
+ /* First check we have the required metadata - we should always have it. */
+ if (!demux_res->num_time_to_samples || !demux_res->num_sample_byte_sizes)
{
- if (demux_res->lookup_table[i].offset == 0)
- break;
- if (demux_res->lookup_table[i].sample > *frame)
+ return 0;
+ }
+
+ /* The 'sound_sample_loc' we have is PCM-based and not directly usable.
+ * We need to convert it to an MP4 sample number 'sample_i' first. */
+ sample_i = sound_sample_i = 0;
+ for (time = 0; time < demux_res->num_time_to_samples; ++time)
+ {
+ time_cnt = tts_tab[time].sample_count;
+ time_dur = tts_tab[time].sample_duration;
+ uint32_t time_var = time_cnt * time_dur;
+
+ if (sound_sample_loc < sound_sample_i + time_var)
+ {
+ time_var = sound_sample_loc - sound_sample_i;
+ sample_i += time_var / time_dur;
break;
+ }
+
+ sample_i += time_cnt;
+ sound_sample_i += time_var;
}
- i = (i>0) ? i-1 : 0; /* We want the last chunk _before_ *frame. */
- *frame = demux_res->lookup_table[i].sample;
- *offset = demux_res->lookup_table[i].offset;
-}
-/* Seek to desired sound sample location. Return 1 on success (and modify
- * sound_samples_done and current_sample), 0 if failed.
- *
- * Find the sample (=frame) that contains the given sound sample, find a best
- * fit for this sample in the lookup_table[], seek to the byte position. */
-unsigned int m4a_seek(demux_res_t* demux_res, stream_t* stream,
- uint32_t sound_sample_loc, uint32_t* sound_samples_done,
- int* current_sample)
-{
- uint32_t i = 0;
- uint32_t tmp_var, tmp_cnt, tmp_dur;
- uint32_t new_sample = 0; /* Holds the amount of chunks/frames. */
- uint32_t new_sound_sample = 0; /* Sums up total amount of samples. */
- uint32_t new_pos; /* Holds the desired chunk/frame index. */
-
- /* First check we have the appropriate metadata - we should always
- * have it.
- */
- if (!demux_res->num_time_to_samples || !demux_res->num_sample_byte_sizes)
- {
- return 0;
+ /* Find the chunk after 'sample_i'. */
+ for (chunk = 1; chunk < demux_res->num_lookup_table; ++chunk)
+ {
+ if (tco_tab[chunk].sample > sample_i)
+ break;
}
- /* Find the destination block from time_to_sample array */
- time_to_sample_t *tab = demux_res->time_to_sample;
- while (i < demux_res->num_time_to_samples)
+ /* The preceding chunk is the one that contains 'sample_i'. */
+ chunk--;
+ *lookup_table_idx = chunk;
+ chunk_first_sample = tco_tab[chunk].sample;
+ offset = tco_tab[chunk].offset;
+
+ /* Compute the PCM sample number of the chunk's first sample
+ * to get an accurate base for sound_sample_i. */
+ i = sound_sample_i = 0;
+ for (time = 0; time < demux_res->num_time_to_samples; ++time)
{
- tmp_cnt = tab[i].sample_count;
- tmp_dur = tab[i].sample_duration;
- tmp_var = tmp_cnt * tmp_dur;
- if (sound_sample_loc <= new_sound_sample + tmp_var)
+ time_cnt = tts_tab[time].sample_count;
+ time_dur = tts_tab[time].sample_duration;
+
+ if (chunk_first_sample < i + time_cnt)
{
- tmp_var = (sound_sample_loc - new_sound_sample);
- new_sample += tmp_var / tmp_dur;
- new_sound_sample += tmp_var;
+ sound_sample_i += (chunk_first_sample - i) * time_dur;
break;
}
- new_sample += tmp_cnt;
- new_sound_sample += tmp_var;
- ++i;
+
+ i += time_cnt;
+ sound_sample_i += time_cnt * time_dur;
}
- /* We know the new sample (=frame), now calculate the file position. */
- gather_offset(demux_res, &new_sample, &new_pos);
+ if (demux_res->sample_byte_sizes_offset)
+ {
+ stream->ci->seek_buffer(demux_res->sample_byte_sizes_offset + chunk_first_sample * 4);
+ }
- /* We know the new file position, so let's try to seek to it */
- if (stream->ci->seek_buffer(new_pos))
+ if (tsz_tab || demux_res->sample_byte_sizes_offset)
{
- *sound_samples_done = new_sound_sample;
- *current_sample = new_sample;
+ /* We have a sample-to-bytes table available so we can do accurate
+ * seeking. Move one sample at a time and update the file offset and
+ * PCM sample offset as we go. */
+ for (i = chunk_first_sample;
+ i < sample_i && i < demux_res->num_sample_byte_sizes; ++i)
+ {
+ /* this could be unnecessary */
+ if (time_cnt == 0 && ++time < demux_res->num_time_to_samples)
+ {
+ time_cnt = tts_tab[time].sample_count;
+ time_dur = tts_tab[time].sample_duration;
+ }
+
+ offset += tsz_tab ? tsz_tab[i] : stream_read_uint32(stream);
+ sound_sample_i += time_dur;
+ time_cnt--;
+ }
+ } else {
+ /* No sample-to-bytes table available so we can only seek to the
+ * start of a chunk, which is often much lower resolution. */
+ sample_i = chunk_first_sample;
+ }
+
+ DEBUGF("seek chunk=%lu, chunk_first_sample=%lu, sample_i=%u, soundsample=%lu, offset=%lu\n",
+ (unsigned long)chunk,
+ (unsigned long)chunk_first_sample,
+ sample_i,
+ (unsigned long)sound_sample_i,
+ (unsigned long)offset);
+
+ if (stream->ci->seek_buffer(offset))
+ {
+ *sound_samples_done = sound_sample_i;
+ *current_sample = sample_i;
return 1;
}
-
+
return 0;
}
@@ -208,7 +264,7 @@ unsigned int m4a_seek(demux_res_t* demux_res, stream_t* stream,
* 1) the lookup_table array contains the file offset for the first sample
* of each chunk.
*
- * 2) the time_to_sample array contains the duration (in sound samples)
+ * 2) the time_to_sample array contains the duration (in sound samples)
* of each sample of data.
*
* Locate the chunk containing location (using lookup_table), find the first
@@ -216,28 +272,29 @@ unsigned int m4a_seek(demux_res_t* demux_res, stream_t* stream,
* calculate the sound_samples_done value.
*/
unsigned int m4a_seek_raw(demux_res_t* demux_res, stream_t* stream,
- uint32_t file_loc, uint32_t* sound_samples_done,
- int* current_sample)
+ uint32_t file_loc, uint64_t* sound_samples_done,
+ uint32_t* current_sample, uint32_t* lookup_table_idx)
{
uint32_t i;
uint32_t chunk_sample = 0;
uint32_t total_samples = 0;
- uint32_t new_sound_sample = 0;
+ uint64_t new_sound_sample = 0;
uint32_t tmp_dur;
uint32_t tmp_cnt;
uint32_t new_pos;
- /* We know the desired byte offset, search for the chunk right before.
+ /* We know the desired byte offset, search for the chunk right before.
* Return the associated sample to this chunk as chunk_sample. */
- for (i=0; i < demux_res->num_lookup_table; ++i)
+ for (i = 1; i < demux_res->num_lookup_table; ++i)
{
if (demux_res->lookup_table[i].offset > file_loc)
break;
}
- i = (i>0) ? i-1 : 0; /* We want the last chunk _before_ file_loc. */
+ --i; /* We want the last chunk _before_ file_loc. */
+ *lookup_table_idx = i;
chunk_sample = demux_res->lookup_table[i].sample;
new_pos = demux_res->lookup_table[i].offset;
-
+
/* Get sound sample offset. */
i = 0;
time_to_sample_t *tab2 = demux_res->time_to_sample;
@@ -249,19 +306,19 @@ unsigned int m4a_seek_raw(demux_res_t* demux_res, stream_t* stream,
new_sound_sample += tmp_cnt * tmp_dur;
if (chunk_sample <= total_samples)
{
- new_sound_sample += (chunk_sample - total_samples) * tmp_dur;
+ new_sound_sample -= (total_samples - chunk_sample) * tmp_dur;
break;
}
++i;
}
/* Go to the new file position. */
- if (stream->ci->seek_buffer(new_pos))
+ if (stream->ci->seek_buffer(new_pos))
{
*sound_samples_done = new_sound_sample;
*current_sample = chunk_sample;
return 1;
- }
+ }
return 0;
}
diff --git a/lib/rbcodec/codecs/libm4a/m4a.h b/lib/rbcodec/codecs/libm4a/m4a.h
index aa8e768045..14b22f5dbf 100644
--- a/lib/rbcodec/codecs/libm4a/m4a.h
+++ b/lib/rbcodec/codecs/libm4a/m4a.h
@@ -45,13 +45,13 @@ typedef struct {
typedef uint32_t fourcc_t;
-typedef struct
+typedef struct
{
uint32_t first_chunk;
uint32_t num_samples;
} sample_to_chunk_t;
-typedef struct
+typedef struct
{
uint32_t sample_count;
uint32_t sample_duration;
@@ -71,16 +71,18 @@ typedef struct
fourcc_t format;
void *buf;
- sample_to_chunk_t *sample_to_chunk;
+ int32_t sample_to_chunk_offset;
uint32_t num_sample_to_chunks;
-
+
sample_offset_t *lookup_table;
uint32_t num_lookup_table;
-
+
time_to_sample_t *time_to_sample;
uint32_t num_time_to_samples;
+ uint32_t *sample_byte_sizes;
uint32_t num_sample_byte_sizes;
+ int32_t sample_byte_sizes_offset;
uint32_t codecdata_len;
uint8_t codecdata[MAX_CODECDATA_SIZE];
@@ -129,10 +131,10 @@ int stream_eof(stream_t *stream);
void stream_create(stream_t *stream,struct codec_api* ci);
unsigned int get_sample_offset(demux_res_t *demux_res, uint32_t sample);
unsigned int m4a_seek (demux_res_t* demux_res, stream_t* stream,
- uint32_t sound_sample_loc, uint32_t* sound_samples_done,
- int* current_sample);
+ uint64_t sound_sample_loc, uint64_t* sound_samples_done,
+ uint32_t* current_sample, uint32_t* lookup_table_idx);
unsigned int m4a_seek_raw (demux_res_t* demux_res, stream_t* stream,
- uint32_t file_loc, uint32_t* sound_samples_done, int* current_sample);
+ uint32_t file_loc, uint64_t* sound_samples_done, uint32_t* current_sample, uint32_t* lookup_table_idx);
int m4a_check_sample_offset(demux_res_t *demux_res, uint32_t frame, uint32_t *start);
#endif /* STREAM_H */
diff --git a/lib/rbcodec/codecs/libmusepack/mpc_decoder.c b/lib/rbcodec/codecs/libmusepack/mpc_decoder.c
index 3bfc4cc7fc..f0cb75e5d2 100644
--- a/lib/rbcodec/codecs/libmusepack/mpc_decoder.c
+++ b/lib/rbcodec/codecs/libmusepack/mpc_decoder.c
@@ -56,7 +56,7 @@ extern const mpc_can_data mpc_can_Bands;
extern const mpc_can_data mpc_can_SCFI[2];
extern const mpc_can_data mpc_can_DSCF[2];
extern const mpc_can_data mpc_can_Res [2];
-extern const mpc_can_data mpc_can_Q [8][2];
+extern const mpc_can_data mpc_can_Q [6][2];
extern const mpc_can_data mpc_can_Q1;
extern const mpc_can_data mpc_can_Q9up;
diff --git a/lib/rbcodec/codecs/libopus/ogg/framing.c b/lib/rbcodec/codecs/libopus/ogg/framing.c
index a7032a6a35..eb32351590 100644
--- a/lib/rbcodec/codecs/libopus/ogg/framing.c
+++ b/lib/rbcodec/codecs/libopus/ogg/framing.c
@@ -235,8 +235,9 @@ static int _os_lacing_expand(ogg_stream_state *os,long needed){
perform the checksum simultaneously with other copies */
static ogg_uint32_t _os_update_crc(ogg_uint32_t crc, unsigned char *buffer, int size){
+ #define u32(v) (uint32_t)v
while (size>=8){
- crc^=buffer[0]<<24|buffer[1]<<16|buffer[2]<<8|buffer[3];
+ crc^=((u32(buffer[0]))<<24)|((u32(buffer[1]))<<16)|((u32(buffer[2]))<<8)|(u32(buffer[3]));
crc=crc_lookup[7][ crc>>24 ]^crc_lookup[6][(crc>>16)&0xFF]^
crc_lookup[5][(crc>> 8)&0xFF]^crc_lookup[4][ crc &0xFF]^
@@ -246,7 +247,7 @@ static ogg_uint32_t _os_update_crc(ogg_uint32_t crc, unsigned char *buffer, int
buffer+=8;
size-=8;
}
-
+ #undef u32
while (size--)
crc=(crc<<8)^crc_lookup[0][((crc >> 24)&0xff)^*buffer++];
return crc;
diff --git a/lib/rbcodec/codecs/libopus/silk/NLSF2A.c b/lib/rbcodec/codecs/libopus/silk/NLSF2A.c
index d5b7730638..8f472f25f7 100644
--- a/lib/rbcodec/codecs/libopus/silk/NLSF2A.c
+++ b/lib/rbcodec/codecs/libopus/silk/NLSF2A.c
@@ -80,7 +80,7 @@ void silk_NLSF2A(
};
const unsigned char *ordering;
opus_int k, i, dd;
- opus_int32 cos_LSF_QA[ SILK_MAX_ORDER_LPC ];
+ opus_int32 cos_LSF_QA[ SILK_MAX_ORDER_LPC ] = {0};
opus_int32 P[ SILK_MAX_ORDER_LPC / 2 + 1 ], Q[ SILK_MAX_ORDER_LPC / 2 + 1 ];
opus_int32 Ptmp, Qtmp, f_int, f_frac, cos_val, delta;
opus_int32 a32_QA1[ SILK_MAX_ORDER_LPC ];
diff --git a/lib/rbcodec/codecs/libtta/filter_arm.S b/lib/rbcodec/codecs/libtta/filter_arm.S
index f3959b83ca..10f1491796 100644
--- a/lib/rbcodec/codecs/libtta/filter_arm.S
+++ b/lib/rbcodec/codecs/libtta/filter_arm.S
@@ -165,8 +165,8 @@ hybrid_filter:
sub r10, r11, r10
@ set to the memory: *pA, *(pA-1), *(pA-2), *(pA-3), *pM, *(pM-1), *(pM-2), *(pM-3)
- stmneda r2, {r10, r11, r12, lr}
- stmneda r3, {r5, r6, r7, r8}
+ stmdane r2, {r10, r11, r12, lr}
+ stmdane r3, {r5, r6, r7, r8}
ldmpc cond=ne regs=r4-r12 @ hybrid_filter end (when fs->index != 0)
.hf_memshl:
diff --git a/lib/rbcodec/codecs/mpa.c b/lib/rbcodec/codecs/mpa.c
index d6bcc04910..2c651d11b0 100644
--- a/lib/rbcodec/codecs/mpa.c
+++ b/lib/rbcodec/codecs/mpa.c
@@ -176,38 +176,38 @@ static int get_file_pos(int newtime)
struct mp3entry *id3 = ci->id3;
if (id3->vbr) {
- /* Convert newtime and id3->length to seconds to
- * avoid overflow */
- unsigned int newtime_s = newtime/1000;
- unsigned int length_s = id3->length/1000;
-
+ int curpos = ci->curpos - id3->first_frame_offset;
+ long skipms_from_curpos = curpos > 0 ? (long) (id3->elapsed - newtime) : - newtime;
if (id3->has_toc) {
/* Use the TOC to find the new position */
- unsigned int percent, remainder;
- int curtoc, nexttoc, plen;
-
- percent = (newtime_s*100) / length_s;
+ unsigned int percent = ((uint64_t)newtime * 100) / id3->length;
if (percent > 99)
percent = 99;
- curtoc = id3->toc[percent];
+ unsigned int pct_timestep = id3->length / 100;
- if (percent < 99) {
- nexttoc = id3->toc[percent+1];
- } else {
- nexttoc = 256;
- }
-
- pos = (id3->filesize/256)*curtoc;
+ /* Interpolate between this TOC mark and the next TOC mark */
+ int skipms_from_toc = newtime - percent * pct_timestep;
+ if (skipms_from_toc < abs(skipms_from_curpos))
+ {
+ unsigned int toc_sizestep = id3->filesize / 256;
+ unsigned int cur_toc = id3->toc[percent];
+ unsigned int next_toc = percent < 99 ? id3->toc[percent+1] : 256;
+ unsigned int plength = (next_toc - cur_toc) * toc_sizestep;
- /* Use the remainder to get a more accurate position */
- remainder = (newtime_s*100) % length_s;
- remainder = (remainder*100) / length_s;
- plen = (nexttoc - curtoc)*(id3->filesize/256);
- pos += (plen/100)*remainder;
- } else {
+ pos = cur_toc * toc_sizestep + (uint64_t) plength * skipms_from_toc / pct_timestep;
+ }
+ } else if (newtime < abs(skipms_from_curpos)) {
/* No TOC exists, estimate the new position */
- pos = (id3->filesize / length_s) * newtime_s;
+ pos = (uint64_t)newtime * id3->filesize / id3->length;
+ }
+ // VBR seek might be very inaccurate in long files
+ // So make sure that seeking actually happened in the intended direction
+ // Fix jumps in the wrong direction by seeking relative to the current position
+ if (pos == -1 || (skipms_from_curpos >= 0 && pos > curpos) || (skipms_from_curpos < 0 && pos < curpos))
+ {
+ pos = curpos - skipms_from_curpos * (id3->filesize / id3->length);
+ //LOGF("сurpos relative seek: %d, curpos: %d, newtime: %d", pos, curpos, newtime);
}
} else if (id3->bitrate) {
pos = newtime * (id3->bitrate / 8);
@@ -234,43 +234,31 @@ static void set_elapsed(struct mp3entry* id3)
if ( id3->vbr ) {
if ( id3->has_toc ) {
- /* calculate elapsed time using TOC */
- int i;
- unsigned int remainder, plen, relpos, nextpos;
+ unsigned int pct_timestep = id3->length / 100;
+ unsigned int toc_sizestep = id3->filesize / 256;
- /* find wich percent we're at */
- for (i=0; i<100; i++ )
- if ( offset < id3->toc[i] * (id3->filesize / 256) )
+ int percent;
+ for (percent = 0; percent < 100; ++percent)
+ if (offset < id3->toc[percent] * toc_sizestep)
break;
+ if (percent > 0)
+ --percent;
- i--;
- if (i < 0)
- i = 0;
-
- relpos = id3->toc[i];
-
- if (i < 99)
- nextpos = id3->toc[i+1];
- else
- nextpos = 256;
-
- remainder = offset - (relpos * (id3->filesize / 256));
+ unsigned int cur_toc = id3->toc[percent];
+ unsigned int next_toc = percent < 99 ? id3->toc[percent+1] : 256;
+ unsigned int plength = (next_toc - cur_toc) * toc_sizestep;
- /* set time for this percent (divide before multiply to prevent
- overflow on long files. loss of precision is negligible on
- short files) */
- elapsed = i * (id3->length / 100);
+ /* Set elapsed time to the TOC mark */
+ elapsed = percent * pct_timestep;
- /* calculate remainder time */
- plen = (nextpos - relpos) * (id3->filesize / 256);
- elapsed += (((remainder * 100) / plen) * (id3->length / 10000));
- }
- else {
- /* no TOC exists. set a rough estimate using average bitrate */
- int tpk = id3->length /
- ((id3->filesize - id3->first_frame_offset - id3->id3v1len) /
- 1024);
- elapsed = offset / 1024 * tpk;
+ /* Interpolate between this TOC mark and the next TOC mark */
+ offset -= cur_toc * toc_sizestep;
+ elapsed += (uint64_t)pct_timestep * offset / plength;
+ } else {
+ /* No TOC, use an approximation (this'll be wildly inaccurate) */
+ uint64_t data_size = id3->filesize -
+ id3->first_frame_offset - id3->id3v1len;
+ elapsed = (uint64_t)id3->length * offset / data_size;
}
}
else
@@ -408,6 +396,35 @@ enum codec_status codec_main(enum codec_entry_call_reason reason)
return CODEC_OK;
}
+bool seek_by_time(int64_t* samplesdone, unsigned long current_frequency, unsigned long elapsed_ms)
+{
+ if (ci->id3->is_asf_stream) {
+ asf_waveformatex_t *wfx = (asf_waveformatex_t *)(ci->id3->toc);
+ int elapsedtime = asf_seek(elapsed_ms, wfx);
+
+ *samplesdone = (elapsedtime > 0) ?
+ (((int64_t)elapsedtime)*current_frequency/1000) : 0;
+
+ if (elapsedtime < 1) {
+ ci->set_elapsed(0);
+ return false;
+ } else {
+ ci->set_elapsed(elapsedtime);
+ reset_stream_buffer();
+ }
+ } else {
+ int newpos = elapsed_ms ? get_file_pos(elapsed_ms) : (int)(ci->id3->first_frame_offset);
+
+ *samplesdone = ((int64_t)elapsed_ms) * current_frequency / 1000;
+
+ if (!ci->seek_buffer(newpos))
+ return false;
+
+ ci->set_elapsed((*samplesdone * 1000LL) / current_frequency);
+ }
+ return true;
+}
+
/* this is called for each file to process */
enum codec_status codec_run(void)
{
@@ -431,13 +448,8 @@ enum codec_status codec_run(void)
ci->configure(DSP_SET_FREQUENCY, ci->id3->frequency);
current_frequency = ci->id3->frequency;
codec_set_replaygain(ci->id3);
-
- if (!ci->id3->is_asf_stream && !ci->id3->offset && ci->id3->elapsed) {
- /* Have elapsed time but not offset */
- ci->id3->offset = get_file_pos(ci->id3->elapsed);
- }
- if (ci->id3->offset) {
+ if (ci->id3->offset) {
if (ci->id3->is_asf_stream) {
asf_waveformatex_t *wfx = (asf_waveformatex_t *)(ci->id3->toc);
@@ -450,9 +462,19 @@ enum codec_status codec_run(void)
}
else {
ci->seek_buffer(ci->id3->offset);
- set_elapsed(ci->id3);
+ if (ci->id3->elapsed && ci->id3->elapsed < ci->id3->length)
+ {
+ ci->set_elapsed(ci->id3->elapsed);
+ }
+ else
+ {
+ set_elapsed(ci->id3);
+ }
}
}
+ else if (ci->id3->elapsed)
+ /* Have elapsed time but not offset */
+ seek_by_time(&samplesdone, current_frequency, ci->id3->elapsed);
else
ci->seek_buffer(ci->id3->first_frame_offset);
@@ -508,36 +530,10 @@ enum codec_status codec_run(void)
samples_to_skip = 0;
}
- if (ci->id3->is_asf_stream) {
- asf_waveformatex_t *wfx = (asf_waveformatex_t *)(ci->id3->toc);
- int elapsedtime = asf_seek(param, wfx);
-
- samplesdone = (elapsedtime > 0) ?
- (((int64_t)elapsedtime)*current_frequency/1000) : 0;
-
- if (elapsedtime < 1) {
- ci->set_elapsed(0);
- ci->seek_complete();
- break;
- } else {
- ci->set_elapsed(elapsedtime);
- ci->seek_complete();
- reset_stream_buffer();
- }
- } else {
- int newpos = param ? get_file_pos(param) : (int)(ci->id3->first_frame_offset);
-
- samplesdone = ((int64_t)param)*current_frequency/1000;
-
- if (!ci->seek_buffer(newpos))
- {
- ci->seek_complete();
- break;
- }
-
- ci->set_elapsed((samplesdone * 1000LL) / current_frequency);
- ci->seek_complete();
- }
+ bool success = seek_by_time(&samplesdone, current_frequency, param);
+ ci->seek_complete();
+ if (!success)
+ break;
init_mad();
framelength = 0;
diff --git a/lib/rbcodec/codecs/sid.c b/lib/rbcodec/codecs/sid.c
index 6ce11b34cb..ce6caa8198 100644
--- a/lib/rbcodec/codecs/sid.c
+++ b/lib/rbcodec/codecs/sid.c
@@ -5,13 +5,13 @@
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
- * $Id$
*
- * SID Codec for rockbox based on the TinySID engine
- *
- * Written by Tammo Hinrichs (kb) and Rainer Sinsch in 1998-1999
- * Ported to rockbox on 14 April 2006
+ * SID Codec for Rockbox using Hermit's cRSID library
*
+ * Written by Hermit (Mihaly Horvath) and Ninja (Wolfram Sang) in 2022/23.
+ * Some generic codec handling taken from the former SID codec done by
+ * Tammo Hinrichs, Rainer Sinsch, Dave Chapman, Stefan Waigand, Igor Poretsky,
+ * Solomon Peachy.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -21,1331 +21,95 @@
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
- ****************************************************************************/
-
- /*****************************
- * kb explicitly points out that this emulation sounds crappy, though
- * we decided to put it open source so everyone can enjoy sidmusic
- * on rockbox
- *
- *****************************/
-
- /*********************
- * v1.1
- * Added 16-04-2006: Rainer Sinsch
- * Removed all time critical floating point operations and
- * replaced them with quick & dirty integer calculations
- *
- * Added 17-04-2006: Rainer Sinsch
- * Improved quick & dirty integer calculations for the resonant filter
- * Improved audio quality by 4 bits
- *
- * v1.2
- * Added 17-04-2006: Dave Chapman
- * Improved file loading
- *
- * Added 17-04-2006: Rainer Sinsch
- * Added sample routines
- * Added cia timing routines
- * Added fast forwarding capabilities
- * Corrected bug in sid loading
- *
- * v1.2.1
- * Added 04-05-2006: Rainer Sinsch
- * Implemented Marco Alanens suggestion for subsong selection:
- * Select the subsong by seeking: Each second represents a subsong
- *
- * v1.3
- * Added 25-07-2019: Stefan Waigand, Igor Poretsky, Solomon Peachy
- * SID playback in stereo (See FS#11052)
- *
- **************************/
-
-#define USE_FILTER
+ ***************************************************************************/
-#include "debug.h"
+#include "cRSID/libcRSID.h"
#include "codeclib.h"
#include <inttypes.h>
CODEC_HEADER
-#define CHUNK_SIZE (1024*2)
+/* bigger CHUNK_SIZE makes Clip sluggish when playing 2SIDs */
+#define CHUNK_SIZE 512
#define SID_BUFFER_SIZE 0x10000
#define SAMPLE_RATE 44100
-/* This codec supports SID Files:
- *
- */
-
-/* The sample buffers */
static int32_t samples_r[CHUNK_SIZE] IBSS_ATTR;
static int32_t samples_l[CHUNK_SIZE] IBSS_ATTR;
-void sidPoke(int reg, unsigned char val) ICODE_ATTR;
-
-#define FLAG_N 128
-#define FLAG_V 64
-#define FLAG_B 16
-#define FLAG_D 8
-#define FLAG_I 4
-#define FLAG_Z 2
-#define FLAG_C 1
-
-#define imp 0
-#define imm 1
-#define _abs 2
-#define absx 3
-#define absy 4
-#define zp 6
-#define zpx 7
-#define zpy 8
-#define ind 9
-#define indx 10
-#define indy 11
-#define acc 12
-#define rel 13
-
-enum {
- adc, _and, asl, bcc, bcs, beq, bit, bmi, bne, bpl, _brk, bvc, bvs, clc,
- cld, cli, clv, cmp, cpx, cpy, dec, dex, dey, eor, inc, inx, iny, jmp,
- jsr, lda, ldx, ldy, lsr, _nop, ora, pha, php, pla, plp, rol, ror, rti,
- rts, sbc, sec, sed, sei, sta, stx, sty, tax, tay, tsx, txa, txs, tya,
- xxx
-};
-
-/* SID register definition */
-struct s6581 {
- struct sidvoice {
- unsigned short freq;
- unsigned short pulse;
- unsigned char wave;
- unsigned char ad;
- unsigned char sr;
- } v[3];
- unsigned char ffreqlo;
- unsigned char ffreqhi;
- unsigned char res_ftv;
- unsigned char ftp_vol;
-};
-
-/* internal oscillator def */
-struct sidosc {
- unsigned long freq;
- unsigned long pulse;
- unsigned char wave;
- unsigned char filter;
- unsigned long attack;
- unsigned long decay;
- unsigned long sustain;
- unsigned long release;
- unsigned long counter;
- signed long envval;
- unsigned char envphase;
- unsigned long noisepos;
- unsigned long noiseval;
- unsigned char noiseout;
-};
-
-/* internal filter def */
-struct sidflt {
- int freq;
- unsigned char l_ena;
- unsigned char b_ena;
- unsigned char h_ena;
- unsigned char v3ena;
- int vol;
- int rez;
- int h;
- int b;
- int l;
-};
-
-/* ------------------------ pseudo-constants (depending on mixing freq) */
-static int mixing_frequency IDATA_ATTR;
-static unsigned long freqmul IDATA_ATTR;
-static int filtmul IDATA_ATTR;
-#ifndef ROCKBOX
-unsigned long attacks [16] IDATA_ATTR;
-unsigned long releases[16] IDATA_ATTR;
-#endif
-
-/* ------------------------------------------------------------ globals */
-static struct s6581 sid IDATA_ATTR;
-static struct sidosc osc[3] IDATA_ATTR;
-static struct sidflt filter IDATA_ATTR;
-
-/* ------------------------------------------------------ C64 Emu Stuff */
-static unsigned char bval IDATA_ATTR;
-static unsigned short wval IDATA_ATTR;
-/* -------------------------------------------------- Register & memory */
-static unsigned char a,x,y,s,p IDATA_ATTR;
-static unsigned short pc IDATA_ATTR;
-
-static unsigned char memory[65536];
-
-/* ----------------------------------------- Variables for sample stuff */
-static int sample_active IDATA_ATTR;
-static int sample_position, sample_start, sample_end, sample_repeat_start IDATA_ATTR;
-static int fracPos IDATA_ATTR; /* Fractal position of sample */
-static int sample_period IDATA_ATTR;
-static int sample_repeats IDATA_ATTR;
-static int sample_order IDATA_ATTR;
-static int sample_nibble IDATA_ATTR;
-
-static int internal_period, internal_order, internal_start, internal_end,
- internal_add, internal_repeat_times, internal_repeat_start IDATA_ATTR;
-
-/* ---------------------------------------------------------- constants */
-#ifndef ROCKBOX
-static const float attackTimes[16] ICONST_ATTR =
-{
- 0.0022528606, 0.0080099577, 0.0157696042, 0.0237795619,
- 0.0372963655, 0.0550684591, 0.0668330845, 0.0783473987,
- 0.0981219818, 0.244554021, 0.489108042, 0.782472742,
- 0.977715461, 2.93364701, 4.88907793, 7.82272493
-};
-static const float decayReleaseTimes[16] ICONST_ATTR =
-{
- 0.00891777693, 0.024594051, 0.0484185907, 0.0730116639, 0.114512475,
- 0.169078356, 0.205199432, 0.240551975, 0.301266125, 0.750858245,
- 1.50171551, 2.40243682, 3.00189298, 9.00721405, 15.010998, 24.0182111
-};
-#else
-#define DIV(X) ((int)(0x1000000 / (X * SAMPLE_RATE)))
-static const unsigned long attacks[16] ICONST_ATTR =
-{
- DIV(0.0022528606), DIV(0.0080099577), DIV(0.0157696042), DIV(0.0237795619),
- DIV(0.0372963655), DIV(0.0550684591), DIV(0.0668330845), DIV(0.0783473987),
- DIV(0.0981219818), DIV(0.2445540210), DIV(0.4891080420), DIV(0.7824727420),
- DIV(0.9777154610), DIV(2.9336470100), DIV(4.8890779300), DIV(7.8227249300)
-};
-static const unsigned long releases[16] ICONST_ATTR =
-{
- DIV(0.00891777693), DIV(0.0245940510), DIV(0.0484185907), DIV(0.0730116639),
- DIV(0.11451247500), DIV(0.1690783560), DIV(0.2051994320), DIV(0.2405519750),
- DIV(0.30126612500), DIV(0.7508582450), DIV(1.5017155100), DIV(2.4024368200),
- DIV(3.00189298000), DIV(9.0072140500), DIV(15.010998000), DIV(24.018211100)
-};
-#endif
-static const int opcodes[256] ICONST_ATTR = {
- _brk,ora,xxx,xxx,xxx,ora,asl,xxx,php,ora,asl,xxx,xxx,ora,asl,xxx,
- bpl,ora,xxx,xxx,xxx,ora,asl,xxx,clc,ora,xxx,xxx,xxx,ora,asl,xxx,
- jsr,_and,xxx,xxx,bit,_and,rol,xxx,plp,_and,rol,xxx,bit,_and,rol,xxx,
- bmi,_and,xxx,xxx,xxx,_and,rol,xxx,sec,_and,xxx,xxx,xxx,_and,rol,xxx,
- rti,eor,xxx,xxx,xxx,eor,lsr,xxx,pha,eor,lsr,xxx,jmp,eor,lsr,xxx,
- bvc,eor,xxx,xxx,xxx,eor,lsr,xxx,cli,eor,xxx,xxx,xxx,eor,lsr,xxx,
- rts,adc,xxx,xxx,xxx,adc,ror,xxx,pla,adc,ror,xxx,jmp,adc,ror,xxx,
- bvs,adc,xxx,xxx,xxx,adc,ror,xxx,sei,adc,xxx,xxx,xxx,adc,ror,xxx,
- xxx,sta,xxx,xxx,sty,sta,stx,xxx,dey,xxx,txa,xxx,sty,sta,stx,xxx,
- bcc,sta,xxx,xxx,sty,sta,stx,xxx,tya,sta,txs,xxx,xxx,sta,xxx,xxx,
- ldy,lda,ldx,xxx,ldy,lda,ldx,xxx,tay,lda,tax,xxx,ldy,lda,ldx,xxx,
- bcs,lda,xxx,xxx,ldy,lda,ldx,xxx,clv,lda,tsx,xxx,ldy,lda,ldx,xxx,
- cpy,cmp,xxx,xxx,cpy,cmp,dec,xxx,iny,cmp,dex,xxx,cpy,cmp,dec,xxx,
- bne,cmp,xxx,xxx,xxx,cmp,dec,xxx,cld,cmp,xxx,xxx,xxx,cmp,dec,xxx,
- cpx,sbc,xxx,xxx,cpx,sbc,inc,xxx,inx,sbc,_nop,xxx,cpx,sbc,inc,xxx,
- beq,sbc,xxx,xxx,xxx,sbc,inc,xxx,sed,sbc,xxx,xxx,xxx,sbc,inc,xxx
-};
-
-
-static const int modes[256] ICONST_ATTR = {
- imp,indx,xxx,xxx,zp,zp,zp,xxx,imp,imm,acc,xxx,_abs,_abs,_abs,xxx,
- rel,indy,xxx,xxx,xxx,zpx,zpx,xxx,imp,absy,xxx,xxx,xxx,absx,absx,xxx,
- _abs,indx,xxx,xxx,zp,zp,zp,xxx,imp,imm,acc,xxx,_abs,_abs,_abs,xxx,
- rel,indy,xxx,xxx,xxx,zpx,zpx,xxx,imp,absy,xxx,xxx,xxx,absx,absx,xxx,
- imp,indx,xxx,xxx,zp,zp,zp,xxx,imp,imm,acc,xxx,_abs,_abs,_abs,xxx,
- rel,indy,xxx,xxx,xxx,zpx,zpx,xxx,imp,absy,xxx,xxx,xxx,absx,absx,xxx,
- imp,indx,xxx,xxx,zp,zp,zp,xxx,imp,imm,acc,xxx,ind,_abs,_abs,xxx,
- rel,indy,xxx,xxx,xxx,zpx,zpx,xxx,imp,absy,xxx,xxx,xxx,absx,absx,xxx,
- imm,indx,xxx,xxx,zp,zp,zp,xxx,imp,imm,acc,xxx,_abs,_abs,_abs,xxx,
- rel,indy,xxx,xxx,zpx,zpx,zpy,xxx,imp,absy,acc,xxx,xxx,absx,absx,xxx,
- imm,indx,imm,xxx,zp,zp,zp,xxx,imp,imm,acc,xxx,_abs,_abs,_abs,xxx,
- rel,indy,xxx,xxx,zpx,zpx,zpy,xxx,imp,absy,acc,xxx,absx,absx,absy,xxx,
- imm,indx,xxx,xxx,zp,zp,zp,xxx,imp,imm,acc,xxx,_abs,_abs,_abs,xxx,
- rel,indy,xxx,xxx,zpx,zpx,zpx,xxx,imp,absy,acc,xxx,xxx,absx,absx,xxx,
- imm,indx,xxx,xxx,zp,zp,zp,xxx,imp,imm,acc,xxx,_abs,_abs,_abs,xxx,
- rel,indy,xxx,xxx,zpx,zpx,zpx,xxx,imp,absy,acc,xxx,xxx,absx,absx,xxx
-};
-
-/* Routines for quick & dirty float calculation */
-
-static inline int quickfloat_ConvertFromInt(int i)
-{
- return (i<<16);
-}
-#ifndef ROCKBOX
-static inline int quickfloat_ConvertFromFloat(float f)
-{
- return (int)(f*(1<<16));
-}
-#else
-#define quickfloat_ConvertFromFloat(X) (int)(X*(1<<16))
-#endif
-static inline int quickfloat_Multiply(int a, int b)
-{
- return (a>>8)*(b>>8);
-}
-static inline int quickfloat_ConvertToInt(int i)
-{
- return (i>>16);
-}
-
-/* Get the bit from an unsigned long at a specified position */
-static inline unsigned char get_bit(unsigned long val, unsigned char b)
-{
- return (unsigned char) ((val >> b) & 1);
-}
-
-
-static inline int GenerateDigi(int sIn)
-{
- static int sample = 0;
-
- if (!sample_active) return(sIn);
-
- if ((sample_position < sample_end) && (sample_position >= sample_start))
- {
- sIn += sample;
-
- fracPos += 985248/sample_period;
-
- if (fracPos > mixing_frequency)
- {
- fracPos%=mixing_frequency;
-
- // N�hstes Samples holen
- if (sample_order == 0) {
- sample_nibble++; // Nähstes Sample-Nibble
- if (sample_nibble==2) {
- sample_nibble = 0;
- sample_position++;
- }
- }
- else {
- sample_nibble--;
- if (sample_nibble < 0) {
- sample_nibble=1;
- sample_position++;
- }
- }
- if (sample_repeats)
- {
- if (sample_position > sample_end)
- {
- sample_repeats--;
- sample_position = sample_repeat_start;
- }
- else sample_active = 0;
- }
-
- sample = memory[sample_position&0xffff];
- if (sample_nibble==1) // Hi-Nibble holen?
- sample = (sample & 0xf0)>>4;
- else sample = sample & 0x0f;
-
- sample -= 7;
- sample <<= 10;
- }
- }
-
- return (sIn);
-}
-
-/* ------------------------------------------------------------- synthesis
- initialize SID and frequency dependant values */
-void synth_init(unsigned long mixfrq) ICODE_ATTR;
-void synth_init(unsigned long mixfrq)
-{
-#ifndef ROCKBOX
- int i;
-#endif
- mixing_frequency = mixfrq;
- fracPos = 0;
- freqmul = 15872000 / mixfrq;
- filtmul = quickfloat_ConvertFromFloat(21.5332031f)/mixfrq;
-#ifndef ROCKBOX
- for (i=0;i<16;i++) {
- attacks [i]=(int) (0x1000000 / (attackTimes[i]*mixfrq));
- releases[i]=(int) (0x1000000 / (decayReleaseTimes[i]*mixfrq));
- }
-#endif
- memset(&sid,0,sizeof(sid));
- memset(osc,0,sizeof(osc));
- memset(&filter,0,sizeof(filter));
- osc[0].noiseval = 0xffffff;
- osc[1].noiseval = 0xffffff;
- osc[2].noiseval = 0xffffff;
-}
-
-/* render a buffer of n samples with the actual register contents */
-void synth_render (int32_t *buffer_r, int32_t *buffer_l, unsigned long len) ICODE_ATTR;
-void synth_render (int32_t *buffer_r, int32_t *buffer_l, unsigned long len)
-{
+void sid_render(int32_t *buffer_r, int32_t *buffer_l, unsigned long len) ICODE_ATTR;
+void sid_render(int32_t *buffer_r, int32_t *buffer_l, unsigned long len) {
unsigned long bp;
- /* step 1: convert the not easily processable sid registers into some
- more convenient and fast values (makes the thing much faster
- if you process more than 1 sample value at once) */
- unsigned char v;
- for (v=0;v<3;v++) {
- osc[v].pulse = (sid.v[v].pulse & 0xfff) << 16;
- osc[v].filter = get_bit(sid.res_ftv,v);
- osc[v].attack = attacks[sid.v[v].ad >> 4];
- osc[v].decay = releases[sid.v[v].ad & 0xf];
- osc[v].sustain = sid.v[v].sr & 0xf0;
- osc[v].release = releases[sid.v[v].sr & 0xf];
- osc[v].wave = sid.v[v].wave;
- osc[v].freq = ((unsigned long)sid.v[v].freq)*freqmul;
- }
-
-#ifdef USE_FILTER
- filter.freq = (16*sid.ffreqhi + (sid.ffreqlo&0x7)) * filtmul;
-
- if (filter.freq>quickfloat_ConvertFromInt(1))
- filter.freq=quickfloat_ConvertFromInt(1);
- /* the above line isnt correct at all - the problem is that the filter
- works only up to rmxfreq/4 - this is sufficient for 44KHz but isnt
- for 32KHz and lower - well, but sound quality is bad enough then to
- neglect the fact that the filter doesnt come that high ;) */
- filter.l_ena = get_bit(sid.ftp_vol,4);
- filter.b_ena = get_bit(sid.ftp_vol,5);
- filter.h_ena = get_bit(sid.ftp_vol,6);
- filter.v3ena = !get_bit(sid.ftp_vol,7);
- filter.vol = (sid.ftp_vol & 0xf);
- filter.rez = quickfloat_ConvertFromFloat(1.2f) -
- quickfloat_ConvertFromFloat(0.04f)*(sid.res_ftv >> 4);
-
- /* We precalculate part of the quick float operation, saves time in loop later */
- filter.rez>>=8;
-#endif
-
-
- /* now render the buffer */
- for (bp=0;bp<len;bp++) {
-#ifdef USE_FILTER
- int outo[2]={0,0};
-#endif
- int outf[2]={0,0};
- /* step 2 : generate the two output signals (for filtered and non-
- filtered) from the osc/eg sections */
- for (v=0;v<3;v++) {
- /* update wave counter */
- osc[v].counter = (osc[v].counter+osc[v].freq) & 0xFFFFFFF;
- /* reset counter / noise generator if reset get_bit set */
- if (osc[v].wave & 0x08) {
- osc[v].counter = 0;
- osc[v].noisepos = 0;
- osc[v].noiseval = 0xffffff;
- }
- unsigned char refosc = v?v-1:2; /* reference oscillator for sync/ring */
- /* sync oscillator to refosc if sync bit set */
- if (osc[v].wave & 0x02)
- if (osc[refosc].counter < osc[refosc].freq)
- osc[v].counter = osc[refosc].counter * osc[v].freq / osc[refosc].freq;
- /* generate waveforms with really simple algorithms */
- unsigned char triout = (unsigned char) (osc[v].counter>>19);
- if (osc[v].counter>>27)
- triout^=0xff;
- unsigned char sawout = (unsigned char) (osc[v].counter >> 20);
- unsigned char plsout = (unsigned char) ((osc[v].counter > osc[v].pulse)-1);
-
- /* generate noise waveform exactly as the SID does. */
- if (osc[v].noisepos!=(osc[v].counter>>23))
- {
- osc[v].noisepos = osc[v].counter >> 23;
- osc[v].noiseval = (osc[v].noiseval << 1) |
- (get_bit(osc[v].noiseval,22) ^ get_bit(osc[v].noiseval,17));
- osc[v].noiseout = (get_bit(osc[v].noiseval,22) << 7) |
- (get_bit(osc[v].noiseval,20) << 6) |
- (get_bit(osc[v].noiseval,16) << 5) |
- (get_bit(osc[v].noiseval,13) << 4) |
- (get_bit(osc[v].noiseval,11) << 3) |
- (get_bit(osc[v].noiseval, 7) << 2) |
- (get_bit(osc[v].noiseval, 4) << 1) |
- (get_bit(osc[v].noiseval, 2) << 0);
- }
- unsigned char nseout = osc[v].noiseout;
-
- /* modulate triangle wave if ringmod bit set */
- if (osc[v].wave & 0x04)
- if (osc[refosc].counter < 0x8000000)
- triout ^= 0xff;
-
- /* now mix the oscillators with an AND operation as stated in
- the SID's reference manual - even if this is completely wrong.
- well, at least, the $30 and $70 waveform sounds correct and there's
- no real solution to do $50 and $60, so who cares. */
-
- unsigned char outv=0xFF;
- if (osc[v].wave & 0x10) outv &= triout;
- if (osc[v].wave & 0x20) outv &= sawout;
- if (osc[v].wave & 0x40) outv &= plsout;
- if (osc[v].wave & 0x80) outv &= nseout;
-
- /* so now process the volume according to the phase and adsr values */
- switch (osc[v].envphase) {
- case 0 : { /* Phase 0 : Attack */
- osc[v].envval+=osc[v].attack;
- if (osc[v].envval >= 0xFFFFFF)
- {
- osc[v].envval = 0xFFFFFF;
- osc[v].envphase = 1;
- }
- break;
- }
- case 1 : { /* Phase 1 : Decay */
- osc[v].envval-=osc[v].decay;
- if ((signed int) osc[v].envval <= (signed int) (osc[v].sustain<<16))
- {
- osc[v].envval = osc[v].sustain<<16;
- osc[v].envphase = 2;
- }
- break;
- }
- case 2 : { /* Phase 2 : Sustain */
- if ((signed int) osc[v].envval != (signed int) (osc[v].sustain<<16))
- {
- osc[v].envphase = 1;
- }
- /* :) yes, thats exactly how the SID works. and maybe
- a music routine out there supports this, so better
- let it in, thanks :) */
- break;
- }
- case 3 : { /* Phase 3 : Release */
- osc[v].envval-=osc[v].release;
- if (osc[v].envval < 0x40000) osc[v].envval= 0x40000;
-
- /* the volume offset is because the SID does not
- completely silence the voices when it should. most
- emulators do so though and thats the main reason
- why the sound of emulators is too, err... emulated :) */
- break;
- }
- }
-
-#ifdef USE_FILTER
-
- /* now route the voice output to either the non-filtered or the
- filtered channel and dont forget to blank out osc3 if desired */
-
- if (v<2 || filter.v3ena)
- {
- if (osc[v].filter)
- outf[v&1]+=(((int)(outv-0x80))*osc[v].envval)>>22;
- else
- outo[v&1]+=(((int)(outv-0x80))*osc[v].envval)>>22;
- }
-#else /* !USE_FILTER */
- /* Don't use filters, just mix voices together */
- outf[v&1]+=((signed short)(outv-0x80)) * (osc[v].envval>>4);
-#endif
- } /* for (v=0;v<3;v++) */
-
-
-#ifdef USE_FILTER
- /* step 3
- * so, now theres finally time to apply the multi-mode resonant filter
- * to the signal. The easiest thing ist just modelling a real electronic
- * filter circuit instead of fiddling around with complex IIRs or even
- * FIRs ...
- * it sounds as good as them or maybe better and needs only 3 MULs and
- * 4 ADDs for EVERYTHING. SIDPlay uses this kind of filter, too, but
- * Mage messed the whole thing completely up - as the rest of the
- * emulator.
- * This filter sounds a lot like the 8580, as the low-quality, dirty
- * sound of the 6581 is uuh too hard to achieve :) */
-
- for (v=0;v<2;v++) { /* do step 3 for both channels */
- filter.h = quickfloat_ConvertFromInt(outf[v]) - (filter.b>>8)*filter.rez - filter.l;
- filter.b += quickfloat_Multiply(filter.freq, filter.h);
- filter.l += quickfloat_Multiply(filter.freq, filter.b);
-
- outf[v] = 0;
-
- if (filter.l_ena) outf[v]+=quickfloat_ConvertToInt(filter.l);
- if (filter.b_ena) outf[v]+=quickfloat_ConvertToInt(filter.b);
- if (filter.h_ena) outf[v]+=quickfloat_ConvertToInt(filter.h);
- }
-
- /* mix in other channel to reduce stereo panning for better sound on headphones */
- int final_sample_r = filter.vol*((outo[0]+outf[0]) + ((outo[1]+outf[1])>>4));
- int final_sample_l = filter.vol*((outo[1]+outf[1]) + ((outo[0]+outf[0])>>4));
- *(buffer_r+bp)= GenerateDigi(final_sample_r)<<13;
- *(buffer_l+bp)= GenerateDigi(final_sample_l)<<13;
-#else /* !USE_FILTER */
- *(buffer_r+bp) = GenerateDigi(outf[0])<<3;
- *(buffer_l+bp) = GenerateDigi(outf[1])<<3;
-#endif
- } /*for (bp=0;bp<len;bp++) */
-}
-
-
-
-/*
-* C64 Mem Routines
-*/
-static inline unsigned char getmem(unsigned short addr)
-{
- return memory[addr];
-}
-
-static inline void setmem(unsigned short addr, unsigned char value)
-{
- if ((addr&0xfc00)==0xd400)
- {
- sidPoke(addr&0x1f,value);
- /* New SID-Register */
- if (addr > 0xd418)
- {
- switch (addr)
- {
- case 0xd41f: /* Start-Hi */
- internal_start = (internal_start&0x00ff) | (value<<8); break;
- case 0xd41e: /* Start-Lo */
- internal_start = (internal_start&0xff00) | (value); break;
- case 0xd47f: /* Repeat-Hi */
- internal_repeat_start = (internal_repeat_start&0x00ff) | (value<<8); break;
- case 0xd47e: /* Repeat-Lo */
- internal_repeat_start = (internal_repeat_start&0xff00) | (value); break;
- case 0xd43e: /* End-Hi */
- internal_end = (internal_end&0x00ff) | (value<<8); break;
- case 0xd43d: /* End-Lo */
- internal_end = (internal_end&0xff00) | (value); break;
- case 0xd43f: /* Loop-Size */
- internal_repeat_times = value; break;
- case 0xd45e: /* Period-Hi */
- internal_period = (internal_period&0x00ff) | (value<<8); break;
- case 0xd45d: /* Period-Lo */
- internal_period = (internal_period&0xff00) | (value); break;
- case 0xd47d: /* Sample Order */
- internal_order = value; break;
- case 0xd45f: /* Sample Add */
- internal_add = value; break;
- case 0xd41d: /* Start sampling */
- sample_repeats = internal_repeat_times;
- sample_position = internal_start;
- sample_start = internal_start;
- sample_end = internal_end;
- sample_repeat_start = internal_repeat_start;
- sample_period = internal_period;
- sample_order = internal_order;
- switch (value)
- {
- case 0xfd: sample_active = 0; break;
- case 0xfe:
- case 0xff: sample_active = 1; break;
- default: return;
- }
- break;
- }
- }
- }
- else memory[addr]=value;
-}
-
-/*
-* Poke a value into the sid register
-*/
-void sidPoke(int reg, unsigned char val) ICODE_ATTR;
-void sidPoke(int reg, unsigned char val)
-{
- int voice=0;
-
- if ((reg >= 7) && (reg <=13)) {voice=1; reg-=7;}
- else if ((reg >= 14) && (reg <=20)) {voice=2; reg-=14;}
-
- switch (reg) {
- case 0: { /* Set frequency: Low byte */
- sid.v[voice].freq = (sid.v[voice].freq&0xff00)+val;
- break;
- }
- case 1: { /* Set frequency: High byte */
- sid.v[voice].freq = (sid.v[voice].freq&0xff)+(val<<8);
- break;
- }
- case 2: { /* Set pulse width: Low byte */
- sid.v[voice].pulse = (sid.v[voice].pulse&0xff00)+val;
- break;
- }
- case 3: { /* Set pulse width: High byte */
- sid.v[voice].pulse = (sid.v[voice].pulse&0xff)+(val<<8);
- break;
- }
- case 4: { sid.v[voice].wave = val;
- /* Directly look at GATE-Bit!
- * a change may happen twice or more often during one cpujsr
- * Put the Envelope Generator into attack or release phase if desired
- */
- if ((val & 0x01) == 0) osc[voice].envphase=3;
- else if (osc[voice].envphase==3) osc[voice].envphase=0;
- break;
- }
-
- case 5: { sid.v[voice].ad = val; break;}
- case 6: { sid.v[voice].sr = val; break;}
-
- case 21: { sid.ffreqlo = val; break; }
- case 22: { sid.ffreqhi = val; break; }
- case 23: { sid.res_ftv = val; break; }
- case 24: { sid.ftp_vol = val; break;}
- }
- return;
-}
-
-static inline unsigned char getaddr(int mode)
-{
- unsigned short ad,ad2;
- switch(mode)
- {
- case imp:
- return 0;
- case imm:
- return getmem(pc++);
- case _abs:
- ad=getmem(pc++);
- ad|=256*getmem(pc++);
- return getmem(ad);
- case absx:
- ad=getmem(pc++);
- ad|=256*getmem(pc++);
- ad2=ad+x;
- return getmem(ad2);
- case absy:
- ad=getmem(pc++);
- ad|=256*getmem(pc++);
- ad2=ad+y;
- return getmem(ad2);
- case zp:
- ad=getmem(pc++);
- return getmem(ad);
- case zpx:
- ad=getmem(pc++);
- ad+=x;
- return getmem(ad&0xff);
- case zpy:
- ad=getmem(pc++);
- ad+=y;
- return getmem(ad&0xff);
- case indx:
- ad=getmem(pc++);
- ad+=x;
- ad2=getmem(ad&0xff);
- ad++;
- ad2|=getmem(ad&0xff)<<8;
- return getmem(ad2);
- case indy:
- ad=getmem(pc++);
- ad2=getmem(ad);
- ad2|=getmem((ad+1)&0xff)<<8;
- ad=ad2+y;
- return getmem(ad);
- case acc:
- return a;
- }
- return 0;
-}
-
-static inline void setaddr(int mode, unsigned char val)
-{
- unsigned short ad,ad2;
- switch(mode)
- {
- case _abs:
- ad=getmem(pc-2);
- ad|=256*getmem(pc-1);
- setmem(ad,val);
- return;
- case absx:
- ad=getmem(pc-2);
- ad|=256*getmem(pc-1);
- ad2=ad+x;
- setmem(ad2,val);
- return;
- case zp:
- ad=getmem(pc-1);
- setmem(ad,val);
- return;
- case zpx:
- ad=getmem(pc-1);
- ad+=x;
- setmem(ad&0xff,val);
- return;
- case acc:
- a=val;
- return;
- }
-}
-
-
-static inline void putaddr(int mode, unsigned char val)
-{
- unsigned short ad,ad2;
- switch(mode)
- {
- case _abs:
- ad=getmem(pc++);
- ad|=getmem(pc++)<<8;
- setmem(ad,val);
- return;
- case absx:
- ad=getmem(pc++);
- ad|=getmem(pc++)<<8;
- ad2=ad+x;
- setmem(ad2,val);
- return;
- case absy:
- ad=getmem(pc++);
- ad|=getmem(pc++)<<8;
- ad2=ad+y;
- setmem(ad2,val);
- return;
- case zp:
- ad=getmem(pc++);
- setmem(ad,val);
- return;
- case zpx:
- ad=getmem(pc++);
- ad+=x;
- setmem(ad&0xff,val);
- return;
- case zpy:
- ad=getmem(pc++);
- ad+=y;
- setmem(ad&0xff,val);
- return;
- case indx:
- ad=getmem(pc++);
- ad+=x;
- ad2=getmem(ad&0xff);
- ad++;
- ad2|=getmem(ad&0xff)<<8;
- setmem(ad2,val);
- return;
- case indy:
- ad=getmem(pc++);
- ad2=getmem(ad);
- ad2|=getmem((ad+1)&0xff)<<8;
- ad=ad2+y;
- setmem(ad,val);
- return;
- case acc:
- a=val;
- return;
- }
-}
-
-
-static inline void setflags(int flag, int cond)
-{
- if (cond) p|=flag;
- else p&=~flag;
-}
-
-
-static inline void push(unsigned char val)
-{
- setmem(0x100+s,val);
- if (s) s--;
-}
-
-static inline unsigned char pop(void)
-{
- if (s<0xff) s++;
- return getmem(0x100+s);
-}
-
-static inline void branch(int flag)
-{
- signed char dist;
- dist=(signed char)getaddr(imm);
- wval=pc+dist;
- if (flag) pc=wval;
-}
+ int output;
-void cpuReset(void) ICODE_ATTR;
-void cpuReset(void)
-{
- a=x=y=0;
- p=0;
- s=255;
- pc=getaddr(0xfffc);
-}
-
-void cpuResetTo(unsigned short npc, unsigned char na) ICODE_ATTR;
-void cpuResetTo(unsigned short npc, unsigned char na)
-{
- a=na;
- x=0;
- y=0;
- p=0;
- s=255;
- pc=npc;
-}
-
-static inline void cpuParse(void)
-{
- unsigned char opc=getmem(pc++);
- int cmd=opcodes[opc];
- int addr=modes[opc];
- int c;
- switch (cmd)
- {
- case adc:
- wval=(unsigned short)a+getaddr(addr)+((p&FLAG_C)?1:0);
- setflags(FLAG_C, wval&0x100);
- a=(unsigned char)wval;
- setflags(FLAG_Z, !a);
- setflags(FLAG_N, a&0x80);
- setflags(FLAG_V, (!!(p&FLAG_C)) ^ (!!(p&FLAG_N)));
- break;
- case _and:
- bval=getaddr(addr);
- a&=bval;
- setflags(FLAG_Z, !a);
- setflags(FLAG_N, a&0x80);
- break;
- case asl:
- wval=getaddr(addr);
- wval<<=1;
- setaddr(addr,(unsigned char)wval);
- setflags(FLAG_Z,!wval);
- setflags(FLAG_N,wval&0x80);
- setflags(FLAG_C,wval&0x100);
- break;
- case bcc:
- branch(!(p&FLAG_C));
- break;
- case bcs:
- branch(p&FLAG_C);
- break;
- case bne:
- branch(!(p&FLAG_Z));
- break;
- case beq:
- branch(p&FLAG_Z);
- break;
- case bpl:
- branch(!(p&FLAG_N));
- break;
- case bmi:
- branch(p&FLAG_N);
- break;
- case bvc:
- branch(!(p&FLAG_V));
- break;
- case bvs:
- branch(p&FLAG_V);
- break;
- case bit:
- bval=getaddr(addr);
- setflags(FLAG_Z,!(a&bval));
- setflags(FLAG_N,bval&0x80);
- setflags(FLAG_V,bval&0x40);
- break;
- case _brk:
- pc=0; /* Just quit the emulation */
- break;
- case clc:
- setflags(FLAG_C,0);
- break;
- case cld:
- setflags(FLAG_D,0);
- break;
- case cli:
- setflags(FLAG_I,0);
- break;
- case clv:
- setflags(FLAG_V,0);
- break;
- case cmp:
- bval=getaddr(addr);
- wval=(unsigned short)a-bval;
- setflags(FLAG_Z,!wval);
- setflags(FLAG_N,wval&0x80);
- setflags(FLAG_C,a>=bval);
- break;
- case cpx:
- bval=getaddr(addr);
- wval=(unsigned short)x-bval;
- setflags(FLAG_Z,!wval);
- setflags(FLAG_N,wval&0x80);
- setflags(FLAG_C,x>=bval);
- break;
- case cpy:
- bval=getaddr(addr);
- wval=(unsigned short)y-bval;
- setflags(FLAG_Z,!wval);
- setflags(FLAG_N,wval&0x80);
- setflags(FLAG_C,y>=bval);
- break;
- case dec:
- bval=getaddr(addr);
- bval--;
- setaddr(addr,bval);
- setflags(FLAG_Z,!bval);
- setflags(FLAG_N,bval&0x80);
- break;
- case dex:
- x--;
- setflags(FLAG_Z,!x);
- setflags(FLAG_N,x&0x80);
- break;
- case dey:
- y--;
- setflags(FLAG_Z,!y);
- setflags(FLAG_N,y&0x80);
- break;
- case eor:
- bval=getaddr(addr);
- a^=bval;
- setflags(FLAG_Z,!a);
- setflags(FLAG_N,a&0x80);
- break;
- case inc:
- bval=getaddr(addr);
- bval++;
- setaddr(addr,bval);
- setflags(FLAG_Z,!bval);
- setflags(FLAG_N,bval&0x80);
- break;
- case inx:
- x++;
- setflags(FLAG_Z,!x);
- setflags(FLAG_N,x&0x80);
- break;
- case iny:
- y++;
- setflags(FLAG_Z,!y);
- setflags(FLAG_N,y&0x80);
- break;
- case jmp:
- wval=getmem(pc++);
- wval|=256*getmem(pc++);
- switch (addr)
- {
- case _abs:
- pc=wval;
- break;
- case ind:
- pc=getmem(wval);
- pc|=256*getmem(wval+1);
- break;
- }
- break;
- case jsr:
- push((pc+1)>>8);
- push((pc+1));
- wval=getmem(pc++);
- wval|=256*getmem(pc++);
- pc=wval;
- break;
- case lda:
- a=getaddr(addr);
- setflags(FLAG_Z,!a);
- setflags(FLAG_N,a&0x80);
- break;
- case ldx:
- x=getaddr(addr);
- setflags(FLAG_Z,!x);
- setflags(FLAG_N,x&0x80);
- break;
- case ldy:
- y=getaddr(addr);
- setflags(FLAG_Z,!y);
- setflags(FLAG_N,y&0x80);
- break;
- case lsr:
- bval=getaddr(addr); wval=(unsigned char)bval;
- wval>>=1;
- setaddr(addr,(unsigned char)wval);
- setflags(FLAG_Z,!wval);
- setflags(FLAG_N,wval&0x80);
- setflags(FLAG_C,bval&1);
- break;
- case _nop:
- break;
- case ora:
- bval=getaddr(addr);
- a|=bval;
- setflags(FLAG_Z,!a);
- setflags(FLAG_N,a&0x80);
- break;
- case pha:
- push(a);
- break;
- case php:
- push(p);
- break;
- case pla:
- a=pop();
- setflags(FLAG_Z,!a);
- setflags(FLAG_N,a&0x80);
- break;
- case plp:
- p=pop();
- break;
- case rol:
- bval=getaddr(addr);
- c=!!(p&FLAG_C);
- setflags(FLAG_C,bval&0x80);
- bval<<=1;
- bval|=c;
- setaddr(addr,bval);
- setflags(FLAG_N,bval&0x80);
- setflags(FLAG_Z,!bval);
- break;
- case ror:
- bval=getaddr(addr);
- c=!!(p&FLAG_C);
- setflags(FLAG_C,bval&1);
- bval>>=1;
- bval|=128*c;
- setaddr(addr,bval);
- setflags(FLAG_N,bval&0x80);
- setflags(FLAG_Z,!bval);
- break;
- case rti:
- /* Treat RTI like RTS */
- case rts:
- wval=pop();
- wval|=pop()<<8;
- pc=wval+1;
- break;
- case sbc:
- bval=getaddr(addr)^0xff;
- wval=(unsigned short)a+bval+((p&FLAG_C)?1:0);
- setflags(FLAG_C, wval&0x100);
- a=(unsigned char)wval;
- setflags(FLAG_Z, !a);
- setflags(FLAG_N, a>127);
- setflags(FLAG_V, (!!(p&FLAG_C)) ^ (!!(p&FLAG_N)));
- break;
- case sec:
- setflags(FLAG_C,1);
- break;
- case sed:
- setflags(FLAG_D,1);
- break;
- case sei:
- setflags(FLAG_I,1);
- break;
- case sta:
- putaddr(addr,a);
- break;
- case stx:
- putaddr(addr,x);
- break;
- case sty:
- putaddr(addr,y);
- break;
- case tax:
- x=a;
- setflags(FLAG_Z, !x);
- setflags(FLAG_N, x&0x80);
- break;
- case tay:
- y=a;
- setflags(FLAG_Z, !y);
- setflags(FLAG_N, y&0x80);
- break;
- case tsx:
- x=s;
- setflags(FLAG_Z, !x);
- setflags(FLAG_N, x&0x80);
- break;
- case txa:
- a=x;
- setflags(FLAG_Z, !a);
- setflags(FLAG_N, a&0x80);
- break;
- case txs:
- s=x;
- break;
- case tya:
- a=y;
- setflags(FLAG_Z, !a);
- setflags(FLAG_N, a&0x80);
- break;
- }
-}
-
-void cpuJSR(unsigned short npc, unsigned char na) ICODE_ATTR;
-void cpuJSR(unsigned short npc, unsigned char na)
-{
- a=na;
- x=0;
- y=0;
- p=0;
- s=255;
- pc=npc;
- push(0);
- push(0);
-
- while (pc > 1)
- cpuParse();
-
-}
-
-void c64Init(int nSampleRate) ICODE_ATTR;
-void c64Init(int nSampleRate)
-{
- synth_init(nSampleRate);
- memset(memory, 0, sizeof(memory));
-
- cpuReset();
-}
-
-
-
-unsigned short LoadSIDFromMemory(void *pSidData, unsigned short *load_addr,
- unsigned short *init_addr, unsigned short *play_addr, unsigned char *subsongs, unsigned char *startsong, unsigned char *speed, unsigned short size) ICODE_ATTR;
-unsigned short LoadSIDFromMemory(void *pSidData, unsigned short *load_addr,
- unsigned short *init_addr, unsigned short *play_addr, unsigned char *subsongs, unsigned char *startsong, unsigned char *speed, unsigned short size)
-{
- unsigned char *pData;
- unsigned char data_file_offset;
-
- pData = (unsigned char*)pSidData;
- data_file_offset = pData[7];
-
- *load_addr = pData[8]<<8;
- *load_addr|= pData[9];
-
- *init_addr = pData[10]<<8;
- *init_addr|= pData[11];
-
- *play_addr = pData[12]<<8;
- *play_addr|= pData[13];
-
- *subsongs = pData[0xf]-1;
- *startsong = pData[0x11]-1;
-
- *load_addr = pData[data_file_offset];
- *load_addr|= pData[data_file_offset+1]<<8;
-
- *speed = pData[0x15];
-
- memset(memory, 0, sizeof(memory));
- memcpy(&memory[*load_addr], &pData[data_file_offset+2], size-(data_file_offset+2));
-
- if (*play_addr == 0)
- {
- cpuJSR(*init_addr, 0);
- *play_addr = (memory[0x0315]<<8)+memory[0x0314];
+ for (bp = 0; bp < len; bp++) {
+ output = cRSID_generateSample(&cRSID_C64) << 12;
+ *(buffer_r + bp) = output; *(buffer_l + bp) = output;
}
-
- return *load_addr;
}
-static int nSamplesRendered = 0;
-static int nSamplesPerCall = 882; /* This is PAL SID single speed (44100/50Hz) */
-static int nSamplesToRender = 0;
-
-/* this is the codec entry point */
enum codec_status codec_main(enum codec_entry_call_reason reason)
{
if (reason == CODEC_LOAD) {
- /* Make use of 44.1khz */
ci->configure(DSP_SET_FREQUENCY, SAMPLE_RATE);
- /* Sample depth is 28 bit host endian */
ci->configure(DSP_SET_SAMPLE_DEPTH, 28);
- /* Stereo output */
ci->configure(DSP_SET_STEREO_MODE, STEREO_NONINTERLEAVED);
+ cRSID_init(SAMPLE_RATE, CHUNK_SIZE);
}
return CODEC_OK;
}
-/* this is called for each file to process */
enum codec_status codec_run(void)
{
+
+ cRSID_SIDheader *SIDheader;
size_t filesize;
- unsigned short load_addr, init_addr, play_addr;
- unsigned char subSongsMax, subSong, song_speed;
+ unsigned char subSong;
unsigned char *sidfile = NULL;
intptr_t param;
bool resume;
+ long action;
- if (codec_init()) {
+ if (codec_init())
return CODEC_ERROR;
- }
codec_set_replaygain(ci->id3);
- /* Load SID file the read_filebuf callback will return the full requested
- * size if at all possible, so there is no need to loop */
ci->seek_buffer(0);
sidfile = ci->request_buffer(&filesize, SID_BUFFER_SIZE);
-
- if (filesize == 0) {
+ if (filesize == 0)
return CODEC_ERROR;
- }
param = ci->id3->elapsed;
resume = param != 0;
- goto sid_start;
-
- /* The main decoder loop */
- while (1) {
- long action = ci->get_command(&param);
-
- if (action == CODEC_ACTION_HALT)
- break;
+ /* Start first song */
+ action = CODEC_ACTION_SEEK_TIME;
+ while (action != CODEC_ACTION_HALT) {
if (action == CODEC_ACTION_SEEK_TIME) {
- sid_start:
- /* New time is ready in param */
-
/* Start playing from scratch */
- c64Init(SAMPLE_RATE);
- LoadSIDFromMemory(sidfile, &load_addr, &init_addr, &play_addr,
- &subSongsMax, &subSong, &song_speed,
- (unsigned short)filesize);
- sidPoke(24, 15); /* Turn on full volume */
+ SIDheader = cRSID_processSIDfile(&cRSID_C64, sidfile, filesize);
+ subSong = SIDheader->DefaultSubtune - 1;
+
+ /* Now use the current seek time in seconds as subsong */
if (!resume || (resume && param))
- subSong = param / 1000; /* Now use the current seek time in
- seconds as subsong */
- cpuJSR(init_addr, subSong); /* Start the song initialize */
- nSamplesToRender = 0; /* Start the rendering from scratch */
+ subSong = param / 1000;
/* Set the elapsed time to the current subsong (in seconds) */
- ci->set_elapsed(subSong*1000);
+ ci->set_elapsed(subSong * 1000);
ci->seek_complete();
-
resume = false;
- }
-
- nSamplesRendered = 0;
- while (nSamplesRendered < CHUNK_SIZE)
- {
- if (nSamplesToRender == 0)
- {
- cpuJSR(play_addr, 0);
- /* Find out if cia timing is used and how many samples
- have to be calculated for each cpujsr */
- int nRefreshCIA = (int)(20000*(memory[0xdc04]|(memory[0xdc05]<<8))/0x4c00);
- if ((nRefreshCIA==0) || (song_speed == 0))
- nRefreshCIA = 20000;
- nSamplesPerCall = mixing_frequency*nRefreshCIA/1000000;
-
- nSamplesToRender = nSamplesPerCall;
- }
- if (nSamplesRendered + nSamplesToRender > CHUNK_SIZE)
- {
- synth_render(samples_r+nSamplesRendered, samples_l+nSamplesRendered, CHUNK_SIZE-nSamplesRendered);
- nSamplesToRender -= CHUNK_SIZE-nSamplesRendered;
- nSamplesRendered = CHUNK_SIZE;
- }
- else
- {
- synth_render(samples_r+nSamplesRendered, samples_l+nSamplesRendered, nSamplesToRender);
- nSamplesRendered += nSamplesToRender;
- nSamplesToRender = 0;
- }
+ cRSID_initSIDtune(&cRSID_C64, SIDheader, subSong + 1);
}
+ sid_render(samples_r, samples_l, CHUNK_SIZE);
ci->pcmbuf_insert(samples_r, samples_l, CHUNK_SIZE);
+
+ /* New time is in param */
+ action = ci->get_command(&param);
}
return CODEC_OK;