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

change custom font function name to its current name in PR; combined filter modes, rework a bit the tracker engine, cutoff up and cutoff down commands

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

+ 1 - 1
flizzer_tracker.c

@@ -51,7 +51,7 @@ void draw_callback(Canvas *canvas, void *ctx)
         return;
     }
 
-    canvas_set_custom_font(canvas, u8g2_font_tom_thumb_4x6_tr);
+    canvas_set_custom_u8g2_font(canvas, u8g2_font_tom_thumb_4x6_tr);
 
     switch (tracker->mode)
     {

+ 44 - 17
sound_engine/sound_engine.c

@@ -145,26 +145,53 @@ void sound_engine_fill_buffer(SoundEngine *sound_engine, uint16_t *audio_buffer,
 
                 if (channel->flags & SE_ENABLE_FILTER)
                 {
-                    sound_engine_filter_cycle(&channel->filter, channel_output_final[chan]);
-
-                    switch (channel->filter_mode)
+                    if (channel->filter_mode != 0)
                     {
-                        case FIL_OUTPUT_LOWPASS:
-                        {
-                            channel_output_final[chan] = sound_engine_output_lowpass(&channel->filter);
-                            break;
-                        }
-
-                        case FIL_OUTPUT_HIGHPASS:
-                        {
-                            channel_output_final[chan] = sound_engine_output_highpass(&channel->filter);
-                            break;
-                        }
+                        sound_engine_filter_cycle(&channel->filter, channel_output_final[chan]);
 
-                        case FIL_OUTPUT_BANDPASS:
+                        switch (channel->filter_mode)
                         {
-                            channel_output_final[chan] = sound_engine_output_bandpass(&channel->filter);
-                            break;
+                            case FIL_OUTPUT_LOWPASS:
+                            {
+                                channel_output_final[chan] = sound_engine_output_lowpass(&channel->filter);
+                                break;
+                            }
+
+                            case FIL_OUTPUT_HIGHPASS:
+                            {
+                                channel_output_final[chan] = sound_engine_output_highpass(&channel->filter);
+                                break;
+                            }
+
+                            case FIL_OUTPUT_BANDPASS:
+                            {
+                                channel_output_final[chan] = sound_engine_output_bandpass(&channel->filter);
+                                break;
+                            }
+
+                            case FIL_OUTPUT_LOW_HIGH:
+                            {
+                                channel_output_final[chan] = sound_engine_output_lowpass(&channel->filter) + sound_engine_output_highpass(&channel->filter);
+                                break;
+                            }
+
+                            case FIL_OUTPUT_HIGH_BAND:
+                            {
+                                channel_output_final[chan] = sound_engine_output_highpass(&channel->filter) + sound_engine_output_bandpass(&channel->filter);
+                                break;
+                            }
+
+                            case FIL_OUTPUT_LOW_BAND:
+                            {
+                                channel_output_final[chan] = sound_engine_output_lowpass(&channel->filter) + sound_engine_output_bandpass(&channel->filter);
+                                break;
+                            }
+
+                            case FIL_OUTPUT_LOW_HIGH_BAND:
+                            {
+                                channel_output_final[chan] = sound_engine_output_lowpass(&channel->filter) + sound_engine_output_highpass(&channel->filter) + sound_engine_output_bandpass(&channel->filter);
+                                break;
+                            }
                         }
                     }
                 }

+ 5 - 3
sound_engine/sound_engine_defs.h

@@ -46,8 +46,12 @@ typedef enum
     FIL_OUTPUT_LOWPASS = 1,
     FIL_OUTPUT_HIGHPASS = 2,
     FIL_OUTPUT_BANDPASS = 3,
+    FIL_OUTPUT_LOW_HIGH = 4,
+    FIL_OUTPUT_HIGH_BAND = 5,
+    FIL_OUTPUT_LOW_BAND = 6,
+    FIL_OUTPUT_LOW_HIGH_BAND = 7,
     /* ============ */
-    FIL_MODES = 4,
+    FIL_MODES = 8,
 } SoundEngineFilterModes;
 
 typedef enum
@@ -86,8 +90,6 @@ typedef struct
     uint8_t sync_bit;
 
     uint8_t filter_mode;
-    uint16_t filter_cutoff;
-    uint16_t filter_resonace;
 
     SoundEngineFilter filter;
 } SoundEngineChannel;

+ 57 - 0
tracker_engine/do_effects.c

