Tmi

tmi

textual music instructions / tiny midi interface / too much information

tmi is a norns library for composing and sequencing devices with text, ported to norns from a version i previously wrote. its basically a norns tracker, but unlike other norns trackers with wonderful visuals and features (e.g. yggdrasil, orca), tmi has few features and basically no visual interface. however, the one feature that tmi does have is that tmi can be used within any other norns script so with a few lines of code+text you can sequence multiple external devices (notes and ccs) from your favorite norns script.

tmi music tracks are written in text files (more on that below). when tmi is added to a script, these files can be loaded via the PARAMETERS > TMI screen in the parameters menu. once loaded, any changes to files are hot-loaded so you could do live-coding (if you have a computer handy).

this script finalizes a trilogy of norns scripts i’ve been writing that can be imported into other norns scripts. my goals was to take a existing sample-based script be able to also

  • …have command-mapping to single buttons (via middy)
  • …be compatible with a grid-based drum machine (via kolor)
  • …be able to do midi sequencing (via tmi)

the importable scripts above work in a multitude of scripts (barcode, oooooo, cranes, otis, to name a few) but might not work with all (especially if the host script already uses midi or something).

Requirements

  • norns
  • external midi device

Documentation

Install

first install in maiden with

;install https://github.com/schollz/tmi

then edit an existing script. in the existing script add these lines of code somewhere (preferable near the top) of the script:

if util.file_exists(_path.code.."tmi") then 
  tmi=include("tmi/lib/tmi")
  m=tmi:new()
end

if you want tmi to play a certain file on a certain instrument right away, you can add these two lines:

-- change "op-1" to the instrument your using
m:load("op-1","/home/we/dust/data/tmi/somefile",1)
m:toggle_play()

now open the script and goto the parameters menu: PARAMETERS > TMI. make sure you have your midi device plugged in before you start, otherwise TMI menu will not be available. now you can load tmi files into any connected midi instrument (up to 4 tracks per instrument).

Making tmi files

tmi works with text files with textual musical notation - either notes, chords, rests, or sustains. by default these files are found in the ~/data/dust/tmi directory. you need to make these files yourself using maiden or another text editor.

rules for these files:

  • one line is one measure, and is subdivided according to how many things are in it. example: “C . . .” plays a C-major chord on beat 1 and rests for 3 beats
  • chords start with an uppercase letter, inversions allowed with “/” and octaves allowed with “;”. examples: “Cmin”, “F#min/A;4”, or “Db;5”)
  • notes start with a lower case letter, with optional octave number, separated by commas. examples: “e5”, or “f4,a,c
  • appending “_X” will change the velocity of a note/chord. example: “Cmin_20” plays a c-minor chord at velocity 20
  • the “-” character sustains the last entry
  • the “*” character re-plays the last entry
  • the “.” character is a rest
  • multiple sequences can be in one file with each below a line specifying “pattern X” where you fill in “X
  • if multiple sequences are in one file, chain them with “chain X Y
  • comments are specified by “#
  • pairs of numbers are interpreted as cc number and cc value respectively, example: “24,99

by default tmi uses a meter of 4, but this can be changed at startup using m = tmi:new{meter=X}.

examples of tmi files

the following are valid tmi files.

this one plays four chords:

# a four chord song
C
G/B
Am/C
F/C

this one alternates between holding out a C-major7 chord and an arpeggio:

# switch between playing a chord for two measures 
# and an arpeggio of the chord

chain a b 

pattern a 
Cmaj7
-

pattern b
c4 e g b c e g b
c6 b g e c b g e

modulate two ccs (74 and 24) periodically:

74,100,24,40 74,99,24,40 74,99,24,42 74,99,24,45 
74,98,24,48 74,97,24,53 74,96,24,58 74,95,24,64 
74,94,24,69 74,92,24,75 74,91,24,81 74,89,24,86 
74,87,24,91 74,85,24,94 74,83,24,97 74,81,24,99 

this last example is actually generated from a lua script. though you can certainly type out the numbers you want, you can also generate your own cc lfo patterns on any number of ccs, just open ~/dust/code/tmi/lib/cc_lfo.lua and edit it and then run:

> lua ~/dust/code/tmi/lib/cc_lfo.lua > ~/dust/data/tmi/your_ccs
67 Likes

THAT DEMO! so simple, but so perfect- the absolute best combination

3 Likes

speechless! this is incredible! amazing idea, really.

1 Like

uh
yeah
this is INSANE

1 Like

how do you come up with this stuff; so fantastic! an amazing addition to yr other patches, stoked to play with this

1 Like

