202 lines
6.8 KiB
Python
Executable file
202 lines
6.8 KiB
Python
Executable file
#!/usr/bin/env python3
|
|
import sys
|
|
from xml.dom.minidom import parse
|
|
import re
|
|
from collections import defaultdict
|
|
|
|
import argparse
|
|
|
|
|
|
def key_change(key):
|
|
if key[-1].isdigit():
|
|
num = int(key[-1])
|
|
return '%s_%d' % (key[:-1], num+1)
|
|
return key
|
|
|
|
|
|
def starting(key, args):
|
|
'''returns True if key starts with any of the string in args'''
|
|
return any(key.startswith(x) for x in args)
|
|
|
|
|
|
def search(key, *regexps):
|
|
return any(bool(re.search(r, key)) for r in regexps)
|
|
|
|
|
|
def parse_params(preset):
|
|
return {par.attributes['name'].value: par.attributes['value'].value
|
|
for par in preset.getElementsByTagName('param')}
|
|
|
|
|
|
def multibandcompressor_get_params(params):
|
|
newparams = {}
|
|
skipped = 0
|
|
for key, val in params.items():
|
|
if starting(key, ('level_', 'meter_', 'clip_', 'detection',
|
|
'compression', 'mode', 'output', 'notebook',
|
|
)):
|
|
skipped += 1
|
|
continue
|
|
if key == 'bypass' or key.startswith('solo'):
|
|
newparams[key_change(key)] = bool(int(val))
|
|
elif search(key, r'p\d_q$'):
|
|
par['q_%c' % key[1]] = float(val)
|
|
elif key.startswith('bypass') or re.match(r'output\d', key):
|
|
continue
|
|
elif search(key, 's_level$'):
|
|
newparams['level_%c' % key[0]] = bool(int(val))
|
|
elif starting(key, ('attack', 'ratio', 'release', 'makeup', 'knee',
|
|
'threshold')):
|
|
newparams[key_change(key)] = float(val)
|
|
elif search(key, '^mode', '^output', '_mode$'):
|
|
newparams[key_change(key)] = int(val)
|
|
elif key.startswith('freq'):
|
|
num = int(key[-1])
|
|
newparams['split_%d_%d' % (num+1, num+2)] = float(val)
|
|
else:
|
|
print('!!', key, val, file=sys.stderr)
|
|
if skipped:
|
|
print('%d skipped' % skipped, file=sys.stderr)
|
|
return newparams
|
|
|
|
|
|
def filter_get_params(params):
|
|
newparams = {}
|
|
skipped = 0
|
|
for key in params:
|
|
if key == 'freq':
|
|
newparams['frequency'] = float(params[key])
|
|
elif key == 'res':
|
|
newparams['resonance'] = float(params[key])
|
|
elif key == 'inertia':
|
|
newparams[key] = float(params[key])
|
|
elif key in ('mode',):
|
|
newparams[key] = int(params[key])
|
|
else:
|
|
print('!!', key, params[key], file=sys.stderr)
|
|
skipped += 1
|
|
if skipped:
|
|
print('%d skipped' % skipped, file=sys.stderr)
|
|
return newparams
|
|
|
|
|
|
def eq_get_params(params):
|
|
par = {}
|
|
skipped = 0
|
|
for key, val in params.items():
|
|
if starting(key, ('level_', 'meter_', 'clip_', 'detection',
|
|
'compression', 'mode', 'output', 'notebook',
|
|
'analyzer', 'zoom', 'individuals', 'bypass',
|
|
)) or\
|
|
search(key, '^.s_freq$'):
|
|
skipped += 1
|
|
continue
|
|
if search(key, '^bypass$', '^solo'):
|
|
par[key_change(key)] = bool(int(val))
|
|
elif search(key, r'p\d_q$'):
|
|
par['q_%c' % key[1]] = float(val)
|
|
elif search(key, r'^p\d_active$'):
|
|
par['f%c_active' % key[1]] = bool(int(val))
|
|
elif key.endswith('_active'):
|
|
par[key] = bool(int(val))
|
|
elif search(key, r'\d_freq$'):
|
|
par['freq_%c' % key[1]] = float(val)
|
|
elif search(key, r'^.p_freq$'):
|
|
par['freq_%c' % key[0]] = float(val)
|
|
elif search(key, 's_level$'):
|
|
par['level_%c' % key[0]] = float(val)
|
|
elif search(key, r'^p\d_level$'):
|
|
par['level_%c' % key[1]] = float(val)
|
|
elif re.match(r'output\d', key):
|
|
continue
|
|
elif starting(key, ('attack', 'ratio', 'release', 'makeup', 'knee',
|
|
'threshold')) \
|
|
or re.search('_freq$', key):
|
|
par[key_change(key)] = float(val)
|
|
elif search(key, '_mode$'):
|
|
par[key_change(key)] = int(val)
|
|
elif key.startswith('freq'):
|
|
num = int(key[-1])
|
|
par['split_%d_%d' % (num+1, num+2)] = float(val)
|
|
else:
|
|
print('!! <%s> = `%s`' % (key, val), file=sys.stderr)
|
|
par[key] = val
|
|
print('%d skipped' % skipped, file=sys.stderr)
|
|
return par
|
|
|
|
|
|
get_params = {
|
|
'multibandcompressor': multibandcompressor_get_params,
|
|
'filter': filter_get_params,
|
|
'eq8': eq_get_params,
|
|
}
|
|
fx_names = {'eq8': 'equalizer8band'}
|
|
|
|
|
|
def ls_value_format(v):
|
|
if type(v) is bool:
|
|
return 'true' if v else 'false'
|
|
if type(v) is int:
|
|
return str(v)
|
|
if type(v) is float:
|
|
return str(v)
|
|
if type(v) is str:
|
|
return '"%s"' % v # let's hope no quote inside!
|
|
raise ValueError('Unsupported type')
|
|
|
|
|
|
def ls_format(params, plugin_name):
|
|
param_set = ', '.join(['{}={}'.format(k, ls_value_format(v))
|
|
for k, v in sorted(params.items())])
|
|
return ' a = ladspa.%s(%s, a)' % \
|
|
(fx_names[plugin_name] if plugin_name in fx_names
|
|
else plugin_name, param_set)
|
|
|
|
|
|
def usage():
|
|
print('%s: Convert an XML file created by calfjackhost to '
|
|
'liquidsoap-equivalent code, making use of calf-ladspa' %
|
|
sys.argv[0])
|
|
print('\nUsage:')
|
|
print(' %s FILENAME.xml [PRESET]' % sys.argv[0])
|
|
print('\nIf PRESET is omitted, the command will print a list of available '
|
|
'presets found in the specified file')
|
|
print('\nIf PRESET is given, the command will convert that preset in '
|
|
'liquidsoap ladspa code')
|
|
|
|
|
|
def get_parser():
|
|
p = argparse.ArgumentParser()
|
|
p.add_argument('--function-name', type=str, default='calffilter',
|
|
help='Generate a liquidsoap function with this name')
|
|
p.add_argument('fname', nargs=1,
|
|
help='An XML file generated by calfjackhost')
|
|
p.add_argument('presets', nargs='*',
|
|
help='All the filters you want to use')
|
|
return p
|
|
|
|
|
|
if __name__ == '__main__':
|
|
p = get_parser()
|
|
args = p.parse_args()
|
|
dom = parse(args.fname[0])
|
|
if not args.presets:
|
|
print('available presets:')
|
|
for preset in dom.getElementsByTagName('preset'):
|
|
print('-', preset.attributes['name'].value)
|
|
sys.exit(0)
|
|
print('def %s(a) =' % args.function_name)
|
|
for preset in args.presets:
|
|
pr_info = [p for p in dom.getElementsByTagName('preset')
|
|
if p.attributes['name'].value == preset][0]
|
|
raw_params = parse_params(pr_info)
|
|
fx_type = pr_info.attributes['plugin'].value
|
|
if fx_type not in get_params:
|
|
print('plugin <%s> unsupported! output will probably be wrong' %
|
|
fx_type, file=sys.stderr)
|
|
params = raw_params
|
|
else:
|
|
params = get_params[fx_type](raw_params)
|
|
print(ls_format(params, fx_type))
|
|
print(' a')
|
|
print('end')
|