Selaa lähdekoodia

basic commands, pattern skip command

LTVA1 3 vuotta sitten
vanhempi
commit
b02397f3fd

+ 1 - 1
sound_engine/freqs.c

@@ -33,6 +33,6 @@ uint32_t get_freq(uint16_t note)
         uint64_t f1 = frequency_table[((note >> 8) % 12)] / (uint64_t)(2 << (((NUM_OCTAVES) - ((note >> 8) / 12)) - 2));
         uint64_t f2 = frequency_table[(((note >> 8) + 1) % 12)] / (uint64_t)(2 << (((NUM_OCTAVES) - (((note >> 8) + 1) / 12)) - 2));
 
-        return (uint64_t)f1 + (uint64_t)((f2 - f1) * (uint64_t)(note & 0xff)) / (uint64_t)256;
+        return f1 + (uint64_t)((f2 - f1) * (uint64_t)(note & 0xff)) / (uint64_t)256;
     }
 }

+ 1 - 1
sound_engine/sound_engine_defs.h

@@ -30,7 +30,7 @@ typedef enum
     SE_WAVEFORM_SAW = 8,
     SE_WAVEFORM_NOISE_METAL = 16,
     SE_WAVEFORM_SINE = 32,
-} SoudEngineWaveformType;
+} SoundEngineWaveformType;
 
 typedef enum
 {

+ 181 - 3
tracker_engine/do_effects.c

@@ -1,15 +1,37 @@
 #include "do_effects.h"
 #include <furi.h>
 
-void do_command(uint16_t opcode, TrackerEngine *tracker_engine, uint8_t channel)
+#include "../sound_engine/sound_engine_filter.h"
+
+void do_command(uint16_t opcode, TrackerEngine *tracker_engine, uint8_t channel, uint8_t tick, bool from_program)
 {
+    UNUSED(from_program);
+
     TrackerEngineChannel *te_channel = &tracker_engine->channel[channel];
     SoundEngineChannel *se_channel = &tracker_engine->sound_engine->channel[channel];
 
-    UNUSED(se_channel);
-
     switch (opcode & 0x7f00)
     {
+        case TE_EFFECT_ARPEGGIO:
+        {
+            if (tick == 0)
+            {
+                if (te_channel->fixed_note != 0xffff)
+                {
+                    te_channel->note = te_channel->last_note;
+                    te_channel->fixed_note = 0xffff;
+                }
+
+                if ((opcode & 0xff) == 0xf0)
+                    te_channel->arpeggio_note = te_channel->extarp1;
+                else if ((opcode & 0xff) == 0xf1)
+                    te_channel->arpeggio_note = te_channel->extarp2;
+                else
+                    te_channel->arpeggio_note = (opcode & 0xff);
+            }
+            break;
+        }
+
         case TE_EFFECT_PORTAMENTO_UP:
         {
             uint32_t prev = te_channel->note;
@@ -34,6 +56,162 @@ void do_command(uint16_t opcode, TrackerEngine *tracker_engine, uint8_t channel)
             break;
         }
 
+        case TE_EFFECT_VIBRATO:
+        {
+            if (tick == 0)
+            {
+                if (opcode & 0xff)
+                {
+                    te_channel->flags |= TE_ENABLE_VIBRATO;
+
+                    te_channel->vibrato_speed = (opcode & 0xf0);
+                    te_channel->vibrato_depth = ((opcode & 0x0f) << 4);
+                }
+
+                else
+                {
+                    te_channel->flags &= ~(TE_ENABLE_VIBRATO);
+                }
+            }
+
+            break;
+        }
+
+        case TE_EFFECT_PWM:
+        {
+            if (tick == 0)
+            {
+                if (opcode & 0xff)
+                {
+                    te_channel->flags |= TE_ENABLE_PWM;
+
+                    te_channel->pwm_speed = (opcode & 0xf0);
+                    te_channel->pwm_depth = ((opcode & 0x0f) << 4);
+                }
+
+                else
+                {
+                    te_channel->flags &= ~(TE_ENABLE_PWM);
+                }
+            }
+
+            break;
+        }
+
+        case TE_EFFECT_SET_PW:
+        {
+            if (tick == 0)
+            {
+                te_channel->pw = ((opcode & 0xff) << 4);
+            }
+
+            break;
+        }
+
+        case TE_EFFECT_PW_UP:
+        {
+            int16_t temp_pw = te_channel->pw + (int16_t)(opcode & 0xff);
+
+            if (temp_pw < 0)
+                temp_pw = 0;
+            if (temp_pw > 0xfff)
+                temp_pw = 0xfff;
+
+            te_channel->pw = temp_pw;
+
+            break;
+        }
+
+        case TE_EFFECT_PW_DOWN:
+        {
+            int16_t temp_pw = te_channel->pw - (int16_t)(opcode & 0xff);
+
+            if (temp_pw < 0)
+                temp_pw = 0;
+            if (temp_pw > 0xfff)
+                temp_pw = 0xfff;
+
+            te_channel->pw = temp_pw;
+
+            break;
+        }
+
+        case TE_EFFECT_SET_CUTOFF:
+        {
+            if (tick == 0)
+            {
+                te_channel->filter_cutoff = ((opcode & 0xff) << 3);
+                sound_engine_filter_set_coeff(&se_channel->filter, te_channel->filter_cutoff, te_channel->filter_resonance);
+            }
+
+            break;
+        }
+
+        case TE_EFFECT_VOLUME_FADE:
+        {
+            if (tick == 0)
+            {
+                if (!(te_channel->channel_flags & TEC_DISABLED))
+                {
+                    te_channel->volume -= opcode & 0xf;
+                    if (te_channel->volume > MAX_ADSR_VOLUME)
+                        te_channel->volume = 0;
+                    te_channel->volume += (opcode >> 4) & 0xf;
+                    if (te_channel->volume > MAX_ADSR_VOLUME)
+                        te_channel->volume = MAX_ADSR_VOLUME;
+
+                    se_channel->adsr.volume = (int32_t)se_channel->adsr.volume * (int32_t)te_channel->volume / MAX_ADSR_VOLUME * (int32_t)te_channel->instrument->adsr.volume / MAX_ADSR_VOLUME;
+                    se_channel->adsr.volume = (int32_t)se_channel->adsr.volume * (int32_t)tracker_engine->master_volume / MAX_ADSR_VOLUME;
+                }
+            }
+
+            break;
+        }
+
+        case TE_EFFECT_SET_WAVEFORM:
+        {
+            if (tick == 0)
+            {
+                se_channel->waveform = (opcode & 0x3f);
+            }
+
+            break;
+        }
+
+        case TE_EFFECT_SET_VOLUME:
+        {
+            if (tick == 0)
+            {
+                if (!(te_channel->channel_flags & TEC_DISABLED))
+                {
+                    te_channel->volume = opcode & 0xff;
+
+                    se_channel->adsr.volume = (int32_t)se_channel->adsr.volume * (int32_t)te_channel->volume / MAX_ADSR_VOLUME * (int32_t)te_channel->instrument->adsr.volume / MAX_ADSR_VOLUME;
+                    se_channel->adsr.volume = (int32_t)se_channel->adsr.volume * (int32_t)tracker_engine->master_volume / MAX_ADSR_VOLUME;
+                }
+            }
+
+            break;
+        }
+
+        case TE_EFFECT_SET_SPEED_PROG_PERIOD:
+        {
+            if (tick == 0)
+            {
+                if (from_program)
+                {
+                    te_channel->program_period = opcode & 0xff;
+                }
+
+                else
+                {
+                    tracker_engine->song->speed = opcode & 0xff;
+                }
+            }
+
+            break;
+        }
+
         default:
             break;
     }

+ 1 - 1
tracker_engine/do_effects.h

@@ -2,4 +2,4 @@
 #include <stdbool.h>
 #include <stdio.h>
 
-void do_command(uint16_t opcode, TrackerEngine *tracker_engine, uint8_t channel);
+void do_command(uint16_t opcode, TrackerEngine *tracker_engine, uint8_t channel, uint8_t tick, bool from_program);

+ 37 - 5
tracker_engine/tracker_engine.c

@@ -236,8 +236,10 @@ void tracker_engine_trigger_instrument_internal(TrackerEngine *tracker_engine, u
     se_channel->adsr.s = pinst->adsr.s;
     se_channel->adsr.r = pinst->adsr.r;
     se_channel->adsr.volume = pinst->adsr.volume;
+    se_channel->adsr.volume = (int32_t)se_channel->adsr.volume * (int32_t)tracker_engine->master_volume / MAX_ADSR_VOLUME;
 
     te_channel->volume = pinst->adsr.volume;
+    te_channel->volume = (int32_t)te_channel->volume * (int32_t)tracker_engine->master_volume / MAX_ADSR_VOLUME;
 
     sound_engine_enable_gate(tracker_engine->sound_engine, &tracker_engine->sound_engine->channel[chan], true);
 }
@@ -253,7 +255,8 @@ void tracker_engine_execute_track_command(TrackerEngine *tracker_engine, uint8_t
 
     if (vol != MUS_NOTE_VOLUME_NONE && !(tracker_engine->channel[chan].channel_flags & TEC_DISABLED))
     {
-        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);
+        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)tracker_engine->channel[chan].instrument->adsr.volume / MAX_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->master_volume / MAX_ADSR_VOLUME;
     }
 
     if (tracker_engine->channel[chan].instrument != NULL && opcode != 0)
@@ -266,7 +269,7 @@ void tracker_engine_execute_track_command(TrackerEngine *tracker_engine, uint8_t
 
         else
         {
-            do_command(opcode, tracker_engine, chan);
+            do_command(opcode, tracker_engine, chan, tracker_engine->current_tick, false);
         }
     }
 
@@ -347,7 +350,7 @@ do_it_again:;
 
             default:
             {
-                do_command(inst, tracker_engine, chan);
+                do_command(inst, tracker_engine, chan, te_channel->program_counter, true);
                 break;
             }
         }
