gSkinner - Home

Playing Records (Vinyl) With ActionScript

Posted on November 9, 2009 by Grant Skinner

Rather than just blog an experiment, and leave it at that, I thought I’d blog the story and thought behind the experiment. Hopefully it’s interesting to someone. :)

The Idea

Friday morning I woke up with the random idea to try to simulate playing records in Flash. Don’t ask me where it came from, I just remember waking up and saying to my wife “I wonder if I could make MP3s sound like records with ActionScript?”. She smiled and nodded and said it sounded like a lovely idea (she’s used to humoring random thoughts first thing in the morning). If I were to take a guess, I’d guess the idea grew from a seed planted a month or so ago when my wife and I were discussing the idea of getting a new record player. Not sure why it took a month to turn into an idea, but apparently I think slowly.

I headed to the office and started thinking through the code. Beyond a cursory glance, I’ve never really played with any of the new sound APIs, so I managed to justify this experiment to my team as R&D for future projects.

Getting Started

I started by glancing through the API, and checking out a simple tutorial by Lee Brimelow on working with extractSound and the sampleData event. Then I switched over to designing a 2.5D vector record. I often start explorations this way – learn the core concepts I’ll need, then switch to design for a while. I’m not really a designer, but I think it helps turn on my creative facilities, and gives my subconscious a chance to fit the pieces together while I play with design.

Design

For anyone interested in the design side, here are the more interesting bits: the grooves are dynamically drawn circles, offset from the center randomly by a tiny amount so that you can see them spinning; the highlights are just two layers of vector wedges with blur applied to them, they are counter rotated as the record spins; the whole record is slightly rotated on the Y axis and the highlights are slightly offset to make it wobble a little bit when it spins. Nothing too exciting, but it was kind of fun getting it to look right.

Playback

Once I had a decent looking record, my next step was getting basic playback working (again, no sound API experience). I wanted to use FileReference, so that users could play back their own music from their harddrive. Unfortunately, there is no Sound.loadBytes() method (you can vote on this feature here), which makes it difficult to get a sound from the ByteArray data that FileReference returns. Fortunately, Chris at FlexibleFactory wrote a handy class that extracts the MP3 data, wraps it in a SWF, reads it into a Loader, and then pulls it back out as a Sound object.

Once I had the Sound object, it was easy to use extractSound and the sampleData event to get simple playback working (see Lee’s tutorial for help on this).

Scratching and Seeking

Next, I wanted to tie the on screen record to the music playback. I wanted the record to spin when the music was playing, and I wanted you to be able to spin the record to change the music’s playback speed. To make it more complicated, I wanted it to be as physically realistic as possible.

I quickly realized that to do this, I would have to make the record’s rotation subservient to the position of the playback. This is to prevent problems if my sampling events get out of synch with the rotation (you’ll notice even the tiniest audio glitch, but not slight variations in the rotation speed). As my sampling position changes, I update the rotation of the record by using the formula: position/44100/(60/rpm)*360, where 44100 is the sampling rate, 60 is the number of seconds in a minute, rpm is the revolutions per minute (33.3 for an LP), and 360 is the number of degrees in a full rotation. And yes, that formula can be optimized.

When you click and drag the record, it isn’t rotated directly. Instead I calculate a new sound position based on the rotation change implied by the mouse x/y, then update the rotation based on that position.

To generate the sound when dragging the record, I extract the samples between the last position and current position from the source music, then use simple interpolation to generate enough sample data to fill my standard sample size. If you rotate it backwards, it reverses the sampling direction to play backwards.

I’m going to try enhancing the interpolation algorithm in the future. I’m actually planning to try a method I used for my old pattern recognition system, which should hopefully increase the fidelity a bit.

Effects

I also wanted to introduce the hissing, pops, and skipping of a real record player.

Hissing was easy. I just add a percentage of random noise to the sample. I determine this percentage using a sine wave based on the current rotation of the record. This way the hissing fades in and out in conjunction with the records wobble, which is inline with how I remember records sounding. (mental note, I probably should have gone back and listened / looked at a physical record at some point during this experiment)

Skipping started easily. Using a derivative of the formula above, it was pretty simple to adjust the position by exactly one revolution of the record, and repeat that a random number of times at the same position. The hard bit was that I wanted it to pop a bit when it skipped, as opposed to just cleanly rewinding. I got this working by simply writing a block of “1″‘s at the point that it skips. I’m sure there’s a smarter way to do it, but I haven’t had a chance to find one yet.

