///|
let max_win : Int = 4096
///|
let min_win : Int = 256
///|
let plan_count : Int = 5
///|
priv struct Plan {
rev : FixedArray[Int]
cos : FixedArray[Double]
sin : FixedArray[Double]
hann : FixedArray[Double]
}
///|
let plans : FixedArray[Plan?] = FixedArray::make(plan_count, None)
///|
fn plan_of(win : Int) -> Int {
if win < min_win || win > max_win || (win & (win - 1)) != 0 {
return -1
}
let i = (@math.log2(win.to_double()) - @math.log2(min_win.to_double())).to_int()
if i >= plan_count {
return -1
}
i
}
///|
fn plan_at(i : Int) -> Plan? {
if i < 0 || i >= plan_count {
None
} else {
plans.unsafe_get(i)
}
}
///|
#export_name("dsp_plan")
pub fn plan(win : Int) -> Int {
let i = plan_of(win)
if i < 0 {
return -1
}
match plans.unsafe_get(i) {
Some(_) => i
None => {
let mut levels = 0
while 1 << levels < win {
levels = levels + 1
}
let rev = FixedArray::make(win, 0)
for k = 0; k < win; k = k + 1 {
let mut r = 0
for b = 0; b < levels; b = b + 1 {
if (k & (1 << b)) != 0 {
r = r | (1 << (levels - 1 - b))
}
}
rev.unsafe_set(k, r)
}
let half = win / 2
let n = win.to_double()
let cos = FixedArray::make(half, 0.0)
let sin = FixedArray::make(half, 0.0)
for k = 0; k < half; k = k + 1 {
let angle = 2.0 * @math.PI * k.to_double() / n
cos.unsafe_set(k, @math.cos(angle))
sin.unsafe_set(k, @math.sin(angle))
}
let hann = FixedArray::make(win, 0.0)
for k = 0; k < win; k = k + 1 {
hann.unsafe_set(
k,
0.5 - 0.5 * @math.cos(2.0 * @math.PI * k.to_double() / n),
)
}
let p : Plan = { rev, cos, sin, hann, }
plans.unsafe_set(i, Some(p))
i
}
}
}
///|
#export_name("dsp_plan_rev")
pub fn plan_rev_of(i : Int) -> FixedArray[Int] {
match plan_at(i) {
Some(p) => p.rev
None => FixedArray::make(0, 0)
}
}
///|
#export_name("dsp_plan_cos")
pub fn plan_cos_of(i : Int) -> FixedArray[Double] {
match plan_at(i) {
Some(p) => p.cos
None => FixedArray::make(0, 0.0)
}
}
///|
#export_name("dsp_plan_sin")
pub fn plan_sin_of(i : Int) -> FixedArray[Double] {
match plan_at(i) {
Some(p) => p.sin
None => FixedArray::make(0, 0.0)
}
}
///|
#export_name("dsp_plan_hann")
pub fn plan_hann_of(i : Int) -> FixedArray[Double] {
match plan_at(i) {
Some(p) => p.hann
None => FixedArray::make(0, 0.0)
}
}