cbfishes
nxstmp
The fantastic VCV Rack, still in its pre-1.0 version, doesn’t yet have a way to generate MIDI. I wanted a way to have Rack send gates and triggers to my DIY modular synth that wasn’t audio (that’s the easiest way to do it, btw, but it uses up at least one audio output).
After some research, I figured out that I could use a module that converts Rack voltages into OSC messages to get data out of Rack, then use a little python OSC server to convert those into MIDI messages. Then I take those MIDI messages and send them into ttymidi, which converts them into serial messages which my Arduino module can understand. You wouldn’t necessarily have to send this to an Arduino, you could also just use this to generate MIDI note on and off messages to trigger software or hardware. Until Rack has a MIDI output module, this is one way to do it.
To hear this in action, check out my post from yesterday.
Here’s the code. Maybe this could be useful to other folks!
# VCV RACK VOLTAGES -> OSC MESSAGES -> MIDI MESSAGES -> TTYMIDI -> MISSION CONTROL -> MY DIY ANALOG MODULAR SYNTH
# 2018-10-08
# Chris Beckstrom - chrisbeckstrom.com
# WHAT IS THIS?
# this script is a little OSC server that listens for certain OSC messages
# converts them to MIDI messages
# and spits them out
# WHY?
# I wanted Rack to be able to trigger things on my modular synth
# and I didn't want to use up my audio outputs
# HOW TO USE THIS:
# 1. run this script i.e. python3 mido_send_midi.py (I think it requires python >=3)
# 2. in Rack (or anything else that can send osc) send messages
# to 127.0.0.1 on port 5005
# 2.1 in rack, use trowa cv osc, outport 5005, send gates to "val" input
# config: type: float, osc value min = 0, max = 10, convert values = true
# the destination for this MIDI output is set below, the variable "outport"
# now you've got MIDI out of Rack (on virmidi 4, assuming that is enabled on your system)
# for my purposes, I want to send this MIDI to my modular, but over serial, so I use ttymidi
# 3. connect the outport (virmidi 4) to ttymidi mission control
# info about mido:
# mido.readthedocs.io/en/latest/messages.html
# not sure if this is necessary:
# -*- coding: utf-8 -*-
# import stuff we need
# to install, do pip install mido, I think
import mido
from mido import *
from mido import Message
"""Small example OSC server
This program listens to several addresses, and prints some information about
received packets.
"""
import argparse
import math
from pythonosc import dispatcher
from pythonosc import osc_server
# mido output port
# !!!! IMPORTANT !!!!!
# this is where our midi messages will be sent
# !!!!!
# make sure that this device's output is connected to the mission_control midi input
outport = mido.open_output('Virtual Raw MIDI 0-3:VirMIDI 0-3 19:0')
#def print_volume_handler(unused_addr, args, volume):
# print("[0] ~ 1".format(args[0], volume))
# define the various messages that we want to send
# these notes (ie note=36) correspond to the MIDI messages
# my arduino module (mission control) is listening for
# when the arduino receives a note 36 on, it will spit out
# a short trigger from digital output 2, and so on
twoOn = Message('note_on', note=36)
twoOff = Message('note_off', note=36)
fourOn= Message('note_on', note=38)
fourOff= Message('note_off', note=38)
sevenOn= Message('note_on', note=40)
sevenOff= Message('note_off', note=40)
eightOn= Message('note_on', note=41)
eightOff= Message('note_off', note=41)
twelveOn= Message('note_on', note=43)
twelveOff= Message('note_off', note=43)
thirteenOn= Message('note_on', note=45)
thirteenOff= Message('note_off', note=45)
def print_trowa_handler(unused_addr, args, volume):
#print("[0] ~ 1".format(args[0], volume))
if volume > 0: # only do stuff when we receive an osc value > 0
if unused_addr == "/trowacv/ch/1":
outport.send(twoOn)
outport.send(twoOff)
elif unused_addr == "/trowacv/ch/2":
outport.send(fourOn)
outport.send(fourOff)
elif unused_addr == "/trowacv/ch/3":
outport.send(sevenOn)
outport.send(sevenOff)
elif unused_addr == "/trowacv/ch/4":
outport.send(eightOn)
outport.send(eightOff)
elif unused_addr == "/trowacv/ch/5":
outport.send(twelveOn)
outport.send(twelveOff)
elif unused_addr == "/trowacv/ch/6":
outport.send(thirteenOn)
outport.send(thirteenOff)
if __name__ == "__main__":
# I think this stuff sets up the server
parser = argparse.ArgumentParser()
# configure the host and port for the osc server
parser.add_argument("--ip",
default="127.0.0.1", help="The ip to listen on")
parser.add_argument("--port",
type=int, default=5005, help="The port to listen on")
args = parser.parse_args()
# I think this is the thing that actually does the listening
dispatcher = dispatcher.Dispatcher()
# take the first 6 channels of the trowacv output
# and do stuff with them. are these functions? I'm not sure. Maybe?
dispatcher.map("/trowacv/ch/1", print_trowa_handler, "1:")
dispatcher.map("/trowacv/ch/2", print_trowa_handler, "2:")
dispatcher.map("/trowacv/ch/3", print_trowa_handler, "3:")
dispatcher.map("/trowacv/ch/4", print_trowa_handler, "4:")
dispatcher.map("/trowacv/ch/5", print_trowa_handler, "5:")
dispatcher.map("/trowacv/ch/6", print_trowa_handler, "6")
# ?? here is the OSC server, I think
server = osc_server.ThreadingOSCUDPServer(
(args.ip, args.port), dispatcher)
print("Serving on ".format(server.server_address))
server.serve_forever()
### for debugging:
#print mido.get_input_names()
#with mido.open_input('New Port', virtual=True) as inport:
# for message in inport:
# print(message)
---
(original: chrisbeckstrom.com/2018/10/09/using-python-and-osc-to-con...)
nxstmp
The fantastic VCV Rack, still in its pre-1.0 version, doesn’t yet have a way to generate MIDI. I wanted a way to have Rack send gates and triggers to my DIY modular synth that wasn’t audio (that’s the easiest way to do it, btw, but it uses up at least one audio output).
After some research, I figured out that I could use a module that converts Rack voltages into OSC messages to get data out of Rack, then use a little python OSC server to convert those into MIDI messages. Then I take those MIDI messages and send them into ttymidi, which converts them into serial messages which my Arduino module can understand. You wouldn’t necessarily have to send this to an Arduino, you could also just use this to generate MIDI note on and off messages to trigger software or hardware. Until Rack has a MIDI output module, this is one way to do it.
To hear this in action, check out my post from yesterday.
Here’s the code. Maybe this could be useful to other folks!
# VCV RACK VOLTAGES -> OSC MESSAGES -> MIDI MESSAGES -> TTYMIDI -> MISSION CONTROL -> MY DIY ANALOG MODULAR SYNTH
# 2018-10-08
# Chris Beckstrom - chrisbeckstrom.com
# WHAT IS THIS?
# this script is a little OSC server that listens for certain OSC messages
# converts them to MIDI messages
# and spits them out
# WHY?
# I wanted Rack to be able to trigger things on my modular synth
# and I didn't want to use up my audio outputs
# HOW TO USE THIS:
# 1. run this script i.e. python3 mido_send_midi.py (I think it requires python >=3)
# 2. in Rack (or anything else that can send osc) send messages
# to 127.0.0.1 on port 5005
# 2.1 in rack, use trowa cv osc, outport 5005, send gates to "val" input
# config: type: float, osc value min = 0, max = 10, convert values = true
# the destination for this MIDI output is set below, the variable "outport"
# now you've got MIDI out of Rack (on virmidi 4, assuming that is enabled on your system)
# for my purposes, I want to send this MIDI to my modular, but over serial, so I use ttymidi
# 3. connect the outport (virmidi 4) to ttymidi mission control
# info about mido:
# mido.readthedocs.io/en/latest/messages.html
# not sure if this is necessary:
# -*- coding: utf-8 -*-
# import stuff we need
# to install, do pip install mido, I think
import mido
from mido import *
from mido import Message
"""Small example OSC server
This program listens to several addresses, and prints some information about
received packets.
"""
import argparse
import math
from pythonosc import dispatcher
from pythonosc import osc_server
# mido output port
# !!!! IMPORTANT !!!!!
# this is where our midi messages will be sent
# !!!!!
# make sure that this device's output is connected to the mission_control midi input
outport = mido.open_output('Virtual Raw MIDI 0-3:VirMIDI 0-3 19:0')
#def print_volume_handler(unused_addr, args, volume):
# print("[0] ~ 1".format(args[0], volume))
# define the various messages that we want to send
# these notes (ie note=36) correspond to the MIDI messages
# my arduino module (mission control) is listening for
# when the arduino receives a note 36 on, it will spit out
# a short trigger from digital output 2, and so on
twoOn = Message('note_on', note=36)
twoOff = Message('note_off', note=36)
fourOn= Message('note_on', note=38)
fourOff= Message('note_off', note=38)
sevenOn= Message('note_on', note=40)
sevenOff= Message('note_off', note=40)
eightOn= Message('note_on', note=41)
eightOff= Message('note_off', note=41)
twelveOn= Message('note_on', note=43)
twelveOff= Message('note_off', note=43)
thirteenOn= Message('note_on', note=45)
thirteenOff= Message('note_off', note=45)
def print_trowa_handler(unused_addr, args, volume):
#print("[0] ~ 1".format(args[0], volume))
if volume > 0: # only do stuff when we receive an osc value > 0
if unused_addr == "/trowacv/ch/1":
outport.send(twoOn)
outport.send(twoOff)
elif unused_addr == "/trowacv/ch/2":
outport.send(fourOn)
outport.send(fourOff)
elif unused_addr == "/trowacv/ch/3":
outport.send(sevenOn)
outport.send(sevenOff)
elif unused_addr == "/trowacv/ch/4":
outport.send(eightOn)
outport.send(eightOff)
elif unused_addr == "/trowacv/ch/5":
outport.send(twelveOn)
outport.send(twelveOff)
elif unused_addr == "/trowacv/ch/6":
outport.send(thirteenOn)
outport.send(thirteenOff)
if __name__ == "__main__":
# I think this stuff sets up the server
parser = argparse.ArgumentParser()
# configure the host and port for the osc server
parser.add_argument("--ip",
default="127.0.0.1", help="The ip to listen on")
parser.add_argument("--port",
type=int, default=5005, help="The port to listen on")
args = parser.parse_args()
# I think this is the thing that actually does the listening
dispatcher = dispatcher.Dispatcher()
# take the first 6 channels of the trowacv output
# and do stuff with them. are these functions? I'm not sure. Maybe?
dispatcher.map("/trowacv/ch/1", print_trowa_handler, "1:")
dispatcher.map("/trowacv/ch/2", print_trowa_handler, "2:")
dispatcher.map("/trowacv/ch/3", print_trowa_handler, "3:")
dispatcher.map("/trowacv/ch/4", print_trowa_handler, "4:")
dispatcher.map("/trowacv/ch/5", print_trowa_handler, "5:")
dispatcher.map("/trowacv/ch/6", print_trowa_handler, "6")
# ?? here is the OSC server, I think
server = osc_server.ThreadingOSCUDPServer(
(args.ip, args.port), dispatcher)
print("Serving on ".format(server.server_address))
server.serve_forever()
### for debugging:
#print mido.get_input_names()
#with mido.open_input('New Port', virtual=True) as inport:
# for message in inport:
# print(message)
---
(original: chrisbeckstrom.com/2018/10/09/using-python-and-osc-to-con...)