Click here to Skip to main content
15,886,060 members
Articles / Desktop Programming / WPF

Duplicate songs detector via audio fingerprinting

Rate me:
Please Sign up or sign in to vote.
4.96/5 (337 votes)
23 Jun 2020MIT44 min read 1.3M   20.4K   533  
Explains sound fingerprinting algorithm, with a practical example of detecting duplicate files on the user's local drive.
The aim of this article is to show an efficient algorithm of signal processing which will allow one to have a competent system of sound fingerprinting and signal recognition. I'll try to come with some explanations of the article's algorithm, and also speak about how it can be implemented using the C# programming language. Additionally, I'll try to cover topics of digital signal processing that are used in the algorithm, thus you'll be able to get a clearer image of the entire system. And as a proof of concept, I'll show you how to develop a simple WPF MVVM application.
// Sound Fingerprinting framework
// git://github.com/AddictedCS/soundfingerprinting.git
// Code license: CPOL v.1.02
// ciumac.sergiu@gmail.com
using System;

namespace Soundfingerprinting.SoundTools
{
    /// <summary>
    ///   Query statistical information
    /// </summary>
    public class QueryStats
    {
        #region Private Fields

        private readonly int _endQueryIndex;
        private readonly int _startQueryIndex;

        #endregion

        /// <summary>
        ///   Public parameter less constructor
        /// </summary>
        public QueryStats()
        {
            HammingDistance = NumberOfTrackIdOccurences = NumberOfTotalTableVotes =
                                                          _startQueryIndex = _endQueryIndex = TotalFingerprints = HammingDistanceByTrack = 0;
            MaxPathThroughTables = MaxHammingDistance = MaxTableVote = Int32.MinValue;
            MinHammingDistance = Int32.MaxValue;
            OrderingValue = 0;
            Similarity = 0;
        }

        /// <summary>
        ///   Constructor
        /// </summary>
        /// <param name = "hammingDistance">Hamming distance</param>
        /// <param name = "numberOfTrackOccurences">Number of track id occurrences</param>
        /// <param name = "numberOfTotalVotes">Number of total table votes</param>
        /// <param name = "startQueryIndex">Start query index</param>
        /// <param name = "endQueryIndex">End query index</param>
        /// <param name = "totalFingerprints">Number of total fingerprints</param>
        public QueryStats(double hammingDistance, int numberOfTrackOccurences, int numberOfTotalVotes, int startQueryIndex, int endQueryIndex, int totalFingerprints)
        {
            HammingDistance = hammingDistance;
            NumberOfTrackIdOccurences = numberOfTrackOccurences;
            NumberOfTotalTableVotes = numberOfTotalVotes;
            _startQueryIndex = startQueryIndex;
            _endQueryIndex = endQueryIndex;
            TotalFingerprints = totalFingerprints;
        }

        /// <summary>
        ///   Constructor
        /// </summary>
        /// <param name = "hammingDistance">Hamming distance</param>
        /// <param name = "numberOfTrackOccurences">Number of track id occurences</param>
        /// <param name = "numberOfTotalVotes">Number of total table votes</param>
        /// <param name = "startQueryIndex">Start query index</param>
        /// <param name = "endQueryIndex">End query index</param>
        /// <param name = "totalFingerprints">Number of total fingerprints</param>
        /// <param name = "maxTableVote">Maximal table vote</param>
        /// <param name = "hammingDistanceByTrack">Hamming distance summed over track id</param>
        /// <param name = "minHammingDistance">Minimal hamming distance</param>
        /// <param name = "maxHammingDistance">Maximal hamming distance</param>
        /// <param name = "maxPathThroughTables">Maximal path through tables</param>
        /// <param name = "similarity">Similarity set</param>
        public QueryStats(double hammingDistance, int numberOfTrackOccurences, int numberOfTotalVotes, int startQueryIndex, int endQueryIndex, int totalFingerprints, int maxTableVote, int hammingDistanceByTrack, int minHammingDistance, int maxHammingDistance, int maxPathThroughTables, double similarity)
        {
            HammingDistance = hammingDistance;
            NumberOfTrackIdOccurences = numberOfTrackOccurences;
            NumberOfTotalTableVotes = numberOfTotalVotes;
            _startQueryIndex = startQueryIndex;
            _endQueryIndex = endQueryIndex;
            TotalFingerprints = totalFingerprints;
            MaxTableVote = maxTableVote;
            HammingDistanceByTrack = hammingDistanceByTrack;
            MinHammingDistance = minHammingDistance;
            MaxHammingDistance = maxHammingDistance;
            MaxPathThroughTables = maxPathThroughTables;
            Similarity = similarity;
        }

        /// <summary>
        ///   Start of the query index
        /// </summary>
        public int StartQueryIndex
        {
            get { return _startQueryIndex; }
        }

        /// <summary>
        ///   End of the query index
        /// </summary>
        public int EndQueryIndex
        {
            get { return _endQueryIndex; }
        }

        /// <summary>
        ///   Total fingeprints generated
        /// </summary>
        public int TotalFingerprints { get; set; }

        /// <summary>
        ///   Hamming distance (summed by fingerprint count)
        /// </summary>
        public double HammingDistance { get; set; }

        /// <summary>
        ///   Number of Track Id occurences
        /// </summary>
        public int NumberOfTrackIdOccurences { get; set; }

        /// <summary>
        ///   Number of total table votes
        /// </summary>
        public int NumberOfTotalTableVotes { get; set; }

        /// <summary>
        ///   Maximum table votes gathered by this specific query fingerprint
        /// </summary>
        public int MaxTableVote { get; set; }

        /// <summary>
        ///   Hamming distance by track count
        /// </summary>
        public int HammingDistanceByTrack { get; set; }

        /// <summary>
        ///   Minimal hamming distance gathered by a specific query fingerprint
        /// </summary>
        public int MinHammingDistance { get; set; }

        /// <summary>
        ///   Maximum hamming distance gathered by a specific query fingerprint
        /// </summary>
        public int MaxHammingDistance { get; set; }

        /// <summary>
        ///   Ordering value
        /// </summary>
        public double OrderingValue { get; set; }

        /// <summary>
        ///   Max path through tables (dynamic programming)
        /// </summary>
        public int MaxPathThroughTables { get; set; }

        /// <summary>
        ///   Similarity value
        /// </summary>
        public double Similarity { get; set; }
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The MIT License


Written By
Software Developer
Moldova (Republic of) Moldova (Republic of)
Interested in computer science, math, research, and everything that relates to innovation. Fan of agnostic programming, don't mind developing under any platform/framework if it explores interesting topics. In search of a better programming paradigm.

Comments and Discussions