This commit is contained in:
Julius Koskela 2022-09-23 20:03:03 +03:00
parent 3cc46118ca
commit 2384026b07
3 changed files with 23 additions and 25 deletions

View File

@ -1,13 +1,15 @@
use anyhow::anyhow;
use cpal::traits::{DeviceTrait, HostTrait};
use cpal::*;
use std::path::PathBuf;
use hound::WavSpec;
use chrono::prelude::*;
use anyhow::{Error, anyhow};
use super::*;
/// # Get Host
///
/// Returns the host with the given id if it's available.
pub fn get_host(host: HostId) -> Result<Host, anyhow::Error> {
pub fn get_host(host: HostId) -> Result<Host, Error> {
Ok(cpal::host_from_id(cpal::available_hosts()
.into_iter()
.find(|id| *id == host)
@ -18,7 +20,7 @@ pub fn get_host(host: HostId) -> Result<Host, anyhow::Error> {
/// # Get Device
///
/// Returns the default input device for the host if it's available.
pub fn get_device(host: Host) -> Result<Device, anyhow::Error> {
pub fn get_device(host: Host) -> Result<Device, Error> {
Ok(host.default_input_device()
.ok_or(anyhow!("No input device available. Try running `jackd -R -d alsa -d hw:0`",
))?)
@ -27,7 +29,7 @@ pub fn get_device(host: Host) -> Result<Device, anyhow::Error> {
/// # Get Default Config
///
/// Get the default config for the given device.
pub fn get_default_config(device: &Device) -> Result<SupportedStreamConfig, anyhow::Error> {
pub fn get_default_config(device: &Device) -> Result<SupportedStreamConfig, Error> {
Ok(device.default_input_config()?)
}
@ -38,7 +40,7 @@ pub fn get_default_config(device: &Device) -> Result<SupportedStreamConfig, anyh
/// sample_rate: The user's sample rate if it is supported by the device, otherwise the default sample rate.
/// channels: The user's number of channels if it is supported by the device, otherwise the default number of channels.
/// buffer_size: The user's buffer size if it is supported by the device, otherwise the default buffer size.
pub fn get_user_config(sample_rate: u32, channels: u16, buffer_size: u32) -> Result<StreamConfig, anyhow::Error> {
pub fn get_user_config(sample_rate: u32, channels: u16, buffer_size: u32) -> Result<StreamConfig, Error> {
if !ALLOWED_SAMPLE_RATES.contains(&sample_rate) {
return Err(anyhow!(
"Sample rate {} is not supported. Allowed sample rates: {:?}",
@ -71,8 +73,8 @@ pub fn get_user_config(sample_rate: u32, channels: u16, buffer_size: u32) -> Res
/// # Get WAV Spec
///
/// Get the WAV spec for the given stream config.
pub fn get_wav_spec(default_config: &SupportedStreamConfig, user_config: &StreamConfig) -> Result<hound::WavSpec, anyhow::Error> {
Ok(hound::WavSpec {
pub fn get_wav_spec(default_config: &SupportedStreamConfig, user_config: &StreamConfig) -> Result<WavSpec, Error> {
Ok(WavSpec {
channels: user_config.channels,
sample_rate: user_config.sample_rate.0,
bits_per_sample: (default_config.sample_format().sample_size() * 8) as u16,
@ -88,17 +90,13 @@ pub fn get_wav_spec(default_config: &SupportedStreamConfig, user_config: &Stream
///
/// Get the filename for the current recording according to the given format,
/// the current date and time, and the name prefix.
pub fn get_filename(name: &str, path: &PathBuf) -> Result<String, anyhow::Error> {
pub fn get_filename(name: &str, path: &PathBuf) -> String {
let now: DateTime<Local> = Local::now();
let filename = format!(
"{}-{}-{}-{}-{}:{}:{}.wav",
name,
now.year(),
now.month(),
now.day(),
now.hour(),
now.minute(),
now.second(),
now.year(), now.month(), now.day(),
now.hour(), now.minute(), now.second(),
);
Ok(path.join(filename).to_str().unwrap().to_string())
path.join(filename).to_str().unwrap().to_string()
}

View File

@ -17,7 +17,7 @@ use std::sync::{Condvar, atomic::{AtomicBool, Ordering}};
const DEFAULT_SAMPLE_RATE: u32 = 44100;
const DEFAULT_CHANNEL_COUNT: u16 = 1;
const DEFAULT_BUFFER_SIZE: u32 = 1024;
const ALLOWED_SAMPLE_RATES: &[u32] = &[44100, 48000, 88200, 96000, 176400, 192000];
const ALLOWED_SAMPLE_RATES: [u32; 6] = [44100, 48000, 88200, 96000, 176400, 192000];
const MAX_CHANNEL_COUNT: u16 = 2;
const MIN_BUFFER_SIZE: usize = 64;
const MAX_BUFFER_SIZE: usize = 8192;

View File

@ -6,7 +6,7 @@ use std::path::PathBuf;
use std::sync::{Arc, Mutex};
use crate::getters::*;
use crate::input_handling::*;
use anyhow::Error;
type WriteHandle = Arc<Mutex<Option<hound::WavWriter<BufWriter<File>>>>>;
pub struct Recorder {
@ -42,7 +42,7 @@ impl Recorder {
sample_rate: u32,
channels: u16,
buffer_size: u32,
) -> Result<Self, anyhow::Error> {
) -> Result<Self, Error> {
// Create interrupt handles to be used by the stream or batch loop.
let interrupt_handles = InterruptHandles::new()?;
@ -75,14 +75,14 @@ impl Recorder {
})
}
fn init_writer(&mut self) -> Result<(), anyhow::Error> {
let filename = get_filename(&self.name, &self.path)?;
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)?);
Ok(())
}
fn create_stream(&self) -> Result<Stream, anyhow::Error> {
fn create_stream(&self) -> Result<Stream, Error> {
let writer = self.writer.clone();
let config = self.user_config.clone();
let err_fn = |err| { eprintln!("An error occurred on stream: {}", err); };
@ -111,7 +111,7 @@ impl Recorder {
///
/// Start a continuous recording. The recording will be stopped when the
/// user presses `Ctrl+C`.
pub fn record(&mut self) -> Result<(), anyhow::Error> {
pub fn record(&mut self) -> Result<(), Error> {
self.init_writer()?;
let stream = self.create_stream()?;
stream.play()?;
@ -127,7 +127,7 @@ impl Recorder {
///
/// Record for a given number of seconds or until the user presses `Ctrl+C`.
/// Current batch is finished before stopping.
pub fn record_secs(&mut self, secs: u64) -> Result<(), anyhow::Error> {
pub fn record_secs(&mut self, secs: u64) -> Result<(), Error> {
self.init_writer()?;
let stream = self.create_stream()?;
stream.play()?;
@ -161,14 +161,14 @@ where
}
}
pub fn batch_recording(rec: &mut Recorder, secs: u64) -> Result<(), anyhow::Error> {
pub fn batch_recording(rec: &mut Recorder, secs: u64) -> Result<(), Error> {
while rec.interrupt_handles.batch_is_running() {
rec.record_secs(secs)?;
}
Ok(())
}
pub fn contiguous_recording(rec: &mut Recorder) -> Result<(), anyhow::Error> {
pub fn contiguous_recording(rec: &mut Recorder) -> Result<(), Error> {
rec.record()?;
Ok(())
}