Merge in upstream version 0.3 to Debian pkg

This commit is contained in:
2025-06-09 20:26:36 -05:00
27 changed files with 16121 additions and 177 deletions

View File

@@ -0,0 +1,56 @@
name: Build debian package
on:
release:
branches: '*'
types: [published]
env:
APP_NAME: alsa-scarlett-gui
APP_VERSION: ${{ github.event.release.tag_name }}
jobs:
build:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v3
- name: Install build dependencies
run: |
sudo apt -y update
sudo apt -y install git make gcc libgtk-4-dev libasound2-dev
- name: Build from sources
run: |
make -C src -j4 PREFIX=/usr
- name: Prepare package workspace
run: |
mkdir -p ${{ github.workspace }}/deb-workspace/usr/bin \
${{ github.workspace }}/deb-workspace/usr/share/applications \
${{ github.workspace }}/deb-workspace/usr/share/icons/hicolor/256x256/apps \
${{ github.workspace }}/deb-workspace/usr/share/doc/${{ env.APP_NAME }}-${{ env.APP_VERSION }}
cp src/alsa-scarlett-gui ${{ github.workspace }}/deb-workspace/usr/bin/
cp src/vu.b4.alsa-scarlett-gui.desktop ${{ github.workspace }}/deb-workspace/usr/share/applications/
cp src/img/alsa-scarlett-gui.png ${{ github.workspace }}/deb-workspace/usr/share/icons/hicolor/256x256/apps/
cp -r *.md img demo ${{ github.workspace }}/deb-workspace/usr/share/doc/${{ env.APP_NAME }}-${{ env.APP_VERSION }}/
- name: Build debian package
uses: jiro4989/build-deb-action@v2
with:
package: ${{ env.APP_NAME }}
package_root: ${{ github.workspace }}/deb-workspace
maintainer: geoffreybennett
version: ${{ env.APP_VERSION }}
desc: ${{ env.APP_NAME }} is a Gtk4 GUI for the ALSA controls presented by the Linux kernel Focusrite Scarlett Gen 2/3 Mixer Driver.
- name: Upload Release Asset
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ github.event.release.upload_url }}
asset_path: ./${{ env.APP_NAME }}_${{ env.APP_VERSION }}_amd64.deb
asset_name: ${{ env.APP_NAME }}_${{ env.APP_VERSION }}_amd64.deb
asset_content_type: application/vnd.debian.binary-package

View File

@@ -0,0 +1,37 @@
name: Build flatpak package
on:
release:
branches: '*'
types: [published]
env:
APP_NAME: alsa-scarlett-gui
APP_VERSION: ${{ github.event.release.tag_name }}
jobs:
flatpak:
name: "Flatpak"
runs-on: ubuntu-latest
container:
image: bilelmoussaoui/flatpak-github-actions:gnome-45
options: --privileged
steps:
- uses: actions/checkout@v4
- name: Build flatpak package
uses: flatpak/flatpak-github-actions/flatpak-builder@v6
with:
bundle: ${{ env.APP_NAME }}.flatpak
manifest-path: vu.b4.alsa-scarlett-gui.yml
cache-key: flatpak-builder-${{ github.sha }}
- name: Upload Release Asset
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ github.event.release.upload_url }}
asset_path: ./${{ env.APP_NAME }}.flatpak
asset_name: ${{ env.APP_NAME }}_${{ env.APP_VERSION }}.flatpak
asset_content_type: application/octet-stream

2
.gitignore vendored
View File

@@ -5,3 +5,5 @@
alsa-scarlett-gui alsa-scarlett-gui
alsa-scarlett-gui-resources.c alsa-scarlett-gui-resources.c
vu.b4.alsa-scarlett-gui.desktop vu.b4.alsa-scarlett-gui.desktop
.flatpak-builder/
flatpak-build/

158
INSTALL.md Normal file
View File

