My MIDI Upgrade
In Part 1 of this article series, Jeff built a system to simulate breezes randomly playing the sounds of suspended wind chimes. In Part 2 the effort evolves into a less random, more orchestrated project. Using the MIDI standard, Jeff decided to craft a string of chromatically tuned chimes, similar to what an orchestra might use so the project could be used to play music.
This project that began last month to simulate a breeze’s random playing of suspended chimes has expanded—as all engineering projects seem to do. While the circuit and code presented last month can be limited to the standard five-note pentatonic chimes, in the process the code was structured to allow more that those five notes. Please read last month’s article (Circuit Cellar 347, June 2019) to get some background on wind chimes and the music theory used to document or score how a song is written.
By the end of Part 1, you had all the tools to produce random strikes of a pentatonic chime, using solenoids instead of the wind. The aim was to give some relief during those long winter months, by bringing the sounds we relate to summer’s warm tropical breezes—wind chimes—indoors. In the process of discussing the music of wind chimes and having extra I/O available on the microcontroller (MCU), I decided to create a string of chromatically tuned chimes similar to those an orchestra would use. With that in mind, the project could be used to play music as well as soothe the savage soul with random (potentially) harmonious tinkles. With 16 outputs, I can cover more than an octave of chromatic notes. A chromatic octave has seven natural notes and five sharps/flats (the white and black keys of a piano).
When you research music, or more precisely the scoring of music, you eventually bump into MIDI. MIDI (Musical Instrument Digital Interface) is an industry-standard music technology protocol designed to create, perform, learn and share music and artistic works. MIDI communication is via a serial stream commands of what, when and how to play specific notes. The simplest MIDI stream sends commands to play and to stop playing a specific note, known as Note ON and Note OFF.
To receive MIDI commands, we need an asynchronous serial interface running at 31.25 Kbaud (8 bits, 1 stop, no parity). You may have noticed that this is a non-standard communication rate. It was chosen to allow a 3-byte command to be sent in just 1 ms. The MIDI communication standard requires current loop circuitry to be used as shown in Figure 1. This isolation helps to eliminate ground loops. By rights, any device outputting MIDI should conform to this MIDI standard, but, in fact, newer technology makes this a bit outdated and USB is being written into the standard.
All MIDI commands begin with a Command Byte. The command byte has the MSB (most significant bit) set, while all other data have the MSB cleared. This means any character from 0x80-0xFF will be a command. Please refer to the MIDI specification  for additional information. While the project will interpret many of the MIDI commands, I need only mention two commands that pertain to this project.
0x8? Note OFF, where “?” is Channel (or Instrument) 0-15
0x9? Note ON, where “?” is Channel (or Instrument) 0-15
Both commands are followed by two additional bytes—the note number and velocity—both of which are numbers 0-127. The note number indicates which note is to be played, and this is based on a piano (Figure 2). The velocity byte is an indication of the sound envelope or volume. Note ON with a velocity of “0” may be interpreted as a Note OFF, because it has no volume. Because our end product here is striking a chime, we really only need to pay attention to the Note ON commands because we won’t be turning off a chime.
In a live performance, the musician’s pressing and releasing a note will send the Note ON and Note OFF MIDI commands. If the performance is recorded, then there must be timing commands added to a MIDI file, so when the MIDI file is played back the proper Note timing can be reproduced. So, a MIDI file contains more than just ON and OFF commands. It begins with some descriptive information followed by formatted commands as a list. Each command is preceded by a delta time code. In many cases this will be a zero, meaning the following command is executed immediately. Values other than zero mean a delay must be carried out before the next command is executed. These values represent the timing added to the playing of notes to signify either a DURATION of note (before a note OFF is sent) or a REST (pause) between notes.
We’ve already discussed the Command rule of having the 8th-bit set and their supporting data bytes having their 8th-bit cleared. These timing values must take on a special format, so they don’t break this rule. The delta time code is made up of one or more bytes, where all bytes except the last have their 8th-bit set. This means that every byte is limited to 7 significant bits (except the last). You must squash all of the (significant) bits together to interpret the value. The value you end up with is the number of ticks per quarter note you must delay. It helps to know what a quarter note is, and you can refer to my last article or just be content in knowing that in music, this is a measure of time. Sheet music represents all notes and rests (pauses), with their own special icons representing a duration of time. That time is some division of the music’s beat.
You can delve more deeply into this in last month’s article. If you wish, the specifications are available at midi.org. The code for this project must understand the majority of the MIDI commands, so as not to lose sync with a MIDI file. I won’t be spending time on those here. The basics for Live MIDI consist of mostly ON and OFF commands. Since this project only requires ON commands, this simplifies the execution of solenoid pulses to only those commands. This boils down to interpreting ON commands (0x9? 0x?? 0x??) by extracting the Note of interest, looking for that Note in the Note table (EEPROM), and if found, pulse the appropriate solenoid to strike the proper chime. So, now let’s look into the chimes.
Google “DIY wind chimes,” and you will find a plethora of information. My browser led me to Leland Hite’s page, leehite.org. After seeing what he’s written on the subject of chimes, you’ll want to explore his other engineering interests. I made use of a number of charts listed there for cutting various materials into tubular chimes. I was able to find 8’ of 1” aluminum stock  from Home Depot for less than $15. Using the appropriate chart, I sawed up a bunch of aluminum for my chimes. See Figure 3 for some pictures of that process. I wasn’t sure of the accuracy I would need to have these chimes tuned properly. My hacksaw cuts weren’t the straightest, so I added a bit to the lengths. That meant that when I used the sanding belt to square off the ends, they would end up not being too short. So, what does that mean?
As you remove material from the end of the chime, its pitch gets higher and higher. I grabbed an app for my phone that aids in tuning a stringed instrument by indicating the frequency in which the string is vibrating. I used the mobile app “gStrings” to aid in tuning the frequency of each tube (available on Google Play). It uses the phone’s microphone and interprets what it hears. You need to realize that in most cases there will be overtones, or other frequencies produced that can interfere with this process. Using a soft material for rapping on the chime will produce the least interference. There are two ways in which you can tune your chime. The phone app will give you an indication of the frequency it hears, or you can set it to play the appropriate frequency, like striking a tuning fork. Listening to this while you strike the chime will allow you to judge the difference. Remember, you can only raise the pitch of a chime by shortening it. If the pitch needs to be lower, you have to cut a new chime. I was able to get pretty darn close to the actual frequency by sanding off a little at a time and rechecking as shown in Figure 3.
With all the chimes cut, I needed a way to hold them and the solenoids in place. I used a few pieces of oak for the frame. Grooves at 1.5” intervals allow 1/2” between chimes (Figure 4). Holes in tops, centered on the solenoid grooves, allow each chime to hang in line with each solenoid’s plunger. The solenoids are wired in two groups of eight, to the 9-pin connectors on the prototype PCB. It took a while to locate some #M3 hardware of an appropriate length to mount the solenoids. They’re tapped for #M3 (metric screws).
If you are interested in making a traditional, round, five-note pentatonic chime, you might try using the solenoids attached to the standard suspended clapper from different directions. With this approach you would be moving the clapper like the wind does, and not striking each chime directly. However, this project’s direction has taken a chromatic approach. By using chromatic chimes, I can reproduce notes corresponding to those played on a MIDI keyboard or other instrument. MIDI input can also direct the chimes to play prerecorded MIDI files. All this feature creep is typical of many an engineer’s approach to a project. While I wouldn’t do this when designing for a client, I am free here to let my projects fly free. So, while the project started off with buttons to choose modes and LEDs to provide feedback, I’m leaning toward more feedback for a cleaner “user” interface.
The last project I used this display on was the one described in my articles “Long-Range, Low-Power Wireless Communications, Parts 1 and 2” in June and July of 2017 (Circuit Cellar 323 and 324). Available from Adafruit, the SSD1306 is a 128 x 64 Dot Matrix OLED display with a 4-wire I2C interface. It was simple to use with an Arduino device, thanks to the SSD1306 library. But this time I’ll need to write my own routines for the Microchip PIC MCU I’m using here. The most difficult part of using this device is getting all the registers initialized correctly for the mode in which you wish to use it. I’m using the “Page Mode” here, which allows the display to be broken up into eight, 8-row pages of 128 bits (columns) each.
When you point to a page and column with a command byte and write-a-data byte, the 8 bits of the data byte are displayed vertically in that column. A data byte of 0x00 turns OFF all the bits in that column, and a data byte of 0xFF turns all the bits ON in that column. So, with 5 bytes of the proper data, you can form any 8 x 5 graphic or alphanumeric character. You can therefore use a stored table of character data to aid in displaying messages.
Presently, I’ve defined messages for five of the eight pages (character lines). The top two lines display typical sign-on project information. The fourth line displays the present mode. The last lines display user feedback messages that indicate which of the three original buttons are enabled and what their purpose is. One button is a reset to the circuit, and the other two are for user entry.
There are presently six modes of operation:
1. Play Random Mode
2. Play Live Mode
3. MIDI File EE Record
4. MIDI File EE Play
5. MIDI File EE Store
6. MIDI File EE Read
The first was discussed last month and is the basic “No Wind Chime.” The second allows Live Play from a MIDI device or a MIDI prerecorded file. The last four are used to capture Live MIDI, play it back, store it in EEPROM and recover it from EEPROM. These might be used to save the little ditty on board, and use it as one might use a ringtone. Button 1 allows the user to cycle through the various modes. Button 2 is used to start and stop each mode. Pretty simple, but doing this without the display would be next to impossible. Let’s see how this is all tied together by code.
Much of the MIDI code was developed to support last month’s article. I knew at the time that I didn’t want to limit the project to simply rapping chimes. The MIDI format is being used for more than just music. These days, it can be used for show, machine and phone control. This established format could use a technology update. The biggest issue would be backward compatibility. MIDI users will not accept any new standard that disregards equipment already in use. Note: To ensure compatibility, a new specification has been added MIDI-CI. This is a systematic inquiring of the equipment attached, to determine its limitations. In the case of no reply, the fallback position is MIDI 1.0. This mechanism will open up a MIDI exchange to the new MIDI 2.0 specification that is in the draft process.
While MIDI 1.0 can be complex, basic “Live” communication is pretty simple. But you need to be aware of all potential MIDI traffic, or you run the risk of losing sync with the data, at least short term. The decision to add the OLED display added a layer to the previous code. As you can see from the flow diagram in Figure 5, the Main loop handles this layer by determining what mode to run in. The text displayed will vary slightly, depending on the mode value. Additionally, the ModeFlag bit “YES” determines whether the mode displayed is actually initiated. Just displaying a mode does not initiate it. While NOT initiated, Button 2’s label is “Start”. The user must initiate the mode by pressing Start. Once the mode is executing, the label on Button 2 is “Stop”. Pressing Button 2 a second time will halt execution and relabel the button Start.
Button polling is handled in the Timer0 interrupt routine. Figure 6 shows the Timer0 interrupt, which gets triggered when the timer count rolls over. This register is loaded with a value that will roll over every millisecond. The first set of queries, Note0Count through Note15Count, handle turning off any solenoid pulse that has been activated. The activation of a solenoid also must set the associated Note?Count value to 100, to allow this part of the Timer0 interrupt to turn off the solenoid after 100 ms.
The second part of this routine only has to execute every 40 ms, so a NoteTick register—pre-loaded with 40—is decremented to keep track of this. Only when NoteTick reaches zero will the following three routines be tested. These run once every 40 ms.
40 ms is a magic number determined by the BPM (beats per minute) value. BPM is description of the tempo of a piece of music or song. It tells a musician how long to hold a note. A BPM of 120 equals 2 beats/s or 500 ms/beat. In many cases, the quarter note gets the beat, meaning a quarter note will last for 500 ms, the duration of 1 beat. Faster notes (eighth notes, sixteenth notes and so on) require faster times (250 ms, 125 ms and so forth). 500 ms /12, or about 40 ms was chosen because it is a factor of all these notes, including the special case triplets. The DurationCount can be used for timing the duration of notes or the duration of pauses (or rests) between notes. The count placed in the DurationCount register determines the time until the DurationDone flag is set to 1, a multiple of NoteTick. This is used only in the “Random Mode” where durations are chosen on the fly. For any MIDI operation, durations are part of the MIDI communications.
Finally, the buttons are polled here. The 40 ms acts a switch debounce. Button 1 increments the Mode register on each push. Button 2 toggles the YES bit in the Flags register, which starts/stops execution of the chosen mode.
This is a bit of a misnomer. It is actually a MIDI stream that’s either Live or from a prerecorded MIDI file. Note: The MIDI Record mode extracts the essentials, notes and durations and stores them in a volatile array. EE Store saves the array to EEPROM. EE Read transfers the EEPROM back to a volatile array. MIDI Play plays the volatile array. This allows the user to store a short performance and replay it. It’s beyond the scope of this article to expand on these future embellishments.
There are differences in Live MIDI vs. a MIDI recording. A MIDI file has a ton of other information about the performance, whereas a Live MIDI stream has mostly note ON and OFF information. Note durations and rests are implied by the data within the stream. So, let’s go through what happens when the Live mode is selected and the user hit’s Start (ModeFlags.YES).
Actually, nothing happens until we receive a character, as shown in Figure 7. Once MIDI data begins, we can begin to interpret it. Since Live MIDI data are only event data, we know that the first byte will have its MSB set. The data will be 0x8?, 0x9?, 0xA?, 0xB?, 0xC?, 0xD?, 0xE? or 0xF?. While we are only interested in event 0x9? (Note ON), we still have to interpret all events to stay in sync with the data stream (Figure 8). Figure 9 shows the flow for Event or Message 0x9?. The “?”, or LSNibble (least significant nibble) carries the channel number 0x0-0xF. The channel number or instrument allows up to 16 instruments to stream their MIDI data in the same MIDI connection. Although we could be selective here, we’ll accept any channel, and assume only one instrument is attached. Message 0x9? requires two additional bytes of data. The first is the actual Note Number (refer back to Figure 2). The second is the velocity, volume of the note. In Live MIDI we only need the Note Number, and search for it in the EEPROM Note Table—the list of notes assigned to each solenoid. If the note is in the list then it is played by pulsing the appropriate solenoid. Remember: We only need to enable the solenoid driver. The code in the Timer0 interrupt disables it after 100 ms. The execution returns (Figure 7), and we have a chance to Stop or look for more MIDI data.
Although I’m not a musician, I do play one in this engineering column. My instrument of choice here is Rockband 3’s Keyboard (for the Wii), to stream MIDI data to this project so I can “wail some mean chimes” (Figure 10). I do have a pretty good imagination when it comes to performance. However, the reality is that this project is more like playing a Carillon than rockin’ out. I guess I’ll need to get a powdered wig!
Thanks for staying with me on this one. There were quite a number of different skills necessary to pull off this project—and still a lot more coding to do if I want to save a performance. Most likely, this project will get delegated to becoming a fancy doorbell or a Westminster chime. Hmm…I’ve always liked the sound of a “chiming grandfather clock!”
Additional materials from the author are available at:
References  and  as marked in the article can be found there
Adafruit | www.adafruit.com
Microchip Technology | www.microchip.com
PUBLISHED IN CIRCUIT CELLAR MAGAZINE • JULY 2019 #348 – Get a PDF of the IssueSponsor this Article
Jeff Bachiochi (pronounced BAH-key-AH-key) has been writing for Circuit Cellar since 1988. His background includes product design and manufacturing. You can reach him at: email@example.com or at: www.imaginethatnow.com.