|
|
|
@ -24,6 +24,7 @@ import base64
|
|
|
|
|
import email.parser
|
|
|
|
|
import email.policy
|
|
|
|
|
import email.message
|
|
|
|
|
import itertools
|
|
|
|
|
import logging
|
|
|
|
|
import os.path
|
|
|
|
|
import time
|
|
|
|
@ -38,129 +39,340 @@ from .clef import Clef
|
|
|
|
|
from .key_signature import KeySignature
|
|
|
|
|
from .time_signature import TimeSignature
|
|
|
|
|
from .time import Duration
|
|
|
|
|
from . import base_track
|
|
|
|
|
from . import beat_track
|
|
|
|
|
from . import score_track
|
|
|
|
|
from . import sample_track
|
|
|
|
|
from . import commands
|
|
|
|
|
from . import control_track
|
|
|
|
|
from . import pipeline_graph
|
|
|
|
|
from . import misc
|
|
|
|
|
from . import model
|
|
|
|
|
from . import mutations
|
|
|
|
|
from . import pipeline_graph
|
|
|
|
|
from . import property_track
|
|
|
|
|
from . import sample_track
|
|
|
|
|
from . import score_track
|
|
|
|
|
from . import state
|
|
|
|
|
from . import commands
|
|
|
|
|
from . import sheet
|
|
|
|
|
from . import misc
|
|
|
|
|
from . import track_group
|
|
|
|
|
|
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class AddSheet(commands.Command):
|
|
|
|
|
name = core.Property(str, allow_none=True)
|
|
|
|
|
class UpdateProjectProperties(commands.Command):
|
|
|
|
|
bpm = core.Property(int, allow_none=True)
|
|
|
|
|
|
|
|
|
|
def __init__(self, bpm=None, state=None):
|
|
|
|
|
super().__init__(state=state)
|
|
|
|
|
if state is None:
|
|
|
|
|
self.bpm = bpm
|
|
|
|
|
|
|
|
|
|
def run(self, project):
|
|
|
|
|
assert isinstance(project, BaseProject)
|
|
|
|
|
|
|
|
|
|
if self.bpm is not None:
|
|
|
|
|
project.bpm = self.bpm
|
|
|
|
|
|
|
|
|
|
commands.Command.register_command(UpdateProjectProperties)
|
|
|
|
|
|
|
|
|
|
def __init__(self, name=None, state=None):
|
|
|
|
|
|
|
|
|
|
class AddTrack(commands.Command):
|
|
|
|
|
track_type = core.Property(str)
|
|
|
|
|
parent_group_id = core.Property(str)
|
|
|
|
|
insert_index = core.Property(int)
|
|
|
|
|
|
|
|
|
|
def __init__(self, track_type=None, parent_group_id=None, insert_index=-1, state=None):
|
|
|
|
|
super().__init__(state=state)
|
|
|
|
|
if state is None:
|
|
|
|
|
self.name = name
|
|
|
|
|
self.track_type = track_type
|
|
|
|
|
self.parent_group_id = parent_group_id
|
|
|
|
|
self.insert_index = insert_index
|
|
|
|
|
|
|
|
|
|
def run(self, project):
|
|
|
|
|
assert isinstance(project, BaseProject)
|
|
|
|
|
|
|
|
|
|
if self.name is not None:
|
|
|
|
|
name = self.name
|
|
|
|
|
parent_group = project.get_object(self.parent_group_id)
|
|
|
|
|
assert parent_group.is_child_of(project)
|
|
|
|
|
assert isinstance(parent_group, track_group.TrackGroup)
|
|
|
|
|
|
|
|
|
|
if self.insert_index == -1:
|
|
|
|
|
insert_index = len(parent_group.tracks)
|
|
|
|
|
else:
|
|
|
|
|
idx = 1
|
|
|
|
|
while True:
|
|
|
|
|
name = 'Sheet %d' % idx
|
|
|
|
|
if name not in [sheet.name for sheet in project.sheets]:
|
|
|
|
|
break
|
|
|
|
|
idx += 1
|
|
|
|
|
insert_index = self.insert_index
|
|
|
|
|
assert 0 <= insert_index <= len(parent_group.tracks)
|
|
|
|
|
|
|
|
|
|
track_name = "Track %d" % (len(parent_group.tracks) + 1)
|
|
|
|
|
track_cls_map = {
|
|
|
|
|
'score': score_track.ScoreTrack,
|
|
|
|
|
'beat': beat_track.BeatTrack,
|
|
|
|
|
'control': control_track.ControlTrack,
|
|
|
|
|
'sample': sample_track.SampleTrack,
|
|
|
|
|
'group': track_group.TrackGroup,
|
|
|
|
|
}
|
|
|
|
|
track_cls = track_cls_map[self.track_type]
|
|
|
|
|
|
|
|
|
|
kwargs = {}
|
|
|
|
|
if issubclass(track_cls, model.MeasuredTrack):
|
|
|
|
|
num_measures = 1
|
|
|
|
|
for track in parent_group.walk_tracks():
|
|
|
|
|
if isinstance(track, model.MeasuredTrack):
|
|
|
|
|
num_measures = max(num_measures, len(track.measure_list))
|
|
|
|
|
kwargs['num_measures'] = num_measures
|
|
|
|
|
|
|
|
|
|
track = track_cls(name=track_name, **kwargs)
|
|
|
|
|
|
|
|
|
|
if name in [s.name for s in project.sheets]:
|
|
|
|
|
raise ValueError("Sheet %s already exists" % name)
|
|
|
|
|
s = sheet.Sheet(name)
|
|
|
|
|
project.add_sheet(s)
|
|
|
|
|
project.add_track(parent_group, insert_index, track)
|
|
|
|
|
|
|
|
|
|
commands.Command.register_command(AddSheet)
|
|
|
|
|
return insert_index
|
|
|
|
|
|
|
|
|
|
commands.Command.register_command(AddTrack)
|
|
|
|
|
|
|
|
|
|
class ClearSheet(commands.Command):
|
|
|
|
|
name = core.Property(str)
|
|
|
|
|
|
|
|
|
|
def __init__(self, name=None, state=None):
|
|
|
|
|
class RemoveTrack(commands.Command):
|
|
|
|
|
track_id = core.Property(str)
|
|
|
|
|
|
|
|
|
|
def __init__(self, track_id=None, state=None):
|
|
|
|
|
super().__init__(state=state)
|
|
|
|
|
if state is None:
|
|
|
|
|
self.name = name
|
|
|
|
|
self.track_id = track_id
|
|
|
|
|
|
|
|
|
|
def run(self, project):
|
|
|
|
|
assert isinstance(project, BaseProject)
|
|
|
|
|
|
|
|
|
|
project.get_sheet(self.name).clear()
|
|
|
|
|
track = project.get_object(self.track_id)
|
|
|
|
|
assert track.is_child_of(project)
|
|
|
|
|
parent_group = track.parent
|
|
|
|
|
|
|
|
|
|
project.remove_track(parent_group, track)
|
|
|
|
|
|
|
|
|
|
commands.Command.register_command(ClearSheet)
|
|
|
|
|
commands.Command.register_command(RemoveTrack)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class DeleteSheet(commands.Command):
|
|
|
|
|
name = core.Property(str)
|
|
|
|
|
class InsertMeasure(commands.Command):
|
|
|
|
|
tracks = core.ListProperty(str)
|
|
|
|
|
pos = core.Property(int)
|
|
|
|
|
|
|
|
|
|
def __init__(self, name=None, state=None):
|
|
|
|
|
def __init__(self, tracks=None, pos=None, state=None):
|
|
|
|
|
super().__init__(state=state)
|
|
|
|
|
if state is None:
|
|
|
|
|
self.name = name
|
|
|
|
|
self.tracks.extend(tracks)
|
|
|
|
|
self.pos = pos
|
|
|
|
|
|
|
|
|
|
def run(self, project):
|
|
|
|
|
assert isinstance(project, BaseProject)
|
|
|
|
|
|
|
|
|
|
assert len(project.sheets) > 1
|
|
|
|
|
for idx, sheet in enumerate(project.sheets):
|
|
|
|
|
if sheet.name == self.name:
|
|
|
|
|
sheet.remove_from_pipeline()
|
|
|
|
|
del project.sheets[idx]
|
|
|
|
|
project.current_sheet = min(
|
|
|
|
|
project.current_sheet, len(project.sheets) - 1)
|
|
|
|
|
return
|
|
|
|
|
if not self.tracks:
|
|
|
|
|
project.property_track.insert_measure(self.pos)
|
|
|
|
|
else:
|
|
|
|
|
project.property_track.append_measure()
|
|
|
|
|
|
|
|
|
|
raise ValueError("No sheet %r" % self.name)
|
|
|
|
|
for track in project.master_group.walk_tracks():
|
|
|
|
|
if not isinstance(track, model.MeasuredTrack):
|
|
|
|
|
continue
|
|
|
|
|
|
|
|
|
|
commands.Command.register_command(DeleteSheet)
|
|
|
|
|
if not self.tracks or track.id in self.tracks:
|
|
|
|
|
track.insert_measure(self.pos)
|
|
|
|
|
else:
|
|
|
|
|
track.append_measure()
|
|
|
|
|
|
|
|
|
|
commands.Command.register_command(InsertMeasure)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class RenameSheet(commands.Command):
|
|
|
|
|
name = core.Property(str)
|
|
|
|
|
new_name = core.Property(str)
|
|
|
|
|
class RemoveMeasure(commands.Command):
|
|
|
|
|
tracks = core.ListProperty(int)
|
|
|
|
|
pos = core.Property(int)
|
|
|
|
|
|
|
|
|
|
def __init__(self, name=None, new_name=None, state=None):
|
|
|
|
|
def __init__(self, tracks=None, pos=None, state=None):
|
|
|
|
|
super().__init__(state=state)
|
|
|
|
|
if state is None:
|
|
|
|
|
self.name = name
|
|
|
|
|
self.new_name = new_name
|
|
|
|
|
self.tracks.extend(tracks)
|
|
|
|
|
self.pos = pos
|
|
|
|
|
|
|
|
|
|
def run(self, project):
|
|
|
|
|
assert isinstance(project, BaseProject)
|
|
|
|
|
|
|
|
|
|
if self.name == self.new_name:
|
|
|
|
|
return
|
|
|
|
|
if not self.tracks:
|
|
|
|
|
project.property_track.remove_measure(self.pos)
|
|
|
|
|
|
|
|
|
|
for idx, track in enumerate(project.master_group.tracks):
|
|
|
|
|
if not self.tracks or idx in self.tracks:
|
|
|
|
|
track.remove_measure(self.pos)
|
|
|
|
|
if self.tracks:
|
|
|
|
|
track.append_measure()
|
|
|
|
|
|
|
|
|
|
commands.Command.register_command(RemoveMeasure)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ClearMeasures(commands.Command):
|
|
|
|
|
measure_ids = core.ListProperty(str)
|
|
|
|
|
|
|
|
|
|
def __init__(self, measure_ids=None, state=None):
|
|
|
|
|
super().__init__(state=state)
|
|
|
|
|
if state is None:
|
|
|
|
|
self.measure_ids.extend(measure_ids)
|
|
|
|
|
|
|
|
|
|
def run(self, project):
|
|
|
|
|
assert isinstance(project, BaseProject)
|
|
|
|
|
|
|
|
|
|
measure_references = [project.get_object(obj_id) for obj_id in self.measure_ids]
|
|
|
|
|
assert all(isinstance(obj, base_track.MeasureReference) for obj in measure_references)
|
|
|
|
|
|
|
|
|
|
if self.new_name in [s.name for s in project.sheets]:
|
|
|
|
|
raise ValueError("Sheet %s already exists" % self.new_name)
|
|
|
|
|
affected_track_ids = set(obj.track.id for obj in measure_references)
|
|
|
|
|
|
|
|
|
|
sheet = project.get_sheet(self.name)
|
|
|
|
|
sheet.name = self.new_name
|
|
|
|
|
for mref in measure_references:
|
|
|
|
|
track = mref.track
|
|
|
|
|
measure = track.create_empty_measure(mref.measure)
|
|
|
|
|
track.measure_heap.append(measure)
|
|
|
|
|
mref.measure_id = measure.id
|
|
|
|
|
|
|
|
|
|
commands.Command.register_command(RenameSheet)
|
|
|
|
|
for track_id in affected_track_ids:
|
|
|
|
|
project.get_object(track_id).garbage_collect_measures()
|
|
|
|
|
|
|
|
|
|
commands.Command.register_command(ClearMeasures)
|
|
|
|
|
|
|
|
|
|
class SetCurrentSheet(commands.Command):
|
|
|
|
|
name = core.Property(str)
|
|
|
|
|
|
|
|
|
|
def __init__(self, name=None, state=None):
|
|
|
|
|
class PasteMeasures(commands.Command):
|
|
|
|
|
mode = core.Property(str)
|
|
|
|
|
src_objs = core.ListProperty(bytes)
|
|
|
|
|
target_ids = core.ListProperty(str)
|
|
|
|
|
|
|
|
|
|
def __init__(self, mode=None, src_objs=None, target_ids=None, state=None):
|
|
|
|
|
super().__init__(state=state)
|
|
|
|
|
if state is None:
|
|
|
|
|
self.name = name
|
|
|
|
|
self.mode = mode
|
|
|
|
|
self.src_objs.extend(src_objs)
|
|
|
|
|
self.target_ids.extend(target_ids)
|
|
|
|
|
|
|
|
|
|
def run(self, project):
|
|
|
|
|
assert isinstance(project, BaseProject)
|
|
|
|
|
|
|
|
|
|
project.current_sheet = project.get_sheet_index(self.name)
|
|
|
|
|
src_measures = [project.deserialize_object(obj) for obj in self.src_objs]
|
|
|
|
|
assert all(isinstance(obj, base_track.Measure) for obj in src_measures)
|
|
|
|
|
|
|
|
|
|
target_measures = [project.get_object(obj_id) for obj_id in self.target_ids]
|
|
|
|
|
assert all(isinstance(obj, base_track.MeasureReference) for obj in target_measures)
|
|
|
|
|
|
|
|
|
|
affected_track_ids = set(obj.track.id for obj in target_measures)
|
|
|
|
|
assert len(affected_track_ids) == 1
|
|
|
|
|
|
|
|
|
|
if self.mode == 'link':
|
|
|
|
|
for target, src in zip(target_measures, itertools.cycle(src_measures)):
|
|
|
|
|
assert(any(src.id == m.id for m in target.track.measure_heap))
|
|
|
|
|
target.measure_id = src.id
|
|
|
|
|
|
|
|
|
|
commands.Command.register_command(SetCurrentSheet)
|
|
|
|
|
elif self.mode == 'overwrite':
|
|
|
|
|
measure_map = {}
|
|
|
|
|
for target, src in zip(target_measures, itertools.cycle(src_measures)):
|
|
|
|
|
try:
|
|
|
|
|
measure = measure_map[src.id]
|
|
|
|
|
except KeyError:
|
|
|
|
|
measure = measure_map[src.id] = src.clone()
|
|
|
|
|
target.track.measure_heap.append(measure)
|
|
|
|
|
|
|
|
|
|
target.measure_id = measure.id
|
|
|
|
|
|
|
|
|
|
else:
|
|
|
|
|
raise ValueError(mode)
|
|
|
|
|
|
|
|
|
|
for track_id in affected_track_ids:
|
|
|
|
|
project.get_object(track_id).garbage_collect_measures()
|
|
|
|
|
|
|
|
|
|
commands.Command.register_command(PasteMeasures)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class AddPipelineGraphNode(commands.Command):
|
|
|
|
|
uri = core.Property(str)
|
|
|
|
|
graph_pos = core.Property(misc.Pos2F)
|
|
|
|
|
|
|
|
|
|
def __init__(self, uri=None, graph_pos=None, state=None):
|
|
|
|
|
super().__init__(state=state)
|
|
|
|
|
if state is None:
|
|
|
|
|
self.uri = uri
|
|
|
|
|
self.graph_pos = graph_pos
|
|
|
|
|
|
|
|
|
|
def run(self, project):
|
|
|
|
|
assert isinstance(project, BaseProject)
|
|
|
|
|
|
|
|
|
|
node_desc = project.project.get_node_description(self.uri)
|
|
|
|
|
|
|
|
|
|
node = pipeline_graph.PipelineGraphNode(
|
|
|
|
|
name=node_desc.display_name,
|
|
|
|
|
node_uri=self.uri,
|
|
|
|
|
graph_pos=self.graph_pos)
|
|
|
|
|
project.add_pipeline_graph_node(node)
|
|
|
|
|
return node.id
|
|
|
|
|
|
|
|
|
|
commands.Command.register_command(AddPipelineGraphNode)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class RemovePipelineGraphNode(commands.Command):
|
|
|
|
|
node_id = core.Property(str)
|
|
|
|
|
|
|
|
|
|
def __init__(self, node_id=None, state=None):
|
|
|
|
|
super().__init__(state=state)
|
|
|
|
|
if state is None:
|
|
|
|
|
self.node_id = node_id
|
<