· 6 years ago · Sep 18, 2019, 08:22 PM
1use nannou::prelude::*;
2use nannou::geom::Point2;
3use nannou_audio as audio;
4use nannou_audio::Buffer;
5use std::f64::consts::PI;
6
7fn main() {
8 nannou::app(model)
9 .update(update)
10 .run();
11}
12
13struct Rectangle {
14 pos: Point2,
15 width: f32,
16 height: f32,
17 text: String,
18 color: ( f32, f32, f32 ),
19}
20impl Rectangle {
21 fn new(pos: Point2, width: f32, height: f32, text: String, color: ( f32, f32, f32 )) -> Rectangle {
22 Rectangle {
23 pos: pos,
24 width: width,
25 height: height,
26 text: text,
27 color: color,
28 }
29 }
30}
31
32struct GridCell {
33 note: i32,
34 rect: Rectangle,
35
36}
37
38struct Model {
39 // Store the window ID so we can refer to this specific window later if needed.
40 _window: WindowId,
41 rects: Vec<Rectangle>,
42 stream: audio::Stream<Audio>,
43}
44
45struct Audio {
46 phase: f64,
47 hz: f64,
48}
49
50fn model(app: &App) -> Model {
51 let physical_device = best_gpu(app).expect("no available GPU detected on system");
52 println!("Physical device: {}", physical_device.name());
53 let _window = app
54 .new_window()
55 .key_pressed(key_pressed)
56 .event(event)
57 .vk_physical_device(physical_device)
58 .view(view)
59 .build()
60 .expect("failed to build window");
61
62 // Initialise the audio API so we can spawn an audio stream.
63 let audio_host = audio::Host::new();
64 // Initialise the state that we want to live on the audio thread.
65 let model = Audio {
66 phase: 0.0,
67 hz: 440.0,
68 };
69 let stream = audio_host
70 .new_output_stream(model)
71 .render(audio)
72 .build()
73 .unwrap();
74 Model { _window, rects: vec![], stream }
75}
76
77fn update(_app: &App, _model: &mut Model, _update: Update) {
78}
79
80fn view(app: &App, model: &Model, frame: &Frame){
81 // Begin drawing
82 let draw = app.draw();
83
84 // Clear the background to blue.
85 draw.background().color(CORNFLOWERBLUE);
86
87 for rect in &model.rects {
88 draw.rect()
89 .xy(rect.pos)
90 .w(rect.width)
91 .h(rect.height)
92 .rgb(rect.color.0, rect.color.1, rect.color.2 );
93 draw.text(rect.text.as_str())
94 .x(rect.pos.x)
95 .y(rect.pos.y)
96 .rgb(0., 1., 0.);
97 }
98
99 draw.text("hello you sloppy jalopy").x(100.0).y(-1000000.0);
100
101 // Write the result of our drawing to the window's frame.
102 draw.to_frame(app, &frame).unwrap();
103
104}
105
106// We can also update the application based on events received by the window like key presses and
107// mouse movement here.
108fn event(app: &App, model: &mut Model, event: WindowEvent) {
109 // Print events as they occur to the console
110 // println!("{:?}", event);
111
112 // We can `match` on the event to do something different depending on the kind of event.
113 match event {
114 // Keyboard events
115 KeyPressed(_key) => {}
116 KeyReleased(_key) => {}
117
118 // Mouse events
119 MouseMoved(_pos) => {}
120 MousePressed(_button) => {
121 model.rects.push(Rectangle::new(Point2::new(app.mouse.x, app.mouse.y), 100.0, 100.0, "Lbl".to_owned(), (1.0, 0.2, 0.0)));
122 }
123 MouseReleased(_button) => {}
124 MouseWheel(_amount, _phase) => {}
125 MouseEntered => {}
126 MouseExited => {}
127
128 // Touch events
129 Touch(_touch) => {}
130 TouchPressure(_pressure) => {}
131
132 // Window events
133 Moved(_pos) => {}
134 Resized(_size) => {}
135 HoveredFile(_path) => {}
136 DroppedFile(_path) => {}
137 HoveredFileCancelled => {}
138 Focused => {}
139 Unfocused => {}
140 Closed => {}
141 }
142}
143
144fn key_pressed(_app: &App, model: &mut Model, key: Key) {
145 match key {
146 // Pause or unpause the audio when Space is pressed.
147 Key::Space => {
148 if model.stream.is_playing() {
149 model.stream.pause().unwrap();
150 } else {
151 model.stream.play().unwrap();
152 }
153 }
154 // Raise the frequency when the up key is pressed.
155 Key::Up => {
156 model
157 .stream
158 .send(|audio| {
159 audio.hz += 10.0;
160 })
161 .unwrap();
162 }
163 // Lower the frequency when the down key is pressed.
164 Key::Down => {
165 model
166 .stream
167 .send(|audio| {
168 audio.hz -= 10.0;
169 })
170 .unwrap();
171 }
172 _ => {}
173 }
174}
175
176// Return a dedicated GPU device if there is one.
177fn find_discrete_gpu<'a, I>(devices: I) -> Option<vk::PhysicalDevice<'a>>
178where
179 I: IntoIterator<Item = vk::PhysicalDevice<'a>>,
180{
181 devices
182 .into_iter()
183 .find(|d| d.ty() == vk::PhysicalDeviceType::DiscreteGpu)
184}
185
186/// Select the best GPU from those available.
187pub fn best_gpu(app: &App) -> Option<vk::PhysicalDevice> {
188 find_discrete_gpu(app.vk_physical_devices()).or_else(|| app.default_vk_physical_device())
189}
190
191// A function that renders the given `Audio` to the given `Buffer`.
192// In this case we play a simple sine wave at the audio's current frequency in `hz`.
193fn audio(audio: &mut Audio, buffer: &mut Buffer) {
194 let sample_rate = buffer.sample_rate() as f64;
195 let volume = 0.5;
196 for frame in buffer.frames_mut() {
197 let sine_amp = (2.0 * PI * audio.phase).sin() as f32;
198 audio.phase += audio.hz / sample_rate;
199 audio.phase %= sample_rate;
200 for channel in frame {
201 *channel = sine_amp * volume;
202 }
203 }
204}