oxisynth 0.1.0

Rust soundfont synthesizer
Documentation
use std::sync::LazyLock;

static CT2HZ_TAB: LazyLock<[f32; 1200]> = LazyLock::new(|| {
    std::array::from_fn(|i| {
        let i = i as f64;

        f64::powf(2.0, i / 1200.0) as f32
    })
});

static CB2AMP_TAB: LazyLock<[f32; 961]> = LazyLock::new(|| {
    std::array::from_fn(|i| {
        let i = i as f64;

        f64::powf(10.0, i / -200.0) as f32
    })
});

static ATTEN2AMP_TAB: LazyLock<[f32; 1441]> = LazyLock::new(|| {
    std::array::from_fn(|i| {
        let i = i as f64;

        f64::powf(10.0, i / -200.0) as f32
    })
});

static CONCAVE_TAB: LazyLock<[f32; 128]> = LazyLock::new(|| {
    let mut init = [0.0; 128];
    init[0] = 0.0;
    init[127] = 1.0;
    let mut x: f64;
    for i in 1..127 {
        x = -20.0f64 / 96.0 * f64::ln((i * i) as f64 / (127.0 * 127.0)) / f64::ln(10.0);
        init[127 - i] = x as f32;
    }
    init
});

static CONVEX_TAB: LazyLock<[f32; 128]> = LazyLock::new(|| {
    let mut init = [0.0; 128];
    init[0] = 0.0;
    init[127] = 1.0;

    #[allow(clippy::needless_range_loop)]
    for i in 1..127 {
        let x = -20.0 / 96.0 * f64::ln((i * i) as f64 / (127.0 * 127.0)) / f64::ln(10.0);
        init[i] = (1.0 - x) as f32;
    }

    init
});

static PAN_TAB: LazyLock<[f32; 1002]> = LazyLock::new(|| {
    const X: f64 = std::f64::consts::PI / 2.0 / (1002.0 - 1.0);

    std::array::from_fn(|i| {
        let i = i as f64;

        f64::sin(i * X) as f32
    })
});

pub fn ct2hz_real(cents: f32) -> f32 {
    if cents < 0.0 {
        1.0
    } else if cents < 900.0 {
        6.875 * CT2HZ_TAB[cents as usize + 300]
    } else if cents < 2100.0 {
        13.75 * CT2HZ_TAB[cents as usize - 900]
    } else if cents < 3300.0 {
        27.5 * CT2HZ_TAB[cents as usize - 2100]
    } else if cents < 4500.0 {
        55.0 * CT2HZ_TAB[cents as usize - 3300]
    } else if cents < 5700.0 {
        110.0 * CT2HZ_TAB[cents as usize - 4500]
    } else if cents < 6900.0 {
        220.0 * CT2HZ_TAB[cents as usize - 5700]
    } else if cents < 8100.0 {
        440.0 * CT2HZ_TAB[cents as usize - 6900]
    } else if cents < 9300.0 {
        880.0 * CT2HZ_TAB[cents as usize - 8100]
    } else if cents < 10500.0 {
        1760.0 * CT2HZ_TAB[cents as usize - 9300]
    } else if cents < 11700.0 {
        3520.0 * CT2HZ_TAB[cents as usize - 10500]
    } else if cents < 12900.0 {
        7040.0 * CT2HZ_TAB[cents as usize - 11700]
    } else if cents < 14100.0 {
        14080.0 * CT2HZ_TAB[cents as usize - 12900]
    } else {
        1.0
    }
}

pub fn ct2hz(cents: f32) -> f32 {
    ct2hz_real(cents.clamp(1500.0, 13500.0))
}

pub fn cb2amp(cb: f32) -> f32 {
    if cb < 0.0 {
        1.0
    } else if cb >= 961.0 {
        0.0
    } else {
        CB2AMP_TAB[cb as i32 as usize]
    }
}

pub fn atten2amp(atten: f32) -> f32 {
    if atten < 0.0 {
        1.0
    } else if atten >= 1441.0 {
        0.0
    } else {
        ATTEN2AMP_TAB[atten as i32 as usize]
    }
}

pub fn tc2sec_delay(tc: f32) -> f32 {
    if tc <= -32768.0 {
        0.0
    } else {
        let tc = tc.clamp(-12000.0, 5000.0) as f64;
        f64::powf(2.0, tc / 1200.0) as f32
    }
}

pub fn tc2sec_attack(tc: f32) -> f32 {
    if tc <= -32768.0 {
        0.0
    } else {
        let tc = tc.clamp(-12000.0, 8000.0) as f64;
        f64::powf(2.0, tc / 1200.0) as f32
    }
}

pub fn tc2sec(tc: f64) -> f64 {
    f64::powf(2.0, tc / 1200.0)
}

pub fn tc2sec_release(tc: f32) -> f32 {
    if tc <= -32768.0 {
        0.0
    } else {
        let tc = tc.clamp(-12000.0, 8000.0) as f64;
        f64::powf(2.0, tc / 1200.0f64) as f32
    }
}

pub fn act2hz(c: f32) -> f32 {
    (8.176 * f64::powf(2.0, c as f64 / 1200.0f64)) as f32
}

pub fn pan(mut c: f32, left: i32) -> f32 {
    if left != 0 {
        c = -c
    }

    if c < -500.0 {
        0.0
    } else if c > 500.0 {
        1.0
    } else {
        PAN_TAB[(c + 500.0) as usize]
    }
}

pub fn concave(val: f32) -> f32 {
    if val < 0.0 {
        0.0
    } else if val > 127.0 {
        1.0
    } else {
        CONCAVE_TAB[val as usize]
    }
}

pub fn convex(val: f32) -> f32 {
    if val < 0.0 {
        0.0
    } else if val > 127.0 {
        1.0
    } else {
        CONVEX_TAB[val as usize]
    }
}