@@ -0,0 +1,158 @@
# ALSA Scarlett Gen 2/3 Control Panel Installation
## Prerequisites
Linux Kernel with the ALSA Scarlett2 Protocol Driver.
- Use at least version 5.14 for Scarlett Gen 3 support and bug fixes
for the Gen 2 support.
- For Clarett+ 8Pre support, you need 6.1.
- For the other Clarett USB and Clarett+ models, you need 6.7.
- For the level meters to work, you need 6.7.
If you don't have 6.7, you can get the driver from here and build it
for your current kernel:
https://github.com/geoffreybennett/scarlett-gen2/releases/tag/v6.5.11c1
## Enabling the Driver
As of Linux 6.7 the driver is enabled by default and you can skip this
section.
If you're running a kernel before 6.7, the driver needs to be enabled
at module load time with the `device_setup=1` option to
insmod/modprobe. Create a file /etc/modprobe.d/scarlett.conf
containing the appropriate line for your device:
Scarlett Gen 2:
- 6i6: `options snd_usb_audio vid=0x1235 pid=0x8203 device_setup=1`
- 18i8: `options snd_usb_audio vid=0x1235 pid=0x8204 device_setup=1`
- 18i20: `options snd_usb_audio vid=0x1235 pid=0x8201 device_setup=1`
Scarlett Gen 3:
- Solo: `options snd_usb_audio vid=0x1235 pid=0x8211 device_setup=1`
- 2i2: `options snd_usb_audio vid=0x1235 pid=0x8210 device_setup=1`
- 4i4: `options snd_usb_audio vid=0x1235 pid=0x8212 device_setup=1`
- 8i6: `options snd_usb_audio vid=0x1235 pid=0x8213 device_setup=1`
- 18i8: `options snd_usb_audio vid=0x1235 pid=0x8214 device_setup=1`
- 18i20: `options snd_usb_audio vid=0x1235 pid=0x8215 device_setup=1`
Clarett+:
- 8Pre: `options snd_usb_audio vid=0x1235 pid=0x820c device_setup=1`
Or you can use a sledgehammer:
```
options snd_usb_audio device_setup=1,1,1,1
```
to pass that option to the first 4 USB audio devices.
To see if the driver is present and enabled: `dmesg | grep -i -A 5 -B
5 focusrite` should display information like:
```
New USB device found, idVendor=1235, idProduct=8215, bcdDevice= 6.0b
Product: Scarlett 18i20 USB
Focusrite Scarlett Gen 2/3 Mixer Driver enabled pid=0x8215
```
If the driver is disabled youll see a message like:
```
Focusrite Scarlett Gen 2/3 Mixer Driver disabled; use options
snd_usb_audio vid=0x1235 pid=0x8215 device_setup=1 to enable and
report any issues to g@b4.vu",
```
## Building and Running
On Fedora, the packages `alsa-lib-devel` and `gtk4-devel` need to be
installed:
```
sudo dnf -y install alsa-lib-devel gtk4-devel
```
On Ubuntu 22.04:
```
sudo apt -y install git make gcc libgtk-4-dev libasound2-dev
```
To download from github:
```
git clone https://github.com/geoffreybennett/alsa-scarlett-gui
cd alsa-scarlett-gui
```
To build:
```
cd src
make -j4
```
To run:
```
./alsa-scarlett-gui
```
You can install it into `/usr/local` (binary, desktop file, and icon)
with:
```
sudo make install
```
And uninstall with:
```
sudo make uninstall
```
Continue on to reading [USAGE.md](USAGE.md) for usage information and
known issues.
## Flatpak
With Flatpak, in any distro:
```
flatpak-builder --user --install --force-clean flatpak-build \
vu.b4.alsa-scarlett-gui.yml
```
Be sure to use `flatpak-build` as the directory where the flatpak is
built or hence you risk bundling the artifacts when comitting!
If you get messages like these:
```
Failed to init: Unable to find sdk org.gnome.Sdk version 45
Failed to init: Unable to find runtime org.gnome.Platform version 45
```
Then install them:
```
flatpak install org.gnome.Sdk
flatpak install org.gnome.Platform
```
If you get:
```
Looking for matches…
error: No remote refs found for org.gnome.Sdk
```
Then:
```
flatpak remote-add --user --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo
```

View File

@@ -355,7 +355,7 @@ driver hides this from you.
- 19× Hardware Inputs - 19× Hardware Inputs
- Analogue 12: Mic/Line/Inst In 12 (Air, Pad) - Analogue 12: Mic/Line/Inst In 12 (Air, Pad)
- Analogue 38: Mic/Line In 34 (Air, Pad) - Analogue 38: Mic/Line In 38 (Air, Pad)
- Analogue 9: Talkback Mic - Analogue 9: Talkback Mic
- S/PDIF 12 - S/PDIF 12
- ADAT 18 - ADAT 18

View File

