MIDI-KIT - script processor for MIDI - by stoermelder

It’s not obvious to me - does it support sending/receiving 14-bit midi CC messages (fine + coarse CC/CC+32) ?

Looking forward to see your version of an OSC module too ?.

Yes, but there is currently nothing special for 14-bit CC messages implemented, as these are just two stardard CC messages.
Technically the module supports all MIDI messages, even SysEx, but I’m not sure about any use-cases yet.

1 Like

Also, If it’s not too much work - can you describe how MIDI system realtime messages are handled in rack now ? Do they have higher queue priority than common MIDI messages incl sysex. (less jitter?)

I don’t see any functions related to Start, Stop, Cont, Tick - but I don’t know if it’s relevant either - I haven’t much experience with complex midi setups involving tempo/transport mangling.

edit: found them

  • midi.isClock(msg)
  • midi.isContinue(msg)
  • midi.isStart(msg)
  • midi.isStop(msg)

Looks really handy. As a working coder who would rather not code seriously in my hobby this looks ideal for sketching out midi transformations. Exactly what I used to use CAL for when Cakewalk/Sonar was my DAW for a decade.

1 Like

I haven’t investiged all details yet but MIDI messages have timestamps in v2 and realtime message are priotized in modules which generate different kind of MIDI messages, like CV-MIDI.

Same here, this is why I skipped these for now, except of midi.isClock etc…

1 Like

Exactly this is the idea. No complete development environment, but a simple way of transforming MIDI.
For example for such controllers:

This looks very useful!

The first thing I think of is mapping various controllers to be more useful. A simple example would be velocity scaling (eg my Korg Wavestate only outputs velocities between ~30-100 unless you smash the thing or barely touch it). Another case is making use of the center detent in rotary controllers like the LaunchControl XL to provide dual function for rotating right/left.

Some scaling functions would be useful, such as curve/bezier, log, exp, abs, linear between max/min. The option for higher bit resolution on the function output might be useful in this case.

The LaunchControl is an example where it needs different output than what it sends on the input. In this case I could see MIDI-CAT sending its feedback first to MIDI-KIT on loopback, and MIDI-KIT sending to the LaunchControl. That would require different scripts for handling input from and output to the same controller. That might be a use-case for an expander?

Very cool idea!

One immediate use case for me would be what I did in VCV using about a dozen modules yesterday. I have a vpme.de Trig31 module on my rack that lets me send up to eight CV triggers out as MIDI notes, but when looking to map them at my DAW end the Trig31 sends them on strange notes and different channels e.g. the kick is sent as a C-1 note on channel 10, but the snare as a C#-1 on channel 11, the hi hat as an e2 on channel 12. All come in with velocity 0 and ultra short as they’re triggers not gates. One module with a short script letting me remap those notes to 32nd notes as standard GM MIDI drums on channel 10 would be really handy.

I can do the remapping directly in some DAWs, others using DAW tools and others not at all so this helps with consistency.

Great fun driving an Elektron Analog Rytm from hardware Grids, Bastl Kompas or the vpme Euclidean Circles!

midi.sendSysex(msg)
midi.receiveSysex(msg)

With sysex data we can use the script processor for many hardware.

2 Likes

Super cool, I know for me, when max/msp added their javascript object it was a huge convenience!

This is a very nice idea! I don’t think I can send a PM here, and don’t want to hijack this thread, but wanted to suggest that you take a look at the MIDI stuff I’ve been working on.

Specifically my patchable “vMIDI” spec that allows the use of normal patch cables to send MIDI between modules. There is also a MIDI helper class that helps reconnect MIDI devices so you can work offline and plug the hardware in later and it automatically maps it. The code is here:

I also make some hardware USB MIDI controllers with companion VCV modules that implement the same features described above:

Thanks and good luck with your project!

2 Likes

MIDI-KIT is still “work-in-progress” and I haven’t done much coding in the last few months. This is its programming interface right of today, most of the stuff is working and tested. I haven’t released anything because I want the API being stable before.

