Timbre ("Glide") on Seaboard Rise


#1

(This relates to previous posts here and here, but since it's not the main concern of either thread, I'll start a new topic.)

I am still having diffulty getting the correct initial cc74 (timbre/glide) value from the Seaboard Rise MPE keyboard. The Seaboard sends a cc74 message right before the key-on message*, so that the note starts with the correct timbre value (it then sends further cc74s while the key is pressed if the position of the finger changes).

However, that value is not outputted by the mpe keyboard object, nor is it read into the _timbre variable in Smashed Transistor's modified mpe keyboard object (axoloti-contrib/objects/tiar/midi/in/mpe sbrd rise)

As a consequence one often gets ugly glitches from the cc74 value at the end of the previous note to the real one shortly after the key press. It also leads to completely wrong `initTimbre' with Smashed T's object.

I suspect this has to do with the voice allocation of axoloti polyphonic patches. At any rate I noticed that a midi monitor placed in the main patch correctly displays the pre-note-on cc74 message, but the same monitor placed within the polyphonic subpatch only shows cc74s after the key-on message.

Long story (sorry!) short: Anyone have a workaround for this? Or better yet: Am I missing something?

Thanks & cheers!

*at least most of the time; I'd be happy to get those cases to work properly and deal with the outliers later...


#2

The _timbre is continuously updated in the MIDI Code (whatever the note off or on).
_initTimbre is set to _timbre when the note on is received.

if ((status == MIDI_NOTE_ON + attr_midichannel) && (data2)) {
  ...
  _initTimbre = _timbre;
} else

...

} else if (status == attr_midichannel + MIDI_CONTROL_CHANGE) {
  if (data1 == MIDI_C_TIMBRE) {
    _timbre = (((int)(data2<<7)-0x2000)<<14) + _yl;
}
...

I do not have my Seaboard rise connected to the axo, but i will certainly experiment asap.


#3

You'd think so, wouldn't you? After I got weird results, I put some logging into your code...

...and it turns out, nothing is registered. Here's a typical log. The 'Control...' and 'NoteOn/Off...' messages are from the midi/in/monitor.

Control ch 2 cc 74 v 39
PitchBnd ch 2 v  0 v 64
NoteOn  ch 2 n 74 v 56
InitialTimbre 0
Control ch 2 cc 74 v 42
Timbre set to -22
NoteOff ch 2 n 74 v  1

Note how there is no `Timbre set to...' corresponding to the first 'Control ch 2 cc 74 v 39'.

For reference, here's the kind of setup i'm using to check this. Maybe i did something stupid...

timbre2.axp (12.1 KB)


#4

