Release v0.16 – JACK MIDI output, ports + rename Guile to Scheme + improve CLI interfaces v_0
authorFrantišek Kučera <franta-hg@frantovo.cz>
Thu, 22 Oct 2020 01:51:32 +0200
branchv_0
changeset 317 fce3d6290c40
parent 316 d7ae02390fac
child 318 137f63652fa2
Release v0.16 – JACK MIDI output, ports + rename Guile to Scheme + improve CLI interfaces
relpipe-data/download.xml
relpipe-data/examples-hello-world.xml
relpipe-data/examples-jack-midi-generating-1.xml
relpipe-data/examples-jack-ports.xml
relpipe-data/examples/jack-midi-1.sql
relpipe-data/examples/mercurial-hg-xmltable-sql.sh
relpipe-data/examples/release-v0.17.sh
relpipe-data/examples/relpipe-out-fstab.sh
relpipe-data/img/jack-connections-2.png
relpipe-data/img/sc-88-video-1.jpeg
relpipe-data/release-v0.17.xml
relpipe-data/roadmap.xml
--- a/relpipe-data/download.xml	Fri Sep 25 14:38:24 2020 +0200
+++ b/relpipe-data/download.xml	Thu Oct 22 01:51:32 2020 +0200
@@ -31,6 +31,7 @@
 hg clone https://hg.globalcode.info/relpipe/relpipe-out-asn1.cpp;
 hg clone https://hg.globalcode.info/relpipe/relpipe-out-csv.cpp;
 hg clone https://hg.globalcode.info/relpipe/relpipe-out-gui.qt.cpp;
+hg clone https://hg.globalcode.info/relpipe/relpipe-out-jack.cpp;
 hg clone https://hg.globalcode.info/relpipe/relpipe-out-nullbyte.cpp;
 hg clone https://hg.globalcode.info/relpipe/relpipe-out-ods.cpp;
 hg clone https://hg.globalcode.info/relpipe/relpipe-out-recfile.cpp;
@@ -56,9 +57,14 @@
 		
 		<m:pre jazyk="bash"><![CDATA[ls -1d relpipe-* | while read r; do hg pull --update --repository "$r"; done]]></m:pre>
 		
+		<p>
+			Build instructions are in release notes below.
+		</p>
+		
 		<h2>Released versions</h2>
 			
 		<ul>
+			<li>2020-10-20: <m:a href="release-v0.17">v0.17</m:a></li>
 			<li>2020-06-06: <m:a href="release-v0.16">v0.16</m:a></li>
 			<li>2020-01-31: <m:a href="release-v0.15">v0.15</m:a></li>
 			<li>2019-10-30: <m:a href="release-v0.14">v0.14</m:a></li>
--- a/relpipe-data/examples-hello-world.xml	Fri Sep 25 14:38:24 2020 +0200
+++ b/relpipe-data/examples-hello-world.xml	Thu Oct 22 01:51:32 2020 +0200
@@ -12,25 +12,27 @@
 			Let's start with an obligatory Hello World example.
 		</p>
 		
-		<m:pre jazyk="bash"><![CDATA[relpipe-in-cli generate "relation_from_cli" 3 \
-	"a" "integer" \
-	"b" "string" \
-	"c" "boolean" \
-	"1" "Hello" "true" \
-	"2" "World!" "false"]]></m:pre>
+		<m:pre jazyk="bash"><![CDATA[relpipe-in-cli \
+		--relation "relation_from_cli" \
+			--attribute "a" "integer" \
+			--attribute "b" "string" \
+			--attribute "c" "boolean" \
+			--record "1" "Hello" "true" \
+			--record "2" "World!" "false"]]></m:pre>
 	
 		<p>
 			This command generates relational data.
 			In order to see them, we need to convert them to some other format.
-			For now, we will use the "tabular" format and pipe relational data to the <code>relpipe-out-tabular</code>.
+			For now, we will use the „tabular“ format and pipe relational data to the <code>relpipe-out-tabular</code>.
 		</p>
 		
-		<m:pre jazyk="bash"><![CDATA[relpipe-in-cli generate "relation_from_cli" 3 \
-		"a" "integer" \
-		"b" "string" \
-		"c" "boolean" \
-		"1" "Hello" "true" \
-		"2" "World!" "false" \
+		<m:pre jazyk="bash"><![CDATA[relpipe-in-cli \
+		--relation "relation_from_cli" \
+			--attribute "a" "integer" \
+			--attribute "b" "string" \
+			--attribute "c" "boolean" \
+			--record "1" "Hello" "true" \
+			--record "2" "World!" "false" \
 	| relpipe-out-tabular]]></m:pre>
 	
 		<p>Output:</p>
@@ -46,8 +48,8 @@
 ]]></pre>
 
 		<p>
-			The syntax is simple as we see above. We specify the name of the relation, number of attributes,
-			and then their definitions (names and types),
+			The syntax is simple as we see above. We specify the name of the relation
+			and the names and types of attributes
 			followed by the data.
 		</p>
 
@@ -55,8 +57,8 @@
 			A single stream may contain multiple relations:
 		</p>		
 		
-		<m:pre jazyk="bash"><![CDATA[(relpipe-in-cli generate a 1 x string hello; \
- relpipe-in-cli generate b 1 y string world) \
+		<m:pre jazyk="bash"><![CDATA[(relpipe-in-cli --relation "a" --attribute "x" string --record "hello"; \
+ relpipe-in-cli --relation "b" --attribute "y" string --record "world") \
 	| relpipe-out-tabular]]></m:pre>
 			
 		<p>
@@ -77,6 +79,38 @@
  │ world      │
  ╰────────────╯
 Record count: 1]]></pre>
+
+		<p>
+			In the example above, we call <code>relpipe-in-cli</code> twice and let the shell combine their outputs.
+			This approach is useful when we want to combine relational data from various sources: different <code>relpipe-in-*</code> tools, files etc.
+			But when we work with <code>relpipe-in-cli</code> only, we can ask it to create several relations during one run:
+		</p>
+		
+		<m:pre jazyk="bash"><![CDATA[relpipe-in-cli \
+		--relation "a" --attribute "x" string --record "hello" \
+		--relation "b" --attribute "y" string --record "world" \
+	| relpipe-out-tabular]]></m:pre>
+	
+		<p>
+			The result will be the same.
+			We can also use the <code>--records</code> option instead of the <code>--record</code> option – then the rest of the CLI arguments is treated as data of given relation.
+			Obviously this option can be used only once for the last relation.
+		</p>
+		
+		<m:pre jazyk="bash"><![CDATA[relpipe-in-cli \
+		--relation "relation_from_cli" \
+			--attribute "a" "integer" \
+			--attribute "b" "string" \
+			--attribute "c" "boolean" \
+			--records \
+				"1" "Hello" "true" \
+				"2" "World!" "false" \
+	| relpipe-out-tabular]]></m:pre>
+	
+		<p>
+			It will generate the same <code>relation_from_cli</code> table as above.
+			If we have more data (especially from external sources), we can use the <code>--records-on-stdin</code> option and pass them through the <m:a href="examples-cli-stdin">STDIN</m:a>.
+		</p>
 		
 	</text>
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/relpipe-data/examples-jack-midi-generating-1.xml	Thu Oct 22 01:51:32 2020 +0200
@@ -0,0 +1,398 @@
+<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>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/relpipe-data/examples-jack-ports.xml	Thu Oct 22 01:51:32 2020 +0200
@@ -0,0 +1,170 @@
+<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>Working with JACK ports</nadpis>
+	<perex>list ports and connections, connect and disconnect ports, both MIDI and audio</perex>
+	<m:pořadí-příkladu>04400</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>
+			In JACK, we have <em>clients</em> (applications) and they have <em>ports</em> (input and output channels).
+			The JACK graph consists of connections between input and output ports.
+			There might be multiple connections from or to a single port – singals are then replicated or combined.
+			Obviously, we can connect MIDI ports only to other MIDI ports and PCM/audio ports only to other ports of the same kind.
+			However there can be applications with both kinds of ports that e.g. translate MIDI signal to audio signal (synthesizers).
+		</p>
+		
+		<m:img src="img/jack-connections-2.png"/>
+		
+		<p>
+			The JACK <em>daemon</em> is responsible for maintaining the graph and transmitting the messages.
+			Clients connect to the <em>daemon</em>.
+		</p>
+		
+		<p>
+			Since <m:a href="release-v0.17">v0.17</m:a>, we can list the ports using the <code>relpipe-in-jack</code> command:
+		</p>
+		
+		<m:pre jazyk="bash"><![CDATA[relpipe-in-jack --list-ports true --list-midi-messages false | relpipe-out-tabular]]></m:pre>
+
+		<p>and see it as a relation:</p>
+		
+		<pre><![CDATA[port:
+ ╭───────────────────────────────────┬───────────────┬─────────────────┬──────────────────┬────────────────────┬────────────────────┬────────────────┬────────────────┬─────────────────────────╮
+ │ name                     (string) │ uuid (string) │ input (boolean) │ output (boolean) │ physical (boolean) │ terminal (boolean) │ mine (boolean) │ midi (boolean) │ type           (string) │
+ ├───────────────────────────────────┼───────────────┼─────────────────┼──────────────────┼────────────────────┼────────────────────┼────────────────┼────────────────┼─────────────────────────┤
+ │ system:capture_1                  │               │           false │             true │               true │               true │          false │          false │ 32 bit float mono audio │
+ │ system:capture_2                  │               │           false │             true │               true │               true │          false │          false │ 32 bit float mono audio │
+ │ system:playback_1                 │               │            true │            false │               true │               true │          false │          false │ 32 bit float mono audio │
+ │ system:playback_2                 │               │            true │            false │               true │               true │          false │          false │ 32 bit float mono audio │
+ │ j2a_bridge:playback               │               │            true │            false │              false │              false │          false │           true │ 8 bit raw midi          │
+ │ relpipe-in-jack_processed:midi-in │               │            true │            false │              false │              false │          false │           true │ 8 bit raw midi          │
+ │ relpipe-out-jack:midi-out         │               │           false │             true │              false │              false │          false │           true │ 8 bit raw midi          │
+ │ a2j_bridge:capture                │               │           false │             true │              false │              false │          false │           true │ 8 bit raw midi          │
+ │ yoshimi:left                      │               │           false │             true │              false │              false │          false │          false │ 32 bit float mono audio │
+ │ yoshimi:right                     │               │           false │             true │              false │              false │          false │          false │ 32 bit float mono audio │
+ │ yoshimi:midi in                   │               │            true │            false │              false │              false │          false │           true │ 8 bit raw midi          │
+ │ Qtractor:Master/in_1              │               │            true │            false │              false │              false │          false │          false │ 32 bit float mono audio │
+ │ Qtractor:Master/in_2              │               │            true │            false │              false │              false │          false │          false │ 32 bit float mono audio │
+ │ Qtractor:Master/out_1             │               │           false │             true │              false │              false │          false │          false │ 32 bit float mono audio │
+ │ Qtractor:Master/out_2             │               │           false │             true │              false │              false │          false │          false │ 32 bit float mono audio │
+ │ qmidiarp:in                       │               │            true │            false │              false │              false │          false │           true │ 8 bit raw midi          │
+ │ qmidiarp:out 1                    │               │           false │             true │              false │              false │          false │           true │ 8 bit raw midi          │
+ │ qmidiarp:out 2                    │               │           false │             true │              false │              false │          false │           true │ 8 bit raw midi          │
+ │ jack-keyboard:midi_out            │               │           false │             true │              false │              false │          false │           true │ 8 bit raw midi          │
+ │ jack-keyboard:midi_in             │               │            true │            false │              false │              false │          false │           true │ 8 bit raw midi          │
+ │ relpipe-in-jack_original:midi-in  │               │            true │            false │              false │              false │          false │           true │ 8 bit raw midi          │
+ │ relpipe-in-jack:midi-in           │               │            true │            false │              false │              false │           true │           true │ 8 bit raw midi          │
+ ╰───────────────────────────────────┴───────────────┴─────────────────┴──────────────────┴────────────────────┴────────────────────┴────────────────┴────────────────┴─────────────────────────╯
+Record count: 22]]></pre>
+
+		<p>
+			Port names are prefixed with the names of clients.
+			We see the port direction in the <code>input</code> and <code>output</code> attributes
+			and can distinguish MIDI and audio ports by the value of the <code>midi</code> attribute.
+		</p>
+		
+		<p>
+			We can also list the connections using the <code>--list-connections true</code> option:
+		</p>
+		
+		<pre><![CDATA[connection:
+ ╭────────────────┬───────────────────────────┬───────────────────────────────────╮
+ │ event (string) │ source_port      (string) │ destination_port         (string) │
+ ├────────────────┼───────────────────────────┼───────────────────────────────────┤
+ │ connect        │ system:capture_1          │ Qtractor:Master/in_1              │
+ │ connect        │ system:capture_2          │ Qtractor:Master/in_2              │
+ │ connect        │ relpipe-out-jack:midi-out │ qmidiarp:in                       │
+ │ connect        │ relpipe-out-jack:midi-out │ relpipe-in-jack_original:midi-in  │
+ │ connect        │ yoshimi:left              │ system:playback_1                 │
+ │ connect        │ yoshimi:right             │ system:playback_2                 │
+ │ connect        │ Qtractor:Master/out_1     │ system:playback_1                 │
+ │ connect        │ Qtractor:Master/out_2     │ system:playback_2                 │
+ │ connect        │ qmidiarp:out 1            │ yoshimi:midi in                   │
+ │ connect        │ qmidiarp:out 1            │ relpipe-in-jack_processed:midi-in │
+ │ connect        │ jack-keyboard:midi_out    │ qmidiarp:in                       │
+ │ connect        │ jack-keyboard:midi_out    │ relpipe-in-jack_original:midi-in  │
+ ╰────────────────┴───────────────────────────┴───────────────────────────────────╯
+Record count: 12]]></pre>
+
+		<p>
+			Instead of formatting as a table, we can direct this relation into a file and later recreate the saved connections:
+		</p>
+		
+		<m:pre jazyk="bash"><![CDATA[relpipe-in-jack --list-connections true --list-midi-messages false > connections.rp
+cat connections.rp | relpipe-out-jack --required-connections 0]]></m:pre>
+
+		<p>
+			If we want to store the connections in a human readable format in order to be able to edit them,
+			we should add e.g. <code>relpipe-out-csv</code> (or XML, or Recfile) stage before redirecting the stream to the file
+			and add <code>relpipe-in-csv</code> etc. stage to the second pipeline.
+		</p>
+		
+		<pre><![CDATA["event","source_port","destination_port"
+"connect","system:capture_1","Qtractor:Master/in_1"
+"connect","system:capture_2","Qtractor:Master/in_2"
+"connect","relpipe-out-jack:midi-out","qmidiarp:in"
+"connect","relpipe-out-jack:midi-out","relpipe-in-jack_original:midi-in"
+"connect","yoshimi:left","system:playback_1"
+"connect","yoshimi:right","system:playback_2"
+"connect","Qtractor:Master/out_1","system:playback_1"
+"connect","Qtractor:Master/out_2","system:playback_2"
+"connect","qmidiarp:out 1","yoshimi:midi in"
+"connect","qmidiarp:out 1","relpipe-in-jack_processed:midi-in"
+"connect","jack-keyboard:midi_out","qmidiarp:in"
+"connect","jack-keyboard:midi_out","relpipe-in-jack_original:midi-in"]]></pre>
+
+		
+		<p>
+			Or we can write the file by hand and just send it to the JACK output module:
+		</p>
+		
+		<m:pre jazyk="bash"><![CDATA[cat connections.csv | relpipe-in-csv | relpipe-out-jack --required-connections 0]]></m:pre>
+
+		<p>
+			The primary purpose of the <code>relpipe-out-jack</code> is sending MIDI messages.
+			And because it does not make much sense to send them nowhere, it waits for at least one connection.
+			But if we are not sending any messages and are using this tool just to connect or disconnect the ports,
+			we should set <code>--required-connections 0</code>.
+		</p>
+		
+		<p>
+			We can also connect or disconnect particular ports specified on the command line:
+		</p>
+		
+		<m:pre jazyk="bash"><![CDATA[relpipe-in-jack --connect-ports "a2j_bridge:capture" "qmidiarp:in" --list-midi-messages false]]></m:pre>
+
+		<p>
+			The primary purpose of the <code>relpipe-in-jack</code> command is monitoring the MIDI commands.
+			If we want just to connect or disconnect some ports, we can disable monitoring by setting <code>--list-midi-messages false</code>
+			and the command will return immediately.
+		</p>
+		
+		<p>
+			The port names are suggested by the Bash-completion, so we do not have to memorize them.
+			Because these names contain the colon, we should use quotes (otherwise the Bash-completion may be confused).
+		</p>
+		
+		<p>
+			Disconnecting works the same way – just use the <code>--disconnect-ports</code> option
+			or specify the <code>disconnect</code> command in the <code>event</code> attribute.
+		</p>
+
+		<p>
+			Note: there are sophisticated GUI tools focused on working with the JACK graph
+			like <a href="https://qjackctl.sourceforge.io/">QjackCtl</a> or <a href="https://kx.studio/Applications:Claudia">KXStudio/Claudia</a>.
+			But sometimes it is useful to have a simple CLI tool for this job.
+		</p>
+
+	</text>
+
+</stránka>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/relpipe-data/examples/jack-midi-1.sql	Thu Oct 22 01:51:32 2020 +0200
@@ -0,0 +1,77 @@
+WITH
+	-- Configuration parameters:
+	duration AS (SELECT    16 AS value), -- in seconds
+	bpm      AS (SELECT   120 AS value), -- beats per minute
+
+	-- Numbered beats, the outline:
+	beat AS (
+		WITH RECURSIVE beat0 AS (
+			SELECT 0 AS value
+			UNION ALL
+			SELECT beat0.value + 1 FROM beat0, duration, bpm
+			WHERE beat0.value < (duration.value * bpm.value / 60 - 1)
+		)
+		SELECT * FROM beat0
+	),
+
+	-- Set instruments for particular channels:
+	raw AS (
+		SELECT 0 AS time, 'c0 0e' AS raw UNION ALL   -- channel 1 = Tubular Bells
+		SELECT 0 AS time, 'c1 58' AS raw             -- channel 2 = Fantasia
+	),
+
+	-- Parts (quite random sounds):
+
+	drums_1 AS (
+		SELECT
+			9 AS channel,
+			beat.value AS beat, NULL AS custom_time,
+			250 * 1000 AS duration,
+			CASE WHEN beat.value % 4 IN (0,1,2) THEN 35 ELSE 40 END AS note_pitch,
+			80 AS note_velocity
+		FROM beat, bpm
+	),
+
+	bells_1 AS (
+		SELECT
+			0 AS channel,
+			beat.value AS beat, NULL AS custom_time,
+			500 * 1000 AS duration,
+			CASE WHEN beat.value / 4 % 2 = 0 THEN 68 ELSE 55 END AS note_pitch,
+			90 AS note_velocity
+		FROM beat, bpm
+		WHERE beat.value % 4 IN (1)
+	),
+
+	fantasia_1 AS (
+		SELECT
+			1 AS channel,
+			beat.value AS beat, NULL AS custom_time,
+			500 * 1000 AS duration,
+			60 + beat.value % 4 AS note_pitch,
+			90 AS note_velocity
+		FROM beat, bpm
+		WHERE beat.value % 4 IN (2,3,0)
+	),
+
+	-- Put all parts together:
+	notes AS (
+		SELECT
+			part.*,
+			CASE
+				WHEN custom_time IS NULL THEN beat * 1000 * 1000 * 60 / bpm.value
+				ELSE CAST(custom_time AS integer)
+			END AS time
+		FROM (
+			SELECT * FROM drums_1        UNION ALL
+			SELECT * FROM bells_1        UNION ALL
+			SELECT * FROM fantasia_1
+		) AS part, bpm
+	)
+
+-- We need to emit two MIDI events: one for key press and one for key release.
+-- So we add the release events (note_on = false) derived from the time and duration values.
+SELECT 'note'  AS event, time,                  channel, 1 AS note_on,      note_pitch,      note_velocity, '' AS raw FROM notes   UNION ALL
+SELECT 'note'  AS event, time+duration AS time, channel, 0 AS note_on,      note_pitch,      note_velocity, '' AS raw FROM notes   UNION ALL
+SELECT 'sysex' AS event, time,             0 AS channel, 0 AS note_on, 0 AS note_pitch, 0 AS note_velocity,       raw FROM raw
+ORDER BY time ASC, event DESC;
--- a/relpipe-data/examples/mercurial-hg-xmltable-sql.sh	Fri Sep 25 14:38:24 2020 +0200
+++ b/relpipe-data/examples/mercurial-hg-xmltable-sql.sh	Thu Oct 22 01:51:32 2020 +0200
@@ -22,10 +22,10 @@
 		| sed -E 's/([^ \s]+)\s+([0-9]+):(.*)/\1\n\2\n\3/g' \
 		| tr \\n \\0 \
 		| relpipe-in-cli \
-			generate-from-stdin hg_tags 3 \
-				tag string \
-				revision integer \
-				hash_short string
+			--relation "hg_tags" \
+				--attribute "tag" string \
+				--attribute "revision" integer \
+				--attribute "hash_short" string
 }
 
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/relpipe-data/examples/release-v0.17.sh	Thu Oct 22 01:51:32 2020 +0200
@@ -0,0 +1,53 @@
+# Install dependencies as root:
+apt install g++ make cmake mercurial pkg-config
+apt install libxerces-c-dev       # needed only for relpipe-in-xml module
+apt install guile-2.2-dev         # needed only for relpipe-tr-scheme module
+apt install gawk                  # needed only for relpipe-tr-awk module
+apt install libxml++2.6-dev       # needed only for relpipe-in-xmltable module
+apt install unixodbc-dev          # needed only for relpipe-tr-sql module
+apt install libsqliteodbc         # needed only for relpipe-tr-sql module if used with SQLite
+apt install odbc-postgresql       # needed only for relpipe-tr-sql module if used with PostgreSQL
+apt install libjack-jackd2-dev    # needed only for relpipe-in-jack and relpipe-out-jack modules; Jack1 should also work
+
+# Run rest of installation as a non-root user:
+export RELPIPE_VERSION="v0.17"
+export RELPIPE_SRC=~/src
+export RELPIPE_BUILD=~/build
+export RELPIPE_INSTALL=~/install
+export PKG_CONFIG_PATH="$RELPIPE_INSTALL/lib/pkgconfig/:$PKG_CONFIG_PATH"
+export PATH="$RELPIPE_INSTALL/bin:$PATH"
+
+rm -rf "$RELPIPE_BUILD"/relpipe-*
+mkdir -p "$RELPIPE_SRC" "$RELPIPE_BUILD" "$RELPIPE_INSTALL"
+
+# Helper functions:
+relpipe_download() { for m in "$@"; do cd "$RELPIPE_SRC" && ([[ -d "relpipe-$m.cpp" ]] && hg pull -R "relpipe-$m.cpp" && hg update -R "relpipe-$m.cpp" "$RELPIPE_VERSION" || hg clone -u "$RELPIPE_VERSION" https://hg.globalcode.info/relpipe/relpipe-$m.cpp) || break; done; }
+relpipe_install()  { for m in "$@"; do cd "$RELPIPE_BUILD" && mkdir -p relpipe-$m.cpp && cd relpipe-$m.cpp && cmake -DCMAKE_INSTALL_PREFIX:PATH="$RELPIPE_INSTALL" "$RELPIPE_SRC/relpipe-$m.cpp" && make && make install || break; done; }
+
+# Download all sources:
+relpipe_download lib-common lib-reader lib-writer lib-cli lib-xmlwriter in-cli in-fstab in-xml in-xmltable in-csv in-filesystem in-recfile out-gui.qt out-nullbyte out-ods out-tabular out-xml out-csv out-asn1 out-recfile tr-cut tr-grep tr-python tr-sed tr-validator tr-scheme tr-awk tr-sql in-jack out-jack
+
+# Optional: At this point, we have all dependencies and sources downloaded, so we can disconnect this computer from the internet in order to verify that our build process is sane, deterministic and does not depend on any external resources.
+
+# Build and install libraries:
+relpipe_install lib-common lib-reader lib-writer lib-cli lib-xmlwriter
+
+# Build and install tools:
+relpipe_install in-fstab in-cli in-fstab in-xml in-xmltable in-csv in-recfile tr-cut tr-grep tr-sed tr-scheme tr-awk tr-sql out-nullbyte out-ods out-tabular out-xml out-csv out-asn1 out-recfile in-filesystem in-jack out-jack
+
+# Load Bash completion scripts:
+for c in "$RELPIPE_SRC"/relpipe-*/bash-completion.sh ; do . "$c"; done
+
+# Enable streamlet examples:
+export RELPIPE_IN_FILESYSTEM_STREAMLET_PATH="$RELPIPE_SRC"/relpipe-in-filesystem.cpp/streamlet-examples/
+
+# Clean-up:
+unset -f relpipe_install
+unset -f relpipe_download
+unset -v RELPIPE_VERSION
+unset -v RELPIPE_SRC
+unset -v RELPIPE_BUILD
+unset -v RELPIPE_INSTALL
+
+# List available JACK ports (the JACK daemon should be running):
+relpipe-in-jack --list-ports true --list-midi-messages false | relpipe-out-tabular
--- a/relpipe-data/examples/relpipe-out-fstab.sh	Fri Sep 25 14:38:24 2020 +0200
+++ b/relpipe-data/examples/relpipe-out-fstab.sh	Thu Oct 22 01:51:32 2020 +0200
@@ -2,9 +2,16 @@
 
 (
 	# Just troll-in the first record:
-	relpipe-in-cli generate Heathers 7 \
-		Duke string McNamara string Chandler string Veronica string J.D. string \
-		Big string Fun string \
+	relpipe-in-cli \
+		--relation "Heathers" \
+			--attribute "Duke" string \
+			--attribute "McNamara" string \
+			--attribute "Chandler" string \
+			--attribute "Veronica" string \
+			--attribute "J.D." string \
+			--attribute "Big" string \
+			--attribute "Fun" string \
+			--record \
 		'' '# <file system>' '<mount point>' '<type>' '<options>' '<dump>' '<pass>';
 		# relpipe-out-nullbyte processes only attribute values
 	# Read the actual pipe's input:
Binary file relpipe-data/img/jack-connections-2.png has changed
Binary file relpipe-data/img/sc-88-video-1.jpeg has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/relpipe-data/release-v0.17.xml	Thu Oct 22 01:51:32 2020 +0200
@@ -0,0 +1,275 @@
+<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>Release v0.17</nadpis>
+	<perex>new public release of Relational pipes</perex>
+	<m:release>v0.17</m:release>
+
+	<text xmlns="http://www.w3.org/1999/xhtml">
+		<p>
+			We are pleased to introduce you the new development version of <m:name/>.
+			This release improves and standardizes the CLI interface of several tools, brings a new output module + several smaller improvements.
+		</p>
+		
+		<ul>
+			<li>
+				<strong>The <code>relpipe-in-cli</code> module has changed CLI interface</strong>: see details below
+			</li>
+			<li>
+				<strong>The <code>relpipe-in-csv</code> module has changed CLI interface</strong>: see details below
+			</li>
+			<li>
+				<strong>The <code>relpipe-out-csv</code> module has new CLI interface</strong>: see details below
+			</li>
+			<li>
+				<strong>The <code>relpipe-out-tabular</code> module has new CLI interface</strong>: see details below
+			</li>
+			<li>
+				<strong>The <code>relpipe-tr-guile</code> was renamed to <code>relpipe-tr-scheme</code></strong>: see details below
+			</li>
+			<li>
+				<strong>New tool <code>relpipe-out-jack</code> for generating MIDI through JACK</strong>: see details below
+			</li>
+		</ul>
+		
+		<p>
+			See the <m:a href="examples">examples</m:a> and <m:a href="screenshots">screenshots</m:a> pages for details.
+		</p>
+		
+		<p>
+			Please note that this is still a development release and thus the API (libraries, CLI arguments, formats) might and will change.
+			Any suggestions, ideas and bug reports are welcome in our <m:a href="contact">mailing list</m:a>.
+		</p>
+		
+		<h2>New CLI interfaces</h2>
+		
+		<p>
+			Several earlier tools have non-standard CLI interface and does not conform with <m:a href="principles">principle</m:a> „Use --long-options“.
+			Posistional parameters might be shorter but they are also cryptic and less flexible.
+			In this release the <code>relpipe-in-cli</code>, <code>relpipe-in-csv</code> tools dropped their old CLI interface
+			and got a new one based on named parameters and long options.
+			The <code>relpipe-out-csv</code> and <code>relpipe-out-tabular</code> had no parameters in previous versions and now have standard CLI interface.
+		</p>
+		
+		<p>
+			In <code>relpipe-out-tabular</code> we can now optionally omit several parts:
+			<code>--write-record-count false</code>,
+			<code>--write-types false</code>,
+			<code>--write-relation-name false</code>
+			and thus simplify the output if we do not need given information.
+		</p>
+		
+		<pre><![CDATA[ ╭───────┬────────╮
+ │ first │ second │
+ ├───────┼────────┤
+ │     1 │ abc    │
+ │     2 │ def    │
+ ╰───────┴────────╯]]></pre>
+ 
+		<p>
+			These options may be set globally or for particular relation using the <code>--relation</code> option with pattern parameter.
+			Thus we may e.g. print some relations with data types and some without them.
+		</p>
+
+		
+		<p>
+			Remaining tools that will be transformed in the same way: <code>relpipe-tr-grep</code>, <code>relpipe-tr-cut</code>, <code>relpipe-tr-sed</code>
+			and will get standard CLI interface.
+		</p>
+		
+		<h2>JACK (MIDI) output module</h2>
+		
+		<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>
+			In the <m:a href="release-v0.16">v0.16</m:a> release, the <code>relpipe-in-jack</code> was introduced.
+			This tools allowed capturing the MIDI events from JACK and sending them to the relational pipeline.
+			Now, in v0.17, we introduce the counterpart tool <code>relpipe-out-jack</code> that reads relational data
+			and sends SysEx messages, MIDI notes and other events to the JACK pipeline.
+		</p>
+		
+		<m:img src="img/jack-connections-2.png"/>
+		
+		<p>
+			We can join the JACK graph with <code>relpipe-out-jack</code> command.
+			It does not produce anything on STDOUT, it sends MIDI events to JACK instead, so no other output data are needed.
+		</p>
+		
+		<p>
+			Besides capturing and playing the MIDI, we can use the <code>relpipe-in-jack</code> and <code>relpipe-out-jack</code>
+			to tak a snapshot of the JACK graph (connections between ports) and recreate it later.
+			Or establish any new connections or break existing ones.
+			Either through CLI commands of <code>relpipe-in-jack</code> or through relational data (list of connection and disconnection commands)
+			sent to <code>relpipe-out-jack</code>.
+		</p>
+		
+		<p>
+			Both commands have also the <code>--required-connections</code> and <code>--connect-to</code> parameters,
+			so they can react on reaching particular connection count or automatically connect their port to another one specified on the CLI.
+			The bash-completion suggests available port names.
+		</p>
+		
+		<p>
+			More details in the examples:
+			<m:a href="examples-jack-ports">Working with JACK ports</m:a>
+			and <m:a href="examples-jack-midi-generating-1">Generating and sending MIDI messages</m:a>.
+		</p>
+		
+		<h2>Feature overview</h2>
+		
+		<h3>Data types</h3>
+		<ul>
+			<li m:since="v0.8">boolean</li>
+			<li m:since="v0.15">variable-length signed integer (SLEB128)</li>
+			<li m:since="v0.8">string in UTF-8</li>
+		</ul>
+		<h3>Inputs</h3>
+		<ul>
+			<li m:since="v0.11">Recfile</li>
+			<li m:since="v0.9">XML</li>
+			<li m:since="v0.13">XMLTable</li>
+			<li m:since="v0.9">CSV</li>
+			<li m:since="v0.9">file system</li>
+			<li m:since="v0.8">CLI</li>
+			<li m:since="v0.8">fstab</li>
+			<li m:since="v0.14">SQL script</li>
+			<li m:since="v0.16">JACK</li>
+		</ul>
+		<h3>Transformations</h3>
+		<ul>
+			<li m:since="v0.13">sql: filtering and transformations using the SQL language</li>
+			<li m:since="v0.12">awk: filtering and transformations using the classic AWK tool and language</li>
+			<li m:since="v0.10">scheme: filtering and transformations defined in the Scheme language using GNU Guile</li>
+			<li m:since="v0.8">grep: regular expression filter, removes unwanted records from the relation</li>
+			<li m:since="v0.8">cut: regular expression attribute cutter (removes or duplicates attributes and can also DROP whole relation)</li>
+			<li m:since="v0.8">sed: regular expression replacer</li>
+			<li m:since="v0.8">validator: just a pass-through filter that crashes on invalid data</li>
+			<li m:since="v0.8">python: highly experimental</li>
+		</ul>
+		<h3>Streamlets</h3>
+		<ul>
+			<li m:since="v0.15">xpath (example, unstable)</li>
+			<li m:since="v0.15">hash (example, unstable)</li>
+			<li m:since="v0.15">jar_info (example, unstable)</li>
+			<li m:since="v0.15">mime_type (example, unstable)</li>
+			<li m:since="v0.15">exiftool (example, unstable)</li>
+			<li m:since="v0.15">pid (example, unstable)</li>
+			<li m:since="v0.15">cloc (example, unstable)</li>
+			<li m:since="v0.15">exiv2 (example, unstable)</li>
+			<li m:since="v0.15">inode (example, unstable)</li>
+			<li m:since="v0.15">lines_count (example, unstable)</li>
+			<li m:since="v0.15">pdftotext (example, unstable)</li>
+			<li m:since="v0.15">pdfinfo (example, unstable)</li>
+			<li m:since="v0.15">tesseract (example, unstable)</li>
+		</ul>
+		<h3>Outputs</h3>
+		<ul>
+			<li m:since="v0.11">ASN.1 BER</li>
+			<li m:since="v0.11">Recfile</li>
+			<li m:since="v0.9">CSV</li>
+			<li m:since="v0.8">tabular</li>
+			<li m:since="v0.8">XML</li>
+			<li m:since="v0.8">nullbyte</li>
+			<li m:since="v0.8">GUI in Qt</li>
+			<li m:since="v0.8">ODS (LibreOffice)</li>
+			<li m:since="v0.17">JACK</li>
+		</ul>
+		
+		<h2>New examples</h2>
+		<ul>
+			<li><m:a href="examples-jack-ports">Working with JACK ports</m:a></li>
+			<li><m:a href="examples-jack-midi-generating-1">Generating and sending MIDI messages</m:a></li>
+		</ul>
+		
+		<h2>Backward incompatible changes</h2>
+		
+		<p>
+			The <code>relpipe-tr-guile</code> has been renamed to <code>relpipe-tr-scheme</code>, so it is necessary to modify existing scripts.
+			However the CLI interface has not been changed, thus it can be simply updated e.g. by:
+		</p>
+		<m:pre jazyk="bash">sed s/relpipe-tr-guile/relpipe-tr-scheme/g -i script.sh</m:pre>
+		<p>
+			The reason behind this rename is that Scheme is a programming language and Guile is one of implementations of this language.
+			And we prefer <a href="https://sane-software.globalcode.info/v_0/#a0f42ec9-5032-4f6d-a50a-4b7bddde77f0">depending on interfaces</a> rather than on particular implementations.
+			Similar situation is <code>relpipe-tr-sql</code>: this module is also named after the language (SQL), not after the default implementation (SQLite)
+			and this module can use <m:a href="examples-tr-sql-odbc">any SQL engine</m:a>.
+		</p>
+		
+		<p>
+			The CLI interface of the <code>relpipe-in-cli</code> tool has been standardized and made consistent with other tools.
+			Now, it uses named parameters instead of cryptic positional ones.
+			The format of the STDIN stream remains unchanged (values separated by <code>\0</code> byte).
+		</p>
+		
+		<m:pre jazyk="bash"><![CDATA[# Old syntax before v0.17:
+relpipe-in-cli generate "relation_from_cli" 3 \
+	"a" "integer" \
+	"b" "string" \
+	"c" "boolean" \
+	"1" "Hello" "true" \
+	"2" "World!" "false"
+
+# New syntax:
+relpipe-in-cli \
+	--relation "relation_from_cli" \
+		--attribute "a" integer \
+		--attribute "b" string \
+		--attribute "c" boolean \
+		--record "1" "Hello" "true" \
+		--record "2" "World!" "false"
+]]></m:pre>
+
+		<p>
+			We can repeat these parameters and generate several relations (that was not possibel in the older version).
+			One relation may be filled with values from STDIN: <code>--records-on-stdin true</code> (replaces the old <code>relpipe-in-cli generate-from-stdin</code> syntax).
+			And the last relation may be filled with values from remaining CLI arguments: <code>--records "1" "Hello" "true" "2" "World!" "false"</code>.
+			The demo (<code>relpipe-in-cli demo</code>) has been removed (sample data can be easily generated by setting the CLI arguments).
+		</p>
+
+		<p>
+			The CLI interface of the <code>relpipe-in-csv</code> tool has also been standardized and made consistent with other tools.
+			If we have attribute names on the first line of the CSV file (which is quite common), the usage is same as in previous versions:
+		</p>
+		
+		<m:pre jazyk="bash"><![CDATA[cat file.csv | relpipe-in-csv]]></m:pre>
+
+		<p>If we have only data in the CSV file (no headers) and thus want to specify them on CLI, the syntax is different:</p>
+		
+		<m:pre jazyk="bash"><![CDATA[# Old syntax before v0.17:
+cat file.csv | relpipe-in-csv "my_relation" "a" integer "b" boolean
+			
+# New syntax:
+cat file.csv | relpipe-in-csv \
+	--relation "my_relation" \
+		--attribute "a" integer \
+		--attribute "b" boolean
+]]></m:pre>
+
+		<p>Bash-completion scripts for all tools are provided.</p>
+		
+		<p>
+			Future versions should allow optionally storing the attribute data types in the CSV header and parsing them back (together with the attribute names).
+		</p>
+		
+		<h2>Installation</h2>
+		
+		<p>
+			Instalation was tested on Debian GNU/Linux 10.2.
+			The process should be similar on other distributions.
+		</p>
+		
+		<m:pre src="examples/release-v0.17.sh" jazyk="bash" odkaz="ano"/>
+		
+		<p>
+			<m:name/> are modular thus you can download and install only parts you need (the libraries are needed always).
+			Tools <code>out-gui.qt</code> and <code>tr-python</code> require additional libraries and are not built by default.
+		</p>
+		
+	</text>
+
+</stránka>
\ No newline at end of file
--- a/relpipe-data/roadmap.xml	Fri Sep 25 14:38:24 2020 +0200
+++ b/relpipe-data/roadmap.xml	Thu Oct 22 01:51:32 2020 +0200
@@ -64,6 +64,7 @@
 			<li>test the build with another compiler and tune the code</li>
 			<li>pkg-config: version numbers, debug vs. release</li>
 			<li>packaging for Guix SD and .deb and .rpm distributions, Snapcraft, Flatpak etc.</li>
+			<li>more examples, screenshots, videos, asciinema etc.</li>
 		</ul>
 		
 		<h2>v1.0</h2>