Update plugins
This commit is contained in:
33
Cargo.lock
generated
33
Cargo.lock
generated
@@ -242,6 +242,12 @@ dependencies = [
|
||||
"windows",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.8.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
|
||||
|
||||
[[package]]
|
||||
name = "dasp_sample"
|
||||
version = "0.11.0"
|
||||
@@ -694,6 +700,21 @@ version = "0.3.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c"
|
||||
|
||||
[[package]]
|
||||
name = "portable-atomic"
|
||||
version = "1.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f59e70c4aef1e55797c2e8fd94a4f2a973fc972cfde0e0b05f683667b0cd39dd"
|
||||
|
||||
[[package]]
|
||||
name = "portable-atomic-util"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507"
|
||||
dependencies = [
|
||||
"portable-atomic",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-crate"
|
||||
version = "3.4.0"
|
||||
@@ -737,6 +758,17 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ringbuf"
|
||||
version = "0.4.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fe47b720588c8702e34b5979cb3271a8b1842c7cb6f57408efa70c779363488c"
|
||||
dependencies = [
|
||||
"crossbeam-utils",
|
||||
"portable-atomic",
|
||||
"portable-atomic-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustversion"
|
||||
version = "1.0.22"
|
||||
@@ -951,6 +983,7 @@ dependencies = [
|
||||
"cpal",
|
||||
"jack",
|
||||
"pulseaudio",
|
||||
"ringbuf",
|
||||
"symphonia",
|
||||
]
|
||||
|
||||
|
||||
@@ -5,15 +5,15 @@ edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
clap = { version = "4.5.53", features = ["derive"] }
|
||||
jack = { version = "0.13.3", optional = true}
|
||||
jack = { version = "0.13.3" }
|
||||
pulseaudio = { version = "0.3.1", optional = true}
|
||||
alsa = { version = "0.10.0", optional = true}
|
||||
symphonia = { version = "0.5.5", features = ["mp3"] }
|
||||
coreaudio-rs = { version = "0.13.0", optional = true }
|
||||
cpal = { version = "0.16.0", optional = true }
|
||||
ringbuf = "0.4.8"
|
||||
|
||||
[features]
|
||||
jack = ["dep:jack"]
|
||||
pulseaudio = ["dep:pulseaudio"]
|
||||
alsa = ["dep:alsa"]
|
||||
coreaudio = ["dep:coreaudio-rs"]
|
||||
|
||||
116
src/main.rs
116
src/main.rs
@@ -1,7 +1,9 @@
|
||||
use std::{fs::File, path::PathBuf};
|
||||
|
||||
use clap::{Parser, Subcommand, ValueEnum};
|
||||
use jack::{AudioOut, Client, ClientOptions};
|
||||
use symphonia::core::{audio::{AudioBufferRef, SampleBuffer}, codecs::DecoderOptions, formats::FormatOptions, io::MediaSourceStream, meta::MetadataOptions, probe::Hint};
|
||||
use ringbuf::RingBuffer;
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum)]
|
||||
enum Backend {
|
||||
@@ -24,90 +26,76 @@ struct Cli {
|
||||
|
||||
fn main() {
|
||||
let cli = Cli::parse();
|
||||
// You can check the value provided by positional arguments, or option arguments
|
||||
// Read the track from the tracks into the buffer
|
||||
let mut data: Vec<f32>;
|
||||
if let Some(files) = cli.track {
|
||||
for file in files {
|
||||
data = read_audio_file(file);
|
||||
}
|
||||
}
|
||||
let (client, _status) = Client::new("rust_jack_simple", ClientOptions::default()).unwrap();
|
||||
let out_l = client.register_port("out_l", AudioOut::default()).unwrap();
|
||||
let out_r = client.register_port("out_r", AudioOut::default()).unwrap();
|
||||
let ring_l = RingBuffer::<f32>::new(48000 * 2);
|
||||
let ring_r = RingBuffer::<f32>::new(48000 * 2);
|
||||
let (prod_l, cons_l) = ring_l.split();
|
||||
let (prod_r, cons_r) = ring_r.split();
|
||||
|
||||
|
||||
if let Some(backend) = cli.backend {
|
||||
match backend {
|
||||
Backend::Jack => play_with_jack(),
|
||||
Backend::Jack => println!("jack"),
|
||||
Backend::Alsa => println!("alsa"),
|
||||
Backend::Pulseaudio => println!("pulse"),
|
||||
Backend::Coreaudio => println!("coreaudio"),
|
||||
Backend::Cpal => println!("cpal"),
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#[cfg(feature = "jack")]
|
||||
fn play_with_jack(data: Vec<f32>) {
|
||||
unimplemented!()
|
||||
}
|
||||
fn spawn_mp3_decoder(
|
||||
path: String,
|
||||
mut prod_l: ringbuf::Producer<f32>,
|
||||
mut prod_r: ringbuf::Producer<f32>,
|
||||
) {
|
||||
thread::spawn(move || {
|
||||
let file = File::open(path).expect("failed to open mp3");
|
||||
let mss = MediaSourceStream::new(Box::new(file), Default::default());
|
||||
|
||||
#[cfg(not(feature = "jack"))]
|
||||
fn play_with_jack(_: Vec<f32>) {
|
||||
unimplemented!()
|
||||
}
|
||||
let mut hint = Hint::new();
|
||||
hint.with_extension("mp3");
|
||||
|
||||
fn read_audio_file(path: String) -> Vec<f32>{
|
||||
// Open file
|
||||
let file = File::open(path).expect("Failed to open file");
|
||||
let mss = MediaSourceStream::new(Box::new(file), Default::default());
|
||||
let probed = symphonia::default::get_probe()
|
||||
.format(
|
||||
&hint,
|
||||
mss,
|
||||
&FormatOptions::default(),
|
||||
&MetadataOptions::default(),
|
||||
)
|
||||
.expect("format probe failed");
|
||||
|
||||
// Hint format by extension
|
||||
let mut hint = Hint::new();
|
||||
let mut format = probed.format;
|
||||
let track = format.default_track().unwrap();
|
||||
|
||||
// Probe the file
|
||||
let probed = symphonia::default::get_probe()
|
||||
.format(&hint, mss, &FormatOptions::default(), &MetadataOptions::default())
|
||||
.expect("Unsupported format");
|
||||
let mut decoder = symphonia::default::get_codecs()
|
||||
.make(&track.codec_params, &DecoderOptions::default())
|
||||
.unwrap();
|
||||
|
||||
let mut format = probed.format;
|
||||
let track = format.default_track().expect("No default track");
|
||||
let mut sample_buf: Option<SampleBuffer<f32>> = None;
|
||||
|
||||
let mut decoder = symphonia::default::get_codecs()
|
||||
.make(&track.codec_params, &DecoderOptions::default())
|
||||
.expect("Failed to create decoder");
|
||||
loop {
|
||||
let packet = match format.next_packet() {
|
||||
Ok(p) => p,
|
||||
Err(_) => break,
|
||||
};
|
||||
|
||||
let mut samples = Vec::new();
|
||||
let decoded = decoder.decode(&packet).unwrap();
|
||||
|
||||
// Temporary sample buffer for decoding
|
||||
let mut sample_buf = None;
|
||||
let buf = sample_buf.get_or_insert_with(|| {
|
||||
SampleBuffer::new(decoded.capacity() as u64, *decoded.spec())
|
||||
});
|
||||
|
||||
while let Ok(packet) = format.next_packet() {
|
||||
if packet.track_id() != track.id {
|
||||
continue;
|
||||
}
|
||||
buf.copy_interleaved_ref(decoded);
|
||||
|
||||
// Decode packet
|
||||
match decoder.decode(&packet) {
|
||||
Ok(audio_buf) => {
|
||||
// Create a f32 sample buffer if not already
|
||||
if sample_buf.is_none() {
|
||||
let spec = *audio_buf.spec();
|
||||
let capacity = audio_buf.capacity() as u64;
|
||||
sample_buf = Some(SampleBuffer::<f32>::new(capacity, spec));
|
||||
}
|
||||
|
||||
// Copy decoded data to f32 buffer
|
||||
if let Some(buf) = &mut sample_buf {
|
||||
buf.copy_interleaved_ref(audio_buf);
|
||||
samples.extend(buf.samples());
|
||||
}
|
||||
// Assume stereo
|
||||
for frame in buf.samples().chunks(2) {
|
||||
let _ = prod_l.push(frame[0]);
|
||||
let _ = prod_r.push(frame[1]);
|
||||
}
|
||||
Err(_) => continue,
|
||||
}
|
||||
}
|
||||
|
||||
samples
|
||||
}
|
||||
|
||||
pub struct DecodedAudio {
|
||||
pub samples: Vec<i16>, // interleaved
|
||||
pub sample_rate: u32,
|
||||
pub channels: u16,
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user