From c2f924de3df4ec8faa25f7967a02f8016a3453ed Mon Sep 17 00:00:00 2001 From: Sergiu Ciumac Date: Sun, 25 Feb 2024 10:44:07 +0200 Subject: [PATCH 1/3] Improving the design of the API by extracting methods that are responsible for querying into a separate interface (IQueryService). --- .../Command/IUsingQueryServices.cs | 28 +++++------ .../Command/QueryCommand.cs | 50 +++++++++---------- .../InMemory/InMemoryModelService.cs | 2 +- src/SoundFingerprinting/LCS/Candidates.cs | 17 ++++--- .../Query/GroupedQueryResults.cs | 2 +- .../QueryFingerprintService.cs | 4 +- .../SoundFingerprinting.csproj | 7 ++- 7 files changed, 58 insertions(+), 52 deletions(-) diff --git a/src/SoundFingerprinting/Command/IUsingQueryServices.cs b/src/SoundFingerprinting/Command/IUsingQueryServices.cs index b652c076..04c8e4b7 100644 --- a/src/SoundFingerprinting/Command/IUsingQueryServices.cs +++ b/src/SoundFingerprinting/Command/IUsingQueryServices.cs @@ -13,71 +13,71 @@ public interface IUsingQueryServices : IQueryCommand /// /// Sets model service that will be used for querying the data source. /// - /// Model service used as access interfaces to underlying fingerprints storage. + /// Model service used as access interfaces to underlying fingerprints storage. /// Query command. - IQueryCommand UsingServices(IModelService modelService); + IQueryCommand UsingServices(IQueryService queryService); /// /// Sets model service as well as audio service using in querying the source. /// - /// Model service used as access interfaces to underlying fingerprints storage. + /// Model service used as access interfaces to underlying fingerprints storage. /// Audio service used in building the fingerprints from the source. /// Query command. - IQueryCommand UsingServices(IModelService modelService, IAudioService audioService); + IQueryCommand UsingServices(IQueryService queryService, IAudioService audioService); /// /// Sets model service as well as audio service using in querying the source. /// - /// Model service used as access interfaces to underlying fingerprints storage. + /// Model service used as access interfaces to underlying fingerprints storage. /// Audio service used in building the fingerprints from the source. /// Match registry used to store the results in a separate storage. /// Query command. - IQueryCommand UsingServices(IModelService modelService, IAudioService audioService, IQueryMatchRegistry queryMatchRegistry); + IQueryCommand UsingServices(IQueryService queryService, IAudioService audioService, IQueryMatchRegistry queryMatchRegistry); /// /// Sets model service as well as video service. /// - /// Model service used as access interfaces to underlying fingerprints storage. + /// Model service used as access interfaces to underlying fingerprints storage. /// Video service that will be used for reading from the underlying source. /// Query command. /// /// Set video service in case you want to generate video fingerprints only by setting MediaType.Video on the overloads. /// - IQueryCommand UsingServices(IModelService modelService, IVideoService videoService); + IQueryCommand UsingServices(IQueryService queryService, IVideoService videoService); /// /// Sets model service as well as video service. /// - /// Model service used as access interfaces to underlying fingerprints storage. + /// Model service used as access interfaces to underlying fingerprints storage. /// Video service that will be used for reading from the underlying source. /// Match registry used to store the results in a separate storage. /// Query command. /// /// Set video service in case you want to generate video fingerprints only by setting MediaType.Video on the overloads. /// - IQueryCommand UsingServices(IModelService modelService, IVideoService videoService, IQueryMatchRegistry queryMatchRegistry); + IQueryCommand UsingServices(IQueryService queryService, IVideoService videoService, IQueryMatchRegistry queryMatchRegistry); /// /// Sets model service as well as media service. /// - /// Model service used as access interfaces to underlying fingerprints storage. + /// Model service used as access interfaces to underlying fingerprints storage. /// Media service that will be used to read or or both, from the underlying source. /// Query command. /// /// Media service can be used to read both and from a media file, and generate that will be used to query the underlying source. /// - IQueryCommand UsingServices(IModelService modelService, IMediaService mediaService); + IQueryCommand UsingServices(IQueryService queryService, IMediaService mediaService); /// /// Sets model service as well as media service. /// - /// Model service used as access interfaces to underlying fingerprints storage. + /// Model service used as access interfaces to underlying fingerprints storage. /// Media service that will be used to read or or both, from the underlying source. /// Match registry used to store the results in a separate storage. /// Query command. /// /// Media service can be used to read both and from a media file, and generate that will be used to query the underlying source. /// - IQueryCommand UsingServices(IModelService modelService, IMediaService mediaService, IQueryMatchRegistry queryMatchRegistry); + IQueryCommand UsingServices(IQueryService queryService, IMediaService mediaService, IQueryMatchRegistry queryMatchRegistry); } } \ No newline at end of file diff --git a/src/SoundFingerprinting/Command/QueryCommand.cs b/src/SoundFingerprinting/Command/QueryCommand.cs index c8b39c95..028ff3fa 100644 --- a/src/SoundFingerprinting/Command/QueryCommand.cs +++ b/src/SoundFingerprinting/Command/QueryCommand.cs @@ -22,7 +22,7 @@ public sealed class QueryCommand : IQuerySource, IWithQueryConfiguration private readonly IFingerprintCommandBuilder fingerprintCommandBuilder; private readonly IQueryFingerprintService queryFingerprintService; - private IModelService? modelService; + private IQueryService? queryService; private IAudioService audioService; private IVideoService? videoService; private IMediaService? mediaService; @@ -100,59 +100,59 @@ public IInterceptHashes WithQueryConfig(Func - public IQueryCommand UsingServices(IModelService modelService) + /// + public IQueryCommand UsingServices(IQueryService queryService) { - this.modelService = modelService; + this.queryService = queryService; return this; } - /// - public IQueryCommand UsingServices(IModelService modelService, IAudioService audioService) + /// + public IQueryCommand UsingServices(IQueryService queryService, IAudioService audioService) { - this.modelService = modelService; + this.queryService = queryService; this.audioService = audioService; return this; } - /// - public IQueryCommand UsingServices(IModelService modelService, IAudioService audioService, IQueryMatchRegistry queryMatchRegistry) + /// + public IQueryCommand UsingServices(IQueryService queryService, IAudioService audioService, IQueryMatchRegistry queryMatchRegistry) { - this.modelService = modelService; + this.queryService = queryService; this.audioService = audioService; this.queryMatchRegistry = queryMatchRegistry; return this; } - /// - public IQueryCommand UsingServices(IModelService modelService, IVideoService videoService) + /// + public IQueryCommand UsingServices(IQueryService queryService, IVideoService videoService) { - this.modelService = modelService; + this.queryService = queryService; this.videoService = videoService; return this; } - /// - public IQueryCommand UsingServices(IModelService modelService, IVideoService videoService, IQueryMatchRegistry queryMatchRegistry) + /// + public IQueryCommand UsingServices(IQueryService queryService, IVideoService videoService, IQueryMatchRegistry queryMatchRegistry) { - this.modelService = modelService; + this.queryService = queryService; this.videoService = videoService; this.queryMatchRegistry = queryMatchRegistry; return this; } - /// - public IQueryCommand UsingServices(IModelService modelService, IMediaService mediaService) + /// + public IQueryCommand UsingServices(IQueryService queryService, IMediaService mediaService) { - this.modelService = modelService; + this.queryService = queryService; this.mediaService = mediaService; return this; } - /// - public IQueryCommand UsingServices(IModelService modelService, IMediaService mediaService, IQueryMatchRegistry queryMatchRegistry) + /// + public IQueryCommand UsingServices(IQueryService queryService, IMediaService mediaService, IQueryMatchRegistry queryMatchRegistry) { - this.modelService = modelService; + this.queryService = queryService; this.mediaService = mediaService; this.queryMatchRegistry = queryMatchRegistry; return this; @@ -223,12 +223,12 @@ private AVQueryResult GetAvQueryResult(Hashes? audioHashes, Hashes? videoHashes, private QueryResult? GetQueryResult(Hashes? hashes, QueryConfiguration configuration) { - if (modelService == null) + if (queryService == null) { - throw new ArgumentException("Provide an instance of IModelService to query the storage via UsingServices(IModelService)", nameof(modelService)); + throw new ArgumentException("Provide an instance of IModelService to query the storage via UsingServices(IModelService)", nameof(queryService)); } - return hashes != null ? queryFingerprintService.Query(hashes, configuration, modelService) : null; + return hashes != null ? queryFingerprintService.Query(hashes, configuration, queryService) : null; } } } \ No newline at end of file diff --git a/src/SoundFingerprinting/InMemory/InMemoryModelService.cs b/src/SoundFingerprinting/InMemory/InMemoryModelService.cs index f1ab2bff..897504b7 100644 --- a/src/SoundFingerprinting/InMemory/InMemoryModelService.cs +++ b/src/SoundFingerprinting/InMemory/InMemoryModelService.cs @@ -133,7 +133,7 @@ public Candidates QueryEfficiently(Hashes hashes, QueryConfiguration config) { double score = config.ScoreAlgorithm.GetScore(hashedFingerprint, subFingerprint, config); var match = new MatchedWith(hashedFingerprint.SequenceNumber, hashedFingerprint.StartsAt, subFingerprint.SequenceNumber, subFingerprint.SequenceAt, score); - candidates.AddNewMatchForTrack(subFingerprint.TrackReference, match); + candidates.AddMatchesForTrack(subFingerprint.TrackReference, match); } } } diff --git a/src/SoundFingerprinting/LCS/Candidates.cs b/src/SoundFingerprinting/LCS/Candidates.cs index 250964ed..83ba6c80 100644 --- a/src/SoundFingerprinting/LCS/Candidates.cs +++ b/src/SoundFingerprinting/LCS/Candidates.cs @@ -48,7 +48,7 @@ public Candidates(IModelReference trackReference, IEnumerable candi { foreach (var candidate in candidates) { - AddNewMatchForTrack(trackReference, candidate); + AddMatchesForTrack(trackReference, candidate); } } @@ -84,14 +84,17 @@ public IEnumerable>> GetMatches( /// Add new match for a particular track. /// /// Track reference add matched with. - /// An instance of . - public void AddNewMatchForTrack(IModelReference trackReference, MatchedWith match) + /// An instance of . + public void AddMatchesForTrack(IModelReference trackReference, params MatchedWith[] matches) { - candidates?.AddOrUpdate(trackReference, _ => new List {match}, (_, old) => + foreach (var match in matches) { - old.Add(match); - return old; - }); + candidates?.AddOrUpdate(trackReference, _ => new List { match }, (_, old) => + { + old.Add(match); + return old; + }); + } } } } diff --git a/src/SoundFingerprinting/Query/GroupedQueryResults.cs b/src/SoundFingerprinting/Query/GroupedQueryResults.cs index a770fd8a..499be2fd 100644 --- a/src/SoundFingerprinting/Query/GroupedQueryResults.cs +++ b/src/SoundFingerprinting/Query/GroupedQueryResults.cs @@ -33,7 +33,7 @@ public void Add(uint queryHashSequenceNumber, IModelReference trackReference, Ma } else { - candidates.AddNewMatchForTrack(trackReference, matchedWith); + candidates.AddMatchesForTrack(trackReference, matchedWith); } } diff --git a/src/SoundFingerprinting/QueryFingerprintService.cs b/src/SoundFingerprinting/QueryFingerprintService.cs index ed76379b..6b8a39bc 100644 --- a/src/SoundFingerprinting/QueryFingerprintService.cs +++ b/src/SoundFingerprinting/QueryFingerprintService.cs @@ -33,7 +33,7 @@ private QueryFingerprintService(IQueryMath queryMath) public QueryResult Query(Hashes hashes, QueryConfiguration configuration, IQueryService queryService) { var queryStopwatch = Stopwatch.StartNew(); - var groupedQueryResults = GetSimilaritiesUsingBatchedStrategy(hashes, configuration, queryService); + var groupedQueryResults = GetSimilarities(hashes, configuration, queryService); if (!groupedQueryResults.ContainsMatches) { return QueryResult.Empty(hashes, queryStopwatch.ElapsedMilliseconds); @@ -45,7 +45,7 @@ public QueryResult Query(Hashes hashes, QueryConfiguration configuration, IQuery return QueryResult.NonEmptyResult(resultEntries, hashes, totalTracksAnalyzed, totalSubFingerprintsAnalyzed, queryStopwatch.ElapsedMilliseconds); } - private static GroupedQueryResults GetSimilaritiesUsingBatchedStrategy(Hashes queryHashes, QueryConfiguration configuration, IQueryService queryService) + private static GroupedQueryResults GetSimilarities(Hashes queryHashes, QueryConfiguration configuration, IQueryService queryService) { var candidates = queryService.QueryEfficiently(queryHashes, configuration); var groupedResults = new GroupedQueryResults(queryHashes.DurationInSeconds, queryHashes.RelativeTo); diff --git a/src/SoundFingerprinting/SoundFingerprinting.csproj b/src/SoundFingerprinting/SoundFingerprinting.csproj index 8a040bf8..26367eb5 100644 --- a/src/SoundFingerprinting/SoundFingerprinting.csproj +++ b/src/SoundFingerprinting/SoundFingerprinting.csproj @@ -4,14 +4,17 @@ true false enable - 9.4.0-beta1 + 9.4.0-beta2 Sergiu Ciumac SoundFingerprinting is a C# framework that implements an efficient algorithm of audio fingerprinting and identification. Designed for developers, enthusiasts, researchers in the fields of audio processing, data mining, digital signal processing. https://github.com/addictedcs/soundfingerprinting https://github.com/AddictedCS/soundfingerprinting git - Version bump to v9.4.0. + Version 9.4.0 + - Contains an important improvement to QueryCommand, allowing a much faster lookup for the use-cases when the track and the query are very long and almost identical. + - The improvement is rooted in the idea of returning Candidates from the IModelService instead of list of SubFingerprints. This provided knowledge on which hashed fingerprint matched with the query. + - To further improve the API design, methods related to the correct functioning of the QueryCommand were extracted into IQueryService interface (from which IModelService derives). Audio Video Identification Fingerprinting Digital Signal Processing Music Recognition Data Mining Content Sound Shazam latest From a3c4997c0ea6d363ffadc489db0d86a3a97aea2d Mon Sep 17 00:00:00 2001 From: Sergiu Ciumac Date: Mon, 26 Feb 2024 11:41:26 +0200 Subject: [PATCH 2/3] Version bump to v9.4.0 stable. --- src/SoundFingerprinting.Tests/Properties/AssemblyInfo.cs | 4 ++-- src/SoundFingerprinting/Properties/AssemblyInfo.cs | 4 ++-- src/SoundFingerprinting/SoundFingerprinting.csproj | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/SoundFingerprinting.Tests/Properties/AssemblyInfo.cs b/src/SoundFingerprinting.Tests/Properties/AssemblyInfo.cs index 16fd0d7a..b7d16022 100644 --- a/src/SoundFingerprinting.Tests/Properties/AssemblyInfo.cs +++ b/src/SoundFingerprinting.Tests/Properties/AssemblyInfo.cs @@ -11,5 +11,5 @@ [assembly: AssemblyCulture("")] [assembly: ComVisible(false)] [assembly: Guid("4cac962e-ebc5-4006-a1e0-7ffb3e2483c2")] -[assembly: AssemblyVersion("9.4.0.100")] -[assembly: AssemblyInformationalVersion("9.4.0.100")] +[assembly: AssemblyVersion("9.4.0.101")] +[assembly: AssemblyInformationalVersion("9.4.0.101")] diff --git a/src/SoundFingerprinting/Properties/AssemblyInfo.cs b/src/SoundFingerprinting/Properties/AssemblyInfo.cs index 4bdd8157..a60b095c 100644 --- a/src/SoundFingerprinting/Properties/AssemblyInfo.cs +++ b/src/SoundFingerprinting/Properties/AssemblyInfo.cs @@ -19,5 +19,5 @@ [assembly: InternalsVisibleTo("SoundFingerprinting.FFT.FFTW")] [assembly: InternalsVisibleTo("SoundFingerprinting.FFT.FFTW.Tests")] -[assembly: AssemblyVersion("9.4.0.100")] -[assembly: AssemblyInformationalVersion("9.4.0.100")] +[assembly: AssemblyVersion("9.4.0.101")] +[assembly: AssemblyInformationalVersion("9.4.0.101")] diff --git a/src/SoundFingerprinting/SoundFingerprinting.csproj b/src/SoundFingerprinting/SoundFingerprinting.csproj index 26367eb5..3e726a41 100644 --- a/src/SoundFingerprinting/SoundFingerprinting.csproj +++ b/src/SoundFingerprinting/SoundFingerprinting.csproj @@ -4,7 +4,7 @@ true false enable - 9.4.0-beta2 + 9.4.0 Sergiu Ciumac SoundFingerprinting is a C# framework that implements an efficient algorithm of audio fingerprinting and identification. Designed for developers, enthusiasts, researchers in the fields of audio processing, data mining, digital signal processing. https://github.com/addictedcs/soundfingerprinting From 8812d1ed604078736518bac8e0ef4ae5ff129f75 Mon Sep 17 00:00:00 2001 From: Sergiu Ciumac Date: Mon, 26 Feb 2024 11:45:27 +0200 Subject: [PATCH 3/3] Updating Readme. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 18df5db0..86cafe6d 100644 --- a/README.md +++ b/README.md @@ -63,7 +63,7 @@ Since `v8.0.0` video fingerprinting support has been added. Similarly to audio f ### Version 9 Version 9 was released to accomodate `SoundFingerprinting.Emy` v9.0.0, which upgrades to FFmpeg v5.x (breaking change as v8.x is using FFmpeg v4.x). -If you are not using `SoundFingerprinting.Emy` you can safely upgrade to v9. +If you are not using `SoundFingerprinting.Emy` you can safely upgrade to v9. Version 9.4.0 provides dramatic improvement for long queries (over 1 hour), that match long tracks. ### FAQ