@@ -455,6 +458,11 @@ void tracker_engine_advance_channel(TrackerEngine *tracker_engine, uint8_t chan)
             tracker_engine->sound_engine->channel[chan].pw = final_pwm;
         }
 
+        else
+        {
+            tracker_engine->sound_engine->channel[chan].pw = tracker_engine->channel[chan].pw;
+        }
+
         int32_t chn_note = (int16_t)(te_channel->fixed_note != 0xffff ? te_channel->fixed_note : te_channel->note) + vib + ((int16_t)te_channel->arpeggio_note << 8);
 
         if (chn_note < 0)
@@ -486,6 +494,8 @@ void tracker_engine_advance_tick(TrackerEngine *tracker_engine)
 
     TrackerSong *song = tracker_engine->song;
 
+    uint16_t opcode = 0;
+
     for (int chan = 0; chan < SONG_MAX_CHANNELS; ++chan)
     {
         SoundEngineChannel *se_channel = &tracker_engine->sound_engine->channel[chan];
@@ -501,7 +511,7 @@ void tracker_engine_advance_tick(TrackerEngine *tracker_engine)
 
             uint8_t note_delay = 0;
 
-            uint16_t opcode = tracker_engine_get_command(&pattern->step[pattern_step]);
+            opcode = tracker_engine_get_command(&pattern->step[pattern_step]);
 
             if ((opcode & 0x7ff0) == TE_EFFECT_EXT_NOTE_DELAY)
             {
@@ -568,7 +578,29 @@ void tracker_engine_advance_tick(TrackerEngine *tracker_engine)
                 }
             }
 
