Compare commits
41 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 921944e64e | |||
| 9e00217cec | |||
| 04ad890f16 | |||
| a89558d5a7 | |||
| 5b8bdaca4b | |||
| d8b08b46fc | |||
| b33d2ace99 | |||
| 5ddb8b020b | |||
| 3831f4e0c0 | |||
| d8ff8876b4 | |||
| 036b9d1a94 | |||
| 8401d9eada | |||
| be28bf0dc8 | |||
| 0857a02c77 | |||
| e50d13b992 | |||
| 41f1593443 | |||
| 46652862d3 | |||
| 5bd8a5de42 | |||
| 646a62afdb | |||
| 169feb563f | |||
| fb99a3783f | |||
| a3d77ee98a | |||
|
|
e6fbb4f146 | ||
|
|
e4dc805422 | ||
|
|
87ee0ed66b | ||
|
|
adeea461fd | ||
|
|
1f7bafbfc3 | ||
|
|
b8420ba31c | ||
|
|
a5676eeb5a | ||
|
|
9a33b92392 | ||
|
|
97f993db7b | ||
|
|
6f0ab1890d | ||
|
|
c88f7796f4 | ||
|
|
0b5b47ae66 | ||
|
|
b6117a501f | ||
|
|
a34df84dfa | ||
|
|
6677e5c87d | ||
|
|
91fc3bbb03 | ||
|
|
460b03c668 | ||
|
|
8a2e5f5835 | ||
| 05ae063b90 |
62
FAQ.md
62
FAQ.md
@@ -24,7 +24,7 @@ deactivate MSD mode by holding down the 48V button while powering it
|
||||
on).
|
||||
|
||||
However, to access the mixer, routing, and hardware-specific features,
|
||||
you'll need the appropriate driver for your interface model.
|
||||
you’ll need the appropriate driver for your interface model.
|
||||
|
||||
## MSD Mode?
|
||||
|
||||
@@ -34,7 +34,7 @@ you'll need the appropriate driver for your interface model.
|
||||
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, there'll be a tiny read-only virtual
|
||||
When you plug the interface in, there’ll 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.
|
||||
@@ -46,7 +46,7 @@ powering on the interface, or by clicking the button in
|
||||
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 they're not needed for basic audio?
|
||||
## What is the purpose of these drivers if they’re not needed for basic audio?
|
||||
|
||||
These drivers are for users who want more control over their
|
||||
interface. They allow for detailed manipulation of:
|
||||
@@ -72,13 +72,13 @@ The ALSA Scarlett Control Panel supports:
|
||||
- **Vocaster**: One, Two
|
||||
|
||||
Note: The Scarlett 1st and 2nd Gen small interfaces (Solo, 2i2, 2i4)
|
||||
don't have any software controls. All the controls are available from
|
||||
the front panel, so they don't require the specialised drivers or this
|
||||
don’t have any software controls. All the controls are available from
|
||||
the front panel, so they don’t require the specialised drivers or this
|
||||
GUI.
|
||||
|
||||
## Where are the options to set the sample rate and buffer size?
|
||||
|
||||
The ALSA Scarlett Control Panel doesn't handle audio input/output
|
||||
The ALSA Scarlett Control Panel doesn’t 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.
|
||||
@@ -90,8 +90,58 @@ displays the current rate being used by applications. If it shows
|
||||
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 interface’s 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? It’s 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
|
||||
|
||||
|
||||
95
README.md
95
README.md
@@ -1,95 +1,8 @@
|
||||
# ALSA Scarlett Control Panel (`alsa-scarlett-gui`)
|
||||
|
||||
`alsa-scarlett-gui` is a Gtk4 GUI for the ALSA controls presented by
|
||||
the three Linux kernel Focusrite USB drivers:
|
||||
- Upstream project here: https://github.com/geoffreybennett/alsa-scarlett-gui
|
||||
- Debian's packaged version here: https://salsa.debian.org/doge-tech/alsa-scarlett-gui
|
||||
|
||||
- Scarlett 1st Gen Driver for ALSA
|
||||
- Scarlett2 USB Protocol Mixer Driver
|
||||
- FCP (Focusrite Control Protocol) Driver
|
||||
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.
|
||||
|
||||
Supported interfaces:
|
||||
- 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 2Pre, 4Pre, 8Pre USB
|
||||
- Clarett+ 2Pre, 4Pre, 8Pre
|
||||
- Vocaster One and Vocaster Two
|
||||
|
||||
## About
|
||||
|
||||
<img src="img/alsa-scarlett-gui.png" align="right">
|
||||
|
||||
All 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/Vocaster 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.
|
||||
|
||||
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 Control Panel, now supporting all
|
||||
Scarlett Gen 1, 2, 3, 4, Clarett, and Vocaster USB interfaces!
|
||||
|
||||

