view Plugins/Input/console/Spc_Dsp.cpp @ 90:252843aac42f trunk

[svn] Import the initial sources for console music support.
author nenolod
date Tue, 01 Nov 2005 19:57:26 -0800
parents
children 7c5e886205ef
line wrap: on
line source


// Game_Music_Emu 0.2.4. http://www.slack.net/~ant/libs/

// Based on Brad Martin's OpenSPC DSP emulator.

#include "Spc_Dsp.h"

#include <string.h>

#include "blargg_endian.h"

/* Copyright (C) 2002 Brad Martin */
/* Copyright (C) 2004-2005 Shay Green. This module is free software; you
can redistribute it and/or modify it under the terms of the GNU Lesser
General Public License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version. This
module is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
more details. You should have received a copy of the GNU Lesser General
Public License along with this module; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */

#include BLARGG_SOURCE_BEGIN

Spc_Dsp::Spc_Dsp( uint8_t* ram_ ) : ram( ram_ )
{
	voices_muted = 0;
	set_gain( 1.0 );
	
	BOOST_STATIC_ASSERT( sizeof (g) == register_count && sizeof (voice) == register_count );
}

void Spc_Dsp::reset()
{
	keys = 0;
	echo_ptr = 0;
	noise_count = 0;
	noise = 1;
	fir_offset = 0;
	
	g.flags = 0xE0; // reset, mute, echo off
	g.key_ons = 0;
	
	for ( int i = 0; i < voice_count; i++ ) {
		voice_state [i].on_cnt = 0;
		voice_state [i].envstate = state_release;
	}
	
	memset( fir_buf, 0, sizeof fir_buf );
	memset( voice_vol, 0, sizeof voice_vol );
}

void Spc_Dsp::write( int i, int data )
{
	require( (unsigned) i < register_count );
	
	reg [i] = data;
	int high = i >> 4;
	switch ( i & 0x0f )
	{
		// voice volume
		case 0:
		case 1: {
			int left = (int8_t) reg [i & ~1];
			int right = (int8_t) reg [i | 1];
			voice_vol [high] [0] = left; 
			voice_vol [high] [1] = right; 
			// kill surround only if signs of volumes differ
			if ( left * right < 0 )
			{
				if ( left < 0 )
					voice_vol [high] [0] = -left;
				else
					voice_vol [high] [1] = -right;
			}
			break;
		}
		
		// fir coefficients
		case 0x0f:
			fir_coeff [high] = (int8_t) data; // sign-extend
			break;
	}
}

// This table is for envelope timing.  It represents the number of counts
// that should be subtracted from the counter each sample period (32kHz).
// The counter starts at 30720 (0x7800). Each count divides exactly into
// 0x7800 without remainder.
const int env_rate_init = 0x7800;
static const short env_rates [0x20] = {
	0x0000, 0x000F, 0x0014, 0x0018, 0x001E, 0x0028, 0x0030, 0x003C,
	0x0050, 0x0060, 0x0078, 0x00A0, 0x00C0, 0x00F0, 0x0140, 0x0180,
	0x01E0, 0x0280, 0x0300, 0x03C0, 0x0500, 0x0600, 0x0780, 0x0A00,
	0x0C00, 0x0F00, 0x1400, 0x1800, 0x1E00, 0x2800, 0x3C00, 0x7800
};

const int env_range = 0x800;

int Spc_Dsp::clock_envelope( int v )
{                               /* Return value is current 
								 * ENVX */
	raw_voice_t& raw_voice = this->voice [v];
	voice_t& voice = voice_state [v];
	
	int envx = voice.envx;
	if ( voice.envstate == state_release )
	{
		/*
		 * Docs: "When in the state of "key off". the "click" sound is 
		 * prevented by the addition of the fixed value 1/256" WTF???
		 * Alright, I'm going to choose to interpret that this way:
		 * When a note is keyed off, start the RELEASE state, which
		 * subtracts 1/256th each sample period (32kHz).  Note there's 
		 * no need for a count because it always happens every update. 
		 */
		envx -= env_range / 256;
		if ( envx <= 0 ) {
			envx = 0;
			keys &= ~(1 << v);
			return -1;
		}
		voice.envx = envx;
		raw_voice.envx = envx >> 8;
		return envx;
	}
	
	int cnt = voice.envcnt;
	int adsr1 = raw_voice.adsr [0];
	if ( adsr1 & 0x80 )
	{
		switch ( voice.envstate )
		{
			case state_attack: {
				// increase envelope by 1/64 each step
				int t = adsr1 & 15;
				if ( t == 15 ) {
					envx += env_range / 2;
				}
				else {
					cnt -= env_rates [t * 2 + 1];
					if ( cnt > 0 )
						break;
					envx += env_range / 64;
					cnt = env_rate_init;
				}
				if ( envx >= env_range ) {
					envx = env_range - 1;
					voice.envstate = state_decay;
				}
				voice.envx = envx;
				break;
			}
			
			case state_decay: {
				// Docs: "DR... [is multiplied] by the fixed value
				// 1-1/256." Well, at least that makes some sense.
				// Multiplying ENVX by 255/256 every time DECAY is
				// updated. 
				cnt -= env_rates [((adsr1 >> 3) & 0xE) + 0x10];
				if ( cnt <= 0 ) {
					cnt = env_rate_init;
					envx -= ((envx - 1) >> 8) + 1;
					voice.envx = envx;
				}
				int sustain_level = raw_voice.adsr [1] >> 5;
				
				if ( envx <= (sustain_level + 1) * 0x100 )
					voice.envstate = state_sustain;
				break;
			}
			
			case state_sustain:
				// Docs: "SR [is multiplied] by the fixed value 1-1/256."
				// Multiplying ENVX by 255/256 every time SUSTAIN is
				// updated. 
				cnt -= env_rates [raw_voice.adsr [1] & 0x1f];
				if ( cnt <= 0 ) {
					cnt = env_rate_init;
					envx -= ((envx - 1) >> 8) + 1;
					voice.envx = envx;
				}
				break;
		}
	}
	else
	{                           /* GAIN mode is set */
		/*
		 * Note: if the game switches between ADSR and GAIN modes
		 * partway through, should the count be reset, or should it
		 * continue from where it was? Does the DSP actually watch for 
		 * that bit to change, or does it just go along with whatever
		 * it sees when it performs the update? I'm going to assume
		 * the latter and not update the count, unless I see a game
		 * that obviously wants the other behavior.  The effect would
		 * be pretty subtle, in any case. 
		 */
		int t = raw_voice.gain;
		if (t < 0x80)
		{
			envx = voice.envx = t << 4;
		}
		else switch (t >> 5)
		{
		case 4:         /* Docs: "Decrease (linear): Subtraction
							 * of the fixed value 1/64." */
			cnt -= env_rates [t & 0x1F];
			if (cnt > 0)
				break;
			cnt = env_rate_init;
			envx -= env_range / 64;
			if ( envx < 0 ) {
				envx = 0;
				if ( voice.envstate == state_attack )
					voice.envstate = state_decay;
			}
			voice.envx = envx;
			break;
		case 5:         /* Docs: "Drecrease <sic> (exponential):
							 * Multiplication by the fixed value
							 * 1-1/256." */
			cnt -= env_rates [t & 0x1F];
			if (cnt > 0)
				break;
			cnt = env_rate_init;
			envx -= ((envx - 1) >> 8) + 1;
			if ( envx < 0 ) {
				envx = 0;
				if ( voice.envstate == state_attack )
					voice.envstate = state_decay;
			}
			voice.envx = envx;
			break;
		case 6:         /* Docs: "Increase (linear): Addition of
							 * the fixed value 1/64." */
			cnt -= env_rates [t & 0x1F];
			if (cnt > 0)
				break;
			cnt = env_rate_init;
			envx += env_range / 64;
			if ( envx >= env_range )
				envx = env_range - 1;
			voice.envx = envx;
			break;
		case 7:         /* Docs: "Increase (bent line): Addition
							 * of the constant 1/64 up to .75 of the
							 * constaint <sic> 1/256 from .75 to 1." */
			cnt -= env_rates [t & 0x1F];
			if (cnt > 0)
				break;
			cnt = env_rate_init;
			if ( envx < env_range * 3 / 4 )
				envx += env_range / 64;
			else
				envx += env_range / 256;
			if ( envx >= env_range )
				envx = env_range - 1;
			voice.envx = envx;
			break;
		}
	}
	voice.envcnt = cnt;
	raw_voice.envx = envx >> 4;
	return envx;
}

// Clamp n into range -32768 <= n <= 32767
inline int clamp_16( int n )
{
	if ( (BOOST::int16_t) n != n )
		n = BOOST::int16_t (0x7FFF - (n >> 31));
	return n;
}

void Spc_Dsp::run( long count, short* out_buf )
{
	// to do: make clock_envelope() inline to avoid out-of-line calls?
	
	// Should we just fill the buffer with silence? Flags won't be cleared
	// during this run so it seems it should keep resetting every sample.
	if ( g.flags & 0x80 )
		reset();
	
	struct src_dir {
		char start [2];
		char loop [2];
	};
	
	const src_dir* const sd = (src_dir*) &ram [g.wave_page * 0x100];
	
	int const left_volume = g.left_volume * emu_gain;
	int right_volume = g.right_volume * emu_gain;
	if ( left_volume * right_volume < 0 )
		right_volume = -right_volume; // kill global surround
	
	while ( --count >= 0 )
	{
		// Here we check for keys on/off.  Docs say that successive writes
		// to KON/KOF must be separated by at least 2 Ts periods or risk
		// being neglected.  Therefore DSP only looks at these during an
		// update, and not at the time of the write.  Only need to do this
		// once however, since the regs haven't changed over the whole
		// period we need to catch up with. 
		
		g.wave_ended &= ~g.key_ons; // Keying on a voice resets that bit in ENDX.
		
		if ( g.noise_enables ) {
			noise_count -= env_rates [g.flags & 0x1F];
			if ( noise_count <= 0 ) {
				noise_count = env_rate_init;
				
				if ( noise & 0x4000 )
					noise_amp += (noise & 1) ? noise : -noise;
				else
					noise_amp >>= 1;
				
				int feedback = (noise << 13) ^ (noise << 14);
				noise = (feedback & 0x4000) | (noise >> 1);
			}
		}
		
		// What is the expected behavior when pitch modulation is enabled on
		// voice 0? Jurassic Park 2 does this. Assume 0 for now.
		long prev_outx = 0;
		
		int echol = 0;
		int echor = 0;
		int left = 0;
		int right = 0;
		for ( int vidx = 0; vidx < voice_count; vidx++ )
		{
			const int vbit = 1 << vidx;
			raw_voice_t& raw_voice = voice [vidx];
			voice_t& voice = voice_state [vidx];
			
			if ( voice.on_cnt && !--voice.on_cnt )
			{
				// key on
				keys |= vbit;
				voice.addr = GET_LE16( sd [raw_voice.waveform].start );
				voice.block_remain = 1;
				voice.envx = 0;
				voice.block_header = 0;
				voice.fraction = 0x3fff; // decode three samples immediately
				voice.interp0 = 0; // BRR decoder filter uses previous two samples
				voice.interp1 = 0;
				
				// NOTE: Real SNES does *not* appear to initialize the
				// envelope counter to anything in particular. The first
				// cycle always seems to come at a random time sooner than 
				// expected; as yet, I have been unable to find any
				// pattern.  I doubt it will matter though, so we'll go
				// ahead and do the full time for now. 
				voice.envcnt = env_rate_init;
				voice.envstate = state_attack;
			}
			
			if ( g.key_ons & vbit & ~g.key_offs ) {
				// voice doesn't come on if key off is set
				g.key_ons &= ~vbit;
				voice.on_cnt = 8;
			}
			
			if ( keys & g.key_offs & vbit ) {
				// key off
				voice.envstate = state_release;
				voice.on_cnt = 0;
			}
			
			int envx;
			if ( !(keys & vbit) || (envx = clock_envelope( vidx )) < 0 ) {
				raw_voice.envx = 0;
				raw_voice.outx = 0;
				prev_outx = 0;
				continue;
			}
			
			// Decode samples when fraction >= 1.0 (0x1000)
			for ( int n = voice.fraction >> 12; --n >= 0; )
			{
				if ( !--voice.block_remain )
				{
					if ( voice.block_header & 1 )
					{
						g.wave_ended |= vbit;
					
						if ( voice.block_header & 2 ) {
							// verified (played endless looping sample and ENDX was set)
							voice.addr = GET_LE16( sd [raw_voice.waveform].loop );
						}
						else {
							// first block was end block; don't play anything (verified)
							goto sample_ended; // to do: find alternative to goto
						}
					}
					
					voice.block_header = ram [voice.addr++];
					voice.block_remain = 16; // nybbles
				}
				
				// if next block has end flag set, *this* block ends *early* (verified)
				if ( voice.block_remain == 9 && (ram [voice.addr + 5] & 3) == 1 &&
						(voice.block_header & 3) != 3 )
				{
			sample_ended:
					g.wave_ended |= vbit;
					keys &= ~vbit;
					raw_voice.envx = 0;
					voice.envx = 0;
					// add silence samples to interpolation buffer
					do {
						voice.interp3 = voice.interp2;
						voice.interp2 = voice.interp1;
						voice.interp1 = voice.interp0;
						voice.interp0 = 0;
					}
					while ( --n >= 0 );
					break;
				}
				
				int delta = ram [voice.addr];
				if ( voice.block_remain & 1 ) {
					delta <<= 4; // use lower nybble
					voice.addr++;
				}
				
				// Use sign-extended upper nybble
				delta = int8_t (delta) >> 4;
				
				// For invalid ranges (D,E,F): if the nybble is negative,
				// the result is F000.  If positive, 0000. Nothing else
				// like previous range, etc seems to have any effect.  If
				// range is valid, do the shift normally.  Note these are
				// both shifted right once to do the filters properly, but 
				// the output will be shifted back again at the end.
				int shift = voice.block_header >> 4;
				delta = (delta << shift) >> 1;
				if ( shift > 0x0C )
					delta = (delta >> 14) & ~0x7FF;
				
				// One, two and three point IIR filters
				int smp1 = voice.interp0;
				int smp2 = voice.interp1;
				switch ( (voice.block_header >> 2) & 3 )
				{
					case 0:
						break;
					
					case 1:
						delta += smp1 >> 1;
						delta += (-smp1) >> 5;
						break;
					
					case 2:
						delta += smp1;
						delta += (-(smp1 + (smp1 >> 1))) >> 5;
						delta -= smp2 >> 1;
						delta += smp2 >> 5;
						break;
					
					case 3:
						delta += smp1;
						delta += (-(smp1 + (smp1 << 2) + (smp1 << 3))) >> 7;
						delta -= smp2 >> 1;
						delta += (smp2 + (smp2 >> 1)) >> 4;
						break;
				}
				
				voice.interp3 = voice.interp2;
				voice.interp2 = smp2;
				voice.interp1 = smp1;
				voice.interp0 = BOOST::int16_t (clamp_16( delta ) * 2); // sign-extend
			}
			
			// rate (with possible modulation)
			int rate = GET_LE16( raw_voice.rate ) & 0x3fff;
			if ( g.pitch_mods & vbit )
				rate = (rate * (prev_outx + 32768)) >> 15;
			
			// fraction
			int fraction = voice.fraction & 0xfff;
			voice.fraction = fraction + rate;
			fraction >>= 4;
			
			// Gaussian interpolation using most recent 4 samples
			const short* table = gauss [fraction];
			const short* table2 = gauss [255 - fraction];
			int s = ((table  [0] * voice.interp3) >> 12) +
					((table  [1] * voice.interp2) >> 12) +
					((table2 [1] * voice.interp1) >> 12) +
					((table2 [0] * voice.interp0) >> 12);
			int output = noise_amp; // noise is almost never used
			if ( !(g.noise_enables & vbit) )
				output = clamp_16( s * 2 );
			
			int muted = vbit & voices_muted;
			
			// scale output and set outx values
			output = ((output * envx) >> 11) & ~1;
			prev_outx = output;
			raw_voice.outx = output >> 8;
			
			// apply muting if voice is externally disabled (not a SNES feature)
			if ( muted )
				output = 0;
			
			// output
			int l = (voice_vol [vidx] [0] * output) >> 7;
			int r = (voice_vol [vidx] [1] * output) >> 7;
			if ( g.echo_ons & vbit ) {
				echol += l;
				echor += r;
			}
			left += l;
			right += r;
		} // end of channel loop
		
		// main volume control
		left = (left * left_volume) >> (7 + emu_gain_bits);
		right = (right * right_volume) >> (7 + emu_gain_bits);
		
		// Echo FIR filter
		
		// read feedback from echo buffer
		int echo_ptr = this->echo_ptr;
		uint8_t* echo_buf = &ram [(g.echo_page * 0x100 + echo_ptr) & 0xFFFF];
		echo_ptr += 4;
		if ( echo_ptr >= (g.echo_delay & 15) * 0x800 )
			echo_ptr = 0;
		int fb_left = (BOOST::int16_t) GET_LE16( echo_buf ); // sign-extend
		int fb_right = (BOOST::int16_t) GET_LE16( echo_buf + 2 ); // sign-extend
		this->echo_ptr = echo_ptr;
		
		// put samples in history ring buffer
		const int fir_offset = this->fir_offset;
		short (*fir_pos) [2] = &fir_buf [fir_offset];
		this->fir_offset = (fir_offset + 7) & 7; // move backwards one step
		fir_pos [0] [0] = fb_left;
		fir_pos [0] [1] = fb_right;
		fir_pos [8] [0] = fb_left; // duplicate at +8 eliminates wrap checking below
		fir_pos [8] [1] = fb_right;
		
		// FIR
		fb_left =       fb_left * fir_coeff [7] +
				fir_pos [1] [0] * fir_coeff [6] +
				fir_pos [2] [0] * fir_coeff [5] +
				fir_pos [3] [0] * fir_coeff [4] +
				fir_pos [4] [0] * fir_coeff [3] +
				fir_pos [5] [0] * fir_coeff [2] +
				fir_pos [6] [0] * fir_coeff [1] +
				fir_pos [7] [0] * fir_coeff [0];
		
		fb_right =     fb_right * fir_coeff [7] +
				fir_pos [1] [1] * fir_coeff [6] +
				fir_pos [2] [1] * fir_coeff [5] +
				fir_pos [3] [1] * fir_coeff [4] +
				fir_pos [4] [1] * fir_coeff [3] +
				fir_pos [5] [1] * fir_coeff [2] +
				fir_pos [6] [1] * fir_coeff [1] +
				fir_pos [7] [1] * fir_coeff [0];
		
		// overlap calculations with tests
		left += (fb_left * g.left_echo_volume) >> 14;
		
		// echo buffer feedback
		if ( !(g.flags & 0x20) ) {
			echol += (fb_left * g.echo_feedback) >> 14;
			echor += (fb_right * g.echo_feedback) >> 14;
			SET_LE16( echo_buf, clamp_16( echol ) );
			SET_LE16( echo_buf + 2, clamp_16( echor ) );
		}
		
		right += (fb_right * g.right_echo_volume) >> 14;
		
		if ( out_buf )
		{
			// write final samples
			
			left = clamp_16( left );
			right = clamp_16( right );
			
			int mute = g.flags & 0x40;
			
			out_buf [0] = left;
			out_buf [1] = right;
			out_buf += 2;
			
			// muting
			if ( mute ) {
				out_buf [-2] = 0;
				out_buf [-1] = 0;
			}
		}
	}
}

