#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# generated by wxGlade 0.3.5.1 on Fri Jun 10 10:32:01 2005

from gnuradio import gr, gru, eng_notation, optfir
from gnuradio import audio
from gnuradio import usrp
from gnuradio import blks
from gnuradio import tv_rx
from gnuradio.eng_option import eng_option
from gnuradio.wxgui import slider, powermate
from gnuradio.wxgui import stdgui, fftsink
from optparse import OptionParser
import sys
import math
import wx

ID_EXIT = wx.NewId()
ID_SLIDER_1 = wx.NewId()
ID_SLIDER_2 = wx.NewId()
ID_RADIO_FREQ = wx.NewId()
ID_RADIO_VOL = wx.NewId()
ID_RADIO_STEREO = wx.NewId()
ID_GAUGE_1 = wx.NewId()
ID_SPINBUTTON_1 = wx.NewId()
ID_SPINBUTTON_2 = wx.NewId()

class MyFrame(wx.Frame):
    def __init__(self, *args, **kwds):
        # begin wxGlade: MyFrame.__init__
        kwds["style"] = wx.DEFAULT_FRAME_STYLE
        wx.Frame.__init__(self, *args, **kwds)
        
        # Menu Bar
        self.frame_1_menubar = wx.MenuBar()
        self.SetMenuBar(self.frame_1_menubar)
        wxglade_tmp_menu = wx.Menu()
        wxglade_tmp_menu.Append(ID_EXIT, "Exit", "Exit", wx.ITEM_NORMAL)
        self.frame_1_menubar.Append(wxglade_tmp_menu, "File")
        # Menu Bar end
        self.gauge_2 = wx.Gauge(self, -1, 300, style=wx.GA_VERTICAL)
        self.gauge_3 = wx.Gauge(self, -1, 300, style=wx.GA_VERTICAL)
        self.gauge_4 = wx.Gauge(self, -1, 300, style=wx.GA_VERTICAL)
        self.gauge_5 = wx.Gauge(self, -1, 300, style=wx.GA_VERTICAL)
        self.gauge_6 = wx.Gauge(self, -1, 300, style=wx.GA_VERTICAL)
        self.gauge_7 = wx.Gauge(self, -1, 300, style=wx.GA_VERTICAL)
        self.gauge_8 = wx.Gauge(self, -1, 300, style=wx.GA_VERTICAL)
        self.gauge_9 = wx.Gauge(self, -1, 300, style=wx.GA_VERTICAL)
        self.gauge_10 = wx.Gauge(self, -1, 300, style=wx.GA_VERTICAL)
        self.gauge_11 = wx.Gauge(self, -1, 300, style=wx.GA_VERTICAL)
        self.gauge_12 = wx.Gauge(self, -1, 300, style=wx.GA_VERTICAL)
        self.gauge_13 = wx.Gauge(self, -1, 300, style=wx.GA_VERTICAL)
        self.gauge_14 = wx.Gauge(self, -1, 300, style=wx.GA_VERTICAL)
        self.gauge_15 = wx.Gauge(self, -1, 300, style=wx.GA_VERTICAL)
        self.gauge_16 = wx.Gauge(self, -1, 300, style=wx.GA_VERTICAL)
        self.gauge_17 = wx.Gauge(self, -1, 300, style=wx.GA_VERTICAL)
        self.gauge_18 = wx.Gauge(self, -1, 300, style=wx.GA_VERTICAL)
        self.gauge_19 = wx.Gauge(self, -1, 300, style=wx.GA_VERTICAL)
        self.gauge_20 = wx.Gauge(self, -1, 300, style=wx.GA_VERTICAL)
        self.gauge_21 = wx.Gauge(self, -1, 300, style=wx.GA_VERTICAL)
        self.gauge_22 = wx.Gauge(self, -1, 300, style=wx.GA_VERTICAL)
        self.gauge_23 = wx.Gauge(self, -1, 300, style=wx.GA_VERTICAL)
        self.gauge_24 = wx.Gauge(self, -1, 300, style=wx.GA_VERTICAL)
        self.gauge_25 = wx.Gauge(self, -1, 300, style=wx.GA_VERTICAL)
        self.gauge_26 = wx.Gauge(self, -1, 300, style=wx.GA_VERTICAL)
        self.gauge_27 = wx.Gauge(self, -1, 300, style=wx.GA_VERTICAL)
        self.gauge_28 = wx.Gauge(self, -1, 300, style=wx.GA_VERTICAL)
        self.gauge_29 = wx.Gauge(self, -1, 300, style=wx.GA_VERTICAL)
        self.gauge_30 = wx.Gauge(self, -1, 300, style=wx.GA_VERTICAL)
        self.gauge_31 = wx.Gauge(self, -1, 300, style=wx.GA_VERTICAL)
        self.gauge_32 = wx.Gauge(self, -1, 300, style=wx.GA_VERTICAL)
        self.gauge_33 = wx.Gauge(self, -1, 300, style=wx.GA_VERTICAL)
        self.label_2 = wx.StaticText(self, -1, "Frequency")
        self.bitmap_1 = wx.StaticBitmap(self, -1, wx.Bitmap("/usr/src/radio/wx/numerals/fancydigitalgreen/1.bmp", wx.BITMAP_TYPE_ANY))
        self.bitmap_2 = wx.StaticBitmap(self, -1, wx.Bitmap("/usr/src/radio/wx/numerals/fancydigitalgreen/0.bmp", wx.BITMAP_TYPE_ANY))
        self.bitmap_3 = wx.StaticBitmap(self, -1, wx.Bitmap("/usr/src/radio/wx/numerals/fancydigitalgreen/2.bmp", wx.BITMAP_TYPE_ANY))
        self.bitmap_4 = wx.StaticBitmap(self, -1, wx.Bitmap("/usr/src/radio/wx/numerals/fancydigitalgreen/7.bmp", wx.BITMAP_TYPE_ANY))
        self.radio_btn_1 = wx.RadioButton(self, ID_RADIO_FREQ, "frequency", style=wx.RB_GROUP)
        self.spin_button_1 = wx.SpinButton(self, ID_SPINBUTTON_1 )
        self.label_3 = wx.StaticText(self, -1, "Volume")
        self.gauge_1 = wx.Gauge(self, -1, 200)
        self.radio_btn_2 = wx.RadioButton(self, ID_RADIO_VOL, "volume")
        self.spin_button_2 = wx.SpinButton(self, ID_SPINBUTTON_2 )
        self.label_1 = wx.StaticText(self, -1, "         RF Gain      ")
        self.slider_1 = wx.Slider(self, ID_SLIDER_1, 0, 0, 115)
        self.label_4 = wx.StaticText(self, -1, "        Stereo Adjust")
        self.slider_2 = wx.Slider(self, ID_SLIDER_2, 0, 0, 260)
        self.radio_btn_3 = wx.RadioButton(self, ID_RADIO_STEREO, "Stereo")

        # end wxGlade

	# wxpython gui events
        wx.EVT_MENU(self, ID_EXIT, self.MenuExit)
        wx.EVT_SLIDER(self, ID_SLIDER_1, self.set_gain)
	wx.EVT_SLIDER(self, ID_SLIDER_2, self.set_adv)
        wx.EVT_RADIOBUTTON(self, ID_RADIO_FREQ, self.radio_button)
        wx.EVT_RADIOBUTTON(self, ID_RADIO_VOL, self.radio_button)
	wx.EVT_RADIOBUTTON(self, ID_RADIO_STEREO, self.radio_button)
	wx.EVT_SPIN(self, ID_SPINBUTTON_1, self.spin_button)
	wx.EVT_SPIN_UP(self, ID_SPINBUTTON_2, self.spin_up)
	wx.EVT_SPIN_DOWN(self, ID_SPINBUTTON_2, self.spin_down)

	# load pretty green numerals
        self.n0 = wx.Bitmap("/usr/src/radio/wx/numerals/fancydigitalgreen/0.bmp", wx.BITMAP_TYPE_ANY)
        self.n1 = wx.Bitmap("/usr/src/radio/wx/numerals/fancydigitalgreen/1.bmp", wx.BITMAP_TYPE_ANY)
        self.n2 = wx.Bitmap("/usr/src/radio/wx/numerals/fancydigitalgreen/2.bmp", wx.BITMAP_TYPE_ANY)
        self.n3 = wx.Bitmap("/usr/src/radio/wx/numerals/fancydigitalgreen/3.bmp", wx.BITMAP_TYPE_ANY)
        self.n4 = wx.Bitmap("/usr/src/radio/wx/numerals/fancydigitalgreen/4.bmp", wx.BITMAP_TYPE_ANY)
        self.n5 = wx.Bitmap("/usr/src/radio/wx/numerals/fancydigitalgreen/5.bmp", wx.BITMAP_TYPE_ANY)
        self.n6 = wx.Bitmap("/usr/src/radio/wx/numerals/fancydigitalgreen/6.bmp", wx.BITMAP_TYPE_ANY)
        self.n7 = wx.Bitmap("/usr/src/radio/wx/numerals/fancydigitalgreen/7.bmp", wx.BITMAP_TYPE_ANY)
        self.n8 = wx.Bitmap("/usr/src/radio/wx/numerals/fancydigitalgreen/8.bmp", wx.BITMAP_TYPE_ANY)
        self.n9 = wx.Bitmap("/usr/src/radio/wx/numerals/fancydigitalgreen/9.bmp", wx.BITMAP_TYPE_ANY)

# radio from tvrx_wfm_rcv_gui_pm.py
        self.fg = gr.flow_graph()
        self.vol = .1
        self.state = "FREQ"

        adc_rate = 64e6
        usrp_decim = 250
        self.quad_rate = adc_rate / usrp_decim           # 256000
        audio_decimation = 8
        audio_rate = self.quad_rate / audio_decimation  # 32 kHz

        # usrp is data source
        src = usrp.source_c (0, usrp_decim)
        self.src = src

        dboards = (src.daughterboard_id(0),src.daughterboard_id(1))
        print dboards
        if dboards[0]==3:
            if dboards[1]==3:
                print "Which side?"
                sys.exit(0)
            else:
                which_side = 0
                which_type = 3
        elif dboards[1]==3:
            which_side = 1
            which_type = 3
        elif dboards[0]==1:
            if dboards[1]==1:
                print "Which side?"
                sys.exit(0)
            else:
                which_side = 0
                which_type = 1
        elif dboards[1]==1:
            which_side = 1
            which_type = 1
        else:
            print "No usable daughterboard found"
            sys.exit(0)

        if which_type == 3:
            dboard = tv_rx.tv_rx (src, which_side)
            self.dboard = dboard

        if which_side == 0:
            src.set_mux(gru.hexint(0xf0f0f0f0))
        else:
            src.set_mux(gru.hexint(0xf0f0f0f2))

        # set up frontend

        self.set_freq(102.7)

# from Achilleas stereo FM
# Demodulation of the MUX signal-->input: complex; output: float
        peak_composite = 1.0
        fm_demod_gain = 1.0 / (2 * math.pi * 75e3 / peak_composite / self.quad_rate)
        print "FM demodulator gain =", fm_demod_gain
        volume = 1.0
        fm_demod = gr.quadrature_demod_cf (volume*fm_demod_gain)
# L+R processing: LPF + decimation
        # compute FIR filter taps for audio filter
        width = 1.5e3
        # the 0.5 gain compensates for (L+R)+(L-R)=2L
        audio_coefs = gr.firdes.low_pass (0.5, self.quad_rate, 15e3, width, gr.firdes.WIN_HAMMING)
        audio_filter_lpr = gr.fir_filter_fff (audio_decimation, audio_coefs)
# Pilot extraction: BPF, squarer
        # compute FIR filter taps for pilot filter
        # FIX ME: we need a power-meter/AGC to adjust the pilot amplitude
        Ap=math.sqrt(0.00012) * fm_demod_gain / (2200.0/32768.0) # this seems to work fine, but why?
        print "Pilot power = ", Ap*Ap/2
        p_width = 1e3
        pilot_coefs = gr.firdes.band_pass (2/Ap, self.quad_rate, 19e3-p_width/2, 19e3+p_width/2, p_width, gr.firdes.WIN_HAMMING)
        f0=19e3
        d1 = find_arg(pilot_coefs,self.quad_rate,f0)
        print "Delay of Pilot BPF @", f0, " = ", d1
        pilot_filter = gr.fir_filter_fff(1, pilot_coefs)
        # square the pilot to get the 38KHz local carrier (should result in a unit amplitude carrier @ 38KHz --- effect of DC term is removed later)
        square = gr.multiply_ff()
