Arduino MIDI Rotary Encoder Step Sequencer

I’m thinking about other applications for a rotary encoder and one thought was to support a multi-step, step sequencer with just a single knob, so this takes the Arduino MIDI Step Sequencer and recodes it to use the rotary encoder and 7 segment display described in Arduino MIDI Rotary Encoder Controller.

Here are some links to follow-up posts:

  • In part 2, I use some “LED bars” as the visualisation.
  • In part 3, I use a ring of NeoPixels.
  • In the following part, I make the step sequencer support multiple tracks.

Warning! I strongly recommend using old or second hand equipment for your experiments.  I am not responsible for any damage to expensive instruments!

These are the key Arduino tutorials for the main concepts used in this project:

If you are new to Arduino, see the Getting Started pages.

Parts list

The Circuit

ArduinoMIDIRE7SegmentController2_bb

This is using essentially the same circuit as described in the previous project: Arduino MIDI Rotary Encoder Controller, but I’ve moved the rotary encoder over to use the analog pins (in digital input mode) to free up the digital pins for something else in the future.

Recall that the display is using I2C so has A4 and A5 tied up.  The encoder is wired as follows:

  • CLK – A0
  • DAT – A1
  • SW – A2

And of course a MIDI module is connected to RX/TX.

The Code

This is using the same libraries from the previous project: Arduino MIDI Rotary Encoder Controller so you’ll need to have those installed.

There are two distinct sections to this code: the sequencer and the IO control.  The sequencer is pretty much the same as for the Arduino MIDI Step Sequencer but I’ve updated it to read the notes from an array of steps and to support a variable tempo control.

The basic logic in the main loop is as follows:

scanEncoder()
scanDisplay()

IF millis() says it's time for the next step THEN
   Update the timer ready for the next step based on the TEMPO
   Move to the next step
   IF there is a note already playing THEN
      Send the MIDI NoteOff for the playing note
   IF next step note is non-zero THEN
      Send the MIDI NoteOn for the next note

The notes that are stored in the array are set up using the rotary encoder.  Much of the encoder code is based on that from the previous project but it is now split out into a number of functions:

  • initEncoder – initialise the encoder.
  • scanEncoder – perform a single scan of the encoders direction (if turned) and the switch.
  • swEncoder – act on the switch if detected.
  • incEncoder – act on the encoder if increasing.
  • decEncoder – act on the encoder if decreasing.

One thing I wanted is to have the sequencer programmable using a single rotary encoder.  To do this I’m using the encoder’s switch to change the current mode for the encoder.  The modes are as follows:

  • Play mode – it is free running at the current tempo and rotating the encoder will change the tempo.
  • Step mode – when the switch is pressed it enters “step edit” mode.  In this mode, the encoder is used to pick one of the steps for the sequencer and it is selected by pressing the switch again to change to:
  • Note mode – the encoder now allows you to choose a note for this step.  As soon as the note is changed it is updated and stored – there is no need to press the switch.  Pressing the switch will change back to step mode showing the next step in the sequence.

If no interaction with the encoder is detected for a set period of time, then it will automatically change back to play mode.  To support this there are two additional functions:

  • resetEncoder – reset the timeout associated with the encoder’s mode.
  • timeEncoder – check the timeout to see if the mode needs to change.

So each of the inc/dec/sw encoder functions needs to be aware of the current mode and update the internal state of the system as appropriate (updating the tempo, current step, or a step’s note as required).

The last part of the code supports the display.  The basics are the same as the previous project, but I’ve broken that out into the following functions:

  • initDisplay – as you’d expect performs the first time initialisation for the display.
  • scanDisplay – this will update what is being shown on the display.  Once again this has to be aware of the current encoder mode, and so has to show one of: current playing step; current step to edit; current note being changed.

One complication is how the “wrap around” is coded for the encoder:

  • For the tempo, it will not wrap, it just changes between the minimum supported tempo and the maximum supported tempo.
  • For the step being edited, it will wrap around to make selecting the step as easy as possible.
  • For the note being edited, I’ve opted for non wrap-around again.  It takes 0 as meaning a step should be silent, so it has to jump from 0 (disabled) to the lowest note to be played and it will stop when you reach the highest note.

Notes are currently shown using their MIDI note values, which isn’t particularly user-friendly, but it gets the job done for now.

The number of steps, initial tempo, supported MIDI note range and MIDI channel are all configurable at the top of the file.  Using an encoder like this means I can go for a lot more steps than when using potentiometers.  The downside is that it is more fiddly to configure.

I’ve opted for 32 steps, at quite a high tempo, which gives four measures subdivided into eight (and all variants of course).  Just tweak the values and see how you go!

Find it on GitHub here.

Closing Thoughts

It should be possible to get the seven segment display to show a note name and octave number rather than MIDI note number, so that is one possible enhancement. It might also be interesting to experiment with different display ideas – I have some LED “bars” that might be fun to try, and an OLED display is another idea.

I’d also like to try this with the ATemga32U4 to build a USB MIDI controller version.  Other ideas might include multiple rotary encoders and possibly more control switches too.

Kevin

Leave a comment