desandro / arpeggiator

Web audio arpeggiator
http://arpeggiator.desandro.com/
177 stars 16 forks source link

Audio skips after playing two simultaneous notes #1

Open stuartpb opened 8 years ago

stuartpb commented 8 years ago

Chrome OS Version 48.0.2564.116 Platform 7647.84.0 (Official Build) stable-channel veyron_minnie Firmware Google_Veyron_Minnie.6588.138.0

Not sure if this is a UA bug or not

desandro commented 8 years ago

Thanks for reporting this issue. Just so I understand: when the same note is played right after itself, the third note is not heard?

wbernoudy commented 8 years ago

I also noticed what I think is a similar issue on my system:

Windows 10 Google Chrome Version 48.0.2564.116

It seemed to randomly start skipping after about 10 seconds of playing, I couldn't find anything specific such as playing multiple notes that would trigger it. The audio starts skipping so fast that it's like it's buzzing. I reloaded the tab several times and that didn't help, though it would reset the effect (so it would work for just a little bit). Everything works fine on the same computer with Microsoft Edge.

stevengoldberg commented 8 years ago

I think the issue -- or if not this one, then another issue -- may be caused by the fact that you ramp the gain down on release, but never actually call stop() on your oscillatorNodes.

It takes awhile on my system, but as I hold down an arpeggio with the activity monitor open, I can watch the CPU usage gradually get higher and higher because the oscillators are not being destroyed.

wraybowling commented 8 years ago

It's not actually optimal for oscillators to be destroyed. It's more traditional to pick a fixed number of oscillators and recycle them.

https://www.youtube.com/watch?v=9ZvncyIYW40

Keep all the voices in an array [one,two,three,...,sixteen]

Choose one method of recycling:

  1. Pick the oldest voice
  2. Pick the voice with the highest note in the scale (Moog-style)
  3. Pick from an index that moves through the array linearly and loops around when it reaches polyMax

Now you might ask why this method is necessarily better. Most notably because of glissando/portamento. When you recycle your oscillator, you'll likely change it's pitch. When that happens, you can do it with a hard setValueAtTime(freq,0) or you can glide the pitch with an exponential ramp. (musical scales are exponential). That's maybe worth making a different discussion for entirely, but without recycling your oscillators, it'll be impossible to glide later down the road.

https://www.youtube.com/watch?v=wQZo5-JTfGc

The number of voices you'll need will multiply if you want to maintain overlapping notes with the sequencer. But starting with 100 voices will still be more performant than dynamically creating and destroying them.

final note: this way of thinking is not a general rule of all things web audio. When playing samples, they are automatically destroyed when the sound finishes playing. In that case, you actually are meant to keep creating new instances.