mirror of
https://github.com/librespot-org/librespot.git
synced 2024-12-18 17:11:53 +00:00
Improve sample rounding and clean up noise shaping leftovers (#771)
This commit is contained in:
parent
a2fde0a1d6
commit
8062bd2518
4 changed files with 89 additions and 24 deletions
85
Cargo.lock
generated
85
Cargo.lock
generated
|
@ -435,6 +435,12 @@ dependencies = [
|
||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fuchsia-cprng"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures"
|
name = "futures"
|
||||||
version = "0.3.15"
|
version = "0.3.15"
|
||||||
|
@ -1073,6 +1079,15 @@ version = "0.2.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c7d73b3f436185384286bd8098d17ec07c9a7d2388a6599f824d8502b529702a"
|
checksum = "c7d73b3f436185384286bd8098d17ec07c9a7d2388a6599f824d8502b529702a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libmath"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dfd3416934a853ae80d5c3b006f632dfcbaf320300c5167e88a469e9ac214502"
|
||||||
|
dependencies = [
|
||||||
|
"rand 0.3.23",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libmdns"
|
name = "libmdns"
|
||||||
version = "0.6.1"
|
version = "0.6.1"
|
||||||
|
@ -1085,7 +1100,7 @@ dependencies = [
|
||||||
"if-addrs",
|
"if-addrs",
|
||||||
"log",
|
"log",
|
||||||
"multimap",
|
"multimap",
|
||||||
"rand",
|
"rand 0.8.3",
|
||||||
"socket2",
|
"socket2",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"tokio",
|
"tokio",
|
||||||
|
@ -1190,7 +1205,7 @@ dependencies = [
|
||||||
"librespot-protocol",
|
"librespot-protocol",
|
||||||
"log",
|
"log",
|
||||||
"protobuf",
|
"protobuf",
|
||||||
"rand",
|
"rand 0.8.3",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"tokio",
|
"tokio",
|
||||||
|
@ -1223,7 +1238,7 @@ dependencies = [
|
||||||
"pbkdf2",
|
"pbkdf2",
|
||||||
"priority-queue",
|
"priority-queue",
|
||||||
"protobuf",
|
"protobuf",
|
||||||
"rand",
|
"rand 0.8.3",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"sha-1",
|
"sha-1",
|
||||||
|
@ -1254,7 +1269,7 @@ dependencies = [
|
||||||
"libmdns",
|
"libmdns",
|
||||||
"librespot-core",
|
"librespot-core",
|
||||||
"log",
|
"log",
|
||||||
"rand",
|
"rand 0.8.3",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"sha-1",
|
"sha-1",
|
||||||
"simple_logger",
|
"simple_logger",
|
||||||
|
@ -1288,6 +1303,7 @@ dependencies = [
|
||||||
"gstreamer-app",
|
"gstreamer-app",
|
||||||
"jack 0.7.1",
|
"jack 0.7.1",
|
||||||
"lewton",
|
"lewton",
|
||||||
|
"libmath",
|
||||||
"libpulse-binding",
|
"libpulse-binding",
|
||||||
"libpulse-simple-binding",
|
"libpulse-simple-binding",
|
||||||
"librespot-audio",
|
"librespot-audio",
|
||||||
|
@ -1296,7 +1312,7 @@ dependencies = [
|
||||||
"log",
|
"log",
|
||||||
"ogg",
|
"ogg",
|
||||||
"portaudio-rs",
|
"portaudio-rs",
|
||||||
"rand",
|
"rand 0.8.3",
|
||||||
"rand_distr",
|
"rand_distr",
|
||||||
"rodio",
|
"rodio",
|
||||||
"sdl2",
|
"sdl2",
|
||||||
|
@ -1488,7 +1504,7 @@ dependencies = [
|
||||||
"autocfg",
|
"autocfg",
|
||||||
"num-integer",
|
"num-integer",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
"rand",
|
"rand 0.8.3",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1840,6 +1856,29 @@ dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand"
|
||||||
|
version = "0.3.23"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "64ac302d8f83c0c1974bf758f6b041c6c8ada916fbb44a609158ca8b064cc76c"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"rand 0.4.6",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand"
|
||||||
|
version = "0.4.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293"
|
||||||
|
dependencies = [
|
||||||
|
"fuchsia-cprng",
|
||||||
|
"libc",
|
||||||
|
"rand_core 0.3.1",
|
||||||
|
"rdrand",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rand"
|
name = "rand"
|
||||||
version = "0.8.3"
|
version = "0.8.3"
|
||||||
|
@ -1848,7 +1887,7 @@ checksum = "0ef9e7e66b4468674bfcb0c81af8b7fa0bb154fa9f28eb840da5c447baeb8d7e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"rand_chacha",
|
"rand_chacha",
|
||||||
"rand_core",
|
"rand_core 0.6.2",
|
||||||
"rand_hc",
|
"rand_hc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -1859,9 +1898,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d"
|
checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ppv-lite86",
|
"ppv-lite86",
|
||||||
"rand_core",
|
"rand_core 0.6.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_core"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
|
||||||
|
dependencies = [
|
||||||
|
"rand_core 0.4.2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_core"
|
||||||
|
version = "0.4.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rand_core"
|
name = "rand_core"
|
||||||
version = "0.6.2"
|
version = "0.6.2"
|
||||||
|
@ -1878,7 +1932,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "da9e8f32ad24fb80d07d2323a9a2ce8b30d68a62b8cb4df88119ff49a698f038"
|
checksum = "da9e8f32ad24fb80d07d2323a9a2ce8b30d68a62b8cb4df88119ff49a698f038"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"num-traits",
|
"num-traits",
|
||||||
"rand",
|
"rand 0.8.3",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1887,7 +1941,16 @@ version = "0.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73"
|
checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"rand_core",
|
"rand_core 0.6.2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rdrand"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
|
||||||
|
dependencies = [
|
||||||
|
"rand_core 0.3.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -2212,7 +2275,7 @@ checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if 1.0.0",
|
"cfg-if 1.0.0",
|
||||||
"libc",
|
"libc",
|
||||||
"rand",
|
"rand 0.8.3",
|
||||||
"redox_syscall",
|
"redox_syscall",
|
||||||
"remove_dir_all",
|
"remove_dir_all",
|
||||||
"winapi",
|
"winapi",
|
||||||
|
|
|
@ -20,6 +20,7 @@ version = "0.2.0"
|
||||||
[dependencies]
|
[dependencies]
|
||||||
futures-executor = "0.3"
|
futures-executor = "0.3"
|
||||||
futures-util = { version = "0.3", default_features = false, features = ["alloc"] }
|
futures-util = { version = "0.3", default_features = false, features = ["alloc"] }
|
||||||
|
libmath = "0.2"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
byteorder = "1.4"
|
byteorder = "1.4"
|
||||||
shell-words = "1.0.0"
|
shell-words = "1.0.0"
|
||||||
|
|
|
@ -32,18 +32,19 @@ impl Converter {
|
||||||
|
|
||||||
// Denormalize and dither
|
// Denormalize and dither
|
||||||
pub fn scale(&mut self, sample: f32, factor: i64) -> f32 {
|
pub fn scale(&mut self, sample: f32, factor: i64) -> f32 {
|
||||||
|
let dither = match self.ditherer {
|
||||||
|
Some(ref mut d) => d.noise(),
|
||||||
|
None => 0.0,
|
||||||
|
};
|
||||||
|
|
||||||
// From the many float to int conversion methods available, match what
|
// From the many float to int conversion methods available, match what
|
||||||
// the reference Vorbis implementation uses: sample * 32768 (for 16 bit)
|
// the reference Vorbis implementation uses: sample * 32768 (for 16 bit)
|
||||||
let int_value = sample * factor as f32;
|
let int_value = sample * factor as f32 + dither;
|
||||||
|
|
||||||
// https://doc.rust-lang.org/nomicon/casts.html: casting float to integer
|
// Casting float to integer rounds towards zero by default, i.e. it
|
||||||
// rounds towards zero, then saturates. Ideally halves should round to even to
|
// truncates, and that generates larger error than rounding to nearest.
|
||||||
// prevent any bias, but since it is extremely unlikely that a float has
|
// Absolute lowest error is gained from rounding ties to even.
|
||||||
// *exactly* .5 as fraction, this should be more than precise enough.
|
math::round::half_to_even(int_value.into(), 0) as f32
|
||||||
match self.ditherer {
|
|
||||||
Some(ref mut d) => int_value + d.noise(int_value),
|
|
||||||
None => int_value,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Special case for samples packed in a word of greater bit depth (e.g.
|
// Special case for samples packed in a word of greater bit depth (e.g.
|
||||||
|
|
|
@ -32,7 +32,7 @@ pub trait Ditherer {
|
||||||
where
|
where
|
||||||
Self: Sized;
|
Self: Sized;
|
||||||
fn name(&self) -> &'static str;
|
fn name(&self) -> &'static str;
|
||||||
fn noise(&mut self, sample: f32) -> f32;
|
fn noise(&mut self) -> f32;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for dyn Ditherer {
|
impl fmt::Display for dyn Ditherer {
|
||||||
|
@ -64,7 +64,7 @@ impl Ditherer for TriangularDitherer {
|
||||||
"Triangular"
|
"Triangular"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn noise(&mut self, _sample: f32) -> f32 {
|
fn noise(&mut self) -> f32 {
|
||||||
self.distribution.sample(&mut self.cached_rng)
|
self.distribution.sample(&mut self.cached_rng)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -87,7 +87,7 @@ impl Ditherer for GaussianDitherer {
|
||||||
"Gaussian"
|
"Gaussian"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn noise(&mut self, _sample: f32) -> f32 {
|
fn noise(&mut self) -> f32 {
|
||||||
self.distribution.sample(&mut self.cached_rng)
|
self.distribution.sample(&mut self.cached_rng)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -113,7 +113,7 @@ impl Ditherer for HighPassDitherer {
|
||||||
"Triangular, High Passed"
|
"Triangular, High Passed"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn noise(&mut self, _sample: f32) -> f32 {
|
fn noise(&mut self) -> f32 {
|
||||||
let new_noise = self.distribution.sample(&mut self.cached_rng);
|
let new_noise = self.distribution.sample(&mut self.cached_rng);
|
||||||
let high_passed_noise = new_noise - self.previous_noises[self.active_channel];
|
let high_passed_noise = new_noise - self.previous_noises[self.active_channel];
|
||||||
self.previous_noises[self.active_channel] = new_noise;
|
self.previous_noises[self.active_channel] = new_noise;
|
||||||
|
|
Loading…
Reference in a new issue