@@ -1,30 +1,35 @@
# ALSA Scarlett Gen 2/3 Control Panel (`alsa-scarlett-gui`) # ALSA Scarlett Gen 2/3 Control Panel (`alsa-scarlett-gui`)
`alsa-scarlett-gui` is a Gtk4 GUI for the ALSA controls presented by `alsa-scarlett-gui` is a Gtk4 GUI for the ALSA controls presented by
the Linux kernel Focusrite Scarlett Gen 2/3 Mixer Driver. the Linux kernel Focusrite Scarlett Gen 2/3/Clarett USB/Clarett+ Mixer
Driver.
## About ## About
<img src="src/img/alsa-scarlett-gui-logo.png" align="right"> <img src="src/img/alsa-scarlett-gui-logo.png" align="right">
The Focusrite Scarlett interfaces are class compliant USB audio The Focusrite USB audio interfaces are class compliant meaning that
interfaces meaning that they work “out of the box” on Linux as audio they work “out of the box” on Linux as audio and MIDI interfaces
and MIDI interfaces (although on Gen 3 you need to disable MSD mode (although on Gen 3/4 you need to disable MSD mode first for full
first). However, the Gen 2 6i6+ and Gen 3 4i4+ interfaces have a bunch functionality). However, except for some of the smallest models, they
of proprietary functionality that required a kernel driver to be have a bunch of proprietary functionality that required a kernel
written specifically for those devices. driver to be written specifically for those devices.
Linux kernel support (“ALSA Focusrite Scarlett Gen 2/3 Mixer Driver”) Linux kernel support (“ALSA Focusrite Scarlett Gen 2/3 Mixer Driver”)
for the proprietary functionality of Gen 2 devices was first added in for the proprietary functionality was first added in:
5.4 and Gen 3 devices in 5.14. - Scarlett Gen 2: Linux 5.4 (bugs fixed in Linux 5.14)
- Scarlett Gen 3: Linux 5.14
- Clarett+ 8Pre: Linux 6.1
- Clarett 2Pre/4Pre/8Pre USB, Clarett+ 2Pre/4Pre: Linux 6.7
Unfortunately, actually using this functionality was quite awful. The Unfortunately, actually using this functionality used to be quite an
existing applications like `alsamixer` and `qasmixer` become awful experience. The existing applications like `alsamixer` and
completely user-hostile with the hundreds of controls presented for `qasmixer` become completely user-hostile with the hundreds of
the Gen 3 18i20. Even the smallest Gen 3 4i4 interface at last count controls presented for the Gen 3 18i20. Even the smallest Gen 3 4i4
had 84 ALSA controls. interface at last count had 84 ALSA controls.
Announcing the ALSA Scarlett Gen 2/3 Control Panel! Announcing the ALSA Scarlett Gen 2/3 (and Clarett USB/Clarett+!)
Control Panel!
![Demonstration](img/demo.gif) ![Demonstration](img/demo.gif)
@@ -33,28 +38,43 @@ report a bug).
## Documentation ## Documentation
Refer to [USAGE.md](USAGE.md) for prerequisites, instructions, usage Refer to [INSTALL.md](INSTALL.md) for prerequisites, how to build,
information, and known issues. install, and run.
Refer to [USAGE.md](USAGE.md) for usage information and known issues.
## Donations ## Donations
This program is Free Software, developed using my personal resources, This program is Free Software, developed using my personal resources,
over hundreds of hours. Focusrite did not support the development of over hundreds of hours.
the driver or this control panel in any way. Thanks to Laurent
Debricon who got me started on the Gen 3 drivers by donating a 4i4.
If you like it, please consider a donation to say thank you as it was If you like this software, please consider a donation to say thank you
expensive to purchase one of each model for development and testing! as it was expensive to purchase one of each model for development and
Any donation is appreciated. testing! Any donation is appreciated.
- https://liberapay.com/gdb - https://liberapay.com/gdb
- https://paypal.me/gdbau - https://paypal.me/gdbau
Thank you! ## Scarlett Gen 4 Support
Focusrite recently released 3 new "Generation 4" interfaces: Solo,
2i2, and 4i4. Thanks to all the Linux Musicians who donated so I could
purchase one of each Gen 4 interface: https://gofund.me/ae997781,
support for these is coming soon.
The overwhelming response to the GoFundMe also got the attention of
Focusrite. They offered to send me any devices that I didn't already
have, and also said that for any future product releases, they will do
their utmost to send me devices in advance.
## Vocaster Support
Vocaster One and Two support will be coming once I've completed the
Scarlett 4th Gen support.
## License ## License
Copyright 2022 Geoffrey D. Bennett Copyright 2022-2023 Geoffrey D. Bennett
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -71,7 +91,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
## Disclaimer Third Parties ## Disclaimer Third Parties
Focusrite and Scarlett are trademarks or registered trademarks of Focusrite, Scarlett, Clarett, and Vocaster are trademarks or
Focusrite Audio Engineering Limited in England, USA, and/or other registered trademarks of Focusrite Audio Engineering Limited in
countries. Use of these trademarks does not imply any affiliation or England, USA, and/or other countries. Use of these trademarks does not
endorsement of this software. imply any affiliation or endorsement of this software.

117
USAGE.md
View File

