Monday, July 28, 2014

Music Box



In my last digikey order (for quadcopter stuff), I threw in a cheap piezo speaker just to play with. I had a lot of free time recently, so I decided to make a simple music box. It can store ~5 songs (depending on length), and you can also play it manually with the buttons.



I started off with simple square-wave waveform (with linearly decreasing amplitude) to get something that sounded like:



Not too bad, but a bit grating. I then tried using actual samples from pianos/guitars. This worked ok, but I had issues with the tradeoffs between sample size and the quality; in addition, I could only change the pitch by going through the sample faster or slower (so higher notes ended up being shorter).

Eventually, I found a great writeup by someone who made a similar project (http://www.deep-shadows.com/hax/wordpress/?page_id=1111). He used an approach that was relatively simple but sounded very nice and music-boxy. Essentially, it involves using a sine wave and decreasing the amplitude gradually:


(sine wave frequency not to scale)

In addition, he also wrote a really neat program that would convert .midi files into more direct data; this ended up being super useful.

The final design supports 4 independent notes playing at once. Both terminals of the speaker are controlled by PWM pins, so each pin is a software mix of two channels. Technically, I can mix more channels in software, but N channels means each channel's amplitude must be 1/N of the max. 4 channels seemed like a good balance.

Overall, the code is pretty short, at a couple hundred lines (https://bitbucket.org/kevinbchen/musicbox/src), but I feel like I've become a lot more comfortable with fiddling with the timer registers now!

The hardware was also generally straightforward:
The ~SHDN pin on the MAX756 should actually be connected to +5V (this ended up not being a problem though)


I wanted the form-factor to be small and self-contained (ie. some single-cell battery). I was initially hoping a 3.3V button cell (CR2032...I have like 100 of those leftover from ditch day...) would work, but those wouldn't be able to supply enough current for a decently audible speaker. I started looking into dc-dc step up converters so I could run it off a single AAA battery, and settled on the MAX756 chip - mostly because of it's DIP form factor. I stuck with the ATmega328p chip since I already had one on hand (and it had enough pins so I could have an octave of buttons.

Breadboarding the MAX756
I decided to order the PCBs from OSH Park again (I really like how easy their process is...just upload the Eagle .brd and that's it!). Might check out iTead next time, but it sounds like the turnaround time might be longer.


Assembly was pretty straightforward, since I went with all through-hole components (although I still had some trouble heating up the metal battery clips). Also, the thumbnail for the switch on digikey is wrong! I wanted black colored switches for the black keys, but got white instead ):

For some reason, the switch attached to pin D7 (the 'B key') wasn't being pulled up properly to logic high when open. Specifically, it looked like the microcontroller saw the pin as logic low whenever the speaker was being powered (from some rudimentary LED debugging). The speaker PWM pins are on D6 and D5, so it might be a problem with the speaker pulling too much current and pulling down the VCC? The other switches (like the ones on D0-D4) didn't have issues, so it's still a bit odd in any case. I also tried switching ATmega328p chips, so I don't think I messed up that specific pin. Unfortunately, I don't have an oscilloscope to properly debug.

Anyways, routing the switch to unused pin B4 and cutting off the D7 pin on the microcontroller fixed it!



I still have 2 PCBs left, so I might just order more parts and make two more music boxes when I get the chance (~$25 worth of parts for a single board if I buy from digikey).

3 comments:

  1. Hi:

    Thanks for your work.

    How to Use MidiToC.exe, if your code needs 3 fields, but software produces only 2.

    const uint8_t ambiguous[][3] PROGMEM = {
    {67, 160, 0},
    {69, 161, 0},

    vs

    const uint16_t fivecm[][2] PROGMEM = {
    {83, 464},
    {85, 465},

    ReplyDelete
  2. I see.
    Selecting all channels in midiToC.exe.
    Copying to clipboard.
    Run midi.py.
    Write name, choose tone shift.Paste clipboard.
    Look file *.h in songs/.

    please check this:
    song_index > NUM_SONGS

    ReplyDelete
  3. Hi there, could you please give a quick overview of how to create the song files? Which settings are needed in the miditoc.exe and what to do afterwards to create a file that can be used in your code.

    That would be great, thanks.

    ReplyDelete