Skip to content

Commit

Permalink
bugfixes, benchmarks and ability to analyze only a portion of a track.
Browse files Browse the repository at this point in the history
Updated link to binary.
  • Loading branch information
thomas.friedel committed Apr 3, 2017
1 parent 8d16d24 commit 5662899
Show file tree
Hide file tree
Showing 10 changed files with 457 additions and 30 deletions.
2 changes: 1 addition & 1 deletion README.txt
Expand Up @@ -16,7 +16,7 @@ BPM and key information will be calculated and written to the tags
(KEY_START and BPM fields).

A current build of TrackAnalyzer can be downloaded at
https://dl.dropbox.com/u/367262/TrackAnalyzer.zip
https://www.dropbox.com/s/gevfxcay5mvrv2e/TrackAnalyzer.zip?dl=0

TrackAnalyzer is licensed under the GPL, see gpl.txt.

Expand Down
23 changes: 22 additions & 1 deletion TrackAnalyzer/AudioData.java
Expand Up @@ -112,7 +112,28 @@ public void reduceToMono() {
channels = 1;
}


/**
* cuts the audio file to a shorter version of length duration, starting
* at offset 60 seconds, or earlier if not possible at 60 sec.
* @param duration
*/
public void cutLength(int duration) {
int bps = frameRate * channels;
double[] new_samples = new double[duration * bps];
int start_offset = 60;
// if file too short to start at start_offset, start at length of track - duration
start_offset = Math.min(start_offset*bps, sampleCount-duration*bps);
if (start_offset < 0)
start_offset = 0;
if (duration * bps > sampleCount)
return;
else {
System.arraycopy(samples, start_offset, new_samples, 0, duration*bps);
samples = new_samples;
sampleCount = duration * frameRate;
}
}

