MIDI Controlled Bells

Hi All

I have never used Arduino before but based on the research I have done for my project, it is what I need to be using.

I have a set of nine tuned bells, each with a solenoid which activates a wooden clapper. I want to adapt these so that I can plug them into my computer as a MIDI instrument, ie so I can send MIDI messages from my computer to play the bells. I also intend on connecting my MIDI piano to my computer, then through to the bells.

I have no idea where to start, and am uncertain whether this is a project I can manage. In light of this, I have a few questions;

  1. Would you recommend a complete beginner attempt such a project?
  2. Is the the place where I might be able to find step-by-step support from the community?
  3. Where do I start? What do I need? (I have a Macbook Pro, MIDI Piano, nine wired bells)

Your support is appreciated

DT

In your shoes I would be getting one bell to dong under program control (eg. once every 5 seconds). To do that I guess you will need some sort of driver transistor to amplify the Arduino output pin enough to drive the solenoid. Once one is working, get all 9 to work. Then reading the MIDI input should be fairly simple. :slight_smile:

You will need at least the following:

  • Arduino board
  • Midi interface like this one: https://www.sparkfun.com/products/9598.
  • solenoid drivers. ULN2xxx can provide up to 500mA/outputand are quite inexpensive. They have built in diodes as well.
  • Power supply(s) you can use one common supply for both the arduine and the solenoids but i recommend two separate
  • If you want to turn the project into a standalone midi instrument later, there should be som HMI, Dont focus on that, but have it in mind when planning for pin assignment etc.

Start by getting an arduino board and learn how to write simple programs. Then build the solenoid interface and proceed on the path that nick points out. Take small steps, complete each step and dont be afraid to ask for help and you'll get there

Not step by step but gives you an idea of the overall system you need http://www.thebox.myzen.co.uk/Hardware/Glockenspiel.html

Thank you all for your advice.

I now have an Arduino board.

As for the MIDI breakout, can you confirm that I won't actually need this as I am doing everything with USB (I have an adapter than converts midi from my piano to USB)?

@Grumpy_Mike: This article is mighty useful, thank you! The author refers to an LM18293 driver chip to boost the output pins from 5V to 12V. I also need to fire my solenoids with 12V. What is this driver chip? How do I get one? Can I get away without using it?

@nilton61: Your advice is also very useful. I have a 12V power source that would plug right into the Arduino board it is the adapter that came with the bells, will this be sufficient? Can the Arduino board handle 12V? If I were to give another power source, where would this plug into?

I agree that I need to start form the basics to familiarise myself with the Arduino. Can you recommend some basic guides? I don't have a clue where to start.

Your help is greatly appreciated :)

Note: The chip on my Arduino says it is an ATMEGA328P-PU

@Grumpy_Mike: This article is mighty useful, thank you! The author refers to an LM18293 driver chip to boost the output pins from 5V to 12V. I also need to five my solenoids with 12V. What is this driver chip? How do I get one? Can I get away without using it?

The author is me. :) That is an old chip you might not be able to get it any more. However a ULN2003 will work just as well.

I am doing everything with ISB (I have an adapter than converts midi from my piano to USB)?

You won't be able to read that MIDI on your Arduino

USB is a real pain on Arduino. You're far better off interfacing with MIDI from the piano directly.

You won’t be able to read that MIDI on your Arduino

Well, my project is on track. This is what I have achieved thus far;

  1. I was easily able to get my Arduino to respond to MIDI messages sent by my computer by USB. I used Hairless MIDI from The Hairless MIDI<->Serial Bridge (Thank you Angus Gratton), and wrote a simple program to control an LED using MIDI messages.

  2. My next step was to create a secondary circuit with a separate 12V DC power source to drive the nine solenoids (12V, 150mA, 80?). My output pins 3 – 11 are each connected via a 1K resistor to a transistor (2N2222) which activates the 12V flow for the solenoid. Each solenoid has a reverse diode to protect any back flow from frying the transistors. The bells (with solenoids inside of them) are connected in a chain, which I think puts them into a parallel circuit. Here is how the bells are setup:


The switch symbol represents the circuit below.

Here is how my circuit is setup:

