///////////////////////////////////////////////////////////////////////////// // Set CCs via MIDI (different mapping, especially used by Loopback Feature) // see also doc/mbseqv4_cc_implementation.txt ///////////////////////////////////////////////////////////////////////////// s32 SEQ_CC_MIDI_Set(u8 track, u8 cc, u8 value) { if( cc == 0x01 ) { // ModWheel -> Morph Value // update screen immediately if in morph page if( ui_page == SEQ_UI_PAGE_TRKMORPH ) seq_ui_display_update_req = 1; // forward morph value return SEQ_MORPH_ValueSet(value); } else if( cc == 0x03 ) { seq_core_global_scale = value; return 1; } else if( cc >= 0x10 && cc <= 0x5f ) { u8 mapped_cc = cc+0x20; switch( mapped_cc ) { case SEQ_CC_LFO_AMPLITUDE: value *= 2; // 7bit -> 8bit break; case SEQ_CC_MIDI_PORT: if( value >= 0x70 ) value = 0xf0 | (value & 0x0f); // map to Bus else if( value >= 0x60 ) value = 0x80 | (value & 0x0f); // map to AOUT break; } return SEQ_CC_Set(track, mapped_cc, value); // 0x10..0x5f -> 0x30..0x7f } return -1; // CC not mapped }
///////////////////////////////////////////////////////////////////////////// // Local encoder callback function // Should return: // 1 if value has been changed // 0 if value hasn't been changed // -1 if invalid or unsupported encoder ///////////////////////////////////////////////////////////////////////////// static s32 Encoder_Handler(seq_ui_encoder_t encoder, s32 incrementer) { u8 visible_track = SEQ_UI_VisibleTrackGet(); switch( encoder ) { case SEQ_UI_ENCODER_GP1: case SEQ_UI_ENCODER_GP2: ui_selected_item = ITEM_GXTY; break; case SEQ_UI_ENCODER_GP3: case SEQ_UI_ENCODER_GP4: ui_selected_item = ITEM_REPEATS; break; case SEQ_UI_ENCODER_GP5: case SEQ_UI_ENCODER_GP6: ui_selected_item = ITEM_DELAY; break; case SEQ_UI_ENCODER_GP7: case SEQ_UI_ENCODER_GP8: ui_selected_item = ITEM_VELOCITY; break; case SEQ_UI_ENCODER_GP9: case SEQ_UI_ENCODER_GP10: ui_selected_item = ITEM_FB_VELOCITY; break; case SEQ_UI_ENCODER_GP11: case SEQ_UI_ENCODER_GP12: ui_selected_item = ITEM_FB_NOTE; break; case SEQ_UI_ENCODER_GP13: case SEQ_UI_ENCODER_GP14: ui_selected_item = ITEM_FB_GATELENGTH; break; case SEQ_UI_ENCODER_GP15: case SEQ_UI_ENCODER_GP16: ui_selected_item = ITEM_FB_TICKS; break; } // for GP encoders and Datawheel switch( ui_selected_item ) { case ITEM_GXTY: return SEQ_UI_GxTyInc(incrementer); case ITEM_REPEATS: return SEQ_UI_CC_Inc(SEQ_CC_ECHO_REPEATS, 0, 15, incrementer); case ITEM_DELAY: { // for compatibility with older patches pre Beta30 u8 value = SEQ_CC_Get(visible_track, SEQ_CC_ECHO_DELAY); value = SEQ_CORE_Echo_MapInternalToUser(value); if( SEQ_UI_Var8_Inc(&value, 0, 21, incrementer) ) { value = SEQ_CORE_Echo_MapUserToInternal(value); SEQ_CC_Set(visible_track, SEQ_CC_ECHO_DELAY, value); return 1; } return 0; } break; case ITEM_VELOCITY: return SEQ_UI_CC_Inc(SEQ_CC_ECHO_VELOCITY, 0, 40, incrementer); case ITEM_FB_VELOCITY: return SEQ_UI_CC_Inc(SEQ_CC_ECHO_FB_VELOCITY, 0, 40, incrementer); case ITEM_FB_NOTE: return SEQ_UI_CC_Inc(SEQ_CC_ECHO_FB_NOTE, 0, 49, incrementer); case ITEM_FB_GATELENGTH: return SEQ_UI_CC_Inc(SEQ_CC_ECHO_FB_GATELENGTH, 0, 40, incrementer); case ITEM_FB_TICKS: return SEQ_UI_CC_Inc(SEQ_CC_ECHO_FB_TICKS, 0, 40, incrementer); } return -1; // invalid or unsupported encoder }
///////////////////////////////////////////////////////////////////////////// // Local encoder callback function // Should return: // 1 if value has been changed // 0 if value hasn't been changed // -1 if invalid or unsupported encoder ///////////////////////////////////////////////////////////////////////////// static s32 Encoder_Handler(seq_ui_encoder_t encoder, s32 incrementer) { u8 visible_track = SEQ_UI_VisibleTrackGet(); switch( encoder ) { case SEQ_UI_ENCODER_GP1: ui_selected_item = ITEM_GXTY; break; case SEQ_UI_ENCODER_GP2: case SEQ_UI_ENCODER_GP3: case SEQ_UI_ENCODER_GP4: ui_selected_item = ITEM_GROOVE_STYLE; break; case SEQ_UI_ENCODER_GP5: case SEQ_UI_ENCODER_GP6: ui_selected_item = ITEM_GROOVE_VALUE; break; case SEQ_UI_ENCODER_GP7: case SEQ_UI_ENCODER_GP8: ui_selected_item = ITEM_GROOVE_VALUE_GLB; break; case SEQ_UI_ENCODER_GP9: ui_selected_item = ITEM_GROOVE_STEP; break; case SEQ_UI_ENCODER_GP10: ui_selected_item = ITEM_GROOVE_DELAY; break; case SEQ_UI_ENCODER_GP11: ui_selected_item = ITEM_GROOVE_LENGTH; break; case SEQ_UI_ENCODER_GP12: ui_selected_item = ITEM_GROOVE_VELOCITY; break; case SEQ_UI_ENCODER_GP13: ui_selected_item = ITEM_GROOVE_NUM_STEPS; break; case SEQ_UI_ENCODER_GP14: case SEQ_UI_ENCODER_GP15: case SEQ_UI_ENCODER_GP16: return -1; // not mapped yet } // for GP encoders and Datawheel u8 grooves_total = SEQ_GROOVE_NUM_PRESETS+SEQ_GROOVE_NUM_TEMPLATES; u8 selected_groove = SEQ_CC_Get(visible_track, SEQ_CC_GROOVE_STYLE); s32 groove_template = selected_groove - SEQ_GROOVE_NUM_PRESETS; // negative if not a custom template seq_groove_entry_t *g; if( selected_groove >= SEQ_GROOVE_NUM_PRESETS ) g = (seq_groove_entry_t *)&seq_groove_templates[selected_groove-SEQ_GROOVE_NUM_PRESETS]; else g = (seq_groove_entry_t *)&seq_groove_presets[selected_groove]; switch( ui_selected_item ) { case ITEM_GXTY: return SEQ_UI_GxTyInc(incrementer); case ITEM_GROOVE_STYLE: return SEQ_UI_CC_Inc(SEQ_CC_GROOVE_STYLE, 0, grooves_total-1, incrementer); case ITEM_GROOVE_VALUE: return SEQ_UI_CC_Inc(SEQ_CC_GROOVE_VALUE, 0, 127, incrementer); case ITEM_GROOVE_STEP: return SEQ_UI_Var8_Inc(&edit_step, 0, g->num_steps-1, incrementer); case ITEM_GROOVE_VALUE_GLB: { if( SEQ_UI_CC_Inc(SEQ_CC_GROOVE_VALUE, 0, 127, incrementer) > 0 ) { // change value for all tracks u8 value = SEQ_CC_Get(visible_track, SEQ_CC_GROOVE_VALUE); u8 track; for(track=0; track<SEQ_CORE_NUM_TRACKS; ++track) { SEQ_CC_Set(track, SEQ_CC_GROOVE_VALUE, value); } return 1; } return 0; } case ITEM_GROOVE_DELAY: { if( groove_template < 0 || groove_template >= SEQ_GROOVE_NUM_TEMPLATES ) return 0; u8 value = (u8)seq_groove_templates[groove_template].add_step_delay[edit_step] + 128; if( SEQ_UI_Var8_Inc(&value, 0, 255, incrementer) > 0 ) { seq_groove_templates[groove_template].add_step_delay[edit_step] = (s8)(value - 128); ui_store_file_required = 1; return 1; } return 0; } case ITEM_GROOVE_LENGTH: { if( groove_template < 0 || groove_template >= SEQ_GROOVE_NUM_TEMPLATES ) return 0; u8 value = (u8)seq_groove_templates[groove_template].add_step_length[edit_step] + 128; if( SEQ_UI_Var8_Inc(&value, 0, 255, incrementer) > 0 ) { seq_groove_templates[groove_template].add_step_length[edit_step] = (s8)(value - 128); ui_store_file_required = 1; return 1; } return 0; } case ITEM_GROOVE_VELOCITY: { if( groove_template < 0 || groove_template >= SEQ_GROOVE_NUM_TEMPLATES ) return 0; u8 value = (u8)seq_groove_templates[groove_template].add_step_velocity[edit_step] + 128; if( SEQ_UI_Var8_Inc(&value, 0, 255, incrementer) > 0 ) { seq_groove_templates[groove_template].add_step_velocity[edit_step] = (s8)(value - 128); ui_store_file_required = 1; return 1; } return 0; } case ITEM_GROOVE_NUM_STEPS: { if( groove_template < 0 || groove_template >= SEQ_GROOVE_NUM_TEMPLATES ) return 0; u8 value = (u8)seq_groove_templates[groove_template].num_steps; if( SEQ_UI_Var8_Inc(&value, 1, 16, incrementer) > 0 ) { seq_groove_templates[groove_template].num_steps = value; ui_store_file_required = 1; return 1; } return 0; } } return -1; // invalid or unsupported encoder }
///////////////////////////////////////////////////////////////////////////// // Called when a GP button has been toggled ///////////////////////////////////////////////////////////////////////////// s32 SEQ_UI_PAGES_GP_Button_Handler(u8 button, u8 depressed) { if( ui_controller_mode ) return SEQ_UI_PAGES_GP_Button_Handler_Controller(button, depressed); // no page reacts on depressed buttons if( depressed ) return 0; // clear button pressed: clear track if( seq_ui_button_state.CLEAR ) { u8 seq = (button >= 8) ? 1 : 0; u8 track_offset = seq ? 8 : 0; ui_selected_tracks = seq ? 0xff00 : 0x00ff; seq_record_state.ARMED_TRACKS = seq ? 0xff00 : 0x00ff; u8 seq_button = button % 8; switch( seq_button ) { case 0: { // clear note triggers (values are kept but not played) u8 track = track_offset; int num_t_steps = SEQ_TRG_NumStepsGet(track); int step8; u8 instrument = 0; u8 layer = 0; for(step8=0; step8<(num_t_steps/8); ++step8) SEQ_TRG_Set8(track, step8, layer, instrument, 0x00); } break; case 1: { // reset velocity values to 64 u8 track = track_offset + 1; int num_p_layers = SEQ_PAR_NumLayersGet(track); int par_layer; for(par_layer=0; par_layer<num_p_layers; ++par_layer) { int num_p_instruments = SEQ_PAR_NumInstrumentsGet(track); int num_p_steps = SEQ_PAR_NumStepsGet(track);; u8 init_value = 64; int step; int instrument; for(instrument=0; instrument<num_p_instruments; ++instrument) for(step=0; step<num_p_steps; ++step) SEQ_PAR_Set(track, step, par_layer, instrument, init_value); } } break; case 2: { // reset note length values to half step u8 track = track_offset + 2; int num_p_layers = SEQ_PAR_NumLayersGet(track); int par_layer; for(par_layer=0; par_layer<num_p_layers; ++par_layer) { int num_p_instruments = SEQ_PAR_NumInstrumentsGet(track); int num_p_steps = SEQ_PAR_NumStepsGet(track);; u8 init_value = 51; // half length int step; int instrument; for(instrument=0; instrument<num_p_instruments; ++instrument) for(step=0; step<num_p_steps; ++step) SEQ_PAR_Set(track, step, par_layer, instrument, init_value); } } break; default: { u8 track = track_offset + seq_button; if( seq_button == 3 ) { // special treatmend for pitchbend int par_layer = 0; { int num_p_instruments = SEQ_PAR_NumInstrumentsGet(track); int num_p_steps = SEQ_PAR_NumStepsGet(track);; u8 init_value = 64; int step; int instrument; for(instrument=0; instrument<num_p_instruments; ++instrument) for(step=0; step<num_p_steps; ++step) SEQ_PAR_Set(track, step, par_layer, instrument, init_value); } // send pitchbend 0 for proper reset of MIDI device SEQ_LAYER_DirectSendEvent(track, par_layer); } // clear CCs { int num_p_layers = SEQ_PAR_NumLayersGet(track); int par_layer; for(par_layer=(track == 3) ? 1 : 0; par_layer<num_p_layers; ++par_layer) { // don't touch pitchbender int num_p_instruments = SEQ_PAR_NumInstrumentsGet(track); int num_p_steps = SEQ_PAR_NumStepsGet(track);; u8 init_value = 64; int step; int instrument; for(instrument=0; instrument<num_p_instruments; ++instrument) for(step=0; step<num_p_steps; ++step) SEQ_PAR_Set(track, step, par_layer, instrument, init_value); // disable CC assignment SEQ_CC_Set(track, SEQ_CC_LAY_CONST_B1+par_layer, 0x80); } } } } return 0; } switch( ui_page ) { /////////////////////////////////////////////////////////////////////////// case SEQ_UI_PAGE_LOAD: case SEQ_UI_PAGE_SAVE: { // not atomic so that files can be stored in background //portENTER_CRITICAL(); u8 group; for(group=0; group<SEQ_CORE_NUM_GROUPS; ++group) { seq_pattern_t *pattern = &ui_selected_pattern[group]; pattern->bank = group; // always same as group if( button < 8 ) { pattern->group = button; ui_selected_pattern_changing = 1; } else { pattern->num = button-8; ui_selected_pattern_changing = 0; if( ui_page == SEQ_UI_PAGE_SAVE ) { //DEBUG_MSG("BEGIN Save %d:%c%d\n", pattern->bank+1, 'A'+pattern->group, pattern->num+1); s32 status = 0; if( (status=SEQ_PATTERN_Save(group, *pattern)) < 0 ) SEQ_UI_SDCardErrMsg(2000, status); else load_save_notifier_ctr = 300; // notify about save operation for 300 mS //DEBUG_MSG("END Save %d:%c%d\n", pattern->bank+1, 'A'+pattern->group, pattern->num+1); } else { //DEBUG_MSG("BEGIN Load %d:%c%d\n", pattern->bank+1, 'A'+pattern->group, pattern->num+1); SEQ_PATTERN_Change(group, *pattern, 0); load_save_notifier_ctr = 300; // notify about load operation for 300 mS //DEBUG_MSG("END Load %d:%c%d\n", pattern->bank+1, 'A'+pattern->group, pattern->num+1); } } } //portEXIT_CRITICAL(); return 0; } break; /////////////////////////////////////////////////////////////////////////// case SEQ_UI_PAGE_TRIGGER: { // should be atomic portENTER_CRITICAL(); ui_selected_step = button; u8 track; // only change triggers if track 0 and 8 for(track=0; track<SEQ_CORE_NUM_TRACKS; track+=8) if( ui_selected_tracks & (1 << track) ) { u8 *trg_ptr = (u8 *)&seq_trg_layer_value[track][2*ui_selected_step_view + (button>>3)]; *trg_ptr ^= (1 << (button&7)); } portEXIT_CRITICAL(); return 0; } break; /////////////////////////////////////////////////////////////////////////// case SEQ_UI_PAGE_LENGTH: { // should be atomic portENTER_CRITICAL(); u8 track; for(track=0; track<SEQ_CORE_NUM_TRACKS; ++track) { if( ui_selected_tracks & (1 << track) ) { if( seq_ui_button_state.LENGTH_PRESSED ) { if( (track >= 0 && track <= 2) || (track >= 8 && track <= 10) ) SEQ_CC_Set(track, SEQ_CC_LOOP, 16*ui_selected_step_view + button); else SEQ_CC_Set(track, SEQ_CC_LOOP, 64*ui_selected_step_view + 4*button + 3); // 4x resolution } else { if( (track >= 0 && track <= 2) || (track >= 8 && track <= 10) ) SEQ_CC_Set(track, SEQ_CC_LENGTH, 16*ui_selected_step_view + button); else SEQ_CC_Set(track, SEQ_CC_LENGTH, 64*ui_selected_step_view + 4*button + 3); // 4x resolution } } } portEXIT_CRITICAL(); return 0; } break; /////////////////////////////////////////////////////////////////////////// case SEQ_UI_PAGE_PROGRESSION: { // should be atomic portENTER_CRITICAL(); ui_selected_progression_preset = button; seq_ui_pages_progression_presets_t *preset = (seq_ui_pages_progression_presets_t *)&seq_ui_pages_progression_presets[ui_selected_progression_preset]; u8 track; for(track=0; track<SEQ_CORE_NUM_TRACKS; track+=8) { if( ui_selected_tracks & (1 << track) ) { SEQ_CC_Set(track, SEQ_CC_STEPS_FORWARD, (preset->steps_forward > 0) ? (preset->steps_forward-1) : 0); SEQ_CC_Set(track, SEQ_CC_STEPS_JMPBCK, preset->steps_jump_back); SEQ_CC_Set(track, SEQ_CC_STEPS_REPLAY, preset->steps_replay); SEQ_CC_Set(track, SEQ_CC_STEPS_REPEAT, preset->steps_repeat); SEQ_CC_Set(track, SEQ_CC_STEPS_SKIP, preset->steps_skip); SEQ_CC_Set(track, SEQ_CC_STEPS_RS_INTERVAL, preset->steps_rs_interval); } } // GP1 also requests synch to measure // it's a good idea to do this for all tracks so that both sequences are in synch again if( button == 0 ) SEQ_CORE_ManualSynchToMeasure(0xffff); portEXIT_CRITICAL(); return 0; } break; /////////////////////////////////////////////////////////////////////////// case SEQ_UI_PAGE_GROOVE: { // should be atomic portENTER_CRITICAL(); // first button turns off groove function // remaining buttons select custom groove #1..15 u8 groove_style = 0; if( button > 0 ) // note: starting at second custom groove, the first groove is always "off" groove_style = button+8-1; SEQ_UI_CC_Set(SEQ_CC_GROOVE_STYLE, groove_style); portEXIT_CRITICAL(); return 0; } break; /////////////////////////////////////////////////////////////////////////// case SEQ_UI_PAGE_ECHO: { // should be atomic portENTER_CRITICAL(); ui_selected_echo_preset = button; seq_ui_pages_echo_presets_t *preset = (seq_ui_pages_echo_presets_t *)&seq_ui_pages_echo_presets[ui_selected_echo_preset]; u8 track; for(track=0; track<SEQ_CORE_NUM_TRACKS; track+=8) { if( ui_selected_tracks & (1 << track) ) { SEQ_CC_Set(track, SEQ_CC_ECHO_REPEATS, preset->repeats); SEQ_CC_Set(track, SEQ_CC_ECHO_DELAY, preset->delay); SEQ_CC_Set(track, SEQ_CC_ECHO_VELOCITY, preset->velocity); SEQ_CC_Set(track, SEQ_CC_ECHO_FB_VELOCITY, preset->fb_velocity); SEQ_CC_Set(track, SEQ_CC_ECHO_FB_NOTE, preset->fb_note); SEQ_CC_Set(track, SEQ_CC_ECHO_FB_GATELENGTH, preset->fb_gatelength); SEQ_CC_Set(track, SEQ_CC_ECHO_FB_TICKS, preset->fb_ticks); } } portEXIT_CRITICAL(); } break; /////////////////////////////////////////////////////////////////////////// case SEQ_UI_PAGE_HUMANIZER: { // should be atomic portENTER_CRITICAL(); ui_selected_humanizer_preset = button; seq_ui_pages_humanizer_presets_t *preset = (seq_ui_pages_humanizer_presets_t *)&seq_ui_pages_humanizer_presets[ui_selected_humanizer_preset]; u8 track; for(track=0; track<SEQ_CORE_NUM_TRACKS; track+=8) { if( ui_selected_tracks & (1 << track) ) { SEQ_CC_Set(track, SEQ_CC_HUMANIZE_MODE, preset->mode); SEQ_CC_Set(track, SEQ_CC_HUMANIZE_VALUE, preset->value); } } portEXIT_CRITICAL(); return 0; } break; /////////////////////////////////////////////////////////////////////////// case SEQ_UI_PAGE_LFO: { // should be atomic portENTER_CRITICAL(); ui_selected_lfo_preset = button; seq_ui_pages_lfo_presets_t *preset = (seq_ui_pages_lfo_presets_t *)&seq_ui_pages_lfo_presets[ui_selected_lfo_preset]; u8 track; for(track=0; track<SEQ_CORE_NUM_TRACKS; track+=8) { if( ui_selected_tracks & (1 << track) ) { SEQ_CC_Set(track, SEQ_CC_LFO_WAVEFORM, preset->waveform); SEQ_CC_Set(track, SEQ_CC_LFO_AMPLITUDE, preset->amplitude); SEQ_CC_Set(track, SEQ_CC_LFO_PHASE, preset->phase); SEQ_CC_Set(track, SEQ_CC_LFO_STEPS, preset->steps); SEQ_CC_Set(track, SEQ_CC_LFO_STEPS_RST, preset->steps_rst); SEQ_CC_Set(track, SEQ_CC_LFO_ENABLE_FLAGS, preset->enable_flags); SEQ_CC_Set(track, SEQ_CC_LFO_CC, preset->cc); SEQ_CC_Set(track, SEQ_CC_LFO_CC_OFFSET, preset->cc_offset); SEQ_CC_Set(track, SEQ_CC_LFO_CC_PPQN, preset->cc_ppqn); } } portEXIT_CRITICAL(); return 0; } break; /////////////////////////////////////////////////////////////////////////// case SEQ_UI_PAGE_SCALE: { // should be atomic portENTER_CRITICAL(); // if SCALE button not pressed: select root key if( !seq_ui_button_state.SCALE_PRESSED ) { if( button < 12 ) { seq_core_global_scale_root_selection = button + 1; } else { seq_core_global_scale_root_selection = 0; // via keyboard } } else { // if pressed: select scale ui_selected_scale = button; if( ui_selected_scale == 0 ) { // disable force-to-scale for both note tracks (makes sense, since the scale itself is global as well) u8 track; for(track=0; track<SEQ_CORE_NUM_TRACKS; track+=8) seq_cc_trk[track].mode.FORCE_SCALE = 0; } else { // select scale seq_core_global_scale = seq_ui_pages_scale_presets[ui_selected_scale]; // enable force-to-scale for both note tracks (makes sense, since the scale itself is global as well) u8 track; for(track=0; track<SEQ_CORE_NUM_TRACKS; track+=8) seq_cc_trk[track].mode.FORCE_SCALE = 1; } } portEXIT_CRITICAL(); return 0; } break; /////////////////////////////////////////////////////////////////////////// case SEQ_UI_PAGE_MUTE: { // should be atomic portENTER_CRITICAL(); seq_core_trk_muted ^= (1 << button); portEXIT_CRITICAL(); return 0; } break; /////////////////////////////////////////////////////////////////////////// case SEQ_UI_PAGE_MIDICHN: { // should be atomic portENTER_CRITICAL(); u8 track; for(track=0; track<SEQ_CORE_NUM_TRACKS; ++track) if( ui_selected_tracks & (1 << track) ) SEQ_CC_Set(track, SEQ_CC_MIDI_CHANNEL, button); portEXIT_CRITICAL(); return 0; } break; /////////////////////////////////////////////////////////////////////////// case SEQ_UI_PAGE_REC_ARM: { // should be atomic portENTER_CRITICAL(); // allow to select an unplayed track if( button >= 8 && (seq_record_state.ARMED_TRACKS & 0x00ff) ) seq_record_state.ARMED_TRACKS = 0xff00; else if( button < 8 && (seq_record_state.ARMED_TRACKS & 0xff00) ) seq_record_state.ARMED_TRACKS = 0x00ff; else { seq_record_state.ARMED_TRACKS ^= (1 << button); } portEXIT_CRITICAL(); return 0; } break; /////////////////////////////////////////////////////////////////////////// case SEQ_UI_PAGE_REC_STEP: { case SEQ_UI_PAGE_REC_LIVE: // should be atomic portENTER_CRITICAL(); seq_record_step = 16*ui_selected_step_view + button; // we will always clear the current step for more comfortable handling // (no need to select the Trigger page for doing this) u8 track; // only change triggers if track 0 and 8 for(track=0; track<SEQ_CORE_NUM_TRACKS; track+=8) if( seq_record_state.ARMED_TRACKS & (1 << track) ) { u8 *trg_ptr = (u8 *)&seq_trg_layer_value[track][2*ui_selected_step_view + (button>>3)]; *trg_ptr &= ~(1 << (button&7)); SEQ_RECORD_Reset(track); } portEXIT_CRITICAL(); return 0; } break;
///////////////////////////////////////////////////////////////////////////// // Local encoder callback function // Should return: // 1 if value has been changed // 0 if value hasn't been changed // -1 if invalid or unsupported encoder ///////////////////////////////////////////////////////////////////////////// static s32 Encoder_Handler(seq_ui_encoder_t encoder, s32 incrementer) { u8 visible_track = SEQ_UI_VisibleTrackGet(); switch( encoder ) { case SEQ_UI_ENCODER_GP1: ui_selected_item = ITEM_GXTY; break; case SEQ_UI_ENCODER_GP2: ui_selected_item = ITEM_WAVEFORM; break; case SEQ_UI_ENCODER_GP3: ui_selected_item = ITEM_AMPLITUDE; break; case SEQ_UI_ENCODER_GP4: ui_selected_item = ITEM_PHASE; break; case SEQ_UI_ENCODER_GP5: ui_selected_item = ITEM_STEPS; break; case SEQ_UI_ENCODER_GP6: ui_selected_item = ITEM_STEPS_RST; break; case SEQ_UI_ENCODER_GP7: ui_selected_item = ITEM_ENABLE_ONE_SHOT; break; case SEQ_UI_ENCODER_GP8: return -1; // not mapped case SEQ_UI_ENCODER_GP9: ui_selected_item = ITEM_ENABLE_NOTE; break; case SEQ_UI_ENCODER_GP10: ui_selected_item = ITEM_ENABLE_VELOCITY; break; case SEQ_UI_ENCODER_GP11: ui_selected_item = ITEM_ENABLE_LENGTH; break; case SEQ_UI_ENCODER_GP12: ui_selected_item = ITEM_ENABLE_CC; break; case SEQ_UI_ENCODER_GP13: return -1; // not mapped case SEQ_UI_ENCODER_GP14: // CC number selection now has to be confirmed with GP button if( ui_selected_item != ITEM_CC ) { edit_cc_number = SEQ_CC_Get(visible_track, SEQ_CC_LFO_CC); ui_selected_item = ITEM_CC; SEQ_UI_Msg(SEQ_UI_MSG_USER, 2000, "Please confirm CC", "with GP button!"); } else if( incrementer == 0 ) { if( edit_cc_number != SEQ_CC_Get(visible_track, SEQ_CC_LFO_CC) ) { SEQ_CC_Set(visible_track, SEQ_CC_LFO_CC, edit_cc_number); SEQ_UI_Msg(SEQ_UI_MSG_USER, 2000, "CC number", "has been changed."); } // send event mios32_midi_package_t p; if( SEQ_LFO_FastCC_Event(visible_track, 0, &p, 1) >= 1 ) { MUTEX_MIDIOUT_TAKE; MIOS32_MIDI_SendPackage(SEQ_CC_Get(visible_track, SEQ_CC_MIDI_PORT), p); MUTEX_MIDIOUT_GIVE; } } break; case SEQ_UI_ENCODER_GP15: ui_selected_item = ITEM_CC_OFFSET; break; case SEQ_UI_ENCODER_GP16: ui_selected_item = ITEM_CC_PPQN; break; } // for GP encoders and Datawheel switch( ui_selected_item ) { case ITEM_GXTY: return SEQ_UI_GxTyInc(incrementer); case ITEM_WAVEFORM: return SEQ_UI_CC_Inc(SEQ_CC_LFO_WAVEFORM, 0, 22, incrementer); case ITEM_AMPLITUDE: return SEQ_UI_CC_Inc(SEQ_CC_LFO_AMPLITUDE, 0, 255, incrementer); case ITEM_PHASE: return SEQ_UI_CC_Inc(SEQ_CC_LFO_PHASE, 0, 99, incrementer); case ITEM_STEPS: return SEQ_UI_CC_Inc(SEQ_CC_LFO_STEPS, 0, 255, incrementer); case ITEM_STEPS_RST: return SEQ_UI_CC_Inc(SEQ_CC_LFO_STEPS_RST, 0, 255, incrementer); case ITEM_ENABLE_ONE_SHOT: case ITEM_ENABLE_NOTE: case ITEM_ENABLE_VELOCITY: case ITEM_ENABLE_LENGTH: case ITEM_ENABLE_CC: { u8 flag = ui_selected_item - ITEM_ENABLE_ONE_SHOT; u8 mask = 1 << flag; u8 value = SEQ_CC_Get(visible_track, SEQ_CC_LFO_ENABLE_FLAGS); if( incrementer == 0 ) // toggle SEQ_UI_CC_SetFlags(SEQ_CC_LFO_ENABLE_FLAGS, mask, value ^ mask); else if( incrementer > 0 ) SEQ_UI_CC_SetFlags(SEQ_CC_LFO_ENABLE_FLAGS, mask, mask); else SEQ_UI_CC_SetFlags(SEQ_CC_LFO_ENABLE_FLAGS, mask, 0); } break; case ITEM_CC: { // CC number selection now has to be confirmed with GP button s32 status = SEQ_UI_Var8_Inc(&edit_cc_number, 0, 127, incrementer); mios32_midi_port_t port = SEQ_CC_Get(visible_track, SEQ_CC_MIDI_PORT); u8 loopback = port == 0xf0; if( !edit_cc_number ) { SEQ_UI_Msg(SEQ_UI_MSG_USER_R, 1000, "LFO CC", "disabled"); } else { SEQ_UI_Msg(SEQ_UI_MSG_USER_R, 1000, loopback ? "Loopback CC" : "Controller:", (char *)SEQ_CC_LABELS_Get(port, edit_cc_number)); } return status; } break; case ITEM_CC_OFFSET: return SEQ_UI_CC_Inc(SEQ_CC_LFO_CC_OFFSET, 0, 127, incrementer); case ITEM_CC_PPQN: return SEQ_UI_CC_Inc(SEQ_CC_LFO_CC_PPQN, 0, 8, incrementer); } return -1; // invalid or unsupported encoder }