diff --git a/src/effects/PanEffect.js b/src/effects/PanEffect.js
index aeebb2c..a31890b 100644
--- a/src/effects/PanEffect.js
+++ b/src/effects/PanEffect.js
@@ -5,11 +5,12 @@
 */
 class PanEffect {
      /**
-     * @param {AudioContext} audioContext - a webAudio context
+     * @param {AudioEngine} audioEngine - the audio engine.
      * @constructor
      */
-    constructor (audioContext) {
-        this.audioContext = audioContext;
+    constructor (audioEngine) {
+        this.audioEngine = audioEngine;
+        this.audioContext = this.audioEngine.audioContext;
         this.value = 0;
 
         this.input = this.audioContext.createGain();
@@ -37,8 +38,11 @@ class PanEffect {
 
         // Use trig functions for equal-loudness panning
         // See e.g. https://docs.cycling74.com/max7/tutorials/13_panningchapter01
-        this.leftGain.gain.value = Math.cos(p * Math.PI / 2);
-        this.rightGain.gain.value = Math.sin(p * Math.PI / 2);
+        const leftVal = Math.cos(p * Math.PI / 2);
+        const rightVal = Math.sin(p * Math.PI / 2);
+
+        this.leftGain.gain.setTargetAtTime(leftVal, 0, this.audioEngine.ONE_THIRD_FRAME);
+        this.rightGain.gain.setTargetAtTime(rightVal, 0, this.audioEngine.ONE_THIRD_FRAME);
     }
 
     /**
diff --git a/src/index.js b/src/index.js
index 6dccf70..3cab5d8 100644
--- a/src/index.js
+++ b/src/index.js
@@ -28,7 +28,7 @@ class AudioPlayer {
 
         // Create the audio effects
         this.pitchEffect = new PitchEffect();
-        this.panEffect = new PanEffect(this.audioEngine.audioContext);
+        this.panEffect = new PanEffect(this.audioEngine);
 
         // Chain the audio effects together
         // effectsNode -> panEffect -> audioEngine.input
@@ -121,7 +121,8 @@ class AudioPlayer {
     clearEffects () {
         this.panEffect.set(0);
         this.pitchEffect.set(0, this.activeSoundPlayers);
-        this.effectsNode.gain.value = 1;
+        if (this.audioEngine === null) return;
+        this.effectsNode.gain.setTargetAtTime(1.0, 0, this.audioEngine.ONE_THIRD_FRAME);
     }
 
     /**
@@ -129,7 +130,8 @@ class AudioPlayer {
      * @param {number} value - the volume in range 0-100
      */
     setVolume (value) {
-        this.effectsNode.gain.value = value / 100;
+        if (this.audioEngine === null) return;
+        this.effectsNode.gain.setTargetAtTime(value / 100, 0, this.audioEngine.ONE_THIRD_FRAME);
     }
 }
 
@@ -164,6 +166,18 @@ class AudioEngine {
         };
     }
 
+    /**
+     * The duration in seconds of one third of one frame, at 30 frames per second.
+     * This is useful for setting web audio time constants. For example, in order for
+     * a gain to reach 95% of its target value in one frame, use this time constant.
+     * See:
+     * https://developer.mozilla.org/en-US/docs/Web/API/AudioParam/setTargetAtTime
+     * @const {number}
+     */
+    get ONE_THIRD_FRAME () {
+        return (1 / 30) / 3;
+    }
+
     /**
      * Decode a sound, decompressing it into audio samples.
      * Store a reference to it the sound in the audioBuffers dictionary, indexed by soundId