Add matching host platform, max seconds recording, template Makefile

This commit is contained in:
Satu Koskinen 2022-09-25 22:41:09 +03:00
parent aba5279be9
commit 36dea6c9e2
8 changed files with 93 additions and 16 deletions

17
Makefile Normal file
View File

@ -0,0 +1,17 @@
configure:
build:
run-audio-recorder:
run-gps-recorder:
run-depth-recorder:

View File

@ -1,8 +1,7 @@
all:
cargo build --release
test:
cargo build --release
test: all
mkdir -p recordings
bash run_test.sh

View File

@ -4,6 +4,8 @@ use clap::{Parser, ValueEnum, Subcommand};
pub enum Hosts {
Alsa,
Jack,
CoreAudio,
Asio,
}
#[derive(Subcommand)]
@ -52,6 +54,10 @@ pub struct Rec {
#[clap(short, long, value_name = "SECONDS")]
pub batch_recording: Option<u64>,
/// (optional) Will record for a total of [SECONDS]
#[clap(short, long, value_name = "MAX_SECONDS")]
pub max_seconds: Option<u64>,
/// Host API to use
#[clap(value_enum)]
pub host: Hosts,

View File

@ -97,7 +97,7 @@ pub fn get_wav_spec(default_config: &SupportedStreamConfig, user_config: &Stream
pub fn get_date_time_string() -> String {
let now: DateTime<Local> = Local::now();
format!(
"{}-{}-{}_{}:{}:{}",
"{}-{}-{}_{}:{}:{:02}",
now.year(), now.month(), now.day(),
now.hour(), now.minute(), now.second(),
)

View File

@ -19,10 +19,11 @@ type BatchInterrupt= Arc<AtomicBool>;
pub struct InterruptHandles {
batch_interrupt: BatchInterrupt,
stream_interrupt: StreamInterrupt,
max_seconds: Option<u64>,
}
impl InterruptHandles {
pub fn new() -> Result<Self, anyhow::Error> {
pub fn new(max_seconds: Option<u64>) -> Result<Self, anyhow::Error> {
let stream_interrupt = Arc::new((Mutex::new(false), Condvar::new()));
let stream_interrupt_cloned = stream_interrupt.clone();
@ -42,13 +43,23 @@ impl InterruptHandles {
Ok(Self {
batch_interrupt,
stream_interrupt,
max_seconds,
})
}
pub fn stream_wait(&self) {
let &(ref lock, ref cvar) = &*self.stream_interrupt;
let mut started = lock.lock().unwrap();
let now = std::time::Instant::now();
while !*started {
match self.max_seconds {
Some(secs) => {
if now.elapsed().as_secs() >= secs {
break;
}
}
None => (),
}
started = cvar.wait(started).unwrap();
}
}

View File

@ -16,8 +16,8 @@ use constants::*;
use getters::*;
use input_handling::*;
use play::*;
use anyhow::{Error, Result, anyhow};
use anyhow::{Result, Error};
use clap::Parser;
fn main() -> Result<(), Error> {

View File

@ -27,6 +27,7 @@ pub struct Recorder {
name: String,
path: PathBuf,
current_file: String,
max_seconds: Option<u64>,
}
/// # Recorder
@ -50,10 +51,11 @@ impl Recorder {
sample_rate: u32,
channels: u16,
buffer_size: u32,
max_seconds: Option<u64>,
) -> Result<Self, Error> {
// Create interrupt handles to be used by the stream or batch loop.
let interrupt_handles = InterruptHandles::new()?;
let interrupt_handles = InterruptHandles::new(max_seconds)?;
// Select requested host.
let host = get_host(host)?;
@ -80,13 +82,14 @@ impl Recorder {
name,
path,
current_file: "".to_string(),
max_seconds,
})
}
fn init_writer(&mut self) -> Result<(), Error> {
let filename = get_filename(&self.name, &self.path);
self.current_file = filename.clone();
*self.writer.lock().unwrap() = Some(hound::WavWriter::create(filename, self.spec)?);
self.writer = Arc::new(Mutex::new(Some(hound::WavWriter::create(filename, self.spec)?)));
Ok(())
}
@ -141,15 +144,19 @@ impl Recorder {
stream.play()?;
println!("REC: {}", self.current_file);
let now = std::time::Instant::now();
loop {
std::thread::sleep(std::time::Duration::from_millis(500));
while self.interrupt_handles.batch_is_running() {
std::thread::sleep(std::time::Duration::from_millis(1));
if now.elapsed().as_secs() >= secs {
break;
}
}
drop(stream);
self.writer.lock().unwrap().take().unwrap().finalize()?;
println!("STOP: {}", self.current_file);
let writer = self.writer.clone();
let current_file = self.current_file.clone();
std::thread::spawn(move || {
writer.lock().unwrap().take().unwrap().finalize().unwrap();
println!("STOP: {}", current_file);
});
Ok(())
}
}
@ -170,7 +177,16 @@ where
}
fn batch_recording(rec: &mut Recorder, secs: u64) -> Result<(), Error> {
let now = std::time::Instant::now();
while rec.interrupt_handles.batch_is_running() {
match rec.max_seconds {
Some(max_secs) => {
if now.elapsed().as_secs() >= max_secs {
break;
}
}
None => {}
}
rec.record_secs(secs)?;
}
Ok(())
@ -181,6 +197,31 @@ fn continuous_recording(rec: &mut Recorder) -> Result<(), Error> {
Ok(())
}
#[cfg(target_os = "linux")]
fn match_host_platform(host: Hosts) -> Result<cpal::HostId, Error> {
match host {
Hosts::Alsa => Ok(cpal::HostId::Alsa),
Hosts::Jack => Ok(cpal::HostId::Jack),
_ => Err(anyhow!("Host not supported on Linux.")),
}
}
#[cfg(target_os = "macos")]
fn match_host_platform(host: Hosts) -> Result<cpal::HostId, Error> {
match host {
Hosts::CoreAudio => Ok(cpal::HostId::CoreAudio),
_ => Err(anyhow!("Host not supported on macOS.")),
}
}
#[cfg(target_os = "windows")]
fn match_host_platform(host: Hosts) -> Result<cpal::HostId, Error> {
match host {
Hosts::Asio => Ok(cpal::HostId::Asio),
_ => Err(anyhow!("Host not supported on Windows.")),
}
}
pub fn record(args: &Rec) -> Result<(), Error> {
let mut recorder = Recorder::init(
args.name.clone(),
@ -188,13 +229,11 @@ pub fn record(args: &Rec) -> Result<(), Error> {
Some(path) => path,
None => Path::new("./").to_path_buf(),
},
match args.host {
Hosts::Alsa => cpal::HostId::Alsa,
Hosts::Jack => cpal::HostId::Jack,
},
match_host_platform(args.host)?,
args.sample_rate.unwrap_or(DEFAULT_SAMPLE_RATE),
args.channels.unwrap_or(DEFAULT_CHANNEL_COUNT),
args.buffer_size.unwrap_or(DEFAULT_BUFFER_SIZE),
args.max_seconds,
)?;
match args.batch_recording {

View File

@ -6,4 +6,9 @@ https://www.circuito.io/app?components=9443,200000,267055
# Setting up Jack on Raspberry Pi
https://wiki.linuxaudio.org/wiki/raspberrypi
https://wiki.linuxaudio.org/wiki/raspberrypi
https://github.com/supercollider/supercollider/blob/develop/README_RASPBERRY_PI.md
https://madskjeldgaard.dk/posts/raspi4-notes/
# Setting up GPS