diff --git a/src/main_perkons.cc b/src/main_perkons.cc
index 31c5ae3..4e0c92a 100644
--- a/src/main_perkons.cc
+++ b/src/main_perkons.cc
@@ -31,27 +31,18 @@ namespace Heck {
 
     std::array<Track, Constants::TRACK_COUNT> tracks;
 
-    // function prototypes
-    int create_tracks();
-
-    void AudioCallback(
-        ld::AudioHandle::InterleavingInputBuffer in,
-        ld::AudioHandle::InterleavingOutputBuffer out,
-        size_t size);
-
-    void midi_realtime_handler(ld::MidiEvent& msg);
-
-    struct Clock {
-        void advance()
+    struct MidiClock {
+    public:
+        void tick_advance()
         {
             if (enabled) {
-                time++;
+                time_inf++;
             }
         };
 
         void reset()
         {
-            time = 0;
+            time_inf = 0;
         };
 
         void enable(bool enabled)
@@ -59,17 +50,148 @@ namespace Heck {
             this->enabled = enabled;
         };
 
-        int gettime()
+        // get time
+
+        int tick_infinite()
+        {
+            return time_inf;
+        }
+
+        int tick_4n()
+        {
+            return time_inf % PPQ;
+        }
+
+        int tick_1n()
+        {
+            return time_inf % (PPQ * 4);
+        }
+
+        int count_8n()
         {
-            return time;
+            return std::floor(tick_1n() / 12);
+        }
+
+        int count_16n()
+        {
+            return std::floor(tick_1n() / 6);
+        }
+
+        int count_bar()
+        {
+            return std::floor(time_inf / 96.);
         }
 
     private:
+        static constexpr int PPQ = 24;
         bool enabled{ true };
-        int time{ 0 };
+        int time_inf{ 0 };
+    };
+
+    struct Sequencer {
+
+        Sequencer()
+        {
+            clear_sequence();
+        }
+
+        // its a MIDI CC step sequencer
+        constexpr static int MIDI_MAX = 127;
+        constexpr static int STEP_COUNT = 16;
+        constexpr static int TRACK_COUNT = 16;
+
+        using Step = std::array<int, MIDI_MAX>;
+        using Track = std::array<Step, STEP_COUNT>;
+        using Sequence = std::array<Track, TRACK_COUNT>;
+
+
+        void reset()
+        {
+            step_current = 0;
+        }
+
+        void next_step()
+        {
+            step_current++;
+            if(step_current >= STEP_COUNT) {
+                step_current = 0;
+            }
+        }
+
+        void clear_track(int track_nr)
+        {
+            for (int step = 0; step < STEP_COUNT; step++) {
+                for (int cc_nr = 0; cc_nr < MIDI_MAX; cc_nr++) {
+                    sequence[track_nr][step][cc_nr] = -1;
+                }
+            }
+        }
+
+        void clear_track_cc(int track_nr, int cc_nr)
+        {
+            for (int step = 0; step < STEP_COUNT; step++) {
+                sequence[track_nr][step][cc_nr] = -1;
+            }
+        }
+
+        void clear_sequence()
+        {
+            for (int track = 0; track < TRACK_COUNT; track++) {
+                clear_track(track);
+            }
+        }
+
+        void midi_in(ld::MidiEvent& msg)
+        {
+            if (recording) {
+                ld::ControlChangeEvent cc = msg.AsControlChange();
+                sequence[cc.channel][step_current][cc.control_number] = cc.value;
+            }
+        }
+
+        std::vector<ld::MidiEvent> midi_out()
+        {
+            std::vector<ld::MidiEvent> ret{};
+            for (int track = 0; track < TRACK_COUNT; track++) {
+                for (int cc_nr = 0; cc_nr < MIDI_MAX; cc_nr++) {
+                    int cc_val = sequence[track][step_current][cc_nr];
+                    if (cc_val != -1) {
+                        ld::MidiEvent ev{};
+                        ev.channel = track;
+                        ev.type = ld::ControlChange;
+                        ev.data[0] = cc_nr;
+                        ev.data[1] = cc_val;
+                        ret.push_back(ev);
+                    }
+                }
+            }
+            return ret;
+        }
+
+        int step_current{ 0 };
+        bool recording{ false };
+        Sequence sequence{};
     };
 
-    Clock clock{};
+    MidiClock clock{};
+    Sequencer sequencer{};
+
+    // function prototypes
+    void AudioCallback(
+        ld::AudioHandle::InterleavingInputBuffer in,
+        ld::AudioHandle::InterleavingOutputBuffer out,
+        size_t size);
+
+    void midi_realtime_handler(ld::MidiEvent& msg);
+
+
+    void init_tracks()
+    {
+        tracks[0].init(instrument0);
+        tracks[1].init(instrument1);
+        tracks[2].init(instrument2);
+        tracks[3].init(instrument3);
+    }
 
     void init()
     {
@@ -105,38 +227,21 @@ namespace Heck {
                 break;
         }
 
-        hw.PrintLine("Creating Tracks");
-        create_tracks();
-
-
-        hw.PrintLine("Setting up MIDI");
+        hw.PrintLine("Initializing MIDI");
         ld::MidiUartHandler::Config midi_config{};
         midi.Init(midi_config);
-
         midi.realtime_callback = &midi_realtime_handler;
 
+        init_tracks();
+
         hw.PrintLine("Starting MIDI Receive");
         midi.StartReceive();
         midi.Listen();
 
         hw.PrintLine("Starting Audio");
         hw.StartAudio(AudioCallback);
-
-        hw.PrintLine("Entering MainLoop");
     }
 
-    int create_tracks()
-    {
-        instrument0.init();
-        tracks[0].init(instrument0);
-        instrument1.init();
-        tracks[1].init(instrument1);
-        instrument2.init();
-        tracks[2].init(instrument2);
-        instrument3.init();
-        tracks[3].init(instrument3);
-        return 0;
-    }
 
     // =============================================================================================
     // RUN
@@ -163,15 +268,17 @@ namespace Heck {
         event_log.PushBack(msg);
         switch (msg.srt_type) {
             case daisy::TimingClock:
-                clock.advance();
+                clock.tick_advance();
                 break;
             case daisy::Start: {
+                sequencer.reset();
                 clock.reset();
                 clock.enable(true);
             } break;
             case daisy::Stop: {
                 clock.enable(false);
                 clock.reset();
+                sequencer.reset();
             } break;
             case daisy::Reset:
                 break;
@@ -180,67 +287,82 @@ namespace Heck {
         }
     }
 
+    void tracks_midi_in(ld::MidiEvent msg)
+    {
+        switch (msg.type) {
+            case ld::MidiMessageType::NoteOn: {
+                if (msg.channel >= 0 && msg.channel < Constants::TRACK_COUNT) {
+                    tracks[msg.channel].instrument->trigger();
+                }
+            } break;
+            case ld::MidiMessageType::ControlChange: {
+                sequencer.midi_in(msg);
+                ld::ControlChangeEvent cc = msg.AsControlChange();
+                float val_normalized = cc.value / 127.;
+                switch (cc.control_number) {
+                        // Pots
+                    case Constants::MIDI_Mapping::TRACK_PITCH:
+                        tracks[cc.channel].instrument->ctl(0, val_normalized);
+                        break;
+                    case Constants::MIDI_Mapping::TRACK_DECAY:
+                        tracks[cc.channel].instrument->ctl(1, val_normalized);
+                        break;
+                    case Constants::MIDI_Mapping::TRACK_PARAM1:
+                        tracks[cc.channel].instrument->ctl(2, val_normalized);
+                        break;
+                    case Constants::MIDI_Mapping::TRACK_PARAM2:
+                        tracks[cc.channel].instrument->ctl(3, val_normalized);
+                        break;
+                    case Constants::MIDI_Mapping::TRACK_FILTER:
+                        tracks[cc.channel].filter(val_normalized);
+                        break;
+                    case Constants::MIDI_Mapping::TRACK_DRIVE:
+                        tracks[cc.channel].drive(val_normalized);
+                        break;
+                    case Constants::MIDI_Mapping::TRACK_VOLUME:
+                        tracks[cc.channel].volume(val_normalized);
+                        break;
+                        // Switches
+                    case Constants::MIDI_Mapping::TRACK_MODE1:
+                        tracks[cc.channel].instrument->switch_mode1(int(val_normalized * 2.));
+                        break;
+                    case Constants::MIDI_Mapping::TRACK_MODE2:
+                        tracks[cc.channel].instrument->switch_mode2(int(val_normalized * 2.));
+                        break;
+                    case Constants::MIDI_Mapping::TRACK_FILTERMODE:
+                        tracks[cc.channel].filtermode(val_normalized);
+                        break;
+                    default:
+                        break;
+                }
+            } break;
+            default: {
+                // Other MIDI message
+            } break;
+        }
+    }
+
     void midi_async_handler()
     {
         while (midi.HasEvents()) {
             ld::MidiEvent msg = midi.PopEvent();
             event_log.PushBack(msg);
-            switch (msg.type) {
-                case ld::MidiMessageType::NoteOn: {
-                    if (msg.channel >= 0 && msg.channel < Constants::TRACK_COUNT) {
-                        tracks[msg.channel].instrument->trigger();
-                    }
-                } break;
-                case ld::MidiMessageType::ControlChange: {
-                    ld::ControlChangeEvent cc = msg.AsControlChange();
-                    float val_normalized = cc.value / 127.;
-                    switch (cc.control_number) {
-                            // Pots
-                        case Constants::MIDI_Mapping::TRACK_PITCH:
-                            tracks[cc.channel].instrument->ctl(0, val_normalized);
-                            break;
-                        case Constants::MIDI_Mapping::TRACK_DECAY:
-                            tracks[cc.channel].instrument->ctl(1, val_normalized);
-                            break;
-                        case Constants::MIDI_Mapping::TRACK_PARAM1:
-                            tracks[cc.channel].instrument->ctl(2, val_normalized);
-                            break;
-                        case Constants::MIDI_Mapping::TRACK_PARAM2:
-                            tracks[cc.channel].instrument->ctl(3, val_normalized);
-                            break;
-                        case Constants::MIDI_Mapping::TRACK_FILTER:
-                            tracks[cc.channel].filter(val_normalized);
-                            break;
-                        case Constants::MIDI_Mapping::TRACK_DRIVE:
-                            tracks[cc.channel].drive(val_normalized);
-                            break;
-                        case Constants::MIDI_Mapping::TRACK_VOLUME:
-                            tracks[cc.channel].volume(val_normalized);
-                            break;
-                            // Switches
-                        case Constants::MIDI_Mapping::TRACK_MODE1:
-                            tracks[cc.channel].instrument->switch_mode1(int(val_normalized * 2.));
-                            break;
-                        case Constants::MIDI_Mapping::TRACK_MODE2:
-                            tracks[cc.channel].instrument->switch_mode2(int(val_normalized * 2.));
-                            break;
-                        case Constants::MIDI_Mapping::TRACK_FILTERMODE:
-                            tracks[cc.channel].filtermode(val_normalized);
-                            break;
-                        default:
-                            break;
-                    }
-                } break;
-                default: {
-                    // Other MIDI message
-                } break;
-            }
+            tracks_midi_in(msg);
+        }
+    }
+
+    void sequencer_midi_handler()
+    {
+        std::vector<ld::MidiEvent> queue = sequencer.midi_out();
+        for (ld::MidiEvent msg : queue) {
+            tracks_midi_in(msg);
         }
     }
 
     void mainloop()
     {
-        u32 systick_now = ld::System::GetNow();
+        hw.PrintLine("Entering MainLoop");
+        u32 systick_now{};
         u32 midi_log_systick_last{};
 
         bool heartbeat_led_state{ false };
@@ -252,16 +374,21 @@ namespace Heck {
         int clock_time_new{};
         int clock_time_current{};
 
+        int clock_bar_new{};
+        int clock_bar_current{};
+
+        int clock_16n_new{};
+        int clock_16n_current{};
+
 
         while (1) {
             // Get current values for state
             // if update is different
             // Update state
             // handle change
-
             systick_now = ld::System::GetNow();
 
-            clock_time_new = clock.gettime();
+            clock_time_new = clock.tick_infinite();
             if (clock_time_current != clock_time_new) {
                 clock_time_current = clock_time_new;
                 if (0) {
@@ -269,6 +396,20 @@ namespace Heck {
                 }
             }
 
+            clock_bar_new = clock.count_bar();
+            if (clock_bar_new != clock_bar_current) {
+                clock_bar_current = clock_bar_new;
+                hw.PrintLine("Bar: %i", clock_bar_current);
+            }
+
+            clock_16n_new = clock.count_16n();
+            if (clock_16n_new != clock_16n_current) {
+                clock_16n_current = clock_16n_new;
+                hw.PrintLine("16n: %i", clock_16n_current);
+                sequencer.next_step();
+            }
+
+            sequencer_midi_handler();
             midi_async_handler();
 
             // REC
@@ -281,6 +422,7 @@ namespace Heck {
                 } else {
                     hw.PrintLine("RECORDING OFF");
                 }
+                sequencer.recording = seq_recording_current;
             }
 
             if (systick_now - midi_log_systick_last > 5) {
@@ -303,7 +445,7 @@ namespace Heck {
                         case ld::NoteOn:
                         case ld::NoteOff:
                         case ld::MidiMessageType::ControlChange: {
-                            if (1) {
+                            if (0) {
                                 char outstr[256];
                                 char type_str[32];
                                 GetMidiTypeAsString(msg, type_str);