Skip to content

Commit

Permalink
feature parity: basic track, clip and note operations
Browse files Browse the repository at this point in the history
  • Loading branch information
andantei committed Feb 22, 2023
1 parent 273482c commit 52dedc3
Show file tree
Hide file tree
Showing 20 changed files with 3,433 additions and 52 deletions.
3 changes: 3 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,6 @@ exclude = ["**/__pycache__", "src/experimental", "src/typestubs"]

reportTypedDictNotRequiredAccess = "warning"
reportGeneralTypeIssues = "warning"

[tool.autopep8]
max_line_length = 120
2 changes: 1 addition & 1 deletion scripts/test.sh
Original file line number Diff line number Diff line change
@@ -1 +1 @@
pytest --doctest-modules --junitxml=junit/test-results.xml --cov=src --cov-report=xml
pytest --doctest-modules --junitxml=junit/test-results.xml --cov=src --cov-report=xml --cov-report=html
1 change: 1 addition & 0 deletions src/tuneflow_py/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from __future__ import annotations
from tuneflow_py.base_plugin import TuneflowPlugin, ReadAPIs
from tuneflow_py.models.audio_plugin import AudioPlugin, get_audio_plugin_tuneflow_id, are_tuneflow_ids_equal, are_tuneflow_ids_equal_ignore_version, decode_audio_plugin_tuneflow_id
from tuneflow_py.models.automation import AutomationTarget, AutomationTargetType
from tuneflow_py.models.clip import ClipType, Clip
from tuneflow_py.models.note import Note
Expand Down
2 changes: 1 addition & 1 deletion src/tuneflow_py/base_plugin.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from tuneflow_py.descriptors.text import LabelText
from tuneflow_py.descriptors.common import PluginInfo
from tuneflow_py.descriptors.param import ParamDescriptor
from tuneflow_py.descriptors.audio_plugin import AudioPluginDescriptor
from tuneflow_py.descriptors.audio_plugin_descriptor import AudioPluginDescriptor
from typing import Optional, Any, List, Dict
from tuneflow_py.models.song import Song

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
from typing_extensions import TypedDict


class AudioPluginDescriptor(TypedDict, total=False):
'''
Descriptor of an audio plugin.
'''

category: str
'''
Category of the plugin.
Expand Down
2 changes: 1 addition & 1 deletion src/tuneflow_py/descriptors/param.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ class ParamDescriptor(TypedDict, total=False):
''' Whether this param is hidden completely. '''

optional: Optional[bool]
''' Whether this param can be left undefined or null. '''
''' Whether this param can be left None. '''

description: Optional[LabelText]
''' Explaining what this parameter is for. '''
Expand Down
84 changes: 84 additions & 0 deletions src/tuneflow_py/models/audio_plugin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
from __future__ import annotations
from tuneflow_py.models.protos import song_pb2
from tuneflow_py.utils import get_audio_plugin_tuneflow_id, are_tuneflow_ids_equal, are_tuneflow_ids_equal_ignore_version, decode_audio_plugin_tuneflow_id
from nanoid import generate as generate_nanoid


class AudioPlugin:
def __init__(self,
name: str | None = None,
manufacturer_name: str | None = None,
plugin_format_name: str | None = None,
plugin_version: str | None = None,
proto: song_pb2.AudioPluginInfo | None = None
):
'''
DO NOT call the constructor directly, use Track.create_audio_plugin(tf_id: str) instead.
'''
if proto is not None:
self._proto = proto
else:
self._proto = song_pb2.AudioPluginInfo()
self._proto.tf_id = get_audio_plugin_tuneflow_id(
manufacturer_name=manufacturer_name, plugin_format_name=plugin_format_name, plugin_name=name,
plugin_version=plugin_version)
self._proto.is_enabled = True
self._proto.local_instance_id = AudioPlugin._generate_audio_plugin_instance_id()

def get_tuneflow_id(self):
'''
A unique id that TuneFlow uses to identify the type of plugin
'''
return self._proto.tf_id

def matches_tf_id(self, tf_id: str):
'''
Exactly matches the plugin type specified by the tf_id.
'''
return are_tuneflow_ids_equal(tf_id, self.get_tuneflow_id())

def matches_tf_id_ignore_version(self, tf_id: str):
'''
Similar to matches_tf_id but does not check version.
'''
return are_tuneflow_ids_equal_ignore_version(tf_id, self.get_tuneflow_id())

def get_instance_id(self):
'''
A unique id to identify the plugin instance.
'''
return self._proto.local_instance_id

def to_json(self):
audio_plugin_info = decode_audio_plugin_tuneflow_id(self.get_tuneflow_id())
return {
"name": audio_plugin_info["name"],
"manufacturer_name": audio_plugin_info["manufacturer_name"],
"plugin_format_name": audio_plugin_info["plugin_format_name"],
"plugin_version": audio_plugin_info["plugin_version"],
"is_enabled": self._proto.is_enabled,
}

def set_is_enabled(self, is_enabled: bool):
self._proto.is_enabled = is_enabled

def get_is_enabled(self):
return self._proto.is_enabled

def set_base64_states(self, base64_states: str | None = None):
if base64_states is None:
self._proto.ClearField("base64_states")
else:
self._proto.base64_states = base64_states

def get_base64_states(self):
return self._proto.base64_states

def __repr__(self) -> str:
return str(self._proto)

@staticmethod
def _generate_audio_plugin_instance_id():
return generate_nanoid(size=10)

DEFAULT_SYNTH_TFID = get_audio_plugin_tuneflow_id('TuneFlow', 'VST3', 'TFSynth', '1.0.0')
18 changes: 13 additions & 5 deletions src/tuneflow_py/models/automation.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@


class AutomationTarget:
def __init__(self, type: AutomationTargetType | None = None, plugin_instance_id: str | None = None, param_id: str | None = None, proto: song_pb2.AutomationTarget | None = None) -> None:
def __init__(
self, type: AutomationTargetType | None = None, plugin_instance_id: str | None = None, param_id: str | None = None,
proto: song_pb2.AutomationTarget | None = None) -> None:
if proto is not None:
self._proto = proto
else:
Expand All @@ -23,7 +25,7 @@ def get_plugin_instance_id(self):

def set_plugin_instance_id(self, plugin_instance_id: str | None = None):
if plugin_instance_id is None:
del self._proto.audio_plugin_id
self._proto.ClearField("audio_plugin_id")
else:
self._proto.audio_plugin_id = plugin_instance_id

Expand All @@ -32,15 +34,21 @@ def get_param_id(self):

def set_param_id(self, param_id: str | None = None):
if param_id is None:
del self._proto.param_id
self._proto.ClearField("param_id")
else:
self._proto.param_id = param_id

def to_tf_automation_target_id(self):
'''
Gets a unique id that identifies this target type.
Gets a unique string id that identifies this target type.
'''
return AutomationTarget.encode_automation_target(self.get_type(), self.get_plugin_instance_id(), self.get_param_id())
return AutomationTarget.encode_automation_target(
self.get_type(),
self.get_plugin_instance_id(),
self.get_param_id())

def __repr__(self) -> str:
return str(self._proto)

@staticmethod
def encode_automation_target(
Expand Down
Loading

0 comments on commit 52dedc3

Please sign in to comment.