소스 검색

Formatting, structuring, song loop points, finishing effects (for now).

The tracker is basically ready.
LTVA1 3 년 전
부모
커밋
639918a161
13개의 변경된 파일329개의 추가작업 그리고 37개의 파일을 삭제
  1. 1 24
      flizzer_tracker.c
  2. 25 0
      font.h
  3. 8 1
      input/instrument_program.c
  4. 30 0
      input/sequence.c
  5. 2 0
      macros.h
  6. 136 0
      tracker_engine/do_effects.c
  7. 20 3
      tracker_engine/tracker_engine.c
  8. 32 3
      tracker_engine/tracker_engine_defs.h
  9. 2 1
      util.c
  10. 3 1
      util.h
  11. 16 2
      view/instrument_editor.c
  12. 13 0
      view/opcode_description.c
  13. 41 2
      view/pattern_editor.c

+ 1 - 24
flizzer_tracker.c

@@ -6,32 +6,9 @@
 #include "view/instrument_editor.h"
 #include "view/instrument_editor.h"
 #include "view/pattern_editor.h"
 #include "view/pattern_editor.h"
 
 
+#include "font.h"
 #include <flizzer_tracker_icons.h>
 #include <flizzer_tracker_icons.h>
 
 
-/*
-Fontname: -Raccoon-Fixed4x6-Medium-R-Normal--6-60-75-75-P-40-ISO10646-1
-Copyright:
-Glyphs: 95/203
-BBX Build Mode: 0
-*/
-// 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] =
-    "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";
-
 void draw_callback(Canvas *canvas, void *ctx)
 void draw_callback(Canvas *canvas, void *ctx)
 {
 {
     TrackerViewModel *model = (TrackerViewModel *)ctx;
     TrackerViewModel *model = (TrackerViewModel *)ctx;

+ 25 - 0
font.h

@@ -0,0 +1,25 @@
+#include <stdint.h>
+
+/*
+Fontname: -Raccoon-Fixed4x6-Medium-R-Normal--6-60-75-75-P-40-ISO10646-1
+Copyright:
+Glyphs: 95/203
+BBX Build Mode: 0
+*/
+// 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] =
+    "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";

+ 8 - 1
input/instrument_program.c

@@ -1,4 +1,5 @@
 #include "instrument_program.h"
 #include "instrument_program.h"
+#include "../macros.h"
 
 
 void instrument_program_edit_event(FlizzerTrackerApp *tracker, FlizzerTrackerEvent *event)
 void instrument_program_edit_event(FlizzerTrackerApp *tracker, FlizzerTrackerEvent *event)
 {
 {
@@ -10,7 +11,7 @@ void instrument_program_edit_event(FlizzerTrackerApp *tracker, FlizzerTrackerEve
 
 
     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 = fmin(2, tracker->current_digit + 1);
+        tracker->current_digit = my_min(2, tracker->current_digit + 1);
         return;
         return;
     }
     }
 
 
@@ -199,6 +200,12 @@ void instrument_program_edit_event(FlizzerTrackerApp *tracker, FlizzerTrackerEve
                         inst->program[tracker->current_program_step] = TE_PROGRAM_END | (inst->program[tracker->current_program_step] & 0x8000);
                         inst->program[tracker->current_program_step] = TE_PROGRAM_END | (inst->program[tracker->current_program_step] & 0x8000);
                     }
                     }
 
 
+                    if ((inst->program[tracker->current_program_step] & 0x7f00) == (TE_PROGRAM_LOOP_BEGIN - 0x100))
+                    {
+                        // param = (TE_PROGRAM_END >> 8);
+                        inst->program[tracker->current_program_step] = TE_EFFECT_TRIGGER_RELEASE | (inst->program[tracker->current_program_step] & 0x8000);
+                    }
+
                     break;
                     break;
                 }
                 }
 
 

+ 30 - 0
input/sequence.c

@@ -158,6 +158,36 @@ void sequence_edit_event(FlizzerTrackerApp *tracker, FlizzerTrackerEvent *event)
         }
         }
     }
     }
 
 
