pub struct Audio { /* private fields */ }Expand description
The audio system. Reach it through ctx.audio.
Implementations§
Source§impl Audio
impl Audio
Sourcepub fn silent(sound_dir: impl Into<PathBuf>) -> Self
pub fn silent(sound_dir: impl Into<PathBuf>) -> Self
An audio system without an output device. Everything works, nothing is heard.
Sourcepub fn sample_rate(&self) -> u32
pub fn sample_rate(&self) -> u32
Sample rate of the output device in Hz.
Sourcepub fn has_output(&self) -> bool
pub fn has_output(&self) -> bool
Whether an output device is open (false means sounds are silently ignored).
Sourcepub fn set_sound_dir(&mut self, dir: impl Into<PathBuf>)
pub fn set_sound_dir(&mut self, dir: impl Into<PathBuf>)
Changes the directory searched for sounds. See the module docs.
Sourcepub fn preload(&mut self, name: &str) -> Result<()>
pub fn preload(&mut self, name: &str) -> Result<()>
Loads a sound into the cache now, so the first play has no delay.
Sourcepub fn preload_dir(&mut self, dir: impl AsRef<Path>) -> Result<usize>
pub fn preload_dir(&mut self, dir: impl AsRef<Path>) -> Result<usize>
Loads every sound file found in dir (not recursive). Names are the file paths
relative to the sound directory without extension, e.g. "step".
Returns how many files were loaded.
Sourcepub fn register(&mut self, name: impl Into<String>, data: impl Into<SoundData>)
pub fn register(&mut self, name: impl Into<String>, data: impl Into<SoundData>)
Registers sound data generated in code (or a Synth) under a name, so it can be
played like a file. Registering the same name again replaces the sound.
ctx.audio.register("beep", SoundData::tone(880.0, 0.1, 0.5));
ctx.audio.play("beep");Examples found in repository?
22fn main() -> audio_code::Result<()> {
23 Engine::new("Bell Catcher").run_with(|ctx| {
24 ctx.audio.register("bell", Synth::sine(1568.0).with(Synth::sine(3136.0).volume(0.3)).length(0.35).decay(9.0).volume(0.6));
25 ctx.audio.register("step", Synth::noise().length(0.05).decay(80.0).volume(0.5));
26 ctx.audio.register("edge", Synth::sine(110.0).length(0.12).decay(30.0).volume(0.8));
27 ctx.audio.register(
28 "catch",
29 Synth::sine(784.0).length(0.08).then(Synth::sine(1047.0).length(0.08)).then(Synth::sine(1568.0).length(0.2).decay(12.0)).volume(0.4),
30 );
31 ctx.audio.register("miss", Synth::saw(220.0).sweep_to(80.0).length(0.5).decay(5.0).volume(0.35));
32
33 // Restore the speech settings from the last session.
34 if let Some(voice) = ctx.storage.get::<String>("voice") {
35 ctx.speech.set_voice(voice);
36 }
37 let rate: f32 = ctx.storage.get_or("rate", 50.0);
38 if rate != 50.0 {
39 ctx.speech.set_rate(rate / 100.0);
40 }
41 Title
42 })
43}More examples
32 fn new(ctx: &mut Context) -> Self {
33 ctx.audio.register("step", Synth::noise().length(0.08).decay(60.0));
34 ctx.audio.register("wall", Synth::sine(90.0).length(0.15).decay(25.0).volume(0.8));
35 ctx.audio.register("beacon", Synth::sine(1320.0).length(0.08).then(Synth::silence(0.04)).then(Synth::sine(1320.0).length(0.08)).then(Synth::silence(0.8)));
36 ctx.audio.register("found", Synth::sine(440.0).sweep_to(1200.0).length(0.6).decay(4.0).volume(0.3));
37
38 // Every character is a 2 meter tile: walls, the player start and three beacons.
39 let level = ctx.physics.build_level(MAP, 2.0);
40 let player = ctx.physics.add(Body::kinematic(level.point('P').unwrap()).with_sphere(0.4).with_tag("player"));
41 ctx.follow(player); // the ears go wherever the player goes and face where it faces
42
43 let mut beacons = Vec::new();
44 for spot in level.points('B') {
45 let beacon = ctx.physics.add(Body::sensor(spot).with_sphere(0.8).with_tag("beacon"));
46 ctx.loop_on(beacon, "beacon"); // stops by itself when the beacon is removed
47 beacons.push(beacon);
48 }
49 Self { player, beacons, clock: Timer::new() }
50 }31 fn new(ctx: &mut Context) -> Self {
32 ctx.audio.register("bird", Synth::sine(2200.0).sweep_to(3200.0).length(0.07).then(Synth::silence(0.05)).then(Synth::sine(2600.0).length(0.06)).then(Synth::silence(0.7)));
33 ctx.audio.register("hum", Synth::saw(70.0).length(1.0).volume(0.08));
34 ctx.audio.register("bump", Synth::sine(80.0).length(0.15).decay(25.0).volume(0.8));
35 ctx.audio.register("found", Synth::triangle(660.0).sweep_to(1320.0).length(0.4).decay(6.0).volume(0.3));
36
37 // A hall of 40 x 40 meters and 16 meters high: floor, roof and four walls.
38 // A box is given by its center and its full width (x), depth (y) and height (z).
39 let physics = &mut ctx.physics;
40 physics.add(Body::fixed(vec3(0.0, 0.0, -0.5)).with_box(40.0, 40.0, 1.0).with_tag("floor"));
41 physics.add(Body::fixed(vec3(0.0, 0.0, 16.5)).with_box(40.0, 40.0, 1.0).with_tag("roof"));
42 physics.add(Body::fixed(vec3(0.0, 20.5, 8.0)).with_box(40.0, 1.0, 16.0).with_tag("north wall"));
43 physics.add(Body::fixed(vec3(0.0, -20.5, 8.0)).with_box(40.0, 1.0, 16.0).with_tag("south wall"));
44 physics.add(Body::fixed(vec3(20.5, 0.0, 8.0)).with_box(1.0, 40.0, 16.0).with_tag("east wall"));
45 physics.add(Body::fixed(vec3(-20.5, 0.0, 8.0)).with_box(1.0, 40.0, 16.0).with_tag("west wall"));
46
47 // The drone starts in the middle, 2 meters above the floor. No gravity: it hovers.
48 let drone = ctx.physics.add(Body::kinematic(vec3(0.0, 0.0, 2.0)).with_sphere(0.5).with_tag("drone"));
49 ctx.follow(drone); // the ears use the drone's position, facing and pitch
50 ctx.audio.play_looped("hum");
51
52 for spot in BIRDS {
53 let bird = ctx.physics.add(Body::sensor(spot).with_sphere(1.0).with_tag("bird"));
54 ctx.loop_on(bird, "bird");
55 }
56 Self { drone, birds: BIRDS.len(), blocked: false }
57 }29 fn new(ctx: &mut Context) -> Self {
30 // Engine: a low buzz that loops without clicks (whole cycles, no fades).
31 let engine = Synth::saw(55.0).length(1.0).attack(0.0).release(0.0).volume(0.25)
32 .with(Synth::square(110.0).length(1.0).attack(0.0).release(0.0).volume(0.08));
33 ctx.audio.register("engine", engine);
34 ctx.audio.register("horn", Synth::square(415.0).length(0.5).volume(0.25).with(Synth::square(523.0).length(0.5).volume(0.2)));
35 ctx.audio.register("shift", Synth::noise().length(0.04).decay(90.0).volume(0.3));
36 ctx.audio.register("crash", Synth::noise().length(0.4).decay(10.0).volume(0.8).with(Synth::sine(80.0).sweep_to(30.0).length(0.3)));
37 ctx.audio.register("start", Synth::saw(40.0).sweep_to(55.0).length(0.6).volume(0.3));
38 ctx.audio.register("garage", Synth::sine(880.0).length(0.15).decay(10.0));
39
40 let level = ctx.physics.build_level(MAP, 6.0);
41 let sounds = |v: Vehicle| {
42 v.with_engine_sound("engine")
43 .with_horn_sound("horn")
44 .with_shift_sound("shift")
45 .with_crash_sound("crash")
46 .with_start_sound("start")
47 };
48 let car_start = level.point('P').unwrap_or(Vec3::ZERO);
49 let car = ctx.physics.add(Body::car(car_start).with_facing(90.0).with_vehicle(sounds(Vehicle::car().with_fuel(5.0, 8.0))));
50 let truck_start = level.point('T').unwrap_or(Vec3::ZERO);
51 let truck = ctx.physics.add(
52 Body::truck(truck_start).with_facing(90.0).with_vehicle(sounds(Vehicle::truck()).engine_off()),
53 );
54 let garage_at = level.point('G').unwrap_or(Vec3::ZERO);
55 let garage = ctx.physics.add(Body::sensor(garage_at).with_box(6.0, 6.0, 3.0).with_tag("garage"));
56 ctx.loop_on(garage, "garage");
57 ctx.follow(car);
58 Self { car, truck, driving: car, garage }
59 }19 fn new(ctx: &mut Context) -> Self {
20 let audio = &mut ctx.audio;
21 audio.register("jump", Synth::square(300.0).sweep_to(700.0).length(0.15).decay(10.0).volume(0.2));
22 audio.register("land", Synth::noise().length(0.1).decay(40.0).with(Synth::sine(90.0).length(0.1).decay(30.0)));
23 audio.register("coin", Synth::triangle(988.0).length(0.08).then(Synth::triangle(1319.0).length(0.17).decay(15.0)));
24 audio.register("run", Synth::noise().length(0.06).decay(60.0).volume(0.3).then(Synth::silence(0.09)));
25 audio.register("lift", Synth::saw(55.0).length(1.0).volume(0.1));
26 audio.register("push", Synth::noise().length(0.3).volume(0.15));
27
28 let physics = &mut ctx.physics;
29 physics.add(Body::fixed(vec3(0.0, 0.0, -0.5)).with_box(200.0, 4.0, 1.0).with_tag("ground"));
30 for (x, z) in [(8.0, 2.0), (14.0, 4.0), (20.0, 2.5)] {
31 physics.add(Body::fixed(vec3(x, 0.0, z)).with_box(4.0, 4.0, 0.5).with_tag("platform"));
32 }
33 // A lift going up and down at x = 40, and a heavy crate at x = 30.
34 let lift = physics.add(Body::kinematic(vec3(40.0, 0.0, 0.0)).with_box(3.0, 4.0, 0.5).with_tag("lift"));
35 physics.add(Body::dynamic(vec3(30.0, 0.0, 0.5)).with_box(1.0, 1.0, 1.0).with_mass(5.0).with_tag("crate"));
36 // Facing north, so x maps to left and right in the ears.
37 let player = physics
38 .add(Body::dynamic(vec3(0.0, 0.0, 1.0)).with_box(0.8, 0.8, 1.6).with_max_speed(25.0).with_tag("player"));
39
40 ctx.follow(player);
41 ctx.loop_on(lift, "lift");
42 // Coins are sensors with a looping sound, so you can hear where they are.
43 for (x, z) in [(5.0, 1.0), (14.0, 5.5), (25.0, 1.0), (40.0, 8.0)] {
44 let coin = ctx.physics.add(Body::sensor(vec3(x, 0.0, z)).with_sphere(0.6).with_tag("coin"));
45 ctx.loop_on(coin, "coin").set_volume(0.3);
46 }
47
48 let run_sound = ctx.audio.sound("run").looped().volume(0.0).play();
49 Self { player, lift, run_sound, score: 0 }
50 }Sourcepub fn is_loaded(&self, name: &str) -> bool
pub fn is_loaded(&self, name: &str) -> bool
Whether a sound with this name is loaded or registered.
Sourcepub fn unload(&mut self, name: &str)
pub fn unload(&mut self, name: &str)
Removes a sound from the cache to free memory. Playing sounds are not affected.
Sourcepub fn duration(&mut self, name: &str) -> Option<f32>
pub fn duration(&mut self, name: &str) -> Option<f32>
Length of a sound in seconds (loads it if needed).
Sourcepub fn sound(&mut self, name: &str) -> SoundBuilder<'_>
pub fn sound(&mut self, name: &str) -> SoundBuilder<'_>
Starts building a sound with full control over its settings. Finish with
SoundBuilder::play.
Examples found in repository?
179 fn ring(&mut self, ctx: &mut Context) {
180 // 0.0 when the bell starts falling, 1.0 when it lands.
181 let progress = 1.0 - self.left / self.fall;
182 let position = self.bell_position();
183 ctx.audio.sound("bell").at(position).pitch(1.0 + progress * 0.6).play();
184 self.next_ring = 0.12 + 0.45 * (1.0 - progress);
185 }
186
187 fn land(&mut self, ctx: &mut Context) {
188 if self.lane == self.bell_lane {
189 self.score += 1;
190 self.fall = (self.fall * 0.93).max(FASTEST_FALL);
191 ctx.play("catch");
192 if self.score.is_multiple_of(5) {
193 ctx.speak(format!("{} bells!", self.score));
194 }
195 } else {
196 self.lives -= 1;
197 ctx.play("miss");
198 match self.lives {
199 0 => return self.game_over(ctx),
200 1 => ctx.speak("Missed! Last life."),
201 n => ctx.speak(format!("Missed! {n} lives left.")),
202 }
203 }
204 // A short break before the next bell.
205 self.left = -0.8;
206 }
207
208 fn game_over(&mut self, ctx: &mut Context) {
209 self.over = true;
210 let best: u32 = ctx.storage.get_or("best", 0);
211 let text = if self.score > best {
212 ctx.storage.set("best", self.score);
213 format!("Game over. {} bells, a new best score!", self.score)
214 } else {
215 format!("Game over. {} bells. Your best is {best}.", self.score)
216 };
217 ctx.ui.message("over", text);
218 }
219}
220
221impl Scene for Game {
222 fn start(&mut self, ctx: &mut Context) {
223 ctx.speak("Catch the bells! Left and right to move.");
224 // Give the player a moment to listen to the first bell.
225 self.left = -1.5;
226 }
227
228 fn update(&mut self, ctx: &mut Context) {
229 if self.over {
230 if ctx.ui.closed("over") {
231 ctx.switch_scene(Title);
232 }
233 return;
234 }
235 if ctx.pressed(Key::Escape) {
236 ctx.switch_scene(Title);
237 return;
238 }
239 if ctx.pressed(Key::S) {
240 ctx.speak(format!("{} bells, {} lives", self.score, self.lives));
241 }
242 for (key, step) in [(Key::Left, -1), (Key::Right, 1)] {
243 if ctx.input.repeating(key, 0.3, 0.15) {
244 let lane = (self.lane + step).clamp(-LANES, LANES);
245 if lane == self.lane {
246 ctx.play("edge");
247 } else {
248 self.lane = lane;
249 ctx.audio.sound("step").at(vec3(step as f32 * 0.5, 0.0, 0.0)).random_pitch(0.9, 1.1).play();
250 }
251 }
252 }
253
254 let dt = ctx.time.delta();
255 if self.left < 0.0 {
256 self.left += dt;
257 if self.left >= 0.0 {
258 self.drop_bell();
259 }
260 return;
261 }
262 self.left -= dt;
263 self.next_ring -= dt;
264 if self.left <= 0.0 {
265 self.land(ctx);
266 } else if self.next_ring <= 0.0 {
267 self.ring(ctx);
268 }
269 }More examples
58 fn update(&mut self, ctx: &mut Context) {
59 if ctx.pressed(Key::Escape) {
60 ctx.push_scene(Pause);
61 }
62 if ctx.pressed(Key::Left) || ctx.pressed(Key::Right) {
63 let degrees = if ctx.pressed(Key::Left) { -45.0 } else { 45.0 };
64 let facing = ctx.physics.turn(self.player, degrees);
65 ctx.speak(math::direction_name(facing));
66 }
67
68 let forward = ctx.input.repeating(Key::Up, 0.35, 0.35);
69 let backward = ctx.input.repeating(Key::Down, 0.35, 0.35);
70 if forward || backward {
71 let step = if forward { 1.0 } else { -1.0 };
72 if ctx.physics.move_forward(self.player, step).blocked {
73 ctx.play("wall");
74 } else {
75 ctx.audio.sound("step").random_pitch(0.85, 1.15).play();
76 }
77 }
78
79 if ctx.pressed(Key::C) {
80 let position = ctx.physics.position(self.player);
81 match ctx.physics.nearest_with_tag(position, "beacon") {
82 Some(beacon) => {
83 let text = ctx.physics.describe(self.player, beacon);
84 ctx.speak(text);
85 }
86 None => ctx.speak("No beacons left"),
87 }
88 }
89 if ctx.pressed(Key::F) {
90 let facing = ctx.physics.facing(self.player);
91 ctx.speak(format!("Facing {}", math::direction_name(facing)));
92 }
93
94 if let Some(beacon) = ctx.physics.entered_tag(self.player, "beacon") {
95 ctx.physics.remove(beacon);
96 self.beacons.retain(|b| *b != beacon);
97 ctx.play("found");
98 if self.beacons.is_empty() {
99 self.finish(ctx);
100 } else {
101 ctx.speak(format!("Beacon found! {} left.", self.beacons.len()));
102 }
103 }
104 if ctx.ui.closed("done") {
105 ctx.quit();
106 }
107 }19 fn new(ctx: &mut Context) -> Self {
20 let audio = &mut ctx.audio;
21 audio.register("jump", Synth::square(300.0).sweep_to(700.0).length(0.15).decay(10.0).volume(0.2));
22 audio.register("land", Synth::noise().length(0.1).decay(40.0).with(Synth::sine(90.0).length(0.1).decay(30.0)));
23 audio.register("coin", Synth::triangle(988.0).length(0.08).then(Synth::triangle(1319.0).length(0.17).decay(15.0)));
24 audio.register("run", Synth::noise().length(0.06).decay(60.0).volume(0.3).then(Synth::silence(0.09)));
25 audio.register("lift", Synth::saw(55.0).length(1.0).volume(0.1));
26 audio.register("push", Synth::noise().length(0.3).volume(0.15));
27
28 let physics = &mut ctx.physics;
29 physics.add(Body::fixed(vec3(0.0, 0.0, -0.5)).with_box(200.0, 4.0, 1.0).with_tag("ground"));
30 for (x, z) in [(8.0, 2.0), (14.0, 4.0), (20.0, 2.5)] {
31 physics.add(Body::fixed(vec3(x, 0.0, z)).with_box(4.0, 4.0, 0.5).with_tag("platform"));
32 }
33 // A lift going up and down at x = 40, and a heavy crate at x = 30.
34 let lift = physics.add(Body::kinematic(vec3(40.0, 0.0, 0.0)).with_box(3.0, 4.0, 0.5).with_tag("lift"));
35 physics.add(Body::dynamic(vec3(30.0, 0.0, 0.5)).with_box(1.0, 1.0, 1.0).with_mass(5.0).with_tag("crate"));
36 // Facing north, so x maps to left and right in the ears.
37 let player = physics
38 .add(Body::dynamic(vec3(0.0, 0.0, 1.0)).with_box(0.8, 0.8, 1.6).with_max_speed(25.0).with_tag("player"));
39
40 ctx.follow(player);
41 ctx.loop_on(lift, "lift");
42 // Coins are sensors with a looping sound, so you can hear where they are.
43 for (x, z) in [(5.0, 1.0), (14.0, 5.5), (25.0, 1.0), (40.0, 8.0)] {
44 let coin = ctx.physics.add(Body::sensor(vec3(x, 0.0, z)).with_sphere(0.6).with_tag("coin"));
45 ctx.loop_on(coin, "coin").set_volume(0.3);
46 }
47
48 let run_sound = ctx.audio.sound("run").looped().volume(0.0).play();
49 Self { player, lift, run_sound, score: 0 }
50 }
51}
52
53impl Scene for Platformer {
54 fn start(&mut self, ctx: &mut Context) {
55 ctx.speak("Collect the coins. Left and right to run, space to jump, S for score, escape to quit.");
56 }
57
58 fn update(&mut self, ctx: &mut Context) {
59 if ctx.pressed(Key::Escape) {
60 ctx.quit();
61 }
62
63 // The lift goes up for 4 seconds and down for 4 seconds.
64 let lift_up = (ctx.time.elapsed() % 8.0) < 4.0;
65 ctx.physics.set_velocity(self.lift, vec3(0.0, 0.0, if lift_up { 2.0 } else { -2.0 }));
66
67 let run = ctx.input.axis(Key::Left, Key::Right);
68 let mut velocity = ctx.physics.velocity(self.player);
69 velocity.x = run * 6.0;
70 ctx.physics.set_velocity(self.player, velocity);
71 if ctx.pressed(Key::Space) && ctx.physics.jump(self.player, 2.5) {
72 ctx.play("jump");
73 }
74 let running = ctx.physics.on_ground(self.player) && run != 0.0;
75 self.run_sound.set_volume(if running { 0.6 } else { 0.0 });
76
77 if let Some(speed) = ctx.physics.landed(self.player) {
78 ctx.audio.sound("land").volume((speed / 12.0).clamp(0.2, 1.0)).play();
79 if speed > 15.0 {
80 ctx.speak("Ouch!");
81 }
82 }
83 if let Some((other, _)) = ctx.physics.collided(self.player)
84 && ctx.physics.tag(other) == "crate"
85 {
86 ctx.play_on(other, "push");
87 }
88 if let Some(coin) = ctx.physics.entered_tag(self.player, "coin") {
89 ctx.physics.remove(coin); // its looping sound stops by itself
90 self.score += 1;
91 ctx.audio.sound("coin").pitch(1.5).play();
92 ctx.speak(format!("{} of {COINS} coins", self.score));
93 if self.score == COINS {
94 ctx.ui.message("won", "You collected every coin! Press enter to quit.");
95 }
96 }
97 if ctx.ui.closed("won") {
98 ctx.quit();
99 }
100
101 if ctx.pressed(Key::S) {
102 let x = ctx.physics.position(self.player).x;
103 ctx.speak(format!("Score {}, position {x:.0}", self.score));
104 }
105 }Sourcepub fn play(&mut self, name: &str) -> Sound
pub fn play(&mut self, name: &str) -> Sound
Plays a sound once, centered. Returns a handle you may keep or ignore.
Sourcepub fn play_at(&mut self, name: &str, position: Vec3) -> Sound
pub fn play_at(&mut self, name: &str, position: Vec3) -> Sound
Plays a sound once at a position in the world.
Sourcepub fn play_looped(&mut self, name: &str) -> Sound
pub fn play_looped(&mut self, name: &str) -> Sound
Plays a sound in an endless loop. Stop it with Sound::stop.
Examples found in repository?
31 fn new(ctx: &mut Context) -> Self {
32 ctx.audio.register("bird", Synth::sine(2200.0).sweep_to(3200.0).length(0.07).then(Synth::silence(0.05)).then(Synth::sine(2600.0).length(0.06)).then(Synth::silence(0.7)));
33 ctx.audio.register("hum", Synth::saw(70.0).length(1.0).volume(0.08));
34 ctx.audio.register("bump", Synth::sine(80.0).length(0.15).decay(25.0).volume(0.8));
35 ctx.audio.register("found", Synth::triangle(660.0).sweep_to(1320.0).length(0.4).decay(6.0).volume(0.3));
36
37 // A hall of 40 x 40 meters and 16 meters high: floor, roof and four walls.
38 // A box is given by its center and its full width (x), depth (y) and height (z).
39 let physics = &mut ctx.physics;
40 physics.add(Body::fixed(vec3(0.0, 0.0, -0.5)).with_box(40.0, 40.0, 1.0).with_tag("floor"));
41 physics.add(Body::fixed(vec3(0.0, 0.0, 16.5)).with_box(40.0, 40.0, 1.0).with_tag("roof"));
42 physics.add(Body::fixed(vec3(0.0, 20.5, 8.0)).with_box(40.0, 1.0, 16.0).with_tag("north wall"));
43 physics.add(Body::fixed(vec3(0.0, -20.5, 8.0)).with_box(40.0, 1.0, 16.0).with_tag("south wall"));
44 physics.add(Body::fixed(vec3(20.5, 0.0, 8.0)).with_box(1.0, 40.0, 16.0).with_tag("east wall"));
45 physics.add(Body::fixed(vec3(-20.5, 0.0, 8.0)).with_box(1.0, 40.0, 16.0).with_tag("west wall"));
46
47 // The drone starts in the middle, 2 meters above the floor. No gravity: it hovers.
48 let drone = ctx.physics.add(Body::kinematic(vec3(0.0, 0.0, 2.0)).with_sphere(0.5).with_tag("drone"));
49 ctx.follow(drone); // the ears use the drone's position, facing and pitch
50 ctx.audio.play_looped("hum");
51
52 for spot in BIRDS {
53 let bird = ctx.physics.add(Body::sensor(spot).with_sphere(1.0).with_tag("bird"));
54 ctx.loop_on(bird, "bird");
55 }
56 Self { drone, birds: BIRDS.len(), blocked: false }
57 }Sourcepub fn play_looped_at(&mut self, name: &str, position: Vec3) -> Sound
pub fn play_looped_at(&mut self, name: &str, position: Vec3) -> Sound
Plays a looping sound at a position in the world.
Sourcepub fn play_random(&mut self, names: &[&str]) -> Sound
pub fn play_random(&mut self, names: &[&str]) -> Sound
Plays one of several sounds picked at random, e.g. footstep variations.
Sourcepub fn play_random_at(&mut self, names: &[&str], position: Vec3) -> Sound
pub fn play_random_at(&mut self, names: &[&str], position: Vec3) -> Sound
Plays one of several sounds picked at random at a position.
Sourcepub fn play_tone(&mut self, frequency: f32, seconds: f32) -> Sound
pub fn play_tone(&mut self, frequency: f32, seconds: f32) -> Sound
Plays a generated sine beep of frequency hertz (e.g. 880.0) for seconds. Great
for prototyping before you have sound files.
Examples found in repository?
14 fn update(&mut self, ctx: &mut Context) {
15 if ctx.input.pressed(Key::Space) {
16 // A pitch that rises over time, so every beep sounds different.
17 let pitch = 300.0 + (ctx.time.elapsed() as f32 * 50.0) % 900.0;
18 ctx.audio.play_tone(pitch.round(), 0.15);
19 }
20 if ctx.input.pressed(Key::F1) {
21 ctx.speech.repeat_last();
22 }
23 if ctx.input.pressed(Key::Escape) {
24 ctx.quit();
25 }
26 }More examples
8fn main() -> audio_code::Result<()> {
9 let mut score = 0;
10
11 audio_code::run("Clicker", move |ctx| {
12 if ctx.once("intro") {
13 let best: u32 = ctx.storage.get_or("best", 0);
14 ctx.speak(format!("Press space as often as you can in ten seconds. Your best is {best}. Go!"));
15 ctx.time.after("end", 10.0);
16 }
17
18 if ctx.time.is_scheduled("end") && ctx.pressed(Key::Space) {
19 score += 1;
20 ctx.audio.play_tone(300.0 + score as f32 * 15.0, 0.05);
21 }
22
23 if ctx.time.fired("end") {
24 let best: u32 = ctx.storage.get_or("best", 0);
25 if score > best {
26 ctx.storage.set("best", score);
27 ctx.ui.message("result", format!("{score} presses. New record!"));
28 } else {
29 ctx.ui.message("result", format!("{score} presses. Your best is {best}."));
30 }
31 }
32
33 if ctx.ui.closed("result") || ctx.pressed(Key::Escape) {
34 ctx.quit();
35 }
36 })
37}Sourcepub fn play_music(&mut self, name: &str) -> Sound
pub fn play_music(&mut self, name: &str) -> Sound
Plays background music in a loop. The file is decoded in the background so the game does not stutter. Any previous music fades out while the new one fades in. Calling it again with the music that is already playing does nothing.
Sourcepub fn play_music_with_fade(&mut self, name: &str, fade: f32) -> Sound
pub fn play_music_with_fade(&mut self, name: &str, fade: f32) -> Sound
Like Audio::play_music with a custom cross fade time in seconds.
Sourcepub fn stop_music(&mut self, fade: f32)
pub fn stop_music(&mut self, fade: f32)
Fades out the current music over fade seconds.
Sourcepub fn music_name(&self) -> Option<&str>
pub fn music_name(&self) -> Option<&str>
Name of the current music, as passed to Audio::play_music.
Sourcepub fn set_listener(&mut self, position: Vec3, yaw: f32)
pub fn set_listener(&mut self, position: Vec3, yaw: f32)
Places the listener (the player’s ears) in the world. yaw is the compass direction
the player faces (0 = north, 90 = east). Call this whenever the player moves or turns.
The listener looks level with the horizon; use Audio::set_listener_3d to also
look up or down.
Sourcepub fn set_listener_3d(&mut self, position: Vec3, yaw: f32, pitch: f32)
pub fn set_listener_3d(&mut self, position: Vec3, yaw: f32, pitch: f32)
Like Audio::set_listener, plus pitch: how far the player looks up (positive,
90 = straight up) or down (negative, -90 = straight down), in degrees. For flying,
swimming or space games.
Sourcepub fn listener_position(&self) -> Vec3
pub fn listener_position(&self) -> Vec3
Current listener position.
Sourcepub fn listener_yaw(&self) -> f32
pub fn listener_yaw(&self) -> f32
Current listener facing in compass degrees.
Sourcepub fn listener_pitch(&self) -> f32
pub fn listener_pitch(&self) -> f32
Current listener pitch in degrees (0 = level, 90 = straight up).
Sourcepub fn set_default_distance(&mut self, min: f32, max: f32)
pub fn set_default_distance(&mut self, min: f32, max: f32)
Default audible range for positioned sounds in meters: full volume up to min,
silent from max on. The default is 1.0 and 30.0.
Sourcepub fn set_default_rolloff(&mut self, rolloff: f32)
pub fn set_default_rolloff(&mut self, rolloff: f32)
Default rolloff for positioned sounds: how fast the volume drops between min and
max distance. 1.0 is physically accurate (twice the distance, half the volume),
lower values keep distant sounds louder, 0.0 keeps full volume until shortly before
max. Default is 0.7, which is at 32 % volume at 5 m and 18 % at 10 m.
Sourcepub fn set_master_volume(&mut self, volume: f32)
pub fn set_master_volume(&mut self, volume: f32)
Sets the overall volume as a linear factor: 1.0 = unchanged (default), 0.5 = half, 0.0 = silent. Higher values amplify and may distort.
Examples found in repository?
50 fn on_ui(&mut self, event: &UiEvent, ctx: &mut Context) {
51 match event {
52 UiEvent::Activated { menu, item } => match (menu.as_str(), item.as_str()) {
53 ("main", "play") => {
54 let s = ctx.get::<Settings>().expect("settings exist");
55 let text = format!("Good luck, {}! (this is where your game would start)", s.name);
56 ctx.ui.message("intro", text);
57 }
58 ("main", "options") => {
59 let menu = options_menu(ctx.get::<Settings>().expect("settings exist"));
60 ctx.ui.open(menu);
61 }
62 ("main", "name") => ctx.ui.open(TextInput::new("name", "Enter your name").max_length(20).required()),
63 ("main", "quit") => ctx.ui.open(Confirm::new("quit", "Do you really want to quit?").default_no()),
64 ("options", "back") => ctx.ui.close(),
65 _ => {}
66 },
67 UiEvent::Changed { menu, item, value } if menu == "options" => {
68 let s = ctx.get_mut::<Settings>().expect("settings exist");
69 match item.as_str() {
70 "volume" => s.volume = value.as_f32() / 100.0,
71 "difficulty" => s.difficulty = value.as_index(),
72 "name" => s.name = value.as_str().to_string(),
73 _ => {}
74 }
75 let volume = s.volume;
76 ctx.audio.set_master_volume(volume);
77 }
78 UiEvent::TextSubmitted { id, text } if id == "name" => {
79 ctx.get_mut::<Settings>().expect("settings exist").name = text.clone();
80 ctx.speech.speak_queued(format!("Hello, {text}"));
81 }
82 UiEvent::Confirmed { id, yes: true } if id == "quit" => ctx.quit(),
83 _ => {}
84 }
85 }Sourcepub fn master_volume(&self) -> f32
pub fn master_volume(&self) -> f32
Overall volume.
Sourcepub fn set_group_volume(&mut self, group: Group, volume: f32)
pub fn set_group_volume(&mut self, group: Group, volume: f32)
Sets the volume of one group (sound effects, music or UI) as a linear factor, 1.0 = unchanged (default). It is multiplied with each sound’s own volume and the master volume.
Sourcepub fn group_volume(&self, group: Group) -> f32
pub fn group_volume(&self, group: Group) -> f32
Volume of one group.
Sourcepub fn set_music_volume(&mut self, volume: f32)
pub fn set_music_volume(&mut self, volume: f32)
Shortcut for set_group_volume(Group::Music, volume).
Sourcepub fn set_sound_volume(&mut self, volume: f32)
pub fn set_sound_volume(&mut self, volume: f32)
Shortcut for set_group_volume(Group::Sound, volume).
Sourcepub fn stop_group(&mut self, group: Group, fade: f32)
pub fn stop_group(&mut self, group: Group, fade: f32)
Fades out all sounds of a group over fade seconds and stops them.
Trait Implementations§
Auto Trait Implementations§
impl !RefUnwindSafe for Audio
impl !UnwindSafe for Audio
impl Freeze for Audio
impl Send for Audio
impl Sync for Audio
impl Unpin for Audio
impl UnsafeUnpin for Audio
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
Source§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can
then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.Source§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be
further downcast into Rc<ConcreteType> where ConcreteType implements Trait.Source§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &Any’s vtable from &Trait’s.Source§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &mut Any’s vtable from &mut Trait’s.