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)
예제 #2
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
예제 #3
0
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
예제 #4
0
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
예제 #5
0
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
예제 #6
0
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))
예제 #7
0
    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)
예제 #8
0
    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)
예제 #9
0
    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
예제 #10
0
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 __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
예제 #12
0
    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