将文件中的代码导入Python并添加文件对话框

时间:2011-10-02 18:58:12

标签: python

我有一个使用方程式播放音频的python脚本signalgen.py,但我希望能够将方程存储在eq1.txt中的文件硬编码或选择一个文件并导入方程。
我遇到的问题是:

1)如何正确地对文件及其路径进行硬编码,以便将等式视为音频

我收到错误 Traceback(最近一次调用最后一次):   在need_data中输入“signalgen.py”,第484行     v + =(datum * self.sig_level) TypeError:不能将序列乘以'float'

类型的非int

我认为导致问题的特定代码块

def equation_import_function(self,t,f):
    fileobj=open("/home/rat/eq1.txt","r")
    eqdata =fileobj.read() #read whole file
    fileobj.close()
    #return math.tan(2.0*math.pi*f*t)
    return eqdata

我在eq1.txt文件中有这行代码 - > math.tan(2.0 * math.pi * F * T)

2)如何添加文件打开对话框以便能够选择文件并导入等式。

PS我正在使用Ubuntu 10.04(Linux),方程式将长达几页,这就是我想将它们从文本文件导入python的原因

以下是整个代码,如果您想查看我在下面使用或在pastebin上看到的内容,其中包含行号http://pastebin.com/HZg0Jhaw

#!/usr/bin/env python
# -*- coding: utf-8 -*-

# ***************************************************************************
# *   Copyright (C) 2011, Paul Lutus                                        *
# *                                                                         *
# *   This program is free software; you can redistribute it and/or modify  *
# *   it under the terms of the GNU General Public License as published by  *
# *   the Free Software Foundation; either version 2 of the License, or     *
# *   (at your option) any later version.                                   *
# *                                                                         *
# *   This program is distributed in the hope that it will be useful,       *
# *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
# *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
# *   GNU General Public License for more details.                          *
# *                                                                         *
# *   You should have received a copy of the GNU General Public License     *
# *   along with this program; if not, write to the                         *
# *   Free Software Foundation, Inc.,                                       *
# *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
# ***************************************************************************

# version date 01-12-2011

VERSION = '1.1'

import re, sys, os

import gobject
gobject.threads_init()
import gst
import gtk
gtk.gdk.threads_init()
import time
import struct
import math
import random
import signal
import webbrowser

class Icon:
  icon = [
    "32 32 17 1",
    "   c None",
    ".  c #2A2E30",
    "+  c #333739",
    "@  c #464A4C",
    "#  c #855023",
    "$  c #575A59",
    "%  c #676A69",
    "&  c #CC5B00",
    "*  c #777A78",
    "=  c #DB731A",
    "-  c #8A8C8A",
    ";  c #969895",
    ">  c #F68C22",
    ",  c #A5A7A4",
    "'  c #F49D4A",
    ")  c #B3B5B2",
    "!  c #DEE0DD",
    "                        &&&&&&& ",
    "                  &&&===='''''& ",
    "                  &'''''====&'& ",
    "             +++++&'&&&&&   &'& ",
    "          +@$%****&'&+      &'& ",
    "        +@**%$@++@&'&*@+    &'& ",
    "      +@**@+++++++&'&@**@+  &'& ",
    "     +$*$+++++++++&'&++$*$+ &'& ",
    "     @*@++++++++++&'&+++@#&&&'& ",
    "    +*@++++++++#&&&'&+++#=''''& ",
    "   +*$++++++++#=''''&+++&'>>>'& ",
    "   @*+++++++++&'>>>'&+++#='''=  ",
    "  +%$++++++++@#='''=#@@++#&&&#  ",
    "  +*@+++++++@@@#&&&#@@@@@++@*+  ",
    "  +*+++++++@@@@++@$%$$@@@@++*+  ",
    "  +*++++++@@+@;,,*@@*$$$@@@+*+  ",
    "  +*@++++@@@%!!!!,;@$*$$$@@@*+  ",
    "  +%$++++@@+)!!!),-*+-%$$$@$%+  ",
    "  +@*+++@@@+-!!!,;-%@;%%$$+*@+  ",
    "   +*@++@@@@+$*-*%@+*-%%$@@*+   ",
    "   ++*@+@@@$$%@++@%;;*%%$@-$+   ",
    "    +@%+@@@$$%*;;;;-*%%%@**+    ",
    "    .+$%@@@$$$*******%$$*-+.    ",
    "     .+@%%@@$$*@*@%%%$%-%+.     ",
    "      .++@%$$$$$$%%%%--@+.      ",
    "        +++@@$%*****%+++        ",
    "         +++++++++++++@.        ",
    "          @--%@++@$*-%+         ",
    "           +%,))),;%+.          ",
    "             ++++++.            ",
    "                                ",
    "                                "
  ]

