changeset 0:e38dacceb958

initial import
author Robert McIntyre <rlm@mit.edu>
date Fri, 21 Oct 2011 05:53:11 -0700
parents
children 2ad543b339f1
files Makefile changes.txt demo/benchmark.c demo/comm.c demo/demo_util.c demo/demo_util.h demo/play_spc.c demo/save_state.c demo/spc_record demo/trim_spc.c demo/wave_writer.c demo/wave_writer.h fast_dsp/SPC_DSP.cpp fast_dsp/SPC_DSP.h license.txt readme.txt snes_spc.txt snes_spc/SNES_SPC.cpp snes_spc/SNES_SPC.h snes_spc/SNES_SPC.h.gch snes_spc/SNES_SPC_misc.cpp snes_spc/SNES_SPC_state.cpp snes_spc/SPC_CPU.h snes_spc/SPC_CPU.h.gch snes_spc/SPC_DSP.cpp snes_spc/SPC_DSP.h snes_spc/SPC_DSP.h.gch snes_spc/SPC_Filter.cpp snes_spc/SPC_Filter.h snes_spc/SPC_Filter.h.gch snes_spc/blargg_common.h snes_spc/blargg_common.h.gch snes_spc/blargg_config.h snes_spc/blargg_config.h.gch snes_spc/blargg_endian.h snes_spc/blargg_endian.h.gch snes_spc/blargg_source.h snes_spc/blargg_source.h.gch snes_spc/dsp.cpp snes_spc/dsp.h snes_spc/dsp.h.gch snes_spc/spc.cpp snes_spc/spc.h snes_spc/spc.h.gch
diffstat 44 files changed, 7432 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/Makefile	Fri Oct 21 05:53:11 2011 -0700
     1.3 @@ -0,0 +1,11 @@
     1.4 +spc_record: 
     1.5 +
     1.6 +
     1.7 +whatever : snes_spc/SNES_SPC.cpp
     1.8 +	g++ -c snes_spc/*.cpp
     1.9 +
    1.10 +
    1.11 +
    1.12 +clean: 
    1.13 +	find . \( -name "*.o" -print0 \) -o \
    1.14 +               \( -name "spc" -print0 \) | xargs -t -0 rm
    1.15 \ No newline at end of file
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/changes.txt	Fri Oct 21 05:53:11 2011 -0700
     2.3 @@ -0,0 +1,107 @@
     2.4 +snes_spc Change Log
     2.5 +-------------------
     2.6 +
     2.7 +snes_spc 0.9.0
     2.8 +--------------
     2.9 +- Improved documentation
    2.10 +
    2.11 +- SPC: Added spc_skip() function for quickly seeking in an SPC music
    2.12 +file. Runs 3-4x faster than normal playback using the fast DSP (or about
    2.13 +43-60X real-time on my 400 MHz Mac).
    2.14 +
    2.15 +- SPC: Added spc_set_tempo() to change tempo of SPC music playback.
    2.16 +
    2.17 +- SPC: Sample generation is now corrected to generate exactly one pair
    2.18 +of samples every 32 clocks without exception. Before it could generate a
    2.19 +few samples more or less depending on how far ahead or behind DSP was at
    2.20 +the moment.
    2.21 +
    2.22 +- SPC: Changed spc_reset() and spc_soft_reset() to also reset output
    2.23 +buffer (see spc.h).
    2.24 +
    2.25 +- SPC: Fixed minor timer counting bug.
    2.26 +
    2.27 +- SPC: Stack pointer wrap-around is now emulated (and without any
    2.28 +noticeable performance hit).
    2.29 +
    2.30 +- SPC: Runs about 5% faster due to various optimizations.
    2.31 +
    2.32 +- SPC: Found way to make fast DSP register accesses cycle-accurate in
    2.33 +most cases, without reducing performance. Allows fast DSP to pass most
    2.34 +of my validation tests.
    2.35 +
    2.36 +- DSP: Added surround disable support to fast DSP again.
    2.37 +
    2.38 +- DSP: Improved voice un-muting to take effect immediately on fast DSP.
    2.39 +
    2.40 +- DSP: Noise shift register now starts at 0x4000 instead of 0x4001 as it
    2.41 +incorrectly did before.
    2.42 +
    2.43 +- Converted library to C++ code internally. A C interface is still
    2.44 +included in spc.h and dsp.h. Note that these are different than the
    2.45 +previous interface, so your code will require minor changes:
    2.46 +
    2.47 +	Old SPC code                            New SPC code
    2.48 +	- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    2.49 +	#include "spc/spc.h"                    #include "snes_spc/spc.h"
    2.50 +
    2.51 +	snes_spc_t* spc;                        SNES_SPC* spc;
    2.52 +	spc = malloc( sizeof (snes_spc_t) );    spc = spc_new();
    2.53 +	spc_init( spc );
    2.54 +	
    2.55 +	spc_end_frame( time );                  spc_end_frame( spc, time );
    2.56 +	/* etc. */
    2.57 +	
    2.58 +	/* done using SPC */                    spc_delete( spc );
    2.59 +	
    2.60 +	
    2.61 +	Old DSP code                            New DSP code
    2.62 +	- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    2.63 +	#include "spc/spc_dsp.h"                #include "snes_spc/dsp.h"
    2.64 +	
    2.65 +	spc_dsp_init( ram );                    SPC_DSP* dsp;
    2.66 +											dsp = spc_dsp_new();
    2.67 +											spc_dsp_init( dsp, ram );
    2.68 +	
    2.69 +	spc_dsp_run( count );                   spc_dsp_run( dsp, count );
    2.70 +	/* etc. */
    2.71 +	
    2.72 +	/* done using DSP */                    spc_dsp_delete( dsp );
    2.73 +	
    2.74 +
    2.75 +snes_spc 0.8.0
    2.76 +--------------
    2.77 +- Added several demos
    2.78 +
    2.79 +- Added high-pass/low-pass filter to better match SNES sound
    2.80 +
    2.81 +- Added save state functionality for SPC and accurate DSP (but not fast
    2.82 +DSP)
    2.83 +
    2.84 +- Added emulation of reset switch on NES (soft reset)
    2.85 +
    2.86 +- Made source more compatible with pre-C99 compilers by eliminating
    2.87 +mid-block declarations
    2.88 +
    2.89 +- SPC: Many S-SMP accuracy improvements, mostly in memory access times
    2.90 +
    2.91 +- SPC: S-SMP speed improvements
    2.92 +
    2.93 +- SPC: Added SPC load/save functions and KON checking to help trim
    2.94 +silence from beginning
    2.95 +
    2.96 +- SPC: Changed spc_init() to have you allocate most of the memory used
    2.97 +by the library so you have more control over it
    2.98 +
    2.99 +- DSP: New highly accurate DSP and faster version derived from same code
   2.100 +
   2.101 +- DSP: Changed prefix from dsp_ to spc_dsp_. Your DSP code will require
   2.102 +changes.
   2.103 +
   2.104 +- DSP: Removed surround disable and gain. Gain can now be done with the
   2.105 +dsp_filter module, and surround disable will probably only be
   2.106 +implemented in the fast DSP at some point.
   2.107 +
   2.108 +- DSP: Changed interface to work in clocks rather than samples,
   2.109 +necessary for the new accurate DSP. Sample output is now done with
   2.110 +separate functions. Your DSP code will require changes.
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/demo/benchmark.c	Fri Oct 21 05:53:11 2011 -0700
     3.3 @@ -0,0 +1,58 @@
     3.4 +/* Measures performance of SPC emulator. Takes about 4 seconds.
     3.5 +NOTE: This assumes that the program is getting all processor time; you might need to
     3.6 +arrange for this or else the performance will be reported lower than it really is.
     3.7 +
     3.8 +Usage: benchmark [test.spc]
     3.9 +*/
    3.10 +
    3.11 +#include "snes_spc/spc.h"
    3.12 +
    3.13 +#include "demo_util.h" /* error(), load_file() */
    3.14 +#include <time.h>
    3.15 +
    3.16 +clock_t start_timing( int seconds );
    3.17 +
    3.18 +int main( int argc, char** argv )
    3.19 +{
    3.20 +	/* Load SPC */
    3.21 +	long spc_size;
    3.22 +	void* spc = load_file( (argc > 1) ? argv [1] : "test.spc", &spc_size );
    3.23 +	SNES_SPC* snes_spc = spc_new();
    3.24 +	if ( !snes_spc ) error( "Out of memory" );
    3.25 +	spc_load_spc( snes_spc, spc, spc_size );
    3.26 +	free( spc );
    3.27 +	
    3.28 +	{
    3.29 +		/* Repeatedly fill buffer for 4 seconds */
    3.30 +		int const seconds = 4;
    3.31 +		#define BUF_SIZE 4096
    3.32 +		clock_t end = start_timing( seconds );
    3.33 +		int count = 0;
    3.34 +		while ( clock() < end )
    3.35 +		{
    3.36 +			static short buf [BUF_SIZE];
    3.37 +			error( spc_play( snes_spc, BUF_SIZE, buf ) );
    3.38 +			count++;
    3.39 +		}
    3.40 +		
    3.41 +		/* Report performance based on how many buffer fills were possible */
    3.42 +		{
    3.43 +			double rate = (double) count * BUF_SIZE / (spc_sample_rate * 2 * seconds);
    3.44 +			printf( "Performance: %.3fx real-time, or %.0f%% CPU for normal rate\n",
    3.45 +					rate, 100.0 / rate );
    3.46 +		}
    3.47 +	}
    3.48 +	
    3.49 +	return 0;
    3.50 +}
    3.51 +
    3.52 +/* Synchronizes with host clock and returns clock() time that is duration seconds from now */
    3.53 +clock_t start_timing( int duration )
    3.54 +{
    3.55 +	clock_t clock_dur = duration * CLOCKS_PER_SEC;
    3.56 +	clock_t time = clock();
    3.57 +	while ( clock() == time ) { }
    3.58 +	if ( clock() - time > clock_dur )
    3.59 +		error( "Insufficient clock() time resolution" );
    3.60 +	return clock() + clock_dur;
    3.61 +}
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/demo/comm.c	Fri Oct 21 05:53:11 2011 -0700
     4.3 @@ -0,0 +1,70 @@
     4.4 +/* Communicates with SPC the way the SNES would.
     4.5 +
     4.6 +Note: You'll need an "spc_rom.h" file that contains the 64-byte IPL ROM contents */
     4.7 +
     4.8 +#include "snes_spc/spc.h"
     4.9 +
    4.10 +#include "demo_util.h"
    4.11 +#include <string.h>
    4.12 +#include <stdio.h>
    4.13 +
    4.14 +static SNES_SPC* snes_spc;
    4.15 +
    4.16 +/* Make port access more convenient. Fakes time by simply incrementing it each call. */
    4.17 +static spc_time_t stime;
    4.18 +static int  pread ( int port )           { return spc_read_port( snes_spc, stime++, port ); }
    4.19 +static void pwrite( int port, int data ) { spc_write_port( snes_spc, stime++, port, data ); }
    4.20 +
    4.21 +static unsigned char const spc_rom [spc_rom_size] = {
    4.22 +	/* ROM data not provided with emulator */
    4.23 +	#include "spc_rom.h"
    4.24 +};
    4.25 +
    4.26 +int main()
    4.27 +{
    4.28 +	int i;
    4.29 +	
    4.30 +	/* Data to upload */
    4.31 +	static unsigned char const data [4] = "\xFA\xDE\xD1";
    4.32 +	unsigned const data_addr = 0xF5; /* second I/O port */
    4.33 +	
    4.34 +	snes_spc = spc_new();
    4.35 +	if ( !snes_spc ) error( "Out of memory" );
    4.36 +	spc_init_rom( snes_spc, spc_rom );
    4.37 +	spc_reset( snes_spc );
    4.38 +	
    4.39 +	/* Simulate reads and writes that SNES code would do */
    4.40 +	
    4.41 +	/* Wait for SPC to be ready */
    4.42 +	while ( pread( 0 ) != 0xAA || pread( 1 ) != 0xBB ) { }
    4.43 +	
    4.44 +	/* Start address */
    4.45 +	pwrite( 2, data_addr & 0xFF );
    4.46 +	pwrite( 3, data_addr >> 8 );
    4.47 +	
    4.48 +	/* Tell SPC to start transfer and wait for acknowledgement */
    4.49 +	pwrite( 0, 0xCC );
    4.50 +	pwrite( 1, 0x01 );
    4.51 +	while ( pread( 0 ) != 0xCC ) { }
    4.52 +	
    4.53 +	/* Send each byte and wait for acknowledgement */
    4.54 +	for ( i = 0; i < 4; i++ )
    4.55 +	{
    4.56 +		printf( "%02X ", data [i] );
    4.57 +		pwrite( 1, data [i] );
    4.58 +		pwrite( 0, i );
    4.59 +		while ( pread( 0 ) != i ) { }
    4.60 +	}
    4.61 +	printf( "\n" );
    4.62 +	
    4.63 +	/* Verify that data was transferred properly */
    4.64 +	for ( i = 0; i < 3; i++ )
    4.65 +		printf( "%02X ", pread( i + 1 ) );
    4.66 +	printf( "\n" );
    4.67 +	
    4.68 +	printf( "Cycles: %ld\n", (long) stime );
    4.69 +	
    4.70 +	spc_delete( snes_spc );
    4.71 +	
    4.72 +	return 0;
    4.73 +}
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/demo/demo_util.c	Fri Oct 21 05:53:11 2011 -0700
     5.3 @@ -0,0 +1,57 @@
     5.4 +#include "demo_util.h"
     5.5 +
     5.6 +#include <assert.h>
     5.7 +#include <string.h>
     5.8 +#include <stdlib.h>
     5.9 +#include <stdio.h>
    5.10 +
    5.11 +/* Copyright (C) 2007 Shay Green. This module is free software; you
    5.12 +can redistribute it and/or modify it under the terms of the GNU Lesser
    5.13 +General Public License as published by the Free Software Foundation; either
    5.14 +version 2.1 of the License, or (at your option) any later version. This
    5.15 +module is distributed in the hope that it will be useful, but WITHOUT ANY
    5.16 +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    5.17 +FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
    5.18 +details. You should have received a copy of the GNU Lesser General Public
    5.19 +License along with this module; if not, write to the Free Software Foundation,
    5.20 +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
    5.21 +
    5.22 +unsigned char* load_file( const char* path, long* size_out )
    5.23 +{
    5.24 +	size_t size;
    5.25 +	unsigned char* data;
    5.26 +	
    5.27 +	FILE* in = fopen( path, "rb" );
    5.28 +	if ( !in ) error( "Couldn't open file" );
    5.29 +	
    5.30 +	fseek( in, 0, SEEK_END );
    5.31 +	size = ftell( in );
    5.32 +	if ( size_out )
    5.33 +		*size_out = size;
    5.34 +	rewind( in );
    5.35 +	
    5.36 +	data = (unsigned char*) malloc( size );
    5.37 +	if ( !data ) error( "Out of memory" );
    5.38 +	
    5.39 +	if ( fread( data, 1, size, in ) < size ) error( "Couldn't read file" );
    5.40 +	fclose( in );
    5.41 +	
    5.42 +	return data;
    5.43 +}
    5.44 +
    5.45 +void write_file( const char* path, void const* in, long size )
    5.46 +{
    5.47 +	FILE* out = fopen( path, "wb" );
    5.48 +	if ( !out ) error( "Couldn't create file" );
    5.49 +	if ( (long) fwrite( in, 1, size, out ) < size ) error( "Couldn't write file" );
    5.50 +	fclose( out );
    5.51 +}
    5.52 +
    5.53 +void error( const char* str )
    5.54 +{
    5.55 +	if ( str )
    5.56 +	{
    5.57 +		fprintf( stderr, "Error: %s\n", str );
    5.58 +		exit( EXIT_FAILURE );
    5.59 +	}
    5.60 +}
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/demo/demo_util.h	Fri Oct 21 05:53:11 2011 -0700
     6.3 @@ -0,0 +1,31 @@
     6.4 +/* General-purpose utilities used by demos */
     6.5 +
     6.6 +/* snes_spc 0.9.0 */
     6.7 +#ifndef DEMO_UTIL_H
     6.8 +#define DEMO_UTIL_H
     6.9 +
    6.10 +/* commonly used headers */
    6.11 +#include <assert.h>
    6.12 +#include <stdlib.h>
    6.13 +#include <string.h>
    6.14 +#include <stdio.h>
    6.15 +
    6.16 +#ifdef __cplusplus
    6.17 +	extern "C" {
    6.18 +#endif
    6.19 +
    6.20 +/* If str is not NULL, prints it and exits program, otherwise returns */
    6.21 +void error( const char* str );
    6.22 +
    6.23 +/* Loads file and returns pointer to data in memory, allocated with malloc().
    6.24 +If size_out != NULL, sets *size_out to size of data. */
    6.25 +unsigned char* load_file( const char* path, long* size_out );
    6.26 +
    6.27 +/* Writes data to file */
    6.28 +void write_file( const char* path, void const* in, long size );
    6.29 +
    6.30 +#ifdef __cplusplus
    6.31 +	}
    6.32 +#endif
    6.33 +
    6.34 +#endif
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/demo/play_spc.c	Fri Oct 21 05:53:11 2011 -0700
     7.3 @@ -0,0 +1,57 @@
     7.4 +/* Records SPC into wave file. Uses dsp_filter to give more authentic sound.
     7.5 +
     7.6 +Usage: play_spc [test.spc]
     7.7 +*/
     7.8 +
     7.9 +#include "snes_spc/spc.h"
    7.10 +
    7.11 +#include "wave_writer.h"
    7.12 +#include "demo_util.h" /* error(), load_file() */
    7.13 +
    7.14 +int main( int argc, char** argv )
    7.15 +{
    7.16 +	/* Create emulator and filter */
    7.17 +	SNES_SPC* snes_spc = spc_new();
    7.18 +	SPC_Filter* filter = spc_filter_new();
    7.19 +	if ( !snes_spc || !filter ) error( "Out of memory" );
    7.20 +	
    7.21 +	/* Load SPC */
    7.22 +	{
    7.23 +		/* Load file into memory */
    7.24 +		long spc_size;
    7.25 +		void* spc = load_file( (argc > 1) ? argv [1] : "test.spc", &spc_size );
    7.26 +		
    7.27 +		/* Load SPC data into emulator */
    7.28 +		error( spc_load_spc( snes_spc, spc, spc_size ) );
    7.29 +		free( spc ); /* emulator makes copy of data */
    7.30 +		
    7.31 +		/* Most SPC files have garbage data in the echo buffer, so clear that */
    7.32 +		spc_clear_echo( snes_spc );
    7.33 +		
    7.34 +		/* Clear filter before playing */
    7.35 +		spc_filter_clear( filter );
    7.36 +	}
    7.37 +	
    7.38 +	/* Record 20 seconds to wave file */
    7.39 +	wave_open( spc_sample_rate, "out.wav" );
    7.40 +	wave_enable_stereo();
    7.41 +	while ( wave_sample_count() < 20 * spc_sample_rate * 2 )
    7.42 +	{
    7.43 +		/* Play into buffer */
    7.44 +		#define BUF_SIZE 2048
    7.45 +		short buf [BUF_SIZE];
    7.46 +		error( spc_play( snes_spc, BUF_SIZE, buf ) );
    7.47 +		
    7.48 +		/* Filter samples */
    7.49 +		spc_filter_run( filter, buf, BUF_SIZE );
    7.50 +		
    7.51 +		wave_write( buf, BUF_SIZE );
    7.52 +	}
    7.53 +	
    7.54 +	/* Cleanup */
    7.55 +	spc_filter_delete( filter );
    7.56 +	spc_delete( snes_spc );
    7.57 +	wave_close();
    7.58 +	
    7.59 +	return 0;
    7.60 +}
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/demo/save_state.c	Fri Oct 21 05:53:11 2011 -0700
     8.3 @@ -0,0 +1,107 @@
     8.4 +/* Loads "test.spc", skips 5 seconds, saves exact emulator state to "state.bin",
     8.5 +hen records 5 seconds to "first.wav". When run again, loads this state back into
     8.6 +emulator and records 5 seconds to "second.wav". These two wave files should
     8.7 +be identical.
     8.8 +
     8.9 +Usage: save_state [test.spc]
    8.10 +*/
    8.11 +
    8.12 +#include "snes_spc/spc.h"
    8.13 +
    8.14 +#include "wave_writer.h"
    8.15 +#include "demo_util.h" /* error(), load_file() */
    8.16 +
    8.17 +static SNES_SPC* snes_spc;
    8.18 +
    8.19 +void record_wav( const char* path, int secs )
    8.20 +{
    8.21 +	/* Start writing wave file */
    8.22 +	wave_open( spc_sample_rate, path );
    8.23 +	wave_enable_stereo();
    8.24 +	while ( wave_sample_count() < secs * spc_sample_rate * 2 )
    8.25 +	{
    8.26 +		/* Play into buffer */
    8.27 +		#define BUF_SIZE 2048
    8.28 +		short buf [BUF_SIZE];
    8.29 +		error( spc_play( snes_spc, BUF_SIZE, buf ) );
    8.30 +		
    8.31 +		wave_write( buf, BUF_SIZE );
    8.32 +	}
    8.33 +	wave_close();
    8.34 +}
    8.35 +
    8.36 +void state_save( unsigned char** out, void* in, size_t size )
    8.37 +{
    8.38 +	memcpy( *out, in, size );
    8.39 +	*out += size;
    8.40 +}
    8.41 +
    8.42 +void make_save_state( const char* path )
    8.43 +{
    8.44 +	/* Load SPC */
    8.45 +	long spc_size;
    8.46 +	void* spc = load_file( path, &spc_size );
    8.47 +	error( spc_load_spc( snes_spc, spc, spc_size ) );
    8.48 +	free( spc );
    8.49 +	spc_clear_echo( snes_spc );
    8.50 +	
    8.51 +	/* Skip several seconds */
    8.52 +	error( spc_play( snes_spc, 5 * spc_sample_rate * 2, 0 ) );
    8.53 +	
    8.54 +	/* Save state to file */
    8.55 +	{
    8.56 +		static unsigned char state [spc_state_size]; /* buffer large enough for data */
    8.57 +		unsigned char* out = state;
    8.58 +		spc_copy_state( snes_spc, &out, state_save );
    8.59 +		write_file( "state.bin", state, out - state );
    8.60 +	}
    8.61 +	
    8.62 +	record_wav( "first.wav", 5 );
    8.63 +}
    8.64 +
    8.65 +void state_load( unsigned char** in, void* out, size_t size )
    8.66 +{
    8.67 +	memcpy( out, *in, size );
    8.68 +	*in += size;
    8.69 +}
    8.70 +
    8.71 +void use_save_state()
    8.72 +{
    8.73 +	/* Load state into memory */
    8.74 +	long state_size;
    8.75 +	unsigned char* state = load_file( "state.bin", &state_size );
    8.76 +	
    8.77 +	/* Load into emulator */
    8.78 +	unsigned char* in = state;
    8.79 +	spc_copy_state( snes_spc, &in, state_load );
    8.80 +	assert( in  - state <= state_size ); /* be sure it didn't read past end */
    8.81 +	
    8.82 +	record_wav( "second.wav", 5 );
    8.83 +}
    8.84 +
    8.85 +int file_exists( const char* path )
    8.86 +{
    8.87 +	FILE* file = fopen( path, "rb" );
    8.88 +	if ( !file )
    8.89 +		return 0;
    8.90 +	
    8.91 +	fclose( file );
    8.92 +	return 1;
    8.93 +}
    8.94 +
    8.95 +int main( int argc, char** argv )
    8.96 +{
    8.97 +	snes_spc = spc_new();
    8.98 +	if ( !snes_spc ) error( "Out of memory" );
    8.99 +	
   8.100 +	/* Make new state if it doesn't exist, otherwise load it and
   8.101 +	record to wave file */
   8.102 +	if ( !file_exists( "state.bin" ) )
   8.103 +		make_save_state( (argc > 1) ? argv [1] : "test.spc" );
   8.104 +	else
   8.105 +		use_save_state();
   8.106 +	
   8.107 +	spc_delete( snes_spc );
   8.108 +	
   8.109 +	return 0;
   8.110 +}
     9.1 Binary file demo/spc_record has changed
    10.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.2 +++ b/demo/trim_spc.c	Fri Oct 21 05:53:11 2011 -0700
    10.3 @@ -0,0 +1,83 @@
    10.4 +/* Trims silence off beginning of SPC file.
    10.5 +Requires the accurate DSP; won't compile with the fast DSP.
    10.6 +Please note that the algorithm could be improved; this is just
    10.7 +a simple example showing the idea.
    10.8 +
    10.9 +Usage: trim_spc [test.spc [trimmed.spc]]
   10.10 +*/
   10.11 +
   10.12 +#include "snes_spc/spc.h"
   10.13 +
   10.14 +#include "demo_util.h" /* error(), load_file() */
   10.15 +
   10.16 +/* Change to 1 to have it trim to next key on event rather than trim silence */
   10.17 +enum { use_kon_check = 0 };
   10.18 +
   10.19 +/* True if all count samples from in are silent (or very close to it) */
   10.20 +int is_silent( short const* in, int count );
   10.21 +
   10.22 +int main( int argc, char** argv )
   10.23 +{
   10.24 +	/* Load file into memory */
   10.25 +	long spc_size;
   10.26 +	void* spc = load_file( (argc > 1) ? argv [1] : "test.spc", &spc_size );
   10.27 +	
   10.28 +	/* Load into emulator */
   10.29 +	SNES_SPC* snes_spc = spc_new();
   10.30 +	if ( !snes_spc ) error( "Out of memory" );
   10.31 +	error( spc_load_spc( snes_spc, spc, spc_size ) );
   10.32 +	
   10.33 +	/* Expand SPC data so there's enough room for emulator to save to.
   10.34 +	We simply overwrite the emulator data in the old SPC file rather
   10.35 +	than creating new SPC data. This preserves the text tags from
   10.36 +	the old file. */
   10.37 +	if ( spc_size < spc_file_size )
   10.38 +	{
   10.39 +		spc_size = spc_file_size;
   10.40 +		spc = realloc( spc, spc_size ); /* leaks memory if allocation fails */
   10.41 +		if ( !spc ) error( "Out of memory" );
   10.42 +	}
   10.43 +	
   10.44 +	/* Keep saving SPC, then playing a little more. Once SPC becomes non-silent,
   10.45 +	write the SPC data saved just before this. */
   10.46 +	{
   10.47 +		long samples_trimmed = 0;
   10.48 +		while ( 1 )
   10.49 +		{
   10.50 +			#define BUF_SIZE 1024
   10.51 +			short buf [BUF_SIZE];
   10.52 +			
   10.53 +			if ( samples_trimmed > 10 * spc_sample_rate * 2 )
   10.54 +				error( "Excess silence found" );
   10.55 +			
   10.56 +			spc_clear_echo( snes_spc );
   10.57 +			spc_save_spc( snes_spc, spc );
   10.58 +			
   10.59 +			/* Fill buffer */
   10.60 +			error( spc_play( snes_spc, BUF_SIZE, buf ) );
   10.61 +			samples_trimmed += BUF_SIZE;
   10.62 +			
   10.63 +			/* See if SPC became non-silent */
   10.64 +			if ( use_kon_check ? spc_check_kon( snes_spc ) : !is_silent( buf, BUF_SIZE ) )
   10.65 +				break;
   10.66 +		}
   10.67 +		
   10.68 +		printf( "Trimmed %.1f seconds\n", (double) samples_trimmed / spc_sample_rate / 2 );
   10.69 +	}
   10.70 +	
   10.71 +	spc_delete( snes_spc );
   10.72 +	write_file( (argc > 2) ? argv [2] : "trimmed.spc", spc, spc_size );
   10.73 +	
   10.74 +	return 0;
   10.75 +}
   10.76 +
   10.77 +int is_silent( short const* in, int count )
   10.78 +{
   10.79 +	unsigned const threshold = 0x10;
   10.80 +	while ( count-- )
   10.81 +	{
   10.82 +		if ( (unsigned) (*in++ + threshold / 2) > threshold )
   10.83 +			return 0;
   10.84 +	}
   10.85 +	return 1;
   10.86 +}
    11.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    11.2 +++ b/demo/wave_writer.c	Fri Oct 21 05:53:11 2011 -0700
    11.3 @@ -0,0 +1,153 @@
    11.4 +/* snes_spc 0.9.0. http://www.slack.net/~ant/ */
    11.5 +
    11.6 +#include "wave_writer.h"
    11.7 +
    11.8 +#include <assert.h>
    11.9 +#include <stdlib.h>
   11.10 +#include <stdio.h>
   11.11 +
   11.12 +/* Copyright (C) 2003-2007 Shay Green. This module is free software; you
   11.13 +can redistribute it and/or modify it under the terms of the GNU Lesser
   11.14 +General Public License as published by the Free Software Foundation; either
   11.15 +version 2.1 of the License, or (at your option) any later version. This
   11.16 +module is distributed in the hope that it will be useful, but WITHOUT ANY
   11.17 +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   11.18 +FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
   11.19 +details. You should have received a copy of the GNU Lesser General Public
   11.20 +License along with this module; if not, write to the Free Software Foundation,
   11.21 +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
   11.22 +
   11.23 +enum { buf_size = 32768 * 2 };
   11.24 +enum { header_size = 0x2C };
   11.25 +
   11.26 +typedef short sample_t;
   11.27 +
   11.28 +static unsigned char* buf;
   11.29 +static FILE* file;
   11.30 +static long  sample_count_;
   11.31 +static long  sample_rate_;
   11.32 +static long  buf_pos;
   11.33 +static int   chan_count;
   11.34 +
   11.35 +static void exit_with_error( const char* str )
   11.36 +{
   11.37 +	printf( "Error: %s\n", str ); getchar();
   11.38 +	exit( EXIT_FAILURE );
   11.39 +}
   11.40 +
   11.41 +void wave_open( long sample_rate, const char* filename )
   11.42 +{
   11.43 +	sample_count_ = 0;
   11.44 +	sample_rate_  = sample_rate;
   11.45 +	buf_pos       = header_size;
   11.46 +	chan_count    = 1;
   11.47 +	
   11.48 +	buf = (unsigned char*) malloc( buf_size * sizeof *buf );
   11.49 +	if ( !buf )
   11.50 +		exit_with_error( "Out of memory" );
   11.51 +	
   11.52 +	file = fopen( filename, "wb" );
   11.53 +	if ( !file )
   11.54 +		exit_with_error( "Couldn't open WAVE file for writing" );
   11.55 +	
   11.56 +	setvbuf( file, 0, _IOFBF, 32 * 1024L );
   11.57 +}
   11.58 +
   11.59 +void wave_enable_stereo( void )
   11.60 +{
   11.61 +	chan_count = 2;
   11.62 +}
   11.63 +
   11.64 +static void flush_()
   11.65 +{
   11.66 +	if ( buf_pos && !fwrite( buf, buf_pos, 1, file ) )
   11.67 +		exit_with_error( "Couldn't write WAVE data" );
   11.68 +	buf_pos = 0;
   11.69 +}
   11.70 +
   11.71 +void wave_write( short const* in, long remain )
   11.72 +{
   11.73 +	sample_count_ += remain;
   11.74 +	while ( remain )
   11.75 +	{
   11.76 +		if ( buf_pos >= buf_size )
   11.77 +			flush_();
   11.78 +		
   11.79 +		{
   11.80 +			unsigned char* p = &buf [buf_pos];
   11.81 +			long n = (buf_size - buf_pos) / sizeof (sample_t);
   11.82 +			if ( n > remain )
   11.83 +				n = remain;
   11.84 +			remain -= n;
   11.85 +			
   11.86 +			/* convert to LSB first format */
   11.87 +			while ( n-- )
   11.88 +			{
   11.89 +				int s = *in++;
   11.90 +				*p++ = (unsigned char) s;
   11.91 +				*p++ = (unsigned char) (s >> 8);
   11.92 +			}
   11.93 +			
   11.94 +			buf_pos = p - buf;
   11.95 +			assert( buf_pos <= buf_size );
   11.96 +		}
   11.97 +	}
   11.98 +}
   11.99 +
  11.100 +long wave_sample_count( void )
  11.101 +{
  11.102 +	return sample_count_;
  11.103 +}
  11.104 +
  11.105 +static void set_le32( void* p, unsigned long n )
  11.106 +{
  11.107 +	((unsigned char*) p) [0] = (unsigned char) n;
  11.108 +	((unsigned char*) p) [1] = (unsigned char) (n >> 8);
  11.109 +	((unsigned char*) p) [2] = (unsigned char) (n >> 16);
  11.110 +	((unsigned char*) p) [3] = (unsigned char) (n >> 24);
  11.111 +}
  11.112 +
  11.113 +void wave_close( void )
  11.114 +{
  11.115 +	if ( file )
  11.116 +	{
  11.117 +		/* generate header */
  11.118 +		unsigned char h [header_size] =
  11.119 +		{
  11.120 +			'R','I','F','F',
  11.121 +			0,0,0,0,        /* length of rest of file */
  11.122 +			'W','A','V','E',
  11.123 +			'f','m','t',' ',
  11.124 +			0x10,0,0,0,     /* size of fmt chunk */
  11.125 +			1,0,            /* uncompressed format */
  11.126 +			0,0,            /* channel count */
  11.127 +			0,0,0,0,        /* sample rate */
  11.128 +			0,0,0,0,        /* bytes per second */
  11.129 +			0,0,            /* bytes per sample frame */
  11.130 +			16,0,           /* bits per sample */
  11.131 +			'd','a','t','a',
  11.132 +			0,0,0,0,        /* size of sample data */
  11.133 +			/* ... */       /* sample data */
  11.134 +		};
  11.135 +		long ds = sample_count_ * sizeof (sample_t);
  11.136 +		int frame_size = chan_count * sizeof (sample_t);
  11.137 +		
  11.138 +		set_le32( h + 0x04, header_size - 8 + ds );
  11.139 +		h [0x16] = chan_count;
  11.140 +		set_le32( h + 0x18, sample_rate_ );
  11.141 +		set_le32( h + 0x1C, sample_rate_ * frame_size );
  11.142 +		h [0x20] = frame_size;
  11.143 +		set_le32( h + 0x28, ds );
  11.144 +		
  11.145 +		flush_();
  11.146 +		
  11.147 +		/* write header */
  11.148 +		fseek( file, 0, SEEK_SET );
  11.149 +		fwrite( h, sizeof h, 1, file );
  11.150 +		
  11.151 +		fclose( file );
  11.152 +		file = 0;
  11.153 +		free( buf );
  11.154 +		buf = 0;
  11.155 +	}
  11.156 +}
    12.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    12.2 +++ b/demo/wave_writer.h	Fri Oct 21 05:53:11 2011 -0700
    12.3 @@ -0,0 +1,20 @@
    12.4 +/* WAVE sound file writer for recording 16-bit output during program development */
    12.5 +
    12.6 +#ifndef WAVE_WRITER_H
    12.7 +#define WAVE_WRITER_H
    12.8 +
    12.9 +#ifdef __cplusplus
   12.10 +	extern "C" {
   12.11 +#endif
   12.12 +
   12.13 +void wave_open( long sample_rate, const char* filename );
   12.14 +void wave_enable_stereo( void );
   12.15 +void wave_write( short const* in, long count );
   12.16 +long wave_sample_count( void );
   12.17 +void wave_close( void );
   12.18 +
   12.19 +#ifdef __cplusplus
   12.20 +	}
   12.21 +#endif
   12.22 +
   12.23 +#endif
    13.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    13.2 +++ b/fast_dsp/SPC_DSP.cpp	Fri Oct 21 05:53:11 2011 -0700
    13.3 @@ -0,0 +1,703 @@
    13.4 +// snes_spc 0.9.0. http://www.slack.net/~ant/
    13.5 +
    13.6 +#include "SPC_DSP.h"
    13.7 +
    13.8 +#include "blargg_endian.h"
    13.9 +#include <string.h>
   13.10 +
   13.11 +/* Copyright (C) 2007 Shay Green. This module is free software; you
   13.12 +can redistribute it and/or modify it under the terms of the GNU Lesser
   13.13 +General Public License as published by the Free Software Foundation; either
   13.14 +version 2.1 of the License, or (at your option) any later version. This
   13.15 +module is distributed in the hope that it will be useful, but WITHOUT ANY
   13.16 +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   13.17 +FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
   13.18 +details. You should have received a copy of the GNU Lesser General Public
   13.19 +License along with this module; if not, write to the Free Software Foundation,
   13.20 +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
   13.21 +
   13.22 +#include "blargg_source.h"
   13.23 +
   13.24 +#ifdef BLARGG_ENABLE_OPTIMIZER
   13.25 +	#include BLARGG_ENABLE_OPTIMIZER
   13.26 +#endif
   13.27 +
   13.28 +#if INT_MAX < 0x7FFFFFFF
   13.29 +	#error "Requires that int type have at least 32 bits"
   13.30 +#endif
   13.31 +
   13.32 +
   13.33 +// TODO: add to blargg_endian.h
   13.34 +#define GET_LE16SA( addr )      ((BOOST::int16_t) GET_LE16( addr ))
   13.35 +#define GET_LE16A( addr )       GET_LE16( addr )
   13.36 +#define SET_LE16A( addr, data ) SET_LE16( addr, data )
   13.37 +
   13.38 +static BOOST::uint8_t const initial_regs [SPC_DSP::register_count] =
   13.39 +{
   13.40 +	0x45,0x8B,0x5A,0x9A,0xE4,0x82,0x1B,0x78,0x00,0x00,0xAA,0x96,0x89,0x0E,0xE0,0x80,
   13.41 +	0x2A,0x49,0x3D,0xBA,0x14,0xA0,0xAC,0xC5,0x00,0x00,0x51,0xBB,0x9C,0x4E,0x7B,0xFF,
   13.42 +	0xF4,0xFD,0x57,0x32,0x37,0xD9,0x42,0x22,0x00,0x00,0x5B,0x3C,0x9F,0x1B,0x87,0x9A,
   13.43 +	0x6F,0x27,0xAF,0x7B,0xE5,0x68,0x0A,0xD9,0x00,0x00,0x9A,0xC5,0x9C,0x4E,0x7B,0xFF,
   13.44 +	0xEA,0x21,0x78,0x4F,0xDD,0xED,0x24,0x14,0x00,0x00,0x77,0xB1,0xD1,0x36,0xC1,0x67,
   13.45 +	0x52,0x57,0x46,0x3D,0x59,0xF4,0x87,0xA4,0x00,0x00,0x7E,0x44,0x9C,0x4E,0x7B,0xFF,
   13.46 +	0x75,0xF5,0x06,0x97,0x10,0xC3,0x24,0xBB,0x00,0x00,0x7B,0x7A,0xE0,0x60,0x12,0x0F,
   13.47 +	0xF7,0x74,0x1C,0xE5,0x39,0x3D,0x73,0xC1,0x00,0x00,0x7A,0xB3,0xFF,0x4E,0x7B,0xFF
   13.48 +};
   13.49 +
   13.50 +// if ( io < -32768 ) io = -32768;
   13.51 +// if ( io >  32767 ) io =  32767;
   13.52 +#define CLAMP16( io )\
   13.53 +{\
   13.54 +	if ( (int16_t) io != io )\
   13.55 +		io = (io >> 31) ^ 0x7FFF;\
   13.56 +}
   13.57 +
   13.58 +// Access global DSP register
   13.59 +#define REG(n)      m.regs [r_##n]
   13.60 +
   13.61 +// Access voice DSP register
   13.62 +#define VREG(r,n)   r [v_##n]
   13.63 +
   13.64 +#define WRITE_SAMPLES( l, r, out ) \
   13.65 +{\
   13.66 +	out [0] = l;\
   13.67 +	out [1] = r;\
   13.68 +	out += 2;\
   13.69 +	if ( out >= m.out_end )\
   13.70 +	{\
   13.71 +		check( out == m.out_end );\
   13.72 +		check( m.out_end != &m.extra [extra_size] || \
   13.73 +			(m.extra <= m.out_begin && m.extra < &m.extra [extra_size]) );\
   13.74 +		out       = m.extra;\
   13.75 +		m.out_end = &m.extra [extra_size];\
   13.76 +	}\
   13.77 +}\
   13.78 +
   13.79 +void SPC_DSP::set_output( sample_t* out, int size )
   13.80 +{
   13.81 +	require( (size & 1) == 0 ); // must be even
   13.82 +	if ( !out )
   13.83 +	{
   13.84 +		out  = m.extra;
   13.85 +		size = extra_size;
   13.86 +	}
   13.87 +	m.out_begin = out;
   13.88 +	m.out       = out;
   13.89 +	m.out_end   = out + size;
   13.90 +}
   13.91 +
   13.92 +// Volume registers and efb are signed! Easy to forget int8_t cast.
   13.93 +// Prefixes are to avoid accidental use of locals with same names.
   13.94 +
   13.95 +// Interleved gauss table (to improve cache coherency)
   13.96 +// interleved_gauss [i] = gauss [(i & 1) * 256 + 255 - (i >> 1 & 0xFF)]
   13.97 +static short const interleved_gauss [512] =
   13.98 +{
   13.99 + 370,1305, 366,1305, 362,1304, 358,1304, 354,1304, 351,1304, 347,1304, 343,1303,
  13.100 + 339,1303, 336,1303, 332,1302, 328,1302, 325,1301, 321,1300, 318,1300, 314,1299,
  13.101 + 311,1298, 307,1297, 304,1297, 300,1296, 297,1295, 293,1294, 290,1293, 286,1292,
  13.102 + 283,1291, 280,1290, 276,1288, 273,1287, 270,1286, 267,1284, 263,1283, 260,1282,
  13.103 + 257,1280, 254,1279, 251,1277, 248,1275, 245,1274, 242,1272, 239,1270, 236,1269,
  13.104 + 233,1267, 230,1265, 227,1263, 224,1261, 221,1259, 218,1257, 215,1255, 212,1253,
  13.105 + 210,1251, 207,1248, 204,1246, 201,1244, 199,1241, 196,1239, 193,1237, 191,1234,
  13.106 + 188,1232, 186,1229, 183,1227, 180,1224, 178,1221, 175,1219, 173,1216, 171,1213,
  13.107 + 168,1210, 166,1207, 163,1205, 161,1202, 159,1199, 156,1196, 154,1193, 152,1190,
  13.108 + 150,1186, 147,1183, 145,1180, 143,1177, 141,1174, 139,1170, 137,1167, 134,1164,
  13.109 + 132,1160, 130,1157, 128,1153, 126,1150, 124,1146, 122,1143, 120,1139, 118,1136,
  13.110 + 117,1132, 115,1128, 113,1125, 111,1121, 109,1117, 107,1113, 106,1109, 104,1106,
  13.111 + 102,1102, 100,1098,  99,1094,  97,1090,  95,1086,  94,1082,  92,1078,  90,1074,
  13.112 +  89,1070,  87,1066,  86,1061,  84,1057,  83,1053,  81,1049,  80,1045,  78,1040,
  13.113 +  77,1036,  76,1032,  74,1027,  73,1023,  71,1019,  70,1014,  69,1010,  67,1005,
  13.114 +  66,1001,  65, 997,  64, 992,  62, 988,  61, 983,  60, 978,  59, 974,  58, 969,
  13.115 +  56, 965,  55, 960,  54, 955,  53, 951,  52, 946,  51, 941,  50, 937,  49, 932,
  13.116 +  48, 927,  47, 923,  46, 918,  45, 913,  44, 908,  43, 904,  42, 899,  41, 894,
  13.117 +  40, 889,  39, 884,  38, 880,  37, 875,  36, 870,  36, 865,  35, 860,  34, 855,
  13.118 +  33, 851,  32, 846,  32, 841,  31, 836,  30, 831,  29, 826,  29, 821,  28, 816,
  13.119 +  27, 811,  27, 806,  26, 802,  25, 797,  24, 792,  24, 787,  23, 782,  23, 777,
  13.120 +  22, 772,  21, 767,  21, 762,  20, 757,  20, 752,  19, 747,  19, 742,  18, 737,
  13.121 +  17, 732,  17, 728,  16, 723,  16, 718,  15, 713,  15, 708,  15, 703,  14, 698,
  13.122 +  14, 693,  13, 688,  13, 683,  12, 678,  12, 674,  11, 669,  11, 664,  11, 659,
  13.123 +  10, 654,  10, 649,  10, 644,   9, 640,   9, 635,   9, 630,   8, 625,   8, 620,
  13.124 +   8, 615,   7, 611,   7, 606,   7, 601,   6, 596,   6, 592,   6, 587,   6, 582,
  13.125 +   5, 577,   5, 573,   5, 568,   5, 563,   4, 559,   4, 554,   4, 550,   4, 545,
  13.126 +   4, 540,   3, 536,   3, 531,   3, 527,   3, 522,   3, 517,   2, 513,   2, 508,
  13.127 +   2, 504,   2, 499,   2, 495,   2, 491,   2, 486,   1, 482,   1, 477,   1, 473,
  13.128 +   1, 469,   1, 464,   1, 460,   1, 456,   1, 451,   1, 447,   1, 443,   1, 439,
  13.129 +   0, 434,   0, 430,   0, 426,   0, 422,   0, 418,   0, 414,   0, 410,   0, 405,
  13.130 +   0, 401,   0, 397,   0, 393,   0, 389,   0, 385,   0, 381,   0, 378,   0, 374,
  13.131 +};
  13.132 +
  13.133 +
  13.134 +//// Counters
  13.135 +
  13.136 +#define RATE( rate, div )\
  13.137 +	(rate >= div ? rate / div * 8 - 1 : rate - 1)
  13.138 +
  13.139 +static unsigned const counter_mask [32] =
  13.140 +{
  13.141 +	RATE(   2,2), RATE(2048,4), RATE(1536,3),
  13.142 +	RATE(1280,5), RATE(1024,4), RATE( 768,3),
  13.143 +	RATE( 640,5), RATE( 512,4), RATE( 384,3),
  13.144 +	RATE( 320,5), RATE( 256,4), RATE( 192,3),
  13.145 +	RATE( 160,5), RATE( 128,4), RATE(  96,3),
  13.146 +	RATE(  80,5), RATE(  64,4), RATE(  48,3),
  13.147 +	RATE(  40,5), RATE(  32,4), RATE(  24,3),
  13.148 +	RATE(  20,5), RATE(  16,4), RATE(  12,3),
  13.149 +	RATE(  10,5), RATE(   8,4), RATE(   6,3),
  13.150 +	RATE(   5,5), RATE(   4,4), RATE(   3,3),
  13.151 +	              RATE(   2,4),
  13.152 +	              RATE(   1,4)
  13.153 +};
  13.154 +#undef RATE
  13.155 +
  13.156 +inline void SPC_DSP::init_counter()
  13.157 +{
  13.158 +	// counters start out with this synchronization
  13.159 +	m.counters [0] =     1;
  13.160 +	m.counters [1] =     0;
  13.161 +	m.counters [2] = -0x20u;
  13.162 +	m.counters [3] =  0x0B;
  13.163 +	
  13.164 +	int n = 2;
  13.165 +	for ( int i = 1; i < 32; i++ )
  13.166 +	{
  13.167 +		m.counter_select [i] = &m.counters [n];
  13.168 +		if ( !--n )
  13.169 +			n = 3;
  13.170 +	}
  13.171 +	m.counter_select [ 0] = &m.counters [0];
  13.172 +	m.counter_select [30] = &m.counters [2];
  13.173 +}
  13.174 +
  13.175 +inline void SPC_DSP::run_counter( int i )
  13.176 +{
  13.177 +	int n = m.counters [i];
  13.178 +	if ( !(n-- & 7) )
  13.179 +		n -= 6 - i;
  13.180 +	m.counters [i] = n;
  13.181 +}
  13.182 +
  13.183 +#define READ_COUNTER( rate )\
  13.184 +	(*m.counter_select [rate] & counter_mask [rate])
  13.185 +
  13.186 +
  13.187 +//// Emulation
  13.188 +
  13.189 +void SPC_DSP::run( int clock_count )
  13.190 +{
  13.191 +	int new_phase = m.phase + clock_count;
  13.192 +	int count = new_phase >> 5;
  13.193 +	m.phase = new_phase & 31;
  13.194 +	if ( !count )
  13.195 +		return;
  13.196 +	
  13.197 +	uint8_t* const ram = m.ram;
  13.198 +	uint8_t const* const dir = &ram [REG(dir) * 0x100];
  13.199 +	int const slow_gaussian = (REG(pmon) >> 1) | REG(non);
  13.200 +	int const noise_rate = REG(flg) & 0x1F;
  13.201 +	
  13.202 +	// Global volume
  13.203 +	int mvoll = (int8_t) REG(mvoll);
  13.204 +	int mvolr = (int8_t) REG(mvolr);
  13.205 +	if ( mvoll * mvolr < m.surround_threshold )
  13.206 +		mvoll = -mvoll; // eliminate surround
  13.207 +	
  13.208 +	do
  13.209 +	{
  13.210 +		// KON/KOFF reading
  13.211 +		if ( (m.every_other_sample ^= 1) != 0 )
  13.212 +		{
  13.213 +			m.new_kon &= ~m.kon;
  13.214 +			m.kon    = m.new_kon;
  13.215 +			m.t_koff = REG(koff); 
  13.216 +		}
  13.217 +		
  13.218 +		run_counter( 1 );
  13.219 +		run_counter( 2 );
  13.220 +		run_counter( 3 );
  13.221 +		
  13.222 +		// Noise
  13.223 +		if ( !READ_COUNTER( noise_rate ) )
  13.224 +		{
  13.225 +			int feedback = (m.noise << 13) ^ (m.noise << 14);
  13.226 +			m.noise = (feedback & 0x4000) ^ (m.noise >> 1);
  13.227 +		}
  13.228 +		
  13.229 +		// Voices
  13.230 +		int pmon_input = 0;
  13.231 +		int main_out_l = 0;
  13.232 +		int main_out_r = 0;
  13.233 +		int echo_out_l = 0;
  13.234 +		int echo_out_r = 0;
  13.235 +		voice_t* v = m.voices;
  13.236 +		uint8_t* v_regs = m.regs;
  13.237 +		int vbit = 1;
  13.238 +		do
  13.239 +		{
  13.240 +			#define SAMPLE_PTR(i) GET_LE16A( &dir [VREG(v_regs,srcn) * 4 + i * 2] )
  13.241 +			
  13.242 +			int brr_header = ram [v->brr_addr];
  13.243 +			int kon_delay = v->kon_delay;
  13.244 +			
  13.245 +			// Pitch
  13.246 +			int pitch = GET_LE16A( &VREG(v_regs,pitchl) ) & 0x3FFF;
  13.247 +			if ( REG(pmon) & vbit )
  13.248 +				pitch += ((pmon_input >> 5) * pitch) >> 10;
  13.249 +			
  13.250 +			// KON phases
  13.251 +			if ( --kon_delay >= 0 )
  13.252 +			{
  13.253 +				v->kon_delay = kon_delay;
  13.254 +				
  13.255 +				// Get ready to start BRR decoding on next sample
  13.256 +				if ( kon_delay == 4 )
  13.257 +				{
  13.258 +					v->brr_addr   = SAMPLE_PTR( 0 );
  13.259 +					v->brr_offset = 1;
  13.260 +					v->buf_pos    = v->buf;
  13.261 +					brr_header    = 0; // header is ignored on this sample
  13.262 +				}
  13.263 +				
  13.264 +				// Envelope is never run during KON
  13.265 +				v->env        = 0;
  13.266 +				v->hidden_env = 0;
  13.267 +				
  13.268 +				// Disable BRR decoding until last three samples
  13.269 +				v->interp_pos = (kon_delay & 3 ? 0x4000 : 0);
  13.270 +				
  13.271 +				// Pitch is never added during KON
  13.272 +				pitch = 0;
  13.273 +			}
  13.274 +			
  13.275 +			int env = v->env;
  13.276 +			
  13.277 +			// Gaussian interpolation
  13.278 +			{
  13.279 +				int output = 0;
  13.280 +				VREG(v_regs,envx) = (uint8_t) (env >> 4);
  13.281 +				if ( env )
  13.282 +				{
  13.283 +					// Make pointers into gaussian based on fractional position between samples
  13.284 +					int offset = (unsigned) v->interp_pos >> 3 & 0x1FE;
  13.285 +					short const* fwd = interleved_gauss       + offset;
  13.286 +					short const* rev = interleved_gauss + 510 - offset; // mirror left half of gaussian
  13.287 +					
  13.288 +					int const* in = &v->buf_pos [(unsigned) v->interp_pos >> 12];
  13.289 +					
  13.290 +					if ( !(slow_gaussian & vbit) ) // 99%
  13.291 +					{
  13.292 +						// Faster approximation when exact sample value isn't necessary for pitch mod
  13.293 +						output = (fwd [0] * in [0] +
  13.294 +						          fwd [1] * in [1] +
  13.295 +						          rev [1] * in [2] +
  13.296 +						          rev [0] * in [3]) >> 11;
  13.297 +						output = (output * env) >> 11;
  13.298 +					}
  13.299 +					else
  13.300 +					{
  13.301 +						output = (int16_t) (m.noise * 2);
  13.302 +						if ( !(REG(non) & vbit) )
  13.303 +						{
  13.304 +							output  = (fwd [0] * in [0]) >> 11;
  13.305 +							output += (fwd [1] * in [1]) >> 11;
  13.306 +							output += (rev [1] * in [2]) >> 11;
  13.307 +							output = (int16_t) output;
  13.308 +							output += (rev [0] * in [3]) >> 11;
  13.309 +							
  13.310 +							CLAMP16( output );
  13.311 +							output &= ~1;
  13.312 +						}
  13.313 +						output = (output * env) >> 11 & ~1;
  13.314 +					}
  13.315 +					
  13.316 +					// Output
  13.317 +					int l = output * v->volume [0];
  13.318 +					int r = output * v->volume [1];
  13.319 +					
  13.320 +					main_out_l += l;
  13.321 +					main_out_r += r;
  13.322 +					
  13.323 +					if ( REG(eon) & vbit )
  13.324 +					{
  13.325 +						echo_out_l += l;
  13.326 +						echo_out_r += r;
  13.327 +					}
  13.328 +				}
  13.329 +				
  13.330 +				pmon_input = output;
  13.331 +				VREG(v_regs,outx) = (uint8_t) (output >> 8);
  13.332 +			}
  13.333 +			
  13.334 +			// Soft reset or end of sample
  13.335 +			if ( REG(flg) & 0x80 || (brr_header & 3) == 1 )
  13.336 +			{
  13.337 +				v->env_mode = env_release;
  13.338 +				env         = 0;
  13.339 +			}
  13.340 +			
  13.341 +			if ( m.every_other_sample )
  13.342 +			{
  13.343 +				// KOFF
  13.344 +				if ( m.t_koff & vbit )
  13.345 +					v->env_mode = env_release;
  13.346 +				
  13.347 +				// KON
  13.348 +				if ( m.kon & vbit )
  13.349 +				{
  13.350 +					v->kon_delay = 5;
  13.351 +					v->env_mode  = env_attack;
  13.352 +					REG(endx) &= ~vbit;
  13.353 +				}
  13.354 +			}
  13.355 +			
  13.356 +			// Envelope
  13.357 +			if ( !v->kon_delay )
  13.358 +			{
  13.359 +				if ( v->env_mode == env_release ) // 97%
  13.360 +				{
  13.361 +					env -= 0x8;
  13.362 +					v->env = env;
  13.363 +					if ( env <= 0 )
  13.364 +					{
  13.365 +						v->env = 0;
  13.366 +						goto skip_brr; // no BRR decoding for you!
  13.367 +					}
  13.368 +				}
  13.369 +				else // 3%
  13.370 +				{
  13.371 +					int rate;
  13.372 +					int const adsr0 = VREG(v_regs,adsr0);
  13.373 +					int env_data = VREG(v_regs,adsr1);
  13.374 +					if ( adsr0 >= 0x80 ) // 97% ADSR
  13.375 +					{
  13.376 +						if ( v->env_mode > env_decay ) // 89%
  13.377 +						{
  13.378 +							env--;
  13.379 +							env -= env >> 8;
  13.380 +							rate = env_data & 0x1F;
  13.381 +							
  13.382 +							// optimized handling
  13.383 +							v->hidden_env = env;
  13.384 +							if ( READ_COUNTER( rate ) )
  13.385 +								goto exit_env;
  13.386 +							v->env = env;
  13.387 +							goto exit_env;
  13.388 +						}
  13.389 +						else if ( v->env_mode == env_decay )
  13.390 +						{
  13.391 +							env--;
  13.392 +							env -= env >> 8;
  13.393 +							rate = (adsr0 >> 3 & 0x0E) + 0x10;
  13.394 +						}
  13.395 +						else // env_attack
  13.396 +						{
  13.397 +							rate = (adsr0 & 0x0F) * 2 + 1;
  13.398 +							env += rate < 31 ? 0x20 : 0x400;
  13.399 +						}
  13.400 +					}
  13.401 +					else // GAIN
  13.402 +					{
  13.403 +						int mode;
  13.404 +						env_data = VREG(v_regs,gain);
  13.405 +						mode = env_data >> 5;
  13.406 +						if ( mode < 4 ) // direct
  13.407 +						{
  13.408 +							env = env_data * 0x10;
  13.409 +							rate = 31;
  13.410 +						}
  13.411 +						else
  13.412 +						{
  13.413 +							rate = env_data & 0x1F;
  13.414 +							if ( mode == 4 ) // 4: linear decrease
  13.415 +							{
  13.416 +								env -= 0x20;
  13.417 +							}
  13.418 +							else if ( mode < 6 ) // 5: exponential decrease
  13.419 +							{
  13.420 +								env--;
  13.421 +								env -= env >> 8;
  13.422 +							}
  13.423 +							else // 6,7: linear increase
  13.424 +							{
  13.425 +								env += 0x20;
  13.426 +								if ( mode > 6 && (unsigned) v->hidden_env >= 0x600 )
  13.427 +									env += 0x8 - 0x20; // 7: two-slope linear increase
  13.428 +							}
  13.429 +						}
  13.430 +					}
  13.431 +					
  13.432 +					// Sustain level
  13.433 +					if ( (env >> 8) == (env_data >> 5) && v->env_mode == env_decay )
  13.434 +						v->env_mode = env_sustain;
  13.435 +					
  13.436 +					v->hidden_env = env;
  13.437 +					
  13.438 +					// unsigned cast because linear decrease going negative also triggers this
  13.439 +					if ( (unsigned) env > 0x7FF )
  13.440 +					{
  13.441 +						env = (env < 0 ? 0 : 0x7FF);
  13.442 +						if ( v->env_mode == env_attack )
  13.443 +							v->env_mode = env_decay;
  13.444 +					}
  13.445 +					
  13.446 +					if ( !READ_COUNTER( rate ) )
  13.447 +						v->env = env; // nothing else is controlled by the counter
  13.448 +				}
  13.449 +			}
  13.450 +		exit_env:
  13.451 +			
  13.452 +			{
  13.453 +				// Apply pitch
  13.454 +				int old_pos = v->interp_pos;
  13.455 +				int interp_pos = (old_pos & 0x3FFF) + pitch;
  13.456 +				if ( interp_pos > 0x7FFF )
  13.457 +					interp_pos = 0x7FFF;
  13.458 +				v->interp_pos = interp_pos;
  13.459 +				
  13.460 +				// BRR decode if necessary
  13.461 +				if ( old_pos >= 0x4000 )
  13.462 +				{
  13.463 +					// Arrange the four input nybbles in 0xABCD order for easy decoding
  13.464 +					int nybbles = ram [(v->brr_addr + v->brr_offset) & 0xFFFF] * 0x100 +
  13.465 +							ram [(v->brr_addr + v->brr_offset + 1) & 0xFFFF];
  13.466 +					
  13.467 +					// Advance read position
  13.468 +					int const brr_block_size = 9;
  13.469 +					int brr_offset = v->brr_offset;
  13.470 +					if ( (brr_offset += 2) >= brr_block_size )
  13.471 +					{
  13.472 +						// Next BRR block
  13.473 +						int brr_addr = (v->brr_addr + brr_block_size) & 0xFFFF;
  13.474 +						assert( brr_offset == brr_block_size );
  13.475 +						if ( brr_header & 1 )
  13.476 +						{
  13.477 +							brr_addr = SAMPLE_PTR( 1 );
  13.478 +							if ( !v->kon_delay )
  13.479 +								REG(endx) |= vbit;
  13.480 +						}
  13.481 +						v->brr_addr = brr_addr;
  13.482 +						brr_offset  = 1;
  13.483 +					}
  13.484 +					v->brr_offset = brr_offset;
  13.485 +					
  13.486 +					// Decode
  13.487 +					
  13.488 +					// 0: >>1  1: <<0  2: <<1 ... 12: <<11  13-15: >>4 <<11
  13.489 +					static unsigned char const shifts [16 * 2] = {
  13.490 +						13,12,12,12,12,12,12,12,12,12,12, 12, 12, 16, 16, 16,
  13.491 +						 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 11, 11, 11
  13.492 +					};
  13.493 +					int const scale = brr_header >> 4;
  13.494 +					int const right_shift = shifts [scale];
  13.495 +					int const left_shift  = shifts [scale + 16];
  13.496 +					
  13.497 +					// Write to next four samples in circular buffer
  13.498 +					int* pos = v->buf_pos;
  13.499 +					int* end;
  13.500 +					
  13.501 +					// Decode four samples
  13.502 +					for ( end = pos + 4; pos < end; pos++, nybbles <<= 4 )
  13.503 +					{
  13.504 +						// Extract upper nybble and scale appropriately
  13.505 +						int s = ((int16_t) nybbles >> right_shift) << left_shift;
  13.506 +						
  13.507 +						// Apply IIR filter (8 is the most commonly used)
  13.508 +						int const filter = brr_header & 0x0C;
  13.509 +						int const p1 = pos [brr_buf_size - 1];
  13.510 +						int const p2 = pos [brr_buf_size - 2] >> 1;
  13.511 +						if ( filter >= 8 )
  13.512 +						{
  13.513 +							s += p1;
  13.514 +							s -= p2;
  13.515 +							if ( filter == 8 ) // s += p1 * 0.953125 - p2 * 0.46875
  13.516 +							{
  13.517 +								s += p2 >> 4;
  13.518 +								s += (p1 * -3) >> 6;
  13.519 +							}
  13.520 +							else // s += p1 * 0.8984375 - p2 * 0.40625
  13.521 +							{
  13.522 +								s += (p1 * -13) >> 7;
  13.523 +								s += (p2 * 3) >> 4;
  13.524 +							}
  13.525 +						}
  13.526 +						else if ( filter ) // s += p1 * 0.46875
  13.527 +						{
  13.528 +							s += p1 >> 1;
  13.529 +							s += (-p1) >> 5;
  13.530 +						}
  13.531 +						
  13.532 +						// Adjust and write sample
  13.533 +						CLAMP16( s );
  13.534 +						s = (int16_t) (s * 2);
  13.535 +						pos [brr_buf_size] = pos [0] = s; // second copy simplifies wrap-around
  13.536 +					}
  13.537 +					
  13.538 +					if ( pos >= &v->buf [brr_buf_size] )
  13.539 +						pos = v->buf;
  13.540 +					v->buf_pos = pos;
  13.541 +				}
  13.542 +			}
  13.543 +skip_brr:
  13.544 +			// Next voice
  13.545 +			vbit <<= 1;
  13.546 +			v_regs += 0x10;
  13.547 +			v++;
  13.548 +		}
  13.549 +		while ( vbit < 0x100 );
  13.550 +		
  13.551 +		// Echo position
  13.552 +		int echo_offset = m.echo_offset;
  13.553 +		uint8_t* const echo_ptr = &ram [(REG(esa) * 0x100 + echo_offset) & 0xFFFF];
  13.554 +		if ( !echo_offset )
  13.555 +			m.echo_length = (REG(edl) & 0x0F) * 0x800;
  13.556 +		echo_offset += 4;
  13.557 +		if ( echo_offset >= m.echo_length )
  13.558 +			echo_offset = 0;
  13.559 +		m.echo_offset = echo_offset;
  13.560 +		
  13.561 +		// FIR
  13.562 +		int echo_in_l = GET_LE16SA( echo_ptr + 0 );
  13.563 +		int echo_in_r = GET_LE16SA( echo_ptr + 2 );
  13.564 +		
  13.565 +		int (*echo_hist_pos) [2] = m.echo_hist_pos;
  13.566 +		if ( ++echo_hist_pos >= &m.echo_hist [echo_hist_size] )
  13.567 +			echo_hist_pos = m.echo_hist;
  13.568 +		m.echo_hist_pos = echo_hist_pos;
  13.569 +		
  13.570 +		echo_hist_pos [0] [0] = echo_hist_pos [8] [0] = echo_in_l;
  13.571 +		echo_hist_pos [0] [1] = echo_hist_pos [8] [1] = echo_in_r;
  13.572 +		
  13.573 +		#define CALC_FIR_( i, in )  ((in) * (int8_t) REG(fir + i * 0x10))
  13.574 +		echo_in_l = CALC_FIR_( 7, echo_in_l );
  13.575 +		echo_in_r = CALC_FIR_( 7, echo_in_r );
  13.576 +		
  13.577 +		#define CALC_FIR( i, ch )   CALC_FIR_( i, echo_hist_pos [i + 1] [ch] )
  13.578 +		#define DO_FIR( i )\
  13.579 +			echo_in_l += CALC_FIR( i, 0 );\
  13.580 +			echo_in_r += CALC_FIR( i, 1 );
  13.581 +		DO_FIR( 0 );
  13.582 +		DO_FIR( 1 );
  13.583 +		DO_FIR( 2 );
  13.584 +		#if defined (__MWERKS__) && __MWERKS__ < 0x3200
  13.585 +			__eieio(); // keeps compiler from stupidly "caching" things in memory
  13.586 +		#endif
  13.587 +		DO_FIR( 3 );
  13.588 +		DO_FIR( 4 );
  13.589 +		DO_FIR( 5 );
  13.590 +		DO_FIR( 6 );
  13.591 +		
  13.592 +		// Echo out
  13.593 +		if ( !(REG(flg) & 0x20) )
  13.594 +		{
  13.595 +			int l = (echo_out_l >> 7) + ((echo_in_l * (int8_t) REG(efb)) >> 14);
  13.596 +			int r = (echo_out_r >> 7) + ((echo_in_r * (int8_t) REG(efb)) >> 14);
  13.597 +			
  13.598 +			// just to help pass more validation tests
  13.599 +			#if SPC_MORE_ACCURACY
  13.600 +				l &= ~1;
  13.601 +				r &= ~1;
  13.602 +			#endif
  13.603 +			
  13.604 +			CLAMP16( l );
  13.605 +			CLAMP16( r );
  13.606 +			
  13.607 +			SET_LE16A( echo_ptr + 0, l );
  13.608 +			SET_LE16A( echo_ptr + 2, r );
  13.609 +		}
  13.610 +		
  13.611 +		// Sound out
  13.612 +		int l = (main_out_l * mvoll + echo_in_l * (int8_t) REG(evoll)) >> 14;
  13.613 +		int r = (main_out_r * mvolr + echo_in_r * (int8_t) REG(evolr)) >> 14;
  13.614 +		
  13.615 +		CLAMP16( l );
  13.616 +		CLAMP16( r );
  13.617 +		
  13.618 +		if ( (REG(flg) & 0x40) )
  13.619 +		{
  13.620 +			l = 0;
  13.621 +			r = 0;
  13.622 +		}
  13.623 +		
  13.624 +		sample_t* out = m.out;
  13.625 +		WRITE_SAMPLES( l, r, out );
  13.626 +		m.out = out;
  13.627 +	}
  13.628 +	while ( --count );
  13.629 +}
  13.630 +
  13.631 +
  13.632 +//// Setup
  13.633 +
  13.634 +void SPC_DSP::mute_voices( int mask )
  13.635 +{
  13.636 +	m.mute_mask = mask;
  13.637 +	for ( int i = 0; i < voice_count; i++ )
  13.638 +	{
  13.639 +		m.voices [i].enabled = (mask >> i & 1) - 1;
  13.640 +		update_voice_vol( i * 0x10 );
  13.641 +	}
  13.642 +}
  13.643 +
  13.644 +void SPC_DSP::init( void* ram_64k )
  13.645 +{
  13.646 +	m.ram = (uint8_t*) ram_64k;
  13.647 +	mute_voices( 0 );
  13.648 +	disable_surround( false );
  13.649 +	set_output( 0, 0 );
  13.650 +	reset();
  13.651 +	
  13.652 +	#ifndef NDEBUG
  13.653 +		// be sure this sign-extends
  13.654 +		assert( (int16_t) 0x8000 == -0x8000 );
  13.655 +		
  13.656 +		// be sure right shift preserves sign
  13.657 +		assert( (-1 >> 1) == -1 );
  13.658 +		
  13.659 +		// check clamp macro
  13.660 +		int i;
  13.661 +		i = +0x8000; CLAMP16( i ); assert( i == +0x7FFF );
  13.662 +		i = -0x8001; CLAMP16( i ); assert( i == -0x8000 );
  13.663 +		
  13.664 +		blargg_verify_byte_order();
  13.665 +	#endif
  13.666 +}
  13.667 +
  13.668 +void SPC_DSP::soft_reset_common()
  13.669 +{
  13.670 +	require( m.ram ); // init() must have been called already
  13.671 +	
  13.672 +	m.noise              = 0x4000;
  13.673 +	m.echo_hist_pos      = m.echo_hist;
  13.674 +	m.every_other_sample = 1;
  13.675 +	m.echo_offset        = 0;
  13.676 +	m.phase              = 0;
  13.677 +	
  13.678 +	init_counter();
  13.679 +}
  13.680 +
  13.681 +void SPC_DSP::soft_reset()
  13.682 +{
  13.683 +	REG(flg) = 0xE0;
  13.684 +	soft_reset_common();
  13.685 +}
  13.686 +
  13.687 +void SPC_DSP::load( uint8_t const regs [register_count] )
  13.688 +{
  13.689 +	memcpy( m.regs, regs, sizeof m.regs );
  13.690 +	memset( &m.regs [register_count], 0, offsetof (state_t,ram) - register_count );
  13.691 +	
  13.692 +	// Internal state
  13.693 +	int i;
  13.694 +	for ( i = voice_count; --i >= 0; )
  13.695 +	{
  13.696 +		voice_t& v = m.voices [i];
  13.697 +		v.brr_offset = 1;
  13.698 +		v.buf_pos    = v.buf;
  13.699 +	}
  13.700 +	m.new_kon = REG(kon);
  13.701 +	
  13.702 +	mute_voices( m.mute_mask );
  13.703 +	soft_reset_common();
  13.704 +}
  13.705 +
  13.706 +void SPC_DSP::reset() { load( initial_regs ); }
    14.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    14.2 +++ b/fast_dsp/SPC_DSP.h	Fri Oct 21 05:53:11 2011 -0700
    14.3 @@ -0,0 +1,212 @@
    14.4 +// Fast SNES SPC-700 DSP emulator (about 3x speed of accurate one)
    14.5 +
    14.6 +// snes_spc 0.9.0
    14.7 +#ifndef SPC_DSP_H
    14.8 +#define SPC_DSP_H
    14.9 +
   14.10 +#include "blargg_common.h"
   14.11 +
   14.12 +class SPC_DSP {
   14.13 +public:
   14.14 +	typedef BOOST::uint8_t uint8_t;
   14.15 +	
   14.16 +// Setup
   14.17 +	
   14.18 +	// Initializes DSP and has it use the 64K RAM provided
   14.19 +	void init( void* ram_64k );
   14.20 +
   14.21 +	// Sets destination for output samples. If out is NULL or out_size is 0,
   14.22 +	// doesn't generate any.
   14.23 +	typedef short sample_t;
   14.24 +	void set_output( sample_t* out, int out_size );
   14.25 +
   14.26 +	// Number of samples written to output since it was last set, always
   14.27 +	// a multiple of 2. Undefined if more samples were generated than
   14.28 +	// output buffer could hold.
   14.29 +	int sample_count() const;
   14.30 +
   14.31 +// Emulation
   14.32 +	
   14.33 +	// Resets DSP to power-on state
   14.34 +	void reset();
   14.35 +
   14.36 +	// Emulates pressing reset switch on SNES
   14.37 +	void soft_reset();
   14.38 +	
   14.39 +	// Reads/writes DSP registers. For accuracy, you must first call spc_run_dsp()
   14.40 +	// to catch the DSP up to present.
   14.41 +	int  read ( int addr ) const;
   14.42 +	void write( int addr, int data );
   14.43 +
   14.44 +	// Runs DSP for specified number of clocks (~1024000 per second). Every 32 clocks
   14.45 +	// a pair of samples is be generated.
   14.46 +	void run( int clock_count );
   14.47 +
   14.48 +// Sound control
   14.49 +
   14.50 +	// Mutes voices corresponding to non-zero bits in mask (overrides VxVOL with 0).
   14.51 +	// Reduces emulation accuracy.
   14.52 +	enum { voice_count = 8 };
   14.53 +	void mute_voices( int mask );
   14.54 +
   14.55 +	// If true, prevents channels and global volumes from being phase-negated
   14.56 +	void disable_surround( bool disable = true );
   14.57 +
   14.58 +// State
   14.59 +	
   14.60 +	// Resets DSP and uses supplied values to initialize registers
   14.61 +	enum { register_count = 128 };
   14.62 +	void load( uint8_t const regs [register_count] );
   14.63 +
   14.64 +// DSP register addresses
   14.65 +
   14.66 +	// Global registers
   14.67 +	enum {
   14.68 +	    r_mvoll = 0x0C, r_mvolr = 0x1C,
   14.69 +	    r_evoll = 0x2C, r_evolr = 0x3C,
   14.70 +	    r_kon   = 0x4C, r_koff  = 0x5C,
   14.71 +	    r_flg   = 0x6C, r_endx  = 0x7C,
   14.72 +	    r_efb   = 0x0D, r_pmon  = 0x2D,
   14.73 +	    r_non   = 0x3D, r_eon   = 0x4D,
   14.74 +	    r_dir   = 0x5D, r_esa   = 0x6D,
   14.75 +	    r_edl   = 0x7D,
   14.76 +	    r_fir   = 0x0F // 8 coefficients at 0x0F, 0x1F ... 0x7F
   14.77 +	};
   14.78 +
   14.79 +	// Voice registers
   14.80 +	enum {
   14.81 +		v_voll   = 0x00, v_volr   = 0x01,
   14.82 +		v_pitchl = 0x02, v_pitchh = 0x03,
   14.83 +		v_srcn   = 0x04, v_adsr0  = 0x05,
   14.84 +		v_adsr1  = 0x06, v_gain   = 0x07,
   14.85 +		v_envx   = 0x08, v_outx   = 0x09
   14.86 +	};
   14.87 +
   14.88 +public:
   14.89 +	enum { extra_size = 16 };
   14.90 +	sample_t* extra()               { return m.extra; }
   14.91 +	sample_t const* out_pos() const { return m.out; }
   14.92 +public:
   14.93 +	BLARGG_DISABLE_NOTHROW
   14.94 +	
   14.95 +	typedef BOOST::int8_t   int8_t;
   14.96 +	typedef BOOST::int16_t int16_t;
   14.97 +	
   14.98 +	enum { echo_hist_size = 8 };
   14.99 +	
  14.100 +	enum env_mode_t { env_release, env_attack, env_decay, env_sustain };
  14.101 +	enum { brr_buf_size = 12 };
  14.102 +	struct voice_t
  14.103 +	{
  14.104 +		int buf [brr_buf_size*2];// decoded samples (twice the size to simplify wrap handling)
  14.105 +		int* buf_pos;           // place in buffer where next samples will be decoded
  14.106 +		int interp_pos;         // relative fractional position in sample (0x1000 = 1.0)
  14.107 +		int brr_addr;           // address of current BRR block
  14.108 +		int brr_offset;         // current decoding offset in BRR block
  14.109 +		int kon_delay;          // KON delay/current setup phase
  14.110 +		env_mode_t env_mode;
  14.111 +		int env;                // current envelope level
  14.112 +		int hidden_env;         // used by GAIN mode 7, very obscure quirk
  14.113 +		int volume [2];         // copy of volume from DSP registers, with surround disabled
  14.114 +		int enabled;            // -1 if enabled, 0 if muted
  14.115 +	};
  14.116 +private:
  14.117 +	struct state_t
  14.118 +	{
  14.119 +		uint8_t regs [register_count];
  14.120 +		
  14.121 +		// Echo history keeps most recent 8 samples (twice the size to simplify wrap handling)
  14.122 +		int echo_hist [echo_hist_size * 2] [2];
  14.123 +		int (*echo_hist_pos) [2]; // &echo_hist [0 to 7]
  14.124 +		
  14.125 +		int every_other_sample; // toggles every sample
  14.126 +		int kon;                // KON value when last checked
  14.127 +		int noise;
  14.128 +		int echo_offset;        // offset from ESA in echo buffer
  14.129 +		int echo_length;        // number of bytes that echo_offset will stop at
  14.130 +		int phase;              // next clock cycle to run (0-31)
  14.131 +		unsigned counters [4];
  14.132 +		
  14.133 +		int new_kon;
  14.134 +		int t_koff;
  14.135 +		
  14.136 +		voice_t voices [voice_count];
  14.137 +		
  14.138 +		unsigned* counter_select [32];
  14.139 +		
  14.140 +		// non-emulation state
  14.141 +		uint8_t* ram; // 64K shared RAM between DSP and SMP
  14.142 +		int mute_mask;
  14.143 +		int surround_threshold;
  14.144 +		sample_t* out;
  14.145 +		sample_t* out_end;
  14.146 +		sample_t* out_begin;
  14.147 +		sample_t extra [extra_size];
  14.148 +	};
  14.149 +	state_t m;
  14.150 +	
  14.151 +	void init_counter();
  14.152 +	void run_counter( int );
  14.153 +	void soft_reset_common();
  14.154 +	void write_outline( int addr, int data );
  14.155 +	void update_voice_vol( int addr );
  14.156 +};
  14.157 +
  14.158 +#include <assert.h>
  14.159 +
  14.160 +inline int SPC_DSP::sample_count() const { return m.out - m.out_begin; }
  14.161 +
  14.162 +inline int SPC_DSP::read( int addr ) const
  14.163 +{
  14.164 +	assert( (unsigned) addr < register_count );
  14.165 +	return m.regs [addr];
  14.166 +}
  14.167 +
  14.168 +inline void SPC_DSP::update_voice_vol( int addr )
  14.169 +{
  14.170 +	int l = (int8_t) m.regs [addr + v_voll];
  14.171 +	int r = (int8_t) m.regs [addr + v_volr];
  14.172 +	
  14.173 +	if ( l * r < m.surround_threshold )
  14.174 +	{
  14.175 +		// signs differ, so negate those that are negative
  14.176 +		l ^= l >> 7;
  14.177 +		r ^= r >> 7;
  14.178 +	}
  14.179 +	
  14.180 +	voice_t& v = m.voices [addr >> 4];
  14.181 +	int enabled = v.enabled;
  14.182 +	v.volume [0] = l & enabled;
  14.183 +	v.volume [1] = r & enabled;
  14.184 +}
  14.185 +
  14.186 +inline void SPC_DSP::write( int addr, int data )
  14.187 +{
  14.188 +	assert( (unsigned) addr < register_count );
  14.189 +	
  14.190 +	m.regs [addr] = (uint8_t) data;
  14.191 +	int low = addr & 0x0F;
  14.192 +	if ( low < 0x2 ) // voice volumes
  14.193 +	{
  14.194 +		update_voice_vol( low ^ addr );
  14.195 +	}
  14.196 +	else if ( low == 0xC )
  14.197 +	{
  14.198 +		if ( addr == r_kon )
  14.199 +			m.new_kon = (uint8_t) data;
  14.200 +		
  14.201 +		if ( addr == r_endx ) // always cleared, regardless of data written
  14.202 +			m.regs [r_endx] = 0;
  14.203 +	}
  14.204 +}
  14.205 +
  14.206 +inline void SPC_DSP::disable_surround( bool disable )
  14.207 +{
  14.208 +	m.surround_threshold = disable ? 0 : -0x4000;
  14.209 +}
  14.210 +
  14.211 +#define SPC_NO_COPY_STATE_FUNCS 1
  14.212 +
  14.213 +#define SPC_LESS_ACCURATE 1
  14.214 +
  14.215 +#endif
    15.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    15.2 +++ b/license.txt	Fri Oct 21 05:53:11 2011 -0700
    15.3 @@ -0,0 +1,504 @@
    15.4 +		  GNU LESSER GENERAL PUBLIC LICENSE
    15.5 +		       Version 2.1, February 1999
    15.6 +
    15.7 + Copyright (C) 1991, 1999 Free Software Foundation, Inc.
    15.8 + 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
    15.9 + Everyone is permitted to copy and distribute verbatim copies
   15.10 + of this license document, but changing it is not allowed.
   15.11 +
   15.12 +[This is the first released version of the Lesser GPL.  It also counts
   15.13 + as the successor of the GNU Library Public License, version 2, hence
   15.14 + the version number 2.1.]
   15.15 +
   15.16 +			    Preamble
   15.17 +
   15.18 +  The licenses for most software are designed to take away your
   15.19 +freedom to share and change it.  By contrast, the GNU General Public
   15.20 +Licenses are intended to guarantee your freedom to share and change
   15.21 +free software--to make sure the software is free for all its users.
   15.22 +
   15.23 +  This license, the Lesser General Public License, applies to some
   15.24 +specially designated software packages--typically libraries--of the
   15.25 +Free Software Foundation and other authors who decide to use it.  You
   15.26 +can use it too, but we suggest you first think carefully about whether
   15.27 +this license or the ordinary General Public License is the better
   15.28 +strategy to use in any particular case, based on the explanations below.
   15.29 +
   15.30 +  When we speak of free software, we are referring to freedom of use,
   15.31 +not price.  Our General Public Licenses are designed to make sure that
   15.32 +you have the freedom to distribute copies of free software (and charge
   15.33 +for this service if you wish); that you receive source code or can get
   15.34 +it if you want it; that you can change the software and use pieces of
   15.35 +it in new free programs; and that you are informed that you can do
   15.36 +these things.
   15.37 +
   15.38 +  To protect your rights, we need to make restrictions that forbid
   15.39 +distributors to deny you these rights or to ask you to surrender these
   15.40 +rights.  These restrictions translate to certain responsibilities for
   15.41 +you if you distribute copies of the library or if you modify it.
   15.42 +
   15.43 +  For example, if you distribute copies of the library, whether gratis
   15.44 +or for a fee, you must give the recipients all the rights that we gave
   15.45 +you.  You must make sure that they, too, receive or can get the source
   15.46 +code.  If you link other code with the library, you must provide
   15.47 +complete object files to the recipients, so that they can relink them
   15.48 +with the library after making changes to the library and recompiling
   15.49 +it.  And you must show them these terms so they know their rights.
   15.50 +
   15.51 +  We protect your rights with a two-step method: (1) we copyright the
   15.52 +library, and (2) we offer you this license, which gives you legal
   15.53 +permission to copy, distribute and/or modify the library.
   15.54 +
   15.55 +  To protect each distributor, we want to make it very clear that
   15.56 +there is no warranty for the free library.  Also, if the library is
   15.57 +modified by someone else and passed on, the recipients should know
   15.58 +that what they have is not the original version, so that the original
   15.59 +author's reputation will not be affected by problems that might be
   15.60 +introduced by others.
   15.61 +
   15.62 +  Finally, software patents pose a constant threat to the existence of
   15.63 +any free program.  We wish to make sure that a company cannot
   15.64 +effectively restrict the users of a free program by obtaining a
   15.65 +restrictive license from a patent holder.  Therefore, we insist that
   15.66 +any patent license obtained for a version of the library must be
   15.67 +consistent with the full freedom of use specified in this license.
   15.68 +
   15.69 +  Most GNU software, including some libraries, is covered by the
   15.70 +ordinary GNU General Public License.  This license, the GNU Lesser
   15.71 +General Public License, applies to certain designated libraries, and
   15.72 +is quite different from the ordinary General Public License.  We use
   15.73 +this license for certain libraries in order to permit linking those
   15.74 +libraries into non-free programs.
   15.75 +
   15.76 +  When a program is linked with a library, whether statically or using
   15.77 +a shared library, the combination of the two is legally speaking a
   15.78 +combined work, a derivative of the original library.  The ordinary
   15.79 +General Public License therefore permits such linking only if the
   15.80 +entire combination fits its criteria of freedom.  The Lesser General
   15.81 +Public License permits more lax criteria for linking other code with
   15.82 +the library.
   15.83 +
   15.84 +  We call this license the "Lesser" General Public License because it
   15.85 +does Less to protect the user's freedom than the ordinary General
   15.86 +Public License.  It also provides other free software developers Less
   15.87 +of an advantage over competing non-free programs.  These disadvantages
   15.88 +are the reason we use the ordinary General Public License for many
   15.89 +libraries.  However, the Lesser license provides advantages in certain
   15.90 +special circumstances.
   15.91 +
   15.92 +  For example, on rare occasions, there may be a special need to
   15.93 +encourage the widest possible use of a certain library, so that it becomes
   15.94 +a de-facto standard.  To achieve this, non-free programs must be
   15.95 +allowed to use the library.  A more frequent case is that a free
   15.96 +library does the same job as widely used non-free libraries.  In this
   15.97 +case, there is little to gain by limiting the free library to free
   15.98 +software only, so we use the Lesser General Public License.
   15.99 +
  15.100 +  In other cases, permission to use a particular library in non-free
  15.101 +programs enables a greater number of people to use a large body of
  15.102 +free software.  For example, permission to use the GNU C Library in
  15.103 +non-free programs enables many more people to use the whole GNU
  15.104 +operating system, as well as its variant, the GNU/Linux operating
  15.105 +system.
  15.106 +
  15.107 +  Although the Lesser General Public License is Less protective of the
  15.108 +users' freedom, it does ensure that the user of a program that is
  15.109 +linked with the Library has the freedom and the wherewithal to run
  15.110 +that program using a modified version of the Library.
  15.111 +
  15.112 +  The precise terms and conditions for copying, distribution and
  15.113 +modification follow.  Pay close attention to the difference between a
  15.114 +"work based on the library" and a "work that uses the library".  The
  15.115 +former contains code derived from the library, whereas the latter must
  15.116 +be combined with the library in order to run.
  15.117 +
  15.118 +		  GNU LESSER GENERAL PUBLIC LICENSE
  15.119 +   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
  15.120 +
  15.121 +  0. This License Agreement applies to any software library or other
  15.122 +program which contains a notice placed by the copyright holder or
  15.123 +other authorized party saying it may be distributed under the terms of
  15.124 +this Lesser General Public License (also called "this License").
  15.125 +Each licensee is addressed as "you".
  15.126 +
  15.127 +  A "library" means a collection of software functions and/or data
  15.128 +prepared so as to be conveniently linked with application programs
  15.129 +(which use some of those functions and data) to form executables.
  15.130 +
  15.131 +  The "Library", below, refers to any such software library or work
  15.132 +which has been distributed under these terms.  A "work based on the
  15.133 +Library" means either the Library or any derivative work under
  15.134 +copyright law: that is to say, a work containing the Library or a
  15.135 +portion of it, either verbatim or with modifications and/or translated
  15.136 +straightforwardly into another language.  (Hereinafter, translation is
  15.137 +included without limitation in the term "modification".)
  15.138 +
  15.139 +  "Source code" for a work means the preferred form of the work for
  15.140 +making modifications to it.  For a library, complete source code means
  15.141 +all the source code for all modules it contains, plus any associated
  15.142 +interface definition files, plus the scripts used to control compilation
  15.143 +and installation of the library.
  15.144 +
  15.145 +  Activities other than copying, distribution and modification are not
  15.146 +covered by this License; they are outside its scope.  The act of
  15.147 +running a program using the Library is not restricted, and output from
  15.148 +such a program is covered only if its contents constitute a work based
  15.149 +on the Library (independent of the use of the Library in a tool for
  15.150 +writing it).  Whether that is true depends on what the Library does
  15.151 +and what the program that uses the Library does.
  15.152 +  
  15.153 +  1. You may copy and distribute verbatim copies of the Library's
  15.154 +complete source code as you receive it, in any medium, provided that
  15.155 +you conspicuously and appropriately publish on each copy an
  15.156 +appropriate copyright notice and disclaimer of warranty; keep intact
  15.157 +all the notices that refer to this License and to the absence of any
  15.158 +warranty; and distribute a copy of this License along with the
  15.159 +Library.
  15.160 +
  15.161 +  You may charge a fee for the physical act of transferring a copy,
  15.162 +and you may at your option offer warranty protection in exchange for a
  15.163 +fee.
  15.164 +
  15.165 +  2. You may modify your copy or copies of the Library or any portion
  15.166 +of it, thus forming a work based on the Library, and copy and
  15.167 +distribute such modifications or work under the terms of Section 1
  15.168 +above, provided that you also meet all of these conditions:
  15.169 +
  15.170 +    a) The modified work must itself be a software library.
  15.171 +
  15.172 +    b) You must cause the files modified to carry prominent notices
  15.173 +    stating that you changed the files and the date of any change.
  15.174 +
  15.175 +    c) You must cause the whole of the work to be licensed at no
  15.176 +    charge to all third parties under the terms of this License.
  15.177 +
  15.178 +    d) If a facility in the modified Library refers to a function or a
  15.179 +    table of data to be supplied by an application program that uses
  15.180 +    the facility, other than as an argument passed when the facility
  15.181 +    is invoked, then you must make a good faith effort to ensure that,
  15.182 +    in the event an application does not supply such function or
  15.183 +    table, the facility still operates, and performs whatever part of
  15.184 +    its purpose remains meaningful.
  15.185 +
  15.186 +    (For example, a function in a library to compute square roots has
  15.187 +    a purpose that is entirely well-defined independent of the
  15.188 +    application.  Therefore, Subsection 2d requires that any
  15.189 +    application-supplied function or table used by this function must
  15.190 +    be optional: if the application does not supply it, the square
  15.191 +    root function must still compute square roots.)
  15.192 +
  15.193 +These requirements apply to the modified work as a whole.  If
  15.194 +identifiable sections of that work are not derived from the Library,
  15.195 +and can be reasonably considered independent and separate works in
  15.196 +themselves, then this License, and its terms, do not apply to those
  15.197 +sections when you distribute them as separate works.  But when you
  15.198 +distribute the same sections as part of a whole which is a work based
  15.199 +on the Library, the distribution of the whole must be on the terms of
  15.200 +this License, whose permissions for other licensees extend to the
  15.201 +entire whole, and thus to each and every part regardless of who wrote
  15.202 +it.
  15.203 +
  15.204 +Thus, it is not the intent of this section to claim rights or contest
  15.205 +your rights to work written entirely by you; rather, the intent is to
  15.206 +exercise the right to control the distribution of derivative or
  15.207 +collective works based on the Library.
  15.208 +
  15.209 +In addition, mere aggregation of another work not based on the Library
  15.210 +with the Library (or with a work based on the Library) on a volume of
  15.211 +a storage or distribution medium does not bring the other work under
  15.212 +the scope of this License.
  15.213 +
  15.214 +  3. You may opt to apply the terms of the ordinary GNU General Public
  15.215 +License instead of this License to a given copy of the Library.  To do
  15.216 +this, you must alter all the notices that refer to this License, so
  15.217 +that they refer to the ordinary GNU General Public License, version 2,
  15.218 +instead of to this License.  (If a newer version than version 2 of the
  15.219 +ordinary GNU General Public License has appeared, then you can specify
  15.220 +that version instead if you wish.)  Do not make any other change in
  15.221 +these notices.
  15.222 +
  15.223 +  Once this change is made in a given copy, it is irreversible for
  15.224 +that copy, so the ordinary GNU General Public License applies to all
  15.225 +subsequent copies and derivative works made from that copy.
  15.226 +
  15.227 +  This option is useful when you wish to copy part of the code of
  15.228 +the Library into a program that is not a library.
  15.229 +
  15.230 +  4. You may copy and distribute the Library (or a portion or
  15.231 +derivative of it, under Section 2) in object code or executable form
  15.232 +under the terms of Sections 1 and 2 above provided that you accompany
  15.233 +it with the complete corresponding machine-readable source code, which
  15.234 +must be distributed under the terms of Sections 1 and 2 above on a
  15.235 +medium customarily used for software interchange.
  15.236 +
  15.237 +  If distribution of object code is made by offering access to copy
  15.238 +from a designated place, then offering equivalent access to copy the
  15.239 +source code from the same place satisfies the requirement to
  15.240 +distribute the source code, even though third parties are not
  15.241 +compelled to copy the source along with the object code.
  15.242 +
  15.243 +  5. A program that contains no derivative of any portion of the
  15.244 +Library, but is designed to work with the Library by being compiled or
  15.245 +linked with it, is called a "work that uses the Library".  Such a
  15.246 +work, in isolation, is not a derivative work of the Library, and
  15.247 +therefore falls outside the scope of this License.
  15.248 +
  15.249 +  However, linking a "work that uses the Library" with the Library
  15.250 +creates an executable that is a derivative of the Library (because it
  15.251 +contains portions of the Library), rather than a "work that uses the
  15.252 +library".  The executable is therefore covered by this License.
  15.253 +Section 6 states terms for distribution of such executables.
  15.254 +
  15.255 +  When a "work that uses the Library" uses material from a header file
  15.256 +that is part of the Library, the object code for the work may be a
  15.257 +derivative work of the Library even though the source code is not.
  15.258 +Whether this is true is especially significant if the work can be
  15.259 +linked without the Library, or if the work is itself a library.  The
  15.260 +threshold for this to be true is not precisely defined by law.
  15.261 +
  15.262 +  If such an object file uses only numerical parameters, data
  15.263 +structure layouts and accessors, and small macros and small inline
  15.264 +functions (ten lines or less in length), then the use of the object
  15.265 +file is unrestricted, regardless of whether it is legally a derivative
  15.266 +work.  (Executables containing this object code plus portions of the
  15.267 +Library will still fall under Section 6.)
  15.268 +
  15.269 +  Otherwise, if the work is a derivative of the Library, you may
  15.270 +distribute the object code for the work under the terms of Section 6.
  15.271 +Any executables containing that work also fall under Section 6,
  15.272 +whether or not they are linked directly with the Library itself.
  15.273 +
  15.274 +  6. As an exception to the Sections above, you may also combine or
  15.275 +link a "work that uses the Library" with the Library to produce a
  15.276 +work containing portions of the Library, and distribute that work
  15.277 +under terms of your choice, provided that the terms permit
  15.278 +modification of the work for the customer's own use and reverse
  15.279 +engineering for debugging such modifications.
  15.280 +
  15.281 +  You must give prominent notice with each copy of the work that the
  15.282 +Library is used in it and that the Library and its use are covered by
  15.283 +this License.  You must supply a copy of this License.  If the work
  15.284 +during execution displays copyright notices, you must include the
  15.285 +copyright notice for the Library among them, as well as a reference
  15.286 +directing the user to the copy of this License.  Also, you must do one
  15.287 +of these things:
  15.288 +
  15.289 +    a) Accompany the work with the complete corresponding
  15.290 +    machine-readable source code for the Library including whatever
  15.291 +    changes were used in the work (which must be distributed under
  15.292 +    Sections 1 and 2 above); and, if the work is an executable linked
  15.293 +    with the Library, with the complete machine-readable "work that
  15.294 +    uses the Library", as object code and/or source code, so that the
  15.295 +    user can modify the Library and then relink to produce a modified
  15.296 +    executable containing the modified Library.  (It is understood
  15.297 +    that the user who changes the contents of definitions files in the
  15.298 +    Library will not necessarily be able to recompile the application
  15.299 +    to use the modified definitions.)
  15.300 +
  15.301 +    b) Use a suitable shared library mechanism for linking with the
  15.302 +    Library.  A suitable mechanism is one that (1) uses at run time a
  15.303 +    copy of the library already present on the user's computer system,
  15.304 +    rather than copying library functions into the executable, and (2)
  15.305 +    will operate properly with a modified version of the library, if
  15.306 +    the user installs one, as long as the modified version is
  15.307 +    interface-compatible with the version that the work was made with.
  15.308 +
  15.309 +    c) Accompany the work with a written offer, valid for at
  15.310 +    least three years, to give the same user the materials
  15.311 +    specified in Subsection 6a, above, for a charge no more
  15.312 +    than the cost of performing this distribution.
  15.313 +
  15.314 +    d) If distribution of the work is made by offering access to copy
  15.315 +    from a designated place, offer equivalent access to copy the above
  15.316 +    specified materials from the same place.
  15.317 +
  15.318 +    e) Verify that the user has already received a copy of these
  15.319 +    materials or that you have already sent this user a copy.
  15.320 +
  15.321 +  For an executable, the required form of the "work that uses the
  15.322 +Library" must include any data and utility programs needed for
  15.323 +reproducing the executable from it.  However, as a special exception,
  15.324 +the materials to be distributed need not include anything that is
  15.325 +normally distributed (in either source or binary form) with the major
  15.326 +components (compiler, kernel, and so on) of the operating system on
  15.327 +which the executable runs, unless that component itself accompanies
  15.328 +the executable.
  15.329 +
  15.330 +  It may happen that this requirement contradicts the license
  15.331 +restrictions of other proprietary libraries that do not normally
  15.332 +accompany the operating system.  Such a contradiction means you cannot
  15.333 +use both them and the Library together in an executable that you
  15.334 +distribute.
  15.335 +
  15.336 +  7. You may place library facilities that are a work based on the
  15.337 +Library side-by-side in a single library together with other library
  15.338 +facilities not covered by this License, and distribute such a combined
  15.339 +library, provided that the separate distribution of the work based on
  15.340 +the Library and of the other library facilities is otherwise
  15.341 +permitted, and provided that you do these two things:
  15.342 +
  15.343 +    a) Accompany the combined library with a copy of the same work
  15.344 +    based on the Library, uncombined with any other library
  15.345 +    facilities.  This must be distributed under the terms of the
  15.346 +    Sections above.
  15.347 +
  15.348 +    b) Give prominent notice with the combined library of the fact
  15.349 +    that part of it is a work based on the Library, and explaining
  15.350 +    where to find the accompanying uncombined form of the same work.
  15.351 +
  15.352 +  8. You may not copy, modify, sublicense, link with, or distribute
  15.353 +the Library except as expressly provided under this License.  Any
  15.354 +attempt otherwise to copy, modify, sublicense, link with, or
  15.355 +distribute the Library is void, and will automatically terminate your
  15.356 +rights under this License.  However, parties who have received copies,
  15.357 +or rights, from you under this License will not have their licenses
  15.358 +terminated so long as such parties remain in full compliance.
  15.359 +
  15.360 +  9. You are not required to accept this License, since you have not
  15.361 +signed it.  However, nothing else grants you permission to modify or
  15.362 +distribute the Library or its derivative works.  These actions are
  15.363 +prohibited by law if you do not accept this License.  Therefore, by
  15.364 +modifying or distributing the Library (or any work based on the
  15.365 +Library), you indicate your acceptance of this License to do so, and
  15.366 +all its terms and conditions for copying, distributing or modifying
  15.367 +the Library or works based on it.
  15.368 +
  15.369 +  10. Each time you redistribute the Library (or any work based on the
  15.370 +Library), the recipient automatically receives a license from the
  15.371 +original licensor to copy, distribute, link with or modify the Library
  15.372 +subject to these terms and conditions.  You may not impose any further
  15.373 +restrictions on the recipients' exercise of the rights granted herein.
  15.374 +You are not responsible for enforcing compliance by third parties with
  15.375 +this License.
  15.376 +
  15.377 +  11. If, as a consequence of a court judgment or allegation of patent
  15.378 +infringement or for any other reason (not limited to patent issues),
  15.379 +conditions are imposed on you (whether by court order, agreement or
  15.380 +otherwise) that contradict the conditions of this License, they do not
  15.381 +excuse you from the conditions of this License.  If you cannot
  15.382 +distribute so as to satisfy simultaneously your obligations under this
  15.383 +License and any other pertinent obligations, then as a consequence you
  15.384 +may not distribute the Library at all.  For example, if a patent
  15.385 +license would not permit royalty-free redistribution of the Library by
  15.386 +all those who receive copies directly or indirectly through you, then
  15.387 +the only way you could satisfy both it and this License would be to
  15.388 +refrain entirely from distribution of the Library.
  15.389 +
  15.390 +If any portion of this section is held invalid or unenforceable under any
  15.391 +particular circumstance, the balance of the section is intended to apply,
  15.392 +and the section as a whole is intended to apply in other circumstances.
  15.393 +
  15.394 +It is not the purpose of this section to induce you to infringe any
  15.395 +patents or other property right claims or to contest validity of any
  15.396 +such claims; this section has the sole purpose of protecting the
  15.397 +integrity of the free software distribution system which is
  15.398 +implemented by public license practices.  Many people have made
  15.399 +generous contributions to the wide range of software distributed
  15.400 +through that system in reliance on consistent application of that
  15.401 +system; it is up to the author/donor to decide if he or she is willing
  15.402 +to distribute software through any other system and a licensee cannot
  15.403 +impose that choice.
  15.404 +
  15.405 +This section is intended to make thoroughly clear what is believed to
  15.406 +be a consequence of the rest of this License.
  15.407 +
  15.408 +  12. If the distribution and/or use of the Library is restricted in
  15.409 +certain countries either by patents or by copyrighted interfaces, the
  15.410 +original copyright holder who places the Library under this License may add
  15.411 +an explicit geographical distribution limitation excluding those countries,
  15.412 +so that distribution is permitted only in or among countries not thus
  15.413 +excluded.  In such case, this License incorporates the limitation as if
  15.414 +written in the body of this License.
  15.415 +
  15.416 +  13. The Free Software Foundation may publish revised and/or new
  15.417 +versions of the Lesser General Public License from time to time.
  15.418 +Such new versions will be similar in spirit to the present version,
  15.419 +but may differ in detail to address new problems or concerns.
  15.420 +
  15.421 +Each version is given a distinguishing version number.  If the Library
  15.422 +specifies a version number of this License which applies to it and
  15.423 +"any later version", you have the option of following the terms and
  15.424 +conditions either of that version or of any later version published by
  15.425 +the Free Software Foundation.  If the Library does not specify a
  15.426 +license version number, you may choose any version ever published by
  15.427 +the Free Software Foundation.
  15.428 +
  15.429 +  14. If you wish to incorporate parts of the Library into other free
  15.430 +programs whose distribution conditions are incompatible with these,
  15.431 +write to the author to ask for permission.  For software which is
  15.432 +copyrighted by the Free Software Foundation, write to the Free
  15.433 +Software Foundation; we sometimes make exceptions for this.  Our
  15.434 +decision will be guided by the two goals of preserving the free status
  15.435 +of all derivatives of our free software and of promoting the sharing
  15.436 +and reuse of software generally.
  15.437 +
  15.438 +			    NO WARRANTY
  15.439 +
  15.440 +  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
  15.441 +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
  15.442 +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
  15.443 +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
  15.444 +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
  15.445 +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  15.446 +PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
  15.447 +LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
  15.448 +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
  15.449 +
  15.450 +  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
  15.451 +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
  15.452 +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
  15.453 +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
  15.454 +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
  15.455 +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
  15.456 +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
  15.457 +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
  15.458 +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
  15.459 +DAMAGES.
  15.460 +
  15.461 +		     END OF TERMS AND CONDITIONS
  15.462 +
  15.463 +           How to Apply These Terms to Your New Libraries
  15.464 +
  15.465 +  If you develop a new library, and you want it to be of the greatest
  15.466 +possible use to the public, we recommend making it free software that
  15.467 +everyone can redistribute and change.  You can do so by permitting
  15.468 +redistribution under these terms (or, alternatively, under the terms of the
  15.469 +ordinary General Public License).
  15.470 +
  15.471 +  To apply these terms, attach the following notices to the library.  It is
  15.472 +safest to attach them to the start of each source file to most effectively
  15.473 +convey the exclusion of warranty; and each file should have at least the
  15.474 +"copyright" line and a pointer to where the full notice is found.
  15.475 +
  15.476 +    <one line to give the library's name and a brief idea of what it does.>
  15.477 +    Copyright (C) <year>  <name of author>
  15.478 +
  15.479 +    This library is free software; you can redistribute it and/or
  15.480 +    modify it under the terms of the GNU Lesser General Public
  15.481 +    License as published by the Free Software Foundation; either
  15.482 +    version 2.1 of the License, or (at your option) any later version.
  15.483 +
  15.484 +    This library is distributed in the hope that it will be useful,
  15.485 +    but WITHOUT ANY WARRANTY; without even the implied warranty of
  15.486 +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  15.487 +    Lesser General Public License for more details.
  15.488 +
  15.489 +    You should have received a copy of the GNU Lesser General Public
  15.490 +    License along with this library; if not, write to the Free Software
  15.491 +    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  15.492 +
  15.493 +Also add information on how to contact you by electronic and paper mail.
  15.494 +
  15.495 +You should also get your employer (if you work as a programmer) or your
  15.496 +school, if any, to sign a "copyright disclaimer" for the library, if
  15.497 +necessary.  Here is a sample; alter the names:
  15.498 +
  15.499 +  Yoyodyne, Inc., hereby disclaims all copyright interest in the
  15.500 +  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
  15.501 +
  15.502 +  <signature of Ty Coon>, 1 April 1990
  15.503 +  Ty Coon, President of Vice
  15.504 +
  15.505 +That's all there is to it!
  15.506 +
  15.507 +
    16.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    16.2 +++ b/readme.txt	Fri Oct 21 05:53:11 2011 -0700
    16.3 @@ -0,0 +1,86 @@
    16.4 +snes_spc 0.9.0: SNES SPC-700 APU Emulator
    16.5 +-----------------------------------------
    16.6 +This library includes a full SPC emulator and an S-DSP emulator that can
    16.7 +be used on its own. Two S-DSP emulators are available: a highly accurate
    16.8 +one for use in a SNES emulator, and a 3x faster one for use in an SPC
    16.9 +music player or a resource-limited SNES emulator.
   16.10 +
   16.11 +* Can be used from C and C++ code
   16.12 +* Full SPC-700 APU emulator with cycle accuracy in most cases
   16.13 +* Loads, plays, and saves SPC music files
   16.14 +* Can save and load exact full emulator state
   16.15 +* DSP voice muting, surround sound disable, and song tempo adjustment
   16.16 +* Uses 7% CPU average on 400 MHz Mac to play an SPC using fast DSP
   16.17 +
   16.18 +The accurate DSP emulator is based on past research by others and
   16.19 +hundreds of hours of recent research by me. It passes over a hundred
   16.20 +strenuous timing and behavior validation tests that were also run on the
   16.21 +SNES. As far as I know, it's the first DSP emulator with cycle accuracy,
   16.22 +properly emulating every DSP register and memory access at the exact SPC
   16.23 +cycle it occurs at, whereas previous DSP emulators emulated these only
   16.24 +to the nearest sample (which occurs every 32 clocks).
   16.25 +
   16.26 +Author : Shay Green <gblargg@gmail.com>
   16.27 +Website: http://www.slack.net/~ant/
   16.28 +Forum  : http://groups.google.com/group/blargg-sound-libs
   16.29 +License: GNU Lesser General Public License (LGPL)
   16.30 +
   16.31 +
   16.32 +Getting Started
   16.33 +---------------
   16.34 +Build a program consisting of demo/play_spc.c, demo/demo_util.c,
   16.35 +demo/wave_writer.c, and all source files in snes_spc/. Put an SPC music
   16.36 +file in the same directory and name it "test.spc". Running the program
   16.37 +should generate the recording "out.wav".
   16.38 +
   16.39 +Read snes_spc.txt for more information. Post to the discussion forum for
   16.40 +assistance.
   16.41 +
   16.42 +
   16.43 +Files
   16.44 +-----
   16.45 +snes_spc.txt            Documentation
   16.46 +changes.txt             Change log
   16.47 +license.txt             GNU LGPL license
   16.48 +
   16.49 +demo/
   16.50 +  play_spc.c            Records SPC file to wave sound file
   16.51 +  benchmark.c           Finds how fast emulator runs on your computer
   16.52 +  trim_spc.c            Trims silence off beginning of an SPC file
   16.53 +  save_state.c          Saves/loads exact emulator state to/from file
   16.54 +  comm.c                Communicates with SPC how SNES would
   16.55 +  demo_util.h           General utility functions used by demos
   16.56 +  demo_util.c
   16.57 +  wave_writer.h         WAVE sound file writer used for demo output
   16.58 +  wave_writer.c
   16.59 +
   16.60 +fast_dsp/               Optional standalone fast DSP emulator
   16.61 +  SPC_DSP.h             To use with full SPC emulator, move into
   16.62 +  SPC_DSP.cpp           snes_spc/ and replace original files
   16.63 +
   16.64 +snes_spc/               Library sources
   16.65 +  blargg_config.h       Configuration (modify as necessary)
   16.66 +  
   16.67 +  spc.h                 C interface to SPC emulator and sound filter
   16.68 +  spc.cpp
   16.69 +  
   16.70 +  SPC_Filter.h          Optional filter to make sound more authentic
   16.71 +  SPC_Filter.cpp
   16.72 +  
   16.73 +  SNES_SPC.h            Full SPC emulator
   16.74 +  SNES_SPC.cpp
   16.75 +  SNES_SPC_misc.cpp
   16.76 +  SNES_SPC_state.cpp
   16.77 +  SPC_CPU.h
   16.78 +  
   16.79 +  dsp.h                 C interface to DSP emulator
   16.80 +  dsp.cpp
   16.81 +  
   16.82 +  SPC_DSP.h             Standalone accurate DSP emulator
   16.83 +  SPC_DSP.cpp
   16.84 +  blargg_common.h
   16.85 +  blargg_endian.h
   16.86 +  blargg_source.h
   16.87 +
   16.88 +-- 
   16.89 +Shay Green <gblargg@gmail.com>
    17.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    17.2 +++ b/snes_spc.txt	Fri Oct 21 05:53:11 2011 -0700
    17.3 @@ -0,0 +1,318 @@
    17.4 +snes_spc 0.9.0: SNES SPC-700 APU Emulator
    17.5 +-----------------------------------------
    17.6 +Author : Shay Green <gblargg@gmail.com>
    17.7 +Website: http://www.slack.net/~ant/
    17.8 +Forum  : http://groups.google.com/group/blargg-sound-libs
    17.9 +License: GNU Lesser General Public License (LGPL)
   17.10 +
   17.11 +
   17.12 +Contents
   17.13 +--------
   17.14 +* C and C++ Interfaces
   17.15 +* Overview
   17.16 +* Full SPC Emulation
   17.17 +* DSP Emulation
   17.18 +* SPC Music Playback
   17.19 +* State Copying
   17.20 +* Library Compilation
   17.21 +* Error handling
   17.22 +* Solving Problems
   17.23 +* Accurate S-DSP Limitations
   17.24 +* Fast S-DSP Limitations
   17.25 +* S-SMP Limitations
   17.26 +* To Do
   17.27 +* Thanks
   17.28 +
   17.29 +
   17.30 +C and C++ Interfaces
   17.31 +--------------------
   17.32 +The library includes a C interface in spc.h and dsp.h, which can be used
   17.33 +from C and C++. This C interface is referred to in the following
   17.34 +documentation. If you're building this as a shared library (rather than
   17.35 +linking statically), you should use the C interface since it will change
   17.36 +less in future versions.
   17.37 +
   17.38 +The native C++ interface is in the header files SNES_SPC.h, SPC_DSP.h,
   17.39 +and SPC_Filter.h, and the two interfaces can be freely mixed in C++
   17.40 +code. Conversion between the two interfaces generally follows a pattern:
   17.41 +
   17.42 +	C interface                     C++ interface
   17.43 +	- - - - - - - - - - - - - - - - - - - - - - - - - - - - -
   17.44 +	SNES_SPC* spc;                  SNES_SPC* spc;
   17.45 +	
   17.46 +	spc = spc_new();                spc = new SNES_SPC;
   17.47 +	
   17.48 +	spc_play( spc, count, buf );    spc->play( count, buf );
   17.49 +	
   17.50 +	spc_sample_rate                 SNES_SPC::sample_rate
   17.51 +	
   17.52 +	spc_delete( spc );              delete spc;
   17.53 +
   17.54 +
   17.55 +Overview
   17.56 +--------
   17.57 +There are three main roles for this library:
   17.58 +* Full SPC emulation in a SNES emulator
   17.59 +* DSP emulation in a SNES emulator (where you emulate the SMP CPU)
   17.60 +* SPC playback in an SPC music file player
   17.61 +
   17.62 +Each of these uses are described separately below.
   17.63 +
   17.64 +
   17.65 +Full SPC Emulation
   17.66 +------------------
   17.67 +See spc.h for full function reference (SNES_SPC.h if using C++).
   17.68 +
   17.69 +* Create SPC emulator with spc_new() and check for NULL.
   17.70 +
   17.71 +* Call spc_init_rom() with a pointer to the 64-byte IPL ROM dump (not
   17.72 +included with library).
   17.73 +
   17.74 +* When your emulated SNES is powered on, call spc_reset(). When the
   17.75 +reset switch is pressed, call spc_soft_reset().
   17.76 +
   17.77 +* Call spc_set_output() with your output buffer, then do emulation.
   17.78 +
   17.79 +* When the SNES CPU accesses APU ports, call spc_read_port() and
   17.80 +spc_write_port().
   17.81 +
   17.82 +* When your emulator's timebase is going back to 0, call
   17.83 +spc_end_frame(), usually at the end of a video frame or scanline.
   17.84 +
   17.85 +* Periodically play samples from your buffer. Use spc_sample_count() to
   17.86 +find out how many samples have been written, then spc_set_output() after
   17.87 +you've made more space in your buffer.
   17.88 +
   17.89 +* Save/load full emulator state with spc_copy_state().
   17.90 +
   17.91 +* You can save as an SPC music file with spc_save_spc().
   17.92 +
   17.93 +* When done, use spc_delete() to free memory.
   17.94 +
   17.95 +
   17.96 +DSP Emulation
   17.97 +-------------
   17.98 +See dsp.h for full function reference (SPC_DSP.h if using C++).
   17.99 +
  17.100 +* Create DSP emulator with spc_dsp_new() and check for NULL.
  17.101 +
  17.102 +* Let the DSP know where your 64K RAM is with spc_dsp_init().
  17.103 +
  17.104 +* When your emulated SNES is powered on, call spc_dsp_reset(). When the
  17.105 +reset switch is pressed, call spc_dsp_soft_reset().
  17.106 +
  17.107 +* Call spc_dsp_set_output() with your output buffer, then do emulation.
  17.108 +
  17.109 +* Use spc_dsp_run() to run DSP for specified number of clocks (1024000
  17.110 +per second). Every 32 clocks a pair of samples is added to your output
  17.111 +buffer.
  17.112 +
  17.113 +* Use spc_dsp_read() and spc_dsp_write() to handle DSP reads/writes from
  17.114 +the S-SMP. Before calling these always catch the DSP up to present time
  17.115 +with spc_dsp_run().
  17.116 +
  17.117 +* Periodically play samples from your buffer. Use spc_dsp_sample_count()
  17.118 +to find out how many samples have been written, then
  17.119 +spc_dsp_set_output() after you've made more space in your buffer.
  17.120 +
  17.121 +* Use spc_dsp_copy_state() to save/load full DSP state.
  17.122 +
  17.123 +* When done, use spc_delete() to free memory.
  17.124 +
  17.125 +
  17.126 +SPC Music Playback
  17.127 +------------------
  17.128 +See spc.h for full function reference (SNES_SPC.h if using C++).
  17.129 +
  17.130 +* Create SPC emulator with spc_new() and check for NULL.
  17.131 +
  17.132 +* Load SPC with spc_load_spc() and check for error.
  17.133 +
  17.134 +* Optionally cear echo buffer with spc_clear_echo(). Many SPCs have
  17.135 +garbage in echo buffer, which causes noise at the beginning.
  17.136 +
  17.137 +* Generate samples as needed with spc_play().
  17.138 +
  17.139 +* When done, use spc_delete() to free memory.
  17.140 +
  17.141 +* For a more complete game music playback library, use Game_Music_Emu
  17.142 +
  17.143 +
  17.144 +State Copying
  17.145 +-------------
  17.146 +The SPC and DSP modules include state save/load functions. They take a
  17.147 +pointer to a pointer to a buffer to store state, and a copy function.
  17.148 +This copy function can either copy data to the buffer or from it,
  17.149 +allowing state save and restore with the same library function. The
  17.150 +internal save state format allows for future expansion without making
  17.151 +previous save states unusable.
  17.152 +
  17.153 +The SPC save state format puts the most important parts first to make it
  17.154 +easier to manually examine. It's organized as follows:
  17.155 +
  17.156 +Offset  Size    Data
  17.157 +- - - - - - - - - - - - - - - - - -
  17.158 +     0 $10000   SPC RAM
  17.159 +$10000    $10   SMP $F0-$FF registers
  17.160 +$10010      4   SMP $F4-$F8 output registers
  17.161 +$10014      2   PC
  17.162 +$10016      1   A
  17.163 +$10017      1   X
  17.164 +$10018      1   Y
  17.165 +$10019      1   PSW
  17.166 +$1001A      1   SP
  17.167 +$1001B      5   internal
  17.168 +$10020    $80   DSP registers
  17.169 +$100A0    ...   internal
  17.170 +
  17.171 +
  17.172 +Library Compilation
  17.173 +-------------------
  17.174 +While this library is in C++, it has been written to easily link in a C
  17.175 +program *without* needing the standard C++ library. It doesn't use
  17.176 +exception handling or run-time type information (RTTI), so you can
  17.177 +disable these in your C++ compiler to increase efficiency.
  17.178 +
  17.179 +If you're building a shared library (DLL), I recommend only exporting
  17.180 +the C interfaces in spc.h and dsp.h, as the C++ interfaces expose
  17.181 +implementation details that will break link compatibility across
  17.182 +versions.
  17.183 +
  17.184 +If you're using C and compiling with GCC, I recommend the following
  17.185 +command-line options when compiling the library source, otherwise GCC
  17.186 +will insert calls to the standard C++ library and require that it be
  17.187 +linked in:
  17.188 +
  17.189 +	-fno-rtti -fno-exceptions
  17.190 +
  17.191 +For maximum optimization, see the NDEBUG and BLARGG_NONPORTABLE options
  17.192 +in blargg_config. If using GCC, you can enable these by adding the
  17.193 +following command-line options when you invoke gcc. If you encounter
  17.194 +problems, try without -DBLARGG_NONPORTABLE; if that works, contact me so
  17.195 +I can figure out why BLARGG_NONPORTABLE was causing it to fail.
  17.196 +
  17.197 +	-O3 -DNDEBUG -DBLARGG_NONPORTABLE -fno-rtti -fno-exceptions
  17.198 +
  17.199 +
  17.200 +
  17.201 +Error handling
  17.202 +--------------
  17.203 +Functions which can fail have a return type of spc_err_t (blargg_err_t
  17.204 +in the C++ interfaces), which is a pointer to an error string (const
  17.205 +char*). If a function is successful it returns NULL. Errors that you can
  17.206 +easily avoid are checked with debug assertions; spc_err_t return values
  17.207 +are only used for genuine run-time errors that can't be easily predicted
  17.208 +in advance (out of memory, I/O errors, incompatible file data). Your
  17.209 +code should check all error values.
  17.210 +
  17.211 +To improve usability for C programmers, C++ programmers unfamiliar with
  17.212 +exceptions, and compatibility with older C++ compilers, the library does
  17.213 +*not* throw any C++ exceptions and uses malloc() instead of the standard
  17.214 +operator new. This means that you *must* check for NULL when creating a
  17.215 +library object with the new operator.
  17.216 +
  17.217 +
  17.218 +Solving Problems
  17.219 +----------------
  17.220 +If you're having problems, try the following:
  17.221 +
  17.222 +* If you're getting garbled sound, try this simple siren generator in
  17.223 +place of your call to play(). This will quickly tell whether the problem
  17.224 +is in the library or in your code.
  17.225 +
  17.226 +	static void play_siren( long count, short* out )
  17.227 +	{
  17.228 +		static double a, a2;
  17.229 +		while ( count-- )
  17.230 +			*out++ = 0x2000 * sin( a += .1 + .05*sin( a2+=.00005 ) );
  17.231 +	}
  17.232 +
  17.233 +* Enable debugging support in your environment. This enables assertions
  17.234 +and other run-time checks.
  17.235 +
  17.236 +* Turn the compiler's optimizer is off. Sometimes an optimizer generates
  17.237 +bad code.
  17.238 +
  17.239 +* If multiple threads are being used, ensure that only one at a time is
  17.240 +accessing a given set of objects from the library. This library is not
  17.241 +in general thread-safe, though independent objects can be used in
  17.242 +separate threads.
  17.243 +
  17.244 +* If all else fails, see if the demos work.
  17.245 +
  17.246 +
  17.247 +Accurate S-DSP Limitations
  17.248 +--------------------------
  17.249 +* Power-up and soft reset behavior might have slight inaccuracies.
  17.250 +
  17.251 +* Muting (FLG bit 6) behavior when toggling bit very rapidly is not
  17.252 +emulated properly.
  17.253 +
  17.254 +* No other known inaccuracies. Has passed 100+ strenuous tests.
  17.255 +
  17.256 +
  17.257 +Fast S-DSP Limitations
  17.258 +----------------------
  17.259 +* Uses faster sample calculations except in cases where exact value is
  17.260 +actually important (BRR decoding, and gaussian interpolation combined
  17.261 +with pitch modulation).
  17.262 +
  17.263 +* Stops decoding BRR data when a voice's envelope has released to
  17.264 +silence.
  17.265 +
  17.266 +* Emulates 32 clocks at a time, so DSP register and memory accesses are
  17.267 +all done in a bunch rather than spread out. Even though, some clever
  17.268 +code makes register accesses separated by 40 or so clocks occur with
  17.269 +cycle-accurate timing.
  17.270 +
  17.271 +
  17.272 +S-SMP Limitations
  17.273 +-----------------
  17.274 +* Opcode fetches and indirect pointers are always read directly from
  17.275 +memory, even for the $F0-$FF region, and the DSP is not caught up for
  17.276 +these fetches.
  17.277 +
  17.278 +* Attempts to perversely execute data in registers or an area being
  17.279 +modified by echo will not be emulated properly.
  17.280 +
  17.281 +* Has not been thoroughly tested.
  17.282 +
  17.283 +* Test register ($F0) is not implemented.
  17.284 +
  17.285 +* Echo buffer can overwrite IPL ROM area, and does not correctly update
  17.286 +extra RAM there.
  17.287 +
  17.288 +
  17.289 +To Do
  17.290 +-----
  17.291 +* I'd like feedback on the interface and any ways to improve it. In
  17.292 +particular, the differing features between the accurate and fast DSP
  17.293 +emulators might make it harder to cleanly switch between them without
  17.294 +modifying source code.
  17.295 +
  17.296 +* Finish thorough tests on SMP memory access times.
  17.297 +
  17.298 +* Finish thorough tests on SMP instruction behavior (flags, registers).
  17.299 +
  17.300 +* Finish thorough tests on SMP timers.
  17.301 +
  17.302 +* Finish power-up and reset behavior testing.
  17.303 +
  17.304 +* Come up with best starting conditions to play an SPC and implement in
  17.305 +hardware SNES SPC player for verification.
  17.306 +
  17.307 +
  17.308 +Thanks
  17.309 +------
  17.310 +Thanks to Anti-Resonance's SPC2ROM and help getting SPCs playing on my
  17.311 +SNES in the first place, then Brad Martin's openspc and Chris Moeller's
  17.312 +openspc++ C++ adaptation, giving me a good SPC emulator to start with
  17.313 +several years ago. Thanks to Richard Bannister, Mahendra Tallur, Shazz,
  17.314 +nenolod, theHobbit, Johan Samuelsson, nes6502, and Micket for helping
  17.315 +test my Game_Music_Emu library. Thanks to hcs for help in converting to
  17.316 +C for the Rockbox port. Thanks to byuu (bsnes author) and pagefault and
  17.317 +Nach (zsnes team) for testing and using my new rewritten DSP in their
  17.318 +emulators. Thanks to anomie for his good SNES documentation and
  17.319 +discussions with me to keep it up to date with my latest findings.
  17.320 +-- 
  17.321 +Shay Green <gblargg@gmail.com>
    18.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    18.2 +++ b/snes_spc/SNES_SPC.cpp	Fri Oct 21 05:53:11 2011 -0700
    18.3 @@ -0,0 +1,564 @@
    18.4 +// Core SPC emulation: CPU, timers, SMP registers, memory
    18.5 +
    18.6 +// snes_spc 0.9.0. http://www.slack.net/~ant/
    18.7 +
    18.8 +#include "SNES_SPC.h"
    18.9 +
   18.10 +#include <string.h>
   18.11 +
   18.12 +/* Copyright (C) 2004-2007 Shay Green. This module is free software; you
   18.13 +can redistribute it and/or modify it under the terms of the GNU Lesser
   18.14 +General Public License as published by the Free Software Foundation; either
   18.15 +version 2.1 of the License, or (at your option) any later version. This
   18.16 +module is distributed in the hope that it will be useful, but WITHOUT ANY
   18.17 +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   18.18 +FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
   18.19 +details. You should have received a copy of the GNU Lesser General Public
   18.20 +License along with this module; if not, write to the Free Software Foundation,
   18.21 +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
   18.22 +
   18.23 +#include "blargg_source.h"
   18.24 +
   18.25 +#define RAM         (m.ram.ram)
   18.26 +#define REGS        (m.smp_regs [0])
   18.27 +#define REGS_IN     (m.smp_regs [1])
   18.28 +
   18.29 +// (n ? n : 256)
   18.30 +#define IF_0_THEN_256( n ) ((uint8_t) ((n) - 1) + 1)
   18.31 +
   18.32 +// Note: SPC_MORE_ACCURACY exists mainly so I can run my validation tests, which
   18.33 +// do crazy echo buffer accesses.
   18.34 +#ifndef SPC_MORE_ACCURACY
   18.35 +	#define SPC_MORE_ACCURACY 0
   18.36 +#endif
   18.37 +
   18.38 +#ifdef BLARGG_ENABLE_OPTIMIZER
   18.39 +	#include BLARGG_ENABLE_OPTIMIZER
   18.40 +#endif
   18.41 +
   18.42 +
   18.43 +//// Timers
   18.44 +
   18.45 +#if SPC_DISABLE_TEMPO
   18.46 +	#define TIMER_DIV( t, n ) ((n) >> t->prescaler)
   18.47 +	#define TIMER_MUL( t, n ) ((n) << t->prescaler)
   18.48 +#else
   18.49 +	#define TIMER_DIV( t, n ) ((n) / t->prescaler)
   18.50 +	#define TIMER_MUL( t, n ) ((n) * t->prescaler)
   18.51 +#endif
   18.52 +
   18.53 +SNES_SPC::Timer* SNES_SPC::run_timer_( Timer* t, rel_time_t time )
   18.54 +{
   18.55 +	int elapsed = TIMER_DIV( t, time - t->next_time ) + 1;
   18.56 +	t->next_time += TIMER_MUL( t, elapsed );
   18.57 +	
   18.58 +	if ( t->enabled )
   18.59 +	{
   18.60 +		int remain = IF_0_THEN_256( t->period - t->divider );
   18.61 +		int divider = t->divider + elapsed;
   18.62 +		int over = elapsed - remain;
   18.63 +		if ( over >= 0 )
   18.64 +		{
   18.65 +			int n = over / t->period;
   18.66 +			t->counter = (t->counter + 1 + n) & 0x0F;
   18.67 +			divider = over - n * t->period;
   18.68 +		}
   18.69 +		t->divider = (uint8_t) divider;
   18.70 +	}
   18.71 +	return t;
   18.72 +}
   18.73 +
   18.74 +inline SNES_SPC::Timer* SNES_SPC::run_timer( Timer* t, rel_time_t time )
   18.75 +{
   18.76 +	if ( time >= t->next_time )
   18.77 +		t = run_timer_( t, time );
   18.78 +	return t;
   18.79 +}
   18.80 +
   18.81 +
   18.82 +//// ROM
   18.83 +
   18.84 +void SNES_SPC::enable_rom( int enable )
   18.85 +{
   18.86 +	if ( m.rom_enabled != enable )
   18.87 +	{
   18.88 +		m.rom_enabled = enable;
   18.89 +		if ( enable )
   18.90 +			memcpy( m.hi_ram, &RAM [rom_addr], sizeof m.hi_ram );
   18.91 +		memcpy( &RAM [rom_addr], (enable ? m.rom : m.hi_ram), rom_size );
   18.92 +		// TODO: ROM can still get overwritten when DSP writes to echo buffer
   18.93 +	}
   18.94 +}
   18.95 +
   18.96 +
   18.97 +//// DSP
   18.98 +
   18.99 +#if SPC_LESS_ACCURATE
  18.100 +	int const max_reg_time = 29;
  18.101 +	
  18.102 +	signed char const SNES_SPC::reg_times_ [256] =
  18.103 +	{
  18.104 +		 -1,  0,-11,-10,-15,-11, -2, -2,  4,  3, 14, 14, 26, 26, 14, 22,
  18.105 +		  2,  3,  0,  1,-12,  0,  1,  1,  7,  6, 14, 14, 27, 14, 14, 23,
  18.106 +		  5,  6,  3,  4, -1,  3,  4,  4, 10,  9, 14, 14, 26, -5, 14, 23,
  18.107 +		  8,  9,  6,  7,  2,  6,  7,  7, 13, 12, 14, 14, 27, -4, 14, 24,
  18.108 +		 11, 12,  9, 10,  5,  9, 10, 10, 16, 15, 14, 14, -2, -4, 14, 24,
  18.109 +		 14, 15, 12, 13,  8, 12, 13, 13, 19, 18, 14, 14, -2,-36, 14, 24,
  18.110 +		 17, 18, 15, 16, 11, 15, 16, 16, 22, 21, 14, 14, 28, -3, 14, 25,
  18.111 +		 20, 21, 18, 19, 14, 18, 19, 19, 25, 24, 14, 14, 14, 29, 14, 25,
  18.112 +		 
  18.113 +		 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
  18.114 +		 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
  18.115 +		 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
  18.116 +		 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
  18.117 +		 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
  18.118 +		 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
  18.119 +		 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
  18.120 +		 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
  18.121 +	};
  18.122 +	
  18.123 +	#define RUN_DSP( time, offset ) \
  18.124 +		int count = (time) - (offset) - m.dsp_time;\
  18.125 +		if ( count >= 0 )\
  18.126 +		{\
  18.127 +			int clock_count = (count & ~(clocks_per_sample - 1)) + clocks_per_sample;\
  18.128 +			m.dsp_time += clock_count;\
  18.129 +			dsp.run( clock_count );\
  18.130 +		}
  18.131 +#else
  18.132 +	#define RUN_DSP( time, offset ) \
  18.133 +		{\
  18.134 +			int count = (time) - m.dsp_time;\
  18.135 +			if ( !SPC_MORE_ACCURACY || count )\
  18.136 +			{\
  18.137 +				assert( count > 0 );\
  18.138 +				m.dsp_time = (time);\
  18.139 +				dsp.run( count );\
  18.140 +			}\
  18.141 +		}
  18.142 +#endif
  18.143 +
  18.144 +int SNES_SPC::dsp_read( rel_time_t time )
  18.145 +{
  18.146 +	RUN_DSP( time, reg_times [REGS [r_dspaddr] & 0x7F] );
  18.147 +	
  18.148 +	int result = dsp.read( REGS [r_dspaddr] & 0x7F );
  18.149 +	
  18.150 +	#ifdef SPC_DSP_READ_HOOK
  18.151 +		SPC_DSP_READ_HOOK( spc_time + time, (REGS [r_dspaddr] & 0x7F), result );
  18.152 +	#endif
  18.153 +	
  18.154 +	return result;
  18.155 +}
  18.156 +
  18.157 +inline void SNES_SPC::dsp_write( int data, rel_time_t time )
  18.158 +{
  18.159 +	RUN_DSP( time, reg_times [REGS [r_dspaddr]] )
  18.160 +	#if SPC_LESS_ACCURATE
  18.161 +		else if ( m.dsp_time == skipping_time )
  18.162 +		{
  18.163 +			int r = REGS [r_dspaddr];
  18.164 +			if ( r == SPC_DSP::r_kon )
  18.165 +				m.skipped_kon |= data & ~dsp.read( SPC_DSP::r_koff );
  18.166 +			
  18.167 +			if ( r == SPC_DSP::r_koff )
  18.168 +			{
  18.169 +				m.skipped_koff |= data;
  18.170 +				m.skipped_kon &= ~data;
  18.171 +			}
  18.172 +		}
  18.173 +	#endif
  18.174 +	
  18.175 +	#ifdef SPC_DSP_WRITE_HOOK
  18.176 +		SPC_DSP_WRITE_HOOK( m.spc_time + time, REGS [r_dspaddr], (uint8_t) data );
  18.177 +	#endif
  18.178 +	
  18.179 +	if ( REGS [r_dspaddr] <= 0x7F )
  18.180 +		dsp.write( REGS [r_dspaddr], data );
  18.181 +	else if ( !SPC_MORE_ACCURACY )
  18.182 +		dprintf( "SPC wrote to DSP register > $7F\n" );
  18.183 +}
  18.184 +
  18.185 +
  18.186 +//// Memory access extras
  18.187 +
  18.188 +#if SPC_MORE_ACCURACY
  18.189 +	#define MEM_ACCESS( time, addr ) \
  18.190 +	{\
  18.191 +		if ( time >= m.dsp_time )\
  18.192 +		{\
  18.193 +			RUN_DSP( time, max_reg_time );\
  18.194 +		}\
  18.195 +	}
  18.196 +#elif !defined (NDEBUG)
  18.197 +	// Debug-only check for read/write within echo buffer, since this might result in
  18.198 +	// inaccurate emulation due to the DSP not being caught up to the present.
  18.199 +	
  18.200 +	bool SNES_SPC::check_echo_access( int addr )
  18.201 +	{
  18.202 +		if ( !(dsp.read( SPC_DSP::r_flg ) & 0x20) )
  18.203 +		{
  18.204 +			int start = 0x100 * dsp.read( SPC_DSP::r_esa );
  18.205 +			int size  = 0x800 * (dsp.read( SPC_DSP::r_edl ) & 0x0F);
  18.206 +			int end   = start + (size ? size : 4);
  18.207 +			if ( start <= addr && addr < end )
  18.208 +			{
  18.209 +				if ( !m.echo_accessed )
  18.210 +				{
  18.211 +					m.echo_accessed = 1;
  18.212 +					return true;
  18.213 +				}
  18.214 +			}
  18.215 +		}
  18.216 +		return false;
  18.217 +	}
  18.218 +	
  18.219 +	#define MEM_ACCESS( time, addr ) check( !check_echo_access( (uint16_t) addr ) );
  18.220 +#else
  18.221 +	#define MEM_ACCESS( time, addr )
  18.222 +#endif
  18.223 +
  18.224 +
  18.225 +//// CPU write
  18.226 +
  18.227 +#if SPC_MORE_ACCURACY
  18.228 +static unsigned char const glitch_probs [3] [256] =
  18.229 +{
  18.230 +	0xC3,0x92,0x5B,0x1C,0xD1,0x92,0x5B,0x1C,0xDB,0x9C,0x72,0x18,0xCD,0x5C,0x38,0x0B,
  18.231 +	0xE1,0x9C,0x74,0x17,0xCF,0x75,0x45,0x0C,0xCF,0x6E,0x4A,0x0D,0xA3,0x3A,0x1D,0x08,
  18.232 +	0xDB,0xA0,0x82,0x19,0xD9,0x73,0x3C,0x0E,0xCB,0x76,0x52,0x0B,0xA5,0x46,0x1D,0x09,
  18.233 +	0xDA,0x74,0x55,0x0F,0xA2,0x3F,0x21,0x05,0x9A,0x40,0x20,0x07,0x63,0x1E,0x10,0x01,
  18.234 +	0xDF,0xA9,0x85,0x1D,0xD3,0x84,0x4B,0x0E,0xCF,0x6F,0x49,0x0F,0xB3,0x48,0x1E,0x05,
  18.235 +	0xD8,0x77,0x52,0x12,0xB7,0x49,0x23,0x06,0xAA,0x45,0x28,0x07,0x7D,0x28,0x0F,0x07,
  18.236 +	0xCC,0x7B,0x4A,0x0E,0xB2,0x4F,0x24,0x07,0xAD,0x43,0x2C,0x06,0x86,0x29,0x11,0x07,
  18.237 +	0xAE,0x48,0x1F,0x0A,0x76,0x21,0x19,0x05,0x76,0x21,0x14,0x05,0x44,0x11,0x0B,0x01,
  18.238 +	0xE7,0xAD,0x96,0x23,0xDC,0x86,0x59,0x0E,0xDC,0x7C,0x5F,0x15,0xBB,0x53,0x2E,0x09,
  18.239 +	0xD6,0x7C,0x4A,0x16,0xBB,0x4A,0x25,0x08,0xB3,0x4F,0x28,0x0B,0x8E,0x23,0x15,0x08,
  18.240 +	0xCF,0x7F,0x57,0x11,0xB5,0x4A,0x23,0x0A,0xAA,0x42,0x28,0x05,0x7D,0x22,0x12,0x03,
  18.241 +	0xA6,0x49,0x28,0x09,0x82,0x2B,0x0D,0x04,0x7A,0x20,0x0F,0x04,0x3D,0x0F,0x09,0x03,
  18.242 +	0xD1,0x7C,0x4C,0x0F,0xAF,0x4E,0x21,0x09,0xA8,0x46,0x2A,0x07,0x85,0x1F,0x0E,0x07,
  18.243 +	0xA6,0x3F,0x26,0x07,0x7C,0x24,0x14,0x07,0x78,0x22,0x16,0x04,0x46,0x12,0x0A,0x02,
  18.244 +	0xA6,0x41,0x2C,0x0A,0x7E,0x28,0x11,0x05,0x73,0x1B,0x14,0x05,0x3D,0x11,0x0A,0x02,
  18.245 +	0x70,0x22,0x17,0x05,0x48,0x13,0x08,0x03,0x3C,0x07,0x0D,0x07,0x26,0x07,0x06,0x01,
  18.246 +	
  18.247 +	0xE0,0x9F,0xDA,0x7C,0x4F,0x18,0x28,0x0D,0xE9,0x9F,0xDA,0x7C,0x4F,0x18,0x1F,0x07,
  18.248 +	0xE6,0x97,0xD8,0x72,0x64,0x13,0x26,0x09,0xDC,0x67,0xA9,0x38,0x21,0x07,0x15,0x06,
  18.249 +	0xE9,0x91,0xD2,0x6B,0x63,0x14,0x2B,0x0E,0xD6,0x61,0xB7,0x41,0x2B,0x0E,0x10,0x09,
  18.250 +	0xCF,0x59,0xB0,0x2F,0x35,0x08,0x0F,0x07,0xB6,0x30,0x7A,0x21,0x17,0x07,0x09,0x03,
  18.251 +	0xE7,0xA3,0xE5,0x6B,0x65,0x1F,0x34,0x09,0xD8,0x6B,0xBE,0x45,0x27,0x07,0x10,0x07,
  18.252 +	0xDA,0x54,0xB1,0x39,0x2E,0x0E,0x17,0x08,0xA9,0x3C,0x86,0x22,0x16,0x06,0x07,0x03,
  18.253 +	0xD4,0x51,0xBC,0x3D,0x38,0x0A,0x13,0x06,0xB2,0x37,0x79,0x1C,0x17,0x05,0x0E,0x06,
  18.254 +	0xA7,0x31,0x74,0x1C,0x11,0x06,0x0C,0x02,0x6D,0x1A,0x38,0x10,0x0B,0x05,0x06,0x03,
  18.255 +	0xEB,0x9A,0xE1,0x7A,0x6F,0x13,0x34,0x0E,0xE6,0x75,0xC5,0x45,0x3E,0x0B,0x1A,0x05,
  18.256 +	0xD8,0x63,0xC1,0x40,0x3C,0x1B,0x19,0x06,0xB3,0x42,0x83,0x29,0x18,0x0A,0x08,0x04,
  18.257 +	0xD4,0x58,0xBA,0x43,0x3F,0x0A,0x1F,0x09,0xB1,0x33,0x8A,0x1F,0x1F,0x06,0x0D,0x05,
  18.258 +	0xAF,0x3C,0x7A,0x1F,0x16,0x08,0x0A,0x01,0x72,0x1B,0x52,0x0D,0x0B,0x09,0x06,0x01,
  18.259 +	0xCF,0x63,0xB7,0x47,0x40,0x10,0x14,0x06,0xC0,0x41,0x96,0x20,0x1C,0x09,0x10,0x05,
  18.260 +	0xA6,0x35,0x82,0x1A,0x20,0x0C,0x0E,0x04,0x80,0x1F,0x53,0x0F,0x0B,0x02,0x06,0x01,
  18.261 +	0xA6,0x31,0x81,0x1B,0x1D,0x01,0x08,0x08,0x7B,0x20,0x4D,0x19,0x0E,0x05,0x07,0x03,
  18.262 +	0x6B,0x17,0x49,0x07,0x0E,0x03,0x0A,0x05,0x37,0x0B,0x1F,0x06,0x04,0x02,0x07,0x01,
  18.263 +	
  18.264 +	0xF0,0xD6,0xED,0xAD,0xEC,0xB1,0xEB,0x79,0xAC,0x22,0x47,0x1E,0x6E,0x1B,0x32,0x0A,
  18.265 +	0xF0,0xD6,0xEA,0xA4,0xED,0xC4,0xDE,0x82,0x98,0x1F,0x50,0x13,0x52,0x15,0x2A,0x0A,
  18.266 +	0xF1,0xD1,0xEB,0xA2,0xEB,0xB7,0xD8,0x69,0xA2,0x1F,0x5B,0x18,0x55,0x18,0x2C,0x0A,
  18.267 +	0xED,0xB5,0xDE,0x7E,0xE6,0x85,0xD3,0x59,0x59,0x0F,0x2C,0x09,0x24,0x07,0x15,0x09,
  18.268 +	0xF1,0xD6,0xEA,0xA0,0xEC,0xBB,0xDA,0x77,0xA9,0x23,0x58,0x14,0x5D,0x12,0x2F,0x09,
  18.269 +	0xF1,0xC1,0xE3,0x86,0xE4,0x87,0xD2,0x4E,0x68,0x15,0x26,0x0B,0x27,0x09,0x15,0x02,
  18.270 +	0xEE,0xA6,0xE0,0x5C,0xE0,0x77,0xC3,0x41,0x67,0x1B,0x3C,0x07,0x2A,0x06,0x19,0x07,
  18.271 +	0xE4,0x75,0xC6,0x43,0xCC,0x50,0x95,0x23,0x35,0x09,0x14,0x04,0x15,0x05,0x0B,0x04,
  18.272 +	0xEE,0xD6,0xED,0xAD,0xEC,0xB1,0xEB,0x79,0xAC,0x22,0x56,0x14,0x5A,0x12,0x26,0x0A,
  18.273 +	0xEE,0xBB,0xE7,0x7E,0xE9,0x8D,0xCB,0x49,0x67,0x11,0x34,0x07,0x2B,0x0B,0x14,0x07,
  18.274 +	0xED,0xA7,0xE5,0x76,0xE3,0x7E,0xC4,0x4B,0x77,0x14,0x34,0x08,0x27,0x07,0x14,0x04,
  18.275 +	0xE7,0x8B,0xD2,0x4C,0xCA,0x56,0x9E,0x31,0x36,0x0C,0x11,0x07,0x14,0x04,0x0A,0x02,
  18.276 +	0xF0,0x9B,0xEA,0x6F,0xE5,0x81,0xC4,0x43,0x74,0x10,0x30,0x0B,0x2D,0x08,0x1B,0x06,
  18.277 +	0xE6,0x83,0xCA,0x48,0xD9,0x56,0xA7,0x23,0x3B,0x09,0x12,0x09,0x15,0x07,0x0A,0x03,
  18.278 +	0xE5,0x5F,0xCB,0x3C,0xCF,0x48,0x91,0x22,0x31,0x0A,0x17,0x08,0x15,0x04,0x0D,0x02,
  18.279 +	0xD1,0x43,0x91,0x20,0xA9,0x2D,0x54,0x12,0x17,0x07,0x09,0x02,0x0C,0x04,0x05,0x03,
  18.280 +};
  18.281 +#endif
  18.282 +
  18.283 +// divided into multiple functions to keep rarely-used functionality separate
  18.284 +// so often-used functionality can be optimized better by compiler
  18.285 +
  18.286 +// If write isn't preceded by read, data has this added to it
  18.287 +int const no_read_before_write = 0x2000;
  18.288 +
  18.289 +void SNES_SPC::cpu_write_smp_reg_( int data, rel_time_t time, int addr )
  18.290 +{
  18.291 +	switch ( addr )
  18.292 +	{
  18.293 +	case r_t0target:
  18.294 +	case r_t1target:
  18.295 +	case r_t2target: {
  18.296 +		Timer* t = &m.timers [addr - r_t0target];
  18.297 +		int period = IF_0_THEN_256( data );
  18.298 +		if ( t->period != period )
  18.299 +		{
  18.300 +			t = run_timer( t, time );
  18.301 +			#if SPC_MORE_ACCURACY
  18.302 +				// Insane behavior when target is written just after counter is
  18.303 +				// clocked and counter matches new period and new period isn't 1, 2, 4, or 8
  18.304 +				if ( t->divider == (period & 0xFF) &&
  18.305 +						t->next_time == time + TIMER_MUL( t, 1 ) &&
  18.306 +						((period - 1) | ~0x0F) & period )
  18.307 +				{
  18.308 +					//dprintf( "SPC pathological timer target write\n" );
  18.309 +					
  18.310 +					// If the period is 3, 5, or 9, there's a probability this behavior won't occur,
  18.311 +					// based on the previous period
  18.312 +					int prob = 0xFF;
  18.313 +					int old_period = t->period & 0xFF;
  18.314 +					if ( period == 3 ) prob = glitch_probs [0] [old_period];
  18.315 +					if ( period == 5 ) prob = glitch_probs [1] [old_period];
  18.316 +					if ( period == 9 ) prob = glitch_probs [2] [old_period];
  18.317 +					
  18.318 +					// The glitch suppresses incrementing of one of the counter bits, based on
  18.319 +					// the lowest set bit in the new period
  18.320 +					int b = 1;
  18.321 +					while ( !(period & b) )
  18.322 +						b <<= 1;
  18.323 +					
  18.324 +					if ( (rand() >> 4 & 0xFF) <= prob )
  18.325 +						t->divider = (t->divider - b) & 0xFF;
  18.326 +				}
  18.327 +			#endif
  18.328 +			t->period = period;
  18.329 +		}
  18.330 +		break;
  18.331 +	}
  18.332 +	
  18.333 +	case r_t0out:
  18.334 +	case r_t1out:
  18.335 +	case r_t2out:
  18.336 +		if ( !SPC_MORE_ACCURACY )
  18.337 +			dprintf( "SPC wrote to counter %d\n", (int) addr - r_t0out );
  18.338 +		
  18.339 +		if ( data < no_read_before_write  / 2 )
  18.340 +			run_timer( &m.timers [addr - r_t0out], time - 1 )->counter = 0;
  18.341 +		break;
  18.342 +	
  18.343 +	// Registers that act like RAM
  18.344 +	case 0x8:
  18.345 +	case 0x9:
  18.346 +		REGS_IN [addr] = (uint8_t) data;
  18.347 +		break;
  18.348 +	
  18.349 +	case r_test:
  18.350 +		if ( (uint8_t) data != 0x0A )
  18.351 +			dprintf( "SPC wrote to test register\n" );
  18.352 +		break;
  18.353 +	
  18.354 +	case r_control:
  18.355 +		// port clears
  18.356 +		if ( data & 0x10 )
  18.357 +		{
  18.358 +			REGS_IN [r_cpuio0] = 0;
  18.359 +			REGS_IN [r_cpuio1] = 0;
  18.360 +		}
  18.361 +		if ( data & 0x20 )
  18.362 +		{
  18.363 +			REGS_IN [r_cpuio2] = 0;
  18.364 +			REGS_IN [r_cpuio3] = 0;
  18.365 +		}
  18.366 +		
  18.367 +		// timers
  18.368 +		{
  18.369 +			for ( int i = 0; i < timer_count; i++ )
  18.370 +			{
  18.371 +				Timer* t = &m.timers [i];
  18.372 +				int enabled = data >> i & 1;
  18.373 +				if ( t->enabled != enabled )
  18.374 +				{
  18.375 +					t = run_timer( t, time );
  18.376 +					t->enabled = enabled;
  18.377 +					if ( enabled )
  18.378 +					{
  18.379 +						t->divider = 0;
  18.380 +						t->counter = 0;
  18.381 +					}
  18.382 +				}
  18.383 +			}
  18.384 +		}
  18.385 +		enable_rom( data & 0x80 );
  18.386 +		break;
  18.387 +	}
  18.388 +}
  18.389 +
  18.390 +void SNES_SPC::cpu_write_smp_reg( int data, rel_time_t time, int addr )
  18.391 +{
  18.392 +	if ( addr == r_dspdata ) // 99%
  18.393 +		dsp_write( data, time );
  18.394 +	else
  18.395 +		cpu_write_smp_reg_( data, time, addr );
  18.396 +}
  18.397 +
  18.398 +void SNES_SPC::cpu_write_high( int data, int i, rel_time_t time )
  18.399 +{
  18.400 +	if ( i < rom_size )
  18.401 +	{
  18.402 +		m.hi_ram [i] = (uint8_t) data;
  18.403 +		if ( m.rom_enabled )
  18.404 +			RAM [i + rom_addr] = m.rom [i]; // restore overwritten ROM
  18.405 +	}
  18.406 +	else
  18.407 +	{
  18.408 +		assert( RAM [i + rom_addr] == (uint8_t) data );
  18.409 +		RAM [i + rom_addr] = cpu_pad_fill; // restore overwritten padding
  18.410 +		cpu_write( data, i + rom_addr - 0x10000, time );
  18.411 +	}
  18.412 +}
  18.413 +
  18.414 +int const bits_in_int = CHAR_BIT * sizeof (int);
  18.415 +
  18.416 +void SNES_SPC::cpu_write( int data, int addr, rel_time_t time )
  18.417 +{
  18.418 +	MEM_ACCESS( time, addr )
  18.419 +	
  18.420 +	// RAM
  18.421 +	RAM [addr] = (uint8_t) data;
  18.422 +	int reg = addr - 0xF0;
  18.423 +	if ( reg >= 0 ) // 64%
  18.424 +	{
  18.425 +		// $F0-$FF
  18.426 +		if ( reg < reg_count ) // 87%
  18.427 +		{
  18.428 +			REGS [reg] = (uint8_t) data;
  18.429 +			
  18.430 +			// Ports
  18.431 +			#ifdef SPC_PORT_WRITE_HOOK
  18.432 +				if ( (unsigned) (reg - r_cpuio0) < port_count )
  18.433 +					SPC_PORT_WRITE_HOOK( m.spc_time + time, (reg - r_cpuio0),
  18.434 +							(uint8_t) data, &REGS [r_cpuio0] );
  18.435 +			#endif
  18.436 +			
  18.437 +			// Registers other than $F2 and $F4-$F7
  18.438 +			//if ( reg != 2 && reg != 4 && reg != 5 && reg != 6 && reg != 7 )
  18.439 +			// TODO: this is a bit on the fragile side
  18.440 +			if ( ((~0x2F00 << (bits_in_int - 16)) << reg) < 0 ) // 36%
  18.441 +				cpu_write_smp_reg( data, time, reg );
  18.442 +		}
  18.443 +		// High mem/address wrap-around
  18.444 +		else
  18.445 +		{
  18.446 +			reg -= rom_addr - 0xF0;
  18.447 +			if ( reg >= 0 ) // 1% in IPL ROM area or address wrapped around
  18.448 +				cpu_write_high( data, reg, time );
  18.449 +		}
  18.450 +	}
  18.451 +}
  18.452 +
  18.453 +
  18.454 +//// CPU read
  18.455 +
  18.456 +inline int SNES_SPC::cpu_read_smp_reg( int reg, rel_time_t time )
  18.457 +{
  18.458 +	int result = REGS_IN [reg];
  18.459 +	reg -= r_dspaddr;
  18.460 +	// DSP addr and data
  18.461 +	if ( (unsigned) reg <= 1 ) // 4% 0xF2 and 0xF3
  18.462 +	{
  18.463 +		result = REGS [r_dspaddr];
  18.464 +		if ( (unsigned) reg == 1 )
  18.465 +			result = dsp_read( time ); // 0xF3
  18.466 +	}
  18.467 +	return result;
  18.468 +}
  18.469 +
  18.470 +int SNES_SPC::cpu_read( int addr, rel_time_t time )
  18.471 +{
  18.472 +	MEM_ACCESS( time, addr )
  18.473 +	
  18.474 +	// RAM
  18.475 +	int result = RAM [addr];
  18.476 +	int reg = addr - 0xF0;
  18.477 +	if ( reg >= 0 ) // 40%
  18.478 +	{
  18.479 +		reg -= 0x10;
  18.480 +		if ( (unsigned) reg >= 0xFF00 ) // 21%
  18.481 +		{
  18.482 +			reg += 0x10 - r_t0out;
  18.483 +			
  18.484 +			// Timers
  18.485 +			if ( (unsigned) reg < timer_count ) // 90%
  18.486 +			{
  18.487 +				Timer* t = &m.timers [reg];
  18.488 +				if ( time >= t->next_time )
  18.489 +					t = run_timer_( t, time );
  18.490 +				result = t->counter;
  18.491 +				t->counter = 0;
  18.492 +			}
  18.493 +			// Other registers
  18.494 +			else if ( reg < 0 ) // 10%
  18.495 +			{
  18.496 +				result = cpu_read_smp_reg( reg + r_t0out, time );
  18.497 +			}
  18.498 +			else // 1%
  18.499 +			{
  18.500 +				assert( reg + (r_t0out + 0xF0 - 0x10000) < 0x100 );
  18.501 +				result = cpu_read( reg + (r_t0out + 0xF0 - 0x10000), time );
  18.502 +			}
  18.503 +		}
  18.504 +	}
  18.505 +	
  18.506 +	return result;
  18.507 +}
  18.508 +
  18.509 +
  18.510 +//// Run
  18.511 +
  18.512 +// Prefix and suffix for CPU emulator function
  18.513 +#define SPC_CPU_RUN_FUNC \
  18.514 +BOOST::uint8_t* SNES_SPC::run_until_( time_t end_time )\
  18.515 +{\
  18.516 +	rel_time_t rel_time = m.spc_time - end_time;\
  18.517 +	assert( rel_time <= 0 );\
  18.518 +	m.spc_time = end_time;\
  18.519 +	m.dsp_time += rel_time;\
  18.520 +	m.timers [0].next_time += rel_time;\
  18.521 +	m.timers [1].next_time += rel_time;\
  18.522 +	m.timers [2].next_time += rel_time;
  18.523 +
  18.524 +#define SPC_CPU_RUN_FUNC_END \
  18.525 +	m.spc_time += rel_time;\
  18.526 +	m.dsp_time -= rel_time;\
  18.527 +	m.timers [0].next_time -= rel_time;\
  18.528 +	m.timers [1].next_time -= rel_time;\
  18.529 +	m.timers [2].next_time -= rel_time;\
  18.530 +	assert( m.spc_time <= end_time );\
  18.531 +	return &REGS [r_cpuio0];\
  18.532 +}
  18.533 +
  18.534 +int const cpu_lag_max = 12 - 1; // DIV YA,X takes 12 clocks
  18.535 +
  18.536 +void SNES_SPC::end_frame( time_t end_time )
  18.537 +{
  18.538 +	// Catch CPU up to as close to end as possible. If final instruction
  18.539 +	// would exceed end, does NOT execute it and leaves m.spc_time < end.
  18.540 +	if ( end_time > m.spc_time )
  18.541 +		run_until_( end_time );
  18.542 +	
  18.543 +	m.spc_time     -= end_time;
  18.544 +	m.extra_clocks += end_time;
  18.545 +	
  18.546 +	// Greatest number of clocks early that emulation can stop early due to
  18.547 +	// not being able to execute current instruction without going over
  18.548 +	// allowed time.
  18.549 +	assert( -cpu_lag_max <= m.spc_time && m.spc_time <= 0 );
  18.550 +	
  18.551 +	// Catch timers up to CPU
  18.552 +	for ( int i = 0; i < timer_count; i++ )
  18.553 +		run_timer( &m.timers [i], 0 );
  18.554 +	
  18.555 +	// Catch DSP up to CPU
  18.556 +	if ( m.dsp_time < 0 )
  18.557 +	{
  18.558 +		RUN_DSP( 0, max_reg_time );
  18.559 +	}
  18.560 +	
  18.561 +	// Save any extra samples beyond what should be generated
  18.562 +	if ( m.buf_begin )
  18.563 +		save_extra();
  18.564 +}
  18.565 +
  18.566 +// Inclusion here allows static memory access functions and better optimization
  18.567 +#include "SPC_CPU.h"
    19.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    19.2 +++ b/snes_spc/SNES_SPC.h	Fri Oct 21 05:53:11 2011 -0700
    19.3 @@ -0,0 +1,279 @@
    19.4 +// SNES SPC-700 APU emulator
    19.5 +
    19.6 +// snes_spc 0.9.0
    19.7 +#ifndef SNES_SPC_H
    19.8 +#define SNES_SPC_H
    19.9 +
   19.10 +#include "SPC_DSP.h"
   19.11 +#include "blargg_endian.h"
   19.12 +
   19.13 +struct SNES_SPC {
   19.14 +public:
   19.15 +	typedef BOOST::uint8_t uint8_t;
   19.16 +	
   19.17 +	// Must be called once before using
   19.18 +	blargg_err_t init();
   19.19 +	
   19.20 +	// Sample pairs generated per second
   19.21 +	enum { sample_rate = 32000 };
   19.22 +	
   19.23 +// Emulator use
   19.24 +	
   19.25 +	// Sets IPL ROM data. Library does not include ROM data. Most SPC music files
   19.26 +	// don't need ROM, but a full emulator must provide this.
   19.27 +	enum { rom_size = 0x40 };
   19.28 +	void init_rom( uint8_t const rom [rom_size] );
   19.29 +
   19.30 +	// Sets destination for output samples
   19.31 +	typedef short sample_t;
   19.32 +	void set_output( sample_t* out, int out_size );
   19.33 +
   19.34 +	// Number of samples written to output since last set
   19.35 +	int sample_count() const;
   19.36 +
   19.37 +	// Resets SPC to power-on state. This resets your output buffer, so you must
   19.38 +	// call set_output() after this.
   19.39 +	void reset();
   19.40 +
   19.41 +	// Emulates pressing reset switch on SNES. This resets your output buffer, so
   19.42 +	// you must call set_output() after this.
   19.43 +	void soft_reset();
   19.44 +
   19.45 +	// 1024000 SPC clocks per second, sample pair every 32 clocks
   19.46 +	typedef int time_t;
   19.47 +	enum { clock_rate = 1024000 };
   19.48 +	enum { clocks_per_sample = 32 };
   19.49 +	
   19.50 +	// Emulated port read/write at specified time
   19.51 +	enum { port_count = 4 };
   19.52 +	int  read_port ( time_t, int port );
   19.53 +	void write_port( time_t, int port, int data );
   19.54 +
   19.55 +	// Runs SPC to end_time and starts a new time frame at 0
   19.56 +	void end_frame( time_t end_time );
   19.57 +	
   19.58 +// Sound control
   19.59 +	
   19.60 +	// Mutes voices corresponding to non-zero bits in mask (issues repeated KOFF events).
   19.61 +	// Reduces emulation accuracy.
   19.62 +	enum { voice_count = 8 };
   19.63 +	void mute_voices( int mask );
   19.64 +	
   19.65 +	// If true, prevents channels and global volumes from being phase-negated.
   19.66 +	// Only supported by fast DSP.
   19.67 +	void disable_surround( bool disable = true );
   19.68 +	
   19.69 +	// Sets tempo, where tempo_unit = normal, tempo_unit / 2 = half speed, etc.
   19.70 +	enum { tempo_unit = 0x100 };
   19.71 +	void set_tempo( int );
   19.72 +
   19.73 +// SPC music files
   19.74 +
   19.75 +	// Loads SPC data into emulator
   19.76 +	enum { spc_min_file_size = 0x10180 };
   19.77 +	enum { spc_file_size     = 0x10200 };
   19.78 +	blargg_err_t load_spc( void const* in, long size );
   19.79 +	
   19.80 +	// Clears echo region. Useful after loading an SPC as many have garbage in echo.
   19.81 +	void clear_echo();
   19.82 +
   19.83 +	// Plays for count samples and write samples to out. Discards samples if out
   19.84 +	// is NULL. Count must be a multiple of 2 since output is stereo.
   19.85 +	blargg_err_t play( int count, sample_t* out );
   19.86 +	
   19.87 +	// Skips count samples. Several times faster than play() when using fast DSP.
   19.88 +	blargg_err_t skip( int count );
   19.89 +	
   19.90 +// State save/load (only available with accurate DSP)
   19.91 +
   19.92 +#if !SPC_NO_COPY_STATE_FUNCS
   19.93 +	// Saves/loads state
   19.94 +	enum { state_size = 67 * 1024L }; // maximum space needed when saving
   19.95 +	typedef SPC_DSP::copy_func_t copy_func_t;
   19.96 +	void copy_state( unsigned char** io, copy_func_t );
   19.97 +	
   19.98 +	// Writes minimal header to spc_out
   19.99 +	static void init_header( void* spc_out );
  19.100 +
  19.101 +	// Saves emulator state as SPC file data. Writes spc_file_size bytes to spc_out.
  19.102 +	// Does not set up SPC header; use init_header() for that.
  19.103 +	void save_spc( void* spc_out );
  19.104 +
  19.105 +	// Returns true if new key-on events occurred since last check. Useful for
  19.106 +	// trimming silence while saving an SPC.
  19.107 +	bool check_kon();
  19.108 +#endif
  19.109 +
  19.110 +public:
  19.111 +	BLARGG_DISABLE_NOTHROW
  19.112 +	
  19.113 +	typedef BOOST::uint16_t uint16_t;
  19.114 +	
  19.115 +	// Time relative to m_spc_time. Speeds up code a bit by eliminating need to
  19.116 +	// constantly add m_spc_time to time from CPU. CPU uses time that ends at
  19.117 +	// 0 to eliminate reloading end time every instruction. It pays off.
  19.118 +	typedef int rel_time_t;
  19.119 +	
  19.120 +	struct Timer
  19.121 +	{
  19.122 +		rel_time_t next_time; // time of next event
  19.123 +		int prescaler;
  19.124 +		int period;
  19.125 +		int divider;
  19.126 +		int enabled;
  19.127 +		int counter;
  19.128 +	};
  19.129 +	enum { reg_count = 0x10 };
  19.130 +	enum { timer_count = 3 };
  19.131 +	enum { extra_size = SPC_DSP::extra_size };
  19.132 +	
  19.133 +	enum { signature_size = 35 };
  19.134 +	
  19.135 +private:
  19.136 +	SPC_DSP dsp;
  19.137 +	
  19.138 +	#if SPC_LESS_ACCURATE
  19.139 +		static signed char const reg_times_ [256];
  19.140 +		signed char reg_times [256];
  19.141 +	#endif
  19.142 +	
  19.143 +	struct state_t
  19.144 +	{
  19.145 +		Timer timers [timer_count];
  19.146 +		
  19.147 +		uint8_t smp_regs [2] [reg_count];
  19.148 +		
  19.149 +		struct
  19.150 +		{
  19.151 +			int pc;
  19.152 +			int a;
  19.153 +			int x;
  19.154 +			int y;
  19.155 +			int psw;
  19.156 +			int sp;
  19.157 +		} cpu_regs;
  19.158 +		
  19.159 +		rel_time_t  dsp_time;
  19.160 +		time_t      spc_time;
  19.161 +		bool        echo_accessed;
  19.162 +		
  19.163 +		int         tempo;
  19.164 +		int         skipped_kon;
  19.165 +		int         skipped_koff;
  19.166 +		const char* cpu_error;
  19.167 +		
  19.168 +		int         extra_clocks;
  19.169 +		sample_t*   buf_begin;
  19.170 +		sample_t const* buf_end;
  19.171 +		sample_t*   extra_pos;
  19.172 +		sample_t    extra_buf [extra_size];
  19.173 +		
  19.174 +		int         rom_enabled;
  19.175 +		uint8_t     rom    [rom_size];
  19.176 +		uint8_t     hi_ram [rom_size];
  19.177 +		
  19.178 +		unsigned char cycle_table [256];
  19.179 +		
  19.180 +		struct
  19.181 +		{
  19.182 +			// padding to neutralize address overflow
  19.183 +			union {
  19.184 +				uint8_t padding1 [0x100];
  19.185 +				uint16_t align; // makes compiler align data for 16-bit access
  19.186 +			} padding1 [1];
  19.187 +			uint8_t ram      [0x10000];
  19.188 +			uint8_t padding2 [0x100];
  19.189 +		} ram;
  19.190 +	};
  19.191 +	state_t m;
  19.192 +	
  19.193 +	enum { rom_addr = 0xFFC0 };
  19.194 +	
  19.195 +	enum { skipping_time = 127 };
  19.196 +	
  19.197 +	// Value that padding should be filled with
  19.198 +	enum { cpu_pad_fill = 0xFF };
  19.199 +	
  19.200 +	enum {
  19.201 +        r_test     = 0x0, r_control  = 0x1,
  19.202 +        r_dspaddr  = 0x2, r_dspdata  = 0x3,
  19.203 +        r_cpuio0   = 0x4, r_cpuio1   = 0x5,
  19.204 +        r_cpuio2   = 0x6, r_cpuio3   = 0x7,
  19.205 +        r_f8       = 0x8, r_f9       = 0x9,
  19.206 +        r_t0target = 0xA, r_t1target = 0xB, r_t2target = 0xC,
  19.207 +        r_t0out    = 0xD, r_t1out    = 0xE, r_t2out    = 0xF
  19.208 +	};
  19.209 +	
  19.210 +	void timers_loaded();
  19.211 +	void enable_rom( int enable );
  19.212 +	void reset_buf();
  19.213 +	void save_extra();
  19.214 +	void load_regs( uint8_t const in [reg_count] );
  19.215 +	void ram_loaded();
  19.216 +	void regs_loaded();
  19.217 +	void reset_time_regs();
  19.218 +	void reset_common( int timer_counter_init );
  19.219 +	
  19.220 +	Timer* run_timer_      ( Timer* t, rel_time_t );
  19.221 +	Timer* run_timer       ( Timer* t, rel_time_t );
  19.222 +	int dsp_read           ( rel_time_t );
  19.223 +	void dsp_write         ( int data, rel_time_t );
  19.224 +	void cpu_write_smp_reg_( int data, rel_time_t, int addr );
  19.225 +	void cpu_write_smp_reg ( int data, rel_time_t, int addr );
  19.226 +	void cpu_write_high    ( int data, int i, rel_time_t );
  19.227 +	void cpu_write         ( int data, int addr, rel_time_t );
  19.228 +	int cpu_read_smp_reg   ( int i, rel_time_t );
  19.229 +	int cpu_read           ( int addr, rel_time_t );
  19.230 +	unsigned CPU_mem_bit   ( uint8_t const* pc, rel_time_t );
  19.231 +	
  19.232 +	bool check_echo_access ( int addr );
  19.233 +	uint8_t* run_until_( time_t end_time );
  19.234 +	
  19.235 +	struct spc_file_t
  19.236 +	{
  19.237 +		char    signature [signature_size];
  19.238 +		uint8_t has_id666;
  19.239 +		uint8_t version;
  19.240 +		uint8_t pcl, pch;
  19.241 +		uint8_t a;
  19.242 +		uint8_t x;
  19.243 +		uint8_t y;
  19.244 +		uint8_t psw;
  19.245 +		uint8_t sp;
  19.246 +		char    text [212];
  19.247 +		uint8_t ram [0x10000];
  19.248 +		uint8_t dsp [128];
  19.249 +		uint8_t unused [0x40];
  19.250 +		uint8_t ipl_rom [0x40];
  19.251 +	};
  19.252 +
  19.253 +	static char const signature [signature_size + 1];
  19.254 +	
  19.255 +	void save_regs( uint8_t out [reg_count] );
  19.256 +};
  19.257 +
  19.258 +#include <assert.h>
  19.259 +
  19.260 +inline int SNES_SPC::sample_count() const { return (m.extra_clocks >> 5) * 2; }
  19.261 +
  19.262 +inline int SNES_SPC::read_port( time_t t, int port )
  19.263 +{
  19.264 +	assert( (unsigned) port < port_count );
  19.265 +	return run_until_( t ) [port];
  19.266 +}
  19.267 +
  19.268 +inline void SNES_SPC::write_port( time_t t, int port, int data )
  19.269 +{
  19.270 +	assert( (unsigned) port < port_count );
  19.271 +	run_until_( t ) [0x10 + port] = data;
  19.272 +}
  19.273 +
  19.274 +inline void SNES_SPC::mute_voices( int mask ) { dsp.mute_voices( mask ); }
  19.275 +	
  19.276 +inline void SNES_SPC::disable_surround( bool disable ) { dsp.disable_surround( disable ); }
  19.277 +
  19.278 +#if !SPC_NO_COPY_STATE_FUNCS
  19.279 +inline bool SNES_SPC::check_kon() { return dsp.check_kon(); }
  19.280 +#endif
  19.281 +
  19.282 +#endif
    20.1 Binary file snes_spc/SNES_SPC.h.gch has changed
    21.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    21.2 +++ b/snes_spc/SNES_SPC_misc.cpp	Fri Oct 21 05:53:11 2011 -0700
    21.3 @@ -0,0 +1,380 @@
    21.4 +// SPC emulation support: init, sample buffering, reset, SPC loading
    21.5 +
    21.6 +// snes_spc 0.9.0. http://www.slack.net/~ant/
    21.7 +
    21.8 +#include "SNES_SPC.h"
    21.9 +
   21.10 +#include <string.h>
   21.11 +
   21.12 +/* Copyright (C) 2004-2007 Shay Green. This module is free software; you
   21.13 +can redistribute it and/or modify it under the terms of the GNU Lesser
   21.14 +General Public License as published by the Free Software Foundation; either
   21.15 +version 2.1 of the License, or (at your option) any later version. This
   21.16 +module is distributed in the hope that it will be useful, but WITHOUT ANY
   21.17 +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   21.18 +FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
   21.19 +details. You should have received a copy of the GNU Lesser General Public
   21.20 +License along with this module; if not, write to the Free Software Foundation,
   21.21 +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
   21.22 +
   21.23 +#include "blargg_source.h"
   21.24 +
   21.25 +#define RAM         (m.ram.ram)
   21.26 +#define REGS        (m.smp_regs [0])
   21.27 +#define REGS_IN     (m.smp_regs [1])
   21.28 +
   21.29 +// (n ? n : 256)
   21.30 +#define IF_0_THEN_256( n ) ((uint8_t) ((n) - 1) + 1)
   21.31 +
   21.32 +
   21.33 +//// Init
   21.34 +
   21.35 +blargg_err_t SNES_SPC::init()
   21.36 +{
   21.37 +	memset( &m, 0, sizeof m );
   21.38 +	dsp.init( RAM );
   21.39 +	
   21.40 +	m.tempo = tempo_unit;
   21.41 +	
   21.42 +	// Most SPC music doesn't need ROM, and almost all the rest only rely
   21.43 +	// on these two bytes
   21.44 +	m.rom [0x3E] = 0xFF;
   21.45 +	m.rom [0x3F] = 0xC0;
   21.46 +	
   21.47 +	static unsigned char const cycle_table [128] =
   21.48 +	{//   01   23   45   67   89   AB   CD   EF
   21.49 +	    0x28,0x47,0x34,0x36,0x26,0x54,0x54,0x68, // 0
   21.50 +	    0x48,0x47,0x45,0x56,0x55,0x65,0x22,0x46, // 1
   21.51 +	    0x28,0x47,0x34,0x36,0x26,0x54,0x54,0x74, // 2
   21.52 +	    0x48,0x47,0x45,0x56,0x55,0x65,0x22,0x38, // 3
   21.53 +	    0x28,0x47,0x34,0x36,0x26,0x44,0x54,0x66, // 4
   21.54 +	    0x48,0x47,0x45,0x56,0x55,0x45,0x22,0x43, // 5
   21.55 +	    0x28,0x47,0x34,0x36,0x26,0x44,0x54,0x75, // 6
   21.56 +	    0x48,0x47,0x45,0x56,0x55,0x55,0x22,0x36, // 7
   21.57 +	    0x28,0x47,0x34,0x36,0x26,0x54,0x52,0x45, // 8
   21.58 +	    0x48,0x47,0x45,0x56,0x55,0x55,0x22,0xC5, // 9
   21.59 +	    0x38,0x47,0x34,0x36,0x26,0x44,0x52,0x44, // A
   21.60 +	    0x48,0x47,0x45,0x56,0x55,0x55,0x22,0x34, // B
   21.61 +	    0x38,0x47,0x45,0x47,0x25,0x64,0x52,0x49, // C
   21.62 +	    0x48,0x47,0x56,0x67,0x45,0x55,0x22,0x83, // D
   21.63 +	    0x28,0x47,0x34,0x36,0x24,0x53,0x43,0x40, // E
   21.64 +	    0x48,0x47,0x45,0x56,0x34,0x54,0x22,0x60, // F
   21.65 +	};
   21.66 +	
   21.67 +	// unpack cycle table
   21.68 +	for ( int i = 0; i < 128; i++ )
   21.69 +	{
   21.70 +		int n = cycle_table [i];
   21.71 +		m.cycle_table [i * 2 + 0] = n >> 4;
   21.72 +		m.cycle_table [i * 2 + 1] = n & 0x0F;
   21.73 +	}
   21.74 +	
   21.75 +	#if SPC_LESS_ACCURATE
   21.76 +		memcpy( reg_times, reg_times_, sizeof reg_times );
   21.77 +	#endif
   21.78 +	
   21.79 +	reset();
   21.80 +	return 0;
   21.81 +}
   21.82 +
   21.83 +void SNES_SPC::init_rom( uint8_t const in [rom_size] )
   21.84 +{
   21.85 +	memcpy( m.rom, in, sizeof m.rom );
   21.86 +}
   21.87 +
   21.88 +void SNES_SPC::set_tempo( int t )
   21.89 +{
   21.90 +	m.tempo = t;
   21.91 +	int const timer2_shift = 4; // 64 kHz
   21.92 +	int const other_shift  = 3; //  8 kHz
   21.93 +	
   21.94 +	#if SPC_DISABLE_TEMPO
   21.95 +		m.timers [2].prescaler = timer2_shift;
   21.96 +		m.timers [1].prescaler = timer2_shift + other_shift;
   21.97 +		m.timers [0].prescaler = timer2_shift + other_shift;
   21.98 +	#else
   21.99 +		if ( !t )
  21.100 +			t = 1;
  21.101 +		int const timer2_rate  = 1 << timer2_shift;
  21.102 +		int rate = (timer2_rate * tempo_unit + (t >> 1)) / t;
  21.103 +		if ( rate < timer2_rate / 4 )
  21.104 +			rate = timer2_rate / 4; // max 4x tempo
  21.105 +		m.timers [2].prescaler = rate;
  21.106 +		m.timers [1].prescaler = rate << other_shift;
  21.107 +		m.timers [0].prescaler = rate << other_shift;
  21.108 +	#endif
  21.109 +}
  21.110 +
  21.111 +// Timer registers have been loaded. Applies these to the timers. Does not
  21.112 +// reset timer prescalers or dividers.
  21.113 +void SNES_SPC::timers_loaded()
  21.114 +{
  21.115 +	int i;
  21.116 +	for ( i = 0; i < timer_count; i++ )
  21.117 +	{
  21.118 +		Timer* t = &m.timers [i];
  21.119 +		t->period  = IF_0_THEN_256( REGS [r_t0target + i] );
  21.120 +		t->enabled = REGS [r_control] >> i & 1;
  21.121 +		t->counter = REGS_IN [r_t0out + i] & 0x0F;
  21.122 +	}
  21.123 +	
  21.124 +	set_tempo( m.tempo );
  21.125 +}
  21.126 +
  21.127 +// Loads registers from unified 16-byte format
  21.128 +void SNES_SPC::load_regs( uint8_t const in [reg_count] )
  21.129 +{
  21.130 +	memcpy( REGS, in, reg_count );
  21.131 +	memcpy( REGS_IN, REGS, reg_count );
  21.132 +	
  21.133 +	// These always read back as 0
  21.134 +	REGS_IN [r_test    ] = 0;
  21.135 +	REGS_IN [r_control ] = 0;
  21.136 +	REGS_IN [r_t0target] = 0;
  21.137 +	REGS_IN [r_t1target] = 0;
  21.138 +	REGS_IN [r_t2target] = 0;
  21.139 +}
  21.140 +
  21.141 +// RAM was just loaded from SPC, with $F0-$FF containing SMP registers
  21.142 +// and timer counts. Copies these to proper registers.
  21.143 +void SNES_SPC::ram_loaded()
  21.144 +{
  21.145 +	m.rom_enabled = 0;
  21.146 +	load_regs( &RAM [0xF0] );
  21.147 +	
  21.148 +	// Put STOP instruction around memory to catch PC underflow/overflow
  21.149 +	memset( m.ram.padding1, cpu_pad_fill, sizeof m.ram.padding1 );
  21.150 +	memset( m.ram.padding2, cpu_pad_fill, sizeof m.ram.padding2 );
  21.151 +}
  21.152 +
  21.153 +// Registers were just loaded. Applies these new values.
  21.154 +void SNES_SPC::regs_loaded()
  21.155 +{
  21.156 +	enable_rom( REGS [r_control] & 0x80 );
  21.157 +	timers_loaded();
  21.158 +}
  21.159 +
  21.160 +void SNES_SPC::reset_time_regs()
  21.161 +{
  21.162 +	m.cpu_error     = 0;
  21.163 +	m.echo_accessed = 0;
  21.164 +	m.spc_time      = 0;
  21.165 +	m.dsp_time      = 0;
  21.166 +	#if SPC_LESS_ACCURATE
  21.167 +		m.dsp_time = clocks_per_sample + 1;
  21.168 +	#endif
  21.169 +	
  21.170 +	for ( int i = 0; i < timer_count; i++ )
  21.171 +	{
  21.172 +		Timer* t = &m.timers [i];
  21.173 +		t->next_time = 1;
  21.174 +		t->divider   = 0;
  21.175 +	}
  21.176 +	
  21.177 +	regs_loaded();
  21.178 +	
  21.179 +	m.extra_clocks = 0;
  21.180 +	reset_buf();
  21.181 +}
  21.182 +
  21.183 +void SNES_SPC::reset_common( int timer_counter_init )
  21.184 +{
  21.185 +	int i;
  21.186 +	for ( i = 0; i < timer_count; i++ )
  21.187 +		REGS_IN [r_t0out + i] = timer_counter_init;
  21.188 +	
  21.189 +	// Run IPL ROM
  21.190 +	memset( &m.cpu_regs, 0, sizeof m.cpu_regs );
  21.191 +	m.cpu_regs.pc = rom_addr;
  21.192 +	
  21.193 +	REGS [r_test   ] = 0x0A;
  21.194 +	REGS [r_control] = 0xB0; // ROM enabled, clear ports
  21.195 +	for ( i = 0; i < port_count; i++ )
  21.196 +		REGS_IN [r_cpuio0 + i] = 0;
  21.197 +	
  21.198 +	reset_time_regs();
  21.199 +}
  21.200 +
  21.201 +void SNES_SPC::soft_reset()
  21.202 +{
  21.203 +	reset_common( 0 );
  21.204 +	dsp.soft_reset();
  21.205 +}
  21.206 +
  21.207 +void SNES_SPC::reset()
  21.208 +{
  21.209 +	memset( RAM, 0xFF, 0x10000 );
  21.210 +	ram_loaded();
  21.211 +	reset_common( 0x0F );
  21.212 +	dsp.reset();
  21.213 +}
  21.214 +
  21.215 +char const SNES_SPC::signature [signature_size + 1] =
  21.216 +		"SNES-SPC700 Sound File Data v0.30\x1A\x1A";
  21.217 +
  21.218 +blargg_err_t SNES_SPC::load_spc( void const* data, long size )
  21.219 +{
  21.220 +	spc_file_t const* const spc = (spc_file_t const*) data;
  21.221 +	
  21.222 +	// be sure compiler didn't insert any padding into fle_t
  21.223 +	assert( sizeof (spc_file_t) == spc_min_file_size + 0x80 );
  21.224 +	
  21.225 +	// Check signature and file size
  21.226 +	if ( size < signature_size || memcmp( spc, signature, 27 ) )
  21.227 +		return "Not an SPC file";
  21.228 +	
  21.229 +	if ( size < spc_min_file_size )
  21.230 +		return "Corrupt SPC file";
  21.231 +	
  21.232 +	// CPU registers
  21.233 +	m.cpu_regs.pc  = spc->pch * 0x100 + spc->pcl;
  21.234 +	m.cpu_regs.a   = spc->a;
  21.235 +	m.cpu_regs.x   = spc->x;
  21.236 +	m.cpu_regs.y   = spc->y;
  21.237 +	m.cpu_regs.psw = spc->psw;
  21.238 +	m.cpu_regs.sp  = spc->sp;
  21.239 +	
  21.240 +	// RAM and registers
  21.241 +	memcpy( RAM, spc->ram, 0x10000 );
  21.242 +	ram_loaded();
  21.243 +	
  21.244 +	// DSP registers
  21.245 +	dsp.load( spc->dsp );
  21.246 +	
  21.247 +	reset_time_regs();
  21.248 +	
  21.249 +	return 0;
  21.250 +}
  21.251 +
  21.252 +void SNES_SPC::clear_echo()
  21.253 +{
  21.254 +	if ( !(dsp.read( SPC_DSP::r_flg ) & 0x20) )
  21.255 +	{
  21.256 +		int addr = 0x100 * dsp.read( SPC_DSP::r_esa );
  21.257 +		int end  = addr + 0x800 * (dsp.read( SPC_DSP::r_edl ) & 0x0F);
  21.258 +		if ( end > 0x10000 )
  21.259 +			end = 0x10000;
  21.260 +		memset( &RAM [addr], 0xFF, end - addr );
  21.261 +	}
  21.262 +}
  21.263 +
  21.264 +
  21.265 +//// Sample output
  21.266 +
  21.267 +void SNES_SPC::reset_buf()
  21.268 +{
  21.269 +	// Start with half extra buffer of silence
  21.270 +	sample_t* out = m.extra_buf;
  21.271 +	while ( out < &m.extra_buf [extra_size / 2] )
  21.272 +		*out++ = 0;
  21.273 +	
  21.274 +	m.extra_pos = out;
  21.275 +	m.buf_begin = 0;
  21.276 +	
  21.277 +	dsp.set_output( 0, 0 );
  21.278 +}
  21.279 +
  21.280 +void SNES_SPC::set_output( sample_t* out, int size )
  21.281 +{
  21.282 +	require( (size & 1) == 0 ); // size must be even
  21.283 +	
  21.284 +	m.extra_clocks &= clocks_per_sample - 1;
  21.285 +	if ( out )
  21.286 +	{
  21.287 +		sample_t const* out_end = out + size;
  21.288 +		m.buf_begin = out;
  21.289 +		m.buf_end   = out_end;
  21.290 +		
  21.291 +		// Copy extra to output
  21.292 +		sample_t const* in = m.extra_buf;
  21.293 +		while ( in < m.extra_pos && out < out_end )
  21.294 +			*out++ = *in++;
  21.295 +		
  21.296 +		// Handle output being full already
  21.297 +		if ( out >= out_end )
  21.298 +		{
  21.299 +			// Have DSP write to remaining extra space
  21.300 +			out     = dsp.extra();
  21.301 +			out_end = &dsp.extra() [extra_size];
  21.302 +			
  21.303 +			// Copy any remaining extra samples as if DSP wrote them
  21.304 +			while ( in < m.extra_pos )
  21.305 +				*out++ = *in++;
  21.306 +			assert( out <= out_end );
  21.307 +		}
  21.308 +		
  21.309 +		dsp.set_output( out, out_end - out );
  21.310 +	}
  21.311 +	else
  21.312 +	{
  21.313 +		reset_buf();
  21.314 +	}
  21.315 +}
  21.316 +
  21.317 +void SNES_SPC::save_extra()
  21.318 +{
  21.319 +	// Get end pointers
  21.320 +	sample_t const* main_end = m.buf_end;     // end of data written to buf
  21.321 +	sample_t const* dsp_end  = dsp.out_pos(); // end of data written to dsp.extra()
  21.322 +	if ( m.buf_begin <= dsp_end && dsp_end <= main_end )
  21.323 +	{
  21.324 +		main_end = dsp_end;
  21.325 +		dsp_end  = dsp.extra(); // nothing in DSP's extra
  21.326 +	}
  21.327 +	
  21.328 +	// Copy any extra samples at these ends into extra_buf
  21.329 +	sample_t* out = m.extra_buf;
  21.330 +	sample_t const* in;
  21.331 +	for ( in = m.buf_begin + sample_count(); in < main_end; in++ )
  21.332 +		*out++ = *in;
  21.333 +	for ( in = dsp.extra(); in < dsp_end ; in++ )
  21.334 +		*out++ = *in;
  21.335 +	
  21.336 +	m.extra_pos = out;
  21.337 +	assert( out <= &m.extra_buf [extra_size] );
  21.338 +}
  21.339 +
  21.340 +blargg_err_t SNES_SPC::play( int count, sample_t* out )
  21.341 +{
  21.342 +	require( (count & 1) == 0 ); // must be even
  21.343 +	if ( count )
  21.344 +	{
  21.345 +		set_output( out, count );
  21.346 +		end_frame( count * (clocks_per_sample / 2) );
  21.347 +	}
  21.348 +	
  21.349 +	const char* err = m.cpu_error;
  21.350 +	m.cpu_error = 0;
  21.351 +	return err;
  21.352 +}
  21.353 +
  21.354 +blargg_err_t SNES_SPC::skip( int count )
  21.355 +{
  21.356 +	#if SPC_LESS_ACCURATE
  21.357 +	if ( count > 2 * sample_rate * 2 )
  21.358 +	{
  21.359 +		set_output( 0, 0 );
  21.360 +		
  21.361 +		// Skip a multiple of 4 samples
  21.362 +		time_t end = count;
  21.363 +		count = (count & 3) + 1 * sample_rate * 2;
  21.364 +		end = (end - count) * (clocks_per_sample / 2);
  21.365 +		
  21.366 +		m.skipped_kon  = 0;
  21.367 +		m.skipped_koff = 0;
  21.368 +		
  21.369 +		// Preserve DSP and timer synchronization
  21.370 +		// TODO: verify that this really preserves it
  21.371 +		int old_dsp_time = m.dsp_time + m.spc_time;
  21.372 +		m.dsp_time = end - m.spc_time + skipping_time;
  21.373 +		end_frame( end );
  21.374 +		m.dsp_time = m.dsp_time - skipping_time + old_dsp_time;
  21.375 +		
  21.376 +		dsp.write( SPC_DSP::r_koff, m.skipped_koff & ~m.skipped_kon );
  21.377 +		dsp.write( SPC_DSP::r_kon , m.skipped_kon );
  21.378 +		clear_echo();
  21.379 +	}
  21.380 +	#endif
  21.381 +	
  21.382 +	return play( count, 0 );
  21.383 +}
    22.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    22.2 +++ b/snes_spc/SNES_SPC_state.cpp	Fri Oct 21 05:53:11 2011 -0700
    22.3 @@ -0,0 +1,129 @@
    22.4 +// SPC emulation state save/load: copy_state(), save_spc()
    22.5 +// Separate file to avoid linking in unless needed
    22.6 +
    22.7 +// snes_spc 0.9.0. http://www.slack.net/~ant/
    22.8 +
    22.9 +#include "SNES_SPC.h"
   22.10 +
   22.11 +#if !SPC_NO_COPY_STATE_FUNCS
   22.12 +
   22.13 +#include <string.h>
   22.14 +
   22.15 +/* Copyright (C) 2004-2007 Shay Green. This module is free software; you
   22.16 +can redistribute it and/or modify it under the terms of the GNU Lesser
   22.17 +General Public License as published by the Free Software Foundation; either
   22.18 +version 2.1 of the License, or (at your option) any later version. This
   22.19 +module is distributed in the hope that it will be useful, but WITHOUT ANY
   22.20 +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   22.21 +FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
   22.22 +details. You should have received a copy of the GNU Lesser General Public
   22.23 +License along with this module; if not, write to the Free Software Foundation,
   22.24 +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
   22.25 +
   22.26 +#include "blargg_source.h"
   22.27 +
   22.28 +#define RAM         (m.ram.ram)
   22.29 +#define REGS        (m.smp_regs [0])
   22.30 +#define REGS_IN     (m.smp_regs [1])
   22.31 +
   22.32 +void SNES_SPC::save_regs( uint8_t out [reg_count] )
   22.33 +{
   22.34 +	// Use current timer counter values
   22.35 +	for ( int i = 0; i < timer_count; i++ )
   22.36 +		out [r_t0out + i] = m.timers [i].counter;
   22.37 +	
   22.38 +	// Last written values
   22.39 +	memcpy( out, REGS, r_t0out );
   22.40 +}
   22.41 +
   22.42 +void SNES_SPC::init_header( void* spc_out )
   22.43 +{
   22.44 +	spc_file_t* const spc = (spc_file_t*) spc_out;
   22.45 +	
   22.46 +	spc->has_id666 = 26; // has none
   22.47 +	spc->version   = 30;
   22.48 +	memcpy( spc, signature, sizeof spc->signature );
   22.49 +	memset( spc->text, 0, sizeof spc->text );
   22.50 +}
   22.51 +
   22.52 +void SNES_SPC::save_spc( void* spc_out )
   22.53 +{
   22.54 +	spc_file_t* const spc = (spc_file_t*) spc_out;
   22.55 +	
   22.56 +	// CPU
   22.57 +	spc->pcl = (uint8_t) (m.cpu_regs.pc >> 0);
   22.58 +	spc->pch = (uint8_t) (m.cpu_regs.pc >> 8);
   22.59 +	spc->a   = m.cpu_regs.a;
   22.60 +	spc->x   = m.cpu_regs.x;
   22.61 +	spc->y   = m.cpu_regs.y;
   22.62 +	spc->psw = m.cpu_regs.psw;
   22.63 +	spc->sp  = m.cpu_regs.sp;
   22.64 +	
   22.65 +	// RAM, ROM
   22.66 +	memcpy( spc->ram, RAM, sizeof spc->ram );
   22.67 +	if ( m.rom_enabled )
   22.68 +		memcpy( spc->ram + rom_addr, m.hi_ram, sizeof m.hi_ram );
   22.69 +	memset( spc->unused, 0, sizeof spc->unused );
   22.70 +	memcpy( spc->ipl_rom, m.rom, sizeof spc->ipl_rom );
   22.71 +	
   22.72 +	// SMP registers
   22.73 +	save_regs( &spc->ram [0xF0] );
   22.74 +	int i;
   22.75 +	for ( i = 0; i < port_count; i++ )
   22.76 +		spc->ram [0xF0 + r_cpuio0 + i] = REGS_IN [r_cpuio0 + i];
   22.77 +	
   22.78 +	// DSP registers
   22.79 +	for ( i = 0; i < SPC_DSP::register_count; i++ )
   22.80 +		spc->dsp [i] = dsp.read( i );
   22.81 +}
   22.82 +
   22.83 +void SNES_SPC::copy_state( unsigned char** io, copy_func_t copy )
   22.84 +{
   22.85 +	SPC_State_Copier copier( io, copy );
   22.86 +	
   22.87 +	// Make state data more readable by putting 64K RAM, 16 SMP registers,
   22.88 +	// then DSP (with its 128 registers) first
   22.89 +	
   22.90 +	// RAM
   22.91 +	enable_rom( 0 ); // will get re-enabled if necessary in regs_loaded() below
   22.92 +	copier.copy( RAM, 0x10000 );
   22.93 +	
   22.94 +	{
   22.95 +		// SMP registers
   22.96 +		uint8_t out_ports [port_count];
   22.97 +		uint8_t regs [reg_count];
   22.98 +		memcpy( out_ports, &REGS [r_cpuio0], sizeof out_ports );
   22.99 +		save_regs( regs );
  22.100 +		copier.copy( regs, sizeof regs );
  22.101 +		copier.copy( out_ports, sizeof out_ports );
  22.102 +		load_regs( regs );
  22.103 +		regs_loaded();
  22.104 +		memcpy( &REGS [r_cpuio0], out_ports, sizeof out_ports );
  22.105 +	}
  22.106 +	
  22.107 +	// CPU registers
  22.108 +	SPC_COPY( uint16_t, m.cpu_regs.pc );
  22.109 +	SPC_COPY(  uint8_t, m.cpu_regs.a );
  22.110 +	SPC_COPY(  uint8_t, m.cpu_regs.x );
  22.111 +	SPC_COPY(  uint8_t, m.cpu_regs.y );
  22.112 +	SPC_COPY(  uint8_t, m.cpu_regs.psw );
  22.113 +	SPC_COPY(  uint8_t, m.cpu_regs.sp );
  22.114 +	copier.extra();
  22.115 +	
  22.116 +	SPC_COPY( int16_t, m.spc_time );
  22.117 +	SPC_COPY( int16_t, m.dsp_time );
  22.118 +	
  22.119 +	// DSP
  22.120 +	dsp.copy_state( io, copy );
  22.121 +	
  22.122 +	// Timers
  22.123 +	for ( int i = 0; i < timer_count; i++ )
  22.124 +	{
  22.125 +		Timer* t = &m.timers [i];
  22.126 +		SPC_COPY( int16_t, t->next_time );
  22.127 +		SPC_COPY( uint8_t, t->divider );
  22.128 +		copier.extra();
  22.129 +	}
  22.130 +	copier.extra();
  22.131 +}
  22.132 +#endif
    23.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    23.2 +++ b/snes_spc/SPC_CPU.h	Fri Oct 21 05:53:11 2011 -0700
    23.3 @@ -0,0 +1,1220 @@
    23.4 +// snes_spc 0.9.0. http://www.slack.net/~ant/
    23.5 +
    23.6 +/* Copyright (C) 2004-2007 Shay Green. This module is free software; you
    23.7 +can redistribute it and/or modify it under the terms of the GNU Lesser
    23.8 +General Public License as published by the Free Software Foundation; either
    23.9 +version 2.1 of the License, or (at your option) any later version. This
   23.10 +module is distributed in the hope that it will be useful, but WITHOUT ANY
   23.11 +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   23.12 +FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
   23.13 +details. You should have received a copy of the GNU Lesser General Public
   23.14 +License along with this module; if not, write to the Free Software Foundation,
   23.15 +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
   23.16 +
   23.17 +//// Memory access
   23.18 +
   23.19 +#if SPC_MORE_ACCURACY
   23.20 +	#define SUSPICIOUS_OPCODE( name ) ((void) 0)
   23.21 +#else
   23.22 +	#define SUSPICIOUS_OPCODE( name ) dprintf( "SPC: suspicious opcode: " name "\n" )
   23.23 +#endif
   23.24 +
   23.25 +#define CPU_READ( time, offset, addr )\
   23.26 +	cpu_read( addr, time + offset )
   23.27 +
   23.28 +#define CPU_WRITE( time, offset, addr, data )\
   23.29 +	cpu_write( data, addr, time + offset )
   23.30 +
   23.31 +#if SPC_MORE_ACCURACY
   23.32 +	#define CPU_READ_TIMER( time, offset, addr, out )\
   23.33 +		{ out = CPU_READ( time, offset, addr ); }
   23.34 +
   23.35 +#else
   23.36 +	// timers are by far the most common thing read from dp
   23.37 +	#define CPU_READ_TIMER( time, offset, addr_, out )\
   23.38 +	{\
   23.39 +		rel_time_t adj_time = time + offset;\
   23.40 +		int dp_addr = addr_;\
   23.41 +		int ti = dp_addr - (r_t0out + 0xF0);\
   23.42 +		if ( (unsigned) ti < timer_count )\
   23.43 +		{\
   23.44 +			Timer* t = &m.timers [ti];\
   23.45 +			if ( adj_time >= t->next_time )\
   23.46 +				t = run_timer_( t, adj_time );\
   23.47 +			out = t->counter;\
   23.48 +			t->counter = 0;\
   23.49 +		}\
   23.50 +		else\
   23.51 +		{\
   23.52 +			out = ram [dp_addr];\
   23.53 +			int i = dp_addr - 0xF0;\
   23.54 +			if ( (unsigned) i < 0x10 )\
   23.55 +				out = cpu_read_smp_reg( i, adj_time );\
   23.56 +		}\
   23.57 +	}
   23.58 +#endif
   23.59 +
   23.60 +#define TIME_ADJ( n )   (n)
   23.61 +
   23.62 +#define READ_TIMER( time, addr, out )       CPU_READ_TIMER( rel_time, TIME_ADJ(time), (addr), out )
   23.63 +#define READ(  time, addr )                 CPU_READ ( rel_time, TIME_ADJ(time), (addr) )
   23.64 +#define WRITE( time, addr, data )           CPU_WRITE( rel_time, TIME_ADJ(time), (addr), (data) )
   23.65 +
   23.66 +#define DP_ADDR( addr )                     (dp + (addr))
   23.67 +
   23.68 +#define READ_DP_TIMER(  time, addr, out )   CPU_READ_TIMER( rel_time, TIME_ADJ(time), DP_ADDR( addr ), out )
   23.69 +#define READ_DP(  time, addr )              READ ( time, DP_ADDR( addr ) )
   23.70 +#define WRITE_DP( time, addr, data )        WRITE( time, DP_ADDR( addr ), data )
   23.71 +
   23.72 +#define READ_PROG16( addr )                 GET_LE16( ram + (addr) )
   23.73 +
   23.74 +#define SET_PC( n )     (pc = ram + (n))
   23.75 +#define GET_PC()        (pc - ram)
   23.76 +#define READ_PC( pc )   (*(pc))
   23.77 +#define READ_PC16( pc ) GET_LE16( pc )
   23.78 +
   23.79 +// TODO: remove non-wrapping versions?
   23.80 +#define SPC_NO_SP_WRAPAROUND 0
   23.81 +
   23.82 +#define SET_SP( v )     (sp = ram + 0x101 + (v))
   23.83 +#define GET_SP()        (sp - 0x101 - ram)
   23.84 +
   23.85 +#if SPC_NO_SP_WRAPAROUND
   23.86 +#define PUSH16( v )     (sp -= 2, SET_LE16( sp, v ))
   23.87 +#define PUSH( v )       (void) (*--sp = (uint8_t) (v))
   23.88 +#define POP( out )      (void) ((out) = *sp++)
   23.89 +
   23.90 +#else
   23.91 +#define PUSH16( data )\
   23.92 +{\
   23.93 +	int addr = (sp -= 2) - ram;\
   23.94 +	if ( addr > 0x100 )\
   23.95 +	{\
   23.96 +		SET_LE16( sp, data );\
   23.97 +	}\
   23.98 +	else\
   23.99 +	{\
  23.100 +		ram [(uint8_t) addr + 0x100] = (uint8_t) data;\
  23.101 +		sp [1] = (uint8_t) (data >> 8);\
  23.102 +		sp += 0x100;\
  23.103 +	}\
  23.104 +}
  23.105 +
  23.106 +#define PUSH( data )\
  23.107 +{\
  23.108 +	*--sp = (uint8_t) (data);\
  23.109 +	if ( sp - ram == 0x100 )\
  23.110 +		sp += 0x100;\
  23.111 +}
  23.112 +
  23.113 +#define POP( out )\
  23.114 +{\
  23.115 +	out = *sp++;\
  23.116 +	if ( sp - ram == 0x201 )\
  23.117 +	{\
  23.118 +		out = sp [-0x101];\
  23.119 +		sp -= 0x100;\
  23.120 +	}\
  23.121 +}
  23.122 +
  23.123 +#endif
  23.124 +
  23.125 +#define MEM_BIT( rel ) CPU_mem_bit( pc, rel_time + rel )
  23.126 +
  23.127 +unsigned SNES_SPC::CPU_mem_bit( uint8_t const* pc, rel_time_t rel_time )
  23.128 +{
  23.129 +	unsigned addr = READ_PC16( pc );
  23.130 +	unsigned t = READ( 0, addr & 0x1FFF ) >> (addr >> 13);
  23.131 +	return t << 8 & 0x100;
  23.132 +}
  23.133 +
  23.134 +//// Status flag handling
  23.135 +
  23.136 +// Hex value in name to clarify code and bit shifting.
  23.137 +// Flag stored in indicated variable during emulation
  23.138 +int const n80 = 0x80; // nz
  23.139 +int const v40 = 0x40; // psw
  23.140 +int const p20 = 0x20; // dp
  23.141 +int const b10 = 0x10; // psw
  23.142 +int const h08 = 0x08; // psw
  23.143 +int const i04 = 0x04; // psw
  23.144 +int const z02 = 0x02; // nz
  23.145 +int const c01 = 0x01; // c
  23.146 +
  23.147 +int const nz_neg_mask = 0x880; // either bit set indicates N flag set
  23.148 +
  23.149 +#define GET_PSW( out )\
  23.150 +{\
  23.151 +	out = psw & ~(n80 | p20 | z02 | c01);\
  23.152 +	out |= c  >> 8 & c01;\
  23.153 +	out |= dp >> 3 & p20;\
  23.154 +	out |= ((nz >> 4) | nz) & n80;\
  23.155 +	if ( !(uint8_t) nz ) out |= z02;\
  23.156 +}
  23.157 +
  23.158 +#define SET_PSW( in )\
  23.159 +{\
  23.160 +	psw = in;\
  23.161 +	c   = in << 8;\
  23.162 +	dp  = in << 3 & 0x100;\
  23.163 +	nz  = (in << 4 & 0x800) | (~in & z02);\
  23.164 +}
  23.165 +
  23.166 +SPC_CPU_RUN_FUNC
  23.167 +{
  23.168 +	uint8_t* const ram = RAM;
  23.169 +	int a = m.cpu_regs.a;
  23.170 +	int x = m.cpu_regs.x;
  23.171 +	int y = m.cpu_regs.y;
  23.172 +	uint8_t const* pc;
  23.173 +	uint8_t* sp;
  23.174 +	int psw;
  23.175 +	int c;
  23.176 +	int nz;
  23.177 +	int dp;
  23.178 +	
  23.179 +	SET_PC( m.cpu_regs.pc );
  23.180 +	SET_SP( m.cpu_regs.sp );
  23.181 +	SET_PSW( m.cpu_regs.psw );
  23.182 +	
  23.183 +	goto loop;
  23.184 +	
  23.185 +	
  23.186 +	// Main loop
  23.187 +	
  23.188 +cbranch_taken_loop:
  23.189 +	pc += *(BOOST::int8_t const*) pc;
  23.190 +inc_pc_loop:
  23.191 +	pc++;
  23.192 +loop:
  23.193 +{
  23.194 +	unsigned opcode;
  23.195 +	unsigned data;
  23.196 +	
  23.197 +	check( (unsigned) a < 0x100 );
  23.198 +	check( (unsigned) x < 0x100 );
  23.199 +	check( (unsigned) y < 0x100 );
  23.200 +	
  23.201 +	opcode = *pc;
  23.202 +	if ( (rel_time += m.cycle_table [opcode]) > 0 )
  23.203 +		goto out_of_time;
  23.204 +	
  23.205 +	#ifdef SPC_CPU_OPCODE_HOOK
  23.206 +		SPC_CPU_OPCODE_HOOK( GET_PC(), opcode );
  23.207 +	#endif
  23.208 +	/*
  23.209 +	//SUB_CASE_COUNTER( 1 );
  23.210 +	#define PROFILE_TIMER_LOOP( op, addr, len )\
  23.211 +	if ( opcode == op )\
  23.212 +	{\
  23.213 +		int cond = (unsigned) ((addr) - 0xFD) < 3 &&\
  23.214 +				pc [len] == 0xF0 && pc [len+1] == 0xFE - len;\
  23.215 +		SUB_CASE_COUNTER( op && cond );\
  23.216 +	}
  23.217 +	
  23.218 +	PROFILE_TIMER_LOOP( 0xEC, GET_LE16( pc + 1 ), 3 );
  23.219 +	PROFILE_TIMER_LOOP( 0xEB, pc [1], 2 );
  23.220 +	PROFILE_TIMER_LOOP( 0xE4, pc [1], 2 );
  23.221 +	*/
  23.222 +	
  23.223 +	// TODO: if PC is at end of memory, this will get wrong operand (very obscure)
  23.224 +	data = *++pc;
  23.225 +	switch ( opcode )
  23.226 +	{
  23.227 +	
  23.228 +// Common instructions
  23.229 +
  23.230 +#define BRANCH( cond )\
  23.231 +{\
  23.232 +	pc++;\
  23.233 +	pc += (BOOST::int8_t) data;\
  23.234 +	if ( cond )\
  23.235 +		goto loop;\
  23.236 +	pc -= (BOOST::int8_t) data;\
  23.237 +	rel_time -= 2;\
  23.238 +	goto loop;\
  23.239 +}
  23.240 +
  23.241 +	case 0xF0: // BEQ
  23.242 +		BRANCH( !(uint8_t) nz ) // 89% taken
  23.243 +	
  23.244 +	case 0xD0: // BNE
  23.245 +		BRANCH( (uint8_t) nz )
  23.246 +	
  23.247 +	case 0x3F:{// CALL
  23.248 +		int old_addr = GET_PC() + 2;
  23.249 +		SET_PC( READ_PC16( pc ) );
  23.250 +		PUSH16( old_addr );
  23.251 +		goto loop;
  23.252 +	}
  23.253 +	
  23.254 +	case 0x6F:// RET
  23.255 +		#if SPC_NO_SP_WRAPAROUND
  23.256 +		{
  23.257 +			SET_PC( GET_LE16( sp ) );
  23.258 +			sp += 2;
  23.259 +		}
  23.260 +		#else
  23.261 +		{
  23.262 +			int addr = sp - ram;
  23.263 +			SET_PC( GET_LE16( sp ) );
  23.264 +			sp += 2;
  23.265 +			if ( addr < 0x1FF )
  23.266 +				goto loop;
  23.267 +			
  23.268 +			SET_PC( sp [-0x101] * 0x100 + ram [(uint8_t) addr + 0x100] );
  23.269 +			sp -= 0x100;
  23.270 +		}
  23.271 +		#endif
  23.272 +		goto loop;
  23.273 +	
  23.274 +	case 0xE4: // MOV a,dp
  23.275 +		++pc;
  23.276 +		// 80% from timer
  23.277 +		READ_DP_TIMER( 0, data, a = nz );
  23.278 +		goto loop;
  23.279 +	
  23.280 +	case 0xFA:{// MOV dp,dp
  23.281 +		int temp;
  23.282 +		READ_DP_TIMER( -2, data, temp );
  23.283 +		data = temp + no_read_before_write ;
  23.284 +	}
  23.285 +	// fall through
  23.286 +	case 0x8F:{// MOV dp,#imm
  23.287 +		int temp = READ_PC( pc + 1 );
  23.288 +		pc += 2;
  23.289 +		
  23.290 +		#if !SPC_MORE_ACCURACY
  23.291 +		{
  23.292 +			int i = dp + temp;
  23.293 +			ram [i] = (uint8_t) data;
  23.294 +			i -= 0xF0;
  23.295 +			if ( (unsigned) i < 0x10 ) // 76%
  23.296 +			{
  23.297 +				REGS [i] = (uint8_t) data;
  23.298 +				
  23.299 +				// Registers other than $F2 and $F4-$F7
  23.300 +				//if ( i != 2 && i != 4 && i != 5 && i != 6 && i != 7 )
  23.301 +				if ( ((~0x2F00 << (bits_in_int - 16)) << i) < 0 ) // 12%
  23.302 +					cpu_write_smp_reg( data, rel_time, i );
  23.303 +			}
  23.304 +		}
  23.305 +		#else
  23.306 +			WRITE_DP( 0, temp, data );
  23.307 +		#endif
  23.308 +		goto loop;
  23.309 +	}
  23.310 +	
  23.311 +	case 0xC4: // MOV dp,a
  23.312 +		++pc;
  23.313 +		#if !SPC_MORE_ACCURACY
  23.314 +		{
  23.315 +			int i = dp + data;
  23.316 +			ram [i] = (uint8_t) a;
  23.317 +			i -= 0xF0;
  23.318 +			if ( (unsigned) i < 0x10 ) // 39%
  23.319 +			{
  23.320 +				unsigned sel = i - 2;
  23.321 +				REGS [i] = (uint8_t) a;
  23.322 +				
  23.323 +				if ( sel == 1 ) // 51% $F3
  23.324 +					dsp_write( a, rel_time );
  23.325 +				else if ( sel > 1 ) // 1% not $F2 or $F3
  23.326 +					cpu_write_smp_reg_( a, rel_time, i );
  23.327 +			}
  23.328 +		}
  23.329 +		#else
  23.330 +			WRITE_DP( 0, data, a );
  23.331 +		#endif
  23.332 +		goto loop;
  23.333 +	
  23.334 +#define CASE( n )   case n:
  23.335 +
  23.336 +// Define common address modes based on opcode for immediate mode. Execution
  23.337 +// ends with data set to the address of the operand.
  23.338 +#define ADDR_MODES_( op )\
  23.339 +	CASE( op - 0x02 ) /* (X) */\
  23.340 +		data = x + dp;\
  23.341 +		pc--;\
  23.342 +		goto end_##op;\
  23.343 +	CASE( op + 0x0F ) /* (dp)+Y */\
  23.344 +		data = READ_PROG16( data + dp ) + y;\
  23.345 +		goto end_##op;\
  23.346 +	CASE( op - 0x01 ) /* (dp+X) */\
  23.347 +		data = READ_PROG16( ((uint8_t) (data + x)) + dp );\
  23.348 +		goto end_##op;\
  23.349 +	CASE( op + 0x0E ) /* abs+Y */\
  23.350 +		data += y;\
  23.351 +		goto abs_##op;\
  23.352 +	CASE( op + 0x0D ) /* abs+X */\
  23.353 +		data += x;\
  23.354 +	CASE( op - 0x03 ) /* abs */\
  23.355 +	abs_##op:\
  23.356 +		data += 0x100 * READ_PC( ++pc );\
  23.357 +		goto end_##op;\
  23.358 +	CASE( op + 0x0C ) /* dp+X */\
  23.359 +		data = (uint8_t) (data + x);
  23.360 +
  23.361 +#define ADDR_MODES_NO_DP( op )\
  23.362 +	ADDR_MODES_( op )\
  23.363 +		data += dp;\
  23.364 +	end_##op:
  23.365 +
  23.366 +#define ADDR_MODES( op )\
  23.367 +	ADDR_MODES_( op )\
  23.368 +	CASE( op - 0x04 ) /* dp */\
  23.369 +		data += dp;\
  23.370 +	end_##op:
  23.371 +
  23.372 +// 1. 8-bit Data Transmission Commands. Group I
  23.373 +
  23.374 +	ADDR_MODES_NO_DP( 0xE8 ) // MOV A,addr
  23.375 +		a = nz = READ( 0, data );
  23.376 +		goto inc_pc_loop;
  23.377 +	
  23.378 +	case 0xBF:{// MOV A,(X)+
  23.379 +		int temp = x + dp;
  23.380 +		x = (uint8_t) (x + 1);
  23.381 +		a = nz = READ( -1, temp );
  23.382 +		goto loop;
  23.383 +	}
  23.384 +	
  23.385 +	case 0xE8: // MOV A,imm
  23.386 +		a  = data;
  23.387 +		nz = data;
  23.388 +		goto inc_pc_loop;
  23.389 +	
  23.390 +	case 0xF9: // MOV X,dp+Y
  23.391 +		data = (uint8_t) (data + y);
  23.392 +	case 0xF8: // MOV X,dp
  23.393 +		READ_DP_TIMER( 0, data, x = nz );
  23.394 +		goto inc_pc_loop;
  23.395 +	
  23.396 +	case 0xE9: // MOV X,abs
  23.397 +		data = READ_PC16( pc );
  23.398 +		++pc;
  23.399 +		data = READ( 0, data );
  23.400 +	case 0xCD: // MOV X,imm
  23.401 +		x  = data;
  23.402 +		nz = data;
  23.403 +		goto inc_pc_loop;
  23.404 +	
  23.405 +	case 0xFB: // MOV Y,dp+X
  23.406 +		data = (uint8_t) (data + x);
  23.407 +	case 0xEB: // MOV Y,dp
  23.408 +		// 70% from timer
  23.409 +		pc++;
  23.410 +		READ_DP_TIMER( 0, data, y = nz );
  23.411 +		goto loop;
  23.412 +	
  23.413 +	case 0xEC:{// MOV Y,abs
  23.414 +		int temp = READ_PC16( pc );
  23.415 +		pc += 2;
  23.416 +		READ_TIMER( 0, temp, y = nz );
  23.417 +		//y = nz = READ( 0, temp );
  23.418 +		goto loop;
  23.419 +	}
  23.420 +	
  23.421 +	case 0x8D: // MOV Y,imm
  23.422 +		y  = data;
  23.423 +		nz = data;
  23.424 +		goto inc_pc_loop;
  23.425 +	
  23.426 +// 2. 8-BIT DATA TRANSMISSION COMMANDS, GROUP 2
  23.427 +
  23.428 +	ADDR_MODES_NO_DP( 0xC8 ) // MOV addr,A
  23.429 +		WRITE( 0, data, a );
  23.430 +		goto inc_pc_loop;
  23.431 +	
  23.432 +	{
  23.433 +		int temp;
  23.434 +	case 0xCC: // MOV abs,Y
  23.435 +		temp = y;
  23.436 +		goto mov_abs_temp;
  23.437 +	case 0xC9: // MOV abs,X
  23.438 +		temp = x;
  23.439 +	mov_abs_temp:
  23.440 +		WRITE( 0, READ_PC16( pc ), temp );
  23.441 +		pc += 2;
  23.442 +		goto loop;
  23.443 +	}
  23.444 +	
  23.445 +	case 0xD9: // MOV dp+Y,X
  23.446 +		data = (uint8_t) (data + y);
  23.447 +	case 0xD8: // MOV dp,X
  23.448 +		WRITE( 0, data + dp, x );
  23.449 +		goto inc_pc_loop;
  23.450 +	
  23.451 +	case 0xDB: // MOV dp+X,Y
  23.452 +		data = (uint8_t) (data + x);
  23.453 +	case 0xCB: // MOV dp,Y
  23.454 +		WRITE( 0, data + dp, y );
  23.455 +		goto inc_pc_loop;
  23.456 +
  23.457 +// 3. 8-BIT DATA TRANSMISSIN COMMANDS, GROUP 3.
  23.458 +	
  23.459 +	case 0x7D: // MOV A,X
  23.460 +		a  = x;
  23.461 +		nz = x;
  23.462 +		goto loop;
  23.463 +	
  23.464 +	case 0xDD: // MOV A,Y
  23.465 +		a  = y;
  23.466 +		nz = y;
  23.467 +		goto loop;
  23.468 +	
  23.469 +	case 0x5D: // MOV X,A
  23.470 +		x  = a;
  23.471 +		nz = a;
  23.472 +		goto loop;
  23.473 +	
  23.474 +	case 0xFD: // MOV Y,A
  23.475 +		y  = a;
  23.476 +		nz = a;
  23.477 +		goto loop;
  23.478 +	
  23.479 +	case 0x9D: // MOV X,SP
  23.480 +		x = nz = GET_SP();
  23.481 +		goto loop;
  23.482 +	
  23.483 +	case 0xBD: // MOV SP,X
  23.484 +		SET_SP( x );
  23.485 +		goto loop;
  23.486 +	
  23.487 +	//case 0xC6: // MOV (X),A (handled by MOV addr,A in group 2)
  23.488 +	
  23.489 +	case 0xAF: // MOV (X)+,A
  23.490 +		WRITE_DP( 0, x, a + no_read_before_write  );
  23.491 +		x++;
  23.492 +		goto loop;
  23.493 +	
  23.494 +// 5. 8-BIT LOGIC OPERATION COMMANDS
  23.495 +	
  23.496 +#define LOGICAL_OP( op, func )\
  23.497 +	ADDR_MODES( op ) /* addr */\
  23.498 +		data = READ( 0, data );\
  23.499 +	case op: /* imm */\
  23.500 +		nz = a func##= data;\
  23.501 +		goto inc_pc_loop;\
  23.502 +	{   unsigned addr;\
  23.503 +	case op + 0x11: /* X,Y */\
  23.504 +		data = READ_DP( -2, y );\
  23.505 +		addr = x + dp;\
  23.506 +		goto addr_##op;\
  23.507 +	case op + 0x01: /* dp,dp */\
  23.508 +		data = READ_DP( -3, data );\
  23.509 +	case op + 0x10:{/*dp,imm*/\
  23.510 +		uint8_t const* addr2 = pc + 1;\
  23.511 +		pc += 2;\
  23.512 +		addr = READ_PC( addr2 ) + dp;\
  23.513 +	}\
  23.514 +	addr_##op:\
  23.515 +		nz = data func READ( -1, addr );\
  23.516 +		WRITE( 0, addr, nz );\
  23.517 +		goto loop;\
  23.518 +	}
  23.519 +	
  23.520 +	LOGICAL_OP( 0x28, & ); // AND
  23.521 +	
  23.522 +	LOGICAL_OP( 0x08, | ); // OR
  23.523 +	
  23.524 +	LOGICAL_OP( 0x48, ^ ); // EOR
  23.525 +	
  23.526 +// 4. 8-BIT ARITHMETIC OPERATION COMMANDS
  23.527 +
  23.528 +	ADDR_MODES( 0x68 ) // CMP addr
  23.529 +		data = READ( 0, data );
  23.530 +	case 0x68: // CMP imm
  23.531 +		nz = a - data;
  23.532 +		c = ~nz;
  23.533 +		nz &= 0xFF;
  23.534 +		goto inc_pc_loop;
  23.535 +	
  23.536 +	case 0x79: // CMP (X),(Y)
  23.537 +		data = READ_DP( -2, y );
  23.538 +		nz = READ_DP( -1, x ) - data;
  23.539 +		c = ~nz;
  23.540 +		nz &= 0xFF;
  23.541 +		goto loop;
  23.542 +	
  23.543 +	case 0x69: // CMP dp,dp
  23.544 +		data = READ_DP( -3, data );
  23.545 +	case 0x78: // CMP dp,imm
  23.546 +		nz = READ_DP( -1, READ_PC( ++pc ) ) - data;
  23.547 +		c = ~nz;
  23.548 +		nz &= 0xFF;
  23.549 +		goto inc_pc_loop;
  23.550 +	
  23.551 +	case 0x3E: // CMP X,dp
  23.552 +		data += dp;
  23.553 +		goto cmp_x_addr;
  23.554 +	case 0x1E: // CMP X,abs
  23.555 +		data = READ_PC16( pc );
  23.556 +		pc++;
  23.557 +	cmp_x_addr:
  23.558 +		data = READ( 0, data );
  23.559 +	case 0xC8: // CMP X,imm
  23.560 +		nz = x - data;
  23.561 +		c = ~nz;
  23.562 +		nz &= 0xFF;
  23.563 +		goto inc_pc_loop;
  23.564 +	
  23.565 +	case 0x7E: // CMP Y,dp
  23.566 +		data += dp;
  23.567 +		goto cmp_y_addr;
  23.568 +	case 0x5E: // CMP Y,abs
  23.569 +		data = READ_PC16( pc );
  23.570 +		pc++;
  23.571 +	cmp_y_addr:
  23.572 +		data = READ( 0, data );
  23.573 +	case 0xAD: // CMP Y,imm
  23.574 +		nz = y - data;
  23.575 +		c = ~nz;
  23.576 +		nz &= 0xFF;
  23.577 +		goto inc_pc_loop;
  23.578 +	
  23.579 +	{
  23.580 +		int addr;
  23.581 +	case 0xB9: // SBC (x),(y)
  23.582 +	case 0x99: // ADC (x),(y)
  23.583 +		pc--; // compensate for inc later
  23.584 +		data = READ_DP( -2, y );
  23.585 +		addr = x + dp;
  23.586 +		goto adc_addr;
  23.587 +	case 0xA9: // SBC dp,dp
  23.588 +	case 0x89: // ADC dp,dp
  23.589 +		data = READ_DP( -3, data );
  23.590 +	case 0xB8: // SBC dp,imm
  23.591 +	case 0x98: // ADC dp,imm
  23.592 +		addr = READ_PC( ++pc ) + dp;
  23.593 +	adc_addr:
  23.594 +		nz = READ( -1, addr );
  23.595 +		goto adc_data;
  23.596 +		
  23.597 +// catch ADC and SBC together, then decode later based on operand
  23.598 +#undef CASE
  23.599 +#define CASE( n ) case n: case (n) + 0x20:
  23.600 +	ADDR_MODES( 0x88 ) // ADC/SBC addr
  23.601 +		data = READ( 0, data );
  23.602 +	case 0xA8: // SBC imm
  23.603 +	case 0x88: // ADC imm
  23.604 +		addr = -1; // A
  23.605 +		nz = a;
  23.606 +	adc_data: {
  23.607 +		int flags;
  23.608 +		if ( opcode >= 0xA0 ) // SBC
  23.609 +			data ^= 0xFF;
  23.610 +		
  23.611 +		flags = data ^ nz;
  23.612 +		nz += data + (c >> 8 & 1);
  23.613 +		flags ^= nz;
  23.614 +		
  23.615 +		psw = (psw & ~(v40 | h08)) |
  23.616 +				(flags >> 1 & h08) |
  23.617 +				((flags + 0x80) >> 2 & v40);
  23.618 +		c = nz;
  23.619 +		if ( addr < 0 )
  23.620 +		{
  23.621 +			a = (uint8_t) nz;
  23.622 +			goto inc_pc_loop;
  23.623 +		}
  23.624 +		WRITE( 0, addr, /*(uint8_t)*/ nz );
  23.625 +		goto inc_pc_loop;
  23.626 +	}
  23.627 +	
  23.628 +	}
  23.629 +	
  23.630 +// 6. ADDITION & SUBTRACTION COMMANDS
  23.631 +
  23.632 +#define INC_DEC_REG( reg, op )\
  23.633 +		nz  = reg op;\
  23.634 +		reg = (uint8_t) nz;\
  23.635 +		goto loop;
  23.636 +
  23.637 +	case 0xBC: INC_DEC_REG( a, + 1 ) // INC A
  23.638 +	case 0x3D: INC_DEC_REG( x, + 1 ) // INC X
  23.639 +	case 0xFC: INC_DEC_REG( y, + 1 ) // INC Y
  23.640 +	
  23.641 +	case 0x9C: INC_DEC_REG( a, - 1 ) // DEC A
  23.642 +	case 0x1D: INC_DEC_REG( x, - 1 ) // DEC X
  23.643 +	case 0xDC: INC_DEC_REG( y, - 1 ) // DEC Y
  23.644 +
  23.645 +	case 0x9B: // DEC dp+X
  23.646 +	case 0xBB: // INC dp+X
  23.647 +		data = (uint8_t) (data + x);
  23.648 +	case 0x8B: // DEC dp
  23.649 +	case 0xAB: // INC dp
  23.650 +		data += dp;
  23.651 +		goto inc_abs;
  23.652 +	case 0x8C: // DEC abs
  23.653 +	case 0xAC: // INC abs
  23.654 +		data = READ_PC16( pc );
  23.655 +		pc++;
  23.656 +	inc_abs:
  23.657 +		nz = (opcode >> 4 & 2) - 1;
  23.658 +		nz += READ( -1, data );
  23.659 +		WRITE( 0, data, /*(uint8_t)*/ nz );
  23.660 +		goto inc_pc_loop;
  23.661 +	
  23.662 +// 7. SHIFT, ROTATION COMMANDS
  23.663 +
  23.664 +	case 0x5C: // LSR A
  23.665 +		c = 0;
  23.666 +	case 0x7C:{// ROR A
  23.667 +		nz = (c >> 1 & 0x80) | (a >> 1);
  23.668 +		c = a << 8;
  23.669 +		a = nz;
  23.670 +		goto loop;
  23.671 +	}
  23.672 +	
  23.673 +	case 0x1C: // ASL A
  23.674 +		c = 0;
  23.675 +	case 0x3C:{// ROL A
  23.676 +		int temp = c >> 8 & 1;
  23.677 +		c = a << 1;
  23.678 +		nz = c | temp;
  23.679 +		a = (uint8_t) nz;
  23.680 +		goto loop;
  23.681 +	}
  23.682 +	
  23.683 +	case 0x0B: // ASL dp
  23.684 +		c = 0;
  23.685 +		data += dp;
  23.686 +		goto rol_mem;
  23.687 +	case 0x1B: // ASL dp+X
  23.688 +		c = 0;
  23.689 +	case 0x3B: // ROL dp+X
  23.690 +		data = (uint8_t) (data + x);
  23.691 +	case 0x2B: // ROL dp
  23.692 +		data += dp;
  23.693 +		goto rol_mem;
  23.694 +	case 0x0C: // ASL abs
  23.695 +		c = 0;
  23.696 +	case 0x2C: // ROL abs
  23.697 +		data = READ_PC16( pc );
  23.698 +		pc++;
  23.699 +	rol_mem:
  23.700 +		nz = c >> 8 & 1;
  23.701 +		nz |= (c = READ( -1, data ) << 1);
  23.702 +		WRITE( 0, data, /*(uint8_t)*/ nz );
  23.703 +		goto inc_pc_loop;
  23.704 +	
  23.705 +	case 0x4B: // LSR dp
  23.706 +		c = 0;
  23.707 +		data += dp;
  23.708 +		goto ror_mem;
  23.709 +	case 0x5B: // LSR dp+X
  23.710 +		c = 0;
  23.711 +	case 0x7B: // ROR dp+X
  23.712 +		data = (uint8_t) (data + x);
  23.713 +	case 0x6B: // ROR dp
  23.714 +		data += dp;
  23.715 +		goto ror_mem;
  23.716 +	case 0x4C: // LSR abs
  23.717 +		c = 0;
  23.718 +	case 0x6C: // ROR abs
  23.719 +		data = READ_PC16( pc );
  23.720 +		pc++;
  23.721 +	ror_mem: {
  23.722 +		int temp = READ( -1, data );
  23.723 +		nz = (c >> 1 & 0x80) | (temp >> 1);
  23.724 +		c = temp << 8;
  23.725 +		WRITE( 0, data, nz );
  23.726 +		goto inc_pc_loop;
  23.727 +	}
  23.728 +
  23.729 +	case 0x9F: // XCN
  23.730 +		nz = a = (a >> 4) | (uint8_t) (a << 4);
  23.731 +		goto loop;
  23.732 +
  23.733 +// 8. 16-BIT TRANSMISION COMMANDS
  23.734 +
  23.735 +	case 0xBA: // MOVW YA,dp
  23.736 +		a = READ_DP( -2, data );
  23.737 +		nz = (a & 0x7F) | (a >> 1);
  23.738 +		y = READ_DP( 0, (uint8_t) (data + 1) );
  23.739 +		nz |= y;
  23.740 +		goto inc_pc_loop;
  23.741 +	
  23.742 +	case 0xDA: // MOVW dp,YA
  23.743 +		WRITE_DP( -1, data, a );
  23.744 +		WRITE_DP( 0, (uint8_t) (data + 1), y + no_read_before_write  );
  23.745 +		goto inc_pc_loop;
  23.746 +	
  23.747 +// 9. 16-BIT OPERATION COMMANDS
  23.748 +
  23.749 +	case 0x3A: // INCW dp
  23.750 +	case 0x1A:{// DECW dp
  23.751 +		int temp;
  23.752 +		// low byte
  23.753 +		data += dp;
  23.754 +		temp = READ( -3, data );
  23.755 +		temp += (opcode >> 4 & 2) - 1; // +1 for INCW, -1 for DECW
  23.756 +		nz = ((temp >> 1) | temp) & 0x7F;
  23.757 +		WRITE( -2, data, /*(uint8_t)*/ temp );
  23.758 +		
  23.759 +		// high byte
  23.760 +		data = (uint8_t) (data + 1) + dp;
  23.761 +		temp = (uint8_t) ((temp >> 8) + READ( -1, data ));
  23.762 +		nz |= temp;
  23.763 +		WRITE( 0, data, temp );
  23.764 +		
  23.765 +		goto inc_pc_loop;
  23.766 +	}
  23.767 +		
  23.768 +	case 0x7A: // ADDW YA,dp
  23.769 +	case 0x9A:{// SUBW YA,dp
  23.770 +		int lo = READ_DP( -2, data );
  23.771 +		int hi = READ_DP( 0, (uint8_t) (data + 1) );
  23.772 +		int result;
  23.773 +		int flags;
  23.774 +		
  23.775 +		if ( opcode == 0x9A ) // SUBW
  23.776 +		{
  23.777 +			lo = (lo ^ 0xFF) + 1;
  23.778 +			hi ^= 0xFF;
  23.779 +		}
  23.780 +		
  23.781 +		lo += a;
  23.782 +		result = y + hi + (lo >> 8);
  23.783 +		flags = hi ^ y ^ result;
  23.784 +		
  23.785 +		psw = (psw & ~(v40 | h08)) |
  23.786 +				(flags >> 1 & h08) |
  23.787 +				((flags + 0x80) >> 2 & v40);
  23.788 +		c = result;
  23.789 +		a = (uint8_t) lo;
  23.790 +		result = (uint8_t) result;
  23.791 +		y = result;
  23.792 +		nz = (((lo >> 1) | lo) & 0x7F) | result;
  23.793 +		
  23.794 +		goto inc_pc_loop;
  23.795 +	}
  23.796 +	
  23.797 +	case 0x5A: { // CMPW YA,dp
  23.798 +		int temp = a - READ_DP( -1, data );
  23.799 +		nz = ((temp >> 1) | temp) & 0x7F;
  23.800 +		temp = y + (temp >> 8);
  23.801 +		temp -= READ_DP( 0, (uint8_t) (data + 1) );
  23.802 +		nz |= temp;
  23.803 +		c  = ~temp;
  23.804 +		nz &= 0xFF;
  23.805 +		goto inc_pc_loop;
  23.806 +	}
  23.807 +	
  23.808 +// 10. MULTIPLICATION & DIVISON COMMANDS
  23.809 +
  23.810 +	case 0xCF: { // MUL YA
  23.811 +		unsigned temp = y * a;
  23.812 +		a = (uint8_t) temp;
  23.813 +		nz = ((temp >> 1) | temp) & 0x7F;
  23.814 +		y = temp >> 8;
  23.815 +		nz |= y;
  23.816 +		goto loop;
  23.817 +	}
  23.818 +	
  23.819 +	case 0x9E: // DIV YA,X
  23.820 +	{
  23.821 +		unsigned ya = y * 0x100 + a;
  23.822 +		
  23.823 +		psw &= ~(h08 | v40);
  23.824 +		
  23.825 +		if ( y >= x )
  23.826 +			psw |= v40;
  23.827 +		
  23.828 +		if ( (y & 15) >= (x & 15) )
  23.829 +			psw |= h08;
  23.830 +		
  23.831 +		if ( y < x * 2 )
  23.832 +		{
  23.833 +			a = ya / x;
  23.834 +			y = ya - a * x;
  23.835 +		}
  23.836 +		else
  23.837 +		{
  23.838 +			a = 255 - (ya - x * 0x200) / (256 - x);
  23.839 +			y = x   + (ya - x * 0x200) % (256 - x);
  23.840 +		}
  23.841 +		
  23.842 +		nz = (uint8_t) a;
  23.843 +		a = (uint8_t) a;
  23.844 +		
  23.845 +		goto loop;
  23.846 +	}
  23.847 +	
  23.848 +// 11. DECIMAL COMPENSATION COMMANDS
  23.849 +	
  23.850 +	case 0xDF: // DAA
  23.851 +		SUSPICIOUS_OPCODE( "DAA" );
  23.852 +		if ( a > 0x99 || c & 0x100 )
  23.853 +		{
  23.854 +			a += 0x60;
  23.855 +			c = 0x100;
  23.856 +		}
  23.857 +		
  23.858 +		if ( (a & 0x0F) > 9 || psw & h08 )
  23.859 +			a += 0x06;
  23.860 +		
  23.861 +		nz = a;
  23.862 +		a = (uint8_t) a;
  23.863 +		goto loop;
  23.864 +	
  23.865 +	case 0xBE: // DAS
  23.866 +		SUSPICIOUS_OPCODE( "DAS" );
  23.867 +		if ( a > 0x99 || !(c & 0x100) )
  23.868 +		{
  23.869 +			a -= 0x60;
  23.870 +			c = 0;
  23.871 +		}
  23.872 +		
  23.873 +		if ( (a & 0x0F) > 9 || !(psw & h08) )
  23.874 +			a -= 0x06;
  23.875 +		
  23.876 +		nz = a;
  23.877 +		a = (uint8_t) a;
  23.878 +		goto loop;
  23.879 +	
  23.880 +// 12. BRANCHING COMMANDS
  23.881 +
  23.882 +	case 0x2F: // BRA rel
  23.883 +		pc += (BOOST::int8_t) data;
  23.884 +		goto inc_pc_loop;
  23.885 +	
  23.886 +	case 0x30: // BMI
  23.887 +		BRANCH( (nz & nz_neg_mask) )
  23.888 +	
  23.889 +	case 0x10: // BPL
  23.890 +		BRANCH( !(nz & nz_neg_mask) )
  23.891 +	
  23.892 +	case 0xB0: // BCS
  23.893 +		BRANCH( c & 0x100 )
  23.894 +	
  23.895 +	case 0x90: // BCC
  23.896 +		BRANCH( !(c & 0x100) )
  23.897 +	
  23.898 +	case 0x70: // BVS
  23.899 +		BRANCH( psw & v40 )
  23.900 +	
  23.901 +	case 0x50: // BVC
  23.902 +		BRANCH( !(psw & v40) )
  23.903 +	
  23.904 +	#define CBRANCH( cond )\
  23.905 +	{\
  23.906 +		pc++;\
  23.907 +		if ( cond )\
  23.908 +			goto cbranch_taken_loop;\
  23.909 +		rel_time -= 2;\
  23.910 +		goto inc_pc_loop;\
  23.911 +	}
  23.912 +	
  23.913 +	case 0x03: // BBS dp.bit,rel
  23.914 +	case 0x23:
  23.915 +	case 0x43:
  23.916 +	case 0x63:
  23.917 +	case 0x83:
  23.918 +	case 0xA3:
  23.919 +	case 0xC3:
  23.920 +	case 0xE3:
  23.921 +		CBRANCH( READ_DP( -4, data ) >> (opcode >> 5) & 1 )
  23.922 +	
  23.923 +	case 0x13: // BBC dp.bit,rel
  23.924 +	case 0x33:
  23.925 +	case 0x53:
  23.926 +	case 0x73:
  23.927 +	case 0x93:
  23.928 +	case 0xB3:
  23.929 +	case 0xD3:
  23.930 +	case 0xF3:
  23.931 +		CBRANCH( !(READ_DP( -4, data ) >> (opcode >> 5) & 1) )
  23.932 +	
  23.933 +	case 0xDE: // CBNE dp+X,rel
  23.934 +		data = (uint8_t) (data + x);
  23.935 +		// fall through
  23.936 +	case 0x2E:{// CBNE dp,rel
  23.937 +		int temp;
  23.938 +		// 61% from timer
  23.939 +		READ_DP_TIMER( -4, data, temp );
  23.940 +		CBRANCH( temp != a )
  23.941 +	}
  23.942 +	
  23.943 +	case 0x6E: { // DBNZ dp,rel
  23.944 +		unsigned temp = READ_DP( -4, data ) - 1;
  23.945 +		WRITE_DP( -3, (uint8_t) data, /*(uint8_t)*/ temp + no_read_before_write  );
  23.946 +		CBRANCH( temp )
  23.947 +	}
  23.948 +	
  23.949 +	case 0xFE: // DBNZ Y,rel
  23.950 +		y = (uint8_t) (y - 1);
  23.951 +		BRANCH( y )
  23.952 +	
  23.953 +	case 0x1F: // JMP [abs+X]
  23.954 +		SET_PC( READ_PC16( pc ) + x );
  23.955 +		// fall through
  23.956 +	case 0x5F: // JMP abs
  23.957 +		SET_PC( READ_PC16( pc ) );
  23.958 +		goto loop;
  23.959 +	
  23.960 +// 13. SUB-ROUTINE CALL RETURN COMMANDS
  23.961 +	
  23.962 +	case 0x0F:{// BRK
  23.963 +		int temp;
  23.964 +		int ret_addr = GET_PC();
  23.965 +		SUSPICIOUS_OPCODE( "BRK" );
  23.966 +		SET_PC( READ_PROG16( 0xFFDE ) ); // vector address verified
  23.967 +		PUSH16( ret_addr );
  23.968 +		GET_PSW( temp );
  23.969 +		psw = (psw | b10) & ~i04;
  23.970 +		PUSH( temp );
  23.971 +		goto loop;
  23.972 +	}
  23.973 +	
  23.974 +	case 0x4F:{// PCALL offset
  23.975 +		int ret_addr = GET_PC() + 1;
  23.976 +		SET_PC( 0xFF00 | data );
  23.977 +		PUSH16( ret_addr );
  23.978 +		goto loop;
  23.979 +	}
  23.980 +	
  23.981 +	case 0x01: // TCALL n
  23.982 +	case 0x11:
  23.983 +	case 0x21:
  23.984 +	case 0x31:
  23.985 +	case 0x41:
  23.986 +	case 0x51:
  23.987 +	case 0x61:
  23.988 +	case 0x71:
  23.989 +	case 0x81:
  23.990 +	case 0x91:
  23.991 +	case 0xA1:
  23.992 +	case 0xB1:
  23.993 +	case 0xC1:
  23.994 +	case 0xD1:
  23.995 +	case 0xE1:
  23.996 +	case 0xF1: {
  23.997 +		int ret_addr = GET_PC();
  23.998 +		SET_PC( READ_PROG16( 0xFFDE - (opcode >> 3) ) );
  23.999 +		PUSH16( ret_addr );
 23.1000 +		goto loop;
 23.1001 +	}
 23.1002 +	
 23.1003 +// 14. STACK OPERATION COMMANDS
 23.1004 +
 23.1005 +	{
 23.1006 +		int temp;
 23.1007 +	case 0x7F: // RET1
 23.1008 +		temp = *sp;
 23.1009 +		SET_PC( GET_LE16( sp + 1 ) );
 23.1010 +		sp += 3;
 23.1011 +		goto set_psw;
 23.1012 +	case 0x8E: // POP PSW
 23.1013 +		POP( temp );
 23.1014 +	set_psw:
 23.1015 +		SET_PSW( temp );
 23.1016 +		goto loop;
 23.1017 +	}
 23.1018 +	
 23.1019 +	case 0x0D: { // PUSH PSW
 23.1020 +		int temp;
 23.1021 +		GET_PSW( temp );
 23.1022 +		PUSH( temp );
 23.1023 +		goto loop;
 23.1024 +	}
 23.1025 +
 23.1026 +	case 0x2D: // PUSH A
 23.1027 +		PUSH( a );
 23.1028 +		goto loop;
 23.1029 +	
 23.1030 +	case 0x4D: // PUSH X
 23.1031 +		PUSH( x );
 23.1032 +		goto loop;
 23.1033 +	
 23.1034 +	case 0x6D: // PUSH Y
 23.1035 +		PUSH( y );
 23.1036 +		goto loop;
 23.1037 +	
 23.1038 +	case 0xAE: // POP A
 23.1039 +		POP( a );
 23.1040 +		goto loop;
 23.1041 +	
 23.1042 +	case 0xCE: // POP X
 23.1043 +		POP( x );
 23.1044 +		goto loop;
 23.1045 +	
 23.1046 +	case 0xEE: // POP Y
 23.1047 +		POP( y );
 23.1048 +		goto loop;
 23.1049 +	
 23.1050 +// 15. BIT OPERATION COMMANDS
 23.1051 +
 23.1052 +	case 0x02: // SET1
 23.1053 +	case 0x22:
 23.1054 +	case 0x42:
 23.1055 +	case 0x62:
 23.1056 +	case 0x82:
 23.1057 +	case 0xA2:
 23.1058 +	case 0xC2:
 23.1059 +	case 0xE2:
 23.1060 +	case 0x12: // CLR1
 23.1061 +	case 0x32:
 23.1062 +	case 0x52:
 23.1063 +	case 0x72:
 23.1064 +	case 0x92:
 23.1065 +	case 0xB2:
 23.1066 +	case 0xD2:
 23.1067 +	case 0xF2: {
 23.1068 +		int bit = 1 << (opcode >> 5);
 23.1069 +		int mask = ~bit;
 23.1070 +		if ( opcode & 0x10 )
 23.1071 +			bit = 0;
 23.1072 +		data += dp;
 23.1073 +		WRITE( 0, data, (READ( -1, data ) & mask) | bit );
 23.1074 +		goto inc_pc_loop;
 23.1075 +	}
 23.1076 +		
 23.1077 +	case 0x0E: // TSET1 abs
 23.1078 +	case 0x4E: // TCLR1 abs
 23.1079 +		data = READ_PC16( pc );
 23.1080 +		pc += 2;
 23.1081 +		{
 23.1082 +			unsigned temp = READ( -2, data );
 23.1083 +			nz = (uint8_t) (a - temp);
 23.1084 +			temp &= ~a;
 23.1085 +			if ( opcode == 0x0E )
 23.1086 +				temp |= a;
 23.1087 +			WRITE( 0, data, temp );
 23.1088 +		}
 23.1089 +		goto loop;
 23.1090 +	
 23.1091 +	case 0x4A: // AND1 C,mem.bit
 23.1092 +		c &= MEM_BIT( 0 );
 23.1093 +		pc += 2;
 23.1094 +		goto loop;
 23.1095 +	
 23.1096 +	case 0x6A: // AND1 C,/mem.bit
 23.1097 +		c &= ~MEM_BIT( 0 );
 23.1098 +		pc += 2;
 23.1099 +		goto loop;
 23.1100 +	
 23.1101 +	case 0x0A: // OR1 C,mem.bit
 23.1102 +		c |= MEM_BIT( -1 );
 23.1103 +		pc += 2;
 23.1104 +		goto loop;
 23.1105 +	
 23.1106 +	case 0x2A: // OR1 C,/mem.bit
 23.1107 +		c |= ~MEM_BIT( -1 );
 23.1108 +		pc += 2;
 23.1109 +		goto loop;
 23.1110 +	
 23.1111 +	case 0x8A: // EOR1 C,mem.bit
 23.1112 +		c ^= MEM_BIT( -1 );
 23.1113 +		pc += 2;
 23.1114 +		goto loop;
 23.1115 +	
 23.1116 +	case 0xEA: // NOT1 mem.bit
 23.1117 +		data = READ_PC16( pc );
 23.1118 +		pc += 2;
 23.1119 +		{
 23.1120 +			unsigned temp = READ( -1, data & 0x1FFF );
 23.1121 +			temp ^= 1 << (data >> 13);
 23.1122 +			WRITE( 0, data & 0x1FFF, temp );
 23.1123 +		}
 23.1124 +		goto loop;
 23.1125 +	
 23.1126 +	case 0xCA: // MOV1 mem.bit,C
 23.1127 +		data = READ_PC16( pc );
 23.1128 +		pc += 2;
 23.1129 +		{
 23.1130 +			unsigned temp = READ( -2, data & 0x1FFF );
 23.1131 +			unsigned bit = data >> 13;
 23.1132 +			temp = (temp & ~(1 << bit)) | ((c >> 8 & 1) << bit);
 23.1133 +			WRITE( 0, data & 0x1FFF, temp + no_read_before_write  );
 23.1134 +		}
 23.1135 +		goto loop;
 23.1136 +	
 23.1137 +	case 0xAA: // MOV1 C,mem.bit
 23.1138 +		c = MEM_BIT( 0 );
 23.1139 +		pc += 2;
 23.1140 +		goto loop;
 23.1141 +	
 23.1142 +// 16. PROGRAM PSW FLAG OPERATION COMMANDS
 23.1143 +
 23.1144 +	case 0x60: // CLRC
 23.1145 +		c = 0;
 23.1146 +		goto loop;
 23.1147 +		
 23.1148 +	case 0x80: // SETC
 23.1149 +		c = ~0;
 23.1150 +		goto loop;
 23.1151 +	
 23.1152 +	case 0xED: // NOTC
 23.1153 +		c ^= 0x100;
 23.1154 +		goto loop;
 23.1155 +		
 23.1156 +	case 0xE0: // CLRV
 23.1157 +		psw &= ~(v40 | h08);
 23.1158 +		goto loop;
 23.1159 +	
 23.1160 +	case 0x20: // CLRP
 23.1161 +		dp = 0;
 23.1162 +		goto loop;
 23.1163 +	
 23.1164 +	case 0x40: // SETP
 23.1165 +		dp = 0x100;
 23.1166 +		goto loop;
 23.1167 +	
 23.1168 +	case 0xA0: // EI
 23.1169 +		SUSPICIOUS_OPCODE( "EI" );
 23.1170 +		psw |= i04;
 23.1171 +		goto loop;
 23.1172 +	
 23.1173 +	case 0xC0: // DI
 23.1174 +		SUSPICIOUS_OPCODE( "DI" );
 23.1175 +		psw &= ~i04;
 23.1176 +		goto loop;
 23.1177 +	
 23.1178 +// 17. OTHER COMMANDS
 23.1179 +
 23.1180 +	case 0x00: // NOP
 23.1181 +		goto loop;
 23.1182 +	
 23.1183 +	case 0xFF:{// STOP
 23.1184 +		// handle PC wrap-around
 23.1185 +		unsigned addr = GET_PC() - 1;
 23.1186 +		if ( addr >= 0x10000 )
 23.1187 +		{
 23.1188 +			addr &= 0xFFFF;
 23.1189 +			SET_PC( addr );
 23.1190 +			dprintf( "SPC: PC wrapped around\n" );
 23.1191 +			goto loop;
 23.1192 +		}
 23.1193 +	}
 23.1194 +	// fall through
 23.1195 +	case 0xEF: // SLEEP
 23.1196 +		SUSPICIOUS_OPCODE( "STOP/SLEEP" );
 23.1197 +		--pc;
 23.1198 +		rel_time = 0;
 23.1199 +		m.cpu_error = "SPC emulation error";
 23.1200 +		goto stop;
 23.1201 +	} // switch
 23.1202 +	
 23.1203 +	assert( 0 ); // catch any unhandled instructions
 23.1204 +}   
 23.1205 +out_of_time:
 23.1206 +	rel_time -= m.cycle_table [*pc]; // undo partial execution of opcode
 23.1207 +stop:
 23.1208 +	
 23.1209 +	// Uncache registers
 23.1210 +	if ( GET_PC() >= 0x10000 )
 23.1211 +		dprintf( "SPC: PC wrapped around\n" );
 23.1212 +	m.cpu_regs.pc = (uint16_t) GET_PC();
 23.1213 +	m.cpu_regs.sp = ( uint8_t) GET_SP();
 23.1214 +	m.cpu_regs.a  = ( uint8_t) a;
 23.1215 +	m.cpu_regs.x  = ( uint8_t) x;
 23.1216 +	m.cpu_regs.y  = ( uint8_t) y;
 23.1217 +	{
 23.1218 +		int temp;
 23.1219 +		GET_PSW( temp );
 23.1220 +		m.cpu_regs.psw = (uint8_t) temp;
 23.1221 +	}
 23.1222 +}
 23.1223 +SPC_CPU_RUN_FUNC_END
    24.1 Binary file snes_spc/SPC_CPU.h.gch has changed
    25.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    25.2 +++ b/snes_spc/SPC_DSP.cpp	Fri Oct 21 05:53:11 2011 -0700
    25.3 @@ -0,0 +1,1018 @@
    25.4 +// snes_spc 0.9.0. http://www.slack.net/~ant/
    25.5 +
    25.6 +#include "SPC_DSP.h"
    25.7 +
    25.8 +#include "blargg_endian.h"
    25.9 +#include <string.h>
   25.10 +
   25.11 +/* Copyright (C) 2007 Shay Green. This module is free software; you
   25.12 +can redistribute it and/or modify it under the terms of the GNU Lesser
   25.13 +General Public License as published by the Free Software Foundation; either
   25.14 +version 2.1 of the License, or (at your option) any later version. This
   25.15 +module is distributed in the hope that it will be useful, but WITHOUT ANY
   25.16 +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   25.17 +FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
   25.18 +details. You should have received a copy of the GNU Lesser General Public
   25.19 +License along with this module; if not, write to the Free Software Foundation,
   25.20 +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
   25.21 +
   25.22 +#include "blargg_source.h"
   25.23 +
   25.24 +#ifdef BLARGG_ENABLE_OPTIMIZER
   25.25 +	#include BLARGG_ENABLE_OPTIMIZER
   25.26 +#endif
   25.27 +
   25.28 +#if INT_MAX < 0x7FFFFFFF
   25.29 +	#error "Requires that int type have at least 32 bits"
   25.30 +#endif
   25.31 +
   25.32 +// TODO: add to blargg_endian.h
   25.33 +#define GET_LE16SA( addr )      ((BOOST::int16_t) GET_LE16( addr ))
   25.34 +#define GET_LE16A( addr )       GET_LE16( addr )
   25.35 +#define SET_LE16A( addr, data ) SET_LE16( addr, data )
   25.36 +
   25.37 +static BOOST::uint8_t const initial_regs [SPC_DSP::register_count] =
   25.38 +{
   25.39 +	0x45,0x8B,0x5A,0x9A,0xE4,0x82,0x1B,0x78,0x00,0x00,0xAA,0x96,0x89,0x0E,0xE0,0x80,
   25.40 +	0x2A,0x49,0x3D,0xBA,0x14,0xA0,0xAC,0xC5,0x00,0x00,0x51,0xBB,0x9C,0x4E,0x7B,0xFF,
   25.41 +	0xF4,0xFD,0x57,0x32,0x37,0xD9,0x42,0x22,0x00,0x00,0x5B,0x3C,0x9F,0x1B,0x87,0x9A,
   25.42 +	0x6F,0x27,0xAF,0x7B,0xE5,0x68,0x0A,0xD9,0x00,0x00,0x9A,0xC5,0x9C,0x4E,0x7B,0xFF,
   25.43 +	0xEA,0x21,0x78,0x4F,0xDD,0xED,0x24,0x14,0x00,0x00,0x77,0xB1,0xD1,0x36,0xC1,0x67,
   25.44 +	0x52,0x57,0x46,0x3D,0x59,0xF4,0x87,0xA4,0x00,0x00,0x7E,0x44,0x9C,0x4E,0x7B,0xFF,
   25.45 +	0x75,0xF5,0x06,0x97,0x10,0xC3,0x24,0xBB,0x00,0x00,0x7B,0x7A,0xE0,0x60,0x12,0x0F,
   25.46 +	0xF7,0x74,0x1C,0xE5,0x39,0x3D,0x73,0xC1,0x00,0x00,0x7A,0xB3,0xFF,0x4E,0x7B,0xFF
   25.47 +};
   25.48 +
   25.49 +// if ( io < -32768 ) io = -32768;
   25.50 +// if ( io >  32767 ) io =  32767;
   25.51 +#define CLAMP16( io )\
   25.52 +{\
   25.53 +	if ( (int16_t) io != io )\
   25.54 +		io = (io >> 31) ^ 0x7FFF;\
   25.55 +}
   25.56 +
   25.57 +// Access global DSP register
   25.58 +#define REG(n)      m.regs [r_##n]
   25.59 +
   25.60 +// Access voice DSP register
   25.61 +#define VREG(r,n)   r [v_##n]
   25.62 +
   25.63 +#define WRITE_SAMPLES( l, r, out ) \
   25.64 +{\
   25.65 +	out [0] = l;\
   25.66 +	out [1] = r;\
   25.67 +	out += 2;\
   25.68 +	if ( out >= m.out_end )\
   25.69 +	{\
   25.70 +		check( out == m.out_end );\
   25.71 +		check( m.out_end != &m.extra [extra_size] || \
   25.72 +			(m.extra <= m.out_begin && m.extra < &m.extra [extra_size]) );\
   25.73 +		out       = m.extra;\
   25.74 +		m.out_end = &m.extra [extra_size];\
   25.75 +	}\
   25.76 +}\
   25.77 +
   25.78 +void SPC_DSP::set_output( sample_t* out, int size )
   25.79 +{
   25.80 +	require( (size & 1) == 0 ); // must be even
   25.81 +	if ( !out )
   25.82 +	{
   25.83 +		out  = m.extra;
   25.84 +		size = extra_size;
   25.85 +	}
   25.86 +	m.out_begin = out;
   25.87 +	m.out       = out;
   25.88 +	m.out_end   = out + size;
   25.89 +}
   25.90 +
   25.91 +// Volume registers and efb are signed! Easy to forget int8_t cast.
   25.92 +// Prefixes are to avoid accidental use of locals with same names.
   25.93 +
   25.94 +// Gaussian interpolation
   25.95 +
   25.96 +static short const gauss [512] =
   25.97 +{
   25.98 +   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
   25.99 +   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   2,   2,   2,   2,   2,
  25.100 +   2,   2,   3,   3,   3,   3,   3,   4,   4,   4,   4,   4,   5,   5,   5,   5,
  25.101 +   6,   6,   6,   6,   7,   7,   7,   8,   8,   8,   9,   9,   9,  10,  10,  10,
  25.102 +  11,  11,  11,  12,  12,  13,  13,  14,  14,  15,  15,  15,  16,  16,  17,  17,
  25.103 +  18,  19,  19,  20,  20,  21,  21,  22,  23,  23,  24,  24,  25,  26,  27,  27,
  25.104 +  28,  29,  29,  30,  31,  32,  32,  33,  34,  35,  36,  36,  37,  38,  39,  40,
  25.105 +  41,  42,  43,  44,  45,  46,  47,  48,  49,  50,  51,  52,  53,  54,  55,  56,
  25.106 +  58,  59,  60,  61,  62,  64,  65,  66,  67,  69,  70,  71,  73,  74,  76,  77,
  25.107 +  78,  80,  81,  83,  84,  86,  87,  89,  90,  92,  94,  95,  97,  99, 100, 102,
  25.108 + 104, 106, 107, 109, 111, 113, 115, 117, 118, 120, 122, 124, 126, 128, 130, 132,
  25.109 + 134, 137, 139, 141, 143, 145, 147, 150, 152, 154, 156, 159, 161, 163, 166, 168,
  25.110 + 171, 173, 175, 178, 180, 183, 186, 188, 191, 193, 196, 199, 201, 204, 207, 210,
  25.111 + 212, 215, 218, 221, 224, 227, 230, 233, 236, 239, 242, 245, 248, 251, 254, 257,
  25.112 + 260, 263, 267, 270, 273, 276, 280, 283, 286, 290, 293, 297, 300, 304, 307, 311,
  25.113 + 314, 318, 321, 325, 328, 332, 336, 339, 343, 347, 351, 354, 358, 362, 366, 370,
  25.114 + 374, 378, 381, 385, 389, 393, 397, 401, 405, 410, 414, 418, 422, 426, 430, 434,
  25.115 + 439, 443, 447, 451, 456, 460, 464, 469, 473, 477, 482, 486, 491, 495, 499, 504,
  25.116 + 508, 513, 517, 522, 527, 531, 536, 540, 545, 550, 554, 559, 563, 568, 573, 577,
  25.117 + 582, 587, 592, 596, 601, 606, 611, 615, 620, 625, 630, 635, 640, 644, 649, 654,
  25.118 + 659, 664, 669, 674, 678, 683, 688, 693, 698, 703, 708, 713, 718, 723, 728, 732,
  25.119 + 737, 742, 747, 752, 757, 762, 767, 772, 777, 782, 787, 792, 797, 802, 806, 811,
  25.120 + 816, 821, 826, 831, 836, 841, 846, 851, 855, 860, 865, 870, 875, 880, 884, 889,
  25.121 + 894, 899, 904, 908, 913, 918, 923, 927, 932, 937, 941, 946, 951, 955, 960, 965,
  25.122 + 969, 974, 978, 983, 988, 992, 997,1001,1005,1010,1014,1019,1023,1027,1032,1036,
  25.123 +1040,1045,1049,1053,1057,1061,1066,1070,1074,1078,1082,1086,1090,1094,1098,1102,
  25.124 +1106,1109,1113,1117,1121,1125,1128,1132,1136,1139,1143,1146,1150,1153,1157,1160,
  25.125 +1164,1167,1170,1174,1177,1180,1183,1186,1190,1193,1196,1199,1202,1205,1207,1210,
  25.126 +1213,1216,1219,1221,1224,1227,1229,1232,1234,1237,1239,1241,1244,1246,1248,1251,
  25.127 +1253,1255,1257,1259,1261,1263,1265,1267,1269,1270,1272,1274,1275,1277,1279,1280,
  25.128 +1282,1283,1284,1286,1287,1288,1290,1291,1292,1293,1294,1295,1296,1297,1297,1298,
  25.129 +1299,1300,1300,1301,1302,1302,1303,1303,1303,1304,1304,1304,1304,1304,1305,1305,
  25.130 +};
  25.131 +
  25.132 +inline int SPC_DSP::interpolate( voice_t const* v )
  25.133 +{
  25.134 +	// Make pointers into gaussian based on fractional position between samples
  25.135 +	int offset = v->interp_pos >> 4 & 0xFF;
  25.136 +	short const* fwd = gauss + 255 - offset;
  25.137 +	short const* rev = gauss       + offset; // mirror left half of gaussian
  25.138 +	
  25.139 +	int const* in = &v->buf [(v->interp_pos >> 12) + v->buf_pos];
  25.140 +	int out;
  25.141 +	out  = (fwd [  0] * in [0]) >> 11;
  25.142 +	out += (fwd [256] * in [1]) >> 11;
  25.143 +	out += (rev [256] * in [2]) >> 11;
  25.144 +	out = (int16_t) out;
  25.145 +	out += (rev [  0] * in [3]) >> 11;
  25.146 +	
  25.147 +	CLAMP16( out );
  25.148 +	out &= ~1;
  25.149 +	return out;
  25.150 +}
  25.151 +
  25.152 +
  25.153 +//// Counters
  25.154 +
  25.155 +int const simple_counter_range = 2048 * 5 * 3; // 30720
  25.156 +
  25.157 +static unsigned const counter_rates [32] =
  25.158 +{
  25.159 +   simple_counter_range + 1, // never fires
  25.160 +          2048, 1536,
  25.161 +	1280, 1024,  768,
  25.162 +	 640,  512,  384,
  25.163 +	 320,  256,  192,
  25.164 +	 160,  128,   96,
  25.165 +	  80,   64,   48,
  25.166 +	  40,   32,   24,
  25.167 +	  20,   16,   12,
  25.168 +	  10,    8,    6,
  25.169 +	   5,    4,    3,
  25.170 +	         2,
  25.171 +	         1
  25.172 +};
  25.173 +
  25.174 +static unsigned const counter_offsets [32] =
  25.175 +{
  25.176 +	  1, 0, 1040,
  25.177 +	536, 0, 1040,
  25.178 +	536, 0, 1040,
  25.179 +	536, 0, 1040,
  25.180 +	536, 0, 1040,
  25.181 +	536, 0, 1040,
  25.182 +	536, 0, 1040,
  25.183 +	536, 0, 1040,
  25.184 +	536, 0, 1040,
  25.185 +	536, 0, 1040,
  25.186 +	     0,
  25.187 +	     0
  25.188 +};
  25.189 +
  25.190 +inline void SPC_DSP::init_counter()
  25.191 +{
  25.192 +	m.counter = 0;
  25.193 +}
  25.194 +
  25.195 +inline void SPC_DSP::run_counters()
  25.196 +{
  25.197 +	if ( --m.counter < 0 )
  25.198 +		m.counter = simple_counter_range - 1;
  25.199 +}
  25.200 +
  25.201 +inline unsigned SPC_DSP::read_counter( int rate )
  25.202 +{
  25.203 +	return ((unsigned) m.counter + counter_offsets [rate]) % counter_rates [rate];
  25.204 +}
  25.205 +
  25.206 +
  25.207 +//// Envelope
  25.208 +
  25.209 +inline void SPC_DSP::run_envelope( voice_t* const v )
  25.210 +{
  25.211 +	int env = v->env;
  25.212 +	if ( v->env_mode == env_release ) // 60%
  25.213 +	{
  25.214 +		if ( (env -= 0x8) < 0 )
  25.215 +			env = 0;
  25.216 +		v->env = env;
  25.217 +	}
  25.218 +	else
  25.219 +	{
  25.220 +		int rate;
  25.221 +		int env_data = VREG(v->regs,adsr1);
  25.222 +		if ( m.t_adsr0 & 0x80 ) // 99% ADSR
  25.223 +		{
  25.224 +			if ( v->env_mode >= env_decay ) // 99%
  25.225 +			{
  25.226 +				env--;
  25.227 +				env -= env >> 8;
  25.228 +				rate = env_data & 0x1F;
  25.229 +				if ( v->env_mode == env_decay ) // 1%
  25.230 +					rate = (m.t_adsr0 >> 3 & 0x0E) + 0x10;
  25.231 +			}
  25.232 +			else // env_attack
  25.233 +			{
  25.234 +				rate = (m.t_adsr0 & 0x0F) * 2 + 1;
  25.235 +				env += rate < 31 ? 0x20 : 0x400;
  25.236 +			}
  25.237 +		}
  25.238 +		else // GAIN
  25.239 +		{
  25.240 +			int mode;
  25.241 +			env_data = VREG(v->regs,gain);
  25.242 +			mode = env_data >> 5;
  25.243 +			if ( mode < 4 ) // direct
  25.244 +			{
  25.245 +				env = env_data * 0x10;
  25.246 +				rate = 31;
  25.247 +			}
  25.248 +			else
  25.249 +			{
  25.250 +				rate = env_data & 0x1F;
  25.251 +				if ( mode == 4 ) // 4: linear decrease
  25.252 +				{
  25.253 +					env -= 0x20;
  25.254 +				}
  25.255 +				else if ( mode < 6 ) // 5: exponential decrease
  25.256 +				{
  25.257 +					env--;
  25.258 +					env -= env >> 8;
  25.259 +				}
  25.260 +				else // 6,7: linear increase
  25.261 +				{
  25.262 +					env += 0x20;
  25.263 +					if ( mode > 6 && (unsigned) v->hidden_env >= 0x600 )
  25.264 +						env += 0x8 - 0x20; // 7: two-slope linear increase
  25.265 +				}
  25.266 +			}
  25.267 +		}
  25.268 +		
  25.269 +		// Sustain level
  25.270 +		if ( (env >> 8) == (env_data >> 5) && v->env_mode == env_decay )
  25.271 +			v->env_mode = env_sustain;
  25.272 +		
  25.273 +		v->hidden_env = env;
  25.274 +		
  25.275 +		// unsigned cast because linear decrease going negative also triggers this
  25.276 +		if ( (unsigned) env > 0x7FF )
  25.277 +		{
  25.278 +			env = (env < 0 ? 0 : 0x7FF);
  25.279 +			if ( v->env_mode == env_attack )
  25.280 +				v->env_mode = env_decay;
  25.281 +		}
  25.282 +		
  25.283 +		if ( !read_counter( rate ) )
  25.284 +			v->env = env; // nothing else is controlled by the counter
  25.285 +	}
  25.286 +}
  25.287 +
  25.288 +
  25.289 +//// BRR Decoding
  25.290 +
  25.291 +inline void SPC_DSP::decode_brr( voice_t* v )
  25.292 +{
  25.293 +	// Arrange the four input nybbles in 0xABCD order for easy decoding
  25.294 +	int nybbles = m.t_brr_byte * 0x100 + m.ram [(v->brr_addr + v->brr_offset + 1) & 0xFFFF];
  25.295 +	
  25.296 +	int const header = m.t_brr_header;
  25.297 +	
  25.298 +	// Write to next four samples in circular buffer
  25.299 +	int* pos = &v->buf [v->buf_pos];
  25.300 +	int* end;
  25.301 +	if ( (v->buf_pos += 4) >= brr_buf_size )
  25.302 +		v->buf_pos = 0;
  25.303 +	
  25.304 +	// Decode four samples
  25.305 +	for ( end = pos + 4; pos < end; pos++, nybbles <<= 4 )
  25.306 +	{
  25.307 +		// Extract nybble and sign-extend
  25.308 +		int s = (int16_t) nybbles >> 12;
  25.309 +		
  25.310 +		// Shift sample based on header
  25.311 +		int const shift = header >> 4;
  25.312 +		s = (s << shift) >> 1;
  25.313 +		if ( shift >= 0xD ) // handle invalid range
  25.314 +			s = (s >> 25) << 11; // same as: s = (s < 0 ? -0x800 : 0)
  25.315 +		
  25.316 +		// Apply IIR filter (8 is the most commonly used)
  25.317 +		int const filter = header & 0x0C;
  25.318 +		int const p1 = pos [brr_buf_size - 1];
  25.319 +		int const p2 = pos [brr_buf_size - 2] >> 1;
  25.320 +		if ( filter >= 8 )
  25.321 +		{
  25.322 +			s += p1;
  25.323 +			s -= p2;
  25.324 +			if ( filter == 8 ) // s += p1 * 0.953125 - p2 * 0.46875
  25.325 +			{
  25.326 +				s += p2 >> 4;
  25.327 +				s += (p1 * -3) >> 6;
  25.328 +			}
  25.329 +			else // s += p1 * 0.8984375 - p2 * 0.40625
  25.330 +			{
  25.331 +				s += (p1 * -13) >> 7;
  25.332 +				s += (p2 * 3) >> 4;
  25.333 +			}
  25.334 +		}
  25.335 +		else if ( filter ) // s += p1 * 0.46875
  25.336 +		{
  25.337 +			s += p1 >> 1;
  25.338 +			s += (-p1) >> 5;
  25.339 +		}
  25.340 +		
  25.341 +		// Adjust and write sample
  25.342 +		CLAMP16( s );
  25.343 +		s = (int16_t) (s * 2);
  25.344 +		pos [brr_buf_size] = pos [0] = s; // second copy simplifies wrap-around
  25.345 +	}
  25.346 +}
  25.347 +
  25.348 +
  25.349 +//// Misc
  25.350 +
  25.351 +#define MISC_CLOCK( n ) inline void SPC_DSP::misc_##n()
  25.352 +
  25.353 +MISC_CLOCK( 27 )
  25.354 +{
  25.355 +	m.t_pmon = REG(pmon) & 0xFE; // voice 0 doesn't support PMON
  25.356 +}
  25.357 +MISC_CLOCK( 28 )
  25.358 +{
  25.359 +	m.t_non = REG(non);
  25.360 +	m.t_eon = REG(eon);
  25.361 +	m.t_dir = REG(dir);
  25.362 +}
  25.363 +MISC_CLOCK( 29 )
  25.364 +{
  25.365 +	if ( (m.every_other_sample ^= 1) != 0 )
  25.366 +		m.new_kon &= ~m.kon; // clears KON 63 clocks after it was last read
  25.367 +}
  25.368 +MISC_CLOCK( 30 )
  25.369 +{
  25.370 +	if ( m.every_other_sample )
  25.371 +	{
  25.372 +		m.kon    = m.new_kon;
  25.373 +		m.t_koff = REG(koff) | m.mute_mask; 
  25.374 +	}
  25.375 +	
  25.376 +	run_counters();
  25.377 +	
  25.378 +	// Noise
  25.379 +	if ( !read_counter( REG(flg) & 0x1F ) )
  25.380 +	{
  25.381 +		int feedback = (m.noise << 13) ^ (m.noise << 14);
  25.382 +		m.noise = (feedback & 0x4000) ^ (m.noise >> 1);
  25.383 +	}
  25.384 +}
  25.385 +
  25.386 +
  25.387 +//// Voices
  25.388 +
  25.389 +#define VOICE_CLOCK( n ) void SPC_DSP::voice_##n( voice_t* const v )
  25.390 +
  25.391 +inline VOICE_CLOCK( V1 )
  25.392 +{
  25.393 +	m.t_dir_addr = m.t_dir * 0x100 + m.t_srcn * 4;
  25.394 +	m.t_srcn = VREG(v->regs,srcn);
  25.395 +}
  25.396 +inline VOICE_CLOCK( V2 )
  25.397 +{
  25.398 +	// Read sample pointer (ignored if not needed)
  25.399 +	uint8_t const* entry = &m.ram [m.t_dir_addr];
  25.400 +	if ( !v->kon_delay )
  25.401 +		entry += 2;
  25.402 +	m.t_brr_next_addr = GET_LE16A( entry );
  25.403 +	
  25.404 +	m.t_adsr0 = VREG(v->regs,adsr0);
  25.405 +	
  25.406 +	// Read pitch, spread over two clocks
  25.407 +	m.t_pitch = VREG(v->regs,pitchl);
  25.408 +}
  25.409 +inline VOICE_CLOCK( V3a )
  25.410 +{
  25.411 +	m.t_pitch += (VREG(v->regs,pitchh) & 0x3F) << 8;
  25.412 +}
  25.413 +inline VOICE_CLOCK( V3b )
  25.414 +{
  25.415 +	// Read BRR header and byte
  25.416 +	m.t_brr_byte   = m.ram [(v->brr_addr + v->brr_offset) & 0xFFFF];
  25.417 +	m.t_brr_header = m.ram [v->brr_addr]; // brr_addr doesn't need masking
  25.418 +}
  25.419 +VOICE_CLOCK( V3c )
  25.420 +{
  25.421 +	// Pitch modulation using previous voice's output
  25.422 +	if ( m.t_pmon & v->vbit )
  25.423 +		m.t_pitch += ((m.t_output >> 5) * m.t_pitch) >> 10;
  25.424 +	
  25.425 +	if ( v->kon_delay )
  25.426 +	{
  25.427 +		// Get ready to start BRR decoding on next sample
  25.428 +		if ( v->kon_delay == 5 )
  25.429 +		{
  25.430 +			v->brr_addr    = m.t_brr_next_addr;
  25.431 +			v->brr_offset  = 1;
  25.432 +			v->buf_pos     = 0;
  25.433 +			m.t_brr_header = 0; // header is ignored on this sample
  25.434 +			m.kon_check    = true;
  25.435 +		}
  25.436 +		
  25.437 +		// Envelope is never run during KON
  25.438 +		v->env        = 0;
  25.439 +		v->hidden_env = 0;
  25.440 +		
  25.441 +		// Disable BRR decoding until last three samples
  25.442 +		v->interp_pos = 0;
  25.443 +		if ( --v->kon_delay & 3 )
  25.444 +			v->interp_pos = 0x4000;
  25.445 +		
  25.446 +		// Pitch is never added during KON
  25.447 +		m.t_pitch = 0;
  25.448 +	}
  25.449 +	
  25.450 +	// Gaussian interpolation
  25.451 +	{
  25.452 +		int output = interpolate( v );
  25.453 +		
  25.454 +		// Noise
  25.455 +		if ( m.t_non & v->vbit )
  25.456 +			output = (int16_t) (m.noise * 2);
  25.457 +		
  25.458 +		// Apply envelope
  25.459 +		m.t_output = (output * v->env) >> 11 & ~1;
  25.460 +		v->t_envx_out = (uint8_t) (v->env >> 4);
  25.461 +	}
  25.462 +	
  25.463 +	// Immediate silence due to end of sample or soft reset
  25.464 +	if ( REG(flg) & 0x80 || (m.t_brr_header & 3) == 1 )
  25.465 +	{
  25.466 +		v->env_mode = env_release;
  25.467 +		v->env      = 0;
  25.468 +	}
  25.469 +	
  25.470 +	if ( m.every_other_sample )
  25.471 +	{
  25.472 +		// KOFF
  25.473 +		if ( m.t_koff & v->vbit )
  25.474 +			v->env_mode = env_release;
  25.475 +		
  25.476 +		// KON
  25.477 +		if ( m.kon & v->vbit )
  25.478 +		{
  25.479 +			v->kon_delay = 5;
  25.480 +			v->env_mode  = env_attack;
  25.481 +		}
  25.482 +	}
  25.483 +	
  25.484 +	// Run envelope for next sample
  25.485 +	if ( !v->kon_delay )
  25.486 +		run_envelope( v );
  25.487 +}
  25.488 +inline void SPC_DSP::voice_output( voice_t const* v, int ch )
  25.489 +{
  25.490 +	// Apply left/right volume
  25.491 +	int amp = (m.t_output * (int8_t) VREG(v->regs,voll + ch)) >> 7;
  25.492 +	
  25.493 +	// Add to output total
  25.494 +	m.t_main_out [ch] += amp;
  25.495 +	CLAMP16( m.t_main_out [ch] );
  25.496 +	
  25.497 +	// Optionally add to echo total
  25.498 +	if ( m.t_eon & v->vbit )
  25.499 +	{
  25.500 +		m.t_echo_out [ch] += amp;
  25.501 +		CLAMP16( m.t_echo_out [ch] );
  25.502 +	}
  25.503 +}
  25.504 +VOICE_CLOCK( V4 )
  25.505 +{
  25.506 +	// Decode BRR
  25.507 +	m.t_looped = 0;
  25.508 +	if ( v->interp_pos >= 0x4000 )
  25.509 +	{
  25.510 +		decode_brr( v );
  25.511 +		
  25.512 +		if ( (v->brr_offset += 2) >= brr_block_size )
  25.513 +		{
  25.514 +			// Start decoding next BRR block
  25.515 +			assert( v->brr_offset == brr_block_size );
  25.516 +			v->brr_addr = (v->brr_addr + brr_block_size) & 0xFFFF;
  25.517 +			if ( m.t_brr_header & 1 )
  25.518 +			{
  25.519 +				v->brr_addr = m.t_brr_next_addr;
  25.520 +				m.t_looped = v->vbit;
  25.521 +			}
  25.522 +			v->brr_offset = 1;
  25.523 +		}
  25.524 +	}
  25.525 +	
  25.526 +	// Apply pitch
  25.527 +	v->interp_pos = (v->interp_pos & 0x3FFF) + m.t_pitch;
  25.528 +	
  25.529 +	// Keep from getting too far ahead (when using pitch modulation)
  25.530 +	if ( v->interp_pos > 0x7FFF )
  25.531 +		v->interp_pos = 0x7FFF;
  25.532 +	
  25.533 +	// Output left
  25.534 +	voice_output( v, 0 );
  25.535 +}
  25.536 +inline VOICE_CLOCK( V5 )
  25.537 +{
  25.538 +	// Output right
  25.539 +	voice_output( v, 1 );
  25.540 +	
  25.541 +	// ENDX, OUTX, and ENVX won't update if you wrote to them 1-2 clocks earlier
  25.542 +	int endx_buf = REG(endx) | m.t_looped;
  25.543 +	
  25.544 +	// Clear bit in ENDX if KON just began
  25.545 +	if ( v->kon_delay == 5 )
  25.546 +		endx_buf &= ~v->vbit;
  25.547 +	m.endx_buf = (uint8_t) endx_buf;
  25.548 +}
  25.549 +inline VOICE_CLOCK( V6 )
  25.550 +{
  25.551 +	(void) v; // avoid compiler warning about unused v
  25.552 +	m.outx_buf = (uint8_t) (m.t_output >> 8);
  25.553 +}
  25.554 +inline VOICE_CLOCK( V7 )
  25.555 +{
  25.556 +	// Update ENDX
  25.557 +	REG(endx) = m.endx_buf;
  25.558 +	
  25.559 +	m.envx_buf = v->t_envx_out;
  25.560 +}
  25.561 +inline VOICE_CLOCK( V8 )
  25.562 +{
  25.563 +	// Update OUTX
  25.564 +	VREG(v->regs,outx) = m.outx_buf;
  25.565 +}
  25.566 +inline VOICE_CLOCK( V9 )
  25.567 +{
  25.568 +	// Update ENVX
  25.569 +	VREG(v->regs,envx) = m.envx_buf;
  25.570 +}
  25.571 +
  25.572 +// Most voices do all these in one clock, so make a handy composite
  25.573 +inline VOICE_CLOCK( V3 )
  25.574 +{
  25.575 +	voice_V3a( v );
  25.576 +	voice_V3b( v );
  25.577 +	voice_V3c( v );
  25.578 +}
  25.579 +
  25.580 +// Common combinations of voice steps on different voices. This greatly reduces
  25.581 +// code size and allows everything to be inlined in these functions.
  25.582 +VOICE_CLOCK(V7_V4_V1) { voice_V7(v); voice_V1(v+3); voice_V4(v+1); }
  25.583 +VOICE_CLOCK(V8_V5_V2) { voice_V8(v); voice_V5(v+1); voice_V2(v+2); }
  25.584 +VOICE_CLOCK(V9_V6_V3) { voice_V9(v); voice_V6(v+1); voice_V3(v+2); }
  25.585 +
  25.586 +
  25.587 +//// Echo
  25.588 +
  25.589 +// Current echo buffer pointer for left/right channel
  25.590 +#define ECHO_PTR( ch )      (&m.ram [m.t_echo_ptr + ch * 2])
  25.591 +
  25.592 +// Sample in echo history buffer, where 0 is the oldest
  25.593 +#define ECHO_FIR( i )       (m.echo_hist_pos [i])
  25.594 +
  25.595 +// Calculate FIR point for left/right channel
  25.596 +#define CALC_FIR( i, ch )   ((ECHO_FIR( i + 1 ) [ch] * (int8_t) REG(fir + i * 0x10)) >> 6)
  25.597 +
  25.598 +#define ECHO_CLOCK( n ) inline void SPC_DSP::echo_##n()
  25.599 +
  25.600 +inline void SPC_DSP::echo_read( int ch )
  25.601 +{
  25.602 +	int s = GET_LE16SA( ECHO_PTR( ch ) );
  25.603 +	// second copy simplifies wrap-around handling
  25.604 +	ECHO_FIR( 0 ) [ch] = ECHO_FIR( 8 ) [ch] = s >> 1;
  25.605 +}
  25.606 +
  25.607 +ECHO_CLOCK( 22 )
  25.608 +{
  25.609 +	// History
  25.610 +	if ( ++m.echo_hist_pos >= &m.echo_hist [echo_hist_size] )
  25.611 +		m.echo_hist_pos = m.echo_hist;
  25.612 +	
  25.613 +	m.t_echo_ptr = (m.t_esa * 0x100 + m.echo_offset) & 0xFFFF;
  25.614 +	echo_read( 0 );
  25.615 +	
  25.616 +	// FIR (using l and r temporaries below helps compiler optimize)
  25.617 +	int l = CALC_FIR( 0, 0 );
  25.618 +	int r = CALC_FIR( 0, 1 );
  25.619 +	
  25.620 +	m.t_echo_in [0] = l;
  25.621 +	m.t_echo_in [1] = r;
  25.622 +}
  25.623 +ECHO_CLOCK( 23 )
  25.624 +{
  25.625 +	int l = CALC_FIR( 1, 0 ) + CALC_FIR( 2, 0 );
  25.626 +	int r = CALC_FIR( 1, 1 ) + CALC_FIR( 2, 1 );
  25.627 +	
  25.628 +	m.t_echo_in [0] += l;
  25.629 +	m.t_echo_in [1] += r;
  25.630 +	
  25.631 +	echo_read( 1 );
  25.632 +}
  25.633 +ECHO_CLOCK( 24 )
  25.634 +{
  25.635 +	int l = CALC_FIR( 3, 0 ) + CALC_FIR( 4, 0 ) + CALC_FIR( 5, 0 );
  25.636 +	int r = CALC_FIR( 3, 1 ) + CALC_FIR( 4, 1 ) + CALC_FIR( 5, 1 );
  25.637 +	
  25.638 +	m.t_echo_in [0] += l;
  25.639 +	m.t_echo_in [1] += r;
  25.640 +}
  25.641 +ECHO_CLOCK( 25 )
  25.642 +{
  25.643 +	int l = m.t_echo_in [0] + CALC_FIR( 6, 0 );
  25.644 +	int r = m.t_echo_in [1] + CALC_FIR( 6, 1 );
  25.645 +	
  25.646 +	l = (int16_t) l;
  25.647 +	r = (int16_t) r;
  25.648 +	
  25.649 +	l += (int16_t) CALC_FIR( 7, 0 );
  25.650 +	r += (int16_t) CALC_FIR( 7, 1 );
  25.651 +	
  25.652 +	CLAMP16( l );
  25.653 +	CLAMP16( r );
  25.654 +	
  25.655 +	m.t_echo_in [0] = l & ~1;
  25.656 +	m.t_echo_in [1] = r & ~1;
  25.657 +}
  25.658 +inline int SPC_DSP::echo_output( int ch )
  25.659 +{
  25.660 +	int out = (int16_t) ((m.t_main_out [ch] * (int8_t) REG(mvoll + ch * 0x10)) >> 7) +
  25.661 +			(int16_t) ((m.t_echo_in [ch] * (int8_t) REG(evoll + ch * 0x10)) >> 7);
  25.662 +	CLAMP16( out );
  25.663 +	return out;
  25.664 +}
  25.665 +ECHO_CLOCK( 26 )
  25.666 +{
  25.667 +	// Left output volumes
  25.668 +	// (save sample for next clock so we can output both together)
  25.669 +	m.t_main_out [0] = echo_output( 0 );
  25.670 +	
  25.671 +	// Echo feedback
  25.672 +	int l = m.t_echo_out [0] + (int16_t) ((m.t_echo_in [0] * (int8_t) REG(efb)) >> 7);
  25.673 +	int r = m.t_echo_out [1] + (int16_t) ((m.t_echo_in [1] * (int8_t) REG(efb)) >> 7);
  25.674 +	
  25.675 +	CLAMP16( l );
  25.676 +	CLAMP16( r );
  25.677 +	
  25.678 +	m.t_echo_out [0] = l & ~1;
  25.679 +	m.t_echo_out [1] = r & ~1;
  25.680 +}
  25.681 +ECHO_CLOCK( 27 )
  25.682 +{
  25.683 +	// Output
  25.684 +	int l = m.t_main_out [0];
  25.685 +	int r = echo_output( 1 );
  25.686 +	m.t_main_out [0] = 0;
  25.687 +	m.t_main_out [1] = 0;
  25.688 +	
  25.689 +	// TODO: global muting isn't this simple (turns DAC on and off
  25.690 +	// or something, causing small ~37-sample pulse when first muted)
  25.691 +	if ( REG(flg) & 0x40 )
  25.692 +	{
  25.693 +		l = 0;
  25.694 +		r = 0;
  25.695 +	}
  25.696 +	
  25.697 +	// Output sample to DAC
  25.698 +	#ifdef SPC_DSP_OUT_HOOK
  25.699 +		SPC_DSP_OUT_HOOK( l, r );
  25.700 +	#else
  25.701 +		sample_t* out = m.out;
  25.702 +		WRITE_SAMPLES( l, r, out );
  25.703 +		m.out = out;
  25.704 +	#endif
  25.705 +}
  25.706 +ECHO_CLOCK( 28 )
  25.707 +{
  25.708 +	m.t_echo_enabled = REG(flg);
  25.709 +}
  25.710 +inline void SPC_DSP::echo_write( int ch )
  25.711 +{
  25.712 +	if ( !(m.t_echo_enabled & 0x20) )
  25.713 +		SET_LE16A( ECHO_PTR( ch ), m.t_echo_out [ch] );
  25.714 +	m.t_echo_out [ch] = 0;
  25.715 +}
  25.716 +ECHO_CLOCK( 29 )
  25.717 +{
  25.718 +	m.t_esa = REG(esa);
  25.719 +	
  25.720 +	if ( !m.echo_offset )
  25.721 +		m.echo_length = (REG(edl) & 0x0F) * 0x800;
  25.722 +	
  25.723 +	m.echo_offset += 4;
  25.724 +	if ( m.echo_offset >= m.echo_length )
  25.725 +		m.echo_offset = 0;
  25.726 +	
  25.727 +	// Write left echo
  25.728 +	echo_write( 0 );
  25.729 +	
  25.730 +	m.t_echo_enabled = REG(flg);
  25.731 +}
  25.732 +ECHO_CLOCK( 30 )
  25.733 +{
  25.734 +	// Write right echo
  25.735 +	echo_write( 1 );
  25.736 +}
  25.737 +
  25.738 +
  25.739 +//// Timing
  25.740 +
  25.741 +// Execute clock for a particular voice
  25.742 +#define V( clock, voice )   voice_##clock( &m.voices [voice] );
  25.743 +
  25.744 +/* The most common sequence of clocks uses composite operations
  25.745 +for efficiency. For example, the following are equivalent to the
  25.746 +individual steps on the right:
  25.747 +
  25.748 +V(V7_V4_V1,2) -> V(V7,2) V(V4,3) V(V1,5)
  25.749 +V(V8_V5_V2,2) -> V(V8,2) V(V5,3) V(V2,4)
  25.750 +V(V9_V6_V3,2) -> V(V9,2) V(V6,3) V(V3,4) */
  25.751 +
  25.752 +// Voice      0      1      2      3      4      5      6      7
  25.753 +#define GEN_DSP_TIMING \
  25.754 +PHASE( 0)  V(V5,0)V(V2,1)\
  25.755 +PHASE( 1)  V(V6,0)V(V3,1)\
  25.756 +PHASE( 2)  V(V7_V4_V1,0)\
  25.757 +PHASE( 3)  V(V8_V5_V2,0)\
  25.758 +PHASE( 4)  V(V9_V6_V3,0)\
  25.759 +PHASE( 5)         V(V7_V4_V1,1)\
  25.760 +PHASE( 6)         V(V8_V5_V2,1)\
  25.761 +PHASE( 7)         V(V9_V6_V3,1)\
  25.762 +PHASE( 8)                V(V7_V4_V1,2)\
  25.763 +PHASE( 9)                V(V8_V5_V2,2)\
  25.764 +PHASE(10)                V(V9_V6_V3,2)\
  25.765 +PHASE(11)                       V(V7_V4_V1,3)\
  25.766 +PHASE(12)                       V(V8_V5_V2,3)\
  25.767 +PHASE(13)                       V(V9_V6_V3,3)\
  25.768 +PHASE(14)                              V(V7_V4_V1,4)\
  25.769 +PHASE(15)                              V(V8_V5_V2,4)\
  25.770 +PHASE(16)                              V(V9_V6_V3,4)\
  25.771 +PHASE(17)  V(V1,0)                            V(V7,5)V(V4,6)\
  25.772 +PHASE(18)                                     V(V8_V5_V2,5)\
  25.773 +PHASE(19)                                     V(V9_V6_V3,5)\
  25.774 +PHASE(20)         V(V1,1)                            V(V7,6)V(V4,7)\
  25.775 +PHASE(21)                                            V(V8,6)V(V5,7)  V(V2,0)  /* t_brr_next_addr order dependency */\
  25.776 +PHASE(22)  V(V3a,0)                                  V(V9,6)V(V6,7)  echo_22();\
  25.777 +PHASE(23)                                                   V(V7,7)  echo_23();\
  25.778 +PHASE(24)                                                   V(V8,7)  echo_24();\
  25.779 +PHASE(25)  V(V3b,0)                                         V(V9,7)  echo_25();\
  25.780 +PHASE(26)                                                            echo_26();\
  25.781 +PHASE(27) misc_27();                                                 echo_27();\
  25.782 +PHASE(28) misc_28();                                                 echo_28();\
  25.783 +PHASE(29) misc_29();                                                 echo_29();\
  25.784 +PHASE(30) misc_30();V(V3c,0)                                         echo_30();\
  25.785 +PHASE(31)  V(V4,0)       V(V1,2)\
  25.786 +
  25.787 +#if !SPC_DSP_CUSTOM_RUN
  25.788 +
  25.789 +void SPC_DSP::run( int clocks_remain )
  25.790 +{
  25.791 +	require( clocks_remain > 0 );
  25.792 +	
  25.793 +	int const phase = m.phase;
  25.794 +	m.phase = (phase + clocks_remain) & 31;
  25.795 +	switch ( phase )
  25.796 +	{
  25.797 +	loop:
  25.798 +	
  25.799 +		#define PHASE( n ) if ( n && !--clocks_remain ) break; case n:
  25.800 +		GEN_DSP_TIMING
  25.801 +		#undef PHASE
  25.802 +	
  25.803 +		if ( --clocks_remain )
  25.804 +			goto loop;
  25.805 +	}
  25.806 +}
  25.807 +
  25.808 +#endif
  25.809 +
  25.810 +
  25.811 +//// Setup
  25.812 +
  25.813 +void SPC_DSP::init( void* ram_64k )
  25.814 +{
  25.815 +	m.ram = (uint8_t*) ram_64k;
  25.816 +	mute_voices( 0 );
  25.817 +	disable_surround( false );
  25.818 +	set_output( 0, 0 );
  25.819 +	reset();
  25.820 +	
  25.821 +	#ifndef NDEBUG
  25.822 +		// be sure this sign-extends
  25.823 +		assert( (int16_t) 0x8000 == -0x8000 );
  25.824 +		
  25.825 +		// be sure right shift preserves sign
  25.826 +		assert( (-1 >> 1) == -1 );
  25.827 +		
  25.828 +		// check clamp macro
  25.829 +		int i;
  25.830 +		i = +0x8000; CLAMP16( i ); assert( i == +0x7FFF );
  25.831 +		i = -0x8001; CLAMP16( i ); assert( i == -0x8000 );
  25.832 +		
  25.833 +		blargg_verify_byte_order();
  25.834 +	#endif
  25.835 +}
  25.836 +
  25.837 +void SPC_DSP::soft_reset_common()
  25.838 +{
  25.839 +	require( m.ram ); // init() must have been called already
  25.840 +	
  25.841 +	m.noise              = 0x4000;
  25.842 +	m.echo_hist_pos      = m.echo_hist;
  25.843 +	m.every_other_sample = 1;
  25.844 +	m.echo_offset        = 0;
  25.845 +	m.phase              = 0;
  25.846 +	
  25.847 +	init_counter();
  25.848 +}
  25.849 +
  25.850 +void SPC_DSP::soft_reset()
  25.851 +{
  25.852 +	REG(flg) = 0xE0;
  25.853 +	soft_reset_common();
  25.854 +}
  25.855 +
  25.856 +void SPC_DSP::load( uint8_t const regs [register_count] )
  25.857 +{
  25.858 +	memcpy( m.regs, regs, sizeof m.regs );
  25.859 +	memset( &m.regs [register_count], 0, offsetof (state_t,ram) - register_count );
  25.860 +	
  25.861 +	// Internal state
  25.862 +	for ( int i = voice_count; --i >= 0; )
  25.863 +	{
  25.864 +		voice_t* v = &m.voices [i];
  25.865 +		v->brr_offset = 1;
  25.866 +		v->vbit       = 1 << i;
  25.867 +		v->regs       = &m.regs [i * 0x10];
  25.868 +	}
  25.869 +	m.new_kon = REG(kon);
  25.870 +	m.t_dir   = REG(dir);
  25.871 +	m.t_esa   = REG(esa);
  25.872 +	
  25.873 +	soft_reset_common();
  25.874 +}
  25.875 +
  25.876 +void SPC_DSP::reset() { load( initial_regs ); }
  25.877 +
  25.878 +
  25.879 +//// State save/load
  25.880 +
  25.881 +#if !SPC_NO_COPY_STATE_FUNCS
  25.882 +
  25.883 +void SPC_State_Copier::copy( void* state, size_t size )
  25.884 +{
  25.885 +	func( buf, state, size );
  25.886 +}
  25.887 +
  25.888 +int SPC_State_Copier::copy_int( int state, int size )
  25.889 +{
  25.890 +	BOOST::uint8_t s [2];
  25.891 +	SET_LE16( s, state );
  25.892 +	func( buf, &s, size );
  25.893 +	return GET_LE16( s );
  25.894 +}
  25.895 +
  25.896 +void SPC_State_Copier::skip( int count )
  25.897 +{
  25.898 +	if ( count > 0 )
  25.899 +	{
  25.900 +		char temp [64];
  25.901 +		memset( temp, 0, sizeof temp );
  25.902 +		do
  25.903 +		{
  25.904 +			int n = sizeof temp;
  25.905 +			if ( n > count )
  25.906 +				n = count;
  25.907 +			count -= n;
  25.908 +			func( buf, temp, n );
  25.909 +		}
  25.910 +		while ( count );
  25.911 +	}
  25.912 +}
  25.913 +
  25.914 +void SPC_State_Copier::extra()
  25.915 +{
  25.916 +	int n = 0;
  25.917 +	SPC_State_Copier& copier = *this;
  25.918 +	SPC_COPY( uint8_t, n );
  25.919 +	skip( n );
  25.920 +}
  25.921 +
  25.922 +void SPC_DSP::copy_state( unsigned char** io, copy_func_t copy )
  25.923 +{
  25.924 +	SPC_State_Copier copier( io, copy );
  25.925 +	
  25.926 +	// DSP registers
  25.927 +	copier.copy( m.regs, register_count );
  25.928 +	
  25.929 +	// Internal state
  25.930 +	
  25.931 +	// Voices
  25.932 +	int i;
  25.933 +	for ( i = 0; i < voice_count; i++ )
  25.934 +	{
  25.935 +		voice_t* v = &m.voices [i];
  25.936 +		
  25.937 +		// BRR buffer
  25.938 +		int i;
  25.939 +		for ( i = 0; i < brr_buf_size; i++ )
  25.940 +		{
  25.941 +			int s = v->buf [i];
  25.942 +			SPC_COPY(  int16_t, s );
  25.943 +			v->buf [i] = v->buf [i + brr_buf_size] = s;
  25.944 +		}
  25.945 +		
  25.946 +		SPC_COPY( uint16_t, v->interp_pos );
  25.947 +		SPC_COPY( uint16_t, v->brr_addr );
  25.948 +		SPC_COPY( uint16_t, v->env );
  25.949 +		SPC_COPY(  int16_t, v->hidden_env );
  25.950 +		SPC_COPY(  uint8_t, v->buf_pos );
  25.951 +		SPC_COPY(  uint8_t, v->brr_offset );
  25.952 +		SPC_COPY(  uint8_t, v->kon_delay );
  25.953 +		{
  25.954 +			int m = v->env_mode;
  25.955 +			SPC_COPY(  uint8_t, m );
  25.956 +			v->env_mode = (enum env_mode_t) m;
  25.957 +		}
  25.958 +		SPC_COPY(  uint8_t, v->t_envx_out );
  25.959 +		
  25.960 +		copier.extra();
  25.961 +	}
  25.962 +	
  25.963 +	// Echo history
  25.964 +	for ( i = 0; i < echo_hist_size; i++ )
  25.965 +	{
  25.966 +		int j;
  25.967 +		for ( j = 0; j < 2; j++ )
  25.968 +		{
  25.969 +			int s = m.echo_hist_pos [i] [j];
  25.970 +			SPC_COPY( int16_t, s );
  25.971 +			m.echo_hist [i] [j] = s; // write back at offset 0
  25.972 +		}
  25.973 +	}
  25.974 +	m.echo_hist_pos = m.echo_hist;
  25.975 +	memcpy( &m.echo_hist [echo_hist_size], m.echo_hist, echo_hist_size * sizeof m.echo_hist [0] );
  25.976 +	
  25.977 +	// Misc
  25.978 +	SPC_COPY(  uint8_t, m.every_other_sample );
  25.979 +	SPC_COPY(  uint8_t, m.kon );
  25.980 +	
  25.981 +	SPC_COPY( uint16_t, m.noise );
  25.982 +	SPC_COPY( uint16_t, m.counter );
  25.983 +	SPC_COPY( uint16_t, m.echo_offset );
  25.984 +	SPC_COPY( uint16_t, m.echo_length );
  25.985 +	SPC_COPY(  uint8_t, m.phase );
  25.986 +	
  25.987 +	SPC_COPY(  uint8_t, m.new_kon );
  25.988 +	SPC_COPY(  uint8_t, m.endx_buf );
  25.989 +	SPC_COPY(  uint8_t, m.envx_buf );
  25.990 +	SPC_COPY(  uint8_t, m.outx_buf );
  25.991 +	
  25.992 +	SPC_COPY(  uint8_t, m.t_pmon );
  25.993 +	SPC_COPY(  uint8_t, m.t_non );
  25.994 +	SPC_COPY(  uint8_t, m.t_eon );
  25.995 +	SPC_COPY(  uint8_t, m.t_dir );
  25.996 +	SPC_COPY(  uint8_t, m.t_koff );
  25.997 +	
  25.998 +	SPC_COPY( uint16_t, m.t_brr_next_addr );
  25.999 +	SPC_COPY(  uint8_t, m.t_adsr0 );
 25.1000 +	SPC_COPY(  uint8_t, m.t_brr_header );
 25.1001 +	SPC_COPY(  uint8_t, m.t_brr_byte );
 25.1002 +	SPC_COPY(  uint8_t, m.t_srcn );
 25.1003 +	SPC_COPY(  uint8_t, m.t_esa );
 25.1004 +	SPC_COPY(  uint8_t, m.t_echo_enabled );
 25.1005 +	
 25.1006 +	SPC_COPY(  int16_t, m.t_main_out [0] );
 25.1007 +	SPC_COPY(  int16_t, m.t_main_out [1] );
 25.1008 +	SPC_COPY(  int16_t, m.t_echo_out [0] );
 25.1009 +	SPC_COPY(  int16_t, m.t_echo_out [1] );
 25.1010 +	SPC_COPY(  int16_t, m.t_echo_in  [0] );
 25.1011 +	SPC_COPY(  int16_t, m.t_echo_in  [1] );
 25.1012 +	
 25.1013 +	SPC_COPY( uint16_t, m.t_dir_addr );
 25.1014 +	SPC_COPY( uint16_t, m.t_pitch );
 25.1015 +	SPC_COPY(  int16_t, m.t_output );
 25.1016 +	SPC_COPY( uint16_t, m.t_echo_ptr );
 25.1017 +	SPC_COPY(  uint8_t, m.t_looped );
 25.1018 +	
 25.1019 +	copier.extra();
 25.1020 +}
 25.1021 +#endif
    26.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    26.2 +++ b/snes_spc/SPC_DSP.h	Fri Oct 21 05:53:11 2011 -0700
    26.3 @@ -0,0 +1,304 @@
    26.4 +// Highly accurate SNES SPC-700 DSP emulator
    26.5 +
    26.6 +// snes_spc 0.9.0
    26.7 +#ifndef SPC_DSP_H
    26.8 +#define SPC_DSP_H
    26.9 +
   26.10 +#include "blargg_common.h"
   26.11 +
   26.12 +extern "C" { typedef void (*dsp_copy_func_t)( unsigned char** io, void* state, size_t ); }
   26.13 +
   26.14 +class SPC_DSP {
   26.15 +public:
   26.16 +	typedef BOOST::uint8_t uint8_t;
   26.17 +	
   26.18 +// Setup
   26.19 +
   26.20 +	// Initializes DSP and has it use the 64K RAM provided
   26.21 +	void init( void* ram_64k );
   26.22 +
   26.23 +	// Sets destination for output samples. If out is NULL or out_size is 0,
   26.24 +	// doesn't generate any.
   26.25 +	typedef short sample_t;
   26.26 +	void set_output( sample_t* out, int out_size );
   26.27 +
   26.28 +	// Number of samples written to output since it was last set, always
   26.29 +	// a multiple of 2. Undefined if more samples were generated than
   26.30 +	// output buffer could hold.
   26.31 +	int sample_count() const;
   26.32 +
   26.33 +// Emulation
   26.34 +
   26.35 +	// Resets DSP to power-on state
   26.36 +	void reset();
   26.37 +
   26.38 +	// Emulates pressing reset switch on SNES
   26.39 +	void soft_reset();
   26.40 +	
   26.41 +	// Reads/writes DSP registers. For accuracy, you must first call run()
   26.42 +	// to catch the DSP up to present.
   26.43 +	int  read ( int addr ) const;
   26.44 +	void write( int addr, int data );
   26.45 +
   26.46 +	// Runs DSP for specified number of clocks (~1024000 per second). Every 32 clocks
   26.47 +	// a pair of samples is be generated.
   26.48 +	void run( int clock_count );
   26.49 +	
   26.50 +// Sound control
   26.51 +
   26.52 +	// Mutes voices corresponding to non-zero bits in mask (issues repeated KOFF events).
   26.53 +	// Reduces emulation accuracy.
   26.54 +	enum { voice_count = 8 };
   26.55 +	void mute_voices( int mask );
   26.56 +
   26.57 +// State
   26.58 +	
   26.59 +	// Resets DSP and uses supplied values to initialize registers
   26.60 +	enum { register_count = 128 };
   26.61 +	void load( uint8_t const regs [register_count] );
   26.62 +
   26.63 +	// Saves/loads exact emulator state
   26.64 +	enum { state_size = 640 }; // maximum space needed when saving
   26.65 +	typedef dsp_copy_func_t copy_func_t;
   26.66 +	void copy_state( unsigned char** io, copy_func_t );
   26.67 +
   26.68 +	// Returns non-zero if new key-on events occurred since last call
   26.69 +	bool check_kon();
   26.70 +	
   26.71 +// DSP register addresses
   26.72 +
   26.73 +	// Global registers
   26.74 +	enum {
   26.75 +	    r_mvoll = 0x0C, r_mvolr = 0x1C,
   26.76 +	    r_evoll = 0x2C, r_evolr = 0x3C,
   26.77 +	    r_kon   = 0x4C, r_koff  = 0x5C,
   26.78 +	    r_flg   = 0x6C, r_endx  = 0x7C,
   26.79 +	    r_efb   = 0x0D, r_pmon  = 0x2D,
   26.80 +	    r_non   = 0x3D, r_eon   = 0x4D,
   26.81 +	    r_dir   = 0x5D, r_esa   = 0x6D,
   26.82 +	    r_edl   = 0x7D,
   26.83 +	    r_fir   = 0x0F // 8 coefficients at 0x0F, 0x1F ... 0x7F
   26.84 +	};
   26.85 +
   26.86 +	// Voice registers
   26.87 +	enum {
   26.88 +		v_voll   = 0x00, v_volr   = 0x01,
   26.89 +		v_pitchl = 0x02, v_pitchh = 0x03,
   26.90 +		v_srcn   = 0x04, v_adsr0  = 0x05,
   26.91 +		v_adsr1  = 0x06, v_gain   = 0x07,
   26.92 +		v_envx   = 0x08, v_outx   = 0x09
   26.93 +	};
   26.94 +
   26.95 +public:
   26.96 +	enum { extra_size = 16 };
   26.97 +	sample_t* extra()               { return m.extra; }
   26.98 +	sample_t const* out_pos() const { return m.out; }
   26.99 +	void disable_surround( bool ) { } // not supported
  26.100 +public:
  26.101 +	BLARGG_DISABLE_NOTHROW
  26.102 +	
  26.103 +	typedef BOOST::int8_t   int8_t;
  26.104 +	typedef BOOST::int16_t int16_t;
  26.105 +	
  26.106 +	enum { echo_hist_size = 8 };
  26.107 +	
  26.108 +	enum env_mode_t { env_release, env_attack, env_decay, env_sustain };
  26.109 +	enum { brr_buf_size = 12 };
  26.110 +	struct voice_t
  26.111 +	{
  26.112 +		int buf [brr_buf_size*2];// decoded samples (twice the size to simplify wrap handling)
  26.113 +		int buf_pos;            // place in buffer where next samples will be decoded
  26.114 +		int interp_pos;         // relative fractional position in sample (0x1000 = 1.0)
  26.115 +		int brr_addr;           // address of current BRR block
  26.116 +		int brr_offset;         // current decoding offset in BRR block
  26.117 +		uint8_t* regs;          // pointer to voice's DSP registers
  26.118 +		int vbit;               // bitmask for voice: 0x01 for voice 0, 0x02 for voice 1, etc.
  26.119 +		int kon_delay;          // KON delay/current setup phase
  26.120 +		env_mode_t env_mode;
  26.121 +		int env;                // current envelope level
  26.122 +		int hidden_env;         // used by GAIN mode 7, very obscure quirk
  26.123 +		uint8_t t_envx_out;
  26.124 +	};
  26.125 +private:
  26.126 +	enum { brr_block_size = 9 };
  26.127 +	
  26.128 +	struct state_t
  26.129 +	{
  26.130 +		uint8_t regs [register_count];
  26.131 +		
  26.132 +		// Echo history keeps most recent 8 samples (twice the size to simplify wrap handling)
  26.133 +		int echo_hist [echo_hist_size * 2] [2];
  26.134 +		int (*echo_hist_pos) [2]; // &echo_hist [0 to 7]
  26.135 +		
  26.136 +		int every_other_sample; // toggles every sample
  26.137 +		int kon;                // KON value when last checked
  26.138 +		int noise;
  26.139 +		int counter;
  26.140 +		int echo_offset;        // offset from ESA in echo buffer
  26.141 +		int echo_length;        // number of bytes that echo_offset will stop at
  26.142 +		int phase;              // next clock cycle to run (0-31)
  26.143 +		bool kon_check;         // set when a new KON occurs
  26.144 +		
  26.145 +		// Hidden registers also written to when main register is written to
  26.146 +		int new_kon;
  26.147 +		uint8_t endx_buf;
  26.148 +		uint8_t envx_buf;
  26.149 +		uint8_t outx_buf;
  26.150 +		
  26.151 +		// Temporary state between clocks
  26.152 +		
  26.153 +		// read once per sample
  26.154 +		int t_pmon;
  26.155 +		int t_non;
  26.156 +		int t_eon;
  26.157 +		int t_dir;
  26.158 +		int t_koff;
  26.159 +		
  26.160 +		// read a few clocks ahead then used
  26.161 +		int t_brr_next_addr;
  26.162 +		int t_adsr0;
  26.163 +		int t_brr_header;
  26.164 +		int t_brr_byte;
  26.165 +		int t_srcn;
  26.166 +		int t_esa;
  26.167 +		int t_echo_enabled;
  26.168 +		
  26.169 +		// internal state that is recalculated every sample
  26.170 +		int t_dir_addr;
  26.171 +		int t_pitch;
  26.172 +		int t_output;
  26.173 +		int t_looped;
  26.174 +		int t_echo_ptr;
  26.175 +		
  26.176 +		// left/right sums
  26.177 +		int t_main_out [2];
  26.178 +		int t_echo_out [2];
  26.179 +		int t_echo_in  [2];
  26.180 +		
  26.181 +		voice_t voices [voice_count];
  26.182 +		
  26.183 +		// non-emulation state
  26.184 +		uint8_t* ram; // 64K shared RAM between DSP and SMP
  26.185 +		int mute_mask;
  26.186 +		sample_t* out;
  26.187 +		sample_t* out_end;
  26.188 +		sample_t* out_begin;
  26.189 +		sample_t extra [extra_size];
  26.190 +	};
  26.191 +	state_t m;
  26.192 +	
  26.193 +	void init_counter();
  26.194 +	void run_counters();
  26.195 +	unsigned read_counter( int rate );
  26.196 +	
  26.197 +	int  interpolate( voice_t const* v );
  26.198 +	void run_envelope( voice_t* const v );
  26.199 +	void decode_brr( voice_t* v );
  26.200 +
  26.201 +	void misc_27();
  26.202 +	void misc_28();
  26.203 +	void misc_29();
  26.204 +	void misc_30();
  26.205 +
  26.206 +	void voice_output( voice_t const* v, int ch );
  26.207 +	void voice_V1( voice_t* const );
  26.208 +	void voice_V2( voice_t* const );
  26.209 +	void voice_V3( voice_t* const );
  26.210 +	void voice_V3a( voice_t* const );
  26.211 +	void voice_V3b( voice_t* const );
  26.212 +	void voice_V3c( voice_t* const );
  26.213 +	void voice_V4( voice_t* const );
  26.214 +	void voice_V5( voice_t* const );
  26.215 +	void voice_V6( voice_t* const );
  26.216 +	void voice_V7( voice_t* const );
  26.217 +	void voice_V8( voice_t* const );
  26.218 +	void voice_V9( voice_t* const );
  26.219 +	void voice_V7_V4_V1( voice_t* const );
  26.220 +	void voice_V8_V5_V2( voice_t* const );
  26.221 +	void voice_V9_V6_V3( voice_t* const );
  26.222 +
  26.223 +	void echo_read( int ch );
  26.224 +	int  echo_output( int ch );
  26.225 +	void echo_write( int ch );
  26.226 +	void echo_22();
  26.227 +	void echo_23();
  26.228 +	void echo_24();
  26.229 +	void echo_25();
  26.230 +	void echo_26();
  26.231 +	void echo_27();
  26.232 +	void echo_28();
  26.233 +	void echo_29();
  26.234 +	void echo_30();
  26.235 +	
  26.236 +	void soft_reset_common();
  26.237 +};
  26.238 +
  26.239 +#include <assert.h>
  26.240 +
  26.241 +inline int SPC_DSP::sample_count() const { return m.out - m.out_begin; }
  26.242 +
  26.243 +inline int SPC_DSP::read( int addr ) const
  26.244 +{
  26.245 +	assert( (unsigned) addr < register_count );
  26.246 +	return m.regs [addr];
  26.247 +}
  26.248 +
  26.249 +inline void SPC_DSP::write( int addr, int data )
  26.250 +{
  26.251 +	assert( (unsigned) addr < register_count );
  26.252 +	
  26.253 +	m.regs [addr] = (uint8_t) data;
  26.254 +	switch ( addr & 0x0F )
  26.255 +	{
  26.256 +	case v_envx:
  26.257 +		m.envx_buf = (uint8_t) data;
  26.258 +		break;
  26.259 +		
  26.260 +	case v_outx:
  26.261 +		m.outx_buf = (uint8_t) data;
  26.262 +		break;
  26.263 +	
  26.264 +	case 0x0C:
  26.265 +		if ( addr == r_kon )
  26.266 +			m.new_kon = (uint8_t) data;
  26.267 +		
  26.268 +		if ( addr == r_endx ) // always cleared, regardless of data written
  26.269 +		{
  26.270 +			m.endx_buf = 0;
  26.271 +			m.regs [r_endx] = 0;
  26.272 +		}
  26.273 +		break;
  26.274 +	}
  26.275 +}
  26.276 +
  26.277 +inline void SPC_DSP::mute_voices( int mask ) { m.mute_mask = mask; }
  26.278 +
  26.279 +inline bool SPC_DSP::check_kon()
  26.280 +{
  26.281 +	bool old = m.kon_check;
  26.282 +	m.kon_check = 0;
  26.283 +	return old;
  26.284 +}
  26.285 +
  26.286 +#if !SPC_NO_COPY_STATE_FUNCS
  26.287 +
  26.288 +class SPC_State_Copier {
  26.289 +	SPC_DSP::copy_func_t func;
  26.290 +	unsigned char** buf;
  26.291 +public:
  26.292 +	SPC_State_Copier( unsigned char** p, SPC_DSP::copy_func_t f ) { func = f; buf = p; }
  26.293 +	void copy( void* state, size_t size );
  26.294 +	int copy_int( int state, int size );
  26.295 +	void skip( int count );
  26.296 +	void extra();
  26.297 +};
  26.298 +
  26.299 +#define SPC_COPY( type, state )\
  26.300 +{\
  26.301 +	state = (BOOST::type) copier.copy_int( state, sizeof (BOOST::type) );\
  26.302 +	assert( (BOOST::type) state == state );\
  26.303 +}
  26.304 +
  26.305 +#endif
  26.306 +
  26.307 +#endif
    27.1 Binary file snes_spc/SPC_DSP.h.gch has changed
    28.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    28.2 +++ b/snes_spc/SPC_Filter.cpp	Fri Oct 21 05:53:11 2011 -0700
    28.3 @@ -0,0 +1,68 @@
    28.4 +// snes_spc 0.9.0. http://www.slack.net/~ant/
    28.5 +
    28.6 +#include "SPC_Filter.h"
    28.7 +
    28.8 +#include <string.h>
    28.9 +
   28.10 +/* Copyright (C) 2007 Shay Green. This module is free software; you
   28.11 +can redistribute it and/or modify it under the terms of the GNU Lesser
   28.12 +General Public License as published by the Free Software Foundation; either
   28.13 +version 2.1 of the License, or (at your option) any later version. This
   28.14 +module is distributed in the hope that it will be useful, but WITHOUT ANY
   28.15 +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   28.16 +FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
   28.17 +details. You should have received a copy of the GNU Lesser General Public
   28.18 +License along with this module; if not, write to the Free Software Foundation,
   28.19 +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
   28.20 +
   28.21 +#include "blargg_source.h"
   28.22 +
   28.23 +void SPC_Filter::clear() { memset( ch, 0, sizeof ch ); }
   28.24 +
   28.25 +SPC_Filter::SPC_Filter()
   28.26 +{
   28.27 +	gain = gain_unit;
   28.28 +	bass = bass_norm;
   28.29 +	clear();
   28.30 +}
   28.31 +
   28.32 +void SPC_Filter::run( short* io, int count )
   28.33 +{
   28.34 +	require( (count & 1) == 0 ); // must be even
   28.35 +	
   28.36 +	int const gain = this->gain;
   28.37 +	int const bass = this->bass;
   28.38 +	chan_t* c = &ch [2];
   28.39 +	do
   28.40 +	{
   28.41 +		// cache in registers
   28.42 +		int sum = (--c)->sum;
   28.43 +		int pp1 = c->pp1;
   28.44 +		int p1  = c->p1;
   28.45 +		
   28.46 +		for ( int i = 0; i < count; i += 2 )
   28.47 +		{
   28.48 +			// Low-pass filter (two point FIR with coeffs 0.25, 0.75)
   28.49 +			int f = io [i] + p1;
   28.50 +			p1 = io [i] * 3;
   28.51 +			
   28.52 +			// High-pass filter ("leaky integrator")
   28.53 +			int delta = f - pp1;
   28.54 +			pp1 = f;
   28.55 +			int s = sum >> (gain_bits + 2);
   28.56 +			sum += (delta * gain) - (sum >> bass);
   28.57 +			
   28.58 +			// Clamp to 16 bits
   28.59 +			if ( (short) s != s )
   28.60 +				s = (s >> 31) ^ 0x7FFF;
   28.61 +			
   28.62 +			io [i] = (short) s;
   28.63 +		}
   28.64 +		
   28.65 +		c->p1  = p1;
   28.66 +		c->pp1 = pp1;
   28.67 +		c->sum = sum;
   28.68 +		++io;
   28.69 +	}
   28.70 +	while ( c != ch );
   28.71 +}
    29.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    29.2 +++ b/snes_spc/SPC_Filter.h	Fri Oct 21 05:53:11 2011 -0700
    29.3 @@ -0,0 +1,47 @@
    29.4 +// Simple low-pass and high-pass filter to better match sound output of a SNES
    29.5 +
    29.6 +// snes_spc 0.9.0
    29.7 +#ifndef SPC_FILTER_H
    29.8 +#define SPC_FILTER_H
    29.9 +
   29.10 +#include "blargg_common.h"
   29.11 +
   29.12 +struct SPC_Filter {
   29.13 +public:
   29.14 +	
   29.15 +	// Filters count samples of stereo sound in place. Count must be a multiple of 2.
   29.16 +	typedef short sample_t;
   29.17 +	void run( sample_t* io, int count );
   29.18 +	
   29.19 +// Optional features
   29.20 +
   29.21 +	// Clears filter to silence
   29.22 +	void clear();
   29.23 +
   29.24 +	// Sets gain (volume), where gain_unit is normal. Gains greater than gain_unit
   29.25 +	// are fine, since output is clamped to 16-bit sample range.
   29.26 +	enum { gain_unit = 0x100 };
   29.27 +	void set_gain( int gain );
   29.28 +
   29.29 +	// Sets amount of bass (logarithmic scale)
   29.30 +	enum { bass_none =  0 };
   29.31 +	enum { bass_norm =  8 }; // normal amount
   29.32 +	enum { bass_max  = 31 };
   29.33 +	void set_bass( int bass );
   29.34 +	
   29.35 +public:
   29.36 +	SPC_Filter();
   29.37 +	BLARGG_DISABLE_NOTHROW
   29.38 +private:
   29.39 +	enum { gain_bits = 8 };
   29.40 +	int gain;
   29.41 +	int bass;
   29.42 +	struct chan_t { int p1, pp1, sum; };
   29.43 +	chan_t ch [2];
   29.44 +};
   29.45 +
   29.46 +inline void SPC_Filter::set_gain( int g ) { gain = g; }
   29.47 +
   29.48 +inline void SPC_Filter::set_bass( int b ) { bass = b; }
   29.49 +
   29.50 +#endif
    30.1 Binary file snes_spc/SPC_Filter.h.gch has changed
    31.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    31.2 +++ b/snes_spc/blargg_common.h	Fri Oct 21 05:53:11 2011 -0700
    31.3 @@ -0,0 +1,186 @@
    31.4 +// Sets up common environment for Shay Green's libraries.
    31.5 +// To change configuration options, modify blargg_config.h, not this file.
    31.6 +
    31.7 +// snes_spc 0.9.0
    31.8 +#ifndef BLARGG_COMMON_H
    31.9 +#define BLARGG_COMMON_H
   31.10 +
   31.11 +#include <stddef.h>
   31.12 +#include <stdlib.h>
   31.13 +#include <assert.h>
   31.14 +#include <limits.h>
   31.15 +
   31.16 +#undef BLARGG_COMMON_H
   31.17 +// allow blargg_config.h to #include blargg_common.h
   31.18 +#include "blargg_config.h"
   31.19 +#ifndef BLARGG_COMMON_H
   31.20 +#define BLARGG_COMMON_H
   31.21 +
   31.22 +// BLARGG_RESTRICT: equivalent to restrict, where supported
   31.23 +#if defined (__GNUC__) || _MSC_VER >= 1100
   31.24 +	#define BLARGG_RESTRICT __restrict
   31.25 +#else
   31.26 +	#define BLARGG_RESTRICT
   31.27 +#endif
   31.28 +
   31.29 +// STATIC_CAST(T,expr): Used in place of static_cast<T> (expr)
   31.30 +#ifndef STATIC_CAST
   31.31 +	#define STATIC_CAST(T,expr) ((T) (expr))
   31.32 +#endif
   31.33 +
   31.34 +// blargg_err_t (0 on success, otherwise error string)
   31.35 +#ifndef blargg_err_t
   31.36 +	typedef const char* blargg_err_t;
   31.37 +#endif
   31.38 +
   31.39 +// blargg_vector - very lightweight vector of POD types (no constructor/destructor)
   31.40 +template<class T>
   31.41 +class blargg_vector {
   31.42 +	T* begin_;
   31.43 +	size_t size_;
   31.44 +public:
   31.45 +	blargg_vector() : begin_( 0 ), size_( 0 ) { }
   31.46 +	~blargg_vector() { free( begin_ ); }
   31.47 +	size_t size() const { return size_; }
   31.48 +	T* begin() const { return begin_; }
   31.49 +	T* end() const { return begin_ + size_; }
   31.50 +	blargg_err_t resize( size_t n )
   31.51 +	{
   31.52 +		// TODO: blargg_common.cpp to hold this as an outline function, ugh
   31.53 +		void* p = realloc( begin_, n * sizeof (T) );
   31.54 +		if ( p )
   31.55 +			begin_ = (T*) p;
   31.56 +		else if ( n > size_ ) // realloc failure only a problem if expanding
   31.57 +			return "Out of memory";
   31.58 +		size_ = n;
   31.59 +		return 0;
   31.60 +	}
   31.61 +	void clear() { void* p = begin_; begin_ = 0; size_ = 0; free( p ); }
   31.62 +	T& operator [] ( size_t n ) const
   31.63 +	{
   31.64 +		assert( n <= size_ ); // <= to allow past-the-end value
   31.65 +		return begin_ [n];
   31.66 +	}
   31.67 +};
   31.68 +
   31.69 +#ifndef BLARGG_DISABLE_NOTHROW
   31.70 +	// throw spec mandatory in ISO C++ if operator new can return NULL
   31.71 +	#if __cplusplus >= 199711 || defined (__GNUC__)
   31.72 +		#define BLARGG_THROWS( spec ) throw spec
   31.73 +	#else
   31.74 +		#define BLARGG_THROWS( spec )
   31.75 +	#endif
   31.76 +	#define BLARGG_DISABLE_NOTHROW \
   31.77 +		void* operator new ( size_t s ) BLARGG_THROWS(()) { return malloc( s ); }\
   31.78 +		void operator delete ( void* p ) { free( p ); }
   31.79 +	#define BLARGG_NEW new
   31.80 +#else
   31.81 +	#include <new>
   31.82 +	#define BLARGG_NEW new (std::nothrow)
   31.83 +#endif
   31.84 +
   31.85 +// BLARGG_4CHAR('a','b','c','d') = 'abcd' (four character integer constant)
   31.86 +#define BLARGG_4CHAR( a, b, c, d ) \
   31.87 +	((a&0xFF)*0x1000000L + (b&0xFF)*0x10000L + (c&0xFF)*0x100L + (d&0xFF))
   31.88 +
   31.89 +// BOOST_STATIC_ASSERT( expr ): Generates compile error if expr is 0.
   31.90 +#ifndef BOOST_STATIC_ASSERT
   31.91 +	#ifdef _MSC_VER
   31.92 +		// MSVC6 (_MSC_VER < 1300) fails for use of __LINE__ when /Zl is specified
   31.93 +		#define BOOST_STATIC_ASSERT( expr ) \
   31.94 +			void blargg_failed_( int (*arg) [2 / (int) !!(expr) - 1] )
   31.95 +	#else
   31.96 +		// Some other compilers fail when declaring same function multiple times in class,
   31.97 +		// so differentiate them by line
   31.98 +		#define BOOST_STATIC_ASSERT( expr ) \
   31.99 +			void blargg_failed_( int (*arg) [2 / !!(expr) - 1] [__LINE__] )
  31.100 +	#endif
  31.101 +#endif
  31.102 +
  31.103 +// BLARGG_COMPILER_HAS_BOOL: If 0, provides bool support for old compiler. If 1,
  31.104 +// compiler is assumed to support bool. If undefined, availability is determined.
  31.105 +#ifndef BLARGG_COMPILER_HAS_BOOL
  31.106 +	#if defined (__MWERKS__)
  31.107 +		#if !__option(bool)
  31.108 +			#define BLARGG_COMPILER_HAS_BOOL 0
  31.109 +		#endif
  31.110 +	#elif defined (_MSC_VER)
  31.111 +		#if _MSC_VER < 1100
  31.112 +			#define BLARGG_COMPILER_HAS_BOOL 0
  31.113 +		#endif
  31.114 +	#elif defined (__GNUC__)
  31.115 +		// supports bool
  31.116 +	#elif __cplusplus < 199711
  31.117 +		#define BLARGG_COMPILER_HAS_BOOL 0
  31.118 +	#endif
  31.119 +#endif
  31.120 +#if defined (BLARGG_COMPILER_HAS_BOOL) && !BLARGG_COMPILER_HAS_BOOL
  31.121 +	// If you get errors here, modify your blargg_config.h file
  31.122 +	typedef int bool;
  31.123 +	const bool true  = 1;
  31.124 +	const bool false = 0;
  31.125 +#endif
  31.126 +
  31.127 +// blargg_long/blargg_ulong = at least 32 bits, int if it's big enough
  31.128 +
  31.129 +#if INT_MAX < 0x7FFFFFFF || LONG_MAX == 0x7FFFFFFF
  31.130 +	typedef long blargg_long;
  31.131 +#else
  31.132 +	typedef int blargg_long;
  31.133 +#endif
  31.134 +
  31.135 +#if UINT_MAX < 0xFFFFFFFF || ULONG_MAX == 0xFFFFFFFF
  31.136 +	typedef unsigned long blargg_ulong;
  31.137 +#else
  31.138 +	typedef unsigned blargg_ulong;
  31.139 +#endif
  31.140 +
  31.141 +// BOOST::int8_t etc.
  31.142 +
  31.143 +// HAVE_STDINT_H: If defined, use <stdint.h> for int8_t etc.
  31.144 +#if defined (HAVE_STDINT_H)
  31.145 +	#include <stdint.h>
  31.146 +	#define BOOST
  31.147 +
  31.148 +// HAVE_INTTYPES_H: If defined, use <stdint.h> for int8_t etc.
  31.149 +#elif defined (HAVE_INTTYPES_H)
  31.150 +	#include <inttypes.h>
  31.151 +	#define BOOST
  31.152 +
  31.153 +#else
  31.154 +	struct BOOST
  31.155 +	{
  31.156 +		#if UCHAR_MAX == 0xFF && SCHAR_MAX == 0x7F
  31.157 +			typedef signed char     int8_t;
  31.158 +			typedef unsigned char   uint8_t;
  31.159 +		#else
  31.160 +			// No suitable 8-bit type available
  31.161 +			typedef struct see_blargg_common_h int8_t;
  31.162 +			typedef struct see_blargg_common_h uint8_t;
  31.163 +		#endif
  31.164 +		
  31.165 +		#if USHRT_MAX == 0xFFFF
  31.166 +			typedef short           int16_t;
  31.167 +			typedef unsigned short  uint16_t;
  31.168 +		#else
  31.169 +			// No suitable 16-bit type available
  31.170 +			typedef struct see_blargg_common_h int16_t;
  31.171 +			typedef struct see_blargg_common_h uint16_t;
  31.172 +		#endif
  31.173 +		
  31.174 +		#if ULONG_MAX == 0xFFFFFFFF
  31.175 +			typedef long            int32_t;
  31.176 +			typedef unsigned long   uint32_t;
  31.177 +		#elif UINT_MAX == 0xFFFFFFFF
  31.178 +			typedef int             int32_t;
  31.179 +			typedef unsigned int    uint32_t;
  31.180 +		#else
  31.181 +			// No suitable 32-bit type available
  31.182 +			typedef struct see_blargg_common_h int32_t;
  31.183 +			typedef struct see_blargg_common_h uint32_t;
  31.184 +		#endif
  31.185 +	};
  31.186 +#endif
  31.187 +
  31.188 +#endif
  31.189 +#endif
    32.1 Binary file snes_spc/blargg_common.h.gch has changed
    33.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    33.2 +++ b/snes_spc/blargg_config.h	Fri Oct 21 05:53:11 2011 -0700
    33.3 @@ -0,0 +1,24 @@
    33.4 +// snes_spc 0.9.0 user configuration file. Don't replace when updating library.
    33.5 +
    33.6 +// snes_spc 0.9.0
    33.7 +#ifndef BLARGG_CONFIG_H
    33.8 +#define BLARGG_CONFIG_H
    33.9 +
   33.10 +// Uncomment to disable debugging checks
   33.11 +//#define NDEBUG 1
   33.12 +
   33.13 +// Uncomment to enable platform-specific (and possibly non-portable) optimizations
   33.14 +//#define BLARGG_NONPORTABLE 1
   33.15 +
   33.16 +// Uncomment if automatic byte-order determination doesn't work
   33.17 +//#define BLARGG_BIG_ENDIAN 1
   33.18 +
   33.19 +// Uncomment if you get errors in the bool section of blargg_common.h
   33.20 +//#define BLARGG_COMPILER_HAS_BOOL 1
   33.21 +
   33.22 +// Use standard config.h if present
   33.23 +#ifdef HAVE_CONFIG_H
   33.24 +	#include "config.h"
   33.25 +#endif
   33.26 +
   33.27 +#endif
    34.1 Binary file snes_spc/blargg_config.h.gch has changed
    35.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    35.2 +++ b/snes_spc/blargg_endian.h	Fri Oct 21 05:53:11 2011 -0700
    35.3 @@ -0,0 +1,185 @@
    35.4 +// CPU Byte Order Utilities
    35.5 +
    35.6 +// snes_spc 0.9.0
    35.7 +#ifndef BLARGG_ENDIAN
    35.8 +#define BLARGG_ENDIAN
    35.9 +
   35.10 +#include "blargg_common.h"
   35.11 +
   35.12 +// BLARGG_CPU_CISC: Defined if CPU has very few general-purpose registers (< 16)
   35.13 +#if defined (_M_IX86) || defined (_M_IA64) || defined (__i486__) || \
   35.14 +		defined (__x86_64__) || defined (__ia64__) || defined (__i386__)
   35.15 +	#define BLARGG_CPU_X86 1
   35.16 +	#define BLARGG_CPU_CISC 1
   35.17 +#endif
   35.18 +
   35.19 +#if defined (__powerpc__) || defined (__ppc__) || defined (__POWERPC__) || defined (__powerc)
   35.20 +	#define BLARGG_CPU_POWERPC 1
   35.21 +	#define BLARGG_CPU_RISC 1
   35.22 +#endif
   35.23 +
   35.24 +// BLARGG_BIG_ENDIAN, BLARGG_LITTLE_ENDIAN: Determined automatically, otherwise only
   35.25 +// one may be #defined to 1. Only needed if something actually depends on byte order.
   35.26 +#if !defined (BLARGG_BIG_ENDIAN) && !defined (BLARGG_LITTLE_ENDIAN)
   35.27 +#ifdef __GLIBC__
   35.28 +	// GCC handles this for us
   35.29 +	#include <endian.h>
   35.30 +	#if __BYTE_ORDER == __LITTLE_ENDIAN
   35.31 +		#define BLARGG_LITTLE_ENDIAN 1
   35.32 +	#elif __BYTE_ORDER == __BIG_ENDIAN
   35.33 +		#define BLARGG_BIG_ENDIAN 1
   35.34 +	#endif
   35.35 +#else
   35.36 +
   35.37 +#if defined (LSB_FIRST) || defined (__LITTLE_ENDIAN__) || BLARGG_CPU_X86 || \
   35.38 +		(defined (LITTLE_ENDIAN) && LITTLE_ENDIAN+0 != 1234)
   35.39 +	#define BLARGG_LITTLE_ENDIAN 1
   35.40 +#endif
   35.41 +
   35.42 +#if defined (MSB_FIRST)     || defined (__BIG_ENDIAN__) || defined (WORDS_BIGENDIAN) || \
   35.43 +	defined (__sparc__)     ||  BLARGG_CPU_POWERPC || \
   35.44 +	(defined (BIG_ENDIAN) && BIG_ENDIAN+0 != 4321)
   35.45 +	#define BLARGG_BIG_ENDIAN 1
   35.46 +#elif !defined (__mips__)
   35.47 +	// No endian specified; assume little-endian, since it's most common
   35.48 +	#define BLARGG_LITTLE_ENDIAN 1
   35.49 +#endif
   35.50 +#endif
   35.51 +#endif
   35.52 +
   35.53 +#if BLARGG_LITTLE_ENDIAN && BLARGG_BIG_ENDIAN
   35.54 +	#undef BLARGG_LITTLE_ENDIAN
   35.55 +	#undef BLARGG_BIG_ENDIAN
   35.56 +#endif
   35.57 +
   35.58 +inline void blargg_verify_byte_order()
   35.59 +{
   35.60 +	#ifndef NDEBUG
   35.61 +		#if BLARGG_BIG_ENDIAN
   35.62 +			volatile int i = 1;
   35.63 +			assert( *(volatile char*) &i == 0 );
   35.64 +		#elif BLARGG_LITTLE_ENDIAN
   35.65 +			volatile int i = 1;
   35.66 +			assert( *(volatile char*) &i != 0 );
   35.67 +		#endif
   35.68 +	#endif
   35.69 +}
   35.70 +
   35.71 +inline unsigned get_le16( void const* p )
   35.72 +{
   35.73 +	return  (unsigned) ((unsigned char const*) p) [1] << 8 |
   35.74 +			(unsigned) ((unsigned char const*) p) [0];
   35.75 +}
   35.76 +
   35.77 +inline unsigned get_be16( void const* p )
   35.78 +{
   35.79 +	return  (unsigned) ((unsigned char const*) p) [0] << 8 |
   35.80 +			(unsigned) ((unsigned char const*) p) [1];
   35.81 +}
   35.82 +
   35.83 +inline blargg_ulong get_le32( void const* p )
   35.84 +{
   35.85 +	return  (blargg_ulong) ((unsigned char const*) p) [3] << 24 |
   35.86 +			(blargg_ulong) ((unsigned char const*) p) [2] << 16 |
   35.87 +			(blargg_ulong) ((unsigned char const*) p) [1] <<  8 |
   35.88 +			(blargg_ulong) ((unsigned char const*) p) [0];
   35.89 +}
   35.90 +
   35.91 +inline blargg_ulong get_be32( void const* p )
   35.92 +{
   35.93 +	return  (blargg_ulong) ((unsigned char const*) p) [0] << 24 |
   35.94 +			(blargg_ulong) ((unsigned char const*) p) [1] << 16 |
   35.95 +			(blargg_ulong) ((unsigned char const*) p) [2] <<  8 |
   35.96 +			(blargg_ulong) ((unsigned char const*) p) [3];
   35.97 +}
   35.98 +
   35.99 +inline void set_le16( void* p, unsigned n )
  35.100 +{
  35.101 +	((unsigned char*) p) [1] = (unsigned char) (n >> 8);
  35.102 +	((unsigned char*) p) [0] = (unsigned char) n;
  35.103 +}
  35.104 +
  35.105 +inline void set_be16( void* p, unsigned n )
  35.106 +{
  35.107 +	((unsigned char*) p) [0] = (unsigned char) (n >> 8);
  35.108 +	((unsigned char*) p) [1] = (unsigned char) n;
  35.109 +}
  35.110 +
  35.111 +inline void set_le32( void* p, blargg_ulong n )
  35.112 +{
  35.113 +	((unsigned char*) p) [0] = (unsigned char) n;
  35.114 +	((unsigned char*) p) [1] = (unsigned char) (n >> 8);
  35.115 +	((unsigned char*) p) [2] = (unsigned char) (n >> 16);
  35.116 +	((unsigned char*) p) [3] = (unsigned char) (n >> 24);
  35.117 +}
  35.118 +
  35.119 +inline void set_be32( void* p, blargg_ulong n )
  35.120 +{
  35.121 +	((unsigned char*) p) [3] = (unsigned char) n;
  35.122 +	((unsigned char*) p) [2] = (unsigned char) (n >> 8);
  35.123 +	((unsigned char*) p) [1] = (unsigned char) (n >> 16);
  35.124 +	((unsigned char*) p) [0] = (unsigned char) (n >> 24);
  35.125 +}
  35.126 +
  35.127 +#if BLARGG_NONPORTABLE
  35.128 +	// Optimized implementation if byte order is known
  35.129 +	#if BLARGG_LITTLE_ENDIAN
  35.130 +		#define GET_LE16( addr )        (*(BOOST::uint16_t*) (addr))
  35.131 +		#define GET_LE32( addr )        (*(BOOST::uint32_t*) (addr))
  35.132 +		#define SET_LE16( addr, data )  (void) (*(BOOST::uint16_t*) (addr) = (data))
  35.133 +		#define SET_LE32( addr, data )  (void) (*(BOOST::uint32_t*) (addr) = (data))
  35.134 +	#elif BLARGG_BIG_ENDIAN
  35.135 +		#define GET_BE16( addr )        (*(BOOST::uint16_t*) (addr))
  35.136 +		#define GET_BE32( addr )        (*(BOOST::uint32_t*) (addr))
  35.137 +		#define SET_BE16( addr, data )  (void) (*(BOOST::uint16_t*) (addr) = (data))
  35.138 +		#define SET_BE32( addr, data )  (void) (*(BOOST::uint32_t*) (addr) = (data))
  35.139 +		
  35.140 +		#if BLARGG_CPU_POWERPC
  35.141 +			// PowerPC has special byte-reversed instructions
  35.142 +			#if defined (__MWERKS__)
  35.143 +				#define GET_LE16( addr )        (__lhbrx( addr, 0 ))
  35.144 +				#define GET_LE32( addr )        (__lwbrx( addr, 0 ))
  35.145 +				#define SET_LE16( addr, in )    (__sthbrx( in, addr, 0 ))
  35.146 +				#define SET_LE32( addr, in )    (__stwbrx( in, addr, 0 ))
  35.147 +			#elif defined (__GNUC__)
  35.148 +				#define GET_LE16( addr )        ({unsigned ppc_lhbrx_; asm( "lhbrx %0,0,%1" : "=r" (ppc_lhbrx_) : "r" (addr), "0" (ppc_lhbrx_) ); ppc_lhbrx_;})
  35.149 +				#define GET_LE32( addr )        ({unsigned ppc_lwbrx_; asm( "lwbrx %0,0,%1" : "=r" (ppc_lwbrx_) : "r" (addr), "0" (ppc_lwbrx_) ); ppc_lwbrx_;})
  35.150 +				#define SET_LE16( addr, in )    ({asm( "sthbrx %0,0,%1" : : "r" (in), "r" (addr) );})
  35.151 +				#define SET_LE32( addr, in )    ({asm( "stwbrx %0,0,%1" : : "r" (in), "r" (addr) );})
  35.152 +			#endif
  35.153 +		#endif
  35.154 +	#endif
  35.155 +#endif
  35.156 +
  35.157 +#ifndef GET_LE16
  35.158 +	#define GET_LE16( addr )        get_le16( addr )
  35.159 +	#define SET_LE16( addr, data )  set_le16( addr, data )
  35.160 +#endif
  35.161 +
  35.162 +#ifndef GET_LE32
  35.163 +	#define GET_LE32( addr )        get_le32( addr )
  35.164 +	#define SET_LE32( addr, data )  set_le32( addr, data )
  35.165 +#endif
  35.166 +
  35.167 +#ifndef GET_BE16
  35.168 +	#define GET_BE16( addr )        get_be16( addr )
  35.169 +	#define SET_BE16( addr, data )  set_be16( addr, data )
  35.170 +#endif
  35.171 +
  35.172 +#ifndef GET_BE32
  35.173 +	#define GET_BE32( addr )        get_be32( addr )
  35.174 +	#define SET_BE32( addr, data )  set_be32( addr, data )
  35.175 +#endif
  35.176 +
  35.177 +// auto-selecting versions
  35.178 +
  35.179 +inline void set_le( BOOST::uint16_t* p, unsigned     n ) { SET_LE16( p, n ); }
  35.180 +inline void set_le( BOOST::uint32_t* p, blargg_ulong n ) { SET_LE32( p, n ); }
  35.181 +inline void set_be( BOOST::uint16_t* p, unsigned     n ) { SET_BE16( p, n ); }
  35.182 +inline void set_be( BOOST::uint32_t* p, blargg_ulong n ) { SET_BE32( p, n ); }
  35.183 +inline unsigned     get_le( BOOST::uint16_t* p ) { return GET_LE16( p ); }
  35.184 +inline blargg_ulong get_le( BOOST::uint32_t* p ) { return GET_LE32( p ); }
  35.185 +inline unsigned     get_be( BOOST::uint16_t* p ) { return GET_BE16( p ); }
  35.186 +inline blargg_ulong get_be( BOOST::uint32_t* p ) { return GET_BE32( p ); }
  35.187 +
  35.188 +#endif
    36.1 Binary file snes_spc/blargg_endian.h.gch has changed
    37.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    37.2 +++ b/snes_spc/blargg_source.h	Fri Oct 21 05:53:11 2011 -0700
    37.3 @@ -0,0 +1,100 @@
    37.4 +/* Included at the beginning of library source files, after all other #include lines.
    37.5 +Sets up helpful macros and services used in my source code. They don't need
    37.6 +module an annoying module prefix on their names since they are defined after
    37.7 +all other #include lines. */
    37.8 +
    37.9 +// snes_spc 0.9.0
   37.10 +#ifndef BLARGG_SOURCE_H
   37.11 +#define BLARGG_SOURCE_H
   37.12 +
   37.13 +// If debugging is enabled, abort program if expr is false. Meant for checking
   37.14 +// internal state and consistency. A failed assertion indicates a bug in the module.
   37.15 +// void assert( bool expr );
   37.16 +#include <assert.h>
   37.17 +
   37.18 +// If debugging is enabled and expr is false, abort program. Meant for checking
   37.19 +// caller-supplied parameters and operations that are outside the control of the
   37.20 +// module. A failed requirement indicates a bug outside the module.
   37.21 +// void require( bool expr );
   37.22 +#undef require
   37.23 +#define require( expr ) assert( expr )
   37.24 +
   37.25 +// Like printf() except output goes to debug log file. Might be defined to do
   37.26 +// nothing (not even evaluate its arguments).
   37.27 +// void dprintf( const char* format, ... );
   37.28 +static inline void blargg_dprintf_( const char*, ... ) { }
   37.29 +#undef dprintf
   37.30 +#define dprintf (1) ? (void) 0 : blargg_dprintf_
   37.31 +
   37.32 +// If enabled, evaluate expr and if false, make debug log entry with source file
   37.33 +// and line. Meant for finding situations that should be examined further, but that
   37.34 +// don't indicate a problem. In all cases, execution continues normally.
   37.35 +#undef check
   37.36 +#define check( expr ) ((void) 0)
   37.37 +
   37.38 +// If expr yields error string, return it from current function, otherwise continue.
   37.39 +#undef RETURN_ERR
   37.40 +#define RETURN_ERR( expr ) do {                         \
   37.41 +		blargg_err_t blargg_return_err_ = (expr);               \
   37.42 +		if ( blargg_return_err_ ) return blargg_return_err_;    \
   37.43 +	} while ( 0 )
   37.44 +
   37.45 +// If ptr is 0, return out of memory error string.
   37.46 +#undef CHECK_ALLOC
   37.47 +#define CHECK_ALLOC( ptr ) do { if ( (ptr) == 0 ) return "Out of memory"; } while ( 0 )
   37.48 +
   37.49 +// Avoid any macros which evaluate their arguments multiple times
   37.50 +#undef min
   37.51 +#undef max
   37.52 +
   37.53 +#define DEF_MIN_MAX( type ) \
   37.54 +	static inline type min( type x, type y ) { if ( x < y ) return x; return y; }\
   37.55 +	static inline type max( type x, type y ) { if ( y < x ) return x; return y; }
   37.56 +
   37.57 +DEF_MIN_MAX( int )
   37.58 +DEF_MIN_MAX( unsigned )
   37.59 +DEF_MIN_MAX( long )
   37.60 +DEF_MIN_MAX( unsigned long )
   37.61 +DEF_MIN_MAX( float )
   37.62 +DEF_MIN_MAX( double )
   37.63 +
   37.64 +#undef DEF_MIN_MAX
   37.65 +
   37.66 +/*
   37.67 +// using const references generates crappy code, and I am currenly only using these
   37.68 +// for built-in types, so they take arguments by value
   37.69 +
   37.70 +// TODO: remove
   37.71 +inline int min( int x, int y ) 
   37.72 +template<class T>
   37.73 +inline T min( T x, T y )
   37.74 +{
   37.75 +	if ( x < y )
   37.76 +		return x;
   37.77 +	return y;
   37.78 +}
   37.79 +
   37.80 +template<class T>
   37.81 +inline T max( T x, T y )
   37.82 +{
   37.83 +	if ( x < y )
   37.84 +		return y;
   37.85 +	return x;
   37.86 +}
   37.87 +*/
   37.88 +
   37.89 +// TODO: good idea? bad idea?
   37.90 +#undef byte
   37.91 +#define byte byte_
   37.92 +typedef unsigned char byte;
   37.93 +
   37.94 +// deprecated
   37.95 +#define BLARGG_CHECK_ALLOC CHECK_ALLOC
   37.96 +#define BLARGG_RETURN_ERR RETURN_ERR
   37.97 +
   37.98 +// BLARGG_SOURCE_BEGIN: If defined, #included, allowing redefition of dprintf and check
   37.99 +#ifdef BLARGG_SOURCE_BEGIN
  37.100 +	#include BLARGG_SOURCE_BEGIN
  37.101 +#endif
  37.102 +
  37.103 +#endif
    38.1 Binary file snes_spc/blargg_source.h.gch has changed
    39.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    39.2 +++ b/snes_spc/dsp.cpp	Fri Oct 21 05:53:11 2011 -0700
    39.3 @@ -0,0 +1,48 @@
    39.4 +// snes_spc 0.9.0. http://www.slack.net/~ant/
    39.5 +
    39.6 +#include "dsp.h"
    39.7 +
    39.8 +#include "SPC_DSP.h"
    39.9 +
   39.10 +/* Copyright (C) 2007 Shay Green. This module is free software; you
   39.11 +can redistribute it and/or modify it under the terms of the GNU Lesser
   39.12 +General Public License as published by the Free Software Foundation; either
   39.13 +version 2.1 of the License, or (at your option) any later version. This
   39.14 +module is distributed in the hope that it will be useful, but WITHOUT ANY
   39.15 +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   39.16 +FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
   39.17 +details. You should have received a copy of the GNU Lesser General Public
   39.18 +License along with this module; if not, write to the Free Software Foundation,
   39.19 +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
   39.20 +
   39.21 +#include "blargg_source.h"
   39.22 +
   39.23 +SPC_DSP* spc_dsp_new( void )
   39.24 +{
   39.25 +	// be sure constants match
   39.26 +	assert( spc_dsp_voice_count     == (int) SPC_DSP::voice_count );
   39.27 +	assert( spc_dsp_register_count  == (int) SPC_DSP::register_count );
   39.28 +	#if !SPC_NO_COPY_STATE_FUNCS
   39.29 +	assert( spc_dsp_state_size      == (int) SPC_DSP::state_size );
   39.30 +	#endif
   39.31 +	
   39.32 +	return new SPC_DSP;
   39.33 +}
   39.34 +
   39.35 +void spc_dsp_delete      ( SPC_DSP* s )                                 { delete s; }
   39.36 +void spc_dsp_init        ( SPC_DSP* s, void* ram_64k )                  { s->init( ram_64k ); }
   39.37 +void spc_dsp_set_output  ( SPC_DSP* s, spc_dsp_sample_t* p, int n )     { s->set_output( p, n ); }
   39.38 +int  spc_dsp_sample_count( SPC_DSP const* s )                           { return s->sample_count(); }
   39.39 +void spc_dsp_reset       ( SPC_DSP* s )                                 { s->reset(); }
   39.40 +void spc_dsp_soft_reset  ( SPC_DSP* s )                                 { s->soft_reset(); }
   39.41 +int  spc_dsp_read        ( SPC_DSP const* s, int addr )                 { return s->read( addr ); }
   39.42 +void spc_dsp_write       ( SPC_DSP* s, int addr, int data )             { s->write( addr, data ); }
   39.43 +void spc_dsp_run         ( SPC_DSP* s, int clock_count )                { s->run( clock_count ); }
   39.44 +void spc_dsp_mute_voices ( SPC_DSP* s, int mask )                       { s->mute_voices( mask ); }
   39.45 +void spc_dsp_disable_surround( SPC_DSP* s, int disable )                { s->disable_surround( disable ); }
   39.46 +void spc_dsp_load        ( SPC_DSP* s, unsigned char const regs [spc_dsp_register_count] ) { s->load( regs ); }
   39.47 +
   39.48 +#if !SPC_NO_COPY_STATE_FUNCS
   39.49 +void spc_dsp_copy_state  ( SPC_DSP* s, unsigned char** p, spc_dsp_copy_func_t f ) { s->copy_state( p, f ); }
   39.50 +int  spc_dsp_check_kon   ( SPC_DSP* s )                                 { return s->check_kon(); }
   39.51 +#endif
    40.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    40.2 +++ b/snes_spc/dsp.h	Fri Oct 21 05:53:11 2011 -0700
    40.3 @@ -0,0 +1,83 @@
    40.4 +/* SNES SPC-700 DSP emulator C interface (also usable from C++) */
    40.5 +
    40.6 +/* snes_spc 0.9.0 */
    40.7 +#ifndef DSP_H
    40.8 +#define DSP_H
    40.9 +
   40.10 +#include <stddef.h>
   40.11 +
   40.12 +#ifdef __cplusplus
   40.13 +	extern "C" {
   40.14 +#endif
   40.15 +
   40.16 +typedef struct SPC_DSP SPC_DSP;
   40.17 +
   40.18 +/* Creates new DSP emulator. NULL if out of memory. */
   40.19 +SPC_DSP* spc_dsp_new( void );
   40.20 +
   40.21 +/* Frees DSP emulator */
   40.22 +void spc_dsp_delete( SPC_DSP* );
   40.23 +
   40.24 +/* Initializes DSP and has it use the 64K RAM provided */
   40.25 +void spc_dsp_init( SPC_DSP*, void* ram_64k );
   40.26 +
   40.27 +/* Sets destination for output samples. If out is NULL or out_size is 0,
   40.28 +doesn't generate any. */
   40.29 +typedef short spc_dsp_sample_t;
   40.30 +void spc_dsp_set_output( SPC_DSP*, spc_dsp_sample_t* out, int out_size );
   40.31 +
   40.32 +/* Number of samples written to output since it was last set, always
   40.33 +a multiple of 2. Undefined if more samples were generated than
   40.34 +output buffer could hold. */
   40.35 +int spc_dsp_sample_count( SPC_DSP const* );
   40.36 +
   40.37 +
   40.38 +/**** Emulation *****/
   40.39 +
   40.40 +/* Resets DSP to power-on state */
   40.41 +void spc_dsp_reset( SPC_DSP* );
   40.42 +
   40.43 +/* Emulates pressing reset switch on SNES */
   40.44 +void spc_dsp_soft_reset( SPC_DSP* );
   40.45 +
   40.46 +/* Reads/writes DSP registers. For accuracy, you must first call spc_dsp_run() */
   40.47 +/* to catch the DSP up to present. */
   40.48 +int  spc_dsp_read ( SPC_DSP const*, int addr );
   40.49 +void spc_dsp_write( SPC_DSP*, int addr, int data );
   40.50 +
   40.51 +/* Runs DSP for specified number of clocks (~1024000 per second). Every 32 clocks */
   40.52 +/* a pair of samples is be generated. */
   40.53 +void spc_dsp_run( SPC_DSP*, int clock_count );
   40.54 +
   40.55 +
   40.56 +/**** Sound control *****/
   40.57 +
   40.58 +/* Mutes voices corresponding to non-zero bits in mask. Reduces emulation accuracy. */
   40.59 +enum { spc_dsp_voice_count = 8 };
   40.60 +void spc_dsp_mute_voices( SPC_DSP*, int mask );
   40.61 +
   40.62 +/* If true, prevents channels and global volumes from being phase-negated.
   40.63 +Only supported by fast DSP; has no effect on accurate DSP. */
   40.64 +void spc_dsp_disable_surround( SPC_DSP*, int disable );
   40.65 +
   40.66 +
   40.67 +/**** State save/load *****/
   40.68 +
   40.69 +/* Resets DSP and uses supplied values to initialize registers */
   40.70 +enum { spc_dsp_register_count = 128 };
   40.71 +void spc_dsp_load( SPC_DSP*, unsigned char const regs [spc_dsp_register_count] );
   40.72 +
   40.73 +/* Saves/loads exact emulator state (accurate DSP only) */
   40.74 +enum { spc_dsp_state_size = 640 }; /* maximum space needed when saving */
   40.75 +typedef void (*spc_dsp_copy_func_t)( unsigned char** io, void* state, size_t );
   40.76 +void spc_dsp_copy_state( SPC_DSP*, unsigned char** io, spc_dsp_copy_func_t );
   40.77 +
   40.78 +/* Returns non-zero if new key-on events occurred since last call (accurate DSP only) */
   40.79 +int spc_dsp_check_kon( SPC_DSP* );
   40.80 +
   40.81 +
   40.82 +#ifdef __cplusplus
   40.83 +	}
   40.84 +#endif
   40.85 +
   40.86 +#endif
    41.1 Binary file snes_spc/dsp.h.gch has changed
    42.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    42.2 +++ b/snes_spc/spc.cpp	Fri Oct 21 05:53:11 2011 -0700
    42.3 @@ -0,0 +1,73 @@
    42.4 +// snes_spc 0.9.0. http://www.slack.net/~ant/
    42.5 +
    42.6 +#include "spc.h"
    42.7 +
    42.8 +#include "SNES_SPC.h"
    42.9 +#include "SPC_Filter.h"
   42.10 +
   42.11 +/* Copyright (C) 2004-2007 Shay Green. This module is free software; you
   42.12 +can redistribute it and/or modify it under the terms of the GNU Lesser
   42.13 +General Public License as published by the Free Software Foundation; either
   42.14 +version 2.1 of the License, or (at your option) any later version. This
   42.15 +module is distributed in the hope that it will be useful, but WITHOUT ANY
   42.16 +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   42.17 +FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
   42.18 +details. You should have received a copy of the GNU Lesser General Public
   42.19 +License along with this module; if not, write to the Free Software Foundation,
   42.20 +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
   42.21 +
   42.22 +#include "blargg_source.h"
   42.23 +
   42.24 +SNES_SPC* spc_new( void )
   42.25 +{
   42.26 +	// be sure constants match
   42.27 +	assert( spc_sample_rate         == (int) SNES_SPC::sample_rate );
   42.28 +	assert( spc_rom_size            == (int) SNES_SPC::rom_size );
   42.29 +	assert( spc_clock_rate          == (int) SNES_SPC::clock_rate );
   42.30 +	assert( spc_clocks_per_sample   == (int) SNES_SPC::clocks_per_sample );
   42.31 +	assert( spc_port_count          == (int) SNES_SPC::port_count );
   42.32 +	assert( spc_voice_count         == (int) SNES_SPC::voice_count );
   42.33 +	assert( spc_tempo_unit          == (int) SNES_SPC::tempo_unit );
   42.34 +	assert( spc_file_size           == (int) SNES_SPC::spc_file_size );
   42.35 +	#if !SPC_NO_COPY_STATE_FUNCS
   42.36 +	assert( spc_state_size          == (int) SNES_SPC::state_size );
   42.37 +	#endif
   42.38 +	
   42.39 +	SNES_SPC* s = new SNES_SPC;
   42.40 +	if ( s && s->init() )
   42.41 +	{
   42.42 +		delete s;
   42.43 +		s = 0;
   42.44 +	}
   42.45 +	return s;
   42.46 +}
   42.47 +
   42.48 +void spc_delete          ( SNES_SPC* s )                                { delete s; }
   42.49 +void spc_init_rom        ( SNES_SPC* s, unsigned char const r [64] )    { s->init_rom( r ); }
   42.50 +void spc_set_output      ( SNES_SPC* s, spc_sample_t* p, int n )        { s->set_output( p, n ); }
   42.51 +int  spc_sample_count    ( SNES_SPC const* s )                          { return s->sample_count(); }
   42.52 +void spc_reset           ( SNES_SPC* s )                                { s->reset(); }
   42.53 +void spc_soft_reset      ( SNES_SPC* s )                                { s->soft_reset(); }
   42.54 +int  spc_read_port       ( SNES_SPC* s, spc_time_t t, int p )           { return s->read_port( t, p ); }
   42.55 +void spc_write_port      ( SNES_SPC* s, spc_time_t t, int p, int d )    { s->write_port( t, p, d ); }
   42.56 +void spc_end_frame       ( SNES_SPC* s, spc_time_t t )                  { s->end_frame( t ); }  
   42.57 +void spc_mute_voices     ( SNES_SPC* s, int mask )                      { s->mute_voices( mask ); }
   42.58 +void spc_disable_surround( SNES_SPC* s, int disable )                   { s->disable_surround( disable ); }
   42.59 +void spc_set_tempo       ( SNES_SPC* s, int tempo )                     { s->set_tempo( tempo ); }
   42.60 +spc_err_t spc_load_spc   ( SNES_SPC* s, void const* p, long n )         { return s->load_spc( p, n ); }
   42.61 +void spc_clear_echo      ( SNES_SPC* s )                                { s->clear_echo(); }
   42.62 +spc_err_t spc_play       ( SNES_SPC* s, int count, short* out )         { return s->play( count, out ); }
   42.63 +spc_err_t spc_skip       ( SNES_SPC* s, int count )                     { return s->skip( count ); }
   42.64 +#if !SPC_NO_COPY_STATE_FUNCS
   42.65 +void spc_copy_state      ( SNES_SPC* s, unsigned char** p, spc_copy_func_t f ) { s->copy_state( p, f ); }
   42.66 +void spc_init_header     ( void* spc_out )                              { SNES_SPC::init_header( spc_out ); }
   42.67 +void spc_save_spc        ( SNES_SPC* s, void* spc_out )                 { s->save_spc( spc_out ); }
   42.68 +int  spc_check_kon       ( SNES_SPC* s )                                { return s->check_kon(); }
   42.69 +#endif
   42.70 +
   42.71 +SPC_Filter* spc_filter_new( void )                              { return new SPC_Filter; }
   42.72 +void spc_filter_delete( SPC_Filter* f )                         { delete f; }
   42.73 +void spc_filter_run( SPC_Filter* f, spc_sample_t* p, int s )    { f->run( p, s ); }
   42.74 +void spc_filter_clear( SPC_Filter* f )                          { f->clear(); }
   42.75 +void spc_filter_set_gain( SPC_Filter* f, int gain )             { f->set_gain( gain ); }
   42.76 +void spc_filter_set_bass( SPC_Filter* f, int bass )             { f->set_bass( bass ); }
    43.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    43.2 +++ b/snes_spc/spc.h	Fri Oct 21 05:53:11 2011 -0700
    43.3 @@ -0,0 +1,147 @@
    43.4 +/* SNES SPC-700 APU emulator C interface (also usable from C++) */
    43.5 +
    43.6 +/* snes_spc 0.9.0 */
    43.7 +#ifndef SPC_H
    43.8 +#define SPC_H
    43.9 +
   43.10 +#include <stddef.h>
   43.11 +
   43.12 +#ifdef __cplusplus
   43.13 +	extern "C" {
   43.14 +#endif
   43.15 +
   43.16 +/* Error string return. NULL if success, otherwise error message. */
   43.17 +typedef const char* spc_err_t;
   43.18 +
   43.19 +typedef struct SNES_SPC SNES_SPC;
   43.20 +
   43.21 +/* Creates new SPC emulator. NULL if out of memory. */
   43.22 +SNES_SPC* spc_new( void );
   43.23 +
   43.24 +/* Frees SPC emulator */
   43.25 +void spc_delete( SNES_SPC* );
   43.26 +
   43.27 +/* Sample pairs generated per second */
   43.28 +enum { spc_sample_rate = 32000 };
   43.29 +
   43.30 +
   43.31 +/**** Emulator use ****/
   43.32 +
   43.33 +/* Sets IPL ROM data. Library does not include ROM data. Most SPC music files
   43.34 +don't need ROM, but a full emulator must provide this. */
   43.35 +enum { spc_rom_size = 0x40 };
   43.36 +void spc_init_rom( SNES_SPC*, unsigned char const rom [spc_rom_size] );
   43.37 +
   43.38 +/* Sets destination for output samples */
   43.39 +typedef short spc_sample_t;
   43.40 +void spc_set_output( SNES_SPC*, spc_sample_t* out, int out_size );
   43.41 +
   43.42 +/* Number of samples written to output since last set */
   43.43 +int spc_sample_count( SNES_SPC const* );
   43.44 +
   43.45 +/* Resets SPC to power-on state. This resets your output buffer, so you must
   43.46 +call spc_set_output() after this. */
   43.47 +void spc_reset( SNES_SPC* );
   43.48 +
   43.49 +/* Emulates pressing reset switch on SNES. This resets your output buffer, so
   43.50 +you must call spc_set_output() after this. */
   43.51 +void spc_soft_reset( SNES_SPC* );
   43.52 +
   43.53 +/* 1024000 SPC clocks per second, sample pair every 32 clocks */
   43.54 +typedef int spc_time_t;
   43.55 +enum { spc_clock_rate = 1024000 };
   43.56 +enum { spc_clocks_per_sample = 32 };
   43.57 +
   43.58 +/* Reads/writes port at specified time */
   43.59 +enum { spc_port_count = 4 };
   43.60 +int  spc_read_port ( SNES_SPC*, spc_time_t, int port );
   43.61 +void spc_write_port( SNES_SPC*, spc_time_t, int port, int data );
   43.62 +
   43.63 +/* Runs SPC to end_time and starts a new time frame at 0 */
   43.64 +void spc_end_frame( SNES_SPC*, spc_time_t end_time );
   43.65 +
   43.66 +
   43.67 +/**** Sound control ****/
   43.68 +
   43.69 +/*Mutes voices corresponding to non-zero bits in mask. Reduces emulation accuracy. */
   43.70 +enum { spc_voice_count = 8 };
   43.71 +void spc_mute_voices( SNES_SPC*, int mask );
   43.72 +
   43.73 +/* If true, prevents channels and global volumes from being phase-negated.
   43.74 +Only supported by fast DSP; has no effect on accurate DSP. */
   43.75 +void spc_disable_surround( SNES_SPC*, int disable );
   43.76 +
   43.77 +/* Sets tempo, where spc_tempo_unit = normal, spc_tempo_unit / 2 = half speed, etc. */
   43.78 +enum { spc_tempo_unit = 0x100 };
   43.79 +void spc_set_tempo( SNES_SPC*, int );
   43.80 +
   43.81 +
   43.82 +/**** SPC music playback *****/
   43.83 +
   43.84 +/* Loads SPC data into emulator. Returns NULL on success, otherwise error string. */
   43.85 +spc_err_t spc_load_spc( SNES_SPC*, void const* spc_in, long size );
   43.86 +
   43.87 +/* Clears echo region. Useful after loading an SPC as many have garbage in echo. */
   43.88 +void spc_clear_echo( SNES_SPC* );
   43.89 +
   43.90 +/* Plays for count samples and write samples to out. Discards samples if out
   43.91 +is NULL. Count must be a multiple of 2 since output is stereo. */
   43.92 +spc_err_t spc_play( SNES_SPC*, int count, short* out );
   43.93 +
   43.94 +/* Skips count samples. Several times faster than spc_play(). */
   43.95 +spc_err_t spc_skip( SNES_SPC*, int count );
   43.96 +
   43.97 +
   43.98 +/**** State save/load (only available with accurate DSP) ****/
   43.99 +
  43.100 +/* Saves/loads exact emulator state */
  43.101 +enum { spc_state_size = 67 * 1024L }; /* maximum space needed when saving */
  43.102 +typedef void (*spc_copy_func_t)( unsigned char** io, void* state, size_t );
  43.103 +void spc_copy_state( SNES_SPC*, unsigned char** io, spc_copy_func_t );
  43.104 +
  43.105 +/* Writes minimal SPC file header to spc_out */
  43.106 +void spc_init_header( void* spc_out );
  43.107 +
  43.108 +/* Saves emulator state as SPC file data. Writes spc_file_size bytes to spc_out.
  43.109 +Does not set up SPC header; use spc_init_header() for that. */
  43.110 +enum { spc_file_size = 0x10200 }; /* spc_out must have this many bytes allocated */
  43.111 +void spc_save_spc( SNES_SPC*, void* spc_out );
  43.112 +
  43.113 +/* Returns non-zero if new key-on events occurred since last check. Useful for 
  43.114 +trimming silence while saving an SPC. */
  43.115 +int spc_check_kon( SNES_SPC* );
  43.116 +
  43.117 +
  43.118 +/**** SPC_Filter ****/
  43.119 +
  43.120 +typedef struct SPC_Filter SPC_Filter;
  43.121 +
  43.122 +/* Creates new filter. NULL if out of memory. */
  43.123 +SPC_Filter* spc_filter_new( void );
  43.124 +
  43.125 +/* Frees filter */
  43.126 +void spc_filter_delete( SPC_Filter* );
  43.127 +
  43.128 +/* Filters count samples of stereo sound in place. Count must be a multiple of 2. */
  43.129 +void spc_filter_run( SPC_Filter*, spc_sample_t* io, int count );
  43.130 +
  43.131 +/* Clears filter to silence */
  43.132 +void spc_filter_clear( SPC_Filter* );
  43.133 +
  43.134 +/* Sets gain (volume), where spc_filter_gain_unit is normal. Gains greater than
  43.135 +spc_filter_gain_unit are fine, since output is clamped to 16-bit sample range. */
  43.136 +enum { spc_filter_gain_unit = 0x100 };
  43.137 +void spc_filter_set_gain( SPC_Filter*, int gain );
  43.138 +
  43.139 +/* Sets amount of bass (logarithmic scale) */
  43.140 +enum { spc_filter_bass_none =  0 };
  43.141 +enum { spc_filter_bass_norm =  8 }; /* normal amount */
  43.142 +enum { spc_filter_bass_max  = 31 };
  43.143 +void spc_filter_set_bass( SPC_Filter*, int bass );
  43.144 +
  43.145 +
  43.146 +#ifdef __cplusplus
  43.147 +	}
  43.148 +#endif
  43.149 +
  43.150 +#endif
    44.1 Binary file snes_spc/spc.h.gch has changed