rodio/source/mod.rs
1//! Sources of sound and various filters.
2
3use core::time::Duration;
4use std::sync::Arc;
5
6use crate::{
7 buffer::SamplesBuffer,
8 common::{assert_error_traits, ChannelCount, SampleRate},
9 math, BitDepth, Float, Sample,
10};
11
12use dasp_sample::FromSample;
13
14pub use self::agc::{AutomaticGainControl, AutomaticGainControlSettings};
15pub use self::amplify::Amplify;
16pub use self::blt::BltFilter;
17pub use self::buffered::Buffered;
18pub use self::channel_volume::ChannelVolume;
19pub use self::chirp::{chirp, Chirp};
20pub use self::crossfade::Crossfade;
21pub use self::delay::Delay;
22pub use self::distortion::Distortion;
23pub use self::done::Done;
24pub use self::empty::Empty;
25pub use self::empty_callback::EmptyCallback;
26pub use self::fadein::FadeIn;
27pub use self::fadeout::FadeOut;
28pub use self::from_factory::{from_factory, FromFactoryIter};
29pub use self::from_iter::{from_iter, FromIter};
30pub use self::limit::{Limit, LimitSettings};
31pub use self::linear_ramp::LinearGainRamp;
32pub use self::mix::Mix;
33pub use self::pausable::Pausable;
34pub use self::periodic::PeriodicAccess;
35pub use self::position::TrackPosition;
36pub use self::repeat::Repeat;
37pub use self::sawtooth::SawtoothWave;
38pub use self::signal_generator::{Function, GeneratorFunction, SignalGenerator};
39pub use self::sine::SineWave;
40pub use self::skip::SkipDuration;
41pub use self::skippable::Skippable;
42pub use self::spatial::Spatial;
43pub use self::speed::Speed;
44pub use self::square::SquareWave;
45pub use self::stoppable::Stoppable;
46pub use self::take::TakeDuration;
47pub use self::triangle::TriangleWave;
48pub use self::uniform::UniformSourceIterator;
49pub use self::zero::Zero;
50
51mod agc;
52mod amplify;
53mod blt;
54mod buffered;
55mod channel_volume;
56mod chirp;
57mod crossfade;
58mod delay;
59mod distortion;
60mod done;
61mod empty;
62mod empty_callback;
63mod fadein;
64mod fadeout;
65mod from_factory;
66mod from_iter;
67mod limit;
68mod linear_ramp;
69mod mix;
70mod pausable;
71mod periodic;
72mod position;
73mod repeat;
74mod sawtooth;
75mod signal_generator;
76mod sine;
77mod skip;
78mod skippable;
79mod spatial;
80mod speed;
81mod square;
82mod stoppable;
83mod take;
84mod triangle;
85mod uniform;
86mod zero;
87
88#[cfg(feature = "dither")]
89pub mod dither;
90#[cfg(feature = "dither")]
91pub use self::dither::{Algorithm as DitherAlgorithm, Dither};
92
93#[cfg(feature = "noise")]
94pub mod noise;
95#[cfg(feature = "noise")]
96pub use self::noise::{Pink, WhiteUniform};
97
98/// A source of samples.
99///
100/// # A quick lesson about sounds
101///
102/// ## Sampling
103///
104/// A sound is a vibration that propagates through air and reaches your ears. This vibration can
105/// be represented as an analog signal.
106///
107/// In order to store this signal in the computer's memory or on the disk, we perform what is
108/// called *sampling*. This consists in choosing an interval of time (for example 20µs) and reading
109/// the amplitude of the signal at each interval (for example, if the interval is 20µs we read the
110/// amplitude every 20µs). By doing so we obtain a list of numerical values, each value being
111/// called a *sample*.
112///
113/// Therefore, a sound can be represented in memory by a frequency and a list of samples. The
114/// frequency is expressed in hertz and corresponds to the number of samples that have been
115/// read per second. For example if we read one sample every 20µs, the frequency would be
116/// 50000 Hz. In reality, common values for the frequency are 44100, 48000 and 96000.
117///
118/// ## Channels
119///
120/// But a frequency and a list of values only represent one signal. When you listen to a sound,
121/// your left and right ears don't receive exactly the same signal. In order to handle this,
122/// we usually record not one but two different signals: one for the left ear and one for the right
123/// ear. We say that such a sound has two *channels*.
124///
125/// Sometimes sounds even have five or six channels, each corresponding to a location around the
126/// head of the listener.
127///
128/// The standard in audio manipulation is to *interleave* the multiple channels. In other words,
129/// in a sound with two channels the list of samples contains the first sample of the first
130/// channel, then the first sample of the second channel, then the second sample of the first
131/// channel, then the second sample of the second channel, and so on. The same applies if you have
132/// more than two channels. The rodio library only supports this schema.
133///
134/// Therefore, in order to represent a sound in memory in fact we need three characteristics: the
135/// frequency, the number of channels, and the list of samples.
136///
137/// ## The `Source` trait
138///
139/// A Rust object that represents a sound should implement the `Source` trait.
140///
141/// The three characteristics that describe a sound are provided through this trait:
142///
143/// - The number of channels can be retrieved with `channels`.
144/// - The frequency can be retrieved with `sample_rate`.
145/// - The list of values can be retrieved by iterating on the source. The `Source` trait requires
146/// that the `Iterator` trait be implemented as well. When a `Source` returns None the
147/// sound has ended.
148///
149/// # Spans
150///
151/// The samples rate and number of channels of some sound sources can change by itself from time
152/// to time.
153///
154/// > **Note**: As a basic example, if you play two audio files one after the other and treat the
155/// > whole as a single source, then the channels and samples rate of that source may change at the
156/// > transition between the two files.
157///
158/// However, for optimization purposes rodio supposes that the number of channels and the frequency
159/// stay the same for long periods of time and avoids calling `channels()` and
160/// `sample_rate` too frequently.
161///
162/// In order to properly handle this situation, the `current_span_len()` method should return
163/// the number of samples that remain in the iterator before the samples rate and number of
164/// channels can potentially change.
165///
166pub trait Source: Iterator<Item = Sample> {
167 /// Returns the number of samples before the current span ends.
168 ///
169 /// `None` means "infinite" or "until the sound ends". Sources that return `Some(x)` should
170 /// return `Some(0)` if and only if when there's no more data.
171 ///
172 /// After the engine has finished reading the specified number of samples, it will check
173 /// whether the value of `channels()` and/or `sample_rate()` have changed.
174 ///
175 /// # Frame Alignment
176 ///
177 /// Span lengths must be multiples of the channel count to ensure spans end on frame
178 /// boundaries. A "frame" is one sample for each channel. Returning a span length
179 /// that is not a multiple of `channels()` will cause channel misalignment issues.
180 ///
181 /// Note: This returns the total span size, not the remaining samples. Use `Iterator::size_hint`
182 /// to determine how many samples remain in the iterator.
183 fn current_span_len(&self) -> Option<usize>;
184
185 /// Returns true if the source is exhausted (has no more samples available).
186 #[inline]
187 fn is_exhausted(&self) -> bool {
188 self.current_span_len() == Some(0)
189 }
190
191 /// Returns the number of channels. Channels are always interleaved.
192 /// Should never be Zero
193 fn channels(&self) -> ChannelCount;
194
195 /// Returns the rate at which the source should be played. In number of samples per second.
196 fn sample_rate(&self) -> SampleRate;
197
198 /// Returns the total duration of this source, if known.
199 ///
200 /// `None` indicates at the same time "infinite" or "unknown".
201 fn total_duration(&self) -> Option<Duration>;
202
203 /// Stores the source in a buffer in addition to returning it. This iterator can be cloned.
204 #[inline]
205 fn buffered(self) -> Buffered<Self>
206 where
207 Self: Sized,
208 {
209 buffered::buffered(self)
210 }
211
212 /// Applies dithering to the source at the specified bit depth.
213 ///
214 /// Dithering eliminates quantization artifacts during digital audio playback
215 /// and when converting between bit depths. Apply at the target output bit depth.
216 ///
217 /// # Example
218 ///
219 /// ```
220 /// use rodio::source::{SineWave, Source, DitherAlgorithm};
221 /// use rodio::BitDepth;
222 ///
223 /// let source = SineWave::new(440.0)
224 /// .amplify(0.5)
225 /// .dither(BitDepth::new(16).unwrap(), DitherAlgorithm::default());
226 /// ```
227 #[cfg(feature = "dither")]
228 #[inline]
229 fn dither(self, target_bits: BitDepth, algorithm: DitherAlgorithm) -> Dither<Self>
230 where
231 Self: Sized,
232 {
233 Dither::new(self, target_bits, algorithm)
234 }
235
236 /// Mixes this source with another one.
237 #[inline]
238 fn mix<S>(self, other: S) -> Mix<Self, S>
239 where
240 Self: Sized,
241 S: Source,
242 {
243 mix::mix(self, other)
244 }
245
246 /// Repeats this source forever.
247 ///
248 /// Note that this works by storing the data in a buffer, so the amount of memory used is
249 /// proportional to the size of the sound.
250 #[inline]
251 fn repeat_infinite(self) -> Repeat<Self>
252 where
253 Self: Sized,
254 {
255 repeat::repeat(self)
256 }
257
258 /// Takes a certain duration of this source and then stops.
259 #[inline]
260 fn take_duration(self, duration: Duration) -> TakeDuration<Self>
261 where
262 Self: Sized,
263 {
264 take::take_duration(self, duration)
265 }
266
267 /// Delays the sound by a certain duration.
268 ///
269 /// The rate and channels of the silence will use the same format as the first span of the
270 /// source.
271 #[inline]
272 fn delay(self, duration: Duration) -> Delay<Self>
273 where
274 Self: Sized,
275 {
276 delay::delay(self, duration)
277 }
278
279 /// Immediately skips a certain duration of this source.
280 ///
281 /// If the specified duration is longer than the source itself, `skip_duration` will skip to the end of the source.
282 #[inline]
283 fn skip_duration(self, duration: Duration) -> SkipDuration<Self>
284 where
285 Self: Sized,
286 {
287 skip::skip_duration(self, duration)
288 }
289
290 /// Amplifies the sound by the given value.
291 #[inline]
292 fn amplify(self, value: Float) -> Amplify<Self>
293 where
294 Self: Sized,
295 {
296 amplify::amplify(self, value)
297 }
298
299 /// Amplifies the sound logarithmically by the given value.
300 #[inline]
301 fn amplify_decibel(self, value: Float) -> Amplify<Self>
302 where
303 Self: Sized,
304 {
305 amplify::amplify(self, math::db_to_linear(value))
306 }
307
308 /// Normalized amplification in `[0.0, 1.0]` range. This method better matches the perceived
309 /// loudness of sounds in human hearing and is recommended to use when you want to change
310 /// volume in `[0.0, 1.0]` range.
311 /// based on article: <https://www.dr-lex.be/info-stuff/volumecontrols.html>
312 ///
313 /// **note: it clamps values outside this range.**
314 #[inline]
315 fn amplify_normalized(self, value: Float) -> Amplify<Self>
316 where
317 Self: Sized,
318 {
319 const NORMALIZATION_MIN: Float = 0.0;
320 const NORMALIZATION_MAX: Float = 1.0;
321 const LOG_VOLUME_GROWTH_RATE: Float = 6.907_755_4;
322 const LOG_VOLUME_SCALE_FACTOR: Float = 1000.0;
323
324 let value = value.clamp(NORMALIZATION_MIN, NORMALIZATION_MAX);
325
326 let mut amplitude = Float::exp(LOG_VOLUME_GROWTH_RATE * value) / LOG_VOLUME_SCALE_FACTOR;
327 if value < 0.1 {
328 amplitude *= value * 10.0;
329 }
330
331 amplify::amplify(self, amplitude)
332 }
333
334 /// Applies automatic gain control to the sound.
335 ///
336 /// Automatic Gain Control (AGC) adjusts the amplitude of the audio signal
337 /// to maintain a consistent output level.
338 ///
339 /// # Parameters
340 ///
341 /// `target_level`:
342 /// **TL;DR**: Desired output level. 1.0 = original level, > 1.0 amplifies, < 1.0 reduces.
343 ///
344 /// The desired output level, where 1.0 represents the original sound level.
345 /// Values above 1.0 will amplify the sound, while values below 1.0 will lower it.
346 /// For example, a target_level of 1.4 means that at normal sound levels, the AGC
347 /// will aim to increase the gain by a factor of 1.4, resulting in a minimum 40% amplification.
348 /// A recommended level is `1.0`, which maintains the original sound level.
349 ///
350 /// `attack_time`:
351 /// **TL;DR**: Response time for volume increases. Shorter = faster but may cause abrupt changes. **Recommended: `4.0` seconds**.
352 ///
353 /// The time (in seconds) for the AGC to respond to input level increases.
354 /// Shorter times mean faster response but may cause abrupt changes. Longer times result
355 /// in smoother transitions but slower reactions to sudden volume changes. Too short can
356 /// lead to overreaction to peaks, causing unnecessary adjustments. Too long can make the
357 /// AGC miss important volume changes or react too slowly to sudden loud passages. Very
358 /// high values might result in excessively loud output or sluggish response, as the AGC's
359 /// adjustment speed is limited by the attack time. Balance is key for optimal performance.
360 /// A recommended attack_time of `4.0` seconds provides a sweet spot for most applications.
361 ///
362 /// `release_time`:
363 /// **TL;DR**: Response time for volume decreases. Shorter = faster gain reduction. **Recommended: `0.0` seconds**.
364 ///
365 /// The time (in seconds) for the AGC to respond to input level decreases.
366 /// This parameter controls how quickly the gain is reduced when the signal level drops.
367 /// Shorter release times result in faster gain reduction, which can be useful for quick
368 /// adaptation to quieter passages but may lead to pumping effects. Longer release times
369 /// provide smoother transitions but may be slower to respond to sudden decreases in volume.
370 /// However, if the release_time is too high, the AGC may not be able to lower the gain
371 /// quickly enough, potentially leading to clipping and distorted sound before it can adjust.
372 /// Finding the right balance is crucial for maintaining natural-sounding dynamics and
373 /// preventing distortion. A recommended release_time of `0.0` seconds works well for
374 /// general use, allowing the AGC to decrease the gain immediately with no delay, ensuring there is no clipping.
375 ///
376 /// `absolute_max_gain`:
377 /// **TL;DR**: Maximum allowed gain. Prevents over-amplification. **Recommended: `5.0`**.
378 ///
379 /// The maximum gain that can be applied to the signal.
380 /// This parameter acts as a safeguard against excessive amplification of quiet signals
381 /// or background noise. It establishes an upper boundary for the AGC's signal boost,
382 /// effectively preventing distortion or overamplification of low-level sounds.
383 /// This is crucial for maintaining audio quality and preventing unexpected volume spikes.
384 /// A recommended value for `absolute_max_gain` is `5`, which provides a good balance between
385 /// amplification capability and protection against distortion in most scenarios.
386 ///
387 /// `automatic_gain_control` example in this project shows a pattern you can use
388 /// to enable/disable the AGC filter dynamically.
389 ///
390 /// # Example (Quick start)
391 ///
392 /// ```rust
393 /// // Apply Automatic Gain Control to the source (AGC is on by default)
394 /// use rodio::source::{Source, SineWave, AutomaticGainControlSettings};
395 /// use rodio::Player;
396 /// use std::time::Duration;
397 /// let source = SineWave::new(444.0); // An example.
398 /// let (player, output) = Player::new(); // An example.
399 ///
400 /// let agc_source = source.automatic_gain_control(AutomaticGainControlSettings::default());
401 ///
402 /// // Add the AGC-controlled source to the sink
403 /// player.append(agc_source);
404 ///
405 /// ```
406 #[inline]
407 fn automatic_gain_control(
408 self,
409 agc_settings: AutomaticGainControlSettings,
410 ) -> AutomaticGainControl<Self>
411 where
412 Self: Sized,
413 {
414 // Added Limits to prevent the AGC from blowing up. ;)
415 let attack_time_limited = agc_settings.attack_time.min(Duration::from_secs(10));
416 let release_time_limited = agc_settings.release_time.min(Duration::from_secs(10));
417
418 agc::automatic_gain_control(
419 self,
420 agc_settings.target_level,
421 attack_time_limited,
422 release_time_limited,
423 agc_settings.absolute_max_gain,
424 )
425 }
426
427 /// Mixes this sound fading out with another sound fading in for the given duration.
428 ///
429 /// Only the crossfaded portion (beginning of self, beginning of other) is returned.
430 #[inline]
431 fn take_crossfade_with<S: Source>(self, other: S, duration: Duration) -> Crossfade<Self, S>
432 where
433 Self: Sized,
434 Self::Item: FromSample<S::Item>,
435 {
436 crossfade::crossfade(self, other, duration)
437 }
438
439 /// Fades in the sound.
440 #[inline]
441 fn fade_in(self, duration: Duration) -> FadeIn<Self>
442 where
443 Self: Sized,
444 {
445 fadein::fadein(self, duration)
446 }
447
448 /// Fades out the sound.
449 #[inline]
450 fn fade_out(self, duration: Duration) -> FadeOut<Self>
451 where
452 Self: Sized,
453 {
454 fadeout::fadeout(self, duration)
455 }
456
457 /// Applies limiting to prevent audio peaks from exceeding a threshold.
458 ///
459 /// A limiter reduces the amplitude of audio signals that exceed a specified level,
460 /// preventing clipping and maintaining consistent output levels. The limiter processes
461 /// each channel independently for envelope detection but applies gain reduction uniformly
462 /// across all channels to preserve stereo imaging.
463 ///
464 /// # Arguments
465 ///
466 /// * `settings` - [`LimitSettings`] struct containing:
467 /// - **threshold** - Level in dB where limiting begins (must be negative)
468 /// - **knee_width** - Range in dB over which limiting gradually increases
469 /// - **attack** - Time to respond to level increases
470 /// - **release** - Time to recover after level decreases
471 ///
472 /// # Returns
473 ///
474 /// A [`Limit`] source that applies the limiting to the input audio.
475 ///
476 /// # Examples
477 ///
478 /// ## Basic Usage with Default Settings
479 ///
480 /// ```
481 /// use rodio::source::{SineWave, Source, LimitSettings};
482 /// use std::time::Duration;
483 ///
484 /// // Create a loud sine wave and apply default limiting (-1dB threshold)
485 /// let source = SineWave::new(440.0).amplify(2.0);
486 /// let limited = source.limit(LimitSettings::default());
487 /// ```
488 ///
489 /// ## Custom Settings with Builder Pattern
490 ///
491 /// ```
492 /// use rodio::source::{SineWave, Source, LimitSettings};
493 /// use std::time::Duration;
494 ///
495 /// let source = SineWave::new(440.0).amplify(3.0);
496 /// let settings = LimitSettings::default()
497 /// .with_threshold(-6.0) // Limit at -6dB
498 /// .with_knee_width(2.0) // 2dB soft knee
499 /// .with_attack(Duration::from_millis(3)) // Fast 3ms attack
500 /// .with_release(Duration::from_millis(50)); // 50ms release
501 ///
502 /// let limited = source.limit(settings);
503 /// ```
504 fn limit(self, settings: LimitSettings) -> Limit<Self>
505 where
506 Self: Sized,
507 {
508 limit::limit(self, settings)
509 }
510
511 /// Applies a linear gain ramp to the sound.
512 ///
513 /// If `clamp_end` is `true`, all samples subsequent to the end of the ramp
514 /// will be scaled by the `end_value`. If `clamp_end` is `false`, all
515 /// subsequent samples will not have any scaling applied.
516 #[inline]
517 fn linear_gain_ramp(
518 self,
519 duration: Duration,
520 start_value: Float,
521 end_value: Float,
522 clamp_end: bool,
523 ) -> LinearGainRamp<Self>
524 where
525 Self: Sized,
526 {
527 linear_ramp::linear_gain_ramp(self, duration, start_value, end_value, clamp_end)
528 }
529
530 /// Calls the `access` closure on `Self` the first time the source is iterated and every
531 /// time `period` elapses.
532 ///
533 /// Later changes in either `sample_rate()` or `channels_count()` won't be reflected in
534 /// the rate of access.
535 ///
536 /// The rate is based on playback speed, so both the following will call `access` when the
537 /// same samples are reached:
538 /// `periodic_access(Duration::from_secs(1), ...).speed(2.0)`
539 /// `speed(2.0).periodic_access(Duration::from_secs(2), ...)`
540 #[inline]
541 fn periodic_access<F>(self, period: Duration, access: F) -> PeriodicAccess<Self, F>
542 where
543 Self: Sized,
544 F: FnMut(&mut Self),
545 {
546 periodic::periodic(self, period, access)
547 }
548
549 /// Changes the play speed of the sound. Does not adjust the samples, only the playback speed.
550 ///
551 /// # Note:
552 /// 1. **Increasing the speed will increase the pitch by the same factor**
553 /// - If you set the speed to 0.5 this will halve the frequency of the sound
554 /// lowering its pitch.
555 /// - If you set the speed to 2 the frequency will double raising the
556 /// pitch of the sound.
557 /// 2. **Change in the speed affect the total duration inversely**
558 /// - If you set the speed to 0.5, the total duration will be twice as long.
559 /// - If you set the speed to 2 the total duration will be halve of what it
560 /// was.
561 ///
562 /// See [`Speed`] for details
563 #[inline]
564 fn speed(self, ratio: f32) -> Speed<Self>
565 where
566 Self: Sized,
567 {
568 speed::speed(self, ratio)
569 }
570
571 /// Consumes the source and returns a SamplesBuffer
572 ///
573 /// Use `take_duration` on infinite sources (like the microphone source) before
574 /// calling `record` to prevent this from hanging forever.
575 ///
576 /// # Note
577 /// As `SamplesBuffer` only supports a single *samplerate* and *channel count*
578 /// all samples are resampled to the initial samplerate and channel count is.
579 ///
580 /// # Example
581 /// ```no_run
582 ///
583 /// # use rodio::source::SineWave;
584 /// # use rodio::Source;
585 /// # use std::time::Duration;
586 /// let wave = SineWave::new(740.0)
587 /// .amplify(0.2)
588 /// .take_duration(Duration::from_secs(3));
589 /// let wave = wave.record();
590 /// ```
591 fn record(self) -> SamplesBuffer
592 where
593 Self: Sized,
594 {
595 SamplesBuffer::record_source(self)
596 }
597
598 /// Adds a basic reverb effect.
599 ///
600 /// This function requires the source to implement `Clone`. This can be done by using
601 /// `buffered()`.
602 ///
603 /// # Example
604 ///
605 /// ```ignore
606 /// use std::time::Duration;
607 ///
608 /// let source = source.buffered().reverb(Duration::from_millis(100), 0.7);
609 /// ```
610 #[inline]
611 fn reverb(self, duration: Duration, amplitude: Float) -> Mix<Self, Delay<Amplify<Self>>>
612 where
613 Self: Sized + Clone,
614 {
615 let echo = self.clone().amplify(amplitude).delay(duration);
616 self.mix(echo)
617 }
618
619 /// Makes the sound pausable.
620 // TODO: add example
621 #[inline]
622 fn pausable(self, initially_paused: bool) -> Pausable<Self>
623 where
624 Self: Sized,
625 {
626 pausable::pausable(self, initially_paused)
627 }
628
629 /// Makes the sound stoppable.
630 // TODO: add example
631 #[inline]
632 fn stoppable(self) -> Stoppable<Self>
633 where
634 Self: Sized,
635 {
636 stoppable::stoppable(self)
637 }
638
639 /// Adds a method [`Skippable::skip`] for skipping this source. Skipping
640 /// makes Source::next() return None. Which in turn makes the Player skip to
641 /// the next source.
642 fn skippable(self) -> Skippable<Self>
643 where
644 Self: Sized,
645 {
646 skippable::skippable(self)
647 }
648
649 /// Start tracking the elapsed duration since the start of the underlying
650 /// source.
651 ///
652 /// If a speedup and or delay is applied after this that will not be reflected
653 /// in the position returned by [`get_pos`](TrackPosition::get_pos).
654 ///
655 /// This can get confusing when using [`get_pos()`](TrackPosition::get_pos)
656 /// together with [`Source::try_seek()`] as the latter does take all
657 /// speedup's and delay's into account. It's recommended therefore to apply
658 /// track_position after speedup's and delay's.
659 fn track_position(self) -> TrackPosition<Self>
660 where
661 Self: Sized,
662 {
663 position::track_position(self)
664 }
665
666 /// Applies a low-pass filter to the source.
667 /// **Warning**: Probably buggy.
668 #[inline]
669 fn low_pass(self, freq: u32) -> BltFilter<Self>
670 where
671 Self: Sized,
672 Self: Source<Item = Sample>,
673 {
674 blt::low_pass(self, freq)
675 }
676
677 /// Applies a high-pass filter to the source.
678 #[inline]
679 fn high_pass(self, freq: u32) -> BltFilter<Self>
680 where
681 Self: Sized,
682 Self: Source<Item = Sample>,
683 {
684 blt::high_pass(self, freq)
685 }
686
687 /// Applies a low-pass filter to the source while allowing the q (bandwidth) to be changed.
688 #[inline]
689 fn low_pass_with_q(self, freq: u32, q: Float) -> BltFilter<Self>
690 where
691 Self: Sized,
692 Self: Source<Item = Sample>,
693 {
694 blt::low_pass_with_q(self, freq, q)
695 }
696
697 /// Applies a high-pass filter to the source while allowing the q (bandwidth) to be changed.
698 #[inline]
699 fn high_pass_with_q(self, freq: u32, q: Float) -> BltFilter<Self>
700 where
701 Self: Sized,
702 Self: Source<Item = Sample>,
703 {
704 blt::high_pass_with_q(self, freq, q)
705 }
706
707 /// Applies a distortion effect to the sound.
708 #[inline]
709 fn distortion(self, gain: Float, threshold: Float) -> Distortion<Self>
710 where
711 Self: Sized,
712 {
713 distortion::distortion(self, gain, threshold)
714 }
715
716 // There is no `can_seek()` method as it is impossible to use correctly. Between
717 // checking if a source supports seeking and actually seeking the sink can
718 // switch to a new source.
719
720 /// Attempts to seek to a given position in the current source.
721 ///
722 /// As long as the duration of the source is known, seek is guaranteed to saturate
723 /// at the end of the source. For example given a source that reports a total duration
724 /// of 42 seconds calling `try_seek()` with 60 seconds as argument will seek to
725 /// 42 seconds.
726 ///
727 /// # Errors
728 /// This function will return [`SeekError::NotSupported`] if one of the underlying
729 /// sources does not support seeking.
730 ///
731 /// It will return an error if an implementation ran
732 /// into one during the seek.
733 ///
734 /// Seeking beyond the end of a source might return an error if the total duration of
735 /// the source is not known.
736 #[allow(unused_variables)]
737 fn try_seek(&mut self, pos: Duration) -> Result<(), SeekError> {
738 Err(SeekError::NotSupported {
739 underlying_source: std::any::type_name::<Self>(),
740 })
741 }
742}
743
744// We might add decoders requiring new error types, without non_exhaustive
745// this would break users' builds.
746/// Occurs when `try_seek` fails because the underlying decoder has an error or
747/// does not support seeking.
748#[non_exhaustive]
749#[derive(Debug, thiserror::Error, Clone)]
750pub enum SeekError {
751 /// One of the underlying sources does not support seeking
752 #[error("Seeking is not supported by source: {underlying_source}")]
753 NotSupported {
754 /// The source that did not support seek
755 underlying_source: &'static str,
756 },
757 #[cfg(feature = "symphonia")]
758 /// The symphonia decoder ran into an issue
759 #[error("Symphonia decoder returned an error")]
760 SymphoniaDecoder(#[source] crate::decoder::symphonia::SeekError),
761 #[cfg(feature = "hound")]
762 /// The hound (wav) decoder ran into an issue
763 #[error("Hound decoder returned an error")]
764 HoundDecoder(#[source] Arc<std::io::Error>),
765 // Prefer adding an enum variant to using this. It's meant for end users their
766 // own `try_seek` implementations.
767 /// Any other error probably in a custom Source
768 #[error(transparent)]
769 Other(Arc<dyn std::error::Error + Send + Sync + 'static>),
770}
771assert_error_traits!(SeekError);
772
773#[cfg(feature = "symphonia")]
774impl From<crate::decoder::symphonia::SeekError> for SeekError {
775 fn from(source: crate::decoder::symphonia::SeekError) -> Self {
776 SeekError::SymphoniaDecoder(source)
777 }
778}
779
780impl SeekError {
781 /// Will the source remain playing at its position before the seek or is it
782 /// broken?
783 pub fn source_intact(&self) -> bool {
784 match self {
785 SeekError::NotSupported { .. } => true,
786 #[cfg(feature = "symphonia")]
787 SeekError::SymphoniaDecoder(_) => false,
788 #[cfg(feature = "hound")]
789 SeekError::HoundDecoder(_) => false,
790 SeekError::Other(_) => false,
791 }
792 }
793}
794
795macro_rules! source_pointer_impl {
796 ($($sig:tt)+) => {
797 impl $($sig)+ {
798 #[inline]
799 fn current_span_len(&self) -> Option<usize> {
800 (**self).current_span_len()
801 }
802
803 #[inline]
804 fn channels(&self) -> ChannelCount {
805 (**self).channels()
806 }
807
808 #[inline]
809 fn sample_rate(&self) -> SampleRate {
810 (**self).sample_rate()
811 }
812
813 #[inline]
814 fn total_duration(&self) -> Option<Duration> {
815 (**self).total_duration()
816 }
817
818 #[inline]
819 fn try_seek(&mut self, pos: Duration) -> Result<(), SeekError> {
820 (**self).try_seek(pos)
821 }
822 }
823 };
824}
825
826source_pointer_impl!(Source for Box<dyn Source>);
827
828source_pointer_impl!(Source for Box<dyn Source + Send>);
829
830source_pointer_impl!(Source for Box<dyn Source + Send + Sync>);
831
832source_pointer_impl!(<'a, Src> Source for &'a mut Src where Src: Source,);