# Package buffers
'''
    Copyright (C) 2017 Bertram Fey

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
'''
from math import pi, sqrt

# title           : DelayLockedLoop.py
# description     : a simple implementation of a delay locked loop
# author          : Bertram Fey
# date            :
# version         :
# notes           :
# python_version  :
# ==============================================================================

"""
    A simple implementation of a Delay Locked Loop. It's used to reduce
    jitter (recording, playback, network latencies) from frame times.
    
    It's a straight forward implementation of the algorithm described
    in "Using a DLL to filter time" by Fons ADRIAENSEN (Alcatel Space).
"""

class DelayLockedLoop:
    def __init__(self, periodSize, expectedSampleRate):
        '''
            :type periodSize: number
            :type expectedSampleRate: number
        '''
        self.sampleRate = expectedSampleRate
        self.nper = periodSize
        self.tper = periodSize / expectedSampleRate
        
        self.n0 = 0
        self.n1 = self.nper
        
        self.e2 = self.tper
        self.t0 = 0
        self.t1 = 0
        
        bandwidth = 1
        
        omega = 2 * pi * bandwidth / expectedSampleRate
        
        self.paramB = omega * sqrt(2)
        self.paramC = omega * omega
        
        print(omega, self.paramB, self.paramC, self.e2)
        
    def updatePeriodTime(self, periodTimestampSeconds):
        '''
            :type periodTimestampSeconds :number
        '''
        if (0 == self.t0):
            self.t0 = periodTimestampSeconds
            self.t1 = self.t0 + self.e2
        else:
            e = periodTimestampSeconds - self.t1
            self.t0 = self.t1
            self.t1 = self.t1 + (self.paramB * e) + self.e2
            self.e2 = self.e2 + (self.paramC * e)
            
            self.n0 = self.n1
            self.n1 = self.n1 + self.nper
            
        return self.t0

    def getLastPeriodStartTimeSeconds(self):
        return self.t0
    
    def getLastPeriodEndTimeSeconds(self):
        return self.t1