GithubHelp home page GithubHelp logo

dagargo / overwitch Goto Github PK

View Code? Open in Web Editor NEW
120.0 16.0 14.0 461 KB

JACK client for Overbridge devices

License: GNU General Public License v3.0

Makefile 2.16% M4 1.02% C 96.82%
audio jack midi usb hacktoberfest

overwitch's Introduction

Overwitch

Overwitch is an Overbridge 2 device client for JACK (JACK Audio Connection Kit).

This project is based on the Overbridge USB reverse engineering done by Stefan Rehm in dtdump.

The papers Controlling adaptive resampling and Using a DLL to filter time by Fons Adriaensen have been very helpful and inspiring, as well as his own implementation done in the zita resamplers found in the alsa tools project.

At the moment, it provides support for all Overbridge 2 devices, which are Analog Four MKII, Analog Rytm MKII, Digitakt, Digitone, Digitone Keys, Analog Heat, Analog Heat MKII and Syntakt.

Overbridge 1 devices, which are Analog Four MKI, Analog Keys and Analog Rytm MKI, are not supported yet.

Overwitch consists of 4 different binaries: overwitch, which is a GUI application, overwitch-cli which offers the same functionality for the command line; and overwitch-play and overwitch-record which do not integrate with JACK at all but stream the audio from and to a WAVE file.

Installation

As with other autotools project, you need to run the commands below. There are a few options available.

  • If you just want to compile the command line applications, pass CLI_ONLY=yes to ./configure.
  • If you do not want to use the JSON devices files, pass JSON_DEVS_FILE=no to ./configure. This is useful to eliminate GLIB dependencies when building the library. In this case, the devices configuration used are the ones in the source code. See the adding devices section for more information.
autoreconf --install
./configure
make
sudo make install
sudo ldconfig

Some udev rules might need to be installed manually with sudo make install from the udev directory as they are not part of the install target. This is not needed when packaging or when distributions already provide them.

The package dependencies for Debian based distributions are:

  • automake
  • libtool
  • libusb-1.0-0-dev
  • libjack-jackd2-dev
  • libsamplerate0-dev
  • libsndfile1-dev
  • autopoint
  • gettext
  • libjson-glib-dev (only if JSON_DEVS_FILE=no is not used)
  • libgtk-3-dev (only if CLI_ONLY=yes is not used)

You can easily install all them by running sudo apt install automake libtool libusb-1.0-0-dev libjack-jackd2-dev libsamplerate0-dev libsndfile1-dev autopoint gettext libjson-glib-dev libgtk-3-dev.

As this will install jackd2, you would be asked to configure it to be run with real time priority. Be sure to answer yes. With this, the audio group would be able to run processes with real time priority. Be sure to be in the audio group too.

Usage

Overwitch contains two JACK clients, one for the desktop and one for the command line and a recording and playing utility for the command line.

Regarding the JACK clients, latency needs to be under control and it can be tuned with the following parameters.

  • Blocks, which controls the amount of data sent in a single USB operation. The higher, the higher latency but the lower CPU usage. 4 blocks keeps the latency quite low and does not impact on the CPU.
  • Quality, which controls the resampler accuracy. The higher, the more CPU consuming. A medium value is recommended. Notice that in overwitch-cli, a value of 0 means the highest quality while a value of 4 means the lowest.

overwitch

The GUI is self explanatory and does not requiere any parameter passed from the command line.

$ overwitch -h
overwitch 1.0
Usage: overwitch [options]
Options:
  --verbose, -v
  --help, -h

If you are running PipeWire, go to the PipeWire section for additional information.

Notice that once an Overbridge device is running the options can not be changed so you will need to stop the running instances and refresh the list.

It is possible to rename Overbridge devices by simply editing its name on the list. Still, as JACK devices can not be renamed while running, the device will be restarted.

overwitch-cli

First, list the available devices. The first element is an internal ID that allows to identify the devices.

$ overwitch-cli -l
0: Digitakt (ID 1935:000c) at bus 001, address 005

Then, you can choose which device you want to use by using one of these options. Notice that the second option will only work for the first device found with that name.

$ overwitch-cli -n 0
$ overwitch-cli -d Digitakt

To stop, just press Ctrl+C. You'll see an oputput like the one below. Notice that we are using the verbose option here but it is not recommended to use it and it is showed here for illustrative purposes only.

$ overwitch-cli -d Digitakt -v -b 4
DEBUG:overwitch.c:206:(ow_get_devices): Found Digitakt (bus 001, address 005, ID 1935:000c)
DEBUG:jclient.c:112:(jclient_set_sample_rate_cb): JACK sample rate: 48000
DEBUG:jclient.c:471:(jclient_run): Using RT priority 5...
DEBUG:engine.c:1001:(ow_engine_activate): Starting p2o MIDI thread...
DEBUG:engine.c:1015:(ow_engine_activate): Starting audio and o2p MIDI thread...
DEBUG:jclient.c:112:(jclient_set_sample_rate_cb): JACK sample rate: 48000
DEBUG:jclient.c:102:(jclient_set_buffer_size_cb): JACK buffer size: 64
DEBUG:jclient.c:102:(jclient_set_buffer_size_cb): JACK buffer size: 64
Digitakt@001,005: o2j latency: -1.0 ms, max. -1.0 ms; j2o latency: -1.0 ms, max. -1.0 ms, o2j ratio: 0.999888, avg. 0.999904
Digitakt@001,005: o2j latency: -1.0 ms, max. -1.0 ms; j2o latency: -1.0 ms, max. -1.0 ms, o2j ratio: 0.999901, avg. 0.999903
Digitakt@001,005: o2j latency:  1.4 ms, max.  1.8 ms; j2o latency: -1.0 ms, max. -1.0 ms, o2j ratio: 0.999903, avg. 0.999905
^C
DEBUG:jclient.c:579:(jclient_run): Exiting...

To limit latency to the lowest possible value, audio is not sent through during the first seconds.

You can list all the available options with -h.

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

If you are running PipeWire, you might want to pass the PIPEWIRE_PROPS environment variable with the node.group property set to same value the hardware has. Go to the PipeWire section for additional information.

$ PIPEWIRE_PROPS='{ node.group = hardware_node_group }' overwitch

overwitch-play

This small utility let the user play an audio file thru the Overbridge devices.

$ overwitch-play -d Digitakt audio_file

You can list all the available options with -h.

$ overwitch-play -h
overwitch 1.1
Usage: overwitch-play [options] file
Options:
  --use-device-number, -n value
  --use-device, -d value
  --blocks-per-transfer, -b value
  --usb-transfer-timeout, -t value
  --list-devices, -l
  --verbose, -v
  --help, -h

overwitch-record

This small utility let the user record the audio output from the Overbridge devices into a WAVE file with the following command. To stop, just press Ctrl+C.

$ overwitch-record -d Digitakt
^C
2106720 frames written
Digitakt_dump_2022-04-20T19:20:19.wav file created

By default, it records all the output tracks from the Overbridge device but it is possible to select which ones to record. First, list the devices in verbose mode to see all the available tracks.

$ overwitch-record -l -v
DEBUG:overwitch.c:206:(ow_get_devices): Found Digitakt (bus 001, address 005, ID 1935:000c)
0: Digitakt (ID 1935:000c) at bus 001, address 005
  Inputs:
    Main L Input
    Main R Input
  Outputs:
    Main L
    Main R
    Track 1
    Track 2
    Track 3
    Track 4
    Track 5
    Track 6
    Track 7
    Track 8
    Input L
    Input R

Then, just select the output tracks to record as this. 0 means that the track is not recorded while any other character means it will. In this example, we are recording tracks 1, 2, 5 and 6.

$ overwitch-record -d Digitakt -m 001100110000
^C
829920 frames written
Digitakt_dump_2022-04-20T19:33:30.wav file created

It is not neccessary to provide all tracks, meaning that using 00110011 as the mask will behave exactly as the example above.

You can list all the available options with -h.

$ overwitch-record -h
overwitch 1.1
Usage: overwitch-record [options]
Options:
  --use-device-number, -n value
  --use-device, -d value
  --track-mask, -m value
  --track-buffer-size-kilobytes, -s value
  --blocks-per-transfer, -b value
  --usb-transfer-timeout, -t value
  --list-devices, -l
  --verbose, -v
  --help, -h

PipeWire

Depending on your PipeWire configuration, you might want to pass some additional information to Overwitch by setting the PIPEWIRE_PROPS environment variable. This value can be set in the GUI settings directly but any value passed at command launch will always take precedence over that configuration.

Under PipeWire, a JACK client always follows a driver and when no connections are created it follows the "Dummy-Driver". This might cause some latency issues when making connections as the clients will transit to a new driver, making the timing measurements to wobble for a moment and ultimately increasing the latency.