// Base normal_gauss table is very close to the following:
#if 0
double e = 2.718281828;
for ( int i = 0; i < 512; i++ ) {
	double x = i / 511.0 * 2.31 - 0.05;
	double y = pow( e, -x * x ) * 1305.64;
	normal_gauss [i] = y - 16.54;
}
#endif

// Interleved gauss table (to improve cache coherency).
// gauss [i] [j] = normal_gauss [(1 - j) * 256 + i]
const short Spc_Dsp::gauss [256] [2] = {
 370,1305, 366,1305, 362,1304, 358,1304, 354,1304, 351,1304, 347,1304, 343,1303,
 339,1303, 336,1303, 332,1302, 328,1302, 325,1301, 321,1300, 318,1300, 314,1299,
 311,1298, 307,1297, 304,1297, 300,1296, 297,1295, 293,1294, 290,1293, 286,1292,
 283,1291, 280,1290, 276,1288, 273,1287, 270,1286, 267,1284, 263,1283, 260,1282,
 257,1280, 254,1279, 251,1277, 248,1275, 245,1274, 242,1272, 239,1270, 236,1269,
 233,1267, 230,1265, 227,1263, 224,1261, 221,1259, 218,1257, 215,1255, 212,1253,
 210,1251, 207,1248, 204,1246, 201,1244, 199,1241, 196,1239, 193,1237, 191,1234,
 188,1232, 186,1229, 183,1227, 180,1224, 178,1221, 175,1219, 173,1216, 171,1213,
 168,1210, 166,1207, 163,1205, 161,1202, 159,1199, 156,1196, 154,1193, 152,1190,
 150,1186, 147,1183, 145,1180, 143,1177, 141,1174, 139,1170, 137,1167, 134,1164,
 132,1160, 130,1157, 128,1153, 126,1150, 124,1146, 122,1143, 120,1139, 118,1136,
 117,1132, 115,1128, 113,1125, 111,1121, 109,1117, 107,1113, 106,1109, 104,1106,
 102,1102, 100,1098,  99,1094,  97,1090,  95,1086,  94,1082,  92,1078,  90,1074,
  89,1070,  87,1066,  86,1061,  84,1057,  83,1053,  81,1049,  80,1045,  78,1040,
  77,1036,  76,1032,  74,1027,  73,1023,  71,1019,  70,1014,  69,1010,  67,1005,
  66,1001,  65, 997,  64, 992,  62, 988,  61, 983,  60, 978,  59, 974,  58, 969,
  56, 965,  55, 960,  54, 955,  53, 951,  52, 946,  51, 941,  50, 937,  49, 932,
  48, 927,  47, 923,  46, 918,  45, 913,  44, 908,  43, 904,  42, 899,  41, 894,
  40, 889,  39, 884,  38, 880,  37, 875,  36, 870,  36, 865,  35, 860,  34, 855,
  33, 851,  32, 846,  32, 841,  31, 836,  30, 831,  29, 826,  29, 821,  28, 816,
  27, 811,  27, 806,  26, 802,  25, 797,  24, 792,  24, 787,  23, 782,  23, 777,
  22, 772,  21, 767,  21, 762,  20, 757,  20, 752,  19, 747,  19, 742,  18, 737,
  17, 732,  17, 728,  16, 723,  16, 718,  15, 713,  15, 708,  15, 703,  14, 698,
  14, 693,  13, 688,  13, 683,  12, 678,  12, 674,  11, 669,  11, 664,  11, 659,
  10, 654,  10, 649,  10, 644,   9, 640,   9, 635,   9, 630,   8, 625,   8, 620,
   8, 615,   7, 611,   7, 606,   7, 601,   6, 596,   6, 592,   6, 587,   6, 582,
   5, 577,   5, 573,   5, 568,   5, 563,   4, 559,   4, 554,   4, 550,   4, 545,
   4, 540,   3, 536,   3, 531,   3, 527,   3, 522,   3, 517,   2, 513,   2, 508,
   2, 504,   2, 499,   2, 495,   2, 491,   2, 486,   1, 482,   1, 477,   1, 473,
   1, 469,   1, 464,   1, 460,   1, 456,   1, 451,   1, 447,   1, 443,   1, 439,
   0, 434,   0, 430,   0, 426,   0, 422,   0, 418,   0, 414,   0, 410,   0, 405,
   0, 401,   0, 397,   0, 393,   0, 389,   0, 385,   0, 381,   0, 378,   0, 374,
};