Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add reset and phase versions of lf_sawpos #44

Merged
merged 2 commits into from
Oct 13, 2020

Conversation

magnetophon
Copy link
Contributor

No description provided.

oscillators.lib Outdated
// License: STK-4.3
lf_sawpos_phase_reset(freq,phase,reset) = lf_sawpos_reset(freq,reset) +phase :ma.frac
with {
dontReset = reset:ba.impulsify*-1+1;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dontReset is not used in the function?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops!
Fixed now.

oscillators.lib Outdated
// License: STK-4.3
lf_sawpos_reset(freq,reset) = ma.frac * dontReset ~ +(freq/ma.SR)
with {
dontReset = reset:ba.impulsify*-1+1;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this dontReset so complicated? Can you explain what signal it produces?

Copy link
Contributor Author

@magnetophon magnetophon Jun 27, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a stream of 1's,with a single sample zero when reset goes from 0 to bigger then 0.
Can you think of a way to simplify it?

@josmithiii
Copy link
Collaborator

josmithiii commented Jun 27, 2020 via email

@magnetophon
Copy link
Contributor Author

Hi Julius,

@sletz Suggested the much more elegant (reset <= reset') on the slack chat.
I changed the PR to use that.

Coincidentally, while making that change, I also thought of not debouncing, but initially decided to leave it in.
After reading your comment I reconsidered and removed it.

@josmithiii
Copy link
Collaborator

josmithiii commented Jun 28, 2020 via email

@sletz
Copy link
Member

sletz commented Jun 28, 2020

I think detecting fronts should be standardised because they happens everywhere and we really want the most efficient way to write those low-level stuff, so I suggest to add in the basics.lib:

upfront(x) = x > x';        // equal 1 for upfront, 0 otherwise
downfront(x) =  x < x';  // equal 1 for downfront, 0 otherwise
front(x) = x != x';	          // equal 1 for upfront or downfront, 0 otherwise
inv_upfront(x) = x <= x';      // equal 0 for upfront, 1 otherwise
inv_downfront(x) = x >= x'; // equal 0 for downfront, 1 otherwise
inv_front(x) = x == x';          // equal 0 for upfront or downfront, 1 otherwise 

What do you guys think? Then my suggestion would be to check if some lower-level control signal can be improved using this.

@josmithiii
Copy link
Collaborator

josmithiii commented Jun 28, 2020 via email

@sletz
Copy link
Member

sletz commented Jun 28, 2020

I still like the idea of having the front or edge idea in the name, and also suggesting the "inverse" idea (0 becomes 1, and 1 becomes 0) so possibly:

rising_edge
falling_edge
edge ? front ?
inv_rising_edge
inv_falling_edge
inv_edge ?  inv_front

@sletz
Copy link
Member

sletz commented Jun 28, 2020

And more generally; trying to rewrite everything starting from the more general version with phase and reset, and specialising it using the fact the compiler will only keep the really needed code, so:

lf_sawpos_phase_reset(freq,phase,reset) = (+(phase-phase') : ma.frac * (reset <= reset')) ~ +(freq/ma.SR);
lf_sawpos_phase(freq,phase) = lf_sawpos_phase_reset(freq, phase, 0);
lf_sawpos_reset(freq,reset) = lf_sawpos_phase_reset(freq, 0, reset);
lf_sawpos(freq) = lf_sawpos_phase_reset(freq, 0, 0);

Then we can possibly define :

lf_sin_phase_reset(freq,phase,reset) = sin(2* ma.PI * lf_sawpos_phase_reset(freq,phase,reset));
lf_sin_phase(freq,phase) = sin(2* ma.PI * lf_sawpos_phase(freq, phase));
lf_sin_reset(freq,reset) = sin(2* ma.PI * lf_sawpos_reset(freq, reset));
lf_sin(freq) = sin(2* ma.PI * lf_sawpos(freq));

So you see the point here, rebuilding from scratch, starting from the most efficient general form, using the compiler optimising features to define more specialised versions, building more complex signals (the sin version here) by wrapping the basic sawpos and so on...

@magnetophon
Copy link
Contributor Author

I like the suggestion to clean up the edge detection in the libraries.
I think that the last set of names is the best so far.

Small nitpick: As I understand it, the lf_ prefix as used in faust, marks oscillators that might alias, so lf_sin doesn't make sense.

In any case, none of the above applies to this PR, as Julius and I decided to take out the debunce altogether.

@LFSaw
Copy link

LFSaw commented Jun 28, 2020

In any case, none of the above applies to this PR, as Julius and I decided to take out the debunce altogether.

I went ahead and created a new issue for this: #45

@magnetophon
Copy link
Contributor Author

magnetophon commented Jun 28, 2020

I found some bugs.
When I compile this:

import("stdfaust.lib");
freq = hslider("freq",440,0,24000,0.0001);
gain = hslider("gain",0.5,0,1,0.001);
gate = button("gate");
phase = hslider("phase", 0.5, 0, 1, 0.001)<:select2(checkbox("smooth phase"),_, si.smoo);

process =
  lf_sawpos_phase_reset(freq,phase,gate:ba.impulsify)*gate
, stephan_lf_sawpos_phase_reset(freq,phase,gate:ba.impulsify)*gate;

lf_sawpos_reset(freq,reset) = ma.frac * (reset == 0) ~ +(freq/ma.SR);
lf_sawpos_phase_reset(freq,phase,reset) = lf_sawpos_reset(freq,reset) +phase :ma.frac;

stephan_lf_sawpos_phase_reset(freq,phase,reset) = (+(phase-phase') : ma.frac * (reset == 0)) ~ +(freq/ma.SR);

I get different results depending on how I compile:

  1. with faust2jack bug.dsp && ./bug:
  • lf_sawpos_phase_reset works as expected
  • stephan_lf_sawpos_phase_reset seems to ignore the phase slider
  1. with faust2jack -midi -nvoices 1 bug.dsp && ./bug
  • lf_sawpos_phase_reset
    works as expected without "smooth phase",
    has a pitch bend (described below) with "smooth phase"
  • stephan_lf_sawpos_phase_reset
    seems to ignore the phase slider without "smooth phase".
    has a pitch bend (described below) with "smooth phase"

When the pitch bend is present, the oscillators start at phase 0, but with a higher pitch, and then pitch down during the course of the note.

I guess these are side-effects of the fact that with -nvoices, the dsp is turned on and off, but I'm not sure what to do about it.

@sletz
Copy link
Member

sletz commented Jun 28, 2020

My proposal was lf_sawpos_phase_reset(freq,phase,reset) = (+(phase-phase') : ma.frac * (reset <= reset')) ~ +(freq/ma.SR);

The reset handling is different.

@magnetophon
Copy link
Contributor Author

The only difference is that reset is impulsified.
The above bugs remain.

@sletz
Copy link
Member

sletz commented Jun 28, 2020

It seems that your lf_sawpos_phase(phase,freq) = (+(phase-phase') : ma.frac) ~ +(freq/ma.SR); I started from is not working as expected also ((-;

@magnetophon
Copy link
Contributor Author

magnetophon commented Jun 28, 2020

It works when compiled without -nvoices, so iow when the dsp is "on" all the time.

Any idea how to get it working with -nvoices?
Is this a bug in the above code or in the faust compiler?

@josmithiii
Copy link
Collaborator

josmithiii commented Jun 28, 2020 via email

@LFSaw
Copy link

LFSaw commented Jun 29, 2020

Speaking of prefixes, maybe "b_" could be a good prefix for all functions return 0 or 1, i.e., a one-bit signal?

could also be g_ as in gate, or t_ as in trigger, or is_ as in a question (is_falling, is_rising), assuming 0 to be equivalent to false and 1 equivalent to true.

@josmithiii
Copy link
Collaborator

josmithiii commented Jun 29, 2020 via email

@magnetophon
Copy link
Contributor Author

I figured out my smooth issue is, of course, an issue that every smoothed synth parameter has.
I came up with my own solution before I found polySmooth(g,s,d).

Why does it have the d parameter?
I can only see the use case for d=1, and that is how it's used in the examples I found.

This smooth function doesn't need g either, and does the same job, as far as I can tell.

new_smooth(s) = si.smooth(s * ((1-1') < 1) );

One could even make the case that this should be the default smooth function.
The current smooth(s) would be renamed, for use in exceptional cases.
That might break some dsp "in the wild" though.

What do you think?

@josmithiii
Copy link
Collaborator

josmithiii commented Jun 29, 2020 via email

@magnetophon
Copy link
Contributor Author

@josmithiii Thanks.
How does your solution work?
I don't understand how a delay comes into it, other then in creating the initialization pulse. That is not what you mean, is it?

@josmithiii
Copy link
Collaborator

josmithiii commented Jun 29, 2020 via email

@magnetophon
Copy link
Contributor Author

Thanks.
Why is d variable?

@josmithiii
Copy link
Collaborator

josmithiii commented Jun 29, 2020 via email

@magnetophon
Copy link
Contributor Author

Sorry to be dense, but if you implement smoothDelayedBy using smooth, then the case d=0 is not needed, right?
That brings me back to my original question: what is the d parameter in polySmooth used for?

@josmithiii
Copy link
Collaborator

josmithiii commented Jun 30, 2020 via email

@magnetophon
Copy link
Contributor Author

How can we move forward with this?

@josmithiii
Copy link
Collaborator

Since the commit just adds new functions, I see no problems with it.

@magnetophon
Copy link
Contributor Author

@rmichon Could you have a look at this one as well?

Most of the discussion above is about providing general functions for edge/front detection and is not really relevant for this PR.
When I say not really relevant, I mean:

  • Yes, general functions for edge/front detection would be nice.
  • Yes, once we have those, these functions should be rewritten.
  • But: this PR is useful as-is, imho.

@rmichon rmichon merged commit 21978db into grame-cncm:master Oct 13, 2020
@sletz
Copy link
Member

sletz commented Oct 13, 2020

Well, I think we should restart this edge/front detection discussion... Otherwise what will happen? Same kind of edge/front detection code rewritten again and again in similar use-cases, with "slight" differences that the average user will not grasp...
We (GRAME) have to provide clean and reference implementations, and so share code when it make sense.

@rmichon
Copy link
Contributor

rmichon commented Oct 13, 2020

I accepted this commit because it only adds new functions as @josmithiii pointed out. However, I agree with @sletz that this conversation on edge detection is important and should be continued.

@sletz
Copy link
Member

sletz commented Oct 13, 2020

OK ((-;

@magnetophon
Copy link
Contributor Author

@rmichon Thanks.
@sletz As mentioned above: Yes, general functions for edge/front detection would be nice.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants