Index: /gs2-extensions/music-ir-src/trunk/bin/script/pessentia
===================================================================
--- /gs2-extensions/music-ir-src/trunk/bin/script/pessentia	(revision 33105)
+++ /gs2-extensions/music-ir-src/trunk/bin/script/pessentia	(revision 33105)
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+if [ -z "$GEXT_MUSICIR" ] ; then
+  echo "Environment variable GEXT_MUSICIR is not set."
+  echo "Have you sourced setup.bash?"
+  exit -1
+fi
+
+( cd "$GEXT_MUSICIR/lib/python" && \
+  python3 ./pessentia.py $* )
+
+
+
Index: /gs2-extensions/music-ir-src/trunk/perllib/plugins/MusicIRPlugin.pm
===================================================================
--- /gs2-extensions/music-ir-src/trunk/perllib/plugins/MusicIRPlugin.pm	(revision 33104)
+++ /gs2-extensions/music-ir-src/trunk/perllib/plugins/MusicIRPlugin.pm	(revision 33105)
@@ -27,7 +27,8 @@
 package MusicIRPlugin;
 
-use BasePlugin;
+use BaseImporter;
 use jAudioExtractor;
 use jSongMinerExtractor;
+use pEssentiaExtractor;
 
 use strict;
@@ -38,5 +39,5 @@
 
 sub BEGIN {
-    @MusicIRPlugin::ISA = ('BasePlugin', 'jAudioExtractor', 'jSongMinerExtractor');
+    @MusicIRPlugin::ISA = ('BaseImporter', 'jAudioExtractor', 'jSongMinerExtractor', 'pEssentiaExtractor');
 }
 
@@ -44,5 +45,12 @@
     [ 
       { 'name' => "compute_mir_features",
-	'desc' => "{BasePlugin.compute_mir_features}",
+	'desc' => "{BaseImporter.compute_mir_features}",
+	'type' => "enum",
+	'list' => [{'name' => "true",  'desc' => "{common.true}"},
+		   {'name' => "false", 'desc' => "{common.false}"}],
+	'deft' => "false",
+	'reqd' => "no" },
+      { 'name' => "compute_essentia_features",
+	'desc' => "{BaseImporter.compute_essentia_features}",
 	'type' => "enum",
 	'list' => [{'name' => "true",  'desc' => "{common.true}"},
@@ -51,5 +59,5 @@
 	'reqd' => "no" },
       { 'name' => "retrieve_mir_metadata",
-	'desc' => "{BasePlugin.retrieve_mir_metadata}",
+	'desc' => "{BaseImporter.retrieve_mir_metadata}",
 	'type' => "enum",
 	'list' => [{'name' => "true",  'desc' => "{common.true}"},
@@ -58,5 +66,5 @@
 	'reqd' => "no" },
       { 'name' => "process_exp",
-	'desc' => "{BasePlugin.process_exp}",
+	'desc' => "{BaseImporter.process_exp}",
 	'type' => "regexp",
 	'deft' => &get_default_process_exp(),
@@ -83,7 +91,9 @@
     my $jae_self = new jAudioExtractor($pluginlist, $inputargs, $hashArgOptLists,1);
     my $jsme_self = new jSongMinerExtractor($pluginlist, $inputargs, $hashArgOptLists,1);
-    my $base_self = new BasePlugin($pluginlist, $inputargs, $hashArgOptLists);
-
-    my $self = BasePlugin::merge_inheritance($jae_self,$jsme_self,$base_self);
+    my $pee_self = new pEssentiaExtractor($pluginlist, $inputargs, $hashArgOptLists,1);
+
+    my $base_self = new BaseImporter($pluginlist, $inputargs, $hashArgOptLists);
+
+    my $self = BaseImporter::merge_inheritance($jae_self,$jsme_self,$base_self);
 
     return bless $self, $class;
@@ -93,5 +103,5 @@
     my $self = shift (@_);
     
-    return q^(?i)(\.mp3|\.wave?|\.aif[fc]?|\.au|\.snd|\.og[ga])$^; 
+    return q^(?i)(\.mp3|\.wave?|\.aif[fc]?|\.au|\.snd|\.og[ga]|\.m4a)$^; 
 }
 
@@ -103,4 +113,5 @@
     $self->jAudioExtractor::begin(@_);
     $self->jSongMinerExtractor::begin(@_);
+    $self->pEssentiaExtractor::begin(@_);
 }
 
@@ -132,4 +143,19 @@
     }
 
+    if ($self->{'compute_essentia_features'} eq "true")
+    {
+	my $utf8_filename_no_path = $self->filepath_to_utf8($filename_no_path);
+	my $url_encoded_filename = &util::rename_file($utf8_filename_no_path, $self->{'file_rename_method'});
+	
+	my $features_filename = $self->compute_essentia_features($filename_full_path);
+	my ($features_ext) = ($features_filename =~ m/\.([^.]+)$/);
+
+	
+	my $mime_type = ($features_ext eq "json") ? "application/json" : "text/plain";
+	$doc_obj->associate_file($features_filename, "pessentia.$features_ext", 
+				 $mime_type, $top_section);
+
+    }
+
 }
 
