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