mirror of
				https://github.com/TomHarte/CLK.git
				synced 2025-11-03 09:16:11 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			223 lines
		
	
	
		
			7.8 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			223 lines
		
	
	
		
			7.8 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
//
 | 
						|
//  Tables.hpp
 | 
						|
//  Clock Signal
 | 
						|
//
 | 
						|
//  Created by Thomas Harte on 15/04/2020.
 | 
						|
//  Copyright © 2020 Thomas Harte. All rights reserved.
 | 
						|
//
 | 
						|
 | 
						|
#pragma once
 | 
						|
 | 
						|
namespace Yamaha::OPL {
 | 
						|
 | 
						|
/*
 | 
						|
	These are the OPL's built-in log-sin and exponentiation tables, as recovered by
 | 
						|
	Matthew Gambrell and Olli Niemitalo in 'OPLx decapsulated'. Despite the formulas
 | 
						|
	being well known, I've elected not to generate these at runtime because even if I
 | 
						|
	did, I'd just end up with the proper values laid out in full in a unit test, and
 | 
						|
	they're very compact.
 | 
						|
*/
 | 
						|
 | 
						|
/*!
 | 
						|
	Represents both the logarithm of a value and its sign.
 | 
						|
 | 
						|
	It's actually the negative logarithm, in base two, in fixed point.
 | 
						|
*/
 | 
						|
struct LogSign {
 | 
						|
	int log;
 | 
						|
	int sign;
 | 
						|
 | 
						|
	void reset() {
 | 
						|
		log = 0;
 | 
						|
		sign = 1;
 | 
						|
	}
 | 
						|
 | 
						|
	LogSign &operator +=(int attenuation) {
 | 
						|
		log += attenuation;
 | 
						|
		return *this;
 | 
						|
	}
 | 
						|
 | 
						|
	LogSign &operator +=(LogSign log_sign) {
 | 
						|
		log += log_sign.log;
 | 
						|
		sign *= log_sign.sign;
 | 
						|
		return *this;
 | 
						|
	}
 | 
						|
 | 
						|
	int level(int fractional = 0) const;
 | 
						|
};
 | 
						|
 | 
						|
/*!
 | 
						|
	@returns Negative log sin of x, assuming a 1024-unit circle.
 | 
						|
*/
 | 
						|
constexpr LogSign negative_log_sin(int x) {
 | 
						|
	/// Defines the first quadrant of 1024-unit negative log to the base two of sine (that conveniently misses sin(0)).
 | 
						|
	///
 | 
						|
	/// Expected branchless usage for a full 1024 unit output:
 | 
						|
	///
 | 
						|
	///	constexpr int multiplier[] = { 1, -1 };
 | 
						|
	///	constexpr int mask[] = { 0, 255 };
 | 
						|
	///
 | 
						|
	/// value = exp( log_sin[angle & 255] ^ mask[(angle >> 8) & 1]) * multitplier[(angle >> 9) & 1]
 | 
						|
	///
 | 
						|
	/// ... where exp(x) = 2 ^ -x / 256
 | 
						|
	constexpr int16_t log_sin[] = {
 | 
						|
		2137,	1731,	1543,	1419,	1326,	1252,	1190,	1137,
 | 
						|
		1091,	1050,	1013,	979,	949,	920,	894,	869,
 | 
						|
		846,	825,	804,	785,	767,	749,	732,	717,
 | 
						|
		701,	687,	672,	659,	646,	633,	621,	609,
 | 
						|
		598,	587,	576,	566,	556,	546,	536,	527,
 | 
						|
		518,	509,	501,	492,	484,	476,	468,	461,
 | 
						|
		453,	446,	439,	432,	425,	418,	411,	405,
 | 
						|
		399,	392,	386,	380,	375,	369,	363,	358,
 | 
						|
		352,	347,	341,	336,	331,	326,	321,	316,
 | 
						|
		311,	307,	302,	297,	293,	289,	284,	280,
 | 
						|
		276,	271,	267,	263,	259,	255,	251,	248,
 | 
						|
		244,	240,	236,	233,	229,	226,	222,	219,
 | 
						|
		215,	212,	209,	205,	202,	199,	196,	193,
 | 
						|
		190,	187,	184,	181,	178,	175,	172,	169,
 | 
						|
		167,	164,	161,	159,	156,	153,	151,	148,
 | 
						|
		146,	143,	141,	138,	136,	134,	131,	129,
 | 
						|
		127,	125,	122,	120,	118,	116,	114,	112,
 | 
						|
		110,	108,	106,	104,	102,	100,	98,		96,
 | 
						|
		94,		92,		91,		89,		87,		85,		83,		82,
 | 
						|
		80,		78,		77,		75,		74,		72,		70,		69,
 | 
						|
		67,		66,		64,		63,		62,		60,		59,		57,
 | 
						|
		56,		55,		53,		52,		51,		49,		48,		47,
 | 
						|
		46,		45,		43,		42,		41,		40,		39,		38,
 | 
						|
		37,		36,		35,		34,		33,		32,		31,		30,
 | 
						|
		29,		28,		27,		26,		25,		24,		23,		23,
 | 
						|
		22,		21,		20,		20,		19,		18,		17,		17,
 | 
						|
		16,		15,		15,		14,		13,		13,		12,		12,
 | 
						|
		11,		10,		10,		9,		9,		8,		8,		7,
 | 
						|
		7,		7,		6,		6,		5,		5,		5,		4,
 | 
						|
		4,		4,		3,		3,		3,		2,		2,		2,
 | 
						|
		2,		1,		1,		1,		1,		1,		1,		1,
 | 
						|
		0,		0,		0,		0,		0,		0,		0,		0
 | 
						|
	};
 | 
						|
	constexpr int16_t sign[] = { 1, -1 };
 | 
						|
	constexpr int16_t mask[] = { 0, 255 };
 | 
						|
 | 
						|
	return {
 | 
						|
		.log = log_sin[(x & 255) ^ mask[(x >> 8) & 1]],
 | 
						|
		.sign = sign[(x >> 9) & 1]
 | 
						|
	};
 | 
						|
}
 | 
						|
 | 
						|
/*!
 | 
						|
	Computes the linear value represented by the log-sign @c ls, shifted left by @c fractional prior
 | 
						|
	to loss of precision.
 | 
						|
*/
 | 
						|
constexpr int power_two(LogSign ls, int fractional = 0) {
 | 
						|
	/// A derivative of the exponent table in a real OPL2; mapped_exp[x] = (source[c ^ 0xff] << 1) | 0x800.
 | 
						|
	///
 | 
						|
	/// The ahead-of-time transformation represents fixed work the OPL2 does when reading its table
 | 
						|
	/// independent on the input.
 | 
						|
	///
 | 
						|
	/// The original table is a 0.10 fixed-point representation of 2^x - 1 with bit 10 implicitly set, where x is
 | 
						|
	/// in 0.8 fixed point.
 | 
						|
	///
 | 
						|
	/// Since the log_sin table represents sine in a negative base-2 logarithm, values from it would need
 | 
						|
	/// to be negatived before being put into the original table. That's haned with the ^ 0xff. The | 0x800 is to
 | 
						|
	/// set the implicit bit 10 (subject to the shift).
 | 
						|
	///
 | 
						|
	/// The shift by 1 is to allow the chip's exploitation of the recursive symmetry of the exponential table to
 | 
						|
	/// be achieved more easily. Specifically, to convert a logarithmic attenuation to a linear one, just perform:
 | 
						|
	///
 | 
						|
	///	result = mapped_exp[x & 0xff] >> (x >> 8)
 | 
						|
	constexpr int16_t mapped_exp[] = {
 | 
						|
		4084,	4074,	4062,	4052,	4040,	4030,	4020,	4008,
 | 
						|
		3998,	3986,	3976,	3966,	3954,	3944,	3932,	3922,
 | 
						|
		3912,	3902,	3890,	3880,	3870,	3860,	3848,	3838,
 | 
						|
		3828,	3818,	3808,	3796,	3786,	3776,	3766,	3756,
 | 
						|
		3746,	3736,	3726,	3716,	3706,	3696,	3686,	3676,
 | 
						|
		3666,	3656,	3646,	3636,	3626,	3616,	3606,	3596,
 | 
						|
		3588,	3578,	3568,	3558,	3548,	3538,	3530,	3520,
 | 
						|
		3510,	3500,	3492,	3482,	3472,	3464,	3454,	3444,
 | 
						|
		3434,	3426,	3416,	3408,	3398,	3388,	3380,	3370,
 | 
						|
		3362,	3352,	3344,	3334,	3326,	3316,	3308,	3298,
 | 
						|
		3290,	3280,	3272,	3262,	3254,	3246,	3236,	3228,
 | 
						|
		3218,	3210,	3202,	3192,	3184,	3176,	3168,	3158,
 | 
						|
		3150,	3142,	3132,	3124,	3116,	3108,	3100,	3090,
 | 
						|
		3082,	3074,	3066,	3058,	3050,	3040,	3032,	3024,
 | 
						|
		3016,	3008,	3000,	2992,	2984,	2976,	2968,	2960,
 | 
						|
		2952,	2944,	2936,	2928,	2920,	2912,	2904,	2896,
 | 
						|
		2888,	2880,	2872,	2866,	2858,	2850,	2842,	2834,
 | 
						|
		2826,	2818,	2812,	2804,	2796,	2788,	2782,	2774,
 | 
						|
		2766,	2758,	2752,	2744,	2736,	2728,	2722,	2714,
 | 
						|
		2706,	2700,	2692,	2684,	2678,	2670,	2664,	2656,
 | 
						|
		2648,	2642,	2634,	2628,	2620,	2614,	2606,	2600,
 | 
						|
		2592,	2584,	2578,	2572,	2564,	2558,	2550,	2544,
 | 
						|
		2536,	2530,	2522,	2516,	2510,	2502,	2496,	2488,
 | 
						|
		2482,	2476,	2468,	2462,	2456,	2448,	2442,	2436,
 | 
						|
		2428,	2422,	2416,	2410,	2402,	2396,	2390,	2384,
 | 
						|
		2376,	2370,	2364,	2358,	2352,	2344,	2338,	2332,
 | 
						|
		2326,	2320,	2314,	2308,	2300,	2294,	2288,	2282,
 | 
						|
		2276,	2270,	2264,	2258,	2252,	2246,	2240,	2234,
 | 
						|
		2228,	2222,	2216,	2210,	2204,	2198,	2192,	2186,
 | 
						|
		2180,	2174,	2168,	2162,	2156,	2150,	2144,	2138,
 | 
						|
		2132,	2128,	2122,	2116,	2110,	2104,	2098,	2092,
 | 
						|
		2088,	2082,	2076,	2070,	2064,	2060,	2054,	2048,
 | 
						|
	};
 | 
						|
 | 
						|
	return ((mapped_exp[ls.log & 0xff] << fractional) >> (ls.log >> 8)) * ls.sign;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 | 
						|
	Credit for the fixed register lists goes to Nuke.YKT; I found them at:
 | 
						|
	https://siliconpr0n.org/archive/doku.php?id=vendor:yamaha:opl2#ym2413_instrument_rom
 | 
						|
 | 
						|
	The arrays below begin with channel 1, then each line is a single channel defined
 | 
						|
	in exactly the same terms as the OPL's user-defined channel.
 | 
						|
 | 
						|
*/
 | 
						|
 | 
						|
constexpr uint8_t opll_patch_set[] = {
 | 
						|
	0x71, 0x61, 0x1e, 0x17, 0xd0, 0x78, 0x00, 0x17,
 | 
						|
	0x13, 0x41, 0x1a, 0x0d, 0xd8, 0xf7, 0x23, 0x13,
 | 
						|
	0x13, 0x01, 0x99, 0x00, 0xf2, 0xc4, 0x11, 0x23,
 | 
						|
	0x31, 0x61, 0x0e, 0x07, 0xa8, 0x64, 0x70, 0x27,
 | 
						|
	0x32, 0x21, 0x1e, 0x06, 0xe0, 0x76, 0x00, 0x28,
 | 
						|
	0x31, 0x22, 0x16, 0x05, 0xe0, 0x71, 0x00, 0x18,
 | 
						|
	0x21, 0x61, 0x1d, 0x07, 0x82, 0x81, 0x10, 0x07,
 | 
						|
	0x23, 0x21, 0x2d, 0x14, 0xa2, 0x72, 0x00, 0x07,
 | 
						|
	0x61, 0x61, 0x1b, 0x06, 0x64, 0x65, 0x10, 0x17,
 | 
						|
	0x41, 0x61, 0x0b, 0x18, 0x85, 0xf7, 0x71, 0x07,
 | 
						|
	0x13, 0x01, 0x83, 0x11, 0xfa, 0xe4, 0x10, 0x04,
 | 
						|
	0x17, 0xc1, 0x24, 0x07, 0xf8, 0xf8, 0x22, 0x12,
 | 
						|
	0x61, 0x50, 0x0c, 0x05, 0xc2, 0xf5, 0x20, 0x42,
 | 
						|
	0x01, 0x01, 0x55, 0x03, 0xc9, 0x95, 0x03, 0x02,
 | 
						|
	0x61, 0x41, 0x89, 0x03, 0xf1, 0xe4, 0x40, 0x13,
 | 
						|
};
 | 
						|
 | 
						|
constexpr uint8_t vrc7_patch_set[] = {
 | 
						|
	0x03, 0x21, 0x05, 0x06, 0xe8, 0x81, 0x42, 0x27,
 | 
						|
	0x13, 0x41, 0x14, 0x0d, 0xd8, 0xf6, 0x23, 0x12,
 | 
						|
	0x11, 0x11, 0x08, 0x08, 0xfa, 0xb2, 0x20, 0x12,
 | 
						|
	0x31, 0x61, 0x0c, 0x07, 0xa8, 0x64, 0x61, 0x27,
 | 
						|
	0x32, 0x21, 0x1e, 0x06, 0xe1, 0x76, 0x01, 0x28,
 | 
						|
	0x02, 0x01, 0x06, 0x00, 0xa3, 0xe2, 0xf4, 0xf4,
 | 
						|
	0x21, 0x61, 0x1d, 0x07, 0x82, 0x81, 0x11, 0x07,
 | 
						|
	0x23, 0x21, 0x22, 0x17, 0xa2, 0x72, 0x01, 0x17,
 | 
						|
	0x35, 0x11, 0x25, 0x00, 0x40, 0x73, 0x72, 0x01,
 | 
						|
	0xb5, 0x01, 0x0f, 0x0f, 0xa8, 0xa5, 0x51, 0x02,
 | 
						|
	0x17, 0xc1, 0x24, 0x07, 0xf8, 0xf8, 0x22, 0x12,
 | 
						|
	0x71, 0x23, 0x11, 0x06, 0x65, 0x74, 0x18, 0x16,
 | 
						|
	0x01, 0x02, 0xd3, 0x05, 0xc9, 0x95, 0x03, 0x02,
 | 
						|
	0x61, 0x63, 0x0c, 0x00, 0x94, 0xc0, 0x33, 0xf6,
 | 
						|
	0x21, 0x72, 0x0d, 0x00, 0xc1, 0xd5, 0x56, 0x06,
 | 
						|
};
 | 
						|
 | 
						|
constexpr uint8_t percussion_patch_set[] = {
 | 
						|
	0x01, 0x01, 0x18, 0x0f, 0xdf, 0xf8, 0x6a, 0x6d,
 | 
						|
	0x01, 0x01, 0x00, 0x00, 0xc8, 0xd8, 0xa7, 0x48,
 | 
						|
	0x05, 0x01, 0x00, 0x00, 0xf8, 0xaa, 0x59, 0x55,
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
inline int LogSign::level(int fractional) const {
 | 
						|
	return power_two(*this, fractional);
 | 
						|
}
 | 
						|
 | 
						|
}
 |