|
||||
|
||||
## Documentation
|
||||
|
||||
Refer to [INSTALL.md](docs/INSTALL.md) for prerequisites, how to
|
||||
build, install, and run.
|
||||
|
||||
Refer to [USAGE.md](docs/USAGE.md) for general usage information and
|
||||
known issues.
|
||||
|
||||
Information specific to various models:
|
||||
|
||||
- [Scarlett 1st Gen](docs/iface-1st-gen.md)
|
||||
|
||||
- [Scarlett 3rd Gen Solo and 2i2](docs/iface-small.md)
|
||||
|
||||
- [Scarlett 2nd Gen 6i6+, 3rd Gen 4i4+, Clarett USB, and
|
||||
Clarett+](docs/iface-large.md)
|
||||
|
||||
- [Scarlett Small 4th Gen](docs/iface-4th-gen-small.md)
|
||||
|
||||
- [Scarlett Big 4th Gen](docs/iface-4th-gen-big.md)
|
||||
|
||||
## 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! Any donation is appreciated.
|
||||
|
||||
- https://liberapay.com/gdb
|
||||
- https://paypal.me/gdbau
|
||||
|
||||
## License
|
||||
|
||||
Copyright 2022-2025 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.
|
||||
|
||||
@@ -1,35 +1,29 @@
|
||||
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
|
||||
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 USB drivers.
|
||||
|
||||
%prep
|
||||
%setup
|
||||
%setup -q -n %{name}-%{version}/src
|
||||
|
||||
%build
|
||||
make -C src %{?_smp_mflags} 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
|
||||
mkdir $DOCDIR/docs
|
||||
cp *.md $DOCDIR
|
||||
cp img/* $DOCDIR/img
|
||||
cp demo/* $DOCDIR/demo
|
||||
cp docs/* $DOCDIR/docs
|
||||
%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
410
debian/changelog
vendored
Normal 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
16
debian/control
vendored
Normal 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
34
debian/copyright
vendored
Normal 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
8
debian/gbp.conf
vendored
Normal 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
5
debian/rules
vendored
Executable file
@@ -0,0 +1,5 @@
|
||||
#!/usr/bin/make -f
|
||||
|
||||
%:
|
||||
PREFIX=/usr dh $@ --sourcedirectory=src/
|
||||
|
||||
1
debian/source/format
vendored
Normal file
1
debian/source/format
vendored
Normal file
@@ -0,0 +1 @@
|
||||
3.0 (quilt)
|
||||
@@ -30,7 +30,7 @@ is not needed, useful, or supported for these models.
|
||||
|
||||
If your distribution doesn’t include a recent-enough kernel for your
|
||||
interface, you can get the latest driver from here and build it for
|
||||
your current kernel if it's not too old (the Scarlett2 and FCP drivers
|
||||
your current kernel if it’s not too old (the Scarlett2 and FCP drivers
|
||||
are both maintained in the same tree here):
|
||||
https://github.com/geoffreybennett/linux-fcp/releases
|
||||
|
||||
|
||||
@@ -26,18 +26,22 @@ ALSA driver implementation that you should be aware of:
|
||||
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
|
||||
won't actually update the control.
|
||||
won’t actually update the control.
|
||||
|
||||
3. **Level Meters**: The driver does not support reading the level
|
||||
meters from the hardware.
|
||||
|
||||
4. **Startup Controls**: The driver has no startup controls.
|
||||
4. **Startup Configuration**: The driver is not able to save the
|
||||
current configuration to the non-volatile memory of the device, so
|
||||
you’ll 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
|
||||
1. Apply a “zero” configuration that sets all controls to values that
|
||||
are *not* what you desire.
|
||||
2. Then apply your desired configuration
|
||||
|
||||
@@ -70,12 +74,12 @@ 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 aren't using S/PDIF or ADAT inputs, set this to Internal.
|
||||
from. If you aren’t 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 aren't using S/PDIF or ADAT inputs and the status is
|
||||
clock. If you aren’t using S/PDIF or ADAT inputs and the status is
|
||||
Unlocked, change the Clock Source to Internal.
|
||||
|
||||
### Analogue Input Controls
|
||||
@@ -136,16 +140,16 @@ 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
|
||||
- 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
|
||||
- The “Preamp” preset connects all Hardware Inputs to Hardware
|
||||
Outputs.
|
||||
|
||||
- The "Stereo Out" preset connects PCM 1 and 2 Outputs to pairs of
|
||||
- The “Stereo Out” preset connects PCM 1 and 2 Outputs to pairs of
|
||||
Hardware Outputs.
|
||||
|
||||
## Mixer
|
||||
|
||||
@@ -10,7 +10,7 @@ with the big Scarlett 4th Gen interfaces:
|
||||
### FCP Driver
|
||||
|
||||
The big 4th Gen interfaces are supported by a new “FCP” (Focusrite
|
||||
Control Protocol) driver introduced in Linux 6.14. If you haven't
|
||||
Control Protocol) driver introduced in Linux 6.14. If you haven’t
|
||||
installed
|
||||
[fcp-support](https://github.com/geoffreybennett/fcp-support) yet, you
|
||||
need to do that (and update the firmware) before you can use
|
||||
|
||||
200
src/alsa.c
200
src/alsa.c
@@ -5,10 +5,15 @@
|
||||
#include <alsa/sound/uapi/tlv.h>
|
||||
|
||||
#include "alsa.h"
|
||||
#include "scarlett2.h"
|
||||
#include "scarlett2-firmware.h"
|
||||
#include "scarlett2-ioctls.h"
|
||||
#include "stringhelper.h"
|
||||
#include "window-iface.h"
|
||||
|
||||
#define MAJOR_HWDEP_VERSION_SCARLETT2 1
|
||||
#define MAJOR_HWDEP_VERSION_FCP 2
|
||||
|
||||
#define MAX_TLV_RANGE_SIZE 1024
|
||||
|
||||
// TLV type for channel labels
|
||||
@@ -215,8 +220,8 @@ long alsa_get_elem_value(struct alsa_elem *elem) {
|
||||
|
||||
// for elements with multiple int values, return all the values
|
||||
// the int array returned needs to be freed by the caller
|
||||
int *alsa_get_elem_int_values(struct alsa_elem *elem) {
|
||||
int *values = calloc(elem->count, sizeof(int));
|
||||
long *alsa_get_elem_int_values(struct alsa_elem *elem) {
|
||||
long *values = calloc(elem->count, sizeof(long));
|
||||
|
||||
if (elem->card->num == SIMULATED_CARD_NUM) {
|
||||
for (int i = 0; i < elem->count; i++)
|
||||
@@ -787,6 +792,77 @@ static void card_destroy_callback(void *data) {
|
||||
}
|
||||
}
|
||||
|
||||
// Complete card initialisation after the driver is ready
|
||||
static void complete_card_init(struct alsa_card *card) {
|
||||
|
||||
// Get full element list and create main window
|
||||
alsa_get_elem_list(card);
|
||||
alsa_set_lr_nums(card);
|
||||
alsa_get_routing_controls(card);
|
||||
card->best_firmware_version = scarlett2_get_best_firmware_version(card->pid);
|
||||
|
||||
if (card->serial) {
|
||||
// Call the reopen callbacks for this card
|
||||
struct reopen_callback *rc = g_hash_table_lookup(
|
||||
reopen_callbacks, card->serial
|
||||
);
|
||||
if (rc)
|
||||
rc->callback(rc->data);
|
||||
|
||||
g_hash_table_remove(reopen_callbacks, card->serial);
|
||||
}
|
||||
|
||||
create_card_window(card);
|
||||
}
|
||||
|
||||
// Check if the Firmware Version control has a TLV and is locked,
|
||||
// indicating the driver is ready
|
||||
static int check_driver_ready(snd_ctl_elem_info_t *info) {
|
||||
return snd_ctl_elem_info_is_tlv_readable(info) &&
|
||||
snd_ctl_elem_info_is_locked(info);
|
||||
}
|
||||
|
||||
// Check if the FCP driver is initialised
|
||||
static void check_driver_init(
|
||||
struct alsa_card *card, int numid, unsigned int mask
|
||||
) {
|
||||
|
||||
// Ignore controls going away
|
||||
if (mask == SND_CTL_EVENT_MASK_REMOVE)
|
||||
return;
|
||||
|
||||
// Get the control's info
|
||||
snd_ctl_elem_id_t *id;
|
||||
snd_ctl_elem_info_t *info;
|
||||
|
||||
snd_ctl_elem_id_alloca(&id);
|
||||
snd_ctl_elem_info_alloca(&info);
|
||||
|
||||
snd_ctl_elem_id_set_numid(id, numid);
|
||||
snd_ctl_elem_info_set_id(info, id);
|
||||
|
||||
if (snd_ctl_elem_info(card->handle, info) < 0) {
|
||||
fprintf(stderr, "error getting elem info %d\n", numid);
|
||||
return;
|
||||
}
|
||||
|
||||
const char *name = snd_ctl_elem_info_get_name(info);
|
||||
|
||||
// Check if it's the Firmware Version control being updated
|
||||
if (strcmp(name, "Firmware Version"))
|
||||
return;
|
||||
|
||||
// Check if the driver is ready
|
||||
if (!check_driver_ready(info))
|
||||
return;
|
||||
|
||||
// The driver is initialised; update the card's driver type
|
||||
card->driver_type = DRIVER_TYPE_SOCKET;
|
||||
|
||||
// Complete the card initialisation
|
||||
complete_card_init(card);
|
||||
}
|
||||
|
||||
static gboolean alsa_card_callback(
|
||||
GIOChannel *source,
|
||||
GIOCondition condition,
|
||||
@@ -818,6 +894,13 @@ static gboolean alsa_card_callback(
|
||||
int numid = snd_ctl_event_elem_get_numid(event);
|
||||
unsigned int mask = snd_ctl_event_elem_get_mask(event);
|
||||
|
||||
// Check if we're waiting for FCP driver to initialise and check if
|
||||
// it's now ready
|
||||
if (card->driver_type == DRIVER_TYPE_SOCKET_UNINIT) {
|
||||
check_driver_init(card, numid, mask);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (mask == SND_CTL_EVENT_MASK_REMOVE) {
|
||||
card_destroy_callback(card);
|
||||
return 0;
|
||||
@@ -1067,6 +1150,94 @@ static void alsa_get_serial_number(struct alsa_card *card) {
|
||||
card->serial = strdup(serial);
|
||||
}
|
||||
|
||||
// return true if the Firmware Version control exists and is writable
|
||||
// and locked (i.e. the FCP server is running)
|
||||
static int check_firmware_version_locked(struct alsa_card *card) {
|
||||
snd_ctl_elem_id_t *id;
|
||||
snd_ctl_elem_info_t *info;
|
||||
|
||||
snd_ctl_elem_id_alloca(&id);
|
||||
snd_ctl_elem_info_alloca(&info);
|
||||
|
||||
// look for the Firmware Version control
|
||||
snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_CARD);
|
||||
snd_ctl_elem_id_set_name(id, "Firmware Version");
|
||||
snd_ctl_elem_info_set_id(info, id);
|
||||
|
||||
// no Firmware Version control found
|
||||
int err = snd_ctl_elem_info(card->handle, info);
|
||||
if (err < 0)
|
||||
return 0;
|
||||
|
||||
return check_driver_ready(info);
|
||||
}
|
||||
|
||||
// return the driver type for this card
|
||||
// DRIVER_TYPE_NONE: no driver
|
||||
// DRIVER_TYPE_HWDEP: Scarlett2 driver
|
||||
// DRIVER_TYPE_SOCKET: FCP driver
|
||||
// DRIVER_TYPE_SOCKET_UNINIT: FCP driver, but not initialised
|
||||
static int get_driver_type(struct alsa_card *card) {
|
||||
snd_hwdep_t *hwdep;
|
||||
|
||||
int err = scarlett2_open_card(card->device, &hwdep);
|
||||
|
||||
// no hwdep for this card - driver type none
|
||||
if (err == -ENOENT)
|
||||
return DRIVER_TYPE_NONE;
|
||||
|
||||
// if we get EPERM, it's FCP but no server running
|
||||
if (err == -EPERM)
|
||||
return DRIVER_TYPE_SOCKET_UNINIT;
|
||||
|
||||
// if we get EBUSY, it's FCP
|
||||
if (err == -EBUSY)
|
||||
// fcp-server locks the Firmware Version control when it has
|
||||
// finished starting up
|
||||
return check_firmware_version_locked(card) ?
|
||||
DRIVER_TYPE_SOCKET : DRIVER_TYPE_SOCKET_UNINIT;
|
||||
|
||||
// failed to open hwdep
|
||||
if (err < 0)
|
||||
return DRIVER_TYPE_NONE;
|
||||
|
||||
// we can open hwdep, so now check the protocol version
|
||||
int ver = scarlett2_get_protocol_version(hwdep);
|
||||
scarlett2_close(hwdep);
|
||||
|
||||
// failed to get protocol version
|
||||
if (ver < 0)
|
||||
return DRIVER_TYPE_NONE;
|
||||
|
||||
// hwdep protocol version 1.x.x is Scarlett2 driver
|
||||
if (SCARLETT2_HWDEP_VERSION_MAJOR(ver) == MAJOR_HWDEP_VERSION_SCARLETT2)
|
||||
return DRIVER_TYPE_HWDEP;
|
||||
|
||||
// hwdep protocol version 2.x.x is FCP driver (but not initialised,
|
||||
// because we were able to open the hwdep)
|
||||
if (SCARLETT2_HWDEP_VERSION_MAJOR(ver) == MAJOR_HWDEP_VERSION_FCP)
|
||||
return DRIVER_TYPE_SOCKET_UNINIT;
|
||||
|
||||
return DRIVER_TYPE_NONE;
|
||||
}
|
||||
|
||||
static void card_init(struct alsa_card *card) {
|
||||
alsa_get_usbid(card);
|
||||
alsa_get_serial_number(card);
|
||||
alsa_subscribe(card);
|
||||
alsa_add_card_callback(card);
|
||||
|
||||
card->driver_type = get_driver_type(card);
|
||||
|
||||
// Driver not ready? Create the iface-waiting window
|
||||
if (card->driver_type == DRIVER_TYPE_SOCKET_UNINIT) {
|
||||
create_card_window(card);
|
||||
return;
|
||||
}
|
||||
|
||||
complete_card_init(card);
|
||||
}
|
||||
|
||||
static void alsa_scan_cards(void) {
|
||||
snd_ctl_card_info_t *info;
|
||||
snd_ctl_t *ctl;
|
||||
@@ -1110,30 +1281,7 @@ static void alsa_scan_cards(void) {
|
||||
card->name = strdup(snd_ctl_card_info_get_name(info));
|
||||
card->handle = ctl;
|
||||
|
||||
alsa_get_elem_list(card);
|
||||
alsa_set_lr_nums(card);
|
||||
alsa_get_routing_controls(card);
|
||||
|
||||
alsa_subscribe(card);
|
||||
alsa_get_usbid(card);
|
||||
alsa_get_serial_number(card);
|
||||
card->best_firmware_version =
|
||||
scarlett2_get_best_firmware_version(card->pid);
|
||||
|
||||
if (card->serial) {
|
||||
|
||||
// call the reopen callbacks for this card
|
||||
struct reopen_callback *rc = g_hash_table_lookup(
|
||||
reopen_callbacks, card->serial
|
||||
);
|
||||
if (rc)
|
||||
rc->callback(rc->data);
|
||||
|
||||
g_hash_table_remove(reopen_callbacks, card->serial);
|
||||
}
|
||||
|
||||
create_card_window(card);
|
||||
alsa_add_card_callback(card);
|
||||
card_init(card);
|
||||
|
||||
continue;
|
||||
|
||||
|
||||
16
src/alsa.h
16
src/alsa.h
@@ -41,6 +41,19 @@ enum {
|
||||
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];
|
||||
|
||||
@@ -162,6 +175,7 @@ struct alsa_card {
|
||||
uint32_t pid;
|
||||
char *serial;
|
||||
char *name;
|
||||
int driver_type;
|
||||
char *fcp_socket;
|
||||
int best_firmware_version;
|
||||
snd_ctl_t *handle;
|
||||
@@ -226,7 +240,7 @@ void alsa_elem_add_callback(
|
||||
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);
|
||||
|
||||
19
src/fcp-shared.c
Normal file
19
src/fcp-shared.c
Normal 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
80
src/fcp-shared.h
Normal 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
220
src/fcp-socket.c
Normal 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
27
src/fcp-socket.h
Normal 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);
|
||||
117
src/iface-waiting.c
Normal file
117
src/iface-waiting.c
Normal file
@@ -0,0 +1,117 @@
|
||||
// SPDX-FileCopyrightText: 2025 Geoffrey D. Bennett <g@b4.vu>
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "alsa.h"
|
||||
#include "iface-waiting.h"
|
||||
#include "scarlett2-ioctls.h"
|
||||
#include "window-iface.h"
|
||||
|
||||
// Structure to hold timeout-related widgets
|
||||
struct timeout_data {
|
||||
GtkWidget *box;
|
||||
GtkWidget *spinner;
|
||||
GtkWidget *message_label;
|
||||
guint timeout_id;
|
||||
};
|
||||
|
||||
// Timeout callback function
|
||||
static gboolean on_timeout(gpointer user_data) {
|
||||
struct timeout_data *data = (struct timeout_data *)user_data;
|
||||
|
||||
// Remove spinner
|
||||
gtk_box_remove(GTK_BOX(data->box), data->spinner);
|
||||
|
||||
// Update message with clickable link
|
||||
if (data->message_label && GTK_IS_WIDGET(data->message_label))
|
||||
gtk_label_set_markup(
|
||||
GTK_LABEL(data->message_label),
|
||||
"Driver not detected. Please ensure "
|
||||
"<span font='monospace'>fcp-server</span> from "
|
||||
"<a href=\"https://github.com/geoffreybennett/fcp-support\">"
|
||||
"https://github.com/geoffreybennett/fcp-support</a> "
|
||||
"has been installed."
|
||||
);
|
||||
|
||||
// Reset the timeout ID since it won't be called again
|
||||
data->timeout_id = 0;
|
||||
|
||||
// Return FALSE to prevent the timeout from repeating
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Weak reference callback for cleanup
|
||||
static void on_widget_dispose(gpointer data, GObject *where_the_object_was) {
|
||||
struct timeout_data *timeout_data = (struct timeout_data *)data;
|
||||
|
||||
// Cancel the timeout if it's still active
|
||||
if (timeout_data->timeout_id > 0)
|
||||
g_source_remove(timeout_data->timeout_id);
|
||||
|
||||
// Free the data structure
|
||||
g_free(timeout_data);
|
||||
}
|
||||
|
||||
GtkWidget *create_iface_waiting_main(struct alsa_card *card) {
|
||||
struct timeout_data *data;
|
||||
|
||||
// Main vertical box
|
||||
GtkWidget *box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 20);
|
||||
gtk_widget_set_margin_start(box, 40);
|
||||
gtk_widget_set_margin_end(box, 40);
|
||||
gtk_widget_set_margin_top(box, 40);
|
||||
gtk_widget_set_margin_bottom(box, 40);
|
||||
|
||||
// Heading
|
||||
GtkWidget *label = gtk_label_new(NULL);
|
||||
gtk_label_set_markup(GTK_LABEL(label),
|
||||
"<span weight='bold' size='large'>Waiting for FCP Server</span>");
|
||||
gtk_box_append(GTK_BOX(box), label);
|
||||
|
||||
// Add picture (scaled down properly)
|
||||
GtkWidget *picture_box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
|
||||
gtk_widget_set_hexpand(picture_box, TRUE);
|
||||
gtk_widget_set_halign(picture_box, GTK_ALIGN_CENTER);
|
||||
|
||||
GtkWidget *picture = gtk_picture_new_for_resource(
|
||||
"/vu/b4/alsa-scarlett-gui/icons/vu.b4.alsa-scarlett-gui.png"
|
||||
);
|
||||
gtk_picture_set_can_shrink(GTK_PICTURE(picture), TRUE);
|
||||
gtk_widget_set_size_request(picture, 128, 128);
|
||||
|
||||
gtk_box_append(GTK_BOX(picture_box), picture);
|
||||
gtk_box_append(GTK_BOX(box), picture_box);
|
||||
|
||||
// Add spinner
|
||||
GtkWidget *spinner = gtk_spinner_new();
|
||||
gtk_spinner_start(GTK_SPINNER(spinner));
|
||||
gtk_widget_set_size_request(spinner, 48, 48);
|
||||
gtk_box_append(GTK_BOX(box), spinner);
|
||||
|
||||
// Description
|
||||
label = gtk_label_new(
|
||||
"Waiting for the user-space FCP driver to initialise..."
|
||||
);
|
||||
gtk_label_set_wrap(GTK_LABEL(label), TRUE);
|
||||
gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_CENTER);
|
||||
gtk_label_set_max_width_chars(GTK_LABEL(label), 1);
|
||||
gtk_widget_set_hexpand(label, TRUE);
|
||||
gtk_widget_set_halign(label, GTK_ALIGN_FILL);
|
||||
|
||||
gtk_box_append(GTK_BOX(box), label);
|
||||
|
||||
// Setup timeout
|
||||
data = g_new(struct timeout_data, 1);
|
||||
data->box = box;
|
||||
data->spinner = spinner;
|
||||
data->message_label = label;
|
||||
|
||||
// Set timeout
|
||||
data->timeout_id = g_timeout_add_seconds(5, on_timeout, data);
|
||||
|
||||
// Ensure data is freed when the box is destroyed
|
||||
g_object_weak_ref(G_OBJECT(box), on_widget_dispose, data);
|
||||
|
||||
return box;
|
||||
}
|
||||
8
src/iface-waiting.h
Normal file
8
src/iface-waiting.h
Normal file
@@ -0,0 +1,8 @@
|
||||
// SPDX-FileCopyrightText: 2025 Geoffrey D. Bennett <g@b4.vu>
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "alsa.h"
|
||||
|
||||
GtkWidget *create_iface_waiting_main(struct alsa_card *card);
|
||||
@@ -30,13 +30,9 @@ struct hw_info gen_2_info[] = {
|
||||
{ }
|
||||
};
|
||||
|
||||
struct hw_info gen_3_small_info[] = {
|
||||
struct hw_info gen_3_info[] = {
|
||||
{ "Scarlett Solo 3rd Gen" },
|
||||
{ "Scarlett 2i2 3rd Gen" },
|
||||
{ }
|
||||
};
|
||||
|
||||
struct hw_info gen_3_big_info[] = {
|
||||
{ "Scarlett 4i4 3rd Gen" },
|
||||
{ "Scarlett 8i6 3rd Gen" },
|
||||
{ "Scarlett 18i8 3rd Gen" },
|
||||
@@ -48,6 +44,9 @@ struct hw_info gen_4_info[] = {
|
||||
{ "Scarlett Solo 4th Gen" },
|
||||
{ "Scarlett 2i2 4th Gen" },
|
||||
{ "Scarlett 4i4 4th Gen" },
|
||||
{ "Scarlett 16i16 4th Gen" },
|
||||
{ "Scarlett 18i16 4th Gen" },
|
||||
{ "Scarlett 18i20 4th Gen" },
|
||||
{ }
|
||||
};
|
||||
|
||||
@@ -65,6 +64,12 @@ struct hw_info clarett_plus_info[] = {
|
||||
{ }
|
||||
};
|
||||
|
||||
struct hw_info vocaster_info[] = {
|
||||
{ "Vocaster One" },
|
||||
{ "Vocaster Two" },
|
||||
{ }
|
||||
};
|
||||
|
||||
struct hw_cat hw_cat[] = {
|
||||
{ "1st Gen",
|
||||
gen_1_info
|
||||
@@ -72,11 +77,8 @@ struct hw_cat hw_cat[] = {
|
||||
{ "2nd Gen",
|
||||
gen_2_info
|
||||
},
|
||||
{ "Small 3rd Gen",
|
||||
gen_3_small_info
|
||||
},
|
||||
{ "Big 3rd Gen",
|
||||
gen_3_big_info
|
||||
{ "3rd Gen",
|
||||
gen_3_info
|
||||
},
|
||||
{ "4th Gen",
|
||||
gen_4_info
|
||||
@@ -87,6 +89,9 @@ struct hw_cat hw_cat[] = {
|
||||
{ "Clarett+",
|
||||
clarett_plus_info
|
||||
},
|
||||
{ "Vocaster",
|
||||
vocaster_info
|
||||
},
|
||||
{ }
|
||||
};
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "iface-none.h"
|
||||
#include "iface-unknown.h"
|
||||
#include "iface-update.h"
|
||||
#include "iface-waiting.h"
|
||||
#include "main.h"
|
||||
#include "menu.h"
|
||||
#include "window-iface.h"
|
||||
@@ -21,11 +22,34 @@ void create_card_window(struct alsa_card *card) {
|
||||
gtk_window_destroy(GTK_WINDOW(no_cards_window));
|
||||
no_cards_window = NULL;
|
||||
}
|
||||
window_count++;
|
||||
|
||||
// Replacing an existing window
|
||||
if (card->window_main)
|
||||
gtk_window_destroy(GTK_WINDOW(card->window_main));
|
||||
|
||||
// New window
|
||||
else
|
||||
window_count++;
|
||||
|
||||
int has_startup = true;
|
||||
int has_mixer = true;
|
||||
|
||||
// Check if the FCP driver is not initialised yet
|
||||
if (card->driver_type == DRIVER_TYPE_SOCKET_UNINIT) {
|
||||
card->window_main_contents = create_iface_waiting_main(card);
|
||||
has_startup = false;
|
||||
has_mixer = false;
|
||||
|
||||
// Create minimal window with only the waiting interface
|
||||
card->window_main = gtk_application_window_new(app);
|
||||
gtk_window_set_resizable(GTK_WINDOW(card->window_main), FALSE);
|
||||
gtk_window_set_title(GTK_WINDOW(card->window_main), card->name);
|
||||
gtk_window_set_child(GTK_WINDOW(card->window_main), card->window_main_contents);
|
||||
gtk_widget_set_visible(card->window_main, TRUE);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
struct alsa_elem *msd_elem =
|
||||
get_elem_by_name(card->elems, "MSD Mode Switch");
|
||||
int in_msd_mode = msd_elem && alsa_get_elem_value(msd_elem);
|
||||
@@ -54,6 +78,7 @@ void create_card_window(struct alsa_card *card) {
|
||||
// Scarlett Gen 1
|
||||
} else if (get_elem_by_prefix(card->elems, "Matrix")) {
|
||||
card->window_main_contents = create_iface_mixer_main(card);
|
||||
has_startup = false;
|
||||
|
||||
// Scarlett Gen 2, Gen 3 4i4+, Gen 4, Clarett, or Vocaster
|
||||
} else if (get_elem_by_prefix(card->elems, "Mixer")) {
|
||||
|
||||
@@ -38,7 +38,7 @@ static int update_levels_controls(void *user_data) {
|
||||
|
||||
struct alsa_elem *level_meter_elem = data->level_meter_elem;
|
||||
|
||||
int *values = alsa_get_elem_int_values(level_meter_elem);
|
||||
long *values = alsa_get_elem_int_values(level_meter_elem);
|
||||
|
||||
gtk_dial_peak_tick();
|
||||
|
||||
|
||||
@@ -279,9 +279,10 @@ static void create_routing_grid(struct alsa_card *card) {
|
||||
routing_grid, card->routing_dsp_out_grid, dsp_col_num, 3, 1, 1
|
||||
);
|
||||
}
|
||||
gtk_grid_attach(
|
||||
routing_grid, card->routing_mixer_in_grid, mix_col_num, 0, 1, 1
|
||||
);
|
||||
if (!card->has_fixed_mixer_inputs)
|
||||
gtk_grid_attach(
|
||||
routing_grid, card->routing_mixer_in_grid, mix_col_num, 0, 1, 1
|
||||
);
|
||||
gtk_grid_attach(
|
||||
routing_grid, card->routing_mixer_out_grid, mix_col_num, 3, 1, 1
|
||||
);
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include "device-reset-config.h"
|
||||
#include "device-update-firmware.h"
|
||||
#include "fcp-socket.h"
|
||||
#include "gtkhelper.h"
|
||||
#include "scarlett2.h"
|
||||
#include "scarlett2-ioctls.h"
|
||||
@@ -10,8 +11,6 @@
|
||||
#include "widget-drop-down.h"
|
||||
#include "window-startup.h"
|
||||
|
||||
#define REQUIRED_HWDEP_VERSION_MAJOR 1
|
||||
|
||||
static GtkWidget *small_label(const char *text) {
|
||||
GtkWidget *w = gtk_label_new(NULL);
|
||||
|
||||
@@ -238,21 +237,32 @@ static void add_reset_action(
|
||||
}
|
||||
|
||||
static void reboot_device(GtkWidget *button, struct alsa_card *card) {
|
||||
snd_hwdep_t *hwdep;
|
||||
int err = 0;
|
||||
|
||||
int err = scarlett2_open_card(card->device, &hwdep);
|
||||
if (err < 0) {
|
||||
fprintf(stderr, "unable to open hwdep interface: %s\n", snd_strerror(err));
|
||||
return;
|
||||
// HWDEP (Scarlett2) driver type
|
||||
if (card->driver_type == DRIVER_TYPE_HWDEP) {
|
||||
snd_hwdep_t *hwdep;
|
||||
|
||||
err = scarlett2_open_card(card->device, &hwdep);
|
||||
if (err < 0) {
|
||||
fprintf(stderr, "unable to open hwdep interface: %s\n", snd_strerror(err));
|
||||
return;
|
||||
}
|
||||
|
||||
err = scarlett2_reboot(hwdep);
|
||||
if (err < 0) {
|
||||
fprintf(stderr, "unable to reboot device: %s\n", snd_strerror(err));
|
||||
return;
|
||||
}
|
||||
|
||||
scarlett2_close(hwdep);
|
||||
|
||||
// Socket (FCP) driver type
|
||||
} else if (card->driver_type == DRIVER_TYPE_SOCKET) {
|
||||
err = fcp_socket_reboot_device(card);
|
||||
if (err < 0)
|
||||
fprintf(stderr, "unable to reboot device via socket\n");
|
||||
}
|
||||
|
||||
err = scarlett2_reboot(hwdep);
|
||||
if (err < 0) {
|
||||
fprintf(stderr, "unable to reboot device: %s\n", snd_strerror(err));
|
||||
return;
|
||||
}
|
||||
|
||||
scarlett2_close(hwdep);
|
||||
}
|
||||
|
||||
static void add_reset_actions(
|
||||
@@ -261,38 +271,10 @@ static void add_reset_actions(
|
||||
int *grid_y,
|
||||
int show_reboot_option
|
||||
) {
|
||||
// simulated cards don't support hwdep
|
||||
if (!card->device)
|
||||
if (card->driver_type != DRIVER_TYPE_HWDEP &&
|
||||
card->driver_type != DRIVER_TYPE_SOCKET)
|
||||
return;
|
||||
|
||||
snd_hwdep_t *hwdep;
|
||||
|
||||
int err = scarlett2_open_card(card->device, &hwdep);
|
||||
if (err < 0) {
|
||||
fprintf(stderr, "unable to open hwdep interface: %s\n", snd_strerror(err));
|
||||
return;
|
||||
}
|
||||
|
||||
int ver = scarlett2_get_protocol_version(hwdep);
|
||||
if (ver < 0) {
|
||||
fprintf(stderr, "unable to get protocol version: %s\n", snd_strerror(ver));
|
||||
return;
|
||||
}
|
||||
|
||||
if (SCARLETT2_HWDEP_VERSION_MAJOR(ver) != REQUIRED_HWDEP_VERSION_MAJOR) {
|
||||
fprintf(
|
||||
stderr,
|
||||
"Unsupported hwdep protocol version %d.%d.%d on card %s\n",
|
||||
SCARLETT2_HWDEP_VERSION_MAJOR(ver),
|
||||
SCARLETT2_HWDEP_VERSION_MINOR(ver),
|
||||
SCARLETT2_HWDEP_VERSION_SUBMINOR(ver),
|
||||
card->device
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
scarlett2_close(hwdep);
|
||||
|
||||
// Add reboot action if there is a control that requires a reboot
|
||||
// to take effect
|
||||
if (show_reboot_option) {
|
||||
|
||||
@@ -17,10 +17,45 @@ finish-args:
|
||||
# Point to the firmware directory
|
||||
- --env=SCARLETT2_FIRMWARE_DIR=/app/lib/firmware/scarlett2
|
||||
modules:
|
||||
- name: alsa-utils
|
||||
sources:
|
||||
- type: archive
|
||||
url: https://www.alsa-project.org/files/pub/lib/alsa-lib-1.2.12.tar.bz2
|
||||
sha256: 4868cd908627279da5a634f468701625be8cc251d84262c7e5b6a218391ad0d2
|
||||
dest: .deps/alsa-lib
|
||||
- type: archive
|
||||
url: https://www.alsa-project.org/files/pub/utils/alsa-utils-1.2.12.tar.bz2
|
||||
sha256: 98bc6677d0c0074006679051822324a0ab0879aea558a8f68b511780d30cd924
|
||||
buildsystem: autotools
|
||||
config-opts:
|
||||
# We are only interested in alsactl
|
||||
- --bindir=/app/null
|
||||
- --with-udev-rules-dir=/app/null
|
||||
- --with-systemdsystemunitdir=/app/null
|
||||
# https://github.com/alsa-project/alsa-utils/issues/33
|
||||
- --enable-alsa-topology
|
||||
- --disable-alsaconf
|
||||
- --disable-alsatest
|
||||
- --disable-alsabat-backend-tiny
|
||||
- --disable-alsamixer
|
||||
- --disable-alsaloop
|
||||
- --disable-nhlt
|
||||
- --disable-xmlto
|
||||
- --disable-rst2man
|
||||
- --with-alsa-inc-prefix=.deps/alsa-lib/include
|
||||
post-install:
|
||||
- install -Dm755 /app/sbin/alsactl /app/bin/alsactl
|
||||
cleanup:
|
||||
- /lib/debug
|
||||
- /lib/alsa-topology
|
||||
- /null
|
||||
- /sbin
|
||||
- /share/alsa
|
||||
- /share/locale
|
||||
- /share/man
|
||||
- /share/runtime
|
||||
- /share/sounds
|
||||
- name: alsa-scarlett-gui
|
||||
buildsystem: simple
|
||||
build-commands:
|
||||
- make -j8 install PREFIX=$FLATPAK_DEST
|
||||
sources:
|
||||
- type: dir
|
||||
path: ./src
|
||||
@@ -28,13 +63,18 @@ modules:
|
||||
# - type: git
|
||||
# url: https://github.com/geoffreybennett/alsa-scarlett-gui.git
|
||||
# tag: "0.2"
|
||||
|
||||
- name: scarlett2-firmware
|
||||
buildsystem: simple
|
||||
build-commands:
|
||||
- mkdir -p $FLATPAK_DEST/lib/firmware/scarlett2
|
||||
- cp -a LICENSE.Focusrite firmware/* $FLATPAK_DEST/lib/firmware/scarlett2
|
||||
- make -j8 install PREFIX=$FLATPAK_DEST
|
||||
cleanup:
|
||||
- /lib/debug
|
||||
- /lib/source
|
||||
- name: scarlett2-firmware
|
||||
sources:
|
||||
- type: archive
|
||||
url: https://github.com/geoffreybennett/scarlett2-firmware/archive/refs/tags/2128b.tar.gz
|
||||
sha256: 4a17fdbe2110855c2f7f6cfc5ea1894943a6e58770f3dff5ef283961f8ae2a03
|
||||
buildsystem: simple
|
||||
build-commands:
|
||||
- mkdir -p $FLATPAK_DEST/lib/firmware/scarlett2
|
||||
- cp -a LICENSE.Focusrite firmware/* $FLATPAK_DEST/lib/firmware/scarlett2
|
||||
|
||||
Reference in New Issue
Block a user