# this should be a temporary hack

class WidgetFinder:
  def localize_widgets(self,parent,xmlfile):
    # an unbelievable hack made necessary by
    # someone unwilling to fix a year-old bug
    with open(xmlfile) as f:
      for name in re.findall('(?s) id="(.*?)"',f.read()):
        if re.search('^k_',name):
          obj = parent.builder.get_object(name)
          setattr(parent,name,obj)

class ConfigManager:
  def __init__(self,path,dic):
    self.path = path
    self.dic = dic

  def read_config(self):
    if os.path.exists(self.path):
      with open(self.path) as f:
        for record in f.readlines():
          se = re.search('(.*?)\s*=\s*(.*)',record.strip())
          if(se):
            key,value = se.groups()
            if (key in self.dic):
              widget = self.dic[key]
              typ = type(widget)
              if(typ == list):
                widget[0] = value
              elif(typ == gtk.Entry):
                widget.set_text(value)
              elif(typ == gtk.HScale):
                widget.set_value(float(value))
              elif(typ == gtk.Window):
                w,h = value.split(',')
                widget.resize(int(w),int(h))
              elif(typ == gtk.CheckButton or typ == gtk.RadioButton or typ == gtk.ToggleButton):
                widget.set_active(value == 'True')
              elif(typ == gtk.ComboBox):
                if(value in widget.datalist):
                  i = widget.datalist.index(value)
                  widget.set_active(i)
              else:
                print "ERROR: reading, cannot identify key %s with type %s" % (key,type(widget))

  def write_config(self):
    with open(self.path,'w') as f:
      for key,widget in sorted(self.dic.iteritems()):
        typ = type(widget)
        if(typ == list):
          value = widget[0]
        elif(typ == gtk.Entry):
          value = widget.get_text()
        elif(typ == gtk.HScale):
          value = str(widget.get_value())
        elif(typ == gtk.Window):
          _,_,w,h = widget.get_allocation()
          value = "%d,%d" % (w,h)
        elif(typ == gtk.CheckButton or typ == gtk.RadioButton or typ == gtk.ToggleButton):
          value = ('False','True')[widget.get_active()]
        elif(typ == gtk.ComboBox):
          value = widget.get_active_text()
        else:
          print "ERROR: writing, cannot identify key %s with type %s" % (key,type(widget))
          value = "Error"
        f.write("%s = %s\n" % (key,value))

  def preset_combobox(self,box,v):
    if(v in box.datalist):
      i = box.datalist.index(v)
      box.set_active(i)
    else:
      box.set_active(0)

  def load_combobox(self,obj,data):
    if(len(obj.get_cells()) == 0):
      # Create a text cell renderer
      cell = gtk.CellRendererText ()
      obj.pack_start(cell)
      obj.add_attribute (cell, "text", 0)
    obj.get_model().clear()
    for s in data:
      obj.append_text(s.strip())
    setattr(obj,'datalist',data)

class TextEntryController:
  def __init__(self,parent,widget):
    self.par = parent
    self.widget = widget
    widget.connect('scroll-event',self.scroll_event)
    widget.set_tooltip_text('Enter number or:\n\
    Mouse wheel: increase,decrease\n\
    Shift/Ctrl/Alt: faster change')

  def scroll_event(self,w,evt):
    q = (-1,1)[evt.direction == gtk.gdk.SCROLL_UP]
    # magnify change if shift,ctrl,alt pressed
    for m in (1,2,4):
      if(self.par.mod_key_val & m): q *= 10
    s = self.widget.get_text()
    v = float(s)
    v += q
    v = max(0,v)
    s = self.par.format_num(v)
    self.widget.set_text(s)

