A Native Client (NaCl) wrapper for ZenGarden. ZGNaCl == "Cynical"?
C++ Shell Objective-C
Switch branches/tags
Nothing to show
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.
ZenGarden @ 19d25ec
zgnacl chmod 644 COPYING.LESSER Aug 16, 2012


Cynical Overview

Cynical is a Native Client (NaCl) wrapper for the ZenGarden Pure Data (Pd) runtime. It allows Pd patches to be run in the Google Chrome webbrowser and exposes a simple JavaScript API for creating, querying, and modifying them in real time.

How to Get Started

The JavaScript API

There is currently a very primitive JavaScript API available. Please note the restrictions and limitations listed below.


A single graph can be easily loaded with new newGraph command. The netlist (as written in a .pd file) is provided as is, and will be parsed by ZenGarden.

function newGraph(netlist) {
  ZgnaclModule.postMessage("newGraph:" + netlist);


Messages may be sent to the graph with the sendMessage command. The receiver name, timestamp at which the message should be delivered, and the message formatted as a string are required arguments. In practice the timestamp should always be zero (i.e. 0.0) such that the message is delivered immediately. The message string can be anything that describes a valid Pd message. Examples include:

  • 0 0 0: a message with three floats, each equal to zero.
  • hello world 0: a message with three elements, the first two are strings and the last one is a float.
  • !: a message with one bang element
// the message is delivered immediately (when in doubt, use this function)
function sendMessage(receiverName, timestamp, messageString) {
  ZgnaclModule.postMessage("sendMessage:" + receiverName + ":0:" + messageString);

function sendMessageWithTimestamp(receiverName, timestamp, messageString) {
  ZgnaclModule.postMessage("sendMessage:" + receiverName + ":" + timestamp + ":" + messageString);


In order to receive messages sent from ZenGarden to JavaScript, an external receiver must be registered. For instance, if a receiver named "toJs" is registered, then every message sent to that receiver in ZenGarden (perhaps via a [s toJs] object) will also be sent to JavaScript. External receivers may be registered and unregistered at any time.

function registerReceiver(receiverName) {
  ZgnaclModule.postMessage("registerReceiver:" + receiverName);
function unregisterReceiver(receiverName) {
  ZgnaclModule.postMessage("unregisterReceiver:" + receiverName);

play & pause

Audio can be easily started and stopped via the play and pause commands, their function being self-explanatory. Note that when Cynical is paused, neither audio nor messages are processed. Cynical will behave as if time were standing still. If some kind of mute functionality is desired, while messages continue to be processed, this must be build directly into the patch.

function play() {

function pause() {


For experts only. Messages sent in the reverse direction are polled by a reader thread. This function allows the poll interval (given in milliseconds) to be adjusted. The default interval is 50ms (20Hz). In this case, messages are delivered to JavaScript with up to a 50ms delay (+ a small delay added by Native Client).

function setPipeReadInterval(intervalMs) {
  ZgnaclModule.postMessage("setPipeReadInterval:" + intervalMs);

An Example

// TODO(mhroth)

Restrictions and Limitations

Currenty there are a number of important limitations to the implementation. These are due to technical hurdles which can be overcome, with the exception of the last point.

  • Messages cannot be sent from ZenGarden to JavaScript. This includes the output of objects such as [print], or messages sent to external receivers.
    • This issue is no longer a problem. Arbitrary messages may be sent to ZenGarden from JavaScript (forward direction), and from ZenGarden to JavaScript (reverse direction). In order to receive messages sent in the reverse direction, a receiver name must be registered with ZenGarden. Print statements will also be sent to JavaScript.
  • The loaded patch cannot refer to any abstractions. Subpatches are acceptable.
  • Binary assets, such as samples, cannot be loaded.
  • Microphone or line input is not available. This is unlikely to change soon, if at all, and is due to security issues raised by allowing automatic access to the system microphone in the browser.

Cynical is currently best suited for making synthesizers.

Where the Action is

The ZgnaclInstance class contains most of the wrapper code. Start there for an overview. If you just want to use the library and start hacking away in JavaScript, see zgnacl.html for a basic example.

Build the project with scons.

  • Download the NaCl SDK. http://code.google.com/chrome/nativeclient/docs/download.html

  • Ensure you have downloaded the ZenGarden submodule into your zgnacl directory

  • (Whilst cd'd into your zgnacl directory) git submodule init

  • In your zgnacl directory edit 'scons' (using vi or nano or any other text editor)

    • vi scons
    • edit the line beginning "export NACL_SDK_ROOT=/Users…" to reflect the path to the NaCl SDK on your machine e.g. export NACL_SDK_ROOT=/Users/[yourusername]/[pathto]/native_client_sdk_0_5_1052
    • exit your text editor
  • Check this has worked by cleaning the target repository

    • ./scons -c
  • To build

    • ./scons
    • You should now see the files being compiled in your terminal window (may take 5-10 minutes)
    • Once that has finished there should be (among others) four .nexe files in your zgnacl directory

Testing your plug-in in the browser

  • Create a symlink to your zgnacl directory in the examples folder of the NaCl SDK

    • ln -s /Users/[yourusername]/[pathto]/zgnacl /Users/[yourusername]/[pathto]/native_client_sdk_0_5_1052/examples
  • Start the NaCl web server

    • python /Users/[yourusername]/[pathto]/native_client_sdk_0_5_1052/examples/httpd.py
    • note down the port number
  • Run your plug-in in Chrome

Native Client docs