         }
         return curvePoints
     }
+    
+    func scheduleCADTimer(seconds: Double) {
+        if seconds == 0 {
+            startImmediately()
+        }else{
+            let delayRate = (seconds / cadTimerRate)
+            let frameDelay = Int(floor(delayRate))
+            cadDelayTimer = CADisplayLink(target: self, selector: #selector(startFadeFromCADTimer))
+            cadDelayTimer?.frameInterval = frameDelay
+            cadDelayTimer?.addToRunLoop(NSRunLoop.currentRunLoop(), forMode: NSRunLoopCommonModes)
+        }
+    }
+    
+    @objc func startFadeFromCADTimer() {
+        let millis = NSDate().timeIntervalSince1970*1000
+        print("startFadeFromCADTimer fired \(millis) - \(cadTimerIncrement) \(directionString)")
+        //runs twice, once when scheduled and again at next frame, so we have to skip the first one and run the second.
+        if cadTimerIncrement > 0 {
+            cadDelayTimer?.invalidate()
+            startImmediately()
+        }
+        cadTimerIncrement += 1
+    }
 }

        self.curvature = curvature
        self.duration = duration
        self.offset = offset
        stepCount = Int(floor(duration / controlRate))
        self.output = output
    }
    
    func scheduleFade(fireTime: Double) {
        //this schedules a fade to start after fireTime
        fadeScheduleTimer = NSTimer.scheduledTimerWithTimeInterval(
            fireTime + offset,
            target: self,
            selector: #selector(scheduleFadeTimer),
            userInfo: nil,
            repeats: false)
        //print("scheduled for \(fireTime) @ \(duration) seconds")
        output!.gain = initialVolume
    }
    @objc func scheduleFadeTimer(timer: NSTimer) {
        startImmediately()
    }
    
    public func start() { //starts the fade WITH the offset

    }
    public func startImmediately() { //skips the offset
        //this starts the recurring timer
        let millis = NSDate().timeIntervalSince1970*1000
        print("starting fade \(millis) \(directionString)")
        stepCounter = 0
        
        if cadUpdateTimer != nil{
            cadUpdateTimer?.invalidate()
        }
        if numberOfSteps == 0{ //if no steps to run, go ahead and set the volume early
            output!.gain = finalVolume
        }
        cadUpdateTimer = CADisplayLink(target: self, selector: #selector(updateFadeFromCADTimer))
        cadUpdateTimer?.addToRunLoop(NSRunLoop.currentRunLoop(), forMode: NSRunLoopCommonModes)
        }
    
    @objc func updateFadeFromCADTimer() {
        let direction: Double = (initialVolume > finalVolume ? 1.0 : -1.0)
        let millis = NSDate().timeIntervalSince1970*1000
        print("updatingFade fade \(millis) - \(stepCounter) \(directionString)")
        if numberOfSteps == 0{
            endFade()
        }else if stepCounter <= numberOfSteps {
            let controlAmount: Double = Double(stepCounter) / Double(numberOfSteps) //normalized 0-1 value
            var scaledControlAmount: Double = 0.0
            
            switch curveType {
