![]() |
#1 |
Human being with feelings
Join Date: Jan 2014
Location: Ontario, Canada
Posts: 1,638
|
![]()
This is probably only something Justin or Schwa can answer, but if anyone knows, I'd be grateful:
Specifically, I am trying to understand if this code is invalid. A Reaticulate user reported an issue that could be explained by a race condition in JSFX initialization if atomic_setifequal() does not support gmem buffers. Ultimately I need to be able to lock a critical section across arbitrarily many instances of a JSFX. Thanks! Last edited by tack; 05-23-2020 at 07:16 PM. |
![]() |
![]() |
![]() |
#2 |
Human being with feelings
Join Date: Jan 2014
Location: Ontario, Canada
Posts: 1,638
|
![]()
And to add, if atomic_setifequal() can't work across JSFX instances (gmem regions or _global.* variables), is anyone aware of some other pattern or recipe to implement some form of cross-instance locking?
|
![]() |
![]() |
![]() |
#3 |
Human being with feelings
Join Date: Jan 2014
Location: Ontario, Canada
Posts: 1,638
|
![]()
I'm fairly well convinced by now that atomic_setifequal() doesn't work with gmem region or global variables.
I've implemented a horrifying workaround by having a central Lua script elect one of the JSFX instances to be a lock manager. But this is really tragic. I'm quite interested to know if there's a proper way to do synchronization of critical sections across JSFX instances. By way of example, consider the scenario where a JSFX instance wants to allocate a unique instance id by counter. (This is what Reaticulate needs to do, as each JSFX instance must autonomously and safely carve out its own region in the shared gmem buffer.) Here's the JSFX, which tries (and fails) to use atomic_setifequal() to implement a spinlock used to generate a synchronized counter to act as an instance id: Code:
// RaceMaker.jsfx desc:RaceMaker options:gmem=racemaker slider1:-1<-1,1000,1>instance counter @init MAGIC = 0xdeadbeef; instance_id = -1; slider1 = instance_id; @block while (instance_id == -1 && gmem[0] == MAGIC) ( // Spin until lock is acquired (or we reach max allowed iterations) (atomic_setifequal(_global.racemaker_lock, 0, 1) == 0) ? ( // Lock was acquired. instance_id = gmem[1]; gmem[1] += 1; // Release lock _global.racemaker_lock = 0; slider1 = instance_id; ); ); Here is a Lua script now which writes the magic value to the gmem buffer, and then scans all the instances to look for collisions of instance ids. Code:
function scan() local seen = {} local collisions = 0 for tidx = 0, reaper.CountTracks(0) - 1 do local track = reaper.GetTrack(0, tidx) local fx = reaper.TrackFX_GetByName(track, "RaceMaker", false) if fx and fx ~= -1 and reaper.GetMediaTrackInfo_Value(track, "I_FXEN") == 1 and reaper.TrackFX_GetEnabled(track, fx) then local instance_id, _, _ = reaper.TrackFX_GetParam(track, fx, 0) if seen[tostring(instance_id)] then reaper.ShowConsoleMsg("COLLISION: track " .. tostring(tidx + 1) .. " with " .. seen[tostring(instance_id)] .. ": " .. tostring(instance_id) .. "\n") collisions = collisions + 1 else seen[tostring(instance_id)] = tostring(tidx + 1) end end end if collisions == 0 then reaper.ShowConsoleMsg("OK: no counter collisions\n") end end reaper.gmem_attach("racemaker") reaper.gmem_write(0, 0xdeadbeef) -- Give instances a bit of time to allocate an id reaper.defer(function() scan() end)
This outputs something like: Code:
COLLISION: track 5 with 1: 163.0 COLLISION: track 16 with 13: 12.0 COLLISION: track 17 with 12: 18.0 COLLISION: track 22 with 12: 18.0 COLLISION: track 28 with 12: 18.0 COLLISION: track 42 with 36: 29.0 COLLISION: track 52 with 48: 38.0 [...] So, with all that, unless I've done something silly with my spinlock implementation, I feel confident in saying atomic_setifequal() doesn't work with global variables. Can this be implemented? Or is there another option to accomplish synchronization between JSFX instances? Thanks! Last edited by tack; 05-25-2020 at 05:37 PM. |
![]() |
![]() |
![]() |
#4 |
Human being with feelings
Join Date: Jan 2007
Location: mcr:uk
Posts: 3,975
|
![]()
Can't help regarding the atomics but I made a library ages ago to track instances of a JSFX. Here's the link if it's any use... https://stash.reaper.fm/v/25417/IX.Tracker.jsfx-inc.zip
|
![]() |
![]() |
![]() |
#5 | |
Human being with feelings
Join Date: Jan 2014
Location: Ontario, Canada
Posts: 1,638
|
![]() Quote:
It looks like your code has the same problem mine does. In the case of your tracker library, you're making the assumption that Tracker.Register() can't execute concurrently across multiple JSFX instances. In my case, I was assuming that wasn't safe, but was making a different assumption that atomic_setifequal() worked on gmem buffers, which appears also to be false. Concurrent execution of Tracker.Register() breaks the promise of unique instance ids. Now, in practice, this race seems to be really rare. Personally, I have never run into it: I'd never observed multiple Reaticulate JSFX instances getting the same id. It works much like your code does: if the instance id isn't yet assigned in @block, then it goes and allocates one. This has been fine for me and until recently I'd not received user reports of any problems. But the user in question can, for reasons that still aren't clear to me, very reliably reproduce the race with a few reloads of a project. So to prove the unsafeness of the approach you and I have taken for allocating instance ids, I've made concurrency of the id allocation code much more likely by requiring a flag be set somewhere in gmem before the JSFX will try to allocate its id. And this works for your Tracker library too: Code:
@block (gmem[20000] == 0xdeadbeef) ? ( refresh_state = _global.Demo.Tracker.Update(self); my_id = _global.Demo.Tracker.GetID(self); instance_count = _global.Demo.Tracker.GetCount(); ); So ultimately the raciness is still there. Like I mentioned earlier, I've got a solution baking to basically assign one of the JSFX instances to act as a lock manager for the critical section (which assignment is done by a single-instance Lua script). But I'd really like there to be a proper way to solve this concurrency problem in JSFX. (One may wonder, if I have a global Lua script running, why it doesn't take the role of assigning unique instance ids. There are reasons we can talk about if you want. But it's still only a workaround to the basic problem of memory-safe concurrency in JSFX.) |
|
![]() |
![]() |
![]() |
#6 |
Human being with feelings
Join Date: Jan 2007
Location: mcr:uk
Posts: 3,975
|
![]()
Oh, sorry it wasn't more helpful. I didn't think instances could be updated simultaneously but perhaps that's something to do with anticipative processing, multiple cores and all that voodoo. IIRC the atomic functions were to help manage interaction between the gfx and audio threads of a single jsfx.
I'm sure Justin would probably consider adding global variants if there's a valid use case but he's probably super busy with much bigger fish right now, so don't hold your breath. |
![]() |
![]() |
![]() |
#7 | |
Human being with feelings
Join Date: Jan 2014
Location: Ontario, Canada
Posts: 1,638
|
![]() Quote:
![]() Indeed. I've come to learn that one can't quite predict what things catch Justin and schwa's attention. I think it somehow relates to quantum indeterminacy. |
|
![]() |
![]() |
![]() |
#8 |
Human being with feelings
Join Date: Jan 2007
Location: mcr:uk
Posts: 3,975
|
![]()
Haha! I think their focus will definitely be elsewhere for the next couple of months but yes, you never know.
|
![]() |
![]() |
![]() |
#9 |
Administrator
Join Date: Jan 2005
Location: NYC
Posts: 16,511
|
![]()
sorry I've been weighing over this for a bit figuring out what to do.
atomic_*() work on gmem, but only atomically within a particular JSFX instance (so not across multiple instances). Internally they are implemented using a mutex, so while I'd like to make it global, I want to make sure it doesn't cause any performance issues down the road. Expect some changes for this in a build soon. |
![]() |
![]() |
![]() |
#10 | ||
Human being with feelings
Join Date: Jan 2014
Location: Ontario, Canada
Posts: 1,638
|
![]() Quote:
Quote:
![]() But if you're confident enough in making the atomic_() mutexes global would be safe, that'd definitely be nicest from a Just Works perspective. |
||
![]() |
![]() |
![]() |
#11 |
Human being with feelings
Join Date: Oct 2007
Location: home is where the heart is
Posts: 12,417
|
![]()
tack, you may want to check latest pre-release.
![]() |
![]() |
![]() |
![]() |
#12 |
Human being with feelings
Join Date: Jan 2014
Location: Ontario, Canada
Posts: 1,638
|
![]() |
![]() |
![]() |
![]() |
#13 | |
Human being with feelings
Join Date: Jun 2013
Location: Krefeld, Germany
Posts: 17,432
|
![]() Quote:
I just tried to build a queue with the ability to handle multiple senders, each of which will be a JSFX instance in different tracks, and a single consumer JSFX. Hence the queue is in gmem. Works fine when not using the atomic functions. But of course this is not safe. Hence I do need atomic to work across instances of JSFXes. So I tried atomic_setifequal(), checking the result of that function and spinning if the result is not as expected (== previous value ). Works with a single instance, but I do need the multiple instance stuff. Is this already working ? Thanks, -Michael Code:
desc:midi to partner send options:gmem=MIDI_TRANSFER in_pin:none out_pin:none @init gmem[0] = 4; // write pointer for writers (needs atomic) gmem[1] = 4; // write pointer for readers gmem[2] = 4; // read pointer @block while (midirecv(mpos, msg1, msg2, msg3) ) ( midisend(mpos, msg1, msg2, msg3); // pass through ptr_if = 1; while (ptr_if) ( ptr = atomic_get(gmem[0]); ptr_old = ptr; ptr_4 = ptr+4; ptr_4 >= 4+4*10000 ? ptr_4 = 4; ptr_cmp = atomic_setifequal(gmem[0], ptr_old, ptr_4); ptr_cmp == ptr_old ? ( // qmwm[0] not changend by another sending instance gmem[ptr] = mpos; // we can do this, as the other only reads the prevoisly stored values ptr +=1; gmem[ptr] = msg1; ptr +=1; gmem[ptr] = msg2; ptr +=1; gmem[ptr] = msg3; ptr +=1; gmem[1] = ptr_4; // allow reading ptr_if = 0; // successfully queued ); ); ); Last edited by mschnell; 09-07-2022 at 06:08 AM. |
|
![]() |
![]() |
![]() |
#14 |
Human being with feelings
Join Date: Jun 2013
Location: Krefeld, Germany
Posts: 17,432
|
![]() AFAIU both X86 and ARM architectures do feature instructions that allow to implement e.g. atomic_setifequal() without the help of the OS. That would automatically be global and supposedly the fastest way to do it. BTW.: what is atomic_get() and atomic_set() supposed to do ? AFAIU these actions don't need atomicness. -Michael Last edited by mschnell; 09-08-2022 at 02:59 AM. |
![]() |
![]() |
![]() |
#15 |
Human being with feelings
Join Date: Jun 2013
Location: Krefeld, Germany
Posts: 17,432
|
![]()
Two instances of these
Code:
desc:midi to partner send options:gmem=MIDI_TRANSFER in_pin:none out_pin:none @init gmem[0] = 4; // write pointer for writers (needs atomic) gmem[1] = 4; // write pointer for readers gmem[2] = 4; // read pointer @block while (midirecv(mpos, msg1, msg2, msg3) ) ( midisend(mpos, msg1, msg2, msg3); // pass through ptr_if = 1; while (ptr_if) ( ptr = atomic_get(gmem[0]); ptr_4 = ptr+4; ptr_4 >= 4+4*10000 ? ptr_4 = 4; ptr == atomic_setifequal(gmem[0], ptr, ptr_4) ? ( // qmwm[0] not changend by another sending instance gmem[ptr] = mpos; // we can do this, as the other only reads the prevoisly stored values ptr +=1; gmem[ptr] = msg1; ptr +=1; gmem[ptr] = msg2; ptr +=1; gmem[ptr] = msg3; ptr +=1; gmem[1] = ptr_4; // allow reading ptr_if = 0; // successfully queued ):( _1 += 1; ); ); ); Hence the atomicness across instances seems to work now. -Michael Last edited by mschnell; 09-08-2022 at 03:01 AM. |
![]() |
![]() |
![]() |
#16 |
Human being with feelings
Join Date: Jun 2013
Location: Krefeld, Germany
Posts: 17,432
|
![]()
BTW.: the list of library functions used for "atomic" by the C++ compiler (and hence might be considered useful) can be found here: -> https://en.cppreference.com/w/cpp/atomic
-Michael Last edited by mschnell; 09-09-2022 at 03:23 AM. |
![]() |
![]() |
![]() |
#17 |
Human being with feelings
Join Date: Jun 2013
Location: Krefeld, Germany
Posts: 17,432
|
![]()
Why do we need atomic_set() and atomic_get(). Is it really possible that a thread is interrupted and a floating point value is saved only partly ?
-Michael Last edited by mschnell; 09-30-2022 at 10:58 PM. |
![]() |
![]() |
![]() |
#18 |
Human being with feelings
Join Date: Jun 2013
Location: Krefeld, Germany
Posts: 17,432
|
![]()
...
Or is this related to some multicore cache issues - which seems unlikely as the code in GHitGub does not use "memory boundary" ASM instructions but a Mutex ? |
![]() |
![]() |
![]() |
#19 |
Human being with feelings
Join Date: Jun 2013
Location: Krefeld, Germany
Posts: 17,432
|
![]()
I posted a FR regarding this issues.
-Michael |
![]() |
![]() |
![]() |
#20 | |
Human being with feelings
Join Date: Oct 2015
Posts: 82
|
![]() Quote:
You could try something like the follow. It is not much different from your code but does a little more work to try to keep things straight. The main linchpin here is that a random value is used as a unique ID for separating out the race condition: atomic_setifequal(gmem[mcfx_base + mcfx_idx_sync], 0, uidr); (gmem[mcfx_base + mcfx_idx_sync] == uidr) ? ( Assuming the atomic set works and uidr is unique per instance then it should work. One could potentially check for any uidr collisions by also storing them and generating new ones if they already exist. I'm not sure about the serialization. It only seems to serialize one value in the rpp but it is remembering both. There is also unique FXID instance guids and that seems like it is what one actually wants to get but I doubt there is a way to do it. Code:
desc:new effect options:gmem=LuaCommTest /* reaper.gmem_attach("LuaCommTest") reaper.gmem_read(idx) The following example tries to enable setting unique fx instance ID's to enable cross communication */ @serialize file_string(0, #uid); @init function rc() ( (rand(36) > 25) ? floor('0' + rand(9)) : floor('A' + rand(26)); ); max_instances = 1000; // Max number of instances mcfx_init = -1; // If this instance is mc initialized mcfx_i = -1; // the instance idx into the list of instances mcfx_base = 0; // Offset where multiple instances of this JS are configured for cross-communication mcfx_idx_zero = 0; // If gmem is zero then no instance has been synced. Clears the count and other pre-initialization. mcfx_idx_sync = 1; // the synchronization lock idx mcfx_idx_num = 2; // the FX instance number idx mcfx_idx_ids = 3; // the FX instance id's (each of length 13) file_string(0, #uid); (strlen(#uid) == 0) ? ( #uid = ""; // uid for FX sprintf(#uid, "%c%c%c%c-%c%c%c%c%c%c%c%c", rc(),rc(),rc(),rc(), rc(),rc(),rc(),rc(),rc(),rc(),rc(),rc()); ); uidr = rand(0); // real uid used to avoid collisions(if this is not unique then there may be race conditions) uids = 14; // Size of uid string(including null) // Force complete pre-initalization //i = 0; while(i < 2000) ( gmem[mcfx_base + i] = 0; i = i + 1; ); // pre-initialize (singleton) (gmem[mcfx_base + mcfx_idx_zero] == 0) ? ( gmem[mcfx_base + mcfx_idx_sync] = 0; gmem[mcfx_base + mcfx_idx_num] = 0; ); // prevents any further pre-initialization gmem[mcfx_base + mcfx_idx_zero] = 1; function gmRStr(index, output) local(offset, buf) ( offset = 0; buf = #; while ( gmem[index] ? ( str_setchar(buf, offset, gmem[index]); offset += 1; index += 1; ) : 0; ); strcpy_substr(output, buf, 0, offset); // truncates the output ); function gmWStr(index, str) local(offset, buf, ch) ( while (offset < strlen(str)) ( ch = str_getchar(str, offset); ch ? ( gmem[index + offset] = ch; offset += 1; ) : 0; ); gmem[index+offset] = 0; ); function gmRStrB(index, output) ( gmRStr(index*1000, output); ); function gmWStrB(index, str) ( gmWStr(index*1000, str); ); @slider @block // gmem vars for display numFX = gmem[mcfx_base + mcfx_idx_num]; gmRStr(mcfx_base + mcfx_idx_ids + 0*uids, #uidFX1); gmRStr(mcfx_base + mcfx_idx_ids + 1*uids, #uidFX2); gmRStr(mcfx_base + mcfx_idx_ids + 2*uids, #uidFX3); gmRStr(mcfx_base + mcfx_idx_ids + 3*uids, #uidFX4); gmRStr(mcfx_base + mcfx_idx_ids + 4*uids, #uidFX5); (mcfx_init == -1) ? ( // Scan for uid in list, if found then do not instantiate lmax = max_instances; lcnt = 0; while (lcnt < lmax) ( gmRStr(mcfx_base + mcfx_idx_ids + lcnt*uids, #tmpstr); (strcmp(#tmpstr, #uid) == 0) ? ( lcnt = lcnt + lmax + 10; ); lcnt = lcnt + 1; ); // uid was found in list from previous initialization so ignore (lcnt >= lmax + 10) ? ( mcfx_i = lcnt - lmax - 10 - 1; lcnt = 1000100; ) : ( lcnt = 0; ); // Initalize instance while (lcnt < 100) ( lcnt = lcnt + 1; atomic_setifequal(gmem[mcfx_base + mcfx_idx_sync], 0, uidr); (gmem[mcfx_base + mcfx_idx_sync] == uidr) ? ( mcfx_init = 1; lcnt = 1000000; mcfx_i = atomic_add(gmem[mcfx_base + mcfx_idx_num], 1) - 1; gmWStr(mcfx_base + mcfx_idx_ids + mcfx_i*uids, #uid); gmem[mcfx_base + mcfx_idx_sync] = 0; ); ); ) |
|
![]() |
![]() |
![]() |
#21 | |
Human being with feelings
Join Date: Jun 2013
Location: Krefeld, Germany
Posts: 17,432
|
![]() Quote:
I did check that the atomic* functionality on gmem does work with multiple instances on I64 arch. Code see above. (I don't have Reaper on ARM, even though I do own a RasPI.) Very long ago I did code that assigns an ID to each instance of a JSFX (using gmem). I never saw a problem, but its many years ago and I can't claim I did it right ![]() Last edited by mschnell; 03-04-2025 at 02:31 AM. |
|
![]() |
![]() |
![]() |
#22 | |
Human being with feelings
Join Date: Oct 2015
Posts: 82
|
![]() Quote:
JSFX instances should be able to get their uid's. Seems to have them by looking at the rpp so why not have some js fx function that can retrieve them. Slider that allows text input. [I requested this long ago] E.g., say I had some AI based FX that generates a unique sound based on a prompt. No way to do this without creating or using some gfx ui code. No simple "slider" that allows for text input. My use case is that I want to be able to enter filenames. I had to create my own gfx code to do it and it doesn't support copy and paste so this makes it a real pain(I end up editing the source code and change the variable value manually so I can get the copy and paste). The ability to query variables and their values from a script. E.g., reaper obviously knows of the variables and their values since it displays them(maybe this only works in the editor though). But if a script could get and set a JSFX variable then it would make it much easier to have the two interact. In fact, JSFX likely should be able to interact with scripts without issue. In fact, that is what I'm trying to achieve using gmem and some message passing which is why I need unique id's to avoid collisions. E.g., one can call scripts relatively easily by simply passing a string, as a message, to a script listener that then can execute that string. Passing data back and forth is a problem. Strings and numbers could be passed relatively easily but userdata(tracks, items, etc) might be more difficult. But a translation table could be done where uid's are passed instead. What I'm trying to achieve is to write a master FX that controls many other JS FX instances so that I can have an easier interface into those instances. E.g., say I have 100 FX A instances. Currently I have to manually go and mess with each one(and in my case edit the code to change variables and each one is an FX on an item(not track FX)). FX B then is a master FX that is one interface into all those 100 allowing configuring them from one window or do other things. If I could, in JSFX, query other FX and get all the FX of a certain type or id and their unique id along with their variables and to be able to change the playback position to them then it would be a relatively simple thing to do. E.g., think of it like writing a custom "Track Manager", "Routing Matrix", "FX Browser", or whatever. Some window that lets one message with a bunch of other things(in this case a bunch of FX instances). That is what I'm trying to write because I'm tired of messing with the FX individually or manually doing certain tasks which can be more easily automated or drastically simplified with a nice single interface. The interface can be done by a script which is what I'm doing but I need some way to get at those FX instances and information they contain. But this is not an easy task because there is no sane way for scripts and JSFX to interact. gmem allows it to be hacked but does not seem to be safe and requires a lot of extra code(that pollutes the script but I guess one could put it in an include). E.g., just to give an example of what could be done: Suppose one has a bunch of logger FX that compute various audio and/or midi statistics and has them strewn throughout the project(tracks and items). Then one could have a master logger(script or possibly another JSFX) which consolidates all that information and presents it in one interface. First and foremost having a way to uniquely identify the JSFX instances is key. Second, some type of messaging or data passing system is beneficial. This can be done with gmem but, again, is a lot of extra work(which I'm currently implementing for my specific use case) and would be better to have it built in. |
|
![]() |
![]() |
![]() |
#23 |
Human being with feelings
Join Date: Jun 2013
Location: Krefeld, Germany
Posts: 17,432
|
![]()
Scripts and JSFXes in different instances live in different threads. Hence the communication needs to be done via FiFos (this is exactly what the "Midi Transfer" Code above does). Neither JSFXes not Scripts are allowed to wait on something. Hence communication is bound to be somewhat complex and not straight forward...and not at all "realtime".
OK, as any plugin obviously does have an ID, so it might be possible that it could be provided in a variable. Last edited by mschnell; 03-04-2025 at 11:41 AM. |
![]() |
![]() |
![]() |
#24 | |
Human being with feelings
Join Date: Oct 2015
Posts: 82
|
![]() Quote:
What would be nice is not just to get the ID but be able to get other plugin information. Some way to distinguish both the JSFX and the JSFX instance. e.g., maybe be able to get the filename and the id. This way one can check if the JSFX instance is an instance of a certain FX. This would make it easier to have multiple FX running multiple sub-instances and being able to disambiguate them all. E.g., JSFX_GetInstanceID() returns the uuid as a string or possibly a unique handle or whatever. JSFX_GetInstanceFilename(id) returns the filename backing the script. JSFX_PostMessage(str) posts a message on a global messaging system that can be read by scripts and vice versa(JSFX_GetMessage()). These behave, of course, like typical messaging systems. One gets any message with it's id or if it is broadcast. One posts a message and it's ID is attached. This would allow for basic communications between scripts and fx. This is what I'm basically implementing now. I'm generating my own uids to enable the messaging(which is done using a chunk of gmem partitioned in to message blocks). Making such a feature available in general would make it more useful and give some basic messaging features and it could be optimized and less error prone. e.g., timing info(timestamp) could be easily added to the messages to help deal with old or dead messages. This would also make it easy for various script types to interact such as lua and python. As long as enough disambiguating info is added it should be easy to avoid conflicts. |
|
![]() |
![]() |
![]() |
#25 |
Human being with feelings
Join Date: Oct 2015
Posts: 82
|
![]()
Also, to be clear. What is important for the uid is so that one can associate item FX's in such a way that the scripts and interact in a meaningful way with the instances.
Right now there, AFAIK, no way for an item FX instance to in any way be distinguished from any other. A instance uid helps solve that. More so, a script needs to be able to also get a takefx's uid. In this way, by having the JSFX itself be able to get it's own uid and a script to be able to get the an FX's id then they can synchronize themselves in an unambiguous way. E.g. I have a need to get know the specific positions of take FX. I can get an item and then it's FX instances but I have no way of getting any uid's for them. More so, the JSFX themselves have data I want to use but there is no way to coordinate these 3 pieces of info(item, it's FX instances, and the FX instance itself) because there is no way to get uid's in of them or at least not all of them which is required. I think simply having a way to get an instance UID in a script and a JSFX will go a long way to solving these types of issues. e.g., we can get fx_type : type string fx_ident : type-specific identifier fx_name : name of FX (also supported as original_name) so I suggest adding an 'fx_uid' to get the unique id. Then in JSFX a function that also allows the instance to get it's own instance uid. Then gmem can be used to synchronize between everything. If it is not too difficult then something like 'fx_var.Name' to get the instances variable value. E.g., fx_var.srate can get the srate or fx_var.myvar will get whatever myvar is set to. If a string then returns that string value). Also possibly being able to set such variables. |
![]() |
![]() |
![]() |
#26 |
Human being with feelings
Join Date: Oct 2015
Posts: 82
|
![]()
A bigger issue I am having is that item take FX are never initialized in any way unless the are active(being played).
This prevents me from initializing or sending any setup information from them on project load and the code only works when I have played the item(and I guess the active take fx) or the playback occurs after the item's end but before any other(seems reaper calls only the previous item's active take fx's @init section). This makes it impossible to do anything in regards to consolidating take fx's into a single interface since they will never be active in any way until they are "used"(which is when the item they are used on is being played). Ideally there would be some way to have the @init run on project load to initialize the interactions with scripts. Possibly another block like @projectinit could be created to enable global initialization on project load. |
![]() |
![]() |
![]() |
Thread Tools | |
|
|