[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Aw: Re: [sc-users] Building UGens with shared resources so that constructors/deconstructors work with JITLib



> Is there a special function to put plugin initialization code that runs before any and all UGen Ctor calls?
 
Yes, in the PluginLoad function (actually, it's a macro), just where you store the interface table and define the UGen (e.g. with DefineDtorUnit). For example, in my VSTPlugin UGen that's the place where I read the cache file with VST plugin definitions.
 
> There's definitely quite some overhead in creating/destroying connections.. usually there are dropped audio blocks.
 
That's what I thought. You can use DoAsynchronousCommand to perform asynchronous operations. I guess this method was original meant to be used in plugin commands (see DefinePluginCmd), but it's totally possible to use it in UGens as well. This way you can make the connection to the I2C bus on the NRT thread to avoid audio dropouts. In my VSTPlugin UGen, I use DoAsynchronousCommand to make sure that plugins are opened/closed in a realtime-safe manner. See https://git.iem.at/pd/vstplugin/blob/master/sc/src/VSTPlugin.cpp#L1110.

There's an edge case you have to consider: it's possible that the UGen gets destroyed while an asynchronous command is still running, so have to make sure that the command data can outlive the UGen. In VSTPlugin, I keep certain state in a std::shared_ptr with a custom allocator (which calls RTAlloc and RTFree). The command data holds a std::shared_ptr to the shared state, to keep it alive even if the UGen gets destroyed. In the UGen destructor I set a flag in the shared state, so that running async commands know that the state is invalid. (Note that you must check the flag only in the RT thread!)

In your case, you could keep the I2C connection in the shared state. It's the responsibility of the shared state's destructor to close the connection. It might either get called when the UGen is destroyed or when a *remaining* async command calls the cleanup function.

I know it's a bit complicated and it's just my personal solution. Apparantely, I've been the first one to use async commands in UGens (if not at all) and there are no other examples I'm aware of...

It's up to you to decide whether you accept audio dropouts or not :-)

---

From your GitHub code:

> // object constructors will not be called automatically

You can do this:

void TrillRaw_Ctor(TrillRaw* unit){
    new(unit) TrillRaw(); // placement new, will call the constructor 
}

void TrillRaw_Dtor(TrillRaw* unit){
    unit->~TrillRaw(); // manually call destructor
}

---

Spawning a new thread in the UGen constructor is not realtime-safe, either. The bela documentation explicitly mentions that task shouldn't be spawned in the render() function. http://docs.bela.io/group__auxtask.html#ga4da01aeb487bedbe16bf17b2ffe6af9b

Also, if Bela_createAuxiliaryTask() actually creates a new thread, you wouldn't want to do this for every UGen. Actually, you only need to create a *single* task at setup and then schedule it from each UGen. Have a look at DiskIOThread in DiskIO_UGens.cpp on how to do that it in a realtime-safe manner.

Apart from that, your code isn't really thread-safe because class members (e.g. updateNeeded and sensorReading[]) are read/written from different threads without synchronization. (You could make them atomic, for example).

Finally, you have the same issue as described in the first part of my e-mail: updateTrill() might get called although the UGen has already been destroyed, so "data" will point to garbage. 


Christof

Von: info@xxxxxxxxxxxxxxxx
An: sc-users@xxxxxxxxxxxxxxxx
Betreff: Re: [sc-users] Building UGens with shared resources so that constructors/deconstructors work with JITLib

Thanks Christof & Scott for the great suggestions,
There's definitely quite some overhead in creating/destroying connections.. usually there are dropped audio blocks. For now it would be just a single connection for the lifetime of the plugin, so ownership/management of the connection needs to shift from one UGen instance to the other when the new UGen is instantiated by JITlib. Are you saying that I would be better off establishing the I2C connection automatically when the server boots? Is there a special function to put plugin initialization code that runs before any and all UGen Ctor calls? Forgive my ignorance, this is my first time diving into UGen development and I'm still quite fuzzy on many of the intricacies!
If it helps in any way, here's the code thusfar of the UGen. All the lower level I2C stuff is encapsulated in the Trill class, but the UGen is still responsible for triggering bus reads via a task running in a lower priority thread.
https://github.com/jreus/banjer/blob/master/Bela_UGens/TrillRaw/TrillRaw.cpp
thanks a lot for all your advice!
Jonathan
 

On 25/11/2019 18:17, scott@xxxxxxxxxxxxx[mailto:scott@xxxxxxxxxxxxx] wrote:

If you only need either a single or a fixed number of connections for the lifetime of your plugin, setting these up during plugin initialization rather than UGen construction might be the right approach. 
 
If each UGen can potentially have a different connection, you'll have to pool them and reference count, something like what Christof suggested - keeping in mind that JITlib will Crossfade running synths, so supporting two ugen instances pointed to the same sensor connection is absolutely required.
 
If resource management is too complex, and the overall number of connections you'll have is finite (e.g. someone can attach 20 sensors, but not 2000), you might consider creating them lazily, sharing them between ugens, and keeping them alive for the duration of the plugin - this could even improve performance if there's overhead in creating / destroying connections.
 
- S
 

On Mon, Nov 25, 2019, 3:30 PM <christof.ressi@xxxxxx[mailto:christof.ressi@xxxxxx]> wrote:

Each hardware I2C bus might be represented by a global object with a reference count. When a UGen connects to a certain I2C bus, its refcount is incremented; when a UGen disconnects from a I2C bus, its refcount is decremented. If the refcount goes from 0 to 1, the "actual" connection to the I2C bus is made; if the refcount goes from 1 to 0, the "actual" connection can be closed; otherwise you don't need to do anything.
 
This is how the OS manages many ressources under the hood.

 
Christof

Gesendet: Montag, 25. November 2019 um 14:35 Uhr
Von: info@xxxxxxxxxxxxxxxx[mailto:info@xxxxxxxxxxxxxxxx]
An: sc-users <sc-users@xxxxxxxxxxxxxxxx[mailto:sc-users@xxxxxxxxxxxxxxxx]>
Betreff: [sc-users] Building UGens with shared resources so that constructors/deconstructors work with JITLib

Dear all,
This is a rather technical question, so please let me know if I should better post it in sc-dev.
Right now I'm developing a kr UGen that reads data in from a specific sensor over an I2C bus. When this UGen is instantiated, there is code in its constructor method that creates an I2C object which establishes a connection to the I2C bus and configures everything properly. And inside the deconstructor method there is code that cleans up the I2C bus and then deletes the I2C object.
The UGen works fine when synths are manually instantiated and freed, but encounters some problems when using it inside an Ndef (nodeproxy).
The problem as I can see it (from print statements) is that when I update the UGen graph of a running Ndef, the order of allocation/deallocation goes something like this:
1. UGens of the new graph are instantiated (I get a "hello world" print statement from my UGen's constructor) - however there is already an existing I2C connection being managed by the already existing UGen instance (BAD!)
2. UGens of the old graph are de-allocated (I get a "goodbye world" statement from my UGen's deconstructor) - the "clean up I2C bus" code is called by the old UGen while the new one has an active connection to the I2C bus that it is managing (ALSO BAD!)
 
Does anyone on the list have any suggestions for how to deal with this behavior? I would very much like to be able to use JitLIB in developing programs with this UGen... there must be some clever way to specify the order of allocation/deallocation? Or...?
any thoughts are very welcome!
best
Jon
 
 

--
JReus
jonathanreus.com[http://www.jonathanreus.com]sensorycartographies.info[https://sensorycartographies.info/]anatomiesofintelligence.github.io[https://anatomiesofintelligence.github.io/]

Recent:Interview with PERFORM-TECH, by Fionn[https://www.composerfh.com/perform-tech] HanInterview with Asko-Schönberg Ensemble[https://instrumentinventors.org/jonathan-reus-interviewed-on-brave-new-world-2-0/]Interview with Leuphana University, Teaching Prize for Cross-Disciplinary Education Across Arts, Science and Humanities[https://www.leuphana.de/en/current-affairs/studies-releases/singleview/date/2018/01/29/the-computer-musician-portrait-of-jonathan-reus-winner-of-a-teaching-award.html]
_______________________________________________ sc-users mailing list info (subscription, etc.): http://www.birmingham.ac.uk/facilities/ea-studios/research/supercollider/mailinglist.aspx[http://www.birmingham.ac.uk/facilities/ea-studios/research/supercollider/mailinglist.aspx] archive: https://listarc.bham.ac.uk/marchives/sc-users/[https://listarc.bham.ac.uk/marchives/sc-users/] search: https://listarc.bham.ac.uk/lists/sc-users/search/[https://listarc.bham.ac.uk/lists/sc-users/search/]
--
JReus
jonathanreus.com[http://www.jonathanreus.com]sensorycartographies.info[https://sensorycartographies.info/]anatomiesofintelligence.github.io[https://anatomiesofintelligence.github.io/]

Recent:Interview with PERFORM-TECH, by Fionn[https://www.composerfh.com/perform-tech] HanInterview with Asko-Schönberg Ensemble[https://instrumentinventors.org/jonathan-reus-interviewed-on-brave-new-world-2-0/]Interview with Leuphana University, Teaching Prize for Cross-Disciplinary Education Across Arts, Science and Humanities[https://www.leuphana.de/en/current-affairs/studies-releases/singleview/date/2018/01/29/the-computer-musician-portrait-of-jonathan-reus-winner-of-a-teaching-award.html]


_______________________________________________
sc-users mailing list

info (subscription, etc.): http://www.birmingham.ac.uk/facilities/ea-studios/research/supercollider/mailinglist.aspx
archive: https://listarc.bham.ac.uk/marchives/sc-users/
search: https://listarc.bham.ac.uk/lists/sc-users/search/