Skip to content

Instantly share code, notes, and snippets.

@miguel-negrao
Created November 18, 2015 09:35
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save miguel-negrao/8d71807afb513412d780 to your computer and use it in GitHub Desktop.
Save miguel-negrao/8d71807afb513412d780 to your computer and use it in GitHub Desktop.
synthdef binary parsing
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"SynthDefFile\n",
" { version = 2\n",
" , numDefs = 1\n",
" , defs =\n",
" [ SynthDef\n",
" { synthDefName = \"system_line_audio\"\n",
" , numConsts = 1\n",
" , consts = [ 2.0 ]\n",
" , numParams = 3\n",
" , params = [ 0.0 , 1.0 , 1.0 ]\n",
" , numPNames = 3\n",
" , pnames =\n",
" [ ( \"i_bus\" , 0 ) , ( \"i_level\" , 1 ) , ( \"i_dur\" , 2 ) ]\n",
" , numUGens = 4\n",
" , ugenSpecs =\n",
" [ UGen\n",
" { ugenName = \"Control\"\n",
" , rate = 0\n",
" , numIns = 0\n",
" , inSpecs = []\n",
" , numOuts = 3\n",
" , outSpecs = [ 0 , 0 , 0 ]\n",
" , special = 0\n",
" }\n",
" , UGen\n",
" { ugenName = \"InFeedback\"\n",
" , rate = 2\n",
" , numIns = 1\n",
" , inSpecs = [ UGenOutput { ugenIndex = 0 , ugenOutputIndex = 0 } ]\n",
" , numOuts = 1\n",
" , outSpecs = [ 2 ]\n",
" , special = 0\n",
" }\n",
" , UGen\n",
" { ugenName = \"Line\"\n",
" , rate = 2\n",
" , numIns = 4\n",
" , inSpecs =\n",
" [ UGenOutput { ugenIndex = 1 , ugenOutputIndex = 0 }\n",
" , UGenOutput { ugenIndex = 0 , ugenOutputIndex = 1 }\n",
" , UGenOutput { ugenIndex = 0 , ugenOutputIndex = 2 }\n",
" , Constant 0\n",
" ]\n",
" , numOuts = 1\n",
" , outSpecs = [ 2 ]\n",
" , special = 0\n",
" }\n",
" , UGen\n",
" { ugenName = \"ReplaceOut\"\n",
" , rate = 2\n",
" , numIns = 2\n",
" , inSpecs =\n",
" [ UGenOutput { ugenIndex = 0 , ugenOutputIndex = 0 }\n",
" , UGenOutput { ugenIndex = 2 , ugenOutputIndex = 0 }\n",
" ]\n",
" , numOuts = 0\n",
" , outSpecs = []\n",
" , special = 0\n",
" }\n",
" ]\n",
" , numVariants = 0\n",
" , variants = []\n",
" }\n",
" ]\n",
" }"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"import qualified Data.ByteString.Lazy as B\n",
"import qualified Data.ByteString.Char8 as C\n",
"import Data.Binary.Get\n",
"import Data.Word\n",
"import Data.Binary.IEEE754\n",
"import Control.Monad (replicateM)\n",
"import Text.Show.Pretty\n",
"\n",
"deffile = \"/home/miguel/.local/share/SuperCollider/synthdefs/system_line_audio.scsyndef\" \n",
" \n",
"--helper functions\n",
"getInt8 = fmap (\\x -> fromIntegral x ::Int) getWord8\n",
"\n",
"getInt16 = fmap (\\x -> fromIntegral x ::Int) getWord16be\n",
"\n",
"getInt32 = fmap (\\x -> fromIntegral x ::Int) getWord32be\n",
"\n",
"getFloat32 = fmap wordToFloat getWord32be\n",
"\n",
"getPascalString = do\n",
" n <- getInt8\n",
" fmap C.unpack $ getBytes n\n",
" \n",
"getFloats = do\n",
" n <- getInt32\n",
" floats <- replicateM n getFloat32\n",
" return (n, floats)\n",
" \n",
"{--\n",
"a param-name is :\n",
"\n",
"pstring - the name of the parameter\n",
"int32 - its index in the parameter array\n",
"--}\n",
"getParamName = do\n",
" name <- getPascalString\n",
" n <- getInt32\n",
" return (name, n)\n",
" \n",
"{--\n",
"an input-spec is :\n",
"\n",
" int32 - index of unit generator or -1 for a constant\n",
" if (unit generator index == -1) :\n",
" int32 - index of constant\n",
"\n",
" else :\n",
" int32 - index of unit generator output\n",
"\n",
"an output-spec is :\n",
"\n",
" int8 - calculation rate\n",
"--}\n",
"\n",
"data InputSpec = Constant Int | UGenOutput { ugenIndex::Int,ugenOutputIndex::Int } deriving Show\n",
"\n",
"getInputSpec = do\n",
" index1 <- getInt32\n",
" index2 <- getInt32\n",
" return $ if index1 == 4294967295 then Constant index2 else UGenOutput index1 index2\n",
"\n",
"{--\n",
"pstring - the name of the SC unit generator class\n",
"int8 - calculation rate\n",
"int32 - number of inputs (I)\n",
"int32 - number of outputs (O)\n",
"int16 - special index\n",
"[ input-spec ] * I\n",
"[ output-spec ] * O\n",
"--}\n",
"\n",
"data UGen = UGen { ugenName::String, rate::Int, numIns::Int, inSpecs::[InputSpec], numOuts::Int, outSpecs::[Int], special::Int } deriving Show\n",
"getUGenSpec = do\n",
" name <- getPascalString\n",
" rate <- getInt8\n",
" numIns <- getInt32\n",
" numOuts <- getInt32\n",
" sIndex <- getInt16\n",
" inSpecs <- replicateM numIns getInputSpec\n",
" outSpecs <- replicateM numOuts getInt8\n",
" --return (name, rate, numIns, numOuts, sIndex, inSpecs, outSpecs)\n",
" return $ UGen name rate numIns inSpecs numOuts outSpecs sIndex\n",
"\n",
"{--\n",
"a variant-spec is :\n",
"\n",
"pstring - the name of the variant\n",
"[float32] * P - variant initial parameter values\n",
"--}\n",
"getVariant n = do\n",
" name <- getPascalString\n",
" replicateM n getFloat32\n",
"\n",
"\n",
"{--\n",
"pstring - the name of the synth definition\n",
"int32 - number of constants (K)\n",
"[float32] * K - constant values\n",
"int32 - number of parameters (P)\n",
"[float32] * P - initial parameter values\n",
"int32 - number of parameter names (N)\n",
"[ param-name ] * N\n",
"int32 - number of unit generators (U)\n",
"[ ugen-spec ] * U\n",
"int16 - number of variants (V)\n",
"[ variant-spec ] * V\n",
"--}\n",
"\n",
"data SynthDef = SynthDef { synthDefName::String, numConsts::Int, consts::[Float], numParams::Int, params::[Float],\n",
" numPNames::Int, pnames::[(String,Int)], numUGens::Int, ugenSpecs::[UGen],\n",
" numVariants::Int, variants::[[Float]]} deriving Show\n",
"\n",
"getDef = do\n",
" name <- getPascalString\n",
" (numConsts, consts) <- getFloats\n",
" (numParams, params) <- getFloats\n",
" numPNames <- getInt32\n",
" pnames <- replicateM numPNames getParamName\n",
" numUGens <- getInt32\n",
" ugenSpecs <- replicateM numUGens getUGenSpec\n",
" numVariants <- getInt16\n",
" variants <- replicateM numVariants $ getVariant numParams\n",
" return $ SynthDef name numConsts consts numParams params numPNames pnames numUGens ugenSpecs numVariants variants\n",
"\n",
"\n",
"{--\n",
"a synth-definition-file is :\n",
"\n",
" int32 - four byte file type id containing the ASCII characters: \"SCgf\"\n",
" int32 - file version, currently 2.\n",
" int16 - number of synth definitions in this file (D).\n",
" [ synth-definition ] * D\n",
"--}\n",
"\n",
"data SynthDefFile = SynthDefFile { version::Int, numDefs::Int, defs::[SynthDef] } deriving Show\n",
"\n",
"getSynthDef = do\n",
" scgf <- getBytes 4\n",
" version <- getInt32\n",
" numDefs <- getInt16\n",
" defs <- replicateM numDefs getDef\n",
" return $ SynthDefFile version numDefs defs\n",
" \n",
"do\n",
" contents <- B.readFile deffile\n",
" putStr.ppShow.runGet getSynthDef $ contents"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Haskell",
"language": "haskell",
"name": "haskell"
},
"language_info": {
"codemirror_mode": "ihaskell",
"file_extension": ".hs",
"name": "haskell",
"version": "7.10.2"
}
},
"nbformat": 4,
"nbformat_minor": 0
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment