LEGO ipMIDI

This post is part 1 of 6 of  LEGO ipMIDI

3 weeks since COVID-19 lockdown.

Bored.

Let’s go back to MIDI and the never completed LEGO Laser Harp idea – instead of usinq MQTT to send codes from the EV3 to my laptop and converting there to MIDI… how can I send pure MIDI?

More than 2 years have past. Python MIDI libraries are better. ev3dev is better. I am bored. Let’s search.

TouchDAW supports two network MIDI protocols: multicast (ipMIDI) and RTP-MIDI. The first one is not exactly a MIDI standard although lots of products seem to support it. But RPT-MIDI is so I’ll try it first.

Found David Moreno’s rtpmidi. It installs a daemon on my Ubuntu laptop. I can use TouchDAW to play music on my laptop through it. Very nice!

But it is not available for ev3dev so I would have to build it… I’m always afraid of that. So maybe there is a python library that can send midi notes through rptmidi? Found none 🙁

OK, ipMIDI then.

‘qmidinet’ on my laptop works. Had to disable jack and sometimes notes get stuck (usually the last note) but it works.

It also works on ev3dev (without GUI, of course):

qmidinet -g -j off

And I can play a MIDI file directly to the laptop:

aplaymidi --port 128:0 happy_birthday.midi

playing heavy MIDI files seemed to stress EV3 (or maybe just Wi-Fi) but small files worked very well – and a single MIDI instrument like my Laser Harp will generate just a few notes per second (at best).

While I was fiddling with different MIDI files I dedided to try ‘multimidicast’, the linux father of ‘qmidinet’. And it also works, just needed to compile from source (not as slow as I expected). Since it is command line only and doesn’t support jack, it uses fewer resources so I’ll use it instead of qmidinet.

I can send a full MIDI file… but what I really need is to send notes, in real time. So I need to generate those notes in python.

‘python-rtmidi’ seems to be the best choice and I remember trying it with the Harp when I was playing MIDI locally on the EV3 (running timidity as a soft synth). At that time, I managed to install ‘python-rtmidi’ and also ‘mido’ that uses it as a backend.

But I couldn’t install it.

There is a ‘python3-rtmidi’ package for armel but not for stretcht. I tryed the buster package but requires python 3.7 (at this moment, ev3dev includes 3.5.3).
So I tried ‘pip’… and after a while I loose network connectivity.
Then i tried downloading the source code and install it… and after a while I also loose network. Even tried installing it without jack support to make it a bit lighter… same thing.

Argh!

So I needed a plan B: playing notes without a python library. And found a post on a Raspberry Pi forum where someone played notes from Ruby using system calls to ‘amidi’:

amidi -p hw:1,0 -S "90 3C 7F"
amidi -p hw:1,0 -S "90 3C 00"

This turns ‘C’ on then off on MIDI channel #0. But it only works with sound cards, not with MIDI connections.

So… there is a kernel module ‘snd-virmidi’ that creates a virtual midi sound card… and it is available in ev3dev !!

sudo modprobe snd-virmidi

This creates 4 MIDI clients:

client 20: 'Virtual Raw MIDI 1-0' [type=kernel,card=1]
    0 'VirMIDI 1-0     '
client 21: 'Virtual Raw MIDI 1-1' [type=kernel,card=1]
    0 'VirMIDI 1-1     '
client 22: 'Virtual Raw MIDI 1-2' [type=kernel,card=1]
    0 'VirMIDI 1-2     '
client 23: 'Virtual Raw MIDI 1-3' [type=kernel,card=1]
    0 'VirMIDI 1-3     '

so I connect one of them to multimidicast:

aconnect 20:0 128:0

and now amidi works!

From python I can now play a ‘C’:

os.system('amidi -p hw:1,0 -S "90 3C 7F"')
time.sleep(0.1)
os.system('amidi -p hw:1,0 -S "90 3C 00"')

Even better: I can do it also from micropython because ‘os.system’ is also available, including the new ‘pybricks-micropython’ library.

Now I need to learn a few hexadecimal MIDI codes and prepare a Raspberry Pi to work as an ipMIDI synth to free my laptop from that role.

