Play ‘Round
aka the Mother Plucker
Eli Marschner / Michael Yu-Ta Lu
Introduction

Play music. Play ‘Round. Pluck.

Play ‘Round (aka the Mother Plucker) is a space for collaborative rhythmic exploration (we're pretty committed to being pretentious). Use it to draw some stuff, then watch your creation generate music. Share your art with others and interact with them to create something even stranger — and more beautiful — together.

Back to Top
Tutorial

“Basics”

After getting the code, you'll want to build it. Try this:
(um...works best on a Mac w/ coder stuff installed)

$ make

You'll want to run it. Try this:

$ ./playround localhost 20202

After starting, you'll see a canvas. You can draw stuff on it.

You'll want to start with a round pad. Click & drag on any blank part of the canvas. Pads are the stage on which magical things happen.

Now that you have a round pad try dragging around inside of it. You'll create one of two things: a string, or a track.

Strings make sound when plucked (duh). (By "plucked" here we really mean "moused over".) You'll get one when you draw a radial line. Long strings make low sounds, short strings make high sounds. You'll hear a string's pitch as you're drawing it. You can use your cursor to pluck strings whenever you want.

Tracks are directional paths that let you bend time to your will. They always go clockwise. Try drawing a track that goes through a string. Then, click on the beginning of the track (green dot). You'll see a plucker happily moving along the track. When the plucker hits the string, it does what you expect. Sweet!

Connect tracks by starting or ending your dragging on an existing track's end points. Pluckers jump between connected tracks. If tracks fork your pluckers will multiply (be careful!). Try creating a loop...

The last piece of the puzzle is connections between pads. Draw another pad, then draw a track on it. Then drag a track from an end point of one pad's track to an end point of another pad's track. You'll get a linear track, which pluckers will travel along just as happily as they do along the curved ones.

Deleting

Oh no, you've drawn something that's a terrible mistake! What to do?! Well, you can delete it. Just hover your mouse on the thing you want to delete (for pads, hover on the center dot) and hit the delete/back-space key. All gone!

Collaborate

Sharing is caring. We know you care, and we care too, so we want you to be able to share.

Let's talk networking; specifically, the peer-to-peer kind. With Play ‘Round no one's central. Everyone is both a client & a server. You connect to others, they tell you who else to connect to, and you tell whoever you know about whoever else you think they should connect to. It's all very democratic (and sort of magical).

Consider the command from before:

$ ./playround localhost 20202

With this you're actually saying which peer you want to connect to first — the "bootstrap peer" ("localhost" above) — and also the port you want to listen to ("20202" above). The generic form is:

$ ./playround <bootstrap-host:port> <listen-port>

It means you will join <bootstrap-host:port>'s network, and you are listening to the port <listen-port>. (By the way, these are UDP ports, not TCP.) If someone's listening at <bootstrap-host:port> they'll tell you about any other peers they know about, and you'll be connected to them, too.

Now what? Well, you're synchronized with all your new-found friends. You see what they draw, and they see what you draw. Everyone also sees everyone else's mouse positions (pink circles — dots when the mouse button's held down).

Express Yourself

Annotate pads by hovering over their centers and typing a message. If you move the mouse anywhere else then anything you type will appear as a message next to your cursor.

Yes, everyone else in your network sees these messages. Use them to identify yourself, make demands, claim dominion over a pad, or simply chat.

Back to Top
Implementation
Nerd Alert...

Play ‘Round has three major components:

  • Audio
  • Graphics (GUI)
  • Networking

For API documentation, refer here.

Audio

For plucking we're using STK. Specifically, the string sound comes from the Stk::Plucked class, which uses the Karplus-Strong algorithm to generate sound. Nope, it's not anything fancy.

Double Buffering of Sound Source Buffer

With audio, graphics, and networking all going on at once, we've got a lot of threads to deal with, and have to be especially cautious about keeping that audio thread running at real-time speeds. The fact that we're reading data about the strings from an STL map in the audio thread makes this risky business. (Ok, ok, we could have gone with an intrinsically thread-safe data structure, but STL's just so so darn easy, and we're lazy...) We don't want another thread to change the map while the audio thread's reading it (race condition!), but we don't want to make the audio thread wait for any changes to finish, because that might take a long time (memory allocations, etc.).

So, we double-buffer the map. That is, we keep two copies of it, and at any given moment one copy is for reading by the audio thread, and the other is for writing by anyone else. When all writes are done we swap the read/write pointers, which is pretty much guaranteed to happen super-quick. We then copy the contents of the new read map into the old read map (now the write map), and go about business as usual. That copy might take a while (in CPU-relative terms), but it doesn't affect the audio thread, so that's fine. We only put a lock around the swap code to prevent swapping when the audio thread is reading the read-map.

Graphical User Interface

We made a bare-bones widget library, suitably custom-/bastard-ized for our specific needs. Everything's a Shape (what it looks like), and most things are a Widget (what it acts like). Widgets ("children") nest within other Widgets ("parents").

OpenGL FTW.

Network

We're using OSC (and therefore UDP) to talk over the network.

The devil's in the details, but the tutorial above does a pretty good job at explaining how the peer-to-peer stuff works, which is the interesting part. See the docs and/or code for everything else :)

Back to Top