class SignalGen:
  M_AM,M_FM = range(2)
  W_SINE,W_TRIANGLE,W_SQUARE,W_SAWTOOTH,W_EQUATION_IMPORT = range(5)
  waveform_strings = ('Sine','Triangle','Square','Sawtooth', 'Equation_Import')
  R_48000,R_44100,R_22050,R_16000,R_11025,R_8000,R_4000 = range(7)
  sample_rates = ('48000','44100','22050','16000', '11025', '8000', '4000')
  def __init__(self):
    self.restart = False
    # exit correctly on system signals
    signal.signal(signal.SIGTERM, self.close)
    signal.signal(signal.SIGINT, self.close)
    # precompile struct operator
    self.struct_int = struct.Struct('i')
    self.max_level = (2.0**31)-1
    self.gen_functions = (
      self.sine_function,
      self.triangle_function,
      self.square_function,
      self.sawtooth_function,
      self.equation_import_function
    )
    self.main_color = gtk.gdk.color_parse('#c04040')
    self.sig_color = gtk.gdk.color_parse('#40c040')
    self.mod_color = gtk.gdk.color_parse('#4040c0')
    self.noise_color = gtk.gdk.color_parse('#c040c0')
    self.pipeline = False
    self.count = 0
    self.imod = 0
    self.rate = 1
    self.mod_key_val = 0
    self.sig_freq = 440
    self.mod_freq = 3
    self.sig_level = 100
    self.mod_level = 100
    self.noise_level = 100
    self.enable = True
    self.sig_waveform = SignalGen.W_SINE
    self.sig_enable = True
    self.sig_function = False
    self.mod_waveform = SignalGen.W_SINE
    self.mod_function = False
    self.mod_mode = SignalGen.M_AM
    self.mod_enable = False
    self.noise_enable = False
    self.sample_rate = SignalGen.R_22050
    self.left_audio  = True
    self.right_audio = True
    self.program_name = self.__class__.__name__
    self.config_file = os.path.expanduser("~/." + self.program_name)
    self.builder = gtk.Builder()
    self.xmlfile = 'signalgen_gui.glade'
    self.builder.add_from_file(self.xmlfile)
    WidgetFinder().localize_widgets(self,self.xmlfile)
    self.k_quit_button.connect('clicked',self.close)
    self.k_help_button.connect('clicked',self.launch_help)
    self.k_mainwindow.connect('destroy',self.close)
    self.k_mainwindow.set_icon(gtk.gdk.pixbuf_new_from_xpm_data(Icon.icon))
    self.title = self.program_name + ' ' + VERSION
    self.k_mainwindow.set_title(self.title)
    self.tooltips = {
      self.k_sample_rate_combobox : 'Change data sampling rate',
      self.k_left_checkbutton : 'Enable left channel audio',
      self.k_right_checkbutton : 'Enable right channel audio',
      self.k_sig_waveform_combobox : 'Select signal waveform',
      self.k_mod_waveform_combobox : 'Select modulation waveform',
      self.k_mod_enable_checkbutton  : 'Enable modulation',
      self.k_sig_enable_checkbutton  : 'Enable signal',
      self.k_noise_enable_checkbutton  : 'Enable white noise',
      self.k_mod_am_radiobutton : 'Enable amplitude modulation',
      self.k_mod_fm_radiobutton : 'Enable frequency modulation',
      self.k_quit_button : 'Quit %s' % self.title,
      self.k_enable_checkbutton : 'Enable output',
      self.k_help_button : 'Visit the %s Web page' % self.title,
    }
    for k,v in self.tooltips.iteritems():
      k.set_tooltip_text(v)
    self.config_data = {
      'SampleRate' : self.k_sample_rate_combobox,
      'LeftChannelEnabled' : self.k_left_checkbutton,
      'RightChannelEnabled' : self.k_right_checkbutton,
      'SignalWaveform' : self.k_sig_waveform_combobox,
      'SignalFrequency' : self.k_sig_freq_entry,
      'SignalLevel' : self.k_sig_level_entry,
      'SignalEnabled' : self.k_sig_enable_checkbutton,
      'ModulationWaveform' : self.k_mod_waveform_combobox,
      'ModulationFrequency' : self.k_mod_freq_entry,
      'ModulationLevel' : self.k_mod_level_entry,
      'ModulationEnabled' : self.k_mod_enable_checkbutton,
      'AmplitudeModulation' : self.k_mod_am_radiobutton,
      'FrequencyModulation' : self.k_mod_fm_radiobutton,
      'NoiseEnabled' : self.k_noise_enable_checkbutton,
      'NoiseLevel' : self.k_noise_level_entry,
      'OutputEnabled' : self.k_enable_checkbutton,
    }
    self.cm = ConfigManager(self.config_file,self.config_data)
    self.cm.load_combobox(self.k_sig_waveform_combobox,self.waveform_strings)
    self.k_sig_waveform_combobox.set_active(self.sig_waveform)
    self.cm.load_combobox(self.k_mod_waveform_combobox,self.waveform_strings)
    self.k_mod_waveform_combobox.set_active(self.mod_waveform)
    self.cm.load_combobox(self.k_sample_rate_combobox,self.sample_rates)
    self.k_sample_rate_combobox.set_active(self.sample_rate)
    self.k_sig_freq_entry.set_text(self.format_num(self.sig_freq))
    self.k_sig_level_entry.set_text(self.format_num(self.sig_level))
    self.k_mod_freq_entry.set_text(self.format_num(self.mod_freq))
    self.k_mod_level_entry.set_text(self.format_num(self.mod_level))
    self.k_noise_level_entry.set_text(self.format_num(self.noise_level))
    self.k_main_viewport_border.modify_bg(gtk.STATE_NORMAL,self.main_color)
    self.k_sig_viewport_border.modify_bg(gtk.STATE_NORMAL,self.sig_color)
    self.k_mod_viewport_border.modify_bg(gtk.STATE_NORMAL,self.mod_color)
    self.k_noise_viewport_border.modify_bg(gtk.STATE_NORMAL,self.noise_color)
    self.sig_freq_cont = TextEntryController(self,self.k_sig_freq_entry)
    self.sig_level_cont = TextEntryController(self,self.k_sig_level_entry)
    self.mod_freq_cont = TextEntryController(self,self.k_mod_freq_entry)
    self.mod_level_cont = TextEntryController(self,self.k_mod_level_entry)
    self.noise_level_cont = TextEntryController(self,self.k_noise_level_entry)
    self.k_mainwindow.connect('key-press-event',self.key_event)
    self.k_mainwindow.connect('key-release-event',self.key_event)
    self.k_enable_checkbutton.connect('toggled',self.update_values)
    self.k_sig_freq_entry.connect('changed',self.update_entry_values)
    self.k_sig_level_entry.connect('changed',self.update_entry_values)
    self.k_sig_enable_checkbutton.connect('toggled',self.update_checkbutton_values)
    self.k_mod_freq_entry.connect('changed',self.update_entry_values)
    self.k_mod_level_entry.connect('changed',self.update_entry_values)
    self.k_noise_level_entry.connect('changed',self.update_entry_values)
    self.k_sample_rate_combobox.connect('changed',self.update_values)
    self.k_sig_waveform_combobox.connect('changed',self.update_values)
    self.k_mod_waveform_combobox.connect('changed',self.update_values)
    self.k_left_checkbutton.connect('toggled',self.update_checkbutton_values)
    self.k_right_checkbutton.connect('toggled',self.update_checkbutton_values)
    self.k_mod_enable_checkbutton.connect('toggled',self.update_checkbutton_values)
    self.k_noise_enable_checkbutton.connect('toggled',self.update_checkbutton_values)
    self.k_mod_am_radiobutton.connect('toggled',self.update_checkbutton_values)
    self.cm.read_config()
    self.update_entry_values()
    self.update_checkbutton_values()
    self.update_values()

  def format_num(self,v):
    return "%.2f" % v

  def get_widget_text(self,w):
    typ = type(w)
    if(typ == gtk.ComboBox):
      return w.get_active_text()
    elif(typ == gtk.Entry):
      return w.get_text()

  def get_widget_num(self,w):
    try:
      return float(self.get_widget_text(w))
    except:
      return 0.0

  def restart_test(self,w,pv):
    nv = w.get_active()
    self.restart |= (nv != pv)
    return nv

  def update_entry_values(self,*args):
    self.sig_freq = self.get_widget_num(self.k_sig_freq_entry)
    self.sig_level = self.get_widget_num(self.k_sig_level_entry) / 100.0
    self.mod_freq = self.get_widget_num(self.k_mod_freq_entry)
    self.mod_level = self.get_widget_num(self.k_mod_level_entry) / 100.0
    self.noise_level = self.get_widget_num(self.k_noise_level_entry) / 100.0

  def update_checkbutton_values(self,*args):
    self.left_audio = self.k_left_checkbutton.get_active()
    self.right_audio = self.k_right_checkbutton.get_active()
    self.mod_enable = self.k_mod_enable_checkbutton.get_active()
    self.sig_enable = self.k_sig_enable_checkbutton.get_active()
    self.mod_mode = (SignalGen.M_FM,SignalGen.M_AM)[self.k_mod_am_radiobutton.get_active()]
    self.noise_enable = self.k_noise_enable_checkbutton.get_active()

  def update_values(self,*args):
    self.restart = (not self.sig_function)
    self.sample_rate = self.restart_test(self.k_sample_rate_combobox, self.sample_rate)
    self.enable = self.restart_test(self.k_enable_checkbutton,self.enable)
    self.mod_waveform = self.k_mod_waveform_combobox.get_active()
    self.mod_function = self.gen_functions[self.mod_waveform]
    self.sig_waveform = self.k_sig_waveform_combobox.get_active()
    self.sig_function = self.gen_functions[self.sig_waveform]
    self.k_sample_rate_combobox.set_sensitive(not self.enable)
    if(self.restart):
      self.init_audio()

  def make_and_chain(self,name):
    target = gst.element_factory_make(name)
    self.chain.append(target)
    return target

  def unlink_gst(self):
    if(self.pipeline):
      self.pipeline.set_state(gst.STATE_NULL)
      self.pipeline.remove_many(*self.chain)
      gst.element_unlink_many(*self.chain)
      for item in self.chain:
        item = False
      self.pipeline = False
      time.sleep(0.01)

  def init_audio(self):
    self.unlink_gst()
    if(self.enable):
      self.chain = []
      self.pipeline = gst.Pipeline("mypipeline")
      self.source = self.make_and_chain("appsrc")
      rs = SignalGen.sample_rates[self.sample_rate]
      self.rate = float(rs)
      self.interval = 1.0 / self.rate
      caps = gst.Caps(
      'audio/x-raw-int,'
      'endianness=(int)1234,'
      'channels=(int)2,'
      'width=(int)32,'
      'depth=(int)32,'
      'signed=(boolean)true,'
      'rate=(int)%s' % rs)
      self.source.set_property('caps', caps)
      self.sink = self.make_and_chain("autoaudiosink")
      self.pipeline.add(*self.chain)
      gst.element_link_many(*self.chain)
      self.source.connect('need-data', self.need_data)
      self.pipeline.set_state(gst.STATE_PLAYING)

  def key_event(self,w,evt):
    cn = gtk.gdk.keyval_name(evt.keyval)
    if(re.search('Shift',cn) != None):
      mod = 1
    elif(re.search('Control',cn) != None):
      mod = 2
    elif(re.search('Alt|Meta',cn) != None):
      mod = 4
    else:
      return
    if(evt.type == gtk.gdk.KEY_PRESS):
      self.mod_key_val |= mod
    else:
      self.mod_key_val &= ~mod

  def sine_function(self,t,f):
    return math.sin(2.0*math.pi*f*t)



  def triangle_function(self,t,f):
    q = 4*math.fmod(t*f,1)
    q = (q,2-q)[q > 1]
    return (q,-2-q)[q < -1]

  def square_function(self,t,f):
    if(f == 0): return 0
    q = 0.5 - math.fmod(t*f,1)
    return (-1,1)[q > 0]

  def sawtooth_function(self,t,f):
    return 2.0*math.fmod((t*f)+0.5,1.0)-1.0

  def equation_import_function(self,t,f):
    fileobj=open("/home/rat/eq1.txt","r")
    eqdata =fileobj.read() #read whole file
    fileobj.close()
    #return math.tan(2.0*math.pi*f*t)
    return eqdata

  def need_data(self,src,length):
    bytes = ""
    # sending two channels, so divide requested length by 2
    ld2 = length / 2
    for tt in range(ld2):
      t = (self.count + tt) * self.interval
      if(not self.mod_enable):
        datum = self.sig_function(t,self.sig_freq)
      else:
        mod = self.mod_function(t,self.mod_freq)
        # AM mode
        if(self.mod_mode == SignalGen.M_AM):
          datum = 0.5 * self.sig_function(t,self.sig_freq) * (1.0 + (mod * self.mod_level))
        # FM mode
        else:
          self.imod += (mod * self.mod_level * self.interval)
          datum = self.sig_function(t+self.imod,self.sig_freq)
      v = 0
      if(self.sig_enable):
        v += (datum * self.sig_level)
      if(self.noise_enable):
        noise = ((2.0 * random.random()) - 1.0)
        v += noise * self.noise_level
      v *= self.max_level
      v = max(-self.max_level,v)
      v = min(self.max_level,v)
      left  = (0,v)[self.left_audio]
      right = (0,v)[self.right_audio]
      bytes += self.struct_int.pack(left)
      bytes += self.struct_int.pack(right)
    self.count += ld2
    src.emit('push-buffer', gst.Buffer(bytes))

  def launch_help(self,*args):
    webbrowser.open("http://arachnoid.com/python/signalgen_program.html")

  def close(self,*args):
    self.unlink_gst()
    self.cm.write_config()
    gtk.main_quit()

