https://github.com/adamico/picotron-mml-parser
A Macro Music Language parser for Picotron
https://github.com/adamico/picotron-mml-parser
lua mml music parser-api picotron
Last synced: about 1 month ago
JSON representation
A Macro Music Language parser for Picotron
- Host: GitHub
- URL: https://github.com/adamico/picotron-mml-parser
- Owner: adamico
- Created: 2025-12-21T22:48:17.000Z (6 months ago)
- Default Branch: main
- Last Pushed: 2025-12-21T22:54:20.000Z (6 months ago)
- Last Synced: 2025-12-23T10:03:45.541Z (6 months ago)
- Topics: lua, mml, music, parser-api, picotron
- Language: Lua
- Homepage:
- Size: 10.7 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# Picotron MML Parser
A lightweight **Music Macro Language (MML)** parser and sequencer for [Picotron](https://www.lexaloffle.com/picotron.php), designed for compatibility with the [Pyxel MML specification](https://kitao.github.io/pyxel/wasm/mml-studio/mml-commands.html).
This library allows you to play complex musical sequences in your Picotron games using simple strings, supporting features like nested loops, custom tempos, and precise timing.
## Features
- **Pyxel Compatibility**: Supports standard MML commands used by the Pyxel game engine.
- **Nested Loops**: Arbitrary nesting of sequences using `[...]` syntax.
- **Coroutine-Based Playback**: Integrates seamlessly into your `_update()` loop without blocking.
- **Precise Timing**: Uses sub-tick accumulation for stable playback even at high tempos and non-integer durations.
- **Automatic Silence**: Correctly handles rests (`r`) and ensures the channel is silenced when the sequence ends.
- **Volume Scaling**: Automatically maps MML volume (0-15) to Picotron's internal volume range (0-7).
## Installation
Simply copy `mml_parser.lua` into your Picotron project folder (e.g., `/drive/lib/`).
## Quick Start
```lua
local mml_parser = require("lib/mml_parser")
-- 1. Compile your MML string
local mml_string = "t120 l8 o3 c d e [f g [a b]2]2 r4 c2"
local result = mml_parser:compile(mml_string)
-- 2. Create a player coroutine (Channel 0, Instrument 0, 30 ticks per beat)
local music_co = cocreate(mml_parser:create_player(result, 0, 0, 30))
function _update()
-- 3. Resume the coroutine every frame
if music_co and costatus(music_co) ~= "dead" then
coresume(music_co)
end
end
```
## Supported Commands
| Command | Description | Example |
| :--- | :--- | :--- |
| `c`, `d`, `e`, `f`, `g`, `a`, `b` | Play a note. Use `#` or `+` for sharp, `-` for flat. | `c4 d#8 g+16` |
| `r` | Rest (silence). | `r4` |
| `o` | Set octave (0-8). Default is 3. | `o4` |
| `<` / `>` | Decrease / Increase octave. | `> c < b` |
| `t` | Set tempo (BPM). Default is 120. | `t150` |
| `v` | Set volume (0-15). Default is 12. | `v8` |
| `l` | Set default note length (1, 2, 4, 8, 16...). Default is 4. | `l8` |
| `[...]n` | Loop the bracketed sequence `n` times. | `[c d e]2` |
## API Reference
### `mml_parser:compile(mml_string)`
Parses the MML string and returns a table containing:
- `notes`: A list of compiled note events.
- `tempo`: The initial tempo.
- `duration`: The total duration of the sequence in beats.
### `mml_parser:create_player(result, channel, instrument, ticks_per_beat)`
Returns a function intended to be wrapped in a `cocreate()`.
- `result`: The output from `compile()`.
- `channel`: (0-15) Target audio channel.
- `instrument`: (0-127) Instrument index.
- `ticks_per_beat`: Adjust this based on your game's FPS and tempo (default 30).
## License
This project is released under the MIT License.