fluid-dev
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [fluid-dev] CC7 reset


From: R.L. Horn
Subject: Re: [fluid-dev] CC7 reset
Date: Sun, 5 Feb 2012 07:57:42 -0600 (CST)
User-agent: Alpine 2.00 (LNX 1167 2008-08-23)

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



reply via email to

[Prev in Thread] Current Thread [Next in Thread]