Просмотр исходного кода

add ability to save/load instruments in separate .fzi files (not tested properly yet!)

LTVA1 2 лет назад
Родитель
Сommit
ac5943c83d
10 измененных файлов с 226 добавлено и 9 удалено
  1. 60 0
      diskop.c
  2. 2 2
      diskop.h
  3. 40 2
      flizzer_tracker.c
  4. 9 0
      flizzer_tracker.h
  5. 33 0
      init_deinit.c
  6. 70 2
      input_event.c
  7. 3 0
      input_event.h
  8. 4 2
      tracker_engine/diskop.c
  9. 3 1
      tracker_engine/diskop.h
  10. 2 0
      tracker_engine/tracker_engine_defs.h

+ 60 - 0
diskop.c

@@ -64,6 +64,32 @@ void save_instrument_inner(Stream* stream, Instrument* inst) {
     UNUSED(rwops);
     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 save_song(FlizzerTrackerApp* tracker, FuriString* filepath) {
     bool file_removed =
     bool file_removed =
         storage_simply_remove(tracker->storage, furi_string_get_cstr(filepath)); // just in case
         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;
     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) {
 void save_config(FlizzerTrackerApp* tracker) {
     // stream_read_line
     // stream_read_line
     FuriString* filepath = furi_string_alloc();
     FuriString* filepath = furi_string_alloc();

+ 2 - 2
diskop.h

@@ -3,11 +3,11 @@
 #include "flizzer_tracker.h"
 #include "flizzer_tracker.h"
 #include "tracker_engine/diskop.h"
 #include "tracker_engine/diskop.h"
 
 
-#define INST_FILE_SIG "FZT!INST"
-
 bool save_song(FlizzerTrackerApp* tracker, FuriString* filepath);
 bool save_song(FlizzerTrackerApp* tracker, FuriString* filepath);
+bool save_instrument(FlizzerTrackerApp* tracker, FuriString* filepath);
 
 
 bool load_song_util(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 save_config(FlizzerTrackerApp* tracker);
 void load_config(FlizzerTrackerApp* tracker);
 void load_config(FlizzerTrackerApp* tracker);

+ 40 - 2
flizzer_tracker.c

@@ -15,12 +15,12 @@ void draw_callback(Canvas* canvas, void* ctx) {
 
 
     canvas_set_color(canvas, ColorXOR);
     canvas_set_color(canvas, ColorXOR);
 
 
-    if(tracker->is_loading) {
+    if(tracker->is_loading || tracker->is_loading_instrument) {
         canvas_draw_str(canvas, 10, 10, "Loading...");
         canvas_draw_str(canvas, 10, 10, "Loading...");
         return;
         return;
     }
     }
 
 
-    if(tracker->is_saving) {
+    if(tracker->is_saving || tracker->is_saving_instrument) {
         canvas_draw_str(canvas, 10, 10, "Saving...");
         canvas_draw_str(canvas, 10, 10, "Saving...");
         return;
         return;
     }
     }
@@ -95,6 +95,7 @@ int32_t flizzer_tracker_app(void* p) {
     Storage* storage = furi_record_open(RECORD_STORAGE);
     Storage* storage = furi_record_open(RECORD_STORAGE);
     bool st = storage_simply_mkdir(storage, APPSDATA_FOLDER);
     bool st = storage_simply_mkdir(storage, APPSDATA_FOLDER);
     st = storage_simply_mkdir(storage, FLIZZER_TRACKER_FOLDER);
     st = storage_simply_mkdir(storage, FLIZZER_TRACKER_FOLDER);
+    st = storage_simply_mkdir(storage, FLIZZER_TRACKER_INSTRUMENTS_FOLDER);
     UNUSED(st);
     UNUSED(st);
     furi_record_close(RECORD_STORAGE);
     furi_record_close(RECORD_STORAGE);
 
 
@@ -121,6 +122,10 @@ int32_t flizzer_tracker_app(void* p) {
             save_song(tracker, tracker->filepath);
             save_song(tracker, tracker->filepath);
         }
         }
 
 
+        if(event.type == EventTypeSaveInstrument) {
+            save_instrument(tracker, tracker->filepath);
+        }
+
         if(event.type == EventTypeLoadSong) {
         if(event.type == EventTypeLoadSong) {
             stop_song(tracker);
             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) {
         if(event.type == EventTypeSetAudioMode) {
             sound_engine_PWM_timer_init(tracker->external_audio);
             sound_engine_PWM_timer_init(tracker->external_audio);
 
 

+ 9 - 0
flizzer_tracker.h

@@ -24,12 +24,15 @@
 
 
 #define APPSDATA_FOLDER "/ext/apps_data"
 #define APPSDATA_FOLDER "/ext/apps_data"
 #define FLIZZER_TRACKER_FOLDER "/ext/apps_data/flizzer_tracker"
 #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
 #define FILE_NAME_LEN 64
 
 
 typedef enum {
 typedef enum {
     EventTypeInput,
     EventTypeInput,
     EventTypeSaveSong,
     EventTypeSaveSong,
     EventTypeLoadSong,
     EventTypeLoadSong,
+    EventTypeLoadInstrument,
+    EventTypeSaveInstrument,
     EventTypeSetAudioMode,
     EventTypeSetAudioMode,
 } EventType;
 } EventType;
 
 
@@ -132,6 +135,7 @@ typedef enum {
     VIEW_SUBMENU_PATTERN,
     VIEW_SUBMENU_PATTERN,
     VIEW_SUBMENU_INSTRUMENT,
     VIEW_SUBMENU_INSTRUMENT,
     VIEW_FILE_OVERWRITE,
     VIEW_FILE_OVERWRITE,
+    VIEW_INSTRUMENT_FILE_OVERWRITE,
     VIEW_SETTINGS,
     VIEW_SETTINGS,
 } FlizzerTrackerViews;
 } FlizzerTrackerViews;
 
 
@@ -144,6 +148,8 @@ typedef enum {
 } PatternSubmenuParams;
 } PatternSubmenuParams;
 
 
 typedef enum {
 typedef enum {
+    SUBMENU_INSTRUMENT_LOAD,
+    SUBMENU_INSTRUMENT_SAVE,
     SUBMENU_INSTRUMENT_EXIT,
     SUBMENU_INSTRUMENT_EXIT,
 } InstrumentSubmenuParams;
 } InstrumentSubmenuParams;
 
 
@@ -162,6 +168,7 @@ typedef struct {
     Submenu* instrument_submenu;
     Submenu* instrument_submenu;
     VariableItemList* settings_list;
     VariableItemList* settings_list;
     Widget* overwrite_file_widget;
     Widget* overwrite_file_widget;
+    Widget* overwrite_instrument_file_widget;
     char filename[FILE_NAME_LEN + 1];
     char filename[FILE_NAME_LEN + 1];
     bool was_it_back_keypress;
     bool was_it_back_keypress;
     uint32_t current_time;
     uint32_t current_time;
@@ -187,6 +194,8 @@ typedef struct {
 
 
     bool is_loading;
     bool is_loading;
     bool is_saving;
     bool is_saving;
+    bool is_loading_instrument;
+    bool is_saving_instrument;
     bool showing_help;
     bool showing_help;
 
 
     bool quit;
     bool quit;

+ 33 - 0
init_deinit.c

@@ -107,6 +107,10 @@ FlizzerTrackerApp* init_tracker(
     submenu_add_item(
     submenu_add_item(
         tracker->pattern_submenu, "Exit", SUBMENU_PATTERN_EXIT, submenu_callback, tracker);
         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(
     submenu_add_item(
         tracker->instrument_submenu, "Exit", SUBMENU_INSTRUMENT_EXIT, submenu_callback, tracker);
         tracker->instrument_submenu, "Exit", SUBMENU_INSTRUMENT_EXIT, submenu_callback, tracker);
 
 
@@ -169,6 +173,34 @@ FlizzerTrackerApp* init_tracker(
         VIEW_FILE_OVERWRITE,
         VIEW_FILE_OVERWRITE,
         widget_get_view(tracker->overwrite_file_widget));
         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);
     tracker->notification = furi_record_open(RECORD_NOTIFICATION);
     notification_message(tracker->notification, &sequence_display_backlight_enforce_on);
     notification_message(tracker->notification, &sequence_display_backlight_enforce_on);
 
 
@@ -199,6 +231,7 @@ void deinit_tracker(FlizzerTrackerApp* tracker) {
     submenu_free(tracker->instrument_submenu);
     submenu_free(tracker->instrument_submenu);
 
 
     widget_free(tracker->overwrite_file_widget);
     widget_free(tracker->overwrite_file_widget);
+    widget_free(tracker->overwrite_instrument_file_widget);
 
 
     view_dispatcher_free(tracker->view_dispatcher);
     view_dispatcher_free(tracker->view_dispatcher);
 
 

+ 70 - 2
input_event.c

@@ -7,7 +7,7 @@
 void return_from_keyboard_callback(void* ctx) {
 void return_from_keyboard_callback(void* ctx) {
     FlizzerTrackerApp* tracker = (FlizzerTrackerApp*)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;
         uint8_t string_length = 0;
         char* string = NULL;
         char* string = NULL;
 
 
@@ -65,6 +65,24 @@ void return_from_keyboard_callback(void* ctx) {
             furi_message_queue_put(tracker->event_queue, &event, FuriWaitForever);
             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) {
 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) {
 uint32_t submenu_settings_exit_callback(void* context) {
     UNUSED(context);
     UNUSED(context);
     return VIEW_SUBMENU_PATTERN;
     return VIEW_SUBMENU_PATTERN;
@@ -181,6 +225,30 @@ void submenu_callback(void* context, uint32_t index) {
             break;
             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:
         default:
             break;
             break;
         }
         }
@@ -305,7 +373,7 @@ void process_input_event(FlizzerTrackerApp* tracker, FlizzerTrackerEvent* event)
         }
         }
 
 
         case INST_EDITOR_VIEW: {
         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);
             view_dispatcher_switch_to_view(tracker->view_dispatcher, VIEW_SUBMENU_INSTRUMENT);
             break;
             break;
         }
         }

+ 3 - 0
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_yes_input_callback(GuiButtonType result, InputType type, void* ctx);
 void overwrite_file_widget_no_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_exit_callback(void* context);
 uint32_t submenu_settings_exit_callback(void* context);
 uint32_t submenu_settings_exit_callback(void* context);
 void submenu_callback(void* context, uint32_t index);
 void submenu_callback(void* context, uint32_t index);

+ 4 - 2
tracker_engine/diskop.c

@@ -1,6 +1,8 @@
 #include "diskop.h"
 #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));
     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->waveform, sizeof(inst->waveform));
     rwops = stream_read(stream, (uint8_t*)&inst->flags, sizeof(inst->flags));
     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++) {
     for(uint16_t i = 0; i < song->num_instruments; i++) {
         song->instrument[i] = (Instrument*)malloc(sizeof(Instrument));
         song->instrument[i] = (Instrument*)malloc(sizeof(Instrument));
         set_default_instrument(song->instrument[i]);
         set_default_instrument(song->instrument[i]);
-        load_instrument_inner(stream, song->instrument[i]);
+        load_instrument_inner(stream, song->instrument[i], version);
     }
     }
 
 
     UNUSED(rwops);
     UNUSED(rwops);

+ 3 - 1
tracker_engine/diskop.h

@@ -7,4 +7,6 @@
 #include <storage/storage.h>
 #include <storage/storage.h>
 #include <toolbox/stream/file_stream.h>
 #include <toolbox/stream/file_stream.h>
 
 
-bool load_song(TrackerSong* song, Stream* stream);
+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);

+ 2 - 0
tracker_engine/tracker_engine_defs.h

@@ -25,6 +25,8 @@
 
 
 #define SONG_FILE_SIG "FZT!SONG"
 #define SONG_FILE_SIG "FZT!SONG"
 #define SONG_FILE_EXT ".fzt"
 #define SONG_FILE_EXT ".fzt"
+#define INST_FILE_SIG "FZT!INST"
+#define INST_FILE_EXT ".fzi"
 
 
 #define TRACKER_ENGINE_VERSION 1
 #define TRACKER_ENGINE_VERSION 1