soundfingerprinting

repository·develop·Indexed 21 days ago

https://github.com/addictedcs/soundfingerprinting

A C# framework for audio and video fingerprinting and recognition in .NET. It provides tools for high-precision retrieval and efficient storage of acoustic and visual signatures, featuring a fluent API via FingerprintCommandBuilder and QueryCommandBuilder. The framework supports multiple storage backends including InMemoryModelService and Emy, and offers spectral-profile path bridging (since v15.0.0) to handle broadband noise and silence. It includes compatibility matrices for FFmpegAudioService and specialized filters for real-time matching.

Tokens
14.9K
Snippets
39
Records
56
Agent score
77%

What's inside soundfingerprinting

  1. Configure Spectral-profile path bridging

    develop

    Since v15.0.0, you can use spectral profiles (SFM + relative power) to bridge regions where hashes don't match, such as broadband noise (ocean waves), fade-outs, or atmospheric silence. This is disabled by default and must be opted into via QueryConfiguration.SfmMatchStrategy during a query.

    Available strategies:

    • NoBridgingStrategy: Default (no bridging).
    • BroadbandNoiseBridgingStrategy: Uses per-second SFM > 0.70 on both sides.
    • SilentRegionBridgingStrategy: Uses per-second power < 5% on both sides.
    • SimilarProfileBridgingStrategy: Uses tight $|\Delta sfm| < 0.10$ tolerance.
    • CompositeBridgingStrategy: A safe union of the above strategies.

    Bridging is capped at a 70% cumulative-bridged-seconds limit and is reported via Coverage.BridgedSeconds.

    var queryResult = await QueryCommandBuilder.Instance.BuildQueryCommand()
        .From(file)
        .WithQueryConfig(config =>
        {
            // covers both broadband and silent regions in one pass
            config.Audio.SfmMatchStrategy = CompositeBridgingStrategy.BroadbandOrSilent;
            return config;
        })
        .UsingServices(modelService, audioService)
        .Query();
  2. Fingerprint storage options

    develop

    SoundFingerprinting supports different storage backends:

    • In-Memory: Use InMemoryModelService for volatile, RAM-based storage. Note that 100 hours of content with DefaultFingerprintingConfiguration consumes approximately 5GB of RAM.
    • Persistent Storage: For external, persistent storage, Emy is the preferred choice. A community version is available for non-commercial use.
  3. Install SoundFingerprinting via NuGet

    develop

    To use the SoundFingerprinting framework in your .NET project, install the main package using the NuGet Package Manager.

    Install-Package SoundFingerprinting
  4. Perform realtime audio/video querying with RealtimeQueryCommand

    develop

    The RealtimeQueryCommand is used to query underlying data storage in real-time by consuming a continuous stream of media. It supports various input sources including broadcast URLs, audio sample streams, file lists, and pre-computed hashes.

    To use it, you typically follow a builder-like pattern:

    1. Initialize the command (via your command builder).
    2. Define the source using .From(...).
    3. Provide necessary services (like IQueryService or IMediaService) using .UsingServices(...).
    4. Configure the query behavior using .WithRealtimeQueryConfig(...).
    5. Execute the query with .Query(CancellationToken).

    Note: If querying from a broadcast URL, you must provide an IRealtimeMediaService via .UsingServices(...).

    // Example conceptual usage
    await realtimeQueryCommand
        .From("http://broadcast-url.com/stream", chunkLength: 1.0, MediaType.Audio)
        .UsingServices(myQueryService, myRealtimeMediaService)
        .WithRealtimeQueryConfig(myConfig)
        .Query(cancellationToken);
  5. Extract and store audio fingerprints

    develop

    To index audio for later recognition, use FingerprintCommandBuilder to generate hashes from a file and then use an IModelService to store them. You will need an IAudioService (such as SoundFingerprintingAudioService) to handle the audio processing.

    Example of extracting fingerprints from a file and storing them in an InMemoryModelService:

    private readonly IModelService modelService = new InMemoryModelService(); // store fingerprints in RAM
    private readonly IAudioService audioService = new SoundFingerprintingAudioService(); // default audio library
    
    public async Task StoreForLaterRetrieval(string file)
    {
        var track = new TrackInfo("GBBKS1200164", "Skyfall", "Adele");
    
        // create fingerprints
        var avHashes = await FingerprintCommandBuilder.Instance
                                    .BuildFingerprintCommand()
                                    .From(file)
                                    .UsingServices(audioService)
                                    .Hash();
                                    
        // store hashes in the database for later retrieval
        modelService.Insert(track, avHashes);
    }
  6. Query fingerprints to recognize audio

    develop

    To identify a track from a query sample (file, URL, microphone, etc.), use QueryCommandBuilder. You must provide the IModelService (where fingerprints are stored) and the IAudioService (to process the query sample).

    public async Task<TrackData?> GetBestMatchForSong(string file)
    {
        int secondsToAnalyze = 10; // number of seconds to analyze from query file
        int startAtSecond = 0; // start at the begining
    	    
        // query the underlying database for similar audio sub-fingerprints
        var queryResult = await QueryCommandBuilder.Instance.BuildQueryCommand()
                                             .From(file, secondsToAnalyze, startAtSecond)
                                             .UsingServices(modelService, audioService)
                                             .Query();
    
        return queryResult.BestMatch?.Audio.Track;
    }
  7. Compensate for pitch and tempo changes in queries

    develop

    If your query sample was played with vinyl-style pitch control (where tempo and pitch change together by a known percentage), you can compensate for this during the fingerprinting process using the .From method on the command builder.

    // Example: compensating for an 8% pitch/tempo change
    .From(audioSamples, sourcePlaybackSpeedPercentage: 8)
  8. FFmpeg version compatibility matrix

    develop

    If you are using FFmpegAudioService, ensure your FFmpeg version is compatible with your SoundFingerprinting version according to the following matrix:

    SoundFingerprintingSoundFingerprinting.EmyFFmpeg
    8.x8.x4.x
    9.x9.x5.x
    10.x10.x6.x
    11.x11.x6.x
    12.x12.x7.x
    13.x13.x7.x
    14.x14.x8.x
    15.x15.x8.x
  9. Configure realtime query settings using IWithRealtimeQueryConfiguration

    develop

    When setting up realtime query operations, you can use the IWithRealtimeQueryConfiguration interface to define how queries are executed. This interface provides two ways to apply configuration:

    1. Direct Configuration: Pass a complete RealtimeQueryConfiguration object.
    2. Functional Amendment: Pass a Func<RealtimeQueryConfiguration, RealtimeQueryConfiguration> to modify an existing DefaultRealtimeQueryConfiguration instance using an amendment functor.

    Both methods return an IInterceptRealtimeSource, allowing for a fluent builder-style configuration pattern.

    // Example 1: Using a direct configuration object
    services.WithRealtimeQueryConfig(new RealtimeQueryConfiguration { /* settings */ });
    
    // Example 2: Using an amendment functor to modify default settings
    services.WithRealtimeQueryConfig(config => {
        config.SomeProperty = true;
        return config;
    });
  10. Provide services to QueryCommand using UsingServices

    develop

    To execute a query, you must provide the necessary services to the command. The UsingServices method is overloaded to support different combinations of services:

    • UsingServices(IQueryService queryService): The core service required to query storage.
    • UsingServices(IQueryService queryService, IAudioService audioService)
    • UsingServices(IQueryService queryService, IAudioService audioService, IAVQueryMatchRegistry queryMatchRegistry)
    • UsingServices(IQueryService queryService, IVideoService videoService)
    • UsingServices(IQueryService queryService, IVideoService videoService, IAVQueryMatchRegistry queryMatchRegistry)
    • UsingServices(IQueryService queryService, IMediaService mediaService)
    • UsingServices(IQueryService queryService, IMediaService mediaService, IAVQueryMatchRegistry queryMatchRegistry)
  11. Configure query services with IUsingQueryServices

    develop

    The IUsingQueryServices interface is used to configure the services required for a query command. It allows you to inject the necessary components for accessing fingerprint storage, processing audio/video media, and managing match results.

    Depending on whether you are performing audio-only, video-only, or combined audio/video (AV) fingerprinting, you can provide different combinations of services:

    • IQueryService: The model service used to access the underlying fingerprint storage.
    • IAudioService: Used for building fingerprints from audio sources.
    • IVideoService: Used for reading Frames from video sources. Required if you set MediaType.Video on the IQuerySource.
    • IMediaService: A versatile service that can read both AudioSamples and Frames to generate AVHashes for querying.
    • IAVQueryMatchRegistry: A registry used to store query results in a separate storage.

    All UsingServices methods return an IQueryCommand, allowing for a fluent API pattern.

    // Example of configuring a query command with a query service and a media service
    // that handles both audio and video.
    IQueryCommand command = queryCommand
        .UsingServices(queryService, mediaService, queryMatchRegistry);
  12. Implement IRealtimeResultEntryFilter to filter realtime results

    develop

    The IRealtimeResultEntryFilter interface allows you to define custom logic for filtering result entries during a realtime query. This filter is used during the configuration of a RealtimeQueryCommand and applies to both realtime result entries and ongoing query result entries.

    Implement the Pass method to determine if a specific AVResultEntry should be kept or discarded based on its properties and whether it is eligible to persist into the next query cycle.

    using SoundFingerprinting.Command;
    using SoundFingerprinting.Query;
    
    public class MyCustomFilter : IRealtimeResultEntryFilter
    {
        public bool Pass(AVResultEntry entry, bool canContinueInTheNextQuery)
        {
            // Implement custom filtering logic here
            // Example: only allow entries with a high confidence score
            return entry.Confidence > 0.8;
        }
    }