8 Commits

Author SHA1 Message Date
bl df06d7fa36 chore: Release spectrust version 0.2.4
Release / build (aarch64, aarch64, aarch64-unknown-linux-gnu) (push) Successful in 4m4s
Release / build (x86_64, ubuntu-latest, x86_64-unknown-linux-gnu) (push) Successful in 4m12s
Release / update-aur (push) Successful in 14s
2026-06-22 16:18:11 +02:00
bl af5a345458 add MIT LICENSE
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-22 16:17:53 +02:00
bl cf05f6a796 chore: Release spectrust version 0.2.3
Release / build (aarch64, aarch64, aarch64-unknown-linux-gnu) (push) Failing after 58s
Release / build (x86_64, ubuntu-latest, x86_64-unknown-linux-gnu) (push) Failing after 1m9s
Release / update-aur (push) Has been skipped
2026-06-22 16:05:22 +02:00
bl cce05dbfcc fix: remove ncurses dependency from PKGBUILD
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-22 16:02:59 +02:00
bl 70543e210a chore: Release spectrust version 0.2.2
Release / build (x86_64, ubuntu-latest, x86_64-unknown-linux-gnu) (push) Failing after 1m7s
Release / build (aarch64, aarch64, aarch64-unknown-linux-gnu) (push) Failing after 1m6s
Release / update-aur (push) Has been skipped
2026-06-22 16:01:58 +02:00
bl ccfb20f8bf fix: replace ncurses with crossterm to fix CI builds on both arches
ncurses-rs is broken on Arch Linux ARM (missing TRUE constant in
generated bindings) and the git HEAD version breaks Ubuntu too.
crossterm is pure Rust with no C dependency, eliminating the issue
on all platforms.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-22 16:01:36 +02:00
bl 0bb335e429 chore: Release spectrust version 0.2.1
Release / build (aarch64, aarch64, aarch64-unknown-linux-gnu) (push) Failing after 32s
Release / build (x86_64, ubuntu-latest, x86_64-unknown-linux-gnu) (push) Failing after 57s
Release / update-aur (push) Has been skipped
2026-06-22 15:20:45 +02:00
bl 754527d029 fix: patch ncurses via git to fix aarch64 build
ncurses-6.0.1 on crates.io uses a TRUE constant that Arch Linux ARM's
ncurses headers no longer define, breaking the rpi runner. Patch to git
HEAD which has the fix.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-22 15:20:20 +02:00
6 changed files with 385 additions and 102 deletions
-6
View File
@@ -25,12 +25,6 @@ jobs:
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Install system dependencies
if: matrix.arch == 'x86_64'
run: |
sudo apt-get update
sudo apt-get install -y libncurses-dev
- name: Install Rust stable - name: Install Rust stable
uses: dtolnay/rust-toolchain@stable uses: dtolnay/rust-toolchain@stable
with: with:
Generated
+271 -23
View File
@@ -38,7 +38,7 @@ version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c"
dependencies = [ dependencies = [
"windows-sys", "windows-sys 0.59.0",
] ]
[[package]] [[package]]
@@ -48,7 +48,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125"
dependencies = [ dependencies = [
"anstyle", "anstyle",
"windows-sys", "windows-sys 0.59.0",
] ]
[[package]] [[package]]
@@ -57,6 +57,12 @@ version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
[[package]]
name = "bitflags"
version = "2.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4388bee8683e3d04af747c73422af53102d2bd24d9eadb6cbc100baef4b43f8"
[[package]] [[package]]
name = "byteorder" name = "byteorder"
version = "1.5.0" version = "1.5.0"
@@ -64,13 +70,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
[[package]] [[package]]
name = "cc" name = "cfg-if"
version = "1.2.1" version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd9de9f2205d5ef3fd67e685b0df337994ddd4495e2a28d185500d0e1edfea47" checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
dependencies = [
"shlex",
]
[[package]] [[package]]
name = "clap" name = "clap"
@@ -118,6 +121,83 @@ version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
[[package]]
name = "convert_case"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "633458d4ef8c78b72454de2d54fd6ab2e60f9e02be22f3c6104cdc8a4e0fceb9"
dependencies = [
"unicode-segmentation",
]
[[package]]
name = "crossterm"
version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8b9f2e4c67f833b660cdb0a3523065869fb35570177239812ed4c905aeff87b"
dependencies = [
"bitflags",
"crossterm_winapi",
"derive_more",
"document-features",
"mio",
"parking_lot",
"rustix",
"signal-hook",
"signal-hook-mio",
"winapi",
]
[[package]]
name = "crossterm_winapi"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b"
dependencies = [
"winapi",
]
[[package]]
name = "derive_more"
version = "2.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134"
dependencies = [
"derive_more-impl",
]
[[package]]
name = "derive_more-impl"
version = "2.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb"
dependencies = [
"convert_case",
"proc-macro2",
"quote",
"rustc_version",
"syn",
]
[[package]]
name = "document-features"
version = "0.2.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4b8a88685455ed29a21542a33abd9cb6510b6b129abadabdcef0f4c55bc8f61"
dependencies = [
"litrs",
]
[[package]]
name = "errno"
version = "0.3.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
dependencies = [
"libc",
"windows-sys 0.59.0",
]
[[package]] [[package]]
name = "heck" name = "heck"
version = "0.5.0" version = "0.5.0"
@@ -132,19 +212,47 @@ checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.164" version = "0.2.186"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "433bfe06b8c75da9b2e3fbea6e5329ff87748f0b144ef75306e674c3f6f7c13f" checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66"
[[package]] [[package]]
name = "ncurses" name = "linux-raw-sys"
version = "6.0.1" version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fbd71afa95710e841d173521e8483e764004eb332bdf47bd01d00f568688027f" checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53"
[[package]]
name = "litrs"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092"
[[package]]
name = "lock_api"
version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965"
dependencies = [
"scopeguard",
]
[[package]]
name = "log"
version = "0.4.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad"
[[package]]
name = "mio"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02bd0af71c67b473010cbbc60715ee815645a4dc942899111f494b4b737d6fda"
dependencies = [ dependencies = [
"cc",
"libc", "libc",
"pkg-config", "log",
"wasi",
"windows-sys 0.61.2",
] ]
[[package]] [[package]]
@@ -175,10 +283,27 @@ dependencies = [
] ]
[[package]] [[package]]
name = "pkg-config" name = "parking_lot"
version = "0.3.31" version = "0.12.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a"
dependencies = [
"lock_api",
"parking_lot_core",
]
[[package]]
name = "parking_lot_core"
version = "0.9.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1"
dependencies = [
"cfg-if",
"libc",
"redox_syscall",
"smallvec",
"windows-link",
]
[[package]] [[package]]
name = "primal-check" name = "primal-check"
@@ -207,6 +332,24 @@ dependencies = [
"proc-macro2", "proc-macro2",
] ]
[[package]]
name = "redox_syscall"
version = "0.5.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d"
dependencies = [
"bitflags",
]
[[package]]
name = "rustc_version"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92"
dependencies = [
"semver",
]
[[package]] [[package]]
name = "rustfft" name = "rustfft"
version = "6.2.0" version = "6.2.0"
@@ -223,18 +366,74 @@ dependencies = [
] ]
[[package]] [[package]]
name = "shlex" name = "rustix"
version = "1.3.0" version = "1.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190"
dependencies = [
"bitflags",
"errno",
"libc",
"linux-raw-sys",
"windows-sys 0.59.0",
]
[[package]]
name = "scopeguard"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "semver"
version = "1.0.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd"
[[package]]
name = "signal-hook"
version = "0.3.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d881a16cf4426aa584979d30bd82cb33429027e42122b169753d6ef1085ed6e2"
dependencies = [
"libc",
"signal-hook-registry",
]
[[package]]
name = "signal-hook-mio"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b75a19a7a740b25bc7944bdee6172368f988763b744e3d4dfe753f6b4ece40cc"
dependencies = [
"libc",
"mio",
"signal-hook",
]
[[package]]
name = "signal-hook-registry"
version = "1.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b"
dependencies = [
"errno",
"libc",
]
[[package]]
name = "smallvec"
version = "1.15.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ed6a63f02c8539c91a8685a86f4099661ba3da017932f6ebbea6de3f0fa7c90"
[[package]] [[package]]
name = "spectrust" name = "spectrust"
version = "0.2.0" version = "0.2.4"
dependencies = [ dependencies = [
"byteorder", "byteorder",
"clap", "clap",
"ncurses", "crossterm",
"rustfft", "rustfft",
] ]
@@ -277,6 +476,12 @@ version = "1.0.13"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe"
[[package]]
name = "unicode-segmentation"
version = "1.13.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c6f5d3c3b1bf09027a88a6bc961fc00497d651009560b5463668dc81b0fa87a8"
[[package]] [[package]]
name = "utf8parse" name = "utf8parse"
version = "0.2.2" version = "0.2.2"
@@ -289,6 +494,40 @@ version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
[[package]]
name = "wasi"
version = "0.11.1+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows-link"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
[[package]] [[package]]
name = "windows-sys" name = "windows-sys"
version = "0.59.0" version = "0.59.0"
@@ -298,6 +537,15 @@ dependencies = [
"windows-targets", "windows-targets",
] ]
[[package]]
name = "windows-sys"
version = "0.61.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
dependencies = [
"windows-link",
]
[[package]] [[package]]
name = "windows-targets" name = "windows-targets"
version = "0.52.6" version = "0.52.6"
+2 -2
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "spectrust" name = "spectrust"
version = "0.2.0" version = "0.2.4"
edition = "2021" edition = "2021"
[profile.release] [profile.release]
@@ -10,5 +10,5 @@ codegen-units = 1
[dependencies] [dependencies]
byteorder = "1.5.0" byteorder = "1.5.0"
clap = { version = "4.5.21", features = ["derive"] } clap = { version = "4.5.21", features = ["derive"] }
ncurses = "6.0.1" crossterm = "0.29.0"
rustfft = "6.2.0" rustfft = "6.2.0"
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2024 Bendik Aagaard Lynghaug
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+3 -3
View File
@@ -1,12 +1,12 @@
# Maintainer: Bendik Aagaard Lynghaug <bendik.lynghaug@gmail.com> # Maintainer: Bendik Aagaard Lynghaug <bendik.lynghaug@gmail.com>
pkgname=spectrust pkgname=spectrust
pkgver=0.2.0 pkgver=0.2.4
pkgrel=1 pkgrel=1
pkgdesc="Terminal audio spectrum analyzer using ncurses" pkgdesc="Terminal audio spectrum analyzer"
arch=('x86_64' 'aarch64') arch=('x86_64' 'aarch64')
url="https://prosjekt.klingenbergbygg.no/bl/spectrust" url="https://prosjekt.klingenbergbygg.no/bl/spectrust"
license=('MIT') license=('MIT')
depends=('ncurses') depends=()
provides=('spectrust') provides=('spectrust')
conflicts=('spectrust-git' 'spectrust-bin') conflicts=('spectrust-git' 'spectrust-bin')
source_x86_64=("spectrust-v${pkgver}-x86_64.tar.gz::https://prosjekt.klingenbergbygg.no/bl/spectrust/releases/download/v${pkgver}/spectrust-v${pkgver}-x86_64.tar.gz") source_x86_64=("spectrust-v${pkgver}-x86_64.tar.gz::https://prosjekt.klingenbergbygg.no/bl/spectrust/releases/download/v${pkgver}/spectrust-v${pkgver}-x86_64.tar.gz")
+78 -58
View File
@@ -1,9 +1,17 @@
use clap::Parser; use clap::Parser;
use ncurses::*; use crossterm::{
use ncurses::{LcCategory, setlocale}; cursor::{Hide, MoveTo},
event::{self, Event, KeyCode, KeyEvent, KeyModifiers},
execute, queue,
style::Print,
terminal::{
self, Clear, ClearType, EnterAlternateScreen, LeaveAlternateScreen,
disable_raw_mode, enable_raw_mode,
},
};
use rustfft::{algorithm::Radix4, num_complex::Complex, Fft, FftDirection}; use rustfft::{algorithm::Radix4, num_complex::Complex, Fft, FftDirection};
use std::collections::VecDeque; use std::collections::VecDeque;
use std::io::{stdin, Read}; use std::io::{stdout, Read, Write};
use std::fs::File; use std::fs::File;
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
use byteorder::{LittleEndian, ReadBytesExt}; use byteorder::{LittleEndian, ReadBytesExt};
@@ -20,7 +28,7 @@ struct Cell {
} }
struct ViewDiff { struct ViewDiff {
changes: Vec<(i32, i32, char)>, changes: Vec<(u16, u16, char)>,
} }
impl ViewDiff { impl ViewDiff {
@@ -33,13 +41,13 @@ impl ViewDiff {
} }
fn add_change(&mut self, y: usize, x: usize, character: char) { fn add_change(&mut self, y: usize, x: usize, character: char) {
self.changes.push((y as i32, x as i32, character)); self.changes.push((y as u16, x as u16, character));
} }
fn apply(&self) { fn apply(&self) {
let mut buf = [0u8; 4]; let mut out = stdout();
for &(y, x, ch) in &self.changes { for &(y, x, ch) in &self.changes {
let _ = mvprintw(y, x, ch.encode_utf8(&mut buf)); let _ = queue!(out, MoveTo(x, y), Print(ch));
} }
} }
} }
@@ -56,14 +64,14 @@ fn render_bar(buf: &mut Vec<Vec<Cell>>, col: usize, sr: usize, bar_height_f: f32
} }
fn handle_terminal_resize( fn handle_terminal_resize(
rows: &mut i32, rows: &mut u16,
cols: &mut i32, cols: &mut u16,
new_rows: i32, new_rows: u16,
new_cols: i32, new_cols: u16,
max_width: i32, max_width: u16,
max_height: i32, max_height: u16,
safe_rows: &mut i32, safe_rows: &mut u16,
safe_cols: &mut i32, safe_cols: &mut u16,
current_buffer: &mut Vec<Vec<Cell>>, current_buffer: &mut Vec<Vec<Cell>>,
next_buffer: &mut Vec<Vec<Cell>>, next_buffer: &mut Vec<Vec<Cell>>,
last_bars: &mut Vec<f32>, last_bars: &mut Vec<f32>,
@@ -95,8 +103,9 @@ fn handle_terminal_resize(
freq_mapping.push(index.min(fft_size / 2 - 1)); freq_mapping.push(index.min(fft_size / 2 - 1));
} }
clear(); let mut out = stdout();
refresh(); let _ = queue!(out, Clear(ClearType::All));
let _ = out.flush();
} }
#[derive(Parser)] #[derive(Parser)]
@@ -129,16 +138,18 @@ struct Cli {
fn main() { fn main() {
let cli = Cli::parse(); let cli = Cli::parse();
let _ = setlocale(LcCategory::all, ""); enable_raw_mode().expect("failed to enable raw mode");
initscr(); let mut out = stdout();
noecho(); execute!(out, EnterAlternateScreen, Hide).expect("failed to initialize terminal");
curs_set(CURSOR_VISIBILITY::CURSOR_INVISIBLE);
keypad(stdscr(), true);
timeout(0);
let mut rows: i32 = 0; let default_hook = std::panic::take_hook();
let mut cols: i32 = 0; std::panic::set_hook(Box::new(move |info| {
getmaxyx(stdscr(), &mut rows, &mut cols); let _ = disable_raw_mode();
let _ = execute!(stdout(), LeaveAlternateScreen);
default_hook(info);
}));
let (mut cols, mut rows) = terminal::size().expect("failed to get terminal size");
let sample_rate: usize = 48000; let sample_rate: usize = 48000;
let bit_depth: usize = 16; let bit_depth: usize = 16;
@@ -161,26 +172,26 @@ fn main() {
PipeWire(std::process::ChildStdout), PipeWire(std::process::ChildStdout),
} }
refresh(); let _ = out.flush();
let mut audio_source = if cli.pipewire { let mut audio_source = if cli.pipewire {
let process = Command::new("pw-record") let process = Command::new("pw-record")
.args(["--format=s16", "--rate=48000", "--channels=2", "--raw", "-"]) .args(["--format=s16", "--rate=48000", "--channels=2", "--raw", "-"])
.stdout(Stdio::piped()) .stdout(Stdio::piped())
.spawn() .spawn()
.expect("Failed to start pw-record"); .expect("failed to start pw-record");
let stdout = process.stdout.expect("Failed to capture pw-record stdout"); let pipe = process.stdout.expect("failed to capture pw-record stdout");
refresh(); let _ = out.flush();
AudioSource::PipeWire(stdout) AudioSource::PipeWire(pipe)
} else if let Some(filename) = &cli.input { } else if let Some(filename) = &cli.input {
let file = File::open(filename).expect("Failed to open input file"); let file = File::open(filename).expect("failed to open input file");
AudioSource::File(file) AudioSource::File(file)
} else { } else {
AudioSource::StdIn(stdin().lock()) AudioSource::StdIn(std::io::stdin().lock())
}; };
let max_width = 1000; let max_width: u16 = 1000;
let max_height = 1000; let max_height: u16 = 1000;
let mut safe_cols = cols.min(max_width); let mut safe_cols = cols.min(max_width);
let mut safe_rows = rows.min(max_height); let mut safe_rows = rows.min(max_height);
@@ -215,10 +226,31 @@ fn main() {
let mut max_magnitude: f32 = 1.0; let mut max_magnitude: f32 = 1.0;
loop { loop {
if event::poll(Duration::ZERO).unwrap_or(false) {
match event::read() {
Ok(Event::Key(KeyEvent { code: KeyCode::Char('q'), .. })) => break,
Ok(Event::Key(KeyEvent {
code: KeyCode::Char('c'),
modifiers: KeyModifiers::CONTROL,
..
})) => break,
Ok(Event::Resize(new_cols, new_rows)) => {
handle_terminal_resize(
&mut rows, &mut cols, new_rows, new_cols,
max_width, max_height, &mut safe_rows, &mut safe_cols,
&mut current_buffer, &mut next_buffer,
&mut last_bars, &mut freq_bands, &mut freq_mapping,
cli.log_power, fft_size,
);
sc = safe_cols as usize;
sr = safe_rows as usize;
}
_ => {}
}
}
if last_terminal_resize.elapsed() >= resize_check_interval { if last_terminal_resize.elapsed() >= resize_check_interval {
let mut new_rows = 0; if let Ok((new_cols, new_rows)) = terminal::size() {
let mut new_cols = 0;
getmaxyx(stdscr(), &mut new_rows, &mut new_cols);
if new_rows != rows || new_cols != cols { if new_rows != rows || new_cols != cols {
handle_terminal_resize( handle_terminal_resize(
&mut rows, &mut cols, new_rows, new_cols, &mut rows, &mut cols, new_rows, new_cols,
@@ -230,23 +262,8 @@ fn main() {
sc = safe_cols as usize; sc = safe_cols as usize;
sr = safe_rows as usize; sr = safe_rows as usize;
} }
last_terminal_resize = Instant::now();
} }
last_terminal_resize = Instant::now();
let ch = getch();
if ch == KEY_RESIZE {
let mut new_rows = 0;
let mut new_cols = 0;
getmaxyx(stdscr(), &mut new_rows, &mut new_cols);
handle_terminal_resize(
&mut rows, &mut cols, new_rows, new_cols,
max_width, max_height, &mut safe_rows, &mut safe_cols,
&mut current_buffer, &mut next_buffer,
&mut last_bars, &mut freq_bands, &mut freq_mapping,
cli.log_power, fft_size,
);
sc = safe_cols as usize;
sr = safe_rows as usize;
} }
if last_frame_time.elapsed() >= interval { if last_frame_time.elapsed() >= interval {
@@ -261,7 +278,7 @@ fn main() {
let read_result = match &mut audio_source { let read_result = match &mut audio_source {
AudioSource::StdIn(input) => input.read(&mut input_buffer), AudioSource::StdIn(input) => input.read(&mut input_buffer),
AudioSource::File(file) => file.read(&mut input_buffer), AudioSource::File(file) => file.read(&mut input_buffer),
AudioSource::PipeWire(stdout) => stdout.read(&mut input_buffer), AudioSource::PipeWire(pipe) => pipe.read(&mut input_buffer),
}; };
match read_result { match read_result {
@@ -313,7 +330,7 @@ fn main() {
} }
view_diff.apply(); view_diff.apply();
std::mem::swap(&mut current_buffer, &mut next_buffer); std::mem::swap(&mut current_buffer, &mut next_buffer);
refresh(); let _ = out.flush();
break; break;
} }
} }
@@ -379,7 +396,7 @@ fn main() {
view_diff.apply(); view_diff.apply();
std::mem::swap(&mut current_buffer, &mut next_buffer); std::mem::swap(&mut current_buffer, &mut next_buffer);
last_frame_time = Instant::now(); last_frame_time = Instant::now();
refresh(); let _ = out.flush();
} else if buffer_is_empty { } else if buffer_is_empty {
for i in 0..sc { for i in 0..sc {
last_bars[i] *= drop_factor; last_bars[i] *= drop_factor;
@@ -397,8 +414,11 @@ fn main() {
view_diff.apply(); view_diff.apply();
std::mem::swap(&mut current_buffer, &mut next_buffer); std::mem::swap(&mut current_buffer, &mut next_buffer);
last_frame_time = Instant::now(); last_frame_time = Instant::now();
refresh(); let _ = out.flush();
} }
} }
} }
let _ = execute!(out, LeaveAlternateScreen);
let _ = disable_raw_mode();
} }