device selection

This commit is contained in:
Paul Sajna committed 2022-08-21 03:12:49 -07:00
1 parent b571ccf1c2
commit 8a525f31a4
1 file changed
+93 -30
+93 -30
View File
@@ -1,6 +1,8 @@
use iced::{executor, Application, Command, Element, Settings, Column};
use iced::widget::{Slider, slider, Button, button, Text};
use cpal::{SampleRate, BufferSize};
use iced::{executor, Application, Command, Element, Settings, Column, Row};
use iced::widget::{Slider, slider, Button, button, Text, pick_list, PickList};
use cpal::traits::{DeviceTrait, HostTrait, StreamTrait};
use cpal::{SampleRate, BufferSize, Device};
use ringbuf::RingBuffer;
pub fn main() -> iced::Result {
App::run(Settings::default())
@@ -14,36 +16,63 @@ struct App {
record_state: button::State,
recording: bool,
record_sender: Option<std::sync::mpsc::Sender<bool>>,
//record_receiver: std::sync::mpsc::Receiver<bool>,
input_device_list_state: pick_list::State<String>,
input_device_list_options: Vec<String>,
input_device_list_selected: Option<String>,
output_device_list_state: pick_list::State<String>,
output_device_list_options: Vec<String>,
output_device_list_selected: Option<String>,
}
#[derive(Clone, Debug)]
pub enum Message {
enum Message {
Slider1Changed(f32),
Slider2Changed(f32),
RecordPressed,
InputDeviceChanged(String),
OutputDeviceChanged(String),
}
impl Application for App {
type Executor = executor::Default;
type Message = crate::Message;
type Flags = ();
fn new(_flags: ()) -> (App, Command<Self::Message>) {
let slider_1_state = slider::State::new();
let slider_1_value = 50.0;
let slider_2_state = slider::State::new();
let slider_2_value = 50.0;
let record_state = button::State::new();
let recording = false;
//let (record_sender, record_receiver) = std::sync::mpsc::channel();
(App { slider_1_state, slider_1_value, slider_2_state, slider_2_value, record_state, recording, record_sender: None}, Command::none())
let record_sender = None;
let input_device_list_state = pick_list::State::new();
let input_device_list_options = cpal::default_host().input_devices().unwrap().map(|d|d.name().unwrap()).collect();
let input_device_list_selected = None;
let output_device_list_state = pick_list::State::new();
let output_device_list_options = cpal::default_host().output_devices().unwrap().map(|d| d.name().unwrap()).collect();
let output_device_list_selected = None;
(
App {
slider_1_state,
slider_1_value,
slider_2_state,
slider_2_value,
record_state,
recording,
record_sender,
input_device_list_state,
input_device_list_options,
input_device_list_selected,
output_device_list_state,
output_device_list_options,
output_device_list_selected,
},
Command::none()
)
}
fn title(&self) -> String {
@@ -67,12 +96,20 @@ impl Application for App {
} else {
let (record_sender, record_receiver) = std::sync::mpsc::channel();
self.record_sender = Some(record_sender);
std::thread::spawn(move || { start_recording(record_receiver) });
let input_device_name = self.input_device_list_selected.clone();
let output_device_name = self.output_device_list_selected.clone();
std::thread::spawn(move || { start_recording(record_receiver, input_device_name, output_device_name) });
self.record_sender.as_ref().unwrap().send(true).unwrap();
}
self.recording = !self.recording;
}
Message::InputDeviceChanged(new_device) => {
self.input_device_list_selected = Some(new_device);
}
Message::OutputDeviceChanged(new_device) => {
self.output_device_list_selected = Some(new_device);
}
}
Command::none()
}
@@ -80,40 +117,62 @@ impl Application for App {
fn view(&mut self) -> Element<Self::Message> {
Column::new()
.push(
Slider::new(&mut self.slider_1_state, 0.0..=100.0, self.slider_1_value, Message::Slider1Changed)
Row::new()
.push(Text::new("Input Device: "))
.push(
PickList::new(
&mut self.input_device_list_state,
&self.input_device_list_options,
self.input_device_list_selected.clone(),
Message::InputDeviceChanged,
)
)
.push(Text::new("Output Device: "))
.push(
PickList::new(
&mut self.output_device_list_state,
&self.output_device_list_options,
self.output_device_list_selected.clone(),
Message::OutputDeviceChanged,
)
)
)
.push(
Slider::new(&mut self.slider_2_state, 0.0..=100.0, self.slider_2_value, Message::Slider2Changed)
Row::new()
.push(Text::new("Input Volume: "))
.push(
Slider::new(&mut self.slider_1_state, 0.0..=100.0, self.slider_1_value, Message::Slider1Changed)
)
.push(Text::new("Output Volume: "))
.push(
Slider::new(&mut self.slider_2_state, 0.0..=100.0, self.slider_2_value, Message::Slider2Changed)
)
)
.push(
Button::new(&mut self.record_state, Text::new("Record")).on_press(Message::RecordPressed)
Button::new(&mut self.record_state, if self.recording { Text::new("Stop") } else {Text::new("Record")} ).on_press(Message::RecordPressed)
).into()
}
}
use cpal::traits::{DeviceTrait, HostTrait, StreamTrait};
use ringbuf::RingBuffer;
fn err_fn(err: cpal::StreamError) {
eprintln!("Error: {:?}", err);
}
fn start_recording(record_receiver: std::sync::mpsc::Receiver<bool>) {
fn start_recording(record_receiver: std::sync::mpsc::Receiver<bool>, input_device_name: Option<String>, output_device_name: Option<String>) {
let host = cpal::default_host();
// Find devices.
let input_device = host.default_input_device().unwrap();
let output_device = host.default_output_device().unwrap();
//FIXME better unique identifier than the name of the device
let input_device: cpal::Device;
match input_device_name {
Some(input_device_name) => { input_device = host.input_devices().unwrap().filter(|d| d.name().unwrap() == input_device_name).next().unwrap(); }
None => { input_device = host.default_input_device().unwrap(); }
}
let output_device: cpal::Device;
match output_device_name {
Some(output_device_name) => { output_device = host.output_devices().unwrap().filter(|d| d.name().unwrap() == output_device_name).next().unwrap(); }
None => { output_device = host.default_output_device().unwrap(); }
}
// We'll try and use the same configuration between streams to keep it simple.
let config = cpal::StreamConfig { channels: 1, sample_rate: SampleRate(48000), buffer_size: BufferSize::Default };
let ring = RingBuffer::new(100_0000);
let (mut producer, mut consumer) = ring.split();
// Create a delay in case the input and output devices aren't synced.
let input_data_fn = move |data: &[f32], _: &cpal::InputCallbackInfo| {
for &sample in data {
producer.push(sample).unwrap();
@@ -145,3 +204,7 @@ fn start_recording(record_receiver: std::sync::mpsc::Receiver<bool>) {
}
}
}
fn err_fn(err: cpal::StreamError) {
eprintln!("Error: {:?}", err);
}