Synthdef

pre-Alpha

A gem to work with SuperCollider's binary synthdef format. This uses the excellent bindata gem to define the spec in a very readable way. The implementation is around than 60 lines of code.

It works with both SynthDef and SynthDef2 formats.

I found the actual spec here:

http://doc.sccode.org/Reference/Synth-Definition-File-Format.html

Before I found the spec(!), inspiration was taken from the following links:

This handles the synthdef format in Overtone, using Jeff Rose's byte-spec library.

Code by @miguel-negrao to parse synthdefs in Haskell.

Other libraries and langs I haven't checked out yet:

Installation

Add this line to your application's Gemfile:

gem 'synthdef'

And then execute:

$ bundle

Or install it yourself as:

$ gem install synthdef

Command line usage

The gem ships with a command line tool to print the contents of a synthdef file as json

$ gem install synthdef
$ synthdef -v
synthdef gem version 0.0.5
Manipulate SuperCollider synthdef files from the command line
Usage: synthdef [options] [path]
    -c, --convert [VERSION]          Specify synthdef version of output
    -f, --format [FORMAT]            Specify output format: json,  raw
    -v, --version                    Show version
$ synthdef /path/to/synthdefs/foo.scsyndef
=> {
  "file_type_id": "SCgf",
  "file_version": 1,
  "no_of_synthdefs": 1,
  "synthdefs": [
    {
      "name": "sonic-pi-pretty_bell",
      "no_of_constants": 15,
      "constants": [
        0.0,
        ...
$ synthdef --convert 2 /path/to/synthdefs/foo.scsyndef
=> {
  "file_type_id": "SCgf",
  "file_version": 2,
  "no_of_synthdefs": 1,
  "synthdefs": [
    {
      "name": "sonic-pi-pretty_bell",
      "no_of_constants": 15,
      "constants": [
        0.0,
        ...

Usage

Take a binary scsyndef file (you can find an example in spec/data/recorder.scsyndef)

$ bundle exec irb

# pp is just to pretty print the output, not essential
>> require 'pp'
=> true
>> require 'synthdef'
=> true
>> raw = open("spec/data/recorder.scsyndef").read
>> pp Synthdef.read(raw)
=> {:file_type_id=>"SCgf",
 :file_version=>1,
 :no_of_synthdefs=>1,
 :synthdefs=>
  [{:name=>"sonic-pi-recorder",
    :no_of_constants=>0,
    :constants=>[],
    :no_of_params=>2,
    :params=>[0.0, 0.0],
    :no_of_param_names=>2,
    :param_names=>
     [{:param_name=>"out-buf", :param_index=>0},
      {:param_name=>"in_bus", :param_index=>1}],
    :no_of_ugens=>3,
    :ugens=>
     [{:ugen_name=>"Control",
       :rate=>1,
       :no_of_inputs=>0,
       :no_of_outputs=>2,
       :special=>0,
       :inputs=>[],
       :outputs=>[1, 1]},
      {:ugen_name=>"In",
       :rate=>2,
       :no_of_inputs=>1,
       :no_of_outputs=>2,
       :special=>0,
       :inputs=>[{:src=>0, :input_constant_index=>1}],
       :outputs=>[2, 2]},
      {:ugen_name=>"DiskOut",
       :rate=>2,
       :no_of_inputs=>3,
       :no_of_outputs=>1,
       :special=>0,
       :inputs=>
        [{:src=>0, :input_constant_index=>0},
         {:src=>1, :input_constant_index=>0},
         {:src=>1, :input_constant_index=>1}],
       :outputs=>[2]}],
    :no_of_variants=>0,
    :variants=>[]}]}

Differences between SynthDef versions 1 and 2

# Taken from spec
# synth-definition-file for version 2

int32 - four byte file type id containing the ASCII characters: "SCgf"
int32 - file version, currently 2.
int16 - number of synth definitions in this file (D).
[ synth-definition ] * D
pstring - the name of the synth definition
int32 - number of constants (K)
[float32] * K - constant values
int32 - number of parameters (P)
[float32] * P - initial parameter values
int32 - number of parameter names (N)
[ param-name ] * N
pstring - the name of the parameter
int32 - its index in the parameter array
int32 - number of unit generators (U)
[ ugen-spec ] * U
pstring - the name of the SC unit generator class
int8 - calculation rate
int32 - number of inputs (I)
int32 - number of outputs (O)
int16 - special index
[ input-spec ] * I
int32 - index of unit generator or -1 for a constant
if (unit generator index == -1)
int32 - index of constant
else
int32 - index of unit generator output
[ output-spec ] * O
int8 - calculation rate
int16 - number of variants (V)
[ variant-spec ] * V
pstring - the name of the variant
[float32] * P - variant initial parameter values

Again, taken from the spec

The original SynthDef format differs in that the following items are int16 instead of int32.
NOTE: The following list describes what has changed between SynthDef and SynthDef2. It is not a complete description of the the original SynthDef file format.
int32 - file version, currently 1. (This is 2 for the new format.)
a synth-definition is :
int16 - number of constants (K)
int16 - number of parameters (P)
int16 - number of parameter names (N)
int16 - number of unit generators (U)
a param-name is :
int16 - its index in the parameter array
a ugen-spec is :
int16 - number of inputs (I)
int16 - number of outputs (O)
an input-spec is :
int16 - index of unit generator or -1 for a constant
int16 - index of constant
int16 - index of unit generator output

Contributing

  1. Fork it ( http://github.com/xavriley/synthdef/fork )
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create new Pull Request