mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-04 17:38:10 +00:00
device selection
This commit is contained in:
1 parent
b571ccf1c2
commit
8a525f31a4
1 file changed
+93
-30
@@ -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);
|
||||
}
|
||||
Reference in new issue
Block a user