821 lines
		
	
	
		
			33 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			821 lines
		
	
	
		
			33 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| // license:BSD-3-Clause
 | |
| 
 | |
| /**********************************************************************************************
 | |
|  *
 | |
|  *   SGS-Thomson Microelectronics M114S/M114A/M114AF Digital Sound Generator
 | |
|  *   by Steve Ellenoff
 | |
|  *   09/02/2004
 | |
|  *
 | |
|  *   Thanks to R.Belmont for Support & Agreeing to read through that nasty data sheet with me..
 | |
|  *   Big thanks to Destruk for help in tracking down the data sheet.. Could have never done it
 | |
|  *   without it!!
 | |
|  *
 | |
|  *   A note about the word "table" as used by the M114S datasheet. A table refers to rom data
 | |
|  *   representing 1 full period/cycle of a sound. The chip always reads from 2 different tables
 | |
|  *   and intermixes them during playback for smoother sound. Different table lengths simply allow
 | |
|  *   the chip to play lower frequencies due to the fact that the table represents 1 full period,ie
 | |
|  *   1 full sine wave, if that's what the rom data happens to contain.
 | |
|  *
 | |
|  *   It would seem that the chip comes in two versions - the M114A 4Mhz & M114AF 6Mhz versions. Unlike other sound chips which
 | |
|  *   allow for clock variations on the same chip, this chip uses hard coded frequency tables
 | |
|  *   in an internal ROM based on which version of the chip is being used.
 | |
|  *
 | |
|  *   Some ideas were taken from the source from BSMT2000 & AY8910
 | |
|  *
 | |
|  *   Heavily modified/extended by Carsten Waechter later-on
 | |
|  *
 | |
|  *   The mixer can optionally mix every (internal) channel into a separate stream for testing (set M114S_OUTPUT_CHANNELS to 16)
 | |
|  *
 | |
|  *   TODO: - No full/tested support for the M114AF 6Mhz version of the chip (but seems at least to work 'good enough')
 | |
|  *         - Maybe also low pass filter heavily/some channels only?? (some channels sound too high frequency heavy (clicks, pops), for example on Dakar)
 | |
|  **********************************************************************************************/
 | |
| 
 | |
| #include "m114s.h"
 | |
| #include <stdbool.h>
 | |
| 
 | |
| #if defined(_MSC_VER) && (_MSC_VER <= 1500)
 | |
|  #define llabs _abs64
 | |
| #endif
 | |
| 
 | |
| #define SAMPLE_RATE 48000
 | |
| 
 | |
| #define USE_FREQTABLE_FROM_MANUAL // undef to use a generated freqtable with 'correct' semitones (i.e. unlike the real chip) for the M114A 4MHz
 | |
| 
 | |
| //!! unsure how the actual vol envelope actually works internally and at what precision -> spec says 'either immediate' (=no envelope) or 'gradual increments of 1/256 of maximum amplitude'
 | |
| // BUT THEN also mentions: only 8 MSBits from the 10 of v_linear are influenced! -> simple increase/decrease of the 8 MSBits with same frequency as table read (if diff > 128, every 2nd read if diff > 64, every 4th read if diff > 32 or every 8th read if diff <= 32)
 | |
| #define USE_VOL_ENVELOPE // to test no volume envelope (=no smooth blending in of new volume that is set), set to 0
 | |
| 
 | |
| #define DO_FULL_PRECISION_MIXING // unclear how the mixing of channels and interpolation of channels works internally, so this allows to switch between two modes (use highest precision vs a lower precision/interpretation of the datasheet text)
 | |
| #define USE_LERP_FOR_REPEATED_SAMPLES // unclear how repeated table reads really work, datasheet can be interpreted either way
 | |
| 
 | |
| #define MR_GAME_VOLUME_HACK // rather do this for specific machines only!? (i.e. is this only due to the filter network of output channels of Mr.Game??!)
 | |
| 
 | |
| #if 0
 | |
| #include <stdio.h>
 | |
| #include <stdlib.h>
 | |
| #define LOG(x) printf x
 | |
| #else
 | |
| #define LOG(x) logerror x
 | |
| #endif
 | |
| 
 | |
| /**********************************************************************************************
 | |
| 
 | |
|      CONSTANTS
 | |
| 
 | |
| ***********************************************************************************************/
 | |
| 
 | |
| #define FRAC_BITS				16
 | |
| #define FRAC_ONE				(1 << FRAC_BITS)
 | |
| #define FRAC_MASK				(FRAC_ONE - 1)
 | |
| 
 | |
| /**********************************************************************************************
 | |
| 
 | |
|      GLOBALS
 | |
| 
 | |
| ***********************************************************************************************/
 | |
| 
 | |
| /* Table 1 & Table 2 Repetition Values based on Mode */
 | |
| static const int mode_to_rep[8][2] = {
 | |
|   {2,2},	//Mode 0
 | |
|   {1,1},	//Mode 1
 | |
|   {4,4},	//Mode 2
 | |
|   {1,1},	//Mode 3
 | |
|   {1,2},	//Mode 4
 | |
|   {1,1},	//Mode 5
 | |
|   {1,4},	//Mode 6
 | |
|   {1,1}		//Mode 7
 | |
| };
 | |
| 
 | |
| /* Table 1 Length Values based on Mode */ // these are always larger as table 2 values! (thus mixing code below makes sense to not handle the other case)
 | |
| static const int mode_to_len_t1[8][8] = {
 | |
| {16,32,64,128,256,512,1024,2048 },	//Mode 0
 | |
| {16,32,64,128,256,512,1024,2048 },	//Mode 1
 | |
| {16,32,64,128,256,512,1024,1024 },	//Mode 2
 | |
| {16,32,64,128,256,512,1024,2048 },	//Mode 3
 | |
| {16,32,64,128,256,512,1024,2048 },	//Mode 4
 | |
| {16,32,64,128,256,512,1024,2048 },	//Mode 5
 | |
| {16,32,64,128,256,512,1024,2048 },	//Mode 6
 | |
| {16,32,64,128,256,512,1024,2048 },	//Mode 7
 | |
| };
 | |
| 
 | |
| /* Table 2 Length Values based on Mode */
 | |
| static const int mode_to_len_t2[8][8] = {
 | |
| {16,32,64,128,256,512,1024,2048 },	//Mode 0 //datasheet has last value = 1048 //!! -> try 1024 instead??
 | |
| {16,32,64,128,256,512,1024,2048 },	//Mode 1
 | |
| {16,32,64,128,256,512,1024,1024 },	//Mode 2
 | |
| {16,32,64,128,256,512,1024,2048 },	//Mode 3
 | |
| { 8,16,32, 64,128,256, 512,1024 },	//Mode 4
 | |
| {16,16,16, 32, 64,128, 256, 512 },	//Mode 5
 | |
| { 4, 8,16, 32, 64,128, 256, 512 },	//Mode 6
 | |
| {16,16,16, 16, 32, 64, 128, 256 },	//Mode 7
 | |
| };
 | |
