Compare commits

...

30 Commits

Author SHA1 Message Date
Ben Niemann 13bef24fad Minor cleanup. 3 years ago
Ben Niemann 85e60a58ed Delete obsolete file. 3 years ago
Ben Niemann 1a99e078fc MidiCCtoCV: UI tweaks. 3 years ago
Ben Niemann d543ed8ca3 MidiCCtoCV: processor post CC events as node messages. 3 years ago
Ben Niemann b2da93d21a Update mypy and pylint to the latest versions. 3 years ago
Ben Niemann 8b5e031f71 Pin cython to 0.29.6. 3 years ago
Ben Niemann c54c4686b2 Fix tests. 3 years ago
Ben Niemann 5c0fa2e354 Factor session values storage out to a separate module. 3 years ago
Ben Niemann d1d2f3d37a Give NodeConnectors access to the AudioProcClient. 3 years ago
Ben Niemann c045ffe0a3 Move the unpacking of node messages into Python objects into the AudioProcClient. 3 years ago
Ben Niemann 6f37aa79bc Allow read-only control value dials. 3 years ago
Ben Niemann 0913aef84e MidiCCtoCV: add MIDI learn mode. 3 years ago
Ben Niemann d2ea690253 Initial (not quite finished) version of a MIDI CC->CV node. 3 years ago
Ben Niemann bcf0935ef9 Fix MIDI code for CC messages. 3 years ago
Ben Niemann 99459b6f57 Lint fixes. 3 years ago
Ben Niemann 90c1958cd8 Add a simple (white/pink) noise generator. 3 years ago
Ben Niemann 5d70c22fd5 Minor reformatting. 3 years ago
Ben Niemann 038cc02a17 Add a Step Sequencer node. 3 years ago
Ben Niemann 6504f2645a Add a simple VCA node. 3 years ago
Ben Niemann 5b71cc4063 Support h-/vslider controls in faust DSPs. 3 years ago
Ben Niemann e7258371a5 Fix crash in insert node dialog. 3 years ago
Ben Niemann e00ffa5d96 Fix name collision when there's more than one Faust processor. 3 years ago
Ben Niemann 415f0109b5 Minor bug fixes. 3 years ago
Ben Niemann 016755c7f3 Generate a JSON dump of the faust meta data. Autogenerate the NodeDescription from it. 3 years ago
Ben Niemann 897b3023bf Autogenerate full processor class from templates. 3 years ago
Ben Niemann 5c32e26029 Add a builtin oscillator node based on faust. 3 years ago
Ben Niemann 97202cbd6a Support ports with a list of fixed values, support ports with log scale. 3 years ago
Ben Niemann 07ce0e0498 Support faust processors. 3 years ago
Ben Niemann 55712cb1e1 Show some minimal information about nodes in the insert node dialog. 3 years ago
Ben Niemann c943386dee Show icons in insert node dialog. 3 years ago
  1. 169
      3rdparty/faust/setup.py
  2. 157
      3rdparty/faustlibraries/setup.py
  3. 3
      3rdparty/typeshed/PyQt5/QtCore.pyi
  4. 6
      3rdparty/typeshed/PyQt5/QtWidgets.pyi
  5. 2
      3rdparty/typeshed/pyparsing.pyi
  6. 10
      CMakeLists.txt
  7. 44
      bin/build-faust-processor
  8. 3
      data/icons/CMakeLists.txt
  9. 69
      data/icons/node-type-builtin.svg
  10. 109
      data/icons/node-type-ladspa.svg
  11. 3
      data/icons/node-type-lv2.license
  12. 80
      data/icons/node-type-lv2.orig.svg
  13. 86
      data/icons/node-type-lv2.svg
  14. 9
      listdeps
  15. 52
      noisicaa/audioproc/audioproc_client.py
  16. 18
      noisicaa/audioproc/audioproc_client_test.py
  17. 1
      noisicaa/audioproc/engine/CMakeLists.txt
  18. 2
      noisicaa/audioproc/engine/backend_portaudio.cpp
  19. 210
      noisicaa/audioproc/engine/processor_faust.cpp
  20. 40
      noisicaa/audioproc/engine/processor_faust.cpp.tmpl
  21. 67
      noisicaa/audioproc/engine/processor_faust.h
  22. 44
      noisicaa/audioproc/engine/processor_faust.h.tmpl
  23. 2
      noisicaa/audioproc/engine/realm.pyx
  24. 11
      noisicaa/builtin_nodes/CMakeLists.txt
  25. 1
      noisicaa/builtin_nodes/beat_track/node_description.py
  26. 8
      noisicaa/builtin_nodes/beat_track/server_impl.py
  27. 7
      noisicaa/builtin_nodes/client_registry.py
  28. 14
      noisicaa/builtin_nodes/commands_registry.proto
  29. 1
      noisicaa/builtin_nodes/control_track/node_description.py
  30. 7
      noisicaa/builtin_nodes/control_track/server_impl.py
  31. 6
      noisicaa/builtin_nodes/control_track/server_impl_test.py
  32. 1
      noisicaa/builtin_nodes/custom_csound/node_description.py
  33. 2
      noisicaa/builtin_nodes/custom_csound/node_ui.py
  34. 1
      noisicaa/builtin_nodes/instrument/node_description.py
  35. 6
      noisicaa/builtin_nodes/instrument/server_impl.py
  36. 51
      noisicaa/builtin_nodes/midi_cc_to_cv/CMakeLists.txt
  37. 21
      noisicaa/builtin_nodes/midi_cc_to_cv/__init__.py
  38. 42
      noisicaa/builtin_nodes/midi_cc_to_cv/client_impl.py
  39. 94
      noisicaa/builtin_nodes/midi_cc_to_cv/client_impl_test.py
  40. 50
      noisicaa/builtin_nodes/midi_cc_to_cv/commands.proto
  41. 83
      noisicaa/builtin_nodes/midi_cc_to_cv/commands.py
  42. 41
      noisicaa/builtin_nodes/midi_cc_to_cv/model.proto
  43. 113
      noisicaa/builtin_nodes/midi_cc_to_cv/model.py
  44. 44
      noisicaa/builtin_nodes/midi_cc_to_cv/node_description.py
  45. 400
      noisicaa/builtin_nodes/midi_cc_to_cv/node_ui.py
  46. 117
      noisicaa/builtin_nodes/midi_cc_to_cv/node_ui_test.py
  47. 270
      noisicaa/builtin_nodes/midi_cc_to_cv/processor.cpp
  48. 79
      noisicaa/builtin_nodes/midi_cc_to_cv/processor.h
  49. 44
      noisicaa/builtin_nodes/midi_cc_to_cv/processor.proto
  50. 29
      noisicaa/builtin_nodes/midi_cc_to_cv/processor_messages.proto
  51. 34
      noisicaa/builtin_nodes/midi_cc_to_cv/processor_messages.py
  52. 75
      noisicaa/builtin_nodes/midi_cc_to_cv/processor_test.py
  53. 271
      noisicaa/builtin_nodes/midi_cc_to_cv/server_impl.py
  54. 33
      noisicaa/builtin_nodes/midi_cc_to_cv/server_impl_test.py
  55. 1
      noisicaa/builtin_nodes/midi_source/node_description.py
  56. 3
      noisicaa/builtin_nodes/midi_source/processor.h
  57. 6
      noisicaa/builtin_nodes/midi_source/server_impl.py
  58. 3
      noisicaa/builtin_nodes/midi_source/server_impl_test.py
  59. 1
      noisicaa/builtin_nodes/mixer/node_description.py
  60. 2
      noisicaa/builtin_nodes/mixer/node_ui.py
  61. 11
      noisicaa/builtin_nodes/model_registry.proto
  62. 10
      noisicaa/builtin_nodes/node_description_registry.py
  63. 32
      noisicaa/builtin_nodes/noise/CMakeLists.txt
  64. 21
      noisicaa/builtin_nodes/noise/__init__.py
  65. 29
      noisicaa/builtin_nodes/noise/node_description.py
  66. 40
      noisicaa/builtin_nodes/noise/processor.dsp
  67. 66
      noisicaa/builtin_nodes/noise/processor_test.py
  68. 32
      noisicaa/builtin_nodes/oscillator/CMakeLists.txt
  69. 21
      noisicaa/builtin_nodes/oscillator/__init__.py
  70. 29
      noisicaa/builtin_nodes/oscillator/node_description.py
  71. 46
      noisicaa/builtin_nodes/oscillator/processor.dsp
  72. 69
      noisicaa/builtin_nodes/oscillator/processor_test.py
  73. 4
      noisicaa/builtin_nodes/processor_message_registry.proto
  74. 20
      noisicaa/builtin_nodes/processor_registry.cpp
  75. 1
      noisicaa/builtin_nodes/sample_track/node_description.py
  76. 6
      noisicaa/builtin_nodes/sample_track/server_impl.py
  77. 6
      noisicaa/builtin_nodes/sample_track/server_impl_test.py
  78. 1
      noisicaa/builtin_nodes/score_track/node_description.py
  79. 7
      noisicaa/builtin_nodes/score_track/server_impl.py
  80. 3
      noisicaa/builtin_nodes/score_track/server_impl_test.py
  81. 17
      noisicaa/builtin_nodes/server_registry.py
  82. 44
      noisicaa/builtin_nodes/step_sequencer/CMakeLists.txt
  83. 21
      noisicaa/builtin_nodes/step_sequencer/__init__.py
  84. 51
      noisicaa/builtin_nodes/step_sequencer/client_impl.py
  85. 126
      noisicaa/builtin_nodes/step_sequencer/client_impl_test.py
  86. 52
      noisicaa/builtin_nodes/step_sequencer/commands.proto
  87. 89
      noisicaa/builtin_nodes/step_sequencer/commands.py
  88. 49
      noisicaa/builtin_nodes/step_sequencer/model.proto
  89. 142
      noisicaa/builtin_nodes/step_sequencer/model.py
  90. 49
      noisicaa/builtin_nodes/step_sequencer/node_description.py
  91. 553
      noisicaa/builtin_nodes/step_sequencer/node_ui.py
  92. 56
      noisicaa/builtin_nodes/step_sequencer/node_ui_test.py
  93. 212
      noisicaa/builtin_nodes/step_sequencer/processor.cpp
  94. 76
      noisicaa/builtin_nodes/step_sequencer/processor.h
  95. 44
      noisicaa/builtin_nodes/step_sequencer/processor.proto
  96. 79
      noisicaa/builtin_nodes/step_sequencer/processor_test.py
  97. 296
      noisicaa/builtin_nodes/step_sequencer/server_impl.py
  98. 33
      noisicaa/builtin_nodes/step_sequencer/server_impl_test.py
  99. 4
      noisicaa/builtin_nodes/ui_registry.py
  100. 32
      noisicaa/builtin_nodes/vca/CMakeLists.txt
  101. Some files were not shown because too many files have changed in this diff Show More

