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

small song rate and sample rate calc error fixed, tidying up, added better volume calc, pattern resize, finish inst editor, channel mute icons

LTVA1 3 лет назад
Родитель
Сommit
a8ec3385cc

+ 4 - 63
flizzer_tracker.c

@@ -15,7 +15,7 @@ Copyright:
 Glyphs: 95/203
 Glyphs: 95/203
 BBX Build Mode: 0
 BBX Build Mode: 0
 */
 */
-// this is a modified version with dot and semicolon moved 1 pixel to the left; lowercase symbols removed
+// this is a modified version with dot and semicolon moved 1 pixel to the left; lowercase symbols removed to save space
 const uint8_t u8g2_font_tom_thumb_4x6_tr[479] U8G2_FONT_SECTION("u8g2_font_tom_thumb_4x6_tr") =
 const uint8_t u8g2_font_tom_thumb_4x6_tr[479] U8G2_FONT_SECTION("u8g2_font_tom_thumb_4x6_tr") =
     "A\0\2\2\2\3\2\3\4\3\5\0\0\5\0\5\0\0\340\0\0\1\306 \4@\62!\5u\62+"
     "A\0\2\2\2\3\2\3\4\3\5\0\0\5\0\5\0\0\340\0\0\1\306 \4@\62!\5u\62+"
     "\42\6\313\63I\5#\10W\62i\250\241\2$\10Wr#\216\230\0%\10W\62\31\265Q\0&\10"
     "\42\6\313\63I\5#\10W\62i\250\241\2$\10Wr#\216\230\0%\10W\62\31\265Q\0&\10"
@@ -33,7 +33,7 @@ const uint8_t u8g2_font_tom_thumb_4x6_tr[479] U8G2_FONT_SECTION("u8g2_font_tom_t
     "X\10W\62I\265T\0Y\10W\62I\225\25\0Z\7W\62\63\225\3[\7W\62#\226\3\134\7"
     "X\10W\62I\265T\0Y\10W\62I\225\25\0Z\7W\62\63\225\3[\7W\62#\226\3\134\7"
     "\317\62\31d\20]\7W\62\263\34\1^\5\313s\15_\5G\62\3`\5\312\63\61\0\0\0";
     "\317\62\31d\20]\7W\62\263\34\1^\5\313s\15_\5G\62\3`\5\312\63\61\0\0\0";
 
 
-static void draw_callback(Canvas *canvas, void *ctx)
+void draw_callback(Canvas *canvas, void *ctx)
 {
 {
     TrackerViewModel *model = (TrackerViewModel *)ctx;
     TrackerViewModel *model = (TrackerViewModel *)ctx;
     FlizzerTrackerApp *tracker = (FlizzerTrackerApp *)(model->tracker);
     FlizzerTrackerApp *tracker = (FlizzerTrackerApp *)(model->tracker);
@@ -70,7 +70,7 @@ static void draw_callback(Canvas *canvas, void *ctx)
     }
     }
 }
 }
 
 
-static bool input_callback(InputEvent *input_event, void *ctx)
+bool input_callback(InputEvent *input_event, void *ctx)
 {
 {
     // Проверяем, что контекст не нулевой
     // Проверяем, что контекст не нулевой
     furi_assert(ctx);
     furi_assert(ctx);
@@ -102,53 +102,14 @@ static bool input_callback(InputEvent *input_event, void *ctx)
     return consumed;
     return consumed;
 }
 }
 
 
-TrackerView *tracker_view_alloc(FlizzerTrackerApp *tracker)
-{
-    TrackerView *tracker_view = malloc(sizeof(TrackerView));
-    tracker_view->view = view_alloc();
-    tracker_view->context = tracker;
-    view_set_context(tracker_view->view, tracker_view);
-    view_allocate_model(tracker_view->view, ViewModelTypeLocking, sizeof(TrackerViewModel));
-    view_set_draw_callback(tracker_view->view, draw_callback);
-    view_set_input_callback(tracker_view->view, input_callback);
-
-    return tracker_view;
-}
-
-void tracker_view_free(TrackerView *tracker_view)
-{
-    furi_assert(tracker_view);
-    view_free(tracker_view->view);
-    free(tracker_view);
-}
-
 int32_t flizzer_tracker_app(void *p)
 int32_t flizzer_tracker_app(void *p)
 {
 {
     UNUSED(p);
     UNUSED(p);
 
 
-    FlizzerTrackerApp *tracker = init_tracker(44100, 50, true, 1024);
+    FlizzerTrackerApp *tracker = init_tracker(44100, 50, false, 1024);
 
 
     // Текущее событие типа кастомного типа FlizzerTrackerEvent
     // Текущее событие типа кастомного типа FlizzerTrackerEvent
     FlizzerTrackerEvent event;
     FlizzerTrackerEvent event;
-    // Очередь событий на 8 элементов размера FlizzerTrackerEvent
-    tracker->event_queue = furi_message_queue_alloc(8, sizeof(FlizzerTrackerEvent));
-
-    tracker->gui = furi_record_open(RECORD_GUI);
-    tracker->view_dispatcher = view_dispatcher_alloc();
-
-    tracker->tracker_view = tracker_view_alloc(tracker);
-
-    view_dispatcher_add_view(tracker->view_dispatcher, VIEW_TRACKER, tracker->tracker_view->view);
-    view_dispatcher_attach_to_gui(tracker->view_dispatcher, tracker->gui, ViewDispatcherTypeFullscreen);
-
-    with_view_model(
-        tracker->tracker_view->view, TrackerViewModel * model, { model->tracker = tracker; }, true);
-
-    tracker->text_input = text_input_alloc();
-    view_dispatcher_add_view(tracker->view_dispatcher, VIEW_KEYBOARD, text_input_get_view(tracker->text_input));
-
-    tracker->notification = furi_record_open(RECORD_NOTIFICATION);
-    notification_message(tracker->notification, &sequence_display_backlight_enforce_on);
 
 
     tracker->tracker_engine.master_volume = 0x80;
     tracker->tracker_engine.master_volume = 0x80;
 
 
@@ -216,10 +177,6 @@ int32_t flizzer_tracker_app(void *p)
     tracker->song.instrument[0]->adsr.volume = 0x80;
     tracker->song.instrument[0]->adsr.volume = 0x80;
     tracker->song.instrument[0]->waveform = SE_WAVEFORM_TRIANGLE;
     tracker->song.instrument[0]->waveform = SE_WAVEFORM_TRIANGLE;
     tracker->song.instrument[0]->sound_engine_flags |= SE_ENABLE_KEYDOWN_SYNC;
     tracker->song.instrument[0]->sound_engine_flags |= SE_ENABLE_KEYDOWN_SYNC;
-    /*tracker->song.instrument[0]->sound_engine_flags |= (SE_ENABLE_KEYDOWN_SYNC | SE_ENABLE_FILTER);
-    tracker->song.instrument[0]->flags |= TE_SET_CUTOFF;
-    tracker->song.instrument[0]->filter_type = FIL_OUTPUT_LOWPASS;
-    tracker->song.instrument[0]->filter_cutoff = 10;*/
 
 
     tracker->song.instrument[1]->base_note = MIDDLE_C;
     tracker->song.instrument[1]->base_note = MIDDLE_C;
     tracker->song.instrument[1]->adsr.a = 0x0;
     tracker->song.instrument[1]->adsr.a = 0x0;
@@ -249,22 +206,6 @@ int32_t flizzer_tracker_app(void *p)
 
 
     stop();
     stop();
 
 
-    notification_message(tracker->notification, &sequence_display_backlight_enforce_auto);
-    furi_record_close(RECORD_NOTIFICATION);
-
-    // Специальная очистка памяти, занимаемой очередью
-    furi_message_queue_free(tracker->event_queue);
-
-    view_dispatcher_remove_view(tracker->view_dispatcher, VIEW_KEYBOARD);
-    view_dispatcher_remove_view(tracker->view_dispatcher, VIEW_TRACKER);
-
-    text_input_free(tracker->text_input);
-
-    view_dispatcher_free(tracker->view_dispatcher);
-
-    tracker_view_free(tracker->tracker_view);
-    furi_record_close(RECORD_GUI);
-
     deinit_tracker(tracker);
     deinit_tracker(tracker);
 
 
     return 0;
     return 0;

+ 24 - 3
flizzer_tracker.h

@@ -5,6 +5,9 @@
 #include <gui/gui.h>
 #include <gui/gui.h>
 #include <input/input.h>
 #include <input/input.h>
 #include <notification/notification_messages.h>
 #include <notification/notification_messages.h>
+#include <dialogs/dialogs.h>
+#include <gui/modules/submenu.h>
+#include <toolbox/stream/file_stream.h>
 #include <stdio.h>
 #include <stdio.h>
 #include <u8g2_glue.h>
 #include <u8g2_glue.h>
 
 
@@ -110,7 +113,7 @@ typedef enum
     INST_PWMDELAY,
     INST_PWMDELAY,
 
 
     INST_PROGRAMEPERIOD,
     INST_PROGRAMEPERIOD,
-    /* ========  */
+    /* ========= */
     INST_PARAMS,
     INST_PARAMS,
 } InstrumentParam;
 } InstrumentParam;
 
 
