Przeglądaj źródła

saving/loading kinda works

LTVA1 3 lat temu
rodzic
commit
71a6b50b8a
13 zmienionych plików z 277 dodań i 80 usunięć
  1. 1 1
      README.md
  2. 18 2
      diskop.c
  3. 4 1
      diskop.h
  4. 31 0
      flizzer_tracker.c
  5. 1 0
      flizzer_tracker.h
  6. 0 3
      input/songinfo.c
  7. 9 0
      input_event.c
  8. 127 0
      tracker_engine/diskop.c
  9. 10 0
      tracker_engine/diskop.h
  10. 65 0
      tracker_engine/tracker_engine.c
  11. 10 1
      tracker_engine/tracker_engine.h
  12. 0 65
      util.c
  13. 1 7
      util.h

+ 1 - 1
README.md

@@ -1,4 +1,4 @@
 # flizzer_tracker
  A Flipper Zero chiptune tracker.
 
-CURRENT STATE: proof of concept++. Works only on custom build of the firmware (tiny font not supported yet); effects, vibrato and PWM are not implemented, as well as a lot of other things (loading module (only saving and it is untested), song loop points, instrument klystrack-like program (you can edit it but it does not work), etc.)
+CURRENT STATE: proof of concept++. Works only on custom build of the firmware (tiny font not supported yet); effects, vibrato and PWM are not implemented, as well as a lot of other things (song loop points, instrument klystrack-like program (you can edit it but it does not work), etc.). After brief testing looks like it saves and loads modules properly tho.

+ 18 - 2
diskop.c

@@ -29,7 +29,7 @@ void save_instrument_inner(Stream* stream, Instrument* inst)
 
     for(uint8_t i = 0; i < INST_PROG_LEN; i++)
     {
-        if(inst->program[i] != TE_PROGRAM_NOP)
+        if((inst->program[i] & 0x7fff) != TE_PROGRAM_NOP)
         {
             progsteps = i + 1;
         }
@@ -39,7 +39,7 @@ void save_instrument_inner(Stream* stream, Instrument* inst)
 
     if(progsteps > 0)
     {
-        rwops = stream_write(stream, (uint8_t*)inst->program, sizeof(progsteps) * sizeof(inst->program[0]));
+        rwops = stream_write(stream, (uint8_t*)inst->program, progsteps * sizeof(inst->program[0]));
     }
 
     rwops = stream_write(stream, (uint8_t*)&inst->program_period, sizeof(inst->program_period));
@@ -89,6 +89,9 @@ bool save_song(FlizzerTrackerApp* tracker, FuriString* filepath)
     rwops = stream_write(tracker->stream, (uint8_t*)&song->loop_end, sizeof(song->loop_end));
     rwops = stream_write(tracker->stream, (uint8_t*)&song->pattern_length, sizeof(song->pattern_length));
 
+    rwops = stream_write(tracker->stream, (uint8_t*)&song->speed, sizeof(song->speed));
+    rwops = stream_write(tracker->stream, (uint8_t*)&song->rate, sizeof(song->rate));
+
     rwops = stream_write(tracker->stream, (uint8_t*)&song->num_sequence_steps, sizeof(song->num_sequence_steps));
 
     for(uint16_t i = 0; i < song->num_sequence_steps; i++)
@@ -118,4 +121,17 @@ bool save_song(FlizzerTrackerApp* tracker, FuriString* filepath)
     UNUSED(open_file);
     UNUSED(rwops);
     return false;
+}
+
+bool load_song_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_song(&tracker->song, tracker->stream);
+
+    tracker->is_loading = false;
+    file_stream_close(tracker->stream);
+    furi_string_free(filepath);
+    UNUSED(open_file);
+    return result;
 }

+ 4 - 1
diskop.h

@@ -1,7 +1,10 @@
 #pragma once
 
 #include "flizzer_tracker.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 load_song_util(FlizzerTrackerApp* tracker, FuriString* filepath);

+ 31 - 0
flizzer_tracker.c

@@ -226,6 +226,37 @@ int32_t flizzer_tracker_app(void *p)
         {
             save_song(tracker, tracker->filepath);
         }
