mirror of
https://github.com/ZDoom/fluidsynth.git
synced 2025-04-22 07:30:50 +00:00
Merge branch 'master' into fluidsynth-on-mcu-1
This commit is contained in:
commit
c594bdf466
14 changed files with 2146 additions and 1298 deletions
53
.clang-tidy
Normal file
53
.clang-tidy
Normal file
|
@ -0,0 +1,53 @@
|
|||
---
|
||||
Checks: 'clang-diagnostic-*,clang-analyzer-*,-*,cert-*,clang-analyzer-*,performance-*,readability-avoid-const-params-in-decls,readability-braces-around-statements,readability-delete-null-pointer,readability-implicit-bool-conversion,readability-inconsistent-declaration-parameter-name,readability-misleading-indentation,readability-misplaced-array-index,readability-non-const-parameter,readability-redundant-control-flow,readability-redundant-declaration,readability-redundant-function-ptr-dereference,readability-simplify-boolean-expr'
|
||||
WarningsAsErrors: ''
|
||||
HeaderFilterRegex: ''
|
||||
AnalyzeTemporaryDtors: false
|
||||
User: tom
|
||||
CheckOptions:
|
||||
- key: cert-dcl59-cpp.HeaderFileExtensions
|
||||
value: h,hh,hpp,hxx
|
||||
- key: cert-err09-cpp.CheckThrowTemporaries
|
||||
value: '1'
|
||||
- key: cert-err61-cpp.CheckThrowTemporaries
|
||||
value: '1'
|
||||
- key: cert-oop11-cpp.IncludeStyle
|
||||
value: llvm
|
||||
- key: google-readability-braces-around-statements.ShortStatementLines
|
||||
value: '1'
|
||||
- key: google-readability-function-size.StatementThreshold
|
||||
value: '800'
|
||||
- key: google-readability-namespace-comments.ShortNamespaceLines
|
||||
value: '10'
|
||||
- key: google-readability-namespace-comments.SpacesBeforeComments
|
||||
value: '2'
|
||||
- key: modernize-loop-convert.MaxCopySize
|
||||
value: '16'
|
||||
- key: modernize-loop-convert.MinConfidence
|
||||
value: reasonable
|
||||
- key: modernize-loop-convert.NamingStyle
|
||||
value: CamelCase
|
||||
- key: modernize-pass-by-value.IncludeStyle
|
||||
value: llvm
|
||||
- key: modernize-replace-auto-ptr.IncludeStyle
|
||||
value: llvm
|
||||
- key: modernize-use-nullptr.NullMacros
|
||||
value: 'NULL'
|
||||
- key: performance-faster-string-find.StringLikeClasses
|
||||
value: 'std::basic_string'
|
||||
- key: performance-for-range-copy.WarnOnAllAutoCopies
|
||||
value: '0'
|
||||
- key: performance-inefficient-string-concatenation.StrictMode
|
||||
value: '0'
|
||||
- key: performance-type-promotion-in-math-fn.IncludeStyle
|
||||
value: llvm
|
||||
- key: performance-unnecessary-value-param.IncludeStyle
|
||||
value: llvm
|
||||
- key: readability-braces-around-statements.ShortStatementLines
|
||||
value: '0'
|
||||
- key: readability-simplify-boolean-expr.ChainedConditionalAssignment
|
||||
value: '0'
|
||||
- key: readability-simplify-boolean-expr.ChainedConditionalReturn
|
||||
value: '0'
|
||||
...
|
||||
|
64
doc/ladspa.md
Normal file
64
doc/ladspa.md
Normal file
|
@ -0,0 +1,64 @@
|
|||
# FluidSynth LADSPA Interface
|
||||
|
||||
The [LADSPA](http://ladspa.org/) (Linux Audio Developer's Simple Plugin API)
|
||||
binding can be used to route the FluidSynth audio output through any number
|
||||
of LADSPA plugins. As the name implies, it is only available on Linux.
|
||||
|
||||
## Configuration
|
||||
|
||||
To configure and compile FluidSynth with LADSPA support, make sure you have
|
||||
the LADSPA SDK (basically the ladspa.h header file) installed. Then enable
|
||||
LADSPA when calling cmake:
|
||||
|
||||
cmake -Denable-ladspa=1 <path-to-source>
|
||||
|
||||
You should see `LADSPA support: yes` in the cmake output.
|
||||
|
||||
To enable the LADSPA engine, use the `synth.ladspa.active` setting when
|
||||
starting FluidSynth:
|
||||
|
||||
fluidsynth -o synth.ladspa.active=1 ...
|
||||
|
||||
|
||||
# Signal Flow
|
||||
|
||||
The LADSPA effects unit runs immediately after the internal reverb and chorus
|
||||
effects have been processed. When no plugins have been configured, the
|
||||
effects unit is dormant and uses no additional system resources.
|
||||
|
||||
When at least one plugin is configured and the engine is activated, the
|
||||
rendered audio is passed into the LADSPA effects unit, each plugin is
|
||||
run in the order that they were created and the resulting audio is
|
||||
passed back into FluidSynth (and from there to the sound card or other
|
||||
output).
|
||||
|
||||
|
||||
# Loading and Connecting Plugins
|
||||
|
||||
Currently the only way to configure the effects unit is via the FluidSynth
|
||||
shell or via a config file.
|
||||
|
||||
## Example Setups
|
||||
|
||||
All examples assume that your `LADSPA_PATH` environment variable points
|
||||
to the directory containing the plugin libraries (e.g. /usr/lib/ladspa).
|
||||
|
||||
### Single Plugin
|
||||
|
||||
The following loads the delay.so plugin library from the LADSPA SDK and
|
||||
instantiates the `delay_5s` plugin from that library. It connects the
|
||||
main left channel output from FluidSynth with the plugin input, the
|
||||
main left channel input to FluidSynth with the plugin output. It also
|
||||
sets the two control ports of the plugin to example values and starts
|
||||
the engine.
|
||||
|
||||
ladspa_plugin delay.so delay_5s
|
||||
ladspa_port Input < in1_L
|
||||
ladspa_port Output > out1_L
|
||||
ladspa_port Delay = 1.0
|
||||
ladspa_port Dry/Wet = 0.5
|
||||
|
||||
ladspa_start
|
||||
|
||||
The audible effect should be an untouched right channel and a slightly
|
||||
lower volume on the left with a delay effect of 1 second on top.
|
289
run-clang-tidy.py
Normal file
289
run-clang-tidy.py
Normal file
|
@ -0,0 +1,289 @@
|
|||
#!/usr/bin/env python
|
||||
#
|
||||
#===- run-clang-tidy.py - Parallel clang-tidy runner ---------*- python -*--===#
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is distributed under the University of Illinois Open Source
|
||||
# License. See LICENSE.TXT for details.
|
||||
#
|
||||
#===------------------------------------------------------------------------===#
|
||||
# FIXME: Integrate with clang-tidy-diff.py
|
||||
|
||||
"""
|
||||
Parallel clang-tidy runner
|
||||
==========================
|
||||
|
||||
Runs clang-tidy over all files in a compilation database. Requires clang-tidy
|
||||
and clang-apply-replacements in $PATH.
|
||||
|
||||
Example invocations.
|
||||
- Run clang-tidy on all files in the current working directory with a default
|
||||
set of checks and show warnings in the cpp files and all project headers.
|
||||
run-clang-tidy.py $PWD
|
||||
|
||||
- Fix all header guards.
|
||||
run-clang-tidy.py -fix -checks=-*,llvm-header-guard
|
||||
|
||||
- Fix all header guards included from clang-tidy and header guards
|
||||
for clang-tidy headers.
|
||||
run-clang-tidy.py -fix -checks=-*,llvm-header-guard extra/clang-tidy \
|
||||
-header-filter=extra/clang-tidy
|
||||
|
||||
Compilation database setup:
|
||||
http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html
|
||||
"""
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import argparse
|
||||
import glob
|
||||
import json
|
||||
import multiprocessing
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
import threading
|
||||
import traceback
|
||||
import yaml
|
||||
|
||||
is_py2 = sys.version[0] == '2'
|
||||
|
||||
if is_py2:
|
||||
import Queue as queue
|
||||
else:
|
||||
import queue as queue
|
||||
|
||||
def find_compilation_database(path):
|
||||
"""Adjusts the directory until a compilation database is found."""
|
||||
result = './'
|
||||
while not os.path.isfile(os.path.join(result, path)):
|
||||
if os.path.realpath(result) == '/':
|
||||
print('Error: could not find compilation database.')
|
||||
sys.exit(1)
|
||||
result += '../'
|
||||
return os.path.realpath(result)
|
||||
|
||||
|
||||
def get_tidy_invocation(f, clang_tidy_binary, checks, tmpdir, build_path,
|
||||
header_filter, extra_arg, extra_arg_before, quiet):
|
||||
"""Gets a command line for clang-tidy."""
|
||||
start = [clang_tidy_binary]
|
||||
if header_filter is not None:
|
||||
start.append('-header-filter=' + header_filter)
|
||||
else:
|
||||
# Show warnings in all in-project headers by default.
|
||||
start.append('-header-filter=^' + build_path + '/.*')
|
||||
if checks:
|
||||
start.append('-checks=' + checks)
|
||||
if tmpdir is not None:
|
||||
start.append('-export-fixes')
|
||||
# Get a temporary file. We immediately close the handle so clang-tidy can
|
||||
# overwrite it.
|
||||
(handle, name) = tempfile.mkstemp(suffix='.yaml', dir=tmpdir)
|
||||
os.close(handle)
|
||||
start.append(name)
|
||||
for arg in extra_arg:
|
||||
start.append('-extra-arg=%s' % arg)
|
||||
for arg in extra_arg_before:
|
||||
start.append('-extra-arg-before=%s' % arg)
|
||||
start.append('-p=' + build_path)
|
||||
if quiet:
|
||||
start.append('-quiet')
|
||||
start.append(f)
|
||||
return start
|
||||
|
||||
|
||||
def merge_replacement_files(tmpdir, mergefile):
|
||||
"""Merge all replacement files in a directory into a single file"""
|
||||
# The fixes suggested by clang-tidy >= 4.0.0 are given under
|
||||
# the top level key 'Diagnostics' in the output yaml files
|
||||
mergekey="Diagnostics"
|
||||
merged=[]
|
||||
for replacefile in glob.iglob(os.path.join(tmpdir, '*.yaml')):
|
||||
content = yaml.safe_load(open(replacefile, 'r'))
|
||||
if not content:
|
||||
continue # Skip empty files.
|
||||
merged.extend(content.get(mergekey, []))
|
||||
|
||||
if merged:
|
||||
# MainSourceFile: The key is required by the definition inside
|
||||
# include/clang/Tooling/ReplacementsYaml.h, but the value
|
||||
# is actually never used inside clang-apply-replacements,
|
||||
# so we set it to '' here.
|
||||
output = { 'MainSourceFile': '', mergekey: merged }
|
||||
with open(mergefile, 'w') as out:
|
||||
yaml.safe_dump(output, out)
|
||||
else:
|
||||
# Empty the file:
|
||||
open(mergefile, 'w').close()
|
||||
|
||||
|
||||
def check_clang_apply_replacements_binary(args):
|
||||
"""Checks if invoking supplied clang-apply-replacements binary works."""
|
||||
try:
|
||||
subprocess.check_call([args.clang_apply_replacements_binary, '--version'])
|
||||
except:
|
||||
print('Unable to run clang-apply-replacements. Is clang-apply-replacements '
|
||||
'binary correctly specified?', file=sys.stderr)
|
||||
traceback.print_exc()
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def apply_fixes(args, tmpdir):
|
||||
"""Calls clang-apply-fixes on a given directory."""
|
||||
invocation = [args.clang_apply_replacements_binary]
|
||||
if args.format:
|
||||
invocation.append('-format')
|
||||
if args.style:
|
||||
invocation.append('-style=' + args.style)
|
||||
invocation.append(tmpdir)
|
||||
subprocess.call(invocation)
|
||||
|
||||
|
||||
def run_tidy(args, tmpdir, build_path, queue):
|
||||
"""Takes filenames out of queue and runs clang-tidy on them."""
|
||||
while True:
|
||||
name = queue.get()
|
||||
invocation = get_tidy_invocation(name, args.clang_tidy_binary, args.checks,
|
||||
tmpdir, build_path, args.header_filter,
|
||||
args.extra_arg, args.extra_arg_before,
|
||||
args.quiet)
|
||||
sys.stdout.write(' '.join(invocation) + '\n')
|
||||
subprocess.call(invocation)
|
||||
queue.task_done()
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description='Runs clang-tidy over all files '
|
||||
'in a compilation database. Requires '
|
||||
'clang-tidy and clang-apply-replacements in '
|
||||
'$PATH.')
|
||||
parser.add_argument('-clang-tidy-binary', metavar='PATH',
|
||||
default='clang-tidy',
|
||||
help='path to clang-tidy binary')
|
||||
parser.add_argument('-clang-apply-replacements-binary', metavar='PATH',
|
||||
default='clang-apply-replacements',
|
||||
help='path to clang-apply-replacements binary')
|
||||
parser.add_argument('-checks', default=None,
|
||||
help='checks filter, when not specified, use clang-tidy '
|
||||
'default')
|
||||
parser.add_argument('-header-filter', default=None,
|
||||
help='regular expression matching the names of the '
|
||||
'headers to output diagnostics from. Diagnostics from '
|
||||
'the main file of each translation unit are always '
|
||||
'displayed.')
|
||||
parser.add_argument('-export-fixes', metavar='filename', dest='export_fixes',
|
||||
help='Create a yaml file to store suggested fixes in, '
|
||||
'which can be applied with clang-apply-replacements.')
|
||||
parser.add_argument('-j', type=int, default=0,
|
||||
help='number of tidy instances to be run in parallel.')
|
||||
parser.add_argument('files', nargs='*', default=['.*'],
|
||||
help='files to be processed (regex on path)')
|
||||
parser.add_argument('-fix', action='store_true', help='apply fix-its')
|
||||
parser.add_argument('-format', action='store_true', help='Reformat code '
|
||||
'after applying fixes')
|
||||
parser.add_argument('-style', default='file', help='The style of reformat '
|
||||
'code after applying fixes')
|
||||
parser.add_argument('-p', dest='build_path',
|
||||
help='Path used to read a compile command database.')
|
||||
parser.add_argument('-extra-arg', dest='extra_arg',
|
||||
action='append', default=[],
|
||||
help='Additional argument to append to the compiler '
|
||||
'command line.')
|
||||
parser.add_argument('-extra-arg-before', dest='extra_arg_before',
|
||||
action='append', default=[],
|
||||
help='Additional argument to prepend to the compiler '
|
||||
'command line.')
|
||||
parser.add_argument('-quiet', action='store_true',
|
||||
help='Run clang-tidy in quiet mode')
|
||||
args = parser.parse_args()
|
||||
|
||||
db_path = 'compile_commands.json'
|
||||
|
||||
if args.build_path is not None:
|
||||
build_path = args.build_path
|
||||
else:
|
||||
# Find our database
|
||||
build_path = find_compilation_database(db_path)
|
||||
|
||||
try:
|
||||
invocation = [args.clang_tidy_binary, '-list-checks']
|
||||
invocation.append('-p=' + build_path)
|
||||
if args.checks:
|
||||
invocation.append('-checks=' + args.checks)
|
||||
invocation.append('-')
|
||||
print(subprocess.check_output(invocation))
|
||||
except:
|
||||
print("Unable to run clang-tidy.", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
# Load the database and extract all files.
|
||||
database = json.load(open(os.path.join(build_path, db_path)))
|
||||
files = [entry['file'] for entry in database]
|
||||
|
||||
max_task = args.j
|
||||
if max_task == 0:
|
||||
max_task = multiprocessing.cpu_count()
|
||||
|
||||
tmpdir = None
|
||||
if args.fix or args.export_fixes:
|
||||
check_clang_apply_replacements_binary(args)
|
||||
tmpdir = tempfile.mkdtemp()
|
||||
|
||||
# Build up a big regexy filter from all command line arguments.
|
||||
file_name_re = re.compile('|'.join(args.files))
|
||||
|
||||
try:
|
||||
# Spin up a bunch of tidy-launching threads.
|
||||
task_queue = queue.Queue(max_task)
|
||||
for _ in range(max_task):
|
||||
t = threading.Thread(target=run_tidy,
|
||||
args=(args, tmpdir, build_path, task_queue))
|
||||
t.daemon = True
|
||||
t.start()
|
||||
|
||||
# Fill the queue with files.
|
||||
for name in files:
|
||||
if file_name_re.search(name):
|
||||
task_queue.put(name)
|
||||
|
||||
# Wait for all threads to be done.
|
||||
task_queue.join()
|
||||
|
||||
except KeyboardInterrupt:
|
||||
# This is a sad hack. Unfortunately subprocess goes
|
||||
# bonkers with ctrl-c and we start forking merrily.
|
||||
print('\nCtrl-C detected, goodbye.')
|
||||
if tmpdir:
|
||||
shutil.rmtree(tmpdir)
|
||||
os.kill(0, 9)
|
||||
|
||||
return_code = 0
|
||||
if args.export_fixes:
|
||||
print('Writing fixes to ' + args.export_fixes + ' ...')
|
||||
try:
|
||||
merge_replacement_files(tmpdir, args.export_fixes)
|
||||
except:
|
||||
print('Error exporting fixes.\n', file=sys.stderr)
|
||||
traceback.print_exc()
|
||||
return_code=1
|
||||
|
||||
if args.fix:
|
||||
print('Applying fixes ...')
|
||||
try:
|
||||
apply_fixes(args, tmpdir)
|
||||
except:
|
||||
print('Error applying fixes.\n', file=sys.stderr)
|
||||
traceback.print_exc()
|
||||
return_code=1
|
||||
|
||||
if tmpdir:
|
||||
shutil.rmtree(tmpdir)
|
||||
sys.exit(return_code)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
|
@ -48,6 +48,11 @@ struct _fluid_cmd_handler_t {
|
|||
|
||||
fluid_midi_router_rule_t *cmd_rule; /* Rule currently being processed by shell command handler */
|
||||
int cmd_rule_type; /* Type of the rule (#fluid_midi_router_rule_type) */
|
||||
|
||||
#ifdef LADSPA
|
||||
/* Instance id of the LADSPA plugin currently being processed by shell command handler */
|
||||
int ladspa_plugin_id;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
|
@ -176,16 +181,22 @@ static const fluid_cmd_int_t fluid_commands[] = {
|
|||
"echo arg Print arg" },
|
||||
/* LADSPA-related commands */
|
||||
#ifdef LADSPA
|
||||
{ "ladspa_clear", "ladspa", (fluid_cmd_func_t) fluid_LADSPA_handle_clear,
|
||||
"ladspa_clear Resets LADSPA effect unit to bypass state"},
|
||||
{ "ladspa_add", "ladspa", (fluid_cmd_func_t) fluid_LADSPA_handle_add,
|
||||
"ladspa_add lib plugin n1 <- p1 n2 -> p2 ... Loads and connects LADSPA plugin"},
|
||||
{ "ladspa_start", "ladspa", (fluid_cmd_func_t) fluid_LADSPA_handle_start,
|
||||
"ladspa_start Starts LADSPA effect unit"},
|
||||
{ "ladspa_declnode", "ladspa", (fluid_cmd_func_t) fluid_LADSPA_handle_declnode,
|
||||
"ladspa_declnode node value Declares control node `node' with value `value'"},
|
||||
{ "ladspa_setnode", "ladspa", (fluid_cmd_func_t) fluid_LADSPA_handle_setnode,
|
||||
"ladspa_setnode node value Assigns `value' to `node'"},
|
||||
{ "ladspa_plugin", "ladspa", (fluid_cmd_func_t) fluid_handle_ladspa_plugin,
|
||||
"ladspa_plugin Instantiate a new LADSPA plugin"},
|
||||
{ "ladspa_port", "ladspa", (fluid_cmd_func_t) fluid_handle_ladspa_port,
|
||||
"ladspa_port Connect a LADSPA plugin port"},
|
||||
{ "ladspa_node", "ladspa", (fluid_cmd_func_t) fluid_handle_ladspa_node,
|
||||
"ladspa_node Create a LADSPA audio or control node"},
|
||||
{ "ladspa_control", "ladspa", (fluid_cmd_func_t) fluid_handle_ladspa_control,
|
||||
"ladspa_control Set the value of a LADSPA control node"},
|
||||
{ "ladspa_check", "ladspa", (fluid_cmd_func_t) fluid_handle_ladspa_check,
|
||||
"ladspa_check Check LADSPA configuration"},
|
||||
{ "ladspa_start", "ladspa", (fluid_cmd_func_t) fluid_handle_ladspa_start,
|
||||
"ladspa_start Start LADSPA effects"},
|
||||
{ "ladspa_stop", "ladspa", (fluid_cmd_func_t) fluid_handle_ladspa_stop,
|
||||
"ladspa_stop Stop LADSPA effect unit"},
|
||||
{ "ladspa_reset", "ladspa", (fluid_cmd_func_t) fluid_handle_ladspa_reset,
|
||||
"ladspa_reset Stop and reset LADSPA effects"},
|
||||
#endif
|
||||
{ "router_clear", "router", (fluid_cmd_func_t) fluid_handle_router_clear,
|
||||
"router_clear Clears all routing rules from the midi router"},
|
||||
|
@ -1826,6 +1837,266 @@ int fluid_handle_router_par2(fluid_cmd_handler_t* handler, int ac, char** av, fl
|
|||
return FLUID_OK;
|
||||
}
|
||||
|
||||
#ifdef LADSPA
|
||||
|
||||
#define CHECK_LADSPA_ENABLED(_fx, _out) \
|
||||
if (_fx == NULL) \
|
||||
{ \
|
||||
fluid_ostream_printf(_out, "LADSPA is not enabled.\n"); \
|
||||
return FLUID_FAILED; \
|
||||
}
|
||||
|
||||
#define LADSPA_ERR_LEN (1024)
|
||||
|
||||
int fluid_handle_ladspa_start(fluid_cmd_handler_t *handler, int ac, char **av, fluid_ostream_t out)
|
||||
{
|
||||
fluid_ladspa_fx_t *fx = handler->synth->ladspa_fx;
|
||||
char error[LADSPA_ERR_LEN];
|
||||
|
||||
CHECK_LADSPA_ENABLED(fx, out);
|
||||
|
||||
if (fluid_ladspa_is_active(fx))
|
||||
{
|
||||
fluid_ostream_printf(out, "LADSPA already started.\n");
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
|
||||
if (fluid_ladspa_check(fx, error, LADSPA_ERR_LEN) != FLUID_OK)
|
||||
{
|
||||
fluid_ostream_printf(out, "LADSPA check failed: %s", error);
|
||||
fluid_ostream_printf(out, "LADSPA not started.\n");
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
|
||||
if (fluid_ladspa_activate(fx) != FLUID_OK)
|
||||
{
|
||||
fluid_ostream_printf(out, "Unable to start LADSPA.\n");
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
int fluid_handle_ladspa_stop(fluid_cmd_handler_t *handler, int ac, char **av, fluid_ostream_t out)
|
||||
{
|
||||
fluid_ladspa_fx_t *fx = handler->synth->ladspa_fx;
|
||||
|
||||
CHECK_LADSPA_ENABLED(fx, out);
|
||||
|
||||
if (!fluid_ladspa_is_active(fx))
|
||||
{
|
||||
fluid_ostream_printf(out, "LADSPA has not been started.\n");
|
||||
}
|
||||
|
||||
if (fluid_ladspa_deactivate(fx) != FLUID_OK)
|
||||
{
|
||||
fluid_ostream_printf(out, "Unable to stop LADSPA.\n");
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
int fluid_handle_ladspa_reset(fluid_cmd_handler_t *handler, int ac, char **av, fluid_ostream_t out)
|
||||
{
|
||||
fluid_ladspa_fx_t *fx = handler->synth->ladspa_fx;
|
||||
|
||||
CHECK_LADSPA_ENABLED(fx, out);
|
||||
|
||||
fluid_ladspa_reset(fx);
|
||||
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
int fluid_handle_ladspa_check(fluid_cmd_handler_t *handler, int ac, char **av, fluid_ostream_t out)
|
||||
{
|
||||
fluid_ladspa_fx_t *fx = handler->synth->ladspa_fx;
|
||||
char error[LADSPA_ERR_LEN];
|
||||
|
||||
CHECK_LADSPA_ENABLED(fx, out);
|
||||
|
||||
if (fluid_ladspa_check(fx, error, LADSPA_ERR_LEN) != FLUID_OK)
|
||||
{
|
||||
fluid_ostream_printf(out, "LADSPA check failed: %s", error);
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
|
||||
fluid_ostream_printf(out, "LADSPA check ok\n");
|
||||
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
int fluid_handle_ladspa_control(fluid_cmd_handler_t *handler, int ac, char **av, fluid_ostream_t out)
|
||||
{
|
||||
fluid_ladspa_fx_t *fx = handler->synth->ladspa_fx;
|
||||
|
||||
CHECK_LADSPA_ENABLED(fx, out);
|
||||
|
||||
if (ac != 2)
|
||||
{
|
||||
fluid_ostream_printf(out, "ladspa_control needs two arguments: node name and value.\n");
|
||||
return FLUID_FAILED;
|
||||
};
|
||||
|
||||
/* Redundant check, just here to give a more detailed error message */
|
||||
if (!fluid_ladspa_node_exists(fx, av[0]))
|
||||
{
|
||||
fluid_ostream_printf(out, "Node '%s' not found.\n", av[0]);
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
|
||||
if (fluid_ladspa_set_control_node(fx, av[0], atof(av[1])) != FLUID_OK)
|
||||
{
|
||||
fluid_ostream_printf(out, "Failed to set node '%s', maybe it's not a control node?\n",
|
||||
av[0]);
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
|
||||
return FLUID_OK;
|
||||
};
|
||||
|
||||
int fluid_handle_ladspa_node(fluid_cmd_handler_t *handler, int ac, char **av, fluid_ostream_t out)
|
||||
{
|
||||
fluid_ladspa_fx_t *fx = handler->synth->ladspa_fx;
|
||||
char *name;
|
||||
char *type;
|
||||
|
||||
CHECK_LADSPA_ENABLED(fx, out);
|
||||
|
||||
if (ac < 2)
|
||||
{
|
||||
fluid_ostream_printf(out, "ladspa_node needs at least two arguments: node name and type.\n");
|
||||
return FLUID_FAILED;
|
||||
};
|
||||
|
||||
name = av[0];
|
||||
type = av[1];
|
||||
|
||||
/* audio node - additional no arguments */
|
||||
if (FLUID_STRCMP(type, "audio") == 0)
|
||||
{
|
||||
if (fluid_ladspa_add_audio_node(fx, name) != FLUID_OK)
|
||||
{
|
||||
fluid_ostream_printf(out, "Failed to add audio node.\n");
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
}
|
||||
/* control node - arguments: <val> */
|
||||
else if (FLUID_STRCMP(type, "control") == 0)
|
||||
{
|
||||
if (ac != 3)
|
||||
{
|
||||
fluid_ostream_printf(out, "Control nodes need 3 arguments.\n");
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
|
||||
if (fluid_ladspa_add_control_node(fx, name, atof(av[2])) != FLUID_OK)
|
||||
{
|
||||
fluid_ostream_printf(out, "Failed to add contrl node.\n");
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
}
|
||||
else {
|
||||
fluid_ostream_printf(out, "Invalid node type.\n");
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
|
||||
return FLUID_OK;
|
||||
};
|
||||
|
||||
int fluid_handle_ladspa_plugin(fluid_cmd_handler_t *handler, int ac, char **av, fluid_ostream_t out)
|
||||
{
|
||||
fluid_ladspa_fx_t *fx = handler->synth->ladspa_fx;
|
||||
int plugin_id;
|
||||
|
||||
CHECK_LADSPA_ENABLED(fx, out);
|
||||
|
||||
if (ac != 2)
|
||||
{
|
||||
fluid_ostream_printf(out, "ladspa_plugin needs 2 arguments: library and plugin id.\n");
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
|
||||
plugin_id = fluid_ladspa_add_plugin(fx, av[0], av[1]);
|
||||
if (plugin_id < 0)
|
||||
{
|
||||
fluid_ostream_printf(out, "Failed to add plugin.\n");
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
|
||||
/* store current plugin in the handler, so that subsequent ladspa_port
|
||||
* commands know which plugin to configure */
|
||||
handler->ladspa_plugin_id = plugin_id;
|
||||
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
int fluid_handle_ladspa_port(fluid_cmd_handler_t *handler, int ac, char **av, fluid_ostream_t out)
|
||||
{
|
||||
fluid_ladspa_fx_t *fx = handler->synth->ladspa_fx;
|
||||
int dir;
|
||||
|
||||
CHECK_LADSPA_ENABLED(fx, out);
|
||||
|
||||
if (ac != 3)
|
||||
{
|
||||
fluid_ostream_printf(out, "ladspa_port needs 3 arguments: "
|
||||
"port name, direction and node name.\n");
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
|
||||
if (handler->ladspa_plugin_id == -1)
|
||||
{
|
||||
fluid_ostream_printf(out, "Please choose a plugin with ladspa_plugin first.\n");
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
|
||||
if (FLUID_STRCMP(av[1], "<") == 0)
|
||||
{
|
||||
dir = FLUID_LADSPA_INPUT;
|
||||
}
|
||||
else if (FLUID_STRCMP(av[1], ">") == 0)
|
||||
{
|
||||
dir = FLUID_LADSPA_OUTPUT;
|
||||
}
|
||||
else if (FLUID_STRCMP(av[1], "=") == 0)
|
||||
{
|
||||
dir = FLUID_LADSPA_FIXED;
|
||||
}
|
||||
else
|
||||
{
|
||||
fluid_ostream_printf(out, "Invalid direction, please use <, > or =\n");
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
|
||||
/* Check port and node name before trying to connect them by name. This is
|
||||
* redundant, as fluid_ladspa_connect checks them as well, but we do it
|
||||
* here anyway to give the user better feedback in case a port or node
|
||||
* could not be found.
|
||||
*/
|
||||
if (!fluid_ladspa_port_exists(fx, handler->ladspa_plugin_id, av[0]))
|
||||
{
|
||||
fluid_ostream_printf(out, "Port '%s' not found.\n", av[0]);
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
|
||||
if (dir != FLUID_LADSPA_FIXED && !fluid_ladspa_node_exists(fx, av[2]))
|
||||
{
|
||||
fluid_ostream_printf(out, "Node '%s' not found.\n", av[2]);
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
|
||||
if (fluid_ladspa_connect(fx, handler->ladspa_plugin_id, dir, av[0], av[2]) != FLUID_OK)
|
||||
{
|
||||
fluid_ostream_printf(out, "Failed to connect plugin port.\n");
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
#endif /* LADSPA */
|
||||
|
||||
int
|
||||
fluid_is_number(char* a)
|
||||
{
|
||||
|
@ -1958,6 +2229,10 @@ fluid_cmd_handler_t* new_fluid_cmd_handler(fluid_synth_t* synth, fluid_midi_rout
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef LADSPA
|
||||
handler->ladspa_plugin_id = -1;
|
||||
#endif
|
||||
|
||||
return handler;
|
||||
}
|
||||
|
||||
|
@ -2183,7 +2458,6 @@ fluid_client_t*
|
|||
new_fluid_client(fluid_server_t* server, fluid_settings_t* settings, fluid_socket_t sock)
|
||||
{
|
||||
fluid_client_t* client;
|
||||
fluid_cmd_handler_t* handler;
|
||||
|
||||
client = FLUID_NEW(fluid_client_t);
|
||||
if (client == NULL) {
|
||||
|
@ -2191,19 +2465,14 @@ new_fluid_client(fluid_server_t* server, fluid_settings_t* settings, fluid_socke
|
|||
return NULL;
|
||||
}
|
||||
|
||||
handler = new_fluid_cmd_handler(server->synth, server->router);
|
||||
if (handler == NULL) {
|
||||
goto error_recovery;
|
||||
}
|
||||
|
||||
client->server = server;
|
||||
client->socket = sock;
|
||||
client->settings = settings;
|
||||
client->handler = handler;
|
||||
client->handler = new_fluid_cmd_handler(server->synth, server->router);
|
||||
client->thread = new_fluid_thread("client", (fluid_thread_func_t) fluid_client_run, client,
|
||||
0, FALSE);
|
||||
|
||||
if (client->thread == NULL) {
|
||||
if (client->handler == NULL || client->thread == NULL) {
|
||||
goto error_recovery;
|
||||
}
|
||||
|
||||
|
|
|
@ -86,6 +86,16 @@ int fluid_handle_router_chan(fluid_cmd_handler_t* handler, int ac, char** av, fl
|
|||
int fluid_handle_router_par1(fluid_cmd_handler_t* handler, int ac, char** av, fluid_ostream_t out);
|
||||
int fluid_handle_router_par2(fluid_cmd_handler_t* handler, int ac, char** av, fluid_ostream_t out);
|
||||
|
||||
#ifdef LADSPA
|
||||
int fluid_handle_ladspa_plugin(fluid_cmd_handler_t *handler, int ac, char **av, fluid_ostream_t out);
|
||||
int fluid_handle_ladspa_port(fluid_cmd_handler_t *handler, int ac, char **av, fluid_ostream_t out);
|
||||
int fluid_handle_ladspa_node(fluid_cmd_handler_t *handler, int ac, char **av, fluid_ostream_t out);
|
||||
int fluid_handle_ladspa_control(fluid_cmd_handler_t *handler, int ac, char **av, fluid_ostream_t out);
|
||||
int fluid_handle_ladspa_check(fluid_cmd_handler_t *handler, int ac, char **av, fluid_ostream_t out);
|
||||
int fluid_handle_ladspa_start(fluid_cmd_handler_t *handler, int ac, char **av, fluid_ostream_t out);
|
||||
int fluid_handle_ladspa_stop(fluid_cmd_handler_t *handler, int ac, char **av, fluid_ostream_t out);
|
||||
int fluid_handle_ladspa_reset(fluid_cmd_handler_t *handler, int ac, char **av, fluid_ostream_t out);
|
||||
#endif
|
||||
|
||||
fluid_cmd_t* fluid_cmd_copy(fluid_cmd_t* cmd);
|
||||
void delete_fluid_cmd(fluid_cmd_t* cmd);
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -21,220 +21,133 @@
|
|||
/* Author: Markus Nentwig, nentwig@users.sourceforge.net
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _FLUID_LADSPA_H
|
||||
#define _FLUID_LADSPA_H
|
||||
|
||||
/***************************************************************
|
||||
*
|
||||
* INCLUDES
|
||||
*/
|
||||
|
||||
#include "fluid_sys.h"
|
||||
#include "fluidsynth_priv.h"
|
||||
|
||||
#ifdef LADSPA
|
||||
#include "fluid_list.h"
|
||||
#include <pthread.h>
|
||||
#include <ladspa.h>
|
||||
|
||||
/***************************************************************
|
||||
*
|
||||
* DEFINES
|
||||
*/
|
||||
#define FLUID_LADSPA_MAX_LIBS 100
|
||||
#define FLUID_LADSPA_MAX_PLUGINS 100
|
||||
#define FLUID_LADSPA_MAX_NODES 100
|
||||
#define FLUID_LADSPA_MAX_PATH_LENGTH 512
|
||||
|
||||
/* How many different plugin libraries may be used at the same time? */
|
||||
#define FLUID_LADSPA_MaxLibs 100
|
||||
/* How many plugin instances may be used at the same time? */
|
||||
#define FLUID_LADSPA_MaxPlugins 100
|
||||
/* How many nodes are allowed? */
|
||||
#define FLUID_LADSPA_MaxNodes 100
|
||||
/* How many tokens are allowed in one command line? (for example 152 => max. 50 port plugin allowed) */
|
||||
#define FLUID_LADSPA_MaxTokens 152
|
||||
/* What is the maximum path length? */
|
||||
#define FLUID_LADSPA_MaxPathLength 512
|
||||
/***************************************************************
|
||||
*
|
||||
* ENUM
|
||||
*/
|
||||
#define FLUID_LADSPA_INACTIVE (0)
|
||||
#define FLUID_LADSPA_ACTIVE (1)
|
||||
#define FLUID_LADSPA_RUNNING (2)
|
||||
|
||||
typedef enum {
|
||||
fluid_LADSPA_NoMatch,
|
||||
fluid_LADSPA_PartialMatch,
|
||||
fluid_LADSPA_FullMatch
|
||||
} fluid_LADSPA_Stringmatch_t;
|
||||
typedef enum _fluid_ladspa_dir_t {
|
||||
FLUID_LADSPA_INPUT,
|
||||
FLUID_LADSPA_OUTPUT,
|
||||
FLUID_LADSPA_FIXED
|
||||
|
||||
/* Bypass state of the Fx unit */
|
||||
typedef enum {
|
||||
fluid_LADSPA_Active,
|
||||
fluid_LADSPA_Bypassed,
|
||||
fluid_LADSPA_BypassRequest
|
||||
} fluid_LADSPA_BypassState;
|
||||
} fluid_ladspa_dir_t;
|
||||
|
||||
typedef enum {
|
||||
fluid_LADSPA_node_is_source=1,
|
||||
fluid_LADSPA_node_is_sink=2,
|
||||
fluid_LADSPA_node_is_audio=4,
|
||||
fluid_LADSPA_node_is_control=8,
|
||||
fluid_LADSPA_node_is_dummy=16,
|
||||
fluid_LADSPA_node_is_user_ctrl=32
|
||||
} fluid_LADSPA_nodeflags;
|
||||
typedef enum _fluid_ladspa_node_type_t {
|
||||
FLUID_LADSPA_NODE_AUDIO,
|
||||
FLUID_LADSPA_NODE_CONTROL,
|
||||
|
||||
/* fluid_LADSPA_Node_t
|
||||
* An internal node of the Fx unit.
|
||||
* A 'node' is the 'glue' that connects several LADSPA plugins.
|
||||
* Basically it's a real-valued variable (control node) or a real-valued buffer (audio node).
|
||||
*/
|
||||
typedef struct {
|
||||
LADSPA_Data * buf; /*Either the buffer (Audio node) or a single control value (Control node)*/
|
||||
char * Name; /* Unique identifier*/
|
||||
int InCount; /* How many sources feed into this node? (0 or 1) */
|
||||
int OutCount; /* How many other elements take data out of this node? */
|
||||
int flags;
|
||||
} fluid_LADSPA_Node_t;
|
||||
} fluid_ladspa_node_type_t;
|
||||
|
||||
/*
|
||||
* fluid_LADSPA_Fx_t
|
||||
* Fx unit using LADSPA.
|
||||
* This includes a number of LADSPA plugins, their libraries, nodes etc.
|
||||
* The Fx unit connects its input to Fluidsynth and its output to the soundcard.
|
||||
*/
|
||||
typedef struct {
|
||||
/* LADSPA-plugins are in shared libraries (for example aw.so).
|
||||
* Pointers to them are stored here. A library is uniquely identified through
|
||||
* its filename (full path).*/
|
||||
fluid_synth_t* synth;
|
||||
typedef struct _fluid_ladspa_lib_t
|
||||
{
|
||||
char *filename;
|
||||
void *dlib;
|
||||
LADSPA_Descriptor_Function descriptor;
|
||||
|
||||
int NumberLibs;
|
||||
void * ppvPluginLibs[FLUID_LADSPA_MaxLibs];
|
||||
char * ppvPluginLibNames[FLUID_LADSPA_MaxLibs];
|
||||
} fluid_ladspa_lib_t;
|
||||
|
||||
/*List of plugins (descriptor and instance)
|
||||
* A LADSPA plugin descriptor points to the code, which is executed, when a plugin is run.
|
||||
* The plugin instance is given as a parameter, when calling.
|
||||
*/
|
||||
int NumberPlugins;
|
||||
const LADSPA_Descriptor * PluginDescriptorTable[FLUID_LADSPA_MaxPlugins];
|
||||
LADSPA_Handle * PluginInstanceTable[FLUID_LADSPA_MaxPlugins];
|
||||
typedef struct _fluid_ladspa_port_state_t
|
||||
{
|
||||
int num_inputs;
|
||||
int num_outputs;
|
||||
|
||||
/* List of nodes */
|
||||
int NumberNodes;
|
||||
fluid_LADSPA_Node_t * Nodelist[FLUID_LADSPA_MaxNodes];
|
||||
} fluid_ladspa_port_state_t;
|
||||
|
||||
/* List of Command lines
|
||||
* During the setup phase, each ladspa_add command creates one command sequence. For example:
|
||||
* ./aw.so alienwah_stereo Input <- Master_L_Synth Output -> Master_R_Synth Parameter <- $42.0
|
||||
* Those lists are stored in LADSPA_Command_Sequence.
|
||||
* One command line results in one plugin => size MaxPlugins.
|
||||
*/
|
||||
int NumberCommands;
|
||||
char ** LADSPA_Command_Sequence[FLUID_LADSPA_MaxPlugins];
|
||||
typedef struct _fluid_ladspa_plugin_t
|
||||
{
|
||||
/* plugin instance id unique to the effects unit */
|
||||
int id;
|
||||
|
||||
/* User control nodes
|
||||
* A user control node is declared at any time before the ladspa_start command.
|
||||
* It acts as a constant node, but it has a name and can be changed with the ladspa_nodeset command. */
|
||||
int NumberUserControlNodes;
|
||||
char * UserControlNodeNames[FLUID_LADSPA_MaxNodes];
|
||||
fluid_real_t UserControlNodeValues[FLUID_LADSPA_MaxNodes];
|
||||
const LADSPA_Descriptor *desc;
|
||||
LADSPA_Handle *handle;
|
||||
|
||||
/* Bypass switch
|
||||
* If set, the LADSPA Fx unit does not touch the signal.*/
|
||||
fluid_LADSPA_BypassState Bypass;
|
||||
int active;
|
||||
|
||||
/* Communication between the 'command line' process and the synthesis process.
|
||||
* A possible conflict situation arises, when fluid_clear is called, and starts to destroy
|
||||
* the plugins. But the synthesis thread still processes plugins at the same time. The consequences are ugly.
|
||||
* Therefore ladspa_clear waits for acknowledgement from the synthesis thread, that the Fx unit is bypassed.
|
||||
* 'cond' is used for the communication, the mutex is required for changing the condition.
|
||||
*/
|
||||
pthread_cond_t cond;
|
||||
pthread_mutex_t mutex;
|
||||
} fluid_LADSPA_FxUnit_t;
|
||||
/* Used to keep track of the port connection states */
|
||||
fluid_ladspa_port_state_t *ports;
|
||||
|
||||
/*
|
||||
* misc
|
||||
*/
|
||||
} fluid_ladspa_plugin_t;
|
||||
|
||||
/* Purpose:
|
||||
* Creates a new Fx unit in bypass mode with default settings.
|
||||
* It is ready for further calls (add, clear, start).
|
||||
*/
|
||||
fluid_LADSPA_FxUnit_t* new_fluid_LADSPA_FxUnit(fluid_synth_t* synth);
|
||||
typedef struct _fluid_ladspa_node_t
|
||||
{
|
||||
char *name;
|
||||
fluid_ladspa_node_type_t type;
|
||||
LADSPA_Data *buf;
|
||||
|
||||
/* Purpose:
|
||||
* Applies the master gain (from command line option --gain or gain command).
|
||||
* Processes one block of sound data (generated from the synthesizer) through
|
||||
* the LADSPA Fx unit.
|
||||
* Acknowledges a bypass request.
|
||||
*/
|
||||
void fluid_LADSPA_run(fluid_LADSPA_FxUnit_t* Fx_unit, fluid_real_t* left_buf[], fluid_real_t* right_buf[], fluid_real_t* fx_left_buf[], fluid_real_t* fx_right_buf[]);
|
||||
char num_inputs;
|
||||
char num_outputs;
|
||||
|
||||
/* Purpose:
|
||||
* Returns the node belonging to Name or NULL, if not found
|
||||
*/
|
||||
fluid_LADSPA_Node_t* fluid_LADSPA_RetrieveNode(fluid_LADSPA_FxUnit_t* FxUnit, char * Name);
|
||||
} fluid_ladspa_node_t;
|
||||
|
||||
/* Purpose:
|
||||
* Creates a new node with the given characteristics.
|
||||
*/
|
||||
fluid_LADSPA_Node_t* fluid_LADSPA_CreateNode(fluid_LADSPA_FxUnit_t* FxUnit, char * Name, int flags);
|
||||
typedef struct _fluid_ladspa_fx_t
|
||||
{
|
||||
unsigned long sample_rate;
|
||||
|
||||
/* Purpose:
|
||||
* - Resets LADSPA Fx unit to bypass.
|
||||
* - Removes all plugins from the reverb unit.
|
||||
* - Releases all libraries.
|
||||
* Note: It would be more efficient to keep the libraries. But then the user would have to restart fluidsynth each time
|
||||
* a plugin is recompiled.
|
||||
*/
|
||||
void fluid_LADSPA_clear(fluid_LADSPA_FxUnit_t* FxUnit);
|
||||
int audio_groups;
|
||||
int effects_channels;
|
||||
int audio_channels;
|
||||
|
||||
/* Purpose:
|
||||
* Frees all memory and shuts down the Fx block.
|
||||
* The synthesis thread must be stopped, when calling.
|
||||
*/
|
||||
void fluid_LADSPA_shutdown(fluid_LADSPA_FxUnit_t* FxUnit);
|
||||
fluid_ladspa_lib_t *libs[FLUID_LADSPA_MAX_LIBS];
|
||||
int num_libs;
|
||||
|
||||
fluid_ladspa_node_t *nodes[FLUID_LADSPA_MAX_NODES];
|
||||
int num_nodes;
|
||||
|
||||
/* plugins are really plugin instances */
|
||||
fluid_ladspa_plugin_t *plugins[FLUID_LADSPA_MAX_PLUGINS];
|
||||
int num_plugins;
|
||||
|
||||
/* used to generate the unique plugin ids */
|
||||
int next_plugin_id;
|
||||
|
||||
fluid_rec_mutex_t api_mutex;
|
||||
|
||||
int state;
|
||||
int pending_deactivation;
|
||||
|
||||
fluid_cond_mutex_t *run_finished_mutex;
|
||||
fluid_cond_t *run_finished_cond;
|
||||
|
||||
} fluid_ladspa_fx_t;
|
||||
|
||||
|
||||
fluid_ladspa_fx_t *new_fluid_ladspa_fx(fluid_real_t sample_rate, int audio_groups, int effects_channels, int audio_channels);
|
||||
void delete_fluid_ladspa_fx(fluid_ladspa_fx_t *fx);
|
||||
int fluid_ladspa_set_sample_rate(fluid_ladspa_fx_t *fx, fluid_real_t sample_rate);
|
||||
|
||||
/*
|
||||
* fluid_handle_LADSPA_XXX
|
||||
* Those functions are called from fluid_cmd, when a command is entered on the command line.
|
||||
*/
|
||||
int fluid_ladspa_is_active(fluid_ladspa_fx_t *fx);
|
||||
int fluid_ladspa_activate(fluid_ladspa_fx_t *fx);
|
||||
int fluid_ladspa_deactivate(fluid_ladspa_fx_t *fx);
|
||||
int fluid_ladspa_reset(fluid_ladspa_fx_t *fx);
|
||||
|
||||
/* Purpose:
|
||||
* - Resets LADSPA Fx unit to bypass.
|
||||
* - Removes all plugins from the reverb unit.
|
||||
* - Releases all libraries.
|
||||
* Note: It would be more efficient to keep the libraries. But then the user would have to restart fluidsynth each time
|
||||
* a plugin is recompiled.
|
||||
*/
|
||||
int fluid_LADSPA_handle_clear(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out);
|
||||
void fluid_ladspa_run(fluid_ladspa_fx_t *fx, fluid_real_t *left_buf[], fluid_real_t *right_buf[],
|
||||
fluid_real_t *fx_left_buf[], fluid_real_t *fx_right_buf[]);
|
||||
|
||||
/* Purpose:
|
||||
* Loads the plugins added with 'ladspa_add' and then start the Fx unit.
|
||||
* Internal processes:
|
||||
* - load the LADSPA plugin libraries
|
||||
* - instantiate the plugins
|
||||
* - connect the plugins
|
||||
* - set the bypass switch to 'not bypassed'
|
||||
*/
|
||||
int fluid_LADSPA_handle_start(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out);
|
||||
int fluid_ladspa_add_plugin(fluid_ladspa_fx_t *fx, const char *lib_name, const char *plugin_name);
|
||||
int fluid_ladspa_port_exists(fluid_ladspa_fx_t *fx, int plugin_id, const char *name);
|
||||
|
||||
/* Purpose:
|
||||
* Adds one plugin into the list of the LADSPA Fx unit.
|
||||
* This is only allowed, while the Fx block is in 'bypass' state (after clear).
|
||||
*/
|
||||
int fluid_LADSPA_handle_add(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out);
|
||||
int fluid_ladspa_add_audio_node(fluid_ladspa_fx_t *fx, const char *name);
|
||||
int fluid_ladspa_add_control_node(fluid_ladspa_fx_t *fx, const char *name, fluid_real_t val);
|
||||
int fluid_ladspa_set_control_node(fluid_ladspa_fx_t *fx, const char *name, fluid_real_t val);
|
||||
int fluid_ladspa_node_exists(fluid_ladspa_fx_t *fx, const char *name);
|
||||
|
||||
/* Purpose:
|
||||
* Declares a user control node and a value; for further processing in ladspa_start.
|
||||
*/
|
||||
int fluid_LADSPA_handle_declnode(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out);
|
||||
|
||||
/* Purpose:
|
||||
* Assigns a value to the a user control node
|
||||
*/
|
||||
int fluid_LADSPA_handle_setnode(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out);
|
||||
int fluid_ladspa_connect(fluid_ladspa_fx_t *fx, int plugin_id, fluid_ladspa_dir_t dir,
|
||||
const char *port_name, const char *node_name);
|
||||
int fluid_ladspa_check(fluid_ladspa_fx_t *fx, char *err, int err_size);
|
||||
|
||||
#endif /* LADSPA */
|
||||
|
||||
#endif /* _FLUID_LADSPA_H */
|
||||
#endif /* _FLUID_LADSPA_H */
|
||||
|
|
|
@ -250,6 +250,9 @@ fluid_pulse_audio_run2(void* d)
|
|||
|
||||
if (left == NULL || right == NULL || buf == NULL)
|
||||
{
|
||||
FLUID_FREE(left);
|
||||
FLUID_FREE(right);
|
||||
FLUID_FREE(buf);
|
||||
FLUID_LOG(FLUID_ERR, "Out of memory.");
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -81,7 +81,7 @@ struct _fluid_rvoice_mixer_t {
|
|||
int current_blockcount; /**< Read-only: how many blocks to process this time */
|
||||
|
||||
#ifdef LADSPA
|
||||
fluid_LADSPA_FxUnit_t* LADSPA_FxUnit; /**< Used by mixer only: Effects unit for LADSPA support. Never created or freed */
|
||||
fluid_ladspa_fx_t* ladspa_fx; /**< Used by mixer only: Effects unit for LADSPA support. Never created or freed */
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_MIXER_THREADS
|
||||
|
@ -142,7 +142,7 @@ fluid_rvoice_mixer_process_fx(fluid_rvoice_mixer_t* mixer)
|
|||
|
||||
#ifdef LADSPA
|
||||
/* Run the signal through the LADSPA Fx unit */
|
||||
if (mixer->LADSPA_FxUnit) {
|
||||
if (mixer->ladspa_fx && mixer->ladspa_fx->state == FLUID_LADSPA_ACTIVE) {
|
||||
int j;
|
||||
FLUID_DECLARE_VLA(fluid_real_t*, left_buf, mixer->buffers.buf_count);
|
||||
FLUID_DECLARE_VLA(fluid_real_t*, right_buf, mixer->buffers.buf_count);
|
||||
|
@ -157,8 +157,8 @@ fluid_rvoice_mixer_process_fx(fluid_rvoice_mixer_t* mixer)
|
|||
fx_right_buf[j] = mixer->buffers.fx_right_buf[j];
|
||||
}
|
||||
for (i=0; i < mixer->current_blockcount * FLUID_BUFSIZE; i += FLUID_BUFSIZE) {
|
||||
fluid_LADSPA_run(mixer->LADSPA_FxUnit, left_buf, right_buf, fx_left_buf,
|
||||
fx_right_buf);
|
||||
fluid_ladspa_run(mixer->ladspa_fx, left_buf, right_buf, fx_left_buf,
|
||||
fx_right_buf);
|
||||
for (j=0; j < mixer->buffers.buf_count; j++) {
|
||||
left_buf[j] += FLUID_BUFSIZE;
|
||||
right_buf[j] += FLUID_BUFSIZE;
|
||||
|
@ -522,6 +522,12 @@ fluid_rvoice_mixer_set_samplerate(fluid_rvoice_mixer_t* mixer, fluid_real_t samp
|
|||
fluid_revmodel_samplerate_change(mixer->fx.reverb, samplerate);
|
||||
for (i=0; i < mixer->active_voices; i++)
|
||||
fluid_rvoice_set_output_rate(mixer->rvoices[i], samplerate);
|
||||
#if LADSPA
|
||||
if (mixer->ladspa_fx != NULL)
|
||||
{
|
||||
fluid_ladspa_set_sample_rate(mixer->ladspa_fx, samplerate);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
@ -642,10 +648,9 @@ void delete_fluid_rvoice_mixer(fluid_rvoice_mixer_t* mixer)
|
|||
|
||||
|
||||
#ifdef LADSPA
|
||||
void fluid_rvoice_mixer_set_ladspa(fluid_rvoice_mixer_t* mixer,
|
||||
fluid_LADSPA_FxUnit_t* ladspa)
|
||||
void fluid_rvoice_mixer_set_ladspa(fluid_rvoice_mixer_t* mixer, fluid_ladspa_fx_t *ladspa_fx)
|
||||
{
|
||||
mixer->LADSPA_FxUnit = ladspa;
|
||||
mixer->ladspa_fx = ladspa_fx;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -69,8 +69,7 @@ void fluid_rvoice_mixer_set_threads(fluid_rvoice_mixer_t* mixer, int thread_coun
|
|||
int prio_level);
|
||||
|
||||
#ifdef LADSPA
|
||||
void fluid_rvoice_mixer_set_ladspa(fluid_rvoice_mixer_t* mixer,
|
||||
fluid_LADSPA_FxUnit_t* ladspa);
|
||||
void fluid_rvoice_mixer_set_ladspa(fluid_rvoice_mixer_t* mixer, fluid_ladspa_fx_t* ladspa_fx);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
@ -554,7 +554,9 @@ new_fluid_synth(fluid_settings_t *settings)
|
|||
fluid_sfloader_t* loader;
|
||||
double gain;
|
||||
int i, nbuf;
|
||||
#ifdef LADSPA
|
||||
int with_ladspa = 0;
|
||||
#endif
|
||||
|
||||
/* initialize all the conversion tables and other stuff */
|
||||
if (fluid_synth_initialized == 0)
|
||||
|
@ -710,12 +712,13 @@ new_fluid_synth(fluid_settings_t *settings)
|
|||
/* Create and initialize the Fx unit.*/
|
||||
fluid_settings_getint(settings, "synth.ladspa.active", &with_ladspa);
|
||||
if (with_ladspa) {
|
||||
synth->LADSPA_FxUnit = new_fluid_LADSPA_FxUnit(synth);
|
||||
if(synth->LADSPA_FxUnit == NULL) {
|
||||
synth->ladspa_fx = new_fluid_ladspa_fx(synth->sample_rate, synth->audio_groups,
|
||||
synth->effects_channels, synth->audio_channels);
|
||||
if(synth->ladspa_fx == NULL) {
|
||||
FLUID_LOG(FLUID_ERR, "Out of memory");
|
||||
goto error_recovery;
|
||||
}
|
||||
fluid_rvoice_mixer_set_ladspa(synth->eventhandler->mixer, synth->LADSPA_FxUnit);
|
||||
fluid_rvoice_mixer_set_ladspa(synth->eventhandler->mixer, synth->ladspa_fx);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -927,10 +930,9 @@ delete_fluid_synth(fluid_synth_t* synth)
|
|||
fluid_private_free (synth->tuning_iter);
|
||||
|
||||
#ifdef LADSPA
|
||||
/* Release the LADSPA Fx unit */
|
||||
if (synth->LADSPA_FxUnit) {
|
||||
fluid_LADSPA_shutdown(synth->LADSPA_FxUnit);
|
||||
FLUID_FREE(synth->LADSPA_FxUnit);
|
||||
/* Release the LADSPA effects unit */
|
||||
if (synth->ladspa_fx) {
|
||||
delete_fluid_ladspa_fx(synth->ladspa_fx);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -2342,7 +2344,7 @@ fluid_synth_update_presets(fluid_synth_t* synth)
|
|||
}
|
||||
}
|
||||
|
||||
/* Handler for synth.gain setting. */
|
||||
/* Handler for synth.sample-rate setting. */
|
||||
static int
|
||||
fluid_synth_update_sample_rate(fluid_synth_t* synth, char* name, double value)
|
||||
{
|
||||
|
@ -5259,4 +5261,3 @@ int fluid_synth_set_channel_type(fluid_synth_t* synth, int chan, int type)
|
|||
|
||||
FLUID_API_RETURN(FLUID_OK);
|
||||
}
|
||||
|
||||
|
|
|
@ -100,7 +100,7 @@ typedef struct _fluid_sfont_info_t {
|
|||
* ticks_since_start - atomic, set by rendering thread only
|
||||
* cpu_load - atomic, set by rendering thread only
|
||||
* cur, curmax, dither_index - used by rendering thread only
|
||||
* LADSPA_FxUnit - same instance copied in rendering thread. Synchronising handled internally (I think...?).
|
||||
* ladspa_fx - same instance copied in rendering thread. Synchronising handled internally.
|
||||
*
|
||||
*/
|
||||
|
||||
|
@ -170,7 +170,7 @@ struct _fluid_synth_t
|
|||
fluid_mod_t* default_mod; /**< the (dynamic) list of default modulators */
|
||||
|
||||
#ifdef LADSPA
|
||||
fluid_LADSPA_FxUnit_t* LADSPA_FxUnit; /**< Effects unit for LADSPA support */
|
||||
fluid_ladspa_fx_t* ladspa_fx; /**< Effects unit for LADSPA support */
|
||||
#endif
|
||||
};
|
||||
|
||||
|
|
|
@ -753,7 +753,15 @@ new_fluid_timer (int msec, fluid_timer_callback_t callback, void* data,
|
|||
return NULL;
|
||||
}
|
||||
}
|
||||
else fluid_timer_run (timer); /* Run directly, instead of as a separate thread */
|
||||
else
|
||||
{
|
||||
fluid_timer_run (timer); /* Run directly, instead of as a separate thread */
|
||||
if(timer->auto_destroy)
|
||||
{
|
||||
/* do NOT return freed memory */
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return timer;
|
||||
}
|
||||
|
|
|
@ -227,7 +227,12 @@ typedef FILE* fluid_file;
|
|||
#define FLUID_STRCMP(_s,_t) strcmp(_s,_t)
|
||||
#define FLUID_STRNCMP(_s,_t,_n) strncmp(_s,_t,_n)
|
||||
#define FLUID_STRCPY(_dst,_src) strcpy(_dst,_src)
|
||||
#define FLUID_STRNCPY(_dst,_src,_n) strncpy(_dst,_src,_n)
|
||||
|
||||
#define FLUID_STRNCPY(_dst,_src,_n) \
|
||||
do { strncpy(_dst,_src,_n); \
|
||||
(_dst)[(_n)-1]=0; \
|
||||
}while(0)
|
||||
|
||||
#define FLUID_STRCHR(_s,_c) strchr(_s,_c)
|
||||
#define FLUID_STRRCHR(_s,_c) strrchr(_s,_c)
|
||||
|
||||
|
@ -258,6 +263,12 @@ typedef FILE* fluid_file;
|
|||
#define FLUID_STRCASECMP strcasecmp
|
||||
#endif
|
||||
|
||||
#if defined(WIN32) && !defined(MINGW32)
|
||||
#define FLUID_STRNCASECMP _strincmp
|
||||
#else
|
||||
#define FLUID_STRNCASECMP strncasecmp
|
||||
#endif
|
||||
|
||||
|
||||
#define fluid_clip(_val, _min, _max) \
|
||||
{ (_val) = ((_val) < (_min))? (_min) : (((_val) > (_max))? (_max) : (_val)); }
|
||||
|
|
Loading…
Reference in a new issue