Shallow Thoughts : tags : music

Akkana's Musings on Open Source Computing, Science, and Nature.

Sun, 17 Feb 2013

Playing music or sound samples on Arduino

I've done a few experiments with playing music on an Arduino over the years -- the Arduino library has a tone() call that gives you a nice tinny monophonic "chiptunes" style noise. But for playing anything more complex, you need more processing power.

I had a silly little project in mind. I like some pink noise when I'm sleeping (in summer, I usually have a fan running). You can buy electronic devices called "sleep soothers" that have tracks of the ocean, rain, trains etc. but they often have annoying misfeatures (like foghorns or train whistles in the middle of a track). Wouldn't it be more fun to make my own, with sound samples of my choice?

Pink noise samples

Of course, I needed some sound samples, and I found a great resource: Laptop.org's list of Free sound samples. I downloaded a few sample collections that looked like they might have some nice ambient pink-noise sounds -- rain, ocean and so forth.

Some of the samples were usable right away. But others are only available at 44.1k, and the Adafruit Wave Shield, the hardware I was targeting first, will only play WAV audio at 16k. So they needed to be converted. A simple shell loop did that:

for fil in *.wav ; do
  avconv -i $fil -ar 16000 ../samples16/$fil
  echo $fil
done

Arduino hardware

There are several Arduino shields for playing sound files. The simplest (and probably cheapest) is the Adafruit Wave Shield, and that's what I started with. It comes as a kit that you solder together (an easy soldering project) and it has its own volume control and SD card reader. On the down side, it can only play .WAV files, not other formats like .MP3 or .OGG. But for my sleep soother project that was okay.

Getting basic sounds playing was easy, following Adafruit's tutorial and sample code. But for my project, I also needed some external buttons, to allow for jumping from one track to the next. I was a little confused about which pins are used by the shield, and I ended up wiring my button to one of the pins that the shield uses for talking to the SD card reader. Things didn't work at all. And then while I was fumbling with plugging/unplugging things, at some point I installed the shield onto the Arduino wrong, with the pins off by one. I'm not sure whether it was the miswired button or the off-by-one shield, but something got fried in the wave shield and it was never able to read an SD card again after that (yes, even after plugging it in properly).

I thought about ordering another Wave Shield. But I was leery -- if it's so delicate that a stray 5v signal in the wrong place can fry it permanently, how long did I expect a second one to last? Besides, I was tired of soldering things, and I happened to be putting in an Amazon order for some other things. So I ran a search and found that there was an MP3 player shield available through them, made by Seeed Studio. It even had buttons built in, so I wouldn't need any extra hardware. It was a little more expensive than the Wave shield, but it claimed to play MP3 and OGG as well as WAV, and it comes pre-assembled, no soldering needed.

The hardware arrived and looked nice. Two simple buttons plus a "multifunction" button you can press or rock left or right. I grabbed a micro SD card, put some MP3s on it, and went to Seeed's page on the Music Shield.

Hacking the Seeed library

I was a little worried when I discovered that they have three different demos there -- each of which comes with a different library, and you have to remove one set of libraries before you can try a different demo. Not a good sign.

And indeed, it wasn't. None of the demos worked at all. When I added some debug Serial.printlns, I found that it wasn't opening the SD card.

Much web searching found a couple of people saying they'd discovered that the Seeed shield only works with 2G or smaller microSD cards. Good luck finding one of those! The next day, I drove all over town looking for one, without success, and was on the verge of giving up when Dave remembered a little cheapie camera he'd bought a few years ago for taking airplane movies. It came with a microSD card. Success! It was a 2G card.

Back to trying the various demos and their incompatible libraries again. And this time, one of the demos, the first one (the one that comes with the Music v1 14.zip library), worked. I could play tracks, sequentially as they were loaded on the SD card.

Unfortunately, that wasn't what I wanted to do -- I wanted to play the same track over and over, jumping to the next track when the user presses a button. I tried the other demos. None of them worked at all.

Long story short, after struggling for the better part of a week and reverse-engineering a fair amount of the Music v1 14 library, I finally got my sketch working.

Sharing the changes

I come from the open-source world. I keep my Arduino sketches on GitHub (at least once they work well enough to be useful to anybody). So of course I wanted to share the work I'd put into fixing this library.

