DataHoarder
de2974b87d
All checks were successful
continuous-integration/drone/push Build is passing
170 lines
3.3 KiB
Go
170 lines
3.3 KiB
Go
package hasher
|
|
|
|
import (
|
|
"crypto/md5"
|
|
"crypto/sha1"
|
|
"crypto/sha256"
|
|
"encoding/binary"
|
|
"git.gammaspectra.live/S.O.N.G/Kirika/audio/format"
|
|
"git.gammaspectra.live/S.O.N.G/Kirika/vector"
|
|
"hash"
|
|
"hash/crc32"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
const TocPregap = 150
|
|
const SectorsPerSecond = 75
|
|
const DataTrackGap = 11400
|
|
const BytesPerSector = 2352
|
|
const CDChannels = 2
|
|
const Int16SamplesPerSector = BytesPerSector / (2 * CDChannels)
|
|
const CDSampleRate = Int16SamplesPerSector * SectorsPerSecond
|
|
|
|
type HashType int
|
|
|
|
const (
|
|
HashtypeCrc32 = HashType(iota)
|
|
HashtypeSha256
|
|
HashtypeSha1
|
|
HashtypeMd5
|
|
HashtypeAccurateRipV1
|
|
HashtypeAccurateRipV1Start
|
|
HashtypeAccurateRipV2
|
|
HashtypeAccurateRipV2Start
|
|
)
|
|
|
|
type Hasher struct {
|
|
hash HashType
|
|
hasher hash.Hash
|
|
result []byte
|
|
channel format.AnalyzerChannel
|
|
wg sync.WaitGroup
|
|
samples int
|
|
duration float64
|
|
sampleRate int
|
|
bitDepth int
|
|
channels int
|
|
buffer [][]int32
|
|
}
|
|
|
|
func NewHasher(channel format.AnalyzerChannel, hashType HashType) (h *Hasher) {
|
|
h = &Hasher{
|
|
hash: hashType,
|
|
channel: channel,
|
|
}
|
|
|
|
switch hashType {
|
|
case HashtypeCrc32:
|
|
h.hasher = crc32.NewIEEE()
|
|
case HashtypeSha256:
|
|
h.hasher = sha256.New()
|
|
case HashtypeSha1:
|
|
h.hasher = sha1.New()
|
|
case HashtypeMd5:
|
|
h.hasher = md5.New()
|
|
case HashtypeAccurateRipV1:
|
|
h.hasher = NewAccurateRipV1(0)
|
|
case HashtypeAccurateRipV1Start:
|
|
h.hasher = NewAccurateRipV1(Int16SamplesPerSector*5 - 1)
|
|
case HashtypeAccurateRipV2:
|
|
h.hasher = NewAccurateRipV2(0)
|
|
case HashtypeAccurateRipV2Start:
|
|
h.hasher = NewAccurateRipV2(Int16SamplesPerSector*5 - 1)
|
|
|
|
}
|
|
|
|
h.startRoutine()
|
|
|
|
return
|
|
}
|
|
|
|
func (h *Hasher) startRoutine() {
|
|
h.wg.Add(1)
|
|
go func() {
|
|
defer h.wg.Done()
|
|
|
|
for packet := range h.channel {
|
|
h.handlePacket(packet)
|
|
}
|
|
|
|
h.result = h.hasher.Sum([]byte{})
|
|
|
|
}()
|
|
}
|
|
|
|
func (h *Hasher) handlePacket(packet *format.AnalyzerPacket) {
|
|
samples := len(packet.Samples) / packet.Channels
|
|
|
|
h.samples += samples
|
|
|
|
if h.sampleRate == 0 {
|
|
h.sampleRate = packet.SampleRate
|
|
} else if h.sampleRate != packet.SampleRate {
|
|
h.sampleRate = -1
|
|
}
|
|
if h.bitDepth == 0 {
|
|
h.bitDepth = packet.BitDepth
|
|
} else if h.bitDepth != packet.BitDepth {
|
|
h.bitDepth = -1
|
|
}
|
|
if h.channels == 0 {
|
|
h.channels = packet.Channels
|
|
} else if h.channels != packet.Channels {
|
|
h.channels = -1
|
|
}
|
|
|
|
h.duration += float64(samples) / float64(packet.SampleRate)
|
|
|
|
var buf []byte
|
|
switch packet.BitDepth {
|
|
case 8, 16, 24, 32:
|
|
buf = vector.Int32ToBytes(packet.Samples, packet.BitDepth)
|
|
default:
|
|
buf = make([]byte, len(packet.Samples)*4)
|
|
for i := range packet.Samples {
|
|
binary.LittleEndian.PutUint32(buf[i*4:], uint32(packet.Samples[i]))
|
|
}
|
|
|
|
}
|
|
|
|
h.hasher.Write(buf)
|
|
}
|
|
|
|
func (h *Hasher) GetSampleCount() int {
|
|
return h.samples
|
|
}
|
|
|
|
func (h *Hasher) GetChannels() int {
|
|
return h.channels
|
|
}
|
|
|
|
func (h *Hasher) GetSampleRate() int {
|
|
return h.sampleRate
|
|
}
|
|
|
|
func (h *Hasher) GetHashType() HashType {
|
|
return h.hash
|
|
}
|
|
|
|
func (h *Hasher) GetResult() []byte {
|
|
return h.result
|
|
}
|
|
|
|
func (h *Hasher) GetDuration() time.Duration {
|
|
if h.sampleRate > 0 {
|
|
return time.Duration(float64(time.Second) * (float64(h.samples) / float64(h.sampleRate)))
|
|
}
|
|
|
|
//Fallback calculated duration
|
|
return time.Duration(float64(time.Second) * h.duration)
|
|
}
|
|
|
|
func (h *Hasher) GetWaitGroup() *sync.WaitGroup {
|
|
return &h.wg
|
|
}
|
|
|
|
func (h *Hasher) Wait() {
|
|
h.wg.Wait()
|
|
}
|