WebAudio / web-audio-api

The Web Audio API v1.0, developed by the W3C Audio WG
https://webaudio.github.io/web-audio-api/
Other
1.04k stars 166 forks source link

Phase-offset of oscillator nodes #2402

Open pendragon-andyh opened 9 years ago

pendragon-andyh commented 9 years ago

Can we have an a-rate parameter on the OscillatorNode that allows modulation of the phase offset? This would allow:

ghost commented 9 years ago

+1, agreed that this is needed. A couple more use cases:

joeberkovitz commented 9 years ago

Seems like a significant gap. We want to get implementors' feedback on the effort involved.

rtoy commented 9 years ago

@hoch and I took a quick look at this a while back. Seems doable without huge effort.

padenot commented 8 years ago

Yeah it's not very hard and very useful, we should do it.

rtoy commented 8 years ago

I concur.

On Wed, Sep 23, 2015 at 2:00 AM, Paul Adenot notifications@github.com wrote:

Yeah it's not very hard and very useful, we should do it.

— Reply to this email directly or view it on GitHub https://github.com/WebAudio/web-audio-api/issues/541#issuecomment-142534272 .

Ray

meszaros-lajos-gyorgy commented 8 years ago

With this I would have more control on the wave and could change the oscillator's gain more smoothly. Currently the gain doesn't wait for the wave to reach 0, so it cuts the wave anywhere, resulting in a clicking sound whenever the gain is changed.

Please look at my bugzilla report for examples: https://bugzilla.mozilla.org/show_bug.cgi?id=1232644

jesup commented 8 years ago

I agree with @meszaros-lajos-gyorgy -- make it easy/possible to do the most common thing, which would be to avoid pops/clicks. They're almost never what you want...

meszaros-lajos-gyorgy commented 8 years ago

To add another example: I'm currently developing an app, which heavily relies on the Audio API's oscillators and gains and it is about constantly changing the volume and pitch of the generated frequencies. You can hear the clicking an popping almost every time you change something.

Live project: http://meszaros-lajos-gyorgy.github.io/microtonal/monochord/ Source code: https://github.com/meszaros-lajos-gyorgy/meszaros-lajos-gyorgy.github.io/tree/master/microtonal/monochord

modosc commented 8 years ago

@meszaros-lajos-gyorgy fwiw i ran into similar issues and worked around them with setValueAtTime - this removed all clicks for both pitch and volume in my app. granted this isn't something we should have to do (setting value directly should work) but at least it's possible to avoid them for now.

modosc commented 8 years ago

also, it would be great to get a sync input/output on the oscillator node. then to implement hard sync you could do something like:

osc1.sync.connect(osc2.sync)

i suppose i could see this as a callback too (similar to processor.onaudioprocess) but i'm not sure how well this would work if it was buffered. having logic in the sync would be great since you could selectively sync based on the phase of the second oscillator for soft sync, implement reversing sync, etc. probably i should open a separate issue on this?

modosc commented 8 years ago

sorry, one more thing:

Currently the gain doesn't wait for the wave to reach 0

