#!/usr/bin/perl use strict; use Audio::DSP; use Math::BigInt; use integer; my ($filename) = @ARGV; #$dsp->audiofile($filename); open(SOURCE_WAV, '<:bytes', $filename); # read header (44 bytes), the last 4 bytes is for data size my $header; my $tmp; read(SOURCE_WAV, $header, 22); # channel my $chan; read(SOURCE_WAV, $chan, 2); $header .= $chan; $chan = unpack('S', $chan); # rate my $rate; read(SOURCE_WAV, $rate, 2); $header .= $rate; $rate = unpack('S', $rate); read(SOURCE_WAV, $tmp, 6); $header .= $tmp; # bytes per sample my $fmt; read(SOURCE_WAV, $fmt, 2); $header .= $fmt; $fmt = 8 * unpack('S', $fmt); read(SOURCE_WAV, $tmp, 6); $header .= $tmp; # size my $size; read(SOURCE_WAV, $size, 4); $size = unpack('l', $size) / 2; # 16bit data # a voice is defined as signal above $min_sound last for $min_sound_time and doesn't include silence last for $max_silent_time my $min_sound = 100; my $min_sound_sec = 10; # per second my $max_silent_sec = 50; # per second my $min_sound_unit = $rate / $min_sound_sec; # second my $max_silent_unit = $rate / $max_silent_sec; # second my $min_pitch = 80; my $buf = 4096; my $dsp = new Audio::DSP(buffer => $buf, channels => $chan, format => $fmt, rate => $rate); $dsp->init() || die $dsp->errstr(); my $total = Math::BigInt->new(0); my $avg_total = Math::BigInt->new(0); my $silent_total = Math::BigInt->new(0); my $silent_avg_total = Math::BigInt->new(0); my $silent_begin = 0; my $silent_end = 0; my $is_sound = 0; my $begin = 0; my $end = 0; my $sound_data = ''; my $file_num = 1; $filename =~ /(.*)[.]wav$/; #my $file_prefix = $1; my $file_prefix = 'sound'; # read the first buffer my $buf_end = -1; my @dt; my $pitch = 0; sub expend_buffer { read(SOURCE_WAV, $tmp, $buf); push(@dt, unpack('s' x ($buf / 2), $tmp)); $buf_end += $buf / 2; } # count 0 point throuh times, this can be a sign of pitch sub count_pitch { my $time_span = 20; return 0 if ($end < $time_span); my $a = $dt[$end - $buf_end - 2]; my $b = $dt[$end - $buf_end - 1]; if ($b < 0 && $a > 0) { for ($end - $buf_end - $time_span .. $end - $buf_end - 3) { return 0 if ($dt[$_] < 0); } } elsif ($b > 0 && $a < 0) { for ($end - $buf_end - $time_span .. $end - $buf_end - 3) { return 0 if ($dt[$_] > 0); } } else { return 0; } $pitch++; } expend_buffer(); ##### Main loop ##### while ($begin < $size) { # print "\rProgress: begin - $begin, end - $end"; while ($total >= $avg_total && $end - $begin < $min_sound_unit && $end < $size) { count_pitch(); $total += abs($dt[$end - $buf_end - 1]); $avg_total += $min_sound; $end++; if ($end > $buf_end) { expend_buffer(); } } if ($end - $begin >= $min_sound_unit) { $is_sound = 1; } elsif ($is_sound) { $silent_begin = ($end + $begin) / 2; $silent_end = $silent_begin; $silent_total = 0; $silent_avg_total = 0; while ($silent_total <= $silent_avg_total && $silent_end - $silent_begin < $max_silent_unit && $silent_end < $size) { $silent_total += abs($dt[$silent_end - $buf_end - 1]); $silent_avg_total += $min_sound; $silent_end++; expend_buffer() if ($silent_end > $buf_end); } if ($silent_end - $silent_begin >= $max_silent_unit) { if ($pitch >= $min_pitch) { $sound_data .= pack('s' x (($end - $begin) / 2), @dt[0 .. ($end - $begin) / 2 - 1]); open(WAV_FILE, '>', "$file_prefix.$file_num.wav"); print WAV_FILE $header; print WAV_FILE pack('l', length($sound_data)); print WAV_FILE $sound_data; close(WAV_FILE); print "\tpitch: $pitch\n"; system("ls -l $file_prefix.$file_num.wav"); $file_num++; $dsp->dwrite($sound_data); } $sound_data = ''; $is_sound = 0; shift @dt for (1 .. ($end - $begin)); $begin = $end; $pitch = 0; $total = 0; $avg_total = 0; } else { $total += abs($dt[$end - $buf_end - 1]); $avg_total += $min_sound; $end++; expend_buffer() if ($end > $buf_end); } } else { $total = 0; $avg_total = 0; shift @dt for (1 .. ($end - $begin)); $begin = $end; $pitch = 0; } if ($is_sound && $end - $begin >= $min_sound_unit) { for (1 .. ($end - $begin) / 2) { $sound_data .= pack('s', shift @dt); } $begin = ($begin + $end) / 2; $end = $begin; $total = 0; $avg_total = 0; } } # process the last sound part if ($is_sound) { $sound_data .= shift @dt for (1 .. ($end - $begin) / 2); open(WAV_FILE, '>', "$file_prefix.$file_num.wav"); print WAV_FILE $header; print WAV_FILE pack('l', length($sound_data)); print WAV_FILE $sound_data; close(WAV_FILE); $dsp->dwrite($sound_data); } $dsp->close(); close(SOURCE_WAV);