@@ -125,9 +128,20 @@ typedef enum
     VIEW_TRACKER,
     VIEW_TRACKER,
     VIEW_KEYBOARD,
     VIEW_KEYBOARD,
     VIEW_FILE_MANAGER,
     VIEW_FILE_MANAGER,
-    VIEW_SUBMENU,
+    VIEW_SUBMENU_PATTERN,
+    VIEW_SUBMENU_INSTRUMENT,
 } FlizzerTrackerViews;
 } FlizzerTrackerViews;
 
 
+typedef enum
+{
+    SUBMENU_PATTERN_EXIT,
+} PatternSubmenuParams;
+
+typedef enum
+{
+    SUBMENU_INSTRUMENT_EXIT,
+} InstrumentSubmenuParams;
+
 typedef struct
 typedef struct
 {
 {
     NotificationApp *notification;
     NotificationApp *notification;
@@ -136,6 +150,10 @@ typedef struct
     TrackerView *tracker_view;
     TrackerView *tracker_view;
     ViewDispatcher *view_dispatcher;
     ViewDispatcher *view_dispatcher;
     TextInput *text_input;
     TextInput *text_input;
+    Stream* stream;
+    DialogsApp* dialogs;
+    Submenu* pattern_submenu;
+    Submenu* instrument_submenu;
     bool was_it_back_keypress;
     bool was_it_back_keypress;
     uint32_t current_time;
     uint32_t current_time;
     uint32_t period;
     uint32_t period;
@@ -161,4 +179,7 @@ typedef struct
 typedef struct
 typedef struct
 {
 {
     FlizzerTrackerApp *tracker;
     FlizzerTrackerApp *tracker;
-} TrackerViewModel;
+} TrackerViewModel;
+
+void draw_callback(Canvas *canvas, void *ctx);
+bool input_callback(InputEvent *input_event, void *ctx);

+ 5 - 5
flizzer_tracker_hal.c

@@ -74,7 +74,7 @@ void sound_engine_timer_init(uint32_t sample_rate) // external audio on pin PA6
     LL_TIM_OC_InitTypeDef TIM_OC_InitStruct = {0};
     LL_TIM_OC_InitTypeDef TIM_OC_InitStruct = {0};
 
 
     TIM_InitStruct.Prescaler = 0;
     TIM_InitStruct.Prescaler = 0;
-    TIM_InitStruct.Autoreload = TIMER_BASE_CLOCK / sample_rate; // to support various sample rates
+    TIM_InitStruct.Autoreload = TIMER_BASE_CLOCK / sample_rate - 1; // to support various sample rates
     TIM_InitStruct.CounterMode = LL_TIM_COUNTERMODE_UP;
     TIM_InitStruct.CounterMode = LL_TIM_COUNTERMODE_UP;
     LL_TIM_Init(SAMPLE_RATE_TIMER, &TIM_InitStruct);
     LL_TIM_Init(SAMPLE_RATE_TIMER, &TIM_InitStruct);
 
 
@@ -90,8 +90,8 @@ void tracker_engine_timer_init(uint8_t rate) // 0-255 hz
     LL_TIM_InitTypeDef TIM_InitStruct = {0};
     LL_TIM_InitTypeDef TIM_InitStruct = {0};
     LL_TIM_OC_InitTypeDef TIM_OC_InitStruct = {0};
     LL_TIM_OC_InitTypeDef TIM_OC_InitStruct = {0};
 
 
-    TIM_InitStruct.Prescaler = 0;                                            // using 32-bit timer
-    TIM_InitStruct.Autoreload = (uint32_t)TIMER_BASE_CLOCK / (uint32_t)rate; // to support various tracker engine rates
+    TIM_InitStruct.Prescaler = 0;                                                // using 32-bit timer
+    TIM_InitStruct.Autoreload = (uint32_t)TIMER_BASE_CLOCK / (uint32_t)rate - 1; // to support various tracker engine rates
     TIM_InitStruct.CounterMode = LL_TIM_COUNTERMODE_UP;
     TIM_InitStruct.CounterMode = LL_TIM_COUNTERMODE_UP;
     LL_TIM_Init(TRACKER_ENGINE_TIMER, &TIM_InitStruct);
     LL_TIM_Init(TRACKER_ENGINE_TIMER, &TIM_InitStruct);
 
 
@@ -106,8 +106,8 @@ void tracker_engine_set_rate(uint8_t rate)
 {
 {
     LL_TIM_InitTypeDef TIM_InitStruct = {0};
     LL_TIM_InitTypeDef TIM_InitStruct = {0};
 
 
-    TIM_InitStruct.Prescaler = 0;                                            // using 32-bit timer
-    TIM_InitStruct.Autoreload = (uint32_t)TIMER_BASE_CLOCK / (uint32_t)rate; // to support various tracker engine rates
+    TIM_InitStruct.Prescaler = 0;                                                // using 32-bit timer
+    TIM_InitStruct.Autoreload = (uint32_t)TIMER_BASE_CLOCK / (uint32_t)rate - 1; // to support various tracker engine rates
     TIM_InitStruct.CounterMode = LL_TIM_COUNTERMODE_UP;
     TIM_InitStruct.CounterMode = LL_TIM_COUNTERMODE_UP;
     LL_TIM_Init(TRACKER_ENGINE_TIMER, &TIM_InitStruct);
     LL_TIM_Init(TRACKER_ENGINE_TIMER, &TIM_InitStruct);
 }
 }

+ 71 - 0
init_deinit.c

@@ -1,4 +1,25 @@
 #include "init_deinit.h"
 #include "init_deinit.h"
+#include "input_event.h"
+
+TrackerView *tracker_view_alloc(FlizzerTrackerApp *tracker)
+{
+    TrackerView *tracker_view = malloc(sizeof(TrackerView));
+    tracker_view->view = view_alloc();
+    tracker_view->context = tracker;
+    view_set_context(tracker_view->view, tracker_view);
+    view_allocate_model(tracker_view->view, ViewModelTypeLocking, sizeof(TrackerViewModel));
+    view_set_draw_callback(tracker_view->view, draw_callback);
+    view_set_input_callback(tracker_view->view, input_callback);
+
+    return tracker_view;
+}
+
+void tracker_view_free(TrackerView *tracker_view)
+{
+    furi_assert(tracker_view);
+    view_free(tracker_view->view);
+    free(tracker_view);
+}
 
 
 FlizzerTrackerApp *init_tracker(uint32_t sample_rate, uint8_t rate, bool external_audio_output, uint32_t audio_buffer_size)
 FlizzerTrackerApp *init_tracker(uint32_t sample_rate, uint8_t rate, bool external_audio_output, uint32_t audio_buffer_size)
 {
 {
@@ -12,11 +33,61 @@ FlizzerTrackerApp *init_tracker(uint32_t sample_rate, uint8_t rate, bool externa
 
 
     tracker->current_note = MIDDLE_C;
     tracker->current_note = MIDDLE_C;
 
 
+    // Очередь событий на 8 элементов размера FlizzerTrackerEvent
+    tracker->event_queue = furi_message_queue_alloc(8, sizeof(FlizzerTrackerEvent));
+
+    tracker->gui = furi_record_open(RECORD_GUI);
+    tracker->view_dispatcher = view_dispatcher_alloc();
+
+    tracker->tracker_view = tracker_view_alloc(tracker);
+
+    view_dispatcher_add_view(tracker->view_dispatcher, VIEW_TRACKER, tracker->tracker_view->view);
+    view_dispatcher_attach_to_gui(tracker->view_dispatcher, tracker->gui, ViewDispatcherTypeFullscreen);
+
+    with_view_model(
+        tracker->tracker_view->view, TrackerViewModel * model, { model->tracker = tracker; }, true);
+
+    tracker->text_input = text_input_alloc();
+    view_dispatcher_add_view(tracker->view_dispatcher, VIEW_KEYBOARD, text_input_get_view(tracker->text_input));
+
+    tracker->pattern_submenu = submenu_alloc();
+    tracker->instrument_submenu = submenu_alloc();
+
+    submenu_add_item(tracker->pattern_submenu, "Exit", SUBMENU_PATTERN_EXIT, submenu_callback, tracker);
+    submenu_add_item(tracker->instrument_submenu, "Exit", SUBMENU_INSTRUMENT_EXIT, submenu_callback, tracker);
+
+    view_dispatcher_add_view(tracker->view_dispatcher, VIEW_SUBMENU_PATTERN, submenu_get_view(tracker->pattern_submenu));
+    view_dispatcher_add_view(tracker->view_dispatcher, VIEW_SUBMENU_INSTRUMENT, submenu_get_view(tracker->instrument_submenu));
+
+    tracker->notification = furi_record_open(RECORD_NOTIFICATION);
+    notification_message(tracker->notification, &sequence_display_backlight_enforce_on);
+
     return tracker;
     return tracker;
 }
 }
 
 
 void deinit_tracker(FlizzerTrackerApp *tracker)
 void deinit_tracker(FlizzerTrackerApp *tracker)
 {
 {
+    notification_message(tracker->notification, &sequence_display_backlight_enforce_auto);
+    furi_record_close(RECORD_NOTIFICATION);
+
+    // Специальная очистка памяти, занимаемой очередью
+    furi_message_queue_free(tracker->event_queue);
+
+    view_dispatcher_remove_view(tracker->view_dispatcher, VIEW_SUBMENU_INSTRUMENT);
+    view_dispatcher_remove_view(tracker->view_dispatcher, VIEW_SUBMENU_PATTERN);
+    view_dispatcher_remove_view(tracker->view_dispatcher, VIEW_KEYBOARD);
+    view_dispatcher_remove_view(tracker->view_dispatcher, VIEW_TRACKER);
+
+    text_input_free(tracker->text_input);
+
+    submenu_free(tracker->pattern_submenu);
+    submenu_free(tracker->instrument_submenu);
+
+    view_dispatcher_free(tracker->view_dispatcher);
+
+    tracker_view_free(tracker->tracker_view);
+    furi_record_close(RECORD_GUI);
+
     sound_engine_deinit(&tracker->sound_engine);
     sound_engine_deinit(&tracker->sound_engine);
 
 
     if (tracker->tracker_engine.song == NULL)
     if (tracker->tracker_engine.song == NULL)

+ 10 - 1
input/instrument.c

@@ -289,6 +289,11 @@ void edit_instrument_param(FlizzerTrackerApp *tracker, uint8_t selected_param, i
                 inst->ring_mod = 0xff; // 0xff = self
                 inst->ring_mod = 0xff; // 0xff = self
             }
             }
 
 
+            if ((int16_t)inst->ring_mod == 0xff && (int16_t)delta > 0)
+            {
+                inst->ring_mod = 0;
+            }
+
             break;
             break;
         }
         }
 
 
@@ -310,6 +315,11 @@ void edit_instrument_param(FlizzerTrackerApp *tracker, uint8_t selected_param, i
                 inst->hard_sync = 0xff; // 0xff = self
                 inst->hard_sync = 0xff; // 0xff = self
             }
             }
 
 
+            if ((int16_t)inst->hard_sync == 0xff && (int16_t)delta > 0)
+            {
+                inst->hard_sync = 0;
+            }
+
             break;
             break;
         }
         }
 
 