| 
 | |
| /* Attenuation Table */
 | |
| static const int v_linear[32] = {
 | |
| 1023,939,863,791,727,667,611,559,515,471,431,
 | |
|  395,363,335,307,283,259,235,215,199,183,166,
 | |
|  152,140,128,117,107, 98, 90, 83, 76, 69
 | |
| };
 | |
| // a_decibel = 20 * log((v_linear+1)/1024)
 | |
| /*static const double a_decibel[32] = {
 | |
|  0.00, 0.74, 1.48, 2.23, 2.96, 3.71, 4.47, 5.24, 5.95,
 | |
|  6.73, 7.50, 8.25, 8.98, 9.68,10.43,11.14,11.91,12.75,
 | |
| 13.52,14.19,14.91,15.75,16.51,17.22,17.99,18.77,19.54,
 | |
| 20.29,21.03,21.72,22.48,23.30
 | |
| };*/
 | |
| 
 | |
| #ifdef USE_FREQTABLE_FROM_MANUAL
 | |
| /* Frequency Table for a 4Mhz Clocked Chip */
 | |
| static const double freqtable4Mhz[256] = {
 | |
|  1016.78,1021.45,1026.69,1031.46,1036.27,1041.67,1044.39,1045.48,
 | |
|  1046.57,1047.67,1048.77,1051.52,1056.52,1061.57,1066.67,1071.81,	//0x00 - 0x0F
 | |
|  1077.01,1082.25,1087.55,1092.90,1098.30,1103.14,1106.81,1107.42,
 | |
|  1108.65,1109.88,1111.11,1114.21,1119.19,1124.86,1130.58,1135.72,	//0x10 - 0x1F
 | |
|  1140.90,1146.79,1152.07,1158.08,1163.47,1168.91,1172.33,1173.71,
 | |
|  1174.40,1175.78,1177.16,1180.64,1186.24,1191.90,1197.60,1203.37,	//0x20 - 0x2F
 | |
|  1209.19,1215.07,1221.00,1226.99,1232.29,1238.39,1242.24,1243.78,
 | |
|  1244.56,1245.33,1246.88,1250.78,1256.28,1262.63,1269.04,1274.70,	//0x30 - 0x3F
 | |
|  1281.23,1287.00,1293.66,1299.55,1305.48,1312.34,1315.79,1317.52,
 | |
|  1318.39,1319.26,1321.00,1324.50,1331.56,1337.79,1344.09,1350.44,	//0x40 - 0x4F
 | |
|  1356.85,1363.33,1369.86,1376.46,1383.13,1389.85,1393.73,1395.67,
 | |
|  1396.65,1397.62,1398.60,1403.51,1410.44,1417.43,1424.50,1430.62,	//0x50 - 0x5F
 | |
|  1437.81,1445.09,1451.38,1458.79,1466.28,1472.75,1478.20,1479.29,
 | |
|  1480.38,1481.48,1482.58,1486.99,1494.77,1501.50,1508.30,1516.30,	//0x60 - 0x6F
 | |
|  1523.23,1530.22,1538.46,1545.60,1552.80,1560.06,1564.95,1566.17,
 | |
|  1567.40,1568.63,1569.86,1576.04,1583.53,1591.09,1598.72,1606.43,	//0x70 - 0x7F
 | |
|  1614.21,1622.06,1629.99,1638.00,1644.74,1652.89,1658.37,1659.75,
 | |
|  1661.13,1662.51,1663.89,1669.45,1677.85,1684.92,1693.48,1702.13,	//0x80 - 0x8F
 | |
|  1709.40,1718.21,1727.12,1734.61,1743.68,1751.31,1757.47,1759.01,	//(2nd entry in manual shows 1781.21 but that's cleary wrong)
 | |
|  1760.56,1762.11,1763.89,1768.35,1777.78,1785.71,1793.72,1803.43,	//0x90 - 0x9F
 | |
|  1811.59,1819.84,1829.83,1838.24,1846.72,1855.29,1860.47,1862.20,
 | |
|  1863.93,1865.67,1867.41,1874.41,1883.24,1892.15,1901.14,1910.22,	//0xA0 - 0xAF
 | |
|  1919.39,1928.64,1937.98,1947.42,1956.95,1966.57,1972.39,1974.33,
 | |
|  1976.28,1978.24,1980.20,1984.13,1994.02,2004.01,2014.10,2024.29,	//0xB0 - 0xBF
 | |
|  2032.52,2042.90,2053.39,2063.98,2072.54,2083.33,2087.68,2089.86,
 | |
|  2092.05,2094.24,2096.44,2103.05,2114.16,2123.14,2134.47,2143.62,	//0xC0 - 0xCF
 | |
|  2155.17,2164.50,2176.28,2185.79,2195.39,2207.51,2212.39,2214.84,
 | |
|  2217.29,2219.76,2222.22,2227.17,2239.64,2249.72,2259.89,2272.73,	//0xD0 - 0xDF
 | |
|  2283.11,2293.58,2304.15,2314.81,2325.58,2339.18,2344.67,2347.42,
 | |
|  2350.18,2352.94,2355.71,2361.28,2372.48,2383.79,2395.21,2406.74,	//0xE0 - 0xEF
 | |
|  0,0,0,0,0,0,0,0,
 | |
|  0,0,0,0,0,0,0,0,													//0xF0 - 0xFF (Special codes)
 | |
| };
 | |
| 
 | |
| /* Frequency Table for a 6Mhz Clocked Chip */
 | |