+    if (event->input.key == InputKeyUp && event->input.type == InputTypeLong && !(tracker->editing)) // set loop begin or loop end for the song
+    {
+        TrackerSong *song = &tracker->song;
+
+        if (song->loop_start == song->loop_end && song->loop_end == 0) // if both are 0
+        {
+            song->loop_end = tracker->tracker_engine.sequence_position;
+        }
+
+        else
+        {
+            if (tracker->tracker_engine.sequence_position < song->loop_end)
+            {
+                song->loop_start = tracker->tracker_engine.sequence_position;
+            }
+
+            if (tracker->tracker_engine.sequence_position > song->loop_start)
+            {
+                song->loop_end = tracker->tracker_engine.sequence_position;
+            }
+        }
+    }
+
+    if (event->input.key == InputKeyDown && event->input.type == InputTypeLong && !(tracker->editing)) // erase loop begin and loop end points
+    {
+        TrackerSong *song = &tracker->song;
+
+        song->loop_start = song->loop_end = 0;
+    }
+
     if (event->input.key == InputKeyBack && event->input.type == InputTypeShort && tracker->editing)
     if (event->input.key == InputKeyBack && event->input.type == InputTypeShort && tracker->editing)
     {
     {
         delete_sequence_step(tracker);
         delete_sequence_step(tracker);

+ 2 - 0
macros.h

@@ -0,0 +1,2 @@
+#define my_min(a, b) (((a) < (b)) ? (a) : (b))
+#define my_max(a, b) (((a) > (b)) ? (a) : (b))

+ 136 - 0
tracker_engine/do_effects.c

@@ -1,6 +1,7 @@
 #include "do_effects.h"
 #include "do_effects.h"
 #include <furi.h>
 #include <furi.h>
 
 
+#include "../sound_engine/sound_engine.h"
 #include "../sound_engine/sound_engine_filter.h"
 #include "../sound_engine/sound_engine_filter.h"
 #include "tracker_engine.h"
 #include "tracker_engine.h"
 
 
@@ -246,6 +247,16 @@ void do_command(uint16_t opcode, TrackerEngine *tracker_engine, uint8_t channel,
                     break;
                     break;
                 }
                 }
 
 
+                case TE_EFFECT_EXT_FILTER_MODE:
+                {
+                    if (tick == 0)
+                    {
+                        se_channel->filter_mode = (opcode & 0xf);
+                    }
+
+                    break;
+                }
+
                 case TE_EFFECT_EXT_RETRIGGER:
                 case TE_EFFECT_EXT_RETRIGGER:
                 {
                 {
                     if ((opcode & 0xf) > 0 && (tick % (opcode & 0xf)) == 0)
                     if ((opcode & 0xf) > 0 && (tick % (opcode & 0xf)) == 0)
@@ -364,6 +375,131 @@ void do_command(uint16_t opcode, TrackerEngine *tracker_engine, uint8_t channel,
             break;
             break;
         }
         }
 
 
+        case TE_EFFECT_SET_RESONANCE:
+        {
+            if (tick == 0)
+            {
+                te_channel->filter_resonance = ((opcode & 0xff) << 5);
+                sound_engine_filter_set_coeff(&se_channel->filter, te_channel->filter_cutoff, te_channel->filter_resonance);
+            }
+
+            break;
+        }
+
+        case TE_EFFECT_RESONANCE_UP:
+        {
+            te_channel->filter_resonance += ((opcode & 0xff) << 2);
+
+            if (te_channel->filter_resonance > (0xff << 5))
+            {
+                te_channel->filter_resonance = (0xff << 5);
+            }
+
+            sound_engine_filter_set_coeff(&se_channel->filter, te_channel->filter_cutoff, te_channel->filter_resonance);
+            break;
+        }
+
+        case TE_EFFECT_RESONANCE_DOWN:
+        {
+            te_channel->filter_resonance -= ((opcode & 0xff) << 2);
+
+            if (te_channel->filter_resonance > (0xff << 5))
+            {
+                te_channel->filter_resonance = 0;
+            }
+
+            sound_engine_filter_set_coeff(&se_channel->filter, te_channel->filter_cutoff, te_channel->filter_resonance);
+            break;
+        }
+
+        case TE_EFFECT_SET_RING_MOD_SRC:
+        {
+            if (tick == 0)
+            {
+                se_channel->ring_mod = (opcode & 0xff);
+            }
+
+            break;
+        }
+
+        case TE_EFFECT_SET_HARD_SYNC_SRC:
+        {
+            if (tick == 0)
+            {
+                se_channel->hard_sync = (opcode & 0xff);
+            }
+
+            break;
+        }
+
+        case TE_EFFECT_SET_ATTACK:
+        {
+            if (tick == 0)
+            {
+                se_channel->adsr.a = (opcode & 0xff);
+            }
+
+            break;
+        }
+
+        case TE_EFFECT_SET_DECAY:
+        {
+            if (tick == 0)
+            {
+                se_channel->adsr.d = (opcode & 0xff);
+            }
+
+            break;
+        }
+
+        case TE_EFFECT_SET_SUSTAIN:
+        {
+            if (tick == 0)
+            {
+                se_channel->adsr.s = (opcode & 0xff);
+            }
+
+            break;
+        }
+
+        case TE_EFFECT_SET_RELEASE:
+        {
+            if (tick == 0)
+            {
+                se_channel->adsr.r = (opcode & 0xff);
+            }
+
+            break;
+        }
+
+        case TE_EFFECT_PROGRAM_RESTART:
+        {
+            if (tick == 0)
+            {
+                te_channel->program_counter = 0;
+                te_channel->program_loop = 0;
+                te_channel->program_period = 0;
+                te_channel->program_tick = 0;
+            }
+
+            break;
+        }
+
+        case TE_EFFECT_ARPEGGIO_ABS:
+        {
+            te_channel->arpeggio_note = 0;
+            te_channel->fixed_note = ((opcode & 0xff) << 8);
+
+            break;
+        }
+
+        case TE_EFFECT_TRIGGER_RELEASE:
+        {
+            sound_engine_enable_gate(tracker_engine->sound_engine, se_channel, 0);
+
+            break;
+        }
+
         default:
         default:
             break;
             break;
     }
     }