@@ -196,6 +196,24 @@ void do_command(uint16_t opcode, TrackerEngine *tracker_engine, uint8_t channel,
         {
             switch (opcode & 0x7ff0)
             {
+                case TE_EFFECT_EXT_TOGGLE_FILTER:
+                {
+                    if (tick == 0)
+                    {
+                        if (opcode & 0xf)
+                        {
+                            se_channel->flags |= SE_ENABLE_FILTER;
+                        }
+
+                        else
+                        {
+                            se_channel->flags &= ~SE_ENABLE_FILTER;
+                        }
+                    }
+
+                    break;
+                }
+
                 case TE_EFFECT_EXT_PORTA_DN:
                 {
                     if (tick == 0)
@@ -284,6 +302,17 @@ void do_command(uint16_t opcode, TrackerEngine *tracker_engine, uint8_t channel,
 
                     break;
                 }
+
+                case TE_EFFECT_EXT_PHASE_RESET:
+                {
+                    if (tick == (opcode & 0xf))
+                    {
+                        se_channel->accumulator = 0;
+                        se_channel->lfsr = RANDOM_SEED;
+                    }
+
+                    break;
+                }
             }
 
             break;
@@ -307,6 +336,34 @@ void do_command(uint16_t opcode, TrackerEngine *tracker_engine, uint8_t channel,
             break;
         }
 
+        case TE_EFFECT_CUTOFF_UP:
+        {
+            te_channel->filter_cutoff += (opcode & 0xff);
+
+            if (te_channel->filter_cutoff > 0x7ff)
+            {
+                te_channel->filter_cutoff = 0x7ff;
+            }
+
+            sound_engine_filter_set_coeff(&se_channel->filter, te_channel->filter_cutoff, te_channel->filter_resonance);
+
+            break;
+        }
+
+        case TE_EFFECT_CUTOFF_DOWN:
+        {
+            te_channel->filter_cutoff -= (opcode & 0xff);
+
+            if (te_channel->filter_cutoff > 0x7ff) // unsigned int overflow
+            {
+                te_channel->filter_cutoff = 0;
+            }
+
+            sound_engine_filter_set_coeff(&se_channel->filter, te_channel->filter_cutoff, te_channel->filter_resonance);
+
+            break;
+        }
+
         default:
             break;
     }

+ 84 - 28
tracker_engine/tracker_engine.c

@@ -82,7 +82,7 @@ void set_default_instrument(Instrument *inst)
 {
     memset(inst, 0, sizeof(Instrument));
 
-    inst->flags = TE_SET_CUTOFF | TE_SET_PW;
+    inst->flags = TE_SET_CUTOFF | TE_SET_PW | TE_ENABLE_VIBRATO;
     inst->sound_engine_flags = SE_ENABLE_KEYDOWN_SYNC;
 
     inst->base_note = MIDDLE_C;
@@ -94,10 +94,19 @@ void set_default_instrument(Instrument *inst)
     inst->adsr.d = 0x28;
     inst->adsr.volume = 0x80;
 
+    inst->filter_type = FIL_OUTPUT_LOWPASS;
+    inst->filter_cutoff = 0xff;
+
+    inst->program_period = 1;
+
     for (int i = 0; i < INST_PROG_LEN; i++)
     {
         inst->program[i] = TE_PROGRAM_NOP;
     }
+
+    inst->vibrato_speed = 0x60;
+    inst->vibrato_depth = 0x20;
+    inst->vibrato_delay = 0x20;
 }
 
 void set_empty_pattern(TrackerSongPattern *pattern, uint16_t pattern_length)
@@ -216,8 +225,6 @@ void tracker_engine_trigger_instrument_internal(TrackerEngine *tracker_engine, u
     {
         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)
@@ -578,29 +585,7 @@ void tracker_engine_advance_tick(TrackerEngine *tracker_engine)
                 }
             }
 
-            if ((opcode & 0x7f00) == TE_EFFECT_SKIP_PATTERN && tracker_engine->current_tick == 0)
-            {
-                tracker_engine->sequence_position++;
-                tracker_engine->pattern_position = 0;
-
-                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;
-                }
-
-                sequence_position = tracker_engine->sequence_position;
-                current_pattern = song->sequence.sequence_step[sequence_position].pattern_indices[chan];
-                pattern_step = tracker_engine->pattern_position;
-
-                pattern = &song->pattern[current_pattern];
-            }
-
-            else
-            {
-                tracker_engine_execute_track_command(tracker_engine, chan, &pattern->step[pattern_step], tracker_engine->current_tick == note_delay);
-            }
+            tracker_engine_execute_track_command(tracker_engine, chan, &pattern->step[pattern_step], tracker_engine->current_tick == note_delay);
         }
 
         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")
