Thursday, 17 March 2016 20:57

Raspberry Pi and Behringer x32 Mixer to control On-Air Sign

Written by 
Rate this item
(0 votes)

Raspberry Pi and a Behringer x32 Mixer controls an OnAir Sign

Polling channel status on the mixer over the local network to turn on / off sign

I was working on a side project for a small TV studio and they needed a way to automate their on-air sign, Pi to the rescue....

I made this a while back ago, so some of the details maybe are not as clear as they could be.  Feel free to reach out and leave a comment if you have any questions.

 

Update 20170328:

This project has been running for several months now at a small TV studio without any reported issues.  If you are hesitant about homebrewing a solution, I did receive an email from someone who also suggested a MIDI relay box http://www.midisolutions.com/prodr8.htm.  I personally have no experience or feedback about this product, but I figured it may help someone else out while looking for different solutions.

 

Video is posted at the bottom of the page, to see it in action!

I used a Raspberry Pi (1) Model B+ for this project, although a newer model would also work.  The TV studio used channels 1-10 on the Behringer mixer as microphone inputs.  They wanted the on-air sign to automatically turn on if any of these mics were live.  Seeing that the Behringer can be controlled over the network, I found the lowest cost solution would be to use a Raspberry Pi with some python code to poll the status of the microphone channels and in turn, trigger a GPIO to turn on and off the on-air sign.

Here's a picture of the Pi with only an LED and series resistor connected to GPIO 18 for testing purposes

raspberry pi mixer onair sign 03

 

Interacting with the Behringer Mixer

I searched around a bit and found that I can control the mixer as well as get status of all of its settings remotely over the network.  It uses the X32 protocol (link at the bottom) over UDP port 10023.  I was unable to find a way to get status of all of the channels (levels and mute status) with a single command so instead I ended up polling each channel that we wanted to monitor individually using the command /node  , s

For channel 1, I would send,

/node ,s ch/01/mix

and it would return a string

X->,   52 B: node~~~~,s~~/ch/01/mix ON  +3.9 OFF +0 OFF   -oo~~~~

The highlighted parts are what we are interested in (Channel/Mute status = ON, Channel is on, it is NOT muted)(Fader Level = +3.9)

 

Raspberry Pi Python Code

I used python to write a script to poll the Behringer mixer that is on the same network.  The code could be improved upon many ways, one being that it currently does not re-open the UDP socket if a failure occurs.  I'm sure other parts can certainly be cleaned up a bit too, but it's been working fine for a few months now at the site, so I'm satisfied with it.

The code first opens up a UDP socket on the IP address and port specified (10.10.10.25, 10023) and then continues to poll each channel we wanted to monitor (1-10) using the command "/node   ,s" for its status.  The Behringer mixer returns mute status (with an ON or OFF), ON being that the channel is on and signal is allowed to pass, along with the actual level the fader is set too (or infinity = ‐oo) which then the code looks for a lower case "o" = decimal 111.  If a channel returns ON and the fader is not all the way down, it then adds a 1 to the channel list.  The code then finally checks if any channels in the list are set to 1, if any channel in the list is set to 1, it will trigger the GPIO 18 to on, otherwise if all of the channels are set to 0, it will trigger GPIO 18 to off.

Because it is constantly polling each channel few times a second, the response time to trigger the on-air sign on or off is very fast (maybe 1/2 a second).

Create the onair.py file

nano onair.py

Copy and paste the code below (Ctrl+x and y to save)

#!/usr/bin/python
'''
Polls a Behringer mixer over UDP port 10023 (channels 1-10), if any are Not muted and the fader is up, it will trigger GPIO 18 to True
    Algis Salys
'''

import socket   #for sockets
import sys  #for exit
import time
import RPi.GPIO as GPIO

GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)

# create dgram udp socket
try:
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    s.settimeout(2)
except socket.error:
    print '[-]   ERR:   Failed to create socket'
    sys.exit()

led = 18
GPIO.setup(led, GPIO.OUT)

host = '10.10.10.25';
port = 10023;
onair = 0;
channel_status = [];
state = 0;
count = 0;

while(1) :
    time.sleep(.01)
    for x in range(1,11):
     if count > 5:
        state = 0
            GPIO.output(led, 0)
         count = 0
        channel = str(x).zfill(2)
        s.sendto("/node"+'\x00\x00\x00'+",s"+'\x00\x00'+"ch/" + channel + "/mix"+'\x00\x00\x00', (host, port))
        try:
         d = s.recvfrom(1024)
            time.sleep(.01)
            if len(d) == 0:
            print '[-]   ERR:   No data received'
            reply = d[0]
            addr = d[1]
        except socket.timeout, e:
            err = e.args[0]
            if err == 'timed out':
                print '[-]   ERR:   Recv timed out, retry later'
                time.sleep(1)
                print count
                count += 1
                continue
            else:
                print e
                continue
                #sys.exit(1)
            except socket.error, e:
             err = e.arg[0]
                if err == errno.EAGAIN or err == errno.EWOULDBLOCK:
                    time.sleep(1)
                    print '[-]   ERR:   No data available'
                    continue
                else:
                    print '[-]   ERR:   Error Code : ' + str(e[0]) + ' Message ' + e[1]
                    #sys.exit()
             continue
             count += 1
            else:
                volume_ack = reply.split(' ',2)
                data = bytearray(volume_ack[2])
                volume = int(data[3])
                if volume_ack[1] == 'ON' and volume != 111:
                    channel_status.append(1)
                else:
                    channel_status.append(0)
    if 1 in channel_status and state == 0:
        print 'On Air'
        state = 1
        GPIO.output(led, 1)
    elif 1 in channel_status:
        state = 1
    else:
        print 'Off Air'
        state = 0
        GPIO.output(led, 0)
    channel_status = [];

GPIO.cleanup()

 

Make the script executable

chmod +x onair.py

Manually run the script (accessing the GPIO requires sudo)

sudo ./onair.py

 

Starting the Code At Boot

The python code above needs to start whenever the Raspberry Pi boots up.  Using nano, I simply added a line to /etc/rc.local for this.

sudo nano /etc/rc.local

add the following line to the end ofthe file BUT above the last line exit 0

(sleep 15;python onair.py)&

 

Wiring in the On-Air Sign

We just built a simple circuit, connecting the base of a transistor to a GPIO pin on the Raspberry Pi, this then controls a relay to switch the 12VDC on-air sign on and off.  Here is a picture of the board we made that connected to GPIO 18 on the Raspberry Pi.

 raspberry pi mixer onair sign 01

 

Video of the Pi Controller in Action

Here's a short video we made demonstrating the Pi controller in action

 

 

References:

https://sourceforge.net/projects/x32livetoolbox/files/Documents/

 

 

 

Read 6352 times Last modified on Tuesday, 28 March 2017 12:52
Algis Salys

Creator and owner of algissalys.com.  Linux enthusiast, electronics tinkerer, and likes to spend time in the workshop building and creating new projects.