Real time note transmittor with standard MIDI

Hi Martin and Thomas,
perhaps some crazy ideas here below, and not within the intended comfort zone of the E1.
Nonetheless, I’m just curious: is the E1 fast enough when it comes to real time processing/retransmitting incoming notes and aftertouch ?
If it is fast enough, we may use it for MIDI note event filtering/routing. Not the standard stuff like taking out messages or changing channels, but more advanced things:

  • Take the lowest note played below middle C and transmit only that note to a different MIDI channel, so the bass can (also) be played by a separate bass synth
  • Same for highest note played above a certain threshold => lead synth
  • Apply multitimbral keyboard tricks in combination with monotimbral sound engines:
    • layering: duplicate incoming messages over multiple channels, to allow quick layering of multiple synths (16 on/off buttons on a screen define to which midi channel you transmit to)
    • velocity layering: same as layering, but per outgoing channel the velocity values can be recalculated, for instance: Vel becomes 127-Vel). Now you can dynamically balance between 2 synth sounds.
    • keyboard split : assign key zones to different midi channels, combined with a transpose function
  • Filter out the channel aftertouch and assign its value as polyphonic aftertouch to the highest note only
  • Synth polychaining: Distribute the incoming notes messages via some round robin method over multiple midi channels, so you could polyphonically control multiple (monophonic) synths of various make.

I’ll be testing some of these ideas just to learn working with midi callback functions.

Now I’ll try to leave this behind me and concentrate on today’s work :slight_smile:

1 Like

i had as wel this idea of implementing polyphony over different channels using rounrobin.
you could use it to play polyphonic synths that are multimembral.
then change every patch a bit for depth
If i am correct we should now be able to perform actions based on any incomming midi message type. not sure
polyAT on the last note only is as wel a cool idea. i believe the SY 85 or 99 does that.

the idea is not mine. Steve Hunt has implemented it in his LFE and also Arturia has foreseen something similar in the latest polybrute firmware. It is indeed a very musical way of using aftertouch. And a lot of synths respond to polyAT (without generating it themselves).

Based on my experimentation it is fast enough. I’m working on E1-based “advanced” controller for Launchpad Pro – chords, arp, sequencer, that kind of stuff – and the initial tests are rather promising.

3 Likes

So far the midi layering is quite simple to do. Code is below.
A bit of explanation. I have 16 buttons with parameter numbers 1001 til 1016. If on value 1, the purpose is to transmit the note to channel 1 to 16, hence why I subtract 1000 from the parameternumber.
I need to check transmission for each note On and note Off, therefor two callback functions.
I allow incoming messages from any channel, but I never retransmit into the incoming channel as this is already covered by the E1’s own routing.
Last but not least, I gave each button the function ‘silenceNotes’ so it will send the ‘All Notes Off’ on midiCC123 when layering is no longer wanted. This to prevent stuck notes.

Learnings so far

  • the E1 is pretty fast, so I hear no delay so far, even when I send the same note to 10 different MIDI channels at once :slight_smile:
  • Not all synths responds to midiCC 123 (or 120) so I do get stuck notes if I switch off a button whilst playing

Can anyone help with the following:

  • This is still simple code, but it does process lots of if-statements. Is that good coding if we want the E1 to be at it fastest? If not, how should I rewrite it?
  • To overcome the issue with the stuck notes, I will need to retain what notes are being held so I can individually transmit a NoteOff to each of them to the appropiate channel. What is the best (and fastest) way to get this working: should I make an array with 120 notes where I keep the state of each note at all times? Or should I rather assume a max polyphony of let’s say 10 held notes max, so my array would be much smaller and only contains the current notes, but is maybe much more difficult to handle? I’m inclinded to actually go for an array of 122 notes (120 + spaceholder for current lowest and current highest note)

– Setup

deviceId = 1
device = devices.get(deviceId)
devport = device:getPort()
devchannel = device:getChannel()
pages.setActiveControlSet(1)

– callback functions

function midi.onNoteOn (midiInput, channel, noteNumber, velocity)
for i = 1,16 do
if i == channel then end
if (parameterMap.get (deviceId, PT_CC7, 1000+i) == 1 ) then
midi.sendNoteOn (devport , i, noteNumber, velocity)
end
end
end

function midi.onNoteOff (midiInput, channel, noteNumber, velocity)
for i = 1,16 do
if i == channel then end
if (parameterMap.get (deviceId, PT_CC7, 1000+i) == 1 ) then
midi.sendNoteOff (devport , i, noteNumber, 0)
end
end
end

– this sends an ‘all notes off’ when the midi channel is no longer to be used.
function silenceNotes(valueObject, value)
local message = valueObject:getMessage()
if value == 0 then
midi.sendControlChange(devport, tonumber(message:getParameterNumber())-1000, 123, 0)
end
end