First useful version

This post is part 3 of 3 of  barcode

Added a few more lines to my first python script in order to achieve ‘Record and Play’ functionality, like the original LEGO Code Pilot.

Also change a bit the structure of the dicitionary, adding the code to execute to each “barcode item”. So the recording part is just adding “items” to a list and the playing is just a loop through the list, picking the code and executing it with the ‘exec’ function (kudos to Daniel Walton).

So ‘codepilot03.py’ is now able to record an undefined number of steps and execute them in a row. And since the barcode scanner is fully Plug and Play we can detach it and reattach it between runs (and since wi-fi is not needed, we can also remove the clumsy USB hub).

Next version will have an extended “language set”.

EV3 barcode scanner

This post is part 1 of 3 of  barcode

Should be finishing my EV3 Alexa program… but not in the mood.

So I got a USB barcode scanner in front of me… hmm, I wonder…?

My Ubuntu linux laptop recognizes. HID device, a keyboard. Great, plug and play!

So does my EV3 running ev3dev:

[  538.808906] usb 1-1.2: new full-speed USB device number 6 using ohci-da8xx
[  538.972308] usb 1-1.2: New USB device found, idVendor=04b4, idProduct=0100
[  538.972383] usb 1-1.2: New USB device strings: Mfr=1, Product=2, SerialNumber=0
[  538.972425] usb 1-1.2: Product: USB Virtual PS2 Port    
[  538.972462] usb 1-1.2: Manufacturer: Future            
[  539.040788] input: Future             USB Virtual PS2 Port     as /devices/platform/soc@1c00000/ohci-da8xx/usb1/1-1/1-1.2/1-1.2:1.0/0003:04B4:0100.0001/input/input2
[  539.128526] hid-generic 0003:04B4:0100.0001: input,hidraw0: USB HID v1.00 Keyboard [Future             USB Virtual PS2 Port    ] on usb-ohci-da8xx-1.2/input0

So if this is a keyboard I can read it with input functions:

#! /usr/bin/env python3

# if you are running from ssh session invoke this script with 'brickrun'
from ev3dev2 .sound import Sound

sound = Sound()

while True:
    ucc = input('Scan a UCC: ')
    ucc = ucc.lower().strip().replace('\t','').replace('\n','')
    sound.speak(ucc)

Yes, it works. Just need to disable Brickman interface (first time I ran it the ‘keys’ read from from the scanner disabled my Wi-Fi connection). I can use print but the since the LCD is so small I prefer to use ‘speak’.

Now… what can I do with it?

Of course… identify LEGO sets!

So I found out that there are online databases of barcodes and some even offer webservices API. I asked a free trial key at “https://www.barcodelookup.com/api” and copy&pasted their python demo code… and it just works.

Code: https://github.com/JorgePe/ev3-barcode/blob/master/barcode02.py

How to change your EV3 hostname

Now that more and more people are using ev3dev thanks to LEGO Education’ EV3 MicroPyhton a few might find in need to change their bricks’s names.

Until that feature is available at BrickMan level, this is the a way:

  1. access the ev3dev shell either through SSH (puTTY) or Visual Studio Code – don’t forget that the default user is ‘robot’ and it’s password is ‘maker’
  2. change te hostname with command ‘sudo hostnamectl set-hostname NAME’
  3. restart avahi service with command ‘sudo service avahi-daemon restart’

David Lechner pointed me to the ‘ev3dev-config’ tool having also an option for this purpose:

sudo ev3dev-config

Then choose

4 Advanced Options  Configure advanced settings

Followed by

A1 Hostname    Set the visible name for this ev3dev device on a network

This can all be done from Visual Studio Code through the EV3DEV Device Browser plugin – I wrote a detailed visual explanation for those less confortable with above explanation.

Clearing MQTT retained messages

When using your own ‘mosquitto’ broker and things start to get weird, ghost messages being received as soon as you start subscribing…

sudo service mosquitto start
sudo rm /var/lib/mosquitto/mosquitto.db
sudo service mosquitto start

This will crear your retained messages. Next time be careful with option “retain message” when playing with MQTT Dashboards…