Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
* develop:
  Updating Readme.
  Version bump to v9.4.0 stable.
  Improving the design of the API by extracting methods that are responsible for querying into a separate interface (IQueryService).
  • Loading branch information
AddictedCS committed Feb 26, 2024
2 parents 0aae7ee + 8812d1e commit a3879c1
Show file tree
Hide file tree
Showing 10 changed files with 63 additions and 57 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions src/SoundFingerprinting.Tests/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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")]
28 changes: 14 additions & 14 deletions src/SoundFingerprinting/Command/IUsingQueryServices.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,71 +13,71 @@ public interface IUsingQueryServices : IQueryCommand
/// <summary>
/// Sets model service that will be used for querying the data source.
/// </summary>
/// <param name="modelService">Model service used as access interfaces to underlying fingerprints storage.</param>
/// <param name="queryService">Model service used as access interfaces to underlying fingerprints storage.</param>
/// <returns>Query command.</returns>
IQueryCommand UsingServices(IModelService modelService);
IQueryCommand UsingServices(IQueryService queryService);

/// <summary>
/// Sets model service as well as audio service using in querying the source.
/// </summary>
/// <param name="modelService">Model service used as access interfaces to underlying fingerprints storage.</param>
/// <param name="queryService">Model service used as access interfaces to underlying fingerprints storage.</param>
/// <param name="audioService">Audio service used in building the fingerprints from the source.</param>
/// <returns>Query command.</returns>
IQueryCommand UsingServices(IModelService modelService, IAudioService audioService);
IQueryCommand UsingServices(IQueryService queryService, IAudioService audioService);

/// <summary>
/// Sets model service as well as audio service using in querying the source.
/// </summary>
/// <param name="modelService">Model service used as access interfaces to underlying fingerprints storage.</param>
/// <param name="queryService">Model service used as access interfaces to underlying fingerprints storage.</param>
/// <param name="audioService">Audio service used in building the fingerprints from the source.</param>
/// <param name="queryMatchRegistry">Match registry used to store the results in a separate storage.</param>
/// <returns>Query command.</returns>
IQueryCommand UsingServices(IModelService modelService, IAudioService audioService, IQueryMatchRegistry queryMatchRegistry);
IQueryCommand UsingServices(IQueryService queryService, IAudioService audioService, IQueryMatchRegistry queryMatchRegistry);

/// <summary>
/// Sets model service as well as video service.
/// </summary>
/// <param name="modelService">Model service used as access interfaces to underlying fingerprints storage.</param>
/// <param name="queryService">Model service used as access interfaces to underlying fingerprints storage.</param>
/// <param name="videoService">Video service that will be used for reading <see cref="Frames"/> from the underlying source.</param>
/// <returns>Query command.</returns>
/// <remarks>
/// Set video service in case you want to generate video fingerprints only by setting MediaType.Video on the <see cref="IQuerySource"/> overloads.
/// </remarks>
IQueryCommand UsingServices(IModelService modelService, IVideoService videoService);
IQueryCommand UsingServices(IQueryService queryService, IVideoService videoService);

/// <summary>
/// Sets model service as well as video service.
/// </summary>
/// <param name="modelService">Model service used as access interfaces to underlying fingerprints storage.</param>
/// <param name="queryService">Model service used as access interfaces to underlying fingerprints storage.</param>
/// <param name="videoService">Video service that will be used for reading <see cref="Frames"/> from the underlying source.</param>
/// <param name="queryMatchRegistry">Match registry used to store the results in a separate storage.</param>
/// <returns>Query command.</returns>
/// <remarks>
/// Set video service in case you want to generate video fingerprints only by setting MediaType.Video on the <see cref="IQuerySource"/> overloads.
/// </remarks>
IQueryCommand UsingServices(IModelService modelService, IVideoService videoService, IQueryMatchRegistry queryMatchRegistry);
IQueryCommand UsingServices(IQueryService queryService, IVideoService videoService, IQueryMatchRegistry queryMatchRegistry);

