-
Notifications
You must be signed in to change notification settings - Fork 79
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
livecodable dsp #309
base: develop
Are you sure you want to change the base?
livecodable dsp #309
Conversation
amazing. next (on the Haskell side): make an SC backend for https://hackage.haskell.org/package/csound-expression to produce programmatically the strings that describe the DSP ... |
there are certainly interesting possibilities for DSLs, but lets keep discussion here focused on the SuperDirt implementation :) i am currently working on extending this idea to per-orbit global effects, so we can write our own delays, reverbs, etc! tidal.gdsp.mp4 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I really like it. Simple and appropriately dirty. Let's take some time to think about how to best integrate it into core – of course it would need to be switched on explicitly.
Moreover, we should test the address the OSC message was sent from and only accept if it is 127.0.0.1 (just as a minimum protection).
We used to have a message called avoidTheWorst
in our Republic
system, that filtered all kinds of dangerous stuff, but of course it was exactly only a protection against unserious attempts.
It could also be an OSC responder with a separate OSC message that builds the synth def. Then tidalcycles could do this separation into another message. Or at least a separate method. Also, we need to rebuild only when something in the code changes. The code could be kept ins a set and you check for changes? |
here are my motivations for some of the decisions in the current implementation, and some thoughts on integration. the module:
the global effect:
with the above in mind, i am not sure using separate OSC messages would be an improvement, while it would certainly increase complexity. the current design requires no additional support from frontends, which i consider a big advantage. as for integration into core, i think something like the structure i ended up with in the latest commit could work: we would introduce a new type of event diversion which runs in a Routine and can signal "i need to run some code after a server sync" by returning a post-sync callback. for hackability, it would also be nice if this was a list of functions rather than a single function (like the current diversions are), so that new diversions could easily be added while keeping existing ones in place. with the above mechanism, enabling the livecodable dsp functionality would be just a matter of adding functions to the new "syncable diversions" list. it seems like there could be other use cases for this, though i cant think of any right now. it does raise the question of whether such a mechanism should be even more general, perhaps having the ability to wait for arbitrary things such as finally, there is some room for optimization:
|
Sorry, for some reason I haven't seen your reply, it wasn't in my notifications. I think we can make a version that does not require hacking the diversion. But it'll have to wait till later this week. |
no worries, interested to hear your ideas whenever you have time! |
@telephon have you had a chance to look at the latest version? :) |
Yes, I have, and thought about some things, just a few points to consider
As I've already said, this will be a great addition. So just some refactoring, if you agree. After that, I may just have a few minor improvements on the code, mostly "cosmetic". |
events do already sync in parallel, the idea behind the syncable diversions was just to provide a general hackable mechanism for diversions that follow the pattern "run code A, wait for server sync, run code B" which could possibly be useful for other purposes. do you mean it would be better to not provide this, and instead have the live dsp logic more tightly coupled with
this is to make it possible to write a different global effect for each orbit, which surely is much more useful musically. since
good idea! |
Thinking again, I tend towards keeping it general, it is good to have. I may be wrong, but I wouldn't make it a diversion, it is just if(~sustain >= orbit.minSustain.value or: { ~play.notNil }) {
this.finaliseParameters;
// unless event diversion returns something, we proceed
~play.(this) ?? {
if(~syncFunctions.notNil) {
Routine {
this.callSyncFunctions;
this.playSynths;
}.()
} {
this.playSynths
}
}
}
All the rest – preparing the right instrument name etc. would be done in the One more point, but that can be done in a next step, is that there is no need to add the diversions to every orbit even if you are not using it for patterned dsp. All that is needed is adding one syncFunction?
My thinking is this: The orbit.globalEffects.do { |x| x.set(currentEnvironment) }; So the calls
|
Another idea, what about this? DirtModule {
var <name, <func, <test, <preparationFunc, <preparationTest;
*new { |name, func, test, preparationFunc, preparationTest|
^super.newCopyArgs(name, func, test ? true, preparationFunc, preparationTest)
}
value { |orbit|
if(test.value, { func.value(orbit) })
}
prepareValue { |orbit|
if(preparationTest.value, { preparationFunc.value(orbit) })
}
mayNeedPreparation {
^preparationFunc.notNil
}
== { arg that;
^this.compareObject(that, #[\name])
}
hash {
^this.instVarHash(#[\name])
}
printOn { |stream|
stream << this.class.name << "(" <<< name << ")"
}
storeArgs {
^[name, func, test, preparationFunc, preparationTest]
}
} Then we could run: prepareModules {
if(modules.any(_.mayNeedPreparation)) {
Routine {
modules.do(_.prepareValue(this));
server.sync;
~latency = ~timeStamp - thisThread.seconds;
}.value
};
} |
this is an implementation of livecodable DSP by interpreting sclang code embedded in the OSC messages sent from Tidal. the code is extensively commented, so please see files changed for the details!
this is currently implemented as a "hack", but imho it is kind of a game changer and i propose that it might be worth considering as a core feature (but disabled by default, given the security implications). thoughts?