The red dots are where one point of the solenoid is connected. The orange wire is where the other end of the solenoid is connected. These are all joined together.

  1. Then I wrote the sketch to control the individual bells. This is my first ever sketch (apart from the tests leading up to this). Any suggestions for improvement would be greatly appreciated. Can anyone suggest code that will allow me to play two or three bells at once? The current code only allows quick successions which are 80 ms apart – this is to allow for the solenoids to strike.

This is the code:

#include <MIDI.h>

void HandleNoteOn(byte channel, byte pitch, byte velocity) { 
  if (velocity == 1) {
    if (channel == 1){
      if (pitch == 62){
          digitalWrite(3,HIGH);
          delay(40);
          digitalWrite(3,LOW);
      }
      if (pitch == 64){
          digitalWrite(4,HIGH);
          delay(40);
          digitalWrite(4,LOW);
      }
      if (pitch == 66){
          digitalWrite(5,HIGH);
          delay(40);
          digitalWrite(5,LOW);
      }
      
      if (pitch == 67){
          digitalWrite(6,HIGH);
          delay(40);
          digitalWrite(6,LOW);
      }
      if (pitch == 69){
          digitalWrite(7,HIGH);
          delay(40);
          digitalWrite(7,LOW);
      }
      if (pitch == 71){
          digitalWrite(8,HIGH);
          delay(40);
          digitalWrite(8,LOW);
      }
      if (pitch == 72){
          digitalWrite(9,HIGH);
          delay(40);
          digitalWrite(9,LOW);
      }
      if (pitch == 74){
          digitalWrite(10,HIGH);
          delay(40);
          digitalWrite(10,LOW);
      }
      if (pitch == 76){
          digitalWrite(11,HIGH);
          delay(40);
          digitalWrite(11,LOW);
      }
    }
  }
  }

void setup() {
  MIDI.begin(MIDI_CHANNEL_OMNI);
  Serial.begin(115200);
  
  pinMode(3,OUTPUT); 
  pinMode(4,OUTPUT);
  pinMode(5,OUTPUT);
  pinMode(6,OUTPUT);
  pinMode(7,OUTPUT);
  pinMode(8,OUTPUT);
  pinMode(9,OUTPUT);
  pinMode(10,OUTPUT);
  pinMode(11,OUTPUT);
  
  MIDI.setHandleNoteOn(HandleNoteOn);
}

void loop() {
  MIDI.read();
}

My current problem:
You have have spotted my problem from the above information, but I cannot get my head around what I have done wrong with my circuit. Any help would be greatly appreciated.