Index: /gs2-extensions/music-ir-src/trunk/perllib/plugins/pEssentiaExtractor.pm
===================================================================
--- /gs2-extensions/music-ir-src/trunk/perllib/plugins/pEssentiaExtractor.pm	(revision 33105)
+++ /gs2-extensions/music-ir-src/trunk/perllib/plugins/pEssentiaExtractor.pm	(revision 33105)
@@ -0,0 +1,304 @@
+###########################################################################
+#
+# pEssentiaExtractor - helper plugin that computers audio features for 
+#                        music information retrieval use, using python bindings of Essentia
+#
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 2010 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+package pEssentiaExtractor;
+
+use BaseMediaConverter;
+
+use Cwd;
+
+use FileUtils;
+
+use strict;
+no strict 'refs'; # allow filehandles to be variables and viceversa
+
+
+BEGIN {
+    @pEssentiaExtractor::ISA = ('BaseMediaConverter');
+}
+
+
+my $arguments = [
+    { 'name' => "window_size",
+      'desc' => "{jAudioExtractor.window_size}",
+      'type' => "int",
+      'range' => "128,",
+      'deft' => '512',
+      'reqd' => "no" },
+    { 'name' => "window_overlap",
+      'desc' => "{jAudioExtractor.window_overlap}",
+      'type' => "string",
+      'range' => "0.0",
+      'deft' => '0.0',
+      'reqd' => "no" },
+    { 'name' => "sample_rate",
+      'desc' => "{jAudioExtractor.sample_rate}",
+      'type' => "enum",
+      'list' => [{'name' => "8 kHz",      'desc' => "{jAudioExtractor.8000Hz}"},
+		 {'name' => "11.025 kHz", 'desc' => "{jAudioExtractor.11025Hz}"},
+		 {'name' => "16 kHz",     'desc' => "{jAudioExtractor.16000Hz}"},
+		 {'name' => "22.05 kHz",  'desc' => "{jAudioExtractor.22050Hz}"},
+		 {'name' => "44.1 kHz",   'desc' => "{jAudioExtractor.44100Hz}"} ],
+      'deft' => '16 kHz',
+      'reqd' => "no" },
+    { 'name' => "extracted_data",
+      'desc' => "{pEssentiaExtractor.extracted_data}", # ****** delete or change
+      'type' => "enum",
+      'list' => [{'name' => "Overall and Windowed", 'desc' => "{jAudioExtractor.overall_and_windowed}"},
+		 {'name' => "Windowed only", 'desc' => "{jAudioExtractor.windowed_only}"},
+		 {'name' => "Overall only", 'desc' => "{jAudioExtractor.overall_only}"}],
+      'deft' => 'Overall and Windowed',
+      'reqd' => "no" },
+    { 'name' => "essentia_output_type",
+      'desc' => "{pEssentiaExtractor.output_type}",
+      'type' => "enum",
+      'list' => [
+	  {'name' => "JSON", 'desc' => "{pEssentiaExtractor.json}"},
+	  {'name' => "CSV",  'desc' => "{pEssentiaExtractor.csv}"},
+	  {'name' => "YAML", 'desc' => "{pEssentiaExtractor.yaml}"},
+	  {'name' => "Weka ARFF", 'desc' => "{jAudioExtractor.weka_arff}"}
+	  ],
+      'deft' => 'JSON',
+      'reqd' => "no" }
+    ];
+
+
+
+my $options = { 'name' => "pEssentiaExtractor",
+		'desc' => "{pEssentiaExtractor.desc}",
+		'abstract' => "yes",
+		'inherits' => "yes",
+		'args' => $arguments };
+
+sub new {
+    my ($class) = shift (@_);
+    my ($pluginlist,$inputargs,$hashArgOptLists) = @_;
+    push(@$pluginlist, $class);
+
+    push(@{$hashArgOptLists->{"ArgList"}},@{$arguments});
+    push(@{$hashArgOptLists->{"OptList"}},$options);
+
+    my $self = new BaseMediaConverter($pluginlist, $inputargs, $hashArgOptLists, 1);
+
+    # Set controlling variables
+    my $gsdl_home = $ENV{'GSDLHOME'};
+    my $music_ir_home = $ENV{'GEXT_MUSICIR'};
+
+    my $essentia_output_directory = &util::filename_cat($gsdl_home,"tmp"); # Set the directory to save the the ACE XML output files in
+    if (!FileUtils::directoryExists($essentia_output_directory)) {
+	FileUtils::makeDirectory($essentia_output_directory);
+    }
+    $self->{'essentia_output_directory'} = $essentia_output_directory;
+
+    $self->{'jmir_directory'} = &util::filename_cat($music_ir_home,"lib","java"); # Set the directory holding the jMIR .jar files
+
+
+
+    return bless $self, $class;
+}
+
+
+# Create and save a temporary pEssentia batch file referring to a file to extract
+# features from
+sub prepareTempPEssentiaBatchFile 
+{
+    # ARG Ob1: $new_batch_file_path refers to the path of the temporary batch file to create
+    # ARG Ob2: $model_batch_file_path refers to the path of the model batch file to base the temporary one on
+    # ARG Ob3: $input_music_file_path refers to the file to extract features with
+    # ARG Ob4: $feature_values_file_path refers to the path of the ACE XML Feature Values file that the jMIR component will output to
+    # ARG Ob5: $feature_values_file_path refers to the path of the ACE XML Feature Descriptions file that the jMIR component will output to
+    my ( $self, $new_batch_file_path, $model_batch_file_path, $input_music_file_path, $feature_values_file_path, $feature_descriptions_file_path ) = @_;
+
+    # **** TODO
+    
+    # Retrieve settings for jAudioPlugin and use in batch file that is generated
+    my $sample_rate = $self->{'sample_rate'}; # sample of how to get parameter from Greenstone/GLI
+
+
+    # Read the contents of the model batch file
+    my $batch_file_contents;
+    local $/=undef;
+    open (INPUT, "$model_batch_file_path") or die "Could not read the model jAudio batch file $model_batch_file_path";
+    binmode INPUT;
+    $batch_file_contents = <INPUT>;
+    close INPUT;
+
+    # Set the batch ID tag in the temporary file
+    $batch_file_contents =~ s/<batch ID="SampleJAudioBatch">/<batch ID="$input_music_file_path">/;
+
+    # Set the input file name in the file tag in the temporary file
+    if ($^O eq "cygwin") {
+	$input_music_file_path = `cygpath -m "$input_music_file_path"`;
+	$input_music_file_path=~ s/\s+$//;
+    }
+    $batch_file_contents =~ s/<file><\/file>/<file>$input_music_file_path<\/file>/;
+
+    # Set the feature vales save path in the temporary file
+    if ($^O eq "cygwin") {
+	$feature_descriptions_file_path = `cygpath -m "$feature_descriptions_file_path"`;
+	$feature_descriptions_file_path=~ s/\s+$//;
+    }
+
+    $batch_file_contents =~ s/<destination><\/destination>/<destination>$feature_descriptions_file_path<\/destination>/;
+
+    # Set the feature vales save path in the temporary file
+    if ($^O eq "cygwin") {
+	$feature_values_file_path = `cygpath -m "$feature_values_file_path"`;
+	$feature_values_file_path=~ s/\s+$//;
+    }
+    $batch_file_contents =~ s/<destination><\/destination>/<destination>$feature_values_file_path<\/destination>/;
+
+    # Save the temporary batch file
+    open (OUTPUT, ">$new_batch_file_path") or die "Could not create the temporary jAudio batch file $new_batch_file_path";
+    print OUTPUT "$batch_file_contents";
+    close OUTPUT;
+    
+    # Done
+    return 0;
+}
+
+
+sub compute_essentia_features
+{
+    my $self = shift(@_);
+    my $source_file_path = shift(@_);
+    my $convert_options  = shift(@_) || "";
+
+    my $outhandle = $self->{'outhandle'};
+    my $verbosity = $self->{'verbosity'};
+
+    my $source_file_no_path = &File::Basename::basename($source_file_path);
+
+    print STDERR "******* Essentia: source_file_path = $source_file_path\n\n\n";
+    
+    $self->init_cache_for_file($source_file_path);
+
+    # Determine the full name and path of the output file
+    my $target_file_path;
+    my $feature_values_file_path;
+    my $feature_descriptions_file_path;
+
+    my $target_file_type;
+    if ($self->{'output_type'} eq "CSV") {
+	$target_file_type="csv";
+    }
+    elsif ($self->{'output_type'} eq "YAML") {
+	$target_file_type="xml";
+    }
+    elsif ($self->{'output_type'} eq "ARFF") {
+	$target_file_type="arff";
+    }
+    else {
+	# JSON
+	$target_file_type="json";
+    }
+
+    if ($self->{'enable_cache'}) {
+	my $cached_dir = $self->{'cached_dir'};
+	my $file_root = $self->{'cached_file_root'};
+
+	my $target_file = "$file_root.$target_file_type";
+
+	$target_file_path = &util::filename_cat($cached_dir,$target_file);
+    }
+    else {
+	$target_file_path = &util::get_tmp_filename($target_file_type);
+    }
+
+    # **** Do-over?
+#    if ($self->{'output_type'} eq "ACE XML") {
+#	$feature_values_file_path = $target_file_path;
+#	$feature_values_file_path =~ s/\.xml$/_FV.xml/;
+#
+#	$feature_descriptions_file_path = $target_file_path;
+#	$feature_descriptions_file_path =~ s/\.xml$/_FD.xml/;
+#
+#	# Make target_file_path be the principle file generated by jAudio when using ACE XML
+#	$target_file_path = $feature_values_file_path;
+#    }
+
+    my $essentia_output_directory = $self->{'essentia_output_directory'};
+    my $jmir_directory = $self->{'jmir_directory'};
+
+
+    my $store_cwd = cwd();
+
+    # **** Do-over
+    if (!-d $jmir_directory) {
+	print STDERR "Error: Unable able to find directory '$jmir_directory'\n";
+	print STDERR "       Cannot run pEssentia\n";
+    }
+    elsif (chdir($jmir_directory)) {
+
+	# Run the feature extraction.
+
+	# Specify the name for a temporary pEssentia batch file
+#	my $template_batch_file_path = &util::filename_cat($jmir_directory,"SampleJAudioBatchFile.xml.in");
+#	my $batch_file_path = &util::filename_cat($essentia_output_directory,"tempjaudiobatchfile.xml");
+	
+#	# Create the batch file
+#	$self->prepareTempPEssentiaBatchFile( $batch_file_path, $template_batch_file_path, 
+#					      $source_file_path, $feature_values_file_path, $feature_descriptions_file_path );
+	
+	# Input and Output files to use are stored in the batch_file
+#	my $batch_file_path_os = $batch_file_path;
+
+#	$batch_file_path_os = &util::makeFilenameJavaCygwinCompatible($batch_file_path_os);
+##	if ($^O eq "cygwin") {
+##	    $batch_file_path_os = `cygpath -w "$batch_file_path"`;
+##	    $batch_file_path_os =~ s/\s+$//;
+##	}
+
+	# ****
+	# my $pessentia_cmd = "java -Xmx1024M -jar jaudio.jar $convert_options -b \"$batch_file_path_os\"";
+	my $pessentia_cmd = "pessentia $convert_options \"$source_file_path\" \"$target_file_path\"";
+		
+	# Test the execution path
+	print("EXECUTION CMD: $pessentia_cmd\n");
+    
+	my $print_info = { 'message_prefix' => "pEssentia",
+			   'message' => "Extracting audio features from $source_file_no_path" };
+	
+	my ($regenerated,$result,$had_error) 
+	    = $self->autorun_general_cmd($pessentia_cmd,$source_file_path,$target_file_path,$print_info);
+	
+#	# Delete the pEssentia batch file
+#	unlink($batch_file_path);
+    }
+    else {
+	print STDERR "Error: failed to change directory to '$jmir_directory'\n";
+	print STDERR "       Cannot run pEssentia\n";
+    }
+
+    chdir($store_cwd);
+
+    return ($target_file_path);
+}
+    
+
+
+
+1;	
