Skip to content

Commit

Permalink
documentation work
Browse files Browse the repository at this point in the history
  • Loading branch information
JorenSix committed Aug 19, 2022
1 parent 8452109 commit 123ccd8
Show file tree
Hide file tree
Showing 25 changed files with 440 additions and 162 deletions.
4 changes: 2 additions & 2 deletions README.textile
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ The Panako repository is organized as follows:
* @resources@ default configuration settings, script for evaluation and to analyze results and schemas to document Panako.


To compile Panako, a Java JDK 11 or later is required. See, for example the "OpenJDK website":https://openjdk.org/install/", for installation instructions for your operating system.
To compile Panako, a Java JDK 11 or later is required. See, for example the "OpenJDK website":https://openjdk.org/install/", for installation instructions for your operating system.

Panako uses the "Gradle":https://gradle.org/ build system. If Gradle is not present on your system it is automatically installed by the @gradlew@ script. To build and install Panako, the following should get you started:

Expand Down Expand Up @@ -353,6 +353,6 @@ h2(#changelog). Changelog
* A new set of helper scripts are added in the @scripts@ directory. They help with evaluation, parsing results, checking results, building panako, creating documentation,...
* Changed the default panako location to ~/.panako, so users can install and use panako more easily (withouth need for sudo rights)

<dt>Version 2.1</dt><dd>2022-05</dd> Changed the build system to "Gradle":https://gradle.org/, mainly to make upgrading dependencies more straightforward. The folder structure has been changed accordingly. The default JDK target has been changed to Java SE 11 (LTS). Panako now also supports Apple M1 targets.
<dt>Version 2.1</dt><dd>2022-05</dd> Changed the build system to "Gradle":https://gradle.org/, mainly to make upgrading dependencies more straightforward. The folder structure has been changed accordingly. The default JDK target has been changed to Java SE 17 (LTS). Panako now also supports Apple M1 targets.


3 changes: 3 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ plugins {
group 'be.panako'
version '2.1'

sourceCompatibility = 1.11
targetCompatibility = 1.11

repositories {
mavenCentral()
maven { url 'https://oss.sonatype.org/content/repositories/snapshots' }
Expand Down
1 change: 1 addition & 0 deletions gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

2 changes: 1 addition & 1 deletion paper.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ Alternative systems with available implementations are by @neuralfp and audfprin

Simplicity and maintainability are two keywords in the design of Panako. The code aims to be as readable and simple as possible. The second version of Panako is a complete rewrite to ensure this simplicity while still keeping query and computational performance in check.

Relying on conservative platforms with a long history of backwards compatibility should allow Panako to stand the test of time. Panako is developed in Java and targets the long term support release Java SE 17. Panako also relies on software in C and C++. Java, C and C++ have been around for decades and it is reasonable to assume that these platforms will be supported for decades to come. Boring technoloy enables longevity.
Relying on conservative platforms with a long history of backwards compatibility should allow Panako to stand the test of time. Panako is developed in Java and targets the long term support release Java SE 11. Panako also relies on software in C and C++. Java, C and C++ have been around for decades and it is reasonable to assume that these platforms will be supported for decades to come. Boring technoloy enables longevity.

Next to Java 11, Panako depends on three libraries: a DSP library, a key-value store and a spectral transform library. The first is a pure Java DSP library called TarsosDSP[^1] [@six2014tarsosdsp]. LMDB[^2] is used as a high performance key-value store. It is a C library and accessible through lmdbjava. The third and final dependency is JGaborator[^3]: a wrapper around the Gaborator[^4] library which implements a constant-Q non-stationary Gabor transform in C++11 [@velasco2011constructing]. The last two have native compiled parts and need to be ported to new or exotic platforms if the need arises. The transition to aarch64 (Apple M1), for example consisted of a straightforward compilation step and repackaging of this native library. Panako can be containerized and the Docker file supports both ARM and x86 platforms and always compiles these native dependencies.

Expand Down
2 changes: 0 additions & 2 deletions src/main/java/be/panako/cli/Clear.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,8 @@

package be.panako.cli;


import be.panako.strategy.Strategy;


/**
* A command line application to clear all items from the index.
*/
Expand Down
50 changes: 47 additions & 3 deletions src/main/java/be/panako/strategy/QueryResult.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,23 +39,63 @@

package be.panako.strategy;

/**
* A data class representing a query result
*/
public class QueryResult {

//query info
public final String queryPath;
/**
* The path of the query
*/
public final String queryPath;
/**
* The start of the match in the query, in seconds.
*/
public final double queryStart;
/**
* The end of the match in the query, in seconds.
*/
public final double queryStop;

//ref info
/**
* The internal identifier of the matching audio
*/
public final String refIdentifier;
/**
* The path of the matching audio
*/
public final String refPath;
/**
* The start of the match in the reference audio, in seconds.
*/
public final double refStart;
/**
* The end of the match in the reference audio, in seconds.
*/
public final double refStop;

//match info
/**
* The start of the match in the reference audio, in seconds.
*/
public final double score;
/**
* The amount of time stretching that needs to be applied to the query to match the reference audio.
*
*/
public final double timeFactor;
/**
* The amount of pitch shifting that needs to be applied to the query to match the reference audio.
* A percentage which is expected to be between 0.8 and 1.2
*/
public final double frequencyFactor;
/**
* If the match has a duration of 10 seconds but only the first and last second contain all the matches,
* this indicates an unreliable match. 2/10 = 0.2 would be the percentage.
* If all seconds also have matches then it is 1.0.
*/
public final double percentOfSecondsWithMatches;

/**
Expand All @@ -78,6 +118,10 @@ public class QueryResult {
* The factor (percentage) of change in frequency. 110 means 10%
* higher frequency compared to the reference. 90 means a 10%
* lower frequency.
* @param percentOfSecondsWithMatches
* If the match has a duration of 10 seconds but only the first and last second contain all the matches,
* this indicates an unreliable match. 2/10 = 0.2 would be the percentage.
* If all seconds also have matches then it is 1.0.
*/
public QueryResult(String queryPath,
double queryStart,
Expand Down Expand Up @@ -114,11 +158,11 @@ public QueryResult(String query, double queryStart, double queryStop, String ref
}



/*
public QueryResult(String queryPath,double queryStart,double queryStop, String refPath, String refIdentifier, double refStart, double refStop, double score,double timeFactor, double frequencyFactor){
this( queryPath, queryStart, queryStop, refPath, refIdentifier, refStart, refStop, score, timeFactor, frequencyFactor,0);
}
*/



Expand Down
18 changes: 10 additions & 8 deletions src/main/java/be/panako/strategy/QueryResultHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,20 +32,22 @@
* *
****************************************************************************/






package be.panako.strategy;

/**
* An interface to return result to a caller.
*/
public interface QueryResultHandler {

/**
* Handle the result of a query.
* @param result The result to handle
*/
public void handleQueryResult(QueryResult result);

public void handleEmptyResult(QueryResult result);
void handleQueryResult(QueryResult result);

/**
* This indicates that no result has been found.
* @param result The empty result
*/
void handleEmptyResult(QueryResult result);
}
3 changes: 2 additions & 1 deletion src/main/java/be/panako/strategy/olaf/OlafEventPoint.java
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,8 @@ public class OlafEventPoint {
/**
* Create a new event point with a time, frequency and energy and contrast..
* @param t The time expressed using an analysis frame index.
* @param f The frequency expressed using the bin number in the constant Q transform.
* @param f The frequency expressed using the bin number in the FFT transform.
* @param m The magnitude of the FFT-bin.
*/
public OlafEventPoint(final int t, final int f, final float m){
this.t = t;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
import be.tarsos.dsp.util.fft.HammingWindow;

/**
* A TarsosDSP AudioProcessor which steps through
* A TarsosDSP AudioProcessor which steps through the audio and returns peaks in the spectrogram.
*/
public class OlafEventPointProcessor implements AudioProcessor {

Expand Down
65 changes: 56 additions & 9 deletions src/main/java/be/panako/strategy/olaf/OlafFingerprint.java
Original file line number Diff line number Diff line change
Expand Up @@ -43,21 +43,62 @@
* @author Joren Six
*/
public class OlafFingerprint {


/**
* time component of the event point 1
*/
public final int t1;
/**
* frequency component of the event point 1
*/
public final int f1;
/**
* magnitude component of the event point 1
*/
public final float m1;



/**
* time component of the event point 2
*/
public final int t2;
/**
* frequency component of the event point 2
*/
public final int f2;
/**
* magnitude component of the event point 2
*/
public final float m2;



/**
* time component of the event point 3
*/
public final int t3;
/**
* frequency component of the event point 3
*/
public final int f3;
/**
* magnitude component of the event point 3
*/
public final float m3;

private long hash;


/**
* Creates a new fingerprint based on three event points with each three components
* @param t1 time component of the event point 1
* @param f1 frequency component of the event point 1
* @param m1 time component of the event point 1
* @param t2 magnitude component of the event point 2
* @param f2 frequency component of the event point 2
* @param m2 magnitude component of the event point 2
* @param t3 time component of the event point 3
* @param f3 frequency component of the event point 3
* @param m3 magnitude component of the event point 3
*/
public OlafFingerprint(int t1,int f1,float m1,int t2,int f2,float m2,int t3,int f3,float m3){
this.t1 = t1;
this.f1 = f1;
Expand Down Expand Up @@ -89,8 +130,14 @@ public OlafFingerprint(long hash,int t1){
this.t3 = -1;
this.f3 = -1;
this.m3 = -1;
}

}

/**
* Creates a new fingerprint based on three event points
* @param e1 Event point 1
* @param e2 Event point 2
* @param e3 Event point 3
*/
public OlafFingerprint(OlafEventPoint e1, OlafEventPoint e2, OlafEventPoint e3){
this(e1.t,e1.f,e1.m, e2.t,e2.f,e2.m, e3.t,e3.f,e3.m);
}
Expand Down Expand Up @@ -139,7 +186,7 @@ public long hash(){
return hash;
}


@Override
public String toString(){
return String.format("(%d,%d),(%d,%d),(%d,%d),%d",t1,f1,t2,f2,t3,f3,hash());
}
Expand All @@ -164,14 +211,14 @@ public boolean equals(Object other){

/*
* This is not completely consistent with the expected hash code / equals
* behavior: It is very well possible that that two hashes collide, while
* behavior: It is very well possible that two hashes collide, while
* the fingerprints are not equal to each other. Implementing hash code makes
* sure no identical fingerprints are added, but also that no collisions are
* allowed. Take care when using sets.
*/
public int hashCode(){
//This is not completely consistent with the expected hash code / equals behavior:
//It is very well possible that that two hashes collide, while the fingerprints are not equal to each other.
//It is very well possible that two hashes collide, while the fingerprints are not equal to each other.
//Implementing hash code makes sure no identical fingerprints are added, but also that no collisions are
//allowed. Take care when using sets.
return (int) hash();
Expand Down
13 changes: 10 additions & 3 deletions src/main/java/be/panako/strategy/olaf/OlafMatch.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,12 @@

package be.panako.strategy.olaf;

/**
* A data class representing matching fingerprints
*/
public class OlafMatch {



public long matchedNearHash;

public long originalHash;
Expand All @@ -54,8 +58,11 @@ public class OlafMatch {
* Time in blocks in the query.
*/
public int queryTime;



/**
* The time difference between the indexed and query times
* @return The time difference between the indexed and query times
*/
public int deltaT() {
return matchTime - queryTime;
}
Expand Down
12 changes: 11 additions & 1 deletion src/main/java/be/panako/strategy/olaf/OlafStrategy.java
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,14 @@
import be.tarsos.dsp.AudioDispatcher;
import be.tarsos.dsp.io.jvm.AudioDispatcherFactory;

/**
* The algorithm implemented here is inspired by the 'shazam' algorithm but does differ in a few crucial elements.
*
* A fingerprint consists of three spectral peaks
* The matching step allows for moderate time stretching amounts
*
*
*/
public class OlafStrategy extends Strategy {
private static final int MAX_TIME = 5_000_000;

Expand Down Expand Up @@ -231,11 +239,13 @@ private int mostCommonDeltaTforHitList(List<OlafMatch> hitList) {
}
return mostCommonDeltaT;
}

@Override
public void query(String query, int maxNumberOfResults, Set<Integer> avoid, QueryResultHandler handler) {
query(query,maxNumberOfResults,avoid,handler,0,MAX_TIME);
}



public void query(String query, int maxNumberOfResults, Set<Integer> avoid, QueryResultHandler handler, double startTimeOffset,double numberOfSeconds ) {

final String queryPath ;
Expand Down
Loading

0 comments on commit 123ccd8

Please sign in to comment.