app=SignalGen()
gtk.main()

2 个答案:

答案 0 :(得分:2)

imp模块将帮助您从任意文件中干净地加载Python代码块。

#!/usr/bin/env python
# equation in equation-one.py
def eqn(arg):
    return arg * 3 + 2

#!/usr/bin/env python
# your code

import imp
path = "equation-one.py"
eq_mod = imp.load_source("equation", path, open(path))

print("Oh the nice stuff in eq_mod: %s" % dir(eq_mod))

在自定义函数定义中,您可以创建文件选择器对话框,获取选定的文件路径,使用imp加载代码,并在导入的模块中返回函数的结果。

答案 1 :(得分:1)

之前我正在评论,但我盯着你的代码足够长,并且有点意识到你想要做的事情,所以我更容易发布答案。当我扩展他使用imp模块的建议时,请参考cJ Zougloubs的回答。 您的公式文件应该实现一个通用接口:

# equation1.py
def eqn(*args):
    return sum(*args)

然后你会使用cj Zougloubs建议加载它们,但是有一个共同的界面:

# python_rt.py
def equation_import_function(self, *args):
    filepath = ''
    # filepath = ... do file chooser dialog here ...

    eq_mod = imp.load_source("equation", filepath)
    eqdata = eq_mod.eqn(*args)
    return eqdata

现在你的主代码中有一个函数,它接受任意数量的参数,要求用户选择方程式文件,并为你得到结果。

修改更具体地说明您的评论

# equation1.py
import math

def eqn(*args):
    f = args[0]
    t = args[1]
    return math.tan(2.0*math.pi*f*t)

在你的主要工具中,你可以使用imp.load_source将它带入。无论你需要音频等式,你都可以这样做:

eq_mod.eqn(f, t)