Created
November 18, 2015 09:35
-
-
Save miguel-negrao/8d71807afb513412d780 to your computer and use it in GitHub Desktop.
synthdef binary parsing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"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