To get popping working, I just applied what I had learned from skipping. I add a random offset to a randomly length block of samples. This results in quiet pops and louder ones.

Volume Monitor

I quickly added a retro style volume monitor behind the record. It just uses the drawing API to draw out the bars based on the output SoundChannel’s leftPeak and rightPeak values. No need to touch computeSpectrum for something this simple.

This was the last thing I did before heading home for the day, but hey, I had a whole weekend ahead of me.

ID3 Data

I didn’t have a lot of time to play on the weekend, but I did really want to get ID3 support in. Unfortunately, the Sound object that is generated from the FileReference data is stripped of ID3 tags, so I had to find another option.

After a bit of hunting, I found the Metaphile library which can read ID3 data from an MP3 in a ByteArray. It’s not well documented, and it has some minor dependencies on the Flex framework, but it was pretty easy to figure it out and get it working without Flex. This let me display the song title, artist, and album. More excitingly, I could pull out allbum art (usually), and display it on the record.

I also did a bit of clean up on the UI, and tweaked some of the effects a bit.

Here’s the current result. Fittingly, I think it sounds best with older tracks (the Beatles and Louis Armstrong sound pretty good). The effects get drowned out by louder tracks (this is true on real record players, too). Turn up your volume to hear the hissing and pops. If it skips, you can either wait for it to continue, or advance the record manually to stop the skipping.

Unfortunately, the ID3 library occasionally generates errors, and I haven’t got around to suppressing them yet. If an MP3 won’t play, try reloading and trying a different one.

I still plan on improving the interpolation, finessing the effects, and making the scratching sound more realistic (I think I need to introduce some random sawtooth wave forms or something). I’d also love to build a multi-touch version with two turntables and a cross fader. For now, I’m not going to release the source – I’m still playing with it and it’s a horrible, stinky mess. I might release it in the future. I thought I should blog it now though, in case it falls off my radar.

Follow @gskinner on Twitter for more news and views on interactive media.
26 Comments

The result is amazing, excellent work Grant!!

Posted by: pixel4 on Nov 9, 2009 12:48pm URL: http://pixel4.biz

Ahhh man I've been waiting for you to say something about this... It keeps getting better and better each time I refresh the URL.

+1 for source ;)

I have a few good ideas for an app that i'd like to use somethin like this in - I'll have to read this over and over and check the resources you've posted.

Thanks!

Posted by: KillerSpaz on Nov 9, 2009 12:48pm URL: http://killerspaz.com

Gotta say, reading the album art out of the ID3 tag was an excellent touch.

Alice in Chains works well too. :)

Posted by: Michael Hoskins on Nov 9, 2009 1:29pm URL: http://www.pixelbath.com/

Awesome work as always Grant. I do need to go back and clean up the Metaphile stuff one of these days, but probably won't until I need it in a real project. :) Feel free to send me any issues that are getting in your way though.

Posted by: Ben Stucki on Nov 9, 2009 1:33pm URL: http://blog.benstucki.net

Awesome. Love it.

A tonearm would be a nice addition.

Posted by: Phillip Kerman on Nov 9, 2009 1:51pm URL: http://www.phillipkerman.com/blog

awesome! I created a similar effect with a scrub bar = ] I also couldn't make the scratches sound truly realistic, and playing in reverse with sample data isn't clean, but it's awesome enough! I like what you did with the ID3 image.

Posted by: leef on Nov 9, 2009 2:10pm

Works really well. One thing that I always enjoy with record players is the sound of quickly spinning the record forward (while it's already playing) and then hearing the ease of the music slowly going back to the proper play speed.

Could be cool to integrate some gTween into the playback ;)

Posted by: Dustin Senos on Nov 9, 2009 2:29pm URL: http://dustinsenos.com

Would be nice to see the needle

Posted by: guest on Nov 9, 2009 3:53pm

amazing work man - some type of physics/easing/throwing type behaviour for the platter itself would be cool, so I could dub-styles it up and rewind out of a track :)

Posted by: stiggofthedump on Nov 9, 2009 5:15pm URL: http://endemikmusic.com

Grant, I'm not trying to put a "spin" on your post, but I was wondering if it was possible to "scratch" sound with ActionScript also this week too. The link you provide from the theflashblog proves it and your inspiring 3D turn table is very motivating.

I have only played with the physics, had no idea how to do the sound until your post...

http://keith-hair.net/blog/examples/turntables

Posted by: Keith H on Nov 9, 2009 9:49pm URL: http://keith-hair.net/blog

Hi. It's very interesting.

Did you try to record sound in flash with new sound api?

Suppose we have 2 mp3 files that playing simultaneously in flash player, and we want to record one mp3 that is mixing that 2 mp3s, how can we do that ?

Posted by: hovox on Nov 10, 2009 1:31am

For scratching you need to implement a decimation filter. The coefficients of the filter depend on the speed of your "scratch" so you can build the filter in memory and use a lookup table...

Posted by: Glen on Nov 10, 2009 2:29am

that's just super!! awaiting for the source... :)

Posted by: Rahmat Hidayat on Nov 10, 2009 3:01am URL: http://blog.bebensiganteng.com

Great write-up :) As an avid vinyl collector myself I do miss the feeling of a real turntable. I think it's due to the way the sound stops abruptly. If you're near a 1200/1210 turntable you will immediately hear the way a record sounds like when you put your hand on the platter...or when you hit start/stop. I think implementing this will immediately make it feel more realistic.

Posted by: Owen van Dijk on Nov 10, 2009 3:54am

Sorry, I meant to post a useful URL for decimation or "multirate resampling"...

http://www.dspguru.com/info/faqs/multrate/decim.htm

http://www.dspguru.com/sw/opendsp/alglib2.htm

Posted by: Glen on Nov 10, 2009 5:04am

Sorry, I meant to post a URL, but your spam filter sucked it up...

If you google "decimation filter" and read the "Multirate FAQ" about decimation, you can find some useful links to info and code.

You are looking for FIR decimation filters, but after seeing Andre's talk at FOTB, there is probably a shortcut to this as AS3 might not be upto the job, unless you can write a PB kernel to do it...

Posted by: Glen on Nov 10, 2009 5:08am

Really cool... You should add a pickup that you can move for fast seeking, two turntables and a cross fade between so it becomes a retro DJ set... Then the ability to load a whole playlist as a LP and a box where you can flip through the LP:s to pick the ones you want to load up... And then... Well ok I'll stop... :)

Posted by: mikael on Nov 10, 2009 5:18am

oops sorry you had already thought of that.. I should have read before posting..

Posted by: mikael on Nov 10, 2009 5:22am

Great job ! very nice design to !

I also played with this kind of stuff a while ago to build a scratch tool.

http://demo.actiplay.com/scratch/

you can scratch the vinyls, play with the crossfader, the pitch and the volumes

Posted by: babeuf on Nov 10, 2009 6:17am URL: http://www.babeuf.net

Love it! Way better than I imagined! As already mentioned by Owen: A slow down when you click and then a speed up again when you let go the record, that would feel incredible.

Posted by: simurai on Nov 10, 2009 6:26am URL: http://simurai.com

Nice work Grant. Thx for the mention!

Posted by: chris on Nov 10, 2009 7:17pm URL: http://flexiblefactory.co.uk

Hello

I like your brilliant idea about to simulate playing records in Flash.You have done a good job.Now I am also thinking about to try this idea.

Posted by: the a la menthe  on Nov 11, 2009 2:19am URL: http://www.vitabits.fr/the

cool idea Grant, is there too much skipping going on, or is that a bug?

Posted by: randygland on Nov 11, 2009 3:31am URL: http://www.andy-hayes.com

been there, done that ;) in a not so dynamic way: http://krisrok.de/blok/?p=47

you're lacking performance though. the sound isn't running smoothly at all on my netbook.

but the mp3 upload is great of course, show us :D

cheers

Posted by: kris on Nov 13, 2009 6:33am URL: http://krisrok.de

Wow, amazing posts as usual. I see a huge potential for these ideas! as a musician / programmer I can see amazing uses for an app like this..

If you get a chance check out DBlueGlitch, its a virtual fx plugin for modern music sequencers:

http://illformed.org/plugins/glitch/

Posted by: Nick on Nov 14, 2009 2:21am URL: http://www.myspace.com/fractured

very cool grant!

Posted by: jared on Dec 27, 2009 7:32pm URL: http://jaredfromtheblock.com

Leave a Reply

Your email is never published nor shared.




You may use these HTML tags and attributes:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="" highlight="">