Overwitch, a JACK client for Overbridge devices, AKA Overbridge for Linux

Ok, I changed that line and recompiled the software, which moved things forward. Running

$ chrt -f 35 overwitch -d "Analog Four MKII"

now gave me new errors (I tried both with and without sudo) :slight_smile:

Device: Analog Four MKII (outputs: 8, inputs: 6)
Cannot connect to server socket err = No such file or directory
Cannot connect to server request channel
exec of JACK server (command = "#!/bin/sh") failed: No such file or directory
Cannot connect to server socket err = No such file or directory
Cannot connect to server request channel
Cannot connect to server socket err = No such file or directory
Cannot connect to server request channel
Cannot connect to server socket err = No such file or directory
Cannot connect to server request channel
Cannot connect to server socket err = No such file or directory
Cannot connect to server request channel
Cannot connect to server socket err = No such file or directory
Cannot connect to server request channel
jack server is not running or cannot be started
JackShmReadWritePtr::~JackShmReadWritePtr - Init not done for -1, skipping unlock
JackShmReadWritePtr::~JackShmReadWritePtr - Init not done for -1, skipping unlock
ERROR:jclient.c:607:(jclient_run): jack_client_open() failed, status = 0x11
ERROR:jclient.c:611:(jclient_run): Unable to connect to JACK server

So, there seems to be something up with the JACK server… maybe. Interesting to note is that I never received any request to configure JACK for real time priority when installing jackd2(as specified in the manual). I’m going to dig around with JACK itself for a bit (I’m not really familiar with this software from before).

Also, I’ve forked the repository and I’m writing down everything that I learn in the readme file while doing all this so that hopefully whoever comes after me will have an easier time. I’ll make a pull request later if you’d like to accept it (or maybe just pick out some parts of it).

Ok, after some digging around, what I had to do was to execute

jack_control start

before starting Overwitch. Everything seems to run as it should now.

$ chrt -f 35 overwitch -d "Analog Four MKII" -v
Device: Analog Four MKII (outputs: 8, inputs: 6)
JACK sample rate: 48000
JACK buffer size: 1024
DEBUG:overbridge.c:757:(overbridge_run): Starting MIDI thread...
DEBUG:overbridge.c:765:(overbridge_run): Starting device thread...
DEBUG:jclient.c:347:(jclient_compute_ratios): Max. latencies (ms): 0.0, 0.0; avg. ratios: 1.000175, 0.999826; curr. ratios: 0.999866, 1.000134
DEBUG:jclient.c:347:(jclient_compute_ratios): Max. latencies (ms): 0.0, 0.0; avg. ratios: 0.999917, 1.000083; curr. ratios: 0.999946, 1.000054
DEBUG:jclient.c:347:(jclient_compute_ratios): Max. latencies (ms): 0.0, 0.0; avg. ratios: 0.999970, 1.000030; curr. ratios: 0.999985, 1.000015
DEBUG:jclient.c:347:(jclient_compute_ratios): Max. latencies (ms): 0.0, 0.0; avg. ratios: 1.000002, 0.999998; curr. ratios: 1.000005, 0.999995
DEBUG:jclient.c:347:(jclient_compute_ratios): Max. latencies (ms): 0.0, 0.0; avg. ratios: 1.000012, 0.999988; curr. ratios: 1.000013, 0.999987

Next step is to figure out how to actually hear the sound from my devices, setting up several devices, and recording my sessions. All of these things are beyond the scope of the readme, but I’ll try to add as much as I can when (if :stuck_out_tongue: ) I find out what to do.

2 Likes

Currently, I have some general problem with Jack on my Raspberry Pi 4 running Patchbox OS. Hopefully, I can get it solved.

In the meantime, I take it that when you get Overwitch up and running the way it seamed like I did above, the work of Overwitch is really done. However, I would like to output whatever comes through my Elektron devices on the main outputs as well as multi-track record it, all via some Terminal commands so that I can automate this process whenever I start up my Raspberry Pi 4.

Do any of you have any suggestions on what programs that I could use?

WRT recording the audio to file you could do something like this.

First and foremost install jack_capture and run JACK and Overwitch as stated above.

Then, let’s see all the JACK ports and how they are connected. My audio interface is a Soundcraft Signature MTK12 (14 inputs and 12 outputs). For the sake of brevity I’ll omit some ports.

$ jack_lsp -c
[...]
system:playback_11
system:playback_12
Digitakt:Main L
Digitakt:Main R
Digitakt:Track 1
Digitakt:Track 2
[...]
Digitakt:Track 7
Digitakt:Track 8
Digitakt:Input L
Digitakt:Input R
Digitakt:Main L Input
Digitakt:Main R Input
[...]