# L-R processing: BPF, L-R demod, LPF, decimation
        # compute FIR filter taps for bandpass L-R filter
        width = 1e3
        band_coefs = gr.firdes.band_pass (1.0,self.quad_rate, 23e3, 53e3, width, gr.firdes.WIN_HAMMING)
        f0 = 38e3+0e3
        d2 = find_arg(band_coefs,self.quad_rate,f0)
        print "Delay of BPF @", f0 , " = ", d2
        band_filter = gr.fir_filter_fff (1, band_coefs)

        # calc total advance required
        # adv = math.fmod(d1 - d2 , 1/38e3)
        self.adv = 7e-6
        print "Required Advance  = ", self.adv
        # design the interpolation filter
        self.degree = 1
        a_coefs = build_advance_interpolator(self.quad_rate,self.adv,self.degree,False,sinc)
        print a_coefs
        self.a_filter = gr.fir_filter_fff (1, a_coefs)
        # demodulation of L-R
        demod_lmr = gr.multiply_ff()
        audio_filter_lmr = gr.fir_filter_fff (audio_decimation, audio_coefs)


# DEMUX of L and R channels and deemphasis
        Left = gr.add_ff()
        Right = gr.sub_ff()

        TAU  = 75e-6  # 75us in US, 50us in EUR
        fftaps = [ 1 - math.exp(-1/TAU/audio_rate), 0]
        fbtaps= [ 0 , math.exp(-1/TAU/audio_rate) ]
        deemphl = gr.iir_filter_ffd(fftaps,fbtaps)
        deemphr = gr.iir_filter_ffd(fftaps,fbtaps)

        self.volume_control_l = gr.multiply_const_ff(self.vol)
        self.volume_control_r = gr.multiply_const_ff(self.vol)
	combine = gr.add_ff()

        audio_sink = audio.sink (int (audio_rate))

