Läuft die Voice Acoustic VA-Remotecontrol (AllDSP AllControl) nativ unter Linux auf echtem wxGTK 3.0 — ohne Wine und ohne dekompilierten App-Code. Ausgeführt wird das unveränderte Python-2.7-Bytecode aus dem macOS-.app; C-Extensions (wxGTK/numpy/ scipy/PortAudio) kommen nativ aus Debian stretch. Enthält: va/ (Original-.pyc + pure-Python-Libs + Assets + launch.py mit den drei Linux-Fixes), Dockerfile/run.sh/entrypoint.sh, reference/ (dekompilierter Quellcode zum Debuggen) und README/STATUS. img.cache (378 MB, regenerierbar) ist per .gitignore ausgeschlossen. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
395 lines
16 KiB
Python
395 lines
16 KiB
Python
# uncompyle6 version 3.9.3
|
|
# Python bytecode version base 2.6 (62161)
|
|
# Decompiled from: Python 3.9.25 (main, Oct 31 2025, 23:16:49)
|
|
# [GCC 14.2.0]
|
|
# Embedded file name: fir_dialog.pyc
|
|
# Compiled at: 2022-04-20 07:08:28
|
|
import mytime, wx, os, data_model, traceback, one_unit, sys, math, dialog
|
|
mac_names = 'posix'
|
|
accepted = '+-.0123456789Ee'
|
|
|
|
def safeNumber(text):
|
|
res = ''
|
|
for c in text:
|
|
if c in accepted:
|
|
res += c
|
|
|
|
return res
|
|
|
|
|
|
def getString(strID):
|
|
return one_unit.getString(strID)
|
|
|
|
|
|
class Dialog(wx.Dialog):
|
|
|
|
def __init__(self, parent, id, title, infotext='', optkey=None, optmask=0, opttext={}, bgcolour=(220, 220, 220), fgcolour=(70, 70, 70), OK_Only=False, textkey=None, default_text=None, IsPassword=False, Set=True, Wrap=400, size=(250, 10), bg=None, choices={}, value_mask=None, selectkey=None, default_choice=0, OK_Enable=True, OKtext='Ok', Canceltext='Cancel', OK_Show=True, max=None, default_options=0, numtaps=0, maxnumtaps=0, Fs=48828):
|
|
wx.Dialog.__init__(self, None, wx.ID_ANY, title, size=size, style=wx.CAPTION | wx.DEFAULT_DIALOG_STYLE)
|
|
self.parent = parent
|
|
if bg != None:
|
|
self.bg = bg
|
|
self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground)
|
|
self.value_mask = value_mask
|
|
self.optkey = optkey
|
|
self.numtaps = numtaps
|
|
self.textkey = textkey
|
|
self.selectkey = selectkey
|
|
self.options = default_options
|
|
self.choices = choices
|
|
self.default_options = default_options
|
|
self.max = max
|
|
self.maxnumtaps = maxnumtaps
|
|
self.Fs = Fs
|
|
self.optmask = optmask
|
|
self.frame_height = 2 * wx.SystemSettings.GetMetric(wx.SYS_CAPTION_Y) + wx.SystemSettings.GetMetric(wx.SYS_BORDER_Y)
|
|
if os.name in mac_names:
|
|
self.frame_height = 24
|
|
self.chkboxes = {}
|
|
self.Set = Set
|
|
self.infotext = None
|
|
textpanel = wx.Panel(self, -1)
|
|
textvbox = wx.BoxSizer(wx.VERTICAL)
|
|
textfieldpanel = wx.Panel(self, -1)
|
|
textfieldvbox = wx.BoxSizer(wx.HORIZONTAL)
|
|
loadbuttonpanel = wx.Panel(self, -1)
|
|
loadbuttonvbox = wx.BoxSizer(wx.HORIZONTAL)
|
|
selectfieldpanel = wx.Panel(self, -1)
|
|
selectfieldvbox = wx.BoxSizer(wx.VERTICAL)
|
|
optionspanel = wx.Panel(self, -1)
|
|
optionsvbox = wx.BoxSizer(wx.VERTICAL)
|
|
buttonspanel = wx.Panel(self, -1)
|
|
buttonshbox = wx.BoxSizer(wx.HORIZONTAL)
|
|
mainvbox = wx.BoxSizer(wx.VERTICAL)
|
|
if infotext != '':
|
|
textstring = wx.StaticText(textpanel, -1, infotext, style=wx.ALIGN_LEFT | wx.ST_NO_AUTORESIZE)
|
|
textstring.Wrap(Wrap)
|
|
textstring.SetForegroundColour(fgcolour)
|
|
textvbox.Add(textstring, 1, wx.EXPAND)
|
|
textpanel.SetSizer(textvbox)
|
|
if Wrap > 0:
|
|
textvbox.SetMinSize((Wrap, 10))
|
|
else:
|
|
textvbox.SetMinSize(size)
|
|
mainvbox.Add(textpanel, 0, border=10, flag=wx.ALL)
|
|
self.infotext = textstring
|
|
self.infostring = infotext
|
|
self.wrap = Wrap
|
|
self.Bind(wx.EVT_BUTTON, self.OnLoad, id=3)
|
|
if numtaps > 0:
|
|
numtapstring = wx.StaticText(textfieldpanel, -1, 'Number of Taps:', style=wx.ALIGN_LEFT | wx.ST_NO_AUTORESIZE, pos=(0,
|
|
30))
|
|
textfieldvbox.Add(numtapstring, 1, border=5, flag=wx.ALIGN_LEFT | wx.ALL)
|
|
textval = str(numtaps)
|
|
textfield = wx.TextCtrl(textfieldpanel, 3, unicode(textval), style=wx.TE_PROCESS_ENTER, pos=(100,
|
|
30))
|
|
textfieldvbox.Add(textfield, 1, border=5, flag=wx.ALIGN_LEFT | wx.ALL)
|
|
self.textfield = textfield
|
|
textfield.Bind(wx.EVT_TEXT_ENTER, self.OnTextEnter, textfield)
|
|
sample_time = 1.0 / self.Fs
|
|
latency = str(round(numtaps * sample_time * 500, 2)) + 'ms'
|
|
self.latencyfield = wx.StaticText(textfieldpanel, -1, '(' + latency + ' latency)', style=wx.ALIGN_LEFT | wx.ST_NO_AUTORESIZE)
|
|
textfieldvbox.Add(self.latencyfield, 1, border=5, flag=wx.ALIGN_LEFT | wx.ALL)
|
|
textfieldpanel.SetSizer(textfieldvbox)
|
|
mainvbox.Add(textfieldpanel, 0, border=10, flag=wx.LEFT | wx.RIGHT)
|
|
if selectkey != None:
|
|
selectval = None
|
|
try:
|
|
selectval = self.parent.model.get(selectkey)
|
|
if value_mask != None:
|
|
selectval = int(int(selectval) & value_mask)
|
|
except:
|
|
traceback.print_exc(file=sys.stdout)
|
|
else:
|
|
if selectval == None:
|
|
selectval = default_choice
|
|
if selectval not in self.choices.keys():
|
|
selectval = default_choice
|
|
style = wx.BORDER_NONE | wx.CB_READONLY
|
|
mychoices = []
|
|
for i in sorted(choices.keys()):
|
|
mychoices.append(choices[i])
|
|
|
|
selectfield = wx.ComboBox(selectfieldpanel, 30, choices=mychoices, style=style)
|
|
selectfield.SetStringSelection(self.choices[selectval])
|
|
selectfieldvbox.Add(selectfield, 1, border=5, flag=wx.ALIGN_LEFT | wx.ALL)
|
|
selectfieldpanel.SetSizer(selectfieldvbox)
|
|
mainvbox.Add(selectfieldpanel, 0, border=10, flag=wx.LEFT | wx.RIGHT)
|
|
self.selectfield = selectfield
|
|
if optkey != None and optmask != 0:
|
|
try:
|
|
options = int(self.parent.model.get(optkey))
|
|
except:
|
|
options = default_options
|
|
else:
|
|
chkboxes = {}
|
|
for i in range(0, 31):
|
|
optnr = optmask & 1 << i
|
|
val = options & 1 << i
|
|
if optnr > 0:
|
|
try:
|
|
this_opttext = opttext[optnr]
|
|
except:
|
|
this_opttext = 'Unlisted Option: ' + hex(optnr)
|
|
else:
|
|
chkboxes[i] = wx.CheckBox(optionspanel, i, this_opttext)
|
|
chkboxes[i].SetForegroundColour(fgcolour)
|
|
optionsvbox.Add(chkboxes[i], 1, border=5, flag=wx.ALIGN_LEFT | wx.ALL)
|
|
if val > 0:
|
|
chkboxes[i].SetValue(1)
|
|
if optnr == 32768:
|
|
if self.parent.fir_file != '':
|
|
chkboxes[i].SetLabel(self.parent.fir_file)
|
|
chkboxes[i].SetSize((100, 150))
|
|
if self.parent.parent.fir_taps_from_file == None:
|
|
chkboxes[i].Enable(False)
|
|
self.file_chkbox = chkboxes[i]
|
|
self.load_button = wx.Button(optionspanel, 3, 'Load File')
|
|
self.load_button.Enable(True)
|
|
self.load_button.Show(True)
|
|
optionsvbox.Add(self.load_button, 1, border=5, flag=wx.ALIGN_RIGHT | wx.ALL)
|
|
self.Bind(wx.EVT_CHECKBOX, self.OnEnabled, id=i)
|
|
|
|
optionspanel.SetSizer(optionsvbox)
|
|
optionsvbox.SetMinSize((250, 10))
|
|
mainvbox.Add(optionspanel, 0, border=10, flag=wx.LEFT | wx.RIGHT)
|
|
self.chkboxes = chkboxes
|
|
self.OK_button = wx.Button(buttonspanel, 1, OKtext)
|
|
self.OK_button.Enable(OK_Enable)
|
|
self.OK_button.Show(OK_Show)
|
|
buttonshbox.Add(self.OK_button, 1, border=3, flag=wx.ALL)
|
|
if OK_Only == False:
|
|
buttonshbox.Add(wx.Button(buttonspanel, 2, Canceltext), 1, border=3, flag=wx.ALL)
|
|
buttonspanel.SetSizer(buttonshbox)
|
|
if OK_Only == True:
|
|
buttonshbox.SetMinSize((75, self.frame_height))
|
|
else:
|
|
buttonshbox.SetMinSize((150, self.frame_height))
|
|
mainvbox.Add(buttonspanel, 0, border=5, flag=wx.ALL)
|
|
self.SetSizerAndFit(mainvbox)
|
|
self.Centre()
|
|
self.textvbox = textvbox
|
|
self.SetBackgroundColour(bgcolour)
|
|
self.Bind(wx.EVT_TEXT_ENTER, self.OnOK, id=3)
|
|
self.Bind(wx.EVT_BUTTON, self.OnOK, id=1)
|
|
self.Bind(wx.EVT_BUTTON, self.OnCancel, id=2)
|
|
self.CenterOnScreen()
|
|
self.mainvbox = mainvbox
|
|
self.response = None
|
|
return
|
|
|
|
def OnEnabled(self, e):
|
|
id = e.GetId()
|
|
try:
|
|
if self.chkboxes[id].GetValue() == 1:
|
|
if id == 15:
|
|
for i in range(15):
|
|
self.chkboxes[i].SetValue(0)
|
|
|
|
else:
|
|
self.chkboxes[15].SetValue(0)
|
|
except:
|
|
pass
|
|
|
|
return
|
|
|
|
def OnTextEnter(self, e):
|
|
try:
|
|
numtaps = int(self.textfield.GetValue())
|
|
except:
|
|
self.textfield.SetValue(str(self.numtaps))
|
|
numtaps = self.numtaps
|
|
|
|
if numtaps > self.maxnumtaps:
|
|
self.textfield.SetValue(str(self.maxnumtaps))
|
|
numtaps = self.maxnumtaps
|
|
sample_time = 1.0 / self.Fs
|
|
latency = str(round(numtaps * sample_time * 500, 2)) + 'ms'
|
|
self.latencyfield.SetLabel('(' + latency + ' latency)')
|
|
return
|
|
|
|
def OnEraseBackground(self, evt):
|
|
"""
|
|
Add a picture to the background
|
|
"""
|
|
dc = evt.GetDC()
|
|
if not dc:
|
|
dc = wx.ClientDC(self)
|
|
rect = self.GetUpdateRegion().GetBox()
|
|
dc.SetClippingRect(rect)
|
|
dc.Clear()
|
|
bmp = wx.Bitmap(self.bg)
|
|
dc.DrawBitmap(bmp, 0, 0)
|
|
return
|
|
|
|
def OnLoad(self, e):
|
|
wildcard = 'Text File (*.txt)|*.txt|Comma Separated Values File (*.csv)|*.csv'
|
|
path = None
|
|
dlg = wx.FileDialog(self, message='Select File....', defaultDir=one_unit.app.library_path, defaultFile='', wildcard=wildcard, style=wx.OPEN | wx.CHANGE_DIR)
|
|
answer = dlg.Show()
|
|
dlg.Destroy()
|
|
dlg = wx.FileDialog(self, message='Select File....', defaultDir=one_unit.app.library_path, defaultFile='', wildcard=wildcard, style=wx.OPEN | wx.CHANGE_DIR)
|
|
answer = dlg.ShowModal()
|
|
if answer == wx.ID_OK:
|
|
path = dlg.GetPath()
|
|
else:
|
|
path = None
|
|
dlg.Destroy()
|
|
if path:
|
|
one_unit.app.library_path = os.path.split(path)[0]
|
|
print mytime.displayTime() + ' Loading FIR file:', path
|
|
f = open(path, 'r')
|
|
content = f.readlines()
|
|
f.close()
|
|
if path.endswith('.csv'):
|
|
split_content = []
|
|
for line in content:
|
|
split_content += line.split(',')
|
|
|
|
content = split_content
|
|
coefs_raw = []
|
|
coefs_float = []
|
|
scaled_coefs = []
|
|
max_val = 0
|
|
floating_point = False
|
|
checked_content = []
|
|
q = 0
|
|
for value in content:
|
|
try:
|
|
checked_content.append(float(safeNumber(value)))
|
|
q += 1
|
|
if str(value).find('.') > 0:
|
|
floating_point = True
|
|
except:
|
|
pass
|
|
|
|
content = checked_content
|
|
if floating_point:
|
|
for coef in content:
|
|
scaled_coefs.append(coef)
|
|
|
|
else:
|
|
for raw_coef in content:
|
|
coef = int(raw_coef)
|
|
coefs_raw.append(coef)
|
|
if abs(coef) > max_val:
|
|
max_val = abs(coef)
|
|
|
|
scale = 8388607
|
|
if max_val >= 16777215:
|
|
scale = 2147483647
|
|
scale = scale * 1.0
|
|
for coef in coefs_raw:
|
|
coef = coef / scale
|
|
scaled_coefs.append(coef)
|
|
|
|
if len(scaled_coefs) > self.parent.maxnumtaps + 1:
|
|
print mytime.displayTime() + ' Filter too long:', len(scaled_coefs)
|
|
dlgMessage = getString('lffmt1') + ' ' + str(len(scaled_coefs)) + ' ' + getString('lffmt2') + ' ' + str(self.parent.maxnumtaps) + ' ' + getString('lffmt3')
|
|
dlgTitle = getString('lff')
|
|
res = wx.MessageBox(dlgMessage, dlgTitle, wx.OK | wx.CANCEL)
|
|
if res != wx.OK:
|
|
print 'fd.ol.Customer declined filter resampling'
|
|
return
|
|
taps = self.parent.RecalculateFIR(scaled_coefs, int(self.parent.maxnumtaps))
|
|
print mytime.displayTime() + ' Resampled to ', len(taps), 'taps'
|
|
else:
|
|
taps = scaled_coefs
|
|
self.textfield.SetValue(str(len(taps)))
|
|
self.parent.parent.numtaps = len(taps)
|
|
self.parent.parent.fir_taps_from_file = taps
|
|
self.parent.calc_fir_options |= 32768
|
|
self.file_chkbox.Enable(True)
|
|
self.file_chkbox.SetValue(1)
|
|
self.parent.fir_file = os.path.split(path)[1]
|
|
self.chkboxes[15].SetLabel(self.parent.fir_file)
|
|
font = self.chkboxes[15].GetFont()
|
|
dc = wx.ScreenDC()
|
|
dc.SetFont(font)
|
|
(w, h) = dc.GetTextExtent(self.parent.fir_file)
|
|
print 'Size:', w, h
|
|
self.chkboxes[15].SetSize((w + 50, h + 10))
|
|
if w + 100 > self.GetSize()[0]:
|
|
self.SetSize((w + 100, self.GetSize()[1]))
|
|
for i in range(15):
|
|
try:
|
|
self.chkboxes[i].SetValue(0)
|
|
except:
|
|
pass
|
|
|
|
self.chkboxes[15].SetValue(1)
|
|
return
|
|
|
|
def OnOK(self, evt):
|
|
self.response = 'OK'
|
|
try:
|
|
self.numtaps = self.textfield.GetValue()
|
|
if self.optkey != None and self.optmask != 0:
|
|
try:
|
|
options = int(self.parent.model.get(self.optkey))
|
|
except:
|
|
options = self.default_options
|
|
else:
|
|
for i in range(0, 31):
|
|
optnr = self.optmask & 1 << i
|
|
val = 1 << i
|
|
if optnr > 0:
|
|
if self.chkboxes[i].GetValue() == True:
|
|
options |= val
|
|
else:
|
|
options &= 4294967295L - val
|
|
|
|
if self.Set == True:
|
|
self.parent.set_value(self.optkey, options)
|
|
self.options = options
|
|
if self.selectkey != None and self.Set == True:
|
|
s = self.selectfield.GetStringSelection()
|
|
for (k, v) in self.choices.items():
|
|
if v == s:
|
|
v = k
|
|
if self.value_mask != None:
|
|
val = int(self.parent.model.get(self.selectkey)) & (4294967295L ^ self.value_mask)
|
|
val |= int(v)
|
|
v = val
|
|
self.parent.set_value(self.selectkey, v)
|
|
|
|
except:
|
|
traceback.print_exc(file=sys.stdout)
|
|
|
|
if self.IsModal() == False:
|
|
self.Destroy()
|
|
else:
|
|
self.Close()
|
|
return
|
|
|
|
def OnCancel(self, evt):
|
|
self.response = 'Cancel'
|
|
if self.IsModal == False:
|
|
self.Destroy()
|
|
else:
|
|
self.Close()
|
|
return
|
|
|
|
def Update(self, text):
|
|
if self.infotext == None:
|
|
return
|
|
else:
|
|
if unicode(text) != self.infostring:
|
|
self.infostring = unicode(text)
|
|
self.infotext.SetLabel(self.infostring)
|
|
self.infotext.Wrap(self.wrap)
|
|
self.Layout()
|
|
self.SetSizerAndFit(self.mainvbox)
|
|
return
|
|
|
|
def EnableOK(self, OK_Enable):
|
|
self.OK_button.Enable(OK_Enable)
|
|
return
|
|
|
|
def ShowOK(self, OK_Enable):
|
|
self.OK_button.Show(OK_Enable)
|
|
return
|
|
|
|
|
|
|
|
# okay decompiling pycode/fir_dialog.pyc
|