From ac5943c83dfee8ba772a25db634dce3644b5b3c2 Mon Sep 17 00:00:00 2001 From: LTVA1 <87536432+LTVA1@users.noreply.github.com> Date: Sat, 8 Apr 2023 16:43:44 +0300 Subject: [PATCH] add ability to save/load instruments in separate .fzi files (not tested properly yet!) --- diskop.c | 60 +++++++++++++++++++++++ diskop.h | 4 +- flizzer_tracker.c | 42 +++++++++++++++- flizzer_tracker.h | 9 ++++ init_deinit.c | 33 +++++++++++++ input_event.c | 72 +++++++++++++++++++++++++++- input_event.h | 3 ++ tracker_engine/diskop.c | 6 ++- tracker_engine/diskop.h | 4 +- tracker_engine/tracker_engine_defs.h | 2 + 10 files changed, 226 insertions(+), 9 deletions(-) diff --git a/diskop.c b/diskop.c index 6e905e4..21e5a1d 100644 --- a/diskop.c +++ b/diskop.c @@ -64,6 +64,32 @@ void save_instrument_inner(Stream* stream, Instrument* inst) { UNUSED(rwops); } +bool save_instrument(FlizzerTrackerApp* tracker, FuriString* filepath) +{ + bool file_removed = + storage_simply_remove(tracker->storage, furi_string_get_cstr(filepath)); // just in case + bool open_file = file_stream_open( + tracker->stream, furi_string_get_cstr(filepath), FSAM_WRITE, FSOM_OPEN_ALWAYS); + + uint8_t version = TRACKER_ENGINE_VERSION; + size_t rwops = + stream_write(tracker->stream, (uint8_t*)INST_FILE_SIG, sizeof(INST_FILE_SIG) - 1); + rwops = stream_write(tracker->stream, (uint8_t*)&version, sizeof(uint8_t)); + + Instrument* inst = tracker->song.instrument[tracker->current_instrument]; + + save_instrument_inner(tracker->stream, inst); + + file_stream_close(tracker->stream); + tracker->is_saving_instrument = false; + furi_string_free(filepath); + + UNUSED(file_removed); + UNUSED(open_file); + UNUSED(rwops); + return false; +} + bool save_song(FlizzerTrackerApp* tracker, FuriString* filepath) { bool file_removed = storage_simply_remove(tracker->storage, furi_string_get_cstr(filepath)); // just in case @@ -141,6 +167,40 @@ bool load_song_util(FlizzerTrackerApp* tracker, FuriString* filepath) { return result; } +bool load_instrument_disk(TrackerSong* song, uint8_t inst, Stream* stream) { + char header[sizeof(INST_FILE_SIG) + 2] = {0}; + size_t rwops = stream_read(stream, (uint8_t*)&header, sizeof(INST_FILE_SIG) - 1); + header[sizeof(INST_FILE_SIG)] = '\0'; + + uint8_t version = 0; + + if(strcmp(header, INST_FILE_SIG) == 0) { + rwops = stream_read(stream, (uint8_t*)&version, sizeof(version)); + + if(version <= TRACKER_ENGINE_VERSION) + { + load_instrument_inner(stream, song->instrument[inst], version); + } + } + + UNUSED(rwops); + return false; +} + +bool load_instrument_util(FlizzerTrackerApp* tracker, FuriString* filepath) +{ + bool open_file = file_stream_open( + tracker->stream, furi_string_get_cstr(filepath), FSAM_READ, FSOM_OPEN_ALWAYS); + + bool result = load_instrument_disk(&tracker->song, tracker->current_instrument, tracker->stream); + + tracker->is_loading_instrument = false; + file_stream_close(tracker->stream); + furi_string_free(filepath); + UNUSED(open_file); + return result; +} + void save_config(FlizzerTrackerApp* tracker) { // stream_read_line FuriString* filepath = furi_string_alloc(); diff --git a/diskop.h b/diskop.h index ce585ad..ed8b52a 100644 --- a/diskop.h +++ b/diskop.h @@ -3,11 +3,11 @@ #include "flizzer_tracker.h" #include "tracker_engine/diskop.h" -#define INST_FILE_SIG "FZT!INST" - bool save_song(FlizzerTrackerApp* tracker, FuriString* filepath); +bool save_instrument(FlizzerTrackerApp* tracker, FuriString* filepath); bool load_song_util(FlizzerTrackerApp* tracker, FuriString* filepath); +bool load_instrument_util(FlizzerTrackerApp* tracker, FuriString* filepath); void save_config(FlizzerTrackerApp* tracker); void load_config(FlizzerTrackerApp* tracker); \ No newline at end of file diff --git a/flizzer_tracker.c b/flizzer_tracker.c index cab745d..e47424b 100644 --- a/flizzer_tracker.c +++ b/flizzer_tracker.c @@ -15,12 +15,12 @@ void draw_callback(Canvas* canvas, void* ctx) { canvas_set_color(canvas, ColorXOR); - if(tracker->is_loading) { + if(tracker->is_loading || tracker->is_loading_instrument) { canvas_draw_str(canvas, 10, 10, "Loading..."); return; } - if(tracker->is_saving) { + if(tracker->is_saving || tracker->is_saving_instrument) { canvas_draw_str(canvas, 10, 10, "Saving..."); return; } @@ -95,6 +95,7 @@ int32_t flizzer_tracker_app(void* p) { Storage* storage = furi_record_open(RECORD_STORAGE); bool st = storage_simply_mkdir(storage, APPSDATA_FOLDER); st = storage_simply_mkdir(storage, FLIZZER_TRACKER_FOLDER); + st = storage_simply_mkdir(storage, FLIZZER_TRACKER_INSTRUMENTS_FOLDER); UNUSED(st); furi_record_close(RECORD_STORAGE); @@ -121,6 +122,10 @@ int32_t flizzer_tracker_app(void* p) { save_song(tracker, tracker->filepath); } + if(event.type == EventTypeSaveInstrument) { + save_instrument(tracker, tracker->filepath); + } + if(event.type == EventTypeLoadSong) { stop_song(tracker); @@ -157,6 +162,39 @@ int32_t flizzer_tracker_app(void* p) { } } + if(event.type == EventTypeLoadInstrument) { + stop_song(tracker); + + tracker->dialogs = furi_record_open(RECORD_DIALOGS); + tracker->is_loading_instrument = true; + + FuriString* path; + path = furi_string_alloc(); + furi_string_set(path, FLIZZER_TRACKER_INSTRUMENTS_FOLDER); + + DialogsFileBrowserOptions browser_options; + dialog_file_browser_set_basic_options( + &browser_options, INST_FILE_EXT, &I_flizzer_tracker_instrument); + browser_options.base_path = FLIZZER_TRACKER_FOLDER; + browser_options.hide_ext = false; + + bool ret = dialog_file_browser_show(tracker->dialogs, path, path, &browser_options); + + furi_record_close(RECORD_DIALOGS); + + const char* cpath = furi_string_get_cstr(path); + + if(ret && strcmp(&cpath[strlen(cpath) - 4], INST_FILE_EXT) == 0) { + bool result = load_instrument_util(tracker, path); + UNUSED(result); + } + + else { + furi_string_free(path); + tracker->is_loading = false; + } + } + if(event.type == EventTypeSetAudioMode) { sound_engine_PWM_timer_init(tracker->external_audio); diff --git a/flizzer_tracker.h b/flizzer_tracker.h index 2c85034..ab473a2 100644 --- a/flizzer_tracker.h +++ b/flizzer_tracker.h @@ -24,12 +24,15 @@ #define APPSDATA_FOLDER "/ext/apps_data" #define FLIZZER_TRACKER_FOLDER "/ext/apps_data/flizzer_tracker" +#define FLIZZER_TRACKER_INSTRUMENTS_FOLDER "/ext/apps_data/flizzer_tracker/instruments" #define FILE_NAME_LEN 64 typedef enum { EventTypeInput, EventTypeSaveSong, EventTypeLoadSong, + EventTypeLoadInstrument, + EventTypeSaveInstrument, EventTypeSetAudioMode, } EventType; @@ -132,6 +135,7 @@ typedef enum { VIEW_SUBMENU_PATTERN, VIEW_SUBMENU_INSTRUMENT, VIEW_FILE_OVERWRITE, + VIEW_INSTRUMENT_FILE_OVERWRITE, VIEW_SETTINGS, } FlizzerTrackerViews; @@ -144,6 +148,8 @@ typedef enum { } PatternSubmenuParams; typedef enum { + SUBMENU_INSTRUMENT_LOAD, + SUBMENU_INSTRUMENT_SAVE, SUBMENU_INSTRUMENT_EXIT, } InstrumentSubmenuParams; @@ -162,6 +168,7 @@ typedef struct { Submenu* instrument_submenu; VariableItemList* settings_list; Widget* overwrite_file_widget; + Widget* overwrite_instrument_file_widget; char filename[FILE_NAME_LEN + 1]; bool was_it_back_keypress; uint32_t current_time; @@ -187,6 +194,8 @@ typedef struct { bool is_loading; bool is_saving; + bool is_loading_instrument; + bool is_saving_instrument; bool showing_help; bool quit; diff --git a/init_deinit.c b/init_deinit.c index 58988e1..b0d52e8 100644 --- a/init_deinit.c +++ b/init_deinit.c @@ -107,6 +107,10 @@ FlizzerTrackerApp* init_tracker( submenu_add_item( tracker->pattern_submenu, "Exit", SUBMENU_PATTERN_EXIT, submenu_callback, tracker); + submenu_add_item( + tracker->instrument_submenu, "Load instrument", SUBMENU_INSTRUMENT_LOAD, submenu_callback, tracker); + submenu_add_item( + tracker->instrument_submenu, "Save instrument", SUBMENU_INSTRUMENT_SAVE, submenu_callback, tracker); submenu_add_item( tracker->instrument_submenu, "Exit", SUBMENU_INSTRUMENT_EXIT, submenu_callback, tracker); @@ -169,6 +173,34 @@ FlizzerTrackerApp* init_tracker( VIEW_FILE_OVERWRITE, widget_get_view(tracker->overwrite_file_widget)); + tracker->overwrite_instrument_file_widget = widget_alloc(); + + widget_add_button_element( + tracker->overwrite_instrument_file_widget, + GuiButtonTypeLeft, + "No", + (ButtonCallback)overwrite_instrument_file_widget_no_input_callback, + tracker); + widget_add_button_element( + tracker->overwrite_instrument_file_widget, + GuiButtonTypeRight, + "Yes", + (ButtonCallback)overwrite_instrument_file_widget_yes_input_callback, + tracker); + + widget_add_text_scroll_element( + tracker->overwrite_instrument_file_widget, + 0, + 0, + 128, + 64, + "This instrument file already\nexists, do you want to\noverwrite it?"); + + view_dispatcher_add_view( + tracker->view_dispatcher, + VIEW_INSTRUMENT_FILE_OVERWRITE, + widget_get_view(tracker->overwrite_instrument_file_widget)); + tracker->notification = furi_record_open(RECORD_NOTIFICATION); notification_message(tracker->notification, &sequence_display_backlight_enforce_on); @@ -199,6 +231,7 @@ void deinit_tracker(FlizzerTrackerApp* tracker) { submenu_free(tracker->instrument_submenu); widget_free(tracker->overwrite_file_widget); + widget_free(tracker->overwrite_instrument_file_widget); view_dispatcher_free(tracker->view_dispatcher); diff --git a/input_event.c b/input_event.c index 3958122..c29d0df 100644 --- a/input_event.c +++ b/input_event.c @@ -7,7 +7,7 @@ void return_from_keyboard_callback(void* ctx) { FlizzerTrackerApp* tracker = (FlizzerTrackerApp*)ctx; - if(!tracker->is_loading && !tracker->is_saving) { + if(!tracker->is_loading && !tracker->is_saving && !tracker->is_loading_instrument && !tracker->is_saving_instrument) { uint8_t string_length = 0; char* string = NULL; @@ -65,6 +65,24 @@ void return_from_keyboard_callback(void* ctx) { furi_message_queue_put(tracker->event_queue, &event, FuriWaitForever); } } + + if(tracker->is_saving_instrument) { + stop_song(tracker); + + tracker->filepath = furi_string_alloc(); + furi_string_cat_printf( + tracker->filepath, "%s/%s%s", FLIZZER_TRACKER_INSTRUMENTS_FOLDER, tracker->filename, INST_FILE_EXT); + + if(storage_file_exists(tracker->storage, furi_string_get_cstr(tracker->filepath))) { + view_dispatcher_switch_to_view(tracker->view_dispatcher, VIEW_INSTRUMENT_FILE_OVERWRITE); + return; + } + + else { + FlizzerTrackerEvent event = {.type = EventTypeSaveInstrument, .input = {{0}}, .period = 0}; + furi_message_queue_put(tracker->event_queue, &event, FuriWaitForever); + } + } } void overwrite_file_widget_yes_input_callback(GuiButtonType result, InputType type, void* ctx) { @@ -93,6 +111,32 @@ void overwrite_file_widget_no_input_callback(GuiButtonType result, InputType typ } } +void overwrite_instrument_file_widget_yes_input_callback(GuiButtonType result, InputType type, void* ctx) { + UNUSED(result); + + FlizzerTrackerApp* tracker = (FlizzerTrackerApp*)ctx; + + if(type == InputTypeShort) { + tracker->is_saving_instrument = true; + view_dispatcher_switch_to_view(tracker->view_dispatcher, VIEW_TRACKER); + // save_song(tracker, tracker->filepath); + static FlizzerTrackerEvent event = {.type = EventTypeSaveInstrument, .input = {{0}}, .period = 0}; + furi_message_queue_put(tracker->event_queue, &event, FuriWaitForever); + } +} + +void overwrite_instrument_file_widget_no_input_callback(GuiButtonType result, InputType type, void* ctx) { + UNUSED(result); + + FlizzerTrackerApp* tracker = (FlizzerTrackerApp*)ctx; + + if(type == InputTypeShort) { + tracker->is_saving_instrument = false; + furi_string_free(tracker->filepath); + view_dispatcher_switch_to_view(tracker->view_dispatcher, VIEW_TRACKER); + } +} + uint32_t submenu_settings_exit_callback(void* context) { UNUSED(context); return VIEW_SUBMENU_PATTERN; @@ -181,6 +225,30 @@ void submenu_callback(void* context, uint32_t index) { break; } + case SUBMENU_INSTRUMENT_SAVE: { + text_input_set_header_text(tracker->text_input, "Instrument filename:"); + memset(&tracker->filename, 0, FILE_NAME_LEN); + text_input_set_result_callback( + tracker->text_input, + return_from_keyboard_callback, + tracker, + (char*)&tracker->filename, + FILE_NAME_LEN, + true); + + tracker->is_saving_instrument = true; + + view_dispatcher_switch_to_view(tracker->view_dispatcher, VIEW_KEYBOARD); + break; + } + + case SUBMENU_INSTRUMENT_LOAD: { + FlizzerTrackerEvent event = {.type = EventTypeLoadInstrument, .input = {{0}}, .period = 0}; + furi_message_queue_put(tracker->event_queue, &event, FuriWaitForever); + view_dispatcher_switch_to_view(tracker->view_dispatcher, VIEW_TRACKER); + break; + } + default: break; } @@ -305,7 +373,7 @@ void process_input_event(FlizzerTrackerApp* tracker, FlizzerTrackerEvent* event) } case INST_EDITOR_VIEW: { - submenu_set_selected_item(tracker->instrument_submenu, SUBMENU_INSTRUMENT_EXIT); + submenu_set_selected_item(tracker->instrument_submenu, SUBMENU_INSTRUMENT_LOAD); view_dispatcher_switch_to_view(tracker->view_dispatcher, VIEW_SUBMENU_INSTRUMENT); break; } diff --git a/input_event.h b/input_event.h index a143aed..fa380dc 100644 --- a/input_event.h +++ b/input_event.h @@ -23,6 +23,9 @@ void return_from_keyboard_callback(void* ctx); void overwrite_file_widget_yes_input_callback(GuiButtonType result, InputType type, void* ctx); void overwrite_file_widget_no_input_callback(GuiButtonType result, InputType type, void* ctx); +void overwrite_instrument_file_widget_yes_input_callback(GuiButtonType result, InputType type, void* ctx); +void overwrite_instrument_file_widget_no_input_callback(GuiButtonType result, InputType type, void* ctx); + uint32_t submenu_exit_callback(void* context); uint32_t submenu_settings_exit_callback(void* context); void submenu_callback(void* context, uint32_t index); diff --git a/tracker_engine/diskop.c b/tracker_engine/diskop.c index 154ba35..46de567 100644 --- a/tracker_engine/diskop.c +++ b/tracker_engine/diskop.c @@ -1,6 +1,8 @@ #include "diskop.h" -void load_instrument_inner(Stream* stream, Instrument* inst) { +void load_instrument_inner(Stream* stream, Instrument* inst, uint8_t version) { + UNUSED(version); + size_t rwops = stream_read(stream, (uint8_t*)inst->name, sizeof(inst->name)); rwops = stream_read(stream, (uint8_t*)&inst->waveform, sizeof(inst->waveform)); rwops = stream_read(stream, (uint8_t*)&inst->flags, sizeof(inst->flags)); @@ -103,7 +105,7 @@ bool load_song_inner(TrackerSong* song, Stream* stream) { for(uint16_t i = 0; i < song->num_instruments; i++) { song->instrument[i] = (Instrument*)malloc(sizeof(Instrument)); set_default_instrument(song->instrument[i]); - load_instrument_inner(stream, song->instrument[i]); + load_instrument_inner(stream, song->instrument[i], version); } UNUSED(rwops); diff --git a/tracker_engine/diskop.h b/tracker_engine/diskop.h index e3dc99f..bed7c01 100644 --- a/tracker_engine/diskop.h +++ b/tracker_engine/diskop.h @@ -7,4 +7,6 @@ #include #include -bool load_song(TrackerSong* song, Stream* stream); \ No newline at end of file +bool load_song(TrackerSong* song, Stream* stream); +bool load_instrument(Instrument* inst, Stream* stream); +void load_instrument_inner(Stream* stream, Instrument* inst, uint8_t version); \ No newline at end of file diff --git a/tracker_engine/tracker_engine_defs.h b/tracker_engine/tracker_engine_defs.h index 9e7d531..ef92b1a 100644 --- a/tracker_engine/tracker_engine_defs.h +++ b/tracker_engine/tracker_engine_defs.h @@ -25,6 +25,8 @@ #define SONG_FILE_SIG "FZT!SONG" #define SONG_FILE_EXT ".fzt" +#define INST_FILE_SIG "FZT!INST" +#define INST_FILE_EXT ".fzi" #define TRACKER_ENGINE_VERSION 1