Dup Ver Goto 📝

MidiCcMapperGenerator

DAW/reaper/jsfx does not exist
To
127 lines, 454 words, 2806 chars Page 'MidiCcMapperGenerator' does not exist.

This is a very simple generator for JSFX scripts that remap CC numbers. The main idea is that when you have a synth that takes controls like filter frequency on certain CC's, and you have a controller like a Midimix, which generates fixed CC numbers for each knob, this allows you to create a mapper between the two. Very quick and dirty. The main intended use are the Ostirus and Nodal Red emulations of the Virus TI and Nord Rack 2X respectively, or indeed the hardware Rack 2X I have lying around.

Input File

Example

mr_flibble_says_hi
10 50
40 55
# comment
5 6 # other comment

The first line is the name (output is name.jsfx, desc line is desc: name). The remaining lines, after # comments are stripped, consist of two numbers. These can be integers like 42 or hex values like 0x42.

Example output:

desc: mr_flibble_says_hi
@block
while (
midirecv(ts,msg1,msg2,msg3) ? 
(
  c = msg1 & 0xF;
  s = msg1 >> 4;

  ( s == 0xB ) ? (
    cc = msg2;
    val = msg3;
    ( cc == 5 ) ? ( cc = 6 ) : 
    ( cc == 10 ) ? ( cc = 50 ) : 
    ( cc == 64 ) ? ( cc = 55 );
    midisend(ts,msg1,cc,val);
  ) : (
    midisend(ts,msg1,msg2,msg3);
  );
));

Python Script

#!/usr/bin/env python

import argparse

def main():
  parser = argparse.ArgumentParser(prog="cc_map_gen",
                                  description="CC Mapper JSFX Generator")
  parser.add_argument("files",nargs="+")
  ns = parser.parse_args()
  for fn in ns.files:
    proc(fn)

def decodehex(x):
  try:
    if x.startswith("0x"):
      return int(x[2:],16)
    return int(x)
  except ValueError as e:
    raise ValueError(f"Failed to parse as int or hex: {x}")

def proc(fn):
  try:
    with open(fn) as f:
      lines = f.read().rstrip().splitlines()
  except Exception as e:
    print("#Exception",type(e),e,fn)
    return
  name = lines.pop(0)
  d = {}
  ks = set()
  for line in lines:
    line = line.split("#")[0].strip()
    xs = line.split(" ")
    if len(xs) != 2:
      continue
    try:
      xs = [ decodehex(x) for x in xs ]
    except ValueError as e:
      print("#Exception",e)
      continue
    s,t = xs
    ks.add(s)
    d[s] = t
  ks = sorted(ks)

  """
  ( cc == {s} ) ? ( cc = {t} ) :
  ( cc == {s} ) ? ( cc = {t} )
  """
  out_lines = [ f"    ( cc == {s} ) ? ( cc = {d[s]} )" for s in ks ]
  out = " : \n".join(out_lines) + ";"

  ofn = name + ".jsfx"
  jsfx = gen_jsfx(name,out)
  with open(ofn,"wt") as f:
    print(jsfx,file=f)
  print("Written",ofn)

def gen_jsfx(name,payload):
  return f"""desc: {name}
@block
while (
midirecv(ts,msg1,msg2,msg3) ? 
(
  c = msg1 & 0xF;
  s = msg1 >> 4;

  ( s == 0xB ) ? (
    cc = msg2;
    val = msg3;
{payload}
    midisend(ts,msg1,cc,val);
  ) : (
    midisend(ts,msg1,msg2,msg3);
  );
));
"""


if __name__ == "__main__":
  main()