| 306 | | // Mixer registers |
|---|
| 307 | | const MatrixMixBus MixerBuses_Traveler[] = { |
|---|
| 308 | | {"Mix 1", 0x4000, }, |
|---|
| 309 | | {"Mix 2", 0x4100, }, |
|---|
| 310 | | {"Mix 3", 0x4200, }, |
|---|
| 311 | | {"Mix 4", 0x4300, }, |
|---|
| 312 | | }; |
|---|
| 313 | | |
|---|
| 314 | | const MatrixMixChannel MixerChannels_Traveler[] = { |
|---|
| 315 | | {"Analog 1", MOTU_CTRL_STD_CHANNEL, 0x0000, }, |
|---|
| 316 | | {"Analog 2", MOTU_CTRL_STD_CHANNEL, 0x0004, }, |
|---|
| 317 | | {"Analog 3", MOTU_CTRL_STD_CHANNEL, 0x0008, }, |
|---|
| 318 | | {"Analog 4", MOTU_CTRL_STD_CHANNEL, 0x000c, }, |
|---|
| 319 | | {"Analog 5", MOTU_CTRL_STD_CHANNEL, 0x0010, }, |
|---|
| 320 | | {"Analog 6", MOTU_CTRL_STD_CHANNEL, 0x0014, }, |
|---|
| 321 | | {"Analog 7", MOTU_CTRL_STD_CHANNEL, 0x0018, }, |
|---|
| 322 | | {"Analog 8", MOTU_CTRL_STD_CHANNEL, 0x001c, }, |
|---|
| 323 | | {"AES/EBU 1", MOTU_CTRL_STD_CHANNEL, 0x0020, }, |
|---|
| 324 | | {"AES/EBU 2", MOTU_CTRL_STD_CHANNEL, 0x0024, }, |
|---|
| 325 | | {"SPDIF 1", MOTU_CTRL_STD_CHANNEL, 0x0028, }, |
|---|
| 326 | | {"SPDIF 2", MOTU_CTRL_STD_CHANNEL, 0x002c, }, |
|---|
| 327 | | {"ADAT 1", MOTU_CTRL_STD_CHANNEL, 0x0030, }, |
|---|
| 328 | | {"ADAT 2", MOTU_CTRL_STD_CHANNEL, 0x0034, }, |
|---|
| 329 | | {"ADAT 3", MOTU_CTRL_STD_CHANNEL, 0x0038, }, |
|---|
| 330 | | {"ADAT 4", MOTU_CTRL_STD_CHANNEL, 0x003c, }, |
|---|
| 331 | | {"ADAT 5", MOTU_CTRL_STD_CHANNEL, 0x0040, }, |
|---|
| 332 | | {"ADAT 6", MOTU_CTRL_STD_CHANNEL, 0x0044, }, |
|---|
| 333 | | {"ADAT 7", MOTU_CTRL_STD_CHANNEL, 0x0048, }, |
|---|
| 334 | | {"ADAT 8", MOTU_CTRL_STD_CHANNEL, 0x004c, }, |
|---|
| 335 | | }; |
|---|
| 336 | | |
|---|
| 337 | | const MixerCtrl MixerCtrls_Traveler[] = { |
|---|
| 338 | | {"Mix1/Mix_", "Mix 1 ", "", MOTU_CTRL_STD_MIX, 0x0c20, }, |
|---|
| 339 | | {"Mix2/Mix_", "Mix 2 ", "", MOTU_CTRL_STD_MIX, 0x0c24, }, |
|---|
| 340 | | {"Mix3/Mix_", "Mix 3 ", "", MOTU_CTRL_STD_MIX, 0x0c28, }, |
|---|
| 341 | | {"Mix4/Mix_", "Mix 4 ", "", MOTU_CTRL_STD_MIX, 0x0c2c, }, |
|---|
| 342 | | {"Mainout_", "MainOut ", "", MOTU_CTRL_MIX_FADER, 0x0c0c, }, |
|---|
| 343 | | {"Phones_", "Phones ", "", MOTU_CTRL_MIX_FADER, 0x0c10, }, |
|---|
| 344 | | |
|---|
| 345 | | /* For mic/line input controls, the "register" is the zero-based channel number */ |
|---|
| 346 | | {"Control/Ana1_", "Analog 1 input ", "", MOTU_CTRL_TRAVELER_MIC_INPUT_CTRLS, 0}, |
|---|
| 347 | | {"Control/Ana2_", "Analog 2 input ", "", MOTU_CTRL_TRAVELER_MIC_INPUT_CTRLS, 1}, |
|---|
| 348 | | {"Control/Ana3_", "Analog 3 input ", "", MOTU_CTRL_TRAVELER_MIC_INPUT_CTRLS, 2}, |
|---|
| 349 | | {"Control/Ana4_", "Analog 4 input ", "", MOTU_CTRL_TRAVELER_MIC_INPUT_CTRLS, 3}, |
|---|
| 350 | | {"Control/Ana5_", "Analog 5 input ", "", MOTU_CTRL_TRAVELER_LINE_INPUT_CTRLS, 4}, |
|---|
| 351 | | {"Control/Ana6_", "Analog 6 input ", "", MOTU_CTRL_TRAVELER_LINE_INPUT_CTRLS, 5}, |
|---|
| 352 | | {"Control/Ana7_", "Analog 7 input ", "", MOTU_CTRL_TRAVELER_LINE_INPUT_CTRLS, 6}, |
|---|
| 353 | | {"Control/Ana8_", "Analog 8 input ", "", MOTU_CTRL_TRAVELER_LINE_INPUT_CTRLS, 7}, |
|---|
| 354 | | |
|---|
| 355 | | /* For phones source control, "register" is currently unused */ |
|---|
| 356 | | {"Control/Phones_", "Phones source", "", MOTU_CTRL_PHONES_SRC, 0}, |
|---|
| 357 | | |
|---|
| 358 | | /* For optical mode controls, the "register" is used to indicate direction */ |
|---|
| 359 | | {"Control/OpticalIn_mode", "Optical input mode ", "", MOTU_CTRL_OPTICAL_MODE, MOTU_CTRL_DIR_IN}, |
|---|
| 360 | | {"Control/OpticalOut_mode", "Optical output mode ", "", MOTU_CTRL_OPTICAL_MODE, MOTU_CTRL_DIR_OUT}, |
|---|
| 361 | | }; |
|---|
| 362 | | |
|---|
| 363 | | const MatrixMixBus MixerBuses_Ultralite[] = { |
|---|
| 364 | | {"Mix 1", 0x4000, }, |
|---|
| 365 | | {"Mix 2", 0x4100, }, |
|---|
| 366 | | {"Mix 3", 0x4200, }, |
|---|
| 367 | | {"Mix 4", 0x4300, }, |
|---|
| 368 | | }; |
|---|
| 369 | | |
|---|
| 370 | | const MatrixMixChannel MixerChannels_Ultralite[] = { |
|---|
| 371 | | {"Analog 1", MOTU_CTRL_STD_CHANNEL, 0x0000, }, |
|---|
| 372 | | {"Analog 2", MOTU_CTRL_STD_CHANNEL, 0x0004, }, |
|---|
| 373 | | {"Analog 3", MOTU_CTRL_STD_CHANNEL, 0x0008, }, |
|---|
| 374 | | {"Analog 4", MOTU_CTRL_STD_CHANNEL, 0x000c, }, |
|---|
| 375 | | {"Analog 5", MOTU_CTRL_STD_CHANNEL, 0x0010, }, |
|---|
| 376 | | {"Analog 6", MOTU_CTRL_STD_CHANNEL, 0x0014, }, |
|---|
| 377 | | {"Analog 7", MOTU_CTRL_STD_CHANNEL, 0x0018, }, |
|---|
| 378 | | {"Analog 8", MOTU_CTRL_STD_CHANNEL, 0x001c, }, |
|---|
| 379 | | {"AES/EBU 1", MOTU_CTRL_STD_CHANNEL, MOTU_CTRL_NONE, }, |
|---|
| 380 | | {"AES/EBU 2", MOTU_CTRL_STD_CHANNEL, MOTU_CTRL_NONE, }, |
|---|
| 381 | | {"SPDIF 1", MOTU_CTRL_STD_CHANNEL, 0x0020, }, |
|---|
| 382 | | {"SPDIF 2", MOTU_CTRL_STD_CHANNEL, 0x0024, }, |
|---|
| 383 | | {"ADAT 1", MOTU_CTRL_STD_CHANNEL, MOTU_CTRL_NONE, }, |
|---|
| 384 | | {"ADAT 2", MOTU_CTRL_STD_CHANNEL, MOTU_CTRL_NONE, }, |
|---|
| 385 | | {"ADAT 3", MOTU_CTRL_STD_CHANNEL, MOTU_CTRL_NONE, }, |
|---|
| 386 | | {"ADAT 4", MOTU_CTRL_STD_CHANNEL, MOTU_CTRL_NONE, }, |
|---|
| 387 | | {"ADAT 5", MOTU_CTRL_STD_CHANNEL, MOTU_CTRL_NONE, }, |
|---|
| 388 | | {"ADAT 6", MOTU_CTRL_STD_CHANNEL, MOTU_CTRL_NONE, }, |
|---|
| 389 | | {"ADAT 7", MOTU_CTRL_STD_CHANNEL, MOTU_CTRL_NONE, }, |
|---|
| 390 | | {"ADAT 8", MOTU_CTRL_STD_CHANNEL, MOTU_CTRL_NONE, }, |
|---|
| 391 | | }; |
|---|
| 392 | | |
|---|
| 393 | | const MixerCtrl MixerCtrls_Ultralite[] = { |
|---|
| 394 | | {"Mix1/Mix_", "Mix 1 ", "", MOTU_CTRL_STD_MIX, 0x0c20, }, |
|---|
| 395 | | {"Mix2/Mix_", "Mix 2 ", "", MOTU_CTRL_STD_MIX, 0x0c24, }, |
|---|
| 396 | | {"Mix3/Mix_", "Mix 3 ", "", MOTU_CTRL_STD_MIX, 0x0c28, }, |
|---|
| 397 | | {"Mix4/Mix_", "Mix 4 ", "", MOTU_CTRL_STD_MIX, 0x0c2c, }, |
|---|
| 398 | | {"Mainout_", "MainOut ", "", MOTU_CTRL_MIX_FADER, 0x0c0c, }, |
|---|
| 399 | | {"Phones_", "Phones ", "", MOTU_CTRL_MIX_FADER, 0x0c10, }, |
|---|
| 400 | | |
|---|
| 401 | | /* For mic/line input controls, the "register" is the zero-based channel number */ |
|---|
| 402 | | {"Control/Ana1_", "Analog 1 input ", "", MOTU_CTRL_ULTRALITE_INPUT_CTRLS, 0}, |
|---|
| 403 | | {"Control/Ana2_", "Analog 2 input ", "", MOTU_CTRL_ULTRALITE_INPUT_CTRLS, 1}, |
|---|
| 404 | | {"Control/Ana3_", "Analog 3 input ", "", MOTU_CTRL_ULTRALITE_INPUT_CTRLS, 2}, |
|---|
| 405 | | {"Control/Ana4_", "Analog 4 input ", "", MOTU_CTRL_ULTRALITE_INPUT_CTRLS, 3}, |
|---|
| 406 | | {"Control/Ana5_", "Analog 5 input ", "", MOTU_CTRL_ULTRALITE_INPUT_CTRLS, 4}, |
|---|
| 407 | | {"Control/Ana6_", "Analog 6 input ", "", MOTU_CTRL_ULTRALITE_INPUT_CTRLS, 5}, |
|---|
| 408 | | {"Control/Ana7_", "Analog 7 input ", "", MOTU_CTRL_ULTRALITE_INPUT_CTRLS, 6}, |
|---|
| 409 | | {"Control/Ana8_", "Analog 8 input ", "", MOTU_CTRL_ULTRALITE_INPUT_CTRLS, 7}, |
|---|
| 410 | | {"Control/Spdif1_", "SPDIF 1 input ", "", MOTU_CTRL_ULTRALITE_INPUT_CTRLS, 6}, |
|---|
| 411 | | {"Control/Spdif2_", "SPDIF 2 input ", "", MOTU_CTRL_ULTRALITE_INPUT_CTRLS, 7}, |
|---|
| 412 | | |
|---|
| 413 | | /* For phones source control, "register" is currently unused */ |
|---|
| 414 | | {"Control/Phones_", "Phones source", "", MOTU_CTRL_PHONES_SRC, 0}, |
|---|
| 415 | | |
|---|
| 416 | | /* For optical mode controls, the "register" is used to indicate direction */ |
|---|
| 417 | | {"Control/OpticalIn_mode", "Optical input mode ", "", MOTU_CTRL_OPTICAL_MODE, MOTU_CTRL_DIR_IN}, |
|---|
| 418 | | {"Control/OpticalOut_mode", "Optical output mode ", "", MOTU_CTRL_OPTICAL_MODE, MOTU_CTRL_DIR_OUT}, |
|---|
| 419 | | }; |
|---|
| 420 | | |
|---|
| 421 | | const MatrixMixBus MixerBuses_896HD[] = { |
|---|
| 422 | | {"Mix 1", 0x4000, }, |
|---|
| 423 | | {"Mix 2", 0x4100, }, |
|---|
| 424 | | {"Mix 3", 0x4200, }, |
|---|
| 425 | | {"Mix 4", 0x4300, }, |
|---|
| 426 | | }; |
|---|
| 427 | | |
|---|
| 428 | | const MatrixMixChannel MixerChannels_896HD[] = { |
|---|
| 429 | | {"Analog 1", MOTU_CTRL_STD_CHANNEL, 0x0000, }, |
|---|
| 430 | | {"Analog 2", MOTU_CTRL_STD_CHANNEL, 0x0004, }, |
|---|
| 431 | | {"Analog 3", MOTU_CTRL_STD_CHANNEL, 0x0008, }, |
|---|
| 432 | | {"Analog 4", MOTU_CTRL_STD_CHANNEL, 0x000c, }, |
|---|
| 433 | | {"Analog 5", MOTU_CTRL_STD_CHANNEL, 0x0010, }, |
|---|
| 434 | | {"Analog 6", MOTU_CTRL_STD_CHANNEL, 0x0014, }, |
|---|
| 435 | | {"Analog 7", MOTU_CTRL_STD_CHANNEL, 0x0018, }, |
|---|
| 436 | | {"Analog 8", MOTU_CTRL_STD_CHANNEL, 0x001c, }, |
|---|
| 437 | | {"AES/EBU 1", MOTU_CTRL_STD_CHANNEL, 0x0020, }, |
|---|
| 438 | | {"AES/EBU 2", MOTU_CTRL_STD_CHANNEL, 0x0024, }, |
|---|
| 439 | | {"SPDIF 1", MOTU_CTRL_STD_CHANNEL, 0x0048, }, |
|---|
| 440 | | {"SPDIF 2", MOTU_CTRL_STD_CHANNEL, 0x004c, }, |
|---|
| 441 | | {"ADAT 1", MOTU_CTRL_STD_CHANNEL, 0x0028, }, |
|---|
| 442 | | {"ADAT 2", MOTU_CTRL_STD_CHANNEL, 0x002c, }, |
|---|
| 443 | | {"ADAT 3", MOTU_CTRL_STD_CHANNEL, 0x0030, }, |
|---|
| 444 | | {"ADAT 4", MOTU_CTRL_STD_CHANNEL, 0x0034, }, |
|---|
| 445 | | {"ADAT 5", MOTU_CTRL_STD_CHANNEL, 0x0038, }, |
|---|
| 446 | | {"ADAT 6", MOTU_CTRL_STD_CHANNEL, 0x003c, }, |
|---|
| 447 | | {"ADAT 7", MOTU_CTRL_STD_CHANNEL, 0x0040, }, |
|---|
| 448 | | {"ADAT 8", MOTU_CTRL_STD_CHANNEL, 0x0044, }, |
|---|
| 449 | | }; |
|---|
| 450 | | |
|---|
| 451 | | const MixerCtrl MixerCtrls_896HD[] = { |
|---|
| 452 | | {"Mix1/Mix_", "Mix 1 ", "", MOTU_CTRL_STD_MIX, 0x0c20, }, |
|---|
| 453 | | {"Mix2/Mix_", "Mix 2 ", "", MOTU_CTRL_STD_MIX, 0x0c24, }, |
|---|
| 454 | | {"Mix3/Mix_", "Mix 3 ", "", MOTU_CTRL_STD_MIX, 0x0c28, }, |
|---|
| 455 | | {"Mix4/Mix_", "Mix 4 ", "", MOTU_CTRL_STD_MIX, 0x0c2c, }, |
|---|
| 456 | | {"Mainout_", "MainOut ", "", MOTU_CTRL_MIX_FADER, 0x0c0c, }, |
|---|
| 457 | | {"Phones_", "Phones ", "", MOTU_CTRL_MIX_FADER, 0x0c10, }, |
|---|
| 458 | | |
|---|
| 459 | | /* For phones source control, "register" is currently unused */ |
|---|
| 460 | | {"Control/Phones_", "Phones source", "", MOTU_CTRL_PHONES_SRC, 0}, |
|---|
| 461 | | |
|---|
| 462 | | /* For optical mode controls, the "register" is used to indicate direction */ |
|---|
| 463 | | {"Control/OpticalIn_mode", "Optical input mode ", "", MOTU_CTRL_OPTICAL_MODE, MOTU_CTRL_DIR_IN}, |
|---|
| 464 | | {"Control/OpticalOut_mode", "Optical output mode ", "", MOTU_CTRL_OPTICAL_MODE, MOTU_CTRL_DIR_OUT}, |
|---|
| 465 | | |
|---|
| 466 | | /* For meter controls the "register" indicates which meter controls are available */ |
|---|
| 467 | | {"Control/Meter_", "Meter ", "", MOTU_CTRL_METER, |
|---|
| 468 | | MOTU_CTRL_METER_PEAKHOLD | MOTU_CTRL_METER_CLIPHOLD | MOTU_CTRL_METER_AESEBU_SRC | |
|---|
| 469 | | MOTU_CTRL_METER_PROG_SRC}, |
|---|
| 470 | | }; |
|---|
| 471 | | |
|---|
| 472 | | const MatrixMixBus MixerBuses_828Mk2[] = { |
|---|
| 473 | | {"Mix 1", 0x4000, }, |
|---|
| 474 | | {"Mix 2", 0x4100, }, |
|---|
| 475 | | {"Mix 3", 0x4200, }, |
|---|
| 476 | | {"Mix 4", 0x4300, }, |
|---|
| 477 | | }; |
|---|
| 478 | | |
|---|
| 479 | | const MatrixMixChannel MixerChannels_828Mk2[] = { |
|---|
| 480 | | {"Analog 1", MOTU_CTRL_STD_CHANNEL, 0x0000, }, |
|---|
| 481 | | {"Analog 2", MOTU_CTRL_STD_CHANNEL, 0x0004, }, |
|---|
| 482 | | {"Analog 3", MOTU_CTRL_STD_CHANNEL, 0x0008, }, |
|---|
| 483 | | {"Analog 4", MOTU_CTRL_STD_CHANNEL, 0x000c, }, |
|---|
| 484 | | {"Analog 5", MOTU_CTRL_STD_CHANNEL, 0x0010, }, |
|---|
| 485 | | {"Analog 6", MOTU_CTRL_STD_CHANNEL, 0x0014, }, |
|---|
| 486 | | {"Analog 7", MOTU_CTRL_STD_CHANNEL, 0x0018, }, |
|---|
| 487 | | {"Analog 8", MOTU_CTRL_STD_CHANNEL, 0x001c, }, |
|---|
| 488 | | {"Mic 1", MOTU_CTRL_STD_CHANNEL, 0x0020, }, |
|---|
| 489 | | {"Mic 2", MOTU_CTRL_STD_CHANNEL, 0x0024, }, |
|---|
| 490 | | {"SPDIF 1", MOTU_CTRL_STD_CHANNEL, 0x0028, }, |
|---|
| 491 | | {"SPDIF 2", MOTU_CTRL_STD_CHANNEL, 0x002c, }, |
|---|
| 492 | | {"ADAT 1", MOTU_CTRL_STD_CHANNEL, 0x0030, }, |
|---|
| 493 | | {"ADAT 2", MOTU_CTRL_STD_CHANNEL, 0x0034, }, |
|---|
| 494 | | {"ADAT 3", MOTU_CTRL_STD_CHANNEL, 0x0038, }, |
|---|
| 495 | | {"ADAT 4", MOTU_CTRL_STD_CHANNEL, 0x003c, }, |
|---|
| 496 | | {"ADAT 5", MOTU_CTRL_STD_CHANNEL, 0x0040, }, |
|---|
| 497 | | {"ADAT 6", MOTU_CTRL_STD_CHANNEL, 0x0044, }, |
|---|
| 498 | | {"ADAT 7", MOTU_CTRL_STD_CHANNEL, 0x0048, }, |
|---|
| 499 | | {"ADAT 8", MOTU_CTRL_STD_CHANNEL, 0x004c, }, |
|---|
| 500 | | }; |
|---|
| 501 | | |
|---|
| 502 | | const MixerCtrl MixerCtrls_828Mk2[] = { |
|---|
| 503 | | {"Mix1/Mix_", "Mix 1 ", "", MOTU_CTRL_STD_MIX, 0x0c20, }, |
|---|
| 504 | | {"Mix2/Mix_", "Mix 2 ", "", MOTU_CTRL_STD_MIX, 0x0c24, }, |
|---|
| 505 | | {"Mix3/Mix_", "Mix 3 ", "", MOTU_CTRL_STD_MIX, 0x0c28, }, |
|---|
| 506 | | {"Mix4/Mix_", "Mix 4 ", "", MOTU_CTRL_STD_MIX, 0x0c2c, }, |
|---|
| 507 | | {"Mainout_", "MainOut ", "", MOTU_CTRL_MIX_FADER, 0x0c0c, }, |
|---|
| 508 | | {"Phones_", "Phones ", "", MOTU_CTRL_MIX_FADER, 0x0c10, }, |
|---|
| 509 | | |
|---|
| 510 | | /* For mic/line input controls, the "register" is the zero-based channel number */ |
|---|
| 511 | | {"Control/Ana1_", "Analog 1 input ", "", MOTU_CTRL_TRAVELER_LINE_INPUT_CTRLS, 0}, |
|---|
| 512 | | {"Control/Ana2_", "Analog 2 input ", "", MOTU_CTRL_TRAVELER_LINE_INPUT_CTRLS, 1}, |
|---|
| 513 | | {"Control/Ana3_", "Analog 3 input ", "", MOTU_CTRL_TRAVELER_LINE_INPUT_CTRLS, 2}, |
|---|
| 514 | | {"Control/Ana4_", "Analog 4 input ", "", MOTU_CTRL_TRAVELER_LINE_INPUT_CTRLS, 3}, |
|---|
| 515 | | {"Control/Ana5_", "Analog 5 input ", "", MOTU_CTRL_TRAVELER_LINE_INPUT_CTRLS, 4}, |
|---|
| 516 | | {"Control/Ana6_", "Analog 6 input ", "", MOTU_CTRL_TRAVELER_LINE_INPUT_CTRLS, 5}, |
|---|
| 517 | | {"Control/Ana7_", "Analog 7 input ", "", MOTU_CTRL_TRAVELER_LINE_INPUT_CTRLS, 6}, |
|---|
| 518 | | {"Control/Ana8_", "Analog 8 input ", "", MOTU_CTRL_TRAVELER_LINE_INPUT_CTRLS, 7}, |
|---|
| 519 | | |
|---|
| 520 | | /* For phones source control, "register" is currently unused */ |
|---|
| 521 | | {"Control/Phones_", "Phones source", "", MOTU_CTRL_PHONES_SRC, 0}, |
|---|
| 522 | | |
|---|
| 523 | | /* For optical mode controls, the "register" is used to indicate direction */ |
|---|
| 524 | | {"Control/OpticalIn_mode", "Optical input mode ", "", MOTU_CTRL_OPTICAL_MODE, MOTU_CTRL_DIR_IN}, |
|---|
| 525 | | {"Control/OpticalOut_mode", "Optical output mode ", "", MOTU_CTRL_OPTICAL_MODE, MOTU_CTRL_DIR_OUT}, |
|---|
| 526 | | }; |
|---|
| 527 | | |
|---|
| 528 | | const MotuMixer Mixer_Traveler = MOTUMIXER( |
|---|
| 529 | | MixerCtrls_Traveler, MixerBuses_Traveler, MixerChannels_Traveler); |
|---|
| 530 | | |
|---|
| 531 | | const MotuMixer Mixer_Ultralite = MOTUMIXER( |
|---|
| 532 | | MixerCtrls_Ultralite, MixerBuses_Ultralite, MixerChannels_Ultralite); |
|---|
| 533 | | |
|---|
| 534 | | const MotuMixer Mixer_828Mk2 = MOTUMIXER( |
|---|
| 535 | | MixerCtrls_828Mk2, MixerBuses_828Mk2, MixerChannels_828Mk2); |
|---|
| 536 | | |
|---|
| 537 | | const MotuMixer Mixer_896HD = MOTUMIXER( |
|---|
| 538 | | MixerCtrls_896HD, MixerBuses_896HD, MixerChannels_896HD); |
|---|
| 539 | | |
|---|
| 584 | | } |
|---|
| 585 | | |
|---|
| 586 | | bool |
|---|
| 587 | | MotuDevice::buildMixerAudioControls(void) { |
|---|
| 588 | | |
|---|
| 589 | | bool result = true; |
|---|
| 590 | | MotuMatrixMixer *fader_mmixer = NULL; |
|---|
| 591 | | MotuMatrixMixer *pan_mmixer = NULL; |
|---|
| 592 | | MotuMatrixMixer *solo_mmixer = NULL; |
|---|
| 593 | | MotuMatrixMixer *mute_mmixer = NULL; |
|---|
| 594 | | const struct MatrixMixBus *buses = NULL; |
|---|
| 595 | | const struct MatrixMixChannel *channels = NULL; |
|---|
| 596 | | unsigned int bus, ch, i; |
|---|
| 597 | | |
|---|
| 598 | | if (DevicesProperty[m_motu_model-1].mixer == NULL) { |
|---|
| 599 | | debugOutput(DEBUG_LEVEL_WARNING, "No mixer controls defined for model %d\n", m_motu_model); |
|---|
| 600 | | result = false; |
|---|
| 601 | | } else { |
|---|
| 602 | | buses = DevicesProperty[m_motu_model-1].mixer->mixer_buses; |
|---|
| 603 | | if (buses == NULL) { |
|---|
| 604 | | debugOutput(DEBUG_LEVEL_WARNING, "No buses defined for model %d\n", m_motu_model); |
|---|
| 605 | | result = false; |
|---|
| 606 | | } |
|---|
| 607 | | channels = DevicesProperty[m_motu_model-1].mixer->mixer_channels; |
|---|
| 608 | | if (channels == NULL) { |
|---|
| 609 | | debugOutput(DEBUG_LEVEL_WARNING, "No channels defined for model %d\n", m_motu_model); |
|---|
| 610 | | result = false; |
|---|
| 611 | | } |
|---|
| 612 | | } |
|---|
| 613 | | if (result == false) { |
|---|
| 614 | | return true; |
|---|
| 615 | | } |
|---|
| 616 | | |
|---|
| 617 | | /* Create the top-level matrix mixers */ |
|---|
| 618 | | fader_mmixer = new ChannelFaderMatrixMixer(*this, "fader"); |
|---|
| 619 | | result &= m_MixerContainer->addElement(fader_mmixer); |
|---|
| 620 | | pan_mmixer = new ChannelPanMatrixMixer(*this, "pan"); |
|---|
| 621 | | result &= m_MixerContainer->addElement(pan_mmixer); |
|---|
| 622 | | solo_mmixer = new ChannelBinSwMatrixMixer(*this, "solo", |
|---|
| 623 | | MOTU_CTRL_MASK_SOLO_VALUE, MOTU_CTRL_MASK_SOLO_SETENABLE); |
|---|
| 624 | | result &= m_MixerContainer->addElement(solo_mmixer); |
|---|
| 625 | | mute_mmixer = new ChannelBinSwMatrixMixer(*this, "mute", |
|---|
| 626 | | MOTU_CTRL_MASK_MUTE_VALUE, MOTU_CTRL_MASK_MUTE_SETENABLE); |
|---|
| 627 | | result &= m_MixerContainer->addElement(mute_mmixer); |
|---|
| 628 | | |
|---|
| 629 | | for (bus=0; bus<DevicesProperty[m_motu_model-1].mixer->n_mixer_buses; bus++) { |
|---|
| 630 | | fader_mmixer->addRowInfo(buses[bus].name, 0, buses[bus].address); |
|---|
| 631 | | pan_mmixer->addRowInfo(buses[bus].name, 0, buses[bus].address); |
|---|
| 632 | | solo_mmixer->addRowInfo(buses[bus].name, 0, buses[bus].address); |
|---|
| 633 | | mute_mmixer->addRowInfo(buses[bus].name, 0, buses[bus].address); |
|---|
| 634 | | } |
|---|
| 635 | | |
|---|
| 636 | | for (ch=0; ch<DevicesProperty[m_motu_model-1].mixer->n_mixer_channels; ch++) { |
|---|
| 637 | | uint32_t flags = channels[ch].flags; |
|---|
| 638 | | if (flags & MOTU_CTRL_CHANNEL_FADER) |
|---|
| 639 | | fader_mmixer->addColInfo(channels[ch].name, 0, channels[ch].addr_ofs); |
|---|
| 640 | | if (flags & MOTU_CTRL_CHANNEL_PAN) |
|---|
| 641 | | pan_mmixer->addColInfo(channels[ch].name, 0, channels[ch].addr_ofs); |
|---|
| 642 | | if (flags & MOTU_CTRL_CHANNEL_SOLO) |
|---|
| 643 | | solo_mmixer->addColInfo(channels[ch].name, 0, channels[ch].addr_ofs); |
|---|
| 644 | | if (flags & MOTU_CTRL_CHANNEL_MUTE) |
|---|
| 645 | | mute_mmixer->addColInfo(channels[ch].name, 0, channels[ch].addr_ofs); |
|---|
| 646 | | flags &= ~(MOTU_CTRL_CHANNEL_FADER|MOTU_CTRL_CHANNEL_PAN|MOTU_CTRL_CHANNEL_SOLO|MOTU_CTRL_CHANNEL_MUTE); |
|---|
| 647 | | if (flags) { |
|---|
| 648 | | debugOutput(DEBUG_LEVEL_WARNING, "Control %s: unknown flag bits 0x%08x\n", channels[ch].name, flags); |
|---|
| 649 | | } |
|---|
| 650 | | } |
|---|
| 651 | | |
|---|
| 652 | | // Single non-matrixed mixer controls get added here. Channel controls are supported |
|---|
| 653 | | // here, but usually these will be a part of a matrix mixer. |
|---|
| 654 | | for (i=0; i<DevicesProperty[m_motu_model-1].mixer->n_mixer_ctrls; i++) { |
|---|
| 655 | | const struct MixerCtrl *ctrl = &DevicesProperty[m_motu_model-1].mixer->mixer_ctrl[i]; |
|---|
| 656 | | unsigned int type; |
|---|
| 657 | | char name[100]; |
|---|
| 658 | | char label[100]; |
|---|
| 659 | | |
|---|
| 660 | | if (ctrl == NULL) { |
|---|
| 661 | | debugOutput(DEBUG_LEVEL_WARNING, "NULL control at index %d for model %d\n", i, m_motu_model); |
|---|
| 662 | | continue; |
|---|
| 663 | | } |
|---|
| 664 | | type = ctrl->type; |
|---|
| 665 | | if (type & MOTU_CTRL_CHANNEL_FADER) { |
|---|
| 666 | | snprintf(name, 100, "%s%s", ctrl->name, "fader"); |
|---|
| 667 | | snprintf(label,100, "%s%s", ctrl->label,"fader"); |
|---|
| 668 | | result &= m_MixerContainer->addElement( |
|---|
| 669 | | new ChannelFader(*this, ctrl->dev_register, name, label, ctrl->desc)); |
|---|
| 670 | | type &= ~MOTU_CTRL_CHANNEL_FADER; |
|---|
| 671 | | } |
|---|
| 672 | | if (type & MOTU_CTRL_CHANNEL_PAN) { |
|---|
| 673 | | snprintf(name, 100, "%s%s", ctrl->name, "pan"); |
|---|
| 674 | | snprintf(label,100, "%s%s", ctrl->label,"pan"); |
|---|
| 675 | | result &= m_MixerContainer->addElement( |
|---|
| 676 | | new ChannelPan(*this, |
|---|
| 677 | | ctrl->dev_register, |
|---|
| 678 | | name, label, |
|---|
| 679 | | ctrl->desc)); |
|---|
| 680 | | type &= ~MOTU_CTRL_CHANNEL_PAN; |
|---|
| 681 | | } |
|---|
| 682 | | if (type & MOTU_CTRL_CHANNEL_MUTE) { |
|---|
| 683 | | snprintf(name, 100, "%s%s", ctrl->name, "mute"); |
|---|
| 684 | | snprintf(label,100, "%s%s", ctrl->label,"mute"); |
|---|
| 685 | | result &= m_MixerContainer->addElement( |
|---|
| 686 | | new MotuBinarySwitch(*this, ctrl->dev_register, |
|---|
| 687 | | MOTU_CTRL_MASK_MUTE_VALUE, MOTU_CTRL_MASK_MUTE_SETENABLE, |
|---|
| 688 | | name, label, ctrl->desc)); |
|---|
| 689 | | type &= ~MOTU_CTRL_CHANNEL_MUTE; |
|---|
| 690 | | } |
|---|
| 691 | | if (type & MOTU_CTRL_CHANNEL_SOLO) { |
|---|
| 692 | | snprintf(name, 100, "%s%s", ctrl->name, "solo"); |
|---|
| 693 | | snprintf(label,100, "%s%s", ctrl->label,"solo"); |
|---|
| 694 | | result &= m_MixerContainer->addElement( |
|---|
| 695 | | new MotuBinarySwitch(*this, ctrl->dev_register, |
|---|
| 696 | | MOTU_CTRL_MASK_SOLO_VALUE, MOTU_CTRL_MASK_SOLO_SETENABLE, |
|---|
| 697 | | name, label, ctrl->desc)); |
|---|
| 698 | | type &= ~MOTU_CTRL_CHANNEL_SOLO; |
|---|
| 699 | | } |
|---|
| 700 | | |
|---|
| 701 | | if (type & MOTU_CTRL_MIX_FADER) { |
|---|
| 702 | | snprintf(name, 100, "%s%s", ctrl->name, "fader"); |
|---|
| 703 | | snprintf(label,100, "%s%s", ctrl->label,"fader"); |
|---|
| 704 | | result &= m_MixerContainer->addElement( |
|---|
| 705 | | new MixFader(*this, ctrl->dev_register, name, label, ctrl->desc)); |
|---|
| 706 | | type &= ~MOTU_CTRL_MIX_FADER; |
|---|
| 707 | | } |
|---|
| 708 | | if (type & MOTU_CTRL_MIX_MUTE) { |
|---|
| 709 | | snprintf(name, 100, "%s%s", ctrl->name, "mute"); |
|---|
| 710 | | snprintf(label,100, "%s%s", ctrl->label,"mute"); |
|---|
| 711 | | result &= m_MixerContainer->addElement( |
|---|
| 712 | | new MixMute(*this, ctrl->dev_register, name, label, ctrl->desc)); |
|---|
| 713 | | type &= ~MOTU_CTRL_MIX_MUTE; |
|---|
| 714 | | } |
|---|
| 715 | | if (type & MOTU_CTRL_MIX_DEST) { |
|---|
| 716 | | snprintf(name, 100, "%s%s", ctrl->name, "dest"); |
|---|
| 717 | | snprintf(label,100, "%s%s", ctrl->label,"dest"); |
|---|
| 718 | | result &= m_MixerContainer->addElement( |
|---|
| 719 | | new MixDest(*this, ctrl->dev_register, name, label, ctrl->desc)); |
|---|
| 720 | | type &= ~MOTU_CTRL_MIX_DEST; |
|---|
| 721 | | } |
|---|
| 722 | | |
|---|
| 723 | | if (type & MOTU_CTRL_INPUT_UL_GAIN) { |
|---|
| 724 | | snprintf(name, 100, "%s%s", ctrl->name, "trimgain"); |
|---|
| 725 | | snprintf(label,100, "%s%s", ctrl->label,"trimgain"); |
|---|
| 726 | | result &= m_MixerContainer->addElement( |
|---|
| 727 | | new InputGainPadInv(*this, ctrl->dev_register, MOTU_CTRL_MODE_UL_GAIN, |
|---|
| 728 | | name, label, ctrl->desc)); |
|---|
| 729 | | type &= ~MOTU_CTRL_INPUT_UL_GAIN; |
|---|
| 730 | | } |
|---|
| 731 | | if (type & MOTU_CTRL_INPUT_PHASE_INV) { |
|---|
| 732 | | snprintf(name, 100, "%s%s", ctrl->name, "invert"); |
|---|
| 733 | | snprintf(label,100, "%s%s", ctrl->label,"invert"); |
|---|
| 734 | | result &= m_MixerContainer->addElement( |
|---|
| 735 | | new InputGainPadInv(*this, ctrl->dev_register, MOTU_CTRL_MODE_PHASE_INV, |
|---|
| 736 | | name, label, ctrl->desc)); |
|---|
| 737 | | type &= ~MOTU_CTRL_INPUT_PHASE_INV; |
|---|
| 738 | | } |
|---|
| 739 | | if (type & MOTU_CTRL_INPUT_TRIMGAIN) { |
|---|
| 740 | | snprintf(name, 100, "%s%s", ctrl->name, "trimgain"); |
|---|
| 741 | | snprintf(label,100, "%s%s", ctrl->label,"trimgain"); |
|---|
| 742 | | result &= m_MixerContainer->addElement( |
|---|
| 743 | | new InputGainPadInv(*this, ctrl->dev_register, MOTU_CTRL_MODE_TRIMGAIN, |
|---|
| 744 | | name, label, ctrl->desc)); |
|---|
| 745 | | type &= ~MOTU_CTRL_INPUT_TRIMGAIN; |
|---|
| 746 | | } |
|---|
| 747 | | if (type & MOTU_CTRL_INPUT_PAD) { |
|---|
| 748 | | snprintf(name, 100, "%s%s", ctrl->name, "pad"); |
|---|
| 749 | | snprintf(label,100, "%s%s", ctrl->label,"pad"); |
|---|
| 750 | | result &= m_MixerContainer->addElement( |
|---|
| 751 | | new InputGainPadInv(*this, ctrl->dev_register, MOTU_CTRL_MODE_PAD, |
|---|
| 752 | | name, label, ctrl->desc)); |
|---|
| 753 | | type &= ~MOTU_CTRL_INPUT_PAD; |
|---|
| 754 | | } |
|---|
| 755 | | |
|---|
| 756 | | if (type & MOTU_CTRL_INPUT_LEVEL) { |
|---|
| 757 | | snprintf(name, 100, "%s%s", ctrl->name, "level"); |
|---|
| 758 | | snprintf(label,100, "%s%s", ctrl->label,"level"); |
|---|
| 759 | | result &= m_MixerContainer->addElement( |
|---|
| 760 | | new MotuBinarySwitch(*this, MOTU_REG_INPUT_LEVEL, |
|---|
| 761 | | 1<<ctrl->dev_register, 0, name, label, ctrl->desc)); |
|---|
| 762 | | type &= ~MOTU_CTRL_INPUT_LEVEL; |
|---|
| 763 | | } |
|---|
| 764 | | if (type & MOTU_CTRL_INPUT_BOOST) { |
|---|
| 765 | | snprintf(name, 100, "%s%s", ctrl->name, "boost"); |
|---|
| 766 | | snprintf(label,100, "%s%s", ctrl->label,"boost"); |
|---|
| 767 | | result &= m_MixerContainer->addElement( |
|---|
| 768 | | new MotuBinarySwitch(*this, MOTU_REG_INPUT_BOOST, |
|---|
| 769 | | 1<<ctrl->dev_register, 0, name, label, ctrl->desc)); |
|---|
| 770 | | type &= ~MOTU_CTRL_INPUT_BOOST; |
|---|
| 771 | | } |
|---|
| 772 | | if (type & MOTU_CTRL_PHONES_SRC) { |
|---|
| 773 | | snprintf(name, 100, "%s%s", ctrl->name, "src"); |
|---|
| 774 | | snprintf(label,100, "%s%s", ctrl->label,"src"); |
|---|
| 775 | | result &= m_MixerContainer->addElement( |
|---|
| 776 | | new PhonesSrc(*this, name, label, ctrl->desc)); |
|---|
| 777 | | type &= ~MOTU_CTRL_PHONES_SRC; |
|---|
| 778 | | } |
|---|
| 779 | | if (type & MOTU_CTRL_OPTICAL_MODE) { |
|---|
| 780 | | result &= m_MixerContainer->addElement( |
|---|
| 781 | | new OpticalMode(*this, ctrl->dev_register, |
|---|
| 782 | | ctrl->name, ctrl->label, ctrl->desc)); |
|---|
| 783 | | type &= ~MOTU_CTRL_OPTICAL_MODE; |
|---|
| 784 | | } |
|---|
| 785 | | if (type & MOTU_CTRL_METER) { |
|---|
| 786 | | if (ctrl->dev_register & MOTU_CTRL_METER_PEAKHOLD) { |
|---|
| 787 | | snprintf(name, 100, "%s%s", ctrl->name, "peakhold_time"); |
|---|
| 788 | | snprintf(label,100, "%s%s", ctrl->label,"peakhold time"); |
|---|
| 789 | | result &= m_MixerContainer->addElement( |
|---|
| 790 | | new MeterControl(*this, MOTU_METER_PEAKHOLD_MASK, |
|---|
| 791 | | MOTU_METER_PEAKHOLD_SHIFT, name, label, ctrl->desc)); |
|---|
| 792 | | } |
|---|
| 793 | | if (ctrl->dev_register & MOTU_CTRL_METER_CLIPHOLD) { |
|---|
| 794 | | snprintf(name, 100, "%s%s", ctrl->name, "cliphold_time"); |
|---|
| 795 | | snprintf(label,100, "%s%s", ctrl->label,"cliphold time"); |
|---|
| 796 | | result &= m_MixerContainer->addElement( |
|---|
| 797 | | new MeterControl(*this, MOTU_METER_CLIPHOLD_MASK, |
|---|
| 798 | | MOTU_METER_CLIPHOLD_SHIFT, name, label, ctrl->desc)); |
|---|
| 799 | | } |
|---|
| 800 | | if (ctrl->dev_register & MOTU_CTRL_METER_AESEBU_SRC) { |
|---|
| 801 | | snprintf(name, 100, "%s%s", ctrl->name, "aesebu_src"); |
|---|
| 802 | | snprintf(label,100, "%s%s", ctrl->label,"AESEBU source"); |
|---|
| 803 | | result &= m_MixerContainer->addElement( |
|---|
| 804 | | new MeterControl(*this, MOTU_METER_AESEBU_SRC_MASK, |
|---|
| 805 | | MOTU_METER_AESEBU_SRC_SHIFT, name, label, ctrl->desc)); |
|---|
| 806 | | } |
|---|
| 807 | | if (ctrl->dev_register & MOTU_CTRL_METER_PROG_SRC) { |
|---|
| 808 | | snprintf(name, 100, "%s%s", ctrl->name, "src"); |
|---|
| 809 | | snprintf(label,100, "%s%s", ctrl->label,"source"); |
|---|
| 810 | | result &= m_MixerContainer->addElement( |
|---|
| 811 | | new MeterControl(*this, MOTU_METER_PROG_SRC_MASK, |
|---|
| 812 | | MOTU_METER_PROG_SRC_SHIFT, name, label, ctrl->desc)); |
|---|
| 813 | | } |
|---|
| 814 | | type &= ~MOTU_CTRL_METER; |
|---|
| 815 | | } |
|---|
| 816 | | |
|---|
| 817 | | if (type) { |
|---|
| 818 | | debugOutput(DEBUG_LEVEL_WARNING, "Unknown mixer control type flag bits 0x%08x\n", ctrl->type); |
|---|
| 819 | | } |
|---|
| 820 | | } |
|---|
| 821 | | return result; |
|---|
| 822 | | } |
|---|
| 823 | | |
|---|
| 824 | | bool |
|---|
| 825 | | MotuDevice::buildMixer() { |
|---|
| 826 | | bool result = true; |
|---|
| 827 | | debugOutput(DEBUG_LEVEL_VERBOSE, "Building a MOTU mixer...\n"); |
|---|
| 828 | | |
|---|
| 829 | | destroyMixer(); |
|---|
| 830 | | |
|---|
| 831 | | // create the mixer object container |
|---|
| 832 | | m_MixerContainer = new Control::Container(this, "Mixer"); |
|---|
| 833 | | if (!m_MixerContainer) { |
|---|
| 834 | | debugError("Could not create mixer container...\n"); |
|---|
| 835 | | return false; |
|---|
| 836 | | } |
|---|
| 837 | | |
|---|
| 838 | | // Create and populate the top-level matrix mixers |
|---|
| 839 | | result = buildMixerAudioControls(); |
|---|
| 840 | | |
|---|
| 841 | | /* Now add some general device information controls. These may yet |
|---|
| 842 | | * become device-specific if it turns out to be easier that way. |
|---|
| 843 | | */ |
|---|
| 844 | | result &= m_MixerContainer->addElement( |
|---|
| 845 | | new InfoElement(*this, MOTU_INFO_MODEL, "Info/Model", "Model identifier", "")); |
|---|
| 846 | | result &= m_MixerContainer->addElement( |
|---|
| 847 | | new InfoElement(*this, MOTU_INFO_IS_STREAMING, "Info/IsStreaming", "Is device streaming", "")); |
|---|
| 848 | | result &= m_MixerContainer->addElement( |
|---|
| 849 | | new InfoElement(*this, MOTU_INFO_SAMPLE_RATE, "Info/SampleRate", "Device sample rate", "")); |
|---|
| 850 | | |
|---|
| 851 | | if (!addElement(m_MixerContainer)) { |
|---|
| 852 | | debugWarning("Could not register mixer to device\n"); |
|---|
| 853 | | // clean up |
|---|
| 854 | | destroyMixer(); |
|---|
| 855 | | return false; |
|---|
| 856 | | } |
|---|
| 857 | | |
|---|
| 858 | | // Special controls |
|---|
| 859 | | m_ControlContainer = new Control::Container(this, "Control"); |
|---|
| 860 | | if (!m_ControlContainer) { |
|---|
| 861 | | debugError("Could not create control container...\n"); |
|---|
| 862 | | return false; |
|---|
| 863 | | } |
|---|
| 864 | | |
|---|
| 865 | | // Special controls get added here |
|---|
| 866 | | |
|---|
| 867 | | if (!result) { |
|---|
| 868 | | debugWarning("One or more device control elements could not be created."); |
|---|
| 869 | | // clean up those that couldn't be created |
|---|
| 870 | | destroyMixer(); |
|---|
| 871 | | return false; |
|---|
| 872 | | } |
|---|
| 873 | | if (!addElement(m_ControlContainer)) { |
|---|
| 874 | | debugWarning("Could not register controls to device\n"); |
|---|
| 875 | | // clean up |
|---|
| 876 | | destroyMixer(); |
|---|
| 877 | | return false; |
|---|
| 878 | | } |
|---|
| 879 | | |
|---|
| 880 | | return true; |
|---|
| 881 | | } |
|---|
| 882 | | |
|---|
| 883 | | |
|---|
| 884 | | bool |
|---|
| 885 | | MotuDevice::destroyMixer() { |
|---|
| 886 | | debugOutput(DEBUG_LEVEL_VERBOSE, "destroy mixer...\n"); |
|---|
| 887 | | |
|---|
| 888 | | if (m_MixerContainer == NULL) { |
|---|
| 889 | | debugOutput(DEBUG_LEVEL_VERBOSE, "no mixer to destroy...\n"); |
|---|
| 890 | | return true; |
|---|
| 891 | | } |
|---|
| 892 | | |
|---|
| 893 | | if (!deleteElement(m_MixerContainer)) { |
|---|
| 894 | | debugError("Mixer present but not registered to the avdevice\n"); |
|---|
| 895 | | return false; |
|---|
| 896 | | } |
|---|
| 897 | | |
|---|
| 898 | | // remove and delete (as in free) child control elements |
|---|
| 899 | | m_MixerContainer->clearElements(true); |
|---|
| 900 | | delete m_MixerContainer; |
|---|
| 901 | | m_MixerContainer = NULL; |
|---|
| 902 | | |
|---|
| 903 | | // remove control container |
|---|
| 904 | | if (m_ControlContainer == NULL) { |
|---|
| 905 | | debugOutput(DEBUG_LEVEL_VERBOSE, "no controls to destroy...\n"); |
|---|
| 906 | | return true; |
|---|
| 907 | | } |
|---|
| 908 | | |
|---|
| 909 | | if (!deleteElement(m_ControlContainer)) { |
|---|
| 910 | | debugError("Controls present but not registered to the avdevice\n"); |
|---|
| 911 | | return false; |
|---|
| 912 | | } |
|---|
| 913 | | |
|---|
| 914 | | // remove and delete (as in free) child control elements |
|---|
| 915 | | m_ControlContainer->clearElements(true); |
|---|
| 916 | | delete m_ControlContainer; |
|---|
| 917 | | m_ControlContainer = NULL; |
|---|
| 918 | | |
|---|
| 919 | | return true; |
|---|