Global functions

  • processMidi(midiPort, msg): Main entry point of the script. This function is called by the module on each incoming MIDI message msg, received from MIDI input port midiPort (always 1 for this version).
  • log(str): Prints string str to the display of the module.
  • overlay(str1, [str2], [str3]): Displays string str1 in an overlay widget.

input

  • input.enable(port): Enables input with index port (1…4).
  • input.getName(port): Callback function used by the module to display a tooltip text for the input. The default implementation can be replaced to display some additional information for the input.
  • input.getVoltage(port, [channel]): Reads the current voltage on the input port port (1…4) of polyphonic channel (1…16).
  • input.isHigh(port, [channel]): Returns true if the voltage on input port port (1…4) of polyphonic channel (1…16) is above 0.7V.
  • input.isLow(port, [channel]): Returns true if the voltage on input port port (1…4) of polyphonic channel (1…16) is below 0.7V.

trig

  • trig.getTicks([trigPort]): Returns the number of triggers on trigger port trigPort (only 1 is supported in this version) since loading the script. If trigPort is omitted the default trigger port is selected.
  • trig.isHigh([trigPort]): Returns true if the voltage on trigger port trigPort (only 1 is supported in this version) is above 0.7V. If trigPort is omitted the default trigger port is selected.
  • trig.isLow([trigPort]): Returns true if the voltage on trigger port trigPort (only 1 is supported in this version) is below 0.7V. If trigPort is omitted the default trigger port is selected.

param

  • param.enable(arg): Enables parameter with index arg (1…4).
  • param.getName(arg): Callback function used by the module to display a tooltip text for the parameter. The default implementation can be replaced to display some additional information for the parameter.
  • param.getValueFormat(arg): This function is used by the module to display a formated value on the tooltip for the parameter. The default implementation can be replaced.
  • param.getValue(arg): Reads the value of the parameter with index arg (1…4). The return value is interval [0, 1].

number

  • number.ceil(arg): Computes the largest integer value not less than arg.
  • number.floor(arg): Computes the largest integer value not greater than arg.
  • number.max(arg1, arg2): Returns the greater of two arguments.
  • number.min(arg1, arg2): Returns the smaller of two arguments.
  • number.random(): Returns a random number of interval [0, 1).
  • number.toString(arg): Converts arg to a string representation.

