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