diff -r d7ae02390fac -r fce3d6290c40 relpipe-data/examples-jack-midi-generating-1.xml --- /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 @@ + + + Generating and sending MIDI messages + generate some sounds and send them to the JACK daemon + 04500 + + + +

+ A powerful audio system called JACK 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. +

+ +

+ While relpipe-in-jack can be used for monitoring MIDI messages (recording), + the relpipe-out-jack (since v0.17) is designed for sending messages to JACK (playback). + So instead of playing Standard MIDI Files (.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 client in JACK terminology). +

+ +

+ The relpipe-out-jack reads relational data in the same format as relpipe-in-jack. + 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 , the relation containing such „music“ can come from many various sources. + In this example we will use the SQL language. +

+ + +

Connect and say hello to MT-32 (SysEx)

+ +

+ 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 event and says what should be done. + The second one raw contains the raw MIDI data. It is a SysEx message specific to Roland MT-32, + but it can be any MIDI event: +

+ + + +

+ If we omit the --connect-to j2a_bridge:playback part, the relpipe-out-jack command + will wait util we connect it somewhere e.g. using QjackCtl. + We can control this behavior by explicitly specifying --required-connections N (default N is 1) + and say e.g. „Wait until you have 3 connections and then start sending“. + But because we specified the destination port, the relpipe-out-jack command immediately + connects to it and sends data there. +

+ +

+ The j2a_bridge:playback port was created by the j2amidi_bridge + 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. +

+ +

+ See more details on MT-32 and MIDI SysEx in: Monitoring MIDI messages using JACK. +

+ +

Set the MIDI instruments for particular channels

+ +

+ 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 (Patch change). + Currently we misuse the sysex event for this and send this configuration as raw MIDI commands + (the c0 0e and c1 58 below). + In later versions of relpipe-out-jack, there might be better support for instrument configuration. +

+ +

+ The list of standard instruments is available at MIDI.org: General MIDI: GM 1 Sound Set. +

+ +

Play some SQL tones

+ +

+ Specifying the notes as raw MIDI messages is possible but uncomfortable. + So we will put note in the event attribute + and specify also time, channel, note_on, note_pitch and note_velocity attributes. + The relpipe-out-jack will compose the raw MIDI event from these values. +

+ +

+ 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. +

+ + + +

+ The SQL engine (SQLite by default) called from relpipe-in-sql converts our script into a relation. + Then the relpipe-out-jack translates this relation to actual MIDI events and sends them to JACK system. +

+ + + +

+ We connect it to two ports, so we can hear the sounds and at the same time, we can monitor the MIDI events + (through relpipe-in-jack and usually relpipe-out-csv). + We can also use relpipe-out-tabular instead of relpipe-out-jack 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). +

+ +

+ If we have some hardware, it should look and sound like this: +

+ + + +

+ In this video, the Roland MT-32 and SC-88 Pro are daisy-chained and most sounds come from the SC-88. +

+ +

+ n.b. the MIDI channel 1 (index 0) is usually silent on MT-32 (default configuration). +

+ + + +

Supported event types and attributes

+ +

+ The relpipe-out-jack supports following event types: +

+ +
    +
  • + note: press or release (depending on note_on) of particular key on keyboard +
  • +
  • + control: change value of a controller (knob, slider, switch etc.) +
  • +
  • + sysex: SystemExclusive command specific for particular device or manufacturer (e.g. show some text on the display) +
  • +
  • + connect: link two JACK ports using a virtual cable +
  • +
  • + disconnect: put that cable away +
  • +
+ +

+ 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: +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
eventnotecontrolsysexconnectdisconnect
time
channel
note_on
note_pitch
note_velocity
controller_id
controller_value
raw
source_port
destination_port
+ + +

+ Note: this design pattern is one of possible ways how to implement the inheritance (an object-oriented concept) in the relational world. + The relation contains one attribute that determines the type (or class) + and then union of all attributes of all that types. + Each type uses just its relevant attributes and the rest is empty. +

+ +

+ The meaning of the attributes is following: +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
attributetypedescription
+ event + + string + type of the record
+ time + + integer + time in microseconds since start of the playback
+ channel + + integer + number of the MIDI channel; starts from 0
+ note_on + + boolean + whether the key was pressed (true) or released (false)
+ note_pitch + + integer + pitch or tone; starts from 0; e.g. C4 is 60
+ note_velocity + + integer + force with which a note is played; 0-127
+ controller_id + + integer + number of the controller; starts from 0
+ controller_value + + integer + value of the controller; 0-127
+ raw + + string + raw MIDI bytes written in hexadecimal format; e.g. 91 3c 41
+ source_port + + string + name of the JACK output port; e.g. system:capture_1
+ destination_port + + string + name of the JACK input port; e.g. system:playback_1
+ +

+ Besides the event we need to specify only attributes we use. + So if we e.g. only send SysEx messages, we need only event and raw attributes. + If the time is missing, the event is processed as soon as possible (in the next real-time cycle). + The time attribute is used for precise timing + – so the process is not driven by the time when the event arrives on STDIN of the relpipe-out-jack. +

+ + +
+ +