Example #1
0
    def __init__(self, parent, surface):
        scrolled.ScrolledPanel.__init__(self, parent, -1)
        self.SetBackgroundColour(BACKGROUND_COLOUR)
        self.parent = parent
        self.surface = surface
        self.type = 0
        self.selected = 0
        self.selectedOkToChange = True
        self.sndPath = ""
        self.sndDur = 0.0
        self.amplitude = 1
        self.nchnls = 2
        self.samplingRate = 44100
        self.fileformat = 0
        self.sampletype = 0
        self.tempState = None

        box = wx.BoxSizer(wx.VERTICAL)

        box.Add(wx.StaticText(self, -1, "Trajectories"), 0, wx.CENTER | wx.TOP,
                3)

        typeBox = wx.BoxSizer(wx.HORIZONTAL)
        popupBox = wx.BoxSizer(wx.VERTICAL)
        self.trajType = wx.Choice(self,
                                  -1,
                                  choices=['Free', 'Circle', 'Oscil', 'Line'])
        self.trajType.SetSelection(0)
        popupBox.Add(self.trajType)
        typeBox.Add(popupBox, 0, wx.CENTER | wx.RIGHT, 5)

        # TODO: Check the size of this button on Windows and OSX
        self.closedToggle = wx.ToggleButton(self,
                                            -1,
                                            'Closed',
                                            size=self.trajType.GetSize())
        font = self.closedToggle.GetFont()
        if PLATFORM.startswith('linux') or PLATFORM == 'win32':
            font = wx.Font(8, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL,
                           wx.FONTWEIGHT_NORMAL)
        self.closedToggle.SetFont(font)
        typeBox.Add(self.closedToggle, wx.CENTER | wx.RIGHT, 5)
        box.Add(typeBox, 0, wx.CENTER | wx.ALL, 5)

        self.notebook = wx.Notebook(self, -1, style=wx.BK_DEFAULT | wx.EXPAND)
        self.notebook.SetBackgroundColour(BACKGROUND_COLOUR)
        self.drawing = DrawingParameters(self.notebook)
        self.playback = PlaybackParameters(self.notebook)
        self.notebook.AddPage(self.drawing, "Drawing")
        self.notebook.AddPage(self.playback, "Playback")
        box.Add(self.notebook, 0, wx.ALL, 5)

        # EQ
        eqTitle = wx.StaticText(self, id=-1, label="4 Bands Equalizer")
        box.Add(eqTitle, 0, wx.CENTER)

        eqFreqBox = wx.BoxSizer(wx.HORIZONTAL)
        self.knobEqF1 = ControlKnob(self,
                                    40,
                                    250,
                                    100,
                                    label='Freq 1',
                                    outFunction=self.changeEqF1)
        eqFreqBox.Add(self.knobEqF1, 0, wx.LEFT | wx.RIGHT, 20)
        self.knobEqF1.setFloatPrecision(2)
        self.knobEqF2 = ControlKnob(self,
                                    300,
                                    1000,
                                    500,
                                    label='Freq 2',
                                    outFunction=self.changeEqF2)
        eqFreqBox.Add(self.knobEqF2, 0, wx.LEFT | wx.RIGHT, 4)
        self.knobEqF2.setFloatPrecision(2)
        self.knobEqF3 = ControlKnob(self,
                                    1200,
                                    5000,
                                    2000,
                                    label='Freq 3',
                                    outFunction=self.changeEqF3)
        eqFreqBox.Add(self.knobEqF3, 0, wx.LEFT | wx.RIGHT, 20)
        self.knobEqF3.setFloatPrecision(2)

        box.Add(eqFreqBox)

        eqGainBox = wx.BoxSizer(wx.HORIZONTAL)
        self.knobEqA1 = ControlKnob(self,
                                    -40,
                                    18,
                                    0,
                                    label='B1 gain',
                                    outFunction=self.changeEqA1)
        eqGainBox.Add(self.knobEqA1, 0, wx.LEFT | wx.RIGHT, 5)
        self.knobEqA2 = ControlKnob(self,
                                    -40,
                                    18,
                                    0,
                                    label='B2 gain',
                                    outFunction=self.changeEqA2)
        eqGainBox.Add(self.knobEqA2, 0, wx.LEFT | wx.RIGHT, 5)
        self.knobEqA3 = ControlKnob(self,
                                    -40,
                                    18,
                                    0,
                                    label='B3 gain',
                                    outFunction=self.changeEqA3)
        eqGainBox.Add(self.knobEqA3, 0, wx.LEFT | wx.RIGHT, 5)
        self.knobEqA4 = ControlKnob(self,
                                    -40,
                                    18,
                                    0,
                                    label='B4 gain',
                                    outFunction=self.changeEqA4)
        eqGainBox.Add(self.knobEqA4, 0, wx.LEFT | wx.RIGHT, 5)

        box.Add(eqGainBox)

        box.Add(wx.StaticLine(self, size=(210, 1)), 0, wx.ALL, 5)

        #Compress
        compTitle = wx.StaticText(self, id=-1, label="Dynamic Compressor")
        box.Add(compTitle, 0, wx.CENTER)

        cpKnobBox = wx.BoxSizer(wx.HORIZONTAL)
        self.knobComp1 = ControlKnob(self,
                                     -60,
                                     0,
                                     -3,
                                     label='Thresh',
                                     outFunction=self.changeComp1)
        cpKnobBox.Add(self.knobComp1, 0, wx.LEFT | wx.RIGHT, 5)
        self.knobComp2 = ControlKnob(self,
                                     1,
                                     10,
                                     2,
                                     label='Ratio',
                                     outFunction=self.changeComp2)
        cpKnobBox.Add(self.knobComp2, 0, wx.LEFT | wx.RIGHT, 5)
        self.knobComp3 = ControlKnob(self,
                                     0.001,
                                     0.5,
                                     0.05,
                                     label='Rise',
                                     outFunction=self.changeComp3)
        cpKnobBox.Add(self.knobComp3, 0, wx.LEFT | wx.RIGHT, 5)
        self.knobComp4 = ControlKnob(self,
                                     0.01,
                                     1,
                                     .2,
                                     label='Fall',
                                     outFunction=self.changeComp4)
        cpKnobBox.Add(self.knobComp4, 0, wx.LEFT | wx.RIGHT, 5)

        box.Add(cpKnobBox)

        box.Add(wx.StaticLine(self, size=(210, 1)), 0, wx.ALL, 5)

        box.Add(wx.StaticText(self, -1, "Global amplitude (dB)"), 0,
                wx.LEFT | wx.TOP, 10)
        ampBox = wx.BoxSizer(wx.HORIZONTAL)
        self.sl_amp = ControlSlider(self,
                                    -60,
                                    18,
                                    0,
                                    size=(200, 16),
                                    outFunction=self.handleAmp)
        ampBox.Add(self.sl_amp, 0, wx.LEFT | wx.RIGHT, 5)
        box.Add(ampBox, 0, wx.LEFT | wx.RIGHT, 5)
        box.AddSpacer(10)
        self.meter = VuMeter(self, size=(200, 11))
        self.meter.setNumSliders(self.nchnls)
        box.Add(self.meter, 0, wx.LEFT, 10)
        box.AddSpacer(5)

        box.Add(wx.StaticLine(self, size=(210, 1)), 0, wx.ALL, 5)

        box.Add(wx.StaticText(self, -1, "Project Settings"), 0,
                wx.CENTER | wx.ALL, 5)

        projSettingsBox = wx.BoxSizer(wx.HORIZONTAL)
        srBox = wx.BoxSizer(wx.VERTICAL)
        srText = wx.StaticText(self, -1, "Rate")
        srBox.Add(srText, 0, wx.CENTER | wx.LEFT | wx.RIGHT, 5)
        self.pop_sr = wx.Choice(self,
                                -1,
                                choices=['44100', '48000', '96000'],
                                size=(80, -1))
        self.pop_sr.SetSelection(0)
        self.pop_sr.Bind(wx.EVT_CHOICE, self.handleSamplingRate)
        srBox.Add(self.pop_sr, 0, wx.LEFT | wx.RIGHT, 5)
        chnlsBox = wx.BoxSizer(wx.VERTICAL)
        chnlsText = wx.StaticText(self, -1, "Chnls")
        chnlsBox.Add(chnlsText, 0, wx.CENTER | wx.LEFT | wx.RIGHT, 5)
        self.tx_chnls = wx.TextCtrl(self,
                                    -1,
                                    "2",
                                    size=(60, -1),
                                    style=wx.TE_PROCESS_ENTER)
        self.tx_chnls.Bind(wx.EVT_TEXT_ENTER, self.handleNchnls)
        chnlsBox.Add(self.tx_chnls, 0, wx.LEFT | wx.RIGHT, 5)
        projSettingsBox.Add(srBox, 0, wx.LEFT | wx.RIGHT | wx.BOTTOM, 5)
        projSettingsBox.Add(chnlsBox, 0, wx.LEFT | wx.RIGHT | wx.BOTTOM, 5)
        box.Add(projSettingsBox, 0, wx.ALIGN_CENTER, 5)

        box.Add(wx.StaticLine(self, size=(210, 1)), 0, wx.ALL, 5)

        soundBox = wx.BoxSizer(wx.HORIZONTAL)
        self.tog_audio = wx.ToggleButton(self, -1, "Start", size=(80, -1))
        self.tog_audio.SetFont(font)
        self.tog_audio.Disable()
        soundBox.Add(self.tog_audio, 0, wx.CENTER | wx.LEFT | wx.RIGHT, 5)
        box.Add(soundBox, 0, wx.CENTER | wx.ALL, 5)

        box.Add(wx.StaticLine(self, size=(210, 1)), 0, wx.ALL, 5)

        box.Add(wx.StaticText(self, -1, "Record Settings"), 0,
                wx.CENTER | wx.ALL, 5)

        recSettingsBox = wx.BoxSizer(wx.HORIZONTAL)
        fileformatBox = wx.BoxSizer(wx.VERTICAL)
        fileformatText = wx.StaticText(self, -1, "Format")
        fileformatBox.Add(fileformatText, 0, wx.CENTER | wx.LEFT | wx.RIGHT, 5)
        self.pop_fileformat = wx.Choice(self,
                                        -1,
                                        choices=EXPORT_FORMATS,
                                        size=(80, -1))
        self.pop_fileformat.SetSelection(0)
        self.pop_fileformat.Bind(wx.EVT_CHOICE, self.handleFileFormat)
        fileformatBox.Add(self.pop_fileformat, 0, wx.LEFT | wx.RIGHT, 5)
        sampletypeBox = wx.BoxSizer(wx.VERTICAL)
        sampletypeText = wx.StaticText(self, -1, "Type")
        sampletypeBox.Add(sampletypeText, 0, wx.CENTER | wx.LEFT | wx.RIGHT, 5)
        self.pop_sampletype = wx.Choice(self, -1, choices=EXPORT_TYPES)
        self.pop_sampletype.SetSelection(0)
        self.pop_sampletype.Bind(wx.EVT_CHOICE, self.handleSampleType)
        sampletypeBox.Add(self.pop_sampletype, 0, wx.LEFT | wx.RIGHT, 5)
        recSettingsBox.Add(fileformatBox, 0, wx.LEFT | wx.RIGHT | wx.BOTTOM, 5)
        recSettingsBox.Add(sampletypeBox, 0, wx.LEFT | wx.RIGHT | wx.BOTTOM, 5)
        box.Add(recSettingsBox, 0, wx.ALIGN_CENTER | wx.BOTTOM, 5)

        rec1Box = wx.BoxSizer(wx.HORIZONTAL)

        self.tx_rec_folder = wx.TextCtrl(self, -1, "~/Desktop", size=(120, -1))
        rec1Box.Add(self.tx_rec_folder, 0, wx.LEFT | wx.RIGHT, 10)
        self.but_folder = wx.ToggleButton(self, -1, "Choose", size=(65, -1))
        self.but_folder.SetFont(font)
        rec1Box.Add(self.but_folder, 1,
                    wx.ALIGN_CENTER_VERTICAL | wx.EXPAND | wx.RIGHT, 10)

        rec2Box = wx.BoxSizer(wx.HORIZONTAL)

        self.tx_output = wx.TextCtrl(self, -1, "snd", size=(120, -1))
        rec2Box.Add(self.tx_output, 0, wx.LEFT | wx.RIGHT, 10)
        self.tog_record = wx.ToggleButton(self, -1, "Start Rec", size=(65, -1))
        self.tog_record.SetFont(font)
        rec2Box.Add(self.tog_record, 1,
                    wx.ALIGN_CENTER_VERTICAL | wx.EXPAND | wx.RIGHT, 10)

        box.Add(wx.StaticText(self, -1, "Destination"), 0, wx.LEFT | wx.RIGHT,
                17)
        box.Add(rec1Box, 0, wx.EXPAND | wx.BOTTOM | wx.LEFT | wx.RIGHT, 5)
        box.Add(wx.StaticText(self, -1, "Filename"), 0, wx.LEFT | wx.RIGHT, 17)
        box.Add(rec2Box, 0, wx.EXPAND | wx.BOTTOM | wx.LEFT | wx.RIGHT, 5)

        self.Bind(wx.EVT_CHOICE, self.handleType, self.trajType)
        self.Bind(wx.EVT_TOGGLEBUTTON, self.handleClosed, self.closedToggle)
        self.Bind(wx.EVT_TOGGLEBUTTON, self.handleAudio, self.tog_audio)
        self.tx_output.Bind(wx.EVT_CHAR, self.handleOutput)
        self.tx_rec_folder.Bind(wx.EVT_CHAR, self.handleOutput)
        self.Bind(wx.EVT_TOGGLEBUTTON, self.handleRecord, self.tog_record)
        self.Bind(wx.EVT_TOGGLEBUTTON, self.chooseRecFolder, self.but_folder)

        self.SetAutoLayout(True)
        self.SetSizerAndFit(box)
        self.SetupScrolling(scroll_x=False)