| static const double freqtable6Mhz[256] = {
 | |
|  1523.78,1523.79,1538.64,1545.79,1552.99,1561.08,1565.16,1566.80,
 | |
|  1568.44,1570.08,1571.73,1575.86,1583.35,1590.91,1598.55,1606.26,	//0x00 - 0x0F
 | |
|  1614.04,1621.90,1629.84,1637.86,1645.95,1653.22,1658.71,1659.62,
 | |
|  1661.46,1663.31,1665.16,1669.79,1677.27,1685.76,1694.34,1702.03,	//0x10 - 0x1F
 | |
|  1709.80,1718.62,1726.54,1735.54,1743.62,1751.77,1758.91,1758.97,
 | |
|  1760.00,1762.07,1764.14,1769.35,1777.75,1786.22,1794.78,1803.42,	//0x20 - 0x2F
 | |
|  1812.14,1820.95,1829.84,1838.82,1846.75,1855.90,1861.66,1863.98,
 | |
|  1865.14,1866.30,1868.63,1874.47,1882.71,1892.22,1901.83,1910.31,	//0x30 - 0x3F
 | |
|  1920.10,1928.75,1938.73,1947.55,1956.45,1966.72,1971.89,1974.49,
 | |
|  1975.79,1977.10,1979.71,1984.95,1995.53,2004.87,2014.30,2023.82,	//0x40 - 0x4F
 | |
|  2033.43,2043.14,2052.93,2062.82,2072.82,2082.89,2088.70,2091.61,
 | |
|  2093.07,2094.54,2096.00,2103.35,2113.74,2124.22,2134.81,2143.98,	//0x50 - 0x5F
 | |
|  2154.77,2165.66,2175.09,2186.20,2197.42,2207.13,2215.28,2216.92,
 | |
|  2218.56,2220.21,2221.85,2228.46,2240.12,2250.21,2260.39,2272.39,	//0x60 - 0x6F
 | |
|  2282.77,2293.25,2305.60,2316.29,2327.08,2337.97,2345.29,2347.13,
 | |
|  2348.97,2350.81,2352.65,2361.92,2373.14,2384.47,2395.91,2407.45,	//0x70 - 0x7F
 | |
|  2419.11,2430.88,2442.77,2454.77,2464.87,2477.09,2485.31,2487.37,
 | |
|  2489.44,2491.50,2493.58,2501.90,2514.50,2525.09,2537.92,2550.88,	//0x80 - 0x8F
 | |
|  2561.78,2574.98,2588.32,2599.55,2613.15,2624.59,2633.81,2636.13,
 | |
|  2638.45,2640.78,2643.10,2650.11,2664.25,2676.14,2688.14,2702.69,	//0x90 - 0x9F
 | |
|  2714.93,2727.28,2742.25,2754.85,2767.57,2780.41,2788.17,2790.76,
 | |
|  2793.06,2795.97,2798.58,2809.07,2822.30,2835.65,2849.13,2862.73,	//0xA0 - 0xAF
 | |
|  2876.47,2890.34,2904.34,2918.48,2932.76,2947.18,2955.90,2958.82,
 | |
|  2961.74,2964.67,2967.60,2973.49,2988.31,3003.29,3018.41,3033.68,	//0xB0 - 0xBF
 | |
|  3046.02,3061.57,3077.29,3093.17,3105.99,3122.17,3128.68,3131.95,
 | |
|  3135.23,3138.51,3141.80,3151.71,3168.37,3181.83,3198.80,3212.52,	//0xC0 - 0xCF
 | |
|  3229.83,3243.81,3261.46,3275.72,3290.10,3308.26,3315.58,3319.25,
 | |
|  3322.93,3326.61,3330.31,3337.73,3356.42,3371.52,3386.76,3406.00,	//0xD0 - 0xDF
 | |
|  3421.55,3437.25,3453.09,3469.07,3485.21,3505.59,3513.81,3517.93,
 | |
|  3522.07,3526.21,3530.37,3538.70,3555.49,3572.44,3589.56,3606.84,	//0xE0 - 0xEF
 | |
|  0,0,0,0,0,0,0,0,
 | |
|  0,0,0,0,0,0,0,0,													//0xF0 - 0xFF (Special codes)
 | |
| };
 | |
| #else
 | |
| /* Frequency Table for a 4Mhz Clocked Chip
 | |
|    Note: Only the 1st set of frequencies came from the manual, the rest were calculated using 1 semitone increments
 | |
|    using a program called Test Tone Generator 3.91
 | |
| */
 | |
| static const double freqtable4Mhz[256] = {
 | |
|  1016.78,1021.45,1026.69,1031.46,1036.27,1041.67,1044.39,1045.48,
 | |
|  1046.57,1047.67,1048.77,1051.52,1056.52,1061.57,1066.67,1071.81,	//0x00 - 0x0F
 | |
|  1077.24,1082.19,1087.74,1092.79,1097.89,1103.61,1106.49,1107.65,
 | |
|  1108.80,1109.97,1111.13,1114.05,1119.34,1124.69,1130.10,1135.54,	//0x10 - 0x1F
 | |
|  1141.29,1146.54,1152.42,1157.77,1163.17,1169.24,1172.29,1173.51,
 | |
|  1174.74,1175.97,1177.20,1180.29,1185.90,1191.57,1197.30,1203.07,	//0x20 - 0x2F
 | |
|  1209.16,1214.72,1220.95,1226.62,1232.34,1238.76,1242.00,1243.29,
 | |
|  1244.59,1245.90,1247.20,1250.47,1256.42,1262.43,1268.49,1274.60,	//0x30 - 0x3F
 | |
|  1281.06,1286.95,1293.55,1299.56,1305.62,1312.42,1315.85,1317.22,
 | |
|  1318.60,1319.98,1321.37,1324.83,1331.13,1337.49,1343.92,1350.40,	//0x40 - 0x4F
 | |
|  1357.24,1363.47,1370.46,1376.83,1383.25,1390.46,1394.09,1395.55,
 | |
|  1397.00,1398.47,1399.94,1403.61,1410.29,1417.03,1423.83,1430.70,	//0x50 - 0x5F
 | |
|  1437.94,1444.55,1451.96,1457.07,1465.51,1473.14,1477.00,1478.53,
 | |
|  1480.07,1481.63,1483.18,1486.99,1494.14,1501.29,1508.50,1515.77,	//0x60 - 0x6F
 | |
|  1523.45,1530.45,1538.30,1545.44,1552.65,1560.74,1564.82,1566.45,
 | |
|  1568.08,1569.73,1571.38,1575.50,1583.00,1590.56,1598.20,1605.90,	//0x70 - 0x7F
 | |
|  1614.04,1621.45,1629.77,1637.34,1644.98,1653.55,1657.87,1659.60,
 | |
|  1661.33,1663.07,1664.82,1669.18,1677.12,1685.14,1693.23,1701.39,	//0x80 - 0x8F
 | |
|  1710.01,1717.87,1726.69,1734.70,1742.79,1751.87,1756.45,1758.28,
 | |
|  1760.11,1761.96,1763.81,1768.44,1776.85,1785.34,1793.92,1802.56,	//0x90 - 0x9F
 | |
|  1811.70,1820.02,1829.35,1837.85,1846.42,1856.05,1860.89,1862.83,
 | |
|  1864.78,1866.74,1868.70,1873.60,1882.50,1891.50,1900.59,1909.75,	//0xA0 - 0xAF
 | |
|  1919.43,1928.24,1938.13,1947.14,1956.22,1966.41,1971.55,1973.60,
 | |
|  1975.66,1977.74,1979.81,1985.01,1994.44,2003.98,2013.61,2023.31,	//0xB0 - 0xBF
 | |
|  2033.56,2042.90,2053.38,2062.92,2072.54,2083.34,2088.78,2090.96,
 | |
|  2093.14,2095.34,2097.54,2103.04,2113.04,2123.14,2133.34,2143.62,	//0xC0 - 0xCF
 | |
|  2154.48,2164.38,2175.48,2185.59,2195.78,2207.22,2212.99,2215.30,
 | |
|  2217.60,2219.94,2222.27,2228.09,2238.69,2249.39,2260.20,2271.09,	//0xD0 - 0xDF
 | |
|  2282.59,2293.08,2304.84,2315.55,2326.35,2338.47,2344.58,2347.02,
 | |
|  2349.47,2351.94,2354.41,2360.58,2371.80,2383.14,2394.59,2406.13,	//0xE0 - 0xEF
 | |
|  0,0,0,0,0,0,0,0,
 | |
|  0,0,0,0,0,0,0,0,													//0xF0 - 0xFF (Special codes)
 | |
| };
 | |