169
3rdparty/faust/setup.py vendored

@ -0,0 +1,169 @@
# @begin:license
#
# Copyright (c) 2015-2019, Benjamin Niemann <pink@odahoda.de>
#
# 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.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
# @end:license
from distutils import core
from distutils.command.build import build
from distutils.command.install import install
import urllib.request
import os
import os.path
import subprocess
import sys
import time
import zipfile
VERSION = '2.15.11'
DOWNLOAD_URL = 'https://github.com/grame-cncm/faust/archive/%s.zip' % VERSION
assert os.getenv('VIRTUAL_ENV'), "Not running in a virtualenv."
class FaustMixin(object):
user_options = [
('build-base=', 'b',
"base directory for build library"),
]
def initialize_options(self):
self.build_base = os.path.join(os.getenv('VIRTUAL_ENV'), 'build', 'faust')
def finalize_options(self):
pass
@property
def zip_path(self):
return os.path.join(self.build_base, 'faust-%s.zip' % VERSION)
@property
def src_dir(self):
return os.path.join(self.build_base, 'src-%s' % VERSION)
class BuildFaust(FaustMixin, core.Command):
def run(self):
if not os.path.isdir(self.build_base):
os.makedirs(self.build_base)
self._download_zip(self.zip_path)
self._unpack_zip(self.zip_path, self.src_dir)
self._make(self.src_dir)
def _download_zip(self, zip_path):
if os.path.exists(zip_path):
return
total_bytes = 0
with urllib.request.urlopen(DOWNLOAD_URL) as fp_in:
with open(zip_path + '.partial', 'wb') as fp_out:
last_report = time.time()
try:
while True:
dat = fp_in.read(10240)
if not dat:
break
fp_out.write(dat)
total_bytes += len(dat)
if time.time() - last_report > 1:
sys.stderr.write(
'Downloading %s: %d bytes\r'
% (DOWNLOAD_URL, total_bytes))
sys.stderr.flush()
last_report = time.time()
finally:
sys.stderr.write('\033[K')
sys.stderr.flush()
os.rename(zip_path + '.partial', zip_path)
print('Downloaded %s: %d bytes' % (DOWNLOAD_URL, total_bytes))
def _unpack_zip(self, zip_path, src_dir):
if os.path.isdir(src_dir):
return
print("Extracting...")
base_dir = None
with zipfile.ZipFile(zip_path) as fp:
for path in fp.namelist():
while path:
path, b = os.path.split(path)
if not path:
if base_dir is None:
base_dir = b
elif b != base_dir:
raise RuntimeError(
"No common base dir (%s)" % b)
fp.extractall(self.build_base)
os.rename(os.path.join(self.build_base, base_dir), src_dir)
print("Extracted to %s" % src_dir)
return src_dir
def _make(self, make_dir):
if os.path.exists(os.path.join(make_dir, '.build.complete')):
return
print("Running make...")
subprocess.run(
['make',
'-j8',
'PREFIX=' + os.getenv('VIRTUAL_ENV'),
'compiler'],
cwd=make_dir,
check=True)
open(os.path.join(make_dir, '.build.complete'), 'w').close()
class InstallFaust(FaustMixin, core.Command):
@property
def sentinel_path(self):
return os.path.join(
os.getenv('VIRTUAL_ENV'), '.faust-%s-installed' % VERSION)
def run(self):
if os.path.exists(self.sentinel_path):
return
print("Running make install...")
subprocess.run(
['make',
'PREFIX=' + os.getenv('VIRTUAL_ENV'),
'install'],
cwd=self.src_dir,
check=True)
open(self.sentinel_path, 'w').close()
def get_outputs(self):
return [self.sentinel_path]
build.sub_commands.append(('build_faust', None))
install.sub_commands.insert(0, ('install_faust', None))
core.setup(
name = 'faust',
version = VERSION,
cmdclass = {
'build_faust': BuildFaust,
'install_faust': InstallFaust,
},
)

