Add some more builtin nodes.

- Oscillator
- VCA
- Noise
- Step Sequencer
- MIDI CC to CV

Also added the infrastructure to use Faust for creating new processors (used by the Oscillator, VCA
and Noise nodes).
looper
Ben Niemann 4 years ago
parent 1a4435dd71
commit 5ca602b9e4

@ -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,
},
)

@ -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,
},
)

@ -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: ...

@ -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: ...

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

@ -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)

@ -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

@ -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

@ -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

@ -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

@ -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

@ -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

@ -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

@ -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'),

@ -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,

@ -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):

@ -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

@ -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;

@ -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::Ok();
}
Status ProcessorFaust::process_block_internal(BlockContext* ctxt, TimeMapper* time_mapper) {
PerfTracker tracker(ctxt->perf.get(), "faust");
float** inputs = _inputs.get();
float** outputs = _outputs.get();
int input_idx = 0;
int output_idx = 0;
int control_idx = 0;
for (int port_idx = 0 ; port_idx < _desc.ports_size() ; ++port_idx) {
BufferPtr buf = _buffers.get()[port_idx];
if (buf == nullptr) {
return ERROR_STATUS("Port %d not connected.", port_idx);
}
if (port_idx < _dsp->getNumInputs()) {
inputs[input_idx] = (float*)buf;
++input_idx;
} else if (port_idx < _dsp->getNumInputs() + _dsp->getNumOutputs()) {
outputs[output_idx] = (float*)buf;
++output_idx;
} else {
*(_controls.get()[control_idx]) = *((float*)buf);
++control_idx;
}
}
_dsp->compute(_host_system->block_size(), inputs, outputs);
return Status::Ok();
}
}

@ -0,0 +1,40 @@
/*
* @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 "<<srcDir>>/<<base>>.h"
<<includeIntrinsic>>
<<includeclass>>
namespace noisicaa {
Processor<<className>>::Processor<<className>>(
const string& realm_name, const string& node_id, HostSystem* host_system,
const pb::NodeDescription& desc)
: ProcessorFaust(realm_name, node_id, host_system, desc) {}
FaustDSP* Processor<<className>>::create_dsp() {
return new ::Processor<<className>>DSP();
}
}

@ -0,0 +1,67 @@
// -*- mode: c++ -*-
/*
* @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
*/
#ifndef _NOISICAA_AUDIOPROC_ENGINE_PROCESSOR_FAUST_H
#define _NOISICAA_AUDIOPROC_ENGINE_PROCESSOR_FAUST_H
#include <memory>
#include "faust/dsp/dsp.h"
#include "faust/gui/meta.h"
#include "faust/gui/UI.h"
#include "noisicaa/core/status.h"
#include "noisicaa/audioproc/engine/processor.h"
namespace noisicaa {
using namespace std;
class FaustDSP : public dsp {
};
class ProcessorFaust : public Processor {
protected:
ProcessorFaust(
const string& realm_name, const string& node_id, HostSystem* host_system,
const pb::NodeDescription& desc);
Status setup_internal() override;
void cleanup_internal() override;
Status connect_port_internal(BlockContext* ctxt, uint32_t port_idx, BufferPtr buf) override;
Status process_block_internal(BlockContext* ctxt, TimeMapper* time_mapper) override;
virtual FaustDSP* create_dsp() = 0;
private:
unique_ptr<FaustDSP> _dsp;
unique_ptr<BufferPtr> _buffers;
unique_ptr<float*> _controls;
unique_ptr<float*> _inputs;
unique_ptr<float*> _outputs;
};
} // namespace noisicaa
#endif

@ -0,0 +1,44 @@
// -*- mode: c++ -*-
/*
* @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
*/
#ifndef _NOISICAA_BUILTIN_NODES_<<classNameUpper>>_PROCESSOR_H
#define _NOISICAA_BUILTIN_NODES_<<classNameUpper>>_PROCESSOR_H
#include "noisicaa/audioproc/engine/processor_faust.h"
namespace noisicaa {
class Processor<<className>> : public ProcessorFaust {
public:
Processor<<className>>(
const string& realm_name, const string& node_id, HostSystem* host_system,
const pb::NodeDescription& desc);
protected:
FaustDSP* create_dsp() override;
};
} // namespace noisicaa
#endif

@ -230,7 +230,7 @@ cdef class PyRealm(object):
for session_value in session_values:
key = session_value.name
if key.startswith('node/'):
_, node_id, node_key = key.split('/', 3)
_, node_id, node_key = key.split('/', 2)
node = self.__graph.find_node(node_id)
node.set_session_value(node_key, session_value)

@ -37,6 +37,7 @@ target_link_libraries(noisicaa-builtin_nodes-processor_message_registry PRIVATE