Also autogenerate the boilerplate for core model classes.

And merge noisicaa.model_base into noisicaa.music
model-merge
Ben Niemann 4 years ago
parent 0547d8aaea
commit da30e0065d

@ -148,21 +148,20 @@ macro(faust_dsp clsName src)
)
endmacro(faust_dsp)
macro(build_model src)
string(REGEX REPLACE "\.desc.pb" ".py" out ${src})
macro(build_model src out template)
file(RELATIVE_PATH pkg_path ${CMAKE_SOURCE_DIR} ${CMAKE_CURRENT_LIST_DIR})
add_custom_command(
OUTPUT _model.py model.proto
COMMAND python noisidev/build_model.py -o ${CMAKE_BINARY_DIR} ${pkg_path}/${src}
OUTPUT ${out} model.proto
COMMAND python noisidev/build_model.py --output ${CMAKE_BINARY_DIR} --template ${CMAKE_SOURCE_DIR}/${template} ${pkg_path}/${src}
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
DEPENDS
${CMAKE_CURRENT_LIST_DIR}/${src}
${CMAKE_SOURCE_DIR}/noisidev/build_model.py
noisidev.model_desc.proto
${CMAKE_SOURCE_DIR}/noisicaa/builtin_nodes/model.tmpl.py
${CMAKE_SOURCE_DIR}/${template}
)
string(REGEX REPLACE "/" "." pkg_target ${pkg_path})
add_custom_target("model-${pkg_target}" ALL DEPENDS _${out})
add_custom_target("model-${pkg_target}" ALL DEPENDS ${out})
endmacro(build_model)
add_subdirectory(noisicaa)

@ -38,7 +38,6 @@ add_subdirectory(host_system)
add_subdirectory(instr)
add_subdirectory(instrument_db)
add_subdirectory(lv2)
add_subdirectory(model_base)
add_subdirectory(value_types)
add_subdirectory(music)
add_subdirectory(node_db)

@ -27,6 +27,6 @@ add_python_package(
track_ui_test.py
)
build_model(model.desc.pb)
build_model(model.desc.pb _model.py noisicaa/builtin_nodes/model.tmpl.py)
py_proto(model.proto)