/// <summary>
/// Sets model service as well as media service.
/// </summary>
/// <param name="modelService">Model service used as access interfaces to underlying fingerprints storage.</param>
/// <param name="queryService">Model service used as access interfaces to underlying fingerprints storage.</param>
/// <param name="mediaService">Media service that will be used to read <see cref="AudioSamples"/> or <see cref="Frames"/> or both, from the underlying source.</param>
/// <returns>Query command.</returns>
/// <remarks>
/// Media service can be used to read both <see cref="AudioSamples"/> and <see cref="Frames"/> from a media file, and generate <see cref="AVHashes"/> that will be used to query the underlying source.
/// </remarks>
IQueryCommand UsingServices(IModelService modelService, IMediaService mediaService);
IQueryCommand UsingServices(IQueryService queryService, IMediaService mediaService);

/// <summary>
/// Sets model service as well as media service.
/// </summary>
/// <param name="modelService">Model service used as access interfaces to underlying fingerprints storage.</param>
/// <param name="queryService">Model service used as access interfaces to underlying fingerprints storage.</param>
/// <param name="mediaService">Media service that will be used to read <see cref="AudioSamples"/> or <see cref="Frames"/> or both, from the underlying source.</param>
/// <param name="queryMatchRegistry">Match registry used to store the results in a separate storage.</param>
/// <returns>Query command.</returns>
/// <remarks>
/// Media service can be used to read both <see cref="AudioSamples"/> and <see cref="Frames"/> from a media file, and generate <see cref="AVHashes"/> that will be used to query the underlying source.
/// </remarks>
IQueryCommand UsingServices(IModelService modelService, IMediaService mediaService, IQueryMatchRegistry queryMatchRegistry);
IQueryCommand UsingServices(IQueryService queryService, IMediaService mediaService, IQueryMatchRegistry queryMatchRegistry);
}
}
50 changes: 25 additions & 25 deletions src/SoundFingerprinting/Command/QueryCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -100,59 +100,59 @@ public IInterceptHashes WithQueryConfig(Func<AVQueryConfiguration, AVQueryConfig
return this;
}

/// <inheritdoc cref="IUsingQueryServices.UsingServices(IModelService)"/>
public IQueryCommand UsingServices(IModelService modelService)
/// <inheritdoc cref="IUsingQueryServices.UsingServices(IQueryService)"/>
public IQueryCommand UsingServices(IQueryService queryService)
{
this.modelService = modelService;
this.queryService = queryService;
return this;
}

/// <inheritdoc cref="IUsingQueryServices.UsingServices(IModelService,IAudioService)"/>
public IQueryCommand UsingServices(IModelService modelService, IAudioService audioService)
/// <inheritdoc cref="IUsingQueryServices.UsingServices(IQueryService,IAudioService)"/>
public IQueryCommand UsingServices(IQueryService queryService, IAudioService audioService)
{
this.modelService = modelService;
this.queryService = queryService;
this.audioService = audioService;
return this;
}

/// <inheritdoc cref="IUsingQueryServices.UsingServices(IModelService,IAudioService,IQueryMatchRegistry)"/>
public IQueryCommand UsingServices(IModelService modelService, IAudioService audioService, IQueryMatchRegistry queryMatchRegistry)
/// <inheritdoc cref="IUsingQueryServices.UsingServices(IQueryService,IAudioService,IQueryMatchRegistry)"/>
public IQueryCommand UsingServices(IQueryService queryService, IAudioService audioService, IQueryMatchRegistry queryMatchRegistry)
{
this.modelService = modelService;
this.queryService = queryService;
this.audioService = audioService;
this.queryMatchRegistry = queryMatchRegistry;
return this;
}

/// <inheritdoc cref="IUsingQueryServices.UsingServices(IModelService,IVideoService)"/>
public IQueryCommand UsingServices(IModelService modelService, IVideoService videoService)
/// <inheritdoc cref="IUsingQueryServices.UsingServices(IQueryService,IVideoService)"/>
public IQueryCommand UsingServices(IQueryService queryService, IVideoService videoService)
{
this.modelService = modelService;
this.queryService = queryService;
this.videoService = videoService;
return this;
}

/// <inheritdoc cref="IUsingQueryServices.UsingServices(IModelService,IVideoService,IQueryMatchRegistry)"/>
public IQueryCommand UsingServices(IModelService modelService, IVideoService videoService, IQueryMatchRegistry queryMatchRegistry)
/// <inheritdoc cref="IUsingQueryServices.UsingServices(IQueryService,IVideoService,IQueryMatchRegistry)"/>
public IQueryCommand UsingServices(IQueryService queryService, IVideoService videoService, IQueryMatchRegistry queryMatchRegistry)
{
this.modelService = modelService;
this.queryService = queryService;
this.videoService = videoService;
this.queryMatchRegistry = queryMatchRegistry;
return this;
}