-            tracker_engine_execute_track_command(tracker_engine, chan, &pattern->step[pattern_step], tracker_engine->current_tick == note_delay);
+            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_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")

+ 6 - 1
tracker_engine/tracker_engine_defs.h

@@ -55,8 +55,13 @@ typedef enum
     TE_EFFECT_PORTAMENTO_DOWN = 0x0200,
     TE_EFFECT_SLIDE = 0x0300,
     TE_EFFECT_VIBRATO = 0x0400,
-    /* TODO: add smth there */
+    TE_EFFECT_PWM = 0x0500,
+    TE_EFFECT_SET_PW = 0x0600,
+    TE_EFFECT_PW_DOWN = 0x0700,
+    TE_EFFECT_PW_UP = 0x0800,
+    TE_EFFECT_SET_CUTOFF = 0x0900,
     TE_EFFECT_VOLUME_FADE = 0x0a00,
+    TE_EFFECT_SET_WAVEFORM = 0x0b00,
     TE_EFFECT_SET_VOLUME = 0x0c00,
     TE_EFFECT_SKIP_PATTERN = 0x0d00,
     TE_EFFECT_EXT = 0x0e00,

+ 1 - 1
view/instrument_editor.c

@@ -98,7 +98,7 @@ static const char *instrument_editor_params_description[] =
         "PWM DEPTH",
         "PWM DELAY (IN TICKS)",
         "DON'T RESTART PROGRAM ON KEYDOWN",
-        "PROG.PERIOD (00 ACTS SAME AS 01)",
+        "PROG.PERIOD (00 = PROGRAM OFF)",
 };
 
 void draw_instrument_view(Canvas *canvas, FlizzerTrackerApp *tracker)

+ 9 - 0
view/opcode_description.c

@@ -8,7 +8,16 @@ static const OpcodeDescription opcode_desc[] =
         {TE_EFFECT_PORTAMENTO_DOWN, 0x7f00, "PORTAMENTO DOWN", "PORTDN"},
         {TE_EFFECT_SLIDE, 0x7f00, "SLIDE", "SLIDE"},
         {TE_EFFECT_VIBRATO, 0x7f00, "VIBRATO", "VIB"},
+        {TE_EFFECT_PWM, 0x7f00, "PULSE WIDTH MODIFICATION", "PWM"},
+
+        {TE_EFFECT_SET_PW, 0x7f00, "SET PULSE WIDTH", "SET PW"},
+        {TE_EFFECT_PW_DOWN, 0x7f00, "PULSE WIDTH DOWN", "PWDOWN"},
+        {TE_EFFECT_PW_UP, 0x7f00, "PULSE WIDTH UP", "PW UP"},
+        {TE_EFFECT_SET_CUTOFF, 0x7f00, "SET FILTER CUTOFF", "F.CUT"},
+
         {TE_EFFECT_VOLUME_FADE, 0x7f00, "VOLUME FADE", "V.FADE"},
+        {TE_EFFECT_SET_WAVEFORM, 0x7f00, "SET WAVEFORM", "S.WAVE"},
+        {TE_EFFECT_SET_VOLUME, 0x7f00, "SET VOLUME", "VOLUME"},
         {TE_EFFECT_SKIP_PATTERN, 0x7f00, "SKIP PATTERN", "P.SKIP"},
         {TE_EFFECT_EXT_NOTE_DELAY, 0x7ff0, "NOTE DELAY", "N.DEL."},
         {TE_EFFECT_SET_SPEED_PROG_PERIOD, 0x7f00, "SET SPEED (PROG.PER.IN PROGRAM)", "P.PER."},