am-filters/calf2ladspa/calf2ladspa.py

203 lines
6.8 KiB
Python
Raw Normal View History

2018-08-29 12:24:48 +02:00
#!/usr/bin/env python3
import sys
from xml.dom.minidom import parse
import re
2018-09-09 22:51:43 +02:00
from collections import defaultdict
import argparse
2018-08-29 12:24:48 +02:00
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)
2018-09-09 22:51:43 +02:00
def search(key, *regexps):
return any(bool(re.search(r, key)) for r in regexps)
2018-08-29 12:24:48 +02:00
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 = {}
2018-09-09 22:51:43 +02:00
skipped = 0
for key, val in params.items():
2018-08-29 12:24:48 +02:00
if starting(key, ('level_', 'meter_', 'clip_', 'detection',
2018-09-09 22:51:43 +02:00
'compression', 'mode', 'output', 'notebook',
)):
skipped += 1
2018-08-29 12:24:48 +02:00
continue
if key == 'bypass' or key.startswith('solo'):
2018-09-09 22:51:43 +02:00
newparams[key_change(key)] = bool(int(val))
elif search(key, r'p\d_q$'):
par['q_%c' % key[1]] = float(val)
2018-08-29 12:24:48 +02:00
elif key.startswith('bypass') or re.match(r'output\d', key):
continue
2018-09-09 22:51:43 +02:00
elif search(key, 's_level$'):
newparams['level_%c' % key[0]] = bool(int(val))
2018-08-29 12:24:48 +02:00
elif starting(key, ('attack', 'ratio', 'release', 'makeup', 'knee',
'threshold')):
2018-09-09 22:51:43 +02:00
newparams[key_change(key)] = float(val)
elif search(key, '^mode', '^output', '_mode$'):
newparams[key_change(key)] = int(val)
2018-08-29 12:24:48 +02:00
elif key.startswith('freq'):
num = int(key[-1])
2018-09-09 22:51:43 +02:00
newparams['split_%d_%d' % (num+1, num+2)] = float(val)
2018-08-29 12:24:48 +02:00
else:
2018-09-09 22:51:43 +02:00
print('!!', key, val, file=sys.stderr)
if skipped:
print('%d skipped' % skipped, file=sys.stderr)
2018-08-29 12:24:48 +02:00
return newparams
def filter_get_params(params):
newparams = {}
2018-09-09 22:51:43 +02:00
skipped = 0
2018-08-29 12:24:48 +02:00
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)
2018-09-09 22:51:43 +02:00
skipped += 1
if skipped:
print('%d skipped' % skipped, file=sys.stderr)
2018-08-29 12:24:48 +02:00
return newparams
2018-09-09 22:51:43 +02:00
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
2018-08-29 12:24:48 +02:00
get_params = {
'multibandcompressor': multibandcompressor_get_params,
'filter': filter_get_params,
2018-09-09 22:51:43 +02:00
'eq8': eq_get_params,
2018-08-29 12:24:48 +02:00
}
2018-09-09 22:51:43 +02:00
fx_names = {'eq8': 'equalizer8band'}
2018-08-29 12:24:48 +02:00
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))
2018-09-09 22:51:43 +02:00
for k, v in sorted(params.items())])
return ' a = ladspa.%s(%s, a)' % \
2018-09-09 22:51:43 +02:00
(fx_names[plugin_name] if plugin_name in fx_names
else plugin_name, param_set)
2018-08-29 12:24:48 +02:00
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
2018-08-29 12:24:48 +02:00
if __name__ == '__main__':
p = get_parser()
args = p.parse_args()
dom = parse(args.fname[0])
if not args.presets:
2018-08-29 12:24:48 +02:00
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')