@@ -612,9 +597,80 @@ void tracker_engine_advance_tick(TrackerEngine *tracker_engine)
 
         if (tracker_engine->current_tick >= song->speed)
         {
-            // TODO: add pattern loop and pattern skip commands
+            bool flag = true;
 
-            tracker_engine->pattern_position++;
+            for (int chan = 0; chan < SONG_MAX_CHANNELS; ++chan)
+            {
+                uint16_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];
+
+                opcode = tracker_engine_get_command(&pattern->step[pattern_step]);
+
+                if ((opcode & 0x7ff0) == TE_EFFECT_EXT_PATTERN_LOOP)
+                {
+                    if (opcode & 0xf) // loop end
+                    {
+                        if (!(tracker_engine->in_loop))
+                        {
+                            tracker_engine->loops_left = (opcode & 0xf);
+                            tracker_engine->in_loop = true;
+
+                            for (int j = tracker_engine->pattern_position; j >= 0; j--)
+                            {
+                                if (tracker_engine_get_command(&pattern->step[j]) == TE_EFFECT_EXT_PATTERN_LOOP) // search for loop start
+                                {
+                                    tracker_engine->pattern_position = fmax((int16_t)j - 1, 0); // jump to loop start
+
+                                    goto out;
+                                }
+                            }
+                        }
+
+                        else
+                        {
+                            tracker_engine->loops_left--;
+
+                            if (tracker_engine->loops_left == 0)
+                            {
+                                tracker_engine->in_loop = false;
+                                goto out;
+                            }
+
+                            for (int j = tracker_engine->pattern_position; j >= 0; j--)
+                            {
+                                if (tracker_engine_get_command(&pattern->step[j]) == TE_EFFECT_EXT_PATTERN_LOOP) // search for loop start
+                                {
+                                    tracker_engine->pattern_position = fmax((int16_t)j - 1, 0); // jump to loop start
+
+                                    goto out;
+                                }
+                            }
+                        }
+                    }
+
+                    else // loop start
+                    {
+                    }
+
+                out:;
+                }
+
+                if ((opcode & 0x7f00) == TE_EFFECT_SKIP_PATTERN)
+                {
+                    tracker_engine->sequence_position++;
+                    tracker_engine->pattern_position = 0;
+
+                    flag = false;
+                }
+            }
+
+            if (flag)
+            {
+                tracker_engine->pattern_position++;
+            }
 
             tracker_engine->current_tick = 0;
 

+ 8 - 0
tracker_engine/tracker_engine_defs.h

@@ -66,14 +66,19 @@ typedef enum
     TE_EFFECT_SKIP_PATTERN = 0x0d00,
     TE_EFFECT_EXT = 0x0e00,
     /* TODO: add 0exy effects here */
+    TE_EFFECT_EXT_TOGGLE_FILTER = 0x0e00,
     TE_EFFECT_EXT_PORTA_UP = 0x0e10,
     TE_EFFECT_EXT_PORTA_DN = 0x0e20,
+    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_FINE_VOLUME_DOWN = 0x0ea0,
     TE_EFFECT_EXT_FINE_VOLUME_UP = 0x0eb0,
     TE_EFFECT_EXT_NOTE_CUT = 0x0ec0,
     TE_EFFECT_EXT_NOTE_DELAY = 0x0ed0,
+    TE_EFFECT_EXT_PHASE_RESET = 0x0ef0,
     TE_EFFECT_SET_SPEED_PROG_PERIOD = 0x0f00,
+    TE_EFFECT_CUTOFF_UP = 0x1000,   // Gxx
+    TE_EFFECT_CUTOFF_DOWN = 0x1100, // Hxx
     /* These effects work only in instrument program */
     TE_PROGRAM_LOOP_BEGIN = 0x7d00,
     TE_PROGRAM_LOOP_END = 0x7e00,
@@ -197,4 +202,7 @@ typedef struct
     uint8_t master_volume;
 
     bool playing; // if we reach the end of the song and song does not loop we just stop there
+
+    bool in_loop; // for E6X (pattern loop) command
+    uint8_t loops_left;
 } TrackerEngine;

+ 4 - 0
view/instrument_editor.c

@@ -56,6 +56,10 @@ static const char *filter_types[] =
         "LOW",
         "HIGH",
         "BAND",
+        "LOHI",
+        "HIBD",
+        "LOBD",
+        "ALL",
 };
 
 static const char *instrument_editor_params_description[] =

+ 6 - 0
view/opcode_description.c

@@ -20,15 +20,21 @@ static const OpcodeDescription opcode_desc[] =
         {TE_EFFECT_SET_VOLUME, 0x7f00, "SET VOLUME", "VOLUME"},
         {TE_EFFECT_SKIP_PATTERN, 0x7f00, "SKIP PATTERN", "P.SKIP"},
 
+        {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_DN, 0x7ff0, "FINE PORTAMENTO DOWN", "PDN F."},
+        {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_FINE_VOLUME_DOWN, 0x7ff0, "FINE VOLUME DOWN", "VDN F."},
         {TE_EFFECT_EXT_FINE_VOLUME_UP, 0x7ff0, "FINE VOLUME UP", "VUP F."},
         {TE_EFFECT_EXT_NOTE_CUT, 0x7ff0, "NOTE CUT", "N.CUT"},
         {TE_EFFECT_EXT_NOTE_DELAY, 0x7ff0, "NOTE DELAY", "N.DEL."},
+        {TE_EFFECT_EXT_PHASE_RESET, 0x7ff0, "PHASE RESET ON TICK X", "PH.RES."},
 
         {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_DOWN, 0x7f00, "FILTER CUTOFF DOWN", "CUT.DN"},
+
         {TE_PROGRAM_LOOP_BEGIN, 0x7f00, "PROGRAM LOOP BEGIN", "L.BEG."},
         {TE_PROGRAM_LOOP_END, 0x7f00, "PROGRAM LOOP END", "L.END"},