+
+        if(event.type == EventTypeLoadSong)
+        {
+            tracker->dialogs = furi_record_open(RECORD_DIALOGS);
+            tracker->is_loading = true;
+
+            FuriString* path;
+            path = furi_string_alloc();
+            furi_string_set(path, FLIZZER_TRACKER_FOLDER);
+
+            DialogsFileBrowserOptions browser_options;
+            dialog_file_browser_set_basic_options(&browser_options, SONG_FILE_EXT, &I_flizzer_tracker_module);
+            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);
+
+            if(ret)
+            {
+                bool result = load_song_util(tracker, path);
+                UNUSED(result);
+            }
+
+            else
+            {
+                furi_string_free(path);
+            }
+
+        }
     }
 
     stop();

+ 1 - 0
flizzer_tracker.h

@@ -29,6 +29,7 @@ typedef enum
 {
     EventTypeInput,
     EventTypeSaveSong,
+    EventTypeLoadSong,
 } EventType;
 
 typedef struct

+ 0 - 3
input/songinfo.c

@@ -57,7 +57,6 @@ void return_from_keyboard_callback(void *ctx)
 
     if(tracker->is_saving)
     {
-        //storage_file_exists(storage, NFC_TEST_DICT_PATH);
         tracker->filepath = furi_string_alloc();
         furi_string_cat_printf(tracker->filepath, "%s/%s%s", FLIZZER_TRACKER_FOLDER, tracker->filename, SONG_FILE_EXT);
 
@@ -71,8 +70,6 @@ void return_from_keyboard_callback(void *ctx)
         {
             FlizzerTrackerEvent event = {.type = EventTypeSaveSong, .input = {0}, .period = 0};
             furi_message_queue_put(tracker->event_queue, &event, FuriWaitForever);
-            //bool song_saved = save_song(tracker, tracker->filepath);
-            //UNUSED(song_saved);
         }
     }
 }

+ 9 - 0
input_event.c

@@ -68,6 +68,15 @@ void submenu_callback(void *context, uint32_t index)
                     tracker->is_saving = true;
 
                     view_dispatcher_switch_to_view(tracker->view_dispatcher, VIEW_KEYBOARD);
