MIDI to Velocity parser


    Jul 13 2019 | 8:06 pm
    Dear M4L community, first time poster, absolute beginner with M4L.
    I'm trying to write a MIDI parser in M4L for a module (hardware) I've built. It's a simple monophonic MIDI 2 CV converter, it receives MIDI messages of the following type: 1. pitch + pitchbend 2. note (on/off) 3. velocity 4. modulation using the MIDI standards, it then converts those to CV using a quad 16bit DAC, each DAC is dedicated to those parameters, that's what the hardware looks like (attached photo):
    power/midi
    The hardware extracts all the incoming MIDI values (3.5mm stereo to MIDI adapter cable) and converts them in the following manner:
    1. MIDI pitch + pitchbend is parsed to -3V to 5V range. 2. MIDI modulation is parsed to 0V-5V, effectively 39mV per 1 MIDI value change. 3. MIDI velocity is parsed to 0V-5V, effectively 39mV per 1 MIDI value change. 4. Note ON = high = 5V, else = low = 0V.
    The MCU does not require any other arguments, and receives on CH1 by default, there is a DIP Switch on the PCB to set a different channel if needed.
    Now, what I'm trying to do, is build a Plug-In in M4L that does the following:
    Incoming DAW MIDI (to plug-in) is being fragmented into:
    1. Pitch + Pitchbend then THRUed 2. Note ON/OFF simply THRUed (but without any additional arguments!) 3. Velocity is simply bypassed/ignored altogether, completely! 4. Modulation is redirected to f.e. a live.dial but NOT THRUed to MIDI out.
    The Plug-In UI would consist of 3 live.dials.
    1. ModWheel dial = accepts Modulation, it does not do anything by itself, nor forwards that info (can be mapped further if needed, but basically just hangs in the "air"). 2. Mappable "vel out" dial -> whatever is mapped here, is being forwarded to MIDI velocity out (0-127 value range). 3. Mappable "mod out" dial -> whatever is mapped here, is being forwarded to MIDI CC1 (0-127 value range).
    Attached a diagram as PNG (open in new TAB for enlarged version) and PDF
    Diagram
    Can someone help me wrap my head around isolating the velocity? I've figured out how to map anything to output on CC1 = modulation. But I need to understand is, how:
    1. Velocity can be decoupled from flow. 2. Can be replaced by a dynamic dial that does not simply bang out a value once on Note = on, but continuously runs its course.
    Example: The built-in envelope that ships with Ableton can be mapped to a dial, here's the course: 1. Note = ON message triggers said envelope, the attack rise begins 2. I can write a patch that bangs/triggers/makenote with the Note pitch value while the Envelope modulates the dial, that I figured out.
    What I cannot influence, is that in my MIDI log I see the following example values:
    Left = incoming MIDI, Envelope is triggered -> modulates the dial -> MIDI output rises to envelope peak, but with every value change it constantly also jumps back to "0" inbetween, which causes artifacts in CV jumps, think metalic FM. It looks like Ableton considers every "released" note to have to go back to velocity value 0 before it can be played again. Is there any way to bypass velocity going back to zero? I just want the envelope to run its course and bang out the note + value til it reaches a natural zero.

    • Jul 15 2019 | 7:37 am
      Here's a screenshot of my current attempt to solve the unwanted "default to velocity = 0" after every note change.
      And here's the code:
    • Jul 15 2019 | 8:24 am
      in case both ableton and your hardware allows this, you could skip velocity 0 and use "real" note off events instead. (or even all notes off.) note off is 0x80 where note on is 0x90, not sure offhand what is the best way to implement it in max. all notes off is (decimal) "123 0" or "120 0" sent as CC message into [midiformat].
    • Jul 15 2019 | 8:40 am
      Dear Roman, the hardware does not care whether its a note-on or off, it just interprets the separate streams of data incoming as MIDI standards, what it does care is that it gets velocity = 0 intermitently with value jumps, such as 55 - 0, 56 - 0 , n+1 - 0 etc.. so it keeps alternating between n +/-1 and 0 which causes short Voltage differences and since it's 128 possible steps, a short jump in voltage is almost noise data instead of a continuous flow such as an LFO or Envelope would yield. I'm trying to find out, if I can bypass the ableton default of defaulting to 0 after a note has been triggered.
    • Jul 15 2019 | 11:01 am
      What a complicated description of so simple stuff, huh... Velocity does not exist as such without having note number prepended. So in simple words - what do You want to do ? Receive midi notes and ignore velocity values, but send own - preselected velocity ? To which midi note number ? Or something else ? Using velocity to make cv ramps is nonesense, so why not just use CC if that stupid Live is not capable of dealing with simple midi notes ? Or is it You don't unerstand how midi works ? What does that hardware thing expect to interpret velocity as input for cv ? Values 0 - 127 on specific note and channel ? You talk about "midi standard", If so than just send 144 48 $1 to midiout and use slider 0-127 to send velocity 0-127 on midi channel 1 and note C3.
    • Jul 15 2019 | 2:33 pm
      Dear SOURCE AUDIO, Thank you for taking the time to reply! Gonna answer inline:
      What a complicated description of so simple stuff, huh...
      I imagine it can be frustrating when you're pro, to read in such length when the problem is so easily solvable for you! However as I stated in the very first sentence, I'm a newcomer and just started looking into M4L last week. So forgive my attempt to explicitly explain what I mean :)
      Velocity does not exist as such without having note number prepended.
      Yes, that much is clear, hence the code snippet I've attached above ;)
      So in simple words - what do You want to do ? Receive midi notes and ignore velocity values, but send own - preselected velocity ? To which midi note number ? Or something else ?
      Yes. Again see code snippet. Done.
      Using velocity to make cv ramps is nonesense, so why not just use CC if that stupid Live is not capable of dealing with simple midi notes ? OK, fair enough. Thank you for the evaluation and suggestion, again I could assign to CC without a problem, see above, that's NOT the issue :) I wouldn't myself state that Live is stupid, but I am puzzled by the lack of possibility to bypass default drop to 0 value when a note is played.
      Or is it You don't unerstand how midi works ? What does that hardware thing expect to interpret velocity as input for cv ? Values 0 - 127 on specific note and channel ?
      I leave the implication of not understanding MIDI to your judgement, I'd say I have a grasp of MIDI ;) The Hardware just expects MIDI standard Velocity upon a played note. let's say a list with parameters: [pitch,velocity] no channel needed, again see above all explained in detail, it extracts all of that already.
      You talk about "midi standard", If so than just send 144 48 $1 to midiout and use slider 0-127 to send velocity 0-127 on midi channel 1 and note C3.
      The idea is mapping whatever MIDI output gizmo in ableton, let's say Envelope to a dial, the dial spits out 0-127, correct. And outputs on whatever Channel (doesn't matter) what matters is, that it cannot drop to velocity = 0 every time a note is changed, and what happens is, as soon as the note changes or is being TRIGGERED in some way, it rises + velocity value, and then outputs the same note but with velocity = 0.
      Every note change with velocity change first delivers the correct value I'm attempting, but then defaults to 0 to signify release...
      I'm just trying to filter out that "release" interpretation of Live's MIDI Monitor towards the output channel. I wanna see a continuous stream from 0-127 not 0-0, 1-0, 2-0 etc...
      Here's the snippet again, I've mapped the dial to stripnote, which outputs whatever pitch (doesn't matter for now) and the velocity which = value of dial from 0-127. Further there's a sel, if it falls to 0, I'm rerouting the value from dial to xnoteout's velocity input. So in theory the midi output has a continuous stream between 0-127, and never defaults to 0. BUT the MIDI Monitor still perceives each triggered note as begun and ended and defaults to velocity = 0 inbetween each state change.
    • Jul 15 2019 | 8:14 pm
      i think the main issue here is that you underestimate what you can do in max. you do not even have to follow any midi specs or whatever, you can abuse midi data for whatever you wish an format data within max to your liking. btw, when you say "no channel is needed", actually the channel status will be always sent; [midiout] is the same as [midiout 1]. but yes of course, it makes sense that your device reacts to omni. now to your "drop to 0" problem. that live does this is normal, all commercial software i know uses note events with velocity 0 insteads of real note off. in max4live you could change note events with velocity 0 to real note off events. but what does your device do when it receives real note off? in case you device also doesnt react to real note off there is nothing you can do on the PC/ in max to prevent this. except maybe not sending any form of note off at all?
    • Jul 15 2019 | 8:26 pm
      Dear Roman Thilenius,
      I understand that some channel data is always sent, what I meant by not needed, is that I do not really need to supply any type of argument regarding channel for the hardware or my debugging attempt. Having a continuous CC stream for the modulation (by routing my dial to CC1) is a no-brainer as well, what I'm struggling with is the "drop to 0" issue as you well put it. My device extracts the following set of arguments received through midi,
      Note [note value, pitchbend, velocity] -> note and pitchbend are combined to one set of output stream, converted to -3V to 5V so a total range of 8V and output to a single 3.5mm jack titled 1v/oct Gate [note on/note off] -> either low (note = OFF) or HIGH voltage for the duration of note=ON (0V or 5V) output to a single 3.5mm jack titled gate Modulation [value between 0 and 127, incoming on CC1] -> output to voltage range between 0V and 5V, output to a single 3.5mm jack titled mod Velocity is extracted from Note info, it is a [value between 0 and 127] -> output to voltage range between 0V and 5V, output to a single 3.5mm jack titled vel
      So its 4 x 3.5mm jacks in total, they all extract what they need from a single Note event sent via MIDI and additionaly modulation sent via CC1.
      Obviously I need to trigger some note-on event in Ableton to cause my device to even see incoming velocity, as it cannot be passed by itself, and it's working well with banging/triggering note events in my patch, but I don't see how I can keep the note continuously ON, that is not defaulting to 0 at the moment.
      You've suggested going to note-off in case note-on = 0, how would I try that out?
    • Jul 16 2019 | 12:28 am
      It gets complicated again ... Here is what I understand about what You want to do : 1 Receive midi note in Live Device 2 Send that note to midi out and Your hardware, ignoring note off 3 ? Change that received velocity to some other value, or trigger ramp or what You call envelope which than sends velocity for received note out. ------- To do so, use notein - stripnote combo at input to remove note off or velocity 0. Than pack it again into list and send to noteout or midiout . If You want to trigger that envelope, use output of stripnote to form message containing note number and velocity . Here one example :
    • Jul 16 2019 | 12:35 am
      i totally understand that velocity 0 it is a problem when you want to convert the velocity value to a CV. but to be able to give advice about formatting the data or finding workarounds we need to know what the device can do. is it programmable? what does your device do when it receives a note on event followed by all notes off? use [midiformat] and [midiout] to send first note on 60 127, then CC 120 0 and see what happens.
    • Jul 16 2019 | 7:34 am
      Dear SOURCE AUDIO and ROMAN THILENIUS,
      thank you so much for the coherent and great answers!
      SOURCE AUDIO, here's the explicit visualisation of your patch, it's lovely thank you so much!
      The patch, outlet = ramp
      And here's the MIDI output on Ableton's side.
      The issue being: value changes of note+velocity as desired, namely 0-127 continuous, are intermitted with same note+velocity = 0, which I guess is Ableton's way of saying, every note change also means the last note played has to go = OFF and OFF = velocity 0
      Now, on my hardware's side, it accepts a stream of MIDI messages, and routes those to individual DACs. So any, note info + velocity change are immediately converted to voltage changes. I know for a fact, that a patch that creates a continous stream out of ableton, like f.e. the same patch as above, that outputs to CC1 = modulation, does not default to 0 in the MIDI monitor, and thus my CV output is smooth.
      So if there's a way to trick Ableton into not defaulting to note+Velocity = 0 on change of note, it would do the trick. In other words, same patch as above, same MIDI Monitor output, but without the velocity = 0 bits inbetween :)
      @ROMAN, the hardware's firmware can be rewritten in our workshop of course, but there's dozens of those deployed around the world, and I just wanted to create a tiny parser Plug-in for ableton users and our hardware users to be able to remap those mod+vel outputs for LFO's, Envelopes, S&H outputs with a range of 0V-5V using any given MIDI stream out of ableton they would choose.
    • Jul 16 2019 | 7:42 am
      That just excuses me for calling Live - stupid... There are some midi objects, I can't recall the exact name which someone created to overcome other Midi issues with Live, sysex etc.Not sure, but i think imp.midi or something. Maybe that could be of some help. And as last instance, if Live is really so stupid, one could make a standalone max app that receives notes from Live via iac buss and sends them out. If You are on Mac... P.S. just found the info : www.theimpersonalstereo.com/blog/blog/2016/3/impmidi-cross