@@ -423,7 +433,6 @@ void instrument_edit_event(FlizzerTrackerApp *tracker, FlizzerTrackerEvent *even
     {
     {
         SoundEngineChannel *se_channel = &tracker->sound_engine.channel[0];
         SoundEngineChannel *se_channel = &tracker->sound_engine.channel[0];
         sound_engine_enable_gate(&tracker->sound_engine, se_channel, false);
         sound_engine_enable_gate(&tracker->sound_engine, se_channel, false);
-        // tracker_engine_set_song(&tracker->tracker_engine, &tracker->song);
         return;
         return;
     }
     }
 
 

+ 3 - 3
input/pattern.c

@@ -71,7 +71,7 @@ void edit_instrument(FlizzerTrackerApp *tracker, TrackerSongPatternStep *step, i
     }
     }
 
 
     clamp(inst, delta, 0, MUS_NOTE_INSTRUMENT_NONE - 1);
     clamp(inst, delta, 0, MUS_NOTE_INSTRUMENT_NONE - 1);
-    tracker->current_instrument = inst; // remember last instrument
+    tracker->current_instrument = inst; //remember last instrument
     set_instrument(step, (uint8_t)inst);
     set_instrument(step, (uint8_t)inst);
 }
 }
 
 
@@ -278,9 +278,9 @@ void pattern_edit_event(FlizzerTrackerApp *tracker, FlizzerTrackerEvent *event)
 {
 {
     uint8_t sequence_position = tracker->tracker_engine.sequence_position;
     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];
     uint8_t current_pattern = tracker->tracker_engine.song->sequence.sequence_step[sequence_position].pattern_indices[tracker->current_channel];
-    uint8_t pattern_step = tracker->tracker_engine.pattern_position;
+    uint16_t pattern_step = tracker->tracker_engine.pattern_position;
 
 
-    uint8_t pattern_length = tracker->tracker_engine.song->pattern_length;
+    uint16_t pattern_length = tracker->tracker_engine.song->pattern_length;
 
 
     TrackerSongPattern *pattern = &tracker->tracker_engine.song->pattern[current_pattern];
     TrackerSongPattern *pattern = &tracker->tracker_engine.song->pattern[current_pattern];
 
 

+ 0 - 13
input/sequence.c

@@ -83,19 +83,6 @@ void sequence_edit_event(FlizzerTrackerApp *tracker, FlizzerTrackerEvent *event)
         tracker->editing = !tracker->editing;
         tracker->editing = !tracker->editing;
     }
     }
 
 
