Project:
3D Printed Music Box Records 2nd
April 2012
Some time ago we bought a Fisher-Price music box
record player for
the kids and I wondered if it would be possible to make new
records for
it.
3D printing offered a way but I needed to
put in quite some
work and develop quite a few bits of code to get the model.
This post
will cover how I did it.
First: a disclaimer...
Most
of the code that I wrote in this project is really, really bad.
It was designed to work once and, in some cases, didn't even
really manage that. If you try to run this code and it
doesn't work or does work but deletes something important I won't be
surprised at all. Emailing me will mean I can sympathise with
you, I probably won't be able to help. If you want proof you
should see my generally confused and very possibly confusing comments
in the code below.
The Fisher-Price record player that we've got is
not a real record player (although they did make one), it's a music box
and the "records" are patterns that control the sounding of the notes
on a music box comb.
Before I could make any records I needed to work
out what the notes were. I spent some time with a tone
generator (written in Processing) trying to work out the frequencies of
each note in the comb. Once I had this I would be able to
check these notes by playing back the notes from an existing record.
The frequency finder (named "freq_finder2") is a
(slightly) modified
piece of code from the Beads
library examples:
ac = new AudioContext(); /* * This is an Envelope. It can be used to modify * the behaviour of other UGen object. We need to * do this to get precise control of certain parameters * at an audio rate. */ freqEnv = new Envelope(ac, 500); /* * This is a WavePlayer. Here we've set it up using * the above Envelope, and a SineBuffer. We'll use * the Envelope to modify the freqency below. */ WavePlayer wp = new WavePlayer(ac, freqEnv, Buffer.SINE); /* * So now that the WavePlayer is set up with the * frequency Envelope, do stuff with the frequency * envelope. This command tells the Envelope to change * to 1000 in 1 second. Note that when we made the Envelope * it was set to 500, so the transition goes from 500 to * 1000. These control the frequency of the WavePlayer * in Hz. */ //freqEnv.addSegment(1000, 1000); /* * Connect it all together as before. */ Gain g = new Gain(ac, 1, 0.1); g.addInput(wp); ac.out.addInput(g); ac.start(); } /* * Here's the code to draw a scatterplot waveform. * The code draws the current buffer of audio across the * width of the window. To find out what a buffer of audio * is, read on. * * Start with some spunky colors. */ color fore = color(255, 102, 204); color back = color(0,0,0); /* * Just do the work straight into Processing's draw() method. */ voiddraw() { loadPixels(); //set the background Arrays.fill(pixels, back); //scan across the pixels for(int i = 0; i < width; i++) { //for each pixel work out where in the current audio buffer we are int buffIndex = i * ac.getBufferSize() / width; //then work out the pixel height of the audio data at that point int vOffset = (int)((1 + ac.out.getValue(0, buffIndex)) * height / 2); //draw into Processing's convenient 1-D array of pixels pixels[vOffset * height + i] = fore; } updatePixels();
The thing to see here is that some of the notes
(in red) are repeated. This was a surprise initially but when
I was making the model (later on) I think I worked out why.
Once I had the notes I could work out a tune.
I don't have a keyboard or other instrument so I used another
Processing sketch (with the name "player") and the keys on the PC:
import beads.*; Gain g;
AudioContext ac; WavePlayer[] wp; //should this be an array, added to the ac and then controlled individually? //Envelope env; float[] freqs = newfloat[22]; voidsetup() { size(200,200); frameRate(200);
void noteOn(char pressed) { // Receive a noteOn from your midi device int index = findKey(pressed); println(index); Envelope env = new Envelope(ac, freqs[index]); wp[index].setFrequencyEnvelope(env); } void noteOff(char pressed) { // Receive a noteOff - or releasing the note from your midi device int index = findKey(pressed); Envelope env = new Envelope(ac, 0); wp[index].setFrequencyEnvelope(env); } int findKey(char pressed) { switch(pressed) { case'q': return 0; case'a': return 1; case'w': return 2; case's': return 3; case'e': return 4; case'd': return 5; case'r': return 6; case'f': return 7; case't': return 9; case'g': return 11; case'y': return 13; case'h': return 15; case'u': return 17; case'j': return 19; case'i': return 20; case'k': return 21; } return 0; } voidkeyPressed() { noteOn(key); } voidkeyReleased() { noteOff(key); }
I tried a few tunes, including "Cavatina"
and "MyLovelyHorse"
(both versions) before I settled on "Still Alive" by
Jonathan
Coulton from the game Portal. This was partly
because I thought it might be fun and partly because, as I discovered,
it's really
hard to get tunes that fit in this restricted range of notes. Someone
with more musical training than I might be able to work out why...
even so I couldn't get all of the tune to work so I settled
for a repeated section that could play continuously around the disc.
Once I'd worked out what tune was possible I
needed to arrange it. I spent a bit more time writing a
bigger sketch that would allow me to set, move and erase notes on a
'stave' formed by all of possible notes, including the repeats.
This didn't work that well (the sound tends to come and go
for no reason I could work out) but worked well enough to give me an
initial tune. If you want to have a look at it you can go to
the sketch "fisherPrice_linearTunes". This sketch gives me a
text file with the series of notes that I've set up.
Once this is ready I wrote another sketch to
transform the notes from linear to polar coordinates; I could have done
this in one go but didn't.
I was now faced with the problem of making a model
of the disc. This proved not to be easy.
I tried a few options:
Autodesk 123D: this was OK but I couldn't get
on with it, possibly due to conflicting reflexes from other CAD
systems. It also didn't export an accurate enough STL file
when I tried, this may be fixable but by this point I'd already decided
not to use it
Blender: as I soon discovered I really don't know
how to do precise shapes in Blender
CATIA: I was getting desperate at this point, I
came close to asking for help to set up the model in this industrial
strength CAD system at work over lunchtimes but in the end didn't even
start because I ended with;
Processing (you may be noticing a theme
emerging) with the unlekker
library for STL export
I ended up "lathing" the outline of the disc around the required axis
vertex-by-vertex based on measurements for each track or other feature
taken with vernier
calipers (no digital here, analog technology FTW).
The sketch called "sketch_Dec29a_loftCurve" gave me
a blank disc (STL file download from Shapeways here) that I could put notes on.
The unlekker library let me bring in the
blank disc and join it with the notes in the sketch
"sketch_Dec29b_modelCombine" before exporting back to STL, fixing a few normals in Blender and uploading at
Shapeways.
I finally was able to order the print after over a
year (on and off) of messing around with this project. It
pretty much worked out of the box (I added a few foam stickers to make
it level, you could avoid that by re-doing the model with smaller drive
blocks near the centre - and no, I'm not going to do that) and I was
able to record (badly) this
clip after using warm water to flatten the model a bit:
Which now has over 120,000 views (!). This was a surprise but
the interest after BoingBoing picked it up was quite amazing to see.
So, now you should have enough information to make your own discs (if you want to), let me know if you do and try not to get sued by the RIAA...
fastness
- Iain Banks Graphics
All of the content from my Iain M Banks website, now
shifted to be a section in this one
fastness
- Links & Resources:
Processing:
An open source programming tool aimed at artists,
engineers and designers. Simple, light and Java-based with a
wealth of libraries and a strong user community
Shapeways:
3D
printing for the masses - plastics and metal to your design or team up
with a desigenr to personalise a design with a 'co-creator'.
Visit my Shapeways
shop for some things I've designed.
Meshlab:
MeshLab is an open source, portable, and extensible
system for the processing and editing of unstructured 3D triangular
meshes
Blender:
Blender
is the free open source 3D content creation suite, available for all
major operating systems under the GNU General Public License
Gimp:
GIMP is the GNU Image Manipulation Program. It is a
freely distributed piece of software for such tasks as photo
retouching, image composition and image authoring. It works on many
operating systems, in many languages
Inkscape:
An Open Source vector graphics editor, with
capabilities similar to Illustrator, CorelDraw, or Xara X, using the
W3C standard Scalable Vector Graphics (SVG) file format
Ponoko:
Retail laser cutting outlet with centres in New
Zealand, USA, Germany, Italy and the UK (if not more by now)