rodio/source/
mod.rs

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