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()) }