Lich - Gen~ phasor vs cycle and audio levels discussion + cv out

cool thanks @undefined, I’ll check that out.
Could you upload your .gendsp file as well? Then we can see how the patch is put together!

Oh right!
Updated the patch and included the maxpat too.

must be just the weird operations that are done in that oscillator example (it is supposed to work inside a polysynth that oversamples by 8x - differentiated polynomial waveform oscillators - Gen Forum | Cycling '74) and they get rounded off and mess with the Lich patch (very low signal is getting extremely boosted at the end) - pretty interesting what happens vs max and website.

  • also noticed that the “cycle” object doesn’t go into 50hz after getting a -50 value while the “phasor” does in that patch on the lich. Pretty sure gen doesn’t care if it gets negative or positve values for the frequency - this might explain why another patch wasn’t working though!
    Putting an “abs” before the “cycle” frequency fixes it obviously. https://www.rebeltech.org/patch-library/patch/Phasor_to_Triangle_Test_Abs
  • also wondering if knobs B, C, D affect the oscillator frequency on your hardware - maybe mine is leaky and needs a clean, since they seem to affect it even though they are not assigned to anything and only Param A is controlling the frequency

Yep the low frequency freak-out is because of how safepow() is implemented, on the hardware we use a high-performance approximative function with lookup tables.

If I change it to use standard powf() implementation it stops making weird noise at near-zero frequencies. But the CPU usage goes up, from 11% to 26%.

I think the optimised approximative maths functions are very useful, and work perfectly in most cases. Maybe what we should do however is to also use them in the web version of the patch, so that any side effects can be spotted there.

It is also clear without the extra noise that on the hardware, with the abs patch, the range goes past zero when you turn fully anti-clockwise. Is that intentional? Does it make time run backwards - should I be worried? :smile:

must be just the weird operations that are done in that oscillator example

Maybe good to find a better low-frequency oscillator example!

wondering if knobs B, C, D affect the oscillator frequency on your hardware

Nope, I’m not getting any pitch changes when turning the other knobs.

maybe mine is leaky and needs a clean

Already??

I am always too lazy to clean solder residue and then 3 days later funky things happen. But no worries.

With the abs example I just put in an “abs” object so any negative value becomes positive - i guess cycle in gen~ doesn’t care or can run inverted or something with negative values for frequency.

I made an example without the funky division and multiplication of the levels and its seems ok - other than my knob issue changing the pitch with unassigned knobs
https://www.rebeltech.org/patch-library/patch/Phasor_to_Triangle_2 - no issues with low frequencies there

It’s dangerous only if left on for a long time and you wake up in diapers.

Regarding powf optimization, we could allow disabling optimized function by adding defines (one for each function). Or maybe we could have a different implementation that would only use LUT in the range where its reasonably precise.

yessss this “cycle” discovery and switching to manually creating a sine with phasor and fastsin fixed my original patch. It doesn’t lose power now and I am really glad there wasn’t something funky with the history or sample rate that was causing it to not always work. I am still not sure how stuff is processed, but seems like doing gen~ feedback loops works well!
Now eagerly awaiting gate and cv out :slight_smile:

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:

1 Like

here we go haha https://www.rebeltech.org/patch-library/patch/Lich_Gen_out_tester

@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.

Docs: gen_common_out Reference - Max 8 Documentation

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 :smile:

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.