private AcoustID.FingerprintAcoustID MakeAcoustIDFinger(string key, string filename) { // resample to 11025Hz IAudioDecoder decoder = new BassDecoder(); try { decoder.Load(filename); ChromaContext context = new ChromaContext(); context.Start(decoder.SampleRate, decoder.Channels); decoder.Decode(context.Consumer, 120); if (context.Finish()) { FingerprintAcoustID fingerprint = new FingerprintAcoustID(); fingerprint.Reference = key; fingerprint.DurationInMS = (long)decoder.Duration * 1000; fingerprint.SignatureInt32 = context.GetRawFingerprint(); return(fingerprint); } } catch (Exception e) { // Probleem waarschijnlijk met file. Console.Error.WriteLine(e.ToString()); } finally { decoder.Dispose(); } return(null); }
public void RunAcoustIDTest() { Console.WriteLine("AcoustID test."); if (!System.IO.Directory.Exists(acoustIDfingerLookupPath)) { Console.WriteLine("AcoustID path not found."); return; } Console.WriteLine("Opening index. With larges indexes this can take a while."); IndexSearcher indexSubFinger = new IndexSearcher(IndexReader.Open(FSDirectory.Open(new System.IO.DirectoryInfo(acoustIDfingerLookupPath)), true)); indexSubFinger.Similarity = new CDR.Indexer.SimilarityNoPriority(); Console.WriteLine("Ready opening index."); AcoustIDQuery query = new AcoustIDQuery(indexSubFinger); FingerprintAcoustID fsQuery = null; Resultset answer = null; fsQuery = query.MakeAcoustIDFingerFromAudio(@"..\..\..\Audio\Samples\JK147510-0002-64kpbs.mp3"); answer = query.MatchAudioFingerprint(fsQuery); if (!retrieveMetadataFromMuziekweb) { ThrowIfInvalidAnswer(answer, "A5D062DE"); } PrintAnswer(answer); Console.WriteLine(); }
public FingerprintHit(FingerprintAcoustID fingerprint, float score, int indexNumberInMatchList, int fingerCountHitInFingerprint) { this.Fingerprint = fingerprint; this.Score = score; this.IndexNumberInMatchList = indexNumberInMatchList; this.FingerCountHitInFingerprint = fingerCountHitInFingerprint; }
public Resultset MatchAudioFingerprint(FingerprintAcoustID fsQuery) { DateTime startTime = DateTime.Now; BooleanQuery.MaxClauseCount = 600000; Resultset result = new Resultset(); result.Algorithm = FingerprintAlgorithm.AcoustIDFingerprint; int[] query = fsQuery.AcoustID_Extract_Query; if (query.Length <= 0) { goto exitFunc; } // Vuurt nu query af op lucene index DateTime dtStart = DateTime.Now; TopDocs topHits = QuerySubAcoustIDFingers(query); int[] titelnummertrackIDs = LuceneTopDocs2TitelnummertrackIDs(topHits); result.FingerQueryTime = (DateTime.Now - dtStart); if (titelnummertrackIDs.Length == 0) { goto exitFunc; } dtStart = DateTime.Now; List <FingerprintAcoustID> fingerprints = GetFingerprintsMySQL(titelnummertrackIDs); result.FingerLoadTime = (DateTime.Now - dtStart); dtStart = DateTime.Now; ConcurrentDictionary <string, FingerprintHit> hits = FindPossibleMatch(fsQuery, fingerprints); result.MatchTime = (DateTime.Now - dtStart); // Geef resultaat terug List <ResultEntry> resultEntries = hits.OrderByDescending(e => e.Value.Score) .Select(e => new ResultEntry { Reference = e.Value.Fingerprint.Reference, Similarity = Convert.ToInt32(e.Value.Score * 100), // acoustic id math from 0 to 100% // Dummy settings TimeIndex = -1, // match is on complete track (or al least first 120 seconds!) IndexNumberInMatchList = e.Value.IndexNumberInMatchList, SubFingerCountHitInFingerprint = 0, SearchStrategy = SearchStrategy.NotSet, SearchIteration = 0 }) .ToList(); result.ResultEntries = resultEntries; exitFunc: result.QueryTime = (DateTime.Now - startTime); return(result); }
private List <FingerprintAcoustID> GetFingerprintsMySQL(int[] fingerIDList) { DateTime startTime = DateTime.Now; System.Collections.Concurrent.ConcurrentBag <FingerprintAcoustID> fingerBag = new System.Collections.Concurrent.ConcurrentBag <FingerprintAcoustID>(); using (MySql.Data.MySqlClient.MySqlConnection conn = CDR.DB_Helper.NewMySQLConnection()) { StringBuilder sb = new StringBuilder(1024); sb.Append("SELECT *\r\n"); sb.Append("FROM FINGERID AS T1,\r\n"); sb.Append(" TITELNUMMERTRACK_ID AS T2\r\n"); sb.Append("WHERE T1.TITELNUMMERTRACK_ID = T2.TITELNUMMERTRACK_ID\r\n"); sb.Append("AND T2.TITELNUMMERTRACK_ID IN (\r\n"); int count = 0; System.Collections.Hashtable hTable = new System.Collections.Hashtable(fingerIDList.Length); foreach (int id in fingerIDList) { if (count > 0) { sb.Append(','); } sb.Append(id.ToString()); hTable.Add(id, count); count++; } sb.Append(')'); MySql.Data.MySqlClient.MySqlCommand command = new MySql.Data.MySqlClient.MySqlCommand(sb.ToString(), conn); command.CommandTimeout = 60; MySql.Data.MySqlClient.MySqlDataAdapter adapter = new MySql.Data.MySqlClient.MySqlDataAdapter(command); System.Data.DataSet ds = new System.Data.DataSet(); adapter.Fill(ds); if (ds.Tables.Count > 0) { foreach (System.Data.DataRow row in ds.Tables[0].Rows) { FingerprintAcoustID fs = new FingerprintAcoustID(); fs.Reference = row["TITELNUMMERTRACK"].ToString(); fs.Signature = (byte[])row["SIGNATURE"]; fs.DurationInMS = Convert.ToInt64(row["DURATIONINMS"]); int titelnummertrackID = Convert.ToInt32(row["TITELNUMMERTRACK_ID"]); fs.Tag = hTable[titelnummertrackID]; fingerBag.Add(fs); } } } List <FingerprintAcoustID> result = fingerBag.OrderBy(e => (int)e.Tag) .ToList(); return(result); }
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 }
private ConcurrentDictionary <string, FingerprintHit> FindPossibleMatch(FingerprintAcoustID fsQuery, List <FingerprintAcoustID> fingerprints) { DateTime starttime = DateTime.Now; ConcurrentDictionary <string, FingerprintHit> possibleHits = new ConcurrentDictionary <string, FingerprintHit>(); int indexNumberInMatchList = 0; int[] fsQueryInts = fsQuery.SignatureInt32; foreach (FingerprintAcoustID fsMatch in fingerprints) { indexNumberInMatchList++; // --------------------------------------------------------------- // Tel aantal hits dat we vonden int fingerCountHitInFingerprint = 0; foreach (int hash in fsQueryInts) { if (fsMatch.IndexOf(hash).Length > 0) { fingerCountHitInFingerprint++; } } //foreach // --------------------------------------------------------------- float score = FingerprintAcoustID.MatchFingerprint(fsMatch, fsQuery, 0); if (score >= 0.60f) // 0.60 zoals ik terugvond levert te slechte resultaten op (engelse en nederlandse versie zijn dan hetzelfde) { if (System.Math.Abs(100 - ((fsMatch.DurationInMS * 100) / fsQuery.DurationInMS)) < 15) { possibleHits.TryAdd(fsMatch.Reference.ToString(), new FingerprintHit(fsMatch, score, indexNumberInMatchList, fingerCountHitInFingerprint)); } } } return(possibleHits); }
public bool CreateAcoustIDFingerLookupIndex(string luceneIndexPath) { DateTime startTime = DateTime.Now; DateTime endTime = startTime; Console.WriteLine("Creating acoustID Finger 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); int fingerCount = 0; Lucene.Net.Store.Directory directory = FSDirectory.Open(new System.IO.DirectoryInfo(luceneIndexPath)); IndexWriter iw = null; 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("TITELNUMMERTRACK_ID", "", Field.Store.YES, Field.Index.NOT_ANALYZED)); doc.Add(new Field("FINGERID", "", Field.Store.NO, Field.Index.ANALYZED)); Field fTitelnummertrackID = doc.GetField("TITELNUMMERTRACK_ID"); fTitelnummertrackID.OmitNorms = true; fTitelnummertrackID.OmitTermFreqAndPositions = true; Field fFingerID = doc.GetField("FINGERID"); fFingerID.OmitNorms = true; fFingerID.OmitTermFreqAndPositions = true; StringBuilder sb = new StringBuilder(256 * 1024); int start = minID; int count = 5000; while (start <= maxID) { DataTable dt; if (Exec_MySQL_LOADFINGERIDS(start, (start + count - 1), out dt)) { foreach (DataRow row in dt.Rows) { fingerCount++; if ((fingerCount % 100) == 0 || fingerCount <= 1) { Console.Write("\rIndexing fingerprint #" + fingerCount.ToString()); } FingerprintAcoustID fingerprint = new FingerprintAcoustID(); fingerprint.Signature = (byte[])row["SIGNATURE"]; // Bij AcoustiID halen we vanaf positie 80 (int32 gerekend) 120 (360 nu) int lang eruit. We bepalen de 28 belangrijkste bits // en slaan deze getallen vervolgens op. // Dit kan omdat we een fingerprint hebben van de gehele song (eigenlijk eerste 120 seconden) en die ook gaan vergelijken met // een fingerprint die aan dezelfde voorwaarde voldoet. sb.Clear(); List <int> query = new List <int>(); foreach (int subFingerValue in fingerprint.AcoustID_Extract_Query) { // deduplicate if (query.Contains(subFingerValue)) { continue; } query.Add(subFingerValue); sb.Append(subFingerValue.ToString()); sb.Append(' '); } fTitelnummertrackID.SetValue(row["TITELNUMMERTRACK_ID"].ToString()); fFingerID.SetValue(sb.ToString()); iw.AddDocument(doc); } //foreach Console.Write("\rIndexing fingerprint #" + fingerCount.ToString()); start += count; } else { if (!RetryDatabaseError()) { return(false); } } } //while } 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); }