Get started
with Emy

A self-hosted database for audio and video fingerprints,
with a JSON API and a .NET client.

A self-hosted database for audio and video fingerprints, with a JSON API and a .NET client.

Quick start

Emy ships as a single Docker container. Start it with one command:

docker run -d -v /persistent-dir:/app/data -p 3399:3399 -p 3340:3340 addictedcs/soundfingerprinting.emy:latest

Port 3340 serves the JSON API together with the backoffice UI — open it in a browser to manage tracks, streams, and matches visually. Port 3399 serves the binary protocol used by the .NET client. Fingerprints are persisted under the mounted /app/data volume.

The Community Edition ships with default credentials: application ID Admin and an empty API key. Generate your own keys in the backoffice under API Keys.

Insert tracks

Insert audio or video with a multipart request. The mediaType field controls whether Emy fingerprints the audio track, the video frames, or both. Attach any key-value metaFields you want returned with future matches.


curl 'https://<your-emysound-host>/api/v1.1/tracks' \
    -H 'Authorization: Basic Admin:' \
    -F 'id=test-id' \
    -F 'title=test-title' \
    -F 'artist=test-artist' \
    -F 'metaFields[test-meta-key]=test-meta-value' \
    -F 'mediaType=Audio,Video' \
    -F 'file=@ad.mp4'

The same insert with the SoundFingerprinting.Emy .NET client:


// connect to Emy on port 3399
var emyModelService = EmyModelService.NewInstance("localhost", 3399);
    
// define track info
var track = new TrackInfo("GBBKS1200164", "Skyfall", "Adele", 290d);
 
// create fingerprints
var hashedFingerprints = await FingerprintCommandBuilder.Instance
                                 .BuildFingerprintCommand()
                                 .From(pathToAudioFile)
                                 .UsingServices(audioService)
                                 .Hash();
 								
// store hashes in the database for later retrieval
emyModelService.Insert(track, hashedFingerprints);

You can also ingest directly from a URL — Emy downloads and fingerprints the media for you:


 curl --request PUT \
  --url 'http://localhost:3340/api/v1.1/tracks?encodedMediaUrl=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DvNkIj_BhHvY' \
  --header 'Accept: application/json' \
  --header 'Authorization: Basic Admin:' \
  --header 'Content-Type: application/*+json' \
  --data '{"id":"e96d43b7-0f02-486c-a6d5-acc6bbfdd7be","title":"Bach Air on G string Piano","artist":"Valentina Lisitsa","mediaType":"Audio"}'

Query

Query with a media file — a five-second snippet is enough. minCoverage filters out partial matches below the requested coverage ratio.


curl 'https://<your-emysound-host>/api/v1.1/query?mediaType=AudioAndVideo&minCoverage=0.4' \
    -H 'Authorization: Basic Admin:' \
    -F 'file=@query.ts'

Or with the .NET client:


 // connect to Emy on port 3399
 var emyModelService = EmyModelService.NewInstance("localhost", 3399);
  
 // query Emy database
 var queryResult = await QueryCommandBuilder.Instance.BuildQueryCommand()
                                          .From(queryAudioFile, secondsToAnalyze, startAtSecond)
                                          .UsingServices(modelService, audioService)
                                          .Query();
 					
 // register matches such that they appear in the dashboard					
 emyModelService.RegisterMatches(queryResult.ResultEntries);

Every match reports exact coverage details: where the match starts in the track and in the query, how much of each is covered, and any gaps in between.

Monitor live streams

Register an HTTP or HLS stream and Emy monitors it continuously, matching everything it hears against your catalog. Set savePlaybackTrack to keep the aired audio available for playback and review.


curl --request POST \
  --url https://<your-emysound-host>/api/v1.1/streams \
  --header 'Authorization: Basic Admin:' \
  --header 'Accept: application/json' \
  --header 'Content-Type: application/*+json' \
  --data '
{
  "streamId": "CNN",
  "streamUrl": "https://tunein.streamguys1.com/cnn-new",
  "savePlaybackTrack": true
}

Don't have a stream URL at hand? The backoffice ships with a built-in radio directory — thousands of stations, searchable by country and genre — so you can pick a station and start monitoring without leaving the dashboard.

Read more in the step-by-step guide: How to monitor online broadcasts.

Read your matches

Matches are available in the backoffice, or programmatically with cursor-based pagination and filters:


curl --request GET \
  --url 'https://<your-emysound-host>/api/v1.1/matches?limit=50&sinceDays=90' \
  --header 'Authorization: Basic Admin:' \
  --header 'Accept: application/json'


Aggregate with facets — for example, count matches per track:


curl --request GET \
  --url 'https://<your-emysound-host>/api/v1.1/matches?facets=trackId&sinceDays=90' \
  --header 'Authorization: Basic Admin:' \
  --header 'Accept: application/json'

When playback is enabled, download the aired media for any match:


curl --request GET \
     --url 'https://<your-emysound-host>/api/v1.1/media/matches/query-match-id?applicationId=your-application-id&jsonApiKey=your-json-api-key' \
     --header 'Accept: application/json'

Under the hood

Emy is not a wrapper around a general-purpose database — the index is purpose-built for fingerprint lookups:

Open source roots

Emy grew out of SoundFingerprinting, an open source audio fingerprinting framework maintained since 2011 — over 1,000 GitHub stars and more than 600,000 NuGet downloads. The algorithm is public, the client is open source, and the Community Edition of the server is free for non-commercial use.

Further reading:

See Emysound in action

Spin up a server and match
your first track in minutes.