Multi-Mode MIDI Step Sequencer – CDR Format – Part 2

This post is the second part of my series to document the building of a “CDR format” (CD Rack Format) panel version of my Multi-Mode MIDI Step Sequencer.

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

I used my Universal Synthesizer Panel with Arduino Nano FM Mozzi Synthesizer.

The Code

The main bulk of the code is the same as described in the Multi-Mode MIDI Step Sequencer but there are a few enhancements and updates required:

  • All pins must be updated to match those used the the panel version.
  • The MIDI library must be told to use a different serial port.
  • I’ve added a “random” mode switch.
  • The manual trigger handling needs improving.

The pin definitions are relatively straightforward to change.  The updated map now looks like this.

int seqpot[NUM_STEPS] = {A14,A15,A12,A13,A10,A11,A8,A9};
int seqsw[NUM_STEPS] = {38,39,36,37,34,35,32,33};
int seqled[NUM_STEPS] = {46,47,44,45,42,43,40,41};

int tempopot = A0;
int octsw[2] = {31,30}; // Up/Down switch positions
int trigsw[2] = {29,28};
int runsw[2] = {27,26};
int swsw[2] = {25,24};
int rndsw[2] = {23,22};
int gatesig = 8;
int gateout = 6;
int gatebtn = 10;
int midiled = 12;

Initialising the MIDI library for Serial3 is similarly fairly straightforward:

MIDI_CREATE_INSTANCE(HardwareSerial, Serial3, MIDI);

The manual trigger worked ok previously as each step was still governed by the tempo setting. However for true manual triggering it should really ignore the tempo when in single step mode.  However with no delays involved, some “debouncing” of the switch is required to prevent spurious readings.

There is a really good discussion of a range of hardware and software “debouncing” techniques here. I’ve use the first software technique, so my switch handling for triggering now looks like this.

int gate_b = digitalRead(gatebtn);
if (trigmode != T_FREE) {
// Check the gate button with some debouncing
if (gate_b == HIGH) {
// No switch pressed yet
gatebtndbcnt = 0;
lastgatebtn = HIGH;
} else {
gatebtndbcnt++;
}
if ((lastgatebtn == HIGH) && (gatebtndbcnt >= 1000)) {
gatebtndbcnt=0;
triggered++;
lastgatebtn = LOW;
}
}

Essentially, it won’t consider the switch “pressed” until it is seen to give a stable “LOW” reading for a period of time.  Any “bouncing” between HIGH and LOW will keep resetting gatebtndbcnt to zero preventing it from being counted as a proper reading.  Once stable, I’m still looking for a HIGH to LOW transaction to register a single trigger though, and then wait for the next button push.  If you want it to repeatedly trigger if you hold the button, you can remove the check for lastgatebtn.  Experimenting with a range of counter values found that the relatively high value of 1000 works well at the speed the code is running.

Further on in the code, when it comes to doing the “tempo” delay, I now only do that if not in single step mode.

if (trigmode == T_STEP) {
delay(100);
} else {
int tempodelay = tempomap(analogRead(tempopot));
delay(tempodelay);
}

Although you can see I keep in a short (fixed) delay in single step mode in order to allow the LED to light up enough to be visible.

In terms of implementing a random mode, I’ve opted for the following two option settings:

  • Randomize the note to be played; or
  • Randomize the next step to play.

This is implemented by the fifth switch, so the “mode switch” code from before needs copying a fifth time to initialise a new mode variable: rndmode to one of three settings: RN_NORM, RN_NOTE, RN_STEP.  Adding in the appropriate functionality was actually relatively simple compared to some of the other modes.

For RN_NOTE, when the pot for the current step is being read, I just adjust the value by a random amount.  This means that it will choose a random note, but still be centred around the pot setting.  I’ve gone for “pot setting +/- 100” as the range.

int potReading = analogRead (seqpot[playingNote]);
if (rndmode == RN_NOTE) {
potReading = potReading - 100 + random (200);
if (potReading > 1023) potReading = 1023;
if (potReading < 0) potReading = 0;
}

The nice thing about doing it to the pot reading itself, is all the other handling (e.g. mapping to a note range and so on) can carry on as before.

When it comes to randomizing the step to play, again, I just need to add some code where the current playing step is being updated.

if (rndmode == RN_STEP) {
playingNote = random (0,NUM_STEPS);
} else {
playingNote += runDir;
}

When in “random step” mode, the run mode is largely ignored.  But that’s ok as it makes little sense to talk of “reverse” or “cycling” of notes, when the next step is being chosen at random anyway.

In order to make the Arduino random() function useful, it needs to be initialised.  This is because the function is actually a “pseudo-random number generator” – it is calculating a sequence of numbers that seems random, but isn’t really.  But if you start it off in a different place each time, it is random enough for our purposes.  A good way to “seed” the random number generator is by feeding in the value from a floating input, so that is what I do in the setup.

 randomSeed (analogRead(RND_POT));

I think that’s about it for now.

Find it on GitHub here.

Closing Thoughts

You can see from the video that this is now pretty functional.  There are still a few rough edges, notably:

  • Sometimes there is a “wobble” from the pots – they aren’t very accurate.
  • The button I’ve used for the manual trigger is largely ok, but you really have to press it right in to register.
  • It would be nice to have more control over the one and four octave ranges.
  • There is still no functionality associated with the GATE input or output.  Watch this space!

When initially testing the module, I found that MIDI wasn’t working.  After quite a bit of debugging it turned out to be a faulty MIDI TRS socket.  They are a little hard to push a jack into, so I might need to find a better quality socket – I’ll see how things go!

I’d really like to find a simple way to make some panels.  I’ve a printout that is the right dimensions, but cutting them out isn’t easy without a laser cutter… so for now, it is scissors and bluetack.

But as a general sequencing platform, this is now pretty functional and there is still plenty of scope of trying different modes of operation.  Some other ideas I have at present include:

  • Providing a way to set the MIDI channel.
  • A random timing mode.
  • Some kind of algorithmic sequencing mode.
  • Using some of the unused IO to link up to an “expander module” to provide more steps.
  • Adding some kind of “doubling up” of notes – e.g. always sending out two notes with an interval defined somehow.  In fact, I could send out a different note in a range of MIDI channels for each pot – channel one for the root, channel two for a third above; channel three for a fifth; etc.

Kevin

 

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s