public void writeWavFile(String filename) {
try {
String outputfilename = filename;
Expand Down
5 changes: 4 additions & 1 deletion TrackAnalyzer/CommandLineArgs.java
Expand Up @@ -22,6 +22,9 @@ public class CommandLineArgs {
@Parameter(names = "--nobpm", description = "don't detect bpm")
public boolean noBpm = false;

@Parameter(names = "--duration", description = "cut track to length <duration> s for faster analysis")
public int duration = -1;

@Parameter(names = "-l", description = "text file containing list of audio files")
public String filelist = "";

Expand All @@ -30,5 +33,5 @@ public class CommandLineArgs {

public static final String DEBUG = "-debug";
@Parameter(names = DEBUG, description = "Used to debug TrackAnalyzer")
public Boolean debug = Boolean.FALSE;
public boolean debug = false;
}
63 changes: 63 additions & 0 deletions TrackAnalyzer/CommandLineArgsBenchmark.java
@@ -0,0 +1,63 @@
package TrackAnalyzer;

import com.beust.jcommander.Parameter;
import com.beust.jcommander.converters.CommaParameterSplitter;

import java.util.ArrayList;
import java.util.List;

public class CommandLineArgsBenchmark {
@Parameter
public List<String> filenames = new ArrayList<String>();

@Parameter(names = "--duration", description = "cut track to length <duration> s for faster analysis")
public int duration = -1;

@Parameter(names = "-setToneProfile", description = "sets tone profile to one of 6")
public int toneProfile = 4;

@Parameter(names = "-setHopSize", description = "hopsize")
public int hopSize = 8192;

@Parameter(names = "-setOctaves", description = "octaves")
public int octaves = 6;

@Parameter(names = "-setTemporalWindow", description = "temporal window (0-2")
public int temporalWindow = 0;

@Parameter(names = "-setSegmentation", description = "segmentation (0,2)")
public int segmentation = 0;

@Parameter(names = "-setSimilarityMeasure", description = "similarity measure (0-1)")
public int similarityMeasure = 0;

@Parameter(names = "-setDetunedBandweight", description = "bandweight")
public float detunedBandweight = 0.2f;


@Parameter(names = "-setGaussianSigma", description = "gaussian sigma")
public float hcdfGaussianSigma = (float) 8.0;


@Parameter(names = "-setTuningMethod", description = "tuning method")
public int tuningMethod = 0;

@Parameter(names = "-setDirectSkStretch", description = "sets spectral kernal bandwidth (between zero and 4)")
public double directSkStretch = 0.8;

@Parameter(names = "-1", description = "nothing")
public boolean nothing = false;

@Parameter(names = "-l", description = "text file containing list of audio files")
public String filelist = "";

@Parameter(names = "-o", description = "write results to text file")
public String writeList = "";

@Parameter(names = {"--help","-h","-?"}, help = true)
public boolean help;

public static final String DEBUG = "-debug";
@Parameter(names = DEBUG, description = "Used to debug TrackAnalyzer")
public boolean debug = false;
}
2 changes: 1 addition & 1 deletion TrackAnalyzer/CosineHcdf.java
Expand Up @@ -30,7 +30,7 @@
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;

//@todo test this class
public class CosineHcdf extends Segmentation {

@Override
Expand Down
42 changes: 42 additions & 0 deletions TrackAnalyzer/MirexScore.java
@@ -0,0 +1,42 @@
package TrackAnalyzer;

public class MirexScore {
/**
* calculate mirex score between keys a and b (camelot notation)
*
* MIREX score weightings
* Key relation Score
* Exact match (tonic) 1.0
* Perfect Fifth (dominant) 0.5
* Perfect fourth (subdominant) 0.5
* Relative major/minor 0.3
* Parallel major/minor 0.2
* @param camelotA - string of 2 or 3 characters containing camelot key, e.g. 8A
* @param camelotB - string of 2 or 3 characters containing camelot key, e.g. 8A
* @return
*/
public static float mirexScore(String camelotA, String camelotB) {
int a_nr, b_nr;
try {
a_nr = Integer.parseInt(camelotA.substring(0, camelotA.length()-1));
b_nr = Integer.parseInt(camelotB.substring(0, camelotB.length()-1));
} catch(NumberFormatException e) {
return 0;
}
char a_gender = camelotA.charAt(camelotA.length()-1);
char b_gender = camelotB.charAt(camelotB.length()-1);
if (camelotA.equals(camelotB))
return (float)1.0;
else if (((a_nr - b_nr) % 12 == 1 || (b_nr - a_nr) % 12 == 1) &&
a_gender == b_gender)
return (float)0.5;
else if (
(a_gender == 'A' && b_gender == 'B' && (a_nr + 3) % 12 == (b_nr % 12))
||
(a_gender == 'B' && b_gender == 'A' && (a_nr % 12 == (b_nr + 3) % 12))
)
return (float)0.2;
else
return 0;
}
}
63 changes: 42 additions & 21 deletions TrackAnalyzer/TrackAnalyzer.java
Expand Up @@ -65,7 +65,7 @@ public class TrackAnalyzer {
CommandLineArgs c = new CommandLineArgs();
BufferedWriter writeListWriter;
ArrayList<String> filenames = new ArrayList<String>();
public final KeyFinder k;
//public final KeyFinder k;
public final Parameters p;

TrackAnalyzer(String[] args) throws Exception {
Expand Down Expand Up @@ -117,9 +117,18 @@ public class TrackAnalyzer {
Logger.getLogger(TrackAnalyzer.class.getName()).log(Level.SEVERE, null, ex);
}
}
k = new KeyFinder();
p = new Parameters();
p.setHopSize(8192);
//p.setToneProfile(Parameters.tone_profile_t.TONE_PROFILE_KRUMHANSL);
//p.setToneProfile(Parameters.tone_profile_t.);
/*
p.setDirectSkStretch(0.8f);
p.setHopSize(4096);
p.setDetunedBandWeight(0.4f);
p.setHcdfGaussianSigma(16.0f);
p.setOctaves(6);
p.setTemporalWindow(Parameters.temporal_window_t.WINDOW_HANN);
*/
}

/**
Expand Down Expand Up @@ -238,32 +247,44 @@ public boolean updateTags(String filename, String formattedBpm, String key) {
* @return
*/
public boolean analyzeTrack(String filename, boolean writeTags) {
KeyFinder k = new KeyFinder();
String wavfilename = "";
AudioData data = new AudioData();
File temp = null;
File temp2 = null;
try {
temp = File.createTempFile("keyfinder", ".wav");
temp2 = File.createTempFile("keyfinder2", ".wav");
wavfilename = temp.getAbsolutePath();
// Delete temp file when program exits.
temp.deleteOnExit();
temp2.deleteOnExit();
decodeAudioFile(new File(filename), temp, 44100);
decodeAudioFile(temp, temp2);
} catch (Exception ex) {
Logger.getLogger(TrackAnalyzer.class.getName()).log(Level.WARNING, "error while decoding" + filename + ".");
if (temp.length() == 0) {
logDetectionResult(filename, "-", "-", false);
temp.delete();
temp2.delete();
return false;
synchronized (this) {
try {

temp = File.createTempFile("keyfinder", ".wav");
temp2 = File.createTempFile("keyfinder2", ".wav");
wavfilename = temp.getAbsolutePath();
// Delete temp file when program exits.
temp.deleteOnExit();
temp2.deleteOnExit();
if (filename.toLowerCase().endsWith((".wav"))) {
decodeAudioFile(new File(filename), temp2);
} else {
decodeAudioFile(new File(filename), temp, 44100);
decodeAudioFile(temp, temp2);
}
} catch (Exception ex) {
Logger.getLogger(TrackAnalyzer.class.getName()).log(Level.WARNING, "error while decoding" + filename + ".");
if (temp.length() == 0) {
logDetectionResult(filename, "-", "-", false);
temp.delete();
temp2.delete();
return false;
}
}
}

KeyDetectionResult r;
try {
data.loadFromAudioFile(temp2.getAbsolutePath());
synchronized (this) {
data.loadFromAudioFile(temp2.getAbsolutePath());
}
if (c.duration != -1) {
data.cutLength(c.duration);
}
r = k.findKey(data, p);
if (r.globalKeyEstimate == Parameters.key_t.SILENCE) {
System.out.println("SILENCE");
Expand Down Expand Up @@ -327,6 +348,7 @@ private void deleteTempFiles(File temp, File temp2) {
temp2.delete();
}
}

/**
* This is the main loop of the program. For every file in the filenames
* list, the file gets decoded and downsampled to a 4410 hz mono wav file.
Expand Down Expand Up @@ -367,7 +389,6 @@ public void run() throws ExecutionException {
public static void main(String[] args) throws Exception {
TrackAnalyzer ta = new TrackAnalyzer(args);
ta.run();

}

/**
Expand Down

0 comments on commit 5662899

Please sign in to comment.