as @SmashedTransistors said, the CC are sent thru regardless of if the voice is active or not,
you can see this in teh generated code of xpatch.cpp

        } else if (msg == MIDI_CONTROL_CHANGE) {
          if (data1 == MIDI_C_POLY) {
            if (data2 > 0) {
              if (channel == 0) {
                if (channel != 15) {
                  lowChannel = channel + 1;
                  highChannel = lowChannel + data2 - 1;
                } else {
                  highChannel = channel - 1;
                  lowChannel = highChannel + 1 - data2;
                }
                for (int i = 0; i < 1; i++) {
                  getVoices()[i].MidiInHandler(dev, port, MIDI_CONTROL_CHANGE + 0, 100, lastRPN_LSB);
                  getVoices()[i].MidiInHandler(dev, port, MIDI_CONTROL_CHANGE + 0, 101, lastRPN_MSB);
                  getVoices()[i].MidiInHandler(dev, port, MIDI_CONTROL_CHANGE + 0, 6, pitchbendRange);
                }
              }
            } else {
              lowChannel = 0;
              highChannel = 0;
            }
          }
// HERE  IS BIT YOUR INTERESTED IN, 
// as you see, sends to voice regardless of 'state'  (voices are created at compile time) 
          if (channel != 0
              && (channel < lowChannel || channel > highChannel))
            return;
          int i;
          for (i = 0; i < 1; i++) {
            if (voiceChannel[i] == channel || channel == 0) {
              getVoices()[i].MidiInHandler(dev, port, MIDI_CONTROL_CHANGE + 0, data1, data2);
            }
          }
// STOPS HERE

the only odd thing I see in your patch (sorry dont have time to test it) ,
is that you set the sub patch midi channel to 2, this should not be done (it should remain at 1) , but in practice i dont think it makes any difference.... but perhaps a quirk there? (as i never change it, so haven't test it )
(basically, when I code this, I decided midi channel would represent the global channel, as the note channels are always relative to it)

hmm, what I would do is... probably put some logtextmessages in xpatch.cpp to see where the message is getting lost.

also does this happen with the factory mpe keyboard object?
Im sure it was fine when I tested it with the eigenharp and soundplane ... as you say, not taking taking timbre into account before note-on would cause nasty glitches (and pitchbend is the same if you use a continuous surface like the soundplane)

all odd, as I used the mpe factory object quite a bit and didnt have any issues, but its been a while since I last looked at it...
(there were some small issues noted, which are worked around in the derivative objects, but honestly its a long time ago, since I looked at them, so cant remember precise details)


#5

I'm getting back a seaboard rise, i'll try to give a try this weekend.


#6

I confirm that the timbre info is received after the note on in the MIDI handler.
(thus the initTimbre on my mpe sbrd rise object does not work)

@thetechnobear, maybe

  • the seaboard does not send the timbre info ahead of the note on (as it should do) ?
  • or the midi is sorted by the Axoloti firmware before calling the midi handler ?

[EDIT 26jan 11:30 :clock1130: ]
It seems that the seaboard does not send the timbre info before the note on.
It sends it after the note on.

It does not seem to be a fixed time, it seems that the timbre signal is sent by the seaboard when a pressure level is reached (maybe it needs some pressure to get good accuracy).

I should have experimented more with this :confused:


[EDIT 26jan 12:00 :clock12: ]

It is quite confusing, when i connect it to the PC with the Roli Dashboard, the display shows the right glide position even for very light pressure.


#7

Sure about the not sending? Try putting a midi monitor in the main patch; i see a timbre before most notes (though not each and every one, for some reason).


#8

You're right.
I'm quite confused, i missed something :face_with_raised_eyebrow:


#9

That makes two of us :slight_smile:


#10

I put the midi monitor in the patcher (which i forced to polyphony 1).
and, when placed in there, there is no more "pre note on" Timbre CC.

@thetechnobear, @Captain_Burek
Now, I guess it has something to do with polyvoice allocation, if voice allocation is triggered by note on, the "pre note on" Timbre CC cannot be sent to it and the seaboard won't transmit a new value until it changes.

The MPE polyvoice allocation system should keep track of the timbre CC for each channel (even for note off channels) in order to send it to the allocated voice when the note on comes in).

I'm afraid i can't do anything more.


#11

as a workaround you can have monophonic subpatches set to different channels, inconvenient, but i had to do the same to get guitar midi (one channel per string) working correctly. of course you need a way to decrease polyphony on the seabord, if you can't have 16 mono voices in your patch (cpu or sram)


#12

I'm not sure if it is a firmware issue or a problem with the generated code. In the second case, i think it could be fixed more easily than firmware.

Maybe, much like you suggested, it is possible to design a "midi processor object" that can preprocess the midi stream ahead of the polyvoice allocation system to move the "pre-note-on-timbre-CC" to "first-post-note-on-timbre-CC" so that it will be compatible with the current polyvoice allocation system of the MPE patcher... It will be quite complicated and prone to bugs but it should work.

External MPE    ->  pre-note-on CC74 -> patch/patcher (MPE with MIDI selector)
midi device: usb    preprocessor        midi device: internal

#13

So here's a first go at the kind of workaround SmashedTransistors hinted at. I fear that this will be too resource intensive, but I will continue playing with it and reporting back.

The general idea is to write the latest cc74 for each channel into a table and then read out that table upon gate close in each polyphonic subpatch. The rest would be straightforward.

All comments/suggestions welcome.

initial timb.axp (12.4 KB)


#14

Yes, that's exactly the kind of stuff I'm planning to do. :slight_smile:
It's a live proof of concept.

As my first experiments go, with hard coded objects it won't be CPU intensive.

I experiment a patch/patcher with a 1 polyphony for test purpose (so that i can see the values with oulets on the patch/patcher).

The procCC74 object takes all MIDI (excepted internal MIDI) and send it to the internal port 1. It memorizes the "pre Note on" CC74 for each channel and send it just after the note On.

Inside the patch/patcher I have a "mpe sbrd rise" with a new attribute "initTimbreMode" that I can set to "post NoteOn".

I'll experiment a little more with these and I'll upload it to the library (along with an example patch) as soon as I am confident enough :wink:


#15

You can try the help patch
Editor's menu Help -> Library -> community -> tiar -> midi -> in -> procCC74

It is a 8 voice saw generator with a resonant filter, the cutoff is controlled by the relative "slide/timbre" (i.e. the current vertical position minus the initial position).

It seems to work fine with my seaboard rise 49.

Tell me if it works with yours or if you have some issues.


#16

This works great, Smashed T.! I will update my patches over the weekend. Thanks, I thought this was a nice example of a fruitful exchange.


#17

Sure, sorry you had to wait for me getting back my seaboard. Withbthis kind of little nasty bugs i prefer the live practical approach to the theoretical speculative approach.

The Axoloti is really great in that respect as it allows quick experimentation.

It should be used in digital signal processing classes.