mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-14 22:02:36 +00:00
more ui stuff
This commit is contained in:
1 parent
7594a90abb
commit
0af881ca5f
3 files changed
+219
-39
No files matched your search
Generated
+75
-1
@@ -566,6 +566,27 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs-next"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"dirs-sys-next",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs-sys-next"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"redox_users",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dispatch"
|
||||
version = "0.2.0"
|
||||
@@ -1254,6 +1275,26 @@ dependencies = [
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "native-dialog"
|
||||
version = "0.6.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0ab637f328b31bd0855c43bd38a4a4455e74324d9e74e0aac6a803422f43abc6"
|
||||
dependencies = [
|
||||
"block",
|
||||
"cocoa",
|
||||
"dirs-next",
|
||||
"objc",
|
||||
"objc-foundation",
|
||||
"objc_id",
|
||||
"once_cell",
|
||||
"raw-window-handle 0.4.3",
|
||||
"thiserror",
|
||||
"wfd",
|
||||
"which",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ndk"
|
||||
version = "0.5.0"
|
||||
@@ -1712,6 +1753,17 @@ dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_users"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"redox_syscall",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.6.0"
|
||||
@@ -1875,12 +1927,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ef5430c8e36b713e13b48a9f709cc21e046723fe44ce34587b73a830203b533e"
|
||||
|
||||
[[package]]
|
||||
name = "storyteller-vc"
|
||||
name = "storyteller-recast"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"console_error_panic_hook",
|
||||
"cpal",
|
||||
"iced",
|
||||
"native-dialog",
|
||||
"ringbuf",
|
||||
"wasm-bindgen",
|
||||
"web-sys",
|
||||
@@ -2175,6 +2228,16 @@ dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wfd"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e713040b67aae5bf1a0ae3e1ebba8cc29ab2b90da9aa1bff6e09031a8a41d7a8"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wgpu"
|
||||
version = "0.12.0"
|
||||
@@ -2278,6 +2341,17 @@ dependencies = [
|
||||
"wgpu",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "which"
|
||||
version = "4.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c4fb54e6113b6a8772ee41c3404fb0301ac79604489467e0a9ce1f3e97c24ae"
|
||||
dependencies = [
|
||||
"either",
|
||||
"lazy_static",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
[package]
|
||||
name = "storyteller-vc"
|
||||
name = "storyteller-recast"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
@@ -8,6 +8,7 @@ edition = "2021"
|
||||
[dependencies]
|
||||
iced = "0.4.2"
|
||||
ringbuf = "0.2.8"
|
||||
native-dialog = "0.6.3"
|
||||
|
||||
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
||||
cpal = { version = "0.13.5", features=["wasm-bindgen"] }
|
||||
|
||||
@@ -3,35 +3,52 @@ 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;
|
||||
use native_dialog::FileDialog;
|
||||
|
||||
pub fn main() -> iced::Result {
|
||||
App::run(Settings::default())
|
||||
}
|
||||
|
||||
struct App {
|
||||
model_browse_state: button::State,
|
||||
slider_1_state: slider::State,
|
||||
slider_1_value: f32,
|
||||
slider_2_state: slider::State,
|
||||
slider_2_value: f32,
|
||||
record_state: button::State,
|
||||
recording: bool,
|
||||
record_sender: Option<std::sync::mpsc::Sender<(bool, f32, f32)>>,
|
||||
record_sender: Option<std::sync::mpsc::Sender<(bool, f32)>>,
|
||||
play_target_state: button::State,
|
||||
play_source_state: button::State,
|
||||
target_playing: bool,
|
||||
source_playing: bool,
|
||||
realtime_record_state: button::State,
|
||||
realtime_recording: bool,
|
||||
realtime_record_sender: Option<std::sync::mpsc::Sender<(bool, f32, f32)>>,
|
||||
input_device_list_state: pick_list::State<String>,
|
||||
input_device_list_options: Vec<String>,
|
||||
input_device_list_selected: Option<String>,
|
||||
input_browse_state: button::State,
|
||||
output_device_list_state: pick_list::State<String>,
|
||||
output_device_list_options: Vec<String>,
|
||||
output_device_list_selected: Option<String>,
|
||||
output_browse_state: button::State,
|
||||
}
|
||||
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
enum Message {
|
||||
ModelBrowsePressed,
|
||||
Slider1Changed(f32),
|
||||
Slider2Changed(f32),
|
||||
RecordPressed,
|
||||
PlayTargetPressed,
|
||||
PlaySourcePressed,
|
||||
RealtimeRecordPressed,
|
||||
InputDeviceChanged(String),
|
||||
OutputDeviceChanged(String),
|
||||
InputBrowsePressed,
|
||||
OutputBrowsePressed,
|
||||
}
|
||||
|
||||
impl Application for App {
|
||||
@@ -40,6 +57,7 @@ impl Application for App {
|
||||
type Flags = ();
|
||||
|
||||
fn new(_flags: ()) -> (App, Command<Self::Message>) {
|
||||
let model_browse_state = button::State::new();
|
||||
let slider_1_state = slider::State::new();
|
||||
let slider_1_value = 85.0;
|
||||
let slider_2_state = slider::State::new();
|
||||
@@ -47,15 +65,27 @@ impl Application for App {
|
||||
let record_state = button::State::new();
|
||||
let recording = false;
|
||||
let record_sender = None;
|
||||
let play_target_state = button::State::new();
|
||||
let play_source_state = button::State::new();
|
||||
let target_playing = false;
|
||||
let source_playing = false;
|
||||
let realtime_record_state = button::State::new();
|
||||
let realtime_recording = false;
|
||||
let realtime_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 mut input_device_list_options: Vec<String> = cpal::default_host().input_devices().unwrap().map(|d|d.name().unwrap()).collect();
|
||||
input_device_list_options.insert(0, String::from("From file"));
|
||||
let input_browse_state = button::State::new();
|
||||
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 mut output_device_list_options: Vec<String> = cpal::default_host().output_devices().unwrap().map(|d| d.name().unwrap()).collect();
|
||||
output_device_list_options.insert(0, String::from("To file"));
|
||||
let output_device_list_selected = None;
|
||||
let output_browse_state = button::State::new();
|
||||
|
||||
(
|
||||
App {
|
||||
model_browse_state,
|
||||
slider_1_state,
|
||||
slider_1_value,
|
||||
slider_2_state,
|
||||
@@ -63,77 +93,106 @@ impl Application for App {
|
||||
record_state,
|
||||
recording,
|
||||
record_sender,
|
||||
play_target_state,
|
||||
play_source_state,
|
||||
target_playing,
|
||||
source_playing,
|
||||
realtime_record_state,
|
||||
realtime_recording,
|
||||
realtime_record_sender,
|
||||
input_device_list_state,
|
||||
input_device_list_options,
|
||||
input_device_list_selected,
|
||||
input_browse_state,
|
||||
output_device_list_state,
|
||||
output_device_list_options,
|
||||
output_device_list_selected,
|
||||
|
||||
output_browse_state,
|
||||
},
|
||||
Command::none()
|
||||
)
|
||||
}
|
||||
|
||||
fn title(&self) -> String {
|
||||
String::from("Storyteller VC")
|
||||
String::from("Storyteller Recast")
|
||||
}
|
||||
|
||||
fn update(&mut self, msg: Self::Message) -> Command<Self::Message> {
|
||||
match msg {
|
||||
Message::Slider1Changed(new_value) => {
|
||||
self.slider_1_value = new_value;
|
||||
if self.record_sender.is_some() {
|
||||
self.record_sender.as_ref().unwrap().send((self.recording.clone(), self.slider_1_value.clone(), self.slider_2_value.clone())).unwrap();
|
||||
if self.realtime_record_sender.is_some() {
|
||||
self.realtime_record_sender.as_ref().unwrap().send((self.realtime_recording.clone(), self.slider_1_value.clone(), self.slider_2_value.clone())).unwrap();
|
||||
}
|
||||
}
|
||||
Message::Slider2Changed(new_value) => {
|
||||
self.slider_2_value = new_value;
|
||||
if self.record_sender.is_some() {
|
||||
self.record_sender.as_ref().unwrap().send((self.recording.clone(), self.slider_1_value.clone(), self.slider_2_value.clone())).unwrap();
|
||||
if self.realtime_record_sender.is_some() {
|
||||
self.realtime_record_sender.as_ref().unwrap().send((self.realtime_recording.clone(), self.slider_1_value.clone(), self.slider_2_value.clone())).unwrap();
|
||||
}
|
||||
}
|
||||
Message::RecordPressed => {
|
||||
if self.recording {
|
||||
if self.record_sender.is_some()
|
||||
// Realtime record button => record and playback at the same time
|
||||
Message::RealtimeRecordPressed => {
|
||||
if self.realtime_recording {
|
||||
if self.realtime_record_sender.is_some()
|
||||
{
|
||||
self.record_sender.as_ref().unwrap().send((false, self.slider_1_value.clone(), self.slider_2_value.clone())).unwrap();
|
||||
self.realtime_record_sender.as_ref().unwrap().send((false, self.slider_1_value.clone(), self.slider_2_value.clone())).unwrap();
|
||||
}
|
||||
} else {
|
||||
let (record_sender, record_receiver) = std::sync::mpsc::channel();
|
||||
self.record_sender = Some(record_sender);
|
||||
let (realtime_record_sender, realtime_record_receiver) = std::sync::mpsc::channel();
|
||||
self.realtime_record_sender = Some(realtime_record_sender);
|
||||
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, self.slider_1_value.clone(), self.slider_2_value.clone())).unwrap();
|
||||
let output_device_name = self.output_device_list_selected.clone(); std::thread::spawn(move || { start_realtime_recording(realtime_record_receiver, input_device_name, output_device_name) });
|
||||
self.realtime_record_sender.as_ref().unwrap().send((true, self.slider_1_value.clone(), self.slider_2_value.clone())).unwrap();
|
||||
}
|
||||
|
||||
self.recording = !self.recording;
|
||||
self.realtime_recording = !self.realtime_recording;
|
||||
}
|
||||
Message::ModelBrowsePressed => {
|
||||
let path = FileDialog::new()
|
||||
.add_filter("Storyteller Recast Model", &["recast"])
|
||||
.show_open_single_file()
|
||||
.unwrap();
|
||||
}
|
||||
Message::InputBrowsePressed => {
|
||||
let path = FileDialog::new()
|
||||
.add_filter("WAV audio file", &["wav"])
|
||||
.show_open_single_file()
|
||||
.unwrap();
|
||||
}
|
||||
Message::OutputBrowsePressed => {
|
||||
let path = FileDialog::new()
|
||||
.add_filter("WAV audio file", &["wav"])
|
||||
.show_save_single_file()
|
||||
.unwrap();
|
||||
}
|
||||
Message::RecordPressed => { }
|
||||
Message::PlayTargetPressed => { }
|
||||
Message::PlaySourcePressed => { }
|
||||
Message::InputDeviceChanged(new_device) => {
|
||||
self.input_device_list_selected = Some(new_device);
|
||||
// Restart recording if currently recording and the device changes
|
||||
if self.recording {
|
||||
self.record_sender.as_ref().unwrap().send((false, self.slider_1_value.clone(), self.slider_2_value.clone())).unwrap();
|
||||
let (record_sender, record_receiver) = std::sync::mpsc::channel();
|
||||
self.record_sender = Some(record_sender);
|
||||
if self.realtime_recording {
|
||||
self.realtime_record_sender.as_ref().unwrap().send((false, self.slider_1_value.clone(), self.slider_2_value.clone())).unwrap();
|
||||
let (realtime_record_sender, realtime_record_receiver) = std::sync::mpsc::channel();
|
||||
self.realtime_record_sender = Some(realtime_record_sender);
|
||||
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, self.slider_1_value.clone(), self.slider_2_value.clone())).unwrap();
|
||||
std::thread::spawn(move || { start_realtime_recording(realtime_record_receiver, input_device_name, output_device_name) });
|
||||
self.realtime_record_sender.as_ref().unwrap().send((true, self.slider_1_value.clone(), self.slider_2_value.clone())).unwrap();
|
||||
}
|
||||
}
|
||||
Message::OutputDeviceChanged(new_device) => {
|
||||
self.output_device_list_selected = Some(new_device);
|
||||
// Restart recording if currently recording and the device changes
|
||||
if self.recording {
|
||||
self.record_sender.as_ref().unwrap().send((false, self.slider_1_value.clone(), self.slider_2_value.clone())).unwrap();
|
||||
let (record_sender, record_receiver) = std::sync::mpsc::channel();
|
||||
self.record_sender = Some(record_sender);
|
||||
if self.realtime_recording {
|
||||
self.realtime_record_sender.as_ref().unwrap().send((false, self.slider_1_value.clone(), self.slider_2_value.clone())).unwrap();
|
||||
let (realtime_record_sender, realtime_record_receiver) = std::sync::mpsc::channel();
|
||||
self.realtime_record_sender = Some(realtime_record_sender);
|
||||
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, self.slider_1_value.clone(), self.slider_2_value.clone())).unwrap();
|
||||
std::thread::spawn(move || { start_realtime_recording(realtime_record_receiver, input_device_name, output_device_name) });
|
||||
self.realtime_record_sender.as_ref().unwrap().send((true, self.slider_1_value.clone(), self.slider_2_value.clone())).unwrap();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -142,7 +201,33 @@ impl Application for App {
|
||||
}
|
||||
|
||||
fn view(&mut self) -> Element<Self::Message> {
|
||||
Column::new()
|
||||
let mut file_selection_row_elems: Vec<Element<Self::Message>> = vec![];
|
||||
if self.input_device_list_selected == Some(String::from("From file"))
|
||||
{
|
||||
file_selection_row_elems.push(
|
||||
Text::new("Input File: ").into()
|
||||
);
|
||||
file_selection_row_elems.push(
|
||||
Button::new(&mut self.input_browse_state, Text::new("Browse")).on_press(Message::InputBrowsePressed).into()
|
||||
);
|
||||
}
|
||||
if self.output_device_list_selected == Some(String::from("To file"))
|
||||
{
|
||||
file_selection_row_elems.push(
|
||||
Text::new("Output File: ").into()
|
||||
);
|
||||
file_selection_row_elems.push(
|
||||
Button::new(&mut self.output_browse_state, Text::new("Browse")).on_press(Message::OutputBrowsePressed).into()
|
||||
);
|
||||
}
|
||||
let mut file_selection_row = Row::with_children(file_selection_row_elems);
|
||||
|
||||
let elements = Column::new()
|
||||
.push(
|
||||
Row::new()
|
||||
.push(Text::new("Select Voice File: "))
|
||||
.push(Button::new(&mut self.model_browse_state, Text::new("Browse")).on_press(Message::ModelBrowsePressed))
|
||||
)
|
||||
.push(
|
||||
Row::new()
|
||||
.push(Text::new("Input Device: "))
|
||||
@@ -164,6 +249,9 @@ impl Application for App {
|
||||
)
|
||||
)
|
||||
)
|
||||
.push(
|
||||
file_selection_row
|
||||
)
|
||||
.push(
|
||||
Row::new()
|
||||
.push(Text::new("Input Volume: "))
|
||||
@@ -176,12 +264,28 @@ impl Application for App {
|
||||
)
|
||||
)
|
||||
.push(
|
||||
Button::new(&mut self.record_state, if self.recording { Text::new("Stop") } else {Text::new("Record")} ).on_press(Message::RecordPressed)
|
||||
).into()
|
||||
Row::new()
|
||||
.push(
|
||||
Button::new(&mut self.record_state, if self.recording { Text::new("Stop")} else {Text::new("Record")}).on_press(Message::RecordPressed)
|
||||
)
|
||||
.push(
|
||||
Button::new(&mut self.play_target_state, Text::new("Play Target")).on_press(Message::PlayTargetPressed)
|
||||
)
|
||||
.push(
|
||||
Button::new(&mut self.play_source_state, Text::new("Play Source")).on_press(Message::PlaySourcePressed)
|
||||
)
|
||||
.push(
|
||||
Button::new(&mut self.realtime_record_state, if self.realtime_recording { Text::new("Stop") } else {Text::new("Realtime\n(experimental)")}).on_press(Message::RealtimeRecordPressed)
|
||||
)
|
||||
|
||||
);
|
||||
|
||||
elements.into()
|
||||
}
|
||||
}
|
||||
|
||||
fn start_recording(record_receiver: std::sync::mpsc::Receiver<(bool, f32, f32)>, input_device_name: Option<String>, output_device_name: Option<String>) {
|
||||
// Realtime record => record and playback at the same time
|
||||
fn start_realtime_recording(realtime_record_receiver: std::sync::mpsc::Receiver<(bool, f32, f32)>, input_device_name: Option<String>, output_device_name: Option<String>) {
|
||||
let host = cpal::default_host();
|
||||
|
||||
//FIXME better unique identifier than the name of the device
|
||||
@@ -199,6 +303,7 @@ fn start_recording(record_receiver: std::sync::mpsc::Receiver<(bool, f32, f32)>,
|
||||
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();
|
||||
//FIXME unsafe
|
||||
static mut input_volume: f32 = 85.0;
|
||||
static mut output_volume: f32 = 85.0;
|
||||
|
||||
@@ -237,8 +342,8 @@ fn start_recording(record_receiver: std::sync::mpsc::Receiver<(bool, f32, f32)>,
|
||||
input_stream.play().unwrap();
|
||||
output_stream.play().unwrap();
|
||||
loop {
|
||||
let (recording, ivol, ovol) = record_receiver.recv().unwrap();
|
||||
if recording {
|
||||
let (realtime_recording, ivol, ovol) = realtime_record_receiver.recv().unwrap();
|
||||
if realtime_recording {
|
||||
unsafe { input_volume = ivol };
|
||||
unsafe { output_volume = ovol };
|
||||
std::thread::sleep(std::time::Duration::from_millis(50));
|
||||
|
||||
Reference in new issue
Block a user