Zero experience - Trying to write a script for multi for round robin of 8 instruments

Options
vogelscheiss
vogelscheiss Member Posts: 6 Newcomer
edited November 2023 in Scripting Workshop

I'm trying to write a script that will send incoming MIDI notes sequentially to 8 separate instruments in a multi. I keep getting errors. I'd be grateful for pointers.

I started by trying with 2 instruments.

Here's my bad script:

on init

  declare $currentInstrument := 0

  declare $numberOfInstruments := 2 { Assuming 2 instruments in the multi }

end on


on note

  $currentInstrument := ($currentInstrument + 1) % $numberOfInstruments


  if ($currentInstrument = 0) then

    { Send note to the first instrument in the multi }

    play_note(0, $EVENT_NOTE, $EVENT_VELOCITY, -1) 

  else

    { Send note to the second instrument in the multi }

    play_note(1, $EVENT_NOTE, $EVENT_VELOCITY, -1)

  end if


  ignore_event($EVENT_ID)

end on


Where is this getting screwed up? (Throughout?) I'd be grateful for any thoughts/corrections.

Comments

  • medusa
    medusa Member Posts: 85 Helper
    Options

    You can't use play_note in a multi script.

    I reckon the best way to do this would be with MIDI channels

  • stephen24
    stephen24 Member Posts: 281 Pro
    edited November 2023
    Options

    You need to be clear about the difference between Instrument Scripts and Multi Scripts. Instrument Scripts can apply to only one instrument. Multiscripts require some understanding of the MIDI protocol (not rocket science)

    You need to programme precisely as in the manual (your syntax for play_note is wrong, as well as its use)

    As medusa says, you could have your round robins in different instruments on their own channels with a multiscript, but only if your note-off messages are to be ignored (e.g. one-shot samples) otherwise you'd have to keep track of which note was played on which channel for the note-off, which would be very complicated.

    something like

    set_event_par($EVENT_ID, $EVENT_PAR_MIDI_CHANNEL . . . .)

    with a variable which you increment with each note.

    Be a lot simpler to use groups within an instrument. You probably wouldn't even need a script.

  • vogelscheiss
    vogelscheiss Member Posts: 6 Newcomer
    edited November 2023
    Options

    Thanks!

    The goal is to arrive at a round robin whereby successive MIDI notes are played on successive instruments. e.g. instead of 1 (piano) 2 (same piano) 3 (same piano) 4 (same piano) etc. it would be 1 (piano) 2 (banjo) 3 (electric guitar) 4 (marimba), or whatever. This would be much like using a MonoPoly in revolving mode or a modular synth with sequential switches.

    If you know of a simple way to achieve that I'd be very interested!

    The brute force method would be splitting up my MIDI into 8 tracks, but definitely not preferred. I'm sure a good script is possible.

    Your "be a lot simpler to use groups within an instrument" is interesting. Guessing wanting different instruments altogether per MIDI note makes that impossible?

  • vogelscheiss
    vogelscheiss Member Posts: 6 Newcomer
    Options

    Now I'm trying an instrument specific script to do the same thing. For simplicity I'm just doing a 2-instrument round-robin.

    I would put the script in the instrument @ MIDI ch1 and no script in MIDI ch2.

    This is the script:

    on init

     make_persistent($RR_chan)

     $RR_chan := 1

    end on


    on note

     if ($RR_chan = 1)

      play_note($EVENT_NOTE, $EVENT_VELOCITY, 1, -1) { Route to Instrument 1 on MIDI channel 1 }

      $RR_chan := 2

     else

      play_note($EVENT_NOTE, $EVENT_VELOCITY, 2, -1) { Route to Instrument 2 on MIDI channel 2 }

      $RR_chan := 1


     ignore_event($EVENT_ID)

    end on


    It throws off an error @ the last line, "end on". Any ideas? I'd be grateful.

  • Gablux
    Gablux Member Posts: 81 Member
    Options

    you are missing an "end if"

  • vogelscheiss
    vogelscheiss Member Posts: 6 Newcomer
    edited November 2023
    Options

    Unfortunately if I add "end if" it throws off an error:

    When I removed "end if" it passed that line but threw off an error on the last line:


  • Gablux
    Gablux Member Posts: 81 Member
    Options

    read the errors


  • stephen24
    stephen24 Member Posts: 281 Pro
    edited November 2023
    Options

    You really do need to study the parameters of play_note in the KSP manual. In your script the third parameter (your 1 or 2) is the sample start. In microseconds.

    Others may correct me, but I don't think there is any way that a script in instrument 1 can trigger activity in instrument 2. You would have to use a multiscript, which would have the complications I mentioned above unless all your notes are one-shot (when it would be easy). You could set the channel for a note as I suggested, but its note-off must be on the same channel, so you would have to make a record of each note's channel to recall when its note-off is received. You could set up a 127-element array and do it.

    Why not do it with groups? No reason why you shouldn't have piano banjo guitar internal combustion engine etc in separate groups in a single instrument - you can copy/paste groups - then give them RR numbers in Group Start Options. If one of your instruments has lots of groups, do the Group Start Options bit (Edit All Groups) before you copy them into the composite instrument.

  • vogelscheiss
    vogelscheiss Member Posts: 6 Newcomer
    Options

    Thanks for that feedback. I'm going to take a close look at whether I can make that work for me. Good stuff, much appreciated.

  • stephen24
    stephen24 Member Posts: 281 Pro
    Options

    Actually not as complicated as I thought. Try this (untested) multiscript - assumes 4 instruments (line 11)

    on init
     declare %nofchan[128] :=(0)
     declare $rr :=0
    end on
    
    on midi_in
    
     if ($MIDI_COMMAND = $MIDI_COMMAND_NOTE_ON)
      set_event_par($EVENT_ID, $EVENT_PAR_MIDI_CHANNEL, $rr)
      %nofchan [get_event_par ($EVENT_ID, $EVENT_PAR_MIDI_BYTE_1)] := $rr
      $rr := ($rr + 1) mod 4
     end if
    
     if ($MIDI_COMMAND = $MIDI_COMMAND_NOTE_OFF)
      set_event_par($EVENT_ID, $EVENT_PAR_MIDI_CHANNEL, %nofchan [get_event_par ($EVENT_ID, $EVENT_PAR_MIDI_BYTE_1)] )
     end if
    
    end on
    

    Paste into empty multiscript slot (KSP button top R of Kontakt window) and click Apply. If I've got it right, notes-off should be dealt with correctly.

  • vogelscheiss
    vogelscheiss Member Posts: 6 Newcomer
    Options

    Stephen, you nailed it! That works! Lives up to my hopes too.

    Thanks so much, really very appreciated.

Back To Top