157
3rdparty/faustlibraries/setup.py vendored

@ -0,0 +1,157 @@
# @begin:license
#
# Copyright (c) 2015-2019, Benjamin Niemann <pink@odahoda.de>
#
# 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.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
# @end:license
from distutils import core
from distutils.command.build import build
from distutils.command.install import install
import urllib.request
import os
import os.path
import shutil
import subprocess
import sys
import time
import zipfile
VERSION = '0.20190330'
COMMIT_ID = '64a57f5693573ed73409f16c0d7ba420cde6111e'
DOWNLOAD_URL = 'https://github.com/grame-cncm/faustlibraries/archive/%s.zip' % COMMIT_ID
assert os.getenv('VIRTUAL_ENV'), "Not running in a virtualenv."
class FaustLibrariesMixin(object):
user_options = [
('build-base=', 'b',
"base directory for build library"),
]
def initialize_options(self):
self.build_base = os.path.join(os.getenv('VIRTUAL_ENV'), 'build', 'faustlibraries')
def finalize_options(self):
pass
@property
def zip_path(self):
return os.path.join(self.build_base, 'faustlibraries-%s.zip' % VERSION)
@property
def src_dir(self):
return os.path.join(self.build_base, 'src-%s' % VERSION)
class BuildFaustLibraries(FaustLibrariesMixin, core.Command):
def run(self):
if not os.path.isdir(self.build_base):
os.makedirs(self.build_base)
self._download_zip(self.zip_path)
self._unpack_zip(self.zip_path, self.src_dir)
def _download_zip(self, zip_path):
if os.path.exists(zip_path):
return
total_bytes = 0
with urllib.request.urlopen(DOWNLOAD_URL) as fp_in:
with open(zip_path + '.partial', 'wb') as fp_out:
last_report = time.time()
try:
while True:
dat = fp_in.read(10240)
if not dat:
break
fp_out.write(dat)
total_bytes += len(dat)
if time.time() - last_report > 1:
sys.stderr.write(
'Downloading %s: %d bytes\r'
% (DOWNLOAD_URL, total_bytes))
sys.stderr.flush()
last_report = time.time()
finally:
sys.stderr.write('\033[K')
sys.stderr.flush()
os.rename(zip_path + '.partial', zip_path)
print('Downloaded %s: %d bytes' % (DOWNLOAD_URL, total_bytes))
def _unpack_zip(self, zip_path, src_dir):
if os.path.isdir(src_dir):
return
print("Extracting...")
base_dir = None
with zipfile.ZipFile(zip_path) as fp:
for path in fp.namelist():
while path:
path, b = os.path.split(path)
if not path:
if base_dir is None:
base_dir = b
elif b != base_dir:
raise RuntimeError(
"No common base dir (%s)" % b)
fp.extractall(self.build_base)
os.rename(os.path.join(self.build_base, base_dir), src_dir)
print("Extracted to %s" % src_dir)
return src_dir
class InstallFaustLibraries(FaustLibrariesMixin, core.Command):
@property
def sentinel_path(self):
return os.path.join(
os.getenv('VIRTUAL_ENV'), '.faustlibraries-%s-installed' % VERSION)
@property
def install_dir(self):
return os.path.join(
os.getenv('VIRTUAL_ENV'), 'share', 'faustlibraries')
def run(self):
if os.path.exists(self.sentinel_path):
return
print("Copy files...")
shutil.rmtree(self.install_dir)
shutil.copytree(self.src_dir, self.install_dir)
open(self.sentinel_path, 'w').close()
def get_outputs(self):
return [self.sentinel_path]
build.sub_commands.append(('build_faustlibraries', None))
install.sub_commands.insert(0, ('install_faustlibraries', None))
core.setup(
name = 'faustlibraries',
version = VERSION,
cmdclass = {
'build_faustlibraries': BuildFaustLibraries,
'install_faustlibraries': InstallFaustLibraries,
},
)

3
3rdparty/typeshed/PyQt5/QtCore.pyi vendored

@ -7620,6 +7620,7 @@ class QTimeLine(QObject):
class QTimer(QObject):
timeout = ... # type: PYQT_SIGNAL
def __init__(self, parent: typing.Optional[QObject] = ...) -> None: ...
@ -7627,7 +7628,7 @@ class QTimer(QObject):
def timerType(self) -> Qt.TimerType: ...
def setTimerType(self, atype: Qt.TimerType) -> None: ...
def timerEvent(self, a0: QTimerEvent) -> None: ...
def timeout(self) -> None: ...
#def timeout(self) -> None: ...
def stop(self) -> None: ...
@typing.overload
def start(self, msec: int) -> None: ...

