diff --git a/smnp/environment/factory.py b/smnp/environment/factory.py index 244a3ed..95cbf0b 100644 --- a/smnp/environment/factory.py +++ b/smnp/environment/factory.py @@ -1,12 +1,16 @@ from smnp.environment.environment import Environment from smnp.library.function.combine import combine from smnp.library.function.display import display +from smnp.library.function.duration import withDuration from smnp.library.function.exit import exit from smnp.library.function.flat import flat from smnp.library.function.interval import interval from smnp.library.function.mic import wait +from smnp.library.function.octave import withOctave +from smnp.library.function.rand import random from smnp.library.function.semitones import semitones from smnp.library.function.sleep import sleep +from smnp.library.function.tuplet import tuplet from smnp.library.function.type import objectType @@ -20,11 +24,14 @@ def createEnvironment(): interval, combine, flat, - wait + wait, + random, + tuplet ] methods = [ - + withDuration, + withOctave ] # 'exit': Function(base.exit, ONLY_FUNCTION), # 'print': Function(base.display, ONLY_FUNCTION), diff --git a/smnp/error/function.py b/smnp/error/function.py index 3904a09..1d14789 100644 --- a/smnp/error/function.py +++ b/smnp/error/function.py @@ -13,4 +13,9 @@ class FunctionNotFoundException(SmnpException): class MethodNotFoundException(SmnpException): def __init__(self, object, method): - self.msg = f"Method '{method}' of type '{object}' not found" \ No newline at end of file + self.msg = f"Method '{method}' of type '{object}' not found" + + +class IllegalArgumentException(SmnpException): + def __init__(self, msg): + self.msg = msg \ No newline at end of file diff --git a/smnp/library/function/duration.py b/smnp/library/function/duration.py new file mode 100644 index 0000000..5191238 --- /dev/null +++ b/smnp/library/function/duration.py @@ -0,0 +1,14 @@ +from smnp.library.model import Function +from smnp.library.signature import signature, ofTypes +from smnp.type.model import Type +from smnp.type.value import Value + + +def _withDuration(env, note, duration): + return Value(Type.NOTE, note.value.withDuration(duration.value)) + + +_sign = signature(ofTypes(Type.NOTE), ofTypes(Type.INTEGER)) + + +withDuration = Function(_sign, _withDuration, 'withDuration') \ No newline at end of file diff --git a/smnp/library/function/note.py b/smnp/library/function/note.py deleted file mode 100644 index 3c58b42..0000000 --- a/smnp/library/function/note.py +++ /dev/null @@ -1,31 +0,0 @@ -from smnp.library.tools import returnElementOrList - - -def changeDuration(args, env): - if len(args) == 2 and isinstance(args[0], Note) and isinstance(args[1], int): - return args[0].withDuration(args[1]) - return # invalid signature - - -def changeOctave(args, env): - if len(args) == 2 and isinstance(args[0], Note) and isinstance(args[1], int): - return args[0].withOctave(args[1]) - return # invalid signature - - -def tupletList(n, m, list): - return [note.withDuration(note.duration * n / m) for note in list] - - -def tuplet(args, env): - if len(args) > 2 and type(args[0]) == int and type(args[1]) == int and all(type(x) == Note for x in args[2:]): - n = args[0] # how many notes - m = args[1] # instead of number of notes (3-tuplet: 3 instead 2; 5-tuplet: 5 instead 4 etc.) - return returnElementOrList(tupletList(n, m, args[2:])) - elif len(args) == 3 and type(args[0]) == int and type(args[1]) == int and type(args[2]) == list and all(type(x) == Note for x in args[2]): - n = args[0] - m = args[1] - l = args[2] - return returnElementOrList(tupletList(n, m, l)) - else: - pass # not valid signature \ No newline at end of file diff --git a/smnp/library/function/octave.py b/smnp/library/function/octave.py new file mode 100644 index 0000000..0a0d596 --- /dev/null +++ b/smnp/library/function/octave.py @@ -0,0 +1,14 @@ +from smnp.library.model import Function +from smnp.library.signature import signature, ofTypes +from smnp.type.model import Type +from smnp.type.value import Value + + +def _withOctave(env, note, octave): + return Value(Type.NOTE, note.value.withOctave(octave.value)) + + +_sign = signature(ofTypes(Type.NOTE), ofTypes(Type.INTEGER)) + + +withOctave = Function(_sign, _withOctave, 'withOctave') \ No newline at end of file diff --git a/smnp/library/function/rand.py b/smnp/library/function/rand.py index 3ad8ca2..318f470 100644 --- a/smnp/library/function/rand.py +++ b/smnp/library/function/rand.py @@ -1,17 +1,41 @@ import random as r +from smnp.error.function import IllegalArgumentException +from smnp.library.model import Function, CombinedFunction +from smnp.library.signature import varargSignature, listMatches, ofTypes +from smnp.type.model import Type -def random(args, env): - if not all(isinstance(x, list) and len(x) == 2 and isinstance(x[0], float) for x in args): - return # not valid signature - if sum([x[0] for x in args]) != 1.0: - return # not sums to 100% - choice = r.random() - acc = 0 - for e in args: - acc += e[0] - if choice <= acc: - return e[1] +def forType(t): + def _random(env, vararg): + choice = r.random() + acc = 0 + if sum(arg.value[0].value for arg in vararg) != 1.0: + raise IllegalArgumentException("Sum of all percentage values must be equal 100%") + for arg in vararg: + percent, item = arg.value + acc += percent.value + if choice <= acc: + return item + + _sign = varargSignature(listMatches(ofTypes(Type.PERCENT), ofTypes(t))) + + return Function(_sign, _random) + + +random = CombinedFunction('random', *[ forType(t) for t in Type if t != Type.VOID ]) +# +# def random(args, env): +# if not all(isinstance(x, list) and len(x) == 2 and isinstance(x[0], float) for x in args): +# return # not valid signature +# if sum([x[0] for x in args]) != 1.0: +# return # not sums to 100% +# choice = r.random() +# acc = 0 +# for e in args: +# acc += e[0] +# if choice <= acc: +# return e[1] +# #TODO: sample \ No newline at end of file diff --git a/smnp/library/function/tuplet.py b/smnp/library/function/tuplet.py new file mode 100644 index 0000000..d13455e --- /dev/null +++ b/smnp/library/function/tuplet.py @@ -0,0 +1,44 @@ +from smnp.library.model import CombinedFunction, Function +from smnp.library.signature import signature, listOf, ofTypes, varargSignature +from smnp.type.model import Type +from smnp.type.value import Value + + +def _tuplet1(env, n, m, vararg): + t = [Value(Type.NOTE, arg.value.withDuration(arg.value.duration * n.value / m.value)) for arg in vararg] + return Value(Type.LIST, t).decompose() + + +_sign1 = varargSignature(ofTypes(Type.NOTE), ofTypes(Type.INTEGER), ofTypes(Type.INTEGER)) + + + +def _tuplet2(env, n, m, notes): + return _tuplet1(env, n, m, notes.value) + + +_sign2 = signature(ofTypes(Type.INTEGER), ofTypes(Type.INTEGER), listOf(Type.NOTE)) + + +tuplet = CombinedFunction( + 'tuplet', + Function(_sign1, _tuplet1), + Function(_sign2, _tuplet2) +) + +# def tupletList(n, m, list): +# return [note.withDuration(note.duration * n / m) for note in list] +# +# +# def tuplet(args, env): +# if len(args) > 2 and type(args[0]) == int and type(args[1]) == int and all(type(x) == Note for x in args[2:]): +# n = args[0] # how many notes +# m = args[1] # instead of number of notes (3-tuplet: 3 instead 2; 5-tuplet: 5 instead 4 etc.) +# return returnElementOrList(tupletList(n, m, args[2:])) +# elif len(args) == 3 and type(args[0]) == int and type(args[1]) == int and type(args[2]) == list and all(type(x) == Note for x in args[2]): +# n = args[0] +# m = args[1] +# l = args[2] +# return returnElementOrList(tupletList(n, m, l)) +# else: +# pass # not valid signature \ No newline at end of file