Compare commits

...

28 Commits

Author SHA1 Message Date
Ben Niemann 400c782903 Disable test, which causes a mysterious crash. 3 years ago
Ben Niemann a8c916e91f Oscilloscope: Improve rendering when signal is noisy. 3 years ago
Ben Niemann cee374c403 Oscilloscope: Time out when waiting for trigger and show warning sign. 3 years ago
Ben Niemann daabaee6b2 Oscilloscope: correctly render y grid and labels, given the current Y offset. 3 years ago
Ben Niemann 93d9f7ab58 Oscilloscope: Trigger value scaled to be always center of view. 3 years ago
Ben Niemann 08a8fdc39c Oscilloscope: persist state in model. 3 years ago
Ben Niemann 57853f4009 Lint fixes. 3 years ago
Ben Niemann b39194a3f8 Factor out common test code for processors. 3 years ago
Ben Niemann 2743cac468 Oscilloscope: Fancy layout. 3 years ago
Ben Niemann 61e9670fbf Add an IntDial widget. 3 years ago
Ben Niemann ddf34346da Oscilloscope: muting doesn't make sense. 3 years ago
Ben Niemann 9a28daff24 Oscilloscope: better grid lines. 3 years ago
Ben Niemann e67bffc5b4 Oscilloscope: Add a variable hold period. 3 years ago
Ben Niemann 9506433653 Oscilloscope: add pause and step buttons. 3 years ago
Ben Niemann 2c4f691ac8 Oscilloscope: render labels outside of plot area. 3 years ago
Ben Niemann 4240ad0ec9 Oscilloscope: Cache the background grid. 3 years ago
Ben Niemann 251ed48527 Oscilloscope: Add Y offset. 3 years ago
Ben Niemann ded2879831 Oscilloscope: Add time and y scale, trigger sweep on zero cross for a stable plot. 3 years ago
Ben Niemann 6c80505cf7 Add Oscilloscope node. 3 years ago
Ben Niemann b36257b915 Add Control Value Mapper node. 3 years ago
Ben Niemann 596247f11c Edit transfer functions from the plot by dragging handles. 3 years ago
Ben Niemann 01d754d350 Add a widget to plot the current transfer function. 3 years ago
Ben Niemann 7a17e27f84 Move the existing UI code to edit a transfer function to a separate module. 3 years ago
Ben Niemann 98a715faa9 Move the code to apply a transfer function to a separate module. 3 years ago
Ben Niemann 937daafa9a MIDI Monitor and Velocity Mapper don't need to iterate over every sample. 3 years ago
Ben Niemann 0d33e536b2 Add a MIDI Velocity Mapper node. 3 years ago
Ben Niemann a3accbfea2 Add a Metronome node. 3 years ago
Ben Niemann 6863a64013 Add a MIDI Monitor node. 3 years ago
  1. 1
      data/icons/CMakeLists.txt
  2. 81
      data/icons/warning.svg
  3. 2
      noisicaa/audioproc/__init__.py
  4. 8
      noisicaa/audioproc/public/CMakeLists.txt
  5. 6
      noisicaa/audioproc/public/__init__.py
  6. 55
      noisicaa/audioproc/public/transfer_function.cpp
  7. 41
      noisicaa/audioproc/public/transfer_function.h
  8. 51
      noisicaa/audioproc/public/transfer_function.proto
  9. 24
      noisicaa/audioproc/public/transfer_function.pxd
  10. 29
      noisicaa/audioproc/public/transfer_function.pyi
  11. 33
      noisicaa/audioproc/public/transfer_function.pyx
  12. 10
      noisicaa/builtin_nodes/CMakeLists.txt
  13. 108
      noisicaa/builtin_nodes/control_track/processor_test.py
  14. 81
      noisicaa/builtin_nodes/custom_csound/processor_test.py
  15. 42
      noisicaa/builtin_nodes/cv_mapper/CMakeLists.txt
  16. 21
      noisicaa/builtin_nodes/cv_mapper/__init__.py
  17. 31
      noisicaa/builtin_nodes/cv_mapper/model.desc.pb
  18. 83
      noisicaa/builtin_nodes/cv_mapper/model.py
  19. 40
      noisicaa/builtin_nodes/cv_mapper/model_test.py
  20. 49
      noisicaa/builtin_nodes/cv_mapper/node_description.py
  21. 101
      noisicaa/builtin_nodes/cv_mapper/node_ui.py
  22. 45
      noisicaa/builtin_nodes/cv_mapper/node_ui_test.py
  23. 152
      noisicaa/builtin_nodes/cv_mapper/processor.cpp
  24. 68
      noisicaa/builtin_nodes/cv_mapper/processor.h
  25. 36
      noisicaa/builtin_nodes/cv_mapper/processor.proto
  26. 44
      noisicaa/builtin_nodes/cv_mapper/processor_test.py
  27. 71
      noisicaa/builtin_nodes/instrument/processor_test.py
  28. 42
      noisicaa/builtin_nodes/metronome/CMakeLists.txt
  29. 21
      noisicaa/builtin_nodes/metronome/__init__.py
  30. 30
      noisicaa/builtin_nodes/metronome/model.desc.pb
  31. 73
      noisicaa/builtin_nodes/metronome/model.py
  32. 40
      noisicaa/builtin_nodes/metronome/model_test.py
  33. 49
      noisicaa/builtin_nodes/metronome/node_description.py
  34. 127
      noisicaa/builtin_nodes/metronome/node_ui.py
  35. 44
      noisicaa/builtin_nodes/metronome/node_ui_test.py
  36. 205
      noisicaa/builtin_nodes/metronome/processor.cpp
  37. 79
      noisicaa/builtin_nodes/metronome/processor.h
  38. 37
      noisicaa/builtin_nodes/metronome/processor.proto
  39. 46
      noisicaa/builtin_nodes/metronome/processor_test.py
  40. 51
      noisicaa/builtin_nodes/midi_cc_to_cv/processor_test.py
  41. 65
      noisicaa/builtin_nodes/midi_looper/processor_test.py
  42. 39
      noisicaa/builtin_nodes/midi_monitor/CMakeLists.txt
  43. 21
      noisicaa/builtin_nodes/midi_monitor/__init__.py
  44. 25
      noisicaa/builtin_nodes/midi_monitor/model.desc.pb
  45. 37
      noisicaa/builtin_nodes/midi_monitor/model.py
  46. 40
      noisicaa/builtin_nodes/midi_monitor/model_test.py
  47. 44
      noisicaa/builtin_nodes/midi_monitor/node_description.py
  48. 222
      noisicaa/builtin_nodes/midi_monitor/node_ui.py
  49. 45
      noisicaa/builtin_nodes/midi_monitor/node_ui_test.py
  50. 111
      noisicaa/builtin_nodes/midi_monitor/processor.cpp
  51. 66
      noisicaa/builtin_nodes/midi_monitor/processor.h
  52. 31
      noisicaa/builtin_nodes/midi_monitor/processor_test.py
  53. 55
      noisicaa/builtin_nodes/midi_source/processor_test.py
  54. 42
      noisicaa/builtin_nodes/midi_velocity_mapper/CMakeLists.txt
  55. 21
      noisicaa/builtin_nodes/midi_velocity_mapper/__init__.py
  56. 31
      noisicaa/builtin_nodes/midi_velocity_mapper/model.desc.pb
  57. 79
      noisicaa/builtin_nodes/midi_velocity_mapper/model.py
  58. 40
      noisicaa/builtin_nodes/midi_velocity_mapper/model_test.py
  59. 49
      noisicaa/builtin_nodes/midi_velocity_mapper/node_description.py
  60. 101
      noisicaa/builtin_nodes/midi_velocity_mapper/node_ui.py
  61. 45
      noisicaa/builtin_nodes/midi_velocity_mapper/node_ui_test.py
  62. 180
      noisicaa/builtin_nodes/midi_velocity_mapper/processor.cpp
  63. 70
      noisicaa/builtin_nodes/midi_velocity_mapper/processor.h
  64. 36
      noisicaa/builtin_nodes/midi_velocity_mapper/processor.proto
  65. 43
      noisicaa/builtin_nodes/midi_velocity_mapper/processor_test.py
  66. 69
      noisicaa/builtin_nodes/mixer/processor_test.py
  67. 2
      noisicaa/builtin_nodes/model.tmpl.py
  68. 20
      noisicaa/builtin_nodes/model_registry.proto
  69. 15
      noisicaa/builtin_nodes/model_registry.py
  70. 10
      noisicaa/builtin_nodes/node_description_registry.py
  71. 53
      noisicaa/builtin_nodes/noise/processor_test.py
  72. 55
      noisicaa/builtin_nodes/oscillator/processor_test.py
  73. 42
      noisicaa/builtin_nodes/oscilloscope/CMakeLists.txt
  74. 21
      noisicaa/builtin_nodes/oscilloscope/__init__.py
  75. 49
      noisicaa/builtin_nodes/oscilloscope/model.desc.pb
  76. 63
      noisicaa/builtin_nodes/oscilloscope/model.py
  77. 40
      noisicaa/builtin_nodes/oscilloscope/model_test.py
  78. 45
      noisicaa/builtin_nodes/oscilloscope/node_description.py
  79. 660
      noisicaa/builtin_nodes/oscilloscope/node_ui.py
  80. 46
      noisicaa/builtin_nodes/oscilloscope/node_ui_test.py
  81. 159
      noisicaa/builtin_nodes/oscilloscope/processor.cpp
  82. 76
      noisicaa/builtin_nodes/oscilloscope/processor.h
  83. 36
      noisicaa/builtin_nodes/oscilloscope/processor.proto
  84. 39
      noisicaa/builtin_nodes/oscilloscope/processor_test.py
  85. 133
      noisicaa/builtin_nodes/pianoroll/processor_test.py
  86. 20
      noisicaa/builtin_nodes/processor_registry.cpp
  87. 129
      noisicaa/builtin_nodes/sample_track/processor_test.py
  88. 47
      noisicaa/builtin_nodes/step_sequencer/processor_test.py
  89. 10
      noisicaa/builtin_nodes/ui_registry.py
  90. 61
      noisicaa/builtin_nodes/vca/processor_test.py
  91. 17
      noisicaa/lv2/atom.pyx
  92. 2
      noisicaa/music/CMakeLists.txt
  93. 3
      noisicaa/music/__init__.py
  94. 14
      noisicaa/music/graph.py
  95. 64
      noisicaa/music/model.desc.pb
  96. 3
      noisicaa/music/project.proto
  97. 2
      noisicaa/music/project.py
  98. 80
      noisicaa/music/transfer_function.py
  99. 49
      noisicaa/music/transfer_function_test.py
  100. 4
      noisicaa/ui/CMakeLists.txt
  101. Some files were not shown because too many files have changed in this diff Show More

1
data/icons/CMakeLists.txt

@ -58,4 +58,5 @@ install_files(
track-type-sample.svg
track-type-score.svg
track-visible.svg
warning.svg
)

81
data/icons/warning.svg

@ -0,0 +1,81 @@
<?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="warning.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 />
</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="16.000001"
inkscape:cx="-6.3115405"
inkscape:cy="25.123386"
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">
<g
id="layer1"
transform="matrix(0.05920137,0,0,-0.05920137,128.73324,826.15201)">
<path
id="path11039"
style="fill:#ee1c23;fill-rule:nonzero;stroke:none"
d="m 840.83969,544.41993 c -14.03378,24.29258 -37.01519,24.29258 -51.06339,0 L 321.28695,-265.67834 c -14.03379,-24.29257 -2.55029,-44.16176 25.5317,-44.16176 l 936.94985,-0.0144 c 28.0964,0 39.5799,19.86919 25.5317,44.16177 z"
inkscape:connector-curvature="0" />
<path
id="path10308"
style="fill:#ffffff;fill-rule:nonzero;stroke:none"
d="m 1154.4675,-205.95549 -678.31899,0.0144 339.15949,586.4942 339.1595,-586.50861"
inkscape:connector-curvature="0" />
</g>
<g
aria-label="!"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:33.58262253px;line-height:125%;font-family:'Arial Black';-inkscape-font-specification:'Arial Black, 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:3.3582623pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
id="text955">
<path
d="m 173.43348,812.48346 h 7.13303 v 5.47685 l -1.37741,11.0029 h -4.411 l -1.34462,-11.0029 z m 0.24597,18.15233 h 6.65749 v 5.88679 h -6.65749 z"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:33.58262253px;font-family:'Arial Black';-inkscape-font-specification:'Arial Black, 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:3.3582623pt"
id="path825" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.5 KiB

2
noisicaa/audioproc/__init__.py

@ -61,4 +61,6 @@ from .public import (
NodePortProperties,
NodeParameters,
MidiEvent,
TransferFunction,
TransferFunctionSpec,
)

8
noisicaa/audioproc/public/CMakeLists.txt

@ -21,6 +21,7 @@
add_python_package(
time_mapper.pyi
musical_time.pyi
transfer_function.pyi
)
set(LIB_SRCS
@ -40,6 +41,8 @@ set(LIB_SRCS
processor_message.pb.cc
project_properties.pb.cc
time_mapper.cpp
transfer_function.cpp
transfer_function.pb.cc
)
set(TEST_SRCS
@ -75,6 +78,8 @@ cpp_proto(node_parameters.proto)
py_proto(node_parameters.proto)
cpp_proto(midi_event.proto)
py_proto(midi_event.proto)
cpp_proto(transfer_function.proto)
py_proto(transfer_function.proto)
add_library(noisicaa-audioproc-public SHARED ${LIB_SRCS})
target_compile_options(noisicaa-audioproc-public PRIVATE -fPIC -std=c++11 -Wall -Werror -pedantic -DHAVE_PTHREAD_SPIN_LOCK)
@ -90,6 +95,9 @@ target_link_libraries(${musical_time.so} PRIVATE noisicaa-audioproc-public)
add_cython_module(time_mapper CXX)
target_link_libraries(${time_mapper.so} PRIVATE noisicaa-audioproc-public)
add_cython_module(transfer_function CXX)
target_link_libraries(${transfer_function.so} PRIVATE noisicaa-audioproc-public)
foreach(TEST_SRC ${TEST_SRCS})
string(REGEX REPLACE "\.pyx$" "" TEST_MOD ${TEST_SRC})
add_cython_module(${TEST_MOD} CXX)

6
noisicaa/audioproc/public/__init__.py

@ -72,3 +72,9 @@ from .node_parameters_pb2 import (
from .midi_event_pb2 import (
MidiEvent,
)
from .transfer_function import (
TransferFunction,
)
from .transfer_function_pb2 import (
TransferFunctionSpec,
)

55
noisicaa/audioproc/public/transfer_function.cpp

@ -0,0 +1,55 @@
/*
* @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 <math.h>
#include "noisicaa/audioproc/public/transfer_function.h"
#include "noisicaa/audioproc/public/transfer_function.pb.h"
namespace noisicaa {
float apply_transfer_function(const pb::TransferFunctionSpec& spec, float value) {
switch (spec.type_case()) {
case pb::TransferFunctionSpec::kFixed:
value = spec.fixed().value();
break;
case pb::TransferFunctionSpec::kLinear: {
value = (spec.linear().right_value() - spec.linear().left_value()) * (value - spec.input_min()) / (spec.input_max() - spec.input_min()) + spec.linear().left_value();
break;
}
case pb::TransferFunctionSpec::kGamma:
value = (spec.output_max() - spec.output_min()) * powf((value - spec.input_min()) / (spec.input_max() - spec.input_min()), spec.gamma().value()) + spec.output_min();
break;
default:
break;
}
return value;
}
float apply_transfer_function(const std::string& serialized_spec, float value) {
pb::TransferFunctionSpec spec;
assert(spec.ParseFromString(serialized_spec));
return apply_transfer_function(spec, value);
}
}

41
noisicaa/audioproc/public/transfer_function.h

@ -0,0 +1,41 @@
// -*- 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_PUBLIC_TRANSFER_FUNCTION_H
#define _NOISICAA_AUDIOPROC_PUBLIC_TRANSFER_FUNCTION_H
#include <string>
namespace noisicaa {
namespace pb {
class TransferFunctionSpec;
}
float apply_transfer_function(const pb::TransferFunctionSpec& spec, float value);
float apply_transfer_function(const std::string& serialized_spec, float value);
} // namespace noisicaa
#endif

51
noisicaa/audioproc/public/transfer_function.proto

@ -0,0 +1,51 @@
/*
* @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
*/
syntax = "proto2";
package noisicaa.pb;
message TransferFunctionSpec {
required float input_min = 1;
required float input_max = 2;
required float output_min = 3;
required float output_max = 4;
message Fixed {
required float value = 1;
}
message Linear {
required float left_value = 1;
required float right_value = 2;
}
message Gamma {
required float value = 1;
}
oneof type {
Fixed fixed = 5;
Linear linear = 6;
Gamma gamma = 7;
}
}

24
noisicaa/audioproc/public/transfer_function.pxd

@ -0,0 +1,24 @@
# @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 libcpp.string cimport string
cdef extern from "noisicaa/audioproc/public/transfer_function.h" namespace "noisicaa" nogil:
cdef float apply_transfer_function(const string& spec, float value)

29
noisicaa/audioproc/public/transfer_function.pyi

@ -0,0 +1,29 @@
#!/usr/bin/python3
# @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 . import transfer_function_pb2
class TransferFunction(object):
def __init__(self, spec: transfer_function_pb2.TransferFunctionSpec) -> None: ...
def __call__(self, value: float) -> float: ...

33
noisicaa/audioproc/public/transfer_function.pyx

@ -0,0 +1,33 @@
#!/usr/bin/python3
# @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 . import transfer_function_pb2
cdef class TransferFunction(object):
cdef bytes __serialized_spec
def __init__(self, spec: transfer_function_pb2.TransferFunctionSpec) -> None:
self.__serialized_spec = spec.SerializeToString()
def __call__(self, value: float) -> float:
return apply_transfer_function(self.__serialized_spec, value)

10
noisicaa/builtin_nodes/CMakeLists.txt

@ -55,6 +55,11 @@ target_link_libraries(noisicaa-builtin_nodes-processors PRIVATE noisicaa-builtin
target_link_libraries(noisicaa-builtin_nodes-processors PRIVATE noisicaa-builtin_nodes-step_sequencer-processor)
target_link_libraries(noisicaa-builtin_nodes-processors PRIVATE noisicaa-builtin_nodes-midi_cc_to_cv-processor)
target_link_libraries(noisicaa-builtin_nodes-processors PRIVATE noisicaa-builtin_nodes-midi_looper-processor)
target_link_libraries(noisicaa-builtin_nodes-processors PRIVATE noisicaa-builtin_nodes-midi_monitor-processor)
target_link_libraries(noisicaa-builtin_nodes-processors PRIVATE noisicaa-builtin_nodes-metronome-processor)
target_link_libraries(noisicaa-builtin_nodes-processors PRIVATE noisicaa-builtin_nodes-midi_velocity_mapper-processor)
target_link_libraries(noisicaa-builtin_nodes-processors PRIVATE noisicaa-builtin_nodes-cv_mapper-processor)
target_link_libraries(noisicaa-builtin_nodes-processors PRIVATE noisicaa-builtin_nodes-oscilloscope-processor)
add_subdirectory(score_track)
add_subdirectory(beat_track)
@ -71,3 +76,8 @@ add_subdirectory(noise)
add_subdirectory(step_sequencer)
add_subdirectory(midi_cc_to_cv)
add_subdirectory(midi_looper)
add_subdirectory(midi_monitor)
add_subdirectory(metronome)
add_subdirectory(midi_velocity_mapper)
add_subdirectory(cv_mapper)
add_subdirectory(oscilloscope)

108
noisicaa/builtin_nodes/control_track/processor_test.py

@ -21,123 +21,73 @@
import math
from noisidev import unittest
from noisidev import unittest_mixins
from noisidev import unittest_engine_mixins
from noisidev import unittest_engine_utils
from noisidev import unittest_processor_mixins
from noisicaa.audioproc.public import musical_time
from noisicaa.audioproc.engine import block_context
from noisicaa.audioproc.engine import buffers
from noisicaa.audioproc.engine import processor
from . import processor_messages
class ProcessorCVGeneratorTest(
unittest_engine_mixins.HostSystemMixin,
unittest_mixins.NodeDBMixin,
unittest_processor_mixins.ProcessorTestMixin,
unittest.TestCase):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.proc = None
self.arena = None
self.buffer_mgr = None
self.ctxt = None
self.outbuf = None
def setup_testcase(self):
self.node_description = self.node_db['builtin://control-track']
self.host_system.set_block_size(4096)
plugin_uri = 'builtin://control-track'
node_description = self.node_db[plugin_uri]
self.proc = processor.PyProcessor('realm', 'test_node', self.host_system, node_description)
self.proc.setup()
self.buffer_mgr = unittest_engine_utils.BufferManager(self.host_system)
self.outbuf = self.buffer_mgr.allocate('out', buffers.PyFloatAudioBlockBuffer())
self.ctxt = block_context.PyBlockContext()
self.ctxt.clear_time_map(self.host_system.block_size)
for s in range(self.host_system.block_size):
self.ctxt.set_sample_time(
s,
musical_time.PyMusicalTime(s, 44100),
musical_time.PyMusicalTime(s + 1, 44100))
self.proc.connect_port(self.ctxt, 0, self.buffer_mgr.data('out'))
def cleanup_testcase(self):
if self.proc is not None:
self.proc.cleanup()
self.create_processor()
def test_empty(self):
self.proc.process_block(self.ctxt, None) # TODO: pass time_mapper
self.assertTrue(all(v == 0.0 for v in self.outbuf))
self.process_block()
self.assertBufferIsQuiet('out')
def test_single_control_point(self):
msg = processor_messages.add_control_point(
self.processor.handle_message(processor_messages.add_control_point(
node_id='123',
id=0x0001,
time=musical_time.PyMusicalTime(1024, 44100),
value=0.5)
self.proc.handle_message(msg)
time=musical_time.PyMusicalTime(1024, self.host_system.sample_rate),
value=0.5))
self.proc.process_block(self.ctxt, None) # TODO: pass time_mapper
self.assertTrue(all(math.isclose(v, 0.5) for v in self.outbuf))
self.process_block()
self.assertBufferAllEqual('out', 0.5)
def test_two_control_points(self):
msg = processor_messages.add_control_point(
self.processor.handle_message(processor_messages.add_control_point(
node_id='123',
id=0x0001,
time=musical_time.PyMusicalTime(1024, 44100),
value=0.2)
self.proc.handle_message(msg)
msg = processor_messages.add_control_point(
time=musical_time.PyMusicalTime(1024, self.host_system.sample_rate),
value=0.2))
self.processor.handle_message(processor_messages.add_control_point(
node_id='123',
id=0x0002,
time=musical_time.PyMusicalTime(3072, 44100),
value=0.8)
self.proc.handle_message(msg)
time=musical_time.PyMusicalTime(3072, self.host_system.sample_rate),
value=0.8))
self.proc.process_block(self.ctxt, None) # TODO: pass time_mapper
self.process_block()
# Constant value before first control point.
self.assertTrue(all(math.isclose(v, 0.2, rel_tol=0.001) for v in self.outbuf[:1024]))
self.assertBufferRangeEqual('out', 0, 1024, 0.2)
# Linear ramp up between first and second control points.
self.assertTrue(all(math.isclose(v, e, rel_tol=0.001)
for v, e
in zip(self.outbuf[1024:3072],
in zip(self.buffers['out'][1024:3072],
[0.2 + 0.6 * i / 2048 for i in range(2048)])))
# Constant value after second control point.
self.assertTrue(all(math.isclose(v, 0.8, rel_tol=0.001) for v in self.outbuf[3072:]))
self.assertBufferRangeEqual('out', 3072, 4096, 0.8)
def test_remove_control_point(self):
msg = processor_messages.add_control_point(
self.processor.handle_message(processor_messages.add_control_point(
node_id='123',
id=0x0001,
time=musical_time.PyMusicalTime(1024, 44100),
value=0.5)
self.proc.handle_message(msg)
msg = processor_messages.add_control_point(
value=0.5))
self.processor.handle_message(processor_messages.add_control_point(
node_id='123',
id=0x0002,
time=musical_time.PyMusicalTime(2048, 44100),
value=1.0)
self.proc.handle_message(msg)
msg = processor_messages.remove_control_point(
value=1.0))
self.processor.handle_message(processor_messages.remove_control_point(
node_id='123',
id=0x0002)
self.proc.handle_message(msg)
self.proc.process_block(self.ctxt, None) # TODO: pass time_mapper
id=0x0002))
self.assertTrue(all(math.isclose(v, 0.5) for v in self.outbuf))
self.process_block()
self.assertBufferAllEqual('out', 0.5)

81
noisicaa/builtin_nodes/custom_csound/processor_test.py

@ -21,75 +21,42 @@
import textwrap
from noisidev import unittest
from noisidev import unittest_mixins
from noisidev import unittest_engine_mixins
from noisidev import unittest_engine_utils
from noisidev import unittest_processor_mixins
from noisicaa import node_db
from noisicaa import lv2
from noisicaa.audioproc.public import node_parameters_pb2
from noisicaa.audioproc.engine import block_context
from noisicaa.audioproc.engine import buffers
from noisicaa.audioproc.engine import processor
from . import processor_pb2
class ProcessorCustomCSoundTest(
unittest_engine_mixins.HostSystemMixin,
unittest_mixins.NodeDBMixin,
unittest_processor_mixins.ProcessorTestMixin,
unittest.TestCase):
def setup_testcase(self):
self.buffer_mgr = unittest_engine_utils.BufferManager(self.host_system)
self.ctxt = block_context.PyBlockContext()
def create_proc(self, orchestra, score):
node_desc = self.node_db['builtin://custom-csound']
node_desc.ports.add(
self.node_description = self.node_db['builtin://custom-csound']
self.node_description.ports.add(
name='in',
type=node_db.PortDescription.AUDIO,
direction=node_db.PortDescription.INPUT)
node_desc.ports.add(
self.node_description.ports.add(
name='out',
type=node_db.PortDescription.AUDIO,
direction=node_db.PortDescription.OUTPUT)
node_desc.ports.add(
self.node_description.ports.add(
name='ctrl',
type=node_db.PortDescription.KRATE_CONTROL,
direction=node_db.PortDescription.INPUT)
node_desc.ports.add(
self.node_description.ports.add(
name='ev',
type=node_db.PortDescription.EVENTS,
direction=node_db.PortDescription.INPUT)
proc = processor.PyProcessor('realm', 'test_node', self.host_system, node_desc)
proc.setup()
self.create_processor()
def set_code(self, orchestra, score):
params = node_parameters_pb2.NodeParameters()
csound_params = params.Extensions[processor_pb2.custom_csound_parameters]
csound_params.orchestra = orchestra
csound_params.score = score
proc.set_parameters(params)
audio_in = self.buffer_mgr.allocate('in', buffers.PyFloatAudioBlockBuffer())
ctrl = self.buffer_mgr.allocate('ctrl', buffers.PyFloatControlValueBuffer())
self.buffer_mgr.allocate('ev', buffers.PyAtomDataBuffer())
audio_out = self.buffer_mgr.allocate('out', buffers.PyFloatAudioBlockBuffer())
# clear all buffers
forge = lv2.AtomForge(self.urid_mapper)
forge.set_buffer(self.buffer_mgr.data('ev'), 10240)
with forge.sequence():
pass
ctrl[0] = 0.0
for i in range(self.host_system.block_size):
audio_in[i] = 0.0
audio_out[i] = 0.0
proc.connect_port(self.ctxt, 0, self.buffer_mgr.data('in'))
proc.connect_port(self.ctxt, 1, self.buffer_mgr.data('out'))
proc.connect_port(self.ctxt, 2, self.buffer_mgr.data('ctrl'))
proc.connect_port(self.ctxt, 3, self.buffer_mgr.data('ev'))
return proc
self.processor.set_parameters(params)
def test_synth(self):
orchestra = textwrap.dedent('''\
@ -108,19 +75,18 @@ class ProcessorCustomCSoundTest(
score = textwrap.dedent('''\
e 10000
''')
proc = self.create_proc(orchestra, score)
self.set_code(orchestra, score)
forge = lv2.AtomForge(self.urid_mapper)
forge.set_buffer(self.buffer_mgr.data('ev'), 10240)
with forge.sequence():
forge.write_midi_event(0, bytes([0x90, 60, 100]), 3)
forge.write_midi_event(64, bytes([0x80, 60, 0]), 3)
self.fill_midi_buffer(
'ev',
[(0, [0x90, 60, 100]),
(64, [0x80, 60, 0])])
proc.process_block(self.ctxt, None) # TODO: pass time_mapper
self.process_block()
# The instrument only gets active with one cycle delay, so the first 32 samples a silence.
# Turning it off though works instantaneously.
audio_out = self.buffer_mgr['out']
audio_out = self.buffers['out']
self.assertTrue(all(v == 0.0 for v in audio_out[:32]))
self.assertTrue(all(v == 1.0 for v in audio_out[32:64]))
self.assertTrue(all(v == 0.0 for v in audio_out[64:]))
@ -143,17 +109,14 @@ class ProcessorCustomCSoundTest(
i1 0 -1
e 10000
''')
proc = self.create_proc(orchestra, score)
self.set_code(orchestra, score)
audio_in = self.buffer_mgr['in']
for i in range(self.host_system.block_size):
audio_in[i] = 1.0
audio_in[i] = 1.0
self.buffer_mgr['ctrl'][0] = 0.5
self.fill_buffer('in', 1.0)
self.fill_buffer('ctrl', 0.5)
proc.process_block(self.ctxt, None) # TODO: pass time_mapper
self.process_block()
# The instrument only gets active with one cycle delay, so the first 32 samples a silence.
audio_out = self.buffer_mgr['out']
audio_out = self.buffers['out']
self.assertTrue(all(v == 0.0 for v in audio_out[:32]))
self.assertTrue(all(v == 0.5 for v in audio_out[32:]))

42
noisicaa/builtin_nodes/cv_mapper/CMakeLists.txt

@ -0,0 +1,42 @@
# @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
add_python_package(
node_description.py
model.py
model_test.py
node_ui.py
node_ui_test.py
processor_test.py
)
build_model(model.desc.pb _model.py noisicaa/builtin_nodes/model.tmpl.py)
py_proto(model.proto)
add_dependencies(noisicaa.builtin_nodes.cv_mapper.model.proto model-noisicaa.builtin_nodes.cv_mapper)
cpp_proto(model.proto)
py_proto(processor.proto)
cpp_proto(processor.proto)
add_dependencies(noisicaa.builtin_nodes.cv_mapper.processor.proto model-noisicaa.builtin_nodes.cv_mapper)
add_library(noisicaa-builtin_nodes-cv_mapper-processor SHARED processor.cpp processor.pb.cc)
target_compile_options(noisicaa-builtin_nodes-cv_mapper-processor PRIVATE -fPIC -std=c++11 -Wall -Werror -pedantic -DHAVE_PTHREAD_SPIN_LOCK)
target_link_libraries(noisicaa-builtin_nodes-cv_mapper-processor PRIVATE noisicaa-audioproc-public)
target_link_libraries(noisicaa-builtin_nodes-cv_mapper-processor PRIVATE noisicaa-host_system)

21
noisicaa/builtin_nodes/cv_mapper/__init__.py

@ -0,0 +1,21 @@
#!/usr/bin/python3
# @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

31
noisicaa/builtin_nodes/cv_mapper/model.desc.pb

@ -0,0 +1,31 @@
# @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
classes {
name: "CVMapper"
super_class: "noisicaa.music.graph.BaseNode"
proto_ext_name: "cv_mapper"
properties {
name: "transfer_function"
type: OBJECT
obj_type: "noisicaa.music.transfer_function.TransferFunction"
proto_id: 1
}
}

83
noisicaa/builtin_nodes/cv_mapper/model.py

@ -0,0 +1,83 @@
#!/usr/bin/python3
# @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
import logging
from typing import Any, Iterator
from noisicaa import audioproc
from noisicaa import music
from noisicaa import node_db
from noisicaa import value_types
from . import node_description
from . import processor_pb2
from . import _model
logger = logging.getLogger(__name__)
class CVMapper(_model.CVMapper):
def create(self, **kwargs: Any) -> None:
super().create(**kwargs)
self.transfer_function = self._pool.create(
music.TransferFunction,
input_min=-1.0,
input_max=1.0,
output_min=-1.0,
output_max=1.0,
type=music.TransferFunction.FIXED,
fixed_value=0.0,
linear_left_value=-1.0,
linear_right_value=1.0)
def setup(self) -> None:
super().setup()
self.transfer_function.object_changed.add(lambda _: self.update_spec())
def default_port_properties(self, port_name: str) -> value_types.NodePortProperties:
return value_types.NodePortProperties(port_name, exposed=True)
def get_initial_parameter_mutations(self) -> Iterator[audioproc.Mutation]:
yield from super().get_initial_parameter_mutations()
yield self.__get_spec_mutation()
def update_spec(self) -> None:
if self.attached_to_project:
self.project.handle_pipeline_mutation(
self.__get_spec_mutation())
def __get_spec_mutation(self) -> audioproc.Mutation:
params = audioproc.NodeParameters()
spec = params.Extensions[processor_pb2.cv_mapper_spec]
spec.transfer_function.CopyFrom(self.transfer_function.get_function_spec())
return audioproc.Mutation(
set_node_parameters=audioproc.SetNodeParameters(
node_id=self.pipeline_node_id,
parameters=params))
@property
def description(self) -> node_db.NodeDescription:
node_desc = node_db.NodeDescription()
node_desc.CopyFrom(node_description.CVMapperDescription)
return node_desc

40
noisicaa/builtin_nodes/cv_mapper/model_test.py

@ -0,0 +1,40 @@
#!/usr/bin/python3
# @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 typing import cast
from noisidev import unittest
from noisidev import unittest_mixins
from . import model
class CVMapperTest(unittest_mixins.ProjectMixin, unittest.AsyncTestCase):
async def _add_node(self) -> model.CVMapper:
with self.project.apply_mutations('test'):
return cast(
model.CVMapper,
self.project.create_node('builtin://cv-mapper'))
async def test_add_node(self):
node = await self._add_node()
self.assertIsInstance(node, model.CVMapper)

49
noisicaa/builtin_nodes/cv_mapper/node_description.py

@ -0,0 +1,49 @@
#!/usr/bin/python3
# @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 noisicaa import node_db
CVMapperDescription = node_db.NodeDescription(
uri='builtin://cv-mapper',
display_name='Control Value Mapper (a-rate)',
type=node_db.NodeDescription.PROCESSOR,
node_ui=node_db.NodeUIDescription(
type='builtin://cv-mapper',
),
builtin_icon='node-type-builtin',
processor=node_db.ProcessorDescription(
type='builtin://cv-mapper',
),
ports=[
node_db.PortDescription(
name='in',
direction=node_db.PortDescription.INPUT,
type=node_db.PortDescription.ARATE_CONTROL,
),
node_db.PortDescription(
name='out',
direction=node_db.PortDescription.OUTPUT,
type=node_db.PortDescription.ARATE_CONTROL,
),
]
)

101
noisicaa/builtin_nodes/cv_mapper/node_ui.py

@ -0,0 +1,101 @@
#!/usr/bin/python3
# @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
import logging
from typing import Any
from PyQt5.QtCore import Qt
from PyQt5 import QtWidgets
from noisicaa import core
from noisicaa import music
from noisicaa.ui import ui_base
from noisicaa.ui import transfer_function_editor
from noisicaa.ui.graph import base_node
from . import model
logger = logging.getLogger(__name__)
class CVMapperNodeWidget(ui_base.ProjectMixin, core.AutoCleanupMixin, QtWidgets.QWidget):
def __init__(self, node: model.CVMapper, session_prefix: str, **kwargs: Any) -> None:
super().__init__(**kwargs)
self.__node = node
self.__transfer_function_editor = transfer_function_editor.TransferFunctionEditor(
transfer_function=self.__node.transfer_function,
mutation_name_prefix=self.__node.name,
context=self.context)
self.add_cleanup_function(self.__transfer_function_editor.cleanup)
l1 = QtWidgets.QVBoxLayout()
l1.setContentsMargins(0, 0, 0, 0)
l1.addWidget(self.__transfer_function_editor)
self.setLayout(l1)
class CVMapperNode(base_node.Node):
has_window = True
def __init__(self, *, node: music.BaseNode, **kwargs: Any) -> None:
assert isinstance(node, model.CVMapper), type(node).__name__
self.__widget = None # type: QtWidgets.QWidget
self.__node = node # type: model.CVMapper
super().__init__(node=node, **kwargs)
def createBodyWidget(self) -> QtWidgets.QWidget:
assert self.__widget is None
body = CVMapperNodeWidget(
node=self.__node,
session_prefix='inline',
context=self.context)
self.add_cleanup_function(body.cleanup)
body.setAutoFillBackground(False)
body.setAttribute(Qt.WA_NoSystemBackground, True)
self.__widget = QtWidgets.QScrollArea()
self.__widget.setWidgetResizable(True)
self.__widget.setFrameShape(QtWidgets.QFrame.NoFrame)
self.__widget.setWidget(body)
return self.__widget
def createWindow(self, **kwargs: Any) -> QtWidgets.QWidget:
window = QtWidgets.QDialog(**kwargs)
window.setAttribute(Qt.WA_DeleteOnClose, False)
window.setWindowTitle("Control Value Mapper")
body = CVMapperNodeWidget(
node=self.__node,
session_prefix='window',
context=self.context)
self.add_cleanup_function(body.cleanup)
layout = QtWidgets.QVBoxLayout()
layout.setContentsMargins(0, 0, 0, 0)
layout.addWidget(body)
window.setLayout(layout)
return window

45
noisicaa/builtin_nodes/cv_mapper/node_ui_test.py

@ -0,0 +1,45 @@
#!/usr/bin/python3
# @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 noisidev import uitest
from . import node_ui
class CVMapperNodeTest(uitest.ProjectMixin, uitest.UITestCase):
async def setup_testcase(self):
with self.project.apply_mutations('test'):
self.node = self.project.create_node('builtin://cv-mapper')
async def test_init(self):
widget = node_ui.CVMapperNode(node=self.node, context=self.context)
widget.cleanup()
class CVMapperNodeWidgetTest(uitest.ProjectMixin, uitest.UITestCase):
async def setup_testcase(self):
with self.project.apply_mutations('test'):
self.node = self.project.create_node('builtin://cv-mapper')
async def test_init(self):
widget = node_ui.CVMapperNodeWidget(
node=self.node, session_prefix='test', context=self.context)
widget.cleanup()

152
noisicaa/builtin_nodes/cv_mapper/processor.cpp

@ -0,0 +1,152 @@
/*
* @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 <math.h>
#include "noisicaa/audioproc/engine/misc.h"
#include "noisicaa/audioproc/public/engine_notification.pb.h"
#include "noisicaa/audioproc/public/transfer_function.h"
#include "noisicaa/audioproc/engine/message_queue.h"
#include "noisicaa/host_system/host_system.h"
#include "noisicaa/builtin_nodes/cv_mapper/processor.h"
#include "noisicaa/builtin_nodes/cv_mapper/processor.pb.h"
namespace noisicaa {
ProcessorCVMapper::ProcessorCVMapper(
const string& realm_name, const string& node_id, HostSystem *host_system,
const pb::NodeDescription& desc)
: Processor(
realm_name, node_id, "noisicaa.audioproc.engine.processor.cv_mapper", host_system, desc),
_next_spec(nullptr),
_current_spec(nullptr),
_old_spec(nullptr) {
}
Status ProcessorCVMapper::setup_internal() {
RETURN_IF_ERROR(Processor::setup_internal());
_buffers[0] = nullptr;
_buffers[1] = nullptr;
return Status::Ok();
}
void ProcessorCVMapper::cleanup_internal() {
pb::CVMapperSpec* spec = _next_spec.exchange(nullptr);
if (spec != nullptr) {
delete spec;
}
spec = _current_spec.exchange(nullptr);
if (spec != nullptr) {
delete spec;
}
spec = _old_spec.exchange(nullptr);