Skip to content

Instantly share code, notes, and snippets.

@peyo22
Forked from windytan/whistle-encode.pl
Created November 18, 2015 13:12
Show Gist options
  • Select an option

  • Save peyo22/3e44ec95d4ecc2f2da9f to your computer and use it in GitHub Desktop.

Select an option

Save peyo22/3e44ec95d4ecc2f2da9f to your computer and use it in GitHub Desktop.
whistle encoder
use warnings;
use strict;
my $data = $ARGV[0] // "OHAI!";
my $fs = 96000;
my $fc = 2600;
my $bps = 100;
my $risetime = 0.09;
my $padding = 0.5;
my $f_am = 20;
my $vol_am = 0.18;
my $sig_vol = 1;
my $noise_vol = 4;
my $noise_shift = 1.0;
my $lp_alfa_fm = 0.004;
my $lp_alfa_noise = 0.009;
my $fshift = 0.0769 * $fc;
my $riseband = 0.7 * $fc;
$data = "\xAA\xA7".chr(length($data)).$data;
my $dur = length($data) * 8 / $bps;
my @harmonics = (1, 0.141, 0.022, 0.0398, 0.0282, 0.0063);
my @harmonics_noise = (1, 0.9, 0.8, 0.7, 0.6, 0.5);
open my $stream, '|-', "sox -t .s16 -c 1 -r $fs - whistle.wav"
or die $!;
print $stream pack("s", 0) x ($padding * $fs);
my $t = 0;
my $prevy = 0;
my $prev_f = $fc - $riseband;
my $f, my $f_filt, my $vol;
my $ph_am, my $ph_fm;
for (0.. ($risetime+$dur+$risetime) * $fs) {
$t += 1/$fs;
if ($t < $risetime) {
$f = $fc - $riseband + ($t/$risetime * $riseband);
$vol = $t/$risetime;
$harmonics[0] = ($t < $risetime * .66 ? 0 :
($t-$risetime * .66) / ($risetime * .66));
} elsif ($t > $risetime + $dur) {
$f = $fc - ($t-$dur-$risetime) / $risetime * $riseband;
$vol = 1 - ($t-$dur-$risetime) / $risetime;
$harmonics[0] = ($t-$dur-$risetime > $risetime * .33 ? 0 :
1 - (($t-$dur-$risetime) * .33) / ($risetime * .33));
} else {
$f = $fc;
$harmonics[0] = 1;
my $bitind = int(($t - $risetime) * $bps);
my $byte = substr($data, int($bitind / 8),1);
my $bit = ((ord($byte) >> ($bitind % 8)) & 1);
$f = ($bit-.5)*$fshift + $fc;
$vol = 1;
}
$f_filt = $lp_alfa_fm * $f + (1-$lp_alfa_fm) * $prev_f;
$prev_f = $f_filt;
my $noise = (rand()-.5);
my $noise_filt = $lp_alfa_noise*$noise + (1-$lp_alfa_noise) * $prevy;
$prevy = $noise_filt;
$ph_fm += 2 * 3.14159 * $f_filt / $fs;
$ph_am += 2 * 3.14159 * $f_am / $fs;
my $total = 0;
for (0..$#harmonics) {
my $s = $harmonics[$_] * sin(($_+1) * $ph_fm);
$total += $sig_vol * $s * (1 + $vol_am*sin($ph_am));
$total += $noise_vol * $noise_filt * $harmonics_noise[$_] *
sin(($_+1) * ($ph_fm * $noise_shift));
}
print $stream pack("s", 0.2 * $vol * $total * 0x7FFF);
}
print $stream pack("s", 0) x ($padding * $fs);
close $stream;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment