variable-size Data arrays and a translation error
this code shows that Data can not be resized by changing a Param. Is there a way to somehow pass in the param's default value from the containing patch? (Something like "gen @number 8", which doesn't work...)
It also shows a translation error, allowing to overwrite the param from a function (but not to read it).
Cheers... Diemo
func(a)
{
//ret = number; // <-- this read of the Param gives an (indescriptive) error
number = 99; // this overwrites the Param!!!
ret = peek(a, 0, number); // ...but only if it is used here
return ret;
}
Param number;
Data arr(8, number); // changing the Param does not resize the Data arr
func(arr);
poke(arr, 99, in1, in2);
out1 = peek(arr, in1, in2);
out2 = number;
Sorry - you cannot change the size of a data operator on the fly.
You'll need to keep track of the size of your data operator's contents and adjust the ways that you interact with the changing size of your data operator accordingly (things like peeks/samples and pokes, counting your way through the data operator's contents, etc.).
Hi Diemo!
Yes exactly as Gregory says, unfortunately a [data] cannot be resized dynamically; the arguments to the Data object constructor must be constants.
(For the technical reason why: we determined very early on in gen~ development to disallow dynamic memory allocation within the code generated by gen~, since a) memory allocation by default is an operating system call that can cause unpredictable delays on different kinds of CPUs, and can be problematic on embedded devices too, which could cause audio dropouts, b) writing a fast dynamic-safe allocator is possible in certain conditions but may require re-implementation for different export targets, and c) letting a generative algorithm or simply a typo error in code suddenly cause huge unintended allocations, possibly at sample rates or faster, would be a disastrous thing to unleash, etc.)
As Gregory says, the best policy is to pre-allocate as much memory as you anticipate needing in the [data] object, and then use your [param number] or something similar to identify how much of this data you will actually be using at any particular moment.
---
One other comment from your code above -- hope it helps clarify a bit more:
You can't refer to a global Param or Data etc. within a function, unless you pass that param value or data reference into the function as an argument. Functions are more like patcher abstractions, best to think of them as a self-contained chunk of code that you can put inputs into and get outputs out of. They don't have scope access to variables, param, data, history etc. from your main body of code. So the first line in the function (`ret = number;`) is really an error of referring to a variable that is not within the scope in the function, or hasn't (yet) been declared within the function. The next line in the function (`number = 99;`) doesn't overwrite the param (because params are not visible within functions), it just creates a new local variable called "number". This new variable is local to the function and will disappear when the function returns.
I realize you might have been asking a different question, which is "how can a gen subpatcher initialize data to a length computed according to some constant thing in the parent gen~ patcher", and I'm afraid that it is a good question and I don't think there is a solution at the moment.
You *can* do some constant expression computations in data arguments, e.g. [data 16*16] or [data samplerate/2] etc., but this constant expression parser in gen~ can't read things from outside of that context, and can't refer to a [param] or an input from a parent patcher, as these are not evaluated as constants in the type system evaluator.
Dear Greg and Graham, thanks for your insights on these gritty gen details!
I realize you might have been asking a different question, which is "how can a gen subpatcher initialize data to a length computed according to some constant thing in the parent gen~ patcher", and I'm afraid that it is a good question and I don't think there is a solution at the moment.
This was the exact question I was asking, can the Data's size be determined from the containing patch, like #1 can be used in an abstraction. One pbly could use scripting?
OTOH, one can see in the compiled code that memory allocation happens in the generated reset() method, so technically, the allocated size could be different at each call of reset().
You can't refer to a global Param or Data etc. within a function, unless you pass that param value or data reference into the function as an argument.
That's what Joshua found out and told me, too. I would have loved to read that information somewhere, especially after running around in circles in the gen documentation for hours.
So the first line in the function (`ret = number;`) is really an error of referring to a variable that is not within the scope in the function.
Yes, the code doesn't compile, but the error doesn't give the slightest hint what's wrong:gen_domain: dsp.gen: [string "-- main2.lua..."]:697: failed to compile genpatcher
The next line in the function (`number = 99;`) doesn't overwrite the param (because params are not visible within functions), it just creates a new local variable called "number".
Except that it DOES overwrite the param. No local variable is created:
inline t_sample func_dat(Data& a) {
m_number_1 = int(((int)99));
... }