@@ -1,95 +1,16 @@
# ALSA Scarlett Gen 2/3 Control Panel Usage # ALSA Scarlett Gen 2/3 Control Panel Usage
## Prerequisites Refer to [INSTALL.md](INSTALL.md) for prerequisites, how to build,
install, and run.
Linux Kernel with the ALSA Scarlett Gen 2/3 mixer driver. Use at least For usage instructions, read on...
version 5.14 for Scarlett Gen 3 support and bug fixes for the Gen 2
support.
As of Linux 5.17, the driver is still disabled by default and needs to
be enabled at module load time with the `device_setup=1` option to
insmod/modprobe. Create a file /etc/modprobe.d/scarlett.conf
containing the appropriate line for your device:
Gen 2:
- 6i6: `options snd_usb_audio vid=0x1235 pid=0x8203 device_setup=1`
- 18i8: `options snd_usb_audio vid=0x1235 pid=0x8204 device_setup=1`
- 18i20: `options snd_usb_audio vid=0x1235 pid=0x8201 device_setup=1`
Gen 3:
- Solo: `options snd_usb_audio vid=0x1235 pid=0x8211 device_setup=1`
- 2i2: `options snd_usb_audio vid=0x1235 pid=0x8210 device_setup=1`
- 4i4: `options snd_usb_audio vid=0x1235 pid=0x8212 device_setup=1`
- 8i6: `options snd_usb_audio vid=0x1235 pid=0x8213 device_setup=1`
- 18i8: `options snd_usb_audio vid=0x1235 pid=0x8214 device_setup=1`
- 18i20: `options snd_usb_audio vid=0x1235 pid=0x8215 device_setup=1`
Or you can use a sledgehammer:
```
options snd_usb_audio device_setup=1,1,1,1
```
to pass that option to the first 4 USB audio devices.
To see if the driver is present and enabled: `dmesg | grep -i -A 5 -B
5 scarlett` should display information like:
```
New USB device found, idVendor=1235, idProduct=8215, bcdDevice= 6.0b
Product: Scarlett 18i20 USB
Focusrite Scarlett Gen 2/3 Mixer Driver enabled pid=0x8215
```
If the driver is disabled youll see a message like:
```
Focusrite Scarlett Gen 2/3 Mixer Driver disabled; use options
snd_usb_audio vid=0x1235 pid=0x8215 device_setup=1 to enable and
report any issues to g@b4.vu",
```
## Building and Running
On Fedora, the packages `alsa-lib-devel` and `gtk4-devel` need to be
installed:
```
sudo dnf -y install alsa-lib-devel gtk4-devel
```
To build:
```
cd src
make -j4
```
To run:
```
./alsa-scarlett-gui
```
You can install it into `/usr/local` (binary, desktop file, and icon)
with:
```
sudo make install
```
And uninstall with:
```
sudo make uninstall
```
## No interface connected ## No interface connected
If no interface is detected (usually because there isnt one If no interface is detected (usually because there isnt one
connected!) youll see this window: connected!) youll see this window:
![MSD Mode](img/iface-none.png) ![No Interface Connected](img/iface-none.png)
Plug in an interface or select the menu option File → Interface Plug in an interface or select the menu option File → Interface
Simulation and load a demo file to make more interesting things Simulation and load a demo file to make more interesting things
@@ -125,11 +46,11 @@ The one control not accessible from the front panel is “Phantom Power
Persistence” (menu option View → Startup) which controls the Phantom Persistence” (menu option View → Startup) which controls the Phantom
Power state when the interface is powered on. Power state when the interface is powered on.
## Gen 2 6i6+ and Gen 3 4i4+ Interfaces ## Gen 2 6i6+, Gen 3 4i4+, Clarett USB, and Clarett+ Interfaces
The Gen 2 6i6+ and Gen 3 4i4+ interfaces have many controls available. The Gen 2 6i6+, Gen 3 4i4+, and Clarett interfaces have many controls
The controls are split between 4 windows, 3 of which are by default available. The controls are split between 4 windows, 3 of which are by
hidden. default hidden.
The main window has: The main window has:
- Global Controls - Global Controls
@@ -223,7 +144,7 @@ level/impedance. When plugging in microphones or line-level equipment
to the input, set it to “Line”. The “Inst” setting is for instrument to the input, set it to “Line”. The “Inst” setting is for instrument
with pickups such as guitars. with pickups such as guitars.
#### Air (Gen 3 only) #### Air (Gen 3, Clarett USB, and Clarett+ only)
Enabling Air will transform your recordings and inspire you while Enabling Air will transform your recordings and inspire you while
making music. making music.
@@ -250,7 +171,7 @@ configuration (menu option View → Startup).
### Analogue Output Controls ### Analogue Output Controls
The analogue output controls let you set the output volume (gain) on The analogue output controls let you set the output volume (gain) on
the analogue line out and headphones outputs. All interfaces support the analogue line out and headphone outputs. All interfaces support
setting the gain and muting individual channels. setting the gain and muting individual channels.
Click and drag up/down to change the volume, or use your mouse scroll Click and drag up/down to change the volume, or use your mouse scroll
@@ -272,7 +193,7 @@ channels are disabled.
There are “mute” and “dim” (reduce volume) buttons below the “HW” dial There are “mute” and “dim” (reduce volume) buttons below the “HW” dial
which affect only the outputs with “HW” control enabled. The Gen 3 which affect only the outputs with “HW” control enabled. The Gen 3
18i8 doesnt have physical buttons or indicator lights for these 18i8 doesnt have physical buttons or indicator lights for these
control, but the 18i20 devices do. controls, but the 18i20 devices do.
On the other (smaller) interfaces, the big volume knob on the front of On the other (smaller) interfaces, the big volume knob on the front of
the interface controls the volume of the Line 1 and 2 outputs. This is the interface controls the volume of the Line 1 and 2 outputs. This is
@@ -329,13 +250,13 @@ configuration:
#### Loopback #### Loopback
Gen 2 interfaces have as many PCM Inputs as Hardware Inputs. Gen 3 Gen 2, Clarett USB, and Clarett+ interfaces have as many PCM Inputs as
interfaces have two more PCM Inputs which the proprietary driver Hardware Inputs. Gen 3 interfaces have two more PCM Inputs which
restricts to being “Loopback” inputs. Focusrite Control uses as “Loopback” inputs.
The “Loopback” feature advertised for Gen 3 devices is actually a The “Loopback” feature advertised for Gen 3 devices is actually a
limitation of the propretary Focusrite Control software. Both Gen 2 limitation of the proprietary Focusrite Control software. All devices
and Gen 3 devices support full reassignment of the PCM Inputs, so you (except Solo/2i2) support full reassignment of the PCM Inputs, so you
can have any PCM Input as a “Loopback” or assigned to any other can have any PCM Input as a “Loopback” or assigned to any other
source. source.
@@ -351,7 +272,7 @@ to a PCM Input.
If you use the Routing window to connect Sources to Mixer Inputs and If you use the Routing window to connect Sources to Mixer Inputs and
Mixer Outputs to Destinations, then you can use the Mixer window to Mixer Outputs to Destinations, then you can use the Mixer window to
set the amount of each Mixer Input that is sent to each Mixer Output set the amount of each Mixer Input that is sent to each Mixer Output
using a matrix of controls. using a matrix of controls:
![Mixer Window](img/window-mixer.png) ![Mixer Window](img/window-mixer.png)
@@ -433,8 +354,8 @@ menu option File → Interface Simulation to load.
- Cant select (focus) the gain/volume controls or use a keyboard to - Cant select (focus) the gain/volume controls or use a keyboard to
adjust them. adjust them.
- Level (monitoring) doesnt work yet and is disabled (needs kernel - Level meters dont work if you're not running the driver from Linux
driver update). 6.7.
- Load/Save uses `alsactl` which will be confused if the ALSA - Load/Save uses `alsactl` which will be confused if the ALSA
interface name (e.g. `USB`) changes. interface name (e.g. `USB`) changes.