My problem is that when I send and of the designated MIDI messages, all of the bells try to ring (there is not enough power to ring all of them. I doubled checked the sketch and have determined that this is not the problem. I have looked at the circuit but cannot figure out what I have done wrong; is it the fact that all of the ground ends of the solenoids are joined together? Am I going to have to tear apart the whole cable just to get this thing to work?

Here are a few more pics for those interested:


PS
This is so friggin’ addictive! I’ve only been doing this for a few days!

Theodoridis:

You won't be able to read that MIDI on your Arduino

Well, my project is on track. This is what I have achieved thus far; 1. I was easily able to get my Arduino to respond to MIDI messages sent by my computer by USB. I used Hairless MIDI from http://projectgus.github.io/hairless-midiserial/ (Thank you Angus Gratton), and wrote a simple program to control an LED using MIDI messages.

Well if you has said that you were going to use a laptop and MIDI interface then I would not have said that. You appeared to be wanting to plug a MIDI keyboard into an arduino through USB.

Anyway have you got a schematic of your interface because a Physical layout like you posted is absolutely useless. You seem to have connected the arduino outputs directly to a 9V power source. That is a sure fire way to destroy your arduino.

I am not quite happy with your wiring. I attach two pictures as well as the fritzing file

Midi glockenspiel.fzz (29.1 KB)

Theodoridis:
Can anyone suggest code that will allow me to play two or three bells at once? The current code only allows quick successions which are 80 ms apart – this is to allow for the solenoids to strike.

To ‘multitask’, you must eliminate all those delay()s.

You’ll need unsigned long timer variable for each solenoid.

When you receive a MIDI ‘strike’ message, turn the appropriate pin HIGH and set the appropriate timer. Don’t set the pin LOW here! Then go back to looping as usual.

In your loop, check for expired timers against millis() and when a particular timer has passed, set that corresponding solenoid pin LOW again.

const byte solenoid[9] = { 3, 4, 5, 6, 7, 8, 9, 10, 11 }; // pin numbers here
unsigned long solenoidTimer[9]; // tracks when it's time to turn a solenoid off

void HandleNoteOn( blah blah )
{
if ( blah blah)
  if (pitch == 62)
    {
    digitalWrite(solenoid[0], HIGH);
    solenoidTimer[0] = millis() + 80; // schedule a 'turn off' event 80ms from now
    }
  if (pitch == 64)
    {
    digitalWrite(solenoid[1], HIGH);
    solenoidTimer[1] = millis() + 80; // schedule a 'turn off' event 80ms from now
    }
  etc
}


void loop()
{

MIDI.read();

// UNstrike
for(byte i=0; i < 9; i++) // for each solenoid,
  {
  if (millis() > solenoidTimer[i])  // more than enough time has passed...
    { digitalWrite(solenoid[i], LOW); } // ...so turn this one off
  }
}

I’m going to offer some code style advice. I hate reading code with a ton of nested IFs. Try this:

void HandleNoteOn(byte channel, byte pitch, byte velocity) {
  
  int pin = 0;        // Pin number for bell solenoid
  
  // Ignore messages on other channels
  if (channel != 1) return;

  // ED:  Why would you want to do this?
  if (velocity != 1) return;
  
  // Set appropriate pin based on pitch
  switch (pitch) {
    case 62:
        pin = 3;
        break;
    
    case 64:
        pin = 4;
        break;
    
    ...
    
    case 76:
        pin = 11;
        break;
  }
  
  // Only play a bell if the note is within range
  if (pin) digitalWrite(pin, HIGH);    // Use a timer instead, but it would go here
}

You might also want to use constants:

#define NOTE_D3  62
#define NOTE_E3  64
#define NOTE_F3  65
...
#define NOTE_E4  76

#define PIN_D3  3
#define PIN_E3  4
...
#define PIN_E4  11
   // Set appropriate pin based on pitch
  switch (pitch) {
    case NOTE_E3:
        pin = PIN_E3;
        break;
    
    ...
    
    case NOTE_E4:
        pin = PIN_E4;
        break;
  }

Makes it a little less confusing to edit later on.

Agreed on using a timer to turn of the note rather than toggling in the same function. Although the previous code example will run into problems once millis() overflows to 0 again. Not sure if your program will ever run long enough for that to be a concern (almost 2 months), but beware anyway.

Maybe a better approach would be to set the timers as a time-to-live counter that gets decremented every few ms until 0, then the solenoid is disengaged:

#define NOTE_COUNT  (NOTE_E4 - NOTE_D3) + 1

uint8_t  note_timer[NOTE_COUNT];  // # of semitones
uint32_t  last_millis;

setup () {
  uint8_t  i;
  
  // Pre-fill timer array
  for (i = 0; i < NOTE_COUNT; i++) {
    note_timer[i] = 0;
  }
  
  // Store time
  last_millis = millis();
  ..
}

loop () {
  uint8_t  i;
  uint32_t  time_elapsed = (millis() - last_millis);
  
  // Decrement note timer if millis() has advanced since last loop
  if (time_elapsed) {
    for (i = 0; i < NOTE_COUNT; i++) {
        // This note has been triggered, check its timer
        if (note_timer[i] > 0) {
          // Not ready to turn off yet, just decrement time-to-live
          if (note_timer[i] > time_elapsed) {
            note_timer[i] -= time_elapsed;
          
          // About to time out, clear TTL and turn off note
          } else {
            note_timer[i] = 0;
            // Assuming pin numbers are consecutive, calculate pin number
            // based on offset from lowest note
            digitalWrite(PIN_D3 + i, LOW);
          }
        }  // if note_timer > 0
      }  // for
    }  // if time_elapsed
}  // loop


void HandleNoteOn(byte channel, byte pitch, byte velocity) {
  
  ...
  
  // Only play a bell if the note is within range
  if (pin) {
    digitalWrite(pin, HIGH);
    note_timer[pin - PIN_D3] = 40;
  }
}

@nilton61: YOU ROCK! That fixed it! Thank you so much!

@SirNickity and @tylernt: Thank you for your suggestions. For now I have found that a 40ms delay is sufficient to ring the bells and to also allow for a polyphonic effect. I will still look into your codes and improve everything. I'm just a bit distracted playing these things now :D

This code eliminates the conditionals for solenoid detection as far as possible. It also uses separate timers for each solenoid

#include <MIDI.h>

const int Solenoid = 2;//Pin of first solenoid
const int NoBells = 9;
const int firstNote = 62;//number of first midinote to handle
const int lastNote = 76;//number of last midinote to handle
const int Note2Pin[] ={0, -1, 1, -1, 2, 3, -1, 4, -1, 5, 6, -1, 7, -1, 8 };//map midi notes to pin offset
unsigned long StrikeTimer[NoBells];//timers for turning off solenoids
const int StrikeTime = 40;//strike time 40ms
int StrikeCount;//#solenoids turned on

void setup() {
  MIDI.begin();
  MIDI.setHandleNoteOn(HandleNoteOn);
  for(int i = 0; i<NoBells; i++) pinMode(Solenoid+i, OUTPUT);//consecutive solenoid pins  
}//setup()

void loop() {
  MIDI.read();
  Turnoff();
}//loop()

void HandleNoteOn (byte channel, byte note, byte velocity){
  int pin;
  if((note < firstNote)||(note > lastNote)) return;//notes out of range
  if((pin=Note2Pin[note-firstNote]) > -1){//we have a valid note 
    digitalWrite(Solenoid+pin, 1);//strike bell
    StrikeTimer[pin] = millis();//start timer
    StrikeCount++;//update account
  }
}//HandleNoteOn()

void Turnoff(){
  if(StrikeCount < 1) return;//nothing to turn off
  unsigned long compare = millis()-StrikeTime;
  for(int i = 0; i < NoBells; i++) if(compare > StrikeTimer[i]){
    digitalWrite(Solenoid+i, 0);//Turn off solenoid
    StrikeCount--;//update account
  }//for-if
}//Turnoff()

@SirNickity and @tylernt: Thank you for your suggestions. For now I have found that a 40ms delay is sufficient to ring the bells and to also allow for a polyphonic effect. I will still look into your codes and improve everything. I’m just a bit distracted playing these things now

You could map the note velocity to the strike time for more dynamics. But first get this working

@nilton61: Thanks for your code, I've uploaded it and added Serial.begin(115200); after MIDI.begin();.

It is seriously doing something quite strange: the strike time is uneven, it won't let me play repeated notes, some notes will sometimes play, sometimes they won't.

Hmmm… I’m not sure thats a wise thing to do. In my reckoning both midi and serial use the hardware serial port. its very possible you have a conflict there. Its the right thing to do, i did not check hairless midi, sorry

I haven’t tested my code though, it was only meant as an example, and i don’t have the hardware to do the testing.

Some explanation to help you troubleshoot

HandleNoteOn():
first we check if the note is in the valid range 62 <= note <= 76, if not return from function immediately
Note2Pin[note-firstNote] does two things: if there is a bell for that note it gives the solenoid offset for that bell(0…8 ). othervise the value is -1.
The if statement checks for a valid note and simultaneously assigns the offset to the pin variable.
if we have a valid note the digitalWrite(Solenoid+pin, 1) turns on that solenoid and records the strike time for that solenoid in the StrikeTimer array.
After that we increase the StrikeCount variable. This variable keeps track of the number of solenoids currently activated.

TurnOff():
We first check if there are any solenoid activated. if not we return immediately.
If there is a active solenoid we first calculate the maximum allowable timer value (millis()-striketime) and store in the compare variable.
Then we scan through all StrikeTimer values and if we find a value thats older than 40ms we turn that solenoid off.

nilton61: I am not quite happy with your wiring. I attach two pictures as well as the fritzing file

Really sorry about pulling this old thread back up but I'm struggling with my code. Using the photos attached for my wiring whats my starting point for the code?

Your starting point is not to resurrect a thread from 2013 but start your own.

Hey Mike,

Thanks, just as i was using someone else’s images i thought it made a lot more sense to use this thread as it would be more specific to this one than a new one.

Id be more than happy to start a new thread if that will get me some guidance on this.

Thanks.