Ambika MPE support?

Hi all,

I do not think the Ambika supports MPE, or does it? That would be really awesome. Anyone working on this?

Regards
Björn

No it doesn’t.

But it is does support polyphonic aftertouch!
Cheers

(quick question, is there a docker image to build the firmware? I only remember having to install a bunch of stuff on my osx to flash the chips)

I’d interested in implementing per channel aftertouch on the ambika to use with my continuum. I tried to understand a bit the ambika code and first searched in the firmware code using (https://github.com/pichenettes/ambika/search?q=Aftertouch&unscoped_q=Aftertouch&type=Code). But I’m not sure i understand the flow of midi data. Seems like

  1. controller.cc is calling a function to pool if there’s new midi data and also supports running_status to minimize midi data.

int main(void) {
Init();
ui.FlushEvents();
while (1) {
// Do some MIDI.
while (midi_in_buffer.readable()) {
midi_parser.PushByte(midi_in_buffer.ImmediateRead());
}
// Do some LFOs and clocks.
multi.UpdateClocks();
// Do some display.
ui.DoEvents();
}
}

Ok, looking at void MidiStreamParser<Device>::PushByte(uint8_t byte) in midi.h we see that realtime stuff gets processed and skips the whole checking:

if (byte >= 0xf8) {
MessageReceived(byte);

It then checks on hi value to adjust parameter #s and sets polyAT and CCs expected_data_size_ to 2 and channel pressure to 1, which is expected. Ultimately, after checking we’re not dealing with sysex we set

} else {
running_status_ = byte;
}

Eventually, we keep on parsing the midi stream (filling data_) until we have the right amount of parameters:

if (data_size_ >= expected_data_size_) {
MessageReceived(running_status_);
data_size_ = 0;

Where we will call MessageReceived(running_status_) which contains the type of MIDI message as it was filled up with our command byte.

Early into this function we have

// If this is a channel-specific message, check first that the receiver is
// tune to this channel.
if (hi != 0xf0 && !Device::CheckChannel(lo)) {
Device::RawMidiData(status, data_, data_size_, 0);
return;
}

Now, as far as I can see, CheckChannel is:

static uint8_t CheckChannel (uint8_t channel) { return 1; }

which translates to if (true && false) in case of a non system exclusive msg, so we keep on going.

Eventually we arrive at switch (hi) for polyAt and channel. When we get to channel pressure we have:

case 0xd0:
Device::Aftertouch(lo, data_[0]);
break;

Which I’m guessing should be this one, with interesting use of velocity instead of pressure :slight_smile:

static void Aftertouch(uint8_t channel, uint8_t velocity) {
multi.Aftertouch(channel, velocity);
}

which leads to

static void Aftertouch(uint8_t channel, uint8_t velocity) {
for (uint8_t i = 0; i < kNumParts; ++i) {
if (data_.part_mapping_[i].receive_channel(channel)) {
parts_[i].Aftertouch(velocity);
}
}
}

So, after here we lose track of the channel reference as we will call parts_[i].Aftertouch with only the velocity (pressure?) which leads to sending it to everyone:

void Part::Aftertouch(uint8_t velocity) {
WriteToAllVoices(VOICECARD_DATA_MODULATION, MOD_SRC_AFTERTOUCH, velocity);
}

I’m wonder if Oliver can give some tips on the best way to add MPE-like channel pressure per channel. My idea was to change the multi.h to actually send to the channel the pressure level.

has anyone figured this out yet? is MPE support even possible?

I’m coming back to this project… but I still need to figure out the best way to compile the firmware on my Mac and I’m assuming there’s no debugging possible. I wonder if I can use the screen for debugging

1 Like

Ooohhh… this would be great. Although, if it isn’t working yet, it might be best to wait until the midi 2.0 spec is released. I suspect it will offer a tidier way to implement poly expression.

edit: never mind… it seems that 2.0 will not work over the 5-pin DIN.