@ -18,11 +18,9 @@
#
# @end:license
template: "noisicaa/builtin_nodes/model.tmpl.py"
classes {
name: "Beat"
super_class: "noisicaa.music.model.ProjectChild"
super_class: "noisicaa.music.model_base.ProjectChild"
proto_ext_name: "beat"
properties {
name: "time"

@ -26,7 +26,7 @@ from noisicaa.core.typing_extra import down_cast
from noisicaa import core
from noisicaa import node_db
from noisicaa import audioproc
from noisicaa import model_base
from noisicaa import music
from noisicaa import value_types
from noisicaa.music import base_track
from . import node_description
@ -58,7 +58,7 @@ class BeatTrackConnector(base_track.MeasuredTrackConnector):
self._node.pitch, 127)
yield event
def __pitch_changed(self, change: model_base.PropertyChange) -> None:
def __pitch_changed(self, change: music.PropertyChange) -> None:
self._update_measure_range(0, len(self._node.measure_list))
def __measure_beats_changed(self, mref: base_track.MeasureReference) -> None:
@ -80,7 +80,7 @@ class Beat(_model.Beat):
def measure(self) -> 'BeatMeasure':
return cast(BeatMeasure, self.parent)
def property_changed(self, change: model_base.PropertyChange) -> None:
def property_changed(self, change: music.PropertyChange) -> None:
super().property_changed(change)
if self.measure is not None:
self.measure.content_changed.call()

@ -31,7 +31,6 @@ from PyQt5 import QtSvg
from noisicaa.constants import DATA_DIR
from noisicaa import core
from noisicaa import value_types
from noisicaa import model_base
from noisicaa import music
from noisicaa.ui.graph import track_node
from noisicaa.ui import ui_base
@ -73,7 +72,7 @@ class BeatTrackWidget(ui_base.ProjectMixin, QtWidgets.QScrollArea):
listener.remove()
self.__listeners.clear()
def __pitchChanged(self, change: model_base.PropertyValueChange[str]) -> None:
def __pitchChanged(self, change: music.PropertyValueChange[str]) -> None:
self.__pitch.setText(str(change.new_value))
def __pitchEdited(self) -> None:

@ -29,7 +29,7 @@ add_python_package(
processor_messages.py
)
build_model(model.desc.pb)
build_model(model.desc.pb _model.py noisicaa/builtin_nodes/model.tmpl.py)
py_proto(model.proto)
add_dependencies(noisicaa.builtin_nodes.control_track.model.proto model-noisicaa.builtin_nodes.control_track)

@ -18,11 +18,9 @@
#
# @end:license
template: "noisicaa/builtin_nodes/model.tmpl.py"
classes {
name: "ControlPoint"
super_class: "noisicaa.music.model.ProjectChild"
super_class: "noisicaa.music.model_base.ProjectChild"
proto_ext_name: "control_point"
properties {
name: "time"

@ -27,7 +27,7 @@ from typing import cast, Any, Dict, Optional, Callable
from noisicaa import core
from noisicaa import audioproc
from noisicaa import node_db
from noisicaa import model_base
from noisicaa import music
from noisicaa.music import node_connector
from . import node_description
from . import processor_messages
@ -60,11 +60,11 @@ class ControlTrackConnector(node_connector.NodeConnector):
super().close()
def __points_list_changed(self, change: model_base.PropertyChange) -> None:
if isinstance(change, model_base.PropertyListInsert):
def __points_list_changed(self, change: music.PropertyChange) -> None:
if isinstance(change, music.PropertyListInsert):
self.__add_point(change.new_value)
elif isinstance(change, model_base.PropertyListDelete):
elif isinstance(change, music.PropertyListDelete):
self.__remove_point(change.old_value)
else:

@ -31,7 +31,7 @@ from PyQt5 import QtGui
from noisicaa.core.typing_extra import down_cast
from noisicaa import audioproc
from noisicaa import core
from noisicaa import model_base
from noisicaa import music
from noisicaa.ui.track_list import base_track_editor
from noisicaa.ui.track_list import time_view_mixin
from noisicaa.ui.track_list import tools
@ -225,13 +225,13 @@ class ControlPoint(object):
listener.remove()
self.__listeners.clear()
def onTimeChanged(self, change: model_base.PropertyValueChange[audioproc.MusicalTime]) -> None:
def onTimeChanged(self, change: music.PropertyValueChange[audioproc.MusicalTime]) -> None:
self.__pos = QtCore.QPoint(
self.__track_editor.timeToX(change.new_value),
self.__pos.y())
self.__track_editor.rectChanged.emit(self.__track_editor.viewRect())
def onValueChanged(self, change: model_base.PropertyValueChange[float]) -> None:
def onValueChanged(self, change: music.PropertyValueChange[float]) -> None:
self.__pos = QtCore.QPoint(
self.__pos.x(),
self.__track_editor.valueToY(change.new_value))
@ -345,12 +345,12 @@ class ControlTrackEditor(time_view_mixin.ContinuousTimeMixin, base_track_editor.
cpoint.close()
self.rectChanged.emit(self.viewRect())
def onPointsChanged(self, change: model_base.PropertyListChange[model.ControlPoint]) -> None:
if isinstance(change, model_base.PropertyListInsert):
def onPointsChanged(self, change: music.PropertyListChange[model.ControlPoint]) -> None:
if isinstance(change, music.PropertyListInsert):
self.addPoint(change.index, change.new_value)
self.updateHighlightedPoint()
elif isinstance(change, model_base.PropertyListDelete):
elif isinstance(change, music.PropertyListDelete):
self.removePoint(change.index, change.old_value)
self.updateHighlightedPoint()

@ -27,7 +27,7 @@ add_python_package(
processor_test.py
)
build_model(model.desc.pb)
build_model(model.desc.pb _model.py noisicaa/builtin_nodes/model.tmpl.py)
py_proto(model.proto)
add_dependencies(noisicaa.builtin_nodes.custom_csound.model.proto model-noisicaa.builtin_nodes.custom_csound)

@ -18,8 +18,6 @@
#
# @end:license
template: "noisicaa/builtin_nodes/model.tmpl.py"
classes {
name: "CustomCSoundPort"
super_class: "noisicaa.music.graph.Port"

@ -27,7 +27,7 @@ from noisicaa.core.typing_extra import down_cast
from noisicaa import core
from noisicaa import node_db
from noisicaa import audioproc
from noisicaa import model_base
from noisicaa import music
from . import node_description
from . import processor_pb2
from . import _model
@ -49,7 +49,7 @@ class CustomCSoundPort(_model.CustomCSoundPort):
def node(self) -> 'CustomCSound':
return down_cast(CustomCSound, self.parent)
def csound_name_prefix(self, *, type: node_db.PortDescription.Type = None) -> str: # pylint: disable=redefined-builtin
def csound_name_prefix(self, *, type: int = None) -> str: # pylint: disable=redefined-builtin
if type is None:
type = self.type
@ -63,7 +63,7 @@ class CustomCSoundPort(_model.CustomCSoundPort):
return ''
def csound_name_default(
self, *, name: str = None, type: node_db.PortDescription.Type = None) -> str: # pylint: disable=redefined-builtin
self, *, name: str = None, type: int = None) -> str: # pylint: disable=redefined-builtin
if name is None:
name = self.name
@ -83,7 +83,7 @@ class CustomCSound(_model.CustomCSound):
self.__listeners = {} # type: Dict[int, core.Listener]
self.__orchestra_preamble = None # type: str
self.orchestra_preamble_changed = core.Callback[model_base.PropertyChange[str]]()
self.orchestra_preamble_changed = core.Callback[music.PropertyChange[str]]()
def create(
self, *,
@ -110,21 +110,21 @@ class CustomCSound(_model.CustomCSound):
self.__add_port(None, port)
self.ports_changed.add(self.__ports_changed)
def __ports_changed(self, change: model_base.PropertyChange) -> None:
if isinstance(change, model_base.PropertyListInsert):
def __ports_changed(self, change: music.PropertyChange) -> None:
if isinstance(change, music.PropertyListInsert):
self.__add_port(change, change.new_value)
elif isinstance(change, model_base.PropertyListDelete):
elif isinstance(change, music.PropertyListDelete):
self.__remove_port(change, change.old_value)
else:
raise TypeError("Unsupported change type %s" % type(change))
self.description_changed.call(change)
def __add_port(self, change: model_base.PropertyChange, port: CustomCSoundPort) -> None:
def __add_port(self, change: music.PropertyChange, port: CustomCSoundPort) -> None:
self.__listeners[port.id] = port.object_changed.add(self.description_changed.call)
self.description_changed.call(change)
def __remove_port(self, change: model_base.PropertyChange, port: CustomCSoundPort) -> None:
def __remove_port(self, change: music.PropertyChange, port: CustomCSoundPort) -> None:
self.__listeners.pop(port.id).remove()
self.description_changed.call(change)
@ -179,7 +179,7 @@ class CustomCSound(_model.CustomCSound):
if preamble != old_preamble:
self.__orchestra_preamble = preamble
self.orchestra_preamble_changed.call(
model_base.PropertyValueChange(self, 'orchestra_preamble', old_preamble, preamble))
music.PropertyValueChange(self, 'orchestra_preamble', old_preamble, preamble))
@property
def description(self) -> node_db.NodeDescription:

@ -29,7 +29,6 @@ from PyQt5 import QtGui
from PyQt5 import QtWidgets
from noisicaa import core
from noisicaa import model_base
from noisicaa import music
from noisicaa import node_db
from noisicaa.ui import object_list_editor
@ -285,11 +284,11 @@ class PortListEditor(ui_base.ProjectMixin, object_list_editor.ObjectListEditor):
self.__ports_listener = self.__node.ports_changed.add(self.__portsChanged)
def __portsChanged(
self, change: model_base.PropertyListChange[model.CustomCSoundPort]) -> None:
if isinstance(change, model_base.PropertyListInsert):
self, change: music.PropertyListChange[model.CustomCSoundPort]) -> None:
if isinstance(change, music.PropertyListInsert):
self.objectAdded(change.new_value, change.index)
elif isinstance(change, model_base.PropertyListDelete):
elif isinstance(change, music.PropertyListDelete):
self.objectRemoved(change.index)
else:
@ -409,11 +408,11 @@ class Editor(ui_base.ProjectMixin, QtWidgets.QDialog):
self.__orchestra_editor.toPlainText() != self.__node.orchestra
or self.__score_editor.toPlainText() != self.__node.score)
def __orchestraChanged(self, change: model_base.PropertyValueChange[str]) -> None:
def __orchestraChanged(self, change: music.PropertyValueChange[str]) -> None:
if change.new_value != self.__orchestra:
logger.error("oops")
def __scoreChanged(self, change: model_base.PropertyValueChange[str]) -> None:
def __scoreChanged(self, change: music.PropertyValueChange[str]) -> None:
if change.new_value != self.__score:
logger.error("oops")

@ -27,7 +27,7 @@ add_python_package(
processor_messages.py
)
build_model(model.desc.pb)
build_model(model.desc.pb _model.py noisicaa/builtin_nodes/model.tmpl.py)
py_proto(model.proto)
add_dependencies(noisicaa.builtin_nodes.instrument.model.proto model-noisicaa.builtin_nodes.instrument)

@ -18,8 +18,6 @@
#
# @end:license
template: "noisicaa/builtin_nodes/model.tmpl.py"
classes {
name: "Instrument"
super_class: "noisicaa.music.graph.BaseNode"

@ -28,7 +28,6 @@ from PyQt5 import QtGui
from PyQt5 import QtWidgets
from noisicaa import core
from noisicaa import model_base
from noisicaa import music
from noisicaa.ui import ui_base
from noisicaa.ui import instrument_library
@ -85,7 +84,7 @@ class InstrumentNodeWidget(ui_base.ProjectMixin, QtWidgets.QScrollArea):
listener.remove()
self.__listeners.clear()
def __instrumentURIChanged(self, change: model_base.PropertyValueChange[str]) -> None:
def __instrumentURIChanged(self, change: music.PropertyValueChange[str]) -> None:
if change.new_value is not None:
self.__instrument.setText(change.new_value)
else:

@ -28,7 +28,7 @@ add_python_package(
processor_messages.py
)
build_model(model.desc.pb)
build_model(model.desc.pb _model.py noisicaa/builtin_nodes/model.tmpl.py)
py_proto(model.proto)
add_dependencies(noisicaa.builtin_nodes.midi_cc_to_cv.model.proto model-noisicaa.builtin_nodes.midi_cc_to_cv)

@ -18,11 +18,9 @@
#
# @end:license
template: "noisicaa/builtin_nodes/model.tmpl.py"
classes {
name: "MidiCCtoCVChannel"
super_class: "noisicaa.music.model.ProjectChild"
super_class: "noisicaa.music.model_base.ProjectChild"
proto_ext_name: "midi_cc_to_cv_channel"
properties {
name: "type"

@ -30,7 +30,6 @@ from PyQt5 import QtGui
from PyQt5 import QtWidgets
from noisicaa import core
from noisicaa import model_base
from noisicaa import music
from noisicaa.ui import ui_base
from noisicaa.ui import control_value_dial
@ -212,7 +211,7 @@ class ChannelUI(ui_base.ProjectMixin, QtCore.QObject):
else:
self.__learnStop()
def __midiChannelChanged(self, change: model_base.PropertyValueChange[int]) -> None:
def __midiChannelChanged(self, change: music.PropertyValueChange[int]) -> None:
self.__midi_channel.setValue(change.new_value + 1)
def __midiChannelEdited(self, value: int) -> None:
@ -221,7 +220,7 @@ class ChannelUI(ui_base.ProjectMixin, QtCore.QObject):
with self.project.apply_mutations('%s: Change MIDI channel' % self.__node.name):
self.__channel.midi_channel = value
def __midiControllerChanged(self, change: model_base.PropertyValueChange[int]) -> None:
def __midiControllerChanged(self, change: music.PropertyValueChange[int]) -> None:
self.__midi_controller.setValue(change.new_value)
def __midiControllerEdited(self, value: int) -> None:
@ -229,7 +228,7 @@ class ChannelUI(ui_base.ProjectMixin, QtCore.QObject):
with self.project.apply_mutations('%s: Change MIDI controller' % self.__node.name):
self.__channel.midi_controller = value
def __minValueChanged(self, change: model_base.PropertyValueChange[float]) -> None:
def __minValueChanged(self, change: music.PropertyValueChange[float]) -> None:
self.__min_value.setText(fmt_value(self.__channel.min_value))
def __minValueEdited(self) -> None:
@ -240,7 +239,7 @@ class ChannelUI(ui_base.ProjectMixin, QtCore.QObject):
with self.project.apply_mutations('%s: Change min. value' % self.__node.name):
self.__channel.min_value = value
def __maxValueChanged(self, change: model_base.PropertyValueChange[float]) -> None:
def __maxValueChanged(self, change: music.PropertyValueChange[float]) -> None:
self.__max_value.setText(fmt_value(self.__channel.max_value))
def __maxValueEdited(self) -> None:
@ -251,7 +250,7 @@ class ChannelUI(ui_base.ProjectMixin, QtCore.QObject):
with self.project.apply_mutations('%s: Change max. value' % self.__node.name):
self.__channel.max_value = value
def __logScaleChanged(self, change: model_base.PropertyValueChange[bool]) -> None:
def __logScaleChanged(self, change: music.PropertyValueChange[bool]) -> None:
self.__log_scale.setChecked(self.__channel.log_scale)
def __logScaleEdited(self, value: bool) -> None:
@ -343,12 +342,12 @@ class MidiCCtoCVNodeWidget(ui_base.ProjectMixin, QtWidgets.QScrollArea):
def __channelsChanged(
self,
change: model_base.PropertyListChange[model.MidiCCtoCVChannel]
change: music.PropertyListChange[model.MidiCCtoCVChannel]
) -> None:
if isinstance(change, model_base.PropertyListInsert):
if isinstance(change, music.PropertyListInsert):
self.__addChannel(change.new_value, change.index)
elif isinstance(change, model_base.PropertyListDelete):
elif isinstance(change, music.PropertyListDelete):
self.__removeChannel(change.index)
else:

@ -27,7 +27,7 @@ add_python_package(
processor_messages.py
)
build_model(model.desc.pb)
build_model(model.desc.pb _model.py noisicaa/builtin_nodes/model.tmpl.py)
py_proto(model.proto)
py_proto(processor_messages.proto)

@ -18,8 +18,6 @@
#
# @end:license
template: "noisicaa/builtin_nodes/model.tmpl.py"
classes {
name: "MidiSource"
super_class: "noisicaa.music.graph.BaseNode"

@ -27,7 +27,6 @@ from PyQt5.QtCore import Qt
from PyQt5 import QtWidgets
from noisicaa import core
from noisicaa import model_base
from noisicaa import value_types
from noisicaa import music
from noisicaa.ui import device_list
@ -99,7 +98,7 @@ class MidiSourceNodeWidget(ui_base.ProjectMixin, QtWidgets.QWidget):
with self.project.apply_mutations('%s: Change device' % self.__node.name):
self.__node.device_uri = uri
def __channelFilterChanged(self, change: model_base.PropertyValueChange[int]) -> None:
def __channelFilterChanged(self, change: music.PropertyValueChange[int]) -> None:
for idx in range(self.__channel_filter.count()):
if self.__channel_filter.itemData(idx) == change.new_value:
self.__channel_filter.setCurrentIndex(idx)

@ -27,7 +27,7 @@
import typing
from noisicaa import core
from noisicaa import model_base
from noisicaa import music
from noisicaa.builtin_nodes import model_registry_pb2
{%- for mod in imports %}
import {{mod}}
@ -42,17 +42,17 @@ if typing.TYPE_CHECKING:
{% for cls in desc.classes %}
class {{cls.name}}({{cls.super_class|join(', ')}}): # pylint: disable=abstract-method
class {{cls.name}}Spec(model_base.ObjectSpec):
class {{cls.name}}Spec(music.ObjectSpec):
proto_type = '{{cls.proto_ext_name}}'
proto_ext = model_registry_pb2.{{cls.proto_ext_name}}
{% for prop in cls.properties %}
{{prop.name}} = model_base.{{prop|prop_cls}}({{prop|prop_cls_type}}{% if prop.HasField("allow_none") %}, allow_none={{prop.allow_none}}{% endif %}{% if prop.HasField("default") %}, default={{prop.default}}{% endif %})
{{prop.name}} = music.{{prop|prop_cls}}({{prop|prop_cls_type}}{% if prop.HasField("allow_none") %}, allow_none={{prop.allow_none}}{% endif %}{% if prop.HasField("default") %}, default={{prop.default}}{% endif %})
{%- endfor %}
def __init__(self, **kwargs: typing.Any) -> None:
super().__init__(**kwargs)
{% for prop in cls.properties %}
self.{{prop.name}}_changed = core.Callback[model_base.{{prop|change_cls}}]()
self.{{prop.name}}_changed = core.Callback[music.{{prop|change_cls}}]()
{%- endfor %}
{% for prop in cls.properties %}

@ -24,7 +24,7 @@ syntax = "proto2";
package noisicaa.pb;
import "noisicaa/model_base/model_base.proto";
import "noisicaa/music/model_base.proto";
import "noisicaa/builtin_nodes/score_track/model.proto";
import "noisicaa/builtin_nodes/beat_track/model.proto";
import "noisicaa/builtin_nodes/control_track/model.proto";

@ -22,7 +22,7 @@
from typing import Dict, Type
from noisicaa import model_base
from noisicaa import music
from noisicaa.music import graph
from .score_track import model as score_track
from .beat_track import model as beat_track
@ -48,7 +48,7 @@ node_cls_map = {
} # type: Dict[str, Type[graph.BaseNode]]
def register_classes(pool: model_base.AbstractPool) -> None:
def register_classes(pool: music.Pool) -> None:
pool.register_class(score_track.Note)
pool.register_class(score_track.ScoreMeasure)
pool.register_class(score_track.ScoreTrack)

@ -29,7 +29,7 @@ add_python_package(
processor_messages.py
)
build_model(model.desc.pb)
build_model(model.desc.pb _model.py noisicaa/builtin_nodes/model.tmpl.py)
py_proto(model.proto)
add_dependencies(noisicaa.builtin_nodes.sample_track.model.proto model-noisicaa.builtin_nodes.sample_track)

@ -18,11 +18,9 @@
#
# @end:license
template: "noisicaa/builtin_nodes/model.tmpl.py"
classes {
name: "SampleRef"
super_class: "noisicaa.music.model.ProjectChild"
super_class: "noisicaa.music.model_base.ProjectChild"
proto_ext_name: "sample_ref"
properties {
name: "time"

@ -27,7 +27,7 @@ from typing import Any, Dict, Optional, Callable
from noisicaa.core.typing_extra import down_cast
from noisicaa import audioproc
from noisicaa import model_base
from noisicaa import music
from noisicaa import core
from noisicaa import node_db
from noisicaa.bindings import sndfile
@ -110,11 +110,11 @@ class SampleTrackConnector(node_connector.NodeConnector):
super().close()
def __samples_list_changed(self, change: model_base.PropertyChange) -> None:
if isinstance(change, model_base.PropertyListInsert):
def __samples_list_changed(self, change: music.PropertyChange) -> None:
if isinstance(change, music.PropertyListInsert):
self.__add_sample(change.new_value)
elif isinstance(change, model_base.PropertyListDelete):
elif isinstance(change, music.PropertyListDelete):
self.__remove_sample(change.old_value)
else: # pragma: no coverage

@ -34,7 +34,7 @@ from PyQt5 import QtWidgets
from noisicaa.core.typing_extra import down_cast
from noisicaa import audioproc
from noisicaa import core
from noisicaa import model_base
from noisicaa import music
from noisicaa.ui.track_list import base_track_editor
from noisicaa.ui.track_list import time_view_mixin
from noisicaa.ui.track_list import tools
@ -183,7 +183,7 @@ class SampleItem(object):
def rect(self) -> QtCore.QRect:
return QtCore.QRect(self.pos(), self.size())
def onTimeChanged(self, change: model_base.PropertyValueChange[audioproc.MusicalTime]) -> None:
def onTimeChanged(self, change: music.PropertyValueChange[audioproc.MusicalTime]) -> None:
self.__pos = QtCore.QPoint(
self.__track_editor.timeToX(change.new_value), 0)
self.__track_editor.rectChanged.emit(self.__track_editor.viewRect())
@ -294,11 +294,11 @@ class SampleTrackEditor(time_view_mixin.ContinuousTimeMixin, base_track_editor.B
super().close()
def onSamplesChanged(self, change: model_base.PropertyListChange[model.SampleRef]) -> None:
if isinstance(change, model_base.PropertyListInsert):
def onSamplesChanged(self, change: music.PropertyListChange[model.SampleRef]) -> None:
if isinstance(change, music.PropertyListInsert):
self.addSample(change.index, change.new_value)
elif isinstance(change, model_base.PropertyListDelete):
elif isinstance(change, music.PropertyListDelete):
self.removeSample(change.index, change.old_value)
else:

@ -27,7 +27,7 @@ add_python_package(
track_ui_test.py
)
build_model(model.desc.pb)
build_model(model.desc.pb _model.py noisicaa/builtin_nodes/model.tmpl.py)
py_proto(model.proto)
add_dependencies(noisicaa.builtin_nodes.score_track.model.proto model-noisicaa.builtin_nodes.score_track)

@ -18,11 +18,9 @@
#
# @end:license
template: "noisicaa/builtin_nodes/model.tmpl.py"
classes {
name: "Note"
super_class: "noisicaa.music.model.ProjectChild"
super_class: "noisicaa.music.model_base.ProjectChild"
proto_ext_name: "note"
properties {
name: "pitches"

@ -29,7 +29,7 @@ from noisicaa import core
from noisicaa import audioproc
from noisicaa import value_types
from noisicaa import node_db
from noisicaa import model_base
from noisicaa import music
from noisicaa.music import base_track
from . import node_description
from . import _model
@ -66,7 +66,7 @@ class ScoreTrackConnector(base_track.MeasuredTrackConnector):
time += note.duration
def __transpose_octaves_changed(self, change: model_base.PropertyChange) -> None:
def __transpose_octaves_changed(self, change: music.PropertyChange) -> None:
self._update_measure_range(0, len(self._node.measure_list))
def __measure_notes_changed(self, mref: base_track.MeasureReference) -> None:
@ -152,7 +152,7 @@ class Note(_model.Note):
duration *= fractions.Fraction(4, 5)
return audioproc.MusicalDuration(duration)
def property_changed(self, change: model_base.PropertyChange) -> None:
def property_changed(self, change: music.PropertyChange) -> None:
super().property_changed(change)
if self.measure is not None:
self.measure.content_changed.call()

@ -29,7 +29,6 @@ from PyQt5 import QtSvg
from PyQt5 import QtWidgets
from noisicaa import core
from noisicaa import model_base
from noisicaa import music
from noisicaa.constants import DATA_DIR
from noisicaa.ui import ui_base
@ -76,7 +75,7 @@ class ScoreTrackWidget(ui_base.ProjectMixin, QtWidgets.QScrollArea):
listener.remove()
self.__listeners.clear()
def onTransposeOctavesChanged(self, change: model_base.PropertyValueChange[int]) -> None:
def onTransposeOctavesChanged(self, change: music.PropertyValueChange[int]) -> None:
self.__transpose_octaves.setValue(change.new_value)
def onTransposeOctavesEdited(self, transpose_octaves: int) -> None:

@ -31,7 +31,7 @@ from PyQt5 import QtSvg
from noisicaa.core.typing_extra import down_cast
from noisicaa import audioproc
from noisicaa import model_base
from noisicaa import music
from noisicaa import value_types
from noisicaa.ui import svg_symbol
from noisicaa.ui.track_list import tools
@ -577,12 +577,12 @@ class ScoreMeasureEditor(measured_track_editor.MeasureEditor):
self.measure_listeners.append(self.measure.key_signature_changed.add(
self.onKeySignatureChanged))
def onClefChanged(self, change: model_base.PropertyValueChange[value_types.Clef]) -> None:
def onClefChanged(self, change: music.PropertyValueChange[value_types.Clef]) -> None:
self.invalidatePaintCache(self.BACKGROUND, self.FOREGROUND)
self.next_sibling.invalidatePaintCache(self.BACKGROUND, self.FOREGROUND)
def onKeySignatureChanged(
self, change: model_base.PropertyValueChange[value_types.KeySignature]) -> None:
self, change: music.PropertyValueChange[value_types.KeySignature]) -> None:
self.invalidatePaintCache(self.BACKGROUND, self.FOREGROUND)
self.next_sibling.invalidatePaintCache(self.BACKGROUND, self.FOREGROUND)

@ -27,7 +27,7 @@ add_python_package(
processor_test.py
)
build_model(model.desc.pb)
build_model(model.desc.pb _model.py noisicaa/builtin_nodes/model.tmpl.py)
py_proto(model.proto)
add_dependencies(noisicaa.builtin_nodes.step_sequencer.model.proto model-noisicaa.builtin_nodes.step_sequencer)

@ -18,11 +18,9 @@
#
# @end:license
template: "noisicaa/builtin_nodes/model.tmpl.py"
classes {
name: "StepSequencerStep"
super_class: "noisicaa.music.model.ProjectChild"
super_class: "noisicaa.music.model_base.ProjectChild"
proto_ext_name: "step_sequencer_step"
properties {
name: "enabled"
@ -40,7 +38,7 @@ classes {
classes {
name: "StepSequencerChannel"
super_class: "noisicaa.music.model.ProjectChild"
super_class: "noisicaa.music.model_base.ProjectChild"
proto_ext_name: "step_sequencer_channel"
properties {
name: "type"

@ -31,7 +31,6 @@ from PyQt5 import QtGui
from PyQt5 import QtWidgets
from noisicaa import core
from noisicaa import model_base
from noisicaa import music
from noisicaa import node_db
from noisicaa.ui import ui_base
@ -360,7 +359,7 @@ class StepSequencerNodeWidget(ui_base.ProjectMixin, QtWidgets.QScrollArea):
for col in range(self.__node.num_steps):
self.__step_layout.setColumnStretch(col + 2, 2)
def __numStepsChanged(self, change: model_base.PropertyValueChange[int]) -> None:
def __numStepsChanged(self, change: music.PropertyValueChange[int]) -> None:
self.__num_steps.setValue(self.__node.num_steps)
self.__updateStepMatrix()
@ -371,7 +370,7 @@ class StepSequencerNodeWidget(ui_base.ProjectMixin, QtWidgets.QScrollArea):
def __numChannelsChanged(
self,
change: model_base.PropertyListChange[model.StepSequencerChannel]
change: music.PropertyListChange[model.StepSequencerChannel]
) -> None:
self.__num_channels.setValue(len(self.__node.channels))
self.__updateStepMatrix()
@ -389,7 +388,7 @@ class StepSequencerNodeWidget(ui_base.ProjectMixin, QtWidgets.QScrollArea):
self,
channel: model.StepSequencerChannel,
widget: QtWidgets.QComboBox,
change: model_base.PropertyValueChange[int]
change: music.PropertyValueChange[int]
) -> None:
self.__updateStepMatrix()
@ -407,7 +406,7 @@ class StepSequencerNodeWidget(ui_base.ProjectMixin, QtWidgets.QScrollArea):
self,
channel: model.StepSequencerChannel,
widget: control_value_dial.ControlValueDial,
change: model_base.PropertyValueChange[float]
change: music.PropertyValueChange[float]
) -> None:
widget.setText(fmt_value(channel.min_value))
@ -428,7 +427,7 @@ class StepSequencerNodeWidget(ui_base.ProjectMixin, QtWidgets.QScrollArea):
self,
channel: model.StepSequencerChannel,
widget: control_value_dial.ControlValueDial,
change: model_base.PropertyValueChange[float]
change: music.PropertyValueChange[float]
) -> None:
widget.setText(fmt_value(channel.max_value))
@ -449,7 +448,7 @@ class StepSequencerNodeWidget(ui_base.ProjectMixin, QtWidgets.QScrollArea):
self,
channel: model.StepSequencerChannel,
widget: control_value_dial.ControlValueDial,
change: model_base.PropertyValueChange[bool]
change: music.PropertyValueChange[bool]
) -> None:
widget.setChecked(channel.log_scale)
@ -483,7 +482,7 @@ class StepSequencerNodeWidget(ui_base.ProjectMixin, QtWidgets.QScrollArea):
self,
step: model.StepSequencerStep,
widget: control_value_dial.ControlValueDial,
change: model_base.PropertyValueChange[float]
change: music.PropertyValueChange[float]
) -> None:
widget.setValue(step.value)
@ -501,7 +500,7 @@ class StepSequencerNodeWidget(ui_base.ProjectMixin, QtWidgets.QScrollArea):
self,
step: model.StepSequencerStep,
widget: StepToggle,
change: model_base.PropertyValueChange[bool]
change: music.PropertyValueChange[bool]
) -> None:
widget.setChecked(step.enabled)

@ -1,27 +0,0 @@
# @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(
model_base.py
model_base_test.py
)
py_proto(model_base.proto)
py_proto(model_base_test.proto)

@ -1,44 +0,0 @@
# @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 .model_base import (
ObjectBase,
ObjectSpec,
PropertyBase,
Property, ListProperty,
ProtoProperty,
WrappedProtoProperty, WrappedProtoListProperty,
ObjectProperty, ObjectReferenceProperty, ObjectListProperty,
Mutation,
ObjectChange,
ObjectAdded,
ObjectRemoved,
PropertyChange,
PropertyValueChange,
PropertyListChange,
PropertyListInsert, PropertyListDelete, PropertyListSet,
AbstractPool, Pool,
)
from .model_base_pb2 import (
ObjectTree,
)

@ -24,7 +24,8 @@ add_python_package(
graph.py
graph_test.py
metadata.py
model.py
model_base.py
model_base_test.py
mutations.py
node_connector.py
player.py
@ -47,7 +48,15 @@ add_python_package(
add_cython_module(rms CXX)
build_model(model.desc.pb _model.py noisicaa/music/model.py)
py_proto(model.proto)
add_dependencies(noisicaa.music.model.proto model-noisicaa.music)
py_proto(project.proto)
add_dependencies(noisicaa.music.project.proto noisicaa.music.model.proto)
py_proto(model_base.proto)
py_proto(model_base_test.proto)
py_proto(writer_process.proto)
py_proto(render.proto)
py_proto(mutations.proto)
add_dependencies(noisicaa.music.mutations.proto noisicaa.music.model.proto)

@ -18,12 +18,30 @@
#
# @end:license
from .project_client import (
ProjectClient,
)
from .model import (
from .model_base import (
ObjectBase,
ObjectSpec,
ProjectChild,
PropertyBase,
Property, ListProperty,
ProtoProperty,
WrappedProtoProperty, WrappedProtoListProperty,
ObjectProperty, ObjectReferenceProperty, ObjectListProperty,
Mutation,
ObjectChange,
ObjectAdded,
ObjectRemoved,
PropertyChange,
PropertyValueChange,
PropertyListChange,
PropertyListInsert, PropertyListDelete, PropertyListSet,
Pool,
)
from .model_base_pb2 import (
ObjectTree,
)
from .metadata import (
Metadata,
@ -55,3 +73,6 @@ from .mutations_pb2 import (
from .session_value_store import (
SessionValueStore,
)
from .project_client import (
ProjectClient,
)

@ -22,79 +22,33 @@
import logging
import random
from typing import cast, Any, Optional, Iterator, Dict, List, Type, MutableSequence
from typing import cast, Any, Optional, Iterator, Dict, List, Type
from noisicaa.core.typing_extra import down_cast
from noisicaa import audioproc
from noisicaa import model_base
from noisicaa import value_types
from noisicaa import core
from noisicaa.builtin_nodes.pianoroll import processor_messages as pianoroll
from . import model
from . import model_pb2
from . import model_base
from . import _model
from . import node_connector
from . import graph
logger = logging.getLogger(__name__)
class Track(graph.BaseNode): # pylint: disable=abstract-method
class TrackSpec(model_base.ObjectSpec):
proto_ext = model_pb2.track
visible = model_base.Property(bool, default=True)
list_position = model_base.Property(int, default=0)
class Track(_model.Track, graph.BaseNode): # pylint: disable=abstract-method
def __init__(self, **kwargs: Any) -> None:
super().__init__(**kwargs)
self.visible_changed = core.Callback[model_base.PropertyChange[bool]]()
self.list_position_changed = core.Callback[model_base.PropertyChange[int]]()
self.duration_changed = core.Callback[None]()
@property
def visible(self) -> bool:
return self.get_property_value('visible')
@visible.setter
def visible(self, value: bool) -> None:
self.set_property_value('visible', value)
@property
def list_position(self) -> int:
return self.get_property_value('list_position')
@list_position.setter
def list_position(self, value: int) -> None:
self.set_property_value('list_position', value)
@property
def duration(self) -> audioproc.MusicalDuration:
return audioproc.MusicalDuration(1, 1)
class Measure(model.ProjectChild):
class MeasureSpec(model_base.ObjectSpec):
proto_ext = model_pb2.measure
time_signature = model_base.WrappedProtoProperty(
value_types.TimeSignature,
default=value_types.TimeSignature(4, 4))
def __init__(self, **kwargs: Any) -> None:
super().__init__(**kwargs)
self.time_signature_changed = \
core.Callback[model_base.PropertyChange[value_types.TimeSignature]]()
@property
def time_signature(self) -> value_types.TimeSignature:
return self.get_property_value('time_signature')
@time_signature.setter
def time_signature(self, value: value_types.TimeSignature) -> None:
self.set_property_value('time_signature', value)
class Measure(_model.Measure, model_base.ProjectChild):
@property
def track(self) -> 'MeasuredTrack':
return cast(MeasuredTrack, self.parent)
@ -109,31 +63,12 @@ class Measure(model.ProjectChild):
return False
class MeasureReference(model.ProjectChild):
class MeasureReferenceSpec(model_base.ObjectSpec):
proto_type = 'measure_reference'