Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/examples/audio/decodable.rs
6592 views
1
//! Shows how to create a custom [`Decodable`] type by implementing a Sine wave.
2
3
use bevy::{
4
audio::{AddAudioSource, AudioPlugin, Source, Volume},
5
math::ops,
6
prelude::*,
7
reflect::TypePath,
8
};
9
use core::time::Duration;
10
11
// This struct usually contains the data for the audio being played.
12
// This is where data read from an audio file would be stored, for example.
13
// This allows the type to be registered as an asset.
14
#[derive(Asset, TypePath)]
15
struct SineAudio {
16
frequency: f32,
17
}
18
// This decoder is responsible for playing the audio,
19
// and so stores data about the audio being played.
20
struct SineDecoder {
21
// how far along one period the wave is (between 0 and 1)
22
current_progress: f32,
23
// how much we move along the period every frame
24
progress_per_frame: f32,
25
// how long a period is
26
period: f32,
27
sample_rate: u32,
28
}
29
30
impl SineDecoder {
31
fn new(frequency: f32) -> Self {
32
// standard sample rate for most recordings
33
let sample_rate = 44_100;
34
SineDecoder {
35
current_progress: 0.,
36
progress_per_frame: frequency / sample_rate as f32,
37
period: std::f32::consts::PI * 2.,
38
sample_rate,
39
}
40
}
41
}
42
43
// The decoder must implement iterator so that it can implement `Decodable`.
44
impl Iterator for SineDecoder {
45
type Item = f32;
46
47
fn next(&mut self) -> Option<Self::Item> {
48
self.current_progress += self.progress_per_frame;
49
// we loop back round to 0 to avoid floating point inaccuracies
50
self.current_progress %= 1.;
51
Some(ops::sin(self.period * self.current_progress))
52
}
53
}
54
// `Source` is what allows the audio source to be played by bevy.
55
// This trait provides information on the audio.
56
impl Source for SineDecoder {
57
fn current_frame_len(&self) -> Option<usize> {
58
None
59
}
60
61
fn channels(&self) -> u16 {
62
1
63
}
64
65
fn sample_rate(&self) -> u32 {
66
self.sample_rate
67
}
68
69
fn total_duration(&self) -> Option<Duration> {
70
None
71
}
72
}
73
74
// Finally `Decodable` can be implemented for our `SineAudio`.
75
impl Decodable for SineAudio {
76
type DecoderItem = <SineDecoder as Iterator>::Item;
77
78
type Decoder = SineDecoder;
79
80
fn decoder(&self) -> Self::Decoder {
81
SineDecoder::new(self.frequency)
82
}
83
}
84
85
fn main() {
86
let mut app = App::new();
87
// register the audio source so that it can be used
88
app.add_plugins(DefaultPlugins.set(AudioPlugin {
89
global_volume: Volume::Linear(0.2).into(),
90
..default()
91
}))
92
.add_audio_source::<SineAudio>()
93
.add_systems(Startup, setup)
94
.run();
95
}
96
97
fn setup(mut assets: ResMut<Assets<SineAudio>>, mut commands: Commands) {
98
// add a `SineAudio` to the asset server so that it can be played
99
let audio_handle = assets.add(SineAudio {
100
frequency: 440., // this is the frequency of A4
101
});
102
commands.spawn(AudioPlayer(audio_handle));
103
}
104
105