def exec(self, symbols_scope: SymbolsScope, context: Context, *args, **kargs): forked = context.fork(symbols=symbols_scope.fork()) forked.symbols.assign('__callerctx__', context, local=True) for variable_name in self.using: forked.symbols.using(variable_name) for i in range(len(self.arguments)): (name, arg_mod, default_value) = self.arguments[i] argument_node, default_node = None, default_value if len(args) > i: argument_node = args[i] elif name in kargs: argument_node = kargs[name] elif default_value == None: raise Exception(f"Mandatory argument { name } was not given.") if arg_mod == 'expr': forked.symbols.assign(name, argument_node) elif (arg_mod == 'ref' or arg_mod == 'in') and argument_node is not None: is_variable = isinstance(argument_node, VariableExpressionNode) if arg_mod == 'ref' and not is_variable: raise BaseException( f"Only variable references can be passed to a function (function { self.name }, parameter { name })" ) # TODO: Should ref pointers be shallow? Since ref can mutate # the value, it could be sensible for them to be so if is_variable: pointer = context.symbols.pointer(argument_node.name) if pointer is None: context.symbols.assign(argument_node.name, None) else: forked.symbols.using(pointer, name) else: forked.symbols.assign( name, Value.assignment(argument_node.eval(context.fork()))) else: if argument_node is not None: value = Value.assignment(argument_node.eval( context.fork())) else: value = Value.assignment(default_node.eval(forked.fork())) value = forked.symbols.assign(name, value) return self.body.eval(forked)
def values(self, context: Context): condition_value = self.condition.eval(context) while condition_value: forked = context.fork(symbols=context.symbols.fork(opaque=False)) yield self.body.eval(forked) context.join(forked) condition_value = self.condition.eval(context)
def __eval__(self, context: Context): forked = context.fork(symbols=context.symbols.fork( opaque=False)) if self.fork_context else context try: if self.create_stack_frame: return self.body.eval(forked) else: return self.body.child.eval(forked) finally: context.join(forked)
def __eval__(self, context: Context, assignment: bool = False): if self.expression is None: return None forked = context.fork() value = self.expression.eval(forked) if isinstance(value, Music): return Music(self.get_events(context, forked, value)) else: context.join(forked) return value
def modify(self, context: Context): if self.upper != None or self.lower != None: context.voice = context.voice.clone(time_signature=(self.upper, self.lower)) elif self.upper != None: context.voice = context.voice.clone( time_signature=(self.upper, context.time_signature[1])) elif self.lower != None: context.voice = context.voice.clone( time_signature=(context.time_signature[0], self.lower)) yield ContextChangeEvent(context.cursor, "timeSignature", context.voice.time_signature, context.voice, 0)
def function_to_mkl(context: Context, music: Music, ast: bool = False, nameless_voices: bool = True, declare_voices: bool = True, base_voice: Voice = None) -> Union[str, Node]: source: Box[str] = Box("") inp, out = Transformer.pipeline2( VoiceIdentifierTransformer(), MusiklaNotationBuilderTransformer(only_final=True, ast=ast, context=context, nameless_voices=nameless_voices, declare_voices=declare_voices, base_voice=base_voice), ) out.subscribe(lambda s: source.set(s)) for ev in music.expand(context.fork(cursor=0)): inp.add_input(ev) inp.end_input() return source.value
def function_save(context: Context, music: Music, outputs: Union[str, Sequencer, List[SequencerLike]]) -> Any: # The single parameter specifies if only one sequencer was given # In that case, instead of returning an array, we return just the sequencer single: bool = False if type(outputs) is str or isinstance(outputs, Sequencer): sequencers: List[Sequencer] = [ function_make_sequencer(context, outputs) ] single = True else: sequencers: List[Sequencer] = [ function_make_sequencer(context, seq) for seq in outputs ] for seq in sequencers: seq.realtime = False seq.start() for ev in music.expand(context.fork(cursor=0)): for seq in sequencers: seq.register_event(ev) for seq in sequencers: seq.close() if single: return sequencers[0] return sequencers
def modify(self, context: Context): context.voice = context.voice.clone( instrument=Instrument.from_program(self.instrument)) yield ContextChangeEvent(context.cursor, "instrument", context.voice.instrument.program, context.voice, 0)
def function_make_sequencer(context: Context, sequencer: SequencerLike) -> Sequencer: std = cast(StandardLibrary, context.library(StandardLibrary)) format = None uri = None args = None if type(sequencer) is str: uri = sequencer elif type(sequencer) is list: args_start = 0 if len(sequencer) >= args_start + 2 and sequencer[args_start] == '-o': uri = sequencer[args_start + 1] args_start += 2 if len(sequencer) >= args_start + 2 and sequencer[args_start] == '-f': format = sequencer[args_start + 1] args_start += 2 args = sequencer[args_start:] elif isinstance(sequencer, Sequencer): return sequencer if format is not None: return std.player.make_sequencer_from_format(format, uri or "", args or []) return std.player.make_sequencer_from_uri(uri or "", args or [])
def __init__(self, only_final: bool = False, ast: bool = False, context: Context = None, nameless_voices: bool = True, declare_voices: bool = True, base_voice: Voice = None): """ only_final When true, the result is only emitted after the entire input (musical sequence) has been processed. When false, intermediate notations are continuously emitted. ast When true, emits the Abstract Syntax Tree objects. When false, transforms those objects into a string that can be parsed, and emits the string instead nameless_voices When true, it tries to produce notation that carries with it any state that is needed, instead of prepending the names of the voices the events belonged to declare_voices When `nameless_voices = False`, also include the definitions of the named voices used. base_voice ... """ super().__init__(only_final) self.ast: bool = ast self.context: Context = context or Context.create() self.nameless_voices: bool = nameless_voices self.declare_voices: bool = declare_voices self.base_voice: Voice = base_voice or Voice()
def keyboard_close ( context : Context, keyboard : Keyboard ): if keyboard != None: keyboard.close() else: lib : KeyboardLibrary = cast( KeyboardLibrary, context.library( KeyboardLibrary ) ) lib.close()
def function_voices_create(context: Context, name: str, modifiers: Node = None, inherit: Voice = None): if inherit != None: pass voice = Voice(name, Instrument(name, 1)) forked = context.fork() forked.voice = voice if inherit != None: voice.instrument = inherit.instrument voice.time_signature = inherit.time_signature voice.velocity = inherit.velocity voice.octave = inherit.octave voice.value = inherit.value voice.tempo = inherit.tempo if modifiers != None: if isinstance(modifiers, MusicSequenceNode): for modifier in modifiers: if isinstance(modifier, ContextModifierNode): modifier.apply(voice) else: modifier.eval(forked) else: if isinstance(modifiers, ContextModifierNode): modifiers.apply(voice) else: modifiers.eval(forked) return voice
def create_context ( self, player : Player ): ctx = Context.create() ctx.link( StandardLibrary() ) ctx.link( MusicLibrary() ) ctx.link( KeyboardLibrary( player ) ) return ctx
def function_discard(context: Context, *expr): for e in expr: value = e.eval(context.fork()) if isinstance(value, Music): for _ in value: pass return None
def function_debug(context: Context, expr): value = expr.eval(context.fork()) if value is None: print(None) elif isinstance(value, Music): print('<Music> ' + ' '.join(str(event) for event in value.expand(context))) else: print("<%s>%s" % (Value.typeof(value), value))
def function_readmidi(context: Context, file: str = None, port: Union[str, List[str], bool] = None, voices: List[Voice] = None, cutoff_sequence=None, ignore_message_types: List[str] = None): if file is not None: mid = mido.MidiFile(file) return read_midi_file(context, mid, voices, cutoff_sequence, ignore_message_types) else: if port == True: default_port = context.library( MidiLibrary).get_midi_default_input() if default_port is None: port = mido.open_input() else: port = mido.open_input(default_port) elif type(port) == str: port = mido.open_input(port) elif type(port) == list: port = MultiPort([mido.open_input(p) for p in port]) events = midi_stream_to_music(context, port, context.voice, ignore_message_types) events = ComposeNotesTransformer.iter(events) if cutoff_sequence != None: events = TerminationMelodyTransformer.iter( events, list(cutoff_sequence.expand(context.fork(cursor=0)))) events = TeeTransformer.iter( events, Transformer.pipeline( VoiceIdentifierTransformer(), MusiklaNotationBuilderTransformer(), Transformer.subscriber(lambda n: print(n + '\n\n')))) return Music(list(events))
def __init__(self, event: Union[Music, NoteEvent, Note, None]): super().__init__() if isinstance(event, Music): event = event.first_note(Context()) if isinstance(event, NoteEvent): event = event.note if event is None: raise Exception("Cannot create PianoKey of None") self.note: Note = event.timeless()
def keyboard_filedialog ( context : Context, title : str = "File", text : str = "File Path:", default_value : str = None, cb = None ): from prompt_toolkit.patch_stdout import patch_stdout from prompt_toolkit.shortcuts import input_dialog from prompt_toolkit.completion import PathCompleter lib : KeyboardLibrary = cast( KeyboardLibrary, context.library( KeyboardLibrary ) ) def _run (): with patch_stdout(): application = input_dialog( title = title, text = text, completer = PathCompleter() ) with application.input.raw_mode(): application.input.read_keys() application.layout.current_control.buffer.insert_text(default_value or "") return application.run_async() lib.prompt( _run, cb )
def __eval__(self, context: Context): val = Value.assignment(self.right.eval(context.fork(cursor=0))) if self.operator is None or self.operator == "": self.left.assign(context, val, local=self.local) else: def _set(value): nonlocal val # value = context.symbols.lookup( self.name, recursive = not self.local ) if self.operator == '*': value *= val elif self.operator == '/': value /= val elif self.operator == '+': value += val elif self.operator == '-': value -= val elif self.operator == '&': value &= val elif self.operator == '|': value |= val else: raise Exception("Invalid operator: " + self.operator) return value self.left.lookup_assign(context, _set, local=self.local) return None
def __eval__(self, context: Context): val = Value.assignment(self.right.eval(context.fork(cursor=0))) for i, op in enumerate(self.left): if self.operator is None or self.operator == "": op.assign(context, val[i], local=self.local) else: def _set(value): nonlocal val if self.operator == '*': value *= val[i] elif self.operator == '/': value /= val[i] elif self.operator == '+': value += val[i] elif self.operator == '-': value -= val[i] elif self.operator == '&': value &= val[i] elif self.operator == '|': value |= val[i] else: raise Exception("Invalid operator: " + self.operator) return value op.lookup_assign(context, _set, local=self.local) return None
def function_set_midi_input_name(context: Context, name: str): context.library(MidiLibrary).set_midi_default_input(name)
def keyboard_readperf ( context : Context, file : str, keyboards : List[Keyboard] = None ) -> Music: lib : KeyboardLibrary = cast( KeyboardLibrary, context.library( KeyboardLibrary ) ) return lib.readperf( context, file, keyboards )
def function_get_midi_input_name(context: Context) -> str: return context.library(MidiLibrary).get_midi_default_input()
def setUp(self): self.parser = parser self.context = Context.create() self.context.link(StandardLibrary(None))
def modify(self, context: Context): context.voice = context.voice.clone(value=self.length) yield ContextChangeEvent(context.cursor, "length", context.voice.value, context.voice, 0)
def modify ( self, context : Context ): context.voice = context.voice.clone( tempo = self.tempo ) yield ContextChangeEvent( context.cursor, "tempo", context.voice.tempo, context.voice, 0 )
def keyboard_open_repl ( context : Context ): lib : KeyboardLibrary = cast( KeyboardLibrary, context.library( KeyboardLibrary ) ) lib.eval( context ) return None
def function_setvoice(context: Context, voice: Voice): context.voice = voice
def function_settime(context: Context, time: int): context.cursor = time
def keyboard_replay ( context : Context, file : str ): lib : KeyboardLibrary = cast( KeyboardLibrary, context.library( KeyboardLibrary ) ) lib.replay( file )