Skip to content

Commit

Permalink
Implement int_to_float() function
Browse files Browse the repository at this point in the history
  • Loading branch information
AldaronLau committed Jun 3, 2024
1 parent 4ccd467 commit e6ba68e
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 2 deletions.
60 changes: 60 additions & 0 deletions src/tree/conversions.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/// Convert unsigned 32-bit integer counter to floating point (-1 to 1)
pub(crate) fn int_to_float(int: i32) -> f32 {

Check warning on line 2 in src/tree/conversions.rs

View workflow job for this annotation

GitHub Actions / test (macos-latest, beta)

function `int_to_float` is never used

Check warning on line 2 in src/tree/conversions.rs

View workflow job for this annotation

GitHub Actions / test (ubuntu-latest, beta)

function `int_to_float` is never used

Check warning on line 2 in src/tree/conversions.rs

View workflow job for this annotation

GitHub Actions / test (macos-latest, nightly)

function `int_to_float` is never used

Check warning on line 2 in src/tree/conversions.rs

View workflow job for this annotation

GitHub Actions / test (ubuntu-latest, nightly)

function `int_to_float` is never used

Check warning on line 2 in src/tree/conversions.rs

View workflow job for this annotation

GitHub Actions / test (windows-latest, beta)

function `int_to_float` is never used

Check warning on line 2 in src/tree/conversions.rs

View workflow job for this annotation

GitHub Actions / test (windows-latest, nightly)

function `int_to_float` is never used
// Split sign and magnitude from signed integer
let (uint, sign_bit) = if int < 0 {
((-1 - int) as u32, 1 << 31)
} else {
(int as u32, 0)
};
// Remove sign bit, so that it's not counted in leading zeros, add 1 for
// rounding accuracy
let fraction = (uint << 1) + 1;
// Calculate leading zeros including inferred 1.
let leading_zeros = fraction.leading_zeros();
// Remove leading zeros to subtract from exponent
let fraction = if leading_zeros >= 31 {
0
} else {
// Remove inferred one in addition to leading zeros
fraction << (leading_zeros + 1)
};
// Convert to 24-bit fraction
let fraction = fraction >> 8;
// Round up from extra half
let fraction = fraction + (fraction & 1);
// Remove zeroed-out bit, bringing fraction to 23/24 bits
let fraction = fraction >> 1;
// Clear 24th bit
let fraction = fraction & !(1 << 23);
// Calculate -127 bias exponent
let exponent = (127 - leading_zeros) << 23;

f32::from_bits(sign_bit | exponent | fraction)
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn conversions() {
// Since there are more negative than positive integers, zeros are not
// an exact match between integer and floating point
assert_eq!(int_to_float(i32::MAX), 1.0);
assert_eq!(int_to_float(i32::MAX / 2), 0.5);
assert_eq!(int_to_float(i32::MAX / 4), 0.25);
assert_eq!(int_to_float(4), 4.1909516e-9);
assert_eq!(int_to_float(3), 3.259629e-9);
assert_eq!(int_to_float(2), 2.3283064e-9);
assert_eq!(int_to_float(1), 1.3969839e-9);
assert_eq!(int_to_float(0), 2.0f32.powf(-31.0));
assert_eq!(int_to_float(-1), -2.0f32.powf(-31.0));
assert_eq!(int_to_float(-2), -1.3969839e-9);
assert_eq!(int_to_float(-3), -2.3283064e-9);
assert_eq!(int_to_float(-4), -3.259629e-9);
assert_eq!(int_to_float(-5), -4.1909516e-9);
assert_eq!(int_to_float(i32::MIN / 4), -0.25);
assert_eq!(int_to_float(i32::MIN / 2), -0.5);
assert_eq!(int_to_float(i32::MIN), -1.0);
}
}
1 change: 1 addition & 0 deletions src/tree/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ macro_rules! const_postfix_waveform {

mod chunk;
mod consts;
mod conversions;
pub mod line;
pub mod osc;
mod params;
Expand Down
5 changes: 3 additions & 2 deletions src/tree/osc/osc.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::tree::{Chunk, Data, Wave, consts};
use crate::tree::{consts, Chunk, Data, Wave};

/// Phase oscillator (sawtooth wave)
///
Expand All @@ -18,7 +18,8 @@ where
fn synthesize(&self, data: &mut Data<'_>) -> Chunk {
let mut i = 0;
let mut phase = f32::from_bits(data.state[0]);
let chunk = self.0
let chunk = self
.0
.synthesize(data)
.for_each_sample(|sample| {
let frequency = *sample;
Expand Down

0 comments on commit e6ba68e

Please sign in to comment.