+                    break;
+                }
+
+                case SUBMENU_PATTERN_LOAD_SONG:
+                {
+                    FlizzerTrackerEvent event = {.type = EventTypeLoadSong, .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:

+ 127 - 0
tracker_engine/diskop.c

@@ -0,0 +1,127 @@
+#include "diskop.h"
+
+void load_instrument_inner(Stream* stream, Instrument* inst)
+{
+    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));
+    rwops = stream_read(stream, (uint8_t*)&inst->sound_engine_flags, sizeof(inst->sound_engine_flags));
+
+    rwops = stream_read(stream, (uint8_t*)&inst->base_note, sizeof(inst->base_note));
+    rwops = stream_read(stream, (uint8_t*)&inst->finetune, sizeof(inst->finetune));
+
+    rwops = stream_read(stream, (uint8_t*)&inst->slide_speed, sizeof(inst->slide_speed));
+
+    rwops = stream_read(stream, (uint8_t*)&inst->adsr, sizeof(inst->adsr));
+    rwops = stream_read(stream, (uint8_t*)&inst->pw, sizeof(inst->pw));
+
+    if(inst->sound_engine_flags & SE_ENABLE_RING_MOD)
+    {
+        rwops = stream_read(stream, (uint8_t*)&inst->ring_mod, sizeof(inst->ring_mod));
+    }
+
+    if(inst->sound_engine_flags & SE_ENABLE_HARD_SYNC)
+    {
+        rwops = stream_read(stream, (uint8_t*)&inst->hard_sync, sizeof(inst->hard_sync));
+    }
+
+    uint8_t progsteps = 0;
+
+    rwops = stream_read(stream, (uint8_t*)&progsteps, sizeof(progsteps));
+
+    if(progsteps > 0)
+    {
+        rwops = stream_read(stream, (uint8_t*)inst->program, progsteps * sizeof(inst->program[0]));
+    }
+
+    rwops = stream_read(stream, (uint8_t*)&inst->program_period, sizeof(inst->program_period));
+
+    if(inst->flags & TE_ENABLE_VIBRATO)
+    {
+        rwops = stream_read(stream, (uint8_t*)&inst->vibrato_speed, sizeof(inst->vibrato_speed));
+        rwops = stream_read(stream, (uint8_t*)&inst->vibrato_depth, sizeof(inst->vibrato_depth));
+        rwops = stream_read(stream, (uint8_t*)&inst->vibrato_delay, sizeof(inst->vibrato_delay));
+    }
+
+    if(inst->flags & TE_ENABLE_PWM)
+    {
+        rwops = stream_read(stream, (uint8_t*)&inst->pwm_speed, sizeof(inst->pwm_speed));
+        rwops = stream_read(stream, (uint8_t*)&inst->pwm_depth, sizeof(inst->pwm_depth));
+        rwops = stream_read(stream, (uint8_t*)&inst->pwm_delay, sizeof(inst->pwm_delay));
+    }
+
+    if(inst->sound_engine_flags & SE_ENABLE_FILTER)
+    {
+        rwops = stream_read(stream, (uint8_t*)&inst->filter_cutoff, sizeof(inst->filter_cutoff));
+        rwops = stream_read(stream, (uint8_t*)&inst->filter_resonance, sizeof(inst->filter_resonance));
+        rwops = stream_read(stream, (uint8_t*)&inst->filter_type, sizeof(inst->filter_type));
+    }
+
+    UNUSED(rwops);
+}
+
+bool load_song_inner(TrackerSong* song, Stream* stream)
+{
+    uint8_t version = 0;
+    size_t rwops = stream_read(stream, (uint8_t*)&version, sizeof(version));
+
+    if(version > TRACKER_ENGINE_VERSION) //if song is of newer version this version of tracker engine can't support
+    {
+        return false;
+    }
+
+    tracker_engine_deinit_song(song, false);
+    memset(song, 0, sizeof(TrackerSong));
+
+    rwops = stream_read(stream, (uint8_t*)song->song_name, sizeof(song->song_name));
+    rwops = stream_read(stream, (uint8_t*)&song->loop_start, sizeof(song->loop_start));
+    rwops = stream_read(stream, (uint8_t*)&song->loop_end, sizeof(song->loop_end));
+    rwops = stream_read(stream, (uint8_t*)&song->pattern_length, sizeof(song->pattern_length));
+
+    rwops = stream_read(stream, (uint8_t*)&song->speed, sizeof(song->speed));
+    rwops = stream_read(stream, (uint8_t*)&song->rate, sizeof(song->rate));
+
+    rwops = stream_read(stream, (uint8_t*)&song->num_sequence_steps, sizeof(song->num_sequence_steps));
+
+    for(uint16_t i = 0; i < song->num_sequence_steps; i++)
+    {
+        rwops = stream_read(stream, (uint8_t*)&song->sequence.sequence_step[i], sizeof(song->sequence.sequence_step[0]));
+    }
+
+    rwops = stream_read(stream, (uint8_t*)&song->num_patterns, sizeof(song->num_patterns));
+
+    for(uint16_t i = 0; i < song->num_patterns; i++)
+    {
+        song->pattern[i].step = (TrackerSongPatternStep*)malloc(sizeof(TrackerSongPatternStep) * (song->pattern_length - 1));
+        set_empty_pattern(&song->pattern[i], song->pattern_length);
+        rwops = stream_read(stream, (uint8_t*)song->pattern[i].step, sizeof(TrackerSongPatternStep) * (song->pattern_length - 1));
+    }
+
+    rwops = stream_read(stream, (uint8_t*)&song->num_instruments, sizeof(song->num_instruments));
+
+    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]);
+    }
+
+    UNUSED(rwops);
+    return false;
+}
+
+bool load_song(TrackerSong* song, Stream* stream)
+{
+    char header[sizeof(SONG_FILE_SIG) + 2] = {0};
+    size_t rwops = stream_read(stream, (uint8_t*)&header, sizeof(SONG_FILE_SIG) - 1);
+    header[sizeof(SONG_FILE_SIG)] = '\0';
+
+    if(strcmp(header, SONG_FILE_SIG) == 0)
+    {
+        bool result = load_song_inner(song, stream);
+        UNUSED(result);
+    }
+
+    UNUSED(rwops);
+    return false;
+}

+ 10 - 0
tracker_engine/diskop.h

@@ -0,0 +1,10 @@
+#pragma once
+
+#include <stdio.h>
+#include <stdbool.h>
+#include <toolbox/stream/file_stream.h>
+#include <storage/storage.h>
+#include "tracker_engine_defs.h"
+#include "tracker_engine.h"
+
+bool load_song(TrackerSong* song, Stream* stream);