View File

@@ -30,4 +30,4 @@ cp demo/* $DOCDIR/demo
%doc /usr/share/doc/%{name}-%{version} %doc /usr/share/doc/%{name}-%{version}
/usr/bin/alsa-scarlett-gui /usr/bin/alsa-scarlett-gui
/usr/share/applications/vu.b4.alsa-scarlett-gui.desktop /usr/share/applications/vu.b4.alsa-scarlett-gui.desktop
/usr/share/icons/hicolor/256x256/apps/alsa-scarlett-gui.png /usr/share/icons/hicolor/256x256/apps/vu.b4.alsa-scarlett-gui.png

4147
demo/Clarett Plus 2Pre.state Normal file

File diff suppressed because it is too large Load Diff

5041
demo/Clarett Plus 4Pre.state Normal file

File diff suppressed because it is too large Load Diff

6455
demo/Clarett Plus 8Pre.state Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -10,6 +10,7 @@ DEPFLAGS = -MT $@ -MMD -MP -MF $(DEPDIR)/$*.d
CFLAGS := -Wall -Werror -ggdb -fno-omit-frame-pointer -O2 -D_FORTIFY_SOURCE=2 CFLAGS := -Wall -Werror -ggdb -fno-omit-frame-pointer -O2 -D_FORTIFY_SOURCE=2
CFLAGS += -DVERSION=\"$(VERSION)\" CFLAGS += -DVERSION=\"$(VERSION)\"
CFLAGS += -Wno-error=deprecated-declarations
PKG_CONFIG=pkg-config PKG_CONFIG=pkg-config
@@ -37,7 +38,9 @@ XML_OBJ := $(patsubst %.xml,%.c,$(XML_SRC))
SRCS := $(sort $(wildcard *.c) $(XML_OBJ)) SRCS := $(sort $(wildcard *.c) $(XML_OBJ))
OBJS := $(patsubst %.c,%.o,$(SRCS)) OBJS := $(patsubst %.c,%.o,$(SRCS))
TARGET := alsa-scarlett-gui TARGET := alsa-scarlett-gui
DESKTOP_FILE := vu.b4.$(TARGET).desktop DOMAIN_PREFIX := vu.b4
DESKTOP_FILE := $(DOMAIN_PREFIX).$(TARGET).desktop
ICON_FILE := $(DOMAIN_PREFIX).$(TARGET).png
GLIB_COMPILE_RESOURCES := $(shell $(PKG_CONFIG) --variable=glib_compile_resources gio-2.0) GLIB_COMPILE_RESOURCES := $(shell $(PKG_CONFIG) --variable=glib_compile_resources gio-2.0)
@@ -75,13 +78,13 @@ install: all
install -d $(BINDIR) install -d $(BINDIR)
install -m 755 $(TARGET) $(BINDIR) install -m 755 $(TARGET) $(BINDIR)
install -d $(ICONDIR) install -d $(ICONDIR)
install -m 644 img/$(TARGET).png $(ICONDIR) install -m 644 img/$(ICON_FILE) $(ICONDIR)
install -d $(DESKTOPDIR) install -d $(DESKTOPDIR)
install -m 644 $(DESKTOP_FILE) $(DESKTOPDIR) install -m 644 $(DESKTOP_FILE) $(DESKTOPDIR)
uninstall: uninstall:
rm -f $(BINDIR)/$(TARGET) rm -f $(BINDIR)/$(TARGET)
rm -f $(ICONDIR)/$(TARGET).png rm -f $(ICONDIR)/$(ICON_FILE)
rm -f $(DESKTOPDIR)/$(DESKTOP_FILE) rm -f $(DESKTOPDIR)/$(DESKTOP_FILE)
help: help:

View File

@@ -1,9 +1,11 @@
.route-label { .route-label {
font-size: smaller; font-size: smaller;
border-radius: 3px;
} }
.route-label:hover { .route-label:hover {
background: @theme_selected_bg_color; background: @theme_selected_bg_color;
outline: 2px solid @theme_selected_bg_color;
} }
.route-label:drop(active) { .route-label:drop(active) {

View File

@@ -505,7 +505,8 @@ void alsa_scan_cards(void) {
if (err < 0) if (err < 0)
goto next; goto next;
if (strncmp(snd_ctl_card_info_get_name(info), "Scarlett", 8) != 0) if (strncmp(snd_ctl_card_info_get_name(info), "Scarlett", 8) != 0 &&
strncmp(snd_ctl_card_info_get_name(info), "Clarett", 7) != 0)
goto next; goto next;
// is there already an entry for this card in alsa_cards? // is there already an entry for this card in alsa_cards?

View File

@@ -14,6 +14,7 @@ void show_error(GtkWindow *w, char *s) {
GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL, GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL,
GTK_MESSAGE_ERROR, GTK_MESSAGE_ERROR,
GTK_BUTTONS_CLOSE, GTK_BUTTONS_CLOSE,
"%s",
s s
); );
gtk_widget_show(dialog); gtk_widget_show(dialog);

View File

@@ -15,7 +15,7 @@ static void run_alsactl(
GtkWindow *w = GTK_WINDOW(card->window_main); GtkWindow *w = GTK_WINDOW(card->window_main);
gchar *argv[] = { gchar *argv[] = {
"alsactl", cmd, card->device, "-f", fn, NULL "/usr/sbin/alsactl", cmd, card->device, "-f", fn, NULL
}; };
gchar *stdout; gchar *stdout;
gchar *stderr; gchar *stderr;

View File

@@ -141,7 +141,19 @@ static void dial_measure(GtkWidget *widget,
static inline double calc_valp(double val, double mn, double mx) static inline double calc_valp(double val, double mn, double mx)
{ {
return (val - mn)/(mx-mn); if (val <= mn)
return 0.0;
if (val >= mx)
return 1.0;
// convert val from mn..mx to 0..1
val = (val - mn)/(mx-mn);
// 10^(val - 1) converts it to 0.1..1 with a nice curve
val = pow(10, val - 1);
// convert to 0..1 again
return (val - 0.1) / 0.9;
} }
static inline double calc_val(double valp, double mn, double mx) static inline double calc_val(double valp, double mn, double mx)

View File

@@ -155,9 +155,8 @@ static void create_input_controls(
) { ) {
GArray *elems = card->elems; GArray *elems = card->elems;
// there's consistently a pad capture for each analogue input that // find how many inputs have switches
// has a control int input_count = get_max_elem_by_name(elems, "Line", "Capture Switch");
int input_count = get_max_elem_by_name(elems, "Line", "Pad Capture Switch");
// Only the 18i20 Gen 2 has no input controls // Only the 18i20 Gen 2 has no input controls
if (!input_count) if (!input_count)

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

View File

@@ -125,7 +125,7 @@ GMenu *create_app_menu(GtkApplication *app) {
g_menu_append_submenu(menu, "_View", G_MENU_MODEL(view_menu)); g_menu_append_submenu(menu, "_View", G_MENU_MODEL(view_menu));
g_menu_append(view_menu, "_Routing", "win.routing"); g_menu_append(view_menu, "_Routing", "win.routing");
g_menu_append(view_menu, "_Mixer", "win.mixer"); g_menu_append(view_menu, "_Mixer", "win.mixer");
//g_menu_append(view_menu, "_Levels", "win.levels"); g_menu_append(view_menu, "_Levels", "win.levels");
g_menu_append(view_menu, "_Startup", "win.startup"); g_menu_append(view_menu, "_Startup", "win.startup");
GMenu *help_menu = g_menu_new(); GMenu *help_menu = g_menu_new();

View File

@@ -17,37 +17,55 @@ static void choose_line_colour(
double *g, double *g,
double *b double *b
) { ) {
int odd_in = r_src->lr_num & 1; // left channels have odd numbers
int odd_out = r_dst->elem->lr_num & 1; // right channels have even numbers
int in2 = ((r_src->lr_num - 1) / 2 & 1); int odd_src = r_src->lr_num & 1;
int out2 = ((r_dst->elem->lr_num - 1) / 2 & 1); int odd_dst = r_dst->elem->lr_num & 1;
if (odd_in && odd_out) { // for colouring, pair channels up
// 0 for odd pairs, 1 for even pairs
int src2 = ((r_src->lr_num - 1) / 2 & 1);
int dst2 = ((r_dst->elem->lr_num - 1) / 2 & 1);
// left -> left, black
if (odd_src && odd_dst) {
*r = 0; *r = 0;
*g = 0; *g = 0;
*b = 0; *b = 0;
} else if (!odd_in && !odd_out) {
// right -> right, red
} else if (!odd_src && !odd_dst) {
*r = 1; *r = 1;
*g = 0; *g = 0;
*b = 0; *b = 0;
} else if (odd_in) {
// left -> right, dark green
} else if (odd_src) {
*r = 0; *r = 0;
*g = 0.25; *g = 0.25;
*b = 0; *b = 0;
// right -> left, dark brown/olive
} else { } else {
*r = 0.25; *r = 0.25;
*g = 0.25; *g = 0.25;
*b = 0; *b = 0;
} }
// mix <-> non-mix, add blue
if ((r_src->port_category == PC_MIX) != if ((r_src->port_category == PC_MIX) !=
(r_dst->port_category == PC_MIX)) { (r_dst->port_category == PC_MIX)) {
*b = 0.5; *b = 0.5;
} }
if (in2) {
// even input pairs, lighten red and green components
if (src2) {
*r = (*r + 1) / 2; *r = (*r + 1) / 2;
*g = (*g + 1) / 2; *g = (*g + 1) / 2;
} }
if (out2) {
// even output pairs, lighten blue component
if (dst2) {
*b = (*b + 1) / 2; *b = (*b + 1) / 2;
} }
} }

View File

@@ -1,9 +1,7 @@
[Desktop Entry] [Desktop Entry]
Encoding=UTF-8
Value=1.5
Type=Application Type=Application
Name=ALSA Scarlett Gen 2/3 Control Panel Name=ALSA Scarlett Gen 2/3 Control Panel
Icon=alsa-scarlett-gui Icon=vu.b4.alsa-scarlett-gui
Exec=PREFIX/bin/alsa-scarlett-gui Exec=PREFIX/bin/alsa-scarlett-gui
Categories=GTK;AudioVideo;Audio;Mixer; Categories=GTK;AudioVideo;Audio;Mixer;
Keywords=focusrite;

View File

@@ -9,6 +9,18 @@ static void button_clicked(GtkWidget *widget, struct alsa_elem *elem) {
alsa_set_elem_value(elem, value); alsa_set_elem_value(elem, value);
} }
static void toggle_button_set_text(struct alsa_elem *elem, const char *text) {
if (!text)
return;
if (*text == '*') {
GtkWidget *icon = gtk_image_new_from_icon_name(text + 1);
gtk_button_set_child(GTK_BUTTON(elem->widget), icon);
} else {
gtk_button_set_label(GTK_BUTTON(elem->widget), text);
}
}
static void toggle_button_updated(struct alsa_elem *elem) { static void toggle_button_updated(struct alsa_elem *elem) {
int is_writable = alsa_get_elem_writable(elem); int is_writable = alsa_get_elem_writable(elem);
gtk_widget_set_sensitive(elem->widget, is_writable); gtk_widget_set_sensitive(elem->widget, is_writable);
@@ -16,17 +28,7 @@ static void toggle_button_updated(struct alsa_elem *elem) {
int value = alsa_get_elem_value(elem); int value = alsa_get_elem_value(elem);
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(elem->widget), value); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(elem->widget), value);
const char *text = elem->bool_text[value]; toggle_button_set_text(elem, elem->bool_text[value]);
if (text) {
if (*text == '*') {
GtkWidget *icon = gtk_image_new_from_icon_name(text + 1);
gtk_button_set_child(GTK_BUTTON(elem->widget), icon);
} else {
gtk_button_set_label(
GTK_BUTTON(elem->widget), elem->bool_text[value]
);
}
}
} }
GtkWidget *make_boolean_alsa_elem( GtkWidget *make_boolean_alsa_elem(
@@ -44,6 +46,24 @@ GtkWidget *make_boolean_alsa_elem(
elem->bool_text[0] = disabled_text; elem->bool_text[0] = disabled_text;
elem->bool_text[1] = enabled_text; elem->bool_text[1] = enabled_text;
// find the maximum width and height of both possible labels
int max_width = 0, max_height = 0;
for (int i = 0; i < 2; i++) {
toggle_button_set_text(elem, elem->bool_text[i]);
GtkRequisition *size = gtk_requisition_new();
gtk_widget_get_preferred_size(button, size, NULL);
if (size->width > max_width)
max_width = size->width;
if (size->height > max_height)
max_height = size->height;
}
// set the widget minimum size to the maximum label size so that the
// widget doesn't change size when the label changes
gtk_widget_set_size_request(button, max_width, max_height);
toggle_button_updated(elem); toggle_button_updated(elem);
return button; return button;

View File

@@ -24,7 +24,17 @@ static int update_levels_controls(void *user_data) {
// go through the ports in that category // go through the ports in that category
for (int j = 0; j < card->routing_out_count[i]; j++) { for (int j = 0; j < card->routing_out_count[i]; j++) {
GtkWidget *meter = card->meters[meter_num]; GtkWidget *meter = card->meters[meter_num];
gtk_dial_set_value(GTK_DIAL(meter), values[meter_num]); double value = 20 * log10(values[meter_num] / 4095.0);
int int_value;
if (value < -80)
int_value = -80;
else if (value > 0)
int_value = 0;
else
int_value = round(value);
gtk_dial_set_value(GTK_DIAL(meter), int_value);
meter_num++; meter_num++;
} }
} }
@@ -93,7 +103,7 @@ GtkWidget *create_levels_controls(struct alsa_card *card) {
count_labels[j] = add_count_label(grid, j); count_labels[j] = add_count_label(grid, j);
// create the meter widget and attach to the grid // create the meter widget and attach to the grid
GtkWidget *meter = gtk_dial_new_with_range(0, 4096, 1); GtkWidget *meter = gtk_dial_new_with_range(-80, 0, 1);
card->meters[meter_num++] = meter; card->meters[meter_num++] = meter;
gtk_grid_attach(GTK_GRID(grid), meter, j + 1, i + 1, 1, 1); gtk_grid_attach(GTK_GRID(grid), meter, j + 1, i + 1, 1, 1);
} }

View File

@@ -107,8 +107,9 @@ static void get_routing_dsts(struct alsa_card *card) {
assert(j == count); assert(j == count);
} }
static void routing_grid_label(char *s, GtkGrid *g) { static void routing_grid_label(char *s, GtkGrid *g, GtkAlign align) {
GtkWidget *l = gtk_label_new(s); GtkWidget *l = gtk_label_new(s);
gtk_widget_set_halign(l, align);
gtk_grid_attach(g, l, 0, 0, 1, 1); gtk_grid_attach(g, l, 0, 0, 1, 1);
} }
@@ -301,16 +302,16 @@ static void create_routing_grid(struct alsa_card *card) {
gtk_widget_set_hexpand(card->routing_mixer_in_grid, TRUE); gtk_widget_set_hexpand(card->routing_mixer_in_grid, TRUE);
gtk_widget_set_hexpand(card->routing_mixer_out_grid, TRUE); gtk_widget_set_hexpand(card->routing_mixer_out_grid, TRUE);
gtk_widget_set_align( gtk_widget_set_align(
card->routing_hw_in_grid, GTK_ALIGN_END, GTK_ALIGN_CENTER card->routing_hw_in_grid, GTK_ALIGN_FILL, GTK_ALIGN_CENTER
); );
gtk_widget_set_align( gtk_widget_set_align(
card->routing_pcm_in_grid, GTK_ALIGN_END, GTK_ALIGN_CENTER card->routing_pcm_in_grid, GTK_ALIGN_FILL, GTK_ALIGN_CENTER
); );
gtk_widget_set_align( gtk_widget_set_align(
card->routing_hw_out_grid, GTK_ALIGN_START, GTK_ALIGN_CENTER card->routing_hw_out_grid, GTK_ALIGN_FILL, GTK_ALIGN_CENTER
); );
gtk_widget_set_align( gtk_widget_set_align(
card->routing_pcm_out_grid, GTK_ALIGN_START, GTK_ALIGN_CENTER card->routing_pcm_out_grid, GTK_ALIGN_FILL, GTK_ALIGN_CENTER
); );
gtk_widget_set_align( gtk_widget_set_align(
card->routing_mixer_in_grid, GTK_ALIGN_CENTER, GTK_ALIGN_END card->routing_mixer_in_grid, GTK_ALIGN_CENTER, GTK_ALIGN_END
@@ -319,10 +320,18 @@ static void create_routing_grid(struct alsa_card *card) {
card->routing_mixer_out_grid, GTK_ALIGN_CENTER, GTK_ALIGN_START card->routing_mixer_out_grid, GTK_ALIGN_CENTER, GTK_ALIGN_START
); );
routing_grid_label("Hardware Inputs", GTK_GRID(card->routing_hw_in_grid)); routing_grid_label(
routing_grid_label("Hardware Outputs", GTK_GRID(card->routing_hw_out_grid)); "Hardware Inputs", GTK_GRID(card->routing_hw_in_grid), GTK_ALIGN_END
routing_grid_label("PCM Outputs", GTK_GRID(card->routing_pcm_in_grid)); );
routing_grid_label("PCM Inputs", GTK_GRID(card->routing_pcm_out_grid)); routing_grid_label(
"Hardware Outputs", GTK_GRID(card->routing_hw_out_grid), GTK_ALIGN_START
);
routing_grid_label(
"PCM Outputs", GTK_GRID(card->routing_pcm_in_grid), GTK_ALIGN_END
);
routing_grid_label(
"PCM Inputs", GTK_GRID(card->routing_pcm_out_grid), GTK_ALIGN_START
);
GtkWidget *src_label = gtk_label_new("\nSources →"); GtkWidget *src_label = gtk_label_new("\nSources →");
gtk_label_set_justify(GTK_LABEL(src_label), GTK_JUSTIFY_CENTER); gtk_label_set_justify(GTK_LABEL(src_label), GTK_JUSTIFY_CENTER);
@@ -645,11 +654,17 @@ static void make_src_routing_widget(
GtkWidget *label = gtk_label_new(name); GtkWidget *label = gtk_label_new(name);
gtk_box_append(GTK_BOX(box), label); gtk_box_append(GTK_BOX(box), label);
gtk_widget_add_class(box, "route-label"); gtk_widget_add_class(box, "route-label");
if (orientation == GTK_ORIENTATION_HORIZONTAL) {
gtk_widget_set_halign(label, GTK_ALIGN_END);
gtk_widget_set_hexpand(label, TRUE);
}
} }
if (orientation == GTK_ORIENTATION_HORIZONTAL) { if (orientation == GTK_ORIENTATION_HORIZONTAL) {
gtk_box_append(GTK_BOX(box), socket); gtk_box_append(GTK_BOX(box), socket);
gtk_widget_set_halign(box, GTK_ALIGN_END); gtk_widget_set_halign(box, GTK_ALIGN_FILL);
gtk_widget_set_hexpand(box, TRUE);
} else { } else {
gtk_box_prepend(GTK_BOX(box), socket); gtk_box_prepend(GTK_BOX(box), socket);
gtk_widget_set_margin_start(box, 5); gtk_widget_set_margin_start(box, 5);
@@ -703,7 +718,10 @@ static void make_dst_routing_widget(
gtk_widget_set_margin_end(box, 5); gtk_widget_set_margin_end(box, 5);
} else { } else {
gtk_box_prepend(GTK_BOX(box), socket); gtk_box_prepend(GTK_BOX(box), socket);
gtk_widget_set_halign(box, GTK_ALIGN_START); gtk_widget_set_halign(box, GTK_ALIGN_FILL);
gtk_widget_set_hexpand(box, TRUE);
gtk_widget_set_hexpand(label, TRUE);
gtk_widget_set_halign(label, GTK_ALIGN_START);
} }
// handle clicks on the box // handle clicks on the box

View File

@@ -86,7 +86,7 @@ static void add_phantom_persistence_control(
GtkWidget *w; GtkWidget *w;
w = small_label("Phantom Power Persistance"); w = small_label("Phantom Power Persistence");
gtk_grid_attach(GTK_GRID(grid), w, 0, *grid_y, 1, 1); gtk_grid_attach(GTK_GRID(grid), w, 0, *grid_y, 1, 1);
w = make_boolean_alsa_elem(phantom, "Disabled", "Enabled"); w = make_boolean_alsa_elem(phantom, "Disabled", "Enabled");

View File

@@ -0,0 +1,25 @@
app-id: vu.b4.alsa-scarlett-gui
runtime: org.gnome.Platform
runtime-version: "45"
sdk: org.gnome.Sdk
command: alsa-scarlett-gui
finish-args:
# X11 + XShm access
- --share=ipc
- --socket=fallback-x11
# Wayland access
- --socket=wayland
# Needs access to ALSA device nodes:
- --device=all
modules:
- name: alsa-scarlett-gui
buildsystem: simple
build-commands:
- make install PREFIX=$FLATPAK_DEST
sources:
- type: dir
path: ./src
# Use the following and remove the above for Flathub publishing
# - type: git
# url: https://github.com/geoffreybennett/alsa-scarlett-gui.git
# tag: "0.2"