2

I've got a little chime maker going here. It generates several overtones at once, and uses variable gain on each overtone to produce a rich chime sound. I call a function to play a series of these in sequence. But if I rapidly press the button a few times, the sound output stops, as though it's running out of memory:

https://codepen.io/ophello/pen/OJVRMQe

function ding(freq) { var toneGen = new AudioContext() var duration = 15 var T = toneGen.currentTime var overtones = [1,2.76,5.4,8.93,13.34,18.64] overtones.forEach(function(overtone,i) { var osc = toneGen.createOscillator() osc.type = "sine" var freqVal = freq * overtone if (freqVal <= 22050) { osc.frequency.value = freq * overtone var envelope = toneGen.createGain() osc.connect(envelope) envelope.gain.setValueAtTime(0.1/Math.pow((i+1),5), T) envelope.gain.exponentialRampToValueAtTime(0.00001, T + duration) envelope.connect(toneGen.destination) osc.start(T) osc.stop(T + duration) } }) } var hzValues = [216, 288, 324, 405, 432, 648] $("#b1").mousedown(() => { hzValues.forEach((thisHz,i) => { setTimeout(() => { ding(thisHz) }, 100 * i); }) }) 

Why does this stop working after a few presses? Am I missing something critical here? I don't know where in the console to look for any problems with this. Is this a memory issue?

8
  • needs more developer.mozilla.org/en-US/docs/Web/API/AudioContext/close ; you only get so many active contexts to use at once, which could be a browser or os or hardware limit. "it will forcibly release any system audio resources that might prevent additional AudioContexts from being created and used" In other words, even though it's JS, you have to cleanup after yourself. Commented Feb 14, 2020 at 20:18
  • Then is there a way to achieve the result I want with fewer contexts? I'm not sure how to fix this. I already tell every oscillator to stop after a certain duration, isn't that the cleanup part? Commented Feb 14, 2020 at 20:20
  • you can destroy the ones that are not playing. you could also limit the count and round robin though an array of contexts if you need several active. Commented Feb 14, 2020 at 20:21
  • I'm not sure how to implement that. I tried using .close() but it halts all audio completely. Commented Feb 14, 2020 at 20:25
  • 1
    i can't break it permanently anymore if i add setTimeout(toneGen.close.bind(toneGen), 3500); after osc.stop(). Adjust as needed Commented Feb 14, 2020 at 20:29

1 Answer 1

1

Thanks to dandavis above, I got this working by adding a timeout function:

setTimeout(toneGen.close.bind(toneGen), duration*1000); 

Update: Improved by moving the audio context outside the main function!

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.