1use std::sync::{
7 atomic::{AtomicBool, Ordering},
8 Arc,
9};
10
11use embedded_graphics::{
12 mono_font::{ascii::FONT_6X10, MonoTextStyle},
13 pixelcolor::BinaryColor,
14 prelude::*,
15 text::Text,
16};
17use embedded_graphics_simulator::{
18 sdl2::Keycode, OutputSettingsBuilder, SimulatorDisplay, SimulatorEvent, Window,
19};
20use sdl2::audio::{AudioCallback, AudioSpecDesired};
21
22const SAMPLE_RATE: i32 = 44100;
23
24const PITCH_MIN: f32 = 440.0;
25const PITCH_MAX: f32 = 10000.0;
26
27const PERIOD: f32 = 0.5; const SAMPLES_PER_PERIOD: f32 = SAMPLE_RATE as f32 * PERIOD;
29const PITCH_CHANGE_PER_SAMPLE: f32 = (PITCH_MAX - PITCH_MIN) / SAMPLES_PER_PERIOD;
30
31fn main() -> Result<(), core::convert::Infallible> {
32 let gate = Arc::new(AtomicBool::new(false));
34 let audio_wrapper = AudioWrapper::new(gate.clone());
35
36 let audio_spec = AudioSpecDesired {
37 freq: Some(SAMPLE_RATE),
38 channels: Some(1),
39 samples: Some(32),
40 };
41
42 let sdl = sdl2::init().unwrap();
49 let audio_subsystem = sdl.audio().unwrap();
50
51 let audio_device = audio_subsystem
53 .open_playback(None, &audio_spec, |_| audio_wrapper)
54 .unwrap();
55 audio_device.resume();
56
57 let output_settings = OutputSettingsBuilder::new()
58 .scale(4)
59 .theme(embedded_graphics_simulator::BinaryColorTheme::OledWhite)
60 .build();
61
62 let mut window = Window::new("Simulator audio example", &output_settings);
63
64 let text_style = MonoTextStyle::new(&FONT_6X10, BinaryColor::On);
65 let text_position = Point::new(25, 30);
66 let text = Text::new("Press space...", text_position, text_style);
67
68 let mut display: SimulatorDisplay<BinaryColor> = SimulatorDisplay::new(Size::new(128, 64));
69 text.draw(&mut display).unwrap();
70 'running: loop {
71 window.update(&display);
72
73 for event in window.events() {
74 match event {
75 SimulatorEvent::Quit => break 'running,
76 SimulatorEvent::KeyDown {
77 keycode, repeat, ..
78 } if keycode == Keycode::Space && !repeat => {
79 gate.store(true, Ordering::SeqCst);
80 display.clear(BinaryColor::On).unwrap();
81 }
82 SimulatorEvent::KeyUp { keycode, .. } => match keycode {
83 Keycode::Space => {
84 gate.store(false, Ordering::SeqCst);
85 display.clear(BinaryColor::Off).unwrap();
86 text.draw(&mut display).unwrap();
87 }
88 _ => {}
89 },
90 _ => {}
91 }
92 }
93 }
94
95 Ok(())
96}
97
98struct AudioWrapper {
99 gate: Arc<AtomicBool>,
100 phase: f32,
101 pitch: f32,
102}
103
104impl AudioWrapper {
105 fn new(gate: Arc<AtomicBool>) -> Self {
106 Self {
107 gate,
108 phase: 0.0,
109 pitch: PITCH_MIN,
110 }
111 }
112}
113
114impl AudioCallback for AudioWrapper {
115 type Channel = f32;
116
117 fn callback(&mut self, out: &mut [f32]) {
118 let gate = self.gate.load(Ordering::SeqCst);
119 if !gate {
120 self.pitch = PITCH_MIN;
121 out.fill(0.0);
122 return;
123 }
124
125 for x in out.iter_mut() {
126 self.phase += self.pitch / SAMPLE_RATE as f32;
127 *x = self.phase.sin();
128
129 if self.pitch > PITCH_MAX {
130 self.pitch = PITCH_MIN;
131 }
132
133 self.pitch += PITCH_CHANGE_PER_SAMPLE;
134 }
135 }
136}