xref: /haiku/src/add-ons/media/media-add-ons/radeon/MSP3430.cpp (revision ffec4cb14d0b87745137bcb115e949f1fbc895b9)
1 /******************************************************************************
2 /
3 /	File:			MSP3430.cpp
4 /
5 /	Description:	Micronas Multistandard Sound Processor (MSP) interface.
6 /
7 /	Copyright 2001, Carlos Hasan
8 /
9 *******************************************************************************/
10 
11 #include <Debug.h>
12 #include "MSP3430.h"
13 
14 enum MSP3430_register {
15     MSP3430_CONTROL					= 0x00,				// R/W control register
16     MSP3430_WR_DEM					= 0x10,				// Write demodulator register
17     MSP3430_RD_DEM					= 0x11,				// Read demodulator register
18     MSP3430_WR_DSP					= 0x12,				// Read DSP register
19     MSP3430_RD_DSP					= 0x13				// Write DSP register
20 };
21 
22 enum MSP3430_control_register {
23 	MSP3430_CONTROL_NORMAL			= 0x0000,			// normal operation mode
24 	MSP3430_CONTROL_RESET			= 0x8000			// reset mode
25 };
26 
27 enum MSP3430_wr_dem_register {
28 	MSP3430_DEM_STANDARD_SEL		= 0x0020,			// standard selection
29 	MSP3430_DEM_MODUS				= 0x0030,			// demodulator options
30 	MSP3430_DEM_I2S_CONFIG			= 0x0040			// I2S configuration
31 };
32 
33 enum MSP3430_rd_dem_register {
34 	MSP3430_DEM_STANDARD_RES		= 0x007e,			// standard detection result
35 	MSP3430_DEM_STATUS				= 0x0200			// status register
36 };
37 
38 enum MSP3430_wr_dsp_register {
39 	// preprocessing
40 	MSP3430_DSP_FM_PRESCALE			= 0x000e,			// FM/AM analog signal prescale
41 		MSP3430_DSP_PRE_FM			= BITS(15:8),
42 		MSP3430_DSP_FM_MATRIX		= BITS(7:0),
43 	MSP3430_DSP_NICAM_PRESCALE		= 0x0010,			// NICAM digital signal prescale
44 		MSP34300_DSP_PRE_NICAM		= BITS(15:8),
45 	MSP3430_DSP_PRE_I2S2			= 0x0012,			// I2S digital signal prescale
46 	MSP3430_DSP_PRE_I2S1			= 0x0016,
47 	MSP3430_DSP_PRE_SCART			= 0x000d,			// SCART prescale
48 
49 	// source select and output channel matrix
50 	MSP3430_DSP_SRC_MAT_MAIN		= 0x0008,			// loudspeaker source and matrix
51 		MSP3430_DSP_SRC_MAIN		= BITS(15:8),
52 		MSP3430_DSP_MAT_MAIN		= BITS(7:0),
53 	MSP3430_DSP_SRC_MAT_AUX			= 0x0009,			// headphone source and matrix
54 		MSP3430_DSP_SRC_AUX			= BITS(15:8),
55 		MSP3430_DSP_MAT_AUX			= BITS(7:0),
56 	MSP3430_DSP_SRC_MAT_SCART1		= 0x000a,			// SCART1 source and matrix
57 		MSP3430_DSP_SRC_SCART1		= BITS(15:8),
58 		MSP3430_DSP_MAT_SCART1		= BITS(7:0),
59 	MSP3430_DSP_SRC_MAT_SCART2		= 0x0041,			// SCART2 source and matrix
60 		MSP3430_DSP_SRC_SCART2		= BITS(15:8),
61 		MSP3430_DSP_MAT_SCART2		= BITS(7:0),
62 	MSP3430_DSP_SRC_MAT_I2S			= 0x000b,			// I2S source and matrix
63 		MSP3430_DSP_SRC_I2S			= BITS(15:8),
64 		MSP3430_DSP_MAT_I2S			= BITS(7:0),
65 	MSP3430_DSP_SRC_MAT_QPEAK		= 0x000c,			// QuasiPeak detector source and matrix
66 		MSP3430_DSP_SRC_QPEAK		= BITS(15:8),
67 		MSP3430_DSP_MAT_QPEAK		= BITS(7:0),
68 
69 	// loudspeaker and headphone processing
70 	MSP3430_DSP_VOL_MAIN			= 0x0000,			// loudspeaker volume
71 	MSP3430_DSP_VOL_AUX				= 0x0006,			// headphone volume
72 	MSP3430_DSP_AVC					= 0x0029,			// automatic volume correction
73 	MSP3430_DSP_BAL_MAIN			= 0x0001,			// loudspeaker balance
74 	MSP3430_DSP_BAL_AUX				= 0x0030,			// headphone balance
75 	MSP3430_DSP_TONE_MODE			= 0x0020,			// select bass/treble or equalizer
76 	MSP3430_DSP_BASS_MAIN			= 0x0002,			// loudspeaker bass
77 	MSP3430_DSP_BASS_AUX			= 0x0031,			// headphone bass
78 	MSP3430_DSP_TREB_MAIN			= 0x0003,			// loudspeaker treble
79 	MSP3430_DSP_TREB_AUX			= 0x0032,			// headphone treble
80 	MSP3430_DSP_EQUAL_BAND1			= 0x0021,			// equalizer coefficients
81 	MSP3430_DSP_EQUAL_BAND2			= 0x0022,
82 	MSP3430_DSP_EQUAL_BAND3			= 0x0023,
83 	MSP3430_DSP_EQUAL_BAND4			= 0x0024,
84 	MSP3430_DSP_EQUAL_BAND5			= 0x0025,
85 	MSP3430_DSP_LOUD_MAIN			= 0x0004,			// loudspeaker loudness
86 	MSP3430_DSP_LOUD_AUX			= 0x0033,			// headphone loudness
87 	MSP3430_DSP_SPAT_MAIN			= 0x0005,			// spatial effects
88 
89 	// subwoofer output channel
90 	MSP3430_DSP_SUBW_LEVEL			= 0x002c,			// subwoofer level
91 	MSP3430_DSP_SUBW_FREQ			= 0x002d,			// subwoofer frequency
92 
93 	// micronas dynamic bass
94 	MSP3430_DSP_MDB_STR				= 0x0068,			// MDB strength
95 	MSP3430_DSP_MDB_LIM				= 0x0069,			// MDB limit
96 	MSP3430_DSP_MDB_HMC				= 0x006a,			// MDB harmonic content
97 	MSP3430_DSP_MDB_LP				= 0x006b,			// MDB low frequency
98 	MSP3430_DSP_MDB_HP				= 0x006c,			// MDB high frequency
99 
100 	// SCART output channel
101 	MSP3430_DSP_VOL_SCART1			= 0x0007,			// SCART1 volume
102 	MSP3430_DSP_VOL_SCART2			= 0x0040,			// SCART2 volume
103 
104 	// SCART switches and digital I/O pins
105 	MSP3430_DSP_ACB_REG				= 0x0013,			// SCART switches
106 	MSP3430_DSP_BEEPER				= 0x0014			// Beeper volume and frequency
107 };
108 
109 enum MSP3430_rd_dsp_register {
110 	// quasi-peak detector readout
111 	MSP3430_DSP_QPEAK_L				= 0x0019,			// Quasipeak detector left and right
112 	MSP3430_DSP_QPEAK_R				= 0x001a,
113 
114 	// MSP 34x0G version readout
115 	MSP3430_DSP_MSP_HARD_REVISION	= 0x001e,			// MSP hardware and revision
116 		MSP3430_DSP_MSP_HARD		= BITS(15:8),
117 		MSP3430_DSP_MSP_REVISION	= BITS(7:0),
118 	MSP3430_DSP_MSP_PRODUCT_ROM		= 0x001f,			// MSP product and ROM version
119 		MSP3430_DSP_MSP_PRODUCT		= BITS(15:8),
120 		MSP3430_DSP_MSP_ROM			= BITS(7:0)
121 };
122 
123 enum MSP3430_sound_standard {
124 	C_MSP3430_AUTOMATIC			= 0x0001,	// Automatic Detection (*)
125 	C_MSP3430_M_FM_STEREO		= 0x0002,	// NTSC M/N (*)
126 	C_MSP3430_BG_FM_STEREO		= 0x0003,	// PAL B/G (*)
127 	C_MSP3430_DK1_FM_STEREO		= 0x0004,	// (*)
128 	C_MSP3430_DK2_FM_STEREO		= 0x0005,	//
129 	C_MSP3430_DK_FM_MONO		= 0x0006,	//
130 	C_MSP3430_DK3_FM_STEREO		= 0x0007,	//
131 	C_MSP3430_BG_NICAM_FM		= 0x0008,	// PAL B/G (*)
132 	C_MSP3430_L_NICAM_AM		= 0x0009,	// (*)
133 	C_MSP3430_I_NICAM_FM		= 0x000A,	// PAL I (*)
134 	C_MSP3430_DK_NICAM_FM		= 0x000B,	// (*)
135 	C_MSP3430_DK_NICAM_FM_HDEV2	= 0x000C,
136 	C_MSP3430_DK_NICAM_FM_HDEV3	= 0x000D,
137 	C_MSP3430_BTSC_STEREO		= 0x0020,	// BTSC Stereo (*)
138 	C_MSP3430_BTSC_MONO_SAP		= 0x0021,
139 	C_MSP3430_M_JAPAN_STEREO	= 0x0030,	// NTSC Japan (*)
140 	C_MSP3430_FM_RADIO			= 0x0040,	// FM Radio (*)
141 	C_MSP3430_SAT_MONO			= 0x0050,	// Satellite Mono
142 	C_MSP3430_SAT_STEREO		= 0x0051,	// Satellite Stereo
143 	C_MSP3430_SAT_ASTRA_RADIO	= 0x0060	// Astra Digital Radio
144 };
145 
146 enum MSP3430_channel_source {
147 	C_MSP3430_SOURCE_FM			= 0x00,		// FM/AM Mono
148 	C_MSP3430_SOURCE_STEREO		= 0x01,		// Stereo or A/B (NICAM)
149 	C_MSP3430_SOURCE_SCART		= 0x02,		// SCART Input
150 	C_MSP3430_SOURCE_LANG_A		= 0x03,		// Stereo/Language A
151 	C_MSP3430_SOURCE_LANG_B		= 0x04,		// Stereo/Language B
152 	C_MSP3430_SOURCE_I2S1		= 0x05,		// I2S1 Input
153 	C_MSP3430_SOURCE_I2S2		= 0x06		// I2S2 Input
154 };
155 
156 enum MSP3430_channel_matrix {
157 	C_MSP3430_MATRIX_SOUND_A	= 0x00,		// Sound A Mono
158 	C_MSP3430_MATRIX_SOUND_B	= 0x10,		// Sound B Mono
159 	C_MSP3430_MATRIX_STEREO		= 0x20,		// Stereo
160 	C_MSP3430_MATRIX_MONO		= 0x30		// Mono
161 };
162 
163 
164 
165 /*
166 
167 -------------------------------------------------------------------
168 System			Sound			Sound				Color
169 				Carrier (MHz)	Modulation			System
170 -------------------------------------------------------------------
171 Satellite		6.5/5.85		FM-Mono/NICAM		PAL
172 				6.5				FM-Mono
173 				7.02/7.2		FM-Stereo			PAL
174 				7.38/7.56		ASTRA Digital Radio
175 				etc.
176 				4.5/4.724212	FM-Stereo (A2)		NTSC
177 -------------------------------------------------------------------
178 NTSC M/N		4.5				FM-FM (EIA-J)		NTSC
179 -------------------------------------------------------------------
180 				4.5				BTSC Stereo + SAP	NTSC, PAL
181 FM-Radio		10.7			FM-Stereo Radio		.
182 -------------------------------------------------------------------
183 
184 
185 
186 
187 
188 */
189 
CMSP3430(CI2CPort & port)190 CMSP3430::CMSP3430(CI2CPort & port)
191 	:	fPort(port),
192 		fAddress(0)
193 {
194 	PRINT(("CMSP3430::CMSP3430()\n"));
195 
196 	if( fPort.InitCheck() == B_OK ) {
197 		for (fAddress = 0x80; fAddress <= 0x80; fAddress += 0x02) {
198 	        if (fPort.Probe(fAddress)) {
199 	        	PRINT(("CMSP3430::CMSP3430() - Sound Processor found at I2C port 0x%02x\n", fAddress));
200 				break;
201 			}
202 		}
203 	}
204 	if( InitCheck() != B_OK )
205 		PRINT(("CMSP3430::CMSP3430() - Sound processor not found!\n"));
206 }
207 
~CMSP3430()208 CMSP3430::~CMSP3430()
209 {
210 	PRINT(("CMSP3430::~CMSP3430()\n"));
211 }
212 
InitCheck() const213 status_t CMSP3430::InitCheck() const
214 {
215 	status_t res;
216 
217 	res = fPort.InitCheck();
218 	if( res != B_OK )
219 		return res;
220 
221 	return (fAddress >= 0x80 && fAddress <= 0x80) ? B_OK : B_ERROR;
222 }
223 
SetEnable(bool enable)224 void CMSP3430::SetEnable(bool enable)
225 {
226 	PRINT(("CMSP3430::SetEnable(%d)\n", enable));
227 
228 	SetControlRegister(MSP3430_CONTROL_RESET);
229 	SetControlRegister(MSP3430_CONTROL_NORMAL);
230 
231 	if (enable) {
232 		SetRegister(MSP3430_WR_DEM, MSP3430_DEM_MODUS, 0x2003);
233 		SetRegister(MSP3430_WR_DEM, MSP3430_DEM_STANDARD_SEL, C_MSP3430_BTSC_STEREO); // 0x20
234 		SetRegister(MSP3430_WR_DSP, MSP3430_DSP_FM_PRESCALE, 0x2403);
235 		SetRegister(MSP3430_WR_DSP, MSP3430_DSP_SRC_MAT_MAIN, 0x0320);
236 		SetRegister(MSP3430_WR_DSP, MSP3430_DSP_VOL_MAIN, 0x7300);
237 		SetRegister(MSP3430_WR_DSP, MSP3430_DSP_SRC_MAT_MAIN, 0x0320);
238 	}
239 	else {
240 		SetRegister(MSP3430_WR_DSP, MSP3430_DSP_VOL_MAIN, 0x0000);
241 	}
242 }
243 
244 #if 0
245 #pragma mark -
246 
247 void CMSP3430::SetI2S(bool fast)
248 {
249 	// select 2 x 16 bit (1024 MHz) or 2 x 32 bit (2048) frequency
250 	SetRegister(MSP3430_WR_DEM, I2S_CONFIG, fast ? 0x0001 : 0x0000);
251 }
252 
253 bool CMSP3430::IsSAP()
254 {
255 	// bilingual sound mode or SAP present?
256 	if ((Register(MSP3430_RD_DEM, STATUS) & 0x0100) != 0x0000)
257 		return true;
258 	return false;
259 }
260 
261 bool CMSP3430::IsMonoNICAM()
262 {
263 	// independent mono sound (only NICAM)?
264 	if ((Register(MSP3430_RD_DEM, STATUS) & 0x0080) != 0x0000)
265 		return true;
266 	return false;
267 }
268 
269 bool CMSP3430::IsStereo()
270 {
271 	// mono/stereo indication
272 	if ((Register(MSP3430_RD_DEM, STATUS) & 0x0040) != 0x0000)
273 		return true;
274 	return false;
275 }
276 
277 bool CMSP3430::IsFM()
278 {
279 	// is analog sound standard (FM or AM) active?
280 	if ((Register(MSP3430_RD_DEM, STATUS) & 0x0120) == 0x0000)
281 		return true;
282 	return false;
283 }
284 
285 bool CMSP3430::IsNICAM()
286 {
287 	// digital sound (NICAM) available?
288 	if ((Register(MSP3430_RD_DEM, STATUS) & 0x0100) == 0x0100)
289 		return true;
290 	return false;
291 }
292 
293 bool CMSP3430::HasSecondaryCarrier()
294 {
295 	// detected secondary carrier (2nd A2 or SAP sub-carrier)
296 	if ((Register(MSP3430_RD_DEM, STATUS) & 0x0004) != 0x0000)
297 		return true;
298 	return false;
299 }
300 
301 bool CMSP3430::HasPrimaryCarrier()
302 {
303 	// detected primary carrier (Mono or MPX carrier)
304 	if ((Register(MSP3430_RD_DEM, STATUS) & 0x0002) != 0x0000)
305 		return true;
306 	return false;
307 }
308 
309 void CMSP3430::SetStandard(MSP3430_standard standard)
310 {
311 	fStandard = standard;
312 
313 	// set sound mode, FM/AM matrix, source channels
314 	switch (standard) {
315 	C_MSP3430_STANDARD_BG_FM:
316 	C_MSP3430_STANDARD_DK_FM:
317 		// Sound Mode	FM Matrix		FM/AM Source	Stereo A/B Source
318 		// ---------------------------------------------------------------
319 		// Mono 		Sound A Mono	Mono			Mono
320 	C_MSP3430_STANDARD_M_KOREA:
321 	C_MSP3430_STANDARD_M_JAPAN:
322 		// Stereo 		Korean Stereo	Stereo			Stereo
323 		// Stereo 		German Stereo	Stereo			Stereo
324 		// Lang A & B	No Matrix		Left=A, Right=B	Left=A, Right=B
325 
326 	C_MSP3430_STANDARD_BG_NICAM:
327 
328 
329 	}
330 
331 	SetDemodulator();
332 }
333 
334 void CMSP3430::SetFMPrescale(int gain, MSP3430_fm_matrix matrix, bool mute)
335 {
336 	// set FM/AM prescale and FM matrix mode
337 	fFMPrescale = (mute ? 0x00 : Clamp(gain, 0x00, 0x7f)) << 8;
338 	/// see table 6--17, Appendix B.
339 	switch (matrix) {
340 	case C_MSP3430_MATRIX_NONE:
341 		fFMPrescale |= 0x0000;
342 		break;
343 	case C_MSP3430_MATRIX_GERMAN_STEREO_BG:
344 		fFMPrescale |= 0x0001;
345 		break;
346 	case C_MSP3430_MATRIX_KOREAN_STEREO:
347 		fFMPrescale |= 0x0002;
348 		break;
349 	case C_MSP3430_MATRIX_SOUND_A_MONO:
350 		fFMPrescale |= 0x0003;
351 		break;
352 	case C_MSP3430_MATROX_SOUND_B_MONO:
353 		fFMPrescale |= 0x0004;
354 		break;
355 	}
356 
357 	SetDemodulator();
358 }
359 
360 void CMSP3430::SetNICAMPrescale(int gain, bool mute)
361 {
362 	// set NICAM prescale to 0..12 dB
363 	fNICAMPrescale = (mute ? 0x00 : Clamp(0x20 + (0x5f * gain) / 12, 0x20, 0x7f)) << 8;
364 
365 	SetDemodulator();
366 }
367 
368 void CMSP3430::SetI2SPrescale(int gain, bool mute)
369 {
370 	// set digital I2S input prescale 0..18 dB
371 	fI2SPrescale = (mute ? 0x00 : Clamp(0x10 + (0x7f * gain) / 18, 0x10, 0x7f) << 8;
372 	SetSCARTInput();
373 }
374 
375 void CMSP3430::SetSCARTPrescale(int gain, bool mute)
376 {
377 	// set SCART input signal prescale 0..14 dB
378 	fSCARTPrescale = (mute ? 0x00 : Clamp(0x19 + (0x66 * gain) / 14, 0x19, 0x7f) << 8;
379 	SetSCARTInput();
380 }
381 
382 void CMSP3430::SetSource(MSP3430_source_channel speaker,
383 						 MSP3430_source_channel headphone,
384 						 MSP3430_source_channel scart1,
385 						 MSP3430_source_channel scart2,
386 						 MSP3430_source_channel i2s,
387 						 MSP3430_source_channel qpeak)
388 {
389 	// set source and matrix..
390 	// select FM/AM, Stereo A/B, Stereo A, Stereo B, SCART, I2S1 or I2S2 source channels
391 	// and select Sound A Mono, Sound B Mono, Stereo or Mono mode
392 	fSrcMain = loudspeaker;
393 	fSrcAux = headphone;
394 	fSrcSCART1 = scart1;
395 	fSrcSCART2 = scart2;
396 	fSrcI2S = i2s;
397 	fSrcQPeak = qpeak;
398 	SetOutputChannels();
399 }
400 
401 
402 void CMSP3430::SetVolume(int level, bool mute, MSP3430_clipping_mode mode,
403 				MSP3430_automatic_volume automatic)
404 {
405 	// set volume between -114 dB and 12 dB with 1 dB step size
406 	fVolume = (mute ? 0x00 : Clamp(level + 0x73, 0x01, 0x7f)) << 8;
407 	switch (mode) {
408 	case C_MSP3430_CLIP_REDUCE_VOLUME:
409 		fVolume |= 0x00;
410 		break;
411 	case C_MSP3430_CLIP_REDUCE_TONE:
412 		fVolume |= 0x01;
413 		break;
414 	case C_MSP3430_CLIP_COMPROMISE:
415 		fVolume |= 0x02;
416 		break;
417 	case C_MSP3430_CLIP_DYNAMIC:
418 		fVolume |= 0x03;
419 		break;
420 	}
421 
422 	// enable/disable automatic volume correction
423 	switch (automatic) {
424 	case C_MSP3430_AUTOMATIC_VOLUME_OFF:
425 		fAVC = 0x0000;
426 		break;
427 	case C_MSP3430_AUTOMATIC_VOLUME_20_MS:
428 		fAVC = 0x8100;
429 		break;
430 	case C_MSP3430_AUTOMATIC_VOLUME_2_SEC:
431 		fAVC = 0x8200;
432 		break;
433 	case C_MSP3430_AUTOMATIC_VOLUME_4_SEC:
434 		fAVC = 0x8400;
435 		break;
436 	case C_MSP3430_AUTOMATIC_VOLUME_8_SEC:
437 		fAVC = 0x8800;
438 		break;
439 	}
440 	SetOutputChannels();
441 }
442 
443 void CMSP3430::SetBalance(int balance, MSP3430_balance_mode mode)
444 {
445 	switch (mode) {
446 	case C_MSP3430_BALANCE_LINEAR:
447 		// set balance between -100% (right) and 100% (left)
448 		fBalance = (((0x7f * Clamp(balance, -100, 100)) / 100) << 8) + 0x0000;
449 		break;
450 
451 	case C_MSP3430_BALANCE_LOGARITHMIC:
452 		// set balance between -128 dB (right) and 127 dB (left)
453 		fBalance = (((0x7f * Clamp(balance, -128, 127)) / 127) << 8) + 0x0001;
454 		break;
455 	}
456 	SetOutputChannels();
457 }
458 
459 
460 void CMSP3430::SetEqualizer(int bass, int treble)
461 {
462 	// set bass to -12..12 dB or 14..20 dB
463 	if (bass <= 12)
464 		fBass = Clamp(0x00 + 8 * bass, -0x60, 0x60) << 8;
465 	else
466 		fBass = Clamp(0x68 + 4 * (bass - 14), 0x68, 0x7f) << 8;
467 
468 	// set treble to -12..15 dB
469 	fTreble = Clamp(0x00 + 8 * treble, -0x60, 0x78) << 8;
470 
471 	// enable bass/treble and disable equalizer
472 	fToneControl = 0x00;
473 	fEqualizer[0] = fEqualizer[1] = fEqualizer[2] =
474 	fEqualizer[3] = fEqualizer[4] = fEqualizer[5] = 0x00;
475 
476 	SetOutputChannels();
477 }
478 
479 void CMSP3430::SetEqualizer(int gain[5])
480 {
481 	// set five band equalizer (120 Hz, 500 Hz, 1500 Hz, 5000 Hz, 10000 Hz)
482 	for (int index = 0; index < 5; index++)
483 		fEqualizer[index] = Clamp(0x00 + 8 * gain[index], -0x60, 0x60) << 8;
484 
485 	// disable bass/treble and enable equalizer
486 	fToneControl = 0xff;
487 	fBass = fTreble = 0x00;
488 
489 	SetOutputChannels();
490 }
491 
492 void CMSP3430::SetLoudness(int loudness, MSP3430_loudness_mode mode)
493 {
494 	// set loudness gain between 0 dB and 17 dB
495 	fLoudness = Clamp(0x00 + 4 * loudness, 0x00, 0x44) << 8;
496 	switch (mode) {
497 	case C_MSP3430_LOUDNESS_NORMAL:
498 		fLoudness |= 0x0000;
499 		break;
500 	case C_MSP3430_LOUDNESS_SUPER_BASS:
501 		fLoudness |= 0x0004;
502 		break;
503 	}
504 
505 	SetOutputChannels();
506 }
507 
508 void CMSP3430::SetSpatial(int strength, MSP3430_spatial_mode mode, MSP3430_spatial_highpass pass)
509 {
510 	// enlarge or reduce spatial effects -100% to +100%
511 	fSpatial = Clamp(0x00 + (0x7f * strength) / 100, -0x80, 0x7f) << 8;
512 	switch (mode) {
513 	case C_MSP3430_SPATIAL_MODE_A:
514 		fSpatial |= 0x0000;
515 		break;
516 	case C_MSP3430_SPATIAL_MODE_B:
517 		fSpatial |= 0x0020;
518 		break;
519 	}
520 	switch (pass) {
521 	case C_MSP3430_SPATIAL_MAX_HIGH_PASS:
522 		fSpatial |= 0x0000;
523 		break;
524 	case C_MSP3430_SPATIAL_2_3_HIGH_PASS:
525 		fSpatial |= 0x0002;
526 		break;
527 	case C_MSP3430_SPATIAL_1_3_HIGH_PASS:
528 		fSpatial |= 0x0004;
529 		break;
530 	case C_MSP3430_SPATIAL_MIN_HIGH_PASS:
531 		fSpatial |= 0x0006;
532 		break;
533 	case C_MSP3430_SPATIAL_AUTO_HIGH_PASS:
534 		fSpatial |= 0x0008;
535 		break;
536 	}
537 	SetOutputChannels();
538 }
539 
540 void CMSP3430::SetSubwoofer(int level, int frequency, bool mute, MSP3430_subwoofer_mode mode)
541 {
542 	// set subwoofer level between -128 dB and 12 dB
543 	fSubwooferLevel = (mute ? 0x80 : Clamp(0x00 + level, -128, 12)) << 8;
544 
545 	// set subwoofer corner frequency between 50..400 Hz
546 	fSubwooferFrequency = Clamp(frequency / 10, 5, 40) << 8;
547 	switch (mode) {
548 	case C_MSP3430_SUBWOOFER_UNFILTERED:
549 		fSubwooferFrequency |= 0x0000;
550 		break;
551 	case C_MSP3430_SUBWOOFER_HIGH_PASS:
552 		fSubwooferFrequency |= 0x0001;
553 		break;
554 	case C_MSP3430_SUBWOOFER_MDB_MAIN:
555 		fSubwooferFrequency |= 0x0002;
556 		break;
557 	}
558 
559 	// disable MDB?
560 	fMDBStrength = 0x0000;
561 	fMDBLimit = 0x0000;
562 	fMDBHarmonic = 0x0000;
563 	fMDBHighPass = 0x0a00;
564 	fMDBLowPass = 0x0a00;
565 
566 	SetSubwooferAndMDBOutputChannels();
567 }
568 
569 void CMSP3430::SetMDB(int strength, int limit, int harmonic,
570 					  int minfrequency, int maxfrequency, bool mute)
571 {
572 	// set MDB effect strength 0..127
573 	fMDBStrength = (mute ? 0x00 : Clamp(strength, 0x00, 0x7f)) << 7;
574 
575 	// set MDB amplitude limit between -32..0 dBFS
576 	fMDBLimit = Clamp(limit, -32, 0) << 8;
577 
578 	// set MDB harmonic content 0..100%
579 	fMDBHarmonic = Clamp((0x7f * harmonic) / 100, 0x00, 0x7f) << 8;
580 
581 	// set MDB low pass corner frequency 50..300 Hz
582 	fMDBLowPass = Clamp(minFrequency / 10, 5, 30) << 8;
583 
584 	// set MDB high pass corner frequency 20..300 Hz
585 	fMDBHighPass = Clamp(maxFrequency / 10, 2, 30) << 8;
586 
587 	// disable subwoofer level adjustments
588 	fSubwooferLevel = 0x0000;
589 	fSubwooferFrequency = 0x0002;
590 
591 	// for MDB, use dynamic clipping mode
592 	fVolume = (fVolume & ~0x000f) | 0x0003;
593 
594 	SetSubwooferAndMDBOutputChannels();
595 }
596 
597 void CMSP3430::SetSCART(int level1, int level2, bool mute,
598 						MSP3430_scart_input input,
599 						MSP3430_scart_output output1,
600 						MSP3430_scart_output output2)
601 {
602 	// set volume SCART1/2 output channel -114..12 dB
603 	fSCART1Volume = (mute ? 0x00 : Clamp(0x73 + (0x7f * level1) / 12, 0x00, 0x7f)) << 8;
604 	fSCART2Volume = (mute ? 0x00 : Clamp(0x73 + (0x7f * level2) / 12, 0x00, 0x7f)) << 8;
605 
606 	fSCART1Volume |= 0x0001;
607 	fSCART2Volume |= 0x0001;
608 
609 	// SCART DSP input select
610 	fACB = 0x0000;
611 	switch (input) {
612 	case C_MSP3430_SCART_INPUT_SCART1:
613 		fACB = 0x0000;
614 		break;
615 	case C_MSP3430_SCART_INPUT_MONO:
616 		fACB = 0x0100;
617 		break;
618 	case C_MSP3430_SCART_INPUT_SCART2:
619 		fACB = 0x0200;
620 		break;
621 	case C_MSP3430_SCART_INPUT_SCART3:
622 		fACB = 0x0300;
623 		break;
624 	case C_MSP3430_SCART_INPUT_SCART4:
625 		fACB = 0x0020;
626 		break;
627 	case C_MSP3430_SCART_INPUT_MUTE:
628 		fACB = 0x0320;
629 		break;
630 	}
631 
632 	// SCART1 output select
633 	switch (output1) {
634 	case C_MSP3430_SCART_OUTPUT_SCART3:
635 		fACB |= 0x0000;
636 		break;
637 	case C_MSP3430_SCART_OUTPUT_SCART2:
638 		fACB |= 0x0400;
639 		break;
640 	case C_MSP3430_SCART_OUTPUT_MONO:
641 		fACB |= 0x0800;
642 		break;
643 	case C_MSP3430_SCART_OUTPUT_SCART1_DA:
644 		fACB |= 0x0c00;
645 		break;
646 	case C_MSP3430_SCART_OUTPUT_SCART2_DA:
647 		fACB |= 0x0080;
648 		break;
649 	case C_MSP3430_SCART_OUTPUT_SCART1_INPUT:
650 		fACB |= 0x0480;
651 		break;
652 	case C_MSP3430_SCART_OUTPUT_SCART4_INPUT:
653 		fACB |= 0x0880;
654 		break;
655 	case C_MSP3430_SCART_OUTPUT_MUTE:
656 		fACB |= 0x0c80;
657 		break;
658 	}
659 
660 	// SCART2 output select
661 	switch (output2) {
662 	case C_MSP3430_SCART_OUTPUT_SCART3:
663 		fACB |= 0x0000;
664 		break;
665 	case C_MSP3430_SCART_OUTPUT_SCART2:
666 		fACB |= 0x1000;
667 		break;
668 	case C_MSP3430_SCART_OUTPUT_MONO:
669 		fACB |= 0x2000;
670 		break;
671 	case C_MSP3430_SCART_OUTPUT_SCART1_DA:
672 		fACB |= 0x3000;
673 		break;
674 	case C_MSP3430_SCART_OUTPUT_SCART2_DA:
675 		fACB |= 0x0200;
676 		break;
677 	case C_MSP3430_SCART_OUTPUT_SCART1_INPUT:
678 		fACB |= 0x1200;
679 		break;
680 	case C_MSP3430_SCART_OUTPUT_SCART4_INPUT:
681 		fACB |= 0x2200;
682 		break;
683 	case C_MSP3430_SCART_OUTPUT_MUTE:
684 		fACB |= 0x3200;
685 		break;
686 	}
687 
688 	SetSCARTSignalPath();
689 	SetOutputChannels();
690 }
691 
692 void CMSP3430::SetBeeper(int volume, MSP3430_beeper_frequency frequency, bool mute)
693 {
694 	// set beeper volume 0..127
695 	int beeper = (mute ? 0x00 : Clamp(volume, 0x00, 0x7f)) << 8;
696 
697 	// set beeper frequency 16, 1000 or 4000 Hz
698 	switch (frequency) {
699 	case C_MSP3430_BEEPER_16_HZ:
700 		beeper |= 0x0001;
701 		break;
702 	case C_MSP3430_BEEPER_1_KHZ:
703 		beeper |= 0x0040;
704 		break;
705 	case C_MSP3430_BEEPER_4_KHZ:
706 		beeper |= 0x00ff;
707 		break;
708 	}
709 	SetRegister(MSP3430_WR_DSP, BEEPER, beeper);
710 }
711 
712 void CMSP3430::SetQuasiPeak(int left, int right)
713 {
714 	// set quasipeak detector readout -32768..32767
715 	fQPeakLeft = left;
716 	fQPeakRight = right;
717 
718 	SetOutputChannels();
719 }
720 
721 void CMSP3430::GetVersion(char * version)
722 {
723 	int revision = Register(MSP3430_RD_DSP, MSP_HARD_REVISION);
724 	int product = Register(MSP3430_RD_DSP, MSP_PRODUCT_ROM);
725 
726 	sprintf(version, "MSP34%02d%c-%c%d",
727 		((product  & MSP_PRODUCT)  >> 8),
728 		((revision & MSP_REVISION) >> 0) + 0x40,
729 		((revision & MSP_HARD)     >> 8) + 0x40,
730 		((product  & MSP_ROM)      >> 0));
731 }
732 
733 #pragma mark -
734 
735 void CMSP3430::Reset()
736 {
737 	// software reset
738 	SetControlRegister(MSP3430_CONTROL_RESET);
739 	SetControlRegister(MSP3430_CONTROL_NORMAL);
740 }
741 
742 void CMSP3430::SetSCARTSignalPath()
743 {
744 	// select SCART DSP input and output
745 	SetRegister(MSP3430_WR_DSP, MSP3430_DSP_ACB_REG,fACB);
746 }
747 
748 void CMSP3430::SetDemodulator()
749 {
750 	// set preferred mode and sound IF input
751 	// (automatic, enable STATUS change, detect 4.5 MHz carrier as BTSC)
752 	SetRegister(MSP3430_WR_DEM, MODUS, 0x2003);
753 
754 	// set preferred prescale (FM and NICAM)
755 	SetRegister(MSP3430_WR_DSP, PRE_FM, fFMPrescale);
756 	SetRegister(MSP3430_WR_DSP, PRE_NICAM, fNICAMPrescale);
757 
758 	// automatic sound standard selection
759 	SetRegister(MSP3430_WR_DEM, MSP3430_DEM_STANDARD_SEL, 0x0001);
760 
761 	// readback the detected TV sound or FM-radio standard
762 	while ((fStandard = Register(MSP3430_RD_DEM, STANDARD_RES)) >= 0x0800)
763 		snooze(100000);
764 }
765 
766 void CMSP3430::SetSCARTInput()
767 {
768 	// select preferred prescale for SCART and I2C
769 	SetRegister(MSP3430_WR_DSP, PRE_SCART, fSCARTPrescale);
770 	SetRegister(MSP3430_WR_DSP, PRE_I2S1, fI2SPrescale);
771 	SetRegister(MSP3430_WR_DSP, PRE_I2S2, fI2SPrescale);
772 }
773 
774 void CMSP3430::SetOutputChannels()
775 {
776 	// select source channel and matrix for each output
777 	SetRegister(MSP3430_WR_DSP, MSP3430_DSP_SRC_MAT_MAIN, fMainMatrix);
778 	SetRegister(MSP3430_WR_DSP, MSP3430_DSP_SRC_MAT_AUX, fAuxMatrix);
779 	SetRegister(MSP3430_WR_DSP, MSP3430_DSP_SRC_MAT_SCART1, fSCART1Matrix);
780 	SetRegister(MSP3430_WR_DSP, MSP3430_DSP_SRC_MAT_SCART2, fSCART2Matrix);
781 	SetRegister(MSP3430_WR_DSP, MSP3430_DSP_SRC_MAT_I2S, fI2SMatrix);
782 	SetRegister(MSP3430_WR_DSP, MSP3430_DSP_SRC_MAT_QPEAK, fQPeakMatrix);
783 
784 	// set audio baseband processing
785 	SetRegister(MSP3430_WR_DSP, MSP3430_DSP_TONE_MODE, fToneControl);
786 	SetRegister(MSP3430_WR_DSP, MSP3430_DSP_BASS_MAIN, fBass);
787 	SetRegister(MSP3430_WR_DSP, MSP3430_DSP_BASS_AUX, fBass);
788 	SetRegister(MSP3430_WR_DSP, MSP3430_DSP_TREB_MAIN, fTreble);
789 	SetRegister(MSP3430_WR_DSP, MSP3430_DSP_TREB_AUX, fTreble);
790 	SetRegister(MSP3430_WR_DSP, MSP3430_DSP_EQUAL_BAND1, fEqualizer[0]);
791 	SetRegister(MSP3430_WR_DSP, MSP3430_DSP_EQUAL_BAND2, fEqualizer[1]);
792 	SetRegister(MSP3430_WR_DSP, MSP3430_DSP_EQUAL_BAND3, fEqualizer[2]);
793 	SetRegister(MSP3430_WR_DSP, MSP3430_DSP_EQUAL_BAND4, fEqualizer[3]);
794 	SetRegister(MSP3430_WR_DSP, MSP3430_DSP_EQUAL_BAND5, fEqualizer[4]);
795 	SetRegister(MSP3430_WR_DSP, MSP3430_DSP_LOUD_MAIN, fLoudness);
796 	SetRegister(MSP3430_WR_DSP, MSP3430_DSP_LOUD_AUX, fLoudness);
797 	SetRegister(MSP3430_WR_DSP, MSP3430_DSP_SPAT_MAIN, fSpatial);
798 
799 	// select volume for each output channel
800 	SetRegister(MSP3430_WR_DSP, MSP3430_DSP_VOL_MAIN, fVolume);
801 	SetRegister(MSP3430_WR_DSP, MSP3430_DSP_VOL_AUX, fVolume);
802 	SetRegister(MSP3430_WR_DSP, MSP3430_DSP_AVC, fAVC);
803 	SetRegister(MSP3430_WR_DSP, MSP3430_DSP_BAL_MAIN, fBalance);
804 	SetRegister(MSP3430_WR_DSP, MSP3430_DSP_BAL_AUX, fBalance);
805 
806 	SetRegister(MSP3430_WR_DSP, VOL_SCART1, fSCART1Volume);
807 	SetRegister(MSP3430_WR_DSP, VOL_SCART2, fSCART2Volume);
808 
809 	// set quasipeak detector readout
810 	SetRegister(MSP3430_WR_DSP, QPEAK_L, fQPeakLeft);
811 	SetRegister(MSP3430_WR_DSP, QPEAK_R, fQPeakRight);
812 }
813 
814 void CMSP3430::SetSubwooferAndMDBOutputChannels()
815 {
816 	// set subwoofer output channel
817 	SetRegister(MSP3430_WR_DSP, SUBW_LEVEL, fSubwooferLevel);
818 	SetRegister(MSP3430_WR_DSP, SUBW_FREQ, fSubwooferFrequency);
819 
820 	// set MDB control
821 	SetRegister(MSP3430_WR_DSP, MDB_STR, fMDBStrength);
822 	SetRegister(MSP3430_WR_DSP, MDB_LIM, fMDBLimit);
823 	SetRegister(MSP3430_WR_DSP, MDB_HMC, fMDBHarmonic);
824 	SetRegister(MSP3430_WR_DSP, MDB_LP, fMDBLowPass);
825 	SetRegister(MSP3430_WR_DSP, MDB_HP, fMDBHighPass);
826 }
827 
828 #pragma mark -
829 #endif
830 
ControlRegister()831 int CMSP3430::ControlRegister()
832 {
833 	char message[1], result[2];
834 
835 	message[0] = MSP3430_CONTROL;
836 	if (fPort.Write(fAddress, message, sizeof(message), result, sizeof(result)))
837 		return ((result[0] << 8) & 0xff00) + ((result[1] << 0) & 0x00ff);
838 	return 0;
839 }
840 
SetControlRegister(int value)841 void CMSP3430::SetControlRegister(int value)
842 {
843 	char message[3];
844 
845 	message[0] = MSP3430_CONTROL;
846 	message[1] = value >> 8;
847 	message[2] = value >> 0;
848 
849 	if (!fPort.Write(fAddress, message, sizeof(message)))
850 		PRINT(("CMSP3430::SetControl() - error\n"));
851 }
852 
Register(int address,int subaddress)853 int CMSP3430::Register(int address, int subaddress)
854 {
855 	char message[3], response[2];
856 
857 	message[0] = address;
858 	message[1] = subaddress >> 8;
859 	message[2] = subaddress >> 0;
860 
861 	if (fPort.Write(fAddress, message, sizeof(message), response, sizeof(response)))
862 		return ((response[0] << 8) & 0xff00) + ((response[1] << 0) & 0x00ff);
863 	return 0;
864 }
865 
SetRegister(int address,int subaddress,int value)866 void CMSP3430::SetRegister(int address, int subaddress, int value)
867 {
868 	char message[5];
869 
870 	message[0] = address;
871 	message[1] = subaddress >> 8;
872 	message[2] = subaddress >> 0;
873 	message[3] = value >> 8;
874 	message[4] = value >> 0;
875 
876 	if (!fPort.Write(fAddress, message, sizeof(message)))
877 		PRINT(("CMSP3430::SetRegister() - error\n"));
878 }
879