mirror of
https://github.com/Next-Flip/Momentum-Firmware.git
synced 2026-04-25 03:29:58 -07:00
410 lines
10 KiB
C
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);
|
|
}
|
|
} |