relpipe-data/examples-jack-midi-generating-1.xml
author František Kučera <franta-hg@frantovo.cz>
Mon, 21 Feb 2022 01:21:22 +0100
branchv_0
changeset 330 70e7eb578cfa
parent 317 fce3d6290c40
permissions -rw-r--r--
Added tag relpipe-v0.18 for changeset 5bc2bb8b7946

<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>Generating and sending MIDI messages</nadpis>
	<perex>generate some sounds and send them to the JACK daemon</perex>
	<m:pořadí-příkladu>04500</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.
		</p>
		
		<p>
			While <code>relpipe-in-jack</code> can be used for <m:a href="examples-jack-midi-monitoring">monitoring MIDI messages</m:a> (<i>recording</i>),
			the <code>relpipe-out-jack</code> (since <m:a href="release-v0.17">v0.17</m:a>) is designed for sending messages to JACK (<i>playback</i>).
			So instead of playing <em>Standard MIDI Files</em> (.smf, .mid)
			we can read relational data and send them as MIDI messages to JACK daemon that forwards them to a hardware or software synthesizer
			or other program (called <i>client</i> in JACK terminology).
		</p>
		
		<p>
			The <code>relpipe-out-jack</code> reads relational data in the same format as <code>relpipe-in-jack</code>.
			So we can capture some MIDI data and play it later.
			But this is bit boring and any music sequencer would do a better job.
			We can have more fun with programmatically generating the „music“ (or rather just sounds in beginnings).
			Thanks to the nature of <m:name/>, the relation containing such „music“ can come from many various sources.
			In this example we will use the SQL language.
		</p>
		
		
		<h2>Connect and say hello to MT-32 (SysEx)</h2>
		
		<p>
			Before doing anything audible, we will start with saying hello to our sound module.
			We need a relation with two attributes. The first one is <code>event</code> and says what should be done.
			The second one <code>raw</code> contains the raw MIDI data. It is a SysEx message specific to Roland MT-32,
			but it can be any MIDI event:
		</p>
		
		<m:pre jazyk="bash"><![CDATA[relpipe-in-cli \
	--relation "midi" \
		--attribute "event" string \
		--attribute "raw" string \
		--record "sysex" "f0 41 10 16 12 20 00 00 52 65 6c 70 69 70 65 21 6e f7" \
	| relpipe-out-jack --connect-to j2a_bridge:playback]]></m:pre>
	
		<p>
			If we omit the <code>--connect-to j2a_bridge:playback</code> part, the <code>relpipe-out-jack</code> command
			will wait util we connect it somewhere e.g. using QjackCtl.
			We can control this behavior by explicitly specifying <code>--required-connections N</code> (default <code>N</code> is 1)
			and say e.g. „Wait until you have 3 connections and then start sending“.
			But because we specified the destination port, the <code>relpipe-out-jack</code> command immediately
			connects to it and sends data there.
		</p>
		
		<p>
			The <code>j2a_bridge:playback</code> port was created by the <code>j2amidi_bridge</code>
			that bridges JACK-MIDI and ALSA-MIDI.
			In QjackCtl or other tool, we can connect the ALSA end of this bridge to a physical interface (sound module, synthesizer).
			If we have no audio hardware, we omit this part and stay in the JACK world – we can connect our MIDI ports to various
			applications like Yoshimi, QMidiArp, Qtractor etc.
		</p>
		
		<p>
			See more details on MT-32 and MIDI SysEx in: <m:a href="examples-jack-midi-monitoring">Monitoring MIDI messages using JACK</m:a>.
		</p>
		
		<h2>Set the MIDI instruments for particular channels</h2>
		
		<p>
			Instruments (like particular pianos, guitars, drums, special effects etc.) can be set on our synthesizer for particular channels.
			However for reproducible results and more comfort, it is better to configure the instruments through MIDI commands (<i>Patch change</i>).
			Currently we misuse the <code>sysex</code> event for this and send this configuration as raw MIDI commands
			(the <code>c0 0e</code> and <code>c1 58</code> below).
			In later versions of <code>relpipe-out-jack</code>, there might be better support for instrument configuration.
		</p>
		
		<p>
			The list of standard instruments is available at MIDI.org: <a href="https://www.midi.org/specifications/item/gm-level-1-sound-set">General MIDI: GM 1 Sound Set</a>.
		</p>
		
		<h2>Play some SQL tones</h2>
		
		<p>
			Specifying the notes as raw MIDI messages is possible but uncomfortable.
			So we will put <code>note</code> in the <code>event</code> attribute
			and specify also <code>time</code>, <code>channel</code>, <code>note_on</code>, <code>note_pitch</code> and <code>note_velocity</code> attributes.
			The <code>relpipe-out-jack</code> will compose the raw MIDI event from these values.
		</p>
		
		<p>
			We are not going to create any tables or insert any records.
			Everything in this example is done in-memory by a single SELECT statement executed on an empty database.
			But of course, we can persist our creations in database tables and later play the music by SELECTing from them.
		</p>
		
		<m:pre jazyk="sql" odkaz="ano" src="examples/jack-midi-1.sql"/>
		
		<p>
			The SQL engine (SQLite by default) called from <code>relpipe-in-sql</code> converts our script into a relation.
			Then the <code>relpipe-out-jack</code> translates this relation to actual MIDI events and sends them to JACK system.
		</p>
		
		<m:pre jazyk="bash"><![CDATA[relpipe-in-sql \
	--relation "midi" "$(cat examples/jack-midi-1.sql)" \
	--type-cast 'note_on' boolean \
	| relpipe-out-jack \
		--connect-to j2a_bridge:playback \
		--connect-to relpipe-in-jack:midi-in]]></m:pre>
		
		<p>
			We connect it to two ports, so we can hear the sounds and at the same time, we can monitor the MIDI events
			(through <code>relpipe-in-jack</code> and usually <code>relpipe-out-csv</code>).
			We can also use <code>relpipe-out-tabular</code> instead of <code>relpipe-out-jack</code> and check generated data without sending them to JACK.
			For visual check, we can connect to the JACK port of a MIDI program like Qtractor and record there our creation (like recording from a MIDI keyboard).
			We can also do some real-time post-processing e.g. using QMidiArp (arpeggiator).
		</p>
		
		<p>
			If we have some hardware, it should look and sound like this:
		</p>
		
		<video src="https://blog.frantovo.cz/s/1601/jack-midi-1.webm" poster="img/sc-88-video-1.jpeg" controls="controls" width="820px">Maybe you often ask: What would MT-32 do?</video>
		
		<p>
			In this video, the Roland MT-32 and SC-88 Pro are daisy-chained and most sounds come from the SC-88.
		</p>
		
		<p>
			n.b. the MIDI channel 1 (index 0) is usually silent on MT-32 (default configuration).
		</p>
		
		
		
		<h2>Supported event types and attributes</h2>
		
		<p>
			The <code>relpipe-out-jack</code> supports following event types:
		</p>
		
		<ul>
			<li>
				<code>note</code>: press or release (depending on <code>note_on</code>) of particular key on keyboard
			</li>
			<li>
				<code>control</code>: change value of a controller (knob, slider, switch etc.)
			</li>
			<li>
				<code>sysex</code>: SystemExclusive command specific for particular device or manufacturer (e.g. show some text on the display)
			</li>
			<li>
				<code>connect</code>: link two JACK ports using a virtual cable
			</li>
			<li>
				<code>disconnect</code>: put that cable away
			</li>
		</ul>
		
		<p>
			Because the events of various types are usually interleaved, we pass them as records of one relation.
			Each type uses a different set of attributes:
		</p>
		
		<table>
			<thead>
				<tr>
					<td><code>event</code></td>
					<td><code>note</code></td>
					<td><code>control</code></td>
					<td><code>sysex</code></td>
					<td><code>connect</code></td>
					<td><code>disconnect</code></td>
				</tr>
			</thead>
			<tbody>
				<tr>
					<td><code>time</code></td>
					<td>✔</td>
					<td>✔</td>
					<td>✔</td>
					<td></td>
					<td></td>
				</tr>
				<tr>
					<td><code>channel</code></td>
					<td>✔</td>
					<td>✔</td>
					<td>✔</td>
					<td></td>
					<td></td>
				</tr>
				<tr>
					<td><code>note_on</code></td>
					<td>✔</td>
					<td></td>
					<td></td>
					<td></td>
					<td></td>
				</tr>
				<tr>
					<td><code>note_pitch</code></td>
					<td>✔</td>
					<td></td>
					<td></td>
					<td></td>
					<td></td>
				</tr>
				<tr>
					<td><code>note_velocity</code></td>
					<td>✔</td>
					<td></td>
					<td></td>
					<td></td>
					<td></td>
				</tr>
				<tr>
					<td><code>controller_id</code></td>
					<td></td>
					<td>✔</td>
					<td></td>
					<td></td>
					<td></td>
				</tr>
				<tr>
					<td><code>controller_value</code></td>
					<td></td>
					<td>✔</td>
					<td></td>
					<td></td>
					<td></td>
				</tr>
				<tr>
					<td><code>raw</code></td>
					<td></td>
					<td></td>
					<td>✔</td>
					<td></td>
					<td></td>
				</tr>
				<tr>
					<td><code>source_port</code></td>
					<td></td>
					<td></td>
					<td></td>
					<td>✔</td>
					<td>✔</td>
				</tr>
				<tr>
					<td><code>destination_port</code></td>
					<td></td>
					<td></td>
					<td></td>
					<td>✔</td>
					<td>✔</td>
				</tr>
			</tbody>
		</table>
		
		
		<p>
			Note: this design pattern is one of possible ways how to implement the <em>inheritance</em> (an object-oriented concept) in the relational world.
			The relation contains one attribute that determines the <i>type</i> (or <i>class</i>)
			and then union of all attributes of all that types.
			Each type uses just its relevant attributes and the rest is empty.
		</p>
		
		<p>
			The meaning of the attributes is following:
		</p>
		
		<table>
			<thead>
				<tr>
					<td>attribute</td>
					<td>type</td>
					<td>description</td>
				</tr>
			</thead>
			<tbody>
				<tr>
					<td>
						<code>event</code>
					</td>
					<td>
						<code>string</code>
					</td>
					<td>type of the record</td>
				</tr>
				<tr>
					<td>
						<code>time</code>
					</td>
					<td>
						<code>integer</code>
					</td>
					<td>time in microseconds since start of the playback</td>
				</tr>
				<tr>
					<td>
						<code>channel</code>
					</td>
					<td>
						<code>integer</code>
					</td>
					<td>number of the MIDI channel; starts from 0</td>
				</tr>
				<tr>
					<td>
						<code>note_on</code>
					</td>
					<td>
						<code>boolean</code>
					</td>
					<td>whether the key was pressed (<code>true</code>) or released (<code>false</code>)</td>
				</tr>
				<tr>
					<td>
						<code>note_pitch</code>
					</td>
					<td>
						<code>integer</code>
					</td>
					<td>pitch or tone; starts from 0; e.g. C4 is 60</td>
				</tr>
				<tr>
					<td>
						<code>note_velocity</code>
					</td>
					<td>
						<code>integer</code>
					</td>
					<td>force with which a note is played; 0-127</td>
				</tr>
				<tr>
					<td>
						<code>controller_id</code>
					</td>
					<td>
						<code>integer</code>
					</td>
					<td>number of the controller; starts from 0</td>
				</tr>
				<tr>
					<td>
						<code>controller_value</code>
					</td>
					<td>
						<code>integer</code>
					</td>
					<td>value of the controller; 0-127</td>
				</tr>
				<tr>
					<td>
						<code>raw</code>
					</td>
					<td>
						<code>string</code>
					</td>
					<td>raw MIDI bytes written in hexadecimal format; e.g. <code>91 3c 41</code></td>
				</tr>
				<tr>
					<td>
						<code>source_port</code>
					</td>
					<td>
						<code>string</code>
					</td>
					<td>name of the JACK output port; e.g. <code>system:capture_1</code></td>
				</tr>
				<tr>
					<td>
						<code>destination_port</code>
					</td>
					<td>
						<code>string</code>
					</td>
					<td>name of the JACK input port; e.g. <code>system:playback_1</code></td>
				</tr>
			</tbody>
		</table>
		
		<p>
			Besides the <code>event</code> we need to specify only attributes we use.
			So if we e.g. only send SysEx messages, we need only <code>event</code> and <code>raw</code> attributes.
			If the <code>time</code> is missing, the event is processed as soon as possible (in the next real-time cycle).
			The <code>time</code> attribute is used for precise timing 
			– so the process is not driven by the time when the event arrives on STDIN of the <code>relpipe-out-jack</code>.
		</p>
		

	</text>

</stránka>