diff options
author | Sean Bartell <wingedtachikoma@gmail.com> | 2011-06-25 21:32:25 -0400 |
---|---|---|
committer | Nils Wallménius <nils@rockbox.org> | 2012-04-25 22:13:20 +0200 |
commit | f40bfc9267b13b54e6379dfe7539447662879d24 (patch) | |
tree | 9b20069d5e62809ff434061ad730096836f916f2 /apps/codecs/libgme/nsf_emu.c | |
parent | a0009907de7a0107d49040d8a180f140e2eff299 (diff) |
Add codecs to librbcodec.
Change-Id: Id7f4717d51ed02d67cb9f9cb3c0ada4a81843f97
Reviewed-on: http://gerrit.rockbox.org/137
Reviewed-by: Nils Wallménius <nils@rockbox.org>
Tested-by: Nils Wallménius <nils@rockbox.org>
Diffstat (limited to 'apps/codecs/libgme/nsf_emu.c')
-rw-r--r-- | apps/codecs/libgme/nsf_emu.c | 921 |
1 files changed, 0 insertions, 921 deletions
diff --git a/apps/codecs/libgme/nsf_emu.c b/apps/codecs/libgme/nsf_emu.c deleted file mode 100644 index d9fc4e031d..0000000000 --- a/apps/codecs/libgme/nsf_emu.c +++ /dev/null @@ -1,921 +0,0 @@ -// Game_Music_Emu 0.6-pre. http://www.slack.net/~ant/ - -#include "nsf_emu.h" -#include "multi_buffer.h" - -#include "blargg_endian.h" - -/* Copyright (C) 2003-2006 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 gme_wrong_file_type [] = "Wrong file type for this emulator"; - -// number of frames until play interrupts init -int const initial_play_delay = 7; // KikiKaikai needed this to work -int const bank_size = 0x1000; -int const rom_addr = 0x8000; - -static void clear_track_vars( struct Nsf_Emu* this ) -{ - this->current_track = -1; - track_stop( &this->track_filter ); -} - -static int pcm_read( void* emu, int addr ) -{ - return *Cpu_get_code( &((struct Nsf_Emu*) emu)->cpu, addr ); -} - -void Nsf_init( struct Nsf_Emu* this ) -{ - 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; - - // Set sound gain - Sound_set_gain( this, (int)(FP_ONE_GAIN*1.2) ); - - // Init rom - Rom_init( &this->rom, bank_size ); - - // Init & clear nsfe info - Info_init( &this->info ); - Info_unload( &this->info ); // TODO: extremely hacky! - - Cpu_init( &this->cpu ); - Apu_init( &this->apu ); - Apu_dmc_reader( &this->apu, pcm_read, this ); - - // Unload - this->voice_count = 0; - memset( this->voice_types, 0, sizeof this->voice_types ); - clear_track_vars( this ); -} - -// Setup - -static void append_voices( struct Nsf_Emu* this, int const types [], int count ) -{ - assert( this->voice_count + count < max_voices ); - int i; - for ( i = 0; i < count; i++ ) { - this->voice_types [this->voice_count + i] = types [i]; - } - this->voice_count += count; -} - -static blargg_err_t init_sound( struct Nsf_Emu* this ) -{ -/* if ( header_.chip_flags & ~(fds_flag | namco_flag | vrc6_flag | fme7_flag) ) - warning( "Uses unsupported audio expansion hardware" ); **/ - - { - static int const types [apu_osc_count] = { - wave_type+1, wave_type+2, mixed_type+1, noise_type+0, mixed_type+1 - }; - append_voices( this, types, apu_osc_count ); - } - - int adjusted_gain = (this->gain * 4) / 3; - - #ifdef NSF_EMU_APU_ONLY - { - if ( this->header_.chip_flags ) - set_warning( "Uses unsupported audio expansion hardware" ); - } - #else - { - if ( vrc6_enabled( this ) ) - { - Vrc6_init( &this->vrc6 ); - adjusted_gain = (adjusted_gain*3) / 4; - - static int const types [vrc6_osc_count] = { - wave_type+3, wave_type+4, wave_type+5, - }; - append_voices( this, types, vrc6_osc_count ); - } - - if ( fme7_enabled( this ) ) - { - Fme7_init( &this->fme7 ); - adjusted_gain = (adjusted_gain*3) / 4; - - static int const types [fme7_osc_count] = { - wave_type+3, wave_type+4, wave_type+5, - }; - append_voices( this, types, fme7_osc_count ); - } - - if ( mmc5_enabled( this ) ) - { - Mmc5_init( &this->mmc5 ); - adjusted_gain = (adjusted_gain*3) / 4; - - - static int const types [mmc5_osc_count] = { - wave_type+3, wave_type+4, mixed_type+2 - }; - append_voices( this, types, mmc5_osc_count ); - } - - if ( fds_enabled( this ) ) - { - Fds_init( &this->fds ); - adjusted_gain = (adjusted_gain*3) / 4; - - static int const types [fds_osc_count] = { - wave_type+0 - }; - append_voices( this, types, fds_osc_count ); - } - - if ( namco_enabled( this ) ) - { - Namco_init( &this->namco ); - adjusted_gain = (adjusted_gain*3) / 4; - - static int const types [namco_osc_count] = { - wave_type+3, wave_type+4, wave_type+5, wave_type+ 6, - wave_type+7, wave_type+8, wave_type+9, wave_type+10, - }; - append_voices( this, types, namco_osc_count ); - } - - #ifndef NSF_EMU_NO_VRC7 - if ( vrc7_enabled( this ) ) - { - - Vrc7_init( &this->vrc7 ); - Vrc7_set_rate( &this->vrc7, this->sample_rate ); - - adjusted_gain = (adjusted_gain*3) / 4; - - static int const types [vrc7_osc_count] = { - wave_type+3, wave_type+4, wave_type+5, wave_type+6, - wave_type+7, wave_type+8 - }; - append_voices( this, types, vrc7_osc_count ); - } - - if ( vrc7_enabled( this ) ) Vrc7_volume( &this->vrc7, adjusted_gain ); - #endif - if ( namco_enabled( this ) ) Namco_volume( &this->namco, adjusted_gain ); - if ( vrc6_enabled( this ) ) Vrc6_volume( &this->vrc6, adjusted_gain ); - if ( fme7_enabled( this ) ) Fme7_volume( &this->fme7, adjusted_gain ); - if ( mmc5_enabled( this ) ) Apu_volume( &this->mmc5.apu, adjusted_gain ); - if ( fds_enabled( this ) ) Fds_volume( &this->fds, adjusted_gain ); - } - #endif - - if ( adjusted_gain > this->gain ) - adjusted_gain = this->gain; - - Apu_volume( &this->apu, adjusted_gain ); - - return 0; -} - -// Header stuff -static bool valid_tag( struct header_t* this ) -{ - return 0 == memcmp( this->tag, "NESM\x1A", 5 ); -} - -// True if file supports only PAL speed -static bool pal_only( struct header_t* this ) -{ - return (this->speed_flags & 3) == 1; -} - -static int clock_rate( struct header_t* this ) -{ - return pal_only( this ) ? (int)1662607.125 : (int)1789772.727272727; -} - -static int play_period( struct header_t* this ) -{ - // NTSC - int clocks = 29780; - int value = 0x411A; - byte const* rate_ptr = this->ntsc_speed; - - // PAL - if ( pal_only( this ) ) - { - clocks = 33247; - value = 0x4E20; - rate_ptr = this->pal_speed; - } - - // Default rate - int rate = get_le16( rate_ptr ); - if ( rate == 0 ) - rate = value; - - // Custom rate - if ( rate != value ) - clocks = (int) ((1LL * rate * clock_rate( this )) / 1000000); - - return clocks; -} - -// Gets address, given pointer to it in file header. If zero, returns rom_addr. -addr_t get_addr( byte const in [] ) -{ - addr_t addr = get_le16( in ); - if ( addr == 0 ) - addr = rom_addr; - return addr; -} - -static blargg_err_t check_nsf_header( struct header_t* h ) -{ - if ( !valid_tag( h ) ) - return gme_wrong_file_type; - return 0; -} - -blargg_err_t Nsf_load_mem( struct Nsf_Emu* this, void* data, long size ) -{ - // Unload - Info_unload( &this->info ); // TODO: extremely hacky! - this->m3u.size = 0; - - this->voice_count = 0; - clear_track_vars( this ); - - assert( offsetof (struct header_t,unused [4]) == header_size ); - - if ( !memcmp( data, "NESM\x1A", 5 ) ) { - Nsf_disable_playlist( this, true ); - - RETURN_ERR( Rom_load( &this->rom, data, size, header_size, &this->header, 0 ) ); - return Nsf_post_load( this ); - } - - blargg_err_t err = Info_load( &this->info, data, size, this ); - Nsf_disable_playlist( this, false ); - return err; -} - -blargg_err_t Nsf_post_load( struct Nsf_Emu* this ) -{ - RETURN_ERR( check_nsf_header( &this->header ) ); - - /* if ( header_.vers != 1 ) - warning( "Unknown file version" ); */ - - // set up data - addr_t load_addr = get_addr( this->header.load_addr ); - /* if ( load_addr < (fds_enabled() ? sram_addr : rom_addr) ) - warning( "Load address is too low" ); */ - - Rom_set_addr( &this->rom, load_addr % this->rom.bank_size ); - - /* if ( header_.vers != 1 ) - warning( "Unknown file version" ); */ - - set_play_period( this, play_period( &this->header ) ); - - // sound and memory - blargg_err_t err = init_sound( this ); - if ( err ) - return err; - - // Set track_count - this->track_count = this->header.track_count; - - // Change clock rate & setup buffer - this->clock_rate__ = clock_rate( &this->header ); - Buffer_clock_rate( &this->stereo_buf, this->clock_rate__ ); - 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 ); - - // Post load - Sound_set_tempo( this, this->tempo ); - Sound_mute_voices( this, this->mute_mask_ ); - return 0; -} - -void Nsf_disable_playlist( struct Nsf_Emu* this, bool b ) -{ - Info_disable_playlist( &this->info, b ); - this->track_count = this->info.track_count; -} - -void Nsf_clear_playlist( struct Nsf_Emu* this ) -{ - Nsf_disable_playlist( this, true ); -} - -void write_bank( struct Nsf_Emu* this, int bank, int data ) -{ - // Find bank in ROM - int offset = mask_addr( data * this->rom.bank_size, this->rom.mask ); - /* if ( offset >= rom.size() ) - warning( "invalid bank" ); */ - void const* rom_data = Rom_at_addr( &this->rom, offset ); - - #ifndef NSF_EMU_APU_ONLY - if ( bank < bank_count - fds_banks && fds_enabled( this ) ) - { - // TODO: FDS bank switching is kind of hacky, might need to - // treat ROM as RAM so changes won't get lost when switching. - byte* out = sram( this ); - if ( bank >= fds_banks ) - { - out = fdsram( this ); - bank -= fds_banks; - } - memcpy( &out [bank * this->rom.bank_size], rom_data, this->rom.bank_size ); - return; - } - #endif - - if ( bank >= fds_banks ) - Cpu_map_code( &this->cpu, (bank + 6) * this->rom.bank_size, this->rom.bank_size, rom_data, false ); -} - -static void map_memory( struct Nsf_Emu* this ) -{ - // Map standard things - Cpu_reset( &this->cpu, unmapped_code( this ) ); - Cpu_map_code( &this->cpu, 0, 0x2000, this->low_ram, low_ram_size ); // mirrored four times - Cpu_map_code( &this->cpu, sram_addr, sram_size, sram( this ), 0 ); - - // Determine initial banks - byte banks [bank_count]; - static byte const zero_banks [sizeof this->header.banks] = { 0 }; - if ( memcmp( this->header.banks, zero_banks, sizeof zero_banks ) ) - { - banks [0] = this->header.banks [6]; - banks [1] = this->header.banks [7]; - memcpy( banks + fds_banks, this->header.banks, sizeof this->header.banks ); - } - else - { - // No initial banks, so assign them based on load_addr - int i, first_bank = (get_addr( this->header.load_addr ) - sram_addr) / this->rom.bank_size; - unsigned total_banks = this->rom.size / this->rom.bank_size; - for ( i = bank_count; --i >= 0; ) - { - int bank = i - first_bank; - if ( (unsigned) bank >= total_banks ) - bank = 0; - banks [i] = bank; - } - } - - // Map banks - int i; - for ( i = (fds_enabled( this ) ? 0 : fds_banks); i < bank_count; ++i ) - write_bank( this, i, banks [i] ); - - // Map FDS RAM - if ( fds_enabled( this ) ) - Cpu_map_code( &this->cpu, rom_addr, fdsram_size, fdsram( this ), 0 ); -} - -static void set_voice( struct Nsf_Emu* this, int i, struct Blip_Buffer* buf, struct Blip_Buffer* left, struct Blip_Buffer* right) -{ -#if defined(ROCKBOX) - (void) left; - (void) right; -#endif - - if ( i < apu_osc_count ) - { - Apu_osc_output( &this->apu, i, buf ); - return; - } - i -= apu_osc_count; - - #ifndef NSF_EMU_APU_ONLY - { - if ( vrc6_enabled( this ) && (i -= vrc6_osc_count) < 0 ) - { - Vrc6_osc_output( &this->vrc6, i + vrc6_osc_count, buf ); - return; - } - - if ( fme7_enabled( this ) && (i -= fme7_osc_count) < 0 ) - { - Fme7_osc_output( &this->fme7, i + fme7_osc_count, buf ); - return; - } - - if ( mmc5_enabled( this ) && (i -= mmc5_osc_count) < 0 ) - { - Mmc5_set_output( &this->mmc5, i + mmc5_osc_count, buf ); - return; - } - - if ( fds_enabled( this ) && (i -= fds_osc_count) < 0 ) - { - Fds_set_output( &this->fds, i + fds_osc_count, buf ); - return; - } - - if ( namco_enabled( this ) && (i -= namco_osc_count) < 0 ) - { - Namco_osc_output( &this->namco, i + namco_osc_count, buf ); - return; - } - - #ifndef NSF_EMU_NO_VRC7 - if ( vrc7_enabled( this ) && (i -= vrc7_osc_count) < 0 ) - { - Vrc7_set_output( &this->vrc7, i + vrc7_osc_count, buf ); - return; - } - #endif - } - #endif -} - -// Emulation - -// Music Emu - -blargg_err_t Nsf_set_sample_rate( struct Nsf_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 bass frequency - 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 Nsf_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 Nsf_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, 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 - set_voice( this, i, ch.center, ch.left, ch.right ); - } - } -} - -void Sound_set_tempo( struct Nsf_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; - - set_play_period( this, (int) ((play_period( &this->header ) * FP_ONE_TEMPO) / t) ); - - Apu_set_tempo( &this->apu, t ); - -#ifndef NSF_EMU_APU_ONLY - if ( fds_enabled( this ) ) - Fds_set_tempo( &this->fds, t ); -#endif -} - -static inline void push_byte( struct Nsf_Emu* this, int b ) -{ - this->low_ram [0x100 + this->cpu.r.sp--] = b; -} - -// Jumps to routine, given pointer to address in file header. Pushes idle_addr -// as return address, NOT old PC. -static void jsr_then_stop( struct Nsf_Emu* this, byte const addr [] ) -{ - this->cpu.r.pc = get_addr( addr ); - push_byte( this, (idle_addr - 1) >> 8 ); - push_byte( this, (idle_addr - 1) ); -} - -int cpu_read( struct Nsf_Emu* this, addr_t addr ) -{ - #ifndef NSF_EMU_APU_ONLY - { - if ( namco_enabled( this ) && addr == namco_data_reg_addr ) - return Namco_read_data( &this->namco ); - - if ( fds_enabled( this ) && (unsigned) (addr - fds_io_addr) < fds_io_size ) - return Fds_read( &this->fds, Cpu_time( &this->cpu ), addr ); - - if ( mmc5_enabled( this ) ) { - int i = addr - 0x5C00; - if ( (unsigned) i < mmc5_exram_size ) - return this->mmc5.exram [i]; - - int m = addr - 0x5205; - if ( (unsigned) m < 2 ) - return (this->mmc5_mul [0] * this->mmc5_mul [1]) >> (m * 8) & 0xFF; - } - } - #endif - - /* Unmapped read */ - return addr >> 8; -} - -void cpu_write( struct Nsf_Emu* this, addr_t addr, int data ) -{ - #ifndef NSF_EMU_APU_ONLY - { - if ( fds_enabled( this) && (unsigned) (addr - fds_io_addr) < fds_io_size ) - { - Fds_write( &this->fds, Cpu_time( &this->cpu ), addr, data ); - return; - } - - if ( namco_enabled( this) ) - { - if ( addr == namco_addr_reg_addr ) - { - Namco_write_addr( &this->namco, data ); - return; - } - - if ( addr == namco_data_reg_addr ) - { - Namco_write_data( &this->namco, Cpu_time( &this->cpu ), data ); - return; - } - } - - if ( vrc6_enabled( this) ) - { - int reg = addr & (vrc6_addr_step - 1); - int osc = (unsigned) (addr - vrc6_base_addr) / vrc6_addr_step; - if ( (unsigned) osc < vrc6_osc_count && (unsigned) reg < vrc6_reg_count ) - { - Vrc6_write_osc( &this->vrc6, Cpu_time( &this->cpu ), osc, reg, data ); - return; - } - } - - if ( fme7_enabled( this) && addr >= fme7_latch_addr ) - { - switch ( addr & fme7_addr_mask ) - { - case fme7_latch_addr: - Fme7_write_latch( &this->fme7, data ); - return; - - case fme7_data_addr: - Fme7_write_data( &this->fme7, Cpu_time( &this->cpu ), data ); - return; - } - } - - if ( mmc5_enabled( this) ) - { - if ( (unsigned) (addr - mmc5_regs_addr) < mmc5_regs_size ) - { - Mmc5_write_register( &this->mmc5, Cpu_time( &this->cpu ), addr, data ); - return; - } - - int m = addr - 0x5205; - if ( (unsigned) m < 2 ) - { - this->mmc5_mul [m] = data; - return; - } - - int i = addr - 0x5C00; - if ( (unsigned) i < mmc5_exram_size ) - { - this->mmc5.exram [i] = data; - return; - } - } - - #ifndef NSF_EMU_NO_VRC7 - if ( vrc7_enabled( this) ) - { - if ( addr == 0x9010 ) - { - Vrc7_write_reg( &this->vrc7, data ); - return; - } - - if ( (unsigned) (addr - 0x9028) <= 0x08 ) - { - Vrc7_write_data( &this->vrc7, Cpu_time( &this->cpu ), data ); - return; - } - } - #endif - } - #endif - - // Unmapped_write -} - -blargg_err_t Nsf_start_track( struct Nsf_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; - } - else track = Info_remap_track( &this->info, track ); - - this->current_track = track; - Buffer_clear( &this->stereo_buf ); - - #ifndef NSF_EMU_APU_ONLY - if ( mmc5_enabled( this ) ) - { - this->mmc5_mul [0] = 0; - this->mmc5_mul [1] = 0; - memset( this->mmc5.exram, 0, mmc5_exram_size ); - } - - if ( fds_enabled( this ) ) Fds_reset( &this->fds ); - if ( namco_enabled( this ) ) Namco_reset( &this->namco ); - if ( vrc6_enabled( this ) ) Vrc6_reset( &this->vrc6 ); - if ( fme7_enabled( this ) ) Fme7_reset( &this->fme7 ); - if ( mmc5_enabled( this ) ) Apu_reset( &this->mmc5.apu, false, 0 ); - #ifndef NSF_EMU_NO_VRC7 - if ( vrc7_enabled( this ) ) Vrc7_reset( &this->vrc7 ); - #endif - #endif - - int speed_flags = 0; - #ifdef NSF_EMU_EXTRA_FLAGS - speed_flags = this->header.speed_flags; - #endif - - Apu_reset( &this->apu, pal_only( &this->header ), (speed_flags & 0x20) ? 0x3F : 0 ); - Apu_write_register( &this->apu, 0, 0x4015, 0x0F ); - Apu_write_register( &this->apu, 0, 0x4017, (speed_flags & 0x10) ? 0x80 : 0 ); - - memset( unmapped_code( this ), halt_opcode, unmapped_size ); - memset( this->low_ram, 0, low_ram_size ); - memset( sram( this ), 0, sram_size ); - - map_memory( this ); - - // Arrange time of first call to play routine - this->play_extra = 0; - this->next_play = this->play_period; - - this->play_delay = initial_play_delay; - this->saved_state.pc = idle_addr; - - // Setup for call to init routine - this->cpu.r.a = track; - this->cpu.r.x = pal_only( &this->header ); - this->cpu.r.sp = 0xFF; - jsr_then_stop( this, this->header.init_addr ); - /* if ( this->cpu.r.pc < get_addr( header.load_addr ) ) - warning( "Init address < load address" ); */ - - // 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 ); -} - -void run_once( struct Nsf_Emu* this, nes_time_t end ) -{ - // Emulate until next play call if possible - if ( run_cpu_until( this, min( this->next_play, end ) ) ) - { - // Halt instruction encountered - - if ( this->cpu.r.pc != idle_addr ) - { - // special_event( "illegal instruction" ); - Cpu_set_time( &this->cpu, this->cpu.end_time ); - return; - } - - // Init/play routine returned - this->play_delay = 1; // play can now be called regularly - - if ( this->saved_state.pc == idle_addr ) - { - // nothing to run - nes_time_t t = this->cpu.end_time; - if ( Cpu_time( &this->cpu ) < t ) - Cpu_set_time( &this->cpu, t ); - } - else - { - // continue init routine that was interrupted by play routine - this->cpu.r = this->saved_state; - this->saved_state.pc = idle_addr; - } - } - - if ( Cpu_time( &this->cpu ) >= this->next_play ) - { - // Calculate time of next call to play routine - this->play_extra ^= 1; // extra clock every other call - this->next_play += this->play_period + this->play_extra; - - // Call routine if ready - if ( this->play_delay && !--this->play_delay ) - { - // Save state if init routine is still running - if ( this->cpu.r.pc != idle_addr ) - { - check( this->saved_state.pc == idle_addr ); - this->saved_state = this->cpu.r; - // special_event( "play called during init" ); - } - - jsr_then_stop( this, this->header.play_addr ); - } - } -} - -void run_until( struct Nsf_Emu* this, nes_time_t end ) -{ - while ( Cpu_time( &this->cpu ) < end ) - run_once( this, end ); -} - -static void end_frame( struct Nsf_Emu* this, nes_time_t end ) -{ - if ( Cpu_time( &this->cpu ) < end ) - run_until( this, end ); - Cpu_adjust_time( &this->cpu, -end ); - - // Localize to new time frame - this->next_play -= end; - check( this->next_play >= 0 ); - if ( this->next_play < 0 ) - this->next_play = 0; - - Apu_end_frame( &this->apu, end ); - - #ifndef NSF_EMU_APU_ONLY - if ( fds_enabled( this ) ) Fds_end_frame( &this->fds, end ); - if ( fme7_enabled( this ) ) Fme7_end_frame( &this->fme7, end ); - if ( mmc5_enabled( this ) ) Apu_end_frame( &this->mmc5.apu, end ); - if ( namco_enabled( this ) ) Namco_end_frame( &this->namco, end ); - if ( vrc6_enabled( this ) ) Vrc6_end_frame( &this->vrc6, end ); - #ifndef NSF_EMU_NO_VRC7 - if ( vrc7_enabled( this ) ) Vrc7_end_frame( &this->vrc7, end ); - #endif - #endif -} - -// 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 Nsf_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 Nsf_Emu* this, int msec ) -{ - int time = msec_to_samples( msec, this->sample_rate ); - if ( time < track_sample_count( &this->track_filter ) ) - RETURN_ERR( Nsf_start_track( this, this->current_track ) ); - return Track_skip( this, time - track_sample_count( &this->track_filter ) ); -} - -blargg_err_t Track_skip( struct Nsf_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 Nsf_Emu* this = (struct Nsf_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 ); -} - -// Fading - -void Track_set_fade( struct Nsf_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 Nsf_play( struct Nsf_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 Nsf_Emu* this = (struct Nsf_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; -} - -blargg_err_t run_clocks( struct Nsf_Emu* this, blip_time_t* duration, int msec ) -{ -#if defined(ROCKBOX) - (void) msec; -#endif - - end_frame( this, *duration ); - return 0; -} |