+ 20 - 3
tracker_engine/tracker_engine.c

@@ -1,6 +1,7 @@
 #include "tracker_engine.h"
 #include "tracker_engine.h"
 
 
 #include "../flizzer_tracker_hal.h"
 #include "../flizzer_tracker_hal.h"
+#include "../macros.h"
 
 
 #include "../sound_engine/sound_engine_osc.h"
 #include "../sound_engine/sound_engine_osc.h"
 #include <furi_hal.h>
 #include <furi_hal.h>
@@ -401,12 +402,12 @@ void tracker_engine_advance_channel(TrackerEngine *tracker_engine, uint8_t chan)
         {
         {
             if (te_channel->target_note > te_channel->note)
             if (te_channel->target_note > te_channel->note)
             {
             {
-                te_channel->note += fmin(te_channel->slide_speed, te_channel->target_note - te_channel->note);
+                te_channel->note += my_min(te_channel->slide_speed, te_channel->target_note - te_channel->note);
             }
             }
 
 
             else if (te_channel->target_note < te_channel->note)
             else if (te_channel->target_note < te_channel->note)
             {
             {
-                te_channel->note -= fmin(te_channel->slide_speed, te_channel->note - te_channel->target_note);
+                te_channel->note -= my_min(te_channel->slide_speed, te_channel->note - te_channel->target_note);
             }
             }
         }
         }
 
 
