public FingerprintSignature CreateAudioFingerprint(string key, string filename, int startPositionInMS, int toReadInMS) { SpectrogramConfig spectrogramConfig = new DefaultSpectrogramConfig(); AudioSamples samples = null; try { // First read audio file and downsample it to mono 5512hz samples = audioEngine.ReadMonoFromFile(filename, spectrogramConfig.SampleRate, startPositionInMS, toReadInMS); } catch { return(null); } // No slice the audio is chunks seperated by 11,6 ms (5512hz 11,6ms = 64 samples!) // An with length of 371ms (5512kHz 371ms = 2048 samples [rounded]) FingerprintSignature fingerprint = audioEngine.CreateFingerprint(samples, spectrogramConfig); if (fingerprint != null) { fingerprint.Reference = key; } return(fingerprint); }
private void DetectAudio(float[] inputAudioSample, int inputSampleRate, int inputChannels) { TimeSpan wait = (DateTime.Now - waitUntil); if (wait.TotalDays < 0 && wait.TotalSeconds < 0) { return; } // Run separeted task, ignore when one is allready running lock (lockObject) { // if detection task is runnign don't run a new one (otherwhise als er al een detectie draait dan niet verder gaan if (detectTask != null) { return; } detectTask = new WSRecognize(); } //lock Task task = Task.Factory.StartNew(() => { using (AudioEngine ae = new AudioEngine()) { AudioSamples audio = new AudioSamples(); audio.Channels = inputChannels; audio.SampleRate = inputSampleRate; audio.Samples = inputAudioSample; audio.Origin = "MEMORY"; if (doTimeStretching) { Console.WriteLine("Timestretching with " + timeStretchRateFactor.ToString("#0.00") + "f"); audio = ae.TimeStretch(audio.Samples, audio.SampleRate, audio.Channels, timeStretchRateFactor); } audio = ae.Resample(audio.Samples, audio.SampleRate, audio.Channels, 5512); FingerprintSignature fsQuery = ae.CreateFingerprint(audio, SpectrogramConfig.Default); switch (webServiceCall) { case "SLOW": detectTask.DetectAudioFragmentSlow(fsQuery, null, REST_ResultFingerDetect); break; default: detectTask.DetectAudioFragmentFast(fsQuery, null, REST_ResultFingerDetect); break; } //detectTask.DetectAudioFragment(fsQuery, null, REST_ResultFingerDetect); } //using }); }
public void ScanDirectoryAndFingerprint(string directory) { // Expand directory to full directory path. // We needed to remove filename part because GetFullPath doesn't suppport wildcards string wildcard = Path.GetFileName(directory); directory = Path.GetDirectoryName(directory); directory = Path.GetFullPath(directory); directory = Path.Combine(directory, wildcard); foreach (string f in Directory.GetFiles(Path.GetDirectoryName(directory), Path.GetFileName(directory))) { Console.WriteLine(Path.GetFileName(f)); // For best result you should return the same key for the same file. Muziekweb.nl uses an cataloguenumber (some chars and a number, 7 or 8 char long in total) // then we added the track number. (Fieldname: TITELNUMMERTRACK) string referenceKey = GenerateCRC32Key(f); FingerprintAcoustID fingerprint = MakeAcoustIDFinger(referenceKey, f); FingerprintSignature subFingerprint = MakeSubFingerID(referenceKey, f); // Fill with some subdata if (subFingerprint != null && fingerprint != null) { // AcoustID fingerprint.AudioSource = Path.GetExtension(f).Replace(".", "").ToUpper(); fingerprint.Lokatie = f; // Path.GetDirectoryName(f); fingerprint.DateRelease = DateTime.Now.Date; fingerprint.CatalogusCode = "POPULAIR"; // POPULAIR or CLASSICAL fingerprint.UniformeTitleLink = ""; // used in muziekweb.nl database to find the same track on different albums // Subfinger subFingerprint.AudioSource = Path.GetExtension(f).Replace(".", "").ToUpper(); subFingerprint.Lokatie = f; // Path.GetDirectoryName(f); subFingerprint.DateRelease = DateTime.Now.Date; subFingerprint.CatalogusCode = "POPULAIR"; // POPULAIR or CLASSICAL subFingerprint.UniformeTitleLink = ""; // used in muziekweb.nl database to find the same track on different albums } // Store the data in de MySQL Database, this will later be used to create an inverted index using lucene. int titelnummertrackID; Exec_MySQL_SUBFINGERID_IU(subFingerprint.Reference.ToString(), subFingerprint.CatalogusCode, subFingerprint.DateRelease, subFingerprint.UniformeTitleLink, subFingerprint.AudioSource, subFingerprint.Lokatie, subFingerprint.DurationInMS, subFingerprint.Signature, out titelnummertrackID); Exec_MySQL_FINGERID_IU(fingerprint.Reference.ToString(), fingerprint.CatalogusCode, fingerprint.DateRelease, fingerprint.UniformeTitleLink, fingerprint.AudioSource, fingerprint.Lokatie, fingerprint.DurationInMS, fingerprint.Signature, out titelnummertrackID); } //foreach }
/// <summary> /// Test the subfinger fingerprints, by trying to find a 15 second audio in 3 different bitrates. /// /// Needed are: /// 1. MySQL database /// 2. CreateAudioFingerprint (Fills the MySQL database with fingerprints) /// 3. CreateInversedFingerprintIndex (Create a lucene reversed search index, needed to identity a fingerprint) /// 4. This program to find a 15 second fragment of audio /// </summary> public void RunSubFingerTest() { Console.WriteLine("SubFinger test."); if (!System.IO.Directory.Exists(subFingerLookupPath)) { Console.WriteLine("SubFinger path not found."); return; } Console.WriteLine("Opening index. With larges indexes this can take a while."); IndexSearcher indexSubFingerLookup = new IndexSearcher(IndexReader.Open(FSDirectory.Open(new System.IO.DirectoryInfo(subFingerLookupPath)), true)); indexSubFingerLookup.Similarity = new CDR.Indexer.DefaultSimilarityExtended2(); Console.WriteLine("Ready opening index."); SubFingerprintQuery query = new SubFingerprintQuery(indexSubFingerLookup); FingerprintSignature fsQuery = null; Resultset answer = null; fsQuery = CreateSubFingerprintFromAudio(@"..\..\..\Audio\Samples\JK147510-0002-224Sample-45s-60s.mp3"); answer = query.MatchAudioFingerprint(fsQuery); if (!retrieveMetadataFromMuziekweb) { ThrowIfInvalidAnswer(answer, "A5D062DE"); } PrintAnswer(answer); Console.WriteLine(); fsQuery = CreateSubFingerprintFromAudio(@"..\..\..\Audio\Samples\JK147510-0002-128Sample-45s-60s.mp3"); answer = query.MatchAudioFingerprint(fsQuery); if (!retrieveMetadataFromMuziekweb) { ThrowIfInvalidAnswer(answer, "A5D062DE"); } PrintAnswer(answer); Console.WriteLine(); fsQuery = CreateSubFingerprintFromAudio(@"..\..\..\Audio\Samples\JK147510-0002-64Sample-45s-60s.mp3"); answer = query.MatchAudioFingerprint(fsQuery); if (!retrieveMetadataFromMuziekweb) { ThrowIfInvalidAnswer(answer, "A5D062DE"); } PrintAnswer(answer); Console.WriteLine(); }
/// <summary> /// Read a audio file (remember for sub fingerprints no more than 15 seconds) /// Downsample it to mono and 5512Hz /// Use the samples to create a fingerprint /// /// return a fingerprint signature. /// </summary> private FingerprintSignature CreateSubFingerprintFromAudio(string filename) { DateTime startTime = DateTime.Now; SpectrogramConfig spectrogramConfig = new DefaultSpectrogramConfig(); // First read audio file and downsample it to mono 5512hz AudioSamples samples = audioEngine.ReadMonoFromFile(filename, spectrogramConfig.SampleRate, 0, -1); Console.WriteLine(string.Format("Resample tot mono {0}hz : {1:##0.000} sec.", spectrogramConfig.SampleRate, (DateTime.Now - startTime).TotalMilliseconds / 1000)); startTime = DateTime.Now; // Now slice the audio in chunks seperated by 11,6 ms (5512hz 11,6ms = 64 samples!) // An with length of 371ms (5512kHz 371ms = 2048 samples [rounded]) FingerprintSignature fsQuery = audioEngine.CreateFingerprint(samples, spectrogramConfig); Console.WriteLine(string.Format("Hashing audio to fingerprint : {0:##0.000} sec.", (DateTime.Now - startTime).TotalMilliseconds / 1000)); return(fsQuery); }
private FingerprintSignature MakeSubFingerID(string key, string filename) { FingerprintSignature fingerprint = null; AudioEngine audioEngine = new AudioEngine(); try { SpectrogramConfig spectrogramConfig = new DefaultSpectrogramConfig(); AudioSamples samples = null; try { // First read audio file and downsample it to mono 5512hz samples = audioEngine.ReadMonoFromFile(filename, spectrogramConfig.SampleRate, 0, -1); } catch { return(null); } // No slice the audio is chunks seperated by 11,6 ms (5512hz 11,6ms = 64 samples!) // An with length of 371ms (5512kHz 371ms = 2048 samples [rounded]) fingerprint = audioEngine.CreateFingerprint(samples, spectrogramConfig); if (fingerprint != null) { fingerprint.Reference = key; } } finally { if (audioEngine != null) { audioEngine.Close(); audioEngine = null; } } return(fingerprint); }
public bool CreateSubFingerLookupIndex(string luceneIndexPath) { DateTime startTime = DateTime.Now; DateTime endTime = startTime; Console.WriteLine("Creating SubFingerLookup index."); int minID; int maxID; if (!Exec_MySQL_MinAndMax_IDS(out minID, out maxID) && minID >= 1) { return(false); } if (!System.IO.Directory.Exists(luceneIndexPath)) { System.IO.Directory.CreateDirectory(luceneIndexPath); } ClearFolder(luceneIndexPath); Lucene.Net.Store.Directory directory = FSDirectory.Open(new System.IO.DirectoryInfo(luceneIndexPath)); IndexWriter iw = null; int fingerCount = 0; try { iw = new IndexWriter(directory, new StandardAnalyzer(Lucene.Net.Util.Version.LUCENE_30), true, IndexWriter.MaxFieldLength.UNLIMITED); iw.UseCompoundFile = false; iw.SetSimilarity(new CDR.Indexer.DefaultSimilarityExtended()); iw.MergeFactor = 10; // default = 10 iw.SetRAMBufferSizeMB(512 * 3); // use memory to do a flush iw.SetMaxBufferedDocs(IndexWriter.DISABLE_AUTO_FLUSH); // only use memory as trigger to do a flush iw.SetMaxBufferedDeleteTerms(IndexWriter.DISABLE_AUTO_FLUSH); // only use memory as trigger to do a flush Document doc = new Document(); doc.Add(new Field("FINGERID", "", Field.Store.YES, Field.Index.NOT_ANALYZED)); doc.Add(new Field("SUBFINGER", "", Field.Store.NO, Field.Index.ANALYZED)); Field fFingerID = doc.GetField("FINGERID"); fFingerID.OmitNorms = true; fFingerID.OmitTermFreqAndPositions = true; Field fSubFinger = doc.GetField("SUBFINGER"); fSubFinger.OmitNorms = true; fSubFinger.OmitTermFreqAndPositions = true; StringBuilder sb = new StringBuilder(256 * 1024); int start = minID; int count = 5000; while (start <= maxID) { DataTable dt; if (Exec_MySQL_LOADSUBFINGERIDS(start, (start + count - 1), out dt)) { foreach (DataRow row in dt.Rows) { fingerCount++; if ((fingerCount % 100) == 0 || fingerCount <= 1) { Console.Write("\rIndexing subfingerprint #" + fingerCount.ToString()); } FingerprintSignature fingerprint = new FingerprintSignature((string)row["TITELNUMMERTRACK"], Convert.ToInt64(row["TITELNUMMERTRACK_ID"]), (byte[])row["SIGNATURE"], Convert.ToInt64(row["DURATIONINMS"])); sb.Clear(); for (int i = 0; i < fingerprint.SubFingerprintCount; i++) { uint subFingerValue = fingerprint.SubFingerprint(i); int bits = AudioFingerprint.Math.SimilarityUtility.HammingDistance(subFingerValue, 0); if (bits < 10 || bits > 22) // 5 27 { continue; } sb.Append(subFingerValue.ToString()); sb.Append(' '); } fFingerID.SetValue(row["TITELNUMMERTRACK_ID"].ToString()); fSubFinger.SetValue(sb.ToString()); iw.AddDocument(doc); } //foreach Console.Write("\rIndexing subfingerprint #" + fingerCount.ToString()); start += count; } //if else { if (!RetryDatabaseError()) { return(false); } } } // while alle fingerprints } finally { Console.WriteLine(); Console.WriteLine("Optimizing."); if (iw != null) { // Optimaliseer de index nu iw.Commit(); iw.Optimize(1, true); iw.Dispose(); iw = null; GC.WaitForPendingFinalizers(); } } endTime = DateTime.Now; TimeSpan ts = (endTime - startTime); Console.WriteLine(String.Format("Elapsed index time {0:00}:{1:00}:{2:00}.{3:000}", ts.Hours, ts.Minutes, ts.Seconds, ts.Milliseconds)); Console.WriteLine(); return(true); }
public Message FingerprintRecognize(Stream stream) { string errorMessage; if (!UserAccountManager.HasAccess(UserAccountManager.CurrentAccessGroup, out errorMessage, true)) { return(ServiceHelper.SendErrorMessage(ResultErrorCode.AuthorizationError, errorMessage)); } UserAccountManager.GlobalNumberOfRequestsInc(); XElement xResult = null; try { QueryString qs = new QueryString(stream); string fingerprint = qs["Fingerprint"]; string reliabilty = qs["Reliabilities"]; using (FingerprintSignature fsQuery = new FingerprintSignature("UNKNOWN", 0, System.Convert.FromBase64String(fingerprint), 0, true)) { fsQuery.Reliabilities = System.Convert.FromBase64String(reliabilty); LuceneIndex subFingerIndex = LuceneIndexes.IndexSubFingerprint; try { // We moeten hier al locken aangezien de audiofingerprint library geen weet heeft van onze // LuceneIndex object subFingerIndex.Lock(); using (SubFingerprintQuery query = new SubFingerprintQuery(subFingerIndex.Index)) { Resultset answer = query.MatchAudioFingerprint(fsQuery, 2300); if (answer != null) { xResult = ServiceHelper.CreateRoot(ResultErrorCode.OK); xResult.Add(new XElement("RecognizeResult", new XAttribute("RecognizeCode", 0), "OK")); XElement xTimeStatistics = new XElement("TimeStatistics"); xTimeStatistics.Add(new XElement("TotalQueryTime", new XAttribute("Unit", "ms"), (int)answer.QueryTime.TotalMilliseconds)); xTimeStatistics.Add(new XElement("SubFingerQueryTime", new XAttribute("Unit", "ms"), (int)answer.FingerQueryTime.TotalMilliseconds)); xTimeStatistics.Add(new XElement("FingerLoadTime", new XAttribute("Unit", "ms"), (int)answer.FingerLoadTime.TotalMilliseconds)); xTimeStatistics.Add(new XElement("MatchTime", new XAttribute("Unit", "ms"), (int)answer.MatchTime.TotalMilliseconds)); xResult.Add(xTimeStatistics); XElement xFingerTracks = new XElement("FingerTracks", new XAttribute("Count", 0)); xResult.Add(xFingerTracks); if (answer.ResultEntries.Count > 0) { // Gets a NumberFormatInfo associated with the en-US culture. System.Globalization.NumberFormatInfo nfi = new System.Globalization.CultureInfo("en-US", false).NumberFormat; nfi.CurrencySymbol = "€"; nfi.CurrencyDecimalDigits = 2; nfi.CurrencyDecimalSeparator = "."; nfi.NumberGroupSeparator = ""; nfi.NumberDecimalSeparator = "."; Dictionary <string, ResultEntry> dict = new Dictionary <string, ResultEntry>(); int count = 0; foreach (ResultEntry item in answer.ResultEntries) { XElement xFingerTrack = new XElement("FingerTrack"); xFingerTracks.Add(xFingerTrack); xFingerTrack.Add(new XAttribute("BER", item.Similarity.ToString())); xFingerTrack.Add(new XElement("DetectPosition", new XAttribute("Unit", "ms"), new XAttribute("InSec", string.Format(nfi, "{0:#0.000}", (item.Time.TotalMilliseconds / 1000))), (int)item.Time.TotalMilliseconds)); XElement xSearchStrategy = new XElement("SearchStrategy"); xFingerTrack.Add(xSearchStrategy); xSearchStrategy.Add(new XElement("IndexNumberInMatchList", item.IndexNumberInMatchList)); xSearchStrategy.Add(new XElement("SubFingerCountHitInFingerprint", item.SubFingerCountHitInFingerprint)); xSearchStrategy.Add(new XElement("SearchName", item.SearchStrategy.ToString())); xSearchStrategy.Add(new XElement("SearchIteration", item.SearchIteration)); xFingerTrack.Add(new XElement("Reference", item.Reference.ToString())); xFingerTrack.Add(new XElement("FingerTrackID", item.FingerTrackID.ToString())); count++; } //foreach xFingerTracks.Attribute("Count").Value = count.ToString(); } } else { // Query geeft null waarde terug. Betekent dat er iets goed fout is gegaan xResult = ServiceHelper.CreateRoot(ResultErrorCode.FAILED); } if (xResult != null) { return(Message.CreateMessage(MessageVersion.None, "", new XElementBodyWriter(xResult))); } // Als we hier komen dan hebben we geen resultaat return(ServiceHelper.SendErrorMessage(ResultErrorCode.NoResultset, "No resultset")); } //using } finally { subFingerIndex.UnLock(); } } //using } catch (Exception e) { CDRLogger.Logger.LogError(e); return(ServiceHelper.SendErrorMessage(ResultErrorCode.Exception, e.Message)); } finally { GC.Collect(); } }
public CancellationTokenSource DetectAudioFragmentSlow(FingerprintSignature fingerprint, object userState = null, REST_ResultFingerDetect callback = null) { if (fingerprint == null) { return(null); } CancellationTokenSource cancelTokenSource = new CancellationTokenSource(); Task task = Task.Factory.StartNew(() => { // Were we already canceled? cancelTokenSource.Token.ThrowIfCancellationRequested(); DateTime startTime = DateTime.Now; bool succes = true; RecognizeCode RecognizeCode = RecognizeCode.OK; string RecognizeResult = ""; try { RestClient client = CreateFingerprintClient; // Build search request RestRequest request = new RestRequest("fingerprint/Recognize/Slow", Method.POST); request.AddHeader("Accept-Encoding", "gzip,deflate"); StringBuilder sb = new StringBuilder(200 * 1024); sb.Append("Fingerprint="); sb.Append(RestSharp.Contrib.HttpUtility.UrlEncode(fingerprint.SignatureBase64)); sb.Append("&"); sb.Append("Reliabilities="); sb.Append(RestSharp.Contrib.HttpUtility.UrlEncode(fingerprint.ReliabilitiesBase64)); request.AddParameter("application/x-www-form-urlencoded", sb.ToString(), ParameterType.RequestBody); // Run and wait for result IRestResponse response = client.Execute(request); cancelTokenSource.Token.ThrowIfCancellationRequested(); if (response.ResponseStatus != ResponseStatus.Completed) { // error! succes = false; RecognizeCode = RecognizeCode.EXCEPTION; // exception RecognizeResult = response.ErrorMessage; if (RecognizeResult.ToLower().Contains("timed out")) { RecognizeCode = RecognizeCode.TIMEOUT; } else if (RecognizeResult.ToLower().Contains("unable to connect")) { RecognizeCode = RecognizeCode.SERVERNOTFOUND; } } // decode xml on the fly (must be done because xml can get new tags and attributes without notice XmlDocument xmlDoc = null; XmlElement xResult = null; if (succes) { xmlDoc = new XmlDocument(); xmlDoc.LoadXml(response.Content); xResult = xmlDoc.GetElementsByTagName("Result")[0] as XmlElement; if (xResult == null || xResult.Attributes["ErrorCode"].Value != "0") { // error succes = false; } } if (succes) { ResultFingerprintRecognition resultRecognitions = new ResultFingerprintRecognition(); resultRecognitions.RecognizeCode = 0; resultRecognitions.RecognizeResult = "OK"; succes = resultRecognitions.ParseFingerprintRecognition(xResult); // do something with the result cancelTokenSource.Token.ThrowIfCancellationRequested(); if (callback != null) { DoCallback(callback, this, true, resultRecognitions, userState); } // we're ready return; } } catch (Exception e) { RecognizeCode = RecognizeCode.EXCEPTION; // exception RecognizeResult = e.ToString(); } // return error result when we get here if (callback != null) { ResultFingerprintRecognition resultRecognitions = new ResultFingerprintRecognition(); resultRecognitions.RecognizeCode = RecognizeCode; resultRecognitions.RecognizeResult = RecognizeResult; resultRecognitions.TimeStatistics.TotalQueryTime = DateTime.Now - startTime; DoCallback(callback, this, false, resultRecognitions, userState); } }, cancelTokenSource.Token); return(cancelTokenSource); }