A basic oscilloscope, using the audio data from the triple buffer node.
(&mut self, ui: &mut Ui)
| 26 | |
| 27 | // A basic oscilloscope, using the audio data from the triple buffer node. |
| 28 | fn draw_oscilloscope(&mut self, ui: &mut Ui) { |
| 29 | const NUM_POINTS: usize = 200; |
| 30 | |
| 31 | let size = ui.available_size(); |
| 32 | let (_id, rect) = ui.allocate_space(size); |
| 33 | |
| 34 | let mut output = self.audio_system.triple_buffer_state.output(); |
| 35 | let Some(data) = output.data() else { |
| 36 | return; |
| 37 | }; |
| 38 | let frames = data.frames; |
| 39 | |
| 40 | let mut left_rect = rect; |
| 41 | left_rect.set_height(left_rect.height() / 2.0); |
| 42 | let mut right_rect = left_rect; |
| 43 | right_rect = right_rect.translate(vec2(0.0, left_rect.height())); |
| 44 | |
| 45 | let to_left_rect = |
| 46 | RectTransform::from_to(Rect::from_x_y_ranges(0.0..=1.0, -1.0..=1.0), left_rect); |
| 47 | let to_right_rect = |
| 48 | RectTransform::from_to(Rect::from_x_y_ranges(0.0..=1.0, -1.0..=1.0), right_rect); |
| 49 | |
| 50 | let build_points = |audio_data: &[f32], rect_transform: RectTransform| -> Vec<Pos2> { |
| 51 | (0..NUM_POINTS) |
| 52 | .map(|i| { |
| 53 | let x = i as f32 / NUM_POINTS as f32; |
| 54 | |
| 55 | let pos = x * frames as f32; |
| 56 | let index = pos.floor() as usize; |
| 57 | let fract_index = pos.fract(); |
| 58 | |
| 59 | let s0 = audio_data.get(index).copied().unwrap_or(0.0); |
| 60 | let s1 = audio_data.get(index + 1).copied().unwrap_or(0.0); |
| 61 | |
| 62 | let value = s0 + ((s1 - s0) * fract_index); |
| 63 | |
| 64 | // Apply a windowing function to make the oscilloscope look |
| 65 | // "more interesting". |
| 66 | let y = value * (x * PI).sin(); |
| 67 | |
| 68 | rect_transform * pos2(x, y) |
| 69 | }) |
| 70 | .collect() |
| 71 | }; |
| 72 | |
| 73 | let left_points = build_points(data.buffer.channel_slice(0).unwrap(), to_left_rect); |
| 74 | let right_points = build_points(data.buffer.channel_slice(1).unwrap(), to_right_rect); |
| 75 | |
| 76 | let color = if ui.style().visuals.dark_mode { |
| 77 | egui::Color32::GREEN |
| 78 | } else { |
| 79 | egui::Color32::DARK_GREEN |
| 80 | }; |
| 81 | |
| 82 | ui.painter().extend([ |
| 83 | epaint::Shape::line(left_points, PathStroke::new(2.0f32, color)), |
| 84 | epaint::Shape::line(right_points, PathStroke::new(2.0f32, color)), |
| 85 | ]); |