public List<bool[]> CreateFingerprintsFromAudioSamples(float[] samples, WorkUnitParameterObject param, out double[][] logSpectrogram, out List<double[][]> spectralImages) { IFingerprintingConfiguration configuration = param.FingerprintingConfiguration; AudioServiceConfiguration audioServiceConfiguration = new AudioServiceConfiguration { LogBins = configuration.LogBins, LogBase = configuration.LogBase, MaxFrequency = configuration.MaxFrequency, MinFrequency = configuration.MinFrequency, Overlap = configuration.Overlap, SampleRate = configuration.SampleRate, WindowSize = configuration.WindowSize, NormalizeSignal = configuration.NormalizeSignal, UseDynamicLogBase = configuration.UseDynamicLogBase }; // store the log spectrogram in the out variable logSpectrogram = AudioService.CreateLogSpectrogram( samples, configuration.WindowFunction, audioServiceConfiguration); return this.CreateFingerprintsFromLogSpectrum( logSpectrogram, configuration.Stride, configuration.FingerprintLength, configuration.Overlap, configuration.TopWavelets, out spectralImages); }
private List<bool[]> CreateFingerprintsFromAudioSamples(float[] samples, WorkUnitParameterObject param) { IFingerprintingConfiguration configuration = param.FingerprintingConfiguration; AudioServiceConfiguration audioServiceConfiguration = new AudioServiceConfiguration { LogBins = configuration.LogBins, LogBase = configuration.LogBase, MaxFrequency = configuration.MaxFrequency, MinFrequency = configuration.MinFrequency, Overlap = configuration.Overlap, SampleRate = configuration.SampleRate, WdftSize = configuration.WdftSize }; float[][] spectrum = audioService.CreateLogSpectrogram( samples, configuration.WindowFunction, audioServiceConfiguration); return CreateFingerprintsFromSpectrum( spectrum, configuration.Stride, configuration.FingerprintLength, configuration.Overlap, configuration.LogBins, configuration.TopWavelets); }
public Task<List<bool[]>> Process(WorkUnitParameterObject details) { if (!string.IsNullOrEmpty(details.PathToAudioFile)) { return Task.Factory.StartNew(() => CreateFingerprintsFromAudioFile(details)); } return Task.Factory.StartNew(() => CreateFingerprintsFromAudioSamples(details.AudioSamples, details)); }
public List<bool[]> CreateFingerprintsFromAudioFile(WorkUnitParameterObject param, out double[][] logSpectrogram) { float[] samples = AudioService.ReadMonoFromFile( param.PathToAudioFile, param.FingerprintingConfiguration.SampleRate, param.MillisecondsToProcess, param.StartAtMilliseconds); return CreateFingerprintsFromAudioSamples(samples, param, out logSpectrogram); }
public Dictionary<Track, QueryStats> FindSimilarFromAudioFile( int lshHashTables, int lshGroupsPerKey, int thresholdTables, WorkUnitParameterObject param) { // Get fingerprints // TODO: Note that this method might return too few samples double[][] LogSpectrogram; List<bool[]> signatures = fingerprintService.CreateFingerprintsFromAudioFile(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 }; Dictionary<Track, QueryStats> stats = joined.ToDictionary(Key => Key.track, Value => Value.Value); return stats; }
private static bool AnalyseAndAddScmsUsingFingerprints(List<double[][]> spectralImages, List<bool[]> fingerprints, WorkUnitParameterObject param, Db db, int trackId, bool doOutputDebugInfo=DEFAULT_DEBUG_INFO) { DbgTimer t = new DbgTimer(); t.Start (); // Insert Statistical Cluster Model Similarity Audio Feature string fileName = param.FileName; // Merge the arrays in the List using Linq var result = spectralImages.SelectMany(i => i).ToArray(); Comirva.Audio.Util.Maths.Matrix scmsMatrix = new Comirva.Audio.Util.Maths.Matrix(result); if (doOutputDebugInfo) { scmsMatrix.DrawMatrixImage(String.Format("{0}_spectral.png", fileName)); } #region Store in a Statistical Cluster Model Similarity class. Scms audioFeature = Scms.GetScms(scmsMatrix, fileName); if (audioFeature != null) { // Store bitstring hash as well audioFeature.BitString = GetBitString(scmsMatrix); // Store duration audioFeature.Duration = (long) param.DurationInMs; // Store file name audioFeature.Name = param.PathToAudioFile; // Add to database int id = trackId; if (db.AddTrack(audioFeature) == -1) { Console.Out.WriteLine("Failed! Could not add audio feature to database ({0})!", fileName); return false; } } else { return false; } #endregion Dbg.WriteLine ("AnalyseAndAddScmsUsingFingerprints2 - Execution Time: {0} ms", t.Stop().TotalMilliseconds); return true; }
/// <summary> /// Insert track into database /// </summary> /// <param name="track">Track</param> /// <param name="hashTables">Number of hash tables (e.g. 25)</param> /// <param name="hashKeys">Number of hash keys (e.g. 4)</param> /// <param name="param">WorkUnitParameterObject parameters</param> public bool InsertTrackInDatabaseUsingSamples(Track track, int hashTables, int hashKeys, WorkUnitParameterObject param, out double[][] logSpectrogram) { if (dbService.InsertTrack(track)) { List<bool[]> images = fingerprintService.CreateFingerprintsFromAudioSamples(param.AudioSamples, param, out logSpectrogram); List<Fingerprint> inserted = AssociateFingerprintsToTrack(images, track.Id); if (dbService.InsertFingerprint(inserted)) { return HashFingerprintsUsingMinHash(inserted, track, hashTables, hashKeys); } else { return false; } } else { logSpectrogram = null; return false; } }
// TODO: Rememeber to use another stride when querying public static Dictionary<Track, double> SimilarTracksSoundfingerprinting(FileInfo filePath) { DbgTimer t = new DbgTimer(); t.Start (); FindSimilar.AudioProxies.BassProxy bass = FindSimilar.AudioProxies.BassProxy.Instance; float[] audiodata = AudioFileReader.Decode(filePath.FullName, SAMPLING_RATE, SECONDS_TO_ANALYZE); if (audiodata == null || audiodata.Length == 0) { Dbg.WriteLine("Error! - No Audio Found"); return null; } // Name of file being processed string name = StringUtils.RemoveNonAsciiCharacters(Path.GetFileNameWithoutExtension(filePath.Name)); // Calculate duration in ms double duration = (double) audiodata.Length / SAMPLING_RATE * 1000; // Explode samples to the range of 16 bit shorts (–32,768 to 32,767) // Matlab multiplies with 2^15 (32768) // e.g. if( max(abs(speech))<=1 ), speech = speech * 2^15; end; MathUtils.Multiply(ref audiodata, AUDIO_MULTIPLIER); // 65536 // zero pad if the audio file is too short to perform a mfcc if (audiodata.Length < (fingerprintingConfig.WdftSize + fingerprintingConfig.Overlap)) { int lenNew = fingerprintingConfig.WdftSize + fingerprintingConfig.Overlap; Array.Resize<float>(ref audiodata, lenNew); } // Get fingerprint signatures using the Soundfingerprinting methods // Get database DatabaseService databaseService = DatabaseService.Instance; IPermutations permutations = new LocalPermutations("Soundfingerprinting\\perms.csv", ","); Repository repository = new Repository(permutations, databaseService, fingerprintService); // work config WorkUnitParameterObject param = new WorkUnitParameterObject(); param.FingerprintingConfiguration = fingerprintingConfig; param.PathToAudioFile = filePath.FullName; param.AudioSamples = audiodata; param.MillisecondsToProcess = SECONDS_TO_ANALYZE * 1000; param.StartAtMilliseconds = 0; Dictionary<Track, double> candidates = repository.FindSimilarFromAudioSamples(25, 4, 2, param); return candidates; /* // Use var keyword to enumerate dictionary foreach (var pair in candidates) { Console.WriteLine("{0} - {1:0.00}", pair.Key.Title, pair.Value); } */ Dbg.WriteLine ("Soundfingerprinting - Total Execution Time: {0} ms", t.Stop().TotalMilliseconds); }
/// <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> /// Return information from the Audio File /// </summary> /// <param name="filePath">filepath object</param> /// <returns>a WorkUnitParameter object</returns> public static WorkUnitParameterObject GetWorkUnitParameterObjectFromAudioFile(FileInfo filePath, bool doOutputDebugInfo=DEFAULT_DEBUG_INFO) { DbgTimer t = new DbgTimer(); t.Start (); float[] audiodata = AudioFileReader.Decode(filePath.FullName, SAMPLING_RATE, SECONDS_TO_ANALYZE); if (audiodata == null || audiodata.Length == 0) { Dbg.WriteLine("Error! - No Audio Found"); return null; } // Name of file being processed string fileName = StringUtils.RemoveNonAsciiCharacters(Path.GetFileNameWithoutExtension(filePath.Name)); #if DEBUG if (DEBUG_INFO_VERBOSE) { if (DEBUG_OUTPUT_TEXT) WriteAscii(audiodata, fileName + "_audiodata.ascii"); if (DEBUG_OUTPUT_TEXT) WriteF3Formatted(audiodata, fileName + "_audiodata.txt"); } #endif if (doOutputDebugInfo) { DrawGraph(MathUtils.FloatToDouble(audiodata), fileName + "_audiodata.png"); } // Calculate duration in ms double duration = (double) audiodata.Length / SAMPLING_RATE * 1000; // Explode samples to the range of 16 bit shorts (–32,768 to 32,767) // Matlab multiplies with 2^15 (32768) // e.g. if( max(abs(speech))<=1 ), speech = speech * 2^15; end; MathUtils.Multiply(ref audiodata, AUDIO_MULTIPLIER); // zero pad if the audio file is too short to perform a mfcc if (audiodata.Length < (WINDOW_SIZE + OVERLAP)) { int lenNew = WINDOW_SIZE + OVERLAP; Array.Resize<float>(ref audiodata, lenNew); } // work config WorkUnitParameterObject param = new WorkUnitParameterObject(); param.AudioSamples = audiodata; param.PathToAudioFile = filePath.FullName; param.MillisecondsToProcess = SECONDS_TO_ANALYZE * 1000; param.StartAtMilliseconds = 0; param.FileName = fileName; param.DurationInMs = duration; param.Tags = GetTagInfoFromFile(filePath.FullName); Dbg.WriteLine ("Get Audio File Parameters - Execution Time: {0} ms", t.Stop().TotalMilliseconds); return param; }
private static List<int[]> TestSoundfingerprintingAlgorithm(float[] samples, string name) { // work config WorkUnitParameterObject param = new WorkUnitParameterObject(); param.FingerprintingConfiguration = fingerprintingConfig; // Soundfingerprinting Service FingerprintService fingerprintService = GetSoundfingerprintingService(); // Image Service ImageService imageService = new ImageService(fingerprintService.SpectrumService, fingerprintService.WaveletService); // Get fingerprints double[][] LogSpectrogram; List<bool[]> fingerprints = fingerprintService.CreateFingerprintsFromAudioSamples(samples, param, out LogSpectrogram); int width = param.FingerprintingConfiguration.FingerprintLength; int height = param.FingerprintingConfiguration.LogBins; imageService.GetImageForFingerprints(fingerprints, width, height, 2).Save("imageservice_" + name + "_fingerprints.png"); IPermutations permutations = new LocalPermutations("Soundfingerprinting\\perms.csv", ","); /* Soundfingerprinting.DuplicatesDetector.DataAccess.Repository repository = new Soundfingerprinting.DuplicatesDetector.DataAccess.Repository(permutations); // Define track Soundfingerprinting.DuplicatesDetector.Model.Track track = new Soundfingerprinting.DuplicatesDetector.Model.Track { Title = name }; */ Soundfingerprinting.Hashing.MinHash hasher = new Soundfingerprinting.Hashing.MinHash(permutations); List<int[]> signatures = new List<int[]>(); foreach (bool[] fingerprint in fingerprints) { int[] signature = hasher.ComputeMinHashSignature(fingerprint); /*Compute min-hash signature out of signature*/ signatures.Add(signature); } return signatures; }
private static void TestSoundfingerprintingAlgorithm(string filename, string name) { // work config WorkUnitParameterObject param = new WorkUnitParameterObject(); param.PathToAudioFile = filename; param.StartAtMilliseconds = 0; param.MillisecondsToProcess = 0; param.FingerprintingConfiguration = fingerprintingConfig; // Soundfingerprinting Service FingerprintService fingerprintService = GetSoundfingerprintingService(); // Image Service ImageService imageService = new ImageService( fingerprintService.SpectrumService, fingerprintService.WaveletService); // Configuration AudioServiceConfiguration audioServiceConfiguration = new AudioServiceConfiguration { LogBins = fingerprintingConfig.LogBins, LogBase = fingerprintingConfig.LogBase, MaxFrequency = fingerprintingConfig.MaxFrequency, MinFrequency = fingerprintingConfig.MinFrequency, Overlap = fingerprintingConfig.Overlap, SampleRate = fingerprintingConfig.SampleRate, WdftSize = fingerprintingConfig.WdftSize, NormalizeSignal = fingerprintingConfig.NormalizeSignal, UseDynamicLogBase = fingerprintingConfig.UseDynamicLogBase }; double[][] spectrogram = fingerprintService.AudioService.CreateSpectrogram(filename, new Mirage.HannWindow(fingerprintingConfig.WdftSize), fingerprintingConfig.SampleRate, fingerprintingConfig.Overlap, fingerprintingConfig.WdftSize); imageService.GetSpectrogramImage(spectrogram, 600, 400).Save("imageservice_" + name + "_specgram.png"); /* Comirva.Audio.Util.Maths.Matrix stftdata = new Comirva.Audio.Util.Maths.Matrix(spectrogram).Transpose(); #if DEBUG if (Analyzer.DEBUG_INFO_VERBOSE) { if (DEBUG_OUTPUT_TEXT) { stftdata.WriteAscii(name + "_stftdata2.ascii"); stftdata.WriteCSV(name + "_stftdata2.csv", ";"); } // same as specgram(audio*32768, 2048, 44100, hanning(2048), 1024); stftdata.DrawMatrixImageLogValues(name + "_specgram2.png", true); // spec gram with log values for the y axis (frequency) stftdata.DrawMatrixImageLogY(name + "_specgramlog2.png", SAMPLING_RATE, 20, SAMPLING_RATE/2, 120, WINDOW_SIZE); } #endif */ double[][] logSpectrogram = fingerprintService.AudioService.CreateLogSpectrogram(filename, new Mirage.HannWindow(fingerprintingConfig.WdftSize), audioServiceConfiguration); imageService.GetLogSpectralImages(logSpectrogram, fingerprintingConfig.Stride, fingerprintingConfig.FingerprintLength, fingerprintingConfig.Overlap, 2).Save("imageservice_" + name + "_specgram_logimages.png"); Comirva.Audio.Util.Maths.Matrix stftdataLog = new Comirva.Audio.Util.Maths.Matrix(logSpectrogram).Transpose(); #if DEBUG if (Analyzer.DEBUG_INFO_VERBOSE) { if (DEBUG_OUTPUT_TEXT) { stftdataLog.WriteAscii(name + "_stftdataLog.ascii"); stftdataLog.WriteCSV(name + "_stftdataLog.csv", ";"); } // same as specgram(audio*32768, 2048, 44100, hanning(2048), 1024); stftdataLog.DrawMatrixImageLogValues(name + "_stftdataLog.png", true); } #endif // Get fingerprints double[][] LogSpectrogram; List<bool[]> fingerprints = fingerprintService.CreateFingerprintsFromAudioFile(param, out LogSpectrogram); int width = fingerprintingConfig.FingerprintLength; int height = fingerprintingConfig.LogBins; imageService.GetImageForFingerprints(fingerprints, width, height, 2).Save("imageservice_" + name + "_fingerprints.png"); /* IPermutations permutations = new LocalPermutations("Soundfingerprinting\\perms.csv", ","); Soundfingerprinting.DuplicatesDetector.DataAccess.Repository repository = new Soundfingerprinting.DuplicatesDetector.DataAccess.Repository(permutations); // Define track Soundfingerprinting.DuplicatesDetector.Model.Track track = new Soundfingerprinting.DuplicatesDetector.Model.Track { Title = name, Path = filename }; // Get the HashSignatures List<Soundfingerprinting.DuplicatesDetector.Model.HashSignature> signatures = repository.GetSignatures(fingerprints, track, 25, 4); return signatures; */ }
/// <summary> /// Find Similar Tracks using passed audio samples as input /// </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">Threshold percentage [0.07 for 20 LHash Tables, 0.17 for 25 LHashTables]</param> /// <param name="param">Audio File Work Unit Parameter Object</param> /// <returns>a list of perceptually similar tracks</returns> public List<FindSimilar.QueryResult> FindSimilarFromAudioSamplesList( int lshHashTables, int lshGroupsPerKey, int thresholdTables, WorkUnitParameterObject param) { // Get fingerprints double[][] logSpectrogram; List<double[][]> spectralImages; List<bool[]> signatures = fingerprintService.CreateFingerprintsFromAudioSamples(param.AudioSamples, param, out logSpectrogram, out spectralImages); 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 // TODO: What does the 0.4 number do here? // there doesn't seem to be any change using another number?! // 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 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(); return fingerprintList; }
/// <summary> /// Add the log spectrogram matrix as a Statistical Cluster Model Similarity class to the database /// </summary> /// <param name="logSpectrogramMatrix">log spectrogram matrix</param> /// <param name="fileName">clean filename without extension</param> /// <param name="fullFilePath">full file path</param> /// <param name="duration">duration in ms</param> /// <param name="db">database</param> /// <param name="trackId">track id to insert</param> /// <param name="doOutputDebugInfo">decide whether to output debug info like spectrogram and audiofile (default value can be set)</param> /// <param name="useHaarWavelet">decide whether to use haar wavelet compression or DCT compression</param> /// <returns>true if successful</returns> private static bool AnalyseAndAddScmsUsingLogSpectrogram(Comirva.Audio.Util.Maths.Matrix logSpectrogramMatrix, WorkUnitParameterObject param, Db db, int trackId, bool doOutputDebugInfo=DEFAULT_DEBUG_INFO, bool useHaarWavelet = true) { // Insert Statistical Cluster Model Similarity Audio Feature string fileName = param.FileName; Comirva.Audio.Util.Maths.Matrix scmsMatrix = null; if (useHaarWavelet) { #region Wavelet Transform int lastHeight = 0; int lastWidth = 0; scmsMatrix = mfccMirage.ApplyWaveletCompression(ref logSpectrogramMatrix, out lastHeight, out lastWidth); #if DEBUG if (DEBUG_INFO_VERBOSE) { if (DEBUG_OUTPUT_TEXT) scmsMatrix.WriteAscii(fileName + "_waveletdata.ascii"); } #endif if (doOutputDebugInfo) { scmsMatrix.DrawMatrixImageLogValues(fileName + "_waveletdata.png", true); } #if DEBUG if (DEBUG_DO_INVERSE_TESTS) { #region Inverse Wavelet // try to do an inverse wavelet transform Comirva.Audio.Util.Maths.Matrix stftdata_inverse_wavelet = mfccMirage.InverseWaveletCompression(ref scmsMatrix, lastHeight, lastWidth, logSpectrogramMatrix.Rows, logSpectrogramMatrix.Columns); if (DEBUG_OUTPUT_TEXT) stftdata_inverse_wavelet.WriteCSV(fileName + "_specgramlog_inverse_wavelet.csv", ";"); stftdata_inverse_wavelet.DrawMatrixImageLogValues(fileName + "_specgramlog_inverse_wavelet.png", true); #endregion } #endif #endregion } else { #region DCT Transform // It seems the Mirage way of applying the DCT is slightly faster than the // Comirva way due to less loops scmsMatrix = mfccMirage.ApplyDCT(ref logSpectrogramMatrix); #if DEBUG if (DEBUG_INFO_VERBOSE) { if (DEBUG_OUTPUT_TEXT) scmsMatrix.WriteAscii(fileName + "_mfccdata.ascii"); } #endif if (doOutputDebugInfo) { scmsMatrix.DrawMatrixImageLogValues(fileName + "_mfccdata.png", true); } #if DEBUG if (DEBUG_DO_INVERSE_TESTS) { #region Inverse MFCC // try to do an inverse mfcc Comirva.Audio.Util.Maths.Matrix stftdata_inverse_mfcc = mfccMirage.InverseDCT(ref scmsMatrix); if (DEBUG_OUTPUT_TEXT) stftdata_inverse_mfcc.WriteCSV(fileName + "_stftdata_inverse_mfcc.csv", ";"); stftdata_inverse_mfcc.DrawMatrixImageLogValues(fileName + "_specgramlog_inverse_mfcc.png", true); #endregion } #endif #endregion } // Store in a Statistical Cluster Model Similarity class. // i.e. a Gaussian representation of a song Scms audioFeature = Scms.GetScms(scmsMatrix, fileName); if (audioFeature != null) { // Store image if debugging if (doOutputDebugInfo) { audioFeature.Image = scmsMatrix.DrawMatrixImageLogValues(fileName + "_featuredata.png", true, false, 0, 0, true); } // Store bitstring hash as well string hashString = GetBitString(scmsMatrix); audioFeature.BitString = hashString; // Store duration audioFeature.Duration = (long) param.DurationInMs; // Store file name audioFeature.Name = param.PathToAudioFile; // Add to database int id = trackId; if (db.AddTrack(ref id, audioFeature) == -1) { Console.Out.WriteLine("Failed! Could not add audio feature to database ({0})!", fileName); return false; } else { return true; } } else { Console.Out.WriteLine("Error! Could not compute the Scms for '{0}'!", fileName); return false; } }
//private static Mfcc mfccOptimized = new Mfcc(WINDOW_SIZE, SAMPLING_RATE, MEL_COEFFICIENTS, MFCC_COEFFICIENTS); //private static MFCC mfccComirva = new MFCC(SAMPLING_RATE, WINDOW_SIZE, MFCC_COEFFICIENTS, true, 20.0, SAMPLING_RATE/2, MEL_COEFFICIENTS); #endif #region Methods public static bool AnalyzeAndAdd(FileInfo filePath, Db db, DatabaseService databaseService, bool doOutputDebugInfo=DEFAULT_DEBUG_INFO, bool useHaarWavelet = true) { DbgTimer t = new DbgTimer(); t.Start (); float[] audiodata = AudioFileReader.Decode(filePath.FullName, SAMPLING_RATE, SECONDS_TO_ANALYZE); if (audiodata == null || audiodata.Length == 0) { Dbg.WriteLine("Error! - No Audio Found"); return false; } // Read TAGs using BASS FindSimilar.AudioProxies.BassProxy bass = FindSimilar.AudioProxies.BassProxy.Instance; Un4seen.Bass.AddOn.Tags.TAG_INFO tag_info = bass.GetTagInfoFromFile(filePath.FullName); // Name of file being processed string name = StringUtils.RemoveNonAsciiCharacters(Path.GetFileNameWithoutExtension(filePath.Name)); #if DEBUG if (Analyzer.DEBUG_INFO_VERBOSE) { if (DEBUG_OUTPUT_TEXT) WriteAscii(audiodata, name + "_audiodata.ascii"); if (DEBUG_OUTPUT_TEXT) WriteF3Formatted(audiodata, name + "_audiodata.txt"); } #endif if (doOutputDebugInfo) { DrawGraph(MathUtils.FloatToDouble(audiodata), name + "_audiodata.png"); } // Calculate duration in ms double duration = (double) audiodata.Length / SAMPLING_RATE * 1000; // Explode samples to the range of 16 bit shorts (–32,768 to 32,767) // Matlab multiplies with 2^15 (32768) // e.g. if( max(abs(speech))<=1 ), speech = speech * 2^15; end; MathUtils.Multiply(ref audiodata, AUDIO_MULTIPLIER); // 65536 // zero pad if the audio file is too short to perform a mfcc if (audiodata.Length < (fingerprintingConfig.WdftSize + fingerprintingConfig.Overlap)) { int lenNew = fingerprintingConfig.WdftSize + fingerprintingConfig.Overlap; Array.Resize<float>(ref audiodata, lenNew); } // Get fingerprint signatures using the Soundfingerprinting methods IPermutations permutations = new LocalPermutations("Soundfingerprinting\\perms.csv", ","); Repository repository = new Repository(permutations, databaseService, fingerprintService); // Image Service ImageService imageService = new ImageService( fingerprintService.SpectrumService, fingerprintService.WaveletService); // work config WorkUnitParameterObject param = new WorkUnitParameterObject(); param.FingerprintingConfiguration = fingerprintingConfig; param.AudioSamples = audiodata; param.PathToAudioFile = filePath.FullName; param.MillisecondsToProcess = SECONDS_TO_ANALYZE * 1000; param.StartAtMilliseconds = 0; // build track Track track = new Track(); track.Title = name; track.TrackLengthMs = (int) duration; track.FilePath = filePath.FullName; track.Id = -1; // this will be set by the insert method #region parse tag_info if (tag_info != null) { Dictionary<string, string> tags = new Dictionary<string, string>(); //if (tag_info.title != string.Empty) tags.Add("title", tag_info.title); if (tag_info.artist != string.Empty) tags.Add("artist", tag_info.artist); if (tag_info.album != string.Empty) tags.Add("album", tag_info.album); if (tag_info.albumartist != string.Empty) tags.Add("albumartist", tag_info.albumartist); if (tag_info.year != string.Empty) tags.Add("year", tag_info.year); if (tag_info.comment != string.Empty) tags.Add("comment", tag_info.comment); if (tag_info.genre != string.Empty) tags.Add("genre", tag_info.genre); if (tag_info.track != string.Empty) tags.Add("track", tag_info.track); if (tag_info.disc != string.Empty) tags.Add("disc", tag_info.disc); if (tag_info.copyright != string.Empty) tags.Add("copyright", tag_info.copyright); if (tag_info.encodedby != string.Empty) tags.Add("encodedby", tag_info.encodedby); if (tag_info.composer != string.Empty) tags.Add("composer", tag_info.composer); if (tag_info.publisher != string.Empty) tags.Add("publisher", tag_info.publisher); if (tag_info.lyricist != string.Empty) tags.Add("lyricist", tag_info.lyricist); if (tag_info.remixer != string.Empty) tags.Add("remixer", tag_info.remixer); if (tag_info.producer != string.Empty) tags.Add("producer", tag_info.producer); if (tag_info.bpm != string.Empty) tags.Add("bpm", tag_info.bpm); //if (tag_info.filename != string.Empty) tags.Add("filename", tag_info.filename); tags.Add("channelinfo", tag_info.channelinfo.ToString()); //if (tag_info.duration > 0) tags.Add("duration", tag_info.duration.ToString()); if (tag_info.bitrate > 0) tags.Add("bitrate", tag_info.bitrate.ToString()); if (tag_info.replaygain_track_gain != -100f) tags.Add("replaygain_track_gain", tag_info.replaygain_track_gain.ToString()); if (tag_info.replaygain_track_peak != -1f) tags.Add("replaygain_track_peak", tag_info.replaygain_track_peak.ToString()); if (tag_info.conductor != string.Empty) tags.Add("conductor", tag_info.conductor); if (tag_info.grouping != string.Empty) tags.Add("grouping", tag_info.grouping); if (tag_info.mood != string.Empty) tags.Add("mood", tag_info.mood); if (tag_info.rating != string.Empty) tags.Add("rating", tag_info.rating); if (tag_info.isrc != string.Empty) tags.Add("isrc", tag_info.isrc); foreach(var nativeTag in tag_info.NativeTags) { string[] keyvalue = nativeTag.Split('='); tags.Add(keyvalue[0], keyvalue[1]); } track.Tags = tags; } #endregion double[][] logSpectrogram; if (repository.InsertTrackInDatabaseUsingSamples(track, 25, 4, param, out logSpectrogram)) { // store logSpectrogram as Matrix Comirva.Audio.Util.Maths.Matrix logSpectrogramMatrix = new Comirva.Audio.Util.Maths.Matrix(logSpectrogram); logSpectrogramMatrix = logSpectrogramMatrix.Transpose(); #region Debug for Soundfingerprinting Method if (doOutputDebugInfo) { imageService.GetLogSpectralImages(logSpectrogram, fingerprintingConfig.Stride, fingerprintingConfig.FingerprintLength, fingerprintingConfig.Overlap, 2).Save(name + "_specgram_logimages.png"); logSpectrogramMatrix.DrawMatrixImageLogValues(name + "_specgram_logimage.png", true); if (DEBUG_OUTPUT_TEXT) { logSpectrogramMatrix.WriteCSV(name + "_specgram_log.csv", ";"); } } #endregion #region Insert Statistical Cluster Model Similarity Audio Feature as well Comirva.Audio.Util.Maths.Matrix scmsMatrix = null; if (useHaarWavelet) { #region Wavelet Transform int lastHeight = 0; int lastWidth = 0; scmsMatrix = mfccMirage.ApplyWaveletCompression(ref logSpectrogramMatrix, out lastHeight, out lastWidth); #if DEBUG if (Analyzer.DEBUG_INFO_VERBOSE) { if (DEBUG_OUTPUT_TEXT) scmsMatrix.WriteAscii(name + "_waveletdata.ascii"); } #endif if (doOutputDebugInfo) { scmsMatrix.DrawMatrixImageLogValues(name + "_waveletdata.png", true); } #if DEBUG if (Analyzer.DEBUG_INFO_VERBOSE) { #region Inverse Wavelet // try to do an inverse wavelet transform Comirva.Audio.Util.Maths.Matrix stftdata_inverse_wavelet = mfccMirage.InverseWaveletCompression(ref scmsMatrix, lastHeight, lastWidth, logSpectrogramMatrix.Rows, logSpectrogramMatrix.Columns); if (DEBUG_OUTPUT_TEXT) stftdata_inverse_wavelet.WriteCSV(name + "_specgramlog_inverse_wavelet.csv", ";"); stftdata_inverse_wavelet.DrawMatrixImageLogValues(name + "_specgramlog_inverse_wavelet.png", true); #endregion } #endif #endregion } else { #region DCT Transform // It seems the Mirage way of applying the DCT is slightly faster than the // Comirva way due to less loops scmsMatrix = mfccMirage.ApplyDCT(ref logSpectrogramMatrix); #if DEBUG if (Analyzer.DEBUG_INFO_VERBOSE) { if (DEBUG_OUTPUT_TEXT) scmsMatrix.WriteAscii(name + "_mfccdata.ascii"); } #endif if (doOutputDebugInfo) { scmsMatrix.DrawMatrixImageLogValues(name + "_mfccdata.png", true); } #if DEBUG if (Analyzer.DEBUG_INFO_VERBOSE) { #region Inverse MFCC // try to do an inverse mfcc Comirva.Audio.Util.Maths.Matrix stftdata_inverse_mfcc = mfccMirage.InverseDCT(ref scmsMatrix); if (DEBUG_OUTPUT_TEXT) stftdata_inverse_mfcc.WriteCSV(name + "_stftdata_inverse_mfcc.csv", ";"); stftdata_inverse_mfcc.DrawMatrixImageLogValues(name + "_specgramlog_inverse_mfcc.png", true); #endregion } #endif #endregion } // Store in a Statistical Cluster Model Similarity class. // A Gaussian representation of a song Scms audioFeature = Scms.GetScms(scmsMatrix, name); if (audioFeature != null) { // Store image if debugging if (doOutputDebugInfo) { audioFeature.Image = scmsMatrix.DrawMatrixImageLogValues(name + "_featuredata.png", true, false, 0, 0, true); } // Store bitstring hash as well string hashString = GetBitString(scmsMatrix); audioFeature.BitString = hashString; // Store duration audioFeature.Duration = (long) duration; // Store file name audioFeature.Name = filePath.FullName; int id = track.Id; if (db.AddTrack(ref id, audioFeature) == -1) { Console.Out.WriteLine("Failed! Could not add audioFeature to database {0}!", name); } } #endregion } else { // failed return false; } Dbg.WriteLine ("AnalyzeAndAdd - Total Execution Time: {0} ms", t.Stop().TotalMilliseconds); return true; }
private static List<bool[]> GetFingerprintSignatures(FingerprintService fingerprintService, float[] samples, string name) { Mirage.DbgTimer t = new Mirage.DbgTimer(); t.Start(); // work config WorkUnitParameterObject param = new WorkUnitParameterObject(); param.FingerprintingConfiguration = fingerprintingConfigCreation; // Get fingerprints double[][] LogSpectrogram; List<double[][]> spectralImages; List<bool[]> fingerprints = fingerprintService.CreateFingerprintsFromAudioSamples(samples, param, out LogSpectrogram, out spectralImages); #if DEBUG if (Analyzer.DEBUG_INFO_VERBOSE) { // Image Service ImageService imageService = new ImageService(fingerprintService.SpectrumService, fingerprintService.WaveletService); int width = param.FingerprintingConfiguration.FingerprintLength; int height = param.FingerprintingConfiguration.LogBins; imageService.GetImageForFingerprints(fingerprints, width, height, 2).Save(name + "_fingerprints.png"); } #endif Mirage.Dbg.WriteLine("GetFingerprintSignatures Execution Time: " + t.Stop().TotalMilliseconds + " ms"); return fingerprints; }
public static AudioFeature AnalyzeSoundfingerprinting(FileInfo filePath, bool doOutputDebugInfo=DEFAULT_DEBUG_INFO, bool useHaarWavelet = true) { DbgTimer t = new DbgTimer(); t.Start (); float[] audiodata = AudioFileReader.Decode(filePath.FullName, SAMPLING_RATE, SECONDS_TO_ANALYZE); if (audiodata == null || audiodata.Length == 0) { Dbg.WriteLine("Error! - No Audio Found"); return null; } // Read TAGs using BASS FindSimilar.AudioProxies.BassProxy bass = FindSimilar.AudioProxies.BassProxy.Instance; Un4seen.Bass.AddOn.Tags.TAG_INFO tag_info = bass.GetTagInfoFromFile(filePath.FullName); // Name of file being processed string name = StringUtils.RemoveNonAsciiCharacters(Path.GetFileNameWithoutExtension(filePath.Name)); #if DEBUG if (Analyzer.DEBUG_INFO_VERBOSE) { if (DEBUG_OUTPUT_TEXT) WriteAscii(audiodata, name + "_audiodata.ascii"); if (DEBUG_OUTPUT_TEXT) WriteF3Formatted(audiodata, name + "_audiodata.txt"); } #endif if (doOutputDebugInfo) { DrawGraph(MathUtils.FloatToDouble(audiodata), name + "_audiodata.png"); } // Calculate duration in ms double duration = (double) audiodata.Length / SAMPLING_RATE * 1000; // zero pad if the audio file is too short to perform a mfcc if (audiodata.Length < (fingerprintingConfig.WdftSize + fingerprintingConfig.Overlap)) { int lenNew = fingerprintingConfig.WdftSize + fingerprintingConfig.Overlap; Array.Resize<float>(ref audiodata, lenNew); } // Get fingerprint signatures using the Soundfingerprinting methods // Get database DatabaseService databaseService = DatabaseService.Instance; IPermutations permutations = new LocalPermutations("Soundfingerprinting\\perms.csv", ","); Repository repository = new Repository(permutations, databaseService, fingerprintService); // Image Service ImageService imageService = new ImageService( fingerprintService.SpectrumService, fingerprintService.WaveletService); // work config WorkUnitParameterObject param = new WorkUnitParameterObject(); param.FingerprintingConfiguration = fingerprintingConfig; param.AudioSamples = audiodata; param.PathToAudioFile = filePath.FullName; param.MillisecondsToProcess = SECONDS_TO_ANALYZE * 1000; param.StartAtMilliseconds = 0; // build track Track track = new Track(); track.Title = name; track.TrackLengthMs = (int) duration; track.FilePath = filePath.FullName; track.Id = -1; // this will be set by the insert method #region parse tag_info if (tag_info != null) { Dictionary<string, string> tags = new Dictionary<string, string>(); //if (tag_info.title != string.Empty) tags.Add("title", tag_info.title); if (tag_info.artist != string.Empty) tags.Add("artist", tag_info.artist); if (tag_info.album != string.Empty) tags.Add("album", tag_info.album); if (tag_info.albumartist != string.Empty) tags.Add("albumartist", tag_info.albumartist); if (tag_info.year != string.Empty) tags.Add("year", tag_info.year); if (tag_info.comment != string.Empty) tags.Add("comment", tag_info.comment); if (tag_info.genre != string.Empty) tags.Add("genre", tag_info.genre); if (tag_info.track != string.Empty) tags.Add("track", tag_info.track); if (tag_info.disc != string.Empty) tags.Add("disc", tag_info.disc); if (tag_info.copyright != string.Empty) tags.Add("copyright", tag_info.copyright); if (tag_info.encodedby != string.Empty) tags.Add("encodedby", tag_info.encodedby); if (tag_info.composer != string.Empty) tags.Add("composer", tag_info.composer); if (tag_info.publisher != string.Empty) tags.Add("publisher", tag_info.publisher); if (tag_info.lyricist != string.Empty) tags.Add("lyricist", tag_info.lyricist); if (tag_info.remixer != string.Empty) tags.Add("remixer", tag_info.remixer); if (tag_info.producer != string.Empty) tags.Add("producer", tag_info.producer); if (tag_info.bpm != string.Empty) tags.Add("bpm", tag_info.bpm); //if (tag_info.filename != string.Empty) tags.Add("filename", tag_info.filename); tags.Add("channelinfo", tag_info.channelinfo.ToString()); //if (tag_info.duration > 0) tags.Add("duration", tag_info.duration.ToString()); if (tag_info.bitrate > 0) tags.Add("bitrate", tag_info.bitrate.ToString()); if (tag_info.replaygain_track_gain != -100f) tags.Add("replaygain_track_gain", tag_info.replaygain_track_gain.ToString()); if (tag_info.replaygain_track_peak != -1f) tags.Add("replaygain_track_peak", tag_info.replaygain_track_peak.ToString()); if (tag_info.conductor != string.Empty) tags.Add("conductor", tag_info.conductor); if (tag_info.grouping != string.Empty) tags.Add("grouping", tag_info.grouping); if (tag_info.mood != string.Empty) tags.Add("mood", tag_info.mood); if (tag_info.rating != string.Empty) tags.Add("rating", tag_info.rating); if (tag_info.isrc != string.Empty) tags.Add("isrc", tag_info.isrc); foreach(var nativeTag in tag_info.NativeTags) { string[] keyvalue = nativeTag.Split('='); tags.Add(keyvalue[0], keyvalue[1]); } track.Tags = tags; } #endregion AudioFeature audioFeature = null; double[][] logSpectrogram; if (repository.InsertTrackInDatabaseUsingSamples(track, 25, 4, param, out logSpectrogram)) { if (doOutputDebugInfo) { imageService.GetLogSpectralImages(logSpectrogram, fingerprintingConfig.Stride, fingerprintingConfig.FingerprintLength, fingerprintingConfig.Overlap, 2).Save(name + "_specgram_logimages.png"); Comirva.Audio.Util.Maths.Matrix logSpectrogramMatrix = new Comirva.Audio.Util.Maths.Matrix(logSpectrogram); logSpectrogramMatrix = logSpectrogramMatrix.Transpose(); logSpectrogramMatrix.DrawMatrixImageLogValues(name + "_specgram_logimage.png", true); if (DEBUG_OUTPUT_TEXT) { logSpectrogramMatrix.WriteCSV(name + "_specgram_log.csv", ";"); } } audioFeature = new DummyAudioFeature(); // Store duration audioFeature.Duration = (long) duration; // Store file name audioFeature.Name = filePath.FullName; } else { // failed } Dbg.WriteLine ("Soundfingerprinting - Total Execution Time: {0} ms", t.Stop().TotalMilliseconds); return audioFeature; }
private static bool AnalyseAndAddScmsUsingFingerprints(List<bool[]> fingerprints, WorkUnitParameterObject param, Db db, int trackId, bool doOutputDebugInfo=DEFAULT_DEBUG_INFO) { DbgTimer t = new DbgTimer(); t.Start (); // Insert Statistical Cluster Model Similarity Audio Feature string fileName = param.FileName; int fingerprintWidth = param.FingerprintingConfiguration.FingerprintLength; int fingerprintHeight = param.FingerprintingConfiguration.LogBins; int fingerprintCount = 0; foreach (bool[] fingerprint in fingerprints) { fingerprintCount++; Comirva.Audio.Util.Maths.Matrix scmsMatrix = new Comirva.Audio.Util.Maths.Matrix(fingerprintWidth, fingerprintHeight); for (int i = 0; i < fingerprintWidth /*128*/; i++) { for (int j = 0; j < fingerprintHeight /*32*/; j++) { // Negative Numbers = 01 // Positive Numbers = 10 // Zeros = 00 bool v1 = fingerprint[(2 * fingerprintHeight * i) + (2 * j)]; bool v2 = fingerprint[(2 * fingerprintHeight * i) + (2 * j) + 1]; if (v1) { scmsMatrix.MatrixData[i][j] = 2.0; } else if (v2) { scmsMatrix.MatrixData[i][j] = 0.0; } else { scmsMatrix.MatrixData[i][j] = 1.0; } } } if (doOutputDebugInfo) { scmsMatrix.DrawMatrixImage(String.Format("{0}_fingerprint_{1}.png", fileName, fingerprintCount), fingerprintWidth, fingerprintHeight); } #region Store in a Statistical Cluster Model Similarity class. Scms audioFeature = Scms.GetScmsNoInverse(scmsMatrix, fileName); if (audioFeature != null) { // Store bitstring hash as well audioFeature.BitString = GetBitString(fingerprint); // Store duration audioFeature.Duration = (long) param.DurationInMs; // Store file name audioFeature.Name = param.PathToAudioFile; // Add to database int id = trackId; if (db.AddTrack(audioFeature) == -1) { Console.Out.WriteLine("Failed! Could not add audio feature to database ({0})!", fileName); return false; } } else { return false; } #endregion } Dbg.WriteLine ("AnalyseAndAddScmsUsingFingerprints - Execution Time: {0} ms", t.Stop().TotalMilliseconds); return true; }
/// <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; }