-    /*if(event->input.key == InputKeyOk && event->input.type == InputTypeLong)
-    {
-            if(tracker->tracker_engine.playing)
-            {
-                    stop_song(tracker);
-            }
-
-            else
-            {
-                    play_song(tracker, true);
-            }
-    }*/
-
     if (event->input.key == InputKeyRight && event->input.type == InputTypeShort && tracker->editing)
     if (event->input.key == InputKeyRight && event->input.type == InputTypeShort && tracker->editing)
     {
     {
         tracker->current_digit++;
         tracker->current_digit++;

+ 5 - 2
input/songinfo.c

@@ -62,9 +62,12 @@ void edit_songinfo_param(FlizzerTrackerApp *tracker, uint8_t selected_param, int
     {
     {
         case SI_PATTERNPOS:
         case SI_PATTERNPOS:
         {
         {
-            if ((int16_t)tracker->song.pattern_length + (int16_t)delta > 1 && (int16_t)tracker->song.pattern_length + (int16_t)delta <= 0xff)
+            uint16_t new_length = tracker->song.pattern_length;
+
+            if ((int16_t)new_length + (int16_t)delta > 0 && (int16_t)new_length + (int16_t)delta <= 0x100)
             {
             {
-                tracker->song.pattern_length += delta;
+                new_length += delta;
+                change_pattern_length(&tracker->song, new_length);
             }
             }
 
 
             break;
             break;

+ 75 - 1
input_event.c

@@ -1,5 +1,57 @@
 #include "input_event.h"
 #include "input_event.h"
 
 
+void submenu_callback(void* context, uint32_t index)
+{
+    FlizzerTrackerApp* tracker = (FlizzerTrackerApp*)context;
+
+    switch(tracker->mode)
+    {
+        case PATTERN_VIEW:
+        {
+            switch(index)
+            {
+                case SUBMENU_PATTERN_EXIT:
+                {
+                    tracker->quit = true;
+
+                    static InputEvent inevent = {.sequence = 0, .key = InputKeyLeft, .type = InputTypeMAX};
+                    FlizzerTrackerEvent event = {.type = EventTypeInput, .input = inevent, .period = 0}; //making an event so tracker does not wait for next keypress and exits immediately
+                    furi_message_queue_put(tracker->event_queue, &event, FuriWaitForever);
+                    view_dispatcher_switch_to_view(tracker->view_dispatcher, VIEW_TRACKER);
+                    break;
+                }
+
+                default: break;
+            }
+
+            break;
+        }
+
+        case INST_EDITOR_VIEW:
+        {
+            switch(index)
+            {
+                case SUBMENU_INSTRUMENT_EXIT:
+                {
+                    tracker->quit = true;
+
+                    static InputEvent inevent = {.sequence = 0, .key = InputKeyLeft, .type = InputTypeMAX};
+                    FlizzerTrackerEvent event = {.type = EventTypeInput, .input = inevent, .period = 0}; //making an event so tracker does not wait for next keypress and exits immediately
+                    furi_message_queue_put(tracker->event_queue, &event, FuriWaitForever);
+                    view_dispatcher_switch_to_view(tracker->view_dispatcher, VIEW_TRACKER);
+                    break;
+                }
+
+                default: break;
+            }
+
+            break;
+        }
+
+        default: break;
+    }
+}
+
 void cycle_focus(FlizzerTrackerApp *tracker)
 void cycle_focus(FlizzerTrackerApp *tracker)
 {
 {
     switch (tracker->mode)
     switch (tracker->mode)
@@ -51,6 +103,12 @@ void cycle_view(FlizzerTrackerApp *tracker)
         tracker->mode = PATTERN_VIEW;
         tracker->mode = PATTERN_VIEW;
         tracker->focus = EDIT_PATTERN;
         tracker->focus = EDIT_PATTERN;
 
 
+        if(tracker->tracker_engine.song == NULL)
+        {
+            stop_song(tracker);
+            tracker_engine_set_song(&tracker->tracker_engine, &tracker->song);
+        }
+
         tracker->selected_param = 0;
         tracker->selected_param = 0;
         tracker->current_digit = 0;
         tracker->current_digit = 0;
 
 
@@ -75,7 +133,23 @@ void process_input_event(FlizzerTrackerApp *tracker, FlizzerTrackerEvent *event)
     // Если нажата кнопка "назад", то выходим из цикла, а следовательно и из приложения
     // Если нажата кнопка "назад", то выходим из цикла, а следовательно и из приложения
     if (event->input.key == InputKeyBack && event->input.type == InputTypeLong)
     if (event->input.key == InputKeyBack && event->input.type == InputTypeLong)
     {
     {
-        tracker->quit = true;
+        switch(tracker->mode)
+        {
+            case PATTERN_VIEW:
+            {
+                view_dispatcher_switch_to_view(tracker->view_dispatcher, VIEW_SUBMENU_PATTERN);
+                break;
+            }
+
+            case INST_EDITOR_VIEW:
+            {
+                view_dispatcher_switch_to_view(tracker->view_dispatcher, VIEW_SUBMENU_INSTRUMENT);
+                break;
+            }
+
+            default: break;
+        }
+
         return;
         return;
     }
     }
 
 

+ 1 - 0
input_event.h

@@ -15,4 +15,5 @@
 #include "input/sequence.h"
 #include "input/sequence.h"
 #include "input/songinfo.h"
 #include "input/songinfo.h"
 
 
+void submenu_callback(void* context, uint32_t index);
 void process_input_event(FlizzerTrackerApp *tracker, FlizzerTrackerEvent *event);
 void process_input_event(FlizzerTrackerApp *tracker, FlizzerTrackerEvent *event);

+ 13 - 4
tracker_engine/tracker_engine.c

@@ -150,6 +150,8 @@ void tracker_engine_trigger_instrument_internal(TrackerEngine *tracker_engine, u
     se_channel->adsr.r = pinst->adsr.r;
     se_channel->adsr.r = pinst->adsr.r;
     se_channel->adsr.volume = pinst->adsr.volume;
     se_channel->adsr.volume = pinst->adsr.volume;
 
 
+    te_channel->volume = pinst->adsr.volume;
+
     sound_engine_enable_gate(tracker_engine->sound_engine, &tracker_engine->sound_engine->channel[chan], true);
     sound_engine_enable_gate(tracker_engine->sound_engine, &tracker_engine->sound_engine->channel[chan], true);
 }
 }
 
 
@@ -163,7 +165,7 @@ void tracker_engine_execute_track_command(TrackerEngine *tracker_engine, uint8_t
 
 
     if (vol != MUS_NOTE_VOLUME_NONE)
     if (vol != MUS_NOTE_VOLUME_NONE)
     {
     {
-        tracker_engine->sound_engine->channel[chan].adsr.volume = (int32_t)tracker_engine->sound_engine->channel[chan].adsr.volume * (int32_t)vol / (MUS_NOTE_VOLUME_NONE - 1);
+        tracker_engine->sound_engine->channel[chan].adsr.volume = (int32_t)tracker_engine->sound_engine->channel[chan].adsr.volume * (int32_t)tracker_engine->channel[chan].volume / MAX_ADSR_VOLUME * (int32_t)vol / (MUS_NOTE_VOLUME_NONE - 1);
     }
     }
 
 
     // TODO: add actual big ass function that executes commands; add arpeggio commands there
     // TODO: add actual big ass function that executes commands; add arpeggio commands there
@@ -310,14 +312,21 @@ void tracker_engine_advance_tick(TrackerEngine *tracker_engine)
             if (tracker_engine->pattern_position >= song->pattern_length)
             if (tracker_engine->pattern_position >= song->pattern_length)
             {
             {
                 tracker_engine->pattern_position = 0;
                 tracker_engine->pattern_position = 0;
-                tracker_engine->sequence_position++;
 
 
-                if (tracker_engine->sequence_position >= song->num_sequence_steps)
+                uint16_t temp_sequence_position = tracker_engine->sequence_position;
+                temp_sequence_position++;
+
+                if (temp_sequence_position >= song->num_sequence_steps)
                 {
                 {
                     tracker_engine->playing = false; // TODO: add song loop handling
                     tracker_engine->playing = false; // TODO: add song loop handling
-                    tracker_engine->sequence_position--;
+                    //tracker_engine->sequence_position--;
                     tracker_engine->pattern_position = song->pattern_length - 1;
                     tracker_engine->pattern_position = song->pattern_length - 1;
                 }
                 }
+
+                else
+                {
+                    tracker_engine->sequence_position++;
+                }
             }
             }
         }
         }
     }
     }

+ 2 - 4
tracker_engine/tracker_engine_defs.h

@@ -139,7 +139,7 @@ typedef struct
     TrackerSongSequence sequence;
     TrackerSongSequence sequence;
 
 
     uint8_t num_patterns, num_sequence_steps, num_instruments;
     uint8_t num_patterns, num_sequence_steps, num_instruments;
-    uint8_t pattern_length;
+    uint16_t pattern_length;
 
 
     char song_name[MUS_SONG_NAME_LEN + 1];
     char song_name[MUS_SONG_NAME_LEN + 1];
     uint8_t speed, rate;
     uint8_t speed, rate;
@@ -154,11 +154,9 @@ typedef struct
     TrackerSong *song;
     TrackerSong *song;
     SoundEngine *sound_engine;
     SoundEngine *sound_engine;
 
 
-    uint8_t pattern_position, sequence_position, current_tick;
+    uint16_t pattern_position, sequence_position, current_tick;
     uint16_t absolute_position; // sequence_position * pattern_length + pattern_position
     uint16_t absolute_position; // sequence_position * pattern_length + pattern_position
 
 
-    uint8_t pattern_length;
-
     uint8_t speed, rate;
     uint8_t speed, rate;
     uint8_t master_volume;
     uint8_t master_volume;
 
 

+ 29 - 6
util.c

@@ -75,13 +75,11 @@ bool is_pattern_empty(TrackerSong *song, uint8_t pattern)
     return true;
     return true;
 }
 }
 
 
-void set_empty_pattern(TrackerSong *song, uint8_t pattern)
+void set_empty_pattern(TrackerSongPattern* pattern, uint16_t pattern_length)
 {
 {
-    TrackerSongPattern song_pattern = song->pattern[pattern];
-
-    for (int i = 0; i < song->pattern_length; i++)
+    for (uint16_t i = 0; i < pattern_length; i++)
     {
     {
-        TrackerSongPatternStep *step = &song_pattern.step[i];
+        TrackerSongPatternStep *step = &pattern->step[i];
 
 
         set_note(step, MUS_NOTE_NONE);
         set_note(step, MUS_NOTE_NONE);
         set_instrument(step, MUS_NOTE_INSTRUMENT_NONE);
         set_instrument(step, MUS_NOTE_INSTRUMENT_NONE);
@@ -105,7 +103,7 @@ bool check_and_allocate_pattern(TrackerSong *song, uint8_t pattern)
         if (!(is_pattern_empty(song, pattern - 1))) // don't let the user flood the song with empty patterns
         if (!(is_pattern_empty(song, pattern - 1))) // don't let the user flood the song with empty patterns
         {
         {
             song->pattern[pattern].step = malloc(sizeof(TrackerSongPatternStep) * song->pattern_length);
             song->pattern[pattern].step = malloc(sizeof(TrackerSongPatternStep) * song->pattern_length);
-            set_empty_pattern(song, pattern);
+            set_empty_pattern(&song->pattern[pattern], song->pattern_length);
             song->num_patterns++;
             song->num_patterns++;
             return true;
             return true;
         }
         }
@@ -115,4 +113,29 @@ bool check_and_allocate_pattern(TrackerSong *song, uint8_t pattern)
             return false;
             return false;
         }
         }
     }
     }
+}
+
+void resize_pattern(TrackerSongPattern* pattern, uint16_t old_length, uint16_t new_length)
+{
+    TrackerSongPattern temp;
+    temp.step = malloc((new_length) * sizeof(TrackerSongPatternStep));
+
+    set_empty_pattern(&temp, new_length);
+    memcpy(temp.step, pattern->step, fmin(old_length, new_length) * sizeof(TrackerSongPatternStep));
+
+    free(pattern->step);
+    pattern->step = temp.step;
+}
+
+void change_pattern_length(TrackerSong* song, uint16_t new_length)
+{
+    for(int i = 0; i < MAX_PATTERNS; i++)
+    {
+        if(song->pattern[i].step)
+        {
+            resize_pattern(&song->pattern[i], song->pattern_length, new_length);
+        }
+    }
+
+    song->pattern_length = new_length;
 }
 }

+ 3 - 2
util.h

@@ -21,6 +21,7 @@ void set_command(TrackerSongPatternStep *step, uint16_t command);
 void play_song(FlizzerTrackerApp *tracker, bool from_cursor);
 void play_song(FlizzerTrackerApp *tracker, bool from_cursor);
 void stop_song(FlizzerTrackerApp *tracker);
 void stop_song(FlizzerTrackerApp *tracker);
 
 
-void set_empty_pattern(TrackerSong *song, uint8_t pattern);
+void set_empty_pattern(TrackerSongPattern* pattern, uint16_t pattern_length);
 bool is_pattern_empty(TrackerSong *song, uint8_t pattern);
 bool is_pattern_empty(TrackerSong *song, uint8_t pattern);
-bool check_and_allocate_pattern(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);

+ 80 - 6
view/instrument_editor.c

@@ -26,7 +26,7 @@ void draw_inst_text_one_digit(FlizzerTrackerApp *tracker, Canvas *canvas, uint8_
 {
 {
     canvas_draw_str(canvas, x, y, text);
     canvas_draw_str(canvas, x, y, text);
     char buffer[4];
     char buffer[4];
-    snprintf(buffer, sizeof(buffer), "%01X", value);
+    snprintf(buffer, sizeof(buffer), "%01X", (value & 0xF));
     canvas_draw_str(canvas, x + strlen(text) * 4 - 2, y, buffer);
     canvas_draw_str(canvas, x + strlen(text) * 4 - 2, y, buffer);
 
 
     if (tracker->focus == focus && tracker->selected_param == param && tracker->editing)
     if (tracker->focus == focus && tracker->selected_param == param && tracker->editing)
@@ -56,21 +56,63 @@ static const char *filter_types[] =
         "BAND",
         "BAND",
 };
 };
 
 
+static const char *instrument_editor_params_description[] =
+    {
+        "CURRENT INSTRUMENT",
+        "CURRENT INSTRUMENT NAME",
+        "INSTRUMENT BASE NOTE",
+        "INSTRUMENT FINETUNE",
+        "SLIDE SPEED",
+        "SET PULSE WIDTH ON KEYDOWN",
+        "PULSE WIDTH",
+        "SET FILTER PARAMETERS ON KEYDOWN",
+        "NOISE WAVEFORM",
+        "PULSE WAVEFORM",
+        "TRIANGLE WAVEFORM",
+        "SAWTOOTH WAVEFORM",
+        "METALLIC NOISE WAVEFORM",
+        "SINE WAVEFORM",
+        "ENVELOPE ATTACK",
+        "ENVELOPE DECAY",
+        "ENVELOPE SUSTAIN",
+        "ENVELOPE RELEASE",
+        "ENVELOPE VOLUME",
+        "ENABLE FILTER",
+        "FILTER CUTOFF FREQUENCY",
+        "FILTER RESONANCE",
+        "FILTER TYPE (NONE=OFF)",
+        "ENABLE RING MODULATION",
+        "RINGMOD SOURCE CHANNEL (F=SELF)",
+        "ENABLE HARD SYNC",
+        "HARDSYNC SOURCE CHANNEL (F=SELF)",
+        "RETRIGGER INSTRUMENT ON SLIDE",
+        "SYNC OSCLLATORS ON KEYDOWN",
+        "ENABLE VIBRATO",
+        "VIBRATO SPEED",
+        "VIBRATO DEPTH",
+        "VIBRATO DELAY (IN TICKS)",
+        "ENABLE PWM",
+        "PWM SPEED",
+        "PWM DEPTH",
+        "PWM DELAY (IN TICKS)",
+        "PROG.PERIOD (00 ACTS SAME AS 01)",
+};
+
 void draw_instrument_view(Canvas *canvas, FlizzerTrackerApp *tracker)
 void draw_instrument_view(Canvas *canvas, FlizzerTrackerApp *tracker)
 {
 {
     SoundEngineChannel *se_channel = &tracker->sound_engine.channel[0];
     SoundEngineChannel *se_channel = &tracker->sound_engine.channel[0];
-    if (!(se_channel->flags & SE_ENABLE_GATE))
+    if (!(se_channel->flags & SE_ENABLE_GATE) && tracker->tracker_engine.song == NULL)
     {
     {
         stop();
         stop();
         tracker->tracker_engine.playing = false;
         tracker->tracker_engine.playing = false;
         tracker_engine_set_song(&tracker->tracker_engine, &tracker->song);
         tracker_engine_set_song(&tracker->tracker_engine, &tracker->song);
     }
     }
 
 
-    char buffer[20];
+    char buffer[30];
     Instrument *inst = tracker->song.instrument[tracker->current_instrument];
     Instrument *inst = tracker->song.instrument[tracker->current_instrument];
     uint8_t shift = tracker->inst_editor_shift;
     uint8_t shift = tracker->inst_editor_shift;
 
 
-    if (shift < 6)
+    if (shift == 0)
     {
     {
         snprintf(buffer, sizeof(buffer), "INST:%c", to_char(tracker->current_instrument));
         snprintf(buffer, sizeof(buffer), "INST:%c", to_char(tracker->current_instrument));
         draw_generic_n_digit_field(tracker, canvas, EDIT_INSTRUMENT, INST_CURRENTINSTRUMENT, buffer, 0, 5 - shift, 1);
         draw_generic_n_digit_field(tracker, canvas, EDIT_INSTRUMENT, INST_CURRENTINSTRUMENT, buffer, 0, 5 - shift, 1);
@@ -79,7 +121,7 @@ void draw_instrument_view(Canvas *canvas, FlizzerTrackerApp *tracker)
     }
     }
 
 
     snprintf(buffer, sizeof(buffer), "NOTE:%s", notename(inst->base_note));
     snprintf(buffer, sizeof(buffer), "NOTE:%s", notename(inst->base_note));
-    canvas_draw_str(canvas, 0, 11, buffer);
+    canvas_draw_str(canvas, 0, 11 - shift, buffer);
 
 
     if (tracker->editing && tracker->focus == EDIT_INSTRUMENT && tracker->selected_param == INST_CURRENT_NOTE)
     if (tracker->editing && tracker->focus == EDIT_INSTRUMENT && tracker->selected_param == INST_CURRENT_NOTE)
     {
     {
@@ -95,7 +137,7 @@ void draw_instrument_view(Canvas *canvas, FlizzerTrackerApp *tracker)
     }
     }
 
 
     snprintf(buffer, sizeof(buffer), "FINE:%+02d", inst->finetune);
     snprintf(buffer, sizeof(buffer), "FINE:%+02d", inst->finetune);
-    canvas_draw_str(canvas, 37, 11, buffer);
+    canvas_draw_str(canvas, 37, 11 - shift, buffer);
 
 
     if (tracker->editing && tracker->focus == EDIT_INSTRUMENT && tracker->selected_param == INST_FINETUNE)
     if (tracker->editing && tracker->focus == EDIT_INSTRUMENT && tracker->selected_param == INST_FINETUNE)
     {
     {
@@ -140,6 +182,38 @@ void draw_instrument_view(Canvas *canvas, FlizzerTrackerApp *tracker)
     {
     {
         canvas_draw_box(canvas, 19, 35 - shift, strlen(filter_types[inst->filter_type]) * 4 + 1, 7);
         canvas_draw_box(canvas, 19, 35 - shift, strlen(filter_types[inst->filter_type]) * 4 + 1, 7);
     }
     }
+
+    draw_inst_flag(tracker, canvas, EDIT_INSTRUMENT, INST_ENABLERINGMOD, "R:", 38, 41 - shift, inst->sound_engine_flags, SE_ENABLE_RING_MOD);
+    draw_inst_text_one_digit(tracker, canvas, EDIT_INSTRUMENT, INST_RINGMODSRC, "", 52, 41 - shift, inst->ring_mod);
+    draw_inst_flag(tracker, canvas, EDIT_INSTRUMENT, INST_ENABLEHARDSYNC, "H:", 56, 41 - shift, inst->sound_engine_flags, SE_ENABLE_HARD_SYNC);
+    draw_inst_text_one_digit(tracker, canvas, EDIT_INSTRUMENT, INST_HARDSYNCSRC, "", 70, 41 - shift, inst->hard_sync);
+
+    draw_inst_flag(tracker, canvas, EDIT_INSTRUMENT, INST_RETRIGGERONSLIDE, "SL.RETRIG", 0, 47 - shift, inst->flags, TE_RETRIGGER_ON_SLIDE);
+    draw_inst_flag(tracker, canvas, EDIT_INSTRUMENT, INST_ENABLEKEYSYNC, "KSYNC", 44, 47 - shift, inst->sound_engine_flags, SE_ENABLE_KEYDOWN_SYNC);
+
+    draw_inst_flag(tracker, canvas, EDIT_INSTRUMENT, INST_ENABLEVIBRATO, "VIB", 0, 53 - shift, inst->flags, TE_ENABLE_VIBRATO);
+    draw_inst_text_two_digits(tracker, canvas, EDIT_INSTRUMENT, INST_VIBRATOSPEED, "S:", 20, 53 - shift, inst->vibrato_speed);
+    draw_inst_text_two_digits(tracker, canvas, EDIT_INSTRUMENT, INST_VIBRATODEPTH, "D:", 36, 53 - shift, inst->vibrato_depth);
+    draw_inst_text_two_digits(tracker, canvas, EDIT_INSTRUMENT, INST_VIBRATODELAY, "DEL:", 52, 53 - shift, inst->vibrato_delay);
+
+    if (shift >= 6)
+    {
+        draw_inst_flag(tracker, canvas, EDIT_INSTRUMENT, INST_ENABLEPWM, "PWM", 0, 59 - shift, inst->flags, TE_ENABLE_PWM);
+        draw_inst_text_two_digits(tracker, canvas, EDIT_INSTRUMENT, INST_PWMSPEED, "S:", 20, 59 - shift, inst->pwm_speed);
+        draw_inst_text_two_digits(tracker, canvas, EDIT_INSTRUMENT, INST_PWMDEPTH, "D:", 36, 59 - shift, inst->pwm_depth);
+        draw_inst_text_two_digits(tracker, canvas, EDIT_INSTRUMENT, INST_PWMDELAY, "DEL:", 52, 59 - shift, inst->pwm_delay);
+    }
+
+    draw_inst_text_two_digits(tracker, canvas, EDIT_INSTRUMENT, INST_PROGRAMEPERIOD, "P.PERIOD:", 84, 56, inst->program_period);
+
+    canvas_draw_line(canvas, 0, 57, 127, 57);
+    canvas_draw_line(canvas, 82, 0, 82, 56);
+    canvas_draw_line(canvas, 83, 49, 127, 49);
+
+    if (tracker->focus == EDIT_INSTRUMENT)
+    {
+        canvas_draw_str(canvas, 0, 64, instrument_editor_params_description[tracker->selected_param]);
+    }
 }
 }
 
 
 void draw_instrument_program_view(Canvas *canvas, FlizzerTrackerApp *tracker)
 void draw_instrument_program_view(Canvas *canvas, FlizzerTrackerApp *tracker)

+ 23 - 10
view/pattern_editor.c

@@ -100,9 +100,9 @@ void draw_pattern_view(Canvas *canvas, FlizzerTrackerApp *tracker)
     {
     {
         uint8_t sequence_position = tracker->tracker_engine.sequence_position;
         uint8_t sequence_position = tracker->tracker_engine.sequence_position;
         uint8_t current_pattern = tracker->tracker_engine.song->sequence.sequence_step[sequence_position].pattern_indices[i];
         uint8_t current_pattern = tracker->tracker_engine.song->sequence.sequence_step[sequence_position].pattern_indices[i];
-        uint8_t pattern_step = tracker->tracker_engine.pattern_position;
+        uint16_t pattern_step = tracker->tracker_engine.pattern_position;
 
 
-        uint8_t pattern_length = tracker->tracker_engine.song->pattern_length;
+        uint16_t pattern_length = tracker->tracker_engine.song->pattern_length;
 
 
         TrackerSongPattern *pattern = &tracker->tracker_engine.song->pattern[current_pattern];
         TrackerSongPattern *pattern = &tracker->tracker_engine.song->pattern[current_pattern];
 
 
@@ -163,8 +163,8 @@ void draw_pattern_view(Canvas *canvas, FlizzerTrackerApp *tracker)
 
 
     if (tracker->editing && tracker->focus == EDIT_PATTERN)
     if (tracker->editing && tracker->focus == EDIT_PATTERN)
     {
     {
-        uint8_t x = tracker->current_channel * 32 + tracker->patternx * 4 + (tracker->patternx > 0 ? 4 : 0) - 1;
-        uint8_t y = PATTERN_EDITOR_Y + 6 * 2 + 1;
+        uint16_t x = tracker->current_channel * 32 + tracker->patternx * 4 + (tracker->patternx > 0 ? 4 : 0) - 1;
+        uint16_t y = PATTERN_EDITOR_Y + 6 * 2 + 1;
 
 
         canvas_draw_box(canvas, x, y, (tracker->patternx > 0 ? 5 : 9), 7);
         canvas_draw_box(canvas, x, y, (tracker->patternx > 0 ? 5 : 9), 7);
     }
     }
@@ -179,6 +179,19 @@ void draw_pattern_view(Canvas *canvas, FlizzerTrackerApp *tracker)
         }
         }
     }
     }
 
 
+    for (int i = 0; i < SONG_MAX_CHANNELS; ++i)
+    {
+        if(tracker->tracker_engine.channel[i].channel_flags & TEC_DISABLED)
+        {
+            canvas_draw_icon(canvas, 13 + 32 * i, PATTERN_EDITOR_Y - 3, &I_channel_off);
+        }
+
+        else
+        {
+            canvas_draw_icon(canvas, 13 + 32 * i, PATTERN_EDITOR_Y - 3, &I_channel_on);
+        }
+    }
+
     canvas_set_color(canvas, ColorXOR);
     canvas_set_color(canvas, ColorXOR);
 }
 }
 
 