To avoid that, here are some recommendations. Still, always try to follow the official PipeWire documentation.

  • Use the Pro audio profile.
  • Schedule Overwitch (both CLI and GUI) under the hardware driver. This can be achieved by using the properties node.link-group or node.group.
  • Do not have passive PipeWire nodes (node.passive set to true) to avoid driver changes.

Latency

Device to JACK latency is different from JACK to device latency though they are very close. These latencies are the transferred frames to and from the device and, by default, these are performed in 24 blocks of 7 frames (168 frames).

Thus, the minimum theoretical latency is the device frames plus the JACK buffer frames plus some additional buffer frames are used in the resamplers but it is unknown how many.

To keep latency as low as possible, the amount of blocks can be configured in the JACK clients. Values between 2 and 32 can be used.

Tuning

Although this is a matter of JACK, Ardour and OS tuning, Here you have some tips.

First and foremost, real time applications work much better without SMT/HyperThreading activated. This script might be handy. It also changes the CPU governor to performance.

#!/bin/bash

function disable() {
  for c in $(seq 0 $(cat /sys/devices/system/cpu/present | awk -F- '{print $2}')); do
    cpu_sibling_file=/sys/devices/system/cpu/cpu$c/topology/thread_siblings_list
    if [ -f $cpu_sibling_file ]; then
      id=$(cat $cpu_sibling_file | awk -F, '{print $1}')
      if [ "$c" != "$id" ]; then
        echo 0 | sudo tee /sys/devices/system/cpu/cpu$c/online > /dev/null
      else
        sudo cpufreq-set -c $c -g performance
      fi
    fi
  done
}

function enable() {
  for c in $(seq 1 $(cat /sys/devices/system/cpu/present | awk -F- '{print $2}')); do
    echo 1  | sudo tee /sys/devices/system/cpu/cpu$c/online > /dev/null
    sudo cpufreq-set -c $c -g ondemand
  done
}

function status() {
  grep -E '^model name|^cpu MHz' /proc/cpuinfo
}

if [ "$1" == "enable" ] || [ "$1" == "disable" ] || [ "$1" == "status" ]; then
  $1
  [ "$1" != "status" ] && status
  exit 0
else
  echo "Unknown smt setup" >&2
  exit -1
fi

With rtirq-init package installed I simply let the script reconfigure the priorities of IRQ handling threads and then I run JACK, Overwitch and the desired applications. Notice that real time priorities are set by default so there is no need to set explicitely these.

$ sudo /etc/init.d/rtirq start
$ jackd ...
$ overwitch -b 8 -q 2 -d Digitakt
$ ardour

Currently I'm using this RT kernel. You don't need an RT kernel but it will help even more to reduce latency and xruns.

$ uname -v
#1 SMP PREEMPT_RT Debian 5.10.28-1 (2021-04-09)

With all this configuration I get no JACK xruns with 64 frames buffer (2 periods) and occasional xruns with 32 frames buffer (3 periods) with network enabled and under normal usage conditions.

Although you can run Overwitch with verbose output this is not recommended unless you are debugging the application.

Adding devices

Devices can be specified in two ways.

  • Outside the library, in JSON files. Useful for a typical desktop usage as devices can be user-defined, so no need to recompile the code or wait for new releases.
  • Inside the library, in C code. Useful when using the liboverwitch library and GLib dependencies are unwanted. Notice that the library is compiled with JSON support by default. See the Installation section.

Outside the library

This is a self-explanatory device definition from res/devices.json. The file is an array of definitions.

{
  "pid": 12,
  "name": "Digitakt",
  "input_track_names": [
    "Main L Input",
    "Main R Input"
  ],
  "output_track_names": [
    "Main L",
    "Main R",
    "Track 1",
    "Track 2",
    "Track 3",
    "Track 4",
    "Track 5",
    "Track 6",
    "Track 7",
    "Track 8",
    "Input L",
    "Input R"
  ]
}

If the file ~/.config/elektroid/elektron-devices.json is found, it will take precedence over the installed one.

Inside the library

New Overbridge 2 devices could be easily added in the overbridge.c file as they all share the same protocol.

To define a new device, just add a new struct like this and add the new constant to the array. USB PIDs are already defined just above. For instance, if you were adding the Analog Rytm MKII, you could do it like in the example below.

Notice that the definition of the device must match the device itself, so outputs and inputs must match the ones the device has and must be in the same order. As this struct defines the device, an input is a port the device will read data from and an output is a port the device will write data to.

static const struct overbridge_device_desc_static ARMK2_DESC = {
  .pid = ARMK2_PID,
  .name = "Analog Rytm MKII",
  .inputs = 12,
  .outputs = 12,
  .input_track_names =
    {"Main L Input", "Main R Input", "Main FX L Input", "Main FX R Input",
     "BD Input", "SD Input", "RS/CP Input", "BT Input",
     "LT Input", "MT/HT Input", "CH/OH Input", "CY/CB Input"},
  .output_track_names = {"Main L", "Main R", "BD", "SD", "RS/CP",
			 "BT", "LT", "MT/HT", "CH/OH", "CY/CB", "Input L",
			 "Input R"}
};

static const struct overbridge_device_desc OB_DEVICE_DESCS[] = {
  DIGITAKT_DESC, DIGITONE_DESC, ARMK2_DESC, NULL
};

overwitch's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

overwitch's Issues

Fix JACK audio disconnection of device inputs

In 887f18e, only writing to the j2o ring buffer was performed if there were inputs connected.

This works well but if we later disconnect the inputs, the OB end keeps reading and resampling from the queue, what creates a noisy and undesirable output.

latest master will stop working after a minute with Digitone

I haven't tried with Digitakt,yet. But on my Digitone I get this with latest master after approx one minute

[...]
DEBUG:overbridge.c:815:(run_j2o_midi): Event frames: 25; diff: 0
DEBUG:overbridge.c:815:(run_j2o_midi): Event frames: 117; diff: 0
DEBUG:overbridge.c:815:(run_j2o_midi): Event frames: 118; diff: 0
DEBUG:overbridge.c:815:(run_j2o_midi): Event frames: 82; diff: 0
DEBUG:overbridge.c:815:(run_j2o_midi): Event frames: 62; diff: 0
DEBUG:overbridge.c:815:(run_j2o_midi): Event frames: 111; diff: 0
DEBUG:overbridge.c:815:(run_j2o_midi): Event frames: 100; diff: 0
DEBUG:overbridge.c:815:(run_j2o_midi): Event frames: 16; diff: 0
DEBUG:overbridge.c:815:(run_j2o_midi): Event frames: 35; diff: 0
DEBUG:overbridge.c:815:(run_j2o_midi): Event frames: 18; diff: 0
DEBUG:overbridge.c:815:(run_j2o_midi): Event frames: 114; diff: 0
DEBUG:overbridge.c:815:(run_j2o_midi): Event frames: 69; diff: 0
DEBUG:overbridge.c:815:(run_j2o_midi): Event frames: 66; diff: 0
DEBUG:overbridge.c:815:(run_j2o_midi): Event frames: 12; diff: 0
DEBUG:overbridge.c:815:(run_j2o_midi): Event frames: 86; diff: 0
DEBUG:overbridge.c:815:(run_j2o_midi): Event frames: 61; diff: 0
DEBUG:overbridge.c:815:(run_j2o_midi): Event frames: 91; diff: 0
DEBUG:overbridge.c:815:(run_j2o_midi): Event frames: 15; diff: 0
DEBUG:overbridge.c:815:(run_j2o_midi): Event frames: 66; diff: 0
DEBUG:overbridge.c:815:(run_j2o_midi): Event frames: 29; diff: 0
DEBUG:overbridge.c:815:(run_j2o_midi): Event frames: 13; diff: 0
DEBUG:overbridge.c:815:(run_j2o_midi): Event frames: 34; diff: 0
DEBUG:overbridge.c:815:(run_j2o_midi): Event frames: 44; diff: 0
DEBUG:overbridge.c:815:(run_j2o_midi): Event frames: 99; diff: 0
DEBUG:overbridge.c:815:(run_j2o_midi): Event frames: 78; diff: 0
DEBUG:overbridge.c:815:(run_j2o_midi): Event frames: 0; diff: 0
DEBUG:overbridge.c:815:(run_j2o_midi): Event frames: 82; diff: 0
DEBUG:overbridge.c:815:(run_j2o_midi): Event frames: 53; diff: 0
DEBUG:overbridge.c:815:(run_j2o_midi): Event frames: 3; diff: 0
DEBUG:overbridge.c:815:(run_j2o_midi): Event frames: 58; diff: 0
DEBUG:overbridge.c:815:(run_j2o_midi): Event frames: 7; diff: 0
DEBUG:overbridge.c:815:(run_j2o_midi): Event frames: 31; diff: 0
DEBUG:overbridge.c:815:(run_j2o_midi): Event frames: 23; diff: 0
DEBUG:overbridge.c:815:(run_j2o_midi): Event frames: 0; diff: 0
DEBUG:overbridge.c:815:(run_j2o_midi): Event frames: 49; diff: 0
ERROR:overbridge.c:530:(prepare_cycle_out_midi): j2o: Error when submitting USB MIDI transfer: Resource busy
DEBUG:jclient.c:830:(jclient_run): Exiting...
Jack: JackClient::Deactivate
Jack: JackClient::ClientNotify ref = 6 name = Digitone notify = 12
Jack: JackClient::ClientNotify ref = 6 name = Digitone notify = 12
Jack: JackClient::ClientNotify ref = 6 name = Digitone notify = 12
Jack: JackClient::Deactivate res = 0
Jack: JackPosixThread::Kill
Jack: jack_client_close
Jack: JackClient::Close ref = 6
Jack: JackClient::Deactivate
Jack: JackSocketClientChannel::Stop
Jack: JackPosixThread::Kill
Jack: JackClientSocket::Close
Jack: JackClientSocket::Close
Jack: JackLibClient::~JackLibClient
Jack: JackShmReadWritePtr1::~JackShmReadWritePtr1 6
Jack: Succeeded in unlocking 426 byte memory area
Jack: JackLibGlobals Destroy a402d390
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 107341338 byte memory area
Jack: jack_client_close res = 0

