Release v0.2.34
This commit is contained in:
@@ -0,0 +1,74 @@
|
||||
package subsync
|
||||
|
||||
import "math/bits"
|
||||
|
||||
// signal is "somebody is speaking" as one bit per time bin.
|
||||
//
|
||||
// A bitset rather than a []bool because the search is the whole cost of this feature: a
|
||||
// two-hour film at 50ms is around 144,000 bins, and every one of ~2,400 shifts has to
|
||||
// compare all of them against every stretch candidate. Packed into words, one comparison
|
||||
// is an AND and a population count over 2,250 words instead of 144,000 byte reads, which
|
||||
// is the difference between a button that answers while somebody is still looking at the
|
||||
// menu and one they wait on. math/bits.OnesCount64 compiles to a single instruction on
|
||||
// every architecture this runs on.
|
||||
type signal struct {
|
||||
words []uint64
|
||||
bins int
|
||||
on int
|
||||
}
|
||||
|
||||
func newSignal(bins int) *signal {
|
||||
if bins < 1 {
|
||||
bins = 1
|
||||
}
|
||||
return &signal{words: make([]uint64, (bins+63)/64), bins: bins}
|
||||
}
|
||||
|
||||
// set marks the half-open bin range [from, to) as speech.
|
||||
func (s *signal) set(from, to int) {
|
||||
if from < 0 {
|
||||
from = 0
|
||||
}
|
||||
if to > s.bins {
|
||||
to = s.bins
|
||||
}
|
||||
for i := from; i < to; i++ {
|
||||
word, bit := i/64, uint(i%64)
|
||||
if s.words[word]&(1<<bit) == 0 {
|
||||
s.words[word] |= 1 << bit
|
||||
s.on++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// overlap counts the bins where both signals are speaking, with other displaced by shift
|
||||
// bins. A positive shift means other is read later — the value to add to this signal's
|
||||
// times to bring them onto other's.
|
||||
//
|
||||
// Negative shifts are answered by swapping the two, which is the same count from the other
|
||||
// side and saves writing the word arithmetic twice in mirror image.
|
||||
func (s *signal) overlap(other *signal, shift int) int {
|
||||
if shift < 0 {
|
||||
return other.overlap(s, -shift)
|
||||
}
|
||||
wordShift, bitShift := shift/64, uint(shift%64)
|
||||
total := 0
|
||||
for i := range s.words {
|
||||
mine := s.words[i]
|
||||
if mine == 0 {
|
||||
continue
|
||||
}
|
||||
j := i + wordShift
|
||||
if j >= len(other.words) {
|
||||
break
|
||||
}
|
||||
theirs := other.words[j] >> bitShift
|
||||
// Go defines a shift of 64 or more as zero, so this term vanishes when bitShift
|
||||
// is zero rather than needing a branch of its own.
|
||||
if j+1 < len(other.words) {
|
||||
theirs |= other.words[j+1] << (64 - bitShift)
|
||||
}
|
||||
total += bits.OnesCount64(mine & theirs)
|
||||
}
|
||||
return total
|
||||
}
|
||||
Reference in New Issue
Block a user