Example #2
0
    def __init__(self, parent, surface):
        scrolled.ScrolledPanel.__init__(self, parent, -1)
        self.SetBackgroundColour(BACKGROUND_COLOUR)
        self.parent = parent
        self.surface = surface
        self.type = 0
        self.selected = 0
        self.selectedOkToChange = True
        self.sndPath = ""
        self.sndDur = 0.0
        self.amplitude = 1
        self.nchnls = 2
        self.samplingRate = 44100
        self.midiInterface = None
        self.fileformat = 0
        self.sampletype = 0
        self.tempState = None

        box = wx.BoxSizer(wx.VERTICAL)

        box.Add(wx.StaticText(self, -1, "Trajectories"), 0, wx.CENTER|wx.TOP, 3)

        typeBox = wx.BoxSizer(wx.HORIZONTAL)
        popupBox = wx.BoxSizer(wx.VERTICAL)
        self.trajType = wx.Choice(self, -1, choices = ['Free', 'Circle', 'Oscil', 'Line'])
        self.trajType.SetSelection(0)
        popupBox.Add(self.trajType)
        typeBox.Add(popupBox, 0, wx.CENTER|wx.RIGHT, 5)

        # TODO: Check the size of this button on Windows and OSX
        self.closedToggle = wx.ToggleButton(self, -1, 'Closed', size=self.trajType.GetSize())
        font = self.closedToggle.GetFont()
        if PLATFORM in ['win32', 'linux2']:
            font = wx.Font(8, wx.FONTFAMILY_DEFAULT, wx.NORMAL, wx.NORMAL)
        self.closedToggle.SetFont(font)
        typeBox.Add(self.closedToggle, wx.CENTER|wx.RIGHT, 5 )
        box.Add(typeBox, 0, wx.CENTER|wx.ALL, 5)

        self.notebook = wx.Notebook(self, -1, style=wx.BK_DEFAULT | wx.EXPAND)
        self.notebook.SetBackgroundColour(BACKGROUND_COLOUR)
        self.drawing = DrawingParameters(self.notebook)
        self.playback = PlaybackParameters(self.notebook)
        self.notebook.AddPage(self.drawing, "Drawing")
        self.notebook.AddPage(self.playback, "Playback")
        box.Add(self.notebook, 0, wx.ALL, 5)

        box.Add(wx.StaticText(self, -1, "Global amplitude (dB)"), 0, wx.LEFT | wx.TOP, 10)
        ampBox = wx.BoxSizer(wx.HORIZONTAL)
        self.sl_amp = ControlSlider(self, -60, 18, 0, size=(200, 16), outFunction=self.handleAmp)
        ampBox.Add(self.sl_amp, 0, wx.LEFT | wx.RIGHT, 5)
        box.Add(ampBox, 0, wx.LEFT | wx.RIGHT, 5)
        box.AddSpacer(10)
        self.meter = VuMeter(self, size=(200,11))
        self.meter.setNumSliders(self.nchnls)
        box.Add(self.meter, 0, wx.LEFT, 10)
        box.AddSpacer(5)

        box.Add(wx.StaticLine(self, size=(210, 1)), 0, wx.ALL, 5)

        box.Add(wx.StaticText(self, -1, "Project Settings"), 0, wx.CENTER | wx.ALL, 5)

        projSettingsBox = wx.BoxSizer(wx.HORIZONTAL)
        srBox = wx.BoxSizer(wx.VERTICAL)
        srText = wx.StaticText(self, -1, "Sample Rate")
        srBox.Add(srText, 0, wx.CENTER | wx.LEFT | wx.RIGHT, 5)
        self.pop_sr = wx.Choice(self, -1, choices = ['44100', '48000', '96000'], size=(80,-1))
        self.pop_sr.SetSelection(0)
        self.pop_sr.Bind(wx.EVT_CHOICE, self.handleSamplingRate)
        srBox.Add(self.pop_sr, 0, wx.LEFT | wx.RIGHT, 5)
        chnlsBox = wx.BoxSizer(wx.VERTICAL)
        chnlsText = wx.StaticText(self, -1, "Channels")
        chnlsBox.Add(chnlsText, 0, wx.CENTER  | wx.LEFT | wx.RIGHT, 5)
        self.tx_chnls = wx.TextCtrl(self, -1, "2", size=(80, -1), style=wx.TE_PROCESS_ENTER)
        self.tx_chnls.Bind(wx.EVT_TEXT_ENTER, self.handleNchnls)
        chnlsBox.Add(self.tx_chnls, 0, wx.LEFT | wx.RIGHT, 5)
        projSettingsBox.Add(srBox, 0, wx.LEFT | wx.RIGHT | wx.BOTTOM, 5)
        projSettingsBox.Add(chnlsBox, 0, wx.LEFT | wx.RIGHT | wx.BOTTOM, 5)
        box.Add(projSettingsBox, 0, wx.ALIGN_CENTER, 5)

        box.Add(wx.StaticLine(self, size=(210, 1)), 0, wx.ALL, 5)

        soundBox = wx.BoxSizer(wx.HORIZONTAL)
        self.tog_audio = wx.ToggleButton(self, -1, "Start", size=(80,-1))
        self.tog_audio.SetFont(font)
        self.tog_audio.Disable()
        soundBox.Add(self.tog_audio, 0, wx.CENTER |  wx.LEFT | wx.RIGHT, 5)
        box.Add(soundBox, 0, wx.CENTER | wx.ALL, 5)

        box.Add(wx.StaticLine(self, size=(210, 1)), 0, wx.ALL, 5)

        box.Add(wx.StaticText(self, -1, "Record Settings"), 0, wx.CENTER | wx.ALL, 5)

        recSettingsBox = wx.BoxSizer(wx.HORIZONTAL)
        fileformatBox = wx.BoxSizer(wx.VERTICAL)
        fileformatText = wx.StaticText(self, -1, "File Format")
        fileformatBox.Add(fileformatText, 0, wx.CENTER | wx.LEFT | wx.RIGHT, 5)
        self.pop_fileformat = wx.Choice(self, -1, choices=EXPORT_FORMATS, size=(80,-1))
        self.pop_fileformat.SetSelection(0)
        self.pop_fileformat.Bind(wx.EVT_CHOICE, self.handleFileFormat)
        fileformatBox.Add(self.pop_fileformat, 0, wx.LEFT | wx.RIGHT, 5)
        sampletypeBox = wx.BoxSizer(wx.VERTICAL)
        sampletypeText = wx.StaticText(self, -1, "Sample Type")
        sampletypeBox.Add(sampletypeText, 0, wx.CENTER  | wx.LEFT | wx.RIGHT, 5)
        self.pop_sampletype = wx.Choice(self, -1, choices=EXPORT_TYPES)
        self.pop_sampletype.SetSelection(0)
        self.pop_sampletype.Bind(wx.EVT_CHOICE, self.handleSampleType)
        sampletypeBox.Add(self.pop_sampletype, 0, wx.LEFT | wx.RIGHT, 5)
        recSettingsBox.Add(fileformatBox, 0, wx.LEFT | wx.RIGHT | wx.BOTTOM, 5)
        recSettingsBox.Add(sampletypeBox, 0, wx.LEFT | wx.RIGHT | wx.BOTTOM, 5)
        box.Add(recSettingsBox, 0, wx.ALIGN_CENTER | wx.BOTTOM, 5)

        rec1Box = wx.BoxSizer(wx.HORIZONTAL)

        self.tx_rec_folder = wx.TextCtrl( self, -1, "~/Desktop", size=(120, -1))
        rec1Box.Add(self.tx_rec_folder, 0, wx.LEFT | wx.RIGHT, 10)
        self.but_folder = wx.ToggleButton(self, -1, "Choose", size=(65,-1))
        self.but_folder.SetFont(font)
        rec1Box.Add(self.but_folder, 1, wx.ALIGN_CENTER_VERTICAL | wx.EXPAND | wx.RIGHT, 10)

        rec2Box = wx.BoxSizer(wx.HORIZONTAL)

        self.tx_output = wx.TextCtrl( self, -1, "snd", size=(120, -1))
        rec2Box.Add(self.tx_output, 0, wx.LEFT | wx.RIGHT, 10)
        self.tog_record = wx.ToggleButton(self, -1, "Start Rec", size=(65,-1))
        self.tog_record.SetFont(font)
        rec2Box.Add(self.tog_record, 1, wx.ALIGN_CENTER_VERTICAL | wx.EXPAND | wx.RIGHT, 10)
        
        box.Add(wx.StaticText(self, -1, "Destination"), 0, wx.LEFT | wx.RIGHT, 17)
        box.Add(rec1Box, 0, wx.EXPAND | wx.BOTTOM  | wx.LEFT | wx.RIGHT, 5)
        box.Add(wx.StaticText(self, -1, "Filename"), 0, wx.LEFT | wx.RIGHT, 17)
        box.Add(rec2Box, 0, wx.EXPAND | wx.BOTTOM  | wx.LEFT | wx.RIGHT, 5)


        self.Bind(wx.EVT_CHOICE, self.handleType, self.trajType)
        self.Bind(wx.EVT_TOGGLEBUTTON, self.handleClosed, self.closedToggle)
        self.Bind(wx.EVT_TOGGLEBUTTON, self.handleAudio, self.tog_audio)
        self.tx_output.Bind(wx.EVT_CHAR, self.handleOutput)
        self.tx_rec_folder.Bind(wx.EVT_CHAR, self.handleOutput)
        self.Bind(wx.EVT_TOGGLEBUTTON, self.handleRecord, self.tog_record)
        self.Bind(wx.EVT_TOGGLEBUTTON, self.chooseRecFolder, self.but_folder)

        self.SetAutoLayout(True)

        self.SetSizer(box)
        self.SetBestSize()
        self.SetupScrolling(scroll_x = False)