Digitone Keys shows up as Digitone in GUI/Jack

I got a Digitone Keys to see if it can replace the Digitone and a MIDI keyboard.

The CLI is able to tell it apart from a Digitone:

$ overwitch-cli -l
0: Digitone (ID 1935:0014) at bus 001, address 020
1: Digitone Keys (ID 1935:001c) at bus 001, address 016

When I start overwitch both show up as Digitone. This is also true for the nodes created in Jack.
image
image

It is also the same if I just start an overwitch instance for the Digitone Keys alone:

$ overwitch-cli -n 1
$ lsusb | grep Elektron
Bus 001 Device 020: ID 1935:0014 Elektron Music Machines Elektron Digitone
Bus 001 Device 016: ID 1935:001c Elektron Music Machines Elektron Digitone Keys

This is with only the Digitone Keys plugged in:

$ overwitch-cli -n 0 -v                      
DEBUG:overwitch.c:303:(ow_get_device_desc_from_vid_pid): Failed to open file “/home/eon/.config/overwitch/devices.json”: No such file or directory
DEBUG:overwitch.c:309:(ow_get_device_desc_from_vid_pid): Falling back to /usr/local/share/overwitch/devices.json...
DEBUG:overwitch.c:368:(ow_get_device_desc_from_vid_pid): Device with PID 28 found
DEBUG:overwitch.c:229:(ow_get_usb_device_list): Found Digitone Keys (bus 001, address 016, ID 1935:001c)
DEBUG:overwitch.c:303:(ow_get_device_desc_from_vid_pid): Failed to open file “/home/eon/.config/overwitch/devices.json”: No such file or directory
DEBUG:overwitch.c:309:(ow_get_device_desc_from_vid_pid): Falling back to /usr/local/share/overwitch/devices.json...
DEBUG:overwitch.c:368:(ow_get_device_desc_from_vid_pid): Device with PID 28 found
DEBUG:engine.c:1280:(ow_engine_load_overbridge_name): USB control in data (32 B): Digitone
DEBUG:engine.c:1300:(ow_engine_load_overbridge_name): USB control in data (16 B): 0080       1.40A
DEBUG:resampler.c:539:(ow_resampler_set_buffer_size): resampler buffer size: 1024
DEBUG:resampler.c:552:(ow_resampler_set_samplerate): resampler sample rate: 48000

It looks like the Digitone Keys is reporting itself as Digitone.

Would it be possible to take the device name from the JSON file that contains the device descriptors?

Cannot build on Debian Bullseye

Hi there,
very interesting project. Unfortunately I'm not able to build it on my machine. When I follow the instructions all seems to work well until the make. Then it throws many (linking?-)errors at me and fails ultimately at:

