Browse Source

tinier font, song and instrument name editing

LTVA1 3 years ago
parent
commit
d392c94a99

+ 36 - 29
flizzer_tracker.c

@@ -2,8 +2,8 @@
 #include "init_deinit.h"
 #include "input_event.h"
 #include "util.h"
-#include "view/pattern_editor.h"
 #include "view/instrument_editor.h"
+#include "view/pattern_editor.h"
 
 #define FLIZZER_TRACKER_FOLDER "/ext/flizzer_tracker"
 
@@ -15,30 +15,23 @@ Copyright:
 Glyphs: 95/203
 BBX Build Mode: 0
 */
-const uint8_t u8g2_font_tom_thumb_4x6_tr[725] U8G2_FONT_SECTION("u8g2_font_tom_thumb_4x6_tr") =
-    "_\0\2\2\2\3\3\4\4\3\6\0\377\5\377\5\0\0\352\1\330\2\270 \5\340\315\0!\6\265\310"
-    "\254\0\42\6\213\313$\25#\10\227\310\244\241\206\12$\10\227\310\215\70b\2%\10\227\310d\324F\1"
-    "&\10\227\310(\65R\22'\5\251\313\10(\6\266\310\251\62)\10\226\310\304\224\24\0*\6\217\312\244"
-    "\16+\7\217\311\245\225\0,\6\212\310)\0-\5\207\312\14.\5\245\310\4/\7\227\310Ve\4\60"
-    "\7\227\310-k\1\61\6\226\310\255\6\62\10\227\310h\220\312\1\63\11\227\310h\220\62X\0\64\10\227"
-    "\310$\65b\1\65\10\227\310\214\250\301\2\66\10\227\310\315\221F\0\67\10\227\310\314TF\0\70\10\227"
-    "\310\214\64\324\10\71\10\227\310\214\64\342\2:\6\255\311\244\0;\7\222\310e\240\0<\10\227\310\246\32"
-    "d\20=\6\217\311l\60>\11\227\310d\220A*\1\77\10\227\310\314\224a\2@\10\227\310UC\3"
-    "\1A\10\227\310UC\251\0B\10\227\310\250\264\322\2C\7\227\310\315\32\10D\10\227\310\250d-\0"
-    "E\10\227\310\214\70\342\0F\10\227\310\214\70b\4G\10\227\310\315\221\222\0H\10\227\310$\65\224\12"
-    "I\7\227\310\254X\15J\7\227\310\226\252\2K\10\227\310$\265\222\12L\7\227\310\304\346\0M\10\227"
-    "\310\244\61\224\12N\10\227\310\244q\250\0O\7\227\310UV\5P\10\227\310\250\264b\4Q\10\227\310"
-    "Uj$\1R\10\227\310\250\64V\1S\10\227\310m\220\301\2T\7\227\310\254\330\2U\7\227\310$"
-    "W\22V\10\227\310$\253L\0W\10\227\310$\65\206\12X\10\227\310$\325R\1Y\10\227\310$U"
-    "V\0Z\7\227\310\314T\16[\7\227\310\214X\16\134\10\217\311d\220A\0]\7\227\310\314r\4^"
-    "\5\213\313\65_\5\207\310\14`\6\212\313\304\0a\7\223\310\310\65\2b\10\227\310D\225\324\2c\7"
-    "\223\310\315\14\4d\10\227\310\246\245\222\0e\6\223\310\235\2f\10\227\310\246\264b\2g\10\227\307\35"
-    "\61%\0h\10\227\310D\225\254\0i\6\265\310\244\1j\10\233\307f\30U\5k\10\227\310\304\264T"
-    "\1l\7\227\310\310\326\0m\7\223\310<R\0n\7\223\310\250d\5o\7\223\310U\252\2p\10\227"
-    "\307\250\244V\4q\10\227\307-\225d\0r\6\223\310\315\22s\10\223\310\215\70\22\0t\10\227\310\245"
-    "\25\243\0u\7\223\310$+\11v\10\223\310$\65R\2w\7\223\310\244q\4x\7\223\310\244\62\25"
-    "y\11\227\307$\225dJ\0z\7\223\310\254\221\6{\10\227\310\251\32D\1|\6\265\310(\1}\11"
-    "\227\310\310\14RR\0~\6\213\313\215\4\0\0\0\4\377\377\0";
+// this is a modified version with dot and semicolon moved 1 pixel to the left; lowercase symbols removed
+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+"
+    "\42\6\313\63I\5#\10W\62i\250\241\2$\10Wr#\216\230\0%\10W\62\31\265Q\0&\10"
+    "W\62J\215\224\4'\5\351\63\2(\6vr\252\14)\7V\62\61%\5*\6O\63\251\3+\7"
+    "\317ri%\0,\5Jr\12-\5G\63\3.\5E\62\1/\7W\262U\31\1\60\7Wr\313"
+    "Z\0\61\6Vr\253\1\62\7W\62\32\244r\63\11W\62\32\244\14\26\0\64\7W\62I\215X\65"
+    "\10W\62#j\260\0\66\7Wrs\244\21\67\7W\62\63\225\21\70\10W\62#\15\65\2\71\10W"
+    "\62#\215\270\0:\5\315\62);\7Rr\31(\0<\10W\262\251\6\31\4=\6\317\62\33\14>"
+    "\11W\62\31d\220J\0?\10W\62\63e\230\0@\7Wr\325\320@A\7Wr\325P*B\10"
+    "W\62*\255\264\0C\7Wr\263\6\2D\7W\62*Y\13E\7W\62#\216\70F\10W\62#"
+    "\216\30\1G\7Wrs\244$H\10W\62I\15\245\2I\7W\62+V\3J\7W\262\245\252\0"
+    "K\10W\62I\255\244\2L\6W\62\261\71M\10W\62i\14\245\2N\7W\62i\34*O\7W"
+    "r\225U\1P\10W\62*\255\30\1Q\7Wr\225\32IR\7W\62*\215US\10Wr\33d"
+    "\260\0T\7W\62+\266\0U\7W\62\311\225\4V\10W\62\311*\23\0W\10W\62I\215\241\2"
+    "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";
 
 static void draw_callback(Canvas *canvas, void *ctx)
 {
@@ -136,14 +129,19 @@ int32_t flizzer_tracker_app(void *p)
 
     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, 0, tracker->tracker_view->view);
