# SLAM Cross-Platform A cross-platform soundboard for CS2 and general voice chat apps (TeamSpeak, Discord, etc.). Play music and audio clips through your microphone (micspam) using a virtual audio cable. Works on Linux and Windows. This is a rewrite of [Skintillion/SLAM](https://github.com/Skintillion/SLAM) built with .NET 8 and Avalonia UI. ## How it works **CS2 mode**: SLAM writes CS2 config files that use `voice_device_override` to switch your active mic to a virtual audio cable when you play a sound, then switches back to your real mic when it stops. Other players hear it through your voice channel. **Stream to Mic mode**: Plays audio directly into a virtual microphone that any app (TeamSpeak, Discord, etc.) can use as a capture device. Your real mic is mixed in simultaneously so you can talk while sounds play. This does not inject into CS2 or modify game memory. It only writes `.cfg` files and routes system audio, which is VAC safe. ## Requirements ### Linux - .NET 8 SDK - ffmpeg - PipeWire with PulseAudio compatibility (pactl must be available) - yt-dlp (optional, for YouTube import) Install on Fedora/Nobara: ```bash sudo dnf install dotnet-sdk-8.0 ffmpeg ``` Install on Ubuntu/Debian: ```bash sudo apt install dotnet-sdk-8.0 ffmpeg ``` ### Windows - .NET 8 SDK or Runtime - ffmpeg on PATH - VB-Audio Virtual Cable or similar ## Linux audio setup This is the most involved part. You need a virtual audio sink that SLAM plays into, a virtual microphone source that apps like TeamSpeak can capture from, and a loopback so your real voice is mixed in alongside the soundboard audio. ### 1. Create the virtual devices (persistent) Create `~/.config/pipewire/pipewire-pulse.conf.d/virtual-mic.conf` with: ``` context.exec = [ { path = "pactl" args = "load-module module-null-sink sink_name=VirtualMic sink_properties=device.description=VirtualMic" } { path = "pactl" args = "load-module module-virtual-source source_name=VirtualMicInput master=VirtualMic.monitor source_properties=device.description=VirtualMicInput" } ] ``` This creates: - `VirtualMic` -- a virtual sink SLAM plays audio into - `VirtualMicInput` -- a virtual microphone source apps like TeamSpeak see as a capture device To apply without rebooting: ```bash mkdir -p ~/.config/pipewire/pipewire-pulse.conf.d # (create the file above, then:) systemctl --user restart pipewire-pulse ``` ### 2. Route your real mic into VirtualMic (optional but recommended) Without this step, only soundboard audio goes through VirtualMic. With it, your voice and the soundboard are mixed together so you can talk and stream sounds at the same time. Create a systemd user service at `~/.config/systemd/user/slam-mic-loopback.service`: ```ini [Unit] Description=SLAM mic loopback (your mic -> VirtualMic) After=pipewire.service pipewire-pulse.service BindsTo=pipewire.service [Service] ExecStartPre=/bin/bash -c 'until pactl list sinks short | grep -q VirtualMic; do sleep 0.5; done' ExecStart=/bin/bash -c 'pacat --record \ --device=YOUR_MIC_PACTL_ID \ --channels=2 --format=s32le --rate=48000 \ --latency-msec=20 --process-time-msec=10 \ --stream-name=slam-mic-loopback | \ pacat --playback \ --device=VirtualMic \ --channels=2 --format=s32le --rate=48000 \ --latency-msec=20 --process-time-msec=10 \ --stream-name=slam-mic-loopback' Restart=on-failure RestartSec=2 [Install] WantedBy=default.target ``` Replace `YOUR_MIC_PACTL_ID` with your microphone's pactl name. Find it with: ```bash pactl list sources | grep -E "Name:|Description:" | grep -v monitor ``` Enable and start it: ```bash systemctl --user daemon-reload systemctl --user enable --now slam-mic-loopback.service ``` ### 3. Configure TeamSpeak (or Discord, etc.) In TeamSpeak 3: Settings -> Options -> Capture -> set Capture Device to **VirtualMicInput**. In TeamSpeak 5: Settings -> Audio -> Microphone -> select **VirtualMicInput**. Restart the app after creating VirtualMicInput so the device list refreshes. ## Building and running Clone the repo and run from the `SLAM-Cross` directory: ```bash cd SLAM-Cross dotnet run ``` To build a release binary: ```bash dotnet publish -c Release -r linux-x64 --self-contained ``` The output will be in `bin/Release/net8.0/linux-x64/publish/`. ## First-time setup in the app 1. Launch the app. 2. In the three dropdowns at the top, select your audio devices: - **Virtual Cable In**: the sink you play audio into (`VirtualMic` on Linux, CABLE Input on Windows) - **Cable Out (mic)**: the monitor source CS2 uses as your mic (`Monitor of VirtualMic` on Linux) - **Regular Mic**: your actual microphone to switch back to after sounds finish 3. Click **Import Files** to add audio files. Supported formats: mp3, wav, aac, flac, ogg, m4a, mp4, and others supported by ffmpeg. ## CS2 usage 1. Click **Start**. SLAM will search for your CS2 installation. 2. In CS2, open the console and type `exec slam`. 3. Use the relay key (default `=`) to select a track by number or tag, then press the play key (default `MOUSE4`) to play it. Example: type `3` in console, press `MOUSE4` to play track 3. Type `slam_listtracks` to see all tracks. ## Stream to Mic (TeamSpeak, Discord, etc.) Select a track in the list and click **Stream to Mic**. The audio plays directly into VirtualMic without needing CS2. If you set up the mic loopback service above, your voice is mixed in simultaneously. Click **Stream to Mic** again (it becomes a stop button while streaming) or double-click another track to switch. ## CS2 console commands written by SLAM | Command | What it does | |---|---| | `exec slam` | Loads all SLAM binds | | `slam_listtracks` | Prints track list to console | | `slam_play` | Toggle play/stop | | `slam_curtrack` | Echoes the current track name | | `slam_saycurtrack` | Says current track name in chat | | `slam_sayteamcurtrack` | Says current track name in team chat | ## Settings Click the **Settings** button to configure: - **Start polling on launch**: automatically start when the app opens - **Hold key to play**: hold the play key instead of toggling - **Relay key**: the key CS2 uses to pass track selection back to SLAM (default `=`) - **Override Steam folder detection**: manually set your steamapps and userdata paths if auto-detection fails Settings are saved to `~/.config/SLAM/settings.json` on Linux or `%AppData%\SLAM\settings.json` on Windows. ## Track management Right-click any track in the list for options: - **Play**: stream the track immediately (works in both CS2 mode and standalone) - **Set Hotkey**: bind a keyboard key to load this track directly - **Set Volume**: adjust playback volume (1-100) - **Trim**: set start and end points - **Rename**: rename the track file - **Show in Files**: open the track's folder in your file manager - **Delete**: remove the track file ## YouTube import Click **Import from YouTube**. Requires `yt-dlp` installed and on your PATH. Install yt-dlp: ```bash pip install yt-dlp ``` Or on Fedora: ```bash sudo dnf install yt-dlp ``` ## Troubleshooting **SLAM is stuck on "Searching..."** CS2 is not running, or auto-detection failed. Enable "Override Steam folder detection" in Settings and set the paths manually. On Linux the steamapps path is typically `~/.local/share/Steam/steamapps` and userdata is `~/.local/share/Steam/userdata`. **Audio goes to the wrong device or does not reach TeamSpeak** Make sure VirtualMicInput appears in TeamSpeak's device list. If it was created after TeamSpeak was already open, restart TeamSpeak. Also verify the Virtual Cable In dropdown in SLAM is set to `VirtualMic`. **Mic loopback has too much delay** Lower the `--latency-msec` values in the service file (e.g. `10` instead of `20`). If you get crackling, increase them slightly. **Mic loopback crackles** Increase `--latency-msec` in the service file. Values between 20 and 50 are usually stable. **No audio reaches other players in CS2** Make sure the Cable Out (mic) dropdown matches what CS2 uses for voice. On Linux this is typically `Monitor of VirtualMic`. The device name must match what CS2 reports in `voice_device_override`. **Sounds play but cut off immediately** The virtual sink may be suspending due to inactivity. Keep it alive with: ```bash paplay --device=VirtualMic /dev/zero & ``` **Audio distortion or wrong speed** The app converts files to 22050 Hz mono WAV before playback. If conversion fails, check that ffmpeg is installed with `ffmpeg -version`. **errorlog.txt** If "Log errors to errorlog.txt" is enabled in settings, errors are written to `errorlog.txt` in the directory you run the app from.