Files
Momentum-Firmware/applications/external/flizzer_tracker/input/pattern.c
2023-06-17 22:12:41 +01:00

410 lines
10 KiB
C

#include "pattern.h"
uint8_t get_field(uint8_t patternx) {
uint8_t field = 0;
if(patternx <= 1) field = 0;
if(patternx == 2) field = 1;
if(patternx == 3) field = 2;
if(patternx > 3) field = 3;
return field;
}
void edit_note(
FlizzerTrackerApp* tracker,
TrackerSongPatternStep* step,
int8_t delta) // here we need data about last note if we place a new note
{
int16_t note = tracker_engine_get_note(step);
if(note == MUS_NOTE_RELEASE) {
if(delta < 0) {
set_note(step, MUS_NOTE_CUT);
}
return;
}
if(note == MUS_NOTE_CUT) {
if(delta > 0) {
set_note(step, MUS_NOTE_RELEASE);
}
return;
}
if(note == MUS_NOTE_NONE) {
note =
tracker->current_note; // remember which note we entered earlier and use it as reference
}
clamp(note, delta, 0, MAX_NOTE);
set_note(step, (uint8_t)note);
set_instrument(step, tracker->current_instrument);
tracker->current_note = (uint8_t)note;
}
void edit_instrument(FlizzerTrackerApp* tracker, TrackerSongPatternStep* step, int8_t delta) {
int16_t inst = tracker_engine_get_instrument(step);
if(inst == MUS_NOTE_INSTRUMENT_NONE) {
if(delta > 0) {
inst = tracker->current_instrument;
}
else {
inst = MUS_NOTE_INSTRUMENT_NONE - 1;
}
}
clamp(inst, delta, 0, tracker->song.num_instruments - 1);
tracker->current_instrument = inst; // remember last instrument
set_instrument(step, (uint8_t)inst);
}
void edit_volume(FlizzerTrackerApp* tracker, TrackerSongPatternStep* step, int8_t delta) {
int16_t vol = tracker_engine_get_volume(step);
vol = tracker->current_volume;
if(vol + delta < 0) {
vol = MUS_NOTE_VOLUME_NONE - 1 - delta;
}
if(vol + delta >= MUS_NOTE_VOLUME_NONE) {
vol = 0 - delta;
}
clamp(vol, delta, 0, MUS_NOTE_VOLUME_NONE - 1);
set_volume(step, (uint8_t)vol);
tracker->current_volume = vol;
}
void edit_command(TrackerSongPatternStep* step, uint8_t digit, int8_t delta) {
int32_t command = tracker_engine_get_command(step);
switch(digit) {
case 0: // upper 7 bits
{
int16_t fx_name = ((command & 0x7f00) >> 8);
if(fx_name + delta > 35) // loop
{ // 0-9 and then A-Z
fx_name = 0;
}
else if(fx_name + delta < 0) {
fx_name = 35;
}
else {
fx_name += delta;
}
command &= 0x00ff;
command |= (fx_name << 8);
set_command(step, (uint16_t)command);
break;
}
case 1: // upper digit of command param
{
int8_t upper_digit = ((command & 0x00f0) >> 4);
if(upper_digit + delta > 0xf) // loop
{
upper_digit = 0;
}
else if(upper_digit + delta < 0) {
upper_digit = 0xf;
}
else {
upper_digit += delta;
}
command &= 0xff0f;
command |= (upper_digit << 4);
set_command(step, (uint16_t)command);
break;
}
case 2: // lower digit of command param
{
int8_t lower_digit = (command & 0x000f);
if(lower_digit + delta > 0xf) // loop
{
lower_digit = 0;
}
else if(lower_digit + delta < 0) {
lower_digit = 0xf;
}
else {
lower_digit += delta;
}
command &= 0xfff0;
command |= lower_digit;
set_command(step, (uint16_t)command);
break;
}
default:
break;
}
}
void delete_field(TrackerSongPatternStep* step, uint8_t field) {
switch(field) {
case 0: // note
{
set_note(step, MUS_NOTE_NONE);
set_instrument(step, MUS_NOTE_INSTRUMENT_NONE); // also delete instrument
break;
}
case 1: // instrument
{
set_instrument(step, MUS_NOTE_INSTRUMENT_NONE);
break;
}
case 2: // volume
{
set_volume(step, MUS_NOTE_VOLUME_NONE);
break;
}
case 3: // command
{
set_command(step, 0);
break;
}
default:
break;
}
}
void edit_pattern_step(FlizzerTrackerApp* tracker, TrackerSongPatternStep* step, int8_t delta) {
switch(get_field(tracker->patternx)) {
case 0: // note
{
if(tracker->patternx) // editing octave
{
edit_note(tracker, step, 12 * delta);
}
else // editing note
{
edit_note(tracker, step, delta);
}
break;
}
case 1: // instrument
{
edit_instrument(tracker, step, delta);
break;
}
case 2: // volume
{
edit_volume(tracker, step, delta);
break;
}
case 3: // command
{
uint8_t digit = 0;
if(tracker->patternx == 4) digit = 0;
if(tracker->patternx == 5) digit = 1;
if(tracker->patternx == 6) digit = 2;
edit_command(step, digit, delta);
break;
}
default:
break;
}
}
void pattern_edit_event(FlizzerTrackerApp* tracker, FlizzerTrackerEvent* event) {
if(event->input.key == InputKeyLeft && event->input.type == InputTypeLong &&
!(tracker->editing)) {
flipbit(
tracker->tracker_engine.channel[tracker->current_channel].channel_flags, TEC_DISABLED);
return;
}
if(event->input.key == InputKeyDown && event->input.type == InputTypeLong &&
!(tracker->editing)) {
tracker->tracker_engine.pattern_position =
tracker->tracker_engine.song->pattern_length - 1; // go to pattern last row
return;
}
if(event->input.key == InputKeyUp && event->input.type == InputTypeLong &&
!(tracker->editing)) {
tracker->tracker_engine.pattern_position = 0; // return to pattern 1st row
return;
}
uint8_t sequence_position = tracker->tracker_engine.sequence_position;
uint8_t current_pattern =
tracker->tracker_engine.song->sequence.sequence_step[sequence_position]
.pattern_indices[tracker->current_channel];
uint16_t pattern_step = tracker->tracker_engine.pattern_position;
uint16_t pattern_length = tracker->tracker_engine.song->pattern_length;
TrackerSongPattern* pattern = &tracker->tracker_engine.song->pattern[current_pattern];
TrackerSongPatternStep* step = NULL;
if(pattern_step < pattern_length) {
step = &pattern->step[pattern_step];
}
if(!(step)) return;
if(event->input.key == InputKeyOk && event->input.type == InputTypeShort &&
!tracker->tracker_engine.playing) {
tracker->editing = !tracker->editing;
if(tracker->editing) {
// stop_song(tracker);
}
}
if(event->input.key == InputKeyOk && event->input.type == InputTypeLong) {
if(!(tracker->editing)) {
if(tracker->tracker_engine.playing) {
stop_song(tracker);
}
else {
if(tracker->tracker_engine.pattern_position == tracker->song.pattern_length - 1 &&
tracker->tracker_engine.sequence_position ==
tracker->song.num_sequence_steps -
1) // if we are at the very end of the song
{
stop_song(tracker);
}
else {
play_song(tracker, true);
}
}
}
else {
if(get_field(tracker->patternx) == 0) {
set_note(step, MUS_NOTE_RELEASE);
}
}
}
if(event->input.key == InputKeyRight && event->input.type == InputTypeShort) {
tracker->patternx++;
if(tracker->patternx > MAX_PATTERNX - 1) {
tracker->current_channel++;
tracker->patternx = 0;
if(tracker->current_channel > SONG_MAX_CHANNELS - 1) {
tracker->current_channel = 0;
}
}
}
if(event->input.key == InputKeyLeft && event->input.type == InputTypeShort) {
tracker->patternx--;
if(tracker->patternx > MAX_PATTERNX - 1) // unsigned int overflow
{
tracker->current_channel--;
tracker->patternx = MAX_PATTERNX - 1;
if(tracker->current_channel > SONG_MAX_CHANNELS - 1) // unsigned int overflow
{
tracker->current_channel = SONG_MAX_CHANNELS - 1;
}
}
}
if(event->input.key == InputKeyDown && event->input.type == InputTypeShort) {
if(!(tracker->editing)) {
tracker->tracker_engine.pattern_position++;
if(tracker->tracker_engine.pattern_position >
tracker->tracker_engine.song->pattern_length - 1 &&
tracker->tracker_engine.sequence_position <
tracker->tracker_engine.song->num_sequence_steps - 1) {
tracker->tracker_engine.pattern_position = 0;
tracker->tracker_engine.sequence_position++;
}
else if(
tracker->tracker_engine.pattern_position >
tracker->tracker_engine.song->pattern_length - 1) {
tracker->tracker_engine.pattern_position =
tracker->tracker_engine.song->pattern_length - 1;
}
}
if(tracker->editing) {
edit_pattern_step(tracker, step, -1);
}
}
if(event->input.key == InputKeyUp && event->input.type == InputTypeShort) {
if(!(tracker->editing)) {
int16_t temp_pattern_position = tracker->tracker_engine.pattern_position - 1;
if(temp_pattern_position < 0) {
if(tracker->tracker_engine.sequence_position > 0) {
tracker->tracker_engine.sequence_position--;
tracker->tracker_engine.pattern_position =
tracker->tracker_engine.song->pattern_length - 1;
}
}
else {
tracker->tracker_engine.pattern_position--;
}
}
if(tracker->editing) {
edit_pattern_step(tracker, step, 1);
}
}
if(event->input.key == InputKeyBack && event->input.type == InputTypeShort &&
tracker->editing) {
uint8_t field = get_field(tracker->patternx);
delete_field(step, field);
}
}