Search code examples
javafingerprintmusicg

Java compare two audio files with fingerprint


I want find out, if two audio files are same or one contains the other.

For this I use Fingerprint of musicg

byte[] firstAudio = readAudioFileData("first.mp3");
byte[] secondAudio = readAudioFileData("second.mp3");

FingerprintSimilarityComputer fingerprint = 
            new FingerprintSimilarityComputer(firstAudio, secondAudio);

FingerprintSimilarity fingerprintSimilarity = fingerprint.getFingerprintsSimilarity();

System.out.println("clip is found at " + fingerprintSimilarity.getScore());

to convert audio to byte array I use sound API

public static byte[] readAudioFileData(final String filePath) {
    byte[] data = null;
    try {
        final ByteArrayOutputStream baout = new ByteArrayOutputStream();
        final File file = new File(filePath);
        final AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(file);

        byte[] buffer = new byte[4096];
        int c;
        while ((c = audioInputStream.read(buffer, 0, buffer.length)) != -1) {
            baout.write(buffer, 0, c);
        }
        audioInputStream.close();
        baout.close();
        data = baout.toByteArray();
    } catch (Exception e) {
        e.printStackTrace();
    }
    return data;
}

but when I execute it, I became at fingerprint.getFingerprintsSimilarity() an Exception.

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 15999
at com.musicg.fingerprint.PairManager.getPairPositionList(PairManager.java:133)
at com.musicg.fingerprint.PairManager.getPair_PositionList_Table(PairManager.java:80)
at com.musicg.fingerprint.FingerprintSimilarityComputer.getFingerprintsSimilarity(FingerprintSimilarityComputer.java:71)
at Main.main(Main.java:42)

How can I compare 2 mp3 files with fingerprint in Java?


Solution

  • I never did any audio stuff in Java before, but I looked into your code briefly. I think that musicg only works for WAV files, not for MP3. Thus, you need to convert the files first. A web search reveals that you can e.g. use JLayer for that purpose. The corresponding code looks like this:

    package de.scrum_master.so;
    
    import com.musicg.fingerprint.FingerprintManager;
    import com.musicg.fingerprint.FingerprintSimilarity;
    import com.musicg.fingerprint.FingerprintSimilarityComputer;
    import com.musicg.wave.Wave;
    import javazoom.jl.converter.Converter;
    import javazoom.jl.decoder.JavaLayerException;
    
    public class Application {
      public static void main(String[] args) throws JavaLayerException {
        // MP3 to WAV
        new Converter().convert("White Wedding.mp3", "White Wedding.wav");
        new Converter().convert("Poison.mp3", "Poison.wav");
        // Fingerprint from WAV
        byte[] firstFingerPrint = new FingerprintManager().extractFingerprint(new Wave("White Wedding.wav"));
        byte[] secondFingerPrint = new FingerprintManager().extractFingerprint(new Wave("Poison.wav"));
        // Compare fingerprints
        FingerprintSimilarity fingerprintSimilarity = new FingerprintSimilarityComputer(firstFingerPrint, secondFingerPrint).getFingerprintsSimilarity();
        System.out.println("Similarity score = " + fingerprintSimilarity.getScore());
      }
    }
    

    Of course you should make sure that you do not convert each file again whenever the program starts, i.e. you should check if the WAV files already exist. I skipped this step and reduced the sample code to a minimal working version.