Skip to content

Instantly share code, notes, and snippets.

@encryptio
Created July 27, 2010 04:13
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save encryptio/491724 to your computer and use it in GitHub Desktop.
sub make_wantcurve {
my ($sr,$size,$pts) = @_;
my @points = sort { $a->[0] <=> $b->[0] } @$pts;
my $want = [];
FREQ: for my $i ( 0 .. $size-1 ) {
my $f = $i/$size*$sr;
if ( $f > $sr/2 ) {
$f = $sr-$f; # ah, imaginary numbers, how i love you so
}
# nearest-neighbor extension to undefined regions
if ( $f <= $points[0][0] ) {
push @$want, $points[0][1];
next;
} elsif ( $f >= $points[-1][0] ) {
push @$want, $points[-1][1];
next;
}
# linear interpolation between the two closest points
my $lower;
my $upper;
{
my ($min, $max) = (0, $#points);
while ( $min < $max ) {
my $mid = floor +($min+$max)/2;
if ( $points[$mid][0] < $f ) {
# this point is okay, check above too
last if $min == $mid;
$min = $mid;
} elsif ( $points[$mid][0] > $f ) {
# this point is not okay, check below only
last if $max == $mid-1;
$max = $mid-1;
} else {
last;
}
}
my $found = (grep { $points[$_][0] < $f } $min .. $max)[-1];
$lower = $points[$found];
$upper = $points[$found+1];
}
die unless defined $lower and defined $upper;
my $p0 = ($f-$lower->[0])/($upper->[0]-$lower->[0]);
my $val = $p0 * $upper->[1] + (1-$p0) * $lower->[1];
push @$want, $val;
}
return $want;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment