also check gaps at end
[soepkiptng.git] / soepkiptng_detect_hidden_track
blob1d9b1101b12ec2f6f8048ae465111137642d7963
1 #!/usr/bin/perl
2 ############################################################################
3 # soepkiptng (c) copyright 2000 Eric Lammerts <eric@lammerts.org>.
4 ############################################################################
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License, version 2, as
7 # published by the Free Software Foundation.
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
14 # A copy of the GNU General Public License is available on the World Wide Web
15 # at `http://www.gnu.org/copyleft/gpl.html'. You can also obtain it by
16 # writing to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 # Boston, MA 02111-1307, USA.
18 ############################################################################
20 my $progdir;
21 BEGIN {
22 use Cwd qw'abs_path cwd';
24 # find program directory
25 $_ = $0;
26 while(-l) {
27 my $l = readlink or die "readlink $_: $!\n";
28 if($l =~ m|^/|) { $_ = $l; } else { s|[^/]*$|/$l|; }
30 m|(.*)/|;
31 $progdir = abs_path($1);
33 unshift @INC, "$progdir/lib";
35 require "$progdir/soepkiptng.lib";
36 $ENV{PATH} = "$progdir/bin:$ENV{PATH}";
38 use strict;
39 use Data::Dumper;
40 use DBI;
41 use Getopt::Std;
43 our ($opt_c, $opt_d, $opt_h, $opt_n, $opt_t);
45 getopts('c:dhnt:');
47 $opt_h and die <<EOF;
48 usage: soepkiptng_detect_hidden_track [-h] [-c configfile] [-t threshold]
49 EOF
51 my %conf;
52 read_configfile(\%conf, $opt_c);
54 my $dbh = DBI->connect("DBI:$conf{'db_type'}:$conf{'db_name'}:$conf{'db_host'}", $conf{'db_user'}, $conf{'db_pass'})
55 or die "can't connect to database";
57 FILE: foreach my $file (@ARGV) {
58 my $path = abs_path($file);
59 my $song = $dbh->selectrow_hashref("SELECT * FROM song WHERE filename = ?", undef, $path);
61 if(open(F, "-|") == 0) {
62 open STDERR, ">&STDOUT";
63 open STDOUT, ">/dev/null";
64 exec "sox", "-V3", $path, "-";
65 die "sox: $!\n";
67 my %prop;
68 while(<F>) {
69 /^([^:]+[^:\s])\s+:\s*(.*\S)/ and $prop{$1} = $2;
71 close F;
72 print Dumper(\%prop) if $opt_d;
73 my $ch = $prop{Channels}
74 or die "$file: number of channels not found\n";
75 my $srate = $prop{"Sample Rate"}
76 or die "$file: sample rate not found\n";
78 open F, "-|", "sox", $path, "-c2", "-traw", "-b16", "-esigned-integer", "-";
79 my ($buf, $off, $start, $len, %sil);
80 while(read F, $buf, 4096) {
81 foreach(unpack("s*", $buf)) {
82 if(abs($_) <= $opt_t) {
83 if(defined($start)) {
84 $len++;
85 } else {
86 $start = $off;
87 $len = 1;
89 } else {
90 $sil{$start} = $len if defined($start) && $len > 44100;
91 $start = undef;
93 $off++;
96 close F;
98 if(defined($start)) { $sil{$start} = $len; }
99 if(!%sil) {
100 print "$file: no gaps detected\n";
101 next;
103 printf "%d %s", $off, Dumper(\%sil) if $opt_d;
105 my ($max, $max2) = sort { $sil{$b} <=> $sil{$a} } keys %sil;
106 if($sil{$max} < $sil{max2} * 2) {
107 print "no clear gap\n" . Dumper(\%sil);
109 my $siloff = $max;
110 my $sillen = $sil{$max};
111 my $trailing = $siloff + $sillen == $off;
112 if($ch > 1) {
113 $siloff = int($siloff / $ch);
114 my $p = $max % $ch;
115 if($p) {
116 $siloff++;
117 $sillen -= ($ch - $p) % $ch;
119 $sillen = int($sillen / $ch);
122 printf <<EOF,
124 Gap from %d length %d (%d:%02d.%03d - %d:%02d.%03d), trailing %ss
126 $file,
127 $siloff, $sillen,
128 $siloff / $srate / 60, ($siloff / $srate) % 60, ($siloff / $srate * 1000) % 1000,
129 ($siloff + $sillen) / $srate / 60, (($siloff + $sillen) / $srate) % 60, (($siloff + $sillen) / $srate * 1000) % 1000,
130 ($trailing? "n/a " : int(($off / $ch - ($siloff + $sillen)) / $srate));
132 next if $opt_n;
134 for(;;) {
135 print STDERR "y) split b) play last 10 sec before a) play after : ";
136 $_ = <STDIN>;
137 if(/b/i) {
138 system "play", "-V3", $path, "trim", sprintf("%ds", $siloff - 10 * $srate), 10;
139 } elsif(/a/i) {
140 system "play", "-V3", $path, "trim", sprintf("%ds", $siloff + $sillen);
141 } elsif(/y/i) {
142 last;
143 } else {
144 next FILE;
148 $dbh->do("UPDATE song SET length=?,trimstart=NULL,trimlength=? WHERE id=?", undef,
149 int($siloff / $srate), $siloff, $song->{id})
150 or die "can't do sql command: " . $dbh->errstr . "\n";
152 if(!$trailing) {
153 delete $song->{id};
154 delete $song->{last_played};
155 delete $song->{mtime};
156 delete $song->{time_added};
157 delete $song->{trimlength};
158 delete $song->{uuid};
159 $song->{title} = "(Bonus Track)";
160 $song->{track}++;
161 $song->{trimstart} = $siloff + $sillen;
162 $song->{length} = int((($off / $ch) - ($siloff + $sillen)) / $srate);
164 my @k = sort keys %$song;
165 $dbh->do(sprintf("INSERT INTO song (%s,time_added) VALUES (%s,now())",
166 join(",", @k), join(",", map { "?" } @k)), undef,
167 map { $song->{$_} } @k)
168 or die "can't do sql command: " . $dbh->errstr . "\n";