Audiobus: Use your music apps together.

What is Audiobus?Audiobus is an award-winning music app for iPhone and iPad which lets you use your other music apps together. Chain effects on your favourite synth, run the output of apps or Audio Units into an app like GarageBand or Loopy, or select a different audio interface output for each app. Route MIDI between apps — drive a synth from a MIDI sequencer, or add an arpeggiator to your MIDI keyboard — or sync with your external MIDI gear. And control your entire setup from a MIDI controller.

Download on the App Store

Audiobus is the app that makes the rest of your setup better.

(N)RPNs -- how do they avoid "jumps" when a 7-bit boundary is crossed in 14-bit (N)RPNs?

I'm wondering how this is done in other software as the standard doesn't seem to be very exact about this.

Say you have an NRPN and use it to send 14-bit values. The last value you sent is MSB 3 + LSB 127. Now, you want to switch to the next possible value -- MSB 4 + LSB 0.

So, you first send MSB 4. HOWEVER, now the value set at the receiver is MSB 4 + LSB 127 for a brief moment, until LSB 0 is received moments later.

So, this will give a short "spike" in the receiver that is 127 too high.

The same would happen if you wanted to go from, say, MSB 3 + LSB 0 to MSB 2 + LSB 127.

How does software / hardware handle this?

I guess the receiver could specifically wait until both MSB and LSB are received each time, but I think the MIDI standard allows for LSB alone to be sent too as long as MSB doesn't change, so this would be in violation of the spec?

