def run(self): env = self.state.document.settings.env if not hasattr(env, 'file_projects_patterns'): env.file_projects_patterns = defaultdict(project_patterns_map) src_path = self.state.document['source'] varname, = self.arguments projname, patname = varname.split('.') p = env.file_projects[src_path] project = p[projname] pm = env.file_projects_modules[src_path] pp = env.file_projects_patterns[src_path] if patname == '*': # Register all project's patterns. for pat_idx, pat in enumerate(project.patterns): if pat is not None and not isinstance(pat, PatternClone): patname = (pat.name or 'pat_{}'.format(pat_idx)) patname = patname.replace(' ', '_') pp[patname] = pat else: mods = pm[projname] pat = Pattern() pat.x, pat.y = self.pattern_pos(self.options['pos']) modmap = dict(self.module_map(self.options['map'], mods)) self.write_pattern(pat, self.content, modmap) project += pat pp[patname] = pat return []
def test_note_belongs_to_project_of_pattern(): empty_pattern = Pattern(tracks=1, lines=4) note = empty_pattern.data[0][0] assert note.project is None project = Project() project.attach_pattern(empty_pattern) assert note.project is project
def test_pattern_cannot_be_attached_to_multiple_projects(): empty_pattern = Pattern(tracks=1, lines=4) project = Project() project.attach_pattern(empty_pattern) project2 = Project() with pytest.raises(PatternOwnershipError): project2.attach_pattern(empty_pattern)
def flatten(self): mods = sorted(list(self.keys())) index = [(mod, i) for mod in mods for i in range(self[mod].polyphony)] pat = Pattern(lines=self.lines, tracks=len(index)) def notefn(track, i, j): mod, k = index[j] notes = self[mod][i] if k < len(notes): note = notes[k].clone() if note.module: note.module += 1 # NB return note else: return Note() pat.set_via_fn(notefn) return pat
def project_from_timeline(timeline: Timeline) -> Project: """Render a Timeline to a SunVox project.""" project = Project() # 120 BPM, 48 ticks per quarter note project.initial_bpm = 120 * 2 project.initial_tpl = 1 voice_modules = dict((voice, voice.sunvox_module()) for voice in set( part.voice for part in timeline.parts)) modules = list(voice_modules.values()) project += modules project.output << modules for placed_phrase in timeline: p = placed_phrase.phrase ticks = p.ticks for i, part in enumerate(p.parts): pattern = Pattern( tracks=16, x=placed_phrase.x, y=placed_phrase.y + i * 10, lines=ticks, ) project += pattern reserved = set() module = voice_modules[part.voice] mm = module.index + 1 for placed_note in p: if placed_note.part is part: start_tick = p.placed_note_on_tick(placed_note) stop_tick = p.placed_note_off_tick(placed_note) for nn in placed_note.notes: track = 0 while (start_tick, track) in reserved: track += 1 assert track < 16, \ f'Track overflow at {start_tick}' cell = pattern.data[start_tick][track] if nn.pitch.sp_value is not None: cell.note = SET_PITCH cell.val = nn.pitch.sp_value else: cell.note = nn.pitch.sunvox_note cell.module = mm for tick in range(start_tick, stop_tick + 1): if tick < ticks: reserved.add((tick, track)) if stop_tick < ticks: cell = pattern.data[stop_tick][track] cell.note = NOTE_OFF return project
def test_note_mod_property(): project = Project() pattern = Pattern(tracks=1, lines=4) project.attach_pattern(pattern) note = pattern.data[0][0] assert note.module == 0 assert note.module_index is None assert note.mod is None mod: m.Generator = project.new_module(m.Generator) note.mod = mod assert note.mod is mod assert note.module_index == mod.index assert note.module == mod.index + 1 note.module = 5 assert note.mod is None assert note.module_index == 4
def test_pattern_starts_with_no_project(): empty_pattern = Pattern(tracks=1, lines=4) assert empty_pattern.project is None
def test_note_belongs_to_pattern(): empty_pattern = Pattern(tracks=1, lines=4) note = empty_pattern.data[0][0] assert note.pattern is empty_pattern
def test_pattern_project_is_set_after_attaching(): empty_pattern = Pattern(tracks=1, lines=4) project = Project() project.attach_pattern(empty_pattern) assert empty_pattern.project is project