1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
use {
crate::{
IntoSfResult, SfResult,
cpp::FBox,
ffi::{self},
system::{InputStream, Time},
},
std::{
ffi::CString,
io::{Read, Seek},
slice,
},
};
decl_opaque! {
/// Storage for audio samples defining a sound.
///
/// A sound buffer holds the data of a sound, which is an array of audio samples.
///
/// A sample is a 16 bits signed integer that defines the amplitude of the sound at a given time.
/// The sound is then reconstituted by playing these samples at a high rate
/// (for example, 44100 samples per second is the standard rate used for playing CDs).
/// In short, audio samples are like texture pixels, and a `SoundBuffer` is
/// similar to a [`crate::graphics::Texture`].
///
/// A sound buffer can be loaded from a file (see [`from_file`] for the complete list of
/// supported formats), from memory, from a custom stream or directly from an array of samples.
/// It can also be saved back to a file.
///
/// [`from_file`]: SoundBuffer::from_file
///
/// Sound buffers alone are not very useful: they hold the audio data but cannot be played.
/// To do so, you need to use the [`Sound`] type, which provides functions to play/pause/stop
/// the sound as well as changing the way it is outputted (volume, pitch, 3D position, ...).
/// This separation allows more flexibility and better performances: indeed a `SoundBuffer` is
/// a heavy resource, and any operation on it is slow (often too slow for real-time applications).
/// On the other side, a [`Sound`] is a lightweight object, which can use the audio data of a sound
/// buffer and change the way it is played without actually modifying that data.
/// Note that it is also possible to bind several [`Sound`] instances to the same `SoundBuffer`.
///
/// It is important to note that the [`Sound`] instance doesn't copy the buffer that it uses,
/// it only keeps a reference to it. Thus, a `SoundBuffer` can not be destructed while it is
/// borrowed by a [`Sound`].
///
/// [`Sound`]: crate::audio::Sound
pub SoundBuffer;
}
/// Creation and loading
impl SoundBuffer {
/// Creates a new (empty) `SoundBuffer`.
pub fn new() -> SfResult<FBox<Self>> {
FBox::new(unsafe { ffi::audio::sfSoundBuffer_new() }).into_sf_result()
}
/// Creates a new `SoundBuffer` from a file.
///
/// See [`Self::load_from_file`].
pub fn from_file(filename: &str) -> SfResult<FBox<Self>> {
let mut new = Self::new()?;
new.load_from_file(filename)?;
Ok(new)
}
/// Creates a new `SoundBuffer` from a file in memory.
///
/// See [`Self::load_from_memory`].
pub fn from_memory(data: &[u8]) -> SfResult<FBox<Self>> {
let mut new = Self::new()?;
new.load_from_memory(data)?;
Ok(new)
}
/// Creates a new `SoundBuffer` from a stream.
///
/// See [`Self::load_from_stream`].
pub fn from_stream<T: Read + Seek>(stream: &mut T) -> SfResult<FBox<Self>> {
let mut new = Self::new()?;
new.load_from_stream(stream)?;
Ok(new)
}
/// Creates a new `SoundBuffer` from a slice of audio samples.
///
/// See [`Self::load_from_samples`].
pub fn from_samples(
samples: &[i16],
channel_count: u32,
sample_rate: u32,
) -> SfResult<FBox<Self>> {
let mut new = Self::new()?;
new.load_from_samples(samples, channel_count, sample_rate)?;
Ok(new)
}
/// Load sound data from a file.
///
/// Here is a complete list of all the supported audio formats:
/// ogg, wav, flac, aiff, au, raw, paf, svx, nist, voc, ircam,
/// w64, mat4, mat5 pvf, htk, sds, avr, sd2, caf, wve, mpc2k, rf64.
///
/// # Arguments
/// * filename - Path of the sound file to load
pub fn load_from_file(&mut self, filename: &str) -> SfResult<()> {
let c_str = CString::new(filename)?;
unsafe { ffi::audio::sfSoundBuffer_loadFromFile(self, c_str.as_ptr()) }.into_sf_result()
}
/// Load the sound buffer from a file in memory.
pub fn load_from_memory(&mut self, data: &[u8]) -> SfResult<()> {
unsafe { ffi::audio::sfSoundBuffer_loadFromMemory(self, data.as_ptr(), data.len()) }
.into_sf_result()
}
/// Load the sound buffer from a custom stream.
pub fn load_from_stream<T: Read + Seek>(&mut self, stream: &mut T) -> SfResult<()> {
let mut stream = InputStream::new(stream);
unsafe { ffi::audio::sfSoundBuffer_loadFromStream(self, &mut *stream.stream) }
.into_sf_result()
}
/// Load the sound buffer from a slice of audio samples.
///
/// The assumed format of the audio samples is 16 bits signed integer.
pub fn load_from_samples(
&mut self,
samples: &[i16],
channel_count: u32,
sample_rate: u32,
) -> SfResult<()> {
unsafe {
ffi::audio::sfSoundBuffer_loadFromSamples(
self,
samples.as_ptr(),
samples.len() as _,
channel_count,
sample_rate,
)
}
.into_sf_result()
}
}
/// Query properties
impl SoundBuffer {
/// Get the number of samples stored in a sound buffer
///
/// The array of samples can be accessed with [`samples`](SoundBuffer::samples).
///
/// Return the number of samples
#[must_use]
pub fn sample_count(&self) -> u64 {
unsafe { ffi::audio::sfSoundBuffer_getSampleCount(self) }
}
/// Get the samples stored in the buffer
///
/// # Panics
///
/// Panics if the sample count exceeds usize range
#[must_use]
pub fn samples(&self) -> &[i16] {
let len: usize = self
.sample_count()
.try_into()
.expect("Overflow when casting sample count to usize");
unsafe { slice::from_raw_parts(ffi::audio::sfSoundBuffer_getSamples(self), len) }
}
/// Get the number of channels used by a sound buffer
///
/// If the sound is mono then the number of channels will
/// be 1, 2 for stereo, etc.
///
/// Return the number of channels
#[must_use]
pub fn channel_count(&self) -> u32 {
unsafe { ffi::audio::sfSoundBuffer_getChannelCount(self) }
}
/// Get the total duration of a sound buffer
///
/// Return the sound duration
#[must_use]
pub fn duration(&self) -> Time {
unsafe { Time::from_raw(ffi::audio::sfSoundBuffer_getDuration(self)) }
}
/// Get the sample rate of a sound buffer
///
/// The sample rate is the number of samples played per second.
/// The higher, the better the quality (for example, 44100
/// samples/s is CD quality).
///
/// Return the sample rate (number of samples per second)
#[must_use]
pub fn sample_rate(&self) -> u32 {
unsafe { ffi::audio::sfSoundBuffer_getSampleRate(self) }
}
}
/// Saving
impl SoundBuffer {
/// Save a sound buffer to an audio file
///
/// Here is a complete list of all the supported audio formats:
/// ogg, wav, flac, aiff, au, raw, paf, svx, nist, voc, ircam,
/// w64, mat4, mat5 pvf, htk, sds, avr, sd2, caf, wve, mpc2k, rf64.
///
/// # Arguments
/// * filename - Path of the sound file to write
pub fn save_to_file(&self, filename: &str) -> SfResult<()> {
let c_str = CString::new(filename)?;
unsafe { ffi::audio::sfSoundBuffer_saveToFile(self, c_str.as_ptr()) }.into_sf_result()
}
}
impl ToOwned for SoundBuffer {
type Owned = FBox<Self>;
fn to_owned(&self) -> Self::Owned {
let sound_buffer = unsafe { ffi::audio::sfSoundBuffer_cpy(self) };
FBox::new(sound_buffer).expect("Failed to copy SoundBuffer")
}
}
impl Drop for SoundBuffer {
fn drop(&mut self) {
unsafe {
ffi::audio::sfSoundBuffer_del(self);
}
}
}