Example #3
0
class ControlPanel(scrolled.ScrolledPanel):
    def __init__(self, parent, surface):
        scrolled.ScrolledPanel.__init__(self, parent, -1)
        self.SetBackgroundColour(BACKGROUND_COLOUR)
        self.parent = parent
        self.surface = surface
        self.type = 0
        self.selected = 0
        self.selectedOkToChange = True
        self.sndPath = ""
        self.sndDur = 0.0
        self.amplitude = 1
        self.nchnls = 2
        self.samplingRate = 44100
        self.fileformat = 0
        self.sampletype = 0
        self.tempState = None

        box = wx.BoxSizer(wx.VERTICAL)

        box.Add(wx.StaticText(self, -1, "Trajectories"), 0, wx.CENTER | wx.TOP,
                3)

        typeBox = wx.BoxSizer(wx.HORIZONTAL)
        popupBox = wx.BoxSizer(wx.VERTICAL)
        self.trajType = wx.Choice(self,
                                  -1,
                                  choices=['Free', 'Circle', 'Oscil', 'Line'])
        self.trajType.SetSelection(0)
        popupBox.Add(self.trajType)
        typeBox.Add(popupBox, 0, wx.CENTER | wx.RIGHT, 5)

        # TODO: Check the size of this button on Windows and OSX
        self.closedToggle = wx.ToggleButton(self,
                                            -1,
                                            'Closed',
                                            size=self.trajType.GetSize())
        font = self.closedToggle.GetFont()
        if PLATFORM.startswith('linux') or PLATFORM == 'win32':
            font = wx.Font(8, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL,
                           wx.FONTWEIGHT_NORMAL)
        self.closedToggle.SetFont(font)
        typeBox.Add(self.closedToggle, wx.CENTER | wx.RIGHT, 5)
        box.Add(typeBox, 0, wx.CENTER | wx.ALL, 5)

        self.notebook = wx.Notebook(self, -1, style=wx.BK_DEFAULT | wx.EXPAND)
        self.notebook.SetBackgroundColour(BACKGROUND_COLOUR)
        self.drawing = DrawingParameters(self.notebook)
        self.playback = PlaybackParameters(self.notebook)
        self.notebook.AddPage(self.drawing, "Drawing")
        self.notebook.AddPage(self.playback, "Playback")
        box.Add(self.notebook, 0, wx.ALL, 5)

        # EQ
        eqTitle = wx.StaticText(self, id=-1, label="4 Bands Equalizer")
        box.Add(eqTitle, 0, wx.CENTER)

        eqFreqBox = wx.BoxSizer(wx.HORIZONTAL)
        self.knobEqF1 = ControlKnob(self,
                                    40,
                                    250,
                                    100,
                                    label='Freq 1',
                                    outFunction=self.changeEqF1)
        eqFreqBox.Add(self.knobEqF1, 0, wx.LEFT | wx.RIGHT, 20)
        self.knobEqF1.setFloatPrecision(2)
        self.knobEqF2 = ControlKnob(self,
                                    300,
                                    1000,
                                    500,
                                    label='Freq 2',
                                    outFunction=self.changeEqF2)
        eqFreqBox.Add(self.knobEqF2, 0, wx.LEFT | wx.RIGHT, 4)
        self.knobEqF2.setFloatPrecision(2)
        self.knobEqF3 = ControlKnob(self,
                                    1200,
                                    5000,
                                    2000,
                                    label='Freq 3',
                                    outFunction=self.changeEqF3)
        eqFreqBox.Add(self.knobEqF3, 0, wx.LEFT | wx.RIGHT, 20)
        self.knobEqF3.setFloatPrecision(2)

        box.Add(eqFreqBox)

        eqGainBox = wx.BoxSizer(wx.HORIZONTAL)
        self.knobEqA1 = ControlKnob(self,
                                    -40,
                                    18,
                                    0,
                                    label='B1 gain',
                                    outFunction=self.changeEqA1)
        eqGainBox.Add(self.knobEqA1, 0, wx.LEFT | wx.RIGHT, 5)
        self.knobEqA2 = ControlKnob(self,
                                    -40,
                                    18,
                                    0,
                                    label='B2 gain',
                                    outFunction=self.changeEqA2)
        eqGainBox.Add(self.knobEqA2, 0, wx.LEFT | wx.RIGHT, 5)
        self.knobEqA3 = ControlKnob(self,
                                    -40,
                                    18,
                                    0,
                                    label='B3 gain',
                                    outFunction=self.changeEqA3)
        eqGainBox.Add(self.knobEqA3, 0, wx.LEFT | wx.RIGHT, 5)
        self.knobEqA4 = ControlKnob(self,
                                    -40,
                                    18,
                                    0,
                                    label='B4 gain',
                                    outFunction=self.changeEqA4)
        eqGainBox.Add(self.knobEqA4, 0, wx.LEFT | wx.RIGHT, 5)

        box.Add(eqGainBox)

        box.Add(wx.StaticLine(self, size=(210, 1)), 0, wx.ALL, 5)

        #Compress
        compTitle = wx.StaticText(self, id=-1, label="Dynamic Compressor")
        box.Add(compTitle, 0, wx.CENTER)

        cpKnobBox = wx.BoxSizer(wx.HORIZONTAL)
        self.knobComp1 = ControlKnob(self,
                                     -60,
                                     0,
                                     -3,
                                     label='Thresh',
                                     outFunction=self.changeComp1)
        cpKnobBox.Add(self.knobComp1, 0, wx.LEFT | wx.RIGHT, 5)
        self.knobComp2 = ControlKnob(self,
                                     1,
                                     10,
                                     2,
                                     label='Ratio',
                                     outFunction=self.changeComp2)
        cpKnobBox.Add(self.knobComp2, 0, wx.LEFT | wx.RIGHT, 5)
        self.knobComp3 = ControlKnob(self,
                                     0.001,
                                     0.5,
                                     0.05,
                                     label='Rise',
                                     outFunction=self.changeComp3)
        cpKnobBox.Add(self.knobComp3, 0, wx.LEFT | wx.RIGHT, 5)
        self.knobComp4 = ControlKnob(self,
                                     0.01,
                                     1,
                                     .2,
                                     label='Fall',
                                     outFunction=self.changeComp4)
        cpKnobBox.Add(self.knobComp4, 0, wx.LEFT | wx.RIGHT, 5)

        box.Add(cpKnobBox)

        box.Add(wx.StaticLine(self, size=(210, 1)), 0, wx.ALL, 5)

        box.Add(wx.StaticText(self, -1, "Global amplitude (dB)"), 0,
                wx.LEFT | wx.TOP, 10)
        ampBox = wx.BoxSizer(wx.HORIZONTAL)
        self.sl_amp = ControlSlider(self,
                                    -60,
                                    18,
                                    0,
                                    size=(200, 16),
                                    outFunction=self.handleAmp)
        ampBox.Add(self.sl_amp, 0, wx.LEFT | wx.RIGHT, 5)
        box.Add(ampBox, 0, wx.LEFT | wx.RIGHT, 5)
        box.AddSpacer(10)
        self.meter = VuMeter(self, size=(200, 11))
        self.meter.setNumSliders(self.nchnls)
        box.Add(self.meter, 0, wx.LEFT, 10)
        box.AddSpacer(5)

        box.Add(wx.StaticLine(self, size=(210, 1)), 0, wx.ALL, 5)

        box.Add(wx.StaticText(self, -1, "Project Settings"), 0,
                wx.CENTER | wx.ALL, 5)

        projSettingsBox = wx.BoxSizer(wx.HORIZONTAL)
        srBox = wx.BoxSizer(wx.VERTICAL)
        srText = wx.StaticText(self, -1, "Rate")
        srBox.Add(srText, 0, wx.CENTER | wx.LEFT | wx.RIGHT, 5)
        self.pop_sr = wx.Choice(self,
                                -1,
                                choices=['44100', '48000', '96000'],
                                size=(80, -1))
        self.pop_sr.SetSelection(0)
        self.pop_sr.Bind(wx.EVT_CHOICE, self.handleSamplingRate)
        srBox.Add(self.pop_sr, 0, wx.LEFT | wx.RIGHT, 5)
        chnlsBox = wx.BoxSizer(wx.VERTICAL)
        chnlsText = wx.StaticText(self, -1, "Chnls")
        chnlsBox.Add(chnlsText, 0, wx.CENTER | wx.LEFT | wx.RIGHT, 5)
        self.tx_chnls = wx.TextCtrl(self,
                                    -1,
                                    "2",
                                    size=(60, -1),
                                    style=wx.TE_PROCESS_ENTER)
        self.tx_chnls.Bind(wx.EVT_TEXT_ENTER, self.handleNchnls)
        chnlsBox.Add(self.tx_chnls, 0, wx.LEFT | wx.RIGHT, 5)
        projSettingsBox.Add(srBox, 0, wx.LEFT | wx.RIGHT | wx.BOTTOM, 5)
        projSettingsBox.Add(chnlsBox, 0, wx.LEFT | wx.RIGHT | wx.BOTTOM, 5)
        box.Add(projSettingsBox, 0, wx.ALIGN_CENTER, 5)

        box.Add(wx.StaticLine(self, size=(210, 1)), 0, wx.ALL, 5)

        soundBox = wx.BoxSizer(wx.HORIZONTAL)
        self.tog_audio = wx.ToggleButton(self, -1, "Start", size=(80, -1))
        self.tog_audio.SetFont(font)
        self.tog_audio.Disable()
        soundBox.Add(self.tog_audio, 0, wx.CENTER | wx.LEFT | wx.RIGHT, 5)
        box.Add(soundBox, 0, wx.CENTER | wx.ALL, 5)

        box.Add(wx.StaticLine(self, size=(210, 1)), 0, wx.ALL, 5)

        box.Add(wx.StaticText(self, -1, "Record Settings"), 0,
                wx.CENTER | wx.ALL, 5)

        recSettingsBox = wx.BoxSizer(wx.HORIZONTAL)
        fileformatBox = wx.BoxSizer(wx.VERTICAL)
        fileformatText = wx.StaticText(self, -1, "Format")
        fileformatBox.Add(fileformatText, 0, wx.CENTER | wx.LEFT | wx.RIGHT, 5)
        self.pop_fileformat = wx.Choice(self,
                                        -1,
                                        choices=EXPORT_FORMATS,
                                        size=(80, -1))
        self.pop_fileformat.SetSelection(0)
        self.pop_fileformat.Bind(wx.EVT_CHOICE, self.handleFileFormat)
        fileformatBox.Add(self.pop_fileformat, 0, wx.LEFT | wx.RIGHT, 5)
        sampletypeBox = wx.BoxSizer(wx.VERTICAL)
        sampletypeText = wx.StaticText(self, -1, "Type")
        sampletypeBox.Add(sampletypeText, 0, wx.CENTER | wx.LEFT | wx.RIGHT, 5)
        self.pop_sampletype = wx.Choice(self, -1, choices=EXPORT_TYPES)
        self.pop_sampletype.SetSelection(0)
        self.pop_sampletype.Bind(wx.EVT_CHOICE, self.handleSampleType)
        sampletypeBox.Add(self.pop_sampletype, 0, wx.LEFT | wx.RIGHT, 5)
        recSettingsBox.Add(fileformatBox, 0, wx.LEFT | wx.RIGHT | wx.BOTTOM, 5)
        recSettingsBox.Add(sampletypeBox, 0, wx.LEFT | wx.RIGHT | wx.BOTTOM, 5)
        box.Add(recSettingsBox, 0, wx.ALIGN_CENTER | wx.BOTTOM, 5)

        rec1Box = wx.BoxSizer(wx.HORIZONTAL)

        self.tx_rec_folder = wx.TextCtrl(self, -1, "~/Desktop", size=(120, -1))
        rec1Box.Add(self.tx_rec_folder, 0, wx.LEFT | wx.RIGHT, 10)
        self.but_folder = wx.ToggleButton(self, -1, "Choose", size=(65, -1))
        self.but_folder.SetFont(font)
        rec1Box.Add(self.but_folder, 1,
                    wx.ALIGN_CENTER_VERTICAL | wx.EXPAND | wx.RIGHT, 10)

        rec2Box = wx.BoxSizer(wx.HORIZONTAL)

        self.tx_output = wx.TextCtrl(self, -1, "snd", size=(120, -1))
        rec2Box.Add(self.tx_output, 0, wx.LEFT | wx.RIGHT, 10)
        self.tog_record = wx.ToggleButton(self, -1, "Start Rec", size=(65, -1))
        self.tog_record.SetFont(font)
        rec2Box.Add(self.tog_record, 1,
                    wx.ALIGN_CENTER_VERTICAL | wx.EXPAND | wx.RIGHT, 10)

        box.Add(wx.StaticText(self, -1, "Destination"), 0, wx.LEFT | wx.RIGHT,
                17)
        box.Add(rec1Box, 0, wx.EXPAND | wx.BOTTOM | wx.LEFT | wx.RIGHT, 5)
        box.Add(wx.StaticText(self, -1, "Filename"), 0, wx.LEFT | wx.RIGHT, 17)
        box.Add(rec2Box, 0, wx.EXPAND | wx.BOTTOM | wx.LEFT | wx.RIGHT, 5)

        self.Bind(wx.EVT_CHOICE, self.handleType, self.trajType)
        self.Bind(wx.EVT_TOGGLEBUTTON, self.handleClosed, self.closedToggle)
        self.Bind(wx.EVT_TOGGLEBUTTON, self.handleAudio, self.tog_audio)
        self.tx_output.Bind(wx.EVT_CHAR, self.handleOutput)
        self.tx_rec_folder.Bind(wx.EVT_CHAR, self.handleOutput)
        self.Bind(wx.EVT_TOGGLEBUTTON, self.handleRecord, self.tog_record)
        self.Bind(wx.EVT_TOGGLEBUTTON, self.chooseRecFolder, self.but_folder)

        self.SetAutoLayout(True)
        self.SetSizerAndFit(box)
        self.SetupScrolling(scroll_x=False)

    def changeEqF1(self, x):
        self.parent.sg_audio.setEqFreq(0, x)

    def changeEqF2(self, x):
        self.parent.sg_audio.setEqFreq(1, x)

    def changeEqF3(self, x):
        self.parent.sg_audio.setEqFreq(2, x)

    def getEqFreqs(self):
        return [
            self.knobEqF1.GetValue(),
            self.knobEqF2.GetValue(),
            self.knobEqF3.GetValue()
        ]

    def setEqFreqs(self, freqs):
        self.knobEqF1.SetValue(freqs[0])
        self.knobEqF2.SetValue(freqs[1])
        self.knobEqF3.SetValue(freqs[2])

    def changeEqA1(self, x):
        self.parent.sg_audio.setEqGain(0, math.pow(10.0, x * 0.05))

    def changeEqA2(self, x):
        self.parent.sg_audio.setEqGain(1, math.pow(10.0, x * 0.05))

    def changeEqA3(self, x):
        self.parent.sg_audio.setEqGain(2, math.pow(10.0, x * 0.05))

    def changeEqA4(self, x):
        self.parent.sg_audio.setEqGain(3, math.pow(10.0, x * 0.05))

    def getEqAmps(self):
        return [
            self.knobEqA1.GetValue(),
            self.knobEqA2.GetValue(),
            self.knobEqA3.GetValue(),
            self.knobEqA4.GetValue()
        ]

    def setEqAmps(self, amps):
        self.knobEqA1.SetValue(amps[0])
        self.knobEqA2.SetValue(amps[1])
        self.knobEqA3.SetValue(amps[2])
        self.knobEqA4.SetValue(amps[3])

    def changeComp1(self, x):
        self.parent.sg_audio.setCompParam("thresh", x)

    def changeComp2(self, x):
        self.parent.sg_audio.setCompParam("ratio", x)

    def changeComp3(self, x):
        self.parent.sg_audio.setCompParam("risetime", x)

    def changeComp4(self, x):
        self.parent.sg_audio.setCompParam("falltime", x)

    def getCompValues(self):
        return [
            self.knobComp1.GetValue(),
            self.knobComp2.GetValue(),
            self.knobComp3.GetValue(),
            self.knobComp4.GetValue()
        ]

    def setCompValues(self, vals):
        self.knobComp1.SetValue(vals[0])
        self.knobComp2.SetValue(vals[1])
        self.knobComp3.SetValue(vals[2])
        self.knobComp4.SetValue(vals[3])

    def checkEnableWidgets(self):
        if self.type == 0:
            self.closedToggle.Enable()
        else:
            self.closedToggle.Disable()
        if self.type == 2:
            self.drawing.sl_period.Enable()
            self.drawing.sl_scaling.Enable()
        else:
            self.drawing.sl_period.Disable()
            self.drawing.sl_scaling.Disable()

    # TODO: replace all these handle, get, set, with single event
    def handleType(self, event):
        self.processType(event.GetInt())

    def getType(self):
        return self.type

    def setType(self, type):
        self.trajType.SetSelection(type)
        self.processType(type)

    def processType(self, type):
        self.type = type
        self.surface.setMode(type)
        self.checkEnableWidgets()

    def handleClosed(self, event):
        self.surface.setClosed(event.GetInt())

    def getClosed(self):
        return self.closedToggle.GetValue()

    def setClosed(self, closed):
        self.closedToggle.SetValue(closed)
        self.surface.setClosed(closed)

    def handleCutoff(self, val):
        for traj in self.surface.getAllTrajectories():
            traj.setFilterFreq(val)

    def getCutoff(self):
        return self.drawing.sl_cutoff.GetValue()

    def setCutoff(self, cutoff):
        self.drawing.sl_cutoff.SetValue(cutoff)
        for traj in self.surface.getAllTrajectories():
            traj.setFilterFreq(cutoff)

    def handleQ(self, val):
        for traj in self.surface.getAllTrajectories():
            traj.setFilterQ(val)

    def getQ(self):
        return self.drawing.sl_q.GetValue()

    def setQ(self, q):
        self.drawing.sl_q.SetValue(q)
        for traj in self.surface.getAllTrajectories():
            traj.setFilterQ(q)

    def handlePeriod(self, val):
        self.surface.setOscilPeriod(val)

    def getPeriod(self):
        return self.surface.getOscilPeriod()

    def setPeriod(self, period):
        self.drawing.sl_period.SetValue(period)
        self.surface.setOscilPeriod(period)

    def handleScaling(self, val):
        self.surface.setOscilScaling(val)

    def getScaling(self):
        return self.surface.getOscilScaling()

    def setScaling(self, scaling):
        self.drawing.sl_scaling.SetValue(scaling)
        self.surface.setOscilScaling(scaling)

    def resetPlaybackSliders(self):
        selToMax = False
        if self.selected == MAX_STREAMS:
            self.selected = 0
            selToMax = True
        timeSpeed = self.surface.getTrajectory(self.selected).getTimeSpeed()
        self.setTimerSpeed(timeSpeed)
        step = self.surface.getTrajectory(self.selected).getStep()
        self.setStep(step)
        amp = self.surface.getTrajectory(self.selected).getAmplitude()
        self.setTrajAmp(amp)
        if selToMax:
            self.selected = MAX_STREAMS
        self.surface.needBitmap = True

    def handleSelected(self, event):
        if event.GetInt() != self.selected:
            self.selected = event.GetInt()
            self.selectedOkToChange = False
            if self.selected == MAX_STREAMS:
                self.selectedOkToChange = False
            self.resetPlaybackSliders()

    def setSelected(self, selected):
        self.playback.tog_traj.SetSelection(selected)
        self.selected = selected
        self.surface.setSelectedById(selected)
        self.resetPlaybackSliders()

    def getSelected(self):
        return self.selected

    def handlePopupFocus(self, evt):
        self.selectedOkToChange = False
        evt.Skip()

    def handleTimerSpeed(self, val):
        if self.selectedOkToChange:
            if self.selected == MAX_STREAMS:
                for t in self.surface.getActiveTrajectories():
                    t.setTimeSpeed(val)
            else:
                self.surface.getTrajectory(self.selected).setTimeSpeed(val)
        else:
            self.selectedOkToChange = True

    def setTimerSpeed(self, timeSpeed):
        self.playback.sl_timespeed.SetValue(timeSpeed, self.selectedOkToChange)

    def sendTrajSpeed(self, which, speed):
        self.parent.sg_audio.setMetroTime(which, speed * 0.001)

    def handleStep(self, val):
        if self.selectedOkToChange:
            if self.selected == MAX_STREAMS:
                for t in self.surface.getActiveTrajectories():
                    t.setStep(val)
            else:
                self.surface.getTrajectory(self.selected).setStep(val)
        else:
            self.selectedOkToChange = True

    def setStep(self, step):
        self.playback.sl_step.SetValue(step, self.selectedOkToChange)

    def handleTrajAmp(self, val):
        val = pow(10.0, float(val) * 0.05)
        if self.selectedOkToChange:
            if self.selected == MAX_STREAMS:
                for t in self.surface.getActiveTrajectories():
                    t.setAmplitude(val)
                    self.parent.sg_audio.setTrajAmplitude(t.label - 1, val)
            else:
                self.surface.getTrajectory(self.selected).setAmplitude(val)
                self.parent.sg_audio.setTrajAmplitude(self.selected, val)
        else:
            self.selectedOkToChange = True

    def setTrajAmp(self, val):
        if val <= 0.0:
            val = 0.0001
        self.playback.sl_amp.SetValue(20.0 * math.log10(val),
                                      self.selectedOkToChange)

    def handleAmp(self, val):
        self.amplitude = pow(10.0, float(val) * 0.05)
        self.sendAmp()

    def getAmp(self):
        return self.amplitude

    def setAmp(self, amp):
        if amp <= 0.0:
            amp = 0.0001
        self.sl_amp.SetValue(20.0 * math.log10(amp))
        self.amplitude = amp

    def sendAmp(self):
        self.parent.sg_audio.setGlobalAmp(self.amplitude)

    def handleLoad(self):
        dlg = wx.FileDialog(self,
                            message="Choose a sound file",
                            defaultDir=self.parent.lastAudioPath,
                            wildcard=AUDIO_WILDCARD,
                            style=wx.FD_OPEN)
        if dlg.ShowModal() == wx.ID_OK:
            sndPath = dlg.GetPath()
            self.loadSound(ensureNFD(sndPath))
            self.parent.lastAudioPath = os.path.split(sndPath)[0]
        dlg.Destroy()

    def handleInsert(self):
        ok = False
        dlg = wx.FileDialog(self,
                            message="Choose a sound file to insert",
                            defaultDir=self.parent.lastAudioPath,
                            wildcard=AUDIO_WILDCARD,
                            style=wx.FD_OPEN)
        if dlg.ShowModal() == wx.ID_OK:
            ok = True
            sndPath = dlg.GetPath()
            self.parent.lastAudioPath = os.path.split(sndPath)[0]
        dlg.Destroy()
        if ok:
            self.insertSound(ensureNFD(sndPath), True)

    def loadSound(self, sndPath, force=False):
        if sndPath:
            if os.path.isfile(sndPath):
                self.sndPath = sndPath
                self.parent.sg_audio.loadSnd(self.sndPath)
                chnls, samprate, dur = soundInfo(self.sndPath)
                self.sndDur = dur
                self.chnls = chnls
                self.sndInfoStr = u'Loaded sound: %s,  Sr: %i Hz,  Channels: %s,  Duration: %.3f sec' % (
                    self.sndPath, int(samprate), chnls, dur)
                if self.parent.draw:
                    if not self.sndPath in self.surface.bitmapDict.keys(
                    ) or force:
                        self.parent.log("Drawing waveform...")
                        self.surface.analyse(self.sndPath)
                    else:
                        self.surface.list = self.surface.bitmapDict[
                            self.sndPath]
                        self.surface.create_bitmap()
                self.logSndInfo()
            elif os.path.isfile(
                    os.path.join(self.parent.currentPath,
                                 os.path.split(sndPath)[1])):
                self.loadSound(
                    os.path.join(self.parent.currentPath,
                                 os.path.split(sndPath)[1]), force)
            elif ":\\" in sndPath:
                # Handle windows path...
                self.loadSound(
                    os.path.join(self.parent.currentPath,
                                 sndPath.split("\\")[-1]), force)
            else:
                self.parent.log('Sound file "%s" does not exist!' % sndPath)
        else:
            self.parent.log("")

    def insertSound(self, sndPath, force=False):
        if not self.sndPath:
            self.loadSound(sndPath)
            return
        if sndPath:
            if os.path.isfile(sndPath):
                self.sndPath = "Mixed sound " + str(random.randint(0, 10000))
                chnls, samprate, dur = soundInfo(sndPath)
                dlg = InsertDialog(self,
                                   -1,
                                   'Insert sound settings',
                                   actual_dur=self.sndDur,
                                   snd_dur=dur)
                refpos = self.surface.GetPosition()
                refsize = self.surface.GetSize()
                dlgsize = dlg.GetSize()
                X = refpos[0] + (refsize[0] / 2 - dlgsize[0] / 2)
                Y = refpos[1] + (refsize[1] / 2 - dlgsize[1] / 2)
                dlg.SetPosition((X, Y))
                if dlg.ShowModal() == wx.ID_OK:
                    start, end, point, cross = dlg.getValues()
                    ok = True
                else:
                    ok = False
                dlg.Destroy()
                if not ok:
                    return
                self.parent.sg_audio.insertSnd(sndPath, start, end, point,
                                               cross)
                self.sndDur = self.parent.sg_audio.getTableDuration()
                self.sndInfoStr = u'Loaded sound: %s,    Sr: %s Hz,    Channels: %s,    Duration: %s sec' % (
                    self.sndPath, samprate, self.chnls, self.sndDur)
                if self.parent.draw:
                    if not self.sndPath in self.surface.bitmapDict.keys(
                    ) or force:
                        self.parent.log("Drawing waveform...")
                        self.surface.analyse(self.sndPath)
                    else:
                        self.surface.list = self.surface.bitmapDict[
                            self.sndPath]
                        self.surface.create_bitmap()
                self.logSndInfo()
            elif os.path.isfile(
                    os.path.join(self.parent.currentPath,
                                 os.path.split(sndPath)[1])):
                self.insertSound(
                    os.path.join(self.parent.currentPath,
                                 os.path.split(sndPath)[1]), force)
            elif ":\\" in sndPath:
                # Handle windows path...
                self.insertSound(
                    os.path.join(self.parent.currentPath,
                                 sndPath.split("\\")[-1]), force)
            else:
                self.parent.log('Sound file "%s" does not exist!' % sndPath)

    def drawWaveform(self):
        if self.surface.sndBitmap and self.parent.draw:
            self.surface.analyse(self.sndPath)

    def getNchnls(self):
        return self.nchnls

    def setNchnls(self, x):
        if x != self.nchnls:
            self.nchnls = x
            self.tx_chnls.SetValue(str(x))
            self.meter.setNumSliders(self.nchnls)
            self.shutdownServer()
            self.bootServer()

    def handleNchnls(self, event):
        x = int(self.tx_chnls.GetValue())
        if x != self.nchnls:
            status, path = self.parent.checkForMixedSound()
            if not status:
                self.tx_chnls.SetValue(str(self.nchnls))
                return
            if "Mixed sound" in self.sndPath:
                self.sndPath = path
            self.nchnls = x
            self.meter.setNumSliders(self.nchnls)
            self.shutdownServer()
            self.bootServer()

    def getSamplingRate(self):
        return self.samplingRate

    def setSamplingRate(self, x):
        SR = {44100: 0, 48000: 1, 96000: 2}
        if x != self.samplingRate:
            self.samplingRate = x
            self.pop_sr.SetSelection(SR[self.samplingRate])
            self.shutdownServer()
            self.bootServer()

    def handleSamplingRate(self, event):
        SR = {0: 44100, 1: 48000, 2: 96000}
        x = SR[event.GetInt()]
        if x != self.samplingRate:
            status, path = self.parent.checkForMixedSound()
            if not status:
                SR = {44100: 0, 48000: 1, 96000: 2}
                self.pop_sr.SetSelection(SR[self.samplingRate])
                return
            if "Mixed sound" in self.sndPath:
                self.sndPath = path
            self.samplingRate = x
            self.shutdownServer()
            self.bootServer()

    def getFileFormat(self):
        return self.fileformat

    def setFileFormat(self, x):
        self.fileformat = x
        self.pop_fileformat.SetSelection(self.fileformat)

    def handleFileFormat(self, event):
        self.fileformat = event.GetInt()

    def getSampleType(self):
        return self.sampletype

    def setSampleType(self, x):
        self.sampletype = x
        self.pop_sampletype.SetSelection(self.sampletype)

    def handleSampleType(self, event):
        self.sampletype = event.GetInt()

    def bootServer(self):
        self.parent.sg_audio.boot(self.parent.audioDriver, self.nchnls,
                                  self.samplingRate)
        self.tog_audio.Enable()
        if self.sndPath != "" and self.tempState == None:
            self.loadSound(self.sndPath)
        if self.tempState != None:
            self.parent.setState(self.tempState)
            self.tempState = None

    def shutdownServer(self):
        self.tempState = self.parent.getState()
        self.parent.sg_audio.shutdown()
        self.tog_audio.Disable()
        self.surface.Refresh()

    def handleAudio(self, event):
        if event.GetInt() == 1:
            if self.sndPath == "":
                self.parent.log('*** No sound loaded! ***')
                self.tog_audio.SetValue(0)
                self.parent.menu.Check(7, False)
            else:
                self.tx_chnls.Disable()
                self.tx_chnls.SetBackgroundColour("#EEEEEE")
                self.pop_sr.Disable()
                self.parent.enableDrivers(False)
                self.tog_audio.SetLabel('Stop')
                self.tog_audio.SetValue(1)
                self.parent.menu.Check(7, True)

                for t in self.surface.getAllTrajectories():
                    t.initCounter()
                self.parent.sg_audio.start()
        else:
            self.tx_chnls.Enable()
            self.tx_chnls.SetBackgroundColour("#FFFFFF")
            self.pop_sr.Enable()
            self.parent.enableDrivers(True)
            self.tog_audio.SetLabel('Start')
            self.tog_audio.SetValue(0)
            self.parent.menu.Check(7, False)
            self.tog_record.SetValue(0)
            self.tog_record.SetLabel('Start Rec')
            self.parent.sg_audio.stop()

    def handleOutput(self, event):
        key = event.GetKeyCode()
        if key == wx.WXK_TAB or key == wx.WXK_RETURN:
            self.surface.SetFocus()
        event.Skip()

    def setRecordFolder(self, str):
        self.tx_rec_folder.SetValue(str)

    def setRecordFilename(self, str):
        self.tx_output.SetValue(str)

    def handleRecord(self, event):
        if event.GetInt() == 1:
            folder = self.tx_rec_folder.GetValue()
            if folder.startswith("~"):
                folder = folder.replace("~", os.path.expanduser("~"), 1)
            if os.path.isdir(folder):
                filename = os.path.join(folder, self.tx_output.GetValue())
            else:
                filename = os.path.join(os.path.expanduser('~'), "Desktop",
                                        self.tx_output.GetValue())
            self.parent.sg_audio.recStart(filename, self.fileformat,
                                          self.sampletype)
            self.tog_record.SetLabel('Stop Rec')
        else:
            self.tog_record.SetLabel('Start Rec')
            self.parent.sg_audio.recStop()

    def chooseRecFolder(self, evt):
        dlg = wx.DirDialog(
            self,
            message="Choose a folder to save Soundgrain's output sounds...",
            defaultPath=os.path.expanduser("~"))
        if dlg.ShowModal() == wx.ID_OK:
            path = dlg.GetPath()
            self.tx_rec_folder.SetValue(ensureNFD(path))
        dlg.Destroy()
        self.but_folder.SetValue(0)

    def logSndInfo(self):
        self.parent.log(self.sndInfoStr)
