source: gs3-installations/mars/trunk/sites/mars/collect/amc-essentia/AUDIO-FRAME-TO-ESSENTIA-CSV-FEATURE-FILE.pl@ 36966

Last change on this file since 36966 was 36818, checked in by davidb, 18 months ago

Tweak of RE to work on local file, rather than on that is in 'import/'

  • Property svn:executable set to *
File size: 8.0 KB
Line 
1#!/usr/bin/env perl
2
3use strict;
4use warnings;
5
6
7use Cwd qw(cwd getcwd);
8
9sub get_audio_duration
10{
11 my ($audio_file) = @_;
12
13 my $audio_cmd = "./AUDIO-DURATION.sh $audio_file";
14
15 open(my $fh, '-|', $audio_cmd) or die $!;
16
17 # Just need to read in one line:
18
19 my $audio_duration = <$fh>;
20 chomp($audio_duration);
21
22 # otherwise would do
23 #
24 #while (my $line = <$fh>) {
25 # # Do stuff with each $line.
26 #}
27
28 close($fh);
29
30 return $audio_duration;
31}
32
33sub generate_bespoke_profile
34{
35 my ($startTime, $frame_dur_secs, $profile_template_file,$profile_file) = @_;
36
37 #
38 # Generate bespoke profile_file for this time-slice
39 #
40 open(my $ipfh, '<', $profile_template_file) or die $!;
41 open(my $opfh, '>', $profile_file) or die $!;
42
43 my $endTime = $startTime + $frame_dur_secs;
44
45 while (my $line = <$ipfh>) {
46 chomp($line);
47 $line =~ s/\@startTime\@/$startTime/g;
48 $line =~ s/\@endTime\@/$endTime/g;
49
50 print $opfh "$line\n";
51 }
52
53 close($opfh);
54 close($ipfh);
55}
56
57
58#
59# Extract features and convert to CSV
60#
61sub extract_audio_features_as_csv
62{
63 my ($audio_root,$audio_file,$profile_file,$ignore_fields, $fallback_rec) = @_;
64
65 my $tmp_json_file = "tmp/${audio_root}_essentiafeatures.json";
66 my $tmp_csv_file = "tmp/${audio_root}_essentiafeatures.csv";
67
68 my $extract_cmd = "essentia_streaming_extractor_music $audio_file $tmp_json_file $profile_file";
69 my $extract_status = system($extract_cmd);
70
71 if ($extract_status != 0) {
72 if (($extract_status == 256) && defined($fallback_rec)) {
73 # effectively error status '1'
74 print "$!\n";
75 print "Warning: Failed to run command with exit status 1:\n";
76 print " $extract_cmd\n";
77 print "\n";
78 print "The most likely issue is that the segement of audio process was silence\n";
79 print "=> Generating row of 0 feature values for CSV output\n";
80
81 my @lines = ($fallback_rec->{'headerline'}, $fallback_rec->{'zeroline'});
82 return \@lines;
83 }
84 else {
85
86 print STDERR "$!\n";
87 print STDERR "Error: Failed to run command:\n";
88 print STDERR " $extract_cmd\n";
89 return undef;
90 }
91 }
92
93 my $convert_cmd = "json_to_csv.py -i $tmp_json_file -o $tmp_csv_file --ignore $ignore_fields";
94 my $convert_status = system($convert_cmd);
95
96 # Whatever the outcome of this command, now finished with the tmp_json_file
97 unlink($tmp_json_file) or die "Can't delete $tmp_json_file: $!\n";
98
99 if ($convert_status != 0) {
100 print STDERR "$!\n";
101 print STDERR "Error: Failed to run command:\n";
102 print STDERR " $convert_cmd\n";
103 return undef;
104 }
105
106
107 open(my $ifh, '<', $tmp_csv_file) or die $!;
108
109 # read in lines to array: single line shot
110 chomp(my @lines = <$ifh>);
111
112 # my @lines = ();
113 #
114 # while (my $line = <$ifh>) {
115 # chomp($line);
116 # push(@lines,$line);
117 # }
118
119 close($ifh);
120
121 unlink($tmp_csv_file) or die "Can't delete $tmp_csv_file: $!\n";
122
123 return \@lines;
124}
125
126sub generate_csv_feature_header
127{
128 my $exemplar_inputfile="import/00/ds_20491_4100.m4a";
129
130 # _essentiafeatures_frames.csv
131
132
133}
134
135
136sub ensure_representative_fallback
137{
138 my ($audio_file,$profile_file,$ignore_fields) = @_;
139
140 my $fallback_rec = {};
141
142 my $representative_headerline_file = "etc/representative_header.csv";
143 my $representative_zeroline_file = "etc/representative_zeroline.csv";
144
145 if ((! -f $representative_headerline_file) || (! -f $representative_zeroline_file)) {
146 print "Generating Representative Fallback files for CSV Header and Zero-val files:\n";
147 print " $representative_headerline_file and $representative_zeroline_file\n";
148 print "\n";
149
150 my ($full_audio_root) = ($audio_file =~ m/^(.*)\..+?$/);
151 my ($audio_root) = ($full_audio_root =~ m/^(?:.*\/)?(.*?)$/);
152
153 my $lines = extract_audio_features_as_csv($audio_root,$audio_file,$profile_file,$ignore_fields,undef);
154
155 # Count how many elements in the first line (which is the CSV header)
156 my $header_line = $lines->[0];
157 my @header_line_vals = split(",",$header_line);
158
159 # Build an array full of zeros to match
160 my @zero_vals = ();
161 for my $v (@header_line_vals) {
162 push(@zero_vals,0);
163 }
164
165 my $zero_line = join(",",@zero_vals);
166
167 # output headerline
168 open(my $ofh, '>', $representative_headerline_file) or die $!;
169 print $ofh "$header_line\n";
170 close($ofh);
171
172
173 # output zeroline
174 open($ofh, '>', $representative_zeroline_file) or die $!;
175 print $ofh "$zero_line\n";
176 close($ofh);
177
178 $fallback_rec->{'headerline'} = $header_line;
179 $fallback_rec->{'zeroline'} = $zero_line;
180 }
181 else {
182 # read in files
183 print "Reading in Representative Fallback files for CSV Header and Zero-val files:\n";
184 print " $representative_headerline_file and $representative_zeroline_file\n";
185 print "\n";
186
187 open(my $ifh, '<', $representative_headerline_file) or die $!;
188 chomp(my @header_lines = <$ifh>);
189 close($ifh);
190
191 open($ifh, '<', $representative_zeroline_file) or die $!;
192 chomp(my @zero_lines = <$ifh>);
193 close($ifh);
194
195
196 $fallback_rec->{'headerline'} = $header_lines[0];
197 $fallback_rec->{'zeroline'} = $zero_lines[0];
198
199 }
200
201 return $fallback_rec;
202}
203
204
205sub main
206{
207 my $representative_audio_file = "import/00/ds_20491_4100.m4a";
208
209
210 if (scalar(@ARGV) != 3) {
211 print STDERR "****\n";
212 print STDERR "* Error: incorrect usage\n";
213 print STDERR "* Usage: $0 frame-step-in-secs frame-duration-in-secs audio_input_file\n";
214 print STDERR "****\n";
215 exit(1);
216 }
217
218 my $frame_step_secs = $ARGV[0];
219 my $frame_dur_secs = $ARGV[1];
220
221 my $audio_file = $ARGV[2];
222 my ($full_audio_root) = ($audio_file =~ m/^(.*)\..+?$/);
223 my ($audio_root) = ($full_audio_root =~ m/^(?:.*\/)?(.*?)$/);
224
225
226 if ( ! -d "tmp" ) {
227 print "Creating directory: tmp\n";
228 mkdir("tmp");
229 }
230
231
232 my $csv_file = "${full_audio_root}_essentiafeatures_frames.csv";
233
234 my $pwd = cwd();
235 my $profile_template_file = "$pwd/essentia-2013-2014.profile.in";
236 my $profile_file = "$pwd/essentia-2013-2014.profile";
237
238# knock out any arrays in the JSON extracted features file
239 my $ignore_fields="\
240 lowlevel.barkbands.* \
241 lowlevel.erbbands.* \
242 lowlevel.gfcc.* \
243 lowlevel.melbands.* \
244 lowlevel.melbands128.* \
245 lowlevel.mfcc.* \
246\
247 lowlevel.spectral_contrast_coeffs.* \
248 lowlevel.spectral_contrast_valleys.* \
249\
250 metadata.* \
251\
252 rhythm.beats_loudness_band_ratio.* \
253 rhythm.beats_position.* \
254 rhythm.bpm_histogram.* \
255\
256 tonal.hpcp.* \
257 tonal.chords_histogram.* \
258 tonal.thpcp.*";
259
260 $ignore_fields =~ s/\n//sg;
261
262
263 generate_bespoke_profile(0,$frame_dur_secs,$profile_template_file,$profile_file);
264 my $fallback_rec = ensure_representative_fallback($representative_audio_file,$profile_file,$ignore_fields);
265
266 my $audio_duration = get_audio_duration($audio_file);
267
268 if ( ! -f $csv_file ) {
269
270 print "******\n";
271 print "* Running Essentia music extractor\n";
272 print "* on input file: $audio_file (duration $audio_duration)\n";
273 print "* with profile: $profile_file\n";
274 print "* generating output: $csv_file\n";
275 print "****\n";
276
277 open(my $ofh, '>', $csv_file) or die $!;
278
279 for (my $t=0; $t<$audio_duration; $t+=$frame_step_secs) {
280 ##print "," if ($t>0);
281 print "*\n";
282 print "*\n";
283 print "* ### [Time step: $t]\n";
284 print "*\n";
285 print "*\n";
286
287 generate_bespoke_profile($t,$frame_dur_secs,$profile_template_file,$profile_file);
288
289 my $lines = extract_audio_features_as_csv($audio_root,$audio_file,$profile_file,$ignore_fields, $fallback_rec);
290 if (!defined($lines) ) {
291 next;
292 }
293
294 if ($t == 0) {
295 # output first line from $tmp_csv_file to $csv_file
296 print $ofh $lines->[0], "\n";
297 }
298
299 # append 2nd line of $tmp_json_file (i.e. data vals) to $csv_file
300 print $ofh $lines->[1], "\n";
301
302 # break out of loop if there isn't enough time left for a full $frame_dur_secs
303 my $end_of_next_frame = $t+$frame_step_secs+$frame_dur_secs;
304 last if ($end_of_next_frame > $audio_duration);
305 }
306
307 close($ofh);
308
309 print "******\n";
310
311 }
312 else {
313 print "* Skipping frame-by-frame audio features computation as $csv_file already exists\n";
314 }
315}
316
317main();
318
319
320
Note: See TracBrowser for help on using the repository browser.