From here, let’s monitor something. I’ll connect the main output to the stereo pair I’m monitoring thru my headphones.

$ jack_connect "Digitakt:Main L" system:playback_11
$ jack_connect "Digitakt:Main R" system:playback_12

And let’s run jack_lsp -c again. We’ll see the connections.

$ jack_lsp -c
[...]
system:playback_11
   Digitakt:Main L
system:playback_12
   Digitakt:Main R
Digitakt:Main L
   system:playback_11
Digitakt:Main R
   system:playback_12
Digitakt:Track 1
Digitakt:Track 2
[...]
Digitakt:Track 7
Digitakt:Track 8
Digitakt:Input L
Digitakt:Input R
Digitakt:Main L Input
Digitakt:Main R Input
[...]

Now, let’s just record what we want. For instance, the 8 mono tracks.

$ chrt -f 35 jack_capture -b 16 -c 8 -p "Digitakt:Track 1" -p "Digitakt:Track 2" -p "Digitakt:Track 3" -p "Digitakt:Track 4" -p "Digitakt:Track 5" -p "Digitakt:Track 6" -p "Digitakt:Track 7" -p "Digitakt:Track 8" foo.wav
>>> Warning. Could not set higher priority for a SCHED_OTHER process using setpriority().
>>> Recording to "foo.wav". Press <Return> or <Ctrl-C> to stop.
>>> Please wait while writing all data to disk. (shouldn't take long)   
   |"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""|
00:|-----------                    *                                 |
01:|-------------               *                                    |
02:|--------------------------- *                                    |
03:|                                                                 |
04:|-------                     *                                    |
05:|---------                *                                       |
06:|                                                                 |
07:|                                                                 |
Buffer: 4.01s./4.01s    Time: 0.28m.   DHP: [ ]  Overruns: 0  Xruns: 0
Finished.

And there it is. An 8 channel WAVE file directly streamed to disk while monitoring the device mix.

$ sox --i foo.wav 

Input File     : 'foo.wav'
Channels       : 8
Sample Rate    : 48000
Precision      : 16-bit
Duration       : 00:00:28.08 = 1347712 samples ~ 2105.8 CDDA sectors
File Size      : 21.6M
Bit Rate       : 6.14M
Sample Encoding: 16-bit Signed Integer PCM

By the way, these are the reported latencies. No Xruns.

$ chrt -f 35 overwitch -q 2 -d Digitakt -b 8
Device: Digitakt (outputs: 12, inputs: 2)
JACK sample rate: 48000
JACK buffer size: 64
^CMax. latencies (ms): 3.5, 3.4

Edit: I forgot to mention that I’ve fixed the bug in the device selection.

5 Likes

I just wanted to chime in and say I had the same issue trying to set up a Digitone. Did a git pull, rebuild, install, and now it works. I now have Digitakt and Digitone set up in tandem:

$ ps -C overwitch,jackdbus H o pid,tid,comm,rtprio,priority,policy                                    
  PID   TID COMMAND         RTPRIO PRI POL
 4284  7254 jackdbus            40 -41 FF
11147 11153 overwitch           35 -36 FF
11158 11164 overwitch           35 -36 FF

Running jack settings at 128/48000, seems to be working with no issues, even when PulseAudio is bridged.

5 Likes

Yeah, I fixed that the very next morning. :stuck_out_tongue:

Great it’s working as intended and really nice to see both devices together. Thanks for reporting. :+1:

BTW, ¿anyone having succes with AH, AF MKII or AR MKII?

I have encountered an issue:
In my setup I use the Octatrack as the main sequencer and the MIDI master clock. It’s sending MIDI to the audio interface. ALSA MIDI is bridged to Jack, which exposes the audio interface’s MIDI Thru, which can then be connected to the various MIDI inputs in Jack.

Connecting MIDI from the audio interface to Overwitch works at first, but after a while, the connection is broken. Overwitch the prints a lot of these messages:

ERROR:jclient.c:508:(jclient_j2o_midi): j2o: Buffer MIDI overflow. Discarding data...  

Any way I could debug this further? Any workarounds?
I’m running Overwitch with ‘-b 8’

I’d need to take a look at that carefully but I can tell you that the MIDI overflow error is unrelated to the audio blocks (-b parameter). Overwitch uses 4 queues (in and out for audio and MIDI) and these are independent of each other. Because audio is still working, right?

Based on this, can we discard that a MIDI loop is the origin of the issue? It’s really weird that the queue from the computer to the device is full. Another possibility is that Overwitch itself is not reading from that queue for whatever reason.

If audio works and there is no MIDI feedback, please, open an issue on GitHub to keep track of this.

I think it’s better if we don’t pollute this thread with too technical stuff.

Thanks for reporting this. :+1:

1 Like

I don’t see how there could be any MIDI loop/feedback. I’ll open an issue.

I use scripts to set up different configurations on my DAW, so I wrote a script to stop and start Overwitch for any connected devices. Figured I’d post it here in case anyone will benefit from it:

#!/bin/python3

# Simple script which starts Overwitch if it is not running, and vice versa

import re
import subprocess
import os
import psutil
import sys

# List of supported devices
obDeviceList = [
    "Digitakt",
    "Digitone"
    ]
    
presentUSBDevices = subprocess.check_output("lsusb")
presentOBDevices = []
activeOverwitchProcesses = []

## Get Overbridge devices present on the system
def getOBDevices(obDeviceList):
    for obDevice in obDeviceList:
        pattern = "^.*" + obDevice + ".*$"
        device_re = re.compile(pattern)
        
        for currentUSBDevice in presentUSBDevices.split(b'\n'):
            if device_re.match(str(currentUSBDevice)):
                presentOBDevices.append(obDevice)
    
    return presentOBDevices
            
## Check Overwitch running state
def checkOverwitchPSState(activeOverwitchProcesses):
    #Reset the list of processes
    activeOverwitchProcesses.clear()
    #Iterate over the all the running processes, match overwitch
    for proc in psutil.process_iter():
        try:
            if "overwitch" in proc.name().lower():
                activeOverwitchProcesses.append(proc.pid)
        except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
            pass
            
    return activeOverwitchProcesses;
    
## Stop Overwitch
def stopOverwitch(activeOverwitchProcesses):
    for processID in activeOverwitchProcesses:
        try:
            print('Stopping Overwitch process ID: ' + str(processID) + '...')
            os.kill(processID, 24)
        except:
            print('Could not stop Overwitch process ID: ' + str(processID) + '.')
    
## Start Overwitch
def startOverwitch(presentOBDevices):
    for device in presentOBDevices:
        try:
            print('Starting Overwitch for device: ' + device + '...')
            process = subprocess.Popen(['overwitch', '-d', device, '-b', '8'])
            poll = process.poll()
            if poll is None:
                print('Overwitch started for device: ' + device + '.')
            else:
                print("Could not start Overwitch for device: " + device + '.')
        except:
            print("Could not start Overwitch for device: " + device + '.')
            
## Main
checkOverwitchPSState(activeOverwitchProcesses)

if len(activeOverwitchProcesses) > 0:
    stopOverwitch(activeOverwitchProcesses)
    sys.exit()
    
getOBDevices(obDeviceList)
startOverwitch(presentOBDevices)

It currently supports Digitakt and Digitone, but can easily be expanded by adding devices to the “obDeviceList”. Run with python3.

6 Likes

Overwitch 0.2 is finally out!

It is just a much more refined, stable and resilient version.

These are the improvements since version 0.1.

  • Support for all Overbridge 2 machines.
  • MIDI support.
  • Improved latency, stability and XRUN handling.
  • Buffer on the Overbridge side is configurable by selecting the amount of blocks transferred at once. One block is 7 samples. Every combination of Overbridge and JACK buffer sizes is now possible.
  • Resampling quality is user selectable with -q. 0 is the best quality and most computational expensive; 4 is otherwise. The default value is 2.
  • Run with realtime priority by default, so no need to use it with chrt any more.
  • Auto detect the Overbridge machines, so no need to use -dany more.
  • Support for several devices in the same process, so no need to run several instances.
  • Support for several machines of the same type. Option -nshould be used when selecting a device by ID and option -d is not recommended any more but it’s still kept.
  • Support for dynamic change of JACK buffer size, so no need to restart.

These are the options.

$ overwitch -h
overwitch 0.2
Usage: overwitch [options]
Options:
  --use-device-number, -n value
  --use-device, -d value
  --resampling-quality, -q value
  --transfer-blocks, -b value
  --rt-overbridge-priority, -p value
  --list-devices, -l
  --verbose, -v
  --help, -h

Usage examples.

$ overwitch -l
0: Bus 003 Device 065: ID 1935:000c Digitakt

$ overwitch -b 4 -v
Device: Digitakt (outputs: 12, inputs: 2)
JACK sample rate: 48000
DEBUG:jclient.c:756:(jclient_run): Using RT priority 5...
DEBUG:overbridge.c:932:(overbridge_activate): Starting j2o MIDI thread...
DEBUG:overbridge.c:940:(overbridge_activate): Starting audio and o2j MIDI thread...
JACK buffer size: 32
[...]
Digitakt: o2j latency: 0.8 ms, max. 2.0 ms; j2o latency: 1.2 ms, max. 1.9 ms; o2j ratio: 0.999884, avg. 0.999887
[...]

Besides, I’d like to ask you a couple of things.

  • If a very small GUI would be useful for you. What do you think?
  • Has anybody used it successfully with Analog Four MKII, Analog Heat or Analog Heat MKII?

I hope this will be useful for Linux users.

9 Likes

MIDI jitter is all over the place on my setup, which makes the delay lines on the Digitone all wonky. Cool for that “worn out tape delay” effect, but I don’t want that effect.

Any idea how I can reduce the jitter? My setup is Jack at 256/3@48K, with default Overwitch settings.

1 Like

The most critical parameter with regards to MIDI timing is the -b option. It reduces the latency and will surely reduce the MIDI jitter as it sends smaller data blocks at a faster rate.

Try with 4 and let me know if that helps.

I’ve had more effect by enabling the “ALSA Raw-MIDI” driver. That, combined with transfer-block size 4 and 128/2 buffer settings makes the jitter just about acceptable. I guess I will just have to live with switching to lower buffer settings whenever I want to record.

A handy tool for anyone who wishes to monitor Jack MIDI latency/jitter on their audio interface.

2 Likes

Nice you found a way to reduce the jitter.

Perhaps 128 is still a bit too much. Have you tried with 64/3?

I discovered recently that if I use a different USB port I can reduce the ALSA buffer length more safely.

Sure! What makes things more accessible on Linux is always welcome. More access, more users, more development from brands (one day!)

1 Like

Wow, also just learned of this now, I tried to have a go at it myself some time back cause I thought nobody else was but I didn’t know much about writing this sort of thing myself. Gonna give this a shot with my A4

EDIT: Dude holy shit this works beautifully, much love <3

2 Likes

My signal is getting similarly bit-crushed. Digitakt into jack (rt) / 123x2@48K, firewire card. I’m invoking overwitch with:
overwitch -b 8 -q 4 -d Digitakt
What am I missing?

Welcome to elektronauts, @delete000.

It’s difficult to know what’s going on. Let’s check the basics first. Could you run it with the -v option and post the output here?

I suspect it might be related to the USB port being busy because a 128 frames latency should be enough for any modern computer. Check that your Digitakt is connected to a bus where nothing else is connected with lsusb -t and try different values for -b too or don’t use it at all.

Also, it could be the system load or using the dummy cores in your CPU (see the README.md of the project for more info about this). Stop all the system services, close all the unneeded applications and shut down your network just in case.

Let’s reduce it to the minimum and see the output log.

1 Like

@DG2 Thanks!

Re. system: It’s a Dell XPS 13 9300 laptop with a RME Fireface 400 soundcard. Curiously, it works just fine with the onboard card, but that’s useless.

I have disabled networking completely, stopped cron, bluetooth, updates, pulseaudio, etc. Removed all other devices apart from my firewire soundcard. Hyperthreading is disabled. CPU governor is set to performance. System load on qjackctl hovers around 2-3% and there are no spikes, so definitely not a system load issue.

Here’s some output:

$ overwitch -v
Device: Digitakt (outputs: 12, inputs: 2)
Jack: JackClient::SetupDriverSync driver sem in flush mode
Jack: JackLinuxFutex::Connect name = jack_sem.1001_default_Digitakt
Jack: Clock source : system clock via clock_gettime
Jack: JackLibClient::Open name = Digitakt refnum = 4
JACK sample rate: 48000
DEBUG:jclient.c:756:(jclient_run): Using RT priority 5...
Jack: JackClient::PortRegister ref = 4 name = Digitakt:Main L type = 32 bit float mono audio port_index = 37
Jack: JackClient::PortRegister ref = 4 name = Digitakt:Main R type = 32 bit float mono audio port_index = 38
Jack: JackClient::PortRegister ref = 4 name = Digitakt:Track 1 type = 32 bit float mono audio port_index = 39
Jack: JackClient::PortRegister ref = 4 name = Digitakt:Track 2 type = 32 bit float mono audio port_index = 40
Jack: JackClient::PortRegister ref = 4 name = Digitakt:Track 3 type = 32 bit float mono audio port_index = 41
Jack: JackClient::PortRegister ref = 4 name = Digitakt:Track 4 type = 32 bit float mono audio port_index = 42
Jack: JackClient::PortRegister ref = 4 name = Digitakt:Track 5 type = 32 bit float mono audio port_index = 43
Jack: JackClient::PortRegister ref = 4 name = Digitakt:Track 6 type = 32 bit float mono audio port_index = 44
Jack: JackClient::PortRegister ref = 4 name = Digitakt:Track 7 type = 32 bit float mono audio port_index = 45
Jack: JackClient::PortRegister ref = 4 name = Digitakt:Track 8 type = 32 bit float mono audio port_index = 46
Jack: JackClient::PortRegister ref = 4 name = Digitakt:Input L type = 32 bit float mono audio port_index = 47
Jack: JackClient::PortRegister ref = 4 name = Digitakt:Input R type = 32 bit float mono audio port_index = 48
Jack: JackClient::PortRegister ref = 4 name = Digitakt:Main L Input type = 32 bit float mono audio port_index = 49
Jack: JackClient::PortRegister ref = 4 name = Digitakt:Main R Input type = 32 bit float mono audio port_index = 50
Jack: JackClient::PortRegister ref = 4 name = Digitakt:MIDI out type = 8 bit raw midi port_index = 51
Jack: JackClient::PortRegister ref = 4 name = Digitakt:MIDI in type = 8 bit raw midi port_index = 52
DEBUG:overbridge.c:932:(overbridge_activate): Starting j2o MIDI thread...
DEBUG:overbridge.c:940:(overbridge_activate): Starting audio and o2j MIDI thread...
Jack: JackPosixThread::AcquireRealTimeImp priority = 5
Jack: JackClient::Activate
Jack: JackPosixThread::StartImp : create non RT thread
Jack: JackPosixThread::AcquireRealTimeImp priority = 5
Jack: JackPosixThread::ThreadHandler : start
Jack: JackClient::kBufferSizeCallback buffer_size = 128
JACK buffer size: 128
Jack: JackClient::Init : period = 2666 computation = 300 constraint = 2666
Jack: JackPosixThread::AcquireRealTimeImp priority = 5
Jack: JackClient::ClientNotify ref = 4 name = Digitakt notify = 2
Jack: JackClient::kActivateClient name = Digitakt ref = 4 
Jack: JackClient::ClientNotify ref = 4 name = Digitakt notify = 18
Jack: JackClient::ClientNotify ref = 4 name = Digitakt notify = 18
Jack: JackClient::ClientNotify ref = 4 name = Digitakt notify = 18
Jack: JackClient::ClientNotify ref = 4 name = Digitakt notify = 18
Digitakt: o2j latency: 0.0 ms, max. 0.0 ms; j2o latency: 0.0 ms, max. 0.0 ms; o2j ratio: 1.000088, avg. 1.000024
^CDigitakt: o2j latency: 0.0 ms, max. 0.0 ms; j2o latency: 0.0 ms, max. 0.0 ms
DEBUG:jclient.c:830:(jclient_run): Exiting...
Jack: JackClient::Deactivate
Jack: JackClient::Deactivate res = 0
Jack: JackPosixThread::Kill
Jack: jack_client_close
Jack: JackClient::Close ref = 4
Jack: JackClient::Deactivate
Jack: JackSocketClientChannel::Stop
Jack: JackPosixThread::Kill
Jack: JackClientSocket::Close
Jack: JackClientSocket::Close
Jack: JackLibClient::~JackLibClient
Jack: JackShmReadWritePtr1::~JackShmReadWritePtr1 3
Jack: Succeeded in unlocking 422 byte memory area
Jack: JackLibGlobals Destroy 14007220
Jack: ~JackLibGlobals
Jack: no message buffer overruns
Jack: JackPosixThread::Stop
Jack: JackPosixThread::ThreadHandler : exit
Jack: JackShmReadWritePtr::~JackShmReadWritePtr 1
Jack: Succeeded in unlocking 1187 byte memory area
Jack: JackShmReadWritePtr::~JackShmReadWritePtr 0
Jack: Succeeded in unlocking 82280346 byte memory area
Jack: jack_client_close res = 0

Just for completeness: I verified that the bit reduction effect on the Digitakt is off :smile:

Looking at the output, I see lots of “32 bit float mono” in there. I think the soundcard works at 24 bits internally. Could this be the issue? Otoh, all other audio plays just fine through the card.