+    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);
+    with_view_model(
+        tracker->tracker_view->view, TrackerViewModel * model, { model->tracker = tracker; }, true);
+
+    view_dispatcher_switch_to_view(tracker->view_dispatcher, VIEW_TRACKER);
 
-    view_dispatcher_switch_to_view(tracker->view_dispatcher, 0);
+    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);
@@ -213,6 +211,10 @@ int32_t flizzer_tracker_app(void *p)
     tracker->song.instrument[0]->adsr.volume = 0x80;
     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 | 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]->adsr.a = 0x0;
     tracker->song.instrument[1]->adsr.d = 0x3;
@@ -245,8 +247,13 @@ int32_t flizzer_tracker_app(void *p)
     // Специальная очистка памяти, занимаемой очередью
     furi_message_queue_free(tracker->event_queue);
 
-    view_dispatcher_remove_view(tracker->view_dispatcher, 0);
+    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);
 

+ 11 - 0
flizzer_tracker.h

@@ -9,6 +9,7 @@
 #include <u8g2_glue.h>
 
 #include <gui/view_dispatcher.h>
+#include <gui/modules/text_input.h>
 
 #include "flizzer_tracker_hal.h"
 #include "sound_engine/freqs.h"
@@ -56,6 +57,7 @@ typedef enum
     SI_MASTERVOL,
 
     SI_SONGNAME,
+    SI_CURRENTINSTRUMENT,
     SI_INSTRUMENTNAME,
     /* ========  */
     SI_PARAMS,
@@ -67,6 +69,14 @@ typedef struct
     void *context;
 } TrackerView;
 
