Skip to content

Fingerprinting

Hirdaya Shrestha edited this page Oct 3, 2026 · 1 revision

Fingerprinting

Perceptual audio fingerprinting for Flutter. Identify and compare recordings by content - duplicates, renames, and re-encodes matched by content, not filenames.

Why Fingerprinting?

Filenames lie and tags go missing - but the audio doesn't. Fingerprinting lets you identify recordings by what they sound like, so these match as the same recording:

Song A.mp3
song_copy.mp3
01 - Song A.mp3
Song A (Remastered).mp3

Highlights

  • 🧬 Chromaprint-compatible perceptual fingerprints (same algorithm as fpcalc/AcoustID)
  • 🎵 MP3, FLAC, Ogg Vorbis, WAV, AIFF, M4A/AAC/ALAC
  • 🌍 Android, iOS, Linux, macOS, Windows & Web
  • 🦀 100% pure Rust - no C dependencies, builds everywhere including WASM
  • 📦 Separate lightweight package - zero cost unless you depend on it

Installation

Add haudiotagger_fingerprint to your pubspec.yaml:

dependencies:
  haudiotagger: ^1.3.3
  haudiotagger_fingerprint: ^0.4.0

Or install from the command line:

flutter pub add haudiotagger_fingerprint

The package self-registers as the backend at app startup - no extra initialization needed.

Quick Start

Fingerprint a file

import 'package:haudiotagger/haudiotagger.dart';

// Decodes the full stream; tags, filenames, and containers are ignored.
final a = await Haudiotagger.fingerprint('Song A.mp3');
final b = await Haudiotagger.fingerprint('song_copy.mp3');

print(a.durationSecs);

Compare two fingerprints

// 1.0 is (near-)identical audio, 0.0 is unrelated.
final score = await Haudiotagger.similarity(a, b);
print(score); // 1.0

// Or as a method:
print(await a.similarityTo(b));

Fingerprint bytes (Web)

final fp = await Haudiotagger.fingerprintFromBytes(bytes);

Finding duplicates

Group files with similarity >= 0.8 as the same recording:

final seen = <String, AudioFingerprint>{};
for (final path in paths) {
  final fp = await Haudiotagger.fingerprint(path);
  var isDuplicate = false;
  for (final entry in seen.values) {
    if (await Haudiotagger.similarity(fp, entry) >= 0.8) {
      isDuplicate = true;
      break;
    }
  }
  if (!isDuplicate) seen[path] = fp;
}

Finding a clip inside a song

Use contains when searching for a short clip inside a longer recording:

// 1.0 when the clip comes from the song, 0.0 when it doesn't.
final score = await Haudiotagger.contains(songFp, clipFp);

Scores >= 0.7 mean "present". Clips need about 5 seconds of audio to match reliably.

Cancelling long scans

Create one token per scan and cancel when work becomes stale:

import 'package:haudiotagger_fingerprint/haudiotagger_fingerprint.dart';

final token = await CancellationToken.create();
try {
  final fp = await Haudiotagger.fingerprint(
    'long-track.flac',
    cancellationToken: token,
  );
} on FingerprintError_Cancelled {
  // Scan was cancelled
} finally {
  await token.dispose();
}

Score interpretation

Score Meaning
1.0 Identical audio (copies, renames)
> 0.8 Same recording, different encode/container
~0.0 Unrelated audio

Supported formats (decoding)

Format Fingerprint
MP3 Yes
FLAC Yes
Ogg Vorbis Yes
WAV Yes
AIFF Yes
M4A / AAC / ALAC Yes
Opus, APE, WavPack, Musepack No

Platform support

Platform Support
Android Yes
iOS Yes
Linux Yes
macOS Yes
Windows Yes
Web Yes

Web fingerprinting runs fully in-browser via WebAssembly. For large files, prefer native for better performance.

API Reference

hAudiotagger

hAudiotagger

Home

Getting Started

Reference

Platforms

Community


pub.dev

Fingerprinting

Clone this wiki locally