Changeset 35224
- Timestamp:
- 2021-07-03T11:44:55+12:00 (3 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
main/trunk/model-sites-dev/mars/collect/amc-essentia/AUDIO-FRAME-TO-ESSENTIA-CSV-FEATURE-FILE.pl
r34768 r35224 7 7 use Cwd qw(cwd getcwd); 8 8 9 if (scalar(@ARGV) != 3) { 10 print STDERR "****\n"; 11 print STDERR "* Error: incorrect usage\n"; 12 print STDERR "* Usage: $0 frame-step-in-secs frame-duration-in-secs audio_input_file\n"; 13 print STDERR "****\n"; 14 exit(1); 15 } 16 17 my $frame_step_secs = $ARGV[0]; 18 my $frame_dur_secs = $ARGV[1]; 19 20 my $audio_file = $ARGV[2]; 21 my ($full_audio_root) = ($audio_file =~ m/^(.*)\..+?$/); 22 my ($audio_root) = ($full_audio_root =~ m/^.*\/(.*?)$/); 23 24 if ( ! -d "tmp" ) { 25 print "Creating directory: tmp\n"; 26 mkdir("tmp"); 27 } 28 29 my $tmp_json_file = "tmp/${audio_root}_essentiafeatures.json"; 30 my $tmp_csv_file = "tmp/${audio_root}_essentiafeatures.csv"; 31 32 my $csv_file = "${full_audio_root}_essentiafeatures_frames.csv"; 33 34 my $pwd = cwd(); 35 my $profile_template_file = "$pwd/essentia-2013-2014.profile.in"; 36 my $profile_file = "$pwd/essentia-2013-2014.profile"; 37 9 sub 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 33 sub 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 # 61 sub 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 126 sub 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 136 sub 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 205 sub 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 if ( ! -d "tmp" ) { 226 print "Creating directory: tmp\n"; 227 mkdir("tmp"); 228 } 229 230 231 my $csv_file = "${full_audio_root}_essentiafeatures_frames.csv"; 232 233 my $pwd = cwd(); 234 my $profile_template_file = "$pwd/essentia-2013-2014.profile.in"; 235 my $profile_file = "$pwd/essentia-2013-2014.profile"; 236 38 237 # knock out any arrays in the JSON extracted features file 39 my $ignore_fields="\238 my $ignore_fields="\ 40 239 lowlevel.barkbands.* \ 41 240 lowlevel.erbbands.* \ … … 58 257 tonal.thpcp.*"; 59 258 60 $ignore_fields =~ s/\n//sg; 61 62 63 my $audio_cmd = "./AUDIO-DURATION.sh $audio_file"; 64 65 open(my $fh, '-|', $audio_cmd) or die $!; 66 67 # Just need to read in one line: 68 69 my $audio_duration = <$fh>; 70 chomp($audio_duration); 71 72 # otherwise would do 73 # 74 #while (my $line = <$fh>) { 75 # # Do stuff with each $line. 76 #} 77 78 close($fh); 79 80 81 82 if ( ! -f $csv_file ) { 259 $ignore_fields =~ s/\n//sg; 260 261 262 generate_bespoke_profile(0,$frame_dur_secs,$profile_template_file,$profile_file); 263 my $fallback_rec = ensure_representative_fallback($representative_audio_file,$profile_file,$ignore_fields); 264 265 my $audio_duration = get_audio_duration($audio_file); 266 267 if ( ! -f $csv_file ) { 83 268 84 print "******\n"; 85 print "* Running Essentia music extractor\n"; 86 print "* on input file: $audio_file (duration $audio_duration)\n"; 87 print "* with profile: $profile_file\n"; 88 print "* generating output: $csv_file\n"; 89 print "****\n"; 90 91 open(my $ofh, '>', $csv_file) or die $!; 92 93 94 for (my $t=0; $t<$audio_duration; $t+=$frame_step_secs) { 95 ##print "," if ($t>0); 96 print "*\n"; 97 print "*\n"; 98 print "* ### [Time step: $t]\n"; 99 print "*\n"; 100 print "*\n"; 101 102 # 103 # Generate bespoke profile_file for this time-slice 104 # 105 open(my $ipfh, '<', $profile_template_file) or die $!; 106 open(my $opfh, '>', $profile_file) or die $!; 107 108 my $startTime = $t; 109 my $endTime = $t + $frame_dur_secs; 269 print "******\n"; 270 print "* Running Essentia music extractor\n"; 271 print "* on input file: $audio_file (duration $audio_duration)\n"; 272 print "* with profile: $profile_file\n"; 273 print "* generating output: $csv_file\n"; 274 print "****\n"; 110 275 111 while (my $line = <$ipfh>) { 112 chomp($line); 113 $line =~ s/\@startTime\@/$startTime/g; 114 $line =~ s/\@endTime\@/$endTime/g; 115 116 print $opfh "$line\n"; 276 open(my $ofh, '>', $csv_file) or die $!; 277 278 for (my $t=0; $t<$audio_duration; $t+=$frame_step_secs) { 279 ##print "," if ($t>0); 280 print "*\n"; 281 print "*\n"; 282 print "* ### [Time step: $t]\n"; 283 print "*\n"; 284 print "*\n"; 285 286 generate_bespoke_profile($t,$frame_dur_secs,$profile_template_file,$profile_file); 287 288 my $lines = extract_audio_features_as_csv($audio_root,$audio_file,$profile_file,$ignore_fields, $fallback_rec); 289 if (!defined($lines) ) { 290 next; 291 } 292 293 if ($t == 0) { 294 # output first line from $tmp_csv_file to $csv_file 295 print $ofh $lines->[0], "\n"; 296 } 297 298 # append 2nd line of $tmp_json_file (i.e. data vals) to $csv_file 299 print $ofh $lines->[1], "\n"; 300 301 # break out of loop if there isn't enough time left for a full $frame_dur_secs 302 my $end_of_next_frame = $t+$frame_step_secs+$frame_dur_secs; 303 last if ($end_of_next_frame > $audio_duration); 117 304 } 118 119 close($opfh);120 close($ipfh);121 122 #123 # Extract features and convert to CSV124 #125 126 my $extract_cmd = "essentia_streaming_extractor_music $audio_file $tmp_json_file $profile_file";127 my $extract_status = system($extract_cmd);128 if ($extract_status != 0) {129 print STDERR "$!\n";130 print STDERR "Error: Failed to run command:\n";131 print STDERR " $extract_cmd\n";132 next;133 }134 135 my $convert_cmd = "json_to_csv.py -i $tmp_json_file -o $tmp_csv_file --ignore $ignore_fields";136 my $convert_status = system($convert_cmd);137 if ($convert_status != 0) {138 print STDERR "$!\n";139 print STDERR "Error: Failed to run command:\n";140 print STDERR " $convert_cmd\n";141 next;142 }143 144 open(my $ifh, '<', $tmp_csv_file) or die $!;145 146 # read in lines to array: single line shot147 chomp(my @lines = <$ifh>);148 305 149 # my @lines = (); 150 # 151 # while (my $line = <$ifh>) { 152 # chomp($line); 153 # push(@lines,$line); 154 # } 155 156 close($ifh); 306 close($ofh); 157 307 158 if ($t == 0) { 159 # output first line from $tmp_csv_file to $csv_file 160 print $ofh $lines[0], "\n"; 161 } 162 163 # append 2nd line of $tmp_json_file (i.e. data vals) to $csv_file 164 print $ofh $lines[1], "\n"; 165 166 unlink($tmp_json_file) or die "Can't delete $tmp_json_file: $!\n"; 167 unlink($tmp_csv_file) or die "Can't delete $tmp_csv_file: $!\n"; 168 169 # break out of loop if there isn't enough time left for a full $frame_dur_secs 170 my $end_of_next_frame = $t+$frame_step_secs+$frame_dur_secs; 171 last if ($end_of_next_frame > $audio_duration); 172 } 173 174 close($ofh); 175 176 print "******\n"; 177 178 } 179 else { 180 print "* Skipping frame-by-frame audio features computation as $csv_file already exists\n"; 181 } 182 183 184 308 print "******\n"; 309 310 } 311 else { 312 print "* Skipping frame-by-frame audio features computation as $csv_file already exists\n"; 313 } 314 } 315 316 main(); 317 318 319
Note:
See TracChangeset
for help on using the changeset viewer.