Skip to content

Commit

Permalink
MMMLExpressionToEvent: Add option to skip argument with special value…
Browse files Browse the repository at this point in the history
… '_'

Before this patch all arguments of a MMML expression needed to be
defined in their given order. This means that if a user wanted to
specify the 5th argument of an expression, it also needed to specify the
four previous arguments even if the user didn't care about them. So for
instance when setting the clef on a rest the user had to write:

    r 1/4 pp arpeggio.direction=None clef.name=bass

So duration, volume and playing indicators needed to be defined,
although they didn't matter. This patch adds the new special argument
value `_`. With this, arguments are ignored, so the previous example
could simply be:

    r 1/4 _ _ clef.name=bass
  • Loading branch information
levinericzimmermann committed Mar 16, 2024
1 parent 386cdee commit 134ceda
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 2 deletions.
3 changes: 3 additions & 0 deletions mutwo/mmml_converters/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,8 @@
ENCODER_REGISTRY = mmml_utilities.EncoderRegistry()
INDENTATION = r" "

IGNORE_MAGIC = r"_"
"""If this is used as an argument, it is ignored"""


del mmml_utilities
21 changes: 19 additions & 2 deletions mutwo/mmml_converters/frontends.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,11 @@ class MMMLExpressionToEvent(core_converters.abc.Converter):

def __init__(self, use_defaults: bool = False):
self._use_defaults = False

self._wrapped_decoder_dict = {}

self.__decoder_default_dict = {}
self.__decoder_varnames_dict = {}

def reset_defaults(self):
self.__decoder_default_dict = {}
Expand Down Expand Up @@ -104,14 +107,26 @@ def _wrap_decoder(self, decoder_name: str, function: typing.Callable):
n 1/1 c
"""

varnames = function.__code__.co_varnames
self.__decoder_varnames_dict[decoder_name] = varnames

def _(*args):
if self._use_defaults:
self._set_decoder_default_args(decoder_name, args)
args = self._get_decoder_default_args(decoder_name, args)
return function(*args)
kwargs = self._args_to_kwargs(decoder_name, args)
return function(**kwargs)

return _

def _args_to_kwargs(self, decoder_name: str, args: tuple) -> dict:
varnames = self.__decoder_varnames_dict[decoder_name]
return {
name: arg
for name, arg in zip(varnames, args)
if arg != mmml_converters.constants.IGNORE_MAGIC
}

def _set_decoder_default_args(self, decoder_name: str, args: tuple):
"""Set currently defined arguments as new default values for decoder"""
present_default = self.__decoder_default_dict.get(decoder_name, [])
Expand All @@ -138,7 +153,9 @@ def _split_to_header_and_block(expression: str):
header, block = None, expression
while not header:
if not block:
raise mmml_utilities.MalformedMMML(f"No MMML expression found in expression '{expression}'")
raise mmml_utilities.MalformedMMML(
f"No MMML expression found in expression '{expression}'"
)
header, _, block = block.partition("\n")
return header, block

Expand Down
5 changes: 5 additions & 0 deletions tests/converters_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,11 @@ def test_decoder_sim(self):
# Set tag
self.assertEqual(sim(tag="abc"), self.c("sim abc"))

def test_empty_argument(self):
"""Ensure that MMML takes the decoders default value if magic '_' is given as an argument"""
self.assertEqual(n(volume="pppp"), self.c("n _ _ pppp"))
self.assertEqual(n(volume="pppp", duration="5/4"), self.c("n 5/4 _ pppp"))


class EventToMMMLExpressionTest(unittest.TestCase):
def setUp(self):
Expand Down

0 comments on commit 134ceda

Please sign in to comment.