# Wire it
	self.fg.connect (src, fm_demod) # head
        self.fg.connect (fm_demod, audio_filter_lpr)

        self.fg.connect (fm_demod, pilot_filter)
        self.fg.connect (pilot_filter,(square,0))
        self.fg.connect (fm_demod,band_filter)
        self.fg.connect (pilot_filter,(square,1))
        self.fg.connect (band_filter,(demod_lmr,0))
        self.fg.connect (square,self.a_filter)
        self.fg.connect (self.a_filter,(demod_lmr,1))
        self.fg.connect (demod_lmr, audio_filter_lmr)

        self.fg.connect (audio_filter_lpr,(Left,0))
        self.fg.connect (audio_filter_lmr,(Left,1))
        self.fg.connect (audio_filter_lpr,(Right,0))
        self.fg.connect (audio_filter_lmr,(Right,1))

        self.fg.connect (Left,deemphl,self.volume_control_l,(audio_sink,0))
        self.fg.connect (Right,deemphr,self.volume_control_r,(audio_sink,1))
	self.fg.connect (Left,(combine,0))
	self.fg.connect (Right,(combine,1))

        self.slider_1.SetValue(55)
        self.set_gain(ID_SLIDER_1)
        self.gauge_1.SetValue(int(self.vol*200))


	fft_size = 64
	scale4display = gr.multiply_const_ff(2)
	hilbert = gr.hilbert_fc(197)
        s2v = gr.stream_to_vector (gr.sizeof_gr_complex, fft_size)
        fft = gr.fft_vcc (fft_size,True,False) # size, fwd, window
        v2s = gr.vector_to_stream(gr.sizeof_gr_complex, fft_size)
        s2ss = gr.stream_to_streams (gr.sizeof_gr_complex, fft_size)

        self.fg.connect(combine,scale4display,hilbert,s2v,fft,v2s,s2ss)
        alpha = .01
        self.L0 = gr.signal_level_cc(1,alpha)
        self.L1 = gr.signal_level_cc(1,alpha)
        self.L2 = gr.signal_level_cc(1,alpha)
        self.L3 = gr.signal_level_cc(1,alpha)
        self.L4 = gr.signal_level_cc(1,alpha)
        self.L5 = gr.signal_level_cc(1,alpha)
        self.L6 = gr.signal_level_cc(1,alpha)
        self.L7 = gr.signal_level_cc(1,alpha)
        self.L8 = gr.signal_level_cc(1,alpha)
        self.L9 = gr.signal_level_cc(1,alpha)
        self.L10 = gr.signal_level_cc(1,alpha)
        self.L11 = gr.signal_level_cc(1,alpha)
        self.L12 = gr.signal_level_cc(1,alpha)
        self.L13 = gr.signal_level_cc(1,alpha)
        self.L14 = gr.signal_level_cc(1,alpha)
        self.L15 = gr.signal_level_cc(1,alpha)
        self.L16 = gr.signal_level_cc(1,alpha)
        self.L17 = gr.signal_level_cc(1,alpha)
        self.L18 = gr.signal_level_cc(1,alpha)
        self.L19 = gr.signal_level_cc(1,alpha)
        self.L20 = gr.signal_level_cc(1,alpha)
        self.L21 = gr.signal_level_cc(1,alpha)
        self.L22 = gr.signal_level_cc(1,alpha)
        self.L23 = gr.signal_level_cc(1,alpha)
        self.L24 = gr.signal_level_cc(1,alpha)
        self.L25 = gr.signal_level_cc(1,alpha)
        self.L26 = gr.signal_level_cc(1,alpha)
        self.L27 = gr.signal_level_cc(1,alpha)
        self.L28 = gr.signal_level_cc(1,alpha)
        self.L29 = gr.signal_level_cc(1,alpha)
        self.L30 = gr.signal_level_cc(1,alpha)
        self.L31 = gr.signal_level_cc(1,alpha)


        sink0 = gr.null_sink(gr.sizeof_gr_complex)
        sink1 = gr.null_sink(gr.sizeof_gr_complex)
        sink2 = gr.null_sink(gr.sizeof_gr_complex)
        sink3 = gr.null_sink(gr.sizeof_gr_complex)
        sink4 = gr.null_sink(gr.sizeof_gr_complex)
        sink5 = gr.null_sink(gr.sizeof_gr_complex)
        sink6 = gr.null_sink(gr.sizeof_gr_complex)
        sink7 = gr.null_sink(gr.sizeof_gr_complex)
        sink8 = gr.null_sink(gr.sizeof_gr_complex)
        sink9 = gr.null_sink(gr.sizeof_gr_complex)
        sink10 = gr.null_sink(gr.sizeof_gr_complex)
        sink11 = gr.null_sink(gr.sizeof_gr_complex)
        sink12 = gr.null_sink(gr.sizeof_gr_complex)
        sink13 = gr.null_sink(gr.sizeof_gr_complex)
        sink14 = gr.null_sink(gr.sizeof_gr_complex)
        sink15 = gr.null_sink(gr.sizeof_gr_complex)
        sink16 = gr.null_sink(gr.sizeof_gr_complex)
        sink17 = gr.null_sink(gr.sizeof_gr_complex)
        sink18 = gr.null_sink(gr.sizeof_gr_complex)
        sink19 = gr.null_sink(gr.sizeof_gr_complex)
        sink20 = gr.null_sink(gr.sizeof_gr_complex)
        sink21 = gr.null_sink(gr.sizeof_gr_complex)
        sink22 = gr.null_sink(gr.sizeof_gr_complex)
        sink23 = gr.null_sink(gr.sizeof_gr_complex)
        sink24 = gr.null_sink(gr.sizeof_gr_complex)
        sink25 = gr.null_sink(gr.sizeof_gr_complex)
        sink26 = gr.null_sink(gr.sizeof_gr_complex)
        sink27 = gr.null_sink(gr.sizeof_gr_complex)
        sink28 = gr.null_sink(gr.sizeof_gr_complex)
        sink29 = gr.null_sink(gr.sizeof_gr_complex)
        sink30 = gr.null_sink(gr.sizeof_gr_complex)
        sink31 = gr.null_sink(gr.sizeof_gr_complex)
        sink32 = gr.null_sink(gr.sizeof_gr_complex)
        sink33 = gr.null_sink(gr.sizeof_gr_complex)
        sink34 = gr.null_sink(gr.sizeof_gr_complex)
        sink35 = gr.null_sink(gr.sizeof_gr_complex)
        sink36 = gr.null_sink(gr.sizeof_gr_complex)
        sink37 = gr.null_sink(gr.sizeof_gr_complex)
        sink38 = gr.null_sink(gr.sizeof_gr_complex)
        sink39 = gr.null_sink(gr.sizeof_gr_complex)
        sink40 = gr.null_sink(gr.sizeof_gr_complex)
        sink41 = gr.null_sink(gr.sizeof_gr_complex)
        sink42 = gr.null_sink(gr.sizeof_gr_complex)
        sink43 = gr.null_sink(gr.sizeof_gr_complex)
        sink44 = gr.null_sink(gr.sizeof_gr_complex)
        sink45 = gr.null_sink(gr.sizeof_gr_complex)
        sink46 = gr.null_sink(gr.sizeof_gr_complex)
        sink47 = gr.null_sink(gr.sizeof_gr_complex)
        sink48 = gr.null_sink(gr.sizeof_gr_complex)
        sink49 = gr.null_sink(gr.sizeof_gr_complex)
        sink50 = gr.null_sink(gr.sizeof_gr_complex)
        sink51 = gr.null_sink(gr.sizeof_gr_complex)
        sink52 = gr.null_sink(gr.sizeof_gr_complex)
        sink53 = gr.null_sink(gr.sizeof_gr_complex)
        sink54 = gr.null_sink(gr.sizeof_gr_complex)
        sink55 = gr.null_sink(gr.sizeof_gr_complex)
        sink56 = gr.null_sink(gr.sizeof_gr_complex)
        sink57 = gr.null_sink(gr.sizeof_gr_complex)
        sink58 = gr.null_sink(gr.sizeof_gr_complex)
        sink59 = gr.null_sink(gr.sizeof_gr_complex)
        sink60 = gr.null_sink(gr.sizeof_gr_complex)
        sink61 = gr.null_sink(gr.sizeof_gr_complex)
        sink62 = gr.null_sink(gr.sizeof_gr_complex)
        sink63 = gr.null_sink(gr.sizeof_gr_complex)



        self.fg.connect((s2ss,0),sink0)
        self.fg.connect((s2ss,1),self.L0,sink1)
        self.fg.connect((s2ss,2),self.L1,sink2)
        self.fg.connect((s2ss,3),self.L2,sink3)
        self.fg.connect((s2ss,4),self.L3,sink4)
        self.fg.connect((s2ss,5),self.L4,sink5)
        self.fg.connect((s2ss,6),self.L5,sink6)
        self.fg.connect((s2ss,7),self.L6,sink7)
        self.fg.connect((s2ss,8),self.L7,sink8)
        self.fg.connect((s2ss,9),self.L8,sink9)
        self.fg.connect((s2ss,10),self.L9,sink10)
        self.fg.connect((s2ss,11),self.L10,sink11)
        self.fg.connect((s2ss,12),self.L11,sink12)
        self.fg.connect((s2ss,13),self.L12,sink13)
        self.fg.connect((s2ss,14),self.L13,sink14)
        self.fg.connect((s2ss,15),self.L14,sink15)
        self.fg.connect((s2ss,16),self.L15,sink16)
        self.fg.connect((s2ss,17),self.L16,sink17)
        self.fg.connect((s2ss,18),self.L17,sink18)
        self.fg.connect((s2ss,19),self.L18,sink19)
        self.fg.connect((s2ss,20),self.L19,sink20)
        self.fg.connect((s2ss,21),self.L20,sink21)
        self.fg.connect((s2ss,22),self.L21,sink22)
        self.fg.connect((s2ss,23),self.L22,sink23)
        self.fg.connect((s2ss,24),self.L23,sink24)
        self.fg.connect((s2ss,25),self.L24,sink25)
        self.fg.connect((s2ss,26),self.L25,sink26)
        self.fg.connect((s2ss,27),self.L26,sink27)
        self.fg.connect((s2ss,28),self.L27,sink28)
        self.fg.connect((s2ss,29),self.L28,sink29)
        self.fg.connect((s2ss,30),self.L29,sink30)
        self.fg.connect((s2ss,31),self.L30,sink31)
	self.fg.connect((s2ss,32),self.L31,sink32)
        self.fg.connect((s2ss,33),sink33)
        self.fg.connect((s2ss,34),sink34)
        self.fg.connect((s2ss,35),sink35)
        self.fg.connect((s2ss,36),sink36)
        self.fg.connect((s2ss,37),sink37)
        self.fg.connect((s2ss,38),sink38)
        self.fg.connect((s2ss,39),sink39)
        self.fg.connect((s2ss,40),sink40)
        self.fg.connect((s2ss,41),sink41)
        self.fg.connect((s2ss,42),sink42)
        self.fg.connect((s2ss,43),sink43)
        self.fg.connect((s2ss,44),sink44)
        self.fg.connect((s2ss,45),sink45)
        self.fg.connect((s2ss,46),sink46)
        self.fg.connect((s2ss,47),sink47)
        self.fg.connect((s2ss,48),sink48)
        self.fg.connect((s2ss,49),sink49)
        self.fg.connect((s2ss,50),sink50)
        self.fg.connect((s2ss,51),sink51)
        self.fg.connect((s2ss,52),sink52)
        self.fg.connect((s2ss,53),sink53)
        self.fg.connect((s2ss,54),sink54)
        self.fg.connect((s2ss,55),sink55)
        self.fg.connect((s2ss,56),sink56)
        self.fg.connect((s2ss,57),sink57)
        self.fg.connect((s2ss,58),sink58)
        self.fg.connect((s2ss,59),sink59)
        self.fg.connect((s2ss,60),sink60)
        self.fg.connect((s2ss,61),sink61)
        self.fg.connect((s2ss,62),sink62)
        self.fg.connect((s2ss,63),sink63)




	# time for updating gauges every 30 mSec
        self.timer = UpdateTimer(self, 30)

	POWERMATE = True
        try:
            self.knob = powermate.powermate(self)
            self.rot = 0
            powermate.EVT_POWERMATE_ROTATE (self, self.on_rotate)
            powermate.EVT_POWERMATE_BUTTON (self, self.on_button)
        except:
            print "No Powermate or Contour Knob found"
	    POWERMATE = False

        self.brightness = 128
        self.pulse_speed = 0
        if POWERMATE: self.knob.set_led_state(self.brightness, self.pulse_speed)

        self.__set_properties()
        self.__do_layout()

        self.fg.start()


    def __set_properties(self):
        # begin wxGlade: MyFrame.__set_properties
        self.SetTitle("GNU Radio Rocks !")
        self.gauge_2.SetSize((12, 150))
        self.gauge_2.SetBackgroundColour(wx.Colour(0, 255, 0))
        self.gauge_3.SetSize((12, 150))
        self.gauge_3.SetBackgroundColour(wx.Colour(0, 255, 0))
        self.gauge_4.SetSize((12, 150))
        self.gauge_4.SetBackgroundColour(wx.Colour(0, 255, 0))
        self.gauge_5.SetSize((12, 150))
        self.gauge_5.SetBackgroundColour(wx.Colour(0, 255, 0))
        self.gauge_6.SetSize((12, 150))
        self.gauge_6.SetBackgroundColour(wx.Colour(0, 255, 0))
        self.gauge_7.SetSize((12, 150))
        self.gauge_7.SetBackgroundColour(wx.Colour(0, 255, 0))
        self.gauge_8.SetSize((12, 150))
        self.gauge_8.SetBackgroundColour(wx.Colour(0, 255, 0))
        self.gauge_9.SetSize((12, 150))
        self.gauge_9.SetBackgroundColour(wx.Colour(0, 255, 0))
        self.gauge_10.SetSize((12, 150))
        self.gauge_10.SetBackgroundColour(wx.Colour(0, 255, 0))
        self.gauge_11.SetSize((12, 150))
        self.gauge_11.SetBackgroundColour(wx.Colour(0, 255, 0))
        self.gauge_12.SetSize((12, 150))
        self.gauge_12.SetBackgroundColour(wx.Colour(0, 255, 0))
        self.gauge_13.SetSize((12, 150))
        self.gauge_13.SetBackgroundColour(wx.Colour(0, 255, 0))
        self.gauge_14.SetSize((12, 150))
        self.gauge_14.SetBackgroundColour(wx.Colour(0, 255, 0))
        self.gauge_15.SetSize((12, 150))
        self.gauge_15.SetBackgroundColour(wx.Colour(0, 255, 0))
        self.gauge_16.SetSize((12, 150))
        self.gauge_16.SetBackgroundColour(wx.Colour(0, 255, 0))
        self.gauge_17.SetSize((12, 150))
        self.gauge_17.SetBackgroundColour(wx.Colour(0, 255, 0))
        self.gauge_18.SetSize((12, 150))
        self.gauge_18.SetBackgroundColour(wx.Colour(0, 255, 0))
        self.gauge_19.SetSize((12, 150))
        self.gauge_19.SetBackgroundColour(wx.Colour(0, 255, 0))
        self.gauge_20.SetSize((12, 150))
        self.gauge_20.SetBackgroundColour(wx.Colour(0, 255, 0))
        self.gauge_21.SetSize((12, 150))
        self.gauge_21.SetBackgroundColour(wx.Colour(0, 255, 0))
        self.gauge_22.SetSize((12, 150))
        self.gauge_22.SetBackgroundColour(wx.Colour(0, 255, 0))
        self.gauge_23.SetSize((12, 150))
        self.gauge_23.SetBackgroundColour(wx.Colour(0, 255, 0))
        self.gauge_24.SetSize((12, 150))
        self.gauge_24.SetBackgroundColour(wx.Colour(0, 255, 0))
        self.gauge_25.SetSize((12, 150))
        self.gauge_25.SetBackgroundColour(wx.Colour(0, 255, 0))
        self.gauge_26.SetSize((12, 150))
        self.gauge_26.SetBackgroundColour(wx.Colour(0, 255, 0))
        self.gauge_27.SetSize((12, 150))
        self.gauge_27.SetBackgroundColour(wx.Colour(0, 255, 0))
        self.gauge_28.SetSize((12, 150))
        self.gauge_28.SetBackgroundColour(wx.Colour(0, 255, 0))
        self.gauge_29.SetSize((12, 150))
        self.gauge_29.SetBackgroundColour(wx.Colour(0, 255, 0))
        self.gauge_30.SetSize((12, 150))
        self.gauge_30.SetBackgroundColour(wx.Colour(0, 255, 0))
        self.gauge_31.SetSize((12, 150))
        self.gauge_31.SetBackgroundColour(wx.Colour(0, 255, 0))
        self.gauge_32.SetSize((12, 150))
        self.gauge_32.SetBackgroundColour(wx.Colour(0, 255, 0))
        self.gauge_33.SetSize((12, 150))
        self.gauge_33.SetBackgroundColour(wx.Colour(0, 255, 0))
        self.gauge_1.SetBackgroundColour(wx.Colour(0, 255, 0))
        self.gauge_1.SetForegroundColour(wx.Colour(0, 255, 0))
        self.label_1.SetSize((157, 25))
        self.slider_1.SetSize((200, 60))
        self.label_4.SetSize((157, 25))
        self.slider_2.SetSize((200, 60))
        # end wxGlade
	self.spin_button_1.SetRange(881,1081)
	self.spin_button_1.SetValue(1027)
	self.spin_button_2.SetValue(30)
	self.slider_2.SetValue(self.adv*1e7)

    def __do_layout(self):
        # begin wxGlade: MyFrame.__do_layout
        grid_sizer_1 = wx.FlexGridSizer(4, 1, 0, 0)
        sizer_2 = wx.BoxSizer(wx.HORIZONTAL)
        sizer_1 = wx.BoxSizer(wx.HORIZONTAL)
        grid_sizer_2 = wx.GridSizer(2, 4, 0, 0)
        sizer_3 = wx.BoxSizer(wx.HORIZONTAL)
        grid_sizer_3 = wx.FlexGridSizer(1, 32, 0, 0)
        grid_sizer_3.Add(self.gauge_2, 0, wx.FIXED_MINSIZE, 0)
        grid_sizer_3.Add(self.gauge_3, 0, wx.FIXED_MINSIZE, 0)
        grid_sizer_3.Add(self.gauge_4, 0, wx.FIXED_MINSIZE, 0)
        grid_sizer_3.Add(self.gauge_5, 0, wx.FIXED_MINSIZE, 0)
        grid_sizer_3.Add(self.gauge_6, 0, wx.FIXED_MINSIZE, 0)
        grid_sizer_3.Add(self.gauge_7, 0, wx.FIXED_MINSIZE, 0)
        grid_sizer_3.Add(self.gauge_8, 0, wx.FIXED_MINSIZE, 0)
        grid_sizer_3.Add(self.gauge_9, 0, wx.FIXED_MINSIZE, 0)
        grid_sizer_3.Add(self.gauge_10, 0, wx.FIXED_MINSIZE, 0)
        grid_sizer_3.Add(self.gauge_11, 0, wx.FIXED_MINSIZE, 0)
        grid_sizer_3.Add(self.gauge_12, 0, wx.FIXED_MINSIZE, 0)
        grid_sizer_3.Add(self.gauge_13, 0, wx.FIXED_MINSIZE, 0)
        grid_sizer_3.Add(self.gauge_14, 0, wx.FIXED_MINSIZE, 0)
        grid_sizer_3.Add(self.gauge_15, 0, wx.FIXED_MINSIZE, 0)
        grid_sizer_3.Add(self.gauge_16, 0, wx.FIXED_MINSIZE, 0)
        grid_sizer_3.Add(self.gauge_17, 0, wx.FIXED_MINSIZE, 0)
        grid_sizer_3.Add(self.gauge_18, 0, wx.FIXED_MINSIZE, 0)
        grid_sizer_3.Add(self.gauge_19, 0, wx.FIXED_MINSIZE, 0)
        grid_sizer_3.Add(self.gauge_20, 0, wx.FIXED_MINSIZE, 0)
        grid_sizer_3.Add(self.gauge_21, 0, wx.FIXED_MINSIZE, 0)
        grid_sizer_3.Add(self.gauge_22, 0, wx.FIXED_MINSIZE, 0)
        grid_sizer_3.Add(self.gauge_23, 0, wx.FIXED_MINSIZE, 0)
        grid_sizer_3.Add(self.gauge_24, 0, wx.FIXED_MINSIZE, 0)
        grid_sizer_3.Add(self.gauge_25, 0, wx.FIXED_MINSIZE, 0)
        grid_sizer_3.Add(self.gauge_26, 0, wx.FIXED_MINSIZE, 0)
        grid_sizer_3.Add(self.gauge_27, 0, wx.FIXED_MINSIZE, 0)
        grid_sizer_3.Add(self.gauge_28, 0, wx.FIXED_MINSIZE, 0)
        grid_sizer_3.Add(self.gauge_29, 0, wx.FIXED_MINSIZE, 0)
        grid_sizer_3.Add(self.gauge_30, 0, wx.FIXED_MINSIZE, 0)
        grid_sizer_3.Add(self.gauge_31, 0, wx.FIXED_MINSIZE, 0)
        grid_sizer_3.Add(self.gauge_32, 0, wx.FIXED_MINSIZE, 0)
        grid_sizer_3.Add(self.gauge_33, 0, wx.FIXED_MINSIZE, 0)
        grid_sizer_1.Add(grid_sizer_3, 1, wx.EXPAND, 0)
        grid_sizer_2.Add(self.label_2, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL|wx.FIXED_MINSIZE, 0)
        sizer_3.Add(self.bitmap_1, 0, wx.ALIGN_CENTER_VERTICAL|wx.FIXED_MINSIZE, 0)
        sizer_3.Add(self.bitmap_2, 0, wx.ALIGN_CENTER_VERTICAL|wx.FIXED_MINSIZE, 0)
        sizer_3.Add(self.bitmap_3, 0, wx.ALIGN_CENTER_VERTICAL|wx.FIXED_MINSIZE, 0)
        sizer_3.Add(self.bitmap_4, 0, wx.ALIGN_CENTER_VERTICAL|wx.FIXED_MINSIZE, 0)
        grid_sizer_2.Add(sizer_3, 1, wx.EXPAND, 0)
        grid_sizer_2.Add(self.radio_btn_1, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL|wx.FIXED_MINSIZE, 0)
        grid_sizer_2.Add(self.spin_button_1, 0, wx.ALIGN_CENTER_VERTICAL|wx.FIXED_MINSIZE, 0)
        grid_sizer_2.Add(self.label_3, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL|wx.FIXED_MINSIZE, 0)
        grid_sizer_2.Add(self.gauge_1, 0, wx.ALIGN_CENTER_VERTICAL|wx.FIXED_MINSIZE, 0)
        grid_sizer_2.Add(self.radio_btn_2, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL|wx.FIXED_MINSIZE, 0)
        grid_sizer_2.Add(self.spin_button_2, 0, wx.ALIGN_CENTER_VERTICAL|wx.FIXED_MINSIZE, 0)
        grid_sizer_1.Add(grid_sizer_2, 1, wx.EXPAND, 0)
        sizer_1.Add(self.label_1, 0, wx.ALIGN_CENTER_VERTICAL|wx.FIXED_MINSIZE, 0)
        sizer_1.Add(self.slider_1, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL|wx.FIXED_MINSIZE, 0)
        grid_sizer_1.Add(sizer_1, 1, wx.EXPAND, 0)
        sizer_2.Add(self.label_4, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL|wx.FIXED_MINSIZE, 0)
        sizer_2.Add(self.slider_2, 0, wx.ALIGN_CENTER_VERTICAL|wx.FIXED_MINSIZE, 0)
        sizer_2.Add(self.radio_btn_3, 0, wx.ALIGN_CENTER_VERTICAL|wx.FIXED_MINSIZE, 0)
        grid_sizer_1.Add(sizer_2, 1, wx.EXPAND, 0)
        self.SetAutoLayout(True)
        self.SetSizer(grid_sizer_1)
        grid_sizer_1.Fit(self)
        grid_sizer_1.SetSizeHints(self)
        self.Layout()
        # end wxGlade

    def MenuExit(self, event):
        self.fg.stop()
        self.Close()

    def set_gain (self,event):
        gain = self.slider_1.GetValue()
        self.dboard.set_gain(gain)

    def spin_up (self, event):
	id = event.GetId()
	if id == ID_SPINBUTTON_2:
            self.set_vol(self.vol * 1.05)
            if self.vol < 1:
              self.gauge_1.SetValue(int(self.vol*200))
            else:
              self.gauge_1.SetValue(200)


    def spin_down (self, event):
	id = event.GetId()
	if id == ID_SPINBUTTON_2:
            self.set_vol(self.vol * 0.95)
            if self.vol < 1:
              self.gauge_1.SetValue(int(self.vol*200))
            else:
              self.gauge_1.SetValue(200)


    def spin_button (self, event):
	id = event.GetId()
	if id == ID_SPINBUTTON_1:
	   self.set_freq(self.spin_button_1.GetValue()/10.)
	   self.update_display(self.station)

    def on_rotate (self, event):
        self.rot += event.delta
        if (self.state == "FREQ"):
            if self.rot >= 3:
                self.set_freq(self.station + .1)
                self.update_display(self.station)
		self.spin_button_1.SetValue(int(self.station*10))
                self.rot -= 3
            elif self.rot <=-3:
                self.set_freq(self.station - .1)
                self.update_display(self.station)
		self.spin_button_1.SetValue(int(self.station*10))
                self.rot += 3
        elif (self.state == "VOL"):
            if self.rot >= 3:
                self.set_vol(self.vol * 1.05)
		if self.spin_button_2.GetValue() < self.spin_button_2.GetMax():
		   self.spin_button_2.SetValue(self.spin_button_2.GetValue()+1)
                if self.vol < 1:
                  self.gauge_1.SetValue(int(self.vol*200))
                else:
                  self.gauge_1.SetValue(200)
                self.rot -= 3
            elif self.rot <=-3:
                self.set_vol(self.vol * .95)
		if self.spin_button_2.GetValue() > self.spin_button_2.GetMin():
		   self.spin_button_2.SetValue(self.spin_button_2.GetValue()-1)
                if self.vol < 1:
                  self.gauge_1.SetValue(int(self.vol*200))
                else:
                  self.gauge_1.SetValue(200)
                self.rot += 3
	else:
	    self.adv += event.delta*.1e-6
	    if self.adv < 0: self.adv = 0
	    if self.adv > 1/38e3: self.adv = 0
	    self.slider_2.SetValue(int(1e7*self.adv))
            a_coefs = build_advance_interpolator(self.quad_rate,self.adv,self.degree,False,sinc)
            self.a_filter.set_taps(a_coefs)


    def on_button (self, event):
        if event.value == 0:        # button up
            return
        self.rot = 0
        if self.state == "ADV":
            self.state = "FREQ"
            self.radio_btn_1.SetValue(True)
	    self.brightness = 128
            self.knob.set_led_state(self.brightness, self.pulse_speed)
        elif self.state == "FREQ":
            self.state = "VOL"
            self.radio_btn_2.SetValue(True)
	    self.brightness = 128
	    self.knob.set_led_state(self.brightness, self.pulse_speed)
	else:
	    self.state = "ADV"
	    self.radio_btn_3.SetValue(True)
	    self.brightness = 0
	    self.knob.set_led_state(self.brightness, self.pulse_speed)
	
    def set_adv (self, event):
            self.adv = self.slider_2.GetValue()*.1e-6
            if self.adv < 0: self.adv = 0
            if self.adv > 1/38e3: self.adv = 0
            self.slider_2.SetValue(int(10e6*self.adv))
            a_coefs = build_advance_interpolator(self.quad_rate,self.adv,self.degree,False,sinc)
            print self.adv
            self.a_filter.set_taps(a_coefs)



    def set_freq (self, freq):
        if freq >878:
            freq = freq/10.0
        if freq < 87.9:
            freq = 87.9
        elif freq >108.1:
            freq = 108.1
        self.station = freq
        RF_freq = freq * 1e6
        (success, actual_freq) = self.dboard.set_freq(RF_freq)
        assert success
        IF_freq = RF_freq - actual_freq
        self.src.set_rx_freq (0, -IF_freq)

    def set_vol (self, vol):
        self.vol = vol
        self.volume_control_l.set_k(self.vol)
        self.volume_control_r.set_k(self.vol)

    def update_display(self, freq):
        n = int(freq * 10 + .000001) # needs a little help over the digit bound
        d = int(n/1e3)
        if d==0: self.bitmap_1.SetBitmap(self.n0)
        elif d==1: self.bitmap_1.SetBitmap(self.n1)
        elif d==2: self.bitmap_1.SetBitmap(self.n2)
        elif d==3: self.bitmap_1.SetBitmap(self.n3)
        elif d==4: self.bitmap_1.SetBitmap(self.n4)
        elif d==5: self.bitmap_1.SetBitmap(self.n5)
        elif d==6: self.bitmap_1.SetBitmap(self.n6)
        elif d==7: self.bitmap_1.SetBitmap(self.n7)
        elif d==8: self.bitmap_1.SetBitmap(self.n8)
        elif d==9: self.bitmap_1.SetBitmap(self.n9)
        n -= int(d*1e3)
        d = int(n/1e2)
        if d==0: self.bitmap_2.SetBitmap(self.n0)
        elif d==1: self.bitmap_2.SetBitmap(self.n1)
        elif d==2: self.bitmap_2.SetBitmap(self.n2)
        elif d==3: self.bitmap_2.SetBitmap(self.n3)
        elif d==4: self.bitmap_2.SetBitmap(self.n4)
        elif d==5: self.bitmap_2.SetBitmap(self.n5)
        elif d==6: self.bitmap_2.SetBitmap(self.n6)
        elif d==7: self.bitmap_2.SetBitmap(self.n7)
        elif d==8: self.bitmap_2.SetBitmap(self.n8)
        elif d==9: self.bitmap_2.SetBitmap(self.n9)
        n -= int(d*1e2)
        d = int(n/1e1)
        if d==0: self.bitmap_3.SetBitmap(self.n0)
        elif d==1: self.bitmap_3.SetBitmap(self.n1)
        elif d==2: self.bitmap_3.SetBitmap(self.n2)
        elif d==3: self.bitmap_3.SetBitmap(self.n3)
        elif d==4: self.bitmap_3.SetBitmap(self.n4)
        elif d==5: self.bitmap_3.SetBitmap(self.n5)
        elif d==6: self.bitmap_3.SetBitmap(self.n6)
        elif d==7: self.bitmap_3.SetBitmap(self.n7)
        elif d==8: self.bitmap_3.SetBitmap(self.n8)
        elif d==9: self.bitmap_3.SetBitmap(self.n9)
        n -= int(d*1e1)
        d = int(n/1e0)
        if d==0: self.bitmap_4.SetBitmap(self.n0)
        elif d==1: self.bitmap_4.SetBitmap(self.n1)
        elif d==2: self.bitmap_4.SetBitmap(self.n2)
        elif d==3: self.bitmap_4.SetBitmap(self.n3)
        elif d==4: self.bitmap_4.SetBitmap(self.n4)
        elif d==5: self.bitmap_4.SetBitmap(self.n5)
        elif d==6: self.bitmap_4.SetBitmap(self.n6)
        elif d==7: self.bitmap_4.SetBitmap(self.n7)
        elif d==8: self.bitmap_4.SetBitmap(self.n8)
        elif d==9: self.bitmap_4.SetBitmap(self.n9)

    def radio_button(self, event):
        id = event.GetId()
        if id == ID_RADIO_FREQ:
           self.state = "FREQ"
        if id == ID_RADIO_VOL:
           self.state = "VOL"
	if id == ID_RADIO_STEREO:
	   self.state = "ADV"

    def OnUpdate(self):
	self.gauge_2.SetValue(min(300,self.L0.level()))
        self.gauge_3.SetValue(min(300,self.L1.level()))
        self.gauge_4.SetValue(min(300,self.L2.level()))
        self.gauge_5.SetValue(min(300,self.L3.level()))
        self.gauge_6.SetValue(min(300,self.L4.level()))
        self.gauge_7.SetValue(min(300,self.L5.level()))
        self.gauge_8.SetValue(min(300,self.L6.level()))
        self.gauge_9.SetValue(min(300,self.L7.level()))
        self.gauge_10.SetValue(min(300,self.L8.level()))
        self.gauge_11.SetValue(min(300,self.L9.level()))
        self.gauge_12.SetValue(min(300,self.L10.level()))
        self.gauge_13.SetValue(min(300,self.L11.level()))
        self.gauge_14.SetValue(min(300,self.L12.level()))
        self.gauge_15.SetValue(min(300,self.L13.level()))
        self.gauge_16.SetValue(min(300,self.L14.level()))
        self.gauge_17.SetValue(min(300,self.L15.level()))
        self.gauge_18.SetValue(min(300,self.L16.level()))
        self.gauge_19.SetValue(min(300,self.L17.level()))
        self.gauge_20.SetValue(min(300,self.L18.level()))
        self.gauge_21.SetValue(min(300,self.L19.level()))
        self.gauge_22.SetValue(min(300,self.L20.level()))
        self.gauge_23.SetValue(min(300,self.L21.level()))
        self.gauge_24.SetValue(min(300,self.L22.level()))
        self.gauge_25.SetValue(min(300,self.L23.level()))
        self.gauge_26.SetValue(min(300,self.L24.level()))
        self.gauge_27.SetValue(min(300,self.L25.level()))
        self.gauge_28.SetValue(min(300,self.L26.level()))
        self.gauge_29.SetValue(min(300,self.L27.level()))
        self.gauge_30.SetValue(min(300,self.L28.level()))
        self.gauge_31.SetValue(min(300,self.L29.level()))
        self.gauge_32.SetValue(min(300,self.L30.level()))
        self.gauge_33.SetValue(min(300,self.L31.level()))