Example #4
0
class ControlPanel(scrolled.ScrolledPanel):
    def __init__(self, parent, surface):
        scrolled.ScrolledPanel.__init__(self, parent, -1)
        self.SetBackgroundColour(BACKGROUND_COLOUR)
        self.parent = parent
        self.surface = surface
        self.type = 0
        self.selected = 0
        self.selectedOkToChange = True
        self.sndPath = ""
        self.sndDur = 0.0
        self.amplitude = 1
        self.nchnls = 2
        self.samplingRate = 44100
        self.midiInterface = None
        self.fileformat = 0
        self.sampletype = 0
        self.tempState = None

        box = wx.BoxSizer(wx.VERTICAL)

        box.Add(wx.StaticText(self, -1, "Trajectories"), 0, wx.CENTER|wx.TOP, 3)

        typeBox = wx.BoxSizer(wx.HORIZONTAL)
        popupBox = wx.BoxSizer(wx.VERTICAL)
        self.trajType = wx.Choice(self, -1, choices = ['Free', 'Circle', 'Oscil', 'Line'])
        self.trajType.SetSelection(0)
        popupBox.Add(self.trajType)
        typeBox.Add(popupBox, 0, wx.CENTER|wx.RIGHT, 5)

        # TODO: Check the size of this button on Windows and OSX
        self.closedToggle = wx.ToggleButton(self, -1, 'Closed', size=self.trajType.GetSize())
        font = self.closedToggle.GetFont()
        if PLATFORM in ['win32', 'linux2']:
            font = wx.Font(8, wx.FONTFAMILY_DEFAULT, wx.NORMAL, wx.NORMAL)
        self.closedToggle.SetFont(font)
        typeBox.Add(self.closedToggle, wx.CENTER|wx.RIGHT, 5 )
        box.Add(typeBox, 0, wx.CENTER|wx.ALL, 5)

        self.notebook = wx.Notebook(self, -1, style=wx.BK_DEFAULT | wx.EXPAND)
        self.notebook.SetBackgroundColour(BACKGROUND_COLOUR)
        self.drawing = DrawingParameters(self.notebook)
        self.playback = PlaybackParameters(self.notebook)
        self.notebook.AddPage(self.drawing, "Drawing")
        self.notebook.AddPage(self.playback, "Playback")
        box.Add(self.notebook, 0, wx.ALL, 5)

        box.Add(wx.StaticText(self, -1, "Global amplitude (dB)"), 0, wx.LEFT | wx.TOP, 10)
        ampBox = wx.BoxSizer(wx.HORIZONTAL)
        self.sl_amp = ControlSlider(self, -60, 18, 0, size=(200, 16), outFunction=self.handleAmp)
        ampBox.Add(self.sl_amp, 0, wx.LEFT | wx.RIGHT, 5)
        box.Add(ampBox, 0, wx.LEFT | wx.RIGHT, 5)
        box.AddSpacer(10)
        self.meter = VuMeter(self, size=(200,11))
        self.meter.setNumSliders(self.nchnls)
        box.Add(self.meter, 0, wx.LEFT, 10)
        box.AddSpacer(5)

        box.Add(wx.StaticLine(self, size=(210, 1)), 0, wx.ALL, 5)

        box.Add(wx.StaticText(self, -1, "Project Settings"), 0, wx.CENTER | wx.ALL, 5)

        projSettingsBox = wx.BoxSizer(wx.HORIZONTAL)
        srBox = wx.BoxSizer(wx.VERTICAL)
        srText = wx.StaticText(self, -1, "Sample Rate")
        srBox.Add(srText, 0, wx.CENTER | wx.LEFT | wx.RIGHT, 5)
        self.pop_sr = wx.Choice(self, -1, choices = ['44100', '48000', '96000'], size=(80,-1))
        self.pop_sr.SetSelection(0)
        self.pop_sr.Bind(wx.EVT_CHOICE, self.handleSamplingRate)
        srBox.Add(self.pop_sr, 0, wx.LEFT | wx.RIGHT, 5)
        chnlsBox = wx.BoxSizer(wx.VERTICAL)
        chnlsText = wx.StaticText(self, -1, "Channels")
        chnlsBox.Add(chnlsText, 0, wx.CENTER  | wx.LEFT | wx.RIGHT, 5)
        self.tx_chnls = wx.TextCtrl(self, -1, "2", size=(80, -1), style=wx.TE_PROCESS_ENTER)
        self.tx_chnls.Bind(wx.EVT_TEXT_ENTER, self.handleNchnls)
        chnlsBox.Add(self.tx_chnls, 0, wx.LEFT | wx.RIGHT, 5)
        projSettingsBox.Add(srBox, 0, wx.LEFT | wx.RIGHT | wx.BOTTOM, 5)
        projSettingsBox.Add(chnlsBox, 0, wx.LEFT | wx.RIGHT | wx.BOTTOM, 5)
        box.Add(projSettingsBox, 0, wx.ALIGN_CENTER, 5)

        box.Add(wx.StaticLine(self, size=(210, 1)), 0, wx.ALL, 5)

        soundBox = wx.BoxSizer(wx.HORIZONTAL)
        self.tog_audio = wx.ToggleButton(self, -1, "Start", size=(80,-1))
        self.tog_audio.SetFont(font)
        self.tog_audio.Disable()
        soundBox.Add(self.tog_audio, 0, wx.CENTER |  wx.LEFT | wx.RIGHT, 5)
        box.Add(soundBox, 0, wx.CENTER | wx.ALL, 5)

        box.Add(wx.StaticLine(self, size=(210, 1)), 0, wx.ALL, 5)

        box.Add(wx.StaticText(self, -1, "Record Settings"), 0, wx.CENTER | wx.ALL, 5)

        recSettingsBox = wx.BoxSizer(wx.HORIZONTAL)
        fileformatBox = wx.BoxSizer(wx.VERTICAL)
        fileformatText = wx.StaticText(self, -1, "File Format")
        fileformatBox.Add(fileformatText, 0, wx.CENTER | wx.LEFT | wx.RIGHT, 5)
        self.pop_fileformat = wx.Choice(self, -1, choices=EXPORT_FORMATS, size=(80,-1))
        self.pop_fileformat.SetSelection(0)
        self.pop_fileformat.Bind(wx.EVT_CHOICE, self.handleFileFormat)
        fileformatBox.Add(self.pop_fileformat, 0, wx.LEFT | wx.RIGHT, 5)
        sampletypeBox = wx.BoxSizer(wx.VERTICAL)
        sampletypeText = wx.StaticText(self, -1, "Sample Type")
        sampletypeBox.Add(sampletypeText, 0, wx.CENTER  | wx.LEFT | wx.RIGHT, 5)
        self.pop_sampletype = wx.Choice(self, -1, choices=EXPORT_TYPES)
        self.pop_sampletype.SetSelection(0)
        self.pop_sampletype.Bind(wx.EVT_CHOICE, self.handleSampleType)
        sampletypeBox.Add(self.pop_sampletype, 0, wx.LEFT | wx.RIGHT, 5)
        recSettingsBox.Add(fileformatBox, 0, wx.LEFT | wx.RIGHT | wx.BOTTOM, 5)
        recSettingsBox.Add(sampletypeBox, 0, wx.LEFT | wx.RIGHT | wx.BOTTOM, 5)
        box.Add(recSettingsBox, 0, wx.ALIGN_CENTER | wx.BOTTOM, 5)

        rec1Box = wx.BoxSizer(wx.HORIZONTAL)

        self.tx_rec_folder = wx.TextCtrl( self, -1, "~/Desktop", size=(120, -1))
        rec1Box.Add(self.tx_rec_folder, 0, wx.LEFT | wx.RIGHT, 10)
        self.but_folder = wx.ToggleButton(self, -1, "Choose", size=(65,-1))
        self.but_folder.SetFont(font)
        rec1Box.Add(self.but_folder, 1, wx.ALIGN_CENTER_VERTICAL | wx.EXPAND | wx.RIGHT, 10)

        rec2Box = wx.BoxSizer(wx.HORIZONTAL)

        self.tx_output = wx.TextCtrl( self, -1, "snd", size=(120, -1))
        rec2Box.Add(self.tx_output, 0, wx.LEFT | wx.RIGHT, 10)
        self.tog_record = wx.ToggleButton(self, -1, "Start Rec", size=(65,-1))
        self.tog_record.SetFont(font)
        rec2Box.Add(self.tog_record, 1, wx.ALIGN_CENTER_VERTICAL | wx.EXPAND | wx.RIGHT, 10)
        
        box.Add(wx.StaticText(self, -1, "Destination"), 0, wx.LEFT | wx.RIGHT, 17)
        box.Add(rec1Box, 0, wx.EXPAND | wx.BOTTOM  | wx.LEFT | wx.RIGHT, 5)
        box.Add(wx.StaticText(self, -1, "Filename"), 0, wx.LEFT | wx.RIGHT, 17)
        box.Add(rec2Box, 0, wx.EXPAND | wx.BOTTOM  | wx.LEFT | wx.RIGHT, 5)


        self.Bind(wx.EVT_CHOICE, self.handleType, self.trajType)
        self.Bind(wx.EVT_TOGGLEBUTTON, self.handleClosed, self.closedToggle)
        self.Bind(wx.EVT_TOGGLEBUTTON, self.handleAudio, self.tog_audio)
        self.tx_output.Bind(wx.EVT_CHAR, self.handleOutput)
        self.tx_rec_folder.Bind(wx.EVT_CHAR, self.handleOutput)
        self.Bind(wx.EVT_TOGGLEBUTTON, self.handleRecord, self.tog_record)
        self.Bind(wx.EVT_TOGGLEBUTTON, self.chooseRecFolder, self.but_folder)

        self.SetAutoLayout(True)

        self.SetSizer(box)
        self.SetBestSize()
        self.SetupScrolling(scroll_x = False)

    def checkEnableWidgets(self):
        if self.type == 0:
            self.closedToggle.Enable()
        else:
            self.closedToggle.Disable()
        if self.type == 2:
            self.drawing.sl_period.Enable()
            self.drawing.sl_scaling.Enable()
        else:
            self.drawing.sl_period.Disable()
            self.drawing.sl_scaling.Disable()

    # TODO: replace all these handle, get, set, with single event
    def handleType(self, event):
        self.processType(event.GetInt())

    def getType(self):
        return self.type

    def setType(self, type):
        self.trajType.SetSelection(type)
        self.processType(type)

    def processType(self, type):
        self.type = type
        self.surface.setMode(type)
        self.checkEnableWidgets()

    def handleClosed(self, event):
        self.surface.setClosed(event.GetInt())

    def getClosed(self):
        return self.closedToggle.GetValue()

    def setClosed(self, closed):
        self.closedToggle.SetValue(closed)
        self.surface.setClosed(closed)

    def handleCutoff(self, val):
        for traj in self.surface.getAllTrajectories():
            traj.setFilterFreq(val)

    def getCutoff(self):
        return self.drawing.sl_cutoff.GetValue()

    def setCutoff(self, cutoff):
        self.drawing.sl_cutoff.SetValue(cutoff)
        for traj in self.surface.getAllTrajectories():
            traj.setFilterFreq(cutoff)

    def handleQ(self, val):
        for traj in self.surface.getAllTrajectories():
            traj.setFilterQ(val)

    def getQ(self):
        return self.drawing.sl_q.GetValue()

    def setQ(self, q):
        self.drawing.sl_q.SetValue(q)
        for traj in self.surface.getAllTrajectories():
            traj.setFilterQ(q)

    def handlePeriod(self, val):
        self.surface.setOscilPeriod(val)

    def getPeriod(self):
        return self.surface.getOscilPeriod()

    def setPeriod(self, period):
        self.drawing.sl_period.SetValue(period)
        self.surface.setOscilPeriod(period)

    def handleScaling(self, val):
        self.surface.setOscilScaling(val)

    def getScaling(self):
        return self.surface.getOscilScaling()

    def setScaling(self, scaling):
        self.drawing.sl_scaling.SetValue(scaling)
        self.surface.setOscilScaling(scaling)

    def resetPlaybackSliders(self):
        selToMax = False
        if self.selected == MAX_STREAMS:
            self.selected = 0
            selToMax = True
        timeSpeed = self.surface.getTrajectory(self.selected).getTimeSpeed()
        self.setTimerSpeed(timeSpeed)
        step = self.surface.getTrajectory(self.selected).getStep()
        self.setStep(step)
        amp = self.surface.getTrajectory(self.selected).getAmplitude()
        self.setTrajAmp(amp)
        if selToMax:
            self.selected = MAX_STREAMS
        self.surface.needBitmap = True

    def handleSelected(self, event):
        if event.GetInt() != self.selected:
            self.selected = event.GetInt()
            self.selectedOkToChange = False
            if self.selected == MAX_STREAMS:
                self.selectedOkToChange = False
            self.resetPlaybackSliders()

    def setSelected(self, selected):
        self.playback.tog_traj.SetSelection(selected)
        self.selected = selected
        self.surface.setSelectedById(selected)
        self.resetPlaybackSliders()

    def getSelected(self):
        return self.selected

    def handlePopupFocus(self, evt):
        self.selectedOkToChange = False
        evt.Skip()

    def handleTimerSpeed(self, val):
        if self.selectedOkToChange:
            if self.selected == MAX_STREAMS:
                for t in self.surface.getActiveTrajectories():
                    t.setTimeSpeed(val)
            else:
                self.surface.getTrajectory(self.selected).setTimeSpeed(val)
        else:
            self.selectedOkToChange = True

    def setTimerSpeed(self, timeSpeed):
        self.playback.sl_timespeed.SetValue(timeSpeed, self.selectedOkToChange)

    def sendTrajSpeed(self, which, speed):
        self.parent.sg_audio.setMetroTime(which, speed * 0.001)

    def handleStep(self, val):
        if self.selectedOkToChange:
            if self.selected == MAX_STREAMS:
                for t in self.surface.getActiveTrajectories():
                    t.setStep(val)
            else:
                self.surface.getTrajectory(self.selected).setStep(val)
        else:
            self.selectedOkToChange = True

    def setStep(self, step):
        self.playback.sl_step.SetValue(step, self.selectedOkToChange)

    def handleTrajAmp(self, val):
        val = pow(10.0, float(val) * 0.05)
        if self.selectedOkToChange:
            if self.selected == MAX_STREAMS:
                for t in self.surface.getActiveTrajectories():
                    t.setAmplitude(val)
                    self.parent.sg_audio.setTrajAmplitude(t.label-1, val)
            else:
                self.surface.getTrajectory(self.selected).setAmplitude(val)
                self.parent.sg_audio.setTrajAmplitude(self.selected, val)
        else:
            self.selectedOkToChange = True

    def setTrajAmp(self, val):
        if val <= 0.0:
            val = 0.0001
        self.playback.sl_amp.SetValue(20.0 * math.log10(val), self.selectedOkToChange)

    def handleAmp(self, val):
        self.amplitude = pow(10.0, float(val) * 0.05)
        self.sendAmp()

    def getAmp(self):
        return self.amplitude

    def setAmp(self, amp):
        if amp <= 0.0:
            amp = 0.0001
        self.sl_amp.SetValue(20.0 * math.log10(amp))
        self.amplitude = amp

    def sendAmp(self):
        self.parent.sg_audio.setGlobalAmp(self.amplitude)

    def handleLoad(self):
        dlg = wx.FileDialog(self, message="Choose a sound file",
                            wildcard=AUDIO_WILDCARD, style=wx.OPEN)
        if dlg.ShowModal() == wx.ID_OK:
            sndPath = dlg.GetPath()
            self.loadSound(ensureNFD(sndPath))
        dlg.Destroy()

    def handleInsert(self):
        ok = False
        dlg = wx.FileDialog(self, message="Choose a sound file to insert",
                            wildcard=AUDIO_WILDCARD, style=wx.OPEN)
        if dlg.ShowModal() == wx.ID_OK:
            ok = True
            sndPath = dlg.GetPath()
        dlg.Destroy()
        if ok:
            self.insertSound(ensureNFD(sndPath), True)

    def loadSound(self, sndPath, force=False):
        if sndPath:
            if os.path.isfile(sndPath):
                self.sndPath = sndPath
                self.parent.sg_audio.loadSnd(toSysEncoding(self.sndPath))
                chnls, samprate, dur = soundInfo(toSysEncoding(self.sndPath))
                self.sndDur = dur
                self.chnls = chnls
                self.sndInfoStr = u'Loaded sound: %s,    Sr: %s Hz,    Channels: %s,    Duration: %s sec' % (self.sndPath, samprate, chnls, dur)
                if self.parent.draw:
                    if not self.sndPath in self.surface.bitmapDict.keys() or force:
                        self.parent.log("Drawing waveform...")
                        self.surface.analyse(self.sndPath)
                    else:
                        self.surface.list = self.surface.bitmapDict[self.sndPath]
                        self.surface.create_bitmap()
                self.logSndInfo()
            elif os.path.isfile(os.path.join(self.parent.currentPath, os.path.split(sndPath)[1])):
                self.loadSound(os.path.join(self.parent.currentPath, os.path.split(sndPath)[1]), force)
            elif ":\\" in sndPath:
                # Handle windows path...
                self.loadSound(os.path.join(self.parent.currentPath, sndPath.split("\\")[-1]), force)
            else:
                self.parent.log('Sound file "%s" does not exist!' % sndPath)
        else:
            self.parent.log("")

    def insertSound(self, sndPath, force=False):
        if not self.sndPath:
            self.loadSound(sndPath)
            return
        if sndPath:
            if os.path.isfile(sndPath):
                self.sndPath = "Mixed sound " + str(random.randint(0, 10000))
                chnls, samprate, dur = soundInfo(toSysEncoding(sndPath))
                dlg = InsertDialog(self, -1, 'Insert sound settings', actual_dur=self.sndDur, snd_dur=dur)
                refpos = self.surface.GetPosition()
                refsize = self.surface.GetSize()
                dlgsize = dlg.GetSize()
                X = refpos[0] + (refsize[0] / 2 - dlgsize[0] / 2)
                Y = refpos[1] + (refsize[1] / 2 - dlgsize[1] / 2)
                dlg.SetPosition((X,Y))
                if dlg.ShowModal() == wx.ID_OK:
                    start, end, point, cross = dlg.getValues()
                    ok = True
                else:
                    ok = False
                dlg.Destroy()
                if not ok:
                    return
                self.parent.sg_audio.insertSnd(toSysEncoding(sndPath), start, end, point, cross)
                self.sndDur = self.parent.sg_audio.getTableDuration()
                self.sndInfoStr = u'Loaded sound: %s,    Sr: %s Hz,    Channels: %s,    Duration: %s sec' % (self.sndPath, samprate, self.chnls, self.sndDur)
                if self.parent.draw:
                    if not self.sndPath in self.surface.bitmapDict.keys() or force:
                        self.parent.log("Drawing waveform...")
                        self.surface.analyse(self.sndPath)
                    else:
                        self.surface.list = self.surface.bitmapDict[self.sndPath]
                        self.surface.create_bitmap()
                self.logSndInfo()
            elif os.path.isfile(os.path.join(self.parent.currentPath, os.path.split(sndPath)[1])):
                self.insertSound(os.path.join(self.parent.currentPath, os.path.split(sndPath)[1]), force)
            elif ":\\" in sndPath:
                # Handle windows path...
                self.insertSound(os.path.join(self.parent.currentPath, sndPath.split("\\")[-1]), force)
            else:
                self.parent.log('Sound file "%s" does not exist!' % sndPath)

    def drawWaveform(self):
        if self.surface.sndBitmap and self.parent.draw:
            self.surface.analyse(self.sndPath)

    def getNchnls(self):
        return self.nchnls

    def setNchnls(self, x):
        if x != self.nchnls:
            self.nchnls = x
            self.tx_chnls.SetValue(str(x))
            self.meter.setNumSliders(self.nchnls)
            self.shutdownServer()
            self.bootServer()

    def handleNchnls(self, event):
        x = int(self.tx_chnls.GetValue())
        if x != self.nchnls:
            status, path = self.parent.checkForMixedSound()
            if not status:
                self.tx_chnls.SetValue(str(self.nchnls))
                return
            if "Mixed sound" in self.sndPath:
                self.sndPath = path
            self.nchnls = x
            self.meter.setNumSliders(self.nchnls)
            self.shutdownServer()
            self.bootServer()

    def getSamplingRate(self):
        return self.samplingRate

    def setSamplingRate(self, x):
        SR = {44100: 0, 48000: 1, 96000: 2}
        if x != self.samplingRate:
            self.samplingRate = x
            self.pop_sr.SetSelection(SR[self.samplingRate])
            self.shutdownServer()
            self.bootServer()

    def handleSamplingRate(self, event):
        SR = {0: 44100, 1: 48000, 2: 96000}
        x = SR[event.GetInt()]
        if x != self.samplingRate:
            status, path = self.parent.checkForMixedSound()
            if not status:
                SR = {44100: 0, 48000: 1, 96000: 2}
                self.pop_sr.SetSelection(SR[self.samplingRate])
                return
            if "Mixed sound" in self.sndPath:
                self.sndPath = path
            self.samplingRate = x
            self.shutdownServer()
            self.bootServer()

    def getFileFormat(self):
        return self.fileformat

    def setFileFormat(self, x):
        self.fileformat = x
        self.pop_fileformat.SetSelection(self.fileformat)

    def handleFileFormat(self, event):
        self.fileformat = event.GetInt()

    def getSampleType(self):
        return self.sampletype

    def setSampleType(self, x):
        self.sampletype = x
        self.pop_sampletype.SetSelection(self.sampletype)

    def handleSampleType(self, event):
        self.sampletype = event.GetInt()

    def bootServer(self):
        self.parent.sg_audio.boot(self.parent.audioDriver, self.nchnls, self.samplingRate, self.midiInterface)
        self.tog_audio.Enable()
        if self.sndPath != "" and self.tempState == None:
            self.loadSound(self.sndPath)
        if self.tempState != None:
            self.parent.setState(self.tempState)
            self.tempState = None

    def shutdownServer(self):
        self.tempState = self.parent.getState()
        self.parent.sg_audio.shutdown()
        self.tog_audio.Disable()
        self.surface.Refresh()

    def handleAudio(self, event):
        if event.GetInt() == 1:
            if self.sndPath == "":
                self.parent.log('*** No sound loaded! ***')
                self.tog_audio.SetValue(0)
                self.parent.menu.Check(7, False)
            else:
                self.tx_chnls.Disable()
                self.tx_chnls.SetBackgroundColour("#EEEEEE")
                self.pop_sr.Disable()
                self.parent.enableDrivers(False)
                self.parent.midiSettings.popupInterface.Disable()
                self.tog_audio.SetLabel('Stop')
                self.tog_audio.SetValue(1)
                self.parent.menu.Check(7, True)

                for t in self.surface.getAllTrajectories():
                    t.initCounter()
                self.parent.sg_audio.start()
        else:
            self.tx_chnls.Enable()
            self.tx_chnls.SetBackgroundColour("#FFFFFF")
            self.pop_sr.Enable()
            self.parent.enableDrivers(True)
            self.parent.midiSettings.popupInterface.Enable()
            self.tog_audio.SetLabel('Start')
            self.tog_audio.SetValue(0)
            self.parent.menu.Check(7, False)
            self.tog_record.SetValue(0)
            self.tog_record.SetLabel('Start Rec')
            self.parent.sg_audio.stop()

    def handleOutput(self, event):
        key = event.GetKeyCode()
        if key == wx.WXK_TAB or key == wx.WXK_RETURN:
            self.surface.SetFocus()
        event.Skip()

    def setRecordFolder(self, str):
        self.tx_rec_folder.SetValue(str)

    def setRecordFilename(self, str):
        self.tx_output.SetValue(str)

    def handleRecord(self, event):
        if event.GetInt() == 1:
            folder = self.tx_rec_folder.GetValue()
            if folder.startswith("~"):
                folder = folder.replace("~", os.path.expanduser("~"), 1)
            if os.path.isdir(folder):
                filename = os.path.join(folder, self.tx_output.GetValue())
            else:
                filename = os.path.join(os.path.expanduser('~'), "Desktop", self.tx_output.GetValue())
            self.parent.sg_audio.recStart(filename, self.fileformat, self.sampletype)
            self.tog_record.SetLabel('Stop Rec')
        else:
            self.tog_record.SetLabel('Start Rec')
            self.parent.sg_audio.recStop()

    def chooseRecFolder(self, evt):
        dlg = wx.DirDialog(self, message="Choose a folder to save Soundgrain's output sounds...",
                            defaultPath=os.path.expanduser("~"))
        if dlg.ShowModal() == wx.ID_OK:
            path = dlg.GetPath()
            self.tx_rec_folder.SetValue(ensureNFD(path))
        dlg.Destroy()
        self.but_folder.SetValue(0)
        
    def logSndInfo(self):
        self.parent.log(self.sndInfoStr)