MMitB - Panner

by Keith McMillen

HTML

<div class='controls'>
    <button class="btn play" disabled>loading...</button>
    <button class="btn stop" disabled>stop</button>
</div>
<div class='play-controls'>
    <label for='loop'>loop
        <input type='checkbox' name='loop' class="loop" />
    </label>
    <label for='mousepan'>mouse panner &lt;&lt; &#x1f42d; &gt;&gt;
        <input type='checkbox' name='mousepan' class="mousepan" />
    </label>
</div>
<div class='panning-controls'>
    <label>Panning <span class='panning-value'>0</span> 
        <input class="panning-slider" type="range" min="-1" max="1" step="0.1" value="0" disabled/>
    </label>
</div>

CSS

body {
    background-color: rgb(250, 250, 250);
}
button {
    display: inline-block;
    margin-bottom: 20px;
}
label {
    display: block;
    font-family: monospace;
    line-height: 20px;
    text-shadow: 1px 1px 3px #ccc;
}
input {
    display: inline-block;
    float: right;
    width: 45%;
}
span {
    display: inline-block;
    width: 75px;
    text-align: center;
    font-weight: bold;
    border: 1px solid #efefef;
    border-radius: 3px;
    background-color: white;
}
hr {
    border-color: rgba(200, 200, 200, 0.1);
}

JavaScript

// Mouse Control and / or two tracks/panners
var audioContext = new(window.AudioContext || window.webkitAudioContext)(),
    sampleURL = 'https://files.keithmcmillen.com/blog/mmitb/dinky-jam-2.mp3',
    sampleBuffer, sound, playButton = document.querySelector('.play'),
    stopButton = document.querySelector('.stop'),
    loop = false, mousepan = false,
    loopButton = document.querySelector('.loop'),
    mousePanButton = document.querySelector('.mousepan'),
    panningSlider = document.querySelector('.panning-slider'),
    panningValue = document.querySelector('.panning-value'),
    pannner = audioContext.createStereoPanner();

// load our sound
init();

function init() {
    loadSound(sampleURL);
}

// listen for changes to panning slider and update
panningSlider.oninput = function () {
    pannner.pan.value = panningSlider.value;
    panningValue.innerHTML = panningSlider.value;
};

playButton.onclick = function () {
    playSound();
};

stopButton.onclick = function () {
    stopSound();
};

loopButton.onclick = function (event) {
    loop = event.target.checked;
    panningSlider.disabled = false;
};

// mouse movement panning
document.onmousemove = mousePan;

mousePanButton.onclick = function (event) {
    mousepan = event.target.checked;
    if(mousepan){
        panningSlider.disabled = true;
        document.documentElement.style.cursor="ew-resize";
    } else {
        panningSlider.disabled = false;
        document.documentElement.style.cursor="default";
    }
};

// function to load sounds via AJAX
function loadSound(url) {
    // Use a CORS proxy to fetch the audio file
    var proxyUrl = 'https://cors-anywhere.herokuapp.com/';
    var requestUrl = proxyUrl + url;
    
var request = new XMLHttpRequest();
    request.open('GET', requestUrl, true);
    request.responseType = 'arraybuffer';

    request.onload = function () {
        audioContext.decodeAudioData(request.response, function (buffer) {
            sampleBuffer = buffer;
           ...