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 'white', 'pink' and 'brown' oscillators + refactor synth #713

Merged
merged 14 commits into from
Oct 3, 2023
Merged

Add 'white', 'pink' and 'brown' oscillators + refactor synth #713

merged 14 commits into from
Oct 3, 2023

Conversation

Bubobubobubobubo
Copy link
Contributor

@Bubobubobubobubo Bubobubobubobubo commented Sep 30, 2023

This PR is proposing the inclusion of three new base oscillators: pink, white and brown.
It also comes with the addition of a new mechanism for other base oscillators : the addition of noise on sources.

  • The .noise(0->1) parameter can be used to blend noise using a wet/dry principle.
  • white, pink and brown are recognized as oscillators.

It has been fixed to be compatible with FM synthesis: noise is not being modulated.

This PR is also adding documentation about the mechanism.

@Bubobubobubobubo
Copy link
Contributor Author

I keep forgetting how to generate snapshots but this PR is bringing nothing fancy. Should be rather easy to check and merge. It's part of the low hanging fruits floating around in the engine.

- separate waveform / noise oscillators
- pull noise out of getOscillator
- put fm into getOscillator
- simplify overall value plumbing
@felixroos
Copy link
Collaborator

this looks and sounds good! I've done a bit of a refactoring, separating noise and waveform oscillators. most of the oscillator stuff (fm, vibrato, partials) don't make any sense for noise

@Bubobubobubobubo
Copy link
Contributor Author

Alright! Makes sense. I don't think that the vibrato on samples thingie can bite us anyway for this one, it's a separate mechanism living elsewhere so everything should be good.

@felixroos
Copy link
Collaborator

just noticed it might be a bit weird that .noise does something different on zzfx, where it noises the frequency instead of the amplitude: https://strudel.tidalcycles.org/?C3hFa3HJ7owY

@felixroos
Copy link
Collaborator

also sounds a bit more useful imo. without .noise, noise mixing can also be done like this:

s("triangle,pink:0:.1")

or

stack(
  s("triangle"),
  s("pink").gain(.1)
)

noising the frequency cannot be done with existing params (i think?), so it might make more sense to use noise for the thing you can't do otherwise

@felixroos
Copy link
Collaborator

this also makes me wonder why this noise mixing should even be implemented in synth.mjs, as it could be applied to other sounds as well, so superdough.mjs might be a better fit

@Bubobubobubobubo
Copy link
Contributor Author

I suppose it depends on how you see things. The default synthesizer used by Superdough is following a classic substractive architecture. Noise on substractive synths is generally part of the oscillator section and behaves like a wet/dry control over the amount of noise to be added to the section, just like it is currently implemented. ZZfX is a totally different beast. That type of frequency fog used by ZZfX can be reproduced by using vibrato already.

@felixroos
Copy link
Collaborator

I suppose it depends on how you see things. The default synthesizer used by Superdough is following a classic substractive architecture. Noise on substractive synths is generally part of the oscillator section and behaves like a wet/dry control over the amount of noise to be added to the section, just like it is currently implemented.

i agree, but it would behave the same when it's higher up in the abstraction, just with the added benefit of being able to add noise to all kinds of sounds ( not just waveforms )

@felixroos
Copy link
Collaborator

That type of frequency fog used by ZZfX can be reproduced by using vibrato already.

how?

@felixroos
Copy link
Collaborator

just realized your argument was for calling it noise, while my argument was for moving it the abstraction ladder...
I would be fine with calling the noise mixing .noise , tho then we should probably rename zzfx noise to znoise or fmnoise or something

@felixroos
Copy link
Collaborator

felixroos commented Oct 3, 2023

the general idea being that the same property name behaves the same across different types of sounds, because live coders should not have to care about the underlying architecture. also sounds of different types could be in the same pattern, e.g. s("sawtooth zzfx bd").noise(.5)

@Bubobubobubobubo
Copy link
Contributor Author

I see. One part of this debate is tied to different usages of the superdough library. Tidal generally makes it a breeze to make patterning part of the sound design process (superposing noise and other sources) while Topos is more basic, expecting sounds to be fully formed and ready when they are scheduled, with no proper support for polyphonic message sending.

One solution to this problem could be to rename .noise with .znoise and moving the .noise process upper in the chain, making it able to alter any sound played by superdough (synth, sampler, anything). Not sure if this is really useful though now that it lives outside the substractive synth model. This one detail of implementation is up to you 😄

@felixroos
Copy link
Collaborator

Not sure if this is really useful though now that it lives outside the substractive synth model.

certainly useful, just imagine using this with the wavetable synth

@felixroos
Copy link
Collaborator

One part of this debate is tied to different usages of the superdough library. Tidal generally makes it a breeze to make patterning part of the sound design process

While the tidal way of noise mixing is only a bit longer, it still makes sense to have an extra control for noise mixing I'd say. It's easier to remember and also easier to pattern, for example:

s("bd*8").noise(saw.slow(8))

without the noise control, you'd have to write:

s("bd*8").stack(s("pink").gain(saw.slow(8))))

also, needing to stack means a new chain is created which is more resource intensive

@felixroos
Copy link
Collaborator

felixroos commented Oct 3, 2023

another thing I've just noticed is that the noise buffer is recreated for every event, but it's always 2 seconds long.
It would save cpu to only generate each type of noise once

edit: fixed

@felixroos
Copy link
Collaborator

felixroos commented Oct 3, 2023

  • dry / wet now behaves like it should + is now a generic function, used by .noise
  • each noise type will only be generated once, then reused (otherwise costs too much cpu). In the future, we could generate noise with an audio worklet sample by sample, splitting up the cost

I have tried to pull up noise into the general superdough call but it seems the abstraction currently lacks support for nodes that need to be stopped + this is also the first time drywet is used as opposed to additive mixing. So I'll leave it like this for now, the global noise could be implemented when a solution for #721 is found. noise follow up issue: #722

@felixroos
Copy link
Collaborator

ok i've now added znoise which is used by zzfx to add frequency noise instead of amplitude noise. then i guess we're ready to merge?

@felixroos felixroos changed the title Add 'white', 'pink' and 'brown' oscillators Add 'white', 'pink' and 'brown' oscillators + refactor synth Oct 3, 2023
@felixroos felixroos merged commit d1ffdd5 into tidalcycles:main Oct 3, 2023
1 check passed
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.

2 participants