private static void Test() { mirageaudio_initgst(); string song1_filename = "/home/lorentz/Music/Library/Pachelbel/Johann Pachelbel - Canon And Gigue In D Major For 3 Violins And Basso Continuo.mp3"; string song2_filename = "/home/lorentz/Music/Library/Karajan Adagios/CD 1/Pachelbel - Canon in d Major (Kanon And Gigue in d Major = d Dur) av Johann Pachelbel.mp3"; Scms song1 = null; Scms song2 = null; DbgTimer t1 = new DbgTimer(); t1.Start(); int runs = 10; for (int i = 0; i < runs; i++) { Analyzer.Analyze(song1_filename); } long l1 = 0; t1.Stop(ref l1); Dbg.WriteLine("Analysis: " + runs + " times - " + l1 + "ms; " + (double)l1 / (double)runs + "ms per analysis"); song1 = Analyzer.Analyze(song1_filename); song2 = Analyzer.Analyze(song2_filename); ScmsConfiguration config = new ScmsConfiguration(Analyzer.MFCC_COEFFICIENTS); Console.WriteLine("Distance = " + Scms.Distance(song1, song2, config)); DbgTimer t2 = new DbgTimer(); t2.Start(); runs = 100000; for (int i = 0; i < runs; i++) { Scms.Distance(song1, song2, config); } long l2 = 0; t2.Stop(ref l2); Dbg.WriteLine("Distance Computation: " + runs + " times - " + l2 + "ms; " + (double)l2 / (double)runs + "ms per comparison"); }
public double[][] CreateLogSpectrogram( float[] samples, IWindowFunction windowFunction, AudioServiceConfiguration configuration) { DbgTimer t = new DbgTimer(); t.Start(); if (configuration.NormalizeSignal) { NormalizeInPlace(samples); } int width = (samples.Length - configuration.WindowSize) / configuration.Overlap; /*width of the image*/ double[][] frames = new double[width][]; int[] logFrequenciesIndexes = GenerateLogFrequencies(configuration); double[] window = windowFunction.GetWindow(); for (int i = 0; i < width; i++) { double[] complexSignal = new double[2 * configuration.WindowSize]; /*even - Re, odd - Img, thats how Exocortex works*/ // take 371 ms each 11.6 ms (2048 samples each 64 samples, samplerate 5512) // or 256 ms each 16 ms (8192 samples each 512 samples, samplerate 32000) for (int j = 0; j < configuration.WindowSize; j++) { // Weight by Hann Window complexSignal[2 * j] = window[j] * samples[(i * configuration.Overlap) + j]; // need to clear out as fft modifies buffer (phase) complexSignal[(2 * j) + 1] = 0; } lomonFFT.TableFFT(complexSignal, true); frames[i] = ExtractLogBins(complexSignal, logFrequenciesIndexes, configuration.LogBins); } Dbg.WriteLine("Create Log Spectrogram - Execution Time: {0} ms", t.Stop().TotalMilliseconds); return(frames); }
public List <bool[]> CreateFingerprintsFromLogSpectrum( double[][] logarithmizedSpectrum, IStride stride, int fingerprintLength, int overlap, int topWavelets) { DbgTimer t = new DbgTimer(); t.Start(); // Cut the logaritmic spectrogram into smaller spectrograms with one stride between each List <double[][]> spectralImages = SpectrumService.CutLogarithmizedSpectrum(logarithmizedSpectrum, stride, fingerprintLength, overlap); // Then apply the wavelet transform on them to later reduce the resolution // do this in place WaveletService.ApplyWaveletTransformInPlace(spectralImages); // Then for each of the wavelet reduce the resolution by only keeping the top wavelets // and ignore the magnitude of the top wavelets. // Instead, we can simply keep the sign of it (+/-). // This information is enough to keep the extract perceptual characteristics of a song. List <bool[]> fingerprints = new List <bool[]>(); foreach (var spectralImage in spectralImages) { bool[] image = FingerprintDescriptor.ExtractTopWavelets(spectralImage, topWavelets); fingerprints.Add(image); } Dbg.WriteLine("Created {1} Fingerprints from Log Spectrum - Execution Time: {0} ms", t.Stop().TotalMilliseconds, fingerprints.Count); return(fingerprints); }
/// <summary> /// Find Similar Tracks using passed audio samples as input and return a List /// </summary> /// <param name="lshHashTables">Number of hash tables from the database</param> /// <param name="lshGroupsPerKey">Number of groups per hash table</param> /// <param name="thresholdTables">Minimum number of hash tables that must be found for one signature to be considered a candidate (0 and 1 = return all candidates, 2+ = return only exact matches)</param> /// <param name="param">Audio File Work Unit Parameter Object</param> /// <param name="optimizeSignatureCount">Reduce the number of signatures in order to increase the search performance</param> /// <param name="doSearchEverything">disregard the local sensitivity hashes and search the whole database</param> /// <param name="splashScreen">The "please wait" splash screen (or null)</param> /// <returns>a list of perceptually similar tracks</returns> public List <FindSimilar.QueryResult> FindSimilarFromAudioSamplesList( int lshHashTables, int lshGroupsPerKey, int thresholdTables, WorkUnitParameterObject param, bool optimizeSignatureCount, bool doSearchEverything, SplashSceenWaitingForm splashScreen) { DbgTimer t = new DbgTimer(); t.Start(); if (splashScreen != null) { splashScreen.SetProgress(2, "Creating fingerprints from audio samples ..."); } // Get fingerprints double[][] logSpectrogram; List <bool[]> fingerprints = fingerprintService.CreateFingerprintsFromAudioSamples(param.AudioSamples, param, out logSpectrogram); #if DEBUG // Save debug images using fingerprinting methods //Analyzer.SaveFingerprintingDebugImages(param.FileName, logSpectrogram, fingerprints, fingerprintService, param.FingerprintingConfiguration); #endif if (splashScreen != null) { splashScreen.SetProgress(3, String.Format("Successfully created {0} fingerprints.", fingerprints.Count)); } // If the number of signatures is to big, only keep the first MAX_SIGNATURE_COUNT to avoid a very time consuming search if (optimizeSignatureCount && fingerprints.Count > MAX_SIGNATURE_COUNT) { if (splashScreen != null) { splashScreen.SetProgress(4, String.Format("Only using the first {0} fingerprints out of {1}.", MAX_SIGNATURE_COUNT, fingerprints.Count)); } fingerprints.RemoveRange(MAX_SIGNATURE_COUNT, fingerprints.Count - MAX_SIGNATURE_COUNT); Dbg.WriteLine("Only using the first {0} fingerprints.", MAX_SIGNATURE_COUNT); } long elapsedMiliseconds = 0; // Query the database using Min Hash Dictionary <int, QueryStats> allCandidates = QueryFingerprintManager.QueryOneSongMinHash( fingerprints, dbService, minHash, lshHashTables, lshGroupsPerKey, thresholdTables, ref elapsedMiliseconds, doSearchEverything, splashScreen); if (splashScreen != null) { splashScreen.SetProgress(91, String.Format("Found {0} candidates.", allCandidates.Count)); } IEnumerable <int> ids = allCandidates.Select(p => p.Key); IList <Track> tracks = dbService.ReadTrackById(ids); if (splashScreen != null) { splashScreen.SetProgress(95, String.Format("Reading {0} tracks.", tracks.Count)); } // Order by Hamming Similarity // TODO: What does the 0.4 number do here? // there doesn't seem to be any change using another number?! /* * // Using PLINQ * IOrderedEnumerable<KeyValuePair<int, QueryStats>> order = allCandidates * .OrderBy((pair) => pair.Value.OrderingValue = * pair.Value.HammingDistance / pair.Value.NumberOfTotalTableVotes + 0.4 * pair.Value.MinHammingDistance); + + + var fingerprintList = (from o in order + join track in tracks on o.Key equals track.Id + select new FindSimilar.QueryResult { + Id = track.Id, + Path = track.FilePath, + Duration = track.TrackLengthMs, + Similarity = o.Value.Similarity + }).ToList(); */ // http://msdn.microsoft.com/en-us/library/dd460719(v=vs.110).aspx // http://stackoverflow.com/questions/2767709/c-sharp-joins-where-with-linq-and-lambda // Lambda query to order the candidates var order = allCandidates.AsParallel() .OrderBy((pair) => pair.Value.OrderingValue = pair.Value.HammingDistance / pair.Value.NumberOfTotalTableVotes + 0.4 * pair.Value.MinHammingDistance) .Take(200); // TODO: Be able to create the above query as a LINQ query // Join on the ID properties. var fingerprintList = (from o in order.AsParallel() join track in tracks.AsParallel() on o.Key equals track.Id select new FindSimilar.QueryResult { Id = track.Id, Path = track.FilePath, Duration = track.TrackLengthMs, Similarity = o.Value.Similarity }) .OrderByDescending((ord) => ord.Similarity) .ToList(); if (splashScreen != null) { splashScreen.SetProgress(100, "Ready!"); } Dbg.WriteLine("FindSimilarFromAudioSamplesList - Total Execution Time: {0} ms", t.Stop().TotalMilliseconds); return(fingerprintList); }
/// <summary> /// Find Similar Tracks using passed audio samples as input and return a Dictionary /// </summary> /// <param name="lshHashTables">Number of hash tables from the database</param> /// <param name="lshGroupsPerKey">Number of groups per hash table</param> /// <param name="thresholdTables">Minimum number of hash tables that must be found for one signature to be considered a candidate (0 and 1 = return all candidates, 2+ = return only exact matches)</param> /// <param name="param">Audio File Work Unit Parameter Object</param> /// <returns>a dictionary of perceptually similar tracks</returns> public Dictionary <Track, double> FindSimilarFromAudioSamples( int lshHashTables, int lshGroupsPerKey, int thresholdTables, WorkUnitParameterObject param) { DbgTimer t = new DbgTimer(); t.Start(); // Get fingerprints double[][] logSpectrogram; List <bool[]> signatures = fingerprintService.CreateFingerprintsFromAudioSamples(param.AudioSamples, param, out logSpectrogram); long elapsedMiliseconds = 0; // Query the database using Min Hash Dictionary <int, QueryStats> allCandidates = QueryFingerprintManager.QueryOneSongMinHash( signatures, dbService, minHash, lshHashTables, lshGroupsPerKey, thresholdTables, ref elapsedMiliseconds); IEnumerable <int> ids = allCandidates.Select(p => p.Key); IList <Track> tracks = dbService.ReadTrackById(ids); // Order by Hamming Similarity // Using PLINQ //OrderedParallelQuery<KeyValuePair<int, QueryStats>> order = allCandidates.AsParallel() IOrderedEnumerable <KeyValuePair <int, QueryStats> > order = allCandidates .OrderBy((pair) => pair.Value.OrderingValue = pair.Value.HammingDistance / pair.Value.NumberOfTotalTableVotes + 0.4 * pair.Value.MinHammingDistance); // Join on the ID properties. var joined = from o in order join track in tracks on o.Key equals track.Id select new { track, o.Value.Similarity }; Dictionary <Track, double> stats = joined.ToDictionary(Key => Key.track, Value => Value.Similarity); Dbg.WriteLine("Find Similar From Audio Samples - Total Execution Time: {0} ms", t.Stop().TotalMilliseconds); return(stats); }