6
3rdparty/typeshed/PyQt5/QtWidgets.pyi vendored

@ -1436,6 +1436,7 @@ class QCalendarWidget(QWidget):
class QCheckBox(QAbstractButton):
stateChanged = ... # type: PYQT_SIGNAL
@typing.overload
def __init__(self, parent: typing.Optional[QWidget] = ...) -> None: ...
@ -1449,7 +1450,7 @@ class QCheckBox(QAbstractButton):
def nextCheckState(self) -> None: ...
def checkStateSet(self) -> None: ...
def hitButton(self, pos: QtCore.QPoint) -> bool: ...
def stateChanged(self, a0: int) -> None: ...
#def stateChanged(self, a0: int) -> None: ...
def minimumSizeHint(self) -> QtCore.QSize: ...
def setCheckState(self, state: QtCore.Qt.CheckState) -> None: ...
def checkState(self) -> QtCore.Qt.CheckState: ...
@ -5924,6 +5925,7 @@ class QListWidgetItem(sip.wrapper):
class QListWidget(QListView):
currentRowChanged = ... # type: PYQT_SIGNAL
itemDoubleClicked = ... # type: PYQT_SIGNAL
def __init__(self, parent: typing.Optional[QWidget] = ...) -> None: ...
@ -5942,7 +5944,7 @@ class QListWidget(QListView):
def mimeData(self, items: typing.Iterable[QListWidgetItem]) -> QtCore.QMimeData: ...
def mimeTypes(self) -> typing.List[str]: ...
def itemSelectionChanged(self) -> None: ...
def currentRowChanged(self, currentRow: int) -> None: ...
#def currentRowChanged(self, currentRow: int) -> None: ...
def currentTextChanged(self, currentText: str) -> None: ...
def currentItemChanged(self, current: QListWidgetItem, previous: QListWidgetItem) -> None: ...
def itemChanged(self, item: QListWidgetItem) -> None: ...

2
3rdparty/typeshed/pyparsing.pyi vendored

@ -0,0 +1,2 @@
from typing import Any
def __getattr__(arrr: str) -> Any: ...

10
CMakeLists.txt

@ -138,6 +138,16 @@ macro(render_csound src dest)
)
endmacro(render_csound)
macro(faust_dsp clsName src)
string(REGEX REPLACE "\\.dsp$" "" base ${src})
add_custom_command(
OUTPUT ${base}.cpp ${base}.h ${base}.json
COMMAND bin/build-faust-processor ${clsName} ${CMAKE_CURRENT_LIST_DIR}/${src} ${CMAKE_CURRENT_BINARY_DIR}
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
DEPENDS ${CMAKE_CURRENT_LIST_DIR}/${src}
)
endmacro(faust_dsp)
add_subdirectory(noisicaa)
add_subdirectory(noisidev)
add_subdirectory(data)

44
bin/build-faust-processor

@ -0,0 +1,44 @@
#!/bin/bash
set -e
CLASSNAME=$1
SRC=$2
DESTDIR=$3
CLASSNAME_UPPER=$(echo ${CLASSNAME} | tr '[a-z]' '[A-Z]')
SRCDIR=$(realpath --relative-to=$(pwd) $(dirname ${SRC}))
BASE=$(basename ${SRC%.dsp})
LD_LIBRARY_PATH=${VIRTUAL_ENV}/lib ${VIRTUAL_ENV}/bin/faust \
--import-dir ${VIRTUAL_ENV}/share/faustlibraries/ \
--language cpp \
--class-name Processor${CLASSNAME}DSP \
--super-class-name noisicaa::FaustDSP \
-a noisicaa/audioproc/engine/processor_faust.cpp.tmpl \
-o ${DESTDIR}/${BASE}.cpp.tmp \
${SRC}
sed <${DESTDIR}/${BASE}.cpp.tmp >${DESTDIR}/${BASE}.cpp \
-e '1,9d'\
-e '$d' \
-e "s#<<srcDir>>#${SRCDIR}#g" \
-e "s#<<base>>#${BASE}#g" \
-e "s#<<className>>#${CLASSNAME}#g" \
-e "s#<<classNameUpper>>#${CLASSNAME_UPPER}#g"
sed <noisicaa/audioproc/engine/processor_faust.h.tmpl >${DESTDIR}/${BASE}.h \
-e "s#<<srcDir>>#${SRCDIR}#g" \
-e "s#<<base>>#${BASE}#g" \
-e "s#<<className>>#${CLASSNAME}#g" \
-e "s#<<classNameUpper>>#${CLASSNAME_UPPER}#g"
LD_LIBRARY_PATH=${VIRTUAL_ENV}/lib ${VIRTUAL_ENV}/bin/faust \
--import-dir ${VIRTUAL_ENV}/share/faustlibraries/ \
--language cpp \
-a gen-json.cpp \
-o ${DESTDIR}/${BASE}.json_dumper.cpp \
${SRC}
g++ -I${VIRTUAL_ENV}/include -o${DESTDIR}/${BASE}.json_dumper ${DESTDIR}/${BASE}.json_dumper.cpp
${DESTDIR}/${BASE}.json_dumper >${DESTDIR}/${BASE}.json

3
data/icons/CMakeLists.txt

