Analog trigger to MIDI trigger

Hi everyone: this is my first post -please be gentle...

I own a pile of old analog synthesizers, but lately, a few MIDI devices have sneaked into the collection. That creates some compatibility problems....

The one i fight now, is to interface the output from my Boss DR-55 "Dr. Rythm" drum machine (5V positive-going trigger pulse) to the MIDI input (Ch.1 default) to drive the sequencer in a modern keyboard.

So i need a analog trigger input into e.g an Arduino Nano, and get a MIDI trigger signal out on the other side.

I could imagine using D2-D5 for selecting the MIDI channel, one of D6-D12 for the input pulse, and D1 for the transmitted MIDI signal.

Does anyone have an idea what code could do this? I'm not a very bright programmer...

All help would be appreciated!

Have fun, everyone -
Kim "The_Pirate"
Denmark

Welcome to the forum, Kim!

I'm not the right person to help with the MIDI side of things, but if you want others to help, it would be useful to clarify exactly what kind of MIDI message you want the Arduino to generate from the trigger pulse.

For example:

  • MIDI Clock?
  • Start/Stop?
  • Note On/Off?
  • Something else?

Also, which keyboard (manufacturer/model) are you trying to control?

Oh, sorry. I'm not very much into MIDI terminology - i'm a totally analog guy - but i'll try...

I'm trying to control the sequencer in a Behringer MS-1 mk.2 - a clone of the ancient Roland SH-101. The MS-1 has an analog trigger input, but also a bug in the software - the analog input can trigger the arpeggiator, but not the sequencer. So i have to go MIDI - and it works from a MIDI drum machine (That sounds like pooha!)

So i need something that advances the sequencer one step for every sync pulse the analog drum machine sends out - i guess this is "MIDI clock"?

The Start/stop is set in the MS-1; activated, it listens on the selected MIDI port, and triggers the note/advances the sequencer one step for every trigger event received. So the thing i need is neither Start/Stop nor Note on/off.

I'm sorry that i can't put the proper words on it. But, all these years i've been analog - MIDI first came out when i stopped in the music shop - it's only now that i have to start using it.
Building hardware is no problem for me, i have been developing it for years, but these software signals beat me...

I really want my DR-55 to do my drums. It is simple and sounds good - and it was Depeche Mode's first drummer... ;)

And, InquisitiveMind, thanks for the welcome! :)

Please have a look at How to get the best out of this forum

Can you elaborate on that ?

Best is probably to read up on it. The protocol is not very complex.

There are 2 separate things in MIDI. Timecode and sync.
Timecode sends a specific timecode and the receiver will step to that specific timecode. Sync sends a Sync command 24x per beat and syncs the receiver to that.

Sync is the more common option, though for instance Cubase only used timecode for quite long time (don't know if it can use Sync now, i think so..)

'a' eh, 'which' and please with a link to the manual if you want to provide the information we need.

Both Midi-Sync and Midi-timecode are not dependant on the Midi channel. (think about it !)

I have a small Casio keyboard - when i start the drum unit in it, the sequencer in the MS-1 responds. The casio sounds terrible and i won't use it for anything but experiments.

And i have read up on both the MIDI standard and several tutorials... and must confess, i'm in way over my head. I have spent a week trying to understand this, and i don't. Most of the stuff demands that i already have some knowledge of communication protocols, and i don't. Talk about a old dog trying to learn new tricks...

It can't be a Sync command - that would need upscaling one pulse to 24?

I don't understand?

Anyway, here is a link to the MS-1 manual: User manual

Hm. If this really is a timecode signal, that should make the code even simpler; convert a pulse input from a digital input to a serial output containing only the timecode?

Maybe that helps: Search results for 'MIDI order:latest' - Arduino Forum

All in all it isn't all that complex. Keep in mind it was actually designed so that musicians could use it.

The data part in short :

  • Most MIDI commands consist of 3 bytes of which the last are 2 data bytes.
  • There are what are called real-time commands, which consist only of 1 single byte
  • Data bytes and command bytes are distinguished by the value of bit 7. (in the byte)

The hardware protocol is designed to be easy enough to build, to prevent ground-loops and in case of accidental mis-connection (swapping pins or output to output) or short-circuit, to not cause any actual damage.

Yet that is the most likely . Midi-timecode is rare to be used since it syncs to a particular bar in the receiving unit.
Upscaling to 24 pulse (or commands really) is not as hard as it sounds. those 24 commands don't need to be accurately spaced.

for every beat it's specific location in the sequence, it isn't simpler.

The way to approach this puzzle is step by step.

  • First built the hardware for transmitting MIDI and get that to send Note-On & Note-Off commands
  • Then try to send some real-time commands Start, Stop & Sync (or timecode) and confirm what is used to Sync
  • Then start working on the receiving end.

The MIDI.h library (and a few others) will provide you with fairly simple ways of doing some basic programming and examples. It isn't absolute beginners, but not that far beyond.

Anyway start by building the hardware, which Arduino board are you using ?

:laughing: Musicians have absolutely no idea what's going on in the cables! Most of the time i've assisted them, i feel lucky if they can plug a mono jack in....

So for every input trig, you'd send 1 real and 23 dummy commands?

Just a Nano. I've made a "Quick'n-dirty" diagram (Yes, it ain't pretty)

I'll try this out and experiment a bit with the commands.

Thank You very much for Your input; it has given me something to work on! :grinning_face:

...If i find a solution, is it appropiate to publish it in this thread...?

Right now i sit and feel like a real idiot.

I have a USB-to-MIDI-IO box and a Linux laptop. I can just connect the box to the Casio keyboard/drum machine and see what data packages it sends out...

I just have to work out which commands to use.

I'm a (expletive) idiot ! :weary_face:

Not really, what you should do is determine the speed from the input trigger and try and space them as accurately as possible so the 1/8th , 1/16th triplets etc in the sequencer sound at the correct moment.

That single trigger per beat is not very accurate but you can write an algorithm that may drift a bit for the first beat but then syncs perfectly. But the commands you send are not dummy commands. Also you will probably have to send a 'Start' and 'Stop' command.

They don't but musicians involved in synths and drum computers tend to know something about MIDI even if it is just from their DAW use. Most Guitarist don't know about a truss-rod and most definitely don't think about the waveform of the sound and how it can be amplified etc, but with proper explanation it is usually within their level of comprehension.

It's pretty enough. Any reason you chose to use a 7809 and connect to Vin rather than just a 7805 and connect to 5v ?
The onboard regulator on the Nano is small and can source or sink up to 200mA at most. It is fine the way it is, but it does limit you options for expansion of the project if you want to.
Also it may be better to use one of the 2 external interrupt pins (D2 & D3) for receiving the trigger, although a PinChangeInterrupt will also suffice.

Keep in mind that the pin numbering on the DIN plug is ambiguous. Or rather you will find mirrored versions of it for reference. Unlike an XLR plug they don't have numbers written on it. If i compare it with my schematic, the visual way the DIN plug is represented in your schematic it should be the front view of the female plug. Swapping pins 4 & 5 on the plug is the first thing to try when it doesn't work at first.

Yes it is. If you find one particular post to provide you with it, you can mark it as such, but that could be your own post as well.

If you have a program that can tell you exactly which they are, then yes. MIDI tends to stay a bit under the hood.

Actually an Arduino is usually easier for such a task.

I suggest that you just try and send Note-On & Note-Off commands to the Synth first (observe the channel and keep in kind they may not align properly. Channel 1 has a byte representation of 0. The enums and Macros usually cover this up though, but not always, it depends on the code. It may be a bit of trial and error, checking both channels and the polarity on the plug etc. Once you have that working you have the basic hardware thing working and you can start on sending pulses and Start & Stop and get that to work. From there you can move to the receiving end of things.

Yes.

  1. With a 7809 and an appropriate transformer, it can run on 110 and 230V without changing parts

  2. The 7805 on the Nano does not have an awfully large heat sink. By supplying it by a lower-than-12V i reduce the thermal load of the regulator

  3. It is 'dirty' engineering to supply 5V directly to the output of the 7805, as the entire internal regulation circuit is still active. Furthermore, there is no reverse diode (It could be added externally) that prevents the output of the Nano's 7805 to exceed the input voltage with more than 0.6V. Both these factors will severely decrease the lifespan of the 7805, and they tend to short when they break down...

I tried to hook a USB-to-MIDI breakout box ( found here ) up to my Linux laptop.

First, i identified the box:

kim@lillefix:/dev$ aconnect -i
client 0: 'System' [type=kernel]
0 'Timer '
1 'Announce '
client 14: 'Midi Through' [type=kernel]
0 'Midi Through Port-0'
client 20: 'Arduino Leonardo' [type=kernel,card=1]
0 'Arduino Leonardo MIDI 1'

Next, i used a 'sniffer' to see the data when hitting a key:

kim@lillefix:/dev$ aseqdump -p 20:0
Waiting for data. Press Ctrl+C to end.
Source Event Ch Data
20:0 Note on 0, note 65, velocity 64
20:0 Note off 0, note 64, velocity 0

Then i tried to start the Casio rythm unit:

kim@lillefix:/dev$ aseqdump -p 20:0
Waiting for data. Press Ctrl+C to end.
Source Event Ch Data
20:0 System exclusive F0 F7
20:0 Clock
20:0 Clock
20:0 Clock
20:0 Clock
20:0 System exclusive F0 F7
20:0 System exclusive F0 F7

It seems like the only two things the box sends are the "System exclusive" and the MIDI clock.

Now, i need to work out a bit of code so i can try sending these events seperately. But i fear that it is the clock that the sequencer responds to.

Ok !? I have never had the need to provide for that though.

A simply USB wall wart obtained locally is my preferred option. Coil transformers are expensive.

The Basic_IO example provides the NoteOn & NoteOff, for sending the 'clock' you can use

MIDI.sendRealTime(midi::Clock);

a very simple program can be written to send out clock messages initially.

Thereafter things may get a little more complex since you first need to translate the incoming pulses into a BPM, but also that is not to hugely complicated.

This is getting slightly weird. I ran a test, using this code:

// Define the interval between MIDI Clock pulses (in milliseconds)
const int midiClockInterval = 500;

void setup() {
// Initialize Serial communication on the hardware Serial port
Serial.begin(31250);
}

void loop() {
// Send a MIDI Clock pulse (Timing Clock message)
Serial.write(0xF8);
delay(midiClockInterval);
}

I comes out... the sequencer in the MS-1 advances one step for each six MIDI clock signals!

o_0

Well, so be it. Now i just have to add some input trigger code and play a bit with the Clock spacing, then i can get this show on the road...

That would suggest 1/16th note is a step.

Pretty much. Of course delay() or delayMicroseconds() is not the best solution to send the clock signal, since that would be blocking your processing thread, during which reception may not work properly (depending on the use of interrupts of course)

But you clearly have working hardware and figured out the protocol for sync, which was the original query.

Congratulations !

That's it. "The Thing" seems to work!

I still need to polish the code a bit - it is slightly weird - but the crude version is this:

const int inputPin = 2; // Digital pin 2

void setup() {
  // Initialize Serial communication on the hardware Serial port (TXD is D1)
  Serial.begin(31250);
  // Initialize the digital pin as an input:
  pinMode(inputPin, INPUT);
}

void loop() {
  // Read the state of the input pin:
  int pinState = digitalRead(inputPin);

  // If the input pin is HIGH, send the data
  if (pinState == HIGH) {     

    // Send a MIDI Clock pulses (Timing Clock message)
    Serial.write(0xF8);
    Serial.write(0xF8);
    Serial.write(0xF8);
    Serial.write(0xF8);
    Serial.write(0xF8);
    Serial.write(0xF8);
  }

}

The input pin was moved to D2 as suggested.

My best thanks to Deva_Rishi for support, suggestions and ideas. Without Your help, this could not have been done... at least, not by me...

Thanks for Your help! :star_struck:

Update: this code is better (the other worked with one keyboard but tilted another) but it's still dirty.

It works with a DR-55 rythm unit, but ought to work with anything that delivers a 5V pos-going sync pulse.


const int inputPin = 2; // Digital pin 2

void setup() {
  // Initialize Serial communication on the hardware Serial port (TXD is D1)
  Serial.begin(31250);
  // Initialize the digital pin as an input:
  pinMode(inputPin, INPUT);
}

void loop() {
  // Read the state of the input pin:
  int pinState = digitalRead(inputPin);

  // If the input pin is HIGH, send the data
  if (pinState == HIGH) {     

    // Send a MIDI Clock pulses (Timing Clock message)
    Serial.write(0xFA);  // MIDI Start
    delay(5);
    Serial.write(0xF8);  // MIDI Clock
    delay(5);
    Serial.write(0xF8);
    delay(5);
    Serial.write(0xF8);
    delay(5);
    Serial.write(0xF8);
    delay(5);
    Serial.write(0xF8);
    delay(5);
    Serial.write(0xF8);
    delay(5);
    Serial.write(0xFC);  // MIDI Stop
  }

}

These commands should only be required once, not repeatedly.

Serial.write(0xFA);  // MIDI Start
(...)
Serial.write(0xFC);  // MIDI Stop

Before you start checking if the pin is 'HIGH'
you should first make sure that it has actually returned to 'LOW'

if (pinState == HIGH) {     

    // Send a MIDI Clock pulses (Timing Clock message)
    Serial.write(0xF8);  // MIDI Clock
    delay(5);
    Serial.write(0xF8);
    delay(5);
    Serial.write(0xF8);
    delay(5);
    Serial.write(0xF8);
    delay(5);
    Serial.write(0xF8);
    delay(5);
    Serial.write(0xF8);
    while (digitalRead(inputPin) == HIGH)  {
       delay(1);
    }
  }

The idea behind using pin 2 or 3 was to actually use interrupts on the receiving pin.

Try this :

const int inputPin = 2; // Digital pin 2
const uint32_t timeOut = 2000;
volatile bool pulse = false;
bool hasStarted = false;

void setup() {
  // Initialize Serial communication on the hardware Serial port (TXD is D1)
  Serial.begin(31250);
  // Initialize the digital pin as an input:
  pinMode(inputPin, INPUT);
  attachInterrupt(digitalPinToInterrupt(inputPin), pulseReceived, RISING);
}

void loop() {
  static uint32_t lastPulse = millis();


  // If the input pin is HIGH, send the data
  if (pulse) {
    if (!hasStarted) {
      Serial.write(0xFA);  // MIDI Start
      delay(5);
    }
    lastPulse = millis();
    Serial.write(0xF8);  // MIDI Clock
    delay(5);
    Serial.write(0xF8);
    delay(5);
    Serial.write(0xF8);
    delay(5);
    Serial.write(0xF8);
    delay(5);
    Serial.write(0xF8);
    delay(5);
    Serial.write(0xF8);
    pulse = false;    
  }
  if ((hasStarted) && (millis() - lastPulse > timeOut)) {
    Serial.write(0xFC);  // MIDI Stop
    hasStarted = false;
  }

}

void pulseReceived() {
  pulse = true;
}

With an external analog trigger, you never really know when the pulse train starts or stops. One of my keyboards could randomly go out of sync if MIDI Start/Stop is left out, both of them work with the commands left in. So... i left them in! It does not seem to disturb anything.

The entire sequence of the loop fits easily between two trigger pulses, no matter how high setting of the drum machine, so i didn't bother. But i admit it's the correct way of doing things!

Again, the sequence of the loop fits between trigger pulses (The compiler must be quite good - i would have thought that a small ting like the Nano would have needed assembler code to be this fast!). If i managed to interrupt the output pulse sequence, the whole thing would go out of sync anyway.

However, i have been looking for the practical use of interrupts for another project, so i am most grateful for that code snippet! :smiley:

I did an updated version of the circuit diagram. Still not too pretty;

I added a 40106 to ensure that the pulse shape is OK. I also added a switch and a voltage divider - it should be possible to use this box with 3 different analog trigger systems now.

D2 is just there to protect U2 - in case a 15V pulse is applied to the input with the switch in a 5V position, it will clamp the input voltage to the supply voltage.