mirror of
https://github.com/Next-Flip/Momentum-Firmware.git
synced 2026-06-19 20:34:19 -07:00
zero tracker upd
This commit is contained in:
@@ -40,7 +40,7 @@ typedef struct {
|
||||
} UnpackedRow;
|
||||
|
||||
struct Tracker {
|
||||
Song* song;
|
||||
const Song* song;
|
||||
bool playing;
|
||||
TrackerMessageCallback callback;
|
||||
void* context;
|
||||
@@ -126,9 +126,9 @@ static float frequency_get_seventh_of_a_semitone(float frequency) {
|
||||
return frequency * ((1.0f / 12.0f) / 7.0f);
|
||||
}
|
||||
|
||||
static UnpackedRow get_current_row(Song* song, SongState* song_state, uint8_t channel) {
|
||||
Pattern* pattern = &song->patterns[song_state->pattern_index];
|
||||
Row row = pattern->channels[channel].rows[song_state->row_index];
|
||||
static UnpackedRow get_current_row(const Song* song, SongState* song_state, uint8_t channel) {
|
||||
const Pattern* pattern = &song->patterns[song_state->pattern_index];
|
||||
const Row row = pattern->channels[channel].rows[song_state->row_index];
|
||||
return (UnpackedRow){
|
||||
.note = record_get_note(row),
|
||||
.effect = record_get_effect(row),
|
||||
@@ -136,7 +136,7 @@ static UnpackedRow get_current_row(Song* song, SongState* song_state, uint8_t ch
|
||||
};
|
||||
}
|
||||
|
||||
static int16_t advance_order_and_get_next_pattern_index(Song* song, SongState* song_state) {
|
||||
static int16_t advance_order_and_get_next_pattern_index(const Song* song, SongState* song_state) {
|
||||
song_state->order_list_index++;
|
||||
if(song_state->order_list_index >= song->order_list_size) {
|
||||
return -1;
|
||||
@@ -205,7 +205,7 @@ static void tracker_interrupt_body(Tracker* tracker) {
|
||||
const uint8_t channel_index = 0;
|
||||
SongState* song_state = &tracker->song_state;
|
||||
ChannelState* channel_state = &song_state->channels[channel_index];
|
||||
Song* song = tracker->song;
|
||||
const Song* song = tracker->song;
|
||||
UnpackedRow row = get_current_row(song, song_state, channel_index);
|
||||
|
||||
// load frequency from note at tick 0
|
||||
@@ -403,7 +403,7 @@ void tracker_set_message_callback(Tracker* tracker, TrackerMessageCallback callb
|
||||
tracker->context = context;
|
||||
}
|
||||
|
||||
void tracker_set_song(Tracker* tracker, Song* song) {
|
||||
void tracker_set_song(Tracker* tracker, const Song* song) {
|
||||
furi_check(tracker->playing == false);
|
||||
tracker->song = song;
|
||||
tracker_song_state_init(tracker);
|
||||
|
||||
@@ -27,7 +27,7 @@ void tracker_free(Tracker* tracker);
|
||||
|
||||
void tracker_set_message_callback(Tracker* tracker, TrackerMessageCallback callback, void* context);
|
||||
|
||||
void tracker_set_song(Tracker* tracker, Song* song);
|
||||
void tracker_set_song(Tracker* tracker, const Song* song);
|
||||
|
||||
void tracker_set_order_index(Tracker* tracker, uint8_t order_index);
|
||||
|
||||
|
||||
@@ -0,0 +1,182 @@
|
||||
#include "tracker_view.h"
|
||||
#include <gui/elements.h>
|
||||
#include <furi.h>
|
||||
|
||||
typedef struct {
|
||||
const Song* song;
|
||||
uint8_t order_list_index;
|
||||
uint8_t row;
|
||||
} TrackerViewModel;
|
||||
|
||||
struct TrackerView {
|
||||
View* view;
|
||||
void* back_context;
|
||||
TrackerViewCallback back_callback;
|
||||
};
|
||||
|
||||
static Channel* get_current_channel(TrackerViewModel* model) {
|
||||
uint8_t channel_id = 0;
|
||||
uint8_t pattern_id = model->song->order_list[model->order_list_index];
|
||||
Pattern* pattern = &model->song->patterns[pattern_id];
|
||||
return &pattern->channels[channel_id];
|
||||
}
|
||||
|
||||
static const char* get_note_from_id(uint8_t note) {
|
||||
#define NOTE_COUNT 12
|
||||
const char* notes[NOTE_COUNT] = {
|
||||
"C ",
|
||||
"C#",
|
||||
"D ",
|
||||
"D#",
|
||||
"E ",
|
||||
"F ",
|
||||
"F#",
|
||||
"G ",
|
||||
"G#",
|
||||
"A ",
|
||||
"A#",
|
||||
"B ",
|
||||
};
|
||||
return notes[(note) % NOTE_COUNT];
|
||||
#undef NOTE_COUNT
|
||||
}
|
||||
|
||||
static uint8_t get_octave_from_id(uint8_t note) {
|
||||
return ((note) / 12) + 2;
|
||||
}
|
||||
|
||||
static uint8_t get_first_row_id(uint8_t row) {
|
||||
return (row / 10) * 10;
|
||||
}
|
||||
|
||||
static void
|
||||
draw_row(Canvas* canvas, uint8_t i, Channel* channel, uint8_t row, FuriString* buffer) {
|
||||
uint8_t x = 12 * (i + 1);
|
||||
uint8_t first_row_id = get_first_row_id(row);
|
||||
uint8_t current_row_id = first_row_id + i;
|
||||
|
||||
if((current_row_id) >= 64) {
|
||||
return;
|
||||
}
|
||||
|
||||
Row current_row = channel->rows[current_row_id];
|
||||
uint8_t note = current_row & ROW_NOTE_MASK;
|
||||
uint8_t effect = (current_row >> 6) & ROW_EFFECT_MASK;
|
||||
uint8_t data = (current_row >> 10) & ROW_EFFECT_DATA_MASK;
|
||||
|
||||
if(current_row_id == row) {
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
canvas_draw_line(canvas, x - 9, 1, x - 9, 62);
|
||||
canvas_draw_box(canvas, x - 8, 0, 9, 64);
|
||||
canvas_draw_line(canvas, x + 1, 1, x + 1, 62);
|
||||
canvas_set_color(canvas, ColorWhite);
|
||||
}
|
||||
|
||||
furi_string_printf(buffer, "%02X", current_row_id);
|
||||
canvas_draw_str(canvas, x, 61, furi_string_get_cstr(buffer));
|
||||
|
||||
if(note > 0 && note < NOTE_OFF) {
|
||||
furi_string_printf(
|
||||
buffer, "%s%d", get_note_from_id(note - 1), get_octave_from_id(note - 1));
|
||||
canvas_draw_str(canvas, x, 44, furi_string_get_cstr(buffer));
|
||||
} else if(note == NOTE_OFF) {
|
||||
canvas_draw_str(canvas, x, 44, "OFF");
|
||||
} else {
|
||||
canvas_draw_str(canvas, x, 44, "---");
|
||||
}
|
||||
|
||||
if(effect == 0 && data == 0) {
|
||||
canvas_draw_str(canvas, x, 21, "-");
|
||||
canvas_draw_str(canvas, x, 12, "--");
|
||||
} else {
|
||||
furi_string_printf(buffer, "%X", effect);
|
||||
canvas_draw_str(canvas, x, 21, furi_string_get_cstr(buffer));
|
||||
|
||||
if(effect == EffectArpeggio || effect == EffectVibrato) {
|
||||
uint8_t data_x = EFFECT_DATA_GET_X(data);
|
||||
uint8_t data_y = EFFECT_DATA_GET_Y(data);
|
||||
furi_string_printf(buffer, "%d%d", data_x, data_y);
|
||||
canvas_draw_str(canvas, x, 12, furi_string_get_cstr(buffer));
|
||||
} else {
|
||||
furi_string_printf(buffer, "%02X", data);
|
||||
canvas_draw_str(canvas, x, 12, furi_string_get_cstr(buffer));
|
||||
}
|
||||
}
|
||||
|
||||
if(current_row_id == row) {
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
}
|
||||
}
|
||||
|
||||
static void tracker_view_draw_callback(Canvas* canvas, void* _model) {
|
||||
TrackerViewModel* model = _model;
|
||||
if(model->song == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
canvas_set_font_direction(canvas, CanvasDirectionBottomToTop);
|
||||
canvas_set_font(canvas, FontKeyboard);
|
||||
|
||||
Channel* channel = get_current_channel(model);
|
||||
FuriString* buffer = furi_string_alloc();
|
||||
|
||||
for(uint8_t i = 0; i < 10; i++) {
|
||||
draw_row(canvas, i, channel, model->row, buffer);
|
||||
}
|
||||
furi_string_free(buffer);
|
||||
}
|
||||
|
||||
static bool tracker_view_input_callback(InputEvent* event, void* context) {
|
||||
TrackerView* tracker_view = context;
|
||||
|
||||
if(tracker_view->back_callback) {
|
||||
if(event->type == InputTypeShort && event->key == InputKeyBack) {
|
||||
tracker_view->back_callback(tracker_view->back_context);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
TrackerView* tracker_view_alloc() {
|
||||
TrackerView* tracker_view = malloc(sizeof(TrackerView));
|
||||
tracker_view->view = view_alloc();
|
||||
view_allocate_model(tracker_view->view, ViewModelTypeLocking, sizeof(TrackerViewModel));
|
||||
view_set_context(tracker_view->view, tracker_view);
|
||||
view_set_draw_callback(tracker_view->view, (ViewDrawCallback)tracker_view_draw_callback);
|
||||
view_set_input_callback(tracker_view->view, (ViewInputCallback)tracker_view_input_callback);
|
||||
return tracker_view;
|
||||
}
|
||||
|
||||
void tracker_view_free(TrackerView* tracker_view) {
|
||||
view_free(tracker_view->view);
|
||||
free(tracker_view);
|
||||
}
|
||||
|
||||
View* tracker_view_get_view(TrackerView* tracker_view) {
|
||||
return tracker_view->view;
|
||||
}
|
||||
|
||||
void tracker_view_set_back_callback(
|
||||
TrackerView* tracker_view,
|
||||
TrackerViewCallback callback,
|
||||
void* context) {
|
||||
tracker_view->back_callback = callback;
|
||||
tracker_view->back_context = context;
|
||||
}
|
||||
|
||||
void tracker_view_set_song(TrackerView* tracker_view, const Song* song) {
|
||||
with_view_model(
|
||||
tracker_view->view, TrackerViewModel * model, { model->song = song; }, true);
|
||||
}
|
||||
|
||||
void tracker_view_set_position(TrackerView* tracker_view, uint8_t order_list_index, uint8_t row) {
|
||||
with_view_model(
|
||||
tracker_view->view,
|
||||
TrackerViewModel * model,
|
||||
{
|
||||
model->order_list_index = order_list_index;
|
||||
model->row = row;
|
||||
},
|
||||
true);
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
#include <gui/view.h>
|
||||
#include "../tracker_engine/tracker.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct TrackerView TrackerView;
|
||||
|
||||
TrackerView* tracker_view_alloc();
|
||||
|
||||
void tracker_view_free(TrackerView* tracker_view);
|
||||
|
||||
View* tracker_view_get_view(TrackerView* tracker_view);
|
||||
|
||||
typedef void (*TrackerViewCallback)(void* context);
|
||||
|
||||
void tracker_view_set_back_callback(
|
||||
TrackerView* tracker_view,
|
||||
TrackerViewCallback callback,
|
||||
void* context);
|
||||
|
||||
void tracker_view_set_song(TrackerView* tracker_view, const Song* song);
|
||||
|
||||
void tracker_view_set_position(TrackerView* tracker_view, uint8_t order_list_index, uint8_t row);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -1,6 +1,10 @@
|
||||
#include <furi.h>
|
||||
#include <gui/gui.h>
|
||||
#include <gui/view_dispatcher.h>
|
||||
#include <notification/notification_messages.h>
|
||||
#include "zero_tracker.h"
|
||||
#include "tracker_engine/tracker.h"
|
||||
#include "view/tracker_view.h"
|
||||
|
||||
// Channel p_0_channels[] = {
|
||||
// {
|
||||
@@ -479,6 +483,17 @@ void tracker_message(TrackerMessage message, void* context) {
|
||||
int32_t zero_tracker_app(void* p) {
|
||||
UNUSED(p);
|
||||
|
||||
NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION);
|
||||
notification_message(notification, &sequence_display_backlight_enforce_on);
|
||||
|
||||
Gui* gui = furi_record_open(RECORD_GUI);
|
||||
ViewDispatcher* view_dispatcher = view_dispatcher_alloc();
|
||||
TrackerView* tracker_view = tracker_view_alloc();
|
||||
tracker_view_set_song(tracker_view, &song);
|
||||
view_dispatcher_add_view(view_dispatcher, 0, tracker_view_get_view(tracker_view));
|
||||
view_dispatcher_attach_to_gui(view_dispatcher, gui, ViewDispatcherTypeFullscreen);
|
||||
view_dispatcher_switch_to_view(view_dispatcher, 0);
|
||||
|
||||
FuriMessageQueue* queue = furi_message_queue_alloc(8, sizeof(TrackerMessage));
|
||||
Tracker* tracker = tracker_alloc();
|
||||
tracker_set_message_callback(tracker, tracker_message, queue);
|
||||
@@ -493,6 +508,7 @@ int32_t zero_tracker_app(void* p) {
|
||||
uint8_t order_list_index = message.data.position.order_list_index;
|
||||
uint8_t row = message.data.position.row;
|
||||
uint8_t pattern = song.order_list[order_list_index];
|
||||
tracker_view_set_position(tracker_view, order_list_index, row);
|
||||
FURI_LOG_I("Tracker", "O:%d P:%d R:%d", order_list_index, pattern, row);
|
||||
} else if(message.type == TrackerEndOfSong) {
|
||||
FURI_LOG_I("Tracker", "End of song");
|
||||
@@ -505,5 +521,14 @@ int32_t zero_tracker_app(void* p) {
|
||||
tracker_free(tracker);
|
||||
furi_message_queue_free(queue);
|
||||
|
||||
view_dispatcher_remove_view(view_dispatcher, 0);
|
||||
tracker_view_free(tracker_view);
|
||||
view_dispatcher_free(view_dispatcher);
|
||||
|
||||
notification_message(notification, &sequence_display_backlight_enforce_auto);
|
||||
|
||||
furi_record_close(RECORD_NOTIFICATION);
|
||||
furi_record_close(RECORD_GUI);
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user