| #endif
 | |
| 
 | |
| /**********************************************************************************************
 | |
| 
 | |
| 	 read_sample -- returns 1 sample from the channel's output buffer, but upsamples/interpolates the data
 | |
| 	 as necessary to match the Machine driver's output sample rate.
 | |
| 
 | |
| ***********************************************************************************************/
 | |
| int16_t read_sample(struct M114SChannel * const channel, const uint32_t length)
 | |
| {
 | |
| 	const uint32_t pos = channel->outpos >> FRAC_BITS;
 | |
| 	if (pos < length)
 | |
| 	{
 | |
| 		const int32_t frac = channel->outpos & FRAC_MASK;
 | |
| 
 | |
| 		// interpolate
 | |
| 		const int16_t val1 = channel->output[pos];
 | |
| 		const int16_t val2 = channel->output[pos+1 < length ? pos : 0]; // wrap around to 0 (see code below!)?
 | |
| 		const int16_t sample = (val1 * ((int32_t)FRAC_ONE - frac) + val2 * frac) >> FRAC_BITS;
 | |
| 
 | |
| 		channel->outpos += channel->incr;
 | |
| 		return sample;
 | |
| 	}
 | |
| 	else {
 | |
| 		//LOG(("End of Table\n"));
 | |
| 		//channel->end_of_table++;
 | |
| 		channel->outpos = 0; // related to cyclic reading of tables //!! rather wrap over including exact FRAC_BITS instead of just nulling it?
 | |
| 		return channel->output[0]; //!! dto. would need interpolation then
 | |
| 	}
 | |
| }
 | |
| 
 | |
| /**********************************************************************************************
 | |
| 
 | |
| 	 read_table -- Reads the two tables of rom data into a temporary buffer,
 | |
| 	 mixes the samples using the chip's internal interpolation equation,
 | |
| 	 applies the volume, and writes the single mixed sample to the output buffer for the channel.
 | |
| 	 It processes the entire table1 length of data.
 | |
| 
 | |
| 	 Note: Eventually this should flag an End of Table, and should process new table data
 | |
| 
 | |
| ***********************************************************************************************/
 | |
| void read_table(struct M114SChip * const chip, struct M114SChannel * const channel) // get rid of this and write directly to output buffer?!
 | |
