-
Notifications
You must be signed in to change notification settings - Fork 270
feat: add audio dithering support #794
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR introduces audio dithering support to Rodio with four dithering algorithms, while also implementing significant infrastructure improvements across decoders and sources.
Key Changes:
- Audio dithering feature: Adds TPDF, RPDF, GPDF, and HighPass dithering algorithms for quantization noise management
- BitDepth type addition: New type for tracking audio bit depth throughout the audio pipeline
- Decoder improvements: Enhanced seeking, error handling, and configuration for WAV and Vorbis decoders
- Source trait expansion: Added
bits_per_sample()
method and improved seeking error handling
Reviewed Changes
Copilot reviewed 89 out of 91 changed files in this pull request and generated 4 comments.
Show a summary per file
File | Description |
---|---|
src/source/dither.rs | New dithering implementation with four algorithms (TPDF, RPDF, GPDF, HighPass) |
src/common.rs | Adds BitDepth type and updates ChannelCount/SampleRate handling |
src/decoder/wav.rs | Major WAV decoder improvements with better seeking and configuration |
src/decoder/vorbis.rs | Enhanced Vorbis decoder with granule-based seeking and duration scanning |
src/source/mod.rs | Expanded Source trait with bits_per_sample() method and improved SeekError variants |
tests/ | Updated test files to use Path-based decoder APIs instead of File objects |
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
src/decoder/vorbis.rs
Outdated
// Try to find a granule from this position (limited packet scan during binary search) | ||
match find_granule_from_position(data, mid, Some(50)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] The magic number 50 for packet limit should be defined as a named constant to improve code readability and maintainability.
Copilot uses AI. Check for mistakes.
src/decoder/wav.rs
Outdated
}; | ||
// len is number of samples, not bytes, so use samples_to_duration | ||
// Note: hound's len() returns total samples across all channels | ||
let samples_per_channel = len / (channels as u64); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Division by channels as u64 could cause integer truncation issues. The conversion from u16 to u64 for channels should be explicit and the division should handle potential remainders properly.
let samples_per_channel = len / (channels as u64); | |
let channels_u64 = channels as u64; | |
if len % channels_u64 != 0 { | |
eprintln!( | |
"Warning: total number of samples ({}) is not evenly divisible by number of channels ({}). Truncating to {} samples per channel.", | |
len, channels, len / channels_u64 | |
); | |
} | |
let samples_per_channel = len / channels_u64; |
Copilot uses AI. Check for mistakes.
😅 😅 For a minute or two I thought you introduced another ~6k PR. Btw lets add a new rule/convention to keep PR's under 1500 lines. I'll hold myself to that for rewriting the entire audio pipeline. |
…ion for all decoders Major decoder enhancements implementing universal try_seek() support, bit depth detection, and changing decoder selection to prioritize alternative decoders over Symphonia. Key changes: - Universal seeking: All decoders implement try_seek() with SeekMode configuration - Bit depth detection: Added Source::bits_per_sample() for lossless formats - Decoder precedence: Alternative decoders now tried before Symphonia decoders - Enhanced DecoderBuilder: Added scan_duration, total_duration, seek_mode settings - Critical fix: Resolved zero span length issue in Symphonia Ogg Vorbis decoder - Performance: Optimized Vorbis, FLAC, and WAV decoder implementations BREAKING CHANGES: - SeekError::NotSupported renamed to SeekError::SeekingNotSupported - WavDecoder no longer implements ExactSizeIterator - Alternative decoders now take precedence when multiple format features enabled - DecoderBuilder::with_coarse_seek deprecated for with_seek_mode Closes: - #190 - #775
Without this, minimp3 would incorrectly accept WAV files as MP3 when both `minimp3` and Symphonia's `wav` features are enabled.
- Improve clarity and conciseness of doc comments for all decoders - Remove redundant and overly verbose explanations - Add missing details to trait and method docs - Update examples to use consistent file paths and types - Move Settings struct visibility to crate-internal - Refactor Path/PathBuf decoder constructors for optimal hinting - Standardize iterator and trait method documentation across formats - Remove misleading or outdated implementation notes - Fix Zero source bits_per_sample to return None - Update seek test attributes for feature consistency
- Introduce BitDepth as a newtype for non-zero u32 - Update Source trait and all implementations to use Option<BitDepth> - Update decoders, sources, and tests to use BitDepth instead of u32 for bit depth - Replace NonZero usage for sample rate and channel count with SampleRate and ChannelCount types where appropriate - Update documentation and examples to reflect new types fix: change bits_per_sample to return Option<BitDepth>
5286b13
to
98ccef0
Compare
style: cargo fmt
Also replace f32 with Sample where appropriate for consistency
cd1b454
to
01714ce
Compare
Builds on our noise generators to add four dithering algorithms:
Gated by new
dither
feature flag, that's enabled by default.API
Parent branch
This is branched off of #786 which introduces
Source::bits_per_sample()
, because you'll typically want to dither down to:I'll mark this PR for review when that PR is merged.