@@ -678,7 +679,23 @@ void tracker_engine_advance_tick(TrackerEngine *tracker_engine)
             {
             {
                 tracker_engine->pattern_position = 0;
                 tracker_engine->pattern_position = 0;
 
 
-                tracker_engine->sequence_position++;
+                if (song->loop_start != 0 || song->loop_end != 0)
+                {
+                    if (tracker_engine->sequence_position == song->loop_end)
+                    {
+                        tracker_engine->sequence_position = song->loop_start; // infinite loop between loop start and loop end
+                    }
+
+                    else
+                    {
+                        tracker_engine->sequence_position++;
+                    }
+                }
+
+                else
+                {
+                    tracker_engine->sequence_position++;
+                }
 
 
                 if (tracker_engine->sequence_position >= song->num_sequence_steps)
                 if (tracker_engine->sequence_position >= song->num_sequence_steps)
                 {
                 {

+ 32 - 3
tracker_engine/tracker_engine_defs.h

@@ -64,11 +64,12 @@ typedef enum
     TE_EFFECT_SET_WAVEFORM = 0x0b00,
     TE_EFFECT_SET_WAVEFORM = 0x0b00,
     TE_EFFECT_SET_VOLUME = 0x0c00,
     TE_EFFECT_SET_VOLUME = 0x0c00,
     TE_EFFECT_SKIP_PATTERN = 0x0d00,
     TE_EFFECT_SKIP_PATTERN = 0x0d00,
+
     TE_EFFECT_EXT = 0x0e00,
     TE_EFFECT_EXT = 0x0e00,
-    /* TODO: add 0exy effects here */
     TE_EFFECT_EXT_TOGGLE_FILTER = 0x0e00,
     TE_EFFECT_EXT_TOGGLE_FILTER = 0x0e00,
     TE_EFFECT_EXT_PORTA_UP = 0x0e10,
     TE_EFFECT_EXT_PORTA_UP = 0x0e10,
     TE_EFFECT_EXT_PORTA_DN = 0x0e20,
     TE_EFFECT_EXT_PORTA_DN = 0x0e20,
+    TE_EFFECT_EXT_FILTER_MODE = 0x0e30,
     TE_EFFECT_EXT_PATTERN_LOOP = 0x0e60, // e60 = start, e61-e6f = end and indication how many loops you want
     TE_EFFECT_EXT_PATTERN_LOOP = 0x0e60, // e60 = start, e61-e6f = end and indication how many loops you want
     TE_EFFECT_EXT_RETRIGGER = 0x0e90,
     TE_EFFECT_EXT_RETRIGGER = 0x0e90,
     TE_EFFECT_EXT_FINE_VOLUME_DOWN = 0x0ea0,
     TE_EFFECT_EXT_FINE_VOLUME_DOWN = 0x0ea0,
@@ -76,9 +77,37 @@ typedef enum
     TE_EFFECT_EXT_NOTE_CUT = 0x0ec0,
     TE_EFFECT_EXT_NOTE_CUT = 0x0ec0,
     TE_EFFECT_EXT_NOTE_DELAY = 0x0ed0,
     TE_EFFECT_EXT_NOTE_DELAY = 0x0ed0,
     TE_EFFECT_EXT_PHASE_RESET = 0x0ef0,
     TE_EFFECT_EXT_PHASE_RESET = 0x0ef0,
+
     TE_EFFECT_SET_SPEED_PROG_PERIOD = 0x0f00,
     TE_EFFECT_SET_SPEED_PROG_PERIOD = 0x0f00,
-    TE_EFFECT_CUTOFF_UP = 0x1000,   // Gxx
-    TE_EFFECT_CUTOFF_DOWN = 0x1100, // Hxx
+    TE_EFFECT_CUTOFF_UP = 0x1000,      // Gxx
+    TE_EFFECT_CUTOFF_DOWN = 0x1100,    // Hxx
+    TE_EFFECT_SET_RESONANCE = 0x1200,  // Ixx
+    TE_EFFECT_RESONANCE_UP = 0x1300,   // Jxx
+    TE_EFFECT_RESONANCE_DOWN = 0x1400, // Kxx
+
+    TE_EFFECT_SET_ATTACK = 0x1500,      // Lxx
+    TE_EFFECT_SET_DECAY = 0x1600,       // Mxx
+    TE_EFFECT_SET_SUSTAIN = 0x1700,     // Nxx
+    TE_EFFECT_SET_RELEASE = 0x1800,     // Oxx
+    TE_EFFECT_PROGRAM_RESTART = 0x1900, // Pxx
+    /*
+    TE_EFFECT_ = 0x1a00, //Qxx
+    */
+
+    TE_EFFECT_SET_RING_MOD_SRC = 0x1b00,  // Rxx
+    TE_EFFECT_SET_HARD_SYNC_SRC = 0x1c00, // Sxx
+
+    /*
+    TE_EFFECT_ = 0x1d00, //Txx
+    TE_EFFECT_ = 0x1e00, //Uxx
+    TE_EFFECT_ = 0x1f00, //Vxx
+    TE_EFFECT_ = 0x2000, //Wxx
+    TE_EFFECT_ = 0x2100, //Xxx
+    */
+
+    TE_EFFECT_ARPEGGIO_ABS = 0x2200,    // Yxx
+    TE_EFFECT_TRIGGER_RELEASE = 0x2300, // Zxx
+
     /* These effects work only in instrument program */
     /* These effects work only in instrument program */
     TE_PROGRAM_LOOP_BEGIN = 0x7d00,
     TE_PROGRAM_LOOP_BEGIN = 0x7d00,
     TE_PROGRAM_LOOP_END = 0x7e00,
     TE_PROGRAM_LOOP_END = 0x7e00,

+ 2 - 1
util.c

@@ -1,4 +1,5 @@
 #include "util.h"
 #include "util.h"
+#include "macros.h"
 
 
 void reset_buffer(SoundEngine *sound_engine)
 void reset_buffer(SoundEngine *sound_engine)
 {
 {
@@ -91,7 +92,7 @@ void resize_pattern(TrackerSongPattern *pattern, uint16_t old_length, uint16_t n
     temp.step = malloc((new_length) * sizeof(TrackerSongPatternStep));
     temp.step = malloc((new_length) * sizeof(TrackerSongPatternStep));
 
 
     set_empty_pattern(&temp, new_length);
     set_empty_pattern(&temp, new_length);
-    memcpy(temp.step, pattern->step, fmin(old_length, new_length) * sizeof(TrackerSongPatternStep));
+    memcpy(temp.step, pattern->step, my_min(old_length, new_length) * sizeof(TrackerSongPatternStep));
 
 
     free(pattern->step);
     free(pattern->step);
     pattern->step = temp.step;
     pattern->step = temp.step;

+ 3 - 1
util.h

@@ -8,7 +8,9 @@
 #include "tracker_engine/tracker_engine.h"
 #include "tracker_engine/tracker_engine.h"
 #include "tracker_engine/tracker_engine_defs.h"
 #include "tracker_engine/tracker_engine_defs.h"
 
 
-#define clamp(val, add, _min, _max) val = fmin(_max, fmax(_min, (int32_t)val + add))
+#include "macros.h"
+
+#define clamp(val, add, _min, _max) val = my_min(_max, my_max(_min, (int32_t)val + add))
 #define flipbit(val, bit) \
 #define flipbit(val, bit) \
     {                     \
     {                     \
         val ^= bit;       \
         val ^= bit;       \

+ 16 - 2
view/instrument_editor.c

@@ -1,6 +1,7 @@
 #include "instrument_editor.h"
 #include "instrument_editor.h"
 #include "pattern_editor.h"
 #include "pattern_editor.h"
 
 
+#include "../macros.h"
 #include "opcode_description.h"
 #include "opcode_description.h"
 
 
 #include <flizzer_tracker_icons.h>
 #include <flizzer_tracker_icons.h>
@@ -270,7 +271,20 @@ void draw_program_step(Canvas *canvas, uint8_t y, FlizzerTrackerApp *tracker, ui
 
 
     if (opcode != TE_PROGRAM_NOP)
     if (opcode != TE_PROGRAM_NOP)
     {
     {
-        snprintf(buffer, sizeof(buffer), "%01X %c%02X %s", index, command_get_char(opcode & 0x7fff), (opcode & 0xff), get_opcode_description(opcode, true) ? get_opcode_description(opcode, true) : "");
+        if ((opcode & 0x7f00) == TE_EFFECT_ARPEGGIO)
+        {
+            snprintf(buffer, sizeof(buffer), "%01X %c%02X %s", index, command_get_char(opcode & 0x7fff), (opcode & 0xff), notename((opcode & 0xff) + tracker->song.instrument[tracker->current_instrument]->base_note));
+        }
+
+        else if ((opcode & 0x7f00) == TE_EFFECT_ARPEGGIO_ABS)
+        {
+            snprintf(buffer, sizeof(buffer), "%01X %c%02X F.%s", index, command_get_char(opcode & 0x7fff), (opcode & 0xff), notename(opcode & 0xff));
+        }
+
+        else
+        {
+            snprintf(buffer, sizeof(buffer), "%01X %c%02X %s", index, command_get_char(opcode & 0x7fff), (opcode & 0xff), get_opcode_description(opcode, true) ? get_opcode_description(opcode, true) : "");
+        }
 
 
         if (opcode & 0x8000)
         if (opcode & 0x8000)
         {
         {
@@ -314,7 +328,7 @@ void draw_instrument_program_view(Canvas *canvas, FlizzerTrackerApp *tracker)
 {
 {
     Instrument *inst = tracker->song.instrument[tracker->current_instrument];
     Instrument *inst = tracker->song.instrument[tracker->current_instrument];
 
 
-    for (uint8_t i = tracker->program_position; i < fmin(INST_PROG_LEN, tracker->program_position + 8); i++)
+    for (uint8_t i = tracker->program_position; i < my_min(INST_PROG_LEN, tracker->program_position + 8); i++)
     {
     {
         draw_program_step(canvas, 6 + 6 * i - tracker->program_position * 6, tracker, i);
         draw_program_step(canvas, 6 + 6 * i - tracker->program_position * 6, tracker, i);
 
 

+ 13 - 0
view/opcode_description.c

@@ -23,6 +23,7 @@ static const OpcodeDescription opcode_desc[] =
         {TE_EFFECT_EXT_TOGGLE_FILTER, 0x7ff0, "TOGGLE FILTER (0=OFF,1-F=ON)", "T.FILT"},
         {TE_EFFECT_EXT_TOGGLE_FILTER, 0x7ff0, "TOGGLE FILTER (0=OFF,1-F=ON)", "T.FILT"},
         {TE_EFFECT_EXT_PORTA_UP, 0x7ff0, "FINE PORTAMENTO UP", "PUP F."},
         {TE_EFFECT_EXT_PORTA_UP, 0x7ff0, "FINE PORTAMENTO UP", "PUP F."},
         {TE_EFFECT_EXT_PORTA_DN, 0x7ff0, "FINE PORTAMENTO DOWN", "PDN F."},
         {TE_EFFECT_EXT_PORTA_DN, 0x7ff0, "FINE PORTAMENTO DOWN", "PDN F."},
+        {TE_EFFECT_EXT_FILTER_MODE, 0x7ff0, "SET FILTER MODE", "F.MODE"},
         {TE_EFFECT_EXT_PATTERN_LOOP, 0x7ff0, "PATTERN LOOP:E60=BEGIN,E6X=END", "PAT.L."},
         {TE_EFFECT_EXT_PATTERN_LOOP, 0x7ff0, "PATTERN LOOP:E60=BEGIN,E6X=END", "PAT.L."},
         {TE_EFFECT_EXT_RETRIGGER, 0x7ff0, "RETRIGGER AT TICK X (X>0)", "RETRIG"},
         {TE_EFFECT_EXT_RETRIGGER, 0x7ff0, "RETRIGGER AT TICK X (X>0)", "RETRIG"},
         {TE_EFFECT_EXT_FINE_VOLUME_DOWN, 0x7ff0, "FINE VOLUME DOWN", "VDN F."},
         {TE_EFFECT_EXT_FINE_VOLUME_DOWN, 0x7ff0, "FINE VOLUME DOWN", "VDN F."},
@@ -34,6 +35,18 @@ static const OpcodeDescription opcode_desc[] =
         {TE_EFFECT_SET_SPEED_PROG_PERIOD, 0x7f00, "SET SPEED (PROG.PER.IN PROGRAM)", "P.PER."},
         {TE_EFFECT_SET_SPEED_PROG_PERIOD, 0x7f00, "SET SPEED (PROG.PER.IN PROGRAM)", "P.PER."},
         {TE_EFFECT_CUTOFF_UP, 0x7f00, "FILTER CUTOFF UP", "CUT.UP"},
         {TE_EFFECT_CUTOFF_UP, 0x7f00, "FILTER CUTOFF UP", "CUT.UP"},
         {TE_EFFECT_CUTOFF_DOWN, 0x7f00, "FILTER CUTOFF DOWN", "CUT.DN"},
         {TE_EFFECT_CUTOFF_DOWN, 0x7f00, "FILTER CUTOFF DOWN", "CUT.DN"},
+        {TE_EFFECT_SET_RESONANCE, 0x7f00, "SET FILTER RESONANCE", "F.RES."},
+        {TE_EFFECT_RESONANCE_UP, 0x7f00, "FILTER RESONANCE UP", "F.R.UP"},
+        {TE_EFFECT_RESONANCE_DOWN, 0x7f00, "FILTER RESONANCE DOWN", "F.R.DN"},
+        {TE_EFFECT_SET_ATTACK, 0x7f00, "SET ENVELOPE ATTACK", "ADSR A"},
+        {TE_EFFECT_SET_DECAY, 0x7f00, "SET ENVELOPE DECAY", "ADSR D"},
+        {TE_EFFECT_SET_SUSTAIN, 0x7f00, "SET ENVELOPE SUSTAIN", "ADSR S"},
+        {TE_EFFECT_SET_RELEASE, 0x7f00, "SET ENVELOPE RELEASE", "ADSR R"},
+        {TE_EFFECT_PROGRAM_RESTART, 0x7f00, "RESTART INSTRUMENT PROGRAM", "P.RES."},
+        {TE_EFFECT_SET_RING_MOD_SRC, 0x7f00, "SET RING MODULATION SOURCE CH.", "R.SRC"},
+        {TE_EFFECT_SET_HARD_SYNC_SRC, 0x7f00, "SET HARD SYNC SOURCE CHANNEL", "S.SRC"},
+        {TE_EFFECT_ARPEGGIO_ABS, 0x7f00, "ABSOLUTE ARPEGGIO NOTE", ""},
+        {TE_EFFECT_TRIGGER_RELEASE, 0x7f00, "TRIGGER RELEASE", "TR.REL"},
 
 
         {TE_PROGRAM_LOOP_BEGIN, 0x7f00, "PROGRAM LOOP BEGIN", "L.BEG."},
         {TE_PROGRAM_LOOP_BEGIN, 0x7f00, "PROGRAM LOOP BEGIN", "L.BEG."},
         {TE_PROGRAM_LOOP_END, 0x7f00, "PROGRAM LOOP END", "L.END"},
         {TE_PROGRAM_LOOP_END, 0x7f00, "PROGRAM LOOP END", "L.END"},

+ 41 - 2
view/pattern_editor.c

@@ -1,4 +1,5 @@
 #include "pattern_editor.h"
 #include "pattern_editor.h"
+#include "../macros.h"
 
 
 #include <flizzer_tracker_icons.h>
 #include <flizzer_tracker_icons.h>
 
 
@@ -38,7 +39,8 @@ char *notename(uint8_t note)
 
 
     else
     else
     {
     {
-        snprintf(buffer, sizeof(buffer), "%s%d", notenames[note % 12], note / 12);
+        uint8_t final_note = my_min(12 * 7 + 11, note);
+        snprintf(buffer, sizeof(buffer), "%s%d", notenames[final_note % 12], final_note / 12);
     }
     }
 
 
     return buffer;
     return buffer;
@@ -163,6 +165,7 @@ void draw_sequence_view(Canvas *canvas, FlizzerTrackerApp *tracker)
     char buffer[4];
     char buffer[4];
 
 
     uint8_t sequence_position = tracker->tracker_engine.sequence_position;
     uint8_t sequence_position = tracker->tracker_engine.sequence_position;
+    TrackerSong *song = &tracker->song;
 
 
     for (int pos = sequence_position - 2; pos < sequence_position + 3; pos++)
     for (int pos = sequence_position - 2; pos < sequence_position + 3; pos++)
     {
     {
@@ -181,7 +184,43 @@ void draw_sequence_view(Canvas *canvas, FlizzerTrackerApp *tracker)
         }
         }
     }
     }
 
 
-    // TODO: add song loop indication
+    if (song->loop_start != 0 || song->loop_end != 0)
+    {
+        canvas_set_color(canvas, ColorBlack);
+
+        for (int pos = sequence_position - 2; pos < sequence_position + 3; pos++)
+        {
+            if (pos >= 0 && pos < tracker->song.num_sequence_steps)
+            {
+                if (pos == song->loop_start)
+                {
+                    int16_t y = (pos - (sequence_position - 2)) * 6;
+
+                    canvas_draw_line(canvas, 0, fmax(y, 0), 1, fmax(y, 0));
+                    canvas_draw_line(canvas, 0, fmax(y, 0), 0, fmax(y + 4, 0));
+                }
+
+                if (pos > song->loop_start && pos < song->loop_end)
+                {
+                    int16_t y = (pos - (sequence_position - 2)) * 6;
+
+                    canvas_draw_line(canvas, 0, fmax(y - 1, 0), 0, fmax(y + 4, 0));
+                }
+
+                if (pos == song->loop_end)
+                {
+                    int16_t y = (pos - (sequence_position - 2)) * 6;
+
+                    canvas_draw_line(canvas, 0, fmax(y + 4, 0), 1, fmax(y + 4, 0));
+                    canvas_draw_line(canvas, 0, fmax(y - 1, 0), 0, fmax(y + 4, 0));
+
+                    break;
+                }
+            }
+        }
+
+        canvas_set_color(canvas, ColorXOR);
+    }
 
 
     canvas_set_color(canvas, ColorBlack);
     canvas_set_color(canvas, ColorBlack);