| {
 | |
| 	int i;
 | |
| #ifndef USE_LERP_FOR_REPEATED_SAMPLES
 | |
| 	int j;
 | |
| #endif
 | |
| 	const int8_t * const rom = &chip->region_base[0];
 | |
| 	const int t1start = channel->table1.start_address;
 | |
| 	const int t2start = channel->table2.start_address;
 | |
| 	const int lent1 = channel->table1.length;
 | |
| 	const int lent2 = channel->table2.length;
 | |
| 	const int rep1 = channel->table1.reread;
 | |
| 	const int rep2 = channel->table2.reread;
 | |
| 	const int intp = channel->regs.interp;
 | |
| 
 | |
| 	int8_t tb1[4096];	// Temp copy buffer for Table 1 // long enough to hold max sizes of 2048*2 or 1024*4
 | |
| 	int8_t tb2[4096];	// Temp copy buffer for Table 2 // dto.
 | |
| 	memset(&tb1,0,sizeof(tb1));
 | |
| 	memset(&tb2,0,sizeof(tb2));
 | |
| 
 | |
| 	//LOG(("t1s = %d t2s = %d, l1=%d l2=%d, r1=%d, r2=%d, int = %d\n",t1start,t2start,lent1,lent2,rep1,rep2,intp));
 | |
| 
 | |
| 	// datasheet says: multiple reading permits interpolation between two adjoining samples on the same table, so do we really need to lerp instead of just repeating same values here?
 | |
| #ifdef USE_LERP_FOR_REPEATED_SAMPLES
 | |
| 	//Scan Table 1
 | |
| 	if(rep1 == 1)
 | |
| 		memcpy(tb1,&rom[t1start],lent1);
 | |
| 	else if(rep1 == 2)
 | |
| 		for(i=0; i<lent1; i++)
 | |
| 		{
 | |
| 			tb1[i*2+0] =       rom[i+t1start];
 | |
| 			tb1[i*2+1] = ((int)rom[i+t1start] + (int)rom[t1start + ((i < lent1-1) ? i+1 : i)])/2;
 | |
| 		}
 | |
| 	else //if(rep1 == 4)
 | |
| 		for(i=0; i<lent1; i++)
 | |
| 		{
 | |
| 			int val1 = (int)rom[i+t1start];
 | |
| 			int val2 = (int)rom[t1start + ((i < lent1-1) ? i+1 : i)];
 | |
| 			tb1[i*4+0] =    rom[i+t1start];
 | |
| 			tb1[i*4+1] = (val1*3 + val2  )/4;
 | |
| 			tb1[i*4+2] = (val1   + val2  )/2;
 | |
| 			tb1[i*4+3] = (val1   + val2*3)/4;
 | |
| 		}
 | |
| 		
 | |
| 	//Scan Table 2
 | |
| 	if (rep2 == 1)
 | |
| 		memcpy(tb2,&rom[t2start+0x2000],lent2); //A13 is toggled high on Table 2 reading (Implementation specific - ie, Mr. Game)
 | |
| 	else if(rep2 == 2)
 | |
| 		for(i=0; i<lent2; i++)
 | |
| 		{
 | |
| 			tb2[i*2+0] =       rom[i+t2start+0x2000];
 | |
| 			tb2[i*2+1] = ((int)rom[i+t2start+0x2000] + (int)rom[t2start+0x2000 + ((i < lent2-1) ? i+1 : i)])/2;
 | |
| 		}
 | |
| 	else //if(rep2 == 4)
 | |
| 		for(i=0; i<lent2; i++)
 | |
| 		{
 | |
| 			int val1 = (int)rom[i+t2start+0x2000];
 | |
| 			int val2 = (int)rom[t2start+0x2000 + ((i < lent2-1) ? i+1 : i)];
 | |
| 			tb2[i*4+0] =    rom[i+t2start+0x2000];
 | |
| 			tb2[i*4+1] = (val1*3 + val2  )/4;
 | |
| 			tb2[i*4+2] = (val1   + val2  )/2;
 | |
| 			tb2[i*4+3] = (val1   + val2*3)/4;
 | |
| 		}
 | |
| #else
 | |
| 	//Scan Table 1
 | |
| 	for(i=0; i<lent1; i++)
 | |
| 		for(j=0; j<rep1; j++)
 | |
| 			tb1[j+(i*rep1)] = rom[i+t1start];
 | |
| 	//Scan Table 2
 | |
| 	for(i=0; i<lent2; i++)
 | |
| 		for(j=0; j<rep2; j++)
 | |
| 			tb2[j+(i*rep2)] = rom[i+t2start+0x2000];		//A13 is toggled high on Table 2 reading (Implementation specific - ie, Mr. Game)
 | |
| #endif
 | |
| 
 | |
| 	// Table1 is always larger, so use that as the size
 | |
| 
 | |
| 	// How to make up difference (table 2 can be shorter than table 1)? -> was memset above already, so zero for now
 | |
| 	/*for(i=lent2*rep2; i<lent1*rep1; i++)
 | |
| 		tb2[i] = ?;*/
 | |
| 
 | |
| 	// Now Mix based on Interpolation Bits
 | |
| 	for(i=0; i<lent1*rep1; i++)	{
 | |
| 		int l;
 | |
| 		//Apply volume - If envelope - inc/dec volume to calculate sample volume (only 8 most significant bits from the 10 bits, thus +/-4), otherwise, apply directly
 | |
| #ifdef USE_VOL_ENVELOPE
 | |
| 		if(channel->regs.env_enable && ((i & (abs(channel->step_rate_volume_env)-1)) == abs(channel->step_rate_volume_env)/2)) { // check if we match the frequency that the value must be updated
 | |
| 			channel->current_volume += channel->step_rate_volume_env > 0 ? 4 : -4; // dependent on sign inc/dec by 4
 | |
| 			if(channel->step_rate_volume_env > 0)
 | |
| 			{
 | |
| 				if(channel->current_volume > channel->target_volume)
 | |
| 					channel->current_volume = channel->target_volume;
 | |
| 			}
 | |
| 			else if(channel->current_volume < channel->target_volume)
 | |
| 				channel->current_volume = channel->target_volume;
 | |
| 		}
 | |
| #endif
 | |
| 		//write to output buffer
 | |
| #ifdef DO_FULL_PRECISION_MIXING
 | |
| 		l = (int)tb1[i] * (intp + 1) + (int)tb2[i] * (15 - intp);
 | |
| 		channel->output[i] = (int16_t)(0x6f * l * (channel->current_volume + 1) / (1024*16)); // Max Volume would be 256 for an int16_t value (so why was 0x6f chosen??)
 | |
| #else
 | |
| 		l = ((int)tb1[i] * (intp + 1) / 16) + ((int)tb2[i] * (15 - intp) / 16); // formula seen in datasheet, but unclear what this means precision wise (i.e. is this only meant as real number pseudo code?)
 | |
| 		channel->output[i] = (int16_t)(0x6f * l * (channel->current_volume + 1) / 1024); // Max Volume would be 256 for an int16_t value (so why was 0x6f chosen??) //!! do 0x6f scale AFTER division??
 | |
| #endif
 | |
| 	}
 | |
| }
 | |
| 
 | |
| /**********************************************************************************************
 | |
| 
 | |
|      m114s_update -- update the sound chip so that it is in sync with CPU execution
 | |
| 
 | |
| ***********************************************************************************************/
 | |
| //Seems this sometimes still produces some static, but I don't know why!
 | |
| void m114s_update(struct M114SChip* chip,
 | |
| 	int16_t **buffer,
 | |
| 	int samples)
 | |
