| project name: | midarto |
| project url: | https://github.com/mrglennjones/midarto |
| author: | mrglennjones |
| description: | two-deck MIDI file DJ: mix .mid files with a crossfader to General MIDI modules or nb voices, with a full 16x8 grid controller |
| discussion url: | https://llllllll.co/t/midarto/75532 |
| documentation url: | https://github.com/mrglennjones/midarto/raw/main/docs/midarto-guide.pdf |
| tags: | grid midi sequencer nb |


A two-deck MIDI file DJ for monome norns. Load .mid files into deck A and deck B, mix them with a crossfader and play them out to a MIDI sound module (such as a General MIDI module) or to nb voices. It works on the norns alone, and a 16×8 grid adds cues, loops, mutes, sync and big transport keys.
Version 2.14.
From maiden (once the repo is public): in the maiden REPL, type ;install https://github.com/mrglennjones/midarto.
By copying:
midarto.zip. You get a folder called midarto containing midarto.lua, lib/, demo/ and this README.midarto folder into dust/code/ on your norns. Any of these works:smb://norns.local on macOS or \\norns.local on Windows, user we, password sleep unless you changed it). Drop the folder into dust/code/.scp -r midarto we@norns.local:~/dust/code/The first time it runs, Midarto creates a songs folder, dust/data/midarto/songs/, and puts two demo songs in it (acid_trk.mid at 120 BPM and breaks.mid at 98.5 BPM), so you can try it straight away.
Fill the songs folder, dust/data/midarto/songs/, with your own .mid or .midi files. Subfolders are fine, for example one per set or genre. The browser always opens in the songs folder, and you can go up to browse anywhere in dust. You can delete the demo songs once you've added your own; if the folder is ever empty, Midarto puts them back.
Upgrading from v2.4 or earlier: songs you kept directly in dust/data/midarto/ are moved into the songs folder the first time v2.5 runs.
To play a deck through nb voices instead of MIDI, install the nb library (dust/code/nb) plus any nb voice mods you want, then restart Midarto. An "nb voice" output option and a voice selector then appear in each deck's parameters. If nb isn't installed, Midarto simply offers MIDI output only.
Open PARAMS > EDIT > MIDARTO. Midarto saves these settings a couple of seconds after you change them (in dust/data/midarto/settings.pset), so they survive a power cut, and keeps them when you update to a new version. If an update needs to adjust an old setting, it does so once and shows what it changed.
| Parameter | What it does |
|---|---|
| midi outputs | one device (default): both decks play to deck A's MIDI device. two devices: each deck has its own device |
| output | midi or nb voice (nb only if installed) |
| midi device | Which MIDI port the deck plays to (1–16, names shown). With one device, only deck A's shows and both decks use it. With two, deck B defaults to port 2 |
| channel shift | Moves the file's channels up by this amount, so two decks don't fight over the same channels. Deck A defaults to 0, deck B to 8 |
| drums stay on 10 | Keeps channel 10 drums on 10 when shifting; other channels skip 10 |
| nb voice | Voice for the deck when output is nb voice |
| crossfader curve | dj (both full at the centre) or smooth (constant power) |
| cue to first note | first note (default), first drum or off. On load, hot cue 1 and the deck go to the start of the bar where the music begins, skipping silence at the start |
| start on bar | on + sync (default), on or off. PLAY on a stopped deck waits for the other deck's next bar line while it plays; on + sync also locks the tempo |
| quantize jumps | Seek, cue and bar jumps wait for the next bar line |
| knob sensitivity | How far the faders move per encoder step |
| end warning | How long before the end of a song it warns you (platter outline or waveform header flashes): off, 10, 20, 30 (default) or 60 seconds |
| clock follows master | Sets the norns clock tempo from the master deck, so clocked gear follows |
| panic | All notes off on both decks' outputs |
| screen view | platters (default) or waveform |
| waveform zoom | How much time the waveform shows across the screen: 2, 4 (default), 8, 16 or 32 seconds |
| show frame time | Shows how long each screen frame takes to draw, for checking the load on your norns |
| clear song cache | Deletes the song library's cached data (cue points are kept) |
One General MIDI module (the default): plug your GM module into the norns and set deck A's midi device to it. Deck B plays to the same device automatically.
General MIDI has only 16 channels, so deck B's channel shift (8 by default) moves its parts out of deck A's way. For example, deck B's channels 1–7 play on 9 and 11–16 (10 is skipped), while deck A keeps 1–8. Both decks share drums on channel 10, because General MIDI has only one drum channel. Files that use more than 8 channels will still overlap. Shared channels are handled for you: see "Shared channels" below.
Two General MIDI modules: give each deck its own module, so nothing collides and both files keep all 16 channels, drums included.
two devices. Deck B's midi device setting appears.Upgrading from v2.3–v2.7: from 2.14 on, Midarto fixes deck B's old channel shift (0) for you on the first run and shows "B shift 8".
Set screen view to waveform in PARAMS. Each deck gets half the screen (A on top, B below):
S when synced, and time remaining.The waveform is a picture of the MIDI notes, not the sound from your GM module, but it shows beats, drops and breakdowns clearly. It's worked out when a song loads and saved in the song library.
Midarto keeps a small library in dust/data/midarto/library/:
Everything in the library is safe to delete. clear song cache in PARAMS removes the cached data but keeps your cue points.
| Control | Normal | Hold K1 |
|---|---|---|
| E1 | Crossfader | Tempo of both decks |
| E2 | Deck A volume | Deck A tempo (0.1% steps) |
| E3 | Deck B volume | Deck B tempo |
| K2 | Deck A play/pause | Open file browser for deck A |
| K3 | Deck B play/pause | Open file browser for deck B |
A quick tap on K1 still opens the norns menu, as usual.
In the browser: E2 scrolls, E3 scrolls a page, E1 switches the target deck, K3 opens a folder or loads the file, and K2 closes the browser. The other deck keeps playing while you browse.
On screen: each deck shows its file name (long names scroll), a platter outline that flashes as the song runs out, a platter that turns once per bar, a progress bar (with a hot cue 1 mark and the loop region), BPM, tempo offset and time remaining. The mixer in the middle shows both volume faders, output meters and the crossfader. An X under a fader means that deck is killed.
Deck A is on columns 1–6, the mixer on 7–10 and deck B on 11–16. Rows 1–3, 5 and 6 run in the same order on both decks. Row 4 (tempo) and rows 7–8 are mirrored, so NDG, CUE, PLAY/PAUSE and SYNC sit on the outer edges; −/+ pairs still read left to right.
| Row | Deck A x1–x6 | Mixer x7–x10 | Deck B x11–x16 |
|---|---|---|---|
| 1 | SEEK 1–6 | VOL A · MTR A · MTR B · VOL B | SEEK 1–6 |
| 2 | CUE1–4, |
volume and meters | CUE1–4, |
| 3 | LOOP 1, 2, 4, 8, 16, LOOP | volume and meters | LOOP 1, 2, 4, 8, 16, LOOP |
| 4 | NDG−, NDG+, BPM−, BPM+, free, BPM RESET | volume and meters | BPM RESET, free, BPM−, BPM+, NDG−, NDG+ |
| 5 | CHAN 1–6 | volume and meters | CHAN 1–6 |
| 6 | CHAN 7–12 | volume and meters | CHAN 7–12 |
| 7 | CUE, free, CHAN 13–16 | XF A · XF 1/3 · XF 2/3 · XF B | CHAN 13–16, free, CUE |
| 8 | PLAY/PAUSE, SYNC, free, LOAD A, free, SHIFT | KILL A · MSTR A · MSTR B · KILL B | SHIFT, free, LOAD B, free, SYNC, PLAY/PAUSE |
Deck keys:
on + sync). Press PLAY again to cancel.Mixer:
Brightness: dark = nothing there, dim = available (or muted), medium = set or stored, bright = on. A key blinks while its jump waits for the next bar.
For MIDI outputs, Midarto sets each channel's volume (CC7) from the file's own volume multiplied by the deck fader, the crossfader and kill. So moving a fader fades held notes too, and each file's own mix balance is kept. For nb voices there's no channel volume, so note velocity is scaled instead, which only affects new notes.
Instruments: when a file never chooses an instrument for a channel, Midarto sets piano (the General MIDI default), so the part doesn't pick up whatever instrument was left on that channel. Channel shift moves each part's instrument with it.
Shared channels: when both decks use the same channel on the same device (always true for drums on channel 10 with one GM device), the playing deck owns it. Loading, cueing or stopping the other deck sends nothing to that channel: no volume, instrument, controller or all-notes-off messages, so the playing deck carries on untouched. When both decks play, the louder one owns the channel and sets its volume and instrument, and the quieter deck's notes there are played at its own level through velocity. So crossfading hands the drums over from one deck to the other.
midarto.midarto.lua, lib/, demo/: the norns script (this folder is what goes in dust/code/midarto).docs/midarto-guide.pdf: the full user guide (download).docs/images/: screen, grid and splash images.CHANGELOG.md: what changed in each version.LICENSE: the MIT License.The guide uses IBM Plex Mono and the mockup images use Silkscreen, both under the SIL Open Font License.
Midarto is released under the MIT License. You're free to use, change and share it, as long as the copyright notice stays with it.
Created by Glenn Jones, Cutie Suzuki & DJ FingaBlasta.