# end of class MyFrame

# utilities for FM stereo
def find_arg(coefs,rate,f0):
    l = len(coefs)
    ii = range(l)
    s=0
    for i in ii:
        p = -2*math.pi*ii[i]*f0/rate
        s = s + coefs[ii[i]] * (math.cos(p) + math.sin(p) * (0+1j))

    s=s.conjugate()   # because of the way GNURADIO implements filtering

    phi = argument(s)

    #print "argument = " , phi * 180 / math.pi
    #print "norm delay = ", - phi / 2 / math.pi / (f0/rate)
    delay =  - phi / 2 / math.pi / f0
    #print "absolute delay =", delay
    return delay

def argument(c):
    if c.real > 0:
        phi = math.atan(c.imag/c.real)
    elif c.imag > 0:
        phi = math.atan(c.imag/c.real) + math.pi
    else:
        phi = math.atan(c.imag/c.real) - math.pi
    return phi

def build_advance_interpolator(rate,advance,degree,symmetric,pulse):
    if advance<0:
        print "cannot implement negative advances, ie, delays"
        return -1
    m=int(advance*rate)
    Delta = advance*rate - m
    # print m, Delta

    # interpolator using x_{k+m} and x_{k+m+d}
    if symmetric == False:
        c=[]
        i=0
        while i <= m-1:
            c.append(0)
            i=i+1
        i=0
        while i <= degree:
            c.append(pulse(Delta-i))
            i=i+1

        return tuple(c)

    # interpolator using x_{k+m-d} .... x_{k+m+d}
    if degree > m:
         print "degree not consistent with advance"
         return -2

    c=[]
    i=0
    while i <= m-degree-1:
        c.append(0)
        i=i+1
    i=-degree
    while i <= degree:
        c.append(pulse(Delta-i))
        i=i+1
    return tuple(c)

def sinc(x):
    if x == 0:
        return 1
    else:
        return math.sin(math.pi * x)/(math.pi * x)

class UpdateTimer(wx.Timer):
    def __init__(self, target, dur=1000):
        wx.Timer.__init__(self)
        self.target = target
        self.Start(dur)

    def Notify(self):
        """Called every timer interval"""
        if self.target:
            self.target.OnUpdate()


class MyApp(wx.App):
  def OnInit(self):
    frame = MyFrame(None, -1, "GNU FM Radio")
    frame.Show(True)
    self.SetTopWindow(frame)
    return True

app = MyApp(0)
app.MainLoop()

