diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..1ce67e6 --- /dev/null +++ b/Makefile @@ -0,0 +1,17 @@ + + +configure: + + +build: + + +run-audio-recorder: + + +run-gps-recorder: + + +run-depth-recorder: + + diff --git a/audio-logger/Makefile b/audio-logger/Makefile index 38011ab..dc9d307 100644 --- a/audio-logger/Makefile +++ b/audio-logger/Makefile @@ -1,8 +1,7 @@ all: cargo build --release -test: - cargo build --release +test: all mkdir -p recordings bash run_test.sh diff --git a/audio-logger/src/cli.rs b/audio-logger/src/cli.rs index 1843a28..0832a28 100644 --- a/audio-logger/src/cli.rs +++ b/audio-logger/src/cli.rs @@ -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, + /// (optional) Will record for a total of [SECONDS] + #[clap(short, long, value_name = "MAX_SECONDS")] + pub max_seconds: Option, + /// Host API to use #[clap(value_enum)] pub host: Hosts, diff --git a/audio-logger/src/getters.rs b/audio-logger/src/getters.rs index aa6ef1e..72b250c 100644 --- a/audio-logger/src/getters.rs +++ b/audio-logger/src/getters.rs @@ -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::now(); format!( - "{}-{}-{}_{}:{}:{}", + "{}-{}-{}_{}:{}:{:02}", now.year(), now.month(), now.day(), now.hour(), now.minute(), now.second(), ) diff --git a/audio-logger/src/input_handling.rs b/audio-logger/src/input_handling.rs index 9f5b3d1..129c3b1 100644 --- a/audio-logger/src/input_handling.rs +++ b/audio-logger/src/input_handling.rs @@ -19,10 +19,11 @@ type BatchInterrupt= Arc; pub struct InterruptHandles { batch_interrupt: BatchInterrupt, stream_interrupt: StreamInterrupt, + max_seconds: Option, } impl InterruptHandles { - pub fn new() -> Result { + pub fn new(max_seconds: Option) -> Result { 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(); } } diff --git a/audio-logger/src/main.rs b/audio-logger/src/main.rs index d952d5e..048bd68 100644 --- a/audio-logger/src/main.rs +++ b/audio-logger/src/main.rs @@ -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> { diff --git a/audio-logger/src/recorder.rs b/audio-logger/src/recorder.rs index e2d063f..adba7c7 100644 --- a/audio-logger/src/recorder.rs +++ b/audio-logger/src/recorder.rs @@ -27,6 +27,7 @@ pub struct Recorder { name: String, path: PathBuf, current_file: String, + max_seconds: Option, } /// # Recorder @@ -50,10 +51,11 @@ impl Recorder { sample_rate: u32, channels: u16, buffer_size: u32, + max_seconds: Option, ) -> Result { // 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 { + 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 { + 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 { + 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 { diff --git a/resources.md b/resources.md index cf41b0d..37e8e26 100755 --- a/resources.md +++ b/resources.md @@ -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 \ No newline at end of file +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 +