+typedef enum
+{
+    VIEW_TRACKER,
+    VIEW_KEYBOARD,
+    VIEW_FILE_MANAGER,
+    VIEW_SUBMENU,
+} FlizzerTrackerViews;
+
 typedef struct
 {
     NotificationApp *notification;
@@ -74,6 +84,7 @@ typedef struct
     Gui *gui;
     TrackerView *tracker_view;
     ViewDispatcher *view_dispatcher;
+    TextInput* text_input;
     bool was_it_back_keypress;
     uint32_t current_time;
     uint32_t period;

+ 4 - 3
flizzer_tracker_hal.c

@@ -73,7 +73,7 @@ void sound_engine_timer_init(uint32_t sample_rate) // external audio on pin PA6
     LL_TIM_InitTypeDef TIM_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.CounterMode = LL_TIM_COUNTERMODE_UP;
     LL_TIM_Init(SAMPLE_RATE_TIMER, &TIM_InitStruct);
@@ -90,7 +90,7 @@ void tracker_engine_timer_init(uint8_t rate) // 0-255 hz
     LL_TIM_InitTypeDef TIM_InitStruct = {0};
     LL_TIM_OC_InitTypeDef TIM_OC_InitStruct = {0};
 
-    TIM_InitStruct.Prescaler = 0; //using 32-bit timer
+    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.CounterMode = LL_TIM_COUNTERMODE_UP;
     LL_TIM_Init(TRACKER_ENGINE_TIMER, &TIM_InitStruct);
@@ -106,7 +106,7 @@ void tracker_engine_set_rate(uint8_t rate)
 {
     LL_TIM_InitTypeDef TIM_InitStruct = {0};
 
-    TIM_InitStruct.Prescaler = 0; //using 32-bit timer
+    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.CounterMode = LL_TIM_COUNTERMODE_UP;
     LL_TIM_Init(TRACKER_ENGINE_TIMER, &TIM_InitStruct);
@@ -164,6 +164,7 @@ void sound_engine_start()
 
 void sound_engine_stop()
 {
+    LL_TIM_DisableAllOutputs(SAMPLE_RATE_TIMER);
     LL_TIM_DisableCounter(SAMPLE_RATE_TIMER);
 
     sound_engine_dma_stop();

+ 5 - 4
input/pattern.c

@@ -20,9 +20,9 @@ void edit_note(FlizzerTrackerApp *tracker, TrackerSongPatternStep *step, int8_t
 {
     int16_t note = tracker_engine_get_note(step);
 
-    if(note == MUS_NOTE_RELEASE)
+    if (note == MUS_NOTE_RELEASE)
     {
-        if(delta < 0)
+        if (delta < 0)
         {
             set_note(step, MUS_NOTE_CUT);
         }
@@ -30,9 +30,9 @@ void edit_note(FlizzerTrackerApp *tracker, TrackerSongPatternStep *step, int8_t
         return;
     }
 
-    if(note == MUS_NOTE_CUT)
+    if (note == MUS_NOTE_CUT)
     {
-        if(delta > 0)
+        if (delta > 0)
         {
             set_note(step, MUS_NOTE_RELEASE);
         }
@@ -48,6 +48,7 @@ void edit_note(FlizzerTrackerApp *tracker, TrackerSongPatternStep *step, int8_t
     clamp(note, delta, 0, MAX_NOTE);
 
     set_note(step, (uint8_t)note);
+    set_instrument(step, tracker->current_instrument);
 
     tracker->current_note = (uint8_t)note;
 }

+ 137 - 15
input/songinfo.c

@@ -1,6 +1,43 @@
 #include "songinfo.h"
 
-#include <gui/modules/text_input.h>
+#include <ctype.h>
+
+void return_from_keyboard_callback(void* ctx)
+{
+    FlizzerTrackerApp *tracker = (FlizzerTrackerApp*)ctx;
+
+    uint8_t string_length = 0;
+    char* string = NULL;
+
+    if(tracker->focus == EDIT_SONGINFO && tracker->mode == PATTERN_VIEW)
+    {
+        switch(tracker->selected_param)
+        {
+            case SI_SONGNAME:
+            {
+                string_length = MUS_SONG_NAME_LEN;
+                string = (char*)&tracker->song.song_name;
+                break;
+            }
+
+            case SI_INSTRUMENTNAME:
+            {
+                string_length = MUS_INST_NAME_LEN;
+                string = (char*)&tracker->song.instrument[tracker->current_instrument]->name;
+                break;
+            }
+        }
+    }
+
+    if(string == NULL || string_length == 0) return;
+
+    for(uint8_t i = 0; i < string_length; i++) //I tinyfied the font by deleting lowercase chars, and I don't like the lowercase chars of any 3x5 pixels font
+    {
+        string[i] = toupper(string[i]);
+    }
+    
+    view_dispatcher_switch_to_view(tracker->view_dispatcher, VIEW_TRACKER);
+}
 
 void edit_songinfo_param(FlizzerTrackerApp *tracker, uint8_t selected_param, int8_t delta)
 {
@@ -63,6 +100,43 @@ void edit_songinfo_param(FlizzerTrackerApp *tracker, uint8_t selected_param, int
 
         case SI_SONGNAME:
         {
+            text_input_set_header_text(tracker->text_input, "Song name:");
+            text_input_set_result_callback(tracker->text_input, return_from_keyboard_callback, tracker, (char*)&tracker->song.song_name, MUS_SONG_NAME_LEN + 1, false);
+
+            view_dispatcher_switch_to_view(tracker->view_dispatcher, VIEW_KEYBOARD);
+            break;
+        }
+
+        case SI_CURRENTINSTRUMENT:
+        {
+            int16_t inst = tracker->current_instrument;
+
+            if (inst + delta >= MUS_NOTE_INSTRUMENT_NONE)
+            {
+                if (delta > 0)
+                {
+                    inst = 0;
+                }
+
+                else
+                {
+                    inst = MUS_NOTE_INSTRUMENT_NONE - 1;
+                }
+            }
+
+            clamp(inst, delta, 0, tracker->song.num_instruments - 1);
+
+            tracker->current_instrument = inst;
+
+            break;
+        }
+
+        case SI_INSTRUMENTNAME:
+        {
+            text_input_set_header_text(tracker->text_input, "Instrument name:");
+            text_input_set_result_callback(tracker->text_input, return_from_keyboard_callback, tracker, (char*)&tracker->song.instrument[tracker->current_instrument]->name, MUS_INST_NAME_LEN + 1, false);
+
+            view_dispatcher_switch_to_view(tracker->view_dispatcher, VIEW_KEYBOARD);
             break;
         }
 
@@ -80,34 +154,82 @@ void songinfo_edit_event(FlizzerTrackerApp *tracker, FlizzerTrackerEvent *event)
 
     if (event->input.key == InputKeyRight && event->input.type == InputTypeShort && tracker->editing)
     {
-        tracker->current_digit++;
-
-        if (tracker->current_digit > 1)
+        switch(tracker->selected_param)
         {
-            tracker->selected_param++;
+            default:
+            {
+                tracker->current_digit++;
+
+                if (tracker->current_digit > 1)
+                {
+                    tracker->selected_param++;
+
+                    tracker->current_digit = 0;
+
+                    if (tracker->selected_param > SI_PARAMS - 1)
+                    {
+                        tracker->selected_param = 0;
+                    }
+                }
 
-            tracker->current_digit = 0;
+                break;
+            }
 
-            if (tracker->selected_param > SI_PARAMS - 1)
+            case SI_CURRENTINSTRUMENT:
+            case SI_SONGNAME:
+            case SI_INSTRUMENTNAME:
             {
-                tracker->selected_param = 0;
+                tracker->selected_param++;
+
+                tracker->current_digit = 0;
+
+                if (tracker->selected_param > SI_PARAMS - 1)
+                {
+                    tracker->selected_param = 0;
+                }
+
+                break;
             }
         }
     }
 
     if (event->input.key == InputKeyLeft && event->input.type == InputTypeShort && tracker->editing)
     {
-        tracker->current_digit--;
-
-        if (tracker->current_digit > 1) // unsigned int overflow
+        switch(tracker->selected_param)
         {
-            tracker->selected_param--;
+            default:
+            {
+                tracker->current_digit--;
+
+                if (tracker->current_digit > 1) // unsigned int overflow
+                {
+                    tracker->selected_param--;
 
-            tracker->current_digit = 1;
+                    tracker->current_digit = 1;
 
-            if (tracker->selected_param > SI_PARAMS - 1) // unsigned int overflow
+                    if (tracker->selected_param > SI_PARAMS - 1) // unsigned int overflow
+                    {
+                        tracker->selected_param = SI_PARAMS - 1;
+                    }
+                }
+
+                break;
+            }
+
+            case SI_CURRENTINSTRUMENT:
+            case SI_SONGNAME:
+            case SI_INSTRUMENTNAME:
             {
-                tracker->selected_param = SI_PARAMS - 1;
+                tracker->selected_param--;
+
+                tracker->current_digit = 0;
+
+                if (tracker->selected_param > SI_PARAMS - 1) // unsigned int overflow
+                {
+                    tracker->selected_param = SI_PARAMS - 1;
+                }
+
+                break;
             }
         }
     }

+ 2 - 2
input_event.h

@@ -9,10 +9,10 @@
 #include "tracker_engine/tracker_engine_defs.h"
 #include "util.h"
 
+#include "input/instrument.h"
+#include "input/instrument_program.h"
 #include "input/pattern.h"
 #include "input/sequence.h"
 #include "input/songinfo.h"
-#include "input/instrument.h"
-#include "input/instrument_program.h"
 
 void process_input_event(FlizzerTrackerApp *tracker, FlizzerTrackerEvent *event);

+ 1 - 1
sound_engine/sound_engine_adsr.c

@@ -61,5 +61,5 @@ int32_t sound_engine_cycle_and_output_adsr(int32_t input, SoundEngine *eng, Soun
         }
     }
 
-    return (int32_t)((int64_t)input * (int32_t)adsr->envelope / (int32_t)MAX_ADSR * (int32_t)adsr->volume / (int32_t)MAX_ADSR_VOLUME);
+    return (int32_t)((int32_t)input * (int32_t)(adsr->envelope >> 10) / (int32_t)(MAX_ADSR >> 10) * (int32_t)adsr->volume / (int32_t)MAX_ADSR_VOLUME);
 }

+ 1 - 1
sound_engine/sound_engine_defs.h

@@ -19,7 +19,7 @@
 #define MAX_ADSR (0xff << 17)
 #define MAX_ADSR_VOLUME 0x80
 #define BASE_FREQ 22050
-#define envspd(eng, slope) ((slope) != 0 ? (((uint64_t)MAX_ADSR / ((slope) * (slope)*256 / 8)) * BASE_FREQ / eng->sample_rate) : ((uint64_t)MAX_ADSR * BASE_FREQ / eng->sample_rate))
+#define envspd(eng, slope) ((slope) != 0 ? (((uint64_t)MAX_ADSR / ((slope) * (slope) * 256 / 8)) * BASE_FREQ / eng->sample_rate) : ((uint64_t)MAX_ADSR * BASE_FREQ / eng->sample_rate))
 
 typedef enum
 {

+ 114 - 95
tracker_engine/tracker_engine.c

@@ -86,12 +86,10 @@ void tracker_engine_trigger_instrument_internal(TrackerEngine *tracker_engine, u
 
         te_channel->program_counter = 0;
         te_channel->program_loop = 0;
-        te_channel->program_period = 0;
+        te_channel->program_period = pinst->program_period;
         te_channel->program_tick = 0;
     }
 
-    te_channel->program_period = pinst->program_period;
-
     te_channel->instrument = pinst;
 
     se_channel->waveform = pinst->waveform;
@@ -102,21 +100,31 @@ void tracker_engine_trigger_instrument_internal(TrackerEngine *tracker_engine, u
     te_channel->arpeggio_note = 0;
     te_channel->fixed_note = 0xffff;
 
-    tracker_engine_set_note(tracker_engine, chan, note + (uint16_t)pinst->finetune, true);
+    tracker_engine_set_note(tracker_engine, chan, note + (int16_t)pinst->finetune, true);
 
-    te_channel->last_note = te_channel->target_note = note + (uint16_t)pinst->finetune;
+    te_channel->last_note = te_channel->target_note = note + (int16_t)pinst->finetune;
 
     if (pinst->sound_engine_flags & SE_ENABLE_KEYDOWN_SYNC)
     {
         te_channel->vibrato_position = te_channel->pwm_position = 0;
+        se_channel->accumulator = 0;
+        se_channel->lfsr = RANDOM_SEED;
     }
 
     if (pinst->flags & TE_SET_CUTOFF)
     {
-        te_channel->filter_cutoff = pinst->filter_cutoff;
+        te_channel->filter_cutoff = (pinst->filter_cutoff << 3);
         te_channel->filter_resonance = pinst->filter_resonance;
 
-        sound_engine_filter_set_coeff(&se_channel->filter, te_channel->filter_cutoff, (te_channel->filter_resonance << 5));
+        sound_engine_filter_set_coeff(&se_channel->filter, te_channel->filter_cutoff, te_channel->filter_resonance);
+    }
+
+    if(pinst->sound_engine_flags & SE_ENABLE_FILTER)
+    {
+        te_channel->filter_type = pinst->filter_type;
+        se_channel->filter_mode = te_channel->filter_type;
+        se_channel->filter_cutoff = te_channel->filter_cutoff;
+        se_channel->filter_resonace = te_channel->filter_resonance;
     }
 
     if (pinst->flags & TE_SET_PW)
@@ -152,14 +160,51 @@ void tracker_engine_execute_track_command(TrackerEngine *tracker_engine, uint8_t
     // TODO: add actual big ass function that executes commands; add arpeggio commands there
 }
 
+void tracker_engine_advance_channel(TrackerEngine *tracker_engine, uint8_t chan)
+{
+    SoundEngineChannel *se_channel = &tracker_engine->sound_engine->channel[chan];
+    TrackerEngineChannel *te_channel = &tracker_engine->channel[chan];
+
+    if (te_channel->flags & TEC_PLAYING)
+    {
+        if (!(se_channel->flags & SE_ENABLE_GATE))
+        {
+            te_channel->flags &= ~(TEC_PLAYING);
+        }
+
+        if (te_channel->slide_speed != 0)
+        {
+            if (te_channel->target_note > te_channel->note)
+            {
+                te_channel->target_note += fmin(te_channel->slide_speed, te_channel->target_note - te_channel->note);
+            }
+
+            else if (te_channel->target_note < te_channel->note)
+            {
+                te_channel->target_note -= fmin(te_channel->slide_speed, te_channel->note - te_channel->target_note);
+            }
+        }
+
+        // TODO: add instrument program execution
+
+        // TODO: add PWM and vibrato execution
+        uint8_t vib = 0;
+        int32_t chn_note = (te_channel->fixed_note != 0xffff ? te_channel->fixed_note : te_channel->note) + vib + ((int16_t)te_channel->arpeggio_note << 8);
+
+        if (chn_note < 0)
+            chn_note = 0;
+        if (chn_note > ((12 * 7 + 11) << 8))
+            chn_note = ((12 * 7 + 11) << 8); // highest note is B-7
+
+        tracker_engine_set_note(tracker_engine, chan, (uint16_t)chn_note, false);
+    }
+}
+
 void tracker_engine_advance_tick(TrackerEngine *tracker_engine)
 {
     if (!(tracker_engine->playing))
         return;
 
-    if (!(tracker_engine->song))
-        return;
-
     if (!(tracker_engine->sound_engine))
         return;
 
@@ -170,121 +215,95 @@ void tracker_engine_advance_tick(TrackerEngine *tracker_engine)
         SoundEngineChannel *se_channel = &tracker_engine->sound_engine->channel[chan];
         TrackerEngineChannel *te_channel = &tracker_engine->channel[chan];
 
-        uint8_t sequence_position = tracker_engine->sequence_position;
-        uint8_t current_pattern = song->sequence.sequence_step[sequence_position].pattern_indices[chan];
-        uint8_t pattern_step = tracker_engine->pattern_position;
-
-        TrackerSongPattern *pattern = &song->pattern[current_pattern];
-
-        uint8_t note_delay = 0; // TODO: add note delay command
-
-        if (tracker_engine->current_tick == note_delay)
+        if(tracker_engine->song)
         {
-            uint8_t note = tracker_engine_get_note(&pattern->step[pattern_step]);
-            uint8_t inst = tracker_engine_get_instrument(&pattern->step[pattern_step]);
-
-            Instrument *pinst = NULL;
-
-            if (inst == MUS_NOTE_INSTRUMENT_NONE)
-            {
-                pinst = te_channel->instrument;
-            }
+            uint8_t sequence_position = tracker_engine->sequence_position;
+            uint8_t current_pattern = song->sequence.sequence_step[sequence_position].pattern_indices[chan];
+            uint8_t pattern_step = tracker_engine->pattern_position;
 
-            else
-            {
-                if (inst < song->num_instruments)
-                {
-                    pinst = song->instrument[inst];
-                    te_channel->instrument = pinst;
-                }
-            }
+            TrackerSongPattern *pattern = &song->pattern[current_pattern];
 
-            // TODO: add note cut command
+            uint8_t note_delay = 0; // TODO: add note delay command
 
-            if (note == MUS_NOTE_RELEASE)
+            if (tracker_engine->current_tick == note_delay)
             {
-                sound_engine_enable_gate(tracker_engine->sound_engine, se_channel, 0);
-            }
-
-            else if (pinst && note != MUS_NOTE_RELEASE && note != MUS_NOTE_CUT && note != MUS_NOTE_NONE)
-            {
-                te_channel->slide_speed = 0;
-
-                // TODO: add setting slide speed if slide command is there
+                uint8_t note = tracker_engine_get_note(&pattern->step[pattern_step]);
+                uint8_t inst = tracker_engine_get_instrument(&pattern->step[pattern_step]);
 
-                // te_channel->slide_speed = pinst->slide_speed;
-
-                uint8_t prev_adsr_volume = se_channel->adsr.volume;
-
-                tracker_engine_trigger_instrument_internal(tracker_engine, chan, pinst, note << 8);
-                te_channel->note = (note << 8);
-
-                te_channel->target_note = (note << 8) + pinst->finetune;
+                Instrument *pinst = NULL;
 
                 if (inst == MUS_NOTE_INSTRUMENT_NONE)
                 {
-                    se_channel->adsr.volume = prev_adsr_volume;
+                    pinst = te_channel->instrument;
                 }
-            }
-        }
 
-        tracker_engine_execute_track_command(tracker_engine, chan, &pattern->step[pattern_step], tracker_engine->current_tick == note_delay);
+                else
+                {
+                    if (inst < song->num_instruments)
+                    {
+                        pinst = song->instrument[inst];
+                        te_channel->instrument = pinst;
+                    }
+                }
 
-        if (te_channel->flags & TEC_PLAYING)
-        {
-            if (!(se_channel->flags & SE_ENABLE_GATE))
-            {
-                te_channel->flags &= ~(TEC_PLAYING);
-            }
+                // TODO: add note cut command
 
-            if (te_channel->slide_speed != 0)
-            {
-                if (te_channel->target_note > te_channel->note)
+                if (note == MUS_NOTE_RELEASE)
                 {
-                    te_channel->target_note += fmin(te_channel->slide_speed, te_channel->target_note - te_channel->note);
+                    sound_engine_enable_gate(tracker_engine->sound_engine, se_channel, 0);
                 }
 
-                else if (te_channel->target_note < te_channel->note)
+                else if (pinst && note != MUS_NOTE_RELEASE && note != MUS_NOTE_CUT && note != MUS_NOTE_NONE)
                 {
-                    te_channel->target_note -= fmin(te_channel->slide_speed, te_channel->note - te_channel->target_note);
-                }
-            }
+                    te_channel->slide_speed = 0;
 
-            // TODO: add instrument program execution
+                    // TODO: add setting slide speed if slide command is there
 
-            // TODO: add PWM and vibrato execution
-            uint8_t vib = 0;
-            int32_t chn_note = (te_channel->fixed_note != 0xffff ? te_channel->fixed_note : te_channel->note) + vib + ((int16_t)te_channel->arpeggio_note << 8);
+                    // te_channel->slide_speed = pinst->slide_speed;
 
-            if (chn_note < 0)
-                chn_note = 0;
-            if (chn_note > ((12 * 7 + 11) << 8))
-                chn_note = ((12 * 7 + 11) << 8); // highest note is B-7
+                    uint8_t prev_adsr_volume = se_channel->adsr.volume;
 
-            tracker_engine_set_note(tracker_engine, chan, (uint16_t)chn_note, false);
+                    tracker_engine_trigger_instrument_internal(tracker_engine, chan, pinst, note << 8);
+                    te_channel->note = (note << 8);
+
+                    te_channel->target_note = (note << 8) + pinst->finetune;
+
+                    if (inst == MUS_NOTE_INSTRUMENT_NONE)
+                    {
+                        se_channel->adsr.volume = prev_adsr_volume;
+                    }
+                }
+            }
+
+            tracker_engine_execute_track_command(tracker_engine, chan, &pattern->step[pattern_step], tracker_engine->current_tick == note_delay);
         }
-    }
 
-    tracker_engine->current_tick++;
+        tracker_engine_advance_channel(tracker_engine, chan); //this will be executed even if the song pointer is NULL; handy for live instrument playback from inst editor ("jams")
+    }
 
-    if (tracker_engine->current_tick >= song->speed)
+    if(tracker_engine->song)
     {
-        // TODO: add pattern loop and pattern skip commands
+        tracker_engine->current_tick++;
 
-        tracker_engine->pattern_position++;
+        if (tracker_engine->current_tick >= song->speed)
+        {
+            // TODO: add pattern loop and pattern skip commands
 
-        tracker_engine->current_tick = 0;
+            tracker_engine->pattern_position++;
 
-        if (tracker_engine->pattern_position >= song->pattern_length)
-        {
-            tracker_engine->pattern_position = 0;
-            tracker_engine->sequence_position++;
+            tracker_engine->current_tick = 0;
 
-            if (tracker_engine->sequence_position >= song->num_sequence_steps)
+            if (tracker_engine->pattern_position >= song->pattern_length)
             {
-                tracker_engine->playing = false; // TODO: add song loop handling
-                tracker_engine->sequence_position--;
-                tracker_engine->pattern_position = song->pattern_length - 1;
+                tracker_engine->pattern_position = 0;
+                tracker_engine->sequence_position++;
+
+                if (tracker_engine->sequence_position >= song->num_sequence_steps)
+                {
+                    tracker_engine->playing = false; // TODO: add song loop handling
+                    tracker_engine->sequence_position--;
+                    tracker_engine->pattern_position = song->pattern_length - 1;
+                }
             }
         }
     }

+ 1 - 1
tracker_engine/tracker_engine_defs.h

@@ -12,7 +12,7 @@
 #define SONG_MAX_CHANNELS NUM_CHANNELS
 #define MAX_INSTRUMENTS 31
 #define MAX_PATTERN_LENGTH 256
-#define MAX_PATTERNS 64
+#define MAX_PATTERNS 256
 #define MAX_SEQUENCE_LENGTH 256
 
 #define MUS_NOTE_NONE 127

+ 22 - 13
view/pattern_editor.c

@@ -96,14 +96,6 @@ void draw_pattern_view(Canvas *canvas, FlizzerTrackerApp *tracker)
 
     canvas_draw_line(canvas, 0, PATTERN_EDITOR_Y, 127, PATTERN_EDITOR_Y);
 
-    for (int i = 1; i < SONG_MAX_CHANNELS; ++i)
-    {
-        for (int y = PATTERN_EDITOR_Y + 1; y < 64; y += 2)
-        {
-            canvas_draw_dot(canvas, i * 32 - 1, y);
-        }
-    }
-
     for (int i = 0; i < SONG_MAX_CHANNELS; ++i)
     {
         uint8_t sequence_position = tracker->tracker_engine.sequence_position;
@@ -176,6 +168,18 @@ void draw_pattern_view(Canvas *canvas, FlizzerTrackerApp *tracker)
 
         canvas_draw_box(canvas, x, y, (tracker->patternx > 0 ? 5 : 9), 7);
     }
+
+    canvas_set_color(canvas, ColorBlack);
+
+    for (int i = 1; i < SONG_MAX_CHANNELS; ++i)
+    {
+        for (int y = PATTERN_EDITOR_Y + 1; y < 64; y += 2)
+        {
+            canvas_draw_dot(canvas, i * 32 - 1, y);
+        }
+    }
+
+    canvas_set_color(canvas, ColorXOR);
 }
 
 #define SEQ_SLIDER_X (4 * (4 * 2 + 1) + 2)
@@ -253,7 +257,7 @@ void draw_generic_n_digit_field(FlizzerTrackerApp *tracker, Canvas *canvas, uint
 
         else
         {
-            canvas_draw_box(canvas, x - 1, y - 6, strlen(text) * 4 + 2, 7);
+            canvas_draw_box(canvas, x - 1, y - 6, fmax(5, strlen(text) * 4 + 1), 7);
         }
     }
 }
@@ -273,10 +277,15 @@ void draw_songinfo_view(Canvas *canvas, FlizzerTrackerApp *tracker)
     snprintf(buffer, sizeof(buffer), "VOL %02X", tracker->tracker_engine.master_volume);
     draw_generic_n_digit_field(tracker, canvas, EDIT_SONGINFO, SI_MASTERVOL, buffer, 42 + 4 * 7 + 4 * 8, 17, 2);
 
-    snprintf(buffer, sizeof(buffer), "SONG:%s", tracker->song.song_name);
-    draw_generic_n_digit_field(tracker, canvas, EDIT_SONGINFO, SI_SONGNAME, buffer, 42, 23, 1);
-    snprintf(buffer, sizeof(buffer), "INST:%s", tracker->song.instrument[tracker->current_instrument]->name);
-    draw_generic_n_digit_field(tracker, canvas, EDIT_SONGINFO, SI_INSTRUMENTNAME, buffer, 42, 29, 1);
+    snprintf(buffer, sizeof(buffer), "SONG:");
+    canvas_draw_str(canvas, 42, 23, buffer);
+    snprintf(buffer, sizeof(buffer), "%s", tracker->song.song_name);
+    draw_generic_n_digit_field(tracker, canvas, EDIT_SONGINFO, SI_SONGNAME, buffer, 42 + 4 * 5, 23, 1);
+
+    snprintf(buffer, sizeof(buffer), "INST:%c", to_char(tracker->current_instrument));
+    draw_generic_n_digit_field(tracker, canvas, EDIT_SONGINFO, SI_CURRENTINSTRUMENT, buffer, 42, 29, 1);
+    snprintf(buffer, sizeof(buffer), "%s", tracker->song.instrument[tracker->current_instrument]->name);
+    draw_generic_n_digit_field(tracker, canvas, EDIT_SONGINFO, SI_INSTRUMENTNAME, buffer, 42 + 4 * 7, 29, 1);
 
     uint32_t song_size = calculate_song_size(&tracker->song);
     uint32_t free_bytes = memmgr_get_free_heap();