relpipe-data/examples-jack-midi-monitoring.xml
author František Kučera <franta-hg@frantovo.cz>
Mon, 21 Feb 2022 00:43:11 +0100
branchv_0
changeset 329 5bc2bb8b7946
parent 313 a43265235e5a
permissions -rw-r--r--
Release v0.18

<stránka
	xmlns="https://trac.frantovo.cz/xml-web-generator/wiki/xmlns/strana"
	xmlns:m="https://trac.frantovo.cz/xml-web-generator/wiki/xmlns/makro">
	
	<nadpis>Monitoring MIDI messages using JACK</nadpis>
	<perex>examine events running through a JACK pipeline or bind MIDI keys to actions + bonus: Roland MT-32</perex>
	<m:pořadí-příkladu>04100</m:pořadí-příkladu>

	<text xmlns="http://www.w3.org/1999/xhtml">
		
		<p>
			A powerful audio system called <a href="https://jackaudio.org/">JACK</a> allows us to
			build pipelines consisting of audio interfaces, players, recorders, filters and effects…
			and route sound streams (both PCM and MIDI) through them.
			MIDI messages can come from keyboards or other hardware MIDI controllers or from MIDI players and other software.
			Sometimes it is useful to check what is happening under the hood and examine particular MIDI messages
			instead of just playing them on a sound module or synthesizer.
			In this example we will show how to bridge two seemingly unrelated worlds: real-time audio and relational pipes.
		</p>
		
		<p>
			We can join the JACK graph with <code>relpipe-in-jack</code> command.
			It does not consume STDIN, it gets events from JACK instead, so no other input data are needed.
		</p>
		
		<m:pre jazyk="bash">relpipe-in-jack | relpipe-out-csv</m:pre>
		
		<p>
			We are connected to the JACK daemon now, but no data are routed to us.
			So we need to direct some MIDI streams to our input:
		</p>
		
		<m:img src="img/jack-connections-1.png"/>
		
		<p>
			And then incoming MIDI events will generate output like this:
		</p>
		
		<pre><![CDATA["event","channel","note_on","note_pitch","note_velocity","controller_id","controller_value","raw"
"note","0","true","43","64","0","0","90 2b 40"
"note","0","false","43","64","0","0","80 2b 40"
"note","0","true","50","64","0","0","90 32 40"
"note","0","false","50","64","0","0","80 32 40"
"note","0","true","67","64","0","0","90 43 40"
"note","0","false","67","64","0","0","80 43 40"
"control","0","false","0","0","32","1","b0 20 01"
"control","0","false","0","0","0","0","b0 00 00"
"unknown","0","false","0","0","0","0","c0 00"
"note","0","true","36","64","0","0","90 24 40"
"note","0","false","36","64","0","0","80 24 40"
"sysex","0","false","0","0","0","0","f0 41 10 16 12 20 00 00 61 68 6f 6a 3e f7"
"note","0","true","60","64","0","0","90 3c 40"
"note","0","false","60","64","0","0","80 3c 40"]]></pre>
		
		<p>
			CSV is not the only option. Once data are in the machine-readable relational format,
			we can convert them into any other format or process them using any relational transformation.
			For ad-hoc monitoring, we can use <code>relpipe-out-gui</code> and watch MIDI messages – as they come –
			in a table in GUI:
		</p>
		
		<m:img src="img/jack-monitoring-gui-1.png"/>
		
		<p>
			As we can see, there are raw MIDI data and also some decoded values.
			Future versions of <code>relpipe-in-jack</code> should provide improved decoder and other features like timing information.
		</p>
		
		<p>
			We can use <code>relpipe-in-jack</code> not only for monitoring 
			but we can also write a simple script that binds particular MIDI events
			to actions to be executed – like starting a program or running a script on background.
			So we can map some keys/buttons/knobs on our piano, mixer or other controller:
		</p>
		
		<m:pre jazyk="bash"><![CDATA[#!/bin/bash

read_nullbyte() { local IFS=; for v in "$@"; do export "$v"; read -r -d '' "$v"; done }

relpipe-in-jack \
	| relpipe-out-nullbyte \
	| while read_nullbyte event channel note_on note_pitch velocity c_id c_value raw; do
		if   [[ "$note_pitch" == "21" && "$note_on" == "true" ]]; then kcalc &
		elif [[ "$note_pitch" == "23" && "$note_on" == "true" ]]; then dolphin &
		fi
	done]]></m:pre>
		
		<p>
			Many audio applications have similar feature, 
			but we can leave this script running on the background 
			even when we do not want to have loaded a complex software like a DAW (Digital audio workstation).
		</p>
		
		
		<h2 id="mt32_display_message">Bonus: display messages on Roland MT-32</h2>
		
		<p>
			Maybe you remember games or MIDI files that <i>magically</i> displayed text messages on your 
			<a href="https://en.wikipedia.org/wiki/Roland_MT-32">MT-32</a> unit 
			which you used to generate wonderful sounds and music from the MIDI signal.
			Let us look inside and check how this <i>magic</i> works.
		</p>
		
		<p>
			We have to route the MIDI signal through JACK and fork it there (similarly to <code>tee</code> in shell)
			so it will flow both to the MT-32 and the <code>relpipe-in-jack</code> process.
		</p>
		
		<p>
			Given that we have running the JACK daemon (can be started from GUI application like QjackCtl)
			and <code>a2j</code> which bridges ALSA-MIDI and JACK-MIDI together.
			We set up the routing (the fork) and then play a SMF (Standard MIDI file) file:
		</p>
		
		<pre>aplaymidi --port=14:0 test.mid</pre>
		
		<p>Proper port number could be found here:</p>
		
		<pre><![CDATA[$ aplaymidi -l
 Port    Client name                      Port name
 14:0    Midi Through                     Midi Through Port-0
 24:0    Rubix44                          Rubix44 MIDI 1]]></pre>
 
		<p>
			Data sent to the <i>Midi Through</i> port in the ALSA-MIDI emerges in the <code>a2j</code> in the JACK-MIDI graph
			and then flows to <code>relpipe-in-jack</code>.
			So the MT-32 will play the sounds and display messages (if any) and we will get copy of everything in
			<code>relpipe-in-jack</code> that passes data to command like <code>relpipe-out-gui</code>
			or <code>relpipe-out-csv</code> where we see decoded messages and also raw MIDI data.
		</p>
		
		<p>
			n.b. the <i>Midi Through</i> in the ALSA-MIDI graph should be connected to our audio interface 
			(e.g. <a href="https://blog.frantovo.cz/c/365/Roland%20Rubix44%20%E2%80%93%20extern%C3%AD%20zvukov%C3%A1%20karta">Rubix44</a>)
			which is linked to the MT-32 using a MIDI cable.
		</p>
	
		<p>
			Messages that cause text to be showed on the MT-32 display are so called <i>System Exclusive (SysEx) messages</i>.
			After executing the <code>aplaymidi</code> we see for example:
		</p>
		
		<m:img src="img/mt-32-display-1.jpeg"/>
		
		<p>
			And <code>relpipe-in-jack</code> captured and reported this SysEx message:
		</p>
		
		<pre>f0 41 10 16 12 20 00 00 <strong>52 65 6c 61 74 69 6f 6e 61 6c 20 70 69 70 65 73</strong> 14 f7</pre>
		
		<p>
			The highlighted part (52 … 73) is easy – it is just the <code>Relational pipes</code> ASCII bytes in HEX.
			But what does the rest mean?
		</p>
		
		<ul>
			<li><code>f0</code> = start of SysEx message</li>
			<li><code>41</code> = Roland <a href="https://www.midi.org/specifications-old/item/manufacturer-id-numbers">manufacturer ID</a>. This is important because SysEx messages are vendor-specific. So devices from other manufacturers (that might be in the same MIDI daisy-chain) will know, that this message is not for them and will ignore it.</li>
			<li><code>10</code> = device ID – if we have more units with same manufacturer and model ID, we should assign them different device IDs, so we can address them individually.</li>
			<li><code>16</code> = model ID</li>
			<li><code>12</code> = command ID, 12 is set, 11 is get</li>
			<li><code>20 00 00</code> = the address of the value we want to set, 20 00 00 is the text to be displayed</li>
			<li><code>14</code> = checksum computed from the <code>20 00 00 … 73</code> part</li>
			<li><code>f7</code> = end of the SysEx message</li>
		</ul>
		
		<p>
			Only the start and end of the SysEx message and the manufacturer ID are part of the MIDI standard.
			The rest of the bytes is Roland specific. SysEx messages can do much more than controlling the display – consult the documentation for particular device.
		</p>
		
	
		<p>
			We can generate our own messages using the <a href="https://hg.frantovo.cz/midi/mt-32-display/">mt-32-display</a> tool.
			It produces SysEx messages for Roland MT-32 in hex format which can be passed directly to the <code>amidi</code> command (see examples in the code).
			Unfortunately <code>amidi</code> works only with hardware ports and is unable to route through JACK.
			But there is another tool called <a href="https://hg.frantovo.cz/midi/sysex2smf/">sysex2smf</a>
			which translates raw SysEx data to Standard MIDI file (<code>*.mid</code>).
			And SMF can be played using the <code>aplaymidi</code> which can be routed through JACK and our pipelines.
			So the 48 lines of C++ code (both tools together) is everything we need to enjoy this nice feature of our MT-32 unit.
		</p>

		<video src="https://blog.frantovo.cz/s/1581/mt-32.webm" poster="img/mt-32-video-1.jpeg" controls="controls" width="820px">Maybe you often ask: What would MT-32 do?</video>
		
		
	</text>

</stránka>