midi

  • midi.create(): Creates an empty MIDI message.
  • midi.createNRPN(): Creates an empty NRPN MIDI message (actually 4 MIDI messages).
  • midi.getChannel(msg): Returns the MIDI channel (1…16) of msg.
  • midi.getLength(msg): Returns the length of the MIDI message msg, for all common messages this will return 3.
  • midi.getNote(msg): Returns the MIDI note number (0…127) of msg (byte 2 of the MIDI message).
  • midi.getSysExData(msg): Returns the data of a MIDI SysEx message msg as hexstring.
  • midi.getPitchWheel(msg): Returns the MIDI pitch wheel (0…16383) value of msg.
  • midi.getValue(msg). Returns the MIDI value field (0…127) of msg (byte 3 of the MIDI message).
  • midi.isCc(msg): Returns true if msg is a MIDI CC message.
  • midi.isChanPressure(msg): Returns true if msg is a MIDI channel pressure message.
  • midi.isClock(msg): Returns true if msg is a MIDI clock message.
  • midi.isContinue(msg): Returns true if msg is a MIDI continue message.
  • midi.isNoteOff(msg): Returns true if msg is a MIDI note off message.
  • midi.isNoteOn(msg): Returns true if msg is a MIDI note on message.
  • midi.isPitchWheel(msg): Returns true if msg is a MIDI pitch wheel message.
  • midi.isProgramChange(msg): Returns true if msg is a MIDI program change message.
  • midi.isStart(msg): Returns true if msg is a MIDI start message.
  • midi.isStop(msg): Returns true if msg is a MIDI stop message.
  • midi.isSysEx(msg): Returns true if msg is a MIDI SysEx message.
  • midi.setCc(msg, channel, cc, value): Sets msg as a MIDI CC message with the specified MIDI channel channel (1…16), CC number cc (0…127) and value (0…127).
  • midi.setCc14bit(msg1, msg2, channel, cc, value): Sets msg1 and msg2 as a 14-bit MIDI CC message pair, with the MIDI channel channel (1…16), CC number cc (0…127) and value (0…16383).
  • midi.setChannel(msg, channel): Sets the MIDI channel channel (1…16) for msg.
  • midi.setChanPressure(msg, channel, value): Sets msg as a MIDI channel pressure message, with MIDI channel channel (1…16) and pressure value (0…127).
  • midi.setKeyPressure(msg, channel, note, value): Sets msg as MIDI key pressure/aftertouch message, with the MIDI channel channel (1…16), MIDI note number note (0…127) and pressure value (0…127).
  • midi.setNote(msg, note): Sets the MIDI note number (0…127) for msg (byte 2 of the MIDI message).
  • midi.setNoteOff(msg, channel, note): Sets msg as MIDI note off message, with MIDI channel channel (1…16) and MIDI note number note (0…127). Please be aware, some MIDI devices need a MIDI note on message with velocity 0 instead of a MIDI note off message.
  • midi.setNoteOn(msg, channel, note, velocity): Sets msg as MIDI note on message, with MIDI channel channel (1…16), MIDI note number note (0…127) and velocity (0…127).
  • midi.setNRPN(nrpn, channel, number, value): Sets the NRPN number and NRPN value of nrpn.
  • midi.setPitchWheel(msg, channel, value): Sets msg as a MIDI pitch wheel message, with the specified MIDI channel (1…16) and pitch wheel value (0…16383).
  • midi.setProgramChange(msg, channel, prg): Sets msg as a MIDI program change message, with the MIDI channel channel (1…16) and program number prg (0…127).
  • midi.setSysEx(msg, str): Sets msg as a MIDI SysEx message with string str representing a hexstring of data (e.g. “ab0fad050fdd”, whitespaces are ignored).
  • midi.setValue(msg, value): Sets the MIDI value field (0…127) for msg (byte 3 of the MIDI message).

midiOut

  • midiOut.send([midiPort], msg): Sends msg on MIDI port midiPort (default port = 1). If midiPort is omitted the default MIDI output port is used.
  • midiOut.sendAfterMs([midiPort], msg, ms): Sends msg delayed on MIDI port midiPort (default port = 1). The delay ms is specified in milliseconds. If midiPort is omitted the default MIDI output port is used.
  • midiOut.sendAfterTrigger([midiPort], msg, [trigPort], ticks): Sends msg delayed on MIDI port midiPort (default output = 1). The delay is specified in ticks of triggers on CV trigger input trigPort. If midiPort is omitted the default MIDI output port is used. If trigPort is omitted the default trigger port is selected.
4 Likes

In relation to the korg minilogue NRPN example i posted in another thread. I will link the MIDI implementation for the Korg minilogue XD, In case you want to look at it.

I don’t think i will succeed using patchmaster, cv-map and ModScript for my minilogue modulations. Rack keeps crashing(it hangs) when i get to mapping CV’s to the knobs using cv-map (or midi-map).

Edit add: had to slow down the processing to make it stable.

config.frameDivider = 128
config.bufferSize = 8

Do you want some knobs for controlling your MIDI device or do want to send NRPNs for some CV source in Rack?

can i have both ? hehe

when the knobs are not cv-mapped, they can be used manually.

This is how i have it set up now. I plan on making more knows to control everything that is midi controllable on the minilogue xd.

Ok, this is super-complicated for sending some MIDI messages :slight_smile: Why don’t you use the input ports of ModScript? Would this not be easier?

Probably, but it only has 4 input ports. I could just make the LFO’s in modcript too … so many choices…

Ah, I see. My module has 4 (right now), but you can access polyphonic channels, so 4*16. Not sure about ModScript, I never tried it.

Very interesting! I work on MIDI stuff to better understanding this area. And I try to make a patch to interface a controler like L’aunch Control XT with MindMeld Mix and stuff around. Is your module available somewhere now? Thanks. Alain

I didn’t find it in VCV library… Thank you. Alain