From 5fbf71e512a8550f670cb0a7bc0b16eb2e51e564 Mon Sep 17 00:00:00 2001 From: "Ando \"Thor\" Nando" Date: Tue, 14 Jun 2022 13:19:47 +1000 Subject: [PATCH 1/8] wip: make this work in the new world --- Cargo.toml | 24 +- assets/config.json | 21 +- src/lib/audio/dbap.rs | 22 +- src/lib/audio/detection.rs | 128 +++--- src/lib/audio/detector.rs | 20 +- src/lib/audio/fft.rs | 15 +- src/lib/audio/input.rs | 10 +- src/lib/audio/mod.rs | 6 +- src/lib/audio/output.rs | 153 +++---- src/lib/audio/sound.rs | 168 +++---- src/lib/audio/source/mod.rs | 93 ++-- src/lib/audio/source/realtime.rs | 13 +- src/lib/audio/source/wav/mod.rs | 11 +- src/lib/audio/source/wav/reader.rs | 107 +++-- src/lib/audio/source/wav/samples.rs | 10 +- src/lib/audio/speaker.rs | 16 +- src/lib/camera.rs | 20 +- src/lib/config.rs | 6 +- src/lib/gui/control_log.rs | 14 +- src/lib/gui/custom_widget/sound.rs | 69 +-- src/lib/gui/installation_editor.rs | 96 ++-- src/lib/gui/master.rs | 59 +-- src/lib/gui/mod.rs | 276 ++++++------ src/lib/gui/monitor.rs | 12 +- src/lib/gui/osc_in_log.rs | 14 +- src/lib/gui/osc_out_log.rs | 11 +- src/lib/gui/project_editor.rs | 80 ++-- src/lib/gui/soundscape_editor.rs | 76 ++-- src/lib/gui/source_editor.rs | 628 +++++++++++++++++++-------- src/lib/gui/speaker_editor.rs | 119 ++--- src/lib/gui/theme.rs | 20 +- src/lib/installation.rs | 24 +- src/lib/lib.rs | 76 ++-- src/lib/master.rs | 13 +- src/lib/metres.rs | 24 +- src/lib/osc/output.rs | 153 ++++--- src/lib/project/config.rs | 16 +- src/lib/project/mod.rs | 110 +++-- src/lib/soundscape/group.rs | 5 +- src/lib/soundscape/mod.rs | 269 ++++++------ src/lib/soundscape/movement/agent.rs | 72 +-- src/lib/soundscape/movement/mod.rs | 19 +- src/lib/soundscape/movement/ngon.rs | 64 ++- src/lib/utils.rs | 64 +-- 44 files changed, 1827 insertions(+), 1399 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index c6ae394..edcad87 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,6 +2,8 @@ name = "audio_server" version = "0.1.0" authors = ["mitchmindtree "] +resolver = "2" +edition = "2021" [profile.release] debug = true @@ -15,21 +17,23 @@ name = "audio_server" path = "src/lib/lib.rs" [dependencies] -conrod_core = "0.69" -conrod_derive = "0.69" -crossbeam = "0.3" +conrod_core = "0.76.1" +conrod_derive = "0.76.1" +crossbeam = "0.8.1" custom_derive = "0.1" +dasp = { version = "0.11.0", features = ["all"] } fxhash = "0.2" hound = "3.3" mindtree_utils = "0.4" newtype_derive = "0.1" -nannou = "0.13" -nannou_audio = "0.2" -nannou_osc = "0.1" +nannou = "0.18.1" +nannou_audio = "0.18.0" +nannou_conrod = "0.18.0" +nannou_osc = "0.18.0" num_cpus = "1.8" -pitch_calc = "0.11" -rand_xorshift = "0.2" -rustfft = "2.0" +pitch_calc = "0.12.0" +rand_xorshift = "0.3.0" +rustfft = "6.0.1" serde = { version = "1.0", features = ["rc"] } serde_derive = "1.0" serde_json = "1.0" @@ -40,4 +44,4 @@ walkdir = "2" [features] asio = ["nannou_audio/asio"] -test_with_stereo = [] # Compile with this feature to set the max i/o channels as `2`. +test_with_stereo = [] # Compile with this feature to set the max i/o channels as `2`. diff --git a/assets/config.json b/assets/config.json index 19fb63f..2d10b0c 100644 --- a/assets/config.json +++ b/assets/config.json @@ -10,12 +10,27 @@ "min_speaker_radius_metres": 0.25, "max_speaker_radius_metres": 1.0, "seed": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, 0, 0, 0, 0 - ] + ], + "proximity_limit_2": 49.0 }, - "selected_project_slug": "my-project-1", - "cpu_saving_mode": false + "selected_project_slug": "my-project", + "cpu_saving_mode": false, + "target_input_device_name": "", + "target_output_device_name": "" } \ No newline at end of file diff --git a/src/lib/audio/dbap.rs b/src/lib/audio/dbap.rs index 7732991..46e6f2e 100644 --- a/src/lib/audio/dbap.rs +++ b/src/lib/audio/dbap.rs @@ -1,6 +1,6 @@ //! An implementation of Distance-Based Amplitude Panning as published by Trond Lossius, 2009. -use nannou::geom::Point2; +use nannou::glam::DVec2 as Point2; #[derive(Copy, Clone, Debug)] pub struct Speaker { @@ -25,9 +25,9 @@ pub struct SpeakerGains<'a> { /// speaker only." /// /// A non-zero blur will ensure that the distance is greater than `0.0` and that we never divide by 0.0. -pub fn blurred_distance_2(source: Point2, speaker: Point2, blur: f64) -> f64 { - let x = speaker.x - source.x; - let y = speaker.y - source.y; +pub fn blurred_distance_2(source: Point2, speaker: Point2, blur: f64) -> f64 { + let x: f64 = speaker.x - source.x; + let y: f64 = speaker.y - source.y; (x * x + y * y + blur * blur).max(::std::f64::EPSILON) } @@ -105,17 +105,15 @@ fn k_coefficient(a: f64, speakers: &[Speaker]) -> f64 { #[test] fn speaker_gains() { - use nannou::prelude::*; - - let src = pt2(5.0, 5.0); - let speaker = |v: Point2, w| Speaker { + let src = Point2::new(5.0, 5.0); + let speaker = |v: Point2, w| Speaker { distance: v.distance(src), weight: w, }; - let a = speaker(pt2(0.0, 0.0), 1.0); - let b = speaker(pt2(10.0, 0.0), 1.0); - let c = speaker(pt2(10.0, 10.0), 1.0); - let d = speaker(pt2(0.0, 10.0), 1.0); + let a = speaker(Point2::new(0.0, 0.0), 1.0); + let b = speaker(Point2::new(10.0, 0.0), 1.0); + let c = speaker(Point2::new(10.0, 10.0), 1.0); + let d = speaker(Point2::new(0.0, 10.0), 1.0); let spkrs = vec![a, b, c, d]; let r = 6.0; // free-field rolloff db. let gains = SpeakerGains::new(&spkrs, r).collect::>(); diff --git a/src/lib/audio/detection.rs b/src/lib/audio/detection.rs index b3f5916..5b345c1 100644 --- a/src/lib/audio/detection.rs +++ b/src/lib/audio/detection.rs @@ -6,16 +6,17 @@ //! - RMS and Peak per Speaker channel. //! - FFT and avg RMS and Peak per installation. -use audio::{MAX_CHANNELS, FRAMES_PER_BUFFER}; -use audio::{fft, sound, speaker}; -use audio::detector::{EnvDetector, Fft, FftDetector, FFT_WINDOW_LEN}; -use crossbeam::sync::SegQueue; +use super::detector::{EnvDetector, Fft, FftDetector, FFT_WINDOW_LEN}; +use super::{fft, sound, speaker}; +use super::{FRAMES_PER_BUFFER, MAX_CHANNELS}; +use crate::gui; +use crate::installation; +use crate::osc; +use crossbeam::queue::SegQueue; use fxhash::{FxHashMap, FxHashSet}; -use gui; -use installation; -use osc; use rustfft::num_complex::Complex; use rustfft::num_traits::Zero; +use rustfft::FftDirection; use std::ops; use std::sync::{Arc, Mutex}; use std::{thread, time}; @@ -141,6 +142,8 @@ pub struct Model { /// The FFT planner used to prepare the FFT calculations and share data between them. fft_planner: fft::Planner, + /// The FFT Planner direction + fft_direction: FftDirection, /// The FFT to re-use by each of the `Detector`s. fft: Fft, /// A buffer for retrieving the frequency amplitudes from the `fft`. @@ -209,15 +212,14 @@ impl Handle { /// Pop the next available sound buffer for use off the queue. pub fn pop_sound_buffer(&self) -> Vec { - let mut buffer = self.sound_buffer_rx.try_pop().unwrap_or_else(Vec::new); + let mut buffer = self.sound_buffer_rx.pop().unwrap_or_else(Vec::new); buffer.clear(); buffer } /// Pop the next available output buffer for use off the queue. pub fn pop_output_buffer(&self) -> (Vec, OutputInfo) { - let (mut buffer, mut info) = self.output_buffer_rx.try_pop() - .unwrap_or_else(Default::default); + let (mut buffer, mut info) = self.output_buffer_rx.pop().unwrap_or_else(Default::default); buffer.clear(); info.clear(); (buffer, info) @@ -262,7 +264,8 @@ impl Model { let out_window = [Complex::::zero(); FFT_WINDOW_LEN]; let fft = Fft::new(in_window, out_window); let inverse = false; - let fft_planner = fft::Planner::new(inverse); + let fft_planner = fft::Planner::new(); + let fft_direction = rustfft::FftDirection::Inverse; // A buffer for retrieving the frequency amplitudes from the `fft`. let fft_frequency_amplitudes_2 = Box::new([0.0; FFT_WINDOW_LEN / 2]); @@ -283,6 +286,7 @@ impl Model { fft_planner, fft, fft_frequency_amplitudes_2, + fft_direction, } } } @@ -321,12 +325,23 @@ pub fn spawn( let thread = thread::Builder::new() .name("audio_detection".into()) .spawn(move || { - run(gui_audio_monitor_msg_tx, osc_output_msg_tx, rx, sound_buffer_tx, output_buffer_tx); + run( + gui_audio_monitor_msg_tx, + osc_output_msg_tx, + rx, + sound_buffer_tx, + output_buffer_tx, + ); }) .unwrap(); let thread = Arc::new(Mutex::new(Some(thread))); - Handle { tx, thread, sound_buffer_rx, output_buffer_rx } + Handle { + tx, + thread, + sound_buffer_rx, + output_buffer_rx, + } } /// The main loop for the detection thread. @@ -363,19 +378,18 @@ fn run( // Begin the loop. loop { - let msg = match rx.try_pop() { + let msg = match rx.pop() { // If there are no messages waiting, sleep for a tiny bit to avoid rinsing cpu. None => { thread::sleep(time::Duration::from_millis(1)); continue; - }, + } Some(msg) => msg, }; match msg { // Insert the new sound into the map. Message::AddSound(sound_id, channels) => { - let sound = new_sound(channels); model.sounds.insert(sound_id, sound); @@ -389,7 +403,7 @@ fn run( model.num_active_sound_buffers += 1; } } - }, + } // Update the detection for the sound with the given `Id`. Message::UpdateSound(sound_id, buffer) => { @@ -406,7 +420,7 @@ fn run( let Buffer { samples, .. } = buffer; sound_buffer_tx.push(samples); continue; - }, + } Some(sound) => sound, }; @@ -432,36 +446,38 @@ fn run( let msg = gui::AudioMonitorMessage::ActiveSound(sound_id, sound_msg); gui_audio_monitor_msg_tx.push(msg); } - }, + } // The sound has ended and its state should be removed. Message::RemoveSound(sound_id) => { model.sounds.remove(&sound_id); - }, + } // Initialise detection state for the given installation if it does not already exit. Message::AddInstallation(installation_id, computers) => { - let installation = model - .installations - .entry(installation_id) - .or_insert_with(|| { - let speaker_analyses = Vec::with_capacity(MAX_CHANNELS); - let summed_samples_of_all_channels = Vec::with_capacity(FRAMES_PER_BUFFER); - let fft_detector = FftDetector::new(); - Installation { - speaker_analyses, - summed_samples_of_all_channels, - fft_detector, - computers, - } - }); + let installation = + model + .installations + .entry(installation_id) + .or_insert_with(|| { + let speaker_analyses = Vec::with_capacity(MAX_CHANNELS); + let summed_samples_of_all_channels = + Vec::with_capacity(FRAMES_PER_BUFFER); + let fft_detector = FftDetector::new(); + Installation { + speaker_analyses, + summed_samples_of_all_channels, + fft_detector, + computers, + } + }); installation.computers = computers; - }, + } // Remove the given detection state for the given installation. Message::RemoveInstallation(installation_id) => { model.installations.remove(&installation_id); - }, + } // Perform analysis for the output buffer. // @@ -475,6 +491,7 @@ fn run( ref mut installations, ref mut fft, ref mut fft_planner, + fft_direction, ref mut fft_frequency_amplitudes_2, ref gui_audio_monitor_msg_tx, ref osc_output_msg_tx, @@ -484,7 +501,9 @@ fn run( } = model; let Buffer { samples, channels } = buffer; - let OutputInfo { speakers: speaker_infos } = info; + let OutputInfo { + speakers: speaker_infos, + } = info; // The number of frames in the buffer. let len_frames = samples.len() / channels; @@ -492,8 +511,13 @@ fn run( // Initialise the detection state for each installation. for installation in installations.values_mut() { installation.speaker_analyses.clear(); - installation.summed_samples_of_all_channels.resize(len_frames, 0.0); - installation.summed_samples_of_all_channels.iter_mut().for_each(|s| *s = 0.0); + installation + .summed_samples_of_all_channels + .resize(len_frames, 0.0); + installation + .summed_samples_of_all_channels + .iter_mut() + .for_each(|s| *s = 0.0); } // For each speaker, feed its amplitude into its detectors. @@ -504,9 +528,9 @@ fn run( } // Retrieve the detector state for the speaker. - let state = speakers - .entry(id) - .or_insert_with(|| Speaker { env_detector: EnvDetector::new() }); + let state = speakers.entry(id).or_insert_with(|| Speaker { + env_detector: EnvDetector::new(), + }); // Only update the envelope detector if CPU saving is not enabled. let mut rms = 0.0; @@ -594,6 +618,7 @@ fn run( fft_planner, fft, &mut fft_frequency_amplitudes_2[..], + fft_direction, ); // Retrieve the LMH representation. @@ -631,10 +656,13 @@ fn run( // Sort the speakers by channel index as the OSC output thread assumes that // speakers are in order of index. - installation.speaker_analyses.sort_by(|a, b| a.index.cmp(&b.index)); + installation + .speaker_analyses + .sort_by(|a, b| a.index.cmp(&b.index)); // Collect the speaker data. - let speakers = installation.speaker_analyses + let speakers = installation + .speaker_analyses .drain(..) .map(|s| osc::output::Speaker { rms: s.rms, @@ -656,25 +684,25 @@ fn run( } // Send buffer and output info back to audio thread for re-use. - let info = OutputInfo { speakers: speaker_infos }; + let info = OutputInfo { + speakers: speaker_infos, + }; output_buffer_tx.push((samples, info)); - }, + } // Clear all project-specific detection data. Message::ClearProjectSpecificData => { model.sounds.clear(); model.speakers.clear(); model.installations.clear(); - }, + } Message::CpuSavingEnabled(enabled) => { model.cpu_saving_enabled = enabled; } // Exit the loop as the app has exited. - Message::Exit => { - break - }, + Message::Exit => break, } } } diff --git a/src/lib/audio/detector.rs b/src/lib/audio/detector.rs index cb22b07..3c65367 100644 --- a/src/lib/audio/detector.rs +++ b/src/lib/audio/detector.rs @@ -2,9 +2,11 @@ //! //! Detects RMS and Peak envelopes. -use audio; -use nannou_audio::sample::{self, ring_buffer}; -use rustfft::num_complex::Complex; +use dasp::{self as sample}; +use rustfft::{num_complex::Complex, FftDirection}; +use sample::ring_buffer; + +use super::SAMPLE_RATE; // The frame type used within the detectors. type FrameType = [f32; 1]; @@ -30,7 +32,7 @@ pub type FftPlanner = super::fft::Planner; // RMS is monitored for visualisation, so we want a window size roughly the duration of one frame. // // A new visual frame is displayed roughly 60 times per second compared to 44_100 audio frames. -const WINDOW_SIZE: usize = audio::SAMPLE_RATE as usize / 60; +const WINDOW_SIZE: usize = SAMPLE_RATE as usize / 60; // The number of frames used to smooth the attack/release of the RMS detection. const RMS_ATTACK_FRAMES: f32 = 0.0; @@ -42,7 +44,7 @@ const PEAK_RELEASE_FRAMES: f32 = WINDOW_SIZE as f32 / 8.0; pub const FFT_WINDOW_LEN: usize = 512; /// The step between each frequency bin is equal to `samplerate / 2 * windowlength`. -pub const FFT_BIN_STEP_HZ: f64 = audio::SAMPLE_RATE / (2.0 * FFT_WINDOW_LEN as f64); +pub const FFT_BIN_STEP_HZ: f64 = super::SAMPLE_RATE / (2.0 * FFT_WINDOW_LEN as f64); /// An envelope detector for a single channel. /// @@ -113,7 +115,13 @@ impl FftDetector { fft_planner: &mut FftPlanner, fft: &mut Fft, freq_amps: &mut [f32], + direction: FftDirection, ) { - fft.process(fft_planner, self.fft_samples.iter().cloned(), freq_amps); + fft.process( + fft_planner, + self.fft_samples.iter().cloned(), + freq_amps, + direction, + ); } } diff --git a/src/lib/audio/fft.rs b/src/lib/audio/fft.rs index 2514ae7..61d934f 100644 --- a/src/lib/audio/fft.rs +++ b/src/lib/audio/fft.rs @@ -1,7 +1,8 @@ //! An audio-specific FFT implementation using RustFFT. -use rustfft::FFTplanner as FftPlanner; +use nannou::prelude::Zero; use rustfft::num_complex::Complex; +use rustfft::{FftDirection, FftPlanner}; /// An FFT generic over its window type. pub struct Fft { @@ -53,8 +54,8 @@ where planner: &mut Planner, channel_samples: I, freq_amplitudes: &mut [f32], - ) - where + direction: FftDirection, + ) where I: IntoIterator, { process( @@ -63,6 +64,7 @@ where self.input_window.slice_mut(), self.output_window.slice_mut(), freq_amplitudes, + direction, ); } } @@ -81,6 +83,7 @@ pub fn process( input_window: &mut [Complex], output_window: &mut [Complex], frequency_amplitudes_2: &mut [f32], + direction: rustfft::FftDirection, ) where I: IntoIterator, { @@ -102,8 +105,10 @@ pub fn process( assert_eq!(count, input_window.len()); // Perform the fourier transform. - let fft = planner.plan_fft(input_window.len()); - fft.process(input_window, output_window); + let fft = planner.plan_fft(input_window.len(), direction); + + let mut scratch = vec![Complex::zero(); fft.get_outofplace_scratch_len()]; + fft.process_outofplace_with_scratch(input_window, output_window, &mut scratch); // Retrieve the magnitude of the complex numbers as the amplitude of each frequency. // diff --git a/src/lib/audio/input.rs b/src/lib/audio/input.rs index a72839d..1bc87c8 100644 --- a/src/lib/audio/input.rs +++ b/src/lib/audio/input.rs @@ -2,12 +2,12 @@ //! //! The input stream has a number of `Source`s that read from one or more of the stream's channels. -use audio::source; +use crate::audio::source; use fxhash::FxHashMap; use nannou_audio::Buffer; use std::cmp; -use std::sync::Arc; use std::sync::atomic::{self, AtomicBool}; +use std::sync::Arc; /// Simplified type alias for the nannou audio input stream used by the audio server. pub type Stream = nannou_audio::Stream; @@ -106,17 +106,17 @@ pub fn capture(model: &mut Model, buffer: &Buffer) { } // Retrieve the empty buffer to use for sending samples. - let mut samples = match sound.buffer_rx.try_pop() { + let mut samples = match sound.buffer_rx.pop() { // This branch should never be hit but is here just in case. None => { let samples_len = frames_to_take * realtime.channels.len(); Vec::with_capacity(samples_len) - }, + } // There should always be a buffer waiting in this channel. Some(mut samples) => { samples.clear(); samples - }, + } }; // Get the channel range and ensure it is no greater than the buffer len. diff --git a/src/lib/audio/mod.rs b/src/lib/audio/mod.rs index 8d77170..e694a6e 100644 --- a/src/lib/audio/mod.rs +++ b/src/lib/audio/mod.rs @@ -1,4 +1,4 @@ -use metres::Metres; +use crate::metres::Metres; use nannou_audio::{Device, Host}; use time_calc::Ms; @@ -49,9 +49,9 @@ pub const DEFAULT_DBAP_ROLLOFF_DB: f64 = 4.0; pub const DISTANCE_BLUR: f64 = 0.01; /// The initial, default proximity limit. -pub const DEFAULT_PROXIMITY_LIMIT: Metres = Metres(7.0); +pub const DEFAULT_PROXIMITY_LIMIT: Metres = 7.0; /// Proximity limit squared for efficientcy efficiency. -pub const DEFAULT_PROXIMITY_LIMIT_2: Metres = Metres(DEFAULT_PROXIMITY_LIMIT.0 * DEFAULT_PROXIMITY_LIMIT.0); +pub const DEFAULT_PROXIMITY_LIMIT_2: Metres = DEFAULT_PROXIMITY_LIMIT * DEFAULT_PROXIMITY_LIMIT; /// Retrieve the desired audio host for the system. /// diff --git a/src/lib/audio/output.rs b/src/lib/audio/output.rs index 0c3c21f..2b4d303 100644 --- a/src/lib/audio/output.rs +++ b/src/lib/audio/output.rs @@ -3,24 +3,24 @@ //! The render function is passed to `nannou::App`'s build output stream method and describes how //! audio should be rendered to the output. -use audio::{DISTANCE_BLUR, FRAMES_PER_BUFFER, MAX_CHANNELS, MAX_SOUNDS}; -use audio::{Sound, Speaker}; -use audio::{dbap, detection, source, sound, speaker}; +use crate::audio::{dbap, detection, sound, source, speaker}; +use crate::audio::{Sound, Speaker}; +use crate::audio::{DISTANCE_BLUR, FRAMES_PER_BUFFER, MAX_CHANNELS, MAX_SOUNDS}; +use crate::gui; +use crate::installation; +use crate::metres::Metres; +use crate::osc; +use crate::soundscape; +use crate::utils; use fxhash::{FxHashMap, FxHashSet}; -use gui; -use installation; -use metres::Metres; use nannou_audio::Buffer; -use nannou::geom::Point2; -use nannou::math::MetricSpace; -use osc; -use soundscape; use std; use std::ops::{self, Deref, DerefMut}; -use std::sync::{atomic, mpsc, Arc}; use std::sync::atomic::AtomicUsize; +use std::sync::{atomic, mpsc, Arc}; use time_calc::Samples; -use utils; + +type Point2 = nannou::glam::DVec2; /// Simplified type alias for the nannou audio output stream used by the audio server. pub type Stream = nannou_audio::Stream; @@ -98,7 +98,7 @@ impl ActiveSound { (Some(Samples(remaining)), Some(Samples(total))) => { let current_frame = total - remaining; Some(current_frame as f64 / total as f64) - }, + } _ => None, }; normalised_progress @@ -194,7 +194,6 @@ pub struct Model { /// The current value of proximity limit. The limit in meters /// for a speaker to be considered in the dbap calculations pub proximity_limit_2: Metres, - } struct Channels { @@ -346,7 +345,8 @@ impl Model { /// Inserts the speaker and sends an `Add` message to the GUI. pub fn insert_speaker(&mut self, id: speaker::Id, speaker: Speaker) -> Option { - let old_speaker = self.speakers + let old_speaker = self + .speakers .remove(&id) .map(|ActiveSpeaker { speaker }| speaker); let speaker = ActiveSpeaker { speaker }; @@ -359,7 +359,8 @@ impl Model { /// Removes the speaker and sends a `Removed` message to the GUI. pub fn remove_speaker(&mut self, id: speaker::Id) -> Option { - let removed = self.speakers + let removed = self + .speakers .remove(&id) .map(|ActiveSpeaker { speaker }| speaker); if removed.is_some() { @@ -379,7 +380,11 @@ impl Model { } /// Removes the installation from the speaker with the given `speaker::Id`. - pub fn remove_speaker_installation(&mut self, id: speaker::Id, inst: &installation::Id) -> bool { + pub fn remove_speaker_installation( + &mut self, + id: speaker::Id, + inst: &installation::Id, + ) -> bool { self.speakers .get_mut(&id) .map(|active| active.speaker.installations.remove(inst)) @@ -419,7 +424,7 @@ impl Model { Some(active) => { update(&mut active.sound); true - }, + } } } @@ -442,7 +447,9 @@ impl Model { /// /// Returns the number of sounds that were updated. pub fn remove_sounds_with_source(&mut self, id: &source::Id) -> usize { - let ids: Vec<_> = self.sounds.iter() + let ids: Vec<_> = self + .sounds + .iter() .filter(|&(_, s)| s.source_id() == *id) .map(|(&id, _)| id) .collect(); @@ -486,7 +493,11 @@ impl Model { self.soloed.clear(); self.speakers.clear(); - let Model { ref mut sounds, ref channels, .. } = *self; + let Model { + ref mut sounds, + ref channels, + .. + } = *self; for (sound_id, sound) in sounds.drain() { // Notify threads of sound removal. channels.notify_sound_end(sound_id, sound); @@ -505,7 +516,9 @@ impl Channels { let update = move |soundscape: &mut soundscape::Model| { soundscape.remove_active_sound(&id); }; - self.soundscape_tx.send(soundscape::UpdateFn::from(update).into()).ok(); + self.soundscape_tx + .send(soundscape::UpdateFn::from(update).into()) + .ok(); // Detection thread. self.detection.remove_sound(id); @@ -586,7 +599,9 @@ pub fn render(model: &mut Model, buffer: &mut Buffer) { // `unmixed_sounds` buffer. for (sound_i, ordered_sound) in sounds_ordered.iter_mut().enumerate() { let sound_id = ordered_sound.id; - let sound = sounds.get_mut(&sound_id).expect("no sound for the given `Id`"); + let sound = sounds + .get_mut(&sound_id) + .expect("no sound for the given `Id`"); // Update the ordered sound. ordered_sound.channels = sound.channels; @@ -605,10 +620,7 @@ pub fn render(model: &mut Model, buffer: &mut Buffer) { let msg = gui::AudioMonitorMessage::ActiveSound(sound_id, update); channels.gui_audio_monitor_msg_tx.push(msg); - let ActiveSound { - ref mut sound, - .. - } = *sound; + let ActiveSound { ref mut sound, .. } = *sound; // The number of samples to request from the sound for this buffer. let num_samples = buffer.len_frames() * sound.channels; @@ -648,7 +660,9 @@ pub fn render(model: &mut Model, buffer: &mut Buffer) { if !cpu_saving_enabled { let mut detection_buffer = channels.detection.pop_sound_buffer(); detection_buffer.extend(ordered_sound.unmixed_samples.iter().cloned()); - channels.detection.update_sound(sound_id, detection_buffer, n_channels); + channels + .detection + .update_sound(sound_id, detection_buffer, n_channels); } // If we didn't write the expected number of samples, the sound has been exhausted. @@ -692,32 +706,21 @@ pub fn render(model: &mut Model, buffer: &mut Buffer) { let speaker_point = &active.speaker.point; // Get the current gain by performing DBAP calc. - let channel_point_f = Point2 { - x: channel_point.x.0, - y: channel_point.y.0, - }; - let speaker_point_f = Point2 { - x: speaker_point.x.0, - y: speaker_point.y.0, - }; + let channel_point_f = Point2::new(channel_point.x, channel_point.y); + let speaker_point_f = Point2::new(speaker_point.x, speaker_point.y); // Get the squared distance between the channel and speaker. - let distance_2 = dbap::blurred_distance_2( - channel_point_f, - speaker_point_f, - DISTANCE_BLUR, - ); + let distance_2 = + dbap::blurred_distance_2(channel_point_f, speaker_point_f, DISTANCE_BLUR); // If this speaker is not within proximity, skip it. - if proximity_limit_2 < Metres(distance_2) { + if proximity_limit_2 < distance_2 { continue; } // Weight the speaker based on whether or not it is assigned. - let weight = speaker::dbap_weight( - &sound.installations, - &active.speaker.installations, - ); + let weight = + self::speaker::dbap_weight(&sound.installations, &active.speaker.installations); // TODO: Possibly skip speakers with a weight of 0 (as below)? // Uncertain how this will affect DBAP, but may drastically improve CPU. @@ -746,7 +749,10 @@ pub fn render(model: &mut Model, buffer: &mut Buffer) { // Create the `dbap::Speaker` so that we may determine the current gain. This // is done following this loop. - let speaker = dbap::Speaker { distance: distance_2, weight }; + let speaker = dbap::Speaker { + distance: distance_2, + weight, + }; dbap_speakers.push(speaker); dbap_speaker_infos.push(dbap_speaker_info); } @@ -827,17 +833,17 @@ pub fn render(model: &mut Model, buffer: &mut Buffer) { let (mut detection_buffer, mut output_info) = channels.detection.pop_output_buffer(); detection_buffer.extend(buffer.iter().cloned()); output_info.speakers.extend({ - speakers - .iter() - .map(|(&id, speaker)| { - let info = detection::SpeakerInfo { - channel: speaker.channel, - installations: speaker.installations.clone(), - }; - (id, info) - }) + speakers.iter().map(|(&id, speaker)| { + let info = detection::SpeakerInfo { + channel: speaker.channel, + installations: speaker.installations.clone(), + }; + (id, info) + }) }); - channels.detection.update_output(detection_buffer, buffer.channels(), output_info); + channels + .detection + .update_output(detection_buffer, buffer.channels(), output_info); // Remove all sounds that have been exhausted. for sound_id in exhausted_sounds.drain(..) { @@ -856,19 +862,21 @@ pub fn render(model: &mut Model, buffer: &mut Buffer) { // Find the peak amplitude and send it via the monitor channel. let peak = buffer.iter().fold(0.0, |peak, &s| s.max(peak)); - channels.gui_audio_monitor_msg_tx.push(gui::AudioMonitorMessage::Master { peak }); + channels + .gui_audio_monitor_msg_tx + .push(gui::AudioMonitorMessage::Master { peak }); // Step the frame count. frame_count.fetch_add(buffer.len_frames(), atomic::Ordering::Relaxed); } pub fn channel_point( - sound_point: Point2, + sound_point: Point2, channel_index: usize, total_channels: usize, spread: Metres, radians: f32, -) -> Point2 { +) -> Point2 { assert!(channel_index < total_channels); if total_channels == 1 { sound_point @@ -876,25 +884,22 @@ pub fn channel_point( let phase = channel_index as f32 / total_channels as f32; let channel_radians_offset = phase * std::f32::consts::PI * 2.0; let radians = (radians + channel_radians_offset) as f64; - let (rel_x, rel_y) = utils::rad_mag_to_x_y(radians, spread.0); - let x = sound_point.x + Metres(rel_x); - let y = sound_point.y + Metres(rel_y); - Point2 { x, y } + let (rel_x, rel_y) = utils::rad_mag_to_x_y(radians, spread); + let x: Metres = sound_point.x + (rel_x); + let y: Metres = sound_point.y + (rel_y); + Point2::new(x, y) } } /// Tests whether or not the given speaker position is within the `PROXIMITY_LIMIT` distance of the /// given `point` (normally a `Sound`'s channel position). -pub fn speaker_is_in_proximity(point: &Point2, speaker: &Point2, - proximity_limit_2: Metres) -> bool { - let point_f = Point2 { - x: point.x.0, - y: point.y.0, - }; - let speaker_f = Point2 { - x: speaker.x.0, - y: speaker.y.0, - }; - let distance_2 = Metres(point_f.distance2(speaker_f)); +pub fn speaker_is_in_proximity( + point: &Point2, + speaker: &Point2, + proximity_limit_2: Metres, +) -> bool { + let point_f = Point2::new(point.x, point.y); + let speaker_f = Point2::new(speaker.x, speaker.y); + let distance_2 = point_f.distance(speaker_f); distance_2 < proximity_limit_2 } diff --git a/src/lib/audio/sound.rs b/src/lib/audio/sound.rs index f534a91..6ce2fa1 100644 --- a/src/lib/audio/sound.rs +++ b/src/lib/audio/sound.rs @@ -1,14 +1,16 @@ -use audio::{input, output, source, Source, SAMPLE_RATE}; -use crossbeam::sync::SegQueue; +use crate::audio::{input, output, source, Source, SAMPLE_RATE}; +use crate::installation; +use crate::metres::Metres; +use crossbeam::queue::SegQueue; use fxhash::FxHashSet; -use installation; -use metres::Metres; -use nannou::geom::Point2; +use serde::{Deserialize, Serialize}; use std::ops; -use std::sync::{Arc, Mutex}; use std::sync::atomic::{self, AtomicBool}; +use std::sync::{Arc, Mutex}; use time_calc::{Ms, Samples}; +type Point2 = nannou::glam::DVec2; + /// `Sound`s can be thought of as a stack of three primary components: /// /// 1. **Source**: for generating audio data (via oscillator, wave, audio input, etc). @@ -51,7 +53,7 @@ pub struct Sound { #[derive(Copy, Clone, Debug, PartialEq, Deserialize, Serialize)] pub struct Position { /// The location within the exhibition within metres. - pub point: Point2, + pub point: Point2, /// The orientation of the sound. #[serde(default)] pub radians: f32, @@ -67,9 +69,7 @@ pub struct Handle { #[derive(Debug)] pub enum SourceHandle { Wav, - Realtime { - is_capturing: Arc, - }, + Realtime { is_capturing: Arc }, } // State shared between multiple handles to a single sound. @@ -115,7 +115,9 @@ impl Handle { if let SourceHandle::Realtime { ref is_capturing } = self.shared.source { is_capturing.store(false, atomic::Ordering::Relaxed); } - self.shared.is_playing.store(false, atomic::Ordering::Relaxed); + self.shared + .is_playing + .store(false, atomic::Ordering::Relaxed); result } @@ -127,7 +129,9 @@ impl Handle { if let SourceHandle::Realtime { ref is_capturing } = self.shared.source { is_capturing.store(true, atomic::Ordering::Relaxed); } - self.shared.is_playing.store(true, atomic::Ordering::Relaxed); + self.shared + .is_playing + .store(true, atomic::Ordering::Relaxed); result } @@ -154,51 +158,46 @@ pub fn spawn_from_source( input_stream: &input::Stream, output_stream: &output::Stream, latency: Ms, -) -> Handle -{ +) -> Handle { let installations = source.role.clone().into(); match source.kind { - source::Kind::Wav(ref wav) => { - spawn_from_wav( - id, - source_id, - wav, - source.spread, - source.volume, - source.muted, - position, - source.channel_radians, - installations, - attack_duration_frames, - release_duration_frames, - continuous_preview, - max_duration_frames, - frame_count, - wav_reader, - output_stream, - ) - }, - - source::Kind::Realtime(ref realtime) => { - spawn_from_realtime( - id, - source_id, - realtime, - source.spread, - source.volume, - source.muted, - position, - source.channel_radians, - installations, - attack_duration_frames, - release_duration_frames, - continuous_preview, - max_duration_frames, - input_stream, - output_stream, - latency, - ) - }, + source::Kind::Wav(ref wav) => spawn_from_wav( + id, + source_id, + wav, + source.spread, + source.volume, + source.muted, + position, + source.channel_radians, + installations, + attack_duration_frames, + release_duration_frames, + continuous_preview, + max_duration_frames, + frame_count, + wav_reader, + output_stream, + ), + + source::Kind::Realtime(ref realtime) => spawn_from_realtime( + id, + source_id, + realtime, + source.spread, + source.volume, + source.muted, + position, + source.channel_radians, + installations, + attack_duration_frames, + release_duration_frames, + continuous_preview, + max_duration_frames, + input_stream, + output_stream, + latency, + ), } } @@ -220,13 +219,22 @@ pub fn spawn_from_wav( frame_count: u64, wav_reader: &source::wav::reader::Handle, audio_output: &output::Stream, -) -> Handle -{ +) -> Handle { // The wave samples iterator. - let samples = wav_reader.play(id, &wav.path, frame_count, wav.should_loop || continuous_preview) + let samples = wav_reader + .play( + id, + &wav.path, + frame_count, + wav.should_loop || continuous_preview, + ) .unwrap_or_else(|err| { - panic!("failed to send new wav \"{}\"to wav_reader thread: {:?}: {}", - wav.path.display(), err, err); + panic!( + "failed to send new wav \"{}\"to wav_reader thread: {:?}: {}", + wav.path.display(), + err, + err + ); }); // The source signal. @@ -262,9 +270,7 @@ pub fn spawn_from_wav( }; // Create the handle to the sound. - let handle = Handle { - shared, - }; + let handle = Handle { shared }; // The output stream active sound. let output_active_sound = sound.into(); @@ -369,9 +375,7 @@ pub fn spawn_from_realtime( }; // State shared between the handles to a realtime sound. - let source_handle = SourceHandle::Realtime { - is_capturing, - }; + let source_handle = SourceHandle::Realtime { is_capturing }; // State shared between the handles to the sound. let shared = Arc::new(Shared { @@ -395,9 +399,7 @@ pub fn spawn_from_realtime( }; // Create the handle to the sound. - let handle = Handle { - shared, - }; + let handle = Handle { shared }; // The output stream active sound. let output_active_sound = sound.into(); @@ -427,13 +429,19 @@ impl Sound { /// The location of the channel at the given index. /// /// Returns `None` if there is no channel for the given index. - pub fn channel_point(&self, index: usize) -> Option> { + pub fn channel_point(&self, index: usize) -> Option { if self.channels <= index { return None; } let point = self.position.point; let radians = self.position.radians + self.channel_radians; - Some(super::output::channel_point(point, index, self.channels, self.spread, radians)) + Some(super::output::channel_point( + point, + index, + self.channels, + self.spread, + radians, + )) } /// Produce an iterator yielding the location of each channel around the sound. @@ -469,7 +477,7 @@ impl From for Installations { } impl ops::Deref for Position { - type Target = Point2; + type Target = Point2; fn deref(&self) -> &Self::Target { &self.point } @@ -482,14 +490,12 @@ impl ops::DerefMut for Position { } impl<'a> Iterator for ChannelPoints<'a> { - type Item = Point2; + type Item = Point2; fn next(&mut self) -> Option { - self.sound - .channel_point(self.index) - .map(|point| { - self.index +=1 ; - point - }) + self.sound.channel_point(self.index).map(|point| { + self.index += 1; + point + }) } } @@ -514,7 +520,9 @@ impl IdGenerator { } pub fn generate_next(&self) -> Id { - let mut next = self.next.lock() + let mut next = self + .next + .lock() .expect("failed to acquire mutex for generating new `sound::Id`"); let id = *next; *next = Id(id.0.wrapping_add(1)); diff --git a/src/lib/audio/source/mod.rs b/src/lib/audio/source/mod.rs index 1cbd001..4d8de28 100644 --- a/src/lib/audio/source/mod.rs +++ b/src/lib/audio/source/mod.rs @@ -1,12 +1,13 @@ +use crate::installation; +use crate::metres::Metres; +use crate::soundscape; +use crate::utils::{self, Range}; use fxhash::FxHashSet; -use installation; -use metres::Metres; use nannou::math::map_range; use nannou::rand::Rng; -use soundscape; +use serde::{Deserialize, Serialize}; use std::ops; use time_calc::{Ms, Samples}; -use utils::{self, Range}; pub use self::movement::Movement; pub use self::realtime::Realtime; @@ -154,9 +155,12 @@ pub struct Soundscape { /// Items related to the movement of a source's associated sounds within a soundscape. pub mod movement { - use nannou::geom::{Point2, Vector2}; + use crate::utils::Range; + use nannou::glam::DVec2 as Vector2; + use nannou::glam::DVec2 as Point2; use nannou::prelude::PI_F64; - use utils::Range; + use serde::Deserialize; + use serde::Serialize; /// The absolute maximum speed of an agent. pub const MAX_SPEED: f64 = 20.0; @@ -192,7 +196,7 @@ pub mod movement { #[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] pub enum Movement { /// The position normalised to the constraints of the installation. - Fixed(Point2), + Fixed(Point2), Generative(Generative), } @@ -234,7 +238,7 @@ pub mod movement { /// /// `0.0` means all points will be in the center. /// `1.0` means all points will extend to the bounds of the installation area. - pub normalised_dimensions: Vector2, + pub normalised_dimensions: Vector2, /// Some rotation that is applied to the Ngon's points around the centre. #[serde(default = "super::default::radians_offset")] pub radians_offset: Range, @@ -352,7 +356,12 @@ where let range_duration = range.max - range.min; let skew = playback_duration_skew(range_duration); let skewed_normalised_value = rng.gen::().powf(skew as f64); - Ms(utils::unskew_and_unnormalise(skewed_normalised_value, range.min.0, range.max.0, skew)) + Ms(utils::unskew_and_unnormalise( + skewed_normalised_value, + range.min.0, + range.max.0, + skew, + )) } impl Source { @@ -368,7 +377,10 @@ impl Attack { /// Construct an `Attack` from its duration in frames. pub fn from_duration_frames(duration_frames: Samples) -> Self { let current_frame = Samples(0); - Attack { duration_frames, current_frame } + Attack { + duration_frames, + current_frame, + } } } @@ -376,7 +388,10 @@ impl Release { /// Construct a `Release` from its duration in frames. pub fn from_duration_frames(duration_frames: Samples) -> Self { let frame_countdown = duration_frames; - Release { duration_frames, frame_countdown } + Release { + duration_frames, + frame_countdown, + } } } @@ -384,7 +399,10 @@ impl Duration { /// Construct a `Duration` from its frames. pub fn from_frames(duration_frames: Samples) -> Self { let current_frame = Samples(0); - Duration { duration_frames, current_frame } + Duration { + duration_frames, + current_frame, + } } } @@ -408,7 +426,9 @@ impl SignalKind { /// Borrow the inner iterator yielding samples. pub fn samples(&mut self) -> &mut dyn Iterator { match *self { - SignalKind::Wav { ref mut samples, .. } => samples as _, + SignalKind::Wav { + ref mut samples, .. + } => samples as _, SignalKind::Realtime { ref mut samples } => samples as _, } } @@ -420,7 +440,12 @@ impl Signal { let attack = Attack::from_duration_frames(attack_frames); let release = Release::from_duration_frames(release_frames); let duration = None; - Signal { kind, attack, release, duration } + Signal { + kind, + attack, + release, + duration, + } } /// Specify the duration of the signal in frames in the `Signal`. @@ -465,7 +490,7 @@ impl Signal { release.frame_countdown = ::std::cmp::min(release.frame_countdown, frames); } frames_until_release - }, + } None => Samples(::std::i64::MAX), }; @@ -606,28 +631,41 @@ pub mod skew { } pub mod default { - use metres::Metres; - use nannou::geom::{Point2, Vector2}; use super::{movement, Movement}; + use crate::metres::Metres; + use crate::utils::{Range, HR_MS}; + use nannou::glam::DVec2 as Vector2; + use nannou::glam::{const_dvec2, DVec2 as Point2}; use time_calc::Ms; - use utils::{HR_MS, Range}; - pub const SPREAD: Metres = Metres(2.5); + pub const SPREAD: Metres = 2.5; // Rotate the channel radians 90deg so that stereo channels are to the side by default. pub const CHANNEL_RADIANS: f32 = ::std::f32::consts::PI * 0.5; pub const VOLUME: f32 = 0.6; - pub const OCCURRENCE_RATE: Range = Range { min: Ms(500.0), max: Ms(HR_MS as _) }; + pub const OCCURRENCE_RATE: Range = Range { + min: Ms(500.0), + max: Ms(HR_MS as _), + }; pub const SIMULTANEOUS_SOUNDS: Range = Range { min: 0, max: 1 }; // Assume that the user wants to play back the sound endlessly at first. pub const PLAYBACK_DURATION: Range = Range { min: super::MAX_PLAYBACK_DURATION, max: super::MAX_PLAYBACK_DURATION, }; - pub const ATTACK_DURATION: Range = Range { min: Ms(0.0), max: Ms(0.0) }; - pub const RELEASE_DURATION: Range = Range { min: Ms(0.0), max: Ms(0.0) }; - pub const FIXED: Point2 = Point2 { x: 0.5, y: 0.5 }; + pub const ATTACK_DURATION: Range = Range { + min: Ms(0.0), + max: Ms(0.0), + }; + pub const RELEASE_DURATION: Range = Range { + min: Ms(0.0), + max: Ms(0.0), + }; + pub const FIXED: Point2 = const_dvec2!([0.5, 0.5]); pub const MAX_SPEED: Range = Range { min: 1.0, max: 5.0 }; - pub const MAX_FORCE: Range = Range { min: 0.04, max: 0.06 }; + pub const MAX_FORCE: Range = Range { + min: 0.04, + max: 0.06, + }; pub const MAX_ROTATION: Range = Range { min: super::movement::MAX_ROTATION, max: super::movement::MAX_ROTATION, @@ -643,11 +681,8 @@ pub mod default { pub const NTH: Range = Range { min: 1, max: 3 }; pub const NORMALISED_WIDTH: f64 = 1.0; pub const NORMALISED_HEIGHT: f64 = 1.0; - pub const NORMALISED_DIMENSIONS: Vector2 = Vector2 { - x: NORMALISED_WIDTH, - y: NORMALISED_HEIGHT, - }; - pub const RADIANS_OFFSET: Range = Range { + pub const NORMALISED_DIMENSIONS: Vector2 = const_dvec2!([NORMALISED_WIDTH, NORMALISED_HEIGHT]); + pub const RADIANS_OFFSET: Range = Range:: { min: ::std::f64::consts::PI * 0.5, max: ::std::f64::consts::PI * 0.5, }; diff --git a/src/lib/audio/source/realtime.rs b/src/lib/audio/source/realtime.rs index 8fd01b2..ac73277 100644 --- a/src/lib/audio/source/realtime.rs +++ b/src/lib/audio/source/realtime.rs @@ -1,10 +1,12 @@ //! Items related to the realtime audio input sound source kind. -use crossbeam::sync::SegQueue; +use crossbeam::queue::SegQueue; +use serde::Deserialize; +use serde::Serialize; use std::mem; use std::ops; -use std::sync::{atomic, Arc}; use std::sync::atomic::AtomicBool; +use std::sync::{atomic, Arc}; use time_calc::{Ms, Samples}; pub type BufferTx = Arc>>; @@ -46,7 +48,8 @@ impl Signal { /// /// Returns `None` if the signal is "continuous" or has no duration. pub fn remaining_frames(&self) -> Option { - self.remaining_samples.map(|s| Samples((s / self.channels) as _)) + self.remaining_samples + .map(|s| Samples((s / self.channels) as _)) } } @@ -69,13 +72,13 @@ impl Iterator for Signal { *sample_index += 1; return Some(sample); } - match buffer_rx.try_pop() { + match buffer_rx.pop() { None => return None, Some(buffer) => { let used_buffer = mem::replace(current_buffer, buffer); buffer_tx.push(used_buffer); *sample_index = 0; - }, + } } } } diff --git a/src/lib/audio/source/wav/mod.rs b/src/lib/audio/source/wav/mod.rs index 39ff191..40cf8ad 100644 --- a/src/lib/audio/source/wav/mod.rs +++ b/src/lib/audio/source/wav/mod.rs @@ -1,5 +1,6 @@ -use audio; +use crate::audio; use hound; +use serde::{Deserialize, Serialize}; use std::path::PathBuf; use time_calc::{Ms, SampleHz, Samples}; @@ -52,8 +53,12 @@ impl Wav { let spec = reader.spec(); let channels = spec.channels as usize; let sample_hz = spec.sample_rate as _; - assert_eq!(sample_hz, audio::SAMPLE_RATE, - "WAV files must have a sample rate of {}", audio::SAMPLE_RATE); + assert_eq!( + sample_hz, + audio::SAMPLE_RATE, + "WAV files must have a sample rate of {}", + audio::SAMPLE_RATE + ); let duration = Samples(reader.duration() as _); let playback = default_playback(); let should_loop = default_should_loop(); diff --git a/src/lib/audio/source/wav/reader.rs b/src/lib/audio/source/wav/reader.rs index 5153f0c..2381bfa 100644 --- a/src/lib/audio/source/wav/reader.rs +++ b/src/lib/audio/source/wav/reader.rs @@ -1,22 +1,22 @@ //! A thread dedicated to reading sounds from WAV files and feeding their samples to sounds on the //! audio thread. -use audio::{self, sound}; -use crossbeam::sync::{MsQueue, SegQueue}; +use crate::audio::{self, sound}; +use crossbeam::queue::SegQueue; use fxhash::FxHashMap; use hound::{self, SampleFormat}; use num_cpus; use std::cell::RefCell; use std::collections::VecDeque; -use std::io::BufReader; use std::fs::File; +use std::io::BufReader; use std::mem; use std::ops; use std::path::Path; use std::sync::{Arc, Mutex}; use std::thread; -use time_calc::Samples; use threadpool::ThreadPool; +use time_calc::Samples; /// The number of sample buffers that the `reader` thread prepares ahead of time for a single /// sound. @@ -26,10 +26,10 @@ const NUM_BUFFERS: usize = 4; pub type WavReader = hound::WavReader>; /// Sends messages to the `wav::reader` thread. -pub type Tx = Arc>; +pub type Tx = Arc>; /// Receives `Message`s for the `wav::reader` thread. -pub type Rx = Arc>; +pub type Rx = Arc>; /// For sending buffers to a sound's associated `ThreadedSamplesStream`. pub type BufferTx = Arc>; @@ -38,7 +38,7 @@ pub type BufferTx = Arc>; pub type BufferRx = Arc>; /// The mpmc queue used for distributing `Play` messages across the child threads. -type ChildMessageQueue = MsQueue; +type ChildMessageQueue = SegQueue; /// A unique identifier associated with a child thread. #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] @@ -180,15 +180,19 @@ impl Handle { wav_path: &Path, start_frame: u64, looped: bool, - ) -> Result - { + ) -> Result { let reader = WavReader::open(wav_path)?; let wav_len_samples = reader.len() as _; let buffer_queue = Arc::new(SegQueue::new()); let buffer_tx = buffer_queue.clone(); let buffer_rx = buffer_queue; let spec = reader.spec(); - let play = Play { reader, buffer_tx, start_frame, looped }; + let play = Play { + reader, + buffer_tx, + start_frame, + looped, + }; let samples_stream = SamplesStream::new(buffer_rx, spec, wav_len_samples, looped); let msg = Message::Play(sound_id, play); self.tx.push(msg); @@ -262,7 +266,7 @@ impl SamplesStream { } let mut buffer_mut = self.buffer.borrow_mut(); - *buffer_mut = match self.buffer_rx.try_pop() { + *buffer_mut = match self.buffer_rx.pop() { None => return Some(Samples(self.wav_len_samples as _)), Some(buffer) => Some(buffer), }; @@ -295,14 +299,14 @@ impl SamplesStream { mem::drop(buffer_mut.take()); // Receive the next buffer. - *buffer_mut = match buffer_rx.try_pop() { + *buffer_mut = match buffer_rx.pop() { // If there are no more buffers, there must be no more samples so we're done. None => return None, // Otherwise reset Some(buffer) => { *buffer_index = 0; Some(buffer) - }, + } }; } } @@ -319,16 +323,18 @@ impl Model { /// Initialise the `Model`. fn new(tx: Tx) -> Self { let sounds = FxHashMap::default(); - Model { - sounds, - tx, - } + Model { sounds, tx } } } /// Process the given `Play` command and return the resulting `Sound`. fn play_sound(play: Play) -> Sound { - let Play { mut reader, buffer_tx, start_frame, looped } = play; + let Play { + mut reader, + buffer_tx, + start_frame, + looped, + } = play; // Seek to the given `start_frame` within the file. // @@ -339,7 +345,8 @@ fn play_sound(play: Play) -> Sound { // wrapped around to the beginning. let duration_frames = reader.duration() as u64; let frames = start_frame % duration_frames; - reader.seek(frames as u32) + reader + .seek(frames as u32) .expect("failed to seek to start frame in wav source"); // Prepare the buffers for the sound. @@ -348,11 +355,13 @@ fn play_sound(play: Play) -> Sound { .map(|_| { let mut samples = vec![]; let start_sample = wav_len_samples - super::samples::remaining(&mut reader); - fill_buffer(&mut reader, &mut samples, looped) - .expect("failed to fill buffer"); + fill_buffer(&mut reader, &mut samples, looped).expect("failed to fill buffer"); let end_sample = wav_len_samples - super::samples::remaining(&mut reader); let samples_range = start_sample..end_sample; - PreparedBuffer { samples, samples_range } + PreparedBuffer { + samples, + samples_range, + } }) .collect(); @@ -387,10 +396,19 @@ fn next_buffer( let wav_len_samples = reader.len() as usize; // First, send the next queued buffer over the channel. - if let Some(PreparedBuffer { samples, samples_range }) = prepared_buffers.pop_front() { + if let Some(PreparedBuffer { + samples, + samples_range, + }) = prepared_buffers.pop_front() + { let reader_tx = parent_tx.clone(); let info = BufferInfo { samples_range }; - let buffer = Buffer { samples, sound_id, reader_tx, info }; + let buffer = Buffer { + samples, + sound_id, + reader_tx, + info, + }; // The output thread may have exited before us so ignore closed channel error. buffer_tx.push(buffer); } @@ -400,7 +418,10 @@ fn next_buffer( fill_buffer(reader, &mut samples, looped)?; let end = wav_len_samples - super::samples::remaining(reader); let samples_range = start..end; - let prepared_buffer = PreparedBuffer { samples, samples_range }; + let prepared_buffer = PreparedBuffer { + samples, + samples_range, + }; prepared_buffers.push_back(prepared_buffer); Ok(()) @@ -438,14 +459,13 @@ fn fill_buffer( fn read_next_sample_cycled( reader: &mut WavReader, spec: &hound::WavSpec, -) -> Result -{ +) -> Result { loop { match read_next_sample(reader, spec)? { Some(sample) => return Ok(sample), None => { reader.seek(0)?; - }, + } } } } @@ -456,8 +476,7 @@ fn read_next_sample_cycled( fn read_next_sample( reader: &mut WavReader, spec: &hound::WavSpec, -) -> Result, hound::Error> -{ +) -> Result, hound::Error> { // A macro to simplify requesting and returning the next sample. macro_rules! next_sample { ($T:ty) => {{ @@ -478,7 +497,7 @@ fn read_next_sample( "Unsupported bit depth {} - currently only 8, 16 and 32 are supported", spec.bits_per_sample ); - }, + } } return Ok(None); } @@ -487,7 +506,7 @@ fn read_next_sample( /// Runs the wav reader thread and returns a handle to it that may be used to play or seek sounds /// via their unique `Id`. pub fn spawn() -> Handle { - let queue = Arc::new(MsQueue::new()); + let queue = Arc::new(SegQueue::new()); let tx = queue.clone(); let rx = queue; let tx2 = tx.clone(); @@ -530,14 +549,14 @@ fn run(tx: Tx, rx: Rx) { } loop { - let msg = rx.pop(); + let msg = rx.pop().unwrap_or(Message::Exit); match msg { // Enqueue a play message for one of the child threads to process. Message::Play(sound_id, play) => { model.sounds.insert(sound_id, SoundState::Processing); let child_msg = ChildMessage::Play(sound_id, play); child_message_queue.push(child_msg); - }, + } // Insert the `Play`ed sound into the map so that we may track its state. Message::PlayComplete(sound_id, sound) => { @@ -549,7 +568,7 @@ fn run(tx: Tx, rx: Rx) { let msg = Message::NextBuffer(sound_id, vec![]); model.tx.push(msg); } - }, + } // Queue the sound ready for one of the children to process the next buffer. Message::NextBuffer(sound_id, buffer) => { @@ -560,31 +579,31 @@ fn run(tx: Tx, rx: Rx) { SoundState::Processing => { let msg = Message::NextBuffer(sound_id, buffer); model.tx.push(msg); - }, + } // If the sound was waiting, send it to a child thread for processing. SoundState::Waiting(sound) => { let child_msg = ChildMessage::NextBuffer(sound_id, sound, buffer); child_message_queue.push(child_msg); - }, + } } - }, + } // Insert the sound back into the map ready for processing. Message::NextBufferComplete(sound_id, sound) => { let state = get_mut_sound_or_continue!(sound_id); *state = SoundState::Waiting(sound); - }, + } // End the given sound by removing it from the map, dropping the reader and in turn // closing the underlying WAV file handle. Message::End(sound_id) => { mem::drop(model.sounds.remove(&sound_id)); - }, + } // Break from waiting on messages as the program has exited. Message::Exit => { break; - }, + } } } } @@ -593,14 +612,14 @@ fn run(tx: Tx, rx: Rx) { /// the parent thread in their processed form. fn run_child(child_msg_queue: Arc, parent_tx: Tx) { loop { - let msg = child_msg_queue.pop(); + let msg = child_msg_queue.pop().unwrap(); // TODO (ando: 2022-06-09): check if unwrap logic is correct match msg { // Play the given sound and return the resulting `Sound` to the parent. ChildMessage::Play(sound_id, play) => { let sound = play_sound(play); let msg = Message::PlayComplete(sound_id, sound); parent_tx.push(msg); - }, + } // Process the next buffer and return the resulting `Sound` to the parent thread. ChildMessage::NextBuffer(sound_id, mut sound, buffer) => { @@ -608,7 +627,7 @@ fn run_child(child_msg_queue: Arc, parent_tx: Tx) { .expect("failed to process next buffer"); let msg = Message::NextBufferComplete(sound_id, sound); parent_tx.push(msg); - }, + } } } } diff --git a/src/lib/audio/source/wav/samples.rs b/src/lib/audio/source/wav/samples.rs index c0c8ef7..5362f97 100644 --- a/src/lib/audio/source/wav/samples.rs +++ b/src/lib/audio/source/wav/samples.rs @@ -1,18 +1,18 @@ use hound; -use nannou_audio::sample::{FromSample, Sample}; +use nannou_audio::dasp_sample::{FromSample, Sample}; use std::io; /// Retrieve the next sample from the given wav reader samples iterator and yield it in the sample /// format type `S`. -pub fn next<'a, R, H, S>(samples: &mut hound::WavSamples<'a, R, H>) -> Option> +pub fn next<'a, R, H, S>( + samples: &mut hound::WavSamples<'a, R, H>, +) -> Option> where H: hound::Sample + Sample, S: Sample + FromSample, hound::WavSamples<'a, R, H>: Iterator>, { - samples - .next() - .map(|r| r.map(Sample::to_sample)) + samples.next().map(|r| r.map(Sample::to_sample)) } /// The number of remaining samples in the reader from its current position. diff --git a/src/lib/audio/speaker.rs b/src/lib/audio/speaker.rs index bebbcbe..f282edc 100644 --- a/src/lib/audio/speaker.rs +++ b/src/lib/audio/speaker.rs @@ -1,8 +1,9 @@ -use audio; +use crate::audio; +use crate::installation; use fxhash::FxHashSet; -use installation; -use metres::Metres; -use nannou::geom::Point2; +use nannou::glam::DVec2 as Point2; +use serde::Deserialize; +use serde::Serialize; #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Deserialize, Serialize)] pub struct Id(pub u64); @@ -13,7 +14,7 @@ pub struct Id(pub u64); #[derive(Clone, Debug, Deserialize, Serialize)] pub struct Speaker { // The location of the speaker within the space. - pub point: Point2, + pub point: Point2, // The channel on which the output is rendered. pub channel: usize, // Installations assigned to this speaker. @@ -25,8 +26,7 @@ pub struct Speaker { pub fn dbap_weight( sound_installations: &audio::sound::Installations, speaker_installations: &FxHashSet, -) -> f64 -{ +) -> f64 { match *sound_installations { audio::sound::Installations::All => 1.0, audio::sound::Installations::Set(ref set) => { @@ -34,6 +34,6 @@ pub fn dbap_weight( Some(_) => 1.0, None => 0.0, } - }, + } } } diff --git a/src/lib/camera.rs b/src/lib/camera.rs index 79ed280..7158b53 100644 --- a/src/lib/camera.rs +++ b/src/lib/camera.rs @@ -1,9 +1,9 @@ -use metres::Metres; -use nannou::geom::Point2; -use nannou::ui::Scalar; +use crate::metres::Metres; +use serde::{Deserialize, Serialize}; +type Scalar = f64; /// A 2D camera location in exhibition space. -pub type Point = Point2; +pub type Point = nannou::glam::DVec2; /// Items related to the camera that provides a view of the floorplan. #[derive(Debug, Serialize, Deserialize)] @@ -33,13 +33,13 @@ pub struct Camera { impl Camera { /// Convert from metres to the GUI scalar value. - pub fn metres_to_scalar(&self, Metres(metres): Metres) -> Scalar { + pub fn metres_to_scalar(&self, metres: Metres) -> Scalar { self.zoom * metres * self.floorplan_pixels_per_metre } /// Convert from the GUI scalar value to metres. pub fn scalar_to_metres(&self, scalar: Scalar) -> Metres { - Metres((scalar / self.zoom) / self.floorplan_pixels_per_metre) + ((scalar / self.zoom) / self.floorplan_pixels_per_metre) as Metres } } @@ -48,12 +48,16 @@ impl Default for Camera { let position = default_position(); let zoom = default_zoom(); let floorplan_pixels_per_metre = default_floorplan_pixels_per_metre(); - Camera { position, zoom, floorplan_pixels_per_metre } + Camera { + position, + zoom, + floorplan_pixels_per_metre, + } } } fn default_position() -> Point { - [Metres(0.0), Metres(0.0)].into() + [(0.0), (0.0)].into() } fn default_zoom() -> f64 { diff --git a/src/lib/config.rs b/src/lib/config.rs index 89dcf25..6482420 100644 --- a/src/lib/config.rs +++ b/src/lib/config.rs @@ -1,4 +1,6 @@ -use project; +use serde::{Deserialize, Serialize}; + +use crate::project; use std::ops::Deref; /// Various configuration parameters for a single project. @@ -53,7 +55,7 @@ impl Deref for Config { } mod default { - use project; + use crate::project; use slug::slugify; pub fn project_slug() -> String { slugify(project::default_project_name()) diff --git a/src/lib/gui/control_log.rs b/src/lib/gui/control_log.rs index a60eaec..306e96d 100644 --- a/src/lib/gui/control_log.rs +++ b/src/lib/gui/control_log.rs @@ -1,12 +1,10 @@ -use gui::{collapsible_area, info_text, Gui}; -use nannou::ui::prelude::*; -use project::Project; +use crate::gui::{collapsible_area, info_text, Gui}; +use crate::project::Project; +use nannou_conrod as ui; +use nannou_conrod::prelude::*; +use ui::{color, widget}; -pub fn set( - last_area_id: widget::Id, - gui: &mut Gui, - project: &Project, -) -> widget::Id { +pub fn set(last_area_id: widget::Id, gui: &mut Gui, project: &Project) -> widget::Id { let is_open = gui.state.is_open.control_log; let log_canvas_h = 200.0; let (area, event) = collapsible_area(is_open, "Control Log", gui.ids.side_menu) diff --git a/src/lib/gui/custom_widget/sound.rs b/src/lib/gui/custom_widget/sound.rs index ac55145..37df603 100644 --- a/src/lib/gui/custom_widget/sound.rs +++ b/src/lib/gui/custom_widget/sound.rs @@ -1,15 +1,22 @@ //! A visual representation of a `Sound` for displaying over the floorplan. -use metres::Metres; -use nannou::ui::Color; -use nannou::ui::prelude::*; +use crate::metres::Metres; +use conrod_core::Positionable; +use conrod_core::WidgetCommon; +use conrod_core::WidgetStyle; +use nannou_conrod as ui; use std; -use utils; +use ui::widget_ids; +use ui::Color; +use ui::Colorable; +use ui::FontSize; +use ui::Scalar; +use ui::Widget; #[derive(Clone, WidgetCommon)] pub struct Sound<'a> { #[conrod(common_builder)] - common: widget::CommonBuilder, + common: ui::widget::CommonBuilder, style: Style, // Amplitude per channel. channels: &'a [f32], @@ -46,19 +53,19 @@ pub struct State { } pub fn dimension_metres(amplitude: f32) -> Metres { - let min = Sound::MIN_DIMENSION.0; - let max = Sound::MAX_DIMENSION.0; - Metres(min + (max - min) * amplitude as Scalar) + let min = Sound::MIN_DIMENSION; + let max = Sound::MAX_DIMENSION; + min + (max - min) * amplitude as Scalar } impl<'a> Sound<'a> { - pub const DEFAULT_COLOR: Color = color::BLUE; - pub const MIN_DIMENSION: Metres = Metres(0.5); - pub const MAX_DIMENSION: Metres = Metres(1.0); + pub const DEFAULT_COLOR: Color = ui::color::BLUE; + pub const MIN_DIMENSION: Metres = 0.5; + pub const MAX_DIMENSION: Metres = 1.0; pub fn new(channels: &'a [f32], spread: Scalar, radians: f64, channel_radians: f64) -> Self { Sound { - common: widget::CommonBuilder::default(), + common: ui::widget::CommonBuilder::default(), style: Style::default(), channels, spread, @@ -80,7 +87,7 @@ impl<'a> Widget for Sound<'a> { type Style = Style; type Event = (); - fn init_state(&self, id_gen: widget::id::Generator) -> Self::State { + fn init_state(&self, id_gen: ui::widget::id::Generator) -> Self::State { State { ids: Ids::new(id_gen), } @@ -90,10 +97,10 @@ impl<'a> Widget for Sound<'a> { self.style.clone() } - fn update(self, args: widget::UpdateArgs) -> Self::Event { + fn update(self, args: ui::widget::UpdateArgs) -> Self::Event { use std::f64::consts::PI; - let widget::UpdateArgs { + let ui::widget::UpdateArgs { id, state, style, @@ -115,18 +122,20 @@ impl<'a> Widget for Sound<'a> { let color = style.color(&ui.theme); let color = match ui.widget_input(id).mouse() { - Some(mouse) => if mouse.buttons.left().is_down() { - color.clicked() - } else { - color.highlighted() - }, + Some(mouse) => { + if mouse.buttons.left().is_down() { + color.clicked() + } else { + color.highlighted() + } + } None => color, }; // The circle used as a progress bar for the sound. if let Some(progress) = progress { let section = -progress * PI * 2.0; - widget::Circle::fill(radius) + ui::widget::Circle::fill(radius) .section(section) .offset_radians(PI * 0.5) .x_y(x, y) @@ -138,7 +147,7 @@ impl<'a> Widget for Sound<'a> { // The circle of the sound's source position. let inner_radius = radius * 0.75; - widget::Circle::fill(inner_radius) + ui::widget::Circle::fill(inner_radius) .x_y(x, y) .color(color) .graphics_for(id) @@ -163,7 +172,7 @@ impl<'a> Widget for Sound<'a> { let phase = channel_index as f64 / total_channels as f64; let channel_radians_offset = phase * std::f64::consts::PI * 2.0; let radians = radians + channel_radians_offset; - let (rel_x, rel_y) = utils::rad_mag_to_x_y(radians, spread); + let (rel_x, rel_y) = crate::utils::rad_mag_to_x_y(radians, spread); let x = sound_x + rel_x; let y = sound_y + rel_y; (x, y) @@ -191,7 +200,7 @@ impl<'a> Widget for Sound<'a> { let base_thickness = 1.0; let amp_thickness = amp as f64 * 10.0; let thickness = base_thickness + amp_thickness; - widget::Line::abs([x, y], [ch_x, ch_y]) + ui::widget::Line::abs([x, y], [ch_x, ch_y]) .color(color.alpha(0.5)) .thickness(thickness) .graphics_for(id) @@ -200,7 +209,7 @@ impl<'a> Widget for Sound<'a> { let radius_amp = radius * (amp as f64) * 1.2; let channel_radius = radius * 0.6 + radius_amp; - widget::Circle::fill(channel_radius) + ui::widget::Circle::fill(channel_radius) .x_y(ch_x, ch_y) .color(color) .graphics_for(id) @@ -208,7 +217,7 @@ impl<'a> Widget for Sound<'a> { .set(circle_id, ui); let label = format!("{}", i + 1); - widget::Text::new(&label) + ui::widget::Text::new(&label) .font_size((radius * 0.8) as FontSize) .x_y(ch_x, ch_y + radius / 6.0) .color(color.plain_contrast()) @@ -223,19 +232,19 @@ impl<'a> Widget for Sound<'a> { let br_radians = radians + front_to_back_radians; let bl_radians = radians - front_to_back_radians; let rel_front = { - let (x, y) = utils::rad_mag_to_x_y(radians, tri_radius); + let (x, y) = crate::utils::rad_mag_to_x_y(radians, tri_radius); [x, y] }; let rel_back_right = { - let (x, y) = utils::rad_mag_to_x_y(bl_radians, tri_radius); + let (x, y) = crate::utils::rad_mag_to_x_y(bl_radians, tri_radius); [x, y] }; let rel_back_left = { - let (x, y) = utils::rad_mag_to_x_y(br_radians, tri_radius); + let (x, y) = crate::utils::rad_mag_to_x_y(br_radians, tri_radius); [x, y] }; let points = [rel_front, rel_back_right, rel_back_left]; - widget::Polygon::centred_fill(points.iter().cloned()) + ui::widget::Polygon::centred_fill(points.iter().cloned()) .x_y(x, y) .color(color.plain_contrast().alpha(0.5)) .graphics_for(id) diff --git a/src/lib/gui/installation_editor.rs b/src/lib/gui/installation_editor.rs index 31c02da..4da4e06 100644 --- a/src/lib/gui/installation_editor.rs +++ b/src/lib/gui/installation_editor.rs @@ -1,13 +1,14 @@ -use gui::{self, collapsible_area, Channels, Gui, ProjectState, State}; -use gui::{ITEM_HEIGHT, SMALL_FONT_SIZE}; -use installation; -use nannou::ui; +use crate::gui::{self, collapsible_area, Channels, Gui, ProjectState, State}; +use crate::gui::{ITEM_HEIGHT, SMALL_FONT_SIZE}; +use crate::installation; +use crate::osc; +use crate::project::{self, Project}; +use nannou_conrod as ui; +use nannou_conrod::prelude::*; use nannou_osc::Connected; -use nannou::ui::prelude::*; -use osc; -use project::{self, Project}; -use std::{io, net}; use std::sync::Arc; +use std::{io, net}; +use ui::{color, position, widget, Scalar}; /// Runtime state relevant to the installation editor GUI. #[derive(Default)] @@ -40,8 +41,7 @@ pub fn set( ref ids, channels, state: &mut State { - ref mut is_open, - .. + ref mut is_open, .. }, .. } = *gui; @@ -53,10 +53,7 @@ pub fn set( .. } = *project; let ProjectState { - installation_editor: - InstallationEditor { - ref mut selected, - }, + installation_editor: InstallationEditor { ref mut selected }, .. } = *project_state; @@ -78,19 +75,27 @@ pub fn set( let computer_canvas_h = ITEM_HEIGHT + PAD + ITEM_HEIGHT + PAD + COMPUTER_LIST_HEIGHT; let soundscape_canvas_h = PAD + PAD * 3.0 + PAD + SLIDER_H + PAD; let selected_canvas_h = PAD - + NAME_H + PAD - + computer_canvas_h + PAD - + osc_canvas_h + PAD - + soundscape_canvas_h + PAD; + + NAME_H + + PAD + + computer_canvas_h + + PAD + + osc_canvas_h + + PAD + + soundscape_canvas_h + + PAD; // The total height of the installation editor as a sum of the previous heights plus necessary // padding. let installation_editor_h = LIST_HEIGHT + ADD_H + selected_canvas_h; - let (area, event) = collapsible_area(is_open.installation_editor, "Installation Editor", ids.side_menu) - .align_middle_x_of(ids.side_menu) - .down_from(last_area_id, 0.0) - .set(ids.installation_editor, ui); + let (area, event) = collapsible_area( + is_open.installation_editor, + "Installation Editor", + ids.side_menu, + ) + .align_middle_x_of(ids.side_menu) + .down_from(last_area_id, 0.0) + .set(ids.installation_editor, ui); if let Some(event) = event { is_open.installation_editor = event.is_open(); } @@ -120,7 +125,11 @@ pub fn set( let name = installation.name.clone(); installations.insert(id, installation); let selected_computer = None; - *selected = Some(Selected { id, name, selected_computer }); + *selected = Some(Selected { + id, + name, + selected_computer, + }); // Update the soundscape thread. channels @@ -171,11 +180,12 @@ pub fn set( let mut maybe_remove_index = None; // The index of the selected installation. - let selected_index = selected.as_ref() + let selected_index = selected + .as_ref() .and_then(|s| installations_vec.iter().position(|&id| id == s.id)); while let Some(event) = events.next(ui, |i| selected_index == Some(i)) { - use nannou::ui::widget::list_select::Event; + use widget::list_select::Event; match event { // Instantiate a button for each installation. Event::Item(item) => { @@ -202,12 +212,14 @@ pub fn set( // If the button or any of its children are capturing the mouse, display // the `remove` button. - let show_remove_button = ui.global_input() + let show_remove_button = ui + .global_input() .current .widget_capturing_mouse .map(|id| { id == item.widget_id - || ui.widget_graph() + || ui + .widget_graph() .does_recursive_depth_edge_exist(item.widget_id, id) }) .unwrap_or(false); @@ -313,7 +325,8 @@ pub fn set( .y(selected_canvas_y.middle()) .align_middle_x_of(ids.side_menu) .set(ids.installation_editor_selected_canvas, ui); - let selected_canvas_kid_area = ui.kid_area_of(ids.installation_editor_selected_canvas) + let selected_canvas_kid_area = ui + .kid_area_of(ids.installation_editor_selected_canvas) .unwrap(); // If an installation is selected, display the installation computer canvas. @@ -346,7 +359,7 @@ pub fn set( .mid_top_of(ids.installation_editor_selected_canvas) .set(ids.installation_editor_name, ui) { - use nannou::ui::widget::text_box::Event; + use widget::text_box::Event; match event { Event::Update(s) => *name = s, Event::Enter => { @@ -367,7 +380,7 @@ pub fn set( let msg = osc::output::Message::Osc(update); channels.osc_out_msg_tx.push(msg); } - }, + } } } @@ -405,11 +418,14 @@ pub fn set( .kid_area_w_of(ids.installation_editor_soundscape_canvas) .h(SLIDER_H) .label_font_size(SMALL_FONT_SIZE) - .color(ui::color::LIGHT_CHARCOAL) + .color(color::LIGHT_CHARCOAL) .align_left() .label(&label) .down(PAD * 2.0) - .set(ids.installation_editor_soundscape_simultaneous_sounds_slider, ui) + .set( + ids.installation_editor_soundscape_simultaneous_sounds_slider, + ui, + ) { let num = value as usize; @@ -419,7 +435,7 @@ pub fn set( match edge { widget::range_slider::Edge::Start => { installation.soundscape.simultaneous_sounds.min = num; - }, + } widget::range_slider::Edge::End => { installation.soundscape.simultaneous_sounds.max = num; } @@ -490,7 +506,7 @@ pub fn set( Err(err) => { eprintln!("failed to connect localhost OSC sender: {}", err); break; - }, + } }; let target = osc::output::TargetSource::New(osc_tx); let add = osc::output::OscTarget::Add(id, computer, target, osc_addr.clone()); @@ -539,7 +555,7 @@ pub fn set( while let Some(event) = events.next(ui, |i| { selected_computer.as_ref().map(|s| s.computer) == Some(installation::computer::Id(i)) }) { - use self::ui::widget::list_select::Event; + use widget::list_select::Event; match event { // Instantiate a button for each computer. Event::Item(item) => { @@ -619,8 +635,8 @@ pub fn set( Ok(s) => s, Err(_) => { eprintln!("could not parse socket string"); - return - }, + return; + } }; // Check for an existing sender using this socket. @@ -643,7 +659,7 @@ pub fn set( Ok(osc_tx) => { let osc_tx = Arc::new(osc_tx); osc::output::TargetSource::New(osc_tx) - }, + } Err(err) => { eprintln!("could not connect osc_sender: {}", err); return; @@ -683,7 +699,7 @@ pub fn set( .color(color) .set(ids.installation_editor_osc_ip_text_box, ui) { - use nannou::ui::widget::text_box::Event; + use widget::text_box::Event; match event { Event::Enter => { update_addr(id, &selected_computer, channels, installations); @@ -704,7 +720,7 @@ pub fn set( .font_size(SMALL_FONT_SIZE) .set(ids.installation_editor_osc_address_text_box, ui) { - use nannou::ui::widget::text_box::Event; + use widget::text_box::Event; match event { Event::Enter => { update_addr(id, &selected_computer, channels, installations); diff --git a/src/lib/gui/master.rs b/src/lib/gui/master.rs index acad8c5..c5129e2 100644 --- a/src/lib/gui/master.rs +++ b/src/lib/gui/master.rs @@ -1,12 +1,12 @@ //! A "Master" side-bar widget providing control over master volume and input latency. -use gui::{collapsible_area, Gui}; -use gui::{ITEM_HEIGHT, SMALL_FONT_SIZE}; -use project::{self, Project}; -use nannou::ui; -use nannou::ui::prelude::*; +use crate::gui::{collapsible_area, Gui}; +use crate::gui::{ITEM_HEIGHT, SMALL_FONT_SIZE}; +use crate::project::{self, Project}; +use nannou_conrod as ui; +use nannou_conrod::prelude::*; use time_calc::Ms; -use metres::Metres; +use ui::{widget, Scalar}; pub fn set(last_area_id: widget::Id, gui: &mut Gui, project: &mut Project) -> widget::Id { let Gui { @@ -18,10 +18,7 @@ pub fn set(last_area_id: widget::Id, gui: &mut Gui, project: &mut Project) -> wi .. } = *gui; let Project { - state: project::State { - ref mut master, - .. - }, + state: project::State { ref mut master, .. }, .. } = *project; @@ -31,7 +28,8 @@ pub fn set(last_area_id: widget::Id, gui: &mut Gui, project: &mut Project) -> wi const LATENCY_H: Scalar = ITEM_HEIGHT; const DECIBEL_H: Scalar = ITEM_HEIGHT; const PROXIMITY_H: Scalar = ITEM_HEIGHT; - const MASTER_H: Scalar = PAD + MASTER_VOLUME_H + PAD + LATENCY_H + PAD + DECIBEL_H + PAD + PROXIMITY_H + PAD; + const MASTER_H: Scalar = + PAD + MASTER_VOLUME_H + PAD + LATENCY_H + PAD + DECIBEL_H + PAD + PROXIMITY_H + PAD; // The collapsible area widget. let is_open = state.is_open.master; @@ -108,7 +106,10 @@ pub fn set(last_area_id: widget::Id, gui: &mut Gui, project: &mut Project) -> wi } // The realtime source latency slider. - let label = format!("Realtime Source Latency: {:.2} ms", master.realtime_source_latency.ms()); + let label = format!( + "Realtime Source Latency: {:.2} ms", + master.realtime_source_latency.ms() + ); let max_latency_ms = 2_000.0; let ms = master.realtime_source_latency.ms(); for new_latency in widget::Slider::new(ms, 0.0, max_latency_ms) @@ -155,11 +156,14 @@ pub fn set(last_area_id: widget::Id, gui: &mut Gui, project: &mut Project) -> wi }) .expect("failed to send updated DBAP rolloff to audio output thread"); } - + // The proximity slider. // Proximity limit is stored as a squared value so sqrt() is called here - let label = format!("Proximity Limit: {:.2} metres", master.proximity_limit_2.0.sqrt()); - for new_proximity in widget::Slider::new(master.proximity_limit_2.0.sqrt(), 0.0, 10.0) + let label = format!( + "Proximity Limit: {:.2} metres", + master.proximity_limit_2.sqrt() + ); + for new_proximity in widget::Slider::new(master.proximity_limit_2.sqrt(), 0.0, 10.0) .label(&label) .label_font_size(SMALL_FONT_SIZE) .h(PROXIMITY_H) @@ -167,20 +171,19 @@ pub fn set(last_area_id: widget::Id, gui: &mut Gui, project: &mut Project) -> wi .align_middle_x_of(area.id) .down(PAD) .set(ids.master_proximity_limit, ui) - { - // Update the local rolloff. - master.proximity_limit_2 = Metres(new_proximity * new_proximity); - - // Update the audio output thread's rolloff. - channels - .audio_output - .send(move |audio| { - // The proximity squared (for more efficient distance comparisons). - audio.proximity_limit_2 = Metres(new_proximity * new_proximity); - }) - .expect("failed to send updated proximity limit to audio output thread"); - } + { + // Update the local rolloff. + master.proximity_limit_2 = new_proximity * new_proximity; + // Update the audio output thread's rolloff. + channels + .audio_output + .send(move |audio| { + // The proximity squared (for more efficient distance comparisons). + audio.proximity_limit_2 = new_proximity * new_proximity; + }) + .expect("failed to send updated proximity limit to audio output thread"); + } area.id } diff --git a/src/lib/gui/mod.rs b/src/lib/gui/mod.rs index a4572ec..54da3f6 100644 --- a/src/lib/gui/mod.rs +++ b/src/lib/gui/mod.rs @@ -1,25 +1,27 @@ -use audio; -use camera::Camera; -use config::Config; +use crate::audio; +use crate::camera::Camera; +use crate::config::Config; +use crate::metres::Metres; +use crate::osc; +use crate::osc::input::Log as OscInputLog; +use crate::osc::output::Log as OscOutputLog; +use crate::project::{self, Project}; +use crate::soundscape::Soundscape; +use crate::utils::{self, HumanReadableTime, HR_MS, MIN_MS, SEC_MS}; use fxhash::FxHashMap; -use metres::Metres; use nannou; use nannou::prelude::*; -use nannou::ui; -use nannou::ui::prelude::*; -use osc; -use osc::input::Log as OscInputLog; -use osc::output::Log as OscOutputLog; -use project::{self, Project}; -use soundscape::Soundscape; +use nannou::wgpu::TextureUsages; +use nannou_conrod as ui; +use nannou_conrod::prelude::*; use slug::slugify; use std::collections::VecDeque; -use std::path::{Path, PathBuf}; use std::ops::{Deref, DerefMut}; -use std::sync::{mpsc, Arc}; +use std::path::{Path, PathBuf}; use std::sync::atomic::AtomicUsize; +use std::sync::{mpsc, Arc}; use time_calc::Ms; -use utils::{self, HumanReadableTime, SEC_MS, MIN_MS, HR_MS}; +use ui::{color, image, widget, widget_ids, FontSize, Scalar, Ui, UiCell}; use self::installation_editor::InstallationEditor; use self::project_editor::ProjectEditor; @@ -27,19 +29,20 @@ use self::soundscape_editor::SoundscapeEditor; use self::source_editor::{SourceEditor, SourcePreviewMode}; use self::speaker_editor::SpeakerEditor; +pub mod control_log; mod custom_widget; pub mod installation_editor; -pub mod control_log; pub mod master; pub mod monitor; pub mod osc_in_log; pub mod osc_out_log; pub mod project_editor; -pub mod source_editor; pub mod soundscape_editor; +pub mod source_editor; pub mod speaker_editor; mod theme; +type Point2 = nannou::glam::DVec2; type ActiveSoundMap = FxHashMap; /// The structure of the GUI. @@ -146,7 +149,7 @@ pub struct Channels { #[derive(Clone, Copy, Debug)] struct Image { - id: ui::image::Id, + id: image::Id, width: Scalar, height: Scalar, } @@ -189,8 +192,10 @@ impl AudioMonitor { /// removed. /// - All `Speaker`s that have a `speaker::Id` that cannot be found in the project are removed. pub fn clear_invalid(&mut self, project: &Project) { - self.active_sounds.retain(|_, s| project.sources.contains_key(&s.source_id)); - self.speakers.retain(|id, _| project.speakers.contains_key(id)); + self.active_sounds + .retain(|_, s| project.sources.contains_key(&s.source_id)); + self.speakers + .retain(|id, _| project.speakers.contains_key(id)); } } @@ -278,9 +283,8 @@ impl Model { audio_input_channels: usize, audio_output_channels: usize, ) -> Self { - // Load a Nannou UI. - let mut ui = app.new_ui() + let mut ui = ui::builder(app) .window(window_id) .with_theme(theme::construct()) .build() @@ -301,18 +305,20 @@ impl Model { let floorplan_path = images_directory(assets).join("floorplan.png"); let floorplan_texture = { let window = app.window(window_id).expect("window closed unexpectedly"); - let device = window.swap_chain_device(); + let device = window.device(); let image = nannou::image::open(floorplan_path).unwrap(); - let image_rgba = image.into_rgba(); + let image_rgba = image.into_rgba8(); // The wgpu device queue used to load the image data. - let mut queue = window.swap_chain_queue().lock().unwrap(); + let mut queue = window.queue(); // Describe how we will use the texture so that the GPU may handle it efficiently. - let usage = wgpu::TextureUsage::SAMPLED; - wgpu::Texture::load_from_image_buffer(device, &mut *queue, usage, &image_rgba) + let usage = TextureUsages::TEXTURE_BINDING; + wgpu::Texture::load_from_image_buffer(device, &mut queue, usage, &image_rgba) }; let [width, height] = floorplan_texture.size(); let [width, height] = [width as f64, height as f64]; - let id = ui.image_map.insert(floorplan_texture.into_ui_image()); + let id = ui + .image_map + .insert(nannou_conrod::image_from_texture(floorplan_texture)); let floorplan = Image { id, width, height }; let images = Images { floorplan }; @@ -408,7 +414,7 @@ impl Model { .audio_output .send(move |audio| audio.master_volume = volume) .expect("failed to send updated master volume to audio output thread"); - }, + } &osc::input::Control::SourceVolume(ref source_volume) => { let osc::input::SourceVolume { ref name, volume } = *source_volume; @@ -429,7 +435,7 @@ impl Model { Some((&id, ref mut source)) => { source.volume = volume; id - }, + } }; // Update the soundscape copy. @@ -472,7 +478,7 @@ impl Model { // Update the map of active sounds. loop { - let msg = match channels.audio_monitor_msg_rx.try_pop() { + let msg = match channels.audio_monitor_msg_rx.pop() { None => break, Some(msg) => msg, }; @@ -480,7 +486,7 @@ impl Model { match msg { AudioMonitorMessage::Master { peak } => { audio_monitor.master_peak = peak; - }, + } AudioMonitorMessage::ActiveSound(id, msg) => match msg { ActiveSoundMessage::Start { source_id, @@ -488,12 +494,8 @@ impl Model { channels, normalised_progress, } => { - let active_sound = ActiveSound::new( - source_id, - position, - channels, - normalised_progress, - ); + let active_sound = + ActiveSound::new(source_id, position, channels, normalised_progress); audio_monitor.active_sounds.insert(id, active_sound); } ActiveSoundMessage::Update { @@ -502,10 +504,8 @@ impl Model { channels, normalised_progress, } => { - let active_sound = audio_monitor - .active_sounds - .entry(id) - .or_insert_with(|| { + let active_sound = + audio_monitor.active_sounds.entry(id).or_insert_with(|| { ActiveSound::new(source_id, position, channels, normalised_progress) }); active_sound.position = position; @@ -563,18 +563,26 @@ impl Model { if let ui::event::Ui::Press(_, press) = *event { match press.button { ui::event::Button::Keyboard(ui::input::Key::S) => { - let save_mod = - press.modifiers.contains(ui::input::keyboard::ModifierKey::CTRL) - || press.modifiers.contains(ui::input::keyboard::ModifierKey::GUI); + let save_mod = press + .modifiers + .contains(ui::input::keyboard::ModifierKey::CTRL) + || press + .modifiers + .contains(ui::input::keyboard::ModifierKey::GUI); if save_mod { if let Some((ref project, _)) = *project { - project.save(assets).expect("failed to save project on keyboard shortcut"); + project + .save(assets) + .expect("failed to save project on keyboard shortcut"); } } } ui::event::Button::Keyboard(ui::input::Key::Space) => { - if press.modifiers.contains(ui::input::keyboard::ModifierKey::CTRL) { + if press + .modifiers + .contains(ui::input::keyboard::ModifierKey::CTRL) + { *cpu_saving_mode = !*cpu_saving_mode; // Notify audio output thread. @@ -622,7 +630,9 @@ impl Model { /// If a project is currently selected, this returns its directory path slug. pub fn selected_project_slug(&self) -> Option { - self.project.as_ref().map(|&(ref project, _)| slugify(&project.name)) + self.project + .as_ref() + .map(|&(ref project, _)| slugify(&project.name)) } } @@ -1045,19 +1055,19 @@ pub fn hz_label(hz: f64) -> String { match utils::human_readable_hz(hz) { (HumanReadableTime::Ms, times_per_ms) => { format!("{} per millisecond", times_per_ms.round()) - }, + } (HumanReadableTime::Secs, hz) => { format!("{} per second", hz.round()) - }, + } (HumanReadableTime::Mins, times_per_min) => { format!("{} per minute", times_per_min.round()) - }, + } (HumanReadableTime::Hrs, times_per_hr) => { format!("{} per hour", times_per_hr.round()) - }, + } (HumanReadableTime::Days, times_per_day) => { format!("{} per day", times_per_day.round()) - }, + } } } @@ -1067,25 +1077,25 @@ pub fn duration_label(ms: &Ms) -> String { match utils::human_readable_ms(ms) { (HumanReadableTime::Ms, ms) => { format!("{} ms", ms) - }, + } (HumanReadableTime::Secs, secs) => { let secs = secs.floor(); let ms = ms.ms() - (secs * SEC_MS); format!("{} secs {} ms", secs, ms) - }, + } (HumanReadableTime::Mins, mins) => { let mins = mins.floor(); let secs = (ms.ms() - (mins * MIN_MS)) / SEC_MS; format!("{} mins {} secs", mins, secs) - }, + } (HumanReadableTime::Hrs, hrs) => { let hrs = hrs.floor(); let mins = (ms.ms() - (hrs * HR_MS)) / MIN_MS; format!("{} hrs {} mins", hrs, mins) - }, + } (HumanReadableTime::Days, days) => { format!("{} days", days) - }, + } } } @@ -1104,7 +1114,7 @@ fn set_side_menu_widgets( let mut last_area_id = project_editor::set(gui, project, default_project_config); // Many of the sidebar widgets can only be displayed if a project is selected. - if let Some((ref mut project, ref mut project_state)) = *project { + if let Some((project, project_state)) = project { // Installation Editor - for editing installation-specific data. last_area_id = master::set(last_area_id, gui, project); @@ -1205,7 +1215,8 @@ fn set_widgets( let side_menu_w_minus_scrollbar = match side_menu_is_open { false => side_menu_w, true => { - let scrollbar_w = gui.rect_of(gui.ids.side_menu_scrollbar) + let scrollbar_w = gui + .rect_of(gui.ids.side_menu_scrollbar) .map(|r| r.w()) .unwrap_or(0.0); side_menu_w - scrollbar_w @@ -1263,8 +1274,8 @@ fn set_widgets( .set(gui.ids.floorplan_canvas, gui); let floorplan_pixels_per_metre = project.config.floorplan_pixels_per_metre; - let metres_from_floorplan_pixels = |px| Metres(px / floorplan_pixels_per_metre); - let metres_to_floorplan_pixels = |Metres(m)| m * floorplan_pixels_per_metre; + let metres_from_floorplan_pixels = |px: Metres| px / floorplan_pixels_per_metre; + let metres_to_floorplan_pixels = |m: Metres| m * floorplan_pixels_per_metre; let floorplan_w_metres = metres_from_floorplan_pixels(gui.images.floorplan.width); let floorplan_h_metres = metres_from_floorplan_pixels(gui.images.floorplan.height); @@ -1277,7 +1288,8 @@ fn set_widgets( let floorplan_h = full_scale_h * gui.images.floorplan.height; // If the floorplan was scrolled, adjust the camera zoom. - let total_scroll = gui.widget_input(gui.ids.floorplan) + let total_scroll = gui + .widget_input(gui.ids.floorplan) .scrolls() .fold(0.0, |acc, scroll| acc + scroll.y); project.state.camera.zoom = (project.state.camera.zoom - total_scroll / 200.0) @@ -1285,7 +1297,8 @@ fn set_widgets( .min(1.0); // Move the camera by clicking with the left mouse button and dragging. - let total_drag = gui.widget_input(gui.ids.floorplan) + let total_drag = gui + .widget_input(gui.ids.floorplan) .drags() .left() .map(|drag| drag.delta_xy) @@ -1308,13 +1321,15 @@ fn set_widgets( let max_cam_x_m = centre_x_m + half_invisible_w_m; let min_cam_y_m = centre_y_m - half_invisible_h_m; let max_cam_y_m = centre_y_m + half_invisible_h_m; - project.state.camera.position.x = project.state + project.state.camera.position.x = project + .state .camera .position .x .max(min_cam_x_m) .min(max_cam_x_m); - project.state.camera.position.y = project.state + project.state.camera.position.y = project + .state .camera .position .y @@ -1328,7 +1343,8 @@ fn set_widgets( let visible_rect = ui::Rect::from_xy_dim([visible_x, visible_y], [visible_w, visible_h]); // If the left mouse button was clicked on the floorplan, deselect the speaker. - if gui.widget_input(gui.ids.floorplan) + if gui + .widget_input(gui.ids.floorplan) .clicks() .left() .next() @@ -1371,14 +1387,14 @@ fn set_widgets( // Convert the given position in metres to a gui Scalar position relative to the middle of the // floorplan. - fn position_metres_to_floorplan(p: Point2, cam: &Camera) -> (Scalar, Scalar) { + fn position_metres_to_floorplan(p: Point2, cam: &Camera) -> (Scalar, Scalar) { let x = x_position_metres_to_floorplan(p.x, cam); let y = y_position_metres_to_floorplan(p.y, cam); (x, y) - }; + } // Convert the given position in metres to an absolute GUI scalar position. - let position_metres_to_gui = |p: Point2, cam: &Camera| -> (Scalar, Scalar) { + let position_metres_to_gui = |p: Point2, cam: &Camera| -> (Scalar, Scalar) { let (x, y) = position_metres_to_floorplan(p, cam); (floorplan_xy[0] + x, floorplan_xy[1] + y) }; @@ -1402,11 +1418,12 @@ fn set_widgets( } = *gui; let Project { - state: project::State { - ref camera, - ref mut speakers, - .. - }, + state: + project::State { + ref camera, + ref mut speakers, + .. + }, .. } = *project; @@ -1432,7 +1449,8 @@ fn set_widgets( _ => 0.0, }; - let (dragged_x, dragged_y) = ui.widget_input(widget_id) + let (dragged_x, dragged_y) = ui + .widget_input(widget_id) .drags() .left() .fold((0.0, 0.0), |(x, y), drag| { @@ -1445,7 +1463,7 @@ fn set_widgets( let p = speaker.audio.point; let x = p.x + dragged_x_m; let y = p.y + dragged_y_m; - let new_p = Point2 { x, y }; + let new_p = Point2::new(x, y); if p != new_p { // Update the local copy. speaker.audio.point = new_p; @@ -1473,7 +1491,8 @@ fn set_widgets( let (x, y) = position_metres_to_gui(position, camera); // Select the speaker if it was pressed. - if ui.widget_input(widget_id) + if ui + .widget_input(widget_id) .presses() .mouse() .left() @@ -1494,11 +1513,13 @@ fn set_widgets( } }; let color = match ui.widget_input(widget_id).mouse() { - Some(mouse) => if mouse.buttons.left().is_down() { - color.clicked() - } else { - color.highlighted() - }, + Some(mouse) => { + if mouse.buttons.left().is_down() { + color.clicked() + } else { + color.highlighted() + } + } None => color, }; @@ -1547,7 +1568,8 @@ fn set_widgets( // TODO: There should be an Id per active sound. if ids.floorplan_sounds.len() <= i { - ids.floorplan_sounds.resize(i + 1, &mut ui.widget_id_generator()); + ids.floorplan_sounds + .resize(i + 1, &mut ui.widget_id_generator()); } let sound_widget_id = ids.floorplan_sounds[i]; @@ -1564,7 +1586,8 @@ fn set_widgets( }; // Determine how far the source preview has been dragged, if at all. - let (dragged_x, dragged_y) = ui.widget_input(sound_widget_id) + let (dragged_x, dragged_y) = ui + .widget_input(sound_widget_id) .drags() .left() .fold((0.0, 0.0), |(x, y), drag| { @@ -1577,7 +1600,7 @@ fn set_widgets( let position = { let x = point.x + dragged_x_m; let y = point.y + dragged_y_m; - let new_p = Point2 { x, y }; + let new_p = Point2::new(x, y); if point != new_p { // Update the local copy. project_state.source_editor.preview.point = Some(new_p); @@ -1619,13 +1642,14 @@ fn set_widgets( let channel_count = source.audio.channel_count(); let position = active_sound.position; let soloed = &project.state.sources.soloed; - let mut color = if source.audio.muted || (!soloed.is_empty() && !soloed.contains(&id)) { - color::LIGHT_CHARCOAL - } else if soloed.contains(&id) { - color::DARK_YELLOW - } else { - color::DARK_BLUE - }; + let mut color = + if source.audio.muted || (!soloed.is_empty() && !soloed.contains(&id)) { + color::LIGHT_CHARCOAL + } else if soloed.contains(&id) { + color::DARK_YELLOW + } else { + color::DARK_BLUE + }; // If the source editor is open and this sound is selected, highlight it. if state.is_open.source_editor { @@ -1639,13 +1663,7 @@ fn set_widgets( } } - ( - spread, - channel_radians, - channel_count, - position, - color, - ) + (spread, channel_radians, channel_count, position, color) } }; @@ -1653,7 +1671,8 @@ fn set_widgets( let side_m = custom_widget::sound::dimension_metres(0.0); let side = project.state.camera.metres_to_scalar(side_m); let channel_amps = &channel_amplitudes[..channel_count]; - let installations = project.state + let installations = project + .state .sources .iter() .find(|&(&id, _)| id == active_sound.source_id) @@ -1662,11 +1681,13 @@ fn set_widgets( // Determine the line colour by checking for interactions with the sound. let line_color = match ui.widget_input(sound_widget_id).mouse() { - Some(mouse) => if mouse.buttons.left().is_down() { - color.clicked() - } else { - color.highlighted() - }, + Some(mouse) => { + if mouse.buttons.left().is_down() { + color.clicked() + } else { + color.highlighted() + } + } None => color, }; @@ -1685,7 +1706,7 @@ fn set_widgets( // A function for finding all speakers within proximity of a sound channel. fn find_speakers_in_proximity( // The location of the source channel. - point: &Point2, + point: &Point2, // Installations that the current sound is applied to. installations: &audio::sound::Installations, // All speakers. @@ -1703,31 +1724,29 @@ fn set_widgets( let (ids, dbap_speakers): (Vec, Vec) = { // The location of the sound. - let point_f = Point2 { - x: point.x.0, - y: point.y.0, - }; + let point_f = Point2::new(point.x, point.y); let mut iter = speakers.iter(); iter.next() .map(|(&id, speaker)| { // The function used to create the dbap speakers. - let dbap_speaker = |speaker: &project::Speaker| -> audio::dbap::Speaker { - let speaker_f = Point2 { - x: speaker.audio.point.x.0, - y: speaker.audio.point.y.0, + let dbap_speaker = + |speaker: &project::Speaker| -> audio::dbap::Speaker { + let speaker_f = Point2::new( + speaker.audio.point.x, + speaker.audio.point.y, + ); + let distance = audio::dbap::blurred_distance_2( + point_f, + speaker_f, + audio::DISTANCE_BLUR, + ); + let weight = audio::speaker::dbap_weight( + installations, + &speaker.audio.installations, + ); + audio::dbap::Speaker { distance, weight } }; - let distance = audio::dbap::blurred_distance_2( - point_f, - speaker_f, - audio::DISTANCE_BLUR, - ); - let weight = audio::speaker::dbap_weight( - installations, - &speaker.audio.installations, - ); - audio::dbap::Speaker { distance, weight } - }; let init = (vec![id], vec![dbap_speaker(speaker)]); iter.fold(init, |(mut ids, mut speakers), (&id, s)| { @@ -1742,8 +1761,11 @@ fn set_widgets( in_proximity.clear(); for (i, gain) in gains.enumerate() { let id = ids[i]; - if audio::output::speaker_is_in_proximity(point, &speakers[&id].audio.point, - proximity_limit_2) { + if audio::output::speaker_is_in_proximity( + point, + &speakers[&id].audio.point, + proximity_limit_2, + ) { in_proximity.push((gain as f32, id)); } } diff --git a/src/lib/gui/monitor.rs b/src/lib/gui/monitor.rs index 6c12ca0..6033049 100644 --- a/src/lib/gui/monitor.rs +++ b/src/lib/gui/monitor.rs @@ -6,15 +6,15 @@ //! not require performing some kind of I/O depending on the platform, in turn taking an //! unpredictable amount of time. -use crossbeam::sync::{MsQueue, SegQueue}; -use gui; +use crate::gui; +use crossbeam::queue::SegQueue; use nannou; use std::io; -use std::sync::Arc; use std::sync::atomic::{self, AtomicBool}; +use std::sync::Arc; use std::thread; -pub type Sender = Arc>; +pub type Sender = Arc>; pub type Receiver = Arc>; pub type Spawned = (Monitor, Sender, Receiver); @@ -40,7 +40,7 @@ impl Monitor { /// Spawn the intermediary monitoring thread and return the communication channels. pub fn spawn(app_proxy: nannou::app::Proxy) -> io::Result { - let audio_queue = Arc::new(MsQueue::new()); + let audio_queue = Arc::new(SegQueue::new()); let audio_tx = audio_queue.clone(); let audio_rx = audio_queue; @@ -59,7 +59,7 @@ pub fn spawn(app_proxy: nannou::app::Proxy) -> io::Result { // waking up. // Attempt to forward every message and wakeup the GUI when successful. 'run: while !is_closed_2.load(atomic::Ordering::Relaxed) { - let msg = audio_rx.pop(); + let msg = audio_rx.pop().unwrap(); gui_tx.push(msg); // Proxy is currently buggy on linux so we only enable this for macos. if cfg!(target_os = "macos") { diff --git a/src/lib/gui/osc_in_log.rs b/src/lib/gui/osc_in_log.rs index 88932e4..a6e405c 100644 --- a/src/lib/gui/osc_in_log.rs +++ b/src/lib/gui/osc_in_log.rs @@ -1,12 +1,10 @@ -use gui::{collapsible_area, info_text, Gui}; -use nannou::ui::prelude::*; -use project::Project; +use crate::gui::{collapsible_area, info_text, Gui}; +use crate::project::Project; +use conrod_core as ui; +use nannou_conrod::prelude::*; +use ui::{color, widget}; -pub fn set( - last_area_id: widget::Id, - gui: &mut Gui, - project: &Project, -) -> widget::Id { +pub fn set(last_area_id: widget::Id, gui: &mut Gui, project: &Project) -> widget::Id { let is_open = gui.state.is_open.osc_in_log; let log_canvas_h = 200.0; let (area, event) = collapsible_area(is_open, "OSC Input Log", gui.ids.side_menu) diff --git a/src/lib/gui/osc_out_log.rs b/src/lib/gui/osc_out_log.rs index 68be428..6a46786 100644 --- a/src/lib/gui/osc_out_log.rs +++ b/src/lib/gui/osc_out_log.rs @@ -1,10 +1,9 @@ -use gui::{collapsible_area, info_text, Gui}; -use nannou::ui::prelude::*; +use crate::gui::{collapsible_area, info_text, Gui}; +use conrod_core as ui; +use nannou_conrod::prelude::*; +use ui::{color, widget}; -pub fn set( - last_area_id: widget::Id, - gui: &mut Gui, -) -> widget::Id { +pub fn set(last_area_id: widget::Id, gui: &mut Gui) -> widget::Id { let is_open = gui.state.is_open.osc_out_log; let log_canvas_h = 200.0; let (area, event) = collapsible_area(is_open, "OSC Output Log", gui.ids.side_menu) diff --git a/src/lib/gui/project_editor.rs b/src/lib/gui/project_editor.rs index dcc0c6a..ac55b50 100644 --- a/src/lib/gui/project_editor.rs +++ b/src/lib/gui/project_editor.rs @@ -1,13 +1,16 @@ //! A "Projects" side-bar widget providing allowing the user to create and remove new projects. -use gui::{collapsible_area, Gui, ProjectState, State, TEXT_PAD, ITEM_HEIGHT, SMALL_FONT_SIZE}; -use project::{self, Project}; -use nannou::ui; -use nannou::ui::prelude::*; -use osc; +use crate::gui::{ + collapsible_area, Gui, ProjectState, State, ITEM_HEIGHT, SMALL_FONT_SIZE, TEXT_PAD, +}; +use crate::osc; +use crate::project::{self, Project}; +use nannou_conrod as ui; +use nannou_conrod::prelude::*; use slug::slugify; use std::fs; use std::path::Path; +use ui::{color, position, widget, Scalar}; /// State related to the project editor GUI. #[derive(Default)] @@ -26,11 +29,12 @@ pub fn set( ref ids, ref channels, ref assets, - state: &mut State { - ref mut is_open, - ref mut project_editor, - .. - }, + state: + &mut State { + ref mut is_open, + ref mut project_editor, + .. + }, .. } = *gui; @@ -58,11 +62,13 @@ pub fn set( area.set(canvas, ui); let button_w = ui.kid_area_of(area.id).unwrap().w() / 3.0; - let button = || widget::Button::new() - .color(super::DARK_A) - .label_font_size(SMALL_FONT_SIZE) - .w(button_w) - .h(BUTTON_H); + let button = || { + widget::Button::new() + .color(super::DARK_A) + .label_font_size(SMALL_FONT_SIZE) + .w(button_w) + .h(BUTTON_H) + }; // Show the plus button at the bottom of the editor. for _click in button() @@ -80,7 +86,9 @@ pub fn set( // Create a new default project. let new_project = Project::new(assets, default_project_config); - new_project.save(assets).expect("failed to create new project directory"); + new_project + .save(assets) + .expect("failed to create new project directory"); new_project.reset_and_sync_all_threads(channels); audio_monitor.clear(); let new_project_state = ProjectState::default(); @@ -105,7 +113,9 @@ pub fn set( // Create a new default project. let mut new_project = old_project; new_project.name = format!("{} copy", new_project.name); - new_project.save(assets).expect("failed to create new project directory"); + new_project + .save(assets) + .expect("failed to create new project directory"); new_project.reset_and_sync_all_threads(channels); audio_monitor.clear(); let new_project_state = ProjectState::default(); @@ -140,7 +150,7 @@ pub fn set( .center_justify() .set(ids.project_editor_none, ui); return area.id; - }, + } }; // If there are no projects, say so! @@ -218,12 +228,14 @@ pub fn set( // If the button or any of its children are capturing the mouse, display // the `remove` button. - let show_remove_button = ui.global_input() + let show_remove_button = ui + .global_input() .current .widget_capturing_mouse .map(|id| { id == item.widget_id - || ui.widget_graph() + || ui + .widget_graph() .does_recursive_depth_edge_exist(item.widget_id, id) }) .unwrap_or(false); @@ -264,14 +276,15 @@ pub fn set( } // Load the project. - let loaded_project = Project::load(assets, &project_directory, default_project_config); + let loaded_project = + Project::load(assets, &project_directory, default_project_config); loaded_project.reset_and_sync_all_threads(channels); audio_monitor.clear(); let loaded_project_state = ProjectState::default(); selected_project_slug = Some(slugify(&loaded_project.name)); project_editor.text_box_name = loaded_project.name.clone(); *project = Some((loaded_project, loaded_project_state)); - }, + } _ => (), } @@ -294,7 +307,11 @@ pub fn set( // Remove the project directory. if let Err(err) = fs::remove_dir_all(&directory) { - eprintln!("failed to remove project directory `{}`: \"{}\"", directory.display(), err); + eprintln!( + "failed to remove project directory `{}`: \"{}\"", + directory.display(), + err + ); } // Select the next project if there is one. @@ -317,15 +334,21 @@ pub fn set( channels .soundscape .send(move |soundscape| soundscape.clear_project_specific_data()) - .expect("failed to send `clear_project_specific_data` message to soundscape thread"); + .expect( + "failed to send `clear_project_specific_data` message to soundscape thread", + ); channels .audio_input .send(move |audio| audio.clear_project_specific_data()) - .expect("failed to send `clear_project_specific_data` message to audio input thread"); + .expect( + "failed to send `clear_project_specific_data` message to audio input thread", + ); channels .audio_output .send(move |audio| audio.clear_project_specific_data()) - .expect("failed to send `clear_project_specific_data` message to audio output thread"); + .expect( + "failed to send `clear_project_specific_data` message to audio output thread", + ); channels .osc_out_msg_tx .push(osc::output::Message::ClearProjectSpecificData); @@ -373,7 +396,8 @@ pub fn set( let projects_directory = project::projects_directory(assets); if is_name_valid(&projects_directory, &project_editor.text_box_name) { let current_dir = projects_directory.join(slugify(&project.name)); - let renamed_dir = projects_directory.join(slugify(&project_editor.text_box_name)); + let renamed_dir = + projects_directory.join(slugify(&project_editor.text_box_name)); if let Err(err) = fs::rename(¤t_dir, &renamed_dir) { eprintln!( "failed to rename \"{}\" to \"{}\": \"{}\"", @@ -386,7 +410,7 @@ pub fn set( } } } - }, + } } } diff --git a/src/lib/gui/soundscape_editor.rs b/src/lib/gui/soundscape_editor.rs index 2aec1a0..78c9b76 100644 --- a/src/lib/gui/soundscape_editor.rs +++ b/src/lib/gui/soundscape_editor.rs @@ -3,14 +3,15 @@ //! - Play/Pause toggle for the soundscape. //! - Groups panel for creating/removing soundscape source groups. -use gui::{collapsible_area, hz_label, Gui, ProjectState, State}; -use gui::{ITEM_HEIGHT, SMALL_FONT_SIZE}; -use project::{self, Project}; -use nannou::ui; -use nannou::ui::prelude::*; -use soundscape; +use crate::gui::{collapsible_area, hz_label, Gui, ProjectState, State}; +use crate::gui::{ITEM_HEIGHT, SMALL_FONT_SIZE}; +use crate::project::{self, Project}; +use crate::soundscape; +use crate::utils; +use nannou_conrod as ui; +use nannou_conrod::prelude::*; use time_calc::Ms; -use utils; +use ui::{color, position, widget, Scalar}; /// GUI state related to the soundscape editor area. #[derive(Default)] @@ -36,8 +37,7 @@ pub fn set( ref ids, channels, state: &mut State { - ref mut is_open, - .. + ref mut is_open, .. }, .. } = gui; @@ -65,16 +65,30 @@ pub fn set( const GROUP_CANVAS_H: Scalar = PAD + TITLE_H + PAD + PLUS_GROUP_H + GROUP_LIST_MAX_H + PAD; const SLIDER_H: Scalar = ITEM_HEIGHT; const SELECTED_CANVAS_H: Scalar = PAD - + TITLE_H + PAD * 2.0 + TEXT_BOX_H + PAD - + TITLE_H + PAD * 2.0 + SLIDER_H + PAD - + TITLE_H + PAD + SLIDER_H + PAD; - let soundscape_editor_canvas_h = PAD + IS_PLAYING_H + PAD + GROUP_CANVAS_H + PAD + SELECTED_CANVAS_H + PAD; + + TITLE_H + + PAD * 2.0 + + TEXT_BOX_H + + PAD + + TITLE_H + + PAD * 2.0 + + SLIDER_H + + PAD + + TITLE_H + + PAD + + SLIDER_H + + PAD; + let soundscape_editor_canvas_h = + PAD + IS_PLAYING_H + PAD + GROUP_CANVAS_H + PAD + SELECTED_CANVAS_H + PAD; // The collapsible area. - let (area, event) = collapsible_area(is_open.soundscape_editor, "Soundscape Editor", ids.side_menu) - .align_middle_x_of(ids.side_menu) - .down_from(last_area_id, 0.0) - .set(ids.soundscape_editor, ui); + let (area, event) = collapsible_area( + is_open.soundscape_editor, + "Soundscape Editor", + ids.side_menu, + ) + .align_middle_x_of(ids.side_menu) + .down_from(last_area_id, 0.0) + .set(ids.soundscape_editor, ui); if let Some(event) = event { is_open.soundscape_editor = event.is_open(); } @@ -86,9 +100,7 @@ pub fn set( }; // The canvas on which the soundscape editor will be placed. - let canvas = widget::Canvas::new() - .pad(PAD) - .h(soundscape_editor_canvas_h); + let canvas = widget::Canvas::new().pad(PAD).h(soundscape_editor_canvas_h); area.set(canvas, ui); // The toggle for whether or not the soundscape should be playing back. @@ -227,12 +239,14 @@ pub fn set( // If the button or any of its children are capturing the mouse, display // the `remove` button. - let show_remove_button = ui.global_input() + let show_remove_button = ui + .global_input() .current .widget_capturing_mouse .map(|id| { id == item.widget_id - || ui.widget_graph() + || ui + .widget_graph() .does_recursive_depth_edge_exist(item.widget_id, id) }) .unwrap_or(false); @@ -254,13 +268,16 @@ pub fn set( { maybe_remove_index = Some(item.i); } - }, + } // Update the selected source. Event::Selection(idx) => { soundscape_editor.selected = { let (id, ref name) = groups_vec[idx]; - Some(Selected { id, name: name.clone() }) + Some(Selected { + id, + name: name.clone(), + }) }; } @@ -300,8 +317,7 @@ pub fn set( // Only continue if there is some selected group. let SoundscapeEditor { - ref mut selected, - .. + ref mut selected, .. } = *soundscape_editor; let selected = match selected.as_mut() { @@ -341,13 +357,13 @@ pub fn set( // When typing generally, only update the temp selected name. Event::Update(new_name) => { selected.name = new_name; - }, + } // Only when enter is pressed do we update the actual name. Event::Enter => { if let Some(group) = soundscape_groups.get_mut(&selected.id) { group.name = selected.name.clone(); } - }, + } } } @@ -399,7 +415,7 @@ pub fn set( widget::range_slider::Edge::Start => { let ms = utils::hz_to_ms_interval(hz); group.occurrence_rate.max = ms; - }, + } widget::range_slider::Edge::End => { let ms = utils::hz_to_ms_interval(hz); group.occurrence_rate.min = ms; @@ -451,7 +467,7 @@ pub fn set( match edge { widget::range_slider::Edge::Start => { group.simultaneous_sounds.min = num; - }, + } widget::range_slider::Edge::End => { group.simultaneous_sounds.max = num; } diff --git a/src/lib/gui/source_editor.rs b/src/lib/gui/source_editor.rs index 7ad930e..c07e569 100644 --- a/src/lib/gui/source_editor.rs +++ b/src/lib/gui/source_editor.rs @@ -1,18 +1,20 @@ -use audio; -use audio::source::Role; -use audio::source::wav::Playback; -use gui::{collapsible_area, duration_label, hz_label, Gui, ProjectState, State}; -use gui::{DARK_A, ITEM_HEIGHT, SMALL_FONT_SIZE}; -use metres::Metres; -use nannou::prelude::*; -use nannou::ui; -use nannou::ui::prelude::*; -use project::{self, Project}; -use soundscape; -use std::{self, cmp, mem, ops}; +use crate::audio; +use crate::audio::source::wav::Playback; +use crate::audio::source::Role; +use crate::gui::{collapsible_area, duration_label, hz_label, Gui, ProjectState, State}; +use crate::gui::{DARK_A, ITEM_HEIGHT, SMALL_FONT_SIZE}; +use crate::metres::Metres; +use crate::project::{self, Project}; +use crate::soundscape; +use crate::utils; +use nannou_conrod as ui; use std::sync::atomic; +use std::{self, cmp, mem, ops}; use time_calc::{Ms, Samples}; -use utils; +use ui::prelude::*; +use ui::{color, position, widget, Scalar}; + +type Point2 = nannou::glam::DVec2; /// Runtime state related to the source editor GUI panel. #[derive(Debug, Default)] @@ -27,7 +29,7 @@ pub struct SourceEditor { #[derive(Debug, Default)] pub struct SourcePreview { pub current: Option<(SourcePreviewMode, audio::sound::Id)>, - pub point: Option>, + pub point: Option, } /// The mode of source preview. @@ -40,16 +42,14 @@ pub enum SourcePreviewMode { /// Sort sources by kind and then name when displaying in the list. fn source_display_order(a: &project::Source, b: &project::Source) -> cmp::Ordering { match (&a.kind, &b.kind) { - (&audio::source::Kind::Wav(_), &audio::source::Kind::Realtime(_)) => { - cmp::Ordering::Less - } + (&audio::source::Kind::Wav(_), &audio::source::Kind::Realtime(_)) => cmp::Ordering::Less, _ => a.name.cmp(&b.name), } } -const SOUNDSCAPE_COLOR: ui::Color = ui::color::DARK_RED; -const INTERACTIVE_COLOR: ui::Color = ui::color::DARK_GREEN; -const SCRIBBLES_COLOR: ui::Color = ui::color::DARK_PURPLE; +const SOUNDSCAPE_COLOR: ui::Color = color::DARK_RED; +const INTERACTIVE_COLOR: ui::Color = color::DARK_GREEN; +const SCRIBBLES_COLOR: ui::Color = color::DARK_PURPLE; pub fn set( last_area_id: widget::Id, @@ -57,7 +57,6 @@ pub fn set( project: &mut Project, project_state: &mut ProjectState, ) -> widget::Id { - let Gui { ref mut ui, ref mut ids, @@ -74,14 +73,15 @@ pub fn set( } = *gui; let Project { - state: project::State { - ref camera, - ref master, - ref soundscape_groups, - ref installations, - ref mut sources, - .. - }, + state: + project::State { + ref camera, + ref master, + ref soundscape_groups, + ref installations, + ref mut sources, + .. + }, .. } = *project; @@ -100,29 +100,74 @@ pub fn set( const SLIDER_H: Scalar = ITEM_HEIGHT; const SOUNDSCAPE_GROUP_LIST_H: Scalar = ITEM_HEIGHT * 3.0; const BUTTON_H: Scalar = ITEM_HEIGHT; - const SOUNDSCAPE_CANVAS_H: Scalar = PAD + TEXT_PAD + PAD - + TEXT_PAD + PAD + SLIDER_H + PAD - + TEXT_PAD + PAD + SLIDER_H + PAD - + TEXT_PAD + PAD + SLIDER_H + PAD - + TEXT_PAD + PAD + SLIDER_H + PAD - + TEXT_PAD + PAD + SLIDER_H + PAD - + TEXT_PAD + PAD * 3.5 + SOUNDSCAPE_GROUP_LIST_H + PAD - + TEXT_PAD + PAD * 2.0 + BUTTON_H + PAD + BUTTON_H + PAD - + TEXT_PAD + PAD * 2.0 + SLIDER_H + PAD - + TEXT_PAD + PAD * 2.0 + SLIDER_H + PAD - + TEXT_PAD + PAD * 2.0 + SLIDER_H + PAD - + TEXT_PAD + PAD * 2.0 + SLIDER_H * 2.0 + PAD - + TEXT_PAD + PAD * 2.0 + SLIDER_H + PAD; + const SOUNDSCAPE_CANVAS_H: Scalar = PAD + + TEXT_PAD + + PAD + + TEXT_PAD + + PAD + + SLIDER_H + + PAD + + TEXT_PAD + + PAD + + SLIDER_H + + PAD + + TEXT_PAD + + PAD + + SLIDER_H + + PAD + + TEXT_PAD + + PAD + + SLIDER_H + + PAD + + TEXT_PAD + + PAD + + SLIDER_H + + PAD + + TEXT_PAD + + PAD * 3.5 + + SOUNDSCAPE_GROUP_LIST_H + + PAD + + TEXT_PAD + + PAD * 2.0 + + BUTTON_H + + PAD + + BUTTON_H + + PAD + + TEXT_PAD + + PAD * 2.0 + + SLIDER_H + + PAD + + TEXT_PAD + + PAD * 2.0 + + SLIDER_H + + PAD + + TEXT_PAD + + PAD * 2.0 + + SLIDER_H + + PAD + + TEXT_PAD + + PAD * 2.0 + + SLIDER_H * 2.0 + + PAD + + TEXT_PAD + + PAD * 2.0 + + SLIDER_H + + PAD; const LOOP_TOGGLE_H: Scalar = ITEM_HEIGHT; const PLAYBACK_MODE_H: Scalar = ITEM_HEIGHT; - const WAV_CANVAS_H: Scalar = - 100.0 + PAD + LOOP_TOGGLE_H + PAD * 4.0 + PLAYBACK_MODE_H + PAD; + const WAV_CANVAS_H: Scalar = 100.0 + PAD + LOOP_TOGGLE_H + PAD * 4.0 + PLAYBACK_MODE_H + PAD; const REALTIME_CANVAS_H: Scalar = 94.0; const CHANNEL_LAYOUT_H: Scalar = 200.0; const COMMON_CANVAS_H: Scalar = TEXT_PAD + PAD + SLIDER_H + PAD + CHANNEL_LAYOUT_H; let kind_specific_h = WAV_CANVAS_H.max(REALTIME_CANVAS_H); - let selected_canvas_h = ITEM_HEIGHT * 2.0 + PAD * 7.0 + PREVIEW_CANVAS_H + kind_specific_h - + COMMON_CANVAS_H + INSTALLATIONS_CANVAS_H + PAD + SOUNDSCAPE_CANVAS_H; + let selected_canvas_h = ITEM_HEIGHT * 2.0 + + PAD * 7.0 + + PREVIEW_CANVAS_H + + kind_specific_h + + COMMON_CANVAS_H + + INSTALLATIONS_CANVAS_H + + PAD + + SOUNDSCAPE_CANVAS_H; let source_editor_canvas_h = LIST_HEIGHT + ITEM_HEIGHT + selected_canvas_h; let (area, event) = collapsible_area(is_open.source_editor, "Source Editor", ids.side_menu) @@ -139,9 +184,7 @@ pub fn set( }; // The canvas on which the source editor will be placed. - let canvas = widget::Canvas::new() - .pad(0.0) - .h(source_editor_canvas_h); + let canvas = widget::Canvas::new().pad(0.0).h(source_editor_canvas_h); area.set(canvas, ui); // Convert the given map into a sorted list of source Ids. @@ -181,12 +224,13 @@ pub fn set( // invalid indices. let mut maybe_remove_index = None; let selected_id = source_editor.selected; - let selected_index = sources_vec.iter() + let selected_index = sources_vec + .iter() .position(|&id| Some(id) == selected_id) .unwrap_or(0); while let Some(event) = events.next(ui, |i| i == selected_index) { - use self::ui::widget::list_select::Event; + use widget::list_select::Event; match event { // Instantiate a button for each source. Event::Item(item) => { @@ -230,12 +274,14 @@ pub fn set( // If the button or any of its children are capturing the mouse, display // the `remove` button. let show_remove_button = !is_wav - && ui.global_input() + && ui + .global_input() .current .widget_capturing_mouse .map(|id| { id == item.widget_id - || ui.widget_graph() + || ui + .widget_graph() .does_recursive_depth_edge_exist(item.widget_id, id) }) .unwrap_or(false); @@ -295,7 +341,9 @@ pub fn set( } // Remove any monitored sounds using this source ID. - audio_monitor.active_sounds.retain(|_, s| s.source_id != remove_id); + audio_monitor + .active_sounds + .retain(|_, s| s.source_id != remove_id); // Remove the local copy. sources.remove(&remove_id); @@ -403,8 +451,7 @@ pub fn set( .parent(area.id) .set(ids.source_editor_selected_canvas, ui); - let selected_canvas_kid_area = ui.kid_area_of(ids.source_editor_selected_canvas) - .unwrap(); + let selected_canvas_kid_area = ui.kid_area_of(ids.source_editor_selected_canvas).unwrap(); // If a source is selected, display its info. let id = match source_editor.selected { @@ -481,11 +528,16 @@ pub fn set( } } - let selected_role_index = sources[&id].audio.role.as_ref().map(role_index).unwrap_or(0); + let selected_role_index = sources[&id] + .audio + .role + .as_ref() + .map(role_index) + .unwrap_or(0); let role_selected = |j| j == selected_role_index; while let Some(event) = events.next(ui, &role_selected) { - use self::ui::widget::list_select::Event; + use widget::list_select::Event; match event { // Instantiate a button for each role. Event::Item(item) => { @@ -519,15 +571,16 @@ pub fn set( // If the source became a soundscape source, send it to the soundscape thread. (_, Some(Role::Soundscape(_))) => { - let soundscape_source = soundscape::Source::from_audio_source(&source.audio) - .expect("source did not have soundscape role"); + let soundscape_source = + soundscape::Source::from_audio_source(&source.audio) + .expect("source did not have soundscape role"); channels .soundscape .send(move |soundscape| { soundscape.insert_source(id, soundscape_source); }) .expect("failed to send soundscape source to soundscape thread"); - }, + } // If it is no longer a soundscape. (Some(Role::Soundscape(_)), _) => { @@ -546,7 +599,7 @@ pub fn set( audio.remove_sounds_with_source(&id); }) .expect("failed to remove soundscape source sounds from audio output thread"); - }, + } _ => (), } @@ -739,8 +792,14 @@ pub fn set( .set(ids.source_editor_selected_wav_data, ui); // A `Toggle` for whether or not the WAV should loop. - let label = if wav.should_loop { "Looping: ON" } else { "Looping: OFF" }; - let canvas_kid_area = ui.kid_area_of(ids.source_editor_selected_wav_canvas).unwrap(); + let label = if wav.should_loop { + "Looping: ON" + } else { + "Looping: OFF" + }; + let canvas_kid_area = ui + .kid_area_of(ids.source_editor_selected_wav_canvas) + .unwrap(); for new_loop in widget::Toggle::new(wav.should_loop) .color(color::LIGHT_CHARCOAL) .label(label) @@ -811,13 +870,13 @@ pub fn set( let selected_index = index_from_playback(&wav.playback); while let Some(event) = events.next(ui, |i| i == selected_index) { - use self::ui::widget::list_select::Event; + use widget::list_select::Event; match event { // Instantiate a button for each source. Event::Item(item) => { let selected = item.i == selected_index; - let playback = playback_from_index(item.i) - .expect("no playback mode for index"); + let playback = + playback_from_index(item.i).expect("no playback mode for index"); let label = playback_label(&playback); // Blue if selected, gray otherwise. @@ -832,11 +891,11 @@ pub fn set( .label_font_size(SMALL_FONT_SIZE) .color(color); item.set(button, ui); - }, + } // If a selection has occurred. Event::Selection(new_index) => { - let new_playback = playback_from_index(new_index) - .expect("no playback mode for index"); + let new_playback = + playback_from_index(new_index).expect("no playback mode for index"); // Update the local copy. wav.playback = new_playback; @@ -858,13 +917,16 @@ pub fn set( .audio_output .send(move |audio| { audio.update_sounds_with_source(&id, move |_, sound| { - if let audio::source::SignalKind::Wav { ref mut playback, .. } = sound.signal.kind { + if let audio::source::SignalKind::Wav { + ref mut playback, .. + } = sound.signal.kind + { *playback = new_playback; } }); }) .expect("failed to send source playback mode to audio output thread"); - }, + } _ => (), } } @@ -913,7 +975,8 @@ pub fn set( .soundscape .send(move |soundscape| { soundscape.update_source(&id, |source| { - if let audio::source::Kind::Realtime(ref mut realtime) = source.kind { + if let audio::source::Kind::Realtime(ref mut realtime) = source.kind + { $update_fn(realtime); } }); @@ -942,7 +1005,9 @@ pub fn set( { // Update the local copy. let new_duration = Ms(new_ms as _); - update_realtime!(|realtime: &mut audio::source::Realtime| realtime.duration = new_duration); + update_realtime!( + |realtime: &mut audio::source::Realtime| realtime.duration = new_duration + ); } // Starting channel index (to the left). @@ -952,9 +1017,12 @@ pub fn set( .map(|ch| format!("Start Channel: {}", ch + 1)) .collect::>(); let selected_start = Some(realtime.channels.start as usize); - let channel_w = ui.kid_area_of(ids.source_editor_selected_realtime_canvas) + let channel_w = ui + .kid_area_of(ids.source_editor_selected_realtime_canvas) .unwrap() - .w() / 2.0 - PAD / 2.0; + .w() + / 2.0 + - PAD / 2.0; for new_start in widget::DropDownList::new(&start_channel_labels, selected_start) .down(PAD) .align_left() @@ -1052,13 +1120,16 @@ pub fn set( } // Buttons for solo and mute behaviour. - let channel_layout_kid_area = ui.kid_area_of(ids.source_editor_selected_common_canvas) + let channel_layout_kid_area = ui + .kid_area_of(ids.source_editor_selected_common_canvas) .unwrap(); let button_w = channel_layout_kid_area.w() / 2.0 - PAD / 2.0; - let toggle = |value: bool| widget::Toggle::new(value) - .w(button_w) - .h(ITEM_HEIGHT) - .label_font_size(SMALL_FONT_SIZE); + let toggle = |value: bool| { + widget::Toggle::new(value) + .w(button_w) + .h(ITEM_HEIGHT) + .label_font_size(SMALL_FONT_SIZE) + }; // Solo button. let solo = sources.soloed.contains(&id); @@ -1070,7 +1141,12 @@ pub fn set( .set(ids.source_editor_selected_solo, ui) { // If the CTRL key was down, unsolo all other sources. - if ui.global_input().current.modifiers.contains(ui::input::keyboard::ModifierKey::CTRL) { + if ui + .global_input() + .current + .modifiers + .contains(ui::input::keyboard::ModifierKey::CTRL) + { // Update local copy. sources.soloed.clear(); @@ -1080,7 +1156,9 @@ pub fn set( .send(move |audio| { audio.soloed.clear(); }) - .expect("failed to send message for clearing soloed sources to audio output thread"); + .expect( + "failed to send message for clearing soloed sources to audio output thread", + ); } // Update local copy. @@ -1150,7 +1228,7 @@ pub fn set( // Slider for controlling how far apart speakers should be spread. const MIN_SPREAD: f32 = 0.0; const MAX_SPREAD: f32 = 10.0; - let mut spread = sources[&id].audio.spread.0 as f32; + let mut spread = sources[&id].audio.spread as f32; let label = format!("Spread: {:.2} metres", spread); for new_spread in slider(spread, MIN_SPREAD, MAX_SPREAD) .skew(2.0) @@ -1160,7 +1238,7 @@ pub fn set( .set(ids.source_editor_selected_channel_layout_spread, ui) { spread = new_spread; - let spread_m = Metres(spread as _); + let spread_m: Metres = spread as _; // Update the local copy. sources.get_mut(&id).unwrap().audio.spread = spread_m; @@ -1222,7 +1300,8 @@ pub fn set( } // The field over which the channel layout will be visualised. - let spread_rect = ui.rect_of(ids.source_editor_selected_channel_layout_spread) + let spread_rect = ui + .rect_of(ids.source_editor_selected_channel_layout_spread) .unwrap(); let layout_top = spread_rect.bottom() - PAD; let layout_bottom = channel_layout_kid_area.bottom(); @@ -1259,8 +1338,10 @@ pub fn set( ids.source_editor_selected_channel_layout_channels .resize(num_channels, id_gen); } - if ids.source_editor_selected_channel_layout_channel_labels - .len() < num_channels + if ids + .source_editor_selected_channel_layout_channel_labels + .len() + < num_channels { let id_gen = &mut ui.widget_id_generator(); ids.source_editor_selected_channel_layout_channel_labels @@ -1378,20 +1459,26 @@ pub fn set( channels .audio_output .send(move |audio| { - for (_, sound) in audio.sounds_mut().filter(|&(_, ref s)| s.source_id() == id) { - if let audio::sound::Installations::Set(ref mut set) = sound.installations { + for (_, sound) in + audio.sounds_mut().filter(|&(_, ref s)| s.source_id() == id) + { + if let audio::sound::Installations::Set(ref mut set) = + sound.installations + { set.insert(installation); } } }) - .expect("failed to send assigned installation to sounds on audio output thread"); + .expect( + "failed to send assigned installation to sounds on audio output thread", + ); } // A scrollable list showing each of the assigned installations. - let mut selected_installations = source_installations.iter().cloned().collect::>(); - selected_installations.sort_by(|a, b| { - installations[&a].name.cmp(&installations[&b].name) - }); + let mut selected_installations = + source_installations.iter().cloned().collect::>(); + selected_installations + .sort_by(|a, b| installations[&a].name.cmp(&installations[&b].name)); let (mut items, scrollbar) = widget::List::flow_down(selected_installations.len()) .item_size(ITEM_HEIGHT) .h(INSTALLATION_LIST_H) @@ -1417,12 +1504,14 @@ pub fn set( // If the button or any of its children are capturing the mouse, display // the `remove` button. - let show_remove_button = ui.global_input() + let show_remove_button = ui + .global_input() .current .widget_capturing_mouse .map(|id| { id == item.widget_id - || ui.widget_graph() + || ui + .widget_graph() .does_recursive_depth_edge_exist(item.widget_id, id) }) .unwrap_or(false); @@ -1474,8 +1563,12 @@ pub fn set( channels .audio_output .send(move |audio| { - for (_, sound) in audio.sounds_mut().filter(|&(_, ref s)| s.source_id() == id) { - if let audio::sound::Installations::Set(ref mut set) = sound.installations { + for (_, sound) in + audio.sounds_mut().filter(|&(_, ref s)| s.source_id() == id) + { + if let audio::sound::Installations::Set(ref mut set) = + sound.installations + { set.remove(&inst); } } @@ -1514,8 +1607,7 @@ pub fn set( fn expect_soundscape_mut<'a>( sources: &'a mut project::SourcesMap, id: &audio::source::Id, - ) -> &'a mut audio::source::Soundscape - { + ) -> &'a mut audio::source::Soundscape { sources .get_mut(id) .unwrap() @@ -1535,7 +1627,10 @@ pub fn set( .align_left() .down(PAD * 2.0) .font_size(SMALL_FONT_SIZE) - .set(ids.source_editor_selected_soundscape_occurrence_rate_text, ui); + .set( + ids.source_editor_selected_soundscape_occurrence_rate_text, + ui, + ); // A range slider for constraining the occurrence rate. let max_hz = utils::ms_interval_to_hz(occurrence_rate.min); @@ -1551,7 +1646,7 @@ pub fn set( .kid_area_w_of(ids.source_editor_selected_soundscape_canvas) .h(SLIDER_H) .label_font_size(SMALL_FONT_SIZE) - .color(ui::color::LIGHT_CHARCOAL) + .color(color::LIGHT_CHARCOAL) }; for (edge, value) in range_slider(min_hz, max_hz, total_min_hz, total_max_hz) @@ -1559,7 +1654,10 @@ pub fn set( .align_left() .label(&label) .down(PAD * 2.0) - .set(ids.source_editor_selected_soundscape_occurrence_rate_slider, ui) + .set( + ids.source_editor_selected_soundscape_occurrence_rate_slider, + ui, + ) { let hz = { let (unit, times_per_unit) = utils::human_readable_hz(value as _); @@ -1573,7 +1671,7 @@ pub fn set( widget::range_slider::Edge::Start => { let ms = utils::hz_to_ms_interval(hz); soundscape.occurrence_rate.max = ms; - }, + } widget::range_slider::Edge::End => { let ms = utils::hz_to_ms_interval(hz); soundscape.occurrence_rate.min = ms; @@ -1601,7 +1699,10 @@ pub fn set( .align_left() .down(PAD * 2.0) .font_size(SMALL_FONT_SIZE) - .set(ids.source_editor_selected_soundscape_simultaneous_sounds_text, ui); + .set( + ids.source_editor_selected_soundscape_simultaneous_sounds_text, + ui, + ); let range = simultaneous_sounds; let label = format!("{} to {} sounds at once", range.min, range.max); @@ -1614,7 +1715,10 @@ pub fn set( .align_left() .label(&label) .down(PAD * 2.0) - .set(ids.source_editor_selected_soundscape_simultaneous_sounds_slider, ui) + .set( + ids.source_editor_selected_soundscape_simultaneous_sounds_slider, + ui, + ) { let num = value as _; @@ -1624,7 +1728,7 @@ pub fn set( match edge { widget::range_slider::Edge::Start => { soundscape.simultaneous_sounds.min = num; - }, + } widget::range_slider::Edge::End => { soundscape.simultaneous_sounds.max = num; } @@ -1651,7 +1755,10 @@ pub fn set( .align_left() .down(PAD * 2.0) .font_size(SMALL_FONT_SIZE) - .set(ids.source_editor_selected_soundscape_playback_duration_text, ui); + .set( + ids.source_editor_selected_soundscape_playback_duration_text, + ui, + ); // The max duration depends on the kind of source: // @@ -1663,13 +1770,17 @@ pub fn set( audio::source::Kind::Wav(ref wav) => match wav.should_loop { true => audio::source::MAX_PLAYBACK_DURATION, false => wav.duration.to_ms(audio::SAMPLE_RATE), - } + }, }; let min_duration = Ms(0.0); let min_duration_ms = min_duration.ms(); let max_duration_ms = max_duration.ms(); let range = playback_duration; - let label = format!("{} to {}", duration_label(&range.min), duration_label(&range.max)); + let label = format!( + "{} to {}", + duration_label(&range.min), + duration_label(&range.max) + ); let start = range.min.ms() as f64; let end = range.max.ms() as f64; for (edge, value) in range_slider(start, end, min_duration_ms, max_duration_ms) @@ -1677,7 +1788,10 @@ pub fn set( .align_left() .label(&label) .down(PAD * 2.0) - .set(ids.source_editor_selected_soundscape_playback_duration_slider, ui) + .set( + ids.source_editor_selected_soundscape_playback_duration_slider, + ui, + ) { let duration = { let (unit, value) = utils::human_readable_ms(&Ms(value as _)); @@ -1691,7 +1805,7 @@ pub fn set( match edge { widget::range_slider::Edge::Start => { soundscape.playback_duration.min = duration; - }, + } widget::range_slider::Edge::End => { soundscape.playback_duration.max = duration; } @@ -1718,14 +1832,21 @@ pub fn set( .align_left() .down(PAD * 2.0) .font_size(SMALL_FONT_SIZE) - .set(ids.source_editor_selected_soundscape_attack_duration_text, ui); + .set( + ids.source_editor_selected_soundscape_attack_duration_text, + ui, + ); let min_duration = Ms(0.0); let max_duration = audio::source::MAX_ATTACK_DURATION; let min_duration_ms = min_duration.ms(); let max_duration_ms = max_duration.ms(); let range = attack_duration; - let label = format!("{} to {}", duration_label(&range.min), duration_label(&range.max)); + let label = format!( + "{} to {}", + duration_label(&range.min), + duration_label(&range.max) + ); let start = range.min.ms() as f64; let end = range.max.ms() as f64; for (edge, value) in range_slider(start, end, min_duration_ms, max_duration_ms) @@ -1733,7 +1854,10 @@ pub fn set( .align_left() .label(&label) .down(PAD * 2.0) - .set(ids.source_editor_selected_soundscape_attack_duration_slider, ui) + .set( + ids.source_editor_selected_soundscape_attack_duration_slider, + ui, + ) { let duration = { let (unit, value) = utils::human_readable_ms(&Ms(value as _)); @@ -1747,7 +1871,7 @@ pub fn set( match edge { widget::range_slider::Edge::Start => { soundscape.attack_duration.min = duration; - }, + } widget::range_slider::Edge::End => { soundscape.attack_duration.max = duration; } @@ -1774,14 +1898,21 @@ pub fn set( .align_left() .down(PAD * 2.0) .font_size(SMALL_FONT_SIZE) - .set(ids.source_editor_selected_soundscape_release_duration_text, ui); + .set( + ids.source_editor_selected_soundscape_release_duration_text, + ui, + ); let min_duration = Ms(0.0); let max_duration = audio::source::MAX_RELEASE_DURATION; let min_duration_ms = min_duration.ms(); let max_duration_ms = max_duration.ms(); let range = release_duration; - let label = format!("{} to {}", duration_label(&range.min), duration_label(&range.max)); + let label = format!( + "{} to {}", + duration_label(&range.min), + duration_label(&range.max) + ); let start = range.min.ms(); let end = range.max.ms(); for (edge, value) in range_slider(start, end, min_duration_ms, max_duration_ms) @@ -1789,7 +1920,10 @@ pub fn set( .align_left() .label(&label) .down(PAD * 2.0) - .set(ids.source_editor_selected_soundscape_release_duration_slider, ui) + .set( + ids.source_editor_selected_soundscape_release_duration_slider, + ui, + ) { let duration = { let (unit, value) = utils::human_readable_ms(&Ms(value as _)); @@ -1803,7 +1937,7 @@ pub fn set( match edge { widget::range_slider::Edge::Start => { soundscape.release_duration.min = duration; - }, + } widget::range_slider::Edge::End => { soundscape.release_duration.max = duration; } @@ -1845,14 +1979,14 @@ pub fn set( let is_selected = |idx: usize| groups.contains(&groups_vec[idx].0); while let Some(event) = events.next(ui, &is_selected) { - use self::ui::widget::list_select::Event; + use widget::list_select::Event; match event { // Instantiate a button for each group. Event::Item(item) => { let selected = is_selected(item.i); let (&group_id, _) = groups_vec[item.i]; let soundscape = expect_soundscape_mut(sources, &id); - let color = if selected { ui::color::BLUE } else { ui::color::BLACK }; + let color = if selected { color::BLUE } else { color::BLACK }; let button = widget::Button::new() .label(&groups_vec[item.i].1.name) .label_font_size(SMALL_FONT_SIZE) @@ -1880,7 +2014,6 @@ pub fn set( }) .expect("failed to send source soundscape group update to soundscape thread"); } - } _ => (), } @@ -1901,7 +2034,9 @@ pub fn set( .set(ids.source_editor_selected_soundscape_movement_text, ui); // A rightward flowing list for the movement kinds. - let canvas_kid_area = ui.kid_area_of(ids.source_editor_selected_soundscape_canvas).unwrap(); + let canvas_kid_area = ui + .kid_area_of(ids.source_editor_selected_soundscape_canvas) + .unwrap(); let n_items = audio::source::Movement::VARIANT_COUNT; let item_w = canvas_kid_area.w() / n_items as Scalar; let (mut events, _scrollbar) = widget::ListSelect::single(n_items) @@ -1915,12 +2050,16 @@ pub fn set( let selected_index = movement.to_index(); let is_selected = |i| i == selected_index; while let Some(event) = events.next(ui, &is_selected) { - use nannou::ui::widget::list_select::Event; + use widget::list_select::Event; match event { Event::Item(item) => { let index = item.i; let selected = is_selected(index); - let color = if selected { color::BLUE } else { color::DARK_CHARCOAL }; + let color = if selected { + color::BLUE + } else { + color::DARK_CHARCOAL + }; let label = audio::source::Movement::label_from_index(index); let button = widget::Button::new() .label(&label) @@ -1947,7 +2086,7 @@ pub fn set( }) .expect("could not update movement field on soundscape thread"); } - }, + } _ => (), } } @@ -1955,7 +2094,6 @@ pub fn set( // Depending on the selected movement, display the relevant widgets. let generative = match movement { audio::source::Movement::Fixed(position) => { - ///////////////////// // POSITION XY PAD // ///////////////////// @@ -1969,14 +2107,20 @@ pub fn set( .value_font_size(SMALL_FONT_SIZE) .w(w) .h(h) - .down_from(ids.source_editor_selected_soundscape_movement_mode_list, PAD) + .down_from( + ids.source_editor_selected_soundscape_movement_mode_list, + PAD, + ) .align_left_of(ids.source_editor_selected_soundscape_movement_mode_list) - .color(ui::color::DARK_CHARCOAL) - .set(ids.source_editor_selected_soundscape_movement_fixed_point, ui) + .color(color::DARK_CHARCOAL) + .set( + ids.source_editor_selected_soundscape_movement_fixed_point, + ui, + ) { // Update the local copy. let soundscape = expect_soundscape_mut(sources, &id); - let point = pt2(new_x, new_y); + let point = Point2::new(new_x, new_y); let movement = audio::source::Movement::Fixed(point); soundscape.movement = movement.clone(); @@ -1991,7 +2135,7 @@ pub fn set( } return area.id; - }, + } audio::source::Movement::Generative(generative) => generative, }; @@ -2004,21 +2148,31 @@ pub fn set( let item_w = canvas_kid_area.w() / n_items as Scalar; let (mut events, _scrollbar) = widget::ListSelect::single(n_items) .flow_right() - .down_from(ids.source_editor_selected_soundscape_movement_mode_list, PAD) + .down_from( + ids.source_editor_selected_soundscape_movement_mode_list, + PAD, + ) .align_left_of(ids.source_editor_selected_soundscape_movement_mode_list) .w(canvas_kid_area.w()) .h(BUTTON_H) .item_size(item_w) - .set(ids.source_editor_selected_soundscape_movement_generative_list, ui); + .set( + ids.source_editor_selected_soundscape_movement_generative_list, + ui, + ); let selected_index = generative.to_index(); let is_selected = |i| i == selected_index; while let Some(event) = events.next(ui, &is_selected) { - use nannou::ui::widget::list_select::Event; + use widget::list_select::Event; match event { Event::Item(item) => { let index = item.i; let selected = is_selected(index); - let color = if selected { color::BLUE } else { color::DARK_CHARCOAL }; + let color = if selected { + color::BLUE + } else { + color::DARK_CHARCOAL + }; let label = audio::source::movement::Generative::label_from_index(index); let button = widget::Button::new() .label(&label) @@ -2046,7 +2200,7 @@ pub fn set( }) .expect("could not update movement field on soundscape thread"); } - }, + } _ => (), } } @@ -2068,8 +2222,11 @@ pub fn set( .down(PAD * 2.0) .h(ITEM_HEIGHT) .w(canvas_kid_area.w()) - .color(ui::color::LIGHT_CHARCOAL) - .set(ids.source_editor_selected_soundscape_movement_agent_directional, ui) + .color(color::LIGHT_CHARCOAL) + .set( + ids.source_editor_selected_soundscape_movement_agent_directional, + ui, + ) { // Update local copy. agent.directional = new_directional; @@ -2089,7 +2246,9 @@ pub fn set( _ => return, }; let agent = match *gen { - soundscape::movement::Generative::Agent(ref mut agent) => agent, + soundscape::movement::Generative::Agent(ref mut agent) => { + agent + } _ => return, }; agent.directional = new_directional; @@ -2102,7 +2261,9 @@ pub fn set( _ => return, }; let agent = match *gen { - audio::source::movement::Generative::Agent(ref mut agent) => agent, + audio::source::movement::Generative::Agent( + ref mut agent, + ) => agent, _ => return, }; agent.directional = new_directional; @@ -2119,7 +2280,10 @@ pub fn set( .mid_left_of(ids.source_editor_selected_soundscape_canvas) .down(PAD * 2.0) .font_size(SMALL_FONT_SIZE) - .set(ids.source_editor_selected_soundscape_movement_agent_max_speed_text, ui); + .set( + ids.source_editor_selected_soundscape_movement_agent_max_speed_text, + ui, + ); let min = agent.max_speed.min; let max = agent.max_speed.max; @@ -2131,7 +2295,10 @@ pub fn set( .align_left() .label(&label) .down(PAD * 2.0) - .set(ids.source_editor_selected_soundscape_movement_agent_max_speed_slider, ui) + .set( + ids.source_editor_selected_soundscape_movement_agent_max_speed_slider, + ui, + ) { match edge { widget::range_slider::Edge::Start => agent.max_speed.min = value, @@ -2156,7 +2323,9 @@ pub fn set( _ => return, }; let agent = match *gen { - soundscape::movement::Generative::Agent(ref mut agent) => agent, + soundscape::movement::Generative::Agent(ref mut agent) => { + agent + } _ => return, }; agent.max_speed = new_max_speed.clamp(agent.max_speed); @@ -2169,7 +2338,9 @@ pub fn set( _ => return, }; let agent = match *gen { - audio::source::movement::Generative::Agent(ref mut agent) => agent, + audio::source::movement::Generative::Agent( + ref mut agent, + ) => agent, _ => return, }; agent.max_speed = new_max_speed; @@ -2186,7 +2357,10 @@ pub fn set( .mid_left_of(ids.source_editor_selected_soundscape_canvas) .down(PAD * 2.0) .font_size(SMALL_FONT_SIZE) - .set(ids.source_editor_selected_soundscape_movement_agent_max_force_text, ui); + .set( + ids.source_editor_selected_soundscape_movement_agent_max_force_text, + ui, + ); let min = agent.max_force.min; let max = agent.max_force.max; @@ -2198,7 +2372,10 @@ pub fn set( .align_left() .label(&label) .down(PAD * 2.0) - .set(ids.source_editor_selected_soundscape_movement_agent_max_force_slider, ui) + .set( + ids.source_editor_selected_soundscape_movement_agent_max_force_slider, + ui, + ) { match edge { widget::range_slider::Edge::Start => agent.max_force.min = value, @@ -2223,7 +2400,9 @@ pub fn set( _ => return, }; let agent = match *gen { - soundscape::movement::Generative::Agent(ref mut agent) => agent, + soundscape::movement::Generative::Agent(ref mut agent) => { + agent + } _ => return, }; agent.max_force = new_max_force.clamp(agent.max_force); @@ -2236,7 +2415,9 @@ pub fn set( _ => return, }; let agent = match *gen { - audio::source::movement::Generative::Agent(ref mut agent) => agent, + audio::source::movement::Generative::Agent( + ref mut agent, + ) => agent, _ => return, }; agent.max_force = new_max_force; @@ -2253,7 +2434,10 @@ pub fn set( .mid_left_of(ids.source_editor_selected_soundscape_canvas) .down(PAD * 2.0) .font_size(SMALL_FONT_SIZE) - .set(ids.source_editor_selected_soundscape_movement_agent_max_rotation_text, ui); + .set( + ids.source_editor_selected_soundscape_movement_agent_max_rotation_text, + ui, + ); let min = agent.max_rotation.min; let max = agent.max_rotation.max; @@ -2311,11 +2495,10 @@ pub fn set( }) .expect("failed to send movement update to soundscape thread"); } - }, + } // Ngon-specific widgets. audio::source::movement::Generative::Ngon(mut ngon) => { - ////////////// // Vertices // ////////////// @@ -2324,7 +2507,10 @@ pub fn set( .mid_left_of(ids.source_editor_selected_soundscape_canvas) .down(PAD * 2.0) .font_size(SMALL_FONT_SIZE) - .set(ids.source_editor_selected_soundscape_movement_ngon_vertices_text, ui); + .set( + ids.source_editor_selected_soundscape_movement_ngon_vertices_text, + ui, + ); let min = ngon.vertices.min as f64; let max = ngon.vertices.max as f64; @@ -2336,7 +2522,10 @@ pub fn set( .align_left() .label(&label) .down(PAD * 2.0) - .set(ids.source_editor_selected_soundscape_movement_ngon_vertices_slider, ui) + .set( + ids.source_editor_selected_soundscape_movement_ngon_vertices_slider, + ui, + ) { let value = value as usize; match edge { @@ -2362,7 +2551,9 @@ pub fn set( _ => return, }; let ngon = match *gen { - soundscape::movement::Generative::Ngon(ref mut ngon) => ngon, + soundscape::movement::Generative::Ngon(ref mut ngon) => { + ngon + } _ => return, }; ngon.vertices = new_vertices.clamp(ngon.vertices); @@ -2375,7 +2566,9 @@ pub fn set( _ => return, }; let ngon = match *gen { - audio::source::movement::Generative::Ngon(ref mut ngon) => ngon, + audio::source::movement::Generative::Ngon(ref mut ngon) => { + ngon + } _ => return, }; ngon.vertices = new_vertices; @@ -2392,7 +2585,10 @@ pub fn set( .mid_left_of(ids.source_editor_selected_soundscape_canvas) .down(PAD * 2.0) .font_size(SMALL_FONT_SIZE) - .set(ids.source_editor_selected_soundscape_movement_ngon_step_text, ui); + .set( + ids.source_editor_selected_soundscape_movement_ngon_step_text, + ui, + ); let min = ngon.nth.min as f64; let max = ngon.nth.max as f64; @@ -2404,7 +2600,10 @@ pub fn set( .align_left() .label(&label) .down(PAD * 2.0) - .set(ids.source_editor_selected_soundscape_movement_ngon_step_slider, ui) + .set( + ids.source_editor_selected_soundscape_movement_ngon_step_slider, + ui, + ) { let value = value as usize; match edge { @@ -2430,7 +2629,9 @@ pub fn set( _ => return, }; let ngon = match *gen { - soundscape::movement::Generative::Ngon(ref mut ngon) => ngon, + soundscape::movement::Generative::Ngon(ref mut ngon) => { + ngon + } _ => return, }; ngon.nth = new_nth.clamp(ngon.nth); @@ -2443,7 +2644,9 @@ pub fn set( _ => return, }; let ngon = match *gen { - audio::source::movement::Generative::Ngon(ref mut ngon) => ngon, + audio::source::movement::Generative::Ngon(ref mut ngon) => { + ngon + } _ => return, }; ngon.nth = new_nth; @@ -2452,7 +2655,6 @@ pub fn set( .expect("failed to send movement update to soundscape thread"); } - //////////////// // Dimensions // //////////////// @@ -2461,30 +2663,41 @@ pub fn set( .mid_left_of(ids.source_editor_selected_soundscape_canvas) .down(PAD * 2.0) .font_size(SMALL_FONT_SIZE) - .set(ids.source_editor_selected_soundscape_movement_ngon_dimensions_text, ui); + .set( + ids.source_editor_selected_soundscape_movement_ngon_dimensions_text, + ui, + ); let slider = |value, min, max| { widget::Slider::new(value, min, max) .h(SLIDER_H) .w(canvas_kid_area.w()) .label_font_size(SMALL_FONT_SIZE) - .color(ui::color::LIGHT_CHARCOAL) + .color(color::LIGHT_CHARCOAL) }; /////////// // Width // /////////// - let label = format!("{:.2}% of installation width", ngon.normalised_dimensions.x * 100.0); + let label = format!( + "{:.2}% of installation width", + ngon.normalised_dimensions.x * 100.0 + ); for new_width in slider(ngon.normalised_dimensions.x, 0.0, 1.0) .align_left() .label(&label) .down(PAD * 2.0) - .set(ids.source_editor_selected_soundscape_movement_ngon_width_slider, ui) + .set( + ids.source_editor_selected_soundscape_movement_ngon_width_slider, + ui, + ) { // Update local copy. let soundscape = expect_soundscape_mut(sources, &id); - if let audio::source::Movement::Generative(ref mut gen) = soundscape.movement { + if let audio::source::Movement::Generative(ref mut gen) = + soundscape.movement + { if let audio::source::movement::Generative::Ngon(ref mut ngon) = *gen { ngon.normalised_dimensions.x = new_width; } @@ -2501,7 +2714,9 @@ pub fn set( _ => return, }; let ngon = match *gen { - soundscape::movement::Generative::Ngon(ref mut ngon) => ngon, + soundscape::movement::Generative::Ngon(ref mut ngon) => { + ngon + } _ => return, }; ngon.normalised_dimensions.x = new_width; @@ -2513,7 +2728,9 @@ pub fn set( _ => return, }; let ngon = match *gen { - audio::source::movement::Generative::Ngon(ref mut ngon) => ngon, + audio::source::movement::Generative::Ngon(ref mut ngon) => { + ngon + } _ => return, }; ngon.normalised_dimensions.x = new_width; @@ -2526,16 +2743,24 @@ pub fn set( // Height // //////////// - let label = format!("{:.2}% of installation height", ngon.normalised_dimensions.y * 100.0); + let label = format!( + "{:.2}% of installation height", + ngon.normalised_dimensions.y * 100.0 + ); for new_height in slider(ngon.normalised_dimensions.y, 0.0, 1.0) .align_left() .label(&label) .down(PAD) - .set(ids.source_editor_selected_soundscape_movement_ngon_height_slider, ui) + .set( + ids.source_editor_selected_soundscape_movement_ngon_height_slider, + ui, + ) { // Update local copy. let soundscape = expect_soundscape_mut(sources, &id); - if let audio::source::Movement::Generative(ref mut gen) = soundscape.movement { + if let audio::source::Movement::Generative(ref mut gen) = + soundscape.movement + { if let audio::source::movement::Generative::Ngon(ref mut ngon) = *gen { ngon.normalised_dimensions.y = new_height; } @@ -2552,7 +2777,9 @@ pub fn set( _ => return, }; let ngon = match *gen { - soundscape::movement::Generative::Ngon(ref mut ngon) => ngon, + soundscape::movement::Generative::Ngon(ref mut ngon) => { + ngon + } _ => return, }; ngon.normalised_dimensions.y = new_height; @@ -2564,7 +2791,9 @@ pub fn set( _ => return, }; let ngon = match *gen { - audio::source::movement::Generative::Ngon(ref mut ngon) => ngon, + audio::source::movement::Generative::Ngon(ref mut ngon) => { + ngon + } _ => return, }; ngon.normalised_dimensions.y = new_height; @@ -2581,7 +2810,10 @@ pub fn set( .mid_left_of(ids.source_editor_selected_soundscape_canvas) .down(PAD * 2.0) .font_size(SMALL_FONT_SIZE) - .set(ids.source_editor_selected_soundscape_movement_ngon_radians_text, ui); + .set( + ids.source_editor_selected_soundscape_movement_ngon_radians_text, + ui, + ); let min = ngon.radians_offset.min; let max = ngon.radians_offset.max; @@ -2592,7 +2824,10 @@ pub fn set( .align_left() .label(&label) .down(PAD * 2.0) - .set(ids.source_editor_selected_soundscape_movement_ngon_radians_slider, ui) + .set( + ids.source_editor_selected_soundscape_movement_ngon_radians_slider, + ui, + ) { match edge { widget::range_slider::Edge::Start => ngon.radians_offset.min = value, @@ -2617,10 +2852,13 @@ pub fn set( _ => return, }; let ngon = match *gen { - soundscape::movement::Generative::Ngon(ref mut ngon) => ngon, + soundscape::movement::Generative::Ngon(ref mut ngon) => { + ngon + } _ => return, }; - ngon.radians_offset = new_radians_offset.clamp(ngon.radians_offset); + ngon.radians_offset = + new_radians_offset.clamp(ngon.radians_offset); }); // Update the source. @@ -2630,7 +2868,9 @@ pub fn set( _ => return, }; let ngon = match *gen { - audio::source::movement::Generative::Ngon(ref mut ngon) => ngon, + audio::source::movement::Generative::Ngon(ref mut ngon) => { + ngon + } _ => return, }; ngon.radians_offset = new_radians_offset; @@ -2647,7 +2887,10 @@ pub fn set( .mid_left_of(ids.source_editor_selected_soundscape_canvas) .down(PAD * 2.0) .font_size(SMALL_FONT_SIZE) - .set(ids.source_editor_selected_soundscape_movement_ngon_speed_text, ui); + .set( + ids.source_editor_selected_soundscape_movement_ngon_speed_text, + ui, + ); let min = ngon.speed.min; let max = ngon.speed.max; @@ -2659,7 +2902,10 @@ pub fn set( .align_left() .label(&label) .down(PAD * 2.0) - .set(ids.source_editor_selected_soundscape_movement_ngon_speed_slider, ui) + .set( + ids.source_editor_selected_soundscape_movement_ngon_speed_slider, + ui, + ) { match edge { widget::range_slider::Edge::Start => ngon.speed.min = value, @@ -2684,7 +2930,9 @@ pub fn set( _ => return, }; let ngon = match *gen { - soundscape::movement::Generative::Ngon(ref mut ngon) => ngon, + soundscape::movement::Generative::Ngon(ref mut ngon) => { + ngon + } _ => return, }; ngon.speed = new_speed.clamp(ngon.speed); @@ -2697,7 +2945,9 @@ pub fn set( _ => return, }; let ngon = match *gen { - audio::source::movement::Generative::Ngon(ref mut ngon) => ngon, + audio::source::movement::Generative::Ngon(ref mut ngon) => { + ngon + } _ => return, }; ngon.speed = new_speed; @@ -2705,18 +2955,16 @@ pub fn set( }) .expect("failed to send movement update to soundscape thread"); } - }, + } } - }, + } // For interactive sounds, allow the user specify the location. NOTE: Option - just work // this sound out from the location of the speakers? - Some(Role::Interactive) => { - }, + Some(Role::Interactive) => {} // For scribbles, allow a specific location from which the speaking appears. - Some(Role::Scribbles) => { - }, + Some(Role::Scribbles) => {} // If it has no role, no specific stuff to be done. None => (), diff --git a/src/lib/gui/speaker_editor.rs b/src/lib/gui/speaker_editor.rs index ba29a66..7acceec 100644 --- a/src/lib/gui/speaker_editor.rs +++ b/src/lib/gui/speaker_editor.rs @@ -1,10 +1,11 @@ -use audio; -use gui::{collapsible_area, Gui, ProjectState}; -use gui::{DARK_A, ITEM_HEIGHT, SMALL_FONT_SIZE}; -use nannou::ui; -use nannou::ui::prelude::*; -use project::{self, Project}; -use soundscape; +use crate::audio; +use crate::gui::{collapsible_area, Gui, ProjectState}; +use crate::gui::{DARK_A, ITEM_HEIGHT, SMALL_FONT_SIZE}; +use crate::project::{self, Project}; +use crate::soundscape; +use conrod_core::{Borderable, Colorable, Labelable, Positionable, Sizeable, Widget}; +use nannou_conrod as ui; +use ui::{FontSize, Scalar}; /// Runtime state related to the speaker editor GUI panel. #[derive(Default)] @@ -22,11 +23,11 @@ pub fn sorted_speakers_vec(speakers: &project::Speakers) -> Vec widget::Id { +) -> ui::widget::Id { let Gui { ref mut ui, ref mut state, @@ -36,12 +37,13 @@ pub fn set( } = *gui; let Project { - state: project::State { - ref camera, - ref installations, - ref mut speakers, - .. - }, + state: + project::State { + ref camera, + ref installations, + ref mut speakers, + .. + }, .. } = *project; @@ -50,7 +52,6 @@ pub fn set( .. } = *project_state; - let is_open = state.is_open.speaker_editor; const LIST_HEIGHT: Scalar = 140.0; const PAD: Scalar = 6.0; @@ -76,7 +77,7 @@ pub fn set( }; // The canvas on which the log will be placed. - let canvas = widget::Canvas::new() + let canvas = ui::widget::Canvas::new() .pad(0.0) .h(speaker_editor_canvas_h); area.set(canvas, ui); @@ -93,7 +94,7 @@ pub fn set( // If there are no speakers, display a message saying how to add some. if speakers.is_empty() { - widget::Text::new("Add some speaker outputs with the `+` button") + ui::widget::Text::new("Add some speaker outputs with the `+` button") .padded_w_of(area.id, TEXT_PAD) .mid_top_with_margin_on(area.id, TEXT_PAD) .font_size(SMALL_FONT_SIZE) @@ -106,22 +107,20 @@ pub fn set( let mut speakers_vec = sorted_speakers_vec(speakers); let num_items = speakers_vec.len(); - let (mut list_events, scrollbar) = widget::ListSelect::single(num_items) + let (mut list_events, scrollbar) = ui::widget::ListSelect::single(num_items) .item_size(ITEM_HEIGHT) .h(LIST_HEIGHT) .align_middle_x_of(area.id) .align_top_of(area.id) .scrollbar_next_to() - .scrollbar_color(color::LIGHT_CHARCOAL) + .scrollbar_color(ui::color::LIGHT_CHARCOAL) .set(ids.speaker_editor_list, ui); // If a speaker was removed, process it after the whole list is instantiated to avoid // invalid indices. let mut maybe_remove_index = None; - while let Some(event) = - list_events.next(ui, |i| speaker_editor.selected == Some(i)) - { + while let Some(event) = list_events.next(ui, |i| speaker_editor.selected == Some(i)) { use self::ui::widget::list_select::Event; match event { // Instantiate a button for each speaker. @@ -134,37 +133,39 @@ pub fn set( "{} - CH {} - ({}mx, {}my)", speaker.name, speaker.channel + 1, - (speaker.point.x.0 * 100.0).trunc() / 100.0, - (speaker.point.y.0 * 100.0).trunc() / 100.0 + (speaker.point.x * 100.0).trunc() / 100.0, + (speaker.point.y * 100.0).trunc() / 100.0 ); label }; // Blue if selected, gray otherwise. let color = if selected { - color::BLUE + ui::color::BLUE } else { - color::CHARCOAL + ui::color::CHARCOAL }; // Use `Button`s for the selectable items. - let button = widget::Button::new() + let button = ui::widget::Button::new() .label(&label) .label_font_size(SMALL_FONT_SIZE) - .label_x(position::Relative::Place(position::Place::Start(Some( - 10.0, - )))) + .label_x(ui::position::Relative::Place(ui::position::Place::Start( + Some(10.0), + ))) .color(color); item.set(button, ui); // If the button or any of its children are capturing the mouse, display // the `remove` button. - let show_remove_button = ui.global_input() + let show_remove_button = ui + .global_input() .current .widget_capturing_mouse .map(|id| { id == item.widget_id - || ui.widget_graph() + || ui + .widget_graph() .does_recursive_depth_edge_exist(item.widget_id, id) }) .unwrap_or(false); @@ -173,10 +174,10 @@ pub fn set( continue; } - if widget::Button::new() + if ui::widget::Button::new() .label("X") .label_font_size(SMALL_FONT_SIZE) - .color(color::DARK_RED.alpha(0.5)) + .color(ui::color::DARK_RED.alpha(0.5)) .w_h(ITEM_HEIGHT, ITEM_HEIGHT) .align_right_of(item.widget_id) .align_middle_y_of(item.widget_id) @@ -234,7 +235,7 @@ pub fn set( if show_add_button { let plus_size = (ITEM_HEIGHT * 0.66) as FontSize; - if widget::Button::new() + if ui::widget::Button::new() .color(DARK_A) .label("+") .label_font_size(plus_size) @@ -285,7 +286,7 @@ pub fn set( let end = start + SELECTED_CANVAS_H; let selected_canvas_y = ui::Range { start, end }; - widget::Canvas::new() + ui::widget::Canvas::new() .pad(PAD) .w_of(ids.side_menu) .h(SELECTED_CANVAS_H) @@ -297,7 +298,7 @@ pub fn set( let i = match speaker_editor.selected { None => { // Otherwise no speaker is selected. - widget::Text::new("No speaker selected") + ui::widget::Text::new("No speaker selected") .padded_w_of(area.id, TEXT_PAD) .mid_top_with_margin_on(ids.speaker_editor_selected_canvas, TEXT_PAD) .font_size(SMALL_FONT_SIZE) @@ -312,7 +313,7 @@ pub fn set( let id = speakers_vec[i]; // The name of the speaker. - for event in widget::TextBox::new(&speakers[&id].name) + for event in ui::widget::TextBox::new(&speakers[&id].name) .mid_top_of(ids.speaker_editor_selected_canvas) .kid_area_w_of(ids.speaker_editor_selected_canvas) .parent(gui.ids.speaker_editor_selected_canvas) @@ -321,7 +322,7 @@ pub fn set( .font_size(SMALL_FONT_SIZE) .set(ids.speaker_editor_selected_name, ui) { - if let widget::text_box::Event::Update(string) = event { + if let ui::widget::text_box::Event::Update(string) = event { speakers.get_mut(&id).unwrap().name = string; } } @@ -340,7 +341,7 @@ pub fn set( let selected_channel = speakers[&id].audio.channel; // The drop down list for channel selection. - for new_index in widget::DropDownList::new(&channel_vec, Some(selected_channel)) + for new_index in ui::widget::DropDownList::new(&channel_vec, Some(selected_channel)) .down_from(ids.speaker_editor_selected_name, PAD) .align_middle_x_of(ids.side_menu) .kid_area_w_of(ids.speaker_editor_selected_canvas) @@ -349,7 +350,7 @@ pub fn set( .scrollbar_on_top() .max_visible_items(5) .color(DARK_A) - .border_color(color::LIGHT_CHARCOAL) + .border_color(ui::color::LIGHT_CHARCOAL) .label_font_size(SMALL_FONT_SIZE) .set(ids.speaker_editor_selected_channel, ui) { @@ -391,16 +392,16 @@ pub fn set( } // A canvas on which installation selection widgets are instantiated. - widget::Canvas::new() + ui::widget::Canvas::new() .kid_area_w_of(ids.speaker_editor_selected_canvas) .h(INSTALLATIONS_CANVAS_H) .mid_bottom_of(ids.speaker_editor_selected_canvas) .pad(PAD) - .color(color::CHARCOAL) + .color(ui::color::CHARCOAL) .set(ids.speaker_editor_selected_installations_canvas, ui); // A header for the installations editing area. - widget::Text::new("Installations") + ui::widget::Text::new("Installations") .top_left_of(ids.speaker_editor_selected_installations_canvas) .font_size(SMALL_FONT_SIZE) .set(ids.speaker_editor_selected_installations_text, ui); @@ -417,7 +418,7 @@ pub fn set( .iter() .map(|inst_id| &installations[&inst_id].name) .collect::>(); - for index in widget::DropDownList::new(&installation_strs, None) + for index in ui::widget::DropDownList::new(&installation_strs, None) .align_middle_x_of(ids.speaker_editor_selected_installations_canvas) .down_from(ids.speaker_editor_selected_installations_text, PAD * 2.0) .h(ITEM_HEIGHT) @@ -458,17 +459,15 @@ pub fn set( .iter() .cloned() .collect::>(); - selected_installations.sort_by(|a, b| { - installations[a].name.cmp(&installations[b].name) - }); - let (mut items, scrollbar) = widget::List::flow_down(selected_installations.len()) + selected_installations.sort_by(|a, b| installations[a].name.cmp(&installations[b].name)); + let (mut items, scrollbar) = ui::widget::List::flow_down(selected_installations.len()) .item_size(ITEM_HEIGHT) .h(INSTALLATION_LIST_H) .kid_area_w_of(ids.speaker_editor_selected_installations_canvas) .align_middle_x_of(ids.speaker_editor_selected_installations_canvas) .down_from(ids.speaker_editor_selected_installations_ddl, PAD) .scrollbar_next_to() - .scrollbar_color(color::LIGHT_CHARCOAL) + .scrollbar_color(ui::color::LIGHT_CHARCOAL) .set(ids.speaker_editor_selected_installations_list, ui); let mut maybe_remove_index = None; while let Some(item) = items.next(ui) { @@ -476,22 +475,24 @@ pub fn set( let label = &installations[&inst].name; // Use `Button`s for the selectable items. - let button = widget::Button::new() + let button = ui::widget::Button::new() .label(&label) .label_font_size(SMALL_FONT_SIZE) - .label_x(position::Relative::Place(position::Place::Start(Some( - 10.0, - )))); + .label_x(ui::position::Relative::Place(ui::position::Place::Start( + Some(10.0), + ))); item.set(button, ui); // If the button or any of its children are capturing the mouse, display // the `remove` button. - let show_remove_button = ui.global_input() + let show_remove_button = ui + .global_input() .current .widget_capturing_mouse .map(|id| { id == item.widget_id - || ui.widget_graph() + || ui + .widget_graph() .does_recursive_depth_edge_exist(item.widget_id, id) }) .unwrap_or(false); @@ -500,10 +501,10 @@ pub fn set( continue; } - if widget::Button::new() + if ui::widget::Button::new() .label("X") .label_font_size(SMALL_FONT_SIZE) - .color(color::DARK_RED.alpha(0.5)) + .color(ui::color::DARK_RED.alpha(0.5)) .w_h(ITEM_HEIGHT, ITEM_HEIGHT) .align_right_of(item.widget_id) .align_middle_y_of(item.widget_id) diff --git a/src/lib/gui/theme.rs b/src/lib/gui/theme.rs index 475bcd4..0417e06 100644 --- a/src/lib/gui/theme.rs +++ b/src/lib/gui/theme.rs @@ -1,14 +1,16 @@ -use nannou::ui::{self, widget}; -use nannou::ui::theme::WidgetDefault; +use conrod_core as ui; +use conrod_core::{position, Range, Scalar}; +use nannou_conrod::theme::WidgetDefault; +use nannou_conrod::{self, widget}; use std; /// The default width for a widget within a column. -pub const DEFAULT_WIDTH: ui::Scalar = 220.0; +pub const DEFAULT_WIDTH: Scalar = 220.0; -fn common_style(w: ui::Scalar, h: ui::Scalar) -> widget::CommonStyle { +fn common_style(w: ui::Scalar, h: Scalar) -> widget::CommonStyle { widget::CommonStyle { - maybe_x_dimension: Some(ui::position::Dimension::Absolute(w)), - maybe_y_dimension: Some(ui::position::Dimension::Absolute(h)), + maybe_x_dimension: Some(position::Dimension::Absolute(w)), + maybe_y_dimension: Some(position::Dimension::Absolute(h)), ..widget::CommonStyle::default() } } @@ -24,9 +26,9 @@ where pub fn construct() -> ui::Theme { ui::Theme { name: "Monochroma".to_owned(), - padding: ui::position::Padding { - x: ui::Range::new(20.0, 20.0), - y: ui::Range::new(20.0, 20.0), + padding: position::Padding { + x: Range::new(20.0, 20.0), + y: Range::new(20.0, 20.0), }, background_color: ui::color::DARK_CHARCOAL, shape_color: ui::color::BLACK, diff --git a/src/lib/installation.rs b/src/lib/installation.rs index c55ce75..8130450 100644 --- a/src/lib/installation.rs +++ b/src/lib/installation.rs @@ -4,9 +4,9 @@ //! hard-coded and rather identified via dynamically generated unique IDs. Otherwise, most //! of the logic should remain the same. -use serde::{Deserialize, Deserializer}; +use crate::utils::Range; +use serde::{Deserialize, Deserializer, Serialize}; use slug::slugify; -use utils::Range; /// All known beyond perception installations (used by default). pub const BEYOND_PERCEPTION_NAMES: &'static [&'static str] = &[ @@ -53,8 +53,11 @@ impl<'de> Deserialize<'de> for Id { serde_json::Value::Number(n) => { let u = n.as_u64().expect("could not deserialize Id number to u64") as usize; Ok(Id(u)) - }, - err => panic!("failed to deserialize `Id`: expected String or Int, found {:?}", err), + } + err => panic!( + "failed to deserialize `Id`: expected String or Int, found {:?}", + err + ), } } } @@ -81,7 +84,11 @@ impl Default for Installation { let name = default::name().into(); let computers = Default::default(); let soundscape = Default::default(); - Installation { name, computers, soundscape } + Installation { + name, + computers, + soundscape, + } } } @@ -95,7 +102,9 @@ pub struct Soundscape { impl Default for Soundscape { fn default() -> Self { let simultaneous_sounds = default::SIMULTANEOUS_SOUNDS; - Soundscape { simultaneous_sounds } + Soundscape { + simultaneous_sounds, + } } } @@ -123,7 +132,7 @@ pub fn beyond_perception_default_num_computers(name: &str) -> Option { /// Default soundscape constraints. pub mod default { - use utils::Range; + use crate::utils::Range; pub const SIMULTANEOUS_SOUNDS: Range = Range { min: 1, max: 8 }; @@ -143,6 +152,7 @@ pub mod default { /// State related to the computers available to an installation. pub mod computer { use fxhash::FxHashMap; + use serde::{Deserialize, Serialize}; use std::net; /// A unique identifier for a single computer within an installation. diff --git a/src/lib/lib.rs b/src/lib/lib.rs index f807c33..b4af524 100644 --- a/src/lib/lib.rs +++ b/src/lib/lib.rs @@ -1,40 +1,12 @@ // Extend the macro recursion limit to allow for many GUI widget IDs. #![recursion_limit = "256"] -#[macro_use] -extern crate conrod_core; -#[macro_use] -extern crate conrod_derive; -extern crate crossbeam; -#[macro_use] -extern crate custom_derive; -extern crate fxhash; -extern crate hound; // wav loading -extern crate nannou; -extern crate nannou_audio; -extern crate nannou_osc; -#[macro_use] -extern crate newtype_derive; -extern crate num_cpus; -extern crate pitch_calc; -extern crate rand_xorshift; -extern crate rustfft; -extern crate serde; // serialization -#[macro_use] -extern crate serde_derive; -extern crate serde_json; -extern crate slug; -extern crate time_calc; -extern crate threadpool; -extern crate utils as mindtree_utils; -extern crate walkdir; - use config::Config; use nannou::prelude::*; use soundscape::Soundscape; use std::path::{Path, PathBuf}; -use std::sync::{mpsc, Arc}; use std::sync::atomic::AtomicUsize; +use std::sync::{mpsc, Arc}; mod audio; mod camera; @@ -43,8 +15,8 @@ mod gui; mod installation; mod master; mod metres; -mod project; mod osc; +mod project; mod soundscape; mod utils; @@ -89,18 +61,19 @@ fn model(app: &App) -> Model { } // Find the assets directory. - let assets = app.assets_path() - .expect("could not find assets directory"); + let assets = app.assets_path().expect("could not find assets directory"); // Load the configuration struct. let config_path = config_path(&assets); let config: Config = utils::load_from_json_or_default(&config_path); // Spawn the OSC input thread. - let osc_receiver = nannou_osc::receiver(config.osc_input_port) - .unwrap_or_else(|err| { - panic!("failed to create OSC receiver bound to port {}: {}", config.osc_input_port, err) - }); + let osc_receiver = nannou_osc::receiver(config.osc_input_port).unwrap_or_else(|err| { + panic!( + "failed to create OSC receiver bound to port {}: {}", + config.osc_input_port, err + ) + }); let (_osc_in_thread_handle, osc_in_log_rx, control_rx) = osc::input::spawn(osc_receiver); // Spawn the OSC output thread. @@ -108,8 +81,8 @@ fn model(app: &App) -> Model { // A channel for sending active sound info from the audio thread to the GUI. let app_proxy = app.create_proxy(); - let (audio_monitor, audio_monitor_tx, audio_monitor_rx) = gui::monitor::spawn(app_proxy) - .expect("failed to spawn audio_monitor thread"); + let (audio_monitor, audio_monitor_tx, audio_monitor_rx) = + gui::monitor::spawn(app_proxy).expect("failed to spawn audio_monitor thread"); // Spawn the thread used for reading wavs. let wav_reader = audio::source::wav::reader::spawn(); @@ -181,7 +154,8 @@ fn model(app: &App) -> Model { ); // Create a window. - let window = app.new_window() + let window = app + .new_window() .title("Audio Server") .size(config.window_width, config.window_height) .build() @@ -234,13 +208,21 @@ fn model(app: &App) -> Model { // Update the application in accordance with the given event. fn update(_app: &App, model: &mut Model, _update: Update) { - let Model { ref mut gui, ref config, .. } = *model; + let Model { + ref mut gui, + ref config, + .. + } = *model; gui.update(&config.project_default); } // Draw the state of the application to the screen. fn view(app: &App, model: &Model, frame: Frame) { - model.gui.ui.draw_to_frame_if_changed(app, &frame).expect("failed to draw to frame"); + model + .gui + .ui + .draw_to_frame_if_changed(app, &frame) + .expect("failed to draw to frame"); } // Re-join with spawned threads on application exit. @@ -281,13 +263,19 @@ fn exit(app: &App, model: Model) { // Wait for the audio monitoring thread to close // // This should be instant as `GUI` has exited and the receiving channel should be dropped. - audio_monitor.join().expect("failed to join audio_monitor thread when exiting"); + audio_monitor + .join() + .expect("failed to join audio_monitor thread when exiting"); // Send exit signal to the composer thread. let soundscape_thread = soundscape.exit().expect("failed to exit soundscape thread"); - soundscape_thread.join().expect("failed to join the soundscape thread when exiting"); + soundscape_thread + .join() + .expect("failed to join the soundscape thread when exiting"); // Send exit signal to the wav reader thread. let wav_reader_thread = wav_reader.exit().expect("failed to exit wav_reader thread"); - wav_reader_thread.join().expect("failed to join the wav_reader thread when exiting"); + wav_reader_thread + .join() + .expect("failed to join the wav_reader thread when exiting"); } diff --git a/src/lib/master.rs b/src/lib/master.rs index 0bef232..ca62fa3 100644 --- a/src/lib/master.rs +++ b/src/lib/master.rs @@ -1,6 +1,7 @@ -use audio; +use crate::audio; +use crate::metres::Metres; +use serde::{Deserialize, Serialize}; use time_calc::Ms; -use metres::Metres; /// Master state of the project. #[derive(Clone, Debug, Deserialize, Serialize)] @@ -27,8 +28,12 @@ impl Default for Master { let realtime_source_latency = default_realtime_source_latency(); let dbap_rolloff_db = default_dbap_rolloff_db(); let proximity_limit_2 = default_proximity_limit(); - Master { volume, realtime_source_latency, - dbap_rolloff_db, proximity_limit_2 } + Master { + volume, + realtime_source_latency, + dbap_rolloff_db, + proximity_limit_2, + } } } diff --git a/src/lib/metres.rs b/src/lib/metres.rs index 4f58cb6..cf7594e 100644 --- a/src/lib/metres.rs +++ b/src/lib/metres.rs @@ -1,20 +1,12 @@ -custom_derive! { - /// Used for describing locations throughout the installation. - /// - /// Using this GUI agnostic measurement greatly simplifies positioning and makes it easier - #[derive(Copy, Clone, Debug, Default, PartialEq, PartialOrd, - NewtypeFrom, - NewtypeAdd, NewtypeSub, NewtypeMul, NewtypeMul(f64), NewtypeDiv, NewtypeDiv(f64), - NewtypeAddAssign, NewtypeSubAssign, NewtypeMulAssign, NewtypeDivAssign, - NewtypeMulAssign(f64), NewtypeDivAssign(f64), - NewtypeRem, NewtypeRemAssign, - NewtypeNeg)] - #[derive(Serialize, Deserialize)] - pub struct Metres(pub f64); +pub type Metres = f64; //(pub f64); + +pub trait Metric { + fn min(self: Self, other: Self) -> Self; + fn max(self: Self, other: Self) -> Self; } -impl Metres { - pub fn min(self, other: Self) -> Self { +impl Metric for Metres { + fn min(self, other: Self) -> Self { if other < self { other } else { @@ -22,7 +14,7 @@ impl Metres { } } - pub fn max(self, other: Self) -> Self { + fn max(self, other: Self) -> Self { if other > self { other } else { diff --git a/src/lib/osc/output.rs b/src/lib/osc/output.rs index c0c0a6b..a65e23b 100644 --- a/src/lib/osc/output.rs +++ b/src/lib/osc/output.rs @@ -1,13 +1,12 @@ -use crossbeam::sync::MsQueue; +use crate::installation; +use crossbeam::queue::SegQueue; use fxhash::FxHashMap; -use installation; use nannou_osc as osc; use nannou_osc::Type::{Float, Int}; -use std; use std::iter::once; use std::sync::{mpsc, Arc}; -pub type MessageQueue = Arc>; +pub type MessageQueue = Arc>; pub type Tx = MessageQueue; type Rx = MessageQueue; @@ -79,7 +78,7 @@ pub struct Log { /// Spawn the osc sender thread. pub fn spawn() -> (std::thread::JoinHandle<()>, Tx, mpsc::Receiver) { - let msg_queue = Arc::new(MsQueue::new()); + let msg_queue = Arc::new(SegQueue::new()); let msg_tx = msg_queue.clone(); let msg_rx = msg_queue; let (log_tx, log_rx) = mpsc::channel(); @@ -125,12 +124,10 @@ fn run(msg_rx: Rx, log_tx: mpsc::Sender) { // Start a thread for converting `Message`s to `Update`s. std::thread::Builder::new() .name("osc_output_msg_to_update".into()) - .spawn(move || { - loop { - let msg = msg_rx.pop(); - if update_tx.send(Update::Msg(msg)).is_err() { - break; - } + .spawn(move || loop { + let msg = msg_rx.pop().unwrap(); + if update_tx.send(Update::Msg(msg)).is_err() { + break; } }) .unwrap(); @@ -146,7 +143,7 @@ fn run(msg_rx: Rx, log_tx: mpsc::Sender) { last_received.clear(); last_sent.clear(); osc_txs.clear(); - }, + } // Audio data received that is to be delivered to the given installation. Message::Audio(installation, data) => { last_received.insert(installation, data); @@ -166,7 +163,7 @@ fn run(msg_rx: Rx, log_tx: mpsc::Sender) { // If we couldn't find the exising socket, we skip it. None => continue, } - }, + } }; osc_txs .entry(installation_id) @@ -191,81 +188,83 @@ fn run(msg_rx: Rx, log_tx: mpsc::Sender) { }, }, - Update::SendOsc => for (installation, data) in last_received.drain() { - let AudioFrameData { - avg_peak, - avg_rms, - avg_fft, - speakers, - } = data; + Update::SendOsc => { + for (installation, data) in last_received.drain() { + let AudioFrameData { + avg_peak, + avg_rms, + avg_fft, + speakers, + } = data; - let targets = match osc_txs.get(&installation) { - Some(targets) => targets, - None => continue, - }; + let targets = match osc_txs.get(&installation) { + Some(targets) => targets, + None => continue, + }; - // The buffer used to collect arguments. - let mut args = Vec::new(); + // The buffer used to collect arguments. + let mut args = Vec::new(); - // Push the analysis of the averaged channels. - args.push(Float(avg_peak)); - args.push(Float(avg_rms)); - let lmh = avg_fft.lmh.iter().map(|&f| Float(f)); - args.extend(lmh); - let bins = avg_fft.bins.iter().map(|&f| Float(f)); - args.extend(bins); + // Push the analysis of the averaged channels. + args.push(Float(avg_peak)); + args.push(Float(avg_rms)); + let lmh = avg_fft.lmh.iter().map(|&f| Float(f)); + args.extend(lmh); + let bins = avg_fft.bins.iter().map(|&f| Float(f)); + args.extend(bins); - // Push the Peak and RMS per speaker. - let speakers = speakers.into_iter().enumerate().flat_map(|(i, s)| { - once(Int(i as _)) - .chain(once(Float(s.peak))) - .chain(once(Float(s.rms))) - }); - args.extend(speakers); + // Push the Peak and RMS per speaker. + let speakers = speakers.into_iter().enumerate().flat_map(|(i, s)| { + once(Int(i as _)) + .chain(once(Float(s.peak))) + .chain(once(Float(s.rms))) + }); + args.extend(speakers); - // Retrieve the OSC sender for each computer in the installation. - for target in targets.iter() { - let ( - &computer, - &Target { - ref osc_tx, - ref osc_addr, - }, - ) = target; - let addr = &osc_addr[..]; + // Retrieve the OSC sender for each computer in the installation. + for target in targets.iter() { + let ( + &computer, + &Target { + ref osc_tx, + ref osc_addr, + }, + ) = target; + let addr = &osc_addr[..]; - // Send the message! - let msg = osc::Message { - addr: addr.into(), - args: Some(args.clone()), - }; + // Send the message! + let msg = osc::Message { + addr: addr.into(), + args: Some(args.clone()), + }; - // If the message is the same as the last one we sent for this computer, don't - // bother sending it again. - if last_sent.get(&(installation, computer)) == Some(&msg) { - continue; - } + // If the message is the same as the last one we sent for this computer, don't + // bother sending it again. + if last_sent.get(&(installation, computer)) == Some(&msg) { + continue; + } - // Send the OSC. - let error = osc_tx.send(msg.clone()).err(); + // Send the OSC. + let error = osc_tx.send(msg.clone()).err(); - // Update the `last_sent` map if there were no errors. - if error.is_none() { - last_sent.insert((installation, computer), msg.clone()); - } + // Update the `last_sent` map if there were no errors. + if error.is_none() { + last_sent.insert((installation, computer), msg.clone()); + } - // Log the message for displaying in the GUI. - let addr = osc_tx.remote_addr(); - let log = Log { - installation, - computer, - addr, - msg, - error, - }; - log_tx.send(log).ok(); + // Log the message for displaying in the GUI. + let addr = osc_tx.remote_addr(); + let log = Log { + installation, + computer, + addr, + msg, + error, + }; + log_tx.send(log).ok(); + } } - }, + } } } } diff --git a/src/lib/project/config.rs b/src/lib/project/config.rs index c3f10ba..e0ebfce 100644 --- a/src/lib/project/config.rs +++ b/src/lib/project/config.rs @@ -1,5 +1,7 @@ -use metres::Metres; -use utils::Seed; +use serde::{Deserialize, Serialize}; + +use crate::metres::Metres; +use crate::utils::Seed; /// Various configuration parameters for a single project. #[derive(Copy, Clone, Debug, PartialEq, Deserialize, Serialize)] @@ -62,8 +64,8 @@ impl Default for Config { // Fallback parameters in the case that they are missing from the file or invalid. pub mod default { - use metres::Metres; - use utils::Seed; + use crate::metres::Metres; + use crate::utils::Seed; pub fn window_width() -> u32 { 1280 @@ -87,10 +89,10 @@ pub mod default { 148.0 } pub fn min_speaker_radius_metres() -> Metres { - Metres(0.25) + 0.25 } pub fn max_speaker_radius_metres() -> Metres { - Metres(1.0) + 1.0 } pub fn seed() -> Seed { @@ -98,6 +100,6 @@ pub mod default { } pub fn proximity_limit() -> Metres { - ::audio::DEFAULT_PROXIMITY_LIMIT_2 + crate::audio::DEFAULT_PROXIMITY_LIMIT_2 } } diff --git a/src/lib/project/mod.rs b/src/lib/project/mod.rs index fd8df5c..8b674ce 100644 --- a/src/lib/project/mod.rs +++ b/src/lib/project/mod.rs @@ -11,22 +11,23 @@ //! 4. Seaker layout. //! 5. Audio source params and soundscape constraints. -use audio; -use camera::Camera; +use crate::audio; +use crate::camera::Camera; +use crate::gui; +use crate::installation::{self, Installation}; +use crate::master::Master; +use crate::osc; +use crate::soundscape; +use crate::utils; use fxhash::{FxHashMap, FxHashSet}; -use gui; -use installation::{self, Installation}; -use master::Master; -use osc; +use serde::{Deserialize, Serialize}; use slug::slugify; -use soundscape; -use std::{cmp, fs, io}; use std::ffi::OsStr; use std::mem; use std::ops::{Deref, DerefMut}; use std::path::{Component, Path, PathBuf}; use std::sync::Arc; -use utils; +use std::{cmp, fs, io}; use walkdir::WalkDir; pub mod config; @@ -177,7 +178,11 @@ impl State { /// /// Returns `true` if installations were renamed, false if not. fn auto_name_installations_if_all_unnamed(&mut self) -> bool { - if self.installations.values().all(|inst| &inst.name == installation::default::name()) { + if self + .installations + .values() + .all(|inst| &inst.name == installation::default::name()) + { for (id, installation) in self.installations.iter_mut() { let name = match id.0 { 0 => "Waves At Work", @@ -198,18 +203,13 @@ impl State { false } } - } impl Project { /// Construct the project from its `State` and `Config` parts. /// /// This is used internally within the `load` and `default` constructors. - fn from_config_and_state

( - assets: P, - config: Config, - mut state: State, - ) -> Self + fn from_config_and_state

(assets: P, config: Config, mut state: State) -> Self where P: AsRef, { @@ -363,8 +363,6 @@ impl Project { .expect("failed to send source to soundscape thread"); } } - - } /// Create a new project with a unique, default name. @@ -387,7 +385,7 @@ impl Project { } else { i += 1; } - }; + } // Create the default state. let config = default_config.clone(); @@ -418,24 +416,20 @@ impl Project { /// /// **Panics** if the project "state.json" does not exist or is invalid. However, the method /// will attempt to fall back to reasonable default for each field that cannot be deserialized. - pub fn load( - assets_path: A, - project_directory_path: P, - default_config: &Config, - ) -> Self + pub fn load(assets_path: A, project_directory_path: P, default_config: &Config) -> Self where A: AsRef, P: AsRef, { // Load the configuration json. let config_path = project_config_path(&project_directory_path); - let config: Config = utils::load_from_json(&config_path) - .unwrap_or_else(|_| default_config.clone()); + let config: Config = + utils::load_from_json(&config_path).unwrap_or_else(|_| default_config.clone()); // Load the state json. let state_path = project_state_path(project_directory_path); - let state: State = utils::load_from_json(&state_path) - .expect("failed to load project state"); + let state: State = + utils::load_from_json(&state_path).expect("failed to load project state"); Self::from_config_and_state(assets_path, config, state) } @@ -492,7 +486,10 @@ impl Sources { /// This is necessary for startup where the soloed file may contain sources that are no longer /// valid. pub fn remove_invalid_soloed(&mut self) { - let Sources { ref map, ref mut soloed } = *self; + let Sources { + ref map, + ref mut soloed, + } = *self; soloed.retain(|id| map.contains_key(id)); } @@ -530,7 +527,8 @@ where _ => false, }) .map(|_| { - relative.components() + relative + .components() .chain(components) .map(|c| c.as_os_str()) .collect() @@ -542,7 +540,10 @@ fn test_update_path_from_relative() { let path = Path::new("/foo/bar/baz/qux"); let relative = Path::new("/flim/baz"); let expected = Path::new("/flim/baz/qux"); - assert_eq!(update_path_from_relative(path, relative), Some(PathBuf::from(expected))); + assert_eq!( + update_path_from_relative(path, relative), + Some(PathBuf::from(expected)) + ); } /// Check for invalid WAV sources. @@ -576,22 +577,29 @@ where let mut new_wav = match audio::source::Wav::from_path(new_path.clone()) { Ok(wav) => wav, Err(err) => { - eprintln!("Failed to load wav from path \"{}\": {}. It will be ignored.", - new_path.display(), err); + eprintln!( + "Failed to load wav from path \"{}\": {}. It will be ignored.", + new_path.display(), + err + ); continue; - }, + } }; new_wav.should_loop = wav.should_loop; new_wav.playback = wav.playback; mem::swap(wav, &mut new_wav); continue; } - eprintln!("Could not find WAV source at \"{}\" or at \"{}\". It will be ignored.", - wav.path.display(), - new_path.display()); + eprintln!( + "Could not find WAV source at \"{}\" or at \"{}\". It will be ignored.", + wav.path.display(), + new_path.display() + ); } else { - eprintln!("Could not find WAV source at \"{}\". It will be ignored.", - wav.path.display()); + eprintln!( + "Could not find WAV source at \"{}\". It will be ignored.", + wav.path.display() + ); } to_remove.push(id); @@ -645,11 +653,13 @@ where // If we already have this one, continue. for s in sources.map.values() { match s.audio.kind { - audio::source::Kind::Wav(ref wav) => if wav.path == path { + audio::source::Kind::Wav(ref wav) => { if wav.path == path { - continue 'paths; + if wav.path == path { + continue 'paths; + } } - }, + } _ => (), } } @@ -794,8 +804,8 @@ pub fn default_beyond_perception_installations() -> Installations { .enumerate() .map(|(i, &name)| { let id = installation::Id(i); - let n_computers = installation::beyond_perception_default_num_computers(name) - .unwrap_or(0); + let n_computers = + installation::beyond_perception_default_num_computers(name).unwrap_or(0); let osc_addr = installation::osc_addr_string(name); let computers = (0..n_computers) .map(|i| { @@ -808,7 +818,11 @@ pub fn default_beyond_perception_installations() -> Installations { .collect(); let soundscape = Default::default(); let name = name.into(); - let installation = Installation { name, computers, soundscape }; + let installation = Installation { + name, + computers, + soundscape, + }; (id, installation) }) .collect() @@ -869,7 +883,11 @@ where .filter_map(Result::ok) .map(|e| e.path()) .filter(|p| p.is_dir()) - .filter(|p| p.join(STATE_FILE_STEM).with_extension(STATE_EXTENSION).exists()) + .filter(|p| { + p.join(STATE_FILE_STEM) + .with_extension(STATE_EXTENSION) + .exists() + }) .collect(); Ok(paths) } diff --git a/src/lib/soundscape/group.rs b/src/lib/soundscape/group.rs index 3f18fba..69cb22e 100644 --- a/src/lib/soundscape/group.rs +++ b/src/lib/soundscape/group.rs @@ -2,8 +2,9 @@ //! //! Soundscape groups allow for describing rules/constraints for multiple sounds at once. +use crate::utils::Range; +use serde::{Deserialize, Serialize}; use time_calc::Ms; -use utils::Range; /// A name for a soundscape group. #[derive(Clone, Debug, Eq, PartialOrd, Ord, PartialEq, Hash, Deserialize, Serialize)] @@ -21,8 +22,8 @@ pub struct Group { } pub mod default { + use crate::utils::{Range, HR_MS}; use time_calc::Ms; - use utils::{Range, HR_MS}; pub const OCCURRENCE_RATE: Range = Range { min: Ms(0.0), max: Ms(HR_MS as _), diff --git a/src/lib/soundscape/mod.rs b/src/lib/soundscape/mod.rs index e12c425..d80a18c 100644 --- a/src/lib/soundscape/mod.rs +++ b/src/lib/soundscape/mod.rs @@ -1,24 +1,31 @@ -use audio; +use crate::{ + audio, installation, + metres::Metres, + utils::{self, duration_to_secs, Range, Seed}, +}; +use ::utils::noise_walk; use fxhash::{FxHashMap, FxHashSet}; -use installation; -use metres::Metres; -use mindtree_utils::noise_walk; -use nannou; -use nannou::prelude::*; -use nannou::rand::{Rng, SeedableRng}; +use nannou::{ + self, + prelude::*, + rand::{Rng, SeedableRng}, +}; use rand_xorshift::XorShiftRng; -use std::cmp; -use std::ops; -use std::sync::atomic::{AtomicBool, AtomicUsize}; -use std::sync::{atomic, mpsc, Arc, Mutex}; -use std::thread; -use std::time; +use std::{ + cmp, ops, + sync::{ + atomic::{self, AtomicBool, AtomicUsize}, + mpsc, Arc, Mutex, + }, + thread, time, +}; use time_calc::Ms; -use utils::{self, duration_to_secs, Range, Seed}; + +type Point2 = nannou::glam::DVec2; pub use self::group::Group; -pub use self::movement::Movement; use self::movement::BoundingRect; +pub use self::movement::Movement; pub mod group; pub mod movement; @@ -86,7 +93,7 @@ pub struct Soundscape { #[derive(Clone, Debug)] pub struct Speaker { /// The position of the speaker in metres. - pub point: Point2, + pub point: Point2, /// All installations assigned to the speaker. pub installations: FxHashSet, } @@ -155,7 +162,6 @@ pub struct Model { // They should not be relied upon to have up-to-date state without first calling their // associated `update_*` function. These are primarily for efficiency within the `tick` // function. - /// Tracks the speakers assignned to each installation. Updated at the beginning of each tick. installation_speakers: InstallationSpeakers, /// This tracks the bounding area for each installation at the beginning of each tick. @@ -172,7 +178,6 @@ pub struct Model { available_sources: AvailableSources, // Communication channels. - /// A handle to the wav reader thread. wav_reader: audio::source::wav::reader::Handle, /// A handle for submitting new sounds to the input stream. @@ -246,7 +251,7 @@ impl ActiveSound { let source_id = self.handle.source_id(); ActiveSoundPosition { source_id, - position + position, } } } @@ -373,8 +378,7 @@ impl Model { pub fn remove_installation( &mut self, id: &installation::Id, - ) -> Option - { + ) -> Option { // Remove from speakers. for speaker in self.speakers.values_mut() { speaker.installations.remove(id); @@ -540,7 +544,7 @@ impl Model { ); // Update the sound. active_sounds.get_mut(&sound_id).unwrap().movement = movement; - }, + } } } } @@ -749,11 +753,13 @@ pub fn spawn( }; // Spawn the soundscape thread. + /* let thread = thread::Builder::new() .name("soundscape".into()) .spawn(move || run(model, rx)) .unwrap(); - let thread = Arc::new(Mutex::new(Some(thread))); + // */ + let thread = Arc::new(Mutex::new(None)); Soundscape { tx, thread, @@ -798,7 +804,9 @@ fn update_active_sound_positions( active_sound_positions: &mut ActiveSoundPositions, ) { active_sound_positions.clear(); - let extension = active_sounds.iter().map(|(&id, sound)| (id, sound.active_sound_position())); + let extension = active_sounds + .iter() + .map(|(&id, sound)| (id, sound.active_sound_position())); active_sound_positions.extend(extension); } @@ -813,36 +821,30 @@ fn closest_assigned_installation( sound: &ActiveSoundPosition, sources: &Sources, installation_areas: &InstallationAreas, -) -> Option -{ +) -> Option { if let Some(source) = sources.get(&sound.source_id) { - let sound_point = Point2 { - x: sound.position.x.0, - y: sound.position.y.0, - }; + let sound_point = Point2::new(sound.position.point.x, sound.position.point.y); let mut distances = source .constraints .installations .iter() .filter_map(|&i| installation_areas.get(&i).map(|a| (i, a))) .map(|(i, a)| { - let centroid = Point2 { - x: a.centroid.x.0, - y: a.centroid.y.0, - }; - (i, sound_point.distance2(centroid)) + let centroid = Point2::new(a.centroid.x, a.centroid.y); + (i, sound_point.distance(centroid)) }); if let Some((i, dist)) = distances.next() { - let (closest_installation, _) = distances.fold( - (i, dist), - |(ia, min), (ib, dist)| { - if dist < min { - (ib, dist) - } else { - (ia, min) - } - }, - ); + let (closest_installation, _) = + distances.fold( + (i, dist), + |(ia, min), (ib, dist)| { + if dist < min { + (ib, dist) + } else { + (ia, min) + } + }, + ); return Some(closest_installation); } } @@ -877,14 +879,13 @@ fn agent_installation_data( installation_areas: &InstallationAreas, target_sounds_per_installation: &TargetSoundsPerInstallation, active_sound_positions: &ActiveSoundPositions, -) -> movement::agent::InstallationDataMap -{ +) -> movement::agent::InstallationDataMap { // We can't find installation data if there is no source for the given id. let source = match sources.get(&source_id) { None => { eprintln!("`agent_installation_data`: no source found for given `source::Id`"); return Default::default(); - }, + } Some(s) => s, }; @@ -906,7 +907,7 @@ fn agent_installation_data( .filter_map(|inst| { let area = match installation_areas.get(inst) { None => return None, - Some(area) => area.clone() + Some(area) => area.clone(), }; let range = &installations[inst].simultaneous_sounds; let current_num_sounds = active_sounds_per_installation @@ -959,11 +960,11 @@ fn generate_movement( .expect("no area for the given installation"); let x = area.bounding_rect.left + area.bounding_rect.width() * pos.x; let y = area.bounding_rect.bottom + area.bounding_rect.height() * pos.y; - let point = pt2(x, y); + let point = Point2::new(x, y); let radians = 0.0; let position = audio::sound::Position { point, radians }; Movement::Fixed(position) - }, + } audio::source::Movement::Generative(ref gen) => match *gen { audio::source::movement::Generative::Agent(ref agent) => { let mut rng = nannou::rand::thread_rng(); @@ -996,7 +997,7 @@ fn generate_movement( let generative = movement::Generative::Agent(agent); let movement = Movement::Generative(generative); movement - }, + } audio::source::movement::Generative::Ngon(ref ngon) => { let mut rng = nannou::rand::thread_rng(); @@ -1067,9 +1068,10 @@ fn update_installation_areas( None => continue, Some(rect) => rect, }; - let centroid = match nannou::geom::centroid(speaker_points().map(|p| pt2(p.x.0, p.y.0))) { + let centroid = match nannou::geom::centroid(speaker_points().map(|p| Point2::new(p.x, p.y))) + { None => continue, - Some(p) => pt2(Metres(p.x), Metres(p.y)), + Some(p) => Point2::new(p.x, p.y), }; let area = movement::Area { bounding_rect, @@ -1151,71 +1153,66 @@ fn update_available_groups( available_groups: &mut AvailableGroups, ) { available_groups.clear(); - let extension = groups - .iter() - .filter_map(|(group_id, group)| { - // The total number of active sounds spawned via this group across all installations. - let num_active_sounds = active_sounds - .values() - .filter(|sound| { - let source_id = sound.source_id(); - let source = match sources.get(&source_id) { - None => return false, - Some(s) => s, - }; - source.groups.contains(group_id) - }) - .count(); + let extension = groups.iter().filter_map(|(group_id, group)| { + // The total number of active sounds spawned via this group across all installations. + let num_active_sounds = active_sounds + .values() + .filter(|sound| { + let source_id = sound.source_id(); + let source = match sources.get(&source_id) { + None => return false, + Some(s) => s, + }; + source.groups.contains(group_id) + }) + .count(); - // If there are no available sounds, skip this group. - let num_available_sounds = if group.simultaneous_sounds.max > num_active_sounds { - group.simultaneous_sounds.max - num_active_sounds - } else { - return None; - }; + // If there are no available sounds, skip this group. + let num_available_sounds = if group.simultaneous_sounds.max > num_active_sounds { + group.simultaneous_sounds.max - num_active_sounds + } else { + return None; + }; - let num_sounds_needed = if group.simultaneous_sounds.min > num_active_sounds { - group.simultaneous_sounds.min - num_active_sounds - } else { - 0 - }; + let num_sounds_needed = if group.simultaneous_sounds.min > num_active_sounds { + group.simultaneous_sounds.min - num_active_sounds + } else { + 0 + }; - // Find the duration since the last time a sound was spawned using a source from - // this group. - let timing = if let Some(&last_used) = groups_last_used.get(group_id) { - let duration_since_last: time::Duration = - tick.instant.duration_since(last_used); - let duration_since_last_ms = - Ms(duration_to_secs(&duration_since_last) * 1_000.0); - let duration_since_min_interval = - if duration_since_last_ms > group.occurrence_rate.min { - duration_since_last_ms - group.occurrence_rate.min - } else { - return None; - }; - let duration_until_sound_needed = - group.occurrence_rate.max - duration_since_last_ms; - Some(Timing { - duration_since_min_interval, - duration_until_sound_needed, - }) + // Find the duration since the last time a sound was spawned using a source from + // this group. + let timing = if let Some(&last_used) = groups_last_used.get(group_id) { + let duration_since_last: time::Duration = tick.instant.duration_since(last_used); + let duration_since_last_ms = Ms(duration_to_secs(&duration_since_last) * 1_000.0); + let duration_since_min_interval = if duration_since_last_ms > group.occurrence_rate.min + { + duration_since_last_ms - group.occurrence_rate.min } else { - None + return None; }; + let duration_until_sound_needed = group.occurrence_rate.max - duration_since_last_ms; + Some(Timing { + duration_since_min_interval, + duration_until_sound_needed, + }) + } else { + None + }; - let occurrence_rate_interval = group.occurrence_rate; - let suitability = Suitability { - occurrence_rate_interval, - num_sounds_needed, - num_available_sounds, - timing, - }; + let occurrence_rate_interval = group.occurrence_rate; + let suitability = Suitability { + occurrence_rate_interval, + num_sounds_needed, + num_available_sounds, + timing, + }; - Some(AvailableGroup { - id: *group_id, - suitability, - }) - }); + Some(AvailableGroup { + id: *group_id, + suitability, + }) + }); available_groups.extend(extension); } @@ -1238,7 +1235,10 @@ fn update_available_sources( } // We only want sources if they are a part of an available group. - if available_groups.iter().all(|g| !source.groups.contains(&g.id)) { + if available_groups + .iter() + .all(|g| !source.groups.contains(&g.id)) + { return None; } @@ -1266,16 +1266,14 @@ fn update_available_sources( // from this group. let timing = if let Some(&last_use) = sources_last_used.get(source_id) { let duration_since_last = tick.instant.duration_since(last_use); - let duration_since_last_ms = - Ms(duration_to_secs(&duration_since_last) * 1_000.0); - let duration_since_min_interval = - if duration_since_last_ms > source.occurrence_rate.min { - duration_since_last_ms - source.occurrence_rate.min - } else { - return None; - }; - let duration_until_sound_needed = - source.occurrence_rate.max - duration_since_last_ms; + let duration_since_last_ms = Ms(duration_to_secs(&duration_since_last) * 1_000.0); + let duration_since_min_interval = if duration_since_last_ms > source.occurrence_rate.min + { + duration_since_last_ms - source.occurrence_rate.min + } else { + return None; + }; + let duration_until_sound_needed = source.occurrence_rate.max - duration_since_last_ms; Some(Timing { duration_since_min_interval, duration_until_sound_needed, @@ -1303,7 +1301,6 @@ fn update_available_sources( available_sources.extend(extension); } - // Order the two sets or properties by their suitability for use as the next sound. fn suitability(a: &Suitability, b: &Suitability) -> cmp::Ordering { match b.num_sounds_needed.cmp(&a.num_sounds_needed) { @@ -1311,7 +1308,8 @@ fn suitability(a: &Suitability, b: &Suitability) -> cmp::Ordering { (&None, &Some(_)) => cmp::Ordering::Less, (&Some(_), &None) => cmp::Ordering::Greater, (&None, &None) => cmp::Ordering::Equal, - (&Some(ref a), &Some(ref b)) => a.duration_until_sound_needed + (&Some(ref a), &Some(ref b)) => a + .duration_until_sound_needed .partial_cmp(&b.duration_until_sound_needed) .expect("could not compare `duration_until_sound_needed`"), }, @@ -1390,12 +1388,12 @@ fn tick(model: &mut Model, tick: Tick) { &active_sound_positions, ); agent.update(&mut rng, &tick.since_last_tick, &installation_data); - }, + } movement::Generative::Ngon(ref mut ngon) => { if let Some(area) = initial_installation_area { ngon.update(&tick.since_last_tick, &area.bounding_rect); } - }, + } }, } @@ -1429,7 +1427,8 @@ fn tick(model: &mut Model, tick: Tick) { // Determine how many sounds to add (if any) by finding the difference between the target // number and actual number. - 'installations: for (installation, &num_target_sounds) in target_sounds_per_installation.iter() { + 'installations: for (installation, &num_target_sounds) in target_sounds_per_installation.iter() + { let num_active_sounds = match active_sounds_per_installation.get(installation) { None => 0, Some(sounds) => sounds.len(), @@ -1504,7 +1503,7 @@ fn tick(model: &mut Model, tick: Tick) { let num_equal = utils::count_equal(&*available_groups, |a, b| { suitability(&a.suitability, &b.suitability) }); - nannou::rand::thread_rng().gen_range(0, num_equal) + nannou::rand::thread_rng().gen_range(0..num_equal) }; // Retrieve one of the most suitable sources. @@ -1512,7 +1511,7 @@ fn tick(model: &mut Model, tick: Tick) { let num_equal = utils::count_equal(&*available_sources, |a, b| { suitability(&a.suitability, &b.suitability) }); - nannou::rand::thread_rng().gen_range(0, num_equal) + nannou::rand::thread_rng().gen_range(0..num_equal) }; // Pick one of the most suitable sources. @@ -1530,13 +1529,13 @@ fn tick(model: &mut Model, tick: Tick) { let x_mag: f64 = rng.gen(); let x = match left { true => { - Metres(x_mag) + (x_mag) as Metres * (installation_area.centroid.x - installation_area.bounding_rect.left) + installation_area.centroid.x } false => { - Metres(x_mag) + (x_mag) as Metres * (installation_area.centroid.x - installation_area.bounding_rect.right) + installation_area.centroid.x @@ -1546,19 +1545,19 @@ fn tick(model: &mut Model, tick: Tick) { let y_mag: f64 = rng.gen(); let y = match down { true => { - Metres(y_mag) + (y_mag) * (installation_area.centroid.y - installation_area.bounding_rect.bottom) + installation_area.centroid.y } false => { - Metres(y_mag) + (y_mag) as Metres * (installation_area.centroid.y - installation_area.bounding_rect.top) + installation_area.centroid.y } }; - let point = Point2 { x, y }; + let point = Point2::new(x, y); let radians = rng.gen::() * 2.0 * ::std::f32::consts::PI; audio::sound::Position { point, radians } }; diff --git a/src/lib/soundscape/movement/agent.rs b/src/lib/soundscape/movement/agent.rs index 253c22d..84f59e7 100644 --- a/src/lib/soundscape/movement/agent.rs +++ b/src/lib/soundscape/movement/agent.rs @@ -1,18 +1,18 @@ -use audio; +use crate::audio; +use crate::installation; +use crate::metres::Metres; +use crate::utils::{self, duration_to_secs}; use fxhash::FxHashMap; -use installation; -use metres::Metres; -use nannou::prelude::*; +use nannou::glam; use nannou::rand::Rng; use std::{cmp, time}; -use utils::{self, duration_to_secs, pt2, vt2}; // The minimum distance that the point may be from the target before it may switch to the next. -const TARGET_DISTANCE_THRESHOLD: Metres = Metres(1.0); +const TARGET_DISTANCE_THRESHOLD: Metres = 1.0; // The point and vector types in exhibition space. -type Point = Point2; -type Vector = Vector2; +type Point = glam::DVec2; +type Vector = glam::DVec2; /// An automous-agent style movement kind. /// @@ -78,12 +78,12 @@ impl Agent { // Generate these based on "weight" or whatever user params are decided upon. let start_magnitude = rng.gen::() * max_speed; let desired_velocity = desired_velocity(location, target_location); - let desired_radians = desired_velocity.y.0.atan2(desired_velocity.x.0); + let desired_radians = desired_velocity.y.atan2(desired_velocity.x); // Generate initial angle and create velocity from this. let initial_radians = desired_radians + rng.gen::() * 2.0 - 1.0; let velocity = { let (vx, vy) = utils::rad_mag_to_x_y(initial_radians, start_magnitude); - [Metres(vx), Metres(vy)].into() + [vx, vy].into() }; let agent = Agent { location, @@ -102,7 +102,7 @@ impl Agent { pub fn position(&self) -> audio::sound::Position { let point = self.location; let radians = if self.directional { - let vel = vt2::to_f64(self.velocity); + let vel = self.velocity; vel.y.atan2(vel.x) as f32 } else { 0.0 @@ -128,30 +128,33 @@ impl Agent { use std::f64::consts::PI; let delta_secs = duration_to_secs(delta_time); - let mut new_velocity = vt2::to_f64(self.velocity) + vt2::to_f64(force); + let mut new_velocity = self.velocity + force; - fn is_counter_clockwise(b: Vector2, c: Vector2) -> bool { - (b.x * c.y - b.y * c.x) > 0.0 + fn is_counter_clockwise(b: Vector, c: Vector) -> bool { + (b.x * c.y - b.y * c.x) > 0.0 } // Limit `new_velocity` by max_rotation TODO: There must be a way to simplify this. - let new_magnitude = new_velocity.magnitude(); - let radians_start = self.velocity.y.0.atan2(self.velocity.x.0); + let new_magnitude = new_velocity.length(); + let radians_start = self.velocity.y.atan2(self.velocity.x); let radians_end = new_velocity.y.atan2(new_velocity.x); let delta_radians = radians_end - radians_start; - let abs_delta_radians = delta_radians.abs().min(utils::fmod(-delta_radians.abs(), 2.0 * PI)); + let abs_delta_radians = delta_radians + .abs() + .min(utils::fmod(-delta_radians.abs(), 2.0 * PI)); let max_delta_radians = delta_secs * self.max_rotation; if max_delta_radians < abs_delta_radians { let abs_delta_radians_limited = abs_delta_radians.min(max_delta_radians); - let is_left = is_counter_clockwise(vt2::to_f64(self.velocity), new_velocity); - let delta_radians_limited = abs_delta_radians_limited * if is_left { 1.0 } else { -1.0 }; + let is_left = is_counter_clockwise(self.velocity, new_velocity); + let delta_radians_limited = + abs_delta_radians_limited * if is_left { 1.0 } else { -1.0 }; let radians_end_limited = radians_start + delta_radians_limited; let (new_vx, new_vy) = utils::rad_mag_to_x_y(radians_end_limited, new_magnitude); - new_velocity = vec2(new_vx, new_vy); + new_velocity = Vector::new(new_vx, new_vy); } - self.velocity = vt2::to_metres(new_velocity); - self.location = pt2::to_metres(pt2::to_f64(self.location) + new_velocity * delta_secs); + self.velocity = new_velocity; + self.location = (self.location) + new_velocity * delta_secs; } /// Update the agent for the given past amount of time. @@ -220,9 +223,9 @@ fn closest_installation( let mut iter = installations.iter(); iter.next() .map(|first| { - let first_dist = Metres(pt2::to_f64(p).distance2(pt2::to_f64(first.1.area.centroid))); + let first_dist: Metres = (p).distance(first.1.area.centroid); iter.fold((first.0, first_dist), |(closest, dist), inst| { - let inst_dist = Metres(pt2::to_f64(p).distance2(pt2::to_f64(inst.1.area.centroid))); + let inst_dist: Metres = (p).distance(inst.1.area.centroid); if inst_dist < dist { (inst.0, inst_dist) } else { @@ -283,19 +286,19 @@ where let y_len = installation_area.bounding_rect.top - installation_area.bounding_rect.bottom; let x = installation_area.bounding_rect.left + x_len * rng.gen::(); let y = installation_area.bounding_rect.bottom + y_len * rng.gen::(); - Point2 { x, y } + Point::new(x, y) } /// Whether or not the current point has reached the target. fn reached_target(current: Point, target: Point) -> bool { - let distance = Metres(pt2::to_f64(current).distance(pt2::to_f64(target))); + let distance: Metres = (current).distance(target); distance <= TARGET_DISTANCE_THRESHOLD } /// The desired velocity is the velocity that would take the agent from its `current` position /// directly to the `target` position. fn desired_velocity(current: Point, target: Point) -> Vector { - vt2::to_metres(pt2::to_f64(target) - pt2::to_f64(current)) + (target) - (current) } /// The steering vector is the target velocity minus the current velocity. @@ -307,19 +310,18 @@ fn desired_velocity(current: Point, target: Point) -> Vector { /// The resulting vector is a force that may be applied to the current velocity to steer it /// directly towards the target location. fn steering_force(current_velocity: Vector, target_velocity: Vector) -> Vector { - vt2::to_metres(vt2::to_f64(target_velocity) - vt2::to_f64(current_velocity)) + (target_velocity) - (current_velocity) } /// Limit the magnitude of the given vector. fn limit_magnitude(v: Vector, limit: f64) -> Vector { - let vf = vt2::to_f64(v); - let magnitude = vf.magnitude(); - let f = if magnitude > limit { + let vf = v; + let magnitude = vf.length(); + if magnitude > limit { vf.normalize() * limit } else { vf - }; - vt2::to_metres(f) + } } /// Produces a force that steers an agent toward its desired target. @@ -331,9 +333,9 @@ fn seek_force( max_force: f64, ) -> Vector { let desired_velocity = desired_velocity(current_position, target_position); - let desired_normalised = vt2::to_f64(desired_velocity).normalize(); + let desired_normalised = (desired_velocity).normalize(); let desired = desired_normalised * max_speed; - let steering_force = steering_force(current_velocity, vt2::to_metres(desired)); + let steering_force = steering_force(current_velocity, desired); let steering_limited = limit_magnitude(steering_force, max_force); steering_limited } diff --git a/src/lib/soundscape/movement/mod.rs b/src/lib/soundscape/movement/mod.rs index cd80395..823cd97 100644 --- a/src/lib/soundscape/movement/mod.rs +++ b/src/lib/soundscape/movement/mod.rs @@ -1,6 +1,5 @@ -use audio; -use metres::Metres; -use nannou::prelude::*; +use crate::audio; +use crate::metres::Metres; pub use self::agent::Agent; pub use self::ngon::Ngon; @@ -8,6 +7,8 @@ pub use self::ngon::Ngon; pub mod agent; pub mod ngon; +type Point2 = nannou::glam::DVec2; + /// Whether the sound has fixed movement or generative movement. #[derive(Debug)] pub enum Movement { @@ -39,7 +40,7 @@ pub struct BoundingRect { #[derive(Copy, Clone, Debug)] pub struct Area { pub bounding_rect: BoundingRect, - pub centroid: Point2, + pub centroid: Point2, } impl Generative { @@ -64,7 +65,7 @@ impl Movement { impl BoundingRect { /// Initialise a bounding box at a single point in space. - pub fn from_point(p: Point2) -> Self { + pub fn from_point(p: Point2) -> Self { BoundingRect { left: p.x, right: p.x, @@ -76,7 +77,7 @@ impl BoundingRect { /// Determine the movement area bounds on the given set of points. pub fn from_points(points: I) -> Option where - I: IntoIterator>, + I: IntoIterator, { let mut points = points.into_iter(); points.next().map(|p| { @@ -86,7 +87,7 @@ impl BoundingRect { } /// Extend the bounding box to include the given point. - pub fn with_point(self, p: Point2) -> Self { + pub fn with_point(self, p: Point2) -> Self { BoundingRect { left: p.x.min(self.left), right: p.x.max(self.right), @@ -96,12 +97,12 @@ impl BoundingRect { } /// The middle of the bounding box. - pub fn middle(&self) -> Point2 { + pub fn middle(&self) -> Point2 { let width = self.width(); let height = self.height(); let x = self.left + width * 0.5; let y = self.bottom + height * 0.5; - Point2 { x, y } + Point2::new(x, y) } pub fn width(&self) -> Metres { diff --git a/src/lib/soundscape/movement/ngon.rs b/src/lib/soundscape/movement/ngon.rs index 096a48a..431c871 100644 --- a/src/lib/soundscape/movement/ngon.rs +++ b/src/lib/soundscape/movement/ngon.rs @@ -1,13 +1,13 @@ -use audio; -use metres::Metres; +use super::BoundingRect; +use crate::audio; +use crate::utils::duration_to_secs; +use nannou::glam::DVec2 as Vector2; use nannou::prelude::*; use std::time; -use super::BoundingRect; -use utils::{duration_to_secs, pt2}; // The point and vector types in exhibition space. -type Point = Point2; -type Vector = Vector2; +type Point = Vector2; +type Vector = Vector2; /// A 2D N-sided, symmetrical polygon path tracing movement implementation. /// @@ -24,7 +24,7 @@ pub struct Ngon { /// /// `0.0` means all points will be in the center. /// `1.0` means all points will extend to the bounds of the installation area. - pub normalised_dimensions: Vector2, + pub normalised_dimensions: Vector2, /// Some rotation that is applied to the Ngon's points around the centre. pub radians_offset: f64, /// The rate at which the path is being travelled in metres per second. @@ -64,25 +64,25 @@ impl Ngon { pub fn new( vertices: usize, nth: usize, - normalised_dimensions: Vector2, + normalised_dimensions: Vector2, radians_offset: f64, speed: f64, installation_bounding_rect: &BoundingRect, - ) -> Self - { + ) -> Self { let start = 0; let end = (start + nth) % vertices; let line = Line { start, end }; let lerp = 0.0; let position = Position { line, lerp }; let radians = 0.0; - let (middle, half_dim) = middle_and_half_dimensions( - installation_bounding_rect, - normalised_dimensions, - ); + let (middle, half_dim) = + middle_and_half_dimensions(installation_bounding_rect, normalised_dimensions); let point = vertex_at_index(vertices, middle, half_dim, radians_offset, 0); let sound_position = audio::sound::Position { point, radians }; - let state = State { sound_position, position }; + let state = State { + sound_position, + position, + }; Ngon { vertices, nth, @@ -101,28 +101,26 @@ fn vertex_at_index( half_dimensions: Vector, radians_offset: f64, index: usize, -) -> Point -{ +) -> Point { let step = index as f64 / vertices as f64; let radians = step * 2.0 * PI_F64 + radians_offset; let x = middle.x + half_dimensions.x * radians.cos(); let y = middle.y + half_dimensions.y * radians.sin(); - Point2 { x, y } + Point::new(x, y) } // The middle of the given bounding rect and normalised dimensions halved read for use within the // `vertex_at_index` function. fn middle_and_half_dimensions( bounding_rect: &BoundingRect, - normalised_dimensions: Vector2, -) -> (Point, Vector) -{ + normalised_dimensions: Vector2, +) -> (Point, Vector) { let middle = bounding_rect.middle(); let width = bounding_rect.width() * normalised_dimensions.x; let height = bounding_rect.height() * normalised_dimensions.y; let half_width = width * 0.5; let half_height = height * 0.5; - let half_dimensions = Vector2 { x: half_width, y: half_height }; + let half_dimensions = Point::new(half_width, half_height); (middle, half_dimensions) } @@ -141,7 +139,6 @@ impl Ngon { radians_offset, speed, ref mut state, - } = *self; // Find the middle and the half width and height. @@ -149,33 +146,32 @@ impl Ngon { middle_and_half_dimensions(installation_area, normalised_dimensions); // Shorthand for finding a vertex at a specific index. - let vertex_at_index = |index| { - vertex_at_index(vertices, middle, half_dimensions, radians_offset, index) - }; + let vertex_at_index = + |index| vertex_at_index(vertices, middle, half_dimensions, radians_offset, index); // Determine the current position of the Ngon tracer. let mut travel_distance = speed * duration_to_secs(delta_time); let (point, lerp) = loop { - let start = pt2::to_f64(vertex_at_index(state.position.line.start)); - let end = pt2::to_f64(vertex_at_index(state.position.line.end)); - let vec = start.to_vec().lerp(end.to_vec(), state.position.lerp); - let point = pt2(vec.x, vec.y); + let start = vertex_at_index(state.position.line.start); + let end = vertex_at_index(state.position.line.end); + let vec = start.lerp(end, state.position.lerp); + let point = Point::new(vec.x, vec.y); let distance = point.distance(end).abs(); // If there's no distance to travel, make sure the point is up to date with the // installation bounds and return. if travel_distance == 0.0 || distance == 0.0 { - state.sound_position.point = pt2::to_metres(point); + state.sound_position.point = point; return; } if travel_distance < distance { let start_to_end = end - start; - let start_to_end_distance = start_to_end.magnitude(); + let start_to_end_distance = start_to_end.length(); let travel = if start_to_end_distance > 0.0 { start_to_end.normalize() * travel_distance } else { - vec2(0.0, 0.0) + Vector::new(0.0, 0.0) }; let new_point = point + travel; let new_distance = new_point.distance(end).abs(); @@ -184,7 +180,7 @@ impl Ngon { } else { 0.0 }; - let new_point = pt2::to_metres(new_point); + let new_point = new_point; break (new_point, new_lerp); } travel_distance -= distance; diff --git a/src/lib/utils.rs b/src/lib/utils.rs index fcb98df..cafbb5e 100644 --- a/src/lib/utils.rs +++ b/src/lib/utils.rs @@ -1,12 +1,12 @@ use nannou::math::map_range; use nannou::math::num_traits::{Float, NumCast}; -use serde; +use serde::{self, Deserialize, Serialize}; use serde_json; -use std::{cmp, fmt, fs, io}; use std::error::Error; use std::io::Write; use std::path::Path; use std::time; +use std::{cmp, fmt, fs, io}; use time_calc::Ms; pub const SEC_MS: f64 = 1_000.0; @@ -340,63 +340,3 @@ where let rquot: F = (numer / denom).floor(); numer - rquot * denom } - -pub mod pt2 { - use metres::Metres; - use nannou::geom::Point2; - - /// Maps the given point to some new type over the dimensions. - pub fn convert(p: Point2) -> Point2 - where - T: Into, - { - let Point2 { x, y } = p; - let x = x.into(); - let y = y.into(); - Point2 { x, y } - } - - pub fn to_f64(p: Point2) -> Point2 - where - T: Into, - { - convert(p) - } - - pub fn to_metres(p: Point2) -> Point2 - where - T: Into, - { - convert(p) - } -} - -pub mod vt2 { - use metres::Metres; - use nannou::geom::Vector2; - - /// Maps the given vector to some new type over the dimensions. - pub fn convert(p: Vector2) -> Vector2 - where - T: Into, - { - let Vector2 { x, y } = p; - let x = x.into(); - let y = y.into(); - Vector2 { x, y } - } - - pub fn to_f64(v: Vector2) -> Vector2 - where - T: Into, - { - convert(v) - } - - pub fn to_metres(v: Vector2) -> Vector2 - where - T: Into, - { - convert(v) - } -} From a9332c0454db554b53721a17a227d38417302961 Mon Sep 17 00:00:00 2001 From: "Ando \"Thor\" Nando" Date: Tue, 14 Jun 2022 13:32:38 +1000 Subject: [PATCH 2/8] chore: cargo diet --- Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/Cargo.toml b/Cargo.toml index edcad87..750af17 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,6 +4,7 @@ version = "0.1.0" authors = ["mitchmindtree "] resolver = "2" edition = "2021" +include = ["src/**/*", "README.md"] [profile.release] debug = true From 106af21c000451c974e92419fa6617e2736217bb Mon Sep 17 00:00:00 2001 From: "Ando \"Thor\" Nando" Date: Tue, 14 Jun 2022 13:34:09 +1000 Subject: [PATCH 3/8] chore: cargo fix --- src/lib/audio/detection.rs | 2 +- src/lib/soundscape/mod.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/lib/audio/detection.rs b/src/lib/audio/detection.rs index 5b345c1..83d4ad6 100644 --- a/src/lib/audio/detection.rs +++ b/src/lib/audio/detection.rs @@ -263,7 +263,7 @@ impl Model { let in_window = [Complex::::zero(); FFT_WINDOW_LEN]; let out_window = [Complex::::zero(); FFT_WINDOW_LEN]; let fft = Fft::new(in_window, out_window); - let inverse = false; + let _inverse = false; let fft_planner = fft::Planner::new(); let fft_direction = rustfft::FftDirection::Inverse; diff --git a/src/lib/soundscape/mod.rs b/src/lib/soundscape/mod.rs index d80a18c..ce0d466 100644 --- a/src/lib/soundscape/mod.rs +++ b/src/lib/soundscape/mod.rs @@ -672,7 +672,7 @@ pub fn spawn( frame_count: Arc, seed: Seed, tx: mpsc::Sender, - rx: mpsc::Receiver, + _rx: mpsc::Receiver, wav_reader: audio::source::wav::reader::Handle, audio_input_stream: audio::input::Stream, audio_output_stream: audio::output::Stream, @@ -726,7 +726,7 @@ pub fn spawn( let active_sounds_per_installation = Default::default(); let available_groups = Default::default(); let available_sources = Default::default(); - let model = Model { + let _model = Model { frame_count, realtime_source_latency, seed, From ad54f4c9821580c3ea85325fbd936c7fef3742d6 Mon Sep 17 00:00:00 2001 From: "Ando \"Thor\" Nando" Date: Tue, 14 Jun 2022 14:21:23 +1000 Subject: [PATCH 4/8] fix: clean up some panics --- src/lib/audio/source/wav/reader.rs | 29 +++++++++++++++-------------- src/lib/gui/monitor.rs | 5 +++-- src/lib/osc/output.rs | 7 ++++--- 3 files changed, 22 insertions(+), 19 deletions(-) diff --git a/src/lib/audio/source/wav/reader.rs b/src/lib/audio/source/wav/reader.rs index 2381bfa..4ffd80e 100644 --- a/src/lib/audio/source/wav/reader.rs +++ b/src/lib/audio/source/wav/reader.rs @@ -612,21 +612,22 @@ fn run(tx: Tx, rx: Rx) { /// the parent thread in their processed form. fn run_child(child_msg_queue: Arc, parent_tx: Tx) { loop { - let msg = child_msg_queue.pop().unwrap(); // TODO (ando: 2022-06-09): check if unwrap logic is correct - match msg { - // Play the given sound and return the resulting `Sound` to the parent. - ChildMessage::Play(sound_id, play) => { - let sound = play_sound(play); - let msg = Message::PlayComplete(sound_id, sound); - parent_tx.push(msg); - } + if let Some(msg) = child_msg_queue.pop() { + match msg { + // Play the given sound and return the resulting `Sound` to the parent. + ChildMessage::Play(sound_id, play) => { + let sound = play_sound(play); + let msg = Message::PlayComplete(sound_id, sound); + parent_tx.push(msg); + } - // Process the next buffer and return the resulting `Sound` to the parent thread. - ChildMessage::NextBuffer(sound_id, mut sound, buffer) => { - next_buffer(sound_id, &mut sound, buffer, &parent_tx) - .expect("failed to process next buffer"); - let msg = Message::NextBufferComplete(sound_id, sound); - parent_tx.push(msg); + // Process the next buffer and return the resulting `Sound` to the parent thread. + ChildMessage::NextBuffer(sound_id, mut sound, buffer) => { + next_buffer(sound_id, &mut sound, buffer, &parent_tx) + .expect("failed to process next buffer"); + let msg = Message::NextBufferComplete(sound_id, sound); + parent_tx.push(msg); + } } } } diff --git a/src/lib/gui/monitor.rs b/src/lib/gui/monitor.rs index 6033049..a5f5dea 100644 --- a/src/lib/gui/monitor.rs +++ b/src/lib/gui/monitor.rs @@ -59,8 +59,9 @@ pub fn spawn(app_proxy: nannou::app::Proxy) -> io::Result { // waking up. // Attempt to forward every message and wakeup the GUI when successful. 'run: while !is_closed_2.load(atomic::Ordering::Relaxed) { - let msg = audio_rx.pop().unwrap(); - gui_tx.push(msg); + if let Some(msg) = audio_rx.pop() { + gui_tx.push(msg); + } // Proxy is currently buggy on linux so we only enable this for macos. if cfg!(target_os = "macos") { if app_proxy.wakeup().is_err() { diff --git a/src/lib/osc/output.rs b/src/lib/osc/output.rs index a65e23b..6e4a878 100644 --- a/src/lib/osc/output.rs +++ b/src/lib/osc/output.rs @@ -125,9 +125,10 @@ fn run(msg_rx: Rx, log_tx: mpsc::Sender) { std::thread::Builder::new() .name("osc_output_msg_to_update".into()) .spawn(move || loop { - let msg = msg_rx.pop().unwrap(); - if update_tx.send(Update::Msg(msg)).is_err() { - break; + if let Some(msg) = msg_rx.pop() { + if update_tx.send(Update::Msg(msg)).is_err() { + break; + } } }) .unwrap(); From 468850b0b2f651d0e4a4fc33957949d1b93d15ff Mon Sep 17 00:00:00 2001 From: "Ando \"Thor\" Nando" Date: Wed, 15 Jun 2022 14:24:25 +1000 Subject: [PATCH 5/8] chore: update gitignore, add Cargo.lock --- .gitignore | 6 - Cargo.lock | 3672 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 3672 insertions(+), 6 deletions(-) create mode 100644 Cargo.lock diff --git a/.gitignore b/.gitignore index 65240ca..c2c92b0 100644 --- a/.gitignore +++ b/.gitignore @@ -3,12 +3,6 @@ /target/ /builds/ -# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries -# More information here http://doc.crates.io/guide.html#cargotoml-vs-cargolock -Cargo.lock - # These are backup files generated by rustfmt **/*.rs.bk /target/ -**/*.rs.bk -Cargo.lock diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..e25d855 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,3672 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "ab_glyph_rasterizer" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a13739d7177fbd22bb0ed28badfff9f372f8bef46c863db4e1c6248f6b223b6e" + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "adler32" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234" + +[[package]] +name = "ahash" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" +dependencies = [ + "getrandom 0.2.6", + "once_cell", + "version_check", +] + +[[package]] +name = "aho-corasick" +version = "0.7.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" +dependencies = [ + "memchr", +] + +[[package]] +name = "alsa" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5915f52fe2cf65e83924d037b6c5290b7cee097c6b5c8700746e6168a343fd6b" +dependencies = [ + "alsa-sys", + "bitflags", + "libc", + "nix 0.23.1", +] + +[[package]] +name = "alsa-sys" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db8fee663d06c4e303404ef5f40488a53e062f89ba8bfed81f42325aafad1527" +dependencies = [ + "libc", + "pkg-config", +] + +[[package]] +name = "andrew" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b7f09f89872c2b6b29e319377b1fbe91c6f5947df19a25596e121cf19a7b35e" +dependencies = [ + "bitflags", + "line_drawing", + "rusttype 0.7.9", + "walkdir", + "xdg", + "xml-rs", +] + +[[package]] +name = "andrew" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c4afb09dd642feec8408e33f92f3ffc4052946f6b20f32fb99c1f58cd4fa7cf" +dependencies = [ + "bitflags", + "rusttype 0.9.2", + "walkdir", + "xdg", + "xml-rs", +] + +[[package]] +name = "ansi_term" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" +dependencies = [ + "winapi", +] + +[[package]] +name = "approx" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0e60b75072ecd4168020818c0107f2857bb6c4e64252d8d3983f6263b40a5c3" +dependencies = [ + "num-traits", +] + +[[package]] +name = "arrayvec" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" + +[[package]] +name = "arrayvec" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" + +[[package]] +name = "ash" +version = "0.33.3+1.2.191" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc4f1d82f164f838ae413296d1131aa6fa79b917d25bebaa7033d25620c09219" +dependencies = [ + "libloading 0.7.3", +] + +[[package]] +name = "asio-sys" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47629cb63178cf13daf45db2d7256cc3fcd986d05b9070d4d1a758a2b4141bd5" +dependencies = [ + "bindgen 0.54.0", + "cc", + "lazy_static", + "num-derive", + "num-traits", + "walkdir", +] + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + +[[package]] +name = "audio_server" +version = "0.1.0" +dependencies = [ + "conrod_core", + "conrod_derive", + "crossbeam", + "custom_derive", + "dasp", + "fxhash", + "hound", + "mindtree_utils", + "nannou", + "nannou_audio", + "nannou_conrod", + "nannou_osc", + "newtype_derive", + "num_cpus", + "pitch_calc", + "rand_xorshift 0.3.0", + "rustfft", + "serde", + "serde_derive", + "serde_json", + "slug", + "threadpool", + "time_calc", + "walkdir", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "bindgen" +version = "0.53.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c72a978d268b1d70b0e963217e60fdabd9523a941457a6c42a7315d15c7e89e5" +dependencies = [ + "bitflags", + "cexpr", + "cfg-if 0.1.10", + "clang-sys", + "lazy_static", + "lazycell", + "peeking_take_while", + "proc-macro2 1.0.39", + "quote 1.0.18", + "regex", + "rustc-hash", + "shlex", +] + +[[package]] +name = "bindgen" +version = "0.54.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66c0bb6167449588ff70803f4127f0684f9063097eca5016f37eb52b92c2cf36" +dependencies = [ + "bitflags", + "cexpr", + "cfg-if 0.1.10", + "clang-sys", + "clap", + "env_logger", + "lazy_static", + "lazycell", + "log", + "peeking_take_while", + "proc-macro2 1.0.39", + "quote 1.0.18", + "regex", + "rustc-hash", + "shlex", + "which", +] + +[[package]] +name = "bit-set" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e11e16035ea35e4e5997b393eacbf6f63983188f7a2ad25bfb13465f5ad59de" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "block" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" + +[[package]] +name = "bumpalo" +version = "3.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37ccbd214614c6783386c1af30caf03192f17891059cecc394b4fb119e363de3" + +[[package]] +name = "bytemuck" +version = "1.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdead85bdec19c194affaeeb670c0e41fe23de31459efd1c174d049269cf02cc" + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "bytes" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" + +[[package]] +name = "calloop" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b036167e76041694579972c28cf4877b4f92da222560ddb49008937b6a6727c" +dependencies = [ + "log", + "nix 0.18.0", +] + +[[package]] +name = "cc" +version = "1.0.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" +dependencies = [ + "jobserver", +] + +[[package]] +name = "cesu8" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" + +[[package]] +name = "cexpr" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4aedb84272dbe89af497cf81375129abda4fc0a9e7c5d317498c15cc30c0d27" +dependencies = [ + "nom 5.1.2", +] + +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cfg_aliases" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" + +[[package]] +name = "clang-sys" +version = "0.29.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe6837df1d5cba2397b835c8530f51723267e16abbf83892e9e5af4f0e5dd10a" +dependencies = [ + "glob", + "libc", + "libloading 0.5.2", +] + +[[package]] +name = "clap" +version = "2.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" +dependencies = [ + "ansi_term", + "atty", + "bitflags", + "strsim 0.8.0", + "textwrap", + "unicode-width", + "vec_map", +] + +[[package]] +name = "clipboard-win" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3a093d6fed558e5fe24c3dfc85a68bb68f1c824f440d3ba5aca189e2998786b" +dependencies = [ + "winapi", +] + +[[package]] +name = "cocoa" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f63902e9223530efb4e26ccd0cf55ec30d592d3b42e21a28defc42a9586e832" +dependencies = [ + "bitflags", + "block", + "cocoa-foundation", + "core-foundation 0.9.3", + "core-graphics 0.22.3", + "foreign-types", + "libc", + "objc", +] + +[[package]] +name = "cocoa-foundation" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ade49b65d560ca58c403a479bb396592b155c0185eada742ee323d1d68d6318" +dependencies = [ + "bitflags", + "block", + "core-foundation 0.9.3", + "core-graphics-types", + "foreign-types", + "libc", + "objc", +] + +[[package]] +name = "codespan-reporting" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" +dependencies = [ + "termcolor", + "unicode-width", +] + +[[package]] +name = "color_quant" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" + +[[package]] +name = "combine" +version = "4.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a604e93b79d1808327a6fca85a6f2d69de66461e7620f5a4cbf5fb4d1d7c948" +dependencies = [ + "bytes", + "memchr", +] + +[[package]] +name = "conrod_core" +version = "0.76.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "981c1c7c541392abb08100f31a18694d52ec1d633cd5652d544237375d5184ca" +dependencies = [ + "conrod_derive", + "copypasta", + "daggy", + "fnv", + "instant", + "num 0.3.1", + "pistoncore-input", + "rusttype 0.8.3", +] + +[[package]] +name = "conrod_derive" +version = "0.76.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eda5e9d04f37818a74dcd4789b6de3f35c11b752509175352bc4ca19af07e511" +dependencies = [ + "proc-macro2 1.0.39", + "quote 1.0.18", + "syn", +] + +[[package]] +name = "conrod_wgpu" +version = "0.76.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc4e9a68a813d611e771e713de4128a0e3b8725c46e3ebc540999d2d690fe747" +dependencies = [ + "conrod_core", + "wgpu", +] + +[[package]] +name = "conrod_winit" +version = "0.76.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4cbc630c9a424524653ba7ba6c9f896213dd8a6ef0940cbd2dabdaf02d6f0d0" + +[[package]] +name = "copyless" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2df960f5d869b2dd8532793fde43eb5427cceb126c929747a26823ab0eeb536" + +[[package]] +name = "copypasta" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "865e9675691e2a7dfc806b16ef2dd5dd536e26ea9b8046519767d79be03aeb6a" +dependencies = [ + "clipboard-win", + "objc", + "objc-foundation", + "objc_id", + "smithay-clipboard", + "wayland-client 0.23.6", + "x11-clipboard", +] + +[[package]] +name = "core-foundation" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57d24c7a13c43e870e37c1556b74555437870a04514f7685f5b354e090567171" +dependencies = [ + "core-foundation-sys 0.7.0", + "libc", +] + +[[package]] +name = "core-foundation" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" +dependencies = [ + "core-foundation-sys 0.8.3", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3a71ab494c0b5b860bdc8407ae08978052417070c2ced38573a9157ad75b8ac" + +[[package]] +name = "core-foundation-sys" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" + +[[package]] +name = "core-graphics" +version = "0.19.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3889374e6ea6ab25dba90bb5d96202f61108058361f6dc72e8b03e6f8bbe923" +dependencies = [ + "bitflags", + "core-foundation 0.7.0", + "foreign-types", + "libc", +] + +[[package]] +name = "core-graphics" +version = "0.22.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2581bbab3b8ffc6fcbd550bf46c355135d16e9ff2a6ea032ad6b9bf1d7efe4fb" +dependencies = [ + "bitflags", + "core-foundation 0.9.3", + "core-graphics-types", + "foreign-types", + "libc", +] + +[[package]] +name = "core-graphics-types" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a68b68b3446082644c91ac778bf50cd4104bfb002b5a6a7c44cca5a2c70788b" +dependencies = [ + "bitflags", + "core-foundation 0.9.3", + "foreign-types", + "libc", +] + +[[package]] +name = "core-video-sys" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34ecad23610ad9757664d644e369246edde1803fcb43ed72876565098a5d3828" +dependencies = [ + "cfg-if 0.1.10", + "core-foundation-sys 0.7.0", + "core-graphics 0.19.2", + "libc", + "objc", +] + +[[package]] +name = "coreaudio-rs" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11894b20ebfe1ff903cbdc52259693389eea03b94918a2def2c30c3bf227ad88" +dependencies = [ + "bitflags", + "coreaudio-sys", +] + +[[package]] +name = "coreaudio-sys" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17f73df0f29f4c3c374854f076c47dc018f19acaa63538880dba0937ad4fa8d7" +dependencies = [ + "bindgen 0.53.3", +] + +[[package]] +name = "cpal" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74117836a5124f3629e4b474eed03e479abaf98988b4bb317e29f08cfe0e4116" +dependencies = [ + "alsa", + "asio-sys", + "core-foundation-sys 0.8.3", + "coreaudio-rs", + "jni", + "js-sys", + "lazy_static", + "libc", + "mach", + "ndk 0.6.0", + "ndk-glue 0.6.2", + "nix 0.23.1", + "num-traits", + "oboe", + "parking_lot", + "stdweb", + "thiserror", + "web-sys", + "winapi", +] + +[[package]] +name = "crc32fast" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +dependencies = [ + "cfg-if 1.0.0", +] + +[[package]] +name = "crossbeam" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ae5588f6b3c3cb05239e90bd110f257254aecd01e4635400391aeae07497845" +dependencies = [ + "cfg-if 1.0.0", + "crossbeam-channel", + "crossbeam-deque 0.8.1", + "crossbeam-epoch 0.9.8", + "crossbeam-queue", + "crossbeam-utils 0.8.8", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aaa7bd5fb665c6864b5f963dd9097905c54125909c7aa94c9e18507cdbe6c53" +dependencies = [ + "cfg-if 1.0.0", + "crossbeam-utils 0.8.8", +] + +[[package]] +name = "crossbeam-deque" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c20ff29ded3204c5106278a81a38f4b482636ed4fa1e6cfbeef193291beb29ed" +dependencies = [ + "crossbeam-epoch 0.8.2", + "crossbeam-utils 0.7.2", + "maybe-uninit", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e" +dependencies = [ + "cfg-if 1.0.0", + "crossbeam-epoch 0.9.8", + "crossbeam-utils 0.8.8", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "058ed274caafc1f60c4997b5fc07bf7dc7cca454af7c6e81edffe5f33f70dace" +dependencies = [ + "autocfg", + "cfg-if 0.1.10", + "crossbeam-utils 0.7.2", + "lazy_static", + "maybe-uninit", + "memoffset 0.5.6", + "scopeguard", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1145cf131a2c6ba0615079ab6a638f7e1973ac9c2634fcbeaaad6114246efe8c" +dependencies = [ + "autocfg", + "cfg-if 1.0.0", + "crossbeam-utils 0.8.8", + "lazy_static", + "memoffset 0.6.5", + "scopeguard", +] + +[[package]] +name = "crossbeam-queue" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f25d8400f4a7a5778f0e4e52384a48cbd9b5c495d110786187fc750075277a2" +dependencies = [ + "cfg-if 1.0.0", + "crossbeam-utils 0.8.8", +] + +[[package]] +name = "crossbeam-utils" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" +dependencies = [ + "autocfg", + "cfg-if 0.1.10", + "lazy_static", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38" +dependencies = [ + "cfg-if 1.0.0", + "lazy_static", +] + +[[package]] +name = "cty" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35" + +[[package]] +name = "custom_derive" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef8ae57c4978a2acd8b869ce6b9ca1dfe817bff704c220209fdef2c0b75a01b9" + +[[package]] +name = "d3d12" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2daefd788d1e96e0a9d66dee4b828b883509bc3ea9ce30665f04c3246372690c" +dependencies = [ + "bitflags", + "libloading 0.7.3", + "winapi", +] + +[[package]] +name = "daggy" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9293a0da7d1bc1f30090ece4d9f9de79a07be7302ddb00e5eb1fefb6ee6409e2" +dependencies = [ + "petgraph", +] + +[[package]] +name = "darling" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d706e75d87e35569db781a9b5e2416cff1236a47ed380831f959382ccd5f858" +dependencies = [ + "darling_core 0.10.2", + "darling_macro 0.10.2", +] + +[[package]] +name = "darling" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c" +dependencies = [ + "darling_core 0.13.4", + "darling_macro 0.13.4", +] + +[[package]] +name = "darling_core" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0c960ae2da4de88a91b2d920c2a7233b400bc33cb28453a2987822d8392519b" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2 1.0.39", + "quote 1.0.18", + "strsim 0.9.3", + "syn", +] + +[[package]] +name = "darling_core" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2 1.0.39", + "quote 1.0.18", + "strsim 0.10.0", + "syn", +] + +[[package]] +name = "darling_macro" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b5a2f4ac4969822c62224815d069952656cadc7084fdca9751e6d959189b72" +dependencies = [ + "darling_core 0.10.2", + "quote 1.0.18", + "syn", +] + +[[package]] +name = "darling_macro" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835" +dependencies = [ + "darling_core 0.13.4", + "quote 1.0.18", + "syn", +] + +[[package]] +name = "dasp" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7381b67da416b639690ac77c73b86a7b5e64a29e31d1f75fb3b1102301ef355a" +dependencies = [ + "dasp_envelope", + "dasp_frame", + "dasp_interpolate", + "dasp_peak", + "dasp_ring_buffer", + "dasp_rms", + "dasp_sample", + "dasp_signal", + "dasp_slice", + "dasp_window", +] + +[[package]] +name = "dasp_envelope" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ec617ce7016f101a87fe85ed44180839744265fae73bb4aa43e7ece1b7668b6" +dependencies = [ + "dasp_frame", + "dasp_peak", + "dasp_ring_buffer", + "dasp_rms", + "dasp_sample", +] + +[[package]] +name = "dasp_frame" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2a3937f5fe2135702897535c8d4a5553f8b116f76c1529088797f2eee7c5cd6" +dependencies = [ + "dasp_sample", +] + +[[package]] +name = "dasp_interpolate" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fc975a6563bb7ca7ec0a6c784ead49983a21c24835b0bc96eea11ee407c7486" +dependencies = [ + "dasp_frame", + "dasp_ring_buffer", + "dasp_sample", +] + +[[package]] +name = "dasp_peak" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cf88559d79c21f3d8523d91250c397f9a15b5fc72fbb3f87fdb0a37b79915bf" +dependencies = [ + "dasp_frame", + "dasp_sample", +] + +[[package]] +name = "dasp_ring_buffer" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07d79e19b89618a543c4adec9c5a347fe378a19041699b3278e616e387511ea1" + +[[package]] +name = "dasp_rms" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6c5dcb30b7e5014486e2822537ea2beae50b19722ffe2ed7549ab03774575aa" +dependencies = [ + "dasp_frame", + "dasp_ring_buffer", + "dasp_sample", +] + +[[package]] +name = "dasp_sample" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c87e182de0887fd5361989c677c4e8f5000cd9491d6d563161a8f3a5519fc7f" + +[[package]] +name = "dasp_signal" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa1ab7d01689c6ed4eae3d38fe1cea08cba761573fbd2d592528d55b421077e7" +dependencies = [ + "dasp_envelope", + "dasp_frame", + "dasp_interpolate", + "dasp_peak", + "dasp_ring_buffer", + "dasp_rms", + "dasp_sample", + "dasp_window", +] + +[[package]] +name = "dasp_slice" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e1c7335d58e7baedafa516cb361360ff38d6f4d3f9d9d5ee2a2fc8e27178fa1" +dependencies = [ + "dasp_frame", + "dasp_sample", +] + +[[package]] +name = "dasp_window" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99ded7b88821d2ce4e8b842c9f1c86ac911891ab89443cc1de750cae764c5076" +dependencies = [ + "dasp_sample", +] + +[[package]] +name = "deflate" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73770f8e1fe7d64df17ca66ad28994a0a623ea497fa69486e14984e715c5d174" +dependencies = [ + "adler32", + "byteorder", +] + +[[package]] +name = "deunicode" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "850878694b7933ca4c9569d30a34b55031b9b139ee1fc7b94a527c4ef960d690" + +[[package]] +name = "dirs" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + +[[package]] +name = "dispatch" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" + +[[package]] +name = "dlib" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b11f15d1e3268f140f68d390637d5e76d849782d971ae7063e0da69fe9709a76" +dependencies = [ + "libloading 0.6.7", +] + +[[package]] +name = "dlib" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac1b7517328c04c2aa68422fc60a41b92208182142ed04a25879c26c8f878794" +dependencies = [ + "libloading 0.7.3", +] + +[[package]] +name = "downcast-rs" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" + +[[package]] +name = "either" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" + +[[package]] +name = "env_logger" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" +dependencies = [ + "atty", + "humantime", + "log", + "regex", + "termcolor", +] + +[[package]] +name = "euclid" +version = "0.22.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b52c2ef4a78da0ba68fbe1fd920627411096d2ac478f7f4c9f3a54ba6705bade" +dependencies = [ + "num-traits", +] + +[[package]] +name = "find_folder" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f6d018fb95a0b59f854aed68ecd96ce2b80af7911b92b1fed3c4b1fa516b91b" + +[[package]] +name = "fixedbitset" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86d4de0081402f5e88cdac65c8dcdcc73118c1a7a465e2a05f0da05843a8ea33" + +[[package]] +name = "float_next_after" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fc612c5837986b7104a87a0df74a5460931f1c5274be12f8d0f40aa2f30d632" +dependencies = [ + "num-traits", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "fuchsia-cprng" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" + +[[package]] +name = "futures" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f73fe65f54d1e12b726f517d3e2135ca3125a437b6d998caf1962961f7172d9e" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3083ce4b914124575708913bca19bfe887522d6e2e6d0952943f5eac4a74010" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3" + +[[package]] +name = "futures-executor" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9420b90cfa29e327d0429f19be13e7ddb68fa1cccb09d65e5706b8c7a749b8a6" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", + "num_cpus", +] + +[[package]] +name = "futures-io" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc4045962a5a5e935ee2fdedaa4e08284547402885ab326734432bed5d12966b" + +[[package]] +name = "futures-macro" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33c1e13800337f4d4d7a316bf45a567dbcb6ffe087f16424852d97e97a91f512" +dependencies = [ + "proc-macro2 1.0.39", + "quote 1.0.18", + "syn", +] + +[[package]] +name = "futures-sink" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21163e139fa306126e6eedaf49ecdb4588f939600f0b1e770f4205ee4b7fa868" + +[[package]] +name = "futures-task" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c66a976bf5909d801bbef33416c41372779507e7a6b3a5e25e4749c58f776a" + +[[package]] +name = "futures-util" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8b7abd5d659d9b90c8cba917f6ec750a74e2dc23902ef9cd4cc8c8b22e6036a" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "fxhash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" +dependencies = [ + "byteorder", +] + +[[package]] +name = "getrandom" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "wasi 0.9.0+wasi-snapshot-preview1", +] + +[[package]] +name = "getrandom" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9be70c98951c83b8d2f8f60d7065fa6d5146873094452a1008da8c2f1e4205ad" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "wasi 0.10.2+wasi-snapshot-preview1", +] + +[[package]] +name = "gif" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3a7187e78088aead22ceedeee99779455b23fc231fe13ec443f99bb71694e5b" +dependencies = [ + "color_quant", + "weezl", +] + +[[package]] +name = "glam" +version = "0.17.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e01732b97afd8508eee3333a541b9f7610f454bb818669e66e90f5f57c93a776" +dependencies = [ + "num-traits", + "rand 0.8.5", + "serde", +] + +[[package]] +name = "glob" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" + +[[package]] +name = "glow" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8bd5877156a19b8ac83a29b2306fe20537429d318f3ff0a1a2119f8d9c61919" +dependencies = [ + "js-sys", + "slotmap", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "gpu-alloc" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fc59e5f710e310e76e6707f86c561dd646f69a8876da9131703b2f717de818d" +dependencies = [ + "bitflags", + "gpu-alloc-types", +] + +[[package]] +name = "gpu-alloc-types" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54804d0d6bc9d7f26db4eaec1ad10def69b599315f487d32c334a80d1efe67a5" +dependencies = [ + "bitflags", +] + +[[package]] +name = "gpu-descriptor" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a538f217be4d405ff4719a283ca68323cc2384003eca5baaa87501e821c81dda" +dependencies = [ + "bitflags", + "gpu-descriptor-types", + "hashbrown", +] + +[[package]] +name = "gpu-descriptor-types" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "363e3677e55ad168fef68cf9de3a4a310b53124c5e784c53a1d70e92d23f2126" +dependencies = [ + "bitflags", +] + +[[package]] +name = "hashbrown" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" +dependencies = [ + "ahash", +] + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "hexf-parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df" + +[[package]] +name = "hound" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a164bb2ceaeff4f42542bdb847c41517c78a60f5649671b2a07312b6e117549" + +[[package]] +name = "humantime" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" +dependencies = [ + "quick-error", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "image" +version = "0.23.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24ffcb7e7244a9bf19d35bf2883b9c080c4ced3c07a9895572178cdb8f13f6a1" +dependencies = [ + "bytemuck", + "byteorder", + "color_quant", + "gif", + "jpeg-decoder", + "num-iter", + "num-rational 0.3.2", + "num-traits", + "png", + "scoped_threadpool", + "tiff", +] + +[[package]] +name = "indexmap" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6012d540c5baa3589337a98ce73408de9b5a25ec9fc2c6fd6be8f0d39e0ca5a" +dependencies = [ + "autocfg", + "hashbrown", +] + +[[package]] +name = "inplace_it" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90953f308a79fe6d62a4643e51f848fbfddcd05975a38e69fdf4ab86a7baf7ca" + +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if 1.0.0", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "itoa" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d" + +[[package]] +name = "jni" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6df18c2e3db7e453d3c6ac5b3e9d5182664d28788126d39b91f2d1e22b017ec" +dependencies = [ + "cesu8", + "combine", + "jni-sys", + "log", + "thiserror", + "walkdir", +] + +[[package]] +name = "jni-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" + +[[package]] +name = "jobserver" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af25a77299a7f711a01975c35a6a424eb6862092cc2d6c72c4ed6cbc56dfc1fa" +dependencies = [ + "libc", +] + +[[package]] +name = "jpeg-decoder" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "229d53d58899083193af11e15917b5640cd40b29ff475a1fe4ef725deb02d0f2" +dependencies = [ + "rayon", +] + +[[package]] +name = "js-sys" +version = "0.3.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "671a26f820db17c2a2750743f1dd03bafd15b98c9f30c7c2628c024c05d73397" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "khronos-egl" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c2352bd1d0bceb871cb9d40f24360c8133c11d7486b68b5381c1dd1a32015e3" +dependencies = [ + "libc", + "libloading 0.7.3", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "lazycell" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" + +[[package]] +name = "libc" +version = "0.2.126" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" + +[[package]] +name = "libloading" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2b111a074963af1d37a139918ac6d49ad1d0d5e47f72fd55388619691a7d753" +dependencies = [ + "cc", + "winapi", +] + +[[package]] +name = "libloading" +version = "0.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "351a32417a12d5f7e82c368a66781e307834dae04c6ce0cd4456d52989229883" +dependencies = [ + "cfg-if 1.0.0", + "winapi", +] + +[[package]] +name = "libloading" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efbc0f03f9a775e9f6aed295c6a1ba2253c5757a9e03d55c6caa46a681abcddd" +dependencies = [ + "cfg-if 1.0.0", + "winapi", +] + +[[package]] +name = "line_drawing" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cc7ad3d82c845bdb5dde34ffdcc7a5fb4d2996e1e1ee0f19c33bc80e15196b9" +dependencies = [ + "num-traits", +] + +[[package]] +name = "linked-hash-map" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3" + +[[package]] +name = "lock_api" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +dependencies = [ + "cfg-if 1.0.0", +] + +[[package]] +name = "lyon" +version = "0.17.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf0510ed5e3e2fb80f3db2061ef5ca92d87bfda1a624bb1eacf3bd50226e4cbb" +dependencies = [ + "lyon_algorithms", + "lyon_tessellation", +] + +[[package]] +name = "lyon_algorithms" +version = "0.17.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8037f716541ba0d84d3de05c0069f8068baf73990d55980558b84d944c8a244a" +dependencies = [ + "lyon_path", + "sid", +] + +[[package]] +name = "lyon_geom" +version = "0.17.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71d89ccbdafd83d259403e22061be27bccc3254bba65cdc5303250c4227c8c8e" +dependencies = [ + "arrayvec 0.5.2", + "euclid", + "num-traits", +] + +[[package]] +name = "lyon_path" +version = "0.17.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b0a59fdf767ca0d887aa61d1b48d4bbf6a124c1a45503593f7d38ab945bfbc0" +dependencies = [ + "lyon_geom", +] + +[[package]] +name = "lyon_tessellation" +version = "0.17.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7230e08dd0638048e46f387f255dbe7a7344a3e6705beab53242b5af25635760" +dependencies = [ + "float_next_after", + "lyon_path", +] + +[[package]] +name = "mach" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b823e83b2affd8f40a9ee8c29dbc56404c1e34cd2710921f2801e2cf29527afa" +dependencies = [ + "libc", +] + +[[package]] +name = "malloc_buf" +version = "0.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" +dependencies = [ + "libc", +] + +[[package]] +name = "maybe-uninit" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "memmap" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "memmap2" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b70ca2a6103ac8b665dc150b142ef0e4e89df640c9e6cf295d189c3caebe5a" +dependencies = [ + "libc", +] + +[[package]] +name = "memoffset" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "043175f069eda7b85febe4a74abbaeff828d9f8b448515d3151a14a3542811aa" +dependencies = [ + "autocfg", +] + +[[package]] +name = "memoffset" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" +dependencies = [ + "autocfg", +] + +[[package]] +name = "metal" +version = "0.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0514f491f4cc03632ab399ee01e2c1c1b12d3e1cf2d667c1ff5f87d6dcd2084" +dependencies = [ + "bitflags", + "block", + "core-graphics-types", + "foreign-types", + "log", + "objc", +] + +[[package]] +name = "mindtree_utils" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8314d4d41505841877b254f6f6002da7b420c8e77216f3096100c54be9073c2" +dependencies = [ + "num 0.1.42", + "rand 0.3.23", + "time", +] + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "miniz_oxide" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "791daaae1ed6889560f8c4359194f56648355540573244a5448a83ba1ecc7435" +dependencies = [ + "adler32", +] + +[[package]] +name = "miniz_oxide" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b" +dependencies = [ + "adler", + "autocfg", +] + +[[package]] +name = "mio" +version = "0.7.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8067b404fe97c70829f082dec8bcf4f71225d7eaea1d8645349cb76fa06205cc" +dependencies = [ + "libc", + "log", + "miow", + "ntapi", + "winapi", +] + +[[package]] +name = "mio-misc" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b47412f3a52115b936ff2a229b803498c7b4d332adeb87c2f1498c9da54c398c" +dependencies = [ + "crossbeam", + "crossbeam-queue", + "log", + "mio", +] + +[[package]] +name = "miow" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21" +dependencies = [ + "winapi", +] + +[[package]] +name = "naga" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "806f448a7ce662ca79ef5484ef8f451a9b7c51b8166c95f5a667228b3825a6ca" +dependencies = [ + "bit-set", + "bitflags", + "codespan-reporting", + "fxhash", + "hexf-parse", + "indexmap", + "log", + "num-traits", + "spirv", + "thiserror", +] + +[[package]] +name = "nannou" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99e905fd16cfd553b94d92badc04611410889c6fe36e5cfdc3325d6466b1991e" +dependencies = [ + "find_folder", + "futures", + "image", + "instant", + "lyon", + "nannou_core", + "nannou_mesh", + "nannou_wgpu", + "noise", + "notosans", + "num_cpus", + "pennereq", + "rusttype 0.8.3", + "serde", + "serde_derive", + "serde_json", + "toml", + "walkdir", + "wgpu", + "winit", +] + +[[package]] +name = "nannou_audio" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65614c2723bca0fbc1bf3830bb61442962db6ecf166afb9985d5aaa4a1dd2ea4" +dependencies = [ + "cpal", + "dasp_sample", + "thiserror", +] + +[[package]] +name = "nannou_conrod" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a10300da353120f58c873724c9bff65d8fe5b71dae75c55dbef6e9eaf7db5a7" +dependencies = [ + "conrod_core", + "conrod_wgpu", + "conrod_winit", + "nannou", + "winit", +] + +[[package]] +name = "nannou_core" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d53707a99dc3b2908f1d25d982755126d885ac6d780741de29f44956624fcac" +dependencies = [ + "glam", + "num-traits", + "palette", + "rand 0.8.5", +] + +[[package]] +name = "nannou_mesh" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da3ceb90554c048fb5f29a19820d3581d4fb85fe22e6f27d21faca0dbfab5e07" +dependencies = [ + "nannou_core", + "serde", +] + +[[package]] +name = "nannou_osc" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9995e9e5af9e50a05aa056f261e1ebb27b46409f1ff3bb219a0a2277574785c" +dependencies = [ + "rosc", +] + +[[package]] +name = "nannou_wgpu" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ca299eec1e956df21430f66e8fe210f992f4348c1406e6ed965579d9d00d167" +dependencies = [ + "futures", + "image", + "instant", + "num_cpus", + "wgpu", +] + +[[package]] +name = "ndk" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8794322172319b972f528bf90c6b467be0079f1fa82780ffb431088e741a73ab" +dependencies = [ + "jni-sys", + "ndk-sys 0.2.2", + "num_enum", + "thiserror", +] + +[[package]] +name = "ndk" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2032c77e030ddee34a6787a64166008da93f6a352b629261d0fee232b8742dd4" +dependencies = [ + "bitflags", + "jni-sys", + "ndk-sys 0.3.0", + "num_enum", + "thiserror", +] + +[[package]] +name = "ndk-context" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" + +[[package]] +name = "ndk-glue" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5caf0c24d51ac1c905c27d4eda4fa0635bbe0de596b8f79235e0b17a4d29385" +dependencies = [ + "lazy_static", + "libc", + "log", + "ndk 0.3.0", + "ndk-macro 0.2.0", + "ndk-sys 0.2.2", +] + +[[package]] +name = "ndk-glue" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d0c4a7b83860226e6b4183edac21851f05d5a51756e97a1144b7f5a6b63e65f" +dependencies = [ + "lazy_static", + "libc", + "log", + "ndk 0.6.0", + "ndk-context", + "ndk-macro 0.3.0", + "ndk-sys 0.3.0", +] + +[[package]] +name = "ndk-macro" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05d1c6307dc424d0f65b9b06e94f88248e6305726b14729fd67a5e47b2dc481d" +dependencies = [ + "darling 0.10.2", + "proc-macro-crate 0.1.5", + "proc-macro2 1.0.39", + "quote 1.0.18", + "syn", +] + +[[package]] +name = "ndk-macro" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0df7ac00c4672f9d5aece54ee3347520b7e20f158656c7db2e6de01902eb7a6c" +dependencies = [ + "darling 0.13.4", + "proc-macro-crate 1.1.3", + "proc-macro2 1.0.39", + "quote 1.0.18", + "syn", +] + +[[package]] +name = "ndk-sys" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1bcdd74c20ad5d95aacd60ef9ba40fdf77f767051040541df557b7a9b2a2121" + +[[package]] +name = "ndk-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e5a6ae77c8ee183dcbbba6150e2e6b9f3f4196a7666c02a715a95692ec1fa97" +dependencies = [ + "jni-sys", +] + +[[package]] +name = "newtype_derive" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac8cd24d9f185bb7223958d8c1ff7a961b74b1953fd05dba7cc568a63b3861ec" +dependencies = [ + "rustc_version", +] + +[[package]] +name = "nix" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c722bee1037d430d0f8e687bbdbf222f27cc6e4e68d5caf630857bb2b6dbdce" +dependencies = [ + "bitflags", + "cc", + "cfg-if 0.1.10", + "libc", + "void", +] + +[[package]] +name = "nix" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83450fe6a6142ddd95fb064b746083fc4ef1705fe81f64a64e1d4b39f54a1055" +dependencies = [ + "bitflags", + "cc", + "cfg-if 0.1.10", + "libc", +] + +[[package]] +name = "nix" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa9b4819da1bc61c0ea48b63b7bc8604064dd43013e7cc325df098d49cd7c18a" +dependencies = [ + "bitflags", + "cc", + "cfg-if 1.0.0", + "libc", +] + +[[package]] +name = "nix" +version = "0.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f866317acbd3a240710c63f065ffb1e4fd466259045ccb504130b7f668f35c6" +dependencies = [ + "bitflags", + "cc", + "cfg-if 1.0.0", + "libc", + "memoffset 0.6.5", +] + +[[package]] +name = "noise" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82051dd6745d5184c6efb7bc8be14892a7f6d4f3ad6dbf754d1c7d7d5fe24b43" +dependencies = [ + "image", + "rand 0.7.3", + "rand_xorshift 0.2.0", +] + +[[package]] +name = "nom" +version = "5.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffb4262d26ed83a1c0a33a38fe2bb15797329c85770da05e6b828ddb782627af" +dependencies = [ + "memchr", + "version_check", +] + +[[package]] +name = "nom" +version = "7.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8903e5a29a317527874d0402f867152a3d21c908bb0b933e416c65e301d4c36" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "notosans" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "004d578bbfc8a6bdd4690576a8381af234ef051dd4cc358604e1784821e8205c" + +[[package]] +name = "ntapi" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c28774a7fd2fbb4f0babd8237ce554b73af68021b5f695a3cebd6c59bac0980f" +dependencies = [ + "winapi", +] + +[[package]] +name = "num" +version = "0.1.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4703ad64153382334aa8db57c637364c322d3372e097840c72000dabdcf6156e" +dependencies = [ + "num-bigint 0.1.44", + "num-complex 0.1.43", + "num-integer", + "num-iter", + "num-rational 0.1.42", + "num-traits", +] + +[[package]] +name = "num" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b7a8e9be5e039e2ff869df49155f1c06bd01ade2117ec783e56ab0932b67a8f" +dependencies = [ + "num-bigint 0.3.3", + "num-complex 0.3.1", + "num-integer", + "num-iter", + "num-rational 0.3.2", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e63899ad0da84ce718c14936262a41cee2c79c981fc0a0e7c7beb47d5a07e8c1" +dependencies = [ + "num-integer", + "num-traits", + "rand 0.4.6", + "rustc-serialize", +] + +[[package]] +name = "num-bigint" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f6f7833f2cbf2360a6cfd58cd41a53aa7a90bd4c202f5b1c7dd2ed73c57b2c3" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-complex" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b288631d7878aaf59442cffd36910ea604ecd7745c36054328595114001c9656" +dependencies = [ + "num-traits", + "rustc-serialize", +] + +[[package]] +name = "num-complex" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "747d632c0c558b87dbabbe6a82f3b4ae03720d0646ac5b7b4dae89394be5f2c5" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-complex" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fbc387afefefd5e9e39493299f3069e14a140dd34dc19b4c1c1a8fddb6a790" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-derive" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" +dependencies = [ + "proc-macro2 1.0.39", + "quote 1.0.18", + "syn", +] + +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.1.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee314c74bd753fc86b4780aa9475da469155f3848473a261d2d18e35245a784e" +dependencies = [ + "num-bigint 0.1.44", + "num-integer", + "num-traits", + "rustc-serialize", +] + +[[package]] +name = "num-rational" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12ac428b1cb17fce6f731001d307d351ec70a6d202fc2e60f7d4c5e42d8f4f07" +dependencies = [ + "autocfg", + "num-bigint 0.3.3", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_cpus" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "num_enum" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf5395665662ef45796a4ff5486c5d41d29e0c09640af4c5f17fd94ee2c119c9" +dependencies = [ + "num_enum_derive", +] + +[[package]] +name = "num_enum_derive" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0498641e53dd6ac1a4f22547548caa6864cc4933784319cd1775271c5a46ce" +dependencies = [ + "proc-macro-crate 1.1.3", + "proc-macro2 1.0.39", + "quote 1.0.18", + "syn", +] + +[[package]] +name = "objc" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" +dependencies = [ + "malloc_buf", + "objc_exception", +] + +[[package]] +name = "objc-foundation" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9" +dependencies = [ + "block", + "objc", + "objc_id", +] + +[[package]] +name = "objc_exception" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad970fb455818ad6cba4c122ad012fae53ae8b4795f86378bce65e4f6bab2ca4" +dependencies = [ + "cc", +] + +[[package]] +name = "objc_id" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c92d4ddb4bd7b50d730c215ff871754d0da6b2178849f8a2a2ab69712d0c073b" +dependencies = [ + "objc", +] + +[[package]] +name = "oboe" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27f63c358b4fa0fbcfefd7c8be5cfc39c08ce2389f5325687e7762a48d30a5c1" +dependencies = [ + "jni", + "ndk 0.6.0", + "ndk-context", + "num-derive", + "num-traits", + "oboe-sys", +] + +[[package]] +name = "oboe-sys" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3370abb7372ed744232c12954d920d1a40f1c4686de9e79e800021ef492294bd" +dependencies = [ + "cc", +] + +[[package]] +name = "once_cell" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7709cef83f0c1f58f666e746a08b21e0085f7440fa6a29cc194d68aac97a4225" + +[[package]] +name = "ordered-float" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3305af35278dd29f46fcdd139e0b1fbfae2153f0e5928b39b035542dd31e37b7" +dependencies = [ + "num-traits", +] + +[[package]] +name = "owned_ttf_parser" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f923fb806c46266c02ab4a5b239735c144bdeda724a50ed058e5226f594cde3" +dependencies = [ + "ttf-parser", +] + +[[package]] +name = "palette" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a05c0334468e62a4dfbda34b29110aa7d70d58c7fdb2c9857b5874dd9827cc59" +dependencies = [ + "approx", + "num-traits", + "palette_derive", + "serde", +] + +[[package]] +name = "palette_derive" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b4b5f600e60dd3a147fb57b4547033d382d1979eb087af310e91cb45a63b1f4" +dependencies = [ + "proc-macro2 1.0.39", + "quote 1.0.18", + "syn", +] + +[[package]] +name = "parking_lot" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" +dependencies = [ + "instant", + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" +dependencies = [ + "cfg-if 1.0.0", + "instant", + "libc", + "redox_syscall", + "smallvec", + "winapi", +] + +[[package]] +name = "peeking_take_while" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" + +[[package]] +name = "pennereq" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2174a8f4566f0f8cdce1af08dc29d78fc93880f70962a1e49385831b9550dc8b" +dependencies = [ + "num-traits", +] + +[[package]] +name = "percent-encoding" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" + +[[package]] +name = "petgraph" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c3659d1ee90221741f65dd128d9998311b0e40c5d3c23a62445938214abce4f" +dependencies = [ + "fixedbitset", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "piston-float" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad78bf43dcf80e8f950c92b84f938a0fc7590b7f6866fbcbeca781609c115590" + +[[package]] +name = "piston-viewport" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61ecaf8ae0d71dd9cdbbd8662b47659621c09430ff3cb880d154858d3b8ac001" +dependencies = [ + "piston-float", +] + +[[package]] +name = "pistoncore-input" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2977fed6eb16c554fd445a09a50c8a0c250f4c50f752be46a7bd9dcc5ba471f0" +dependencies = [ + "bitflags", + "piston-viewport", + "serde", + "serde_derive", +] + +[[package]] +name = "pitch_calc" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "387005d7ff9e9970f954ffd33e258f9b755d5f27f11a4b57df3e5c6eab5a46f8" +dependencies = [ + "num 0.1.42", + "rand 0.3.23", +] + +[[package]] +name = "pkg-config" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae" + +[[package]] +name = "png" +version = "0.16.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c3287920cb847dee3de33d301c463fba14dda99db24214ddf93f83d3021f4c6" +dependencies = [ + "bitflags", + "crc32fast", + "deflate", + "miniz_oxide 0.3.7", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" + +[[package]] +name = "primal-check" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01419cee72c1a1ca944554e23d83e483e1bccf378753344e881de28b5487511d" +dependencies = [ + "num-integer", +] + +[[package]] +name = "proc-macro-crate" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785" +dependencies = [ + "toml", +] + +[[package]] +name = "proc-macro-crate" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e17d47ce914bf4de440332250b0edd23ce48c005f59fab39d3335866b114f11a" +dependencies = [ + "thiserror", + "toml", +] + +[[package]] +name = "proc-macro2" +version = "0.4.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "proc-macro2" +version = "1.0.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c54b25569025b7fc9651de43004ae593a75ad88543b17178aa5e1b9c4f15f56f" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "profiling" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f61dcf0b917cd75d4521d7343d1ffff3d1583054133c9b5cbea3375c703c40d" + +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + +[[package]] +name = "quick-xml" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8533f14c8382aaad0d592c812ac3b826162128b65662331e1127b45c3d18536b" +dependencies = [ + "memchr", +] + +[[package]] +name = "quote" +version = "0.6.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" +dependencies = [ + "proc-macro2 0.4.30", +] + +[[package]] +name = "quote" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" +dependencies = [ + "proc-macro2 1.0.39", +] + +[[package]] +name = "rand" +version = "0.3.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64ac302d8f83c0c1974bf758f6b041c6c8ada916fbb44a609158ca8b064cc76c" +dependencies = [ + "libc", + "rand 0.4.6", +] + +[[package]] +name = "rand" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" +dependencies = [ + "fuchsia-cprng", + "libc", + "rand_core 0.3.1", + "rdrand", + "winapi", +] + +[[package]] +name = "rand" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" +dependencies = [ + "getrandom 0.1.16", + "libc", + "rand_chacha 0.2.2", + "rand_core 0.5.1", + "rand_hc", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.3", +] + +[[package]] +name = "rand_chacha" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" +dependencies = [ + "ppv-lite86", + "rand_core 0.5.1", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.3", +] + +[[package]] +name = "rand_core" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" +dependencies = [ + "rand_core 0.4.2", +] + +[[package]] +name = "rand_core" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +dependencies = [ + "getrandom 0.1.16", +] + +[[package]] +name = "rand_core" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" +dependencies = [ + "getrandom 0.2.6", +] + +[[package]] +name = "rand_hc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +dependencies = [ + "rand_core 0.5.1", +] + +[[package]] +name = "rand_xorshift" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77d416b86801d23dde1aa643023b775c3a462efc0ed96443add11546cdf1dca8" +dependencies = [ + "rand_core 0.5.1", +] + +[[package]] +name = "rand_xorshift" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" +dependencies = [ + "rand_core 0.6.3", +] + +[[package]] +name = "range-alloc" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63e935c45e09cc6dcf00d2f0b2d630a58f4095320223d47fc68918722f0538b6" + +[[package]] +name = "raw-window-handle" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e28f55143d0548dad60bb4fbdc835a3d7ac6acc3324506450c5fdd6e42903a76" +dependencies = [ + "libc", + "raw-window-handle 0.4.3", +] + +[[package]] +name = "raw-window-handle" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b800beb9b6e7d2df1fe337c9e3d04e3af22a124460fb4c30fcc22c9117cefb41" +dependencies = [ + "cty", +] + +[[package]] +name = "rayon" +version = "1.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd99e5772ead8baa5215278c9b15bf92087709e9c1b2d1f97cdb5a183c933a7d" +dependencies = [ + "autocfg", + "crossbeam-deque 0.8.1", + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "258bcdb5ac6dad48491bb2992db6b7cf74878b0384908af124823d118c99683f" +dependencies = [ + "crossbeam-channel", + "crossbeam-deque 0.8.1", + "crossbeam-utils 0.8.8", + "num_cpus", +] + +[[package]] +name = "rdrand" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" +dependencies = [ + "rand_core 0.3.1", +] + +[[package]] +name = "redox_syscall" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" +dependencies = [ + "bitflags", +] + +[[package]] +name = "redox_users" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" +dependencies = [ + "getrandom 0.2.6", + "redox_syscall", + "thiserror", +] + +[[package]] +name = "regex" +version = "1.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d83f127d94bdbcda4c8cc2e50f6f84f4b611f69c902699ca385a39c3a75f9ff1" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49b3de9ec5dc0a3417da371aab17d729997c15010e7fd24ff707773a33bddb64" + +[[package]] +name = "renderdoc-sys" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1382d1f0a252c4bf97dc20d979a2fdd05b024acd7c2ed0f7595d7817666a157" + +[[package]] +name = "rosc" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39332ba44e0804497d958f692a3fbb7dd993cc996070189f40577de87ff1b8d9" +dependencies = [ + "byteorder", +] + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustc-serialize" +version = "0.3.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" + +[[package]] +name = "rustc_version" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5f5376ea5e30ce23c03eb77cbe4962b988deead10910c372b226388b594c084" +dependencies = [ + "semver", +] + +[[package]] +name = "rustfft" +version = "6.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1d089e5c57521629a59f5f39bca7434849ff89bd6873b521afe389c1c602543" +dependencies = [ + "num-complex 0.4.1", + "num-integer", + "num-traits", + "primal-check", + "strength_reduce", + "transpose", +] + +[[package]] +name = "rusttype" +version = "0.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "310942406a39981bed7e12b09182a221a29e0990f3e7e0c971f131922ed135d5" +dependencies = [ + "rusttype 0.8.3", +] + +[[package]] +name = "rusttype" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f61411055101f7b60ecf1041d87fb74205fb20b0c7a723f07ef39174cf6b4c0" +dependencies = [ + "approx", + "crossbeam-deque 0.7.4", + "crossbeam-utils 0.7.2", + "linked-hash-map", + "num_cpus", + "ordered-float", + "rustc-hash", + "stb_truetype", +] + +[[package]] +name = "rusttype" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc7c727aded0be18c5b80c1640eae0ac8e396abf6fa8477d96cb37d18ee5ec59" +dependencies = [ + "ab_glyph_rasterizer", + "owned_ttf_parser", +] + +[[package]] +name = "ryu" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "scoped-tls" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2" + +[[package]] +name = "scoped_threadpool" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d51f5df5af43ab3f1360b429fa5e0152ac5ce8c0bd6485cae490332e96846a8" + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "semver" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4f410fedcf71af0345d7607d246e7ad15faaadd49d240ee3b24e5dc21a820ac" + +[[package]] +name = "serde" +version = "1.0.137" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.137" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f26faba0c3959972377d3b2d306ee9f71faee9714294e41bb777f83f88578be" +dependencies = [ + "proc-macro2 1.0.39", + "quote 1.0.18", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b7ce2b32a1aed03c558dc61a5cd328f15aff2dbc17daad8fb8af04d2100e15c" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "shlex" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2" + +[[package]] +name = "sid" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd5ac56c121948b4879bba9e519852c211bcdd8f014efff766441deff0b91bdb" +dependencies = [ + "num-traits", +] + +[[package]] +name = "slab" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb703cfe953bccee95685111adeedb76fabe4e97549a58d16f03ea7b9367bb32" + +[[package]] +name = "slotmap" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1e08e261d0e8f5c43123b7adf3e4ca1690d655377ac93a03b2c9d3e98de1342" +dependencies = [ + "version_check", +] + +[[package]] +name = "slug" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3bc762e6a4b6c6fcaade73e77f9ebc6991b676f88bb2358bddb56560f073373" +dependencies = [ + "deunicode", +] + +[[package]] +name = "smallvec" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" + +[[package]] +name = "smithay-client-toolkit" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "421c8dc7acf5cb205b88160f8b4cc2c5cfabe210e43b2f80f009f4c1ef910f1d" +dependencies = [ + "andrew 0.2.1", + "bitflags", + "dlib 0.4.2", + "lazy_static", + "memmap", + "nix 0.14.1", + "wayland-client 0.23.6", + "wayland-protocols 0.23.6", +] + +[[package]] +name = "smithay-client-toolkit" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4750c76fd5d3ac95fa3ed80fe667d6a3d8590a960e5b575b98eea93339a80b80" +dependencies = [ + "andrew 0.3.1", + "bitflags", + "calloop", + "dlib 0.4.2", + "lazy_static", + "log", + "memmap2", + "nix 0.18.0", + "wayland-client 0.28.6", + "wayland-cursor", + "wayland-protocols 0.28.6", +] + +[[package]] +name = "smithay-clipboard" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "917e8ec7f535cd1a6cbf749c8866c24d67c548a80ac48c8e88a182eab5c07bd1" +dependencies = [ + "nix 0.14.1", + "smithay-client-toolkit 0.6.6", +] + +[[package]] +name = "spirv" +version = "0.2.0+1.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "246bfa38fe3db3f1dfc8ca5a2cdeb7348c78be2112740cc0ec8ef18b6d94f830" +dependencies = [ + "bitflags", + "num-traits", +] + +[[package]] +name = "stb_truetype" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f77b6b07e862c66a9f3e62a07588fee67cd90a9135a2b942409f195507b4fb51" +dependencies = [ + "byteorder", +] + +[[package]] +name = "stdweb" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef5430c8e36b713e13b48a9f709cc21e046723fe44ce34587b73a830203b533e" + +[[package]] +name = "strength_reduce" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3ff2f71c82567c565ba4b3009a9350a96a7269eaa4001ebedae926230bc2254" + +[[package]] +name = "strsim" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" + +[[package]] +name = "strsim" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c" + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "syn" +version = "1.0.96" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0748dd251e24453cb8717f0354206b91557e4ec8703673a4b30208f2abaf1ebf" +dependencies = [ + "proc-macro2 1.0.39", + "quote 1.0.18", + "unicode-ident", +] + +[[package]] +name = "termcolor" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "textwrap" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +dependencies = [ + "unicode-width", +] + +[[package]] +name = "thiserror" +version = "1.0.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a" +dependencies = [ + "proc-macro2 1.0.39", + "quote 1.0.18", + "syn", +] + +[[package]] +name = "threadpool" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa" +dependencies = [ + "num_cpus", +] + +[[package]] +name = "tiff" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a53f4706d65497df0c4349241deddf35f84cee19c87ed86ea8ca590f4464437" +dependencies = [ + "jpeg-decoder", + "miniz_oxide 0.4.4", + "weezl", +] + +[[package]] +name = "time" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "time_calc" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87eac2313f2e8e6ac326f44b662cd4491c6f1c6b590668abcdd48be1cc439e83" +dependencies = [ + "num 0.1.42", + "rand 0.3.23", + "serde", +] + +[[package]] +name = "toml" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7" +dependencies = [ + "serde", +] + +[[package]] +name = "transpose" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95f9c900aa98b6ea43aee227fd680550cdec726526aab8ac801549eadb25e39f" +dependencies = [ + "num-integer", + "strength_reduce", +] + +[[package]] +name = "ttf-parser" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e5d7cd7ab3e47dda6e56542f4bbf3824c15234958c6e1bd6aaa347e93499fdc" + +[[package]] +name = "unicode-ident" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d22af068fba1eb5edcb4aea19d382b2a3deb4c8f9d475c589b6ada9e0fd493ee" + +[[package]] +name = "unicode-width" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" + +[[package]] +name = "unicode-xid" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" + +[[package]] +name = "vec_map" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "void" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" + +[[package]] +name = "walkdir" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" +dependencies = [ + "same-file", + "winapi", + "winapi-util", +] + +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + +[[package]] +name = "wasi" +version = "0.10.2+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" + +[[package]] +name = "wasm-bindgen" +version = "0.2.80" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27370197c907c55e3f1a9fbe26f44e937fe6451368324e009cba39e139dc08ad" +dependencies = [ + "cfg-if 1.0.0", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.80" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53e04185bfa3a779273da532f5025e33398409573f348985af9a1cbf3774d3f4" +dependencies = [ + "bumpalo", + "lazy_static", + "log", + "proc-macro2 1.0.39", + "quote 1.0.18", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f741de44b75e14c35df886aff5f1eb73aa114fa5d4d00dcd37b5e01259bf3b2" +dependencies = [ + "cfg-if 1.0.0", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.80" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17cae7ff784d7e83a2fe7611cfe766ecf034111b49deb850a3dc7699c08251f5" +dependencies = [ + "quote 1.0.18", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.80" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99ec0dc7a4756fffc231aab1b9f2f578d23cd391390ab27f952ae0c9b3ece20b" +dependencies = [ + "proc-macro2 1.0.39", + "quote 1.0.18", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.80" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d554b7f530dee5964d9a9468d95c1f8b8acae4f282807e7d27d4b03099a46744" + +[[package]] +name = "wayland-client" +version = "0.23.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af1080ebe0efabcf12aef2132152f616038f2d7dcbbccf7b2d8c5270fe14bcda" +dependencies = [ + "bitflags", + "downcast-rs", + "libc", + "nix 0.14.1", + "wayland-commons 0.23.6", + "wayland-scanner 0.23.6", + "wayland-sys 0.23.6", +] + +[[package]] +name = "wayland-client" +version = "0.28.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3ab332350e502f159382201394a78e3cc12d0f04db863429260164ea40e0355" +dependencies = [ + "bitflags", + "downcast-rs", + "libc", + "nix 0.20.0", + "scoped-tls", + "wayland-commons 0.28.6", + "wayland-scanner 0.28.6", + "wayland-sys 0.28.6", +] + +[[package]] +name = "wayland-commons" +version = "0.23.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb66b0d1a27c39bbce712b6372131c6e25149f03ffb0cd017cf8f7de8d66dbdb" +dependencies = [ + "nix 0.14.1", + "wayland-sys 0.23.6", +] + +[[package]] +name = "wayland-commons" +version = "0.28.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a21817947c7011bbd0a27e11b17b337bfd022e8544b071a2641232047966fbda" +dependencies = [ + "nix 0.20.0", + "once_cell", + "smallvec", + "wayland-sys 0.28.6", +] + +[[package]] +name = "wayland-cursor" +version = "0.28.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be610084edd1586d45e7bdd275fe345c7c1873598caa464c4fb835dee70fa65a" +dependencies = [ + "nix 0.20.0", + "wayland-client 0.28.6", + "xcursor", +] + +[[package]] +name = "wayland-protocols" +version = "0.23.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6cc286643656742777d55dc8e70d144fa4699e426ca8e9d4ef454f4bf15ffcf9" +dependencies = [ + "bitflags", + "wayland-client 0.23.6", + "wayland-commons 0.23.6", + "wayland-scanner 0.23.6", +] + +[[package]] +name = "wayland-protocols" +version = "0.28.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "286620ea4d803bacf61fa087a4242ee316693099ee5a140796aaba02b29f861f" +dependencies = [ + "bitflags", + "wayland-client 0.28.6", + "wayland-commons 0.28.6", + "wayland-scanner 0.28.6", +] + +[[package]] +name = "wayland-scanner" +version = "0.23.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93b02247366f395b9258054f964fe293ddd019c3237afba9be2ccbe9e1651c3d" +dependencies = [ + "proc-macro2 0.4.30", + "quote 0.6.13", + "xml-rs", +] + +[[package]] +name = "wayland-scanner" +version = "0.28.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce923eb2deb61de332d1f356ec7b6bf37094dc5573952e1c8936db03b54c03f1" +dependencies = [ + "proc-macro2 1.0.39", + "quote 1.0.18", + "xml-rs", +] + +[[package]] +name = "wayland-sys" +version = "0.23.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d94e89a86e6d6d7c7c9b19ebf48a03afaac4af6bc22ae570e9a24124b75358f4" +dependencies = [ + "dlib 0.4.2", + "lazy_static", +] + +[[package]] +name = "wayland-sys" +version = "0.28.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d841fca9aed7febf9bed2e9796c49bf58d4152ceda8ac949ebe00868d8f0feb8" +dependencies = [ + "dlib 0.5.0", + "lazy_static", + "pkg-config", +] + +[[package]] +name = "web-sys" +version = "0.3.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b17e741662c70c8bd24ac5c5b18de314a2c26c32bf8346ee1e6f53de919c283" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "weezl" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c97e489d8f836838d497091de568cf16b117486d529ec5579233521065bd5e4" + +[[package]] +name = "wgpu" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eae7181fe6ba5f4b632a9079cc9e922a64555156c87def72c063f94b180c7d68" +dependencies = [ + "arrayvec 0.7.2", + "js-sys", + "log", + "parking_lot", + "raw-window-handle 0.3.4", + "smallvec", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "wgpu-core", + "wgpu-hal", + "wgpu-types", +] + +[[package]] +name = "wgpu-core" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35600627b6c718ad0e23ed75fb6140bfe32cdf21c8f539ce3c9ab8180e2cb38e" +dependencies = [ + "arrayvec 0.7.2", + "bitflags", + "cfg_aliases", + "copyless", + "fxhash", + "log", + "naga", + "parking_lot", + "profiling", + "raw-window-handle 0.3.4", + "smallvec", + "thiserror", + "wgpu-hal", + "wgpu-types", +] + +[[package]] +name = "wgpu-hal" +version = "0.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af28b29ef0b44cd22dd9895d4349b9d5a687df42f58da234871198637eabe328" +dependencies = [ + "arrayvec 0.7.2", + "ash", + "bit-set", + "bitflags", + "block", + "core-graphics-types", + "d3d12", + "foreign-types", + "fxhash", + "glow", + "gpu-alloc", + "gpu-descriptor", + "inplace_it", + "js-sys", + "khronos-egl", + "libloading 0.7.3", + "log", + "metal", + "naga", + "objc", + "parking_lot", + "profiling", + "range-alloc", + "raw-window-handle 0.3.4", + "renderdoc-sys", + "thiserror", + "wasm-bindgen", + "web-sys", + "wgpu-types", + "winapi", +] + +[[package]] +name = "wgpu-types" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e15e44ba88ec415466e18e91881319e7c9e96cb905dc623305168aea65b85ccc" +dependencies = [ + "bitflags", +] + +[[package]] +name = "which" +version = "3.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d011071ae14a2f6671d0b74080ae0cd8ebf3a6f8c9589a2cd45f23126fe29724" +dependencies = [ + "libc", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "winit" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79610794594d5e86be473ef7763f604f2159cbac8c94debd00df8fb41e86c2f8" +dependencies = [ + "bitflags", + "cocoa", + "core-foundation 0.9.3", + "core-graphics 0.22.3", + "core-video-sys", + "dispatch", + "instant", + "lazy_static", + "libc", + "log", + "mio", + "mio-misc", + "ndk 0.3.0", + "ndk-glue 0.3.0", + "ndk-sys 0.2.2", + "objc", + "parking_lot", + "percent-encoding", + "raw-window-handle 0.3.4", + "scopeguard", + "smithay-client-toolkit 0.12.3", + "wayland-client 0.28.6", + "winapi", + "x11-dl", +] + +[[package]] +name = "x11-clipboard" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "473068b7b80ac86a18328824f1054e5e007898c47b5bbc281bd7abe32bc3653c" +dependencies = [ + "xcb", +] + +[[package]] +name = "x11-dl" +version = "2.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea26926b4ce81a6f5d9d0f3a0bc401e5a37c6ae14a1bfaa8ff6099ca80038c59" +dependencies = [ + "lazy_static", + "libc", + "pkg-config", +] + +[[package]] +name = "xcb" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "771e2b996df720cd1c6dd9ff90f62d91698fd3610cc078388d0564bdd6622a9c" +dependencies = [ + "libc", + "log", + "quick-xml", +] + +[[package]] +name = "xcursor" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "463705a63313cd4301184381c5e8042f0a7e9b4bb63653f216311d4ae74690b7" +dependencies = [ + "nom 7.1.1", +] + +[[package]] +name = "xdg" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c4583db5cbd4c4c0303df2d15af80f0539db703fa1c68802d4cbbd2dd0f88f6" +dependencies = [ + "dirs", +] + +[[package]] +name = "xml-rs" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2d7d3948613f75c98fd9328cfdcc45acc4d360655289d0a7d4ec931392200a3" From 32ec007c0f47f18ce38bb9058aa8c3983468c228 Mon Sep 17 00:00:00 2001 From: "Ando \"Thor\" Nando" Date: Wed, 15 Jun 2022 19:54:01 +1000 Subject: [PATCH 6/8] chore: update dependencies some more --- Cargo.lock | 59 ++++++++++++++++++++++++++++++------------------------ Cargo.toml | 26 ++++++++++++------------ 2 files changed, 46 insertions(+), 39 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e25d855..5de27c9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -26,7 +26,7 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" dependencies = [ - "getrandom 0.2.6", + "getrandom 0.2.7", "once_cell", "version_check", ] @@ -1210,13 +1210,13 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.6" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9be70c98951c83b8d2f8f60d7065fa6d5146873094452a1008da8c2f1e4205ad" +checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6" dependencies = [ "cfg-if 1.0.0", "libc", - "wasi 0.10.2+wasi-snapshot-preview1", + "wasi 0.11.0+wasi-snapshot-preview1", ] [[package]] @@ -1435,9 +1435,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.57" +version = "0.3.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "671a26f820db17c2a2750743f1dd03bafd15b98c9f30c7c2628c024c05d73397" +checksum = "c3fac17f7123a73ca62df411b1bf727ccc805daa070338fda671c86dac1bdc27" dependencies = [ "wasm-bindgen", ] @@ -2649,7 +2649,7 @@ version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" dependencies = [ - "getrandom 0.2.6", + "getrandom 0.2.7", ] [[package]] @@ -2752,7 +2752,7 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" dependencies = [ - "getrandom 0.2.6", + "getrandom 0.2.7", "redox_syscall", "thiserror", ] @@ -3139,11 +3139,12 @@ dependencies = [ [[package]] name = "time" -version = "0.1.43" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438" +checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" dependencies = [ "libc", + "wasi 0.10.0+wasi-snapshot-preview1", "winapi", ] @@ -3185,9 +3186,9 @@ checksum = "3e5d7cd7ab3e47dda6e56542f4bbf3824c15234958c6e1bd6aaa347e93499fdc" [[package]] name = "unicode-ident" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d22af068fba1eb5edcb4aea19d382b2a3deb4c8f9d475c589b6ada9e0fd493ee" +checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c" [[package]] name = "unicode-width" @@ -3238,15 +3239,21 @@ checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" [[package]] name = "wasi" -version = "0.10.2+wasi-snapshot-preview1" +version = "0.10.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.80" +version = "0.2.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27370197c907c55e3f1a9fbe26f44e937fe6451368324e009cba39e139dc08ad" +checksum = "7c53b543413a17a202f4be280a7e5c62a1c69345f5de525ee64f8cfdbc954994" dependencies = [ "cfg-if 1.0.0", "wasm-bindgen-macro", @@ -3254,9 +3261,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.80" +version = "0.2.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53e04185bfa3a779273da532f5025e33398409573f348985af9a1cbf3774d3f4" +checksum = "5491a68ab4500fa6b4d726bd67408630c3dbe9c4fe7bda16d5c82a1fd8c7340a" dependencies = [ "bumpalo", "lazy_static", @@ -3269,9 +3276,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.30" +version = "0.4.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f741de44b75e14c35df886aff5f1eb73aa114fa5d4d00dcd37b5e01259bf3b2" +checksum = "de9a9cec1733468a8c657e57fa2413d2ae2c0129b95e87c5b72b8ace4d13f31f" dependencies = [ "cfg-if 1.0.0", "js-sys", @@ -3281,9 +3288,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.80" +version = "0.2.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17cae7ff784d7e83a2fe7611cfe766ecf034111b49deb850a3dc7699c08251f5" +checksum = "c441e177922bc58f1e12c022624b6216378e5febc2f0533e41ba443d505b80aa" dependencies = [ "quote 1.0.18", "wasm-bindgen-macro-support", @@ -3291,9 +3298,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.80" +version = "0.2.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99ec0dc7a4756fffc231aab1b9f2f578d23cd391390ab27f952ae0c9b3ece20b" +checksum = "7d94ac45fcf608c1f45ef53e748d35660f168490c10b23704c7779ab8f5c3048" dependencies = [ "proc-macro2 1.0.39", "quote 1.0.18", @@ -3304,9 +3311,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.80" +version = "0.2.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d554b7f530dee5964d9a9468d95c1f8b8acae4f282807e7d27d4b03099a46744" +checksum = "6a89911bd99e5f3659ec4acf9c4d93b0a90fe4a2a11f15328472058edc5261be" [[package]] name = "wayland-client" diff --git a/Cargo.toml b/Cargo.toml index 750af17..1068d16 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,27 +21,27 @@ path = "src/lib/lib.rs" conrod_core = "0.76.1" conrod_derive = "0.76.1" crossbeam = "0.8.1" -custom_derive = "0.1" +custom_derive = "0.1.7" dasp = { version = "0.11.0", features = ["all"] } -fxhash = "0.2" -hound = "3.3" -mindtree_utils = "0.4" -newtype_derive = "0.1" +fxhash = "0.2.1" +hound = "3.4.0" +mindtree_utils = "0.4.0" +newtype_derive = "0.1.6" nannou = "0.18.1" nannou_audio = "0.18.0" nannou_conrod = "0.18.0" nannou_osc = "0.18.0" -num_cpus = "1.8" +num_cpus = "1.13.1" pitch_calc = "0.12.0" rand_xorshift = "0.3.0" rustfft = "6.0.1" -serde = { version = "1.0", features = ["rc"] } -serde_derive = "1.0" -serde_json = "1.0" -slug = "0.1" -time_calc = { version = "0.13", features = ["serde"] } -threadpool = "1.7" -walkdir = "2" +serde = { version = "1.0.137", features = ["rc"] } +serde_derive = "1.0.137" +serde_json = "1.0.81" +slug = "0.1.4" +time_calc = { version = "0.13.0", features = ["serde"] } +threadpool = "1.8.1" +walkdir = "2.3.2" [features] asio = ["nannou_audio/asio"] From e80d411406cb8adaf2b84246d7d5c6125e71e61d Mon Sep 17 00:00:00 2001 From: "Ando \"Thor\" Nando" Date: Sun, 19 Jun 2022 18:58:19 +1000 Subject: [PATCH 7/8] debugging in progress --- src/lib/lib.rs | 17 +++++++++++++++++ src/lib/soundscape/mod.rs | 16 ++++++++-------- 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/src/lib/lib.rs b/src/lib/lib.rs index b4af524..66f93ae 100644 --- a/src/lib/lib.rs +++ b/src/lib/lib.rs @@ -59,13 +59,16 @@ fn model(app: &App) -> Model { // We will wake it up if it is necessary to re-instantiate and redraw the GUI. app.set_loop_mode(LoopMode::Wait); } + println!("Starting ..."); // Find the assets directory. let assets = app.assets_path().expect("could not find assets directory"); + println!("Found assets"); // Load the configuration struct. let config_path = config_path(&assets); let config: Config = utils::load_from_json_or_default(&config_path); + println!("Found config"); // Spawn the OSC input thread. let osc_receiver = nannou_osc::receiver(config.osc_input_port).unwrap_or_else(|err| { @@ -75,27 +78,34 @@ fn model(app: &App) -> Model { ) }); let (_osc_in_thread_handle, osc_in_log_rx, control_rx) = osc::input::spawn(osc_receiver); + println!("spawned osc input thread"); // Spawn the OSC output thread. let (_osc_out_thread_handle, osc_out_msg_tx, osc_out_log_rx) = osc::output::spawn(); + println!("spawned osc output thread"); // A channel for sending active sound info from the audio thread to the GUI. let app_proxy = app.create_proxy(); let (audio_monitor, audio_monitor_tx, audio_monitor_rx) = gui::monitor::spawn(app_proxy).expect("failed to spawn audio_monitor thread"); + println!("Spawned gui audio_monitor thread"); // Spawn the thread used for reading wavs. let wav_reader = audio::source::wav::reader::spawn(); + println!("spawned wav file reader"); // A channel for sending and receiving on the soundscape thread. let (soundscape_tx, soundscape_rx) = mpsc::channel(); + println!("created soundscape mpsc channel"); // The playhead frame count shared between GUI, soundscape and audio output thread for // synchronising continuous WAV soures. let frame_count = Arc::new(AtomicUsize::new(0)); + println!("made a frame_count Arc"); // Retrieve the audio host. let audio_host = audio::host(); + println!("retrieved the audio host"); // Initialise the audio input model and create the input stream. let input_device = audio::find_input_device(&audio_host, &config.target_input_device_name) @@ -113,6 +123,7 @@ fn model(app: &App) -> Model { .device(input_device) .build() .expect("failed to build audio input stream"); + println!("created audio input stream"); // Initialise the audio output model and create the output stream. let output_device = audio::find_output_device(&audio_host, &config.target_output_device_name) @@ -136,10 +147,12 @@ fn model(app: &App) -> Model { .device(output_device) .build() .expect("failed to build audio output stream"); + println!("created audio output stream"); // To be shared between the `Composer` and `GUI` threads as both are responsible for creating // sounds and sending them to the audio thread. let sound_id_gen = audio::sound::IdGenerator::new(); + println!("created shared sound id generator"); // Spawn the composer thread. let soundscape = soundscape::spawn( @@ -152,6 +165,7 @@ fn model(app: &App) -> Model { audio_output_stream.clone(), sound_id_gen.clone(), ); + println!("spawned soundscape thread"); // Create a window. let window = app @@ -160,6 +174,7 @@ fn model(app: &App) -> Model { .size(config.window_width, config.window_height) .build() .expect("failed to create window"); + println!("created window"); // Initalise the GUI model. let gui_channels = gui::Channels::new( @@ -184,6 +199,7 @@ fn model(app: &App) -> Model { audio_input_channels, audio_output_channels, ); + println!("initialised the gui model"); // Now that everything is initialized, kick off the input and output streams. // @@ -196,6 +212,7 @@ fn model(app: &App) -> Model { if let Err(err) = audio_output_stream.play() { eprintln!("Failed to start playing the audio output stream: {}", err); } + println!("Started the audio input and audio output streams"); Model { soundscape, diff --git a/src/lib/soundscape/mod.rs b/src/lib/soundscape/mod.rs index ce0d466..596a89f 100644 --- a/src/lib/soundscape/mod.rs +++ b/src/lib/soundscape/mod.rs @@ -185,7 +185,7 @@ pub struct Model { /// A handle for submitting new sounds to the output stream. audio_output_stream: audio::output::Stream, // A handle to the ticker thread. - _tick_thread: thread::JoinHandle<()>, + tick_thread: thread::JoinHandle<()>, } // Data related to the suitability of a group or source for selection of use within the soundscape. @@ -672,7 +672,7 @@ pub fn spawn( frame_count: Arc, seed: Seed, tx: mpsc::Sender, - _rx: mpsc::Receiver, + rx: mpsc::Receiver, wav_reader: audio::source::wav::reader::Handle, audio_input_stream: audio::input::Stream, audio_output_stream: audio::output::Stream, @@ -683,7 +683,7 @@ pub fn spawn( // Spawn a thread to generate and send ticks. let tick_tx = tx.clone(); let tick_is_playing = is_playing.clone(); - let _tick_thread = thread::Builder::new() + let tick_thread = thread::Builder::new() .name("soundscape_ticker".into()) .spawn(move || { let mut last = time::Instant::now(); @@ -726,7 +726,7 @@ pub fn spawn( let active_sounds_per_installation = Default::default(); let available_groups = Default::default(); let available_sources = Default::default(); - let _model = Model { + let model = Model { frame_count, realtime_source_latency, seed, @@ -749,16 +749,16 @@ pub fn spawn( audio_input_stream, audio_output_stream, sound_id_gen, - _tick_thread, + tick_thread, }; // Spawn the soundscape thread. /* let thread = thread::Builder::new() .name("soundscape".into()) - .spawn(move || run(model, rx)) + .spawn(|| run(model, rx)) .unwrap(); - // */ + */ let thread = Arc::new(Mutex::new(None)); Soundscape { tx, @@ -768,7 +768,7 @@ pub fn spawn( } // A blocking function that is run on the unique soundscape thread (called by spawn). -fn run(mut model: Model, msg_rx: mpsc::Receiver) { +pub fn run(mut model: Model, msg_rx: mpsc::Receiver) { // Wait for messages. for msg in msg_rx { match msg { From c3f69c8c272ae4f569674ba990fa6a67120ebdca Mon Sep 17 00:00:00 2001 From: "Ando \"Thor\" Nando" Date: Tue, 21 Jun 2022 14:37:14 +1000 Subject: [PATCH 8/8] chore: misc --- Cargo.lock | 140 +++++++++++++++-------------- src/lib/audio/output.rs | 1 + src/lib/audio/sound.rs | 1 + src/lib/audio/source/mod.rs | 2 + src/lib/audio/source/realtime.rs | 1 + src/lib/audio/source/wav/reader.rs | 3 +- src/lib/gui/mod.rs | 11 ++- 7 files changed, 88 insertions(+), 71 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5de27c9..ed7f2c2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -202,8 +202,8 @@ dependencies = [ "lazy_static", "lazycell", "peeking_take_while", - "proc-macro2 1.0.39", - "quote 1.0.18", + "proc-macro2 1.0.40", + "quote 1.0.20", "regex", "rustc-hash", "shlex", @@ -225,8 +225,8 @@ dependencies = [ "lazycell", "log", "peeking_take_while", - "proc-macro2 1.0.39", - "quote 1.0.18", + "proc-macro2 1.0.40", + "quote 1.0.20", "regex", "rustc-hash", "shlex", @@ -450,8 +450,8 @@ version = "0.76.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eda5e9d04f37818a74dcd4789b6de3f35c11b752509175352bc4ca19af07e511" dependencies = [ - "proc-macro2 1.0.39", - "quote 1.0.18", + "proc-macro2 1.0.40", + "quote 1.0.20", "syn", ] @@ -638,19 +638,19 @@ dependencies = [ "cfg-if 1.0.0", "crossbeam-channel", "crossbeam-deque 0.8.1", - "crossbeam-epoch 0.9.8", + "crossbeam-epoch 0.9.9", "crossbeam-queue", - "crossbeam-utils 0.8.8", + "crossbeam-utils 0.8.9", ] [[package]] name = "crossbeam-channel" -version = "0.5.4" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aaa7bd5fb665c6864b5f963dd9097905c54125909c7aa94c9e18507cdbe6c53" +checksum = "4c02a4d71819009c192cf4872265391563fd6a84c81ff2c0f2a7026ca4c1d85c" dependencies = [ "cfg-if 1.0.0", - "crossbeam-utils 0.8.8", + "crossbeam-utils 0.8.9", ] [[package]] @@ -671,8 +671,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e" dependencies = [ "cfg-if 1.0.0", - "crossbeam-epoch 0.9.8", - "crossbeam-utils 0.8.8", + "crossbeam-epoch 0.9.9", + "crossbeam-utils 0.8.9", ] [[package]] @@ -692,15 +692,15 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.8" +version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1145cf131a2c6ba0615079ab6a638f7e1973ac9c2634fcbeaaad6114246efe8c" +checksum = "07db9d94cbd326813772c968ccd25999e5f8ae22f4f8d1b11effa37ef6ce281d" dependencies = [ "autocfg", "cfg-if 1.0.0", - "crossbeam-utils 0.8.8", - "lazy_static", + "crossbeam-utils 0.8.9", "memoffset 0.6.5", + "once_cell", "scopeguard", ] @@ -711,7 +711,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f25d8400f4a7a5778f0e4e52384a48cbd9b5c495d110786187fc750075277a2" dependencies = [ "cfg-if 1.0.0", - "crossbeam-utils 0.8.8", + "crossbeam-utils 0.8.9", ] [[package]] @@ -727,12 +727,12 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.8" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38" +checksum = "8ff1f980957787286a554052d03c7aee98d99cc32e09f6d45f0a814133c87978" dependencies = [ "cfg-if 1.0.0", - "lazy_static", + "once_cell", ] [[package]] @@ -795,8 +795,8 @@ checksum = "f0c960ae2da4de88a91b2d920c2a7233b400bc33cb28453a2987822d8392519b" dependencies = [ "fnv", "ident_case", - "proc-macro2 1.0.39", - "quote 1.0.18", + "proc-macro2 1.0.40", + "quote 1.0.20", "strsim 0.9.3", "syn", ] @@ -809,8 +809,8 @@ checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610" dependencies = [ "fnv", "ident_case", - "proc-macro2 1.0.39", - "quote 1.0.18", + "proc-macro2 1.0.40", + "quote 1.0.20", "strsim 0.10.0", "syn", ] @@ -822,7 +822,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9b5a2f4ac4969822c62224815d069952656cadc7084fdca9751e6d959189b72" dependencies = [ "darling_core 0.10.2", - "quote 1.0.18", + "quote 1.0.20", "syn", ] @@ -833,7 +833,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835" dependencies = [ "darling_core 0.13.4", - "quote 1.0.18", + "quote 1.0.20", "syn", ] @@ -1153,8 +1153,8 @@ version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33c1e13800337f4d4d7a316bf45a567dbcb6ffe087f16424852d97e97a91f512" dependencies = [ - "proc-macro2 1.0.39", - "quote 1.0.18", + "proc-macro2 1.0.40", + "quote 1.0.20", "syn", ] @@ -1285,7 +1285,7 @@ checksum = "a538f217be4d405ff4719a283ca68323cc2384003eca5baaa87501e821c81dda" dependencies = [ "bitflags", "gpu-descriptor-types", - "hashbrown", + "hashbrown 0.11.2", ] [[package]] @@ -1306,6 +1306,12 @@ dependencies = [ "ahash", ] +[[package]] +name = "hashbrown" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db0d4cf898abf0081f964436dc980e96670a0f36863e4b83aaacdb65c9d7ccc3" + [[package]] name = "hermit-abi" version = "0.1.19" @@ -1363,12 +1369,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "1.8.2" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6012d540c5baa3589337a98ce73408de9b5a25ec9fc2c6fd6be8f0d39e0ca5a" +checksum = "6c6392766afd7964e2531940894cffe4bd8d7d17dbc3c1c4857040fd4b33bdb3" dependencies = [ "autocfg", - "hashbrown", + "hashbrown 0.12.1", ] [[package]] @@ -1917,8 +1923,8 @@ checksum = "05d1c6307dc424d0f65b9b06e94f88248e6305726b14729fd67a5e47b2dc481d" dependencies = [ "darling 0.10.2", "proc-macro-crate 0.1.5", - "proc-macro2 1.0.39", - "quote 1.0.18", + "proc-macro2 1.0.40", + "quote 1.0.20", "syn", ] @@ -1930,8 +1936,8 @@ checksum = "0df7ac00c4672f9d5aece54ee3347520b7e20f158656c7db2e6de01902eb7a6c" dependencies = [ "darling 0.13.4", "proc-macro-crate 1.1.3", - "proc-macro2 1.0.39", - "quote 1.0.18", + "proc-macro2 1.0.40", + "quote 1.0.20", "syn", ] @@ -2127,9 +2133,9 @@ dependencies = [ [[package]] name = "num-complex" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97fbc387afefefd5e9e39493299f3069e14a140dd34dc19b4c1c1a8fddb6a790" +checksum = "7ae39348c8bc5fbd7f40c727a9925f03517afd2ab27d46702108b6a7e5414c19" dependencies = [ "num-traits", ] @@ -2140,8 +2146,8 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" dependencies = [ - "proc-macro2 1.0.39", - "quote 1.0.18", + "proc-macro2 1.0.40", + "quote 1.0.20", "syn", ] @@ -2225,8 +2231,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b0498641e53dd6ac1a4f22547548caa6864cc4933784319cd1775271c5a46ce" dependencies = [ "proc-macro-crate 1.1.3", - "proc-macro2 1.0.39", - "quote 1.0.18", + "proc-macro2 1.0.40", + "quote 1.0.20", "syn", ] @@ -2334,8 +2340,8 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b4b5f600e60dd3a147fb57b4547033d382d1979eb087af310e91cb45a63b1f4" dependencies = [ - "proc-macro2 1.0.39", - "quote 1.0.18", + "proc-macro2 1.0.40", + "quote 1.0.20", "syn", ] @@ -2506,9 +2512,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.39" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c54b25569025b7fc9651de43004ae593a75ad88543b17178aa5e1b9c4f15f56f" +checksum = "dd96a1e8ed2596c337f8eae5f24924ec83f5ad5ab21ea8e455d3566c69fbcaf7" dependencies = [ "unicode-ident", ] @@ -2545,11 +2551,11 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.18" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" +checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804" dependencies = [ - "proc-macro2 1.0.39", + "proc-macro2 1.0.40", ] [[package]] @@ -2724,7 +2730,7 @@ checksum = "258bcdb5ac6dad48491bb2992db6b7cf74878b0384908af124823d118c99683f" dependencies = [ "crossbeam-channel", "crossbeam-deque 0.8.1", - "crossbeam-utils 0.8.8", + "crossbeam-utils 0.8.9", "num_cpus", ] @@ -2816,7 +2822,7 @@ version = "6.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1d089e5c57521629a59f5f39bca7434849ff89bd6873b521afe389c1c602543" dependencies = [ - "num-complex 0.4.1", + "num-complex 0.4.2", "num-integer", "num-traits", "primal-check", @@ -2913,8 +2919,8 @@ version = "1.0.137" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f26faba0c3959972377d3b2d306ee9f71faee9714294e41bb777f83f88578be" dependencies = [ - "proc-macro2 1.0.39", - "quote 1.0.18", + "proc-macro2 1.0.40", + "quote 1.0.20", "syn", ] @@ -3070,12 +3076,12 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "syn" -version = "1.0.96" +version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0748dd251e24453cb8717f0354206b91557e4ec8703673a4b30208f2abaf1ebf" +checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd" dependencies = [ - "proc-macro2 1.0.39", - "quote 1.0.18", + "proc-macro2 1.0.40", + "quote 1.0.20", "unicode-ident", ] @@ -3112,8 +3118,8 @@ version = "1.0.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a" dependencies = [ - "proc-macro2 1.0.39", - "quote 1.0.18", + "proc-macro2 1.0.40", + "quote 1.0.20", "syn", ] @@ -3268,8 +3274,8 @@ dependencies = [ "bumpalo", "lazy_static", "log", - "proc-macro2 1.0.39", - "quote 1.0.18", + "proc-macro2 1.0.40", + "quote 1.0.20", "syn", "wasm-bindgen-shared", ] @@ -3292,7 +3298,7 @@ version = "0.2.81" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c441e177922bc58f1e12c022624b6216378e5febc2f0533e41ba443d505b80aa" dependencies = [ - "quote 1.0.18", + "quote 1.0.20", "wasm-bindgen-macro-support", ] @@ -3302,8 +3308,8 @@ version = "0.2.81" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7d94ac45fcf608c1f45ef53e748d35660f168490c10b23704c7779ab8f5c3048" dependencies = [ - "proc-macro2 1.0.39", - "quote 1.0.18", + "proc-macro2 1.0.40", + "quote 1.0.20", "syn", "wasm-bindgen-backend", "wasm-bindgen-shared", @@ -3420,8 +3426,8 @@ version = "0.28.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce923eb2deb61de332d1f356ec7b6bf37094dc5573952e1c8936db03b54c03f1" dependencies = [ - "proc-macro2 1.0.39", - "quote 1.0.18", + "proc-macro2 1.0.40", + "quote 1.0.20", "xml-rs", ] diff --git a/src/lib/audio/output.rs b/src/lib/audio/output.rs index 2b4d303..d989bff 100644 --- a/src/lib/audio/output.rs +++ b/src/lib/audio/output.rs @@ -34,6 +34,7 @@ type Channel = usize; type DbapSpeakerGains = FxHashMap>>; /// A sound that is currently active on the audio thread. +#[derive(Debug)] pub struct ActiveSound { sound: Sound, total_duration_frames: Option, diff --git a/src/lib/audio/sound.rs b/src/lib/audio/sound.rs index 6ce2fa1..048bbb5 100644 --- a/src/lib/audio/sound.rs +++ b/src/lib/audio/sound.rs @@ -16,6 +16,7 @@ type Point2 = nannou::glam::DVec2; /// 1. **Source**: for generating audio data (via oscillator, wave, audio input, etc). /// 2. **Pre-spatial effects processing**: E.g. fades. /// 3. **Spatial Output**: maps the sound from a position in space to the output channels. +#[derive(Debug)] pub struct Sound { // State shared with the handles. pub shared: Arc, diff --git a/src/lib/audio/source/mod.rs b/src/lib/audio/source/mod.rs index 4d8de28..82069bb 100644 --- a/src/lib/audio/source/mod.rs +++ b/src/lib/audio/source/mod.rs @@ -59,6 +59,7 @@ pub struct Source { /// A **Signal** yielding interleaved samples. /// /// **Signal**s are produced by **Source**s and played back on the output thread via **Sound**s. +#[derive(Debug)] pub struct Signal { pub kind: SignalKind, attack: Attack, @@ -72,6 +73,7 @@ pub struct Signal { /// The kind of the **Signal**. /// /// Indicates whether the signal is sourced from a `Wav` or `Realtime` source. +#[derive(Debug)] pub enum SignalKind { Wav { samples: wav::reader::SamplesStream, diff --git a/src/lib/audio/source/realtime.rs b/src/lib/audio/source/realtime.rs index ac73277..7dfd725 100644 --- a/src/lib/audio/source/realtime.rs +++ b/src/lib/audio/source/realtime.rs @@ -28,6 +28,7 @@ pub struct Realtime { /// /// Returns `None` as soon as the inner receiver either runs out of samples due to falling behind /// or if the channel is disconneceted as the sound has played out its duration. +#[derive(Debug)] pub struct Signal { pub buffer_rx: BufferRx, pub buffer_tx: BufferTx, diff --git a/src/lib/audio/source/wav/reader.rs b/src/lib/audio/source/wav/reader.rs index 4ffd80e..620e5e1 100644 --- a/src/lib/audio/source/wav/reader.rs +++ b/src/lib/audio/source/wav/reader.rs @@ -131,7 +131,7 @@ pub enum Message { /// /// When this buffer is depleted, the allocated `Vec` gets sent back to the reader thread for /// re-use. -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct Buffer { samples: Vec, sound_id: sound::Id, @@ -159,6 +159,7 @@ pub struct Play { } /// A handle to a WAV that receives the buffered samples for use on the audio thread. +#[derive(Debug)] pub struct SamplesStream { buffer_rx: BufferRx, buffer: RefCell>, diff --git a/src/lib/gui/mod.rs b/src/lib/gui/mod.rs index 54da3f6..7c20ab4 100644 --- a/src/lib/gui/mod.rs +++ b/src/lib/gui/mod.rs @@ -216,6 +216,7 @@ struct ChannelLevels { } /// A message sent from the audio thread with some audio levels. +#[derive(Debug)] pub enum AudioMonitorMessage { Master { peak: f32 }, ActiveSound(audio::sound::Id, ActiveSoundMessage), @@ -223,6 +224,7 @@ pub enum AudioMonitorMessage { } /// A message related to an active sound. +#[derive(Debug)] pub enum ActiveSoundMessage { Start { normalised_progress: Option, @@ -478,10 +480,12 @@ impl Model { // Update the map of active sounds. loop { + println!("audio active sounds loop entry"); let msg = match channels.audio_monitor_msg_rx.pop() { None => break, Some(msg) => msg, }; + println!("got some msg. {:?}", msg); match msg { AudioMonitorMessage::Master { peak } => { @@ -550,7 +554,7 @@ impl Model { } // Check that all active sounds are still valid in case the GUI switched the project. - match *project { + match project { Some((ref mut project, _)) => audio_monitor.clear_invalid(project), None => audio_monitor.clear(), } @@ -560,7 +564,8 @@ impl Model { // Check for `Ctrl+S` or `Cmd+S` for saving, or `Ctrl+Space` for cpu saving mode. for event in ui.global_input().events().ui() { - if let ui::event::Ui::Press(_, press) = *event { + println!("{:?}", event); + if let ui::event::Ui::Press(_, press) = event { match press.button { ui::event::Button::Keyboard(ui::input::Key::S) => { let save_mod = press @@ -570,7 +575,7 @@ impl Model { .modifiers .contains(ui::input::keyboard::ModifierKey::GUI); if save_mod { - if let Some((ref project, _)) = *project { + if let Some((ref project, _)) = project { project .save(assets) .expect("failed to save project on keyboard shortcut");