/usr/bin/ld: /build/overwitch/src/overbridge.c:560: undefined reference to `jack_ringbuffer_free'
collect2: error: ld returned 1 exit status
make[2]: *** [Makefile:343: overwitch] Fehler 1

This is on Debian testing with all dependencies installed.

As I'm by no means a linux expert, any hint for me how to make this compile? Would love to try it out.

Decouple Overwitch from the JACK client

I'm considering forking your project and turning it into a recording/playback application for Android.

As far as I can tell, everything should work on Android, except for Jack (which is not really an issue).

I'm also thinking that before an Android port becomes possible, I'd have to implement a simple recording mode, where no Jack/PipeWire code is used.

As a start I would likely follow the structure of the current Jack implementation, but instead of sending the samples to Jack, I'd write them to disk as wav files.

When that is done, I could start testing on an Android device and eventually build a UI.

Whichever way the fork would go, I see a lot of potential for cooperating.

Maybe overwitch could be split into liboverwitch, overwitch-cli and overwitch-gui.

An eventual Android port could then use liboverwitch too, but that would require liboverwitch to be decoupled from Jack.

Another option is a complete fresh start, where I would study Overwitch and reimplement bits that are relevant for an Android port.

I'm just bouncing ideas at this point and I thought it would inquiry about future plans for the project.

A4MKII individual synth tracks not stereo?

So I just noticed that the individual tracks out as mono instead of stereo for Overwitch, so this renders the internal panning to not work. It does work when I plug into the individual out on the device.

Recording offsets for Overwitch vs. main JACK inputs

This is probably more of a support question, thanks for indulging me :)

I'm using Bitwig with JACK and Overwitch with a Syntakt, it works great but adds a latency of about 5ms when recording. I can fix this by setting the recording offset in Bitwig's Audio settings to 5ms / 240 samples, but then my other inputs from my main audio interface are recorded ahead as well.

This is probably something that needs to be supported in Bitwig, and I sent them an email asking if it would be possible to support individual recording offsets for different JACK input channels

But I was wondering how other people are dealing with this problem, maybe other DAWs handle this better?
I also reduced the USB buffer length in Overwatch from the default 24 to 8, this shortened the delay by 1-2ms but I guess it's not possible to eliminate entirely.

Maybe there's also a way to add recording offsets inside JACK? As in, if I could delay my main audio interface by 5ms then I could also use the 5ms recording offset in Bitwig, and both my main audio interface and the Syntakt should line up.

Timing issues with PipeWire

The issue seems to appear at random but it also happens when making JACK connections to Overwitch or any other client or hardware.

The clock drifts, and so the ratios, and the buffers get filled up with more data increasing the latency. This is more noticeable in the JACK to Overbridge side.

This is an example of Overwitch running.

$ overwitch -vv
[...]
Digitakt@001,010: o2p latency:  0,8 ms, max.  2,0 ms; p2o latency: -1,0 ms, max. -1,0 ms, o2p ratio: 0,999885, avg. 0,999886
Digitakt@001,010: o2p latency:  0,9 ms, max.  2,0 ms; p2o latency: -1,0 ms, max. -1,0 ms, o2p ratio: 0,999890, avg. 0,999888
Digitakt@001,010: o2p latency:  0,9 ms, max.  2,0 ms; p2o latency: -1,0 ms, max. -1,0 ms, o2p ratio: 0,999887, avg. 0,999889

Just when making a connection this happens (ratio drift).

Digitakt@001,010: o2p latency:  1,0 ms, max.  2,0 ms; p2o latency: -1,0 ms, max. -1,0 ms, o2p ratio: 1,000689, avg. 1,000174
Digitakt@001,010: o2p latency:  0,9 ms, max.  2,6 ms; p2o latency: -1,0 ms, max. -1,0 ms, o2p ratio: 1,001095, avg. 1,000895
Digitakt@001,010: o2p latency:  3,8 ms, max.  3,9 ms; p2o latency: -1,0 ms, max. -1,0 ms, o2p ratio: 1,001637, avg. 1,001503
Digitakt@001,010: o2p latency:  8,0 ms, max.  8,1 ms; p2o latency: -1,0 ms, max. -1,0 ms, o2p ratio: 1,000923, avg. 1,001297
Digitakt@001,010: o2p latency:  9,5 ms, max.  9,9 ms; p2o latency: -1,0 ms, max. -1,0 ms, o2p ratio: 1,000460, avg. 1,000660
Digitakt@001,010: o2p latency: 10,4 ms, max. 10,6 ms; p2o latency: -1,0 ms, max. -1,0 ms, o2p ratio: 1,000241, avg. 1,000340
Digitakt@001,010: o2p latency:  9,7 ms, max. 10,8 ms; p2o latency: -1,0 ms, max. -1,0 ms, o2p ratio: 1,000126, avg. 1,000175
Digitakt@001,010: o2p latency: 10,1 ms, max. 11,1 ms; p2o latency: -1,0 ms, max. -1,0 ms, o2p ratio: 1,000014, avg. 1,000075
Digitakt@001,010: o2p latency: 10,3 ms, max. 11,2 ms; p2o latency: -1,0 ms, max. -1,0 ms, o2p ratio: 0,999912, avg. 0,999958

After a few connections, the delays are unacceptable.

The issue appears when making connections from Ardour or qpwgraph. It doesn't make any difference if Ardour is up or down.

Sometimes, the ratios are not right from the start, meaning that I know that the o2p ratio in my device is around 0,999885 and being greater than 1.0 is a symptom that the clock will drift later.

$ pipewire --version
pipewire
Compiled with libpipewire 0.3.76
Linked with libpipewire 0.3.76

Segfault when running overwitch -l (Digitone)

Hi there, I've just compiled and installed the latest overwitch from the master branch (3a71a8d), and when I run overwitch -l after turning on my Digitone, I get a segfault. I'm including the stack trace and other relevant information.

OS: Ubuntu 20.04 running the latest Liquorix kernel (5.16.0-17.2-liquorix-amd64)
The Digitone is running the latest firmware, 1.32A.

dmesg output after turning on the Digitone:

[   76.785068] usb 3-1.1.4: new high-speed USB device number 7 using xhci_hcd
[   76.875361] usb 3-1.1.4: New USB device found, idVendor=1935, idProduct=1036, bcdDevice= 0.01
[   76.875366] usb 3-1.1.4: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[   76.875369] usb 3-1.1.4: Product: Elektron Digitone
[   76.875370] usb 3-1.1.4: Manufacturer: Elektron Music Machines
[   76.875371] usb 3-1.1.4: SerialNumber: 000000000001
overwitch -l
Segmentation fault (core dumped)
gdb --args /usr/local/bin/overwitch -l
(gdb) run
Starting program: /usr/local/bin/overwitch -l
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
[New Thread 0x7ffff762a700 (LWP 9897)]

Thread 1 "overwitch" received signal SIGSEGV, Segmentation fault.
0x000055555555c2be in ow_get_device_desc_from_vid_pid (vid=<optimized out>, device_desc=<optimized out>, pid=<optimized out>)
    at overwitch.c:200
200	      if ((*d)->pid == pid)
(gdb) bt
#0  0x000055555555c2be in ow_get_device_desc_from_vid_pid (vid=<optimized out>, device_desc=<optimized out>, 
    pid=<optimized out>) at overwitch.c:200
#1  ow_get_device_desc_from_vid_pid (device_desc=<synthetic pointer>, pid=4150, vid=6453) at overwitch.c:191
#2  ow_get_devices (devices=devices@entry=0x7fffffffd430, size=size@entry=0x7fffffffd428) at overwitch.c:167
#3  0x000055555555c6af in print_devices () at common.c:54
#4  0x0000555555557f3e in main (argc=2, argv=0x7fffffffd698) at main.c:241

Please let me know if I can provide any other useful information. And thank you for your work on this project!

MIDI not working on latest master

MIDI seems to have stopped working for me on latest master. I am seeing a lot of
ERROR:jclient.c:265:(jclient_j2o_midi): j2o: MIDI ring buffer overflow. Discarding data...
messages on the console

I did a bisect on the git repo and found the "bad commit" to be 5db0558

I am now running aa7528a.

Devices won't work if they are booted before the computer while being connected

I recently made a fresh install of my system with bullseye (coming from buster). I compiled latest master (after "make distclean"), but now overwitch-cli doesn't work for me (the gui version doesn't find my devices either).

$ overwitch-cli -l
0: Digitone (ID 1935:0014) at bus 003, address 014
1: Digitakt (ID 1935:000c) at bus 003, address 013

$ overwitch-cli -vvv -n 0
DEBUG:overwitch.c:206:(ow_get_devices): Found Digitone (bus 003, address 014, ID 1935:0014)
DEBUG:overwitch.c:206:(ow_get_devices): Found Digitakt (bus 003, address 013, ID 1935:000c)
ERROR:engine.c:708:(ow_engine_init_from_bus_address): Error while opening device: LIBUSB_SUCCESS / LIBUSB_TRANSFER_COMPLETED
ERROR:jclient.c:378:(jclient_init): Overwitch error: can't find a matching device

$ overwitch-cli -vvv -n 1
DEBUG:overwitch.c:206:(ow_get_devices): Found Digitone (bus 003, address 014, ID 1935:0014)
DEBUG:overwitch.c:206:(ow_get_devices): Found Digitakt (bus 003, address 013, ID 1935:000c)
ERROR:engine.c:708:(ow_engine_init_from_bus_address): Error while opening device: LIBUSB_SUCCESS / LIBUSB_TRANSFER_COMPLETED
ERROR:jclient.c:378:(jclient_init): Overwitch error: can't find a matching device

$ overwitch-cli -vvv -d Digitakt
DEBUG:overwitch.c:206:(ow_get_devices): Found Digitone (bus 003, address 014, ID 1935:0014)
DEBUG:overwitch.c:206:(ow_get_devices): Found Digitakt (bus 003, address 013, ID 1935:000c)
ERROR:engine.c:708:(ow_engine_init_from_bus_address): Error while opening device: LIBUSB_SUCCESS / LIBUSB_TRANSFER_COMPLETED
ERROR:jclient.c:378:(jclient_init): Overwitch error: can't find a matching device

$ overwitch-cli -vvv -d Digitone
DEBUG:overwitch.c:206:(ow_get_devices): Found Digitone (bus 003, address 014, ID 1935:0014)
DEBUG:overwitch.c:206:(ow_get_devices): Found Digitakt (bus 003, address 013, ID 1935:000c)
ERROR:engine.c:708:(ow_engine_init_from_bus_address): Error while opening device: LIBUSB_SUCCESS / LIBUSB_TRANSFER_COMPLETED
ERROR:jclient.c:378:(jclient_init): Overwitch error: can't find a matching device

Analog Heat +FX

Anything special need to be done in order to get this to work with Analog Heat +FX?

segmentation fault (core dumped)

This was discovered when implementing AH+FX whereby if I change inputs/outputs in my daw's (bitwig) settings I get the following output:

❯ overwitch
zsh: segmentation fault (core dumped)  overwitch

which kills overwitch.

As per @dagargo's suggestion, I used gdb to track where the issue was coming from and below are those findings:

Reading symbols from /usr/local/bin/overwitch...
(gdb) run
Starting program: /usr/local/bin/overwitch 
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
[New Thread 0x7ffff4bff640 (LWP 99373)]
[New Thread 0x7fffeffff640 (LWP 99374)]
[New Thread 0x7fffef7fe640 (LWP 99375)]
[Thread 0x7fffef7fe640 (LWP 99375) exited]
[New Thread 0x7fffef7fe640 (LWP 99376)]
[New Thread 0x7fffeeffd640 (LWP 99377)]
[Thread 0x7fffef7fe640 (LWP 99376) exited]
[New Thread 0x7fffef7fe640 (LWP 99378)]
[New Thread 0x7fffee7fc640 (LWP 99379)]
[Thread 0x7fffeeffd640 (LWP 99377) exited]
[Thread 0x7fffef7fe640 (LWP 99378) exited]
[Thread 0x7fffee7fc640 (LWP 99379) exited]
[New Thread 0x7fffee7fc640 (LWP 99380)]
[New Thread 0x7fffef7fe640 (LWP 99381)]
[New Thread 0x7fffeeffd640 (LWP 99382)]
[New Thread 0x7fffedf29640 (LWP 99384)]
[New Thread 0x7fffd61ff640 (LWP 99385)]
[Thread 0x7fffd61ff640 (LWP 99385) exited]
[New Thread 0x7fffd59fe640 (LWP 99387)]
[New Thread 0x7fffd61ff640 (LWP 99386)]
[Thread 0x7fffd59fe640 (LWP 99387) exited]
[Thread 0x7fffd61ff640 (LWP 99386) exited]
[New Thread 0x7fffd61ff640 (LWP 99388)]
[Thread 0x7fffd61ff640 (LWP 99388) exited]
[Thread 0x7fffedf29640 (LWP 99384) exited]
[New Thread 0x7fffedf29640 (LWP 99389)]
[Thread 0x7fffedf29640 (LWP 99389) exited]
[New Thread 0x7fffedf29640 (LWP 99391)]
[Thread 0x7fffeeffd640 (LWP 99382) exited]
[Thread 0x7fffee7fc640 (LWP 99380) exited]
[New Thread 0x7fffee7fc640 (LWP 99392)]
[New Thread 0x7fffeeffd640 (LWP 99393)]
[Thread 0x7fffeeffd640 (LWP 99393) exited]
[New Thread 0x7fffeeffd640 (LWP 99394)]
[New Thread 0x7fffd61ff640 (LWP 99395)]
[New Thread 0x7fffd59fe640 (LWP 99396)]
[New Thread 0x7fffd51fd640 (LWP 99397)]
[Thread 0x7fffef7fe640 (LWP 99381) exited]

Thread 24 "overwitch" received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7fffd51fd640 (LWP 99397)]
0x000055555555b702 in jclient_copy_o2j_audio (desc=0x55555565a4b0, buffer=0x7fffd51fc520, nframes=512, f=0x7fffd8034224) at jclient.c:283
283		  buffer[j][i] = *f;

edit: just to followup, i tried changing back and forth from main to fx outputs and overwitch wouldn't die immediately, but eventually (3-5th time?) it would die w/ the segmentation fault (core dumped) error; hope this helps.

Digitakt not reacting to Program Change messages

I am trying to send pc messages from my MPC One to my Digitakt, but it doesn't work.

The problem is that the current implementation seems to be wrong.

https://github.com/dagargo/overwitch/blob/master/src/jclient.c#L407-L430

If you add matching printf's to the code

diff --git a/src/jclient.c b/src/jclient.c
index beae4d6..0bcd6c6 100644
--- a/src/jclient.c
+++ b/src/jclient.c
@@ -419,6 +419,7 @@ jclient_j2o_midi (struct jclient *jclient, jack_nframes_t nframes)
       oevent.bytes[0] = 0;
       jack_midi_event_get (&jevent, midi_port_buf, i);
       status_byte = jevent.buffer[0];
+      printf ("jevent.size: %lu, 1st status_byte: %#x\n", jevent.size, status_byte);
 
       if (jevent.size == 1 && status_byte >= 0xf8 && status_byte <= 0xfc)
        {
@@ -427,6 +428,7 @@ jclient_j2o_midi (struct jclient *jclient, jack_nframes_t nframes)
        }
       else if (jevent.size == 3)
        {
+          printf ("2nd status_byte: %#x\n", status_byte);
          switch (status_byte & 0xf0)
            {
            case 0x80:          //Note-off
@@ -442,6 +444,7 @@ jclient_j2o_midi (struct jclient *jclient, jack_nframes_t nframes)
              oevent.bytes[0] = 0x0b;
              break;
            case 0xc0:          //Program Change
+             printf("Program Change received\n");
              oevent.bytes[0] = 0x0c;
              break;
            case 0xd0:          //Channel Pressure

you will see that program change is not a 3 byte message, but a two byte message.

jevent.size: 2, 1st status_byte: 0xc9
jevent.size: 2, 1st status_byte: 0xc9
jevent.size: 2, 1st status_byte: 0xc9
jevent.size: 2, 1st status_byte: 0xc9
jevent.size: 2, 1st status_byte: 0xc9

It is also defined as such [https://www.recordingblogs.com/wiki/midi-program-change-message]

Pipewire and midi

I recently installed pipewire and everything is working just fine with overwitch - except midi. Here's a screenshot from qpwgraph:
qpwgraph

The audio signals from Digitone and Syntakt are coming through just fine but it's impossible to send midi signals from my controller to one of the devices or from Digitone to Syntakt. I wanted to sync both devices via midi... If I connect Digitone and Syntakt via a standard midi cable everything is working as expected.

Am I overlooking something here? Do I need to configure some special midi stuff? I'm on Arch Linux and also tried to compile the newest version from git.

packaging problem (archlinux)

I'm trying to package overwitch for archlinux, but I'm facing an issue. For reference, this is the PKGBUILD. The important part is the package function.

# Maintainer: Thomas Girod <[email protected]>
pkgname=overwitch
pkgver=0.2
pkgrel=1
epoch=
pkgdesc="JACK client for Overbridge devices"
arch=('x86_64')
url="https://github.com/dagargo/overwitch"
#https://github.com/dagargo/overwitch/archive/refs/tags/0.2.tar.gz
license=('GPL')
groups=()
depends=('libusb' 'jack2' 'libsamplerate')
makedepends=('make' 'autoconf')
checkdepends=()
optdepends=()
provides=()
conflicts=()
replaces=()
backup=()
options=()
install=
changelog=
source=("https://github.com/dagargo/$pkgname/archive/refs/tags/$pkgver.tar.gz")
noextract=()
sha256sums=('51a50dac7c5ab4ff6fe0966144bbf9fd6f024130ecae59d7fa8f5b69d7531e5d')
validpgpkeys=()

prepare() {
	cd "$pkgname-$pkgver"
}

build() {
	cd "$pkgname-$pkgver"
	autoreconf --install
	./configure --prefix=/usr
	make
}

check() {
	cd "$pkgname-$pkgver"
}

package() {
	cd "$pkgname-$pkgver"
	make DESTDIR="$pkgdir/" install
}

When I run makepkg the build fails at the make install step with this error log:

Making install in src
make[1]: Entering directory '/home/tom/Build/overwitch/src/overwitch-0.2/src'
make[2]: Entering directory '/home/tom/Build/overwitch/src/overwitch-0.2/src'
 /usr/bin/mkdir -p '/home/tom/Build/overwitch/pkg/overwitch//usr/bin'
  /bin/sh ../libtool   --mode=install /usr/bin/install -c overwitch '/home/tom/Build/overwitch/pkg/overwitch//usr/bin'
libtool: install: /usr/bin/install -c overwitch /home/tom/Build/overwitch/pkg/overwitch//usr/bin/overwitch
make[2]: Nothing to be done for 'install-data-am'.
make[2]: Leaving directory '/home/tom/Build/overwitch/src/overwitch-0.2/src'
make[1]: Leaving directory '/home/tom/Build/overwitch/src/overwitch-0.2/src'
Making install in udev
make[1]: Entering directory '/home/tom/Build/overwitch/src/overwitch-0.2/udev'
make[2]: Entering directory '/home/tom/Build/overwitch/src/overwitch-0.2/udev'
make[2]: Nothing to be done for 'install-exec-am'.
 /usr/bin/mkdir -p '/home/tom/Build/overwitch/pkg/overwitch//etc/udev/hwdb.d'
 /usr/bin/install -c -m 644 20-usb-elektron.hwdb '/home/tom/Build/overwitch/pkg/overwitch//etc/udev/hwdb.d'
 /usr/bin/mkdir -p '/home/tom/Build/overwitch/pkg/overwitch//etc/udev/rules.d'
 /usr/bin/install -c -m 644 20-usb-elektron.rules '/home/tom/Build/overwitch/pkg/overwitch//etc/udev/rules.d'
make  install-data-hook
make[3]: Entering directory '/home/tom/Build/overwitch/src/overwitch-0.2/udev'
Failed to send reload request: Permission denied
make[3]: *** [Makefile:538: update-udev] Error 1
make[3]: Leaving directory '/home/tom/Build/overwitch/src/overwitch-0.2/udev'
make[2]: *** [Makefile:468: install-data-am] Error 2
make[2]: Leaving directory '/home/tom/Build/overwitch/src/overwitch-0.2/udev'
make[1]: *** [Makefile:422: install-am] Error 2
make[1]: Leaving directory '/home/tom/Build/overwitch/src/overwitch-0.2/udev'
make: *** [Makefile:406: install-recursive] Error 1

Apparently the make install step tries to access the udev daemon to inject new rules for overbridge capable devices. The problem is, when running inside a chroot to build a package, the build process does not have access to the system (outside of the packager, the program compiles and runs just fine).

If I understand correctly, overwitch's makefile should only copy the udev files to /usr/lib/udev/rules.d, and inform the user that udev rules has to be reloaded, or leaving that task to the package manager.

ENODEV undeclared - compilation error

Hi there, thanks again for the nice project!
I have been getting a recurring error when compiling on my Rapsberry Pi as follows:

overwitch.c:314:11: error: ‘ENODEV’ undeclared (first use in this function)

Its fixed by adding #include <errno.h> to overwitch.c but I didnt want to open a PR as I imagine that there must an error in my setup to have such a straightforward and blocking error?

Buffer overflow with Digitakt

Hi there, first off - thank you so much for this great piece of software and all the effort you put into this and the other stuff. Highly appreciated.

So, I just today got my Digitakt and naturally I needed to try overwitch out.
It detects my DT and I can easily connect it with carla to my soundcard.
Unfortunately I do have a lot of crackling. I tried different buffer and resample quality settings and even increased my jack buffer settings to up to 4096. But I never really managed to get rid of them.
My system is a 12 core Xeon Box (a bit older, but still ...) that is able to run Bitwig and dozens of u-he plugins at 256 buffer size without any crackling. I am a bit at a loss on what to try more...
System is running in performance mode, etc, etc. The box is already highly optimized for audio, as I also run Bitwig, Ardour, Mibus32C,...

Would be really grateful for any hints.

$ chrt -f 35 overwitch -b 24 -q 2 -d Digitakt -v -v
DEBUG:overbridge.c:527:(overbridge_init_priv): Checking for Digitakt...
Device: Digitakt (outputs: 12, inputs: 2)
Jack: JackClient::SetupDriverSync driver sem in flush mode
Jack: JackLinuxFutex::Connect name = jack_sem.1002_default_Digitakt
Jack: Clock source : system clock via clock_gettime
Jack: JackLibClient::Open name = Digitakt refnum = 13
JACK sample rate: 48000
JACK buffer size: 256
DEBUG:jclient.c:83:(jclient_init_buffer_size): Target delay: 11.5 ms (552 frames)
Jack: JackClient::PortRegister ref = 13 name = Digitakt:Main L type = 32 bit float mono audio port_index = 71
Jack: JackClient::PortRegister ref = 13 name = Digitakt:Main R type = 32 bit float mono audio port_index = 72
Jack: JackClient::PortRegister ref = 13 name = Digitakt:Track 1 type = 32 bit float mono audio port_index = 73
Jack: JackClient::PortRegister ref = 13 name = Digitakt:Track 2 type = 32 bit float mono audio port_index = 74
Jack: JackClient::PortRegister ref = 13 name = Digitakt:Track 3 type = 32 bit float mono audio port_index = 75
Jack: JackClient::PortRegister ref = 13 name = Digitakt:Track 4 type = 32 bit float mono audio port_index = 76
Jack: JackClient::PortRegister ref = 13 name = Digitakt:Track 5 type = 32 bit float mono audio port_index = 77
Jack: JackClient::PortRegister ref = 13 name = Digitakt:Track 6 type = 32 bit float mono audio port_index = 78
Jack: JackClient::PortRegister ref = 13 name = Digitakt:Track 7 type = 32 bit float mono audio port_index = 79
Jack: JackClient::PortRegister ref = 13 name = Digitakt:Track 8 type = 32 bit float mono audio port_index = 80
Jack: JackClient::PortRegister ref = 13 name = Digitakt:Input L type = 32 bit float mono audio port_index = 81
Jack: JackClient::PortRegister ref = 13 name = Digitakt:Input R type = 32 bit float mono audio port_index = 82
Jack: JackClient::PortRegister ref = 13 name = Digitakt:Main L Input type = 32 bit float mono audio port_index = 83
Jack: JackClient::PortRegister ref = 13 name = Digitakt:Main R Input type = 32 bit float mono audio port_index = 84
Jack: JackClient::PortRegister ref = 13 name = Digitakt:MIDI out type = 8 bit raw midi port_index = 85
Jack: JackClient::PortRegister ref = 13 name = Digitakt:MIDI in type = 8 bit raw midi port_index = 86
DEBUG:overbridge.c:759:(overbridge_run): Starting MIDI thread...
DEBUG:overbridge.c:767:(overbridge_run): Starting device thread...
Jack: JackClient::Activate
Jack: JackPosixThread::StartImp : create non RT thread
Jack: JackPosixThread::ThreadHandler : start
Jack: JackClient::kBufferSizeCallback buffer_size = 256
Jack: JackClient::Init : period = 5333 computation = 100 constraint = 5333
Jack: JackPosixThread::AcquireRealTimeImp priority = 5
DEBUG:jclient.c:109:(jclient_j2o_reader): j2o: Can not read data from queue
Jack: JackClient::ClientNotify ref = 13 name = Digitakt notify = 2
Jack: JackClient::kActivateClient name = Digitakt ref = 13
DEBUG:jclient.c:307:(jclient_compute_ratios): Starting up...
Jack: JackClient::ClientNotify ref = 13 name = Digitakt notify = 18
Jack: JackClient::ClientNotify ref = 13 name = Digitakt notify = 18
Jack: JackClient::ClientNotify ref = 13 name = Digitakt notify = 18
Jack: JackClient::ClientNotify ref = 13 name = Digitakt notify = 18
DEBUG:jclient.c:347:(jclient_compute_ratios): Max. latencies (ms): 0.0, 0.0; avg. ratios: 1.000079, 0.999921; curr. ratios: 0.999953, 1.000047
DEBUG:jclient.c:355:(jclient_compute_ratios): Tunning...
DEBUG:jclient.c:347:(jclient_compute_ratios): Max. latencies (ms): 0.0, 0.0; avg. ratios: 1.000026, 0.999974; curr. ratios: 0.999997, 1.000003
DEBUG:jclient.c:347:(jclient_compute_ratios): Max. latencies (ms): 0.0, 0.0; avg. ratios: 0.999966, 1.000034; curr. ratios: 0.999947, 1.000053
DEBUG:jclient.c:347:(jclient_compute_ratios): Max. latencies (ms): 0.0, 0.0; avg. ratios: 0.999944, 1.000056; curr. ratios: 0.999956, 1.000044
DEBUG:jclient.c:347:(jclient_compute_ratios): Max. latencies (ms): 0.0, 0.0; avg. ratios: 0.999969, 1.000031; curr. ratios: 0.999970, 1.000030
DEBUG:jclient.c:347:(jclient_compute_ratios): Max. latencies (ms): 0.0, 0.0; avg. ratios: 0.999969, 1.000031; curr. ratios: 0.999977, 1.000023
DEBUG:jclient.c:370:(jclient_compute_ratios): Running...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:overbridge.c:296:(set_usb_output_data_blks): j2o: Can not read enough data from ring buffer (0 < 1344). Resampling...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:overbridge.c:308:(set_usb_output_data_blks): j2o: Error while resampling: SRC ratio outside [1/256, 256] range.
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:347:(jclient_compute_ratios): Max. latencies (ms): 10.7, 15.5; avg. ratios: 0.999980, 1.000020; curr. ratios: 0.999980, 1.000020
ERROR:jclient.c:244:(jclient_j2o): j2o: Buffer overflow. Discarding data...
DEBUG:jclient.c:347:(jclient_compute_ratios): Max. latencies (ms): 10.7, 20.2; avg. ratios: 0.999984, 1.000016; curr. ratios: 0.999985, 1.000015
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
ERROR:jclient.c:244:(jclient_j2o): j2o: Buffer overflow. Discarding data...
DEBUG:jclient.c:347:(jclient_compute_ratios): Max. latencies (ms): 10.9, 20.4; avg. ratios: 0.999986, 1.000014; curr. ratios: 0.999998, 1.000002
ERROR:jclient.c:244:(jclient_j2o): j2o: Buffer overflow. Discarding data...
ERROR:jclient.c:244:(jclient_j2o): j2o: Buffer overflow. Discarding data...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:347:(jclient_compute_ratios): Max. latencies (ms): 10.9, 20.4; avg. ratios: 1.000032, 0.999968; curr. ratios: 1.000056, 0.999944
ERROR:jclient.c:244:(jclient_j2o): j2o: Buffer overflow. Discarding data...
DEBUG:jclient.c:347:(jclient_compute_ratios): Max. latencies (ms): 11.1, 21.0; avg. ratios: 1.000051, 0.999949; curr. ratios: 1.000036, 0.999964
ERROR:jclient.c:244:(jclient_j2o): j2o: Buffer overflow. Discarding data...
^CMax. latencies (ms): 11.3, 21.0
DEBUG:jclient.c:748:(jclient_run): Exiting...
Jack: JackClient::Deactivate
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
DEBUG:jclient.c:152:(jclient_o2j_reader): o2j: Can not read data from ring buffer. Replicating last sample...
Jack: JackClient::Deactivate res = 0
Jack: JackPosixThread::Kill
Jack: jack_client_close
Jack: JackClient::Close ref = 13
Jack: JackClient::Deactivate
Jack: JackSocketClientChannel::Stop
Jack: JackPosixThread::Kill
Jack: JackClientSocket::Close
Jack: JackClientSocket::Close
Jack: JackLibClient::~JackLibClient
Jack: JackShmReadWritePtr1::~JackShmReadWritePtr1 13
Jack: Succeeded in unlocking 426 byte memory area
Jack: JackLibGlobals Destroy 35c96bb0
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 107341338 byte memory area
Jack: jack_client_close res = 0

Setup issues

Hi,
I just moved to Linux so I'm still not fluent with compilation ~
I'm running on Pop OS (generally quite working with Debian builds).

I've try to follow the installation instructions, but these did not install jackd2. So I manualy run sudo apt install jackd2.

This was 1 step forward, as I got in the step where I can select yes for the real time priority. Let me know if I can submit a small PR to add this in the readme :)

But now I'm stuck at the ./configure part~

Here is the cmd response:

╰─❯ ./configure                                                                                                                                                                      ─╯
./configure: line 2125: LT_INIT: command not found
checking for gcc... gcc
checking whether the C compiler works... yes
checking for C compiler default output file name... a.out
checking for suffix of executables... 
checking whether we are cross compiling... no
checking for suffix of object files... o
checking whether we are using the GNU C compiler... yes
checking whether gcc accepts -g... yes
checking for gcc option to accept ISO C89... none needed
checking whether gcc understands -c and -o together... yes
checking for library containing sqrt... -lm
checking for a BSD-compatible install... /usr/bin/install -c
checking whether build environment is sane... yes
checking for a thread-safe mkdir -p... /usr/bin/mkdir -p
checking for gawk... no
checking for mawk... mawk
checking whether make sets $(MAKE)... yes
checking whether make supports the include directive... yes (GNU style)
checking whether make supports nested variables... yes
checking dependency style of gcc... gcc3
checking for gcc... (cached) gcc
checking whether we are using the GNU C compiler... (cached) yes
checking whether gcc accepts -g... (cached) yes
checking for gcc option to accept ISO C89... (cached) none needed
checking whether gcc understands -c and -o together... (cached) yes
checking for pkg-config... /home/linuxbrew/.linuxbrew/bin/pkg-config
checking pkg-config is at least version 0.9.0... yes
checking for libusb... no
checking for jack >= 0.100.0... no
configure: error: Package requirements (jack >= 0.100.0) were not met:

No package 'jack' found

Consider adjusting the PKG_CONFIG_PATH environment variable if you
installed software in a non-standard prefix.

Alternatively, you may set the environment variables JACK_CFLAGS
and JACK_LIBS to avoid the need to call pkg-config.
See the pkg-config man page for more details.

Do you have an idea on how I could make it work? :)

Thanks !! :)

Watch/autorun mode

I am wondering if there would be any interest for a watch/autorun mode which would essentially start an Overwitch client instance for every supported device that is connected.

This might not make much sense for Jack because most people would not have Jack running all the time on their computer, but for those who run PipeWire, it could be useful.

This would essentially make Overwitch devices behave the same way a regular USB sound card would when it comes to PipeWire: device connected -> device shows up in PipeWire.

Overwitch error: can't find a matching device

Hi there. Just a couple of weeks ago I had overwitch working with my Digitone on Ubuntu 20.04. I just recently performed a fresh Manjaro Linux install and I'm having issues getting it working again.

Using the latest current master build (f8e18a5), I get the following:

overwitch-cli -l
0: Digitone (ID 1935:0014) at bus 003, address 018

overwitch-cli -d Digitone
ERROR:engine.c:704:(ow_engine_init_from_bus_address): Error while opening device: LIBUSB_SUCCESS / LIBUSB_TRANSFER_COMPLETED
ERROR:jclient.c:394:(jclient_init): Overwitch error: can't find a matching device

My OS has libusb 1.0.25-3 and libusb-compat 0.1.7-1 installed. Let me know if there's anything more I can add to this report to make it more useful.

libusb_set_configuration fails on RPi

Hi there, thanks so much for the amazing work! Truly inspiring!
I am trying to run overwitch on my Raspberry Pi 4, the build and installation went smoothly and overbridge -l gives me the expected:

$ overwitch -l
Bus 001 Port 001:002 Device 006: ID 1935:000c Digitakt

But when trying to run it I get:

$ overwitch -d Digitakt -v -v
DEBUG:overbridge.c:534:(overbridge_init_priv): Checking for Digitakt...
Device: Digitakt (outputs: 12, inputs: 2)
ERROR:jclient.c:593:(jclient_run): USB error: can't set usb config

Any help is very welcome

The error seems to come from here

ret = libusb_set_configuration (ob->device, 1);

Ps: I should mention that I had already installed the alsa driver from here https://github.com/droelfdroelf/snd-digitakt, could this be interfering with overwitch? I tried to remove the module but I'm unsure that it worked.

Allow different gain for every track

The Digitakt tracks 1-8 are lower in volume than the main L-R.

Mains are in the range [1.0, -1.0] while tracks are approximately in the [0.25, -0.25] range regardless of the volume.

As Overbridge data is in [MAX_INT_32 - 1, -MAX_INT_32], the scaling code could easily accommodate this factor per output track.

Add support for MKI devices

I think Analog Heat MKI could work with the same configuration as the MKII because the number of tracks and the bit depth are the same (4x4 and 24 bits). We just need to replicate the configuration.

But for Analog Rytm MKI, Analog Four MKI and Analog Keys the amount of tracks is user configurable and so is the bit depth. So, without reverse engineering how those are configured, we can only give it a try for now.

Assuming the blocks have the same structure for 24 bits values, we need to know if the track and bit depth configuration is stored in the machines. If this is the case, we could set the tracks configuration to be 4 device outputs (better if we use here the 4 output tracks) and 2 device inputs (better if we use here the main output) using Overbridge and then use it on Overwitch.

If the Overbridge block structure is the same as in the Digitakt and we're using 24 bit values, we can define the Analog Keys MKI as follows.

static const struct overbridge_device_desc AKMK1_DESC = {
  .pid = AFMK1_PID,
  .name = "Analog Four MKI",
  .inputs = 2,
  .outputs = 4,
  .input_track_names = {"Main L", "Main R"}
  .output_track_names = {"Track 1", "Track 2", "Track 3", "Track 4"},
};

And add it to the OB_DEVICE_DESCS array.

If all the above constraints are fulfilled, it could work.

Audio not working or with huge glitches

I did not update for a long time, today I did.
I would not get audio at all or only after several minutes and then with hefty glitches.
I bisected the code and found e852feb to be the causing commit.

I confirmed by compiling latest master with this patch, and it worked for me again on both Digitone and Digitakt:

diff --git a/src/engine.c b/src/engine.c
index b283529..9add2de 100644
--- a/src/engine.c
+++ b/src/engine.c
@@ -37,7 +37,7 @@
 #define MIDI_OUT_EP 0x01
 #define MIDI_IN_EP  (MIDI_OUT_EP | 0x80)
 
-#define XFR_TIMEOUT 5
+#define XFR_TIMEOUT 0
 
 #define MIDI_BUF_EVENTS 64
 #define MIDI_BUF_LEN (MIDI_BUF_EVENTS * OB_MIDI_EVENT_SIZE)

Add a simple GUI

overwitch will be renamed to overwitch-cli and overwitch will become the GUI application and the preferred way to run Overwitch.

Syntakt support

I have one of them on it's way. I will do some testing once it is here.

Handle Jack buffer size changes

Hello!

I just got a Digitone and I tried it with overwitch on my system running PipeWire as the Jack server. It seems to work well except one thing: reacting to buffer size changes.

When I change the buffer size of a running Jack server, I get a ton of nasty sounds and a ton of these lines printed to the console:

ERROR:overbridge.c:255:(set_usb_input_data_blks): o2j: Audio ring buffer overflow. Discarding data...

I did some digging in the source code and I found that overwitch doesn't set a callback for buffer size changes.

I suppose that it is not that common that people change the buffer size of an already running Jack server but I suppose it can happen and it would be nice if overwitch could handle the situation gracefully.

Here is the specific callback that I am talking about: https://jackaudio.org/api/group__ClientCallbacks.html#ga030cc371acb19abe52861492acb960ad

Multiple WAVS?

I'm probably doing this wrong, but am I misunderstanding the purpose of this implementation of Overbridge? I installed this on my raspberry pi, I run the record command, and no matter how many tracks I have enabled, all I end up with is just one .wav file with the tracks mixed... isn't the huge benefit of overbridge that you can record each track on its own track (aka stems)?
Am I doing something wrong here?

Trying to add model:cycles

Hi. I tried to add the model cycles like this:

diff --git a/src/overbridge.c b/src/overbridge.c
index 36585be..f48f4d3 100644
--- a/src/overbridge.c
+++ b/src/overbridge.c
@@ -43,6 +43,7 @@
 #define ARMK2_PID 0x0010
 #define DTONE_PID 0x0014
 #define AHMK2_PID 0x0016
+#define MC_PID 0x001b
 #define DKEYS_PID 0x001c
 
 #define MAX_USB_DEPTH 7
@@ -142,9 +143,19 @@ static const struct overbridge_device_desc AHMK2_DESC = {
   .output_track_names = {"Main L", "Main R", "FX Return L", "FX Return R"}
 };
 
+static const struct overbridge_device_desc MC_DESC = {
+  .pid = MC_PID,
+  .name = "Model:Cycles",
+  .inputs = 2,
+  .outputs = 2,
+  .input_track_names =
+    {"Main L Input", "Main R Input"},
+  .output_track_names = {"Main L", "Main R"}
+};
+
 static const struct overbridge_device_desc OB_DEVICE_DESCS[] = {
   DIGITAKT_DESC, DIGITONE_DESC, AFMK2_DESC, ARMK2_DESC, DKEYS_DESC,
-  AHMK1_DESC, AHMK2_DESC
+  AHMK1_DESC, AHMK2_DESC, MC_DESC
 };
 
 static const int OB_DEVICE_DESCS_N =

I can list the device but I get this error:

[I] ➜ overwitch -d Model:Cycles -v
Device: Model:Cycles (outputs: 0, inputs: 2)
ERROR:jclient.c:575:(jclient_run): USB error: can't set usb config


[I] ➜ overwitch -d Model:Cycles -v
Device: Model:Cycles (outputs: 0, inputs: 2)
ERROR:jclient.c:575:(jclient_run): USB error: can't set usb config

Same as root. I'm not sure about the i/o counts or how to find them out.

MIDI buffer overflow

In my setup I use an 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...

Sound is still working (perfectly I might add). When I'm running two instances of Overwitch (one to Digitone, one to Digitakt), they seem to run in to the problem more or less simultaneously.

Support NixOS Stable

Wondering if anyone has integrated Overwitch into a NixOS build? Or, are there any plans to do so?

Would be lovely to have this in the Nix package repository. NixOS is fabulous for building stable realtime audio workstations.

Add input and output MIDI ports for the Overbridge message protocol

Perhaps it's useful for other people have access to what it looks like the internal Overbridge message protocol.

Audio and MIDI are already available thru their respective ports. What we are talking about here is the data needed to synchronize the Overbridge plugins with the devices such as knob position or active step.

The unknown bytes in the USB blocks can be easily arranged in blocks of 128 bytes. Here you see 2 consecutive blocks from my Digitakt while being stopped.

e0 00 23 aa e9 00 00 00  00 00 00 00 00 00 00 00
00 00 00 00 00 00 32 00  00 32 00 00 32 00 00 32
00 00 32 00 00 32 00 00  32 00 00 32 00 00 32 00
00 32 00 00 32 00 00 32  00 00 32 00 00 32 00 00
32 00 00 32 00 00 00 00  00 00 00 00 00 00 00 ef
00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00 

e0 00 23 aa ea 00 00 00  00 00 00 00 00 00 00 00
00 00 00 00 00 01 00 00  00 00 00 00 00 00 00 32
00 00 32 00 00 32 00 00  32 00 00 32 00 00 32 00
00 32 00 00 32 00 00 32  00 00 32 00 00 32 00 00
32 00 00 32 00 00 00 00  00 00 00 00 00 00 00 ef
00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00 

Looks like there is an e0 xx yy zz tt header, where xx yy zz tt is a 4 bytes counter.

Data is only 80 bytes long (ending with a ef) and the last 48 bytes are zeros.

You can print these values with this patch.

$ git diff
diff --git a/src/engine.c b/src/engine.c
index e972c71..c3a2c60 100644
--- a/src/engine.c
+++ b/src/engine.c
@@ -206,6 +206,10 @@ ow_engine_read_usb_input_blocks (struct ow_engine *engine)
        {
          error_print ("o2p: Unexpected block header\n");
        }
+      for (int w = 0; w < OB_PADDING_LEN; w++) {
+              printf("%02x ", blk->padding[w]);
+      }
+      printf("\n");
       s = blk->data;
       for (int j = 0; j < OB_FRAMES_PER_BLOCK; j++)
        {

It's not sure if this would be implemented as we need to know what's really going on under. But we can create a branch.

These two blocks are with the Digitakt playing.

e0 00 60 f7 c8 19 73 00  00 00 00 00 00 00 00 43
78 00 00 00 00 01 00 00  00 00 00 00 00 00 00 4f
00 00 4f 00 00 4f 00 00  4f 00 00 4f 00 00 4f 00
00 4f 00 00 4f 00 00 4f  00 00 4f 00 00 4f 00 00
4f 00 00 4f 00 00 00 d4  00 00 00 00 00 00 00 ef
00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00

e0 00 60 f7 c9 19 82 00  00 00 00 00 00 00 00 43
9f 00 00 00 00 00 50 00  00 50 00 00 50 00 00 50
00 00 50 00 00 50 00 00  50 00 00 50 00 00 50 00
00 50 00 00 50 00 00 50  00 00 50 00 00 50 00 00
50 00 00 50 00 00 00 d2  00 00 00 00 00 00 00 ef
00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00

error: 'cb_xfr_audio_in' undeclared on mki branch

I'm trying to make the mki branch and I get the following errors

make  all-recursive
make[1]: Entering directory '/home/user/dev/overwitch'
Making all in src
make[2]: Entering directory '/home/user/dev/overwitch/src'
gcc -DHAVE_CONFIG_H -I. -I..  -Wall -O3 -DDATADIR='"/usr/local/share/overwitch"' -DLOCALEDIR='"/
 -MT overwitch-main.o -MD -MP -MF .deps/overwitch-main.Tpo -c -o overwitch-main.o `test -f 'main