won't you potentially get weird behavior here if you have something other than a vanilla oscillator connected directly to the GainNode? if you're implementing some sort of weird synthesis technique which results in some unwanted dc shift you may never cross zero in which case gain changes would just get queued up and never occur. with a sync output / input this could be handled (although now we're talking about adding a sync input to the GainNode which is getting more complicated - the behavior would be "if something's connected to the sync input then queue gain changes up until there's a sync input")

pendragon-andyh commented 8 years ago

@meszaros-lajos-gyorgy - I have added a combination of SetValueAtTime and LinearRampToValueAtTime to your fiddle (see http://jsfiddle.net/0pjapu9c/1/). I think it fixes your problem.

meszaros-lajos-gyorgy commented 8 years ago

@pendragon-andyh - I can still hear the clicking for every 'boop' in Firefox 43

padenot commented 8 years ago

This is likely to be a firefox bug.

svgeesus commented 8 years ago

This was asked for again (twice) at the WG plenary panel at WAC2016. One was a call for oscillator sync, to the hard sync effect, which can be done by resetting the phase. The second was the request for pulse waves, with a-rate modulation of mark/space ratio - which could be done with phase control, or could be added directly (to oscillator, or as a new pulseOscillator node).

svgeesus commented 8 years ago

Note that naive hard-sync will introduce aliasing because the hard-synced waveform is no longer bandlimited. But see "Hard Sync Without Aliasing" http://www.cs.cmu.edu/~eli/papers/icmc01-hardsync.pdf

toyoshim commented 8 years ago

+1 on this feature request.

What I want to do more by OscillatorNode is

The first three could be realized by having AudioParam phase that JavaScript code can manage. But the last one may need a special method to sync automatically as modosc suggested. Or could we do something equivalent by connecting "sawtooth" type OscillatorNode to the phase parameter?

rtoy commented 8 years ago

I believe the intent is to add a phase (name TBD) AudioParam.

I have been trying to implement this in Chrome and it's rather hard if we want to preserve the band-limited requirement of the Oscillator. It's easy if you drop this requirement, but I think it's important for the oscillator to be band-limited.

hoch commented 8 years ago

@toyoshim

Reset each oscillator phase on each note-on timing (this is a common approach to implement a synth) Reset LFO's oscillator phase on starting LFO

Is this to reuse a single oscillator without creating a new one? This is doable with osc.phase.setValueAtTime(0, time).

Yeap. Also doable with oscA.phase.value = -Math.PI/2; oscA.phase.value = +Math.PI/2 and two stereo panners.

This has been bugging me for a while. I believe hard-syncing 2 oscillators on zero-crossing might not be possible with this AudioParam approach.

pendragon-andyh commented 8 years ago

Currently Chrome's PeriodicWave::waveDataForFundamentalFrequency() function decides the lower and higher band-limited-tables to use from the frequency passed-in by the OscillatorHandler::process() function.

Instead of indexing the tables by their fundamental frequency, would it be possible to index by their phase-increment? A large phase-increment indicates a high frequency - so you need to cull more of its high harmonics.

pendragon-andyh commented 8 years ago

@hoch

I anticipated that the phase parameter would have a values like:

Is this to reuse a single oscillator without creating a new one? This is doable with osc.phase.setValueAtTime(0, time).

I would not expect this to work. In most designs, the phase parameter is normally an offset to what the unmodified phase of the oscillator would be. An easier way is to just start a new oscillator.

Sync modulation

I have a theory that (if we have a phase parameter) you could achieve this by the following steps:

The "(sine*square)=>waveshaper" trick was the most accurate way that I have found of getting a true sawtooth. Most people would reach for a BufferSourceNode - but the interpolation between samples means that the result is a bit noisy.

toyoshim commented 8 years ago

I assume writing values to the phase make the OSC ignore the frequency value virtually. Is this correct?

This is my understanding. Here, I assume the range for a loop is 0 through 1, and the value will be clipped as set value % 1.

osc1.type = "sine";
osc1.frequency.value = x;
osc2.type = "sawtooth";
osc2.frequency.value = freq;
osc2.conect(osc1.phase);

This makes a sine wave in frequency freq. x could not affect under the phase controlled by something connected.

gain.gain.value = 1.5;
osc2.connect(gain).connect(osc1.phase);

This can generate a periodic wave with 1.5 cycle of sine wave.

This is what I meant in my previous comment about sync modulation.

rtoy commented 8 years ago

On Tue, Aug 2, 2016 at 2:06 AM, Takashi Toyoshima notifications@github.com wrote:

I assume writing values to the phase make the OSC ignore the frequency value virtually. Is this correct?

​That's a good question. No one has actually proposed anything yet, but I was assuming that the resulting waveform would be something like

s(2_pi_f*t + phi(t))

where phi(t) is the phase input to the node. You can achieve what you want by setting the frequency to 0.​ This formulation also makes it much easier to design a cosine wave by setting phi(t) = pi/2.

I was also assuming that s(t) would still be band-limited when including the effect of the phase term. But neither of these has been decided yet.

This is my understanding. Here, I assume the range for a loop is 0 through 1, and the value will be clipped as set value % 1.

osc1.type = "sine"; osc1.frequency.value = x; osc2.type = "sawtooth"; osc2.frequency.value = freq; osc2.conect(osc1.phase);

This makes a sine wave in frequency freq. x could not affect under the phase controlled by something connected.

​Almost. Since osc2 is band-limited, the resulting sawtooth has ringing so the output of osc1 won't quite be a sine wave.​

gain.gain.value = 1.5; osc2.connect(gain).connect(osc1.phase);

This can generate a periodic wave with 1.5 cycle of sine wave.

This is what I meant in my previous comment about sync modulation.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/WebAudio/web-audio-api/issues/541#issuecomment-236847293, or mute the thread https://github.com/notifications/unsubscribe-auth/AAofPHJw_BoMgkTXBo-CiW5cHhe5sJ1bks5qbwiqgaJpZM4E9mrb .

Ray

joeberkovitz commented 7 years ago

New feature; need to defer to a later iteration.

svgeesus commented 6 years ago

Discussed at March 2018 f2f. Hard (phase reset) and soft (reversing) sync, difficulty of maintaining bandlimited with hard sync.

svgeesus commented 6 years ago

Hard Sync Without Aliasing - Carnegie Mellon School of Computer Science

poojarfuturistic5 commented 6 years ago

I have used webaudio API oscillator but getMediaUser doesn't work in ios microphones devices for sinewave Please can someone help me

meszaros-lajos-gyorgy commented 6 years ago

Hi! I don't want to rush anyone, but since the ticket has been opened for over 3 years now, I feel an urge to ask: is there any progress with this? is anyone working on this? have every question been answered regarding this feature? can we help in any way to make this feature happen sooner? Thanks!

hoch commented 6 years ago

It is rather a design problem; how parameters do we expose? Is it involved with 2 oscillator nodes or a new node with multiple oscillators? I think the right course of action is to build a prototype design with AudioWorklet and gather feedback from the dev community.

rtoy commented 6 years ago

Let's keep this issue about a phase offset for the OscillatorNode. Those wanting to talk about hard sync and the like, please open a new issue to discuss that.

svgeesus commented 4 years ago

Those wanting to talk about hard sync and the like, please open a new issue to discuss that.

hard sync issue

waterplea commented 4 years ago

Any news on this issue? phase control seems kinda essential when it comes to any kind of synthesis.

svgeesus commented 4 years ago

Angle Modulation (Phase & Frequency Modulation)

padenot commented 3 years ago

I think what we need is to have a clearer idea of what is expected, mostly about band-limiting. A phase AudioParam can trivially jump in value (setValueAtTime(v, t) will provoke an immediate jump to v). Is it expected to have the output of the oscillator to be band-limited? Intuitively, this wouldn't work too well with our wave table based approached, but I haven't thought about this too much.

pendragon-andyh commented 3 years ago

We get distortion from instantaneously changing most AudioParams. My original thought was that you could apply the phase offset directly to the waveform's lookup index. You would probably get a small amount of aliasing if you modulate like crazy on a square wave.

I don't actually need this feature for pulse width modulation any more (I used a worklet in https://github.com/pendragon-andyh/junox and used polyblep to minimise aliasing). I can use worklets for hard-sync and phase modulation.

rtoy commented 3 years ago

This is really nice and kind of the we intended new feature requests to work: a feature is requested, a polyfill with a worklet is created to show how it might work, and this is used to guide the design.

Thanks!

khoin commented 3 years ago

Is this an implementation issue -- regarding band-limiting?

We already have a-rated frequency AParam, that could easily generate frequencies above Nyquist. Were there any discussions about that before?

rtoy commented 3 years ago

The question is if it should be band-limited in principle.

The a-rate frequency was part of the original implementation, before standardization. Certainly, setValueAtTime() causes instantaneous changes in frequency, and I think we're ok with that not being band-limited.

I personally am ok with phase offset potentially not being band-limited since the oscillator itself isn't always band-limited.

khoin commented 3 years ago

I'm personally okay with that too, and for the same reason.

khoin commented 3 years ago

Here's my mock-up of OscillatorNode with phase AudioParam. https://khoin.github.io/OscillatorNodeP/ Impl.: https://github.com/khoin/OscillatorNodeP/blob/master/OscillatorNodeP.js

You can simply test that phase works by starting two oscillators. If you're lucky, your oscillators are out of phase completely and you'll hear nothing. You can then simply change the phase of the oscillator until you start hearing something. Conversely, you hear something at first and need to change the phase until they cancel each other out.

mdjp commented 3 years ago

We should group WebAudio/web-audio-api-v2#9 WebAudio/web-audio-api-v2#7 & WebAudio/web-audio-api-v2#1 together. Worth discussing with Chris L

WangNianyi2001 commented 2 years ago

It's 2022, I & my college mates are making a web audio host, which require precise control of phases of source nodes. Is this getting anywhere at all?

braebo commented 2 years ago

What is the recommended way to apply phase offset to an oscilator node?

hoch commented 3 months ago

Teleconference 5/30/2024:

To continue with further standardization, the WG needs a prototype based on AudioWorkletNode. (hence needs feedback label)