# SongRec

SongRec is an open-source Shazam client for Linux, written in Rust.

![Screenshot](packaging/Screenshot_hires_light.png?raw=true)

Features:

* Recognize tracks from an arbitrary audio file.
* Recognize audio from the microphone.
* Usage from both GUI and command line.
* Provide an history of the recognized songs on the GUI, exportable to CSV.
* Continuous song detection from the microphone, with the ability to choose your input device.
* Ability to recognize songs from your speakers rather than your microphone.

<p align="center"><a href="https://flathub.org/en/apps/re.fossplant.songrec"><img src="packaging/flathub_badge_black.svg?raw=true"></a></p>

A (command-line only) [Python version](python-version), which I made before rewriting in Rust for performance, is also available for demonstration purposes. It supports file recognition only.

## How it works

For useful information about how audio fingerprinting works, you may want to read [this article](http://coding-geek.com/how-shazam-works/) ([archive.org mirror](https://web.archive.org/web/20230215010310/http://coding-geek.com/how-shazam-works/)). To be put simply, Shazam generates a spectrogram (a time/frequency 2D graph of the sound, with amplitude at intersections) of the sound, and maps out the frequency peaks from it (which should match key points of the harmonics of voice or of certains instruments).

Shazam also downsamples the sound at 16 KHz before processing, and cuts the sound in four bands of 250-520 Hz, 520-1450 Hz, 1450-3500 Hz, 3500-5500 Hz (so that if a band is too much scrambled by noise, recognition from other bands may apply). The frequency peaks are then sent to the servers, which subsequently look up the strongest peaks in a database, in order look for the simultaneous presence of neighboring peaks both in the associated reference fingerprints and in the fingerprint we sent.

Hence, the Shazam fingerprinting algorithm, as implemented by the client, is fairly simple, as much of the processing is done server-side. The general functionment of Shazam has been documented in public [research papers](https://www.ee.columbia.edu/~dpwe/papers/Wang03-shazam.pdf) and patents.

## Installation

Here are a few ways to install and run the application:

Using pacman (Arch Linux):

```bash
sudo pacman -S songrec
songrec
```

Using apt with PPA (Ubuntu, recommended):

```bash
wget -qO- 'http://keyserver.ubuntu.com/pks/lookup?op=get&search=0x6888550b2fc77d09' | sudo tee /etc/apt/trusted.gpg.d/songrec.asc
sudo apt-add-repository ppa:marin-m/songrec -y -u
sudo apt install songrec -y
songrec
```

Using Flatpak (all distributions) (NOTE: with Flatpak, the GUI should work fine but some of the CLI features may not be usable due to filesystem sandboxing restrictions):

```bash
sudo apt install flatpak -y
flatpak remote-add --user flathub https://flathub.org/repo/flathub.flatpakrepo --if-not-exists
flatpak install --user flathub re.fossplant.songrec -y
flatpak run re.fossplant.songrec
```

Note: It is not mandatory, but if you want to be able to recognize more formats than WAV, OGG, FLAC and MP3, you should ensure that you have the `ffmpeg` package installed.

Note: You may remove dependencies over GTK+, Pulseaudio/PipeWire's libpulse or DBus MPRIS through editing the `-F` flag passed to `cargo`.

## Compilation

(**WARNING**: Remind to compile the code in "--release" mode for correct performance.)

<a href="https://weblate.fossplant.re/engage/songrec/">
<img src="https://weblate.fossplant.re/widget/songrec/songrec/svg-badge.svg" alt="État de la traduction" />
</a>
<a href="https://crates.io/crates/songrec">
<img alt="Crates.io Version" src="https://img.shields.io/crates/v/songrec">
</a>
<a href="https://snapcraft.io/songrec">
<img alt="Snapcraft Version" src="https://img.shields.io/snapcraft/v/songrec/latest/stable">
</a>

### Installing Rust

First, you need to [install the Rust compiler and package manager](https://www.rust-lang.org/tools/install). The current minimal `rustc` required version should be at least version 1.88.

You can either install Rust from the repositories, for example using Ubuntu/Debian:

```bash
sudo apt install rustc cargo
# Or, for a more up-to-date binary:
sudo apt install rustup
```

Or, under Fedora Linux:

```bash
sudo dnf install rustc cargo
```

Under Archlinux:

```bash
sudo pacman -S cargo rust
```

With MSYS2 (MINGW64, Windows XP+):

```bash
pacman -S mingw-w64-x86_64-rust
```

With MSYS2 (UCRT64, Windows 10+):

```bash
pacman -S mingw-w64-ucrt-x86_64-rust
```

Using MacPorts (macOS):

```bash
sudo port install rust cargo
```

Using Homebrew (macOS 14+):

```bash
brew install rust
```

Or, using any distribution:

```bash
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh # Type "1"
# Login and reconnect to add Rust to the $PATH, or run:
source $HOME/.cargo/env

# If you already installed Rust, then update it:
rustup update
```

### Install dependent libraries (nothing exotic)

Debian and Ubuntu:

```bash
sudo apt install build-essential libasound2-dev libpipewire-0.3-dev libclang-dev libpulse-dev libgtk-4-dev libsoup-3.0-dev libadwaita-1-dev libdbus-1-dev gettext sed
```

Archlinux:

```bash
sudo pacman -S pkgconf git gtk4 libadwaita libsoup3 alsa-lib libpulse libpipewire clang openssl ffmpeg gettext sed
```

Fedora Linux:

```shell
sudo dnf groupinstall "Development Tools"
sudo dnf install alsa-lib-devel pipewire-devel clang-devel pulseaudio-libs-devel pkgconf-pkg-config glib gtk4-devel libsoup3-devel libadwaita-devel dbus-devel openssl-devel gettext sed
```

MSYS2 with MINGW64 (Windows XP+):

```bash
# Obtain source:
# In PowerShell:
#   winget install --id Git.Git -e --source winget
# (restart PowerShell)
#   cd C:\msys64\home\*
#   git clone https://github.com/marin-m/SongRec.git SongRec-main
pacman -Sy unzip mingw-w64-x86_64-gettext-runtime mingw-w64-x86_64-gcc mingw-w64-x86_64-libadwaita mingw-w64-x86_64-adwaita-icon-theme mingw-w64-x86_64-glib2 mingw-w64-x86_64-gtk4 mingw-w64-x86_64-pkgconf mingw-w64-x86_64-dbus mingw-w64-x86_64-openssl mingw-w64-x86_64-libsoup3 mingw-w64-x86_64-ffmpeg
```

MSYS2 with UCRT64 (Windows 10+):

```bash
pacman -Sy unzip mingw-w64-ucrt-x86_64-gettext-runtime mingw-w64-ucrt-x86_64-gcc mingw-w64-ucrt-x86_64-libadwaita mingw-w64-ucrt-x86_64-adwaita-icon-theme mingw-w64-ucrt-x86_64-glib2 mingw-w64-ucrt-x86_64-gtk4 mingw-w64-ucrt-x86_64-pkgconf mingw-w64-ucrt-x86_64-dbus mingw-w64-ucrt-x86_64-openssl mingw-w64-ucrt-x86_64-libsoup3 mingw-w64-ucrt-x86_64-ffmpeg
```

NOTE: macOS is not officially supported. You may have to first install [XQuartz](https://www.xquartz.org/), export the `GSK_RENDERER=cairo` environment variable, and other tricks to have the application working.

MacPorts (macOS):

```bash
sudo port install libadwaita gtk4 libsoup ffmpeg gmake cctools +xcode
# Note: always install/use gettext from brew, cf.: https://github.com/gettext-rs/gettext-rs/issues/140
brew install gettext
export GETTEXT_DIR=/opt/homebrew
```

Homebrew (macOS 14+):

```bash
brew install libadwaita gtk4 libsoup ffmpeg gettext
export GETTEXT_DIR=/opt/homebrew
```

Void Linux (libressl):

```shell
sudo xbps-install base-devel alsa-lib-devel pipewire-devel clang-devel pulseaudio-devel gtk4-devel libsoup3-devel libadwaita-devel dbus-devel libressl-devel
```

Void Linux (openssl):

```shell
sudo xbps-install base-devel alsa-lib-devel pipewire-devel clang-devel pulseaudio-devel gtk4-devel libsoup3-devel libadwaita-devel dbus-devel openssl-devel
```

### Compiling the project

This will compile and run the projet:

```bash
# For the stable release:
# On Linux:
cargo install songrec --no-default-features -F gui,ffmpeg,pulse,pipewire,mpris
# On Windows or macOS:
cargo install songrec --no-default-features -F gui,ffmpeg
songrec

# For the Github tree:
git clone https://github.com/marin-m/songrec
cd songrec
cp -a .github/hooks/* .git/hooks/ # Or (less secure): git config core.hooksPath .github/hooks
# On Linux:
cargo run --release --no-default-features -F gui,ffmpeg,pulse,pipewire,mpris
# On macOS or Windows:
cargo run --release --no-default-features -F gui,ffmpeg

```

For the latter, you will then find the project's binary (that you will be able to move or execute directly) at `target/release/songrec`.

Note: You may remove dependencies over GTK+, Pulseaudio/PipeWire's libpulse or DBus MPRIS through editing the `-F` flag passed to `cargo`.

### Building the Snap package

When building the Snap package locally, be sure to connect the `:audio-record` interface manually so that the application works:

```bash
git clone https://github.com/marin-m/songrec
cd songrec
snapcraft pack
sudo snap remove --purge songrec
sudo snap install --dangerous songrec_*.snap
sudo snap connect songrec:audio-record :audio-record
songrec
```

## Sample usage

Passing no arguments or using the `gui` subcommand will launch the GUI, and try to recognize audio real-time as soon as the application is launched:

```
./songrec
./songrec gui
```

Using the `gui-norecording` subcommand will launch the GUI without recognizing audio as soon as the software is started (you will need to click the "Turn on microphone recognition" button to do so):

```
./songrec gui-norecording
```

The GUI allows you to recognize songs either from your microphone, speakers, or from an audio file. The MP3, FLAC, WAV and OGG formats should be accepted for audio files if FFMpeg is not installed, and any audio or video formats supported by FFMpeg should be accepted if FFMpeg is installed.

The following commands allow to recognize sound from your microphone or from a file using the command line (`listen` runs while the microphone is usable while `recognize` recognizes only one song), use the `-h` flag in order to see all the available options:

```
./songrec listen -h
./songrec recognize -h
```

By default, only the artist and track name of the concerned song are displayed to the standard output, and other information may be displayed to the error output. The `--csv` and `--json` options allow to display more programmatically usable information to the standard output.

The above decribes the newer CLI interface of SongRec, but an older interface, operating only on audio files or raw audio fingerprints, is also available and described below.

The following subcommand will try to recognize audio from the middle of an audio file, and print the JSON response from Shazam servers:

```
./songrec audio-file-to-recognized-song sound_file.mp3
```

The following subcommands will do the same with an intermediary step, manipulating data-URI audio fingerprints as used by Shazam internally:

```
./songrec audio-file-to-fingerprint sound_file.mp3
./songrec fingerprint-to-recognized-song 'data:audio/vnd.shazam.sig;base64,...'
```

Please note that if you have installed the application through Flathub, you will need to use the `--file-forwarding` flag in order to use the command line with data on the filesystem (which doesn't go through the same Flatpak/XDG portals as the GUI):

```
flatpak run --file-forwarding re.fossplant.songrec audio-file-to-fingerprint @@ sound_file.mp3 @@
```

When using the application, you may notice that certain information will be saved to `~/.local/share/songrec` and `~/.config/songrec` (or an equivalent directory depending on your operating system), including the CSV-format list of the last recognized songs and the last selected microphone input device (so that it is chosen back when restarting the app). You may want to delete these directories in case of persistent issues.

## Privacy

SongRec collects no data and contacts no other servers than Shazam's. SongRec does not upload raw audio data anywhere: only fingerprints of the audio are uploaded, which means sequences of frequency peaks encoded in the form of "(frequency, amplitude, time)" tuples.

This does not suffice to represent anything hearable alone; that means that no actually hearable sound (e.g voice fragments) is sent to servers, only metadata derived on the characteristics of the sound that may only suffice to recognize a song already known by Shazam is being sent.

## Known issues/FAQ

**Q**: SongRec does not work correctly with Easy Effects installed, whan can I do?

**A**: Unchecking "Process all input/output streams" in "Easy Effects > Preferences > Audio" should solve this issue.

See: https://github.com/marin-m/SongRec/issues/207 + https://github.com/wwmm/easyeffects/issues/4517

**Q**: What does "A backend-specific error has occurred: no node available" mean?

**A**: You have PulseAudio and PipeWire both installed on your Linux setup and they are conflicting. I recommend uninstalling PulseAudio and installing the compatibility layer packet called `pipewire-pulse` or `pipewire-pulseaudio`, depending on your distribution, instead.

See: https://github.com/marin-m/SongRec/issues/265 + https://github.com/RustAudio/cpal/issues/1170

## Contributing

Please follow the [GNOME Code of conduct](https://conduct.gnome.org/) when interacting within the boundaries of the project.

## Legal

This software is released under the [GNU GPL v3](https://www.gnu.org/licenses/gpl-3.0.html) license. It was created with the intent of providing interoperability between the remote Shazam services and Linux-based deskop systems.

Please note that in certain countries located outside of the European Union, especially the United States, software patents may apply.

