diff Plugins/Input/console/Spc_Dsp.cpp @ 493:c04dff121e1d trunk

[svn] hostile merge, phase 2: reimport based on new plugin code
author nenolod
date Tue, 24 Jan 2006 20:19:01 -0800
parents
children f12d7e208b43
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/console/Spc_Dsp.cpp	Tue Jan 24 20:19:01 2006 -0800
@@ -0,0 +1,666 @@
+
+// Game_Music_Emu 0.3.0. http://www.slack.net/~ant/
+
+// 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-2006 Shay Green. This module is free software; you
+can redistribute it and/or modify it under the terms of the GNU Lesser
+General Public License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version. This
+module is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
+more details. You should have received a copy of the GNU Lesser General
+Public License along with this module; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include BLARGG_SOURCE_BEGIN
+
+Spc_Dsp::Spc_Dsp( uint8_t* ram_ ) : ram( ram_ )
+{
+	set_gain( 1.0 );
+	mute_voices( 0 );
+	disable_surround( false );
+	
+	BOOST_STATIC_ASSERT( sizeof (g) == register_count && sizeof (voice) == register_count );
+}
+
+void Spc_Dsp::mute_voices( int mask )
+{
+	for ( int i = 0; i < voice_count; i++ )
+		voice_state [i].enabled = (mask >> i & 1) ? 31 : 7;
+}
+
+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_t& v = voice_state [i];
+		v.on_cnt = 0;
+		v.volume [0] = 0;
+		v.volume [1] = 0;
+		v.envstate = state_release;
+	}
+	
+	memset( fir_buf, 0, sizeof fir_buf );
+}
+
+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: {
+			short* volume = voice_state [high].volume;
+			int left  = (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
+			if ( left * right < surround_threshold )
+			{
+				if ( left < 0 )
+					volume [0] = -left;
+				else
+					volume [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;
+
+inline 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;
+			
+			case state_release:
+				// handled above
+				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 so that this becomes a leaf function?
+	
+	// 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 left_volume  = g.left_volume;
+	int right_volume = g.right_volume;
+	if ( left_volume * right_volume < surround_threshold )
+		right_volume = -right_volume; // kill global surround
+	left_volume  *= emu_gain;
+	right_volume *= emu_gain;
+	
+	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;
+				
+				noise_amp = BOOST::int16_t (noise * 2);
+				
+				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;
+			
+			// 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));
+			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 );
+			
+			// scale output and set outx values
+			output = (output * envx) >> 11 & ~1;
+			
+			// output and apply muting (by setting voice.enabled to 31)
+			// if voice is externally disabled (not a SNES feature)
+			int l = (voice.volume [0] * output) >> voice.enabled;
+			int r = (voice.volume [1] * output) >> voice.enabled;
+			prev_outx = output;
+			raw_voice.outx = output >> 8;
+			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];
+		
+		left  += (fb_left  * g.left_echo_volume ) >> 14;
+		right += (fb_right * g.right_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 ) );
+		}
+		
+		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 almost exactly (with an error of 0 or -1 for each entry):
+// int normal_gauss [512];
+// normal_gauss [i] = exp((i-511)*(i-511)*-9.975e-6)*pow(sin(0.00307096*i),1.7358)*1304.45
+
+// Interleved gauss table (to improve cache coherency).
+// gauss [i * 2 + j] = normal_gauss [(1 - j) * 256 + i]
+const BOOST::int16_t Spc_Dsp::gauss [512] =
+{
+ 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,
+};
+