examples: Monitoring MIDI messages using JACK – relpipe-in-jack v_0
authorFrantišek Kučera <franta-hg@frantovo.cz>
Thu, 21 May 2020 01:23:23 +0200
branchv_0
changeset 296 418e11eb6fea
parent 295 72dc2469c438
child 297 192b0059a6c4
examples: Monitoring MIDI messages using JACK – relpipe-in-jack
relpipe-data/examples-jack-midi-monitoring.xml
relpipe-data/img/jack-connections-1.png
relpipe-data/img/jack-monitoring-gui-1.png
relpipe-data/img/mt-32-display-1.jpeg
relpipe-data/img/mt-32-video-1.jpeg
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/relpipe-data/examples-jack-midi-monitoring.xml	Thu May 21 01:23:23 2020 +0200
@@ -0,0 +1,188 @@
+<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-gui</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>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>
Binary file relpipe-data/img/jack-connections-1.png has changed
Binary file relpipe-data/img/jack-monitoring-gui-1.png has changed
Binary file relpipe-data/img/mt-32-display-1.jpeg has changed
Binary file relpipe-data/img/mt-32-video-1.jpeg has changed