157 lines
6.5 KiB
Go
157 lines
6.5 KiB
Go
package panako
|
|
|
|
import (
|
|
"git.gammaspectra.live/S.O.N.G/Kirika/audio/filter"
|
|
"time"
|
|
)
|
|
|
|
type Instance struct {
|
|
//BlockSize size of audio blocks and buffers, in number of samples per channel, passed to lower backends. Needs to be a power of two.
|
|
BlockSize int
|
|
|
|
//SampleRate in Hertz. sample rate of audio that the processor and fingerprinter require/resample to.
|
|
SampleRate Hertz
|
|
|
|
//Spectral transform configuration
|
|
|
|
//TransformMinimumFrequency in Hertz. Acts as base for all others frequencies with octave offsets
|
|
TransformMinimumFrequency Hertz
|
|
//TransformReferenceFrequencyOffset in octaves above TransformMinimumFrequency. Determines bin centers
|
|
TransformReferenceFrequencyOffset Octave
|
|
//TransformMaximumFrequencyOffset in octaves above TransformMinimumFrequency.
|
|
TransformMaximumFrequencyOffset Octave
|
|
|
|
//TransformBands in absolute band count. Do not change away from 512 unless you know what you are doing. Total amount of bins for all octaves from min to TransformMaximumFrequencyOctaves
|
|
TransformBands int
|
|
|
|
//TransformTimeResolution in absolute values. Time resolution of fingerprints/matches
|
|
TransformTimeResolution time.Duration
|
|
|
|
//query config
|
|
|
|
//QueryRange in absolute time bins / hash units(???) range. When searching for hash matches, use query hash value +- QueryRange value
|
|
QueryRange int
|
|
|
|
//QueryMinimumHitsBeforeFiltering and QueryMinimumHitsAfterFiltering probably require adjustment if any of TransformTimeResolution, QueryRange are changed
|
|
//QueryMinimumHitsBeforeFiltering in count per resourceId. Minimum amount of hits for a match to be considered for further filtering.
|
|
QueryMinimumHitsBeforeFiltering int
|
|
//QueryMinimumHitsAfterFiltering in count per resourceId. Minimum amount of hits for a match to be considered after basic filtering.
|
|
QueryMinimumHitsAfterFiltering int
|
|
|
|
//QueryTimeRatioFactor in ratio factor. Any match with its time ratio below or above 1 +- this value will not be considered
|
|
QueryTimeRatioFactor float64
|
|
//QueryFrequencyRatioFactor in ratio factor. Any match with its frequency ratio below or above 1 +- this value will not be considered
|
|
//TODO: maybe change this to work on Octave or Cent?
|
|
QueryFrequencyRatioFactor float64
|
|
|
|
//QueryDurationPercentageMinimum in absolute percentage. Any match with its duration % ratio below this value will not be considered
|
|
QueryDurationPercentageMinimum float64
|
|
//QueryDurationMinimum in absolute value. Any match with its absolute duration below this value will not be considered
|
|
QueryDurationMinimum time.Duration
|
|
|
|
QueryMaximumHitListSize int
|
|
QueryHitListDivisor int
|
|
QueryHitListDeltaTimeDepth int
|
|
|
|
//Event point filter settings
|
|
|
|
//PointFilterMaximumTimeFilterSize in samples from SampleRate. Must be odd
|
|
PointFilterMaximumTimeFilterSize int
|
|
//PointFilterMaximumTimeFilterSize in Cent units(???)
|
|
PointFilterMaximumFrequencyFilterSize int
|
|
|
|
//PointFilterMinimumTimeDistance in TransformTimeResolution units. EventPoint pairings below this time distance will not be considered
|
|
PointFilterMinimumTimeDistance int
|
|
//PointFilterMaximumTimeDistance in TransformTimeResolution units. EventPoint pairings above this time distance will not be considered
|
|
PointFilterMaximumTimeDistance int
|
|
//PointFilterMinimumFrequencyDistance in Cent. EventPoint pairings below this frequency distance will not be considered
|
|
PointFilterMinimumFrequencyDistance Cent
|
|
//PointFilterMaximumFrequencyDistance in Cent. EventPoint pairings above this frequency distance will not be considered
|
|
PointFilterMaximumFrequencyDistance Cent
|
|
|
|
//Other options
|
|
//HashType select whether to use Fingerprint.Hash, Fingerprint.RobustHash or Fingerprint.CompactHash method when creating StoreRecord
|
|
HashType FingerprintHashType
|
|
}
|
|
|
|
func NewDefaultPackedInstance() *Instance {
|
|
i := NewDefaultInstance()
|
|
i.TransformTimeResolution = time.Millisecond * 50
|
|
i.QueryMinimumHitsBeforeFiltering = 5
|
|
i.QueryMinimumHitsAfterFiltering = 3
|
|
i.QueryHitListDivisor = 2
|
|
i.HashType = CompactHash
|
|
return i
|
|
}
|
|
|
|
func NewDefaultInstance() *Instance {
|
|
return &Instance{
|
|
BlockSize: 1 << 17,
|
|
SampleRate: 16000,
|
|
TransformMinimumFrequency: 110,
|
|
TransformReferenceFrequencyOffset: 2, //440Hz, TODO: how was this value achieved
|
|
TransformMaximumFrequencyOffset: 6, //7040Hz, TODO: how was this value achieved
|
|
//constant, other dependencies exist. TODO: remove or make dependencies relative
|
|
TransformBands: 512,
|
|
TransformTimeResolution: time.Millisecond * 8, //8ms
|
|
QueryRange: 3, //could be 2?
|
|
QueryMaximumHitListSize: 250,
|
|
QueryHitListDivisor: 5,
|
|
QueryHitListDeltaTimeDepth: 3,
|
|
QueryMinimumHitsBeforeFiltering: 10,
|
|
QueryMinimumHitsAfterFiltering: 5,
|
|
QueryTimeRatioFactor: 0.2,
|
|
QueryFrequencyRatioFactor: 0.2,
|
|
QueryDurationPercentageMinimum: 0.2,
|
|
QueryDurationMinimum: time.Second * 5, //could be 3, 5, 7?
|
|
|
|
PointFilterMaximumFrequencyFilterSize: 103, //TODO: how was this value achieved
|
|
PointFilterMaximumTimeFilterSize: 25, //TODO: how was this value achieved
|
|
PointFilterMinimumTimeDistance: 2,
|
|
PointFilterMaximumTimeDistance: 33,
|
|
PointFilterMinimumFrequencyDistance: 1,
|
|
PointFilterMaximumFrequencyDistance: 128,
|
|
|
|
HashType: Hash,
|
|
}
|
|
}
|
|
|
|
func (i *Instance) BlockToDuration(t uint32, latency time.Duration) time.Duration {
|
|
return time.Duration(int64(t)*int64(i.TransformTimeResolution)) + latency
|
|
}
|
|
|
|
func (i *Instance) BinToHertz(bin uint32) Hertz {
|
|
centsPerBin := CentsPerOctave / float64(i.GetTransformBandsPerOctave())
|
|
diffFromMinFreqInCents := Cent(float64(bin) * centsPerBin)
|
|
|
|
return i.TransformMinimumFrequency.Cents(diffFromMinFreqInCents)
|
|
}
|
|
|
|
func (i *Instance) GetStrategy(store Store, resamplerQuality ...filter.ResampleQuality) *Strategy {
|
|
return NewStrategy(i, store, resamplerQuality...)
|
|
}
|
|
|
|
func (i *Instance) GetEventPointProcessor() (*EventPointProcessor, error) {
|
|
return NewEventPointProcessor(i)
|
|
}
|
|
|
|
func (i *Instance) GetTransformBandsPerOctave() int {
|
|
return i.TransformBands / int(i.TransformMaximumFrequencyOffset)
|
|
}
|
|
|
|
func (i *Instance) GetTransformMinimumFrequency() Hertz {
|
|
return i.TransformMinimumFrequency
|
|
}
|
|
|
|
func (i *Instance) GetTransformReferenceFrequency() Hertz {
|
|
return i.TransformMinimumFrequency.Octaves(i.TransformReferenceFrequencyOffset)
|
|
}
|
|
|
|
func (i *Instance) GetTransformMaximumFrequency() Hertz {
|
|
return i.TransformMinimumFrequency.Octaves(i.TransformMaximumFrequencyOffset)
|
|
}
|
|
|
|
func (i *Instance) GetTransformTimeResolutionInSamples() int {
|
|
return int(float64(i.SampleRate) * i.TransformTimeResolution.Seconds())
|
|
}
|