Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UGen metadata system #2300

Closed
nhthn opened this issue Aug 21, 2016 · 19 comments
Closed

UGen metadata system #2300

nhthn opened this issue Aug 21, 2016 · 19 comments

Comments

@nhthn
Copy link
Contributor

nhthn commented Aug 21, 2016

Currently, there are two components to every UGen -- a plugin for the server and an SC class that wraps the call to UGen.multiNew. The SC class is where we assign the names of arguments, their default values, their rates, and so on. This kind of data is unknown to scsynth/supernova.

This strikes me as sort of unfair to people who develop or use alternate clients, because they have to dig through SuperCollider's class library to figure out the names and rates of all the arguments. Wouldn't it be neat if the metadata about argument names and default values were packaged in with the server plugin?

This is obviously a proposal for the far future of SC, but it would save a lot of work for plugin developers and client developers.

@josiah-wolf-oberholtzer
Copy link

josiah-wolf-oberholtzer commented Aug 21, 2016

As an alternate client developer, this sort of metadata dump would be really helpful.

One can certainly write up a script in sclang to dump out a considerable amount of metadata about the UGen class family - parent class name, methods, method signatures - and write that data out into files importable/readable by your preferred language. That's how I've stubbed out ~500 Python modules, 1 for each UGen class, in the past. Would have been a lot easier if that data was simply available as JSON/YAML from the get-go. Some hand-adjustment is going to be necessary when porting so much logic from one language to another, but the process can certainly be simplified.

Maybe we could implement a script that gets run as part of the build process? Something that scrapes through all subclasses of UGen, writing out their class names, class parents, method signatures, etc. to a JSON file packaged along with SC's supporting files?

@nhthn
Copy link
Contributor Author

nhthn commented Aug 21, 2016

Sounds like a good short-term solution. I'm not totally sure how to make sc3-plugins and third-party plugins fit into that scheme, but the ideal of having every plugin automatically work with every client will probably remain a distant fantasy for a while.

@crucialfelix
Copy link
Member

This has been discussed a few times. We definitely could use this. JSON is best I think.

Josiah do you have the code you 8sed available as a starter ? Overtone and scala collider have already done this too.

@crucialfelix
Copy link
Member

Also do you have a python synthdef buIlder ? I'd love to have a look at that

@vivid-synth
Copy link
Member

@rd-- also had a script that he used for HSC3, that pulled the metadata from SC.

@josiah-wolf-oberholtzer

@crucialfelix I've lost the original script, but I used something like the following to dump out a Python dictionary of UGens, parents and method signatures:

(
var ugens;
"ugens = {".postln;
ugens = UGen.allSubclasses.collect({|ugen| ugen});
ugens.sort({|a, b| a.name < b.name});
ugens.do({ | ugen |
    var methods;
    ('    "' ++ ugen.name ++ '": {').postln;
    ('        "parent": "' ++ ugen.superclass.name ++ '",').postln;
    methods = ugen.class.methods;
    if (methods.size > 0, {
        '        "methods": {'.postln;
        methods.do({ |method|
            ('            "' ++ method.name ++ '": [').postln;
            method.keyValuePairsFromArgs.asAssociations.do({ | pair |
                ('                ["' ++ pair.key ++ '", ' ++ pair.value ++ '],').postln;
            });
            '                ],'.postln;
        });
        '            },'.postln;
    });
    "        },".postln;
});
"    }".postln;
)

I'm not an sclang user, yadda yadda yadda. But it gets a lot of data out. Shouldn't be too much work to filter out irrelevant methods and tweak it so it outputs JSON. Unfortunately JSON doesn't permit trailing commas, so you'll need to keep track of the counts of things. JSON would definitely be the way to go though - it has wider acceptance than YAML.

If you're curious about my implementation of SynthDef compilation in Python, the relevant classes are mainly in https://github.com/josiah-wolf-oberholtzer/supriya/tree/master/supriya/tools/synthdeftools. Byte-compilation is handled by https://github.com/josiah-wolf-oberholtzer/supriya/blob/master/supriya/tools/synthdeftools/SynthDefCompiler.py. There's also a decompiler, mainly for testing that byte-compiled SynthDefs are well-formed.