+ 65 - 0
tracker_engine/tracker_engine.c

@@ -47,6 +47,71 @@ void tracker_engine_deinit(TrackerEngine *tracker_engine, bool free_song)
     tracker_engine_stop();
 }
 
+void set_note(TrackerSongPatternStep *step, uint8_t note)
+{
+    step->note &= 0x80;
+    step->note |= (note & 0x7f);
+}
+
+void set_instrument(TrackerSongPatternStep *step, uint8_t inst)
+{
+    step->note &= 0x7f;
+    step->inst_vol &= 0x0f;
+
+    step->note |= ((inst & 0x10) << 3);
+    step->inst_vol |= ((inst & 0xf) << 4);
+}
+
+void set_volume(TrackerSongPatternStep *step, uint8_t vol)
+{
+    step->command &= 0x7fff;
+    step->inst_vol &= 0xf0;
+
+    step->command |= ((vol & 0x10) << 11);
+    step->inst_vol |= (vol & 0xf);
+}
+
+void set_command(TrackerSongPatternStep *step, uint16_t command)
+{
+    step->command &= 0x8000;
+    step->command |= command & (0x7fff);
+}
+
+void set_default_instrument(Instrument* inst)
+{
+    memset(inst, 0, sizeof(Instrument));
+
+    inst->flags = TE_SET_CUTOFF | TE_SET_PW;
+    inst->sound_engine_flags = SE_ENABLE_KEYDOWN_SYNC;
+
+    inst->base_note = MIDDLE_C;
+
+    inst->waveform = SE_WAVEFORM_PULSE;
+    inst->pw = 0x80;
+
+    inst->adsr.a = 0x4;
+    inst->adsr.d = 0x28;
+    inst->adsr.volume = 0x80;
+
+    for(int i = 0; i < INST_PROG_LEN; i++)
+    {
+        inst->program[i] = TE_PROGRAM_NOP;
+    }
+}
+
+void set_empty_pattern(TrackerSongPattern *pattern, uint16_t pattern_length)
+{
+    for (uint16_t i = 0; i < pattern_length; i++)
+    {
+        TrackerSongPatternStep *step = &pattern->step[i];
+
+        set_note(step, MUS_NOTE_NONE);
+        set_instrument(step, MUS_NOTE_INSTRUMENT_NONE);
+        set_volume(step, MUS_NOTE_VOLUME_NONE);
+        set_command(step, 0);
+    }
+}
+
 uint8_t tracker_engine_get_note(TrackerSongPatternStep *step)
 {
     return (step->note & 0x7f);

+ 10 - 1
tracker_engine/tracker_engine.h

@@ -6,9 +6,18 @@ void tracker_engine_init(TrackerEngine *tracker_engine, uint8_t rate, SoundEngin
 void tracker_engine_deinit(TrackerEngine *tracker_engine, bool free_song);
 void tracker_engine_advance_tick(TrackerEngine *tracker_engine);
 void tracker_engine_set_song(TrackerEngine *tracker_engine, TrackerSong *song);
+void tracker_engine_deinit_song(TrackerSong *song, bool free_song);
 void tracker_engine_trigger_instrument_internal(TrackerEngine *tracker_engine, uint8_t chan, Instrument *pinst, uint16_t note);
 
 uint8_t tracker_engine_get_note(TrackerSongPatternStep *step);
 uint8_t tracker_engine_get_instrument(TrackerSongPatternStep *step);
 uint8_t tracker_engine_get_volume(TrackerSongPatternStep *step);
-uint16_t tracker_engine_get_command(TrackerSongPatternStep *step);
+uint16_t tracker_engine_get_command(TrackerSongPatternStep *step);
+
+void set_note(TrackerSongPatternStep *step, uint8_t note);
+void set_instrument(TrackerSongPatternStep *step, uint8_t inst);
+void set_volume(TrackerSongPatternStep *step, uint8_t vol);
+void set_command(TrackerSongPatternStep *step, uint16_t command);
+
+void set_default_instrument(Instrument* inst);
+void set_empty_pattern(TrackerSongPattern *pattern, uint16_t pattern_length);

+ 0 - 65
util.c

@@ -1,35 +1,5 @@
 #include "util.h"
 
-void set_note(TrackerSongPatternStep *step, uint8_t note)
-{
-    step->note &= 0x80;
-    step->note |= (note & 0x7f);
-}
-
-void set_instrument(TrackerSongPatternStep *step, uint8_t inst)
-{
-    step->note &= 0x7f;
-    step->inst_vol &= 0x0f;
-
-    step->note |= ((inst & 0x10) << 3);
-    step->inst_vol |= ((inst & 0xf) << 4);
-}
-
-void set_volume(TrackerSongPatternStep *step, uint8_t vol)
-{
-    step->command &= 0x7fff;
-    step->inst_vol &= 0xf0;
-
-    step->command |= ((vol & 0x10) << 11);
-    step->inst_vol |= (vol & 0xf);
-}
-
-void set_command(TrackerSongPatternStep *step, uint16_t command)
-{
-    step->command &= 0x8000;
-    step->command |= command & (0x7fff);
-}
-
 void reset_buffer(SoundEngine *sound_engine)
 {
     for (uint16_t i = 0; i < sound_engine->audio_buffer_size; i++)
@@ -85,19 +55,6 @@ bool is_pattern_empty(TrackerSong *song, uint8_t pattern)
     return true;
 }
 
-void set_empty_pattern(TrackerSongPattern *pattern, uint16_t pattern_length)
-{
-    for (uint16_t i = 0; i < pattern_length; i++)
-    {
-        TrackerSongPatternStep *step = &pattern->step[i];
-
-        set_note(step, MUS_NOTE_NONE);
-        set_instrument(step, MUS_NOTE_INSTRUMENT_NONE);
-        set_volume(step, MUS_NOTE_VOLUME_NONE);
-        set_command(step, 0);
-    }
-}
-
 bool check_and_allocate_pattern(TrackerSong *song, uint8_t pattern)
 {
     if (pattern < song->num_patterns) // we can set this pattern since it already exists
@@ -150,28 +107,6 @@ void change_pattern_length(TrackerSong *song, uint16_t new_length)
     song->pattern_length = new_length;
 }
 
-void set_default_instrument(Instrument* inst)
-{
-    memset(inst, 0, sizeof(Instrument));
-
-    inst->flags = TE_SET_CUTOFF | TE_SET_PW;
-    inst->sound_engine_flags = SE_ENABLE_KEYDOWN_SYNC;
-
-    inst->base_note = MIDDLE_C;
-
-    inst->waveform = SE_WAVEFORM_PULSE;
-    inst->pw = 0x80;
-
-    inst->adsr.a = 0x4;
-    inst->adsr.d = 0x28;
-    inst->adsr.volume = 0x80;
-
-    for(int i = 0; i < INST_PROG_LEN; i++)
-    {
-        inst->program[i] = TE_PROGRAM_NOP;
-    }
-}
-
 bool is_default_instrument(Instrument* inst)
 {
     Instrument* ref = malloc(sizeof(Instrument));

+ 1 - 7
util.h

@@ -6,6 +6,7 @@
 #include "flizzer_tracker.h"
 #include "sound_engine/sound_engine_defs.h"
 #include "tracker_engine/tracker_engine_defs.h"
+#include "tracker_engine/tracker_engine.h"
 
 #define clamp(val, add, _min, _max) val = fmin(_max, fmax(_min, (int32_t)val + add))
 #define flipbit(val, bit) \
@@ -13,19 +14,12 @@
         val ^= bit;       \
     };
 
-void set_note(TrackerSongPatternStep *step, uint8_t note);
-void set_instrument(TrackerSongPatternStep *step, uint8_t inst);
-void set_volume(TrackerSongPatternStep *step, uint8_t vol);
-void set_command(TrackerSongPatternStep *step, uint16_t command);
-
 void reset_buffer(SoundEngine *sound_engine);
 void play_song(FlizzerTrackerApp *tracker, bool from_cursor);
 void stop_song(FlizzerTrackerApp *tracker);
 
-void set_empty_pattern(TrackerSongPattern *pattern, uint16_t pattern_length);
 bool is_pattern_empty(TrackerSong *song, uint8_t pattern);
 bool check_and_allocate_pattern(TrackerSong *song, uint8_t pattern);
 void change_pattern_length(TrackerSong *song, uint16_t new_length);
 
-void set_default_instrument(Instrument* inst);
 bool check_and_allocate_instrument(TrackerSong *song, uint8_t inst);