flowblade icon indicating copy to clipboard operation
flowblade copied to clipboard

Add USB jog/shuttle support to Flowblade

Open ratherlargerobot opened this issue 3 years ago • 14 comments

Initially, the Contour Design family of jog/shuttle devices is supported. This includes the ShuttlePRO v2, and the ShuttleXpress. There are also quite a few rebranded devices that are basically the ShuttleXpress under another name. Those devices are likely to work as well. I have attempted to make the USB and driver code extensible, to make it easier to add additional devices in the future.

The USB implementation is handled by PyUSB, which in turn depends on libusb version 1. Flowblade connects directly to the configured USB device and uses its own userspace drivers to connect/disconnect, and handle input events.

All USB features are off by default. To turn them on, a user has to go to Edit -> Preferences -> Jog/Shuttle, and then enable it. On that window, a driver must also be selected.

The core drivers themselves are in the usbhiddrivers module. However, a res/usbhid/ file contains XML files that specify which lower-level driver to use within Flowblade, some USB connection settings, and also map keys on the device to events.

Flowblade already has great support for user-mappable keys from the keyboard. However, in order to allow a USB device to trigger specific actions when its keys are pressed, a new targetactions module was created. The USB HID driver config XML files use the same "code" action names that the existing keyboard shortcuts feature uses. Hopefully we can unify these systems more over time.

Users can also configure their own custom key mapping by copying and editing a USB HID driver config file in their own local user folder. For example, the flowblade-trunk/Flowblade/res/usbhid/foo.xml file could be copied into ~/.local/share/flowblade/user_usbhid/foo.xml, and edited to taste.

ratherlargerobot avatar Feb 20 '22 21:02 ratherlargerobot

By the way, I bought a Blackmagic Davinci Resolve Speed Editor USB control device, with the hopes of figuring out how to integrate it into Flowblade. That one looks like more of a challenge than the Contour Design ShuttleXpress, since it requires both USB input and output, and some sort of handshake to get the device to send input at all. Wish me luck!

ratherlargerobot avatar Feb 20 '22 21:02 ratherlargerobot

Good luck 😊And thanks for your effort on this. I'll be sure to check it out. RegardsStevenSent from my Huawei tablet-------- Original message --------From: Nathan Rosenquist @.>Date: Sun, 20 Feb 2022, 22:55To: jliljebl/flowblade @.>Cc: Subscribed @.***>Subject: Re: [jliljebl/flowblade] Add USB jog/shuttle support to Flowblade (PR #1052) By the way, I bought a Blackmagic Davinci Resolve Speed Editor USB control device, with the hopes of figuring out how to integrate it into Flowblade. That one looks like more of a challenge than the Contour Design ShuttleXpress, since it requires both USB input and output, and some sort of handshake to get the device to send input at all. Wish me luck!

—Reply to this email directly, view it on GitHub, or unsubscribe.Triage notifications on the go with GitHub Mobile for iOS or Android. You are receiving this because you are subscribed to this thread.Message ID: @.***>

dvdlvr avatar Feb 20 '22 22:02 dvdlvr

Oh! I almost forgot. You have to add a magic file to let the OS know that non-root users should be able to access the USB device.

On my system (Ubuntu 20.04), I added a file named /etc/udev/rules.d/90-flowblade.rules

The file has one line, with the following contents:

ATTRS{idVendor}=="0b33", ATTRS{idProduct}=="0020", MODE="0666"

You can add multiple lines to a file, one per device. Maybe we should publish one in some sort of example document?

Without this, Flowblade will not be able to access the device (unless you're running it as root, which is a bad idea obviously).

You can find the USB vendor ID and device ID using the lsusb command.

When I run lsusb on my system and the Contour Design ShuttleXpress is plugged in, it prints out (among other things), the following line:

Bus 001 Device 017: ID 0b33:0020 Contour Design, Inc. ShuttleXpress

That hex pair is the vendor ID : product ID.

lsusb -vd 0b33:0020 can then give you all sorts of other details about the device, which came in handy when developing the driver.

ratherlargerobot avatar Feb 21 '22 00:02 ratherlargerobot

@dvdlvr I noticed that you played a large role in the keyboard event mapping code in Flowblade. If you review this code, you will see that it introduces a targetactions module, which has a fair amount in common with the keyevent and shortcuts modules. If this pull request does get accepted, it seems like we might want to make an effort to unify the key mappable actions in some way that spans regular keyboards and USB devices. There are TODO comments in the new code in this pull request that should give you a good sense of it.

ratherlargerobot avatar Feb 21 '22 00:02 ratherlargerobot

Note that since the initial pull request a few days ago, I have made some major improvements to the USB subsystem.

The previous implementation of the USB HID subsystem used the pyusb library, in synchronous mode, which polled repeatedly for input.

This commit is a major refactoring of the USB subsystem, which brings several substantial improvements.

The pyusb dependency has been completely eliminated. Instead, USB connections are now implemented in terms of libusb 1.0, which was the underlying library that pyusb itself was using. The resulting code is a bit more verbose, but also provides a lot more control and flexibility. Most notably, the USB HID subsystem now performs asynchronous reads of the USB device, which is a major performance improvement. This was not possible with the pyusb library.

In the previous implementation, a GTK timeout handler was triggered every 5 milliseconds to perform a USB read, with a timeout of 1 millisecond. This actually worked reasonably well, but if you go look at the USB traffic with Wireshark, it was very chatty and was actually talking to the device that often.

In the current implementation, a GTK timeout handler is triggered every 10 milliseconds, which simply goes and checks whether any asynchronous USB transfers are ready to be read. This does not block or timeout, and happens instantly. Meanwhile, during setup, 10 USB transfers were set up to be in flight, being passed back and forth to send and receive messages, and events only occur when the device actually has new input to send. These transfers have no timeouts, so the chattiness is kept to a minimum. Having a queue with multiple transfers in flight also ensures that we capture every single update from the device, which improves the perception of update latency, and also improves reliability, especially with the shuttle.

Finally, the "endpoint_in" and "endpoint_out" XML tags in the USB HID driver config files now use the hex address of the endpoints, instead of numbers describing which endpoint it is counting from zero. The XML config files have been updated accordingly. Similarly, the "alternate" field has been removed, as libusb does not require that field, and neither do any of the devices we're likely to talk to.

ratherlargerobot avatar Feb 25 '22 06:02 ratherlargerobot

I have added a document that describes how to set up Flowblade for jog/shuttle support as part of this pull request: https://github.com/ratherlargerobot/flowblade/blob/jog-shuttle/flowblade-trunk/docs/JOG_SHUTTLE.md

ratherlargerobot avatar Feb 26 '22 05:02 ratherlargerobot

Not much to comment on due to my lack of experience with actual code, but maybe it would be worth mentioning in the main document, probably under interacting with the timeline section something along the lines of "Using Shuttle" or just "using external devices to edit" to allow for room for expansion, also probably could condense this better information wise

in both forward and reverse, and navigating frame by frame are right at your fingertips.

Turning the jog wheel to the right and left moves the playback location forward and backward, one frame at a time, respectively.

Turning the shuttle ring to the right starts out with playback in the forward direction, with increasingly faster speeds the farther you turn the shuttle.

Turning the shuttle ring to the left starts out with playback in the reverse direction, with increasingly faster speeds the farther you turn the shuttle.

Maybe this?

In both forwards and reverse, navigating frame by frame, right at your fingertips.

Turning the jog wheel to the right and left moves the playback forward and backward, one frame at a time respectively,

Turning the shuttle ring leftwards or rightwards starts playback in reverse or forward, and for faster or slower playback, turn the ring more in that direction.

Also I had a question for this function, so this would basically serve as a gradient on the speed of the playback, or will it basically be a remapped J, K, and L key function?

~~could have put all this in a pull request but I'm afk and GitHub on mobile is kinda annoying~~

Disaster2life avatar Feb 26 '22 07:02 Disaster2life

@Disaster2life that is a good suggestion, I'll condense that section a bit based on your feedback.

The shuttle provides a smooth gradient of speed for playback. It is not just remapped J/K/L keys.

With the Contour Design jog/shuttle devices currently supported, the shuttle gives us a total of 15 measurable positions, from -7 full reverse speed, through 0 stopped, to +7 full forward speed. Each available shuttle position is used, with a maximum of +-32x the speed of play at the extremes, to +- normal play speed right past zero on either side. The curve is very smooth, and in my opinion feels very natural and responsive.

ratherlargerobot avatar Feb 26 '22 07:02 ratherlargerobot

@ratherlargerobot ah thanks, also you might have accidentally removed a bit of the line since one frame a time. doesn't make sense, just a heads-up,

And the jog wheel seems like a super useful, think that's actually more than flowblade itself allows you to speed up/ go in reverse of I remember correctly, I was thinking of just getting a secondary keyboard and programming that to perform functions directly (read the idea I raised a while back to allow keyboards to do that) but yeah getting a compatible product might actually be way more useful

Disaster2life avatar Feb 26 '22 09:02 Disaster2life

@Disaster2life good catch! I gave the document one more round of proofreading.

And yes, you are correct, the shuttle implementation here does allow for more levels of speed in both directions than the J/K/L keys. I think the J/K/L keys are great the way they are. It's a balance between getting different speeds, and not pressing the keys too many times. It would be annoying to press the J or L key 7 times just to get it to go at its top speed. But with the shuttle, you just turn the ring about 60 degrees and you've gone through all 7 speeds on your way up to the fastest one.

I spent a fair amount of time during development just playing around with the jog/shuttle on a timeline, to make sure that the feel is just right.

ratherlargerobot avatar Feb 26 '22 20:02 ratherlargerobot

Just a reminder that the arrow keys have modifiers attached to them to increase speed with a factor which you can set yourself in preferences. Eg Shift right could go at 2x speed and Ctrl right at 3x speed, which means ShiftCtril right would go at 23= 6x speed. If I remember right this doesn't affect the jkl keys, but not entirely sure. I always use the arrow keys. Sent from my Huawei tablet-------- Original message --------From: Nathan Rosenquist @.>Date: Sat, 26 Feb 2022, 21:28To: jliljebl/flowblade @.>Cc: dvdlvr @.>, Mention @.*>Subject: Re: [jliljebl/flowblade] Add USB jog/shuttle support to Flowblade (PR #1052) @Disaster2life good catch! I gave the document one more round of proofreading. And yes, you are correct, the shuttle implementation here does allow for more levels of speed in both directions than the J/K/L keys. I think the J/K/L keys are great the way they are. It's a balance between getting different speeds, and not pressing the keys too many times. It would be annoying to press the J or L key 7 times just to get it to go at its top speed. But with the shuttle, you just turn the ring about 60 degrees and you've gone through all 7 speeds on your way up to the fastest one. I spent a fair amount of time during development just playing around with the jog/shuttle on a timeline, to make sure that the feel is just right.

—Reply to this email directly, view it on GitHub, or unsubscribe.Triage notifications on the go with GitHub Mobile for iOS or Android. You are receiving this because you were mentioned.Message ID: @.***>

dvdlvr avatar Feb 26 '22 20:02 dvdlvr

Since there seems to be a bit of interest in this topic, here is the map of shuttle positions to playback speeds in the Contour Design shuttle driver (extracted from the shuttle encoder value playback speed map in usbhiddrivers.py in the ContourDesignShuttle class):

Shuttle Position: Playback Speed (- is reverse, + is forward)

              -7: -32x
              -6: -16x
              -5: -8x
              -4: -5x
              -3: -3x
              -2: -1.8x
              -1: -1x
               0:  0 (stop)
              +1: +1x
              +2: +1.8x
              +3: +3x
              +4: +5x
              +5: +8x
              +6: +16x
              +7: +32x

ratherlargerobot avatar Feb 26 '22 20:02 ratherlargerobot

The Doc seems good now, nothing else I can catch, and yeah to me at least, the J,K, L keys are just rough movement tools on the timeline, having to press them several times before it actually allows you to, use them that way would defeat their purpose, but the shuttle definitely mixes the function of them and the arrow keys with the amount of control, and the curve you later mentioned is pretty good, personally don't see the function of a x32 factor, since at that point it might be better to just use the mouse and go back to whatever section, but that also involves moving your hand off of the shuttle so maybe?

An interesting idea for the shuttle could be allowing a modifier key + the wheel to have some actions? That could allow for some cool possibilities like skipping around the timeline on the basis of markers if that's useful?

Also totally didn't know about the modifiers to the arrow keys, thanks for informing me about that, probably would be useful in my usage

Disaster2life avatar Feb 27 '22 08:02 Disaster2life

I feel like a modifier key to change the jog/shuttle action might be more confusing than helpful. The jog/shuttle is a very well-established concept. To me, at least, making it modifiable feels like it might be adding complexity where simplicity is needed. At least on the Contour Design jog/shuttle devices.

ratherlargerobot avatar Feb 28 '22 06:02 ratherlargerobot

I'll look at this after 2.10.

jliljebl avatar Jun 01 '23 16:06 jliljebl

Thanks! And welcome back!

ratherlargerobot avatar Jun 01 '23 22:06 ratherlargerobot

Can this be reviewed or at least rebased for testing purposes?

luzpaz avatar Oct 31 '23 15:10 luzpaz

Ok, I'll do it merge on test branch first thing after 2.12. This has been unfortuinately left behind a bit I'll get to it soon.

jliljebl avatar Nov 12 '23 13:11 jliljebl

Ok, I pulled the PR as local branch usb-jog-feature and did the following:

  • merged with master
  • fixed the conflicts
  • fixed a circular imports problem, some added new imports in master obviously didn't work with import structure of the pull request
  • pushed the feature branch back to origin here

@ratherlargerobot can you test that the feature branch usb-jog-feature still works as intended?

jliljebl avatar Feb 06 '24 18:02 jliljebl

I plan to test this soon. It looks like I need to go through the mlt7 dependency transition on my computer first to get things running. I will try to get that working in the next few days.

Thank you!

ratherlargerobot avatar Feb 07 '24 04:02 ratherlargerobot

I tested this on Ubuntu 22.04.3 LTS using Xorg, and everything appears to work perfectly! Bravo!

Tested using a Contour ShuttleXpress: https://contourdesign.com/products/shuttle-xpress https://www.amazon.com/Contour-Design-Shuttle-Xpress-Multimedia-Controller/dp/B0001DBEKG

Thank you for merging this into the modern development branch. Much appreciated!

ratherlargerobot avatar Feb 07 '24 22:02 ratherlargerobot

Merged.

Thank you very much for this big development effort, and apologies on the delayed merge. Maybe I'll go out and by a USB control device myself now that we have the support these devices and the structure to add new ones.

The next release will come in about a months time (hopefully, the usual reservations apply), and this will be the headline feature. Thanks again for contributing and extending the capabilities of Flowblade.

jliljebl avatar Feb 08 '24 08:02 jliljebl

@ratherlargerobot I added the JOG_SHUTTLE.md file contents as section Jog / Shuttle Support in help docs chapter Advanced Editing Features. Thanks for providing the text, this will make using the feature and adding new devices much easier to users.

jliljebl avatar Feb 09 '24 08:02 jliljebl

The release and Flatpak is out now. @ratherlargerobot, if you could test the Flatpak sometime so we could get a confirmation that this works with the Flatpak.

jliljebl avatar Mar 29 '24 21:03 jliljebl

It appears that the Flatpak isn't working for me. However, I'm also not very familiar with Flatpak, so it's quite possible that I missed a step somewhere.

I appeared to already have the flatpak command installed on Ubuntu 22. I can't recall ever using it before directly.

I ran the following command:

flatpak install https://flathub.org/repo/appstream/io.github.jliljebl.Flowblade.flatpakref

which I found in the Flowblade install guide: https://github.com/jliljebl/flowblade/blob/master/flowblade-trunk/docs/INSTALLING.md

Here is what that looked like:

$ flatpak install https://flathub.org/repo/appstream/io.github.jliljebl.Flowblade.flatpakref
Required runtime for io.github.jliljebl.Flowblade/x86_64/stable (runtime/org.gnome.Platform/x86_64/45) found in remote flathub
Do you want to install it? [Y/n]: Y

io.github.jliljebl.Flowblade permissions:
    ipc                   pulseaudio            x11       devices
    file access [1]       dbus access [2]

    [1] host
    [2] org.freedesktop.Flatpak
        ID                                                Branch                 Op            Remote             Download
 1. [✓] io.github.jliljebl.Flowblade.Locale               stable                 i             flathub              8.9 kB / 6.2 MB
 2. [✓] org.freedesktop.LinuxAudio.Plugins.swh            23.08                  i             flathub              8.0 MB / 7.7 MB
 3. [✓] org.freedesktop.Platform.GL.default               23.08                  i             flathub            165.2 MB / 164.6 MB
 4. [✓] org.freedesktop.Platform.GL.default               23.08-extra            i             flathub             18.5 MB / 164.6 MB
 5. [✓] org.freedesktop.Platform.VAAPI.Intel              23.08                  i             flathub             13.3 MB / 13.4 MB
 6. [✓] org.freedesktop.Platform.openh264                 2.2.0                  u             flathub            614.3 kB / 944.3 kB
 7. [✓] org.gnome.Platform.Locale                         45                     i             flathub             18.1 kB / 369.6 MB
 8. [✓] org.gnome.Platform                                45                     i             flathub            368.3 MB / 378.2 MB
 9. [✓] io.github.jliljebl.Flowblade                      stable                 i             flathub             69.1 MB / 66.0 MB

Changes complete.

Then I ran the program:

flatpak run io.github.jliljebl.Flowblade

When I started it up, I had to enable jog/shuttle support in settings, and select Contour ShuttleXpress as the type of jog shuttle to use. Then, I had to stop the program, and start it again.

When I started it again, it all seemed to come up normally. However, the moment that I started moving the jog wheel, I got a notice in the terminal window where I launched it about a missing libusb shared library. Here is a snippet from that test, with much of the normal startup parts omitted for brevity:

...
MLT detection succeeded, 184 formats, 114 video codecs and 79 audio codecs found.
639 MLT services found.
Loading render profiles...
ffmpeg version 6.1.1 Copyright (c) 2000-2023 the FFmpeg developers
built with gcc 13.2.0 (GCC)
configuration: --prefix=/app --enable-gpl --disable-static --enable-shared --disable-doc --enable-libfontconfig --enable-libfreetype --enable-libopus --enable-librsvg --enable-libvpx --enable-libx264 --enable-libx265 --enable-libpulse --enable-libmp3lame --enable-libvorbis --enable-libaom --enable-vaapi --enable-ffnvcodec --enable-nvenc --enable-amf --enable-libzimg
libavutil      58. 29.100 / 58. 29.100
libavcodec     60. 31.102 / 60. 31.102
libavformat    60. 16.100 / 60. 16.100
libavdevice    60.  3.100 / 60.  3.100
libavfilter     9. 12.100 /  9. 12.100
libswscale      7.  5.100 /  7.  5.100
libswresample   4. 12.100 /  4. 12.100
libpostproc    57.  3.100 / 57.  3.100
['ffmpeg', '-version']
return code: 0
ffmpeg CLI available
Loading filters...
Loading transitions...
G'MIC found
Player initialized with profile:  HD 1080p 30 fps
Create SDL1 consumer...
Autosave started...
Saving project...
Initializing USB HID driver: Contour Design ShuttleXpress
Can not connect to USB HID device using driver config 'contour_design_shuttlexpress': 'Error connecting to USB HID device: libusb-1.0.so: cannot open shared object file: No such file or directory'
GPU test results {'NVENC H.264 High Profile / .mp4': -11, 'NVENC HEVC / .mp4': -11, 'NVENC HEVC HDR / .mp4': -11, 'VAAPI H.264 / .mp4': 0}

If I had to guess, maybe Flatpak has to find libusb within a Flatpak library, and not from the main OS, where libusb is already installed?

ratherlargerobot avatar Mar 29 '24 22:03 ratherlargerobot

If I had to guess, maybe Flatpak has to find libusb within a Flatpak library, and not from the main OS, where libusb is already installed?

Yeah, obviously. Somehow I thought this was part of the platform (the lib, not the bindings) and because it didn't crash on startup I thought that to be proven. Not true.

I added the needed line:

  - shared-modules/libusb/libusb.json

and pushed an update. Updates usually take about 6 hours to go live, I'll post here once libusb update seems to be available.

Then you can simply do:

flatpak update

and try again.

jliljebl avatar Mar 30 '24 07:03 jliljebl

Oh I forgot, you can pull the test version once the build completes, I'll post link to that here in about half an hour.

jliljebl avatar Mar 30 '24 07:03 jliljebl

Test build is ready. You can install it with:

flatpak install --user https://dl.flathub.org/build-repo/93677/io.github.jliljebl.Flowblade.flatpakref

This is now a "user" install, so need to run it with a flag:

flatpak run -u io.github.jliljebl.Flowblade

jliljebl avatar Mar 30 '24 07:03 jliljebl

I'll go merge the patch that might drop the test build. I'll comment once the new build is up.

jliljebl avatar Mar 30 '24 17:03 jliljebl

The build with libusb is live now and can be tested with re-install or updating existing install:

flatpak update

jliljebl avatar Mar 31 '24 06:03 jliljebl