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 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 208 CMSP3430::~CMSP3430() 209 { 210 PRINT(("CMSP3430::~CMSP3430()\n")); 211 } 212 213 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 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 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 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 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 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