From 569285794b9112f0134ddad4bb886308ea4a7be6 Mon Sep 17 00:00:00 2001 From: Torne Wuff Date: Sun, 6 Nov 2011 22:44:25 +0000 Subject: Bulk convert all DOS line endings to UNIX. For the git migration we want a nice clean repository with UNIX line endings. git does not use svn:eol-style, we just need the file contents to be sane. Sorry everybody. I know this messes up blame. Scumbag *NIX developer says migrating to git will make line ending issues go away; commits giant change to svn which changes line endings anyway. :) git-svn-id: svn://svn.rockbox.org/rockbox/trunk@30924 a1c6a512-1295-4272-9138-f99709370657 --- apps/codecs/libgme/2413tone.h | 40 +- apps/codecs/libgme/281btone.h | 40 +- apps/codecs/libgme/ay_emu.c | 1198 +- apps/codecs/libgme/blargg_config.h | 84 +- apps/codecs/libgme/emu2413.c | 3962 +-- apps/codecs/libgme/emu2413.h | 328 +- apps/codecs/libgme/emutables.h | 420 +- apps/codecs/libgme/emutypes.h | 82 +- apps/codecs/libgme/hes_apu_adpcm.c | 594 +- apps/codecs/libgme/inflate/mbreader.c | 32 +- apps/codecs/libgme/inflate/mbreader.h | 30 +- apps/codecs/libgme/kss_cpu.c | 70 +- apps/codecs/libgme/nes_cpu_run.h | 2244 +- apps/codecs/libgme/nes_vrc7_apu.c | 176 +- apps/codecs/libgme/opl_apu.c | 396 +- apps/codecs/libgme/opl_apu.h | 126 +- apps/codecs/libgme/opltables.h | 484 +- apps/codecs/libgme/sgc_cpu.c | 72 +- apps/codecs/libgme/sgc_emu.c | 960 +- apps/codecs/libgme/sgc_emu.h | 390 +- apps/codecs/libgme/sms_fm_apu.c | 164 +- apps/codecs/libgme/sms_fm_apu.h | 86 +- apps/codecs/libgme/track_filter.c | 588 +- apps/codecs/libgme/track_filter.h | 180 +- apps/codecs/libgme/vrc7tone.h | 40 +- apps/codecs/libgme/ym2413_emu.c | 90 +- apps/codecs/libgme/ym2413_emu.h | 122 +- apps/codecs/libgme/ymtables.h | 1118 +- apps/codecs/libgme/z80_cpu.h | 232 +- apps/codecs/libgme/z80_cpu_run.h | 3392 +-- apps/lang/arabic.lang | 26 +- apps/lang/latviesu.lang | 25500 +++++++++---------- firmware/drivers/audio/cs42l55.c | 490 +- firmware/drivers/audio/dac3550a.c | 2 +- firmware/export/ata-defines.h | 116 +- firmware/export/config/rk27generic.h | 378 +- firmware/export/dac3550a.h | 2 +- firmware/export/mascodec.h | 2 +- firmware/export/s5l8702.h | 1660 +- .../target/arm/as3525/sansa-clipzip/lcd-clipzip.c | 2 +- firmware/target/arm/s5l8700/postmortemstub.S | 616 +- firmware/target/arm/s5l8702/debug-s5l8702.c | 332 +- firmware/target/arm/s5l8702/debug-target.h | 66 +- firmware/target/arm/s5l8702/i2c-s5l8702.c | 392 +- firmware/target/arm/s5l8702/kernel-s5l8702.c | 112 +- firmware/target/arm/s5l8702/pcm-s5l8702.c | 456 +- firmware/target/arm/s5l8702/pcm-target.h | 80 +- firmware/target/arm/s5l8702/system-target.h | 94 +- firmware/target/arm/s5l8702/timer-s5l8702.c | 188 +- firmware/target/sh/archos/mascodec-archos.c | 2 +- rbutil/e200rpatcher/e200rpatcher.rc | 2 +- rbutil/ipodpatcher/ipodpatcher.rc | 2 +- rbutil/sansapatcher/sansapatcher.rc | 2 +- utils/MTP/sendfirm.manifest | 16 +- utils/tcctool/tcctool-windows.txt | 62 +- .../qtfindreplacedialog/findreplace_global.h | 42 +- .../qtfindreplacedialog/findreplacedialog.ui | 64 +- .../qtfindreplacedialog/findreplaceform.ui | 408 +- utils/themeeditor/themeeditor.rc | 2 +- 59 files changed, 24428 insertions(+), 24428 deletions(-) diff --git a/apps/codecs/libgme/2413tone.h b/apps/codecs/libgme/2413tone.h index e4366ab245..c0922c1225 100644 --- a/apps/codecs/libgme/2413tone.h +++ b/apps/codecs/libgme/2413tone.h @@ -1,20 +1,20 @@ -/* YM2413 tone by okazaki@angel.ne.jp */ -0x49,0x4c,0x4c,0x32,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x61,0x61,0x1e,0x17,0xf0,0x7f,0x00,0x17,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x13,0x41,0x16,0x0e,0xfd,0xf4,0x23,0x23,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x03,0x01,0x9a,0x04,0xf3,0xf3,0x13,0xf3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x11,0x61,0x0e,0x07,0xfa,0x64,0x70,0x17,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x22,0x21,0x1e,0x06,0xf0,0x76,0x00,0x28,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x21,0x22,0x16,0x05,0xf0,0x71,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x21,0x61,0x1d,0x07,0x82,0x80,0x17,0x17,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x23,0x21,0x2d,0x16,0x90,0x90,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x21,0x21,0x1b,0x06,0x64,0x65,0x10,0x17,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x21,0x21,0x0b,0x1a,0x85,0xa0,0x70,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x23,0x01,0x83,0x10,0xff,0xb4,0x10,0xf4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x97,0xc1,0x20,0x07,0xff,0xf4,0x22,0x22,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x61,0x00,0x0c,0x05,0xc2,0xf6,0x40,0x44,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x01,0x01,0x56,0x03,0x94,0xc2,0x03,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x21,0x01,0x89,0x03,0xf1,0xe4,0xf0,0x23,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x07,0x21,0x14,0x00,0xee,0xf8,0xff,0xf8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x01,0x31,0x00,0x00,0xf8,0xf7,0xf8,0xf7,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x25,0x11,0x00,0x00,0xf8,0xfa,0xf8,0x55,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +/* YM2413 tone by okazaki@angel.ne.jp */ +0x49,0x4c,0x4c,0x32,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x61,0x61,0x1e,0x17,0xf0,0x7f,0x00,0x17,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x13,0x41,0x16,0x0e,0xfd,0xf4,0x23,0x23,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x03,0x01,0x9a,0x04,0xf3,0xf3,0x13,0xf3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x11,0x61,0x0e,0x07,0xfa,0x64,0x70,0x17,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x22,0x21,0x1e,0x06,0xf0,0x76,0x00,0x28,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x21,0x22,0x16,0x05,0xf0,0x71,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x21,0x61,0x1d,0x07,0x82,0x80,0x17,0x17,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x23,0x21,0x2d,0x16,0x90,0x90,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x21,0x21,0x1b,0x06,0x64,0x65,0x10,0x17,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x21,0x21,0x0b,0x1a,0x85,0xa0,0x70,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x23,0x01,0x83,0x10,0xff,0xb4,0x10,0xf4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x97,0xc1,0x20,0x07,0xff,0xf4,0x22,0x22,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x61,0x00,0x0c,0x05,0xc2,0xf6,0x40,0x44,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x01,0x01,0x56,0x03,0x94,0xc2,0x03,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x21,0x01,0x89,0x03,0xf1,0xe4,0xf0,0x23,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x07,0x21,0x14,0x00,0xee,0xf8,0xff,0xf8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x01,0x31,0x00,0x00,0xf8,0xf7,0xf8,0xf7,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x25,0x11,0x00,0x00,0xf8,0xfa,0xf8,0x55,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 diff --git a/apps/codecs/libgme/281btone.h b/apps/codecs/libgme/281btone.h index 1300523fbe..83f63bff00 100644 --- a/apps/codecs/libgme/281btone.h +++ b/apps/codecs/libgme/281btone.h @@ -1,20 +1,20 @@ -/* YMF281B tone by Chabin */ -0x49,0x4c,0x4c,0x32,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x62,0x21,0x1a,0x07,0xf0,0x6f,0x00,0x16,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x10,0x44,0x02,0xf6,0xf4,0x54,0x23,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x03,0x01,0x97,0x04,0xf3,0xf3,0x13,0xf3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x01,0x61,0x0a,0x0f,0xfa,0x64,0x70,0x17,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x22,0x21,0x1e,0x06,0xf0,0x76,0x00,0x28,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x61,0x8a,0x0e,0xc0,0x61,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x21,0x61,0x1b,0x07,0x84,0x80,0x17,0x17,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x37,0x32,0xc9,0x01,0x66,0x64,0x40,0x28,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x01,0x21,0x06,0x03,0xa5,0x71,0x51,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x06,0x11,0x5e,0x07,0xf3,0xf2,0xf6,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x20,0x18,0x06,0xf5,0xf3,0x20,0x26,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x97,0x41,0x20,0x07,0xff,0xf4,0x22,0x22,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x65,0x61,0x15,0x00,0xf7,0xf3,0x16,0xf4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x01,0x31,0x0e,0x07,0xfa,0xf3,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x48,0x61,0x09,0x07,0xf1,0x94,0xf0,0xf5,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x07,0x21,0x14,0x00,0xee,0xf8,0xff,0xf8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x01,0x31,0x00,0x00,0xf8,0xf7,0xf8,0xf7,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x25,0x11,0x00,0x00,0xf8,0xfa,0xf8,0x55,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +/* YMF281B tone by Chabin */ +0x49,0x4c,0x4c,0x32,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x62,0x21,0x1a,0x07,0xf0,0x6f,0x00,0x16,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x10,0x44,0x02,0xf6,0xf4,0x54,0x23,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x03,0x01,0x97,0x04,0xf3,0xf3,0x13,0xf3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x01,0x61,0x0a,0x0f,0xfa,0x64,0x70,0x17,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x22,0x21,0x1e,0x06,0xf0,0x76,0x00,0x28,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x61,0x8a,0x0e,0xc0,0x61,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x21,0x61,0x1b,0x07,0x84,0x80,0x17,0x17,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x37,0x32,0xc9,0x01,0x66,0x64,0x40,0x28,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x01,0x21,0x06,0x03,0xa5,0x71,0x51,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x06,0x11,0x5e,0x07,0xf3,0xf2,0xf6,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x20,0x18,0x06,0xf5,0xf3,0x20,0x26,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x97,0x41,0x20,0x07,0xff,0xf4,0x22,0x22,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x65,0x61,0x15,0x00,0xf7,0xf3,0x16,0xf4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x01,0x31,0x0e,0x07,0xfa,0xf3,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x48,0x61,0x09,0x07,0xf1,0x94,0xf0,0xf5,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x07,0x21,0x14,0x00,0xee,0xf8,0xff,0xf8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x01,0x31,0x00,0x00,0xf8,0xf7,0xf8,0xf7,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x25,0x11,0x00,0x00,0xf8,0xfa,0xf8,0x55,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 diff --git a/apps/codecs/libgme/ay_emu.c b/apps/codecs/libgme/ay_emu.c index 42e739f2df..92faba4929 100644 --- a/apps/codecs/libgme/ay_emu.c +++ b/apps/codecs/libgme/ay_emu.c @@ -1,599 +1,599 @@ -// Game_Music_Emu 0.6-pre. http://www.slack.net/~ant/ - -#include "ay_emu.h" - -#include "blargg_endian.h" - -/* Copyright (C) 2006-2009 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. This -module 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 Lesser General Public License for more -details. You should have received a copy of the GNU Lesser General Public -License along with this module; if not, write to the Free Software Foundation, -Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ - -#include "blargg_source.h" - -const char* const gme_wrong_file_type = "Wrong file type for this emulator"; - -// TODO: probably don't need detailed errors as to why file is corrupt - -int const spectrum_clock = 3546900; // 128K Spectrum -int const spectrum_period = 70908; - -//int const spectrum_clock = 3500000; // 48K Spectrum -//int const spectrum_period = 69888; - -int const cpc_clock = 2000000; - -static void clear_track_vars( struct Ay_Emu *this ) -{ - this->current_track = -1; - track_stop( &this->track_filter ); -} - -void Ay_init( struct Ay_Emu *this ) -{ - this->sample_rate = 0; - this->mute_mask_ = 0; - this->tempo = (int)FP_ONE_TEMPO; - this->gain = (int)FP_ONE_GAIN; - this->track_count = 0; - - // defaults - this->tfilter = *track_get_setup( &this->track_filter ); - this->tfilter.max_initial = 2; - this->tfilter.lookahead = 6; - this->track_filter.silence_ignored_ = false; - - this->beeper_output = NULL; - disable_beeper( this ); - - Ay_apu_init( &this->apu ); - Z80_init( &this->cpu ); - - // clears fields - this->voice_count = 0; - this->voice_types = 0; - clear_track_vars( this ); -} - -// Track info - -// Given pointer to 2-byte offset of data, returns pointer to data, or NULL if -// offset is 0 or there is less than min_size bytes of data available. -static byte const* get_data( struct file_t const* file, byte const ptr [], int min_size ) -{ - int offset = (int16_t) get_be16( ptr ); - int pos = ptr - (byte const*) file->header; - int size = file->end - (byte const*) file->header; - assert( (unsigned) pos <= (unsigned) size - 2 ); - int limit = size - min_size; - if ( limit < 0 || !offset || (unsigned) (pos + offset) > (unsigned) limit ) - return NULL; - return ptr + offset; -} - -static blargg_err_t parse_header( byte const in [], int size, struct file_t* out ) -{ - if ( size < header_size ) - return gme_wrong_file_type; - - out->header = (struct header_t const*) in; - out->end = in + size; - struct header_t const* h = (struct header_t const*) in; - if ( memcmp( h->tag, "ZXAYEMUL", 8 ) ) - return gme_wrong_file_type; - - out->tracks = get_data( out, h->track_info, (h->max_track + 1) * 4 ); - if ( !out->tracks ) - return "missing track data"; - - return 0; -} - -// Setup - -static void change_clock_rate( struct Ay_Emu *this, int rate ) -{ - this->clock_rate_ = rate; - Buffer_clock_rate( &this->stereo_buf, rate ); -} - -blargg_err_t Ay_load_mem( struct Ay_Emu *this, byte const in [], long size ) -{ - // Unload - this->voice_count = 0; - this->track_count = 0; - this->m3u.size = 0; - clear_track_vars( this ); - - assert( offsetof (struct header_t,track_info [2]) == header_size ); - - RETURN_ERR( parse_header( in, size, &this->file ) ); - - /* if ( file.header->vers > 2 ) - warning( "Unknown file version" ); */ - - this->voice_count = ay_osc_count + 1; // +1 for beeper - static int const types [ay_osc_count + 1] = { - wave_type+0, wave_type+1, wave_type+2, mixed_type+1 - }; - this->voice_types = types; - - Ay_apu_volume( &this->apu, this->gain); - - // Setup buffer - change_clock_rate( this, spectrum_clock ); - RETURN_ERR( Buffer_set_channel_count( &this->stereo_buf, this->voice_count, this->voice_types ) ); - this->buf_changed_count = Buffer_channels_changed_count( &this->stereo_buf ); - - Sound_set_tempo( this, this->tempo ); - Sound_mute_voices( this, this->mute_mask_ ); - - this->track_count = this->file.header->max_track + 1; - return 0; -} - -static void set_beeper_output( struct Ay_Emu *this, struct Blip_Buffer* b ) -{ - this->beeper_output = b; - if ( b && !this->cpc_mode ) - this->beeper_mask = 0x10; - else - disable_beeper( this ); -} - -static void set_voice( struct Ay_Emu *this, int i, struct Blip_Buffer* center ) -{ - if ( i >= ay_osc_count ) - set_beeper_output( this, center ); - else - Ay_apu_set_output( &this->apu, i, center ); -} - -static blargg_err_t run_clocks( struct Ay_Emu *this, blip_time_t* duration, int msec ) -{ -#if defined(ROCKBOX) - (void) msec; -#endif - - cpu_time_t *end = duration; - struct Z80_Cpu* cpu = &this->cpu; - Z80_set_time( cpu, 0 ); - - // Since detection of CPC mode will halve clock rate during the frame - // and thus generate up to twice as much sound, we must generate half - // as much until mode is known. - if ( !(this->spectrum_mode | this->cpc_mode) ) - *end /= 2; - - while ( Z80_time( cpu ) < *end ) - { - run_cpu( this, min( *end, this->next_play ) ); - - if ( Z80_time( cpu ) >= this->next_play ) - { - // next frame - this->next_play += this->play_period; - - if ( cpu->r.iff1 ) - { - // interrupt enabled - - if ( this->mem.ram [cpu->r.pc] == 0x76 ) - cpu->r.pc++; // advance past HALT instruction - - cpu->r.iff1 = 0; - cpu->r.iff2 = 0; - - this->mem.ram [--cpu->r.sp] = (byte) (cpu->r.pc >> 8); - this->mem.ram [--cpu->r.sp] = (byte) (cpu->r.pc); - - // fixed interrupt - cpu->r.pc = 0x38; - Z80_adjust_time( cpu, 12 ); - - if ( cpu->r.im == 2 ) - { - // vectored interrupt - addr_t addr = cpu->r.i * 0x100 + 0xFF; - cpu->r.pc = this->mem.ram [(addr + 1) & 0xFFFF] * 0x100 + this->mem.ram [addr]; - Z80_adjust_time( cpu, 6 ); - } - } - } - } - - // End time frame - *end = Z80_time( cpu ); - this->next_play -= *end; - check( this->next_play >= 0 ); - Z80_adjust_time( cpu, -*end ); - Ay_apu_end_frame( &this->apu, *end ); - return 0; -} - -// Emulation - -void cpu_out_( struct Ay_Emu *this, cpu_time_t time, addr_t addr, int data ) -{ - // Spectrum - if ( !this->cpc_mode ) - { - switch ( addr & 0xFEFF ) - { - case 0xFEFD: - this->spectrum_mode = true; - Ay_apu_write_addr( &this->apu, data ); - return; - - case 0xBEFD: - this->spectrum_mode = true; - Ay_apu_write_data( &this->apu, time, data ); - return; - } - } - - // CPC - if ( !this->spectrum_mode ) - { - switch ( addr >> 8 ) - { - case 0xF6: - switch ( data & 0xC0 ) - { - case 0xC0: - Ay_apu_write_addr( &this->apu, this->cpc_latch ); - goto enable_cpc; - - case 0x80: - Ay_apu_write_data( &this->apu, time, this->cpc_latch ); - goto enable_cpc; - } - break; - - case 0xF4: - this->cpc_latch = data; - goto enable_cpc; - } - } - - /* dprintf( "Unmapped OUT: $%04X <- $%02X\n", addr, data ); */ - return; - -enable_cpc: - if ( !this->cpc_mode ) - { - this->cpc_mode = true; - disable_beeper( this ); - - change_clock_rate( this, cpc_clock ); - Sound_set_tempo( this, this->tempo ); - } -} - -blargg_err_t Ay_set_sample_rate( struct Ay_Emu *this, int rate ) -{ - require( !this->sample_rate ); // sample rate can't be changed once set - Buffer_init( &this->stereo_buf ); - RETURN_ERR( Buffer_set_sample_rate( &this->stereo_buf, rate, 1000 / 20 ) ); - - // Set buffer bass - Buffer_bass_freq( &this->stereo_buf, 160 ); - - this->sample_rate = rate; - RETURN_ERR( track_init( &this->track_filter, this ) ); - this->tfilter.max_silence = 6 * stereo * this->sample_rate; - return 0; -} - -void Sound_mute_voice( struct Ay_Emu *this, int index, bool mute ) -{ - require( (unsigned) index < (unsigned) this->voice_count ); - int bit = 1 << index; - int mask = this->mute_mask_ | bit; - if ( !mute ) - mask ^= bit; - Sound_mute_voices( this, mask ); -} - -void Sound_mute_voices( struct Ay_Emu *this, int mask ) -{ - require( this->sample_rate ); // sample rate must be set first - this->mute_mask_ = mask; - - int i; - for ( i = this->voice_count; i--; ) - { - if ( mask & (1 << i) ) - { - set_voice( this, i, 0 ); - } - else - { - struct channel_t ch = Buffer_channel( &this->stereo_buf, i ); - assert( (ch.center && ch.left && ch.right) || - (!ch.center && !ch.left && !ch.right) ); // all or nothing - set_voice( this, i, ch.center ); - } - } -} - -void Sound_set_tempo( struct Ay_Emu *this, int t ) -{ - require( this->sample_rate ); // sample rate must be set first - int const min = (int)(FP_ONE_TEMPO*0.02); - int const max = (int)(FP_ONE_TEMPO*4.00); - if ( t < min ) t = min; - if ( t > max ) t = max; - this->tempo = t; - - int p = spectrum_period; - if ( this->clock_rate_ != spectrum_clock ) - p = this->clock_rate_ / 50; - - this->play_period = (blip_time_t) ((p * FP_ONE_TEMPO) / t); -} - -blargg_err_t Ay_start_track( struct Ay_Emu *this, int track ) -{ - clear_track_vars( this ); - - // Remap track if playlist available - if ( this->m3u.size > 0 ) { - struct entry_t* e = &this->m3u.entries[track]; - track = e->track; - } - - this->current_track = track; - Buffer_clear( &this->stereo_buf ); - - byte* const mem = this->mem.ram; - - memset( mem + 0x0000, 0xC9, 0x100 ); // fill RST vectors with RET - memset( mem + 0x0100, 0xFF, 0x4000 - 0x100 ); - memset( mem + ram_addr, 0x00, mem_size - ram_addr ); - - // locate data blocks - byte const* const data = get_data( &this->file, this->file.tracks + track * 4 + 2, 14 ); - if ( !data ) - return "file data missing"; - - byte const* const more_data = get_data( &this->file, data + 10, 6 ); - if ( !more_data ) - return "file data missing"; - - byte const* blocks = get_data( &this->file, data + 12, 8 ); - if ( !blocks ) - return "file data missing"; - - // initial addresses - unsigned addr = get_be16( blocks ); - if ( !addr ) - return "file data missing"; - - unsigned init = get_be16( more_data + 2 ); - if ( !init ) - init = addr; - - // copy blocks into memory - do - { - blocks += 2; - unsigned len = get_be16( blocks ); blocks += 2; - if ( addr + len > mem_size ) - { - /* warning( "Bad data block size" ); */ - len = mem_size - addr; - } - check( len ); - byte const* in = get_data( &this->file, blocks, 0 ); blocks += 2; - if ( len > (unsigned) (this->file.end - in) ) - { - /* warning( "File data missing" ); */ - len = this->file.end - in; - } - - memcpy( mem + addr, in, len ); - - if ( this->file.end - blocks < 8 ) - { - /* warning( "File data missing" ); */ - break; - } - } - while ( (addr = get_be16( blocks )) != 0 ); - - // copy and configure driver - static byte const passive [] = { - 0xF3, // DI - 0xCD, 0, 0, // CALL init - 0xED, 0x5E, // LOOP: IM 2 - 0xFB, // EI - 0x76, // HALT - 0x18, 0xFA // JR LOOP - }; - static byte const active [] = { - 0xF3, // DI - 0xCD, 0, 0, // CALL init - 0xED, 0x56, // LOOP: IM 1 - 0xFB, // EI - 0x76, // HALT - 0xCD, 0, 0, // CALL play - 0x18, 0xF7 // JR LOOP - }; - memcpy( mem, passive, sizeof passive ); - int const play_addr = get_be16( more_data + 4 ); - if ( play_addr ) - { - memcpy( mem, active, sizeof active ); - mem [ 9] = play_addr; - mem [10] = play_addr >> 8; - } - mem [2] = init; - mem [3] = init >> 8; - - mem [0x38] = 0xFB; // Put EI at interrupt vector (followed by RET) - - // start at spectrum speed - change_clock_rate( this, spectrum_clock ); - Sound_set_tempo( this, this->tempo ); - - struct registers_t r; - memset( &r, 0, sizeof(struct registers_t) ); - - r.sp = get_be16( more_data ); - r.b.a = r.b.b = r.b.d = r.b.h = data [8]; - r.b.flags = r.b.c = r.b.e = r.b.l = data [9]; - r.alt.w = r.w; - r.ix = r.iy = r.w.hl; - - memset( this->mem.padding1, 0xFF, sizeof this->mem.padding1 ); - - int const mirrored = 0x80; // this much is mirrored after end of memory - memset( this->mem.ram + mem_size + mirrored, 0xFF, sizeof this->mem.ram - mem_size - mirrored ); - memcpy( this->mem.ram + mem_size, this->mem.ram, mirrored ); // some code wraps around (ugh) - - Z80_reset( &this->cpu, this->mem.padding1, this->mem.padding1 ); - Z80_map_mem( &this->cpu, 0, mem_size, this->mem.ram, this->mem.ram ); - this->cpu.r = r; - - this->beeper_delta = (int) ((ay_amp_range*4)/5); - this->last_beeper = 0; - this->next_play = this->play_period; - this->spectrum_mode = false; - this->cpc_mode = false; - this->cpc_latch = 0; - set_beeper_output( this, this->beeper_output ); - Ay_apu_reset( &this->apu ); - - // a few tunes rely on channels having tone enabled at the beginning - Ay_apu_write_addr( &this->apu, 7 ); - Ay_apu_write_data( &this->apu, 0, 0x38 ); - - // convert filter times to samples - struct setup_t s = this->tfilter; - s.max_initial *= this->sample_rate * stereo; - #ifdef GME_DISABLE_SILENCE_LOOKAHEAD - s.lookahead = 1; - #endif - track_setup( &this->track_filter, &s ); - - return track_start( &this->track_filter ); -} - -// Tell/Seek - -static int msec_to_samples( int msec, int sample_rate ) -{ - int sec = msec / 1000; - msec -= sec * 1000; - return (sec * sample_rate + msec * sample_rate / 1000) * stereo; -} - -int Track_tell( struct Ay_Emu *this ) -{ - int rate = this->sample_rate * stereo; - int sec = track_sample_count( &this->track_filter ) / rate; - return sec * 1000 + (track_sample_count( &this->track_filter ) - sec * rate) * 1000 / rate; -} - -blargg_err_t Track_seek( struct Ay_Emu *this, int msec ) -{ - int time = msec_to_samples( msec, this->sample_rate ); - if ( time < track_sample_count( &this->track_filter ) ) - RETURN_ERR( Ay_start_track( this, this->current_track ) ); - return Track_skip( this, time - track_sample_count( &this->track_filter ) ); -} - -blargg_err_t skip_( void *emu, int count ) -{ - struct Ay_Emu* this = (struct Ay_Emu*) emu; - - // for long skip, mute sound - const int threshold = 32768; - if ( count > threshold ) - { - int saved_mute = this->mute_mask_; - Sound_mute_voices( this, ~0 ); - - int n = count - threshold/2; - n &= ~(2048-1); // round to multiple of 2048 - count -= n; - RETURN_ERR( skippy_( &this->track_filter, n ) ); - - Sound_mute_voices( this, saved_mute ); - } - - return skippy_( &this->track_filter, count ); -} - -blargg_err_t Track_skip( struct Ay_Emu *this, int count ) -{ - require( this->current_track >= 0 ); // start_track() must have been called already - return track_skip( &this->track_filter, count ); -} - -int Track_get_length( struct Ay_Emu* this, int n ) -{ - int length = 0; - - byte const* track_info = get_data( &this->file, this->file.tracks + n * 4 + 2, 6 ); - if ( track_info ) - length = get_be16( track_info + 4 ) * (1000 / 50); // frames to msec - - if ( (this->m3u.size > 0) && (n < this->m3u.size) ) { - struct entry_t* entry = &this->m3u.entries [n]; - length = entry->length; - } - - if ( length <= 0 ) - length = 120 * 1000; /* 2 minutes */ - - return length; -} - -void Track_set_fade( struct Ay_Emu *this, int start_msec, int length_msec ) -{ - track_set_fade( &this->track_filter, msec_to_samples( start_msec, this->sample_rate ), - length_msec * this->sample_rate / (1000 / stereo) ); -} - -blargg_err_t Ay_play( struct Ay_Emu *this, int out_count, sample_t* out ) -{ - require( this->current_track >= 0 ); - require( out_count % stereo == 0 ); - return track_play( &this->track_filter, out_count, out ); -} - -blargg_err_t play_( void *emu, int count, sample_t* out ) -{ - struct Ay_Emu* this = (struct Ay_Emu*) emu; - - int remain = count; - while ( remain ) - { - Buffer_disable_immediate_removal( &this->stereo_buf ); - remain -= Buffer_read_samples( &this->stereo_buf, &out [count - remain], remain ); - if ( remain ) - { - if ( this->buf_changed_count != Buffer_channels_changed_count( &this->stereo_buf ) ) - { - this->buf_changed_count = Buffer_channels_changed_count( &this->stereo_buf ); - - // Remute voices - Sound_mute_voices( this, this->mute_mask_ ); - } - int msec = Buffer_length( &this->stereo_buf ); - blip_time_t clocks_emulated = msec * this->clock_rate_ / 1000 - 100; - RETURN_ERR( run_clocks( this, &clocks_emulated, msec ) ); - assert( clocks_emulated ); - Buffer_end_frame( &this->stereo_buf, clocks_emulated ); - } - } - return 0; -} +// Game_Music_Emu 0.6-pre. http://www.slack.net/~ant/ + +#include "ay_emu.h" + +#include "blargg_endian.h" + +/* Copyright (C) 2006-2009 Shay Green. This module is free software; you +can redistribute it and/or modify it under the terms of the GNU Lesser +General Public License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. This +module 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 Lesser General Public License for more +details. You should have received a copy of the GNU Lesser General Public +License along with this module; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ + +#include "blargg_source.h" + +const char* const gme_wrong_file_type = "Wrong file type for this emulator"; + +// TODO: probably don't need detailed errors as to why file is corrupt + +int const spectrum_clock = 3546900; // 128K Spectrum +int const spectrum_period = 70908; + +//int const spectrum_clock = 3500000; // 48K Spectrum +//int const spectrum_period = 69888; + +int const cpc_clock = 2000000; + +static void clear_track_vars( struct Ay_Emu *this ) +{ + this->current_track = -1; + track_stop( &this->track_filter ); +} + +void Ay_init( struct Ay_Emu *this ) +{ + this->sample_rate = 0; + this->mute_mask_ = 0; + this->tempo = (int)FP_ONE_TEMPO; + this->gain = (int)FP_ONE_GAIN; + this->track_count = 0; + + // defaults + this->tfilter = *track_get_setup( &this->track_filter ); + this->tfilter.max_initial = 2; + this->tfilter.lookahead = 6; + this->track_filter.silence_ignored_ = false; + + this->beeper_output = NULL; + disable_beeper( this ); + + Ay_apu_init( &this->apu ); + Z80_init( &this->cpu ); + + // clears fields + this->voice_count = 0; + this->voice_types = 0; + clear_track_vars( this ); +} + +// Track info + +// Given pointer to 2-byte offset of data, returns pointer to data, or NULL if +// offset is 0 or there is less than min_size bytes of data available. +static byte const* get_data( struct file_t const* file, byte const ptr [], int min_size ) +{ + int offset = (int16_t) get_be16( ptr ); + int pos = ptr - (byte const*) file->header; + int size = file->end - (byte const*) file->header; + assert( (unsigned) pos <= (unsigned) size - 2 ); + int limit = size - min_size; + if ( limit < 0 || !offset || (unsigned) (pos + offset) > (unsigned) limit ) + return NULL; + return ptr + offset; +} + +static blargg_err_t parse_header( byte const in [], int size, struct file_t* out ) +{ + if ( size < header_size ) + return gme_wrong_file_type; + + out->header = (struct header_t const*) in; + out->end = in + size; + struct header_t const* h = (struct header_t const*) in; + if ( memcmp( h->tag, "ZXAYEMUL", 8 ) ) + return gme_wrong_file_type; + + out->tracks = get_data( out, h->track_info, (h->max_track + 1) * 4 ); + if ( !out->tracks ) + return "missing track data"; + + return 0; +} + +// Setup + +static void change_clock_rate( struct Ay_Emu *this, int rate ) +{ + this->clock_rate_ = rate; + Buffer_clock_rate( &this->stereo_buf, rate ); +} + +blargg_err_t Ay_load_mem( struct Ay_Emu *this, byte const in [], long size ) +{ + // Unload + this->voice_count = 0; + this->track_count = 0; + this->m3u.size = 0; + clear_track_vars( this ); + + assert( offsetof (struct header_t,track_info [2]) == header_size ); + + RETURN_ERR( parse_header( in, size, &this->file ) ); + + /* if ( file.header->vers > 2 ) + warning( "Unknown file version" ); */ + + this->voice_count = ay_osc_count + 1; // +1 for beeper + static int const types [ay_osc_count + 1] = { + wave_type+0, wave_type+1, wave_type+2, mixed_type+1 + }; + this->voice_types = types; + + Ay_apu_volume( &this->apu, this->gain); + + // Setup buffer + change_clock_rate( this, spectrum_clock ); + RETURN_ERR( Buffer_set_channel_count( &this->stereo_buf, this->voice_count, this->voice_types ) ); + this->buf_changed_count = Buffer_channels_changed_count( &this->stereo_buf ); + + Sound_set_tempo( this, this->tempo ); + Sound_mute_voices( this, this->mute_mask_ ); + + this->track_count = this->file.header->max_track + 1; + return 0; +} + +static void set_beeper_output( struct Ay_Emu *this, struct Blip_Buffer* b ) +{ + this->beeper_output = b; + if ( b && !this->cpc_mode ) + this->beeper_mask = 0x10; + else + disable_beeper( this ); +} + +static void set_voice( struct Ay_Emu *this, int i, struct Blip_Buffer* center ) +{ + if ( i >= ay_osc_count ) + set_beeper_output( this, center ); + else + Ay_apu_set_output( &this->apu, i, center ); +} + +static blargg_err_t run_clocks( struct Ay_Emu *this, blip_time_t* duration, int msec ) +{ +#if defined(ROCKBOX) + (void) msec; +#endif + + cpu_time_t *end = duration; + struct Z80_Cpu* cpu = &this->cpu; + Z80_set_time( cpu, 0 ); + + // Since detection of CPC mode will halve clock rate during the frame + // and thus generate up to twice as much sound, we must generate half + // as much until mode is known. + if ( !(this->spectrum_mode | this->cpc_mode) ) + *end /= 2; + + while ( Z80_time( cpu ) < *end ) + { + run_cpu( this, min( *end, this->next_play ) ); + + if ( Z80_time( cpu ) >= this->next_play ) + { + // next frame + this->next_play += this->play_period; + + if ( cpu->r.iff1 ) + { + // interrupt enabled + + if ( this->mem.ram [cpu->r.pc] == 0x76 ) + cpu->r.pc++; // advance past HALT instruction + + cpu->r.iff1 = 0; + cpu->r.iff2 = 0; + + this->mem.ram [--cpu->r.sp] = (byte) (cpu->r.pc >> 8); + this->mem.ram [--cpu->r.sp] = (byte) (cpu->r.pc); + + // fixed interrupt + cpu->r.pc = 0x38; + Z80_adjust_time( cpu, 12 ); + + if ( cpu->r.im == 2 ) + { + // vectored interrupt + addr_t addr = cpu->r.i * 0x100 + 0xFF; + cpu->r.pc = this->mem.ram [(addr + 1) & 0xFFFF] * 0x100 + this->mem.ram [addr]; + Z80_adjust_time( cpu, 6 ); + } + } + } + } + + // End time frame + *end = Z80_time( cpu ); + this->next_play -= *end; + check( this->next_play >= 0 ); + Z80_adjust_time( cpu, -*end ); + Ay_apu_end_frame( &this->apu, *end ); + return 0; +} + +// Emulation + +void cpu_out_( struct Ay_Emu *this, cpu_time_t time, addr_t addr, int data ) +{ + // Spectrum + if ( !this->cpc_mode ) + { + switch ( addr & 0xFEFF ) + { + case 0xFEFD: + this->spectrum_mode = true; + Ay_apu_write_addr( &this->apu, data ); + return; + + case 0xBEFD: + this->spectrum_mode = true; + Ay_apu_write_data( &this->apu, time, data ); + return; + } + } + + // CPC + if ( !this->spectrum_mode ) + { + switch ( addr >> 8 ) + { + case 0xF6: + switch ( data & 0xC0 ) + { + case 0xC0: + Ay_apu_write_addr( &this->apu, this->cpc_latch ); + goto enable_cpc; + + case 0x80: + Ay_apu_write_data( &this->apu, time, this->cpc_latch ); + goto enable_cpc; + } + break; + + case 0xF4: + this->cpc_latch = data; + goto enable_cpc; + } + } + + /* dprintf( "Unmapped OUT: $%04X <- $%02X\n", addr, data ); */ + return; + +enable_cpc: + if ( !this->cpc_mode ) + { + this->cpc_mode = true; + disable_beeper( this ); + + change_clock_rate( this, cpc_clock ); + Sound_set_tempo( this, this->tempo ); + } +} + +blargg_err_t Ay_set_sample_rate( struct Ay_Emu *this, int rate ) +{ + require( !this->sample_rate ); // sample rate can't be changed once set + Buffer_init( &this->stereo_buf ); + RETURN_ERR( Buffer_set_sample_rate( &this->stereo_buf, rate, 1000 / 20 ) ); + + // Set buffer bass + Buffer_bass_freq( &this->stereo_buf, 160 ); + + this->sample_rate = rate; + RETURN_ERR( track_init( &this->track_filter, this ) ); + this->tfilter.max_silence = 6 * stereo * this->sample_rate; + return 0; +} + +void Sound_mute_voice( struct Ay_Emu *this, int index, bool mute ) +{ + require( (unsigned) index < (unsigned) this->voice_count ); + int bit = 1 << index; + int mask = this->mute_mask_ | bit; + if ( !mute ) + mask ^= bit; + Sound_mute_voices( this, mask ); +} + +void Sound_mute_voices( struct Ay_Emu *this, int mask ) +{ + require( this->sample_rate ); // sample rate must be set first + this->mute_mask_ = mask; + + int i; + for ( i = this->voice_count; i--; ) + { + if ( mask & (1 << i) ) + { + set_voice( this, i, 0 ); + } + else + { + struct channel_t ch = Buffer_channel( &this->stereo_buf, i ); + assert( (ch.center && ch.left && ch.right) || + (!ch.center && !ch.left && !ch.right) ); // all or nothing + set_voice( this, i, ch.center ); + } + } +} + +void Sound_set_tempo( struct Ay_Emu *this, int t ) +{ + require( this->sample_rate ); // sample rate must be set first + int const min = (int)(FP_ONE_TEMPO*0.02); + int const max = (int)(FP_ONE_TEMPO*4.00); + if ( t < min ) t = min; + if ( t > max ) t = max; + this->tempo = t; + + int p = spectrum_period; + if ( this->clock_rate_ != spectrum_clock ) + p = this->clock_rate_ / 50; + + this->play_period = (blip_time_t) ((p * FP_ONE_TEMPO) / t); +} + +blargg_err_t Ay_start_track( struct Ay_Emu *this, int track ) +{ + clear_track_vars( this ); + + // Remap track if playlist available + if ( this->m3u.size > 0 ) { + struct entry_t* e = &this->m3u.entries[track]; + track = e->track; + } + + this->current_track = track; + Buffer_clear( &this->stereo_buf ); + + byte* const mem = this->mem.ram; + + memset( mem + 0x0000, 0xC9, 0x100 ); // fill RST vectors with RET + memset( mem + 0x0100, 0xFF, 0x4000 - 0x100 ); + memset( mem + ram_addr, 0x00, mem_size - ram_addr ); + + // locate data blocks + byte const* const data = get_data( &this->file, this->file.tracks + track * 4 + 2, 14 ); + if ( !data ) + return "file data missing"; + + byte const* const more_data = get_data( &this->file, data + 10, 6 ); + if ( !more_data ) + return "file data missing"; + + byte const* blocks = get_data( &this->file, data + 12, 8 ); + if ( !blocks ) + return "file data missing"; + + // initial addresses + unsigned addr = get_be16( blocks ); + if ( !addr ) + return "file data missing"; + + unsigned init = get_be16( more_data + 2 ); + if ( !init ) + init = addr; + + // copy blocks into memory + do + { + blocks += 2; + unsigned len = get_be16( blocks ); blocks += 2; + if ( addr + len > mem_size ) + { + /* warning( "Bad data block size" ); */ + len = mem_size - addr; + } + check( len ); + byte const* in = get_data( &this->file, blocks, 0 ); blocks += 2; + if ( len > (unsigned) (this->file.end - in) ) + { + /* warning( "File data missing" ); */ + len = this->file.end - in; + } + + memcpy( mem + addr, in, len ); + + if ( this->file.end - blocks < 8 ) + { + /* warning( "File data missing" ); */ + break; + } + } + while ( (addr = get_be16( blocks )) != 0 ); + + // copy and configure driver + static byte const passive [] = { + 0xF3, // DI + 0xCD, 0, 0, // CALL init + 0xED, 0x5E, // LOOP: IM 2 + 0xFB, // EI + 0x76, // HALT + 0x18, 0xFA // JR LOOP + }; + static byte const active [] = { + 0xF3, // DI + 0xCD, 0, 0, // CALL init + 0xED, 0x56, // LOOP: IM 1 + 0xFB, // EI + 0x76, // HALT + 0xCD, 0, 0, // CALL play + 0x18, 0xF7 // JR LOOP + }; + memcpy( mem, passive, sizeof passive ); + int const play_addr = get_be16( more_data + 4 ); + if ( play_addr ) + { + memcpy( mem, active, sizeof active ); + mem [ 9] = play_addr; + mem [10] = play_addr >> 8; + } + mem [2] = init; + mem [3] = init >> 8; + + mem [0x38] = 0xFB; // Put EI at interrupt vector (followed by RET) + + // start at spectrum speed + change_clock_rate( this, spectrum_clock ); + Sound_set_tempo( this, this->tempo ); + + struct registers_t r; + memset( &r, 0, sizeof(struct registers_t) ); + + r.sp = get_be16( more_data ); + r.b.a = r.b.b = r.b.d = r.b.h = data [8]; + r.b.flags = r.b.c = r.b.e = r.b.l = data [9]; + r.alt.w = r.w; + r.ix = r.iy = r.w.hl; + + memset( this->mem.padding1, 0xFF, sizeof this->mem.padding1 ); + + int const mirrored = 0x80; // this much is mirrored after end of memory + memset( this->mem.ram + mem_size + mirrored, 0xFF, sizeof this->mem.ram - mem_size - mirrored ); + memcpy( this->mem.ram + mem_size, this->mem.ram, mirrored ); // some code wraps around (ugh) + + Z80_reset( &this->cpu, this->mem.padding1, this->mem.padding1 ); + Z80_map_mem( &this->cpu, 0, mem_size, this->mem.ram, this->mem.ram ); + this->cpu.r = r; + + this->beeper_delta = (int) ((ay_amp_range*4)/5); + this->last_beeper = 0; + this->next_play = this->play_period; + this->spectrum_mode = false; + this->cpc_mode = false; + this->cpc_latch = 0; + set_beeper_output( this, this->beeper_output ); + Ay_apu_reset( &this->apu ); + + // a few tunes rely on channels having tone enabled at the beginning + Ay_apu_write_addr( &this->apu, 7 ); + Ay_apu_write_data( &this->apu, 0, 0x38 ); + + // convert filter times to samples + struct setup_t s = this->tfilter; + s.max_initial *= this->sample_rate * stereo; + #ifdef GME_DISABLE_SILENCE_LOOKAHEAD + s.lookahead = 1; + #endif + track_setup( &this->track_filter, &s ); + + return track_start( &this->track_filter ); +} + +// Tell/Seek + +static int msec_to_samples( int msec, int sample_rate ) +{ + int sec = msec / 1000; + msec -= sec * 1000; + return (sec * sample_rate + msec * sample_rate / 1000) * stereo; +} + +int Track_tell( struct Ay_Emu *this ) +{ + int rate = this->sample_rate * stereo; + int sec = track_sample_count( &this->track_filter ) / rate; + return sec * 1000 + (track_sample_count( &this->track_filter ) - sec * rate) * 1000 / rate; +} + +blargg_err_t Track_seek( struct Ay_Emu *this, int msec ) +{ + int time = msec_to_samples( msec, this->sample_rate ); + if ( time < track_sample_count( &this->track_filter ) ) + RETURN_ERR( Ay_start_track( this, this->current_track ) ); + return Track_skip( this, time - track_sample_count( &this->track_filter ) ); +} + +blargg_err_t skip_( void *emu, int count ) +{ + struct Ay_Emu* this = (struct Ay_Emu*) emu; + + // for long skip, mute sound + const int threshold = 32768; + if ( count > threshold ) + { + int saved_mute = this->mute_mask_; + Sound_mute_voices( this, ~0 ); + + int n = count - threshold/2; + n &= ~(2048-1); // round to multiple of 2048 + count -= n; + RETURN_ERR( skippy_( &this->track_filter, n ) ); + + Sound_mute_voices( this, saved_mute ); + } + + return skippy_( &this->track_filter, count ); +} + +blargg_err_t Track_skip( struct Ay_Emu *this, int count ) +{ + require( this->current_track >= 0 ); // start_track() must have been called already + return track_skip( &this->track_filter, count ); +} + +int Track_get_length( struct Ay_Emu* this, int n ) +{ + int length = 0; + + byte const* track_info = get_data( &this->file, this->file.tracks + n * 4 + 2, 6 ); + if ( track_info ) + length = get_be16( track_info + 4 ) * (1000 / 50); // frames to msec + + if ( (this->m3u.size > 0) && (n < this->m3u.size) ) { + struct entry_t* entry = &this->m3u.entries [n]; + length = entry->length; + } + + if ( length <= 0 ) + length = 120 * 1000; /* 2 minutes */ + + return length; +} + +void Track_set_fade( struct Ay_Emu *this, int start_msec, int length_msec ) +{ + track_set_fade( &this->track_filter, msec_to_samples( start_msec, this->sample_rate ), + length_msec * this->sample_rate / (1000 / stereo) ); +} + +blargg_err_t Ay_play( struct Ay_Emu *this, int out_count, sample_t* out ) +{ + require( this->current_track >= 0 ); + require( out_count % stereo == 0 ); + return track_play( &this->track_filter, out_count, out ); +} + +blargg_err_t play_( void *emu, int count, sample_t* out ) +{ + struct Ay_Emu* this = (struct Ay_Emu*) emu; + + int remain = count; + while ( remain ) + { + Buffer_disable_immediate_removal( &this->stereo_buf ); + remain -= Buffer_read_samples( &this->stereo_buf, &out [count - remain], remain ); + if ( remain ) + { + if ( this->buf_changed_count != Buffer_channels_changed_count( &this->stereo_buf ) ) + { + this->buf_changed_count = Buffer_channels_changed_count( &this->stereo_buf ); + + // Remute voices + Sound_mute_voices( this, this->mute_mask_ ); + } + int msec = Buffer_length( &this->stereo_buf ); + blip_time_t clocks_emulated = msec * this->clock_rate_ / 1000 - 100; + RETURN_ERR( run_clocks( this, &clocks_emulated, msec ) ); + assert( clocks_emulated ); + Buffer_end_frame( &this->stereo_buf, clocks_emulated ); + } + } + return 0; +} diff --git a/apps/codecs/libgme/blargg_config.h b/apps/codecs/libgme/blargg_config.h index 6490c15cfb..398913d1fe 100644 --- a/apps/codecs/libgme/blargg_config.h +++ b/apps/codecs/libgme/blargg_config.h @@ -1,42 +1,42 @@ -// Library configuration. Modify this file as necessary. - -#ifndef BLARGG_CONFIG_H -#define BLARGG_CONFIG_H - -// Uncomment to enable platform-specific optimizations -//#define BLARGG_NONPORTABLE 1 - -// Uncomment if automatic byte-order determination doesn't work -#ifdef ROCKBOX_BIG_ENDIAN - #define BLARGG_BIG_ENDIAN 1 -#endif - -// Uncomment if you get errors in the bool section of blargg_common.h -#define BLARGG_COMPILER_HAS_BOOL 1 - -// Uncomment to use fast gb apu implementation -// #define GB_APU_FAST 1 - -// Uncomment to remove agb emulation support -// #define GB_APU_NO_AGB 1 - -// Uncomment to emulate only nes apu -// #define NSF_EMU_APU_ONLY 1 - -// Uncomment to remove vrc7 apu support -// #define NSF_EMU_NO_VRC7 1 - -// Uncomment to remove fmopl apu support -// #define KSS_EMU_NO_FMOPL 1 - -// To handle undefined reference to assert -#define NDEBUG 1 - -// Use standard config.h if present -#define HAVE_CONFIG_H 1 - -#ifdef HAVE_CONFIG_H - #include "config.h" -#endif - -#endif +// Library configuration. Modify this file as necessary. + +#ifndef BLARGG_CONFIG_H +#define BLARGG_CONFIG_H + +// Uncomment to enable platform-specific optimizations +//#define BLARGG_NONPORTABLE 1 + +// Uncomment if automatic byte-order determination doesn't work +#ifdef ROCKBOX_BIG_ENDIAN + #define BLARGG_BIG_ENDIAN 1 +#endif + +// Uncomment if you get errors in the bool section of blargg_common.h +#define BLARGG_COMPILER_HAS_BOOL 1 + +// Uncomment to use fast gb apu implementation +// #define GB_APU_FAST 1 + +// Uncomment to remove agb emulation support +// #define GB_APU_NO_AGB 1 + +// Uncomment to emulate only nes apu +// #define NSF_EMU_APU_ONLY 1 + +// Uncomment to remove vrc7 apu support +// #define NSF_EMU_NO_VRC7 1 + +// Uncomment to remove fmopl apu support +// #define KSS_EMU_NO_FMOPL 1 + +// To handle undefined reference to assert +#define NDEBUG 1 + +// Use standard config.h if present +#define HAVE_CONFIG_H 1 + +#ifdef HAVE_CONFIG_H + #include "config.h" +#endif + +#endif diff --git a/apps/codecs/libgme/emu2413.c b/apps/codecs/libgme/emu2413.c index a4637ce15b..01075821cb 100644 --- a/apps/codecs/libgme/emu2413.c +++ b/apps/codecs/libgme/emu2413.c @@ -1,1981 +1,1981 @@ -/*********************************************************************************** - - emu2413.c -- YM2413 emulator written by Mitsutaka Okazaki 2001 - - 2001 01-08 : Version 0.10 -- 1st version. - 2001 01-15 : Version 0.20 -- semi-public version. - 2001 01-16 : Version 0.30 -- 1st public version. - 2001 01-17 : Version 0.31 -- Fixed bassdrum problem. - : Version 0.32 -- LPF implemented. - 2001 01-18 : Version 0.33 -- Fixed the drum problem, refine the mix-down method. - -- Fixed the LFO bug. - 2001 01-24 : Version 0.35 -- Fixed the drum problem, - support undocumented EG behavior. - 2001 02-02 : Version 0.38 -- Improved the performance. - Fixed the hi-hat and cymbal model. - Fixed the default percussive datas. - Noise reduction. - Fixed the feedback problem. - 2001 03-03 : Version 0.39 -- Fixed some drum bugs. - Improved the performance. - 2001 03-04 : Version 0.40 -- Improved the feedback. - Change the default table size. - Clock and Rate can be changed during play. - 2001 06-24 : Version 0.50 -- Improved the hi-hat and the cymbal tone. - Added VRC7 patch (OPLL_reset_patch is changed). - Fixed OPLL_reset() bug. - Added OPLL_setMask, OPLL_getMask and OPLL_toggleMask. - Added OPLL_writeIO. - 2001 09-28 : Version 0.51 -- Removed the noise table. - 2002 01-28 : Version 0.52 -- Added Stereo mode. - 2002 02-07 : Version 0.53 -- Fixed some drum bugs. - 2002 02-20 : Version 0.54 -- Added the best quality mode. - 2002 03-02 : Version 0.55 -- Removed OPLL_init & OPLL_close. - 2002 05-30 : Version 0.60 -- Fixed HH&CYM generator and all voice datas. - 2004 04-10 : Version 0.61 -- Added YMF281B tone (defined by Chabin). - - 2011 03-22 : --------------- Modified by gama to use precalculated tables. - - References: - fmopl.c -- 1999,2000 written by Tatsuyuki Satoh (MAME development). - fmopl.c(fixed) -- (C) 2002 Jarek Burczynski. - s_opl.c -- 2001 written by Mamiya (NEZplug development). - fmgen.cpp -- 1999,2000 written by cisc. - fmpac.ill -- 2000 created by NARUTO. - MSX-Datapack - YMU757 data sheet - YM2143 data sheet - -**************************************************************************************/ -#include -#include -#include -#include -#include "emu2413.h" - -#include "emutables.h" -#if !defined(ROCKBOX) - #define EMU2413_CALCUL_TABLES -#else - #define EMU2413_COMPACTION - #include "emutables.h" -#endif - -#if defined(EMU2413_COMPACTION) && !defined(ROCKBOX) -#define OPLL_TONE_NUM 1 -static unsigned char default_inst[OPLL_TONE_NUM][(16 + 3) * 16] = { - { -#include "2413tone.h" - } -}; -#else -#define OPLL_TONE_NUM 3 -static unsigned char default_inst[OPLL_TONE_NUM][(16 + 3) * 16] = { - { -#include "2413tone.h" - }, - { -#include "vrc7tone.h" - }, - { -#include "281btone.h" - } -}; -#endif - -/* Size of Sintable ( 8 -- 18 can be used. 9 recommended.) */ -#define PG_BITS 9 -#define PG_WIDTH (1<>(b)) - -/* Leave the lower b bit(s). */ -#define LOWBITS(c,b) ((c)&((1<<(b))-1)) - -/* Expand x which is s bits to d bits. */ -#define EXPAND_BITS(x,s,d) ((x)<<((d)-(s))) - -/* Expand x which is s bits to d bits and fill expanded bits '1' */ -#define EXPAND_BITS_X(x,s,d) (((x)<<((d)-(s)))|((1<<((d)-(s)))-1)) - -/* Adjust envelope speed which depends on sampling rate. */ -#define RATE_ADJUST(x) (rate==49716?(e_uint32)x:(e_uint32)(((long long)(x)*clk/rate+36)/72)) - -#define MOD(o,x) (&(o)->slot[(x)<<1]) -#define CAR(o,x) (&(o)->slot[((x)<<1)|1]) - -#define BIT(s,b) (((s)>>(b))&1) - -/* Input clock */ -static e_uint32 clk = 844451141; -/* Sampling rate */ -static e_uint32 rate = 3354932; - -/* WaveTable for each envelope amp */ -static e_uint16 fullsintable[PG_WIDTH]; -static e_uint16 halfsintable[PG_WIDTH]; - -static e_uint16 *waveform[2] = { fullsintable, halfsintable }; - -/* LFO Table */ -#ifdef EMU2413_CALCUL_TABLES - static e_int32 pmtable[PM_PG_WIDTH]; - static e_int32 amtable[AM_PG_WIDTH]; - #define PMTABLE(x) pmtable[x] - #define AMTABLE(x) amtable[x] -#else - #define PMTABLE(x) (e_int32)pm_coeff[x] - #if (PM_PG_WIDTH != 256) - #error PM_PG_WIDTH must be set to 256 if EMU2413_CALCUL_TABLES is not defined - #endif - #define AMTABLE(x) (e_int32)am_coeff[x] - #if (AM_PG_WIDTH != 256) - #error AM_PG_WIDTH must be set to 256 if EMU2413_CALCUL_TABLES is not defined - #endif -#endif - -/* Phase delta for LFO */ -static e_uint32 pm_dphase; -static e_uint32 am_dphase; - -/* dB to Liner table */ -static e_int16 DB2LIN_TABLE[(DB_MUTE + DB_MUTE) * 2]; - -/* Liner to Log curve conversion table (for Attack rate). */ -#ifdef EMU2413_CALCUL_TABLES - static e_uint16 ar_adjust_table[1 << EG_BITS]; - #define AR_ADJUST_TABLE(x) ar_adjust_table[x] -#else - #define AR_ADJUST_TABLE(x) ar_adjust_coeff[x] - #if (EG_BITS != 7) - #error EG_BITS must be set to 7 if EMU2413_CALCUL_TABLES is not defined - #endif -#endif - -/* Empty voice data */ -static OPLL_PATCH null_patch = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - -/* Basic voice Data */ -static OPLL_PATCH default_patch[OPLL_TONE_NUM][(16 + 3) * 2]; - -/* Definition of envelope mode */ -enum OPLL_EG_STATE -{ READY, ATTACK, DECAY, SUSHOLD, SUSTINE, RELEASE, SETTLE, FINISH }; - -/* Phase incr table for Attack */ -static e_uint32 dphaseARTable[16][16]; -/* Phase incr table for Decay and Release */ -static e_uint32 dphaseDRTable[16][16]; - -/* KSL + TL Table */ -e_uint8 tllTable[16][8][1 << TL_BITS][4]; -static e_int32 rksTable[2][8][2]; - -/* We may not have too much SRAM in rockbox */ -#if !defined(ROCKBOX) -/* Phase incr table for PG */ -static e_uint32 dphaseTable[512][8][16]; -#endif - -/*************************************************** - - Create tables - -****************************************************/ -#ifdef EMU2413_CALCUL_TABLES -INLINE static e_int32 -Min (e_int32 i, e_int32 j) -{ - if (i < j) - return i; - else - return j; -} - -/* Table for AR to LogCurve. */ -static void -makeAdjustTable (void) -{ - e_int32 i; - - ar_adjust_table[0] = (1 << EG_BITS) - 1; - for (i = 1; i < (1<= DB_MUTE) DB2LIN_TABLE[i] = 0; - DB2LIN_TABLE[i + DB_MUTE + DB_MUTE] = (e_int16) (-DB2LIN_TABLE[i]); - } -} - -#ifdef EMU2413_CALCUL_TABLES -/* Liner(+0.0 - +1.0) to dB((1<> (20 - DP_BITS)); -} -#endif - -static void -makeTllTable (void) -{ -/* Multiplication owith 8 to have an integer result. This allows to remove floating point operation. */ -#define dB2(x) (int)((x)*2*8) - - static int kltable[16] = { - dB2 ( 0.000), dB2 ( 9.000), dB2 (12.000), dB2 (13.875), dB2 (15.000), dB2 (16.125), dB2 (16.875), dB2 (17.625), - dB2 (18.000), dB2 (18.750), dB2 (19.125), dB2 (19.500), dB2 (19.875), dB2 (20.250), dB2 (20.625), dB2 (21.000) - }; - - e_int32 tmp; - e_int32 fnum, block, TL, KL; - - for (fnum = 0; fnum < 16; fnum++) - for (block = 0; block < 8; block++) - for (TL = 0; TL < 64; TL++) - for (KL = 0; KL < 4; KL++) - { - if (KL == 0) - { - tllTable[fnum][block][TL][KL] = TL2EG (TL); - } - else - { - tmp = (e_int32) ((kltable[fnum] - dB2 (3.000) * (7 - block))/8); - if (tmp <= 0) - tllTable[fnum][block][TL][KL] = TL2EG (TL); - else - /* tllTable[fnum][block][TL][KL] = (e_uint32) ((tmp >> (3 - KL)) / EG_STEP) + TL2EG (TL); */ - tllTable[fnum][block][TL][KL] = (e_uint32) ((tmp << KL) / (int)(EG_STEP*8)) + TL2EG (TL); - } - } -} - -#ifdef USE_SPEC_ENV_SPEED -static double attacktime[16][4] = { - {0, 0, 0, 0}, - {1730.15, 1400.60, 1153.43, 988.66}, - {865.08, 700.30, 576.72, 494.33}, - {432.54, 350.15, 288.36, 247.16}, - {216.27, 175.07, 144.18, 123.58}, - {108.13, 87.54, 72.09, 61.79}, - {54.07, 43.77, 36.04, 30.90}, - {27.03, 21.88, 18.02, 15.45}, - {13.52, 10.94, 9.01, 7.72}, - {6.76, 5.47, 4.51, 3.86}, - {3.38, 2.74, 2.25, 1.93}, - {1.69, 1.37, 1.13, 0.97}, - {0.84, 0.70, 0.60, 0.54}, - {0.50, 0.42, 0.34, 0.30}, - {0.28, 0.22, 0.18, 0.14}, - {0.00, 0.00, 0.00, 0.00} -}; - -static double decaytime[16][4] = { - {0, 0, 0, 0}, - {20926.60, 16807.20, 14006.00, 12028.60}, - {10463.30, 8403.58, 7002.98, 6014.32}, - {5231.64, 4201.79, 3501.49, 3007.16}, - {2615.82, 2100.89, 1750.75, 1503.58}, - {1307.91, 1050.45, 875.37, 751.79}, - {653.95, 525.22, 437.69, 375.90}, - {326.98, 262.61, 218.84, 187.95}, - {163.49, 131.31, 109.42, 93.97}, - {81.74, 65.65, 54.71, 46.99}, - {40.87, 32.83, 27.36, 23.49}, - {20.44, 16.41, 13.68, 11.75}, - {10.22, 8.21, 6.84, 5.87}, - {5.11, 4.10, 3.42, 2.94}, - {2.55, 2.05, 1.71, 1.47}, - {1.27, 1.27, 1.27, 1.27} -}; -#endif - -/* Rate Table for Attack */ -static void -makeDphaseARTable (void) -{ - e_int32 AR, Rks, RM, RL; - -#ifdef USE_SPEC_ENV_SPEED - e_uint32 attacktable[16][4]; - - for (RM = 0; RM < 16; RM++) - for (RL = 0; RL < 4; RL++) - { - if (RM == 0) - attacktable[RM][RL] = 0; - else if (RM == 15) - attacktable[RM][RL] = EG_DP_WIDTH; - else - attacktable[RM][RL] = (e_uint32) ((double) (1 << EG_DP_BITS) / (attacktime[RM][RL] * 3579545 / 72000)); - - } -#endif - - for (AR = 0; AR < 16; AR++) - for (Rks = 0; Rks < 16; Rks++) - { - RM = AR + (Rks >> 2); - RL = Rks & 3; - if (RM > 15) - RM = 15; - switch (AR) - { - case 0: - dphaseARTable[AR][Rks] = 0; - break; - case 15: - dphaseARTable[AR][Rks] = 0;/*EG_DP_WIDTH;*/ - break; - default: -#ifdef USE_SPEC_ENV_SPEED - dphaseARTable[AR][Rks] = RATE_ADJUST (attacktable[RM][RL]); -#else - dphaseARTable[AR][Rks] = RATE_ADJUST ((3 * (RL + 4) << (RM + 1))); -#endif - break; - } - } -} - -/* Rate Table for Decay and Release */ -static void -makeDphaseDRTable (void) -{ - e_int32 DR, Rks, RM, RL; - -#ifdef USE_SPEC_ENV_SPEED - e_uint32 decaytable[16][4]; - - for (RM = 0; RM < 16; RM++) - for (RL = 0; RL < 4; RL++) - if (RM == 0) - decaytable[RM][RL] = 0; - else - decaytable[RM][RL] = (e_uint32) ((double) (1 << EG_DP_BITS) / (decaytime[RM][RL] * 3579545 / 72000)); -#endif - - for (DR = 0; DR < 16; DR++) - for (Rks = 0; Rks < 16; Rks++) - { - RM = DR + (Rks >> 2); - RL = Rks & 3; - if (RM > 15) - RM = 15; - switch (DR) - { - case 0: - dphaseDRTable[DR][Rks] = 0; - break; - default: -#ifdef USE_SPEC_ENV_SPEED - dphaseDRTable[DR][Rks] = RATE_ADJUST (decaytable[RM][RL]); -#else - dphaseDRTable[DR][Rks] = RATE_ADJUST ((RL + 4) << (RM - 1)); -#endif - break; - } - } -} - -static void -makeRksTable (void) -{ - - e_int32 fnum8, block, KR; - - for (fnum8 = 0; fnum8 < 2; fnum8++) - for (block = 0; block < 8; block++) - for (KR = 0; KR < 2; KR++) - { - if (KR != 0) - rksTable[fnum8][block][KR] = (block << 1) + fnum8; - else - rksTable[fnum8][block][KR] = block >> 1; - } -} - -void -OPLL_dump2patch (const e_uint8 * dump, OPLL_PATCH * patch) -{ - patch[0].AM = (dump[0] >> 7) & 1; - patch[1].AM = (dump[1] >> 7) & 1; - patch[0].PM = (dump[0] >> 6) & 1; - patch[1].PM = (dump[1] >> 6) & 1; - patch[0].EG = (dump[0] >> 5) & 1; - patch[1].EG = (dump[1] >> 5) & 1; - patch[0].KR = (dump[0] >> 4) & 1; - patch[1].KR = (dump[1] >> 4) & 1; - patch[0].ML = (dump[0]) & 15; - patch[1].ML = (dump[1]) & 15; - patch[0].KL = (dump[2] >> 6) & 3; - patch[1].KL = (dump[3] >> 6) & 3; - patch[0].TL = (dump[2]) & 63; - patch[0].FB = (dump[3]) & 7; - patch[0].WF = (dump[3] >> 3) & 1; - patch[1].WF = (dump[3] >> 4) & 1; - patch[0].AR = (dump[4] >> 4) & 15; - patch[1].AR = (dump[5] >> 4) & 15; - patch[0].DR = (dump[4]) & 15; - patch[1].DR = (dump[5]) & 15; - patch[0].SL = (dump[6] >> 4) & 15; - patch[1].SL = (dump[7] >> 4) & 15; - patch[0].RR = (dump[6]) & 15; - patch[1].RR = (dump[7]) & 15; -} - -void -OPLL_getDefaultPatch (e_int32 type, e_int32 num, OPLL_PATCH * patch) -{ - OPLL_dump2patch (default_inst[type] + num * 16, patch); -} - -static void -makeDefaultPatch ( void ) -{ - e_int32 i, j; - - for (i = 0; i < OPLL_TONE_NUM; i++) - for (j = 0; j < 19; j++) - OPLL_getDefaultPatch (i, j, &default_patch[i][j * 2]); - -} - -void -OPLL_setPatch (OPLL * opll, const e_uint8 * dump) -{ - OPLL_PATCH patch[2]; - int i; - - for (i = 0; i < 19; i++) - { - OPLL_dump2patch (dump + i * 16, patch); - memcpy (&opll->patch[i*2+0], &patch[0], sizeof (OPLL_PATCH)); - memcpy (&opll->patch[i*2+1], &patch[1], sizeof (OPLL_PATCH)); - } -} - -void -OPLL_patch2dump (const OPLL_PATCH * patch, e_uint8 * dump) -{ - dump[0] = (e_uint8) ((patch[0].AM << 7) + (patch[0].PM << 6) + (patch[0].EG << 5) + (patch[0].KR << 4) + patch[0].ML); - dump[1] = (e_uint8) ((patch[1].AM << 7) + (patch[1].PM << 6) + (patch[1].EG << 5) + (patch[1].KR << 4) + patch[1].ML); - dump[2] = (e_uint8) ((patch[0].KL << 6) + patch[0].TL); - dump[3] = (e_uint8) ((patch[1].KL << 6) + (patch[1].WF << 4) + (patch[0].WF << 3) + patch[0].FB); - dump[4] = (e_uint8) ((patch[0].AR << 4) + patch[0].DR); - dump[5] = (e_uint8) ((patch[1].AR << 4) + patch[1].DR); - dump[6] = (e_uint8) ((patch[0].SL << 4) + patch[0].RR); - dump[7] = (e_uint8) ((patch[1].SL << 4) + patch[1].RR); - dump[8] = 0; - dump[9] = 0; - dump[10] = 0; - dump[11] = 0; - dump[12] = 0; - dump[13] = 0; - dump[14] = 0; - dump[15] = 0; -} - -/************************************************************ - - Calc Parameters - -************************************************************/ - -INLINE static e_uint32 -calc_eg_dphase (OPLL_SLOT * slot) -{ - - switch (slot->eg_mode) - { - case ATTACK: - return dphaseARTable[slot->patch->AR][slot->rks]; - - case DECAY: - return dphaseDRTable[slot->patch->DR][slot->rks]; - - case SUSHOLD: - return 0; - - case SUSTINE: - return dphaseDRTable[slot->patch->RR][slot->rks]; - - case RELEASE: - if (slot->sustine) - return dphaseDRTable[5][slot->rks]; - else if (slot->patch->EG) - return dphaseDRTable[slot->patch->RR][slot->rks]; - else - return dphaseDRTable[7][slot->rks]; - - case SETTLE: - return dphaseDRTable[15][0]; - - case FINISH: - return 0; - - default: - return 0; - } -} - -/************************************************************* - - OPLL internal interfaces - -*************************************************************/ -#define SLOT_BD1 12 -#define SLOT_BD2 13 -#define SLOT_HH 14 -#define SLOT_SD 15 -#define SLOT_TOM 16 -#define SLOT_CYM 17 - -/* We will set this dinamically, but not sure if this affects playback */ -#if defined(ROCKBOX) -INLINE static void -UPDATE_PG(OPLL_SLOT * slot) -{ - static const e_uint32 mltable[16] = - { 1, 1 * 2, 2 * 2, 3 * 2, 4 * 2, 5 * 2, 6 * 2, 7 * 2, 8 * 2, 9 * 2, 10 * 2, 10 * 2, 12 * 2, 12 * 2, 15 * 2, 15 * 2 }; - - slot->dphase = RATE_ADJUST (((slot->fnum * mltable[slot->patch->ML]) << slot->block) >> (20 - DP_BITS)); -} -#else -#define UPDATE_PG(S) (S)->dphase = dphaseTable[(S)->fnum][(S)->block][(S)->patch->ML] -#endif - -#define UPDATE_TLL(S)\ -(((S)->type==0)?\ -((S)->tll = tllTable[((S)->fnum)>>5][(S)->block][(S)->patch->TL][(S)->patch->KL]):\ -((S)->tll = tllTable[((S)->fnum)>>5][(S)->block][(S)->volume][(S)->patch->KL])) -#define UPDATE_RKS(S) (S)->rks = rksTable[((S)->fnum)>>8][(S)->block][(S)->patch->KR] -#define UPDATE_WF(S) (S)->sintbl = waveform[(S)->patch->WF] -#define UPDATE_EG(S) (S)->eg_dphase = calc_eg_dphase(S) -#define UPDATE_ALL(S)\ - UPDATE_PG(S);\ - UPDATE_TLL(S);\ - UPDATE_RKS(S);\ - UPDATE_WF(S); \ - UPDATE_EG(S) /* EG should be updated last. */ - - -/* Slot key on */ -INLINE static void -slotOn (OPLL_SLOT * slot) -{ - slot->eg_mode = ATTACK; - slot->eg_phase = 0; - slot->phase = 0; - UPDATE_EG(slot); -} - -/* Slot key on without reseting the phase */ -INLINE static void -slotOn2 (OPLL_SLOT * slot) -{ - slot->eg_mode = ATTACK; - slot->eg_phase = 0; - UPDATE_EG(slot); -} - -/* Slot key off */ -INLINE static void -slotOff (OPLL_SLOT * slot) -{ - if (slot->eg_mode == ATTACK) - slot->eg_phase = EXPAND_BITS (AR_ADJUST_TABLE(HIGHBITS (slot->eg_phase, EG_DP_BITS - EG_BITS)), EG_BITS, EG_DP_BITS); - slot->eg_mode = RELEASE; - UPDATE_EG(slot); -} - -/* Channel key on */ -INLINE static void -keyOn (OPLL * opll, e_int32 i) -{ - if (!opll->slot_on_flag[i * 2]) - slotOn (MOD(opll,i)); - if (!opll->slot_on_flag[i * 2 + 1]) - slotOn (CAR(opll,i)); - opll->key_status[i] = 1; -} - -/* Channel key off */ -INLINE static void -keyOff (OPLL * opll, e_int32 i) -{ - if (opll->slot_on_flag[i * 2 + 1]) - slotOff (CAR(opll,i)); - opll->key_status[i] = 0; -} - -INLINE static void -keyOn_BD (OPLL * opll) -{ - keyOn (opll, 6); -} -INLINE static void -keyOn_SD (OPLL * opll) -{ - if (!opll->slot_on_flag[SLOT_SD]) - slotOn (CAR(opll,7)); -} -INLINE static void -keyOn_TOM (OPLL * opll) -{ - if (!opll->slot_on_flag[SLOT_TOM]) - slotOn (MOD(opll,8)); -} -INLINE static void -keyOn_HH (OPLL * opll) -{ - if (!opll->slot_on_flag[SLOT_HH]) - slotOn2 (MOD(opll,7)); -} -INLINE static void -keyOn_CYM (OPLL * opll) -{ - if (!opll->slot_on_flag[SLOT_CYM]) - slotOn2 (CAR(opll,8)); -} - -/* Drum key off */ -INLINE static void -keyOff_BD (OPLL * opll) -{ - keyOff (opll, 6); -} -INLINE static void -keyOff_SD (OPLL * opll) -{ - if (opll->slot_on_flag[SLOT_SD]) - slotOff (CAR(opll,7)); -} -INLINE static void -keyOff_TOM (OPLL * opll) -{ - if (opll->slot_on_flag[SLOT_TOM]) - slotOff (MOD(opll,8)); -} -INLINE static void -keyOff_HH (OPLL * opll) -{ - if (opll->slot_on_flag[SLOT_HH]) - slotOff (MOD(opll,7)); -} -INLINE static void -keyOff_CYM (OPLL * opll) -{ - if (opll->slot_on_flag[SLOT_CYM]) - slotOff (CAR(opll,8)); -} - -/* Change a voice */ -INLINE static void -setPatch (OPLL * opll, e_int32 i, e_int32 num) -{ - opll->patch_number[i] = num; - MOD(opll,i)->patch = &opll->patch[num * 2 + 0]; - CAR(opll,i)->patch = &opll->patch[num * 2 + 1]; -} - -/* Change a rhythm voice */ -INLINE static void -setSlotPatch (OPLL_SLOT * slot, OPLL_PATCH * patch) -{ - slot->patch = patch; -} - -/* Set sustine parameter */ -INLINE static void -setSustine (OPLL * opll, e_int32 c, e_int32 sustine) -{ - CAR(opll,c)->sustine = sustine; - if (MOD(opll,c)->type) - MOD(opll,c)->sustine = sustine; -} - -/* Volume : 6bit ( Volume register << 2 ) */ -INLINE static void -setVolume (OPLL * opll, e_int32 c, e_int32 volume) -{ - CAR(opll,c)->volume = volume; -} - -INLINE static void -setSlotVolume (OPLL_SLOT * slot, e_int32 volume) -{ - slot->volume = volume; -} - -/* Set F-Number ( fnum : 9bit ) */ -INLINE static void -setFnumber (OPLL * opll, e_int32 c, e_int32 fnum) -{ - CAR(opll,c)->fnum = fnum; - MOD(opll,c)->fnum = fnum; -} - -/* Set Block data (block : 3bit ) */ -INLINE static void -setBlock (OPLL * opll, e_int32 c, e_int32 block) -{ - CAR(opll,c)->block = block; - MOD(opll,c)->block = block; -} - -/* Change Rhythm Mode */ -INLINE static void -update_rhythm_mode (OPLL * opll) -{ - if (opll->patch_number[6] & 0x10) - { - if (!(opll->slot_on_flag[SLOT_BD2] | (opll->reg[0x0e] & 32))) - { - opll->slot[SLOT_BD1].eg_mode = FINISH; - opll->slot[SLOT_BD2].eg_mode = FINISH; - setPatch (opll, 6, opll->reg[0x36] >> 4); - } - } - else if (opll->reg[0x0e] & 32) - { - opll->patch_number[6] = 16; - opll->slot[SLOT_BD1].eg_mode = FINISH; - opll->slot[SLOT_BD2].eg_mode = FINISH; - setSlotPatch (&opll->slot[SLOT_BD1], &opll->patch[16 * 2 + 0]); - setSlotPatch (&opll->slot[SLOT_BD2], &opll->patch[16 * 2 + 1]); - } - - if (opll->patch_number[7] & 0x10) - { - if (!((opll->slot_on_flag[SLOT_HH] && opll->slot_on_flag[SLOT_SD]) | (opll->reg[0x0e] & 32))) - { - opll->slot[SLOT_HH].type = 0; - opll->slot[SLOT_HH].eg_mode = FINISH; - opll->slot[SLOT_SD].eg_mode = FINISH; - setPatch (opll, 7, opll->reg[0x37] >> 4); - } - } - else if (opll->reg[0x0e] & 32) - { - opll->patch_number[7] = 17; - opll->slot[SLOT_HH].type = 1; - opll->slot[SLOT_HH].eg_mode = FINISH; - opll->slot[SLOT_SD].eg_mode = FINISH; - setSlotPatch (&opll->slot[SLOT_HH], &opll->patch[17 * 2 + 0]); - setSlotPatch (&opll->slot[SLOT_SD], &opll->patch[17 * 2 + 1]); - } - - if (opll->patch_number[8] & 0x10) - { - if (!((opll->slot_on_flag[SLOT_CYM] && opll->slot_on_flag[SLOT_TOM]) | (opll->reg[0x0e] & 32))) - { - opll->slot[SLOT_TOM].type = 0; - opll->slot[SLOT_TOM].eg_mode = FINISH; - opll->slot[SLOT_CYM].eg_mode = FINISH; - setPatch (opll, 8, opll->reg[0x38] >> 4); - } - } - else if (opll->reg[0x0e] & 32) - { - opll->patch_number[8] = 18; - opll->slot[SLOT_TOM].type = 1; - opll->slot[SLOT_TOM].eg_mode = FINISH; - opll->slot[SLOT_CYM].eg_mode = FINISH; - setSlotPatch (&opll->slot[SLOT_TOM], &opll->patch[18 * 2 + 0]); - setSlotPatch (&opll->slot[SLOT_CYM], &opll->patch[18 * 2 + 1]); - } -} - -INLINE static void -update_key_status (OPLL * opll) -{ - int ch; - - for (ch = 0; ch < 9; ch++) - opll->slot_on_flag[ch * 2] = opll->slot_on_flag[ch * 2 + 1] = (opll->reg[0x20 + ch]) & 0x10; - - if (opll->reg[0x0e] & 32) - { - opll->slot_on_flag[SLOT_BD1] |= (opll->reg[0x0e] & 0x10); - opll->slot_on_flag[SLOT_BD2] |= (opll->reg[0x0e] & 0x10); - opll->slot_on_flag[SLOT_SD] |= (opll->reg[0x0e] & 0x08); - opll->slot_on_flag[SLOT_HH] |= (opll->reg[0x0e] & 0x01); - opll->slot_on_flag[SLOT_TOM] |= (opll->reg[0x0e] & 0x04); - opll->slot_on_flag[SLOT_CYM] |= (opll->reg[0x0e] & 0x02); - } -} - -void -OPLL_copyPatch (OPLL * opll, e_int32 num, OPLL_PATCH * patch) -{ - memcpy (&opll->patch[num], patch, sizeof (OPLL_PATCH)); -} - -/*********************************************************** - - Initializing - -***********************************************************/ - -static void -OPLL_SLOT_reset (OPLL_SLOT * slot, int type) -{ - slot->type = type; - slot->sintbl = waveform[0]; - slot->phase = 0; - slot->dphase = 0; - slot->output[0] = 0; - slot->output[1] = 0; - slot->feedback = 0; - slot->eg_mode = FINISH; - slot->eg_phase = EG_DP_WIDTH; - slot->eg_dphase = 0; - slot->rks = 0; - slot->tll = 0; - slot->sustine = 0; - slot->fnum = 0; - slot->block = 0; - slot->volume = 0; - slot->pgout = 0; - slot->egout = 0; - slot->patch = &null_patch; -} - -static void -internal_refresh (void) -{ -#if !defined(ROCKBOX) - makeDphaseTable (); -#endif - makeDphaseARTable (); - makeDphaseDRTable (); - pm_dphase = (e_uint32) RATE_ADJUST ((int)(PM_SPEED * PM_DP_WIDTH) / (clk / 72)); - am_dphase = (e_uint32) RATE_ADJUST ((int)(AM_SPEED * AM_DP_WIDTH) / (clk / 72)); -} - -static void -maketables (e_uint32 c, e_uint32 r) -{ - if (c != clk) - { - clk = c; -#ifdef EMU2413_CALCUL_TABLES - makePmTable (); - makeAmTable (); - makeAdjustTable (); -#endif - makeDB2LinTable (); - makeTllTable (); - makeRksTable (); - makeSinTable (); - makeDefaultPatch (); - } - - if (r != rate) - { - rate = r; - internal_refresh (); - } -} - -void -OPLL_new (OPLL *opll, e_uint32 clk, e_uint32 rate) -{ - e_int32 i; - - maketables (clk, rate); - - memset(opll, 0, sizeof (OPLL)); - for (i = 0; i < 19 * 2; i++) - memcpy(&opll->patch[i],&null_patch,sizeof(OPLL_PATCH)); - - opll->mask = 0; - - OPLL_reset (opll); - OPLL_reset_patch (opll, 0); -} - - -void -OPLL_delete (OPLL * opll) -{ - (void) opll; -} - - -/* Reset patch datas by system default. */ -void -OPLL_reset_patch (OPLL * opll, e_int32 type) -{ - e_int32 i; - - for (i = 0; i < 19 * 2; i++) - OPLL_copyPatch (opll, i, &default_patch[type % OPLL_TONE_NUM][i]); -} - -/* Reset whole of OPLL except patch datas. */ -void -OPLL_reset (OPLL * opll) -{ - e_int32 i; - - if (!opll) - return; - - opll->adr = 0; - opll->out = 0; - - opll->pm_phase = 0; - opll->am_phase = 0; - - opll->noise_seed = 0xffff; - opll->mask = 0; - - for (i = 0; i <18; i++) - OPLL_SLOT_reset(&opll->slot[i], i%2); - - for (i = 0; i < 9; i++) - { - opll->key_status[i] = 0; - setPatch (opll, i, 0); - } - - for (i = 0; i < 0x40; i++) - OPLL_writeReg (opll, i, 0); - -#ifndef EMU2413_COMPACTION - opll->realstep = (e_uint32) ((1 << 31) / rate); - opll->opllstep = (e_uint32) ((1 << 31) / (clk / 72)); - opll->oplltime = 0; - for (i = 0; i < 14; i++) - opll->pan[i] = 2; - opll->sprev[0] = opll->sprev[1] = 0; - opll->snext[0] = opll->snext[1] = 0; -#endif -} - -/* Force Refresh (When external program changes some parameters). */ -void -OPLL_forceRefresh (OPLL * opll) -{ - e_int32 i; - - if (opll == NULL) - return; - - for (i = 0; i < 9; i++) - setPatch(opll,i,opll->patch_number[i]); - - for (i = 0; i < 18; i++) - { - UPDATE_PG (&opll->slot[i]); - UPDATE_RKS (&opll->slot[i]); - UPDATE_TLL (&opll->slot[i]); - UPDATE_WF (&opll->slot[i]); - UPDATE_EG (&opll->slot[i]); - } -} - -void -OPLL_set_rate (OPLL * opll, e_uint32 r) -{ - if (rate == r) return; - if (opll->quality) - rate = 49716; - else - rate = r; - internal_refresh (); - rate = r; -} - -void -OPLL_set_quality (OPLL * opll, e_uint32 q) -{ - opll->quality = q; - OPLL_set_rate (opll, rate); -} - -/********************************************************* - - Generate wave data - -*********************************************************/ -/* Convert Amp(0 to EG_HEIGHT) to Phase(0 to 2PI). */ -#if ( SLOT_AMP_BITS - PG_BITS ) > 0 -#define wave2_2pi(e) ( (e) >> ( SLOT_AMP_BITS - PG_BITS )) -#else -#define wave2_2pi(e) ( (e) << ( PG_BITS - SLOT_AMP_BITS )) -#endif - -/* Convert Amp(0 to EG_HEIGHT) to Phase(0 to 4PI). */ -#if ( SLOT_AMP_BITS - PG_BITS - 1 ) == 0 -#define wave2_4pi(e) (e) -#elif ( SLOT_AMP_BITS - PG_BITS - 1 ) > 0 -#define wave2_4pi(e) ( (e) >> ( SLOT_AMP_BITS - PG_BITS - 1 )) -#else -#define wave2_4pi(e) ( (e) << ( 1 + PG_BITS - SLOT_AMP_BITS )) -#endif - -/* Convert Amp(0 to EG_HEIGHT) to Phase(0 to 8PI). */ -#if ( SLOT_AMP_BITS - PG_BITS - 2 ) == 0 -#define wave2_8pi(e) (e) -#elif ( SLOT_AMP_BITS - PG_BITS - 2 ) > 0 -#define wave2_8pi(e) ( (e) >> ( SLOT_AMP_BITS - PG_BITS - 2 )) -#else -#define wave2_8pi(e) ( (e) << ( 2 + PG_BITS - SLOT_AMP_BITS )) -#endif - -/* Update AM, PM unit */ -INLINE static void -update_ampm (OPLL * opll) -{ - opll->pm_phase = (opll->pm_phase + pm_dphase) & (PM_DP_WIDTH - 1); - opll->am_phase = (opll->am_phase + am_dphase) & (AM_DP_WIDTH - 1); - opll->lfo_am = AMTABLE(HIGHBITS (opll->am_phase, AM_DP_BITS - AM_PG_BITS)); - opll->lfo_pm = PMTABLE(HIGHBITS (opll->pm_phase, PM_DP_BITS - PM_PG_BITS)); -} - -/* PG */ -INLINE static void -calc_phase (OPLL_SLOT * slot, e_int32 lfo) -{ - if (slot->patch->PM) - slot->phase += (slot->dphase * lfo) >> PM_AMP_BITS; - else - slot->phase += slot->dphase; - - slot->phase &= (DP_WIDTH - 1); - - slot->pgout = HIGHBITS (slot->phase, DP_BASE_BITS); -} - -/* Update Noise unit */ -INLINE static void -update_noise (OPLL * opll) -{ - if(opll->noise_seed&1) opll->noise_seed ^= 0x8003020; - opll->noise_seed >>= 1; -} - -/* EG */ -INLINE static void -calc_envelope (OPLL_SLOT * slot, e_int32 lfo) -{ -#define S2E(x) (SL2EG((e_int32)(x/SL_STEP))<<(EG_DP_BITS-EG_BITS)) - - static e_uint32 SL[16] = { - S2E (0.0), S2E (3.0), S2E (6.0), S2E (9.0), S2E (12.0), S2E (15.0), S2E (18.0), S2E (21.0), - S2E (24.0), S2E (27.0), S2E (30.0), S2E (33.0), S2E (36.0), S2E (39.0), S2E (42.0), S2E (48.0) - }; - - e_uint32 egout; - - switch (slot->eg_mode) - { - case ATTACK: - egout = AR_ADJUST_TABLE(HIGHBITS (slot->eg_phase, EG_DP_BITS - EG_BITS)); - slot->eg_phase += slot->eg_dphase; - if((EG_DP_WIDTH & slot->eg_phase)||(slot->patch->AR==15)) - { - egout = 0; - slot->eg_phase = 0; - slot->eg_mode = DECAY; - UPDATE_EG (slot); - } - break; - - case DECAY: - egout = HIGHBITS (slot->eg_phase, EG_DP_BITS - EG_BITS); - slot->eg_phase += slot->eg_dphase; - if (slot->eg_phase >= SL[slot->patch->SL]) - { - if (slot->patch->EG) - { - slot->eg_phase = SL[slot->patch->SL]; - slot->eg_mode = SUSHOLD; - UPDATE_EG (slot); - } - else - { - slot->eg_phase = SL[slot->patch->SL]; - slot->eg_mode = SUSTINE; - UPDATE_EG (slot); - } - } - break; - - case SUSHOLD: - egout = HIGHBITS (slot->eg_phase, EG_DP_BITS - EG_BITS); - if (slot->patch->EG == 0) - { - slot->eg_mode = SUSTINE; - UPDATE_EG (slot); - } - break; - - case SUSTINE: - case RELEASE: - egout = HIGHBITS (slot->eg_phase, EG_DP_BITS - EG_BITS); - slot->eg_phase += slot->eg_dphase; - if (egout >= (1 << EG_BITS)) - { - slot->eg_mode = FINISH; - egout = (1 << EG_BITS) - 1; - } - break; - - case SETTLE: - egout = HIGHBITS (slot->eg_phase, EG_DP_BITS - EG_BITS); - slot->eg_phase += slot->eg_dphase; - if (egout >= (1 << EG_BITS)) - { - slot->eg_mode = ATTACK; - egout = (1 << EG_BITS) - 1; - UPDATE_EG(slot); - } - break; - - case FINISH: - egout = (1 << EG_BITS) - 1; - break; - - default: - egout = (1 << EG_BITS) - 1; - break; - } - - if (slot->patch->AM) - egout = EG2DB (egout + slot->tll) + lfo; - else - egout = EG2DB (egout + slot->tll); - - if (egout >= DB_MUTE) - egout = DB_MUTE - 1; - - slot->egout = egout | 3; -} - -/* CARRIOR */ -INLINE static e_int32 -calc_slot_car (OPLL_SLOT * slot, e_int32 fm) -{ - if (slot->egout >= (DB_MUTE - 1)) - { - slot->output[0] = 0; - } - else - { - slot->output[0] = DB2LIN_TABLE[slot->sintbl[(slot->pgout+wave2_8pi(fm))&(PG_WIDTH-1)] + slot->egout]; - } - - slot->output[1] = (slot->output[1] + slot->output[0]) >> 1; - return slot->output[1]; -} - -/* MODULATOR */ -INLINE static e_int32 -calc_slot_mod (OPLL_SLOT * slot) -{ - e_int32 fm; - - slot->output[1] = slot->output[0]; - - if (slot->egout >= (DB_MUTE - 1)) - { - slot->output[0] = 0; - } - else if (slot->patch->FB != 0) - { - fm = wave2_4pi (slot->feedback) >> (7 - slot->patch->FB); - slot->output[0] = DB2LIN_TABLE[slot->sintbl[(slot->pgout+fm)&(PG_WIDTH-1)] + slot->egout]; - } - else - { - slot->output[0] = DB2LIN_TABLE[slot->sintbl[slot->pgout] + slot->egout]; - } - - slot->feedback = (slot->output[1] + slot->output[0]) >> 1; - - return slot->feedback; - -} - -/* TOM */ -INLINE static e_int32 -calc_slot_tom (OPLL_SLOT * slot) -{ - if (slot->egout >= (DB_MUTE - 1)) - return 0; - - return DB2LIN_TABLE[slot->sintbl[slot->pgout] + slot->egout]; - -} - -/* SNARE */ -INLINE static e_int32 -calc_slot_snare (OPLL_SLOT * slot, e_uint32 noise) -{ - if(slot->egout>=(DB_MUTE-1)) - return 0; - - if(BIT(slot->pgout,7)) - return DB2LIN_TABLE[(noise?DB_POS(0):DB_POS(15))+slot->egout]; - else - return DB2LIN_TABLE[(noise?DB_NEG(0):DB_NEG(15))+slot->egout]; -} - -/* - TOP-CYM - */ -INLINE static e_int32 -calc_slot_cym (OPLL_SLOT * slot, e_uint32 pgout_hh) -{ - e_uint32 dbout; - - if (slot->egout >= (DB_MUTE - 1)) - return 0; - else if( - /* the same as fmopl.c */ - ((BIT(pgout_hh,PG_BITS-8)^BIT(pgout_hh,PG_BITS-1))|BIT(pgout_hh,PG_BITS-7)) ^ - /* different from fmopl.c */ - (BIT(slot->pgout,PG_BITS-7)&!BIT(slot->pgout,PG_BITS-5)) - ) - dbout = DB_NEG(3); - else - dbout = DB_POS(3); - - return DB2LIN_TABLE[dbout + slot->egout]; -} - -/* - HI-HAT -*/ -INLINE static e_int32 -calc_slot_hat (OPLL_SLOT *slot, e_int32 pgout_cym, e_uint32 noise) -{ - e_uint32 dbout; - - if (slot->egout >= (DB_MUTE - 1)) - return 0; - else if( - /* the same as fmopl.c */ - ((BIT(slot->pgout,PG_BITS-8)^BIT(slot->pgout,PG_BITS-1))|BIT(slot->pgout,PG_BITS-7)) ^ - /* different from fmopl.c */ - (BIT(pgout_cym,PG_BITS-7)&!BIT(pgout_cym,PG_BITS-5)) - ) - { - if(noise) - dbout = DB_NEG(12); - else - dbout = DB_NEG(24); - } - else - { - if(noise) - dbout = DB_POS(12); - else - dbout = DB_POS(24); - } - - return DB2LIN_TABLE[dbout + slot->egout]; -} - -static e_int16 -calc (OPLL * opll) EMU2413_CALC_ICODE; -static e_int16 -calc (OPLL * opll) -{ - e_int32 i; - - update_ampm (opll); - update_noise (opll); - - for (i = 0; i < 18; i++) - { - calc_phase(&opll->slot[i],opll->lfo_pm); - calc_envelope(&opll->slot[i],opll->lfo_am); - } - - e_uint32 channel_mask = opll->mask; - for (i = 0; i < 9; i++) { - if (CAR(opll,i)->eg_mode != FINISH) - channel_mask |= (1 << i); - } - - e_int32 mix = 0; - - /* CH6 */ - if (opll->patch_number[6] & 0x10) { - if (channel_mask & OPLL_MASK_CH (6)) { - mix += calc_slot_car (CAR(opll,6), calc_slot_mod(MOD(opll,6))); - channel_mask &= ~(1 << 6); - } - } - - /* CH7 */ - if (opll->patch_number[7] & 0x10) { - if (MOD(opll,7)->eg_mode != FINISH) - mix += calc_slot_hat (MOD(opll,7), CAR(opll,8)->pgout, opll->noise_seed&1); - if (channel_mask & OPLL_MASK_SD) { - mix -= calc_slot_snare (CAR(opll,7), opll->noise_seed&1); - channel_mask &= ~OPLL_MASK_SD; - } - } - - /* CH8 */ - if (opll->patch_number[8] & 0x10) { - if (MOD(opll,8)->eg_mode != FINISH) - mix += calc_slot_tom (MOD(opll,8)); - if (channel_mask & OPLL_MASK_CYM) { - mix -= calc_slot_cym (CAR(opll,8), MOD(opll,7)->pgout); - channel_mask &= ~OPLL_MASK_CYM; - } - } - - mix <<= 1; - - opll->current_mask = channel_mask; - for (i = 0; channel_mask; channel_mask >>= 1, ++i) { - if (channel_mask & 1) { - mix += calc_slot_car (CAR(opll,i), calc_slot_mod(MOD(opll,i))); - } - } - - return (e_int16) mix << 3; -} - -void -OPLL_set_internal_mute(OPLL * opll, e_uint32 mute) -{ - opll->internal_mute = mute; -} - -e_uint32 -OPLL_is_internal_muted(OPLL * opll) -{ - return opll->internal_mute; -} - -static e_uint32 -check_mute_helper(OPLL * opll) -{ - for (int i = 0; i < 6; i++) { - /* if (ch[i].car.eg_mode != FINISH) return 0; */ - if (!(opll->current_mask & OPLL_MASK_CH (i)) && (CAR(opll,i)->eg_mode != FINISH)) return 0; - } - - if (!(opll->reg[0x0e] & 0x20)) { - for(int i = 6; i < 9; i++) { - /* if (ch[i].car.eg_mode != FINISH) return 0; */ - if (!(opll->current_mask & OPLL_MASK_CH (i)) && (CAR(opll,i)->eg_mode != FINISH)) return 0; - } - } else { - /* if (ch[6].car.eg_mode != FINISH) return false; - if (ch[7].mod.eg_mode != FINISH) return false; - if (ch[7].car.eg_mode != FINISH) return false; - if (ch[8].mod.eg_mode != FINISH) return false; - if (ch[8].car.eg_mode != FINISH) return false; */ - if (!(opll->current_mask & OPLL_MASK_CH (6)) && (CAR(opll,6)->eg_mode != FINISH)) return 0; - if (!(opll->current_mask & OPLL_MASK_CH (7)) && (MOD(opll,7)->eg_mode != FINISH)) return 0; - if (!(opll->current_mask & OPLL_MASK_CH (7)) && (CAR(opll,7)->eg_mode != FINISH)) return 0; - if (!(opll->current_mask & OPLL_MASK_CH (8)) && (MOD(opll,8)->eg_mode != FINISH)) return 0; - if (!(opll->current_mask & OPLL_MASK_CH (8)) && (CAR(opll,8)->eg_mode != FINISH)) return 0; - } - - return 1; /* nothing is playing, then mute */ -} - -static void -check_mute(OPLL * opll) -{ - OPLL_set_internal_mute (opll, check_mute_helper (opll)); -} - -EMU2413_API e_int16 *OPLL_update_buffer(OPLL * opll, e_uint32 length) -{ - e_int16* buf = opll->buffer; - while (length--) { - *(buf++) = calc (opll); - } - check_mute (opll); - - return opll->buffer; -} - -#ifdef EMU2413_COMPACTION -e_int16 -OPLL_calc (OPLL * opll) -{ - return calc (opll); -} -#else -e_int16 -OPLL_calc (OPLL * opll) -{ - if (!opll->quality) - return calc (opll); - - while (opll->realstep > opll->oplltime) - { - opll->oplltime += opll->opllstep; - opll->prev = opll->next; - opll->next = calc (opll); - } - - opll->oplltime -= opll->realstep; - opll->out = (e_int16) (((double) opll->next * (opll->opllstep - opll->oplltime) - + (double) opll->prev * opll->oplltime) / opll->opllstep); - - return (e_int16) opll->out; -} -#endif - -e_uint32 -OPLL_setMask (OPLL * opll, e_uint32 mask) -{ - e_uint32 ret; - - if (opll) - { - ret = opll->mask; - opll->mask = mask; - return ret; - } - else - return 0; -} - -e_uint32 -OPLL_toggleMask (OPLL * opll, e_uint32 mask) -{ - e_uint32 ret; - - if (opll) - { - ret = opll->mask; - opll->mask ^= mask; - return ret; - } - else - return 0; -} - -/**************************************************** - - I/O Ctrl - -*****************************************************/ - -void -OPLL_writeReg (OPLL * opll, e_uint32 reg, e_uint32 data) -{ - e_int32 i, v, ch; - - data = data & 0xff; - reg = reg & 0x3f; - opll->reg[reg] = (e_uint8) data; - - switch (reg) - { - case 0x00: - opll->patch[0].AM = (data >> 7) & 1; - opll->patch[0].PM = (data >> 6) & 1; - opll->patch[0].EG = (data >> 5) & 1; - opll->patch[0].KR = (data >> 4) & 1; - opll->patch[0].ML = (data) & 15; - for (i = 0; i < 9; i++) - { - if (opll->patch_number[i] == 0) - { - UPDATE_PG (MOD(opll,i)); - UPDATE_RKS (MOD(opll,i)); - UPDATE_EG (MOD(opll,i)); - } - } - break; - - case 0x01: - opll->patch[1].AM = (data >> 7) & 1; - opll->patch[1].PM = (data >> 6) & 1; - opll->patch[1].EG = (data >> 5) & 1; - opll->patch[1].KR = (data >> 4) & 1; - opll->patch[1].ML = (data) & 15; - for (i = 0; i < 9; i++) - { - if (opll->patch_number[i] == 0) - { - UPDATE_PG (CAR(opll,i)); - UPDATE_RKS (CAR(opll,i)); - UPDATE_EG (CAR(opll,i)); - } - } - break; - - case 0x02: - opll->patch[0].KL = (data >> 6) & 3; - opll->patch[0].TL = (data) & 63; - for (i = 0; i < 9; i++) - { - if (opll->patch_number[i] == 0) - { - UPDATE_TLL(MOD(opll,i)); - } - } - break; - - case 0x03: - opll->patch[1].KL = (data >> 6) & 3; - opll->patch[1].WF = (data >> 4) & 1; - opll->patch[0].WF = (data >> 3) & 1; - opll->patch[0].FB = (data) & 7; - for (i = 0; i < 9; i++) - { - if (opll->patch_number[i] == 0) - { - UPDATE_WF(MOD(opll,i)); - UPDATE_WF(CAR(opll,i)); - } - } - break; - - case 0x04: - opll->patch[0].AR = (data >> 4) & 15; - opll->patch[0].DR = (data) & 15; - for (i = 0; i < 9; i++) - { - if (opll->patch_number[i] == 0) - { - UPDATE_EG (MOD(opll,i)); - } - } - break; - - case 0x05: - opll->patch[1].AR = (data >> 4) & 15; - opll->patch[1].DR = (data) & 15; - for (i = 0; i < 9; i++) - { - if (opll->patch_number[i] == 0) - { - UPDATE_EG(CAR(opll,i)); - } - } - break; - - case 0x06: - opll->patch[0].SL = (data >> 4) & 15; - opll->patch[0].RR = (data) & 15; - for (i = 0; i < 9; i++) - { - if (opll->patch_number[i] == 0) - { - UPDATE_EG (MOD(opll,i)); - } - } - break; - - case 0x07: - opll->patch[1].SL = (data >> 4) & 15; - opll->patch[1].RR = (data) & 15; - for (i = 0; i < 9; i++) - { - if (opll->patch_number[i] == 0) - { - UPDATE_EG (CAR(opll,i)); - } - } - break; - - case 0x0e: - update_rhythm_mode (opll); - if (data & 32) - { - if (data & 0x10) - keyOn_BD (opll); - else - keyOff_BD (opll); - if (data & 0x8) - keyOn_SD (opll); - else - keyOff_SD (opll); - if (data & 0x4) - keyOn_TOM (opll); - else - keyOff_TOM (opll); - if (data & 0x2) - keyOn_CYM (opll); - else - keyOff_CYM (opll); - if (data & 0x1) - keyOn_HH (opll); - else - keyOff_HH (opll); - } - update_key_status (opll); - - UPDATE_ALL (MOD(opll,6)); - UPDATE_ALL (CAR(opll,6)); - UPDATE_ALL (MOD(opll,7)); - UPDATE_ALL (CAR(opll,7)); - UPDATE_ALL (MOD(opll,8)); - UPDATE_ALL (CAR(opll,8)); - - break; - - case 0x0f: - break; - - case 0x10: - case 0x11: - case 0x12: - case 0x13: - case 0x14: - case 0x15: - case 0x16: - case 0x17: - case 0x18: - ch = reg - 0x10; - setFnumber (opll, ch, data + ((opll->reg[0x20 + ch] & 1) << 8)); - UPDATE_ALL (MOD(opll,ch)); - UPDATE_ALL (CAR(opll,ch)); - break; - - case 0x20: - case 0x21: - case 0x22: - case 0x23: - case 0x24: - case 0x25: - case 0x26: - case 0x27: - case 0x28: - ch = reg - 0x20; - setFnumber (opll, ch, ((data & 1) << 8) + opll->reg[0x10 + ch]); - setBlock (opll, ch, (data >> 1) & 7); - setSustine (opll, ch, (data >> 5) & 1); - if (data & 0x10) - keyOn (opll, ch); - else - keyOff (opll, ch); - UPDATE_ALL (MOD(opll,ch)); - UPDATE_ALL (CAR(opll,ch)); - update_key_status (opll); - update_rhythm_mode (opll); - break; - - case 0x30: - case 0x31: - case 0x32: - case 0x33: - case 0x34: - case 0x35: - case 0x36: - case 0x37: - case 0x38: - i = (data >> 4) & 15; - v = data & 15; - if ((opll->reg[0x0e] & 32) && (reg >= 0x36)) - { - switch (reg) - { - case 0x37: - setSlotVolume (MOD(opll,7), i << 2); - break; - case 0x38: - setSlotVolume (MOD(opll,8), i << 2); - break; - default: - break; - } - } - else - { - setPatch (opll, reg - 0x30, i); - } - setVolume (opll, reg - 0x30, v << 2); - UPDATE_ALL (MOD(opll,reg - 0x30)); - UPDATE_ALL (CAR(opll,reg - 0x30)); - break; - - default: - break; - - } -} - -void -OPLL_writeIO (OPLL * opll, e_uint32 adr, e_uint32 val) -{ - if (adr & 1) - OPLL_writeReg (opll, opll->adr, val); - else - opll->adr = val; -} - -e_uint32 -OPLL_read(OPLL * opll, e_uint32 a) -{ - if( !(a&1) ) - { - /* status port */ - return opll->status; - } - return 0xff; -} - -#ifndef EMU2413_COMPACTION -/* STEREO MODE (OPT) */ -void -OPLL_set_pan (OPLL * opll, e_uint32 ch, e_uint32 pan) -{ - opll->pan[ch & 15] = pan & 3; -} - -static void -calc_stereo (OPLL * opll, e_int32 out[2]) -{ - e_int32 b[4] = { 0, 0, 0, 0 }; /* Ignore, Right, Left, Center */ - e_int32 r[4] = { 0, 0, 0, 0 }; /* Ignore, Right, Left, Center */ - e_int32 i; - - update_ampm (opll); - update_noise (opll); - - for(i=0;i<18;i++) - { - calc_phase(&opll->slot[i],opll->lfo_pm); - calc_envelope(&opll->slot[i],opll->lfo_am); - } - - for (i = 0; i < 6; i++) - if (!(opll->mask & OPLL_MASK_CH (i)) && (CAR(opll,i)->eg_mode != FINISH)) - b[opll->pan[i]] += calc_slot_car (CAR(opll,i), calc_slot_mod (MOD(opll,i))); - - - if (opll->patch_number[6] <= 15) - { - if (!(opll->mask & OPLL_MASK_CH (6)) && (CAR(opll,6)->eg_mode != FINISH)) - b[opll->pan[6]] += calc_slot_car (CAR(opll,6), calc_slot_mod (MOD(opll,6))); - } - else - { - if (!(opll->mask & OPLL_MASK_BD) && (CAR(opll,6)->eg_mode != FINISH)) - r[opll->pan[9]] += calc_slot_car (CAR(opll,6), calc_slot_mod (MOD(opll,6))); - } - - if (opll->patch_number[7] <= 15) - { - if (!(opll->mask & OPLL_MASK_CH (7)) && (CAR (opll,7)->eg_mode != FINISH)) - b[opll->pan[7]] += calc_slot_car (CAR (opll,7), calc_slot_mod (MOD (opll,7))); - } - else - { - if (!(opll->mask & OPLL_MASK_HH) && (MOD (opll,7)->eg_mode != FINISH)) - r[opll->pan[10]] += calc_slot_hat (MOD (opll,7), CAR(opll,8)->pgout, opll->noise_seed&1); - if (!(opll->mask & OPLL_MASK_SD) && (CAR (opll,7)->eg_mode != FINISH)) - r[opll->pan[11]] -= calc_slot_snare (CAR (opll,7), opll->noise_seed&1); - } - - if (opll->patch_number[8] <= 15) - { - if (!(opll->mask & OPLL_MASK_CH (8)) && (CAR (opll,8)->eg_mode != FINISH)) - b[opll->pan[8]] += calc_slot_car (CAR (opll,8), calc_slot_mod (MOD (opll,8))); - } - else - { - if (!(opll->mask & OPLL_MASK_TOM) && (MOD (opll,8)->eg_mode != FINISH)) - r[opll->pan[12]] += calc_slot_tom (MOD (opll,8)); - if (!(opll->mask & OPLL_MASK_CYM) && (CAR (opll,8)->eg_mode != FINISH)) - r[opll->pan[13]] -= calc_slot_cym (CAR (opll,8), MOD(opll,7)->pgout); - } - - out[1] = (b[1] + b[3] + ((r[1] + r[3]) << 1)) <<3; - out[0] = (b[2] + b[3] + ((r[2] + r[3]) << 1)) <<3; -} - -void -OPLL_calc_stereo (OPLL * opll, e_int32 out[2]) -{ - if (!opll->quality) - { - calc_stereo (opll, out); - return; - } - - while (opll->realstep > opll->oplltime) - { - opll->oplltime += opll->opllstep; - opll->sprev[0] = opll->snext[0]; - opll->sprev[1] = opll->snext[1]; - calc_stereo (opll, opll->snext); - } - - opll->oplltime -= opll->realstep; - out[0] = (e_int16) (((double) opll->snext[0] * (opll->opllstep - opll->oplltime) - + (double) opll->sprev[0] * opll->oplltime) / opll->opllstep); - out[1] = (e_int16) (((double) opll->snext[1] * (opll->opllstep - opll->oplltime) - + (double) opll->sprev[1] * opll->oplltime) / opll->opllstep); -} -#endif /* EMU2413_COMPACTION */ +/*********************************************************************************** + + emu2413.c -- YM2413 emulator written by Mitsutaka Okazaki 2001 + + 2001 01-08 : Version 0.10 -- 1st version. + 2001 01-15 : Version 0.20 -- semi-public version. + 2001 01-16 : Version 0.30 -- 1st public version. + 2001 01-17 : Version 0.31 -- Fixed bassdrum problem. + : Version 0.32 -- LPF implemented. + 2001 01-18 : Version 0.33 -- Fixed the drum problem, refine the mix-down method. + -- Fixed the LFO bug. + 2001 01-24 : Version 0.35 -- Fixed the drum problem, + support undocumented EG behavior. + 2001 02-02 : Version 0.38 -- Improved the performance. + Fixed the hi-hat and cymbal model. + Fixed the default percussive datas. + Noise reduction. + Fixed the feedback problem. + 2001 03-03 : Version 0.39 -- Fixed some drum bugs. + Improved the performance. + 2001 03-04 : Version 0.40 -- Improved the feedback. + Change the default table size. + Clock and Rate can be changed during play. + 2001 06-24 : Version 0.50 -- Improved the hi-hat and the cymbal tone. + Added VRC7 patch (OPLL_reset_patch is changed). + Fixed OPLL_reset() bug. + Added OPLL_setMask, OPLL_getMask and OPLL_toggleMask. + Added OPLL_writeIO. + 2001 09-28 : Version 0.51 -- Removed the noise table. + 2002 01-28 : Version 0.52 -- Added Stereo mode. + 2002 02-07 : Version 0.53 -- Fixed some drum bugs. + 2002 02-20 : Version 0.54 -- Added the best quality mode. + 2002 03-02 : Version 0.55 -- Removed OPLL_init & OPLL_close. + 2002 05-30 : Version 0.60 -- Fixed HH&CYM generator and all voice datas. + 2004 04-10 : Version 0.61 -- Added YMF281B tone (defined by Chabin). + + 2011 03-22 : --------------- Modified by gama to use precalculated tables. + + References: + fmopl.c -- 1999,2000 written by Tatsuyuki Satoh (MAME development). + fmopl.c(fixed) -- (C) 2002 Jarek Burczynski. + s_opl.c -- 2001 written by Mamiya (NEZplug development). + fmgen.cpp -- 1999,2000 written by cisc. + fmpac.ill -- 2000 created by NARUTO. + MSX-Datapack + YMU757 data sheet + YM2143 data sheet + +**************************************************************************************/ +#include +#include +#include +#include +#include "emu2413.h" + +#include "emutables.h" +#if !defined(ROCKBOX) + #define EMU2413_CALCUL_TABLES +#else + #define EMU2413_COMPACTION + #include "emutables.h" +#endif + +#if defined(EMU2413_COMPACTION) && !defined(ROCKBOX) +#define OPLL_TONE_NUM 1 +static unsigned char default_inst[OPLL_TONE_NUM][(16 + 3) * 16] = { + { +#include "2413tone.h" + } +}; +#else +#define OPLL_TONE_NUM 3 +static unsigned char default_inst[OPLL_TONE_NUM][(16 + 3) * 16] = { + { +#include "2413tone.h" + }, + { +#include "vrc7tone.h" + }, + { +#include "281btone.h" + } +}; +#endif + +/* Size of Sintable ( 8 -- 18 can be used. 9 recommended.) */ +#define PG_BITS 9 +#define PG_WIDTH (1<>(b)) + +/* Leave the lower b bit(s). */ +#define LOWBITS(c,b) ((c)&((1<<(b))-1)) + +/* Expand x which is s bits to d bits. */ +#define EXPAND_BITS(x,s,d) ((x)<<((d)-(s))) + +/* Expand x which is s bits to d bits and fill expanded bits '1' */ +#define EXPAND_BITS_X(x,s,d) (((x)<<((d)-(s)))|((1<<((d)-(s)))-1)) + +/* Adjust envelope speed which depends on sampling rate. */ +#define RATE_ADJUST(x) (rate==49716?(e_uint32)x:(e_uint32)(((long long)(x)*clk/rate+36)/72)) + +#define MOD(o,x) (&(o)->slot[(x)<<1]) +#define CAR(o,x) (&(o)->slot[((x)<<1)|1]) + +#define BIT(s,b) (((s)>>(b))&1) + +/* Input clock */ +static e_uint32 clk = 844451141; +/* Sampling rate */ +static e_uint32 rate = 3354932; + +/* WaveTable for each envelope amp */ +static e_uint16 fullsintable[PG_WIDTH]; +static e_uint16 halfsintable[PG_WIDTH]; + +static e_uint16 *waveform[2] = { fullsintable, halfsintable }; + +/* LFO Table */ +#ifdef EMU2413_CALCUL_TABLES + static e_int32 pmtable[PM_PG_WIDTH]; + static e_int32 amtable[AM_PG_WIDTH]; + #define PMTABLE(x) pmtable[x] + #define AMTABLE(x) amtable[x] +#else + #define PMTABLE(x) (e_int32)pm_coeff[x] + #if (PM_PG_WIDTH != 256) + #error PM_PG_WIDTH must be set to 256 if EMU2413_CALCUL_TABLES is not defined + #endif + #define AMTABLE(x) (e_int32)am_coeff[x] + #if (AM_PG_WIDTH != 256) + #error AM_PG_WIDTH must be set to 256 if EMU2413_CALCUL_TABLES is not defined + #endif +#endif + +/* Phase delta for LFO */ +static e_uint32 pm_dphase; +static e_uint32 am_dphase; + +/* dB to Liner table */ +static e_int16 DB2LIN_TABLE[(DB_MUTE + DB_MUTE) * 2]; + +/* Liner to Log curve conversion table (for Attack rate). */ +#ifdef EMU2413_CALCUL_TABLES + static e_uint16 ar_adjust_table[1 << EG_BITS]; + #define AR_ADJUST_TABLE(x) ar_adjust_table[x] +#else + #define AR_ADJUST_TABLE(x) ar_adjust_coeff[x] + #if (EG_BITS != 7) + #error EG_BITS must be set to 7 if EMU2413_CALCUL_TABLES is not defined + #endif +#endif + +/* Empty voice data */ +static OPLL_PATCH null_patch = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + +/* Basic voice Data */ +static OPLL_PATCH default_patch[OPLL_TONE_NUM][(16 + 3) * 2]; + +/* Definition of envelope mode */ +enum OPLL_EG_STATE +{ READY, ATTACK, DECAY, SUSHOLD, SUSTINE, RELEASE, SETTLE, FINISH }; + +/* Phase incr table for Attack */ +static e_uint32 dphaseARTable[16][16]; +/* Phase incr table for Decay and Release */ +static e_uint32 dphaseDRTable[16][16]; + +/* KSL + TL Table */ +e_uint8 tllTable[16][8][1 << TL_BITS][4]; +static e_int32 rksTable[2][8][2]; + +/* We may not have too much SRAM in rockbox */ +#if !defined(ROCKBOX) +/* Phase incr table for PG */ +static e_uint32 dphaseTable[512][8][16]; +#endif + +/*************************************************** + + Create tables + +****************************************************/ +#ifdef EMU2413_CALCUL_TABLES +INLINE static e_int32 +Min (e_int32 i, e_int32 j) +{ + if (i < j) + return i; + else + return j; +} + +/* Table for AR to LogCurve. */ +static void +makeAdjustTable (void) +{ + e_int32 i; + + ar_adjust_table[0] = (1 << EG_BITS) - 1; + for (i = 1; i < (1<= DB_MUTE) DB2LIN_TABLE[i] = 0; + DB2LIN_TABLE[i + DB_MUTE + DB_MUTE] = (e_int16) (-DB2LIN_TABLE[i]); + } +} + +#ifdef EMU2413_CALCUL_TABLES +/* Liner(+0.0 - +1.0) to dB((1<> (20 - DP_BITS)); +} +#endif + +static void +makeTllTable (void) +{ +/* Multiplication owith 8 to have an integer result. This allows to remove floating point operation. */ +#define dB2(x) (int)((x)*2*8) + + static int kltable[16] = { + dB2 ( 0.000), dB2 ( 9.000), dB2 (12.000), dB2 (13.875), dB2 (15.000), dB2 (16.125), dB2 (16.875), dB2 (17.625), + dB2 (18.000), dB2 (18.750), dB2 (19.125), dB2 (19.500), dB2 (19.875), dB2 (20.250), dB2 (20.625), dB2 (21.000) + }; + + e_int32 tmp; + e_int32 fnum, block, TL, KL; + + for (fnum = 0; fnum < 16; fnum++) + for (block = 0; block < 8; block++) + for (TL = 0; TL < 64; TL++) + for (KL = 0; KL < 4; KL++) + { + if (KL == 0) + { + tllTable[fnum][block][TL][KL] = TL2EG (TL); + } + else + { + tmp = (e_int32) ((kltable[fnum] - dB2 (3.000) * (7 - block))/8); + if (tmp <= 0) + tllTable[fnum][block][TL][KL] = TL2EG (TL); + else + /* tllTable[fnum][block][TL][KL] = (e_uint32) ((tmp >> (3 - KL)) / EG_STEP) + TL2EG (TL); */ + tllTable[fnum][block][TL][KL] = (e_uint32) ((tmp << KL) / (int)(EG_STEP*8)) + TL2EG (TL); + } + } +} + +#ifdef USE_SPEC_ENV_SPEED +static double attacktime[16][4] = { + {0, 0, 0, 0}, + {1730.15, 1400.60, 1153.43, 988.66}, + {865.08, 700.30, 576.72, 494.33}, + {432.54, 350.15, 288.36, 247.16}, + {216.27, 175.07, 144.18, 123.58}, + {108.13, 87.54, 72.09, 61.79}, + {54.07, 43.77, 36.04, 30.90}, + {27.03, 21.88, 18.02, 15.45}, + {13.52, 10.94, 9.01, 7.72}, + {6.76, 5.47, 4.51, 3.86}, + {3.38, 2.74, 2.25, 1.93}, + {1.69, 1.37, 1.13, 0.97}, + {0.84, 0.70, 0.60, 0.54}, + {0.50, 0.42, 0.34, 0.30}, + {0.28, 0.22, 0.18, 0.14}, + {0.00, 0.00, 0.00, 0.00} +}; + +static double decaytime[16][4] = { + {0, 0, 0, 0}, + {20926.60, 16807.20, 14006.00, 12028.60}, + {10463.30, 8403.58, 7002.98, 6014.32}, + {5231.64, 4201.79, 3501.49, 3007.16}, + {2615.82, 2100.89, 1750.75, 1503.58}, + {1307.91, 1050.45, 875.37, 751.79}, + {653.95, 525.22, 437.69, 375.90}, + {326.98, 262.61, 218.84, 187.95}, + {163.49, 131.31, 109.42, 93.97}, + {81.74, 65.65, 54.71, 46.99}, + {40.87, 32.83, 27.36, 23.49}, + {20.44, 16.41, 13.68, 11.75}, + {10.22, 8.21, 6.84, 5.87}, + {5.11, 4.10, 3.42, 2.94}, + {2.55, 2.05, 1.71, 1.47}, + {1.27, 1.27, 1.27, 1.27} +}; +#endif + +/* Rate Table for Attack */ +static void +makeDphaseARTable (void) +{ + e_int32 AR, Rks, RM, RL; + +#ifdef USE_SPEC_ENV_SPEED + e_uint32 attacktable[16][4]; + + for (RM = 0; RM < 16; RM++) + for (RL = 0; RL < 4; RL++) + { + if (RM == 0) + attacktable[RM][RL] = 0; + else if (RM == 15) + attacktable[RM][RL] = EG_DP_WIDTH; + else + attacktable[RM][RL] = (e_uint32) ((double) (1 << EG_DP_BITS) / (attacktime[RM][RL] * 3579545 / 72000)); + + } +#endif + + for (AR = 0; AR < 16; AR++) + for (Rks = 0; Rks < 16; Rks++) + { + RM = AR + (Rks >> 2); + RL = Rks & 3; + if (RM > 15) + RM = 15; + switch (AR) + { + case 0: + dphaseARTable[AR][Rks] = 0; + break; + case 15: + dphaseARTable[AR][Rks] = 0;/*EG_DP_WIDTH;*/ + break; + default: +#ifdef USE_SPEC_ENV_SPEED + dphaseARTable[AR][Rks] = RATE_ADJUST (attacktable[RM][RL]); +#else + dphaseARTable[AR][Rks] = RATE_ADJUST ((3 * (RL + 4) << (RM + 1))); +#endif + break; + } + } +} + +/* Rate Table for Decay and Release */ +static void +makeDphaseDRTable (void) +{ + e_int32 DR, Rks, RM, RL; + +#ifdef USE_SPEC_ENV_SPEED + e_uint32 decaytable[16][4]; + + for (RM = 0; RM < 16; RM++) + for (RL = 0; RL < 4; RL++) + if (RM == 0) + decaytable[RM][RL] = 0; + else + decaytable[RM][RL] = (e_uint32) ((double) (1 << EG_DP_BITS) / (decaytime[RM][RL] * 3579545 / 72000)); +#endif + + for (DR = 0; DR < 16; DR++) + for (Rks = 0; Rks < 16; Rks++) + { + RM = DR + (Rks >> 2); + RL = Rks & 3; + if (RM > 15) + RM = 15; + switch (DR) + { + case 0: + dphaseDRTable[DR][Rks] = 0; + break; + default: +#ifdef USE_SPEC_ENV_SPEED + dphaseDRTable[DR][Rks] = RATE_ADJUST (decaytable[RM][RL]); +#else + dphaseDRTable[DR][Rks] = RATE_ADJUST ((RL + 4) << (RM - 1)); +#endif + break; + } + } +} + +static void +makeRksTable (void) +{ + + e_int32 fnum8, block, KR; + + for (fnum8 = 0; fnum8 < 2; fnum8++) + for (block = 0; block < 8; block++) + for (KR = 0; KR < 2; KR++) + { + if (KR != 0) + rksTable[fnum8][block][KR] = (block << 1) + fnum8; + else + rksTable[fnum8][block][KR] = block >> 1; + } +} + +void +OPLL_dump2patch (const e_uint8 * dump, OPLL_PATCH * patch) +{ + patch[0].AM = (dump[0] >> 7) & 1; + patch[1].AM = (dump[1] >> 7) & 1; + patch[0].PM = (dump[0] >> 6) & 1; + patch[1].PM = (dump[1] >> 6) & 1; + patch[0].EG = (dump[0] >> 5) & 1; + patch[1].EG = (dump[1] >> 5) & 1; + patch[0].KR = (dump[0] >> 4) & 1; + patch[1].KR = (dump[1] >> 4) & 1; + patch[0].ML = (dump[0]) & 15; + patch[1].ML = (dump[1]) & 15; + patch[0].KL = (dump[2] >> 6) & 3; + patch[1].KL = (dump[3] >> 6) & 3; + patch[0].TL = (dump[2]) & 63; + patch[0].FB = (dump[3]) & 7; + patch[0].WF = (dump[3] >> 3) & 1; + patch[1].WF = (dump[3] >> 4) & 1; + patch[0].AR = (dump[4] >> 4) & 15; + patch[1].AR = (dump[5] >> 4) & 15; + patch[0].DR = (dump[4]) & 15; + patch[1].DR = (dump[5]) & 15; + patch[0].SL = (dump[6] >> 4) & 15; + patch[1].SL = (dump[7] >> 4) & 15; + patch[0].RR = (dump[6]) & 15; + patch[1].RR = (dump[7]) & 15; +} + +void +OPLL_getDefaultPatch (e_int32 type, e_int32 num, OPLL_PATCH * patch) +{ + OPLL_dump2patch (default_inst[type] + num * 16, patch); +} + +static void +makeDefaultPatch ( void ) +{ + e_int32 i, j; + + for (i = 0; i < OPLL_TONE_NUM; i++) + for (j = 0; j < 19; j++) + OPLL_getDefaultPatch (i, j, &default_patch[i][j * 2]); + +} + +void +OPLL_setPatch (OPLL * opll, const e_uint8 * dump) +{ + OPLL_PATCH patch[2]; + int i; + + for (i = 0; i < 19; i++) + { + OPLL_dump2patch (dump + i * 16, patch); + memcpy (&opll->patch[i*2+0], &patch[0], sizeof (OPLL_PATCH)); + memcpy (&opll->patch[i*2+1], &patch[1], sizeof (OPLL_PATCH)); + } +} + +void +OPLL_patch2dump (const OPLL_PATCH * patch, e_uint8 * dump) +{ + dump[0] = (e_uint8) ((patch[0].AM << 7) + (patch[0].PM << 6) + (patch[0].EG << 5) + (patch[0].KR << 4) + patch[0].ML); + dump[1] = (e_uint8) ((patch[1].AM << 7) + (patch[1].PM << 6) + (patch[1].EG << 5) + (patch[1].KR << 4) + patch[1].ML); + dump[2] = (e_uint8) ((patch[0].KL << 6) + patch[0].TL); + dump[3] = (e_uint8) ((patch[1].KL << 6) + (patch[1].WF << 4) + (patch[0].WF << 3) + patch[0].FB); + dump[4] = (e_uint8) ((patch[0].AR << 4) + patch[0].DR); + dump[5] = (e_uint8) ((patch[1].AR << 4) + patch[1].DR); + dump[6] = (e_uint8) ((patch[0].SL << 4) + patch[0].RR); + dump[7] = (e_uint8) ((patch[1].SL << 4) + patch[1].RR); + dump[8] = 0; + dump[9] = 0; + dump[10] = 0; + dump[11] = 0; + dump[12] = 0; + dump[13] = 0; + dump[14] = 0; + dump[15] = 0; +} + +/************************************************************ + + Calc Parameters + +************************************************************/ + +INLINE static e_uint32 +calc_eg_dphase (OPLL_SLOT * slot) +{ + + switch (slot->eg_mode) + { + case ATTACK: + return dphaseARTable[slot->patch->AR][slot->rks]; + + case DECAY: + return dphaseDRTable[slot->patch->DR][slot->rks]; + + case SUSHOLD: + return 0; + + case SUSTINE: + return dphaseDRTable[slot->patch->RR][slot->rks]; + + case RELEASE: + if (slot->sustine) + return dphaseDRTable[5][slot->rks]; + else if (slot->patch->EG) + return dphaseDRTable[slot->patch->RR][slot->rks]; + else + return dphaseDRTable[7][slot->rks]; + + case SETTLE: + return dphaseDRTable[15][0]; + + case FINISH: + return 0; + + default: + return 0; + } +} + +/************************************************************* + + OPLL internal interfaces + +*************************************************************/ +#define SLOT_BD1 12 +#define SLOT_BD2 13 +#define SLOT_HH 14 +#define SLOT_SD 15 +#define SLOT_TOM 16 +#define SLOT_CYM 17 + +/* We will set this dinamically, but not sure if this affects playback */ +#if defined(ROCKBOX) +INLINE static void +UPDATE_PG(OPLL_SLOT * slot) +{ + static const e_uint32 mltable[16] = + { 1, 1 * 2, 2 * 2, 3 * 2, 4 * 2, 5 * 2, 6 * 2, 7 * 2, 8 * 2, 9 * 2, 10 * 2, 10 * 2, 12 * 2, 12 * 2, 15 * 2, 15 * 2 }; + + slot->dphase = RATE_ADJUST (((slot->fnum * mltable[slot->patch->ML]) << slot->block) >> (20 - DP_BITS)); +} +#else +#define UPDATE_PG(S) (S)->dphase = dphaseTable[(S)->fnum][(S)->block][(S)->patch->ML] +#endif + +#define UPDATE_TLL(S)\ +(((S)->type==0)?\ +((S)->tll = tllTable[((S)->fnum)>>5][(S)->block][(S)->patch->TL][(S)->patch->KL]):\ +((S)->tll = tllTable[((S)->fnum)>>5][(S)->block][(S)->volume][(S)->patch->KL])) +#define UPDATE_RKS(S) (S)->rks = rksTable[((S)->fnum)>>8][(S)->block][(S)->patch->KR] +#define UPDATE_WF(S) (S)->sintbl = waveform[(S)->patch->WF] +#define UPDATE_EG(S) (S)->eg_dphase = calc_eg_dphase(S) +#define UPDATE_ALL(S)\ + UPDATE_PG(S);\ + UPDATE_TLL(S);\ + UPDATE_RKS(S);\ + UPDATE_WF(S); \ + UPDATE_EG(S) /* EG should be updated last. */ + + +/* Slot key on */ +INLINE static void +slotOn (OPLL_SLOT * slot) +{ + slot->eg_mode = ATTACK; + slot->eg_phase = 0; + slot->phase = 0; + UPDATE_EG(slot); +} + +/* Slot key on without reseting the phase */ +INLINE static void +slotOn2 (OPLL_SLOT * slot) +{ + slot->eg_mode = ATTACK; + slot->eg_phase = 0; + UPDATE_EG(slot); +} + +/* Slot key off */ +INLINE static void +slotOff (OPLL_SLOT * slot) +{ + if (slot->eg_mode == ATTACK) + slot->eg_phase = EXPAND_BITS (AR_ADJUST_TABLE(HIGHBITS (slot->eg_phase, EG_DP_BITS - EG_BITS)), EG_BITS, EG_DP_BITS); + slot->eg_mode = RELEASE; + UPDATE_EG(slot); +} + +/* Channel key on */ +INLINE static void +keyOn (OPLL * opll, e_int32 i) +{ + if (!opll->slot_on_flag[i * 2]) + slotOn (MOD(opll,i)); + if (!opll->slot_on_flag[i * 2 + 1]) + slotOn (CAR(opll,i)); + opll->key_status[i] = 1; +} + +/* Channel key off */ +INLINE static void +keyOff (OPLL * opll, e_int32 i) +{ + if (opll->slot_on_flag[i * 2 + 1]) + slotOff (CAR(opll,i)); + opll->key_status[i] = 0; +} + +INLINE static void +keyOn_BD (OPLL * opll) +{ + keyOn (opll, 6); +} +INLINE static void +keyOn_SD (OPLL * opll) +{ + if (!opll->slot_on_flag[SLOT_SD]) + slotOn (CAR(opll,7)); +} +INLINE static void +keyOn_TOM (OPLL * opll) +{ + if (!opll->slot_on_flag[SLOT_TOM]) + slotOn (MOD(opll,8)); +} +INLINE static void +keyOn_HH (OPLL * opll) +{ + if (!opll->slot_on_flag[SLOT_HH]) + slotOn2 (MOD(opll,7)); +} +INLINE static void +keyOn_CYM (OPLL * opll) +{ + if (!opll->slot_on_flag[SLOT_CYM]) + slotOn2 (CAR(opll,8)); +} + +/* Drum key off */ +INLINE static void +keyOff_BD (OPLL * opll) +{ + keyOff (opll, 6); +} +INLINE static void +keyOff_SD (OPLL * opll) +{ + if (opll->slot_on_flag[SLOT_SD]) + slotOff (CAR(opll,7)); +} +INLINE static void +keyOff_TOM (OPLL * opll) +{ + if (opll->slot_on_flag[SLOT_TOM]) + slotOff (MOD(opll,8)); +} +INLINE static void +keyOff_HH (OPLL * opll) +{ + if (opll->slot_on_flag[SLOT_HH]) + slotOff (MOD(opll,7)); +} +INLINE static void +keyOff_CYM (OPLL * opll) +{ + if (opll->slot_on_flag[SLOT_CYM]) + slotOff (CAR(opll,8)); +} + +/* Change a voice */ +INLINE static void +setPatch (OPLL * opll, e_int32 i, e_int32 num) +{ + opll->patch_number[i] = num; + MOD(opll,i)->patch = &opll->patch[num * 2 + 0]; + CAR(opll,i)->patch = &opll->patch[num * 2 + 1]; +} + +/* Change a rhythm voice */ +INLINE static void +setSlotPatch (OPLL_SLOT * slot, OPLL_PATCH * patch) +{ + slot->patch = patch; +} + +/* Set sustine parameter */ +INLINE static void +setSustine (OPLL * opll, e_int32 c, e_int32 sustine) +{ + CAR(opll,c)->sustine = sustine; + if (MOD(opll,c)->type) + MOD(opll,c)->sustine = sustine; +} + +/* Volume : 6bit ( Volume register << 2 ) */ +INLINE static void +setVolume (OPLL * opll, e_int32 c, e_int32 volume) +{ + CAR(opll,c)->volume = volume; +} + +INLINE static void +setSlotVolume (OPLL_SLOT * slot, e_int32 volume) +{ + slot->volume = volume; +} + +/* Set F-Number ( fnum : 9bit ) */ +INLINE static void +setFnumber (OPLL * opll, e_int32 c, e_int32 fnum) +{ + CAR(opll,c)->fnum = fnum; + MOD(opll,c)->fnum = fnum; +} + +/* Set Block data (block : 3bit ) */ +INLINE static void +setBlock (OPLL * opll, e_int32 c, e_int32 block) +{ + CAR(opll,c)->block = block; + MOD(opll,c)->block = block; +} + +/* Change Rhythm Mode */ +INLINE static void +update_rhythm_mode (OPLL * opll) +{ + if (opll->patch_number[6] & 0x10) + { + if (!(opll->slot_on_flag[SLOT_BD2] | (opll->reg[0x0e] & 32))) + { + opll->slot[SLOT_BD1].eg_mode = FINISH; + opll->slot[SLOT_BD2].eg_mode = FINISH; + setPatch (opll, 6, opll->reg[0x36] >> 4); + } + } + else if (opll->reg[0x0e] & 32) + { + opll->patch_number[6] = 16; + opll->slot[SLOT_BD1].eg_mode = FINISH; + opll->slot[SLOT_BD2].eg_mode = FINISH; + setSlotPatch (&opll->slot[SLOT_BD1], &opll->patch[16 * 2 + 0]); + setSlotPatch (&opll->slot[SLOT_BD2], &opll->patch[16 * 2 + 1]); + } + + if (opll->patch_number[7] & 0x10) + { + if (!((opll->slot_on_flag[SLOT_HH] && opll->slot_on_flag[SLOT_SD]) | (opll->reg[0x0e] & 32))) + { + opll->slot[SLOT_HH].type = 0; + opll->slot[SLOT_HH].eg_mode = FINISH; + opll->slot[SLOT_SD].eg_mode = FINISH; + setPatch (opll, 7, opll->reg[0x37] >> 4); + } + } + else if (opll->reg[0x0e] & 32) + { + opll->patch_number[7] = 17; + opll->slot[SLOT_HH].type = 1; + opll->slot[SLOT_HH].eg_mode = FINISH; + opll->slot[SLOT_SD].eg_mode = FINISH; + setSlotPatch (&opll->slot[SLOT_HH], &opll->patch[17 * 2 + 0]); + setSlotPatch (&opll->slot[SLOT_SD], &opll->patch[17 * 2 + 1]); + } + + if (opll->patch_number[8] & 0x10) + { + if (!((opll->slot_on_flag[SLOT_CYM] && opll->slot_on_flag[SLOT_TOM]) | (opll->reg[0x0e] & 32))) + { + opll->slot[SLOT_TOM].type = 0; + opll->slot[SLOT_TOM].eg_mode = FINISH; + opll->slot[SLOT_CYM].eg_mode = FINISH; + setPatch (opll, 8, opll->reg[0x38] >> 4); + } + } + else if (opll->reg[0x0e] & 32) + { + opll->patch_number[8] = 18; + opll->slot[SLOT_TOM].type = 1; + opll->slot[SLOT_TOM].eg_mode = FINISH; + opll->slot[SLOT_CYM].eg_mode = FINISH; + setSlotPatch (&opll->slot[SLOT_TOM], &opll->patch[18 * 2 + 0]); + setSlotPatch (&opll->slot[SLOT_CYM], &opll->patch[18 * 2 + 1]); + } +} + +INLINE static void +update_key_status (OPLL * opll) +{ + int ch; + + for (ch = 0; ch < 9; ch++) + opll->slot_on_flag[ch * 2] = opll->slot_on_flag[ch * 2 + 1] = (opll->reg[0x20 + ch]) & 0x10; + + if (opll->reg[0x0e] & 32) + { + opll->slot_on_flag[SLOT_BD1] |= (opll->reg[0x0e] & 0x10); + opll->slot_on_flag[SLOT_BD2] |= (opll->reg[0x0e] & 0x10); + opll->slot_on_flag[SLOT_SD] |= (opll->reg[0x0e] & 0x08); + opll->slot_on_flag[SLOT_HH] |= (opll->reg[0x0e] & 0x01); + opll->slot_on_flag[SLOT_TOM] |= (opll->reg[0x0e] & 0x04); + opll->slot_on_flag[SLOT_CYM] |= (opll->reg[0x0e] & 0x02); + } +} + +void +OPLL_copyPatch (OPLL * opll, e_int32 num, OPLL_PATCH * patch) +{ + memcpy (&opll->patch[num], patch, sizeof (OPLL_PATCH)); +} + +/*********************************************************** + + Initializing + +***********************************************************/ + +static void +OPLL_SLOT_reset (OPLL_SLOT * slot, int type) +{ + slot->type = type; + slot->sintbl = waveform[0]; + slot->phase = 0; + slot->dphase = 0; + slot->output[0] = 0; + slot->output[1] = 0; + slot->feedback = 0; + slot->eg_mode = FINISH; + slot->eg_phase = EG_DP_WIDTH; + slot->eg_dphase = 0; + slot->rks = 0; + slot->tll = 0; + slot->sustine = 0; + slot->fnum = 0; + slot->block = 0; + slot->volume = 0; + slot->pgout = 0; + slot->egout = 0; + slot->patch = &null_patch; +} + +static void +internal_refresh (void) +{ +#if !defined(ROCKBOX) + makeDphaseTable (); +#endif + makeDphaseARTable (); + makeDphaseDRTable (); + pm_dphase = (e_uint32) RATE_ADJUST ((int)(PM_SPEED * PM_DP_WIDTH) / (clk / 72)); + am_dphase = (e_uint32) RATE_ADJUST ((int)(AM_SPEED * AM_DP_WIDTH) / (clk / 72)); +} + +static void +maketables (e_uint32 c, e_uint32 r) +{ + if (c != clk) + { + clk = c; +#ifdef EMU2413_CALCUL_TABLES + makePmTable (); + makeAmTable (); + makeAdjustTable (); +#endif + makeDB2LinTable (); + makeTllTable (); + makeRksTable (); + makeSinTable (); + makeDefaultPatch (); + } + + if (r != rate) + { + rate = r; + internal_refresh (); + } +} + +void +OPLL_new (OPLL *opll, e_uint32 clk, e_uint32 rate) +{ + e_int32 i; + + maketables (clk, rate); + + memset(opll, 0, sizeof (OPLL)); + for (i = 0; i < 19 * 2; i++) + memcpy(&opll->patch[i],&null_patch,sizeof(OPLL_PATCH)); + + opll->mask = 0; + + OPLL_reset (opll); + OPLL_reset_patch (opll, 0); +} + + +void +OPLL_delete (OPLL * opll) +{ + (void) opll; +} + + +/* Reset patch datas by system default. */ +void +OPLL_reset_patch (OPLL * opll, e_int32 type) +{ + e_int32 i; + + for (i = 0; i < 19 * 2; i++) + OPLL_copyPatch (opll, i, &default_patch[type % OPLL_TONE_NUM][i]); +} + +/* Reset whole of OPLL except patch datas. */ +void +OPLL_reset (OPLL * opll) +{ + e_int32 i; + + if (!opll) + return; + + opll->adr = 0; + opll->out = 0; + + opll->pm_phase = 0; + opll->am_phase = 0; + + opll->noise_seed = 0xffff; + opll->mask = 0; + + for (i = 0; i <18; i++) + OPLL_SLOT_reset(&opll->slot[i], i%2); + + for (i = 0; i < 9; i++) + { + opll->key_status[i] = 0; + setPatch (opll, i, 0); + } + + for (i = 0; i < 0x40; i++) + OPLL_writeReg (opll, i, 0); + +#ifndef EMU2413_COMPACTION + opll->realstep = (e_uint32) ((1 << 31) / rate); + opll->opllstep = (e_uint32) ((1 << 31) / (clk / 72)); + opll->oplltime = 0; + for (i = 0; i < 14; i++) + opll->pan[i] = 2; + opll->sprev[0] = opll->sprev[1] = 0; + opll->snext[0] = opll->snext[1] = 0; +#endif +} + +/* Force Refresh (When external program changes some parameters). */ +void +OPLL_forceRefresh (OPLL * opll) +{ + e_int32 i; + + if (opll == NULL) + return; + + for (i = 0; i < 9; i++) + setPatch(opll,i,opll->patch_number[i]); + + for (i = 0; i < 18; i++) + { + UPDATE_PG (&opll->slot[i]); + UPDATE_RKS (&opll->slot[i]); + UPDATE_TLL (&opll->slot[i]); + UPDATE_WF (&opll->slot[i]); + UPDATE_EG (&opll->slot[i]); + } +} + +void +OPLL_set_rate (OPLL * opll, e_uint32 r) +{ + if (rate == r) return; + if (opll->quality) + rate = 49716; + else + rate = r; + internal_refresh (); + rate = r; +} + +void +OPLL_set_quality (OPLL * opll, e_uint32 q) +{ + opll->quality = q; + OPLL_set_rate (opll, rate); +} + +/********************************************************* + + Generate wave data + +*********************************************************/ +/* Convert Amp(0 to EG_HEIGHT) to Phase(0 to 2PI). */ +#if ( SLOT_AMP_BITS - PG_BITS ) > 0 +#define wave2_2pi(e) ( (e) >> ( SLOT_AMP_BITS - PG_BITS )) +#else +#define wave2_2pi(e) ( (e) << ( PG_BITS - SLOT_AMP_BITS )) +#endif + +/* Convert Amp(0 to EG_HEIGHT) to Phase(0 to 4PI). */ +#if ( SLOT_AMP_BITS - PG_BITS - 1 ) == 0 +#define wave2_4pi(e) (e) +#elif ( SLOT_AMP_BITS - PG_BITS - 1 ) > 0 +#define wave2_4pi(e) ( (e) >> ( SLOT_AMP_BITS - PG_BITS - 1 )) +#else +#define wave2_4pi(e) ( (e) << ( 1 + PG_BITS - SLOT_AMP_BITS )) +#endif + +/* Convert Amp(0 to EG_HEIGHT) to Phase(0 to 8PI). */ +#if ( SLOT_AMP_BITS - PG_BITS - 2 ) == 0 +#define wave2_8pi(e) (e) +#elif ( SLOT_AMP_BITS - PG_BITS - 2 ) > 0 +#define wave2_8pi(e) ( (e) >> ( SLOT_AMP_BITS - PG_BITS - 2 )) +#else +#define wave2_8pi(e) ( (e) << ( 2 + PG_BITS - SLOT_AMP_BITS )) +#endif + +/* Update AM, PM unit */ +INLINE static void +update_ampm (OPLL * opll) +{ + opll->pm_phase = (opll->pm_phase + pm_dphase) & (PM_DP_WIDTH - 1); + opll->am_phase = (opll->am_phase + am_dphase) & (AM_DP_WIDTH - 1); + opll->lfo_am = AMTABLE(HIGHBITS (opll->am_phase, AM_DP_BITS - AM_PG_BITS)); + opll->lfo_pm = PMTABLE(HIGHBITS (opll->pm_phase, PM_DP_BITS - PM_PG_BITS)); +} + +/* PG */ +INLINE static void +calc_phase (OPLL_SLOT * slot, e_int32 lfo) +{ + if (slot->patch->PM) + slot->phase += (slot->dphase * lfo) >> PM_AMP_BITS; + else + slot->phase += slot->dphase; + + slot->phase &= (DP_WIDTH - 1); + + slot->pgout = HIGHBITS (slot->phase, DP_BASE_BITS); +} + +/* Update Noise unit */ +INLINE static void +update_noise (OPLL * opll) +{ + if(opll->noise_seed&1) opll->noise_seed ^= 0x8003020; + opll->noise_seed >>= 1; +} + +/* EG */ +INLINE static void +calc_envelope (OPLL_SLOT * slot, e_int32 lfo) +{ +#define S2E(x) (SL2EG((e_int32)(x/SL_STEP))<<(EG_DP_BITS-EG_BITS)) + + static e_uint32 SL[16] = { + S2E (0.0), S2E (3.0), S2E (6.0), S2E (9.0), S2E (12.0), S2E (15.0), S2E (18.0), S2E (21.0), + S2E (24.0), S2E (27.0), S2E (30.0), S2E (33.0), S2E (36.0), S2E (39.0), S2E (42.0), S2E (48.0) + }; + + e_uint32 egout; + + switch (slot->eg_mode) + { + case ATTACK: + egout = AR_ADJUST_TABLE(HIGHBITS (slot->eg_phase, EG_DP_BITS - EG_BITS)); + slot->eg_phase += slot->eg_dphase; + if((EG_DP_WIDTH & slot->eg_phase)||(slot->patch->AR==15)) + { + egout = 0; + slot->eg_phase = 0; + slot->eg_mode = DECAY; + UPDATE_EG (slot); + } + break; + + case DECAY: + egout = HIGHBITS (slot->eg_phase, EG_DP_BITS - EG_BITS); + slot->eg_phase += slot->eg_dphase; + if (slot->eg_phase >= SL[slot->patch->SL]) + { + if (slot->patch->EG) + { + slot->eg_phase = SL[slot->patch->SL]; + slot->eg_mode = SUSHOLD; + UPDATE_EG (slot); + } + else + { + slot->eg_phase = SL[slot->patch->SL]; + slot->eg_mode = SUSTINE; + UPDATE_EG (slot); + } + } + break; + + case SUSHOLD: + egout = HIGHBITS (slot->eg_phase, EG_DP_BITS - EG_BITS); + if (slot->patch->EG == 0) + { + slot->eg_mode = SUSTINE; + UPDATE_EG (slot); + } + break; + + case SUSTINE: + case RELEASE: + egout = HIGHBITS (slot->eg_phase, EG_DP_BITS - EG_BITS); + slot->eg_phase += slot->eg_dphase; + if (egout >= (1 << EG_BITS)) + { + slot->eg_mode = FINISH; + egout = (1 << EG_BITS) - 1; + } + break; + + case SETTLE: + egout = HIGHBITS (slot->eg_phase, EG_DP_BITS - EG_BITS); + slot->eg_phase += slot->eg_dphase; + if (egout >= (1 << EG_BITS)) + { + slot->eg_mode = ATTACK; + egout = (1 << EG_BITS) - 1; + UPDATE_EG(slot); + } + break; + + case FINISH: + egout = (1 << EG_BITS) - 1; + break; + + default: + egout = (1 << EG_BITS) - 1; + break; + } + + if (slot->patch->AM) + egout = EG2DB (egout + slot->tll) + lfo; + else + egout = EG2DB (egout + slot->tll); + + if (egout >= DB_MUTE) + egout = DB_MUTE - 1; + + slot->egout = egout | 3; +} + +/* CARRIOR */ +INLINE static e_int32 +calc_slot_car (OPLL_SLOT * slot, e_int32 fm) +{ + if (slot->egout >= (DB_MUTE - 1)) + { + slot->output[0] = 0; + } + else + { + slot->output[0] = DB2LIN_TABLE[slot->sintbl[(slot->pgout+wave2_8pi(fm))&(PG_WIDTH-1)] + slot->egout]; + } + + slot->output[1] = (slot->output[1] + slot->output[0]) >> 1; + return slot->output[1]; +} + +/* MODULATOR */ +INLINE static e_int32 +calc_slot_mod (OPLL_SLOT * slot) +{ + e_int32 fm; + + slot->output[1] = slot->output[0]; + + if (slot->egout >= (DB_MUTE - 1)) + { + slot->output[0] = 0; + } + else if (slot->patch->FB != 0) + { + fm = wave2_4pi (slot->feedback) >> (7 - slot->patch->FB); + slot->output[0] = DB2LIN_TABLE[slot->sintbl[(slot->pgout+fm)&(PG_WIDTH-1)] + slot->egout]; + } + else + { + slot->output[0] = DB2LIN_TABLE[slot->sintbl[slot->pgout] + slot->egout]; + } + + slot->feedback = (slot->output[1] + slot->output[0]) >> 1; + + return slot->feedback; + +} + +/* TOM */ +INLINE static e_int32 +calc_slot_tom (OPLL_SLOT * slot) +{ + if (slot->egout >= (DB_MUTE - 1)) + return 0; + + return DB2LIN_TABLE[slot->sintbl[slot->pgout] + slot->egout]; + +} + +/* SNARE */ +INLINE static e_int32 +calc_slot_snare (OPLL_SLOT * slot, e_uint32 noise) +{ + if(slot->egout>=(DB_MUTE-1)) + return 0; + + if(BIT(slot->pgout,7)) + return DB2LIN_TABLE[(noise?DB_POS(0):DB_POS(15))+slot->egout]; + else + return DB2LIN_TABLE[(noise?DB_NEG(0):DB_NEG(15))+slot->egout]; +} + +/* + TOP-CYM + */ +INLINE static e_int32 +calc_slot_cym (OPLL_SLOT * slot, e_uint32 pgout_hh) +{ + e_uint32 dbout; + + if (slot->egout >= (DB_MUTE - 1)) + return 0; + else if( + /* the same as fmopl.c */ + ((BIT(pgout_hh,PG_BITS-8)^BIT(pgout_hh,PG_BITS-1))|BIT(pgout_hh,PG_BITS-7)) ^ + /* different from fmopl.c */ + (BIT(slot->pgout,PG_BITS-7)&!BIT(slot->pgout,PG_BITS-5)) + ) + dbout = DB_NEG(3); + else + dbout = DB_POS(3); + + return DB2LIN_TABLE[dbout + slot->egout]; +} + +/* + HI-HAT +*/ +INLINE static e_int32 +calc_slot_hat (OPLL_SLOT *slot, e_int32 pgout_cym, e_uint32 noise) +{ + e_uint32 dbout; + + if (slot->egout >= (DB_MUTE - 1)) + return 0; + else if( + /* the same as fmopl.c */ + ((BIT(slot->pgout,PG_BITS-8)^BIT(slot->pgout,PG_BITS-1))|BIT(slot->pgout,PG_BITS-7)) ^ + /* different from fmopl.c */ + (BIT(pgout_cym,PG_BITS-7)&!BIT(pgout_cym,PG_BITS-5)) + ) + { + if(noise) + dbout = DB_NEG(12); + else + dbout = DB_NEG(24); + } + else + { + if(noise) + dbout = DB_POS(12); + else + dbout = DB_POS(24); + } + + return DB2LIN_TABLE[dbout + slot->egout]; +} + +static e_int16 +calc (OPLL * opll) EMU2413_CALC_ICODE; +static e_int16 +calc (OPLL * opll) +{ + e_int32 i; + + update_ampm (opll); + update_noise (opll); + + for (i = 0; i < 18; i++) + { + calc_phase(&opll->slot[i],opll->lfo_pm); + calc_envelope(&opll->slot[i],opll->lfo_am); + } + + e_uint32 channel_mask = opll->mask; + for (i = 0; i < 9; i++) { + if (CAR(opll,i)->eg_mode != FINISH) + channel_mask |= (1 << i); + } + + e_int32 mix = 0; + + /* CH6 */ + if (opll->patch_number[6] & 0x10) { + if (channel_mask & OPLL_MASK_CH (6)) { + mix += calc_slot_car (CAR(opll,6), calc_slot_mod(MOD(opll,6))); + channel_mask &= ~(1 << 6); + } + } + + /* CH7 */ + if (opll->patch_number[7] & 0x10) { + if (MOD(opll,7)->eg_mode != FINISH) + mix += calc_slot_hat (MOD(opll,7), CAR(opll,8)->pgout, opll->noise_seed&1); + if (channel_mask & OPLL_MASK_SD) { + mix -= calc_slot_snare (CAR(opll,7), opll->noise_seed&1); + channel_mask &= ~OPLL_MASK_SD; + } + } + + /* CH8 */ + if (opll->patch_number[8] & 0x10) { + if (MOD(opll,8)->eg_mode != FINISH) + mix += calc_slot_tom (MOD(opll,8)); + if (channel_mask & OPLL_MASK_CYM) { + mix -= calc_slot_cym (CAR(opll,8), MOD(opll,7)->pgout); + channel_mask &= ~OPLL_MASK_CYM; + } + } + + mix <<= 1; + + opll->current_mask = channel_mask; + for (i = 0; channel_mask; channel_mask >>= 1, ++i) { + if (channel_mask & 1) { + mix += calc_slot_car (CAR(opll,i), calc_slot_mod(MOD(opll,i))); + } + } + + return (e_int16) mix << 3; +} + +void +OPLL_set_internal_mute(OPLL * opll, e_uint32 mute) +{ + opll->internal_mute = mute; +} + +e_uint32 +OPLL_is_internal_muted(OPLL * opll) +{ + return opll->internal_mute; +} + +static e_uint32 +check_mute_helper(OPLL * opll) +{ + for (int i = 0; i < 6; i++) { + /* if (ch[i].car.eg_mode != FINISH) return 0; */ + if (!(opll->current_mask & OPLL_MASK_CH (i)) && (CAR(opll,i)->eg_mode != FINISH)) return 0; + } + + if (!(opll->reg[0x0e] & 0x20)) { + for(int i = 6; i < 9; i++) { + /* if (ch[i].car.eg_mode != FINISH) return 0; */ + if (!(opll->current_mask & OPLL_MASK_CH (i)) && (CAR(opll,i)->eg_mode != FINISH)) return 0; + } + } else { + /* if (ch[6].car.eg_mode != FINISH) return false; + if (ch[7].mod.eg_mode != FINISH) return false; + if (ch[7].car.eg_mode != FINISH) return false; + if (ch[8].mod.eg_mode != FINISH) return false; + if (ch[8].car.eg_mode != FINISH) return false; */ + if (!(opll->current_mask & OPLL_MASK_CH (6)) && (CAR(opll,6)->eg_mode != FINISH)) return 0; + if (!(opll->current_mask & OPLL_MASK_CH (7)) && (MOD(opll,7)->eg_mode != FINISH)) return 0; + if (!(opll->current_mask & OPLL_MASK_CH (7)) && (CAR(opll,7)->eg_mode != FINISH)) return 0; + if (!(opll->current_mask & OPLL_MASK_CH (8)) && (MOD(opll,8)->eg_mode != FINISH)) return 0; + if (!(opll->current_mask & OPLL_MASK_CH (8)) && (CAR(opll,8)->eg_mode != FINISH)) return 0; + } + + return 1; /* nothing is playing, then mute */ +} + +static void +check_mute(OPLL * opll) +{ + OPLL_set_internal_mute (opll, check_mute_helper (opll)); +} + +EMU2413_API e_int16 *OPLL_update_buffer(OPLL * opll, e_uint32 length) +{ + e_int16* buf = opll->buffer; + while (length--) { + *(buf++) = calc (opll); + } + check_mute (opll); + + return opll->buffer; +} + +#ifdef EMU2413_COMPACTION +e_int16 +OPLL_calc (OPLL * opll) +{ + return calc (opll); +} +#else +e_int16 +OPLL_calc (OPLL * opll) +{ + if (!opll->quality) + return calc (opll); + + while (opll->realstep > opll->oplltime) + { + opll->oplltime += opll->opllstep; + opll->prev = opll->next; + opll->next = calc (opll); + } + + opll->oplltime -= opll->realstep; + opll->out = (e_int16) (((double) opll->next * (opll->opllstep - opll->oplltime) + + (double) opll->prev * opll->oplltime) / opll->opllstep); + + return (e_int16) opll->out; +} +#endif + +e_uint32 +OPLL_setMask (OPLL * opll, e_uint32 mask) +{ + e_uint32 ret; + + if (opll) + { + ret = opll->mask; + opll->mask = mask; + return ret; + } + else + return 0; +} + +e_uint32 +OPLL_toggleMask (OPLL * opll, e_uint32 mask) +{ + e_uint32 ret; + + if (opll) + { + ret = opll->mask; + opll->mask ^= mask; + return ret; + } + else + return 0; +} + +/**************************************************** + + I/O Ctrl + +*****************************************************/ + +void +OPLL_writeReg (OPLL * opll, e_uint32 reg, e_uint32 data) +{ + e_int32 i, v, ch; + + data = data & 0xff; + reg = reg & 0x3f; + opll->reg[reg] = (e_uint8) data; + + switch (reg) + { + case 0x00: + opll->patch[0].AM = (data >> 7) & 1; + opll->patch[0].PM = (data >> 6) & 1; + opll->patch[0].EG = (data >> 5) & 1; + opll->patch[0].KR = (data >> 4) & 1; + opll->patch[0].ML = (data) & 15; + for (i = 0; i < 9; i++) + { + if (opll->patch_number[i] == 0) + { + UPDATE_PG (MOD(opll,i)); + UPDATE_RKS (MOD(opll,i)); + UPDATE_EG (MOD(opll,i)); + } + } + break; + + case 0x01: + opll->patch[1].AM = (data >> 7) & 1; + opll->patch[1].PM = (data >> 6) & 1; + opll->patch[1].EG = (data >> 5) & 1; + opll->patch[1].KR = (data >> 4) & 1; + opll->patch[1].ML = (data) & 15; + for (i = 0; i < 9; i++) + { + if (opll->patch_number[i] == 0) + { + UPDATE_PG (CAR(opll,i)); + UPDATE_RKS (CAR(opll,i)); + UPDATE_EG (CAR(opll,i)); + } + } + break; + + case 0x02: + opll->patch[0].KL = (data >> 6) & 3; + opll->patch[0].TL = (data) & 63; + for (i = 0; i < 9; i++) + { + if (opll->patch_number[i] == 0) + { + UPDATE_TLL(MOD(opll,i)); + } + } + break; + + case 0x03: + opll->patch[1].KL = (data >> 6) & 3; + opll->patch[1].WF = (data >> 4) & 1; + opll->patch[0].WF = (data >> 3) & 1; + opll->patch[0].FB = (data) & 7; + for (i = 0; i < 9; i++) + { + if (opll->patch_number[i] == 0) + { + UPDATE_WF(MOD(opll,i)); + UPDATE_WF(CAR(opll,i)); + } + } + break; + + case 0x04: + opll->patch[0].AR = (data >> 4) & 15; + opll->patch[0].DR = (data) & 15; + for (i = 0; i < 9; i++) + { + if (opll->patch_number[i] == 0) + { + UPDATE_EG (MOD(opll,i)); + } + } + break; + + case 0x05: + opll->patch[1].AR = (data >> 4) & 15; + opll->patch[1].DR = (data) & 15; + for (i = 0; i < 9; i++) + { + if (opll->patch_number[i] == 0) + { + UPDATE_EG(CAR(opll,i)); + } + } + break; + + case 0x06: + opll->patch[0].SL = (data >> 4) & 15; + opll->patch[0].RR = (data) & 15; + for (i = 0; i < 9; i++) + { + if (opll->patch_number[i] == 0) + { + UPDATE_EG (MOD(opll,i)); + } + } + break; + + case 0x07: + opll->patch[1].SL = (data >> 4) & 15; + opll->patch[1].RR = (data) & 15; + for (i = 0; i < 9; i++) + { + if (opll->patch_number[i] == 0) + { + UPDATE_EG (CAR(opll,i)); + } + } + break; + + case 0x0e: + update_rhythm_mode (opll); + if (data & 32) + { + if (data & 0x10) + keyOn_BD (opll); + else + keyOff_BD (opll); + if (data & 0x8) + keyOn_SD (opll); + else + keyOff_SD (opll); + if (data & 0x4) + keyOn_TOM (opll); + else + keyOff_TOM (opll); + if (data & 0x2) + keyOn_CYM (opll); + else + keyOff_CYM (opll); + if (data & 0x1) + keyOn_HH (opll); + else + keyOff_HH (opll); + } + update_key_status (opll); + + UPDATE_ALL (MOD(opll,6)); + UPDATE_ALL (CAR(opll,6)); + UPDATE_ALL (MOD(opll,7)); + UPDATE_ALL (CAR(opll,7)); + UPDATE_ALL (MOD(opll,8)); + UPDATE_ALL (CAR(opll,8)); + + break; + + case 0x0f: + break; + + case 0x10: + case 0x11: + case 0x12: + case 0x13: + case 0x14: + case 0x15: + case 0x16: + case 0x17: + case 0x18: + ch = reg - 0x10; + setFnumber (opll, ch, data + ((opll->reg[0x20 + ch] & 1) << 8)); + UPDATE_ALL (MOD(opll,ch)); + UPDATE_ALL (CAR(opll,ch)); + break; + + case 0x20: + case 0x21: + case 0x22: + case 0x23: + case 0x24: + case 0x25: + case 0x26: + case 0x27: + case 0x28: + ch = reg - 0x20; + setFnumber (opll, ch, ((data & 1) << 8) + opll->reg[0x10 + ch]); + setBlock (opll, ch, (data >> 1) & 7); + setSustine (opll, ch, (data >> 5) & 1); + if (data & 0x10) + keyOn (opll, ch); + else + keyOff (opll, ch); + UPDATE_ALL (MOD(opll,ch)); + UPDATE_ALL (CAR(opll,ch)); + update_key_status (opll); + update_rhythm_mode (opll); + break; + + case 0x30: + case 0x31: + case 0x32: + case 0x33: + case 0x34: + case 0x35: + case 0x36: + case 0x37: + case 0x38: + i = (data >> 4) & 15; + v = data & 15; + if ((opll->reg[0x0e] & 32) && (reg >= 0x36)) + { + switch (reg) + { + case 0x37: + setSlotVolume (MOD(opll,7), i << 2); + break; + case 0x38: + setSlotVolume (MOD(opll,8), i << 2); + break; + default: + break; + } + } + else + { + setPatch (opll, reg - 0x30, i); + } + setVolume (opll, reg - 0x30, v << 2); + UPDATE_ALL (MOD(opll,reg - 0x30)); + UPDATE_ALL (CAR(opll,reg - 0x30)); + break; + + default: + break; + + } +} + +void +OPLL_writeIO (OPLL * opll, e_uint32 adr, e_uint32 val) +{ + if (adr & 1) + OPLL_writeReg (opll, opll->adr, val); + else + opll->adr = val; +} + +e_uint32 +OPLL_read(OPLL * opll, e_uint32 a) +{ + if( !(a&1) ) + { + /* status port */ + return opll->status; + } + return 0xff; +} + +#ifndef EMU2413_COMPACTION +/* STEREO MODE (OPT) */ +void +OPLL_set_pan (OPLL * opll, e_uint32 ch, e_uint32 pan) +{ + opll->pan[ch & 15] = pan & 3; +} + +static void +calc_stereo (OPLL * opll, e_int32 out[2]) +{ + e_int32 b[4] = { 0, 0, 0, 0 }; /* Ignore, Right, Left, Center */ + e_int32 r[4] = { 0, 0, 0, 0 }; /* Ignore, Right, Left, Center */ + e_int32 i; + + update_ampm (opll); + update_noise (opll); + + for(i=0;i<18;i++) + { + calc_phase(&opll->slot[i],opll->lfo_pm); + calc_envelope(&opll->slot[i],opll->lfo_am); + } + + for (i = 0; i < 6; i++) + if (!(opll->mask & OPLL_MASK_CH (i)) && (CAR(opll,i)->eg_mode != FINISH)) + b[opll->pan[i]] += calc_slot_car (CAR(opll,i), calc_slot_mod (MOD(opll,i))); + + + if (opll->patch_number[6] <= 15) + { + if (!(opll->mask & OPLL_MASK_CH (6)) && (CAR(opll,6)->eg_mode != FINISH)) + b[opll->pan[6]] += calc_slot_car (CAR(opll,6), calc_slot_mod (MOD(opll,6))); + } + else + { + if (!(opll->mask & OPLL_MASK_BD) && (CAR(opll,6)->eg_mode != FINISH)) + r[opll->pan[9]] += calc_slot_car (CAR(opll,6), calc_slot_mod (MOD(opll,6))); + } + + if (opll->patch_number[7] <= 15) + { + if (!(opll->mask & OPLL_MASK_CH (7)) && (CAR (opll,7)->eg_mode != FINISH)) + b[opll->pan[7]] += calc_slot_car (CAR (opll,7), calc_slot_mod (MOD (opll,7))); + } + else + { + if (!(opll->mask & OPLL_MASK_HH) && (MOD (opll,7)->eg_mode != FINISH)) + r[opll->pan[10]] += calc_slot_hat (MOD (opll,7), CAR(opll,8)->pgout, opll->noise_seed&1); + if (!(opll->mask & OPLL_MASK_SD) && (CAR (opll,7)->eg_mode != FINISH)) + r[opll->pan[11]] -= calc_slot_snare (CAR (opll,7), opll->noise_seed&1); + } + + if (opll->patch_number[8] <= 15) + { + if (!(opll->mask & OPLL_MASK_CH (8)) && (CAR (opll,8)->eg_mode != FINISH)) + b[opll->pan[8]] += calc_slot_car (CAR (opll,8), calc_slot_mod (MOD (opll,8))); + } + else + { + if (!(opll->mask & OPLL_MASK_TOM) && (MOD (opll,8)->eg_mode != FINISH)) + r[opll->pan[12]] += calc_slot_tom (MOD (opll,8)); + if (!(opll->mask & OPLL_MASK_CYM) && (CAR (opll,8)->eg_mode != FINISH)) + r[opll->pan[13]] -= calc_slot_cym (CAR (opll,8), MOD(opll,7)->pgout); + } + + out[1] = (b[1] + b[3] + ((r[1] + r[3]) << 1)) <<3; + out[0] = (b[2] + b[3] + ((r[2] + r[3]) << 1)) <<3; +} + +void +OPLL_calc_stereo (OPLL * opll, e_int32 out[2]) +{ + if (!opll->quality) + { + calc_stereo (opll, out); + return; + } + + while (opll->realstep > opll->oplltime) + { + opll->oplltime += opll->opllstep; + opll->sprev[0] = opll->snext[0]; + opll->sprev[1] = opll->snext[1]; + calc_stereo (opll, opll->snext); + } + + opll->oplltime -= opll->realstep; + out[0] = (e_int16) (((double) opll->snext[0] * (opll->opllstep - opll->oplltime) + + (double) opll->sprev[0] * opll->oplltime) / opll->opllstep); + out[1] = (e_int16) (((double) opll->snext[1] * (opll->opllstep - opll->oplltime) + + (double) opll->sprev[1] * opll->oplltime) / opll->opllstep); +} +#endif /* EMU2413_COMPACTION */ diff --git a/apps/codecs/libgme/emu2413.h b/apps/codecs/libgme/emu2413.h index 6a19b102a1..254f042957 100644 --- a/apps/codecs/libgme/emu2413.h +++ b/apps/codecs/libgme/emu2413.h @@ -1,164 +1,164 @@ -#ifndef _EMU2413_H_ -#define _EMU2413_H_ - -#include "blargg_common.h" -#include "emutypes.h" - -#ifdef EMU2413_DLL_EXPORTS - #define EMU2413_API __declspec(dllexport) -#elif defined(EMU2413_DLL_IMPORTS) - #define EMU2413_API __declspec(dllimport) -#else - #define EMU2413_API -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -#define AUDIO_MONO_BUFFER_SIZE 1024 - -#define PI 3.14159265358979323846 - -enum OPLL_TONE_ENUM {OPLL_2413_TONE=0, OPLL_VRC7_TONE=1, OPLL_281B_TONE=2} ; - -/* voice data */ -typedef struct __OPLL_PATCH { - e_uint32 TL,FB,EG,ML,AR,DR,SL,RR,KR,KL,AM,PM,WF ; -} OPLL_PATCH ; - -/* slot */ -typedef struct __OPLL_SLOT { - - OPLL_PATCH *patch; - - e_int32 type ; /* 0 : modulator 1 : carrier */ - - /* OUTPUT */ - e_int32 feedback ; - e_int32 output[2] ; /* Output value of slot */ - - /* for Phase Generator (PG) */ - e_uint16 *sintbl ; /* Wavetable */ - e_uint32 phase ; /* Phase */ - e_uint32 dphase ; /* Phase increment amount */ - e_uint32 pgout ; /* output */ - - /* for Envelope Generator (EG) */ - e_int32 fnum ; /* F-Number */ - e_int32 block ; /* Block */ - e_int32 volume ; /* Current volume */ - e_int32 sustine ; /* Sustine 1 = ON, 0 = OFF */ - e_uint32 tll ; /* Total Level + Key scale level*/ - e_uint32 rks ; /* Key scale offset (Rks) */ - e_int32 eg_mode ; /* Current state */ - e_uint32 eg_phase ; /* Phase */ - e_uint32 eg_dphase ; /* Phase increment amount */ - e_uint32 egout ; /* output */ - -} OPLL_SLOT ; - -/* Mask */ -#define OPLL_MASK_CH(x) (1<<(x)) -#define OPLL_MASK_HH (1<<(9)) -#define OPLL_MASK_CYM (1<<(10)) -#define OPLL_MASK_TOM (1<<(11)) -#define OPLL_MASK_SD (1<<(12)) -#define OPLL_MASK_BD (1<<(13)) -#define OPLL_MASK_RHYTHM ( OPLL_MASK_HH | OPLL_MASK_CYM | OPLL_MASK_TOM | OPLL_MASK_SD | OPLL_MASK_BD ) - -/* opll */ -typedef struct __OPLL { - - e_uint32 adr ; - e_int32 out ; - -#ifndef EMU2413_COMPACTION - e_uint32 realstep ; - e_uint32 oplltime ; - e_uint32 opllstep ; - e_int32 prev, next ; - e_int32 sprev[2],snext[2]; - e_uint32 pan[16]; -#endif - - /* Register */ - e_uint8 reg[0x40] ; - e_int32 slot_on_flag[18] ; - - /* Pitch Modulator */ - e_uint32 pm_phase ; - e_int32 lfo_pm ; - - /* Amp Modulator */ - e_int32 am_phase ; - e_int32 lfo_am ; - - e_uint32 quality; - - /* Noise Generator */ - e_uint32 noise_seed ; - - /* Channel Data */ - e_int32 patch_number[9]; - e_int32 key_status[9] ; - - /* Slot */ - OPLL_SLOT slot[18] ; - - /* Voice Data */ - OPLL_PATCH patch[19*2] ; - e_int32 patch_update[2] ; /* flag for check patch update */ - - e_uint32 mask ; - e_uint32 current_mask; - e_uint32 status; - - e_uint32 internal_mute; - e_int16 buffer[AUDIO_MONO_BUFFER_SIZE]; -} OPLL ; - -/* Create Object */ -EMU2413_API void OPLL_new(OPLL *, e_uint32 clk, e_uint32 rate) ; -EMU2413_API void OPLL_delete(OPLL *) ; - -/* Setup */ -EMU2413_API void OPLL_reset(OPLL *) ; -EMU2413_API void OPLL_reset_patch(OPLL *, e_int32) ; -EMU2413_API void OPLL_set_rate(OPLL *opll, e_uint32 r) ; -EMU2413_API void OPLL_set_quality(OPLL *opll, e_uint32 q) ; -EMU2413_API void OPLL_set_pan(OPLL *, e_uint32 ch, e_uint32 pan); -EMU2413_API void OPLL_set_internal_mute(OPLL *, e_uint32 mute); -EMU2413_API e_uint32 OPLL_is_internal_muted(OPLL *); - -/* Port/Register access */ -EMU2413_API void OPLL_writeIO(OPLL *, e_uint32 reg, e_uint32 val); -EMU2413_API void OPLL_writeReg(OPLL *, e_uint32 reg, e_uint32 val); -EMU2413_API e_uint32 OPLL_read(OPLL *, e_uint32 port); - -/* Synthsize */ -EMU2413_API e_int16 OPLL_calc(OPLL *) EMU2413_CALC_ICODE; -EMU2413_API void OPLL_calc_stereo(OPLL *, e_int32 out[2]) ; -EMU2413_API e_int16 *OPLL_update_buffer(OPLL *, e_uint32 length) ; - -/* Misc */ -EMU2413_API void OPLL_setPatch(OPLL *, const e_uint8 *dump) ; -EMU2413_API void OPLL_copyPatch(OPLL *, e_int32, OPLL_PATCH *) ; -EMU2413_API void OPLL_forceRefresh(OPLL *) ; -/* Utility */ -EMU2413_API void OPLL_dump2patch(const e_uint8 *dump, OPLL_PATCH *patch) ; -EMU2413_API void OPLL_patch2dump(const OPLL_PATCH *patch, e_uint8 *dump) ; -EMU2413_API void OPLL_getDefaultPatch(e_int32 type, e_int32 num, OPLL_PATCH *) ; - -/* Channel Mask */ -EMU2413_API e_uint32 OPLL_setMask(OPLL *, e_uint32 mask) ; -EMU2413_API e_uint32 OPLL_toggleMask(OPLL *, e_uint32 mask) ; - -#define dump2patch OPLL_dump2patch - -#ifdef __cplusplus -} -#endif - -#endif - +#ifndef _EMU2413_H_ +#define _EMU2413_H_ + +#include "blargg_common.h" +#include "emutypes.h" + +#ifdef EMU2413_DLL_EXPORTS + #define EMU2413_API __declspec(dllexport) +#elif defined(EMU2413_DLL_IMPORTS) + #define EMU2413_API __declspec(dllimport) +#else + #define EMU2413_API +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#define AUDIO_MONO_BUFFER_SIZE 1024 + +#define PI 3.14159265358979323846 + +enum OPLL_TONE_ENUM {OPLL_2413_TONE=0, OPLL_VRC7_TONE=1, OPLL_281B_TONE=2} ; + +/* voice data */ +typedef struct __OPLL_PATCH { + e_uint32 TL,FB,EG,ML,AR,DR,SL,RR,KR,KL,AM,PM,WF ; +} OPLL_PATCH ; + +/* slot */ +typedef struct __OPLL_SLOT { + + OPLL_PATCH *patch; + + e_int32 type ; /* 0 : modulator 1 : carrier */ + + /* OUTPUT */ + e_int32 feedback ; + e_int32 output[2] ; /* Output value of slot */ + + /* for Phase Generator (PG) */ + e_uint16 *sintbl ; /* Wavetable */ + e_uint32 phase ; /* Phase */ + e_uint32 dphase ; /* Phase increment amount */ + e_uint32 pgout ; /* output */ + + /* for Envelope Generator (EG) */ + e_int32 fnum ; /* F-Number */ + e_int32 block ; /* Block */ + e_int32 volume ; /* Current volume */ + e_int32 sustine ; /* Sustine 1 = ON, 0 = OFF */ + e_uint32 tll ; /* Total Level + Key scale level*/ + e_uint32 rks ; /* Key scale offset (Rks) */ + e_int32 eg_mode ; /* Current state */ + e_uint32 eg_phase ; /* Phase */ + e_uint32 eg_dphase ; /* Phase increment amount */ + e_uint32 egout ; /* output */ + +} OPLL_SLOT ; + +/* Mask */ +#define OPLL_MASK_CH(x) (1<<(x)) +#define OPLL_MASK_HH (1<<(9)) +#define OPLL_MASK_CYM (1<<(10)) +#define OPLL_MASK_TOM (1<<(11)) +#define OPLL_MASK_SD (1<<(12)) +#define OPLL_MASK_BD (1<<(13)) +#define OPLL_MASK_RHYTHM ( OPLL_MASK_HH | OPLL_MASK_CYM | OPLL_MASK_TOM | OPLL_MASK_SD | OPLL_MASK_BD ) + +/* opll */ +typedef struct __OPLL { + + e_uint32 adr ; + e_int32 out ; + +#ifndef EMU2413_COMPACTION + e_uint32 realstep ; + e_uint32 oplltime ; + e_uint32 opllstep ; + e_int32 prev, next ; + e_int32 sprev[2],snext[2]; + e_uint32 pan[16]; +#endif + + /* Register */ + e_uint8 reg[0x40] ; + e_int32 slot_on_flag[18] ; + + /* Pitch Modulator */ + e_uint32 pm_phase ; + e_int32 lfo_pm ; + + /* Amp Modulator */ + e_int32 am_phase ; + e_int32 lfo_am ; + + e_uint32 quality; + + /* Noise Generator */ + e_uint32 noise_seed ; + + /* Channel Data */ + e_int32 patch_number[9]; + e_int32 key_status[9] ; + + /* Slot */ + OPLL_SLOT slot[18] ; + + /* Voice Data */ + OPLL_PATCH patch[19*2] ; + e_int32 patch_update[2] ; /* flag for check patch update */ + + e_uint32 mask ; + e_uint32 current_mask; + e_uint32 status; + + e_uint32 internal_mute; + e_int16 buffer[AUDIO_MONO_BUFFER_SIZE]; +} OPLL ; + +/* Create Object */ +EMU2413_API void OPLL_new(OPLL *, e_uint32 clk, e_uint32 rate) ; +EMU2413_API void OPLL_delete(OPLL *) ; + +/* Setup */ +EMU2413_API void OPLL_reset(OPLL *) ; +EMU2413_API void OPLL_reset_patch(OPLL *, e_int32) ; +EMU2413_API void OPLL_set_rate(OPLL *opll, e_uint32 r) ; +EMU2413_API void OPLL_set_quality(OPLL *opll, e_uint32 q) ; +EMU2413_API void OPLL_set_pan(OPLL *, e_uint32 ch, e_uint32 pan); +EMU2413_API void OPLL_set_internal_mute(OPLL *, e_uint32 mute); +EMU2413_API e_uint32 OPLL_is_internal_muted(OPLL *); + +/* Port/Register access */ +EMU2413_API void OPLL_writeIO(OPLL *, e_uint32 reg, e_uint32 val); +EMU2413_API void OPLL_writeReg(OPLL *, e_uint32 reg, e_uint32 val); +EMU2413_API e_uint32 OPLL_read(OPLL *, e_uint32 port); + +/* Synthsize */ +EMU2413_API e_int16 OPLL_calc(OPLL *) EMU2413_CALC_ICODE; +EMU2413_API void OPLL_calc_stereo(OPLL *, e_int32 out[2]) ; +EMU2413_API e_int16 *OPLL_update_buffer(OPLL *, e_uint32 length) ; + +/* Misc */ +EMU2413_API void OPLL_setPatch(OPLL *, const e_uint8 *dump) ; +EMU2413_API void OPLL_copyPatch(OPLL *, e_int32, OPLL_PATCH *) ; +EMU2413_API void OPLL_forceRefresh(OPLL *) ; +/* Utility */ +EMU2413_API void OPLL_dump2patch(const e_uint8 *dump, OPLL_PATCH *patch) ; +EMU2413_API void OPLL_patch2dump(const OPLL_PATCH *patch, e_uint8 *dump) ; +EMU2413_API void OPLL_getDefaultPatch(e_int32 type, e_int32 num, OPLL_PATCH *) ; + +/* Channel Mask */ +EMU2413_API e_uint32 OPLL_setMask(OPLL *, e_uint32 mask) ; +EMU2413_API e_uint32 OPLL_toggleMask(OPLL *, e_uint32 mask) ; + +#define dump2patch OPLL_dump2patch + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/apps/codecs/libgme/emutables.h b/apps/codecs/libgme/emutables.h index e34f100bc4..739c8c390a 100644 --- a/apps/codecs/libgme/emutables.h +++ b/apps/codecs/libgme/emutables.h @@ -1,210 +1,210 @@ -#ifndef _EMUTABLES_H_ -#define _EMUTABLES_H_ - -/* Precalculated emu2413 tables for use in Rockbox, - Calculated for 44Khz sampling rate */ - -#include "emutypes.h" - -static const e_uint16 sin_coeff[] = { - 255, 203, 171, 152, 139, 129, 120, - 113, 107, 102, 97, 92, 88, 85, - 81, 78, 75, 72, 70, 67, 65, - 63, 61, 59, 57, 55, 53, 52, - 50, 48, 47, 45, 44, 43, 41, - 40, 39, 38, 37, 35, 34, 33, - 32, 31, 30, 29, 28, 28, 27, - 26, 25, 24, 23, 23, 22, 21, - 21, 20, 19, 19, 18, 17, 17, - 16, 16, 15, 14, 14, 13, 13, - 12, 12, 11, 11, 11, 10, 10, - 9, 9, 8, 8, 8, 7, 7, - 7, 6, 6, 6, 5, 5, 5, - 4, 4, 4, 4, 3, 3, 3, - 3, 2, 2, 2, 2, 2, 2, - 1, 1, 1, 1, 1, 1, 1, - 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, - 0, 0, -}; - -static const e_int16 pm_coeff[] = { - 256, 256, 256, 256, 256, 256, 256, - 256, 256, 256, 256, 256, 256, 256, - 256, 256, 256, 256, 256, 256, 256, - 256, 256, 256, 256, 256, 256, 256, - 256, 256, 256, 256, 257, 257, 257, - 257, 257, 257, 257, 257, 257, 257, - 257, 257, 257, 257, 257, 257, 257, - 257, 257, 257, 257, 257, 257, 257, - 257, 257, 257, 257, 257, 257, 257, - 258, 258, 258, 257, 257, 257, 257, - 257, 257, 257, 257, 257, 257, 257, - 257, 257, 257, 257, 257, 257, 257, - 257, 257, 257, 257, 257, 257, 257, - 257, 257, 257, 257, 257, 257, 256, - 256, 256, 256, 256, 256, 256, 256, - 256, 256, 256, 256, 256, 256, 256, - 256, 256, 256, 256, 256, 256, 256, - 256, 256, 256, 256, 256, 256, 256, - 256, 256, 256, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 254, - 254, 254, 254, 254, 254, 254, 254, - 254, 254, 254, 254, 254, 254, 254, - 254, 254, 254, 254, 254, 254, 254, - 254, 254, 254, 254, 254, 254, 254, - 254, 254, 254, 253, 254, 254, 254, - 254, 254, 254, 254, 254, 254, 254, - 254, 254, 254, 254, 254, 254, 254, - 254, 254, 254, 254, 254, 254, 254, - 254, 254, 254, 254, 254, 254, 254, - 254, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, -}; - -static const e_int8 am_coeff[] = { - 13, 13, 13, 13, 13, 14, 14, - 14, 14, 14, 15, 15, 15, 15, - 15, 16, 16, 16, 16, 16, 17, - 17, 17, 17, 17, 18, 18, 18, - 18, 18, 19, 19, 19, 19, 19, - 20, 20, 20, 20, 20, 21, 21, - 21, 21, 21, 22, 22, 22, 22, - 22, 23, 23, 23, 23, 23, 24, - 24, 24, 24, 24, 25, 25, 25, - 25, 26, 25, 25, 25, 25, 24, - 24, 24, 24, 24, 23, 23, 23, - 23, 23, 22, 22, 22, 22, 22, - 21, 21, 21, 21, 21, 20, 20, - 20, 20, 20, 19, 19, 19, 19, - 19, 18, 18, 18, 18, 18, 17, - 17, 17, 17, 17, 16, 16, 16, - 16, 16, 15, 15, 15, 15, 15, - 14, 14, 14, 14, 14, 13, 13, - 13, 13, 13, 12, 12, 12, 12, - 11, 11, 11, 11, 11, 10, 10, - 10, 10, 10, 9, 9, 9, 9, - 9, 8, 8, 8, 8, 8, 7, - 7, 7, 7, 7, 6, 6, 6, - 6, 6, 5, 5, 5, 5, 5, - 4, 4, 4, 4, 4, 3, 3, - 3, 3, 3, 2, 2, 2, 2, - 2, 1, 1, 1, 1, 1, 0, - 0, 0, 0, 0, 0, 0, 0, - 0, 1, 1, 1, 1, 1, 2, - 2, 2, 2, 2, 3, 3, 3, - 3, 3, 4, 4, 4, 4, 4, - 5, 5, 5, 5, 5, 6, 6, - 6, 6, 6, 7, 7, 7, 7, - 7, 8, 8, 8, 8, 8, 9, - 9, 9, 9, 9, 10, 10, 10, - 10, 10, 11, 11, 11, 11, 11, - 12, 12, 12, 12, -}; - -static const e_int16 db2lin_coeff[] = { - 255, 249, 244, 239, 233, 228, 224, - 219, 214, 209, 205, 201, 196, 192, - 188, 184, 180, 176, 172, 169, 165, - 162, 158, 155, 151, 148, 145, 142, - 139, 136, 133, 130, 127, 125, 122, - 119, 117, 114, 112, 109, 107, 105, - 102, 100, 98, 96, 94, 92, 90, - 88, 86, 84, 82, 81, 79, 77, - 76, 74, 72, 71, 69, 68, 66, - 65, 64, 62, 61, 60, 58, 57, - 56, 55, 53, 52, 51, 50, 49, - 48, 47, 46, 45, 44, 43, 42, - 41, 40, 39, 38, 38, 37, 36, - 35, 34, 34, 33, 32, 32, 31, - 30, 30, 29, 28, 28, 27, 27, - 26, 25, 25, 24, 24, 23, 23, - 22, 22, 21, 21, 20, 20, 19, - 19, 19, 18, 18, 17, 17, 17, - 16, 16, 16, 15, 15, 15, 14, - 14, 14, 13, 13, 13, 12, 12, - 12, 12, 11, 11, 11, 11, 10, - 10, 10, 10, 10, 9, 9, 9, - 9, 8, 8, 8, 8, 8, 8, - 7, 7, 7, 7, 7, 7, 6, - 6, 6, 6, 6, 6, 6, 5, - 5, 5, 5, 5, 5, 5, 5, - 5, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, - 2, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 0, 0, - 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, - 0, -}; - -static const e_uint16 ar_adjust_coeff[] = { - 127, 108, 98, 90, 84, 80, 75, - 72, 69, 66, 64, 61, 59, 57, - 56, 54, 52, 51, 49, 48, 47, - 45, 44, 43, 42, 41, 40, 39, - 38, 37, 36, 36, 35, 34, 33, - 33, 32, 31, 30, 30, 29, 29, - 28, 27, 27, 26, 26, 25, 24, - 24, 23, 23, 22, 22, 21, 21, - 21, 20, 20, 19, 19, 18, 18, - 17, 17, 17, 16, 16, 15, 15, - 15, 14, 14, 14, 13, 13, 13, - 12, 12, 12, 11, 11, 11, 10, - 10, 10, 9, 9, 9, 9, 8, - 8, 8, 7, 7, 7, 7, 6, - 6, 6, 6, 5, 5, 5, 4, - 4, 4, 4, 4, 3, 3, 3, - 3, 2, 2, 2, 2, 1, 1, - 1, 1, 1, 0, 0, 0, 0, - 0, -}; - -#endif +#ifndef _EMUTABLES_H_ +#define _EMUTABLES_H_ + +/* Precalculated emu2413 tables for use in Rockbox, + Calculated for 44Khz sampling rate */ + +#include "emutypes.h" + +static const e_uint16 sin_coeff[] = { + 255, 203, 171, 152, 139, 129, 120, + 113, 107, 102, 97, 92, 88, 85, + 81, 78, 75, 72, 70, 67, 65, + 63, 61, 59, 57, 55, 53, 52, + 50, 48, 47, 45, 44, 43, 41, + 40, 39, 38, 37, 35, 34, 33, + 32, 31, 30, 29, 28, 28, 27, + 26, 25, 24, 23, 23, 22, 21, + 21, 20, 19, 19, 18, 17, 17, + 16, 16, 15, 14, 14, 13, 13, + 12, 12, 11, 11, 11, 10, 10, + 9, 9, 8, 8, 8, 7, 7, + 7, 6, 6, 6, 5, 5, 5, + 4, 4, 4, 4, 3, 3, 3, + 3, 2, 2, 2, 2, 2, 2, + 1, 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + 0, 0, +}; + +static const e_int16 pm_coeff[] = { + 256, 256, 256, 256, 256, 256, 256, + 256, 256, 256, 256, 256, 256, 256, + 256, 256, 256, 256, 256, 256, 256, + 256, 256, 256, 256, 256, 256, 256, + 256, 256, 256, 256, 257, 257, 257, + 257, 257, 257, 257, 257, 257, 257, + 257, 257, 257, 257, 257, 257, 257, + 257, 257, 257, 257, 257, 257, 257, + 257, 257, 257, 257, 257, 257, 257, + 258, 258, 258, 257, 257, 257, 257, + 257, 257, 257, 257, 257, 257, 257, + 257, 257, 257, 257, 257, 257, 257, + 257, 257, 257, 257, 257, 257, 257, + 257, 257, 257, 257, 257, 257, 256, + 256, 256, 256, 256, 256, 256, 256, + 256, 256, 256, 256, 256, 256, 256, + 256, 256, 256, 256, 256, 256, 256, + 256, 256, 256, 256, 256, 256, 256, + 256, 256, 256, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 254, + 254, 254, 254, 254, 254, 254, 254, + 254, 254, 254, 254, 254, 254, 254, + 254, 254, 254, 254, 254, 254, 254, + 254, 254, 254, 254, 254, 254, 254, + 254, 254, 254, 253, 254, 254, 254, + 254, 254, 254, 254, 254, 254, 254, + 254, 254, 254, 254, 254, 254, 254, + 254, 254, 254, 254, 254, 254, 254, + 254, 254, 254, 254, 254, 254, 254, + 254, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, +}; + +static const e_int8 am_coeff[] = { + 13, 13, 13, 13, 13, 14, 14, + 14, 14, 14, 15, 15, 15, 15, + 15, 16, 16, 16, 16, 16, 17, + 17, 17, 17, 17, 18, 18, 18, + 18, 18, 19, 19, 19, 19, 19, + 20, 20, 20, 20, 20, 21, 21, + 21, 21, 21, 22, 22, 22, 22, + 22, 23, 23, 23, 23, 23, 24, + 24, 24, 24, 24, 25, 25, 25, + 25, 26, 25, 25, 25, 25, 24, + 24, 24, 24, 24, 23, 23, 23, + 23, 23, 22, 22, 22, 22, 22, + 21, 21, 21, 21, 21, 20, 20, + 20, 20, 20, 19, 19, 19, 19, + 19, 18, 18, 18, 18, 18, 17, + 17, 17, 17, 17, 16, 16, 16, + 16, 16, 15, 15, 15, 15, 15, + 14, 14, 14, 14, 14, 13, 13, + 13, 13, 13, 12, 12, 12, 12, + 11, 11, 11, 11, 11, 10, 10, + 10, 10, 10, 9, 9, 9, 9, + 9, 8, 8, 8, 8, 8, 7, + 7, 7, 7, 7, 6, 6, 6, + 6, 6, 5, 5, 5, 5, 5, + 4, 4, 4, 4, 4, 3, 3, + 3, 3, 3, 2, 2, 2, 2, + 2, 1, 1, 1, 1, 1, 0, + 0, 0, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 1, 1, 2, + 2, 2, 2, 2, 3, 3, 3, + 3, 3, 4, 4, 4, 4, 4, + 5, 5, 5, 5, 5, 6, 6, + 6, 6, 6, 7, 7, 7, 7, + 7, 8, 8, 8, 8, 8, 9, + 9, 9, 9, 9, 10, 10, 10, + 10, 10, 11, 11, 11, 11, 11, + 12, 12, 12, 12, +}; + +static const e_int16 db2lin_coeff[] = { + 255, 249, 244, 239, 233, 228, 224, + 219, 214, 209, 205, 201, 196, 192, + 188, 184, 180, 176, 172, 169, 165, + 162, 158, 155, 151, 148, 145, 142, + 139, 136, 133, 130, 127, 125, 122, + 119, 117, 114, 112, 109, 107, 105, + 102, 100, 98, 96, 94, 92, 90, + 88, 86, 84, 82, 81, 79, 77, + 76, 74, 72, 71, 69, 68, 66, + 65, 64, 62, 61, 60, 58, 57, + 56, 55, 53, 52, 51, 50, 49, + 48, 47, 46, 45, 44, 43, 42, + 41, 40, 39, 38, 38, 37, 36, + 35, 34, 34, 33, 32, 32, 31, + 30, 30, 29, 28, 28, 27, 27, + 26, 25, 25, 24, 24, 23, 23, + 22, 22, 21, 21, 20, 20, 19, + 19, 19, 18, 18, 17, 17, 17, + 16, 16, 16, 15, 15, 15, 14, + 14, 14, 13, 13, 13, 12, 12, + 12, 12, 11, 11, 11, 11, 10, + 10, 10, 10, 10, 9, 9, 9, + 9, 8, 8, 8, 8, 8, 8, + 7, 7, 7, 7, 7, 7, 6, + 6, 6, 6, 6, 6, 6, 5, + 5, 5, 5, 5, 5, 5, 5, + 5, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, + 2, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + 0, +}; + +static const e_uint16 ar_adjust_coeff[] = { + 127, 108, 98, 90, 84, 80, 75, + 72, 69, 66, 64, 61, 59, 57, + 56, 54, 52, 51, 49, 48, 47, + 45, 44, 43, 42, 41, 40, 39, + 38, 37, 36, 36, 35, 34, 33, + 33, 32, 31, 30, 30, 29, 29, + 28, 27, 27, 26, 26, 25, 24, + 24, 23, 23, 22, 22, 21, 21, + 21, 20, 20, 19, 19, 18, 18, + 17, 17, 17, 16, 16, 15, 15, + 15, 14, 14, 14, 13, 13, 13, + 12, 12, 12, 11, 11, 11, 10, + 10, 10, 9, 9, 9, 9, 8, + 8, 8, 7, 7, 7, 7, 6, + 6, 6, 6, 5, 5, 5, 4, + 4, 4, 4, 4, 3, 3, 3, + 3, 2, 2, 2, 2, 1, 1, + 1, 1, 1, 0, 0, 0, 0, + 0, +}; + +#endif diff --git a/apps/codecs/libgme/emutypes.h b/apps/codecs/libgme/emutypes.h index bf5d7e1bf2..bc523db072 100644 --- a/apps/codecs/libgme/emutypes.h +++ b/apps/codecs/libgme/emutypes.h @@ -1,41 +1,41 @@ -#ifndef _EMUTYPES_H_ -#define _EMUTYPES_H_ - -#if defined(_MSC_VER) -#define INLINE __forceinline -#elif defined(__GNUC__) -#define INLINE __inline__ -#elif defined(_MWERKS_) -#define INLINE inline -#else -#define INLINE -#endif - -#if defined(EMU_DLL_IMPORTS) -#define EMU2149_DLL_IMPORTS -#define EMU2212_DLL_IMPORTS -#define EMU2413_DLL_IMPORTS -#define EMU8950_DLL_IMPORTS -#define EMU76489_DLL_IMPORTS -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -typedef unsigned int e_uint; -typedef signed int e_int; - -typedef unsigned char e_uint8 ; -typedef signed char e_int8 ; - -typedef unsigned short e_uint16 ; -typedef signed short e_int16 ; - -typedef unsigned int e_uint32 ; -typedef signed int e_int32 ; - -#ifdef __cplusplus -} -#endif -#endif +#ifndef _EMUTYPES_H_ +#define _EMUTYPES_H_ + +#if defined(_MSC_VER) +#define INLINE __forceinline +#elif defined(__GNUC__) +#define INLINE __inline__ +#elif defined(_MWERKS_) +#define INLINE inline +#else +#define INLINE +#endif + +#if defined(EMU_DLL_IMPORTS) +#define EMU2149_DLL_IMPORTS +#define EMU2212_DLL_IMPORTS +#define EMU2413_DLL_IMPORTS +#define EMU8950_DLL_IMPORTS +#define EMU76489_DLL_IMPORTS +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +typedef unsigned int e_uint; +typedef signed int e_int; + +typedef unsigned char e_uint8 ; +typedef signed char e_int8 ; + +typedef unsigned short e_uint16 ; +typedef signed short e_int16 ; + +typedef unsigned int e_uint32 ; +typedef signed int e_int32 ; + +#ifdef __cplusplus +} +#endif +#endif diff --git a/apps/codecs/libgme/hes_apu_adpcm.c b/apps/codecs/libgme/hes_apu_adpcm.c index 69ac7120d0..de9b894f5d 100644 --- a/apps/codecs/libgme/hes_apu_adpcm.c +++ b/apps/codecs/libgme/hes_apu_adpcm.c @@ -1,297 +1,297 @@ -// Game_Music_Emu 0.6-pre. http://www.slack.net/~ant/ - -#include "hes_apu_adpcm.h" - -/* Copyright (C) 2006-2008 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. This -module 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 Lesser General Public License for more -details. You should have received a copy of the GNU Lesser General Public -License along with this module; if not, write to the Free Software Foundation, -Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ - - -void Adpcm_init( struct Hes_Apu_Adpcm* this ) -{ - this->output = NULL; - memset( &this->state, 0, sizeof( this->state ) ); - Adpcm_reset( this ); -} - -void Adpcm_reset( struct Hes_Apu_Adpcm* this ) -{ - this->last_time = 0; - this->next_timer = 0; - this->last_amp = 0; - - memset( &this->state.pcmbuf, 0, sizeof(this->state.pcmbuf) ); - memset( &this->state.port, 0, sizeof(this->state.port) ); - - this->state.ad_sample = 0; - this->state.ad_ref_index = 0; - - this->state.addr = 0; - this->state.freq = 0; - this->state.writeptr = 0; - this->state.readptr = 0; - this->state.playflag = 0; - this->state.repeatflag = 0; - this->state.length = 0; - this->state.volume = 0xFF; - this->state.fadetimer = 0; - this->state.fadecount = 0; -} - -static short stepsize[49] = { - 16, 17, 19, 21, 23, 25, 28, - 31, 34, 37, 41, 45, 50, 55, - 60, 66, 73, 80, 88, 97, 107, - 118, 130, 143, 157, 173, 190, 209, - 230, 253, 279, 307, 337, 371, 408, - 449, 494, 544, 598, 658, 724, 796, - 876, 963,1060,1166,1282,1411,1552 -}; - -static int Adpcm_decode( struct Hes_Apu_Adpcm* this,int code ); -static int Adpcm_decode( struct Hes_Apu_Adpcm* this,int code ) -{ - struct State* state = &this->state; - int step = stepsize[state->ad_ref_index]; - int delta; - int c = code & 7; -#if 1 - delta = 0; - if ( c & 4 ) delta += step; - step >>= 1; - if ( c & 2 ) delta += step; - step >>= 1; - if ( c & 1 ) delta += step; - step >>= 1; - delta += step; -#else - delta = ( ( c + c + 1 ) * step ) / 8; // maybe faster, but introduces rounding -#endif - if ( c != code ) - { - state->ad_sample -= delta; - if ( state->ad_sample < -2048 ) - state->ad_sample = -2048; - } - else - { - state->ad_sample += delta; - if ( state->ad_sample > 2047 ) - state->ad_sample = 2047; - } - - static int const steps [8] = { - -1, -1, -1, -1, 2, 4, 6, 8 - }; - state->ad_ref_index += steps [c]; - if ( state->ad_ref_index < 0 ) - state->ad_ref_index = 0; - else if ( state->ad_ref_index > 48 ) - state->ad_ref_index = 48; - - return state->ad_sample; -} - -static void Adpcm_run_until( struct Hes_Apu_Adpcm* this, blip_time_t end_time ); -static void Adpcm_run_until( struct Hes_Apu_Adpcm* this, blip_time_t end_time ) -{ - struct State* state = &this->state; - int volume = state->volume; - int fadetimer = state->fadetimer; - int fadecount = state->fadecount; - int last_time = this->last_time; - int next_timer = this->next_timer; - int last_amp = this->last_amp; - - struct Blip_Buffer* output = this->output; // cache often-used values - - while ( state->playflag && last_time < end_time ) - { - while ( last_time >= next_timer ) - { - if ( fadetimer ) - { - if ( fadecount > 0 ) - { - fadecount--; - volume = 0xFF * fadecount / fadetimer; - } - else if ( fadecount < 0 ) - { - fadecount++; - volume = 0xFF - ( 0xFF * fadecount / fadetimer ); - } - } - next_timer += 7159; // 7159091/1000; - } - int amp; - if ( state->ad_low_nibble ) - { - amp = Adpcm_decode( this, state->pcmbuf[ state->playptr ] & 0x0F ); - state->ad_low_nibble = false; - state->playptr++; - state->playedsamplecount++; - if ( state->playedsamplecount == state->playlength ) - { - state->playflag = 0; - } - } - else - { - amp = Adpcm_decode( this, state->pcmbuf[ state->playptr ] >> 4 ); - state->ad_low_nibble = true; - } - amp = amp * volume / 0xFF; - int delta = amp - last_amp; - if ( output && delta ) - { - last_amp = amp; - Synth_offset_inline( &this->synth, last_time, delta, output ); - } - last_time += state->freq; - } - - if ( !state->playflag ) - { - while ( next_timer <= end_time ) next_timer += 7159; // 7159091/1000 - last_time = end_time; - } - - this->last_time = last_time; - this->next_timer = next_timer; - this->last_amp = last_amp; - state->volume = volume; - state->fadetimer = fadetimer; - state->fadecount = fadecount; -} - -void Adpcm_write_data( struct Hes_Apu_Adpcm* this, blip_time_t time, int addr, int data ) -{ - if ( time > this->last_time ) Adpcm_run_until( this, time ); - struct State* state = &this->state; - - data &= 0xFF; - state->port[ addr & 15 ] = data; - switch ( addr & 15 ) - { - case 8: - state->addr &= 0xFF00; - state->addr |= data; - break; - case 9: - state->addr &= 0xFF; - state->addr |= data << 8; - break; - case 10: - state->pcmbuf[ state->writeptr++ ] = data; - state->playlength ++; - break; - case 11: - dprintf("ADPCM DMA 0x%02X", data); - break; - case 13: - if ( data & 0x80 ) - { - state->addr = 0; - state->freq = 0; - state->writeptr = 0; - state->readptr = 0; - state->playflag = 0; - state->repeatflag = 0; - state->length = 0; - state->volume = 0xFF; - } - if ( ( data & 3 ) == 3 ) - { - state->writeptr = state->addr; - } - if ( data & 8 ) - { - state->readptr = state->addr ? state->addr - 1 : state->addr; - } - if ( data & 0x10 ) - { - state->length = state->addr; - } - state->repeatflag = data & 0x20; - state->playflag = data & 0x40; - if ( state->playflag ) - { - state->playptr = state->readptr; - state->playlength = state->length + 1; - state->playedsamplecount = 0; - state->ad_sample = 0; - state->ad_low_nibble = false; - } - break; - case 14: - state->freq = 7159091 / ( 32000 / ( 16 - ( data & 15 ) ) ); - break; - case 15: - switch ( data & 15 ) - { - case 0: - case 8: - case 12: - state->fadetimer = -100; - state->fadecount = state->fadetimer; - break; - case 10: - state->fadetimer = 5000; - state->fadecount = state->fadetimer; - break; - case 14: - state->fadetimer = 1500; - state->fadecount = state->fadetimer; - break; - } - break; - } -} - -int Adpcm_read_data( struct Hes_Apu_Adpcm* this, blip_time_t time, int addr ) -{ - if ( time > this->last_time ) Adpcm_run_until( this, time ); - - struct State* state = &this->state; - switch ( addr & 15 ) - { - case 10: - return state->pcmbuf [state->readptr++]; - case 11: - return state->port [11] & ~1; - case 12: - if (!state->playflag) - { - state->port [12] |= 1; - state->port [12] &= ~8; - } - else - { - state->port [12] &= ~1; - state->port [12] |= 8; - } - return state->port [12]; - case 13: - return state->port [13]; - } - - return 0xFF; -} - -void Adpcm_end_frame( struct Hes_Apu_Adpcm* this, blip_time_t end_time ) -{ - Adpcm_run_until( this, end_time ); - this->last_time -= end_time; - this->next_timer -= end_time; - check( last_time >= 0 ); - if ( this->output ) - Blip_set_modified( this->output ); -} +// Game_Music_Emu 0.6-pre. http://www.slack.net/~ant/ + +#include "hes_apu_adpcm.h" + +/* Copyright (C) 2006-2008 Shay Green. This module is free software; you +can redistribute it and/or modify it under the terms of the GNU Lesser +General Public License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. This +module 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 Lesser General Public License for more +details. You should have received a copy of the GNU Lesser General Public +License along with this module; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ + + +void Adpcm_init( struct Hes_Apu_Adpcm* this ) +{ + this->output = NULL; + memset( &this->state, 0, sizeof( this->state ) ); + Adpcm_reset( this ); +} + +void Adpcm_reset( struct Hes_Apu_Adpcm* this ) +{ + this->last_time = 0; + this->next_timer = 0; + this->last_amp = 0; + + memset( &this->state.pcmbuf, 0, sizeof(this->state.pcmbuf) ); + memset( &this->state.port, 0, sizeof(this->state.port) ); + + this->state.ad_sample = 0; + this->state.ad_ref_index = 0; + + this->state.addr = 0; + this->state.freq = 0; + this->state.writeptr = 0; + this->state.readptr = 0; + this->state.playflag = 0; + this->state.repeatflag = 0; + this->state.length = 0; + this->state.volume = 0xFF; + this->state.fadetimer = 0; + this->state.fadecount = 0; +} + +static short stepsize[49] = { + 16, 17, 19, 21, 23, 25, 28, + 31, 34, 37, 41, 45, 50, 55, + 60, 66, 73, 80, 88, 97, 107, + 118, 130, 143, 157, 173, 190, 209, + 230, 253, 279, 307, 337, 371, 408, + 449, 494, 544, 598, 658, 724, 796, + 876, 963,1060,1166,1282,1411,1552 +}; + +static int Adpcm_decode( struct Hes_Apu_Adpcm* this,int code ); +static int Adpcm_decode( struct Hes_Apu_Adpcm* this,int code ) +{ + struct State* state = &this->state; + int step = stepsize[state->ad_ref_index]; + int delta; + int c = code & 7; +#if 1 + delta = 0; + if ( c & 4 ) delta += step; + step >>= 1; + if ( c & 2 ) delta += step; + step >>= 1; + if ( c & 1 ) delta += step; + step >>= 1; + delta += step; +#else + delta = ( ( c + c + 1 ) * step ) / 8; // maybe faster, but introduces rounding +#endif + if ( c != code ) + { + state->ad_sample -= delta; + if ( state->ad_sample < -2048 ) + state->ad_sample = -2048; + } + else + { + state->ad_sample += delta; + if ( state->ad_sample > 2047 ) + state->ad_sample = 2047; + } + + static int const steps [8] = { + -1, -1, -1, -1, 2, 4, 6, 8 + }; + state->ad_ref_index += steps [c]; + if ( state->ad_ref_index < 0 ) + state->ad_ref_index = 0; + else if ( state->ad_ref_index > 48 ) + state->ad_ref_index = 48; + + return state->ad_sample; +} + +static void Adpcm_run_until( struct Hes_Apu_Adpcm* this, blip_time_t end_time ); +static void Adpcm_run_until( struct Hes_Apu_Adpcm* this, blip_time_t end_time ) +{ + struct State* state = &this->state; + int volume = state->volume; + int fadetimer = state->fadetimer; + int fadecount = state->fadecount; + int last_time = this->last_time; + int next_timer = this->next_timer; + int last_amp = this->last_amp; + + struct Blip_Buffer* output = this->output; // cache often-used values + + while ( state->playflag && last_time < end_time ) + { + while ( last_time >= next_timer ) + { + if ( fadetimer ) + { + if ( fadecount > 0 ) + { + fadecount--; + volume = 0xFF * fadecount / fadetimer; + } + else if ( fadecount < 0 ) + { + fadecount++; + volume = 0xFF - ( 0xFF * fadecount / fadetimer ); + } + } + next_timer += 7159; // 7159091/1000; + } + int amp; + if ( state->ad_low_nibble ) + { + amp = Adpcm_decode( this, state->pcmbuf[ state->playptr ] & 0x0F ); + state->ad_low_nibble = false; + state->playptr++; + state->playedsamplecount++; + if ( state->playedsamplecount == state->playlength ) + { + state->playflag = 0; + } + } + else + { + amp = Adpcm_decode( this, state->pcmbuf[ state->playptr ] >> 4 ); + state->ad_low_nibble = true; + } + amp = amp * volume / 0xFF; + int delta = amp - last_amp; + if ( output && delta ) + { + last_amp = amp; + Synth_offset_inline( &this->synth, last_time, delta, output ); + } + last_time += state->freq; + } + + if ( !state->playflag ) + { + while ( next_timer <= end_time ) next_timer += 7159; // 7159091/1000 + last_time = end_time; + } + + this->last_time = last_time; + this->next_timer = next_timer; + this->last_amp = last_amp; + state->volume = volume; + state->fadetimer = fadetimer; + state->fadecount = fadecount; +} + +void Adpcm_write_data( struct Hes_Apu_Adpcm* this, blip_time_t time, int addr, int data ) +{ + if ( time > this->last_time ) Adpcm_run_until( this, time ); + struct State* state = &this->state; + + data &= 0xFF; + state->port[ addr & 15 ] = data; + switch ( addr & 15 ) + { + case 8: + state->addr &= 0xFF00; + state->addr |= data; + break; + case 9: + state->addr &= 0xFF; + state->addr |= data << 8; + break; + case 10: + state->pcmbuf[ state->writeptr++ ] = data; + state->playlength ++; + break; + case 11: + dprintf("ADPCM DMA 0x%02X", data); + break; + case 13: + if ( data & 0x80 ) + { + state->addr = 0; + state->freq = 0; + state->writeptr = 0; + state->readptr = 0; + state->playflag = 0; + state->repeatflag = 0; + state->length = 0; + state->volume = 0xFF; + } + if ( ( data & 3 ) == 3 ) + { + state->writeptr = state->addr; + } + if ( data & 8 ) + { + state->readptr = state->addr ? state->addr - 1 : state->addr; + } + if ( data & 0x10 ) + { + state->length = state->addr; + } + state->repeatflag = data & 0x20; + state->playflag = data & 0x40; + if ( state->playflag ) + { + state->playptr = state->readptr; + state->playlength = state->length + 1; + state->playedsamplecount = 0; + state->ad_sample = 0; + state->ad_low_nibble = false; + } + break; + case 14: + state->freq = 7159091 / ( 32000 / ( 16 - ( data & 15 ) ) ); + break; + case 15: + switch ( data & 15 ) + { + case 0: + case 8: + case 12: + state->fadetimer = -100; + state->fadecount = state->fadetimer; + break; + case 10: + state->fadetimer = 5000; + state->fadecount = state->fadetimer; + break; + case 14: + state->fadetimer = 1500; + state->fadecount = state->fadetimer; + break; + } + break; + } +} + +int Adpcm_read_data( struct Hes_Apu_Adpcm* this, blip_time_t time, int addr ) +{ + if ( time > this->last_time ) Adpcm_run_until( this, time ); + + struct State* state = &this->state; + switch ( addr & 15 ) + { + case 10: + return state->pcmbuf [state->readptr++]; + case 11: + return state->port [11] & ~1; + case 12: + if (!state->playflag) + { + state->port [12] |= 1; + state->port [12] &= ~8; + } + else + { + state->port [12] &= ~1; + state->port [12] |= 8; + } + return state->port [12]; + case 13: + return state->port [13]; + } + + return 0xFF; +} + +void Adpcm_end_frame( struct Hes_Apu_Adpcm* this, blip_time_t end_time ) +{ + Adpcm_run_until( this, end_time ); + this->last_time -= end_time; + this->next_timer -= end_time; + check( last_time >= 0 ); + if ( this->output ) + Blip_set_modified( this->output ); +} diff --git a/apps/codecs/libgme/inflate/mbreader.c b/apps/codecs/libgme/inflate/mbreader.c index 96e45cd6c8..825787927c 100644 --- a/apps/codecs/libgme/inflate/mbreader.c +++ b/apps/codecs/libgme/inflate/mbreader.c @@ -1,16 +1,16 @@ - -/* Memory buffer reader, simulates file read - @ gama -*/ - -#include "mbreader.h" - -int mbread(struct mbreader_t *md, void *buf, size_t n) -{ - if (!md) return -1; - size_t read_bytes = (md->offset+n) > md->size ? - md->size-md->offset : n; - memcpy(buf,md->ptr + md->offset,read_bytes); - md->offset += read_bytes; - return read_bytes; -} + +/* Memory buffer reader, simulates file read + @ gama +*/ + +#include "mbreader.h" + +int mbread(struct mbreader_t *md, void *buf, size_t n) +{ + if (!md) return -1; + size_t read_bytes = (md->offset+n) > md->size ? + md->size-md->offset : n; + memcpy(buf,md->ptr + md->offset,read_bytes); + md->offset += read_bytes; + return read_bytes; +} diff --git a/apps/codecs/libgme/inflate/mbreader.h b/apps/codecs/libgme/inflate/mbreader.h index 6427f18231..d345c0c424 100644 --- a/apps/codecs/libgme/inflate/mbreader.h +++ b/apps/codecs/libgme/inflate/mbreader.h @@ -1,15 +1,15 @@ - -#ifndef MBREADER_H -#define MBREADER_H - -#include "codeclib.h" - -struct mbreader_t { - const char *ptr; - size_t size; - size_t offset; -}; - -int mbread(struct mbreader_t *md, void *buf, size_t n); - -#endif + +#ifndef MBREADER_H +#define MBREADER_H + +#include "codeclib.h" + +struct mbreader_t { + const char *ptr; + size_t size; + size_t offset; +}; + +int mbread(struct mbreader_t *md, void *buf, size_t n); + +#endif diff --git a/apps/codecs/libgme/kss_cpu.c b/apps/codecs/libgme/kss_cpu.c index 891a7df255..20601e608f 100644 --- a/apps/codecs/libgme/kss_cpu.c +++ b/apps/codecs/libgme/kss_cpu.c @@ -1,35 +1,35 @@ -// Game_Music_Emu 0.6-pre. http://www.slack.net/~ant/ - -#include "kss_emu.h" - -#include "blargg_endian.h" -//#include "z80_cpu_log.h" - -/* Copyright (C) 2006-2008 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. This -module 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 Lesser General Public License for more -details. You should have received a copy of the GNU Lesser General Public -License along with this module; if not, write to the Free Software Foundation, -Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ - -#include "blargg_source.h" - -#define OUT_PORT( addr, data ) cpu_out( this, TIME(), addr, data ) -#define IN_PORT( addr ) cpu_in( this, TIME(), addr ) -#define WRITE_MEM( addr, data ) {FLUSH_TIME(); cpu_write( this, addr, data );} -#define IDLE_ADDR idle_addr - -#define CPU_BEGIN \ -bool run_cpu( struct Kss_Emu* this, kss_time_t end_time )\ -{\ - struct Z80_Cpu *cpu = &this->cpu; \ - Z80_set_end_time( cpu, end_time ); - - #include "z80_cpu_run.h" - - return warning; -} +// Game_Music_Emu 0.6-pre. http://www.slack.net/~ant/ + +#include "kss_emu.h" + +#include "blargg_endian.h" +//#include "z80_cpu_log.h" + +/* Copyright (C) 2006-2008 Shay Green. This module is free software; you +can redistribute it and/or modify it under the terms of the GNU Lesser +General Public License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. This +module 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 Lesser General Public License for more +details. You should have received a copy of the GNU Lesser General Public +License along with this module; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ + +#include "blargg_source.h" + +#define OUT_PORT( addr, data ) cpu_out( this, TIME(), addr, data ) +#define IN_PORT( addr ) cpu_in( this, TIME(), addr ) +#define WRITE_MEM( addr, data ) {FLUSH_TIME(); cpu_write( this, addr, data );} +#define IDLE_ADDR idle_addr + +#define CPU_BEGIN \ +bool run_cpu( struct Kss_Emu* this, kss_time_t end_time )\ +{\ + struct Z80_Cpu *cpu = &this->cpu; \ + Z80_set_end_time( cpu, end_time ); + + #include "z80_cpu_run.h" + + return warning; +} diff --git a/apps/codecs/libgme/nes_cpu_run.h b/apps/codecs/libgme/nes_cpu_run.h index 5b964d5070..fd1fea9659 100644 --- a/apps/codecs/libgme/nes_cpu_run.h +++ b/apps/codecs/libgme/nes_cpu_run.h @@ -1,1122 +1,1122 @@ -// NES 6502 cpu emulator run function - -#if 0 -/* Define these macros in the source file before #including this file. -- Parameters might be expressions, so they are best evaluated only once, -though they NEVER have side-effects, so multiple evaluation is OK. -- Output parameters might be a multiple-assignment expression like "a=x", -so they must NOT be parenthesized. -- Except where noted, time() and related functions will NOT work -correctly inside a macro. TIME() is always correct, and FLUSH_TIME() and -CACHE_TIME() allow the time changing functions to work. -- Macros "returning" void may use a {} statement block. */ - - // 0 <= addr <= 0xFFFF + page_size - // time functions can be used - int READ_MEM( addr_t ); - void WRITE_MEM( addr_t, int data ); - // 0 <= READ_MEM() <= 0xFF - - // 0 <= addr <= 0x1FF - int READ_LOW( addr_t ); - void WRITE_LOW( addr_t, int data ); - // 0 <= READ_LOW() <= 0xFF - - // Often-used instructions attempt these before using a normal memory access. - // Optional; defaults to READ_MEM() and WRITE_MEM() - bool CAN_READ_FAST( addr_t ); // if true, uses result of READ_FAST - void READ_FAST( addr_t, int& out ); // ALWAYS called BEFORE CAN_READ_FAST - bool CAN_WRITE_FAST( addr_t ); // if true, uses WRITE_FAST instead of WRITE_MEM - void WRITE_FAST( addr_t, int data ); - - // Used by instructions most often used to access the NES PPU (LDA abs and BIT abs). - // Optional; defaults to READ_MEM. - void READ_PPU( addr_t, int& out ); - // 0 <= out <= 0xFF - -// The following can be used within macros: - - // Current time - time_t TIME(); - - // Allows use of time functions - void FLUSH_TIME(); - - // Must be used before end of macro if FLUSH_TIME() was used earlier - void CACHE_TIME(); - -// Configuration (optional; commented behavior if defined) - - // Emulates dummy reads for indexed instructions - #define NES_CPU_DUMMY_READS 1 - - // Optimizes as if map_code( 0, 0x10000 + cpu_padding, FLAT_MEM ) is always in effect - #define FLAT_MEM my_mem_array - - // Expanded just before beginning of code, to help debugger - #define CPU_BEGIN void my_run_cpu() { - -#endif - -/* Copyright (C) 2003-2008 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. This -module 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 Lesser General Public License for more -details. You should have received a copy of the GNU Lesser General Public -License along with this module; if not, write to the Free Software Foundation, -Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ - -// Allows MWCW debugger to step through code properly -#ifdef CPU_BEGIN - CPU_BEGIN -#endif - -// Time -#define TIME() (s_time + s.base) -#define FLUSH_TIME() {s.time = s_time - time_offset;} -#define CACHE_TIME() {s_time = s.time + time_offset;} - -// Defaults -#ifndef CAN_WRITE_FAST - #define CAN_WRITE_FAST( addr ) 0 - #define WRITE_FAST( addr, data ) -#endif - -#ifndef CAN_READ_FAST - #define CAN_READ_FAST( addr ) 0 - #define READ_FAST( addr, out ) -#endif - -#ifndef READ_PPU - #define READ_PPU( addr, out )\ - {\ - FLUSH_TIME();\ - out = READ_MEM( addr );\ - CACHE_TIME();\ - } -#endif - -#define READ_STACK READ_LOW -#define WRITE_STACK WRITE_LOW - -// Dummy reads -#ifdef NES_CPU_DUMMY_READS - // TODO: optimize time handling - #define DUMMY_READ( addr, idx ) \ - if ( (addr & 0xFF) < idx )\ - {\ - int const time_offset = 1;\ - FLUSH_TIME();\ - READ_MEM( (addr - 0x100) );\ - CACHE_TIME();\ - } -#else - #define DUMMY_READ( addr, idx ) -#endif - -// Code -#ifdef FLAT_MEM - #define CODE_PAGE( addr ) (FLAT_MEM) - #define CODE_OFFSET( addr ) (addr) -#else - #define CODE_PAGE( addr ) (s.code_map [NES_CPU_PAGE( addr )]) - #define CODE_OFFSET( addr ) NES_CPU_OFFSET( addr ) -#endif -#define READ_CODE( addr ) (CODE_PAGE( addr ) [CODE_OFFSET( addr )]) - -// Stack -#define SET_SP( v ) (sp = ((v) + 1) | 0x100) -#define GET_SP() ((sp - 1) & 0xFF) -#define SP( o ) ((sp + (o - (o>0)*0x100)) | 0x100) - -// Truncation -#define BYTE( n ) ((uint8_t ) (n)) /* (unsigned) n & 0xFF */ -#define SBYTE( n ) ((int8_t ) (n)) /* (BYTE( n ) ^ 0x80) - 0x80 */ -#define WORD( n ) ((uint16_t) (n)) /* (unsigned) n & 0xFFFF */ - -// Flags with hex value for clarity when used as mask. -// Stored in indicated variable during emulation. -int const n80 = 0x80; // nz -int const v40 = 0x40; // flags -int const r20 = 0x20; -int const b10 = 0x10; -int const d08 = 0x08; // flags -int const i04 = 0x04; // flags -int const z02 = 0x02; // nz -int const c01 = 0x01; // c - -#define IS_NEG (nz & 0x8080) - -#define GET_FLAGS( out ) \ -{\ - out = flags & (v40 | d08 | i04);\ - out += ((nz >> 8) | nz) & n80;\ - out += c >> 8 & c01;\ - if ( !BYTE( nz ) )\ - out += z02;\ -} - -#define SET_FLAGS( in ) \ -{\ - flags = in & (v40 | d08 | i04);\ - c = nz = in << 8;\ - nz += ~in & z02;\ -} - -{ - int const time_offset = 0; - - // Local state - struct cpu_state_t s; - #ifdef FLAT_MEM - s.base = cpu->cpu_state_.base; - #else - s = cpu->cpu_state_; - #endif - cpu->cpu_state = &s; - int s_time = cpu->cpu_state_.time; // helps even on x86 - - // Registers - int pc = cpu->r.pc; - int a = cpu->r.a; - int x = cpu->r.x; - int y = cpu->r.y; - int sp; - SET_SP( cpu->r.sp ); - - // Flags - int flags; - int c; // carry set if (c & 0x100) != 0 - int nz; // Z set if (nz & 0xFF) == 0, N set if (nz & 0x8080) != 0 - { - int temp = cpu->r.flags; - SET_FLAGS( temp ); - } - -loop: - - // Check all values - check( (unsigned) sp - 0x100 < 0x100 ); - check( (unsigned) pc < 0x10000 ); - check( (unsigned) a < 0x100 ); - check( (unsigned) x < 0x100 ); - check( (unsigned) y < 0x100 ); - - // Read instruction - byte const* instr = CODE_PAGE( pc ); - int opcode; - - if ( CODE_OFFSET(~0) == ~0 ) - { - opcode = instr [pc]; - pc++; - instr += pc; - } - else - { - instr += CODE_OFFSET( pc ); - opcode = *instr++; - pc++; - } - - // local to function in case it helps optimizer - static byte const clock_table [256] = - {// 0 1 2 3 4 5 6 7 8 9 A B C D E F - 0,6,2,8,3,3,5,5,3,2,2,2,4,4,6,6,// 0 - 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,// 1 - 6,6,0,8,3,3,5,5,4,2,2,2,4,4,6,6,// 2 - 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,// 3 - 6,6,2,8,3,3,5,5,3,2,2,2,3,4,6,6,// 4 - 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,// 5 - 6,6,2,8,3,3,5,5,4,2,2,2,5,4,6,6,// 6 - 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,// 7 - 2,6,2,6,3,3,3,3,2,2,2,2,4,4,4,4,// 8 - 2,6,2,6,4,4,4,4,2,5,2,5,5,5,5,5,// 9 - 2,6,2,6,3,3,3,3,2,2,2,2,4,4,4,4,// A - 2,5,2,5,4,4,4,4,2,4,2,4,4,4,4,4,// B - 2,6,2,8,3,3,5,5,2,2,2,2,4,4,6,6,// C - 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,// D - 2,6,2,8,3,3,5,5,2,2,2,2,4,4,6,6,// E - 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7 // F - }; // 0x00 was 7 and 0x22 was 2 - - // Update time - if ( s_time >= 0 ) - goto out_of_time; - - #ifdef CPU_INSTR_HOOK - { CPU_INSTR_HOOK( (pc-1), (&instr [-1]), a, x, y, GET_SP(), TIME() ); } - #endif - - s_time += clock_table [opcode]; - - int data; - data = *instr; - - switch ( opcode ) - { - -// Macros - -#define GET_MSB() (instr [1]) -#define ADD_PAGE( out ) (pc++, out = data + 0x100 * GET_MSB()) -#define GET_ADDR() GET_LE16( instr ) - -#define PAGE_PENALTY( lsb ) s_time += (lsb) >> 8; - -#define INC_DEC( reg, n ) reg = BYTE( nz = reg + n ); goto loop; - -#define IND_Y( cross, out ) {\ - int temp = READ_LOW( data ) + y;\ - out = temp + 0x100 * READ_LOW( BYTE( data + 1 ) );\ - cross( temp );\ - } - -#define IND_X( out ) {\ - int temp = data + x;\ - out = 0x100 * READ_LOW( BYTE( temp + 1 ) ) + READ_LOW( BYTE( temp ) );\ - } - -#define ARITH_ADDR_MODES( op )\ -case op - 0x04: /* (ind,x) */\ - IND_X( data )\ - goto ptr##op;\ -case op + 0x0C: /* (ind),y */\ - IND_Y( PAGE_PENALTY, data )\ - goto ptr##op;\ -case op + 0x10: /* zp,X */\ - data = BYTE( data + x );\ -case op + 0x00: /* zp */\ - data = READ_LOW( data );\ - goto imm##op;\ -case op + 0x14: /* abs,Y */\ - data += y;\ - goto ind##op;\ -case op + 0x18: /* abs,X */\ - data += x;\ -ind##op:\ - PAGE_PENALTY( data );\ -case op + 0x08: /* abs */\ - ADD_PAGE( data );\ -ptr##op:\ - FLUSH_TIME();\ - data = READ_MEM( data );\ - CACHE_TIME();\ -case op + 0x04: /* imm */\ -imm##op: - -// TODO: more efficient way to handle negative branch that wraps PC around -#define BRANCH( cond )\ -{\ - ++pc;\ - if ( !(cond) ) goto loop;\ - s_time++;\ - int offset = SBYTE( data );\ - s_time += (BYTE(pc) + offset) >> 8 & 1;\ - pc = WORD( pc + offset );\ - goto loop;\ -} - -// Often-Used - - case 0xB5: // LDA zp,x - a = nz = READ_LOW( BYTE( data + x ) ); - pc++; - goto loop; - - case 0xA5: // LDA zp - a = nz = READ_LOW( data ); - pc++; - goto loop; - - case 0xD0: // BNE - BRANCH( BYTE( nz ) ); - - case 0x20: { // JSR - int temp = pc + 1; - pc = GET_ADDR(); - WRITE_STACK( SP( -1 ), temp >> 8 ); - sp = SP( -2 ); - WRITE_STACK( sp, temp ); - goto loop; - } - - case 0x4C: // JMP abs - pc = GET_ADDR(); - goto loop; - - case 0xE8: // INX - INC_DEC( x, 1 ) - - case 0x10: // BPL - BRANCH( !IS_NEG ) - - ARITH_ADDR_MODES( 0xC5 ) // CMP - nz = a - data; - pc++; - c = ~nz; - nz &= 0xFF; - goto loop; - - case 0x30: // BMI - BRANCH( IS_NEG ) - - case 0xF0: // BEQ - BRANCH( !BYTE( nz ) ); - - case 0x95: // STA zp,x - data = BYTE( data + x ); - case 0x85: // STA zp - pc++; - WRITE_LOW( data, a ); - goto loop; - - case 0xC8: // INY - INC_DEC( y, 1 ) - - case 0xA8: // TAY - y = a; - nz = a; - goto loop; - - case 0x98: // TYA - a = y; - nz = y; - goto loop; - - case 0xAD:{// LDA abs - int addr = GET_ADDR(); - pc += 2; - READ_PPU( addr, a = nz ); - goto loop; - } - - case 0x60: // RTS - pc = 1 + READ_STACK( sp ); - pc += 0x100 * READ_STACK( SP( 1 ) ); - sp = SP( 2 ); - goto loop; - - { - int addr; - - case 0x8D: // STA abs - addr = GET_ADDR(); - pc += 2; - if ( CAN_WRITE_FAST( addr ) ) - { - WRITE_FAST( addr, a ); - goto loop; - } - sta_ptr: - FLUSH_TIME(); - WRITE_MEM( addr, a ); - CACHE_TIME(); - goto loop; - - case 0x99: // STA abs,Y - addr = y + GET_ADDR(); - pc += 2; - if ( CAN_WRITE_FAST( addr ) ) - { - WRITE_FAST( addr, a ); - goto loop; - } - goto sta_abs_x; - - case 0x9D: // STA abs,X (slightly more common than STA abs) - addr = x + GET_ADDR(); - pc += 2; - if ( CAN_WRITE_FAST( addr ) ) - { - WRITE_FAST( addr, a ); - goto loop; - } - DUMMY_READ( addr, x ); - sta_abs_x: - FLUSH_TIME(); - WRITE_MEM( addr, a ); - CACHE_TIME(); - goto loop; - - case 0x91: // STA (ind),Y - #define NO_PAGE_PENALTY( lsb ) - IND_Y( NO_PAGE_PENALTY, addr ) - pc++; - DUMMY_READ( addr, y ); - goto sta_ptr; - - case 0x81: // STA (ind,X) - IND_X( addr ) - pc++; - goto sta_ptr; - - } - - case 0xA9: // LDA #imm - pc++; - a = data; - nz = data; - goto loop; - - // common read instructions - { - int addr; - - case 0xA1: // LDA (ind,X) - IND_X( addr ) - pc++; - goto a_nz_read_addr; - - case 0xB1:// LDA (ind),Y - addr = READ_LOW( data ) + y; - PAGE_PENALTY( addr ); - addr += 0x100 * READ_LOW( BYTE( data + 1 ) ); - pc++; - READ_FAST( addr, a = nz ); - if ( CAN_READ_FAST( addr ) ) - goto loop; - DUMMY_READ( addr, y ); - goto a_nz_read_addr; - - case 0xB9: // LDA abs,Y - PAGE_PENALTY( data + y ); - addr = GET_ADDR() + y; - pc += 2; - READ_FAST( addr, a = nz ); - if ( CAN_READ_FAST( addr ) ) - goto loop; - goto a_nz_read_addr; - - case 0xBD: // LDA abs,X - PAGE_PENALTY( data + x ); - addr = GET_ADDR() + x; - pc += 2; - READ_FAST( addr, a = nz ); - if ( CAN_READ_FAST( addr ) ) - goto loop; - DUMMY_READ( addr, x ); - a_nz_read_addr: - FLUSH_TIME(); - a = nz = READ_MEM( addr ); - CACHE_TIME(); - goto loop; - - } - -// Branch - - case 0x50: // BVC - BRANCH( !(flags & v40) ) - - case 0x70: // BVS - BRANCH( flags & v40 ) - - case 0xB0: // BCS - BRANCH( c & 0x100 ) - - case 0x90: // BCC - BRANCH( !(c & 0x100) ) - -// Load/store - - case 0x94: // STY zp,x - data = BYTE( data + x ); - case 0x84: // STY zp - pc++; - WRITE_LOW( data, y ); - goto loop; - - case 0x96: // STX zp,y - data = BYTE( data + y ); - case 0x86: // STX zp - pc++; - WRITE_LOW( data, x ); - goto loop; - - case 0xB6: // LDX zp,y - data = BYTE( data + y ); - case 0xA6: // LDX zp - data = READ_LOW( data ); - case 0xA2: // LDX #imm - pc++; - x = data; - nz = data; - goto loop; - - case 0xB4: // LDY zp,x - data = BYTE( data + x ); - case 0xA4: // LDY zp - data = READ_LOW( data ); - case 0xA0: // LDY #imm - pc++; - y = data; - nz = data; - goto loop; - - case 0xBC: // LDY abs,X - data += x; - PAGE_PENALTY( data ); - case 0xAC:{// LDY abs - int addr = data + 0x100 * GET_MSB(); - pc += 2; - FLUSH_TIME(); - y = nz = READ_MEM( addr ); - CACHE_TIME(); - goto loop; - } - - case 0xBE: // LDX abs,y - data += y; - PAGE_PENALTY( data ); - case 0xAE:{// LDX abs - int addr = data + 0x100 * GET_MSB(); - pc += 2; - FLUSH_TIME(); - x = nz = READ_MEM( addr ); - CACHE_TIME(); - goto loop; - } - - { - int temp; - case 0x8C: // STY abs - temp = y; - goto store_abs; - - case 0x8E: // STX abs - temp = x; - store_abs: - { - int addr = GET_ADDR(); - pc += 2; - if ( CAN_WRITE_FAST( addr ) ) - { - WRITE_FAST( addr, temp ); - goto loop; - } - FLUSH_TIME(); - WRITE_MEM( addr, temp ); - CACHE_TIME(); - goto loop; - } - } - -// Compare - - case 0xEC: {// CPX abs - int addr = GET_ADDR(); - pc++; - FLUSH_TIME(); - data = READ_MEM( addr ); - CACHE_TIME(); - goto cpx_data; - } - - case 0xE4: // CPX zp - data = READ_LOW( data ); - case 0xE0: // CPX #imm - cpx_data: - nz = x - data; - pc++; - c = ~nz; - nz &= 0xFF; - goto loop; - - case 0xCC:{// CPY abs - int addr = GET_ADDR(); - pc++; - FLUSH_TIME(); - data = READ_MEM( addr ); - CACHE_TIME(); - goto cpy_data; - } - - case 0xC4: // CPY zp - data = READ_LOW( data ); - case 0xC0: // CPY #imm - cpy_data: - nz = y - data; - pc++; - c = ~nz; - nz &= 0xFF; - goto loop; - -// Logical - - ARITH_ADDR_MODES( 0x25 ) // AND - nz = (a &= data); - pc++; - goto loop; - - ARITH_ADDR_MODES( 0x45 ) // EOR - nz = (a ^= data); - pc++; - goto loop; - - ARITH_ADDR_MODES( 0x05 ) // ORA - nz = (a |= data); - pc++; - goto loop; - - case 0x2C:{// BIT abs - int addr = GET_ADDR(); - pc += 2; - READ_PPU( addr, nz ); - flags = (flags & ~v40) + (nz & v40); - if ( a & nz ) - goto loop; - nz <<= 8; // result must be zero, even if N bit is set - goto loop; - } - - case 0x24: // BIT zp - nz = READ_LOW( data ); - pc++; - flags = (flags & ~v40) + (nz & v40); - if ( a & nz ) - goto loop; // Z should be clear, and nz must be non-zero if nz & a is - nz <<= 8; // set Z flag without affecting N flag - goto loop; - -// Add/subtract - - ARITH_ADDR_MODES( 0xE5 ) // SBC - case 0xEB: // unofficial equivalent - data ^= 0xFF; - goto adc_imm; - - ARITH_ADDR_MODES( 0x65 ) // ADC - adc_imm: { - int carry = c >> 8 & 1; - int ov = (a ^ 0x80) + carry + SBYTE( data ); - flags = (flags & ~v40) + (ov >> 2 & v40); - c = nz = a + data + carry; - pc++; - a = BYTE( nz ); - goto loop; - } - -// Shift/rotate - - case 0x4A: // LSR A - c = 0; - case 0x6A: // ROR A - nz = c >> 1 & 0x80; - c = a << 8; - nz += a >> 1; - a = nz; - goto loop; - - case 0x0A: // ASL A - nz = a << 1; - c = nz; - a = BYTE( nz ); - goto loop; - - case 0x2A: { // ROL A - nz = a << 1; - int temp = c >> 8 & 1; - c = nz; - nz += temp; - a = BYTE( nz ); - goto loop; - } - - case 0x5E: // LSR abs,X - data += x; - case 0x4E: // LSR abs - c = 0; - case 0x6E: // ROR abs - ror_abs: { - ADD_PAGE( data ); - FLUSH_TIME(); - int temp = READ_MEM( data ); - nz = (c >> 1 & 0x80) + (temp >> 1); - c = temp << 8; - goto rotate_common; - } - - case 0x3E: // ROL abs,X - data += x; - goto rol_abs; - - case 0x1E: // ASL abs,X - data += x; - case 0x0E: // ASL abs - c = 0; - case 0x2E: // ROL abs - rol_abs: - ADD_PAGE( data ); - nz = c >> 8 & 1; - FLUSH_TIME(); - nz += (c = READ_MEM( data ) << 1); - rotate_common: - pc++; - WRITE_MEM( data, BYTE( nz ) ); - CACHE_TIME(); - goto loop; - - case 0x7E: // ROR abs,X - data += x; - goto ror_abs; - - case 0x76: // ROR zp,x - data = BYTE( data + x ); - goto ror_zp; - - case 0x56: // LSR zp,x - data = BYTE( data + x ); - case 0x46: // LSR zp - c = 0; - case 0x66: // ROR zp - ror_zp: { - int temp = READ_LOW( data ); - nz = (c >> 1 & 0x80) + (temp >> 1); - c = temp << 8; - goto write_nz_zp; - } - - case 0x36: // ROL zp,x - data = BYTE( data + x ); - goto rol_zp; - - case 0x16: // ASL zp,x - data = BYTE( data + x ); - case 0x06: // ASL zp - c = 0; - case 0x26: // ROL zp - rol_zp: - nz = c >> 8 & 1; - nz += (c = READ_LOW( data ) << 1); - goto write_nz_zp; - -// Increment/decrement - - case 0xCA: // DEX - INC_DEC( x, -1 ) - - case 0x88: // DEY - INC_DEC( y, -1 ) - - case 0xF6: // INC zp,x - data = BYTE( data + x ); - case 0xE6: // INC zp - nz = 1; - goto add_nz_zp; - - case 0xD6: // DEC zp,x - data = BYTE( data + x ); - case 0xC6: // DEC zp - nz = -1; - add_nz_zp: - nz += READ_LOW( data ); - write_nz_zp: - pc++; - WRITE_LOW( data, nz ); - goto loop; - - case 0xFE: // INC abs,x - data = x + GET_ADDR(); - goto inc_ptr; - - case 0xEE: // INC abs - data = GET_ADDR(); - inc_ptr: - nz = 1; - goto inc_common; - - case 0xDE: // DEC abs,x - data = x + GET_ADDR(); - goto dec_ptr; - - case 0xCE: // DEC abs - data = GET_ADDR(); - dec_ptr: - nz = -1; - inc_common: - FLUSH_TIME(); - pc += 2; - nz += READ_MEM( data ); - WRITE_MEM( data, BYTE( nz ) ); - CACHE_TIME(); - goto loop; - -// Transfer - - case 0xAA: // TAX - x = nz = a; - goto loop; - - case 0x8A: // TXA - a = nz = x; - goto loop; - - case 0x9A: // TXS - SET_SP( x ); // verified (no flag change) - goto loop; - - case 0xBA: // TSX - x = nz = GET_SP(); - goto loop; - -// Stack - - case 0x48: // PHA - sp = SP( -1 ); - WRITE_STACK( sp, a ); - goto loop; - - case 0x68: // PLA - a = nz = READ_STACK( sp ); - sp = SP( 1 ); - goto loop; - - case 0x40:{// RTI - pc = READ_STACK( SP( 1 ) ); - pc += READ_STACK( SP( 2 ) ) * 0x100; - int temp = READ_STACK( sp ); - sp = SP( 3 ); - data = flags; - SET_FLAGS( temp ); - cpu->r.flags = flags; // update externally-visible I flag - int delta = s.base - cpu->irq_time; - if ( delta <= 0 ) goto loop; // end_time < irq_time - if ( flags & i04 ) goto loop; - s_time += delta; - s.base = cpu->irq_time; - goto loop; - } - - case 0x28:{// PLP - int temp = READ_STACK( sp ); - sp = SP( 1 ); - int changed = flags ^ temp; - SET_FLAGS( temp ); - if ( !(changed & i04) ) - goto loop; // I flag didn't change - if ( flags & i04 ) - goto handle_sei; - goto handle_cli; - } - - case 0x08:{// PHP - int temp; - GET_FLAGS( temp ); - sp = SP( -1 ); - WRITE_STACK( sp, temp | (b10 | r20) ); - goto loop; - } - - case 0x6C:{// JMP (ind) - data = GET_ADDR(); - byte const* page = CODE_PAGE( data ); - pc = page [CODE_OFFSET( data )]; - data = (data & 0xFF00) + ((data + 1) & 0xFF); - pc += page [CODE_OFFSET( data )] * 0x100; - goto loop; - } - - case 0x00: // BRK - goto handle_brk; - -// Flags - - case 0x38: // SEC - c = 0x100; - goto loop; - - case 0x18: // CLC - c = 0; - goto loop; - - case 0xB8: // CLV - flags &= ~v40; - goto loop; - - case 0xD8: // CLD - flags &= ~d08; - goto loop; - - case 0xF8: // SED - flags |= d08; - goto loop; - - case 0x58: // CLI - if ( !(flags & i04) ) - goto loop; - flags &= ~i04; - handle_cli: { - //dprintf( "CLI at %d\n", TIME ); - cpu->r.flags = flags; // update externally-visible I flag - int delta = s.base - cpu->irq_time; - if ( delta <= 0 ) - { - if ( TIME() < cpu->irq_time ) - goto loop; - goto delayed_cli; - } - s.base = cpu->irq_time; - s_time += delta; - if ( s_time < 0 ) - goto loop; - - if ( delta >= s_time + 1 ) - { - // delayed irq until after next instruction - s.base += s_time + 1; - s_time = -1; - goto loop; - } - - // TODO: implement - delayed_cli: - dprintf( "Delayed CLI not emulated\n" ); - goto loop; - } - - case 0x78: // SEI - if ( flags & i04 ) - goto loop; - flags |= i04; - handle_sei: { - cpu->r.flags = flags; // update externally-visible I flag - int delta = s.base - cpu->end_time; - s.base = cpu->end_time; - s_time += delta; - if ( s_time < 0 ) - goto loop; - - dprintf( "Delayed SEI not emulated\n" ); - goto loop; - } - -// Unofficial - - // SKW - skip word - case 0x1C: case 0x3C: case 0x5C: case 0x7C: case 0xDC: case 0xFC: - PAGE_PENALTY( data + x ); - case 0x0C: - pc++; - // SKB - skip byte - case 0x74: case 0x04: case 0x14: case 0x34: case 0x44: case 0x54: case 0x64: - case 0x80: case 0x82: case 0x89: case 0xC2: case 0xD4: case 0xE2: case 0xF4: - pc++; - goto loop; - - // NOP - case 0xEA: case 0x1A: case 0x3A: case 0x5A: case 0x7A: case 0xDA: case 0xFA: - goto loop; - - case halt_opcode: // HLT - halt processor - if ( pc-- > 0x10000 ) - { - // handle wrap-around (assumes caller has put page of HLT at 0x10000) - pc = WORD( pc ); - goto loop; - } - case 0x02: case 0x12: case 0x32: case 0x42: case 0x52: - case 0x62: case 0x72: case 0x92: case 0xB2: case 0xD2: case 0xF2: - goto stop; - -// Unimplemented - - case 0xFF: // force 256-entry jump table for optimization purposes - c |= 1; // compiler doesn't know that this won't affect anything - default: - check( (unsigned) opcode < 0x100 ); - - #ifdef UNIMPL_INSTR - UNIMPL_INSTR(); - #endif - - // At least skip over proper number of bytes instruction uses - static unsigned char const illop_lens [8] = { - 0x40, 0x40, 0x40, 0x80, 0x40, 0x40, 0x80, 0xA0 - }; - int opcode = instr [-1]; - int len = illop_lens [opcode >> 2 & 7] >> (opcode << 1 & 6) & 3; - if ( opcode == 0x9C ) - len = 2; - pc += len; - - // Account for extra clock - if ( (opcode >> 4) == 0x0B ) - { - if ( opcode == 0xB3 ) - data = READ_LOW( data ); - if ( opcode != 0xB7 ) - PAGE_PENALTY( data + y ); - } - goto loop; - } - assert( false ); // catch missing 'goto loop' or accidental 'break' - - int result_; -handle_brk: - pc++; - result_ = b10 | 4; - -#ifdef CPU_DONE -interrupt: -#endif - { - s_time += 7; - - // Save PC and read vector - WRITE_STACK( SP( -1 ), pc >> 8 ); - WRITE_STACK( SP( -2 ), pc ); - pc = GET_LE16( &READ_CODE( 0xFFFA ) + (result_ & 4) ); - - // Save flags - int temp; - GET_FLAGS( temp ); - temp |= r20 + (result_ & b10); // B flag set for BRK - sp = SP( -3 ); - WRITE_STACK( sp, temp ); - - // Update I flag in externally-visible flags - cpu->r.flags = (flags |= i04); - - // Update time - int delta = s.base - cpu->end_time; - if ( delta >= 0 ) - goto loop; - s_time += delta; - s.base = cpu->end_time; - goto loop; - } - -out_of_time: - pc--; - - // Optional action that triggers interrupt or changes irq/end time - #ifdef CPU_DONE - { - CPU_DONE( result_ ); - if ( result_ >= 0 ) - goto interrupt; - if ( s_time < 0 ) - goto loop; - } - #endif -stop: - - // Flush cached state - cpu->r.pc = pc; - cpu->r.sp = GET_SP(); - cpu->r.a = a; - cpu->r.x = x; - cpu->r.y = y; - - int temp; - GET_FLAGS( temp ); - cpu->r.flags = temp; - - cpu->cpu_state_.base = s.base; - cpu->cpu_state_.time = s_time; - cpu->cpu_state = &cpu->cpu_state_; -} +// NES 6502 cpu emulator run function + +#if 0 +/* Define these macros in the source file before #including this file. +- Parameters might be expressions, so they are best evaluated only once, +though they NEVER have side-effects, so multiple evaluation is OK. +- Output parameters might be a multiple-assignment expression like "a=x", +so they must NOT be parenthesized. +- Except where noted, time() and related functions will NOT work +correctly inside a macro. TIME() is always correct, and FLUSH_TIME() and +CACHE_TIME() allow the time changing functions to work. +- Macros "returning" void may use a {} statement block. */ + + // 0 <= addr <= 0xFFFF + page_size + // time functions can be used + int READ_MEM( addr_t ); + void WRITE_MEM( addr_t, int data ); + // 0 <= READ_MEM() <= 0xFF + + // 0 <= addr <= 0x1FF + int READ_LOW( addr_t ); + void WRITE_LOW( addr_t, int data ); + // 0 <= READ_LOW() <= 0xFF + + // Often-used instructions attempt these before using a normal memory access. + // Optional; defaults to READ_MEM() and WRITE_MEM() + bool CAN_READ_FAST( addr_t ); // if true, uses result of READ_FAST + void READ_FAST( addr_t, int& out ); // ALWAYS called BEFORE CAN_READ_FAST + bool CAN_WRITE_FAST( addr_t ); // if true, uses WRITE_FAST instead of WRITE_MEM + void WRITE_FAST( addr_t, int data ); + + // Used by instructions most often used to access the NES PPU (LDA abs and BIT abs). + // Optional; defaults to READ_MEM. + void READ_PPU( addr_t, int& out ); + // 0 <= out <= 0xFF + +// The following can be used within macros: + + // Current time + time_t TIME(); + + // Allows use of time functions + void FLUSH_TIME(); + + // Must be used before end of macro if FLUSH_TIME() was used earlier + void CACHE_TIME(); + +// Configuration (optional; commented behavior if defined) + + // Emulates dummy reads for indexed instructions + #define NES_CPU_DUMMY_READS 1 + + // Optimizes as if map_code( 0, 0x10000 + cpu_padding, FLAT_MEM ) is always in effect + #define FLAT_MEM my_mem_array + + // Expanded just before beginning of code, to help debugger + #define CPU_BEGIN void my_run_cpu() { + +#endif + +/* Copyright (C) 2003-2008 Shay Green. This module is free software; you +can redistribute it and/or modify it under the terms of the GNU Lesser +General Public License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. This +module 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 Lesser General Public License for more +details. You should have received a copy of the GNU Lesser General Public +License along with this module; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ + +// Allows MWCW debugger to step through code properly +#ifdef CPU_BEGIN + CPU_BEGIN +#endif + +// Time +#define TIME() (s_time + s.base) +#define FLUSH_TIME() {s.time = s_time - time_offset;} +#define CACHE_TIME() {s_time = s.time + time_offset;} + +// Defaults +#ifndef CAN_WRITE_FAST + #define CAN_WRITE_FAST( addr ) 0 + #define WRITE_FAST( addr, data ) +#endif + +#ifndef CAN_READ_FAST + #define CAN_READ_FAST( addr ) 0 + #define READ_FAST( addr, out ) +#endif + +#ifndef READ_PPU + #define READ_PPU( addr, out )\ + {\ + FLUSH_TIME();\ + out = READ_MEM( addr );\ + CACHE_TIME();\ + } +#endif + +#define READ_STACK READ_LOW +#define WRITE_STACK WRITE_LOW + +// Dummy reads +#ifdef NES_CPU_DUMMY_READS + // TODO: optimize time handling + #define DUMMY_READ( addr, idx ) \ + if ( (addr & 0xFF) < idx )\ + {\ + int const time_offset = 1;\ + FLUSH_TIME();\ + READ_MEM( (addr - 0x100) );\ + CACHE_TIME();\ + } +#else + #define DUMMY_READ( addr, idx ) +#endif + +// Code +#ifdef FLAT_MEM + #define CODE_PAGE( addr ) (FLAT_MEM) + #define CODE_OFFSET( addr ) (addr) +#else + #define CODE_PAGE( addr ) (s.code_map [NES_CPU_PAGE( addr )]) + #define CODE_OFFSET( addr ) NES_CPU_OFFSET( addr ) +#endif +#define READ_CODE( addr ) (CODE_PAGE( addr ) [CODE_OFFSET( addr )]) + +// Stack +#define SET_SP( v ) (sp = ((v) + 1) | 0x100) +#define GET_SP() ((sp - 1) & 0xFF) +#define SP( o ) ((sp + (o - (o>0)*0x100)) | 0x100) + +// Truncation +#define BYTE( n ) ((uint8_t ) (n)) /* (unsigned) n & 0xFF */ +#define SBYTE( n ) ((int8_t ) (n)) /* (BYTE( n ) ^ 0x80) - 0x80 */ +#define WORD( n ) ((uint16_t) (n)) /* (unsigned) n & 0xFFFF */ + +// Flags with hex value for clarity when used as mask. +// Stored in indicated variable during emulation. +int const n80 = 0x80; // nz +int const v40 = 0x40; // flags +int const r20 = 0x20; +int const b10 = 0x10; +int const d08 = 0x08; // flags +int const i04 = 0x04; // flags +int const z02 = 0x02; // nz +int const c01 = 0x01; // c + +#define IS_NEG (nz & 0x8080) + +#define GET_FLAGS( out ) \ +{\ + out = flags & (v40 | d08 | i04);\ + out += ((nz >> 8) | nz) & n80;\ + out += c >> 8 & c01;\ + if ( !BYTE( nz ) )\ + out += z02;\ +} + +#define SET_FLAGS( in ) \ +{\ + flags = in & (v40 | d08 | i04);\ + c = nz = in << 8;\ + nz += ~in & z02;\ +} + +{ + int const time_offset = 0; + + // Local state + struct cpu_state_t s; + #ifdef FLAT_MEM + s.base = cpu->cpu_state_.base; + #else + s = cpu->cpu_state_; + #endif + cpu->cpu_state = &s; + int s_time = cpu->cpu_state_.time; // helps even on x86 + + // Registers + int pc = cpu->r.pc; + int a = cpu->r.a; + int x = cpu->r.x; + int y = cpu->r.y; + int sp; + SET_SP( cpu->r.sp ); + + // Flags + int flags; + int c; // carry set if (c & 0x100) != 0 + int nz; // Z set if (nz & 0xFF) == 0, N set if (nz & 0x8080) != 0 + { + int temp = cpu->r.flags; + SET_FLAGS( temp ); + } + +loop: + + // Check all values + check( (unsigned) sp - 0x100 < 0x100 ); + check( (unsigned) pc < 0x10000 ); + check( (unsigned) a < 0x100 ); + check( (unsigned) x < 0x100 ); + check( (unsigned) y < 0x100 ); + + // Read instruction + byte const* instr = CODE_PAGE( pc ); + int opcode; + + if ( CODE_OFFSET(~0) == ~0 ) + { + opcode = instr [pc]; + pc++; + instr += pc; + } + else + { + instr += CODE_OFFSET( pc ); + opcode = *instr++; + pc++; + } + + // local to function in case it helps optimizer + static byte const clock_table [256] = + {// 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0,6,2,8,3,3,5,5,3,2,2,2,4,4,6,6,// 0 + 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,// 1 + 6,6,0,8,3,3,5,5,4,2,2,2,4,4,6,6,// 2 + 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,// 3 + 6,6,2,8,3,3,5,5,3,2,2,2,3,4,6,6,// 4 + 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,// 5 + 6,6,2,8,3,3,5,5,4,2,2,2,5,4,6,6,// 6 + 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,// 7 + 2,6,2,6,3,3,3,3,2,2,2,2,4,4,4,4,// 8 + 2,6,2,6,4,4,4,4,2,5,2,5,5,5,5,5,// 9 + 2,6,2,6,3,3,3,3,2,2,2,2,4,4,4,4,// A + 2,5,2,5,4,4,4,4,2,4,2,4,4,4,4,4,// B + 2,6,2,8,3,3,5,5,2,2,2,2,4,4,6,6,// C + 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,// D + 2,6,2,8,3,3,5,5,2,2,2,2,4,4,6,6,// E + 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7 // F + }; // 0x00 was 7 and 0x22 was 2 + + // Update time + if ( s_time >= 0 ) + goto out_of_time; + + #ifdef CPU_INSTR_HOOK + { CPU_INSTR_HOOK( (pc-1), (&instr [-1]), a, x, y, GET_SP(), TIME() ); } + #endif + + s_time += clock_table [opcode]; + + int data; + data = *instr; + + switch ( opcode ) + { + +// Macros + +#define GET_MSB() (instr [1]) +#define ADD_PAGE( out ) (pc++, out = data + 0x100 * GET_MSB()) +#define GET_ADDR() GET_LE16( instr ) + +#define PAGE_PENALTY( lsb ) s_time += (lsb) >> 8; + +#define INC_DEC( reg, n ) reg = BYTE( nz = reg + n ); goto loop; + +#define IND_Y( cross, out ) {\ + int temp = READ_LOW( data ) + y;\ + out = temp + 0x100 * READ_LOW( BYTE( data + 1 ) );\ + cross( temp );\ + } + +#define IND_X( out ) {\ + int temp = data + x;\ + out = 0x100 * READ_LOW( BYTE( temp + 1 ) ) + READ_LOW( BYTE( temp ) );\ + } + +#define ARITH_ADDR_MODES( op )\ +case op - 0x04: /* (ind,x) */\ + IND_X( data )\ + goto ptr##op;\ +case op + 0x0C: /* (ind),y */\ + IND_Y( PAGE_PENALTY, data )\ + goto ptr##op;\ +case op + 0x10: /* zp,X */\ + data = BYTE( data + x );\ +case op + 0x00: /* zp */\ + data = READ_LOW( data );\ + goto imm##op;\ +case op + 0x14: /* abs,Y */\ + data += y;\ + goto ind##op;\ +case op + 0x18: /* abs,X */\ + data += x;\ +ind##op:\ + PAGE_PENALTY( data );\ +case op + 0x08: /* abs */\ + ADD_PAGE( data );\ +ptr##op:\ + FLUSH_TIME();\ + data = READ_MEM( data );\ + CACHE_TIME();\ +case op + 0x04: /* imm */\ +imm##op: + +// TODO: more efficient way to handle negative branch that wraps PC around +#define BRANCH( cond )\ +{\ + ++pc;\ + if ( !(cond) ) goto loop;\ + s_time++;\ + int offset = SBYTE( data );\ + s_time += (BYTE(pc) + offset) >> 8 & 1;\ + pc = WORD( pc + offset );\ + goto loop;\ +} + +// Often-Used + + case 0xB5: // LDA zp,x + a = nz = READ_LOW( BYTE( data + x ) ); + pc++; + goto loop; + + case 0xA5: // LDA zp + a = nz = READ_LOW( data ); + pc++; + goto loop; + + case 0xD0: // BNE + BRANCH( BYTE( nz ) ); + + case 0x20: { // JSR + int temp = pc + 1; + pc = GET_ADDR(); + WRITE_STACK( SP( -1 ), temp >> 8 ); + sp = SP( -2 ); + WRITE_STACK( sp, temp ); + goto loop; + } + + case 0x4C: // JMP abs + pc = GET_ADDR(); + goto loop; + + case 0xE8: // INX + INC_DEC( x, 1 ) + + case 0x10: // BPL + BRANCH( !IS_NEG ) + + ARITH_ADDR_MODES( 0xC5 ) // CMP + nz = a - data; + pc++; + c = ~nz; + nz &= 0xFF; + goto loop; + + case 0x30: // BMI + BRANCH( IS_NEG ) + + case 0xF0: // BEQ + BRANCH( !BYTE( nz ) ); + + case 0x95: // STA zp,x + data = BYTE( data + x ); + case 0x85: // STA zp + pc++; + WRITE_LOW( data, a ); + goto loop; + + case 0xC8: // INY + INC_DEC( y, 1 ) + + case 0xA8: // TAY + y = a; + nz = a; + goto loop; + + case 0x98: // TYA + a = y; + nz = y; + goto loop; + + case 0xAD:{// LDA abs + int addr = GET_ADDR(); + pc += 2; + READ_PPU( addr, a = nz ); + goto loop; + } + + case 0x60: // RTS + pc = 1 + READ_STACK( sp ); + pc += 0x100 * READ_STACK( SP( 1 ) ); + sp = SP( 2 ); + goto loop; + + { + int addr; + + case 0x8D: // STA abs + addr = GET_ADDR(); + pc += 2; + if ( CAN_WRITE_FAST( addr ) ) + { + WRITE_FAST( addr, a ); + goto loop; + } + sta_ptr: + FLUSH_TIME(); + WRITE_MEM( addr, a ); + CACHE_TIME(); + goto loop; + + case 0x99: // STA abs,Y + addr = y + GET_ADDR(); + pc += 2; + if ( CAN_WRITE_FAST( addr ) ) + { + WRITE_FAST( addr, a ); + goto loop; + } + goto sta_abs_x; + + case 0x9D: // STA abs,X (slightly more common than STA abs) + addr = x + GET_ADDR(); + pc += 2; + if ( CAN_WRITE_FAST( addr ) ) + { + WRITE_FAST( addr, a ); + goto loop; + } + DUMMY_READ( addr, x ); + sta_abs_x: + FLUSH_TIME(); + WRITE_MEM( addr, a ); + CACHE_TIME(); + goto loop; + + case 0x91: // STA (ind),Y + #define NO_PAGE_PENALTY( lsb ) + IND_Y( NO_PAGE_PENALTY, addr ) + pc++; + DUMMY_READ( addr, y ); + goto sta_ptr; + + case 0x81: // STA (ind,X) + IND_X( addr ) + pc++; + goto sta_ptr; + + } + + case 0xA9: // LDA #imm + pc++; + a = data; + nz = data; + goto loop; + + // common read instructions + { + int addr; + + case 0xA1: // LDA (ind,X) + IND_X( addr ) + pc++; + goto a_nz_read_addr; + + case 0xB1:// LDA (ind),Y + addr = READ_LOW( data ) + y; + PAGE_PENALTY( addr ); + addr += 0x100 * READ_LOW( BYTE( data + 1 ) ); + pc++; + READ_FAST( addr, a = nz ); + if ( CAN_READ_FAST( addr ) ) + goto loop; + DUMMY_READ( addr, y ); + goto a_nz_read_addr; + + case 0xB9: // LDA abs,Y + PAGE_PENALTY( data + y ); + addr = GET_ADDR() + y; + pc += 2; + READ_FAST( addr, a = nz ); + if ( CAN_READ_FAST( addr ) ) + goto loop; + goto a_nz_read_addr; + + case 0xBD: // LDA abs,X + PAGE_PENALTY( data + x ); + addr = GET_ADDR() + x; + pc += 2; + READ_FAST( addr, a = nz ); + if ( CAN_READ_FAST( addr ) ) + goto loop; + DUMMY_READ( addr, x ); + a_nz_read_addr: + FLUSH_TIME(); + a = nz = READ_MEM( addr ); + CACHE_TIME(); + goto loop; + + } + +// Branch + + case 0x50: // BVC + BRANCH( !(flags & v40) ) + + case 0x70: // BVS + BRANCH( flags & v40 ) + + case 0xB0: // BCS + BRANCH( c & 0x100 ) + + case 0x90: // BCC + BRANCH( !(c & 0x100) ) + +// Load/store + + case 0x94: // STY zp,x + data = BYTE( data + x ); + case 0x84: // STY zp + pc++; + WRITE_LOW( data, y ); + goto loop; + + case 0x96: // STX zp,y + data = BYTE( data + y ); + case 0x86: // STX zp + pc++; + WRITE_LOW( data, x ); + goto loop; + + case 0xB6: // LDX zp,y + data = BYTE( data + y ); + case 0xA6: // LDX zp + data = READ_LOW( data ); + case 0xA2: // LDX #imm + pc++; + x = data; + nz = data; + goto loop; + + case 0xB4: // LDY zp,x + data = BYTE( data + x ); + case 0xA4: // LDY zp + data = READ_LOW( data ); + case 0xA0: // LDY #imm + pc++; + y = data; + nz = data; + goto loop; + + case 0xBC: // LDY abs,X + data += x; + PAGE_PENALTY( data ); + case 0xAC:{// LDY abs + int addr = data + 0x100 * GET_MSB(); + pc += 2; + FLUSH_TIME(); + y = nz = READ_MEM( addr ); + CACHE_TIME(); + goto loop; + } + + case 0xBE: // LDX abs,y + data += y; + PAGE_PENALTY( data ); + case 0xAE:{// LDX abs + int addr = data + 0x100 * GET_MSB(); + pc += 2; + FLUSH_TIME(); + x = nz = READ_MEM( addr ); + CACHE_TIME(); + goto loop; + } + + { + int temp; + case 0x8C: // STY abs + temp = y; + goto store_abs; + + case 0x8E: // STX abs + temp = x; + store_abs: + { + int addr = GET_ADDR(); + pc += 2; + if ( CAN_WRITE_FAST( addr ) ) + { + WRITE_FAST( addr, temp ); + goto loop; + } + FLUSH_TIME(); + WRITE_MEM( addr, temp ); + CACHE_TIME(); + goto loop; + } + } + +// Compare + + case 0xEC: {// CPX abs + int addr = GET_ADDR(); + pc++; + FLUSH_TIME(); + data = READ_MEM( addr ); + CACHE_TIME(); + goto cpx_data; + } + + case 0xE4: // CPX zp + data = READ_LOW( data ); + case 0xE0: // CPX #imm + cpx_data: + nz = x - data; + pc++; + c = ~nz; + nz &= 0xFF; + goto loop; + + case 0xCC:{// CPY abs + int addr = GET_ADDR(); + pc++; + FLUSH_TIME(); + data = READ_MEM( addr ); + CACHE_TIME(); + goto cpy_data; + } + + case 0xC4: // CPY zp + data = READ_LOW( data ); + case 0xC0: // CPY #imm + cpy_data: + nz = y - data; + pc++; + c = ~nz; + nz &= 0xFF; + goto loop; + +// Logical + + ARITH_ADDR_MODES( 0x25 ) // AND + nz = (a &= data); + pc++; + goto loop; + + ARITH_ADDR_MODES( 0x45 ) // EOR + nz = (a ^= data); + pc++; + goto loop; + + ARITH_ADDR_MODES( 0x05 ) // ORA + nz = (a |= data); + pc++; + goto loop; + + case 0x2C:{// BIT abs + int addr = GET_ADDR(); + pc += 2; + READ_PPU( addr, nz ); + flags = (flags & ~v40) + (nz & v40); + if ( a & nz ) + goto loop; + nz <<= 8; // result must be zero, even if N bit is set + goto loop; + } + + case 0x24: // BIT zp + nz = READ_LOW( data ); + pc++; + flags = (flags & ~v40) + (nz & v40); + if ( a & nz ) + goto loop; // Z should be clear, and nz must be non-zero if nz & a is + nz <<= 8; // set Z flag without affecting N flag + goto loop; + +// Add/subtract + + ARITH_ADDR_MODES( 0xE5 ) // SBC + case 0xEB: // unofficial equivalent + data ^= 0xFF; + goto adc_imm; + + ARITH_ADDR_MODES( 0x65 ) // ADC + adc_imm: { + int carry = c >> 8 & 1; + int ov = (a ^ 0x80) + carry + SBYTE( data ); + flags = (flags & ~v40) + (ov >> 2 & v40); + c = nz = a + data + carry; + pc++; + a = BYTE( nz ); + goto loop; + } + +// Shift/rotate + + case 0x4A: // LSR A + c = 0; + case 0x6A: // ROR A + nz = c >> 1 & 0x80; + c = a << 8; + nz += a >> 1; + a = nz; + goto loop; + + case 0x0A: // ASL A + nz = a << 1; + c = nz; + a = BYTE( nz ); + goto loop; + + case 0x2A: { // ROL A + nz = a << 1; + int temp = c >> 8 & 1; + c = nz; + nz += temp; + a = BYTE( nz ); + goto loop; + } + + case 0x5E: // LSR abs,X + data += x; + case 0x4E: // LSR abs + c = 0; + case 0x6E: // ROR abs + ror_abs: { + ADD_PAGE( data ); + FLUSH_TIME(); + int temp = READ_MEM( data ); + nz = (c >> 1 & 0x80) + (temp >> 1); + c = temp << 8; + goto rotate_common; + } + + case 0x3E: // ROL abs,X + data += x; + goto rol_abs; + + case 0x1E: // ASL abs,X + data += x; + case 0x0E: // ASL abs + c = 0; + case 0x2E: // ROL abs + rol_abs: + ADD_PAGE( data ); + nz = c >> 8 & 1; + FLUSH_TIME(); + nz += (c = READ_MEM( data ) << 1); + rotate_common: + pc++; + WRITE_MEM( data, BYTE( nz ) ); + CACHE_TIME(); + goto loop; + + case 0x7E: // ROR abs,X + data += x; + goto ror_abs; + + case 0x76: // ROR zp,x + data = BYTE( data + x ); + goto ror_zp; + + case 0x56: // LSR zp,x + data = BYTE( data + x ); + case 0x46: // LSR zp + c = 0; + case 0x66: // ROR zp + ror_zp: { + int temp = READ_LOW( data ); + nz = (c >> 1 & 0x80) + (temp >> 1); + c = temp << 8; + goto write_nz_zp; + } + + case 0x36: // ROL zp,x + data = BYTE( data + x ); + goto rol_zp; + + case 0x16: // ASL zp,x + data = BYTE( data + x ); + case 0x06: // ASL zp + c = 0; + case 0x26: // ROL zp + rol_zp: + nz = c >> 8 & 1; + nz += (c = READ_LOW( data ) << 1); + goto write_nz_zp; + +// Increment/decrement + + case 0xCA: // DEX + INC_DEC( x, -1 ) + + case 0x88: // DEY + INC_DEC( y, -1 ) + + case 0xF6: // INC zp,x + data = BYTE( data + x ); + case 0xE6: // INC zp + nz = 1; + goto add_nz_zp; + + case 0xD6: // DEC zp,x + data = BYTE( data + x ); + case 0xC6: // DEC zp + nz = -1; + add_nz_zp: + nz += READ_LOW( data ); + write_nz_zp: + pc++; + WRITE_LOW( data, nz ); + goto loop; + + case 0xFE: // INC abs,x + data = x + GET_ADDR(); + goto inc_ptr; + + case 0xEE: // INC abs + data = GET_ADDR(); + inc_ptr: + nz = 1; + goto inc_common; + + case 0xDE: // DEC abs,x + data = x + GET_ADDR(); + goto dec_ptr; + + case 0xCE: // DEC abs + data = GET_ADDR(); + dec_ptr: + nz = -1; + inc_common: + FLUSH_TIME(); + pc += 2; + nz += READ_MEM( data ); + WRITE_MEM( data, BYTE( nz ) ); + CACHE_TIME(); + goto loop; + +// Transfer + + case 0xAA: // TAX + x = nz = a; + goto loop; + + case 0x8A: // TXA + a = nz = x; + goto loop; + + case 0x9A: // TXS + SET_SP( x ); // verified (no flag change) + goto loop; + + case 0xBA: // TSX + x = nz = GET_SP(); + goto loop; + +// Stack + + case 0x48: // PHA + sp = SP( -1 ); + WRITE_STACK( sp, a ); + goto loop; + + case 0x68: // PLA + a = nz = READ_STACK( sp ); + sp = SP( 1 ); + goto loop; + + case 0x40:{// RTI + pc = READ_STACK( SP( 1 ) ); + pc += READ_STACK( SP( 2 ) ) * 0x100; + int temp = READ_STACK( sp ); + sp = SP( 3 ); + data = flags; + SET_FLAGS( temp ); + cpu->r.flags = flags; // update externally-visible I flag + int delta = s.base - cpu->irq_time; + if ( delta <= 0 ) goto loop; // end_time < irq_time + if ( flags & i04 ) goto loop; + s_time += delta; + s.base = cpu->irq_time; + goto loop; + } + + case 0x28:{// PLP + int temp = READ_STACK( sp ); + sp = SP( 1 ); + int changed = flags ^ temp; + SET_FLAGS( temp ); + if ( !(changed & i04) ) + goto loop; // I flag didn't change + if ( flags & i04 ) + goto handle_sei; + goto handle_cli; + } + + case 0x08:{// PHP + int temp; + GET_FLAGS( temp ); + sp = SP( -1 ); + WRITE_STACK( sp, temp | (b10 | r20) ); + goto loop; + } + + case 0x6C:{// JMP (ind) + data = GET_ADDR(); + byte const* page = CODE_PAGE( data ); + pc = page [CODE_OFFSET( data )]; + data = (data & 0xFF00) + ((data + 1) & 0xFF); + pc += page [CODE_OFFSET( data )] * 0x100; + goto loop; + } + + case 0x00: // BRK + goto handle_brk; + +// Flags + + case 0x38: // SEC + c = 0x100; + goto loop; + + case 0x18: // CLC + c = 0; + goto loop; + + case 0xB8: // CLV + flags &= ~v40; + goto loop; + + case 0xD8: // CLD + flags &= ~d08; + goto loop; + + case 0xF8: // SED + flags |= d08; + goto loop; + + case 0x58: // CLI + if ( !(flags & i04) ) + goto loop; + flags &= ~i04; + handle_cli: { + //dprintf( "CLI at %d\n", TIME ); + cpu->r.flags = flags; // update externally-visible I flag + int delta = s.base - cpu->irq_time; + if ( delta <= 0 ) + { + if ( TIME() < cpu->irq_time ) + goto loop; + goto delayed_cli; + } + s.base = cpu->irq_time; + s_time += delta; + if ( s_time < 0 ) + goto loop; + + if ( delta >= s_time + 1 ) + { + // delayed irq until after next instruction + s.base += s_time + 1; + s_time = -1; + goto loop; + } + + // TODO: implement + delayed_cli: + dprintf( "Delayed CLI not emulated\n" ); + goto loop; + } + + case 0x78: // SEI + if ( flags & i04 ) + goto loop; + flags |= i04; + handle_sei: { + cpu->r.flags = flags; // update externally-visible I flag + int delta = s.base - cpu->end_time; + s.base = cpu->end_time; + s_time += delta; + if ( s_time < 0 ) + goto loop; + + dprintf( "Delayed SEI not emulated\n" ); + goto loop; + } + +// Unofficial + + // SKW - skip word + case 0x1C: case 0x3C: case 0x5C: case 0x7C: case 0xDC: case 0xFC: + PAGE_PENALTY( data + x ); + case 0x0C: + pc++; + // SKB - skip byte + case 0x74: case 0x04: case 0x14: case 0x34: case 0x44: case 0x54: case 0x64: + case 0x80: case 0x82: case 0x89: case 0xC2: case 0xD4: case 0xE2: case 0xF4: + pc++; + goto loop; + + // NOP + case 0xEA: case 0x1A: case 0x3A: case 0x5A: case 0x7A: case 0xDA: case 0xFA: + goto loop; + + case halt_opcode: // HLT - halt processor + if ( pc-- > 0x10000 ) + { + // handle wrap-around (assumes caller has put page of HLT at 0x10000) + pc = WORD( pc ); + goto loop; + } + case 0x02: case 0x12: case 0x32: case 0x42: case 0x52: + case 0x62: case 0x72: case 0x92: case 0xB2: case 0xD2: case 0xF2: + goto stop; + +// Unimplemented + + case 0xFF: // force 256-entry jump table for optimization purposes + c |= 1; // compiler doesn't know that this won't affect anything + default: + check( (unsigned) opcode < 0x100 ); + + #ifdef UNIMPL_INSTR + UNIMPL_INSTR(); + #endif + + // At least skip over proper number of bytes instruction uses + static unsigned char const illop_lens [8] = { + 0x40, 0x40, 0x40, 0x80, 0x40, 0x40, 0x80, 0xA0 + }; + int opcode = instr [-1]; + int len = illop_lens [opcode >> 2 & 7] >> (opcode << 1 & 6) & 3; + if ( opcode == 0x9C ) + len = 2; + pc += len; + + // Account for extra clock + if ( (opcode >> 4) == 0x0B ) + { + if ( opcode == 0xB3 ) + data = READ_LOW( data ); + if ( opcode != 0xB7 ) + PAGE_PENALTY( data + y ); + } + goto loop; + } + assert( false ); // catch missing 'goto loop' or accidental 'break' + + int result_; +handle_brk: + pc++; + result_ = b10 | 4; + +#ifdef CPU_DONE +interrupt: +#endif + { + s_time += 7; + + // Save PC and read vector + WRITE_STACK( SP( -1 ), pc >> 8 ); + WRITE_STACK( SP( -2 ), pc ); + pc = GET_LE16( &READ_CODE( 0xFFFA ) + (result_ & 4) ); + + // Save flags + int temp; + GET_FLAGS( temp ); + temp |= r20 + (result_ & b10); // B flag set for BRK + sp = SP( -3 ); + WRITE_STACK( sp, temp ); + + // Update I flag in externally-visible flags + cpu->r.flags = (flags |= i04); + + // Update time + int delta = s.base - cpu->end_time; + if ( delta >= 0 ) + goto loop; + s_time += delta; + s.base = cpu->end_time; + goto loop; + } + +out_of_time: + pc--; + + // Optional action that triggers interrupt or changes irq/end time + #ifdef CPU_DONE + { + CPU_DONE( result_ ); + if ( result_ >= 0 ) + goto interrupt; + if ( s_time < 0 ) + goto loop; + } + #endif +stop: + + // Flush cached state + cpu->r.pc = pc; + cpu->r.sp = GET_SP(); + cpu->r.a = a; + cpu->r.x = x; + cpu->r.y = y; + + int temp; + GET_FLAGS( temp ); + cpu->r.flags = temp; + + cpu->cpu_state_.base = s.base; + cpu->cpu_state_.time = s_time; + cpu->cpu_state = &cpu->cpu_state_; +} diff --git a/apps/codecs/libgme/nes_vrc7_apu.c b/apps/codecs/libgme/nes_vrc7_apu.c index 95bc676c26..8d3c2e88a6 100644 --- a/apps/codecs/libgme/nes_vrc7_apu.c +++ b/apps/codecs/libgme/nes_vrc7_apu.c @@ -1,88 +1,88 @@ - -#include "nes_vrc7_apu.h" -#include "blargg_source.h" - -int const period = 36; // NES CPU clocks per FM clock - -void Vrc7_init( struct Nes_Vrc7_Apu* this ) -{ - Synth_init( &this->synth ); - - OPLL_new ( &this->opll, 3579545, 3579545 / 72 ); - OPLL_reset_patch( &this->opll, OPLL_VRC7_TONE ); - - this->osc.output = 0; - this->osc.last_amp = 0; - this->mask = 0; - - Vrc7_volume( this, (int)FP_ONE_VOLUME ); - Vrc7_reset( this ); -} - -void Vrc7_reset( struct Nes_Vrc7_Apu* this ) -{ - this->addr = 0; - this->next_time = 0; - this->osc.last_amp = 0; - - OPLL_reset (&this->opll); - OPLL_setMask(&this->opll, this->mask); -} - -void Vrc7_set_rate( struct Nes_Vrc7_Apu* this, int r ) -{ - OPLL_set_quality( &this->opll, r < 44100 ? 0 : 1 ); -} - -void Vrc7_write_reg( struct Nes_Vrc7_Apu* this, int data ) -{ - this->addr = data; -} - -void Vrc7_run_until( struct Nes_Vrc7_Apu* this, blip_time_t end_time ); -void Vrc7_write_data( struct Nes_Vrc7_Apu* this, blip_time_t time, int data ) -{ - if ( time > this->next_time ) - Vrc7_run_until( this, time ); - - OPLL_writeIO( &this->opll, 0, this->addr ); - OPLL_writeIO( &this->opll, 1, data ); -} - -void Vrc7_end_frame( struct Nes_Vrc7_Apu* this, blip_time_t time ) -{ - if ( time > this->next_time ) - Vrc7_run_until( this, time ); - - this->next_time -= time; - assert( this->next_time >= 0 ); - - if ( this->osc.output ) - Blip_set_modified( this->osc.output ); -} - -void Vrc7_run_until( struct Nes_Vrc7_Apu* this, blip_time_t end_time ) -{ - require( end_time > this->next_time ); - - blip_time_t time = this->next_time; - OPLL* opll = &this->opll; // cache - struct Blip_Buffer* const output = this-> osc.output; - if ( output ) - { - do - { - int amp = OPLL_calc( opll ) << 1; - int delta = amp - this->osc.last_amp; - if ( delta ) - { - this->osc.last_amp = amp; - Synth_offset_inline( &this->synth, time, delta, output ); - } - time += period; - } - while ( time < end_time ); - } - - this->next_time = time; -} + +#include "nes_vrc7_apu.h" +#include "blargg_source.h" + +int const period = 36; // NES CPU clocks per FM clock + +void Vrc7_init( struct Nes_Vrc7_Apu* this ) +{ + Synth_init( &this->synth ); + + OPLL_new ( &this->opll, 3579545, 3579545 / 72 ); + OPLL_reset_patch( &this->opll, OPLL_VRC7_TONE ); + + this->osc.output = 0; + this->osc.last_amp = 0; + this->mask = 0; + + Vrc7_volume( this, (int)FP_ONE_VOLUME ); + Vrc7_reset( this ); +} + +void Vrc7_reset( struct Nes_Vrc7_Apu* this ) +{ + this->addr = 0; + this->next_time = 0; + this->osc.last_amp = 0; + + OPLL_reset (&this->opll); + OPLL_setMask(&this->opll, this->mask); +} + +void Vrc7_set_rate( struct Nes_Vrc7_Apu* this, int r ) +{ + OPLL_set_quality( &this->opll, r < 44100 ? 0 : 1 ); +} + +void Vrc7_write_reg( struct Nes_Vrc7_Apu* this, int data ) +{ + this->addr = data; +} + +void Vrc7_run_until( struct Nes_Vrc7_Apu* this, blip_time_t end_time ); +void Vrc7_write_data( struct Nes_Vrc7_Apu* this, blip_time_t time, int data ) +{ + if ( time > this->next_time ) + Vrc7_run_until( this, time ); + + OPLL_writeIO( &this->opll, 0, this->addr ); + OPLL_writeIO( &this->opll, 1, data ); +} + +void Vrc7_end_frame( struct Nes_Vrc7_Apu* this, blip_time_t time ) +{ + if ( time > this->next_time ) + Vrc7_run_until( this, time ); + + this->next_time -= time; + assert( this->next_time >= 0 ); + + if ( this->osc.output ) + Blip_set_modified( this->osc.output ); +} + +void Vrc7_run_until( struct Nes_Vrc7_Apu* this, blip_time_t end_time ) +{ + require( end_time > this->next_time ); + + blip_time_t time = this->next_time; + OPLL* opll = &this->opll; // cache + struct Blip_Buffer* const output = this-> osc.output; + if ( output ) + { + do + { + int amp = OPLL_calc( opll ) << 1; + int delta = amp - this->osc.last_amp; + if ( delta ) + { + this->osc.last_amp = amp; + Synth_offset_inline( &this->synth, time, delta, output ); + } + time += period; + } + while ( time < end_time ); + } + + this->next_time = time; +} diff --git a/apps/codecs/libgme/opl_apu.c b/apps/codecs/libgme/opl_apu.c index 64b2714b81..b573baef11 100644 --- a/apps/codecs/libgme/opl_apu.c +++ b/apps/codecs/libgme/opl_apu.c @@ -1,198 +1,198 @@ -#include "opl_apu.h" - -#include "blargg_source.h" - -/* NOTE: Removed unused chips ~ gama */ - -blargg_err_t Opl_init( struct Opl_Apu* this, long clock, long rate, blip_time_t period, enum opl_type_t type ) -{ - Synth_init( &this->synth ); - - this->type_ = type; - this->clock_ = clock; - this->rate_ = rate; - this->period_ = period; - Opl_set_output( this, 0 ); - Opl_volume( this, (int)FP_ONE_VOLUME ); - - switch (type) - { - case type_opll: - case type_msxmusic: - case type_smsfmunit: - OPLL_new ( &this->opll, clock, rate ); - OPLL_reset_patch( &this->opll, OPLL_2413_TONE ); - break; - case type_vrc7: - OPLL_new ( &this->opll, clock, rate ); - OPLL_reset_patch( &this->opll, OPLL_VRC7_TONE ); - break; - case type_msxaudio: - OPL_init( &this->opl, this->opl_memory, sizeof this->opl_memory ); - OPL_setSampleRate( &this->opl, rate, clock ); - OPL_setInternalVolume(&this->opl, 1 << 13); - break; - } - - Opl_reset( this ); - return 0; -} - -void Opl_shutdown( struct Opl_Apu* this ) -{ - switch (this->type_) - { - case type_opll: - case type_msxmusic: - case type_smsfmunit: - case type_vrc7: - OPLL_delete( &this->opll ); - break; - case type_msxaudio: break; - } -} - -void Opl_reset( struct Opl_Apu* this ) -{ - this->addr = 0; - this->next_time = 0; - this->last_amp = 0; - - switch (this->type_) - { - case type_opll: - case type_msxmusic: - case type_smsfmunit: - case type_vrc7: - OPLL_reset( &this->opll ); - OPLL_setMask( &this->opll, 0 ); - break; - case type_msxaudio: - OPL_reset( &this->opl ); - break; - } -} - -static void run_until( struct Opl_Apu* this, blip_time_t end_time ); -void Opl_write_data( struct Opl_Apu* this, blip_time_t time, int data ) -{ - run_until( this, time ); - switch (this->type_) - { - case type_opll: - case type_msxmusic: - case type_smsfmunit: - case type_vrc7: - OPLL_writeIO( &this->opll, 0, this->addr ); - OPLL_writeIO( &this->opll, 1, data ); - break; - case type_msxaudio: - OPL_writeReg( &this->opl, this->addr, data ); - break; - } -} - -int Opl_read( struct Opl_Apu* this, blip_time_t time, int port ) -{ - run_until( this, time ); - switch (this->type_) - { - case type_opll: - case type_msxmusic: - case type_smsfmunit: - case type_vrc7: - return OPLL_read( &this->opll, port ); - case type_msxaudio: - return OPL_readStatus( &this->opl ); - } - - return 0; -} - -void Opl_end_frame( struct Opl_Apu* this, blip_time_t time ) -{ - run_until( this, time ); - this->next_time -= time; - - if ( this->output_ ) - Blip_set_modified( this->output_ ); -} - -static void run_until( struct Opl_Apu* this, blip_time_t end_time ) -{ - if ( end_time > this->next_time ) - { - blip_time_t time_delta = end_time - this->next_time; - blip_time_t time = this->next_time; - unsigned count = time_delta / this->period_ + 1; - switch (this->type_) - { - case type_opll: - case type_msxmusic: - case type_smsfmunit: - case type_vrc7: - { - OPLL* opll = &this->opll; // cache - struct Blip_Buffer* const output = this->output_; - while ( count > 0 ) - { - unsigned todo = count; - if ( todo > 1024 ) todo = 1024; - short *buffer = OPLL_update_buffer(opll, todo); - - if ( output && buffer ) - { - int last_amp = this->last_amp; - unsigned i; - for ( i = 0; i < todo; i++ ) - { - int amp = buffer [i]; - int delta = amp - last_amp; - if ( delta ) - { - last_amp = amp; - Synth_offset_inline( &this->synth, time, delta, output ); - } - time += this->period_; - } - this->last_amp = last_amp; - } - count -= todo; - } - } - break; - case type_msxaudio: - { - struct Y8950* opl = &this->opl; - struct Blip_Buffer* const output = this->output_; - while ( count > 0 ) - { - unsigned todo = count; - if ( todo > 1024 ) todo = 1024; - int *buffer = OPL_updateBuffer(opl, todo); - - if ( output && buffer ) - { - int last_amp = this->last_amp; - unsigned i; - for ( i = 0; i < todo; i++ ) - { - int amp = buffer [i]; - int delta = amp - last_amp; - if ( delta ) - { - last_amp = amp; - Synth_offset_inline( &this->synth, time, delta, output ); - } - time += this->period_; - } - this->last_amp = last_amp; - } - count -= todo; - } - } - break; - } - this->next_time = time; - } -} +#include "opl_apu.h" + +#include "blargg_source.h" + +/* NOTE: Removed unused chips ~ gama */ + +blargg_err_t Opl_init( struct Opl_Apu* this, long clock, long rate, blip_time_t period, enum opl_type_t type ) +{ + Synth_init( &this->synth ); + + this->type_ = type; + this->clock_ = clock; + this->rate_ = rate; + this->period_ = period; + Opl_set_output( this, 0 ); + Opl_volume( this, (int)FP_ONE_VOLUME ); + + switch (type) + { + case type_opll: + case type_msxmusic: + case type_smsfmunit: + OPLL_new ( &this->opll, clock, rate ); + OPLL_reset_patch( &this->opll, OPLL_2413_TONE ); + break; + case type_vrc7: + OPLL_new ( &this->opll, clock, rate ); + OPLL_reset_patch( &this->opll, OPLL_VRC7_TONE ); + break; + case type_msxaudio: + OPL_init( &this->opl, this->opl_memory, sizeof this->opl_memory ); + OPL_setSampleRate( &this->opl, rate, clock ); + OPL_setInternalVolume(&this->opl, 1 << 13); + break; + } + + Opl_reset( this ); + return 0; +} + +void Opl_shutdown( struct Opl_Apu* this ) +{ + switch (this->type_) + { + case type_opll: + case type_msxmusic: + case type_smsfmunit: + case type_vrc7: + OPLL_delete( &this->opll ); + break; + case type_msxaudio: break; + } +} + +void Opl_reset( struct Opl_Apu* this ) +{ + this->addr = 0; + this->next_time = 0; + this->last_amp = 0; + + switch (this->type_) + { + case type_opll: + case type_msxmusic: + case type_smsfmunit: + case type_vrc7: + OPLL_reset( &this->opll ); + OPLL_setMask( &this->opll, 0 ); + break; + case type_msxaudio: + OPL_reset( &this->opl ); + break; + } +} + +static void run_until( struct Opl_Apu* this, blip_time_t end_time ); +void Opl_write_data( struct Opl_Apu* this, blip_time_t time, int data ) +{ + run_until( this, time ); + switch (this->type_) + { + case type_opll: + case type_msxmusic: + case type_smsfmunit: + case type_vrc7: + OPLL_writeIO( &this->opll, 0, this->addr ); + OPLL_writeIO( &this->opll, 1, data ); + break; + case type_msxaudio: + OPL_writeReg( &this->opl, this->addr, data ); + break; + } +} + +int Opl_read( struct Opl_Apu* this, blip_time_t time, int port ) +{ + run_until( this, time ); + switch (this->type_) + { + case type_opll: + case type_msxmusic: + case type_smsfmunit: + case type_vrc7: + return OPLL_read( &this->opll, port ); + case type_msxaudio: + return OPL_readStatus( &this->opl ); + } + + return 0; +} + +void Opl_end_frame( struct Opl_Apu* this, blip_time_t time ) +{ + run_until( this, time ); + this->next_time -= time; + + if ( this->output_ ) + Blip_set_modified( this->output_ ); +} + +static void run_until( struct Opl_Apu* this, blip_time_t end_time ) +{ + if ( end_time > this->next_time ) + { + blip_time_t time_delta = end_time - this->next_time; + blip_time_t time = this->next_time; + unsigned count = time_delta / this->period_ + 1; + switch (this->type_) + { + case type_opll: + case type_msxmusic: + case type_smsfmunit: + case type_vrc7: + { + OPLL* opll = &this->opll; // cache + struct Blip_Buffer* const output = this->output_; + while ( count > 0 ) + { + unsigned todo = count; + if ( todo > 1024 ) todo = 1024; + short *buffer = OPLL_update_buffer(opll, todo); + + if ( output && buffer ) + { + int last_amp = this->last_amp; + unsigned i; + for ( i = 0; i < todo; i++ ) + { + int amp = buffer [i]; + int delta = amp - last_amp; + if ( delta ) + { + last_amp = amp; + Synth_offset_inline( &this->synth, time, delta, output ); + } + time += this->period_; + } + this->last_amp = last_amp; + } + count -= todo; + } + } + break; + case type_msxaudio: + { + struct Y8950* opl = &this->opl; + struct Blip_Buffer* const output = this->output_; + while ( count > 0 ) + { + unsigned todo = count; + if ( todo > 1024 ) todo = 1024; + int *buffer = OPL_updateBuffer(opl, todo); + + if ( output && buffer ) + { + int last_amp = this->last_amp; + unsigned i; + for ( i = 0; i < todo; i++ ) + { + int amp = buffer [i]; + int delta = amp - last_amp; + if ( delta ) + { + last_amp = amp; + Synth_offset_inline( &this->synth, time, delta, output ); + } + time += this->period_; + } + this->last_amp = last_amp; + } + count -= todo; + } + } + break; + } + this->next_time = time; + } +} diff --git a/apps/codecs/libgme/opl_apu.h b/apps/codecs/libgme/opl_apu.h index f24a8d60c2..76fa766492 100644 --- a/apps/codecs/libgme/opl_apu.h +++ b/apps/codecs/libgme/opl_apu.h @@ -1,63 +1,63 @@ -#ifndef OPL_APU_H -#define OPL_APU_H - -#include "blargg_common.h" -#include "blargg_source.h" -#include "blip_buffer.h" - -#include "emu8950.h" -#include "emu2413.h" - -enum opl_type_t { type_opll = 0x10, type_msxmusic = 0x11, type_smsfmunit = 0x12, - type_vrc7 = 0x13, type_msxaudio = 0x21 }; - -enum { opl_osc_count = 1 }; - -struct Opl_Apu { - struct Blip_Buffer* output_; - enum opl_type_t type_; - - blip_time_t next_time; - int last_amp; - int addr; - - long clock_; - long rate_; - blip_time_t period_; - - struct Blip_Synth synth; - - // OPL chips - struct Y8950 opl; - OPLL opll; - - unsigned char regs[ 0x100 ]; - unsigned char opl_memory[ 32768 ]; -}; - -blargg_err_t Opl_init( struct Opl_Apu* this, long clock, long rate, blip_time_t period, enum opl_type_t type ); -void Opl_shutdown( struct Opl_Apu* this ); - -void Opl_reset( struct Opl_Apu* this ); -static inline void Opl_volume( struct Opl_Apu* this, int v ) { Synth_volume( &this->synth, v / (4096 * 6) ); } - -static inline void Opl_osc_output( struct Opl_Apu* this, int i, struct Blip_Buffer* buf ) -{ -#if defined(ROCKBOX) - (void) i; -#endif - assert( (unsigned) i < opl_osc_count ); - this->output_ = buf; -} - -static inline void Opl_set_output( struct Opl_Apu* this, struct Blip_Buffer* buf ) { Opl_osc_output( this, 0, buf ); } -void Opl_end_frame( struct Opl_Apu* this, blip_time_t ); - -static inline void Opl_write_addr( struct Opl_Apu* this, int data ) { this->addr = data; } -void Opl_write_data( struct Opl_Apu* this, blip_time_t, int data ); - -int Opl_read( struct Opl_Apu* this, blip_time_t, int port ); - -static inline bool Opl_supported( void ) { return true; } - -#endif +#ifndef OPL_APU_H +#define OPL_APU_H + +#include "blargg_common.h" +#include "blargg_source.h" +#include "blip_buffer.h" + +#include "emu8950.h" +#include "emu2413.h" + +enum opl_type_t { type_opll = 0x10, type_msxmusic = 0x11, type_smsfmunit = 0x12, + type_vrc7 = 0x13, type_msxaudio = 0x21 }; + +enum { opl_osc_count = 1 }; + +struct Opl_Apu { + struct Blip_Buffer* output_; + enum opl_type_t type_; + + blip_time_t next_time; + int last_amp; + int addr; + + long clock_; + long rate_; + blip_time_t period_; + + struct Blip_Synth synth; + + // OPL chips + struct Y8950 opl; + OPLL opll; + + unsigned char regs[ 0x100 ]; + unsigned char opl_memory[ 32768 ]; +}; + +blargg_err_t Opl_init( struct Opl_Apu* this, long clock, long rate, blip_time_t period, enum opl_type_t type ); +void Opl_shutdown( struct Opl_Apu* this ); + +void Opl_reset( struct Opl_Apu* this ); +static inline void Opl_volume( struct Opl_Apu* this, int v ) { Synth_volume( &this->synth, v / (4096 * 6) ); } + +static inline void Opl_osc_output( struct Opl_Apu* this, int i, struct Blip_Buffer* buf ) +{ +#if defined(ROCKBOX) + (void) i; +#endif + assert( (unsigned) i < opl_osc_count ); + this->output_ = buf; +} + +static inline void Opl_set_output( struct Opl_Apu* this, struct Blip_Buffer* buf ) { Opl_osc_output( this, 0, buf ); } +void Opl_end_frame( struct Opl_Apu* this, blip_time_t ); + +static inline void Opl_write_addr( struct Opl_Apu* this, int data ) { this->addr = data; } +void Opl_write_data( struct Opl_Apu* this, blip_time_t, int data ); + +int Opl_read( struct Opl_Apu* this, blip_time_t, int port ); + +static inline bool Opl_supported( void ) { return true; } + +#endif diff --git a/apps/codecs/libgme/opltables.h b/apps/codecs/libgme/opltables.h index 6ec10eaa6e..50fc0a86c6 100644 --- a/apps/codecs/libgme/opltables.h +++ b/apps/codecs/libgme/opltables.h @@ -1,242 +1,242 @@ -#ifndef _OPLTABLES_H_ -#define _OPLTABLES_H_ - -/* Precalculated emu8950 tables for use in Rockbox, - Calculated for 44Khz sampling rate */ - -static const short ar_adjust_coeff[] = { - 255, 227, 210, 198, 189, 181, 175, 170, 165, 161, 157, - 153, 150, 147, 144, 141, 139, 136, 134, 132, 130, 128, - 126, 125, 123, 121, 120, 118, 117, 115, 114, 113, 112, - 110, 109, 108, 107, 106, 105, 104, 103, 102, 101, 100, - 99, 98, 97, 96, 95, 94, 94, 93, 92, 91, 91, - 90, 89, 88, 88, 87, 86, 86, 85, 84, 84, 83, - 82, 82, 81, 81, 80, 79, 79, 78, 78, 77, 77, - 76, 76, 75, 75, 74, 74, 73, 73, 72, 72, 71, - 71, 70, 70, 69, 69, 69, 68, 68, 67, 67, 66, - 66, 66, 65, 65, 64, 64, 64, 63, 63, 62, 62, - 62, 61, 61, 61, 60, 60, 60, 59, 59, 59, 58, - 58, 58, 57, 57, 57, 56, 56, 56, 55, 55, 55, - 54, 54, 54, 53, 53, 53, 53, 52, 52, 52, 51, - 51, 51, 50, 50, 50, 50, 49, 49, 49, 49, 48, - 48, 48, 48, 47, 47, 47, 46, 46, 46, 46, 45, - 45, 45, 45, 44, 44, 44, 44, 44, 43, 43, 43, - 43, 42, 42, 42, 42, 41, 41, 41, 41, 41, 40, - 40, 40, 40, 39, 39, 39, 39, 39, 38, 38, 38, - 38, 38, 37, 37, 37, 37, 37, 36, 36, 36, 36, - 36, 35, 35, 35, 35, 35, 34, 34, 34, 34, 34, - 33, 33, 33, 33, 33, 33, 32, 32, 32, 32, 32, - 31, 31, 31, 31, 31, 31, 30, 30, 30, 30, 30, - 30, 29, 29, 29, 29, 29, 29, 28, 28, 28, 28, - 28, 28, 27, 27, 27, 27, 27, 27, 26, 26, 26, - 26, 26, 26, 26, 25, 25, 25, 25, 25, 25, 25, - 24, 24, 24, 24, 24, 24, 23, 23, 23, 23, 23, - 23, 23, 22, 22, 22, 22, 22, 22, 22, 21, 21, - 21, 21, 21, 21, 21, 21, 20, 20, 20, 20, 20, - 20, 20, 19, 19, 19, 19, 19, 19, 19, 19, 18, - 18, 18, 18, 18, 18, 18, 18, 17, 17, 17, 17, - 17, 17, 17, 17, 16, 16, 16, 16, 16, 16, 16, - 16, 15, 15, 15, 15, 15, 15, 15, 15, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11, - 11, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, - 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, - 2, 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 -}; - -static const short db2lin_coeff[] = { - 2047, 2003, 1960, 1918, 1877, 1837, 1798, 1759, 1722, 1685, 1649, - 1614, 1579, 1546, 1513, 1480, 1449, 1418, 1387, 1358, 1329, 1300, - 1273, 1245, 1219, 1193, 1167, 1142, 1118, 1094, 1071, 1048, 1025, - 1004, 982, 961, 941, 920, 901, 882, 863, 844, 826, 809, - 791, 774, 758, 742, 726, 710, 695, 680, 666, 651, 638, - 624, 611, 598, 585, 572, 560, 548, 536, 525, 514, 503, - 492, 481, 471, 461, 451, 442, 432, 423, 414, 405, 396, - 388, 380, 371, 364, 356, 348, 341, 333, 326, 319, 312, - 306, 299, 293, 287, 280, 274, 269, 263, 257, 252, 246, - 241, 236, 231, 226, 221, 216, 212, 207, 203, 198, 194, - 190, 186, 182, 178, 174, 170, 167, 163, 160, 156, 153, - 150, 147, 143, 140, 137, 134, 131, 129, 126, 123, 121, - 118, 115, 113, 111, 108, 106, 104, 101, 99, 97, 95, - 93, 91, 89, 87, 85, 83, 82, 80, 78, 76, 75, - 73, 72, 70, 69, 67, 66, 64, 63, 61, 60, 59, - 58, 56, 55, 54, 53, 52, 51, 49, 48, 47, 46, - 45, 44, 43, 42, 42, 41, 40, 39, 38, 37, 36, - 36, 35, 34, 33, 33, 32, 31, 31, 30, 29, 29, - 28, 27, 27, 26, 26, 25, 25, 24, 23, 23, 22, - 22, 21, 21, 21, 20, 20, 19, 19, 18, 18, 18, - 17, 17, 16, 16, 16, 15, 15, 15, 14, 14, 14, - 13, 13, 13, 13, 12, 12, 12, 12, 11, 11, 11, - 11, 10, 10, 10, 10, 9, 9, 9, 9, 9, 8, - 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, - 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, - 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0 -}; - -static const short sin_coeff[] = { - 511, 235, 203, 185, 171, 161, 152, 145, 139, 134, 129, - 124, 120, 117, 113, 110, 107, 104, 102, 99, 97, 95, - 92, 90, 88, 87, 85, 83, 81, 80, 78, 77, 75, - 74, 72, 71, 70, 69, 67, 66, 65, 64, 63, 62, - 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 52, - 51, 50, 49, 48, 48, 47, 46, 45, 45, 44, 43, - 43, 42, 41, 41, 40, 39, 39, 38, 38, 37, 37, - 36, 35, 35, 34, 34, 33, 33, 32, 32, 31, 31, - 30, 30, 29, 29, 28, 28, 28, 27, 27, 26, 26, - 25, 25, 25, 24, 24, 23, 23, 23, 22, 22, 22, - 21, 21, 21, 20, 20, 20, 19, 19, 19, 18, 18, - 18, 17, 17, 17, 16, 16, 16, 16, 15, 15, 15, - 14, 14, 14, 14, 13, 13, 13, 13, 12, 12, 12, - 12, 11, 11, 11, 11, 11, 10, 10, 10, 10, 9, - 9, 9, 9, 9, 8, 8, 8, 8, 8, 7, 7, - 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 5, - 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, - 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, -}; - -static const short pm0_coeff[] = { - 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, - 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, - 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, - 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, - 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, - 256, 256, 257, 257, 257, 257, 257, 257, 257, 257, 257, - 257, 257, 257, 257, 257, 257, 256, 256, 256, 256, 256, - 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, - 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, - 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, - 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, - 256, 256, 256, 256, 256, 256, 256, 256, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 254, - 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, - 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, -}; - -static const short pm1_coeff[] = { - 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, - 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 257, - 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, - 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, - 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, - 257, 258, 258, 258, 258, 258, 258, 258, 258, 258, 258, - 258, 258, 258, 258, 258, 258, 258, 257, 257, 257, 257, - 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, - 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, - 257, 257, 257, 257, 257, 257, 257, 257, 257, 256, 256, - 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, - 256, 256, 256, 256, 256, 256, 256, 256, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 254, 254, 254, 254, 254, - 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, - 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, - 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 253, - 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, - 253, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, - 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, - 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, - 254, 254, 254, 254, 254, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, -}; - -static const short am0_coeff[] = { - 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, -}; - -static const short am1_coeff[] = { - 12, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, - 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 19, - 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, - 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, - 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, - 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, - 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, - 24, 24, 24, 24, 24, 24, 24, 24, 23, 23, 23, - 23, 23, 23, 22, 22, 22, 22, 22, 21, 21, 21, - 21, 20, 20, 20, 20, 19, 19, 19, 19, 18, 18, - 18, 17, 17, 17, 17, 16, 16, 16, 15, 15, 15, - 14, 14, 14, 14, 13, 13, 13, 12, 12, 12, 11, - 11, 11, 10, 10, 10, 9, 9, 9, 9, 8, 8, - 8, 7, 7, 7, 7, 6, 6, 6, 5, 5, 5, - 5, 4, 4, 4, 4, 3, 3, 3, 3, 3, 2, - 2, 2, 2, 2, 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, - 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, - 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, - 5, 5, 5, 6, 6, 6, 7, 7, 7, 7, 8, - 8, 8, 9, 9, 9, 9, 10, 10, 10, 11, 11, - 11, 12, 12, -}; - -#endif +#ifndef _OPLTABLES_H_ +#define _OPLTABLES_H_ + +/* Precalculated emu8950 tables for use in Rockbox, + Calculated for 44Khz sampling rate */ + +static const short ar_adjust_coeff[] = { + 255, 227, 210, 198, 189, 181, 175, 170, 165, 161, 157, + 153, 150, 147, 144, 141, 139, 136, 134, 132, 130, 128, + 126, 125, 123, 121, 120, 118, 117, 115, 114, 113, 112, + 110, 109, 108, 107, 106, 105, 104, 103, 102, 101, 100, + 99, 98, 97, 96, 95, 94, 94, 93, 92, 91, 91, + 90, 89, 88, 88, 87, 86, 86, 85, 84, 84, 83, + 82, 82, 81, 81, 80, 79, 79, 78, 78, 77, 77, + 76, 76, 75, 75, 74, 74, 73, 73, 72, 72, 71, + 71, 70, 70, 69, 69, 69, 68, 68, 67, 67, 66, + 66, 66, 65, 65, 64, 64, 64, 63, 63, 62, 62, + 62, 61, 61, 61, 60, 60, 60, 59, 59, 59, 58, + 58, 58, 57, 57, 57, 56, 56, 56, 55, 55, 55, + 54, 54, 54, 53, 53, 53, 53, 52, 52, 52, 51, + 51, 51, 50, 50, 50, 50, 49, 49, 49, 49, 48, + 48, 48, 48, 47, 47, 47, 46, 46, 46, 46, 45, + 45, 45, 45, 44, 44, 44, 44, 44, 43, 43, 43, + 43, 42, 42, 42, 42, 41, 41, 41, 41, 41, 40, + 40, 40, 40, 39, 39, 39, 39, 39, 38, 38, 38, + 38, 38, 37, 37, 37, 37, 37, 36, 36, 36, 36, + 36, 35, 35, 35, 35, 35, 34, 34, 34, 34, 34, + 33, 33, 33, 33, 33, 33, 32, 32, 32, 32, 32, + 31, 31, 31, 31, 31, 31, 30, 30, 30, 30, 30, + 30, 29, 29, 29, 29, 29, 29, 28, 28, 28, 28, + 28, 28, 27, 27, 27, 27, 27, 27, 26, 26, 26, + 26, 26, 26, 26, 25, 25, 25, 25, 25, 25, 25, + 24, 24, 24, 24, 24, 24, 23, 23, 23, 23, 23, + 23, 23, 22, 22, 22, 22, 22, 22, 22, 21, 21, + 21, 21, 21, 21, 21, 21, 20, 20, 20, 20, 20, + 20, 20, 19, 19, 19, 19, 19, 19, 19, 19, 18, + 18, 18, 18, 18, 18, 18, 18, 17, 17, 17, 17, + 17, 17, 17, 17, 16, 16, 16, 16, 16, 16, 16, + 16, 15, 15, 15, 15, 15, 15, 15, 15, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, + 2, 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 +}; + +static const short db2lin_coeff[] = { + 2047, 2003, 1960, 1918, 1877, 1837, 1798, 1759, 1722, 1685, 1649, + 1614, 1579, 1546, 1513, 1480, 1449, 1418, 1387, 1358, 1329, 1300, + 1273, 1245, 1219, 1193, 1167, 1142, 1118, 1094, 1071, 1048, 1025, + 1004, 982, 961, 941, 920, 901, 882, 863, 844, 826, 809, + 791, 774, 758, 742, 726, 710, 695, 680, 666, 651, 638, + 624, 611, 598, 585, 572, 560, 548, 536, 525, 514, 503, + 492, 481, 471, 461, 451, 442, 432, 423, 414, 405, 396, + 388, 380, 371, 364, 356, 348, 341, 333, 326, 319, 312, + 306, 299, 293, 287, 280, 274, 269, 263, 257, 252, 246, + 241, 236, 231, 226, 221, 216, 212, 207, 203, 198, 194, + 190, 186, 182, 178, 174, 170, 167, 163, 160, 156, 153, + 150, 147, 143, 140, 137, 134, 131, 129, 126, 123, 121, + 118, 115, 113, 111, 108, 106, 104, 101, 99, 97, 95, + 93, 91, 89, 87, 85, 83, 82, 80, 78, 76, 75, + 73, 72, 70, 69, 67, 66, 64, 63, 61, 60, 59, + 58, 56, 55, 54, 53, 52, 51, 49, 48, 47, 46, + 45, 44, 43, 42, 42, 41, 40, 39, 38, 37, 36, + 36, 35, 34, 33, 33, 32, 31, 31, 30, 29, 29, + 28, 27, 27, 26, 26, 25, 25, 24, 23, 23, 22, + 22, 21, 21, 21, 20, 20, 19, 19, 18, 18, 18, + 17, 17, 16, 16, 16, 15, 15, 15, 14, 14, 14, + 13, 13, 13, 13, 12, 12, 12, 12, 11, 11, 11, + 11, 10, 10, 10, 10, 9, 9, 9, 9, 9, 8, + 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, + 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, + 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0 +}; + +static const short sin_coeff[] = { + 511, 235, 203, 185, 171, 161, 152, 145, 139, 134, 129, + 124, 120, 117, 113, 110, 107, 104, 102, 99, 97, 95, + 92, 90, 88, 87, 85, 83, 81, 80, 78, 77, 75, + 74, 72, 71, 70, 69, 67, 66, 65, 64, 63, 62, + 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 52, + 51, 50, 49, 48, 48, 47, 46, 45, 45, 44, 43, + 43, 42, 41, 41, 40, 39, 39, 38, 38, 37, 37, + 36, 35, 35, 34, 34, 33, 33, 32, 32, 31, 31, + 30, 30, 29, 29, 28, 28, 28, 27, 27, 26, 26, + 25, 25, 25, 24, 24, 23, 23, 23, 22, 22, 22, + 21, 21, 21, 20, 20, 20, 19, 19, 19, 18, 18, + 18, 17, 17, 17, 16, 16, 16, 16, 15, 15, 15, + 14, 14, 14, 14, 13, 13, 13, 13, 12, 12, 12, + 12, 11, 11, 11, 11, 11, 10, 10, 10, 10, 9, + 9, 9, 9, 9, 8, 8, 8, 8, 8, 7, 7, + 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 5, + 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, + 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, +}; + +static const short pm0_coeff[] = { + 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, + 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, + 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, + 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, + 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, + 256, 256, 257, 257, 257, 257, 257, 257, 257, 257, 257, + 257, 257, 257, 257, 257, 257, 256, 256, 256, 256, 256, + 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, + 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, + 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, + 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, + 256, 256, 256, 256, 256, 256, 256, 256, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 254, + 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, + 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, +}; + +static const short pm1_coeff[] = { + 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, + 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 257, + 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, + 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, + 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, + 257, 258, 258, 258, 258, 258, 258, 258, 258, 258, 258, + 258, 258, 258, 258, 258, 258, 258, 257, 257, 257, 257, + 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, + 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, + 257, 257, 257, 257, 257, 257, 257, 257, 257, 256, 256, + 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, + 256, 256, 256, 256, 256, 256, 256, 256, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 254, 254, 254, 254, 254, + 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, + 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, + 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 253, + 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, + 253, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, + 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, + 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, + 254, 254, 254, 254, 254, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, +}; + +static const short am0_coeff[] = { + 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, +}; + +static const short am1_coeff[] = { + 12, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, + 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 19, + 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, + 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, + 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 24, 24, 24, 24, 24, 24, 24, 24, 23, 23, 23, + 23, 23, 23, 22, 22, 22, 22, 22, 21, 21, 21, + 21, 20, 20, 20, 20, 19, 19, 19, 19, 18, 18, + 18, 17, 17, 17, 17, 16, 16, 16, 15, 15, 15, + 14, 14, 14, 14, 13, 13, 13, 12, 12, 12, 11, + 11, 11, 10, 10, 10, 9, 9, 9, 9, 8, 8, + 8, 7, 7, 7, 7, 6, 6, 6, 5, 5, 5, + 5, 4, 4, 4, 4, 3, 3, 3, 3, 3, 2, + 2, 2, 2, 2, 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, + 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, + 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, + 5, 5, 5, 6, 6, 6, 7, 7, 7, 7, 8, + 8, 8, 9, 9, 9, 9, 10, 10, 10, 11, 11, + 11, 12, 12, +}; + +#endif diff --git a/apps/codecs/libgme/sgc_cpu.c b/apps/codecs/libgme/sgc_cpu.c index 3bd2d15df9..d23c01499b 100644 --- a/apps/codecs/libgme/sgc_cpu.c +++ b/apps/codecs/libgme/sgc_cpu.c @@ -1,36 +1,36 @@ -// Game_Music_Emu 0.6-pre. http://www.slack.net/~ant/ - -#include "sgc_emu.h" - -#include "blargg_endian.h" -//#include "z80_cpu_log.h" - -/* Copyright (C) 2009 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. This -module 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 Lesser General Public License for more -details. You should have received a copy of the GNU Lesser General Public -License along with this module; if not, write to the Free Software Foundation, -Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ - -#include "blargg_source.h" - -#define OUT_PORT( addr, data ) cpu_out( this, TIME(), addr, data ) -#define IN_PORT( addr ) 0 // cpu in -#define WRITE_MEM( addr, data ) cpu_write( this, addr, data ) -#define IDLE_ADDR this->idle_addr -#define RST_BASE this->vectors_addr - -#define CPU_BEGIN \ -bool run_cpu( struct Sgc_Emu* this, cpu_time_t end_time )\ -{\ - Sgc_Cpu* cpu = &this->cpu; \ - Z80_set_end_time( cpu, end_time ); - - #include "z80_cpu_run.h" - - return warning; -} +// Game_Music_Emu 0.6-pre. http://www.slack.net/~ant/ + +#include "sgc_emu.h" + +#include "blargg_endian.h" +//#include "z80_cpu_log.h" + +/* Copyright (C) 2009 Shay Green. This module is free software; you +can redistribute it and/or modify it under the terms of the GNU Lesser +General Public License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. This +module 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 Lesser General Public License for more +details. You should have received a copy of the GNU Lesser General Public +License along with this module; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ + +#include "blargg_source.h" + +#define OUT_PORT( addr, data ) cpu_out( this, TIME(), addr, data ) +#define IN_PORT( addr ) 0 // cpu in +#define WRITE_MEM( addr, data ) cpu_write( this, addr, data ) +#define IDLE_ADDR this->idle_addr +#define RST_BASE this->vectors_addr + +#define CPU_BEGIN \ +bool run_cpu( struct Sgc_Emu* this, cpu_time_t end_time )\ +{\ + Sgc_Cpu* cpu = &this->cpu; \ + Z80_set_end_time( cpu, end_time ); + + #include "z80_cpu_run.h" + + return warning; +} diff --git a/apps/codecs/libgme/sgc_emu.c b/apps/codecs/libgme/sgc_emu.c index e7253a8d5b..267f2c9271 100644 --- a/apps/codecs/libgme/sgc_emu.c +++ b/apps/codecs/libgme/sgc_emu.c @@ -1,480 +1,480 @@ -// Game_Music_Emu 0.6-pre. http://www.slack.net/~ant/ - -#include "sgc_emu.h" - -/* Copyright (C) 2009 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. This -module 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 Lesser General Public License for more -details. You should have received a copy of the GNU Lesser General Public -License aint with this module; if not, write to the Free Software Foundation, -Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ - -#include "blargg_source.h" - -int const osc_count = sms_osc_count + fm_apu_osc_count; - -const char gme_wrong_file_type [] = "Wrong file type for this emulator"; - -static void clear_track_vars( struct Sgc_Emu* this ) -{ - this->current_track = -1; - track_stop( &this->track_filter ); -} - -void Sgc_init( struct Sgc_Emu* this ) -{ - assert( offsetof (struct header_t,copyright [32]) == header_size ); - - this->sample_rate = 0; - this->mute_mask_ = 0; - this->tempo = (int)FP_ONE_TEMPO; - this->gain = (int)FP_ONE_GAIN; - - // defaults - this->tfilter = *track_get_setup( &this->track_filter ); - this->tfilter.max_initial = 2; - this->tfilter.lookahead = 6; - this->track_filter.silence_ignored_ = false; - - Sms_apu_init( &this->apu ); - Fm_apu_create( &this->fm_apu ); - - Rom_init( &this->rom, 0x4000 ); - Z80_init( &this->cpu ); - - Sound_set_gain( this, (int)(FP_ONE_GAIN*1.2) ); - - // Unload - this->voice_count = 0; - this->voice_types = 0; - clear_track_vars( this ); -} - -// Setup - -blargg_err_t Sgc_load_mem( struct Sgc_Emu* this, const void* data, long size ) -{ - RETURN_ERR( Rom_load( &this->rom, data, size, header_size, &this->header, 0 ) ); - - if ( !valid_tag( &this->header ) ) - return gme_wrong_file_type; - - /* if ( header.vers != 1 ) - warning( "Unknown file version" ); */ - - /* if ( header.system > 2 ) - warning( "Unknown system" ); */ - - addr_t load_addr = get_le16( this->header.load_addr ); - /* if ( load_addr < 0x400 ) - set_warning( "Invalid load address" ); */ - - Rom_set_addr( &this->rom, load_addr ); - this->play_period = clock_rate( this ) / 60; - - if ( sega_mapping( this ) && Fm_apu_supported() ) - RETURN_ERR( Fm_apu_init( &this->fm_apu, clock_rate( this ), clock_rate( this ) / 72 ) ); - - this->m3u.size = 0; - this->track_count = this->header.song_count; - this->voice_count = sega_mapping( this ) ? osc_count : sms_osc_count; - static int const types [sms_osc_count + fm_apu_osc_count] = { - wave_type+1, wave_type+2, wave_type+3, mixed_type+1, mixed_type+2 - }; - this->voice_types = types; - - Sms_apu_volume( &this->apu, this->gain ); - Fm_apu_volume( &this->fm_apu, this->gain ); - - // Setup buffer - this->clock_rate_ = clock_rate( this ); - Buffer_clock_rate( &this->stereo_buf, clock_rate( this ) ); - RETURN_ERR( Buffer_set_channel_count( &this->stereo_buf, this->voice_count, this->voice_types ) ); - this->buf_changed_count = Buffer_channels_changed_count( &this->stereo_buf ); - - Sound_set_tempo( this, this->tempo ); - Sound_mute_voices( this, this->mute_mask_ ); - return 0; -} - -static void Sound_set_voice( struct Sgc_Emu* this, int i, struct Blip_Buffer* c, struct Blip_Buffer* l, struct Blip_Buffer* r ) -{ - if ( i < sms_osc_count ) - Sms_apu_set_output( &this->apu, i, c, l, r ); - else - Fm_apu_set_output( &this->fm_apu, c ); -} - -static blargg_err_t run_clocks( struct Sgc_Emu* this, blip_time_t* duration, int msec ) -{ -#if defined(ROCKBOX) - (void) msec; -#endif - - cpu_time_t t = *duration; - while ( Z80_time( &this->cpu ) < t ) - { - cpu_time_t next = min( t, this->next_play ); - if ( run_cpu( this, next ) ) - { - /* warning( "Unsupported CPU instruction" ); */ - Z80_set_time( &this->cpu, next ); - } - - if ( this->cpu.r.pc == this->idle_addr ) - Z80_set_time( &this->cpu, next ); - - if ( Z80_time( &this->cpu ) >= this->next_play ) - { - this->next_play += this->play_period; - if ( this->cpu.r.pc == this->idle_addr ) - jsr( this, this->header.play_addr ); - } - } - - this->next_play -= t; - check( this->next_play >= 0 ); - Z80_adjust_time( &this->cpu, -t ); - - Sms_apu_end_frame( &this->apu, t ); - if ( sega_mapping( this ) && this->fm_accessed ) - { - if ( Fm_apu_supported() ) - Fm_apu_end_frame( &this->fm_apu, t ); - /* else - warning( "FM sound not supported" ); */ - } - - return 0; -} - -// Emulation - -void cpu_out( struct Sgc_Emu* this, cpu_time_t time, addr_t addr, int data ) -{ - int port = addr & 0xFF; - - if ( sega_mapping( this ) ) - { - switch ( port ) - { - case 0x06: - Sms_apu_write_ggstereo( &this->apu, time, data ); - return; - - case 0x7E: - case 0x7F: - Sms_apu_write_data( &this->apu, time, data ); /* dprintf( "$7E<-%02X\n", data ); */ - return; - - case 0xF0: - this->fm_accessed = true; - if ( Fm_apu_supported() ) - Fm_apu_write_addr( &this->fm_apu, data );//, dprintf( "$F0<-%02X\n", data ); - return; - - case 0xF1: - this->fm_accessed = true; - if ( Fm_apu_supported() ) - Fm_apu_write_data( &this->fm_apu, time, data );//, dprintf( "$F1<-%02X\n", data ); - return; - } - } - else if ( port >= 0xE0 ) - { - Sms_apu_write_data( &this->apu, time, data ); - return; - } -} - -void jsr( struct Sgc_Emu* this, byte addr [2] ) -{ - *Z80_write( &this->cpu, --this->cpu.r.sp ) = this->idle_addr >> 8; - *Z80_write( &this->cpu, --this->cpu.r.sp ) = this->idle_addr & 0xFF; - this->cpu.r.pc = get_le16( addr ); -} - -static void set_bank( struct Sgc_Emu* this, int bank, void const* data ) -{ - //dprintf( "map bank %d to %p\n", bank, (byte*) data - rom.at_addr( 0 ) ); - Z80_map_mem( &this->cpu, bank * this->rom.bank_size, this->rom.bank_size, this->unmapped_write, data ); -} - -void cpu_write( struct Sgc_Emu* this, addr_t addr, int data ) -{ - if ( (addr ^ 0xFFFC) > 3 || !sega_mapping( this ) ) - { - *Z80_write( &this->cpu, addr ) = data; - return; - } - - switch ( addr ) - { - case 0xFFFC: - Z80_map_mem_rw( &this->cpu, 2 * this->rom.bank_size, this->rom.bank_size, this->ram2 ); - if ( data & 0x08 ) - break; - - this->bank2 = this->ram2; - // FALL THROUGH - - case 0xFFFF: { - bool rom_mapped = (Z80_read( &this->cpu, 2 * this->rom.bank_size ) == this->bank2); - this->bank2 = Rom_at_addr( &this->rom, data * this->rom.bank_size ); - if ( rom_mapped ) - set_bank( this, 2, this->bank2 ); - break; - } - - case 0xFFFD: - set_bank( this, 0, Rom_at_addr( &this->rom, data * this->rom.bank_size ) ); - break; - - case 0xFFFE: - set_bank( this, 1, Rom_at_addr( &this->rom, data * this->rom.bank_size ) ); - break; - } -} - -blargg_err_t Sgc_set_sample_rate( struct Sgc_Emu* this, int rate ) -{ - require( !this->sample_rate ); // sample rate can't be changed once set - Buffer_init( &this->stereo_buf ); - Buffer_set_sample_rate( &this->stereo_buf, rate, 1000 / 20 ); - - // Set buffer bass - Buffer_bass_freq( &this->stereo_buf, 80 ); - - this->sample_rate = rate; - RETURN_ERR( track_init( &this->track_filter, this ) ); - this->tfilter.max_silence = 6 * stereo * this->sample_rate; - return 0; -} - -void Sound_mute_voice( struct Sgc_Emu* this, int index, bool mute ) -{ - require( (unsigned) index < (unsigned) this->voice_count ); - int bit = 1 << index; - int mask = this->mute_mask_ | bit; - if ( !mute ) - mask ^= bit; - Sound_mute_voices( this, mask ); -} - -void Sound_mute_voices( struct Sgc_Emu* this, int mask ) -{ - require( this->sample_rate ); // sample rate must be set first - this->mute_mask_ = mask; - - int i; - for ( i = this->voice_count; i--; ) - { - if ( mask & (1 << i) ) - { - Sound_set_voice( this, i, 0, 0, 0 ); - } - else - { - struct channel_t ch = Buffer_channel( &this->stereo_buf, i ); - assert( (ch.center && ch.left && ch.right) || - (!ch.center && !ch.left && !ch.right) ); // all or nothing - Sound_set_voice( this, i, ch.center, ch.left, ch.right ); - } - } -} - -void Sound_set_tempo( struct Sgc_Emu* this, int t ) -{ - require( this->sample_rate ); // sample rate must be set first - int const min = (int)(FP_ONE_TEMPO*0.02); - int const max = (int)(FP_ONE_TEMPO*4.00); - if ( t < min ) t = min; - if ( t > max ) t = max; - this->tempo = t; - - this->play_period = (int) ((clock_rate( this ) * FP_ONE_TEMPO) / (this->header.rate ? 50 : 60) / t); -} - -blargg_err_t Sgc_start_track( struct Sgc_Emu* this, int track ) -{ - clear_track_vars( this ); - - // Remap track if playlist available - if ( this->m3u.size > 0 ) { - struct entry_t* e = &this->m3u.entries[track]; - track = e->track; - } - - this->current_track = track; - - if ( sega_mapping( this ) ) - { - Sms_apu_reset( &this->apu, 0, 0 ); - Fm_apu_reset( &this->fm_apu ); - this->fm_accessed = false; - } - else - { - Sms_apu_reset( &this->apu, 0x0003, 15 ); - } - - memset( this->ram , 0, sizeof this->ram ); - memset( this->ram2, 0, sizeof this->ram2 ); - memset( this->vectors, 0xFF, sizeof this->vectors ); - Z80_reset( &this->cpu, this->unmapped_write, this->rom.unmapped ); - - if ( sega_mapping( this ) ) - { - this->vectors_addr = 0x10000 - page_size; - this->idle_addr = this->vectors_addr; - int i; - for ( i = 1; i < 8; ++i ) - { - this->vectors [i*8 + 0] = 0xC3; // JP addr - this->vectors [i*8 + 1] = this->header.rst_addrs [i - 1] & 0xff; - this->vectors [i*8 + 2] = this->header.rst_addrs [i - 1] >> 8; - } - - Z80_map_mem_rw( &this->cpu, 0xC000, 0x2000, this->ram ); - Z80_map_mem( &this->cpu, this->vectors_addr, page_size, this->unmapped_write, this->vectors ); - - this->bank2 = NULL; - for ( i = 0; i < 4; ++i ) - cpu_write( this, 0xFFFC + i, this->header.mapping [i] ); - } - else - { - if ( !this->coleco_bios ) - return "Coleco BIOS not set"; /* BLARGG_ERR( BLARGG_ERR_CALLER, "Coleco BIOS not set" ); */ - - this->vectors_addr = 0; - Z80_map_mem( &this->cpu, 0, 0x2000, this->unmapped_write, this->coleco_bios ); - int i; - for ( i = 0; i < 8; ++i ) - Z80_map_mem_rw( &this->cpu, 0x6000 + i*0x400, 0x400, this->ram ); - - this->idle_addr = 0x2000; - Z80_map_mem( &this->cpu, 0x2000, page_size, this->unmapped_write, this->vectors ); - - for ( i = 0; i < 0x8000 / this->rom.bank_size; ++i ) - { - int addr = 0x8000 + i*this->rom.bank_size; - Z80_map_mem( &this->cpu, addr, this->rom.bank_size, this->unmapped_write, Rom_at_addr( &this->rom, addr ) ); - } - } - - this->cpu.r.sp = get_le16( this->header.stack_ptr ); - this->cpu.r.b.a = track; - this->next_play = this->play_period; - - jsr( this, this->header.init_addr ); - - Buffer_clear( &this->stereo_buf ); - - // convert filter times to samples - struct setup_t s = this->tfilter; - s.max_initial *= this->sample_rate * stereo; - #ifdef GME_DISABLE_SILENCE_LOOKAHEAD - s.lookahead = 1; - #endif - track_setup( &this->track_filter, &s ); - - return track_start( &this->track_filter ); -} - -// Tell/Seek - -static int msec_to_samples( int msec, int sample_rate ) -{ - int sec = msec / 1000; - msec -= sec * 1000; - return (sec * sample_rate + msec * sample_rate / 1000) * stereo; -} - -int Track_tell( struct Sgc_Emu* this ) -{ - int rate = this->sample_rate * stereo; - int sec = track_sample_count( &this->track_filter ) / rate; - return sec * 1000 + (track_sample_count( &this->track_filter ) - sec * rate) * 1000 / rate; -} - -blargg_err_t Track_seek( struct Sgc_Emu* this, int msec ) -{ - int time = msec_to_samples( msec, this->sample_rate ); - if ( time < track_sample_count( &this->track_filter ) ) - RETURN_ERR( Sgc_start_track( this, this->current_track ) ); - return Track_skip( this, time - track_sample_count( &this->track_filter ) ); -} - -blargg_err_t Track_skip( struct Sgc_Emu* this, int count ) -{ - require( this->current_track >= 0 ); // start_track() must have been called already - return track_skip( &this->track_filter, count ); -} - -blargg_err_t skip_( void* emu, int count ) -{ - struct Sgc_Emu* this = (struct Sgc_Emu*) emu; - - // for long skip, mute sound - const int threshold = 32768; - if ( count > threshold ) - { - int saved_mute = this->mute_mask_; - Sound_mute_voices( this, ~0 ); - - int n = count - threshold/2; - n &= ~(2048-1); // round to multiple of 2048 - count -= n; - RETURN_ERR( skippy_( &this->track_filter, n ) ); - - Sound_mute_voices( this, saved_mute ); - } - - return skippy_( &this->track_filter, count ); -} - -void Track_set_fade( struct Sgc_Emu* this, int start_msec, int length_msec ) -{ - track_set_fade( &this->track_filter, msec_to_samples( start_msec, this->sample_rate ), - length_msec * this->sample_rate / (1000 / stereo) ); -} - -blargg_err_t Sgc_play( struct Sgc_Emu* this, int out_count, sample_t* out ) -{ - require( this->current_track >= 0 ); - require( out_count % stereo == 0 ); - return track_play( &this->track_filter, out_count, out ); -} - -blargg_err_t play_( void* emu, int count, sample_t out [] ) -{ - struct Sgc_Emu* this = (struct Sgc_Emu*) emu; - - int remain = count; - while ( remain ) - { - Buffer_disable_immediate_removal( &this->stereo_buf ); - remain -= Buffer_read_samples( &this->stereo_buf, &out [count - remain], remain ); - if ( remain ) - { - if ( this->buf_changed_count != Buffer_channels_changed_count( &this->stereo_buf ) ) - { - this->buf_changed_count = Buffer_channels_changed_count( &this->stereo_buf ); - - // Remute voices - Sound_mute_voices( this, this->mute_mask_ ); - } - int msec = Buffer_length( &this->stereo_buf ); - blip_time_t clocks_emulated = msec * this->clock_rate_ / 1000 - 100; - RETURN_ERR( run_clocks( this, &clocks_emulated, msec ) ); - assert( clocks_emulated ); - Buffer_end_frame( &this->stereo_buf, clocks_emulated ); - } - } - return 0; -} +// Game_Music_Emu 0.6-pre. http://www.slack.net/~ant/ + +#include "sgc_emu.h" + +/* Copyright (C) 2009 Shay Green. This module is free software; you +can redistribute it and/or modify it under the terms of the GNU Lesser +General Public License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. This +module 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 Lesser General Public License for more +details. You should have received a copy of the GNU Lesser General Public +License aint with this module; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ + +#include "blargg_source.h" + +int const osc_count = sms_osc_count + fm_apu_osc_count; + +const char gme_wrong_file_type [] = "Wrong file type for this emulator"; + +static void clear_track_vars( struct Sgc_Emu* this ) +{ + this->current_track = -1; + track_stop( &this->track_filter ); +} + +void Sgc_init( struct Sgc_Emu* this ) +{ + assert( offsetof (struct header_t,copyright [32]) == header_size ); + + this->sample_rate = 0; + this->mute_mask_ = 0; + this->tempo = (int)FP_ONE_TEMPO; + this->gain = (int)FP_ONE_GAIN; + + // defaults + this->tfilter = *track_get_setup( &this->track_filter ); + this->tfilter.max_initial = 2; + this->tfilter.lookahead = 6; + this->track_filter.silence_ignored_ = false; + + Sms_apu_init( &this->apu ); + Fm_apu_create( &this->fm_apu ); + + Rom_init( &this->rom, 0x4000 ); + Z80_init( &this->cpu ); + + Sound_set_gain( this, (int)(FP_ONE_GAIN*1.2) ); + + // Unload + this->voice_count = 0; + this->voice_types = 0; + clear_track_vars( this ); +} + +// Setup + +blargg_err_t Sgc_load_mem( struct Sgc_Emu* this, const void* data, long size ) +{ + RETURN_ERR( Rom_load( &this->rom, data, size, header_size, &this->header, 0 ) ); + + if ( !valid_tag( &this->header ) ) + return gme_wrong_file_type; + + /* if ( header.vers != 1 ) + warning( "Unknown file version" ); */ + + /* if ( header.system > 2 ) + warning( "Unknown system" ); */ + + addr_t load_addr = get_le16( this->header.load_addr ); + /* if ( load_addr < 0x400 ) + set_warning( "Invalid load address" ); */ + + Rom_set_addr( &this->rom, load_addr ); + this->play_period = clock_rate( this ) / 60; + + if ( sega_mapping( this ) && Fm_apu_supported() ) + RETURN_ERR( Fm_apu_init( &this->fm_apu, clock_rate( this ), clock_rate( this ) / 72 ) ); + + this->m3u.size = 0; + this->track_count = this->header.song_count; + this->voice_count = sega_mapping( this ) ? osc_count : sms_osc_count; + static int const types [sms_osc_count + fm_apu_osc_count] = { + wave_type+1, wave_type+2, wave_type+3, mixed_type+1, mixed_type+2 + }; + this->voice_types = types; + + Sms_apu_volume( &this->apu, this->gain ); + Fm_apu_volume( &this->fm_apu, this->gain ); + + // Setup buffer + this->clock_rate_ = clock_rate( this ); + Buffer_clock_rate( &this->stereo_buf, clock_rate( this ) ); + RETURN_ERR( Buffer_set_channel_count( &this->stereo_buf, this->voice_count, this->voice_types ) ); + this->buf_changed_count = Buffer_channels_changed_count( &this->stereo_buf ); + + Sound_set_tempo( this, this->tempo ); + Sound_mute_voices( this, this->mute_mask_ ); + return 0; +} + +static void Sound_set_voice( struct Sgc_Emu* this, int i, struct Blip_Buffer* c, struct Blip_Buffer* l, struct Blip_Buffer* r ) +{ + if ( i < sms_osc_count ) + Sms_apu_set_output( &this->apu, i, c, l, r ); + else + Fm_apu_set_output( &this->fm_apu, c ); +} + +static blargg_err_t run_clocks( struct Sgc_Emu* this, blip_time_t* duration, int msec ) +{ +#if defined(ROCKBOX) + (void) msec; +#endif + + cpu_time_t t = *duration; + while ( Z80_time( &this->cpu ) < t ) + { + cpu_time_t next = min( t, this->next_play ); + if ( run_cpu( this, next ) ) + { + /* warning( "Unsupported CPU instruction" ); */ + Z80_set_time( &this->cpu, next ); + } + + if ( this->cpu.r.pc == this->idle_addr ) + Z80_set_time( &this->cpu, next ); + + if ( Z80_time( &this->cpu ) >= this->next_play ) + { + this->next_play += this->play_period; + if ( this->cpu.r.pc == this->idle_addr ) + jsr( this, this->header.play_addr ); + } + } + + this->next_play -= t; + check( this->next_play >= 0 ); + Z80_adjust_time( &this->cpu, -t ); + + Sms_apu_end_frame( &this->apu, t ); + if ( sega_mapping( this ) && this->fm_accessed ) + { + if ( Fm_apu_supported() ) + Fm_apu_end_frame( &this->fm_apu, t ); + /* else + warning( "FM sound not supported" ); */ + } + + return 0; +} + +// Emulation + +void cpu_out( struct Sgc_Emu* this, cpu_time_t time, addr_t addr, int data ) +{ + int port = addr & 0xFF; + + if ( sega_mapping( this ) ) + { + switch ( port ) + { + case 0x06: + Sms_apu_write_ggstereo( &this->apu, time, data ); + return; + + case 0x7E: + case 0x7F: + Sms_apu_write_data( &this->apu, time, data ); /* dprintf( "$7E<-%02X\n", data ); */ + return; + + case 0xF0: + this->fm_accessed = true; + if ( Fm_apu_supported() ) + Fm_apu_write_addr( &this->fm_apu, data );//, dprintf( "$F0<-%02X\n", data ); + return; + + case 0xF1: + this->fm_accessed = true; + if ( Fm_apu_supported() ) + Fm_apu_write_data( &this->fm_apu, time, data );//, dprintf( "$F1<-%02X\n", data ); + return; + } + } + else if ( port >= 0xE0 ) + { + Sms_apu_write_data( &this->apu, time, data ); + return; + } +} + +void jsr( struct Sgc_Emu* this, byte addr [2] ) +{ + *Z80_write( &this->cpu, --this->cpu.r.sp ) = this->idle_addr >> 8; + *Z80_write( &this->cpu, --this->cpu.r.sp ) = this->idle_addr & 0xFF; + this->cpu.r.pc = get_le16( addr ); +} + +static void set_bank( struct Sgc_Emu* this, int bank, void const* data ) +{ + //dprintf( "map bank %d to %p\n", bank, (byte*) data - rom.at_addr( 0 ) ); + Z80_map_mem( &this->cpu, bank * this->rom.bank_size, this->rom.bank_size, this->unmapped_write, data ); +} + +void cpu_write( struct Sgc_Emu* this, addr_t addr, int data ) +{ + if ( (addr ^ 0xFFFC) > 3 || !sega_mapping( this ) ) + { + *Z80_write( &this->cpu, addr ) = data; + return; + } + + switch ( addr ) + { + case 0xFFFC: + Z80_map_mem_rw( &this->cpu, 2 * this->rom.bank_size, this->rom.bank_size, this->ram2 ); + if ( data & 0x08 ) + break; + + this->bank2 = this->ram2; + // FALL THROUGH + + case 0xFFFF: { + bool rom_mapped = (Z80_read( &this->cpu, 2 * this->rom.bank_size ) == this->bank2); + this->bank2 = Rom_at_addr( &this->rom, data * this->rom.bank_size ); + if ( rom_mapped ) + set_bank( this, 2, this->bank2 ); + break; + } + + case 0xFFFD: + set_bank( this, 0, Rom_at_addr( &this->rom, data * this->rom.bank_size ) ); + break; + + case 0xFFFE: + set_bank( this, 1, Rom_at_addr( &this->rom, data * this->rom.bank_size ) ); + break; + } +} + +blargg_err_t Sgc_set_sample_rate( struct Sgc_Emu* this, int rate ) +{ + require( !this->sample_rate ); // sample rate can't be changed once set + Buffer_init( &this->stereo_buf ); + Buffer_set_sample_rate( &this->stereo_buf, rate, 1000 / 20 ); + + // Set buffer bass + Buffer_bass_freq( &this->stereo_buf, 80 ); + + this->sample_rate = rate; + RETURN_ERR( track_init( &this->track_filter, this ) ); + this->tfilter.max_silence = 6 * stereo * this->sample_rate; + return 0; +} + +void Sound_mute_voice( struct Sgc_Emu* this, int index, bool mute ) +{ + require( (unsigned) index < (unsigned) this->voice_count ); + int bit = 1 << index; + int mask = this->mute_mask_ | bit; + if ( !mute ) + mask ^= bit; + Sound_mute_voices( this, mask ); +} + +void Sound_mute_voices( struct Sgc_Emu* this, int mask ) +{ + require( this->sample_rate ); // sample rate must be set first + this->mute_mask_ = mask; + + int i; + for ( i = this->voice_count; i--; ) + { + if ( mask & (1 << i) ) + { + Sound_set_voice( this, i, 0, 0, 0 ); + } + else + { + struct channel_t ch = Buffer_channel( &this->stereo_buf, i ); + assert( (ch.center && ch.left && ch.right) || + (!ch.center && !ch.left && !ch.right) ); // all or nothing + Sound_set_voice( this, i, ch.center, ch.left, ch.right ); + } + } +} + +void Sound_set_tempo( struct Sgc_Emu* this, int t ) +{ + require( this->sample_rate ); // sample rate must be set first + int const min = (int)(FP_ONE_TEMPO*0.02); + int const max = (int)(FP_ONE_TEMPO*4.00); + if ( t < min ) t = min; + if ( t > max ) t = max; + this->tempo = t; + + this->play_period = (int) ((clock_rate( this ) * FP_ONE_TEMPO) / (this->header.rate ? 50 : 60) / t); +} + +blargg_err_t Sgc_start_track( struct Sgc_Emu* this, int track ) +{ + clear_track_vars( this ); + + // Remap track if playlist available + if ( this->m3u.size > 0 ) { + struct entry_t* e = &this->m3u.entries[track]; + track = e->track; + } + + this->current_track = track; + + if ( sega_mapping( this ) ) + { + Sms_apu_reset( &this->apu, 0, 0 ); + Fm_apu_reset( &this->fm_apu ); + this->fm_accessed = false; + } + else + { + Sms_apu_reset( &this->apu, 0x0003, 15 ); + } + + memset( this->ram , 0, sizeof this->ram ); + memset( this->ram2, 0, sizeof this->ram2 ); + memset( this->vectors, 0xFF, sizeof this->vectors ); + Z80_reset( &this->cpu, this->unmapped_write, this->rom.unmapped ); + + if ( sega_mapping( this ) ) + { + this->vectors_addr = 0x10000 - page_size; + this->idle_addr = this->vectors_addr; + int i; + for ( i = 1; i < 8; ++i ) + { + this->vectors [i*8 + 0] = 0xC3; // JP addr + this->vectors [i*8 + 1] = this->header.rst_addrs [i - 1] & 0xff; + this->vectors [i*8 + 2] = this->header.rst_addrs [i - 1] >> 8; + } + + Z80_map_mem_rw( &this->cpu, 0xC000, 0x2000, this->ram ); + Z80_map_mem( &this->cpu, this->vectors_addr, page_size, this->unmapped_write, this->vectors ); + + this->bank2 = NULL; + for ( i = 0; i < 4; ++i ) + cpu_write( this, 0xFFFC + i, this->header.mapping [i] ); + } + else + { + if ( !this->coleco_bios ) + return "Coleco BIOS not set"; /* BLARGG_ERR( BLARGG_ERR_CALLER, "Coleco BIOS not set" ); */ + + this->vectors_addr = 0; + Z80_map_mem( &this->cpu, 0, 0x2000, this->unmapped_write, this->coleco_bios ); + int i; + for ( i = 0; i < 8; ++i ) + Z80_map_mem_rw( &this->cpu, 0x6000 + i*0x400, 0x400, this->ram ); + + this->idle_addr = 0x2000; + Z80_map_mem( &this->cpu, 0x2000, page_size, this->unmapped_write, this->vectors ); + + for ( i = 0; i < 0x8000 / this->rom.bank_size; ++i ) + { + int addr = 0x8000 + i*this->rom.bank_size; + Z80_map_mem( &this->cpu, addr, this->rom.bank_size, this->unmapped_write, Rom_at_addr( &this->rom, addr ) ); + } + } + + this->cpu.r.sp = get_le16( this->header.stack_ptr ); + this->cpu.r.b.a = track; + this->next_play = this->play_period; + + jsr( this, this->header.init_addr ); + + Buffer_clear( &this->stereo_buf ); + + // convert filter times to samples + struct setup_t s = this->tfilter; + s.max_initial *= this->sample_rate * stereo; + #ifdef GME_DISABLE_SILENCE_LOOKAHEAD + s.lookahead = 1; + #endif + track_setup( &this->track_filter, &s ); + + return track_start( &this->track_filter ); +} + +// Tell/Seek + +static int msec_to_samples( int msec, int sample_rate ) +{ + int sec = msec / 1000; + msec -= sec * 1000; + return (sec * sample_rate + msec * sample_rate / 1000) * stereo; +} + +int Track_tell( struct Sgc_Emu* this ) +{ + int rate = this->sample_rate * stereo; + int sec = track_sample_count( &this->track_filter ) / rate; + return sec * 1000 + (track_sample_count( &this->track_filter ) - sec * rate) * 1000 / rate; +} + +blargg_err_t Track_seek( struct Sgc_Emu* this, int msec ) +{ + int time = msec_to_samples( msec, this->sample_rate ); + if ( time < track_sample_count( &this->track_filter ) ) + RETURN_ERR( Sgc_start_track( this, this->current_track ) ); + return Track_skip( this, time - track_sample_count( &this->track_filter ) ); +} + +blargg_err_t Track_skip( struct Sgc_Emu* this, int count ) +{ + require( this->current_track >= 0 ); // start_track() must have been called already + return track_skip( &this->track_filter, count ); +} + +blargg_err_t skip_( void* emu, int count ) +{ + struct Sgc_Emu* this = (struct Sgc_Emu*) emu; + + // for long skip, mute sound + const int threshold = 32768; + if ( count > threshold ) + { + int saved_mute = this->mute_mask_; + Sound_mute_voices( this, ~0 ); + + int n = count - threshold/2; + n &= ~(2048-1); // round to multiple of 2048 + count -= n; + RETURN_ERR( skippy_( &this->track_filter, n ) ); + + Sound_mute_voices( this, saved_mute ); + } + + return skippy_( &this->track_filter, count ); +} + +void Track_set_fade( struct Sgc_Emu* this, int start_msec, int length_msec ) +{ + track_set_fade( &this->track_filter, msec_to_samples( start_msec, this->sample_rate ), + length_msec * this->sample_rate / (1000 / stereo) ); +} + +blargg_err_t Sgc_play( struct Sgc_Emu* this, int out_count, sample_t* out ) +{ + require( this->current_track >= 0 ); + require( out_count % stereo == 0 ); + return track_play( &this->track_filter, out_count, out ); +} + +blargg_err_t play_( void* emu, int count, sample_t out [] ) +{ + struct Sgc_Emu* this = (struct Sgc_Emu*) emu; + + int remain = count; + while ( remain ) + { + Buffer_disable_immediate_removal( &this->stereo_buf ); + remain -= Buffer_read_samples( &this->stereo_buf, &out [count - remain], remain ); + if ( remain ) + { + if ( this->buf_changed_count != Buffer_channels_changed_count( &this->stereo_buf ) ) + { + this->buf_changed_count = Buffer_channels_changed_count( &this->stereo_buf ); + + // Remute voices + Sound_mute_voices( this, this->mute_mask_ ); + } + int msec = Buffer_length( &this->stereo_buf ); + blip_time_t clocks_emulated = msec * this->clock_rate_ / 1000 - 100; + RETURN_ERR( run_clocks( this, &clocks_emulated, msec ) ); + assert( clocks_emulated ); + Buffer_end_frame( &this->stereo_buf, clocks_emulated ); + } + } + return 0; +} diff --git a/apps/codecs/libgme/sgc_emu.h b/apps/codecs/libgme/sgc_emu.h index 6595c02daf..83cde1e6ae 100644 --- a/apps/codecs/libgme/sgc_emu.h +++ b/apps/codecs/libgme/sgc_emu.h @@ -1,195 +1,195 @@ -// Sega/Game Gear/Coleco SGC music file emulator - -// Game_Music_Emu 0.6-pre -#ifndef SGC_EMU_H -#define SGC_EMU_H - -#include "blargg_common.h" -#include "multi_buffer.h" - -#include "rom_data.h" -#include "z80_cpu.h" -#include "sms_fm_apu.h" -#include "sms_apu.h" -#include "m3u_playlist.h" -#include "track_filter.h" - -typedef struct Z80_Cpu Sgc_Cpu; - -// SGC file header -enum { header_size = 0xA0 }; -struct header_t -{ - char tag [4]; // "SGC\x1A" - byte vers; // 0x01 - byte rate; // 0=NTSC 1=PAL - byte reserved1 [2]; - byte load_addr [2]; - byte init_addr [2]; - byte play_addr [2]; - byte stack_ptr [2]; - byte reserved2 [2]; - byte rst_addrs [7*2]; - byte mapping [4]; // Used by Sega only - byte first_song; // Song to start playing first - byte song_count; - byte first_effect; - byte last_effect; - byte system; // 0=Master System 1=Game Gear 2=Colecovision - byte reserved3 [23]; - char game [32]; // strings can be 32 chars, NOT terminated - char author [32]; - char copyright [32]; -}; - -// True if header has valid file signature -static inline bool valid_tag( struct header_t* h ) -{ - return 0 == memcmp( h->tag, "SGC\x1A", 4 ); -} - -static inline int effect_count( struct header_t* h ) { return h->last_effect ? h->last_effect - h->first_effect + 1 : 0; } - -struct Sgc_Emu { - bool fm_accessed; - - cpu_time_t play_period; - cpu_time_t next_play; - void const* bank2; // ROM selected for bank 2, in case RAM is currently hiding it - addr_t vectors_addr; // RST vectors start here - addr_t idle_addr; // return address for init/play routines - void* coleco_bios; - - // general - int voice_count; - int const* voice_types; - int mute_mask_; - int tempo; - int gain; - - int sample_rate; - - // track-specific - int current_track; - int track_count; - - int clock_rate_; - unsigned buf_changed_count; - - // M3u Playlist - struct M3u_Playlist m3u; - struct header_t header; - - struct setup_t tfilter; - struct Track_Filter track_filter; - - struct Multi_Buffer stereo_buf; - - struct Sms_Apu apu; - struct Sms_Fm_Apu fm_apu; - - Sgc_Cpu cpu; - - // large items - struct Rom_Data rom; - byte vectors [page_size + page_padding]; - byte unmapped_write [0x4000]; - byte ram [0x2000 + page_padding]; - byte ram2 [0x4000 + page_padding]; -}; - -// Basic functionality (see Gme_File.h for file loading/track info functions) - -void Sgc_init( struct Sgc_Emu* this ); - -blargg_err_t Sgc_load_mem( struct Sgc_Emu* this, const void* data, long size ); - -static inline int clock_rate( struct Sgc_Emu* this ) { return this->header.rate ? 3546893 : 3579545; } - -// 0x2000 bytes -static inline void set_coleco_bios( struct Sgc_Emu* this, void* p ) { this->coleco_bios = p; } - -// Set output sample rate. Must be called only once before loading file. -blargg_err_t Sgc_set_sample_rate( struct Sgc_Emu* this, int sample_rate ); - -// Start a track, where 0 is the first track. Also clears warning string. -blargg_err_t Sgc_start_track( struct Sgc_Emu* this, int track ); - -// Generate 'count' samples info 'buf'. Output is in stereo. Any emulation -// errors set warning string, and major errors also end track. -blargg_err_t Sgc_play( struct Sgc_Emu* this, int count, sample_t* buf ); - -// Track status/control - -// Number of milliseconds (1000 msec = 1 second) played since beginning of track -int Track_tell( struct Sgc_Emu* this ); - -// Seek to new time in track. Seeking backwards or far forward can take a while. -blargg_err_t Track_seek( struct Sgc_Emu* this, int msec ); - -// Skip n samples -blargg_err_t Track_skip( struct Sgc_Emu* this, int n ); - -// Set start time and length of track fade out. Once fade ends track_ended() returns -// true. Fade time can be changed while track is playing. -void Track_set_fade( struct Sgc_Emu* this, int start_msec, int length_msec ); - -// True if a track has reached its end -static inline bool Track_ended( struct Sgc_Emu* this ) -{ - return track_ended( &this->track_filter ); -} - -// Disables automatic end-of-track detection and skipping of silence at beginning -static inline void Track_ignore_silence( struct Sgc_Emu* this, bool disable ) -{ - this->track_filter.silence_ignored_ = disable; -} - -// Get track length in milliseconds -static inline int Track_get_length( struct Sgc_Emu* this, int n ) -{ - int length = 120 * 1000; /* 2 minutes */ - if ( (this->m3u.size > 0) && (n < this->m3u.size) ) { - struct entry_t* entry = &this->m3u.entries [n]; - length = entry->length; - } - - return length; -} - -// Sound customization - -// Adjust song tempo, where 1.0 = normal, 0.5 = half speed, 2.0 = double speed. -// Track length as returned by track_info() assumes a tempo of 1.0. -void Sound_set_tempo( struct Sgc_Emu* this, int t ); - -// Mute/unmute voice i, where voice 0 is first voice -void Sound_mute_voice( struct Sgc_Emu* this, int index, bool mute ); - -// Set muting state of all voices at once using a bit mask, where -1 mutes them all, -// 0 unmutes them all, 0x01 mutes just the first voice, etc. -void Sound_mute_voices( struct Sgc_Emu* this, int mask ); - -// Change overall output amplitude, where 1.0 results in minimal clamping. -// Must be called before set_sample_rate(). -static inline void Sound_set_gain( struct Sgc_Emu* this, int g ) -{ - assert( !this->sample_rate ); // you must set gain before setting sample rate - this->gain = g; -} - -// True if Master System or Game Gear -static inline bool sega_mapping( struct Sgc_Emu* this ) -{ - return this->header.system <= 1; -} - -// Emulation (You shouldn't touch these) - -bool run_cpu( struct Sgc_Emu* this, cpu_time_t end_time ); -void cpu_out( struct Sgc_Emu* this, cpu_time_t time, addr_t addr, int data ); -void cpu_write( struct Sgc_Emu* this, addr_t addr, int data ); -void jsr( struct Sgc_Emu* this, byte addr [2] ); - -#endif +// Sega/Game Gear/Coleco SGC music file emulator + +// Game_Music_Emu 0.6-pre +#ifndef SGC_EMU_H +#define SGC_EMU_H + +#include "blargg_common.h" +#include "multi_buffer.h" + +#include "rom_data.h" +#include "z80_cpu.h" +#include "sms_fm_apu.h" +#include "sms_apu.h" +#include "m3u_playlist.h" +#include "track_filter.h" + +typedef struct Z80_Cpu Sgc_Cpu; + +// SGC file header +enum { header_size = 0xA0 }; +struct header_t +{ + char tag [4]; // "SGC\x1A" + byte vers; // 0x01 + byte rate; // 0=NTSC 1=PAL + byte reserved1 [2]; + byte load_addr [2]; + byte init_addr [2]; + byte play_addr [2]; + byte stack_ptr [2]; + byte reserved2 [2]; + byte rst_addrs [7*2]; + byte mapping [4]; // Used by Sega only + byte first_song; // Song to start playing first + byte song_count; + byte first_effect; + byte last_effect; + byte system; // 0=Master System 1=Game Gear 2=Colecovision + byte reserved3 [23]; + char game [32]; // strings can be 32 chars, NOT terminated + char author [32]; + char copyright [32]; +}; + +// True if header has valid file signature +static inline bool valid_tag( struct header_t* h ) +{ + return 0 == memcmp( h->tag, "SGC\x1A", 4 ); +} + +static inline int effect_count( struct header_t* h ) { return h->last_effect ? h->last_effect - h->first_effect + 1 : 0; } + +struct Sgc_Emu { + bool fm_accessed; + + cpu_time_t play_period; + cpu_time_t next_play; + void const* bank2; // ROM selected for bank 2, in case RAM is currently hiding it + addr_t vectors_addr; // RST vectors start here + addr_t idle_addr; // return address for init/play routines + void* coleco_bios; + + // general + int voice_count; + int const* voice_types; + int mute_mask_; + int tempo; + int gain; + + int sample_rate; + + // track-specific + int current_track; + int track_count; + + int clock_rate_; + unsigned buf_changed_count; + + // M3u Playlist + struct M3u_Playlist m3u; + struct header_t header; + + struct setup_t tfilter; + struct Track_Filter track_filter; + + struct Multi_Buffer stereo_buf; + + struct Sms_Apu apu; + struct Sms_Fm_Apu fm_apu; + + Sgc_Cpu cpu; + + // large items + struct Rom_Data rom; + byte vectors [page_size + page_padding]; + byte unmapped_write [0x4000]; + byte ram [0x2000 + page_padding]; + byte ram2 [0x4000 + page_padding]; +}; + +// Basic functionality (see Gme_File.h for file loading/track info functions) + +void Sgc_init( struct Sgc_Emu* this ); + +blargg_err_t Sgc_load_mem( struct Sgc_Emu* this, const void* data, long size ); + +static inline int clock_rate( struct Sgc_Emu* this ) { return this->header.rate ? 3546893 : 3579545; } + +// 0x2000 bytes +static inline void set_coleco_bios( struct Sgc_Emu* this, void* p ) { this->coleco_bios = p; } + +// Set output sample rate. Must be called only once before loading file. +blargg_err_t Sgc_set_sample_rate( struct Sgc_Emu* this, int sample_rate ); + +// Start a track, where 0 is the first track. Also clears warning string. +blargg_err_t Sgc_start_track( struct Sgc_Emu* this, int track ); + +// Generate 'count' samples info 'buf'. Output is in stereo. Any emulation +// errors set warning string, and major errors also end track. +blargg_err_t Sgc_play( struct Sgc_Emu* this, int count, sample_t* buf ); + +// Track status/control + +// Number of milliseconds (1000 msec = 1 second) played since beginning of track +int Track_tell( struct Sgc_Emu* this ); + +// Seek to new time in track. Seeking backwards or far forward can take a while. +blargg_err_t Track_seek( struct Sgc_Emu* this, int msec ); + +// Skip n samples +blargg_err_t Track_skip( struct Sgc_Emu* this, int n ); + +// Set start time and length of track fade out. Once fade ends track_ended() returns +// true. Fade time can be changed while track is playing. +void Track_set_fade( struct Sgc_Emu* this, int start_msec, int length_msec ); + +// True if a track has reached its end +static inline bool Track_ended( struct Sgc_Emu* this ) +{ + return track_ended( &this->track_filter ); +} + +// Disables automatic end-of-track detection and skipping of silence at beginning +static inline void Track_ignore_silence( struct Sgc_Emu* this, bool disable ) +{ + this->track_filter.silence_ignored_ = disable; +} + +// Get track length in milliseconds +static inline int Track_get_length( struct Sgc_Emu* this, int n ) +{ + int length = 120 * 1000; /* 2 minutes */ + if ( (this->m3u.size > 0) && (n < this->m3u.size) ) { + struct entry_t* entry = &this->m3u.entries [n]; + length = entry->length; + } + + return length; +} + +// Sound customization + +// Adjust song tempo, where 1.0 = normal, 0.5 = half speed, 2.0 = double speed. +// Track length as returned by track_info() assumes a tempo of 1.0. +void Sound_set_tempo( struct Sgc_Emu* this, int t ); + +// Mute/unmute voice i, where voice 0 is first voice +void Sound_mute_voice( struct Sgc_Emu* this, int index, bool mute ); + +// Set muting state of all voices at once using a bit mask, where -1 mutes them all, +// 0 unmutes them all, 0x01 mutes just the first voice, etc. +void Sound_mute_voices( struct Sgc_Emu* this, int mask ); + +// Change overall output amplitude, where 1.0 results in minimal clamping. +// Must be called before set_sample_rate(). +static inline void Sound_set_gain( struct Sgc_Emu* this, int g ) +{ + assert( !this->sample_rate ); // you must set gain before setting sample rate + this->gain = g; +} + +// True if Master System or Game Gear +static inline bool sega_mapping( struct Sgc_Emu* this ) +{ + return this->header.system <= 1; +} + +// Emulation (You shouldn't touch these) + +bool run_cpu( struct Sgc_Emu* this, cpu_time_t end_time ); +void cpu_out( struct Sgc_Emu* this, cpu_time_t time, addr_t addr, int data ); +void cpu_write( struct Sgc_Emu* this, addr_t addr, int data ); +void jsr( struct Sgc_Emu* this, byte addr [2] ); + +#endif diff --git a/apps/codecs/libgme/sms_fm_apu.c b/apps/codecs/libgme/sms_fm_apu.c index 6fd00545d6..ee5ce48932 100644 --- a/apps/codecs/libgme/sms_fm_apu.c +++ b/apps/codecs/libgme/sms_fm_apu.c @@ -1,82 +1,82 @@ -#include "sms_fm_apu.h" - -#include "blargg_source.h" - -void Fm_apu_create( struct Sms_Fm_Apu* this ) -{ - Synth_init( &this->synth ); - Ym2413_init( &this->apu ); -} - -blargg_err_t Fm_apu_init( struct Sms_Fm_Apu* this, int clock_rate, int sample_rate ) -{ - this->period_ = (blip_time_t) (clock_rate / sample_rate); - CHECK_ALLOC( !Ym2413_set_rate( &this->apu, sample_rate, clock_rate ) ); - - Fm_apu_set_output( this, 0 ); - Fm_apu_volume( this, (int)FP_ONE_VOLUME ); - Fm_apu_reset( this ); - return 0; -} - -void Fm_apu_reset( struct Sms_Fm_Apu* this ) -{ - this->addr = 0; - this->next_time = 0; - this->last_amp = 0; - - Ym2413_reset( &this->apu ); -} - -void fm_run_until( struct Sms_Fm_Apu* this, blip_time_t end_time ); -void Fm_apu_write_data( struct Sms_Fm_Apu* this, blip_time_t time, int data ) -{ - if ( time > this->next_time ) - fm_run_until( this, time ); - - Ym2413_write( &this->apu, this->addr, data ); -} - -void fm_run_until( struct Sms_Fm_Apu* this, blip_time_t end_time ) -{ - assert( end_time > this->next_time ); - - struct Blip_Buffer* const output = this->output_; - if ( !output ) - { - this->next_time = end_time; - return; - } - - blip_time_t time = this->next_time; - struct Ym2413_Emu* emu = &this->apu; - do - { - short samples [2]; - Ym2413_run( emu, 1, samples ); - int amp = (samples [0] + samples [1]) >> 1; - - int delta = amp - this->last_amp; - if ( delta ) - { - this->last_amp = amp; - Synth_offset_inline( &this->synth, time, delta, output ); - } - time += this->period_; - } - while ( time < end_time ); - - this->next_time = time; -} - -void Fm_apu_end_frame( struct Sms_Fm_Apu* this, blip_time_t time ) -{ - if ( time > this->next_time ) - fm_run_until( this, time ); - - this->next_time -= time; - assert( this->next_time >= 0 ); - - if ( this->output_ ) - Blip_set_modified( this->output_ ); -} +#include "sms_fm_apu.h" + +#include "blargg_source.h" + +void Fm_apu_create( struct Sms_Fm_Apu* this ) +{ + Synth_init( &this->synth ); + Ym2413_init( &this->apu ); +} + +blargg_err_t Fm_apu_init( struct Sms_Fm_Apu* this, int clock_rate, int sample_rate ) +{ + this->period_ = (blip_time_t) (clock_rate / sample_rate); + CHECK_ALLOC( !Ym2413_set_rate( &this->apu, sample_rate, clock_rate ) ); + + Fm_apu_set_output( this, 0 ); + Fm_apu_volume( this, (int)FP_ONE_VOLUME ); + Fm_apu_reset( this ); + return 0; +} + +void Fm_apu_reset( struct Sms_Fm_Apu* this ) +{ + this->addr = 0; + this->next_time = 0; + this->last_amp = 0; + + Ym2413_reset( &this->apu ); +} + +void fm_run_until( struct Sms_Fm_Apu* this, blip_time_t end_time ); +void Fm_apu_write_data( struct Sms_Fm_Apu* this, blip_time_t time, int data ) +{ + if ( time > this->next_time ) + fm_run_until( this, time ); + + Ym2413_write( &this->apu, this->addr, data ); +} + +void fm_run_until( struct Sms_Fm_Apu* this, blip_time_t end_time ) +{ + assert( end_time > this->next_time ); + + struct Blip_Buffer* const output = this->output_; + if ( !output ) + { + this->next_time = end_time; + return; + } + + blip_time_t time = this->next_time; + struct Ym2413_Emu* emu = &this->apu; + do + { + short samples [2]; + Ym2413_run( emu, 1, samples ); + int amp = (samples [0] + samples [1]) >> 1; + + int delta = amp - this->last_amp; + if ( delta ) + { + this->last_amp = amp; + Synth_offset_inline( &this->synth, time, delta, output ); + } + time += this->period_; + } + while ( time < end_time ); + + this->next_time = time; +} + +void Fm_apu_end_frame( struct Sms_Fm_Apu* this, blip_time_t time ) +{ + if ( time > this->next_time ) + fm_run_until( this, time ); + + this->next_time -= time; + assert( this->next_time >= 0 ); + + if ( this->output_ ) + Blip_set_modified( this->output_ ); +} diff --git a/apps/codecs/libgme/sms_fm_apu.h b/apps/codecs/libgme/sms_fm_apu.h index 00bc2b409c..921db6cef1 100644 --- a/apps/codecs/libgme/sms_fm_apu.h +++ b/apps/codecs/libgme/sms_fm_apu.h @@ -1,43 +1,43 @@ -#ifndef SMS_FM_APU_H -#define SMS_FM_APU_H - -#include "blargg_common.h" -#include "blip_buffer.h" -#include "ym2413_emu.h" - -enum { fm_apu_osc_count = 1 }; - -struct Sms_Fm_Apu { - struct Blip_Buffer* output_; - blip_time_t next_time; - int last_amp; - int addr; - - int clock_; - int rate_; - blip_time_t period_; - - struct Blip_Synth synth; - struct Ym2413_Emu apu; -}; - -void Fm_apu_create( struct Sms_Fm_Apu* this ); - -static inline bool Fm_apu_supported( void ) { return Ym2413_supported(); } -blargg_err_t Fm_apu_init( struct Sms_Fm_Apu* this, int clock_rate, int sample_rate ); - -static inline void Fm_apu_set_output( struct Sms_Fm_Apu* this, struct Blip_Buffer* b ) -{ - this->output_ = b; -} - -static inline void Fm_apu_volume( struct Sms_Fm_Apu* this, int v ) { Synth_volume( &this->synth, (v*2) / 5 / 4096 ); } - -void Fm_apu_reset( struct Sms_Fm_Apu* this ); - -static inline void Fm_apu_write_addr( struct Sms_Fm_Apu* this, int data ) { this->addr = data; } -void Fm_apu_write_data( struct Sms_Fm_Apu* this, blip_time_t, int data ); - -void Fm_apu_end_frame( struct Sms_Fm_Apu* this, blip_time_t t ); - -#endif +#ifndef SMS_FM_APU_H +#define SMS_FM_APU_H + +#include "blargg_common.h" +#include "blip_buffer.h" +#include "ym2413_emu.h" + +enum { fm_apu_osc_count = 1 }; + +struct Sms_Fm_Apu { + struct Blip_Buffer* output_; + blip_time_t next_time; + int last_amp; + int addr; + + int clock_; + int rate_; + blip_time_t period_; + + struct Blip_Synth synth; + struct Ym2413_Emu apu; +}; + +void Fm_apu_create( struct Sms_Fm_Apu* this ); + +static inline bool Fm_apu_supported( void ) { return Ym2413_supported(); } +blargg_err_t Fm_apu_init( struct Sms_Fm_Apu* this, int clock_rate, int sample_rate ); + +static inline void Fm_apu_set_output( struct Sms_Fm_Apu* this, struct Blip_Buffer* b ) +{ + this->output_ = b; +} + +static inline void Fm_apu_volume( struct Sms_Fm_Apu* this, int v ) { Synth_volume( &this->synth, (v*2) / 5 / 4096 ); } + +void Fm_apu_reset( struct Sms_Fm_Apu* this ); + +static inline void Fm_apu_write_addr( struct Sms_Fm_Apu* this, int data ) { this->addr = data; } +void Fm_apu_write_data( struct Sms_Fm_Apu* this, blip_time_t, int data ); + +void Fm_apu_end_frame( struct Sms_Fm_Apu* this, blip_time_t t ); + +#endif diff --git a/apps/codecs/libgme/track_filter.c b/apps/codecs/libgme/track_filter.c index 4776dcc7df..d0d75f2ded 100644 --- a/apps/codecs/libgme/track_filter.c +++ b/apps/codecs/libgme/track_filter.c @@ -1,294 +1,294 @@ -// Game_Music_Emu 0.6-pre. http://www.slack.net/~ant/ - -#include "track_filter.h" - -/* Copyright (C) 2003-2008 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. This -module 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 Lesser General Public License for more -details. You should have received a copy of the GNU Lesser General Public -License along with this module; if not, write to the Free Software Foundation, -Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ - -#include "blargg_source.h" - -int const fade_block_size = 512; -int const fade_shift = 8; // fade ends with gain at 1.0 / (1 << fade_shift) -int const silence_threshold = 8; - -void track_create( struct Track_Filter* this ) -{ - this->emu_ = NULL; - this->setup_.max_initial = 0; - this->setup_.lookahead = 0; - this->setup_.max_silence = indefinite_count; - this->silence_ignored_ = false; - track_stop( this ); -} - -blargg_err_t track_init( struct Track_Filter* this, void* emu ) -{ - this->emu_ = emu; - return 0; -} - -static void clear_time_vars( struct Track_Filter* this ) -{ - this->emu_time = this->buf_remain; - this->out_time = 0; - this->silence_time = 0; - this->silence_count = 0; -} - -void track_stop( struct Track_Filter* this ) -{ - this->emu_track_ended_ = true; - this->track_ended_ = true; - this->fade_start = indefinite_count; - this->fade_step = 1; - this->buf_remain = 0; - this->emu_error = NULL; - clear_time_vars( this ); -} - -blargg_err_t track_start( struct Track_Filter* this ) -{ - this->emu_error = NULL; - track_stop( this ); - - this->emu_track_ended_ = false; - this->track_ended_ = false; - - if ( !this->silence_ignored_ ) - { - // play until non-silence or end of track - while ( this->emu_time < this->setup_.max_initial ) - { - fill_buf( this ); - if ( this->buf_remain | this->emu_track_ended_ ) - break; - } - } - - clear_time_vars( this ); - return this->emu_error; -} - -static void end_track_if_error( struct Track_Filter* this, blargg_err_t err ) -{ - if ( err ) - { - this->emu_error = err; - this->emu_track_ended_ = true; - } -} - -blargg_err_t track_skip( struct Track_Filter* this, int count ) -{ - this->emu_error = NULL; - this->out_time += count; - - // remove from silence and buf first - { - int n = min( count, this->silence_count ); - this->silence_count -= n; - count -= n; - - n = min( count, this->buf_remain ); - this->buf_remain -= n; - count -= n; - } - - if ( count && !this->emu_track_ended_ ) - { - this->emu_time += count; - this->silence_time = this->emu_time; // would otherwise be invalid - end_track_if_error( this, skip_( this->emu_, count ) ); - } - - if ( !(this->silence_count | this->buf_remain) ) // caught up to emulator, so update track ended - this->track_ended_ |= this->emu_track_ended_; - - return this->emu_error; -} - -blargg_err_t skippy_( struct Track_Filter* this, int count ) -{ - while ( count && !this->emu_track_ended_ ) - { - int n = buf_size; - if ( n > count ) - n = count; - count -= n; - RETURN_ERR( play_( this->emu_, n, this->buf ) ); - } - return 0; -} - -// Fading - -void track_set_fade( struct Track_Filter* this, int start, int length ) -{ - this->fade_start = start; - this->fade_step = length / (fade_block_size * fade_shift); - if ( this->fade_step < 1 ) - this->fade_step = 1; -} - -static bool is_fading( struct Track_Filter* this ) -{ - return this->out_time >= this->fade_start && this->fade_start != indefinite_count; -} - -// unit / pow( 2.0, (double) x / step ) -static int int_log( int x, int step, int unit ) -{ - int shift = x / step; - int fraction = (x - shift * step) * unit / step; - return ((unit - fraction) + (fraction >> 1)) >> shift; -} - -static void handle_fade( struct Track_Filter* this, sample_t out [], int out_count ) -{ - int i; - for ( i = 0; i < out_count; i += fade_block_size ) - { - int const shift = 14; - int const unit = 1 << shift; - int gain = int_log( (this->out_time + i - this->fade_start) / fade_block_size, - this->fade_step, unit ); - if ( gain < (unit >> fade_shift) ) - this->track_ended_ = this->emu_track_ended_ = true; - - sample_t* io = &out [i]; - for ( int count = min( fade_block_size, out_count - i ); count; --count ) - { - *io = (sample_t) ((*io * gain) >> shift); - ++io; - } - } -} - -// Silence detection - -static void emu_play( struct Track_Filter* this, sample_t out [], int count ) -{ - this->emu_time += count; - if ( !this->emu_track_ended_ ) - end_track_if_error( this, play_( this->emu_, count, out ) ); - else - memset( out, 0, count * sizeof *out ); -} - -// number of consecutive silent samples at end -static int count_silence( sample_t begin [], int size ) -{ - sample_t first = *begin; - *begin = silence_threshold * 2; // sentinel - sample_t* p = begin + size; - while ( (unsigned) (*--p + silence_threshold) <= (unsigned) silence_threshold * 2 ) { } - *begin = first; - return size - (p - begin); -} - -// fill internal buffer and check it for silence -void fill_buf( struct Track_Filter* this ) -{ - assert( !this->buf_remain ); - if ( !this->emu_track_ended_ ) - { - emu_play( this, this->buf, buf_size ); - int silence = count_silence( this->buf, buf_size ); - if ( silence < buf_size ) - { - this->silence_time = this->emu_time - silence; - this->buf_remain = buf_size; - return; - } - } - this->silence_count += buf_size; -} - -blargg_err_t track_play( struct Track_Filter* this, int out_count, sample_t out [] ) -{ - this->emu_error = NULL; - if ( this->track_ended_ ) - { - memset( out, 0, out_count * sizeof *out ); - } - else - { - assert( this->emu_time >= this->out_time ); - - // prints nifty graph of how far ahead we are when searching for silence - //dprintf( "%*s \n", int ((emu_time - out_time) * 7 / 44100), "*" ); - - // use any remaining silence samples - int pos = 0; - if ( this->silence_count ) - { - if ( !this->silence_ignored_ ) - { - // during a run of silence, run emulator at >=2x speed so it gets ahead - int ahead_time = this->setup_.lookahead * (this->out_time + out_count - this->silence_time) + - this->silence_time; - while ( this->emu_time < ahead_time && !(this->buf_remain | this->emu_track_ended_) ) - fill_buf( this ); - - // end track if sufficient silence has been found - if ( this->emu_time - this->silence_time > this->setup_.max_silence ) - { - this->track_ended_ = this->emu_track_ended_ = true; - this->silence_count = out_count; - this->buf_remain = 0; - } - } - - // fill from remaining silence - pos = min( this->silence_count, out_count ); - memset( out, 0, pos * sizeof *out ); - this->silence_count -= pos; - } - - // use any remaining samples from buffer - if ( this->buf_remain ) - { - int n = min( this->buf_remain, (int) (out_count - pos) ); - memcpy( out + pos, this->buf + (buf_size - this->buf_remain), n * sizeof *out ); - this->buf_remain -= n; - pos += n; - } - - // generate remaining samples normally - int remain = out_count - pos; - if ( remain ) - { - emu_play( this, out + pos, remain ); - this->track_ended_ |= this->emu_track_ended_; - - if ( this->silence_ignored_ && !is_fading( this ) ) - { - // if left unupdated, ahead_time could become too large - this->silence_time = this->emu_time; - } - else - { - // check end for a new run of silence - int silence = count_silence( out + pos, remain ); - if ( silence < remain ) - this->silence_time = this->emu_time - silence; - - if ( this->emu_time - this->silence_time >= buf_size ) - fill_buf( this ); // cause silence detection on next play() - } - } - - if ( is_fading( this ) ) - handle_fade( this, out, out_count ); - } - this->out_time += out_count; - return this->emu_error; -} +// Game_Music_Emu 0.6-pre. http://www.slack.net/~ant/ + +#include "track_filter.h" + +/* Copyright (C) 2003-2008 Shay Green. This module is free software; you +can redistribute it and/or modify it under the terms of the GNU Lesser +General Public License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. This +module 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 Lesser General Public License for more +details. You should have received a copy of the GNU Lesser General Public +License along with this module; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ + +#include "blargg_source.h" + +int const fade_block_size = 512; +int const fade_shift = 8; // fade ends with gain at 1.0 / (1 << fade_shift) +int const silence_threshold = 8; + +void track_create( struct Track_Filter* this ) +{ + this->emu_ = NULL; + this->setup_.max_initial = 0; + this->setup_.lookahead = 0; + this->setup_.max_silence = indefinite_count; + this->silence_ignored_ = false; + track_stop( this ); +} + +blargg_err_t track_init( struct Track_Filter* this, void* emu ) +{ + this->emu_ = emu; + return 0; +} + +static void clear_time_vars( struct Track_Filter* this ) +{ + this->emu_time = this->buf_remain; + this->out_time = 0; + this->silence_time = 0; + this->silence_count = 0; +} + +void track_stop( struct Track_Filter* this ) +{ + this->emu_track_ended_ = true; + this->track_ended_ = true; + this->fade_start = indefinite_count; + this->fade_step = 1; + this->buf_remain = 0; + this->emu_error = NULL; + clear_time_vars( this ); +} + +blargg_err_t track_start( struct Track_Filter* this ) +{ + this->emu_error = NULL; + track_stop( this ); + + this->emu_track_ended_ = false; + this->track_ended_ = false; + + if ( !this->silence_ignored_ ) + { + // play until non-silence or end of track + while ( this->emu_time < this->setup_.max_initial ) + { + fill_buf( this ); + if ( this->buf_remain | this->emu_track_ended_ ) + break; + } + } + + clear_time_vars( this ); + return this->emu_error; +} + +static void end_track_if_error( struct Track_Filter* this, blargg_err_t err ) +{ + if ( err ) + { + this->emu_error = err; + this->emu_track_ended_ = true; + } +} + +blargg_err_t track_skip( struct Track_Filter* this, int count ) +{ + this->emu_error = NULL; + this->out_time += count; + + // remove from silence and buf first + { + int n = min( count, this->silence_count ); + this->silence_count -= n; + count -= n; + + n = min( count, this->buf_remain ); + this->buf_remain -= n; + count -= n; + } + + if ( count && !this->emu_track_ended_ ) + { + this->emu_time += count; + this->silence_time = this->emu_time; // would otherwise be invalid + end_track_if_error( this, skip_( this->emu_, count ) ); + } + + if ( !(this->silence_count | this->buf_remain) ) // caught up to emulator, so update track ended + this->track_ended_ |= this->emu_track_ended_; + + return this->emu_error; +} + +blargg_err_t skippy_( struct Track_Filter* this, int count ) +{ + while ( count && !this->emu_track_ended_ ) + { + int n = buf_size; + if ( n > count ) + n = count; + count -= n; + RETURN_ERR( play_( this->emu_, n, this->buf ) ); + } + return 0; +} + +// Fading + +void track_set_fade( struct Track_Filter* this, int start, int length ) +{ + this->fade_start = start; + this->fade_step = length / (fade_block_size * fade_shift); + if ( this->fade_step < 1 ) + this->fade_step = 1; +} + +static bool is_fading( struct Track_Filter* this ) +{ + return this->out_time >= this->fade_start && this->fade_start != indefinite_count; +} + +// unit / pow( 2.0, (double) x / step ) +static int int_log( int x, int step, int unit ) +{ + int shift = x / step; + int fraction = (x - shift * step) * unit / step; + return ((unit - fraction) + (fraction >> 1)) >> shift; +} + +static void handle_fade( struct Track_Filter* this, sample_t out [], int out_count ) +{ + int i; + for ( i = 0; i < out_count; i += fade_block_size ) + { + int const shift = 14; + int const unit = 1 << shift; + int gain = int_log( (this->out_time + i - this->fade_start) / fade_block_size, + this->fade_step, unit ); + if ( gain < (unit >> fade_shift) ) + this->track_ended_ = this->emu_track_ended_ = true; + + sample_t* io = &out [i]; + for ( int count = min( fade_block_size, out_count - i ); count; --count ) + { + *io = (sample_t) ((*io * gain) >> shift); + ++io; + } + } +} + +// Silence detection + +static void emu_play( struct Track_Filter* this, sample_t out [], int count ) +{ + this->emu_time += count; + if ( !this->emu_track_ended_ ) + end_track_if_error( this, play_( this->emu_, count, out ) ); + else + memset( out, 0, count * sizeof *out ); +} + +// number of consecutive silent samples at end +static int count_silence( sample_t begin [], int size ) +{ + sample_t first = *begin; + *begin = silence_threshold * 2; // sentinel + sample_t* p = begin + size; + while ( (unsigned) (*--p + silence_threshold) <= (unsigned) silence_threshold * 2 ) { } + *begin = first; + return size - (p - begin); +} + +// fill internal buffer and check it for silence +void fill_buf( struct Track_Filter* this ) +{ + assert( !this->buf_remain ); + if ( !this->emu_track_ended_ ) + { + emu_play( this, this->buf, buf_size ); + int silence = count_silence( this->buf, buf_size ); + if ( silence < buf_size ) + { + this->silence_time = this->emu_time - silence; + this->buf_remain = buf_size; + return; + } + } + this->silence_count += buf_size; +} + +blargg_err_t track_play( struct Track_Filter* this, int out_count, sample_t out [] ) +{ + this->emu_error = NULL; + if ( this->track_ended_ ) + { + memset( out, 0, out_count * sizeof *out ); + } + else + { + assert( this->emu_time >= this->out_time ); + + // prints nifty graph of how far ahead we are when searching for silence + //dprintf( "%*s \n", int ((emu_time - out_time) * 7 / 44100), "*" ); + + // use any remaining silence samples + int pos = 0; + if ( this->silence_count ) + { + if ( !this->silence_ignored_ ) + { + // during a run of silence, run emulator at >=2x speed so it gets ahead + int ahead_time = this->setup_.lookahead * (this->out_time + out_count - this->silence_time) + + this->silence_time; + while ( this->emu_time < ahead_time && !(this->buf_remain | this->emu_track_ended_) ) + fill_buf( this ); + + // end track if sufficient silence has been found + if ( this->emu_time - this->silence_time > this->setup_.max_silence ) + { + this->track_ended_ = this->emu_track_ended_ = true; + this->silence_count = out_count; + this->buf_remain = 0; + } + } + + // fill from remaining silence + pos = min( this->silence_count, out_count ); + memset( out, 0, pos * sizeof *out ); + this->silence_count -= pos; + } + + // use any remaining samples from buffer + if ( this->buf_remain ) + { + int n = min( this->buf_remain, (int) (out_count - pos) ); + memcpy( out + pos, this->buf + (buf_size - this->buf_remain), n * sizeof *out ); + this->buf_remain -= n; + pos += n; + } + + // generate remaining samples normally + int remain = out_count - pos; + if ( remain ) + { + emu_play( this, out + pos, remain ); + this->track_ended_ |= this->emu_track_ended_; + + if ( this->silence_ignored_ && !is_fading( this ) ) + { + // if left unupdated, ahead_time could become too large + this->silence_time = this->emu_time; + } + else + { + // check end for a new run of silence + int silence = count_silence( out + pos, remain ); + if ( silence < remain ) + this->silence_time = this->emu_time - silence; + + if ( this->emu_time - this->silence_time >= buf_size ) + fill_buf( this ); // cause silence detection on next play() + } + } + + if ( is_fading( this ) ) + handle_fade( this, out, out_count ); + } + this->out_time += out_count; + return this->emu_error; +} diff --git a/apps/codecs/libgme/track_filter.h b/apps/codecs/libgme/track_filter.h index 35049b91bb..3689be9620 100644 --- a/apps/codecs/libgme/track_filter.h +++ b/apps/codecs/libgme/track_filter.h @@ -1,90 +1,90 @@ -// Removes silence from beginning of track, fades end of track. Also looks ahead -// for excessive silence, and if found, ends track. - -// Game_Music_Emu 0.6-pre -#ifndef TRACK_FILTER_H -#define TRACK_FILTER_H - -#include "blargg_common.h" - -typedef short sample_t; -typedef int sample_count_t; - -enum { indefinite_count = INT_MAX/2 + 1 }; -enum { buf_size = 2048 }; - -struct setup_t { - sample_count_t max_initial; // maximum silence to strip from beginning of track - sample_count_t max_silence; // maximum silence in middle of track without it ending - int lookahead; // internal speed when looking ahead for silence (2=200% etc.) -}; - -struct Track_Filter { - void* emu_; - struct setup_t setup_; - const char* emu_error; - bool silence_ignored_; - - // Timing - int out_time; // number of samples played since start of track - int emu_time; // number of samples emulator has generated since start of track - int emu_track_ended_; // emulator has reached end of track - volatile int track_ended_; - - // Fading - int fade_start; - int fade_step; - - // Silence detection - int silence_time; // absolute number of samples where most recent silence began - int silence_count; // number of samples of silence to play before using buf - int buf_remain; // number of samples left in silence buffer - sample_t buf [buf_size]; -}; - -// Initializes filter. Must be done once before using object. -blargg_err_t track_init( struct Track_Filter* this, void* ); -void track_create( struct Track_Filter* this ); - -// Gets/sets setup -static inline struct setup_t const* track_get_setup( struct Track_Filter* this ) { return &this->setup_; } -static inline void track_setup( struct Track_Filter* this, struct setup_t const* s ) { this->setup_ = *s; } - -// Disables automatic end-of-track detection and skipping of silence at beginning -static inline void track_ignore_silence( struct Track_Filter* this, bool disable ) { this->silence_ignored_ = disable; } - -// Clears state and skips initial silence in track -blargg_err_t track_start( struct Track_Filter* this ); - -// Sets time that fade starts, and how long until track ends. -void track_set_fade( struct Track_Filter* this, sample_count_t start, sample_count_t length ); - -// Generates n samples into buf -blargg_err_t track_play( struct Track_Filter* this, int n, sample_t buf [] ); - -// Skips n samples -blargg_err_t track_skip( struct Track_Filter* this, int n ); - -// Number of samples played/skipped since start_track() -static inline int track_sample_count( struct Track_Filter* this ) { return this->out_time; } - -// True if track ended. Causes are end of source samples, end of fade, -// or excessive silence. -static inline bool track_ended( struct Track_Filter* this ) { return this->track_ended_; } - -// Clears state -void track_stop( struct Track_Filter* this ); - -// For use by callbacks - -// Sets internal "track ended" flag and stops generation of further source samples -static inline void track_set_end( struct Track_Filter* this ) { this->emu_track_ended_ = true; } - -// For use by skip_() callback -blargg_err_t skippy_( struct Track_Filter* this, int count ); -void fill_buf( struct Track_Filter* this ); - -// Skip and play callbacks -blargg_err_t skip_( void* emu, int count ); -blargg_err_t play_( void* emu, int count, sample_t out [] ); -#endif +// Removes silence from beginning of track, fades end of track. Also looks ahead +// for excessive silence, and if found, ends track. + +// Game_Music_Emu 0.6-pre +#ifndef TRACK_FILTER_H +#define TRACK_FILTER_H + +#include "blargg_common.h" + +typedef short sample_t; +typedef int sample_count_t; + +enum { indefinite_count = INT_MAX/2 + 1 }; +enum { buf_size = 2048 }; + +struct setup_t { + sample_count_t max_initial; // maximum silence to strip from beginning of track + sample_count_t max_silence; // maximum silence in middle of track without it ending + int lookahead; // internal speed when looking ahead for silence (2=200% etc.) +}; + +struct Track_Filter { + void* emu_; + struct setup_t setup_; + const char* emu_error; + bool silence_ignored_; + + // Timing + int out_time; // number of samples played since start of track + int emu_time; // number of samples emulator has generated since start of track + int emu_track_ended_; // emulator has reached end of track + volatile int track_ended_; + + // Fading + int fade_start; + int fade_step; + + // Silence detection + int silence_time; // absolute number of samples where most recent silence began + int silence_count; // number of samples of silence to play before using buf + int buf_remain; // number of samples left in silence buffer + sample_t buf [buf_size]; +}; + +// Initializes filter. Must be done once before using object. +blargg_err_t track_init( struct Track_Filter* this, void* ); +void track_create( struct Track_Filter* this ); + +// Gets/sets setup +static inline struct setup_t const* track_get_setup( struct Track_Filter* this ) { return &this->setup_; } +static inline void track_setup( struct Track_Filter* this, struct setup_t const* s ) { this->setup_ = *s; } + +// Disables automatic end-of-track detection and skipping of silence at beginning +static inline void track_ignore_silence( struct Track_Filter* this, bool disable ) { this->silence_ignored_ = disable; } + +// Clears state and skips initial silence in track +blargg_err_t track_start( struct Track_Filter* this ); + +// Sets time that fade starts, and how long until track ends. +void track_set_fade( struct Track_Filter* this, sample_count_t start, sample_count_t length ); + +// Generates n samples into buf +blargg_err_t track_play( struct Track_Filter* this, int n, sample_t buf [] ); + +// Skips n samples +blargg_err_t track_skip( struct Track_Filter* this, int n ); + +// Number of samples played/skipped since start_track() +static inline int track_sample_count( struct Track_Filter* this ) { return this->out_time; } + +// True if track ended. Causes are end of source samples, end of fade, +// or excessive silence. +static inline bool track_ended( struct Track_Filter* this ) { return this->track_ended_; } + +// Clears state +void track_stop( struct Track_Filter* this ); + +// For use by callbacks + +// Sets internal "track ended" flag and stops generation of further source samples +static inline void track_set_end( struct Track_Filter* this ) { this->emu_track_ended_ = true; } + +// For use by skip_() callback +blargg_err_t skippy_( struct Track_Filter* this, int count ); +void fill_buf( struct Track_Filter* this ); + +// Skip and play callbacks +blargg_err_t skip_( void* emu, int count ); +blargg_err_t play_( void* emu, int count, sample_t out [] ); +#endif diff --git a/apps/codecs/libgme/vrc7tone.h b/apps/codecs/libgme/vrc7tone.h index a256c80ba6..c589335c3c 100644 --- a/apps/codecs/libgme/vrc7tone.h +++ b/apps/codecs/libgme/vrc7tone.h @@ -1,20 +1,20 @@ -/* VRC7 TONES by okazaki@angel.ne.jp */ -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x33,0x01,0x09,0x0e,0x94,0x90,0x40,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x13,0x41,0x0f,0x0d,0xce,0xd3,0x43,0x13,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x01,0x12,0x1b,0x06,0xff,0xd2,0x00,0x32,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x61,0x61,0x1b,0x07,0xaf,0x63,0x20,0x28,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x22,0x21,0x1e,0x06,0xf0,0x76,0x08,0x28,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x66,0x21,0x15,0x00,0x93,0x94,0x20,0xf8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x21,0x61,0x1c,0x07,0x82,0x81,0x10,0x17,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x23,0x21,0x20,0x1f,0xc0,0x71,0x07,0x47,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x25,0x31,0x26,0x05,0x64,0x41,0x18,0xf8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x17,0x21,0x28,0x07,0xff,0x83,0x02,0xf8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x97,0x81,0x25,0x07,0xcf,0xc8,0x02,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x21,0x21,0x54,0x0f,0x80,0x7f,0x07,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x01,0x01,0x56,0x03,0xd3,0xb2,0x43,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x31,0x21,0x0c,0x03,0x82,0xc0,0x40,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x21,0x01,0x0c,0x03,0xd4,0xd3,0x40,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x07,0x21,0x14,0x00,0xee,0xf8,0xff,0xf8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x01,0x31,0x00,0x00,0xf8,0xf7,0xf8,0xf7,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x25,0x11,0x00,0x00,0xf8,0xfa,0xf8,0x55,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +/* VRC7 TONES by okazaki@angel.ne.jp */ +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x33,0x01,0x09,0x0e,0x94,0x90,0x40,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x13,0x41,0x0f,0x0d,0xce,0xd3,0x43,0x13,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x01,0x12,0x1b,0x06,0xff,0xd2,0x00,0x32,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x61,0x61,0x1b,0x07,0xaf,0x63,0x20,0x28,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x22,0x21,0x1e,0x06,0xf0,0x76,0x08,0x28,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x66,0x21,0x15,0x00,0x93,0x94,0x20,0xf8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x21,0x61,0x1c,0x07,0x82,0x81,0x10,0x17,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x23,0x21,0x20,0x1f,0xc0,0x71,0x07,0x47,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x25,0x31,0x26,0x05,0x64,0x41,0x18,0xf8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x17,0x21,0x28,0x07,0xff,0x83,0x02,0xf8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x97,0x81,0x25,0x07,0xcf,0xc8,0x02,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x21,0x21,0x54,0x0f,0x80,0x7f,0x07,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x01,0x01,0x56,0x03,0xd3,0xb2,0x43,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x31,0x21,0x0c,0x03,0x82,0xc0,0x40,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x21,0x01,0x0c,0x03,0xd4,0xd3,0x40,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x07,0x21,0x14,0x00,0xee,0xf8,0xff,0xf8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x01,0x31,0x00,0x00,0xf8,0xf7,0xf8,0xf7,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x25,0x11,0x00,0x00,0xf8,0xfa,0xf8,0x55,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 diff --git a/apps/codecs/libgme/ym2413_emu.c b/apps/codecs/libgme/ym2413_emu.c index 9efd3dcc3d..d9ada431ca 100644 --- a/apps/codecs/libgme/ym2413_emu.c +++ b/apps/codecs/libgme/ym2413_emu.c @@ -1,45 +1,45 @@ -// Game_Music_Emu 0.5.5. http://www.slack.net/~ant/ - -#include "ym2413_emu.h" - -void Ym2413_init( struct Ym2413_Emu* this ) -{ - this->last_time = disabled_time; this->out = 0; -} - -int Ym2413_set_rate( struct Ym2413_Emu* this, int sample_rate, int clock_rate ) -{ - OPLL_new ( &this->opll, clock_rate, sample_rate ); - OPLL_reset_patch( &this->opll, OPLL_2413_TONE ); - - Ym2413_reset( this ); - return 0; -} - -void Ym2413_reset( struct Ym2413_Emu* this ) -{ - OPLL_reset( &this->opll ); - OPLL_setMask( &this->opll, 0 ); -} - -void Ym2413_write( struct Ym2413_Emu* this, int addr, int data ) -{ - OPLL_writeIO( &this->opll, 0, addr ); - OPLL_writeIO( &this->opll, 1, data ); -} - -void Ym2413_mute_voices( struct Ym2413_Emu* this, int mask ) -{ - OPLL_setMask( &this->opll, mask ); -} - -void Ym2413_run( struct Ym2413_Emu* this, int pair_count, short* out ) -{ - while ( pair_count-- ) - { - int s = OPLL_calc( &this->opll ) << 1; - out [0] = s; - out [1] = s; - out += 2; - } -} +// Game_Music_Emu 0.5.5. http://www.slack.net/~ant/ + +#include "ym2413_emu.h" + +void Ym2413_init( struct Ym2413_Emu* this ) +{ + this->last_time = disabled_time; this->out = 0; +} + +int Ym2413_set_rate( struct Ym2413_Emu* this, int sample_rate, int clock_rate ) +{ + OPLL_new ( &this->opll, clock_rate, sample_rate ); + OPLL_reset_patch( &this->opll, OPLL_2413_TONE ); + + Ym2413_reset( this ); + return 0; +} + +void Ym2413_reset( struct Ym2413_Emu* this ) +{ + OPLL_reset( &this->opll ); + OPLL_setMask( &this->opll, 0 ); +} + +void Ym2413_write( struct Ym2413_Emu* this, int addr, int data ) +{ + OPLL_writeIO( &this->opll, 0, addr ); + OPLL_writeIO( &this->opll, 1, data ); +} + +void Ym2413_mute_voices( struct Ym2413_Emu* this, int mask ) +{ + OPLL_setMask( &this->opll, mask ); +} + +void Ym2413_run( struct Ym2413_Emu* this, int pair_count, short* out ) +{ + while ( pair_count-- ) + { + int s = OPLL_calc( &this->opll ) << 1; + out [0] = s; + out [1] = s; + out += 2; + } +} diff --git a/apps/codecs/libgme/ym2413_emu.h b/apps/codecs/libgme/ym2413_emu.h index 68d8fe3d8f..8f52b04fbd 100644 --- a/apps/codecs/libgme/ym2413_emu.h +++ b/apps/codecs/libgme/ym2413_emu.h @@ -1,61 +1,61 @@ -// YM2413 FM sound chip emulator interface - -// Game_Music_Emu 0.6-pre -#ifndef YM2413_EMU_H -#define YM2413_EMU_H - -#include "blargg_common.h" -#include "emu2413.h" - -enum { out_chan_count = 2 }; // stereo -enum { channel_count = 14 }; -enum { disabled_time = -1 }; - -struct Ym2413_Emu { - OPLL opll; - - // Impl - int last_time; - short* out; -}; - -void Ym2413_init( struct Ym2413_Emu* this ); - -static inline bool Ym2413_supported( void ) { return true; } - -// Sets output sample rate and chip clock rates, in Hz. Returns non-zero -// if error. -int Ym2413_set_rate( struct Ym2413_Emu* this, int sample_rate, int clock_rate ); - -// Resets to power-up state -void Ym2413_reset( struct Ym2413_Emu* this ); - -// Mutes voice n if bit n (1 << n) of mask is set -void Ym2413_mute_voices( struct Ym2413_Emu* this, int mask ); - -// Writes data to addr -void Ym2413_write( struct Ym2413_Emu* this, int addr, int data ); - -// Runs and writes pair_count*2 samples to output -void Ym2413_run( struct Ym2413_Emu* this, int pair_count, short* out ); - -static inline void Ym2413_enable( struct Ym2413_Emu* this, bool b ) { this->last_time = b ? 0 : disabled_time; } -static inline bool Ym2413_enabled( struct Ym2413_Emu* this ) { return this->last_time != disabled_time; } -static inline void Ym2413_begin_frame( struct Ym2413_Emu* this, short* buf ) { this->out = buf; this->last_time = 0; } - -static inline int Ym2413_run_until( struct Ym2413_Emu* this, int time ) -{ - int count = time - this->last_time; - if ( count > 0 ) - { - if ( this->last_time < 0 ) - return false; - this->last_time = time; - short* p = this->out; - this->out += count * out_chan_count; - Ym2413_run( this, count, p ); - } - return true; -} - -#endif +// YM2413 FM sound chip emulator interface + +// Game_Music_Emu 0.6-pre +#ifndef YM2413_EMU_H +#define YM2413_EMU_H + +#include "blargg_common.h" +#include "emu2413.h" + +enum { out_chan_count = 2 }; // stereo +enum { channel_count = 14 }; +enum { disabled_time = -1 }; + +struct Ym2413_Emu { + OPLL opll; + + // Impl + int last_time; + short* out; +}; + +void Ym2413_init( struct Ym2413_Emu* this ); + +static inline bool Ym2413_supported( void ) { return true; } + +// Sets output sample rate and chip clock rates, in Hz. Returns non-zero +// if error. +int Ym2413_set_rate( struct Ym2413_Emu* this, int sample_rate, int clock_rate ); + +// Resets to power-up state +void Ym2413_reset( struct Ym2413_Emu* this ); + +// Mutes voice n if bit n (1 << n) of mask is set +void Ym2413_mute_voices( struct Ym2413_Emu* this, int mask ); + +// Writes data to addr +void Ym2413_write( struct Ym2413_Emu* this, int addr, int data ); + +// Runs and writes pair_count*2 samples to output +void Ym2413_run( struct Ym2413_Emu* this, int pair_count, short* out ); + +static inline void Ym2413_enable( struct Ym2413_Emu* this, bool b ) { this->last_time = b ? 0 : disabled_time; } +static inline bool Ym2413_enabled( struct Ym2413_Emu* this ) { return this->last_time != disabled_time; } +static inline void Ym2413_begin_frame( struct Ym2413_Emu* this, short* buf ) { this->out = buf; this->last_time = 0; } + +static inline int Ym2413_run_until( struct Ym2413_Emu* this, int time ) +{ + int count = time - this->last_time; + if ( count > 0 ) + { + if ( this->last_time < 0 ) + return false; + this->last_time = time; + short* p = this->out; + this->out += count * out_chan_count; + Ym2413_run( this, count, p ); + } + return true; +} + +#endif diff --git a/apps/codecs/libgme/ymtables.h b/apps/codecs/libgme/ymtables.h index 51812c1b57..c1619026b2 100644 --- a/apps/codecs/libgme/ymtables.h +++ b/apps/codecs/libgme/ymtables.h @@ -1,559 +1,559 @@ -#ifndef _EMUTABLES_H_ -#define _EMUTABLES_H_ - -/* Precompiled ym2612 tables for use in Rockbox */ - -static const int tl_coeff[] = { - 268435455, 267712100, 266990695, 266271234, 265553712, 264838123, 264124462, 263412725, 262702906, 261994999, 261289000, - 260584903, 259882704, 259182396, 258483976, 257787438, 257092777, 256399988, 255709066, 255020006, 254332802, 253647450, - 252963945, 252282282, 251602456, 250924462, 250248294, 249573949, 248901421, 248230705, 247561797, 246894691, 246229383, - 245565867, 244904140, 244244195, 243586029, 242929637, 242275013, 241622154, 240971053, 240321708, 239674112, 239028261, - 238384150, 237741775, 237101131, 236462214, 235825018, 235189539, 234555773, 233923714, 233293359, 232664702, 232037740, - 231412466, 230788878, 230166970, 229546738, 228928178, 228311284, 227696052, 227082479, 226470558, 225860287, 225251660, - 224644674, 224039323, 223435603, 222833510, 222233039, 221634187, 221036948, 220441319, 219847295, 219254871, 218664044, - 218074809, 217487162, 216901098, 216316614, 215733704, 215152366, 214572594, 213994384, 213417732, 212842635, 212269087, - 211697084, 211126623, 210557699, 209990308, 209424446, 208860109, 208297293, 207735993, 207176206, 206617927, 206061153, - 205505879, 204952102, 204399816, 203849019, 203299706, 202751873, 202205517, 201660633, 201117217, 200575266, 200034774, - 199495740, 198958158, 198422024, 197887335, 197354088, 196822277, 196291899, 195762950, 195235427, 194709325, 194184641, - 193661370, 193139510, 192619056, 192100005, 191582352, 191066094, 190551228, 190037748, 189525653, 189014937, 188505598, - 187997631, 187491033, 186985800, 186481928, 185979414, 185478255, 184978446, 184479983, 183982864, 183487085, 182992641, - 182499530, 182007748, 181517291, 181028155, 180540338, 180053835, 179568643, 179084759, 178602178, 178120898, 177640915, - 177162225, 176684825, 176208712, 175733881, 175260330, 174788055, 174317053, 173847320, 173378853, 172911648, 172445702, - 171981012, 171517574, 171055385, 170594441, 170134740, 169676277, 169219049, 168763054, 168308287, 167854746, 167402427, - 166951327, 166501443, 166052770, 165605307, 165159050, 164713995, 164270139, 163827480, 163386013, 162945736, 162506646, - 162068738, 161632011, 161196460, 160762083, 160328877, 159896838, 159465963, 159036250, 158607694, 158180293, 157754044, - 157328943, 156904988, 156482176, 156060502, 155639965, 155220562, 154802288, 154385142, 153969119, 153554218, 153140435, - 152727766, 152316210, 151905763, 151496422, 151088184, 150681046, 150275005, 149870058, 149466203, 149063435, 148661753, - 148261154, 147861634, 147463190, 147065821, 146669522, 146274291, 145880125, 145487021, 145094976, 144703988, 144314054, - 143925170, 143537334, 143150543, 142764795, 142380086, 141996414, 141613775, 141232168, 140851589, 140472035, 140093505, - 139715994, 139339501, 138964022, 138589555, 138216097, 137843646, 137472198, 137101751, 136732302, 136363849, 135996388, - 135629918, 135264436, 134899938, 134536423, 134173887, 133812328, 133451743, 133092130, 132733486, 132375808, 132019095, - 131663342, 131308548, 130954711, 130601826, 130249893, 129898908, 129548869, 129199773, 128851618, 128504401, 128158119, - 127812771, 127468353, 127124864, 126782300, 126440659, 126099939, 125760137, 125421250, 125083277, 124746214, 124410060, - 124074812, 123740467, 123407023, 123074477, 122742828, 122412072, 122082208, 121753232, 121425143, 121097939, 120771615, - 120446172, 120121605, 119797912, 119475092, 119153142, 118832060, 118511843, 118192488, 117873994, 117556359, 117239579, - 116923653, 116608578, 116294353, 115980974, 115668439, 115356747, 115045894, 114735880, 114426700, 114118354, 113810839, - 113504152, 113198292, 112893256, 112589042, 112285648, 111983071, 111681310, 111380362, 111080225, 110780896, 110482375, - 110184657, 109887742, 109591627, 109296310, 109001789, 108708061, 108415125, 108122978, 107831619, 107541044, 107251253, - 106962243, 106674011, 106386556, 106099876, 105813968, 105528830, 105244461, 104960859, 104678020, 104395944, 104114628, - 103834069, 103554267, 103275219, 102996923, 102719377, 102442578, 102166526, 101891217, 101616650, 101342823, 101069734, - 100797381, 100525762, 100254875, 99984718, 99715288, 99446585, 99178606, 98911349, 98644812, 98378993, 98113891, - 97849503, 97585828, 97322863, 97060606, 96799057, 96538212, 96278070, 96018629, 95759887, 95501842, 95244493, - 94987837, 94731873, 94476599, 94222012, 93968112, 93714895, 93462361, 93210508, 92959333, 92708835, 92459012, - 92209863, 91961384, 91713575, 91466434, 91219959, 90974149, 90729000, 90484512, 90240683, 89997511, 89754994, - 89513131, 89271920, 89031358, 88791445, 88552178, 88313556, 88075578, 87838240, 87601542, 87365481, 87130057, - 86895267, 86661110, 86427584, 86194687, 85962418, 85730775, 85499756, 85269359, 85039583, 84810427, 84581888, - 84353965, 84126656, 83899959, 83673874, 83448397, 83223528, 82999266, 82775607, 82552551, 82330096, 82108241, - 81886984, 81666322, 81446256, 81226782, 81007900, 80789608, 80571904, 80354786, 80138254, 79922305, 79706938, - 79492151, 79277943, 79064313, 78851258, 78638777, 78426868, 78215531, 78004763, 77794564, 77584930, 77375862, - 77167357, 76959413, 76752031, 76545207, 76338940, 76133229, 75928072, 75723469, 75519416, 75315914, 75112960, - 74910552, 74708690, 74507373, 74306597, 74106363, 73906668, 73707512, 73508892, 73310807, 73113256, 72916237, - 72719749, 72523791, 72328361, 72133457, 71939079, 71745225, 71551892, 71359081, 71166789, 70975016, 70783759, - 70593018, 70402791, 70213076, 70023872, 69835179, 69646994, 69459315, 69272143, 69085475, 68899310, 68713647, - 68528484, 68343820, 68159653, 67975983, 67792808, 67610127, 67427937, 67246239, 67065030, 66884310, 66704076, - 66524328, 66345065, 66166285, 65987986, 65810168, 65632829, 65455968, 65279583, 65103674, 64928239, 64753277, - 64578786, 64404765, 64231213, 64058129, 63885511, 63713359, 63541670, 63370444, 63199679, 63029375, 62859529, - 62690141, 62521210, 62352734, 62184711, 62017142, 61850024, 61683357, 61517138, 61351368, 61186044, 61021166, - 60856731, 60692741, 60529192, 60366083, 60203414, 60041184, 59879391, 59718034, 59557111, 59396622, 59236566, - 59076941, 58917746, 58758980, 58600642, 58442730, 58285245, 58128183, 57971545, 57815329, 57659533, 57504158, - 57349201, 57194662, 57040539, 56886832, 56733539, 56580659, 56428190, 56276133, 56124486, 55973247, 55822415, - 55671990, 55521971, 55372355, 55223143, 55074333, 54925924, 54777915, 54630305, 54483092, 54336276, 54189856, - 54043830, 53898198, 53752959, 53608110, 53463652, 53319583, 53175903, 53032610, 52889702, 52747180, 52605042, - 52463287, 52321914, 52180922, 52040310, 51900076, 51760221, 51620743, 51481640, 51342912, 51204558, 51066577, - 50928968, 50791729, 50654860, 50518360, 50382228, 50246463, 50111064, 49976029, 49841359, 49707051, 49573105, - 49439520, 49306295, 49173429, 49040922, 48908771, 48776976, 48645537, 48514451, 48383719, 48253339, 48123311, - 47993633, 47864304, 47735324, 47606691, 47478405, 47350465, 47222869, 47095618, 46968709, 46842142, 46715916, - 46590031, 46464484, 46339276, 46214406, 46089871, 45965673, 45841809, 45718279, 45595082, 45472216, 45349682, - 45227478, 45105603, 44984057, 44862838, 44741946, 44621380, 44501139, 44381221, 44261627, 44142355, 44023404, - 43904774, 43786464, 43668472, 43550798, 43433442, 43316402, 43199677, 43083266, 42967170, 42851386, 42735914, - 42620753, 42505903, 42391362, 42277130, 42163206, 42049588, 41936277, 41823271, 41710570, 41598172, 41486077, - 41374285, 41262793, 41151602, 41040711, 40930118, 40819823, 40709826, 40600125, 40490720, 40381609, 40272793, - 40164269, 40056039, 39948099, 39840451, 39733093, 39626024, 39519243, 39412751, 39306545, 39200625, 39094991, - 38989642, 38884576, 38779794, 38675294, 38571075, 38467138, 38363480, 38260102, 38157002, 38054180, 37951635, - 37849367, 37747374, 37645656, 37544212, 37443042, 37342144, 37241518, 37141163, 37041078, 36941264, 36841718, - 36742440, 36643430, 36544687, 36446210, 36347998, 36250051, 36152368, 36054948, 35957790, 35860895, 35764260, - 35667886, 35571772, 35475916, 35380319, 35284980, 35189897, 35095071, 35000500, 34906184, 34812122, 34718314, - 34624758, 34531454, 34438402, 34345601, 34253050, 34160748, 34068695, 33976890, 33885332, 33794021, 33702956, - 33612137, 33521562, 33431231, 33341144, 33251299, 33161697, 33072336, 32983216, 32894336, 32805695, 32717294, - 32629130, 32541204, 32453515, 32366063, 32278846, 32191864, 32105116, 32018602, 31932322, 31846273, 31760457, - 31674872, 31589518, 31504393, 31419498, 31334832, 31250394, 31166183, 31082200, 30998442, 30914911, 30831604, - 30748522, 30665664, 30583029, 30500617, 30418426, 30336458, 30254710, 30173183, 30091875, 30010786, 29929916, - 29849263, 29768829, 29688610, 29608608, 29528822, 29449250, 29369893, 29290750, 29211820, 29133103, 29054598, - 28976304, 28898222, 28820350, 28742687, 28665234, 28587990, 28510954, 28434125, 28357503, 28281088, 28204879, - 28128875, 28053076, 27977482, 27902091, 27826903, 27751917, 27677134, 27602552, 27528172, 27453991, 27380011, - 27306230, 27232648, 27159264, 27086078, 27013089, 26940296, 26867700, 26795300, 26723094, 26651083, 26579267, - 26507643, 26436213, 26364975, 26293929, 26223075, 26152412, 26081939, 26011656, 25941562, 25871657, 25801940, - 25732412, 25663071, 25593916, 25524948, 25456166, 25387569, 25319157, 25250929, 25182886, 25115025, 25047348, - 24979852, 24912539, 24845407, 24778456, 24711686, 24645095, 24578684, 24512451, 24446397, 24380522, 24314823, - 24249302, 24183957, 24118789, 24053796, 23988978, 23924335, 23859866, 23795570, 23731448, 23667499, 23603722, - 23540117, 23476683, 23413421, 23350328, 23287406, 23224653, 23162070, 23099655, 23037408, 22975329, 22913417, - 22851673, 22790094, 22728681, 22667434, 22606352, 22545435, 22484682, 22424092, 22363666, 22303402, 22243301, - 22183362, 22123584, 22063968, 22004512, 21945216, 21886080, 21827104, 21768286, 21709627, 21651126, 21592783, - 21534597, 21476567, 21418694, 21360977, 21303416, 21246009, 21188758, 21131660, 21074717, 21017926, 20961289, - 20904805, 20848473, 20792292, 20736263, 20680385, 20624657, 20569080, 20513652, 20458374, 20403245, 20348264, - 20293432, 20238747, 20184209, 20129819, 20075575, 20021477, 19967525, 19913719, 19860057, 19806540, 19753167, - 19699938, 19646853, 19593910, 19541111, 19488453, 19435937, 19383563, 19331330, 19279238, 19227286, 19175474, - 19123802, 19072269, 19020875, 18969619, 18918502, 18867522, 18816680, 18765974, 18715405, 18664973, 18614676, - 18564515, 18514489, 18464598, 18414842, 18365219, 18315730, 18266375, 18217152, 18168062, 18119105, 18070279, - 18021585, 17973022, 17924590, 17876289, 17828118, 17780076, 17732164, 17684381, 17636727, 17589201, 17541803, - 17494533, 17447391, 17400375, 17353486, 17306724, 17260087, 17213577, 17167191, 17120930, 17074795, 17028783, - 16982896, 16937132, 16891491, 16845974, 16800579, 16755306, 16710155, 16665126, 16620219, 16575432, 16530766, - 16486221, 16441795, 16397490, 16353303, 16309236, 16265287, 16221457, 16177745, 16134151, 16090674, 16047314, - 16004072, 15960945, 15917935, 15875041, 15832263, 15789599, 15747051, 15704617, 15662298, 15620093, 15578001, - 15536023, 15494158, 15452406, 15410766, 15369239, 15327823, 15286519, 15245327, 15204245, 15163274, 15122414, - 15081663, 15041023, 15000491, 14960070, 14919757, 14879552, 14839456, 14799468, 14759588, 14719815, 14680150, - 14640591, 14601139, 14561793, 14522554, 14483420, 14444391, 14405468, 14366649, 14327935, 14289326, 14250820, - 14212418, 14174120, 14135925, 14097833, 14059843, 14021956, 13984171, 13946488, 13908906, 13871426, 13834047, - 13796768, 13759590, 13722512, 13685534, 13648655, 13611876, 13575196, 13538615, 13502132, 13465748, 13429462, - 13393273, 13357183, 13321189, 13285292, 13249492, 13213789, 13178182, 13142670, 13107255, 13071934, 13036709, - 13001579, 12966544, 12931603, 12896756, 12862003, 12827344, 12792778, 12758305, 12723925, 12689638, 12655443, - 12621341, 12587330, 12553411, 12519583, 12485846, 12452201, 12418646, 12385181, 12351807, 12318522, 12285327, - 12252222, 12219206, 12186279, 12153440, 12120690, 12088029, 12055455, 12022969, 11990571, 11958260, 11926036, - 11893899, 11861848, 11829884, 11798006, 11766214, 11734507, 11702886, 11671350, 11639900, 11608533, 11577252, - 11546055, 11514941, 11483912, 11452966, 11422104, 11391325, 11360628, 11330015, 11299484, 11269035, 11238668, - 11208384, 11178180, 11148058, 11118018, 11088058, 11058179, 11028380, 10998662, 10969024, 10939466, 10909987, - 10880588, 10851268, 10822027, 10792865, 10763781, 10734776, 10705849, 10677000, 10648228, 10619535, 10590918, - 10562379, 10533916, 10505530, 10477221, 10448988, 10420831, 10392750, 10364745, 10336815, 10308960, 10281180, - 10253476, 10225846, 10198290, 10170809, 10143401, 10116068, 10088808, 10061622, 10034509, 10007468, 9980501, - 9953607, 9926785, 9900035, 9873357, 9846752, 9820217, 9793755, 9767364, 9741043, 9714794, 9688616, - 9662508, 9636470, 9610503, 9584605, 9558778, 9533019, 9507331, 9481711, 9456161, 9430679, 9405266, - 9379922, 9354646, 9329438, 9304298, 9279225, 9254221, 9229283, 9204413, 9179610, 9154874, 9130204, - 9105601, 9081064, 9056593, 9032188, 9007849, 8983576, 8959368, 8935225, 8911147, 8887134, 8863186, - 8839302, 8815483, 8791728, 8768037, 8744409, 8720846, 8697346, 8673909, 8650535, 8627225, 8603977, - 8580792, 8557669, 8534608, 8511610, 8488674, 8465799, 8442987, 8420235, 8397545, 8374916, 8352348, - 8329841, 8307395, 8285009, 8262683, 8240418, 8218212, 8196067, 8173981, 8151954, 8129987, 8108079, - 8086230, 8064440, 8042709, 8021036, 7999422, 7977866, 7956368, 7934928, 7913545, 7892221, 7870954, - 7849744, 7828591, 7807495, 7786456, 7765474, 7744548, 7723679, 7702866, 7682109, 7661408, 7640763, - 7620173, 7599639, 7579160, 7558737, 7538368, 7518055, 7497796, 7477591, 7457441, 7437346, 7417304, - 7397317, 7377383, 7357503, 7337677, 7317904, 7298185, 7278518, 7258905, 7239344, 7219836, 7200381, - 7180978, 7161627, 7142329, 7123082, 7103888, 7084745, 7065654, 7046614, 7027625, 7008688, 6989802, - 6970966, 6952181, 6933447, 6914764, 6896130, 6877547, 6859014, 6840531, 6822098, 6803715, 6785381, - 6767096, 6748861, 6730675, 6712537, 6694449, 6676410, 6658419, 6640476, 6622582, 6604736, 6586938, - 6569188, 6551486, 6533832, 6516225, 6498666, 6481154, 6463689, 6446272, 6428901, 6411577, 6394299, - 6377069, 6359884, 6342746, 6325655, 6308609, 6291609, 6274655, 6257747, 6240884, 6224066, 6207294, - 6190568, 6173886, 6157249, 6140657, 6124110, 6107607, 6091149, 6074735, 6058365, 6042040, 6025758, - 6009521, 5993327, 5977177, 5961070, 5945007, 5928987, 5913010, 5897076, 5881185, 5865337, 5849532, - 5833769, 5818049, 5802371, 5786735, 5771141, 5755590, 5740080, 5724612, 5709186, 5693802, 5678459, - 5663157, 5647896, 5632677, 5617498, 5602361, 5587264, 5572208, 5557193, 5542218, 5527283, 5512389, - 5497534, 5482720, 5467946, 5453211, 5438517, 5423861, 5409246, 5394669, 5380132, 5365635, 5351176, - 5336756, 5322375, 5308033, 5293729, 5279464, 5265237, 5251049, 5236899, 5222787, 5208713, 5194677, - 5180679, 5166719, 5152796, 5138911, 5125063, 5111252, 5097479, 5083743, 5070044, 5056382, 5042756, - 5029167, 5015615, 5002100, 4988620, 4975178, 4961771, 4948400, 4935066, 4921767, 4908505, 4895278, - 4882086, 4868931, 4855810, 4842725, 4829676, 4816661, 4803682, 4790737, 4777827, 4764953, 4752112, - 4739307, 4726536, 4713799, 4701097, 4688429, 4675795, 4663195, 4650629, 4638097, 4625599, 4613134, - 4600703, 4588306, 4575941, 4563611, 4551313, 4539049, 4526817, 4514619, 4502453, 4490320, 4478220, - 4466153, 4454118, 4442115, 4430145, 4418207, 4406301, 4394428, 4382586, 4370776, 4358998, 4347252, - 4335538, 4323855, 4312203, 4300583, 4288994, 4277437, 4265910, 4254415, 4242950, 4231517, 4220114, - 4208742, 4197401, 4186090, 4174810, 4163560, 4152340, 4141151, 4129992, 4118863, 4107764, 4096694, - 4085655, 4074645, 4063665, 4052715, 4041794, 4030903, 4020041, 4009208, 3998404, 3987630, 3976884, - 3966168, 3955480, 3944821, 3934191, 3923590, 3913017, 3902472, 3891956, 3881469, 3871009, 3860578, - 3850175, 3839800, 3829453, 3819133, 3808842, 3798578, 3788342, 3778134, 3767953, 3757799, 3747673, - 3737574, 3727503, 3717458, 3707441, 3697450, 3687487, 3677550, 3667640, 3657757, 3647900, 3638070, - 3628267, 3618490, 3608739, 3599014, 3589316, 3579644, 3569998, 3560378, 3550783, 3541215, 3531673, - 3522156, 3512665, 3503199, 3493759, 3484344, 3474955, 3465591, 3456252, 3446939, 3437650, 3428387, - 3419148, 3409935, 3400746, 3391582, 3382443, 3373328, 3364238, 3355172, 3346131, 3337114, 3328122, - 3319153, 3310209, 3301289, 3292393, 3283521, 3274673, 3265849, 3257048, 3248271, 3239518, 3230789, - 3222083, 3213400, 3204741, 3196105, 3187493, 3178903, 3170337, 3161794, 3153274, 3144777, 3136302, - 3127851, 3119422, 3111016, 3102633, 3094272, 3085934, 3077619, 3069325, 3061054, 3052806, 3044579, - 3036375, 3028193, 3020033, 3011895, 3003779, 2995684, 2987612, 2979561, 2971532, 2963525, 2955539, - 2947575, 2939632, 2931710, 2923810, 2915931, 2908074, 2900237, 2892422, 2884628, 2876855, 2869102, - 2861371, 2853660, 2845971, 2838302, 2830653, 2823025, 2815418, 2807832, 2800265, 2792719, 2785194, - 2777689, 2770203, 2762739, 2755294, 2747869, 2740464, 2733080, 2725715, 2718370, 2711045, 2703739, - 2696453, 2689187, 2681941, 2674714, 2667506, 2660318, 2653149, 2646000, 2638870, 2631759, 2624667, - 2617594, 2610540, 2603506, 2596490, 2589493, 2582515, 2575556, 2568616, 2561694, 2554791, 2547907, - 2541041, 2534194, 2527365, 2520554, 2513762, 2506988, 2500233, 2493495, 2486776, 2480075, 2473392, - 2466727, 2460080, 2453450, 2446839, 2440246, 2433670, 2427112, 2420571, 2414049, 2407544, 2401056, - 2394586, 2388133, 2381698, 2375280, 2368879, 2362496, 2356130, 2349780, 2343448, 2337134, 2330836, - 2324555, 2318291, 2312044, 2305813, 2299600, 2293403, 2287223, 2281060, 2274913, 2268783, 2262669, - 2256572, 2250491, 2244427, 2238379, 2232347, 2226331, 2220332, 2214349, 2208382, 2202431, 2196496, - 2190577, 2184674, 2178787, 2172916, 2167060, 2161221, 2155397, 2149589, 2143796, 2138019, 2132258, - 2126512, 2120782, 2115067, 2109368, 2103683, 2098015, 2092361, 2086723, 2081100, 2075492, 2069899, - 2064321, 2058758, 2053211, 2047678, 2042160, 2036657, 2031169, 2025695, 2020237, 2014793, 2009364, - 2003949, 1998549, 1993163, 1987792, 1982436, 1977094, 1971766, 1966453, 1961154, 1955869, 1950599, - 1945342, 1940100, 1934872, 1929658, 1924458, 1919272, 1914101, 1908943, 1903799, 1898668, 1893552, - 1888450, 1883361, 1878286, 1873224, 1868176, 1863142, 1858122, 1853115, 1848121, 1843141, 1838174, - 1833221, 1828281, 1823354, 1818441, 1813540, 1808654, 1803780, 1798919, 1794072, 1789237, 1784416, - 1779607, 1774812, 1770029, 1765259, 1760502, 1755758, 1751027, 1746309, 1741603, 1736910, 1732229, - 1727561, 1722906, 1718263, 1713633, 1709015, 1704410, 1699817, 1695237, 1690669, 1686113, 1681569, - 1677038, 1672519, 1668012, 1663517, 1659034, 1654564, 1650105, 1645659, 1641224, 1636801, 1632391, - 1627992, 1623605, 1619230, 1614866, 1610515, 1606175, 1601847, 1597530, 1593225, 1588932, 1584650, - 1580380, 1576122, 1571874, 1567639, 1563414, 1559201, 1555000, 1550810, 1546631, 1542463, 1538306, - 1534161, 1530027, 1525904, 1521792, 1517691, 1513602, 1509523, 1505455, 1501399, 1497353, 1493318, - 1489294, 1485281, 1481278, 1477287, 1473306, 1469336, 1465376, 1461427, 1457489, 1453562, 1449645, - 1445738, 1441843, 1437957, 1434082, 1430218, 1426364, 1422520, 1418687, 1414864, 1411051, 1407249, - 1403457, 1399675, 1395903, 1392142, 1388390, 1384649, 1380918, 1377197, 1373486, 1369784, 1366093, - 1362412, 1358741, 1355079, 1351428, 1347786, 1344154, 1340532, 1336920, 1333317, 1329724, 1326141, - 1322567, 1319004, 1315449, 1311904, 1308369, 1304844, 1301327, 1297821, 1294323, 1290836, 1287357, - 1283888, 1280429, 1276978, 1273537, 1270105, 1266683, 1263269, 1259865, 1256470, 1253084, 1249708, - 1246340, 1242982, 1239632, 1236292, 1232960, 1229638, 1226324, 1223020, 1219724, 1216437, 1213159, - 1209890, 1206630, 1203378, 1200136, 1196902, 1193676, 1190460, 1187252, 1184052, 1180862, 1177680, - 1174506, 1171341, 1168185, 1165037, 1161897, 1158767, 1155644, 1152530, 1149424, 1146327, 1143238, - 1140157, 1137085, 1134021, 1130965, 1127917, 1124878, 1121846, 1118823, 1115809, 1112802, 1109803, - 1106813, 1103830, 1100855, 1097889, 1094931, 1091980, 1089037, 1086103, 1083176, 1080257, 1077346, - 1074443, 1071548, 1068660, 1065781, 1062909, 1060044, 1057188, 1054339, 1051498, 1048664, 1045839, - 1043020, 1040210, 1037407, 1034611, 1031823, 1029043, 1026270, 1023504, 1020746, 1017996, 1015252, - 1012517, 1009788, 1007067, 1004353, 1001647, 998948, 996256, 993571, 990894, 988224, 985561, - 982905, 980256, 977615, 974980, 972353, 969733, 967120, 964514, 961915, 959323, 956737, - 954159, 951588, 949024, 946467, 943916, 941373, 938836, 936306, 933783, 931267, 928757, - 926254, 923758, 921269, 918787, 916311, 913842, 911379, 908923, 906474, 904031, 901595, - 899166, 896743, 894326, 891916, 889513, 887116, 884725, 882341, 879963, 877592, 875227, - 872869, 870517, 868171, 865831, 863498, 861171, 858851, 856536, 854228, 851926, 849631, - 847341, 845058, 842781, 840510, 838245, 835986, 833733, 831487, 829246, 827011, 824783, - 822560, 820344, 818133, 815929, 813730, 811537, 809350, 807169, 804994, 802825, 800662, - 798504, 796352, 794206, 792066, 789932, 787803, 785680, 783563, 781452, 779346, 777246, - 775151, 773062, 770979, 768902, 766830, 764763, 762703, 760647, 758598, 756553, 754515, - 752482, 750454, 748432, 746415, 744403, 742397, 740397, 738402, 736412, 734428, 732448, - 730475, 728506, 726543, 724585, 722633, 720686, 718744, 716807, 714875, 712949, 711028, - 709112, 707201, 705295, 703394, 701499, 699609, 697723, 695843, 693968, 692098, 690233, - 688373, 686518, 684668, 682823, 680983, 679148, 677318, 675493, 673673, 671857, 670047, - 668241, 666441, 664645, 662854, 661067, 659286, 657510, 655738, 653971, 652208, 650451, - 648698, 646950, 645207, 643468, 641734, 640005, 638280, 636560, 634845, 633134, 631428, - 629727, 628030, 626337, 624650, 622966, 621288, 619613, 617944, 616279, 614618, 612962, - 611310, 609663, 608020, 606381, 604747, 603118, 601492, 599872, 598255, 596643, 595035, - 593432, 591833, 590238, 588647, 587061, 585479, 583901, 582328, 580759, 579194, 577633, - 576076, 574524, 572976, 571432, 569892, 568356, 566825, 565297, 563774, 562255, 560740, - 559229, 557722, 556219, 554720, 553225, 551734, 550248, 548765, 547286, 545811, 544341, - 542874, 541411, 539952, 538497, 537046, 535599, 534155, 532716, 531280, 529849, 528421, - 526997, 525577, 524161, 522748, 521340, 519935, 518534, 517136, 515743, 514353, 512967, - 511585, 510206, 508831, 507460, 506093, 504729, 503369, 502012, 500660, 499310, 497965, - 496623, 495285, 493950, 492619, 491292, 489968, 488648, 487331, 486018, 484708, 483402, - 482099, 480800, 479504, 478212, 476924, 475638, 474357, 473078, 471804, 470532, 469264, - 468000, 466739, 465481, 464227, 462976, 461728, 460484, 459243, 458005, 456771, 455540, - 454313, 453089, 451868, 450650, 449436, 448225, 447017, 445812, 444611, 443413, 442218, - 441026, 439838, 438653, 437470, 436292, 435116, 433943, 432774, 431608, 430445, 429285, - 428128, 426974, 425824, 424676, 423532, 422391, 421252, 420117, 418985, 417856, 416730, - 415607, 414487, 413370, 412256, 411146, 410038, 408933, 407831, 406732, 405636, 404543, - 403453, 402365, 401281, 400200, 399121, 398046, 396973, 395903, 394837, 393773, 392712, - 391653, 390598, 389545, 388496, 387449, 386405, 385363, 384325, 383289, 382257, 381226, - 380199, 379175, 378153, 377134, 376118, 375104, 374093, 373085, 372080, 371077, 370077, - 369080, 368085, 367094, 366104, 365118, 364134, 363153, 362174, 361198, 360225, 359254, - 358286, 357321, 356358, 355397, 354440, 353485, 352532, 351582, 350635, 349690, 348748, - 347808, 346871, 345936, 345004, 344074, 343147, 342222, 341300, 340380, 339463, 338548, - 337636, 336726, 335819, 334914, 334011, 333111, 332214, 331318, 330426, 329535, 328647, - 327762, 326878, 325997, 325119, 324243, 323369, 322498, 321629, 320762, 319898, 319036, - 318176, 317319, 316463, 315611, 314760, 313912, 313066, 312222, 311381, 310542, 309705, - 308871, 308038, 307208, 306380, 305555, 304731, 303910, 303091, 302275, 301460, 300648, - 299838, 299030, 298224, 297420, 296619, 295819, 295022, 294227, 293434, 292644, 291855, - 291069, 290284, 289502, 288722, 287944, 287168, 286394, 285622, 284853, 284085, 283320, - 282556, 281795, 281035, 280278, 279523, 278770, 278018, 277269, 276522, 275777, 275034, - 274293, 273553, 272816, 272081, 271348, 270617, 269888, 269160, 268435, 267712, 266990, - 266271, 265553, 264838, 264124, 263412, 262702, 261994, 261289, 260584, 259882, 259182, - 258483, 257787, 257092, 256399, 255709, 255020, 254332, 253647, 252963, 252282, 251602, - 250924, 250248, 249573, 248901, 248230, 247561, 246894, 246229, 245565, 244904, 244244, - 243586, 242929, 242275, 241622, 240971, 240321, 239674, 239028, 238384, 237741, 237101, - 236462, 235825, 235189, 234555, 233923, 233293, 232664, 232037, 231412, 230788, 230166, - 229546, 228928, 228311, 227696, 227082, 226470, 225860, 225251, 224644, 224039, 223435, - 222833, 222233, 221634, 221036, 220441, 219847, 219254, 218664, 218074, 217487, 216901, - 216316, 215733, 215152, 214572, 213994, 213417, 212842, 212269, 211697, 211126, 210557, - 209990, 209424, 208860, 208297, 207735, 207176, 206617, 206061, 205505, 204952, 204399, - 203849, 203299, 202751, 202205, 201660, 201117, 200575, 200034, 199495, 198958, 198422, - 197887, 197354, 196822, 196291, 195762, 195235, 194709, 194184, 193661, 193139, 192619, - 192100, 191582, 191066, 190551, 190037, 189525, 189014, 188505, 187997, 187491, 186985, - 186481, 185979, 185478, 184978, 184479, 183982, 183487, 182992, 182499, 182007, 181517, - 181028, 180540, 180053, 179568, 179084, 178602, 178120, 177640, 177162, 176684, 176208, - 175733, 175260, 174788, 174317, 173847, 173378, 172911, 172445, 171981, 171517, 171055, - 170594, 170134, 169676, 169219, 168763, 168308, 167854, 167402, 166951, 166501, 166052, - 165605, 165159, 164713, 164270, 163827, 163386, 162945, 162506, 162068, 161632, 161196, - 160762, 160328, 159896, 159465, 159036, 158607, 158180, 157754, 157328, 156904, 156482, - 156060, 155639, 155220, 154802, 154385, 153969, 153554, 153140, 152727, 152316, 151905, - 151496, 151088, 150681, 150275, 149870, 149466, 149063, 148661, 148261, 147861, 147463, - 147065, 146669, 146274, 145880, 145487, 145094, 144703, 144314, 143925, 143537, 143150, - 142764, 142380, 141996, 141613, 141232, 140851, 140472, 140093, 139715, 139339, 138964, - 138589, 138216, 137843, 137472, 137101, 136732, 136363, 135996, 135629, 135264, 134899, - 134536, 134173, 133812, 133451, 133092, 132733, 132375, 132019, 131663, 131308, 130954, - 130601, 130249, 129898, 129548, 129199, 128851, 128504, 128158, 127812, 127468, 127124, - 126782, 126440, 126099, 125760, 125421, 125083, 124746, 124410, 124074, 123740, 123407, - 123074, 122742, 122412, 122082, 121753, 121425, 121097, 120771, 120446, 120121, 119797, - 119475, 119153, 118832, 118511, 118192, 117873, 117556, 117239, 116923, 116608, 116294, - 115980, 115668, 115356, 115045, 114735, 114426, 114118, 113810, 113504, 113198, 112893, - 112589, 112285, 111983, 111681, 111380, 111080, 110780, 110482, 110184, 109887, 109591, - 109296, 109001, 108708, 108415, 108122, 107831, 107541, 107251, 106962, 106674, 106386, - 106099, 105813, 105528, 105244, 104960, 104678, 104395, 104114, 103834, 103554, 103275, - 102996, 102719, 102442, 102166, 101891, 101616, 101342, 101069, 100797, 100525, 100254, - 99984, 99715, 99446, 99178, 98911, 98644, 98378, 98113, 97849, 97585, 97322, - 97060, 96799, 96538, 96278, 96018, 95759, 95501, 95244, 94987, 94731, 94476, - 94222, 93968, 93714, 93462, 93210, 92959, 92708, 92459, 92209, 91961, 91713, - 91466, 91219, 90974, 90729, 90484, 90240, 89997, 89754, 89513, 89271, 89031, - 88791, 88552, 88313, 88075, 87838, 87601, 87365, 87130, 86895, 86661, 86427, - 86194, 85962, 85730, 85499, 85269, 85039, 84810, 84581, 84353, 84126, 83899, - 83673, 83448, 83223, 82999, 82775, 82552, 82330, 82108, 81886, 81666, 81446, - 81226, 81007, 80789, 80571, 80354, 80138, 79922, 79706, 79492, 79277, 79064, - 78851, 78638, 78426, 78215, 78004, 77794, 77584, 77375, 77167, 76959, 76752, - 76545, 76338, 76133, 75928, 75723, 75519, 75315, 75112, 74910, 74708, 74507, - 74306, 74106, 73906, 73707, 73508, 73310, 73113, 72916, 72719, 72523, 72328, - 72133, 71939, 71745, 71551, 71359, 71166, 70975, 70783, 70593, 70402, 70213, - 70023, 69835, 69646, 69459, 69272, 69085, 68899, 68713, 68528, 68343, 68159, - 67975, 67792, 67610, 67427, 67246, 67065, 66884, 66704, 66524, 66345, 66166, - 65987, 65810, 65632, 65455, 65279, 65103, 64928, 64753, 64578, 64404, 64231, - 64058, 63885, 63713, 63541, 63370, 63199, 63029, 62859, 62690, 62521, 62352, - 62184, 62017, 61850, 61683, 61517, 61351, 61186, 61021, 60856, 60692, 60529, - 60366, 60203, 60041, 59879, 59718, 59557, 59396, 59236, 59076, 58917, 58758, - 58600, 58442, 58285, 58128, 57971, 57815, 57659, 57504, 57349, 57194, 57040, - 56886, 56733, 56580, 56428, 56276, 56124, 55973, 55822, 55671, 55521, 55372, - 55223, 55074, 54925, 54777, 54630, 54483, 54336, 54189, 54043, 53898, 53752, - 53608, 53463, 53319, 53175, 53032, 52889, 52747, 52605, 52463, 52321, 52180, - 52040, 51900, 51760, 51620, 51481, 51342, 51204, 51066, 50928, 50791, 50654, - 50518, 50382, 50246, 50111, 49976, 49841, 49707, 49573, 49439, 49306, 49173, - 49040, 48908, 48776, 48645, 48514, 48383, 48253, 48123, 47993, 47864, 47735, - 47606, 47478, 47350, 47222, 47095, 46968, 46842, 46715, 46590, 46464, 46339, - 46214, 46089, 45965, 45841, 45718, 45595, 45472, 45349, 45227, 45105, 44984, - 44862, 44741, 44621, 44501, 44381, 44261, 44142, 44023, 43904, 43786, 43668, - 43550, 43433, 43316, 43199, 43083, 42967, 42851, 42735, 42620, 42505, 42391, - 42277, 42163, 42049, 41936, 41823, 41710, 41598, 41486, 41374, 41262, 41151, - 41040, 40930, 40819, 40709, 40600, 40490, 40381, 40272, 40164, 40056, 39948, - 39840, 39733, 39626, 39519, 39412, 39306, 39200, 39094, 38989, 38884, 38779, - 38675, 38571, 38467, 38363, 38260, 38157, 38054, 37951, 37849, 37747, 37645, - 37544, 37443, 37342, 37241, 37141, 37041, 36941, 36841, 36742, 36643, 36544, - 36446, 36347, 36250, 36152, 36054, 35957, 35860, 35764, 35667, 35571, 35475, - 35380, 35284, 35189, 35095, 35000, 34906, 34812, 34718, 34624, 34531, 34438, - 34345, 34253, 34160, 34068, 33976, 33885 -}; - -static const short sindb_coeff[] = { - 2401, 2144, 1994, 1887, 1804, 1737, 1680, 1630, 1587, 1548, 1512, 1480, 1450, - 1423, 1397, 1373, 1351, 1330, 1310, 1291, 1273, 1255, 1239, 1223, 1208, 1194, - 1180, 1166, 1153, 1141, 1128, 1117, 1105, 1094, 1084, 1073, 1063, 1053, 1043, - 1034, 1025, 1016, 1007, 999, 990, 982, 974, 967, 959, 952, 944, 937, - 930, 923, 916, 910, 903, 897, 890, 884, 878, 872, 866, 860, 855, - 849, 843, 838, 832, 827, 822, 817, 812, 807, 802, 797, 792, 787, - 783, 778, 773, 769, 764, 760, 756, 751, 747, 743, 739, 734, 730, - 726, 722, 718, 715, 711, 707, 703, 699, 696, 692, 688, 685, 681, - 678, 674, 671, 667, 664, 661, 657, 654, 651, 648, 644, 641, 638, - 635, 632, 629, 626, 623, 620, 617, 614, 611, 608, 605, 602, 599, - 597, 594, 591, 588, 586, 583, 580, 578, 575, 572, 570, 567, 565, - 562, 560, 557, 555, 552, 550, 547, 545, 542, 540, 538, 535, 533, - 531, 528, 526, 524, 522, 519, 517, 515, 513, 510, 508, 506, 504, - 502, 500, 498, 495, 493, 491, 489, 487, 485, 483, 481, 479, 477, - 475, 473, 471, 469, 467, 465, 464, 462, 460, 458, 456, 454, 452, - 450, 449, 447, 445, 443, 441, 440, 438, 436, 434, 433, 431, 429, - 427, 426, 424, 422, 421, 419, 417, 416, 414, 412, 411, 409, 408, - 406, 404, 403, 401, 400, 398, 396, 395, 393, 392, 390, 389, 387, - 386, 384, 383, 381, 380, 378, 377, 375, 374, 372, 371, 370, 368, - 367, 365, 364, 362, 361, 360, 358, 357, 355, 354, 353, 351, 350, - 349, 347, 346, 345, 343, 342, 341, 339, 338, 337, 336, 334, 333, - 332, 330, 329, 328, 327, 325, 324, 323, 322, 320, 319, 318, 317, - 316, 314, 313, 312, 311, 310, 308, 307, 306, 305, 304, 303, 301, - 300, 299, 298, 297, 296, 295, 293, 292, 291, 290, 289, 288, 287, - 286, 285, 284, 282, 281, 280, 279, 278, 277, 276, 275, 274, 273, - 272, 271, 270, 269, 268, 267, 266, 265, 264, 263, 262, 261, 260, - 259, 258, 257, 256, 255, 254, 253, 252, 251, 250, 249, 248, 247, - 246, 245, 244, 243, 242, 241, 240, 240, 239, 238, 237, 236, 235, - 234, 233, 232, 231, 230, 230, 229, 228, 227, 226, 225, 224, 223, - 222, 222, 221, 220, 219, 218, 217, 216, 216, 215, 214, 213, 212, - 211, 211, 210, 209, 208, 207, 206, 206, 205, 204, 203, 202, 202, - 201, 200, 199, 198, 198, 197, 196, 195, 195, 194, 193, 192, 191, - 191, 190, 189, 188, 188, 187, 186, 185, 185, 184, 183, 182, 182, - 181, 180, 180, 179, 178, 177, 177, 176, 175, 174, 174, 173, 172, - 172, 171, 170, 170, 169, 168, 167, 167, 166, 165, 165, 164, 163, - 163, 162, 161, 161, 160, 159, 159, 158, 157, 157, 156, 155, 155, - 154, 153, 153, 152, 151, 151, 150, 150, 149, 148, 148, 147, 146, - 146, 145, 145, 144, 143, 143, 142, 141, 141, 140, 140, 139, 138, - 138, 137, 137, 136, 135, 135, 134, 134, 133, 133, 132, 131, 131, - 130, 130, 129, 129, 128, 127, 127, 126, 126, 125, 125, 124, 123, - 123, 122, 122, 121, 121, 120, 120, 119, 119, 118, 117, 117, 116, - 116, 115, 115, 114, 114, 113, 113, 112, 112, 111, 111, 110, 110, - 109, 109, 108, 108, 107, 107, 106, 106, 105, 105, 104, 104, 103, - 103, 102, 102, 101, 101, 100, 100, 99, 99, 98, 98, 97, 97, - 96, 96, 95, 95, 94, 94, 94, 93, 93, 92, 92, 91, 91, - 90, 90, 89, 89, 89, 88, 88, 87, 87, 86, 86, 85, 85, - 85, 84, 84, 83, 83, 82, 82, 82, 81, 81, 80, 80, 79, - 79, 79, 78, 78, 77, 77, 77, 76, 76, 75, 75, 75, 74, - 74, 73, 73, 73, 72, 72, 71, 71, 71, 70, 70, 69, 69, - 69, 68, 68, 68, 67, 67, 66, 66, 66, 65, 65, 65, 64, - 64, 63, 63, 63, 62, 62, 62, 61, 61, 61, 60, 60, 59, - 59, 59, 58, 58, 58, 57, 57, 57, 56, 56, 56, 55, 55, - 55, 54, 54, 54, 53, 53, 53, 52, 52, 52, 51, 51, 51, - 50, 50, 50, 49, 49, 49, 49, 48, 48, 48, 47, 47, 47, - 46, 46, 46, 45, 45, 45, 45, 44, 44, 44, 43, 43, 43, - 43, 42, 42, 42, 41, 41, 41, 40, 40, 40, 40, 39, 39, - 39, 39, 38, 38, 38, 37, 37, 37, 37, 36, 36, 36, 36, - 35, 35, 35, 35, 34, 34, 34, 34, 33, 33, 33, 32, 32, - 32, 32, 31, 31, 31, 31, 31, 30, 30, 30, 30, 29, 29, - 29, 29, 28, 28, 28, 28, 27, 27, 27, 27, 27, 26, 26, - 26, 26, 25, 25, 25, 25, 25, 24, 24, 24, 24, 23, 23, - 23, 23, 23, 22, 22, 22, 22, 22, 21, 21, 21, 21, 21, - 20, 20, 20, 20, 20, 19, 19, 19, 19, 19, 19, 18, 18, - 18, 18, 18, 17, 17, 17, 17, 17, 17, 16, 16, 16, 16, - 16, 15, 15, 15, 15, 15, 15, 14, 14, 14, 14, 14, 14, - 13, 13, 13, 13, 13, 13, 13, 12, 12, 12, 12, 12, 12, - 11, 11, 11, 11, 11, 11, 11, 10, 10, 10, 10, 10, 10, - 10, 10, 9, 9, 9, 9, 9, 9, 9, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 7, - 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 -}; - - -static const short lfo_freq_coeff[] = { - 0, 3, 6, 9, 12, 15, 18, 21, 25, 28, 31, 34, 37, - 40, 43, 46, 50, 53, 56, 59, 62, 65, 68, 71, 74, 78, - 81, 84, 87, 90, 93, 96, 99, 102, 105, 108, 111, 115, 118, - 121, 124, 127, 130, 133, 136, 139, 142, 145, 148, 151, 154, 157, - 160, 163, 166, 169, 172, 175, 178, 180, 183, 186, 189, 192, 195, - 198, 201, 204, 207, 209, 212, 215, 218, 221, 224, 226, 229, 232, - 235, 238, 240, 243, 246, 249, 251, 254, 257, 260, 262, 265, 268, - 270, 273, 276, 278, 281, 283, 286, 289, 291, 294, 296, 299, 301, - 304, 306, 309, 311, 314, 316, 319, 321, 324, 326, 328, 331, 333, - 336, 338, 340, 343, 345, 347, 350, 352, 354, 356, 359, 361, 363, - 365, 367, 370, 372, 374, 376, 378, 380, 382, 384, 386, 388, 391, - 393, 395, 396, 398, 400, 402, 404, 406, 408, 410, 412, 414, 415, - 417, 419, 421, 423, 424, 426, 428, 430, 431, 433, 435, 436, 438, - 439, 441, 443, 444, 446, 447, 449, 450, 452, 453, 455, 456, 457, - 459, 460, 461, 463, 464, 465, 467, 468, 469, 470, 472, 473, 474, - 475, 476, 477, 478, 480, 481, 482, 483, 484, 485, 486, 487, 488, - 488, 489, 490, 491, 492, 493, 494, 494, 495, 496, 497, 497, 498, - 499, 499, 500, 501, 501, 502, 502, 503, 504, 504, 504, 505, 505, - 506, 506, 507, 507, 507, 508, 508, 508, 509, 509, 509, 509, 510, - 510, 510, 510, 510, 510, 510, 510, 510, 510, 511, 510, 510, 510, - 510, 510, 510, 510, 510, 510, 510, 509, 509, 509, 509, 508, 508, - 508, 507, 507, 507, 506, 506, 505, 505, 504, 504, 504, 503, 502, - 502, 501, 501, 500, 499, 499, 498, 497, 497, 496, 495, 494, 494, - 493, 492, 491, 490, 489, 488, 488, 487, 486, 485, 484, 483, 482, - 481, 480, 478, 477, 476, 475, 474, 473, 472, 470, 469, 468, 467, - 465, 464, 463, 461, 460, 459, 457, 456, 455, 453, 452, 450, 449, - 447, 446, 444, 443, 441, 439, 438, 436, 435, 433, 431, 430, 428, - 426, 424, 423, 421, 419, 417, 415, 414, 412, 410, 408, 406, 404, - 402, 400, 398, 396, 395, 393, 391, 388, 386, 384, 382, 380, 378, - 376, 374, 372, 370, 367, 365, 363, 361, 359, 356, 354, 352, 350, - 347, 345, 343, 340, 338, 336, 333, 331, 328, 326, 324, 321, 319, - 316, 314, 311, 309, 306, 304, 301, 299, 296, 294, 291, 289, 286, - 283, 281, 278, 276, 273, 270, 268, 265, 262, 260, 257, 254, 251, - 249, 246, 243, 240, 238, 235, 232, 229, 226, 224, 221, 218, 215, - 212, 209, 207, 204, 201, 198, 195, 192, 189, 186, 183, 180, 178, - 175, 172, 169, 166, 163, 160, 157, 154, 151, 148, 145, 142, 139, - 136, 133, 130, 127, 124, 121, 118, 115, 111, 108, 105, 102, 99, - 96, 93, 90, 87, 84, 81, 78, 74, 71, 68, 65, 62, 59, - 56, 53, 50, 46, 43, 40, 37, 34, 31, 28, 25, 21, 18, - 15, 12, 9, 6, 3, 0, -3, -6, -9, -12, -15, -18, -21, - -25, -28, -31, -34, -37, -40, -43, -46, -50, -53, -56, -59, -62, - -65, -68, -71, -74, -78, -81, -84, -87, -90, -93, -96, -99, -102, - -105, -108, -111, -115, -118, -121, -124, -127, -130, -133, -136, -139, -142, - -145, -148, -151, -154, -157, -160, -163, -166, -169, -172, -175, -178, -180, - -183, -186, -189, -192, -195, -198, -201, -204, -207, -209, -212, -215, -218, - -221, -224, -226, -229, -232, -235, -238, -240, -243, -246, -249, -251, -254, - -257, -260, -262, -265, -268, -270, -273, -276, -278, -281, -283, -286, -289, - -291, -294, -296, -299, -301, -304, -306, -309, -311, -314, -316, -319, -321, - -324, -326, -328, -331, -333, -336, -338, -340, -343, -345, -347, -350, -352, - -354, -356, -359, -361, -363, -365, -367, -370, -372, -374, -376, -378, -380, - -382, -384, -386, -388, -391, -393, -395, -396, -398, -400, -402, -404, -406, - -408, -410, -412, -414, -415, -417, -419, -421, -423, -424, -426, -428, -430, - -431, -433, -435, -436, -438, -439, -441, -443, -444, -446, -447, -449, -450, - -452, -453, -455, -456, -457, -459, -460, -461, -463, -464, -465, -467, -468, - -469, -470, -472, -473, -474, -475, -476, -477, -478, -480, -481, -482, -483, - -484, -485, -486, -487, -488, -488, -489, -490, -491, -492, -493, -494, -494, - -495, -496, -497, -497, -498, -499, -499, -500, -501, -501, -502, -502, -503, - -504, -504, -504, -505, -505, -506, -506, -507, -507, -507, -508, -508, -508, - -509, -509, -509, -509, -510, -510, -510, -510, -510, -510, -510, -510, -510, - -510, -511, -510, -510, -510, -510, -510, -510, -510, -510, -510, -510, -509, - -509, -509, -509, -508, -508, -508, -507, -507, -507, -506, -506, -505, -505, - -504, -504, -504, -503, -502, -502, -501, -501, -500, -499, -499, -498, -497, - -497, -496, -495, -494, -494, -493, -492, -491, -490, -489, -488, -488, -487, - -486, -485, -484, -483, -482, -481, -480, -478, -477, -476, -475, -474, -473, - -472, -470, -469, -468, -467, -465, -464, -463, -461, -460, -459, -457, -456, - -455, -453, -452, -450, -449, -447, -446, -444, -443, -441, -439, -438, -436, - -435, -433, -431, -430, -428, -426, -424, -423, -421, -419, -417, -415, -414, - -412, -410, -408, -406, -404, -402, -400, -398, -396, -395, -393, -391, -388, - -386, -384, -382, -380, -378, -376, -374, -372, -370, -367, -365, -363, -361, - -359, -356, -354, -352, -350, -347, -345, -343, -340, -338, -336, -333, -331, - -328, -326, -324, -321, -319, -316, -314, -311, -309, -306, -304, -301, -299, - -296, -294, -291, -289, -286, -283, -281, -278, -276, -273, -270, -268, -265, - -262, -260, -257, -254, -251, -249, -246, -243, -240, -238, -235, -232, -229, - -226, -224, -221, -218, -215, -212, -209, -207, -204, -201, -198, -195, -192, - -189, -186, -183, -180, -178, -175, -172, -169, -166, -163, -160, -157, -154, - -151, -148, -145, -142, -139, -136, -133, -130, -127, -124, -121, -118, -115, - -111, -108, -105, -102, -99, -96, -93, -90, -87, -84, -81, -78, -74, - -71, -68, -65, -62, -59, -56, -53, -50, -46, -43, -40, -37, -34, - -31, -28, -25, -21, -18, -15, -12, -9, -6, -3 -}; - -static const short lfo_env_coeff[] = { - 251, 253, 254, 256, 257, 259, 260, 262, 264, 265, 267, 268, 270, - 271, 273, 274, 276, 277, 279, 281, 282, 284, 285, 287, 288, 290, - 291, 293, 294, 296, 297, 299, 300, 302, 303, 305, 306, 308, 309, - 311, 312, 314, 315, 317, 318, 320, 321, 323, 324, 326, 327, 329, - 330, 332, 333, 335, 336, 337, 339, 340, 342, 343, 345, 346, 348, - 349, 350, 352, 353, 355, 356, 357, 359, 360, 362, 363, 364, 366, - 367, 369, 370, 371, 373, 374, 375, 377, 378, 379, 381, 382, 383, - 385, 386, 387, 389, 390, 391, 392, 394, 395, 396, 397, 399, 400, - 401, 402, 404, 405, 406, 407, 409, 410, 411, 412, 413, 414, 416, - 417, 418, 419, 420, 421, 423, 424, 425, 426, 427, 428, 429, 430, - 431, 432, 434, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, - 445, 446, 447, 448, 449, 450, 451, 452, 453, 453, 454, 455, 456, - 457, 458, 459, 460, 461, 461, 462, 463, 464, 465, 466, 466, 467, - 468, 469, 469, 470, 471, 472, 473, 473, 474, 475, 475, 476, 477, - 477, 478, 479, 479, 480, 481, 481, 482, 483, 483, 484, 484, 485, - 486, 486, 487, 487, 488, 488, 489, 489, 490, 490, 491, 491, 492, - 492, 493, 493, 493, 494, 494, 495, 495, 495, 496, 496, 497, 497, - 497, 498, 498, 498, 498, 499, 499, 499, 500, 500, 500, 500, 500, - 501, 501, 501, 501, 501, 502, 502, 502, 502, 502, 502, 502, 502, - 503, 503, 503, 503, 503, 503, 503, 503, 503, 503, 503, 503, 503, - 503, 503, 503, 503, 503, 503, 502, 502, 502, 502, 502, 502, 502, - 502, 501, 501, 501, 501, 501, 500, 500, 500, 500, 500, 499, 499, - 499, 498, 498, 498, 498, 497, 497, 497, 496, 496, 495, 495, 495, - 494, 494, 493, 493, 493, 492, 492, 491, 491, 490, 490, 489, 489, - 488, 488, 487, 487, 486, 486, 485, 484, 484, 483, 483, 482, 481, - 481, 480, 479, 479, 478, 477, 477, 476, 475, 475, 474, 473, 473, - 472, 471, 470, 469, 469, 468, 467, 466, 466, 465, 464, 463, 462, - 461, 461, 460, 459, 458, 457, 456, 455, 454, 453, 453, 452, 451, - 450, 449, 448, 447, 446, 445, 444, 443, 442, 441, 440, 439, 438, - 437, 436, 435, 434, 432, 431, 430, 429, 428, 427, 426, 425, 424, - 423, 421, 420, 419, 418, 417, 416, 414, 413, 412, 411, 410, 409, - 407, 406, 405, 404, 402, 401, 400, 399, 397, 396, 395, 394, 392, - 391, 390, 389, 387, 386, 385, 383, 382, 381, 379, 378, 377, 375, - 374, 373, 371, 370, 369, 367, 366, 364, 363, 362, 360, 359, 357, - 356, 355, 353, 352, 350, 349, 348, 346, 345, 343, 342, 340, 339, - 337, 336, 335, 333, 332, 330, 329, 327, 326, 324, 323, 321, 320, - 318, 317, 315, 314, 312, 311, 309, 308, 306, 305, 303, 302, 300, - 299, 297, 296, 294, 293, 291, 290, 288, 287, 285, 284, 282, 281, - 279, 277, 276, 274, 273, 271, 270, 268, 267, 265, 264, 262, 260, - 259, 257, 256, 254, 253, 251, 250, 248, 247, 245, 244, 242, 240, - 239, 237, 236, 234, 233, 231, 230, 228, 227, 225, 223, 222, 220, - 219, 217, 216, 214, 213, 211, 210, 208, 207, 205, 204, 202, 201, - 199, 198, 196, 195, 193, 192, 190, 189, 187, 186, 184, 183, 181, - 180, 178, 177, 175, 174, 172, 171, 169, 168, 166, 165, 164, 162, - 161, 159, 158, 156, 155, 153, 152, 151, 149, 148, 146, 145, 144, - 142, 141, 139, 138, 137, 135, 134, 133, 131, 130, 129, 127, 126, - 124, 123, 122, 120, 119, 118, 117, 115, 114, 113, 111, 110, 109, - 108, 106, 105, 104, 103, 101, 100, 99, 98, 96, 95, 94, 93, - 92, 90, 89, 88, 87, 86, 84, 83, 82, 81, 80, 79, 78, - 77, 75, 74, 73, 72, 71, 70, 69, 68, 67, 66, 65, 64, - 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, - 50, 49, 48, 47, 46, 45, 45, 44, 43, 42, 41, 40, 39, - 39, 38, 37, 36, 35, 35, 34, 33, 32, 31, 31, 30, 29, - 29, 28, 27, 26, 26, 25, 24, 24, 23, 22, 22, 21, 20, - 20, 19, 19, 18, 17, 17, 16, 16, 15, 15, 14, 14, 13, - 13, 12, 12, 11, 11, 10, 10, 9, 9, 9, 8, 8, 7, - 7, 7, 6, 6, 6, 5, 5, 5, 4, 4, 4, 3, 3, - 3, 3, 2, 2, 2, 2, 2, 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, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, - 2, 3, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, - 6, 7, 7, 7, 8, 8, 9, 9, 9, 10, 10, 11, 11, - 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, - 19, 19, 20, 20, 21, 22, 22, 23, 24, 24, 25, 26, 26, - 27, 28, 29, 29, 30, 31, 31, 32, 33, 34, 35, 35, 36, - 37, 38, 39, 39, 40, 41, 42, 43, 44, 45, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, - 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, - 74, 75, 77, 78, 79, 80, 81, 82, 83, 84, 86, 87, 88, - 89, 90, 92, 93, 94, 95, 96, 98, 99, 100, 101, 103, 104, - 105, 106, 108, 109, 110, 111, 113, 114, 115, 117, 118, 119, 120, - 122, 123, 124, 126, 127, 129, 130, 131, 133, 134, 135, 137, 138, - 139, 141, 142, 144, 145, 146, 148, 149, 151, 152, 153, 155, 156, - 158, 159, 161, 162, 164, 165, 166, 168, 169, 171, 172, 174, 175, - 177, 178, 180, 181, 183, 184, 186, 187, 189, 190, 192, 193, 195, - 196, 198, 199, 201, 202, 204, 205, 207, 208, 210, 211, 213, 214, - 216, 217, 219, 220, 222, 223, 225, 227, 228, 230, 231, 233, 234, - 236, 237, 239, 240, 242, 244, 245, 247, 248, 250 -}; - -#endif +#ifndef _EMUTABLES_H_ +#define _EMUTABLES_H_ + +/* Precompiled ym2612 tables for use in Rockbox */ + +static const int tl_coeff[] = { + 268435455, 267712100, 266990695, 266271234, 265553712, 264838123, 264124462, 263412725, 262702906, 261994999, 261289000, + 260584903, 259882704, 259182396, 258483976, 257787438, 257092777, 256399988, 255709066, 255020006, 254332802, 253647450, + 252963945, 252282282, 251602456, 250924462, 250248294, 249573949, 248901421, 248230705, 247561797, 246894691, 246229383, + 245565867, 244904140, 244244195, 243586029, 242929637, 242275013, 241622154, 240971053, 240321708, 239674112, 239028261, + 238384150, 237741775, 237101131, 236462214, 235825018, 235189539, 234555773, 233923714, 233293359, 232664702, 232037740, + 231412466, 230788878, 230166970, 229546738, 228928178, 228311284, 227696052, 227082479, 226470558, 225860287, 225251660, + 224644674, 224039323, 223435603, 222833510, 222233039, 221634187, 221036948, 220441319, 219847295, 219254871, 218664044, + 218074809, 217487162, 216901098, 216316614, 215733704, 215152366, 214572594, 213994384, 213417732, 212842635, 212269087, + 211697084, 211126623, 210557699, 209990308, 209424446, 208860109, 208297293, 207735993, 207176206, 206617927, 206061153, + 205505879, 204952102, 204399816, 203849019, 203299706, 202751873, 202205517, 201660633, 201117217, 200575266, 200034774, + 199495740, 198958158, 198422024, 197887335, 197354088, 196822277, 196291899, 195762950, 195235427, 194709325, 194184641, + 193661370, 193139510, 192619056, 192100005, 191582352, 191066094, 190551228, 190037748, 189525653, 189014937, 188505598, + 187997631, 187491033, 186985800, 186481928, 185979414, 185478255, 184978446, 184479983, 183982864, 183487085, 182992641, + 182499530, 182007748, 181517291, 181028155, 180540338, 180053835, 179568643, 179084759, 178602178, 178120898, 177640915, + 177162225, 176684825, 176208712, 175733881, 175260330, 174788055, 174317053, 173847320, 173378853, 172911648, 172445702, + 171981012, 171517574, 171055385, 170594441, 170134740, 169676277, 169219049, 168763054, 168308287, 167854746, 167402427, + 166951327, 166501443, 166052770, 165605307, 165159050, 164713995, 164270139, 163827480, 163386013, 162945736, 162506646, + 162068738, 161632011, 161196460, 160762083, 160328877, 159896838, 159465963, 159036250, 158607694, 158180293, 157754044, + 157328943, 156904988, 156482176, 156060502, 155639965, 155220562, 154802288, 154385142, 153969119, 153554218, 153140435, + 152727766, 152316210, 151905763, 151496422, 151088184, 150681046, 150275005, 149870058, 149466203, 149063435, 148661753, + 148261154, 147861634, 147463190, 147065821, 146669522, 146274291, 145880125, 145487021, 145094976, 144703988, 144314054, + 143925170, 143537334, 143150543, 142764795, 142380086, 141996414, 141613775, 141232168, 140851589, 140472035, 140093505, + 139715994, 139339501, 138964022, 138589555, 138216097, 137843646, 137472198, 137101751, 136732302, 136363849, 135996388, + 135629918, 135264436, 134899938, 134536423, 134173887, 133812328, 133451743, 133092130, 132733486, 132375808, 132019095, + 131663342, 131308548, 130954711, 130601826, 130249893, 129898908, 129548869, 129199773, 128851618, 128504401, 128158119, + 127812771, 127468353, 127124864, 126782300, 126440659, 126099939, 125760137, 125421250, 125083277, 124746214, 124410060, + 124074812, 123740467, 123407023, 123074477, 122742828, 122412072, 122082208, 121753232, 121425143, 121097939, 120771615, + 120446172, 120121605, 119797912, 119475092, 119153142, 118832060, 118511843, 118192488, 117873994, 117556359, 117239579, + 116923653, 116608578, 116294353, 115980974, 115668439, 115356747, 115045894, 114735880, 114426700, 114118354, 113810839, + 113504152, 113198292, 112893256, 112589042, 112285648, 111983071, 111681310, 111380362, 111080225, 110780896, 110482375, + 110184657, 109887742, 109591627, 109296310, 109001789, 108708061, 108415125, 108122978, 107831619, 107541044, 107251253, + 106962243, 106674011, 106386556, 106099876, 105813968, 105528830, 105244461, 104960859, 104678020, 104395944, 104114628, + 103834069, 103554267, 103275219, 102996923, 102719377, 102442578, 102166526, 101891217, 101616650, 101342823, 101069734, + 100797381, 100525762, 100254875, 99984718, 99715288, 99446585, 99178606, 98911349, 98644812, 98378993, 98113891, + 97849503, 97585828, 97322863, 97060606, 96799057, 96538212, 96278070, 96018629, 95759887, 95501842, 95244493, + 94987837, 94731873, 94476599, 94222012, 93968112, 93714895, 93462361, 93210508, 92959333, 92708835, 92459012, + 92209863, 91961384, 91713575, 91466434, 91219959, 90974149, 90729000, 90484512, 90240683, 89997511, 89754994, + 89513131, 89271920, 89031358, 88791445, 88552178, 88313556, 88075578, 87838240, 87601542, 87365481, 87130057, + 86895267, 86661110, 86427584, 86194687, 85962418, 85730775, 85499756, 85269359, 85039583, 84810427, 84581888, + 84353965, 84126656, 83899959, 83673874, 83448397, 83223528, 82999266, 82775607, 82552551, 82330096, 82108241, + 81886984, 81666322, 81446256, 81226782, 81007900, 80789608, 80571904, 80354786, 80138254, 79922305, 79706938, + 79492151, 79277943, 79064313, 78851258, 78638777, 78426868, 78215531, 78004763, 77794564, 77584930, 77375862, + 77167357, 76959413, 76752031, 76545207, 76338940, 76133229, 75928072, 75723469, 75519416, 75315914, 75112960, + 74910552, 74708690, 74507373, 74306597, 74106363, 73906668, 73707512, 73508892, 73310807, 73113256, 72916237, + 72719749, 72523791, 72328361, 72133457, 71939079, 71745225, 71551892, 71359081, 71166789, 70975016, 70783759, + 70593018, 70402791, 70213076, 70023872, 69835179, 69646994, 69459315, 69272143, 69085475, 68899310, 68713647, + 68528484, 68343820, 68159653, 67975983, 67792808, 67610127, 67427937, 67246239, 67065030, 66884310, 66704076, + 66524328, 66345065, 66166285, 65987986, 65810168, 65632829, 65455968, 65279583, 65103674, 64928239, 64753277, + 64578786, 64404765, 64231213, 64058129, 63885511, 63713359, 63541670, 63370444, 63199679, 63029375, 62859529, + 62690141, 62521210, 62352734, 62184711, 62017142, 61850024, 61683357, 61517138, 61351368, 61186044, 61021166, + 60856731, 60692741, 60529192, 60366083, 60203414, 60041184, 59879391, 59718034, 59557111, 59396622, 59236566, + 59076941, 58917746, 58758980, 58600642, 58442730, 58285245, 58128183, 57971545, 57815329, 57659533, 57504158, + 57349201, 57194662, 57040539, 56886832, 56733539, 56580659, 56428190, 56276133, 56124486, 55973247, 55822415, + 55671990, 55521971, 55372355, 55223143, 55074333, 54925924, 54777915, 54630305, 54483092, 54336276, 54189856, + 54043830, 53898198, 53752959, 53608110, 53463652, 53319583, 53175903, 53032610, 52889702, 52747180, 52605042, + 52463287, 52321914, 52180922, 52040310, 51900076, 51760221, 51620743, 51481640, 51342912, 51204558, 51066577, + 50928968, 50791729, 50654860, 50518360, 50382228, 50246463, 50111064, 49976029, 49841359, 49707051, 49573105, + 49439520, 49306295, 49173429, 49040922, 48908771, 48776976, 48645537, 48514451, 48383719, 48253339, 48123311, + 47993633, 47864304, 47735324, 47606691, 47478405, 47350465, 47222869, 47095618, 46968709, 46842142, 46715916, + 46590031, 46464484, 46339276, 46214406, 46089871, 45965673, 45841809, 45718279, 45595082, 45472216, 45349682, + 45227478, 45105603, 44984057, 44862838, 44741946, 44621380, 44501139, 44381221, 44261627, 44142355, 44023404, + 43904774, 43786464, 43668472, 43550798, 43433442, 43316402, 43199677, 43083266, 42967170, 42851386, 42735914, + 42620753, 42505903, 42391362, 42277130, 42163206, 42049588, 41936277, 41823271, 41710570, 41598172, 41486077, + 41374285, 41262793, 41151602, 41040711, 40930118, 40819823, 40709826, 40600125, 40490720, 40381609, 40272793, + 40164269, 40056039, 39948099, 39840451, 39733093, 39626024, 39519243, 39412751, 39306545, 39200625, 39094991, + 38989642, 38884576, 38779794, 38675294, 38571075, 38467138, 38363480, 38260102, 38157002, 38054180, 37951635, + 37849367, 37747374, 37645656, 37544212, 37443042, 37342144, 37241518, 37141163, 37041078, 36941264, 36841718, + 36742440, 36643430, 36544687, 36446210, 36347998, 36250051, 36152368, 36054948, 35957790, 35860895, 35764260, + 35667886, 35571772, 35475916, 35380319, 35284980, 35189897, 35095071, 35000500, 34906184, 34812122, 34718314, + 34624758, 34531454, 34438402, 34345601, 34253050, 34160748, 34068695, 33976890, 33885332, 33794021, 33702956, + 33612137, 33521562, 33431231, 33341144, 33251299, 33161697, 33072336, 32983216, 32894336, 32805695, 32717294, + 32629130, 32541204, 32453515, 32366063, 32278846, 32191864, 32105116, 32018602, 31932322, 31846273, 31760457, + 31674872, 31589518, 31504393, 31419498, 31334832, 31250394, 31166183, 31082200, 30998442, 30914911, 30831604, + 30748522, 30665664, 30583029, 30500617, 30418426, 30336458, 30254710, 30173183, 30091875, 30010786, 29929916, + 29849263, 29768829, 29688610, 29608608, 29528822, 29449250, 29369893, 29290750, 29211820, 29133103, 29054598, + 28976304, 28898222, 28820350, 28742687, 28665234, 28587990, 28510954, 28434125, 28357503, 28281088, 28204879, + 28128875, 28053076, 27977482, 27902091, 27826903, 27751917, 27677134, 27602552, 27528172, 27453991, 27380011, + 27306230, 27232648, 27159264, 27086078, 27013089, 26940296, 26867700, 26795300, 26723094, 26651083, 26579267, + 26507643, 26436213, 26364975, 26293929, 26223075, 26152412, 26081939, 26011656, 25941562, 25871657, 25801940, + 25732412, 25663071, 25593916, 25524948, 25456166, 25387569, 25319157, 25250929, 25182886, 25115025, 25047348, + 24979852, 24912539, 24845407, 24778456, 24711686, 24645095, 24578684, 24512451, 24446397, 24380522, 24314823, + 24249302, 24183957, 24118789, 24053796, 23988978, 23924335, 23859866, 23795570, 23731448, 23667499, 23603722, + 23540117, 23476683, 23413421, 23350328, 23287406, 23224653, 23162070, 23099655, 23037408, 22975329, 22913417, + 22851673, 22790094, 22728681, 22667434, 22606352, 22545435, 22484682, 22424092, 22363666, 22303402, 22243301, + 22183362, 22123584, 22063968, 22004512, 21945216, 21886080, 21827104, 21768286, 21709627, 21651126, 21592783, + 21534597, 21476567, 21418694, 21360977, 21303416, 21246009, 21188758, 21131660, 21074717, 21017926, 20961289, + 20904805, 20848473, 20792292, 20736263, 20680385, 20624657, 20569080, 20513652, 20458374, 20403245, 20348264, + 20293432, 20238747, 20184209, 20129819, 20075575, 20021477, 19967525, 19913719, 19860057, 19806540, 19753167, + 19699938, 19646853, 19593910, 19541111, 19488453, 19435937, 19383563, 19331330, 19279238, 19227286, 19175474, + 19123802, 19072269, 19020875, 18969619, 18918502, 18867522, 18816680, 18765974, 18715405, 18664973, 18614676, + 18564515, 18514489, 18464598, 18414842, 18365219, 18315730, 18266375, 18217152, 18168062, 18119105, 18070279, + 18021585, 17973022, 17924590, 17876289, 17828118, 17780076, 17732164, 17684381, 17636727, 17589201, 17541803, + 17494533, 17447391, 17400375, 17353486, 17306724, 17260087, 17213577, 17167191, 17120930, 17074795, 17028783, + 16982896, 16937132, 16891491, 16845974, 16800579, 16755306, 16710155, 16665126, 16620219, 16575432, 16530766, + 16486221, 16441795, 16397490, 16353303, 16309236, 16265287, 16221457, 16177745, 16134151, 16090674, 16047314, + 16004072, 15960945, 15917935, 15875041, 15832263, 15789599, 15747051, 15704617, 15662298, 15620093, 15578001, + 15536023, 15494158, 15452406, 15410766, 15369239, 15327823, 15286519, 15245327, 15204245, 15163274, 15122414, + 15081663, 15041023, 15000491, 14960070, 14919757, 14879552, 14839456, 14799468, 14759588, 14719815, 14680150, + 14640591, 14601139, 14561793, 14522554, 14483420, 14444391, 14405468, 14366649, 14327935, 14289326, 14250820, + 14212418, 14174120, 14135925, 14097833, 14059843, 14021956, 13984171, 13946488, 13908906, 13871426, 13834047, + 13796768, 13759590, 13722512, 13685534, 13648655, 13611876, 13575196, 13538615, 13502132, 13465748, 13429462, + 13393273, 13357183, 13321189, 13285292, 13249492, 13213789, 13178182, 13142670, 13107255, 13071934, 13036709, + 13001579, 12966544, 12931603, 12896756, 12862003, 12827344, 12792778, 12758305, 12723925, 12689638, 12655443, + 12621341, 12587330, 12553411, 12519583, 12485846, 12452201, 12418646, 12385181, 12351807, 12318522, 12285327, + 12252222, 12219206, 12186279, 12153440, 12120690, 12088029, 12055455, 12022969, 11990571, 11958260, 11926036, + 11893899, 11861848, 11829884, 11798006, 11766214, 11734507, 11702886, 11671350, 11639900, 11608533, 11577252, + 11546055, 11514941, 11483912, 11452966, 11422104, 11391325, 11360628, 11330015, 11299484, 11269035, 11238668, + 11208384, 11178180, 11148058, 11118018, 11088058, 11058179, 11028380, 10998662, 10969024, 10939466, 10909987, + 10880588, 10851268, 10822027, 10792865, 10763781, 10734776, 10705849, 10677000, 10648228, 10619535, 10590918, + 10562379, 10533916, 10505530, 10477221, 10448988, 10420831, 10392750, 10364745, 10336815, 10308960, 10281180, + 10253476, 10225846, 10198290, 10170809, 10143401, 10116068, 10088808, 10061622, 10034509, 10007468, 9980501, + 9953607, 9926785, 9900035, 9873357, 9846752, 9820217, 9793755, 9767364, 9741043, 9714794, 9688616, + 9662508, 9636470, 9610503, 9584605, 9558778, 9533019, 9507331, 9481711, 9456161, 9430679, 9405266, + 9379922, 9354646, 9329438, 9304298, 9279225, 9254221, 9229283, 9204413, 9179610, 9154874, 9130204, + 9105601, 9081064, 9056593, 9032188, 9007849, 8983576, 8959368, 8935225, 8911147, 8887134, 8863186, + 8839302, 8815483, 8791728, 8768037, 8744409, 8720846, 8697346, 8673909, 8650535, 8627225, 8603977, + 8580792, 8557669, 8534608, 8511610, 8488674, 8465799, 8442987, 8420235, 8397545, 8374916, 8352348, + 8329841, 8307395, 8285009, 8262683, 8240418, 8218212, 8196067, 8173981, 8151954, 8129987, 8108079, + 8086230, 8064440, 8042709, 8021036, 7999422, 7977866, 7956368, 7934928, 7913545, 7892221, 7870954, + 7849744, 7828591, 7807495, 7786456, 7765474, 7744548, 7723679, 7702866, 7682109, 7661408, 7640763, + 7620173, 7599639, 7579160, 7558737, 7538368, 7518055, 7497796, 7477591, 7457441, 7437346, 7417304, + 7397317, 7377383, 7357503, 7337677, 7317904, 7298185, 7278518, 7258905, 7239344, 7219836, 7200381, + 7180978, 7161627, 7142329, 7123082, 7103888, 7084745, 7065654, 7046614, 7027625, 7008688, 6989802, + 6970966, 6952181, 6933447, 6914764, 6896130, 6877547, 6859014, 6840531, 6822098, 6803715, 6785381, + 6767096, 6748861, 6730675, 6712537, 6694449, 6676410, 6658419, 6640476, 6622582, 6604736, 6586938, + 6569188, 6551486, 6533832, 6516225, 6498666, 6481154, 6463689, 6446272, 6428901, 6411577, 6394299, + 6377069, 6359884, 6342746, 6325655, 6308609, 6291609, 6274655, 6257747, 6240884, 6224066, 6207294, + 6190568, 6173886, 6157249, 6140657, 6124110, 6107607, 6091149, 6074735, 6058365, 6042040, 6025758, + 6009521, 5993327, 5977177, 5961070, 5945007, 5928987, 5913010, 5897076, 5881185, 5865337, 5849532, + 5833769, 5818049, 5802371, 5786735, 5771141, 5755590, 5740080, 5724612, 5709186, 5693802, 5678459, + 5663157, 5647896, 5632677, 5617498, 5602361, 5587264, 5572208, 5557193, 5542218, 5527283, 5512389, + 5497534, 5482720, 5467946, 5453211, 5438517, 5423861, 5409246, 5394669, 5380132, 5365635, 5351176, + 5336756, 5322375, 5308033, 5293729, 5279464, 5265237, 5251049, 5236899, 5222787, 5208713, 5194677, + 5180679, 5166719, 5152796, 5138911, 5125063, 5111252, 5097479, 5083743, 5070044, 5056382, 5042756, + 5029167, 5015615, 5002100, 4988620, 4975178, 4961771, 4948400, 4935066, 4921767, 4908505, 4895278, + 4882086, 4868931, 4855810, 4842725, 4829676, 4816661, 4803682, 4790737, 4777827, 4764953, 4752112, + 4739307, 4726536, 4713799, 4701097, 4688429, 4675795, 4663195, 4650629, 4638097, 4625599, 4613134, + 4600703, 4588306, 4575941, 4563611, 4551313, 4539049, 4526817, 4514619, 4502453, 4490320, 4478220, + 4466153, 4454118, 4442115, 4430145, 4418207, 4406301, 4394428, 4382586, 4370776, 4358998, 4347252, + 4335538, 4323855, 4312203, 4300583, 4288994, 4277437, 4265910, 4254415, 4242950, 4231517, 4220114, + 4208742, 4197401, 4186090, 4174810, 4163560, 4152340, 4141151, 4129992, 4118863, 4107764, 4096694, + 4085655, 4074645, 4063665, 4052715, 4041794, 4030903, 4020041, 4009208, 3998404, 3987630, 3976884, + 3966168, 3955480, 3944821, 3934191, 3923590, 3913017, 3902472, 3891956, 3881469, 3871009, 3860578, + 3850175, 3839800, 3829453, 3819133, 3808842, 3798578, 3788342, 3778134, 3767953, 3757799, 3747673, + 3737574, 3727503, 3717458, 3707441, 3697450, 3687487, 3677550, 3667640, 3657757, 3647900, 3638070, + 3628267, 3618490, 3608739, 3599014, 3589316, 3579644, 3569998, 3560378, 3550783, 3541215, 3531673, + 3522156, 3512665, 3503199, 3493759, 3484344, 3474955, 3465591, 3456252, 3446939, 3437650, 3428387, + 3419148, 3409935, 3400746, 3391582, 3382443, 3373328, 3364238, 3355172, 3346131, 3337114, 3328122, + 3319153, 3310209, 3301289, 3292393, 3283521, 3274673, 3265849, 3257048, 3248271, 3239518, 3230789, + 3222083, 3213400, 3204741, 3196105, 3187493, 3178903, 3170337, 3161794, 3153274, 3144777, 3136302, + 3127851, 3119422, 3111016, 3102633, 3094272, 3085934, 3077619, 3069325, 3061054, 3052806, 3044579, + 3036375, 3028193, 3020033, 3011895, 3003779, 2995684, 2987612, 2979561, 2971532, 2963525, 2955539, + 2947575, 2939632, 2931710, 2923810, 2915931, 2908074, 2900237, 2892422, 2884628, 2876855, 2869102, + 2861371, 2853660, 2845971, 2838302, 2830653, 2823025, 2815418, 2807832, 2800265, 2792719, 2785194, + 2777689, 2770203, 2762739, 2755294, 2747869, 2740464, 2733080, 2725715, 2718370, 2711045, 2703739, + 2696453, 2689187, 2681941, 2674714, 2667506, 2660318, 2653149, 2646000, 2638870, 2631759, 2624667, + 2617594, 2610540, 2603506, 2596490, 2589493, 2582515, 2575556, 2568616, 2561694, 2554791, 2547907, + 2541041, 2534194, 2527365, 2520554, 2513762, 2506988, 2500233, 2493495, 2486776, 2480075, 2473392, + 2466727, 2460080, 2453450, 2446839, 2440246, 2433670, 2427112, 2420571, 2414049, 2407544, 2401056, + 2394586, 2388133, 2381698, 2375280, 2368879, 2362496, 2356130, 2349780, 2343448, 2337134, 2330836, + 2324555, 2318291, 2312044, 2305813, 2299600, 2293403, 2287223, 2281060, 2274913, 2268783, 2262669, + 2256572, 2250491, 2244427, 2238379, 2232347, 2226331, 2220332, 2214349, 2208382, 2202431, 2196496, + 2190577, 2184674, 2178787, 2172916, 2167060, 2161221, 2155397, 2149589, 2143796, 2138019, 2132258, + 2126512, 2120782, 2115067, 2109368, 2103683, 2098015, 2092361, 2086723, 2081100, 2075492, 2069899, + 2064321, 2058758, 2053211, 2047678, 2042160, 2036657, 2031169, 2025695, 2020237, 2014793, 2009364, + 2003949, 1998549, 1993163, 1987792, 1982436, 1977094, 1971766, 1966453, 1961154, 1955869, 1950599, + 1945342, 1940100, 1934872, 1929658, 1924458, 1919272, 1914101, 1908943, 1903799, 1898668, 1893552, + 1888450, 1883361, 1878286, 1873224, 1868176, 1863142, 1858122, 1853115, 1848121, 1843141, 1838174, + 1833221, 1828281, 1823354, 1818441, 1813540, 1808654, 1803780, 1798919, 1794072, 1789237, 1784416, + 1779607, 1774812, 1770029, 1765259, 1760502, 1755758, 1751027, 1746309, 1741603, 1736910, 1732229, + 1727561, 1722906, 1718263, 1713633, 1709015, 1704410, 1699817, 1695237, 1690669, 1686113, 1681569, + 1677038, 1672519, 1668012, 1663517, 1659034, 1654564, 1650105, 1645659, 1641224, 1636801, 1632391, + 1627992, 1623605, 1619230, 1614866, 1610515, 1606175, 1601847, 1597530, 1593225, 1588932, 1584650, + 1580380, 1576122, 1571874, 1567639, 1563414, 1559201, 1555000, 1550810, 1546631, 1542463, 1538306, + 1534161, 1530027, 1525904, 1521792, 1517691, 1513602, 1509523, 1505455, 1501399, 1497353, 1493318, + 1489294, 1485281, 1481278, 1477287, 1473306, 1469336, 1465376, 1461427, 1457489, 1453562, 1449645, + 1445738, 1441843, 1437957, 1434082, 1430218, 1426364, 1422520, 1418687, 1414864, 1411051, 1407249, + 1403457, 1399675, 1395903, 1392142, 1388390, 1384649, 1380918, 1377197, 1373486, 1369784, 1366093, + 1362412, 1358741, 1355079, 1351428, 1347786, 1344154, 1340532, 1336920, 1333317, 1329724, 1326141, + 1322567, 1319004, 1315449, 1311904, 1308369, 1304844, 1301327, 1297821, 1294323, 1290836, 1287357, + 1283888, 1280429, 1276978, 1273537, 1270105, 1266683, 1263269, 1259865, 1256470, 1253084, 1249708, + 1246340, 1242982, 1239632, 1236292, 1232960, 1229638, 1226324, 1223020, 1219724, 1216437, 1213159, + 1209890, 1206630, 1203378, 1200136, 1196902, 1193676, 1190460, 1187252, 1184052, 1180862, 1177680, + 1174506, 1171341, 1168185, 1165037, 1161897, 1158767, 1155644, 1152530, 1149424, 1146327, 1143238, + 1140157, 1137085, 1134021, 1130965, 1127917, 1124878, 1121846, 1118823, 1115809, 1112802, 1109803, + 1106813, 1103830, 1100855, 1097889, 1094931, 1091980, 1089037, 1086103, 1083176, 1080257, 1077346, + 1074443, 1071548, 1068660, 1065781, 1062909, 1060044, 1057188, 1054339, 1051498, 1048664, 1045839, + 1043020, 1040210, 1037407, 1034611, 1031823, 1029043, 1026270, 1023504, 1020746, 1017996, 1015252, + 1012517, 1009788, 1007067, 1004353, 1001647, 998948, 996256, 993571, 990894, 988224, 985561, + 982905, 980256, 977615, 974980, 972353, 969733, 967120, 964514, 961915, 959323, 956737, + 954159, 951588, 949024, 946467, 943916, 941373, 938836, 936306, 933783, 931267, 928757, + 926254, 923758, 921269, 918787, 916311, 913842, 911379, 908923, 906474, 904031, 901595, + 899166, 896743, 894326, 891916, 889513, 887116, 884725, 882341, 879963, 877592, 875227, + 872869, 870517, 868171, 865831, 863498, 861171, 858851, 856536, 854228, 851926, 849631, + 847341, 845058, 842781, 840510, 838245, 835986, 833733, 831487, 829246, 827011, 824783, + 822560, 820344, 818133, 815929, 813730, 811537, 809350, 807169, 804994, 802825, 800662, + 798504, 796352, 794206, 792066, 789932, 787803, 785680, 783563, 781452, 779346, 777246, + 775151, 773062, 770979, 768902, 766830, 764763, 762703, 760647, 758598, 756553, 754515, + 752482, 750454, 748432, 746415, 744403, 742397, 740397, 738402, 736412, 734428, 732448, + 730475, 728506, 726543, 724585, 722633, 720686, 718744, 716807, 714875, 712949, 711028, + 709112, 707201, 705295, 703394, 701499, 699609, 697723, 695843, 693968, 692098, 690233, + 688373, 686518, 684668, 682823, 680983, 679148, 677318, 675493, 673673, 671857, 670047, + 668241, 666441, 664645, 662854, 661067, 659286, 657510, 655738, 653971, 652208, 650451, + 648698, 646950, 645207, 643468, 641734, 640005, 638280, 636560, 634845, 633134, 631428, + 629727, 628030, 626337, 624650, 622966, 621288, 619613, 617944, 616279, 614618, 612962, + 611310, 609663, 608020, 606381, 604747, 603118, 601492, 599872, 598255, 596643, 595035, + 593432, 591833, 590238, 588647, 587061, 585479, 583901, 582328, 580759, 579194, 577633, + 576076, 574524, 572976, 571432, 569892, 568356, 566825, 565297, 563774, 562255, 560740, + 559229, 557722, 556219, 554720, 553225, 551734, 550248, 548765, 547286, 545811, 544341, + 542874, 541411, 539952, 538497, 537046, 535599, 534155, 532716, 531280, 529849, 528421, + 526997, 525577, 524161, 522748, 521340, 519935, 518534, 517136, 515743, 514353, 512967, + 511585, 510206, 508831, 507460, 506093, 504729, 503369, 502012, 500660, 499310, 497965, + 496623, 495285, 493950, 492619, 491292, 489968, 488648, 487331, 486018, 484708, 483402, + 482099, 480800, 479504, 478212, 476924, 475638, 474357, 473078, 471804, 470532, 469264, + 468000, 466739, 465481, 464227, 462976, 461728, 460484, 459243, 458005, 456771, 455540, + 454313, 453089, 451868, 450650, 449436, 448225, 447017, 445812, 444611, 443413, 442218, + 441026, 439838, 438653, 437470, 436292, 435116, 433943, 432774, 431608, 430445, 429285, + 428128, 426974, 425824, 424676, 423532, 422391, 421252, 420117, 418985, 417856, 416730, + 415607, 414487, 413370, 412256, 411146, 410038, 408933, 407831, 406732, 405636, 404543, + 403453, 402365, 401281, 400200, 399121, 398046, 396973, 395903, 394837, 393773, 392712, + 391653, 390598, 389545, 388496, 387449, 386405, 385363, 384325, 383289, 382257, 381226, + 380199, 379175, 378153, 377134, 376118, 375104, 374093, 373085, 372080, 371077, 370077, + 369080, 368085, 367094, 366104, 365118, 364134, 363153, 362174, 361198, 360225, 359254, + 358286, 357321, 356358, 355397, 354440, 353485, 352532, 351582, 350635, 349690, 348748, + 347808, 346871, 345936, 345004, 344074, 343147, 342222, 341300, 340380, 339463, 338548, + 337636, 336726, 335819, 334914, 334011, 333111, 332214, 331318, 330426, 329535, 328647, + 327762, 326878, 325997, 325119, 324243, 323369, 322498, 321629, 320762, 319898, 319036, + 318176, 317319, 316463, 315611, 314760, 313912, 313066, 312222, 311381, 310542, 309705, + 308871, 308038, 307208, 306380, 305555, 304731, 303910, 303091, 302275, 301460, 300648, + 299838, 299030, 298224, 297420, 296619, 295819, 295022, 294227, 293434, 292644, 291855, + 291069, 290284, 289502, 288722, 287944, 287168, 286394, 285622, 284853, 284085, 283320, + 282556, 281795, 281035, 280278, 279523, 278770, 278018, 277269, 276522, 275777, 275034, + 274293, 273553, 272816, 272081, 271348, 270617, 269888, 269160, 268435, 267712, 266990, + 266271, 265553, 264838, 264124, 263412, 262702, 261994, 261289, 260584, 259882, 259182, + 258483, 257787, 257092, 256399, 255709, 255020, 254332, 253647, 252963, 252282, 251602, + 250924, 250248, 249573, 248901, 248230, 247561, 246894, 246229, 245565, 244904, 244244, + 243586, 242929, 242275, 241622, 240971, 240321, 239674, 239028, 238384, 237741, 237101, + 236462, 235825, 235189, 234555, 233923, 233293, 232664, 232037, 231412, 230788, 230166, + 229546, 228928, 228311, 227696, 227082, 226470, 225860, 225251, 224644, 224039, 223435, + 222833, 222233, 221634, 221036, 220441, 219847, 219254, 218664, 218074, 217487, 216901, + 216316, 215733, 215152, 214572, 213994, 213417, 212842, 212269, 211697, 211126, 210557, + 209990, 209424, 208860, 208297, 207735, 207176, 206617, 206061, 205505, 204952, 204399, + 203849, 203299, 202751, 202205, 201660, 201117, 200575, 200034, 199495, 198958, 198422, + 197887, 197354, 196822, 196291, 195762, 195235, 194709, 194184, 193661, 193139, 192619, + 192100, 191582, 191066, 190551, 190037, 189525, 189014, 188505, 187997, 187491, 186985, + 186481, 185979, 185478, 184978, 184479, 183982, 183487, 182992, 182499, 182007, 181517, + 181028, 180540, 180053, 179568, 179084, 178602, 178120, 177640, 177162, 176684, 176208, + 175733, 175260, 174788, 174317, 173847, 173378, 172911, 172445, 171981, 171517, 171055, + 170594, 170134, 169676, 169219, 168763, 168308, 167854, 167402, 166951, 166501, 166052, + 165605, 165159, 164713, 164270, 163827, 163386, 162945, 162506, 162068, 161632, 161196, + 160762, 160328, 159896, 159465, 159036, 158607, 158180, 157754, 157328, 156904, 156482, + 156060, 155639, 155220, 154802, 154385, 153969, 153554, 153140, 152727, 152316, 151905, + 151496, 151088, 150681, 150275, 149870, 149466, 149063, 148661, 148261, 147861, 147463, + 147065, 146669, 146274, 145880, 145487, 145094, 144703, 144314, 143925, 143537, 143150, + 142764, 142380, 141996, 141613, 141232, 140851, 140472, 140093, 139715, 139339, 138964, + 138589, 138216, 137843, 137472, 137101, 136732, 136363, 135996, 135629, 135264, 134899, + 134536, 134173, 133812, 133451, 133092, 132733, 132375, 132019, 131663, 131308, 130954, + 130601, 130249, 129898, 129548, 129199, 128851, 128504, 128158, 127812, 127468, 127124, + 126782, 126440, 126099, 125760, 125421, 125083, 124746, 124410, 124074, 123740, 123407, + 123074, 122742, 122412, 122082, 121753, 121425, 121097, 120771, 120446, 120121, 119797, + 119475, 119153, 118832, 118511, 118192, 117873, 117556, 117239, 116923, 116608, 116294, + 115980, 115668, 115356, 115045, 114735, 114426, 114118, 113810, 113504, 113198, 112893, + 112589, 112285, 111983, 111681, 111380, 111080, 110780, 110482, 110184, 109887, 109591, + 109296, 109001, 108708, 108415, 108122, 107831, 107541, 107251, 106962, 106674, 106386, + 106099, 105813, 105528, 105244, 104960, 104678, 104395, 104114, 103834, 103554, 103275, + 102996, 102719, 102442, 102166, 101891, 101616, 101342, 101069, 100797, 100525, 100254, + 99984, 99715, 99446, 99178, 98911, 98644, 98378, 98113, 97849, 97585, 97322, + 97060, 96799, 96538, 96278, 96018, 95759, 95501, 95244, 94987, 94731, 94476, + 94222, 93968, 93714, 93462, 93210, 92959, 92708, 92459, 92209, 91961, 91713, + 91466, 91219, 90974, 90729, 90484, 90240, 89997, 89754, 89513, 89271, 89031, + 88791, 88552, 88313, 88075, 87838, 87601, 87365, 87130, 86895, 86661, 86427, + 86194, 85962, 85730, 85499, 85269, 85039, 84810, 84581, 84353, 84126, 83899, + 83673, 83448, 83223, 82999, 82775, 82552, 82330, 82108, 81886, 81666, 81446, + 81226, 81007, 80789, 80571, 80354, 80138, 79922, 79706, 79492, 79277, 79064, + 78851, 78638, 78426, 78215, 78004, 77794, 77584, 77375, 77167, 76959, 76752, + 76545, 76338, 76133, 75928, 75723, 75519, 75315, 75112, 74910, 74708, 74507, + 74306, 74106, 73906, 73707, 73508, 73310, 73113, 72916, 72719, 72523, 72328, + 72133, 71939, 71745, 71551, 71359, 71166, 70975, 70783, 70593, 70402, 70213, + 70023, 69835, 69646, 69459, 69272, 69085, 68899, 68713, 68528, 68343, 68159, + 67975, 67792, 67610, 67427, 67246, 67065, 66884, 66704, 66524, 66345, 66166, + 65987, 65810, 65632, 65455, 65279, 65103, 64928, 64753, 64578, 64404, 64231, + 64058, 63885, 63713, 63541, 63370, 63199, 63029, 62859, 62690, 62521, 62352, + 62184, 62017, 61850, 61683, 61517, 61351, 61186, 61021, 60856, 60692, 60529, + 60366, 60203, 60041, 59879, 59718, 59557, 59396, 59236, 59076, 58917, 58758, + 58600, 58442, 58285, 58128, 57971, 57815, 57659, 57504, 57349, 57194, 57040, + 56886, 56733, 56580, 56428, 56276, 56124, 55973, 55822, 55671, 55521, 55372, + 55223, 55074, 54925, 54777, 54630, 54483, 54336, 54189, 54043, 53898, 53752, + 53608, 53463, 53319, 53175, 53032, 52889, 52747, 52605, 52463, 52321, 52180, + 52040, 51900, 51760, 51620, 51481, 51342, 51204, 51066, 50928, 50791, 50654, + 50518, 50382, 50246, 50111, 49976, 49841, 49707, 49573, 49439, 49306, 49173, + 49040, 48908, 48776, 48645, 48514, 48383, 48253, 48123, 47993, 47864, 47735, + 47606, 47478, 47350, 47222, 47095, 46968, 46842, 46715, 46590, 46464, 46339, + 46214, 46089, 45965, 45841, 45718, 45595, 45472, 45349, 45227, 45105, 44984, + 44862, 44741, 44621, 44501, 44381, 44261, 44142, 44023, 43904, 43786, 43668, + 43550, 43433, 43316, 43199, 43083, 42967, 42851, 42735, 42620, 42505, 42391, + 42277, 42163, 42049, 41936, 41823, 41710, 41598, 41486, 41374, 41262, 41151, + 41040, 40930, 40819, 40709, 40600, 40490, 40381, 40272, 40164, 40056, 39948, + 39840, 39733, 39626, 39519, 39412, 39306, 39200, 39094, 38989, 38884, 38779, + 38675, 38571, 38467, 38363, 38260, 38157, 38054, 37951, 37849, 37747, 37645, + 37544, 37443, 37342, 37241, 37141, 37041, 36941, 36841, 36742, 36643, 36544, + 36446, 36347, 36250, 36152, 36054, 35957, 35860, 35764, 35667, 35571, 35475, + 35380, 35284, 35189, 35095, 35000, 34906, 34812, 34718, 34624, 34531, 34438, + 34345, 34253, 34160, 34068, 33976, 33885 +}; + +static const short sindb_coeff[] = { + 2401, 2144, 1994, 1887, 1804, 1737, 1680, 1630, 1587, 1548, 1512, 1480, 1450, + 1423, 1397, 1373, 1351, 1330, 1310, 1291, 1273, 1255, 1239, 1223, 1208, 1194, + 1180, 1166, 1153, 1141, 1128, 1117, 1105, 1094, 1084, 1073, 1063, 1053, 1043, + 1034, 1025, 1016, 1007, 999, 990, 982, 974, 967, 959, 952, 944, 937, + 930, 923, 916, 910, 903, 897, 890, 884, 878, 872, 866, 860, 855, + 849, 843, 838, 832, 827, 822, 817, 812, 807, 802, 797, 792, 787, + 783, 778, 773, 769, 764, 760, 756, 751, 747, 743, 739, 734, 730, + 726, 722, 718, 715, 711, 707, 703, 699, 696, 692, 688, 685, 681, + 678, 674, 671, 667, 664, 661, 657, 654, 651, 648, 644, 641, 638, + 635, 632, 629, 626, 623, 620, 617, 614, 611, 608, 605, 602, 599, + 597, 594, 591, 588, 586, 583, 580, 578, 575, 572, 570, 567, 565, + 562, 560, 557, 555, 552, 550, 547, 545, 542, 540, 538, 535, 533, + 531, 528, 526, 524, 522, 519, 517, 515, 513, 510, 508, 506, 504, + 502, 500, 498, 495, 493, 491, 489, 487, 485, 483, 481, 479, 477, + 475, 473, 471, 469, 467, 465, 464, 462, 460, 458, 456, 454, 452, + 450, 449, 447, 445, 443, 441, 440, 438, 436, 434, 433, 431, 429, + 427, 426, 424, 422, 421, 419, 417, 416, 414, 412, 411, 409, 408, + 406, 404, 403, 401, 400, 398, 396, 395, 393, 392, 390, 389, 387, + 386, 384, 383, 381, 380, 378, 377, 375, 374, 372, 371, 370, 368, + 367, 365, 364, 362, 361, 360, 358, 357, 355, 354, 353, 351, 350, + 349, 347, 346, 345, 343, 342, 341, 339, 338, 337, 336, 334, 333, + 332, 330, 329, 328, 327, 325, 324, 323, 322, 320, 319, 318, 317, + 316, 314, 313, 312, 311, 310, 308, 307, 306, 305, 304, 303, 301, + 300, 299, 298, 297, 296, 295, 293, 292, 291, 290, 289, 288, 287, + 286, 285, 284, 282, 281, 280, 279, 278, 277, 276, 275, 274, 273, + 272, 271, 270, 269, 268, 267, 266, 265, 264, 263, 262, 261, 260, + 259, 258, 257, 256, 255, 254, 253, 252, 251, 250, 249, 248, 247, + 246, 245, 244, 243, 242, 241, 240, 240, 239, 238, 237, 236, 235, + 234, 233, 232, 231, 230, 230, 229, 228, 227, 226, 225, 224, 223, + 222, 222, 221, 220, 219, 218, 217, 216, 216, 215, 214, 213, 212, + 211, 211, 210, 209, 208, 207, 206, 206, 205, 204, 203, 202, 202, + 201, 200, 199, 198, 198, 197, 196, 195, 195, 194, 193, 192, 191, + 191, 190, 189, 188, 188, 187, 186, 185, 185, 184, 183, 182, 182, + 181, 180, 180, 179, 178, 177, 177, 176, 175, 174, 174, 173, 172, + 172, 171, 170, 170, 169, 168, 167, 167, 166, 165, 165, 164, 163, + 163, 162, 161, 161, 160, 159, 159, 158, 157, 157, 156, 155, 155, + 154, 153, 153, 152, 151, 151, 150, 150, 149, 148, 148, 147, 146, + 146, 145, 145, 144, 143, 143, 142, 141, 141, 140, 140, 139, 138, + 138, 137, 137, 136, 135, 135, 134, 134, 133, 133, 132, 131, 131, + 130, 130, 129, 129, 128, 127, 127, 126, 126, 125, 125, 124, 123, + 123, 122, 122, 121, 121, 120, 120, 119, 119, 118, 117, 117, 116, + 116, 115, 115, 114, 114, 113, 113, 112, 112, 111, 111, 110, 110, + 109, 109, 108, 108, 107, 107, 106, 106, 105, 105, 104, 104, 103, + 103, 102, 102, 101, 101, 100, 100, 99, 99, 98, 98, 97, 97, + 96, 96, 95, 95, 94, 94, 94, 93, 93, 92, 92, 91, 91, + 90, 90, 89, 89, 89, 88, 88, 87, 87, 86, 86, 85, 85, + 85, 84, 84, 83, 83, 82, 82, 82, 81, 81, 80, 80, 79, + 79, 79, 78, 78, 77, 77, 77, 76, 76, 75, 75, 75, 74, + 74, 73, 73, 73, 72, 72, 71, 71, 71, 70, 70, 69, 69, + 69, 68, 68, 68, 67, 67, 66, 66, 66, 65, 65, 65, 64, + 64, 63, 63, 63, 62, 62, 62, 61, 61, 61, 60, 60, 59, + 59, 59, 58, 58, 58, 57, 57, 57, 56, 56, 56, 55, 55, + 55, 54, 54, 54, 53, 53, 53, 52, 52, 52, 51, 51, 51, + 50, 50, 50, 49, 49, 49, 49, 48, 48, 48, 47, 47, 47, + 46, 46, 46, 45, 45, 45, 45, 44, 44, 44, 43, 43, 43, + 43, 42, 42, 42, 41, 41, 41, 40, 40, 40, 40, 39, 39, + 39, 39, 38, 38, 38, 37, 37, 37, 37, 36, 36, 36, 36, + 35, 35, 35, 35, 34, 34, 34, 34, 33, 33, 33, 32, 32, + 32, 32, 31, 31, 31, 31, 31, 30, 30, 30, 30, 29, 29, + 29, 29, 28, 28, 28, 28, 27, 27, 27, 27, 27, 26, 26, + 26, 26, 25, 25, 25, 25, 25, 24, 24, 24, 24, 23, 23, + 23, 23, 23, 22, 22, 22, 22, 22, 21, 21, 21, 21, 21, + 20, 20, 20, 20, 20, 19, 19, 19, 19, 19, 19, 18, 18, + 18, 18, 18, 17, 17, 17, 17, 17, 17, 16, 16, 16, 16, + 16, 15, 15, 15, 15, 15, 15, 14, 14, 14, 14, 14, 14, + 13, 13, 13, 13, 13, 13, 13, 12, 12, 12, 12, 12, 12, + 11, 11, 11, 11, 11, 11, 11, 10, 10, 10, 10, 10, 10, + 10, 10, 9, 9, 9, 9, 9, 9, 9, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 7, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + + +static const short lfo_freq_coeff[] = { + 0, 3, 6, 9, 12, 15, 18, 21, 25, 28, 31, 34, 37, + 40, 43, 46, 50, 53, 56, 59, 62, 65, 68, 71, 74, 78, + 81, 84, 87, 90, 93, 96, 99, 102, 105, 108, 111, 115, 118, + 121, 124, 127, 130, 133, 136, 139, 142, 145, 148, 151, 154, 157, + 160, 163, 166, 169, 172, 175, 178, 180, 183, 186, 189, 192, 195, + 198, 201, 204, 207, 209, 212, 215, 218, 221, 224, 226, 229, 232, + 235, 238, 240, 243, 246, 249, 251, 254, 257, 260, 262, 265, 268, + 270, 273, 276, 278, 281, 283, 286, 289, 291, 294, 296, 299, 301, + 304, 306, 309, 311, 314, 316, 319, 321, 324, 326, 328, 331, 333, + 336, 338, 340, 343, 345, 347, 350, 352, 354, 356, 359, 361, 363, + 365, 367, 370, 372, 374, 376, 378, 380, 382, 384, 386, 388, 391, + 393, 395, 396, 398, 400, 402, 404, 406, 408, 410, 412, 414, 415, + 417, 419, 421, 423, 424, 426, 428, 430, 431, 433, 435, 436, 438, + 439, 441, 443, 444, 446, 447, 449, 450, 452, 453, 455, 456, 457, + 459, 460, 461, 463, 464, 465, 467, 468, 469, 470, 472, 473, 474, + 475, 476, 477, 478, 480, 481, 482, 483, 484, 485, 486, 487, 488, + 488, 489, 490, 491, 492, 493, 494, 494, 495, 496, 497, 497, 498, + 499, 499, 500, 501, 501, 502, 502, 503, 504, 504, 504, 505, 505, + 506, 506, 507, 507, 507, 508, 508, 508, 509, 509, 509, 509, 510, + 510, 510, 510, 510, 510, 510, 510, 510, 510, 511, 510, 510, 510, + 510, 510, 510, 510, 510, 510, 510, 509, 509, 509, 509, 508, 508, + 508, 507, 507, 507, 506, 506, 505, 505, 504, 504, 504, 503, 502, + 502, 501, 501, 500, 499, 499, 498, 497, 497, 496, 495, 494, 494, + 493, 492, 491, 490, 489, 488, 488, 487, 486, 485, 484, 483, 482, + 481, 480, 478, 477, 476, 475, 474, 473, 472, 470, 469, 468, 467, + 465, 464, 463, 461, 460, 459, 457, 456, 455, 453, 452, 450, 449, + 447, 446, 444, 443, 441, 439, 438, 436, 435, 433, 431, 430, 428, + 426, 424, 423, 421, 419, 417, 415, 414, 412, 410, 408, 406, 404, + 402, 400, 398, 396, 395, 393, 391, 388, 386, 384, 382, 380, 378, + 376, 374, 372, 370, 367, 365, 363, 361, 359, 356, 354, 352, 350, + 347, 345, 343, 340, 338, 336, 333, 331, 328, 326, 324, 321, 319, + 316, 314, 311, 309, 306, 304, 301, 299, 296, 294, 291, 289, 286, + 283, 281, 278, 276, 273, 270, 268, 265, 262, 260, 257, 254, 251, + 249, 246, 243, 240, 238, 235, 232, 229, 226, 224, 221, 218, 215, + 212, 209, 207, 204, 201, 198, 195, 192, 189, 186, 183, 180, 178, + 175, 172, 169, 166, 163, 160, 157, 154, 151, 148, 145, 142, 139, + 136, 133, 130, 127, 124, 121, 118, 115, 111, 108, 105, 102, 99, + 96, 93, 90, 87, 84, 81, 78, 74, 71, 68, 65, 62, 59, + 56, 53, 50, 46, 43, 40, 37, 34, 31, 28, 25, 21, 18, + 15, 12, 9, 6, 3, 0, -3, -6, -9, -12, -15, -18, -21, + -25, -28, -31, -34, -37, -40, -43, -46, -50, -53, -56, -59, -62, + -65, -68, -71, -74, -78, -81, -84, -87, -90, -93, -96, -99, -102, + -105, -108, -111, -115, -118, -121, -124, -127, -130, -133, -136, -139, -142, + -145, -148, -151, -154, -157, -160, -163, -166, -169, -172, -175, -178, -180, + -183, -186, -189, -192, -195, -198, -201, -204, -207, -209, -212, -215, -218, + -221, -224, -226, -229, -232, -235, -238, -240, -243, -246, -249, -251, -254, + -257, -260, -262, -265, -268, -270, -273, -276, -278, -281, -283, -286, -289, + -291, -294, -296, -299, -301, -304, -306, -309, -311, -314, -316, -319, -321, + -324, -326, -328, -331, -333, -336, -338, -340, -343, -345, -347, -350, -352, + -354, -356, -359, -361, -363, -365, -367, -370, -372, -374, -376, -378, -380, + -382, -384, -386, -388, -391, -393, -395, -396, -398, -400, -402, -404, -406, + -408, -410, -412, -414, -415, -417, -419, -421, -423, -424, -426, -428, -430, + -431, -433, -435, -436, -438, -439, -441, -443, -444, -446, -447, -449, -450, + -452, -453, -455, -456, -457, -459, -460, -461, -463, -464, -465, -467, -468, + -469, -470, -472, -473, -474, -475, -476, -477, -478, -480, -481, -482, -483, + -484, -485, -486, -487, -488, -488, -489, -490, -491, -492, -493, -494, -494, + -495, -496, -497, -497, -498, -499, -499, -500, -501, -501, -502, -502, -503, + -504, -504, -504, -505, -505, -506, -506, -507, -507, -507, -508, -508, -508, + -509, -509, -509, -509, -510, -510, -510, -510, -510, -510, -510, -510, -510, + -510, -511, -510, -510, -510, -510, -510, -510, -510, -510, -510, -510, -509, + -509, -509, -509, -508, -508, -508, -507, -507, -507, -506, -506, -505, -505, + -504, -504, -504, -503, -502, -502, -501, -501, -500, -499, -499, -498, -497, + -497, -496, -495, -494, -494, -493, -492, -491, -490, -489, -488, -488, -487, + -486, -485, -484, -483, -482, -481, -480, -478, -477, -476, -475, -474, -473, + -472, -470, -469, -468, -467, -465, -464, -463, -461, -460, -459, -457, -456, + -455, -453, -452, -450, -449, -447, -446, -444, -443, -441, -439, -438, -436, + -435, -433, -431, -430, -428, -426, -424, -423, -421, -419, -417, -415, -414, + -412, -410, -408, -406, -404, -402, -400, -398, -396, -395, -393, -391, -388, + -386, -384, -382, -380, -378, -376, -374, -372, -370, -367, -365, -363, -361, + -359, -356, -354, -352, -350, -347, -345, -343, -340, -338, -336, -333, -331, + -328, -326, -324, -321, -319, -316, -314, -311, -309, -306, -304, -301, -299, + -296, -294, -291, -289, -286, -283, -281, -278, -276, -273, -270, -268, -265, + -262, -260, -257, -254, -251, -249, -246, -243, -240, -238, -235, -232, -229, + -226, -224, -221, -218, -215, -212, -209, -207, -204, -201, -198, -195, -192, + -189, -186, -183, -180, -178, -175, -172, -169, -166, -163, -160, -157, -154, + -151, -148, -145, -142, -139, -136, -133, -130, -127, -124, -121, -118, -115, + -111, -108, -105, -102, -99, -96, -93, -90, -87, -84, -81, -78, -74, + -71, -68, -65, -62, -59, -56, -53, -50, -46, -43, -40, -37, -34, + -31, -28, -25, -21, -18, -15, -12, -9, -6, -3 +}; + +static const short lfo_env_coeff[] = { + 251, 253, 254, 256, 257, 259, 260, 262, 264, 265, 267, 268, 270, + 271, 273, 274, 276, 277, 279, 281, 282, 284, 285, 287, 288, 290, + 291, 293, 294, 296, 297, 299, 300, 302, 303, 305, 306, 308, 309, + 311, 312, 314, 315, 317, 318, 320, 321, 323, 324, 326, 327, 329, + 330, 332, 333, 335, 336, 337, 339, 340, 342, 343, 345, 346, 348, + 349, 350, 352, 353, 355, 356, 357, 359, 360, 362, 363, 364, 366, + 367, 369, 370, 371, 373, 374, 375, 377, 378, 379, 381, 382, 383, + 385, 386, 387, 389, 390, 391, 392, 394, 395, 396, 397, 399, 400, + 401, 402, 404, 405, 406, 407, 409, 410, 411, 412, 413, 414, 416, + 417, 418, 419, 420, 421, 423, 424, 425, 426, 427, 428, 429, 430, + 431, 432, 434, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, + 445, 446, 447, 448, 449, 450, 451, 452, 453, 453, 454, 455, 456, + 457, 458, 459, 460, 461, 461, 462, 463, 464, 465, 466, 466, 467, + 468, 469, 469, 470, 471, 472, 473, 473, 474, 475, 475, 476, 477, + 477, 478, 479, 479, 480, 481, 481, 482, 483, 483, 484, 484, 485, + 486, 486, 487, 487, 488, 488, 489, 489, 490, 490, 491, 491, 492, + 492, 493, 493, 493, 494, 494, 495, 495, 495, 496, 496, 497, 497, + 497, 498, 498, 498, 498, 499, 499, 499, 500, 500, 500, 500, 500, + 501, 501, 501, 501, 501, 502, 502, 502, 502, 502, 502, 502, 502, + 503, 503, 503, 503, 503, 503, 503, 503, 503, 503, 503, 503, 503, + 503, 503, 503, 503, 503, 503, 502, 502, 502, 502, 502, 502, 502, + 502, 501, 501, 501, 501, 501, 500, 500, 500, 500, 500, 499, 499, + 499, 498, 498, 498, 498, 497, 497, 497, 496, 496, 495, 495, 495, + 494, 494, 493, 493, 493, 492, 492, 491, 491, 490, 490, 489, 489, + 488, 488, 487, 487, 486, 486, 485, 484, 484, 483, 483, 482, 481, + 481, 480, 479, 479, 478, 477, 477, 476, 475, 475, 474, 473, 473, + 472, 471, 470, 469, 469, 468, 467, 466, 466, 465, 464, 463, 462, + 461, 461, 460, 459, 458, 457, 456, 455, 454, 453, 453, 452, 451, + 450, 449, 448, 447, 446, 445, 444, 443, 442, 441, 440, 439, 438, + 437, 436, 435, 434, 432, 431, 430, 429, 428, 427, 426, 425, 424, + 423, 421, 420, 419, 418, 417, 416, 414, 413, 412, 411, 410, 409, + 407, 406, 405, 404, 402, 401, 400, 399, 397, 396, 395, 394, 392, + 391, 390, 389, 387, 386, 385, 383, 382, 381, 379, 378, 377, 375, + 374, 373, 371, 370, 369, 367, 366, 364, 363, 362, 360, 359, 357, + 356, 355, 353, 352, 350, 349, 348, 346, 345, 343, 342, 340, 339, + 337, 336, 335, 333, 332, 330, 329, 327, 326, 324, 323, 321, 320, + 318, 317, 315, 314, 312, 311, 309, 308, 306, 305, 303, 302, 300, + 299, 297, 296, 294, 293, 291, 290, 288, 287, 285, 284, 282, 281, + 279, 277, 276, 274, 273, 271, 270, 268, 267, 265, 264, 262, 260, + 259, 257, 256, 254, 253, 251, 250, 248, 247, 245, 244, 242, 240, + 239, 237, 236, 234, 233, 231, 230, 228, 227, 225, 223, 222, 220, + 219, 217, 216, 214, 213, 211, 210, 208, 207, 205, 204, 202, 201, + 199, 198, 196, 195, 193, 192, 190, 189, 187, 186, 184, 183, 181, + 180, 178, 177, 175, 174, 172, 171, 169, 168, 166, 165, 164, 162, + 161, 159, 158, 156, 155, 153, 152, 151, 149, 148, 146, 145, 144, + 142, 141, 139, 138, 137, 135, 134, 133, 131, 130, 129, 127, 126, + 124, 123, 122, 120, 119, 118, 117, 115, 114, 113, 111, 110, 109, + 108, 106, 105, 104, 103, 101, 100, 99, 98, 96, 95, 94, 93, + 92, 90, 89, 88, 87, 86, 84, 83, 82, 81, 80, 79, 78, + 77, 75, 74, 73, 72, 71, 70, 69, 68, 67, 66, 65, 64, + 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, + 50, 49, 48, 47, 46, 45, 45, 44, 43, 42, 41, 40, 39, + 39, 38, 37, 36, 35, 35, 34, 33, 32, 31, 31, 30, 29, + 29, 28, 27, 26, 26, 25, 24, 24, 23, 22, 22, 21, 20, + 20, 19, 19, 18, 17, 17, 16, 16, 15, 15, 14, 14, 13, + 13, 12, 12, 11, 11, 10, 10, 9, 9, 9, 8, 8, 7, + 7, 7, 6, 6, 6, 5, 5, 5, 4, 4, 4, 3, 3, + 3, 3, 2, 2, 2, 2, 2, 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, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, + 2, 3, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, + 6, 7, 7, 7, 8, 8, 9, 9, 9, 10, 10, 11, 11, + 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, + 19, 19, 20, 20, 21, 22, 22, 23, 24, 24, 25, 26, 26, + 27, 28, 29, 29, 30, 31, 31, 32, 33, 34, 35, 35, 36, + 37, 38, 39, 39, 40, 41, 42, 43, 44, 45, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, + 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, + 74, 75, 77, 78, 79, 80, 81, 82, 83, 84, 86, 87, 88, + 89, 90, 92, 93, 94, 95, 96, 98, 99, 100, 101, 103, 104, + 105, 106, 108, 109, 110, 111, 113, 114, 115, 117, 118, 119, 120, + 122, 123, 124, 126, 127, 129, 130, 131, 133, 134, 135, 137, 138, + 139, 141, 142, 144, 145, 146, 148, 149, 151, 152, 153, 155, 156, + 158, 159, 161, 162, 164, 165, 166, 168, 169, 171, 172, 174, 175, + 177, 178, 180, 181, 183, 184, 186, 187, 189, 190, 192, 193, 195, + 196, 198, 199, 201, 202, 204, 205, 207, 208, 210, 211, 213, 214, + 216, 217, 219, 220, 222, 223, 225, 227, 228, 230, 231, 233, 234, + 236, 237, 239, 240, 242, 244, 245, 247, 248, 250 +}; + +#endif diff --git a/apps/codecs/libgme/z80_cpu.h b/apps/codecs/libgme/z80_cpu.h index 15115b7e53..341119b6b1 100644 --- a/apps/codecs/libgme/z80_cpu.h +++ b/apps/codecs/libgme/z80_cpu.h @@ -1,116 +1,116 @@ -// Z80 CPU emulator - -// Game_Music_Emu 0.6-pre -#ifndef Z80_CPU_H -#define Z80_CPU_H - -#include "blargg_source.h" -#include "blargg_endian.h" - -typedef int cpu_time_t; -typedef int addr_t; - -enum { page_bits = 10 }; -enum { page_size = 1 << page_bits }; -enum { page_count = 0x10000 / page_size }; - -// Can read this far past end of memory -enum { cpu_padding = 0x100 }; - -// Can read this many bytes past end of a page -enum { page_padding = 4 }; - -#ifdef BLARGG_BIG_ENDIAN - struct regs_t { byte b,c, d,e, h,l, flags,a; }; -#else - struct regs_t { byte c,b, e,d, l,h, a,flags; }; -#endif -// BOOST_STATIC_ASSERT( sizeof (regs_t) == 8 ); - -struct pairs_t { uint16_t bc, de, hl, fa; }; - -// Registers are not updated until run() returns -struct registers_t { - uint16_t pc; - uint16_t sp; - uint16_t ix; - uint16_t iy; - union { - struct regs_t b; // b.b, b.c, b.d, b.e, b.h, b.l, b.flags, b.a - struct pairs_t w; // w.bc, w.de, w.hl. w.fa - }; - union { - struct regs_t b; - struct pairs_t w; - } alt; - byte iff1; - byte iff2; - byte r; - byte i; - byte im; -}; - -struct cpu_state_t { - byte const* read [page_count + 1]; - byte * write [page_count + 1]; - cpu_time_t base; - cpu_time_t time; -}; - -struct Z80_Cpu { - byte szpc [0x200]; - cpu_time_t end_time_; - - struct cpu_state_t* cpu_state; // points to cpu_state_ or a local copy within run() - struct cpu_state_t cpu_state_; - - struct registers_t r; -}; - -void Z80_init( struct Z80_Cpu* this ); - -// Clears registers and maps all pages to unmapped -void Z80_reset( struct Z80_Cpu* this, void* unmapped_write, void const* unmapped_read ); - -// TODO: split mapping out of CPU - -// Maps memory. Start and size must be multiple of page_size. -void Z80_map_mem( struct Z80_Cpu* this, addr_t addr, int size, void* write, void const* read ); - -// Time of beginning of next instruction -static inline cpu_time_t Z80_time( struct Z80_Cpu* this ) { return this->cpu_state->time + this->cpu_state->base; } - -// Alter current time -static inline void Z80_set_time( struct Z80_Cpu* this, cpu_time_t t ) { this->cpu_state->time = t - this->cpu_state->base; } -static inline void Z80_adjust_time( struct Z80_Cpu* this, int delta ) { this->cpu_state->time += delta; } - -#ifdef BLARGG_NONPORTABLE - #define Z80_CPU_OFFSET( addr ) (addr) -#else - #define Z80_CPU_OFFSET( addr ) ((addr) & (page_size - 1)) -#endif - -// Maps address to pointer to that byte -static inline byte* Z80_write( struct Z80_Cpu* this, addr_t addr ) -{ - return this->cpu_state->write [(unsigned) addr >> page_bits] + Z80_CPU_OFFSET( addr ); -} - -static inline byte const* Z80_read( struct Z80_Cpu* this, addr_t addr ) -{ - return this->cpu_state->read [(unsigned) addr >> page_bits] + Z80_CPU_OFFSET( addr ); -} - -static inline void Z80_map_mem_rw( struct Z80_Cpu* this, addr_t addr, int size, void* p ) -{ - Z80_map_mem( this, addr, size, p, p ); -} - -static inline void Z80_set_end_time( struct Z80_Cpu* this, cpu_time_t t ) -{ - cpu_time_t delta = this->cpu_state->base - t; - this->cpu_state->base = t; - this->cpu_state->time += delta; -} - -#endif +// Z80 CPU emulator + +// Game_Music_Emu 0.6-pre +#ifndef Z80_CPU_H +#define Z80_CPU_H + +#include "blargg_source.h" +#include "blargg_endian.h" + +typedef int cpu_time_t; +typedef int addr_t; + +enum { page_bits = 10 }; +enum { page_size = 1 << page_bits }; +enum { page_count = 0x10000 / page_size }; + +// Can read this far past end of memory +enum { cpu_padding = 0x100 }; + +// Can read this many bytes past end of a page +enum { page_padding = 4 }; + +#ifdef BLARGG_BIG_ENDIAN + struct regs_t { byte b,c, d,e, h,l, flags,a; }; +#else + struct regs_t { byte c,b, e,d, l,h, a,flags; }; +#endif +// BOOST_STATIC_ASSERT( sizeof (regs_t) == 8 ); + +struct pairs_t { uint16_t bc, de, hl, fa; }; + +// Registers are not updated until run() returns +struct registers_t { + uint16_t pc; + uint16_t sp; + uint16_t ix; + uint16_t iy; + union { + struct regs_t b; // b.b, b.c, b.d, b.e, b.h, b.l, b.flags, b.a + struct pairs_t w; // w.bc, w.de, w.hl. w.fa + }; + union { + struct regs_t b; + struct pairs_t w; + } alt; + byte iff1; + byte iff2; + byte r; + byte i; + byte im; +}; + +struct cpu_state_t { + byte const* read [page_count + 1]; + byte * write [page_count + 1]; + cpu_time_t base; + cpu_time_t time; +}; + +struct Z80_Cpu { + byte szpc [0x200]; + cpu_time_t end_time_; + + struct cpu_state_t* cpu_state; // points to cpu_state_ or a local copy within run() + struct cpu_state_t cpu_state_; + + struct registers_t r; +}; + +void Z80_init( struct Z80_Cpu* this ); + +// Clears registers and maps all pages to unmapped +void Z80_reset( struct Z80_Cpu* this, void* unmapped_write, void const* unmapped_read ); + +// TODO: split mapping out of CPU + +// Maps memory. Start and size must be multiple of page_size. +void Z80_map_mem( struct Z80_Cpu* this, addr_t addr, int size, void* write, void const* read ); + +// Time of beginning of next instruction +static inline cpu_time_t Z80_time( struct Z80_Cpu* this ) { return this->cpu_state->time + this->cpu_state->base; } + +// Alter current time +static inline void Z80_set_time( struct Z80_Cpu* this, cpu_time_t t ) { this->cpu_state->time = t - this->cpu_state->base; } +static inline void Z80_adjust_time( struct Z80_Cpu* this, int delta ) { this->cpu_state->time += delta; } + +#ifdef BLARGG_NONPORTABLE + #define Z80_CPU_OFFSET( addr ) (addr) +#else + #define Z80_CPU_OFFSET( addr ) ((addr) & (page_size - 1)) +#endif + +// Maps address to pointer to that byte +static inline byte* Z80_write( struct Z80_Cpu* this, addr_t addr ) +{ + return this->cpu_state->write [(unsigned) addr >> page_bits] + Z80_CPU_OFFSET( addr ); +} + +static inline byte const* Z80_read( struct Z80_Cpu* this, addr_t addr ) +{ + return this->cpu_state->read [(unsigned) addr >> page_bits] + Z80_CPU_OFFSET( addr ); +} + +static inline void Z80_map_mem_rw( struct Z80_Cpu* this, addr_t addr, int size, void* p ) +{ + Z80_map_mem( this, addr, size, p, p ); +} + +static inline void Z80_set_end_time( struct Z80_Cpu* this, cpu_time_t t ) +{ + cpu_time_t delta = this->cpu_state->base - t; + this->cpu_state->base = t; + this->cpu_state->time += delta; +} + +#endif diff --git a/apps/codecs/libgme/z80_cpu_run.h b/apps/codecs/libgme/z80_cpu_run.h index 18195ac92b..a453487bb0 100644 --- a/apps/codecs/libgme/z80_cpu_run.h +++ b/apps/codecs/libgme/z80_cpu_run.h @@ -1,1696 +1,1696 @@ -// Game_Music_Emu 0.6-pre. http://www.slack.net/~ant/ - -// Last validated with zexall 2009.12.05. -// Doesn't implement the R register or immediate interrupt after EI. -// Address wrap-around isn't completely correct, but is prevented from crashing emulator. -// 16-bit memory accesses are made directly to mapped memory, instead of using macro. - -#if 0 -/* Define these macros in the source file before #including this file. -- Parameters might be expressions, so they are best evaluated only once, -though they NEVER have side-effects, so multiple evaluation is OK. -- Output parameters might be a multiple-assignment expression like "a=x", -so they must NOT be parenthesized. -- Except where noted, time() and related functions will NOT work -correctly inside a macro. TIME() is always correct, and between FLUSH_TIME() and -CACHE_TIME() the normal time changing functions can be used. -- Macros "returning" void may use a {} statement block. */ - - // 0 <= addr <= 0xFFFF + 0x100 - // Optional; default uses whatever was set with map_mem() - int READ_MEM( addr_t ); - void WRITE_MEM( addr_t, int data ); - - // 0 <= port <= 0xFFFF (apparently upper 8 bits are output by hardware) - void OUT_PORT( int port, int data ); - int IN_PORT int port ); - - // Reference to Z80_Cpu object used for emulation - #define CPU cpu - -// The following can be used within macros: - - // Current time - time_t TIME(); - - // Allows use of time functions - void FLUSH_TIME(); - - // Must be used before end of macro if FLUSH_TIME() was used earlier - void CACHE_TIME(); - -// Configuration (optional; commented behavior if defined) - - // Optimizes as if map_mem( 0, 0x10000, FLAT_MEM, FLAT_MEM ) is always in effect - #define FLAT_MEM my_mem_array - - // If RST 7 ($FF) is encountered and PC = IDLE_ADDR, stops execution - #define IDLE_ADDR 0x1234 - - // Expanded just before beginning of code, to help debugger - #define CPU_BEGIN void my_run_cpu() { - -#endif - -/* Copyright (C) 2006-2008 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. This -module 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 Lesser General Public License for more -details. You should have received a copy of the GNU Lesser General Public -License along with this module; if not, write to the Free Software Foundation, -Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ - -#ifdef CPU_BEGIN - CPU_BEGIN -#endif - -#define R cpu->r - -// flags, named with hex value for clarity -int const S80 = 0x80; -int const Z40 = 0x40; -int const F20 = 0x20; -int const H10 = 0x10; -int const F08 = 0x08; -int const V04 = 0x04; -int const P04 = 0x04; -int const N02 = 0x02; -int const C01 = 0x01; - -#define SZ28P( n ) cpu->szpc [n] -#define SZ28PC( n ) cpu->szpc [n] -#define SZ28C( n ) (cpu->szpc [n] & ~P04) -#define SZ28( n ) SZ28C( n ) - -#define SET_R( n ) (void) (R.r = n) -#define GET_R() (R.r) - -// Time -#define TIME() (s_time + s.base) -#define FLUSH_TIME() {s.time = s_time;} -#define CACHE_TIME() {s_time = s.time;} - -// Memory -#define RW_MEM( addr, rw ) RW_PAGE( addr, rw ) [RW_OFFSET( addr )] -#define READ_CODE( addr ) RW_MEM( addr, read ) - -#ifdef FLAT_MEM - #define RW_PAGE( addr, rw ) FLAT_MEM - #define RW_OFFSET( addr ) (addr) - #define INSTR( off, addr ) READ_CODE( addr ) -#else - #define RW_PAGE( addr, rw ) s.rw [(unsigned) (addr) >> page_bits] - #define RW_OFFSET( addr ) Z80_CPU_OFFSET( addr ) - #define INSTR( off, addr ) instr [off] -#endif - -#ifndef READ_MEM - #define READ_MEM( addr ) RW_MEM( addr, read ) -#endif - -#ifndef WRITE_MEM - #define WRITE_MEM( addr, data ) (RW_MEM( addr, write ) = data) -#endif - -#define READ_WORD( addr ) GET_LE16( &RW_MEM( addr, read ) ) -#define WRITE_WORD( addr, data ) SET_LE16( &RW_MEM( addr, write ), data ) - -// Truncation -#define BYTE( n ) ((uint8_t ) (n)) /* (unsigned) n & 0xFF */ -#define SBYTE( n ) ((int8_t ) (n)) /* (BYTE( n ) ^ 0x80) - 0x80 */ -#define WORD( n ) ((uint16_t) (n)) /* (unsigned) n & 0xFFFF */ - -// Misc -#define CASE5( a, b, c, d, e ) case 0x##a:case 0x##b:case 0x##c:case 0x##d:case 0x##e -#define CASE6( a, b, c, d, e, f ) CASE5( a, b, c, d, e ): case 0x##f -#define CASE7( a, b, c, d, e, f, g ) CASE6( a, b, c, d, e, f ): case 0x##g -#define CASE8( a, b, c, d, e, f, g, h ) CASE7( a, b, c, d, e, f, g ): case 0x##h - -#ifdef BLARGG_BIG_ENDIAN - #define R8( n, offset ) ((r.r8_ - offset) [n]) -#elif BLARGG_LITTLE_ENDIAN - #define R8( n, offset ) ((r.r8_ - offset) [(n) ^ 1]) -#else - #error "Byte order of CPU must be known" -#endif - -#define R16( n, shift, offset ) (r.r16_ [((unsigned) (n) >> shift) - (offset >> shift)]) - -#define EX( x, y ) \ - {\ - int temp = x;\ - x = y;\ - y = temp;\ - } - -#define EXX( name ) \ - EX( R.alt.name, r.name ) - -bool warning = false; -{ - struct cpu_state_t s; - #ifdef FLAT_MEM - s.base = cpu->cpu_state_.base; - #else - s = cpu->cpu_state_; - #endif - cpu->cpu_state = &s; - - - union r_t { - struct regs_t b; - struct pairs_t w; - byte r8_ [8]; // indexed - uint16_t r16_ [4]; - } r; - r.b = R.b; - - cpu_time_t s_time = cpu->cpu_state_.time; - int pc = R.pc; - int sp = R.sp; - int ix = R.ix; // TODO: keep in memory for direct access? - int iy = R.iy; - int flags = R.b.flags; - - //goto loop; // confuses optimizer - s_time += 7; - pc -= 2; - -call_not_taken: - s_time -= 7; -jp_not_taken: - pc += 2; -loop: - - check( (unsigned) pc < 0x10000 + 1 ); // +1 so emulator can catch wrap-around - check( (unsigned) sp < 0x10000 ); - check( (unsigned) flags < 0x100 ); - check( (unsigned) ix < 0x10000 ); - check( (unsigned) iy < 0x10000 ); - - byte const* instr = RW_PAGE( pc, read ); - - int opcode; - - if ( RW_OFFSET( ~0 ) == ~0 ) - { - opcode = instr [RW_OFFSET( pc )]; - pc++; - instr += RW_OFFSET( pc ); - } - else - { - instr += RW_OFFSET( pc ); - opcode = *instr++; - pc++; - } - - static byte const clock_table [256 * 2] = { - // 0 1 2 3 4 5 6 7 8 9 A B C D E F - 4,10, 7, 6, 4, 4, 7, 4, 4,11, 7, 6, 4, 4, 7, 4, // 0 - 8,10, 7, 6, 4, 4, 7, 4,12,11, 7, 6, 4, 4, 7, 4, // 1 - 7,10,16, 6, 4, 4, 7, 4, 7,11,16, 6, 4, 4, 7, 4, // 2 - 7,10,13, 6,11,11,10, 4, 7,11,13, 6, 4, 4, 7, 4, // 3 - 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // 4 - 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // 5 - 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // 6 - 7, 7, 7, 7, 7, 7, 4, 7, 4, 4, 4, 4, 4, 4, 7, 4, // 7 - 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // 8 - 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // 9 - 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // A - 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // B - 11,10,10,10,17,11, 7,11,11,10,10, 8,17,17, 7,11, // C - 11,10,10,11,17,11, 7,11,11, 4,10,11,17, 8, 7,11, // D - 11,10,10,19,17,11, 7,11,11, 4,10, 4,17, 8, 7,11, // E - 11,10,10, 4,17,11, 7,11,11, 6,10, 4,17, 8, 7,11, // F - - // high four bits are $ED time - 8, low four bits are $DD/$FD time - 8 - //0 1 2 3 4 5 6 7 8 9 A B C D E F - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x06,0x0C,0x02,0x00,0x00,0x03,0x00,0x00,0x07,0x0C,0x02,0x00,0x00,0x03,0x00, - 0x00,0x00,0x00,0x00,0x0F,0x0F,0x0B,0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00, - 0x40,0x40,0x70,0xC0,0x00,0x60,0x0B,0x10,0x40,0x40,0x70,0xC0,0x00,0x60,0x0B,0x10, - 0x40,0x40,0x70,0xC0,0x00,0x60,0x0B,0x10,0x40,0x40,0x70,0xC0,0x00,0x60,0x0B,0x10, - 0x40,0x40,0x70,0xC0,0x00,0x60,0x0B,0xA0,0x40,0x40,0x70,0xC0,0x00,0x60,0x0B,0xA0, - 0x4B,0x4B,0x7B,0xCB,0x0B,0x6B,0x00,0x0B,0x40,0x40,0x70,0xC0,0x00,0x60,0x0B,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x0B,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0B,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x0B,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0B,0x00, - 0x80,0x80,0x80,0x80,0x00,0x00,0x0B,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x0B,0x00, - 0xD0,0xD0,0xD0,0xD0,0x00,0x00,0x0B,0x00,0xD0,0xD0,0xD0,0xD0,0x00,0x00,0x0B,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x06,0x00,0x0F,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00, - }; - - if ( s_time >= 0 ) - goto out_of_time; - s_time += clock_table [opcode]; - - #ifdef Z80_CPU_LOG_H - //log_opcode( opcode, READ_CODE( pc ) ); - z80_cpu_log( "log.txt", pc - 1, opcode, READ_CODE( pc ), - READ_CODE( pc + 1 ), READ_CODE( pc + 2 ) ); - z80_log_regs( r.b.a, r.w.bc, r.w.de, r.w.hl, sp, ix, iy ); - #endif - -#define GET_ADDR() GET_LE16( &INSTR( 0, pc ) ) - - int data; - data = INSTR( 0, pc ); - - switch ( opcode ) - { -// Common - - case 0x00: // NOP - CASE7( 40, 49, 52, 5B, 64, 6D, 7F ): // LD B,B etc. - goto loop; - - case 0x08:{// EX AF,AF' - EXX( b.a ); - EX( R.alt.b.flags, flags ); - goto loop; - } - - case 0xD3: // OUT (imm),A - pc++; - OUT_PORT( (data + r.b.a * 0x100), r.b.a ); - goto loop; - - case 0x2E: // LD L,imm - pc++; - r.b.l = data; - goto loop; - - case 0x3E: // LD A,imm - pc++; - r.b.a = data; - goto loop; - - case 0x3A:{// LD A,(addr) - int addr = GET_ADDR(); - pc += 2; - r.b.a = READ_MEM( addr ); - goto loop; - } - -// Conditional - -#define ZERO (flags & Z40) -#define CARRY (flags & C01) -#define EVEN (flags & P04) -#define MINUS (flags & S80) - -// JR -// TODO: more efficient way to handle negative branch that wraps PC around -#define JR_( cond, clocks ) {\ - pc++;\ - if ( !(cond) )\ - goto loop;\ - int offset = SBYTE( data );\ - pc = WORD( pc + offset );\ - s_time += clocks;\ - goto loop;\ -} - -#define JR( cond ) JR_( cond, 5 ) - - case 0x20: JR( !ZERO ) // JR NZ,disp - case 0x28: JR( ZERO ) // JR Z,disp - case 0x30: JR( !CARRY ) // JR NC,disp - case 0x38: JR( CARRY ) // JR C,disp - case 0x18: JR_( true,0) // JR disp - - case 0x10:{// DJNZ disp - int temp = r.b.b - 1; - r.b.b = temp; - JR( temp ) - } - -// JP -#define JP( cond ) \ - if ( !(cond) )\ - goto jp_not_taken;\ - pc = GET_ADDR();\ - goto loop; - - case 0xC2: JP( !ZERO ) // JP NZ,addr - case 0xCA: JP( ZERO ) // JP Z,addr - case 0xD2: JP( !CARRY ) // JP NC,addr - case 0xDA: JP( CARRY ) // JP C,addr - case 0xE2: JP( !EVEN ) // JP PO,addr - case 0xEA: JP( EVEN ) // JP PE,addr - case 0xF2: JP( !MINUS ) // JP P,addr - case 0xFA: JP( MINUS ) // JP M,addr - - case 0xC3: // JP addr - pc = GET_ADDR(); - goto loop; - - case 0xE9: // JP HL - pc = r.w.hl; - goto loop; - -// RET -#define RET( cond ) \ - if ( cond )\ - goto ret_taken;\ - s_time -= 6;\ - goto loop; - - case 0xC0: RET( !ZERO ) // RET NZ - case 0xC8: RET( ZERO ) // RET Z - case 0xD0: RET( !CARRY ) // RET NC - case 0xD8: RET( CARRY ) // RET C - case 0xE0: RET( !EVEN ) // RET PO - case 0xE8: RET( EVEN ) // RET PE - case 0xF0: RET( !MINUS ) // RET P - case 0xF8: RET( MINUS ) // RET M - - case 0xC9: // RET - ret_taken: - pc = READ_WORD( sp ); - sp = WORD( sp + 2 ); - goto loop; - -// CALL -#define CALL( cond ) \ - if ( cond )\ - goto call_taken;\ - goto call_not_taken; - - case 0xC4: CALL( !ZERO ) // CALL NZ,addr - case 0xCC: CALL( ZERO ) // CALL Z,addr - case 0xD4: CALL( !CARRY ) // CALL NC,addr - case 0xDC: CALL( CARRY ) // CALL C,addr - case 0xE4: CALL( !EVEN ) // CALL PO,addr - case 0xEC: CALL( EVEN ) // CALL PE,addr - case 0xF4: CALL( !MINUS ) // CALL P,addr - case 0xFC: CALL( MINUS ) // CALL M,addr - - case 0xCD:{// CALL addr - call_taken: { - int addr = pc + 2; - pc = GET_ADDR(); - sp = WORD( sp - 2 ); - WRITE_WORD( sp, addr ); - goto loop; - } - } - - case 0xFF: // RST - #ifdef IDLE_ADDR - if ( pc == IDLE_ADDR + 1 ) - goto hit_idle_addr; - #else - if ( pc > 0x10000 ) - { - pc = WORD( pc - 1 ); - s_time -= 11; - goto loop; - } - #endif - CASE7( C7, CF, D7, DF, E7, EF, F7 ): - data = pc; - pc = opcode & 0x38; - #ifdef RST_BASE - pc += RST_BASE; - #endif - goto push_data; - -// PUSH/POP - case 0xF5: // PUSH AF - data = r.b.a * 0x100u + flags; - goto push_data; - - case 0xC5: // PUSH BC - case 0xD5: // PUSH DE - case 0xE5: // PUSH HL - data = R16( opcode, 4, 0xC5 ); - push_data: - sp = WORD( sp - 2 ); - WRITE_WORD( sp, data ); - goto loop; - - case 0xF1: // POP AF - flags = READ_MEM( sp ); - r.b.a = READ_MEM( (sp + 1) ); - sp = WORD( sp + 2 ); - goto loop; - - case 0xC1: // POP BC - case 0xD1: // POP DE - case 0xE1: // POP HL - R16( opcode, 4, 0xC1 ) = READ_WORD( sp ); - sp = WORD( sp + 2 ); - goto loop; - -// ADC/ADD/SBC/SUB - case 0x96: // SUB (HL) - case 0x86: // ADD (HL) - flags &= ~C01; - case 0x9E: // SBC (HL) - case 0x8E: // ADC (HL) - data = READ_MEM( r.w.hl ); - goto adc_data; - - case 0xD6: // SUB A,imm - case 0xC6: // ADD imm - flags &= ~C01; - case 0xDE: // SBC A,imm - case 0xCE: // ADC imm - pc++; - goto adc_data; - - CASE7( 90, 91, 92, 93, 94, 95, 97 ): // SUB r - CASE7( 80, 81, 82, 83, 84, 85, 87 ): // ADD r - flags &= ~C01; - CASE7( 98, 99, 9A, 9B, 9C, 9D, 9F ): // SBC r - CASE7( 88, 89, 8A, 8B, 8C, 8D, 8F ): // ADC r - data = R8( opcode & 7, 0 ); - adc_data: { - int result = data + (flags & C01); - data ^= r.b.a; - flags = opcode >> 3 & N02; // bit 4 is set in subtract opcodes - if ( flags ) - result = -result; - result += r.b.a; - data ^= result; - flags +=(data & H10) + - ((data + 0x80) >> 6 & V04) + - SZ28C( result & 0x1FF ); - r.b.a = result; - goto loop; - } - -// CP - case 0xBE: // CP (HL) - data = READ_MEM( r.w.hl ); - goto cp_data; - - case 0xFE: // CP imm - pc++; - goto cp_data; - - CASE7( B8, B9, BA, BB, BC, BD, BF ): // CP r - data = R8( opcode, 0xB8 ); - cp_data: { - int result = r.b.a - data; - flags = N02 + (data & (F20 | F08)) + (result >> 8 & C01); - data ^= r.b.a; - flags +=(((result ^ r.b.a) & data) >> 5 & V04) + - (((data & H10) ^ result) & (S80 | H10)); - if ( BYTE( result ) ) - goto loop; - flags += Z40; - goto loop; - } - -// ADD HL,r.w - - case 0x39: // ADD HL,SP - data = sp; - goto add_hl_data; - - case 0x09: // ADD HL,BC - case 0x19: // ADD HL,DE - case 0x29: // ADD HL,HL - data = R16( opcode, 4, 0x09 ); - add_hl_data: { - int sum = r.w.hl + data; - data ^= r.w.hl; - r.w.hl = sum; - flags = (flags & (S80 | Z40 | V04)) + - (sum >> 16) + - (sum >> 8 & (F20 | F08)) + - ((data ^ sum) >> 8 & H10); - goto loop; - } - - case 0x27:{// DAA - int a = r.b.a; - if ( a > 0x99 ) - flags |= C01; - - int adjust = 0x60 * (flags & C01); - - if ( flags & H10 || (a & 0x0F) > 9 ) - adjust += 0x06; - - if ( flags & N02 ) - adjust = -adjust; - a += adjust; - - flags = (flags & (C01 | N02)) + - ((r.b.a ^ a) & H10) + - SZ28P( BYTE( a ) ); - r.b.a = a; - goto loop; - } - -// INC/DEC - case 0x34: // INC (HL) - data = READ_MEM( r.w.hl ) + 1; - WRITE_MEM( r.w.hl, data ); - goto inc_set_flags; - - CASE7( 04, 0C, 14, 1C, 24, 2C, 3C ): // INC r - data = ++R8( opcode >> 3, 0 ); - inc_set_flags: - flags = (flags & C01) + - (((data & 0x0F) - 1) & H10) + - SZ28( BYTE( data ) ); - if ( data != 0x80 ) - goto loop; - flags += V04; - goto loop; - - case 0x35: // DEC (HL) - data = READ_MEM( r.w.hl ) - 1; - WRITE_MEM( r.w.hl, data ); - goto dec_set_flags; - - CASE7( 05, 0D, 15, 1D, 25, 2D, 3D ): // DEC r - data = --R8( opcode >> 3, 0 ); - dec_set_flags: - flags = (flags & C01) + N02 + - (((data & 0x0F) + 1) & H10) + - SZ28( BYTE( data ) ); - if ( data != 0x7F ) - goto loop; - flags += V04; - goto loop; - - case 0x03: // INC BC - case 0x13: // INC DE - case 0x23: // INC HL - R16( opcode, 4, 0x03 )++; - goto loop; - - case 0x33: // INC SP - sp = WORD( sp + 1 ); - goto loop; - - case 0x0B: // DEC BC - case 0x1B: // DEC DE - case 0x2B: // DEC HL - R16( opcode, 4, 0x0B )--; - goto loop; - - case 0x3B: // DEC SP - sp = WORD( sp - 1 ); - goto loop; - -// AND - case 0xA6: // AND (HL) - data = READ_MEM( r.w.hl ); - goto and_data; - - case 0xE6: // AND imm - pc++; - goto and_data; - - CASE7( A0, A1, A2, A3, A4, A5, A7 ): // AND r - data = R8( opcode, 0xA0 ); - and_data: - r.b.a &= data; - flags = SZ28P( r.b.a ) + H10; - goto loop; - -// OR - case 0xB6: // OR (HL) - data = READ_MEM( r.w.hl ); - goto or_data; - - case 0xF6: // OR imm - pc++; - goto or_data; - - CASE7( B0, B1, B2, B3, B4, B5, B7 ): // OR r - data = R8( opcode, 0xB0 ); - or_data: - r.b.a |= data; - flags = SZ28P( r.b.a ); - goto loop; - -// XOR - case 0xAE: // XOR (HL) - data = READ_MEM( r.w.hl ); - goto xor_data; - - case 0xEE: // XOR imm - pc++; - goto xor_data; - - CASE7( A8, A9, AA, AB, AC, AD, AF ): // XOR r - data = R8( opcode, 0xA8 ); - xor_data: - r.b.a ^= data; - flags = SZ28P( r.b.a ); - goto loop; - -// LD - CASE7( 70, 71, 72, 73, 74, 75, 77 ): // LD (HL),r - WRITE_MEM( r.w.hl, R8( opcode, 0x70 ) ); - goto loop; - - CASE6( 41, 42, 43, 44, 45, 47 ): // LD B,r - CASE6( 48, 4A, 4B, 4C, 4D, 4F ): // LD C,r - CASE6( 50, 51, 53, 54, 55, 57 ): // LD D,r - CASE6( 58, 59, 5A, 5C, 5D, 5F ): // LD E,r - CASE6( 60, 61, 62, 63, 65, 67 ): // LD H,r - CASE6( 68, 69, 6A, 6B, 6C, 6F ): // LD L,r - CASE6( 78, 79, 7A, 7B, 7C, 7D ): // LD A,r - R8( opcode >> 3 & 7, 0 ) = R8( opcode & 7, 0 ); - goto loop; - - CASE5( 06, 0E, 16, 1E, 26 ): // LD r,imm - R8( opcode >> 3, 0 ) = data; - pc++; - goto loop; - - case 0x36: // LD (HL),imm - pc++; - WRITE_MEM( r.w.hl, data ); - goto loop; - - CASE7( 46, 4E, 56, 5E, 66, 6E, 7E ): // LD r,(HL) - R8( opcode >> 3, 8 ) = READ_MEM( r.w.hl ); - goto loop; - - case 0x01: // LD r.w,imm - case 0x11: - case 0x21: - R16( opcode, 4, 0x01 ) = GET_ADDR(); - pc += 2; - goto loop; - - case 0x31: // LD sp,imm - sp = GET_ADDR(); - pc += 2; - goto loop; - - case 0x2A:{// LD HL,(addr) - int addr = GET_ADDR(); - pc += 2; - r.w.hl = READ_WORD( addr ); - goto loop; - } - - case 0x32:{// LD (addr),A - int addr = GET_ADDR(); - pc += 2; - WRITE_MEM( addr, r.b.a ); - goto loop; - } - - case 0x22:{// LD (addr),HL - int addr = GET_ADDR(); - pc += 2; - WRITE_WORD( addr, r.w.hl ); - goto loop; - } - - case 0x02: // LD (BC),A - case 0x12: // LD (DE),A - WRITE_MEM( R16( opcode, 4, 0x02 ), r.b.a ); - goto loop; - - case 0x0A: // LD A,(BC) - case 0x1A: // LD A,(DE) - r.b.a = READ_MEM( R16( opcode, 4, 0x0A ) ); - goto loop; - - case 0xF9: // LD SP,HL - sp = r.w.hl; - goto loop; - -// Rotate - - case 0x07:{// RLCA - int temp = r.b.a; - temp = (temp << 1) + (temp >> 7); - flags = (flags & (S80 | Z40 | P04)) + - (temp & (F20 | F08 | C01)); - r.b.a = temp; - goto loop; - } - - case 0x0F:{// RRCA - int temp = r.b.a; - flags = (flags & (S80 | Z40 | P04)) + - (temp & C01); - temp = (temp << 7) + (temp >> 1); - flags += temp & (F20 | F08); - r.b.a = temp; - goto loop; - } - - case 0x17:{// RLA - int temp = (r.b.a << 1) + (flags & C01); - flags = (flags & (S80 | Z40 | P04)) + - (temp & (F20 | F08)) + - (temp >> 8); - r.b.a = temp; - goto loop; - } - - case 0x1F:{// RRA - int temp = (flags << 7) + (r.b.a >> 1); - flags = (flags & (S80 | Z40 | P04)) + - (temp & (F20 | F08)) + - (r.b.a & C01); - r.b.a = temp; - goto loop; - } - -// Misc - case 0x2F:{// CPL - int temp = ~r.b.a; - flags = (flags & (S80 | Z40 | P04 | C01)) + - (temp & (F20 | F08)) + - (H10 | N02); - r.b.a = temp; - goto loop; - } - - case 0x3F:{// CCF - flags = ((flags & (S80 | Z40 | P04 | C01)) ^ C01) + - (flags << 4 & H10) + - (r.b.a & (F20 | F08)); - goto loop; - } - - case 0x37: // SCF - flags = ((flags & (S80 | Z40 | P04)) | C01) + - (r.b.a & (F20 | F08)); - goto loop; - - case 0xDB: // IN A,(imm) - pc++; - r.b.a = IN_PORT( (data + r.b.a * 0x100) ); - goto loop; - - case 0xE3:{// EX (SP),HL - int temp = READ_WORD( sp ); - WRITE_WORD( sp, r.w.hl ); - r.w.hl = temp; - goto loop; - } - - case 0xEB: // EX DE,HL - EX( r.w.hl, r.w.de ); - goto loop; - - case 0xD9: // EXX DE,HL - EXX( w.bc ); - EXX( w.de ); - EXX( w.hl ); - goto loop; - - case 0xF3: // DI - R.iff1 = 0; - R.iff2 = 0; - goto loop; - - case 0xFB: // EI - R.iff1 = 1; - R.iff2 = 1; - // TODO: delayed effect - goto loop; - - case 0x76: // HALT - goto halt; - -//////////////////////////////////////// CB prefix - { - case 0xCB: - pc++; - switch ( data ) - { - - // Rotate left - - #define RLC( read, write ) {\ - int result = read;\ - result = BYTE( result << 1 ) + (result >> 7);\ - flags = SZ28P( result ) + (result & C01);\ - write;\ - goto loop;\ - } - - case 0x06: // RLC (HL) - s_time += 7; - data = r.w.hl; - rlc_data_addr: - RLC( READ_MEM( data ), WRITE_MEM( data, result ) ) - - CASE7( 00, 01, 02, 03, 04, 05, 07 ):{// RLC r - byte* reg = &R8( data, 0 ); - RLC( *reg, *reg = result ) - } - - #define RL( read, write ) {\ - int result = (read << 1) + (flags & C01);\ - flags = SZ28PC( result );\ - write;\ - goto loop;\ - } - - case 0x16: // RL (HL) - s_time += 7; - data = r.w.hl; - rl_data_addr: - RL( READ_MEM( data ), WRITE_MEM( data, result ) ) - - CASE7( 10, 11, 12, 13, 14, 15, 17 ):{// RL r - byte* reg = &R8( data, 0x10 ); - RL( *reg, *reg = result ) - } - - #define SLA( read, low_bit, write ) {\ - int result = (read << 1) + low_bit;\ - flags = SZ28PC( result );\ - write;\ - goto loop;\ - } - - case 0x26: // SLA (HL) - s_time += 7; - data = r.w.hl; - sla_data_addr: - SLA( READ_MEM( data ), 0, WRITE_MEM( data, result ) ) - - CASE7( 20, 21, 22, 23, 24, 25, 27 ):{// SLA r - byte* reg = &R8( data, 0x20 ); - SLA( *reg, 0, *reg = result ) - } - - case 0x36: // SLL (HL) - s_time += 7; - data = r.w.hl; - sll_data_addr: - SLA( READ_MEM( data ), 1, WRITE_MEM( data, result ) ) - - CASE7( 30, 31, 32, 33, 34, 35, 37 ):{// SLL r - byte* reg = &R8( data, 0x30 ); - SLA( *reg, 1, *reg = result ) - } - - // Rotate right - - #define RRC( read, write ) {\ - int result = read;\ - flags = result & C01;\ - result = BYTE( result << 7 ) + (result >> 1);\ - flags += SZ28P( result );\ - write;\ - goto loop;\ - } - - case 0x0E: // RRC (HL) - s_time += 7; - data = r.w.hl; - rrc_data_addr: - RRC( READ_MEM( data ), WRITE_MEM( data, result ) ) - - CASE7( 08, 09, 0A, 0B, 0C, 0D, 0F ):{// RRC r - byte* reg = &R8( data, 0x08 ); - RRC( *reg, *reg = result ) - } - - #define RR( read, write ) {\ - int result = read;\ - int temp = result & C01;\ - result = BYTE( flags << 7 ) + (result >> 1);\ - flags = SZ28P( result ) + temp;\ - write;\ - goto loop;\ - } - - case 0x1E: // RR (HL) - s_time += 7; - data = r.w.hl; - rr_data_addr: - RR( READ_MEM( data ), WRITE_MEM( data, result ) ) - - CASE7( 18, 19, 1A, 1B, 1C, 1D, 1F ):{// RR r - byte* reg = &R8( data, 0x18 ); - RR( *reg, *reg = result ) - } - - #define SRA( read, write ) {\ - int result = read;\ - flags = result & C01;\ - result = (result & 0x80) + (result >> 1);\ - flags += SZ28P( result );\ - write;\ - goto loop;\ - } - - case 0x2E: // SRA (HL) - data = r.w.hl; - s_time += 7; - sra_data_addr: - SRA( READ_MEM( data ), WRITE_MEM( data, result ) ) - - CASE7( 28, 29, 2A, 2B, 2C, 2D, 2F ):{// SRA r - byte* reg = &R8( data, 0x28 ); - SRA( *reg, *reg = result ) - } - - #define SRL( read, write ) {\ - int result = read;\ - flags = result & C01;\ - result >>= 1;\ - flags += SZ28P( result );\ - write;\ - goto loop;\ - } - - case 0x3E: // SRL (HL) - s_time += 7; - data = r.w.hl; - srl_data_addr: - SRL( READ_MEM( data ), WRITE_MEM( data, result ) ) - - CASE7( 38, 39, 3A, 3B, 3C, 3D, 3F ):{// SRL r - byte* reg = &R8( data, 0x38 ); - SRL( *reg, *reg = result ) - } - - // BIT - { - int temp; - CASE8( 46, 4E, 56, 5E, 66, 6E, 76, 7E ): // BIT b,(HL) - s_time += 4; - temp = READ_MEM( r.w.hl ); - flags &= C01; - goto bit_temp; - CASE7( 40, 41, 42, 43, 44, 45, 47 ): // BIT 0,r - CASE7( 48, 49, 4A, 4B, 4C, 4D, 4F ): // BIT 1,r - CASE7( 50, 51, 52, 53, 54, 55, 57 ): // BIT 2,r - CASE7( 58, 59, 5A, 5B, 5C, 5D, 5F ): // BIT 3,r - CASE7( 60, 61, 62, 63, 64, 65, 67 ): // BIT 4,r - CASE7( 68, 69, 6A, 6B, 6C, 6D, 6F ): // BIT 5,r - CASE7( 70, 71, 72, 73, 74, 75, 77 ): // BIT 6,r - CASE7( 78, 79, 7A, 7B, 7C, 7D, 7F ): // BIT 7,r - temp = R8( data & 7, 0 ); - flags = (flags & C01) + (temp & (F20 | F08)); - bit_temp: - temp = temp & (1 << (data >> 3 & 7)); - flags += (temp & S80) + H10; - flags += (unsigned) --temp >> 8 & (Z40 | P04); - goto loop; - } - - // SET/RES - CASE8( 86, 8E, 96, 9E, A6, AE, B6, BE ): // RES b,(HL) - CASE8( C6, CE, D6, DE, E6, EE, F6, FE ):{// SET b,(HL) - s_time += 7; - int temp = READ_MEM( r.w.hl ); - int bit = 1 << (data >> 3 & 7); - temp |= bit; // SET - if ( !(data & 0x40) ) - temp ^= bit; // RES - WRITE_MEM( r.w.hl, temp ); - goto loop; - } - - CASE7( C0, C1, C2, C3, C4, C5, C7 ): // SET 0,r - CASE7( C8, C9, CA, CB, CC, CD, CF ): // SET 1,r - CASE7( D0, D1, D2, D3, D4, D5, D7 ): // SET 2,r - CASE7( D8, D9, DA, DB, DC, DD, DF ): // SET 3,r - CASE7( E0, E1, E2, E3, E4, E5, E7 ): // SET 4,r - CASE7( E8, E9, EA, EB, EC, ED, EF ): // SET 5,r - CASE7( F0, F1, F2, F3, F4, F5, F7 ): // SET 6,r - CASE7( F8, F9, FA, FB, FC, FD, FF ): // SET 7,r - R8( data & 7, 0 ) |= 1 << (data >> 3 & 7); - goto loop; - - CASE7( 80, 81, 82, 83, 84, 85, 87 ): // RES 0,r - CASE7( 88, 89, 8A, 8B, 8C, 8D, 8F ): // RES 1,r - CASE7( 90, 91, 92, 93, 94, 95, 97 ): // RES 2,r - CASE7( 98, 99, 9A, 9B, 9C, 9D, 9F ): // RES 3,r - CASE7( A0, A1, A2, A3, A4, A5, A7 ): // RES 4,r - CASE7( A8, A9, AA, AB, AC, AD, AF ): // RES 5,r - CASE7( B0, B1, B2, B3, B4, B5, B7 ): // RES 6,r - CASE7( B8, B9, BA, BB, BC, BD, BF ): // RES 7,r - R8( data & 7, 0 ) &= ~(1 << (data >> 3 & 7)); - goto loop; - } - assert( false ); - } - -#undef GET_ADDR -#define GET_ADDR() GET_LE16( &INSTR( 1, pc ) ) - -//////////////////////////////////////// ED prefix - { - case 0xED: - pc++; - s_time += (clock_table + 256) [data] >> 4; - switch ( data ) - { - { - int temp; - case 0x72: // SBC HL,SP - case 0x7A: // ADC HL,SP - temp = sp; - if ( 0 ) - case 0x42: // SBC HL,BC - case 0x52: // SBC HL,DE - case 0x62: // SBC HL,HL - case 0x4A: // ADC HL,BC - case 0x5A: // ADC HL,DE - case 0x6A: // ADC HL,HL - temp = R16( data >> 3 & 6, 1, 0 ); - int sum = temp + (flags & C01); - flags = ~data >> 2 & N02; - if ( flags ) - sum = -sum; - sum += r.w.hl; - temp ^= r.w.hl; - temp ^= sum; - flags +=(sum >> 16 & C01) + - (temp >> 8 & H10) + - (sum >> 8 & (S80 | F20 | F08)) + - ((temp + 0x8000) >> 14 & V04); - r.w.hl = sum; - if ( WORD( sum ) ) - goto loop; - flags += Z40; - goto loop; - } - - CASE8( 40, 48, 50, 58, 60, 68, 70, 78 ):{// IN r,(C) - int temp = IN_PORT( r.w.bc ); - R8( data >> 3, 8 ) = temp; - flags = (flags & C01) + SZ28P( temp ); - goto loop; - } - - case 0x71: // OUT (C),0 - r.b.flags = 0; - CASE7( 41, 49, 51, 59, 61, 69, 79 ): // OUT (C),r - OUT_PORT( r.w.bc, R8( data >> 3, 8 ) ); - goto loop; - - { - int temp; - case 0x73: // LD (ADDR),SP - temp = sp; - if ( 0 ) - case 0x43: // LD (ADDR),BC - case 0x53: // LD (ADDR),DE - temp = R16( data, 4, 0x43 ); - int addr = GET_ADDR(); - pc += 2; - WRITE_WORD( addr, temp ); - goto loop; - } - - case 0x4B: // LD BC,(ADDR) - case 0x5B:{// LD DE,(ADDR) - int addr = GET_ADDR(); - pc += 2; - R16( data, 4, 0x4B ) = READ_WORD( addr ); - goto loop; - } - - case 0x7B:{// LD SP,(ADDR) - int addr = GET_ADDR(); - pc += 2; - sp = READ_WORD( addr ); - goto loop; - } - - case 0x67:{// RRD - int temp = READ_MEM( r.w.hl ); - WRITE_MEM( r.w.hl, ((r.b.a << 4) + (temp >> 4)) ); - temp = (r.b.a & 0xF0) + (temp & 0x0F); - flags = (flags & C01) + SZ28P( temp ); - r.b.a = temp; - goto loop; - } - - case 0x6F:{// RLD - int temp = READ_MEM( r.w.hl ); - WRITE_MEM( r.w.hl, ((temp << 4) + (r.b.a & 0x0F)) ); - temp = (r.b.a & 0xF0) + (temp >> 4); - flags = (flags & C01) + SZ28P( temp ); - r.b.a = temp; - goto loop; - } - - CASE8( 44, 4C, 54, 5C, 64, 6C, 74, 7C ): // NEG - opcode = 0x10; // flag to do SBC instead of ADC - flags &= ~C01; - data = r.b.a; - r.b.a = 0; - goto adc_data; - - { - int inc; - case 0xA9: // CPD - case 0xB9: // CPDR - inc = -1; - if ( 0 ) - case 0xA1: // CPI - case 0xB1: // CPIR - inc = +1; - int addr = r.w.hl; - r.w.hl = addr + inc; - int temp = READ_MEM( addr ); - - int result = r.b.a - temp; - flags = (flags & C01) + N02 + - ((((temp ^ r.b.a) & H10) ^ result) & (S80 | H10)); - - if ( !BYTE( result ) ) - flags += Z40; - result -= (flags & H10) >> 4; - flags += result & F08; - flags += result << 4 & F20; - if ( !--r.w.bc ) - goto loop; - - flags += V04; - if ( flags & Z40 || data < 0xB0 ) - goto loop; - - pc -= 2; - s_time += 5; - goto loop; - } - - { - int inc; - case 0xA8: // LDD - case 0xB8: // LDDR - inc = -1; - if ( 0 ) - case 0xA0: // LDI - case 0xB0: // LDIR - inc = +1; - int addr = r.w.hl; - r.w.hl = addr + inc; - int temp = READ_MEM( addr ); - - addr = r.w.de; - r.w.de = addr + inc; - WRITE_MEM( addr, temp ); - - temp += r.b.a; - flags = (flags & (S80 | Z40 | C01)) + - (temp & F08) + (temp << 4 & F20); - if ( !--r.w.bc ) - goto loop; - - flags += V04; - if ( data < 0xB0 ) - goto loop; - - pc -= 2; - s_time += 5; - goto loop; - } - - { - int inc; - case 0xAB: // OUTD - case 0xBB: // OTDR - inc = -1; - if ( 0 ) - case 0xA3: // OUTI - case 0xB3: // OTIR - inc = +1; - int addr = r.w.hl; - r.w.hl = addr + inc; - int temp = READ_MEM( addr ); - - int b = --r.b.b; - flags = (temp >> 6 & N02) + SZ28( b ); - if ( b && data >= 0xB0 ) - { - pc -= 2; - s_time += 5; - } - - OUT_PORT( r.w.bc, temp ); - goto loop; - } - - { - int inc; - case 0xAA: // IND - case 0xBA: // INDR - inc = -1; - if ( 0 ) - case 0xA2: // INI - case 0xB2: // INIR - inc = +1; - - int addr = r.w.hl; - r.w.hl = addr + inc; - - int temp = IN_PORT( r.w.bc ); - - int b = --r.b.b; - flags = (temp >> 6 & N02) + SZ28( b ); - if ( b && data >= 0xB0 ) - { - pc -= 2; - s_time += 5; - } - - WRITE_MEM( addr, temp ); - goto loop; - } - - case 0x47: // LD I,A - R.i = r.b.a; - goto loop; - - case 0x4F: // LD R,A - SET_R( r.b.a ); - dprintf( "LD R,A not supported\n" ); - warning = true; - goto loop; - - case 0x57: // LD A,I - r.b.a = R.i; - goto ld_ai_common; - - case 0x5F: // LD A,R - r.b.a = GET_R(); - dprintf( "LD A,R not supported\n" ); - warning = true; - ld_ai_common: - flags = (flags & C01) + SZ28( r.b.a ) + (R.iff2 << 2 & V04); - goto loop; - - CASE8( 45, 4D, 55, 5D, 65, 6D, 75, 7D ): // RETI/RETN - R.iff1 = R.iff2; - goto ret_taken; - - case 0x46: case 0x4E: case 0x66: case 0x6E: // IM 0 - R.im = 0; - goto loop; - - case 0x56: case 0x76: // IM 1 - R.im = 1; - goto loop; - - case 0x5E: case 0x7E: // IM 2 - R.im = 2; - goto loop; - - default: - dprintf( "Opcode $ED $%02X not supported\n", data ); - warning = true; - goto loop; - } - assert( false ); - } - -//////////////////////////////////////// DD/FD prefix - { - int ixy; - case 0xDD: - ixy = ix; - goto ix_prefix; - case 0xFD: - ixy = iy; - ix_prefix: - pc++; - int data2 = READ_CODE( pc ); - s_time += (clock_table + 256) [data] & 0x0F; - switch ( data ) - { - // TODO: more efficient way of avoid negative address - // TODO: avoid using this as argument to READ_MEM() since it is evaluated twice - #define IXY_DISP( ixy, disp ) WORD( (ixy ) + (disp)) - - #define SET_IXY( in ) if ( opcode == 0xDD ) ix = in; else iy = in; - - // ADD/ADC/SUB/SBC - - case 0x96: // SUB (IXY+disp) - case 0x86: // ADD (IXY+disp) - flags &= ~C01; - case 0x9E: // SBC (IXY+disp) - case 0x8E: // ADC (IXY+disp) - pc++; - opcode = data; - data = READ_MEM( IXY_DISP( ixy, SBYTE( data2 ) ) ); - goto adc_data; - - case 0x94: // SUB HXY - case 0x84: // ADD HXY - flags &= ~C01; - case 0x9C: // SBC HXY - case 0x8C: // ADC HXY - opcode = data; - data = ixy >> 8; - goto adc_data; - - case 0x95: // SUB LXY - case 0x85: // ADD LXY - flags &= ~C01; - case 0x9D: // SBC LXY - case 0x8D: // ADC LXY - opcode = data; - data = BYTE( ixy ); - goto adc_data; - - { - int temp; - case 0x39: // ADD IXY,SP - temp = sp; - goto add_ixy_data; - - case 0x29: // ADD IXY,HL - temp = ixy; - goto add_ixy_data; - - case 0x09: // ADD IXY,BC - case 0x19: // ADD IXY,DE - temp = R16( data, 4, 0x09 ); - add_ixy_data: { - int sum = ixy + temp; - temp ^= ixy; - ixy = WORD( sum ); - flags = (flags & (S80 | Z40 | V04)) + - (sum >> 16) + - (sum >> 8 & (F20 | F08)) + - ((temp ^ sum) >> 8 & H10); - goto set_ixy; - } - } - - // AND - case 0xA6: // AND (IXY+disp) - pc++; - data = READ_MEM( IXY_DISP( ixy, SBYTE( data2 ) ) ); - goto and_data; - - case 0xA4: // AND HXY - data = ixy >> 8; - goto and_data; - - case 0xA5: // AND LXY - data = BYTE( ixy ); - goto and_data; - - // OR - case 0xB6: // OR (IXY+disp) - pc++; - data = READ_MEM( IXY_DISP( ixy, SBYTE( data2 ) ) ); - goto or_data; - - case 0xB4: // OR HXY - data = ixy >> 8; - goto or_data; - - case 0xB5: // OR LXY - data = BYTE( ixy ); - goto or_data; - - // XOR - case 0xAE: // XOR (IXY+disp) - pc++; - data = READ_MEM( IXY_DISP( ixy, SBYTE( data2 ) ) ); - goto xor_data; - - case 0xAC: // XOR HXY - data = ixy >> 8; - goto xor_data; - - case 0xAD: // XOR LXY - data = BYTE( ixy ); - goto xor_data; - - // CP - case 0xBE: // CP (IXY+disp) - pc++; - data = READ_MEM( IXY_DISP( ixy, SBYTE( data2 ) ) ); - goto cp_data; - - case 0xBC: // CP HXY - data = ixy >> 8; - goto cp_data; - - case 0xBD: // CP LXY - data = BYTE( ixy ); - goto cp_data; - - // LD - CASE7( 70, 71, 72, 73, 74, 75, 77 ): // LD (IXY+disp),r - data = R8( data, 0x70 ); - if ( 0 ) - case 0x36: // LD (IXY+disp),imm - pc++, data = READ_CODE( pc ); - pc++; - WRITE_MEM( IXY_DISP( ixy, SBYTE( data2 ) ), data ); - goto loop; - - CASE5( 44, 4C, 54, 5C, 7C ): // LD r,HXY - R8( data >> 3, 8 ) = ixy >> 8; - goto loop; - - case 0x64: // LD HXY,HXY - case 0x6D: // LD LXY,LXY - goto loop; - - CASE5( 45, 4D, 55, 5D, 7D ): // LD r,LXY - R8( data >> 3, 8 ) = ixy; - goto loop; - - CASE7( 46, 4E, 56, 5E, 66, 6E, 7E ): // LD r,(IXY+disp) - pc++; - R8( data >> 3, 8 ) = READ_MEM( IXY_DISP( ixy, SBYTE( data2 ) ) ); - goto loop; - - case 0x26: // LD HXY,imm - pc++; - goto ld_hxy_data; - - case 0x65: // LD HXY,LXY - data2 = BYTE( ixy ); - goto ld_hxy_data; - - CASE5( 60, 61, 62, 63, 67 ): // LD HXY,r - data2 = R8( data, 0x60 ); - ld_hxy_data: - ixy = BYTE( ixy ) + (data2 << 8); - goto set_ixy; - - case 0x2E: // LD LXY,imm - pc++; - goto ld_lxy_data; - - case 0x6C: // LD LXY,HXY - data2 = ixy >> 8; - goto ld_lxy_data; - - CASE5( 68, 69, 6A, 6B, 6F ): // LD LXY,r - data2 = R8( data, 0x68 ); - ld_lxy_data: - ixy = (ixy & 0xFF00) + data2; - set_ixy: - if ( opcode == 0xDD ) - { - ix = ixy; - goto loop; - } - iy = ixy; - goto loop; - - case 0xF9: // LD SP,IXY - sp = ixy; - goto loop; - - case 0x22:{// LD (ADDR),IXY - int addr = GET_ADDR(); - pc += 2; - WRITE_WORD( addr, ixy ); - goto loop; - } - - case 0x21: // LD IXY,imm - ixy = GET_ADDR(); - pc += 2; - goto set_ixy; - - case 0x2A:{// LD IXY,(addr) - int addr = GET_ADDR(); - ixy = READ_WORD( addr ); - pc += 2; - goto set_ixy; - } - - // DD/FD CB prefix - case 0xCB: { - data = IXY_DISP( ixy, SBYTE( data2 ) ); - pc++; - data2 = READ_CODE( pc ); - pc++; - switch ( data2 ) - { - case 0x06: goto rlc_data_addr; // RLC (IXY) - case 0x16: goto rl_data_addr; // RL (IXY) - case 0x26: goto sla_data_addr; // SLA (IXY) - case 0x36: goto sll_data_addr; // SLL (IXY) - case 0x0E: goto rrc_data_addr; // RRC (IXY) - case 0x1E: goto rr_data_addr; // RR (IXY) - case 0x2E: goto sra_data_addr; // SRA (IXY) - case 0x3E: goto srl_data_addr; // SRL (IXY) - - CASE8( 46, 4E, 56, 5E, 66, 6E, 76, 7E ):{// BIT b,(IXY+disp) - int temp = READ_MEM( data ); - temp = temp & (1 << (data2 >> 3 & 7)); - flags = (flags & C01) + H10 + (temp & S80); - flags += (unsigned) --temp >> 8 & (Z40 | P04); - goto loop; - } - - CASE8( 86, 8E, 96, 9E, A6, AE, B6, BE ): // RES b,(IXY+disp) - CASE8( C6, CE, D6, DE, E6, EE, F6, FE ):{// SET b,(IXY+disp) - int temp = READ_MEM( data ); - int bit = 1 << (data2 >> 3 & 7); - temp |= bit; // SET - if ( !(data2 & 0x40) ) - temp ^= bit; // RES - WRITE_MEM( data, temp ); - goto loop; - } - - default: - dprintf( "Opcode $%02X $CB $%02X not supported\n", opcode, data2 ); - warning = true; - goto loop; - } - assert( false ); - } - - // INC/DEC - case 0x23: // INC IXY - ixy = WORD( ixy + 1 ); - goto set_ixy; - - case 0x2B: // DEC IXY - ixy = WORD( ixy - 1 ); - goto set_ixy; - - case 0x34: // INC (IXY+disp) - ixy = IXY_DISP( ixy, SBYTE( data2 ) ); - pc++; - data = READ_MEM( ixy ) + 1; - WRITE_MEM( ixy, data ); - goto inc_set_flags; - - case 0x35: // DEC (IXY+disp) - ixy = IXY_DISP( ixy, SBYTE( data2 ) ); - pc++; - data = READ_MEM( ixy ) - 1; - WRITE_MEM( ixy, data ); - goto dec_set_flags; - - case 0x24: // INC HXY - ixy = WORD( ixy + 0x100 ); - data = ixy >> 8; - goto inc_xy_common; - - case 0x2C: // INC LXY - data = BYTE( ixy + 1 ); - ixy = (ixy & 0xFF00) + data; - inc_xy_common: - if ( opcode == 0xDD ) - { - ix = ixy; - goto inc_set_flags; - } - iy = ixy; - goto inc_set_flags; - - case 0x25: // DEC HXY - ixy = WORD( ixy - 0x100 ); - data = ixy >> 8; - goto dec_xy_common; - - case 0x2D: // DEC LXY - data = BYTE( ixy - 1 ); - ixy = (ixy & 0xFF00) + data; - dec_xy_common: - if ( opcode == 0xDD ) - { - ix = ixy; - goto dec_set_flags; - } - iy = ixy; - goto dec_set_flags; - - // PUSH/POP - case 0xE5: // PUSH IXY - data = ixy; - goto push_data; - - case 0xE1:{// POP IXY - ixy = READ_WORD( sp ); - sp = WORD( sp + 2 ); - goto set_ixy; - } - - // Misc - - case 0xE9: // JP (IXY) - pc = ixy; - goto loop; - - case 0xE3:{// EX (SP),IXY - int temp = READ_WORD( sp ); - WRITE_WORD( sp, ixy ); - ixy = temp; - goto set_ixy; - } - - default: - dprintf( "Unnecessary DD/FD prefix encountered\n" ); - warning = true; - pc--; - goto loop; - } - assert( false ); - } - - } - dprintf( "Unhandled main opcode: $%02X\n", opcode ); - assert( false ); - -#ifdef IDLE_ADDR -hit_idle_addr: - s_time -= 11; - goto out_of_time; -#endif -halt: - s_time &= 3; // increment by multiple of 4 -out_of_time: - pc--; - - r.b.flags = flags; - R.ix = ix; - R.iy = iy; - R.sp = sp; - R.pc = pc; - R.b = r.b; - - cpu->cpu_state_.base = s.base; - cpu->cpu_state_.time = s_time; - cpu->cpu_state = &cpu->cpu_state_; -} +// Game_Music_Emu 0.6-pre. http://www.slack.net/~ant/ + +// Last validated with zexall 2009.12.05. +// Doesn't implement the R register or immediate interrupt after EI. +// Address wrap-around isn't completely correct, but is prevented from crashing emulator. +// 16-bit memory accesses are made directly to mapped memory, instead of using macro. + +#if 0 +/* Define these macros in the source file before #including this file. +- Parameters might be expressions, so they are best evaluated only once, +though they NEVER have side-effects, so multiple evaluation is OK. +- Output parameters might be a multiple-assignment expression like "a=x", +so they must NOT be parenthesized. +- Except where noted, time() and related functions will NOT work +correctly inside a macro. TIME() is always correct, and between FLUSH_TIME() and +CACHE_TIME() the normal time changing functions can be used. +- Macros "returning" void may use a {} statement block. */ + + // 0 <= addr <= 0xFFFF + 0x100 + // Optional; default uses whatever was set with map_mem() + int READ_MEM( addr_t ); + void WRITE_MEM( addr_t, int data ); + + // 0 <= port <= 0xFFFF (apparently upper 8 bits are output by hardware) + void OUT_PORT( int port, int data ); + int IN_PORT int port ); + + // Reference to Z80_Cpu object used for emulation + #define CPU cpu + +// The following can be used within macros: + + // Current time + time_t TIME(); + + // Allows use of time functions + void FLUSH_TIME(); + + // Must be used before end of macro if FLUSH_TIME() was used earlier + void CACHE_TIME(); + +// Configuration (optional; commented behavior if defined) + + // Optimizes as if map_mem( 0, 0x10000, FLAT_MEM, FLAT_MEM ) is always in effect + #define FLAT_MEM my_mem_array + + // If RST 7 ($FF) is encountered and PC = IDLE_ADDR, stops execution + #define IDLE_ADDR 0x1234 + + // Expanded just before beginning of code, to help debugger + #define CPU_BEGIN void my_run_cpu() { + +#endif + +/* Copyright (C) 2006-2008 Shay Green. This module is free software; you +can redistribute it and/or modify it under the terms of the GNU Lesser +General Public License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. This +module 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 Lesser General Public License for more +details. You should have received a copy of the GNU Lesser General Public +License along with this module; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ + +#ifdef CPU_BEGIN + CPU_BEGIN +#endif + +#define R cpu->r + +// flags, named with hex value for clarity +int const S80 = 0x80; +int const Z40 = 0x40; +int const F20 = 0x20; +int const H10 = 0x10; +int const F08 = 0x08; +int const V04 = 0x04; +int const P04 = 0x04; +int const N02 = 0x02; +int const C01 = 0x01; + +#define SZ28P( n ) cpu->szpc [n] +#define SZ28PC( n ) cpu->szpc [n] +#define SZ28C( n ) (cpu->szpc [n] & ~P04) +#define SZ28( n ) SZ28C( n ) + +#define SET_R( n ) (void) (R.r = n) +#define GET_R() (R.r) + +// Time +#define TIME() (s_time + s.base) +#define FLUSH_TIME() {s.time = s_time;} +#define CACHE_TIME() {s_time = s.time;} + +// Memory +#define RW_MEM( addr, rw ) RW_PAGE( addr, rw ) [RW_OFFSET( addr )] +#define READ_CODE( addr ) RW_MEM( addr, read ) + +#ifdef FLAT_MEM + #define RW_PAGE( addr, rw ) FLAT_MEM + #define RW_OFFSET( addr ) (addr) + #define INSTR( off, addr ) READ_CODE( addr ) +#else + #define RW_PAGE( addr, rw ) s.rw [(unsigned) (addr) >> page_bits] + #define RW_OFFSET( addr ) Z80_CPU_OFFSET( addr ) + #define INSTR( off, addr ) instr [off] +#endif + +#ifndef READ_MEM + #define READ_MEM( addr ) RW_MEM( addr, read ) +#endif + +#ifndef WRITE_MEM + #define WRITE_MEM( addr, data ) (RW_MEM( addr, write ) = data) +#endif + +#define READ_WORD( addr ) GET_LE16( &RW_MEM( addr, read ) ) +#define WRITE_WORD( addr, data ) SET_LE16( &RW_MEM( addr, write ), data ) + +// Truncation +#define BYTE( n ) ((uint8_t ) (n)) /* (unsigned) n & 0xFF */ +#define SBYTE( n ) ((int8_t ) (n)) /* (BYTE( n ) ^ 0x80) - 0x80 */ +#define WORD( n ) ((uint16_t) (n)) /* (unsigned) n & 0xFFFF */ + +// Misc +#define CASE5( a, b, c, d, e ) case 0x##a:case 0x##b:case 0x##c:case 0x##d:case 0x##e +#define CASE6( a, b, c, d, e, f ) CASE5( a, b, c, d, e ): case 0x##f +#define CASE7( a, b, c, d, e, f, g ) CASE6( a, b, c, d, e, f ): case 0x##g +#define CASE8( a, b, c, d, e, f, g, h ) CASE7( a, b, c, d, e, f, g ): case 0x##h + +#ifdef BLARGG_BIG_ENDIAN + #define R8( n, offset ) ((r.r8_ - offset) [n]) +#elif BLARGG_LITTLE_ENDIAN + #define R8( n, offset ) ((r.r8_ - offset) [(n) ^ 1]) +#else + #error "Byte order of CPU must be known" +#endif + +#define R16( n, shift, offset ) (r.r16_ [((unsigned) (n) >> shift) - (offset >> shift)]) + +#define EX( x, y ) \ + {\ + int temp = x;\ + x = y;\ + y = temp;\ + } + +#define EXX( name ) \ + EX( R.alt.name, r.name ) + +bool warning = false; +{ + struct cpu_state_t s; + #ifdef FLAT_MEM + s.base = cpu->cpu_state_.base; + #else + s = cpu->cpu_state_; + #endif + cpu->cpu_state = &s; + + + union r_t { + struct regs_t b; + struct pairs_t w; + byte r8_ [8]; // indexed + uint16_t r16_ [4]; + } r; + r.b = R.b; + + cpu_time_t s_time = cpu->cpu_state_.time; + int pc = R.pc; + int sp = R.sp; + int ix = R.ix; // TODO: keep in memory for direct access? + int iy = R.iy; + int flags = R.b.flags; + + //goto loop; // confuses optimizer + s_time += 7; + pc -= 2; + +call_not_taken: + s_time -= 7; +jp_not_taken: + pc += 2; +loop: + + check( (unsigned) pc < 0x10000 + 1 ); // +1 so emulator can catch wrap-around + check( (unsigned) sp < 0x10000 ); + check( (unsigned) flags < 0x100 ); + check( (unsigned) ix < 0x10000 ); + check( (unsigned) iy < 0x10000 ); + + byte const* instr = RW_PAGE( pc, read ); + + int opcode; + + if ( RW_OFFSET( ~0 ) == ~0 ) + { + opcode = instr [RW_OFFSET( pc )]; + pc++; + instr += RW_OFFSET( pc ); + } + else + { + instr += RW_OFFSET( pc ); + opcode = *instr++; + pc++; + } + + static byte const clock_table [256 * 2] = { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 4,10, 7, 6, 4, 4, 7, 4, 4,11, 7, 6, 4, 4, 7, 4, // 0 + 8,10, 7, 6, 4, 4, 7, 4,12,11, 7, 6, 4, 4, 7, 4, // 1 + 7,10,16, 6, 4, 4, 7, 4, 7,11,16, 6, 4, 4, 7, 4, // 2 + 7,10,13, 6,11,11,10, 4, 7,11,13, 6, 4, 4, 7, 4, // 3 + 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // 4 + 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // 5 + 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // 6 + 7, 7, 7, 7, 7, 7, 4, 7, 4, 4, 4, 4, 4, 4, 7, 4, // 7 + 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // 8 + 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // 9 + 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // A + 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // B + 11,10,10,10,17,11, 7,11,11,10,10, 8,17,17, 7,11, // C + 11,10,10,11,17,11, 7,11,11, 4,10,11,17, 8, 7,11, // D + 11,10,10,19,17,11, 7,11,11, 4,10, 4,17, 8, 7,11, // E + 11,10,10, 4,17,11, 7,11,11, 6,10, 4,17, 8, 7,11, // F + + // high four bits are $ED time - 8, low four bits are $DD/$FD time - 8 + //0 1 2 3 4 5 6 7 8 9 A B C D E F + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x06,0x0C,0x02,0x00,0x00,0x03,0x00,0x00,0x07,0x0C,0x02,0x00,0x00,0x03,0x00, + 0x00,0x00,0x00,0x00,0x0F,0x0F,0x0B,0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00, + 0x40,0x40,0x70,0xC0,0x00,0x60,0x0B,0x10,0x40,0x40,0x70,0xC0,0x00,0x60,0x0B,0x10, + 0x40,0x40,0x70,0xC0,0x00,0x60,0x0B,0x10,0x40,0x40,0x70,0xC0,0x00,0x60,0x0B,0x10, + 0x40,0x40,0x70,0xC0,0x00,0x60,0x0B,0xA0,0x40,0x40,0x70,0xC0,0x00,0x60,0x0B,0xA0, + 0x4B,0x4B,0x7B,0xCB,0x0B,0x6B,0x00,0x0B,0x40,0x40,0x70,0xC0,0x00,0x60,0x0B,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x0B,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0B,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x0B,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0B,0x00, + 0x80,0x80,0x80,0x80,0x00,0x00,0x0B,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x0B,0x00, + 0xD0,0xD0,0xD0,0xD0,0x00,0x00,0x0B,0x00,0xD0,0xD0,0xD0,0xD0,0x00,0x00,0x0B,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x06,0x00,0x0F,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00, + }; + + if ( s_time >= 0 ) + goto out_of_time; + s_time += clock_table [opcode]; + + #ifdef Z80_CPU_LOG_H + //log_opcode( opcode, READ_CODE( pc ) ); + z80_cpu_log( "log.txt", pc - 1, opcode, READ_CODE( pc ), + READ_CODE( pc + 1 ), READ_CODE( pc + 2 ) ); + z80_log_regs( r.b.a, r.w.bc, r.w.de, r.w.hl, sp, ix, iy ); + #endif + +#define GET_ADDR() GET_LE16( &INSTR( 0, pc ) ) + + int data; + data = INSTR( 0, pc ); + + switch ( opcode ) + { +// Common + + case 0x00: // NOP + CASE7( 40, 49, 52, 5B, 64, 6D, 7F ): // LD B,B etc. + goto loop; + + case 0x08:{// EX AF,AF' + EXX( b.a ); + EX( R.alt.b.flags, flags ); + goto loop; + } + + case 0xD3: // OUT (imm),A + pc++; + OUT_PORT( (data + r.b.a * 0x100), r.b.a ); + goto loop; + + case 0x2E: // LD L,imm + pc++; + r.b.l = data; + goto loop; + + case 0x3E: // LD A,imm + pc++; + r.b.a = data; + goto loop; + + case 0x3A:{// LD A,(addr) + int addr = GET_ADDR(); + pc += 2; + r.b.a = READ_MEM( addr ); + goto loop; + } + +// Conditional + +#define ZERO (flags & Z40) +#define CARRY (flags & C01) +#define EVEN (flags & P04) +#define MINUS (flags & S80) + +// JR +// TODO: more efficient way to handle negative branch that wraps PC around +#define JR_( cond, clocks ) {\ + pc++;\ + if ( !(cond) )\ + goto loop;\ + int offset = SBYTE( data );\ + pc = WORD( pc + offset );\ + s_time += clocks;\ + goto loop;\ +} + +#define JR( cond ) JR_( cond, 5 ) + + case 0x20: JR( !ZERO ) // JR NZ,disp + case 0x28: JR( ZERO ) // JR Z,disp + case 0x30: JR( !CARRY ) // JR NC,disp + case 0x38: JR( CARRY ) // JR C,disp + case 0x18: JR_( true,0) // JR disp + + case 0x10:{// DJNZ disp + int temp = r.b.b - 1; + r.b.b = temp; + JR( temp ) + } + +// JP +#define JP( cond ) \ + if ( !(cond) )\ + goto jp_not_taken;\ + pc = GET_ADDR();\ + goto loop; + + case 0xC2: JP( !ZERO ) // JP NZ,addr + case 0xCA: JP( ZERO ) // JP Z,addr + case 0xD2: JP( !CARRY ) // JP NC,addr + case 0xDA: JP( CARRY ) // JP C,addr + case 0xE2: JP( !EVEN ) // JP PO,addr + case 0xEA: JP( EVEN ) // JP PE,addr + case 0xF2: JP( !MINUS ) // JP P,addr + case 0xFA: JP( MINUS ) // JP M,addr + + case 0xC3: // JP addr + pc = GET_ADDR(); + goto loop; + + case 0xE9: // JP HL + pc = r.w.hl; + goto loop; + +// RET +#define RET( cond ) \ + if ( cond )\ + goto ret_taken;\ + s_time -= 6;\ + goto loop; + + case 0xC0: RET( !ZERO ) // RET NZ + case 0xC8: RET( ZERO ) // RET Z + case 0xD0: RET( !CARRY ) // RET NC + case 0xD8: RET( CARRY ) // RET C + case 0xE0: RET( !EVEN ) // RET PO + case 0xE8: RET( EVEN ) // RET PE + case 0xF0: RET( !MINUS ) // RET P + case 0xF8: RET( MINUS ) // RET M + + case 0xC9: // RET + ret_taken: + pc = READ_WORD( sp ); + sp = WORD( sp + 2 ); + goto loop; + +// CALL +#define CALL( cond ) \ + if ( cond )\ + goto call_taken;\ + goto call_not_taken; + + case 0xC4: CALL( !ZERO ) // CALL NZ,addr + case 0xCC: CALL( ZERO ) // CALL Z,addr + case 0xD4: CALL( !CARRY ) // CALL NC,addr + case 0xDC: CALL( CARRY ) // CALL C,addr + case 0xE4: CALL( !EVEN ) // CALL PO,addr + case 0xEC: CALL( EVEN ) // CALL PE,addr + case 0xF4: CALL( !MINUS ) // CALL P,addr + case 0xFC: CALL( MINUS ) // CALL M,addr + + case 0xCD:{// CALL addr + call_taken: { + int addr = pc + 2; + pc = GET_ADDR(); + sp = WORD( sp - 2 ); + WRITE_WORD( sp, addr ); + goto loop; + } + } + + case 0xFF: // RST + #ifdef IDLE_ADDR + if ( pc == IDLE_ADDR + 1 ) + goto hit_idle_addr; + #else + if ( pc > 0x10000 ) + { + pc = WORD( pc - 1 ); + s_time -= 11; + goto loop; + } + #endif + CASE7( C7, CF, D7, DF, E7, EF, F7 ): + data = pc; + pc = opcode & 0x38; + #ifdef RST_BASE + pc += RST_BASE; + #endif + goto push_data; + +// PUSH/POP + case 0xF5: // PUSH AF + data = r.b.a * 0x100u + flags; + goto push_data; + + case 0xC5: // PUSH BC + case 0xD5: // PUSH DE + case 0xE5: // PUSH HL + data = R16( opcode, 4, 0xC5 ); + push_data: + sp = WORD( sp - 2 ); + WRITE_WORD( sp, data ); + goto loop; + + case 0xF1: // POP AF + flags = READ_MEM( sp ); + r.b.a = READ_MEM( (sp + 1) ); + sp = WORD( sp + 2 ); + goto loop; + + case 0xC1: // POP BC + case 0xD1: // POP DE + case 0xE1: // POP HL + R16( opcode, 4, 0xC1 ) = READ_WORD( sp ); + sp = WORD( sp + 2 ); + goto loop; + +// ADC/ADD/SBC/SUB + case 0x96: // SUB (HL) + case 0x86: // ADD (HL) + flags &= ~C01; + case 0x9E: // SBC (HL) + case 0x8E: // ADC (HL) + data = READ_MEM( r.w.hl ); + goto adc_data; + + case 0xD6: // SUB A,imm + case 0xC6: // ADD imm + flags &= ~C01; + case 0xDE: // SBC A,imm + case 0xCE: // ADC imm + pc++; + goto adc_data; + + CASE7( 90, 91, 92, 93, 94, 95, 97 ): // SUB r + CASE7( 80, 81, 82, 83, 84, 85, 87 ): // ADD r + flags &= ~C01; + CASE7( 98, 99, 9A, 9B, 9C, 9D, 9F ): // SBC r + CASE7( 88, 89, 8A, 8B, 8C, 8D, 8F ): // ADC r + data = R8( opcode & 7, 0 ); + adc_data: { + int result = data + (flags & C01); + data ^= r.b.a; + flags = opcode >> 3 & N02; // bit 4 is set in subtract opcodes + if ( flags ) + result = -result; + result += r.b.a; + data ^= result; + flags +=(data & H10) + + ((data + 0x80) >> 6 & V04) + + SZ28C( result & 0x1FF ); + r.b.a = result; + goto loop; + } + +// CP + case 0xBE: // CP (HL) + data = READ_MEM( r.w.hl ); + goto cp_data; + + case 0xFE: // CP imm + pc++; + goto cp_data; + + CASE7( B8, B9, BA, BB, BC, BD, BF ): // CP r + data = R8( opcode, 0xB8 ); + cp_data: { + int result = r.b.a - data; + flags = N02 + (data & (F20 | F08)) + (result >> 8 & C01); + data ^= r.b.a; + flags +=(((result ^ r.b.a) & data) >> 5 & V04) + + (((data & H10) ^ result) & (S80 | H10)); + if ( BYTE( result ) ) + goto loop; + flags += Z40; + goto loop; + } + +// ADD HL,r.w + + case 0x39: // ADD HL,SP + data = sp; + goto add_hl_data; + + case 0x09: // ADD HL,BC + case 0x19: // ADD HL,DE + case 0x29: // ADD HL,HL + data = R16( opcode, 4, 0x09 ); + add_hl_data: { + int sum = r.w.hl + data; + data ^= r.w.hl; + r.w.hl = sum; + flags = (flags & (S80 | Z40 | V04)) + + (sum >> 16) + + (sum >> 8 & (F20 | F08)) + + ((data ^ sum) >> 8 & H10); + goto loop; + } + + case 0x27:{// DAA + int a = r.b.a; + if ( a > 0x99 ) + flags |= C01; + + int adjust = 0x60 * (flags & C01); + + if ( flags & H10 || (a & 0x0F) > 9 ) + adjust += 0x06; + + if ( flags & N02 ) + adjust = -adjust; + a += adjust; + + flags = (flags & (C01 | N02)) + + ((r.b.a ^ a) & H10) + + SZ28P( BYTE( a ) ); + r.b.a = a; + goto loop; + } + +// INC/DEC + case 0x34: // INC (HL) + data = READ_MEM( r.w.hl ) + 1; + WRITE_MEM( r.w.hl, data ); + goto inc_set_flags; + + CASE7( 04, 0C, 14, 1C, 24, 2C, 3C ): // INC r + data = ++R8( opcode >> 3, 0 ); + inc_set_flags: + flags = (flags & C01) + + (((data & 0x0F) - 1) & H10) + + SZ28( BYTE( data ) ); + if ( data != 0x80 ) + goto loop; + flags += V04; + goto loop; + + case 0x35: // DEC (HL) + data = READ_MEM( r.w.hl ) - 1; + WRITE_MEM( r.w.hl, data ); + goto dec_set_flags; + + CASE7( 05, 0D, 15, 1D, 25, 2D, 3D ): // DEC r + data = --R8( opcode >> 3, 0 ); + dec_set_flags: + flags = (flags & C01) + N02 + + (((data & 0x0F) + 1) & H10) + + SZ28( BYTE( data ) ); + if ( data != 0x7F ) + goto loop; + flags += V04; + goto loop; + + case 0x03: // INC BC + case 0x13: // INC DE + case 0x23: // INC HL + R16( opcode, 4, 0x03 )++; + goto loop; + + case 0x33: // INC SP + sp = WORD( sp + 1 ); + goto loop; + + case 0x0B: // DEC BC + case 0x1B: // DEC DE + case 0x2B: // DEC HL + R16( opcode, 4, 0x0B )--; + goto loop; + + case 0x3B: // DEC SP + sp = WORD( sp - 1 ); + goto loop; + +// AND + case 0xA6: // AND (HL) + data = READ_MEM( r.w.hl ); + goto and_data; + + case 0xE6: // AND imm + pc++; + goto and_data; + + CASE7( A0, A1, A2, A3, A4, A5, A7 ): // AND r + data = R8( opcode, 0xA0 ); + and_data: + r.b.a &= data; + flags = SZ28P( r.b.a ) + H10; + goto loop; + +// OR + case 0xB6: // OR (HL) + data = READ_MEM( r.w.hl ); + goto or_data; + + case 0xF6: // OR imm + pc++; + goto or_data; + + CASE7( B0, B1, B2, B3, B4, B5, B7 ): // OR r + data = R8( opcode, 0xB0 ); + or_data: + r.b.a |= data; + flags = SZ28P( r.b.a ); + goto loop; + +// XOR + case 0xAE: // XOR (HL) + data = READ_MEM( r.w.hl ); + goto xor_data; + + case 0xEE: // XOR imm + pc++; + goto xor_data; + + CASE7( A8, A9, AA, AB, AC, AD, AF ): // XOR r + data = R8( opcode, 0xA8 ); + xor_data: + r.b.a ^= data; + flags = SZ28P( r.b.a ); + goto loop; + +// LD + CASE7( 70, 71, 72, 73, 74, 75, 77 ): // LD (HL),r + WRITE_MEM( r.w.hl, R8( opcode, 0x70 ) ); + goto loop; + + CASE6( 41, 42, 43, 44, 45, 47 ): // LD B,r + CASE6( 48, 4A, 4B, 4C, 4D, 4F ): // LD C,r + CASE6( 50, 51, 53, 54, 55, 57 ): // LD D,r + CASE6( 58, 59, 5A, 5C, 5D, 5F ): // LD E,r + CASE6( 60, 61, 62, 63, 65, 67 ): // LD H,r + CASE6( 68, 69, 6A, 6B, 6C, 6F ): // LD L,r + CASE6( 78, 79, 7A, 7B, 7C, 7D ): // LD A,r + R8( opcode >> 3 & 7, 0 ) = R8( opcode & 7, 0 ); + goto loop; + + CASE5( 06, 0E, 16, 1E, 26 ): // LD r,imm + R8( opcode >> 3, 0 ) = data; + pc++; + goto loop; + + case 0x36: // LD (HL),imm + pc++; + WRITE_MEM( r.w.hl, data ); + goto loop; + + CASE7( 46, 4E, 56, 5E, 66, 6E, 7E ): // LD r,(HL) + R8( opcode >> 3, 8 ) = READ_MEM( r.w.hl ); + goto loop; + + case 0x01: // LD r.w,imm + case 0x11: + case 0x21: + R16( opcode, 4, 0x01 ) = GET_ADDR(); + pc += 2; + goto loop; + + case 0x31: // LD sp,imm + sp = GET_ADDR(); + pc += 2; + goto loop; + + case 0x2A:{// LD HL,(addr) + int addr = GET_ADDR(); + pc += 2; + r.w.hl = READ_WORD( addr ); + goto loop; + } + + case 0x32:{// LD (addr),A + int addr = GET_ADDR(); + pc += 2; + WRITE_MEM( addr, r.b.a ); + goto loop; + } + + case 0x22:{// LD (addr),HL + int addr = GET_ADDR(); + pc += 2; + WRITE_WORD( addr, r.w.hl ); + goto loop; + } + + case 0x02: // LD (BC),A + case 0x12: // LD (DE),A + WRITE_MEM( R16( opcode, 4, 0x02 ), r.b.a ); + goto loop; + + case 0x0A: // LD A,(BC) + case 0x1A: // LD A,(DE) + r.b.a = READ_MEM( R16( opcode, 4, 0x0A ) ); + goto loop; + + case 0xF9: // LD SP,HL + sp = r.w.hl; + goto loop; + +// Rotate + + case 0x07:{// RLCA + int temp = r.b.a; + temp = (temp << 1) + (temp >> 7); + flags = (flags & (S80 | Z40 | P04)) + + (temp & (F20 | F08 | C01)); + r.b.a = temp; + goto loop; + } + + case 0x0F:{// RRCA + int temp = r.b.a; + flags = (flags & (S80 | Z40 | P04)) + + (temp & C01); + temp = (temp << 7) + (temp >> 1); + flags += temp & (F20 | F08); + r.b.a = temp; + goto loop; + } + + case 0x17:{// RLA + int temp = (r.b.a << 1) + (flags & C01); + flags = (flags & (S80 | Z40 | P04)) + + (temp & (F20 | F08)) + + (temp >> 8); + r.b.a = temp; + goto loop; + } + + case 0x1F:{// RRA + int temp = (flags << 7) + (r.b.a >> 1); + flags = (flags & (S80 | Z40 | P04)) + + (temp & (F20 | F08)) + + (r.b.a & C01); + r.b.a = temp; + goto loop; + } + +// Misc + case 0x2F:{// CPL + int temp = ~r.b.a; + flags = (flags & (S80 | Z40 | P04 | C01)) + + (temp & (F20 | F08)) + + (H10 | N02); + r.b.a = temp; + goto loop; + } + + case 0x3F:{// CCF + flags = ((flags & (S80 | Z40 | P04 | C01)) ^ C01) + + (flags << 4 & H10) + + (r.b.a & (F20 | F08)); + goto loop; + } + + case 0x37: // SCF + flags = ((flags & (S80 | Z40 | P04)) | C01) + + (r.b.a & (F20 | F08)); + goto loop; + + case 0xDB: // IN A,(imm) + pc++; + r.b.a = IN_PORT( (data + r.b.a * 0x100) ); + goto loop; + + case 0xE3:{// EX (SP),HL + int temp = READ_WORD( sp ); + WRITE_WORD( sp, r.w.hl ); + r.w.hl = temp; + goto loop; + } + + case 0xEB: // EX DE,HL + EX( r.w.hl, r.w.de ); + goto loop; + + case 0xD9: // EXX DE,HL + EXX( w.bc ); + EXX( w.de ); + EXX( w.hl ); + goto loop; + + case 0xF3: // DI + R.iff1 = 0; + R.iff2 = 0; + goto loop; + + case 0xFB: // EI + R.iff1 = 1; + R.iff2 = 1; + // TODO: delayed effect + goto loop; + + case 0x76: // HALT + goto halt; + +//////////////////////////////////////// CB prefix + { + case 0xCB: + pc++; + switch ( data ) + { + + // Rotate left + + #define RLC( read, write ) {\ + int result = read;\ + result = BYTE( result << 1 ) + (result >> 7);\ + flags = SZ28P( result ) + (result & C01);\ + write;\ + goto loop;\ + } + + case 0x06: // RLC (HL) + s_time += 7; + data = r.w.hl; + rlc_data_addr: + RLC( READ_MEM( data ), WRITE_MEM( data, result ) ) + + CASE7( 00, 01, 02, 03, 04, 05, 07 ):{// RLC r + byte* reg = &R8( data, 0 ); + RLC( *reg, *reg = result ) + } + + #define RL( read, write ) {\ + int result = (read << 1) + (flags & C01);\ + flags = SZ28PC( result );\ + write;\ + goto loop;\ + } + + case 0x16: // RL (HL) + s_time += 7; + data = r.w.hl; + rl_data_addr: + RL( READ_MEM( data ), WRITE_MEM( data, result ) ) + + CASE7( 10, 11, 12, 13, 14, 15, 17 ):{// RL r + byte* reg = &R8( data, 0x10 ); + RL( *reg, *reg = result ) + } + + #define SLA( read, low_bit, write ) {\ + int result = (read << 1) + low_bit;\ + flags = SZ28PC( result );\ + write;\ + goto loop;\ + } + + case 0x26: // SLA (HL) + s_time += 7; + data = r.w.hl; + sla_data_addr: + SLA( READ_MEM( data ), 0, WRITE_MEM( data, result ) ) + + CASE7( 20, 21, 22, 23, 24, 25, 27 ):{// SLA r + byte* reg = &R8( data, 0x20 ); + SLA( *reg, 0, *reg = result ) + } + + case 0x36: // SLL (HL) + s_time += 7; + data = r.w.hl; + sll_data_addr: + SLA( READ_MEM( data ), 1, WRITE_MEM( data, result ) ) + + CASE7( 30, 31, 32, 33, 34, 35, 37 ):{// SLL r + byte* reg = &R8( data, 0x30 ); + SLA( *reg, 1, *reg = result ) + } + + // Rotate right + + #define RRC( read, write ) {\ + int result = read;\ + flags = result & C01;\ + result = BYTE( result << 7 ) + (result >> 1);\ + flags += SZ28P( result );\ + write;\ + goto loop;\ + } + + case 0x0E: // RRC (HL) + s_time += 7; + data = r.w.hl; + rrc_data_addr: + RRC( READ_MEM( data ), WRITE_MEM( data, result ) ) + + CASE7( 08, 09, 0A, 0B, 0C, 0D, 0F ):{// RRC r + byte* reg = &R8( data, 0x08 ); + RRC( *reg, *reg = result ) + } + + #define RR( read, write ) {\ + int result = read;\ + int temp = result & C01;\ + result = BYTE( flags << 7 ) + (result >> 1);\ + flags = SZ28P( result ) + temp;\ + write;\ + goto loop;\ + } + + case 0x1E: // RR (HL) + s_time += 7; + data = r.w.hl; + rr_data_addr: + RR( READ_MEM( data ), WRITE_MEM( data, result ) ) + + CASE7( 18, 19, 1A, 1B, 1C, 1D, 1F ):{// RR r + byte* reg = &R8( data, 0x18 ); + RR( *reg, *reg = result ) + } + + #define SRA( read, write ) {\ + int result = read;\ + flags = result & C01;\ + result = (result & 0x80) + (result >> 1);\ + flags += SZ28P( result );\ + write;\ + goto loop;\ + } + + case 0x2E: // SRA (HL) + data = r.w.hl; + s_time += 7; + sra_data_addr: + SRA( READ_MEM( data ), WRITE_MEM( data, result ) ) + + CASE7( 28, 29, 2A, 2B, 2C, 2D, 2F ):{// SRA r + byte* reg = &R8( data, 0x28 ); + SRA( *reg, *reg = result ) + } + + #define SRL( read, write ) {\ + int result = read;\ + flags = result & C01;\ + result >>= 1;\ + flags += SZ28P( result );\ + write;\ + goto loop;\ + } + + case 0x3E: // SRL (HL) + s_time += 7; + data = r.w.hl; + srl_data_addr: + SRL( READ_MEM( data ), WRITE_MEM( data, result ) ) + + CASE7( 38, 39, 3A, 3B, 3C, 3D, 3F ):{// SRL r + byte* reg = &R8( data, 0x38 ); + SRL( *reg, *reg = result ) + } + + // BIT + { + int temp; + CASE8( 46, 4E, 56, 5E, 66, 6E, 76, 7E ): // BIT b,(HL) + s_time += 4; + temp = READ_MEM( r.w.hl ); + flags &= C01; + goto bit_temp; + CASE7( 40, 41, 42, 43, 44, 45, 47 ): // BIT 0,r + CASE7( 48, 49, 4A, 4B, 4C, 4D, 4F ): // BIT 1,r + CASE7( 50, 51, 52, 53, 54, 55, 57 ): // BIT 2,r + CASE7( 58, 59, 5A, 5B, 5C, 5D, 5F ): // BIT 3,r + CASE7( 60, 61, 62, 63, 64, 65, 67 ): // BIT 4,r + CASE7( 68, 69, 6A, 6B, 6C, 6D, 6F ): // BIT 5,r + CASE7( 70, 71, 72, 73, 74, 75, 77 ): // BIT 6,r + CASE7( 78, 79, 7A, 7B, 7C, 7D, 7F ): // BIT 7,r + temp = R8( data & 7, 0 ); + flags = (flags & C01) + (temp & (F20 | F08)); + bit_temp: + temp = temp & (1 << (data >> 3 & 7)); + flags += (temp & S80) + H10; + flags += (unsigned) --temp >> 8 & (Z40 | P04); + goto loop; + } + + // SET/RES + CASE8( 86, 8E, 96, 9E, A6, AE, B6, BE ): // RES b,(HL) + CASE8( C6, CE, D6, DE, E6, EE, F6, FE ):{// SET b,(HL) + s_time += 7; + int temp = READ_MEM( r.w.hl ); + int bit = 1 << (data >> 3 & 7); + temp |= bit; // SET + if ( !(data & 0x40) ) + temp ^= bit; // RES + WRITE_MEM( r.w.hl, temp ); + goto loop; + } + + CASE7( C0, C1, C2, C3, C4, C5, C7 ): // SET 0,r + CASE7( C8, C9, CA, CB, CC, CD, CF ): // SET 1,r + CASE7( D0, D1, D2, D3, D4, D5, D7 ): // SET 2,r + CASE7( D8, D9, DA, DB, DC, DD, DF ): // SET 3,r + CASE7( E0, E1, E2, E3, E4, E5, E7 ): // SET 4,r + CASE7( E8, E9, EA, EB, EC, ED, EF ): // SET 5,r + CASE7( F0, F1, F2, F3, F4, F5, F7 ): // SET 6,r + CASE7( F8, F9, FA, FB, FC, FD, FF ): // SET 7,r + R8( data & 7, 0 ) |= 1 << (data >> 3 & 7); + goto loop; + + CASE7( 80, 81, 82, 83, 84, 85, 87 ): // RES 0,r + CASE7( 88, 89, 8A, 8B, 8C, 8D, 8F ): // RES 1,r + CASE7( 90, 91, 92, 93, 94, 95, 97 ): // RES 2,r + CASE7( 98, 99, 9A, 9B, 9C, 9D, 9F ): // RES 3,r + CASE7( A0, A1, A2, A3, A4, A5, A7 ): // RES 4,r + CASE7( A8, A9, AA, AB, AC, AD, AF ): // RES 5,r + CASE7( B0, B1, B2, B3, B4, B5, B7 ): // RES 6,r + CASE7( B8, B9, BA, BB, BC, BD, BF ): // RES 7,r + R8( data & 7, 0 ) &= ~(1 << (data >> 3 & 7)); + goto loop; + } + assert( false ); + } + +#undef GET_ADDR +#define GET_ADDR() GET_LE16( &INSTR( 1, pc ) ) + +//////////////////////////////////////// ED prefix + { + case 0xED: + pc++; + s_time += (clock_table + 256) [data] >> 4; + switch ( data ) + { + { + int temp; + case 0x72: // SBC HL,SP + case 0x7A: // ADC HL,SP + temp = sp; + if ( 0 ) + case 0x42: // SBC HL,BC + case 0x52: // SBC HL,DE + case 0x62: // SBC HL,HL + case 0x4A: // ADC HL,BC + case 0x5A: // ADC HL,DE + case 0x6A: // ADC HL,HL + temp = R16( data >> 3 & 6, 1, 0 ); + int sum = temp + (flags & C01); + flags = ~data >> 2 & N02; + if ( flags ) + sum = -sum; + sum += r.w.hl; + temp ^= r.w.hl; + temp ^= sum; + flags +=(sum >> 16 & C01) + + (temp >> 8 & H10) + + (sum >> 8 & (S80 | F20 | F08)) + + ((temp + 0x8000) >> 14 & V04); + r.w.hl = sum; + if ( WORD( sum ) ) + goto loop; + flags += Z40; + goto loop; + } + + CASE8( 40, 48, 50, 58, 60, 68, 70, 78 ):{// IN r,(C) + int temp = IN_PORT( r.w.bc ); + R8( data >> 3, 8 ) = temp; + flags = (flags & C01) + SZ28P( temp ); + goto loop; + } + + case 0x71: // OUT (C),0 + r.b.flags = 0; + CASE7( 41, 49, 51, 59, 61, 69, 79 ): // OUT (C),r + OUT_PORT( r.w.bc, R8( data >> 3, 8 ) ); + goto loop; + + { + int temp; + case 0x73: // LD (ADDR),SP + temp = sp; + if ( 0 ) + case 0x43: // LD (ADDR),BC + case 0x53: // LD (ADDR),DE + temp = R16( data, 4, 0x43 ); + int addr = GET_ADDR(); + pc += 2; + WRITE_WORD( addr, temp ); + goto loop; + } + + case 0x4B: // LD BC,(ADDR) + case 0x5B:{// LD DE,(ADDR) + int addr = GET_ADDR(); + pc += 2; + R16( data, 4, 0x4B ) = READ_WORD( addr ); + goto loop; + } + + case 0x7B:{// LD SP,(ADDR) + int addr = GET_ADDR(); + pc += 2; + sp = READ_WORD( addr ); + goto loop; + } + + case 0x67:{// RRD + int temp = READ_MEM( r.w.hl ); + WRITE_MEM( r.w.hl, ((r.b.a << 4) + (temp >> 4)) ); + temp = (r.b.a & 0xF0) + (temp & 0x0F); + flags = (flags & C01) + SZ28P( temp ); + r.b.a = temp; + goto loop; + } + + case 0x6F:{// RLD + int temp = READ_MEM( r.w.hl ); + WRITE_MEM( r.w.hl, ((temp << 4) + (r.b.a & 0x0F)) ); + temp = (r.b.a & 0xF0) + (temp >> 4); + flags = (flags & C01) + SZ28P( temp ); + r.b.a = temp; + goto loop; + } + + CASE8( 44, 4C, 54, 5C, 64, 6C, 74, 7C ): // NEG + opcode = 0x10; // flag to do SBC instead of ADC + flags &= ~C01; + data = r.b.a; + r.b.a = 0; + goto adc_data; + + { + int inc; + case 0xA9: // CPD + case 0xB9: // CPDR + inc = -1; + if ( 0 ) + case 0xA1: // CPI + case 0xB1: // CPIR + inc = +1; + int addr = r.w.hl; + r.w.hl = addr + inc; + int temp = READ_MEM( addr ); + + int result = r.b.a - temp; + flags = (flags & C01) + N02 + + ((((temp ^ r.b.a) & H10) ^ result) & (S80 | H10)); + + if ( !BYTE( result ) ) + flags += Z40; + result -= (flags & H10) >> 4; + flags += result & F08; + flags += result << 4 & F20; + if ( !--r.w.bc ) + goto loop; + + flags += V04; + if ( flags & Z40 || data < 0xB0 ) + goto loop; + + pc -= 2; + s_time += 5; + goto loop; + } + + { + int inc; + case 0xA8: // LDD + case 0xB8: // LDDR + inc = -1; + if ( 0 ) + case 0xA0: // LDI + case 0xB0: // LDIR + inc = +1; + int addr = r.w.hl; + r.w.hl = addr + inc; + int temp = READ_MEM( addr ); + + addr = r.w.de; + r.w.de = addr + inc; + WRITE_MEM( addr, temp ); + + temp += r.b.a; + flags = (flags & (S80 | Z40 | C01)) + + (temp & F08) + (temp << 4 & F20); + if ( !--r.w.bc ) + goto loop; + + flags += V04; + if ( data < 0xB0 ) + goto loop; + + pc -= 2; + s_time += 5; + goto loop; + } + + { + int inc; + case 0xAB: // OUTD + case 0xBB: // OTDR + inc = -1; + if ( 0 ) + case 0xA3: // OUTI + case 0xB3: // OTIR + inc = +1; + int addr = r.w.hl; + r.w.hl = addr + inc; + int temp = READ_MEM( addr ); + + int b = --r.b.b; + flags = (temp >> 6 & N02) + SZ28( b ); + if ( b && data >= 0xB0 ) + { + pc -= 2; + s_time += 5; + } + + OUT_PORT( r.w.bc, temp ); + goto loop; + } + + { + int inc; + case 0xAA: // IND + case 0xBA: // INDR + inc = -1; + if ( 0 ) + case 0xA2: // INI + case 0xB2: // INIR + inc = +1; + + int addr = r.w.hl; + r.w.hl = addr + inc; + + int temp = IN_PORT( r.w.bc ); + + int b = --r.b.b; + flags = (temp >> 6 & N02) + SZ28( b ); + if ( b && data >= 0xB0 ) + { + pc -= 2; + s_time += 5; + } + + WRITE_MEM( addr, temp ); + goto loop; + } + + case 0x47: // LD I,A + R.i = r.b.a; + goto loop; + + case 0x4F: // LD R,A + SET_R( r.b.a ); + dprintf( "LD R,A not supported\n" ); + warning = true; + goto loop; + + case 0x57: // LD A,I + r.b.a = R.i; + goto ld_ai_common; + + case 0x5F: // LD A,R + r.b.a = GET_R(); + dprintf( "LD A,R not supported\n" ); + warning = true; + ld_ai_common: + flags = (flags & C01) + SZ28( r.b.a ) + (R.iff2 << 2 & V04); + goto loop; + + CASE8( 45, 4D, 55, 5D, 65, 6D, 75, 7D ): // RETI/RETN + R.iff1 = R.iff2; + goto ret_taken; + + case 0x46: case 0x4E: case 0x66: case 0x6E: // IM 0 + R.im = 0; + goto loop; + + case 0x56: case 0x76: // IM 1 + R.im = 1; + goto loop; + + case 0x5E: case 0x7E: // IM 2 + R.im = 2; + goto loop; + + default: + dprintf( "Opcode $ED $%02X not supported\n", data ); + warning = true; + goto loop; + } + assert( false ); + } + +//////////////////////////////////////// DD/FD prefix + { + int ixy; + case 0xDD: + ixy = ix; + goto ix_prefix; + case 0xFD: + ixy = iy; + ix_prefix: + pc++; + int data2 = READ_CODE( pc ); + s_time += (clock_table + 256) [data] & 0x0F; + switch ( data ) + { + // TODO: more efficient way of avoid negative address + // TODO: avoid using this as argument to READ_MEM() since it is evaluated twice + #define IXY_DISP( ixy, disp ) WORD( (ixy ) + (disp)) + + #define SET_IXY( in ) if ( opcode == 0xDD ) ix = in; else iy = in; + + // ADD/ADC/SUB/SBC + + case 0x96: // SUB (IXY+disp) + case 0x86: // ADD (IXY+disp) + flags &= ~C01; + case 0x9E: // SBC (IXY+disp) + case 0x8E: // ADC (IXY+disp) + pc++; + opcode = data; + data = READ_MEM( IXY_DISP( ixy, SBYTE( data2 ) ) ); + goto adc_data; + + case 0x94: // SUB HXY + case 0x84: // ADD HXY + flags &= ~C01; + case 0x9C: // SBC HXY + case 0x8C: // ADC HXY + opcode = data; + data = ixy >> 8; + goto adc_data; + + case 0x95: // SUB LXY + case 0x85: // ADD LXY + flags &= ~C01; + case 0x9D: // SBC LXY + case 0x8D: // ADC LXY + opcode = data; + data = BYTE( ixy ); + goto adc_data; + + { + int temp; + case 0x39: // ADD IXY,SP + temp = sp; + goto add_ixy_data; + + case 0x29: // ADD IXY,HL + temp = ixy; + goto add_ixy_data; + + case 0x09: // ADD IXY,BC + case 0x19: // ADD IXY,DE + temp = R16( data, 4, 0x09 ); + add_ixy_data: { + int sum = ixy + temp; + temp ^= ixy; + ixy = WORD( sum ); + flags = (flags & (S80 | Z40 | V04)) + + (sum >> 16) + + (sum >> 8 & (F20 | F08)) + + ((temp ^ sum) >> 8 & H10); + goto set_ixy; + } + } + + // AND + case 0xA6: // AND (IXY+disp) + pc++; + data = READ_MEM( IXY_DISP( ixy, SBYTE( data2 ) ) ); + goto and_data; + + case 0xA4: // AND HXY + data = ixy >> 8; + goto and_data; + + case 0xA5: // AND LXY + data = BYTE( ixy ); + goto and_data; + + // OR + case 0xB6: // OR (IXY+disp) + pc++; + data = READ_MEM( IXY_DISP( ixy, SBYTE( data2 ) ) ); + goto or_data; + + case 0xB4: // OR HXY + data = ixy >> 8; + goto or_data; + + case 0xB5: // OR LXY + data = BYTE( ixy ); + goto or_data; + + // XOR + case 0xAE: // XOR (IXY+disp) + pc++; + data = READ_MEM( IXY_DISP( ixy, SBYTE( data2 ) ) ); + goto xor_data; + + case 0xAC: // XOR HXY + data = ixy >> 8; + goto xor_data; + + case 0xAD: // XOR LXY + data = BYTE( ixy ); + goto xor_data; + + // CP + case 0xBE: // CP (IXY+disp) + pc++; + data = READ_MEM( IXY_DISP( ixy, SBYTE( data2 ) ) ); + goto cp_data; + + case 0xBC: // CP HXY + data = ixy >> 8; + goto cp_data; + + case 0xBD: // CP LXY + data = BYTE( ixy ); + goto cp_data; + + // LD + CASE7( 70, 71, 72, 73, 74, 75, 77 ): // LD (IXY+disp),r + data = R8( data, 0x70 ); + if ( 0 ) + case 0x36: // LD (IXY+disp),imm + pc++, data = READ_CODE( pc ); + pc++; + WRITE_MEM( IXY_DISP( ixy, SBYTE( data2 ) ), data ); + goto loop; + + CASE5( 44, 4C, 54, 5C, 7C ): // LD r,HXY + R8( data >> 3, 8 ) = ixy >> 8; + goto loop; + + case 0x64: // LD HXY,HXY + case 0x6D: // LD LXY,LXY + goto loop; + + CASE5( 45, 4D, 55, 5D, 7D ): // LD r,LXY + R8( data >> 3, 8 ) = ixy; + goto loop; + + CASE7( 46, 4E, 56, 5E, 66, 6E, 7E ): // LD r,(IXY+disp) + pc++; + R8( data >> 3, 8 ) = READ_MEM( IXY_DISP( ixy, SBYTE( data2 ) ) ); + goto loop; + + case 0x26: // LD HXY,imm + pc++; + goto ld_hxy_data; + + case 0x65: // LD HXY,LXY + data2 = BYTE( ixy ); + goto ld_hxy_data; + + CASE5( 60, 61, 62, 63, 67 ): // LD HXY,r + data2 = R8( data, 0x60 ); + ld_hxy_data: + ixy = BYTE( ixy ) + (data2 << 8); + goto set_ixy; + + case 0x2E: // LD LXY,imm + pc++; + goto ld_lxy_data; + + case 0x6C: // LD LXY,HXY + data2 = ixy >> 8; + goto ld_lxy_data; + + CASE5( 68, 69, 6A, 6B, 6F ): // LD LXY,r + data2 = R8( data, 0x68 ); + ld_lxy_data: + ixy = (ixy & 0xFF00) + data2; + set_ixy: + if ( opcode == 0xDD ) + { + ix = ixy; + goto loop; + } + iy = ixy; + goto loop; + + case 0xF9: // LD SP,IXY + sp = ixy; + goto loop; + + case 0x22:{// LD (ADDR),IXY + int addr = GET_ADDR(); + pc += 2; + WRITE_WORD( addr, ixy ); + goto loop; + } + + case 0x21: // LD IXY,imm + ixy = GET_ADDR(); + pc += 2; + goto set_ixy; + + case 0x2A:{// LD IXY,(addr) + int addr = GET_ADDR(); + ixy = READ_WORD( addr ); + pc += 2; + goto set_ixy; + } + + // DD/FD CB prefix + case 0xCB: { + data = IXY_DISP( ixy, SBYTE( data2 ) ); + pc++; + data2 = READ_CODE( pc ); + pc++; + switch ( data2 ) + { + case 0x06: goto rlc_data_addr; // RLC (IXY) + case 0x16: goto rl_data_addr; // RL (IXY) + case 0x26: goto sla_data_addr; // SLA (IXY) + case 0x36: goto sll_data_addr; // SLL (IXY) + case 0x0E: goto rrc_data_addr; // RRC (IXY) + case 0x1E: goto rr_data_addr; // RR (IXY) + case 0x2E: goto sra_data_addr; // SRA (IXY) + case 0x3E: goto srl_data_addr; // SRL (IXY) + + CASE8( 46, 4E, 56, 5E, 66, 6E, 76, 7E ):{// BIT b,(IXY+disp) + int temp = READ_MEM( data ); + temp = temp & (1 << (data2 >> 3 & 7)); + flags = (flags & C01) + H10 + (temp & S80); + flags += (unsigned) --temp >> 8 & (Z40 | P04); + goto loop; + } + + CASE8( 86, 8E, 96, 9E, A6, AE, B6, BE ): // RES b,(IXY+disp) + CASE8( C6, CE, D6, DE, E6, EE, F6, FE ):{// SET b,(IXY+disp) + int temp = READ_MEM( data ); + int bit = 1 << (data2 >> 3 & 7); + temp |= bit; // SET + if ( !(data2 & 0x40) ) + temp ^= bit; // RES + WRITE_MEM( data, temp ); + goto loop; + } + + default: + dprintf( "Opcode $%02X $CB $%02X not supported\n", opcode, data2 ); + warning = true; + goto loop; + } + assert( false ); + } + + // INC/DEC + case 0x23: // INC IXY + ixy = WORD( ixy + 1 ); + goto set_ixy; + + case 0x2B: // DEC IXY + ixy = WORD( ixy - 1 ); + goto set_ixy; + + case 0x34: // INC (IXY+disp) + ixy = IXY_DISP( ixy, SBYTE( data2 ) ); + pc++; + data = READ_MEM( ixy ) + 1; + WRITE_MEM( ixy, data ); + goto inc_set_flags; + + case 0x35: // DEC (IXY+disp) + ixy = IXY_DISP( ixy, SBYTE( data2 ) ); + pc++; + data = READ_MEM( ixy ) - 1; + WRITE_MEM( ixy, data ); + goto dec_set_flags; + + case 0x24: // INC HXY + ixy = WORD( ixy + 0x100 ); + data = ixy >> 8; + goto inc_xy_common; + + case 0x2C: // INC LXY + data = BYTE( ixy + 1 ); + ixy = (ixy & 0xFF00) + data; + inc_xy_common: + if ( opcode == 0xDD ) + { + ix = ixy; + goto inc_set_flags; + } + iy = ixy; + goto inc_set_flags; + + case 0x25: // DEC HXY + ixy = WORD( ixy - 0x100 ); + data = ixy >> 8; + goto dec_xy_common; + + case 0x2D: // DEC LXY + data = BYTE( ixy - 1 ); + ixy = (ixy & 0xFF00) + data; + dec_xy_common: + if ( opcode == 0xDD ) + { + ix = ixy; + goto dec_set_flags; + } + iy = ixy; + goto dec_set_flags; + + // PUSH/POP + case 0xE5: // PUSH IXY + data = ixy; + goto push_data; + + case 0xE1:{// POP IXY + ixy = READ_WORD( sp ); + sp = WORD( sp + 2 ); + goto set_ixy; + } + + // Misc + + case 0xE9: // JP (IXY) + pc = ixy; + goto loop; + + case 0xE3:{// EX (SP),IXY + int temp = READ_WORD( sp ); + WRITE_WORD( sp, ixy ); + ixy = temp; + goto set_ixy; + } + + default: + dprintf( "Unnecessary DD/FD prefix encountered\n" ); + warning = true; + pc--; + goto loop; + } + assert( false ); + } + + } + dprintf( "Unhandled main opcode: $%02X\n", opcode ); + assert( false ); + +#ifdef IDLE_ADDR +hit_idle_addr: + s_time -= 11; + goto out_of_time; +#endif +halt: + s_time &= 3; // increment by multiple of 4 +out_of_time: + pc--; + + r.b.flags = flags; + R.ix = ix; + R.iy = iy; + R.sp = sp; + R.pc = pc; + R.b = r.b; + + cpu->cpu_state_.base = s.base; + cpu->cpu_state_.time = s_time; + cpu->cpu_state = &cpu->cpu_state_; +} diff --git a/apps/lang/arabic.lang b/apps/lang/arabic.lang index 12e84c819b..b9450c1710 100644 --- a/apps/lang/arabic.lang +++ b/apps/lang/arabic.lang @@ -7010,17 +7010,17 @@ radio: "قائمة اذاعة ا٠ام" - - id: LANG_FILESIZE - desc: in record timesplit options and in track information viewer - user: core - - *: "Filesize" - - - *: "حجم الملÙ" - - - *: "حجم الملÙ" - + + id: LANG_FILESIZE + desc: in record timesplit options and in track information viewer + user: core + + *: "Filesize" + + + *: "حجم الملÙ" + + + *: "حجم الملÙ" + diff --git a/apps/lang/latviesu.lang b/apps/lang/latviesu.lang index 0fb0afa417..866820d4f3 100644 --- a/apps/lang/latviesu.lang +++ b/apps/lang/latviesu.lang @@ -1,12750 +1,12750 @@ -# __________ __ ___. -# Open \______ \ ____ ____ | | _\_ |__ _______ ___ -# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / -# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < -# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ -# \/ \/ \/ \/ \/ -# $Id$ -# -# This program 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. -# -# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY -# KIND, either express or implied. -# -# -# Latvian language file, translated by MÄrtiņš Å imis jeb msh - - - id: LANG_SET_BOOL_YES - desc: bool true representation - user: core - - *: "Yes" - - - *: "JÄ" - - - *: "jaa" - - - - id: LANG_SET_BOOL_NO - desc: bool false representation - user: core - - *: "No" - - - *: "NÄ“" - - - *: "nee" - - - - id: LANG_ON - desc: Used in a lot of places - user: core - - *: "On" - - - *: "IeslÄ“gts" - - - *: "iesleegts" - - - - id: LANG_OFF - desc: Used in a lot of places - user: core - - *: "Off" - - - *: "IzslÄ“gts" - - - *: "izsleegts" - - - - id: LANG_ASK - desc: in settings_menu - user: core - - *: "Ask" - - - *: "PrasÄ«t" - - - *: "prasiit" - - - - id: LANG_ALWAYS - desc: used in various places - user: core - - *: "Always" - - - *: "VienmÄ“r" - - - *: "vienmeer" - - - - id: LANG_NORMAL - desc: in settings_menu - user: core - - *: "Normal" - - - *: "NormÄls" - - - *: "normaals" - - - - id: LANG_GAIN - desc: Generic string for gain used in EQ menu and recording screen - user: core - - *: "Gain" - - - *: "PastiprinÄjums" - - - *: "pastiprinaajums" - - - - id: LANG_WAIT - desc: general please wait splash - user: core - - *: "Loading..." - - - *: "IelÄdÄ“..." - - - *: "notiek ielaade" - - - - id: LANG_LOADING_PERCENT - desc: splash number of percents loaded - user: core - - *: "Loading... %d%% done (%s)" - - - *: "ielaade... %d%% gatavs (%s)" - - - *: "" - - - - id: LANG_SCANNING_DISK - desc: when booting up and rebuilding the cache and calculating free space - user: core - - *: "Scanning disk..." - - - *: "SkanÄ“ atmiņu..." - - - *: "skanee atminju" - - - - id: LANG_SHUTTINGDOWN - desc: in main menu - user: core - - *: "Shutting down..." - - - *: "IzslÄ“dzas..." - - - *: "izsleedzas" - - - - id: LANG_CANCEL - desc: Visual confirmation of canceling a changed setting - user: core - - *: "Cancelled" - - - *: "Atcelts" - - - *: "atcelts" - - - - id: LANG_FAILED - desc: Something failed. To be appended after actions - user: core - - *: "Failed" - - - *: "NeizdevÄs" - - - *: "neizdevaas" - - - - id: LANG_CHANNELS - desc: in sound_settings - user: core - - *: "Channels" - - - *: "KanÄli" - - - *: "kanaali" - - - - id: LANG_RESET_ASK - desc: confirm to reset settings - user: core - - *: "Are You Sure?" - - - *: "Vai esi pÄrliecinÄts?" - - - *: "vai esi paarliecinaats" - - - - id: LANG_CONFIRM_WITH_BUTTON - desc: Generic string to use to confirm - user: core - - *: "PLAY = Yes" - cowond2*: "MENU, or top-right = Yes" - iriverh100,iriverh120,iriverh300: "NAVI = Yes" - samsungyh*,ipod*,iaudiox5,iaudiom5,gigabeat*,sansae200*,sansac200*,iriverh10,iriverh10_5gb,mrobe100,sansaclip*,sansafuze*: "SELECT = Yes" - mrobe500: "PLAY, POWER, or top-right = Yes" - archosplayer: "(PLAY/STOP)" - vibe500: "OK = Yes" - - - *: "PLAY = JÄ" - cowond2*: "MENU, vai labÄ augÅ¡Ä“jÄ = JÄ" - iriverh100,iriverh120,iriverh300: "NAVI = JÄ" - samsungyh*,ipod*,iaudiox5,iaudiom5,gigabeat*,sansae200*,sansac200*,iriverh10,iriverh10_5gb,mrobe100,sansaclip*,sansafuze*: "SELECT = JÄ" - mrobe500: "PLAY, POWER, vai labÄ augÅ¡Ä“jÄ = JÄ" - archosplayer: "(PLAY/STOP)" - vibe500: "OK = JÄ" - - - *: "" - - - - id: LANG_CANCEL_WITH_ANY - desc: Generic string to use to cancel - user: core - - *: "Any Other = No" - archosplayer: none - - - *: "Jebkas cits = NÄ“" - archosplayer: none - - - *: "" - archosplayer: none - - - - id: LANG_ROCKBOX_TITLE - desc: main menu title - user: core - - *: "Rockbox" - - - *: "Rockbox" - - - *: "Rockbox" - - - - id: LANG_BOOKMARK_MENU_RECENT_BOOKMARKS - desc: in the main menu - user: core - - *: "Recent Bookmarks" - - - *: "NesenÄs GrÄmatzÄ«mes" - - - *: "nesenaas graamatziimes" - - - - id: LANG_DIR_BROWSER - desc: main menu title - user: core - - *: "Files" - - - *: "Faili" - - - *: "faili" - - - - id: LANG_TAGCACHE - desc: in the main menu and the settings menu - user: core - - *: "Database" - - - *: "DatubÄze" - - - *: "datubaaze" - - - - id: LANG_NOW_PLAYING - desc: in the main menu - user: core - - *: "Now Playing" - - - *: "Å obrÄ«d Atskaņo" - - - *: "shobriid atskanjo" - - - - id: LANG_RESUME_PLAYBACK - desc: in the main menu - user: core - - *: "Resume Playback" - - - *: "TurpinÄt AtskaņoÅ¡anu" - - - *: "turpinaat atskanjoshanu" - - - - id: LANG_SETTINGS - desc: in main menu and visual confirmation after settings reset - user: core - - *: "Settings" - - - *: "UzstÄdÄ«jumi" - - - *: "uzstaadiijumi" - - - - id: LANG_RECORDING - desc: in the main menu - user: core - - *: none - recording: "Recording" - - - *: none - recording: "IerakstÄ«Å¡ana" - - - *: none - recording: "ierakstiishana" - - - - id: LANG_FM_RADIO - desc: in the main menu - user: core - - *: none - radio: "FM Radio" - - - *: none - radio: "FM Radio" - - - *: none - radio: "fm radio" - - - - id: LANG_PLAYLISTS - desc: in the file view setting - user: core - - *: "Playlists" - - - *: "Izlases" - - - *: "izlases" - - - - id: LANG_PLUGINS - desc: in the main menu - user: core - - *: "Plugins" - - - *: "Spraudņi" - - - *: "spraudnji" - - - - id: LANG_SYSTEM - desc: in the main menu and settings menu - user: core - - *: "System" - - - *: "SistÄ“ma" - - - *: "sisteema" - - - - id: LANG_BOOKMARK_SELECT_BOOKMARK - desc: bookmark selection list title - user: core - - *: "Select Bookmark" - - - *: "IzvÄ“lÄ“ties GrÄmatzÄ«mi" - - - *: "izveeleeties graamatziimi" - - - - id: LANG_BOOKMARK_DONT_RESUME - desc: top item in the list when asking user about bookmark auto load - user: core - - *: "" - - - *: "" - - - *: "neatsaakt" - - - - id: LANG_BOOKMARK_SHUFFLE - desc: bookmark selection list, bookmark enables shuffle - user: core - - *: ", Shuffle" - - - *: ", PÄrmaiņus" - - - *: "" - - - - id: LANG_BOOKMARK_INVALID - desc: bookmark selection list, bookmark couldn't be parsed - user: core - - *: "" - - - *: "" - - - *: "nederiiga graamatziime" - - - - id: LANG_BOOKMARK_CONTEXT_MENU - desc: bookmark selection list context menu - user: core - - *: "Bookmark Actions" - - - *: "GrÄmatzÄ«mju DarbÄ«bas" - - - *: "graamatziimju darbiibas" - - - - id: LANG_BOOKMARK_CONTEXT_RESUME - desc: bookmark context menu, resume this bookmark - user: core - - *: "Resume" - - - *: "AtsÄkt" - - - *: "atsaakt" - - - - id: LANG_BOOKMARK_CONTEXT_DELETE - desc: bookmark context menu, delete this bookmark - user: core - - *: "Delete" - - - *: "IzdzÄ“st" - - - *: "izdzeest" - - - - id: LANG_AUTO_BOOKMARK_QUERY - desc: prompt for user to decide to create an bookmark - user: core - - *: "Create a Bookmark?" - - - *: "Izveidot GrÄmatzÄ«mi?" - - - *: "vai izveidot graamatziimi" - - - - id: LANG_BOOKMARK_CREATE_SUCCESS - desc: Indicates bookmark was successfully created - user: core - - *: "Bookmark Created" - - - *: "GrÄmatzÄ«me Izveidota" - - - *: "graamatziime izveidota" - - - - id: LANG_BOOKMARK_CREATE_FAILURE - desc: Indicates bookmark was not created - user: core - - *: "Bookmark Failed!" - - - *: "NeizdevÄs Izveidot!" - - - *: "neizdevaas izveidot" - - - - id: LANG_BOOKMARK_LOAD_EMPTY - desc: Indicates bookmark was empty - user: core - - *: "Bookmark Empty" - - - *: "TukÅ¡a GrÄmatzÄ«me" - - - *: "tuksha graamatziime" - - - - id: LANG_SOUND_SETTINGS - desc: in the main menu - user: core - - *: "Sound Settings" - - - *: "Skaņas UzstÄdÄ«jumi" - - - *: "skanjas uzstaadiijumi" - - - - id: LANG_VOLUME - desc: in sound_settings - user: core - - *: "Volume" - - - *: "Skaļums" - - - *: "skaljums" - - - - id: LANG_BASS - desc: in sound_settings - user: core - - *: "Bass" - - - *: "Basi" - - - *: "basi" - - - - id: LANG_TREBLE - desc: in sound_settings - user: core - - *: "Treble" - - - *: "AugÅ¡as" - - - *: "augshas" - - - - id: LANG_BALANCE - desc: in sound_settings - user: core - - *: "Balance" - - - *: "Balanss" - - - *: "balanss" - - - - id: LANG_CHANNEL_CONFIGURATION - desc: in sound_settings - user: core - - *: "Channel Configuration" - - - *: "KanÄlu KonfigurÄcija" - - - *: "kanaalu konfiguraacija" - - - - id: LANG_CHANNEL_STEREO - desc: in sound_settings - user: core - - *: "Stereo" - - - *: "Stereo" - - - *: "stereo" - - - - id: LANG_CHANNEL_MONO - desc: in sound_settings - user: core - - *: "Mono" - - - *: "Mono" - - - *: "mono" - - - - id: LANG_CHANNEL_CUSTOM - desc: in sound_settings - user: core - - *: "Custom" - - - *: "Nestandarta" - - - *: "nestandarta" - - - - id: LANG_CHANNEL_LEFT - desc: in sound_settings - user: core - - *: "Mono Left" - - - *: "Mono Kreisais" - - - *: "mono kreisais" - - - - id: LANG_CHANNEL_RIGHT - desc: in sound_settings - user: core - - *: "Mono Right" - - - *: "Mono Labais" - - - *: "mono labais" - - - - id: LANG_CHANNEL_LEFTRIGHT - desc: in sound_settings - user: core - - *: none - recording_swcodec: "Mono Left + Right" - - - *: none - recording_swcodec: "Kreisais + Labais" - - - *: none - recording_swcodec: "mono kreisais plus labais" - - - - id: LANG_CHANNEL_KARAOKE - desc: in sound_settings - user: core - - *: "Karaoke" - - - *: "Karaoke" - - - *: "karaoke" - - - - id: LANG_STEREO_WIDTH - desc: in sound_settings - user: core - - *: "Stereo Width" - - - *: "Stereo Platums" - - - *: "stereo platums" - - - - id: LANG_CROSSFEED - desc: in sound settings - user: core - - *: none - swcodec: "Crossfeed" - - - *: none - swcodec: "KanÄlu IzlÄ«dzinÄÅ¡ana" - - - *: none - swcodec: "kanaalu izliidzinaashana" - - - - id: LANG_CROSSFEED_DIRECT_GAIN - desc: in crossfeed settings - user: core - - *: none - swcodec: "Direct Gain" - - - *: none - swcodec: "TieÅ¡ais Skaļums" - - - *: none - swcodec: "tieshais skaljums" - - - - id: LANG_CROSSFEED_CROSS_GAIN - desc: in crossfeed settings - user: core - - *: none - swcodec: "Cross Gain" - - - *: none - swcodec: "Starpskaļums" - - - *: none - swcodec: "starpskaljums" - - - - id: LANG_CROSSFEED_HF_ATTENUATION - desc: in crossfeed settings - user: core - - *: none - swcodec: "High-Frequency Attenuation" - - - *: none - swcodec: "Augsto FrekvenÄu VÄjinÄjums" - - - *: none - swcodec: "augsto frekvenchu vaajinaajums" - - - - id: LANG_CROSSFEED_HF_CUTOFF - desc: in crossfeed settings - user: core - - *: none - swcodec: "High-Frequency Cutoff" - - - *: none - swcodec: "Augsto FrekvenÄu SÄkums" - - - *: none - swcodec: "augsto frekvenchu saakums" - - - - id: LANG_EQUALIZER - desc: in the sound settings menu - user: core - - *: none - swcodec: "Equalizer" - - - *: none - swcodec: "Ekvalaizers" - - - *: none - swcodec: "ekvalaizers" - - - - id: LANG_EQUALIZER_ENABLED - desc: in the equalizer settings menu - user: core - - *: none - swcodec: "Enable EQ" - - - *: none - swcodec: "IeslÄ“gt Ekvalaizeru" - - - *: none - swcodec: "ieslÄ“gt ekvalaizeru" - - - - id: LANG_EQUALIZER_GRAPHICAL - desc: in the equalizer settings menu - user: core - - *: none - swcodec: "Graphical EQ" - - - *: none - swcodec: "Grafiskais Ekvalaizers" - - - *: none - swcodec: "grafiskais ekvalaizers" - - - - id: LANG_EQUALIZER_PRECUT - desc: in eq settings - user: core - - *: none - swcodec: "Precut" - - - *: none - swcodec: "PastiprinÄjums" - - - *: none - swcodec: "kopeejais frekvenchu pastiprinaajums" - - - - id: LANG_EQUALIZER_GAIN - desc: in the equalizer settings menu - user: core - - *: none - swcodec: "Simple EQ Settings" - - - *: none - swcodec: "VienkÄrÅ¡otais Ekvalaizers" - - - *: none - swcodec: "vienkaarshotais ekvalaizers" - - - - id: LANG_EQUALIZER_ADVANCED - desc: in the equalizer settings menu - user: core - - *: none - swcodec: "Advanced EQ Settings" - - - *: none - swcodec: "Papildus UzstÄdÄ«jumi" - - - *: none - swcodec: "papildus uzstaadiijumi" - - - - id: LANG_EQUALIZER_SAVE - desc: in the equalizer settings menu - user: core - - *: none - swcodec: "Save EQ Preset" - - - *: none - swcodec: "SaglabÄt UzstÄdÄ«jumus" - - - *: none - swcodec: "saglabaat ekvalaizera uzstaadiijumus" - - - - id: LANG_EQUALIZER_BROWSE - desc: in the equalizer settings menu - user: core - - *: none - swcodec: "Browse EQ Presets" - - - *: none - swcodec: "AplÅ«kot UzstÄdÄ«jumus" - - - *: none - swcodec: "apluukot ekvalaizera uzstaadiijumus" - - - - id: LANG_EQUALIZER_EDIT_MODE - desc: in the equalizer settings menu - user: core - - *: none - swcodec: "Edit mode: %s" - - - *: none - swcodec: "Režīms: %s" - - - *: none - swcodec: "" - - - - id: LANG_EQUALIZER_GAIN_ITEM - desc: in the equalizer settings menu - user: core - - *: none - swcodec: "%d Hz Band Gain" - - - *: none - swcodec: "%d Hz Joslas Stiprums" - - - *: none - swcodec: "joslas stiprums hercos" - - - - id: LANG_EQUALIZER_BAND_LOW_SHELF - desc: in the equalizer settings menu - user: core - - *: none - swcodec: "Low Shelf Filter" - - - *: none - swcodec: "Basu Filtrs" - - - *: none - swcodec: "basu filtrs" - - - - id: LANG_EQUALIZER_BAND_PEAK - desc: in the equalizer settings menu - user: core - - *: none - swcodec: "Peak Filter %d" - - - *: none - swcodec: "PÄ«Ä·a Filtrs %d" - - - *: none - swcodec: "piikja filtrs" - - - - id: LANG_EQUALIZER_BAND_HIGH_SHELF - desc: in the equalizer settings menu - user: core - - *: none - swcodec: "High Shelf Filter" - - - *: none - swcodec: "Augsto FrekvenÄu Filtrs" - - - *: none - swcodec: "augsto frekvenchu filtrs" - - - - id: LANG_EQUALIZER_BAND_CUTOFF - desc: in the equalizer settings menu - user: core - - *: none - swcodec: "Cutoff Frequency" - - - *: none - swcodec: "Robežfrekvence" - - - *: none - swcodec: "robezhfrekvence" - - - - id: LANG_EQUALIZER_BAND_CENTER - desc: in the equalizer settings menu - user: core - - *: none - swcodec: "Centre Frequency" - - - *: none - swcodec: "Centra Frekvence" - - - *: none - swcodec: "centra frekvence" - - - - id: LANG_EQUALIZER_BAND_Q - desc: in the equalizer settings menu - user: core - - *: none - swcodec: "Q" - - - *: none - swcodec: "Platums" - - - *: none - swcodec: "platums" - - - - id: LANG_DITHERING - desc: in the sound settings menu - user: core - - *: none - swcodec: "Dithering" - - - *: none - swcodec: "Skaņas IzlÄ«dzinÄÅ¡ana" - - - *: none - swcodec: "skanjas izliidzinaashana" - - - - id: LANG_LOUDNESS - desc: in sound_settings - user: core - - *: none - masf: "Loudness" - - - *: none - masf: "Skaļums" - - - *: none - masf: "skaljums" - - - - id: LANG_AUTOVOL - desc: in sound_settings - user: core - - *: none - masf: "Auto Volume" - - - *: none - masf: "Auto Skaļums" - - - *: none - masf: "auto skaljums" - - - - id: LANG_DECAY - desc: in sound_settings - user: core - - *: none - masf: "AV Decay Time" - - - *: none - masf: "AS RegulÄ“Å¡anas Laiks" - - - *: none - masf: "" - - - - id: LANG_SUPERBASS - desc: in sound settings - user: core - - *: none - masf: "Super Bass" - - - *: none - masf: "Basu PastiprinÄjums" - - - *: none - masf: "basu pastiprinaajums" - - - - id: LANG_MDB_ENABLE - desc: in sound settings - user: core - - *: none - masf: "MDB Enable" - - - *: none - masf: "IeslÄ“gt MÄkslÄ«gos Basus" - - - *: none - masf: "iesleegt maaksliigos basus" - - - - id: LANG_MDB_STRENGTH - desc: in sound settings - user: core - - *: none - masf: "MDB Strength" - - - *: none - masf: "MB Stiprums" - - - *: none - masf: "maaksliigo basu stiprums" - - - - id: LANG_MDB_HARMONICS - desc: in sound settings - user: core - - *: none - masf: "MDB Harmonics" - - - *: none - masf: "MB KonvertÄ“Å¡ana" - - - *: none - masf: "maaksliigo basu konverteeshana" - - - - id: LANG_MDB_CENTER - desc: in sound settings - user: core - - *: none - masf: "MDB Centre Frequency" - - - *: none - masf: "MB Centra Frekvence" - - - *: none - masf: "maaksliigo basu centra frekvence" - - - - id: LANG_MDB_SHAPE - desc: in sound settings - user: core - - *: none - masf: "MDB Shape" - - - *: none - masf: "MB Forma" - - - *: none - masf: "maaksliigo basu forma" - - - - id: LANG_GENERAL_SETTINGS - desc: in the main menu - user: core - - *: "General Settings" - - - *: "VispÄrÄ“ji UzstÄdÄ«jumi" - - - *: "vispaareeji uzstaadiijumi" - - - - id: LANG_PLAYBACK - desc: in settings_menu() - user: core - - *: "Playback Settings" - - - *: "AtskaņoÅ¡anas UzstÄdÄ«jumi" - - - *: "atskanjoshanas Uzstaadiijumi" - - - - id: LANG_SHUFFLE - desc: in settings_menu - user: core - - *: "Shuffle" - - - *: "Jaukta SecÄ«ba" - - - *: "jaukta seciiba" - - - - id: LANG_REPEAT - desc: in settings_menu - user: core - - *: "Repeat" - - - *: "AtkÄrtot" - - - *: "atkaartot" - - - - id: LANG_ALL - desc: generic string used both in dir file filter and repeat mode selection - user: core - - *: "All" - - - *: "Visus" - - - *: "visus" - - - - id: LANG_REPEAT_ONE - desc: repeat one song - user: core - - *: "One" - - - *: "Vienu" - - - *: "vienu" - - - - id: LANG_REPEAT_AB - desc: repeat range from point A to B - user: core - - *: "A-B" - - - *: "A-B" - - - *: "aa-bee" - - - - id: LANG_PLAY_SELECTED - desc: in settings_menu - user: core - - *: "Play Selected First" - - - *: "IzvÄ“lÄ“to Atskaņot Pirmo" - - - *: "izveeleeto failu atskanjot pirmo" - - - - id: LANG_WIND_MENU - desc: in the playback sub menu - user: core - - *: "Fast-Forward/Rewind" - - - *: "PÄrtÄ«Å¡ana/AttÄ«Å¡ana" - - - *: "aatraa paartiishana un attiishana" - - - - id: LANG_FFRW_STEP - desc: in settings_menu - user: core - - *: "FF/RW Min Step" - - - *: "PT/ATT Min Solis" - - - *: "minimaalais solis" - - - - id: LANG_FFRW_ACCEL - desc: in settings_menu - user: core - - *: "FF/RW Accel" - - - *: "PT/ATT PaÄtrin" - - - *: "Paaatrinaajums" - - - - id: LANG_MP3BUFFER_MARGIN - desc: MP3 buffer margin time - user: core - - *: "Anti-Skip Buffer" - flash_storage: none - - - *: "PretraustÄ«Å¡anÄs Buferis" - flash_storage: none - - - *: "pretraustiishanaas buferis" - flash_storage: none - - - - id: LANG_FADE_ON_STOP - desc: options menu to set fade on stop or pause - user: core - - *: "Fade on Stop/Pause" - - - *: "IzdziÅ¡ana pie Stop/Pauzes" - - - *: "izdzishana pie stop vai pauzes" - - - - id: LANG_PARTY_MODE - desc: party mode - user: core - - *: "Party Mode" - - - *: "BallÄ«tes Režīms" - - - *: "balliites rezhiims" - - - - id: LANG_CROSSFADE - desc: in playback settings - user: core - - *: none - crossfade: "Crossfade" - - - *: none - crossfade: "PÄrklÄÅ¡anÄs" - - - *: none - crossfade: "paarklaashanaas" - - - - id: LANG_CROSSFADE_ENABLE - desc: in crossfade settings menu - user: core - - *: none - crossfade: "Enable Crossfade" - - - *: none - crossfade: "Izmantot PÄrklÄÅ¡anos" - - - *: none - crossfade: "izmantot paarklaashanos" - - - - id: LANG_MANTRACKSKIP - desc: in crossfade settings - user: core - - *: none - crossfade: "Manual Track Skip Only" - - - *: none - crossfade: "Tikai PÄrslÄ“dzot" - - - *: none - crossfade: "tikai paarsleedzot dziesmas" - - - - id: LANG_SHUFFLE_TRACKSKIP - desc: in settings_menu - user: core - - *: none - crossfade: "Shuffle or Manual Track Skip" - - - *: none - crossfade: "Jaukta SecÄ«ba Vai PÄrslÄ“dzoties" - - - *: none - crossfade: "atskanjojot jauktaa seciibaa vai paarsleedzoties" - - - - id: LANG_CROSSFADE_FADE_IN_DELAY - desc: in crossfade settings menu - user: core - - *: none - crossfade: "Fade-In Delay" - - - *: none - crossfade: "Ievada Aizture" - - - *: none - crossfade: "ievada aizture" - - - - id: LANG_CROSSFADE_FADE_IN_DURATION - desc: in crossfade settings menu - user: core - - *: none - crossfade: "Fade-In Duration" - - - *: none - crossfade: "Ievada Garums" - - - *: none - crossfade: "ievada garums" - - - - id: LANG_CROSSFADE_FADE_OUT_DELAY - desc: in crossfade settings menu - user: core - - *: none - crossfade: "Fade-Out Delay" - - - *: none - crossfade: "Beigu Aizture" - - - *: none - crossfade: "beigu aizture" - - - - id: LANG_CROSSFADE_FADE_OUT_DURATION - desc: in crossfade settings menu - user: core - - *: none - crossfade: "Fade-Out Duration" - - - *: none - crossfade: "Beigu Garums" - - - *: none - crossfade: "beigu garums" - - - - id: LANG_CROSSFADE_FADE_OUT_MODE - desc: in crossfade settings menu - user: core - - *: none - crossfade: "Fade-Out Mode" - - - *: none - crossfade: "Beigu Režīms" - - - *: none - crossfade: "beigu rezhiims" - - - - id: LANG_MIX - desc: in playback settings, crossfade option - user: core - - *: none - crossfade: "Mix" - - - *: none - crossfade: "SajaukÅ¡anÄs" - - - *: none - crossfade: "sajaukshanaas" - - - - id: LANG_REPLAYGAIN - desc: in replaygain - user: core - - *: "Replaygain" - - - *: "Skaļuma NormalizÄcija" - - - *: "skaljuma normalizaacija" - - - - id: LANG_REPLAYGAIN_NOCLIP - desc: in replaygain - user: core - - *: none - swcodec: "Prevent Clipping" - - - *: none - swcodec: "NovÄ“rst PÄrlieku Skaļumu" - - - *: none - swcodec: "noveerst paarlieku skaljumu" - - - - id: LANG_REPLAYGAIN_MODE - desc: in replaygain - user: core - - *: "Replaygain Type" - - - *: "NormalizÄcijas Veids" - - - *: "normalizaacijas veids" - - - - id: LANG_ALBUM_GAIN - desc: in replaygain - user: core - - *: "Album Gain" - - - *: "AlbÅ«mu Skaļums" - - - *: "albuumu skaljums" - - - - id: LANG_TRACK_GAIN - desc: in replaygain - user: core - - *: "Track Gain" - - - *: "Dziesmu Skaļums" - - - *: "dziesmu skaljums" - - - - id: LANG_SHUFFLE_GAIN - desc: use track gain if shuffle mode is on, album gain otherwise - user: core - - *: "Track Gain if Shuffling" - - - *: "Dziesmu Ja Jaukta SecÄ«ba" - - - *: "dziesmu ja jaukta seciiba" - - - - id: LANG_REPLAYGAIN_PREAMP - desc: in replaygain settings - user: core - - *: "Pre-amp" - - - *: "PriekÅ¡pastiprinÄjums" - - - *: "priekshpastiprinaajums" - - - - id: LANG_BEEP - desc: in playback settings - user: core - - *: none - swcodec: "Track Skip Beep" - - - *: none - swcodec: "Dz.PÄrslÄ“gÅ¡anas PÄ«kstiens" - - - *: none - swcodec: "dziesmu paarsleegshanas piikstiens" - - - - id: LANG_WEAK - desc: in beep volume in playback settings - user: core - - *: none - swcodec: "Weak" - - - *: none - swcodec: "VÄjÅ¡" - - - *: none - swcodec: "vaajsh" - - - - id: LANG_MODERATE - desc: in beep volume in playback settings - user: core - - *: none - swcodec: "Moderate" - - - *: none - swcodec: "ViduvÄ“js" - - - *: none - swcodec: "viduveejs" - - - - id: LANG_STRONG - desc: in beep volume in playback settings - user: core - - *: none - swcodec: "Strong" - - - *: none - swcodec: "SpÄ“cÄ«gs" - - - *: none - swcodec: "speeciigs" - - - - id: LANG_SPDIF_ENABLE - desc: in playback settings menu. enable/disable the optical out - user: core - - *: none - spdif_power: "Optical Output" - - - *: none - spdif_power: "OptiskÄ Izeja" - - - *: none - spdif_power: "optiskaa izeja" - - - - id: LANG_NEXT_FOLDER - desc: in settings_menu. Should we allow move to next/prev folder from last/first track of current one - user: core - - *: "Auto-Change Directory" - - - *: "AutomÄtiski MainÄ«t Mapi" - - - *: "automaatiski mainiit mapi" - - - - id: LANG_RANDOM - desc: random folder - user: core - - *: "Random" - - - *: "JauktÄ SecÄ«bÄ" - - - *: "jauktaa seciibaa" - - - - id: LANG_AUDIOSCROBBLER - desc: "Last.fm Log" in the playback menu - user: core - - *: "Last.fm Log" - - - *: "Veidot Last.fm Logu" - - - *: "veidot Last.fm logu" - - - - id: LANG_CUESHEET_ENABLE - desc: cuesheet support option - user: core - - *: "Cuesheet Support" - - - *: "Cue Atbalsts" - - - *: "cue atbalsts" - - - - id: LANG_HEADPHONE_UNPLUG - desc: in settings_menu. - user: core - - *: none - headphone_detection: "Pause on Headphone Unplug" - - - *: none - headphone_detection: "Atvienojot Austiņas NopauzÄ“t" - - - *: none - headphone_detection: "atvienojot austinjas nopauzeet" - - - - id: LANG_HEADPHONE_UNPLUG_RESUME - desc: in pause_phones_menu. - user: core - - *: none - headphone_detection: "Pause and Resume" - - - *: none - headphone_detection: "NopauzÄ“t Un AtsÄkt" - - - *: none - headphone_detection: "nopauzeet un atsaakt" - - - - id: LANG_HEADPHONE_UNPLUG_RW - desc: deprecated - user: core - - *: "" - - - *: none - headphone_detection: "AttÄ«Å¡anas Ilgums" - - - *: none - headphone_detection: "attiishanas ilgums" - - - - id: LANG_HEADPHONE_UNPLUG_DISABLE_AUTORESUME - desc: in pause_phones_menu. - user: core - - *: none - headphone_detection: "Disable resume on startup if phones unplugged" - - - *: none - headphone_detection: "Izsl AtsÄkt Palaižot ja Austiņas Izrautas" - - - *: none - headphone_detection: "izsleegt automaatisku atsaakshanu ja austinjas ir izrautas" - - - - id: LANG_FILE - desc: in settings_menu() - user: core - - *: "File View" - - - *: "Failu PÄrlÅ«ks" - - - *: "failu paarluuks" - - - - id: LANG_SORT_CASE - desc: in settings_menu - user: core - - *: "Sort Case Sensitive" - - - *: "Å Ä·irot PÄ“c Liel.Burt." - - - *: "shkjirot peec lielajiem burtiem" - - - - id: LANG_SORT_DIR - desc: browser sorting setting - user: core - - *: "Sort Directories" - - - *: "Å Ä·irot Mapes" - - - *: "shkjirot mapes" - - - - id: LANG_SORT_FILE - desc: browser sorting setting - user: core - - *: "Sort Files" - - - *: "Å Ä·irot Failus" - - - *: "shkjirot failus" - - - - id: LANG_SORT_ALPHA - desc: browser sorting setting - user: core - - *: "Alphabetical" - - - *: "AlfabÄ“tiski" - - - *: "alfabeetiski" - - - - id: LANG_SORT_DATE - desc: browser sorting setting - user: core - - *: "By Date" - - - *: "PÄ“c Vecuma" - - - *: "peec vecuma" - - - - id: LANG_SORT_DATE_REVERSE - desc: browser sorting setting - user: core - - *: "By Newest Date" - - - *: "PÄ“c JaunÄkÄ" - - - *: "peec jaunaakaa" - - - - id: LANG_SORT_TYPE - desc: browser sorting setting - user: core - - *: "By Type" - - - *: "PÄ“c Veida" - - - *: "peec veida" - - - - id: LANG_FILTER - desc: setting name for dir filter - user: core - - *: "Show Files" - - - *: "RÄdÄ«t Failus" - - - *: "raadiit failus" - - - - id: LANG_FILTER_SUPPORTED - desc: show all file types supported by Rockbox - user: core - - *: "Supported" - - - *: "AtbalstÄ«tos" - - - *: "raadiit atbalstiitos failus" - - - - id: LANG_FILTER_MUSIC - desc: show only music-related files - user: core - - *: "Music" - - - *: "MÅ«zikas" - - - *: "raadiit tikai muuzikas failus" - - - - id: LANG_FOLLOW - desc: in settings_menu - user: core - - *: "Follow Playlist" - - - *: "Sekot Sarakstam" - - - *: "sekot sarakstam" - - - - id: LANG_SHOW_PATH - desc: in settings_menu - user: core - - *: "Show Path" - - - *: "RÄdÄ«t Ceļu" - - - *: "raadiit celju" - - - - id: LANG_SHOW_PATH_CURRENT - desc: in show path menu - user: core - - *: "Current Directory Only" - - - *: "Tikai PatreizÄ“jo Mapi" - - - *: "tikai patreizeejo mapi" - - - - id: LANG_DISPLAY_FULL_PATH - desc: track display options - user: core - - *: "Full Path" - - - *: "Pilnu Ceļu" - - - *: "pilnu celju" - - - - id: LANG_BUILDING_DATABASE - desc: splash database building progress - user: core - - *: "Building database... %d found (OFF to return)" - iriverh100,iriverh120,iriverh300: "Building database... %d found (STOP to return)" - ipod*: "Building database... %d found (PREV to return)" - iaudiox5,iaudiom5,gigabeat*,mrobe100: "Building database... %d found (LEFT to return)" - iriverh10,iriverh10_5gb,sansae200*,sansac200*,sansafuze*,vibe500: "Building database... %d found (PREV to return)" - gogearsa9200: "Building database... %d found (REW to return)" - archosplayer: "Building DB %d found" - - - *: "Veidoju datubÄzi... %d atrastas (OFF lai turpinÄtu)" - iriverh100,iriverh120,iriverh300: "Veidoju datubÄzi... %d atrastas (STOP lai turpinÄtu)" - ipod*: "Veidoju datubÄzi... %d atrastas (PREV lai turpinÄtu)" - iaudiox5,iaudiom5,gigabeat*,mrobe100: "Veidoju datubÄzi... %d atrastas (LEFT lai turpinÄtu)" - iriverh10,iriverh10_5gb,sansae200*,sansac200*,sansafuze*,vibe500: "Veidoju datubÄzi... %d atrastas (PREV lai turpinÄtu)" - gogearsa9200: "Veidoju datubÄzi... %d atrastas (REW lai turpinÄtu)" - archosplayer: "Veidoju DB atrasts %d" - - - *: "atrasti ieraksti datubaazei" - - - - id: LANG_TAGCACHE_RAM - desc: in tag cache settings - user: core - - *: none - tc_ramcache: "Load to RAM" - - - *: none - tc_ramcache: "IelÄdÄ“t AtmiņÄ" - - - *: none - tc_ramcache: "ielaadeet operatiivajaa atminjaa" - - - - id: LANG_TAGCACHE_AUTOUPDATE - desc: in tag cache settings - user: core - - *: "Auto Update" - - - *: "Atjaunot AutomÄtiski" - - - *: "atjaunot automaatiski" - - - - id: LANG_TAGCACHE_FORCE_UPDATE - desc: in tag cache settings - user: core - - *: "Initialize Now" - - - *: "InicializÄ“t Tagad" - - - *: "inicializeet tagad" - - - - id: LANG_TAGCACHE_UPDATE - desc: in tag cache settings - user: core - - *: "Update Now" - - - *: "Atjaunot Tagad" - - - *: "atjaunot tagad" - - - - id: LANG_RUNTIMEDB_ACTIVE - desc: in settings_menu. - user: core - - *: "Gather Runtime Data" - - - *: "KrÄt Statistiku" - - - *: "kraat statistiku" - - - - id: LANG_TAGCACHE_EXPORT - desc: in tag cache settings - user: core - - *: "Export Modifications" - - - *: "EksportÄ“t Izmaiņas" - - - *: "eksporteet izmainjas" - - - - id: LANG_TAGCACHE_IMPORT - desc: in tag cache settings - user: core - - *: "Import Modifications" - - - *: "ImportÄ“t Izmaiņas" - - - *: "importeet izmainjas" - - - - id: LANG_TAGCACHE_FORCE_UPDATE_SPLASH - desc: in tag cache settings - user: core - - *: "Updating in background" - - - *: "Atjaunina fonÄ" - - - *: "atjaunina fonaa" - - - - id: LANG_TAGCACHE_INIT - desc: while initializing tagcache on boot - user: core - - *: "Committing database" - - - *: "Palaiž datubÄzi" - - - *: "palaizh datubaazi" - - - - id: LANG_TAGCACHE_BUSY - desc: when trying to shutdown and tagcache is committing - user: core - - *: "Database is not ready" - - - *: "DatubÄze vÄ“l darbojas" - - - *: "datubaaze veel darbojas" - - - - id: LANG_TAGNAVI_ALL_TRACKS - desc: "" entry in tag browser - user: core - - *: "" - - - *: "" - - - *: "visas dziesmas" - - - - id: LANG_DISPLAY - desc: in settings_menu() - user: core - - *: "Display" - - - *: "AttÄ“ls" - - - *: "atteels" - - - - id: LANG_CUSTOM_FONT - desc: in setting_menu() - user: core - - *: none - lcd_bitmap: "Font" - - - *: none - lcd_bitmap: "Fonti" - - - *: none - lcd_bitmap: "fonti" - - - - id: LANG_WHILE_PLAYING - desc: in settings_menu() - user: core - - *: "While Playing Screen" - - - *: "AtskaņoÅ¡anas EkrÄns" - - - *: "atskanjoshanas ekraans" - - - - id: LANG_REMOTE_WHILE_PLAYING - desc: in settings_menu() - user: core - - *: none - remote: "Remote While Playing Screen" - - - *: none - remote: "Pults AtskaņoÅ¡anas EkrÄns" - - - *: none - remote: "pults atskanjoshanas ekraans" - - - - id: LANG_LCD_MENU - desc: in the display sub menu - user: core - - *: "LCD Settings" - - - *: "EkrÄna UzstÄdÄ«jumi" - - - *: "ekraana uzstaadiijumi" - - - - id: LANG_BACKLIGHT - desc: in settings_menu - user: core - - *: "Backlight" - - - *: "Apgaismojums" - - - *: "apgaismojums" - - - - id: LANG_BACKLIGHT_ON_WHEN_CHARGING - desc: in display_settings_menu, backlight timeout with charger connected - user: core - - *: none - charging: "Backlight (While Plugged In)" - - - *: none - charging: "Apgaismojums (LÄdÄ“jot)" - - - *: none - charging: "apgaismojums laadeeshanas laikaa" - - - - id: LANG_BACKLIGHT_ON_BUTTON_HOLD - desc: in lcd settings - user: core - - *: none - hold_button: "Backlight on Hold" - - - *: none - hold_button: "Apgaismojums kad Hold" - - - *: none - hold_button: "apgaismojums ar noblokjeetiem taustinjiem" - - - - id: LANG_CAPTION_BACKLIGHT - desc: in settings_menu - user: core - - *: "Caption Backlight" - - - *: "Nosaukuma Apgaismojums" - - - *: "nosaukuma apgaismojums" - - - - id: LANG_BACKLIGHT_FADE_IN - desc: in settings_menu - user: core - - *: none - backlight_fade*: "Backlight Fade In" - - - *: none - backlight_fade*: "Apgaismojuma iesl.laiks" - - - *: none - backlight_fade*: "apgaismojuma iesleegshanaas laiks" - - - - id: LANG_BACKLIGHT_FADE_OUT - desc: in settings_menu - user: core - - *: none - backlight_fade*: "Backlight Fade Out" - - - *: none - backlight_fade*: "Apgaismojuma izsl.laiks" - - - *: none - backlight_fade*: "apgaismojuma izsleegshanaas laiks" - - - - id: LANG_BACKLIGHT_FILTER_FIRST_KEYPRESS - desc: Backlight behaviour setting - user: core - - *: "First Buttonpress Enables Backlight Only" - - - *: "Pirmais Spiediens IeslÄ“dz Tikai Apgaismojumu" - - - *: "pirmais spiediens Iesleedz tikai apgaismojumu" - - - - id: LANG_LCD_SLEEP_AFTER_BACKLIGHT_OFF - desc: In display settings, time to switch LCD chip into power saving state - user: core - - *: none - lcd_sleep: "Sleep (After Backlight Off)" - - - *: none - lcd_sleep: "EkrÄna IzslÄ“gÅ¡anas Laiks" - - - *: none - lcd_sleep: "ekraana izsleegshanas laiks" - - - - id: LANG_NEVER - desc: in lcd settings - user: core - - *: none - lcd_sleep: "Never" - - - *: none - lcd_sleep: "Nekad" - - - *: none - lcd_sleep: "nekad" - - - - id: LANG_BRIGHTNESS - desc: in settings_menu - user: core - - *: none - backlight_brightness: "Brightness" - - - *: none - backlight_brightness: "Spilgtums" - - - *: none - backlight_brightness: "spilgtums" - - - - id: LANG_CONTRAST - desc: in settings_menu - user: core - - *: "Contrast" - - - *: "Kontrasts" - - - *: "kontrasts" - - - - id: LANG_INVERT - desc: in settings_menu - user: core - - *: none - lcd_invert,remote_lcd_invert: "LCD Mode" - - - *: none - lcd_invert,remote_lcd_invert: "EkrÄna Režīms" - - - *: none - lcd_invert,remote_lcd_invert: "ekraana rezhiims" - - - - id: LANG_INVERT_LCD_INVERSE - desc: in settings_menu - user: core - - *: none - lcd_invert,remote_lcd_invert: "Inverse" - - - *: none - lcd_invert,remote_lcd_invert: "NegatÄ«vs" - - - *: none - lcd_invert,remote_lcd_invert: "negatiivs" - - - - id: LANG_FLIP_DISPLAY - desc: in settings_menu, option to turn display+buttos by 180 degrees - user: core - - *: none - lcd_bitmap: "Upside Down" - - - *: none - lcd_bitmap: "KÄjÄm GaisÄ" - - - *: none - lcd_bitmap: "kaajaam gaisaa" - - - - id: LANG_INVERT_CURSOR - desc: in settings_menu - user: core - - *: none - lcd_bitmap: "Line Selector Type" - - - *: none - lcd_bitmap: "LÄ«nija" - - - *: none - lcd_bitmap: "liinija" - - - - id: LANG_INVERT_CURSOR_POINTER - desc: in settings_menu - user: core - - *: none - lcd_bitmap: "Pointer" - - - *: none - lcd_bitmap: "Kursors" - - - *: none - lcd_bitmap: "kursors" - - - - id: LANG_INVERT_CURSOR_BAR - desc: in settings_menu - user: core - - *: none - lcd_bitmap: "Bar (Inverse)" - - - *: none - lcd_bitmap: "Rinda (ApvÄ“rsta)" - - - *: none - lcd_bitmap: "apveersta rinda" - - - - id: LANG_CLEAR_BACKDROP - desc: text for LCD settings menu - user: core - - *: none - lcd_non-mono: "Clear Backdrop" - - - *: none - lcd_non-mono: "NovÄkt Fonu" - - - *: none - lcd_non-mono: "novaakt fonu" - - - - id: LANG_BACKGROUND_COLOR - desc: menu entry to set the background color - user: core - - *: none - lcd_color: "Background Colour" - - - *: none - lcd_color: "Fona KrÄsa" - - - *: none - lcd_color: "fona kraasa" - - - - id: LANG_FOREGROUND_COLOR - desc: menu entry to set the foreground color - user: core - - *: none - lcd_color: "Foreground Colour" - - - *: none - lcd_color: "PriekÅ¡plÄna KrÄsa" - - - *: none - lcd_color: "priekshplaana kraasa" - - - - id: LANG_RESET_COLORS - desc: menu - user: core - - *: none - lcd_color: "Reset Colours" - - - *: none - lcd_color: "NoklusÄ“tÄs KrÄsas" - - - *: none - lcd_color: "nokluseetaas kraasas" - - - - id: LANG_COLOR_RGB_LABELS - desc: what to show for the 'R' 'G' 'B' ONE LETTER EACH - user: core - - *: none - lcd_color: "RGB" - - - *: none - lcd_color: "SaZaZi" - - - *: none - lcd_color: "" - - - - id: LANG_COLOR_RGB_VALUE - desc: in color screen - user: core - - *: none - lcd_color: "RGB: %02X%02X%02X" - - - *: none - lcd_color: "SaZaZi: %02X%02X%02X" - - - *: none - lcd_color: "" - - - - id: LANG_COLOR_UNACCEPTABLE - desc: splash when user selects an invalid colour - user: core - - *: none - lcd_color: "Invalid colour" - - - *: none - lcd_color: "NederÄ«ga KrÄsa" - - - *: none - lcd_color: "" - - - - id: LANG_LCD_REMOTE_MENU - desc: in the display sub menu - user: core - - *: none - remote: "Remote-LCD Settings" - - - *: none - remote: "Pults EkrÄna UzstÄdÄ«jumi" - - - *: none - remote: "pults ekraana uzstaadiijumi" - - - - id: LANG_REDUCE_TICKING - desc: in remote lcd settings menu - user: core - - *: none - remote_ticking: "Reduce Ticking" - - - *: none - remote_ticking: "SamazinÄt TikÅ¡Ä·i" - - - *: none - remote_ticking: "samazinaat tikshkji" - - - - id: LANG_SHOW_ICONS - desc: in settings_menu - user: core - - *: "Show Icons" - - - *: "RÄdÄ«t Ikonas" - - - *: "raadiit ikonas" - - - - id: LANG_SCROLL_MENU - desc: in display_settings_menu() - user: core - - *: "Scrolling" - - - *: "RullÄ“Å¡ana" - - - *: "rulleeshana" - - - - id: LANG_SCROLL - desc: in settings_menu - user: core - - *: "Scroll Speed Setting Example" - - - *: "RullÄ“Å¡anas Ä€truma PiemÄ“rs" - - - *: "" - - - - id: LANG_SCROLL_SPEED - desc: in display_settings_menu() - user: core - - *: "Scroll Speed" - - - *: "RullÄ“Å¡anas Ä€trums" - - - *: "rulleeshanas aatrums" - - - - id: LANG_SCROLL_DELAY - desc: Delay before scrolling - user: core - - *: "Scroll Start Delay" - - - *: "RullÄ“Å¡anas Aizture" - - - *: "rulleeshanas aizture" - - - - id: LANG_SCROLL_STEP - desc: Pixels to advance per scroll - user: core - - *: "Scroll Step Size" - - - *: "RullÄ“Å¡anas Solis" - - - *: "rulleeshanas solis" - - - - id: LANG_SCROLL_STEP_EXAMPLE - desc: Pixels to advance per scroll - user: core - - *: "Scroll Step Size Setting Example Text" - - - *: "RullÄ“Å¡anas Soļa PiemÄ“rs" - - - *: "" - - - - id: LANG_BIDIR_SCROLL - desc: Bidirectional scroll limit - user: core - - *: "Bidirectional Scroll Limit" - - - *: "AbpusÄ“jas RullÄ“Å¡anas Limits" - - - *: "abpuseejas rulleeshanas limits" - - - - id: LANG_REMOTE_SCROLL_SETS - desc: "Remote Scrolling Options" Submenu in "Scrolling Options" menu - user: core - - *: none - remote: "Remote Scrolling Options" - - - *: none - remote: "Pults RullÄ“Å¡anas Opcijas" - - - *: none - remote: "pults rulleeshanas opcijas" - - - - id: LANG_SCREEN_SCROLL_VIEW - desc: should lines scroll out of the screen - user: core - - *: none - lcd_bitmap: "Screen Scrolls Out Of View" - - - *: none - lcd_bitmap: "Teksts IzrullÄ“jas Ä€rpus EkrÄna" - - - *: none - lcd_bitmap: "teksts izrulleejas aarpus ekraana" - - - - id: LANG_SCREEN_SCROLL_STEP - desc: Pixels to advance per Screen scroll - user: core - - *: none - lcd_bitmap: "Screen Scroll Step Size" - - - *: none - lcd_bitmap: "EkrÄna RullÄ“Å¡anas Solis" - - - *: none - lcd_bitmap: "ekraana rulleeshanas solis" - - - - id: LANG_SCROLL_PAGINATED - desc: jump to new page when scrolling - user: core - - *: "Paged Scrolling" - - - *: "RullÄ“t Lapas" - - - *: "rulleet lapas" - - - - id: LANG_LISTACCEL_START_DELAY - desc: Delay before list starts accelerating - user: core - - *: "List Acceleration Start Delay" - wheel_acceleration: none - - - *: "Saraksta RullÄ“Å¡anas Aizture" - wheel_acceleration: none - - - *: "saraksta rulleeshanas aizture" - wheel_acceleration: none - - - - id: LANG_LISTACCEL_ACCEL_SPEED - desc: list acceleration speed - user: core - - *: "List Acceleration Speed" - wheel_acceleration: none - - - *: "Saraksta PaÄtrinÄjums" - wheel_acceleration: none - - - *: "saraksta paaatrinaajums" - wheel_acceleration: none - - - - id: LANG_BARS_MENU - desc: in the display sub menu - user: core - - *: none - lcd_bitmap: "Status-/Scrollbar" - - - *: none - lcd_bitmap: "Statusa-/Rulljosla" - - - *: none - lcd_bitmap: "statusa rulljosla" - - - - id: LANG_SCROLL_BAR - desc: display menu, F3 substitute - user: core - - *: none - lcd_bitmap: "Scroll Bar" - - - *: none - lcd_bitmap: "Rulljosla" - - - *: none - lcd_bitmap: "rulljosla" - - - - id: LANG_STATUS_BAR - desc: display menu, F3 substitute - user: core - - *: none - lcd_bitmap: "Status Bar" - - - *: none - lcd_bitmap: "Statusa Josla" - - - *: none - lcd_bitmap: "statusa josla" - - - - id: LANG_BUTTON_BAR - desc: in settings menu - user: core - - *: none - recorder_pad: "Button Bar" - - - *: none - recorder_pad: "Pogu Josla" - - - *: none - recorder_pad: "pogu josla" - - - - id: LANG_VOLUME_DISPLAY - desc: Volume type title - user: core - - *: none - lcd_bitmap: "Volume Display" - - - *: none - lcd_bitmap: "Skaļuma AttÄ“loÅ¡ana" - - - *: none - lcd_bitmap: "skaljuma atteeloshana" - - - - id: LANG_BATTERY_DISPLAY - desc: Battery type title - user: core - - *: none - lcd_bitmap: "Battery Display" - - - *: none - lcd_bitmap: "Batterijas AttÄ“loÅ¡ana" - - - *: none - lcd_bitmap: "baterijas atteeloshana" - - - - id: LANG_DISPLAY_GRAPHIC - desc: Label for type of icon display - user: core - - *: none - lcd_bitmap: "Graphic" - - - *: none - lcd_bitmap: "Grafiski" - - - *: none - lcd_bitmap: "grafiski" - - - - id: LANG_DISPLAY_NUMERIC - desc: Label for type of icon display - user: core - - *: none - lcd_bitmap: "Numeric" - - - *: none - lcd_bitmap: "Numeriski" - - - *: none - lcd_bitmap: "numeriski" - - - - id: LANG_PM_MENU - desc: in the display menu - user: core - - *: "Peak Meter" - masd: none - - - *: "LÄ«meņa Indikators" - masd: none - - - *: "liimenja indikators" - masd: none - - - - id: LANG_PM_CLIP_HOLD - desc: in the peak meter menu - user: core - - *: "Clip Hold Time" - masd: none - - - *: "Kropļojuma Aizture" - masd: none - - - *: "kropljojuma indikaacijas aizture" - masd: none - - - - id: LANG_PM_PEAK_HOLD - desc: in the peak meter menu - user: core - - *: "Peak Hold Time" - masd: none - - - *: "PÄ«Ä·a Aiztures" - masd: none - - - *: "piikja indikaacijas aizture" - masd: none - - - - id: LANG_PM_ETERNAL - desc: in the peak meter menu - user: core - - *: "Eternal" - masd: none - - - *: "Ä€rÄ“js" - masd: none - - - *: "aareejs" - masd: none - - - - id: LANG_PM_RELEASE - desc: in the peak meter menu - user: core - - *: "Peak Release" - masd: none - - - *: "PÄ«Ä·a AtlaiÅ¡ana" - masd: none - - - *: "piikja indikaacijas atlaishana" - masd: none - - - - id: LANG_PM_SCALE - desc: in the peak meter menu - user: core - - *: "Scale" - masd: none - - - *: "Skala" - masd: none - - - *: "skala" - masd: none - - - - id: LANG_PM_DBFS - desc: in the peak meter menu - user: core - - *: "Logarithmic (dB)" - masd: none - - - *: "LogaritmiskÄ (dB)" - masd: none - - - *: "logaritmiskaa decibelu" - masd: none - - - - id: LANG_PM_LINEAR - desc: in the peak meter menu - user: core - - *: "Linear (%)" - masd: none - - - *: "LineÄrÄ (%)" - masd: none - - - *: "lineaaraa procentu" - masd: none - - - - id: LANG_PM_MIN - desc: in the peak meter menu - user: core - - *: "Minimum Of Range" - masd: none - - - *: "Skalas SÄkums" - masd: none - - - *: "skalas saakums" - masd: none - - - - id: LANG_PM_MAX - desc: in the peak meter menu - user: core - - *: "Maximum Of Range" - masd: none - - - *: "Skalas Beigas" - masd: none - - - *: "skalas beigas" - masd: none - - - - id: LANG_DEFAULT_CODEPAGE - desc: default encoding used with id3 tags - user: core - - *: "Default Codepage" - - - *: "NoklusÄ“tais KodÄ“jums" - - - *: "nokluseetais kodeejums" - - - - id: LANG_CODEPAGE_LATIN1 - desc: in codepage setting menu - user: core - - *: "Latin1 (ISO-8859-1)" - - - *: "Latīņu1 (ISO-8859-1)" - - - *: "latiinju viens" - - - - id: LANG_CODEPAGE_GREEK - desc: in codepage setting menu - user: core - - *: "Greek (ISO-8859-7)" - - - *: "GrieÄ·u (ISO-8859-7)" - - - *: "griekju" - - - - id: LANG_CODEPAGE_HEBREW - desc: in codepage setting menu - user: core - - *: none - lcd_bitmap: "Hebrew (ISO-8859-8)" - - - *: none - lcd_bitmap: "Ebreju (ISO-8859-8)" - - - *: none - lcd_bitmap: "ebreju" - - - - id: LANG_CODEPAGE_CYRILLIC - desc: in codepage setting menu - user: core - - *: "Cyrillic (CP1251)" - - - *: "Kirilica (CP1251)" - - - *: "kirilica" - - - - id: LANG_CODEPAGE_THAI - desc: in codepage setting menu - user: core - - *: none - lcd_bitmap: "Thai (ISO-8859-11)" - - - *: none - lcd_bitmap: "Tai (ISO-8859-11)" - - - *: none - lcd_bitmap: "tai" - - - - id: LANG_CODEPAGE_ARABIC - desc: in codepage setting menu - user: core - - *: none - lcd_bitmap: "Arabic (CP1256)" - - - *: none - lcd_bitmap: "ArÄbu (CP1256)" - - - *: none - lcd_bitmap: "araabu" - - - - id: LANG_CODEPAGE_TURKISH - desc: in codepage setting menu - user: core - - *: "Turkish (ISO-8859-9)" - - - *: "Turku (ISO-8859-9)" - - - *: "turku" - - - - id: LANG_CODEPAGE_LATIN_EXTENDED - desc: in codepage setting menu - user: core - - *: "Latin Extended (ISO-8859-2)" - - - *: "Latīņu PaplaÅ¡in. (ISO-8859-2)" - - - *: "latiinju paplashinaatais" - - - - id: LANG_CODEPAGE_JAPANESE - desc: in codepage setting menu - user: core - - *: none - lcd_bitmap: "Japanese (SJIS)" - - - *: none - lcd_bitmap: "JapÄņu (SJIS)" - - - *: none - lcd_bitmap: "Japaanju" - - - - id: LANG_CODEPAGE_SIMPLIFIED - desc: in codepage setting menu - user: core - - *: none - lcd_bitmap: "Simp. Chinese (GB2312)" - - - *: none - lcd_bitmap: "Vienk. ĶīnieÅ¡u (GB2312)" - - - *: none - lcd_bitmap: "vienkaarshotais kjiinieshu" - - - - id: LANG_CODEPAGE_KOREAN - desc: in codepage setting menu - user: core - - *: none - lcd_bitmap: "Korean (KSX1001)" - - - *: none - lcd_bitmap: "KorejieÅ¡u (KSX1001)" - - - *: none - lcd_bitmap: "korejieshu" - - - - id: LANG_CODEPAGE_TRADITIONAL - desc: in codepage setting menu - user: core - - *: none - lcd_bitmap: "Trad. Chinese (BIG5)" - - - *: none - lcd_bitmap: "Trad. ĶīnieÅ¡u (BIG5)" - - - *: none - lcd_bitmap: "tradicionaalais kjiinieshu" - - - - id: LANG_CODEPAGE_UTF8 - desc: in codepage setting menu - user: core - - *: "Unicode (UTF-8)" - - - *: "Unikods (UTF-8)" - - - *: "unikods" - - - - id: LANG_BUTTONLIGHT_TIMEOUT - desc: in settings_menu - user: core - - *: none - button_light: "Button Light Timeout" - sansafuze*,sansae200*: "Wheel Light Timeout" - - - *: none - button_light: "Pogu Apgaismojums" - sansafuze*,sansae200*: "Ripuļa Apgaismojums" - - - *: none - button_light: "pogu apgaismojums" - sansafuze*,sansae200*: "ripulja apgaismojums" - - - - id: LANG_BUTTONLIGHT_BRIGHTNESS - desc: in settings_menu - user: core - - *: none - buttonlight_brightness: "Button Light Brightness" - - - *: none - buttonlight_brightness: "Pogu Spilgtums" - - - *: none - buttonlight_brightness: "pogu spilgtums" - - - - id: LANG_START_SCREEN - desc: in the system sub menu - user: core - - *: "Start Screen" - - - *: "SÄkuma Logs" - - - *: "saakuma logs" - - - - id: LANG_MAIN_MENU - desc: in start screen setting - user: core - - *: "Main Menu" - - - *: "GalvenÄ IzvÄ“lne" - - - *: "galvenaa izveelne" - - - - id: LANG_PREVIOUS_SCREEN - desc: in start screen setting - user: core - - *: "Previous Screen" - - - *: "IepriekÅ¡Ä“jÄ IzvÄ“lne" - - - *: "ieprieksheejaa izveelne" - - - - id: LANG_BATTERY_MENU - desc: in the system sub menu - user: core - - *: "Battery" - - - *: "Baterija" - - - *: "baterija" - - - - id: LANG_BATTERY_CAPACITY - desc: in settings_menu - user: core - - *: "Battery Capacity" - - - *: "IetilpÄ«ba" - - - *: "baterijas ietilpiiba" - - - - id: LANG_BATTERY_TYPE - desc: in battery settings - user: core - - *: none - battery_types: "Battery Type" - - - *: none - battery_types: "Veids" - - - *: none - battery_types: "veids" - - - - id: LANG_BATTERY_TYPE_ALKALINE - desc: in battery settings - user: core - - *: none - battery_types: "Alkaline" - - - *: none - battery_types: "SÄrma" - - - *: none - battery_types: "saarma" - - - - id: LANG_BATTERY_TYPE_NIMH - desc: in battery settings - user: core - - *: none - battery_types: "NiMH" - - - *: none - battery_types: "NiMH" - - - *: none - battery_types: "nikjelja metaalhidraata" - - - - id: LANG_DISK_MENU - desc: in the system sub menu - user: core - - *: "Disk" - - - *: "Disks" - - - *: "disks" - - - - id: LANG_SPINDOWN - desc: in settings_menu - user: core - - *: "Disk Spindown" - flash_storage: none - - - *: "Diska ApstÄdinÄÅ¡ana" - flash_storage: none - - - *: "diska apstaadinaashana" - flash_storage: none - - - - id: LANG_DIRCACHE_ENABLE - desc: in directory cache settings - user: core - - *: none - dircache: "Directory Cache" - - - *: none - dircache: "Mapju Buferis" - - - *: none - dircache: "mapju buferis" - - - - id: LANG_TIME_MENU - desc: in the system sub menu - user: core - - *: none - rtc: "Time & Date" - - - *: none - rtc: "Laiks & Datums" - - - *: none - rtc: "laiks un datums" - - - - id: LANG_SET_TIME - desc: in settings_menu - user: core - - *: none - rtc: "Set Time/Date" - - - *: none - rtc: "UzstÄdÄ«t Laiku/Datumu" - - - *: none - rtc: "uzstaadiit laiku un datumu" - - - - id: LANG_TIMEFORMAT - desc: select the time format of time in status bar - user: core - - *: none - rtc: "Time Format" - - - *: none - rtc: "Laika FormÄts" - - - *: none - rtc: "laika formaats" - - - - id: LANG_12_HOUR_CLOCK - desc: option for 12 hour clock - user: core - - *: none - rtc: "12 Hour Clock" - - - *: none - rtc: "12 Stundu Pulkstenis" - - - *: none - rtc: "divpadsmit stundu pulkstenis" - - - - id: LANG_24_HOUR_CLOCK - desc: option for 24 hour clock - user: core - - *: none - rtc: "24 Hour Clock" - - - *: none - rtc: "24 Stundu Pulkstenis" - - - *: none - rtc: "divdesmit chetru stundu pulkstenis" - - - - id: LANG_TIME_SET_BUTTON - desc: used in set_time() - user: core - - *: none - rtc: "ON = Set" - mrobe500: "HEART = Set" - iriverh100,iriverh120,iriverh300: "NAVI = Set" - ipod*,iaudiox5,iaudiom5,iriverh10,iriverh10_5gb,sansae200*,sansac200*,gigabeat*,mrobe100,sansaclip*,sansafuze*: "SELECT = Set" - gogearsa9200: "PLAY = Set" - vibe500: "OK = Set" - mpiohd300: "ENTER = Set" - - - *: none - rtc: "ON = UzstÄdÄ«t" - mrobe500: "HEART = UzstÄdÄ«t" - iriverh100,iriverh120,iriverh300: "NAVI = UzstÄdÄ«t" - ipod*,iaudiox5,iaudiom5,iriverh10,iriverh10_5gb,sansae200*,sansac200*,gigabeat*,mrobe100,sansaclip*,sansafuze*: "SELECT = UzstÄdÄ«t" - gogearsa9200: "PLAY = UzstÄdÄ«t" - vibe500: "OK = UzstÄdÄ«t" - mpiohd300: "ENTER = UzstÄdÄ«t" - - - *: none - rtc,iriverh100,iriverh120,iriverh300,iriverh10,iriverh10_5gb,iaudiox5,iaudiom5,ipod*,sansae200*,sansac200*,gigabeat*,mrobe100,gogearsa9200: "" - - - - id: LANG_TIME_REVERT - desc: used in set_time() - user: core - - *: none - rtc: "OFF = Revert" - mrobe500: "POWER = Revert" - iriverh100,iriverh120,iriverh300: "STOP = Revert" - ipod*,sansac200*,mpiohd300: "MENU = Revert" - iaudiox5,iaudiom5: "RECORD = Revert" - iriverh10,iriverh10_5gb,sansae200*,sansafuze*: "PREV = Revert" - gigabeatfx: "POWER = Revert" - mrobe100: "DISPLAY = Revert" - gigabeats: "BACK = Revert" - gogearsa9200: "LEFT = Revert" - vibe500: "CANCEL = Revert" - - - *: none - rtc: "OFF = Atcelt" - mrobe500: "POWER = Atcelt" - iriverh100,iriverh120,iriverh300: "STOP = Atcelt" - ipod*,sansac200*,mpiohd300: "MENU = Atcelt" - iaudiox5,iaudiom5: "RECORD = Atcelt" - iriverh10,iriverh10_5gb,sansae200*,sansafuze*: "PREV = Atcelt" - gigabeatfx: "POWER = Atcelt" - mrobe100: "DISPLAY = Atcelt" - gigabeats: "BACK = Atcelt" - gogearsa9200: "LEFT = Atcelt" - vibe500: "CANCEL = Atcelt" - - - *: none - rtc,iriverh100,iriverh120,iriverh300,ipod*,sansae200*,sansac200*,iaudiox5,iaudiom5,iriverh10,iriverh10_5gb,gigabeat*,mrobe100,gogearsa9200: "" - - - - id: LANG_WEEKDAY_SUNDAY - desc: Maximum 3-letter abbreviation for weekday - user: core - - *: none - rtc: "Sun" - - - *: none - rtc: "Sv" - - - *: none - rtc: "" - - - - id: LANG_WEEKDAY_MONDAY - desc: Maximum 3-letter abbreviation for weekday - user: core - - *: none - rtc: "Mon" - - - *: none - rtc: "Prm" - - - *: none - rtc: "" - - - - id: LANG_WEEKDAY_TUESDAY - desc: Maximum 3-letter abbreviation for weekday - user: core - - *: none - rtc: "Tue" - - - *: none - rtc: "Otr" - - - *: none - rtc: "" - - - - id: LANG_WEEKDAY_WEDNESDAY - desc: Maximum 3-letter abbreviation for weekday - user: core - - *: none - rtc: "Wed" - - - *: none - rtc: "Tre" - - - *: none - rtc: "" - - - - id: LANG_WEEKDAY_THURSDAY - desc: Maximum 3-letter abbreviation for weekday - user: core - - *: none - rtc: "Thu" - - - *: none - rtc: "Cet" - - - *: none - rtc: "" - - - - id: LANG_WEEKDAY_FRIDAY - desc: Maximum 3-letter abbreviation for weekday - user: core - - *: none - rtc: "Fri" - - - *: none - rtc: "Pkt" - - - *: none - rtc: "" - - - - id: LANG_WEEKDAY_SATURDAY - desc: Maximum 3-letter abbreviation for weekday - user: core - - *: none - rtc: "Sat" - - - *: none - rtc: "Sst" - - - *: none - rtc: "" - - - - id: LANG_MONTH_JANUARY - desc: Maximum 3-letter abbreviation for monthname - user: core - - *: none - rtc: "Jan" - - - *: none - rtc: "Jan" - - - *: none - rtc: "janvaaris" - - - - id: LANG_MONTH_FEBRUARY - desc: Maximum 3-letter abbreviation for monthname - user: core - - *: none - rtc: "Feb" - - - *: none - rtc: "Feb" - - - *: none - rtc: "februaaris" - - - - id: LANG_MONTH_MARCH - desc: Maximum 3-letter abbreviation for monthname - user: core - - *: none - rtc: "Mar" - - - *: none - rtc: "Mar" - - - *: none - rtc: "marts" - - - - id: LANG_MONTH_APRIL - desc: Maximum 3-letter abbreviation for monthname - user: core - - *: none - rtc: "Apr" - - - *: none - rtc: "Apr" - - - *: none - rtc: "apriilis" - - - - id: LANG_MONTH_MAY - desc: Maximum 3-letter abbreviation for monthname - user: core - - *: none - rtc: "May" - - - *: none - rtc: "Mai" - - - *: none - rtc: "maijs" - - - - id: LANG_MONTH_JUNE - desc: Maximum 3-letter abbreviation for monthname - user: core - - *: none - rtc: "Jun" - - - *: none - rtc: "JÅ«n" - - - *: none - rtc: "juunijs" - - - - id: LANG_MONTH_JULY - desc: Maximum 3-letter abbreviation for monthname - user: core - - *: none - rtc: "Jul" - - - *: none - rtc: "JÅ«l" - - - *: none - rtc: "juulijs" - - - - id: LANG_MONTH_AUGUST - desc: Maximum 3-letter abbreviation for monthname - user: core - - *: none - rtc: "Aug" - - - *: none - rtc: "Aug" - - - *: none - rtc: "augusts" - - - - id: LANG_MONTH_SEPTEMBER - desc: Maximum 3-letter abbreviation for monthname - user: core - - *: none - rtc: "Sep" - - - *: none - rtc: "Sep" - - - *: none - rtc: "septembris" - - - - id: LANG_MONTH_OCTOBER - desc: Maximum 3-letter abbreviation for monthname - user: core - - *: none - rtc: "Oct" - - - *: none - rtc: "Okt" - - - *: none - rtc: "oktobris" - - - - id: LANG_MONTH_NOVEMBER - desc: Maximum 3-letter abbreviation for monthname - user: core - - *: none - rtc: "Nov" - - - *: none - rtc: "Nov" - - - *: none - rtc: "novembris" - - - - id: LANG_MONTH_DECEMBER - desc: Maximum 3-letter abbreviation for monthname - user: core - - *: none - rtc: "Dec" - - - *: none - rtc: "Dec" - - - *: none - rtc: "decembris" - - - - id: LANG_POWEROFF_IDLE - desc: in settings_menu - user: core - - *: "Idle Poweroff" - - - *: "AutomÄtiskÄ IzslÄ“gÅ¡anÄs" - - - *: "automaatiskaa izsleegshanaas" - - - - id: LANG_SLEEP_TIMER - desc: sleep timer setting - user: core - - *: "Sleep Timer" - - - *: "Miega Taimeris" - - - *: "miega taimeris" - - - - id: LANG_LIMITS_MENU - desc: in the system sub menu - user: core - - *: "Limits" - - - *: "Ierobežojumi" - - - *: "ierobezhojumi" - - - - id: LANG_MAX_FILES_IN_DIR - desc: in settings_menu - user: core - - *: "Max Entries in File Browser" - - - *: "Maks. Faili PÄrlÅ«kÄ" - - - *: "maksimaalais failu skaits paarluukaa" - - - - id: LANG_MAX_FILES_IN_PLAYLIST - desc: in settings_menu - user: core - - *: "Max Playlist Size" - - - *: "Maks Saraksta IzmÄ“rs" - - - *: "maksimaalais dziesmu saraksta izmeers" - - - - id: LANG_CAR_ADAPTER_MODE - desc: Displayed for setting car adapter mode to on/off - user: core - - *: none - charging: "Car Adapter Mode" - - - *: none - charging: "AutomaÅ¡Ä«nas Režīms" - - - *: none - charging: "automashiinas rezhiims" - - - - id: LANG_ALARM_MOD_ALARM_MENU - desc: The name of the additional entry in the main menu for the RTC alarm mod. - user: core - - *: none - alarm: "Wake-Up Alarm" - - - *: none - alarm: "ModinÄtÄjs" - - - *: none - alarm: "modinaataajs" - - - - id: LANG_ALARM_WAKEUP_SCREEN - desc: in alarm menu setting - user: core - - *: none - alarm: "Alarm Wake up Screen" - - - *: none - alarm: "ModinÄtÄja DarbÄ«ba" - - - *: none - alarm: "modinaataaja darbiiba" - - - - id: LANG_ALARM_MOD_TIME - desc: The current alarm time shown in the alarm menu for the RTC alarm mod. - user: core - - *: none - alarm: "Alarm Time:" - - - *: none - alarm: "ModinÄtÄja laiks:" - - - *: none - alarm: "" - - - - id: LANG_ALARM_MOD_TIME_TO_GO - desc: The time until the alarm will go off shown in the alarm menu for the RTC alarm mod. - user: core - - *: none - alarm: "Waking Up In %d:%02d" - - - *: none - alarm: "PamoÅ¡anÄs %d:%02d" - - - *: none - alarm: "pamoshanaas" - - - - id: LANG_ALARM_MOD_SHUTDOWN - desc: The text that tells the user that the alarm time is ok and the device shuts off (for the RTC alarm mod). - user: core - - *: none - alarm: "Alarm Set" - - - *: none - alarm: "ModinÄtÄjs IeslÄ“gts" - - - *: none - alarm: "modinaataajs ir iesleegts" - - - - id: LANG_ALARM_MOD_ERROR - desc: The text that tells that the time is incorrect (for the RTC alarm mod). - user: core - - *: none - alarm: "Alarm Time Is Too Soon!" - - - *: none - alarm: "Laiks ir pÄrÄk drÄ«z!" - - - *: none - alarm: "modinaashanas laiks ir paaraak driiz!" - - - - id: LANG_ALARM_MOD_KEYS - desc: Shown key functions in alarm menu (for the RTC alarm mod). - user: core - - *: none - alarm: "PLAY=Set OFF=Cancel" - ipod*: "SELECT=Set MENU=Cancel" - iriverh10,iriverh10_5gb: "SELECT=Set PREV=Cancel" - gigabeats: "SELECT=Set POWER=Cancel" - vibe500: "OK=Set C=Cancel" - mpiohd300: "ENTER=Set MENU=Cancel" - - - *: none - alarm: "PLAY=Uzst OFF=Atteikties" - ipod*: "SELECT=Uzst MENU=Atteikties" - iriverh10,iriverh10_5gb: "SELECT=Uzst PREV=Atteikties" - gigabeats: "SELECT=Uzst POWER=Atteikties" - vibe500: "OK=Uzst C=Atteikties" - mpiohd300: "ENTER=Uzst MENU=Atteikties" - - - *: none - alarm,ipod*: "" - - - - id: LANG_ALARM_MOD_DISABLE - desc: Announce that the RTC alarm has been turned off - user: core - - *: none - alarm: "Alarm Disabled" - - - *: none - alarm: "ModinÄtÄjs IzslÄ“gts" - - - *: none - alarm: "modinaataajs izsleegts" - - - - id: LANG_BOOKMARK_SETTINGS - desc: in general settings - user: core - - *: "Bookmarking" - - - *: "GrÄmatzÄ«mes" - - - *: "graamatziimes" - - - - id: LANG_BOOKMARK_SETTINGS_AUTOCREATE - desc: prompt for user to decide to create an bookmark - user: core - - *: "Bookmark on Stop" - - - *: "GrÄmatzÄ«me ApstÄjoties" - - - *: "izveidot graamatziimi apstaajoties" - - - - id: LANG_BOOKMARK_SETTINGS_RECENT_ONLY_YES - desc: Save in recent bookmarks only - user: core - - *: "Yes - Recent only" - - - *: "JÄ - Tikai pÄ“dÄ“jo" - - - *: "jaa tikai peedeejo" - - - - id: LANG_BOOKMARK_SETTINGS_RECENT_ONLY_ASK - desc: Save in recent bookmarks only - user: core - - *: "Ask - Recent only" - - - *: "JautÄt - Tikai pÄ“dÄ“jo" - - - *: "jautaat tikai peedeejo" - - - - id: LANG_BOOKMARK_SETTINGS_AUTOLOAD - desc: prompt for user to decide to create a bookmark - user: core - - *: "Load Last Bookmark" - - - *: "IelÄdÄ“t PÄ“dÄ“jo GrÄmatzÄ«mi" - - - *: "ielaadeet peedeejo graamatziimi" - - - - id: LANG_BOOKMARK_SETTINGS_MAINTAIN_RECENT_BOOKMARKS - desc: Configuration option to maintain a list of recent bookmarks - user: core - - *: "Maintain a List of Recent Bookmarks?" - - - *: "UzturÄ“t GrÄmatzÄ«mju Sarakstu?" - - - *: "vai uztureet peedeejo graamatziimju sarakstu" - - - - id: LANG_BOOKMARK_SETTINGS_UNIQUE_ONLY - desc: Save only on bookmark for each playlist in recent bookmarks - user: core - - *: "Unique only" - - - *: "Tikai unikÄlu" - - - *: "tikai unikaalu" - - - - id: LANG_LANGUAGE - desc: in settings_menu - user: core - - *: "Language" - - - *: "Valoda" - - - *: "valoda" - - - - id: LANG_LANGUAGE_LOADED - desc: shown when a language has been loaded from the dir browser - user: core - - *: "New Language" - - - *: "Valoda NomainÄ«ta" - - - *: "valoda nomainiita" - - - - id: LANG_VOICE - desc: root of voice menu - user: core - - *: "Voice" - - - *: "Balss" - - - *: "balss" - - - - id: LANG_VOICE_MENU - desc: item of voice menu, enable/disable the voice UI - user: core - - *: "Voice Menus" - - - *: "IzrunÄt IzvÄ“lnes" - - - *: "izrunaat izveelnes" - - - - id: LANG_VOICE_DIR - desc: item of voice menu, set the voice mode for directories - user: core - - *: "Voice Directories" - - - *: "IzrunÄt Mapes" - - - *: "izrunaat mapes" - - - - id: LANG_VOICE_DIR_TALK - desc: Item of voice menu, whether to use directory .talk clips - user: core - - *: "Use Directory .talk Clips" - - - *: "Izmantot Mapes .talk Klipus" - - - *: "izmantot mapes .talk klipus" - - - - id: LANG_VOICE_FILE - desc: item of voice menu, set the voice mode for files - user: core - - *: "Voice Filenames" - - - *: "IzrunÄt Failu Nosaukumus" - - - *: "izrunaat failu nosaukumus" - - - - id: LANG_VOICE_FILE_TALK - desc: Item of voice menu, whether to use file .talk clips - user: core - - *: "Use File .talk Clips" - - - *: "Izmantot Failu .talk Klipus" - - - *: "izmantot failu .talk klipus" - - - - id: LANG_VOICE_NUMBER - desc: "talkbox" mode for files+directories - user: core - - *: "Numbers" - - - *: "Numuri" - - - *: "numuri" - - - - id: LANG_VOICE_SPELL - desc: "talkbox" mode for files+directories - user: core - - *: "Spell" - - - *: "IzrunÄt" - - - *: "izrunaat" - - - - id: LANG_VOICE_DIR_HOVER - desc: "talkbox" mode for directories + files - user: core - - *: ".talk Clip" - - - *: ".talk Klips" - - - *: "talk klips" - - - - id: LANG_MANAGE_MENU - desc: in the main menu - user: core - - *: "Manage Settings" - - - *: "Rediģēt UzstÄdÄ«jumus" - - - *: "redigjeet uzstaadiijumus" - - - - id: LANG_CUSTOM_CFG - desc: in setting_menu() - user: core - - *: "Browse .cfg Files" - - - *: "AplÅ«kot .cfg Failus" - - - *: "apluukot konfiguraacijas failus" - - - - id: LANG_SETTINGS_LOADED - desc: Feedback shown when a .cfg file is loaded - user: core - - *: "Settings Loaded" - - - *: "UzstÄdÄ«jumi IelÄdÄ“ti" - - - *: "uzstaadiijumi ielaadeeti" - - - - id: LANG_RESET - desc: in system_settings_menu() - user: core - - *: "Reset Settings" - - - *: "Atgriezt NoklusÄ“jumu" - - - *: "atgriezt nokluseetos uzstaadiijumus" - - - - id: LANG_RESET_DONE_CLEAR - desc: visual confirmation after settings reset - user: core - - *: "Cleared" - - - *: "Atgriezts NoklusÄ“jums" - - - *: "atgriezti nokluseetie uzstaadiijumi" - - - - id: LANG_SAVE_SETTINGS - desc: in system_settings_menu() - user: core - - *: "Save .cfg File" - - - *: "SaglabÄt .cfg Failu" - - - *: "saglabaat konfiguraacijas failu" - - - - id: LANG_SETTINGS_SAVED - desc: Feedback shown when a .cfg file is saved - user: core - - *: "Settings Saved" - - - *: "UzstÄdÄ«jumi SaglabÄti" - - - *: "uzstaadiijumi saglabaati" - - - - id: LANG_SAVE_THEME - desc: save a theme file - user: core - - *: "Save Theme Settings" - - - *: "SaglabÄt TÄ“mas UzstÄdÄ«jumus" - - - *: "saglabaat teemas uzstaadiijumus" - - - - id: LANG_CUSTOM_THEME - desc: in the main menu - user: core - - *: "Browse Theme Files" - - - *: "AplÅ«kot TÄ“mu Failus" - - - *: "apluukot teemu failus" - - - - id: LANG_RECORDING_SETTINGS - desc: in the main menu - user: core - - *: none - recording: "Recording Settings" - - - *: none - recording: "Ieraksta UzstÄdÄ«jumi" - - - *: none - recording: "ieraksta uzstaadiijumi" - - - - id: LANG_FM_MENU - desc: fm menu title - user: core - - *: none - radio: "FM Radio Menu" - - - *: none - radio: "FM Radio IzvÄ“lne" - - - *: none - radio: "ef em radio izveelne" - - - - id: LANG_FM_NO_PRESETS - desc: error when preset list is empty - user: core - - *: none - radio: "No presets" - - - *: none - radio: "Nav Staciju" - - - *: none - radio: "nav saglabaatu radiostaciju" - - - - id: LANG_FM_ADD_PRESET - desc: in radio menu - user: core - - *: none - radio: "Add Preset" - - - *: none - radio: "Pievienot Staciju" - - - *: none - radio: "pievienot radiostaciju" - - - - id: LANG_FM_EDIT_PRESET - desc: in radio screen - user: core - - *: none - radio: "Edit Preset" - - - *: none - radio: "Labot Staciju" - - - *: none - radio: "labot radiostaciju" - - - - id: LANG_FM_DELETE_PRESET - desc: in radio screen - user: core - - *: none - radio: "Remove Preset" - - - *: none - radio: "IzdzÄ“st Staciju" - - - *: none - radio: "izdzeest radiostaciju" - - - - id: LANG_FM_PRESET_SAVE_FAILED - desc: in radio screen - user: core - - *: none - radio: "Preset Save Failed" - - - *: none - radio: "Staciju NeizdevÄs SaglabÄt" - - - *: none - radio: "radiostaciju neizdevaas saglabaat" - - - - id: LANG_FM_NO_FREE_PRESETS - desc: in radio screen - user: core - - *: none - radio: "The Preset List is Full" - - - *: none - radio: "Saraksts Ir Pilns" - - - *: none - radio: "saraksts ir pilns" - - - - id: LANG_BUTTONBAR_MENU - desc: in button bar - user: core - - *: none - radio_screen_button_bar: "Menu" - - - *: none - radio_screen_button_bar: "IzvÄ“lne" - - - *: none - radio_screen_button_bar: "" - - - - id: LANG_FM_BUTTONBAR_EXIT - desc: in radio screen - user: core - - *: none - radio_screen_button_bar: "Exit" - - - *: none - radio_screen_button_bar: "Iziet" - - - *: none - radio_screen_button_bar: "" - - - - id: LANG_FM_BUTTONBAR_ACTION - desc: in radio screen - user: core - - *: none - radio_screen_button_bar: "Action" - - - *: none - radio_screen_button_bar: "DarbÄ«ba" - - - *: none - radio_screen_button_bar: "" - - - - id: LANG_PRESET - desc: in button bar and radio screen / menu - user: core - - *: none - radio: "Preset" - - - *: none - radio: "Stacija" - - - *: none - radio: "radiostacija" - - - - id: LANG_FM_BUTTONBAR_ADD - desc: in radio screen - user: core - - *: none - radio_screen_button_bar: "Add" - - - *: none - radio_screen_button_bar: "Pievienot" - - - *: none - radio_screen_button_bar: "" - - - - id: LANG_FM_BUTTONBAR_RECORD - desc: in radio screen - user: core - - *: none - radio_screen_button_bar: "Record" - - - *: none - radio_screen_button_bar: "IerakstÄ«t" - - - *: none - radio_screen_button_bar: "" - - - - id: LANG_FM_MONO_MODE - desc: in radio screen - user: core - - *: none - radio: "Force Mono" - - - *: none - radio: "IeslÄ“gt Mono" - - - *: none - radio: "iesleegt mono" - - - - id: LANG_FM_FREEZE - desc: splash screen during freeze in radio mode - user: core - - *: none - radio: "Screen frozen!" - - - *: none - radio: "EkrÄns Sastindzis!" - - - *: none - radio: "" - - - - id: LANG_FM_SCAN_PRESETS - desc: in radio menu - user: core - - *: none - radio: "Auto-Scan Presets" - - - *: none - radio: "NoskanÄ“t Stacijas" - - - *: none - radio: "noskaneet radiostacijas" - - - - id: LANG_FM_CLEAR_PRESETS - desc: confirmation if presets can be cleared - user: core - - *: none - radio: "Clear Current Presets?" - - - *: none - radio: "IzdzÄ“st EsoÅ¡Äs Stacijas?" - - - *: none - radio: "vai izdzeest esoshaas radiostacijas" - - - - id: LANG_FM_SCANNING - desc: during auto scan - user: core - - *: none - radio: "Scanning %d.%02d MHz" - - - *: none - radio: "SkanÄ“ %d.%02d MHz" - - - *: none - radio: "" - - - - id: LANG_FM_DEFAULT_PRESET_NAME - desc: default preset name for auto scan mode - user: core - - *: none - radio: "%d.%02d MHz" - - - *: none - radio: "%d.%02d MHz" - - - *: none - radio: "" - - - - id: LANG_RADIO_SCAN_MODE - desc: in radio screen / menu - user: core - - *: none - radio: "Scan" - - - *: none - radio: "SkanÄ“t" - - - *: none - radio: "skaneet" - - - - id: LANG_FM_PRESET_LOAD - desc: load preset list in fm radio - user: core - - *: none - radio: "Load Preset List" - - - *: none - radio: "IelÄdÄ“t Stacijas" - - - *: none - radio: "ielaadeet radiostacijas" - - - - id: LANG_FM_PRESET_SAVE - desc: Save preset list in fm radio - user: core - - *: none - radio: "Save Preset List" - - - *: none - radio: "SaglabÄt Stacijas" - - - *: none - radio: "saglabaat radiostacijas" - - - - id: LANG_FM_PRESET_CLEAR - desc: clear preset list in fm radio - user: core - - *: none - radio: "Clear Preset List" - - - *: none - radio: "IzdzÄ“st Stacijas" - - - *: none - radio: "izdzeest radiostacijas" - - - - id: LANG_FMR - desc: Used when you need to say Preset List, also voiced - user: core - - *: none - radio: "Preset List" - - - *: none - radio: "Staciju Saraksts" - - - *: none - radio: "radiostaciju saraksts" - - - - id: LANG_FM_FIRST_AUTOSCAN - desc: When you run the radio without an fmr file in settings - user: core - - *: none - radio: "No settings found. Autoscan?" - - - *: none - radio: "Nav UzstÄdÄ«jumu. SkanÄ“t?" - - - *: none - radio: "nav uzstaadiijumu. vai skaneet" - - - - id: LANG_FM_SAVE_CHANGES - desc: deprecated - user: core - - *: none - radio: "" - - - *: none - radio: "" - - - *: none - radio: "" - - - - id: LANG_FM_REGION - desc: fm tuner region setting - user: core - - *: none - radio: "Region" - - - *: none - radio: "ReÄ£ions" - - - *: none - radio: "regjions" - - - - id: LANG_FM_EUROPE - desc: fm tuner region europe - user: core - - *: none - radio: "Europe" - - - *: none - radio: "Eiropa" - - - *: none - radio: "eiropa" - - - - id: LANG_FM_US - desc: fm region us / canada - user: core - - *: none - radio: "US / Canada" - - - *: none - radio: "ASV / KanÄda" - - - *: none - radio: "asv un kanaada" - - - - id: LANG_FM_JAPAN - desc: fm region japan - user: core - - *: none - radio: "Japan" - - - *: none - radio: "JapÄna" - - - *: none - radio: "japaana" - - - - id: LANG_FM_KOREA - desc: fm region korea - user: core - - *: none - radio: "Korea" - - - *: none - radio: "Koreja" - - - *: none - radio: "koreja" - - - - id: LANG_RECORDING_FORMAT - desc: audio format item in recording menu - user: core - - *: none - recording: "Format" - - - *: none - recording: "FormÄts" - - - *: none - recording: "formaats" - - - - id: LANG_AFMT_MPA_L3 - desc: audio format description - user: core - - *: none - recording: "MPEG Layer 3" - - - *: none - recording: "MPEG Layer 3" - - - *: none - recording: "MPEG Layer 3" - - - - id: LANG_AFMT_PCM_WAV - desc: audio format description - user: core - - *: none - recording: "PCM Wave" - - - *: none - recording: "PCM Wave" - - - *: none - recording: "PCM Wave" - - - - id: LANG_AFMT_WAVPACK - desc: audio format description - user: core - - *: none - recording_swcodec: "WavPack" - - - *: none - recording_swcodec: "WavPack" - - - *: none - recording_swcodec: "WavPack" - - - - id: LANG_AFMT_AIFF - desc: audio format description - user: core - - *: none - recording: "AIFF" - - - *: none - recording: "AIFF" - - - *: none - recording: "AIFF" - - - - id: LANG_ENCODER_SETTINGS - desc: encoder settings - user: core - - *: none - recording: "Encoder Settings" - - - *: none - recording: "KodÄ“juma UzstÄdÄ«jumi" - - - *: none - recording: "kodeejuma uzstaadiijumi" - - - - id: LANG_BITRATE - desc: bits-kilobits per unit time - user: core - - *: none - recording_swcodec: "Bitrate" - - - *: none - recording_swcodec: "Bitreits" - - - *: none - recording_swcodec: "bitreits" - - - - id: LANG_NO_SETTINGS - desc: when something has settings in a certain context - user: core - - *: none - recording: "(No Settings)" - - - *: none - recording: "(Nav UzstÄdÄ«jumu)" - - - *: none - recording: "nav ko uzstaadiit" - - - - id: LANG_RECORDING_QUALITY - desc: in the recording settings - user: core - - *: none - recording_hwcodec: "Quality" - - - *: none - recording_hwcodec: "KvalitÄte" - - - *: none - recording_hwcodec: "kvalitaate" - - - - id: LANG_RECORDING_FREQUENCY - desc: in the recording settings - user: core - - *: none - recording: "Frequency" - - - *: none - recording: "Frekvence" - - - *: none - recording: "frekvence" - - - - id: LANG_SOURCE_FREQUENCY - desc: when recording source frequency setting must follow source - user: core - - *: none - recording: "(Same As Source)" - - - *: none - recording: "(KÄ Avots)" - - - *: none - recording: "taads pats kaa avots" - - - - id: LANG_RECORDING_SOURCE - desc: in the recording settings - user: core - - *: none - recording: "Source" - - - *: none - recording: "Avots" - - - *: none - recording: "avots" - - - - id: LANG_RECORDING_SRC_MIC - desc: in the recording settings - user: core - - *: none - recording: "Microphone" - iriverh100,iriverh120,iriverh300: "Internal Microphone" - - - *: none - recording: "Mikrofons" - iriverh100,iriverh120,iriverh300: "IevÅ«vÄ“tais Mikrofons" - - - *: none - recording: "mikrofons" - iriverh100,iriverh120,iriverh300: "iebuuveetais mikrofons" - - - - id: LANG_RECORDING_SRC_DIGITAL - desc: in the recording settings - user: core - - *: none - recording: "Digital" - - - *: none - recording: "DigitÄls" - - - *: none - recording: "digitaals" - - - - id: LANG_LINE_IN - desc: in the recording settings - user: core - - *: none - recording,archosplayer: "Line In" - - - *: none - recording,archosplayer: "LineÄrÄ Ieeja" - - - *: none - recording,archosplayer: "lineaaraa ieeja" - - - - id: LANG_RECORDING_EDITABLE - desc: Editable recordings setting - user: core - - *: none - recording_hwcodec: "Independent Frames" - - - *: none - recording_hwcodec: "NeatkarÄ«gi Kadri" - - - *: none - recording_hwcodec: "neatkariigi kadri" - - - - id: LANG_RECORD_TIMESPLIT - desc: Record split menu - user: core - - *: none - recording: "File Split Options" - - - *: none - recording: "Failu SadalÄ«Å¡anas Opcijas" - - - *: none - recording: "failu sadaliishanas opcijas" - - - - id: LANG_SPLIT_MEASURE - desc: in record timesplit options - user: core - - *: none - recording: "Split Measure" - - - *: none - recording: "SadalÄ«Å¡anas KritÄ“rijs" - - - *: none - recording: "sadaliishanas kriteerijs" - - - - id: LANG_SPLIT_TYPE - desc: in record timesplit options - user: core - - *: none - recording: "What to do when Splitting" - - - *: none - recording: "Ko DarÄ«t PÄ“c SadalÄ«Å¡anas" - - - *: none - recording: "ko dariit peec sadaliishanas" - - - - id: LANG_START_NEW_FILE - desc: in record timesplit options - user: core - - *: none - recording: "Start new file" - - - *: none - recording: "SÄkt Jaunu Failu" - - - *: none - recording: "saakt jaunu failu" - - - - id: LANG_STOP_RECORDING - desc: in record timesplit options - user: core - - *: none - recording: "Stop recording" - - - *: none - recording: "Beigt Ierakstu" - - - *: none - recording: "beigt ierakstu" - - - - id: LANG_SPLIT_TIME - desc: in record timesplit options - user: core - - *: none - recording: "Split Time" - - - *: none - recording: "SadalÄ«Å¡anas Laiks" - - - *: none - recording: "sadaliishanas laiks" - - - - id: LANG_SPLIT_SIZE - desc: in record timesplit options - user: core - - *: none - recording: "Split Filesize" - - - *: none - recording: "SadalÄ«Å¡anas IzmÄ“rs" - - - *: none - recording: "sadaliishanas izmeers" - - - - id: LANG_RECORD_PRERECORD_TIME - desc: in recording settings_menu - user: core - - *: none - recording: "Prerecord Time" - - - *: none - recording: "Pirmsieraksta Laiks" - - - *: none - recording: "pirmsieraksta laiks" - - - - id: LANG_RECORD_DIRECTORY - desc: in recording settings_menu - user: core - - *: none - recording: "Directory" - - - *: none - recording: "Mape" - - - *: none - recording: "mape" - - - - id: LANG_SET_AS_REC_DIR - desc: used in the onplay menu to set a recording dir - user: core - - *: none - recording: "Set As Recording Directory" - - - *: none - recording: "Uzlikt Par Ieraksta Mapi" - - - *: none - recording: "uzlikt par ieraksta mapi" - - - - id: LANG_CLEAR_REC_DIR - desc: - user: core - - *: none - recording: "Clear Recording Directory" - - - *: none - recording: "PÄrstatÄ«t Ieraksta Mapi" - - - *: none - recording: "paarstatiit ieraksta mapi" - - - - id: LANG_REC_DIR_NOT_WRITABLE - desc: - user: core - - *: none - recording: "Can't write to recording directory" - - - *: none - recording: "Nevar saglabÄt ieraksta mapÄ“" - - - *: none - recording: "nevar saglabaat ieraksta mapee" - - - - id: LANG_CLIP_LIGHT - desc: in record settings menu. - user: core - - *: none - recording: "Clipping Light" - - - *: none - recording: "PÄrlÄ«meņa Gaisma" - - - *: none - recording: "paarliimenja gaisma" - - - - id: LANG_MAIN_UNIT - desc: in record settings menu. - user: core - - *: none - remote: "Main Unit Only" - - - *: none - remote: "Tikai Uz EkrÄna" - - - *: none - remote: "tikai uz ekraana" - - - - id: LANG_REMOTE_UNIT - desc: in record settings menu. - user: core - - *: none - remote: "Remote Unit Only" - - - *: none - remote: "Tikai Uz Pults" - - - *: none - remote: "tikai uz pults" - - - - id: LANG_REMOTE_MAIN - desc: in record settings menu. - user: core - - *: none - remote: "Main and Remote Unit" - - - *: none - remote: "Uz EkrÄna Un Pults" - - - *: none - remote: "uz ekraana un pults" - - - - id: LANG_RECORD_TRIGGER - desc: in recording settings_menu - user: core - - *: none - recording: "Trigger" - - - *: none - recording: "PalaidÄ“js" - - - *: none - recording: "ieraksta palaideejs" - - - - id: LANG_RECORD_TRIG_NOREARM - desc: in recording settings_menu - user: core - - *: none - recording: "Once" - - - *: none - recording: "Vienreiz" - - - *: none - recording: "vienreiz" - - - - id: LANG_RECORD_TRIGGER_TYPE - desc: in recording trigger menu - user: core - - *: none - recording: "Trigtype" - - - *: none - recording: "Veids" - - - *: none - recording: "veids" - - - - id: LANG_RECORD_TRIGGER_NEWFILESTP - desc: trigger types - user: core - - *: none - recording: "New file" - - - *: none - recording: "Jauns Fails" - - - *: none - recording: "jauns fails" - - - - id: LANG_RECORD_TRIGGER_STOP - desc: trigger types - user: core - - *: none - recording: "Stop" - - - *: none - recording: "ApstÄties" - - - *: none - recording: "apstaaties" - - - - id: LANG_RECORD_START_THRESHOLD - desc: in recording settings_menu - user: core - - *: none - recording: "Start Above" - - - *: none - recording: "SÄkt Virs" - - - *: none - recording: "saakt virs" - - - - id: LANG_MIN_DURATION - desc: in recording settings_menu - user: core - - *: none - recording: "for at least" - - - *: none - recording: "PÄ“c Vismaz" - - - *: none - recording: "peec vismaz" - - - - id: LANG_RECORD_STOP_THRESHOLD - desc: in recording settings_menu - user: core - - *: none - recording: "Stop Below" - - - *: none - recording: "ApstÄties Zem" - - - *: none - recording: "apstaaties zem" - - - - id: LANG_RECORD_STOP_GAP - desc: in recording settings_menu - user: core - - *: none - recording: "Presplit Gap" - - - *: none - recording: "Pirmssadales Sprauga" - - - *: none - recording: "pirmssadales sprauga" - - - - id: LANG_RECORD_PRERECORD - desc: in recording and radio screen - user: core - - *: none - recording: "Pre-Recording" - - - *: none - recording: "Pirmsieraksts" - - - *: none - recording: "" - - - - id: LANG_AGC_SAFETY - desc: AGC preset - user: core - - *: none - agc: "Safety (clip)" - - - *: none - agc: "DroÅ¡Ä«ba (Skaļums)" - - - *: none - agc: "Droshiiba (skaljums)" - - - - id: LANG_AGC_LIVE - desc: AGC preset - user: core - - *: none - agc: "Live (slow)" - - - *: none - agc: "Koncerts (lÄ“ni)" - - - *: none - agc: "koncerts (leeni)" - - - - id: LANG_AGC_DJSET - desc: AGC preset - user: core - - *: none - agc: "DJ-Set (slow)" - - - *: none - agc: "Reps (lÄ“ni)" - - - *: none - agc: "reps (leeni)" - - - - id: LANG_AGC_MEDIUM - desc: AGC preset - user: core - - *: none - agc: "Medium" - - - *: none - agc: "VidÄ“ji" - - - *: none - agc: "videeji" - - - - id: LANG_AGC_VOICE - desc: AGC preset - user: core - - *: none - agc: "Voice (fast)" - - - *: none - agc: "Balss (Ätri)" - - - *: none - agc: "balss (aatri)" - - - - id: LANG_REMOTE_LCD_OFF - desc: Remote lcd off splash in recording screen - user: core - - *: none - remote: "Remote Display OFF" - - - *: none - remote: "Pults EkrÄns IzslÄ“gts" - - - *: none - remote: "pults ekraans izsleegts" - - - - id: LANG_REMOTE_LCD_ON - desc: Remote lcd off splash in recording screen - user: core - - *: none - remote: "(Vol- : Re-enable)" - - - *: none - remote: "(Skaļums- : IeslÄ“gt)" - - - *: none - remote: "spiest skaljumu lai iesleegtu" - - - - id: LANG_CREATE_PLAYLIST - desc: Menu option for creating a playlist - user: core - - *: "Create Playlist" - - - *: "Izveidot Sarakstu" - - - *: "izveidot sarakstu" - - - - id: LANG_PLAYLISTVIEWER_SETTINGS - desc: title for the playlist viewer settings menus - user: core - - *: "Playlist Viewer Settings" - - - *: "Sarakstu SkatÄ«tÄja UzstÄdÄ«jumi" - - - *: "sarakstu skatiitaaja uzstaadiijumi" - - - - id: LANG_VIEW_DYNAMIC_PLAYLIST - desc: in playlist menu. - user: core - - *: "View Current Playlist" - - - *: "AplÅ«kot PatreizÄ“jo Sarakstu" - - - *: "apluukot patreizeejo sarakstu" - - - - id: LANG_MOVE - desc: The verb/action Move - user: core - - *: "Move" - - - *: "PÄrvietot" - - - *: "paarvietot" - - - - id: LANG_SHOW_INDICES - desc: in playlist viewer menu - user: core - - *: "Show Indices" - - - *: "RÄdÄ«t Indeksus" - - - *: "raadiit indeksus" - - - - id: LANG_TRACK_DISPLAY - desc: in playlist viewer on+play menu - user: core - - *: "Track Display" - - - *: "ParÄdÄ«t Dziesmu" - - - *: "paraadiit dziesmu" - - - - id: LANG_DISPLAY_TRACK_NAME_ONLY - desc: track display options - user: core - - *: "Track Name Only" - - - *: "Tikai Nosaukumu" - - - *: "tikai nosaukumu" - - - - id: LANG_REMOVE - desc: in playlist viewer on+play menu - user: core - - *: "Remove" - - - *: "AizvÄkt" - - - *: "aizvaakt" - - - - id: LANG_SAVE_DYNAMIC_PLAYLIST - desc: in playlist menu. - user: core - - *: "Save Current Playlist" - - - *: "SaglabÄt PatreizÄ“jo Sarakstu" - - - *: "saglabaat patreizeejo sarakstu" - - - - id: LANG_PLAYLIST_SAVE_COUNT - desc: splash number of tracks saved - user: core - - *: "Saved %d tracks (%s)" - - - *: "SaglabÄtas %d dziesmas (%s)" - - - *: "saglabaatas dziesmas" - - - - id: LANG_CATALOG - desc: in main menu and onplay menu - user: core - - *: "Playlist Catalogue" - - - *: "Sarakstu Katalogs" - - - *: "sarakstu katalogs" - - - - id: LANG_RECURSE_DIRECTORY - desc: In playlist menu - user: core - - *: "Recursively Insert Directories" - - - *: "Ievietot Mapes Ar ApakÅ¡mapÄ“m" - - - *: "ievietot mapes ar apakshmapeem" - - - - id: LANG_RECURSE_DIRECTORY_QUESTION - desc: Asked from onplay screen - user: core - - *: "Recursively?" - - - *: "Ar ApakÅ¡mapÄ“m?" - - - *: "vai ar apakshmapeem" - - - - id: LANG_WARN_ERASEDYNPLAYLIST_MENU - desc: in playlist options menu, option to warn when erasing dynamic playlist - user: core - - *: "Warn When Erasing Dynamic Playlist" - - - *: "BrÄ«dinÄt DzÄ“Å¡ot Dinamisku sarakstu" - - - *: "briidinaat dzeeshot dinamisku sarakstu" - - - - id: LANG_WARN_ERASEDYNPLAYLIST_PROMPT - desc: prompt shown when about to erase a modified dynamic playlist - user: core - - *: "Erase dynamic playlist?" - - - *: "IzdzÄ“st Dinamisku Sarakstu?" - - - *: "vai izdzeest dinamisku sarakstu" - - - - id: LANG_SHUTDOWN - desc: in main menu - user: core - - *: none - soft_shutdown: "Shut down" - - - *: none - soft_shutdown: "IzslÄ“gt" - - - *: none - soft_shutdown: "izsleegt" - - - - id: LANG_ROCKBOX_INFO - desc: displayed topmost on the info screen and in the info menu - user: core - - *: "Rockbox Info" - - - *: "Par Rockbox" - - - *: "par rockbox" - - - - id: LANG_BUFFER_STAT - desc: the buffer size, %d MB %d fraction of MB - user: core - - *: "Buffer:" - archosplayer: "Buf:" - - - *: "Buferis:" - archosplayer: "Buf:" - - - *: "bufera izmeers" - - - - id: LANG_BATTERY_TIME - desc: battery level in % and estimated time remaining - user: core - - *: "Battery: %d%% %dh %dm" - archosplayer,archosrecorder,archosfmrecorder,archosrecorderv2,archosondio*,iriverifp7xx: "%d%% %dh %dm" - iriverh10,ipodmini1g,ipodmini2g: "Batt: %d%% %dh %dm" - - - *: "Baterija: %d%% %ds %dm" - archosplayer,archosrecorder,archosfmrecorder,archosrecorderv2,archosondio*,iriverifp7xx: "%d%% %ds %dm" - iriverh10,ipodmini1g,ipodmini2g: "Bat: %d%% %ds %dm" - - - *: "baterijas liimenis" - - - - id: LANG_DISK_SIZE_INFO - desc: disk size info - user: core - - *: "Disk:" - - - *: "Atmiņa:" - - - *: "atminjas izmeers" - - - - id: LANG_DISK_FREE_INFO - desc: disk size info - user: core - - *: "Free:" - - - *: "BrÄ«vs:" - - - *: "briivaa vieta:" - - - - id: LANG_DISK_NAME_INTERNAL - desc: in info menu; name for internal disk with multivolume (keep short!) - user: core - - *: none - multivolume: "Int:" - - - *: none - multivolume: "IeÄ·Å¡:" - - - *: none - multivolume: "ieksheejais" - - - - id: LANG_DISK_NAME_MMC - desc: in info menu; name for external disk with multivolume (Ondio; keep short!) - user: core - - *: none - multivolume: "HD1" - sansae200*,sansac200*,sansafuze*,sansaclipplus: "mSD:" - archosondio*: "MMC:" - - - *: none - multivolume: "HD1" - sansae200*,sansac200*,sansafuze*,sansaclipplus: "MSD:" - archosondio*: "MMC:" - - - *: none - multivolume: "haa dee viens" - sansae200*,sansac200*,sansafuze*: "mikro es dee" - archosondio*: "em em cee" - - - - id: LANG_VERSION - desc: in the Rockbox Info screen - user: core - - *: "Version" - - - *: "Versija" - - - *: "versija" - - - - id: LANG_RUNNING_TIME - desc: in run time screen - user: core - - *: "Running Time" - - - *: "IeslÄ“gts" - - - *: "iesleegts" - - - - id: LANG_TOP_TIME - desc: in run time screen - user: core - - *: "Top Time" - - - *: "IlgÄkais" - - - *: "ilgaakais" - - - - id: LANG_CLEAR_TIME - desc: in run time screen - user: core - - *: "Clear Time?" - - - *: "IzdzÄ“st Laiku?" - - - *: "vai izdzeest laiku" - - - - id: LANG_DEBUG - desc: in the info menu - user: core - - *: "Debug (Keep Out!)" - - - *: "Kļūdas (Neaiztiec!)" - - - *: "kljuudas neaiztiec" - - - - id: LANG_PLAYLIST - desc: Used when you need to say playlist, also voiced - user: core - - *: "Playlist" - - - *: "Saraksts" - - - *: "saraksts" - - - - id: LANG_INSERT - desc: in onplay menu. insert a track/playlist into dynamic playlist. - user: core - - *: "Insert" - - - *: "Ievietot" - - - *: "ievietot" - - - - id: LANG_INSERT_FIRST - desc: in onplay menu. insert a track/playlist into dynamic playlist. - user: core - - *: "Insert Next" - - - *: "Ievietot NÄkamo" - - - *: "ievietot Naakamo" - - - - id: LANG_INSERT_LAST - desc: in onplay menu. append a track/playlist into dynamic playlist. - user: core - - *: "Insert Last" - - - *: "Ievietot PÄ“dÄ“jo" - - - *: "ievietot peedeejo" - - - - id: LANG_INSERT_SHUFFLED - desc: in onplay menu. insert a track/playlist randomly into dynamic playlist - user: core - - *: "Insert Shuffled" - - - *: "Ievietot Sajaukti" - - - *: "ievietot sajaukti" - - - - id: LANG_QUEUE - desc: The verb/action Queue - user: core - - *: "Queue" - - - *: "Rinda" - - - *: "rinda" - - - - id: LANG_QUEUE_FIRST - desc: in onplay menu. queue a track/playlist into dynamic playlist. - user: core - - *: "Queue Next" - - - *: "RindÄ NÄkamo" - - - *: "rindaa naakamo" - - - - id: LANG_QUEUE_LAST - desc: in onplay menu. queue a track/playlist at end of playlist. - user: core - - *: "Queue Last" - - - *: "RindÄ PÄ“dÄ“jo" - - - *: "rindÄ peedeejo" - - - - id: LANG_QUEUE_SHUFFLED - desc: in onplay menu. queue a track/playlist randomly into dynamic playlist - user: core - - *: "Queue Shuffled" - - - *: "RindÄ Sajaukti" - - - *: "rindaa sajaukti" - - - - id: LANG_REPLACE - desc: in onplay menu. Replace the current playlist with a new one. - user: core - - *: "Play Next" - - - *: "Atskaņot NÄkamo" - - - *: "atskanjot naakamo" - - - - id: LANG_PLAYLIST_INSERT_COUNT - desc: splash number of tracks inserted - user: core - - *: "Inserted %d tracks (%s)" - - - *: "Ievietotas %d dziesmas (%s)" - - - *: "ievietotas dziesmas" - - - - id: LANG_PLAYLIST_QUEUE_COUNT - desc: splash number of tracks queued - user: core - - *: "Queued %d tracks (%s)" - - - *: "RindÄ %d dziesmas (%s)" - - - *: "ievietotas rindaa dziesmas" - - - - id: LANG_VIEW - desc: in on+play menu - user: core - - *: "View" - - - *: "AplÅ«kot" - - - *: "apluukot" - - - - id: LANG_SEARCH_IN_PLAYLIST - desc: in playlist menu. - user: core - - *: "Search In Playlist" - - - *: "MeklÄ“t SarakstÄ" - - - *: "mekleet sarakstaa" - - - - id: LANG_PLAYLIST_SEARCH_MSG - desc: splash number of tracks inserted - user: core - - *: "Searching... %d found (%s)" - - - *: "MeklÄ“... %d atrastas (%s)" - - - *: "" - - - - id: LANG_SHUFFLE_PLAYLIST - desc: in playlist menu, reshuffles the order in which songs are played - user: core - - *: "Reshuffle" - - - *: "PÄrkÄrtot" - - - *: "paarkaartot" - - - - id: LANG_CATALOG_VIEW - desc: in onplay playlist catalogue submenu - user: core - - *: "View Catalogue" - - - *: "AplÅ«kot Katalogu" - - - *: "apluukot katalogu" - - - - id: LANG_CATALOG_ADD_TO - desc: in onplay playlist catalogue submenu - user: core - - *: "Add to Playlist" - - - *: "Pievienot Sarakstam" - - - *: "pievienot sarakstam" - - - - id: LANG_CATALOG_ADD_TO_NEW - desc: in onplay playlist catalogue submenu - user: core - - *: "Add to New Playlist" - - - *: "Pievienot Jaunam Sarakstam" - - - *: "pievienot jaunam sarakstam" - - - - id: LANG_CATALOG_NO_DIRECTORY - desc: error message when playlist catalogue directory doesn't exist - user: core - - *: "%s doesn't exist" - - - *: "%s nepastÄv" - - - *: "saraksta mape nepastaav" - - - - id: LANG_CATALOG_NO_PLAYLISTS - desc: error message when no playlists for playlist catalogue - user: core - - *: "No Playlists" - - - *: "Nav Sarakstu" - - - *: "nav sarakstu" - - - - id: LANG_BOOKMARK_MENU - desc: Text on main menu to get to bookmark commands - user: core - - *: "Bookmarks" - - - *: "GrÄmatzÄ«mes" - - - *: "graamatziimes" - - - - id: LANG_BOOKMARK_MENU_CREATE - desc: Used off of the bookmark menu to create a bookmark - user: core - - *: "Create Bookmark" - - - *: "Izveidot GrÄmatzÄ«mi" - - - *: "izveidot graamatziimi" - - - - id: LANG_BOOKMARK_MENU_LIST - desc: Used off of the bookmark menu to list available bookmarks for the currently playing directory or M3U - user: core - - *: "List Bookmarks" - - - *: "SakÄrtot GrÄmatzÄ«mes" - - - *: "sakaartot graamatziimes" - - - - id: LANG_ONPLAY_MENU_TITLE - desc: title for the onplay menus - user: core - - *: "Context Menu" - - - *: "IzvÄ“lne" - - - *: "izveelne" - - - - id: LANG_MENU_SET_RATING - desc: Set the rating of a file in the wps context menu - user: core - - *: "Set Song Rating" - - - *: "Uzlikt VÄ“rtÄ“jumu" - - - *: "uzlikt veerteejumu" - - - - id: LANG_BROWSE_CUESHEET - desc: - user: core - - *: "Browse Cuesheet" - - - *: "AplÅ«kot cue" - - - *: "apluukot cue" - - - - id: LANG_MENU_SHOW_ID3_INFO - desc: Menu option to start tag viewer - user: core - - *: "Show Track Info" - - - *: "Dziesmas Info" - - - *: "paraadiit dziesmas info" - - - - id: LANG_ID3_TITLE - desc: in tag viewer - user: core - - *: "Title" - - - *: "Nosaukums" - - - *: "" - - - - id: LANG_ID3_ARTIST - desc: in tag viewer - user: core - - *: "Artist" - - - *: "IzpildÄ«tÄjs" - - - *: "" - - - - id: LANG_ID3_ALBUM - desc: in tag viewer - user: core - - *: "Album" - - - *: "AlbÅ«ms" - - - *: "" - - - - id: LANG_ID3_TRACKNUM - desc: in tag viewer - user: core - - *: "Tracknum" - - - *: "Numurs" - - - *: "" - - - - id: LANG_ID3_GENRE - desc: in tag viewer - user: core - - *: "Genre" - - - *: "Žanrs" - - - *: "" - - - - id: LANG_ID3_YEAR - desc: in tag viewer - user: core - - *: "Year" - - - *: "Gads" - - - *: "" - - - - id: LANG_ID3_LENGTH - desc: in tag viewer - user: core - - *: "Length" - - - *: "Garums" - - - *: "" - - - - id: LANG_ID3_PLAYLIST - desc: in tag viewer - user: core - - *: "Playlist" - - - *: "Saraksts" - - - *: "" - - - - id: LANG_ID3_BITRATE - desc: in tag viewer - user: core - - *: "Bitrate" - - - *: "Bitreits" - - - *: "" - - - - id: LANG_ID3_ALBUMARTIST - desc: in tag viewer - user: core - - *: "Album Artist" - - - *: "AlbÅ«ma IzpildÄ«tÄjs" - - - *: "" - - - - id: LANG_ID3_DISCNUM - desc: in tag viewer - user: core - - *: "Discnum" - - - *: "Diska Numurs" - - - *: "" - - - - id: LANG_ID3_COMMENT - desc: in tag viewer - user: core - - *: "Comment" - - - *: "KomentÄrs" - - - *: "" - - - - id: LANG_ID3_VBR - desc: in browse_id3 - user: core - - *: " (VBR)" - - - *: " (MBR)" - - - *: "" - - - - id: LANG_ID3_FREQUENCY - desc: in tag viewer - user: core - - *: "Frequency" - - - *: "Frekvence" - - - *: "" - - - - id: LANG_ID3_TRACK_GAIN - desc: in tag viewer - user: core - - *: "Track Gain" - - - *: "Dziesmas Skaļums" - - - *: "" - - - - id: LANG_ID3_ALBUM_GAIN - desc: in tag viewer - user: core - - *: "Album Gain" - - - *: "AlbÅ«ma Skaļums" - - - *: "" - - - - id: LANG_ID3_PATH - desc: in tag viewer - user: core - - *: "Path" - - - *: "Ceļš" - - - *: "" - - - - id: LANG_ID3_NO_INFO - desc: in tag viewer - user: core - - *: "" - - - *: "