Skip to content
Snippets Groups Projects

MMLlib — Modern library for handling Music Macro Language

About

MMLlib is a pure Python implementation of functionality related to the Music Macro Language as implemented by Microsoft® GW-BASIC® and compatibles, which is its most common form, also implemented by the PC speaker driver in Linux and BSD, with a number of extensions and changes:

  • | denotes a bar line, ignored by the Linux/BSD driver
  • support for multiple (parallel) instrument tracks
  • a per-file header with work metadata (optional)
  • lines starting with a # are comments
  • the alias ~ (itself a BSD extension) is not supported

The library currently contains functions to:

  • parse an (extended) MML file into metadata and individual tracks
  • return a normalised form of the MML that does not make use of the extensions and should PLAY on the original BASIC interpreter
  • a duration estimate and the number of tracks are added to the metadata
  • return a list of tuples (frequency, duration) to play (in a threaded interpreter, such as Floppi-Music)
  • bar lines are indicated separately as integer 1 in the playlist
  • return an event-oriented list of measures / bars across all tracks; each measure has a duration and a list of time-fixed tone on/off events; facilitates playing in non-threaded interpreters and, possibly, MIDI export
  • export (extended) MML to MusicXML
  • which can be imported by e.g. MuseScore to…
    • double-check the MML score for mistakes in a visual representation
    • play, arrange, etc. the music
    • beautify the score to print it as sheet music
    • export into other formats or share on their website
  • export (currently only the first track of) MML to an NXC program
  • check tracks for synchronisation error
    • missing tracks, i.e. with 0 bars
    • missing bars (can only be detected at the end, of course)
    • missing notes within a bar, relative to other tracks
  • play a playlist (parsed MML) using PWM on GPIO pins on ESP boards under MicroPython (experimental; may not work for higher pitches)

Prerequisites

The library itself does not have any prerequisites, but argparse is used by the (optional) command-line interface.

While MMLlib is only formally supported for Python releases that are not end-of-life it’s occasionally tested that Python 2.7 and even 2.5 still work, with no guarantees though.

Library

The MMLlib library offers various entry points, such as:

  • mmllib.mml.mml() to parse an MML track from a string
  • mmllib.parser.mml_file() to parse an extended MML file
  • mmllib.parser.mml_file_meta() to get its associated metadata
  • The mmllib.musicxml and mmllib.nxc modules offer various conversion functions
  • mmllib.playlist offers various functions dealing with playlists as returned by the parser functions
  • mmllib.esp contains the (experimental) MicroPython ESP support

See mmllib.cmds for usage examples for most.

Commands

Several quick commands are provided. They can be run by either:

  • ./run.py cmdname [args …] in the source tree
  • python3 -m mmllib.cmds cmdname [args …] once installed
  • consolescriptname [args …] for commands that support this

The following commands are currently offered:

  • mml2musicxml path (also as mml2musicxml console script)

    Converts the given path to MusicXML which is printed on stdout. This utility is intended to be used by end users.

  • mml2nxcmono path

    Converts the first track of the given path to an NXC program for playback on LEGO® Mindstorms robots. This is experimental and subject to change, especially considering multi-robot playback and synchronisation thereof.

  • mmllint [-q] path (also as mmllint console script)

    The file path (which must end with .mml) is parsed and analysed for a set of possible errors in multi-track scenarios.

    Unless -q is given, the timedlist returned by the parser is printed first, then the equivalent BASIC MML for each track.

    Then, the amount of tracks and measures and the total duration is shown, as well as any errors or a message stating lack thereof.

    This utility is intended to be used interactively by MML authors or, possibly, when converting to BASIC MML (grepping is possible).

  • mmllint [-q] mmlstring (also as mmllint console script)

    The same as the above, except mmlstring (which must not end with .mml) is directly interpreted as single-track MML.

  • showmeta path

    The file path is read, and its metadata (see MML description) output.

Testsuite

The testsuite can be run with one of the following commands:

  • with setuptools (note that this is deprecated in recent versions; use one of the other methods if it fails)
    • python3 setup.py test (3.x)
    • python setup.py test (2.5+)
  • with unittest
    • python3 -m unittest (3.x)
    • python -m unittest discover (2.7+)
  • using another suitable testsuite runner

Examples

Some example extended MML files are contained within the examples/ directory, in lieu of better documentation for the extended format, in addition to the MML format documentation.

Projects using MMLlib

Floppi-Music: Floppi-Music has MML as input format for floppy drive music on Raspberry Pi and uses MMLlib for processing. Floppi-Music is also the origin of MMLlib from before it was spun off into a separate project of its own.