so simple and brilliant!
question: might be obvious so some, but why are the different tmi scripts playing different sounds on the plinky in the demo? are the different slots mapped to corresponding midi channels, or…?

1 Like

update: v1.1.0

  • you can now sequence cc’s
  • cc’s are just lists of pairs of numbers, they are chain-able like everything else (see the documentation above)

here’s a quick demo with tmi sequencing the chords and ccs. the ccs are modulating the vcf cutoff and envelope depth simultaneously (at two different frequencies). i’ve never tried this before and its actually quite cool imo:

i realize typing cc’s is wonky, so there is a script you can run (~/dust/code/tmi/lib/cc_lfo.lua) which you can use to generate the tmi files with lfos from ccs (could make this easier too if it seems useful).

thank you @glia for spurring this update!

the sounds sound different, but they are actually the same voice! just with different octave and velocity. plinky has 8 voices so you can keep adding tmi scripts until you run out of voices (i think that demo used 5). the adsr/filters/effects are the same across all the voices on plinky, though it would be awesome to be able to specify individually :slight_smile: i picked two parts that sounded good with the same adsr/filter/effects.

8 Likes

just amazing
thank you for adding my request so quickly!

1 Like

ah, i would never have guessed! but looking at the demo again, i guess it’s obvious that’s what the mezzo piano (mp) command does. is there comprehensive list of other commands for someone like me whose renaissance italian needs brushing up? : )

2 Likes

haha you actually don’t really need that at all anymore. instead of a mute button there is a “scaling” slider which you can use to scale the velocity/volume for notes so that a slot can be louder/softer than others. this also will work for cc’s, the values will be scaled up/down to change the range of its values too.

however if you want to have a bunch of different dynamics, then you can use the piano/forte commands. here there are also two choices though - you can either append the fortismo/pianismo command (pp, p, mp, mf, f, ff, or fff) or you can actually just supply a velocity number (0-127). so that means the following two tmi files are equivalent (each of these both play one note louder and louder):

c_mp d_mf e_f g_ff

is equal to

c_50 d_60 e_80 g_100

the “_X” syntax is not the loveliest thing in the world, which is why you can forgo entirely if you don’t need it and just use the “scaling” slider in the parameter menu if you don’t need to have each note be different.

3 Likes

thanks for the clarification! makes sense.

1 Like

HOLY SHIT. This is killer.

1 Like

i’m testing right now and not sure what it means…do i use cli on my laptop or maiden for this?

1 Like

that command specifically is for the laptop command-line. but you can run it from maiden if you wrap it in os.execute. i.e. this should work in maiden:

> os.execute("lua /home/we/dust/code/tmi/lib/cc_lfo.lua > /home/we/dust/data/tmi/your_ccs")
1 Like

Bonkers, in a good way. Great job! Does tmi pick up file changes on its own, or does the user reload the file?

1 Like

tmi automatically detects saved changes and reloads the file and continues playing from where it was (if you delete a measure though, it will cause a change in measures).

one caveat, currently it is a little clumsy as it will stop all the currently playing notes for that track instead of calculating which notes changed - this is to prevent notes from ringing out forever if you delete them while they are playing. i plan on upgrading this really soon (a pretty easy fix). this is fixed now :slight_smile:

3 Likes

This is really wild. I love it and really appreciate the ‘out of the box’ approach here.

1 Like

to be able to just write the chords! so so useful. thank you so much for this and all the rest.

edit: trying to use this with Orca, which, of course, has midi, the TMI menu is not immediately coming up with a Volca FM or digitakt plugged in. which is probably for the best, i don’t know why I need to have absolute control over every single thing. :stuck_out_tongue:

1 Like

Would it be possible to use tmi internally - let’s say for sequencing the root note within a script, for example?

1 Like

absolutely. you can do add this to the script, anywhere…but probably near the top will work most often:

if util.file_exists(_path.code.."tmi") then 
  tmi=include("tmi/lib/tmi")
  m=tmi:new()
  m:load("op-1","/home/we/dust/data/tmi/rootnote",1)
  m:toggle_play()
end

of course, change “op-1” to the your instrument (it will match any part of the name you put in). the toggle_play will have it start playing right away (you could also put toggle_play somewhere specific, like at a button press or something).

then you can make the /home/we/dust/data/tmi/rootnote file which contains your root note(s). here’s an example which changes between c and e every 4 beats:

c1
e1

hmmm. i just tried with orca and it works for me. where did you put your tmi code? (i put it at the very top of orca.lua). do you have those two devices listed in SYSTEM > DEVICES > MIDI ?

1 Like