243 Commits
0.3.3 ... deb

Author SHA1 Message Date
921944e64e Replace README with a project sunsetting notice 2025-09-08 15:33:10 -05:00
9e00217cec Update changelog for 0.5.1-1 release 2025-06-09 22:38:00 -05:00
04ad890f16 Change default compression to xz level 9 2025-06-09 22:31:10 -05:00
a89558d5a7 Merge in upstream version 0.5.1 to Debian pkg 2025-06-09 22:30:46 -05:00
5b8bdaca4b Bump debian/changelog to verson 0.5.0-1 2025-06-09 22:30:31 -05:00
d8b08b46fc Merge in upstream version 0.5.0 to Debian pkg 2025-06-09 21:59:44 -05:00
b33d2ace99 Bump debian/changelog to version 0.4.0-1 2025-06-09 21:58:41 -05:00
5ddb8b020b Add build-depends on libssl-dev 2025-06-09 21:52:34 -05:00
3831f4e0c0 Merge in upstream version 0.4.0 to Debian pkg 2025-06-09 20:59:04 -05:00
d8ff8876b4 Bump debian/changelog to version 0.3-1 2025-06-09 20:57:21 -05:00
036b9d1a94 Merge in upstream version 0.3 to Debian pkg 2025-06-09 20:26:36 -05:00
8401d9eada Bump debian/changelog to version 0.2-1 2025-06-09 20:24:03 -05:00
be28bf0dc8 Adjust the copyright file a bit...
I'm going to mark Geoffrey as having the copyright range up to 2025
because that's when I'm actually assembling this branch. Not like this
needs to be made as-if it was done at that point.

The previous copyright file indicated "LGPL" was an option. I think I
had done that because of the "GPLv3 *or later*" phrasing. I don't think
that's how it works -- the LGPL is not a "newer version" of the GPL.
2025-06-09 20:07:33 -05:00
0857a02c77 Create a copyright file 2025-06-09 19:59:48 -05:00
e50d13b992 Update changelog via gbp dch 2025-06-09 19:59:40 -05:00
41f1593443 Drop the backported link ordering patch
Now that we're past the v0.2 release tag, there is no need to backport
the patch.
2025-06-09 19:58:05 -05:00
46652862d3 Merge in upstream version 0.2 to Debian pkg 2025-06-09 19:47:43 -05:00
5bd8a5de42 Bump debian/changelog to version 0.1-1 2025-06-09 19:38:18 -05:00
646a62afdb Backport a link order fix from upstream
Upstream made a fix for the linker ordering after marking v0.1. Since I
have the benefit of doing this *years after the fact*, I'll just
backport that thing instead of inventing my own fix.
2025-06-09 19:27:54 -05:00
169feb563f Name upstream and debian branches properly
Upstream keeps it's changes on "master". This may be the default for
`gbp`, but may *not* be. Explicitly set the upstream branch just to be
sure.

The Debian branch shouldn't be called "trunk" (or "main" or "master").
I'm calling it "deb" in case a real Debian maintainer picks up the
upstream project and wants to use the name "debian". It's configurable,
so hardly critical, but I may as well be a good neighbor and leave it
unused.
2025-06-09 19:16:48 -05:00
fb99a3783f Set upstream version tag in gbp.conf 2025-06-09 19:16:32 -05:00
a3d77ee98a Drop pbuilder settings from gbp.conf 2025-06-09 19:16:06 -05:00
runiq
e6fbb4f146 More Flatpak manifest cleanup
The flow should be clearer if every module is structured this way:

1. name
2. sources
3. buildsystem
4. config-opts
5. build-commands
6. post-install
7. cleanup
2025-03-16 20:17:06 +10:30
runiq
e4dc805422 Remove superfluous files from Flatpak 2025-03-16 20:17:03 +10:30
runiq
87ee0ed66b Add alsactl utility
Allows saving and loading device state with the Flatpak version. The
Gnome 47 SDK uses alsa-lib 1.2.12 [1] via the Freedesktop.org SDK [2],
so we use that here as well.

[1] https://gitlab.gnome.org/search?search=alsa&nav_source=navbar&project_id=456&group_id=8&search_code=true&repository_ref=47.4
[2] https://gitlab.com/freedesktop-sdk/freedesktop-sdk/-/blob/release/24.08/elements/components/alsa-lib.bst?ref_type=heads
2025-03-16 20:17:01 +10:30
Geoffrey D. Bennett
adeea461fd Change alsa_get_elem_int_values() to return longs rather than ints 2025-03-16 20:08:47 +10:30
Geoffrey D. Bennett
1f7bafbfc3 Update window-hardware with big 4th Gen and Vocaster models 2025-03-16 20:08:47 +10:30
Geoffrey D. Bennett
b8420ba31c Add support for rebooting devices using the FCP socket interface 2025-03-16 20:08:47 +10:30
Geoffrey D. Bennett
a5676eeb5a Replace hwdep check in window-startup.c with driver_type check
Since alsa.c already checks the hwdep version to determine the driver
type, window-startup.c doesn't need to do the same.
2025-03-16 20:08:47 +10:30
Geoffrey D. Bennett
9a33b92392 Don't attempt to attach unused routing_mixer_in_grid 2025-03-16 20:08:47 +10:30
Geoffrey D. Bennett
97f993db7b Add support for waiting for FCP driver initialisation
When a card using the FCP driver is added at runtime, we need to wait
for fcp-server to finish creating all the controls before we attempt
to enumerate them.
2025-03-16 20:08:47 +10:30
Geoffrey D. Bennett
6f0ab1890d Add driver type detection 2025-03-16 20:08:47 +10:30
Geoffrey D. Bennett
c88f7796f4 Move card init from alsa_scan_cards() to new card_init() function 2025-03-16 20:08:47 +10:30
Geoffrey D. Bennett
0b5b47ae66 Disable the startup menu option for 1st Gen devices 2025-03-16 20:08:47 +10:30
Geoffrey D. Bennett
b6117a501f Replace 1st Gen Startup Controls info with Startup Configuration
The Startup Controls information wasn't very useful, and the Startup
Configuration information is actually important.
2025-03-16 20:08:47 +10:30
Geoffrey D. Bennett
a34df84dfa Improve "settings keep resetting" FAQ entry 2025-03-16 20:08:47 +10:30
Pro-pra
6677e5c87d Use template spec with macros 2025-03-07 23:59:50 +10:30
Geoffrey D. Bennett
91fc3bbb03 Add information about alsa-state and alsa-restore to FAQ.md 2025-02-26 03:27:21 +10:30
Geoffrey D. Bennett
460b03c668 Replace '/" with ’/“/” in *.md 2025-02-26 03:27:21 +10:30
Geoffrey D. Bennett
8a2e5f5835 Add RTFM advice to FAQ.md 2025-02-26 03:27:21 +10:30
Geoffrey D. Bennett
72fd974da1 Update startup window no-startup-controls message
Replace the message suggesting a kernel upgrade because the 1st Gen
driver has no startup controls.
2025-02-26 02:23:24 +10:30
Geoffrey D. Bennett
e6166de04b Update 1st Gen doc to mention Level Meters and Startup Controls 2025-02-26 02:23:24 +10:30
Geoffrey D. Bennett
f0213eadb1 Replace -j4 with -j$(nproc) 2025-02-26 02:23:24 +10:30
Geoffrey D. Bennett
ae23674f21 Add small deadband to dial drag to stop double-click adjustments
Sometimes 0.5 < abs(offset_y) < 1 when double-clicking without moving
the mouse, causing the intended toggling between -inf and 0dB to not
work.

Fixes: #149.
2025-02-26 02:22:59 +10:30
Geoffrey D. Bennett
68e45e58a6 Remove unused start_x, start_y from gtk_dial_drag_gesture_update() 2025-02-26 02:07:55 +10:30
Geoffrey D. Bennett
f1585a3b8c Update flatpak container image from gnome-45 to gnome-47 2025-02-21 05:00:28 +10:30
Geoffrey D. Bennett
d1c1eb5db2 Undefine _FORTIFY_SOURCE before defining so GitHub can build the deb
The GitHub build was failing with:
<command-line>: error: "_FORTIFY_SOURCE" redefined [-Werror]
2025-02-21 04:57:17 +10:30
Geoffrey D. Bennett
21cdfbbe1a Make make clean do depclean too 2025-02-21 04:34:43 +10:30
Geoffrey D. Bennett
7033f9f622 Add big 4th Gen demo files 2025-02-21 04:34:43 +10:30
Geoffrey D. Bennett
5106ed228e Update docs and such for 1st Gen and big 4th Gen support 2025-02-21 04:34:43 +10:30
Geoffrey D. Bennett
ab40037064 Bump copyright year to 2025 2025-02-21 04:08:35 +10:30
Geoffrey D. Bennett
ed4f9cbaa7 Call card_destroy_callback() when an ALSA element is removed 2025-02-21 04:08:35 +10:30
Geoffrey D. Bennett
c7357c0539 Move card_destroy_callback() before alsa_card_callback() 2025-02-21 04:08:35 +10:30
Geoffrey D. Bennett
01c947f434 Fix output control column/mute tooltip handling 2025-02-21 04:08:35 +10:30
Geoffrey D. Bennett
dc21eb52d0 Add support for Level Meter labels 2025-02-21 04:08:35 +10:30
Geoffrey D. Bennett
c4ab20f9b5 Update alsa.c to handle differing FCP mixer element names 2025-02-21 04:08:34 +10:30
Geoffrey D. Bennett
b41a47587b Add support for TLVs from the FCP driver
Decode level meter labels and the FCP socket location from TLVs.
2025-02-21 04:08:34 +10:30
Geoffrey D. Bennett
11dba2b42c Simplify update_levels_controls() 2025-02-21 04:08:34 +10:30
Geoffrey D. Bennett
f1f085abcf Add support for new 4th Gen control names
The 4th Gen driver has renamed "Line" to "Analogue" and removed
"Input" and "Output" in cases like "Mixer Input", "DSP Input", and
"Analogue Output". Some numbers are no longer zero-padded.
2025-02-21 04:08:34 +10:30
Geoffrey D. Bennett
18841b2a45 Add support for two-control speaker switching and talkback
The 4th Gen driver has two boolean controls each for the speaker
switching and talkback controls, rather than the single enum control
that the 3rd Gen driver presents.
2025-02-21 04:08:34 +10:30
Geoffrey D. Bennett
64d9f8173a Make perror("fopen") messages distinct 2025-02-21 04:08:34 +10:30
Geoffrey D. Bennett
78e2d9642f Update alsa interface and gain widget to support linear volume
# Conflicts:
#	src/alsa.c
2025-02-21 04:08:34 +10:30
Geoffrey D. Bennett
4a40b00695 Update gtkdial to support linear-volume controls 2025-02-21 04:08:34 +10:30
Geoffrey D. Bennett
0f7389dca8 Highlight mixer labels on dial hover 2025-02-21 04:08:34 +10:30
Geoffrey D. Bennett
640d027502 Update routing hover to highlight corresponding source sink 2025-02-21 04:08:34 +10:30
Geoffrey D. Bennett
2bc6c86a8d Handle per-channel link buttons
Older kernel versions had one link button per channel pair.
2025-02-21 04:08:34 +10:30
Geoffrey D. Bennett
67ccd1d684 Handle interfaces with fixed mixer inputs 2025-02-21 04:08:34 +10:30
Geoffrey D. Bennett
81bc3c77c8 Treat locked ALSA elements as read-only 2025-02-21 04:08:34 +10:30
Geoffrey D. Bennett
e0083f7085 Update constants for new maximum number of mux inputs and meters
Big 4th Gen devices have more inputs and meters than previous devices.
2025-02-21 04:08:34 +10:30
Geoffrey D. Bennett
5da140df1e Wrap long line, fix reopen callback comment in alsa.c 2025-02-21 04:08:34 +10:30
Geoffrey D. Bennett
1b0e072237 Gen 1: Add support for 1st Gen output controls 2025-02-21 04:08:34 +10:30
Geoffrey D. Bennett
8178bd298b Gen 1: Add support for 1st Gen input controls 2025-02-21 04:08:34 +10:30
Geoffrey D. Bennett
845dd5c98b Gen 1: Add support for 1st Gen mixer controls 2025-02-21 04:08:34 +10:30
Geoffrey D. Bennett
45287711a4 Gen 1: Add support for 1st Gen stereo elements
Move routing src/snk creation into alsa.c from window-routing.c.
Move port_category and port_num from struct routing_snk to struct
alsa_elem.
Handle ALSA elements with two values.
Handle controls labelled as 1L and 1R instead of 1 and 2.
2025-02-21 04:08:34 +10:30
Geoffrey D. Bennett
b1831c137a Gen 1: Add support for elements with count > 1 in saved config 2025-02-21 04:08:34 +10:30
Geoffrey D. Bennett
1cdac65c00 Gen 1: Move alsa-sim elem creation into alsa_config_to_new_elem() 2025-02-21 04:08:34 +10:30
Geoffrey D. Bennett
c38bbba793 Gen 1: Parse and save config count field
Needed for 1st Gen stereo volume controls.
2025-02-21 04:08:34 +10:30
Geoffrey D. Bennett
da1f011ab4 Gen 1: Ignore control "index" value in saved configurations 2025-02-21 04:08:34 +10:30
Geoffrey D. Bennett
64f0cc36cc Gen 1: Add PC_OFF port category 2025-02-21 04:08:34 +10:30
Geoffrey D. Bennett
9034790c06 Gen 1: Trigger support based on "Matrix" element presence 2025-02-21 04:08:34 +10:30
Geoffrey D. Bennett
91d7218a47 Gen 1: Add 1st Gen devices to window-hardware.c 2025-02-21 04:08:34 +10:30
Geoffrey D. Bennett
97ced90466 Gen 1: Mute switches are backwards 2025-02-21 04:08:34 +10:30
Geoffrey D. Bennett
fa3e73d52f Gen 1: Handle different names for clock source and sync status 2025-02-21 04:08:34 +10:30
Geoffrey D. Bennett
602854d087 Add Scarlett 1st Gen demo state files 2025-02-21 04:08:34 +10:30
Geoffrey D. Bennett
97ca9ae754 Add get_elem_by_substr() to alsa.[ch] 2025-02-21 04:08:34 +10:30
Geoffrey D. Bennett
6a04e1d1fa Update logo 2025-02-21 04:08:34 +10:30
Geoffrey D. Bennett
da4be2993e Update flatpak to GNOME 47 2025-02-21 04:08:25 +10:30
Geoffrey D. Bennett
abdb7f40f5 Fix crash in window-level.c on_destroy() 2024-07-03 02:53:18 +09:30
Geoffrey D. Bennett
0187698826 Replace cairo_show_text() in gtkdial.c with Pango
Fixes: #126.
2024-07-03 02:53:18 +09:30
05ae063b90 Initial package check-in
The package should work properly, however the GTK4 dependency isn't
quite correct. The instructions from upstream suggest that the author is
using Fedora, not Debian. After testing real quick, it looks like Fedora
37 compiles properly, but Fedora 38 aborts with a deprecation warning
   (-Werror=deprecated-declarations). Fedora 39 does the same, of
course.
2024-05-29 18:02:01 -05:00
unhappy-ending
c5b1ff0b94 Update Makefile to use $(CC) rather than cc
Calling cc directly causes a build failure on Clang/LLVM based Gentoo
machines that use LLVM specific toolchain flags.
2024-05-17 18:30:13 +09:30
Geoffrey D. Bennett
955dd1355a Add 3rd Gen 18i8/18i20 S/PDIF/Digital I/O Mode startup controls 2024-05-10 22:27:45 +09:30
Geoffrey D. Bennett
1615580de6 Add const to get*elem*() char* function arguments 2024-05-10 22:25:43 +09:30
Geoffrey D. Bennett
5526aa2f54 Fix link from FAQ.md to INSTALL.md
Fixes: #116.
2024-04-15 13:44:59 +09:30
Geoffrey D. Bennett
4ce2565b90 Add peak value display to the level meters 2024-04-11 22:47:48 +09:30
Geoffrey D. Bennett
909d3618b3 Use snprintf() in widget-gain.c when printing floats 2024-04-11 21:24:27 +09:30
Geoffrey D. Bennett
1fa964d348 Add peak display to the level meters 2024-04-11 21:24:27 +09:30
Geoffrey D. Bennett
159b3340eb Move level meter fields out of struct alsa_card
Create a levels struct managed inside window-levels.c.
2024-04-11 21:24:27 +09:30
Geoffrey D. Bennett
5fb3191124 Fix up deb and RPM package description & add docs
# Conflicts:
#	.github/workflows/build-debian-package.yml
2024-04-11 21:24:27 +09:30
Geoffrey D. Bennett
cc6853f541 Make flatpak build faster 2024-04-11 21:24:04 +09:30
Geoffrey D. Bennett
5d77207b66 Download and include scarlett2 firmware in flatpak
Fixes: #112.
2024-04-11 21:23:49 +09:30
Geoffrey D. Bennett
a940db51c2 Add -fPIE and -pie build flags to fix flatpak build under Fedora 2024-04-11 18:13:21 +09:30
Guillaume
d47e31eaed Add missing GTK and ALSA dependencies on deb package
Fixes: #109.
2024-04-11 13:39:23 +09:30
Geoffrey D. Bennett
92f9d5db8e Switch to embedded SVG icons
Make the icons independent of the desktop theme so they always look
good.
2024-03-31 03:29:10 +10:30
Geoffrey D. Bennett
af97b72b12 Update widget-boolean to cache the icon widgets 2024-03-31 03:29:10 +10:30
Geoffrey D. Bennett
3f7a4c2063 Allow for boolean controls that are backwards
Gen 1 has playback controls (0 = off, 1 = on), not mute controls
(0 = not muted, 1 = muted) like the Gen 2+ do.
2024-03-31 03:29:10 +10:30
Geoffrey D. Bennett
111ec1154d Add support for volatile buttons to widget-boolean.c
Will be used by Gen 1 support.
2024-03-31 03:29:10 +10:30
Geoffrey D. Bennett
db0929bd08 Search $PATH and /usr/sbin for alsactl
The path to alsactl was previously hardcoded because some distros put
it in /usr/sbin but don't include that directory in $PATH.
Unfortunately other distros put alsactl elsewhere. Let's search $PATH
and /usr/sbin to cater for both.

Fixes #101.
2024-03-31 03:29:10 +10:30
Geoffrey D. Bennett
2ddede4d3f Override focus and colour CSS button styles
Set all button focus outline properties and set the colour and filter
on fixed buttons so more theme styles are overridden.
2024-03-31 03:29:10 +10:30
Geoffrey D. Bennett
0e227e1e07 Fix Sample Rate button to be insensitive 2024-03-31 03:29:10 +10:30
Geoffrey D. Bennett
1d2ac0fd5c Add Arch package dependency 2024-03-31 03:29:10 +10:30
Geoffrey D. Bennett
05e9d9e0a2 Fix widget-boolean.c to free data on button destruction 2024-03-31 03:17:35 +10:30
Giorgio Reale
fcb5028aa2 Add 4rd Gen models to window-hardware.c 2024-03-28 13:15:21 +10:30
Geoffrey D. Bennett
c57e4eb2a4 Move 4th Gen Solo 48V switch above the Air switch
Fixes #107.
2024-03-28 13:15:21 +10:30
Geoffrey D. Bennett
feba2f4520 Update documentation for Scarlett 4th Gen and Vocaster 2024-03-24 22:40:11 +10:30
Geoffrey D. Bennett
16e3a25f76 Update About dialog 2024-03-24 22:40:11 +10:30
Geoffrey D. Bennett
be1f9763e1 Add firmware info to the INSTALL.md Prerequisites section 2024-03-24 22:40:11 +10:30
Geoffrey D. Bennett
605df45b2f Prompt for firmware update if in MSD Mode and an update is available 2024-03-24 22:40:11 +10:30
Geoffrey D. Bennett
984133f61d Store the best_firmware_version in struct alsa_card 2024-03-24 22:40:11 +10:30
Geoffrey D. Bennett
6e40b8d9ed Add initial support for the Vocaster One and Two 2024-03-24 22:40:11 +10:30
Geoffrey D. Bennett
607b002985 Update gain widget to show no decimal places for scale > 0.5
The 4th Gen input gain control scale is 69/70 which is close enough to
1 that we don't need to display any decimal places.
2024-03-24 22:40:11 +10:30
Geoffrey D. Bennett
0fae084ccb Display "+" before positive dB values in the gain widget 2024-03-24 22:40:11 +10:30
Geoffrey D. Bennett
f00de1bd25 Add display of sample rate 2024-03-24 22:40:11 +10:30
Geoffrey D. Bennett
96b4ec8259 Add gtk_widget_remove_css_classes_by_prefix() helper 2024-03-24 22:40:11 +10:30
Geoffrey D. Bennett
2b664c446b Add missing static to populate_submenu() in menu.c 2024-03-24 22:40:11 +10:30
Geoffrey D. Bennett
486c40048b Make window-helper.c close the window when Esc is pressed
Fixes #102.
2024-03-24 22:40:11 +10:30
Geoffrey D. Bennett
84ad0484f9 Reduce GtkDial circle brightness
Provides better contrast between dials in the sea of mixer knobs.
2024-03-24 22:40:11 +10:30
Geoffrey D. Bennett
b9549eb58e If there's an MSD control, add a reboot control too 2024-03-24 22:40:11 +10:30
Geoffrey D. Bennett
b06b19e2a8 Don't show empty rows in levels window
If a port category has no ports, skip that row. 4th Gen has a DSP port
category that does not exist in previous generations.
2024-03-24 22:40:11 +10:30
Geoffrey D. Bennett
4c2a5ab12a Add 4th Gen Solo, 2i2, and 4i4 demo files 2024-03-24 22:40:11 +10:30
Geoffrey D. Bennett
8b16bbdaed Make gain widget dB numbers smaller 2024-03-24 22:40:11 +10:30
Geoffrey D. Bennett
7e712dece4 Don't set transient on modal window
Doesn't work on Ubuntu 22.04 GNOME when the parent goes away.
2024-03-24 22:40:11 +10:30
Geoffrey D. Bennett
52424dd067 Remove fixed/mentioned-elsewhere issues from USAGE.md 2024-03-24 22:40:11 +10:30
Geoffrey D. Bennett
fdf8c50413 Update OpenSUSE and Ubuntu package dependencies 2024-03-24 22:40:11 +10:30
Antti-Pekka Meronen
1247f8172d Include openssl-devel in Fedora installation instructions 2024-03-24 17:06:17 +10:30
Geoffrey D. Bennett
9026eb76c5 Add support for firmware update 2024-03-24 17:06:17 +10:30
Geoffrey D. Bennett
c9441b2591 Move -lm into LDFLAGS 2024-03-12 01:43:07 +10:30
Geoffrey D. Bennett
b4fc332f0a Retrieve and store the device USB PID 2024-03-12 01:43:07 +10:30
Geoffrey D. Bennett
9544635e30 Add support for config reset 2024-03-12 01:43:07 +10:30
Geoffrey D. Bennett
e95cbff3d5 Don't export alsa_cards from alsa.c 2024-03-12 01:43:07 +10:30
Geoffrey D. Bennett
05006284c6 Retrieve and store the device serial number 2024-03-12 01:43:07 +10:30
Geoffrey D. Bennett
c90fbdc3d1 CSS fixes for buttons
Make non-toggle buttons brighter.
Make disabled glow match the dimmer text colour.
Don't put an opacity filter over status buttons.
2024-02-20 23:38:49 +10:30
Geoffrey D. Bennett
2137000d05 Add red focus outline to GtkDial 2024-02-20 23:38:49 +10:30
Geoffrey D. Bennett
b02ad32d5a Fix GtkDial to redraw on notify::sensitive signal 2024-02-20 23:38:49 +10:30
Geoffrey D. Bennett
7a7e08d4eb Fix GtkDial to not redraw the dial if the set value doesn't change 2024-02-20 23:38:49 +10:30
Geoffrey D. Bennett
22a2aa2ad6 Add routing group tooltips 2024-02-20 23:38:49 +10:30
Geoffrey D. Bennett
8c06e7aff7 Update the gain widget to support updating direct monitor mix controls
The 4th Gen Solo and 2i2 have controls to set custom Mix A/B gains
when Direct Monitor is enabled. Update those controls when the Mix A/B
gains are updated so that they are remembered.
2024-02-20 23:38:49 +10:30
Geoffrey D. Bennett
b9af5dfaf3 Prefix CSS styles so they don't apply to other windows
The custom button styles were erroneously applying to the File
windows; prefix them with ".window-frame" so they only apply to our
windows.
2024-02-20 23:38:49 +10:30
Geoffrey D. Bennett
3048b43b9a Add colour to GtkDial level meters 2024-02-20 23:38:49 +10:30
Geoffrey D. Bennett
a26f607a8b Fix GtkDial to not recreate the cairo patterns on every draw 2024-02-20 23:38:49 +10:30
Geoffrey D. Bennett
1815f61280 Allow GtkDial to shrink more and reduce slider thickness 2024-02-20 23:28:31 +10:30
Geoffrey D. Bennett
eaf73c280b Remove struct dial_properties; cache values in struct _GtkDial 2024-02-20 23:28:29 +10:30
Geoffrey D. Bennett
24a79963ba Use GtkDial off_db (deadband) for level meters
Set HW Output level meters deadband to -55dB, others to -45dB to match
the 4th Gen hardware level meters.
2024-02-20 23:26:10 +10:30
Geoffrey D. Bennett
1cc6c64c04 Add off_db (deadband) to GtkDial for quiet signals
Add an optional deadband at the bottom of the GtkDial so that very
quiet signals can be squashed into the first 1% of the dial. This will
be used to make the level meters more realistic.
2024-02-20 23:26:10 +10:30
Geoffrey D. Bennett
17b39efee0 Add 4th Gen Solo Mix switch 2024-02-20 23:26:10 +10:30
Geoffrey D. Bennett
1c2d966763 Add GtkDial:can_control property
If the dial can't be controlled, it shouldn't be dimmed when it's not
sensitive.
2024-02-20 23:26:10 +10:30
Geoffrey D. Bennett
72d45a0987 Add draw_slider() to remove some common code from dial_snapshot() 2024-02-20 23:26:10 +10:30
Geoffrey D. Bennett
9fc4c7c6e1 Use GtkTextView instead of GtkLabel in startup big_label() 2024-02-20 23:26:10 +10:30
Geoffrey D. Bennett
4b340b4d4c Add CSS for buttons that get dimmer when checked 2024-02-20 23:26:10 +10:30
Geoffrey D. Bennett
f40a1c986d Update about, etc. messages to include Gen 4/Clarett 2024-02-20 23:26:10 +10:30
Geoffrey D. Bennett
793523b0a7 Add some red and grey 2024-02-20 23:26:10 +10:30
Geoffrey D. Bennett
eae7cdc204 Remove now-unused widget-combo 2024-02-20 23:26:10 +10:30
Geoffrey D. Bennett
e0e591db3e Update 3rd Gen Solo Direct Monitor control to match 4th Gen 2024-02-20 23:26:10 +10:30
Geoffrey D. Bennett
b8ca52e7f2 Add power status control for 4th Gen 4i4 2024-02-20 23:26:10 +10:30
Geoffrey D. Bennett
b912ccbf9c Add 4th Gen Solo/2i2 Direct Monitor controls 2024-02-20 23:26:10 +10:30
Geoffrey D. Bennett
1411ff2c3b Switch Clock Source to widget-drop-down 2024-02-20 23:26:10 +10:30
Geoffrey D. Bennett
bc9d8867f3 Add widget-drop-down for Air 2024-02-20 23:26:10 +10:30
Geoffrey D. Bennett
ade852163b Add CSS classes to controls and add more colour 2024-02-20 23:26:10 +10:30
Geoffrey D. Bennett
1caa75a7d2 Move 4th Gen Solo Air control up to be next to Inst control 2024-02-20 23:26:10 +10:30
Geoffrey D. Bennett
56054c2634 Rewrite choose_line_colour() to work with a dark background
Use HSL with fixed saturation/lightness, and a hue based on the sink
index.
2024-02-20 23:26:10 +10:30
Geoffrey D. Bennett
36f724c66c Use CSS to set dark colour scheme 2024-02-20 23:26:10 +10:30
Geoffrey D. Bennett
d0b7c086ca Remove "Analogue" from small Gen 3 device input labels 2024-02-20 23:26:10 +10:30
Geoffrey D. Bennett
54b99aca29 Move label into boolean controls and use button state to show status
Rather than having a label "Air" and the button toggle between "Off"
and "On", have the button just be "Air" and no separate label.
2024-02-20 23:26:10 +10:30
Geoffrey D. Bennett
099e50b91e Remove bool_text from struct alsa_elem
Store the text in the boolean/dual widget private data.
2024-02-20 23:26:10 +10:30
Geoffrey D. Bennett
e655ee39ce Make GtkDial dimmer if insensitive 2024-02-20 23:26:10 +10:30
Geoffrey D. Bennett
7c44f15428 Make GtkDial look better 2024-02-20 23:26:09 +10:30
Geoffrey D. Bennett
df5d0960dd Add support for piecewise linear interpolation taper to GtkDial
This commit adds support for piecewise linear interpolation tapers to
GtkDial and the gain widget so that the 4th Gen 4i4 volume knob taper
can be modelled correctly.
2024-02-11 21:46:22 +10:30
Geoffrey D. Bennett
492c348897 Add configurable taper to GtkDial
The taper was previously set to a log function which matched the
Clarett volume knob. Add linear option to match the Scarlett 4th Gen
input gain knobs and hardware level meters.
2024-02-08 19:04:53 +10:30
Geoffrey D. Bennett
189b9ff6f6 Move valp clamp and scale from calc_valp_log() to calc_valp() 2024-02-08 18:08:34 +10:30
Geoffrey D. Bennett
a77cb0e258 Remove inline from functions in gtkdial.c 2024-02-08 18:08:34 +10:30
Geoffrey D. Bennett
64ca9f78da Fix typo range->dial in gtkdial.[ch] 2024-02-08 18:08:34 +10:30
Geoffrey D. Bennett
d91c9d5687 Add page argument to gtk_dial_new_with_range()
Make gain widget page_incr 3dB.
2024-02-08 18:08:34 +10:30
Geoffrey D. Bennett
1164845b3c Allow for continuous dials
Update gtk_dial_new_with_range() to set round_digits to -1 if step is
zero.

Update create_levels_controls() to set step to zero.
2024-02-08 18:08:34 +10:30
Geoffrey D. Bennett
e40ce4d5ad Fix gtk_dial_new_with_range() to use calculated round_digits 2024-02-08 18:08:34 +10:30
Geoffrey D. Bennett
fcdbc60f16 Add scale to widget-gain.c struct gain 2024-02-08 18:08:34 +10:30
Geoffrey D. Bennett
3740d7ee2d Fix GtkDial:zero_db property comment 2024-02-08 18:08:34 +10:30
Geoffrey D. Bennett
28604f08a3 Reformat gtkdial.c to match rest of code 2024-02-08 18:08:34 +10:30
Geoffrey D. Bennett
b646bc92cc Remove irrelevant GDK_AVAILABLE_IN_ALL from gtkdial.h
GDK_AVAILABLE_IN_ALL is for core GDK/GTK classes, not user-defined
ones.
2024-02-08 18:08:34 +10:30
Geoffrey D. Bennett
9587e2f494 Remove unused guint8 and gsize from gtkdial.c 2024-02-08 18:08:34 +10:30
Geoffrey D. Bennett
2115a26d9d Remove unused GtkDialFormatValueFunc from gtkdial.h 2024-02-08 18:08:34 +10:30
Geoffrey D. Bennett
b2823e79be Bump copyright year 2024-02-08 18:08:34 +10:30
Geoffrey D. Bennett
4a123f5df6 Simplify GtkDial calculations 2024-02-08 18:07:44 +10:30
Geoffrey D. Bennett
bd8f812e01 Fix widget-combo to check if the alsa elem is writable 2024-02-05 20:04:58 +10:30
Geoffrey D. Bennett
6923a3ddb0 Don't round level meter values passed to GtkDial 2024-02-05 20:04:58 +10:30
Geoffrey D. Bennett
20c4ff5559 Display -inf when volume/gain controls are at zero/off 2024-02-05 20:04:58 +10:30
Geoffrey D. Bennett
770ce1cc23 Add bindings for pgup/pgdn/home/end to GtkDial 2024-02-05 20:04:58 +10:30
Geoffrey D. Bennett
1ebd6de6a1 Add missing GtkDial scroll_begin() implementation 2024-02-05 20:04:58 +10:30
Geoffrey D. Bennett
047fb72394 Add 4th Gen 4i4 headphone volume knob control 2024-02-05 20:04:58 +10:30
Geoffrey D. Bennett
b35fa3cf50 Add input select widget for 4th Gen 2i2 and 4i4 2024-02-05 20:04:58 +10:30
Geoffrey D. Bennett
47034d7901 Remove widgets from struct alsa_elem and add data to callbacks
Rather than having widget/widget2/widget_callback fields in the struct
alsa_elem, have a list of callbacks and allow private data to be
passed to callbacks.
2024-02-05 20:04:58 +10:30
Geoffrey D. Bennett
d56a1d34ff Add 4th Gen input controls 2024-02-05 20:04:58 +10:30
Geoffrey D. Bennett
63068ed9c7 Explicitly order main window controls
Rather than looping through the ALSA controls and creating them in
that order, create them in a specific order.
2024-02-05 20:04:56 +10:30
Geoffrey D. Bennett
2eb8e0b7cb Make boolean widget boolify value from alsa_get_elem_value()
Make sure the value is 0/1 as it's used as an index into
elem->bool_text[].
2024-02-05 20:03:10 +10:30
Geoffrey D. Bennett
0347d25fc9 Center-align text in combo boxes 2024-02-05 20:03:10 +10:30
Geoffrey D. Bennett
9a365000ad Combine gain and volume widgets
Remove volume widget and make the gain widget choose the appropriate
format string.
2024-02-05 20:03:10 +10:30
Geoffrey D. Bennett
be458afcc4 Remove hard-coded values from widget-gain.c and widget-volume.c
Update alsa-sim.c and alsa.c to read the TLV info, and update the gain
and volume widgets to use that info rather than hard-coding the
min/max values.
2024-02-05 20:03:10 +10:30
Geoffrey D. Bennett
197f469bd8 Allow for phantom power per-channel 2024-02-05 20:03:10 +10:30
Geoffrey D. Bennett
658f946202 Add support for routing the Gen 4 DSP I/O 2024-02-05 20:03:10 +10:30
Geoffrey D. Bennett
dfa40c79b0 Add margin to socket widget 2024-02-05 20:03:10 +10:30
Geoffrey D. Bennett
93f7a32ea5 Fix Presets button to be centered
The Presets button was filling the available space. It looks better
using GTK_ALIGN_CENTER instead.
2024-02-05 20:03:10 +10:30
Geoffrey D. Bennett
656eb06159 Inline routing_grid_label() in create_routing_group_grid()
As create_routing_grid() and routing_grid_label() are called 1:1 now,
the code from routing_grid_label() can be moved inside
create_routing_group_id() if we add descr and align parameters.
2024-02-05 20:03:10 +10:30
Geoffrey D. Bennett
e66a3ac883 Add orientation parameter to routing_grid_label()
By adding an orientation parameter, then routing_grid_label() can be
used for the Mixer I/O group labels as well.
2024-02-05 20:03:10 +10:30
Geoffrey D. Bennett
aba34f0648 Remove repeated group by code in create_routing_grid()
Create create_routing_group_grid() to remove repeated code from
create_routing_grid().
2024-02-05 20:03:10 +10:30
Geoffrey D. Bennett
9890b4939b Make the Level Meter check compatible with alsa-sim.c
Rather than retrieving the firmware version in alsa_scan_cards(), use
get_elem_by_name() to check if the control is present.

Update alsa-sim.c alsa_config_to_new_elem() to read iface=CARD
controls.
2024-02-05 20:03:10 +10:30
Geoffrey D. Bennett
5b9ff7d457 Remove lots of casts in create_routing_grid()
By storing routing_grid in a GtkGrid *, lots of GTK_GRID() casts can
be removed.
2024-02-05 20:03:10 +10:30
Geoffrey D. Bennett
22fdbaad41 Fix is_elem_routing_snk() for Gen 4
The search for routing sink ALSA elements should only include PCM,
Mixer, and DSP Capture Enums. The previous search for Capture Enum
excluding Line In Level Capture Enums is too broad for Gen 4 as the
Air control is a Capture Enum as well.
2024-02-05 20:03:10 +10:30
Geoffrey D. Bennett
80cd0ebc4d Remove gtk_widget_add_class()
Should use gtk_widget_add_css_class() instead.
2024-02-05 20:03:10 +10:30
Nate Gallaher
b525d8dc23 Clarify pad tooltip to specify attenuation amount 2024-02-02 19:19:22 +10:30
Geoffrey D. Bennett
0c3bc30439 Fix dial to display focus indication
Partial cherry-pick from 5dc3ab Sebastian Kaminski
"dial ... shows focus indication".

Use has_focus() rather than has_visible_focus() as I found
has_visible_focus() to be unreliable.
2023-12-15 03:17:04 +10:30
Geoffrey D. Bennett
945ccc874d Fix dial to grab focus when clicked
Partial cherry-pick from 5dc3ab Sebastian Kaminski
"dial grabs focus when being clicked".
2023-12-15 03:14:23 +10:30
Geoffrey D. Bennett
fef139be64 Split calc_valp() into calc_valp() and calc_valp_log()
gtk_dial_drag_gesture_begin() needs a linear calc_valp().
2023-12-15 02:55:42 +10:30
Geoffrey D. Bennett
e506edc965 Remove keyboard accelerator mention from USAGE.md
Implemented in 21f0d9d.
2023-12-15 02:51:00 +10:30
Geoffrey D. Bennett
f10a383e36 Reformat keyboard accelerators to match existing code
Terminate menus[] with empty-initialised as well.
2023-12-15 02:44:37 +10:30
Trent
21f0d9dd05 Add keyboard accelerators (aka shortcuts, hotkeys) for menu items. 2023-12-12 14:25:25 -07:00
Jason A. Donenfeld
d81f9ca2bb gtkdial: use fabs() for double
Passing a double to abs() truncates it to an integer, which is probably
not intended, and also causes fatal errors on clang.

Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2023-12-05 12:29:49 +10:30
Geoffrey D. Bennett
3a3860f617 Move FUNDING.yml to the right spot 2023-12-04 12:45:30 +10:30
Geoffrey D. Bennett
e7eea495ff Fix typo in INSTALL.md: comitting -> committing 2023-12-03 22:13:44 +10:30
Geoffrey D. Bennett
7b3c662dcb Add OpenSUSE package requirements 2023-12-03 22:07:19 +10:30
Geoffrey D. Bennett
6812c001de Fix long lines 2023-12-02 04:15:55 +10:30
Geoffrey D. Bennett
266b90e8ce Update FAQ with more MSD info 2023-12-02 03:51:53 +10:30
Geoffrey D. Bennett
21cc6d6021 Allow the mixer window to be resized and give it scrollbars 2023-12-02 03:06:53 +10:30
Geoffrey D. Bennett
ce40aa1ba9 Add link from USAGE.md to INTERFACES.md 2023-12-02 02:55:15 +10:30
Geoffrey D. Bennett
33bc54480d Add TOC to INTERFACES.md 2023-12-02 02:45:32 +10:30
Geoffrey D. Bennett
d7f673cb32 Add Clarett info to INTERFACES.md 2023-12-02 02:44:18 +10:30
Geoffrey D. Bennett
0f269fb2da Add issue template 2023-12-02 02:31:31 +10:30
Geoffrey D. Bennett
89e5eeaa61 Add FUNDING.yml 2023-12-02 01:51:02 +10:30
Geoffrey D. Bennett
58446d1511 Add initial version of FAQ.md 2023-12-02 01:37:33 +10:30
Jason A. Donenfeld
4cb1cd6e57 Makefile: prefer distro cflags if specified
The compilation flags that are necessary for building and part of the
developer's intentions belong in the `+=` section, but the base flags
that distros like to override belong in a `?=` section, so that build
systems using their own are respected.

Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2023-12-01 14:19:36 +10:30
Geoffrey D. Bennett
8ef011145c Fix typo in INSTALL.md driver disabled message 2023-12-01 01:27:43 +10:30
Geoffrey D. Bennett
68fb1c3655 Add Gtk4 info to INSTALL.md 2023-12-01 01:27:20 +10:30
Geoffrey D. Bennett
1d844bfa1c Add info to INSTALL.md on how to check the kernel version 2023-12-01 01:23:53 +10:30
Geoffrey D. Bennett
68b6d0a047 Update software name in INSTALL.md and USAGE.md
Rename from "ALSA Scarlett Gen 2/3 Control Panel" to "ALSA Scarlett2
Control Panel".
2023-12-01 01:18:55 +10:30
Geoffrey D. Bennett
734ec616cc Update README.md with Gen 4 info
Driver was renamed to Scarlett2.
Add list of supported interfaces.
Add link to Gen 4 driver update.
2023-12-01 01:15:14 +10:30
170 changed files with 77325 additions and 2853 deletions

2
.github/FUNDING.yml vendored Normal file
View File

@@ -0,0 +1,2 @@
liberapay: gdb
custom: 'https://www.paypal.me/gdbau'

54
.github/ISSUE_TEMPLATE/issue.md vendored Normal file
View File

@@ -0,0 +1,54 @@
---
name: Issue
about: Open an issue for help, to report a bug, or request a feature
title: ''
labels: ''
assignees: ''
---
# `alsa-scarlett-gui` Issue Template
Thank you for taking the time to contribute to the `alsa-scarlett-gui` project. Before you submit your issue, please ensure you have checked the FAQ and provide the necessary information below.
## Confirmation
- [ ] I confirm that I have read the [FAQ](https://github.com/geoffreybennett/alsa-scarlett-gui/blob/master/FAQ.md).
## Issue Category
Please select the category that best describes your issue:
- [ ] Help Request
- [ ] Bug Report
- [ ] Feature Request
## Environment Details
Please provide the following details about your environment.
### Linux Distribution and Version
(paste output from `cat /etc/redhat-release` or `cat /etc/lsb_release` here)
- Distribution:
- Version:
### Kernel Version
(paste output from `uname -r` here)
- Kernel version:
### Kernel Messages
(paste output from `dmesg | grep -A 5 -B 5 -i focusrite` here)
### Focusrite Interface Series and Model
(maybe shown in kernel messages, or paste output from `lsusb -d1235:` if unsure)
- Series (e.g., Scarlett 2nd/3rd/4th Gen, Clarett USB, Clarett+):
- Model (e.g., Solo, 2i2, 4i4, etc.):
### Audio System
(use `ps aux | grep -E "pulseaudio|jackd|pipewire"` to check)
- [ ] PulseAudio
- [ ] JACK
- [ ] PipeWire
## Issue Description
Please provide a detailed description of the issue or feature request, including steps to reproduce (if applicable), expected behavior, and actual behavior:
---
Thank you for helping improve `alsa-scarlett-gui`!

View File

@@ -19,11 +19,11 @@ jobs:
- name: Install build dependencies
run: |
sudo apt -y update
sudo apt -y install git make gcc libgtk-4-dev libasound2-dev
sudo apt -y install git make gcc libgtk-4-dev libasound2-dev libssl-dev
- name: Build from sources
run: |
make -C src -j4 PREFIX=/usr
make -C src -j$(nproc) PREFIX=/usr
- name: Prepare package workspace
run: |
@@ -34,7 +34,7 @@ jobs:
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/vu.b4.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 }}/
cp -r *.md demo docs img ${{ github.workspace }}/deb-workspace/usr/share/doc/${{ env.APP_NAME }}-${{ env.APP_VERSION }}/
- name: Build debian package
uses: jiro4989/build-deb-action@v2
@@ -42,8 +42,9 @@ jobs:
package: ${{ env.APP_NAME }}
package_root: ${{ github.workspace }}/deb-workspace
maintainer: geoffreybennett
depends: 'libgtk-4-1, libasound2, alsa-utils'
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.
desc: ${{ env.APP_NAME }} is a Gtk4 GUI for the ALSA controls presented by the Linux kernel Focusrite USB drivers.
- name: Upload Release Asset
uses: actions/upload-release-asset@v1

View File

@@ -14,7 +14,7 @@ jobs:
name: "Flatpak"
runs-on: ubuntu-latest
container:
image: bilelmoussaoui/flatpak-github-actions:gnome-45
image: bilelmoussaoui/flatpak-github-actions:gnome-47
options: --privileged
steps:
- uses: actions/checkout@v4

154
FAQ.md Normal file
View File

@@ -0,0 +1,154 @@
# FAQ for the ALSA Scarlett Control Panel (`alsa-scarlett-gui`)
## What is this?
The ALSA Scarlett Control Panel (`alsa-scarlett-gui`) is an
easy-to-use application for adjusting the ALSA controls provided by
three Linux kernel drivers for Focusrite USB interfaces:
1. The Scarlett 1st Gen Mixer Driver (for 1st Gen 6i6, 8i6, 18i6, 18i8, 18i20)
2. The Scarlett2 Protocol Driver (for 2nd/3rd Gen interfaces, small 4th Gen, Clarett, and Vocaster)
3. The FCP (Focusrite Control Protocol) Driver (for big 4th Gen interfaces: 16i16, 18i16, 18i20)
To check if your kernel is already up-to-date, and how to upgrade if
not, see the [Control Panel Installation Prerequisites — Linux
Kernel](docs/INSTALL.md).
## Do I need these drivers for my Focusrite interface?
For basic audio functionality? No. Focusrite USB interfaces are
“plug-and-play” — they are USB Audio Class Compliant, meaning they
work out-of-the-box with the standard ALSA USB audio driver (to get
full functionality on Scarlett 3rd/4th Gen/Vocaster interfaces, first
deactivate MSD mode by holding down the 48V button while powering it
on).
However, to access the mixer, routing, and hardware-specific features,
youll need the appropriate driver for your interface model.
## MSD Mode?
"MSD Mode" is the "Mass Storage Device Mode" that the Scarlett 3rd and
4th Gen interfaces ship in.
If MSD Mode is enabled, you need to disable it and restart your
interface to get access to its full functionality.
When you plug the interface in, therell be a tiny read-only virtual
disk that has a link to the Focusrite product registration page; until
you turn off MSD Mode not all features of the interface will be
available.
You can turn off MSD Mode by holding down the 48V button while
powering on the interface, or by clicking the button in
`alsa-scarlett-gui` and rebooting it.
If you do the recommended/required (depending on the model) firmware
update, MSD Mode will automatically be turned off.
## What is the purpose of these drivers if theyre not needed for basic audio?
These drivers are for users who want more control over their
interface. They allow for detailed manipulation of:
- Internal audio routing
- Hardware-specific settings
- Mixer functionality
- Level monitoring
- Input/output configuration
These controls go beyond the basic audio I/O functionality provided by
the generic ALSA USB audio driver.
## What interfaces are supported?
The ALSA Scarlett Control Panel supports:
- **Scarlett 1st Gen**: 6i6, 8i6, 18i6, 18i8, 18i20
- **Scarlett 2nd Gen**: 6i6, 18i8, 18i20
- **Scarlett 3rd Gen**: Solo, 2i2, 4i4, 8i6, 18i8, 18i20
- **Scarlett 4th Gen**: Solo, 2i2, 4i4, 16i16, 18i16, 18i20
- **Clarett USB and Clarett+**: 2Pre, 4Pre, 8Pre
- **Vocaster**: One, Two
Note: The Scarlett 1st and 2nd Gen small interfaces (Solo, 2i2, 2i4)
dont have any software controls. All the controls are available from
the front panel, so they dont require the specialised drivers or this
GUI.
## Where are the options to set the sample rate and buffer size?
The ALSA Scarlett Control Panel doesnt handle audio input/output
settings like sample rate and buffer size. These settings are managed
by the application using the soundcard, typically a sound server such
as PulseAudio, JACK, or PipeWire.
The sample rate shown in the control panel is informative only and
displays the current rate being used by applications. If it shows
“N/A” then no application is using the interface.
Note that not all features are available at higher sample rates; refer
to the user manual of your interface for more information.
## Why do my settings keep resetting?
The settings in the ALSA Scarlett Control Panel are automatically
saved in the interface itself (all series except 1st Gen), so they
should persist across reboots, power cycles, USB disconnect/reconnect,
and even across different computers. This includes all routing,
mixing, and other control panel settings.
If you find that your settings are reverting whenever you plug your
interface in or power it back on, the most likely cause is the
`alsa-state` and `alsa-restore` systemd services. These services save
the state of ALSA controls on system shutdown to
`/var/lib/alsa/asound.state` and then restore it each time the device
is plugged in, potentially overwriting your interfaces stored
settings.
It can be rather annoying, wondering why your device is unusable or
needs to be reconfigured every time you plug it in or turn it on.
To fix this issue, disable these services:
```sh
sudo systemctl mask alsa-state
sudo systemctl mask alsa-restore
```
You can verify if this is the cause of your issues by:
1. Change some setting that is indicated on the device (the “Inst”
setting is a good).
2. Disconnect USB and notice the state of the setting on the device
has not changed.
3. Power cycle the device and notice the state of the setting on the
device has not changed.
4. Reconnect USB and notice the state of the setting on the device has
changed.
If the setting on the device changes at step 4, then the `alsa-state`
and `alsa-restore` services are the likely cause of your issues.
## Help?!
Have you read the User Guide for your interface? Its available
online: https://downloads.focusrite.com/focusrite and contains a lot
of helpful/useful/important information about your device.
You can skip the “Easy Start” and “Setting up your DAW” sections, but
the rest is well worth reading. Even the information about Focusrite
Control is useful, although not directly applicable, because it will
help you understand more about the possibilities of what you can do
with your device.
For help with the Scarlett2 and FCP kernel drivers:
https://github.com/geoffreybennett/linux-fcp/issues
For help with the FCP user-space side:
https://github.com/geoffreybennett/fcp-support/issues
For help with `alsa-scarlett-gui`:
https://github.com/geoffreybennett/alsa-scarlett-gui/issues
For general Linux audio help: https://linuxmusicians.com

View File

@@ -1,158 +0,0 @@
# 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

@@ -1,413 +0,0 @@
# Focusrite Scarlett Interface Features by Model
The information here was compiled carefully and is believed accurate
but there might still be mistakes. Please independently confirm before
relying on anything here.
## 6i6 Gen 2
- 6× Hardware Inputs
- Analogue In 12: Mic/Line/Inst In 12 (Pad)
- Analogue In 34: Line In 34
- S/PDIF 12
- Hardware Input Controls
- 2× Input Gain knobs for Analogue In 12
- Fixed Input Gain for Analogue In 34
- Phantom Power for Analogue 12 linked
- 6× Hardware Outputs
- Analogue 1: Line 1 Out (Monitor L) + Headphone 1 Left
- Analogue 2: Line 2 Out (Monitor R) + Headphone 1 Right
- Analogue 3: Line 3 Out + Headphone 2 Left
- Analogue 4: Line 4 Out + Headphone 2 Right
- S/PDIF 12
- Hardware Output Controls
- Monitor volume knob controlling Line 1+2
- No physical control for Line 3+4 output volume
- Headphone 1 volume knob controlling Headphone 1 Volume
- Headphone 2 volume knob controlling Headphone 2 Volume
- 4× Mute + Line Out Gain controls 127dB to 0dB
- 12 control Line 12 Out and Headphone 1
- 34 control Line 34 Out and Headphone 2
- Mixer: 18 input (118), 10 output (AJ)
- 18×10 gain controls 80dB to +6dB
- Each input assignable to any of the assignable outputs
- 6× PCM Inputs (USB device to host)
- 6× PCM Outputs (USB host to device)
- Assignable outputs to the hardware outputs, mixer, and PCM Inputs:
- Off, Analogue Inputs 14, S/PDIF 12, Mix AJ, PCM Outputs 16
- Sync Status
- Clock Source: Internal or S/PDIF
## 18i8 Gen 2
- 18× Hardware Inputs
- Analogue 12: Mic/Line/Inst In 12 (Pad)
- Analogue 34: Mic/Line In 34 (Pad)
- Analogue 58: Line In 58
- S/PDIF 12
- ADAT 18
- Hardware Input Controls
- 4× Input Gain knobs for Analogue In 14
- Fixed Input Gain for Analogue In 58
- Phantom Power for Analogue 12 linked
- Phantom Power for Analogue 34 linked
- 8× Hardware Outputs
- Analogue 1: Line 1 Out (Monitor L)
- Analogue 2: Line 2 Out (Monitor R)
- Analogue 3: Headphone 1 Left
- Analogue 4: Headphone 1 Right
- Analogue 5: Headphone 2 Left
- Analogue 6: Headphone 2 Right
- S/PDIF 12
- Hardware Output Controls
- Monitor volume knob controlling Line 1+2
- Headphone 1 volume knob controlling Headphone 1 Volume
- Headphone 2 volume knob controlling Headphone 2 Volume
- 6× Mute + Line Out Gain controls 127dB to 0dB
- 12 control Line 12 Out
- 34 control Headphone 1
- 56 control Headphone 2
- Mixer: 20 input (120), 10 output (AJ)
- 20×10 gain controls 80dB to +6dB
- Each input assignable to any of the assignable outputs
- 20× PCM Inputs (USB device to host)
- 8× PCM Outputs (USB host to device)
- Assignable outputs to the hardware outputs, mixer, and PCM Inputs:
- Off, Analogue Inputs 18, S/PDIF 12, ADAT 18, Mix AJ, PCM
Outputs 18
- Sync Status
- Clock Source: Internal, S/PDIF, or ADAT
## 18i20 Gen 2
- 18× Hardware Inputs
- Analogue 12: Mic/Line/Inst In 12 (Pad)
- Analogue 38: Mic/Line In 38
- S/PDIF 12
- ADAT 18
- Hardware Input Controls
- 8× Input Gain knobs for Analogue In 18
- Phantom Power for Analogue 14 linked
- Phantom Power for Analogue 58 linked
- 20× Hardware Outputs
- Analogue 1: Line 1 Out (Monitor L)
- Analogue 2: Line 2 Out (Monitor R)
- Analogue 3: Line 3 Out
- Analogue 4: Line 4 Out
- Analogue 5: Line 5 Out
- Analogue 6: Line 6 Out
- Analogue 7: Line 7 Out + Headphone 1 Left
- Analogue 8: Line 8 Out + Headphone 1 Right
- Analogue 9: Line 9 Out + Headphone 2 Left
- Analogue 10: Line 10 Out + Headphone 2 Right
- S/PDIF 12
- ADAT 18
- Hardware Output Controls
- For Analogue 18 Outputs:
- 8× SW/HW Volume Control Switch
- 8× SW Line Out Gain controls 127dB to 0dB
- 8× SW Mute
- Monitor volume knob controlling volume of Analogue 18 (selected
by SW/HW Volume Control Switches)
- Global Mute and Dim controlling Analogue 18 (enabled per-channel
if SW/HW Volume Control Switch set to HW)
- 2× Headphone volume knob controlling Headphone volume (applied in
addition to the SW/HW Volume Control)
- Mixer: 20 input (120), 10 output (AJ)
- 20×10 gain controls 80dB to +6dB
- Each input assignable to any of the assignable outputs
- 20× PCM Inputs (USB device to host)
- 18× PCM Outputs (USB host to device)
- Assignable outputs to the hardware outputs, mixer, and PCM Inputs:
- Off, Analogue Inputs 18, S/PDIF 12, ADAT 18, Mix AJ, PCM
Outputs 18
- Sync Status
- Clock Source: Internal, S/PDIF, or ADAT
## Solo Gen 3
- 2× Hardware Inputs
- Analogue In 1: Mic In (Air, Phantom Power)
- Analogue In 2: Line/Inst In
- Hardware Input Controls
- 2× Input Gain knobs for Analogue 12
- Phantom Power Persistence
- 2× Hardware Outputs
- Analogue Out 1: Line Out Left + Headphone Left
- Analogue Out 2: Line Out Right + Headphone Right
- Hardware Output Controls
- Monitor volume knob controls all outputs together
- 2× PCM Inputs (USB device to host)
- Fixed to Analogue Inputs 12
- 2× PCM Outputs (USB host to device)
- Fixed to Analogue Outputs 12
- Direct Monitor:
- On: mixes Analogue 1+2 Inputs into both Analogue 1+2 Outputs
## 2i2 Gen 3
- 2× Hardware Inputs
- Analogue In 12: Mic/Line/Inst In 12 (Air)
- Hardware Input Controls
- 2× Input Gain knobs for Analogue 12
- Phantom Power for Analogue 12 linked
- Phantom Power Persistence
- 2× Hardware Outputs
- Analogue Out 1: Line Out Left + Headphone Left
- Analogue Out 2: Line Out Right + Headphone Right
- Hardware Output Controls
- Monitor volume knob for Line Out Left and Right
- Headphone volume knob for Headphone
- 2× PCM Inputs (USB device to host)
- Fixed to Analogue Inputs 12
- 2× PCM Outputs (USB host to device)
- Fixed to Analogue Outputs 12
- Direct Monitor:
- Mono: mixes both Analogue 1+2 Inputs into both Analogue 1+2
Outputs
- Stereo: mixes Analogue 1+2 Inputs into Analogue 1+2 Outputs
respectively
## 4i4 Gen 3
- 4× Hardware Inputs
- Analogue In 12: Mic/Line/Inst In 12 (Air, Pad)
- Analogue In 34: Line In 34
- Hardware Input Controls
- 2× Input Gain knobs for Analogue In 12
- Fixed Input Gain for Analogue In 34
- Phantom Power for Analogue 12 linked
- Phantom Power Persistence
- 4× Hardware Outputs
- Analogue 1: Line 1 Out (Monitor L)
- Analogue 2: Line 2 Out (Monitor R)
- Analogue 3: Line 3 Out + Headphone Left
- Analogue 4: Line 4 Out + Headphone Right
- Hardware Output Controls
- Monitor volume knob controlling Line 1+2
- Headphone volume knob controlling Headphone volume
- No physical control for Line 3+4 output volume
- 4× Mute + Line Out Gain controls 127dB to 0dB
- 12 control Line 12 Out
- 34 control Line 34 Out and Headphone
- Mixer: 8 input (18), 6 output (AF)
- 8×6 gain controls 80dB to +6dB
- Each input assignable to any of the assignable outputs
- 6× PCM Inputs (USB device to host)
- 4× PCM Outputs (USB host to device)
- Assignable outputs to the hardware outputs, mixer, and PCM Inputs:
- Off, Analogue Inputs 14, Mix AF, PCM Outputs 14
- Sync Status
## 8i6 Gen 3
- 8× Hardware Inputs
- Analogue 12: Mic/Line/Inst In 12 (Air, Pad)
- Analogue 36: Line In 36
- S/PDIF 12
- Hardware Input Controls
- 2× Input Gain knobs for Analogue In 12
- Fixed Input Gain for Analogue In 36
- Phantom Power for Analogue 12 linked
- Phantom Power Persistence
- 6× Hardware Outputs
- Analogue 1: Line 1 Out (Monitor L) + Headphone 1 Left
- Analogue 2: Line 2 Out (Monitor R) + Headphone 1 Right
- Analogue 3: Line 3 Out + Headphone 2 Left
- Analogue 4: Line 4 Out + Headphone 2 Right
- S/PDIF 12
- Hardware Output Controls
- Monitor volume knob controlling Line 1+2
- No physical control for Line 3+4 output volume
- Headphone 1 volume knob controlling Headphone 1 Volume
- Headphone 2 volume knob controlling Headphone 2 Volume
- 4× Line Out Gain controls 127dB to 0dB
- 12 control Line 12 Out and Headphone 1
- 34 control Line 34 Out and Headphone 2
- Mixer: 8 input (18), 8 output (AH)
- 8×8 gain controls 80dB to +6dB
- Each input assignable to any of the assignable outputs
- 10× PCM Inputs (USB device to host)
- 6× PCM Outputs (USB host to device)
- Assignable outputs to the hardware outputs, mixer, and PCM Inputs:
- Off, Analogue Inputs 16, S/PDIF 12, Mix AH, PCM Outputs 16
- Sync Status
- Clock Source: Internal or S/PDIF
## 18i8 Gen 3
- 18× Hardware Inputs
- Analogue 12: Mic/Line/Inst In 12 (Air, Pad)
- Analogue 34: Mic/Line In 34 (Air, Pad)
- Analogue 58: Line In 58
- S/PDIF 12
- ADAT 18
- Hardware Input Controls
- 4× Input Gain knobs for Analogue In 14
- Fixed Input Gain for Analogue In 58
- Phantom Power for Analogue 12 linked
- Phantom Power for Analogue 34 linked
- Phantom Power Persistence
- 10× Hardware Outputs
- Analogue 1: Line 1 Out (Monitor L)
- Analogue 2: Line 2 Out (Monitor R)
- Analogue 3: Line 3 Out (Alt Monitor L)
- Analogue 4: Line 4 Out (Alt Monitor R)
- Analogue 5: Headphone 1 Left
- Analogue 6: Headphone 1 Right
- Analogue 7: Headphone 2 Left
- Analogue 8: Headphone 2 Right
- S/PDIF 12
Note: The Headphones outputs are internally Analogue 36 and the rear
Line 3/4 outputs (Alt Monitor) are internally Analogue 7/8, but the
driver hides this from you.
- Hardware Output Controls
- For Analogue 18 Outputs:
- 8× SW/HW Volume Control Switch
- 8× SW Line Out Gain controls 127dB to 0dB
- 8× SW Mute
- Monitor volume knob controlling volume of Analogue 18 (selected
by SW/HW Volume Control Switches)
- Global mute and dim controlling Analogue 18 (enabled per-channel
if SW/HW Volume Control Switch set to HW)
- 2× Headphone volume knob controlling Headphone volume (applied in
addition to the SW/HW Volume Control)
- Mixer: 18 input (118), 10 output (AJ)
- 18×10 gain controls 80dB to +6dB
- Each input assignable to any of the assignable outputs
- 18× PCM Inputs (USB device to host)
- 8× PCM Outputs (USB host to device)
- Assignable outputs to the hardware outputs, mixer, and PCM Inputs:
- Off, Analogue Inputs 18, S/PDIF 12, ADAT 18, Mix AJ, PCM
Outputs 120
- Speaker Switching
- Sync Status
- Clock Source: Internal, S/PDIF, or ADAT
## 18i20 Gen 3
- 19× Hardware Inputs
- Analogue 12: Mic/Line/Inst In 12 (Air, Pad)
- Analogue 38: Mic/Line In 38 (Air, Pad)
- Analogue 9: Talkback Mic
- S/PDIF 12
- ADAT 18
- Hardware Input Controls
- 8× Input Gain knobs for Analogue In 18
- Phantom Power for Analogue 14 linked
- Phantom Power for Analogue 58 linked
- Phantom Power Persistence
- 20× Hardware Outputs
- Analogue 1: Line 1 Out (Monitor L)
- Analogue 2: Line 2 Out (Monitor R)
- Analogue 3: Line 3 Out
- Analogue 4: Line 4 Out
- Analogue 5: Line 5 Out
- Analogue 6: Line 6 Out
- Analogue 7: Line 7 Out + Headphone 1 Left
- Analogue 8: Line 8 Out + Headphone 1 Right
- Analogue 9: Line 9 Out + Headphone 2 Left
- Analogue 10: Line 10 Out + Headphone 2 Right
- S/PDIF 12
- ADAT 18
- Hardware Output Controls
- For Analogue 18 Outputs:
- 8× SW/HW Volume Control Switch
- 8× SW Line Out Gain controls 127dB to 0dB
- 8× SW Mute
- Monitor volume knob controlling volume of Analogue 18 (selected
by SW/HW Volume Control Switches)
- Global Mute and Dim controlling Analogue 18 (enabled per-channel
if SW/HW Volume Control Switch set to HW)
- 2× Headphone volume knob controlling Headphone volume (applied in
addition to the SW/HW Volume Control)
- Mixer: 25 input (125), 12 output (AL)
- 25×12 gain controls 80dB to +6dB
- Each input assignable to any of the assignable outputs
- 20× PCM Inputs (USB device to host)
- 20× PCM Outputs (USB host to device)
- Assignable outputs to the hardware outputs, mixer, and PCM Inputs:
- Off, Analogue Inputs 18, S/PDIF 12, ADAT 18, Mix AL, PCM
Outputs 18
- Speaker Switching
- Talkback Mic
- Sync Status
- Clock Source: Internal, S/PDIF, or ADAT

View File

@@ -10,7 +10,7 @@ default:
@echo
@echo "If you want to build and install from source, please try:"
@echo " cd src"
@echo " make -j4"
@echo " make -j$(shell nproc)"
@echo " sudo make install"
@echo
@echo "This Makefile knows about packaging:"

View File

@@ -1,97 +1,8 @@
# ALSA Scarlett Gen 2/3 Control Panel (`alsa-scarlett-gui`)
# ALSA Scarlett Control Panel (`alsa-scarlett-gui`)
`alsa-scarlett-gui` is a Gtk4 GUI for the ALSA controls presented by
the Linux kernel Focusrite Scarlett Gen 2/3/Clarett USB/Clarett+ Mixer
Driver.
- Upstream project here: https://github.com/geoffreybennett/alsa-scarlett-gui
- Debian's packaged version here: https://salsa.debian.org/doge-tech/alsa-scarlett-gui
## About
This fork of the repo was started so I could write a Debian package manifest for the program. While I successfully made a working package, I had no intention of uploading it to the Debian archives -- I felt that I didn't have enough experience to bother the Debian maintainers with my nonsense. Someone else, however, [did upload one!](https://salsa.debian.org/doge-tech/alsa-scarlett-gui). That version has since been included with the Debian 13 release.
<img src="src/img/alsa-scarlett-gui-logo.png" align="right">
The Focusrite USB audio interfaces are class compliant meaning that
they work “out of the box” on Linux as audio and MIDI interfaces
(although on Gen 3/4 you need to disable MSD mode first for full
functionality). However, except for some of the smallest models, they
have a bunch of proprietary functionality that required a kernel
driver to be written specifically for those devices.
Linux kernel support (“ALSA Focusrite Scarlett Gen 2/3 Mixer Driver”)
for the proprietary functionality was first added in:
- 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 used to be quite an
awful experience. The existing applications like `alsamixer` and
`qasmixer` become completely user-hostile with the hundreds of
controls presented for the Gen 3 18i20. Even the smallest Gen 3 4i4
interface at last count had 84 ALSA controls.
Announcing the ALSA Scarlett Gen 2/3 (and Clarett USB/Clarett+!)
Control Panel!
![Demonstration](img/demo.gif)
The GUI supports all features presented by the driver (if not, please
report a bug).
## Documentation
Refer to [INSTALL.md](INSTALL.md) for prerequisites, how to build,
install, and run.
Refer to [USAGE.md](USAGE.md) for usage information and known issues.
## Donations
This program is Free Software, developed using my personal resources,
over hundreds of hours.
If you like this software, please consider a donation to say thank you
as it was expensive to purchase one of each model for development and
testing! Any donation is appreciated.
- https://liberapay.com/gdb
- https://paypal.me/gdbau
## 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
Copyright 2022-2023 Geoffrey D. Bennett
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
the Free Software Foundation, either version 3 of the License, or (at
your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
## Disclaimer Third Parties
Focusrite, Scarlett, Clarett, and Vocaster are trademarks or
registered trademarks of Focusrite Audio Engineering Limited in
England, USA, and/or other countries. Use of these trademarks does not
imply any affiliation or endorsement of this software.
I'm archiving this repo because it is redundant with that package. I want to keep it around as something I made, while also making it clear that this project is dead.

379
USAGE.md
View File

@@ -1,379 +0,0 @@
# ALSA Scarlett Gen 2/3 Control Panel Usage
Refer to [INSTALL.md](INSTALL.md) for prerequisites, how to build,
install, and run.
For usage instructions, read on...
## No interface connected
If no interface is detected (usually because there isnt one
connected!) youll see this window:
![No Interface Connected](img/iface-none.png)
Plug in an interface or select the menu option File → Interface
Simulation and load a demo file to make more interesting things
happen.
## MSD (Mass Storage Device) Mode
If MSD Mode is enabled (as it is from the factory), you need to
disable it and restart your interface to get access to its full
functionality.
![MSD Mode](img/iface-msd.png)
## Using on Small Interfaces
For the small Gen 3 interfaces (Solo and 2i2), theres just a few
buttons to control the Air, Line, Phantom Power, and Direct Monitor
settings. Mostly nothing that you cant access from the front panel
anyway.
![Gen 3 Small Interfaces](img/iface-small-gen3.png)
The Line/Inst (Level), Air, and 48V controls are described below in
the Analogue Input Controls section.
Direct Monitor sends the analogue input signals to the analogue
outputs for zero-latency monitoring. On the 2i2, you have the choice
of Mono or Stereo monitoring. Mono sends both inputs to the left and
right outputs. Stereo sends input 1 to the left, and input 2 to the
right output.
The one control not accessible from the front panel is “Phantom Power
Persistence” (menu option View → Startup) which controls the Phantom
Power state when the interface is powered on.
## Gen 2 6i6+, Gen 3 4i4+, Clarett USB, and Clarett+ Interfaces
The Gen 2 6i6+, Gen 3 4i4+, and Clarett interfaces have many controls
available. The controls are split between 4 windows, 3 of which are by
default hidden.
The main window has:
- Global Controls
- Analogue Input Controls
- Analogue Output Controls
![Main Window](img/window-main.png)
The View menu option on the main window lets you open three other
windows which contain the other controls:
- Routing
- Mixer
- Startup
### Global Controls
Global controls affect the operation of the interface as a whole.
#### Clock Source
Clock Source selects where the interface receives its digital clock
from. If you arent using S/PDIF or ADAT inputs, set this to Internal.
#### Sync Status
Sync Status indicates if the interface is locked to a valid digital
clock. If you arent using S/PDIF or ADAT inputs and the Sync Status
is Unlocked, change the Clock Source to Internal.
#### Speaker Switching (18i8 Gen 3 and 18i20 Gen 3 only)
Speaker Switching lets you swap between two pairs of monitoring
speakers very easily.
When enabled (Main or Alt):
- Line Out 14 Volume Control Switches are locked to HW
- Line Out 3/4 routing is saved
- Line Out 3/4 routing is set to the Line Out 1/2 routing
When set to Main, Line outputs 3 and 4 are muted.
When set to Alt, Line outputs 1 and 2 are muted.
When disabled (Off):
- Global mute is activated
- Line Out 14 Volume Control Switches are unlocked
- Line Out 3/4 routing is restored to the saved values
#### Talkback (18i20 Gen 3 only)
Talkback lets you add another channel (usually the talkback mic) to a
mix with a button push, usually to talk to musicians, and without
using an additional mic channel.
The Talkback feature has a few parts:
- Talkback Microphone connected to Analogue Input 9
- Talkback Disable/Enable internal switch
- Talkback Off/On physical switch
- Talkback Mix (one switch per mix)
- Mix Input 25
To set up the talkback feature, set Mix Input 25 to the talkback
source (usually Analogue Input 9), enable the Talkback Mix switches
for the mixes you want the talkback input to be heard on, and change
the Talkback control from Disabled to Off. Leave the Mix Input 25 gain
controls at zero (127dB), otherwise the talkback inputs will be heard
even when talkback is disabled/off.
Pressing the Talkback switch on the device will then lower the volume
of the other inputs on the mixes for which talkback is enabled and
unmute Mix Input 25 on those mixes.
Talkback can also be activated by changing the Talkback control from
Off to On.
The talkback microphone can also be used just the same as any of the
other analogue inputs and routed to a physical output, PCM input, or
mixer input.
### Analogue Input Controls
This is applicable to all interfaces except the Gen 2 18i20 which has
hardware-only buttons for these features.
#### Level
The Level buttons are used to select between Mic/Line and Instrument
level/impedance. When plugging in microphones or line-level equipment
to the input, set it to “Line”. The “Inst” setting is for instrument
with pickups such as guitars.
#### Air (Gen 3, Clarett USB, and Clarett+ only)
Enabling Air will transform your recordings and inspire you while
making music.
#### Pad
Enabling Pad engages an attenuator in the channel, giving you more
headroom for very hot signals.
#### Phantom Power (48V)
Gen 2 devices have a hardware button for controlling phantom power.
Gen 3 devices have hardware and software control of phantom power.
Turning the “48V” switch on sends “Phantom Power” to the XLR
microphone input. This is required for some microphones (such as
condensor microphones), and damaging to some microphones (particularly
vintage ribbon microphones).
On Gen 3 device, phantom power is turned off by default when the
interface is turned on. This can be changed in the startup
configuration (menu option View → Startup).
### Analogue Output Controls
The analogue output controls let you set the output volume (gain) on
the analogue line out and headphone outputs. All interfaces support
setting the gain and muting individual channels.
Click and drag up/down to change the volume, or use your mouse scroll
wheel. You can also double-click on the volume dial to quickly toggle
the volume between the minimum value and 0dB.
The bigger interfaces: Gen 2 18i20, Gen 3 18i8, and Gen 3 18i20 have a
switchable hardware/software volume control. The position of the big
volume knob on the front of the interface is indicated by the “HW”
dial in the GUI. The analogue outputs can have their volume set either
by the knob (“HW” setting of of the HW/SW button) or by the dials on
each output (“SW” setting of the HW/SW button).
When set to HW, the mute/volume status for those channels is
controlled by the hardware volume knob and the global dim/mute
controls and the software volume dial and mute button for those
channels are disabled.
There are “mute” and “dim” (reduce volume) buttons below the “HW” dial
which affect only the outputs with “HW” control enabled. The Gen 3
18i8 doesnt have physical buttons or indicator lights for these
controls, but the 18i20 devices do.
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
in addition to the software volume control, therefore both must be
turned up in order to hear anything. The other (line 3+) analogue
outputs are only controlled by the software controls.
The volume controls for the headphone outputs on each interface
operate in addition to any other hardware or software volume controls
for those channels. When using headphones, the volumes for those
channels would usually be set to 0dB and the actual volume controlled
with the physical headphone volume control(s).
### Routing
The routing window allows complete control of signal routing between
the hardware inputs/outputs, internal mixer, and PCM (USB)
inputs/outputs.
![Routing Window](img/window-routing.png)
To manage the routing connections:
- Click and drag from a source to a sink or a sink to a source to
connect them. Audio from the source will then be sent to that sink.
- Click on a source or a sink to clear the links connected to that
source/sink.
Note that a sink can only be connected to one source, but one source
can be connected to many sinks. If you want a sink to receive input
from more than one source, use the mixer inputs and outputs.
The Presets menu can be used to clear all connections, or to set up
common configurations:
- The “Direct” preset sets up the usual configuration using the
interface as an audio interface by connecting:
- all Hardware Inputs to PCM Inputs
- all PCM Outputs to Hardware Outputs
- The “Preamp” preset connects all Hardware Inputs to Hardware Outputs.
- The “Stereo Out” preset connects PCM 1 and 2 Outputs to pairs of
Hardware Outputs.
The Direct routing configuration is the simplest most-generally-useful
configuration:
![Direct Routing](img/routing-direct.png)
#### Loopback
Gen 2, Clarett USB, and Clarett+ interfaces have as many PCM Inputs as
Hardware Inputs. Gen 3 interfaces have two more PCM Inputs which
Focusrite Control uses as “Loopback” inputs.
The “Loopback” feature advertised for Gen 3 devices is actually a
limitation of the proprietary Focusrite Control software. All devices
(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
source.
#### Talkback
The Gen 3 18i20 talkback microphone is Analogue Input 9 and can be
routed like any other source. If you want to record using it, there is
no need for the loopback hack suggested by the vendor. Just route it
to a PCM Input.
### Mixer
If you use the Routing window to connect Sources to Mixer Inputs and
Mixer Outputs to Sinks, then you can use the Mixer window to set the
amount of each Mixer Input that is sent to each Mixer Output using a
matrix of controls:
![Mixer Window](img/window-mixer.png)
Click and drag up/down on the gain controls to adjust, or use your
mouse scroll wheel. You can also double-click on the dial to quickly
toggle between the minimum value and 0dB.
### Startup
The Startup window is used to configure settings that only take effect
when the interface is powered on.
![Startup Window](img/window-startup.png)
#### Standalone
When Standalone mode is enabled, the interface will continue to route
audio as per the previous routing and mixer settings after it has been
disconnected from a computer. By configuring the routing between the
hardware and mixer inputs and outputs appropriately, the interface can
act as a standalone preamp or mixer.
Standalone mode is supported on all devices supported by the kernel
driver. Even the 4i4 Gen 3 (which is bus-powered) will operate in
standalone mode.
#### Phantom Power Persistence (Gen 3 only)
When Phantom Power Persistence is enabled, the interface will restore
the previous Phantom Power/48V setting when the interface is turned
on. For the safety of microphones which can be damaged by phantom
power, the interface defaults to having phantom power disabled when it
is turned on.
#### MSD (Mass Storage Device) Mode (Gen 3 only)
When MSD Mode is enabled (as it is from the factory), the interface
has reduced functionality. Youll want to have this disabled. On the
other hand, when MSD Mode is enabled, the interface presents itself as
a Mass Storage Device (like a USB stick), containing a link to the
Focusrite web site encouraging you to register your product and
download the proprietary drivers which cant be used on Linux.
By default, once MSD Mode is disabled, the control for it is hidden.
If for some reason you want to re-enable MSD Mode, you can set the
`device_setup` option to 3 to get the control back.
## Load/Save Configuration
The entire state of the interface can be loaded and saved using the
File → Load Configuration and File → Save Configuration menu options.
Internally, this uses `alsactl`:
- Load: `alsactl restore USB -f <fn>`
- Save: `alsactl store USB -f <fn>`
The saved state files can be used to simulate an interface if you
dont have one attached. The `demo` directory in the distribution
contains a sample file for every supported model.
## Interface Simulation Mode
The GUI can load an `alsactl` state file saved from a real interface
and display a GUI as if the corresponding interface was connected.
This is useful if you dont have an interface connected and want to
try, develop, or debug the GUI.
Either specify the `.state` filename on the command line or select the
menu option File → Interface Simulation to load.
## Known Bugs/Issues
- The linear-dB scale of the volume controls doesnt work well. Lower
volumes (e.g. below 30dB) dont need as much fine control as higher
volumes.
- Cant select (focus) the gain/volume controls or use a keyboard to
adjust them.
- Level meters dont work if you're not running the driver from Linux
6.7.
- Load/Save uses `alsactl` which will be confused if the ALSA
interface name (e.g. `USB`) changes.
- Load/Save is not implemented for simulated interfaces.
- Lots of “couldn't find weak ref” warnings are emitted when loading a
state file for simulation.
- The read-only status of controls in interface simulation mode does
not change when the HW/SW button is clicked.
- When theres more than one main window open, closing one of them
doesnt free and close everything related to that card.
- There is no facility to group channels into stereo pairs (needs
kernel support to save this information in the interface).
- There is no facility to give channels custom names (needs kernel
support to save this information in the interface).
- No keyboard accelerators (e.g. Ctrl-Q to quit) have been
implemented.

View File

@@ -1,33 +1,29 @@
Summary: ALSA Scarlett Gen 2/3 Control Panel
Name: alsa-scarlett-gui
Version: VERSION
Release: 1%{?dist}
License: GPLv3+ LGPLv3+
Url: https://github.com/geoffreybennett/alsa-scarlett-gui
Source: %{name}-%{version}.tar.gz
Summary: ALSA Scarlett Control Panel
Name: alsa-scarlett-gui
Version: VERSION
Release: 1%{?dist}
License: GPLv3+ LGPLv3+
Url: https://github.com/geoffreybennett/alsa-scarlett-gui
Source0: https://github.com/geoffreybennett/alsa-scarlett-gui/archive/refs/tags/%{version}.tar.gz?/%{name}-%{version}.tar.gz
BuildRequires: pkgconfig(alsa)
BuildRequires: pkgconfig(gtk4)
BuildRequires: pkgconfig(openssl)
%description
alsa-scarlett-gui is a Gtk4 GUI for the ALSA controls presented by the
Linux kernel Focusrite Scarlett Gen 2/3 Mixer Driver.
Linux kernel Focusrite USB drivers.
%prep
%setup
%setup -q -n %{name}-%{version}/src
%build
make -C src -j4 VERSION=%{version} PREFIX=/usr
%make_build VERSION=%{version} PREFIX=%{_prefix}
%install
%make_install -C src PREFIX=/usr
DOCDIR=%{buildroot}/usr/share/doc/%{name}-%{version}
mkdir -p $DOCDIR/img
mkdir $DOCDIR/demo
cp *.md $DOCDIR
cp img/* $DOCDIR/img
cp demo/* $DOCDIR/demo
%make_install PREFIX=%{_prefix}
%files
%doc /usr/share/doc/%{name}-%{version}
/usr/bin/alsa-scarlett-gui
/usr/share/applications/vu.b4.alsa-scarlett-gui.desktop
/usr/share/icons/hicolor/256x256/apps/vu.b4.alsa-scarlett-gui.png
%doc ../img ../demo ../docs ../*.md
%{_bindir}/alsa-scarlett-gui
%{_datadir}/applications/vu.b4.alsa-scarlett-gui.desktop
%{_iconsdir}/hicolor/256x256/apps/vu.b4.alsa-scarlett-gui.png

410
debian/changelog vendored Normal file
View File

@@ -0,0 +1,410 @@
alsa-scarlett-gui (0.5.1-1) unstable; urgency=medium
[ Geoffrey D. Bennett ]
* Add RTFM advice to FAQ.md
* Replace '/" with /“/” in *.md
* Add information about alsa-state and alsa-restore to FAQ.md
[ Pro-pra ]
* Use template spec with macros
[ Geoffrey D. Bennett ]
* Improve "settings keep resetting" FAQ entry
* Replace 1st Gen Startup Controls info with Startup Configuration
* Disable the startup menu option for 1st Gen devices
* Move card init from alsa_scan_cards() to new card_init() function
* Add driver type detection
* Add support for waiting for FCP driver initialisation
* Don't attempt to attach unused routing_mixer_in_grid
* Replace hwdep check in window-startup.c with driver_type check
* Add support for rebooting devices using the FCP socket interface
* Update window-hardware with big 4th Gen and Vocaster models
* Change alsa_get_elem_int_values() to return longs rather than ints
[ runiq ]
* Add alsactl utility
* Remove superfluous files from Flatpak
* More Flatpak manifest cleanup
[ Robert Garrett ]
* Change default compression to xz level 9
-- Robert Garrett <robertgarrett404@gmail.com> Mon, 09 Jun 2025 22:37:54 -0500
alsa-scarlett-gui (0.5.0-1) unstable; urgency=medium
[ Geoffrey D. Bennett ]
* Move 4th Gen Solo 48V switch above the Air switch
[ Giorgio Reale ]
* Add 4rd Gen models to window-hardware.c
[ Geoffrey D. Bennett ]
* Fix widget-boolean.c to free data on button destruction
* Add Arch package dependency
* Fix Sample Rate button to be insensitive
* Override focus and colour CSS button styles
* Search $PATH and /usr/sbin for alsactl
* Add support for volatile buttons to widget-boolean.c
* Allow for boolean controls that are backwards
* Update widget-boolean to cache the icon widgets
* Switch to embedded SVG icons
[ Guillaume ]
* Add missing GTK and ALSA dependencies on deb package
[ Geoffrey D. Bennett ]
* Add -fPIE and -pie build flags to fix flatpak build under Fedora
* Download and include scarlett2 firmware in flatpak
* Make flatpak build faster
* Fix up deb and RPM package description & add docs
* Move level meter fields out of struct alsa_card
* Add peak display to the level meters
* Use snprintf() in widget-gain.c when printing floats
* Add peak value display to the level meters
* Fix link from FAQ.md to INSTALL.md
* Add const to get*elem*() char* function arguments
* Add 3rd Gen 18i8/18i20 S/PDIF/Digital I/O Mode startup controls
[ unhappy-ending ]
* Update Makefile to use $(CC) rather than cc
[ Geoffrey D. Bennett ]
* Replace cairo_show_text() in gtkdial.c with Pango
* Fix crash in window-level.c on_destroy()
* Update flatpak to GNOME 47
* Update logo
* Add get_elem_by_substr() to alsa.[ch]
* Add Scarlett 1st Gen demo state files
* Gen 1: Handle different names for clock source and sync status
* Gen 1: Mute switches are backwards
* Gen 1: Add 1st Gen devices to window-hardware.c
* Gen 1: Trigger support based on "Matrix" element presence
* Gen 1: Add PC_OFF port category
* Gen 1: Ignore control "index" value in saved configurations
* Gen 1: Parse and save config count field
* Gen 1: Move alsa-sim elem creation into alsa_config_to_new_elem()
* Gen 1: Add support for elements with count > 1 in saved config
* Gen 1: Add support for 1st Gen stereo elements
* Gen 1: Add support for 1st Gen mixer controls
* Gen 1: Add support for 1st Gen input controls
* Gen 1: Add support for 1st Gen output controls
* Wrap long line, fix reopen callback comment in alsa.c
* Update constants for new maximum number of mux inputs and meters
* Treat locked ALSA elements as read-only
* Handle interfaces with fixed mixer inputs
* Handle per-channel link buttons
* Update routing hover to highlight corresponding source sink
* Highlight mixer labels on dial hover
* Update gtkdial to support linear-volume controls
* Update alsa interface and gain widget to support linear volume
* Make perror("fopen") messages distinct
* Add support for two-control speaker switching and talkback
* Add support for new 4th Gen control names
* Simplify update_levels_controls()
* Add support for TLVs from the FCP driver
* Update alsa.c to handle differing FCP mixer element names
* Add support for Level Meter labels
* Fix output control column/mute tooltip handling
* Move card_destroy_callback() before alsa_card_callback()
* Call card_destroy_callback() when an ALSA element is removed
* Bump copyright year to 2025
* Update docs and such for 1st Gen and big 4th Gen support
* Add big 4th Gen demo files
* Make make clean do depclean too
* Undefine _FORTIFY_SOURCE before defining so GitHub can build the deb
* Update flatpak container image from gnome-45 to gnome-47
* Remove unused start_x, start_y from gtk_dial_drag_gesture_update()
* Add small deadband to dial drag to stop double-click adjustments
* Replace -j4 with -j$(nproc)
* Update 1st Gen doc to mention Level Meters and Startup Controls
* Update startup window no-startup-controls message
-- Robert Garrett <robertgarrett404@gmail.com> Mon, 09 Jun 2025 22:09:31 -0500
alsa-scarlett-gui (0.4.0-1) UNRELEASED; urgency=low
[ Guillaume ]
* Fix deb package icon install
[ Geoffrey D. Bennett ]
* Update Makefile to get version from $APP_VERSION
* Global replace "destination" with "sink"
[ fenugrec ]
* Replace deprecated gtk_widget_{show,hide} calls
* Reduce code duplication in menu.c
[ Geoffrey D. Bennett ]
* Add Clarett USB/Clarett+ models to window-hardware.c
* Pass APP_VERSION through flatpak-builder
* Check Firmware Version before enabling Levels menu item
* Remove user-control of level meters
* Improve layout for larger interfaces without speaker switching
* Fix the socket widget so that it will not shrink
* Allow the routing window to be resized and give it scrollbars
* Fix typo rounting -> routing
* Update drag_motion() to scroll the routing window
[ sporksnail ]
* src/Makefile: Respect CFLAGS from environment
[ Geoffrey D. Bennett ]
* Update README.md with Gen 4 info
* Update software name in INSTALL.md and USAGE.md
* Add info to INSTALL.md on how to check the kernel version
* Add Gtk4 info to INSTALL.md
* Fix typo in INSTALL.md driver disabled message
[ Jason A. Donenfeld ]
* Makefile: prefer distro cflags if specified
[ Geoffrey D. Bennett ]
* Add initial version of FAQ.md
* Add FUNDING.yml
* Add issue template
* Add Clarett info to INTERFACES.md
* Add TOC to INTERFACES.md
* Add link from USAGE.md to INTERFACES.md
* Allow the mixer window to be resized and give it scrollbars
* Update FAQ with more MSD info
* Fix long lines
* Add OpenSUSE package requirements
* Fix typo in INSTALL.md: comitting -> committing
* Move FUNDING.yml to the right spot
[ Jason A. Donenfeld ]
* gtkdial: use fabs() for double
[ Trent ]
* Add keyboard accelerators (aka shortcuts, hotkeys) for menu items.
[ Geoffrey D. Bennett ]
* Reformat keyboard accelerators to match existing code
* Remove keyboard accelerator mention from USAGE.md
* Split calc_valp() into calc_valp() and calc_valp_log()
* Fix dial to grab focus when clicked
* Fix dial to display focus indication
[ Nate Gallaher ]
* Clarify pad tooltip to specify attenuation amount
[ Geoffrey D. Bennett ]
* Remove gtk_widget_add_class()
* Fix is_elem_routing_snk() for Gen 4
* Remove lots of casts in create_routing_grid()
* Make the Level Meter check compatible with alsa-sim.c
* Remove repeated group by code in create_routing_grid()
* Add orientation parameter to routing_grid_label()
* Inline routing_grid_label() in create_routing_group_grid()
* Fix Presets button to be centered
* Add margin to socket widget
* Add support for routing the Gen 4 DSP I/O
* Allow for phantom power per-channel
* Remove hard-coded values from widget-gain.c and widget-volume.c
* Combine gain and volume widgets
* Center-align text in combo boxes
* Make boolean widget boolify value from alsa_get_elem_value()
* Explicitly order main window controls
* Add 4th Gen input controls
* Remove widgets from struct alsa_elem and add data to callbacks
* Add input select widget for 4th Gen 2i2 and 4i4
* Add 4th Gen 4i4 headphone volume knob control
* Add missing GtkDial scroll_begin() implementation
* Add bindings for pgup/pgdn/home/end to GtkDial
* Display -inf when volume/gain controls are at zero/off
* Don't round level meter values passed to GtkDial
* Fix widget-combo to check if the alsa elem is writable
* Simplify GtkDial calculations
* Bump copyright year
* Remove unused GtkDialFormatValueFunc from gtkdial.h
* Remove unused guint8 and gsize from gtkdial.c
* Remove irrelevant GDK_AVAILABLE_IN_ALL from gtkdial.h
* Reformat gtkdial.c to match rest of code
* Fix GtkDial:zero_db property comment
* Add scale to widget-gain.c struct gain
* Fix gtk_dial_new_with_range() to use calculated round_digits
* Allow for continuous dials
* Add page argument to gtk_dial_new_with_range()
* Fix typo range->dial in gtkdial.[ch]
* Remove inline from functions in gtkdial.c
* Move valp clamp and scale from calc_valp_log() to calc_valp()
* Add configurable taper to GtkDial
* Add support for piecewise linear interpolation taper to GtkDial
* Make GtkDial look better
* Make GtkDial dimmer if insensitive
* Remove bool_text from struct alsa_elem
* Move label into boolean controls and use button state to show status
* Remove "Analogue" from small Gen 3 device input labels
* Use CSS to set dark colour scheme
* Rewrite choose_line_colour() to work with a dark background
* Move 4th Gen Solo Air control up to be next to Inst control
* Add CSS classes to controls and add more colour
* Add widget-drop-down for Air
* Switch Clock Source to widget-drop-down
* Add 4th Gen Solo/2i2 Direct Monitor controls
* Add power status control for 4th Gen 4i4
* Update 3rd Gen Solo Direct Monitor control to match 4th Gen
* Remove now-unused widget-combo
* Add some red and grey
* Update about, etc. messages to include Gen 4/Clarett
* Add CSS for buttons that get dimmer when checked
* Use GtkTextView instead of GtkLabel in startup big_label()
* Add draw_slider() to remove some common code from dial_snapshot()
* Add GtkDial:can_control property
* Add 4th Gen Solo Mix switch
* Add off_db (deadband) to GtkDial for quiet signals
* Use GtkDial off_db (deadband) for level meters
* Remove struct dial_properties; cache values in struct _GtkDial
* Allow GtkDial to shrink more and reduce slider thickness
* Fix GtkDial to not recreate the cairo patterns on every draw
* Add colour to GtkDial level meters
* Prefix CSS styles so they don't apply to other windows
* Update the gain widget to support updating direct monitor mix controls
* Add routing group tooltips
* Fix GtkDial to not redraw the dial if the set value doesn't change
* Fix GtkDial to redraw on notify::sensitive signal
* Add red focus outline to GtkDial
* CSS fixes for buttons
* Retrieve and store the device serial number
* Don't export alsa_cards from alsa.c
* Add support for config reset
* Retrieve and store the device USB PID
* Move -lm into LDFLAGS
* Add support for firmware update
[ Antti-Pekka Meronen ]
* Include openssl-devel in Fedora installation instructions
[ Geoffrey D. Bennett ]
* Update OpenSUSE and Ubuntu package dependencies
* Remove fixed/mentioned-elsewhere issues from USAGE.md
* Don't set transient on modal window
* Make gain widget dB numbers smaller
* Add 4th Gen Solo, 2i2, and 4i4 demo files
* Don't show empty rows in levels window
* If there's an MSD control, add a reboot control too
* Reduce GtkDial circle brightness
* Make window-helper.c close the window when Esc is pressed
* Add missing static to populate_submenu() in menu.c
* Add gtk_widget_remove_css_classes_by_prefix() helper
* Add display of sample rate
* Display "+" before positive dB values in the gain widget
* Update gain widget to show no decimal places for scale > 0.5
* Add initial support for the Vocaster One and Two
* Store the best_firmware_version in struct alsa_card
* Prompt for firmware update if in MSD Mode and an update is available
* Add firmware info to the INSTALL.md Prerequisites section
* Update About dialog
* Update documentation for Scarlett 4th Gen and Vocaster
[ Robert Garrett ]
* Add build-depends on libssl-dev
-- Robert Garrett <robertgarrett404@gmail.com> Mon, 09 Jun 2025 21:57:36 -0500
alsa-scarlett-gui (0.3-1) UNRELEASED; urgency=low
[ Geoffrey D. Bennett ]
* Fix format-security warning in error.c
[ Sebastian Kaminski ]
* Fixed typo for 18i20 Gen 3 Mic/Line 3-8
[ Szabolcs Szőke ]
* Make routing sources and destinations the same width
[ Geoffrey D. Bennett ]
* Clarify comments and variable names in choose_line_colour()
[ Sebastian Kaminski ]
* Prevent the boolean widget from changing size when toggled
[ Geoffrey D. Bennett ]
* Add Ubuntu install and git download instructions
* Add Clarett support
* Fix typos in USAGE.md
* Fix building with Gtk 4.10
* Update README.md and USAGE.md with current driver information
* Add link to fundraiser for adding Scarlett Gen 4 support
* Fix input counting for Clarett+ series
* Update README and USAGE files with new Clarett info
* Split USAGE.md into INSTALL.md and USAGE.md
* Add Clarett Plus 2Pre and 4Pre demo files
* Update Clarett USB and Clarett+ status
* Apply correction curve to the dials
* Update README with Gen 4 and Vocaster info
* Specify full path to alsactl
[ David Cooper ]
* Add keyword to desktop file
[ Alejandro Domínguez ]
* Change icon file name
* Do not use deprecated or non-standard keys in desktop file
* Enable Flatpak packaging support
[ Guillaume ]
* Fix Error: icon alsa-scarlett-gui not found below...
* Remove commented rename-icon property
* Using github.com/flatpak/flatpak-github-actions
[ Geoffrey D. Bennett ]
* Fix iface-none.png image description
* Move flatpak instructions to INSTALL.md
* Update flatpak to gnome 45
* Add org.gnome.Platform and flathub to flatpak instructions
* Update INSTALL and README with Linux 6.7 info
[ sporksnail ]
* window-startup.c: fix typo
[ Geoffrey D. Bennett ]
* Add meter/level display
[ Guillaume ]
* Github action to build debian package on release
[ Robert Garrett ]
* Merge upstream version 0.3 & release package
-- Robert Garrett <robertgarrett404@gmail.com> Mon, 09 Jun 2025 20:36:56 -0500
alsa-scarlett-gui (0.2-1) UNRELEASED; urgency=low
[ Geoffrey D. Bennett ]
* Note lack of keyboard accelerators
* Add demo GIF
* Fix size of mixer output sockets on Gen 3 18i20 routing
* Reduce button padding as intended
* Display input labels across the top of the mixer window
* Reformat CSS to not be so squishy
* Change route-label hover background colour to work with dark theme
* Add desktop and icon files and install into the correct place
* Add copyright info to the Makefile
* Don't hardcode the version number in the about dialog
[ KottV ]
* Fix linking in OBS
[ Geoffrey D. Bennett ]
* Add help target to src/Makefile
* Add top-level Makefile and RPM spec file for packaging
[ Robert Garrett ]
* Drop the backported link ordering patch
* Update changelog via gbp dch
* Create a copyright file
* Adjust the copyright file a bit...
-- Robert Garrett <robertgarrett404@gmail.com> Mon, 09 Jun 2025 20:21:13 -0500
alsa-scarlett-gui (0.1-1) UNRELEASED; urgency=low
* Initial revision, starting up a package manifest.
* Drop pbuilder settings from gbp.conf
* Set upstream version tag in gbp.conf
* Name upstream and debian branches properly
* Backport a link order fix from upstream
-- Robert Garrett <robertgarrett404@gmail.com> Mon, 09 Jun 2025 19:37:00 -0500

16
debian/control vendored Normal file
View File

@@ -0,0 +1,16 @@
Source: alsa-scarlett-gui
Maintainer: Robert Garrett <robertgarrett404@gmail.com>
Section: misc
Priority: optional
Standards-Version: 4.6.2
Build-Depends:
debhelper-compat (= 13),
libasound2-dev,
libgtk-4-dev,
libssl-dev,
Package: alsa-scarlett-gui
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}
Description: GUI tool for Scarlett audio interfaces.
Uses an ALSA backend.

34
debian/copyright vendored Normal file
View File

@@ -0,0 +1,34 @@
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Source: https://github.com/geoffreybennett/alsa-scarlett-gui
Upstream-Name: alsa-scarlett-gui
Upstream-Contact: Geoffrey D. Bennet <g@b4.vu>
License: GPL-3.0-or-later or LGPL-3+
Files: *
Copyright:
2022-2025 Geoffrey D. Bennet <g@b4.vu>
2022 KottV <kv@kott.no-ip.biz>
License: GPL-3+
Files:
debian/*
Copyright: 2024-2025 Robert Garrett
License: GPL-3+
License: GPL-3.0+
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
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
.
On Debian systems, the full text of the GNU General Public
License Version 3 can be found in the file
`/usr/share/common-licenses/GPL-3`

8
debian/gbp.conf vendored Normal file
View File

@@ -0,0 +1,8 @@
[DEFAULT]
compression = xz
compression-level = 9
upstream-branch = master
debian-branch = deb
upstream-tag = %(version)s
pristine-tar = False

5
debian/rules vendored Executable file
View File

@@ -0,0 +1,5 @@
#!/usr/bin/make -f
%:
PREFIX=/usr dh $@ --sourcedirectory=src/

1
debian/source/format vendored Normal file
View File

@@ -0,0 +1 @@
3.0 (quilt)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,997 @@
state.Gen {
control.1 {
iface PCM
name 'Playback Channel Map'
value.0 0
value.1 0
comment {
access read
type INTEGER
count 2
range '0 - 36'
}
}
control.2 {
iface PCM
name 'Capture Channel Map'
value.0 0
value.1 0
value.2 0
value.3 0
comment {
access read
type INTEGER
count 4
range '0 - 36'
}
}
control.3 {
iface CARD
name 'USB Internal Validity'
value true
comment {
access read
type BOOLEAN
count 1
}
}
control.4 {
iface CARD
name 'Firmware Version'
value 2115
comment {
access read
type INTEGER
count 1
range '0 - 0'
}
}
control.5 {
iface CARD
name 'Minimum Firmware Version'
value 2115
comment {
access read
type INTEGER
count 1
range '0 - 0'
}
}
control.6 {
iface MIXER
name 'MSD Mode Switch'
value false
comment {
access 'read write'
type BOOLEAN
count 1
}
}
control.7 {
iface MIXER
name 'Line In 1 Level Capture Enum'
value Line
comment {
access 'read write'
type ENUMERATED
count 1
item.0 Line
item.1 Inst
}
}
control.8 {
iface MIXER
name 'Line In 2 Level Capture Enum'
value Line
comment {
access 'read write'
type ENUMERATED
count 1
item.0 Line
item.1 Inst
}
}
control.9 {
iface MIXER
name 'Line In 1 Air Capture Enum'
value Off
comment {
access 'read write'
type ENUMERATED
count 1
item.0 Off
item.1 Presence
item.2 'Presence + Drive'
}
}
control.10 {
iface MIXER
name 'Line In 2 Air Capture Enum'
value Off
comment {
access 'read write'
type ENUMERATED
count 1
item.0 Off
item.1 Presence
item.2 'Presence + Drive'
}
}
control.11 {
iface MIXER
name 'Line In 1-2 Phantom Power Capture Switch'
value false
comment {
access 'read write'
type BOOLEAN
count 1
}
}
control.12 {
iface MIXER
name 'Input Select Capture Enum'
value 'Input 1'
comment {
access 'read write'
type ENUMERATED
count 1
item.0 'Input 1'
item.1 'Input 2'
}
}
control.13 {
iface MIXER
name 'Line In 1 Gain Capture Volume'
value 9
comment {
access 'read write'
type INTEGER
count 1
range '0 - 70 (step 1)'
dbmin -7000
dbmax 0
dbvalue.0 -6100
}
}
control.14 {
iface MIXER
name 'Line In 1 Autogain Capture Switch'
value false
comment {
access 'read write'
type BOOLEAN
count 1
}
}
control.15 {
iface MIXER
name 'Line In 1 Autogain Status Capture Enum'
value Stopped
comment {
access read
type ENUMERATED
count 1
item.0 Stopped
item.1 Running
item.2 Failed
item.3 Cancelled
item.4 Unknown
}
}
control.16 {
iface MIXER
name 'Line In 1 Safe Capture Switch'
value false
comment {
access 'read write'
type BOOLEAN
count 1
}
}
control.17 {
iface MIXER
name 'Line In 1-2 Link Capture Switch'
value false
comment {
access 'read write'
type BOOLEAN
count 1
}
}
control.18 {
iface MIXER
name 'Line In 2 Gain Capture Volume'
value 9
comment {
access 'read write'
type INTEGER
count 1
range '0 - 70 (step 1)'
dbmin -7000
dbmax 0
dbvalue.0 -6100
}
}
control.19 {
iface MIXER
name 'Line In 2 Autogain Capture Switch'
value false
comment {
access 'read write'
type BOOLEAN
count 1
}
}
control.20 {
iface MIXER
name 'Line In 2 Autogain Status Capture Enum'
value Stopped
comment {
access read
type ENUMERATED
count 1
item.0 Stopped
item.1 Running
item.2 Failed
item.3 Cancelled
item.4 Unknown
}
}
control.21 {
iface MIXER
name 'Line In 2 Safe Capture Switch'
value false
comment {
access 'read write'
type BOOLEAN
count 1
}
}
control.22 {
iface MIXER
name 'Analogue Output 01 Playback Enum'
value 'Mix A'
comment {
access 'read write'
type ENUMERATED
count 1
item.0 Off
item.1 'Analogue 1'
item.2 'Analogue 2'
item.3 'Mix A'
item.4 'Mix B'
item.5 'Mix C'
item.6 'Mix D'
item.7 'DSP 1'
item.8 'DSP 2'
item.9 'PCM 1'
item.10 'PCM 2'
}
}
control.23 {
iface MIXER
name 'Analogue Output 02 Playback Enum'
value 'Mix B'
comment {
access 'read write'
type ENUMERATED
count 1
item.0 Off
item.1 'Analogue 1'
item.2 'Analogue 2'
item.3 'Mix A'
item.4 'Mix B'
item.5 'Mix C'
item.6 'Mix D'
item.7 'DSP 1'
item.8 'DSP 2'
item.9 'PCM 1'
item.10 'PCM 2'
}
}
control.24 {
iface MIXER
name 'Mixer Input 01 Capture Enum'
value 'PCM 1'
comment {
access 'read write'
type ENUMERATED
count 1
item.0 Off
item.1 'Analogue 1'
item.2 'Analogue 2'
item.3 'Mix A'
item.4 'Mix B'
item.5 'Mix C'
item.6 'Mix D'
item.7 'DSP 1'
item.8 'DSP 2'
item.9 'PCM 1'
item.10 'PCM 2'
}
}
control.25 {
iface MIXER
name 'Mixer Input 02 Capture Enum'
value 'PCM 2'
comment {
access 'read write'
type ENUMERATED
count 1
item.0 Off
item.1 'Analogue 1'
item.2 'Analogue 2'
item.3 'Mix A'
item.4 'Mix B'
item.5 'Mix C'
item.6 'Mix D'
item.7 'DSP 1'
item.8 'DSP 2'
item.9 'PCM 1'
item.10 'PCM 2'
}
}
control.26 {
iface MIXER
name 'Mixer Input 03 Capture Enum'
value 'DSP 1'
comment {
access 'read write'
type ENUMERATED
count 1
item.0 Off
item.1 'Analogue 1'
item.2 'Analogue 2'
item.3 'Mix A'
item.4 'Mix B'
item.5 'Mix C'
item.6 'Mix D'
item.7 'DSP 1'
item.8 'DSP 2'
item.9 'PCM 1'
item.10 'PCM 2'
}
}
control.27 {
iface MIXER
name 'Mixer Input 04 Capture Enum'
value 'DSP 2'
comment {
access 'read write'
type ENUMERATED
count 1
item.0 Off
item.1 'Analogue 1'
item.2 'Analogue 2'
item.3 'Mix A'
item.4 'Mix B'
item.5 'Mix C'
item.6 'Mix D'
item.7 'DSP 1'
item.8 'DSP 2'
item.9 'PCM 1'
item.10 'PCM 2'
}
}
control.28 {
iface MIXER
name 'DSP Input 1 Capture Enum'
value 'Analogue 1'
comment {
access 'read write'
type ENUMERATED
count 1
item.0 Off
item.1 'Analogue 1'
item.2 'Analogue 2'
item.3 'Mix A'
item.4 'Mix B'
item.5 'Mix C'
item.6 'Mix D'
item.7 'DSP 1'
item.8 'DSP 2'
item.9 'PCM 1'
item.10 'PCM 2'
}
}
control.29 {
iface MIXER
name 'DSP Input 2 Capture Enum'
value 'Analogue 2'
comment {
access 'read write'
type ENUMERATED
count 1
item.0 Off
item.1 'Analogue 1'
item.2 'Analogue 2'
item.3 'Mix A'
item.4 'Mix B'
item.5 'Mix C'
item.6 'Mix D'
item.7 'DSP 1'
item.8 'DSP 2'
item.9 'PCM 1'
item.10 'PCM 2'
}
}
control.30 {
iface MIXER
name 'PCM 01 Capture Enum'
value 'DSP 1'
comment {
access 'read write'
type ENUMERATED
count 1
item.0 Off
item.1 'Analogue 1'
item.2 'Analogue 2'
item.3 'Mix A'
item.4 'Mix B'
item.5 'Mix C'
item.6 'Mix D'
item.7 'DSP 1'
item.8 'DSP 2'
item.9 'PCM 1'
item.10 'PCM 2'
}
}
control.31 {
iface MIXER
name 'PCM 02 Capture Enum'
value 'DSP 2'
comment {
access 'read write'
type ENUMERATED
count 1
item.0 Off
item.1 'Analogue 1'
item.2 'Analogue 2'
item.3 'Mix A'
item.4 'Mix B'
item.5 'Mix C'
item.6 'Mix D'
item.7 'DSP 1'
item.8 'DSP 2'
item.9 'PCM 1'
item.10 'PCM 2'
}
}
control.32 {
iface MIXER
name 'PCM 03 Capture Enum'
value 'Mix C'
comment {
access 'read write'
type ENUMERATED
count 1
item.0 Off
item.1 'Analogue 1'
item.2 'Analogue 2'
item.3 'Mix A'
item.4 'Mix B'
item.5 'Mix C'
item.6 'Mix D'
item.7 'DSP 1'
item.8 'DSP 2'
item.9 'PCM 1'
item.10 'PCM 2'
}
}
control.33 {
iface MIXER
name 'PCM 04 Capture Enum'
value 'Mix D'
comment {
access 'read write'
type ENUMERATED
count 1
item.0 Off
item.1 'Analogue 1'
item.2 'Analogue 2'
item.3 'Mix A'
item.4 'Mix B'
item.5 'Mix C'
item.6 'Mix D'
item.7 'DSP 1'
item.8 'DSP 2'
item.9 'PCM 1'
item.10 'PCM 2'
}
}
control.34 {
iface MIXER
name 'Mix A Input 01 Playback Volume'
value 160
comment {
access 'read write'
type INTEGER
count 1
range '0 - 172 (step 1)'
dbmin -8000
dbmax 600
dbvalue.0 0
}
}
control.35 {
iface MIXER
name 'Mix A Input 02 Playback Volume'
value 0
comment {
access 'read write'
type INTEGER
count 1
range '0 - 172 (step 1)'
dbmin -8000
dbmax 600
dbvalue.0 -8000
}
}
control.36 {
iface MIXER
name 'Mix A Input 03 Playback Volume'
value 0
comment {
access 'read write'
type INTEGER
count 1
range '0 - 172 (step 1)'
dbmin -8000
dbmax 600
dbvalue.0 -8000
}
}
control.37 {
iface MIXER
name 'Mix A Input 04 Playback Volume'
value 0
comment {
access 'read write'
type INTEGER
count 1
range '0 - 172 (step 1)'
dbmin -8000
dbmax 600
dbvalue.0 -8000
}
}
control.38 {
iface MIXER
name 'Mix B Input 01 Playback Volume'
value 0
comment {
access 'read write'
type INTEGER
count 1
range '0 - 172 (step 1)'
dbmin -8000
dbmax 600
dbvalue.0 -8000
}
}
control.39 {
iface MIXER
name 'Mix B Input 02 Playback Volume'
value 160
comment {
access 'read write'
type INTEGER
count 1
range '0 - 172 (step 1)'
dbmin -8000
dbmax 600
dbvalue.0 0
}
}
control.40 {
iface MIXER
name 'Mix B Input 03 Playback Volume'
value 0
comment {
access 'read write'
type INTEGER
count 1
range '0 - 172 (step 1)'
dbmin -8000
dbmax 600
dbvalue.0 -8000
}
}
control.41 {
iface MIXER
name 'Mix B Input 04 Playback Volume'
value 0
comment {
access 'read write'
type INTEGER
count 1
range '0 - 172 (step 1)'
dbmin -8000
dbmax 600
dbvalue.0 -8000
}
}
control.42 {
iface MIXER
name 'Mix C Input 01 Playback Volume'
value 160
comment {
access 'read write'
type INTEGER
count 1
range '0 - 172 (step 1)'
dbmin -8000
dbmax 600
dbvalue.0 0
}
}
control.43 {
iface MIXER
name 'Mix C Input 02 Playback Volume'
value 0
comment {
access 'read write'
type INTEGER
count 1
range '0 - 172 (step 1)'
dbmin -8000
dbmax 600
dbvalue.0 -8000
}
}
control.44 {
iface MIXER
name 'Mix C Input 03 Playback Volume'
value 0
comment {
access 'read write'
type INTEGER
count 1
range '0 - 172 (step 1)'
dbmin -8000
dbmax 600
dbvalue.0 -8000
}
}
control.45 {
iface MIXER
name 'Mix C Input 04 Playback Volume'
value 0
comment {
access 'read write'
type INTEGER
count 1
range '0 - 172 (step 1)'
dbmin -8000
dbmax 600
dbvalue.0 -8000
}
}
control.46 {
iface MIXER
name 'Mix D Input 01 Playback Volume'
value 0
comment {
access 'read write'
type INTEGER
count 1
range '0 - 172 (step 1)'
dbmin -8000
dbmax 600
dbvalue.0 -8000
}
}
control.47 {
iface MIXER
name 'Mix D Input 02 Playback Volume'
value 160
comment {
access 'read write'
type INTEGER
count 1
range '0 - 172 (step 1)'
dbmin -8000
dbmax 600
dbvalue.0 0
}
}
control.48 {
iface MIXER
name 'Mix D Input 03 Playback Volume'
value 0
comment {
access 'read write'
type INTEGER
count 1
range '0 - 172 (step 1)'
dbmin -8000
dbmax 600
dbvalue.0 -8000
}
}
control.49 {
iface MIXER
name 'Mix D Input 04 Playback Volume'
value 0
comment {
access 'read write'
type INTEGER
count 1
range '0 - 172 (step 1)'
dbmin -8000
dbmax 600
dbvalue.0 -8000
}
}
control.50 {
iface PCM
name 'Level Meter'
value.0 0
value.1 0
value.2 0
value.3 0
value.4 0
value.5 0
value.6 0
value.7 0
value.8 0
value.9 0
value.10 0
value.11 0
comment {
access 'read volatile'
type INTEGER
count 12
range '0 - 4095 (step 1)'
}
}
control.51 {
iface MIXER
name 'Sync Status'
value Locked
comment {
access read
type ENUMERATED
count 1
item.0 Unlocked
item.1 Locked
}
}
control.52 {
iface MIXER
name 'Direct Monitor Playback Enum'
value Off
comment {
access 'read write'
type ENUMERATED
count 1
item.0 Off
item.1 Mono
item.2 Stereo
}
}
control.53 {
iface MIXER
name 'Monitor 1 Mix A Input 01 Playback Volume'
value 150
comment {
access 'read write'
type INTEGER
count 1
range '0 - 172 (step 1)'
dbmin -8000
dbmax 600
dbvalue.0 -500
}
}
control.54 {
iface MIXER
name 'Monitor 1 Mix A Input 02 Playback Volume'
value 0
comment {
access 'read write'
type INTEGER
count 1
range '0 - 172 (step 1)'
dbmin -8000
dbmax 600
dbvalue.0 -8000
}
}
control.55 {
iface MIXER
name 'Monitor 1 Mix A Input 03 Playback Volume'
value 154
comment {
access 'read write'
type INTEGER
count 1
range '0 - 172 (step 1)'
dbmin -8000
dbmax 600
dbvalue.0 -300
}
}
control.56 {
iface MIXER
name 'Monitor 1 Mix A Input 04 Playback Volume'
value 154
comment {
access 'read write'
type INTEGER
count 1
range '0 - 172 (step 1)'
dbmin -8000
dbmax 600
dbvalue.0 -300
}
}
control.57 {
iface MIXER
name 'Monitor 1 Mix B Input 01 Playback Volume'
value 0
comment {
access 'read write'
type INTEGER
count 1
range '0 - 172 (step 1)'
dbmin -8000
dbmax 600
dbvalue.0 -8000
}
}
control.58 {
iface MIXER
name 'Monitor 1 Mix B Input 02 Playback Volume'
value 150
comment {
access 'read write'
type INTEGER
count 1
range '0 - 172 (step 1)'
dbmin -8000
dbmax 600
dbvalue.0 -500
}
}
control.59 {
iface MIXER
name 'Monitor 1 Mix B Input 03 Playback Volume'
value 154
comment {
access 'read write'
type INTEGER
count 1
range '0 - 172 (step 1)'
dbmin -8000
dbmax 600
dbvalue.0 -300
}
}
control.60 {
iface MIXER
name 'Monitor 1 Mix B Input 04 Playback Volume'
value 154
comment {
access 'read write'
type INTEGER
count 1
range '0 - 172 (step 1)'
dbmin -8000
dbmax 600
dbvalue.0 -300
}
}
control.61 {
iface MIXER
name 'Monitor 2 Mix A Input 01 Playback Volume'
value 150
comment {
access 'read write'
type INTEGER
count 1
range '0 - 172 (step 1)'
dbmin -8000
dbmax 600
dbvalue.0 -500
}
}
control.62 {
iface MIXER
name 'Monitor 2 Mix A Input 02 Playback Volume'
value 0
comment {
access 'read write'
type INTEGER
count 1
range '0 - 172 (step 1)'
dbmin -8000
dbmax 600
dbvalue.0 -8000
}
}
control.63 {
iface MIXER
name 'Monitor 2 Mix A Input 03 Playback Volume'
value 160
comment {
access 'read write'
type INTEGER
count 1
range '0 - 172 (step 1)'
dbmin -8000
dbmax 600
dbvalue.0 0
}
}
control.64 {
iface MIXER
name 'Monitor 2 Mix A Input 04 Playback Volume'
value 0
comment {
access 'read write'
type INTEGER
count 1
range '0 - 172 (step 1)'
dbmin -8000
dbmax 600
dbvalue.0 -8000
}
}
control.65 {
iface MIXER
name 'Monitor 2 Mix B Input 01 Playback Volume'
value 0
comment {
access 'read write'
type INTEGER
count 1
range '0 - 172 (step 1)'
dbmin -8000
dbmax 600
dbvalue.0 -8000
}
}
control.66 {
iface MIXER
name 'Monitor 2 Mix B Input 02 Playback Volume'
value 150
comment {
access 'read write'
type INTEGER
count 1
range '0 - 172 (step 1)'
dbmin -8000
dbmax 600
dbvalue.0 -500
}
}
control.67 {
iface MIXER
name 'Monitor 2 Mix B Input 03 Playback Volume'
value 0
comment {
access 'read write'
type INTEGER
count 1
range '0 - 172 (step 1)'
dbmin -8000
dbmax 600
dbvalue.0 -8000
}
}
control.68 {
iface MIXER
name 'Monitor 2 Mix B Input 04 Playback Volume'
value 160
comment {
access 'read write'
type INTEGER
count 1
range '0 - 172 (step 1)'
dbmin -8000
dbmax 600
dbvalue.0 0
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,885 @@
state.Gen {
control.1 {
iface PCM
name 'Playback Channel Map'
value.0 0
value.1 0
comment {
access read
type INTEGER
count 2
range '0 - 36'
}
}
control.2 {
iface PCM
name 'Capture Channel Map'
value.0 0
value.1 0
value.2 0
value.3 0
comment {
access read
type INTEGER
count 4
range '0 - 36'
}
}
control.3 {
iface CARD
name 'USB Internal Validity'
value true
comment {
access read
type BOOLEAN
count 1
}
}
control.4 {
iface CARD
name 'Firmware Version'
value 2115
comment {
access read
type INTEGER
count 1
range '0 - 0'
}
}
control.5 {
iface CARD
name 'Minimum Firmware Version'
value 2115
comment {
access read
type INTEGER
count 1
range '0 - 0'
}
}
control.6 {
iface MIXER
name 'MSD Mode Switch'
value false
comment {
access 'read write'
type BOOLEAN
count 1
}
}
control.7 {
iface MIXER
name 'Line In 1 Level Capture Enum'
value Line
comment {
access 'read write'
type ENUMERATED
count 1
item.0 Line
item.1 Inst
}
}
control.8 {
iface MIXER
name 'Line In 2 Air Capture Enum'
value Off
comment {
access 'read write'
type ENUMERATED
count 1
item.0 Off
item.1 Presence
item.2 'Presence + Drive'
}
}
control.9 {
iface MIXER
name 'Line In 2 Phantom Power Capture Switch'
value false
comment {
access 'read write'
type BOOLEAN
count 1
}
}
control.10 {
iface MIXER
name 'PCM Input Capture Switch'
value Direct
comment {
access 'read write'
type ENUMERATED
count 1
item.0 Direct
item.1 Mixer
}
}
control.11 {
iface MIXER
name 'Analogue Output 01 Playback Enum'
value 'Mix A'
comment {
access 'read write'
type ENUMERATED
count 1
item.0 Off
item.1 'Analogue 1'
item.2 'Analogue 2'
item.3 'Mix A'
item.4 'Mix B'
item.5 'Mix C'
item.6 'Mix D'
item.7 'Mix E'
item.8 'Mix F'
item.9 'DSP 1'
item.10 'DSP 2'
item.11 'PCM 1'
item.12 'PCM 2'
}
}
control.12 {
iface MIXER
name 'Analogue Output 02 Playback Enum'
value 'Mix B'
comment {
access 'read write'
type ENUMERATED
count 1
item.0 Off
item.1 'Analogue 1'
item.2 'Analogue 2'
item.3 'Mix A'
item.4 'Mix B'
item.5 'Mix C'
item.6 'Mix D'
item.7 'Mix E'
item.8 'Mix F'
item.9 'DSP 1'
item.10 'DSP 2'
item.11 'PCM 1'
item.12 'PCM 2'
}
}
control.13 {
iface MIXER
name 'Mixer Input 01 Capture Enum'
value 'PCM 1'
comment {
access 'read write'
type ENUMERATED
count 1
item.0 Off
item.1 'Analogue 1'
item.2 'Analogue 2'
item.3 'Mix A'
item.4 'Mix B'
item.5 'Mix C'
item.6 'Mix D'
item.7 'Mix E'
item.8 'Mix F'
item.9 'DSP 1'
item.10 'DSP 2'
item.11 'PCM 1'
item.12 'PCM 2'
}
}
control.14 {
iface MIXER
name 'Mixer Input 02 Capture Enum'
value 'PCM 2'
comment {
access 'read write'
type ENUMERATED
count 1
item.0 Off
item.1 'Analogue 1'
item.2 'Analogue 2'
item.3 'Mix A'
item.4 'Mix B'
item.5 'Mix C'
item.6 'Mix D'
item.7 'Mix E'
item.8 'Mix F'
item.9 'DSP 1'
item.10 'DSP 2'
item.11 'PCM 1'
item.12 'PCM 2'
}
}
control.15 {
iface MIXER
name 'Mixer Input 03 Capture Enum'
value 'DSP 1'
comment {
access 'read write'
type ENUMERATED
count 1
item.0 Off
item.1 'Analogue 1'
item.2 'Analogue 2'
item.3 'Mix A'
item.4 'Mix B'
item.5 'Mix C'
item.6 'Mix D'
item.7 'Mix E'
item.8 'Mix F'
item.9 'DSP 1'
item.10 'DSP 2'
item.11 'PCM 1'
item.12 'PCM 2'
}
}
control.16 {
iface MIXER
name 'Mixer Input 04 Capture Enum'
value 'DSP 2'
comment {
access 'read write'
type ENUMERATED
count 1
item.0 Off
item.1 'Analogue 1'
item.2 'Analogue 2'
item.3 'Mix A'
item.4 'Mix B'
item.5 'Mix C'
item.6 'Mix D'
item.7 'Mix E'
item.8 'Mix F'
item.9 'DSP 1'
item.10 'DSP 2'
item.11 'PCM 1'
item.12 'PCM 2'
}
}
control.17 {
iface MIXER
name 'DSP Input 1 Capture Enum'
value 'Analogue 1'
comment {
access 'read write'
type ENUMERATED
count 1
item.0 Off
item.1 'Analogue 1'
item.2 'Analogue 2'
item.3 'Mix A'
item.4 'Mix B'
item.5 'Mix C'
item.6 'Mix D'
item.7 'Mix E'
item.8 'Mix F'
item.9 'DSP 1'
item.10 'DSP 2'
item.11 'PCM 1'
item.12 'PCM 2'
}
}
control.18 {
iface MIXER
name 'DSP Input 2 Capture Enum'
value 'Analogue 2'
comment {
access 'read write'
type ENUMERATED
count 1
item.0 Off
item.1 'Analogue 1'
item.2 'Analogue 2'
item.3 'Mix A'
item.4 'Mix B'
item.5 'Mix C'
item.6 'Mix D'
item.7 'Mix E'
item.8 'Mix F'
item.9 'DSP 1'
item.10 'DSP 2'
item.11 'PCM 1'
item.12 'PCM 2'
}
}
control.19 {
iface MIXER
name 'PCM 01 Capture Enum'
value 'DSP 1'
comment {
access 'read write'
type ENUMERATED
count 1
item.0 Off
item.1 'Analogue 1'
item.2 'Analogue 2'
item.3 'Mix A'
item.4 'Mix B'
item.5 'Mix C'
item.6 'Mix D'
item.7 'Mix E'
item.8 'Mix F'
item.9 'DSP 1'
item.10 'DSP 2'
item.11 'PCM 1'
item.12 'PCM 2'
}
}
control.20 {
iface MIXER
name 'PCM 02 Capture Enum'
value 'DSP 2'
comment {
access 'read write'
type ENUMERATED
count 1
item.0 Off
item.1 'Analogue 1'
item.2 'Analogue 2'
item.3 'Mix A'
item.4 'Mix B'
item.5 'Mix C'
item.6 'Mix D'
item.7 'Mix E'
item.8 'Mix F'
item.9 'DSP 1'
item.10 'DSP 2'
item.11 'PCM 1'
item.12 'PCM 2'
}
}
control.21 {
iface MIXER
name 'PCM 03 Capture Enum'
value 'Mix C'
comment {
access 'read write'
type ENUMERATED
count 1
item.0 Off
item.1 'Analogue 1'
item.2 'Analogue 2'
item.3 'Mix A'
item.4 'Mix B'
item.5 'Mix C'
item.6 'Mix D'
item.7 'Mix E'
item.8 'Mix F'
item.9 'DSP 1'
item.10 'DSP 2'
item.11 'PCM 1'
item.12 'PCM 2'
}
}
control.22 {
iface MIXER
name 'PCM 04 Capture Enum'
value 'Mix D'
comment {
access 'read write'
type ENUMERATED
count 1
item.0 Off
item.1 'Analogue 1'
item.2 'Analogue 2'
item.3 'Mix A'
item.4 'Mix B'
item.5 'Mix C'
item.6 'Mix D'
item.7 'Mix E'
item.8 'Mix F'
item.9 'DSP 1'
item.10 'DSP 2'
item.11 'PCM 1'
item.12 'PCM 2'
}
}
control.23 {
iface MIXER
name 'Mix A Input 01 Playback Volume'
value 160
comment {
access 'read write'
type INTEGER
count 1
range '0 - 172 (step 1)'
dbmin -8000
dbmax 600
dbvalue.0 0
}
}
control.24 {
iface MIXER
name 'Mix A Input 02 Playback Volume'
value 0
comment {
access 'read write'
type INTEGER
count 1
range '0 - 172 (step 1)'
dbmin -8000
dbmax 600
dbvalue.0 -8000
}
}
control.25 {
iface MIXER
name 'Mix A Input 03 Playback Volume'
value 0
comment {
access 'read write'
type INTEGER
count 1
range '0 - 172 (step 1)'
dbmin -8000
dbmax 600
dbvalue.0 -8000
}
}
control.26 {
iface MIXER
name 'Mix A Input 04 Playback Volume'
value 0
comment {
access 'read write'
type INTEGER
count 1
range '0 - 172 (step 1)'
dbmin -8000
dbmax 600
dbvalue.0 -8000
}
}
control.27 {
iface MIXER
name 'Mix B Input 01 Playback Volume'
value 0
comment {
access 'read write'
type INTEGER
count 1
range '0 - 172 (step 1)'
dbmin -8000
dbmax 600
dbvalue.0 -8000
}
}
control.28 {
iface MIXER
name 'Mix B Input 02 Playback Volume'
value 160
comment {
access 'read write'
type INTEGER
count 1
range '0 - 172 (step 1)'
dbmin -8000
dbmax 600
dbvalue.0 0
}
}
control.29 {
iface MIXER
name 'Mix B Input 03 Playback Volume'
value 0
comment {
access 'read write'
type INTEGER
count 1
range '0 - 172 (step 1)'
dbmin -8000
dbmax 600
dbvalue.0 -8000
}
}
control.30 {
iface MIXER
name 'Mix B Input 04 Playback Volume'
value 0
comment {
access 'read write'
type INTEGER
count 1
range '0 - 172 (step 1)'
dbmin -8000
dbmax 600
dbvalue.0 -8000
}
}
control.31 {
iface MIXER
name 'Mix C Input 01 Playback Volume'
value 160
comment {
access 'read write'
type INTEGER
count 1
range '0 - 172 (step 1)'
dbmin -8000
dbmax 600
dbvalue.0 0
}
}
control.32 {
iface MIXER
name 'Mix C Input 02 Playback Volume'
value 0
comment {
access 'read write'
type INTEGER
count 1
range '0 - 172 (step 1)'
dbmin -8000
dbmax 600
dbvalue.0 -8000
}
}
control.33 {
iface MIXER
name 'Mix C Input 03 Playback Volume'
value 0
comment {
access 'read write'
type INTEGER
count 1
range '0 - 172 (step 1)'
dbmin -8000
dbmax 600
dbvalue.0 -8000
}
}
control.34 {
iface MIXER
name 'Mix C Input 04 Playback Volume'
value 0
comment {
access 'read write'
type INTEGER
count 1
range '0 - 172 (step 1)'
dbmin -8000
dbmax 600
dbvalue.0 -8000
}
}
control.35 {
iface MIXER
name 'Mix D Input 01 Playback Volume'
value 0
comment {
access 'read write'
type INTEGER
count 1
range '0 - 172 (step 1)'
dbmin -8000
dbmax 600
dbvalue.0 -8000
}
}
control.36 {
iface MIXER
name 'Mix D Input 02 Playback Volume'
value 160
comment {
access 'read write'
type INTEGER
count 1
range '0 - 172 (step 1)'
dbmin -8000
dbmax 600
dbvalue.0 0
}
}
control.37 {
iface MIXER
name 'Mix D Input 03 Playback Volume'
value 0
comment {
access 'read write'
type INTEGER
count 1
range '0 - 172 (step 1)'
dbmin -8000
dbmax 600
dbvalue.0 -8000
}
}
control.38 {
iface MIXER
name 'Mix D Input 04 Playback Volume'
value 0
comment {
access 'read write'
type INTEGER
count 1
range '0 - 172 (step 1)'
dbmin -8000
dbmax 600
dbvalue.0 -8000
}
}
control.39 {
iface MIXER
name 'Mix E Input 01 Playback Volume'
value 0
comment {
access 'read write'
type INTEGER
count 1
range '0 - 172 (step 1)'
dbmin -8000
dbmax 600
dbvalue.0 -8000
}
}
control.40 {
iface MIXER
name 'Mix E Input 02 Playback Volume'
value 0
comment {
access 'read write'
type INTEGER
count 1
range '0 - 172 (step 1)'
dbmin -8000
dbmax 600
dbvalue.0 -8000
}
}
control.41 {
iface MIXER
name 'Mix E Input 03 Playback Volume'
value 144
comment {
access 'read write'
type INTEGER
count 1
range '0 - 172 (step 1)'
dbmin -8000
dbmax 600
dbvalue.0 -800
}
}
control.42 {
iface MIXER
name 'Mix E Input 04 Playback Volume'
value 144
comment {
access 'read write'
type INTEGER
count 1
range '0 - 172 (step 1)'
dbmin -8000
dbmax 600
dbvalue.0 -800
}
}
control.43 {
iface MIXER
name 'Mix F Input 01 Playback Volume'
value 0
comment {
access 'read write'
type INTEGER
count 1
range '0 - 172 (step 1)'
dbmin -8000
dbmax 600
dbvalue.0 -8000
}
}
control.44 {
iface MIXER
name 'Mix F Input 02 Playback Volume'
value 0
comment {
access 'read write'
type INTEGER
count 1
range '0 - 172 (step 1)'
dbmin -8000
dbmax 600
dbvalue.0 -8000
}
}
control.45 {
iface MIXER
name 'Mix F Input 03 Playback Volume'
value 144
comment {
access 'read write'
type INTEGER
count 1
range '0 - 172 (step 1)'
dbmin -8000
dbmax 600
dbvalue.0 -800
}
}
control.46 {
iface MIXER
name 'Mix F Input 04 Playback Volume'
value 144
comment {
access 'read write'
type INTEGER
count 1
range '0 - 172 (step 1)'
dbmin -8000
dbmax 600
dbvalue.0 -800
}
}
control.47 {
iface PCM
name 'Level Meter'
value.0 0
value.1 0
value.2 0
value.3 0
value.4 0
value.5 3
value.6 0
value.7 3
value.8 0
value.9 3
value.10 0
value.11 0
comment {
access 'read volatile'
type INTEGER
count 12
range '0 - 4095 (step 1)'
}
}
control.48 {
iface MIXER
name 'Sync Status'
value Locked
comment {
access read
type ENUMERATED
count 1
item.0 Unlocked
item.1 Locked
}
}
control.49 {
iface MIXER
name 'Direct Monitor Playback Switch'
value false
comment {
access 'read write'
type BOOLEAN
count 1
}
}
control.50 {
iface MIXER
name 'Monitor Mix A Input 01 Playback Volume'
value 150
comment {
access 'read write'
type INTEGER
count 1
range '0 - 172 (step 1)'
dbmin -8000
dbmax 600
dbvalue.0 -500
}
}
control.51 {
iface MIXER
name 'Monitor Mix A Input 02 Playback Volume'
value 0
comment {
access 'read write'
type INTEGER
count 1
range '0 - 172 (step 1)'
dbmin -8000
dbmax 600
dbvalue.0 -8000
}
}
control.52 {
iface MIXER
name 'Monitor Mix A Input 03 Playback Volume'
value 154
comment {
access 'read write'
type INTEGER
count 1
range '0 - 172 (step 1)'
dbmin -8000
dbmax 600
dbvalue.0 -300
}
}
control.53 {
iface MIXER
name 'Monitor Mix A Input 04 Playback Volume'
value 154
comment {
access 'read write'
type INTEGER
count 1
range '0 - 172 (step 1)'
dbmin -8000
dbmax 600
dbvalue.0 -300
}
}
control.54 {
iface MIXER
name 'Monitor Mix B Input 01 Playback Volume'
value 0
comment {
access 'read write'
type INTEGER
count 1
range '0 - 172 (step 1)'
dbmin -8000
dbmax 600
dbvalue.0 -8000
}
}
control.55 {
iface MIXER
name 'Monitor Mix B Input 02 Playback Volume'
value 150
comment {
access 'read write'
type INTEGER
count 1
range '0 - 172 (step 1)'
dbmin -8000
dbmax 600
dbvalue.0 -500
}
}
control.56 {
iface MIXER
name 'Monitor Mix B Input 03 Playback Volume'
value 154
comment {
access 'read write'
type INTEGER
count 1
range '0 - 172 (step 1)'
dbmin -8000
dbmax 600
dbvalue.0 -300
}
}
control.57 {
iface MIXER
name 'Monitor Mix B Input 04 Playback Volume'
value 154
comment {
access 'read write'
type INTEGER
count 1
range '0 - 172 (step 1)'
dbmin -8000
dbmax 600
dbvalue.0 -300
}
}
}

1861
demo/Vocaster One.state Normal file

File diff suppressed because it is too large Load Diff

3428
demo/Vocaster Two.state Normal file

File diff suppressed because it is too large Load Diff

188
docs/INSTALL.md Normal file
View File

@@ -0,0 +1,188 @@
# ALSA Scarlett Control Panel Installation
## Prerequisites
### Linux Kernel
You need to be running a Linux Kernel that contains the appropriate
driver for your interface. Use `uname -r` to check what kernel version
you are running.
Check the following table to see which driver your interface uses and
the first kernel version that the driver was included in:
| Series | Models | Driver | Kernel Version |
|-----------|--------|--------|:----------------------:|
| Scarlett 1st Gen | Solo, 2i2, 2i4 | N/A* | Any |
| Scarlett 1st Gen | 6i6, 8i6, 18i6, 18i8, 18i20 | Scarlett 1st Gen Mixer Driver | 3.19+ |
| Scarlett 2nd Gen | Solo, 2i2, 2i4 | N/A* | Any |
| Scarlett 2nd Gen | 6i6, 18i8, 18i20 | Scarlett2 Mixer Driver | 6.7+ |
| Scarlett 3rd Gen | Solo, 2i2, 4i4, 8i6, 18i8, 18i20 | Scarlett2 Mixer Driver | 6.7+ |
| Scarlett 4th Gen | Solo, 2i2, 4i4 | Scarlett2 Mixer Driver | 6.8+ |
| Scarlett 4th Gen | 16i16, 18i16, 18i20 | FCP (Focusrite Control Protocol) Driver | 6.14+ |
| Clarett USB and Clarett+ | 2Pre, 4Pre, 8Pre | Scarlett2 Mixer Driver | 6.7+ |
| Vocaster | One, Two | Scarlett2 Mixer Driver | 6.10+ |
\* The small 1st Gen and 2nd Gen models dont have any proprietary
software controls so they dont need a driver beyond the standard ALSA
USB Audio driver. This means that this application (alsa-scarlett-gui)
is not needed, useful, or supported for these models.
If your distribution doesnt include a recent-enough kernel for your
interface, you can get the latest driver from here and build it for
your current kernel if its not too old (the Scarlett2 and FCP drivers
are both maintained in the same tree here):
https://github.com/geoffreybennett/linux-fcp/releases
Kernel 6.7 and later have the Scarlett2 driver enabled by default. The
Scarlett 1st Gen driver and the FCP drivers are always enabled.
#### Enabling the Scarlett2 Driver
Some kernels before 6.7 have an earlier version of the Scarlett2
driver which is disabled by default. If this is you, check the driver
status (after plugging your interface in) with this command:
```
dmesg | grep -i -A 5 -B 5 focusrite
```
If all is good youll see messages like this:
```
New USB device found, idVendor=1235, idProduct=8215, bcdDevice= 6.0b
Product: Scarlett 18i20 USB
Focusrite Scarlett Gen 3 Mixer Driver enabled (pid=0x8215); ...
```
If you dont see the “Mixer Driver” message or if it shows “disabled”
then check the [OLDKERNEL.md](OLDKERNEL.md) instructions (or,
preferably, upgrade your distro/kernel!).
### Gtk4
You need a Linux distribution with Gtk4 development libraries. If it
doesnt have them natively, try the Flatpak instructions below.
### Firmware
#### Scarlett2 Driver
As of Linux 6.8, firmware updates of all supported interfaces from the
2nd Gen onwards can be done through Linux. This is mandatory for
Scarlett 4th Gen and Vocaster interfaces (unless youve already
updated it using the manufacturers software), and optional but
recommended for Scarlett 2nd and 3rd Gen, Clarett USB, and Clarett+
interfaces.
Download the firmware from
https://github.com/geoffreybennett/scarlett2-firmware and place it in
`/usr/lib/firmware/scarlett2` or use the RPM/deb package.
#### FCP Driver
Firmware updates for the big Scarlett 4th Gen interfaces is currently
only possible through the CLI `fcp-tool` utility available in the
[fcp-support](https://github.com/geoffreybennett/fcp-support). You
need to install this package and update the firmware before
alsa-scarlett-gui will work.
## Building and Running
On Fedora, these packages need to be installed:
```
sudo dnf -y install alsa-lib-devel gtk4-devel openssl-devel
```
On OpenSUSE:
```
sudo zypper in git alsa-devel gtk4-devel libopenssl-devel
```
On Ubuntu:
```
sudo apt -y install git make gcc libgtk-4-dev libasound2-dev libssl-dev
```
On Arch:
```
sudo pacman -S gtk4
```
To download from github:
```
git clone https://github.com/geoffreybennett/alsa-scarlett-gui
cd alsa-scarlett-gui
```
To build:
```
cd src
make -j$(nproc)
```
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 how to use the GUI.
## 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 committing!
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
```

77
docs/OLDKERNEL.md Normal file
View File

@@ -0,0 +1,77 @@
# ALSA Scarlett2 Usage With Old Kernels
**This information is mostly for historical purposes. If youre
running a kernel before 6.7, you should upgrade to a newer kernel.**
Linux kernel 6.7 (check your version with `uname -r`) was the first
kernel version with the Scarlett2 driver enabled by default. Its
recommended that you run 6.7 or later, or build the backported driver
for your kernel. If you do, then these instructions arent relevant;
continue with [INSTALL.md](INSTALL.md) for prerequisites, how to
build, install, and run `alsa-scarlett-gui`.
If youve got a Scarlett Gen 2 or 3 or a Clarett+ 8Pre and dont mind
the level meters not working, then the first kernel support was added
in:
- **Scarlett Gen 2**: Linux 5.4 (bugs fixed in Linux 5.14)
- **Scarlett Gen 3**: Linux 5.14
- **Clarett+ 8Pre**: Linux 6.1
## Linux Kernel with Backported Driver (recommended)
Install the latest version of the backported driver from here:
https://github.com/geoffreybennett/linux-fcp/releases
then you can ignore the instructions below.
## Linux Kernel before 6.7 without Backported Driver
If youre running a kernel before 6.7 without the backported driver,
you need to enable it 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
```

156
docs/USAGE.md Normal file
View File

@@ -0,0 +1,156 @@
# ALSA Scarlett Control Panel Usage
Refer to [INSTALL.md](INSTALL.md) for prerequisites, how to build,
install, and run.
## No interface connected
If no interface is detected (usually because there isnt one
connected!) youll see this window:
![No Interface Connected](../img/iface-none.png)
Plug in an interface or select the menu option File → Interface
Simulation and load a demo file to make more interesting things
happen.
## First Time Usage
If your interface is fresh out of the box (or you havent updated it
using the manufacturers software), you may need to update the
firmware and/or disable MSD Mode first.
### Firmware Update Required
Some interfaces require a firmware update before all their
functionality is available. If the firmware is not available on your
system, youll see this window:
![Firmware Update Required (Firmware
Missing)](../img/firmware-missing.png)
In this case, click on the link, download and install the firmware
package, then restart `alsa-scarlett-gui`.
If a firmware update is required and the firmware is available, youll
see this window:
![Firmware Update Required](../img/firmware-update-required.png)
Click “Update”, then “Yes” to update the firmware.
![Firmware Update Progress](../img/firmware-updating.png)
The update will take about 15 seconds, and then your interface will
restart, showing the main window.
### MSD (Mass Storage Device/Quick Start/Easy Start) Mode
If MSD Mode is enabled (as it is from the factory) and a firmware
update is not available or required, then youll see this window:
![MSD Mode](../img/iface-msd.png)
Click the “Enabled” button to disable MSD Mode, then click “Reboot” to
restart the interface, and in a moment the main window will appear.
## Startup Controls
The View → Startup menu option opens a window to configure settings
that only take effect when the interface is powered on.
The options common to most interfaces are:
- **Reset Configuration**: this will reset the configuration to the
factory defaults. This is particularly useful with the 4th Gen and
Vocaster interfaces if youve made a mess of the configuration and
want to start again.
- **Update Firmware**: if a firmware update is found in the
`/usr/share/firmware/scarlett2` directory, then an option to update
the firmware will be available here.
## File Menu
The File menu contains options to load and save the configuration,
load a configuration in simulation mode, and to exit the application.
### Load/Save Configuration
The entire state of the interface can be loaded and saved using the
File → Load Configuration and File → Save Configuration menu options.
Internally, this uses `alsactl`:
- **Load**: `alsactl restore USB -f <fn>`
- **Save**: `alsactl store USB -f <fn>`
The saved state files can be used to simulate an interface if you
dont have one attached. The `demo` directory in the distribution
contains a sample file for every supported model.
### Interface Simulation Mode
The GUI can load an `alsactl` state file saved from a real interface
and display a GUI as if the corresponding interface was connected.
This is useful if you dont have an interface connected and want to
try, develop, or debug the GUI.
Either specify the `.state` filename on the command line or select the
menu option File → Interface Simulation to load.
## Interface Controls
The controls and menu items which are available vary widely, depending
on your specific interface.
There are five broad categories of interfaces with different
capabilities; each category of interface is described in a separate
document:
- [Scarlett 1st Gen 6i6+](iface-1st-gen.md)
Full routing and mixing capabilities, but some significant caveats.
- [Scarlett 3rd Gen Solo and 2i2](iface-small.md)
Minimal number of controls, and they mostly accessible through
hardware buttons anyway. Not very interesting.
- [Scarlett 2nd Gen 6i6+, 3rd Gen 4i4+, Clarett USB, and
Clarett+](iface-large.md)
Full routing and mixing capabilities.
- [Scarlett Small 4th Gen](iface-4th-gen-small.md)
Full routing and mixing capabilities, remote-controlled input gain,
but no output controls.
- [Scarlett Big 4th Gen](iface-4th-gen-big.md)
Full routing and mixing capabilities, remote-controlled input gain
and output volume controls.
## Known Bugs/Issues
- For interfaces using the FCP driver, alsa-scarlett-gui needs to be
started after the interface is connected and fcp-server has started.
- Load/Save uses `alsactl` which will be confused if the ALSA
interface name (e.g. `USB`) changes.
- Load/Save is not implemented for simulated interfaces.
- The read-only status of controls in interface simulation mode does
not change when the HW/SW button is clicked.
- When theres more than one main window open, closing one of them
doesnt free and close everything related to that card.
- There is no facility to group channels into stereo pairs (needs
kernel support to save this information in the interface).
- There is no facility to give channels custom names (needs kernel
support to save this information in the interface).

164
docs/iface-1st-gen.md Normal file
View File

@@ -0,0 +1,164 @@
# ALSA Scarlett Control Panel
## Scarlett 1st Gen Interfaces
This document describes how to use the ALSA Scarlett Control Panel
with the Scarlett 1st Gen interfaces:
- Scarlett 1st Gen 6i6, 8i6, 18i6, 18i8, 18i20
Note: The 1st Gen Scarlett Solo, 2i2, and 2i4 have all their controls
accessible from the front panel of the device, and there are no
proprietary software controls, so they do not require this control
panel software.
## Important Driver Limitations
The 1st Gen Scarlett devices have some important limitations in the
ALSA driver implementation that you should be aware of:
1. **Initial State Detection**: The driver cannot read the current
state of hardware controls (this appears to be a limitation of the
device firmware). When alsa-scarlett-gui starts, what you see will
not reflect the actual state of your device unless the controls
have previously been set since startup.
2. **State Update Issues**: The driver only updates the hardware state
when it thinks a setting needs to be changed. If the driver
incorrectly believes a control is already in the desired state, it
wont actually update the control.
3. **Level Meters**: The driver does not support reading the level
meters from the hardware.
4. **Startup Configuration**: The driver is not able to save the
current configuration to the non-volatile memory of the device, so
youll need to reapply the desired configuration each time you
restart it (or write your preferred configuration using MixControl
on Windows or Mac).
### Recommended Workaround
To ensure your settings are properly applied:
1. Apply a “zero” configuration that sets all controls to values that
are *not* what you desire.
2. Then apply your desired configuration
This two-step process helps ensure that the driver actually sends all
commands to the hardware. You may want to create a script using
`alsactl` for this purpose.
## Main Window
The main window is divided into three sections:
- Global Controls
- Analogue Input Controls
- Analogue Output Controls
The particular controls available depend on the interface model.
Note that the View menu option lets you open two other windows which
contain additional controls, described in the following sections:
- [Routing](#routing)
- [Mixer](#mixer)
The Levels and Startup windows that are available for later-generation
interfaces are not available for 1st Gen interfaces due to driver limitations.
### Global Controls
Global controls relate to the operation of the interface as a whole.
#### Clock Source
Clock Source selects where the interface receives its digital clock
from. If you arent using S/PDIF or ADAT inputs, set this to Internal.
#### Sync Status
Sync Status indicates if the interface is locked to a valid digital
clock. If you arent using S/PDIF or ADAT inputs and the status is
Unlocked, change the Clock Source to Internal.
### Analogue Input Controls
#### Inst
The Inst buttons are used to select between Mic/Line and Instrument
level/impedance. When plugging in microphones or line-level equipment
(such as a synthesizer, external preamp, or effects processor) to the
input, set it to “Line”. The “Inst” setting is for instruments with
pickups such as guitars.
#### Pad
Enabling Pad engages a 10dB attenuator in the channel, giving you more
headroom for very hot signals.
#### Gain
The Gain switch selects Low or High gain for the input channel.
### Analogue Output Controls
The analogue output controls let you set the output volume (gain) on
the analogue line outputs.
Click and drag up/down on the volume dial to change the volume, use
your arrow keys, Home/End/PgUp/PgDn keys, or use your mouse scroll
wheel to adjust. You can also double-click on it to quickly toggle the
volume between off and 0dB.
## Routing
The routing window allows complete control of signal routing between
the hardware inputs/outputs, internal mixer, and PCM (USB)
inputs/outputs.
![Routing Window](../img/scarlett-1st-gen-6i6-routing.png)
To manage the routing connections:
- Click and drag from a source to a sink or a sink to a source to
connect them. Audio from the source will then be sent to that sink.
- Click on a source or a sink to clear the links connected to that
source/sink.
Note that a sink can only be connected to one source, but one source
can be connected to many sinks. If you want a sink to receive input
from more than one source, use the mixer inputs and outputs:
- Connect the sources that you want to mix together to mixer inputs
- Connect mixer outputs to the sinks that you want to receive the
mixed audio
- Use the Mixer window to set the amount of each mixer input that is
sent to each mixer output
The Presets menu can be used to clear all connections, or to set up
common configurations:
- The “Direct” preset sets up the usual configuration using the
interface as a regular audio interface by connecting:
- all Hardware Inputs to PCM Inputs
- all PCM Outputs to Hardware Outputs
- The “Preamp” preset connects all Hardware Inputs to Hardware
Outputs.
- The “Stereo Out” preset connects PCM 1 and 2 Outputs to pairs of
Hardware Outputs.
## Mixer
If you use the Routing window to connect Sources to Mixer Inputs and
Mixer Outputs to Sinks, then you can use the Mixer window to set the
amount of each Mixer Input that is sent to each Mixer Output using a
matrix of controls.
Click and drag up/down on the gain controls to adjust, or use your
mouse scroll wheel. You can also double-click on the control to
quickly toggle between off and 0dB.

210
docs/iface-4th-gen-big.md Normal file
View File

@@ -0,0 +1,210 @@
# ALSA Scarlett Control Panel
## Scarlett Big 4th Gen Interfaces
This document describes how to use the ALSA Scarlett Control Panel
with the big Scarlett 4th Gen interfaces:
- Scarlett 4th Gen 16i16, 18i16, 18i20
### FCP Driver
The big 4th Gen interfaces are supported by a new “FCP” (Focusrite
Control Protocol) driver introduced in Linux 6.14. If you havent
installed
[fcp-support](https://github.com/geoffreybennett/fcp-support) yet, you
need to do that (and update the firmware) before you can use
alsa-scarlett-gui.
## Main Window
The main window is divided into three sections:
- Global Controls
- Analogue Input Controls
- Analogue Output Controls
The main window for the 16i16 interface is shown below. The 18i16 and
18i20 interfaces are similar, but with more controls.
![Main Window](../img/iface-4th-gen-big.png)
### Global Controls
#### Clock Source (interfaces with S/PDIF or ADAT inputs only)
Clock Source selects where the interface receives its digital clock
from. If you arent using S/PDIF or ADAT inputs, set this to Internal.
#### Sync Status
Sync Status indicates if the interface is locked to a valid digital
clock. If you arent using S/PDIF or ADAT inputs and the Sync Status
is Unlocked, change the Clock Source to Internal.
#### Sample Rate
Sample Rate is informative only, and displays the current sample rate
if the interface is currently in use. In ALSA, the sample rate is set
by the application using the interface, which is usually a sound
server such as PulseAudio, JACK, or PipeWire.
#### Speaker Switching
Speaker Switching lets you swap between two pairs of monitoring
speakers very easily.
### Analogue Input Controls
#### Input Select
The “Input Select” control allows you to choose which channel the
hardware 48V, Inst, Air, Auto, and Safe buttons control.
#### Link
The “Link” control links the 48V, Inst, Air, Auto, and Safe controls
together so that they control a stereo pair of channels
simultaneously.
#### Gain
The “Gain” controls adjust the input gain for the selected channel.
Click and drag up/down on the control to adjust the gain, use your
mouse scroll wheel, or click the control to select it and use the
arrow keys, Page Up, Page Down, Home, and End keys.
#### Autogain
When the “Autogain” control is enabled, the interface will listen to
the input signal for ten seconds and automatically adjust the gain to
get the best signal level. When autogain is not running, the
most-recent autogain exit status is shown below the “Autogain”
control.
#### Safe
“Safe” mode is a feature that automatically reduces the gain if the
signal is too loud. This can be useful to prevent clipping.
#### Instrument
The Inst button(s) are used to select between Mic/Line and Instrument
level/impedance. When plugging in microphones or line-level equipment
(such as a synthesizer, external preamp, or effects processor) to the
input, set it to “Line”. The “Inst” setting is for instruments with
pickups such as guitars.
#### Air
The Scarlett 3rd Gen introduced Air mode which transformed your
recordings and inspired you while making music by boosting the
signals high-end. The 4th Gen interfaces now call that “Air Presence”
and add a new mode “Air Presence+Drive” which boosts mid-range
harmonics in your sound.
#### Phantom Power (48V)
Turning the “48V” switch on sends “Phantom Power” to the XLR
microphone input. This is required for some microphones (such as
condensor microphones), and damaging to some microphones (particularly
vintage ribbon microphones).
### Analogue Output Controls
The analogue output controls are a bit sparse. More controls are
coming soon.
#### Volume Knobs
The volume knobs control the volume of the analogue outputs. The two
channels of the stereo pairs are shown separately, but are internally
linked together.
#### Mute and Dim
The speaker icon buttons are “mute” and “dim” (reduce volume) buttons,
corresponding to the front-panel buttons on the interface (although
only the 18i20 has a physical dim button).
## Routing and Mixing
The routing window allows (almost) complete control of signal routing
between the hardware inputs/outputs, internal mixer, and PCM (USB)
inputs/outputs.
The routing and mixing capabilities of the big 4th Gen interfaces are
the same in concept as the older interfaces, but the mixer inputs are
fixed and not shown in the routing window as there are too many to
sensibly display.
From the main window, open the Routing window with the View → Routing
menu option or pressing Ctrl-R:
![4th Gen 16i16 Routing](../img/scarlett-4th-gen-16i16-routing.png)
To manage the routing connections:
- Click and drag from a source to a sink or a sink to a source to
connect them. Audio from the source will then be sent to that sink.
- Click on a source or a sink to clear the links connected to that
source/sink.
Note that a sink can only be connected to one source, but one source
can be connected to many sinks. If you want a sink to receive input
from more than one source, connect the sinks to mixer outputs:
- Connect mixer outputs to the sinks that you want to receive the
mixed audio
- Use the Mixer window to set the amount of each mixer input that is
sent to each mixer output
The Presets menu can be used to clear all connections, or to set up
common configurations:
- The “Direct” preset sets up the usual configuration using the
interface as a regular audio interface by connecting:
- all Hardware Inputs to PCM Inputs
- all PCM Outputs to Hardware Outputs
- The “Preamp” preset connects all Hardware Inputs to Hardware
Outputs.
- The “Stereo Out” preset connects PCM 1 and 2 Outputs to pairs of
Hardware Outputs.
To adjust the routing:
- Click and drag from a source to a sink or a sink to a source to
connect them. Audio from the source will then be sent to that sink.
- Click on a source or a sink to clear the links connected to that
source/sink.
Note that a sink can only be connected to one source, but one source
can be connected to many sinks.
To adjust the mixer output levels:
1) Open the mixer window with the main window View → Mixer menu
option, or press Ctrl-M.
2) Mixer levels can be adjusted with your keyboard or mouse in the
same way as the [Gain Controls](#gain).
## Levels
The meters show the levels seen by the interface at every routing
source as well as the analogue outputs. Open this window by selecting
the View → Levels menu option or pressing Ctrl-L.
![Levels](../img/window-levels-4th-gen-big.png)
Look at this in conjunction with the routing window to understand
which meter corresponds to which source or sink.
Thanks for reading this far! If you appreciate the hundreds of hours
of work that went into the kernel driver, the control panel, and this
documentation, please consider supporting the author with a
[donation](../README.md#donations).

346
docs/iface-4th-gen-small.md Normal file
View File

@@ -0,0 +1,346 @@
# ALSA Scarlett Control Panel
## Scarlett Small 4th Gen Interfaces
This document describes how to use the ALSA Scarlett Control Panel
with the small Scarlett 4th Gen interfaces:
- Scarlett 4th Gen Solo, 2i2, and 4i4
### Comparison with earlier Scarlett and Clarett Interfaces
If you are familiar with the Scarlett 2nd and 3rd Gen interfaces or
the Clarett interfaces, the major differences to the 4th Gen
interfaces from the point of view of this software are:
- The 4th Gen Solo and 2i2 interfaces have the full routing and mixing
capabilities of the larger 2nd and 3rd Gen and Clarett interfaces
(although the line outputs and the headphone outputs are still
linked).
- The 4th Gen 2i2 and 4i4 interfaces have software-controllable
(“remote”) input gain controls.
- The 4th Gen interfaces dont have the output volume and mute
controls that the 2nd and 3rd Gen and Clarett interfaces have.
- The Air mode with Presence+Drive is implemented with a DSP which is
separately routable.
## Main Window
The main window is divided into three sections:
- Global Controls
- Analogue Input Controls
- Analogue Output Controls
The main window for the Solo and 2i2 interfaces is shown below; the
4i4 interface is similar to the 2i2, but doesnt have the Direct
Monitor control, and can show the position of the front panel volume
knobs.
![Main Window](../img/iface-4th-gen-small.png)
### Global Controls
#### Sync Status
Sync Status indicates if the interface is locked to a valid digital
clock. This should only ever briefly show “Unlocked” when the sample
rate is changed as these interfaces can only use their internal clock.
#### Power
The 4i4 has a “Power” control that displays the power status. It can
be “Fail”, “Bus”, or “External”. “Fail” means that the interface is
not receiving sufficient power; please see the Scarlett 4i4 4th Gen
User Guide for more information. “Bus” vs. “External” indicates
whether the interface is receiving power from the second USB-C port
(“External”) or not (“Bus”).
#### Sample Rate
Sample Rate is informative only, and displays the current sample rate
if the interface is currently in use. In ALSA, the sample rate is set
by the application using the interface, which is usually a sound
server such as PulseAudio, JACK, or PipeWire.
### Analogue Input Controls
The analogue input controls available depend on the interface model:
- **Instrument, Air, and Phantom Power**: All models
- **Mix**: Solo only (described later in the [Solo Mix
Control](#solo-mix-control) section)
- **Input Select, Link, Gain, Autogain, and Safe**: 2i2 and 4i4
#### Instrument
The Inst button(s) are used to select between Mic/Line and Instrument
level/impedance. When plugging in microphones or line-level equipment
(such as a synthesizer, external preamp, or effects processor) to the
input, set it to “Line”. The “Inst” setting is for instruments with
pickups such as guitars.
#### Air
The Scarlett 3rd Gen introduced Air mode which transformed your
recordings and inspired you while making music by boosting the
signals high-end. The 4th Gen interfaces now call that “Air Presence”
and add a new mode “Air Presence+Drive” which boosts mid-range
harmonics in your sound.
#### Phantom Power (48V)
Turning the “48V” switch on sends “Phantom Power” to the XLR
microphone input. This is required for some microphones (such as
condensor microphones), and damaging to some microphones (particularly
vintage ribbon microphones).
The 2i2 has a single 48V switch that controls both channels, and the
4i4 has an independent 48V switch for each channel.
#### Input Select
The 2i2 and 4i4 interfaces have hardware buttons for 48V, Inst, Air,
Auto, and Safe. The “Input Select” control allows you to choose which
channel those buttons control.
#### Link
The “Link” control links the 48V, Inst, Air, Auto, and Safe controls
together so that they control both channels simultaneously.
#### Gain
The “Gain” controls adjust the input gain for the selected channel.
Click and drag up/down on the control to adjust the gain, use your
mouse scroll wheel, or click the control to select it and use the
arrow keys, Page Up, Page Down, Home, and End keys.
#### Autogain
When the “Autogain” control is enabled, the interface will listen to
the input signal for ten seconds and automatically adjust the gain to
get the best signal level. When autogain is not running, the
most-recent autogain exit status is shown below the “Autogain”
control.
#### Safe
“Safe” mode is a feature that automatically reduces the gain if the
signal is too loud. This can be useful to prevent clipping.
### Analogue Output Controls
The analogue output controls available depend on the interface model:
- **Direct Monitor**: Solo and 2i2
- **Volume Knobs**: 4i4
#### Direct Monitor
Enabling Direct Monitor sends the analogue input signals to the
analogue outputs (speakers/headphones) for zero-latency monitoring.
On the 2i2, you have the choice of Mono or Stereo monitoring when you
click the button:
- **Mono** sends both inputs to the left and right outputs
- **Stereo** sends input 1 to the left, and input 2 to the right
output.
As the 4th Gen Solo and 2i2 interfaces have the full routing and
mixing capabilities of the larger 2nd and 3rd Gen interfaces, the
Direct Monitor levels can be [adjusted in the
mixer](#solo-direct-monitor).
The 4i4 has no Direct Monitor button, but that functionality can be
achieved with [appropriate configuration in the routing and mixing
windows](#4i4-sample-direct-monitor-configuration).
#### Volume Knobs
The 4i4 interface has volume knobs on the front panel, the position of
which is shown in the main window.
## Routing and Mixing
The routing and mixing capabilities of the 4th Gen interfaces are the
same in concept as the 2nd and 3rd Gen interfaces, but there is a DSP
which is separately routable, and the default routing uses the mixer
extensively.
From the main window, open the Routing window with the View → Routing
menu option or pressing Ctrl-R:
![4th Gen 2i2 Routing](../img/scarlett-4th-gen-2i2-routing.png)
To understand the signal flow, note the following:
1. The Analogue 1 & 2 Inputs (i.e. the Mic/Line/Inst inputs) are
routed to the DSP Inputs.
2. The DSP Outputs are routed to the PCM 1 & 2 Inputs (thats what
ALSA sees as the first two inputs from the interface for
recording).
3. The PCM Outputs (thats what ALSA sees as the interface outputs for
playback) and the DSP Outputs are all connected to the Mixer
Inputs.
4. The Mixer A & B Outputs are connected to the Hardware Analogue
outputs (i.e. your speakers/headphones) so you can hear any mix of
the PCM and DSP Outputs (this is how the Direct Monitor function
works).
5. The Mixer C & D Outputs are connected to the PCM 3 & 4 Inputs (this
is referred to as Loopback, for recording audio from your computer,
but can be used for another purpose if you want).
Important Notes:
- The “Presets” are generally not useful with the 4th Gen interfaces
as they are designed for the 2nd and 3rd Gen interfaces. If you try
these out, youll probably want to reset back to the factory
defaults afterwards.
- Besides Air Mode, the DSP is also used for the gain halo level
meters and autogain, so if you route something else to the DSP
Inputs, those features will work “rather differently”.
- The Focusrite Control 2 software cant control most of this routing,
so if you make changes here and then want to use Focusrite Control
2, youll probably need to reset the routing back to the factory
default settings.
To adjust the routing:
- Click and drag from a source to a sink or a sink to a source to
connect them. Audio from the source will then be sent to that sink.
- Click on a source or a sink to clear the links connected to that
source/sink.
Note that a sink can only be connected to one source, but one source
can be connected to many sinks.
To adjust the mixer output levels:
1) Open the mixer window with the main window View → Mixer menu
option, or press Ctrl-M.
2) Mixer levels can be adjusted with your keyboard or mouse in the
same way as the [Gain Controls](#gain).
### Solo Direct Monitor
When you enable or disable Direct Monitor on the Solo interface, the
interface will update the Mix A and B Outputs so that the DSP 1 & 2
Outputs are mixed in (or not) with the PCM 1 & 2 Outputs. Note how the
volume of the PCM outputs is also reduced when Direct Monitor is
enabled so that you can hear the DSP outputs (i.e. your Analogue
inputs) more clearly.
![4th Gen Solo Direct Monitor](../img/scarlett-4th-gen-solo-monitor.gif)
If you customise the Mix A/B mixer levels while Direct Monitor is
enabled, the new settings will be saved and used when Direct Monitor
is enabled again.
### 2i2 Direct Monitor
Similarly to the Solo interface, the 2i2 interface will update the Mix
A and B Outputs when you enable or disable Direct Monitor, but the 2i2
has Mono and Stereo options:
![4th Gen 2i2 Direct Monitor](../img/scarlett-4th-gen-2i2-monitor.gif)
Note how in Mono mode:
- the DSP 1 & 2 Outputs are mixed to both the left and right outputs
and in Stereo mode:
- DSP 1 (i.e. Analogue Input 1) is sent to the left output (Mix A),
and
- DSP 2 (i.e. Analogue Input 2) is sent to the right output (Mix B).
### Solo Mix Control
The Mix control is only available on the Solo interface. It switches
the source for the PCM 1 & 2 Inputs between the DSP Outputs and the
Mixer E & F Outputs.
![4th Gen Solo Mix Control](../img/scarlett-4th-gen-solo-mix.gif)
By default, enabling this control will mix the Analogue 1 & 2 Inputs
together before they are sent to the PCM 1 & 2 Inputs:
![4th Gen Solo Mixer E & F Outputs](../img/scarlett-4th-gen-solo-mix-e-f.png)
This can be useful if you want to treat the PCM 1 & 2 Inputs as a
stereo pair, and not have the line/instrument input panned hard left
and the microphone input panned hard right.
The mixer levels for the Mix E & F Outputs can adjusted to suit.
### 4i4 Routing and Mixing
Although the 4th Gen 4i4 has no explicit Direct Monitor control, it is
far more flexible because it has 6 PCM inputs, 6 PCM outputs, a 10×6
mixer, and 6 Analogue Hardware outputs.
Analogue Outputs 14 correspond to the Line Outputs 14 on the back of
the interface, and Analogue Outputs 56 correspond to the Headphone
Output on the front of the interface.
The default routing and mix for the 4i4 is shown below:
![4th Gen 4i4 Routing](../img/scarlett-4th-gen-4i4-routing.png)
Note that with the default routing/mix settings:
- The Analogue Inputs 14 are routed to the PCM Inputs 14 (the first
two going via the DSP).
- PCM Inputs 56 are used for Loopback (recording audio from your
computer).
- All the Hardware Inputs and PCM Outputs are connected to the Mixer
Inputs.
- PCM Outputs 14 are connected to the Analogue Outputs 14 (via the
mixer).
- The Line 12 Outputs (Analogue Outputs 12) and the Headphones
(Analogue Outputs 56) share the Mixer Outputs A & B.
#### 4i4 Sample Direct Monitor Configuration
A common configuration for the 4i4 is to send the PCM 1 & 2 Outputs
mixed with the Analogue Inputs 1 & 2 to the Headphones, while leaving
the Analogue Outputs 12 as they are. This is an advanced version of
the direct monitoring feature that is available on the Solo and 2i2.
It can be implemented by:
1) Route Mixer Outputs E & F to Analogue Outputs 5 & 6.
2) Turn up Mix E & F DSP 1 & 2 levels in the mixer (see the mixer
example above for [2i2 Direct Monitor](#2i2-direct-monitor)).
As there are only 6 Mixer Outputs, the PCM 5 & 6 Inputs (Loopback) are
now shared with the headphones. If you want to retain the Loopback
functionality without having the Analogue Inputs mixed in, you could:
- Route the PCM 1 & 2 Outputs directly to the PCM 5 & 6 Inputs, rather
than going via the mixer, or
- Free up Mixer Outputs A & B for Loopback by routing PCM Outputs 1 &
2 directly to Analogue Outputs 1 & 2.
Besides Direct Monitor, there are many other possibilities for
routing/mixing with the 4i4. For example, by using the additional PCM
Outputs and Inputs you could set up a mix-minus configuration for a
podcast/video call.
## Levels
The meters show the levels seen by the interface at every routing
sink: Hardware Outputs, Mixer Inputs, DSP Inputs, and PCM Inputs. Open
this window by selecting the View → Levels menu option or pressing
Ctrl-L.
![Levels](../img/window-levels-4th-gen-small.gif)
Look at this in conjunction with the routing window to understand
which meter corresponds to which source or sink.
Thanks for reading this far! If you appreciate the hundreds of hours
of work that went into the kernel driver, the control panel, and this
documentation, please consider supporting the author with a
[donation](../README.md#donations).

321
docs/iface-large.md Normal file
View File

@@ -0,0 +1,321 @@
# ALSA Scarlett Control Panel
## Large Scarlett 2nd and 3rd Gen and Clarett Interfaces
This document describes how to use the ALSA Scarlett Control Panel
with the larger Scarlett 2nd Gen, 3rd Gen, and Clarett USB interfaces:
- Scarlett 2nd Gen 6i6, 18i8, 18i20
- Scarlett 3rd Gen 4i4, 8i6, 18i8, 18i20
- Clarett 2Pre, 4Pre, 8Pre USB
- Clarett+ 2Pre, 4Pre, 8Pre
## Main Window
The main window is divided into three sections:
- Global Controls
- Analogue Input Controls
- Analogue Output Controls
The particular controls available depend on the interface model; the
3rd Gen 18i20 has all the controls so is shown here:
![Main Window](../img/window-main.png)
Note that the View menu option lets you open three other windows which
contain additional controls, described in the following sections:
- [Routing](#routing)
- [Mixer](#mixer)
- [Levels](#levels)
- [Startup](#startup)
### Global Controls
Global controls relate to the operation of the interface as a whole.
![Global Controls](../img/main-global.png)
#### Clock Source (interfaces with S/PDIF or ADAT inputs only)
Clock Source selects where the interface receives its digital clock
from. If you arent using S/PDIF or ADAT inputs, set this to Internal.
#### Sync Status
Sync Status indicates if the interface is locked to a valid digital
clock. If you arent using S/PDIF or ADAT inputs and the Sync Status
is Unlocked, change the Clock Source to Internal.
#### Sample Rate
Sample Rate is informative only, and displays the current sample rate
if the interface is currently in use. In ALSA, the sample rate is set
by the application using the interface, which is usually a sound
server such as PulseAudio, JACK, or PipeWire.
#### Speaker Switching (Scarlett 3rd Gen 18i8 and 18i20 only)
Speaker Switching lets you swap between two pairs of monitoring
speakers very easily.
When enabled (Main or Alt):
- Line Out 14 Volume Control Switches are locked to HW
- Line Out 3/4 routing is saved
- Line Out 3/4 routing is set to the Line Out 1/2 routing
When set to Main, Line outputs 3 and 4 are muted.
When set to Alt, Line outputs 1 and 2 are muted.
When disabled (Off):
- Global mute is activated ⭐
- Line Out 14 Volume Control Switches are unlocked
- Line Out 3/4 routing is restored to the saved values
⭐ You likely wont expect this to happen. Make sure to unmute the
outputs after disabling speaker switching if you want to hear
something again.
#### Talkback (Scarlett 3rd Gen 18i20 only)
Talkback lets you add another channel (usually the talkback mic) to a
mix with a button push, usually to talk to musicians, and without
using an additional mic channel.
The Talkback feature has a few parts:
- Talkback Microphone connected to Analogue Input 9
- Talkback Disable/Enable and Off/On software switches
- Talkback Off/On physical switch
- Talkback Mix (one switch per mix)
- Mix Input 25
To set up the talkback feature, set Mix Input 25 to the talkback
source (usually Analogue Input 9), enable the Talkback Mix switches
for the mixes you want the talkback input to be heard on, and change
the Talkback control from Disabled to Off. Leave the Mix Input 25 gain
controls at zero (127dB), otherwise the talkback inputs will be heard
even when talkback is disabled/off.
Pressing the Talkback switch on the device will then lower the volume
of the other inputs on the mixes for which talkback is enabled and
unmute Mix Input 25 on those mixes.
Talkback can also be activated by changing the Talkback control from
Off to On.
The talkback microphone can also be used just the same as any of the
other analogue inputs and routed to a physical output, PCM input, or
mixer input.
### Analogue Input Controls
This section is applicable to all interfaces except the Scarlett 2nd
Gen 18i20 which has hardware-only buttons for these features.
![Analogue Input Controls](../img/main-inputs.png)
#### Inst
The Inst buttons are used to select between Mic/Line and Instrument
level/impedance. When plugging in microphones or line-level equipment
(such as a synthesizer, external preamp, or effects processor) to the
input, set it to “Line”. The “Inst” setting is for instruments with
pickups such as guitars.
#### Air (Scarlett 3rd Gen and Clarett only)
Enabling Air will transform your recordings and inspire you while
making music.
#### Pad
Enabling Pad engages a 10dB attenuator in the channel, giving you more
headroom for very hot signals.
#### Phantom Power (48V)
Scarlett 2nd Gen and Clarett devices have a hardware button for
controlling phantom power.
Scarlett 3rd Gen devices have hardware and software control of phantom
power. Turning the “48V” switch on sends “Phantom Power” to the XLR
microphone input. This is required for some microphones (such as
condensor microphones), and damaging to some microphones (particularly
vintage ribbon microphones).
On Scarlett 3rd Gen devices, phantom power is turned off by default
when the interface is turned on. This can be changed in the startup
configuration (menu option View → Startup).
### Analogue Output Controls
The analogue output controls let you set the output volume (gain) on
the analogue line out and headphone outputs. All interfaces support
setting the gain and muting individual channels.
![Analogue Output Controls](../img/main-outputs.png)
Click and drag up/down on the volume dial to change the volume, use
your arrow keys, Home/End/PgUp/PgDn keys, or use your mouse scroll
wheel to adjust. You can also double-click on it to quickly toggle the
volume between off and 0dB.
The biggest interfaces: Scarlett 2nd Gen 18i20, 3rd Gen 18i8, and 3rd
Gen 18i20 have a switchable hardware/software volume control. The
position of the big volume knob on the front of the interface is
indicated by the “HW” dial in the GUI. The analogue outputs can have
their volume set either by the knob (“HW” setting of of the HW/SW
button) or by the dials on each output (“SW” setting of the HW/SW
button).
When set to HW, the mute/volume status for those channels is
controlled by the hardware volume knob and the global dim/mute
controls and the software volume dial and mute button for those
channels are disabled.
There are “mute” and “dim” (reduce volume) buttons below the “HW” dial
which affect only the outputs with “HW” control enabled. The 3rd Gen
18i8 doesnt have physical buttons or indicator lights for these
controls, but the 18i20 devices do.
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
in addition to the software volume control, therefore both must be
turned up in order to hear anything. The other (line 3+) analogue
outputs are only controlled by the software controls.
The volume controls for the headphone outputs on each interface
operate in addition to any other hardware or software volume controls
for those channels. When using headphones, the volumes for those
channels would usually be set to 0dB and the actual volume controlled
with the physical headphone volume control(s).
## Routing
The routing window allows complete control of signal routing between
the hardware inputs/outputs, internal mixer, and PCM (USB)
inputs/outputs.
![Routing Window](../img/window-routing.png)
To manage the routing connections:
- Click and drag from a source to a sink or a sink to a source to
connect them. Audio from the source will then be sent to that sink.
- Click on a source or a sink to clear the links connected to that
source/sink.
Note that a sink can only be connected to one source, but one source
can be connected to many sinks. If you want a sink to receive input
from more than one source, use the mixer inputs and outputs:
- Connect the sources that you want to mix together to mixer inputs
- Connect mixer outputs to the sinks that you want to receive the
mixed audio
- Use the Mixer window to set the amount of each mixer input that is
sent to each mixer output
The Presets menu can be used to clear all connections, or to set up
common configurations:
- The “Direct” preset sets up the usual configuration using the
interface as a regular audio interface by connecting:
- all Hardware Inputs to PCM Inputs
- all PCM Outputs to Hardware Outputs
- The “Preamp” preset connects all Hardware Inputs to Hardware
Outputs.
- The “Stereo Out” preset connects PCM 1 and 2 Outputs to pairs of
Hardware Outputs.
The Direct routing configuration is the simplest most-generally-useful
configuration:
![Direct Routing](../img/routing-direct.png)
### Loopback
Scarlett 2nd Gen, Clarett USB, and Clarett+ interfaces have as many
PCM Inputs as Hardware Inputs. Scarlett 3rd Gen interfaces have two
more PCM Inputs which Focusrite Control uses as “Loopback” inputs.
The “Loopback” feature advertised for Scarlett 3rd Gen devices is
actually a limitation of the proprietary Focusrite Control software.
All supported devices with a mixer (thats all but the 2nd and 3rd Gen
Solo/2i2 interfaces) support full reassignment of the PCM Inputs, so
you can have any PCM Input as a “Loopback” or assigned to any other
source.
### Talkback
The Scarlett 3rd Gen 18i20 talkback microphone is Analogue Input 9 and
can be routed like any other source. If you want to record using it,
there is no need for the loopback hack suggested by the manufacturer.
Just route it to a PCM Input.
## Mixer
If you use the Routing window to connect Sources to Mixer Inputs and
Mixer Outputs to Sinks, then you can use the Mixer window to set the
amount of each Mixer Input that is sent to each Mixer Output using a
matrix of controls:
![Mixer Window](../img/window-mixer.png)
Click and drag up/down on the gain controls to adjust, or use your
mouse scroll wheel. You can also double-click on the control to
quickly toggle between off and 0dB.
## Levels
The Levels window shows the current levels of the hardware outputs, the
mixer inputs, and the PCM inputs.
![Levels Window](../img/window-levels-3rd-gen.png)
Look at this in conjunction with the routing window to understand
which meter corresponds to which source or sink.
## Startup
The Startup window is used to configure settings that are
applied/relevant when the interface is powered on.
![Startup Window](../img/window-startup.png)
### Standalone
When Standalone mode is enabled, the interface will continue to route
audio as per the previous routing and mixer settings after it has been
disconnected from a computer. By configuring the routing between the
hardware and mixer inputs and outputs appropriately, the interface can
act as a standalone preamp or mixer.
Standalone mode is supported on all devices supported by the kernel
driver. Even the Scarlett 3rd Gen 4i4 (which is bus-powered) will
operate in standalone mode.
### Phantom Power Persistence (Scarlett 3rd Gen only)
When Phantom Power Persistence is enabled, the interface will restore
the previous Phantom Power/48V setting when the interface is turned
on. For the safety of microphones which can be damaged by phantom
power, the interface defaults to having phantom power disabled when it
is turned on.
### Reset Configuration
This will reset the configuration of the interface to the factory
defaults (except for MSD mode which is left off).
### Update Firmware
If a firmware update is found in the `/usr/share/firmware/scarlett2`
directory, then an option to update the firmware will be available
here.

56
docs/iface-small.md Normal file
View File

@@ -0,0 +1,56 @@
# ALSA Scarlett Control Panel
## Small Scarlett 3rd Gen Interfaces
The Scarlett 3rd Gen Solo and 2i2 interfaces have just a few buttons to control
the Air, Line, Phantom Power, and Direct Monitor settings. Mostly
nothing that you cant access from the front panel anyway.
![Gen 3 Small Interfaces](../img/iface-small-gen3.png)
## Input Controls
### Air
Enabling Air will transform your recordings and inspire you while
making music.
### Inst
The Inst buttons are used to select between Mic/Line and Instrument
level/impedance. When plugging in microphones or line-level equipment
(such as a synthesizer, external preamp, or effects processor) to the
input, set it to “Line”. The “Inst” setting is for instruments with
pickups such as guitars.
### 48V (Phantom Power)
Turning the “48V” switch on sends “Phantom Power” to the XLR
microphone input(s). This is required for some microphones (such as
condensor microphones), and damaging to some microphones (particularly
vintage ribbon microphones).
## Output Controls
### Direct Monitor
Direct Monitor sends the analogue input signals to the analogue
outputs for zero-latency monitoring.
On the 2i2, you have the choice of Mono or Stereo monitoring when you
click the button. Mono sends both inputs to the left and right
outputs. Stereo sends input 1 to the left, and input 2 to the right
output.
## Startup Controls
#### Phantom Power Persistence
By default, phantom power is turned off when the interface is turned
on. This can be changed in the startup configuration (menu option View
→ Startup).
The one control not accessible from the front panel is “Phantom Power
Persistence” (menu option View → Startup) which controls the Phantom
Power state when the interface is powered on.

BIN
img/alsa-scarlett-gui.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 MiB

After

Width:  |  Height:  |  Size: 1.1 MiB

BIN
img/firmware-missing.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

BIN
img/firmware-updating.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

BIN
img/iface-4th-gen-big.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

BIN
img/iface-4th-gen-small.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 52 KiB

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 113 KiB

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 31 KiB

BIN
img/main-global.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

BIN
img/main-inputs.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
img/main-outputs.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 53 KiB

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 180 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 245 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 372 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 155 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 471 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 57 KiB

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 114 KiB

After

Width:  |  Height:  |  Size: 123 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 72 KiB

After

Width:  |  Height:  |  Size: 63 KiB

View File

@@ -1,4 +1,4 @@
# SPDX-FileCopyrightText: 2022 Geoffrey D. Bennett <g@b4.vu>
# SPDX-FileCopyrightText: 2022-2025 Geoffrey D. Bennett <g@b4.vu>
# SPDX-License-Identifier: GPL-3.0-or-later
# Credit to Tom Tromey and Paul D. Smith:
@@ -12,7 +12,9 @@ VERSION := $(shell \
DEPDIR := .deps
DEPFLAGS = -MT $@ -MMD -MP -MF $(DEPDIR)/$*.d
CFLAGS += -Wall -Werror -ggdb -fno-omit-frame-pointer -O2 -D_FORTIFY_SOURCE=2
CFLAGS ?= -ggdb -fno-omit-frame-pointer -fPIE -O2
CFLAGS += -Wall -Werror
CFLAGS += -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=3
CFLAGS += -DVERSION=\"$(VERSION)\"
CFLAGS += -Wno-error=deprecated-declarations
@@ -25,6 +27,7 @@ CFLAGS += $(shell $(PKG_CONFIG) --cflags alsa)
LDFLAGS += $(shell $(PKG_CONFIG) --libs glib-2.0)
LDFLAGS += $(shell $(PKG_CONFIG) --libs gtk4)
LDFLAGS += $(shell $(PKG_CONFIG) --libs alsa)
LDFLAGS += -lm -lcrypto -pie
COMPILE.c = $(CC) $(DEPFLAGS) $(CFLAGS) -c
@@ -50,7 +53,7 @@ GLIB_COMPILE_RESOURCES := $(shell $(PKG_CONFIG) --variable=glib_compile_resource
all: $(TARGET) $(DESKTOP_FILE)
clean:
clean: depclean
rm -f $(TARGET) $(DESKTOP_FILE) $(OBJS) $(XML_OBJ)
depclean:
@@ -64,7 +67,7 @@ $(DEPFILES):
include $(wildcard $(DEPFILES))
$(TARGET): $(OBJS)
cc -o $(TARGET) $(OBJS) ${LDFLAGS} -lm
$(CC) -o $(TARGET) $(OBJS) ${LDFLAGS}
ifeq ($(PREFIX),)
PREFIX := /usr/local

View File

@@ -1,8 +1,10 @@
// SPDX-FileCopyrightText: 2022 Geoffrey D. Bennett <g@b4.vu>
// SPDX-FileCopyrightText: 2022-2025 Geoffrey D. Bennett <g@b4.vu>
// SPDX-License-Identifier: GPL-3.0-or-later
#include "about.h"
static GdkTexture *logo = NULL;
void activate_about(
GSimpleAction *action,
GVariant *parameter,
@@ -11,19 +13,26 @@ void activate_about(
GtkWindow *w = GTK_WINDOW(data);
const char *authors[] = {
"Geoffrey D. Bennett",
"Geoffrey D. Bennett <g@b4.vu>",
NULL
};
if (!logo)
logo = gdk_texture_new_from_resource(
"/vu/b4/alsa-scarlett-gui/icons/vu.b4.alsa-scarlett-gui.png"
);
gtk_show_about_dialog(
w,
"program-name", "ALSA Scarlett Gen 2/3 Control Panel",
"program-name", "ALSA Scarlett Control Panel",
"version", "Version " VERSION,
"comments", "GTK4 interface to the ALSA Scarlett Gen 2/3 Mixer controls",
"comments",
"Gtk4 GUI for the ALSA controls presented by the\n"
"Linux kernel Focusrite USB drivers",
"website", "https://github.com/geoffreybennett/alsa-scarlett-gui",
"copyright", "Copyright 2022 Geoffrey D. Bennett",
"copyright", "Copyright 2022-2025 Geoffrey D. Bennett",
"license-type", GTK_LICENSE_GPL_3_0,
"logo-icon-name", "alsa-scarlett-gui-logo",
"logo", logo,
"title", "About ALSA Scarlett Mixer Interface",
"authors", authors,
NULL

View File

@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2022 Geoffrey D. Bennett <g@b4.vu>
// SPDX-FileCopyrightText: 2022-2025 Geoffrey D. Bennett <g@b4.vu>
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once

View File

@@ -1,8 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<gresources>
<gresource prefix="/vu/b4/alsa-scarlett-gui/icons">
<file alias="alsa-scarlett-gui-logo.png">img/alsa-scarlett-gui-logo.png</file>
<file alias="vu.b4.alsa-scarlett-gui.png">img/vu.b4.alsa-scarlett-gui.png</file>
<file alias="socket.svg">img/socket.svg</file>
<file alias="audio-volume-high.svg">img/audio-volume-high.svg</file>
<file alias="audio-volume-low.svg">img/audio-volume-low.svg</file>
<file alias="audio-volume-medium.svg">img/audio-volume-medium.svg</file>
<file alias="audio-volume-muted.svg">img/audio-volume-muted.svg</file>
</gresource>
<gresource prefix="/vu/b4/alsa-scarlett-gui">
<file>alsa-scarlett-gui.css</file>

View File

@@ -1,18 +1,373 @@
/* Top-level window frame */
.window-frame {
background: black;
color: white;
padding: 15px;
border-radius: 0px;
border: none;
}
/* Top-level window content */
.window-content {
padding: 15px;
border: 2px solid #800000;
border-radius: 20px;
}
/* Title of the window */
.window-title {
font-size: large;
}
/* Links */
.linktext {
color: #89CFF0;
}
/* Label above controls-content */
.controls-label {
font-size: smaller;
margin-top: -4px;
}
/* controls-content boxes */
.controls-content {
background: #141414;
padding: 10px;
border: 1px solid #a00000;
border-radius: 5px;
color: #d0d0d0;
}
/* Tighten up routing groups and make the background a little lighter */
.window-routing .controls-content {
background: #181818;
padding: 5px;
}
/* Used when the controls content is at the top level */
.top-level-content {
background: #141414;
}
.route-label {
font-size: smaller;
border-radius: 3px;
}
.route-label:hover {
background: @theme_selected_bg_color;
outline: 2px solid @theme_selected_bg_color;
.route-label-hover {
background: #801010;
outline: 2px solid #801010;
}
.route-label:drop(active) {
box-shadow: none;
background: @theme_selected_bg_color;
background: #801010;
}
button {
.mixer-label {
}
.mixer-label-hover {
font-weight: bold;
text-shadow: 0 0 5px #00c000, 0 0 15px #00c000;
}
label.gain {
font-size: smaller;
}
/* Default button style */
.window-frame button {
border: 1px solid #303030;
background: linear-gradient(175deg, #202020, #282828);
box-shadow: none;
font-weight: bold;
color: #ffffff;
}
.window-frame button.toggle {
color: #808080;
}
.window-frame button:focus:focus-visible {
outline: 2px solid #801010;
}
/* padding doesn't work when selected with .window-frame, so use
* .toggle instead
*/
button.toggle {
padding: 0px 5px 0px 5px;
}
.window-frame button:checked {
color: #ffffff;
border: 1px solid #404040;
}
.window-frame button:hover {
background: #303030;
}
.window-frame button:disabled {
background: #202020;
color: #505050;
}
/* Stop text shadows on buttons from being applied to the popup menu */
.window-frame button > label > * {
text-shadow: none;
}
/* Button controls that are always disabled because they indicate status */
.window-frame button.fixed {
color: #ffffff;
filter: none;
}
.window-frame button.fixed label {
color: #ffffff;
filter: none;
}
/* Combobox controls that are always disabled because they indicate status */
.window-frame combobox.fixed > box > button {
color: #ffffff;
}
/* Buttons that glow when on */
.window-frame button.sync-status {
text-shadow: 0 0 5px #a00000, 0 0 15px #800000;
}
.window-frame button.sync-status:checked {
text-shadow: 0 0 5px #00c000, 0 0 15px #00c000;
}
.window-frame button.input-select:checked {
color: #ffffff;
text-shadow: 0 0 5px #00ff00, 0 0 10px #00ff00, 0 0 15px #00ff00;
filter: none;
}
.window-frame button.input-link:checked {
text-shadow: 0 0 5px #00c000, 0 0 15px #00c000;
}
.window-frame button.autogain:checked {
text-shadow: 0 0 5px #0000ff, 0 0 15px #0000ff;
}
.window-frame button.speaker-switching-enable:checked {
text-shadow: 0 0 5px #00c000, 0 0 15px #00c000;
}
.window-frame button.speaker-switching-alt {
color: #ffffff;
text-shadow: 0 0 5px #00ff00, 0 0 15px #00c000;
}
.window-frame button.speaker-switching-alt:checked {
text-shadow: 0 0 5px #ff0000, 0 0 15px #c00000;
}
.window-frame button.talkback-enable:checked {
text-shadow: 0 0 5px #00c000, 0 0 15px #00c000;
}
.window-frame button.talk:checked {
text-shadow: 0 0 5px #00c000, 0 0 15px #00c000;
}
/* orange */
.window-frame .vocaster button.autogain:checked {
text-shadow: 0 0 5px #ffc000, 0 0 15px #ffc000;
}
.window-frame button.safe:checked {
text-shadow: 0 0 5px #00c000, 0 0 15px #00c000;
}
.window-frame button.safe:checked:disabled {
text-shadow: 0 0 5px #005000, 0 0 15px #005000;
}
.window-frame button.inst:checked {
text-shadow: 0 0 5px #ff0000, 0 0 15px #ff0000;
}
.window-frame .gen4 button.inst:checked {
text-shadow: 0 0 5px #00c000, 0 0 15px #00c000;
}
.window-frame .gen4 button.inst:checked:disabled {
text-shadow: 0 0 5px #005000, 0 0 15px #005000;
}
.window-frame button.pcm-input-mix:checked {
text-shadow: 0 0 5px #00c000, 0 0 15px #00c000;
}
/* Air Checked (Gen 3) */
.window-frame button.air:checked {
text-shadow: 0 0 5px #ffc000, 0 0 15px #ffc000;
}
/* Air Selections (Gen 4) */
.window-frame button.air.selected-presence > label {
color: #ffffff;
text-shadow: 0 0 5px #00c000, 0 0 15px #00c000;
}
.window-frame button.air.selected-presencedrive > label {
color: #ffffff;
text-shadow: 0 0 5px #ffc000, 0 0 15px #ffc000;
}
.window-frame button.air.selected-presence:disabled > label {
color: #505050;
text-shadow: 0 0 5px #005000, 0 0 15px #005000;
}
.window-frame button.air.selected-presencedrive:disabled > label {
color: #505050;
text-shadow: 0 0 5px #503c00, 0 0 15px #503c00;
}
.window-frame button.pad:checked {
text-shadow: 0 0 5px #00c000, 0 0 15px #00c000;
}
.window-frame button.gain-switch:checked {
text-shadow: 0 0 5px #00c000, 0 0 15px #00c000;
}
.window-frame button.phantom:checked {
text-shadow: 0 0 5px #ff0000, 0 0 15px #c00000;
}
.window-frame .gen4 button.phantom:checked {
text-shadow: 0 0 5px #00c000, 0 0 15px #00c000;
}
.window-frame .gen4 button.phantom:checked:disabled {
text-shadow: 0 0 5px #005000, 0 0 15px #005000;
}
.window-frame button.input-mute:checked {
text-shadow: 0 0 5px #ff0000, 0 0 15px #c00000;
}
.window-frame button.dsp:checked {
text-shadow: 0 0 5px #00c000, 0 0 15px #00c000;
}
/* Direct Monitor Checked (Solo) */
.window-frame .direct-monitor:checked {
text-shadow: 0 0 5px #00c000, 0 0 15px #00c000;
}
/* Direct Monitor Selections (2i2) */
.window-frame button.direct-monitor.selected-mono > label {
color: #ffffff;
text-shadow: 0 0 5px #c0c0c0, 0 0 15px #c0c0c0;
}
.window-frame button.direct-monitor.selected-stereo > label {
color: #ffffff;
text-shadow: 0 0 5px #00c000, 0 0 15px #00c000;
}
/* Sample Rates */
.window-frame button.sample-rate.sample-rate-44100 {
text-shadow: 0 0 5px #00c000, 0 0 15px #00c000;
}
.window-frame button.sample-rate.sample-rate-48000 {
text-shadow: 0 0 5px #00c000, 0 0 15px #00c000;
}
.window-frame button.sample-rate.sample-rate-88200 {
text-shadow: 0 0 5px #ff8000, 0 0 15px #ff8000;
}
.window-frame button.sample-rate.sample-rate-96000 {
text-shadow: 0 0 5px #ff8000, 0 0 15px #ff8000;
}
.window-frame button.sample-rate.sample-rate-176400 {
text-shadow: 0 0 5px #ff0000, 0 0 15px #c00000;
}
.window-frame button.sample-rate.sample-rate-192000 {
text-shadow: 0 0 5px #ff0000, 0 0 15px #c00000;
}
/* Button controls where checked is dimmer */
/* Mute button */
.window-frame button.mute {
color: #ffffff;
-gtk-icon-shadow: 0 0 5px #00c000, 0 0 15px #00c000;
border-color: #404040;
}
.window-frame button.mute:checked {
-gtk-icon-shadow: 0 0 5px #ff0000, 0 0 15px #c00000;
border-color: #303030;
}
/* Dim button */
.window-frame button.dim {
color: #ffffff;
-gtk-icon-shadow: 0 0 5px #00c000, 0 0 15px #00c000;
border-color: #404040;
}
.window-frame button.dim:checked {
-gtk-icon-shadow: 0 0 5px #ffc000, 0 0 15px #ffc000;
border-color: #303030;
}
/* SW/HW button */
.window-frame button.sw-hw {
color: #ffffff;
-gtk-icon-shadow: 0 0 5px #00c000, 0 0 15px #00c000;
border-color: #404040;
}
.window-frame button.sw-hw:checked {
color: #808080;
-gtk-icon-shadow: 0 0 5px #ffc000, 0 0 15px #ffc000;
border-color: #303030;
}
/* Textview used for long descriptions in the startup window */
.window-frame textview {
color: #ffffff;
background: none;
}
.window-frame textview > text {
background: none;
}
/* Bigger buttons in the startup window */
.window-frame .window-startup button {
padding: 5px;
}
/* Separators */
.window-frame separator {
background: #800000;
}
.window-frame .big-padding {
padding: 50px;
}
/* Bigger buttons in confirmation dialogs */
.window-frame .big-padding button {
padding: 5px 30px;
}

View File

@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2022 Geoffrey D. Bennett <g@b4.vu>
// SPDX-FileCopyrightText: 2022-2025 Geoffrey D. Bennett <g@b4.vu>
// SPDX-License-Identifier: GPL-3.0-or-later
#include "alsa.h"
@@ -99,6 +99,53 @@ static void alsa_parse_enum_items(
}
}
static void alsa_parse_int_array(
snd_config_t *node,
long **int_values
) {
int count = snd_config_is_array(node);
if (count < 0) {
printf("error: parse int array value %d\n", count);
return;
}
*int_values = calloc(count, sizeof(long));
int item_num = 0;
snd_config_iterator_t i, next;
snd_config_for_each(i, next, node) {
snd_config_t *node = snd_config_iterator_entry(i);
const char *key;
int err = snd_config_get_id(node, &key);
if (err < 0)
fatal_alsa_error("snd_config_get_id error", err);
int type = snd_config_get_type(node);
if (type == SND_CONFIG_TYPE_STRING) {
const char *string_value;
err = snd_config_get_string(node, &string_value);
if (err < 0)
fatal_alsa_error("snd_config_get_string error", err);
if (strcmp(string_value, "true") == 0)
(*int_values)[item_num++] = 1;
} else if (type == SND_CONFIG_TYPE_INTEGER) {
long int_value;
err = snd_config_get_integer(node, &int_value);
if (err < 0)
fatal_alsa_error("snd_config_get_integer error", err);
(*int_values)[item_num++] = int_value;
}
}
}
// parse a comment node and update elem, e.g.:
//
// comment {
@@ -133,7 +180,7 @@ static void alsa_parse_comment_node(
if (err < 0)
fatal_alsa_error("snd_config_get_string error", err);
if (strstr(access, "write"))
elem->writable = 1;
elem->is_writable = 1;
} else if (strcmp(key, "type") == 0) {
if (type != SND_CONFIG_TYPE_STRING) {
printf("type type not string\n");
@@ -149,15 +196,59 @@ static void alsa_parse_comment_node(
elem->type = SND_CTL_ELEM_TYPE_ENUMERATED;
else if (strcmp(type, "INTEGER") == 0)
elem->type = SND_CTL_ELEM_TYPE_INTEGER;
} else if (strcmp(key, "count") == 0) {
long count;
err = snd_config_get_integer(node, &count);
if (err < 0)
fatal_alsa_error("snd_config_get_integer error", err);
elem->count = count;
} else if (strcmp(key, "item") == 0) {
alsa_parse_enum_items(node, elem);
} else if (strcmp(key, "range") == 0) {
if (type != SND_CONFIG_TYPE_STRING) {
printf("range type not string\n");
return;
}
const char *range;
err = snd_config_get_string(node, &range);
if (err < 0)
fatal_alsa_error("snd_config_get_string error", err);
// Parse the range string and update elem->min_val and elem->max_val
int min_val, max_val;
if (sscanf(range, "%d - %d", &min_val, &max_val) == 2) {
elem->min_val = min_val;
elem->max_val = max_val;
}
} else if (strcmp(key, "dbmin") == 0) {
if (type != SND_CONFIG_TYPE_INTEGER) {
printf("dbmin type not integer\n");
return;
}
long dbmin;
err = snd_config_get_integer(node, &dbmin);
if (err < 0)
fatal_alsa_error("snd_config_get_integer error", err);
elem->min_cdB = dbmin;
} else if (strcmp(key, "dbmax") == 0) {
if (type != SND_CONFIG_TYPE_INTEGER) {
printf("dbmax type not integer\n");
return;
}
long dbmax;
err = snd_config_get_integer(node, &dbmax);
if (err < 0)
fatal_alsa_error("snd_config_get_integer error", err);
elem->max_cdB = dbmax;
}
}
}
static int alsa_config_to_new_elem(
snd_config_t *config,
struct alsa_elem *elem
struct alsa_card *card,
snd_config_t *config
) {
const char *s;
int id;
@@ -166,8 +257,11 @@ static int alsa_config_to_new_elem(
int value_type = -1;
char *string_value = NULL;
long int_value;
long *int_values = NULL;
int err;
struct alsa_elem elem = {};
err = snd_config_get_id(config, &s);
if (err < 0)
fatal_alsa_error("snd_config_get_id error", err);
@@ -224,11 +318,14 @@ static int alsa_config_to_new_elem(
fatal_alsa_error("snd_config_get_string error", err);
string_value = strdup(s);
} else if (type == SND_CONFIG_TYPE_COMPOUND) {
elem->count = snd_config_is_array(node);
elem.count = snd_config_is_array(node);
if (strcmp(name, "Level Meter") == 0) {
seen_value = 1;
value_type = SND_CONFIG_TYPE_INTEGER;
int_value = 0;
} else if (elem.count == 2 && strncmp(name, "Master", 6) == 0) {
alsa_parse_int_array(node, &int_values);
} else {
goto fail;
}
@@ -242,19 +339,24 @@ static int alsa_config_to_new_elem(
// comment node?
} else if (strcmp(key, "comment") == 0) {
alsa_parse_comment_node(node, elem);
alsa_parse_comment_node(node, &elem);
// this isn't needed
} else if (strcmp(key, "index") == 0) {
} else {
printf("skipping unknown node %s for %d\n", key, id);
goto fail;
}
}
// check iface value; only interested in MIXER and PCM
// check iface value; only interested in CARD, MIXER, and PCM
if (!iface) {
printf("missing iface node in control id %d\n", id);
goto fail;
}
if (strcmp(iface, "MIXER") != 0 &&
if (strcmp(iface, "CARD") != 0 &&
strcmp(iface, "MIXER") != 0 &&
strcmp(iface, "PCM") != 0)
goto fail;
@@ -272,21 +374,21 @@ static int alsa_config_to_new_elem(
// integer in config
if (value_type == SND_CONFIG_TYPE_INTEGER) {
elem->value = int_value;
elem.value = int_value;
// string in config
} else if (value_type == SND_CONFIG_TYPE_STRING) {
// translate boolean true/false
if (elem->type == SND_CTL_ELEM_TYPE_BOOLEAN) {
if (elem.type == SND_CTL_ELEM_TYPE_BOOLEAN) {
if (strcmp(string_value, "true") == 0)
elem->value = 1;
elem.value = 1;
// translate enum string value to integer
} else if (elem->type == SND_CTL_ELEM_TYPE_ENUMERATED) {
for (int i = 0; i < elem->item_count; i++) {
if (strcmp(string_value, elem->item_names[i]) == 0) {
elem->value = i;
} else if (elem.type == SND_CTL_ELEM_TYPE_ENUMERATED) {
for (int i = 0; i < elem.item_count; i++) {
if (strcmp(string_value, elem.item_names[i]) == 0) {
elem.value = i;
break;
}
}
@@ -297,11 +399,30 @@ static int alsa_config_to_new_elem(
}
}
elem->numid = id;
elem->name = name;
elem.card = card;
elem.numid = id;
elem.name = name;
// duplicate the element for each channel except for the Level Meter
int count = elem.count;
if (strcmp(elem.name, "Level Meter") == 0)
count = 1;
// for each channel, create a new element and add it to the card
// incrementing the index each time
for (int i = 0; i < count; i++, elem.index++) {
if (count > 1)
elem.value = int_values[i];
int array_len = card->elems->len;
g_array_set_size(card->elems, array_len + 1);
g_array_index(card->elems, struct alsa_elem, array_len) = elem;
}
free(iface);
free(string_value);
free(int_values);
return 0;
@@ -309,6 +430,7 @@ fail:
free(iface);
free(name);
free(string_value);
free(int_values);
return -1;
}
@@ -333,18 +455,8 @@ static void alsa_config_to_new_card(
if (snd_config_get_type(config) != SND_CONFIG_TYPE_COMPOUND)
continue;
struct alsa_elem elem = {};
elem.card = card;
// create the element
int err = alsa_config_to_new_elem(node, &elem);
if (err)
continue;
if (card->elems->len <= elem.numid)
g_array_set_size(card->elems, elem.numid + 1);
g_array_index(card->elems, struct alsa_elem, elem.numid) = elem;
alsa_config_to_new_elem(card, node);
}
}
@@ -396,5 +508,8 @@ void create_sim_from_file(GtkWindow *w, char *fn) {
snd_config_delete(config);
alsa_set_lr_nums(card);
alsa_get_routing_controls(card);
create_card_window(card);
}

View File

@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2022 Geoffrey D. Bennett <g@b4.vu>
// SPDX-FileCopyrightText: 2022-2025 Geoffrey D. Bennett <g@b4.vu>
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once

1000
src/alsa.c

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2022 Geoffrey D. Bennett <g@b4.vu>
// SPDX-FileCopyrightText: 2022-2025 Geoffrey D. Bennett <g@b4.vu>
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
@@ -17,27 +17,46 @@ struct alsa_card;
// typedef for callbacks to update widgets when the alsa element
// notifies of a change
typedef void (AlsaElemCallback)(struct alsa_elem *);
typedef void (AlsaElemCallback)(struct alsa_elem *, void *);
// port categories for routing_src and routing_snk entries
// must match the level meter ordering from the driver
enum {
// Hardware inputs/outputs
PC_HW = 0,
// Mixer inputs/outputs
PC_MIX = 1,
// PCM inputs/outputs
PC_PCM = 2,
// number of port categories
PC_COUNT = 3
PC_OFF, // Off (the source when a sink is not connected)
PC_HW, // Hardware inputs/outputs
PC_MIX, // Mixer inputs/outputs
PC_DSP, // DSP inputs/outputs
PC_PCM, // PCM inputs/outputs
PC_COUNT // number of port categories
};
// names for the port categories
extern const char *port_category_names[PC_COUNT];
// hardware types
enum {
HW_TYPE_ANALOGUE,
HW_TYPE_SPDIF,
HW_TYPE_ADAT,
HW_TYPE_COUNT
};
// driver types
// NONE is 1st Gen or Scarlett2 before hwdep support was added
// (no erase config or firmware update support)
// HWDEP is the Scarlett2 driver after hwdep support was added
// SOCKET is the FCP driver
enum {
DRIVER_TYPE_NONE,
DRIVER_TYPE_HWDEP,
DRIVER_TYPE_SOCKET,
DRIVER_TYPE_SOCKET_UNINIT,
DRIVER_TYPE_COUNT
};
// names for the hardware types
extern const char *hw_type_names[HW_TYPE_COUNT];
// is a drag active, and whether dragging from a routing source or a
// routing sink
enum {
@@ -56,7 +75,7 @@ struct routing_src {
// the enum id of the alsa item
int id;
// PC_MIX, PC_PCM, or PC_HW
// PC_OFF, PC_DSP, PC_MIX, PC_PCM, or PC_HW
int port_category;
// 0-based count within port_category
@@ -65,6 +84,9 @@ struct routing_src {
// the alsa item name
char *name;
// for PC_HW, the hardware type
int hw_type;
// the number (or translated letter; A = 1) in the item name
int lr_num;
@@ -79,8 +101,6 @@ struct routing_src {
// entry in alsa_card routing_snks (routing sinks) array for alsa
// elements that are routing sinks like Analogue Output 01 Playback
// Enum
// port_category is set to PC_MIX, PC_PCM, PC_HW
// port_num is a count (0-based) within that category
struct routing_snk {
// location within the array
@@ -89,17 +109,23 @@ struct routing_snk {
// pointer back to the element this entry is associated with
struct alsa_elem *elem;
// PC_MIX, PC_PCM, or PC_HW
int port_category;
// box widget on the routing page
GtkWidget *box_widget;
// 0-based count within port_category
int port_num;
// socket widget on the routing page
GtkWidget *socket_widget;
// the mixer label widgets for this sink
GtkWidget *mixer_label_top;
GtkWidget *mixer_label_bottom;
};
// hold one callback & its data
struct alsa_elem_callback {
AlsaElemCallback *callback;
void *data;
};
// entry in alsa_card elems (ALSA control elements) array
struct alsa_elem {
@@ -111,27 +137,31 @@ struct alsa_elem {
const char *name;
int type;
int count;
int index;
// for the number (or translated letter; A = 1) in the item name
// TODO: move this to struct routing_snk?
// for gain/volume elements, the value range, dB type, and dB range
int min_val;
int max_val;
int dB_type;
int min_cdB;
int max_cdB;
// level meter labels
char **meter_labels;
// for routing sinks
int is_routing_snk;
int port_category;
int port_num;
int hw_type;
int lr_num;
// the primary GTK widget and callback function for this ALSA
// control element
GtkWidget *widget;
AlsaElemCallback *widget_callback;
// text label for volume controls
// handle for routing controls
// second button for dual controls
GtkWidget *widget2;
// for boolean buttons, the two possible texts
// for dual buttons, the four possible texts
const char *bool_text[4];
// the callback functions for this ALSA control element
GList *callbacks;
// for simulated elements, the current state
int writable;
int is_writable;
int is_volatile;
long value;
// for simulated enumerated elements, the items
@@ -142,13 +172,16 @@ struct alsa_elem {
struct alsa_card {
int num;
char *device;
uint32_t pid;
char *serial;
char *name;
int driver_type;
char *fcp_socket;
int best_firmware_version;
snd_ctl_t *handle;
struct pollfd pfd;
int firmware_version;
GArray *elems;
struct alsa_elem *sample_capture_elem;
struct alsa_elem *level_meter_elem;
GArray *routing_srcs;
GArray *routing_snks;
GIOChannel *io_channel;
@@ -158,6 +191,7 @@ struct alsa_card {
GtkWidget *window_mixer;
GtkWidget *window_levels;
GtkWidget *window_startup;
GtkWidget *window_modal;
GtkWidget *window_main_contents;
GtkWidget *routing_grid;
GtkWidget *routing_lines;
@@ -165,12 +199,13 @@ struct alsa_card {
GtkWidget *routing_hw_out_grid;
GtkWidget *routing_pcm_in_grid;
GtkWidget *routing_pcm_out_grid;
GtkWidget *routing_dsp_in_grid;
GtkWidget *routing_dsp_out_grid;
GtkWidget *routing_mixer_in_grid;
GtkWidget *routing_mixer_out_grid;
GtkWidget *meters[MAX_METERS];
guint meter_gsource_timer;
int has_speaker_switching;
int has_talkback;
int has_fixed_mixer_inputs;
int routing_out_count[PC_COUNT];
int routing_in_count[PC_COUNT];
GMenu *routing_src_menu;
@@ -181,25 +216,34 @@ struct alsa_card {
double drag_x, drag_y;
};
// global array of cards
extern GArray *alsa_cards;
// utility
void fatal_alsa_error(const char *msg, int err);
// locate elements or get information about them
struct alsa_elem *get_elem_by_name(GArray *elems, char *name);
struct alsa_elem *get_elem_by_prefix(GArray *elems, char *prefix);
int get_max_elem_by_name(GArray *elems, char *prefix, char *needle);
int is_elem_routing_snk(struct alsa_elem *elem);
struct alsa_elem *get_elem_by_name(GArray *elems, const char *name);
struct alsa_elem *get_elem_by_prefix(GArray *elems, const char *prefix);
struct alsa_elem *get_elem_by_substr(GArray *elems, const char *substr);
int get_max_elem_by_name(
GArray *elems,
const char *prefix,
const char *needle
);
// add callback to alsa_elem callback list
void alsa_elem_add_callback(
struct alsa_elem *elem,
AlsaElemCallback *callback,
void *data
);
// alsa snd_ctl_elem_*() functions
int alsa_get_elem_type(struct alsa_elem *elem);
char *alsa_get_elem_name(struct alsa_elem *elem);
long alsa_get_elem_value(struct alsa_elem *elem);
int *alsa_get_elem_int_values(struct alsa_elem *elem);
long *alsa_get_elem_int_values(struct alsa_elem *elem);
void alsa_set_elem_value(struct alsa_elem *elem, long value);
int alsa_get_elem_writable(struct alsa_elem *elem);
int alsa_get_elem_volatile(struct alsa_elem *elem);
int alsa_get_elem_count(struct alsa_elem *elem);
int alsa_get_item_count(struct alsa_elem *elem);
char *alsa_get_item_name(struct alsa_elem *elem, int i);
@@ -207,6 +251,19 @@ char *alsa_get_item_name(struct alsa_elem *elem, int i);
// add to alsa_cards array
struct alsa_card *card_create(int card_num);
// scan/rescan for cards
void alsa_scan_cards(void);
void alsa_inotify_init(void);
// parse elements (used by alsa-sim.c)
void alsa_set_lr_nums(struct alsa_card *card);
void alsa_get_routing_controls(struct alsa_card *card);
// init
void alsa_init(void);
// register re-open callback
typedef void (ReOpenCallback)(void *);
void alsa_register_reopen_callback(
const char *serial,
ReOpenCallback *callback,
void *data
);
void alsa_unregister_reopen_callback(const char *serial);
int alsa_has_reopen_callbacks(void);

View File

@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2022 Geoffrey D. Bennett <g@b4.vu>
// SPDX-FileCopyrightText: 2022-2025 Geoffrey D. Bennett <g@b4.vu>
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
@@ -7,7 +7,7 @@
#define MAX_MIX_OUT 12
// maximum number of mux inputs
#define MAX_MUX_IN 25
#define MAX_MUX_IN 42
// maximum number of meters
#define MAX_METERS 65
#define MAX_METERS 92

83
src/db.c Normal file
View File

@@ -0,0 +1,83 @@
// SPDX-FileCopyrightText: 2024-2025 Geoffrey D. Bennett <g@b4.vu>
// SPDX-License-Identifier: GPL-3.0-or-later
#include <alsa/asoundlib.h>
#include <math.h>
static double db_to_linear(double db) {
if (db <= SND_CTL_TLV_DB_GAIN_MUTE)
return 0.0;
return pow(10.0, db / 20.0);
}
static double linear_to_db(double linear) {
if (linear <= 0.0)
return SND_CTL_TLV_DB_GAIN_MUTE;
return 20.0 * log10(linear);
}
int cdb_to_linear_value(
int cdb, int min_val, int max_val, int min_cdb, int max_cdb
) {
if (cdb <= min_cdb)
return min_val;
if (cdb >= max_cdb)
return max_val;
// Convert centidB to dB
double db = (double)cdb / 100.0;
double max_db = (double)max_cdb / 100.0;
// Convert dB relative to max_db to linear scale 0.0-1.0
double linear = db_to_linear(db - max_db);
// Scale to full ALSA range
double scaled = linear * (double)max_val;
int value = (int)round(scaled);
if (value < min_val)
return min_val;
if (value > max_val)
return max_val;
return value;
}
int linear_value_to_cdb(
int value, int min_val, int max_val, int min_cdb, int max_cdb
) {
if (value <= min_val)
return min_cdb;
if (value >= max_val)
return max_cdb;
// Convert to 0.0-1.0 linear scale
double linear = (double)value / (double)max_val;
double max_db = (double)max_cdb / 100.0;
// Convert to dB relative to max_db and back to centidB
int cdb = (int)round((linear_to_db(linear) + max_db) * 100.0);
if (cdb < min_cdb)
return min_cdb;
if (cdb > max_cdb)
return max_cdb;
return cdb;
}
double linear_value_to_db(
int value, int min_val, int max_val, int min_db, int max_db
) {
if (value <= min_val)
return min_db;
if (value >= max_val)
return max_db;
// Convert to 0.0-1.0 linear scale
double linear = (double)value / (double)max_val;
// Convert to dB relative to max_db
double db = linear_to_db(linear) + max_db;
if (db < min_db)
return min_db;
if (db > max_db)
return max_db;
return db;
}

16
src/db.h Normal file
View File

@@ -0,0 +1,16 @@
// SPDX-FileCopyrightText: 2024-2025 Geoffrey D. Bennett <g@b4.vu>
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
int cdb_to_linear_value(
int cdb, int min_val, int max_val, int min_cdb, int max_cdb
);
int linear_value_to_cdb(
int value, int min_val, int max_val, int min_cdb, int max_cdb
);
double linear_value_to_db(
int value, int min_val, int max_val, int min_db, int max_db
);

87
src/device-reset-config.c Normal file
View File

@@ -0,0 +1,87 @@
// SPDX-FileCopyrightText: 2024-2025 Geoffrey D. Bennett <g@b4.vu>
// SPDX-License-Identifier: GPL-3.0-or-later
#include <gtk/gtk.h>
#include "device-reset-config.h"
#include "scarlett2.h"
#include "scarlett2-ioctls.h"
#include "window-modal.h"
static gpointer update_progress(
struct modal_data *modal_data,
char *text,
int progress
) {
struct progress_data *progress_data = g_new0(struct progress_data, 1);
progress_data->modal_data = modal_data;
progress_data->text = text;
progress_data->progress = progress;
g_main_context_invoke(NULL, modal_update_progress, progress_data);
return NULL;
}
#define fail(msg) { \
if (hwdep) \
scarlett2_close(hwdep); \
return update_progress(modal_data, msg, -1); \
}
#define failsndmsg(msg) g_strdup_printf(msg, snd_strerror(err))
gpointer reset_config_thread(gpointer user_data) {
struct modal_data *modal_data = user_data;
update_progress(modal_data, g_strdup("Resetting configuration..."), 0);
snd_hwdep_t *hwdep;
int err = scarlett2_open_card(modal_data->card->device, &hwdep);
if (err < 0)
fail(failsndmsg("Unable to open hwdep interface: %s"));
err = scarlett2_erase_config(hwdep);
if (err < 0)
fail(failsndmsg("Unable to reset configuration: %s"));
while (1) {
g_usleep(50000);
err = scarlett2_get_erase_progress(hwdep);
if (err < 0)
fail(failsndmsg("Unable to get erase progress: %s"));
if (err == 255)
break;
update_progress(modal_data, NULL, err);
}
g_main_context_invoke(NULL, modal_start_reboot_progress, modal_data);
scarlett2_reboot(hwdep);
scarlett2_close(hwdep);
return NULL;
}
static void join_thread(gpointer thread) {
g_thread_join(thread);
}
static void reset_config_yes_callback(struct modal_data *modal_data) {
GThread *thread = g_thread_new(
"reset_config_thread", reset_config_thread, modal_data
);
g_object_set_data_full(
G_OBJECT(modal_data->button_box), "thread", thread, join_thread
);
}
void create_reset_config_window(GtkWidget *w, struct alsa_card *card) {
create_modal_window(
w, card,
"Confirm Reset Configuration",
"Resetting Configuration",
"Are you sure you want to reset the configuration?",
reset_config_yes_callback
);
}

View File

@@ -0,0 +1,9 @@
// SPDX-FileCopyrightText: 2024-2025 Geoffrey D. Bennett <g@b4.vu>
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
#include <gtk/gtk.h>
#include "alsa.h"
void create_reset_config_window(GtkWidget *w, struct alsa_card *card);

View File

@@ -0,0 +1,140 @@
// SPDX-FileCopyrightText: 2024-2025 Geoffrey D. Bennett <g@b4.vu>
// SPDX-License-Identifier: GPL-3.0-or-later
#include <gtk/gtk.h>
#include "device-reset-config.h"
#include "scarlett2.h"
#include "scarlett2-firmware.h"
#include "scarlett2-ioctls.h"
#include "window-modal.h"
static gpointer update_progress(
struct modal_data *modal_data,
char *text,
int progress
) {
struct progress_data *progress_data = g_new0(struct progress_data, 1);
progress_data->modal_data = modal_data;
progress_data->text = text;
progress_data->progress = progress;
g_main_context_invoke(NULL, modal_update_progress, progress_data);
return NULL;
}
#define fail(msg) { \
if (hwdep) \
scarlett2_close(hwdep); \
if (firmware) \
scarlett2_free_firmware_file(firmware); \
return update_progress(modal_data, msg, -1); \
}
#define failsndmsg(msg) g_strdup_printf(msg, snd_strerror(err))
gpointer update_firmware_thread(gpointer user_data) {
struct modal_data *modal_data = user_data;
struct alsa_card *card = modal_data->card;
int err = 0;
snd_hwdep_t *hwdep = NULL;
// read the firmware file
update_progress(modal_data, g_strdup("Checking firmware..."), 0);
struct scarlett2_firmware_file *firmware =
scarlett2_get_best_firmware(card->pid);
// if no firmware, fail
if (!firmware)
fail(failsndmsg("No update firmware found for device: %s"));
if (firmware->header.usb_pid != card->pid)
fail(g_strdup("Firmware file does not match device"));
update_progress(modal_data, g_strdup("Resetting configuration..."), 0);
err = scarlett2_open_card(card->device, &hwdep);
if (err < 0)
fail(failsndmsg("Unable to open hwdep interface: %s"));
err = scarlett2_erase_config(hwdep);
if (err < 0)
fail(failsndmsg("Unable to reset configuration: %s"));
while (1) {
g_usleep(50000);
err = scarlett2_get_erase_progress(hwdep);
if (err < 0)
fail(failsndmsg("Unable to get erase progress: %s"));
if (err == 255)
break;
update_progress(modal_data, NULL, err);
}
update_progress(modal_data, g_strdup("Erasing flash..."), 0);
err = scarlett2_erase_firmware(hwdep);
if (err < 0)
fail(failsndmsg("Unable to erase upgrade firmware: %s"));
while (1) {
g_usleep(50000);
err = scarlett2_get_erase_progress(hwdep);
if (err < 0)
fail(failsndmsg("Unable to get erase progress: %s"));
if (err == 255)
break;
update_progress(modal_data, NULL, err);
}
update_progress(modal_data, g_strdup("Writing firmware..."), 0);
size_t offset = 0;
size_t len = firmware->header.firmware_length;
unsigned char *buf = firmware->firmware_data;
while (offset < len) {
err = snd_hwdep_write(hwdep, buf + offset, len - offset);
if (err < 0)
fail(failsndmsg("Unable to write firmware: %s"));
offset += err;
update_progress(modal_data, NULL, (offset * 100) / len);
}
g_main_context_invoke(NULL, modal_start_reboot_progress, modal_data);
scarlett2_reboot(hwdep);
scarlett2_close(hwdep);
return NULL;
}
static void join_thread(gpointer thread) {
g_thread_join(thread);
}
static void update_firmware_yes_callback(struct modal_data *modal_data) {
GThread *thread = g_thread_new(
"update_firmware_thread", update_firmware_thread, modal_data
);
g_object_set_data_full(
G_OBJECT(modal_data->button_box), "thread", thread, join_thread
);
}
void create_update_firmware_window(GtkWidget *w, struct alsa_card *card) {
create_modal_window(
w, card,
"Confirm Update Firmware",
"Updating Firmware",
"The firmware update process will take about 15 seconds.\n"
"Please do not disconnect the device while updating.\n"
"Ready to proceed?",
update_firmware_yes_callback
);
}

View File

@@ -0,0 +1,9 @@
// SPDX-FileCopyrightText: 2024-2025 Geoffrey D. Bennett <g@b4.vu>
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
#include <gtk/gtk.h>
#include "alsa.h"
void create_update_firmware_window(GtkWidget *w, struct alsa_card *card);

View File

@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2022 Geoffrey D. Bennett <g@b4.vu>
// SPDX-FileCopyrightText: 2022-2025 Geoffrey D. Bennett <g@b4.vu>
// SPDX-License-Identifier: GPL-3.0-or-later
#include "error.h"

View File

@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2022 Geoffrey D. Bennett <g@b4.vu>
// SPDX-FileCopyrightText: 2022-2025 Geoffrey D. Bennett <g@b4.vu>
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once

19
src/fcp-shared.c Normal file
View File

@@ -0,0 +1,19 @@
// SPDX-FileCopyrightText: 2024 Geoffrey D. Bennett <g@b4.vu>
// SPDX-License-Identifier: GPL-3.0-or-later
// Error messages
const char *fcp_socket_error_messages[] = {
"Success",
"Invalid magic",
"Invalid command",
"Invalid length",
"Invalid hash",
"Firmware PID does not match USB PID",
"Configuration error (check fcp-server log)",
"FCP communication error",
"Timeout",
"Read error",
"Write error",
"Not running leapfrog firmware",
"Invalid state"
};

80
src/fcp-shared.h Normal file
View File

@@ -0,0 +1,80 @@
// SPDX-FileCopyrightText: 2024 Geoffrey D. Bennett <g@b4.vu>
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
#include <stdint.h>
// Error codes
#define FCP_SOCKET_ERR_INVALID_MAGIC 1
#define FCP_SOCKET_ERR_INVALID_COMMAND 2
#define FCP_SOCKET_ERR_INVALID_LENGTH 3
#define FCP_SOCKET_ERR_INVALID_HASH 4
#define FCP_SOCKET_ERR_INVALID_USB_ID 5
#define FCP_SOCKET_ERR_CONFIG 6
#define FCP_SOCKET_ERR_FCP 7
#define FCP_SOCKET_ERR_TIMEOUT 8
#define FCP_SOCKET_ERR_READ 9
#define FCP_SOCKET_ERR_WRITE 10
#define FCP_SOCKET_ERR_NOT_LEAPFROG 11
#define FCP_SOCKET_ERR_INVALID_STATE 12
#define FCP_SOCKET_ERR_MAX 12
// Protocol constants
#define FCP_SOCKET_PROTOCOL_VERSION 1
#define FCP_SOCKET_MAGIC_REQUEST 0x53
#define FCP_SOCKET_MAGIC_RESPONSE 0x73
// Maximum payload length (2MB)
#define MAX_PAYLOAD_LENGTH 2 * 1024 * 1024
// Request types
#define FCP_SOCKET_REQUEST_REBOOT 0x0001
#define FCP_SOCKET_REQUEST_CONFIG_ERASE 0x0002
#define FCP_SOCKET_REQUEST_APP_FIRMWARE_ERASE 0x0003
#define FCP_SOCKET_REQUEST_APP_FIRMWARE_UPDATE 0x0004
#define FCP_SOCKET_REQUEST_ESP_FIRMWARE_UPDATE 0x0005
// Response types
#define FCP_SOCKET_RESPONSE_VERSION 0x00
#define FCP_SOCKET_RESPONSE_SUCCESS 0x01
#define FCP_SOCKET_RESPONSE_ERROR 0x02
#define FCP_SOCKET_RESPONSE_PROGRESS 0x03
extern const char *fcp_socket_error_messages[];
// Message structures
#pragma pack(push, 1)
struct fcp_socket_msg_header {
uint8_t magic;
uint8_t msg_type;
uint32_t payload_length;
};
struct firmware_payload {
uint32_t size;
uint16_t usb_vid;
uint16_t usb_pid;
uint8_t sha256[32];
uint8_t md5[16];
uint8_t data[];
};
struct version_msg {
struct fcp_socket_msg_header header;
uint8_t version;
};
struct progress_msg {
struct fcp_socket_msg_header header;
uint8_t percent;
};
struct error_msg {
struct fcp_socket_msg_header header;
int16_t error_code;
};
#pragma pack(pop)

220
src/fcp-socket.c Normal file
View File

@@ -0,0 +1,220 @@
// SPDX-FileCopyrightText: 2024 Geoffrey D. Bennett <g@b4.vu>
// SPDX-License-Identifier: GPL-3.0-or-later
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/time.h>
#include <fcntl.h>
#include "fcp-shared.h"
#include "fcp-socket.h"
#include "error.h"
// Connect to the FCP socket server for the given card
int fcp_socket_connect(struct alsa_card *card) {
if (!card || !card->fcp_socket) {
fprintf(stderr, "FCP socket path is not available");
return -1;
}
int sock_fd = socket(AF_UNIX, SOCK_STREAM, 0);
if (sock_fd < 0) {
fprintf(stderr, "Cannot create socket: %s", strerror(errno));
return -1;
}
struct sockaddr_un addr = {
.sun_family = AF_UNIX
};
strncpy(addr.sun_path, card->fcp_socket, sizeof(addr.sun_path) - 1);
if (connect(sock_fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
fprintf(stderr, "Cannot connect to server at %s: %s",
addr.sun_path, strerror(errno));
close(sock_fd);
return -1;
}
return sock_fd;
}
// Send a simple command with no payload to the server
int fcp_socket_send_command(int sock_fd, uint8_t command) {
struct fcp_socket_msg_header header = {
.magic = FCP_SOCKET_MAGIC_REQUEST,
.msg_type = command,
.payload_length = 0
};
if (write(sock_fd, &header, sizeof(header)) != sizeof(header)) {
fprintf(stderr, "Error sending command: %s", strerror(errno));
return -1;
}
return 0;
}
// Handle server responses from a command
int fcp_socket_handle_response(int sock_fd, bool show_progress) {
struct fcp_socket_msg_header header;
ssize_t bytes_read;
// Read response header
bytes_read = read(sock_fd, &header, sizeof(header));
if (bytes_read != sizeof(header)) {
if (bytes_read == 0) {
// Server closed the connection
return 0;
}
fprintf(stderr, "Error reading response header: %s", strerror(errno));
return -1;
}
// Verify the magic value
if (header.magic != FCP_SOCKET_MAGIC_RESPONSE) {
fprintf(stderr, "Invalid response magic: 0x%02x", header.magic);
return -1;
}
// Handle different response types
switch (header.msg_type) {
case FCP_SOCKET_RESPONSE_VERSION: {
// Protocol version response
uint8_t version;
bytes_read = read(sock_fd, &version, sizeof(version));
if (bytes_read != sizeof(version)) {
fprintf(stderr, "Error reading version: %s", strerror(errno));
return -1;
}
// Protocol version mismatch?
if (version != FCP_SOCKET_PROTOCOL_VERSION) {
fprintf(stderr, "Protocol version mismatch: expected %d, got %d",
FCP_SOCKET_PROTOCOL_VERSION, version);
return -1;
}
break;
}
case FCP_SOCKET_RESPONSE_SUCCESS:
// Command completed successfully
return 0;
case FCP_SOCKET_RESPONSE_ERROR: {
// Error response
int16_t error_code;
bytes_read = read(sock_fd, &error_code, sizeof(error_code));
if (bytes_read != sizeof(error_code)) {
fprintf(stderr, "Error reading error code: %s", strerror(errno));
return -1;
}
if (error_code > 0 && error_code <= FCP_SOCKET_ERR_MAX) {
fprintf(stderr, "Server error: %s", fcp_socket_error_messages[error_code]);
} else {
fprintf(stderr, "Unknown server error code: %d", error_code);
}
return -1;
}
case FCP_SOCKET_RESPONSE_PROGRESS: {
// Progress update
if (show_progress) {
uint8_t percent;
bytes_read = read(sock_fd, &percent, sizeof(percent));
if (bytes_read != sizeof(percent)) {
fprintf(stderr, "Error reading progress: %s", strerror(errno));
return -1;
}
fprintf(stderr, "\rProgress: %d%%", percent);
if (percent == 100)
fprintf(stderr, "\n");
} else {
// Skip the progress byte
uint8_t dummy;
if (read(sock_fd, &dummy, sizeof(dummy)) < 0) {
fprintf(stderr, "Error reading progress: %s", strerror(errno));
return -1;
}
}
// Continue reading responses
return fcp_socket_handle_response(sock_fd, show_progress);
}
default:
fprintf(stderr, "Unknown response type: 0x%02x", header.msg_type);
return -1;
}
return 0;
}
// Wait for server to disconnect (used after reboot command)
int fcp_socket_wait_for_disconnect(int sock_fd) {
fd_set rfds;
struct timeval tv, start_time, now;
char buf[1];
const int TIMEOUT_SECS = 2;
gettimeofday(&start_time, NULL);
while (1) {
FD_ZERO(&rfds);
FD_SET(sock_fd, &rfds);
gettimeofday(&now, NULL);
int elapsed = now.tv_sec - start_time.tv_sec;
if (elapsed >= TIMEOUT_SECS) {
fprintf(stderr, "Timeout waiting for server disconnect\n");
return -1;
}
tv.tv_sec = TIMEOUT_SECS - elapsed;
tv.tv_usec = 0;
int ret = select(sock_fd + 1, &rfds, NULL, NULL, &tv);
if (ret < 0) {
if (errno == EINTR)
continue;
fprintf(stderr, "Select error: %s\n", strerror(errno));
return -1;
}
if (ret > 0) {
// Try to read one byte
ssize_t n = read(sock_fd, buf, 1);
if (n < 0) {
if (errno == EINTR || errno == EAGAIN)
continue;
fprintf(stderr, "Read error: %s\n", strerror(errno));
return -1;
}
if (n == 0) {
// EOF received - server has disconnected
return 0;
}
// Ignore any data received, just keep waiting for EOF
}
}
}
// Reboot a device using the FCP socket interface
int fcp_socket_reboot_device(struct alsa_card *card) {
int sock_fd, ret = -1;
sock_fd = fcp_socket_connect(card);
if (sock_fd < 0)
return -1;
// Send reboot command and wait for server to disconnect
if (fcp_socket_send_command(sock_fd, FCP_SOCKET_REQUEST_REBOOT) == 0)
ret = fcp_socket_wait_for_disconnect(sock_fd);
close(sock_fd);
return ret;
}

27
src/fcp-socket.h Normal file
View File

@@ -0,0 +1,27 @@
// SPDX-FileCopyrightText: 2024 Geoffrey D. Bennett <g@b4.vu>
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
#include <stdbool.h>
#include "alsa.h"
// Connect to the FCP socket server for the given card
// Returns socket file descriptor on success, -1 on error
int fcp_socket_connect(struct alsa_card *card);
// Send a simple command with no payload to the server
// Returns 0 on success, -1 on error
int fcp_socket_send_command(int sock_fd, uint8_t command);
// Handle server responses from a command
// Returns 0 on success, -1 on error
int fcp_socket_handle_response(int sock_fd, bool show_progress);
// Wait for server to disconnect (used after reboot command)
// Returns 0 if disconnected, -1 on timeout or error
int fcp_socket_wait_for_disconnect(int sock_fd);
// Reboot a device using the FCP socket interface
// Returns 0 on success, -1 on error
int fcp_socket_reboot_device(struct alsa_card *card);

View File

@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2022 Geoffrey D. Bennett <g@b4.vu>
// SPDX-FileCopyrightText: 2022-2025 Geoffrey D. Bennett <g@b4.vu>
// SPDX-License-Identifier: GPL-3.0-or-later
#include "alsa.h"
@@ -14,9 +14,15 @@ static void run_alsactl(
) {
GtkWindow *w = GTK_WINDOW(card->window_main);
gchar *alsactl_path = g_find_program_in_path("alsactl");
if (!alsactl_path)
alsactl_path = g_strdup("/usr/sbin/alsactl");
gchar *argv[] = {
"/usr/sbin/alsactl", cmd, card->device, "-f", fn, NULL
alsactl_path, cmd, card->device, "-f", fn, NULL
};
gchar *stdout;
gchar *stderr;
gint exit_status;
@@ -52,6 +58,7 @@ static void run_alsactl(
g_free(error_message);
done:
g_free(alsactl_path);
g_free(stdout);
g_free(stderr);
if (error)

View File

@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2022 Geoffrey D. Bennett <g@b4.vu>
// SPDX-FileCopyrightText: 2022-2025 Geoffrey D. Bennett <g@b4.vu>
// SPDX-License-Identifier: GPL-3.0-or-later
#include <gtk/gtk.h>

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,5 @@
// SPDX-FileCopyrightText: 2021 Stiliyan Varbanov <https://www.fiverr.com/stilvar>
// SPDX-FileCopyrightText: 2022 Geoffrey D. Bennett <g@b4.vu>
// SPDX-FileCopyrightText: 2022-2025 Geoffrey D. Bennett <g@b4.vu>
// SPDX-License-Identifier: LGPL-3.0-or-later
/*
@@ -14,92 +14,100 @@
G_BEGIN_DECLS
#define GTK_TYPE_DIAL (gtk_dial_get_type ())
#define GTK_DIAL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_DIAL, GtkDial))
#define GTK_DIAL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_DIAL, GtkDialClass))
#define GTK_IS_DIAL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_DIAL))
#define GTK_IS_DIAL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_DIAL))
#define GTK_DIAL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_DIAL, GtkDialClass))
#define GTK_TYPE_DIAL (gtk_dial_get_type())
#define GTK_DIAL(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GTK_TYPE_DIAL, GtkDial))
#define GTK_DIAL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GTK_TYPE_DIAL, GtkDialClass))
#define GTK_IS_DIAL(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GTK_TYPE_DIAL))
#define GTK_IS_DIAL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GTK_TYPE_DIAL))
#define GTK_DIAL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GTK_TYPE_DIAL, GtkDialClass))
typedef struct _GtkDial GtkDial;
typedef struct _GtkDialClass GtkDialClass;
typedef struct _GtkDial GtkDial;
typedef struct _GtkDialClass GtkDialClass;
struct _GtkDialClass
{
struct _GtkDialClass {
GtkWidgetClass parent_class;
void (* value_changed) (GtkDial *dial);
void (*value_changed)(GtkDial *dial);
/* action signals for keybindings */
void (* move_slider) (GtkDial *dial,
GtkScrollType scroll);
void (*move_slider)(GtkDial *dial, GtkScrollType scroll);
gboolean (*change_value) (GtkDial *dial,
GtkScrollType scroll,
double new_value);
gboolean (*change_value)(
GtkDial *dial,
GtkScrollType scroll,
double new_value
);
};
typedef char * (*GtkDialFormatValueFunc) (GtkDial *dial,
double value,
gpointer user_data);
GType gtk_dial_get_type(void) G_GNUC_CONST;
GDK_AVAILABLE_IN_ALL
GType gtk_dial_get_type (void) G_GNUC_CONST;
GDK_AVAILABLE_IN_ALL
GtkWidget * gtk_dial_new (GtkAdjustment *adjustment);
GDK_AVAILABLE_IN_ALL
GtkWidget * gtk_dial_new_with_range (double min,
double max,
double step);
GDK_AVAILABLE_IN_ALL
void gtk_dial_set_has_origin (GtkDial *dial,
gboolean has_origin);
GDK_AVAILABLE_IN_ALL
gboolean gtk_dial_get_has_origin (GtkDial *dial);
GtkWidget *gtk_dial_new(GtkAdjustment *adjustment);
GDK_AVAILABLE_IN_ALL
void gtk_dial_set_adjustment (GtkDial *dial,
GtkAdjustment *adj);
GtkWidget *gtk_dial_new_with_range(
double min,
double max,
double step,
double page
);
GDK_AVAILABLE_IN_ALL
GtkAdjustment* gtk_dial_get_adjustment (GtkDial *dial);
void gtk_dial_set_has_origin(GtkDial *dial, gboolean has_origin);
gboolean gtk_dial_get_has_origin(GtkDial *dial);
GDK_AVAILABLE_IN_ALL
double gtk_dial_get_value (GtkDial *dial);
void gtk_dial_set_adjustment(GtkDial *dial, GtkAdjustment *adj);
GtkAdjustment *gtk_dial_get_adjustment(GtkDial *dial);
GDK_AVAILABLE_IN_ALL
void gtk_dial_set_value (GtkDial *dial,
double value);
GDK_AVAILABLE_IN_ALL
void gtk_dial_set_round_digits (GtkDial *dial,
int round_digits);
GDK_AVAILABLE_IN_ALL
int gtk_dial_get_round_digits (GtkDial *range);
GDK_AVAILABLE_IN_ALL
void gtk_dial_set_zero_db (GtkDial *dial,
double zero_db);
GDK_AVAILABLE_IN_ALL
double gtk_dial_get_zero_db (GtkDial *range);
double gtk_dial_get_value(GtkDial *dial);
void gtk_dial_set_value(GtkDial *dial, double value);
void gtk_dial_set_round_digits(GtkDial *dial, int round_digits);
int gtk_dial_get_round_digits(GtkDial *dial);
void gtk_dial_set_zero_db(GtkDial *dial, double zero_db);
double gtk_dial_get_zero_db(GtkDial *dial);
void gtk_dial_set_off_db(GtkDial *dial, double off_db);
double gtk_dial_get_off_db(GtkDial *dial);
void gtk_dial_set_is_linear(GtkDial *dial, gboolean is_linear);
gboolean gtk_dial_get_is_linear(GtkDial *dial);
// taper functions
enum {
GTK_DIAL_TAPER_LINEAR,
GTK_DIAL_TAPER_LOG
};
void gtk_dial_set_taper(GtkDial *dial, int taper);
int gtk_dial_get_taper(GtkDial *dial);
void gtk_dial_set_taper_linear_breakpoints(
GtkDial *dial,
const double *breakpoints,
const double *outputs,
int count
);
void gtk_dial_set_can_control(GtkDial *dial, gboolean can_control);
gboolean gtk_dial_get_can_control(GtkDial *dial);
void gtk_dial_set_level_meter_colours(
GtkDial *dial,
const int *breakpoints,
const double *colours,
int count
);
void gtk_dial_set_peak_hold(GtkDial *dial, int peak_hold);
int gtk_dial_get_peak_hold(GtkDial *dial);
void gtk_dial_peak_tick(void);
int cdb_to_linear_value(
int db, int min_val, int max_val, int min_db, int max_db
);
int linear_value_to_cdb(
int value, int min_val, int max_val, int min_db, int max_db
);
/**
* @brief Set the colors which this dial uses. String codes can be one of the following:
* A standard name (Taken from the X11 rgb.txt file)
* A hexadecimal value in the form “#rgb”, “#rrggbb”, “#rrrgggbbb” or ”#rrrrggggbbbb”
* A RGB color in the form “rgb(r,g,b)” (In this case the color will have full opacity)
* A RGBA color in the form “rgba(r,g,b,a)”
* NULL if the color is to remain unchanged
*
* @param dial: The dial
* @param trough_border: String code for trough border color
* @param trough_bg: String code for trough background color
* @param trough_fill: String code for trough fill color
* @return TRUE if all the colors were set successfully, FALSE otherwise
*/
gboolean gtk_dial_set_style(GtkDial *dial,
const char *trough_border,
const char *trough_bg,
const char *trough_fill,
const char *pointer);
G_END_DECLS
#endif

View File

@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2022 Geoffrey D. Bennett <g@b4.vu>
// SPDX-FileCopyrightText: 2022-2025 Geoffrey D. Bennett <g@b4.vu>
// SPDX-License-Identifier: GPL-3.0-or-later
#include "gtkhelper.h"
@@ -25,7 +25,15 @@ void gtk_grid_set_spacing(GtkGrid *grid, int spacing) {
gtk_grid_set_column_spacing(grid, spacing);
}
void gtk_widget_add_class(GtkWidget *w, const char *class) {
GtkStyleContext *style_context = gtk_widget_get_style_context(w);
gtk_style_context_add_class(style_context, class);
void gtk_widget_remove_css_classes_by_prefix(
GtkWidget *w,
const char *prefix
) {
char **classes = gtk_widget_get_css_classes(w);
for (char **i = classes; *i != NULL; i++)
if (strncmp(*i, prefix, strlen(prefix)) == 0)
gtk_widget_remove_css_class(w, *i);
g_strfreev(classes);
}

View File

@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2022 Geoffrey D. Bennett <g@b4.vu>
// SPDX-FileCopyrightText: 2022-2025 Geoffrey D. Bennett <g@b4.vu>
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
@@ -9,4 +9,4 @@ void gtk_widget_set_margin(GtkWidget *w, int margin);
void gtk_widget_set_expand(GtkWidget *w, gboolean expand);
void gtk_widget_set_align(GtkWidget *w, GtkAlign x, GtkAlign y);
void gtk_grid_set_spacing(GtkGrid *grid, int spacing);
void gtk_widget_add_class(GtkWidget *w, const char *class);
void gtk_widget_remove_css_classes_by_prefix(GtkWidget *w, const char *prefix);

38
src/hardware.c Normal file
View File

@@ -0,0 +1,38 @@
// SPDX-FileCopyrightText: 2023-2025 Geoffrey D. Bennett <g@b4.vu>
// SPDX-License-Identifier: GPL-3.0-or-later
#include <stddef.h>
#include "hardware.h"
struct scarlett2_device scarlett2_supported[] = {
{ 0x8203, "Scarlett 2nd Gen 6i6" },
{ 0x8204, "Scarlett 2nd Gen 18i8" },
{ 0x8201, "Scarlett 2nd Gen 18i20" },
{ 0x8211, "Scarlett 3rd Gen Solo" },
{ 0x8210, "Scarlett 3rd Gen 2i2" },
{ 0x8212, "Scarlett 3rd Gen 4i4" },
{ 0x8213, "Scarlett 3rd Gen 8i6" },
{ 0x8214, "Scarlett 3rd Gen 18i8" },
{ 0x8215, "Scarlett 3rd Gen 18i20" },
{ 0x8216, "Vocaster One" },
{ 0x8217, "Vocaster Two" },
{ 0x8218, "Scarlett 4th Gen Solo" },
{ 0x8219, "Scarlett 4th Gen 2i2" },
{ 0x821a, "Scarlett 4th Gen 4i4" },
{ 0x8206, "Clarett USB 2Pre" },
{ 0x8207, "Clarett USB 4Pre" },
{ 0x8208, "Clarett USB 8Pre" },
{ 0x820a, "Clarett+ 2Pre" },
{ 0x820b, "Clarett+ 4Pre" },
{ 0x820c, "Clarett+ 8Pre" },
{ 0, NULL }
};
struct scarlett2_device *get_device_for_pid(int pid) {
for (int i = 0; scarlett2_supported[i].name; i++)
if (scarlett2_supported[i].pid == pid)
return &scarlett2_supported[i];
return NULL;
}

10
src/hardware.h Normal file
View File

@@ -0,0 +1,10 @@
// SPDX-FileCopyrightText: 2023-2025 Geoffrey D. Bennett <g@b4.vu>
// SPDX-License-Identifier: GPL-3.0-or-later
// Supported devices
struct scarlett2_device {
int pid;
const char *name;
};
struct scarlett2_device *get_device_for_pid(int pid);

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2022 Geoffrey D. Bennett <g@b4.vu>
// SPDX-FileCopyrightText: 2022-2025 Geoffrey D. Bennett <g@b4.vu>
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once

View File

@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2022 Geoffrey D. Bennett <g@b4.vu>
// SPDX-FileCopyrightText: 2022-2025 Geoffrey D. Bennett <g@b4.vu>
// SPDX-License-Identifier: GPL-3.0-or-later
#include "gtkhelper.h"
@@ -6,38 +6,49 @@
#include "stringhelper.h"
#include "tooltips.h"
#include "widget-boolean.h"
#include "widget-combo.h"
#include "widget-drop-down.h"
#include "window-helper.h"
#include "window-startup.h"
GtkWidget *create_iface_no_mixer_main(struct alsa_card *card) {
GArray *elems = card->elems;
GtkWidget *grid = gtk_grid_new();
GtkWidget *top = gtk_frame_new(NULL);
gtk_widget_add_css_class(top, "window-frame");
GtkWidget *content = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 15);
gtk_widget_add_css_class(content, "window-content");
gtk_widget_add_css_class(content, "iface-no-mixer");
gtk_frame_set_child(GTK_FRAME(top), content);
GtkWidget *input_box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 5);
GtkWidget *output_box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 5);
gtk_box_append(GTK_BOX(content), input_box);
gtk_box_append(GTK_BOX(content), output_box);
GtkWidget *label_ic = gtk_label_new("Input Controls");
GtkWidget *vert_sep = gtk_separator_new(GTK_ORIENTATION_VERTICAL);
GtkWidget *label_oc = gtk_label_new("Output Controls");
gtk_widget_set_margin(grid, 10);
gtk_grid_set_spacing(GTK_GRID(grid), 10);
gtk_widget_add_css_class(label_ic, "controls-label");
gtk_widget_add_css_class(label_oc, "controls-label");
gtk_grid_attach(GTK_GRID(grid), label_ic, 0, 0, 1, 1);
gtk_grid_attach(GTK_GRID(grid), vert_sep, 1, 0, 1, 3);
gtk_grid_attach(GTK_GRID(grid), label_oc, 2, 0, 1, 1);
gtk_widget_set_halign(label_ic, GTK_ALIGN_START);
gtk_widget_set_halign(label_oc, GTK_ALIGN_START);
GtkWidget *horiz_input_sep = gtk_separator_new(GTK_ORIENTATION_HORIZONTAL);
gtk_grid_attach(GTK_GRID(grid), horiz_input_sep, 0, 1, 1, 1);
gtk_box_append(GTK_BOX(input_box), label_ic);
gtk_box_append(GTK_BOX(output_box), label_oc);
GtkWidget *input_grid = gtk_grid_new();
gtk_grid_set_spacing(GTK_GRID(input_grid), 10);
gtk_grid_attach(GTK_GRID(grid), input_grid, 0, 2, 1, 1);
GtkWidget *horiz_output_sep = gtk_separator_new(GTK_ORIENTATION_VERTICAL);
gtk_grid_attach(GTK_GRID(grid), horiz_output_sep, 2, 1, 1, 1);
gtk_widget_add_css_class(input_grid, "controls-content");
gtk_widget_set_vexpand(input_grid, TRUE);
gtk_box_append(GTK_BOX(input_box), input_grid);
GtkWidget *output_grid = gtk_grid_new();
gtk_grid_set_spacing(GTK_GRID(output_grid), 10);
gtk_grid_attach(GTK_GRID(grid), output_grid, 2, 2, 1, 1);
gtk_widget_add_css_class(output_grid, "controls-content");
gtk_widget_set_vexpand(output_grid, TRUE);
gtk_box_append(GTK_BOX(output_box), output_grid);
// Solo or 2i2?
// Solo Phantom Power is Line 1 only
@@ -48,7 +59,7 @@ GtkWidget *create_iface_no_mixer_main(struct alsa_card *card) {
for (int i = 0; i < 2; i++) {
char s[20];
snprintf(s, 20, "Analogue %d", i + 1);
snprintf(s, 20, "%d", i + 1);
GtkWidget *label = gtk_label_new(s);
gtk_grid_attach(GTK_GRID(input_grid), label, i, 0, 1, 1);
}
@@ -67,23 +78,25 @@ GtkWidget *create_iface_no_mixer_main(struct alsa_card *card) {
int line_num = get_num_from_string(elem->name);
if (strstr(elem->name, "Level Capture Enum")) {
w = make_boolean_alsa_elem(elem, "Line", "Inst");
w = make_boolean_alsa_elem(elem, "Inst", NULL);
gtk_widget_add_css_class(w, "inst");
gtk_widget_set_tooltip_text(w, level_descr);
gtk_grid_attach(GTK_GRID(input_grid), w, line_num - 1, 1, 1, 1);
} else if (strstr(elem->name, "Air Capture Switch")) {
w = make_boolean_alsa_elem(elem, "Air Off", "Air On");
w = make_boolean_alsa_elem(elem, "Air", NULL);
gtk_widget_add_css_class(w, "air");
gtk_widget_set_tooltip_text(w, air_descr);
gtk_grid_attach(
GTK_GRID(input_grid), w, line_num - 1, 1 + !is_solo, 1, 1
);
} else if (strstr(elem->name, "Phantom Power Capture Switch")) {
w = make_boolean_alsa_elem(elem, "48V Off", "48V On");
w = make_boolean_alsa_elem(elem, "48V", NULL);
gtk_widget_add_css_class(w, "phantom");
gtk_widget_set_tooltip_text(w, phantom_descr);
gtk_grid_attach(GTK_GRID(input_grid), w, 0, 3, 1 + !is_solo, 1);
} else if (strcmp(elem->name, "Direct Monitor Playback Switch") == 0) {
w = make_boolean_alsa_elem(
elem, "Direct Monitor Off", "Direct Monitor On"
);
w = make_boolean_alsa_elem(elem, "Direct Monitor", NULL);
gtk_widget_add_css_class(w, "direct-monitor");
gtk_widget_set_tooltip_text(
w,
"Direct Monitor sends the analogue input signals to the "
@@ -91,9 +104,8 @@ GtkWidget *create_iface_no_mixer_main(struct alsa_card *card) {
);
gtk_grid_attach(GTK_GRID(output_grid), w, 0, 0, 1, 1);
} else if (strcmp(elem->name, "Direct Monitor Playback Enum") == 0) {
GtkWidget *l = gtk_label_new("Direct Monitor");
gtk_grid_attach(GTK_GRID(output_grid), l, 0, 0, 1, 1);
w = make_combo_box_alsa_elem(elem);
w = make_drop_down_alsa_elem(elem, "Direct Monitor");
gtk_widget_add_css_class(w, "direct-monitor");
gtk_widget_set_tooltip_text(
w,
"Direct Monitor sends the analogue input signals to the "
@@ -101,7 +113,7 @@ GtkWidget *create_iface_no_mixer_main(struct alsa_card *card) {
"both inputs to the left and right outputs. Stereo sends "
"input 1 to the left, and input 2 to the right output."
);
gtk_grid_attach(GTK_GRID(output_grid), w, 0, 1, 1, 1);
gtk_grid_attach(GTK_GRID(output_grid), w, 0, 0, 1, 1);
}
}
@@ -112,5 +124,5 @@ GtkWidget *create_iface_no_mixer_main(struct alsa_card *card) {
GtkWidget *startup = create_startup_controls(card);
gtk_window_set_child(GTK_WINDOW(card->window_startup), startup);
return grid;
return top;
}

Some files were not shown because too many files have changed in this diff Show More