Comments

  • edited January 2021

    I know absolutely nothing about NRPN or MIDI programming. But based purely on your last paragraph, my first thought would be to see if you can allow LSB to change even if only LSB is received. But do not change MSB unless LSB is also received.

  • edited January 2021

    @DukeWonder said:
    I know absolutely nothing about NRPN or MIDI programming. But based purely on your last paragraph, my first thought would be to see if you can allow LSB to change even if only LSB is received. But do not change MSB unless LSB is also received.

    Thanks!

    Yes, but the problem is that LSB is not required (as far as I understand the spec). So the receiver might hang indefinitely waiting for an LSB that never arrives.

    EDIT: I guess the only way really is to add a toggle to the configuration "Always wait for LSB". If the user then KNOWS that they have a sender that only sends MSB or doesn't include LSB consistenly, they can turn this off and live with the occasional zipper noise.

  • I have a MIDIFire/Streambyter script that parses the values of a SysEx patch dump from the Novation Peak and then sends these values as NRPNs to a layout in MIDI Designer app.

    I needed to introduce a 20-30ms delay between messages otherwise the values all got scrambled.

    Nic, the Dev of MIDIFire has previously mentioned that the CC#s 98/99 of an NRPN might need 'terminating' between messages. I think this involved sending a 7F value to both of those before the next message.

    I didn't employ this strategy myself as the ms delay seemed to work for me.

    Not sure if this is relevant or useful.

    Good luck!

  • Provided the required order is always MSB before LSB, the receiver could simply buffer the last MSB received, retaining it forever. Then it could merge it with LSB, when LSB is received, to produce the 14-bit result. That would handle the case of sending LSB only; in fact, it may be the only way. This requires a register to store the MSB, separate from the 14-bit value. Obviously, testing with an actual NRPN or RPN implementation would be useful.

  • @SpookyZoo said:
    Nic, the Dev of MIDIFire has previously mentioned that the CC#s 98/99 of an NRPN might need 'terminating' between messages. I think this involved sending a 7F value to both of those before the next message.

    Hey, thanks... yes, I've implemented the "termination", that's not the issue... the issue is that a "complete" 14-bit value can consist either of ONLY the MSB (coarse) part, or BOTH MSB AND LSB (full precision), OR ONLY LSB (fine-adjustment of the last value), and the receiver (to the best of my understanding) has no way to know when the final value is "finished" and can be written to the controller lane while recording.

  • @uncledave said:
    Provided the required order is always MSB before LSB, the receiver could simply buffer the last MSB received, retaining it forever. Then it could merge it with LSB, when LSB is received, to produce the 14-bit result. That would handle the case of sending LSB only; in fact, it may be the only way. This requires a register to store the MSB, separate from the 14-bit value. Obviously, testing with an actual NRPN or RPN implementation would be useful.

    Yes, I've already implemented the MSB + LSB register -- however, this still wouldn't be able to handle the case of a sender which ONLY sends MSB and NOT LSB. Then it would be stuck waiting forever for the LSB and never record any value :(

  • @SevenSystems said:

    @SpookyZoo said:
    Nic, the Dev of MIDIFire has previously mentioned that the CC#s 98/99 of an NRPN might need 'terminating' between messages. I think this involved sending a 7F value to both of those before the next message.

    Hey, thanks... yes, I've implemented the "termination", that's not the issue... the issue is that a "complete" 14-bit value can consist either of ONLY the MSB (coarse) part, or BOTH MSB AND LSB (full precision), OR ONLY LSB (fine-adjustment of the last value), and the receiver (to the best of my understanding) has no way to know when the final value is "finished" and can be written to the controller lane while recording.

    Ah, I see. That is interesting.

    And of course, frustrating.

  • I would think that if you cross a boundary with the MSB, you could force the LSB to do the right thing until a potential actual value comes is. As you note, going up from 3+127, the next value is 4+0, so impose the LSB. If an actual LSB of 10 -- or something greater than 0 -- comes in a few milliseconds later, you'll still be able to smoothly update the value. Same thing going down: if you go from 4+0 to 3+xx, impose an LSB of 127, which would be a small, smooth step, and if an actual LSB comes in, update it. Worst case, you've got a small intermediate update with no spike. Just need to have logic to look at the direction of MSB.

  • @JohnInBoston said:
    I would think that if you cross a boundary with the MSB, you could force the LSB to do the right thing until a potential actual value comes is. As you note, going up from 3+127, the next value is 4+0, so impose the LSB. If an actual LSB of 10 -- or something greater than 0 -- comes in a few milliseconds later, you'll still be able to smoothly update the value. Same thing going down: if you go from 4+0 to 3+xx, impose an LSB of 127, which would be a small, smooth step, and if an actual LSB comes in, update it. Worst case, you've got a small intermediate update with no spike. Just need to have logic to look at the direction of MSB.

    That's an interesting take. But that in turn would introduce spikes (downwards by 127) in case the user actually INTENDED to go 128 steps up! (i.e., sends an MSB 1 higher than before, and no LSB)

    I can't believe the MIDI spec isn't stricter or more thorough on this.

    I know why I haven't looked into ANY 14-bit MIDI value handling till now :D (the only situation where this actually is unambiguous is Pitch Bend, because there both MSB and LSB are required by the spec.)

  • edited January 2021

    Doesn’t this all depend on the parameter number?
    99 MSB 98 LSB (pair)
    6 MSB (coarse)
    38 LSB (fine adjustment)

  • edited January 2021

    @TheOriginalPaulB said:
    Doesn’t this all depend on the parameter number?
    99 MSB 98 LSB (pair)
    6 MSB (coarse)
    38 LSB (fine adjustment)

    No. There is no way to know for a receiver if an NRPN is supposed to be 14 or 7 bit. It is slightly better for RPN as they're obviously standardized and the bit width is standardized too, but even THEN, I think LSB is optional even for 14-bit RPNs. Madness.

  • @SevenSystems said:

    @TheOriginalPaulB said:
    Doesn’t this all depend on the parameter number?
    99 MSB 98 LSB (pair)
    6 MSB (coarse)
    38 LSB (fine adjustment)

    No. There is no way to know for a receiver if an NRPN is supposed to be 14 or 7 bit. It is slightly better for RPN as they're obviously standardized and the bit width is standardized too, but even THEN, I think LSB is optional even for 14-bit RPNs. Madness.

    I recommend finding someone (MIDI programmer) that has a lot of experience dealing with different devices. A quick look through some MIDI programming discussions leads me to believe that devices vary in how they deal with it. Some hardware expects both values to always be sent in which case the hardware is probably waiting till the complete message has been sent.

    This is a case where more important than the spec is how it has come to
    be implemented and whether a de facto standard has emerged. Maybe, the MIDI Designer Pro programmer would be willing to share some insights.

    It might make sense for there to be a setting on whether to require the complete message or not.

  • That doesn’t sound like it adheres to the MIDI standard.

  • @SevenSystems said:

    @JohnInBoston said:
    I would think that if you cross a boundary with the MSB, you could force the LSB to do the right thing until a potential actual value comes is. As you note, going up from 3+127, the next value is 4+0, so impose the LSB. If an actual LSB of 10 -- or something greater than 0 -- comes in a few milliseconds later, you'll still be able to smoothly update the value. Same thing going down: if you go from 4+0 to 3+xx, impose an LSB of 127, which would be a small, smooth step, and if an actual LSB comes in, update it. Worst case, you've got a small intermediate update with no spike. Just need to have logic to look at the direction of MSB.

    That's an interesting take. But that in turn would introduce spikes (downwards by 127) in case the user actually INTENDED to go 128 steps up! (i.e., sends an MSB 1 higher than before, and no LSB)

    This could be paired with a timeout -- or the above-mentioned 20-30ms delay -- that handles the various cases:

    1) User sends MSB only:
    a) Immediately change both MSB+LSB to 4+0, store the current LSB value of 127
    b) After timeout expires, overwrite the 0 with a 127
    User will experience a small change in the correct direction followed by bigger change in that direction 20ms later, with no spikes. In this case, they probably wouldn't perceive the 1LSB change compared to the much larger MSB change

    2) User sends both MSB+LSB:
    a) Immediately change both MSB+LSB to 4+0, store the LSB value of 127
    b) Some very short time later, new LSB comes in. Update it and cancel the timeout.
    Again, user will experience a small change followed by the intended change, both in the correct direction. Latency will be whatever the MIDI message latency is.

    Even if the LSB is in the middle of the range, say 63, you'd go from 3+63 to 4+0 to 4+63 after 20ms, which is 2 half steps in the right direction, with no spikes.

    Otherwise, you either take the spikes if you respond immediately, or you impose a timeout every time.

  • edited January 2021

    Bizarrely, this ancient thread contains an almost identical question from 2013. https://www.kvraudio.com/forum/viewtopic.php?t=293361

    @SevenSystems You aren’t Martin, are you? :)

  • @espiegel123 said:

    @SevenSystems said:

    @TheOriginalPaulB said:
    Doesn’t this all depend on the parameter number?
    99 MSB 98 LSB (pair)
    6 MSB (coarse)
    38 LSB (fine adjustment)

    No. There is no way to know for a receiver if an NRPN is supposed to be 14 or 7 bit. It is slightly better for RPN as they're obviously standardized and the bit width is standardized too, but even THEN, I think LSB is optional even for 14-bit RPNs. Madness.

    I recommend finding someone (MIDI programmer) that has a lot of experience dealing with different devices. A quick look through some MIDI programming discussions leads me to believe that devices vary in how they deal with it. Some hardware expects both values to always be sent in which case the hardware is probably waiting till the complete message has been sent.

    This is a case where more important than the spec is how it has come to
    be implemented and whether a de facto standard has emerged. Maybe, the MIDI Designer Pro programmer would be willing to share some insights.

    It might make sense for there to be a setting on whether to require the complete message or not.

    I was thinking this as well. They are Non-Registered Parameters, after all. So the receiver can implement them as it chooses, and just tell the sender what it expects. It does make it tough for a sequencer, though, since its user needs to be able to configure these specifics for each target device or app. Obviously, this can be managed between components from the same vendor, but outsiders are left with a guessing game.

  • edited January 2021

    @TheOriginalPaulB said:
    Bizarrely, this ancient thread contains an almost identical question from 2013. https://www.kvraudio.com/forum/viewtopic.php?t=293361

    @SevenSystems You aren’t Martin, are you? :)

    Wow, thanks for digging that up. No, I'm not Martin :D reading the thread made me really sad though, as it essentially means that (N)RPNs (and by extension, regular 14-bit CCs) are unusable in practice because of bad specification and implementation. Incredible!

    However, one poster there had an interesting idea: If from a particular source, an MSB is received, wait for LSB with a certain timeout. If no LSB is received, assume that this source ALWAYS only sends MSB, and in the future, act on every MSB immediately. Likewise, if an LSB IS received, "flag" this source as "Sends LSB" and always wait for the LSB in the future.

    It's still a hack though.

    @espiegel123 said:
    I recommend finding someone (MIDI programmer) that has a lot of experience dealing with different devices. A quick look through some MIDI programming discussions leads me to believe that devices vary in how they deal with it. Some hardware expects both values to always be sent in which case the hardware is probably waiting till the complete message has been sent.

    This is a case where more important than the spec is how it has come to
    be implemented and whether a de facto standard has emerged. Maybe, the MIDI Designer Pro programmer would be willing to share some insights.

    It might make sense for there to be a setting on whether to require the complete message or not.

    Yeah, it looks like the only "proper" way to do this is -- again -- to offer a multitude of obscure settings (just as with MIDI sync, but worse!) and have the poor user try all combinations until something works.

    @uncledave said:
    I was thinking this as well. They are Non-Registered Parameters, after all. So the receiver can implement them as it chooses, and just tell the sender what it expects. It does make it tough for a sequencer, though, since its user needs to be able to configure these specifics for each target device or app. Obviously, this can be managed between components from the same vendor, but outsiders are left with a guessing game.

    Yeah, that's the main problem -- as I'm adding (N)RPN support to Xequence, I need to know when I can "write" the received (N)RPN value into the clip. (I want to represent (N)RPNs "properly" so they can be edited comfortably like any normal controller, so I have to "convert" them to the internal "normal" representation with simple atomic values).

  • @SevenSystems said:

    @TheOriginalPaulB said:
    Bizarrely, this ancient thread contains an almost identical question from 2013. https://www.kvraudio.com/forum/viewtopic.php?t=293361

    @SevenSystems You aren’t Martin, are you? :)

    Wow, thanks for digging that up. No, I'm not Martin :D reading the thread made me really sad though, as it essentially means that (N)RPNs (and by extension, regular 14-bit CCs) are unusable in practice because of bad specification and implementation. Incredible!

    However, one poster there had an interesting idea: If from a particular source, an MSB is received, wait for LSB with a certain timeout. If no LSB is received, assume that this source ALWAYS only sends MSB, and in the future, act on every MSB immediately. Likewise, if an LSB IS received, "flag" this source as "Sends LSB" and always wait for the LSB in the future.

    It's still a hack though.

    @espiegel123 said:
    I recommend finding someone (MIDI programmer) that has a lot of experience dealing with different devices. A quick look through some MIDI programming discussions leads me to believe that devices vary in how they deal with it. Some hardware expects both values to always be sent in which case the hardware is probably waiting till the complete message has been sent.

    This is a case where more important than the spec is how it has come to
    be implemented and whether a de facto standard has emerged. Maybe, the MIDI Designer Pro programmer would be willing to share some insights.

    It might make sense for there to be a setting on whether to require the complete message or not.

    Yeah, it looks like the only "proper" way to do this is -- again -- to offer a multitude of obscure settings (just as with MIDI sync, but worse!) and have the poor user try all combinations until something works.

    @uncledave said:
    I was thinking this as well. They are Non-Registered Parameters, after all. So the receiver can implement them as it chooses, and just tell the sender what it expects. It does make it tough for a sequencer, though, since its user needs to be able to configure these specifics for each target device or app. Obviously, this can be managed between components from the same vendor, but outsiders are left with a guessing game.

    Yeah, that's the main problem -- as I'm adding (N)RPN support to Xequence, I need to know when I can "write" the received (N)RPN value into the clip. (I want to represent (N)RPNs "properly" so they can be edited comfortably like any normal controller, so I have to "convert" them to the internal "normal" representation with simple atomic values).

    In practice, I don't think the situation is as dire as you suggest. Yes, there is some variation. But really it amounts to two possibilities and it will be pretty quick to tell which of the two schemes a piece of equipment uses. I also think that if you were to go talk to someone that has written software that has been around for a while that is used by a reasonable number of people, you will get a practical sense that you won't get by querying the folks here.

  • edited January 2021

    @espiegel123 said:
    I also think that if you were to go talk to someone that has written software that has been around for a while that is used by a reasonable number of people, you will get a practical sense that you won't get by querying the folks here.

    Yes, valid point 👍

    I still stand by my criticism though -- specifications are there for a reason and no implementor should have to worry about such stuff. Sorry, I'm German. We've INVENTED standardization 😂

  • @SevenSystems said:

    @espiegel123 said:
    I also think that if you were to go talk to someone that has written software that has been around for a while that is used by a reasonable number of people, you will get a practical sense that you won't get by querying the folks here.

    Yes, valid point 👍

    I still stand by my criticism though -- specifications are there for a reason and no implementor should have to worry about such stuff. Sorry, I'm German. We've INVENTED standardization 😂

    I am going to disagree that specifications should never be violated. Sure, generally wants to stay consistent with standards. But there are times when standards are old in the tooth and inadequate -- I'd argue that it is better to make a thoughtful re-purposing of the standard if it enables one to accomplish something not readily accomplished with the standard. In some cases, a standard (as in this case) left a small amount of wiggle room and resolving the ambiguity is not really terribly tricky.

  • To send NRPN's you always have an MSB+LSB pairing. So, the time for these cases is identical:

    MSB 3 + LSB 126 to MSB 3 + LSB 127
    MSB 3 + LSB 127 to MSB 4 + LSB 0

    So there's isn't really a "jump" when crossing over MSB boundaries.
    It's NOT like the MSB gets set and LSB's are then sent until an MSB changes.

    If there's NOT an MSB sent first then you just have a standard RPN.

    It's seems like synths would using NRPN's for features like programatic Preset recalls
    and not something where the values might get changed with an LFO requiring rapid timely
    processing of NRPN changes.

  • @McD said:
    To send NRPN's you always have an MSB+LSB pairing. So, the time for these cases is identical:

    MSB 3 + LSB 126 to MSB 3 + LSB 127
    MSB 3 + LSB 127 to MSB 4 + LSB 0

    So there's isn't really a "jump" when crossing over MSB boundaries.
    It's NOT like the MSB gets set and LSB's are then sent until an MSB changes.

    If there's NOT an MSB sent first then you just have a standard RPN.

    It's seems like synths would using NRPN's for features like programatic Preset recalls
    and not something where the values might get changed with an LFO requiring rapid timely
    processing of NRPN changes.

    @McD: Some synths use NRPNs in order to achieve 14-bit resolution and do use them for things meant for continuous control (like filter and volume settings).

  • @espiegel123 said:
    @McD: Some synths use NRPNs in order to achieve 14-bit resolution and do use them for things meant for continuous control (like filter and volume settings).

    My point is that 2 bytes are always transmitted. So, a change in the MSB doesn't mean there would be a "jump" (which I interpret to mean a processing delay).

    For rapid processing like filters and volume, I see mention of coarse and fine grain settings.

    On side-tracks:

    how many bits do AUv3 Parameters support?
    does MIDI 2.0 change the byte oriented MIDI 1.0 paradigm?

    Google search...

  • @McD said:

    @espiegel123 said:
    @McD: Some synths use NRPNs in order to achieve 14-bit resolution and do use them for things meant for continuous control (like filter and volume settings).

    My point is that 2 bytes are always transmitted. So, a change in the MSB doesn't mean there would be a "jump" (which I interpret to mean a processing delay).

    I think you might have missed a part of the discussion. The MSB and LSB are not always sent -- hence the question that initiated this.

  • @McD I believe AUv3 parameters are real values (floating-point), with min/max limits specified by the app. They can even specify a logarithmic scale, appropriate for frequency parameters. It is the hosts that let us map them to MIDI CCs.

  • @McD said:
    To send NRPN's you always have an MSB+LSB pairing.

    Nope, that's the problem, the MIDI spec allows any combination to be sent. You can skip either MSB ("fine-adjustment" of last known value) or LSB (then it's a "coarse" 7-bit NRPN).

    It's NOT like the MSB gets set and LSB's are then sent until an MSB changes.

    Oh it is. That's precisely what the spec allows, unfortunately.

    What do you think why I'm again screaming in disgust for days :)

    It's seems like synths would using NRPN's for features like programatic Preset recalls
    and not something where the values might get changed with an LFO requiring rapid timely
    processing of NRPN changes.

    No guarantee for that though. I know at least one example first hand where NRPNs are actually used for parameter movements -- my Yamaha AN1x! When it's in "brown" mode, all knob movements are sent / received via NRPNs.

  • Thanks everyone again for the input -- I've now opted for making "Wait for LSB before writing the value" an option, and otherwise intelligently guessing the LSB when the MSB arrives as per the quoted forum post (depending on incrementing or decrementing MSB value). Also, Xequence has a removeDoubleControllers function that I've extended to try to take care of the "superfluous" MSB value in any case (this works if the two values are close enough together in time so that the MSB can be recognized as a "double" and thus removed).

    I think this is the best possible implementation. Good to have this discussed.

    Also, this option takes the crown for the "Most convoluted and complicated hint message in Xequence", I guess!

Sign In or Register to comment.