#!/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_oss as 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, time
import math
import wx

ID_EXIT = wx.NewId()
ID_OPEN_FILE = wx.NewId()
ID_CLOSE_FILE = wx.NewId()
ID_SLIDER_1 = wx.NewId()
ID_SLIDER_2 = wx.NewId()
ID_SLIDER_3 = wx.NewId()
ID_SLIDER_4 = wx.NewId()
ID_RADIO_FREQ = wx.NewId()
ID_RADIO_VOL = wx.NewId()
ID_SPINBUTTON_1 = wx.NewId()
ID_BUTTON_1 = wx.NewId()
ID_STATION_1 = wx.NewId()
ID_STATION_2 = wx.NewId()
ID_STATION_3 = wx.NewId()
ID_STATION_4 = wx.NewId()
ID_STATION_5 = wx.NewId()
ID_STATION_6 = wx.NewId()
ID_STATION_7 = wx.NewId()
ID_STATION_8 = wx.NewId()
ID_STATION_9 = wx.NewId()
ID_STATION_10 = 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_OPEN_FILE, "Save to file", "Open", wx.ITEM_NORMAL)
        wxglade_tmp_menu.Append(ID_CLOSE_FILE, "Close file", "Close file", wx.ITEM_NORMAL)
        wxglade_tmp_menu.AppendSeparator()
        wxglade_tmp_menu.Append(ID_EXIT, "Exit", "Exit", wx.ITEM_NORMAL)
        self.frame_1_menubar.Append(wxglade_tmp_menu, "File")
        # Menu Bar end
        self.button_1 = wx.ToggleButton(self, ID_BUTTON_1, "Set", size=(40,25))
        self.text_ctrl_1 = wx.TextCtrl(self, -1, "",size=(50,25))
        self.button_2 = wx.Button(self, ID_STATION_1, "Station 1")
        self.text_ctrl_6 = wx.TextCtrl(self, -1, "",size=(50,25))
        self.button_7 = wx.Button(self, ID_STATION_6, "Station 6")
        self.text_ctrl_2 = wx.TextCtrl(self, -1, "",size=(50,25))
        self.button_3 = wx.Button(self, ID_STATION_2, "Station 2")
        self.text_ctrl_7 = wx.TextCtrl(self, -1, "",size=(50,25))
        self.button_8 = wx.Button(self, ID_STATION_7, "Station 7")
        self.text_ctrl_3 = wx.TextCtrl(self, -1, "",size=(50,25))
        self.button_4 = wx.Button(self, ID_STATION_3, "Station 3")
        self.text_ctrl_8 = wx.TextCtrl(self, -1, "",size=(50,25))
        self.button_9 = wx.Button(self, ID_STATION_8, "Station 8")
        self.text_ctrl_4 = wx.TextCtrl(self, -1, "",size=(50,25))
        self.button_5 = wx.Button(self, ID_STATION_4, "Station 4")
        self.text_ctrl_9 = wx.TextCtrl(self, -1, "",size=(50,25))
        self.button_10 = wx.Button(self, ID_STATION_9, "Station 9")
        self.text_ctrl_5 = wx.TextCtrl(self, -1, "",size=(50,25))
        self.button_6 = wx.Button(self, ID_STATION_5, "Station 5")
        self.text_ctrl_10 = wx.TextCtrl(self, -1, "",size=(50,25))
        self.button_11 = wx.Button(self, ID_STATION_10, "Station 10")
        self.gauge_=[]
        for i in range(2,34):
          self.gauge_.append(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.slider_4 = wx.Slider(self, ID_SLIDER_4, 0, 0, 2000)
        self.radio_btn_2 = wx.RadioButton(self, ID_RADIO_VOL, "volume")
        self.panel_2 = wx.Panel(self, -1)
        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.panel_4 = wx.Panel(self, -1)
        self.label_5 = wx.StaticText(self, -1, "    Pilot power    ")
        self.slider_3 = wx.Slider(self, ID_SLIDER_3, 0, 0, 100)
        self.gauge_34 = wx.Gauge(self, -1, 100, style=wx.GA_VERTICAL)
        self.panel_5 = wx.Panel(self, -1)

        # end wxGlade

	# wxpython gui events
        wx.EVT_MENU(self, ID_EXIT, self.MenuExit)
	wx.EVT_MENU(self, ID_OPEN_FILE, self.MenuOpenFile)
	wx.EVT_MENU(self, ID_CLOSE_FILE, self.MenuCloseFile)
        wx.EVT_SLIDER(self, ID_SLIDER_1, self.set_gain)
	wx.EVT_SLIDER(self, ID_SLIDER_2, self.set_adv)
	wx.EVT_SLIDER(self, ID_SLIDER_3, self.set_power)
	wx.EVT_SLIDER(self, ID_SLIDER_4, self.volume)
        wx.EVT_RADIOBUTTON(self, ID_RADIO_FREQ, self.radio_button)
        wx.EVT_RADIOBUTTON(self, ID_RADIO_VOL, self.radio_button)
	wx.EVT_SPIN(self, ID_SPINBUTTON_1, self.spin_button)
        wx.EVT_BUTTON(self, ID_STATION_1, self.station)
        wx.EVT_BUTTON(self, ID_STATION_2, self.station)
        wx.EVT_BUTTON(self, ID_STATION_3, self.station)
        wx.EVT_BUTTON(self, ID_STATION_4, self.station)
        wx.EVT_BUTTON(self, ID_STATION_5, self.station)
        wx.EVT_BUTTON(self, ID_STATION_6, self.station)
        wx.EVT_BUTTON(self, ID_STATION_7, self.station)
        wx.EVT_BUTTON(self, ID_STATION_8, self.station)
        wx.EVT_BUTTON(self, ID_STATION_9, self.station)
        wx.EVT_BUTTON(self, ID_STATION_10, self.station)
        self.s1 = 88.5
	self.text_ctrl_1.SetValue("88.5")
        self.s2 = 94.5
	self.text_ctrl_2.SetValue("94.5")
        self.s3 = 99.9
	self.text_ctrl_3.SetValue("99.9")
        self.s4 = 100.9
	self.text_ctrl_4.SetValue("100.9")
        self.s5 = 102.7
	self.text_ctrl_5.SetValue("102.7")
        self.s6 = 105.1
	self.text_ctrl_6.SetValue("105.1")
        self.s7 = 107.3
	self.text_ctrl_7.SetValue("107.3")
        self.s8 = 88.1
	self.text_ctrl_8.SetValue("88.1")
        self.s9 = 88.1
	self.text_ctrl_9.SetValue("88.1")
        self.s10 = 88.1
	self.text_ctrl_10.SetValue("88.1")

# blocks needed for save to file
# This creates a signed-word 2-channel (stereo) file at 32000 hz
# convert to wav file with: sox -c 2 -r 32000 hfx_out.sw hfx_out.wav
	self.FILEOPEN = False
        self.stereo = gr.interleave(gr.sizeof_short)
        self.sc1 = gr.multiply_const_ff(378000)
        self.sc2 = gr.multiply_const_ff(378000)
        self.f2s1 = gr.float_to_short()
        self.f2s2 = gr.float_to_short()


	# load pretty green numerals
        self.n_ = []
        for i in range(0, 10):
          fname = "/usr/src/radio/wx/numerals/fancydigitalgreen/"+str(i)+".bmp"
          self.n_.append(wx.Bitmap(fname, wx.BITMAP_TYPE_ANY))


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

        adc_rate = 64e6
        usrp_decim = 250
        self.quad_rate = adc_rate / usrp_decim           # 256000
        audio_decimation = 8
        self.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 = 2.0
        fm_demod = gr.quadrature_demod_cf (volume*fm_demod_gain)
# L+R processing: LPF + decimation
        # compute FIR filter taps for audio filter
        width = 1e3
        # 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)
	self.p_adjust = gr.multiply_const_ff(.5)
	self.p_meter = gr.signal_level_ff(1,.01)
        # 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()

        fs = self.quad_rate
        tau=75e-6
        w_p = 1/tau
        w_pp = math.tan (w_p / (fs * 2)) # prewarped analog freq

        a1 = (w_pp - 1)/(w_pp + 1)
        b0 = w_pp/(1 + w_pp)
        b1 = b0

        btaps = [b0, b1]
        ataps = [1, a1]

        self.deemphl = gr.iir_filter_ffd(btaps, ataps)
        self.deemphr = gr.iir_filter_ffd(btaps, ataps)


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

        self.audio_sink = audio.sink (int (self.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,self.p_adjust,self.p_meter)
	self.fg.connect (self.p_meter,(square,0))
        self.fg.connect (fm_demod,band_filter)
        self.fg.connect (self.p_meter,(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,self.deemphl,self.volume_control_l,(self.audio_sink,0))
        self.fg.connect (Right,self.deemphr,self.volume_control_r,(self.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.slider_4.SetValue(int(self.vol*200))
	self.slider_3.SetValue(25)


	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,True) # 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.L=[]
        for i in range(0,32):
          self.L.append(gr.signal_level_cc(1,alpha))

        sink = gr.null_sink(gr.sizeof_gr_complex)
        self.fg.connect((s2ss,0),sink)
        for i in range(0,32):
          sink = gr.null_sink(gr.sizeof_gr_complex)
          self.fg.connect((s2ss,i+1),self.L[i],sink)

        for i in range(33,64):
          sink = gr.null_sink(gr.sizeof_gr_complex)
          self.fg.connect((s2ss,i),sink)



	# 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 !")
        for i in range(0,32):
          self.gauge_[i].SetSize((12, 150))
          self.gauge_[i].SetBackgroundColour(wx.Colour(0, 255, 0))

        self.label_2.SetSize((100, 17))
        self.label_3.SetSize((100, 17))
        self.slider_4.SetSize((110, 19))
        self.label_1.SetSize((110, 25))
        self.slider_1.SetSize((200, 60))
        self.label_4.SetSize((110, 25))
        self.slider_2.SetSize((200, 60))
        self.label_5.SetSize((110, 25))
        self.slider_3.SetSize((200, 60))
        self.gauge_34.SetSize((10, 100))
        # end wxGlade
	self.spin_button_1.SetRange(881,1081)
	self.spin_button_1.SetValue(1027)
	self.slider_2.SetValue(self.adv*1e7)

    def __do_layout(self):
        # begin wxGlade: MyFrame.__do_layout
        grid_sizer_1 = wx.FlexGridSizer(6, 1, 0, 0)
        sizer_4 = wx.BoxSizer(wx.HORIZONTAL)
        sizer_2 = wx.BoxSizer(wx.HORIZONTAL)
        sizer_1 = wx.BoxSizer(wx.HORIZONTAL)
        grid_sizer_2 = wx.FlexGridSizer(2, 4, 0, 0)
        sizer_3 = wx.BoxSizer(wx.HORIZONTAL)
        grid_sizer_3 = wx.FlexGridSizer(1, 32, 0, 0)
        sizer_5 = wx.BoxSizer(wx.HORIZONTAL)
        grid_sizer_4 = wx.GridSizer(5, 4, 0, 0)
        sizer_5.Add(self.button_1, 0, wx.ALIGN_CENTER_VERTICAL|wx.FIXED_MINSIZE, 0)
        grid_sizer_4.Add(self.text_ctrl_1, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL|wx.FIXED_MINSIZE, 0)
        grid_sizer_4.Add(self.button_2, 0, wx.FIXED_MINSIZE, 0)
        grid_sizer_4.Add(self.text_ctrl_6, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL|wx.FIXED_MINSIZE, 0)
        grid_sizer_4.Add(self.button_7, 0, wx.FIXED_MINSIZE, 0)
        grid_sizer_4.Add(self.text_ctrl_2, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL|wx.FIXED_MINSIZE, 0)
        grid_sizer_4.Add(self.button_3, 0, wx.FIXED_MINSIZE, 0)
        grid_sizer_4.Add(self.text_ctrl_7, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL|wx.FIXED_MINSIZE, 0)
        grid_sizer_4.Add(self.button_8, 0, wx.FIXED_MINSIZE, 0)
        grid_sizer_4.Add(self.text_ctrl_3, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL|wx.FIXED_MINSIZE, 0)
        grid_sizer_4.Add(self.button_4, 0, wx.FIXED_MINSIZE, 0)
        grid_sizer_4.Add(self.text_ctrl_8, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL|wx.FIXED_MINSIZE, 0)
        grid_sizer_4.Add(self.button_9, 0, wx.FIXED_MINSIZE, 0)
        grid_sizer_4.Add(self.text_ctrl_4, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL|wx.FIXED_MINSIZE, 0)
        grid_sizer_4.Add(self.button_5, 0, wx.FIXED_MINSIZE, 0)
        grid_sizer_4.Add(self.text_ctrl_9, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL|wx.FIXED_MINSIZE, 0)
        grid_sizer_4.Add(self.button_10, 0, wx.FIXED_MINSIZE, 0)
        grid_sizer_4.Add(self.text_ctrl_5, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL|wx.FIXED_MINSIZE, 0)
        grid_sizer_4.Add(self.button_6, 0, wx.FIXED_MINSIZE, 0)
        grid_sizer_4.Add(self.text_ctrl_10, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL|wx.FIXED_MINSIZE, 0)
        grid_sizer_4.Add(self.button_11, 0, wx.FIXED_MINSIZE, 0)
        sizer_5.Add(grid_sizer_4, 1, wx.EXPAND, 0)
        grid_sizer_1.Add(sizer_5, 1, wx.EXPAND, 0)
        for i in range(0,32):
          grid_sizer_3.Add(self.gauge_[i], 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.slider_4, 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.panel_2, 1, wx.EXPAND, 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.panel_4, 1, wx.EXPAND, 0)
        grid_sizer_1.Add(sizer_2, 1, wx.EXPAND, 0)
        sizer_4.Add(self.label_5, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL|wx.FIXED_MINSIZE, 0)
        sizer_4.Add(self.slider_3, 0, wx.ALIGN_CENTER_VERTICAL|wx.FIXED_MINSIZE, 0)
        sizer_4.Add(self.gauge_34, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL|wx.FIXED_MINSIZE, 0)
        sizer_4.Add(self.panel_5, 1, wx.EXPAND, 0)
        grid_sizer_1.Add(sizer_4, 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_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.vol < 10:
                  self.slider_4.SetValue(int(self.vol*200))
                else:
                  self.slider_4.SetValue(2000)
                self.rot -= 3
            elif self.rot <=-3:
                self.set_vol(self.vol * .95)
                if self.vol < 10:
                  self.slider_4.SetValue(int(self.vol*200))
                else:
                  self.slider_4.SetValue(2000)
                self.rot += 3


    def on_button (self, event):
        if event.value == 0:        # button up
            return
        self.rot = 0
        if self.state == "VOL":
            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)
	
    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)
            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 volume (self, event):
	if self.slider_4.GetValue() > 200:
	  self.set_vol(self.slider_4.GetValue()/200)

    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)
        self.bitmap_1.SetBitmap(self.n_[d])
        n -= int(d*1e3)
        d = int(n/1e2)
        self.bitmap_2.SetBitmap(self.n_[d])
        n -= int(d*1e2)
        d = int(n/1e1)
        self.bitmap_3.SetBitmap(self.n_[d])
        n -= int(d*1e1)
        d = int(n/1e0)
        self.bitmap_4.SetBitmap(self.n_[d])


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

    def OnUpdate(self):
        for i in range (0, 32):
          self.gauge_[i].SetValue(min(300,self.L[i].level()))
	# pilot power
	self.gauge_34.SetValue(min(100,self.p_meter.level()*25))

    def set_power(self,event):
	self.p_adjust.set_k(self.slider_3.GetValue()/50.)

    def MenuOpenFile(self,event):
        fname = wx.GetTextFromUser("Enter Filename",caption="Enter File to save to:",default_value="music.sw")
	if fname !='':
	  self.save = gr.file_sink(gr.sizeof_short,fname)
	  self.FILEOPEN = True
	  self.fg.stop()
          self.fg.connect (self.deemphl, self.sc1)
          self.fg.connect (self.deemphr, self.sc2)
          self.fg.connect (self.sc1, self.f2s1)
          self.fg.connect (self.sc2, self.f2s2)
          self.fg.connect (self.f2s1, (self.stereo, 0))
          self.fg.connect (self.f2s2, (self.stereo, 1))
          self.fg.connect (self.stereo, self.save)
	  self.fg.start()

    def MenuCloseFile(self, event):
	if self.FILEOPEN == True:
	  self.fg.stop()
	  self.FILEOPEN = False
	  self.fg.disconnect(self.deemphl,self.sc1)
	  self.fg.disconnect(self.deemphr,self.sc2)
	  self.fg.disconnect(self.sc1, self.f2s1)
	  self.fg.disconnect(self.sc2, self.f2s2)
	  self.fg.disconnect(self.f2s1, (self.stereo, 0))
	  self.fg.disconnect(self.f2s2, (self.stereo, 1))
	  self.fg.disconnect(self.stereo, self.save)
	  self.fg.start()

    def station(self, event):
        id = event.GetId()
        if self.button_1.GetValue():
          if id == ID_STATION_1:
	    self.s1 = self.station
	    self.text_ctrl_1.SetValue(str(self.station))
          if id == ID_STATION_2:
	    self.s2 = self.station
	    self.text_ctrl_2.SetValue(str(self.station))
          if id == ID_STATION_3:
	    self.s3 = self.station
	    self.text_ctrl_3.SetValue(str(self.station))
          if id == ID_STATION_4:
	    self.s4 = self.station
	    self.text_ctrl_4.SetValue(str(self.station))
          if id == ID_STATION_5:
	    self.s5 = self.station
	    self.text_ctrl_5.SetValue(str(self.station))
          if id == ID_STATION_6:
	    self.s6 = self.station
	    self.text_ctrl_6.SetValue(str(self.station))
          if id == ID_STATION_7:
	    self.s7 = self.station
	    self.text_ctrl_7.SetValue(str(self.station))
          if id == ID_STATION_8:
	    self.s8 = self.station
	    self.text_ctrl_8.SetValue(str(self.station))
          if id == ID_STATION_9:
	    self.s9 = self.station
	    self.text_ctrl_9.SetValue(str(self.station))
          if id == ID_STATION_10:
	    self.s10 = self.station
	    self.text_ctrl_10.SetValue(str(self.station))
          self.button_1.SetValue(False)
        else:
          if id == ID_STATION_1: self.station = self.s1
          if id == ID_STATION_2: self.station = self.s2
          if id == ID_STATION_3: self.station = self.s3
          if id == ID_STATION_4: self.station = self.s4
          if id == ID_STATION_5: self.station = self.s5
          if id == ID_STATION_6: self.station = self.s6
          if id == ID_STATION_7: self.station = self.s7
          if id == ID_STATION_8: self.station = self.s8
          if id == ID_STATION_9: self.station = self.s9
          if id == ID_STATION_10: self.station = self.s10
          self.set_freq(self.station)
          self.update_display(self.station)
          self.spin_button_1.SetValue(int(self.station*10))


# 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()

