From f40bfc9267b13b54e6379dfe7539447662879d24 Mon Sep 17 00:00:00 2001 From: Sean Bartell Date: Sat, 25 Jun 2011 21:32:25 -0400 Subject: Add codecs to librbcodec. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: Id7f4717d51ed02d67cb9f9cb3c0ada4a81843f97 Reviewed-on: http://gerrit.rockbox.org/137 Reviewed-by: Nils Wallménius Tested-by: Nils Wallménius --- lib/rbcodec/codecs/libasap/CREDITS | 58 + lib/rbcodec/codecs/libasap/README | 148 ++ lib/rbcodec/codecs/libasap/README.rockbox | 22 + lib/rbcodec/codecs/libasap/SOURCES | 3 + lib/rbcodec/codecs/libasap/acpu.c | 1291 ++++++++++++++++ lib/rbcodec/codecs/libasap/anylang.h | 218 +++ lib/rbcodec/codecs/libasap/apokeysnd.c | 599 ++++++++ lib/rbcodec/codecs/libasap/asap.c | 2273 ++++++++++++++++++++++++++++ lib/rbcodec/codecs/libasap/asap.h | 328 ++++ lib/rbcodec/codecs/libasap/asap_internal.h | 115 ++ lib/rbcodec/codecs/libasap/libasap.make | 18 + lib/rbcodec/codecs/libasap/players.h | 1386 +++++++++++++++++ 12 files changed, 6459 insertions(+) create mode 100644 lib/rbcodec/codecs/libasap/CREDITS create mode 100644 lib/rbcodec/codecs/libasap/README create mode 100644 lib/rbcodec/codecs/libasap/README.rockbox create mode 100644 lib/rbcodec/codecs/libasap/SOURCES create mode 100644 lib/rbcodec/codecs/libasap/acpu.c create mode 100644 lib/rbcodec/codecs/libasap/anylang.h create mode 100644 lib/rbcodec/codecs/libasap/apokeysnd.c create mode 100644 lib/rbcodec/codecs/libasap/asap.c create mode 100644 lib/rbcodec/codecs/libasap/asap.h create mode 100644 lib/rbcodec/codecs/libasap/asap_internal.h create mode 100644 lib/rbcodec/codecs/libasap/libasap.make create mode 100644 lib/rbcodec/codecs/libasap/players.h (limited to 'lib/rbcodec/codecs/libasap') diff --git a/lib/rbcodec/codecs/libasap/CREDITS b/lib/rbcodec/codecs/libasap/CREDITS new file mode 100644 index 0000000000..387cbb6266 --- /dev/null +++ b/lib/rbcodec/codecs/libasap/CREDITS @@ -0,0 +1,58 @@ +Authors +------- + +Piotr Fusik {asapwww!}:: +Creator and main developer. + +Atari800 Emulator Developers {asapwww!(http://atari800.sourceforge.net)}:: +6502 and POKEY emulation used in 0.x.y versions of ASAP. + +Zdenek Eisenhammer {asapwww!}:: +Testing. + +Henryk Karpowicz {asapwww!}:: +CMC routine modified for the CM3 format. + +Maciek Konecki {asapwww!}:: +Porting to C#. + +Marek Konopka {asapwww!}:: +6502 routine for playing DLT. + +Marcin Lewandowski {asapwww!}:: +6502 routines for playing CMC, MPT, TMC and TM2. + +Adrian Matoga {asapwww!}:: +COVOX information and test files. Testing. + +Perry McFarlane {asapwww!}:: +POKEY reverse-engineering. + +Kostas Nakos {asapwww!}:: +Windows CE testing. + +Mariusz Rozwadowski {asapwww!}:: +Suggested CMS, CM3 and DLT format support. + +Slawomir Sledz {asapwww!}:: +Testing. + +David Spilka:: +6502 routine for playing CMS. + +Radek Sterba {asapwww!}:: +6502 routine for playing RMT. +Testing. + +Lukasz Sychowicz {asapwww!}:: +Windows icons. +Testing. + +Pawel Szewczyk {asapwww!}:: +Windows setup graphics. + +Michal Szpilowski {asapwww!}:: +Testing. + +Grzegorz Zyla {asapwww!}:: +XBMC plugin testing. diff --git a/lib/rbcodec/codecs/libasap/README b/lib/rbcodec/codecs/libasap/README new file mode 100644 index 0000000000..d4fbfe6297 --- /dev/null +++ b/lib/rbcodec/codecs/libasap/README @@ -0,0 +1,148 @@ +ASAP - Another Slight Atari Player +================================== + +// This file is in AsciiDoc format. It is converted to README.html. +:Compact-Option: + +ifdef::asapwww[] +http://sourceforge.net/projects/asap/files/asap/[Download] | +http://asap.git.sourceforge.net/git/gitweb.cgi?p=asap/asap;a=summary[Browse source code (Git)] | +http://sourceforge.net/scm/?type=git&group_id=154391[Get latest source code (Git)] | +http://sourceforge.net/projects/asap/[SourceForge project page] +endif::asapwww[] + +ASAP is a player of http://en.wikipedia.org/wiki/Atari_8-bit_family[8-bit Atari] +music for modern computers. +It emulates the http://en.wikipedia.org/wiki/POKEY[POKEY sound chip] +and the http://en.wikipedia.org/wiki/6502[6502 processor]. +The project was initially based on the routines from the +http://atari800.sourceforge.net/[Atari800 emulator], +but the current version has a completely new original emulation core. + +ASAP includes the following programs: + +- asapconv - portable command-line converter {asapwin=} +- WASAP - tiny player for Windows {asapwin=}{asapwince=} +- plugin for http://koti.welho.com/hylinen/apollo/[Apollo] {asapwin=} +- plugin for http://audacious-media-player.org/[Audacious] +- plugin for http://foobar2000.org/[foobar2000] {asapwin=} +- plugin for http://hp.vector.co.jp/authors/VA032810/[GSPlayer] {asapwin=}{asapwince=} +- plugin for http://moc.daper.net/[MOC] +- plugin for http://www.winamp.com/[Winamp] {asapwin=} +- plugin for http://www.microsoft.com/windows/windowsmedia/player/[Windows Media Player] {asapwin=} +- plugin for http://xbmc.org/[XBMC] {asapwin=} +- plugin for http://xmms.org/[XMMS] +- plugin for http://www.un4seen.com/xmplay.html[XMPlay] {asapwin=} +- add-on for http://www.un4seen.com/bass.html[BASS] (for http://www.aimp.ru/[AIMP] and http://www.un4seen.com/bass_showcase.php[other players]) {asapwin=} +- POKEY sound emulation DLL for http://raster.infos.cz/atari/rmt/rmt.htm[Raster Music Tracker] {asapwin=} +- Windows Explorer extension - shows metadata {asapwin=} +- Java version of ASAP2WAV - command-line converter to WAV files {asapjava=} +- Java applet - for web pages {asapjava=}{asapwww?(see link:applet.html[online demo])} +- Java midlet - for mobile devices {asapjava=} +- C# version of ASAP2WAV +- JavaScript version of ASAP2WAV running in http://en.wikipedia.org/wiki/Windows_Script_Host[Windows Script Host], https://developer.mozilla.org/en/Rhino_Shell[Rhino Shell], http://code.google.com/p/v8/[V8 Shell], http://en.wikipedia.org/wiki/JScript_.NET[JScript .NET] and http://en.wikipedia.org/wiki/JaegerMonkey[JaegerMonkey] {asapjavascript=} +- experimental JavaScript version of ASAP2WAV running in Firefox {asapjavascript=} +- Flash player - for web pages {asapflash=}{asapwww?(see link:flash.html[online demo])} +- asapplay - simple command-line player in C# +- http://www.silverlight.net/[Silverlight] player - for web pages {asapwww?(see link:silverlight.html[online demo])} +- AndroidASAP - for mobile devices + +{asapports}The summary of the differences between the above versions is in link:PORTS.xml[this table]. + +There are other projects which use ASAP: + +- http://mmsap.sourceforge.net/[mmSAP 2] - standalone player for GNU/Linux with GTK+ user interface +- http://www.rockbox.org/[Rockbox] - open source firmware for MP3 players + + +Input file formats +------------------ + +ASAP supports the following file formats (determined by the filename extension): + +SAP (Slight Atari Player):: +The format designed for playing 8-bit Atari music on modern computers. +All other formats can be converted to SAP. +http://asma.atari.org/[Atari SAP Music Archive (ASMA)] +is a single big collection of SAP files. + +CMC (Chaos Music Composer):: +Atari music editor from early 1990s. + +CM3 (CMC "3/4"):: +CMC with modified pattern length. + +CMR (CMC "Rzog"):: +CMC with modified bass sounds. + +CMS (Stereo Double CMC):: +Stereo CMC. + +DMC (DoublePlay CMC):: +CMC with 6502 routine executed at double rate of the original CMC. + +DLT (Delta Music Composer):: +Atari music editor from 1990s. + +MPT (Music ProTracker):: +Atari music editor from 1990s. + +MPD (MPT DoublePlay):: +MPT with 6502 routine executed at double rate of the original MPT. + +RMT (http://raster.infos.cz/atari/rmt/rmt.htm[Raster Music Tracker]):: +Modern Atari music editor running on Windows. + +TMC, TM8 (http://jaskier.atari8.info/[Theta Music Composer] 1.x):: +Atari music editor from late 1990s. +The two file extensions are treated identically and played in stereo. +TM8 means it's stereo (8-channel) music while TMC can be either mono or stereo. + +TM2 (http://jaskier.atari8.info/[Theta Music Composer] 2.x):: +Modern Atari music editor. + + +ifdef::asapsrc[] +include::INSTALL[] +endif::asapsrc[] + +ifdef::asapflash[] +include::flash/USAGE[] +endif::asapflash[] + +ifdef::asapjava[] +include::java/USAGE[] +endif::asapjava[] + +ifdef::asapjavascript[] +include::javascript/USAGE[] +endif::asapjavascript[] + +ifdef::asapwin[] +include::win32/USAGE[] +endif::asapwin[] + +ifdef::asapwince[] +include::win32/wince/USAGE[] +endif::asapwince[] + +include::NEWS[] + +include::CREDITS[] + + +Feedback +-------- + +If you are interested in the ASAP project, please subscribe its +https://lists.sourceforge.net/lists/listinfo/asap-users[mailing list]. +This list is for users and developers. +Once you subscribe, you can post comments, ideas and questions about ASAP. +They will be answered ASAP. ;-) + +Use http://sourceforge.net/tracker/?group_id=154391[tracker] +to submit bug reports, feature requests and small code patches. + +ifdef::asapwww[] +image::http://sflogo.sourceforge.net/sflogo.php?group_id=154391&type=13["Get ASAP - Another Slight Atari Player at SourceForge.net. Fast, secure and Free Open Source software downloads",width=120,height=30,link="http://sourceforge.net/projects/asap/"] +endif::asapwww[] diff --git a/lib/rbcodec/codecs/libasap/README.rockbox b/lib/rbcodec/codecs/libasap/README.rockbox new file mode 100644 index 0000000000..62184822d4 --- /dev/null +++ b/lib/rbcodec/codecs/libasap/README.rockbox @@ -0,0 +1,22 @@ +Library: asap-2.1.2 +Imported: 2010-02-02 by Dominik Wenger +Updated: 2010-08-11 by Dominik Wenger + +This directory contains a local version of asap (http://asap.sourceforge.net/) for decoding Atari 8bit .sap +audio streams. + +LICENSING INFORMATION + +Asap is available under the terms of the GPL v2 or later +license, which is both an open source and free software license. +The Licence is the same as the rest of Rockbox. + + +IMPORT DETAILS + +The .[ch] files in apps/codec/libasap are copied from ASAP. + +players.h (contains binarys of players) was generated and copied +into Rockbox. + + diff --git a/lib/rbcodec/codecs/libasap/SOURCES b/lib/rbcodec/codecs/libasap/SOURCES new file mode 100644 index 0000000000..0d1f1f46fa --- /dev/null +++ b/lib/rbcodec/codecs/libasap/SOURCES @@ -0,0 +1,3 @@ +acpu.c +asap.c +apokeysnd.c diff --git a/lib/rbcodec/codecs/libasap/acpu.c b/lib/rbcodec/codecs/libasap/acpu.c new file mode 100644 index 0000000000..0fd5988b83 --- /dev/null +++ b/lib/rbcodec/codecs/libasap/acpu.c @@ -0,0 +1,1291 @@ +/* + * acpu.c - another 6502 CPU emulator + * + * Copyright (C) 2007-2010 Piotr Fusik + * + * This file is part of ASAP (Another Slight Atari Player), + * see http://asap.sourceforge.net + * + * ASAP is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2 of the License, + * or (at your option) any later version. + * + * ASAP is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ASAP; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* How 6502 registers are stored in this emulator: + All variables are int, because modern processors (and Java bytecode) + tend to operate more effectively on these type than narrower ones. + pc is really an unsigned 16-bit integer. + a, x, y and s are unsigned 8-bit integers. + Flags are decomposed into three variables for improved performance. + c is either 0 or 1. + nz contains 6502 flags N and Z. + N is set if (nz >= 0x80). Z is set if ((nz & 0xff) == 0). + Usually nz is simply assigned the unsigned 8-bit operation result. + There are just a few operations (ADC in decimal mode, BIT, PLP and RTI) + where both N and Z may be set. In these cases, N is reflected by the 8th + (not 7th) bit of nz. + vdi contains rarely used flags V, D and I, as a combination + of V_FLAG, D_FLAG and I_FLAG. Other vdi bits are clear. + + "Unofficial" opcodes are not documented as "legal" 6502 opcodes. + Their operation has been reverse-engineered on Atari 800XL and Atari 65XE. + Unofficial opcodes are identical to C64's 6510, except for 0x8b and 0xab. + The operation of "unstable" opcodes is partially uncertain. + Explanation is welcome. + + Emulation of POKEY timer interrupts is included. + + Two preprocessor symbols may be used to strip the size of this emulator. + Define ACPU_NO_DECIMAL to disable emulation of the BCD mode. + Define ACPU_NO_UNOFFICIAL to disable emulation of unofficial opcodes. */ + +#include "asap_internal.h" + +CONST_ARRAY(int, opcode_cycles) +/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ + 7, 6, 2, 8, 3, 3, 5, 5, 3, 2, 2, 2, 4, 4, 6, 6, /* 0x */ + 2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7, /* 1x */ + 6, 6, 2, 8, 3, 3, 5, 5, 4, 2, 2, 2, 4, 4, 6, 6, /* 2x */ + 2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7, /* 3x */ + 6, 6, 2, 8, 3, 3, 5, 5, 3, 2, 2, 2, 3, 4, 6, 6, /* 4x */ + 2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7, /* 5x */ + 6, 6, 2, 8, 3, 3, 5, 5, 4, 2, 2, 2, 5, 4, 6, 6, /* 6x */ + 2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7, /* 7x */ + 2, 6, 2, 6, 3, 3, 3, 3, 2, 2, 2, 2, 4, 4, 4, 4, /* 8x */ + 2, 6, 2, 6, 4, 4, 4, 4, 2, 5, 2, 5, 5, 5, 5, 5, /* 9x */ + 2, 6, 2, 6, 3, 3, 3, 3, 2, 2, 2, 2, 4, 4, 4, 4, /* Ax */ + 2, 5, 2, 5, 4, 4, 4, 4, 2, 4, 2, 4, 4, 4, 4, 4, /* Bx */ + 2, 6, 2, 8, 3, 3, 5, 5, 2, 2, 2, 2, 4, 4, 6, 6, /* Cx */ + 2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7, /* Dx */ + 2, 6, 2, 8, 3, 3, 5, 5, 2, 2, 2, 2, 4, 4, 6, 6, /* Ex */ + 2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7 /* Fx */ +END_CONST_ARRAY; + +#ifdef ACPU_NO_DECIMAL + +#define DO_ADC \ + { \ + /* binary mode */ \ + V(int, tmp) = a + data + c; \ + vdi = (vdi & (D_FLAG | I_FLAG)) + (((~(data ^ a) & (a ^ tmp)) >> 1) & V_FLAG); \ + c = tmp >> 8; \ + nz = a = tmp & 0xff; \ + } + +#define DO_SBC \ + { \ + /* binary mode */ \ + V(int, tmp) = a - data - 1 + c; \ + vdi = (vdi & (D_FLAG | I_FLAG)) + ((((data ^ a) & (a ^ tmp)) >> 1) & V_FLAG); \ + c = (tmp >= 0) ? 1 : 0; \ + nz = a = tmp & 0xff; \ + } + +#else /* ACPU_NO_DECIMAL */ + +#define DO_ADC \ + { \ + V(int, tmp) = a + data + c; \ + nz = tmp & 0xff; \ + if ((vdi & D_FLAG) == 0) { \ + /* binary mode */ \ + vdi = (vdi & (D_FLAG | I_FLAG)) + (((~(data ^ a) & (a ^ tmp)) >> 1) & V_FLAG); \ + c = tmp >> 8; \ + a = nz; \ + } \ + else { \ + /* decimal mode */ \ + V(int, al) = (a & 0x0f) + (data & 0x0f) + c; \ + if (al >= 10) \ + tmp += (al < 26) ? 6 : -10; \ + nz = ((tmp & 0x80) << 1) + (nz != 0 ? 1 : 0); \ + vdi = (vdi & (D_FLAG | I_FLAG)) + (((~(data ^ a) & (a ^ tmp)) >> 1) & V_FLAG); \ + if (tmp >= 0xa0) { \ + c = 1; \ + a = (tmp + 0x60) & 0xff; \ + } \ + else { \ + c = 0; \ + a = tmp; \ + } \ + } \ + } + +#define DO_SBC \ + {\ + V(int, tmp) = a - data - 1 + c; \ + V(int, al) = (a & 0x0f) - (data & 0x0f) - 1 + c; \ + vdi = (vdi & (D_FLAG | I_FLAG)) + ((((data ^ a) & (a ^ tmp)) >> 1) & V_FLAG); \ + c = (tmp >= 0) ? 1 : 0; \ + nz = a = tmp & 0xff; \ + if ((vdi & D_FLAG) != 0) { \ + /* decimal mode */ \ + if (al < 0) \ + a += (al < -10) ? 10 : -6; \ + if (c == 0) \ + a = (a - 0x60) & 0xff; \ + } \ + } + +#endif /* ACPU_NO_DECIMAL */ + +#define zGetByte(addr) dGetByte((addr) & 0xff) + +#define PEEK dGetByte(pc) +#define FETCH dGetByte(pc++) + +#define ABSOLUTE addr = FETCH; addr += FETCH << 8 +#define ABSOLUTE_X addr = FETCH; addr = (addr + (FETCH << 8) + x) & 0xffff +#define ABSOLUTE_Y addr = FETCH; addr = (addr + (FETCH << 8) + y) & 0xffff +#define ZPAGE addr = FETCH +#define ZPAGE_X addr = (FETCH + x) & 0xff +#define ZPAGE_Y addr = (FETCH + y) & 0xff +#define INDIRECT_X addr = (FETCH + x) & 0xff; addr = dGetByte(addr) + (zGetByte(addr + 1) << 8) +#define INDIRECT_Y addr = FETCH; addr = (dGetByte(addr) + (zGetByte(addr + 1) << 8) + y) & 0xffff +#define NCYCLES_X if ((addr & 0xff) < x) ast _ cycle++ +#define NCYCLES_Y if ((addr & 0xff) < y) ast _ cycle++ + +#define PL(dest) s = (s + 1) & 0xff; dest = dGetByte(0x0100 + s) +#define PLP PL(vdi); nz = ((vdi & 0x80) << 1) + (~vdi & Z_FLAG); c = vdi & 1; vdi &= V_FLAG | D_FLAG | I_FLAG +#define PH(data) dPutByte(0x0100 + s, data); s = (s - 1) & 0xff +#define PHW(data) PH((data) >> 8); PH(TO_BYTE(data)) +#define PHP(bflag) PH(((nz | (nz >> 1)) & 0x80) + vdi + ((nz & 0xff) == 0 ? Z_FLAG : 0) + c + bflag) +#define PHPB0 PHP(0x20) /* push flags with B flag clear (NMI, IRQ) */ +#define PHPB1 PHP(0x30) /* push flags with B flag set (PHP, BRK) */ +#define PHPC PHW(pc) + +#define LDA nz = a = GetByte(addr) +#define LDA_ZP nz = a = dGetByte(addr) +#define LDX nz = x = GetByte(addr) +#define LDX_ZP nz = x = dGetByte(addr) +#define LDY nz = y = GetByte(addr) +#define LDY_ZP nz = y = dGetByte(addr) +#define LAX nz = x = a = GetByte(addr) +#define LAX_ZP nz = x = a = dGetByte(addr) +#define STA PutByte(addr, a) +#define STA_ZP dPutByte(addr, a) +#define STX PutByte(addr, x) +#define STX_ZP dPutByte(addr, x) +#define STY PutByte(addr, y) +#define STY_ZP dPutByte(addr, y) +#define SAX data = a & x; PutByte(addr, data) +#define SAX_ZP data = a & x; dPutByte(addr, data) +#define CMP nz = GetByte(addr); c = (a >= nz) ? 1 : 0; nz = (a - nz) & 0xff +#define CMP_ZP nz = dGetByte(addr); c = (a >= nz) ? 1 : 0; nz = (a - nz) & 0xff +#define CPX nz = GetByte(addr); c = (x >= nz) ? 1 : 0; nz = (x - nz) & 0xff +#define CPX_ZP nz = dGetByte(addr); c = (x >= nz) ? 1 : 0; nz = (x - nz) & 0xff +#define CPY nz = GetByte(addr); c = (y >= nz) ? 1 : 0; nz = (y - nz) & 0xff +#define CPY_ZP nz = dGetByte(addr); c = (y >= nz) ? 1 : 0; nz = (y - nz) & 0xff +#define AND nz = a &= GetByte(addr) +#define AND_ZP nz = a &= dGetByte(addr) +#define ORA nz = a |= GetByte(addr) +#define ORA_ZP nz = a |= dGetByte(addr) +#define EOR nz = a ^= GetByte(addr) +#define EOR_ZP nz = a ^= dGetByte(addr) +#define ADC data = GetByte(addr); DO_ADC +#define ADC_ZP data = dGetByte(addr); DO_ADC +#define SBC data = GetByte(addr); DO_SBC +#define SBC_ZP data = dGetByte(addr); DO_SBC + +#define ASL RMW_GetByte(nz, addr); c = nz >> 7; nz = (nz << 1) & 0xff; PutByte(addr, nz) +#define ASL_ZP nz = dGetByte(addr); c = nz >> 7; nz = (nz << 1) & 0xff; dPutByte(addr, nz) +#define ROL RMW_GetByte(nz, addr); nz = (nz << 1) + c; c = nz >> 8; nz &= 0xff; PutByte(addr, nz) +#define ROL_ZP nz = dGetByte(addr); nz = (nz << 1) + c; c = nz >> 8; nz &= 0xff; dPutByte(addr, nz) +#define LSR RMW_GetByte(nz, addr); c = nz & 1; nz >>= 1; PutByte(addr, nz) +#define LSR_ZP nz = dGetByte(addr); c = nz & 1; nz >>= 1; dPutByte(addr, nz) +#define ROR RMW_GetByte(nz, addr); nz += c << 8; c = nz & 1; nz >>= 1; PutByte(addr, nz) +#define ROR_ZP nz = dGetByte(addr) + (c << 8); c = nz & 1; nz >>= 1; dPutByte(addr, nz) +#define DEC RMW_GetByte(nz, addr); nz = (nz - 1) & 0xff; PutByte(addr, nz) +#define DEC_ZP nz = dGetByte(addr); nz = (nz - 1) & 0xff; dPutByte(addr, nz) +#define INC RMW_GetByte(nz, addr); nz = (nz + 1) & 0xff; PutByte(addr, nz) +#define INC_ZP nz = dGetByte(addr); nz = (nz + 1) & 0xff; dPutByte(addr, nz) + +#define ASO ASL; nz = a |= nz +#define ASO_ZP ASL_ZP; nz = a |= nz +#define RLA ROL; nz = a &= nz +#define RLA_ZP ROL_ZP; nz = a &= nz +#define LSE LSR; nz = a ^= nz +#define LSE_ZP LSR_ZP; nz = a ^= nz +#define RRA ROR; data = nz; DO_ADC +#define RRA_ZP ROR_ZP; data = nz; DO_ADC +#define DCM DEC; c = (a >= nz) ? 1 : 0; nz = (a - nz) & 0xff +#define DCM_ZP DEC_ZP; c = (a >= nz) ? 1 : 0; nz = (a - nz) & 0xff +#define INS INC; data = nz; DO_SBC +#define INS_ZP INC_ZP; data = nz; DO_SBC + +#define BRANCH(cond) \ + if (cond) { \ + addr = SBYTE(PEEK); \ + pc++; \ + addr += pc; \ + if ((addr ^ pc) >> 8 != 0) \ + ast _ cycle++; \ + ast _ cycle++; \ + pc = addr; \ + break; \ + } \ + pc++; \ + break + +#define CHECK_IRQ \ + if ((vdi & I_FLAG) == 0 && ast _ irqst != 0xff) { \ + PHPC; \ + PHPB0; \ + vdi |= I_FLAG; \ + pc = dGetWord(0xfffe); \ + ast _ cycle += 7; \ + } + +/* Runs 6502 emulation for the specified number of Atari scanlines. + Each scanline is 114 cycles of which 9 is taken by ANTIC for memory refresh. */ +FUNC(void, Cpu_RunScanlines, (P(ASAP_State PTR, ast), P(int, scanlines))) +{ + /* copy registers from ASAP_State to local variables for improved performance */ + V(int, pc); + V(int, nz); + V(int, a); + V(int, x); + V(int, y); + V(int, c); + V(int, s); + V(int, vdi); + V(int, next_event_cycle); + V(int, cycle_limit); + pc = ast _ cpu_pc; + nz = ast _ cpu_nz; + a = ast _ cpu_a; + x = ast _ cpu_x; + y = ast _ cpu_y; + c = ast _ cpu_c; + s = ast _ cpu_s; + vdi = ast _ cpu_vdi; + ast _ next_scanline_cycle = 114; + next_event_cycle = 114; + cycle_limit = 114 * scanlines; + if (next_event_cycle > ast _ timer1_cycle) + next_event_cycle = ast _ timer1_cycle; + if (next_event_cycle > ast _ timer2_cycle) + next_event_cycle = ast _ timer2_cycle; + if (next_event_cycle > ast _ timer4_cycle) + next_event_cycle = ast _ timer4_cycle; + ast _ nearest_event_cycle = next_event_cycle; + for (;;) { + V(int, cycle); + V(int, addr); + V(int, data); + cycle = ast _ cycle; + if (cycle >= ast _ nearest_event_cycle) { + if (cycle >= ast _ next_scanline_cycle) { + if (++ast _ scanline_number == (ast _ module_info->ntsc ? 262 : 312)) + ast _ scanline_number = 0; + ast _ cycle = cycle += 9; + ast _ next_scanline_cycle += 114; + if (--scanlines <= 0) + break; + } + next_event_cycle = ast _ next_scanline_cycle; +#define CHECK_TIMER_IRQ(ch) \ + if (cycle >= ast _ timer##ch##_cycle) { \ + ast _ irqst &= ~ch; \ + ast _ timer##ch##_cycle = NEVER; \ + } \ + else if (next_event_cycle > ast _ timer##ch##_cycle) \ + next_event_cycle = ast _ timer##ch##_cycle; + CHECK_TIMER_IRQ(1); + CHECK_TIMER_IRQ(2); + CHECK_TIMER_IRQ(4); + ast _ nearest_event_cycle = next_event_cycle; + CHECK_IRQ; + } +#ifdef ASAPSCAN + if (cpu_trace != 0) + trace_cpu(ast, pc, a, x, y, s, nz, vdi, c); +#endif + data = FETCH; + ast _ cycle += opcode_cycles[data]; + switch (data) { + case 0x00: /* BRK */ + pc++; + PHPC; + PHPB1; + vdi |= I_FLAG; + pc = dGetWord(0xfffe); + break; + case 0x01: /* ORA (ab,x) */ + INDIRECT_X; + ORA; + break; + case 0x02: /* CIM [unofficial] */ + case 0x12: + case 0x22: + case 0x32: + case 0x42: + case 0x52: + case 0x62: + case 0x72: + case 0x92: + case 0xb2: + case 0xd2: + case 0xf2: + ast _ scanline_number = (ast _ scanline_number + scanlines - 1) % (ast _ module_info->ntsc ? 262 : 312); + scanlines = 1; + ast _ cycle = cycle_limit; + break; +#ifndef ACPU_NO_UNOFFICIAL + case 0x03: /* ASO (ab,x) [unofficial] */ + INDIRECT_X; + ASO; + break; + case 0x04: /* NOP ab [unofficial] */ + case 0x44: + case 0x64: + case 0x14: /* NOP ab,x [unofficial] */ + case 0x34: + case 0x54: + case 0x74: + case 0xd4: + case 0xf4: + case 0x80: /* NOP #ab [unofficial] */ + case 0x82: + case 0x89: + case 0xc2: + case 0xe2: + pc++; + break; + case 0x07: /* ASO ab [unofficial] */ + ZPAGE; + ASO_ZP; + break; + case 0x0b: /* ANC #ab [unofficial] */ + case 0x2b: + nz = a &= FETCH; + c = nz >> 7; + break; + case 0x0c: /* NOP abcd [unofficial] */ + pc += 2; + break; + case 0x0f: /* ASO abcd [unofficial] */ + ABSOLUTE; + ASO; + break; + case 0x13: /* ASO (ab),y [unofficial] */ + INDIRECT_Y; + ASO; + break; + case 0x17: /* ASO ab,x [unofficial] */ + ZPAGE_X; + ASO_ZP; + break; + case 0x1b: /* ASO abcd,y [unofficial] */ + ABSOLUTE_Y; + ASO; + break; + case 0x1c: /* NOP abcd,x [unofficial] */ + case 0x3c: + case 0x5c: + case 0x7c: + case 0xdc: + case 0xfc: + if (FETCH + x >= 0x100) + ast _ cycle++; + pc++; + break; + case 0x1f: /* ASO abcd,x [unofficial] */ + ABSOLUTE_X; + ASO; + break; + case 0x23: /* RLA (ab,x) [unofficial] */ + INDIRECT_X; + RLA; + break; + case 0x27: /* RLA ab [unofficial] */ + ZPAGE; + RLA_ZP; + break; + case 0x2f: /* RLA abcd [unofficial] */ + ABSOLUTE; + RLA; + break; + case 0x33: /* RLA (ab),y [unofficial] */ + INDIRECT_Y; + RLA; + break; + case 0x37: /* RLA ab,x [unofficial] */ + ZPAGE_X; + RLA_ZP; + break; + case 0x3b: /* RLA abcd,y [unofficial] */ + ABSOLUTE_Y; + RLA; + break; + case 0x3f: /* RLA abcd,x [unofficial] */ + ABSOLUTE_X; + RLA; + break; + case 0x43: /* LSE (ab,x) [unofficial] */ + INDIRECT_X; + LSE; + break; + case 0x47: /* LSE ab [unofficial] */ + ZPAGE; + LSE_ZP; + break; + case 0x4b: /* ALR #ab [unofficial] */ + a &= FETCH; + c = a & 1; + nz = a >>= 1; + break; + case 0x4f: /* LSE abcd [unofficial] */ + ABSOLUTE; + LSE; + break; + case 0x53: /* LSE (ab),y [unofficial] */ + INDIRECT_Y; + LSE; + break; + case 0x57: /* LSE ab,x [unofficial] */ + ZPAGE_X; + LSE_ZP; + break; + case 0x5b: /* LSE abcd,y [unofficial] */ + ABSOLUTE_Y; + LSE; + break; + case 0x5f: /* LSE abcd,x [unofficial] */ + ABSOLUTE_X; + LSE; + break; + case 0x63: /* RRA (ab,x) [unofficial] */ + INDIRECT_X; + RRA; + break; + case 0x67: /* RRA ab [unofficial] */ + ZPAGE; + RRA_ZP; + break; + case 0x6b: /* ARR #ab [unofficial] */ + data = a & FETCH; + nz = a = (data >> 1) + (c << 7); + vdi = (vdi & (D_FLAG | I_FLAG)) + ((a ^ data) & V_FLAG); +#ifdef ACPU_NO_DECIMAL + c = data >> 7; +#else + if ((vdi & D_FLAG) == 0) + c = data >> 7; + else { + if ((data & 0xf) >= 5) + a = (a & 0xf0) + ((a + 6) & 0xf); + if (data >= 0x50) { + a = (a + 0x60) & 0xff; + c = 1; + } + else + c = 0; + } +#endif + break; + case 0x6f: /* RRA abcd [unofficial] */ + ABSOLUTE; + RRA; + break; + case 0x73: /* RRA (ab),y [unofficial] */ + INDIRECT_Y; + RRA; + break; + case 0x77: /* RRA ab,x [unofficial] */ + ZPAGE_X; + RRA_ZP; + break; + case 0x7b: /* RRA abcd,y [unofficial] */ + ABSOLUTE_Y; + RRA; + break; + case 0x7f: /* RRA abcd,x [unofficial] */ + ABSOLUTE_X; + RRA; + break; + case 0x83: /* SAX (ab,x) [unofficial] */ + INDIRECT_X; + SAX; + break; + case 0x87: /* SAX ab [unofficial] */ + ZPAGE; + SAX_ZP; + break; + case 0x8b: /* ANE #ab [unofficial] */ + data = FETCH; + a &= x; + nz = a & data; + a &= data | 0xef; + break; + case 0x8f: /* SAX abcd [unofficial] */ + ABSOLUTE; + SAX; + break; + case 0x93: /* SHA (ab),y [unofficial, unstable] */ + ZPAGE; + data = zGetByte(addr + 1); + addr = (dGetByte(addr) + (data << 8) + y) & 0xffff; + data = a & x & (data + 1); + PutByte(addr, data); + break; + case 0x97: /* SAX ab,y [unofficial] */ + ZPAGE_Y; + SAX_ZP; + break; + case 0x9b: /* SHS abcd,y [unofficial, unstable] */ + /* S seems to be stable, only memory values vary */ + addr = FETCH; + data = FETCH; + addr = (addr + (data << 8) + y) & 0xffff; + s = a & x; + data = s & (data + 1); + PutByte(addr, data); + break; + case 0x9c: /* SHY abcd,x [unofficial] */ + addr = FETCH; + data = FETCH; + addr = (addr + (data << 8) + x) & 0xffff; + data = y & (data + 1); + PutByte(addr, data); + break; + case 0x9e: /* SHX abcd,y [unofficial] */ + addr = FETCH; + data = FETCH; + addr = (addr + (data << 8) + y) & 0xffff; + data = x & (data + 1); + PutByte(addr, data); + break; + case 0x9f: /* SHA abcd,y [unofficial, unstable] */ + addr = FETCH; + data = FETCH; + addr = (addr + (data << 8) + y) & 0xffff; + data = a & x & (data + 1); + PutByte(addr, data); + break; + case 0xa3: /* LAX (ab,x) [unofficial] */ + INDIRECT_X; + LAX; + break; + case 0xa7: /* LAX ab [unofficial] */ + ZPAGE; + LAX_ZP; + break; + case 0xab: /* ANX #ab [unofficial] */ + nz = x = a &= FETCH; + break; + case 0xaf: /* LAX abcd [unofficial] */ + ABSOLUTE; + LAX; + break; + case 0xb3: /* LAX (ab),y [unofficial] */ + INDIRECT_Y; + NCYCLES_Y; + LAX; + break; + case 0xb7: /* LAX ab,y [unofficial] */ + ZPAGE_Y; + LAX_ZP; + break; + case 0xbb: /* LAS abcd,y [unofficial] */ + ABSOLUTE_Y; + NCYCLES_Y; + nz = x = a = s &= GetByte(addr); + break; + case 0xbf: /* LAX abcd,y [unofficial] */ + ABSOLUTE_Y; + NCYCLES_Y; + LAX; + break; + case 0xc3: /* DCM (ab,x) [unofficial] */ + INDIRECT_X; + DCM; + break; + case 0xc7: /* DCM ab [unofficial] */ + ZPAGE; + DCM_ZP; + break; + case 0xcb: /* SBX #ab [unofficial] */ + nz = FETCH; + x &= a; + c = (x >= nz) ? 1 : 0; + nz = x = (x - nz) & 0xff; + break; + case 0xcf: /* DCM abcd [unofficial] */ + ABSOLUTE; + DCM; + break; + case 0xd3: /* DCM (ab),y [unofficial] */ + INDIRECT_Y; + DCM; + break; + case 0xd7: /* DCM ab,x [unofficial] */ + ZPAGE_X; + DCM_ZP; + break; + case 0xdb: /* DCM abcd,y [unofficial] */ + ABSOLUTE_Y; + DCM; + break; + case 0xdf: /* DCM abcd,x [unofficial] */ + ABSOLUTE_X; + DCM; + break; + case 0xe3: /* INS (ab,x) [unofficial] */ + INDIRECT_X; + INS; + break; + case 0xe7: /* INS ab [unofficial] */ + ZPAGE; + INS_ZP; + break; + case 0xef: /* INS abcd [unofficial] */ + ABSOLUTE; + INS; + break; + case 0xf3: /* INS (ab),y [unofficial] */ + INDIRECT_Y; + INS; + break; + case 0xf7: /* INS ab,x [unofficial] */ + ZPAGE_X; + INS_ZP; + break; + case 0xfb: /* INS abcd,y [unofficial] */ + ABSOLUTE_Y; + INS; + break; + case 0xff: /* INS abcd,x [unofficial] */ + ABSOLUTE_X; + INS; + break; +#endif /* ACPU_NO_UNOFFICIAL */ + case 0x05: /* ORA ab */ + ZPAGE; + ORA_ZP; + break; + case 0x06: /* ASL ab */ + ZPAGE; + ASL_ZP; + break; + case 0x08: /* PHP */ + PHPB1; + break; + case 0x09: /* ORA #ab */ + nz = a |= FETCH; + break; + case 0x0a: /* ASL */ + c = a >> 7; + nz = a = (a << 1) & 0xff; + break; + case 0x0d: /* ORA abcd */ + ABSOLUTE; + ORA; + break; + case 0x0e: /* ASL abcd */ + ABSOLUTE; + ASL; + break; + case 0x10: /* BPL */ + BRANCH(nz < 0x80); + case 0x11: /* ORA (ab),y */ + INDIRECT_Y; + NCYCLES_Y; + ORA; + break; + case 0x15: /* ORA ab,x */ + ZPAGE_X; + ORA_ZP; + break; + case 0x16: /* ASL ab,x */ + ZPAGE_X; + ASL_ZP; + break; + case 0x18: /* CLC */ + c = 0; + break; + case 0x19: /* ORA abcd,y */ + ABSOLUTE_Y; + NCYCLES_Y; + ORA; + break; + case 0x1d: /* ORA abcd,x */ + ABSOLUTE_X; + NCYCLES_X; + ORA; + break; + case 0x1e: /* ASL abcd,x */ + ABSOLUTE_X; + ASL; + break; + case 0x20: /* JSR abcd */ + addr = FETCH; + PHPC; + pc = addr + (PEEK << 8); + break; + case 0x21: /* AND (ab,x) */ + INDIRECT_X; + AND; + break; + case 0x24: /* BIT ab */ + ZPAGE; + nz = dGetByte(addr); + vdi = (vdi & (D_FLAG | I_FLAG)) + (nz & V_FLAG); + nz = ((nz & 0x80) << 1) + (nz & a); + break; + case 0x25: /* AND ab */ + ZPAGE; + AND_ZP; + break; + case 0x26: /* ROL ab */ + ZPAGE; + ROL_ZP; + break; + case 0x28: /* PLP */ + PLP; + CHECK_IRQ; + break; + case 0x29: /* AND #ab */ + nz = a &= FETCH; + break; + case 0x2a: /* ROL */ + a = (a << 1) + c; + c = a >> 8; + nz = a &= 0xff; + break; + case 0x2c: /* BIT abcd */ + ABSOLUTE; + nz = GetByte(addr); + vdi = (vdi & (D_FLAG | I_FLAG)) + (nz & V_FLAG); + nz = ((nz & 0x80) << 1) + (nz & a); + break; + case 0x2d: /* AND abcd */ + ABSOLUTE; + AND; + break; + case 0x2e: /* ROL abcd */ + ABSOLUTE; + ROL; + break; + case 0x30: /* BMI */ + BRANCH(nz >= 0x80); + case 0x31: /* AND (ab),y */ + INDIRECT_Y; + NCYCLES_Y; + AND; + break; + case 0x35: /* AND ab,x */ + ZPAGE_X; + AND_ZP; + break; + case 0x36: /* ROL ab,x */ + ZPAGE_X; + ROL_ZP; + break; + case 0x38: /* SEC */ + c = 1; + break; + case 0x39: /* AND abcd,y */ + ABSOLUTE_Y; + NCYCLES_Y; + AND; + break; + case 0x3d: /* AND abcd,x */ + ABSOLUTE_X; + NCYCLES_X; + AND; + break; + case 0x3e: /* ROL abcd,x */ + ABSOLUTE_X; + ROL; + break; + case 0x40: /* RTI */ + PLP; + PL(pc); + PL(addr); + pc += addr << 8; + CHECK_IRQ; + break; + case 0x41: /* EOR (ab,x) */ + INDIRECT_X; + EOR; + break; + case 0x45: /* EOR ab */ + ZPAGE; + EOR_ZP; + break; + case 0x46: /* LSR ab */ + ZPAGE; + LSR_ZP; + break; + case 0x48: /* PHA */ + PH(a); + break; + case 0x49: /* EOR #ab */ + nz = a ^= FETCH; + break; + case 0x4a: /* LSR */ + c = a & 1; + nz = a >>= 1; + break; + case 0x4c: /* JMP abcd */ + addr = FETCH; + pc = addr + (PEEK << 8); + break; + case 0x4d: /* EOR abcd */ + ABSOLUTE; + EOR; + break; + case 0x4e: /* LSR abcd */ + ABSOLUTE; + LSR; + break; + case 0x50: /* BVC */ + BRANCH((vdi & V_FLAG) == 0); + case 0x51: /* EOR (ab),y */ + INDIRECT_Y; + NCYCLES_Y; + EOR; + break; + case 0x55: /* EOR ab,x */ + ZPAGE_X; + EOR_ZP; + break; + case 0x56: /* LSR ab,x */ + ZPAGE_X; + LSR_ZP; + break; + case 0x58: /* CLI */ + vdi &= V_FLAG | D_FLAG; + CHECK_IRQ; + break; + case 0x59: /* EOR abcd,y */ + ABSOLUTE_Y; + NCYCLES_Y; + EOR; + break; + case 0x5d: /* EOR abcd,x */ + ABSOLUTE_X; + NCYCLES_X; + EOR; + break; + case 0x5e: /* LSR abcd,x */ + ABSOLUTE_X; + LSR; + break; + case 0x60: /* RTS */ + PL(pc); + PL(addr); + pc += (addr << 8) + 1; + break; + case 0x61: /* ADC (ab,x) */ + INDIRECT_X; + ADC; + break; + case 0x65: /* ADC ab */ + ZPAGE; + ADC_ZP; + break; + case 0x66: /* ROR ab */ + ZPAGE; + ROR_ZP; + break; + case 0x68: /* PLA */ + PL(a); + nz = a; + break; + case 0x69: /* ADC #ab */ + data = FETCH; + DO_ADC; + break; + case 0x6a: /* ROR */ + nz = (c << 7) + (a >> 1); + c = a & 1; + a = nz; + break; + case 0x6c: /* JMP (abcd) */ + ABSOLUTE; + if ((addr & 0xff) == 0xff) + pc = (dGetByte(addr - 0xff) << 8) + dGetByte(addr); + else + pc = dGetWord(addr); + break; + case 0x6d: /* ADC abcd */ + ABSOLUTE; + ADC; + break; + case 0x6e: /* ROR abcd */ + ABSOLUTE; + ROR; + break; + case 0x70: /* BVS */ + BRANCH((vdi & V_FLAG) != 0); + case 0x71: /* ADC (ab),y */ + INDIRECT_Y; + NCYCLES_Y; + ADC; + break; + case 0x75: /* ADC ab,x */ + ZPAGE_X; + ADC_ZP; + break; + case 0x76: /* ROR ab,x */ + ZPAGE_X; + ROR_ZP; + break; + case 0x78: /* SEI */ + vdi |= I_FLAG; + break; + case 0x79: /* ADC abcd,y */ + ABSOLUTE_Y; + NCYCLES_Y; + ADC; + break; + case 0x7d: /* ADC abcd,x */ + ABSOLUTE_X; + NCYCLES_X; + ADC; + break; + case 0x7e: /* ROR abcd,x */ + ABSOLUTE_X; + ROR; + break; + case 0x81: /* STA (ab,x) */ + INDIRECT_X; + STA; + break; + case 0x84: /* STY ab */ + ZPAGE; + STY_ZP; + break; + case 0x85: /* STA ab */ + ZPAGE; + STA_ZP; + break; + case 0x86: /* STX ab */ + ZPAGE; + STX_ZP; + break; + case 0x88: /* DEY */ + nz = y = (y - 1) & 0xff; + break; + case 0x8a: /* TXA */ + nz = a = x; + break; + case 0x8c: /* STY abcd */ + ABSOLUTE; + STY; + break; + case 0x8d: /* STA abcd */ + ABSOLUTE; + STA; + break; + case 0x8e: /* STX abcd */ + ABSOLUTE; + STX; + break; + case 0x90: /* BCC */ + BRANCH(c == 0); + case 0x91: /* STA (ab),y */ + INDIRECT_Y; + STA; + break; + case 0x94: /* STY ab,x */ + ZPAGE_X; + STY_ZP; + break; + case 0x95: /* STA ab,x */ + ZPAGE_X; + STA_ZP; + break; + case 0x96: /* STX ab,y */ + ZPAGE_Y; + STX_ZP; + break; + case 0x98: /* TYA */ + nz = a = y; + break; + case 0x99: /* STA abcd,y */ + ABSOLUTE_Y; + STA; + break; + case 0x9a: /* TXS */ + s = x; + break; + case 0x9d: /* STA abcd,x */ + ABSOLUTE_X; + STA; + break; + case 0xa0: /* LDY #ab */ + nz = y = FETCH; + break; + case 0xa1: /* LDA (ab,x) */ + INDIRECT_X; + LDA; + break; + case 0xa2: /* LDX #ab */ + nz = x = FETCH; + break; + case 0xa4: /* LDY ab */ + ZPAGE; + LDY_ZP; + break; + case 0xa5: /* LDA ab */ + ZPAGE; + LDA_ZP; + break; + case 0xa6: /* LDX ab */ + ZPAGE; + LDX_ZP; + break; + case 0xa8: /* TAY */ + nz = y = a; + break; + case 0xa9: /* LDA #ab */ + nz = a = FETCH; + break; + case 0xaa: /* TAX */ + nz = x = a; + break; + case 0xac: /* LDY abcd */ + ABSOLUTE; + LDY; + break; + case 0xad: /* LDA abcd */ + ABSOLUTE; + LDA; + break; + case 0xae: /* LDX abcd */ + ABSOLUTE; + LDX; + break; + case 0xb0: /* BCS */ + BRANCH(c != 0); + case 0xb1: /* LDA (ab),y */ + INDIRECT_Y; + NCYCLES_Y; + LDA; + break; + case 0xb4: /* LDY ab,x */ + ZPAGE_X; + LDY_ZP; + break; + case 0xb5: /* LDA ab,x */ + ZPAGE_X; + LDA_ZP; + break; + case 0xb6: /* LDX ab,y */ + ZPAGE_Y; + LDX_ZP; + break; + case 0xb8: /* CLV */ + vdi &= D_FLAG | I_FLAG; + break; + case 0xb9: /* LDA abcd,y */ + ABSOLUTE_Y; + NCYCLES_Y; + LDA; + break; + case 0xba: /* TSX */ + nz = x = s; + break; + case 0xbc: /* LDY abcd,x */ + ABSOLUTE_X; + NCYCLES_X; + LDY; + break; + case 0xbd: /* LDA abcd,x */ + ABSOLUTE_X; + NCYCLES_X; + LDA; + break; + case 0xbe: /* LDX abcd,y */ + ABSOLUTE_Y; + NCYCLES_Y; + LDX; + break; + case 0xc0: /* CPY #ab */ + nz = FETCH; + c = (y >= nz) ? 1 : 0; + nz = (y - nz) & 0xff; + break; + case 0xc1: /* CMP (ab,x) */ + INDIRECT_X; + CMP; + break; + case 0xc4: /* CPY ab */ + ZPAGE; + CPY_ZP; + break; + case 0xc5: /* CMP ab */ + ZPAGE; + CMP_ZP; + break; + case 0xc6: /* DEC ab */ + ZPAGE; + DEC_ZP; + break; + case 0xc8: /* INY */ + nz = y = (y + 1) & 0xff; + break; + case 0xc9: /* CMP #ab */ + nz = FETCH; + c = (a >= nz) ? 1 : 0; + nz = (a - nz) & 0xff; + break; + case 0xca: /* DEX */ + nz = x = (x - 1) & 0xff; + break; + case 0xcc: /* CPY abcd */ + ABSOLUTE; + CPY; + break; + case 0xcd: /* CMP abcd */ + ABSOLUTE; + CMP; + break; + case 0xce: /* DEC abcd */ + ABSOLUTE; + DEC; + break; + case 0xd0: /* BNE */ + BRANCH((nz & 0xff) != 0); + case 0xd1: /* CMP (ab),y */ + INDIRECT_Y; + NCYCLES_Y; + CMP; + break; + case 0xd5: /* CMP ab,x */ + ZPAGE_X; + CMP_ZP; + break; + case 0xd6: /* DEC ab,x */ + ZPAGE_X; + DEC_ZP; + break; + case 0xd8: /* CLD */ + vdi &= V_FLAG | I_FLAG; + break; + case 0xd9: /* CMP abcd,y */ + ABSOLUTE_Y; + NCYCLES_Y; + CMP; + break; + case 0xdd: /* CMP abcd,x */ + ABSOLUTE_X; + NCYCLES_X; + CMP; + break; + case 0xde: /* DEC abcd,x */ + ABSOLUTE_X; + DEC; + break; + case 0xe0: /* CPX #ab */ + nz = FETCH; + c = (x >= nz) ? 1 : 0; + nz = (x - nz) & 0xff; + break; + case 0xe1: /* SBC (ab,x) */ + INDIRECT_X; + SBC; + break; + case 0xe4: /* CPX ab */ + ZPAGE; + CPX_ZP; + break; + case 0xe5: /* SBC ab */ + ZPAGE; + SBC_ZP; + break; + case 0xe6: /* INC ab */ + ZPAGE; + INC_ZP; + break; + case 0xe8: /* INX */ + nz = x = (x + 1) & 0xff; + break; + case 0xe9: /* SBC #ab */ + case 0xeb: /* SBC #ab [unofficial] */ + data = FETCH; + DO_SBC; + break; + case 0xea: /* NOP */ + case 0x1a: /* NOP [unofficial] */ + case 0x3a: + case 0x5a: + case 0x7a: + case 0xda: + case 0xfa: + break; + case 0xec: /* CPX abcd */ + ABSOLUTE; + CPX; + break; + case 0xed: /* SBC abcd */ + ABSOLUTE; + SBC; + break; + case 0xee: /* INC abcd */ + ABSOLUTE; + INC; + break; + case 0xf0: /* BEQ */ + BRANCH((nz & 0xff) == 0); + case 0xf1: /* SBC (ab),y */ + INDIRECT_Y; + NCYCLES_Y; + SBC; + break; + case 0xf5: /* SBC ab,x */ + ZPAGE_X; + SBC_ZP; + break; + case 0xf6: /* INC ab,x */ + ZPAGE_X; + INC_ZP; + break; + case 0xf8: /* SED */ + vdi |= D_FLAG; + break; + case 0xf9: /* SBC abcd,y */ + ABSOLUTE_Y; + NCYCLES_Y; + SBC; + break; + case 0xfd: /* SBC abcd,x */ + ABSOLUTE_X; + NCYCLES_X; + SBC; + break; + case 0xfe: /* INC abcd,x */ + ABSOLUTE_X; + INC; + break; + } + } + ast _ cpu_pc = pc; + ast _ cpu_nz = nz; + ast _ cpu_a = a; + ast _ cpu_x = x; + ast _ cpu_y = y; + ast _ cpu_c = c; + ast _ cpu_s = s; + ast _ cpu_vdi = vdi; + ast _ cycle -= cycle_limit; + if (ast _ timer1_cycle != NEVER) + ast _ timer1_cycle -= cycle_limit; + if (ast _ timer2_cycle != NEVER) + ast _ timer2_cycle -= cycle_limit; + if (ast _ timer4_cycle != NEVER) + ast _ timer4_cycle -= cycle_limit; +} diff --git a/lib/rbcodec/codecs/libasap/anylang.h b/lib/rbcodec/codecs/libasap/anylang.h new file mode 100644 index 0000000000..e56dfbae0e --- /dev/null +++ b/lib/rbcodec/codecs/libasap/anylang.h @@ -0,0 +1,218 @@ +/* + * anylang.h - C/Java/C#/JavaScript/ActionScript abstraction layer + * + * Copyright (C) 2007-2010 Piotr Fusik + * + * This file is part of ASAP (Another Slight Atari Player), + * see http://asap.sourceforge.net + * + * ASAP is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2 of the License, + * or (at your option) any later version. + * + * ASAP is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ASAP; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _ANYLANG_H_ +#define _ANYLANG_H_ + +#if defined(JAVA) || defined(CSHARP) || defined(JAVASCRIPT) || defined(ACTIONSCRIPT) + +#define FALSE false +#define TRUE true +#define NULL null +#define _ . +#define PRIVATE +#define CONST +#define OUT_STRING STRING + +#else + +#define C +#include + +#define PRIVATE static +#define FUNC(type, name, pars) type name pars +#define P(type, name) type name +#define V(type, name) type name +#define CONST const +#define _ -> +#define PTR * +#define ADDRESSOF & +#define CAST(type) (type) +#define TO_INT(x) (int) (x) +#define TO_BYTE(x) (byte) (x) +#define BYTEARRAY byte * +#define BOOLARRAY abool * +#define VOIDPTR void * +#define UBYTE(data) (data) +#define SBYTE(data) (signed char) (data) +#define CONST_ARRAY(type, name) static const type name[] = { +#define END_CONST_ARRAY } +#define ZERO_ARRAY(array) memset(array, 0, sizeof(array)) +#define COPY_ARRAY(dest, dest_offset, src, src_offset, len) \ + memcpy(dest + dest_offset, src + src_offset, len) +#define NEW_ARRAY(type, name, size) \ + type name[size] +#define INIT_ARRAY(array) memset(array, 0, sizeof(array)) +#define STRING const char * +#define OUT_STRING char * +#define CHARAT(s, i) (s)[i] +#define CHARCODEAT(s, i) (s)[i] +#define CHARCODE(c) (c) +#define EQUAL_STRINGS(s1, s2) (strcmp(s1, s2) == 0) +#define EMPTY_STRING(s) (s)[0] = '\0' +#define SUBSTR(s, i) (s + i) +#define BYTES_TO_STRING(dest, src, src_offset, len) \ + do { memcpy(dest, src + src_offset, len); (dest)[len] = '\0'; } while (FALSE) +#define SUBSTRING(dest, src, src_offset, len) \ + do { memcpy(dest, src + src_offset, len); (dest)[len] = '\0'; } while (FALSE) + +#define RESOURCE const byte * +#define GET_RESOURCE(name, ext) name##_##ext + +#endif /* defined(JAVA) || defined(CSHARP) || defined(JAVASCRIPT) || defined(ACTIONSCRIPT) */ + +#ifdef JAVA + +#define abool boolean +#define FUNC(type, name, pars) private static type name pars +#define P(type, name) type name +#define V(type, name) type name +#define PTR +#define ADDRESSOF +#define CAST(type) (type) +#define TO_INT(x) (int) (x) +#define TO_BYTE(x) (byte) (x) +#define BYTEARRAY byte[] +#define BOOLARRAY boolean[] +#define VOIDPTR byte[] +#define UBYTE(data) ((data) & 0xff) +#define SBYTE(data) (byte) (data) +#define CONST_ARRAY(type, name) private static final type[] name = { +#define END_CONST_ARRAY } +#define sizeof(array) array.length +#define ZERO_ARRAY(array) for (int ii = 0; ii < array.length; ii++) array[ii] = 0 +#define COPY_ARRAY(dest, dest_offset, src, src_offset, len) \ + System.arraycopy(src, src_offset, dest, dest_offset, len) +#define NEW_ARRAY(type, name, size) \ + type[] name = new type[size] +#define INIT_ARRAY(array) +#define STRING String +#define CHARAT(s, i) (s).charAt(i) +#define CHARCODEAT(s, i) (s).charAt(i) +#define CHARCODE(c) (c) +#define strlen(s) (s).length() +#define EQUAL_STRINGS(s1, s2) (s1).equals(s2) +#define EMPTY_STRING(s) (s) = "" +#define SUBSTR(s, i) (s).substring(i) +#define BYTES_TO_STRING(dest, src, src_offset, len) \ + (dest) = new String(src, src_offset, len) +#define SUBSTRING(dest, src, src_offset, len) \ + (dest) = (src).substring(src_offset, src_offset + len) + +#define RESOURCE byte[] +#define GET_RESOURCE(name, ext) getResourceBytes(#name + "." + #ext) + +#elif defined(CSHARP) + +#define abool bool +#define FUNC(type, name, pars) private static type name pars +#define P(type, name) type name +#define V(type, name) type name +#define PTR +#define ADDRESSOF +#define CAST(type) (type) +#define TO_INT(x) (int) (x) +#define TO_BYTE(x) (byte) (x) +#define BYTEARRAY byte[] +#define BOOLARRAY bool[] +#define VOIDPTR byte[] +#define UBYTE(data) (data) +#define SBYTE(data) (sbyte) (data) +#define CONST_ARRAY(type, name) private static readonly type[] name = { +#define END_CONST_ARRAY } +#define sizeof(array) array.Length +#define ZERO_ARRAY(array) Array.Clear(array, 0, array.Length) +#define COPY_ARRAY(dest, dest_offset, src, src_offset, len) \ + Array.Copy(src, src_offset, dest, dest_offset, len) +#define NEW_ARRAY(type, name, size) \ + type[] name = new type[size] +#define INIT_ARRAY(array) +#define STRING string +#define CHARAT(s, i) (s)[i] +#define CHARCODEAT(s, i) (s)[i] +#define CHARCODE(c) (c) +#define strlen(s) (s).Length +#define EQUAL_STRINGS(s1, s2) ((s1) == (s2)) +#define EMPTY_STRING(s) (s) = string.Empty +#define SUBSTR(s, i) (s).Substring(i) +#define BYTES_TO_STRING(dest, src, src_offset, len) \ + (dest) = System.Text.Encoding.UTF8.GetString(src, src_offset, len) +#define SUBSTRING(dest, src, src_offset, len) \ + (dest) = (src).Substring(src_offset, len) + +#define RESOURCE byte[] +#define GET_RESOURCE(name, ext) name##_##ext + +#elif defined(JAVASCRIPT) || defined(ACTIONSCRIPT) + +#ifdef ACTIONSCRIPT +#define abool Boolean +#define char String +#define STRING String +#define BYTEARRAY ByteArray +#define BOOLARRAY Array +#define VOIDPTR ByteArray +#define RESOURCE Array +#define FUNC(type, name, pars) private static function name pars : type +#define P(type, name) name : type +#define V(type, name) var name : type +#define TO_INT(x) int(x) +#define CONST_ARRAY(type, name) private static const name : Array = [ +#else +#define FUNC(type, name, pars) function name pars +#define P(type, name) name +#define V(type, name) var name +#define TO_INT(x) Math.floor(x) +#define CONST_ARRAY(type, name) var name = [ +#endif +#define PTR +#define ADDRESSOF +#define CAST(type) +#define TO_BYTE(x) ((x) & 0xff) +#define UBYTE(data) (data) +#define SBYTE(data) ((data) < 0x80 ? (data) : (data) - 256) +#define END_CONST_ARRAY ] +#define sizeof(array) array.length +#define ZERO_ARRAY(array) for (V(int, ii) = 0; ii < array.length; ii++) array[ii] = 0 +#define COPY_ARRAY(dest, dest_offset, src, src_offset, len) \ + for (V(int, ii) = 0; ii < len; ii++) dest[dest_offset + ii] = src[src_offset + ii] +#define NEW_ARRAY(type, name, size) \ + V(Array, name) = new Array(size) +#define INIT_ARRAY(array) for (V(int, ii) = 0; ii < array.length; ii++) array[ii] = 0 +#define CHARAT(s, i) (s).charAt(i) +#define CHARCODEAT(s, i) (s).charCodeAt(i) +#define CHARCODE(c) (c).charCodeAt(0) +#define strlen(s) (s).length +#define EQUAL_STRINGS(s1, s2) ((s1) == (s2)) +#define EMPTY_STRING(s) s = "" +#define SUBSTR(s, i) (s).substr(i) +#define BYTES_TO_STRING(dest, src, src_offset, len) \ + { dest = ""; for (V(int, ii) = 0; ii < len; ii++) dest += String.fromCharCode(src[src_offset + ii]); } +#define SUBSTRING(dest, src, src_offset, len) \ + dest = (src).substring(src_offset, src_offset + len) + +#define GET_RESOURCE(name, ext) name##_##ext + +#endif + +#endif /* _ANYLANG_H_ */ diff --git a/lib/rbcodec/codecs/libasap/apokeysnd.c b/lib/rbcodec/codecs/libasap/apokeysnd.c new file mode 100644 index 0000000000..811e2f9b4a --- /dev/null +++ b/lib/rbcodec/codecs/libasap/apokeysnd.c @@ -0,0 +1,599 @@ +/* + * apokeysnd.c - another POKEY sound emulator + * + * Copyright (C) 2007-2010 Piotr Fusik + * + * This file is part of ASAP (Another Slight Atari Player), + * see http://asap.sourceforge.net + * + * ASAP is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2 of the License, + * or (at your option) any later version. + * + * ASAP is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ASAP; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "asap_internal.h" + +#define ULTRASOUND_CYCLES 112 + +#define MUTE_FREQUENCY 1 +#define MUTE_INIT 2 +#define MUTE_USER 4 + +CONST_ARRAY(byte, poly4_lookup) + 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1 +END_CONST_ARRAY; +CONST_ARRAY(byte, poly5_lookup) + 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, + 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1 +END_CONST_ARRAY; + +PRIVATE FUNC(void, PokeySound_InitializeChip, (P(PokeyState PTR, pst))) +{ + pst _ audctl = 0; + pst _ init = FALSE; + pst _ poly_index = 15 * 31 * 131071; + pst _ div_cycles = 28; + pst _ mute1 = MUTE_FREQUENCY | MUTE_USER; + pst _ mute2 = MUTE_FREQUENCY | MUTE_USER; + pst _ mute3 = MUTE_FREQUENCY | MUTE_USER; + pst _ mute4 = MUTE_FREQUENCY | MUTE_USER; + pst _ audf1 = 0; + pst _ audf2 = 0; + pst _ audf3 = 0; + pst _ audf4 = 0; + pst _ audc1 = 0; + pst _ audc2 = 0; + pst _ audc3 = 0; + pst _ audc4 = 0; + pst _ tick_cycle1 = NEVER; + pst _ tick_cycle2 = NEVER; + pst _ tick_cycle3 = NEVER; + pst _ tick_cycle4 = NEVER; + pst _ period_cycles1 = 28; + pst _ period_cycles2 = 28; + pst _ period_cycles3 = 28; + pst _ period_cycles4 = 28; + pst _ reload_cycles1 = 28; + pst _ reload_cycles3 = 28; + pst _ out1 = 0; + pst _ out2 = 0; + pst _ out3 = 0; + pst _ out4 = 0; + pst _ delta1 = 0; + pst _ delta2 = 0; + pst _ delta3 = 0; + pst _ delta4 = 0; + pst _ skctl = 3; + ZERO_ARRAY(pst _ delta_buffer); +} + +FUNC(void, PokeySound_Initialize, (P(ASAP_State PTR, ast))) +{ + V(int, i); + V(int, reg); + reg = 0x1ff; + for (i = 0; i < 511; i++) { + reg = ((((reg >> 5) ^ reg) & 1) << 8) + (reg >> 1); + ast _ poly9_lookup[i] = TO_BYTE(reg); + } + reg = 0x1ffff; + for (i = 0; i < 16385; i++) { + reg = ((((reg >> 5) ^ reg) & 0xff) << 9) + (reg >> 8); + ast _ poly17_lookup[i] = TO_BYTE(reg >> 1); + } + ast _ sample_offset = 0; + ast _ sample_index = 0; + ast _ samples = 0; + ast _ iir_acc_left = 0; + ast _ iir_acc_right = 0; + PokeySound_InitializeChip(ADDRESSOF ast _ base_pokey); + PokeySound_InitializeChip(ADDRESSOF ast _ extra_pokey); +} + +#define DO_TICK(ch) \ + if (pst _ init) { \ + switch (pst _ audc##ch >> 4) { \ + case 10: \ + case 14: \ + pst _ out##ch ^= 1; \ + pst _ delta_buffer[CYCLE_TO_SAMPLE(cycle)] += pst _ delta##ch = -pst _ delta##ch; \ + break; \ + default: \ + break; \ + } \ + } \ + else { \ + V(int, poly) = cycle + pst _ poly_index - (ch - 1); \ + V(int, newout) = pst _ out##ch; \ + switch (pst _ audc##ch >> 4) { \ + case 0: \ + if (poly5_lookup[poly % 31] != 0) { \ + if ((pst _ audctl & 0x80) != 0) \ + newout = ast _ poly9_lookup[poly % 511] & 1; \ + else { \ + poly %= 131071; \ + newout = (ast _ poly17_lookup[poly >> 3] >> (poly & 7)) & 1; \ + } \ + } \ + break; \ + case 2: \ + case 6: \ + newout ^= poly5_lookup[poly % 31]; \ + break; \ + case 4: \ + if (poly5_lookup[poly % 31] != 0) \ + newout = poly4_lookup[poly % 15]; \ + break; \ + case 8: \ + if ((pst _ audctl & 0x80) != 0) \ + newout = ast _ poly9_lookup[poly % 511] & 1; \ + else { \ + poly %= 131071; \ + newout = (ast _ poly17_lookup[poly >> 3] >> (poly & 7)) & 1; \ + } \ + break; \ + case 10: \ + case 14: \ + newout ^= 1; \ + break; \ + case 12: \ + newout = poly4_lookup[poly % 15]; \ + break; \ + default: \ + break; \ + } \ + if (newout != pst _ out##ch) { \ + pst _ out##ch = newout; \ + pst _ delta_buffer[CYCLE_TO_SAMPLE(cycle)] += pst _ delta##ch = -pst _ delta##ch; \ + } \ + } + +/* Fills delta_buffer up to current_cycle basing on current AUDF/AUDC/AUDCTL values. */ +PRIVATE FUNC(void, PokeySound_GenerateUntilCycle, (P(ASAP_State PTR, ast), P(PokeyState PTR, pst), P(int, current_cycle))) +{ + for (;;) { + V(int, cycle) = current_cycle; + if (cycle > pst _ tick_cycle1) + cycle = pst _ tick_cycle1; + if (cycle > pst _ tick_cycle2) + cycle = pst _ tick_cycle2; + if (cycle > pst _ tick_cycle3) + cycle = pst _ tick_cycle3; + if (cycle > pst _ tick_cycle4) + cycle = pst _ tick_cycle4; + if (cycle == current_cycle) + break; + if (cycle == pst _ tick_cycle3) { + pst _ tick_cycle3 += pst _ period_cycles3; + if ((pst _ audctl & 4) != 0 && pst _ delta1 > 0 && pst _ mute1 == 0) + pst _ delta_buffer[CYCLE_TO_SAMPLE(cycle)] += pst _ delta1 = -pst _ delta1; + DO_TICK(3); + } + if (cycle == pst _ tick_cycle4) { + pst _ tick_cycle4 += pst _ period_cycles4; + if ((pst _ audctl & 8) != 0) + pst _ tick_cycle3 = cycle + pst _ reload_cycles3; + if ((pst _ audctl & 2) != 0 && pst _ delta2 > 0 && pst _ mute2 == 0) + pst _ delta_buffer[CYCLE_TO_SAMPLE(cycle)] += pst _ delta2 = -pst _ delta2; + DO_TICK(4); + } + if (cycle == pst _ tick_cycle1) { + pst _ tick_cycle1 += pst _ period_cycles1; + if ((pst _ skctl & 0x88) == 8) /* two-tone, sending 1 (i.e. timer1) */ + pst _ tick_cycle2 = cycle + pst _ period_cycles2; + DO_TICK(1); + } + if (cycle == pst _ tick_cycle2) { + pst _ tick_cycle2 += pst _ period_cycles2; + if ((pst _ audctl & 0x10) != 0) + pst _ tick_cycle1 = cycle + pst _ reload_cycles1; + else if ((pst _ skctl & 8) != 0) /* two-tone */ + pst _ tick_cycle1 = cycle + pst _ period_cycles1; + DO_TICK(2); + } + } +} + +#ifdef APOKEYSND + +#define CURRENT_CYCLE 0 +#define CURRENT_SAMPLE 0 +#define DO_STORE(reg) \ + if (data == pst _ reg) \ + break; \ + pst _ reg = data; + +#else + +#define CURRENT_CYCLE ast _ cycle +#define CURRENT_SAMPLE CYCLE_TO_SAMPLE(ast _ cycle) +#define DO_STORE(reg) \ + if (data == pst _ reg) \ + break; \ + PokeySound_GenerateUntilCycle(ast, pst, ast _ cycle); \ + pst _ reg = data; + +#endif /* APOKEYSND */ + +#define MUTE_CHANNEL(ch, cond, mask) \ + if (cond) { \ + pst _ mute##ch |= mask; \ + pst _ tick_cycle##ch = NEVER; \ + } \ + else { \ + pst _ mute##ch &= ~mask; \ + if (pst _ tick_cycle##ch == NEVER && pst _ mute##ch == 0) \ + pst _ tick_cycle##ch = CURRENT_CYCLE; \ + } + +#define DO_ULTRASOUND(ch) \ + MUTE_CHANNEL(ch, pst _ period_cycles##ch <= ULTRASOUND_CYCLES && (pst _ audc##ch >> 4 == 10 || pst _ audc##ch >> 4 == 14), MUTE_FREQUENCY) + +#define DO_AUDC(ch) \ + DO_STORE(audc##ch); \ + if ((data & 0x10) != 0) { \ + data = (data & 0xf) << DELTA_SHIFT_POKEY; \ + if ((pst _ mute##ch & MUTE_USER) == 0) \ + pst _ delta_buffer[CURRENT_SAMPLE] \ + += pst _ delta##ch > 0 ? data - pst _ delta##ch : data; \ + pst _ delta##ch = data; \ + } \ + else { \ + data = (data & 0xf) << DELTA_SHIFT_POKEY; \ + DO_ULTRASOUND(ch); \ + if (pst _ delta##ch > 0) { \ + if ((pst _ mute##ch & MUTE_USER) == 0) \ + pst _ delta_buffer[CURRENT_SAMPLE] \ + += data - pst _ delta##ch; \ + pst _ delta##ch = data; \ + } \ + else \ + pst _ delta##ch = -data; \ + } \ + break; + +#define DO_INIT(ch, cond) \ + MUTE_CHANNEL(ch, pst _ init && cond, MUTE_INIT) + +FUNC(void, PokeySound_PutByte, (P(ASAP_State PTR, ast), P(int, addr), P(int, data))) +{ + V(PokeyState PTR, pst) = (addr & ast _ extra_pokey_mask) != 0 + ? ADDRESSOF ast _ extra_pokey : ADDRESSOF ast _ base_pokey; + switch (addr & 0xf) { + case 0x00: + DO_STORE(audf1); + switch (pst _ audctl & 0x50) { + case 0x00: + pst _ period_cycles1 = pst _ div_cycles * (data + 1); + break; + case 0x10: + pst _ period_cycles2 = pst _ div_cycles * (data + 256 * pst _ audf2 + 1); + pst _ reload_cycles1 = pst _ div_cycles * (data + 1); + DO_ULTRASOUND(2); + break; + case 0x40: + pst _ period_cycles1 = data + 4; + break; + case 0x50: + pst _ period_cycles2 = data + 256 * pst _ audf2 + 7; + pst _ reload_cycles1 = data + 4; + DO_ULTRASOUND(2); + break; + } + DO_ULTRASOUND(1); + break; + case 0x01: + DO_AUDC(1) + case 0x02: + DO_STORE(audf2); + switch (pst _ audctl & 0x50) { + case 0x00: + case 0x40: + pst _ period_cycles2 = pst _ div_cycles * (data + 1); + break; + case 0x10: + pst _ period_cycles2 = pst _ div_cycles * (pst _ audf1 + 256 * data + 1); + break; + case 0x50: + pst _ period_cycles2 = pst _ audf1 + 256 * data + 7; + break; + } + DO_ULTRASOUND(2); + break; + case 0x03: + DO_AUDC(2) + case 0x04: + DO_STORE(audf3); + switch (pst _ audctl & 0x28) { + case 0x00: + pst _ period_cycles3 = pst _ div_cycles * (data + 1); + break; + case 0x08: + pst _ period_cycles4 = pst _ div_cycles * (data + 256 * pst _ audf4 + 1); + pst _ reload_cycles3 = pst _ div_cycles * (data + 1); + DO_ULTRASOUND(4); + break; + case 0x20: + pst _ period_cycles3 = data + 4; + break; + case 0x28: + pst _ period_cycles4 = data + 256 * pst _ audf4 + 7; + pst _ reload_cycles3 = data + 4; + DO_ULTRASOUND(4); + break; + } + DO_ULTRASOUND(3); + break; + case 0x05: + DO_AUDC(3) + case 0x06: + DO_STORE(audf4); + switch (pst _ audctl & 0x28) { + case 0x00: + case 0x20: + pst _ period_cycles4 = pst _ div_cycles * (data + 1); + break; + case 0x08: + pst _ period_cycles4 = pst _ div_cycles * (pst _ audf3 + 256 * data + 1); + break; + case 0x28: + pst _ period_cycles4 = pst _ audf3 + 256 * data + 7; + break; + } + DO_ULTRASOUND(4); + break; + case 0x07: + DO_AUDC(4) + case 0x08: + DO_STORE(audctl); + pst _ div_cycles = ((data & 1) != 0) ? 114 : 28; + /* TODO: tick_cycles */ + switch (data & 0x50) { + case 0x00: + pst _ period_cycles1 = pst _ div_cycles * (pst _ audf1 + 1); + pst _ period_cycles2 = pst _ div_cycles * (pst _ audf2 + 1); + break; + case 0x10: + pst _ period_cycles1 = pst _ div_cycles * 256; + pst _ period_cycles2 = pst _ div_cycles * (pst _ audf1 + 256 * pst _ audf2 + 1); + pst _ reload_cycles1 = pst _ div_cycles * (pst _ audf1 + 1); + break; + case 0x40: + pst _ period_cycles1 = pst _ audf1 + 4; + pst _ period_cycles2 = pst _ div_cycles * (pst _ audf2 + 1); + break; + case 0x50: + pst _ period_cycles1 = 256; + pst _ period_cycles2 = pst _ audf1 + 256 * pst _ audf2 + 7; + pst _ reload_cycles1 = pst _ audf1 + 4; + break; + } + DO_ULTRASOUND(1); + DO_ULTRASOUND(2); + switch (data & 0x28) { + case 0x00: + pst _ period_cycles3 = pst _ div_cycles * (pst _ audf3 + 1); + pst _ period_cycles4 = pst _ div_cycles * (pst _ audf4 + 1); + break; + case 0x08: + pst _ period_cycles3 = pst _ div_cycles * 256; + pst _ period_cycles4 = pst _ div_cycles * (pst _ audf3 + 256 * pst _ audf4 + 1); + pst _ reload_cycles3 = pst _ div_cycles * (pst _ audf3 + 1); + break; + case 0x20: + pst _ period_cycles3 = pst _ audf3 + 4; + pst _ period_cycles4 = pst _ div_cycles * (pst _ audf4 + 1); + break; + case 0x28: + pst _ period_cycles3 = 256; + pst _ period_cycles4 = pst _ audf3 + 256 * pst _ audf4 + 7; + pst _ reload_cycles3 = pst _ audf3 + 4; + break; + } + DO_ULTRASOUND(3); + DO_ULTRASOUND(4); + DO_INIT(1, (data & 0x40) == 0); + DO_INIT(2, (data & 0x50) != 0x50); + DO_INIT(3, (data & 0x20) == 0); + DO_INIT(4, (data & 0x28) != 0x28); + break; + case 0x09: + /* TODO: STIMER */ + break; + case 0x0f: + DO_STORE(skctl); + pst _ init = ((data & 3) == 0); + DO_INIT(1, (pst _ audctl & 0x40) == 0); + DO_INIT(2, (pst _ audctl & 0x50) != 0x50); + DO_INIT(3, (pst _ audctl & 0x20) == 0); + DO_INIT(4, (pst _ audctl & 0x28) != 0x28); + break; + default: + break; + } +} + +FUNC(int, PokeySound_GetRandom, (P(ASAP_State PTR, ast), P(int, addr), P(int, cycle))) +{ + V(PokeyState PTR, pst) = (addr & ast _ extra_pokey_mask) != 0 + ? ADDRESSOF ast _ extra_pokey : ADDRESSOF ast _ base_pokey; + V(int, i); + if (pst _ init) + return 0xff; + i = cycle + pst _ poly_index; + if ((pst _ audctl & 0x80) != 0) + return ast _ poly9_lookup[i % 511]; + else { + V(int, j); + i %= 131071; + j = i >> 3; + i &= 7; + return ((ast _ poly17_lookup[j] >> i) + (ast _ poly17_lookup[j + 1] << (8 - i))) & 0xff; + } +} + +PRIVATE FUNC(void, end_frame, (P(ASAP_State PTR, ast), P(PokeyState PTR, pst), P(int, cycle_limit))) +{ + V(int, m); + PokeySound_GenerateUntilCycle(ast, pst, cycle_limit); + pst _ poly_index += cycle_limit; + m = ((pst _ audctl & 0x80) != 0) ? 15 * 31 * 511 : 15 * 31 * 131071; + if (pst _ poly_index >= 2 * m) + pst _ poly_index -= m; + if (pst _ tick_cycle1 != NEVER) + pst _ tick_cycle1 -= cycle_limit; + if (pst _ tick_cycle2 != NEVER) + pst _ tick_cycle2 -= cycle_limit; + if (pst _ tick_cycle3 != NEVER) + pst _ tick_cycle3 -= cycle_limit; + if (pst _ tick_cycle4 != NEVER) + pst _ tick_cycle4 -= cycle_limit; +} + +FUNC(void, PokeySound_StartFrame, (P(ASAP_State PTR, ast))) +{ + ZERO_ARRAY(ast _ base_pokey.delta_buffer); + if (ast _ extra_pokey_mask != 0) + ZERO_ARRAY(ast _ extra_pokey.delta_buffer); +} + +FUNC(void, PokeySound_EndFrame, (P(ASAP_State PTR, ast), P(int, current_cycle))) +{ + V(int, clk) = ASAP_MAIN_CLOCK(ast); + end_frame(ast, ADDRESSOF ast _ base_pokey, current_cycle); + if (ast _ extra_pokey_mask != 0) + end_frame(ast, ADDRESSOF ast _ extra_pokey, current_cycle); + ast _ sample_offset += current_cycle * ASAP_SAMPLE_RATE; + ast _ sample_index = 0; + ast _ samples = TO_INT(ast _ sample_offset / clk); + ast _ sample_offset %= clk; +} + +/* Fills buffer with samples from delta_buffer. */ +FUNC(int, PokeySound_Generate, (P(ASAP_State PTR, ast), P(BYTEARRAY, buffer), P(int, buffer_offset), P(int, blocks), P(ASAP_SampleFormat, format))) +{ + V(int, i) = ast _ sample_index; + V(int, samples) = ast _ samples; + V(int, acc_left) = ast _ iir_acc_left; + V(int, acc_right) = ast _ iir_acc_right; + if (blocks < samples - i) + samples = i + blocks; + else + blocks = samples - i; + for (; i < samples; i++) { +#ifdef ACTIONSCRIPT + acc_left += ast _ base_pokey.delta_buffer[i] - (acc_left * 3 >> 10); + var sample : Number = acc_left / 33553408; + buffer.writeFloat(sample); + if (ast.extra_pokey_mask != 0) { + acc_right += ast _ extra_pokey.delta_buffer[i] - (acc_right * 3 >> 10); + sample = acc_right / 33553408; + } + buffer.writeFloat(sample); +#else + V(int, sample); + acc_left += ast _ base_pokey.delta_buffer[i] - (acc_left * 3 >> 10); + sample = acc_left >> 10; +#define STORE_SAMPLE \ + if (sample < -32767) \ + sample = -32767; \ + else if (sample > 32767) \ + sample = 32767; \ + switch (format) { \ + case ASAP_FORMAT_U8: \ + buffer[buffer_offset++] = CAST(byte) ((sample >> 8) + 128); \ + break; \ + case ASAP_FORMAT_S16_LE: \ + buffer[buffer_offset++] = TO_BYTE(sample); \ + buffer[buffer_offset++] = TO_BYTE(sample >> 8); \ + break; \ + case ASAP_FORMAT_S16_BE: \ + buffer[buffer_offset++] = TO_BYTE(sample >> 8); \ + buffer[buffer_offset++] = TO_BYTE(sample); \ + break; \ + } + STORE_SAMPLE; + if (ast _ extra_pokey_mask != 0) { + acc_right += ast _ extra_pokey.delta_buffer[i] - (acc_right * 3 >> 10); + sample = acc_right >> 10; + STORE_SAMPLE; + } +#endif /* ACTIONSCRIPT */ + } + if (i == ast _ samples) { + acc_left += ast _ base_pokey.delta_buffer[i]; + acc_right += ast _ extra_pokey.delta_buffer[i]; + } + ast _ sample_index = i; + ast _ iir_acc_left = acc_left; + ast _ iir_acc_right = acc_right; +#ifdef APOKEYSND + return buffer_offset; +#else + return blocks; +#endif +} + +FUNC(abool, PokeySound_IsSilent, (P(CONST PokeyState PTR, pst))) +{ + return ((pst _ audc1 | pst _ audc2 | pst _ audc3 | pst _ audc4) & 0xf) == 0; +} + +FUNC(void, PokeySound_Mute, (P(CONST ASAP_State PTR, ast), P(PokeyState PTR, pst), P(int, mask))) +{ + MUTE_CHANNEL(1, (mask & 1) != 0, MUTE_USER); + MUTE_CHANNEL(2, (mask & 2) != 0, MUTE_USER); + MUTE_CHANNEL(3, (mask & 4) != 0, MUTE_USER); + MUTE_CHANNEL(4, (mask & 8) != 0, MUTE_USER); +} + +#ifdef APOKEYSND + +static ASAP_State asap; + +__declspec(dllexport) void APokeySound_Initialize(abool stereo) +{ + asap.extra_pokey_mask = stereo ? 0x10 : 0; + PokeySound_Initialize(&asap); + PokeySound_Mute(&asap, &asap.base_pokey, 0); + PokeySound_Mute(&asap, &asap.extra_pokey, 0); + PokeySound_StartFrame(&asap); +} + +__declspec(dllexport) void APokeySound_PutByte(int addr, int data) +{ + PokeySound_PutByte(&asap, addr, data); +} + +__declspec(dllexport) int APokeySound_GetRandom(int addr, int cycle) +{ + return PokeySound_GetRandom(&asap, addr, cycle); +} + +__declspec(dllexport) int APokeySound_Generate(int cycles, byte buffer[], ASAP_SampleFormat format) +{ + int len; + PokeySound_EndFrame(&asap, cycles); + len = PokeySound_Generate(&asap, buffer, 0, asap.samples, format); + PokeySound_StartFrame(&asap); + return len; +} + +__declspec(dllexport) void APokeySound_About(const char **name, const char **author, const char **description) +{ + *name = "Another POKEY sound emulator, v" ASAP_VERSION; + *author = "Piotr Fusik, (C) " ASAP_YEARS; + *description = "Part of ASAP, http://asap.sourceforge.net"; +} + +#endif /* APOKEYSND */ diff --git a/lib/rbcodec/codecs/libasap/asap.c b/lib/rbcodec/codecs/libasap/asap.c new file mode 100644 index 0000000000..1aeb843fa3 --- /dev/null +++ b/lib/rbcodec/codecs/libasap/asap.c @@ -0,0 +1,2273 @@ +/* + * asap.c - ASAP engine + * + * Copyright (C) 2005-2010 Piotr Fusik + * + * This file is part of ASAP (Another Slight Atari Player), + * see http://asap.sourceforge.net + * + * ASAP is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2 of the License, + * or (at your option) any later version. + * + * ASAP is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ASAP; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "asap_internal.h" + +static byte s_memory[65536]; +static ASAP_ModuleInfo s_module_info; + +#ifdef ASAP_ONLY_INFO + +#define GET_PLAYER(name) NULL + +#else + +#define GET_PLAYER(name) GET_RESOURCE(name, obx) + +FUNC(int, ASAP_GetByte, (P(ASAP_State PTR, ast), P(int, addr))) +{ + switch (addr & 0xff1f) { + case 0xd014: + return ast _ module_info->ntsc ? 0xf : 1; + case 0xd20a: + case 0xd21a: + return PokeySound_GetRandom(ast, addr, ast _ cycle); + case 0xd20e: + return ast _ irqst; + case 0xd21e: + if (ast _ extra_pokey_mask != 0) { + /* interrupts in the extra POKEY not emulated at the moment */ + return 0xff; + } + return ast _ irqst; + case 0xd20c: + case 0xd21c: + case 0xd20f: /* just because some SAP files rely on this */ + case 0xd21f: + return 0xff; + case 0xd40b: + case 0xd41b: + return ast _ scanline_number >> 1; + default: + return dGetByte(addr); + } +} + +FUNC(void, ASAP_PutByte, (P(ASAP_State PTR, ast), P(int, addr), P(int, data))) +{ + if ((addr >> 8) == 0xd2) { + if ((addr & (ast _ extra_pokey_mask + 0xf)) == 0xe) { + ast _ irqst |= data ^ 0xff; +#define SET_TIMER_IRQ(ch) \ + if ((data & ast _ irqst & ch) != 0) { \ + if (ast _ timer##ch##_cycle == NEVER) { \ + V(int, t) = ast _ base_pokey.tick_cycle##ch; \ + while (t < ast _ cycle) \ + t += ast _ base_pokey.period_cycles##ch; \ + ast _ timer##ch##_cycle = t; \ + if (ast _ nearest_event_cycle > t) \ + ast _ nearest_event_cycle = t; \ + } \ + } \ + else \ + ast _ timer##ch##_cycle = NEVER; + SET_TIMER_IRQ(1); + SET_TIMER_IRQ(2); + SET_TIMER_IRQ(4); + } + else + PokeySound_PutByte(ast, addr, data); + } + else if ((addr & 0xff0f) == 0xd40a) { + if (ast _ cycle <= ast _ next_scanline_cycle - 8) + ast _ cycle = ast _ next_scanline_cycle - 8; + else + ast _ cycle = ast _ next_scanline_cycle + 106; + } + else if ((addr & 0xff00) == ast _ module_info->covox_addr) { + V(PokeyState PTR, pst); + addr &= 3; + if (addr == 0 || addr == 3) + pst = ADDRESSOF ast _ base_pokey; + else + pst = ADDRESSOF ast _ extra_pokey; + pst _ delta_buffer[CYCLE_TO_SAMPLE(ast _ cycle)] += (data - UBYTE(ast _ covox[addr])) << DELTA_SHIFT_COVOX; + ast _ covox[addr] = CAST(byte) (data); + } + else if ((addr & 0xff1f) == 0xd01f) { + V(int, sample) = CYCLE_TO_SAMPLE(ast _ cycle); + V(int, delta); + data &= 8; + /* NOT data - ast _ consol; reverse to the POKEY sound */ + delta = (ast _ consol - data) << DELTA_SHIFT_GTIA; + ast _ consol = data; + ast _ base_pokey.delta_buffer[sample] += delta; + ast _ extra_pokey.delta_buffer[sample] += delta; + } + else + dPutByte(addr, data); +} + +#endif /* ASAP_ONLY_INFO */ + +#define UWORD(array, index) (UBYTE(array[index]) + (UBYTE(array[(index) + 1]) << 8)) + +#ifndef ASAP_ONLY_SAP + +#ifndef ASAP_ONLY_INFO + +#ifndef JAVA +#include "players.h" +#endif + +#define CMR_BASS_TABLE_OFFSET 0x70f + +CONST_ARRAY(byte, cmr_bass_table) + 0x5C, 0x56, 0x50, 0x4D, 0x47, 0x44, 0x41, 0x3E, + 0x38, 0x35, CAST(byte) (0x88), 0x7F, 0x79, 0x73, 0x6C, 0x67, + 0x60, 0x5A, 0x55, 0x51, 0x4C, 0x48, 0x43, 0x3F, + 0x3D, 0x39, 0x34, 0x33, 0x30, 0x2D, 0x2A, 0x28, + 0x25, 0x24, 0x21, 0x1F, 0x1E +END_CONST_ARRAY; + +#endif /* ASAP_ONLY_INFO */ + +CONST_ARRAY(int, perframe2fastplay) + 312, 312 / 2, 312 / 3, 312 / 4 +END_CONST_ARRAY; + +/* Loads native module (anything except SAP) and 6502 player routine. */ +PRIVATE FUNC(abool, load_native, ( + P(ASAP_State PTR, ast), P(ASAP_ModuleInfo PTR, module_info), + P(CONST BYTEARRAY, module), P(int, module_len), P(RESOURCE, player))) +{ +#ifndef ASAP_ONLY_INFO + V(int, player_last_byte); +#endif + V(int, music_last_byte); + V(int, block_len); + if ((UBYTE(module[0]) != 0xff || UBYTE(module[1]) != 0xff) + && (module[0] != 0 || module[1] != 0)) /* some CMC and clones start with zeros */ + return FALSE; + module_info _ music = UWORD(module, 2); +#ifndef ASAP_ONLY_INFO + module_info _ player = UWORD(player, 2); + player_last_byte = UWORD(player, 4); + if (module_info _ music <= player_last_byte) + return FALSE; +#endif + music_last_byte = UWORD(module, 4); + if (module_info _ music <= 0xd7ff && music_last_byte >= 0xd000) + return FALSE; + block_len = music_last_byte + 1 - module_info _ music; + if (6 + block_len != module_len) { + V(int, info_addr); + V(int, info_len); + if (module_info _ type != ASAP_TYPE_RMT || 11 + block_len > module_len) + return FALSE; + /* allow optional info for Raster Music Tracker */ + info_addr = UWORD(module, 6 + block_len); + if (info_addr != module_info _ music + block_len) + return FALSE; + info_len = UWORD(module, 8 + block_len) + 1 - info_addr; + if (10 + block_len + info_len != module_len) + return FALSE; + } +#ifndef ASAP_ONLY_INFO + if (ast != NULL) { + COPY_ARRAY(ast _ memory, module_info _ music, module, 6, block_len); + COPY_ARRAY(ast _ memory, module_info _ player, player, 6, player_last_byte + 1 - module_info _ player); + } +#endif + return TRUE; +} + +PRIVATE FUNC(void, set_song_duration, (P(ASAP_ModuleInfo PTR, module_info), P(int, player_calls))) +{ + module_info _ durations[module_info _ songs] = TO_INT(player_calls * module_info _ fastplay * 114000.0 / 1773447); + module_info _ songs++; +} + +#define SEEN_THIS_CALL 1 +#define SEEN_BEFORE 2 +#define SEEN_REPEAT 3 + +PRIVATE FUNC(void, parse_cmc_song, (P(ASAP_ModuleInfo PTR, module_info), P(CONST BYTEARRAY, module), P(int, pos))) +{ + V(int, tempo) = UBYTE(module[0x19]); + V(int, player_calls) = 0; + V(int, rep_start_pos) = 0; + V(int, rep_end_pos) = 0; + V(int, rep_times) = 0; + NEW_ARRAY(byte, seen, 0x55); + INIT_ARRAY(seen); + while (pos >= 0 && pos < 0x55) { + V(int, p1); + V(int, p2); + V(int, p3); + if (pos == rep_end_pos && rep_times > 0) { + for (p1 = 0; p1 < 0x55; p1++) + if (seen[p1] == SEEN_THIS_CALL || seen[p1] == SEEN_REPEAT) + seen[p1] = 0; + rep_times--; + pos = rep_start_pos; + } + if (seen[pos] != 0) { + if (seen[pos] != SEEN_THIS_CALL) + module_info _ loops[module_info _ songs] = TRUE; + break; + } + seen[pos] = SEEN_THIS_CALL; + p1 = UBYTE(module[0x206 + pos]); + p2 = UBYTE(module[0x25b + pos]); + p3 = UBYTE(module[0x2b0 + pos]); + if (p1 == 0xfe || p2 == 0xfe || p3 == 0xfe) { + pos++; + continue; + } + p1 >>= 4; + if (p1 == 8) + break; + if (p1 == 9) { + pos = p2; + continue; + } + if (p1 == 0xa) { + pos -= p2; + continue; + } + if (p1 == 0xb) { + pos += p2; + continue; + } + if (p1 == 0xc) { + tempo = p2; + pos++; + continue; + } + if (p1 == 0xd) { + pos++; + rep_start_pos = pos; + rep_end_pos = pos + p2; + rep_times = p3 - 1; + continue; + } + if (p1 == 0xe) { + module_info _ loops[module_info _ songs] = TRUE; + break; + } + p2 = rep_times > 0 ? SEEN_REPEAT : SEEN_BEFORE; + for (p1 = 0; p1 < 0x55; p1++) + if (seen[p1] == SEEN_THIS_CALL) + seen[p1] = CAST(byte) p2; + player_calls += tempo * (module_info _ type == ASAP_TYPE_CM3 ? 48 : 64); + pos++; + } + set_song_duration(module_info, player_calls); +} + +PRIVATE FUNC(abool, parse_cmc, ( + P(ASAP_State PTR, ast), P(ASAP_ModuleInfo PTR, module_info), + P(CONST BYTEARRAY, module), P(int, module_len), P(int, type), P(RESOURCE, player))) +{ + V(int, last_pos); + V(int, pos); + if (module_len < 0x306) + return FALSE; + module_info _ type = type; + if (!load_native(ast, module_info, module, module_len, player)) + return FALSE; +#ifndef ASAP_ONLY_INFO + if (ast != NULL && type == ASAP_TYPE_CMR) + COPY_ARRAY(ast _ memory, 0x500 + CMR_BASS_TABLE_OFFSET, cmr_bass_table, 0, sizeof(cmr_bass_table)); +#endif + last_pos = 0x54; + while (--last_pos >= 0) { + if (UBYTE(module[0x206 + last_pos]) < 0xb0 + || UBYTE(module[0x25b + last_pos]) < 0x40 + || UBYTE(module[0x2b0 + last_pos]) < 0x40) + break; + if (module_info _ channels == 2) { + if (UBYTE(module[0x306 + last_pos]) < 0xb0 + || UBYTE(module[0x35b + last_pos]) < 0x40 + || UBYTE(module[0x3b0 + last_pos]) < 0x40) + break; + } + } + module_info _ songs = 0; + parse_cmc_song(module_info, module, 0); + for (pos = 0; pos < last_pos && module_info _ songs < ASAP_SONGS_MAX; pos++) + if (UBYTE(module[0x206 + pos]) == 0x8f || UBYTE(module[0x206 + pos]) == 0xef) + parse_cmc_song(module_info, module, pos + 1); + return TRUE; +} + +PRIVATE FUNC(abool, is_dlt_track_empty, (P(CONST BYTEARRAY, module), P(int, pos))) +{ + return UBYTE(module[0x2006 + pos]) >= 0x43 + && UBYTE(module[0x2106 + pos]) >= 0x40 + && UBYTE(module[0x2206 + pos]) >= 0x40 + && UBYTE(module[0x2306 + pos]) >= 0x40; +} + +PRIVATE FUNC(abool, is_dlt_pattern_end, (P(CONST BYTEARRAY, module), P(int, pos), P(int, i))) +{ + V(int, ch); + for (ch = 0; ch < 4; ch++) { + V(int, pattern) = UBYTE(module[0x2006 + (ch << 8) + pos]); + if (pattern < 64) { + V(int, offset) = 6 + (pattern << 7) + (i << 1); + if ((module[offset] & 0x80) == 0 && (module[offset + 1] & 0x80) != 0) + return TRUE; + } + } + return FALSE; +} + +PRIVATE FUNC(void, parse_dlt_song, ( + P(ASAP_ModuleInfo PTR, module_info), P(CONST BYTEARRAY, module), + P(BOOLARRAY, seen), P(int, pos))) +{ + V(int, player_calls) = 0; + V(abool, loop) = FALSE; + V(int, tempo) = 6; + while (pos < 128 && !seen[pos] && is_dlt_track_empty(module, pos)) + seen[pos++] = TRUE; + module_info _ song_pos[module_info _ songs] = CAST(byte) pos; + while (pos < 128) { + V(int, p1); + if (seen[pos]) { + loop = TRUE; + break; + } + seen[pos] = TRUE; + p1 = module[0x2006 + pos]; + if (p1 == 0x40 || is_dlt_track_empty(module, pos)) + break; + if (p1 == 0x41) + pos = UBYTE(module[0x2086 + pos]); + else if (p1 == 0x42) + tempo = UBYTE(module[0x2086 + pos++]); + else { + V(int, i); + for (i = 0; i < 64 && !is_dlt_pattern_end(module, pos, i); i++) + player_calls += tempo; + pos++; + } + } + if (player_calls > 0) { + module_info _ loops[module_info _ songs] = loop; + set_song_duration(module_info, player_calls); + } +} + +PRIVATE FUNC(abool, parse_dlt, ( + P(ASAP_State PTR, ast), P(ASAP_ModuleInfo PTR, module_info), + P(CONST BYTEARRAY, module), P(int, module_len))) +{ + V(int, pos); + NEW_ARRAY(abool, seen, 128); + if (module_len == 0x2c06) { + if (ast != NULL) + ast _ memory[0x4c00] = 0; + } + else if (module_len != 0x2c07) + return FALSE; + module_info _ type = ASAP_TYPE_DLT; + if (!load_native(ast, module_info, module, module_len, GET_PLAYER(dlt)) + || module_info _ music != 0x2000) { + return FALSE; + } + INIT_ARRAY(seen); + module_info _ songs = 0; + for (pos = 0; pos < 128 && module_info _ songs < ASAP_SONGS_MAX; pos++) { + if (!seen[pos]) + parse_dlt_song(module_info, module, seen, pos); + } + return module_info _ songs > 0; +} + +PRIVATE FUNC(void, parse_mpt_song, ( + P(ASAP_ModuleInfo PTR, module_info), P(CONST BYTEARRAY, module), + P(BOOLARRAY, global_seen), P(int, song_len), P(int, pos))) +{ + V(int, addr_to_offset) = UWORD(module, 2) - 6; + V(int, tempo) = UBYTE(module[0x1cf]); + V(int, player_calls) = 0; + NEW_ARRAY(byte, seen, 256); + NEW_ARRAY(int, pattern_offset, 4); + NEW_ARRAY(int, blank_rows, 4); + NEW_ARRAY(int, blank_rows_counter, 4); + INIT_ARRAY(seen); + INIT_ARRAY(blank_rows); + while (pos < song_len) { + V(int, i); + V(int, ch); + V(int, pattern_rows); + if (seen[pos] != 0) { + if (seen[pos] != SEEN_THIS_CALL) + module_info _ loops[module_info _ songs] = TRUE; + break; + } + seen[pos] = SEEN_THIS_CALL; + global_seen[pos] = TRUE; + i = UBYTE(module[0x1d0 + pos * 2]); + if (i == 0xff) { + pos = UBYTE(module[0x1d1 + pos * 2]); + continue; + } + for (ch = 3; ch >= 0; ch--) { + i = UBYTE(module[0x1c6 + ch]) + (UBYTE(module[0x1ca + ch]) << 8) - addr_to_offset; + i = UBYTE(module[i + pos * 2]); + if (i >= 0x40) + break; + i <<= 1; + i = UWORD(module, 0x46 + i); + pattern_offset[ch] = i == 0 ? 0 : i - addr_to_offset; + blank_rows_counter[ch] = 0; + } + if (ch >= 0) + break; + for (i = 0; i < song_len; i++) + if (seen[i] == SEEN_THIS_CALL) + seen[i] = SEEN_BEFORE; + for (pattern_rows = UBYTE(module[0x1ce]); --pattern_rows >= 0; ) { + for (ch = 3; ch >= 0; ch--) { + if (pattern_offset[ch] == 0 || --blank_rows_counter[ch] >= 0) + continue; + for (;;) { + i = UBYTE(module[pattern_offset[ch]++]); + if (i < 0x40 || i == 0xfe) + break; + if (i < 0x80) + continue; + if (i < 0xc0) { + blank_rows[ch] = i - 0x80; + continue; + } + if (i < 0xd0) + continue; + if (i < 0xe0) { + tempo = i - 0xcf; + continue; + } + pattern_rows = 0; + } + blank_rows_counter[ch] = blank_rows[ch]; + } + player_calls += tempo; + } + pos++; + } + if (player_calls > 0) + set_song_duration(module_info, player_calls); +} + +PRIVATE FUNC(abool, parse_mpt, ( + P(ASAP_State PTR, ast), P(ASAP_ModuleInfo PTR, module_info), + P(CONST BYTEARRAY, module), P(int, module_len))) +{ + V(int, track0_addr); + V(int, pos); + V(int, song_len); + /* seen[i] == TRUE if the track position i has been processed */ + NEW_ARRAY(abool, global_seen, 256); + if (module_len < 0x1d0) + return FALSE; + module_info _ type = ASAP_TYPE_MPT; + if (!load_native(ast, module_info, module, module_len, GET_PLAYER(mpt))) + return FALSE; + track0_addr = UWORD(module, 2) + 0x1ca; + if (UBYTE(module[0x1c6]) + (UBYTE(module[0x1ca]) << 8) != track0_addr) + return FALSE; + /* Calculate the length of the first track. Address of the second track minus + address of the first track equals the length of the first track in bytes. + Divide by two to get number of track positions. */ + song_len = (UBYTE(module[0x1c7]) + (UBYTE(module[0x1cb]) << 8) - track0_addr) >> 1; + if (song_len > 0xfe) + return FALSE; + INIT_ARRAY(global_seen); + module_info _ songs = 0; + for (pos = 0; pos < song_len && module_info _ songs < ASAP_SONGS_MAX; pos++) { + if (!global_seen[pos]) { + module_info _ song_pos[module_info _ songs] = CAST(byte) pos; + parse_mpt_song(module_info, module, global_seen, song_len, pos); + } + } + return module_info _ songs > 0; +} + +CONST_ARRAY(byte, rmt_volume_silent) + 16, 8, 4, 3, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1 +END_CONST_ARRAY; + +PRIVATE FUNC(int, rmt_instrument_frames, ( + P(CONST BYTEARRAY, module), P(int, instrument), + P(int, volume), P(int, volume_frame), P(abool, extra_pokey))) +{ + V(int, addr_to_offset) = UWORD(module, 2) - 6; + V(int, per_frame) = module[0xc]; + V(int, player_call); + V(int, player_calls); + V(int, index); + V(int, index_end); + V(int, index_loop); + V(int, volume_slide_depth); + V(int, volume_min); + V(int, volume_slide); + V(abool, silent_loop); + instrument = UWORD(module, 0xe) - addr_to_offset + (instrument << 1); + if (module[instrument + 1] == 0) + return 0; + instrument = UWORD(module, instrument) - addr_to_offset; + player_calls = player_call = volume_frame * per_frame; + index = UBYTE(module[instrument]) + 1 + player_call * 3; + index_end = UBYTE(module[instrument + 2]) + 3; + index_loop = UBYTE(module[instrument + 3]); + if (index_loop >= index_end) + return 0; /* error */ + volume_slide_depth = UBYTE(module[instrument + 6]); + volume_min = UBYTE(module[instrument + 7]); + if (index >= index_end) + index = (index - index_end) % (index_end - index_loop) + index_loop; + else { + do { + V(int, vol) = module[instrument + index]; + if (extra_pokey) + vol >>= 4; + if ((vol & 0xf) >= rmt_volume_silent[volume]) + player_calls = player_call + 1; + player_call++; + index += 3; + } while (index < index_end); + } + if (volume_slide_depth == 0) + return player_calls / per_frame; + volume_slide = 128; + silent_loop = FALSE; + for (;;) { + V(int, vol); + if (index >= index_end) { + if (silent_loop) + break; + silent_loop = TRUE; + index = index_loop; + } + vol = module[instrument + index]; + if (extra_pokey) + vol >>= 4; + if ((vol & 0xf) >= rmt_volume_silent[volume]) { + player_calls = player_call + 1; + silent_loop = FALSE; + } + player_call++; + index += 3; + volume_slide -= volume_slide_depth; + if (volume_slide < 0) { + volume_slide += 256; + if (--volume <= volume_min) + break; + } + } + return player_calls / per_frame; +} + +PRIVATE FUNC(void, parse_rmt_song, ( + P(ASAP_ModuleInfo PTR, module_info), P(CONST BYTEARRAY, module), + P(BOOLARRAY, global_seen), P(int, song_len), P(int, pos_shift), P(int, pos))) +{ + V(int, ch); + V(int, addr_to_offset) = UWORD(module, 2) - 6; + V(int, tempo) = UBYTE(module[0xb]); + V(int, frames) = 0; + V(int, song_offset) = UWORD(module, 0x14) - addr_to_offset; + V(int, pattern_lo_offset) = UWORD(module, 0x10) - addr_to_offset; + V(int, pattern_hi_offset) = UWORD(module, 0x12) - addr_to_offset; + V(int, instrument_frames); + NEW_ARRAY(byte, seen, 256); + NEW_ARRAY(int, pattern_begin, 8); + NEW_ARRAY(int, pattern_offset, 8); + NEW_ARRAY(int, blank_rows, 8); + NEW_ARRAY(int, instrument_no, 8); + NEW_ARRAY(int, instrument_frame, 8); + NEW_ARRAY(int, volume_value, 8); + NEW_ARRAY(int, volume_frame, 8); + INIT_ARRAY(seen); + INIT_ARRAY(instrument_no); + INIT_ARRAY(instrument_frame); + INIT_ARRAY(volume_value); + INIT_ARRAY(volume_frame); + while (pos < song_len) { + V(int, i); + V(int, pattern_rows); + if (seen[pos] != 0) { + if (seen[pos] != SEEN_THIS_CALL) + module_info _ loops[module_info _ songs] = TRUE; + break; + } + seen[pos] = SEEN_THIS_CALL; + global_seen[pos] = TRUE; + if (UBYTE(module[song_offset + (pos << pos_shift)]) == 0xfe) { + pos = UBYTE(module[song_offset + (pos << pos_shift) + 1]); + continue; + } + for (ch = 0; ch < 1 << pos_shift; ch++) { + i = UBYTE(module[song_offset + (pos << pos_shift) + ch]); + if (i == 0xff) + blank_rows[ch] = 256; + else { + pattern_offset[ch] = pattern_begin[ch] = UBYTE(module[pattern_lo_offset + i]) + + (UBYTE(module[pattern_hi_offset + i]) << 8) - addr_to_offset; + blank_rows[ch] = 0; + } + } + for (i = 0; i < song_len; i++) + if (seen[i] == SEEN_THIS_CALL) + seen[i] = SEEN_BEFORE; + for (pattern_rows = UBYTE(module[0xa]); --pattern_rows >= 0; ) { + for (ch = 0; ch < 1 << pos_shift; ch++) { + if (--blank_rows[ch] > 0) + continue; + for (;;) { + i = UBYTE(module[pattern_offset[ch]++]); + if ((i & 0x3f) < 62) { + i += UBYTE(module[pattern_offset[ch]++]) << 8; + if ((i & 0x3f) != 61) { + instrument_no[ch] = i >> 10; + instrument_frame[ch] = frames; + } + volume_value[ch] = (i >> 6) & 0xf; + volume_frame[ch] = frames; + break; + } + if (i == 62) { + blank_rows[ch] = UBYTE(module[pattern_offset[ch]++]); + break; + } + if ((i & 0x3f) == 62) { + blank_rows[ch] = i >> 6; + break; + } + if ((i & 0xbf) == 63) { + tempo = UBYTE(module[pattern_offset[ch]++]); + continue; + } + if (i == 0xbf) { + pattern_offset[ch] = pattern_begin[ch] + UBYTE(module[pattern_offset[ch]]); + continue; + } + /* assert(i == 0xff); */ + pattern_rows = -1; + break; + } + if (pattern_rows < 0) + break; + } + if (pattern_rows >= 0) + frames += tempo; + } + pos++; + } + instrument_frames = 0; + for (ch = 0; ch < 1 << pos_shift; ch++) { + V(int, frame) = instrument_frame[ch]; + frame += rmt_instrument_frames(module, instrument_no[ch], volume_value[ch], volume_frame[ch] - frame, ch >= 4); + if (instrument_frames < frame) + instrument_frames = frame; + } + if (frames > instrument_frames) { + if (frames - instrument_frames > 100) + module_info _ loops[module_info _ songs] = FALSE; + frames = instrument_frames; + } + if (frames > 0) + set_song_duration(module_info, frames); +} + +PRIVATE FUNC(abool, parse_rmt, ( + P(ASAP_State PTR, ast), P(ASAP_ModuleInfo PTR, module_info), + P(CONST BYTEARRAY, module), P(int, module_len))) +{ + V(int, per_frame); + V(int, pos_shift); + V(int, song_len); + V(int, pos); + NEW_ARRAY(abool, global_seen, 256); + if (module_len < 0x30 || module[6] != CHARCODE('R') || module[7] != CHARCODE('M') + || module[8] != CHARCODE('T') || module[0xd] != 1) + return FALSE; + switch (CAST(char) module[9]) { + case CHARCODE('4'): + pos_shift = 2; + break; + case CHARCODE('8'): + module_info _ channels = 2; + pos_shift = 3; + break; + default: + return FALSE; + } + per_frame = module[0xc]; + if (per_frame < 1 || per_frame > 4) + return FALSE; + module_info _ type = ASAP_TYPE_RMT; + if (!load_native(ast, module_info, module, module_len, + module_info _ channels == 2 ? GET_PLAYER(rmt8) : GET_PLAYER(rmt4))) + return FALSE; + song_len = UWORD(module, 4) + 1 - UWORD(module, 0x14); + if (pos_shift == 3 && (song_len & 4) != 0 + && UBYTE(module[6 + UWORD(module, 4) - UWORD(module, 2) - 3]) == 0xfe) + song_len += 4; + song_len >>= pos_shift; + if (song_len >= 0x100) + return FALSE; + INIT_ARRAY(global_seen); + module_info _ songs = 0; + for (pos = 0; pos < song_len && module_info _ songs < ASAP_SONGS_MAX; pos++) { + if (!global_seen[pos]) { + module_info _ song_pos[module_info _ songs] = CAST(byte) pos; + parse_rmt_song(module_info, module, global_seen, song_len, pos_shift, pos); + } + } + /* must set fastplay after song durations calculations, so they assume 312 */ + module_info _ fastplay = perframe2fastplay[per_frame - 1]; + module_info _ player = 0x600; + return module_info _ songs > 0; +} + +PRIVATE FUNC(void, parse_tmc_song, ( + P(ASAP_ModuleInfo PTR, module_info), P(CONST BYTEARRAY, module), P(int, pos))) +{ + V(int, addr_to_offset) = UWORD(module, 2) - 6; + V(int, tempo) = UBYTE(module[0x24]) + 1; + V(int, frames) = 0; + NEW_ARRAY(int, pattern_offset, 8); + NEW_ARRAY(int, blank_rows, 8); + while (UBYTE(module[0x1a6 + 15 + pos]) < 0x80) { + V(int, ch); + V(int, pattern_rows); + for (ch = 7; ch >= 0; ch--) { + V(int, pat) = UBYTE(module[0x1a6 + 15 + pos - 2 * ch]); + pattern_offset[ch] = UBYTE(module[0xa6 + pat]) + (UBYTE(module[0x126 + pat]) << 8) - addr_to_offset; + blank_rows[ch] = 0; + } + for (pattern_rows = 64; --pattern_rows >= 0; ) { + for (ch = 7; ch >= 0; ch--) { + if (--blank_rows[ch] >= 0) + continue; + for (;;) { + V(int, i) = UBYTE(module[pattern_offset[ch]++]); + if (i < 0x40) { + pattern_offset[ch]++; + break; + } + if (i == 0x40) { + i = UBYTE(module[pattern_offset[ch]++]); + if ((i & 0x7f) == 0) + pattern_rows = 0; + else + tempo = (i & 0x7f) + 1; + if (i >= 0x80) + pattern_offset[ch]++; + break; + } + if (i < 0x80) { + i = module[pattern_offset[ch]++] & 0x7f; + if (i == 0) + pattern_rows = 0; + else + tempo = i + 1; + pattern_offset[ch]++; + break; + } + if (i < 0xc0) + continue; + blank_rows[ch] = i - 0xbf; + break; + } + } + frames += tempo; + } + pos += 16; + } + if (UBYTE(module[0x1a6 + 14 + pos]) < 0x80) + module_info _ loops[module_info _ songs] = TRUE; + set_song_duration(module_info, frames); +} + +PRIVATE FUNC(abool, parse_tmc, ( + P(ASAP_State PTR, ast), P(ASAP_ModuleInfo PTR, module_info), + P(CONST BYTEARRAY, module), P(int, module_len))) +{ + V(int, i); + V(int, last_pos); + if (module_len < 0x1d0) + return FALSE; + module_info _ type = ASAP_TYPE_TMC; + if (!load_native(ast, module_info, module, module_len, GET_PLAYER(tmc))) + return FALSE; + module_info _ channels = 2; + i = 0; + /* find first instrument */ + while (module[0x66 + i] == 0) { + if (++i >= 64) + return FALSE; /* no instrument */ + } + last_pos = (UBYTE(module[0x66 + i]) << 8) + UBYTE(module[0x26 + i]) + - UWORD(module, 2) - 0x1b0; + if (0x1b5 + last_pos >= module_len) + return FALSE; + /* skip trailing jumps */ + do { + if (last_pos <= 0) + return FALSE; /* no pattern to play */ + last_pos -= 16; + } while (UBYTE(module[0x1b5 + last_pos]) >= 0x80); + module_info _ songs = 0; + parse_tmc_song(module_info, module, 0); + for (i = 0; i < last_pos && module_info _ songs < ASAP_SONGS_MAX; i += 16) + if (UBYTE(module[0x1b5 + i]) >= 0x80) + parse_tmc_song(module_info, module, i + 16); + /* must set fastplay after song durations calculations, so they assume 312 */ + i = module[0x25]; + if (i < 1 || i > 4) + return FALSE; + if (ast != NULL) + ast _ tmc_per_frame = module[0x25]; + module_info _ fastplay = perframe2fastplay[i - 1]; + return TRUE; +} + +PRIVATE FUNC(void, parse_tm2_song, ( + P(ASAP_ModuleInfo PTR, module_info), P(CONST BYTEARRAY, module), P(int, pos))) +{ + V(int, addr_to_offset) = UWORD(module, 2) - 6; + V(int, tempo) = UBYTE(module[0x24]) + 1; + V(int, player_calls) = 0; + NEW_ARRAY(int, pattern_offset, 8); + NEW_ARRAY(int, blank_rows, 8); + for (;;) { + V(int, ch); + V(int, pattern_rows) = UBYTE(module[0x386 + 16 + pos]); + if (pattern_rows == 0) + break; + if (pattern_rows >= 0x80) { + module_info _ loops[module_info _ songs] = TRUE; + break; + } + for (ch = 7; ch >= 0; ch--) { + V(int, pat) = UBYTE(module[0x386 + 15 + pos - 2 * ch]); + pattern_offset[ch] = UBYTE(module[0x106 + pat]) + (UBYTE(module[0x206 + pat]) << 8) - addr_to_offset; + blank_rows[ch] = 0; + } + while (--pattern_rows >= 0) { + for (ch = 7; ch >= 0; ch--) { + if (--blank_rows[ch] >= 0) + continue; + for (;;) { + V(int, i) = UBYTE(module[pattern_offset[ch]++]); + if (i == 0) { + pattern_offset[ch]++; + break; + } + if (i < 0x40) { + if (UBYTE(module[pattern_offset[ch]++]) >= 0x80) + pattern_offset[ch]++; + break; + } + if (i < 0x80) { + pattern_offset[ch]++; + break; + } + if (i == 0x80) { + blank_rows[ch] = UBYTE(module[pattern_offset[ch]++]); + break; + } + if (i < 0xc0) + break; + if (i < 0xd0) { + tempo = i - 0xbf; + continue; + } + if (i < 0xe0) { + pattern_offset[ch]++; + break; + } + if (i < 0xf0) { + pattern_offset[ch] += 2; + break; + } + if (i < 0xff) { + blank_rows[ch] = i - 0xf0; + break; + } + blank_rows[ch] = 64; + break; + } + } + player_calls += tempo; + } + pos += 17; + } + set_song_duration(module_info, player_calls); +} + +PRIVATE FUNC(abool, parse_tm2, ( + P(ASAP_State PTR, ast), P(ASAP_ModuleInfo PTR, module_info), + P(CONST BYTEARRAY, module), P(int, module_len))) +{ + V(int, i); + V(int, last_pos); + V(int, c); + if (module_len < 0x3a4) + return FALSE; + module_info _ type = ASAP_TYPE_TM2; + if (!load_native(ast, module_info, module, module_len, GET_PLAYER(tm2))) + return FALSE; + i = module[0x25]; + if (i < 1 || i > 4) + return FALSE; + module_info _ fastplay = perframe2fastplay[i - 1]; + module_info _ player = 0x500; + if (module[0x1f] != 0) + module_info _ channels = 2; + last_pos = 0xffff; + for (i = 0; i < 0x80; i++) { + V(int, instr_addr) = UBYTE(module[0x86 + i]) + (UBYTE(module[0x306 + i]) << 8); + if (instr_addr != 0 && instr_addr < last_pos) + last_pos = instr_addr; + } + for (i = 0; i < 0x100; i++) { + V(int, pattern_addr) = UBYTE(module[0x106 + i]) + (UBYTE(module[0x206 + i]) << 8); + if (pattern_addr != 0 && pattern_addr < last_pos) + last_pos = pattern_addr; + } + last_pos -= UWORD(module, 2) + 0x380; + if (0x386 + last_pos >= module_len) + return FALSE; + /* skip trailing stop/jump commands */ + do { + if (last_pos <= 0) + return FALSE; + last_pos -= 17; + c = UBYTE(module[0x386 + 16 + last_pos]); + } while (c == 0 || c >= 0x80); + module_info _ songs = 0; + parse_tm2_song(module_info, module, 0); + for (i = 0; i < last_pos && module_info _ songs < ASAP_SONGS_MAX; i += 17) { + c = UBYTE(module[0x386 + 16 + i]); + if (c == 0 || c >= 0x80) + parse_tm2_song(module_info, module, i + 17); + } + return TRUE; +} + +#endif /* ASAP_ONLY_SAP */ + +PRIVATE FUNC(abool, has_string_at, (P(CONST BYTEARRAY, module), P(int, module_index), P(STRING, s))) +{ + V(int, i); + V(int, n) = strlen(s); + for (i = 0; i < n; i++) + if (module[module_index + i] != CHARCODEAT(s, i)) + return FALSE; + return TRUE; +} + +PRIVATE FUNC(STRING, parse_text, (P(OUT_STRING, dest), P(CONST BYTEARRAY, module), P(int, module_index))) +{ + V(int, i); + if (module[module_index] != CHARCODE('"')) + return NULL; + if (has_string_at(module, module_index + 1, "\"")) + return dest; + for (i = 0; ; i++) { + V(int, c) = module[module_index + 1 + i]; + if (c == CHARCODE('"')) + break; + if (c < 32 || c >= 127) + return NULL; + } + BYTES_TO_STRING(dest, module, module_index + 1, i); + return dest; +} + +PRIVATE FUNC(int, parse_dec, (P(CONST BYTEARRAY, module), P(int, module_index), P(int, maxval))) +{ + V(int, r); + if (module[module_index] == 0xd) + return -1; + for (r = 0;;) { + V(int, c) = module[module_index++]; + if (c == 0xd) + break; + if (c < CHARCODE('0') || c > CHARCODE('9')) + return -1; + r = 10 * r + c - 48; + if (r > maxval) + return -1; + } + return r; +} + +PRIVATE FUNC(int, parse_hex, (P(CONST BYTEARRAY, module), P(int, module_index))) +{ + V(int, r); + if (module[module_index] == 0xd) + return -1; + for (r = 0;;) { + V(int, c) = module[module_index++]; + if (c == 0xd) + break; + if (r > 0xfff) + return -1; + r <<= 4; + if (c >= CHARCODE('0') && c <= CHARCODE('9')) + r += c - CHARCODE('0'); + else if (c >= CHARCODE('A') && c <= CHARCODE('F')) + r += c - CHARCODE('A') + 10; + else if (c >= CHARCODE('a') && c <= CHARCODE('f')) + r += c - CHARCODE('a') + 10; + else + return -1; + } + return r; +} + +FUNC(int, ASAP_ParseDuration, (P(STRING, s))) +{ + V(int, i) = 0; + V(int, r); + V(int, d); + V(int, n) = strlen(s); +#define PARSE_DIGIT(maxdig, retifnot) \ + if (i >= n) \ + return retifnot; \ + d = CHARCODEAT(s, i) - 48; \ + if (d < 0 || d > maxdig) \ + return -1; \ + i++; + + PARSE_DIGIT(9, -1); + r = d; + if (i < n) { + d = CHARCODEAT(s, i) - 48; + if (d >= 0 && d <= 9) { + i++; + r = 10 * r + d; + } + if (i < n && CHARAT(s, i) == ':') { + i++; + PARSE_DIGIT(5, -1); + r = (6 * r + d) * 10; + PARSE_DIGIT(9, -1); + r += d; + } + } + r *= 1000; + if (i >= n) + return r; + if (CHARAT(s, i) != '.') + return -1; + i++; + PARSE_DIGIT(9, -1); + r += 100 * d; + PARSE_DIGIT(9, r); + r += 10 * d; + PARSE_DIGIT(9, r); + r += d; + return r; +} + +PRIVATE FUNC(abool, parse_sap_header, ( + P(ASAP_ModuleInfo PTR, module_info), P(CONST BYTEARRAY, module), P(int, module_len))) +{ + V(int, module_index); + V(int, type) = 0; + V(int, duration_index) = 0; + if (!has_string_at(module, 0, "SAP\r\n")) + return FALSE; + module_info _ fastplay = -1; + module_index = 5; + while (UBYTE(module[module_index]) != 0xff) { + if (module_index + 8 >= module_len) + return FALSE; +#define TAG_IS(s) has_string_at(module, module_index, s) +#ifdef C +#define SET_TEXT(v, i) if (parse_text(v, module, module_index + i) == NULL) return FALSE +#else +#define SET_TEXT(v, i) v = parse_text(v, module, module_index + i); if (v == NULL) return FALSE +#endif +#define SET_DEC(v, i, min, max) v = parse_dec(module, module_index + i, max); if (v < min) return FALSE +#define SET_HEX(v, i) v = parse_hex(module, module_index + i) + if (TAG_IS("AUTHOR ")) { + SET_TEXT(module_info _ author, 7); + } + else if (TAG_IS("NAME ")) { + SET_TEXT(module_info _ name, 5); + } + else if (TAG_IS("DATE ")) { + SET_TEXT(module_info _ date, 5); + } + else if (TAG_IS("SONGS ")) { + SET_DEC(module_info _ songs, 6, 1, ASAP_SONGS_MAX); + } + else if (TAG_IS("DEFSONG ")) { + SET_DEC(module_info _ default_song, 8, 0, ASAP_SONGS_MAX - 1); + } + else if (TAG_IS("STEREO\r")) + module_info _ channels = 2; + else if (TAG_IS("NTSC\r")) + module_info _ ntsc = TRUE; + else if (TAG_IS("TIME ")) { + V(int, i); +#ifdef C + char s[ASAP_DURATION_CHARS]; +#else + V(STRING, s); +#endif + module_index += 5; + for (i = 0; module[module_index + i] != 0xd; i++) { } + if (i > 5 && has_string_at(module, module_index + i - 5, " LOOP")) { + module_info _ loops[duration_index] = TRUE; + i -= 5; + } +#ifdef C + if (i >= ASAP_DURATION_CHARS) + return FALSE; +#endif + BYTES_TO_STRING(s, module, module_index, i); + i = ASAP_ParseDuration(s); + if (i < 0 || duration_index >= ASAP_SONGS_MAX) + return FALSE; + module_info _ durations[duration_index++] = i; + } + else if (TAG_IS("TYPE ")) + type = module[module_index + 5]; + else if (TAG_IS("FASTPLAY ")) { + SET_DEC(module_info _ fastplay, 9, 1, 312); + } + else if (TAG_IS("MUSIC ")) { + SET_HEX(module_info _ music, 6); + } + else if (TAG_IS("INIT ")) { + SET_HEX(module_info _ init, 5); + } + else if (TAG_IS("PLAYER ")) { + SET_HEX(module_info _ player, 7); + } + else if (TAG_IS("COVOX ")) { + SET_HEX(module_info _ covox_addr, 6); + if (module_info _ covox_addr != 0xd600) + return FALSE; + module_info _ channels = 2; + } + + while (module[module_index++] != 0x0d) { + if (module_index >= module_len) + return FALSE; + } + if (module[module_index++] != 0x0a) + return FALSE; + } + if (module_info _ default_song >= module_info _ songs) + return FALSE; + switch (type) { + case CHARCODE('B'): + if (module_info _ player < 0 || module_info _ init < 0) + return FALSE; + module_info _ type = ASAP_TYPE_SAP_B; + break; + case CHARCODE('C'): + if (module_info _ player < 0 || module_info _ music < 0) + return FALSE; + module_info _ type = ASAP_TYPE_SAP_C; + break; + case CHARCODE('D'): + if (module_info _ init < 0) + return FALSE; + module_info _ type = ASAP_TYPE_SAP_D; + break; + case CHARCODE('S'): + if (module_info _ init < 0) + return FALSE; + module_info _ type = ASAP_TYPE_SAP_S; + module_info _ fastplay = 78; + break; + default: + return FALSE; + } + if (module_info _ fastplay < 0) + module_info _ fastplay = module_info _ ntsc ? 262 : 312; + else if (module_info _ ntsc && module_info _ fastplay > 262) + return FALSE; + if (UBYTE(module[module_index + 1]) != 0xff) + return FALSE; + module_info _ header_len = module_index; + return TRUE; +} + +PRIVATE FUNC(abool, parse_sap, ( + P(ASAP_State PTR, ast), P(ASAP_ModuleInfo PTR, module_info), + P(CONST BYTEARRAY, module), P(int, module_len))) +{ + V(int, module_index); + if (!parse_sap_header(module_info, module, module_len)) + return FALSE; + if (ast == NULL) + return TRUE; + ZERO_ARRAY(ast _ memory); + module_index = module_info _ header_len + 2; + while (module_index + 5 <= module_len) { + V(int, start_addr) = UWORD(module, module_index); + V(int, block_len) = UWORD(module, module_index + 2) + 1 - start_addr; + if (block_len <= 0 || module_index + block_len > module_len) + return FALSE; + module_index += 4; + COPY_ARRAY(ast _ memory, start_addr, module, module_index, block_len); + module_index += block_len; + if (module_index == module_len) + return TRUE; + if (module_index + 7 <= module_len + && UBYTE(module[module_index]) == 0xff && UBYTE(module[module_index + 1]) == 0xff) + module_index += 2; + } + return FALSE; +} + +#define ASAP_EXT(c1, c2, c3) ((CHARCODE(c1) + (CHARCODE(c2) << 8) + (CHARCODE(c3) << 16)) | 0x202020) + +PRIVATE FUNC(int, get_packed_ext, (P(STRING, filename))) +{ + V(int, i) = strlen(filename); + V(int, ext) = 0; + while (--i > 0) { + V(char, c) = CHARAT(filename, i); + if (c <= ' ' || c > 'z') + return 0; + if (c == '.') + return ext | 0x202020; + ext = (ext << 8) + CHARCODE(c); + } + return 0; +} + +PRIVATE FUNC(abool, is_our_ext, (P(int, ext))) +{ + switch (ext) { + case ASAP_EXT('S', 'A', 'P'): +#ifndef ASAP_ONLY_SAP + case ASAP_EXT('C', 'M', 'C'): + case ASAP_EXT('C', 'M', '3'): + case ASAP_EXT('C', 'M', 'R'): + case ASAP_EXT('C', 'M', 'S'): + case ASAP_EXT('D', 'M', 'C'): + case ASAP_EXT('D', 'L', 'T'): + case ASAP_EXT('M', 'P', 'T'): + case ASAP_EXT('M', 'P', 'D'): + case ASAP_EXT('R', 'M', 'T'): + case ASAP_EXT('T', 'M', 'C'): + case ASAP_EXT('T', 'M', '8'): + case ASAP_EXT('T', 'M', '2'): +#endif + return TRUE; + default: + return FALSE; + } +} + +FUNC(abool, ASAP_IsOurFile, (P(STRING, filename))) +{ + V(int, ext) = get_packed_ext(filename); + return is_our_ext(ext); +} + +FUNC(abool, ASAP_IsOurExt, (P(STRING, ext))) +{ + return strlen(ext) == 3 + && is_our_ext(ASAP_EXT(CHARAT(ext, 0), CHARAT(ext, 1), CHARAT(ext, 2))); +} + +PRIVATE FUNC(abool, parse_file, ( + P(ASAP_State PTR, ast), P(ASAP_ModuleInfo PTR, module_info), + P(STRING, filename), P(CONST BYTEARRAY, module), P(int, module_len))) +{ + V(int, i); + V(int, len) = strlen(filename); + V(int, basename) = 0; + V(int, ext) = -1; + for (i = 0; i < len; i++) { + V(char, c) = CHARAT(filename, i); + if (c == '/' || c == '\\') { + basename = i + 1; + ext = -1; + } + else if (c == '.') + ext = i; + } + if (ext < 0) + return FALSE; + EMPTY_STRING(module_info _ author); + SUBSTRING(module_info _ name, filename, basename, ext - basename); + EMPTY_STRING(module_info _ date); + module_info _ channels = 1; + module_info _ songs = 1; + module_info _ default_song = 0; + for (i = 0; i < ASAP_SONGS_MAX; i++) { + module_info _ durations[i] = -1; + module_info _ loops[i] = FALSE; + } + module_info _ ntsc = FALSE; + module_info _ fastplay = 312; + module_info _ music = -1; + module_info _ init = -1; + module_info _ player = -1; + module_info _ covox_addr = -1; + switch (get_packed_ext(filename)) { + case ASAP_EXT('S', 'A', 'P'): + return parse_sap(ast, module_info, module, module_len); +#ifndef ASAP_ONLY_SAP + case ASAP_EXT('C', 'M', 'C'): + return parse_cmc(ast, module_info, module, module_len, ASAP_TYPE_CMC, GET_PLAYER(cmc)); + case ASAP_EXT('C', 'M', '3'): + return parse_cmc(ast, module_info, module, module_len, ASAP_TYPE_CM3, GET_PLAYER(cm3)); + case ASAP_EXT('C', 'M', 'R'): + return parse_cmc(ast, module_info, module, module_len, ASAP_TYPE_CMR, GET_PLAYER(cmc)); + case ASAP_EXT('C', 'M', 'S'): + module_info _ channels = 2; + return parse_cmc(ast, module_info, module, module_len, ASAP_TYPE_CMS, GET_PLAYER(cms)); + case ASAP_EXT('D', 'M', 'C'): + module_info _ fastplay = 156; + return parse_cmc(ast, module_info, module, module_len, ASAP_TYPE_CMC, GET_PLAYER(cmc)); + case ASAP_EXT('D', 'L', 'T'): + return parse_dlt(ast, module_info, module, module_len); + case ASAP_EXT('M', 'P', 'T'): + return parse_mpt(ast, module_info, module, module_len); + case ASAP_EXT('M', 'P', 'D'): + module_info _ fastplay = 156; + return parse_mpt(ast, module_info, module, module_len); + case ASAP_EXT('R', 'M', 'T'): + return parse_rmt(ast, module_info, module, module_len); + case ASAP_EXT('T', 'M', 'C'): + case ASAP_EXT('T', 'M', '8'): + return parse_tmc(ast, module_info, module, module_len); + case ASAP_EXT('T', 'M', '2'): + return parse_tm2(ast, module_info, module, module_len); +#endif + default: + return FALSE; + } +} + +FUNC(abool, ASAP_GetModuleInfo, ( + P(ASAP_ModuleInfo PTR, module_info), P(STRING, filename), + P(CONST BYTEARRAY, module), P(int, module_len))) +{ + return parse_file(NULL, module_info, filename, module, module_len); +} + +#ifndef ASAP_ONLY_INFO + +FUNC(abool, ASAP_Load, ( + P(ASAP_State PTR, ast), P(STRING, filename), + P(CONST BYTEARRAY, module), P(int, module_len))) +{ + /* Set up ast */ + ast _ memory = s_memory; + ast _ module_info = &s_module_info; + ast _ silence_cycles = 0; + return parse_file(ast, ast _ module_info, filename, module, module_len); +} + +FUNC(void, ASAP_DetectSilence, (P(ASAP_State PTR, ast), P(int, seconds))) +{ + ast _ silence_cycles = seconds * ASAP_MAIN_CLOCK(ast); +} + +PRIVATE FUNC(void, call_6502, (P(ASAP_State PTR, ast), P(int, addr), P(int, max_scanlines))) +{ + ast _ cpu_pc = addr; + /* put a CIM at 0xd20a and a return address on stack */ + dPutByte(0xd20a, 0xd2); + dPutByte(0x01fe, 0x09); + dPutByte(0x01ff, 0xd2); + ast _ cpu_s = 0xfd; + Cpu_RunScanlines(ast, max_scanlines); +} + +/* 50 Atari frames for the initialization routine - some SAPs are self-extracting. */ +#define SCANLINES_FOR_INIT (50 * 312) + +PRIVATE FUNC(void, call_6502_init, (P(ASAP_State PTR, ast), P(int, addr), P(int, a), P(int, x), P(int, y))) +{ + ast _ cpu_a = a & 0xff; + ast _ cpu_x = x & 0xff; + ast _ cpu_y = y & 0xff; + call_6502(ast, addr, SCANLINES_FOR_INIT); +} + +FUNC(void, ASAP_PlaySong, (P(ASAP_State PTR, ast), P(int, song), P(int, duration))) +{ + ast _ current_song = song; + ast _ current_duration = duration; + ast _ blocks_played = 0; + ast _ silence_cycles_counter = ast _ silence_cycles; + ast _ extra_pokey_mask = ast _ module_info->channels > 1 ? 0x10 : 0; + ast _ consol = 8; + ast _ covox[0] = CAST(byte) 0x80; + ast _ covox[1] = CAST(byte) 0x80; + ast _ covox[2] = CAST(byte) 0x80; + ast _ covox[3] = CAST(byte) 0x80; + PokeySound_Initialize(ast); + ast _ cycle = 0; + ast _ cpu_nz = 0; + ast _ cpu_c = 0; + ast _ cpu_vdi = 0; + ast _ scanline_number = 0; + ast _ next_scanline_cycle = 0; + ast _ timer1_cycle = NEVER; + ast _ timer2_cycle = NEVER; + ast _ timer4_cycle = NEVER; + ast _ irqst = 0xff; + switch (ast _ module_info->type) { + case ASAP_TYPE_SAP_B: + call_6502_init(ast, ast _ module_info->init, song, 0, 0); + break; + case ASAP_TYPE_SAP_C: +#ifndef ASAP_ONLY_SAP + case ASAP_TYPE_CMC: + case ASAP_TYPE_CM3: + case ASAP_TYPE_CMR: + case ASAP_TYPE_CMS: +#endif + call_6502_init(ast, ast _ module_info->player + 3, 0x70, ast _ module_info->music, ast _ module_info->music >> 8); + call_6502_init(ast, ast _ module_info->player + 3, 0x00, song, 0); + break; + case ASAP_TYPE_SAP_D: + case ASAP_TYPE_SAP_S: + ast _ cpu_a = song; + ast _ cpu_x = 0x00; + ast _ cpu_y = 0x00; + ast _ cpu_s = 0xff; + ast _ cpu_pc = ast _ module_info->init; + break; +#ifndef ASAP_ONLY_SAP + case ASAP_TYPE_DLT: + call_6502_init(ast, ast _ module_info->player + 0x100, 0x00, 0x00, ast _ module_info->song_pos[song]); + break; + case ASAP_TYPE_MPT: + call_6502_init(ast, ast _ module_info->player, 0x00, ast _ module_info->music >> 8, ast _ module_info->music); + call_6502_init(ast, ast _ module_info->player, 0x02, ast _ module_info->song_pos[song], 0); + break; + case ASAP_TYPE_RMT: + call_6502_init(ast, ast _ module_info->player, ast _ module_info->song_pos[song], ast _ module_info->music, ast _ module_info->music >> 8); + break; + case ASAP_TYPE_TMC: + case ASAP_TYPE_TM2: + call_6502_init(ast, ast _ module_info->player, 0x70, ast _ module_info->music >> 8, ast _ module_info->music); + call_6502_init(ast, ast _ module_info->player, 0x00, song, 0); + ast _ tmc_per_frame_counter = 1; + break; +#endif + } + ASAP_MutePokeyChannels(ast, 0); +} + +FUNC(void, ASAP_MutePokeyChannels, (P(ASAP_State PTR, ast), P(int, mask))) +{ + PokeySound_Mute(ast, ADDRESSOF ast _ base_pokey, mask); + PokeySound_Mute(ast, ADDRESSOF ast _ extra_pokey, mask >> 4); +} + +FUNC(abool, call_6502_player, (P(ASAP_State PTR, ast))) +{ + V(int, player) = ast _ module_info->player; + PokeySound_StartFrame(ast); + switch (ast _ module_info->type) { + case ASAP_TYPE_SAP_B: + call_6502(ast, player, ast _ module_info->fastplay); + break; + case ASAP_TYPE_SAP_C: +#ifndef ASAP_ONLY_SAP + case ASAP_TYPE_CMC: + case ASAP_TYPE_CM3: + case ASAP_TYPE_CMR: + case ASAP_TYPE_CMS: +#endif + call_6502(ast, player + 6, ast _ module_info->fastplay); + break; + case ASAP_TYPE_SAP_D: + if (player >= 0) { + V(int, s)= ast _ cpu_s; +#define PUSH_ON_6502_STACK(x) dPutByte(0x100 + s, x); s = (s - 1) & 0xff +#define RETURN_FROM_PLAYER_ADDR 0xd200 + /* save 6502 state on 6502 stack */ + PUSH_ON_6502_STACK(ast _ cpu_pc >> 8); + PUSH_ON_6502_STACK(ast _ cpu_pc & 0xff); + PUSH_ON_6502_STACK(((ast _ cpu_nz | (ast _ cpu_nz >> 1)) & 0x80) + ast _ cpu_vdi + \ + ((ast _ cpu_nz & 0xff) == 0 ? Z_FLAG : 0) + ast _ cpu_c + 0x20); + PUSH_ON_6502_STACK(ast _ cpu_a); + PUSH_ON_6502_STACK(ast _ cpu_x); + PUSH_ON_6502_STACK(ast _ cpu_y); + /* RTS will jump to 6502 code that restores the state */ + PUSH_ON_6502_STACK((RETURN_FROM_PLAYER_ADDR - 1) >> 8); + PUSH_ON_6502_STACK((RETURN_FROM_PLAYER_ADDR - 1) & 0xff); + ast _ cpu_s = s; + dPutByte(RETURN_FROM_PLAYER_ADDR, 0x68); /* PLA */ + dPutByte(RETURN_FROM_PLAYER_ADDR + 1, 0xa8); /* TAY */ + dPutByte(RETURN_FROM_PLAYER_ADDR + 2, 0x68); /* PLA */ + dPutByte(RETURN_FROM_PLAYER_ADDR + 3, 0xaa); /* TAX */ + dPutByte(RETURN_FROM_PLAYER_ADDR + 4, 0x68); /* PLA */ + dPutByte(RETURN_FROM_PLAYER_ADDR + 5, 0x40); /* RTI */ + ast _ cpu_pc = player; + } + Cpu_RunScanlines(ast, ast _ module_info->fastplay); + break; + case ASAP_TYPE_SAP_S: + Cpu_RunScanlines(ast, ast _ module_info->fastplay); + { + V(int, i) = dGetByte(0x45) - 1; + dPutByte(0x45, i); + if (i == 0) + dPutByte(0xb07b, dGetByte(0xb07b) + 1); + } + break; +#ifndef ASAP_ONLY_SAP + case ASAP_TYPE_DLT: + call_6502(ast, player + 0x103, ast _ module_info->fastplay); + break; + case ASAP_TYPE_MPT: + case ASAP_TYPE_RMT: + case ASAP_TYPE_TM2: + call_6502(ast, player + 3, ast _ module_info->fastplay); + break; + case ASAP_TYPE_TMC: + if (--ast _ tmc_per_frame_counter <= 0) { + ast _ tmc_per_frame_counter = ast _ tmc_per_frame; + call_6502(ast, player + 3, ast _ module_info->fastplay); + } + else + call_6502(ast, player + 6, ast _ module_info->fastplay); + break; +#endif + } + PokeySound_EndFrame(ast, ast _ module_info->fastplay * 114); + if (ast _ silence_cycles > 0) { + if (PokeySound_IsSilent(ADDRESSOF ast _ base_pokey) + && PokeySound_IsSilent(ADDRESSOF ast _ extra_pokey)) { + ast _ silence_cycles_counter -= ast _ module_info->fastplay * 114; + if (ast _ silence_cycles_counter <= 0) + return FALSE; + } + else + ast _ silence_cycles_counter = ast _ silence_cycles; + } + return TRUE; +} + +FUNC(int, ASAP_GetPosition, (P(CONST ASAP_State PTR, ast))) +{ + return ast _ blocks_played * 10 / (ASAP_SAMPLE_RATE / 100); +} + +FUNC(int, milliseconds_to_blocks, (P(int, milliseconds))) +{ + return milliseconds * (ASAP_SAMPLE_RATE / 100) / 10; +} + +#ifndef ACTIONSCRIPT + +FUNC(void, ASAP_Seek, (P(ASAP_State PTR, ast), P(int, position))) +{ + V(int, block) = milliseconds_to_blocks(position); + if (block < ast _ blocks_played) + ASAP_PlaySong(ast, ast _ current_song, ast _ current_duration); + while (ast _ blocks_played + ast _ samples - ast _ sample_index < block) { + ast _ blocks_played += ast _ samples - ast _ sample_index; + call_6502_player(ast); + } + ast _ sample_index += block - ast _ blocks_played; + ast _ blocks_played = block; +} + +PRIVATE FUNC(void, serialize_int, (P(BYTEARRAY, buffer), P(int, offset), P(int, value))) +{ + buffer[offset] = TO_BYTE(value); + buffer[offset + 1] = TO_BYTE(value >> 8); + buffer[offset + 2] = TO_BYTE(value >> 16); + buffer[offset + 3] = TO_BYTE(value >> 24); +} + +FUNC(void, ASAP_GetWavHeader, ( + P(CONST ASAP_State PTR, ast), P(BYTEARRAY, buffer), P(ASAP_SampleFormat, format))) +{ + V(int, use_16bit) = format != ASAP_FORMAT_U8 ? 1 : 0; + V(int, block_size) = ast _ module_info->channels << use_16bit; + V(int, bytes_per_second) = ASAP_SAMPLE_RATE * block_size; + V(int, total_blocks) = milliseconds_to_blocks(ast _ current_duration); + V(int, n_bytes) = (total_blocks - ast _ blocks_played) * block_size; + buffer[0] = CAST(byte) CHARCODE('R'); + buffer[1] = CAST(byte) CHARCODE('I'); + buffer[2] = CAST(byte) CHARCODE('F'); + buffer[3] = CAST(byte) CHARCODE('F'); + serialize_int(buffer, 4, n_bytes + 36); + buffer[8] = CAST(byte) CHARCODE('W'); + buffer[9] = CAST(byte) CHARCODE('A'); + buffer[10] = CAST(byte) CHARCODE('V'); + buffer[11] = CAST(byte) CHARCODE('E'); + buffer[12] = CAST(byte) CHARCODE('f'); + buffer[13] = CAST(byte) CHARCODE('m'); + buffer[14] = CAST(byte) CHARCODE('t'); + buffer[15] = CAST(byte) CHARCODE(' '); + buffer[16] = 16; + buffer[17] = 0; + buffer[18] = 0; + buffer[19] = 0; + buffer[20] = 1; + buffer[21] = 0; + buffer[22] = CAST(byte) ast _ module_info->channels; + buffer[23] = 0; + serialize_int(buffer, 24, ASAP_SAMPLE_RATE); + serialize_int(buffer, 28, bytes_per_second); + buffer[32] = CAST(byte) block_size; + buffer[33] = 0; + buffer[34] = CAST(byte) (8 << use_16bit); + buffer[35] = 0; + buffer[36] = CAST(byte) CHARCODE('d'); + buffer[37] = CAST(byte) CHARCODE('a'); + buffer[38] = CAST(byte) CHARCODE('t'); + buffer[39] = CAST(byte) CHARCODE('a'); + serialize_int(buffer, 40, n_bytes); +} + +#endif /* ACTIONSCRIPT */ + +PRIVATE FUNC(int, ASAP_GenerateAt, (P(ASAP_State PTR, ast), P(VOIDPTR, buffer), P(int, buffer_offset), P(int, buffer_len), P(ASAP_SampleFormat, format))) +{ + V(int, block_shift); + V(int, buffer_blocks); + V(int, block); + if (ast _ silence_cycles > 0 && ast _ silence_cycles_counter <= 0) + return 0; +#ifdef ACTIONSCRIPT + block_shift = 0; +#else + block_shift = (ast _ module_info->channels - 1) + (format != ASAP_FORMAT_U8 ? 1 : 0); +#endif + buffer_blocks = buffer_len >> block_shift; + if (ast _ current_duration > 0) { + V(int, total_blocks) = milliseconds_to_blocks(ast _ current_duration); + if (buffer_blocks > total_blocks - ast _ blocks_played) + buffer_blocks = total_blocks - ast _ blocks_played; + } + block = 0; + do { + V(int, blocks) = PokeySound_Generate(ast, CAST(BYTEARRAY) buffer, + buffer_offset + (block << block_shift), buffer_blocks - block, format); + ast _ blocks_played += blocks; + block += blocks; + } while (block < buffer_blocks && call_6502_player(ast)); + return block << block_shift; +} + +FUNC(int, ASAP_Generate, (P(ASAP_State PTR, ast), P(VOIDPTR, buffer), P(int, buffer_len), P(ASAP_SampleFormat, format))) +{ + return ASAP_GenerateAt(ast, buffer, 0, buffer_len, format); +} + +#endif /* ASAP_ONLY_INFO */ + +#ifdef C + +abool ASAP_CanSetModuleInfo(const char *filename) +{ + int ext = get_packed_ext(filename); + return ext == ASAP_EXT('S', 'A', 'P'); +} + +abool ASAP_ChangeExt(char *filename, const char *ext) +{ + char *dest = NULL; + while (*filename != '\0') { + if (*filename == '/' || *filename == '\\') + dest = NULL; + else if (*filename == '.') + dest = filename + 1; + filename++; + } + if (dest == NULL) + return FALSE; + strcpy(dest, ext); + return TRUE; +} + +static byte *put_string(byte *dest, const char *str) +{ + while (*str != '\0') + *dest++ = *str++; + return dest; +} + +static byte *put_dec(byte *dest, int value) +{ + if (value >= 10) { + dest = put_dec(dest, value / 10); + value %= 10; + } + *dest++ = '0' + value; + return dest; +} + +static byte *put_text_tag(byte *dest, const char *tag, const char *value) +{ + dest = put_string(dest, tag); + *dest++ = '"'; + if (*value == '\0') + value = ""; + while (*value != '\0') { + if (*value < ' ' || *value > 'z' || *value == '"' || *value == '`') + return NULL; + *dest++ = *value++; + } + *dest++ = '"'; + *dest++ = '\r'; + *dest++ = '\n'; + return dest; +} + +static byte *put_dec_tag(byte *dest, const char *tag, int value) +{ + dest = put_string(dest, tag); + dest = put_dec(dest, value); + *dest++ = '\r'; + *dest++ = '\n'; + return dest; +} + +static byte *start_sap_header(byte *dest, const ASAP_ModuleInfo *module_info) +{ + dest = put_string(dest, "SAP\r\n"); + dest = put_text_tag(dest, "AUTHOR ", module_info->author); + if (dest == NULL) + return NULL; + dest = put_text_tag(dest, "NAME ", module_info->name); + if (dest == NULL) + return NULL; + dest = put_text_tag(dest, "DATE ", module_info->date); + if (dest == NULL) + return NULL; + if (module_info->songs > 1) { + dest = put_dec_tag(dest, "SONGS ", module_info->songs); + if (module_info->default_song > 0) + dest = put_dec_tag(dest, "DEFSONG ", module_info->default_song); + } + if (module_info->channels > 1) + dest = put_string(dest, "STEREO\r\n"); + return dest; +} + +static char *two_digits(char *s, int x) +{ + s[0] = '0' + x / 10; + s[1] = '0' + x % 10; + return s + 2; +} + +void ASAP_DurationToString(char *s, int duration) +{ + if (duration >= 0 && duration < 100 * 60 * 1000) { + int seconds = duration / 1000; + s = two_digits(s, seconds / 60); + *s++ = ':'; + s = two_digits(s, seconds % 60); + duration %= 1000; + if (duration != 0) { + *s++ = '.'; + s = two_digits(s, duration / 10); + duration %= 10; + if (duration != 0) + *s++ = '0' + duration; + } + } + *s = '\0'; +} + +static byte *put_durations(byte *dest, const ASAP_ModuleInfo *module_info) +{ + int song; + for (song = 0; song < module_info->songs; song++) { + if (module_info->durations[song] < 0) + break; + dest = put_string(dest, "TIME "); + ASAP_DurationToString((char *) dest, module_info->durations[song]); + while (*dest != '\0') + dest++; + if (module_info->loops[song]) + dest = put_string(dest, " LOOP"); + *dest++ = '\r'; + *dest++ = '\n'; + } + return dest; +} + +int ASAP_SetModuleInfo(const ASAP_ModuleInfo *module_info, const BYTEARRAY module, int module_len, BYTEARRAY out_module) +{ + byte *dest; + int i; + if (memcmp(module, "SAP\r\n", 5) != 0) + return -1; + dest = start_sap_header(out_module, module_info); + if (dest == NULL) + return -1; + i = 5; + while (i < module_len && module[i] != 0xff) { + if (memcmp(module + i, "AUTHOR ", 7) == 0 + || memcmp(module + i, "NAME ", 5) == 0 + || memcmp(module + i, "DATE ", 5) == 0 + || memcmp(module + i, "SONGS ", 6) == 0 + || memcmp(module + i, "DEFSONG ", 8) == 0 + || memcmp(module + i, "STEREO\r", 7) == 0 + || memcmp(module + i, "TIME ", 5) == 0) { + while (i < module_len && module[i++] != 0x0a); + } + else { + int b; + do { + b = module[i++]; + *dest++ = b; + } while (i < module_len && b != 0x0a); + } + } + dest = put_durations(dest, module_info); + module_len -= i; + memcpy(dest, module + i, module_len); + dest += module_len; + return dest - out_module; +} + +#if !defined(ASAP_ONLY_SAP) && !defined(ASAP_ONLY_INFO) + +#define RMT_INIT 0x0c80 +#define TM2_INIT 0x1080 + +const char *ASAP_CanConvert( + const char *filename, const ASAP_ModuleInfo *module_info, + const BYTEARRAY module, int module_len) +{ + (void) filename; + switch (module_info->type) { + case ASAP_TYPE_SAP_B: + if ((module_info->init == 0x3fb || module_info->init == 0x3f9) && module_info->player == 0x503) + return "dlt"; + if (module_info->init == 0x4f3 || module_info->init == 0xf4f3 || module_info->init == 0x4ef) + return module_info->fastplay == 156 ? "mpd" : "mpt"; + if (module_info->init == RMT_INIT) + return "rmt"; + if ((module_info->init == 0x4f5 || module_info->init == 0xf4f5 || module_info->init == 0x4f2) + || ((module_info->init == 0x4e7 || module_info->init == 0xf4e7 || module_info->init == 0x4e4) && module_info->fastplay == 156) + || ((module_info->init == 0x4e5 || module_info->init == 0xf4e5 || module_info->init == 0x4e2) && (module_info->fastplay == 104 || module_info->fastplay == 78))) + return "tmc"; + if (module_info->init == TM2_INIT) + return "tm2"; + break; + case ASAP_TYPE_SAP_C: + if (module_info->player == 0x500 || module_info->player == 0xf500) { + if (module_info->fastplay == 156) + return "dmc"; + if (module_info->channels > 1) + return "cms"; + if (module[module_len - 170] == 0x1e) + return "cmr"; + if (module[module_len - 909] == 0x30) + return "cm3"; + return "cmc"; + } + break; + case ASAP_TYPE_CMC: + case ASAP_TYPE_CM3: + case ASAP_TYPE_CMR: + case ASAP_TYPE_CMS: + case ASAP_TYPE_DLT: + case ASAP_TYPE_MPT: + case ASAP_TYPE_RMT: + case ASAP_TYPE_TMC: + case ASAP_TYPE_TM2: + return "sap"; + default: + break; + } + return NULL; +} + +static byte *put_hex_tag(byte *dest, const char *tag, int value) +{ + int i; + if (value < 0) + return dest; + dest = put_string(dest, tag); + for (i = 12; i >= 0; i -= 4) { + int digit = (value >> i) & 0xf; + *dest++ = (byte) (digit + (digit < 10 ? '0' : 'A' - 10)); + } + *dest++ = '\r'; + *dest++ = '\n'; + return dest; +} + +static byte *put_sap_header(byte *dest, const ASAP_ModuleInfo *module_info, char type, int music, int init, int player) +{ + dest = start_sap_header(dest, module_info); + if (dest == NULL) + return NULL; + dest = put_string(dest, "TYPE "); + *dest++ = type; + *dest++ = '\r'; + *dest++ = '\n'; + if (module_info->fastplay != 312) + dest = put_dec_tag(dest, "FASTPLAY ", module_info->fastplay); + dest = put_hex_tag(dest, "MUSIC ", music); + dest = put_hex_tag(dest, "INIT ", init); + dest = put_hex_tag(dest, "PLAYER ", player); + dest = put_durations(dest, module_info); + return dest; +} + +int ASAP_Convert( + const char *filename, const ASAP_ModuleInfo *module_info, + const BYTEARRAY module, int module_len, BYTEARRAY out_module) +{ + (void) filename; + int out_len; + byte *dest; + int addr; + int player; + static const int tmc_player[4] = { 3, -9, -10, -10 }; + static const int tmc_init[4] = { -14, -16, -17, -17 }; + switch (module_info->type) { + case ASAP_TYPE_SAP_B: + case ASAP_TYPE_SAP_C: + out_len = UWORD(module, module_info->header_len + 4) - UWORD(module, module_info->header_len + 2) + 7; + if (out_len < 7 || module_info->header_len + out_len >= module_len) + return -1; + memcpy(out_module, module + module_info->header_len, out_len); + return out_len; + case ASAP_TYPE_CMC: + case ASAP_TYPE_CM3: + case ASAP_TYPE_CMR: + case ASAP_TYPE_CMS: + dest = put_sap_header(out_module, module_info, 'C', module_info->music, -1, module_info->player); + if (dest == NULL) + return -1; + memcpy(dest, module, module_len); + dest[0] = 0xff; /* some modules start with zeros */ + dest[1] = 0xff; + dest += module_len; + if (module_info->type == ASAP_TYPE_CM3) { + memcpy(dest, cm3_obx + 2, sizeof(cm3_obx) - 2); + dest += sizeof(cm3_obx) - 2; + } + else if (module_info->type == ASAP_TYPE_CMS) { + memcpy(dest, cms_obx + 2, sizeof(cms_obx) - 2); + dest += sizeof(cms_obx) - 2; + } + else { + memcpy(dest, cmc_obx + 2, sizeof(cmc_obx) - 2); + if (module_info->type == ASAP_TYPE_CMR) + memcpy(dest + 4 + CMR_BASS_TABLE_OFFSET, cmr_bass_table, sizeof(cmr_bass_table)); + dest += sizeof(cmc_obx) - 2; + } + return dest - out_module; + case ASAP_TYPE_DLT: + if (module_info->songs != 1) { + addr = module_info->player - 7 - module_info->songs; + dest = put_sap_header(out_module, module_info, 'B', -1, module_info->player - 7, module_info->player + 0x103); + } + else { + addr = module_info->player - 5; + dest = put_sap_header(out_module, module_info, 'B', -1, addr, module_info->player + 0x103); + } + if (dest == NULL) + return -1; + memcpy(dest, module, module_len); + if (module_len == 0x2c06) { + dest[4] = 0; + dest[5] = 0x4c; + dest[0x2c06] = 0; + } + dest += 0x2c07; + *dest++ = (byte) addr; + *dest++ = (byte) (addr >> 8); + *dest++ = dlt_obx[4]; + *dest++ = dlt_obx[5]; + if (module_info->songs != 1) { + memcpy(dest, module_info->song_pos, module_info->songs); + dest += module_info->songs; + *dest++ = 0xaa; /* tax */ + *dest++ = 0xbc; /* ldy song2pos,x */ + *dest++ = (byte) addr; + *dest++ = (byte) (addr >> 8); + } + else { + *dest++ = 0xa0; /* ldy #0 */ + *dest++ = 0; + } + *dest++ = 0x4c; /* jmp init */ + *dest++ = (byte) module_info->player; + *dest++ = (byte) ((module_info->player >> 8) + 1); + memcpy(dest, dlt_obx + 6, sizeof(dlt_obx) - 6); + dest += sizeof(dlt_obx) - 6; + return dest - out_module; + case ASAP_TYPE_MPT: + if (module_info->songs != 1) { + addr = module_info->player - 17 - module_info->songs; + dest = put_sap_header(out_module, module_info, 'B', -1, module_info->player - 17, module_info->player + 3); + } + else { + addr = module_info->player - 13; + dest = put_sap_header(out_module, module_info, 'B', -1, addr, module_info->player + 3); + } + if (dest == NULL) + return -1; + memcpy(dest, module, module_len); + dest += module_len; + *dest++ = (byte) addr; + *dest++ = (byte) (addr >> 8); + *dest++ = mpt_obx[4]; + *dest++ = mpt_obx[5]; + if (module_info->songs != 1) { + memcpy(dest, module_info->song_pos, module_info->songs); + dest += module_info->songs; + *dest++ = 0x48; /* pha */ + } + *dest++ = 0xa0; /* ldy #music; + *dest++ = 0xa2; /* ldx #>music */ + *dest++ = (byte) (module_info->music >> 8); + *dest++ = 0xa9; /* lda #0 */ + *dest++ = 0; + *dest++ = 0x20; /* jsr player */ + *dest++ = (byte) module_info->player; + *dest++ = (byte) (module_info->player >> 8); + if (module_info->songs != 1) { + *dest++ = 0x68; /* pla */ + *dest++ = 0xa8; /* tay */ + *dest++ = 0xbe; /* ldx song2pos,y */ + *dest++ = (byte) addr; + *dest++ = (byte) (addr >> 8); + } + else { + *dest++ = 0xa2; /* ldx #0 */ + *dest++ = 0; + } + *dest++ = 0xa9; /* lda #2 */ + *dest++ = 2; + memcpy(dest, mpt_obx + 6, sizeof(mpt_obx) - 6); + dest += sizeof(mpt_obx) - 6; + return dest - out_module; + case ASAP_TYPE_RMT: + dest = put_sap_header(out_module, module_info, 'B', -1, RMT_INIT, module_info->player + 3); + if (dest == NULL) + return -1; + memcpy(dest, module, module_len); + dest += module_len; + *dest++ = (byte) RMT_INIT; + *dest++ = (byte) (RMT_INIT >> 8); + if (module_info->songs != 1) { + addr = RMT_INIT + 10 + module_info->songs; + *dest++ = (byte) addr; + *dest++ = (byte) (addr >> 8); + *dest++ = 0xa8; /* tay */ + *dest++ = 0xb9; /* lda song2pos,y */ + *dest++ = (byte) (RMT_INIT + 11); + *dest++ = (byte) ((RMT_INIT + 11) >> 8); + } + else { + *dest++ = (byte) (RMT_INIT + 8); + *dest++ = (byte) ((RMT_INIT + 8) >> 8); + *dest++ = 0xa9; /* lda #0 */ + *dest++ = 0; + } + *dest++ = 0xa2; /* ldx #music; + *dest++ = 0xa0; /* ldy #>music */ + *dest++ = (byte) (module_info->music >> 8); + *dest++ = 0x4c; /* jmp player */ + *dest++ = (byte) module_info->player; + *dest++ = (byte) (module_info->player >> 8); + if (module_info->songs != 1) { + memcpy(dest, module_info->song_pos, module_info->songs); + dest += module_info->songs; + } + if (module_info->channels == 1) { + memcpy(dest, rmt4_obx + 2, sizeof(rmt4_obx) - 2); + dest += sizeof(rmt4_obx) - 2; + } + else { + memcpy(dest, rmt8_obx + 2, sizeof(rmt8_obx) - 2); + dest += sizeof(rmt8_obx) - 2; + } + return dest - out_module; + case ASAP_TYPE_TMC: + player = module_info->player + tmc_player[module[0x25] - 1]; + addr = player + tmc_init[module[0x25] - 1]; + if (module_info->songs != 1) + addr -= 3; + dest = put_sap_header(out_module, module_info, 'B', -1, addr, player); + if (dest == NULL) + return -1; + memcpy(dest, module, module_len); + dest += module_len; + *dest++ = (byte) addr; + *dest++ = (byte) (addr >> 8); + *dest++ = tmc_obx[4]; + *dest++ = tmc_obx[5]; + if (module_info->songs != 1) + *dest++ = 0x48; /* pha */ + *dest++ = 0xa0; /* ldy #music; + *dest++ = 0xa2; /* ldx #>music */ + *dest++ = (byte) (module_info->music >> 8); + *dest++ = 0xa9; /* lda #$70 */ + *dest++ = 0x70; + *dest++ = 0x20; /* jsr player */ + *dest++ = (byte) module_info->player; + *dest++ = (byte) (module_info->player >> 8); + if (module_info->songs != 1) { + *dest++ = 0x68; /* pla */ + *dest++ = 0xaa; /* tax */ + *dest++ = 0xa9; /* lda #0 */ + *dest++ = 0; + } + else { + *dest++ = 0xa9; /* lda #$60 */ + *dest++ = 0x60; + } + switch (module[0x25]) { + case 2: + *dest++ = 0x06; /* asl 0 */ + *dest++ = 0; + *dest++ = 0x4c; /* jmp player */ + *dest++ = (byte) module_info->player; + *dest++ = (byte) (module_info->player >> 8); + *dest++ = 0xa5; /* lda 0 */ + *dest++ = 0; + *dest++ = 0xe6; /* inc 0 */ + *dest++ = 0; + *dest++ = 0x4a; /* lsr @ */ + *dest++ = 0x90; /* bcc player+3 */ + *dest++ = 5; + *dest++ = 0xb0; /* bcs player+6 */ + *dest++ = 6; + break; + case 3: + case 4: + *dest++ = 0xa0; /* ldy #1 */ + *dest++ = 1; + *dest++ = 0x84; /* sty 0 */ + *dest++ = 0; + *dest++ = 0xd0; /* bne player */ + *dest++ = 10; + *dest++ = 0xc6; /* dec 0 */ + *dest++ = 0; + *dest++ = 0xd0; /* bne player+6 */ + *dest++ = 12; + *dest++ = 0xa0; /* ldy #3 */ + *dest++ = module[0x25]; + *dest++ = 0x84; /* sty 0 */ + *dest++ = 0; + *dest++ = 0xd0; /* bne player+3 */ + *dest++ = 3; + break; + default: + break; + } + memcpy(dest, tmc_obx + 6, sizeof(tmc_obx) - 6); + dest += sizeof(tmc_obx) - 6; + return dest - out_module; + case ASAP_TYPE_TM2: + dest = put_sap_header(out_module, module_info, 'B', -1, TM2_INIT, module_info->player + 3); + if (dest == NULL) + return -1; + memcpy(dest, module, module_len); + dest += module_len; + *dest++ = (byte) TM2_INIT; + *dest++ = (byte) (TM2_INIT >> 8); + if (module_info->songs != 1) { + *dest++ = (byte) (TM2_INIT + 16); + *dest++ = (byte) ((TM2_INIT + 16) >> 8); + *dest++ = 0x48; /* pha */ + } + else { + *dest++ = (byte) (TM2_INIT + 14); + *dest++ = (byte) ((TM2_INIT + 14) >> 8); + } + *dest++ = 0xa0; /* ldy #music; + *dest++ = 0xa2; /* ldx #>music */ + *dest++ = (byte) (module_info->music >> 8); + *dest++ = 0xa9; /* lda #$70 */ + *dest++ = 0x70; + *dest++ = 0x20; /* jsr player */ + *dest++ = (byte) module_info->player; + *dest++ = (byte) (module_info->player >> 8); + if (module_info->songs != 1) { + *dest++ = 0x68; /* pla */ + *dest++ = 0xaa; /* tax */ + *dest++ = 0xa9; /* lda #0 */ + *dest++ = 0; + } + else { + *dest++ = 0xa9; /* lda #0 */ + *dest++ = 0; + *dest++ = 0xaa; /* tax */ + } + *dest++ = 0x4c; /* jmp player */ + *dest++ = (byte) module_info->player; + *dest++ = (byte) (module_info->player >> 8); + memcpy(dest, tm2_obx + 2, sizeof(tm2_obx) - 2); + dest += sizeof(tm2_obx) - 2; + return dest - out_module; + default: + return -1; + } +} + +#endif /* !defined(ASAP_ONLY_SAP) && !defined(ASAP_ONLY_INFO) */ + +static abool has_two_digits(const char *s) +{ + return s[0] >= '0' && s[0] <= '9' && s[1] >= '0' && s[1] <= '9'; +} + +/* "DD/MM/YYYY", "MM/YYYY", "YYYY" -> "YYYY" */ +abool ASAP_DateToYear(const char *date, char *year) +{ + if (!has_two_digits(date)) + return FALSE; + if (date[2] == '/') { + date += 3; + if (!has_two_digits(date)) + return FALSE; + if (date[2] == '/') { + date += 3; + if (!has_two_digits(date)) + return FALSE; + } + } + if (!has_two_digits(date + 2) || date[4] != '\0') + return FALSE; + memcpy(year, date, 5); + return TRUE; +} + +#endif /* C */ diff --git a/lib/rbcodec/codecs/libasap/asap.h b/lib/rbcodec/codecs/libasap/asap.h new file mode 100644 index 0000000000..1cbf8d0100 --- /dev/null +++ b/lib/rbcodec/codecs/libasap/asap.h @@ -0,0 +1,328 @@ +/* + * asap.h - public interface of ASAP + * + * Copyright (C) 2005-2010 Piotr Fusik + * + * This file is part of ASAP (Another Slight Atari Player), + * see http://asap.sourceforge.net + * + * ASAP is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2 of the License, + * or (at your option) any later version. + * + * ASAP is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ASAP; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _ASAP_H_ +#define _ASAP_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* ASAP version. */ +#define ASAP_VERSION_MAJOR 2 +#define ASAP_VERSION_MINOR 1 +#define ASAP_VERSION_MICRO 2 +#define ASAP_VERSION "2.1.2" + +/* Short credits of the ASAP engine. */ +#define ASAP_YEARS "2005-2010" +#define ASAP_CREDITS \ + "Another Slight Atari Player (C) 2005-2010 Piotr Fusik\n" \ + "CMC, MPT, TMC, TM2 players (C) 1994-2005 Marcin Lewandowski\n" \ + "RMT player (C) 2002-2005 Radek Sterba\n" \ + "DLT player (C) 2009 Marek Konopka\n" \ + "CMS player (C) 1999 David Spilka\n" + +/* Short GPL notice. + Display after the credits. */ +#define ASAP_COPYRIGHT \ + "This program is free software; you can redistribute it and/or modify\n" \ + "it under the terms of the GNU General Public License as published\n" \ + "by the Free Software Foundation; either version 2 of the License,\n" \ + "or (at your option) any later version." + +/* Maximum length of AUTHOR, NAME and DATE tags including the terminator. */ +#define ASAP_INFO_CHARS 128 + +/* Maximum length of a "mm:ss.xxx" string including the terminator. */ +#define ASAP_DURATION_CHARS 10 + +/* Maximum length of a supported input file. + You can assume that files longer than this are not supported by ASAP. */ +#define ASAP_MODULE_MAX 65000 + +/* Maximum number of songs in a file. */ +#define ASAP_SONGS_MAX 32 + +/* Output sample rate. */ +#define ASAP_SAMPLE_RATE 44100 + +/* WAV file header length. */ +#define ASAP_WAV_HEADER_BYTES 44 + +/* Output formats. */ +typedef enum { + ASAP_FORMAT_U8 = 8, /* unsigned char */ + ASAP_FORMAT_S16_LE = 16, /* signed short, little-endian */ + ASAP_FORMAT_S16_BE = -16 /* signed short, big-endian */ +} ASAP_SampleFormat; + +/* Useful type definitions. */ +#ifndef FALSE +#define FALSE 0 +#endif +#ifndef TRUE +#define TRUE 1 +#endif +typedef int abool; +typedef unsigned char byte; + +/* Information about a music file. */ +typedef struct { + char author[ASAP_INFO_CHARS]; /* author's name */ + char name[ASAP_INFO_CHARS]; /* title */ + char date[ASAP_INFO_CHARS]; /* creation date */ + int channels; /* 1 for mono or 2 for stereo */ + int songs; /* number of subsongs */ + int default_song; /* 0-based index of the "main" subsong */ + int durations[ASAP_SONGS_MAX]; /* lengths of songs, in milliseconds, -1 = indeterminate */ + abool loops[ASAP_SONGS_MAX]; /* whether songs repeat or not */ + /* the following technical information should not be used outside ASAP. */ + abool ntsc; + int type; + int fastplay; + int music; + int init; + int player; + int covox_addr; + int header_len; + byte song_pos[ASAP_SONGS_MAX]; +} ASAP_ModuleInfo; + +/* POKEY state. + Not for use outside the ASAP engine. */ +typedef struct { + int audctl; + abool init; + int poly_index; + int div_cycles; + int mute1; + int mute2; + int mute3; + int mute4; + int audf1; + int audf2; + int audf3; + int audf4; + int audc1; + int audc2; + int audc3; + int audc4; + int tick_cycle1; + int tick_cycle2; + int tick_cycle3; + int tick_cycle4; + int period_cycles1; + int period_cycles2; + int period_cycles3; + int period_cycles4; + int reload_cycles1; + int reload_cycles3; + int out1; + int out2; + int out3; + int out4; + int delta1; + int delta2; + int delta3; + int delta4; + int skctl; + int delta_buffer[888]; +} PokeyState; + +/* Player state. + Only module_info is meant to be read outside the ASAP engine. */ +typedef struct { + int cycle; + int cpu_pc; + int cpu_a; + int cpu_x; + int cpu_y; + int cpu_s; + int cpu_nz; + int cpu_c; + int cpu_vdi; + int scanline_number; + int nearest_event_cycle; + int next_scanline_cycle; + int timer1_cycle; + int timer2_cycle; + int timer4_cycle; + int irqst; + int extra_pokey_mask; + int consol; + byte covox[4]; + PokeyState base_pokey; + PokeyState extra_pokey; + int sample_offset; + int sample_index; + int samples; + int iir_acc_left; + int iir_acc_right; + ASAP_ModuleInfo *module_info; + int tmc_per_frame; + int tmc_per_frame_counter; + int current_song; + int current_duration; + int blocks_played; + int silence_cycles; + int silence_cycles_counter; + byte poly9_lookup[511]; + byte poly17_lookup[16385]; + byte *memory; +} ASAP_State; + +/* Parses the string in the "mm:ss.xxx" format + and returns the number of milliseconds or -1 if an error occurs. */ +int ASAP_ParseDuration(const char *s); + +/* Converts number of milliseconds to a string in the "mm:ss.xxx" format. */ +void ASAP_DurationToString(char *s, int duration); + +/* Checks whether the extension of the passed filename is known to ASAP. */ +abool ASAP_IsOurFile(const char *filename); + +/* Checks whether the filename extension is known to ASAP. */ +abool ASAP_IsOurExt(const char *ext); + +/* Changes the filename extension, returns true on success. */ +abool ASAP_ChangeExt(char *filename, const char *ext); + +/* Gets information about a module. + "module_info" is the structure where the information is returned. + "filename" determines file format. + "module" is the music data (contents of the file). + "module_len" is the number of data bytes. + ASAP_GetModuleInfo() returns true on success. */ +abool ASAP_GetModuleInfo(ASAP_ModuleInfo *module_info, const char *filename, + const byte module[], int module_len); + +/* Extracts year from date. */ +abool ASAP_DateToYear(const char *date, char *year); + +/* Loads music data. + "ast" is the destination structure. + "filename" determines file format. + "module" is the music data (contents of the file). + "module_len" is the number of data bytes. + ASAP does not make copies of the passed pointers. You can overwrite + or free "filename" and "module" once this function returns. + ASAP_Load() returns true on success. + If false is returned, the structure is invalid and you cannot + call the following functions. */ +abool ASAP_Load(ASAP_State *ast, const char *filename, + const byte module[], int module_len); + +/* Enables silence detection. + Makes ASAP finish playing after the specified period of silence. + "ast" is ASAP state initialized by ASAP_Load(). + "seconds" is the minimum length of silence that ends playback. */ +void ASAP_DetectSilence(ASAP_State *ast, int seconds); + +/* Prepares ASAP to play the specified song of the loaded module. + "ast" is ASAP state initialized by ASAP_Load(). + "song" is a zero-based index which must be less than the "songs" field + of the ASAP_ModuleInfo structure. + "duration" is playback time in milliseconds - use durations[song] + unless you want to override it. -1 means indefinitely. */ +void ASAP_PlaySong(ASAP_State *ast, int song, int duration); + +/* Mutes the selected POKEY channels. + This is only useful for people who want to grab samples of individual + instruments. + "ast" is ASAP state after calling ASAP_PlaySong(). + "mask" is a bit mask which selects POKEY channels to be muted. + Bits 0-3 control the base POKEY channels, + bits 4-7 control the extra POKEY channels. */ +void ASAP_MutePokeyChannels(ASAP_State *ast, int mask); + +/* Returns current position in milliseconds. + "ast" is ASAP state initialized by ASAP_PlaySong(). */ +int ASAP_GetPosition(const ASAP_State *ast); + +/* Rewinds the current song. + "ast" is ASAP state initialized by ASAP_PlaySong(). + "position" is the requested absolute position in milliseconds. */ +void ASAP_Seek(ASAP_State *ast, int position); + +/* Fills the specified buffer with WAV file header. + "ast" is ASAP state initialized by ASAP_PlaySong() with a positive "duration". + "buffer" is buffer of ASAP_WAV_HEADER_BYTES bytes. + "format" is the format of samples. */ +void ASAP_GetWavHeader(const ASAP_State *ast, byte buffer[], + ASAP_SampleFormat format); + +/* Fills the specified buffer with generated samples. + "ast" is ASAP state initialized by ASAP_PlaySong(). + "buffer" is the destination buffer. + "buffer_len" is the length of this buffer in bytes. + "format" is the format of samples. + ASAP_Generate() returns number of bytes actually written + (less than buffer_len if reached the end of the song). + Normally you use a buffer of a few kilobytes or less, + and call ASAP_Generate() in a loop or via a callback. */ +int ASAP_Generate(ASAP_State *ast, void *buffer, int buffer_len, + ASAP_SampleFormat format); + +/* Checks whether information in the specified file can be edited. */ +abool ASAP_CanSetModuleInfo(const char *filename); + +/* Updates the specified module with author, name, date, stereo + and song durations as specified in "module_info". + "module_info" contains the new module information. + "module" is the source file contents. + "module_len" is the source file length. + "out_module" is the destination buffer of size ASAP_MODULE_MAX. + ASAP_SetModuleInfo() returns the resulting file length (number of bytes + written to "out_module") or -1 if illegal characters were found. */ +int ASAP_SetModuleInfo(const ASAP_ModuleInfo *module_info, const byte module[], + int module_len, byte out_module[]); + +/* Checks whether the specified module can be converted to another format. + "filename" determines the source format. + "module_info" contains the information about the source module, + with possibly modified public fields. + "module" is the source file contents. + "module_len" is the source file length. + ASAP_CanConvert() returns the extension of the target format + or NULL if there's no possible conversion. */ +const char *ASAP_CanConvert(const char *filename, const ASAP_ModuleInfo *module_info, + const byte module[], int module_len); + +/* Converts the specified module to the format returned by ASAP_CanConvert(). + "filename" determines the source format. + "module_info" contains the information about the source module, + with possibly modified public fields. + "module" is the source file contents. + "module_len" is the source file length. + "out_module" is the destination buffer of size ASAP_MODULE_MAX. + ASAP_Convert() returns the resulting file length (number of bytes + written to "out_module") or -1 on error. */ +int ASAP_Convert(const char *filename, const ASAP_ModuleInfo *module_info, + const byte module[], int module_len, byte out_module[]); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib/rbcodec/codecs/libasap/asap_internal.h b/lib/rbcodec/codecs/libasap/asap_internal.h new file mode 100644 index 0000000000..def444bc2f --- /dev/null +++ b/lib/rbcodec/codecs/libasap/asap_internal.h @@ -0,0 +1,115 @@ +/* + * asap_internal.h - private interface of ASAP + * + * Copyright (C) 2005-2010 Piotr Fusik + * + * This file is part of ASAP (Another Slight Atari Player), + * see http://asap.sourceforge.net + * + * ASAP is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2 of the License, + * or (at your option) any later version. + * + * ASAP is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ASAP; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _ASAP_INTERNAL_H_ +#define _ASAP_INTERNAL_H_ + +#include "anylang.h" + +#ifndef C + +#define ASAP_SONGS_MAX 32 +#define ASAP_SAMPLE_RATE 44100 + +#endif + +#ifdef JAVA + +#define ASAP_FORMAT_U8 8 +#define ASAP_FORMAT_S16_LE 16 +#define ASAP_FORMAT_S16_BE -16 +#define ASAP_SampleFormat int + +#elif defined(CSHARP) || defined(JAVASCRIPT) + +#define ASAP_FORMAT_U8 ASAP_SampleFormat.U8 +#define ASAP_FORMAT_S16_LE ASAP_SampleFormat.S16LE +#define ASAP_FORMAT_S16_BE ASAP_SampleFormat.S16BE + +#elif defined(ACTIONSCRIPT) + +#define ASAP_SampleFormat int + +#else /* C */ + +#include "asap.h" + +int ASAP_GetByte(ASAP_State *ast, int addr); +void ASAP_PutByte(ASAP_State *ast, int addr, int data); + +void Cpu_RunScanlines(ASAP_State *ast, int scanlines); + +void PokeySound_Initialize(ASAP_State *ast); +void PokeySound_StartFrame(ASAP_State *ast); +void PokeySound_PutByte(ASAP_State *ast, int addr, int data); +int PokeySound_GetRandom(ASAP_State *ast, int addr, int cycle); +void PokeySound_EndFrame(ASAP_State *ast, int cycle_limit); +int PokeySound_Generate(ASAP_State *ast, byte buffer[], int buffer_offset, int blocks, ASAP_SampleFormat format); +abool PokeySound_IsSilent(const PokeyState *pst); +void PokeySound_Mute(const ASAP_State *ast, PokeyState *pst, int mask); + +#ifdef ASAPSCAN +abool call_6502_player(ASAP_State *ast); +extern int cpu_trace; +void trace_cpu(const ASAP_State *ast, int pc, int a, int x, int y, int s, int nz, int vdi, int c); +#endif + +#endif /* C */ + +#define V_FLAG 0x40 +#define D_FLAG 0x08 +#define I_FLAG 0x04 +#define Z_FLAG 0x02 + +#define NEVER 0x800000 + +#define DELTA_SHIFT_POKEY 20 +#define DELTA_SHIFT_GTIA 20 +#define DELTA_SHIFT_COVOX 17 + +/* 6502 player types */ +#define ASAP_TYPE_SAP_B 1 +#define ASAP_TYPE_SAP_C 2 +#define ASAP_TYPE_SAP_D 3 +#define ASAP_TYPE_SAP_S 4 +#define ASAP_TYPE_CMC 5 +#define ASAP_TYPE_CM3 6 +#define ASAP_TYPE_CMR 7 +#define ASAP_TYPE_CMS 8 +#define ASAP_TYPE_DLT 9 +#define ASAP_TYPE_MPT 10 +#define ASAP_TYPE_RMT 11 +#define ASAP_TYPE_TMC 12 +#define ASAP_TYPE_TM2 13 + +#define dGetByte(addr) UBYTE(ast _ memory[addr]) +#define dPutByte(addr, data) ast _ memory[addr] = CAST(byte) (data) +#define dGetWord(addr) (dGetByte(addr) + (dGetByte((addr) + 1) << 8)) +#define GetByte(addr) (((addr) & 0xf900) == 0xd000 ? ASAP_GetByte(ast, addr) : dGetByte(addr)) +#define PutByte(addr, data) do { if (((addr) & 0xf900) == 0xd000) ASAP_PutByte(ast, addr, data); else dPutByte(addr, data); } while (FALSE) +#define RMW_GetByte(dest, addr) do { if (((addr) >> 8) == 0xd2) { dest = ASAP_GetByte(ast, addr); ast _ cycle--; ASAP_PutByte(ast, addr, dest); ast _ cycle++; } else dest = dGetByte(addr); } while (FALSE) + +#define ASAP_MAIN_CLOCK(ast) ((ast) _ module_info->ntsc ? 1789772 : 1773447) +#define CYCLE_TO_SAMPLE(cycle) TO_INT(((cycle) * ASAP_SAMPLE_RATE + ast _ sample_offset) / ASAP_MAIN_CLOCK(ast)) + +#endif /* _ASAP_INTERNAL_H_ */ diff --git a/lib/rbcodec/codecs/libasap/libasap.make b/lib/rbcodec/codecs/libasap/libasap.make new file mode 100644 index 0000000000..cbf461d4fb --- /dev/null +++ b/lib/rbcodec/codecs/libasap/libasap.make @@ -0,0 +1,18 @@ +# __________ __ ___. +# Open \______ \ ____ ____ | | _\_ |__ _______ ___ +# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / +# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < +# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ +# \/ \/ \/ \/ \/ +# $Id$ +# + +# libasap +ASAPLIB := $(CODECDIR)/libasap.a +ASAPLIB_SRC := $(call preprocess, $(RBCODECLIB_DIR)/codecs/libasap/SOURCES) +ASAPLIB_OBJ := $(call c2obj, $(ASAPLIB_SRC)) +OTHER_SRC += $(ASAPLIB_SRC) + +$(ASAPLIB): $(ASAPLIB_OBJ) + $(SILENT)$(shell rm -f $@) + $(call PRINTS,AR $(@F))$(AR) rcs $@ $^ >/dev/null diff --git a/lib/rbcodec/codecs/libasap/players.h b/lib/rbcodec/codecs/libasap/players.h new file mode 100644 index 0000000000..fb90b0c76a --- /dev/null +++ b/lib/rbcodec/codecs/libasap/players.h @@ -0,0 +1,1386 @@ +CONST_ARRAY(byte, cmc_obx) + 255,255,0,5,220,12,76,15,11,76,120,5,76,203,7,0, + 0,0,0,0,0,0,0,0,160,227,237,227,160,240,236,225, + 249,229,242,160,246,160,178,174,177,160,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255, + 255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,128,128,128,128,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,141,110, + 5,142,111,5,140,112,5,41,112,74,74,74,170,189,145,11, + 141,169,5,189,146,11,141,170,5,169,3,141,15,210,216,165, + 254,72,165,255,72,172,112,5,174,111,5,173,110,5,32,178, + 5,104,133,255,104,133,254,96,173,118,5,133,254,173,119,5, + 133,255,160,0,138,240,28,177,254,201,143,240,4,201,239,208, + 12,202,208,9,200,192,84,176,9,152,170,16,6,200,192,84, + 144,229,96,142,104,5,32,123,6,169,0,162,9,157,69,5, + 202,16,250,141,103,5,169,1,141,113,5,169,255,141,106,5, + 173,114,5,133,254,173,115,5,133,255,160,19,177,254,170,173, + 118,5,133,254,173,119,5,133,255,172,104,5,177,254,201,207, + 208,13,152,24,105,85,168,177,254,48,15,170,76,52,6,201, + 143,240,7,201,239,240,3,136,16,226,142,108,5,142,109,5, + 96,41,15,240,245,142,218,10,142,240,10,142,255,10,140,219, + 10,140,241,10,140,0,11,96,142,114,5,134,254,140,115,5, + 132,255,24,138,105,20,141,116,5,152,105,0,141,117,5,142, + 118,5,200,200,140,119,5,160,19,177,254,141,108,5,141,109, + 5,162,8,169,0,141,113,5,157,0,210,224,3,176,8,157, + 9,5,169,255,157,57,5,202,16,233,169,128,162,3,157,75, + 5,202,16,250,96,169,1,141,113,5,169,0,240,238,41,3, + 201,3,240,240,224,64,176,236,192,26,176,232,170,169,128,157, + 75,5,169,0,157,57,5,157,60,5,157,63,5,173,111,5, + 157,12,5,173,112,5,10,10,10,133,254,24,173,114,5,105, + 48,72,173,115,5,105,1,168,104,24,101,254,157,97,5,152, + 105,0,157,100,5,24,173,114,5,105,148,133,254,173,115,5, + 105,0,133,255,173,112,5,10,109,112,5,10,168,177,254,157, + 79,5,200,177,254,157,82,5,41,7,141,110,5,200,177,254, + 157,85,5,200,177,254,157,88,5,200,177,254,157,91,5,200, + 177,254,157,94,5,160,0,173,110,5,201,3,208,2,160,2, + 201,7,208,2,160,4,185,175,11,133,254,185,176,11,133,255, + 189,85,5,74,74,74,74,24,109,111,5,141,111,5,141,194, + 7,168,173,110,5,201,7,208,15,152,10,168,177,254,157,45, + 5,200,140,111,5,76,131,7,177,254,157,45,5,189,85,5, + 41,15,24,109,111,5,141,111,5,172,111,5,173,110,5,201, + 5,8,177,254,40,240,8,221,45,5,208,3,56,233,1,157, + 48,5,189,79,5,72,41,3,168,185,181,11,157,54,5,104, + 74,74,74,74,160,62,201,15,240,16,160,55,201,14,240,10, + 160,48,201,13,240,4,24,105,0,168,185,185,11,157,51,5, + 96,216,165,252,72,165,253,72,165,254,72,165,255,72,173,113, + 5,208,3,76,2,11,173,78,5,240,3,76,107,9,173,108, + 5,205,109,5,240,3,76,88,9,173,103,5,240,3,76,220, + 8,162,2,188,75,5,48,3,157,75,5,157,69,5,202,16, + 242,173,118,5,133,252,173,119,5,133,253,172,104,5,132,254, + 204,106,5,208,25,173,107,5,240,20,173,104,5,172,105,5, + 140,104,5,206,107,5,208,232,141,104,5,168,16,226,162,0, + 177,252,201,254,208,14,172,104,5,200,196,254,240,67,140,104, + 5,76,26,8,157,66,5,24,152,105,85,168,232,224,3,144, + 223,172,104,5,177,252,16,122,201,255,240,118,74,74,74,41, + 14,170,189,161,11,141,126,8,189,162,11,141,127,8,173,67, + 5,133,255,32,147,8,140,104,5,192,85,176,4,196,254,208, + 143,164,254,140,104,5,76,2,11,32,148,6,160,255,96,48, + 251,168,96,48,247,56,152,229,255,168,96,48,239,24,152,101, + 255,168,96,48,231,141,108,5,141,109,5,200,96,48,221,173, + 68,5,48,216,141,107,5,200,140,105,5,24,152,101,255,141, + 106,5,96,136,48,10,177,252,201,143,240,4,201,239,208,243, + 200,96,162,2,189,72,5,240,5,222,72,5,16,99,189,75, + 5,208,94,188,66,5,192,64,176,87,173,116,5,133,252,173, + 117,5,133,253,177,252,133,254,24,152,105,64,168,177,252,133, + 255,37,254,201,255,240,58,188,69,5,177,254,41,192,208,12, + 177,254,41,63,157,15,5,254,69,5,16,235,201,64,208,19, + 177,254,41,63,141,111,5,189,15,5,141,112,5,32,188,6, + 76,72,9,201,128,208,10,177,254,41,63,157,72,5,254,69, + 5,202,16,144,174,103,5,232,138,41,63,141,103,5,206,109, + 5,208,14,173,108,5,141,109,5,173,103,5,208,3,238,104, + 5,172,48,5,173,82,5,41,7,201,5,240,4,201,6,208, + 1,136,140,39,5,160,0,201,5,240,4,201,6,208,2,160, + 2,201,7,208,2,160,40,140,44,5,162,2,189,82,5,41, + 224,157,40,5,189,97,5,133,252,189,100,5,133,253,189,57, + 5,201,255,240,54,201,15,208,32,189,63,5,240,45,222,63, + 5,189,63,5,208,37,188,9,5,240,1,136,152,157,9,5, + 189,88,5,157,63,5,76,229,9,189,57,5,74,168,177,252, + 144,4,74,74,74,74,41,15,157,9,5,188,45,5,189,82, + 5,41,7,201,1,208,31,136,152,200,221,48,5,8,169,1, + 40,208,2,10,10,61,60,5,240,12,188,48,5,192,255,208, + 5,169,0,157,9,5,152,157,36,5,169,1,141,110,5,189, + 57,5,201,15,240,56,41,7,168,185,205,12,133,254,189,57, + 5,41,8,8,138,40,24,240,2,105,3,168,185,91,5,37, + 254,240,27,189,51,5,157,36,5,142,110,5,202,16,8,141, + 39,5,169,0,141,44,5,232,189,54,5,157,40,5,189,57, + 5,41,15,201,15,240,16,254,57,5,189,57,5,201,15,208, + 6,189,88,5,157,63,5,189,75,5,16,10,189,9,5,208, + 5,169,64,157,75,5,254,60,5,160,0,189,82,5,74,74, + 74,74,144,1,136,74,144,1,200,24,152,125,45,5,157,45, + 5,189,48,5,201,255,208,2,160,0,24,152,125,48,5,157, + 48,5,202,48,3,76,150,9,173,40,5,141,43,5,173,82, + 5,41,7,170,160,3,173,110,5,240,3,188,213,12,152,72, + 185,185,12,8,41,127,170,152,41,3,10,168,189,36,5,153, + 0,210,200,189,9,5,224,3,208,3,173,9,5,29,40,5, + 40,16,2,169,0,153,0,210,104,168,136,41,3,208,207,160, + 8,173,44,5,153,0,210,24,104,133,255,104,133,254,104,133, + 253,104,133,252,96,104,170,240,78,201,2,240,6,104,104,202, + 208,251,96,165,20,197,20,240,252,173,36,2,201,134,208,7, + 173,37,2,201,11,240,230,173,36,2,141,143,11,173,37,2, + 141,144,11,169,134,141,36,2,169,11,141,37,2,104,104,240, + 3,56,233,1,141,93,11,104,168,104,170,169,112,32,120,5, + 169,0,162,0,76,120,5,165,20,197,20,240,252,173,36,2, + 201,134,208,174,173,37,2,201,11,208,167,173,143,11,141,36, + 2,173,144,11,141,37,2,169,64,76,120,5,32,203,7,144, + 3,32,117,11,76,255,255,178,5,221,5,168,6,59,6,123, + 6,148,6,159,6,82,6,147,8,153,8,157,8,165,8,173, + 8,183,8,205,8,185,11,250,11,59,12,128,160,32,64,255, + 241,228,215,203,192,181,170,161,152,143,135,127,120,114,107,101, + 95,90,85,80,75,71,67,63,60,56,53,50,47,44,42,39, + 37,35,33,31,29,28,26,24,23,22,20,19,18,17,16,15, + 14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,0, + 0,0,0,0,242,233,218,206,191,182,170,161,152,143,137,128, + 122,113,107,101,95,0,86,80,103,96,90,85,81,76,72,67, + 63,61,57,52,51,57,45,42,40,37,36,33,31,30,0,0, + 15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0, + 0,56,11,140,10,0,10,106,9,232,8,106,8,239,7,128, + 7,8,7,174,6,70,6,230,5,149,5,65,5,246,4,176, + 4,110,4,48,4,246,3,187,3,132,3,82,3,34,3,244, + 2,200,2,160,2,122,2,85,2,52,2,20,2,245,1,216, + 1,189,1,164,1,141,1,119,1,96,1,78,1,56,1,39, + 1,21,1,6,1,247,0,232,0,219,0,207,0,195,0,184, + 0,172,0,162,0,154,0,144,0,136,0,127,0,120,0,112, + 0,106,0,100,0,94,0,87,0,82,0,50,0,10,0,0, + 1,2,131,0,1,2,3,1,0,2,131,1,0,2,3,1, + 2,128,3,128,64,32,16,8,4,2,1,3,3,3,3,7, + 11,15,19 +END_CONST_ARRAY; +CONST_ARRAY(byte, cm3_obx) + 255,255,0,5,223,12,76,18,11,76,120,5,76,203,7,0, + 0,0,0,0,0,0,0,0,160,227,237,227,160,240,236,225, + 249,229,242,160,246,160,178,174,177,160,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255, + 255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,128,128,128,128,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,141,110, + 5,142,111,5,140,112,5,41,112,74,74,74,170,189,148,11, + 141,169,5,189,149,11,141,170,5,169,3,141,15,210,216,165, + 254,72,165,255,72,172,112,5,174,111,5,173,110,5,32,178, + 5,104,133,255,104,133,254,96,173,118,5,133,254,173,119,5, + 133,255,160,0,138,240,28,177,254,201,143,240,4,201,239,208, + 12,202,208,9,200,192,84,176,9,152,170,16,6,200,192,84, + 144,229,96,142,104,5,32,123,6,169,0,162,9,157,69,5, + 202,16,250,141,103,5,169,1,141,113,5,169,255,141,106,5, + 173,114,5,133,254,173,115,5,133,255,160,19,177,254,170,173, + 118,5,133,254,173,119,5,133,255,172,104,5,177,254,201,207, + 208,13,152,24,105,85,168,177,254,48,15,170,76,52,6,201, + 143,240,7,201,239,240,3,136,16,226,142,108,5,142,109,5, + 96,41,15,240,245,142,221,10,142,243,10,142,2,11,140,222, + 10,140,244,10,140,3,11,96,142,114,5,134,254,140,115,5, + 132,255,24,138,105,20,141,116,5,152,105,0,141,117,5,142, + 118,5,200,200,140,119,5,160,19,177,254,141,108,5,141,109, + 5,162,8,169,0,141,113,5,157,0,210,224,3,176,8,157, + 9,5,169,255,157,57,5,202,16,233,169,128,162,3,157,75, + 5,202,16,250,96,169,1,141,113,5,169,0,240,238,41,3, + 201,3,240,240,224,64,176,236,192,26,176,232,170,169,128,157, + 75,5,169,0,157,57,5,157,60,5,157,63,5,173,111,5, + 157,12,5,173,112,5,10,10,10,133,254,24,173,114,5,105, + 48,72,173,115,5,105,1,168,104,24,101,254,157,97,5,152, + 105,0,157,100,5,24,173,114,5,105,148,133,254,173,115,5, + 105,0,133,255,173,112,5,10,109,112,5,10,168,177,254,157, + 79,5,200,177,254,157,82,5,41,7,141,110,5,200,177,254, + 157,85,5,200,177,254,157,88,5,200,177,254,157,91,5,200, + 177,254,157,94,5,160,0,173,110,5,201,3,208,2,160,2, + 201,7,208,2,160,4,185,178,11,133,254,185,179,11,133,255, + 189,85,5,74,74,74,74,24,109,111,5,141,111,5,141,194, + 7,168,173,110,5,201,7,208,15,152,10,168,177,254,157,45, + 5,200,140,111,5,76,131,7,177,254,157,45,5,189,85,5, + 41,15,24,109,111,5,141,111,5,172,111,5,173,110,5,201, + 5,8,177,254,40,240,8,221,45,5,208,3,56,233,1,157, + 48,5,189,79,5,72,41,3,168,185,184,11,157,54,5,104, + 74,74,74,74,160,62,201,15,240,16,160,55,201,14,240,10, + 160,48,201,13,240,4,24,105,0,168,185,188,11,157,51,5, + 96,216,165,252,72,165,253,72,165,254,72,165,255,72,173,113, + 5,208,3,76,5,11,173,78,5,240,3,76,110,9,173,108, + 5,205,109,5,240,3,76,91,9,173,103,5,240,3,76,220, + 8,162,2,188,75,5,48,3,157,75,5,157,69,5,202,16, + 242,173,118,5,133,252,173,119,5,133,253,172,104,5,132,254, + 204,106,5,208,25,173,107,5,240,20,173,104,5,172,105,5, + 140,104,5,206,107,5,208,232,141,104,5,168,16,226,162,0, + 177,252,201,254,208,14,172,104,5,200,196,254,240,67,140,104, + 5,76,26,8,157,66,5,24,152,105,85,168,232,224,3,144, + 223,172,104,5,177,252,16,122,201,255,240,118,74,74,74,41, + 14,170,189,164,11,141,126,8,189,165,11,141,127,8,173,67, + 5,133,255,32,147,8,140,104,5,192,85,176,4,196,254,208, + 143,164,254,140,104,5,76,5,11,32,148,6,160,255,96,48, + 251,168,96,48,247,56,152,229,255,168,96,48,239,24,152,101, + 255,168,96,48,231,141,108,5,141,109,5,200,96,48,221,173, + 68,5,48,216,141,107,5,200,140,105,5,24,152,101,255,141, + 106,5,96,136,48,10,177,252,201,143,240,4,201,239,208,243, + 200,96,162,2,189,72,5,240,5,222,72,5,16,99,189,75, + 5,208,94,188,66,5,192,64,176,87,173,116,5,133,252,173, + 117,5,133,253,177,252,133,254,24,152,105,64,168,177,252,133, + 255,37,254,201,255,240,58,188,69,5,177,254,41,192,208,12, + 177,254,41,63,157,15,5,254,69,5,16,235,201,64,208,19, + 177,254,41,63,141,111,5,189,15,5,141,112,5,32,188,6, + 76,72,9,201,128,208,10,177,254,41,63,157,72,5,254,69, + 5,202,16,144,174,103,5,232,224,48,144,2,162,0,142,103, + 5,206,109,5,208,14,173,108,5,141,109,5,173,103,5,208, + 3,238,104,5,172,48,5,173,82,5,41,7,201,5,240,4, + 201,6,208,1,136,140,39,5,160,0,201,5,240,4,201,6, + 208,2,160,2,201,7,208,2,160,40,140,44,5,162,2,189, + 82,5,41,224,157,40,5,189,97,5,133,252,189,100,5,133, + 253,189,57,5,201,255,240,54,201,15,208,32,189,63,5,240, + 45,222,63,5,189,63,5,208,37,188,9,5,240,1,136,152, + 157,9,5,189,88,5,157,63,5,76,232,9,189,57,5,74, + 168,177,252,144,4,74,74,74,74,41,15,157,9,5,188,45, + 5,189,82,5,41,7,201,1,208,31,136,152,200,221,48,5, + 8,169,1,40,208,2,10,10,61,60,5,240,12,188,48,5, + 192,255,208,5,169,0,157,9,5,152,157,36,5,169,1,141, + 110,5,189,57,5,201,15,240,56,41,7,168,185,208,12,133, + 254,189,57,5,41,8,8,138,40,24,240,2,105,3,168,185, + 91,5,37,254,240,27,189,51,5,157,36,5,142,110,5,202, + 16,8,141,39,5,169,0,141,44,5,232,189,54,5,157,40, + 5,189,57,5,41,15,201,15,240,16,254,57,5,189,57,5, + 201,15,208,6,189,88,5,157,63,5,189,75,5,16,10,189, + 9,5,208,5,169,64,157,75,5,254,60,5,160,0,189,82, + 5,74,74,74,74,144,1,136,74,144,1,200,24,152,125,45, + 5,157,45,5,189,48,5,201,255,208,2,160,0,24,152,125, + 48,5,157,48,5,202,48,3,76,153,9,173,40,5,141,43, + 5,173,82,5,41,7,170,160,3,173,110,5,240,3,188,216, + 12,152,72,185,188,12,8,41,127,170,152,41,3,10,168,189, + 36,5,153,0,210,200,189,9,5,224,3,208,3,173,9,5, + 29,40,5,40,16,2,169,0,153,0,210,104,168,136,41,3, + 208,207,160,8,173,44,5,153,0,210,24,104,133,255,104,133, + 254,104,133,253,104,133,252,96,104,170,240,78,201,2,240,6, + 104,104,202,208,251,96,165,20,197,20,240,252,173,36,2,201, + 137,208,7,173,37,2,201,11,240,230,173,36,2,141,146,11, + 173,37,2,141,147,11,169,137,141,36,2,169,11,141,37,2, + 104,104,240,3,56,233,1,141,96,11,104,168,104,170,169,112, + 32,120,5,169,0,162,0,76,120,5,165,20,197,20,240,252, + 173,36,2,201,137,208,174,173,37,2,201,11,208,167,173,146, + 11,141,36,2,173,147,11,141,37,2,169,64,76,120,5,32, + 203,7,144,3,32,120,11,76,255,255,178,5,221,5,168,6, + 59,6,123,6,148,6,159,6,82,6,147,8,153,8,157,8, + 165,8,173,8,183,8,205,8,188,11,253,11,62,12,128,160, + 32,64,255,241,228,215,203,192,181,170,161,152,143,135,127,120, + 114,107,101,95,90,85,80,75,71,67,63,60,56,53,50,47, + 44,42,39,37,35,33,31,29,28,26,24,23,22,20,19,18, + 17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2, + 1,0,0,0,0,0,0,242,233,218,206,191,182,170,161,152, + 143,137,128,122,113,107,101,95,0,86,80,103,96,90,85,81, + 76,72,67,63,61,57,52,51,57,45,42,40,37,36,33,31, + 30,0,0,15,14,13,12,11,10,9,8,7,6,5,4,3, + 2,1,0,0,56,11,140,10,0,10,106,9,232,8,106,8, + 239,7,128,7,8,7,174,6,70,6,230,5,149,5,65,5, + 246,4,176,4,110,4,48,4,246,3,187,3,132,3,82,3, + 34,3,244,2,200,2,160,2,122,2,85,2,52,2,20,2, + 245,1,216,1,189,1,164,1,141,1,119,1,96,1,78,1, + 56,1,39,1,21,1,6,1,247,0,232,0,219,0,207,0, + 195,0,184,0,172,0,162,0,154,0,144,0,136,0,127,0, + 120,0,112,0,106,0,100,0,94,0,87,0,82,0,50,0, + 10,0,0,1,2,131,0,1,2,3,1,0,2,131,1,0, + 2,3,1,2,128,3,128,64,32,16,8,4,2,1,3,3, + 3,3,7,11,15,19 +END_CONST_ARRAY; +CONST_ARRAY(byte, cms_obx) + 255,255,0,5,186,15,234,234,234,76,21,8,76,92,15,35, + 5,169,5,173,5,184,5,0,0,0,0,0,0,0,0,0, + 0,0,0,128,128,128,128,128,128,0,0,0,0,0,0,255, + 255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,130,0,0,6,6,0, + 128,20,128,128,0,0,0,0,0,0,0,0,0,0,0,15, + 15,0,0,0,0,0,0,0,0,255,0,0,0,0,0,0, + 1,2,131,0,1,2,3,1,0,2,131,1,0,2,3,1, + 2,128,3,128,64,32,16,8,4,2,1,75,8,118,8,133, + 9,19,9,80,9,110,9,124,9,26,9,128,160,32,64,255, + 241,228,215,203,192,181,170,161,152,143,135,127,120,114,107,101, + 95,90,85,80,75,71,67,63,60,56,53,50,47,44,42,39, + 37,35,33,31,29,28,26,24,23,22,20,19,18,17,16,15, + 14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,0, + 0,0,0,0,242,233,218,206,191,182,170,161,152,143,137,128, + 122,113,107,101,95,0,86,80,103,96,90,85,81,76,72,67, + 63,61,57,52,51,57,45,42,40,37,36,33,31,30,0,0, + 15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0, + 0,56,11,140,10,0,10,106,9,232,8,106,8,239,7,128, + 7,8,7,174,6,70,6,230,5,149,5,65,5,246,4,176, + 4,110,4,48,4,246,3,187,3,132,3,82,3,34,3,244, + 2,200,2,160,2,122,2,85,2,52,2,20,2,245,1,216, + 1,189,1,164,1,141,1,119,1,96,1,78,1,56,1,39, + 1,21,1,6,1,247,0,232,0,219,0,207,0,195,0,184, + 0,172,0,162,0,154,0,144,0,136,0,127,0,120,0,112, + 0,106,0,100,0,94,0,87,0,82,0,50,0,10,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,0, + 0,0,0,1,1,1,1,1,1,1,1,2,2,2,2,0, + 0,0,0,1,1,1,1,2,2,2,2,2,3,3,3,0, + 0,1,1,1,2,2,2,2,2,3,3,3,3,4,4,0, + 0,1,1,1,2,2,2,3,3,3,4,4,4,5,5,0, + 0,1,1,2,2,2,3,3,4,4,4,5,5,6,6,0, + 0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,0, + 1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,0, + 1,1,2,2,3,4,4,5,5,6,7,7,8,8,9,0, + 1,1,2,3,3,4,5,5,6,7,7,8,9,9,10,0, + 1,1,2,3,4,4,5,6,7,7,8,9,10,10,11,0, + 1,2,2,3,4,5,6,7,8,9,9,10,11,11,12,0, + 1,2,3,4,5,5,6,7,8,9,10,10,11,12,13,0, + 1,2,3,4,5,6,7,7,8,9,10,11,12,13,14,0, + 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,6, + 12,12,12,18,12,28,12,38,12,50,12,79,12,233,5,42, + 6,107,6,161,11,196,11,185,11,0,0,0,0,0,0,0, + 0,0,0,3,3,3,3,7,11,15,19,141,143,5,142,144, + 5,140,145,5,41,112,74,74,74,170,169,3,141,15,210,189, + 213,5,141,73,8,189,214,5,141,74,8,169,3,141,31,210, + 169,1,141,146,5,172,145,5,174,144,5,173,143,5,76,72, + 8,173,147,5,133,252,173,148,5,133,253,160,0,138,240,28, + 177,252,201,143,240,4,201,239,208,12,202,208,9,200,192,84, + 176,9,152,170,16,6,200,192,84,144,229,96,142,149,5,169, + 0,162,5,157,17,5,157,23,5,157,29,5,202,16,244,141, + 150,5,141,157,5,160,255,140,159,5,173,153,5,133,252,173, + 154,5,133,253,160,19,177,252,170,173,147,5,133,252,173,148, + 5,133,253,172,149,5,152,72,169,15,141,169,5,141,170,5, + 177,252,201,135,208,35,152,72,24,105,85,168,177,252,16,2, + 169,15,41,15,141,169,5,152,24,105,85,168,177,252,16,3, + 173,169,5,41,15,141,170,5,104,76,243,8,177,252,201,143, + 240,7,201,239,240,3,136,16,199,104,168,177,252,201,207,208, + 13,152,24,105,85,168,177,252,48,15,170,76,19,9,201,143, + 240,7,201,239,240,3,136,16,226,142,151,5,142,152,5,96, + 142,153,5,134,252,140,154,5,132,253,24,138,105,20,141,155, + 5,152,105,0,141,156,5,24,138,105,0,141,147,5,152,105, + 2,141,148,5,160,19,177,252,141,151,5,141,152,5,162,3, + 142,31,210,142,15,210,169,0,141,146,5,160,8,169,0,153, + 0,210,153,16,210,192,6,176,8,153,35,5,169,255,153,41, + 5,136,16,233,169,128,162,5,157,29,5,202,16,250,141,157, + 5,96,169,0,240,240,141,157,5,240,11,173,143,5,41,7, + 170,169,128,157,29,5,172,145,5,173,144,5,141,143,5,140, + 145,5,169,0,157,83,5,157,41,5,157,77,5,152,10,10, + 10,133,254,24,173,153,5,105,48,72,173,154,5,105,1,168, + 104,24,101,254,157,101,5,152,105,0,157,71,5,24,173,153, + 5,105,148,133,252,173,154,5,105,0,133,253,173,145,5,10, + 109,145,5,10,168,140,145,5,200,200,200,200,200,177,252,157, + 113,5,136,177,252,157,107,5,136,177,252,157,119,5,136,136, + 177,252,157,59,5,160,0,41,7,201,3,208,2,160,2,201, + 7,208,2,160,4,185,247,7,133,254,185,248,7,133,255,172, + 145,5,200,200,177,252,74,74,74,74,24,109,143,5,141,143, + 5,141,159,10,168,189,59,5,41,7,201,7,208,15,152,10, + 168,177,254,157,125,5,200,140,143,5,76,92,10,177,254,157, + 125,5,172,145,5,200,200,177,252,41,15,24,109,143,5,141, + 143,5,172,143,5,189,59,5,41,7,201,5,8,177,254,40, + 240,8,221,125,5,208,3,56,233,1,157,89,5,172,145,5, + 177,252,72,41,3,168,185,229,5,157,131,5,104,74,74,74, + 74,160,62,201,15,240,16,160,55,201,14,240,10,160,48,201, + 13,240,4,24,105,50,168,185,233,5,157,137,5,96,216,165, + 252,72,165,253,72,165,254,72,165,255,72,173,146,5,208,3, + 76,47,15,173,157,5,240,3,76,225,12,173,152,5,205,151, + 5,176,3,76,206,12,173,150,5,240,3,76,158,11,162,5, + 169,0,188,29,5,48,3,157,29,5,157,17,5,202,16,242, + 173,147,5,133,252,173,148,5,133,253,172,149,5,140,161,5, + 204,159,5,208,25,173,160,5,240,20,173,149,5,172,158,5, + 140,149,5,206,160,5,208,232,141,149,5,168,16,226,162,0, + 177,252,201,254,240,28,157,53,5,230,253,177,252,198,253,201, + 254,240,15,157,56,5,24,152,105,85,168,232,224,3,144,224, + 176,34,172,149,5,200,204,161,5,240,80,140,149,5,76,250, + 10,104,41,14,170,189,253,7,141,135,11,189,254,7,141,136, + 11,76,129,11,172,149,5,177,252,16,57,201,255,240,53,74, + 74,74,72,41,1,240,218,104,41,14,170,189,233,7,141,135, + 11,189,234,7,141,136,11,173,54,5,133,254,32,134,11,140, + 149,5,192,85,176,5,204,161,5,208,179,172,161,5,140,149, + 5,76,47,15,76,94,12,165,254,48,18,41,15,141,169,5, + 173,55,5,16,3,173,169,5,41,15,141,170,5,200,96,165, + 254,48,250,41,1,141,184,5,200,96,173,179,5,48,20,206, + 180,5,208,51,169,50,141,180,5,206,179,5,208,41,206,179, + 5,200,96,165,254,48,214,141,180,5,238,180,5,165,254,48, + 204,141,180,5,238,180,5,173,55,5,141,179,5,16,5,169, + 0,141,179,5,238,179,5,104,104,76,225,12,32,110,9,160, + 255,96,165,254,48,249,168,96,165,254,48,243,56,152,229,254, + 168,96,165,254,48,233,24,152,101,254,168,96,165,254,48,223, + 141,151,5,141,152,5,200,96,165,254,48,211,173,55,5,48, + 206,200,140,158,5,24,152,101,254,141,159,5,173,55,5,141, + 160,5,192,84,96,136,48,10,177,252,201,143,240,4,201,239, + 208,243,200,96,162,5,189,23,5,240,5,222,23,5,16,87, + 189,29,5,208,82,188,53,5,201,64,176,75,173,155,5,133, + 252,173,156,5,133,253,177,252,133,254,24,152,105,64,168,177, + 252,133,255,188,17,5,177,254,41,192,208,12,177,254,41,63, + 157,47,5,254,17,5,16,235,201,64,208,13,177,254,41,63, + 188,47,5,32,150,9,76,190,12,201,128,208,10,177,254,41, + 63,157,23,5,254,17,5,202,16,156,174,150,5,232,138,41, + 63,141,150,5,206,152,5,208,14,173,151,5,141,152,5,173, + 150,5,208,3,238,149,5,172,89,5,173,59,5,41,7,201, + 5,240,4,201,6,208,1,136,140,162,5,160,0,201,5,240, + 4,201,6,208,2,160,2,201,7,208,2,160,40,140,164,5, + 172,92,5,173,62,5,41,7,201,5,240,4,201,6,208,1, + 136,140,163,5,160,0,201,5,240,4,201,6,208,2,160,2, + 201,7,208,2,160,40,140,165,5,162,5,189,59,5,41,224, + 157,65,5,189,101,5,133,252,189,71,5,133,253,189,41,5, + 201,255,240,55,201,15,208,33,189,77,5,240,46,222,77,5, + 189,77,5,208,38,188,35,5,240,1,136,152,157,35,5,189, + 119,5,157,77,5,136,76,133,13,189,41,5,74,168,177,252, + 144,4,74,74,74,74,41,15,157,35,5,188,125,5,189,59, + 5,41,7,201,1,208,31,136,152,200,221,89,5,8,169,1, + 40,208,2,10,10,61,83,5,240,12,188,89,5,192,255,208, + 5,169,0,157,35,5,152,157,95,5,169,1,141,168,5,189, + 41,5,201,15,240,76,41,7,168,185,205,5,133,254,189,41, + 5,41,8,8,138,40,24,240,2,105,6,168,185,107,5,37, + 254,240,47,189,137,5,157,95,5,142,168,5,202,224,2,240, + 15,224,255,208,22,141,162,5,169,0,141,164,5,76,5,14, + 173,140,5,141,163,5,169,0,141,165,5,232,189,131,5,157, + 65,5,189,41,5,41,15,201,15,240,18,254,41,5,189,41, + 5,41,15,201,15,208,6,189,119,5,157,77,5,189,29,5, + 16,10,189,35,5,208,5,169,64,157,29,5,254,83,5,160, + 0,189,59,5,74,74,74,74,144,1,136,74,144,1,200,24, + 152,125,125,5,157,125,5,189,89,5,201,255,208,2,160,0, + 24,152,125,89,5,157,89,5,202,48,3,76,53,13,32,123, + 15,173,65,5,141,166,5,173,68,5,141,167,5,173,59,5, + 41,7,32,181,15,152,72,185,185,5,8,41,127,170,152,41, + 3,10,168,224,3,208,3,76,196,14,189,173,5,208,39,189, + 95,5,153,0,210,189,35,5,29,65,5,40,16,2,169,0, + 153,1,210,104,168,136,41,3,240,3,76,127,14,173,164,5, + 141,8,210,76,228,14,40,76,173,14,173,173,5,208,23,173, + 162,5,153,0,210,173,35,5,13,166,5,40,16,2,169,0, + 153,1,210,76,173,14,40,76,173,14,173,62,5,41,7,32, + 181,15,152,72,185,185,5,8,41,127,170,152,41,3,10,168, + 224,3,208,3,76,60,15,189,176,5,208,30,189,98,5,153, + 16,210,189,38,5,29,68,5,40,16,2,169,0,153,17,210, + 104,168,136,41,3,240,7,76,236,14,40,76,26,15,173,165, + 5,141,24,210,24,104,133,255,104,133,254,104,133,253,104,133, + 252,96,173,176,5,208,23,173,163,5,153,16,210,173,38,5, + 13,167,5,40,16,2,169,0,153,17,210,76,26,15,40,76, + 26,15,32,168,10,176,25,173,184,5,240,20,173,157,5,141, + 183,5,169,1,141,157,5,32,168,10,173,183,5,141,157,5, + 96,173,169,5,10,10,10,10,141,171,5,173,170,5,10,10, + 10,10,141,172,5,162,2,134,200,173,171,5,29,35,5,170, + 189,233,6,166,200,157,35,5,173,172,5,29,38,5,170,189, + 233,6,166,200,157,38,5,202,16,221,96,168,185,13,8,168, + 96 +END_CONST_ARRAY; +CONST_ARRAY(byte, dlt_obx) + 255,255,0,4,70,12,255,241,228,215,203,192,181,170,161,152, + 143,135,127,121,114,107,101,95,90,85,80,75,71,67,63,60, + 56,53,50,47,44,42,39,37,35,33,31,29,28,26,24,23, + 22,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6, + 5,4,255,241,228,215,242,233,218,206,191,182,170,161,152,143, + 137,128,122,113,107,101,95,92,86,80,103,96,90,85,81,76, + 72,67,63,61,57,52,51,48,45,42,40,37,36,33,31,30, + 28,27,25,0,22,21,0,10,9,8,7,6,5,4,3,2, + 1,0,242,233,218,206,242,233,218,206,191,182,170,161,152,143, + 137,128,122,113,107,101,95,92,86,80,103,96,90,85,81,76, + 72,67,63,61,57,52,51,48,45,42,40,37,36,33,31,30, + 28,27,25,0,22,21,0,10,9,8,7,6,5,4,3,2, + 1,0,242,233,218,206,255,241,228,216,202,192,181,171,162,153, + 142,135,127,120,115,108,102,97,90,85,81,75,72,67,63,60, + 57,52,51,48,45,42,40,37,36,33,31,30,28,27,25,23, + 22,21,19,18,17,16,15,14,13,12,11,10,9,8,7,6, + 5,4,3,2,1,255,76,9,5,76,200,5,76,183,5,136, + 140,54,3,169,126,141,53,3,162,6,142,51,3,162,1,142, + 52,3,32,51,5,32,95,5,32,163,5,32,139,5,169,1, + 141,50,3,169,3,141,15,210,96,162,0,160,32,142,48,3, + 140,49,3,160,0,173,48,3,153,0,2,173,49,3,153,64, + 2,173,48,3,24,105,128,141,48,3,144,3,238,49,3,200, + 192,64,208,225,96,162,0,160,68,142,48,3,140,49,3,160, + 0,173,48,3,153,128,2,173,49,3,153,160,2,173,48,3, + 24,105,64,141,48,3,144,3,238,49,3,200,192,32,208,225, + 96,173,0,76,41,1,74,106,106,168,162,0,185,128,4,157, + 64,4,200,232,224,64,208,244,96,160,3,169,0,153,40,3, + 153,32,3,153,36,3,153,44,3,136,16,241,96,169,0,141, + 50,3,160,7,169,0,153,0,210,136,16,250,96,96,173,50, + 3,240,250,173,40,3,13,41,3,13,42,3,13,43,3,141, + 8,210,174,36,3,172,32,3,142,0,210,140,1,210,174,37, + 3,172,33,3,142,2,210,140,3,210,174,38,3,172,34,3, + 142,4,210,140,5,210,174,39,3,172,35,3,142,6,210,140, + 7,210,206,52,3,208,74,173,51,3,141,52,3,238,53,3, + 238,53,3,16,28,238,54,3,169,0,141,53,3,32,199,6, + 173,4,3,13,5,3,13,6,3,13,7,3,208,3,76,183, + 5,173,4,3,240,3,32,97,7,173,5,3,240,3,32,192, + 7,173,6,3,240,3,32,31,8,173,7,3,240,3,32,126, + 8,173,4,3,240,8,173,44,3,240,3,32,221,8,173,5, + 3,240,8,173,45,3,240,3,32,206,9,173,6,3,240,8, + 173,46,3,240,3,32,191,10,173,7,3,240,8,173,47,3, + 240,3,32,131,11,96,192,67,144,14,169,0,141,4,3,141, + 32,3,141,40,3,76,230,6,192,66,208,15,189,128,64,141, + 51,3,141,52,3,238,54,3,76,199,6,192,65,208,9,189, + 128,64,141,54,3,76,199,6,104,104,76,183,5,174,54,3, + 188,0,64,192,64,176,191,189,128,64,141,24,3,185,0,2, + 133,224,185,64,2,133,225,169,1,141,4,3,188,0,65,192, + 64,176,78,189,128,65,141,25,3,185,0,2,133,226,185,64, + 2,133,227,169,1,141,5,3,188,0,66,192,64,176,63,189, + 128,66,141,26,3,185,0,2,133,228,185,64,2,133,229,169, + 1,141,6,3,188,0,67,192,64,176,48,189,128,67,141,27, + 3,185,0,2,133,230,185,64,2,133,231,169,1,141,7,3, + 96,169,0,141,5,3,141,33,3,141,41,3,240,186,169,0, + 141,6,3,141,34,3,141,42,3,240,201,169,0,141,7,3, + 141,35,3,141,43,3,96,172,53,3,177,224,48,11,200,177, + 224,48,1,96,104,104,76,31,6,24,109,24,3,41,127,141, + 8,3,169,15,141,0,3,141,44,3,200,177,224,170,189,160, + 2,133,233,133,241,133,249,189,128,2,133,232,73,16,133,240, + 73,48,133,248,160,49,177,232,141,12,3,160,51,177,232,41, + 127,141,16,3,169,0,141,20,3,141,28,3,160,48,177,232, + 41,213,141,40,3,96,172,53,3,177,226,48,11,200,177,226, + 48,1,96,104,104,76,31,6,24,109,25,3,41,127,141,9, + 3,169,15,141,1,3,141,45,3,200,177,226,170,189,160,2, + 133,235,133,243,133,251,189,128,2,133,234,73,16,133,242,73, + 48,133,250,160,49,177,234,141,13,3,160,51,177,234,41,127, + 141,17,3,169,0,141,21,3,141,29,3,160,48,177,234,41, + 131,141,41,3,96,172,53,3,177,228,48,11,200,177,228,48, + 1,96,104,104,76,31,6,24,109,26,3,41,127,141,10,3, + 169,15,141,2,3,141,46,3,200,177,228,170,189,160,2,133, + 237,133,245,133,253,189,128,2,133,236,73,16,133,244,73,48, + 133,252,160,49,177,236,141,14,3,160,51,177,236,41,127,141, + 18,3,169,0,141,22,3,141,30,3,160,48,177,236,41,169, + 141,42,3,96,172,53,3,177,230,48,11,200,177,230,48,1, + 96,104,104,76,31,6,24,109,27,3,41,127,141,11,3,169, + 15,141,3,3,141,47,3,200,177,230,170,189,160,2,133,239, + 133,247,133,255,189,128,2,133,238,73,16,133,246,73,48,133, + 254,160,49,177,238,141,15,3,160,51,177,238,41,127,141,19, + 3,169,0,141,23,3,141,31,3,160,48,177,238,41,129,141, + 43,3,96,172,0,3,48,70,177,232,141,32,3,177,240,208, + 9,32,108,9,206,0,3,76,79,9,201,1,240,39,201,3, + 208,16,173,8,3,24,113,248,170,173,28,3,141,55,3,76, + 24,9,173,28,3,24,113,248,141,55,3,174,8,3,32,150, + 9,206,0,3,96,177,248,141,36,3,206,0,3,96,32,108, + 9,160,49,177,232,240,30,206,12,3,240,3,76,79,9,173, + 32,3,41,15,240,11,206,32,3,177,232,141,12,3,76,79, + 9,141,44,3,96,173,28,3,24,160,50,113,232,141,28,3, + 206,16,3,208,12,238,20,3,160,51,177,232,41,127,141,16, + 3,96,173,20,3,41,3,24,105,52,168,177,232,170,160,51, + 177,232,48,14,138,109,8,3,170,173,28,3,141,55,3,76, + 150,9,138,109,28,3,141,55,3,174,8,3,189,0,4,24, + 109,55,3,141,36,3,173,40,3,41,4,208,1,96,172,0, + 3,177,240,208,21,138,24,160,0,113,248,170,189,0,4,24, + 109,55,3,24,105,255,141,38,3,96,173,36,3,24,105,255, + 141,38,3,96,172,1,3,48,70,177,234,141,33,3,177,242, + 208,9,32,93,10,206,1,3,76,64,10,201,1,240,39,201, + 3,208,16,173,9,3,24,113,250,170,173,29,3,141,55,3, + 76,9,10,173,29,3,24,113,250,141,55,3,174,9,3,32, + 135,10,206,1,3,96,177,250,141,37,3,206,1,3,96,32, + 93,10,160,49,177,234,240,30,206,13,3,240,3,76,64,10, + 173,33,3,41,15,240,11,206,33,3,177,234,141,13,3,76, + 64,10,141,45,3,96,173,29,3,24,160,50,113,234,141,29, + 3,206,17,3,208,12,238,21,3,160,51,177,234,41,127,141, + 17,3,96,173,21,3,41,3,24,105,52,168,177,234,170,160, + 51,177,234,48,14,138,109,9,3,170,173,29,3,141,55,3, + 76,135,10,138,109,29,3,141,55,3,174,9,3,189,0,4, + 24,109,55,3,141,37,3,173,41,3,41,2,208,1,96,172, + 1,3,177,242,208,21,138,24,160,0,113,250,170,189,0,4, + 24,109,55,3,24,105,255,141,39,3,96,173,37,3,24,105, + 255,141,39,3,96,172,2,3,48,70,177,236,141,34,3,177, + 244,208,9,32,78,11,206,2,3,76,49,11,201,1,240,39, + 201,3,208,16,173,10,3,24,113,252,170,173,30,3,141,55, + 3,76,250,10,173,30,3,24,113,252,141,55,3,174,10,3, + 32,120,11,206,2,3,96,177,252,141,38,3,206,2,3,96, + 32,78,11,160,49,177,236,240,30,206,14,3,240,3,76,49, + 11,173,34,3,41,15,240,11,206,34,3,177,236,141,14,3, + 76,49,11,141,46,3,96,173,30,3,24,160,50,113,236,141, + 30,3,206,18,3,208,12,238,22,3,160,51,177,236,41,127, + 141,18,3,96,173,22,3,41,3,24,105,52,168,177,236,170, + 160,51,177,236,48,14,138,109,10,3,170,173,30,3,141,55, + 3,76,120,11,138,109,30,3,141,55,3,174,10,3,189,0, + 4,24,109,55,3,141,38,3,96,172,3,3,48,70,177,238, + 141,35,3,177,246,208,9,32,18,12,206,3,3,76,245,11, + 201,1,240,39,201,3,208,16,173,11,3,24,113,254,170,173, + 31,3,141,55,3,76,190,11,173,31,3,24,113,254,141,55, + 3,174,11,3,32,60,12,206,3,3,96,177,254,141,39,3, + 206,3,3,96,32,18,12,160,49,177,238,240,30,206,15,3, + 240,3,76,245,11,173,35,3,41,15,240,11,206,35,3,177, + 238,141,15,3,76,245,11,141,47,3,96,173,31,3,24,160, + 50,113,238,141,31,3,206,19,3,208,12,238,23,3,160,51, + 177,238,41,127,141,19,3,96,173,23,3,41,3,24,105,52, + 168,177,238,170,160,51,177,238,48,14,138,109,11,3,170,173, + 31,3,141,55,3,76,60,12,138,109,31,3,141,55,3,174, + 11,3,189,0,4,24,109,55,3,141,39,3,96 +END_CONST_ARRAY; +CONST_ARRAY(byte, mpt_obx) + 255,255,0,5,178,13,76,205,11,173,46,7,208,1,96,169, + 0,141,28,14,238,29,14,173,23,14,205,187,13,144,80,206, + 21,14,240,3,76,197,5,162,0,142,23,14,169,0,157,237, + 13,157,245,13,189,179,13,133,236,189,183,13,133,237,172,22, + 14,177,236,200,201,255,240,7,201,254,208,15,76,42,12,177, + 236,48,249,10,168,140,22,14,76,59,5,157,233,13,177,236, + 157,213,13,232,224,4,208,196,200,140,22,14,76,197,5,206, + 21,14,16,87,173,188,13,141,21,14,162,3,222,245,13,16, + 68,189,233,13,10,168,185,255,255,133,236,200,185,255,255,133, + 237,5,236,240,48,189,237,13,141,31,14,32,62,7,172,31, + 14,200,152,157,237,13,189,241,13,157,245,13,224,2,208,21, + 189,197,13,73,15,10,10,10,10,105,69,141,161,13,169,10, + 105,0,141,162,13,202,16,180,238,23,14,162,1,173,27,14, + 201,2,240,2,162,3,173,27,14,201,2,208,5,236,25,14, + 240,3,76,118,6,181,240,61,114,6,240,18,160,40,177,236, + 24,125,225,13,32,117,9,56,125,1,14,157,203,13,202,16, + 213,169,3,141,15,210,165,241,41,16,240,15,172,226,13,185, + 198,9,141,201,13,185,5,10,141,202,13,173,201,13,141,0, + 210,173,202,13,141,2,210,173,203,13,141,4,210,173,204,13, + 141,6,210,173,193,13,162,255,172,27,14,192,1,208,5,174, + 25,14,240,3,141,1,210,173,194,13,224,1,240,3,141,3, + 210,192,2,240,20,173,195,13,224,2,240,3,141,5,210,173, + 196,13,224,3,240,3,141,7,210,165,240,5,241,5,242,5, + 243,13,28,14,141,8,210,96,4,2,0,0,189,217,13,133, + 236,189,221,13,133,237,5,236,208,8,157,193,13,149,240,76, + 248,5,180,244,192,32,240,66,177,236,56,253,197,13,44,58, + 7,240,2,41,240,157,193,13,200,177,236,141,30,14,200,148, + 244,41,7,240,60,168,185,126,9,141,203,6,185,133,9,141, + 204,6,173,30,14,74,74,74,74,74,9,40,168,177,236,24, + 32,255,255,169,0,149,240,76,248,5,189,9,14,240,18,222, + 13,14,208,13,157,13,14,189,193,13,41,15,240,3,222,193, + 13,160,35,177,236,149,240,189,17,14,24,105,37,168,41,3, + 157,17,14,136,177,236,125,209,13,157,225,13,32,119,9,157, + 201,13,189,5,14,240,6,222,5,14,76,223,5,189,189,13, + 141,30,7,16,254,76,194,8,0,76,229,8,0,76,251,8, + 0,76,21,9,0,76,37,9,0,76,56,9,0,76,66,9, + 16,76,72,9,169,0,157,197,13,172,31,14,136,200,177,236, + 201,254,208,4,140,31,14,96,201,224,144,8,173,187,13,141, + 23,14,208,233,201,208,144,10,41,15,141,188,13,141,21,14, + 16,219,201,192,144,9,41,15,73,15,157,197,13,16,206,201, + 128,144,7,41,63,157,241,13,16,195,201,64,144,27,200,140, + 31,14,41,31,157,229,13,10,168,185,255,255,157,217,13,200, + 185,255,255,157,221,13,76,62,7,140,31,14,141,30,14,24, + 125,213,13,157,209,13,173,27,14,240,66,201,2,240,58,189, + 229,13,201,31,208,55,173,30,14,56,233,1,41,15,168,177, + 254,133,253,152,9,16,168,177,254,133,248,160,1,5,253,208, + 2,160,0,140,26,14,169,0,133,252,157,217,13,157,221,13, + 138,10,141,24,14,142,25,14,96,224,2,176,99,189,217,13, + 133,238,189,221,13,133,239,5,238,240,74,160,32,177,238,41, + 15,157,249,13,177,238,41,112,74,74,157,189,13,200,177,238, + 10,10,72,41,63,157,5,14,104,41,192,157,205,13,200,177, + 238,157,9,14,157,13,14,169,0,149,244,157,17,14,157,253, + 13,157,1,14,189,209,13,157,225,13,32,117,9,157,201,13, + 236,25,14,240,1,96,160,255,140,25,14,200,140,26,14,96, + 224,2,208,51,172,211,13,185,69,11,141,121,13,185,129,11, + 141,127,13,169,0,133,249,133,250,173,231,13,41,15,168,177, + 254,133,251,152,9,16,168,177,254,141,137,13,5,251,208,6, + 141,121,13,141,127,13,96,173,232,13,41,15,168,177,254,133, + 253,152,9,16,168,177,254,5,253,240,15,177,254,56,229,253, + 133,248,169,0,133,252,169,141,208,2,169,173,141,97,13,141, + 56,13,169,24,141,7,210,96,173,29,14,41,7,74,74,144, + 18,208,24,189,249,13,24,157,1,14,125,201,13,157,201,13, + 76,223,5,169,0,157,1,14,76,223,5,189,201,13,56,253, + 249,13,157,201,13,56,169,0,253,249,13,157,1,14,76,223, + 5,189,253,13,24,157,1,14,125,201,13,157,201,13,24,189, + 253,13,125,249,13,157,253,13,76,223,5,189,225,13,56,253, + 253,13,157,225,13,32,117,9,76,5,9,169,0,56,253,253, + 13,157,1,14,189,201,13,56,253,253,13,76,5,9,189,225, + 13,24,125,253,13,76,28,9,32,85,9,76,208,8,32,85, + 9,24,125,225,13,32,155,9,76,223,5,188,253,13,189,249, + 13,48,2,200,200,136,152,157,253,13,221,249,13,208,8,189, + 249,13,73,255,157,249,13,189,253,13,96,41,63,29,205,13, + 168,185,255,255,96,148,145,152,165,173,180,192,9,9,9,9, + 9,9,9,64,0,32,0,125,201,13,157,201,13,96,125,209, + 13,157,225,13,32,117,9,157,201,13,96,157,201,13,189,141, + 9,16,12,157,201,13,169,128,208,5,157,201,13,169,1,13, + 28,14,141,28,14,96,45,10,210,157,201,13,96,242,51,150, + 226,56,140,0,106,232,106,239,128,8,174,70,230,149,65,246, + 176,110,48,246,187,132,82,34,244,200,160,122,85,52,20,245, + 216,189,164,141,119,96,78,56,39,21,6,247,232,219,207,195, + 184,172,162,154,144,136,127,120,112,106,100,94,13,13,12,11, + 11,10,10,9,8,8,7,7,7,6,6,5,5,5,4,4, + 4,4,3,3,3,3,3,2,2,2,2,2,2,2,1,1, + 1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,24,24,24,24,24, + 24,24,24,24,24,24,24,24,24,24,24,22,22,23,23,23, + 23,24,24,24,24,24,25,25,25,25,26,21,21,22,22,22, + 23,23,24,24,24,25,25,26,26,26,27,20,21,21,22,22, + 23,23,24,24,24,25,25,26,26,27,27,20,20,21,21,22, + 22,23,23,24,25,25,26,26,27,27,28,19,20,20,21,22, + 22,23,23,24,25,25,26,26,27,28,28,19,19,20,21,21, + 22,23,23,24,25,25,26,27,27,28,29,18,19,20,20,21, + 22,23,23,24,25,25,26,27,28,28,29,18,19,19,20,21, + 22,22,23,24,25,26,26,27,28,29,29,18,18,19,20,21, + 22,22,23,24,25,26,26,27,28,29,30,17,18,19,20,21, + 22,22,23,24,25,26,26,27,28,29,30,17,18,19,20,21, + 21,22,23,24,25,26,27,27,28,29,30,17,18,19,20,20, + 21,22,23,24,25,26,27,28,28,29,30,17,18,19,19,20, + 21,22,23,24,25,26,27,28,29,29,30,17,18,18,19,20, + 21,22,23,24,25,26,27,28,29,30,30,16,17,18,19,20, + 21,22,23,24,25,26,27,28,29,30,31,32,34,36,38,41, + 43,46,48,51,55,58,61,65,69,73,77,82,87,92,97,103, + 110,116,123,130,138,146,155,164,174,184,195,207,220,233,246,5, + 21,37,55,73,93,113,135,159,184,210,237,11,42,75,110,147, + 186,227,15,62,112,164,219,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1, + 1,1,1,1,1,1,1,2,2,2,2,2,2,2,3,3, + 3,3,3,229,42,64,89,100,238,8,166,11,12,12,12,12, + 12,13,13,142,50,7,140,54,7,41,7,168,185,189,11,141, + 227,11,185,197,11,141,228,11,76,255,255,173,54,7,174,50, + 7,141,148,7,141,155,7,142,149,7,142,156,7,24,105,64, + 141,129,5,141,135,5,144,1,232,142,130,5,142,136,5,24, + 105,128,141,124,9,144,1,232,142,125,9,232,141,31,12,142, + 32,12,162,9,189,255,255,157,179,13,202,16,247,206,188,13, + 169,0,141,46,7,162,98,157,189,13,202,16,250,162,8,157, + 0,210,202,16,250,96,32,42,12,173,50,7,10,141,22,14, + 173,187,13,141,23,14,169,1,141,21,14,141,46,7,96,173, + 54,7,133,254,173,50,7,133,255,96,173,54,7,41,3,170, + 173,50,7,32,198,7,173,26,14,240,238,14,54,7,32,190, + 12,169,1,141,27,14,173,26,14,240,222,201,1,208,5,160, + 0,238,26,14,177,252,174,24,14,74,74,74,74,9,16,141, + 10,212,141,10,212,157,1,210,177,252,9,16,141,10,212,141, + 10,212,157,1,210,200,208,206,230,253,165,253,197,248,208,198, + 140,26,14,96,144,21,169,234,141,153,12,141,154,12,141,155, + 12,141,166,12,141,167,12,141,168,12,96,169,141,141,153,12, + 141,166,12,169,10,141,154,12,141,167,12,169,212,141,155,12, + 141,168,12,96,169,0,141,26,14,173,50,7,74,32,190,12, + 169,1,141,27,14,32,128,12,173,27,14,208,248,96,169,2, + 141,27,14,141,25,14,169,24,141,7,210,169,17,133,250,169, + 13,133,251,169,173,141,97,13,141,56,13,160,0,140,121,13, + 140,127,13,174,11,212,177,252,74,74,74,74,9,16,141,7, + 210,32,117,13,236,11,212,240,251,141,5,210,174,11,212,177, + 252,230,252,208,16,230,253,198,248,208,10,169,173,141,97,13, + 141,56,13,169,8,9,16,141,7,210,32,117,13,236,11,212, + 240,251,141,5,210,173,27,14,208,185,96,24,165,249,105,0, + 133,249,165,250,105,0,133,250,144,15,230,251,165,251,201,0, + 208,7,140,121,13,140,127,13,96,177,250,36,249,48,4,74, + 74,74,74,41,15,168,185,69,10,160,0,96,160,0,140,27, + 14,140,26,14,136,140,25,14,96 +END_CONST_ARRAY; +CONST_ARRAY(byte, rmt4_obx) + 255,255,144,3,96,11,128,0,128,32,128,64,0,192,128,128, + 128,160,0,192,64,192,0,1,5,11,21,0,1,255,255,1, + 1,0,255,255,0,1,1,1,0,255,255,255,255,0,1,1, + 0,0,0,0,0,0,242,51,150,226,56,140,0,106,232,106, + 239,128,8,174,70,230,149,65,246,176,110,48,246,187,132,82, + 34,244,200,160,122,85,52,20,245,216,189,164,141,119,96,78, + 56,39,21,6,247,232,219,207,195,184,172,162,154,144,136,127, + 120,112,106,100,94,0,191,182,170,161,152,143,137,128,242,230, + 218,206,191,182,170,161,152,143,137,128,122,113,107,101,95,92, + 86,80,77,71,68,62,60,56,53,50,47,45,42,40,37,35, + 33,31,29,28,26,24,23,22,20,19,18,17,16,15,14,13, + 12,11,10,9,8,7,255,241,228,216,202,192,181,171,162,153, + 142,135,127,121,115,112,102,97,90,85,82,75,72,67,63,60, + 57,55,51,48,45,42,40,37,36,33,31,30,28,27,25,23, + 22,21,19,18,17,16,15,14,13,12,11,10,9,8,7,6, + 5,4,3,2,1,0,243,230,217,204,193,181,173,162,153,144, + 136,128,121,114,108,102,96,91,85,81,76,72,68,64,60,57, + 53,50,47,45,42,40,37,35,33,31,29,28,26,24,23,22, + 20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5, + 4,3,2,1,0,0,13,13,12,11,11,10,10,9,8,8, + 7,7,7,6,6,5,5,5,4,4,4,4,3,3,3,3, + 3,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1, + 1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1, + 1,1,1,1,1,1,0,0,0,0,1,1,1,1,1,1, + 1,1,2,2,2,2,0,0,0,1,1,1,1,1,2,2, + 2,2,2,3,3,3,0,0,1,1,1,1,2,2,2,2, + 3,3,3,3,4,4,0,0,1,1,1,2,2,2,3,3, + 3,4,4,4,5,5,0,0,1,1,2,2,2,3,3,4, + 4,4,5,5,6,6,0,0,1,1,2,2,3,3,4,4, + 5,5,6,6,7,7,0,1,1,2,2,3,3,4,4,5, + 5,6,6,7,7,8,0,1,1,2,2,3,4,4,5,5, + 6,7,7,8,8,9,0,1,1,2,3,3,4,5,5,6, + 7,7,8,9,9,10,0,1,1,2,3,4,4,5,6,7, + 7,8,9,10,10,11,0,1,2,2,3,4,5,6,6,7, + 8,9,10,10,11,12,0,1,2,3,3,4,5,6,7,8, + 9,10,10,11,12,13,0,1,2,3,4,5,6,7,7,8, + 9,10,11,12,13,14,0,1,2,3,4,5,6,7,8,9, + 10,11,12,13,14,15,76,15,6,76,252,7,76,33,8,76, + 88,6,76,43,11,134,211,132,212,72,160,168,169,0,153,127, + 2,136,208,250,160,4,177,211,141,21,8,200,177,211,141,36, + 3,200,177,211,141,5,8,141,38,3,160,8,177,211,153,195, + 0,200,192,16,208,246,104,72,10,10,24,101,209,133,209,104, + 8,41,192,10,42,42,40,101,210,133,210,32,110,6,169,0, + 141,8,210,160,3,140,15,210,160,8,153,0,210,136,16,250, + 173,5,8,96,162,0,142,39,3,138,168,177,209,201,254,176, + 45,168,177,205,157,128,2,177,207,157,132,2,169,0,157,136, + 2,169,1,157,140,2,169,128,157,180,2,232,224,4,208,217, + 165,209,24,105,4,133,209,144,27,230,210,76,190,6,240,4, + 169,0,240,223,160,2,177,209,170,200,177,209,133,210,134,209, + 162,0,240,181,173,36,3,141,22,7,162,255,232,222,140,2, + 208,69,189,128,2,133,211,189,132,2,133,212,188,136,2,254, + 136,2,177,211,133,217,41,63,201,61,240,17,176,56,157,144, + 2,157,16,3,200,177,211,74,41,126,157,180,2,169,1,157, + 140,2,188,136,2,254,136,2,177,211,74,102,217,74,102,217, + 165,217,41,240,157,148,2,224,3,208,177,169,255,141,36,3, + 141,37,3,76,101,7,201,63,240,27,165,217,41,192,240,9, + 10,42,42,157,140,2,76,17,7,200,177,211,157,140,2,254, + 136,2,76,17,7,165,217,48,12,200,177,211,141,22,7,254, + 136,2,76,214,6,201,255,240,9,200,177,211,157,136,2,76, + 214,6,76,110,6,76,33,8,202,48,250,188,180,2,48,248, + 177,203,157,184,2,133,215,200,177,203,157,188,2,133,216,169, + 1,157,20,3,168,177,215,157,4,3,200,177,215,157,196,2, + 200,177,215,157,200,2,200,177,215,157,240,2,41,63,157,8, + 3,177,215,41,64,157,244,2,200,177,215,157,32,3,200,177, + 215,157,208,2,200,177,215,157,216,2,200,177,215,157,220,2, + 200,177,215,168,185,160,3,157,224,2,157,228,2,185,161,3, + 157,232,2,160,10,177,215,157,236,2,169,128,157,212,2,157, + 180,2,10,157,204,2,157,156,2,168,177,215,157,0,3,105, + 0,157,192,2,169,12,157,252,2,168,177,215,157,248,2,76, + 98,7,32,43,11,206,38,3,208,29,169,255,141,38,3,206, + 37,3,208,19,238,39,3,173,39,3,201,255,240,3,76,190, + 6,76,110,6,76,95,10,169,4,133,214,162,3,189,188,2, + 240,242,133,212,189,184,2,133,211,188,192,2,177,211,133,217, + 200,177,211,133,218,200,177,211,133,219,200,152,221,196,2,144, + 10,240,8,169,128,157,204,2,189,200,2,157,192,2,165,217, + 41,15,29,148,2,168,185,0,5,133,220,165,218,41,14,168, + 185,144,3,133,213,165,220,25,145,3,157,28,3,189,220,2, + 240,40,201,1,208,33,189,156,2,24,125,236,2,24,188,224, + 2,121,165,3,157,156,2,200,152,221,232,2,208,3,189,228, + 2,157,224,2,76,164,8,222,220,2,188,0,3,192,13,144, + 60,189,8,3,16,49,152,221,252,2,208,8,189,4,3,157, + 252,2,208,3,254,252,2,189,184,2,133,215,189,188,2,133, + 216,188,252,2,177,215,188,244,2,240,4,24,125,248,2,157, + 248,2,189,240,2,41,63,56,233,1,157,8,3,189,204,2, + 16,31,189,148,2,240,26,221,216,2,240,21,144,19,168,189, + 212,2,24,125,208,2,157,212,2,144,6,152,233,16,157,148, + 2,169,0,133,221,165,218,157,12,3,41,112,74,74,141,28, + 9,144,254,76,210,9,234,76,60,9,234,76,65,9,234,76, + 75,9,234,76,87,9,234,76,102,9,234,76,169,9,234,76, + 184,9,165,219,76,21,10,165,219,133,221,189,144,2,76,216, + 9,189,144,2,24,101,219,157,144,2,76,216,9,189,156,2, + 24,101,219,157,156,2,189,144,2,76,216,9,189,240,2,16, + 12,188,144,2,177,213,24,125,248,2,76,135,9,189,144,2, + 24,125,248,2,201,61,144,2,169,63,168,177,213,157,160,2, + 164,219,208,3,157,164,2,152,74,74,74,74,157,168,2,157, + 172,2,165,219,41,15,157,176,2,189,144,2,76,216,9,165, + 219,24,125,20,3,157,20,3,189,144,2,76,216,9,165,219, + 201,128,240,6,157,144,2,76,216,9,189,28,3,9,240,157, + 28,3,189,144,2,76,216,9,189,144,2,24,101,219,188,240, + 2,48,31,24,125,248,2,201,61,144,7,169,0,157,28,3, + 169,63,157,16,3,168,177,213,24,125,156,2,24,101,221,76, + 21,10,201,61,144,7,169,0,157,28,3,169,63,168,189,156, + 2,24,125,248,2,24,113,213,24,101,221,157,24,3,189,172, + 2,240,50,222,172,2,208,45,189,168,2,157,172,2,189,164, + 2,221,160,2,240,31,176,13,125,176,2,176,18,221,160,2, + 176,13,76,76,10,253,176,2,144,5,221,160,2,176,3,189, + 160,2,157,164,2,165,218,41,1,240,10,189,164,2,24,125, + 156,2,157,24,3,202,48,3,76,39,8,173,32,3,13,33, + 3,13,34,3,13,35,3,170,142,44,11,173,12,3,16,33, + 173,28,3,41,15,240,26,173,24,3,24,109,20,3,141,26, + 3,173,30,3,41,16,208,5,169,0,141,30,3,138,9,4, + 170,173,13,3,16,33,173,29,3,41,15,240,26,173,25,3, + 24,109,21,3,141,27,3,173,31,3,41,16,208,5,169,0, + 141,31,3,138,9,2,170,236,44,11,208,94,173,13,3,41, + 14,201,6,208,38,173,29,3,41,15,240,31,172,17,3,185, + 192,3,141,24,3,185,192,4,141,25,3,173,28,3,41,16, + 208,5,169,0,141,28,3,138,9,80,170,173,15,3,41,14, + 201,6,208,38,173,31,3,41,15,240,31,172,19,3,185,192, + 3,141,26,3,185,192,4,141,27,3,173,30,3,41,16,208, + 5,169,0,141,30,3,138,9,40,170,142,44,11,173,38,3, + 96,160,255,173,24,3,174,28,3,141,0,210,142,1,210,173, + 25,3,174,29,3,141,2,210,142,3,210,173,26,3,174,30, + 3,141,4,210,142,5,210,173,27,3,174,31,3,141,6,210, + 142,7,210,140,8,210,96 +END_CONST_ARRAY; +CONST_ARRAY(byte, rmt8_obx) + 255,255,144,3,108,12,128,0,128,32,128,64,0,192,128,128, + 128,160,0,192,64,192,0,1,5,11,21,0,1,255,255,1, + 1,0,255,255,0,1,1,1,0,255,255,255,255,0,1,1, + 0,0,0,0,0,0,242,51,150,226,56,140,0,106,232,106, + 239,128,8,174,70,230,149,65,246,176,110,48,246,187,132,82, + 34,244,200,160,122,85,52,20,245,216,189,164,141,119,96,78, + 56,39,21,6,247,232,219,207,195,184,172,162,154,144,136,127, + 120,112,106,100,94,0,191,182,170,161,152,143,137,128,242,230, + 218,206,191,182,170,161,152,143,137,128,122,113,107,101,95,92, + 86,80,77,71,68,62,60,56,53,50,47,45,42,40,37,35, + 33,31,29,28,26,24,23,22,20,19,18,17,16,15,14,13, + 12,11,10,9,8,7,255,241,228,216,202,192,181,171,162,153, + 142,135,127,121,115,112,102,97,90,85,82,75,72,67,63,60, + 57,55,51,48,45,42,40,37,36,33,31,30,28,27,25,23, + 22,21,19,18,17,16,15,14,13,12,11,10,9,8,7,6, + 5,4,3,2,1,0,243,230,217,204,193,181,173,162,153,144, + 136,128,121,114,108,102,96,91,85,81,76,72,68,64,60,57, + 53,50,47,45,42,40,37,35,33,31,29,28,26,24,23,22, + 20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5, + 4,3,2,1,0,0,13,13,12,11,11,10,10,9,8,8, + 7,7,7,6,6,5,5,5,4,4,4,4,3,3,3,3, + 3,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1, + 1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1, + 1,1,1,1,1,1,0,0,0,0,1,1,1,1,1,1, + 1,1,2,2,2,2,0,0,0,1,1,1,1,1,2,2, + 2,2,2,3,3,3,0,0,1,1,1,1,2,2,2,2, + 3,3,3,3,4,4,0,0,1,1,1,2,2,2,3,3, + 3,4,4,4,5,5,0,0,1,1,2,2,2,3,3,4, + 4,4,5,5,6,6,0,0,1,1,2,2,3,3,4,4, + 5,5,6,6,7,7,0,1,1,2,2,3,3,4,4,5, + 5,6,6,7,7,8,0,1,1,2,2,3,4,4,5,5, + 6,7,7,8,8,9,0,1,1,2,3,3,4,5,5,6, + 7,7,8,9,9,10,0,1,1,2,3,4,4,5,6,7, + 7,8,9,10,10,11,0,1,2,2,3,4,5,6,6,7, + 8,9,10,10,11,12,0,1,2,3,3,4,5,6,7,8, + 9,10,10,11,12,13,0,1,2,3,4,5,6,7,7,8, + 9,10,11,12,13,14,0,1,2,3,4,5,6,7,8,9, + 10,11,12,13,14,15,76,15,6,76,9,8,76,46,8,76, + 92,6,76,2,12,134,211,132,212,72,160,0,152,153,0,2, + 153,76,2,200,208,247,160,4,177,211,141,34,8,200,177,211, + 141,72,3,200,177,211,141,18,8,141,74,3,160,8,177,211, + 153,195,0,200,192,16,208,246,104,72,10,10,10,24,101,209, + 133,209,104,8,41,224,10,42,42,42,40,101,210,133,210,32, + 123,6,169,0,141,8,210,141,24,210,160,3,140,15,210,140, + 31,210,160,8,153,0,210,153,16,210,136,16,247,173,18,8, + 96,162,0,142,75,3,138,168,177,209,201,254,176,45,168,177, + 205,157,0,2,177,207,157,8,2,169,0,157,16,2,169,1, + 157,24,2,169,128,157,104,2,232,224,8,208,217,165,209,24, + 105,8,133,209,144,27,230,210,76,203,6,240,4,169,0,240, + 223,160,2,177,209,170,200,177,209,133,210,134,209,162,0,240, + 181,173,72,3,141,35,7,162,255,232,222,24,2,208,69,189, + 0,2,133,211,189,8,2,133,212,188,16,2,254,16,2,177, + 211,133,217,41,63,201,61,240,17,176,56,157,32,2,157,32, + 3,200,177,211,74,41,126,157,104,2,169,1,157,24,2,188, + 16,2,254,16,2,177,211,74,102,217,74,102,217,165,217,41, + 240,157,40,2,224,7,208,177,169,255,141,72,3,141,73,3, + 76,114,7,201,63,240,27,165,217,41,192,240,9,10,42,42, + 157,24,2,76,30,7,200,177,211,157,24,2,254,16,2,76, + 30,7,165,217,48,12,200,177,211,141,35,7,254,16,2,76, + 227,6,201,255,240,9,200,177,211,157,16,2,76,227,6,76, + 123,6,76,46,8,202,48,250,188,104,2,48,248,177,203,157, + 112,2,133,215,200,177,203,157,120,2,133,216,169,1,157,40, + 3,168,177,215,157,8,3,200,177,215,157,136,2,200,177,215, + 157,144,2,200,177,215,157,224,2,41,63,157,16,3,177,215, + 41,64,157,232,2,200,177,215,157,64,3,200,177,215,157,160, + 2,200,177,215,157,176,2,200,177,215,157,184,2,200,177,215, + 168,185,160,3,157,192,2,157,200,2,185,161,3,157,208,2, + 160,10,177,215,157,216,2,169,128,157,168,2,157,104,2,10, + 157,152,2,157,56,2,168,177,215,157,0,3,105,0,157,128, + 2,169,12,157,248,2,168,177,215,157,240,2,76,111,7,32, + 2,12,206,74,3,208,29,169,255,141,74,3,206,73,3,208, + 19,238,75,3,173,75,3,201,255,240,3,76,203,6,76,123, + 6,76,116,10,169,4,133,214,162,7,189,120,2,240,242,133, + 212,189,112,2,133,211,188,128,2,177,211,133,217,200,177,211, + 133,218,200,177,211,133,219,200,152,221,136,2,144,10,240,8, + 169,128,157,152,2,189,144,2,157,128,2,165,217,224,4,144, + 4,74,74,74,74,41,15,29,40,2,168,185,0,5,133,220, + 165,218,41,14,168,185,144,3,133,213,165,220,25,145,3,157, + 56,3,189,184,2,240,40,201,1,208,33,189,56,2,24,125, + 216,2,24,188,192,2,121,165,3,157,56,2,200,152,221,208, + 2,208,3,189,200,2,157,192,2,76,185,8,222,184,2,188, + 0,3,192,13,144,60,189,16,3,16,49,152,221,248,2,208, + 8,189,8,3,157,248,2,208,3,254,248,2,189,112,2,133, + 215,189,120,2,133,216,188,248,2,177,215,188,232,2,240,4, + 24,125,240,2,157,240,2,189,224,2,41,63,56,233,1,157, + 16,3,189,152,2,16,31,189,40,2,240,26,221,176,2,240, + 21,144,19,168,189,168,2,24,125,160,2,157,168,2,144,6, + 152,233,16,157,40,2,169,0,133,221,165,218,157,24,3,41, + 112,74,74,141,49,9,144,254,76,231,9,234,76,81,9,234, + 76,86,9,234,76,96,9,234,76,108,9,234,76,123,9,234, + 76,190,9,234,76,205,9,165,219,76,42,10,165,219,133,221, + 189,32,2,76,237,9,189,32,2,24,101,219,157,32,2,76, + 237,9,189,56,2,24,101,219,157,56,2,189,32,2,76,237, + 9,189,224,2,16,12,188,32,2,177,213,24,125,240,2,76, + 156,9,189,32,2,24,125,240,2,201,61,144,2,169,63,168, + 177,213,157,64,2,164,219,208,3,157,72,2,152,74,74,74, + 74,157,80,2,157,88,2,165,219,41,15,157,96,2,189,32, + 2,76,237,9,165,219,24,125,40,3,157,40,3,189,32,2, + 76,237,9,165,219,201,128,240,6,157,32,2,76,237,9,189, + 56,3,9,240,157,56,3,189,32,2,76,237,9,189,32,2, + 24,101,219,188,224,2,48,31,24,125,240,2,201,61,144,7, + 169,0,157,56,3,169,63,157,32,3,168,177,213,24,125,56, + 2,24,101,221,76,42,10,201,61,144,7,169,0,157,56,3, + 169,63,168,189,56,2,24,125,240,2,24,113,213,24,101,221, + 157,48,3,189,88,2,240,50,222,88,2,208,45,189,80,2, + 157,88,2,189,72,2,221,64,2,240,31,176,13,125,96,2, + 176,18,221,64,2,176,13,76,97,10,253,96,2,144,5,221, + 64,2,176,3,189,64,2,157,72,2,165,218,41,1,240,10, + 189,72,2,24,125,56,2,157,48,3,202,48,3,76,52,8, + 173,64,3,13,65,3,13,66,3,13,67,3,170,142,101,12, + 173,24,3,16,33,173,56,3,41,15,240,26,173,48,3,24, + 109,40,3,141,50,3,173,58,3,41,16,208,5,169,0,141, + 58,3,138,9,4,170,173,25,3,16,33,173,57,3,41,15, + 240,26,173,49,3,24,109,41,3,141,51,3,173,59,3,41, + 16,208,5,169,0,141,59,3,138,9,2,170,236,101,12,208, + 94,173,25,3,41,14,201,6,208,38,173,57,3,41,15,240, + 31,172,33,3,185,192,3,141,48,3,185,192,4,141,49,3, + 173,56,3,41,16,208,5,169,0,141,56,3,138,9,80,170, + 173,27,3,41,14,201,6,208,38,173,59,3,41,15,240,31, + 172,35,3,185,192,3,141,50,3,185,192,4,141,51,3,173, + 58,3,41,16,208,5,169,0,141,58,3,138,9,40,170,142, + 101,12,173,68,3,13,69,3,13,70,3,13,71,3,170,142, + 3,12,173,28,3,16,33,173,60,3,41,15,240,26,173,52, + 3,24,109,44,3,141,54,3,173,62,3,41,16,208,5,169, + 0,141,62,3,138,9,4,170,173,29,3,16,33,173,61,3, + 41,15,240,26,173,53,3,24,109,45,3,141,55,3,173,63, + 3,41,16,208,5,169,0,141,63,3,138,9,2,170,236,3, + 12,208,94,173,29,3,41,14,201,6,208,38,173,61,3,41, + 15,240,31,172,37,3,185,192,3,141,52,3,185,192,4,141, + 53,3,173,60,3,41,16,208,5,169,0,141,60,3,138,9, + 80,170,173,31,3,41,14,201,6,208,38,173,63,3,41,15, + 240,31,172,39,3,185,192,3,141,54,3,185,192,4,141,55, + 3,173,62,3,41,16,208,5,169,0,141,62,3,138,9,40, + 170,142,3,12,173,74,3,96,160,255,173,52,3,174,48,3, + 141,16,210,142,0,210,173,60,3,174,56,3,141,17,210,142, + 1,210,173,53,3,174,49,3,141,18,210,142,2,210,173,61, + 3,174,57,3,141,19,210,142,3,210,173,54,3,174,50,3, + 141,20,210,142,4,210,173,62,3,174,58,3,141,21,210,142, + 5,210,173,55,3,174,51,3,141,22,210,142,6,210,173,63, + 3,174,59,3,141,23,210,142,7,210,169,255,140,24,210,141, + 8,210,96 +END_CONST_ARRAY; +CONST_ARRAY(byte, tmc_obx) + 255,255,0,5,104,15,76,206,13,76,208,8,76,239,9,15, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1, + 1,1,0,0,0,0,1,1,1,1,1,1,1,1,2,2, + 2,2,0,0,0,1,1,1,1,1,2,2,2,2,2,3, + 3,3,0,0,1,1,1,1,2,2,2,2,3,3,3,3, + 4,4,0,0,1,1,1,2,2,2,3,3,3,4,4,4, + 5,5,0,0,1,1,2,2,2,3,3,4,4,4,5,5, + 6,6,0,0,1,1,2,2,3,3,4,4,5,5,6,6, + 7,7,0,1,1,2,2,3,3,4,4,5,5,6,6,7, + 7,8,0,1,1,2,2,3,4,4,5,5,6,7,7,8, + 8,9,0,1,1,2,3,3,4,5,5,6,7,7,8,9, + 9,10,0,1,1,2,3,4,4,5,6,7,7,8,9,10, + 10,11,0,1,2,2,3,4,5,6,6,7,8,9,10,10, + 11,12,0,1,2,3,3,4,5,6,7,8,9,10,10,11, + 12,13,0,1,2,3,4,5,6,7,7,8,9,10,11,12, + 13,14,0,1,2,3,4,5,6,7,8,9,10,11,12,13, + 14,15,0,241,228,215,203,192,181,170,161,152,143,135,127,120, + 114,107,101,95,90,85,80,75,71,67,63,60,56,53,50,47, + 44,42,39,37,35,33,31,29,28,26,24,23,22,20,19,18, + 17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2, + 1,0,0,242,230,218,206,191,182,170,161,152,143,137,128,122, + 113,107,101,95,92,86,80,77,71,68,62,60,56,53,50,47, + 45,42,40,37,35,33,31,29,28,26,24,23,22,20,19,18, + 17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2, + 1,0,0,255,241,228,216,202,192,181,171,162,153,142,135,127, + 121,115,112,102,97,90,85,82,75,72,67,63,60,57,55,51, + 48,45,42,40,37,36,33,31,30,28,27,25,23,22,21,19, + 18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3, + 2,1,0,243,230,217,204,193,181,173,162,153,144,136,128,121, + 114,108,102,96,91,85,81,76,72,68,64,60,57,53,50,47, + 45,42,40,37,35,33,31,29,28,26,24,23,22,20,19,18, + 17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2, + 1,0,0,242,51,150,226,56,140,0,106,232,106,239,128,8, + 174,70,230,149,65,246,176,110,48,246,187,132,82,34,244,200, + 160,122,85,52,20,245,216,189,164,141,119,96,78,56,39,21, + 6,247,232,219,207,195,184,172,162,154,144,136,127,120,112,106, + 100,94,0,13,13,12,11,11,10,10,9,8,8,7,7,7, + 6,6,5,5,5,4,4,4,4,3,3,3,3,3,2,2, + 2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1, + 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,5, + 6,7,0,1,2,3,4,2,0,0,4,2,0,0,0,16, + 0,8,0,16,0,8,173,183,8,240,94,173,182,8,201,64, + 144,90,206,181,8,240,3,76,239,9,162,7,169,0,157,196, + 7,157,204,7,202,16,247,141,182,8,170,160,15,177,254,16, + 32,136,177,254,16,3,76,95,14,134,252,10,10,38,252,10, + 38,252,10,38,252,105,0,133,254,165,252,105,0,133,255,144, + 218,157,212,7,136,177,254,157,220,7,232,136,16,207,24,165, + 254,105,16,133,254,144,2,230,255,76,239,9,206,181,8,16, + 248,238,182,8,173,180,8,141,181,8,162,7,222,204,7,48, + 3,76,233,9,188,212,7,185,255,255,133,252,185,255,255,133, + 253,188,196,7,177,252,208,6,32,109,13,76,230,9,201,64, + 176,18,125,220,7,157,228,7,32,109,13,188,42,5,32,188, + 14,76,230,9,208,34,200,254,196,7,177,252,16,7,133,251, + 32,109,13,165,251,41,127,208,7,169,64,141,182,8,208,76, + 141,180,8,141,181,8,208,68,201,128,176,43,41,63,125,220, + 7,157,228,7,200,254,196,7,177,252,41,127,208,7,169,64, + 141,182,8,208,6,141,180,8,141,181,8,32,109,13,188,42, + 5,32,188,14,76,230,9,201,192,176,12,41,63,157,42,5, + 200,254,196,7,76,94,9,41,63,157,204,7,254,196,7,202, + 48,3,76,70,9,162,7,189,188,7,240,33,32,46,11,189, + 50,5,61,192,8,240,22,160,71,177,252,24,125,34,5,157, + 36,5,168,185,60,6,56,125,100,8,157,246,7,202,16,215, + 14,9,5,14,9,5,14,9,5,14,9,5,232,134,252,134, + 253,162,7,138,168,185,252,7,208,12,188,184,8,185,4,8, + 208,4,138,168,169,0,133,250,152,157,26,5,185,244,7,157, + 18,5,185,50,5,133,251,5,253,133,253,165,251,61,192,8, + 240,6,185,246,7,157,20,5,165,251,61,200,8,240,18,185, + 34,5,41,63,168,200,132,252,185,123,7,157,18,5,76,137, + 10,164,252,240,10,185,59,7,157,18,5,169,0,133,252,165, + 250,13,9,5,168,185,60,5,188,26,5,25,236,7,157,10, + 5,224,4,208,9,165,253,141,59,5,169,0,133,253,202,16, + 130,78,9,5,78,9,5,78,9,5,78,9,5,165,253,162, + 3,142,31,210,142,15,210,174,22,5,172,18,5,142,16,210, + 140,0,210,174,14,5,172,10,5,142,17,210,140,1,210,174, + 23,5,172,19,5,142,18,210,140,2,210,174,15,5,172,11, + 5,142,19,210,140,3,210,174,24,5,172,20,5,142,20,210, + 140,4,210,174,16,5,172,12,5,142,21,210,140,5,210,174, + 25,5,172,21,5,142,22,210,140,6,210,174,17,5,172,13, + 5,142,23,210,140,7,210,141,58,5,174,59,5,142,24,210, + 141,8,210,96,189,28,8,133,252,189,36,8,133,253,188,44, + 8,192,63,240,123,254,44,8,254,44,8,254,44,8,177,252, + 41,240,157,236,7,177,252,41,15,56,253,12,8,16,2,169, + 0,157,252,7,200,177,252,41,15,56,253,20,8,16,2,169, + 0,157,4,8,177,252,41,240,240,116,16,11,160,73,177,252, + 188,44,8,136,136,16,2,169,0,157,50,5,177,252,41,112, + 240,99,74,74,141,154,11,169,0,157,100,8,200,177,252,144, + 254,234,234,234,234,76,56,13,234,76,53,13,234,76,60,13, + 234,76,74,13,234,76,84,13,234,76,95,13,234,76,81,13, + 189,52,8,240,18,222,68,8,208,13,157,68,8,189,252,7, + 41,15,240,3,222,252,7,189,60,8,240,18,222,76,8,208, + 13,157,76,8,189,4,8,41,15,240,3,222,4,8,160,72, + 177,252,157,50,5,189,148,8,24,105,63,168,177,252,125,228, + 7,157,34,5,168,185,60,6,157,244,7,222,164,8,16,51, + 189,156,8,157,164,8,189,172,8,240,24,24,125,148,8,157, + 148,8,240,7,221,140,8,208,26,169,254,24,105,1,157,172, + 8,208,16,254,148,8,189,140,8,221,148,8,176,5,169,0, + 157,148,8,189,116,8,240,4,222,116,8,96,189,108,8,133, + 250,189,92,8,133,251,32,105,12,222,132,8,16,16,165,250, + 157,108,8,165,251,157,92,8,189,124,8,157,132,8,96,189, + 84,8,141,112,12,16,254,76,167,12,234,76,144,12,234,76, + 174,12,234,76,180,12,234,76,190,12,234,76,210,12,234,76, + 226,12,234,76,244,12,165,250,230,250,41,3,74,144,15,208, + 71,165,251,157,100,8,24,125,244,7,157,244,7,96,169,0, + 157,100,8,96,32,29,13,76,157,12,32,29,13,24,125,34, + 5,76,84,13,165,250,157,100,8,24,125,244,7,157,244,7, + 165,250,24,101,251,133,250,96,189,34,5,56,229,250,157,34, + 5,168,185,60,6,76,199,12,189,244,7,56,229,251,157,244, + 7,56,169,0,229,251,157,100,8,96,189,132,8,208,174,165, + 251,16,16,189,4,8,240,165,189,252,7,201,15,240,158,254, + 252,7,96,189,252,7,240,149,189,4,8,201,15,240,142,254, + 4,8,96,164,250,165,251,48,2,200,200,136,152,133,250,197, + 251,208,6,165,251,73,255,133,251,152,96,125,244,7,157,244, + 7,96,188,228,7,121,60,6,157,244,7,152,157,34,5,96, + 45,10,210,157,244,7,96,125,228,7,157,34,5,168,185,60, + 6,157,244,7,96,157,34,5,168,189,244,7,121,60,6,157, + 244,7,96,200,254,196,7,177,252,74,74,74,74,157,12,8, + 177,252,41,15,157,20,8,96,32,95,14,160,15,169,0,133, + 254,169,0,133,255,138,240,46,177,254,16,1,202,24,165,254, + 105,16,133,254,144,239,230,255,176,235,32,95,14,169,0,133, + 252,138,10,10,38,252,10,38,252,10,38,252,105,0,133,254, + 165,252,105,0,133,255,169,64,141,182,8,169,1,141,181,8, + 141,183,8,96,201,16,144,176,201,32,144,206,201,48,176,3, + 76,174,14,201,64,176,9,138,41,15,240,3,141,180,8,96, + 201,80,144,113,201,96,176,6,169,0,141,183,8,96,201,112, + 144,248,169,1,141,181,8,169,64,141,182,8,132,252,134,253, + 160,30,177,252,141,180,8,165,252,24,105,32,141,194,14,144, + 1,232,142,195,14,24,105,64,141,202,14,144,1,232,142,203, + 14,24,105,64,141,82,9,144,1,232,142,83,9,24,105,128, + 141,87,9,144,1,232,142,88,9,24,105,128,133,254,141,16, + 9,141,136,13,141,183,13,144,1,232,134,255,142,22,9,142, + 140,13,142,189,13,160,7,169,0,141,183,8,153,0,210,153, + 16,210,153,10,5,153,252,7,153,4,8,153,50,5,153,188, + 7,136,16,232,141,8,210,141,24,210,141,58,5,141,59,5, + 96,157,252,7,157,4,8,157,50,5,189,228,7,157,34,5, + 96,152,73,240,74,74,74,74,157,12,8,152,41,15,73,15, + 157,20,8,96,41,7,133,252,138,166,252,41,63,240,226,157, + 228,7,169,0,157,188,7,185,255,255,157,28,8,133,252,185, + 255,255,157,36,8,133,253,5,252,240,182,160,74,177,252,157, + 52,8,157,68,8,200,177,252,157,60,8,157,76,8,200,177, + 252,41,112,74,74,157,84,8,177,252,41,15,157,92,8,177, + 252,16,11,189,92,8,73,255,24,105,1,157,92,8,200,177, + 252,157,116,8,200,177,252,41,63,157,124,8,157,132,8,200, + 177,252,41,128,240,2,169,1,157,172,8,177,252,41,112,74, + 74,74,74,157,140,8,208,3,157,172,8,177,252,41,15,157, + 156,8,157,164,8,136,177,252,41,192,24,125,228,7,157,228, + 7,157,34,5,168,185,60,6,157,244,7,169,0,157,44,8, + 157,100,8,157,108,8,157,148,8,169,1,157,188,7,96 +END_CONST_ARRAY; +CONST_ARRAY(byte, tm2_obx) + 255,255,0,2,107,16,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1, + 1,1,1,1,1,1,0,0,0,0,1,1,1,1,1,1, + 1,1,2,2,2,2,0,0,0,1,1,1,1,1,2,2, + 2,2,2,3,3,3,0,0,1,1,1,1,2,2,2,2, + 3,3,3,3,4,4,0,0,1,1,1,2,2,2,3,3, + 3,4,4,4,5,5,0,0,1,1,2,2,2,3,3,4, + 4,4,5,5,6,6,0,0,1,1,2,2,3,3,4,4, + 5,5,6,6,7,7,0,1,1,2,2,3,3,4,4,5, + 5,6,6,7,7,8,0,1,1,2,2,3,4,4,5,5, + 6,7,7,8,8,9,0,1,1,2,3,3,4,5,5,6, + 7,7,8,9,9,10,0,1,1,2,3,4,4,5,6,7, + 7,8,9,10,10,11,0,1,2,2,3,4,5,6,6,7, + 8,9,10,10,11,12,0,1,2,3,3,4,5,6,7,8, + 9,10,10,11,12,13,0,1,2,3,4,5,6,7,7,8, + 9,10,11,12,13,14,0,1,2,3,4,5,6,7,8,9, + 10,11,12,13,14,15,0,241,228,215,203,192,181,170,161,152, + 143,135,127,120,114,107,101,95,90,85,80,75,71,67,63,60, + 56,53,50,47,44,42,39,37,35,33,31,29,28,26,24,23, + 22,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6, + 5,4,3,2,1,0,0,242,233,218,206,191,182,170,161,152, + 143,137,128,122,113,107,101,95,92,86,80,77,71,68,62,60, + 56,53,50,47,45,42,40,37,35,33,31,29,28,26,24,23, + 22,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6, + 5,4,3,2,1,0,0,255,241,228,216,202,192,181,171,162, + 153,142,135,127,121,115,112,102,97,90,85,82,75,72,67,63, + 60,57,55,51,48,45,42,40,37,36,33,31,30,28,27,25, + 23,22,21,19,18,17,16,15,14,13,12,11,10,9,8,7, + 6,5,4,3,2,1,0,243,230,217,204,193,181,173,162,153, + 144,136,128,121,114,108,102,96,91,85,81,76,72,68,64,60, + 57,53,50,47,45,42,40,37,35,33,31,29,28,26,24,23, + 22,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6, + 5,4,3,2,1,0,226,56,140,0,106,232,106,239,128,8, + 174,70,230,149,65,246,176,110,48,246,187,132,82,34,244,200, + 160,122,85,52,20,245,216,189,164,141,119,96,78,56,39,21, + 6,247,232,219,207,195,184,172,162,154,144,136,127,120,112,106, + 100,94,87,82,50,10,0,242,51,150,226,56,140,0,106,232, + 106,239,128,8,174,70,230,149,65,246,176,110,48,246,187,132, + 82,34,244,200,160,122,85,52,20,245,216,189,164,141,119,96, + 78,56,39,21,6,247,232,219,207,195,184,172,162,154,144,136, + 127,120,112,106,100,94,11,11,10,10,9,8,8,7,7,7, + 6,6,5,5,5,4,4,4,4,3,3,3,3,3,2,2, + 2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1, + 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,13,13,12,11,11,10,10,9,8, + 8,7,7,7,6,6,5,5,5,4,4,4,4,3,3,3, + 3,3,2,2,2,2,2,2,2,1,1,1,1,1,1,1, + 1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,76,228,13,76,227,6,76,159,8,1, + 16,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,5, + 6,7,0,1,2,3,4,2,0,0,4,2,0,0,0,16, + 0,8,0,16,0,8,133,211,129,169,133,211,129,169,136,177, + 250,141,23,5,162,0,134,252,10,38,252,10,38,252,10,38, + 252,10,38,252,109,23,5,144,2,230,252,24,105,0,133,250, + 165,252,105,0,133,251,76,7,7,32,181,9,173,22,5,240, + 5,206,28,5,48,3,76,162,8,206,29,5,208,82,162,0, + 238,23,5,173,25,5,133,250,173,26,5,133,251,160,16,177, + 250,48,171,208,3,76,44,15,141,29,5,136,177,250,136,132, + 252,168,185,255,255,157,80,5,185,255,255,157,88,5,169,0, + 157,112,5,157,96,5,164,252,177,250,157,104,5,232,136,16, + 219,169,17,24,101,250,141,25,5,169,0,101,251,141,26,5, + 173,27,5,141,28,5,162,7,222,112,5,48,6,202,16,248, + 76,162,8,189,80,5,133,250,189,88,5,133,251,188,96,5, + 177,250,208,28,200,177,250,157,208,5,41,240,157,216,5,177, + 250,10,10,10,10,157,224,5,200,152,157,96,5,76,87,7, + 201,64,176,79,125,104,5,157,152,5,200,177,250,16,37,41, + 127,133,252,200,177,250,157,208,5,41,240,157,216,5,177,250, + 10,10,10,10,157,224,5,200,152,157,96,5,164,252,32,156, + 15,76,87,7,168,254,96,5,254,96,5,189,208,5,41,240, + 157,216,5,189,208,5,10,10,10,10,157,224,5,32,156,15, + 76,87,7,201,128,176,37,41,63,24,125,104,5,157,152,5, + 200,177,250,157,208,5,41,240,157,216,5,177,250,10,10,10, + 10,157,224,5,200,152,157,96,5,76,87,7,208,14,200,177, + 250,157,112,5,200,152,157,96,5,76,87,7,201,192,176,15, + 41,63,24,125,104,5,157,152,5,254,96,5,76,87,7,201, + 208,176,15,200,254,96,5,41,15,141,27,5,141,28,5,76, + 106,7,201,224,176,22,177,250,133,252,200,177,250,133,253,200, + 152,157,96,5,165,252,32,14,14,76,87,7,201,240,176,46, + 177,250,133,252,200,177,250,133,253,165,252,32,14,14,188,96, + 5,200,200,177,250,157,208,5,41,240,157,216,5,177,250,10, + 10,10,10,157,224,5,200,152,157,96,5,76,87,7,201,255, + 176,11,233,239,157,112,5,254,96,5,76,87,7,169,64,157, + 112,5,76,87,7,32,181,9,162,7,189,120,5,240,115,76, + 217,10,189,14,5,240,14,169,0,157,32,5,157,40,5,202, + 16,232,76,31,9,164,253,185,0,3,24,101,252,157,56,5, + 152,157,160,5,189,176,5,61,168,6,240,40,165,253,41,127, + 168,185,0,4,24,101,252,157,55,5,185,128,4,105,0,157, + 56,5,169,0,157,31,5,188,152,6,153,39,5,202,202,16, + 169,76,31,9,189,176,5,61,160,6,240,22,189,104,6,24, + 101,253,157,162,5,168,185,0,3,24,101,252,56,101,254,157, + 58,5,202,16,133,232,134,252,162,3,173,9,5,240,6,41, + 64,208,60,162,7,138,168,185,32,5,208,12,188,152,6,185, + 40,5,208,4,138,168,169,0,25,168,5,157,48,5,185,56, + 5,157,72,5,185,160,5,157,64,5,185,176,5,5,252,133, + 252,224,4,208,3,141,31,5,202,16,202,141,30,5,96,189, + 32,5,29,168,5,157,48,5,189,44,5,29,172,5,157,52, + 5,189,56,5,157,72,5,189,60,5,157,76,5,189,160,5, + 157,64,5,189,164,5,157,68,5,202,16,211,173,176,5,13, + 177,5,13,178,5,13,179,5,141,30,5,173,180,5,13,181, + 5,13,182,5,13,183,5,141,31,5,96,173,9,5,208,3, + 76,144,10,48,3,76,72,10,173,13,5,170,74,74,41,1, + 168,185,30,5,141,56,210,138,41,4,168,185,56,5,141,48, + 210,189,32,5,141,49,210,185,57,5,141,50,210,189,33,5, + 141,51,210,185,58,5,141,52,210,189,34,5,141,53,210,185, + 59,5,141,54,210,189,35,5,141,55,210,173,12,5,170,74, + 74,41,1,168,185,30,5,141,40,210,138,41,4,168,185,56, + 5,141,32,210,189,32,5,141,33,210,185,57,5,141,34,210, + 189,33,5,141,35,210,185,58,5,141,36,210,189,34,5,141, + 37,210,185,59,5,141,38,210,189,35,5,141,39,210,173,11, + 5,170,74,74,41,1,168,185,30,5,141,24,210,138,172,9, + 5,16,2,41,4,168,185,56,5,141,16,210,189,32,5,141, + 17,210,185,57,5,141,18,210,189,33,5,141,19,210,185,58, + 5,141,20,210,189,34,5,141,21,210,185,59,5,141,22,210, + 189,35,5,141,23,210,173,10,5,170,74,74,41,1,168,185, + 30,5,141,8,210,138,172,9,5,16,2,41,4,168,185,56, + 5,141,0,210,189,32,5,141,1,210,185,57,5,141,2,210, + 189,33,5,141,3,210,185,58,5,141,4,210,189,34,5,141, + 5,210,185,59,5,141,6,210,189,35,5,141,7,210,96,189, + 128,5,133,250,189,136,5,133,251,189,128,6,133,252,189,136, + 6,133,253,189,144,6,133,254,189,184,5,221,192,5,144,12, + 157,8,6,189,200,5,157,184,5,76,11,11,189,8,6,240, + 48,189,232,5,240,19,222,248,5,208,14,157,248,5,189,216, + 5,240,6,56,233,16,157,216,5,189,240,5,240,19,222,0, + 6,208,14,157,0,6,189,224,5,240,6,56,233,16,157,224, + 5,188,72,6,177,250,24,125,152,5,24,101,253,133,253,222, + 88,6,16,57,189,80,6,157,88,6,189,96,6,240,30,24, + 125,72,6,157,72,6,240,13,221,64,6,144,32,169,255,157, + 96,6,76,135,11,169,1,157,96,6,76,135,11,254,72,6, + 189,64,6,221,72,6,176,5,169,0,157,72,6,169,19,24, + 101,250,133,250,144,2,230,251,188,184,5,177,250,41,240,157, + 168,5,177,250,41,15,29,216,5,168,185,0,2,5,255,168, + 185,0,2,157,32,5,188,184,5,200,177,250,41,15,29,224, + 5,168,185,0,2,5,255,168,185,0,2,157,40,5,189,40, + 6,208,39,189,16,6,141,212,11,16,254,76,209,12,234,76, + 108,12,234,76,167,12,234,76,212,12,234,76,1,13,234,76, + 33,13,234,76,65,13,234,76,73,13,222,40,6,188,184,5, + 200,177,250,41,112,74,74,74,141,34,12,177,250,48,6,189, + 112,6,76,18,12,189,120,6,61,176,6,157,176,5,200,200, + 152,157,184,5,136,177,250,144,254,144,22,144,12,144,34,144, + 24,144,46,144,36,144,50,144,52,125,128,6,157,128,6,177, + 250,24,101,252,133,252,76,172,8,125,136,6,157,136,6,177, + 250,24,101,253,133,253,76,172,8,125,144,6,157,144,6,177, + 250,24,101,254,133,254,76,172,8,133,252,169,0,133,253,76, + 172,8,189,32,6,41,3,74,144,10,208,25,189,24,6,24, + 101,252,133,252,222,56,6,16,78,254,32,6,189,48,6,157, + 56,6,76,247,11,165,252,253,24,6,133,252,222,56,6,16, + 54,254,32,6,189,48,6,157,56,6,76,247,11,188,32,6, + 189,24,6,48,2,200,200,136,152,24,101,252,133,252,222,56, + 6,16,20,152,157,32,6,221,24,6,208,5,73,255,157,24, + 6,189,48,6,157,56,6,76,247,11,188,32,6,189,24,6, + 48,2,200,200,136,152,24,101,253,133,253,222,56,6,16,231, + 152,157,32,6,221,24,6,208,216,73,255,157,24,6,189,48, + 6,157,56,6,76,247,11,189,32,6,24,101,252,133,252,222, + 56,6,16,195,189,24,6,24,125,32,6,157,32,6,189,48, + 6,157,56,6,76,247,11,165,253,56,253,32,6,133,253,222, + 56,6,16,163,189,24,6,24,125,32,6,157,32,6,189,48, + 6,157,56,6,76,247,11,189,24,6,24,101,252,133,252,76, + 247,11,160,16,169,0,133,250,169,0,133,251,169,0,141,23, + 5,138,240,63,177,250,240,2,16,1,202,169,17,24,101,250, + 133,250,144,2,230,251,238,23,5,208,230,162,0,169,0,133, + 252,138,141,23,5,10,38,252,10,38,252,10,38,252,10,38, + 252,109,23,5,144,2,230,252,24,105,0,133,250,165,252,105, + 0,133,251,32,44,15,165,250,141,25,5,165,251,141,26,5, + 162,7,169,255,157,208,5,169,240,157,216,5,157,224,5,202, + 16,240,169,3,141,15,210,141,31,210,141,47,210,141,63,210, + 206,23,5,232,142,28,5,232,142,29,5,142,22,5,96,138, + 41,15,141,27,5,96,142,22,5,96,201,16,176,3,76,76, + 13,201,32,144,136,201,48,176,3,76,133,15,201,64,144,223, + 201,80,176,3,76,44,15,201,96,144,219,201,112,144,3,76, + 180,14,132,253,41,15,10,141,23,14,165,253,144,254,144,30, + 144,56,144,89,144,96,144,26,144,28,144,30,144,32,144,34, + 144,36,144,13,144,11,144,9,144,7,144,5,144,3,141,24, + 5,96,157,104,6,96,157,112,6,96,157,120,6,96,157,144, + 6,96,157,128,6,96,157,136,6,96,41,112,74,74,157,16, + 6,41,48,208,3,157,32,6,165,253,48,6,41,15,157,24, + 6,96,41,15,73,255,24,105,1,157,24,6,96,41,63,157, + 48,6,157,56,6,96,41,128,10,42,157,96,6,165,253,41, + 112,74,74,74,74,157,64,6,208,3,157,96,6,165,253,41, + 15,157,80,6,157,88,6,189,72,6,221,64,6,144,143,189, + 64,6,240,2,233,1,157,72,6,96,132,250,134,251,160,25, + 177,250,200,141,9,5,177,250,200,141,10,5,177,250,200,141, + 11,5,177,250,200,141,12,5,177,250,200,141,13,5,177,250, + 141,27,5,165,250,73,128,48,1,232,141,172,15,142,173,15, + 73,128,48,1,232,141,29,7,142,30,7,232,141,35,7,142, + 36,7,232,141,162,15,142,163,15,73,128,48,1,232,141,25, + 5,141,215,6,141,79,13,141,148,13,142,26,5,142,221,6, + 142,83,13,142,154,13,169,240,133,255,169,0,141,22,5,141, + 24,5,162,7,169,0,141,22,5,157,120,5,157,176,5,157, + 32,5,157,40,5,157,48,5,157,48,210,157,32,210,157,16, + 210,157,0,210,202,16,226,141,24,210,141,8,210,141,56,210, + 141,40,210,141,30,5,141,31,5,96,157,32,5,157,40,5, + 157,48,5,157,176,5,96,152,157,208,5,41,240,157,216,5, + 189,208,5,10,10,10,10,157,224,5,96,41,7,133,250,138, + 166,250,41,63,240,225,157,152,5,152,48,238,189,208,5,32, + 117,15,169,0,157,120,5,185,255,255,240,190,157,136,5,133, + 251,185,255,255,157,128,5,133,250,152,157,144,5,160,8,177, + 250,200,157,192,5,177,250,200,157,200,5,177,250,200,157,104, + 6,177,250,200,157,112,6,177,250,200,157,120,6,177,250,200, + 157,232,5,157,248,5,177,250,200,157,240,5,157,0,6,177, + 250,41,112,74,74,157,16,6,177,250,200,48,8,41,15,157, + 24,6,76,9,16,41,15,73,255,24,105,1,157,24,6,177, + 250,200,157,40,6,177,250,200,41,63,157,48,6,157,56,6, + 177,250,41,128,10,42,157,96,6,177,250,41,112,74,74,74, + 74,157,64,6,208,3,157,96,6,177,250,136,41,15,157,80, + 6,157,88,6,177,250,41,192,29,152,5,157,152,5,168,185, + 0,3,157,56,5,169,0,157,184,5,157,32,6,157,8,6, + 157,72,6,157,128,6,157,136,6,157,144,6,169,1,157,120, + 5,96 +END_CONST_ARRAY; -- cgit v1.2.3