| {
 | |
| 
 | |
| 	while (samples > 0)
 | |
| 	{
 | |
| #if M114S_OUTPUT_CHANNELS == 1
 | |
| 		int32_t accum = 0;
 | |
| #else
 | |
| 		int32_t accum[M114S_OUTPUT_CHANNELS];
 | |
| #endif
 | |
| 		int c;
 | |
| 
 | |
| #if M114S_OUTPUT_CHANNELS != 1
 | |
| 		/* clear accum */
 | |
| 		for(c = 0; c < M114S_OUTPUT_CHANNELS; c++)
 | |
| 			accum[c] = 0;
 | |
| #endif
 | |
| 
 | |
| 		/* loop over channels */
 | |
| 		for (c = 0; c < M114S_CHANNELS; c++)
 | |
| 		{
 | |
| 			struct M114SChannel * const channel = &chip->channels[c];
 | |
| 			/* Grab the next sample from the table data if the channel is active */
 | |
| 			if (channel->active)
 | |
| 			{
 | |
| 				//We use Table 1 to drive everything, as Table 2 is really for mixing into Table 1..
 | |
| 				int32_t sample = read_sample(channel, channel->table1.total_length); //!! int16_t if MR_GAME_VOLUME_HACK would be off
 | |
| 
 | |
| #ifdef MR_GAME_VOLUME_HACK
 | |
| 				sample = sample*chip->channel_volume[channel->regs.outputs] / 100; // boost percussion on Dakar, penalty some of the other instruments
 | |
| #endif
 | |
| 				//Mix the output of this channel to the appropriate output channel
 | |
| #if M114S_OUTPUT_CHANNELS == 1
 | |
| 				accum
 | |
| #elif M114S_OUTPUT_CHANNELS == 4
 | |
| 				accum[channel->regs.outputs]
 | |
| #else
 | |
| 				accum[c]
 | |
| #endif
 | |
| 				+= sample;
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		/* Update the buffer & Ensure we don't clip */
 | |
| #if M114S_OUTPUT_CHANNELS == 1
 | |
| 		accum /= (int32_t)4;
 | |
| 		*buffer++ = (accum < -32768) ? -32768 : ((accum > 32767) ? 32767 : accum);
 | |
| #else
 | |
| 		for (c = 0; c < M114S_OUTPUT_CHANNELS; c++)
 | |
| 			*buffer[c]++ = (accum[c] < -32768) ? -32768 : ((accum[c] > 32767) ? 32767 : accum[c]);
 | |
| #endif
 | |
| 
 | |
| 		samples--;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| /**********************************************************************************************
 | |
| 
 | |
|      M114S_sh_start -- start emulation of the M114S
 | |
| 
 | |
| ***********************************************************************************************/
 | |
| 
 | |
| INLINE void init_channel(struct M114SChannel * const channel)
 | |
| {
 | |
| 	//set all internal registers to 0!
 | |
| 	channel->active = 0;
 | |
| 	channel->outpos = 0;
 | |
| 	channel->prev_volume = 0;
 | |
| 	memset(&channel->output,0,sizeof(channel->output));
 | |
| 	memset(&channel->regs,  0,sizeof(channel->regs));
 | |
| 	memset(&channel->table1,0,sizeof(channel->table1));
 | |
| 	memset(&channel->table2,0,sizeof(channel->table2));
 | |
| }
 | |
| 
 | |
| 
 | |
| INLINE void init_all_channels(struct M114SChip * const chip)
 | |
| {
 | |
| 	int i;
 | |
| 
 | |
| 	/* init the channels */
 | |
| 	for (i = 0; i < M114S_CHANNELS; i++)
 | |
| 		init_channel(&chip->channels[i]);
 | |
| 
 | |
| 	//Chip init stuff
 | |
| 	memset(&chip->tempch_regs,0,sizeof(chip->tempch_regs));
 | |
| 	chip->channel = 0;
 | |
| 	chip->bytes_read = 0;
 | |
| }
 | |
| 
 | |
| 
 | |
| int M114S_sh_start(const struct MachineSound *msound)
 | |
| {
 | |
| 	const struct M114Sinterface *intf = msound->sound_interface;
 | |
| #if M114S_OUTPUT_CHANNELS == 1 
 | |
| #else
 | |
| 	int vol[M114S_OUTPUT_CHANNELS];
 | |
| #endif
 | |
| 	int i,j;
 | |
| 
 | |
| 	/* initialize the chips */
 | |
| 	memset(&m114schip, 0, sizeof(m114schip));
 | |
| 	for (i = 0; i < intf->num; i++)
 | |
| 	{
 | |
| 		/* Chip specific setup based on clock speed */
 | |
| 		switch(intf->baseclock[i]) {
 | |
| 			// M114A 4 Mhz
 | |
| 			case 4000000:
 | |
| 				m114schip[i].reset_cycles = 4000000 * 0.000128;	// Chip resets in 128us (microseconds)
 | |
| 				m114schip[i].is_M114A = 1;
 | |
| 				break;
 | |
| 			// M114AF 6 Mhz
 | |
| 			case 6000000:
 | |
| 			case 5994560: // from datasheet: 5.99456 MHz
 | |
| 				m114schip[i].reset_cycles = intf->baseclock[i] * 0.000085;	// Chip resets in 85us (microseconds)
 | |
| 				m114schip[i].is_M114A = 0;
 | |
| 				LOG(("M114S Chip #%d - 6Mhz chip clock not fully supported/tested at this time!\n", i));
 | |
| 				return 1;
 | |
| 			default:
 | |
| 				LOG(("M114S Chip #%d - Invalid Base Clock value specified! Only 4Mhz & 6Mhz values allowed!\n",i));
 | |
| 				return 1;
 | |
| 		}
 | |
| 
 | |
| 		/* initialize the region & interface info */
 | |
| 		m114schip[i].cpu_num = intf->cpunum[i];
 | |
| 		m114schip[i].region_base = (int8_t *)memory_region(intf->region[i]);
 | |
| 		m114schip[i].intf = (struct M114Sinterface *)intf;
 | |
| 
 | |
| 		/* init the channels */
 | |
| 		init_all_channels(&m114schip[i]);
 | |
| 		for(j = 0; j < 4; j++)
 | |
| 			m114schip[i].channel_volume[j] = intf->mixing_level[i][j];
 | |
| 	}
 | |
| 
 | |
| 	/* success */
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| /**********************************************************************************************
 | |
| 
 | |
|      M114S_sh_stop -- stop emulation of the M114S
 | |
| 
 | |
| ***********************************************************************************************/
 | |
| 
 | |
| void M114S_sh_stop(void)
 | |
| {
 | |
| }
 | |
| 
 | |
| /**********************************************************************************************
 | |
| 
 | |
|      M114S_sh_reset -- reset emulation of the M114S
 | |
| 
 | |
| ***********************************************************************************************/
 | |
| 
 | |
| void M114S_sh_reset(void)
 | |
| {
 | |
| 	int i;
 | |
| 	for (i = 0; i < 1; i++) {
 | |
| 		/* reset all channels */
 | |
| 		init_all_channels(&m114schip[i]);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| /**********************************************************************************************
 | |
| 
 | |
|      process_freq_codes -- There are up to 16 special values for frequency that signify a code
 | |
| 
 | |
| ***********************************************************************************************/
 | |
| void process_freq_codes(struct M114SChip * const chip)
 | |
| {
 | |
| 	//Grab pointer to channel being programmed
 | |
| 	struct M114SChannel * const channel = &chip->channels[chip->channel];
 | |
| 	switch(channel->regs.frequency)
 | |
| 	{
 | |
| 		//ROMID - ROM Identification  (Are you kidding me?)
 | |
| 		case 0xf8:
 | |
| 			LOG(("* * Channel: %02d: Frequency Code: %02x - ROMID * * \n",chip->channel,channel->regs.frequency));
 | |
| 			break;
 | |
| 		//SSG - Set Syncro Global
 | |
| 		case 0xf9:
 | |
| 			LOG(("* * Channel: %02d: Frequency Code: %02x - SSG * * \n",chip->channel,channel->regs.frequency));
 | |
| 			break;
 | |
| 		//RSS - Reverse Syncro Status
 | |
| 		case 0xfa:
 | |
| 			// check if used, as this will force frequency changes to wait until table ends
 | |
| 			LOG(("* * Channel: %02d: Frequency Code: %02x - RSS * * \n",chip->channel,channel->regs.frequency));
 | |
| 			break;
 | |
| 		//RSG - Reset Syncro Global
 | |
| 		case 0xfb:
 | |
| 			LOG(("* * Channel: %02d: Frequency Code: %02x - RSG * * \n",chip->channel,channel->regs.frequency));
 | |
| 			break;
 | |
| 		//PSF - Previously Selected Frequency
 | |
| 		case 0xfc:
 | |
| 			// seems to be unused by Mr.Game
 | |
| 			LOG(("* * Channel: %02d: Frequency Code: %02x - PSF * * \n",chip->channel,channel->regs.frequency));
 | |
| 			break;
 | |
| 		//FFT - Forced Table Termination
 | |
| 		case 0xff:
 | |
| 			//Stop whatever output from playing by simulating an end of table event!
 | |
| 			channel->outpos = 0; // but this will just put the cyclic counter back to the beginning!?!
 | |
| 			//LOG(("* * Channel: %02d: Frequency Code: %02x - FFT * * \n",chip->channel,channel->regs.frequency));
 | |
| 			break;
 | |
| 		default:
 | |
| 			LOG(("* * Channel: %02d: Frequency Code: %02x - UNKNOWN * * \n",chip->channel,channel->regs.frequency));
 | |
| 			break;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| /**********************************************************************************************
 | |
| 
 | |
|      process_channel_data -- complete programming for a channel now exists, process it!
 | |
| 
 | |
| ***********************************************************************************************/
 | |
| 
 | |
| void process_channel_data(struct M114SChip * const chip)
 | |
| {
 | |
| 	//Grab pointer to channel being programmed
 | |
| 	struct M114SChannel * const channel = &chip->channels[chip->channel];
 | |
| 
 | |
| 	//Reset # of bytes for next group
 | |
| 	chip->bytes_read = 0;
 | |
| 
 | |
| 	//Copy data to the appropriate channel registers from our temp channel registers
 | |
| 	memcpy(&channel->regs,&chip->tempch_regs,sizeof(chip->tempch_regs));
 | |
| 
 | |
| 	//Look for the 16 special frequency codes
 | |
| 	if(channel->regs.frequency >= 0xf0) {
 | |
| 			process_freq_codes(chip);
 | |
| 			//FFT & PSF are the only codes that should continue to process channel data AFAIK
 | |
| 			if(channel->regs.frequency != 0xff && channel->regs.frequency != 0xfc)
 | |
| 				return;
 | |
| 	}
 | |
| 
 | |
| 	//If Attenuation set to 0x3F - The channel becomes inactive
 | |
| 	if(channel->regs.atten == 0x3f) {
 | |
| 		channel->active = 0;
 | |
| 		return;
 | |
| 	}
 | |
| 	else
 | |
| 	//Process this channel
 | |
| 	{
 | |
| 		//Calculate # of repetitions for Table 1 & Table 2
 | |
| 		const int rep1 = mode_to_rep[channel->regs.read_meth][0];
 | |
| 		const int rep2 = mode_to_rep[channel->regs.read_meth][1];
 | |
| 		//Calculate Table Length for Table 1 & Table 2
 | |
| 		const int lent1 = mode_to_len_t1[channel->regs.read_meth][channel->regs.table_len];
 | |
| 		const int lent2 = mode_to_len_t2[channel->regs.read_meth][channel->regs.table_len];
 | |
| 		//Start & Stop Address - Note the special case for table length of 16 - Bit 5 always 1 in this case // but also for special cases 8 and 4 for table 2?!?
 | |
| 		//Calculate Table 1 Start & End Address in ROM
 | |
| 		const int t1start = ((channel->regs.table1_addr<<5) & (~(lent1-1)&0x1fff)) | (lent1 == 16 ? 0x10 : 0); //T1 Addr is only upper 8 bits, but masked by length
 | |
| 		//const int t1end = t1start | (lent1-1);
 | |
| 		//Calculate Table 2 Start & End Address in ROM
 | |
| 		const int t2start = ((channel->regs.table2_addr<<5) & (~(lent2-1)&0x1fff)) | (lent2 <= 16 ? 0x10 : 0); //T2 Addr is only upper 8 bits, but masked by length
 | |
| 		//const int t2end = t2start | (lent2-1);
 | |
| 
 | |
| 		//Calculate initial frequency of both tables
 | |
| 		double freq = chip->is_M114A ? freqtable4Mhz[channel->regs.frequency] : freqtable6Mhz[channel->regs.frequency];
 | |
| 
 | |
| 		//Calculate new volume
 | |
| 		channel->target_volume = channel->regs.atten < 32 ? v_linear[channel->regs.atten] : 0; // channel must be kept active, but is it really 0? Or is the last value used (v_linear[31])? Or something inbetween??
 | |
| 
 | |
| 		//Adjust frequency if octave divisor set
 | |
| 		if (channel->regs.oct_divisor)
 | |
| 			freq /= 2.; // maybe new frequency must be clamped to freqtable[0]??
 | |
| 
 | |
| 		//Channel is now active!
 | |
| 		channel->active = 1;
 | |
| 
 | |
| 		// Setup Sample Rate/Step size increase
 | |
| 		channel->incr = (uint32_t)(freq * ((double)(16u << FRAC_BITS) / SAMPLE_RATE));
 | |
| 
 | |
| 		//Assign start & stop address offsets to ROM
 | |
| 		channel->table1.start_address = t1start;
 | |
| 		channel->table2.start_address = t2start;
 | |
| 		//channel->table1.stop_address = t1end;
 | |
| 		//channel->table2.stop_address = t2end;
 | |
| 
 | |
| 		//Assign # of times to re-read & Length
 | |
| 		channel->table1.reread = rep1;
 | |
| 		channel->table2.reread = rep2;
 | |
| 		channel->table1.length = lent1;
 | |
| 		channel->table2.length = lent2;
 | |
| 		channel->table1.total_length = lent1*rep1;
 | |
| 		channel->table2.total_length = lent2*rep2;
 | |
| 
 | |
| 		//Calculate Sample Volume
 | |
| 		//- If Envelope should be used, Take the difference in new volume & current volume, and break it into the # of samples in the table
 | |
| 		//- If No Envelope should be used, Volume is simply based on the Volume Table
 | |
| #ifdef USE_VOL_ENVELOPE
 | |
| 		if(channel->regs.env_enable) {
 | |
| 			const int diff = channel->target_volume - channel->prev_volume;
 | |
| 			channel->step_rate_volume_env = abs(diff) > 128 ? 1 : abs(diff) > 64 ? 2 : abs(diff) > 32 ? 4 : 8;
 | |
| 			if(channel->target_volume < channel->prev_volume)
 | |
| 				channel->step_rate_volume_env = -channel->step_rate_volume_env;
 | |
| 			channel->current_volume = channel->prev_volume;
 | |
| 		}
 | |
| 		else
 | |
| #endif
 | |
| 		{
 | |
| 			channel->current_volume = channel->target_volume;
 | |
| 		}
 | |
| 		//Update Last Volume
 | |
| 		channel->prev_volume = channel->target_volume;
 | |
| 
 | |
| 		//Temp hack to ensure we only generate the ouput data 1x - this is WRONG and needs to be addressed eventually!
 | |
| 		//if(channel->output[0] == 0)
 | |
| 			read_table(chip,channel);
 | |
| 
 | |
| #if 0
 | |
| //if(chip->channel == 2) {
 | |
| if(channel->regs.outputs == 2) {
 | |
| 	if(channel->regs.frequency == 0x70)
 | |
| 	{
 | |
| 		LOG(("orig: = %0f, freq = %0f, incr = %0d \n",freqtable4Mhz[channel->regs.frequency],freq,channel->incr));
 | |
| 	}
 | |
| 	//LOG(("EOT=%d\n",channel->end_of_table));
 | |
| 	LOG(("C:%02d V:%02d FQ:%03x TS1:%02x TS2:%02x T1L:%04d T1R:%01d T2L:%04d T2R:%01d OD=%01d I:%02d E:%01d\n",
 | |
| 		chip->channel,
 | |
| 		channel->regs.atten,
 | |
| 		channel->regs.frequency,
 | |
| 		t1start,t2start,
 | |
| 		lent1,rep1,
 | |
| 		lent2,rep2,
 | |
| 		channel->regs.oct_divisor,
 | |
| 		channel->regs.interp,
 | |
| 		channel->regs.env_enable
 | |
| 		));
 | |
| }
 | |
| #endif
 | |
| 
 | |
| 	}
 | |
| }
 | |
| 
 | |
| /**********************************************************************************************
 | |
| 
 | |
|      m114s_data_write -- handle a write to the data bus of the M114S
 | |
| 
 | |
|      The chip has a data bus width of 6 bits, and must be fed 8 consecutive bytes
 | |
| 	 - thus 48 bits of programming! All data must be fed in order, so we make a few assumptions.
 | |
| 
 | |
| ***********************************************************************************************/
 | |
| void m114s_data_write(struct M114SChip* chip, data8_t data)
 | |
| {
 | |
| 	/* Check if the chip needs to 'auto-reset' - this occurs if during the programming sequence (ie before all 8 bytes read)
 | |
| 	   a certain amount of time elapses without receiving another byte of programming...
 | |
| 	   128us in the 4Mhz chip, 85us in the 6Mhz chip.
 | |
| 	*/
 | |
| 	static UINT64 last_totcyc = 0;
 | |
| 	UINT64 curr_totcyc = cpu_gettotalcycles64(chip->cpu_num);
 | |
| 	double diff = (double)llabs((INT64)(curr_totcyc-last_totcyc));
 | |
| 	last_totcyc = curr_totcyc;
 | |
| 	if(chip->bytes_read && diff > chip->reset_cycles) {
 | |
| 		LOG(("M114S: Auto Reset - bytes read=%0d - data=%0x, elapsed cycles = %f\n",chip->bytes_read,data&0x3f,diff));
 | |
| 		M114S_sh_reset();
 | |
| 	}
 | |
| 
 | |
| 	data &= 0x3f;						//Strip off bits 7-8 (only 6 bits for the data bus to the chip)
 | |
| 	chip->bytes_read++;
 | |
| 	switch(chip->bytes_read)
 | |
| 	{
 | |
| 	/*  BYTE #1 -
 | |
| 	    Bits 0-5: Attenuation Value (0-63) - 0 = No Attenuation, 3E = Max, 3F = Silence active channel */
 | |
| 		case 1:
 | |
| 			chip->tempch_regs.atten = data;
 | |
| 			break;
 | |
| 
 | |
| 	/*  BYTE #2 -
 | |
| 		Bits 0-1: Table 2 Address (Bits 6-7)
 | |
| 		Bits 2-3: Table 1 Address (Bits 6-7)
 | |
| 		Bits 4-5: Output Pin Selection (0-3)  */
 | |
| 		case 2:
 | |
| 			chip->tempch_regs.table2_addr = (data & 0x03)<<6;
 | |
| 			chip->tempch_regs.table1_addr = (data & 0x0c)<<4;
 | |
| 			chip->tempch_regs.outputs = (data & 0x30)>>4;
 | |
| 			break;
 | |
| 
 | |
| 	/*  BYTE #3 -
 | |
| 		Bits 0-5: Table 2 Address (Bits 0-5) */
 | |
| 		case 3:
 | |
| 			chip->tempch_regs.table2_addr |= data;
 | |
| 			break;
 | |
| 
 | |
| 	/*	BYTE #4 -
 | |
| 		Bits 0-5: Table 1 Address (Bits 0-5) */
 | |
| 		case 4:
 | |
| 			chip->tempch_regs.table1_addr |= data;
 | |
| 			break;
 | |
| 
 | |
| 	/*  BYTE #5 -
 | |
| 		Bits 0-2: Reading Method
 | |
| 		Bits 3-5: Table Length */
 | |
| 		case 5:
 | |
| 			chip->tempch_regs.read_meth = data & 0x07;
 | |
| 			chip->tempch_regs.table_len = (data & 0x38)>>3;
 | |
| 			break;
 | |
| 
 | |
| 	/*	BYTE #6 -
 | |
| 		Bits 0  : Octave Divisor
 | |
| 		Bits 1  : Envelope Enable/Disable
 | |
| 		Bits 2-5: Interpolation Value (0-15) */
 | |
| 		case 6:
 | |
| 			chip->tempch_regs.oct_divisor = (data & 0x01);
 | |
| 			chip->tempch_regs.env_enable = (data & 0x02);
 | |
| 			chip->tempch_regs.interp = (data & 0x3c)>>2;
 | |
| 			break;
 | |
| 
 | |
| 	/*	BYTE #7 -
 | |
| 		Bits 0-1: Frequency (Bits 0-1)
 | |
| 		Bits 2-5: Channel */
 | |
| 		case 7:
 | |
| 			chip->tempch_regs.frequency = (data & 0x03);
 | |
| 			chip->channel = (data & 0x3c)>>2;
 | |
| 			break;
 | |
| 
 | |
| 	/*	BYTE #8 -
 | |
| 		Bits 0-5: Frequency (Bits 2-7) */
 | |
| 		case 8:
 | |
| 			chip->tempch_regs.frequency |= (data<<2);
 | |
| 			/* Process the channel data */
 | |
| 			process_channel_data(chip);
 | |
| 			break;
 | |
| 
 | |
| 		default:
 | |
| 			LOG(("M114S.C - logic error - too many bytes processed: %x\n",chip->bytes_read));
 | |
| 			break;
 | |
| 	}
 | |
| }
 | |
| 
 | 
