So this week I’ve been giving a more final pass of over the nuts bolts of a few puzzles. What this does is give us a more solid framework for musical structures that interact with the puzzles themselves (I’m being nebulous intentionally, this is super cool, promise)
The big change has been coming back to the bass puzzles; they’ve been riding on very early implementations of some of our tech, and needed some love to get them to parity with the rest of the world. Good news, they’re bassy!
Today I’m tidying up the studio – finalizing layout and features. In the studio we have some simple controls for global effects and parameters for players to fiddle with, but may provide more advanced parameters for those wanting to mess around with reverb, delay and vinyl noise (crackles) further.
The game is designed to permit a certain level of flexibility in how the player explores the world, the puzzles and how they are solved. I was testing a build today and discovered a remarkably backwards way to solve a puzzle (which will have to be addressed slightly) but was surprised and pleased by its’ musicality when approached in reverse.
I love my job
So, I’m polishing and elaborating some of the sound systems in the world – and that starts with a good plan. Quynh suggested I map out an approximation our current voice allocation (synth voices) and then elaborate with the other sound systems (implemented, in need of love, missing etc). Sometimes a holistic view of things can be very informative.
For instance, the bass area of the game (above) is the oldest, and was built using highly-iterated upon sound tech. Not only were we still developing the tools, but our ability to use them effectively. As such, there are a few too many sound shadows in this area – and while contrast is valuable, it’s a little sparse right now.
It was a valuable exercise to quickly mock-up, and will be really helpful in informing the finalization of some aspects of the wacky world we’re building. Oh, and here is the majority of the game world:
This week I’m working on the end game a bit. It’s a complicated puzzle, less from the player’s perspective, but more in terms of what’s going on. Communicating the various stages of interaction effectively is proving challenging, but I think it will be a rewarding apparatus for players to work with. Here are some not-screenshots, more WIP screen-photos while I was working out some of the hierarchies, objectives, and spatial issues (don’t worry, these aren’t spoilery, just cool looking)
We’ve got great news! We’re thrilled to announce that FRACT OSC is now being backed by Indie Fund. Indie Fund was created in 2010 by a group of successful indie game developers and provides financial support to other indies with a goal to help developers get and stay independent. They’ve successfully funded games including Monaco, Antichamber, QUBE, and Dear Esther. With the end in sight, the support from Indie Fund will help us in these final stages of development so that we can wrap up FRACT OSC and get it into your hands in 2013.
A huge thanks to Indie Fund!
Last week I discussed how we can use remote messages to receive messages sent from code, and have them delivered to the right parts of our patch. But there’s a problem: we don’t just want to have one instance of our synth patch, we want to have multiple voices playing alongside each other. If we just make multiple instances, they’ll end up all taking remote messages with the same name, and we’ll be left with no way to differentiate between them. This is what that looks like:
(yeah, in this case the sound isn’t actually going anywhere, but bear with me)
To solve this, we’re going to give each instance of our synth a name. The convention I use is that every patch in FRACT OSC that corresponds to a unique emitter takes a special first argument, which it will use as its name. Inside the patch, we then prefix each message with
$1-, which splices the patch’s first argument into the beginning of the message’s name, like so:
This way there’s no ambiguity; when we send the message, we prefix the message name with the name of the object we want to send the message to, and only that object will receive it.
At this point I should mention a special patch argument which Pure Data creates automatically,
$0. For any abstraction (i.e. a patch saved in its own file),
$0 is a unique name Pure Data generates for that instance of the patch. In fact,
$0 is conventionally used to prefix internal patch messages similarly to our use of
$1. Why don’t we use
The main reason is that we have no good way of predicting what value
$0 will have external to the patch. Within the patch, you can send a message into a
[send $0-message-name] object and then just receive it at a
[receive $0-message-name] and know that they will automatically match up, but when we create a new patch there isn’t an easy way to tell what
$0 is. Another reason is that by choosing our own object name we can use something that’s human-readable, or that corresponds to something in the game engine. For example, you could decide to name the patches after their voice IDs. This way if you get errors telling you that Pure Data couldn’t find the receiver for a message, you can tell just by the name which object it was supposed to go to, and often which object in your engine the message originated from.
Another advantage is that you can further give
$1 as arguments to sub-patches that add their own functionality. For example, in FRACT OSC most patches take the same types of messages for managing their position in the world, for panning purposes. The panning functionality is common and implemented in a shared sub-patch. Using this scheme means I can have the panning sub-patch accept the messages itself, rather than doing something messy like having the outer patch receive the messages and pass them inwards.
$0 is still useful for internal messages, though. In my own patches, I typically use a
$1- prefix for public messages received from other patches and from the game, and
$0- for private ones that a patch sends to itself.
Also check out: part1, part2 part3, and part4
We’re upgrading FRACT OSC to Unity 4, and in general it’s going smoothly. There have been a few objects in the game that have gone a bit wonky though (my fault) due to the way they had to re-import. Here are a few of them:
Continuing along with our audio tech series – last week I talked about wrapping Pure Data, and this week I’ll take a look at exactly what a message is, so that I can move on to how I went about dispatching messages from/to the right Unity scripts and Pure Data sub-patches.
When we want to tell a patch in Pure Data to do something, we need to send it a message. Whenever FRACT needs to tell Pure Data to change a note, modulate a synth, move an audio source in 3D space, play a sample, or do pretty much anything else, it’s done by sending a collection of messages. Pure Data veterans might find this post a little basic, but it’s important to understand this stuff before what comes after. :)
When you’re editing a Pure Data patch, the simplest kind of message is sent by a message box connected directly to an object:
Here we have a cosine wave oscillator which starts at a frequency of 440hz. When we click on the message, the oscillator will switch immediately an octave down to 220hz.
In Pure Data, each message begins with a selector (which must be a symbol, usually a single word or dash-delimited-words), and then continues with zero or more entries (each of which is either a symbol or a number). The selector tells the receiving object what sort of thing to do, and the content gives more details. In object-oriented-programming terms, the selector is the method name, and the entries after it are the arguments. In the above example, the selector is “float” and it’s followed by an argument of 220. The osc~ object implements a method for “float” which sets its oscillation frequency.
Why is the method called “float,” rather than something more intuitive like “set-frequency”? “float” is actually one of a few special selectors, which signifies that we’re simply sending a single number to an object. In fact, there’s a shorthand for sending this kind of message, we can simply write:
While it looks like we’re just sending a message containing 220, when it sees a message box starting with a number Pure Data implicitly inserts the selector “float,” making the full message [float 220(. While you can mostly get by in Pure Data without knowing this detail, it comes up in corner cases (i.e. differentiating between [float 1( and [list 1(, which is a list containing one float) and is very important to be aware of if you’re sending messages from code. So remember, a message always has a selector, even if you can’t necessarily see it.
If you’re curious, there are a few other important selectors: “symbol,” which is usually used to send a single piece of text, and “list,” which is used in a lot of built-in objects for manipulating lists of things.
From code we actually need to do something a bit more complicated, though. Manually connecting objects is fine when authoring patches in the Pure Data editor, but we can’t easily do that from Unity. Instead we’re going to use a special object called “receive” to receive the message. We give it a name, then use the “send” object to send the message.
We can also include the destination in the message itself, prefixing a semicolon to tell Pure Data we’re sending an indirect message:
So in all, a message in Pure Data consists of a symbol identifying the receiver, a symbol identifying the selector, and then any number of symbols or numbers giving the arguments.
There’s a problem, though, in that all the names of our receivers are hard-coded. The examples given are very simple, but FRACT’s subtractive synth takes dozens of different messages to configure different elements. On top of that, if we have two copies of the same patch loaded, how do we send the message to one without sending it to the other? We need some convention for easily assigning different names to different patches and the messages they receive, which is what I’ll dig into next week!
Also check out: part1, part2, and part3