1use anyhow::{anyhow, Context, Result};
2use crossbeam_channel::Receiver;
3use sdl2::event::{Event, WindowEvent};
4use sdl2::keyboard::Keycode;
5use tracing::{debug, error, warn};
6
7use crate::webgpu;
8use crate::{hsl, recorder, renderer, webgpu::Orientation};
9
10pub fn process_event_loop(
13 sdl_context: &sdl2::Sdl,
14 recv_processed: Receiver<Vec<f32>>,
15 orientation: Orientation,
16 fullscreen: bool,
17 scroll_rate: f32,
18 texture_width: usize,
19 mut rec: recorder::Recorder,
20 fourier_thread: std::thread::JoinHandle<()>,
21) -> Result<()> {
22 let icon_webp = include_bytes!("soundview.webp");
23 let icon_image = image::load_from_memory_with_format(icon_webp, image::ImageFormat::WebP)?;
24 let mut icon_bytes = icon_image
25 .as_rgba8()
26 .context("Unable to get RGBA data for icon")?
27 .to_vec();
28 let icon = sdl2::surface::Surface::from_data(
29 &mut icon_bytes,
30 icon_image.width(),
31 icon_image.height(),
32 sdl2::pixels::PixelFormatEnum::RGBA32.byte_size_of_pixels(icon_image.width() as usize)
33 as u32,
34 sdl2::pixels::PixelFormatEnum::RGBA32,
35 )
36 .map_err(|e| anyhow!(e))
37 .context("Failed to init application icon")?;
38
39 let mut window_builder =
40 sdl_context
41 .video()
42 .map_err(|e| anyhow!(e))?
43 .window("soundview", 1280, 720);
44 window_builder.position_centered().resizable().metal_view();
45 if fullscreen {
46 window_builder.fullscreen_desktop();
47 sdl_context.mouse().show_cursor(false);
48 }
49 let mut window = window_builder.build().map_err(|e| anyhow!(e))?;
50 window.set_minimum_size(100, 100).map_err(|e| anyhow!(e))?;
51 window.set_icon(icon);
52
53 let fourier_thread_rc = std::cell::RefCell::new(Some(fourier_thread));
54 let wgpu_state = pollster::block_on(webgpu::WgpuState::new(&window))?;
55 let hsl = hsl::HSL::new(wgpu_state.preferred_format, 50, 40);
56
57 let mut state = pollster::block_on(renderer::State::new(
58 wgpu_state,
59 hsl,
60 recv_processed,
61 orientation,
62 scroll_rate,
63 texture_width,
64 ));
65
66 let mut event_pump = sdl_context.event_pump().map_err(|e| anyhow!(e))?;
67 loop {
68 for event in event_pump.poll_iter() {
70 match event {
71 Event::Quit { .. } => {
73 shut_down(&mut rec, &fourier_thread_rc);
74 return Ok(());
75 }
76
77 Event::Window {
78 window_id,
79 win_event: WindowEvent::SizeChanged(width, height),
80 ..
81 } if window_id == window.id() => {
82 state.resize(Some(webgpu::Dimensions {
83 width: width as usize,
84 height: height as usize,
85 }));
86 }
87
88 Event::KeyDown {
89 keycode: Some(keycode),
90 ..
91 } => match keycode {
92 Keycode::Escape | Keycode::Q => {
94 shut_down(&mut rec, &fourier_thread_rc);
95 return Ok(());
96 }
97 Keycode::F11 | Keycode::F => {
99 if window.fullscreen_state() == sdl2::video::FullscreenType::Off {
100 if let Err(e) =
102 window.set_fullscreen(sdl2::video::FullscreenType::Desktop)
103 {
104 warn!("Failed to enable fullscreen: {}", e);
105 }
106 sdl_context.mouse().show_cursor(false);
107 } else {
108 if let Err(e) = window.set_fullscreen(sdl2::video::FullscreenType::Off)
110 {
111 warn!("Failed to disable fullscreen: {}", e);
112 }
113 sdl_context.mouse().show_cursor(true);
114 }
115 }
116 Keycode::Space | Keycode::R => {
118 state.toggle_orientation();
119 }
120 Keycode::Left => {
122 if let Err(e) = rec.prev_device() {
124 warn!("Failed to switch to previous device: {}", e)
125 }
126 }
127 Keycode::Right => {
129 if let Err(e) = rec.next_device() {
131 warn!("Failed to switch to next device: {}", e)
132 }
133 }
134 _ => {}
136 },
137
138 _ => {}
140 }
141 }
142
143 match state.surface_texture() {
145 Ok(output) => {
146 if let Err(e) = state.render(output) {
147 error!("shutting down: render error {}", e);
148 shut_down(&mut rec, &fourier_thread_rc);
149 return Ok(());
150 }
151 }
152 Err(wgpu::SurfaceError::Lost) => state.resize(None),
154 Err(wgpu::SurfaceError::OutOfMemory) => {
156 error!("shutting down: wgpu is out of memory");
159 rec.stop();
160 match fourier_thread_rc.replace(None) {
161 Some(fourier_thread) => {
162 if let Err(e) = fourier_thread.join() {
163 warn!("failed to wait on fourier thread to exit: {:?}", e);
164 }
165 }
166 None => {} }
168 return Ok(());
169 }
170 Err(e) => debug!("render error: {:?}", e),
173 }
174 }
175}
176
177fn shut_down(
180 rec: &mut recorder::Recorder,
181 fourier_thread_rc: &std::cell::RefCell<Option<std::thread::JoinHandle<()>>>,
182) {
183 debug!("shutting down");
184 rec.stop();
185 match fourier_thread_rc.replace(None) {
186 Some(fourier_thread) => {
187 if let Err(e) = fourier_thread.join() {
188 warn!("failed to wait on fourier thread to exit: {:?}", e);
189 }
190 }
191 None => {} }
193}