Hibiki/panako/instance.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())
}