Building the UGen graph is handled by a number of classes:

  • SynthDefBuilder: acts as the mutable staging area for collecting parameters and UGens.
  • SynthDef: the immutable product of the UGen graph building process.
  • UGenSortBundle: ephemeral class for encapsulating state during the topological sort.

@josiah-wolf-oberholtzer

Of course, you still have to figure out the permissible rates of the arguments by hand, which UGens are even real (Mix for example, not being a "real" UGen), as well as exactly how the signature of the .ar / .kr / .ir calls correspond to the expected input list to send to the server (Klang being one of the chief offenders here). I don't know that there's any near-term automated way of handling extracting this kind of data.

@rd--
Copy link
Contributor

rd-- commented Aug 23, 2016

all

the work i did in this area is at http://rd.slavepianos.org/?t=hsc3-db

best,
rd

@nhthn
Copy link
Contributor Author

nhthn commented Dec 13, 2016

Here's a sketch of a proposal. We amend the plugin API to allow specifying argument names (and rates and whatever info is helpful), and we copy this information from the client to the server. We write a test in sclang to ensure that there are no discrepancies.

Then, we implement some method for clients to access this info through the server. Maybe it's an old-fashioned scsynth --dump-ugens > ugen-metadata.json, or /dumpUGens ugen-metadata.json, or both.

Some UGens take a variable number of arguments, or otherwise have difficulties conforming to a systematic format. For these, we can just leave their metadata blank and tell client developers to deal with them manually.

It's ideologically pure to have this metadata come directly from scsynth, but it may be too laborious to implement. Thoughts?

@crucialfelix
Copy link
Member

@snappizz I think that's too laborious / ideologically motivated.

Personally I don't see a problem with having sclang generate the metadata. It is the reference implementation anyway.

It could dump that and we can include the dump in releases. Plugins and external plugin libraries can dump as well and it should be possible for a client implementation to merge multiple files.

The idea about extending plugin API and then double checking for discrepancies is interesting. But that's a lot of work for a lot of people (cat herding) to spot a possibly small number of minor issues.

@muellmusik
Copy link
Contributor

There are a few UGens which reorder their args before sending to the server. Those also need to be accounted for.

@telephon
Copy link
Member

also multichannel expansion would have to be considered specially, e.g. for Klank and for Pan2.

@vivid-synth
Copy link
Member

Yes, between the reordered ugen args in sclang (there are many), multichannel expansion, and pseudo ugens (though: other clients may want to duplicate the pseudo ugens), I think metadata would ideally be stored on the UGens.

I could get behind a clear proposal for either sclang or scsynth but I imagine the scsynth/ugen route to be less labor-intensive.

@nhthn
Copy link
Contributor Author

nhthn commented Dec 17, 2016

Like I said, we can leave some metadata blank and tell client developers to deal with the special cases manually.

@rd--
Copy link
Contributor

rd-- commented Dec 18, 2016 via email

@nhthn
Copy link
Contributor Author

nhthn commented Dec 18, 2016

@rd-- GitHub automatically sends you email notifications of further comments in any thread you post in. You should be able to unsubscribe by clicking the "mute this thread" link at the bottom of the email notification for this post, or by going to the issue page and clicking the "unsubscribe" button.

@rd--
Copy link
Contributor

rd-- commented Dec 18, 2016 via email

@nhthn
Copy link
Contributor Author

nhthn commented Mar 16, 2017

Added to long-term, large-scale projects. Unfortunately, this is unlikely to become a priority soon.

@sonoro1234
Copy link
Contributor

sonoro1234 commented Mar 8, 2019

Using @rd-- and @josiah-wolf-oberholtzer ideas and my own generator system I have worked this script
https://github.com/sonoro1234/Lua2SC/blob/master/lua2SC/genugens/scugendumpjson.scd
and produced this json output
https://github.com/sonoro1234/Lua2SC/blob/master/lua2SC/genugens/ugens.json

With most ugens this is enought to generate the wrapping functions but some MultiOut ugens need more data to know if number of outputs depends on some input arg or is fixed.

Is there more data we can grab in order to solve this?

Other problems come from input reordering. Can we solve it also?

PseudoUGens are other issue. Can this be detected?

creating new issue as this is closed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

8 participants