On Sat, 4 Feb 2012, James Ong wrote:
I didn't quite catch how all of these works, it will be appreciate to
see each line with a comment so that other will know what it is.
Well, I'm no expert (I've only been seriously messing around with
fluidsynth for about five days), and I've had to figure out a lot of this
router stuff through trial and error (mainly because I'm too lazy to
RTFS), but this is what I've come up with.
It's not really all that complicated, but it is terribly counterintuitive.
It probably helps to avoid thinking in the abstract and simply remember
that each rule causes a new event (really, a virtual event) to be
generated in response to a received MIDI event. All of the numbers merely
specify a transformation to be applied to the parameters of that event
(channel, parameter 1, and parameter 2).
Now that I've written that down, I'm thinking maybe it is sort of
complicated.
Let's look at a typical MIDI event. I'll use a control change, since
that's what the discussion has been about. Here it is stripped down to
the bare essentials (three hexadecimal bytes):
Bn cc vv
"n" is the channel number (four bits). So, to address channel 0, the
first byte would be 0xb0. Channel 1 is 0xb1, and so on, to channel 15,
0xbf. "cc" is the controller number, which can range from 0 to 127 (0x00
to 0x7f). "vv" is the value to which you want the controller set which,
likewise, can have a value between 0 and 127.
So, for example, to set CC7, on channel two, to a value that corresponds,
in some way, to 50%, the controller number is 7 and the value is 64 (or
63, take your pick). In hexadecimal, that's 0x07 and 0x40, so the MIDI
command is:
0xb2 0x07 0x40
What the routing rules do is look at an event's parameters and, if they
match the specified ranges, apply the given transformations
(multiplication by the first number and addition to the second, in that
order) and send a new event to the synthesizer.
Taking a rule line-by-line, we have:
router_begin cc # Begin a new control change rule.
router_chan 0 15 1 0 # Does the CC message's channel value fall in
# the range 0-15? If not, do nothing (this
# rule doesn't apply). If so, multiply it
# by 1 and add 0 (technically, this is known
# as an identity transform, as nothing is
# altered).
router_par1 40 127 1 0 # Does the message's first parameter (i,e,,
# the controller number) fall in the range
# 40-127? If not, the rule doesn't apply. If
# so, again multiply by 1 and add 0.
router_par2 0 127 1 0 # Same again. This time we look at the second
# parameter (controller value). Since 0-127
# is the entire range of values, any value
# meets the condition and is passed on
# unchanged.
router_end # Done. Commit the new rule.
If all of the conditions are met (the channel and both parameters fall
within the specified ranges), an entirely new event is generated, the
specified transforms are applied, and the event is passed to the
synthesizer.
This is a pretty boring example. Effectively, all it does is pass on
controller numbers 40-127 unchanged.
Let's look at something a bit more interesting, this time with note
events. Like control changes, notes have three associated parameters:
channel (0-15), note number (0-127), and velocity (0-127).
Before we begin, this is a good time to emphasize that every rule results
in the creation of an entirely new event, and the rules are independent.
This makes the router commands very powerful, but also more than a bit
cumbersome. The following example illustrates this independence.
First, make sure that the router is in it's default state (all events are
passed to the synthesizer unchanged):
router_default
Now, create a rule that acts on all channels, notes, and velocities, but
which adds 4 to the note value, transposing it up 4 semitones, or a major
third:
router_begin note
router_chan 0 15 1 0 # all channels are acted upon and unchanged
router_par2 0 127 1 0 # likewise for all velocities
router_par1 0 127 1 4 # but all notes (parameter 1) are multiplied by
# 1 and added to 4, transposing them up four
# semitones
router_end
You might well think that this rule will simply cause each note played to
sound a major third higher. E.g., playing a C will give you an E, but
you'd be mistaken. The rules are independent and each generates a new
event, so what you get when you play a note is that note, plus the note
four semitones higher. Thirds sound terrible with 12TET tuning, so let's
add another rule, this time transposing up seven semitones:
router_begin note
router_chan 0 15 1 0
router_par1 0 127 1 7
router_par2 0 127 1 0
router_end
Seven semitones is a perfect fifth, so now every note you play results in
a major triad.
As a final example, let's clear all of the router rules and create a very
restrictive rule:
router_clear
router_begin note
router_chan 0 0 1 0 # channel 0 only
router_par1 60 60 1 0 # middle-c only
router_par2 0 127 0 127 # take any velocity, multiply by 0 and add
# 127
router_end
Now, the only note that will sound is middle-C, played on channel 0, and
as if you pounded it as hard as possible. Since the router rules were
cleared, this is the only normal event that can reach the synthesizer.
No program changes, control changes, pitch bends, etc., etc., etc.
Finally, as best as I can determine, here is the complete list of router
commands required to restore the router to the default state once a
router_clear command has been issued.
I can't make any guarantee as to the accuracy or completeness of this
information. In particular, I haven't a clue what happens to "note off"
events (if fluidsynth doesn't act on release velocity, it hardly matters).
Moreover, the channel ranges might need to be [0,255]. For that matter,
any or all of the ranges might need to be [0,16383], or [0,65535], or
[0,4294967295]. Who knows? The best I can say is that the following
might be sufficient to make things work within the basic MIDI
specifications:
# notes have a four-bit channel and two 7-bit parameters
router_begin note
router_chan 0 15 1 0
router_par1 0 127 1 0
router_par2 0 127 1 0
router_end
# control change has a four-bit channel and two 7-bit parameters
router_begin cc
router_chan 0 15 1 0
router_par1 0 127 1 0
router_par2 0 127 1 0
router_end
# program change has a four-bit channel and two 7-bit parameters
router_begin prog
router_chan 0 15 1 0
router_par1 0 127 1 0
router_par2 0 127 1 0
router_end
# pitch bend has a four-bit channel and one 14-bit parameter
router_begin pbend
router_chan 0 15 1 0
router_par1 0 16383 1 0
router_end
# channel pressure has a four-bit channel and one 7-bit parameter
router_begin cpress
router_chan 0 15 1 0
router_par1 0 127 1 0
router_end
# key pressure has a four-bit channel and two 7-bit parameters
router_begin kpress
router_chan 0 15 1 0
router_par1 0 127 1 0
router_par2 0 127 1 0
router_end
_______________________________________________
fluid-dev mailing list
fluid-dev@nongnu.org
https://lists.nongnu.org/mailman/listinfo/fluid-dev