Commit d667a217 authored by Pierre Donat-Bouillud's avatar Pierre Donat-Bouillud
Browse files

Formatting

parent 820b8448
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
name = "ansi_term"
version = "0.11.0"
......
......@@ -7,99 +7,127 @@ extern crate audio_adaptive;
extern crate rand;
use rand::prelude::*;
use rand::distributions::Uniform;
use rand::prelude::*;
use audio_adaptive::audiograph::*;
use audio_adaptive::samplerate;
fn osc_bench(c : &mut Criterion) {
fn osc_bench(c: &mut Criterion) {
let mut rng = SmallRng::seed_from_u64(345987);
let unity_interval = Uniform::new_inclusive(-1.,1.);
c.bench_function_over_inputs("osc", move |b: &mut Bencher, n: &usize| {
let mut osc = Oscillator::new(0., 440, 1.);
let mut input = vec![DspEdge::new(1, 1, *n, 44100);1];
//let size = input[0].buffer().len();
input[0].buffer_mut().copy_from_slice(&rng.sample_iter(&unity_interval).take(*n).collect::<Vec<f32>>());
b.iter( ||
{
let mut output = vec![DspEdge::new(1, 1, *n, 44100);1];
osc.process(&input, &mut output)}
)},
vec![64, 128,256,512,1024,2048,4096]);
let unity_interval = Uniform::new_inclusive(-1., 1.);
c.bench_function_over_inputs(
"osc",
move |b: &mut Bencher, n: &usize| {
let mut osc = Oscillator::new(0., 440, 1.);
let mut input = vec![DspEdge::new(1, 1, *n, 44100); 1];
//let size = input[0].buffer().len();
input[0].buffer_mut().copy_from_slice(
&rng.sample_iter(&unity_interval)
.take(*n)
.collect::<Vec<f32>>(),
);
b.iter(|| {
let mut output = vec![DspEdge::new(1, 1, *n, 44100); 1];
osc.process(&input, &mut output)
})
},
vec![64, 128, 256, 512, 1024, 2048, 4096],
);
}
fn mod_bench(c : &mut Criterion) {
fn mod_bench(c: &mut Criterion) {
let mut rng = SmallRng::seed_from_u64(345987);
let unity_interval = Uniform::new_inclusive(-1.,1.);
c.bench_function_over_inputs("mod", move |b: &mut Bencher, n: &usize| {
let mut modu = Modulator::new(0., 440, 1.);
let mut input = vec![DspEdge::new(1, 1, *n, 44100);1];
//let size = input[0].buffer().len();
input[0].buffer_mut().copy_from_slice(&rng.sample_iter(&unity_interval).take(*n).collect::<Vec<f32>>());
b.iter( ||
{
let mut output = vec![DspEdge::new(1, 1, *n, 44100);1];
modu.process(&input, &mut output)}
)},
vec![64, 128,256,512,1024,2048,4096]);
let unity_interval = Uniform::new_inclusive(-1., 1.);
c.bench_function_over_inputs(
"mod",
move |b: &mut Bencher, n: &usize| {
let mut modu = Modulator::new(0., 440, 1.);
let mut input = vec![DspEdge::new(1, 1, *n, 44100); 1];
//let size = input[0].buffer().len();
input[0].buffer_mut().copy_from_slice(
&rng.sample_iter(&unity_interval)
.take(*n)
.collect::<Vec<f32>>(),
);
b.iter(|| {
let mut output = vec![DspEdge::new(1, 1, *n, 44100); 1];
modu.process(&input, &mut output)
})
},
vec![64, 128, 256, 512, 1024, 2048, 4096],
);
}
fn resampler_bench(c : &mut Criterion) {
let parameters = vec![samplerate::ConverterType::SincBestQuality, samplerate::ConverterType::SincMediumQuality,
samplerate::ConverterType::SincFastest, samplerate::ConverterType::ZeroOrderHold,
samplerate::ConverterType::Linear];
fn resampler_bench(c: &mut Criterion) {
let parameters = vec![
samplerate::ConverterType::SincBestQuality,
samplerate::ConverterType::SincMediumQuality,
samplerate::ConverterType::SincFastest,
samplerate::ConverterType::ZeroOrderHold,
samplerate::ConverterType::Linear,
];
let mut rng = SmallRng::seed_from_u64(345987);
let unity_interval = Uniform::new_inclusive(-1.,1.);
let unity_interval = Uniform::new_inclusive(-1., 1.);
c.bench(
"resampler",
ParameterizedBenchmark::new(
"resampler",
move |b, conv_type| {
let mut conv = Resampler::new(conv_type.clone(), 0.5);
let mut input = vec![DspEdge::new(1, 1, 256, 44100);1];
let mut input = vec![DspEdge::new(1, 1, 256, 44100); 1];
let size = input[0].buffer().len();
input[0].buffer_mut().copy_from_slice(&rng.sample_iter(&unity_interval).take(size).collect::<Vec<f32>>());
input[0].buffer_mut().copy_from_slice(
&rng.sample_iter(&unity_interval)
.take(size)
.collect::<Vec<f32>>(),
);
b.iter(|| {
let mut output = vec![DspEdge::new(1, 1, 128, 44100);1];
let mut output = vec![DspEdge::new(1, 1, 128, 44100); 1];
conv.process(&input, &mut output)
})},
parameters
)
})
},
parameters,
),
);
}
fn mixer_bench(c : &mut Criterion) {
fn mixer_bench(c: &mut Criterion) {
let n = 6;
let mut parameters = Vec::with_capacity(n*n);
let mut parameters = Vec::with_capacity(n * n);
for i in 1..n {
for j in 1..n {
if i % j == 0 || j % i == 0 {parameters.push((j,i));}
if i % j == 0 || j % i == 0 {
parameters.push((j, i));
}
}
}
let mut rng = SmallRng::seed_from_u64(345987);
let unity_interval = Uniform::new_inclusive(-1.,1.);
let unity_interval = Uniform::new_inclusive(-1., 1.);
c.bench(
"mixer",
ParameterizedBenchmark::new(
"mixer",
move |b, (nb_inlets, nb_outlets)| {
let mut conv = InputsOutputsAdaptor::new(*nb_inlets, *nb_outlets);
let mut inputs = vec![DspEdge::new(1, 1, 256, 44100);*nb_inlets];
let mut inputs = vec![DspEdge::new(1, 1, 256, 44100); *nb_inlets];
let size = inputs[0].buffer().len();
for input in inputs.iter_mut() {
input.buffer_mut().copy_from_slice(&rng.sample_iter(&unity_interval).take(size).collect::<Vec<f32>>());
input.buffer_mut().copy_from_slice(
&rng.sample_iter(&unity_interval)
.take(size)
.collect::<Vec<f32>>(),
);
}
b.iter(|| {
let mut outputs = vec![DspEdge::new(1, 1, 256, 44100);*nb_outlets];
let mut outputs = vec![DspEdge::new(1, 1, 256, 44100); *nb_outlets];
conv.process(&inputs, &mut outputs)
})},
parameters
)
})
},
parameters,
),
);
}
criterion_group!(benches, osc_bench, mod_bench, resampler_bench, mixer_bench);
criterion_main!(benches);
//! ALl the stuff related to audio, audio callback, portaudio, monitoring the callback
use portaudio as pa;
use std::sync::mpsc;
use std::error::Error;
use time::{PreciseTime, Duration};
use std::path::Path;
use std::sync::mpsc;
use std::thread;
use time::{Duration, PreciseTime};
use audio_adaptive::sndfile::*;
use audio_adaptive::samplerate::*;
use audio_adaptive::sndfile::*;
use std::io::prelude::*;
use std::fs::File;
use std::io::prelude::*;
use std;
const FRAMES_PER_BUFFER : u32 = 64;
const UP_RATIO : f64 = 2.;
const FRAMES_PER_BUFFER: u32 = 64;
const UP_RATIO: f64 = 2.;
lazy_static! {
static ref PORTAUDIO: pa::PortAudio = {
let pa = pa::PortAudio::new()
.expect("PortAudio construction shouldn't fail.");
let pa = pa::PortAudio::new().expect("PortAudio construction shouldn't fail.");
println!("PortAudio is initialized.");
pa
};
}
#[derive(Debug)]
struct TimeMonitoring {
pub current_invocation : f64,//When the audio callback is invoked (in s)
pub buffer_dac : f64, // when the first sample of the output buffer will be send to the DAC (in s)
pub audio_processing : Duration,//duration between beginning of callback and when the audio processing has been finished in the audio callback
pub ratio : f64,//Resampling ratio
pub current_invocation: f64, //When the audio callback is invoked (in s)
pub buffer_dac: f64, // when the first sample of the output buffer will be send to the DAC (in s)
pub audio_processing: Duration, //duration between beginning of callback and when the audio processing has been finished in the audio callback
pub ratio: f64, //Resampling ratio
}
pub struct AudioEngine{
pub stream : pa::stream::Stream<pa::stream::NonBlocking, pa::stream::Output<f32>>,
pub control_sender : mpsc::Sender<f64>,
pub struct AudioEngine {
pub stream: pa::stream::Stream<pa::stream::NonBlocking, pa::stream::Output<f32>>,
pub control_sender: mpsc::Sender<f64>,
}
impl AudioEngine {
pub fn new<T : AsRef<Path> >(path: T) -> Result<AudioEngine, pa::Error> {
pub fn new<T: AsRef<Path>>(path: T) -> Result<AudioEngine, pa::Error> {
/*
* Load samples
*/
......@@ -58,74 +52,107 @@ impl AudioEngine {
let audiostream = sndfile.readf_float_all();
println!("Simple test of sound nodes with tradeoff between quality and deadlines.");
println!("Number of samples x number of channels = {}", audiostream.len());
println!(
"Number of samples x number of channels = {}",
audiostream.len()
);
/*
* Playback with portaudio
*/
//Thread to monitor the audio callback
let (tx_monit_exec, rx_monit_exec) = mpsc::channel::<TimeMonitoring>();
//Thread to monitor the audio callback
let (tx_monit_exec, rx_monit_exec) = mpsc::channel::<TimeMonitoring>();
thread::spawn(move || {
let mut f = File::create("execution_audio").expect("Impossible to report execution times");
thread::spawn(move || {
let mut f =
File::create("execution_audio").expect("Impossible to report execution times");
f.write_all(b"CurrentInvocation\tBufferDac\tAudioProcNS\tRatio\n").unwrap();
f.write_all(b"CurrentInvocation\tBufferDac\tAudioProcNS\tRatio\n")
.unwrap();
for monitoring_infos in rx_monit_exec.iter() {
let duration : Duration = monitoring_infos.audio_processing;
let seria = format!("{}\t{}\t{}\t{}\n", monitoring_infos.current_invocation,
monitoring_infos.buffer_dac, duration.num_nanoseconds().unwrap(),
monitoring_infos.ratio);
f.write_all(seria.as_bytes()).unwrap();
let duration: Duration = monitoring_infos.audio_processing;
let seria = format!(
"{}\t{}\t{}\t{}\n",
monitoring_infos.current_invocation,
monitoring_infos.buffer_dac,
duration.num_nanoseconds().unwrap(),
monitoring_infos.ratio
);
f.write_all(seria.as_bytes()).unwrap();
}
println!("End monitoring execution times because {:?}", rx_monit_exec.recv().unwrap_err().description());
});
//Audio callback and audio callback communication
let ( tx, rx) = mpsc::channel();
let mut up_ratio = UP_RATIO;
let mut chunk_it = 0;
//Resampling apparatus...
let mut nb_samples_interm = nb_channels as usize * FRAMES_PER_BUFFER as usize * up_ratio as usize;
let mut upsampler = SmartResampler::new(ConverterType::Linear, nb_channels as u32, up_ratio, nb_samples_interm * 20);
let mut downsampler = SmartResampler::new(ConverterType::Linear, nb_channels as u32, 1. / up_ratio, nb_samples_interm * 10);
let mut interm_buffer = vec![0.;nb_samples_interm];
interm_buffer.reserve(nb_channels as usize * FRAMES_PER_BUFFER as usize * std::cmp::max(20, UP_RATIO as usize));
let callback = move |pa::OutputStreamCallbackArgs {buffer, frames, time, ..}| {
let start = PreciseTime::now();
while let Ok(val) = rx.try_recv() {
up_ratio = val;
}
//New ratio so resize buffer and change resampling ratios
nb_samples_interm = (nb_channels as f64 * FRAMES_PER_BUFFER as f64 * up_ratio).ceil() as usize;
//println!("New interm buffer size: {}", nb_samples_interm);
interm_buffer.resize(nb_samples_interm, 0.);//It shoudn't reallocate memory as we have reserved enough before starting the audio thread
upsampler.set_src_ratio(up_ratio);
downsampler.set_src_ratio_hard(1. / up_ratio);
//The problem with set_src_ratio is that it is going to try to transition smoothly to the
// new ratio, not yielding the righ number of samples.
let nb_samples = frames * nb_channels;
/*
* frame of size 3 with 3 channels. Nb samples is 9
* ||ch1|ch2|ch3||ch1|ch2|ch3||ch1|ch2|ch3||
*/
if chunk_it < audiostream.len() {
let input_buffer = &audiostream[chunk_it..std::cmp::min(chunk_it+ nb_samples, audiostream.len())];
println!(
"End monitoring execution times because {:?}",
rx_monit_exec.recv().unwrap_err().description()
);
});
//Audio callback and audio callback communication
let (tx, rx) = mpsc::channel();
let mut up_ratio = UP_RATIO;
let mut chunk_it = 0;
//Resampling apparatus...
let mut nb_samples_interm =
nb_channels as usize * FRAMES_PER_BUFFER as usize * up_ratio as usize;
let mut upsampler = SmartResampler::new(
ConverterType::Linear,
nb_channels as u32,
up_ratio,
nb_samples_interm * 20,
);
let mut downsampler = SmartResampler::new(
ConverterType::Linear,
nb_channels as u32,
1. / up_ratio,
nb_samples_interm * 10,
);
let mut interm_buffer = vec![0.; nb_samples_interm];
interm_buffer.reserve(
nb_channels as usize
* FRAMES_PER_BUFFER as usize
* std::cmp::max(20, UP_RATIO as usize),
);
let callback = move |pa::OutputStreamCallbackArgs {
buffer,
frames,
time,
..
}| {
let start = PreciseTime::now();
while let Ok(val) = rx.try_recv() {
up_ratio = val;
}
//New ratio so resize buffer and change resampling ratios
nb_samples_interm =
(nb_channels as f64 * FRAMES_PER_BUFFER as f64 * up_ratio).ceil() as usize;
//println!("New interm buffer size: {}", nb_samples_interm);
interm_buffer.resize(nb_samples_interm, 0.); //It shoudn't reallocate memory as we have reserved enough before starting the audio thread
upsampler.set_src_ratio(up_ratio);
downsampler.set_src_ratio_hard(1. / up_ratio);
//The problem with set_src_ratio is that it is going to try to transition smoothly to the
// new ratio, not yielding the righ number of samples.
let nb_samples = frames * nb_channels;
/*
* frame of size 3 with 3 channels. Nb samples is 9
* ||ch1|ch2|ch3||ch1|ch2|ch3||ch1|ch2|ch3||
*/
if chunk_it < audiostream.len() {
let input_buffer =
&audiostream[chunk_it..std::cmp::min(chunk_it + nb_samples, audiostream.len())];
//chunk_it+ nb_samples = audiostream.len() at the end, normally (TODO: to check)
//upsample
upsampler.resample(input_buffer, &mut interm_buffer[..]).unwrap();
upsampler
.resample(input_buffer, &mut interm_buffer[..])
.unwrap();
//Do some processing
//buffer.clone_from_slice(&audiostream[chunk_it..std::cmp::min(chunk_it+ nb_samples, audiostream.len())]);
......@@ -135,39 +162,51 @@ impl AudioEngine {
//
//downsample
downsampler.resample(&interm_buffer[..], &mut buffer[..]).unwrap();
downsampler
.resample(&interm_buffer[..], &mut buffer[..])
.unwrap();
//Send monitoring infos
let duration = start.to(PreciseTime::now());
tx_monit_exec.send(TimeMonitoring {
current_invocation : time.current,
buffer_dac : time.buffer_dac,
audio_processing : duration,
ratio : up_ratio,
}).unwrap();
tx_monit_exec
.send(TimeMonitoring {
current_invocation: time.current,
buffer_dac: time.buffer_dac,
audio_processing: duration,
ratio: up_ratio,
})
.unwrap();
chunk_it += nb_samples;
pa::Continue
}
else {
} else {
upsampler.next_buffer_last();
pa::Complete
}
};
//Init portaudio and stream
//Show default API:
println!("{:?}", PORTAUDIO.host_api_info(PORTAUDIO.default_host_api().unwrap()).unwrap());
let settings = try!(PORTAUDIO.default_output_stream_settings(nb_channels as i32, samplerate, nb_frames));
let mut stream = try!(PORTAUDIO.open_non_blocking_stream(settings, callback));
try!(stream.start());
Ok(AudioEngine {
stream : stream,
control_sender : tx,
})
};
//Init portaudio and stream
//Show default API:
println!(
"{:?}",
PORTAUDIO
.host_api_info(PORTAUDIO.default_host_api().unwrap())
.unwrap()
);
let settings = try!(PORTAUDIO.default_output_stream_settings(
nb_channels as i32,
samplerate,
nb_frames
));
let mut stream = try!(PORTAUDIO.open_non_blocking_stream(settings, callback));
try!(stream.start());
Ok(AudioEngine {
stream: stream,
control_sender: tx,
})
}
}
......
This diff is collapsed.
//! Execute an audiograph file and report stats about it.
extern crate audio_adaptive;
extern crate clap;
extern crate crossbeam_channel;
extern crate portaudio;
extern crate rand;
extern crate time;
extern crate crossbeam_channel;
extern crate clap;
use portaudio as pa;
use crossbeam_channel::unbounded;
use portaudio as pa;
use std::env;
use std::thread;
use std::time as rust_time;//To be used for thread::sleep for instance
use std::process::exit;
use std::thread;
use std::time as rust_time; //To be used for thread::sleep for instance
use time::{PreciseTime, Duration};
use time::{Duration, PreciseTime};
use std::io::prelude::*;
use std::ffi::OsStr;
use std::fs::File;
use std::io::prelude::*;
use std::path::Path;
use std::ffi::OsStr;
use clap::{Arg, App, ArgGroup};
use clap::{App, Arg, ArgGroup};
use audio_adaptive::audiograph::*;
use audio_adaptive::audiograph_parser::*;
use audio_adaptive::sndfile;
use rand::prelude::*;
use rand::distributions::Uniform;
use rand::prelude::*;
const CHANNELS: i32 = 1;
const SAMPLE_RATE: u32 = 44_100;
const NB_CYCLES : u32 = 12000;
const FRAMES_PER_BUFFER : usize = 512;
const NB_CYCLES: u32 = 12000;
const FRAMES_PER_BUFFER: usize = 512;
#[derive(Clone, Copy, Debug)]
pub struct TimeMonitor {
/// Time budget remaining at the end (if negative, deadline exceeded)
pub budget : i64,
pub budget: i64,
/// Deadline as given by portaudio
pub deadline : u64,
pub deadline: u64,
/// Execution time for one cycle
pub execution_time : i64,
pub callback_flags : audio_adaptive::effect::CallbackFlags,
pub execution_time: i64,
pub callback_flags: audio_adaptive::effect::CallbackFlags,
}
impl Default for TimeMonitor {
fn default() -> Self { TimeMonitor {budget:0, deadline:0, execution_time:0,
callback_flags: audio_adaptive::effect::CallbackFlags::NO_FLAG} }
fn default() -> Self {
TimeMonitor {
budget: 0,
deadline: 0,
execution_time: 0,
callback_flags: audio_adaptive::effect::CallbackFlags::NO_FLAG,
}
}
}
//Launch a audio graph in real time
fn real_time_run(mut audio_graph: AudioGraph, graph_name: String, cycles: u32, monitor: bool) -> Result<(), pa::Error> {
fn real_time_run(
mut audio_graph: AudioGraph,
graph_name: String,
cycles: u32,
monitor: bool,
) -> Result<(), pa::Error> {
let pa = try!(pa::PortAudio::new());
//audio_graph.update_schedule().expect("Cycle detected");//Already done when parsing
......@@ -64,8 +73,11 @@ fn real_time_run(mut audio_graph: AudioGraph, graph_name: String, cycles: u32, m
let buffer_size = audio_graph.frames_per_buffer() * audio_graph.nb_channels();
let settings = try!(pa.default_output_stream_settings(audio_graph.nb_channels() as i32,
SAMPLE_RATE as f64, buffer_size));
let settings = try!(pa.default_output_stream_settings(
audio_graph.nb_channels() as i32,
SAMPLE_RATE as f64,
buffer_size
));
let mut nb_cycles = 0;
......@@ -74,15 +86,20 @@ fn real_time_run(mut audio_graph: AudioGraph, graph_name: String, cycles: u32, m
thread::spawn(move || {
if monitor {
let mut f = File::create(format!("{}_{}-rt.csv",time::now().rfc3339(),graph_name)).expect("Impossible to report execution times");
f.write_all(format!("{} {}\n", nb_nodes, nb_edges).as_bytes()).unwrap();