Midiflow is a MIDI router and processor for iOS. It allows you to send MIDI data from any source to any destination that is visible in the iOS operating system. These can be hardware interfaces connected to the iOS device, or other apps. Such a connection can furthermore apply modifications to the data. This allows you to remap channels, limit notes to a range, shift notes, apply a velocity curve to notes, map MIDI messages to a different type (a note to a controller for example) and remap their values in various ways. By controlling connections via MIDI, complex functionality can be implemented. Different configurations can be stored and recalled later, either by selecting from a list, or via MIDI. This documentation is going to show you all the features and what you can do with them.
When starting Midiflow for the first time on the iPad, it looks like this:
The lower part contains controls for switching between a condensed ("ERGO") and a more detailed ("FULL") view. In the middle, you can control the MIDI monitoring. On the right side, you find the transport controls for the internal MIDI clock.
On the iPhone, it looks like this:
The central entity in Midiflow is a routing. A routing specifies where your MIDI data is going and how it is gets transformed.
You create a new routing by tapping the "ADD" button.
It is easy to see that it consists of three main items.
From top to bottom, there is a source, a modifier and a destination. A newly created routing is empty and won't do anything. If you click on the source, a list will appear that shows all the available MIDI sources.
In this case, only the MIDI source 'Network Session 1' is available. After selecting a source, the routing will receive MIDI from that port.
Sometimes it is useful to have multiple sources for one routing. If you have switched to "Multiple" at the very top, you can select up to 8 ports.
Till now, the routing is receiving data, but it is going nowhere. To change that, tap on the destination
The list view looks quite similar to the one for selecting a source. After adding a destination, all the data coming in at the source will be routed to the destination. This is the simplest form of a routing.
You can delete a routing by swiping up on it. In order to duplicate it, you have to tap on the round routing modifier button in the middle and scroll to the bottom.
There, you'll find the button "Duplicate routing". It will create an exact copy of the routing right next to it.
Let's make it a bit more exciting by adding a modifier. In between the source and the destination, there is a button for creating a modifier. On that screen, you can modify the MIDI data coming from the source before it will be sent to the destination.
For a deeper understanding of how Midiflow works, it is helpful to realize that the first four items in the modifier view are called "RESTRICT...". This means that they don't modify anything, but completely filter out all data that doesn't fit in. Modifier items further below won't see it.
By default, a modifier will let all data pass, no matter which channel it is on. That's why "RESTRICT CHANNEL TO" displays "All".
You can restrict that to one specific channel either by tapping the plus or minus button, or by tapping on the value, which will show the channel input screen.
All data on a different channel will be ignored, hence filtered out. If you want to change the channel of the messages, scroll down in the modifier screen until you reach "REMAP CHANNEL TO".
By default, it is set to "No remapping", which means that all data stays on the channel in was received on. However, selecting a specific value here will remap it to that channel.
If the routing has one destination set, you'll find an additional switch below the channel remapping modifier, with the caption "Always remap to this channel when using", followed by the destination name.
When this switch is activated, Midiflow will remember this channel and auto-assign it whenever you set the destination of a routing to that destination again. So, if you set the remapped channel to a specific value, enable that switch, create another routing and select the same destination for it, you'll see that the modifier will immediately change so that the channel is remapped as specified before.
This feature is useful when you want to use one of your devices always with the same channel. This channel memory will then save you from configuring the channel modifier all the time.
Regarding the channel filtering, it is important to note that not all MIDI data is sent on a channel. There are also global messages, like clock messages or SysEx commands. These just pass the channel restriction and likewise ignore the channel remapping.
Incoming notes can be restricted to a range in "RESTRICT NOTES TO RANGE".
Tapping on the lower or the upper limit will show the note input screen.
Besides typing a note name, you can use the "Min" and "Max" buttons to select the minimum or maximum value. Keep in mind that the lower limit has to be lower than or equal to the upper limit. In case of equality, only one note will pass.
Restricting a routing to a note range can be used to split a keyboard. You need two routings which send data from the same source to two different destinations. One routing should be restricted to the lower part of the keyboard and the other one to the upper part. Playing on the lower part will then only trigger the one sources, while the upper part will trigger the other.
MIDI messages that are not notes will pass the note restriction.
Similar to restricting the note values, you can restrict the strength of the key strokes. Scroll to "RESTRICT NOTE VELOCITIES TO RANGE".
Tapping on either the lower or the upper limit will show the value input screen. Besides typing a value, you can use the "Min" and "Max" buttons to select the minimum or maximum value. Keep in mind that the lower limit has to be lower than or equal to the upper limit. In case of equality, only one note velocity will pass.
Restricting a routing to a note velocity range can be used to create a velocity split. You need two routings which send data from the same source to two different destinations. One routing should be restricted to soft notes and the other one to loud notes. Playing soft notes will then only trigger the one sources, while louder notes will trigger the other. There are many variations of this example, like triggering one source all the time while adding the second starting at a minimum velocity.
Notes with a velocity outside of the specified range will be filtered out. However, you may want to limit the note velocity to a maximum value instead of filtering them out completely. Although this might sound like a similar task, this won't be done here because this would be a remapping rather than a restriction. We'll cover that in Note remapping and filtering.
Just like with note value restrictions, MIDI messages that are not notes will pass the note velocity restriction.
Besides restricting messages based on channels, notes and note velocities, you can also filter out messages based on the state of a completely independent controller.
Since this is an advanced topic, we'll cover "RESTRICT TO CONDITIONS" in Controller conditions below.
After note messages have passed the above restrictions, they can be modified or filtered out.
If you enable the "Filter out" switch, no notes will be routed to the destination. If you keep it enabled however, you can easily shift all notes in half-tone steps.
If you wan to shift notes individually, tap "Note remapping".
This screen allows you to select an output note for each input note. By switching the type from "All" to "Tones" at the very top, you can specify this for all octaves at once.
Currently, there is no explicit option for filtering out notes. However, you can achieve that by entering a very low note, like "C-10". Since this note is outside of the range of available notes, it won't be sent to the destination.
In most cases, a simple note shift is what you want. But remapping notes individually can be interesting if you play around with musical scales, or if you want to filter out 'avoid notes' that would ruin your solo. Remapping distinct tones can also be useful when layering sounds.
At the bottom of the screen, you'll find a button for exporting the list of values to the clipboard or to another app.
This allows you to modify the values with another app, or to copy the values to a note remapping of another routing in Midiflow. The data is in simple text format where each of the 128 lines represents one note and contains the output note as number. Use the "Paste" button to insert a list from the clipboard. See Export/import remapping lists for more details.
Besides remapping notes, you can also remap note velocities. There are several remapping types for that purpose.
The type "Curve" lets you adjust the velocity remapping graphically in four different ways.
The standard option lets you define a free curve using four handles. The left-most and right-most handles are fixed to the borders, while the second and third one can be moved freely.
The three other options allow you to adjust one parameter which influences the curve in different ways. Adjusting "Softness" can help you to play softer notes if your keyboard creates high velocities even when playing softly. Or you can use a negative softness to get louder notes from soft attacks.
"Dynamics" increases the output velocity range in the middle input range. So if you wish to control the note's velocities more sensitively, you should increase this parameter.
If your keyboard won't reach the highest velocities, even if you hit the notes a lot, then "Cutoff" might come in handy. It increases the slope of the curve so that the maximum velocity is reached earlier.
After adjusting the parameter or changing the free curve, you can always go back to the standard setting by tapping "Reset curve".
When selecting "Fixed", the note velocities will be remapped to one fixed value.
"List" allows you to specify an output velocity for each input velocity individually.
By doing that, you can create any custom velocity remapping that cannot be achieved with the previously described built-in options. You can either start from scratch here, or convert a curve or the fixed value to a list. To do that, go to "Curve" or "Fixed" and tap "Convert to list".
Then you can make adjustments in the list.
Besides entering values manually, you can also import a value list that you have created with another app. See Export/import remapping lists for more details.
Besides notes, there are MIDI message types for knobs and faders on your keyboard. In Midiflow, they are called "CONTROLLERS". With the "Filter out" switch, you can prevent them from being sent to the destination.
The MIDI standard defines the message type "Control Change". However, "Controllers" in Midiflow include some other message types, too. Here is a list of the messages that are affected by the "CONTROLLERS" modifier:
Control Change: Volume (CC7), Sustain (CC64), etc.
With the in-app purchase "Controller remappings", you can use Midiflow to remap controllers in various ways, or to filter out individual controllers. Since this is an advanced topic, we'll cover this in Controller remappings below.
With the switch "Filter out Clock" you can disable MIDI beat clock messages. If you keep it switched on, you can modify the tempo as a subdivision of the incoming tempo. "1/1" keeps the tempo unchanged. You can divide it to "1/2", "1/3",..., "1/24". Multiplying the tempo is currently not possible. Instead, you have to increase the incoming tempo and adjust all tempo dividers appropriately.
Modifying the tempo works with Midiflow's internal clock and with an external clock, which has been added as a source in the routing. Since Midiflow can send clock data ahead of time, sending different clock divisions to different destinations will be more precise if the internal clock is used.
In this section, you can define one or more MIDI messages that should be sent when the current preset is loaded. Tap "Add controller" and select the desired MIDI message. After that, you can make more adjustments.
Besides the value to be sent, you can also specify a delay. This is useful if you want to send a program change and a volume message. It might be necessary to delay the volume message a short amount of time until the sound device is ready to receive it.
The list of MIDI messages to be sent is sorted by time in the modifier screen.
In order to delete a message, you can swipe to the left on an item of the list in the modifier screen. This will unveil a delete button.
By tapping that button, you can go back to a clean state.
With the button in the upper left corner, you can temporarily disable all modifications and filters. The only exception is the channel modifier, which stays active in order to send the MIDI data still to the right receiver.
With the button in the upper right corner, you can temporarily filter out all data, hence mute the whole routing.
Many values in Midiflow can be set using MIDI learn, which is easier than specifying the numerical value in most cases. You can recognize values with support for MIDI learn by the little process indicator in the upper left corner.
You activate MIDI learn by tapping and holding the button. As long as you hold it and the process indicator is spinning, Midiflow will listen to incoming MIDI and set the value correspondingly.
Midiflow is as tolenrant as possible concerning the incoming MIDI. When setting a routing's incoming or outgoing MIDI channel for example, it will accept MIDI messages of any kind and of any source, no matter what the routing's actual sources/destinations are. As another example, when working with Control Change values in a Controller Remapping, MIDI learn will work with any controller number, not only with the one specified in the remapping. This makes assigning values via MIDI learn very easy even if the to-be-remapped Control Change message will be sent by a sequencer and cannot be triggered for the purpose of MIDI learn. In that case, you can use another available controller, like the modulation wheel for setting the value.
With the in-app purchase "Controller remapping", you can use Midiflow to remap controllers in various ways, or to filter out individual controllers. As described in Controller remapping and filtering, "controllers" in Midiflow are Control Changes, Channel Pressure, Pitch-Bend and Program Changes. By default, a routing forwards all controllers. With the switch "Filter out", you can filter out all controllers.
In order to treat a controller individually, you have to create a remapping by tapping "Add remapping". This will open a dialog that lets you choose the controller you want to remap.
Besides the controllers mentioned above, you'll find some special items here. We'll cover them later in Special input controllers. The second section contains Control Changes. By default, a selection of the most important items is visible. By tapping "Show all", you can get to the whole list.
By selecting one controller, Midiflow will create a remapping for that controller.
In the following screen, you can modify the remapping.
Like in all other parts of Midiflow, the signal goes from top to bottom in that screen. The first section allows you to change the incoming controller. Currently it is set to the one you selected in the previous step.
Furthermore, you can specify the precision of the controller. The default for most controllers is "MSB", which corresponds to a value range from 0 to 127. An exception is Pitch-Bend, where the precision is "MSB + LSB", which corresponds to a value range of 0 to 16383.
You can also get such a high precision with Control Changes, but you need a second Control Change number for that. In that case, MIDI uses two controllers to achieve the higher precision. That's why a second cell will appear when switching to "MSB + LSB".
By default, the LSB controller is the MSB number plus 32, but you could select another one if you wanted.
If you want to filter out this controller, activate the "Filter out" switch. The subsequent sections, which are for remapping, will disappear.
Midiflow supports three different types of controller modes.
They influence how the incoming value of the controller will be used internally during the further processing.
You have the following options:
Direct: This is the default. The controller value will be used internally just as it comes in.
Increment: Each time, the controller reaches a trigger value, the internal value of the controller will be increased by a defined offset. You can use that to step through a series of values. The screen allows you to specify not only the trigger value, but also how the value should be approached ("Trigger edge"): from lower values, from greater values, or from both sides. Furthermore, you can select start and end value of the internal value, and if you want to start from the beginning when reaching the end (start from the end when reaching the beginning in case of a negative value for "Increase by").
If the incoming controller of the remapping is Control Change, Key, or (N)RPN, you also have the option to select a controller (of the same type as the incoming controller) for decrementation.
In case of a Control Change, you can select the controller number in the "number" field, which should trigger the decrementation. In case of a Key, you can select the key number in the "key" field. In case of a (N)RPN, you can select MSB and LSB of the parameter to be used. The decrementation controller will use the same settings for trigger value and trigger edge that were selected above.
Latch: Each time, the controller reaches a trigger value, the internal value of the controller will toggle between "On" and "Off". You can use that for switching something on and off by pressing a controller pedal multiple times. So, while the "Direct" mode would make your pedal switch something on when you press it down, and switch it back off when you release it, the "Latch" mode will keep it on after the first press, and release it when you press again. Just like for the "Increment" mode, you can specify the "Trigger edge".
You can modify the values of the controller in various ways. It is important to understand that the internal value of the controller gets transformed, not the incoming value. The latter is only true if the controller mode is "Direct". Hence, if you have selected "Increase" as the mode, the internal value will first be increased on each controller input, and then transformed according to the following settings.
A linear remapping is given by an input range and an output range.
By default, the full range of input values will the mapped to the full range of output values. If you reduce the input range from 0-127 to 50-100 and keep the output range at 0-127, the output value will stay at 0 if the input is lower than or equal to 0, and will increase to 127 while increasing the input value to 100. After 100, the output value will stay at 127.
While the lower value of the input range has to be lower than or equal to the upper value, there is no such limitation for the output range. So, by selecting 127-0 as an output range and keeping the input range at 0-127, you invert the controller.
After adjusting the input or output range, you can always go back to the standard setting by tapping "Reset".
The type "Curve" lets you adjust the remapping graphically in four different ways. It is identical to the one for creating a Velocity Curve.
"List" allows you to specify an output value for each input value individually.
By doing that, you can create any custom remapping that cannot be achieved with the previously described built-in options. You can either start from scratch here, or convert a curve or the linear remapping to a list. To do that, go to "Curve" or "Linear" and tap "Convert to list".
Then you can make adjustments in the list.
Besides entering values manually, you can also import a value list that you have created with another app. See Export/import remapping lists for more details.
Finally, you can specify the controller type that the input controller should be remapped to.
Like for the incoming controller, you can also select the precision here. If you choose "MSB + LSB", you can select the LSB controller in case of Control Changes.
You might notice that the numbers in the remapping section change when you change the precision of the incoming or the outgoing controller. For example, while the default incoming range in the linear remapping is 0-127, it will change to 0-16383 when switching the incoming precision to "MSB + LSB". If you have already adjusted the input range, the values will be recomputed to their high-precision counterparts.
The selectable values for "Trigger value" etc. in the controller mode settings also reflect the precision of the incoming controller.
You'll also notice that only the "List" remapping type is available if the controller mode is "Latch". Since, this mode only has two values, anything else would not make sense. The list has two values in this case and allows you to select the output values representing the latch states "On" and "Off".
The screens for selecting incoming or outcoming controllers contain some special items along with Control Changes, Channel Pressure, Pitch-Bend und Program Changes.
The items "Note Value" and "Note Velocity" let you use the keyboard as a controller.
For example, if you want to create control changes by pressing keys on the keyboard, you would select "Note Value".
You could use this to adjust the pan value of your sound depending on which key you play. Lower notes could create a lower pan value (left) while higher notes could create a higher value (right).
If you want to use the key velocity of the last note, you would select "Note Velocity".
You could use this to adjust the volume of a sound that has no velocity sensitivity, like an organ. Normally, you would play that with an expression pedal, but if you layer the organ with a piano for example, this might be useful.
Keep in mind that notes outside of the key range and the velocity range of the routing will be filtered out. So, if you only want to remap notes within a key range, you would create a routing with that key range, and then add a controller remapping for notes in that routing. If you want to specify two different key ranges for note messages and the controller remapping, you need two independent routings, where one handles the notes and the other one does the controller remapping.
The notes modifier of the routing does not affect note and note velocity of a controller remapping. For example, if you have specified a note shift there, the notes in the controller remapping won't be shifted. If you wanted to transform the notes before transforming them into a controller, you would do that with the value remapping of the controller remapping as described before.
According to that, you cannot filter out notes here, the "Filter out" switch is not available if "Note Value" or "Note Velocity" are selected as an input controller. See Note remapping and filtering for that.
The input controller "Motion" allows you to create MIDI data out of device motion. This is described in Using device motion data.
When selecting "Key" as an input controller, you can use a key of the keyboard as a switch.
The controller has two states, "Pressed" and "Released", that you can assign output values.
You could use this to switch an effect on by holding down the key "C1", and switch if off by releasing it. Just remap the key to a Control Change (or any other message type) and remap the "Pressed" state to 127 and the "Released" state to 0. The corresponding Control Change values will be sent when pressing/releasing the key.
If you change the controller mode to "Latch", you can toggle the state by pressing the key.
By that, the effect would not be removed when releasing the key but by pressing it a second time.
The major difference to "Note Value" or "Note Velocity" is that "Key" takes releasing the key into account. The other ones let you use the last note value or velocity, which are only related to pressing the key.
Midiflow allows you to remap from and to freely defined MIDI messages, like SysEx messages.
You enter them in the message input screen.
A MIDI message is a string of hexadecimal numbers, each ranging from 0 to FF (255). This corresponds to 8 bits. Besides these numbers, you can use the following placeholders:
[MSB]: This is the position of the MSB value
[LSB]: This is the position of the LSB value. You can leave this out. In that case, you cannot select "MSB + LSB" as precision in the remapping screen.
[CH]: This is the position of the channel. You can leave this out if the message is not a channel message. If you include it in an input message, a message will be filtered out if the value at that position does not match the channel filter of the routing. In an output message, the placeholder will be replaced by the remapped channel. The channel is only a 4 bit value. In order to use it in a message, you need to enter another digit in front of it, like 0.
[**] (only for input messages): This placeholder stands for any value. You can use it in an input message if you want multiple messages that differ in some irrelevant parts to be handled by this one remapping.
If the message, you have specified, is an input controller, Midiflow will check if incoming MIDI data matches the fixed numbers. Furthermore, if you used the channel placeholder, the value at that position has to match, too. Then, the value will be extracted from the message and processed.
In case of an output message, you can use the available placeholders up to 10 times each.
Freely defined messages cannot be filtered out, the "Filter out" switch is not available in that case.
Since sound devices might have a huge number of parameters that cannot all be addressed by Control Changes, the MIDI standard supports RPN and NRPN messages. They support up to 16384 addressable parameters, given by an MSB and an LSB value.
RPN and NRPN message cannot be filtered out, the "Filter out" switch is not available in that case.
Once you have created the first controller remapping, the caption of the "Filter out" switch will change to "Filter out others".
This reflects the fact that the switch only affects controllers that don't have an individual remapping.
If you want to create two very similar controller remappings within the same or two different routings, copying and pasting them is very useful. Copy a remapping by tapping "Copy remapping" at the end of the remapping screen.
You'll then find an extra entry in the list of controller remappings in every modifier screen that lets you paste it there.
By tapping "×", you can remove the copied item from the memory.
You can delete a controller remapping by tapping "Delete remapping" at the end of the remapping screen.
Alternatively, you can swipe to the left on the remapping item of the remapping list in the modifier screen. This will unveil a delete button.
Controller conditions are a very powerful tool in Midiflow that allow you to create MIDI functionality beyond static MIDI routings. By default, a routing is always active and forwards all incoming data. By specifying an input channel or a key range, you can filter out non-matching data. By adding a controller condition however, you can switch the whole routing on or off depending on another MIDI input. You need the in-app purchase "Controller conditions" to use this feature.
A good example for using a condition is switching between sounds with a controller pedal. Let's say, you have created two routings which send MIDI from your keyboard to two different sound modules. Instead of playing them simultaneously (as a layer), you could add a condition to the first routing, so that it only forwards MIDI data while you press the pedal. An identical but inverse condition could deactivate the second routing in that case and only activate it, when the pedal is released. That way, the pedal acts as a switch for the two sounds.
As described before, controller remappings could be used to remap notes to Control Changes. By doing that, you could control parameters of the sound device with a keyboard that doesn't have any faders or knobs. However, you might not want the Control Changes to be sent while you regularly play on the keyboard. For that reason, you could create a condition that enables the routing only when you activate some controller (which could also be a key, like the lowest one on the keyboard).
The controller conditions of a routing are listed below the channel filter in the modifier screen, in the section "RESTRICT TO CONDITIONS". You can add one by tapping "Add condition",
and delete it by swiping to the left on the item and tap delete.
If you create more than one condition for a routing, an additional control will appear at the top.
It allows you to specify if all ("AND"), at least one ("OR") or exactly one ("XOR") of the conditions have to be fulfilled so that the routing is active.
Tapping on one item in the list of controller conditions will bring you to its settings.
The first section allows you to select the "SOURCE" of the MIDI signal that you want to use as a condition, which is the input keyboard by default. Don't forget to configure the input keyboard as described in Input keyboard. You can also select another source buy tapping on it, which will bring you to a screen that you already know from selecting the source of a routing.
Furthermore, you can limit the channel of the incoming messages.
In the next section, you can select the controller. You'll notice that this is similar to the settings of a controller remapping, as described in Controller remapping properties. In fact, a controller condition is similar to a controller remapping: Just as you remap a controller to another controller, a condition lets you "remap" a controller to the activation state of a routing.
Now that you have set which controller should be used to formulate the condition, you now have to specify which values of the controller should fulfill the condition, and which not. That's what the "CONDITION" section is for.
With the standard settings ("Type" set to "≥"), the condition will be fulfilled when the value of the controller is larger than or equal to 50.
You can change the threshold by tapping the value.
You can also change the type to "≤" so that the condition will be fulfilled for values lower that or equal the value.
Finally, if you need more control over the condition, you can use the "List" type to assign the condition result for each input value individually.
You can either start from scratch here, or convert a range condition to a list. To do that, go to "≤" or "≥" and tap "Convert to list".
Besides entering values manually, you can also import a value list that you have created with another app. See Export/import remapping lists for more details.
If you select "Note Value" or "Note Velocity" as input controller, two additional sections will become available for limiting the key and the velocity range. These have to be used if not the whole key range should change the conditions state.
Let's say you want to switch between two sounds by using the lowest two keys, C2 and D2. One key should enable one sound (routing), the other one the other. The first routing for this needs a condition with "Note Value" as input controller. The condition type has to be set to "≤" and the value to C2. If a key lower or equal than C2 is played, the condition will be fulfilled, hence the routing will be activated. Otherwise, the routing will be deactivated. The second routing looks very similar, however, its condition type has to be "≥" and the value "D2". This routing will then be active when the other is inactive. However, if you pressed C2 for the first sound and started playing, the second sound would immediately become active, because you played a note higher than D2. To prevent this, at least the second condition should have the key range set to C2-D2. All other key presses above D2 will then be ignored by the condition. In order to reduce the checks Midiflow has to perform on each key press, you should set the key range of the first routing's condition to that range, too.
Not only a routing can have controller conditions, but also controller conditions themselves. Just as a condition can prevent a routing from sending out MIDI, a sub-condition can prevent its parent condition to change its state.
Continuing the example of switching sounds with the two lowest keys of the keyboard, you might want those keys only to change the sound if you have activated another controller (like a "shift" key that activate an alternative function). Otherwise, pressing the keys won't have any effect, besides producing notes for your regular playing. For that, you add a sub-condition to each condition of the routings, that activates the condition only when the controller is activated, e.g. its value is above a threshold.
Once you have added a sub-condition, another option will appear.
The switch "Require sub-conditions to be 'true'", if activated, will make a condition fail if its sub-conditions are not fulfilled. In most cases, the condition and the sub-condition will then behave similarly as if they were not nested but on the same level. In other words, the sub-condition simply could have been added as a second condition of the routing, with the condition relation set to "AND". In fact, you should prefer a flat list of conditions over nesting them whenever possible just for simplicity. However, if the first condition uses the "Latch" or "Increment" controller mode, you have to decide if the internal value should change while the other condition is false. If yes, you have to add the second condition as a second condition of the routing. If the internal value of the first condition should not change while the second condition is false, you have to add the second condition as a sub-condition of the first one.
In the previous example, you would keep this switch turned off, since the routing for the upper/lower sound should stay active after you released your "shift"-controller.
If you want to create two very similar controller conditions within the same or two different routings, copying and pasting them is very useful. Copy a condition by tapping "Copy condition" at the end of the condition screen.
You'll then find an extra entry in all lists of controller conditions, like in every modifier screen or in the list of sub-conditions. The item lets you paste the copied condition there.
By tapping "×", you can remove the copied item from the memory.
You can delete a controller condition by tapping "Delete condition" at the end of the condition screen.
Alternatively, you can swipe to the left on the condition item of the condition list in the modifier screen or in the list of sub-conditions. This will unveil a delete button, as described in Creating controller conditions.
One of Midiflow's unique features, compared to other MIDI routers, is its routing retention behavior. It takes effect whenever you change the properties of a routing or completely switch it off. As an example, let's say you have two routings that both send the notes from a keyboard to two different sounds. While you're playing, you decide to switch one of them off by tapping "Mute". It is obvious that, from now on, only the other routing will send notes. But what happens to the notes that were pressed when you tapped "Mute"? Without any special treatment, the pressed notes would sound forever even after releasing them because the note off messages wouldn't be routed to the sound device anymore. For that reason, most of the available MIDI routers send an "all notes off" command in order to clear all notes and, by that, prevent such stuck notes. However this has the big disadvantage that this might interrupt your performance.
Midiflow, in contrast, tracks the notes that you play so that it knows, which keys are currently pressed when you change a routing. For those notes then, it retains the routing until they are released. By that, the note off commands are delivered properly. All other notes will already be routed according to the updated routing, or be not forwarded if the routing was deleted. Since this works for changes in the routing and not only for deletions, you can, for example, change the note shift. New notes will immediately be shifted, while the pressed notes will sound with the original shift until you release them.
Not only note routings are retained, but also some controllers.
Sustain: You can hold notes with the sustain pedal and then change a routing. The notes will sound until you release the pedal.
Pitch-Bend: If you change a routing while the Pitch-Bend is not in center position, further Pitch-Bend messages will be forwarded according to the old routing until it is in center position. That way, you will never leave a sound out of tune.
Channel Pressure: If you're pressing the keys and channel pressure data is sent, those messages will be forwarded according to the old routing until the pressure is 0.
Furthermore, any other controller routing will be retained if it is remapped to one of the above controllers, using a controller remapping. So, if you remap a Control Change to Pitch-Bend, the behavior will be as expected.
Routing retention is really useful if you're using controller conditions to change routings while playing. Also, if you're using multiple presets for different songs, you can go to the next song without sound interruption.
Tapping the Panic button will cancel all retained routings.
Midiflow offers quite some options for remapping notes, velocities and controller values. For example, you can easily shift all notes by a number of half tones, apply a velocity curve graphically or convert all velocities to a fixed value, and remap a range of controller input values to a new output range.
However, there might be situations where you want something else. For that reason, all those remapping screens also have a "List" view that allows you to enter an individual output value for each input value. The real power of this screen however is the import and export feature.
At the end of the list, but not further below than the lower screen edge, you'll find a bar with the iOS share button. Tapping it will show options for sending the list via email or just to copy it to the clipboard.
Selecting the email option can be a good choice just to see quickly how the actual data looks like. It is in simple text format, each line contains a number representing the remapped value. More precisely, the n-th line contains the output value that is used when the incoming value is n. If you are working with a note remapping, the raw text format will still contain numbers. 0 corresponds to C-1, 127 corresponds to G9.
Instead of sending it via email (which can be useful to help somebody with a remapping), you can copy it and paste it into another app, like Apple Numbers. This is a great tool for creating remapping lists for Midiflow because you can use formulas to let Numbers create all those numbers for you.
After you have modified your remapping list or created a completely new list of values, you should copy it. Back in Midiflow, you can paste it by tapping "Paste".
The length of a remapping list depends on the precision of the incoming value. Note and velocity remappings always have a length of 128 items. Controller remappings are 128 items long if the precision is "MSB" and 16384 items long in case of "MSB + LSB". Midiflow will show an error message if you try to paste a list which is too short, and cut off values at the end if the list is too long.
You can store multiple routing configurations and recall them later.
Whenever the current configuration differs from the saved one, you will see a "(modified)" hint after the name.
In order to save a configuration, tap "SAVE (AS)".
The appearing message will allow you to choose if you want to overwrite the current configuration or if you want to save it under a new name.
In that case, you can enter a new name.
The list of presets lets you edit the names of all presets. Just tap "Edit" in the upper left corner.
You can tap on the preset names and edit them. In order to delete a preset, tap the red button on the left side of a preset.
You finish the editing process by tapping "Done".
All songs are ordered alphabetically. However, for the purpose of calling configurations via MIDI (see Controller assignments), you have to give them numbers, so that Midiflow can not only find the "first" but also the "next" or "previous" preset.
For that, tap the button on the right side of the preset name, which contains "--" if no number has been assigned yet.
This will show the input screen for preset numbers.
By tapping "Delete", you can remove a number from a preset.
You can also insert a configuration to the current one. This is useful if you have saved some reusable configurations that you want to use in different combinations. Just tap "INSERT". The list of presets will pop up and let you select.
You can use Midiflow with anything that is CoreMIDI compatible. This might be hardware like a keyboard or drumpads, which you connect to the iOS device. This can also be another iOS app, like a synth or sequencer app. If your music apps create a so-called "virtual MIDI port", they will appear in Midiflow so that you can use them to receive MIDI from, send MIDI to, or both. This depends on if the app creates an input or an output port, or both.
Midiflow does not only list those virtual ports. It tries to match a MIDI port to its actual app by communicating with its database and the Apple App Store. For this to work, you should start Midiflow at least from time to time when you are online. That way, you give it a chance to sync its data.
The advantage is not only that you see the app icon next to the MIDI port. It also allows Midiflow to show you the ports even when the corresponding app is not running. Normally, virtual MIDI ports of other apps can only be seen if they have been launched. Midiflow however will list them anyway and allow you to start them with a tap on the item.
However, there is a chance that some of your apps are not in the database yet. Then, you won't see them until you start them manually. In many cases, this is enough and Midiflow will know the app from now on. Sometimes though, the app has to be added manually by us. You don't have to do anything for that, just make sure you have an internet connection so that Midiflow can notify the server about the missing app.
As already described, most apps create a virtual MIDI port that can be used by Midiflow to send or receive MIDI data. However, for some MIDI applications, this is not enough. Those other MIDI apps might no only receive MIDI on their virtual port, but also on other ports. This can be a problem if you want to split your keyboard and send two parts of it to two different apps. This can only work if those other apps don't receive MIDI from the keyboard directly. They should only receive MIDI from Midiflow, otherwise your configuration will be bypassed.
As a consequence, you need to configure your apps so that they receive only on their own virtual input port. If they can also send MIDI, they should likewise only send on their virtual output port. Unfortunately, some apps don't give you this choice. If this is true for some of your apps, you should contact the developers and tell them.
Some of those apps can at least be restricted to one MIDI channel. In that case, you can choose a unique channel for that app and make sure that nothing else in your equipment (especially your keyboard) sends on that channel. Use the channel modifier to remap the channel accordingly.
Warning: If a synth app cannot be restricted to its virtual port or to a distinct channel, it cannot be used with Midiflow.
You can control some functions of Midiflow via MIDI. You do that by creating "Controller assignments" in the configuration screen.
Just tap "Add assignment". Tapping the newly created item brings you to the detail screen of the new assignment. It looks very similar to the screen of a controller condition. You can specify a source and a channel, and the controller that you want to use.
In the "ASSIGNMENT" section, you specify what you want to control, and how. There are two options.
If you select the type "Actions", you can trigger a certain action when the controller reaches a particular value.
You can assign a different action to each possible controller value. Tapping a value brings you to an action selection screen.
The available actions are:
None: Nothing will happen if the controller reaches that value
Select Previous Program
Select Next Program
Start MIDI Clock: Start Midiflow's internal MIDI clock
Stop MIDI Clock
Toggle Start/Pause MIDI Clock: This will change the clock status depending on its actual state
Toggle Start/Stop MIDI Clock
Tap MIDI Clock Tempo
You can control the clock with a key on the keyboard. Just select "Key" as the incoming controller and set the mode to "Latch". Then, assign "Start MIDI Clock" to "On" and "Stop MIDI Clock" to "Off". Pressing the key multiple times will start and stop the clock.
If you start the clock in the previous example with the key and then stop the clock with the stop-button in Midiflow, the clock won't start again when you press the key the next time. Only after you press it another time, it will start. The reason is that the second key press set the clock to off although it was off already. For that reason, you might prefer setting the mode to "Direct", remove the assignment of value 0, and assign 127 to "Toggle Start/Stop MIDI Clock". Now, Midiflow will toggle the clock state on each key press. If you control the clock with the button on the screen, the next key press will correctly toggle the state.
The other available type is "Values".
It is for cases where you don't want to trigger an action but rather set an internal value of Midiflow to the value of the controller. There are currently two parameters available:
MIDI Clock Tempo
Whenever the controller changes to a new value, Midiflow will call the corresponding preset. However, you'll have to set a number to each of your presets first.
Controller assignments can have conditions.
You could use the keys on your keyboard to call presets. Just choose "Note Value" as incoming controller. However, you most probably also want to use the keyboard for playing. So, you can add a condition that only activates this controller assignment when you activate another controller, which then acts as a "shift" key for enabling an alternative function.
You can delete a controller assignment by tapping "Delete assignment" at the end of the assignment screen. Alternatively, you can swipe to the left on the assignment item in the configuration screen. This will unveil a delete button.
The "Input keyboard" is a placeholder for an input port. It appears everywhere in Midiflow where you can select a source, for example the source of a routing.
While you perfectly could select the port of your keyboard directly, it has some advantages to use the "Input keyboard" instead. For example, if you want to build many configurations and store them as presets, you could easily use them with another keyboard. Just reconfigure the "Input keyboard" to another port. You do that by tapping the "INPUT" button.
You can also specify a channel.
Using the "Input keyboard" is also advisable if you plan to share your configuration. After someone has installed you preset, he/she will immediately be able to use it with his/her keyboard without any further configuration.
By sharing a MIDI clock signal across multiple MIDI devices, you can keep them in sync. While you can route the clock signal of a port to other ports with Midiflow, you can also use it's internal clock. It is very precise and can be controlled via MIDI. In order to use the internal clock, just create a routing and select "MIDI clock" as source.
After setting one or more destinations, you can start all of them by using the transport controls at the lower right of the screen.
There, you can either tap the tempo:
Or specify the exact value:
If you would like to set the clock tempo via MIDI, you can do that by creating a controller assignment.
In the modifier screen of a routing, you can modify the clock signal.
Midiflow can generate MIDI data out of device motion. This transforms your device into a great and expressive controller itself. To do that, you first need to specify 'Motion' as a MIDI source:
This will activate polling data from the gravity sensor. It creates raw data that then needs to be transformed into MIDI using a controller remapping. For that reason, you will see the following dialog that allows you to create such a routing very quickly.
You have to choose which axis you want to use. If you hold the device in landscape orientation, the X-axis goes from left to right. That means that the values become larger when you turn the device to yourself. The Y-axis goes from top to bottom, the values increase by turning the device to the right. When you hold the device parallel to the ground, both axes are zero. The following image illustrates this:
After selecting an axis, the details of the newly created controller remapping will show up. However, if you haven't purchased "Controller remapping", you cannot edit the remapping any further. In that case, you can still use the remapping as it is. It converts the motion data to CC1 (Modulation).
The remapping for motion works as any other controller remapping. The first thing you might want to do here is adjusting the input range to a smaller range. By default, you have to rotate the device by 180 degrees to go from minimum to maximum, which is not always desired. As described in MIDI learn, you can simply tap and hold the lower bound and move the device to the desired minimum position.
Do the same with the maximum position.
You could control the volume of a synth sound of another app by tilting the device. This allows for very expressive playing. Just select the appropriate controller (like volume or expression) as outgoing controller, and you are ready to go.
You can add more remappings for motion, for example in order to control something else with the other axis. See controller remapping.
In order to literally see what's happening in your MIDI configuration, you can turn on monitoring at the bottom of the screen.
Each routing will then monitor the data it is processing. Data coming in at the source will scroll down to the modifier. The modified data will scroll down to the destination. This should give you a good understanding of you current configuration and can can be really helpful to find misconfigurations.
Since there can be a lot of MIDI data, you can hide all data which is not a note or a controller, by tapping "NOTES & CTRLS" at the bottom of the screen.
By default, Midiflow displays the MIDI data in a readable format. If you prefer to see the raw hexadecimal or decimal values, you can change the mode in the configuration screen.
As described in Working with apps, Midiflow communicates with other apps via their virtual ports. Midiflow itself does not create own virtual ports by default because this is not need most of the time. However, if you cannot use the virtual port of another app for some reason, you can instead create a custom port in Midiflow and select it in the other app as source.
Creating a new input port is possible in every source selection screen. Respectively, a destination can be created in every destination screen.
Just tap "Add virtual input"/"Add virtual output". This will open a screen that lets you specify a port name. There is no limitation, but make sure yourself that you don't have name clashes with the MIDI ports of other apps.
After you have created a new port, don't forget to select it. The new port is available in all selection screens now, so you can use it in multiple routings.
You can delete a port by swiping to the right on it. This will unveil a delete button.
If you delete a port which is currently selected, it will stay in the list, but grayed out. If you tap on a grayed out port, Midiflow will create it again. If you want to unselect a grayed out virtual port, tap on the check mark (and not on the port name).
The panic button at the upper left corner lets you send note off messages to all MIDI destinations. So, if something goes wrong and you hear stuck notes, you can make all your devices stop producing sounds immediately.
This also cancels all retained routings. See Routing retention for more about that.
If you are using Midiflow in conjunction with other apps, it is important that it runs in the background and continues routing your MIDI data. In order to save battery, it will terminate however after 30 minutes, if no MIDI data has been received during that time. You can adjust this "background time" interval in the configuration screen.
Midiflow can connect to other iOS devices or Macs via Bluetooth. However, this requires iOS8 or later, and Mac OS X 10.10 Yosemite or later.
In order to establish a conection, you can tap "Advertise this device" to make your device act as a server. It can then be seen by other devices.
Alternatively, if there is already a server, you can connect to it by tapping "Nearby devices". A list with available MIDI servers will appear.
Midiflow currently offers two in-app purchases:
If you have reinstalled Midiflow, you can restore these purchases in the configuration screen by tapping "Restore".
Do you have problems with Midiflow or some ideas on how to improve it? Feel free to send a message! There is a feedback button at the top left corner.
Even if everything works fine for you with Midiflow, that's also an important information worth noting. :) Don't forget to tell your friends as well. Writing a review in the App Store is one of the best ways to support Midiflow. However, if you have a problem with the app, make sure to send us an email so that we can send a helpful response. We are not able to reply to an App Store review.