In Pd of course, anyone?
-
looking for velvet noise generator
-
I gave it a shot using zexy relationals, might be more efficient using other externals (hence "pure")
edit: realized I didn't need one of the[samphold~]
s
edit2: now I realize there is also the possibility of missed periods in the case that the[phasor~]
wraps around to a value higher than the[samphold~]
ed[noise~]
.. hmm..
edit3: 3rd time's the charm? used another[rzero~]
to put a 1 in there when the[phasor~]
wraps
pure-velvet.zip -
why do you have a reset phase input for phasor~?
what do you mean by "make sure there is at least 1 1 on wraparound"?
this can be easily made 100% vanilla with expr~
although I see the implementation, I still don't really know how a velvet noise generator is defined so I can check this patch's implementation and maybe think of alternatives, can you help?
thanks
-
@porres oh yeah I always forget about
[expr~]
for some reason.. maybe bc of the license it used to have.There's no real reason to have the phase reset inlet, just more control.
From what I can tell, velvet noise is outputting a 1-sample impulse of value that's either 1 or -1, chosen randomly, at a random point in a regular period.
So I have a[phasor~]
to keep track of the period, and the[samphold~]
samples a random value from 0-1 when the[phasor~]
resets. This will be the point in the phase of that period that the impulse will occur. When the[phasor~]
gets to above or equal to this value, the[<~ ]
will go from 1 to 0. That goes into[rzero~ 1]
, which will put out a -1 on the sample that occurs. That goes into the[==~ -1]
, which acts (together with[*~ ]
) as a gate for the noise value that has been manipulated to either be 1 or -1, depending on if the output of[noise~]
is positive or not.The issue with this original implementation was that when the
[phasor~]
wraps around to start a new phase, it can wrap to a value greater than the new[samphold~]
value from the noise. That means that if the noise value is very small, there will be no impulse for that period since the[phasor~]
value will never be less than the sampled noise value for that period (and therefore the[<~ ]
won't go from 1 to 0, which means the[rzero~ 1]
below it won't output a -1, and so on). So, the[rzero~]
and[<~ 0]
put out a 1-sample value of 1 when the[phasor~]
wraps around, which is combined with the other signal in[min~ 1]
to take care of this. That way the[rzero~ 1]
below the[min~ 1]
will get a 1 even if the wrapped-around[phasor~]
value is less than the new sampled noise value, and there will be an impulse for that period.
(that is what "make sure there is at least 1 1 on wraparound" means)edit: after writing all of this it occurred to me that the sampled noise value could also be greater than the value that the
[phasor~]
will get to before it wraps around.. perhaps the solution is to constrain the sampled noise value depending on the frequency and phase of the[phasor~]
... -
here's a max patch, what do you think?
easy to do with cyclone
reference
https://llllllll.co/t/techniques-for-generating-clicks-pops-hiss-and-noise/31314/45 -
@porres the user's explanation for the basis of that patch doesn't seem to fit what is described in this paper: https://www.researchgate.net/publication/260701331_A_Perceptual_Study_on_Velvet_Noise_and_Its_Variants_at_Different_Pulse_Densities
but it seems like there are a few different types of velvet noise. The original seems to be 1 impulse (chosen to be randomly either 1 or -1) randomly placed in time within a regular period. (which is not what the above patch does)
that's not to say it might not be a different type though, I only looked at the original -
@porres here's another simpler-to-implement type described in the paper - "totally random noise"
total-velvet.zip -
there is a good description here: https://acris.aalto.fi/ws/portalfiles/portal/13412521/applsci_07_00483_v2.pdf
it seems similar to dust2 in supercllider (and I ported that to ELSE already)
-
@porres the first version I posted is what is described in that paper. If you look at figure 1a you can see that there is 1 impulse randomly placed within a regular interval (which is shown by the red dashed lines in the figure).
-
It seems that the original version of the velvet noise generator finally didn't work hundred percent correctly (see the unresolved problems mentioned above). So here's a slightly different algorithm ... velvet-noise.pd
This one doesn't use any externals, in fact not even [expr~]. Hope it works!
Or is there another solution for this in the meantime?
-
nice idea!
here's a version based on it using expr~ and addition instead of subtraction
pure-velvet-noise-2.zip -
nice, I still have this in my list but I never get to it... I might check this all and include a compiled object in ELSE for it right now...
@seb-harmonik-ar I still don't know why you reset the phase on the [phasor~]
-
@porres it's just to give the user more control.. what if the user wants to reset the time period for triggering an impulse?
I included a version in my own library as velvet~ where it's driven by an external phasor (as well as controls for temporal and impulse bias), and just getting the precession to add with[rzero~ 1] | [wrap~]
-
here's my 'ELSE' version. No phase output, no phase reset, signal input and able to set seed
I still wanna check the algorithm, I don't really get it
-
@porres I leave the explaining to @seb-harmonik.ar, but I'm wondering if further optimizations may be possible:
-
Do we really have to scale the white noise going into [samphold~]? I don't think so.
-
Couldn't we use just one noise generator for both random variables? I mean, they are sampled at different times, so shouldn't this guarantee an uncorrelated outcome anyway? Not sure about that ...
-
-
ok, I see that you're going for period transitions in the [phasor~], well, this can be drastically simplified with [else/pimp~]! Let me think
-
So, what we need is just an impulse randomly placed within period, this could be done by modulating the phase of [pimp~] quite easily!
-
nah... it does output impulses more frequently...
-
what I don't get is why you need to add to a multiplication of the frequency and the sample rate period, can you explain that @seb-harmonik.ar ?
-
New ELSE version
Just a single noise source, no [expr~] and no copysign, which might be expensive and also the way I'm doing it now has "real zeros". I was very annoyned that the other version had a bunch of "-0" (minus zeros) values!
-
@porres Ah, now I see the problem ... (so I'll try to explain anyway)
By multiplying the frequency with 1/SR you get the phase increment of the phasor. Since there is exactly one sample in each cycle where the sum of the current phase and the increment gets bigger (or equal to) 1, you get the impulse. Now all you have to do is to randomize the phase to get the impulse at a random position.
I'll have to take a look at your new version ... (Still I don't think the noise scaling and [+~ 0.5] are necessary.)
Edit: Just noticed that you have ">" instead of ">=" in the [op~].