javascriptwebkitaudiocontextaudiocontext

Playing around with audioContext


Inspired by this SO answer, I have this code, and it works, but it pops and doesn't sound as smooth as it could.

$('.btn').each(initDraggable);
function initDraggable() {
	var param = {}
	param.drag = drag
	param.stop = stopper
	$(this).draggable(param)
}
var Variables = {}
Variables.Frequency = 0
function drag(myEvent,myUI) {
	var Frequency = myUI.position.left + 100
	var Duration = 5000
	if (Math.abs(Variables.Frequency-Frequency) > 25) {
		if (typeof(Variables.osc) === 'undefined') {
		} else {
			Variables.osc.stop(0)
		}
		Variables.Frequency = Frequency
		Oscillator(Frequency,Duration)
	}
}
function stopper() {
	Variables.osc.stop(0)
}


Variables.ctx = new(window.audioContext || window.webkitAudioContext)
function Oscillator(argFrequency,argDuration) {
	Variables.osc = Variables.ctx.createOscillator()
	Variables.osc.type = 0
	Variables.osc.connect(Variables.ctx.destination)
	Variables.osc.frequency.value = argFrequency
	Variables.osc.start(0)
	setTimeout(myTimeout,argDuration)
	function myTimeout() {
		Variables.osc.stop(0)
	}
}
<link rel="stylesheet" href="//cdn.jsdelivr.net/bootstrap/latest/css/bootstrap.css">
<link rel="stylesheet" href="//cdn.jsdelivr.net/jquery.ui/latest/jquery-ui.min.css">
<span class="btn btn-primary">Drag me</span>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<script src="//cdn.jsdelivr.net/bootstrap/latest/js/bootstrap.js"></script>
<script src="//cdn.jsdelivr.net/jquery.ui/latest/jquery-ui.min.js"></script>
<script src="//cdn.jsdelivr.net/jquery.ui.touch-punch/latest/jquery.ui.touch-punch.js"></script>

Q: Is there an easy way to get this to sound a little smoother?


Solution

  • There's no need to recreate the oscillator on drag, I think that's what causing the pops. But you can change the frequency value of a started oscillator, so you can achieve your result by creating the oscillator on drag start, stop it on stop, and simply change the frequency value on drag. Like this:

    $('.btn').each(initDraggable);
    
    function initDraggable() {
      var param = {}
      param.drag = drag
      param.stop = stopper
      param.start = startOsc
      $(this).draggable(param)
    }
    var Variables = {}
    Variables.Frequency = 0
    
    function drag(myEvent, myUI) {
      var Frequency = myUI.position.left + 100
      var Duration = 5000
      if (Math.abs(Variables.Frequency - Frequency) > 25) {
        //You could put some validation on creation, but since you're not creating it, it's not necessary here	
        /*if (typeof(Variables.osc) === 'undefined') {
    		} else {
    			Variables.osc.stop(0)
    		}*/
    
        Variables.Frequency = Frequency;
        //Oscillator(Frequency,Duration)
        Variables.osc.frequency.value = Frequency;
      }
    }
    
    function startOsc(myEvent, myUI) {
      var Frequency = myUI.position.left + 100
      Oscillator(Frequency) //Since it plays in continue you don't need duration
    }
    
    function stopper() {
      Variables.osc.stop(0)
    }
    
    
    Variables.ctx = new(window.AudioContext || window.webkitAudioContext)
    
    function Oscillator(argFrequency /*,argDuration*/ ) {
      Variables.osc = Variables.ctx.createOscillator()
      Variables.osc.type = 0
      Variables.osc.connect(Variables.ctx.destination)
      Variables.osc.frequency.value = argFrequency
      Variables.osc.start(0)
        /*setTimeout(myTimeout,argDuration)
    	function myTimeout() {
    		Variables.osc.stop(0)
    	}*/
    }
    <link rel="stylesheet" href="//cdn.jsdelivr.net/bootstrap/latest/css/bootstrap.css">
    <link rel="stylesheet" href="//cdn.jsdelivr.net/jquery.ui/latest/jquery-ui.min.css">
    <span class="btn btn-primary">Drag me</span>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
    <script src="//cdn.jsdelivr.net/bootstrap/latest/js/bootstrap.js"></script>
    <script src="//cdn.jsdelivr.net/jquery.ui/latest/jquery-ui.min.js"></script>
    <script src="//cdn.jsdelivr.net/jquery.ui.touch-punch/latest/jquery.ui.touch-punch.js"></script>