I had it all laid out and ready to commit, and was working on some documentation on how to use it, when I noticed the readme.txt in the library directory. It begins:

Copyright (c) 2010 Seedstudio.  All right reserved.

Pffft! So after finally getting things working, I can't share my working version of the library! What are they thinking? What on earth is the point of distributing a library for your hardware, one that you know doesn't work very well (or you wouldn't be distributing four different incompatible versions of it), and then not letting anyone fix it for you?

I posted a query in one of the many threads discussing problems with the Music Shield, asking if Seeed would consider releasing the library under a license that allowed redistribution. It's been a few weeks now, and no answer yet.

Incidentally, even posting the query wasn't easy. Seeed doesn't let you post in their forums unless you register -- and the registration process requires full name, address, and phone number! Fortunately, they have no way of knowing whether the info you give them is fake, so that's what I did.

Since I don't have permission to share the code directly, I've checked in a patch that updates their library so it can play arbitrary tracks, not just sequential ones, and can re-play the same track. It's here: Music Shield library on GitHub, along with my sample app, called play-repeat.

Conclusions

So my app is working now. Well, mostly; sometimes the volume randomly jumps in the middle of the night, which I think is a hardware glitch, but since it only happens after several hours of play, it's hard to debug.

But if you're looking for an Arduino sound project, I can't recommend either the Wave Shield or the Seeed Music Shield. The Wave Shield seems too fragile and its formats are limited, though the tutorials and support are great. And I'll certainly never buy anything from Seeed again.

If I had it to do over again, I'd spend the big bucks and buy the Sparkfun MP3 Player Shield. It's more expensive ($40) and doesn't have nice buttons like the Seeed shield, but it plays all the formats the Seeed shield does, and they offer tons of documentation and examples, including an open-source library and code contributed by users.

Tags: , ,
[ 11:37 Feb 17, 2013    More hardware | permalink to this entry | comments ]

Fri, 02 Mar 2012

Music with an Arduino

Working on projects that might be fun for a proposed Arduino high school workshop, I realized I hadn't done much with Arduinos and sound. I'd made clicking noise for my sonar echolocation device, but nothing more than that.

But the Arduino library has a nice function to control a speaker: tone(int pin, int frequency, int length).

tone() works much better than trying to make your own square wave, because it uses interrupts and doesn't glitch when the processor gets busy doing other things. You can leave off the length parameter and the tone will continue until you tell it to stop or change frequency.

Random tones

So you can produce random tones like this (SPEAKER is the pin the speaker is plugged into):

uint8_t SPEAKER = 8;

void setup()
{
    pinMode(SPEAKER, OUTPUT);
    // Seed the random number generator from floating analog pin 0:
    randomSeed(analogRead(0));
}

void loop()
{
    // Random frequency between 20 and 1400 (Hz).
    unsigned long freq = random(20, 1400);
    long duration = random(5, 50);

    tone(SPEAKER, freq, duration);
    delay(random(100, 300));
}

Light theremin

Purely random tones aren't very interesting to listen to, though, as it turns out.

How about taking input from a photo-resistor, to make a light theremin that wails as I move my hand up and down above the sensor? The photoresistor I was using typically reads, on the Arduino, between 110 (with my hand over the sensor) and 800. So I wanted to map that range to audible frequencies the speaker could handle, between about 20 Hz and 5000.

uint8_t LIGHTSENSOR = 0;
void loop()
{
    // Set the frequency according to the light value read off analog pin 0.
#define MAX_SIGNAL 800
#define MAX_FREQ  5000
#define MIN_SIGNAL 380
#define MIN_FREQ    20
    int lightsensor = analogRead(LIGHTSENSOR);
    int freq = (lightsensor - MIN_SIGNAL) 
                * (float)(MAX_FREQ - MIN_FREQ) 
                / (MAX_SIGNAL - MIN_SIGNAL)
               + MIN_FREQ;
    tone(SPEAKER, freq);
}

Random music (chiptunes)

That was fun, but I still wanted to try some random music that actually sounded ... musical. So how about programming the standard scale, and choosing frequencies from that list?

I looked up the frequency for Middle C, then used fractions to calculate the rest of the "just" diatonic scale for C major:

float middle_c = 262.626;
float just[] = { 1., 9./8, 5./4, 4./3, 3./2, 5./3, 15./8 };
#define NUMNOTES (sizeof(just)/sizeof(*just))
float cur_octave = 1.;

Multiplying the frequency by 2 transposes a note up one octave; dividing by two, down one octave. cur_octave will keep track of that.

Now if whichnote is a number from 0 to 7, cur_octave * just[whichnote] * middle_c will give the next frequency to play.

Just choosing notes from this list wasn't all that interesting either. So I adjusted the code to make it more likely to choose a note just one step up or down from the current note, so you'd get more runs.

    rand = random(0, 6);
    if (rand == 0)
        whichnote = (whichnote + 1) % NUMNOTES;
    else if (rand == 1)
        whichnote = (whichnote + 1) % NUMNOTES;
    else
        whichnote = random(0, NUMNOTES);

    float freq = middle_c * just[whichnote];

    // Change octave?
    rand = random(0, 10);
    if (rand == 1 && cur_octave <= 3) {
        cur_octave *= 2.;
    } else if (rand == 2 && cur_octave >= 1) {
        cur_octave /= 2.;
    }
    freq *= cur_octave;

It's still not great music, but it's a fun experiment and I'm looking forward to adding more rules and seeing how the music improves.

Bach

But this left me hungry for real music. What if I wanted to play a real piece of music? Certainly I wouldn't want to type in an array of frequency numbers, or even fractions. I'd like to be able to say A, Ab (for A-flat), Cs (for C-sharp), etc.

So I defined the frequency for each of the notes in the scale:

#define NOTE_Ab 207.652
#define NOTE_A  220.000
#define NOTE_As 233.082
#define NOTE_Bb NOTE_As
#define NOTE_B  246.942
#define NOTE_C  261.626
#define NOTE_Cs 277.183
#define NOTE_Db NOTE_Cs
#define NOTE_D  293.665
#define NOTE_Ds 311.127
#define NOTE_Eb NOTE_Ds
#define NOTE_E  329.628
#define NOTE_F  349.228
#define NOTE_Fs 369.994
#define NOTE_Gb NOTE_Fs
#define NOTE_G  391.995
#define NOTE_Gs 415.305

#define NOTE_REST     0.0
#define NOTE_SUSTAIN -1.0

Then the first part of Bach's 2-part invention #4 in D minor looks like this:

float composition[] = {
    NOTE_D, NOTE_E, NOTE_F, NOTE_G, NOTE_A*2, NOTE_As*2,
    NOTE_Db, NOTE_As*2, NOTE_A*2, NOTE_G, NOTE_F, NOTE_E,
    NOTE_F, NOTE_REST, NOTE_A*2, NOTE_REST, NOTE_D*2, NOTE_REST,
    NOTE_G, NOTE_REST, NOTE_Cs*2, NOTE_REST, NOTE_E*2, NOTE_REST,

    NOTE_D*2, NOTE_E*2, NOTE_F*2, NOTE_G*2, NOTE_A*4, NOTE_As*4,
    NOTE_Db*2, NOTE_As*4, NOTE_A*4, NOTE_G*2, NOTE_F*2, NOTE_E*2,
};

And the code to play it looks like:

    unsigned long note = composition[i++];
    if (note == NOTE_REST)
        noTone(SPEAKER);
    else if (note == NOTE_SUSTAIN)
        ;      // Don't do anything, just let the current tone continue
    else
        tone(SPEAKER, note);

It's a bit tedious to type in the notes one by one like that, which is why I stopped when I did. And as far as I know, the Arduino can only emit one tone at once -- to play the real 2-part invention, you either need a second Arduino, or extra hardware like a wave shield.

Anyway, it was a fun series of experiments, even if none of it produces great music. You can see the source at github: akkana/arduino/music.

Tags: , ,
[ 18:54 Mar 02, 2012    More hardware | permalink to this entry | comments ]

Syndicated on:
LinuxChix Live
Ubuntu Women
Women in Free Software
Graphics Planet
DevChix
Ubuntu California
Planet Openbox
Devchix
Planet LCA2009

Friends' Blogs:
Morris "Mojo" Jones
Jane Houston Jones
Dan Heller
Long Live the Village Green
Ups & Downs
DailyBBG

Other Blogs of Interest:
DevChix
Scott Adams
Dave Barry
BoingBoing

Powered by PyBlosxom.