diff src/console/Spc_Dsp.cxx @ 316:fb513e10174e trunk

[svn] - merge libconsole-blargg into mainline libconsole: + obsoletes plugins-ugly:sapplug
author nenolod
date Thu, 30 Nov 2006 19:54:33 -0800
parents 3da1b8942b8b
children 986f098da058
line wrap: on
line diff
--- a/src/console/Spc_Dsp.cxx	Wed Nov 29 14:42:11 2006 -0800
+++ b/src/console/Spc_Dsp.cxx	Thu Nov 30 19:54:33 2006 -0800
@@ -1,14 +1,12 @@
-
-// Game_Music_Emu 0.3.0. http://www.slack.net/~ant/
+// Game_Music_Emu 0.5.1. http://www.slack.net/~ant/
 
 // Based on Brad Martin's OpenSPC DSP emulator
 
 #include "Spc_Dsp.h"
 
+#include "blargg_endian.h"
 #include <string.h>
 
-#include "blargg_endian.h"
-
 /* Copyright (C) 2002 Brad Martin */
 /* Copyright (C) 2004-2006 Shay Green. This module is free software; you
 can redistribute it and/or modify it under the terms of the GNU Lesser
@@ -16,12 +14,16 @@
 version 2.1 of the License, or (at your option) any later version. This
 module is distributed in the hope that it will be useful, but WITHOUT ANY
 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
-FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
-more details. You should have received a copy of the GNU Lesser General
-Public License along with this module; if not, write to the Free Software
-Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
+FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+details. You should have received a copy of the GNU Lesser General Public
+License along with this module; if not, write to the Free Software Foundation,
+Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
 
-#include BLARGG_SOURCE_BEGIN
+#include "blargg_source.h"
+
+#ifdef BLARGG_ENABLE_OPTIMIZER
+	#include BLARGG_ENABLE_OPTIMIZER
+#endif
 
 Spc_Dsp::Spc_Dsp( uint8_t* ram_ ) : ram( ram_ )
 {
@@ -30,6 +32,7 @@
 	disable_surround( false );
 	
 	BOOST_STATIC_ASSERT( sizeof (g) == register_count && sizeof (voice) == register_count );
+	blargg_verify_byte_order();
 }
 
 void Spc_Dsp::mute_voices( int mask )
@@ -67,17 +70,17 @@
 	
 	reg [i] = data;
 	int high = i >> 4;
-	switch ( i & 0x0f )
+	switch ( i & 0x0F )
 	{
 		// voice volume
 		case 0:
 		case 1: {
 			short* volume = voice_state [high].volume;
 			int left  = (int8_t) reg [i & ~1];
-			int right = (int8_t) reg [i | 1];
+			int right = (int8_t) reg [i |  1];
 			volume [0] = left;
 			volume [1] = right;
-			// kill surround only if signs of volumes differ
+			// kill surround only if enabled and signs of volumes differ
 			if ( left * right < surround_threshold )
 			{
 				if ( left < 0 )
@@ -89,7 +92,7 @@
 		}
 		
 		// fir coefficients
-		case 0x0f:
+		case 0x0F:
 			fir_coeff [high] = (int8_t) data; // sign-extend
 			break;
 	}
@@ -100,7 +103,7 @@
 // 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] =
+static short const env_rates [0x20] =
 {
 	0x0000, 0x000F, 0x0014, 0x0018, 0x001E, 0x0028, 0x0030, 0x003C,
 	0x0050, 0x0060, 0x0078, 0x00A0, 0x00C0, 0x00F0, 0x0140, 0x0180,
@@ -192,7 +195,7 @@
 				// 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];
+				cnt -= env_rates [raw_voice.adsr [1] & 0x1F];
 				if ( cnt <= 0 )
 				{
 					cnt = env_rate_init;
@@ -340,6 +343,7 @@
 				
 				noise_amp = BOOST::int16_t (noise * 2);
 				
+				// TODO: switch to Galios style
 				int feedback = (noise << 13) ^ (noise << 14);
 				noise = (feedback & 0x4000) | (noise >> 1);
 			}
@@ -347,7 +351,7 @@
 		
 		// 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;
+		blargg_long prev_outx = 0;
 		
 		int echol = 0;
 		int echor = 0;
@@ -367,7 +371,7 @@
 				voice.block_remain = 1;
 				voice.envx = 0;
 				voice.block_header = 0;
-				voice.fraction = 0x3fff; // decode three samples immediately
+				voice.fraction = 0x3FFF; // decode three samples immediately
 				voice.interp0 = 0; // BRR decoder filter uses previous two samples
 				voice.interp1 = 0;
 				
@@ -474,29 +478,25 @@
 				// One, two and three point IIR filters
 				int smp1 = voice.interp0;
 				int smp2 = voice.interp1;
-				switch ( (voice.block_header >> 2) & 3 )
+				if ( voice.block_header & 8 )
 				{
-					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 += smp1;
+					delta -= smp2 >> 1;
+					if ( !(voice.block_header & 4) )
+					{
+						delta += (-smp1 - (smp1 >> 1)) >> 5;
 						delta += smp2 >> 5;
-						break;
-					
-					case 3:
-						delta += smp1;
-						delta += (-(smp1 + (smp1 << 2) + (smp1 << 3))) >> 7;
-						delta -= smp2 >> 1;
+					}
+					else
+					{
+						delta += (-smp1 * 13) >> 7;
 						delta += (smp2 + (smp2 >> 1)) >> 4;
-						break;
+					}
+				}
+				else if ( voice.block_header & 4 )
+				{
+					delta += smp1 >> 1;
+					delta += (-smp1) >> 5;
 				}
 				
 				voice.interp3 = voice.interp2;
@@ -513,16 +513,16 @@
 			// Gaussian interpolation using most recent 4 samples
 			int index = voice.fraction >> 2 & 0x3FC;
 			voice.fraction = (voice.fraction & 0x0FFF) + rate;
-			const BOOST::int16_t* table  = (BOOST::int16_t*) ((char*) gauss + index);
-			const BOOST::int16_t* table2 = (BOOST::int16_t*) ((char*) gauss + (255*4 - index));
+			const BOOST::int16_t* table  = (BOOST::int16_t const*) ((char const*) gauss + index);
+			const BOOST::int16_t* table2 = (BOOST::int16_t const*) ((char const*) gauss + (255*4 - index));
 			int s = ((table  [0] * voice.interp3) >> 12) +
-					((table  [1] * voice.interp2) >> 12);
-			s +=    ((table2 [1] * voice.interp1) >> 12) +
-			// to do: should clamp here
-					((table2 [0] * voice.interp0) >> 12);
-			int output = noise_amp; // noise is rarely used
-			if ( !(g.noise_enables & vbit) )
-				output = clamp_16( s * 2 );
+					((table  [1] * voice.interp2) >> 12) +
+					((table2 [1] * voice.interp1) >> 12);
+			s = (BOOST::int16_t) (s * 2);
+			s += (table2 [0] * voice.interp0) >> 11 & ~1;
+			int output = clamp_16( s );
+			if ( g.noise_enables & vbit )
+				output = noise_amp;
 			
 			// scale output and set outx values
 			output = (output * envx) >> 11 & ~1;
@@ -532,13 +532,13 @@
 			int l = (voice.volume [0] * output) >> voice.enabled;
 			int r = (voice.volume [1] * output) >> voice.enabled;
 			prev_outx = output;
-			raw_voice.outx = output >> 8;
+			raw_voice.outx = int8_t (output >> 8);
 			if ( g.echo_ons & vbit )
 			{
 				echol += l;
 				echor += r;
 			}
-			left += l;
+			left  += l;
 			right += r;
 		}
 		// end of channel loop
@@ -563,10 +563,10 @@
 		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_pos [0] [0] = (short) fb_left;
+		fir_pos [0] [1] = (short) fb_right;
+		fir_pos [8] [0] = (short) fb_left; // duplicate at +8 eliminates wrap checking below
+		fir_pos [8] [1] = (short) fb_right;
 		
 		// FIR
 		fb_left =       fb_left * fir_coeff [7] +
@@ -608,8 +608,8 @@
 			
 			int mute = g.flags & 0x40;
 			
-			out_buf [0] = left;
-			out_buf [1] = right;
+			out_buf [0] = (short) left;
+			out_buf [1] = (short) right;
 			out_buf += 2;
 			
 			// muting
@@ -663,4 +663,3 @@
    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,
 };
-