audio input and fft
All checks were successful
Build legacy Nix package on Ubuntu / build (push) Successful in 4m17s
All checks were successful
Build legacy Nix package on Ubuntu / build (push) Successful in 4m17s
This commit is contained in:
parent
33907234fd
commit
86dfbd21f4
1247
Cargo.lock
generated
1247
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@ -8,3 +8,9 @@ pedantic = "warn"
|
|||||||
nursery = "warn"
|
nursery = "warn"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
env_logger = "0.11"
|
||||||
|
log = "0.4"
|
||||||
|
color-eyre = "0.6"
|
||||||
|
|
||||||
|
cpal = { version = "0.15", features = ["jack"] }
|
||||||
|
rustfft = "6.2"
|
||||||
|
17
default.nix
17
default.nix
@ -1,7 +1,10 @@
|
|||||||
(import (
|
(import
|
||||||
fetchTarball {
|
(
|
||||||
url = "https://github.com/edolstra/flake-compat/archive/99f1c2157fba4bfe6211a321fd0ee43199025dbf.tar.gz";
|
fetchTarball {
|
||||||
sha256 = "0x2jn3vrawwv9xp15674wjz9pixwjyj3j771izayl962zziivbx2"; }
|
url = "https://github.com/edolstra/flake-compat/archive/99f1c2157fba4bfe6211a321fd0ee43199025dbf.tar.gz";
|
||||||
) {
|
sha256 = "0x2jn3vrawwv9xp15674wjz9pixwjyj3j771izayl962zziivbx2";
|
||||||
src = ./.;
|
}
|
||||||
}).defaultNix
|
)
|
||||||
|
{
|
||||||
|
src = ./.;
|
||||||
|
}).defaultNix
|
||||||
|
@ -12,9 +12,13 @@
|
|||||||
naersk-lib = pkgs.callPackage naersk { };
|
naersk-lib = pkgs.callPackage naersk { };
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
defaultPackage = naersk-lib.buildPackage ./.;
|
defaultPackage = naersk-lib.buildPackage {
|
||||||
|
src = ./.;
|
||||||
|
buildInputs = with pkgs; [ alsa-lib libjack2 ];
|
||||||
|
nativeBuildInputs = with pkgs; [ pkg-config ];
|
||||||
|
};
|
||||||
devShell = with pkgs; mkShell {
|
devShell = with pkgs; mkShell {
|
||||||
buildInputs = [ cargo rustc rustfmt pre-commit rustPackages.clippy ];
|
buildInputs = [ cargo rustc rustfmt pre-commit rustPackages.clippy alsa-lib pipewire ];
|
||||||
RUST_SRC_PATH = rustPlatform.rustLibSrc;
|
RUST_SRC_PATH = rustPlatform.rustLibSrc;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
68
src/main.rs
68
src/main.rs
@ -1,3 +1,67 @@
|
|||||||
fn main() {
|
use std::{thread::sleep, time::Duration};
|
||||||
println!("Hello, world!");
|
|
||||||
|
use color_eyre::eyre::bail;
|
||||||
|
use cpal::{
|
||||||
|
traits::{DeviceTrait, HostTrait, StreamTrait},
|
||||||
|
BufferSize, HostId, SupportedBufferSize,
|
||||||
|
};
|
||||||
|
use log::{debug, error, info, trace};
|
||||||
|
use rustfft::{num_complex::Complex, FftPlanner};
|
||||||
|
|
||||||
|
fn main() -> color_eyre::Result<()> {
|
||||||
|
env_logger::init();
|
||||||
|
debug!("Starting");
|
||||||
|
|
||||||
|
let mut hosts = cpal::platform::available_hosts();
|
||||||
|
hosts.sort_unstable_by_key(|host| match host {
|
||||||
|
HostId::Jack => 0,
|
||||||
|
HostId::Alsa => 1,
|
||||||
|
});
|
||||||
|
let host_id = hosts[0];
|
||||||
|
info!("Selected {host_id:?} audio backend");
|
||||||
|
let host = cpal::platform::host_from_id(host_id)?;
|
||||||
|
|
||||||
|
let Some(device) = host.default_input_device() else {
|
||||||
|
error!("Unable to get default input device for {host_id:?}");
|
||||||
|
bail!("Unable to get default input device")
|
||||||
|
};
|
||||||
|
debug!("Got default input device {:?}", device.name());
|
||||||
|
|
||||||
|
let default_config = device.default_input_config()?;
|
||||||
|
trace!("Default config {:?}", default_config);
|
||||||
|
let mut config = default_config.config();
|
||||||
|
let buffer_size =
|
||||||
|
if let SupportedBufferSize::Range { min, max: _ } = default_config.buffer_size() {
|
||||||
|
*min
|
||||||
|
} else {
|
||||||
|
1024
|
||||||
|
};
|
||||||
|
config.buffer_size = BufferSize::Fixed(buffer_size);
|
||||||
|
config.channels = 1;
|
||||||
|
debug!("Using config {config:?}");
|
||||||
|
|
||||||
|
let mut planner = FftPlanner::<f32>::new();
|
||||||
|
let fft = planner.plan_fft_forward(buffer_size as usize);
|
||||||
|
let mut fft_data = vec![Complex::new(0.0, 0.0); buffer_size as usize];
|
||||||
|
let mut fft_scratch = vec![Complex::new(0.0, 0.0); buffer_size as usize];
|
||||||
|
|
||||||
|
let stream = device.build_input_stream(
|
||||||
|
&config,
|
||||||
|
move |data: &[f32], _| {
|
||||||
|
for i in 0..data.len() {
|
||||||
|
fft_data[i] = Complex::new(data[i], 0.0);
|
||||||
|
}
|
||||||
|
fft.process_with_scratch(&mut fft_data[..], &mut fft_scratch[..]);
|
||||||
|
},
|
||||||
|
|err| {
|
||||||
|
error!("input stream error: {err}");
|
||||||
|
},
|
||||||
|
None,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
stream.play()?;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
sleep(Duration::from_secs(1));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user