1 Like

I have some ideas for all of this, but I really don’t have any time until Sunday to sketch out answers.

LUA doesn’t have a switch statement so my thought would be to use an array and then execute the function directly.

Note offs are a problem for anything doing MIDI. Most end up keeping a queue/stack/list of notes sent (note number, channel) and as you send offs, clear that entry and when there’s a channel switch go through the list and clear out (or adjust) the ones affected by the channel change

1 Like

cool stuff.

Regarding the performance, E1 is rather fast I would say, When it came to adding scripting to E1, I decided to use Lua as the implementation seemed very efficient and fast. I will follow this thread, I guess ideas will be flying around here. If you felt anything is needed to be added or adjusted on the side of the firmware, just post it here.

@farcaller - I am very curious!

1 Like

The first version of the note processor is ready .

It contains the multitimbral functions I was looking for, with layering, splits, key zones, velocity inversions, volume management, incoming notes monitor and a panning randomizer. I must admit it is musically inspiring.

Before making the other functions, I’ll have to learn to work with arrays first. Have fun!

1 Like

I hope to do more work on this in January, for now it’s a quick hack to see a proof of concept :slight_smile:

1 Like

A lot of progress to report :slight_smile: I’m quite happy with the result so far.
Those arrays start to do what I want them to do !
The preset is now called “Notes Transmittor V2”

Now that I get the hang of working with tables, I’ve added a bunch of channel dependent functions and play modes:

  • Two new playing modes have been added, allowing you to layer monophonic synths on to of polyphonic ones, where they will play the highest or lowest notes, with a certain tolerance (without tolerances, you’d loose unintentionally notes when playing legato.
  • Pitch bend and Mod wheel data can now be filtered out per channel.

Next on the wish list: transmission of expression pedal, hold pedal, all cc’s, the aftertouch conversion to poly-AT on highest note only, and a synth polychain play mode.
And also ‘pure non-legato’ monophonic transmission, i.e. the previous note is first given its note off, before the next note is transmitted. This way the EG’s of the receiving synth will always be retriggered.

Idea’s , suggestions and bug reports are welcome.

1 Like

Progress report.

This is a very rewarding project :slight_smile:
Where I am so far on the remaining wish list: almost complete!
This last version is not yet published. I need to test it a bit more.

Implemented from the wishlist:

  • transmission of expression pedal with an added inverted mode, and a parameter setting to lower the range for better musical results when balancing expression values between multiple instruments
  • hold pedal transmission can be switched off per channel (default on)
  • all other cc’s transmission can be switched off per channel (default off)
  • aftertouch transmission ànd conversion to poly-AT on highest note only (SNAT) is possible.
  • 2 new monophonic play modes added, that will work on polyphonic synths also:
    • “highest/retrig”: Highest note only but with instant envelope retrigger (no legato)
    • “last/retrig”: Last note only but with instant envelope retrigger (no legato)

Left to do:

  • synth polychain play mode
  • transpose function
1 Like

thanks @oldgearguy for your tips.
Arrays were indeed the way to go.
The idea with the stack of active notes was also implemented and proofed useful.

Now for the PolyChain play mode I’ll add 2 more stacks to create a dynamic voice assignment algorithm.

  • freeVoices: this one will be fed with entries when:
    • a synth is added to the PolyChain (according to its number of voices)
    • a voice is cleared from the activeVoices stack
    • the oldest voice in the stack will be moved to the activeVoices when a NoteOn is received
  • activeVoices: this one will be fed with every NoteOn:
    • from the freeVoices stack, as long as it is not empty
    • from the activeVoices stack, if no more freeVoices are available (voice stealing)

Whenever a synth will be taken out of the PolyChain play mode, all of its voices will be cleared, regardless of the stack they are assigned to at that moment.

1 Like

very cool stuff here. I downloaded an earlier version to see what it all does and it’s pretty cool.

Glad the forum has been helpful for you.

2 Likes

Hi, version 3 is now ready and available as a preset.

A full explanation is added in its description

Was a challenge to get the polychain working decently, but I think it’s okay now. It needed 3 stacks to make it work: the active voices, the free voices and the pressed notes.

Everything is in there I could think of to turn individual synths into one multitibral monsterengine. And vice versa: to turn a monster synth back into its monophonic counter part.

The transpose is well suited for analog synths with continous pitch faders: you can now change pitch quickly without touching the oscillators and without altering the pitch of the other instruments played by the same keyboard.
And the single note aftertouch? Well, see or better hear for yourself :slight_smile:

Everything isn’t tested together yet, so there might still be some issues left. The logs are still abundant and the code needs some cleaning up.
As this is my first lua project ever, you’ll need to forgive me.
But do mention any found bugs or unexpected behaviour here, as I want this preset to be “a okay”.

2 Likes