Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Web Audio oscillators unexpectedly glide from one frequency to another in Chrome

The behavior I'm about to describe happens in Chrome 44, but does not happen in Firefox 40.

If you create an oscillator, set it to a frequency of 220 Hz, and then change the frequency to 440 Hz a second later, you can hear a distinct portamento effect: instead of changing instantly from 220 to 440, the oscillator glides from the original frequency to the new one.

The code below illustrates this phenomenon:

var ac = new AudioContext();

var osc = ac.createOscillator();
osc.connect( ac.destination );

osc.type = 'sawtooth';

osc.frequency.value = 220;
osc.start( 0 );

window.setTimeout( function() {
    osc.frequency.value = 440;
}, 1000 );

window.setTimeout( function() {
    osc.stop( 0 );
}, 2000 );

I've examined the docs for the OscillatorNode object, and there's no mention of this behavior.

I've also scoured Google, and (surprisingly) I can't find any other mentions of this phenomenon.

What's going on? This doesn't seem like proper behavior. If I wanted the frequency to glide, I'd use the linearRampToValueAtTime() method. Setting the frequency directly to a specific value should just...do that.

Is this just a bug? I know this API is still in flux, but this seems pretty blatant to be a bug - this wouldn't pass the most cursory testing. But I also can't imagine that Google would implement it this way deliberately.

Most importantly: is there a workaround?

like image 771
greenie2600 Avatar asked Aug 27 '15 02:08

greenie2600


1 Answers

Pretty sure this is a bug.

I can't find anything in the spec that says direct assignment of value on an AudioParam should do any kind of interpolation.

It's possible that it's gone unnoticed because typically people probably modify the value using automation methods. Which brings me to your question of workarounds...

If you actually wanted an explicit delay, you can just do this (notice there's no setTimeout).

// change the value to 440Hz 1 second from now
osc.frequency.setValueAtTime( 440, ac.currentTime + 1 );

If you want to be able to change the frequency immediately (say, in response to a user action), you can just do this:

osc.frequency.setValueAtTime( 440, 0 );

Hope that helps.

By the way, you should consider filing an issue for this (https://code.google.com/p/chromium/issues/list).

like image 193
Kevin Ennis Avatar answered Sep 19 '22 08:09

Kevin Ennis