@@ -317,12 +330,12 @@ void draw_songinfo_view(Canvas *canvas, FlizzerTrackerApp *tracker)
     uint32_t free_bytes = memmgr_get_free_heap();
     uint32_t free_bytes = memmgr_get_free_heap();
     canvas_draw_line(canvas, 128 - 4 * 10 - 2, 0, 128 - 4 * 10 - 2, 10);
     canvas_draw_line(canvas, 128 - 4 * 10 - 2, 0, 128 - 4 * 10 - 2, 10);
 
 
-    char song_size_buffer[12];
-    char free_bytes_buffer[12];
+    char song_size_buffer[19];
+    char free_bytes_buffer[19];
 
 
-    if (song_size > 999)
+    if (song_size > 9999)
     {
     {
-        snprintf(song_size_buffer, sizeof(song_size_buffer), "TUNE:%.1fK", (double)song_size / (double)1024.0);
+        snprintf(song_size_buffer, sizeof(song_size_buffer), "TUNE:%ld%c%01ldK", song_size / 1024, '.', (song_size % 1024) / 103);
     }
     }
 
 
     else
     else
@@ -330,9 +343,9 @@ void draw_songinfo_view(Canvas *canvas, FlizzerTrackerApp *tracker)
         snprintf(song_size_buffer, sizeof(song_size_buffer), "TUNE:%ld", song_size);
         snprintf(song_size_buffer, sizeof(song_size_buffer), "TUNE:%ld", song_size);
     }
     }
 
 
-    if (free_bytes > 999)
+    if (free_bytes > 9999)
     {
     {
-        snprintf(free_bytes_buffer, sizeof(song_size_buffer), "FREE:%.1fK", (double)free_bytes / (double)1024.0);
+        snprintf(free_bytes_buffer, sizeof(song_size_buffer), "FREE:%ld%c%01ldK", free_bytes / 1024, '.', (free_bytes % 1024) / 103);
     }
     }
 
 
     else
     else