@ -31,6 +31,9 @@ install_files(
edit-beats.svg
edit-control-points.svg
edit-samples.svg
node-type-builtin.svg
node-type-ladspa.svg
node-type-lv2.svg
note-16th.svg
note-32th.svg
note-8th.svg

69
data/icons/node-type-builtin.svg

@ -0,0 +1,69 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
height="30"
id="svg2"
version="1.1"
viewBox="147 151 60 60"
width="30"
sodipodi:docname="node-type-builtin.svg"
inkscape:version="0.92.3 (2405546, 2018-03-11)">
<metadata
id="metadata3495">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="2560"
inkscape:window-height="1373"
id="namedview3493"
showgrid="false"
inkscape:zoom="32"
inkscape:cx="15.55323"
inkscape:cy="15.50392"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="layer2" />
<defs
id="defs10" />
<g
id="layer2"
style="display:inline"
transform="translate(0,-637.6694)"
inkscape:groupmode="layer"
inkscape:label="Symbol">
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:91.03184509px;line-height:125%;font-family:Dyuthi;-inkscape-font-specification:'Dyuthi, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:9.10318494pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="144.21875"
y="846.13898"
id="text2179"><tspan
sodipodi:role="line"
id="tspan2177"
x="144.21875"
y="846.13898"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:91.03184509px;font-family:Dyuthi;-inkscape-font-specification:'Dyuthi, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:9.10318494pt">N</tspan></text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.7 KiB

109
data/icons/node-type-ladspa.svg

@ -0,0 +1,109 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
height="30"
id="svg2"
version="1.1"
viewBox="147 151 60 60"
width="30"
sodipodi:docname="node-type-ladspa.svg"
inkscape:version="0.92.3 (2405546, 2018-03-11)">
<metadata
id="metadata3495">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="2560"
inkscape:window-height="1373"
id="namedview3493"
showgrid="false"
inkscape:zoom="32"
inkscape:cx="10.006355"
inkscape:cy="14.56642"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="layer2" />
<defs
id="defs10" />
<g
id="layer2"
style="display:inline"
transform="translate(0,-637.6694)"
inkscape:groupmode="layer"
inkscape:label="Symbol">
<flowRoot
xml:space="preserve"
id="flowRoot1549"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10px;line-height:125%;font-family:'DejaVu Serif';-inkscape-font-specification:'DejaVu Serif';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.00000003pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
transform="matrix(2.701507,0,0,2.701507,135.14643,786.61524)"><flowRegion
id="flowRegion1551"><rect
id="rect1553"
width="23.8125"
height="22.75"
x="3.90625"
y="5.4375" /></flowRegion><flowPara
id="flowPara1555">LADSPA</flowPara><flowPara
id="flowPara1557" /></flowRoot> <g
aria-label="LAD"
transform="matrix(2.701507,0,0,2.701507,160.97959,803.49966)"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10px;line-height:125%;font-family:'DejaVu Serif';-inkscape-font-specification:'DejaVu Serif';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.00000003pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
id="flowRoot1559">
<path
d="M -4.4482422,4.4414062 V 3.9238281 h 0.9277344 v -6.25 h -0.9277344 v -0.5224609 h 2.8466797 v 0.5224609 H -2.5292969 V 3.8408203 H 0.80078125 V 2.6201172 H 1.4013672 v 1.821289 z"
id="path1590"
inkscape:connector-curvature="0" />
<path
d="M 3.6425781,1.7998047 H 6.3183594 L 4.9804687,-1.6669922 Z M 1.5820312,4.4414062 V 3.9238281 H 2.2216797 L 4.8193359,-2.8486328 H 5.6396484 L 8.2421875,3.9238281 H 8.9599609 V 4.4414062 H 6.3085937 V 3.9238281 H 7.1191406 L 6.5087891,2.3222656 H 3.4423828 L 2.8320313,3.9238281 h 0.8007812 v 0.5175781 z"
id="path1592"
inkscape:connector-curvature="0" />
<path
d="m 11.337891,3.9238281 h 0.908203 q 1.420898,0 2.177734,-0.8105468 0.761719,-0.8105469 0.761719,-2.3242188 0,-1.51367187 -0.756836,-2.3144531 -0.756836,-0.8007813 -2.182617,-0.8007813 H 11.337891 Z M 9.4189453,4.4414062 V 3.9238281 H 10.34668 v -6.25 H 9.4189453 v -0.5224609 h 2.9003907 q 1.884766,0 2.93457,0.9619141 1.054688,0.96191401 1.054688,2.6757812 0,1.71875 -1.054688,2.6855469 -1.054687,0.9667968 -2.93457,0.9667968 z"
id="path1594"
inkscape:connector-curvature="0" />
</g>
<g
aria-label="SPA"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20px;line-height:125%;font-family:'DejaVu Serif';-inkscape-font-specification:'DejaVu Serif';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:2.00000006pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
id="text1577"
transform="matrix(1.3507535,0,0,1.3507535,-62.083371,-278.68272)">
<path
d="m 158.02051,828.34125 v -3.32031 l 1.12304,0.01 q 0.0488,1.66016 0.95704,2.46094 0.91796,0.79101 2.7832,0.79101 1.73828,0 2.64648,-0.68359 0.91797,-0.69336 0.91797,-2.01172 0,-1.05469 -0.55664,-1.62109 -0.54687,-0.56641 -2.32422,-1.10352 l -1.92383,-0.57617 q -2.08984,-0.63477 -2.94921,-1.58203 -0.84961,-0.94727 -0.84961,-2.59766 0,-1.85547 1.31836,-2.88086 1.31836,-1.02539 3.70117,-1.02539 1.01562,0 2.22656,0.22461 1.21094,0.21485 2.57813,0.63477 v 3.10547 h -1.10352 q -0.16602,-1.54297 -1.03516,-2.22657 -0.85937,-0.69336 -2.62695,-0.69336 -1.54297,0 -2.35352,0.63477 -0.80078,0.625 -0.80078,1.82617 0,1.04492 0.60547,1.64063 0.60547,0.5957 2.56836,1.18164 l 1.80664,0.53711 q 1.98242,0.5957 2.82227,1.52343 0.84961,0.91797 0.84961,2.47071 0,2.11914 -1.35742,3.19336 -1.35743,1.07422 -4.04297,1.07422 -1.20118,0 -2.45118,-0.24414 -1.24023,-0.24415 -2.52929,-0.74219 z"
style="stroke-width:2.00000006pt"
id="path1583"
inkscape:connector-curvature="0" />
<path
d="m 174.81738,821.6225 h 2.57813 q 1.45508,0 2.21679,-0.78125 0.76172,-0.79102 0.76172,-2.27539 0,-1.49414 -0.76172,-2.27539 -0.76171,-0.78125 -2.21679,-0.78125 h -2.57813 z m -3.83789,7.42187 v -1.03515 h 1.85547 v -12.5 h -1.85547 v -1.04493 h 6.89453 q 2.1875,0 3.4668,1.11329 1.2793,1.10351 1.2793,2.98828 0,1.875 -1.2793,2.98828 -1.2793,1.11328 -3.4668,1.11328 h -3.05664 v 5.3418 h 2.25586 v 1.03515 z"
style="stroke-width:2.00000006pt"
id="path1585"
inkscape:connector-curvature="0" />
<path
d="m 185.52051,823.76117 h 5.35156 l -2.67578,-6.93359 z m -4.1211,5.2832 v -1.03515 h 1.2793 l 5.19531,-13.54493 h 1.64063 l 5.20508,13.54493 h 1.43554 v 1.03515 h -5.30273 v -1.03515 h 1.62109 l -1.2207,-3.20313 h -6.13281 l -1.22071,3.20313 h 1.60157 v 1.03515 z"
style="stroke-width:2.00000006pt"
id="path1587"
inkscape:connector-curvature="0" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 6.6 KiB

3
data/icons/node-type-lv2.license

@ -0,0 +1,3 @@
Source: http://lv2plug.in/git/cgit.cgi/lv2site.git/tree/content/images/logo.svg
Author: David Robillard <http://drobilla.net/>
Licence: https://opensource.org/licenses/ISC

80
data/icons/node-type-lv2.orig.svg

@ -0,0 +1,80 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
version="1.1"
id="svg2"
xml:space="preserve"
width="523.89148pt"
height="490.5pt"
viewBox="0 0 698.52205 654.00007"
sodipodi:docname="logo.svg"
inkscape:version="0.92.4 5da689c313, 2019-01-14"
inkscape:export-filename="/home/drobilla/Documents/lv2_flat_purple_padded.png"
inkscape:export-xdpi="68.776169"
inkscape:export-ydpi="68.776169"><metadata
id="metadata8"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
id="defs6" /><sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="3816"
inkscape:window-height="2100"
id="namedview4"
showgrid="false"
showguides="false"
fit-margin-top="1"
fit-margin-right="1"
fit-margin-bottom="1"
fit-margin-left="1"
inkscape:zoom="0.70710678"
inkscape:cx="61.988138"
inkscape:cy="477.06434"
inkscape:window-x="12"
inkscape:window-y="48"
inkscape:window-maximized="0"
inkscape:current-layer="g10"
inkscape:pagecheckerboard="true"
units="pt" /><g
id="g10"
inkscape:groupmode="layer"
inkscape:label="ink_ext_XXXXXX"
transform="matrix(1.3333333,0,0,-1.3333333,-3439.8194,207.04495)"><path
inkscape:connector-curvature="0"
id="path5626"
style="opacity:1;vector-effect:none;fill:#546e00;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:6;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
d="m 2713.1145,150.03372 96,-352 h 192 l -34.91,-128 h -250.18 l -130.91,480 z"
inkscape:export-xdpi="73.139999"
inkscape:export-ydpi="73.139999" /><path
inkscape:connector-curvature="0"
id="path5632"
style="opacity:1;vector-effect:none;fill:#b4c342;fill-opacity:1;stroke:#ffffff;stroke-width:6;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
d="m 2713.1145,150.03372 96,-352 h 64 l 96,352 h -64 l -64,-234.668003 -64,234.668003 z"
inkscape:export-xdpi="73.139999"
inkscape:export-ydpi="73.139999" /><path
inkscape:connector-curvature="0"
id="path5636"
style="opacity:1;vector-effect:none;fill:#96ac00;fill-opacity:1;stroke:#ffffff;stroke-width:6;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
d="m 2873.1145,-201.96628 h 64 l 96,352 h -64 z"
inkscape:export-xdpi="73.139999"
inkscape:export-ydpi="73.139999" /><path
inkscape:connector-curvature="0"
id="path5640"
style="opacity:1;vector-effect:none;fill:#859900;fill-opacity:1;stroke:#ffffff;stroke-width:6;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
d="m 2937.1145,-201.96628 h 64 l 96,352 h -64 z"
inkscape:export-xdpi="73.139999"
inkscape:export-ydpi="73.139999" /></g></svg>

After

Width:  |  Height:  |  Size: 3.7 KiB

86
data/icons/node-type-lv2.svg

@ -0,0 +1,86 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
height="30"
id="svg2"
version="1.1"
viewBox="147 151 60 60"
width="30"
sodipodi:docname="node-type-lv2.svg"
inkscape:version="0.92.3 (2405546, 2018-03-11)">
<metadata
id="metadata3495">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="2560"
inkscape:window-height="1373"
id="namedview3493"
showgrid="false"
inkscape:zoom="32"
inkscape:cx="10.006355"
inkscape:cy="17.96332"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="layer2" />
<defs
id="defs10" />
<g
id="layer2"
style="display:inline"
transform="translate(0,-637.6694)"
inkscape:groupmode="layer"
inkscape:label="Symbol">
<path
inkscape:connector-curvature="0"
id="path5626"
style="opacity:1;vector-effect:none;fill:#546e00;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.63314772;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
d="m 163.49285,793.34349 10.13036,37.14466 h 20.26072 l -3.68386,13.50716 H 163.79992 L 149.9857,793.34349 Z"
inkscape:export-xdpi="73.139999"
inkscape:export-ydpi="73.139999" />
<path
inkscape:connector-curvature="0"
id="path5632"
style="opacity:1;vector-effect:none;fill:#b4c342;fill-opacity:1;stroke:#ffffff;stroke-width:0.63314772;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
d="m 163.49285,793.34349 10.13036,37.14466 h 6.75357 l 10.13036,-37.14466 h -6.75357 L 177,818.10673 170.24642,793.34349 Z"
inkscape:export-xdpi="73.139999"
inkscape:export-ydpi="73.139999" />
<path
inkscape:connector-curvature="0"
id="path5636"
style="opacity:1;vector-effect:none;fill:#96ac00;fill-opacity:1;stroke:#ffffff;stroke-width:0.63314772;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
d="m 180.37678,830.48815 h 6.75358 l 10.13036,-37.14466 h -6.75358 z"
inkscape:export-xdpi="73.139999"
inkscape:export-ydpi="73.139999" />
<path
inkscape:connector-curvature="0"
id="path5640"
style="opacity:1;vector-effect:none;fill:#859900;fill-opacity:1;stroke:#ffffff;stroke-width:0.63314772;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
d="m 187.13036,830.48815 h 6.75357 l 10.13036,-37.14466 h -6.75357 z"
inkscape:export-xdpi="73.139999"
inkscape:export-ydpi="73.139999" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.5 KiB

9
listdeps

@ -60,14 +60,17 @@ PIP_DEPS = {
PKG('protobuf==3.7.1'),
PKG('psutil'),
PKG('pyaudio'),
PKG('pyparsing'),
PKG('quamash'),
PKG('toposort'),
PKG('urwid'),
],
'build': [
PKG('./3rdparty/protoc/'),
PKG('./3rdparty/faust/'),
PKG('./3rdparty/faustlibraries/'),
PKG('cssutils'),
PKG('cython'),
PKG('cython==0.29.6'),
PKG('pkgconfig'),
PKG('pyyaml'),
# TODO: get my changes upstream and use regular mypy-protobuf package from pip.
@ -80,8 +83,8 @@ PIP_DEPS = {
PKG('mox3'),
PKG('py-cpuinfo'),
PKG('pyfakefs'),
PKG('pylint==2.2.2'),
PKG('mypy==0.650'),
PKG('pylint==2.3.1'),
PKG('mypy==0.701'),
PKG('mypy-extensions'),
PKG('PyGObject-stubs'),

52
noisicaa/audioproc/audioproc_client.py

@ -23,13 +23,15 @@
import asyncio
import logging
import random
from typing import Any, Optional, Iterable, Set, Tuple
import traceback
from typing import Any, Optional, Iterable, Set, Tuple, Dict
from noisicaa import core
from noisicaa.core import empty_message_pb2
from noisicaa.core import session_data_pb2
from noisicaa.core import ipc
from noisicaa import node_db
from noisicaa import lv2
from .public import engine_notification_pb2
from .public import player_state_pb2
from .public import processor_message_pb2
@ -47,7 +49,7 @@ class AbstractAudioProcClient(object):
self.engine_state_changed = None # type: core.Callback[engine_notification_pb2.EngineStateChange]
self.player_state_changed = None # type: core.CallbackMap[str, player_state_pb2.PlayerState]
self.node_state_changed = None # type: core.CallbackMap[str, engine_notification_pb2.NodeStateChange]
self.node_messages = None # type: core.CallbackMap[str, bytes]
self.node_messages = None # type: core.CallbackMap[str, Dict[str, Any]]
self.perf_stats = None # type: core.Callback[core.PerfStats]
@property
@ -136,11 +138,17 @@ class AbstractAudioProcClient(object):
class AudioProcClient(AbstractAudioProcClient):
def __init__(self, event_loop: asyncio.AbstractEventLoop, server: ipc.Server) -> None:
def __init__(
self,
event_loop: asyncio.AbstractEventLoop,
server: ipc.Server,
urid_mapper: lv2.URIDMapper,
) -> None:
super().__init__()
self.event_loop = event_loop
self.server = server
self.urid_mapper = urid_mapper
self._stub = None # type: ipc.Stub
@ -148,7 +156,7 @@ class AudioProcClient(AbstractAudioProcClient):
self.engine_state_changed = core.Callback[engine_notification_pb2.EngineStateChange]()
self.player_state_changed = core.CallbackMap[str, player_state_pb2.PlayerState]()
self.node_state_changed = core.CallbackMap[str, engine_notification_pb2.NodeStateChange]()
self.node_messages = core.CallbackMap[str, bytes]()
self.node_messages = core.CallbackMap[str, Dict[str, Any]]()
self.perf_stats = core.Callback[core.PerfStats]()
self.__cb_endpoint_name = 'audioproc-%016x' % random.getrandbits(63)
@ -195,25 +203,33 @@ class AudioProcClient(AbstractAudioProcClient):
request: engine_notification_pb2.EngineNotification,
response: empty_message_pb2.EmptyMessage
) -> None:
self.engine_notifications.call(request)
try:
self.engine_notifications.call(request)
if request.HasField('player_state'):
player_state = request.player_state
self.player_state_changed.call(player_state.realm, player_state)
if request.HasField('player_state'):
player_state = request.player_state
self.player_state_changed.call(player_state.realm, player_state)
for node_state_change in request.node_state_changes:
self.node_state_changed.call(node_state_change.node_id, node_state_change)
for node_state_change in request.node_state_changes:
self.node_state_changed.call(node_state_change.node_id, node_state_change)
for node_message_pb in request.node_messages:
msg_atom = node_message_pb.atom
node_message = lv2.wrap_atom(self.urid_mapper, msg_atom).as_object
self.node_messages.call(node_message_pb.node_id, node_message)
for node_message in request.node_messages:
self.node_messages.call(node_message.node_id, node_message.atom)
for engine_state_change in request.engine_state_changes:
self.engine_state_changed.call(engine_state_change)
for engine_state_change in request.engine_state_changes:
self.engine_state_changed.call(engine_state_change)
if request.HasField('perf_stats'):
perf_stats = core.PerfStats()
perf_stats.deserialize(request.perf_stats)
self.perf_stats.call(perf_stats)
if request.HasField('perf_stats'):
perf_stats = core.PerfStats()
perf_stats.deserialize(request.perf_stats)
self.perf_stats.call(perf_stats)
except: # pylint: disable=bare-except
logger.error(
"Exception while processing engine notification:\n%s\n==========\n%s",
request, traceback.format_exc())
async def create_realm(
self, *, name: str, parent: Optional[str] = None, enable_player: bool = False,

18
noisicaa/audioproc/audioproc_client_test.py

@ -27,8 +27,10 @@ import async_generator
from noisidev import unittest
from noisidev import unittest_mixins
from noisicaa.constants import TEST_OPTS
from noisicaa import lv2
from noisicaa import node_db
from noisicaa import editor_main_pb2
from . import audioproc_client
from .public import engine_notification_pb2
@ -88,7 +90,17 @@ class AudioProcClientTest(
name='audioproc',
entry='noisicaa.audioproc.audioproc_process.AudioProcSubprocess')
client = audioproc_client.AudioProcClient(self.loop, self.server)
create_urid_mapper_response = editor_main_pb2.CreateProcessResponse()
await self.process_manager_client.call(
'CREATE_URID_MAPPER_PROCESS', None, create_urid_mapper_response)
urid_mapper_address = create_urid_mapper_response.address
urid_mapper = lv2.ProxyURIDMapper(
server_address=urid_mapper_address,
tmp_dir=TEST_OPTS.TMP_DIR)
await urid_mapper.setup(self.loop)
client = audioproc_client.AudioProcClient(self.loop, self.server, urid_mapper)
await client.setup()
await client.connect(proc.address)
try:
@ -99,6 +111,8 @@ class AudioProcClientTest(
await client.disconnect()
await client.cleanup()
await urid_mapper.cleanup(self.loop)
await proc.shutdown()
async def test_realms(self):

1
noisicaa/audioproc/engine/CMakeLists.txt

@ -73,6 +73,7 @@ set(LIB_SRCS
plugin_ui_host_lv2.cpp
processor.cpp
processor_null.cpp
processor_faust.cpp
processor_csound_base.cpp
processor_csound.cpp
processor_plugin.cpp

2
noisicaa/audioproc/engine/backend_portaudio.cpp

@ -322,7 +322,7 @@ Status PortAudioBackend::begin_block(BlockContext* ctxt) {
snprintf(uri, sizeof(uri), "alsa://%d/%d", event->source.client, event->source.port);
uint8_t msg[3];
msg[0] = 0xa0 | event->data.control.channel;
msg[0] = 0xb0 | event->data.control.channel;
msg[1] = event->data.control.param;
msg[2] = event->data.control.value;

210
noisicaa/audioproc/engine/processor_faust.cpp

@ -0,0 +1,210 @@
/*
* @begin:license
*
* Copyright (c) 2015-2019, Benjamin Niemann <pink@odahoda.de>
*
* 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.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* @end:license
*/
#include <map>
#include "faust/dsp/dsp.h"
#include "faust/gui/meta.h"
#include "faust/gui/UI.h"
#include "noisicaa/core/perf_stats.h"
#include "noisicaa/host_system/host_system.h"
#include "noisicaa/audioproc/engine/processor_faust.h"
namespace noisicaa {
class FaustControls : public UI {
public:
int num_controls() const {
return _control_map.size();
}
float* get_control_ptr(const string& name) {
return _control_map[name];
}
void openTabBox(const char* label) override {}
void openHorizontalBox(const char* label) override {}
void openVerticalBox(const char* label) override {}
void closeBox() override {}
void addButton(const char* label, float* zone) override {
_control_map[label] = zone;
}
void addCheckButton(const char* label, float* zone) override {
_control_map[label] = zone;
}
void addVerticalSlider(const char* label, float* zone, float init, float min, float max, float step) override {
_control_map[label] = zone;
}
void addHorizontalSlider(const char* label, float* zone, float init, float min, float max, float step) override {
_control_map[label] = zone;
}
void addNumEntry(const char* label, float* zone, float init, float min, float max, float step) override {
_control_map[label] = zone;
}
void addHorizontalBargraph(const char* label, float* zone, float min, float max) override {
_control_map[label] = zone;
}
void addVerticalBargraph(const char* label, float* zone, float min, float max) override {
_control_map[label] = zone;
}
void addSoundfile(const char* label, const char* filename, Soundfile** sf_zone) override {}
void declare(float* zone, const char* key, const char* val) override {}
private:
map<string, float*> _control_map;
};
ProcessorFaust::ProcessorFaust(
const string& realm_name, const string& node_id, HostSystem *host_system,
const pb::NodeDescription& desc)
: Processor(
realm_name, node_id, "noisicaa.audioproc.engine.processor.faust", host_system, desc) {}
Status ProcessorFaust::setup_internal() {
RETURN_IF_ERROR(Processor::setup_internal());
_dsp.reset(create_dsp());
_dsp->init(_host_system->sample_rate());
FaustControls controls;
_dsp->buildUserInterface(&controls);
int dsp_ports = _dsp->getNumInputs() + _dsp->getNumOutputs() + controls.num_controls();
if (dsp_ports != _desc.ports_size()) {
return ERROR_STATUS("Port mismatch (desc=%d, dsp=%d)", _desc.ports_size(), dsp_ports);
}
_buffers.reset(new BufferPtr[_desc.ports_size()]);
_inputs.reset(new float*[_dsp->getNumInputs()]);
_outputs.reset(new float*[_dsp->getNumOutputs()]);
_controls.reset(new float*[controls.num_controls()]);
int control_idx = 0;
for (int port_idx = 0 ; port_idx < _desc.ports_size() ; ++port_idx) {
const auto& port_desc = _desc.ports(port_idx);
if (port_idx < _dsp->getNumInputs()) {
if (port_desc.direction() != pb::PortDescription::INPUT) {
return ERROR_STATUS(
"Port %d: Expected INPUT port, got %s",
port_idx, pb::PortDescription::Direction_Name(port_desc.direction()).c_str());
}
if (port_desc.type() != pb::PortDescription::AUDIO
&& port_desc.type() != pb::PortDescription::ARATE_CONTROL) {
return ERROR_STATUS(
"Port %d: Expected AUDIO/ARATE_CONTROL port, got %s",
port_idx, pb::PortDescription::Type_Name(port_desc.type()).c_str());
}
} else if (port_idx < _dsp->getNumInputs() + _dsp->getNumOutputs()) {
if (port_desc.direction() != pb::PortDescription::OUTPUT) {
return ERROR_STATUS(
"Port %d: Expected OUTPUT port, got %s",
port_idx, pb::PortDescription::Direction_Name(port_desc.direction()).c_str());
}
if (port_desc.type() != pb::PortDescription::AUDIO
&& port_desc.type() != pb::PortDescription::ARATE_CONTROL) {
return ERROR_STATUS(
"Port %d: Expected AUDIO/ARATE_CONTROL port, got %s",
port_idx, pb::PortDescription::Type_Name(port_desc.type()).c_str());
}
} else {
if (port_desc.direction() != pb::PortDescription::INPUT) {
return ERROR_STATUS(
"Port %d: Expected INPUT port, got %s",
port_idx, pb::PortDescription::Direction_Name(port_desc.direction()).c_str());
}
if (port_desc.type() != pb::PortDescription::KRATE_CONTROL) {
return ERROR_STATUS(
"Port %d: Expected KRATE_CONTROL port, got %s",
port_idx, pb::PortDescription::Type_Name(port_desc.type()).c_str());
}
float* control_ptr = controls.get_control_ptr(port_desc.name());
if (control_ptr == nullptr) {
return ERROR_STATUS(
"Port %d: Control '%s' not declared by DSP",
port_idx, port_desc.name().c_str());
}
_controls.get()[control_idx] = control_ptr;
++control_idx;
}
}
return Status::Ok();
}
void ProcessorFaust::cleanup_internal() {
_dsp.reset();
_buffers.reset();
_inputs.reset();
_outputs.reset();
_controls.reset();
Processor::cleanup_internal();
}
Status ProcessorFaust::connect_port_internal(
BlockContext* ctxt, uint32_t port_idx, BufferPtr buf) {
if (port_idx >= (uint32_t)_desc.ports_size()) {
return ERROR_STATUS("Invalid port index %d", port_idx);
}
_buffers.get()[port_idx] = buf;
return Status::