/// <inheritdoc cref="IUsingQueryServices.UsingServices(IModelService,IMediaService)"/>
public IQueryCommand UsingServices(IModelService modelService, IMediaService mediaService)
/// <inheritdoc cref="IUsingQueryServices.UsingServices(IQueryService,IMediaService)"/>
public IQueryCommand UsingServices(IQueryService queryService, IMediaService mediaService)
{
this.modelService = modelService;
this.queryService = queryService;
this.mediaService = mediaService;
return this;
}

/// <inheritdoc cref="IUsingQueryServices.UsingServices(IModelService,IMediaService,IQueryMatchRegistry)"/>
public IQueryCommand UsingServices(IModelService modelService, IMediaService mediaService, IQueryMatchRegistry queryMatchRegistry)
/// <inheritdoc cref="IUsingQueryServices.UsingServices(IQueryService,IMediaService,IQueryMatchRegistry)"/>
public IQueryCommand UsingServices(IQueryService queryService, IMediaService mediaService, IQueryMatchRegistry queryMatchRegistry)
{
this.modelService = modelService;
this.queryService = queryService;
this.mediaService = mediaService;
this.queryMatchRegistry = queryMatchRegistry;
return this;
Expand Down Expand Up @@ -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;
}
}
}
2 changes: 1 addition & 1 deletion src/SoundFingerprinting/InMemory/InMemoryModelService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
}
Expand Down
17 changes: 10 additions & 7 deletions src/SoundFingerprinting/LCS/Candidates.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public Candidates(IModelReference trackReference, IEnumerable<MatchedWith> candi
{
foreach (var candidate in candidates)
{
AddNewMatchForTrack(trackReference, candidate);
AddMatchesForTrack(trackReference, candidate);
}
}

Expand Down Expand Up @@ -84,14 +84,17 @@ public IEnumerable<KeyValuePair<IModelReference, List<MatchedWith>>> GetMatches(
/// Add new match for a particular track.
/// </summary>
/// <param name="trackReference">Track reference add matched with.</param>
/// <param name="match">An instance of <see cref="MatchedWith"/>.</param>
public void AddNewMatchForTrack(IModelReference trackReference, MatchedWith match)
/// <param name="matches">An instance of <see cref="MatchedWith"/>.</param>
public void AddMatchesForTrack(IModelReference trackReference, params MatchedWith[] matches)
{
candidates?.AddOrUpdate(trackReference, _ => new List<MatchedWith> {match}, (_, old) =>
foreach (var match in matches)
{
old.Add(match);
return old;
});
candidates?.AddOrUpdate(trackReference, _ => new List<MatchedWith> { match }, (_, old) =>
{
old.Add(match);
return old;
});
}
}
}
}
4 changes: 2 additions & 2 deletions src/SoundFingerprinting/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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")]
2 changes: 1 addition & 1 deletion src/SoundFingerprinting/Query/GroupedQueryResults.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public void Add(uint queryHashSequenceNumber, IModelReference trackReference, Ma
}
else
{
candidates.AddNewMatchForTrack(trackReference, matchedWith);
candidates.AddMatchesForTrack(trackReference, matchedWith);
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/SoundFingerprinting/QueryFingerprintService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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);
Expand Down
7 changes: 5 additions & 2 deletions src/SoundFingerprinting/SoundFingerprinting.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,17 @@
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<Nullable>enable</Nullable>
<PackageVersion>9.4.0-beta1</PackageVersion>
<PackageVersion>9.4.0</PackageVersion>
<Authors>Sergiu Ciumac</Authors>
<PackageDescription>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.</PackageDescription>
<PackageProjectUrl>https://github.com/addictedcs/soundfingerprinting</PackageProjectUrl>
<RepositoryUrl>https://github.com/AddictedCS/soundfingerprinting</RepositoryUrl>
<RepositoryType>git</RepositoryType>
<PackageReleaseNotes>
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).
</PackageReleaseNotes>
<PackageTags>Audio Video Identification Fingerprinting Digital Signal Processing Music Recognition Data Mining Content Sound Shazam</PackageTags>
<LangVersion>latest</LangVersion>
Expand Down

0 comments on commit a3879c1

Please sign in to comment.