|
- // Copyright 2013 Olivier Gillet.
- //
- // Author: Olivier Gillet (ol.gillet@gmail.com)
- //
- // Permission is hereby granted, free of charge, to any person obtaining a copy
- // of this software and associated documentation files (the "Software"), to deal
- // in the Software without restriction, including without limitation the rights
- // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- // copies of the Software, and to permit persons to whom the Software is
- // furnished to do so, subject to the following conditions:
- //
- // The above copyright notice and this permission notice shall be included in
- // all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- // THE SOFTWARE.
- //
- // See http://creativecommons.org/licenses/MIT/ for more information.
- //
- // -----------------------------------------------------------------------------
- //
- // Multi.
-
- #include "yarns/multi.h"
-
- #include <algorithm>
-
- #include "stmlib/algorithms/voice_allocator.h"
-
- #include "yarns/just_intonation_processor.h"
- #include "yarns/midi_handler.h"
- #include "yarns/settings.h"
-
- namespace yarns {
-
- using namespace std;
- using namespace stmlib;
-
- const uint8_t clock_divisions[] = {
- 96, 48, 32, 24, 16, 12, 8, 6, 4, 3, 2, 1
- };
-
- void Multi::Init() {
- just_intonation_processor.Init();
-
- fill(
- &settings_.custom_pitch_table[0],
- &settings_.custom_pitch_table[12],
- 0);
-
- for (uint8_t i = 0; i < kNumParts; ++i) {
- part_[i].Init();
- part_[i].set_custom_pitch_table(settings_.custom_pitch_table);
- }
- for (uint8_t i = 0; i < kNumVoices; ++i) {
- voice_[i].Init();
- }
- running_ = false;
- latched_ = false;
- recording_ = false;
-
- // Put the multi in a usable state. Even if these settings will later be
- // overriden with some data retrieved from Flash (presets).
- settings_.clock_tempo = 120;
- settings_.clock_swing = 0;
- settings_.clock_input_division = 1;
- settings_.clock_output_division = 7;
- settings_.clock_bar_duration = 4;
- settings_.clock_override = 0;
-
- MidiSettings* midi = part_[0].mutable_midi_settings();
- midi->channel = 0;
- midi->min_note = 0;
- midi->max_note = 127;
- midi->min_velocity = 0;
- midi->max_velocity = 127;
- midi->out_mode = MIDI_OUT_MODE_GENERATED_EVENTS;
-
- VoicingSettings* voicing = part_[0].mutable_voicing_settings();
- voicing->allocation_priority = NOTE_STACK_PRIORITY_LAST;
- voicing->allocation_mode = VOICE_ALLOCATION_MODE_MONO;
- voicing->legato_mode = false;
- voicing->portamento = 0;
- voicing->pitch_bend_range = 2;
- voicing->vibrato_range = 1;
- voicing->modulation_rate = 50;
- voicing->trigger_duration = 2;
- voicing->aux_cv = 1;
- voicing->aux_cv_2 = 6;
- voicing->tuning_transpose = 0;
- voicing->tuning_fine = 0;
- voicing->tuning_root = 0;
- voicing->tuning_system = 0;
- voicing->audio_mode = 0;
-
- SequencerSettings* seq = part_[0].mutable_sequencer_settings();
- seq->clock_division = 7;
- seq->gate_length = 3;
- seq->arp_range = 0;
- seq->arp_direction = 0;
- seq->arp_pattern = 0;
-
- fill(
- &seq->step[0],
- &seq->step[kNumSteps],
- SequencerStep(SEQUENCER_STEP_REST, 0));
- seq->num_steps = 0;
- // A test sequence...
- // seq->num_steps = 4;
- // seq->step[0].data[0] = 48;
- // seq->step[0].data[1] = 0x7f;
- // seq->step[1].data[0] = 72;
- // seq->step[1].data[1] = 0x7f;
- // seq->step[2].data[0] = 60;
- // seq->step[2].data[1] = 0x7f;
- // seq->step[3].data[0] = 72;
- // seq->step[3].data[1] = 0x7f;
- // voicing->audio_mode = 1; // To hear it...
-
- num_active_parts_ = 1;
- part_[0].AllocateVoices(&voice_[0], 1, false);
- settings_.layout = LAYOUT_MONO;
- }
-
- void Multi::Clock() {
- if (!running_) {
- return;
- }
-
- uint16_t output_division = clock_divisions[settings_.clock_output_division];
- uint16_t input_division = settings_.clock_input_division;
-
- // Logic equation for computing a clock output with a 50% duty cycle.
- if (output_division > 1) {
- if (clock_output_prescaler_ == 0 && clock_input_prescaler_ == 0) {
- clock_pulse_counter_ = 0xffff;
- }
- if (clock_output_prescaler_ == (output_division >> 1) &&
- clock_input_prescaler_ == (input_division >> 1)) {
- clock_pulse_counter_ = 0;
- }
- } else {
- if (input_division > 1) {
- clock_pulse_counter_ = \
- clock_input_prescaler_ <= (input_division - 1) >> 1 ? 0xffff : 0;
- } else {
- // Because no division is used, neither on the output nor on the input,
- // we don't have a sufficient fast time base to derive a 50% duty cycle
- // output. Instead, we output 5ms pulses.
- clock_pulse_counter_ = 40;
- }
- }
-
- if (!clock_input_prescaler_) {
- midi_handler.OnClock();
-
- if (song_pointer_) {
- ClockSong();
- } else {
- for (uint8_t i = 0; i < num_active_parts_; ++i) {
- part_[i].Clock();
- }
- }
-
- ++bar_position_;
- if (bar_position_ >= settings_.clock_bar_duration * 24) {
- bar_position_ = 0;
- }
- if (bar_position_ == 0) {
- reset_pulse_counter_ = 81;
- }
- if (settings_.clock_bar_duration > kMaxBarDuration) {
- bar_position_ = 1;
- }
-
- ++clock_output_prescaler_;
- if (clock_output_prescaler_ >= output_division) {
- clock_output_prescaler_ = 0;
- }
- }
-
- ++clock_input_prescaler_;
- if (clock_input_prescaler_ >= settings_.clock_input_division) {
- clock_input_prescaler_ = 0;
- }
-
- if (stop_count_down_) {
- --stop_count_down_;
- if (!stop_count_down_ && started_by_keyboard_ && internal_clock()) {
- Stop();
- }
- }
- }
-
- void Multi::Start(bool started_by_keyboard) {
- if (running_ || recording_) {
- return;
- }
- if (internal_clock()) {
- internal_clock_ticks_ = 0;
- internal_clock_.Start(settings_.clock_tempo, settings_.clock_swing);
- }
- midi_handler.OnStart();
-
- started_by_keyboard_ = started_by_keyboard;
- running_ = true;
- latched_ = false;
- clock_input_prescaler_ = 0;
- clock_output_prescaler_ = 0;
- stop_count_down_ = 0;
- bar_position_ = 0xffff;
- for (uint8_t i = 0; i < num_active_parts_; ++i) {
- part_[i].Start(started_by_keyboard);
- }
- song_pointer_ = NULL;
- }
-
- void Multi::Stop() {
- if (!running()) {
- return;
- }
- for (uint8_t i = 0; i < num_active_parts_; ++i) {
- part_[i].Stop();
- }
- midi_handler.OnStop();
- clock_pulse_counter_ = 0;
- reset_pulse_counter_ = 0;
- stop_count_down_ = 0;
- running_ = false;
- latched_ = false;
- started_by_keyboard_ = false;
- song_pointer_ = NULL;
- }
-
- void Multi::Refresh() {
- if (clock_pulse_counter_) {
- --clock_pulse_counter_;
- }
- if (reset_pulse_counter_) {
- --reset_pulse_counter_;
- }
-
- for (uint8_t i = 0; i < kNumVoices; ++i) {
- voice_[i].Refresh();
- }
- }
-
- void Multi::Set(uint8_t address, uint8_t value) {
- uint8_t* bytes;
- bytes = static_cast<uint8_t*>(static_cast<void*>(&settings_));
- uint8_t previous_value = bytes[address];
- bytes[address] = value;
- if (value != previous_value) {
- if (address == MULTI_LAYOUT) {
- ChangeLayout(
- static_cast<Layout>(previous_value),
- static_cast<Layout>(value));
- } else if (address == MULTI_CLOCK_TEMPO) {
- internal_clock_.set_tempo(settings_.clock_tempo);
- } else if (address == MULTI_CLOCK_SWING) {
- internal_clock_.set_swing(settings_.clock_swing);
- }
- }
- }
-
- void Multi::GetCvGate(uint16_t* cv, bool* gate) {
- switch (settings_.layout) {
- case LAYOUT_MONO:
- case LAYOUT_DUAL_POLYCHAINED:
- cv[0] = voice_[0].note_dac_code();
- cv[1] = voice_[0].velocity_dac_code();
- cv[2] = voice_[0].aux_cv_dac_code();
- cv[3] = voice_[0].aux_cv_dac_code_2();
- gate[0] = voice_[0].gate();
- gate[1] = voice_[0].trigger();
- gate[2] = clock();
- gate[3] = reset_or_playing_flag();
- break;
-
- case LAYOUT_DUAL_MONO:
- cv[0] = voice_[0].note_dac_code();
- cv[1] = voice_[1].note_dac_code();
- cv[2] = voice_[0].aux_cv_dac_code();
- cv[3] = voice_[1].aux_cv_dac_code();
- gate[0] = voice_[0].gate();
- gate[1] = voice_[1].gate();
- gate[2] = clock();
- gate[3] = reset_or_playing_flag();
- break;
-
- case LAYOUT_DUAL_POLY:
- case LAYOUT_QUAD_POLYCHAINED:
- cv[0] = voice_[0].note_dac_code();
- cv[1] = voice_[1].note_dac_code();
- cv[2] = voice_[0].aux_cv_dac_code();
- cv[3] = voice_[1].aux_cv_dac_code_2();
- gate[0] = voice_[0].gate();
- gate[1] = voice_[1].gate();
- gate[2] = clock();
- gate[3] = reset_or_playing_flag();
- break;
-
- case LAYOUT_QUAD_MONO:
- case LAYOUT_QUAD_POLY:
- case LAYOUT_OCTAL_POLYCHAINED:
- case LAYOUT_THREE_ONE:
- cv[0] = voice_[0].note_dac_code();
- cv[1] = voice_[1].note_dac_code();
- cv[2] = voice_[2].note_dac_code();
- cv[3] = voice_[3].note_dac_code();
- gate[0] = voice_[0].gate();
- gate[1] = voice_[1].gate();
- if (settings_.clock_override) {
- gate[2] = clock();
- gate[3] = reset_or_playing_flag();
- } else {
- gate[2] = voice_[2].gate();
- gate[3] = voice_[3].gate();
- }
- break;
-
- case LAYOUT_QUAD_TRIGGERS:
- cv[0] = voice_[0].trigger_dac_code();
- cv[1] = voice_[1].trigger_dac_code();
- cv[2] = voice_[2].trigger_dac_code();
- cv[3] = voice_[3].trigger_dac_code();
- gate[0] = voice_[0].trigger() && ~voice_[1].gate();
- gate[1] = voice_[0].trigger() && voice_[1].gate();
- gate[2] = clock();
- gate[3] = reset_or_playing_flag();
- break;
-
- case LAYOUT_QUAD_VOLTAGES:
- cv[0] = voice_[0].aux_cv_dac_code();
- cv[1] = voice_[1].aux_cv_dac_code();
- cv[2] = voice_[2].aux_cv_dac_code();
- cv[3] = voice_[3].aux_cv_dac_code();
- gate[0] = voice_[0].gate();
- gate[1] = voice_[1].gate();
- if (settings_.clock_override) {
- gate[2] = clock();
- gate[3] = reset_or_playing_flag();
- } else {
- gate[2] = voice_[2].gate();
- gate[3] = voice_[3].gate();
- }
- break;
- }
- }
-
- bool Multi::GetAudioSource(uint8_t* audio_source) {
- bool has_audio_source = false;
- switch (settings_.layout) {
- case LAYOUT_MONO:
- case LAYOUT_DUAL_POLYCHAINED:
- audio_source[0] = 0xff;
- audio_source[1] = 0xff;
- audio_source[2] = 0xff;
- audio_source[3] = voice_[0].audio_mode() ? 0 : 0xff;
- has_audio_source = voice_[0].audio_mode();
- break;
-
- case LAYOUT_DUAL_MONO:
- case LAYOUT_DUAL_POLY:
- case LAYOUT_QUAD_POLYCHAINED:
- audio_source[0] = 0xff;
- audio_source[1] = 0xff;
- audio_source[2] = voice_[0].audio_mode() ? 0 : 0xff;
- audio_source[3] = voice_[1].audio_mode() ? 1 : 0xff;
- has_audio_source = voice_[0].audio_mode() || voice_[1].audio_mode();
- break;
-
- case LAYOUT_QUAD_MONO:
- case LAYOUT_QUAD_POLY:
- case LAYOUT_OCTAL_POLYCHAINED:
- case LAYOUT_THREE_ONE:
- audio_source[0] = voice_[0].audio_mode() ? 0 : 0xff;
- audio_source[1] = voice_[1].audio_mode() ? 1 : 0xff;
- audio_source[2] = voice_[2].audio_mode() ? 2 : 0xff;
- audio_source[3] = voice_[3].audio_mode() ? 3 : 0xff;
- has_audio_source = voice_[0].audio_mode() || voice_[1].audio_mode() || \
- voice_[2].audio_mode() || voice_[3].audio_mode();
- break;
-
- case LAYOUT_QUAD_TRIGGERS:
- case LAYOUT_QUAD_VOLTAGES:
- audio_source[0] = 0xff;
- audio_source[1] = 0xff;
- audio_source[2] = 0xff;
- audio_source[3] = 0xff;
- has_audio_source = false;
- break;
- }
- return has_audio_source;
- }
-
- void Multi::GetLedsBrightness(uint8_t* brightness) {
- if (layout_configurator_.learning()) {
- fill(&brightness[0], &brightness[kNumVoices], 0);
- for (uint8_t i = 0; i < layout_configurator_.num_notes(); ++i) {
- brightness[i] = 255;
- }
- return;
- }
-
- switch (settings_.layout) {
- case LAYOUT_MONO:
- case LAYOUT_DUAL_POLYCHAINED:
- brightness[0] = voice_[0].gate() ? 255 : 0;
- brightness[1] = voice_[0].velocity() << 1;
- brightness[2] = voice_[0].aux_cv();
- brightness[3] = voice_[0].aux_cv_2();
- break;
-
- case LAYOUT_DUAL_MONO:
- brightness[0] = voice_[0].gate() ? 255 : 0;
- brightness[1] = voice_[1].gate() ? 255 : 0;
- brightness[2] = voice_[0].aux_cv();
- brightness[3] = voice_[1].aux_cv();
- break;
-
- case LAYOUT_DUAL_POLY:
- case LAYOUT_QUAD_POLYCHAINED:
- brightness[0] = voice_[0].gate() ? 255 : 0;
- brightness[1] = voice_[1].gate() ? 255 : 0;
- brightness[2] = voice_[0].aux_cv();
- brightness[3] = voice_[1].aux_cv_2();
- break;
-
- case LAYOUT_QUAD_MONO:
- case LAYOUT_QUAD_POLY:
- case LAYOUT_OCTAL_POLYCHAINED:
- case LAYOUT_QUAD_TRIGGERS:
- case LAYOUT_THREE_ONE:
- brightness[0] = voice_[0].gate() ? (voice_[0].velocity() << 1) : 0;
- brightness[1] = voice_[1].gate() ? (voice_[1].velocity() << 1) : 0;
- brightness[2] = voice_[2].gate() ? (voice_[2].velocity() << 1) : 0;
- brightness[3] = voice_[3].gate() ? (voice_[3].velocity() << 1) : 0;
- break;
-
- case LAYOUT_QUAD_VOLTAGES:
- brightness[0] = voice_[0].aux_cv();
- brightness[1] = voice_[1].aux_cv();
- brightness[2] = voice_[2].aux_cv();
- brightness[3] = voice_[3].aux_cv();
- break;
- }
- }
-
- void Multi::UpdateLayout() {
- // Reset and close all parts and voices.
- for (uint8_t i = 0; i < kNumParts; ++i) {
- part_[i].Reset();
- }
- for (uint8_t i = 0; i < kNumVoices; ++i) {
- voice_[i].NoteOff();
- }
-
- switch (settings_.layout) {
- case LAYOUT_MONO:
- case LAYOUT_DUAL_MONO:
- case LAYOUT_QUAD_MONO:
- {
- uint8_t num_parts = settings_.layout == LAYOUT_MONO ? 1 : \
- (settings_.layout == LAYOUT_DUAL_MONO ? 2 : 4);
- for (uint8_t i = 0; i < num_parts; ++i) {
- part_[i].AllocateVoices(&voice_[i], 1, false);
- }
- num_active_parts_ = num_parts;
- }
- break;
-
- case LAYOUT_DUAL_POLY:
- case LAYOUT_QUAD_POLY:
- case LAYOUT_DUAL_POLYCHAINED:
- case LAYOUT_QUAD_POLYCHAINED:
- case LAYOUT_OCTAL_POLYCHAINED:
- {
- uint8_t num_voices = settings_.layout == LAYOUT_DUAL_POLY || \
- settings_.layout == LAYOUT_QUAD_POLYCHAINED ? 2 : \
- (settings_.layout == LAYOUT_DUAL_POLYCHAINED ? 1 : 4);
- part_[0].AllocateVoices(
- &voice_[0],
- num_voices,
- settings_.layout >= LAYOUT_DUAL_POLYCHAINED);
- num_active_parts_ = 1;
- }
- break;
-
- case LAYOUT_QUAD_TRIGGERS:
- case LAYOUT_QUAD_VOLTAGES:
- {
- for (uint8_t i = 0; i < 4; ++i) {
- part_[i].AllocateVoices(&voice_[i], 1, false);
- }
- num_active_parts_ = 4;
- }
- break;
-
- case LAYOUT_THREE_ONE:
- {
- part_[0].AllocateVoices(&voice_[0], 3, false);
- part_[1].AllocateVoices(&voice_[3], 1, false);
- num_active_parts_ = 2;
- }
- break;
-
- default:
- break;
- }
- }
-
- void Multi::ChangeLayout(Layout old_layout, Layout new_layout) {
- // Reset and close all parts and voices.
- for (uint8_t i = 0; i < kNumParts; ++i) {
- part_[i].Reset();
- }
- for (uint8_t i = 0; i < kNumVoices; ++i) {
- voice_[i].NoteOff();
- }
-
- switch (new_layout) {
- case LAYOUT_MONO:
- case LAYOUT_DUAL_MONO:
- case LAYOUT_QUAD_MONO:
- {
- uint8_t num_parts = new_layout == LAYOUT_MONO ? 1 : \
- (new_layout == LAYOUT_DUAL_MONO ? 2 : 4);
-
- for (uint8_t i = 0; i < num_parts; ++i) {
- MidiSettings* midi = part_[i].mutable_midi_settings();
- if (old_layout == LAYOUT_QUAD_TRIGGERS) {
- midi->min_note = 0;
- midi->max_note = 127;
- }
- midi->min_velocity = 0;
- midi->max_velocity = 127;
-
- VoicingSettings* voicing = part_[i].mutable_voicing_settings();
- voicing->allocation_mode = VOICE_ALLOCATION_MODE_MONO;
- voicing->allocation_priority = NOTE_STACK_PRIORITY_LAST;
- }
-
- // Duplicate uninitialized voices.
- for (uint8_t i = 1; i < num_parts; ++i) {
- uint8_t destination = i;
- uint8_t source = i % num_active_parts_;
- if (destination != source) {
- memcpy(
- part_[destination].mutable_midi_settings(),
- part_[source].mutable_midi_settings(),
- sizeof(MidiSettings));
- memcpy(
- part_[destination].mutable_voicing_settings(),
- part_[source].mutable_voicing_settings(),
- sizeof(VoicingSettings));
- memcpy(
- part_[destination].mutable_sequencer_settings(),
- part_[source].mutable_sequencer_settings(),
- sizeof(SequencerSettings));
- }
- }
-
- for (uint8_t i = 0; i < num_parts; ++i) {
- part_[i].AllocateVoices(&voice_[i], 1, false);
- }
- num_active_parts_ = num_parts;
- }
- break;
-
- case LAYOUT_DUAL_POLY:
- case LAYOUT_QUAD_POLY:
- case LAYOUT_DUAL_POLYCHAINED:
- case LAYOUT_QUAD_POLYCHAINED:
- case LAYOUT_OCTAL_POLYCHAINED:
- {
- uint8_t num_voices = settings_.layout == LAYOUT_DUAL_POLY || \
- settings_.layout == LAYOUT_QUAD_POLYCHAINED ? 2 : \
- (settings_.layout == LAYOUT_DUAL_POLYCHAINED ? 1 : 4);
-
- MidiSettings* midi = part_[0].mutable_midi_settings();
- if (old_layout == LAYOUT_QUAD_TRIGGERS) {
- midi->min_note = 0;
- midi->max_note = 127;
- }
- midi->min_velocity = 0;
- midi->max_velocity = 127;
-
- VoicingSettings* voicing = part_[0].mutable_voicing_settings();
- voicing->allocation_mode = VOICE_ALLOCATION_MODE_POLY;
- voicing->allocation_priority = NOTE_STACK_PRIORITY_LAST;
- voicing->portamento = 0;
- voicing->legato_mode = 0;
-
- part_[0].AllocateVoices(
- &voice_[0],
- num_voices,
- new_layout >= LAYOUT_DUAL_POLYCHAINED);
- num_active_parts_ = 1;
- }
- break;
-
- case LAYOUT_QUAD_TRIGGERS:
- {
- for (uint8_t i = 0; i < 4; ++i) {
- MidiSettings* midi = part_[i].mutable_midi_settings();
- if (old_layout != LAYOUT_QUAD_TRIGGERS) {
- midi->min_note = 36 + i * 2;
- midi->max_note = 36 + i * 2;
- }
- midi->min_velocity = 0;
- midi->max_velocity = 127;
- midi->channel = part_[0].mutable_midi_settings()->channel;
- midi->out_mode = part_[0].mutable_midi_settings()->out_mode;
-
- VoicingSettings* voicing = part_[i].mutable_voicing_settings();
- voicing->allocation_mode = VOICE_ALLOCATION_MODE_MONO;
- voicing->allocation_priority = NOTE_STACK_PRIORITY_LAST;
- voicing->portamento = 0;
- voicing->legato_mode = 0;
- }
-
- // Duplicate sequencer settings.
- for (uint8_t i = 1; i < 4; ++i) {
- uint8_t destination = i;
- uint8_t source = i % num_active_parts_;
- if (destination != source) {
- memcpy(
- part_[destination].mutable_sequencer_settings(),
- part_[source].mutable_sequencer_settings(),
- sizeof(SequencerSettings));
- }
- }
-
- for (uint8_t i = 0; i < 4; ++i) {
- part_[i].AllocateVoices(&voice_[i], 1, false);
- }
- num_active_parts_ = 4;
- }
- break;
-
- case LAYOUT_THREE_ONE:
- {
- MidiSettings* midi = part_[0].mutable_midi_settings();
- if (old_layout == LAYOUT_QUAD_TRIGGERS) {
- midi->min_note = 0;
- midi->max_note = 127;
- }
- midi->min_velocity = 0;
- midi->max_velocity = 127;
-
- VoicingSettings* voicing = part_[0].mutable_voicing_settings();
- voicing->allocation_mode = VOICE_ALLOCATION_MODE_POLY;
- voicing->allocation_priority = NOTE_STACK_PRIORITY_LAST;
- voicing->portamento = 0;
- voicing->legato_mode = 0;
- part_[0].AllocateVoices(&voice_[0], 3, false);
-
- midi = part_[1].mutable_midi_settings();
- if (old_layout == LAYOUT_QUAD_TRIGGERS) {
- midi->min_note = 0;
- midi->max_note = 127;
- }
- midi->min_velocity = 0;
- midi->max_velocity = 127;
-
- voicing = part_[1].mutable_voicing_settings();
- voicing->allocation_mode = VOICE_ALLOCATION_MODE_MONO;
- voicing->allocation_priority = NOTE_STACK_PRIORITY_LAST;
- voicing->portamento = 0;
- voicing->legato_mode = 0;
- part_[1].AllocateVoices(&voice_[3], 1, false);
-
- num_active_parts_ = 2;
- }
- break;
-
- case LAYOUT_QUAD_VOLTAGES:
- {
- uint8_t num_parts = 4;
- for (uint8_t i = 0; i < num_parts; ++i) {
- MidiSettings* midi = part_[i].mutable_midi_settings();
- if (old_layout == LAYOUT_QUAD_TRIGGERS) {
- midi->min_note = 0;
- midi->max_note = 127;
- }
- midi->min_velocity = 0;
- midi->max_velocity = 127;
- VoicingSettings* voicing = part_[i].mutable_voicing_settings();
- voicing->allocation_mode = VOICE_ALLOCATION_MODE_MONO;
- voicing->allocation_priority = NOTE_STACK_PRIORITY_LAST;
- }
-
- // Duplicate uninitialized voices.
- for (uint8_t i = 1; i < num_parts; ++i) {
- uint8_t destination = i;
- uint8_t source = i % num_active_parts_;
- if (destination != source) {
- memcpy(
- part_[destination].mutable_midi_settings(),
- part_[source].mutable_midi_settings(),
- sizeof(MidiSettings));
- memcpy(
- part_[destination].mutable_voicing_settings(),
- part_[source].mutable_voicing_settings(),
- sizeof(VoicingSettings));
- memcpy(
- part_[destination].mutable_sequencer_settings(),
- part_[source].mutable_sequencer_settings(),
- sizeof(SequencerSettings));
- }
- }
- for (uint8_t i = 0; i < num_parts; ++i) {
- part_[i].AllocateVoices(&voice_[i], 1, false);
- }
- num_active_parts_ = num_parts;
- }
- break;
-
- default:
- break;
- }
-
- for (uint8_t i = 0; i < num_active_parts_; ++i) {
- part_[i].set_siblings(num_active_parts_ > 1);
- }
- }
-
- void Multi::Touch() {
- Stop();
-
- internal_clock_.set_tempo(settings_.clock_tempo);
- UpdateLayout();
-
- for (uint8_t i = 0; i < kNumParts; ++i) {
- part_[i].Touch();
- }
- }
-
-
- const uint8_t song[] = {
- #include "song/song.h"
- 255,
- };
-
- void Multi::StartSong() {
- Set(MULTI_LAYOUT, LAYOUT_QUAD_MONO);
- part_[0].mutable_voicing_settings()->audio_mode = 0x83;
- part_[1].mutable_voicing_settings()->audio_mode = 0x83;
- part_[2].mutable_voicing_settings()->audio_mode = 0x84;
- part_[3].mutable_voicing_settings()->audio_mode = 0x86;
- UpdateLayout();
- settings_.clock_tempo = 140;
- Stop();
- Start(false);
-
- song_pointer_ = &song[0];
- song_clock_ = 0;
- song_delta_ = 0;
- }
-
- void Multi::ClockSong() {
- while (song_clock_ >= song_delta_) {
- if (*song_pointer_ == 255) {
- song_pointer_ = &song[0];
- }
- if (*song_pointer_ == 254) {
- song_delta_ += 6;
- } else {
- uint8_t part = *song_pointer_ >> 6;
- uint8_t note = *song_pointer_ & 0x3f;
- if (note == 0) {
- part_[part].AllNotesOff();
- } else {
- part_[part].NoteOn(0, note + 24, 100);
- }
- song_clock_ = 0;
- song_delta_ = 0;
- }
- ++song_pointer_;
- }
- ++song_clock_;
- }
-
- bool Multi::ControlChange(uint8_t channel, uint8_t controller, uint8_t value) {
- bool thru = true;
-
- if (channel + 1 == settings_.remote_control_channel) {
- yarns::settings.SetFromCC(0xff, controller, value);
- if (num_active_parts_ >= 4 && \
- (controller == 0x78 || controller == 0x79 || controller == 0x7b)) {
- // Do not continue to avoid treating these messages as "all sound off",
- // "reset all controllers" and "all notes off" CC.
- return true;
- }
- }
-
- for (uint8_t i = 0; i < num_active_parts_; ++i) {
- if (part_[i].accepts(channel) && \
- channel + 1 != settings_.remote_control_channel) {
- thru = part_[i].ControlChange(channel, controller, value) && thru;
- yarns::settings.SetFromCC(i, controller, value);
- }
- }
- return thru;
- }
-
-
- /* extern */
- Multi multi;
-
- } // namespace yarns
|