Martin is looking into that, but the problem is that gen~ doesn’t really have a concept for parameters output. So it would probably have to be done by adding “fake” output audio channels that would be converted to CV when running the patch. This still is not great as we will have to use extra memory for that and maybe patch would be generating CV on audio rate. The latter would be a big deal because some devices (i.e. Magus) can output more CV channels - up to 20 parameters can be used for output there.
I assume this was already explored with the cycling peeps too. I assumed that with gen you could assign a parameter to a cv out - param F, G and Push for example - and OWL would watch those parameters when running the patch and if they are changed by the gen patch - the value would be output to the cv’s. So you would use an encapsulated parameter in a nested gen object and then use “setparam” to change it.
This approach with nested object is something that I’ve thought about recently too. I suspect that there would be some kind of issue, but you could try setting up a patch with a nested object that would be editable via setparam and we’ll see what happens.
I suspect that if you just have a param that is not used for anything, gen~ may end up removing it from compiled code. If that would be the case we would need some way to force it to keep it. Maybe that would require doing something like creating a virtual output channel that would act as sink to force parameter update computation to run.
It didn’t work when I tried it, but I can upload a patch for science
Actually, just by looking at code that runs for gen~ patches I can tell that only parameter for top level patch object are present in generated code that we can use. And it doesn’t look like subpatches are accessible as separate objects in some way, they probably become a part of computation that top level patch runs. Which means that we won’t have access to metadata of subpatch that could be used to get parameter names.
Btw, as far as I remember current gen~ integration was developed with assistance from cycling dev(s), so lack of output is a strong hint that there is no easy solution for this. It was done back in old Owl pedal/modular days, but it had a pushbutton that could be used as output.
If anyone could upload a simple test patch that does the following then I could test it with some new code:
- define 2 input, 4 output channels
- connect input channels 1 and 2 to output channels 1 and 2 to route audio through
- send some LFOs to output channels 3 and 4
The idea is that the ‘extra’ two output channels will be automatically assigned to some output parameters.
But which ones?? This is the tricky bit, because on e.g. Lich and Wizard it’s Parameters F and G. But on Magus, those could be used by the patch already as inputs.
But if we start by simply hardcoding the assignment to ‘F and up’ then at least it will enable a lot more use cases. The longer term solution I think is to collect all parameter meta-data on the patch details page, and send it to the compilation process.
There’s no patches that use outputs yet, so backwards compatibility is not an issue. Which means that we could start assigning parameters starting with F and won’t break anything. It’s probably much better to have this as a temporary solution - and I’m sure that it’s preferable to have gaps in parameters order on Magus compared to no output at all.
The downside is that gen~ implementation would be working like this:
@mars - looks like output names are preserved in generated code, so we could follow the same convention and name them as “F”/“ButtonA”, etc. Am I missing something?
You can name audio output channels?
I’m a poor Linux user too, I dunno. But it would be weird to export output names that can’t be changed, right?
Looks like you can’t rename it, it just takes index. But all objects accept a few common parameters including:
annotation [symbol]
Sets the text that will be displayed in the Clue window when the user moves the mouse over the object.
varname [symbol]
Sets the patcher's scripting name, which can be used to address the object by name in pattr, scripting messages to thispatcher, and the js object.
So one of them could be used to override default F+ parameter IDs. Also, for Magus it could be used for the “>” suffix.
Question is if it is included in the generated source, easy to try and see.
The patch level API looks like this:
int num_inputs();
int num_outputs();
int num_params();
int perform(CommonState *cself, t_sample **ins, long numins, t_sample **outs, long numouts, long n);
void reset(CommonState *cself);
void setparameter(CommonState *cself, long index, t_param value, void *ref);
void getparameter(CommonState *cself, long index, t_param *value);
const char *getparametername(CommonState *cself, long index);
t_param getparametermin(CommonState *cself, long index);
t_param getparametermax(CommonState *cself, long index);
char getparameterhasminmax(CommonState *cself, long index);
const char *getparameterunits(CommonState *cself, long index);
size_t getstatesize(CommonState *cself);
short getstate(CommonState *cself, char *state);
short setstate(CommonState *cself, const char *state);
void *create(t_param sr, long vs);
void destroy(CommonState *cself);
here we go haha https://www.rebeltech.org/patch-library/patch/Lich_Gen_out_tester
Awesome, thanks. I deployed some updates and recompiled your patch. Try it now
A couple of notes on the current version:
- CV values are 0 to 1, audio is -1 to 1. At the moment the audio is clipped when converted to CV.
- CV outputs are updated each block, which means 750Hz with default blocksize of 64 samples.
- The mean value of samples in the assigned audio buffer is converted to CV.
- No CV smoothing is currently applied, so stepping is likely.
nice! can’t wait to try. Will the Gate Out be similar? Does it do cv out or just gate? hmm
A gate output can have just 2 output states by definition. If it could output anything but low/high state, it would be called a CV output.
well yeah, just thought maybe it wasn’t really “just” a gate out in the hardware/owl implementation
I tried with exponential smoothing on the CV values, but if we are only smoothing at blockrate then it doesn’t do much to improve the signal if it is fast moving. And if it isn’t then it’s pretty smooth already.
Maybe if we had a timer running which could interpolate CV values at a faster-than-block rate, then we’d see some really smooth signals. But that would have to be a device-specific firmware update. And it wouldn’t be just for gen patches.
So for now I think the present solution is pretty good, and the result is just like CV output using C++, FAUST or Pure data. You get decent results up to about 100Hz, and slower CV signals work better. If we bring down the blocksize then of course the output can move faster. And if you want additional signal smoothing, you can always filter it in the patch before sending it to the [dac].
Blockrate by default is 128 samples?
Only questions are is if the CV out from gen can be bipolar and if gate out will be “out 5” .
I also didn’t carefully test the last patch but I assume its 0-10v on cv out right now? And I guess the online compiler is set to convert gen “out 3” and “out 4” to cv 1 and 2 already - or was it just the test patch that was manually compiled with test settings? Thanks for all the information!
Blockrate by default is 128 samples?
Have to double check… Actually I think it is 64 samples, so block rate is 750 Hz.
the online compiler is set to convert gen “out 3” and “out 4” to cv 1 and 2 already
Yes that’s right. Out 3 and 4, if present, will be assigned to CV out 1 and 2 on the Lich. More generally, any ‘extra’ outputs will be assigned to output parameters from F up, so on e.g. the Magus you could use any number of them.
Lich CV outputs are 0-10V, corresponding to 0-1 sample range.
Gate out is not working yet, still mulling over how to best do that without wasting so much processing power.
Oh interesting - so CV has always been unipolar - good to know!