mv -f .deps/overwitch-main.Tpo .deps/overwitch-main.Po
gcc -DHAVE_CONFIG_H -I. -I..  -Wall -O3 -DDATADIR='"/usr/local/share/overwitch"' -DLOCALEDIR='"/
 -MT overwitch-jclient.o -MD -MP -MF .deps/overwitch-jclient.Tpo -c -o overwitch-jclient.o `test
mv -f .deps/overwitch-jclient.Tpo .deps/overwitch-jclient.Po
/bin/sh ../libtool  --tag=CC   --mode=compile gcc -DHAVE_CONFIG_H -I. -I..  -Wall -O3 -DDATADIR=
json-glib-1.0` -pthread  -I/usr/include/opus  -g -O2 -MT liboverwitch_la-engine.lo -MD -MP -MF .
libtool: compile:  gcc -DHAVE_CONFIG_H -I. -I.. -Wall -O3 -DDATADIR=\"/usr/local/share/overwitch
glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/sysprof-4 -I/usr/include/libmount -I/usr/inc
gine.Tpo -c engine.c  -fPIC -DPIC -o .libs/liboverwitch_la-engine.o
engine.c: In function 'prepare_transfers':
engine.c:77:29: error: 'cb_xfr_audio_in' undeclared (first use in this function)
   77 |                             cb_xfr_audio_in, engine, XFR_TIMEOUT);
      |                             ^~~~~~~~~~~~~~~
engine.c:77:29: note: each undeclared identifier is reported only once for each function it appe
engine.c:90:29: error: 'cb_xfr_audio_out' undeclared (first use in this function)
   90 |                             cb_xfr_audio_out, engine, XFR_TIMEOUT);
      |                             ^~~~~~~~~~~~~~~~
engine.c: At top level:
engine.c:1314:1: warning: 'ow_engine_load_overbridge_name' defined but not used [-Wunused-functi
 1314 | ow_engine_load_overbridge_name (struct ow_engine *engine)
      | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
engine.c:352:1: warning: 'cb_xfr_audio_out' defined but not used [-Wunused-function]
  352 | cb_xfr_audio_out (struct libusb_transfer *xfr)
      | ^~~~~~~~~~~~~~~~
engine.c:325:1: warning: 'cb_xfr_audio_in' defined but not used [-Wunused-function]
  325 | cb_xfr_audio_in (struct libusb_transfer *xfr)
      | ^~~~~~~~~~~~~~~
make[2]: *** [Makefile:629: liboverwitch_la-engine.lo] Error 1
make[2]: Leaving directory '/home/user/dev/overwitch/src'
make[1]: *** [Makefile:433: all-recursive] Error 1
make[1]: Leaving directory '/home/user/dev/overwitch'
make: *** [Makefile:365: all] Error 2

Gracefully handle when device is disconnected

Hello!

Overwitch should handle when a device is disconnected gracefully. Today it locks up and prints a lot of messages like this:

ERROR:jclient.c:214:(jclient_o2j): o2j: Unexpected frames with ratio -540517.047517 (output 0, expected 1024)

Feature request: multiple device startup support

Would it be possible to add a "--all-devices" or "-d all" flag, which would fork a jclient for any supported device found on the system? That would make service control via systemd a little bit more convenient.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.