Gopher2600/digest/audio.go
JetSetIlly 3aa5885ebe removed curated pacakge. replaced with wrapped errors
curated package predated the standard errors package introduced in
go1.13

the standard package does a better job of what curated attempted to do

the change of package also gave me a opportunity to clean up the error
messages a little bit
2023-02-13 21:58:39 +00:00

112 lines
3.1 KiB
Go

// This file is part of Gopher2600.
//
// Gopher2600 is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Gopher2600 is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Gopher2600. If not, see <https://www.gnu.org/licenses/>.
package digest
import (
"crypto/sha1"
"fmt"
"github.com/jetsetilly/gopher2600/hardware/television"
"github.com/jetsetilly/gopher2600/hardware/television/signal"
)
// the length of the buffer we're using isn't really important. that said, it
// needs to be at least sha1.Size bytes in length.
const audioBufferLength = 1024 + sha1.Size
// to allow us to create digests on audio streams longer than
// audioBufferLength, we'll stuff the previous digest value into the first part
// of the buffer array and make sure we include it when we create the next
// digest value.
const audioBufferStart = sha1.Size
// Audio is an implementation of the television.AudioMixer interface with an
// embedded television for convenience. It periodically generates a SHA-1 value
// of the audio stream.
//
// Note that the use of SHA-1 is fine for this application because this is not a
// cryptographic task.
type Audio struct {
*television.Television
digest [sha1.Size]byte
buffer []uint8
bufferCt int
}
// NewAudio is the preferred method of initialisation for the Audio2Wav type.
func NewAudio(tv *television.Television) (*Audio, error) {
dig := &Audio{Television: tv}
// register ourselves as a protocol.AudioMixer
dig.AddAudioMixer(dig)
// create buffer
dig.buffer = make([]uint8, audioBufferLength)
dig.bufferCt = audioBufferStart
return dig, nil
}
// Hash implements digest.Digest interface.
func (dig Audio) Hash() string {
return fmt.Sprintf("%x", dig.digest)
}
// ResetDigest implements digest.Digest interface.
func (dig *Audio) ResetDigest() {
for i := range dig.digest {
dig.digest[i] = 0
}
}
// SetAudio implements the protocol.AudioMixer interface.
func (dig *Audio) SetAudio(sig []signal.SignalAttributes) error {
for _, s := range sig {
if s&signal.AudioUpdate != signal.AudioUpdate {
continue
}
d := uint8((s & signal.AudioChannel0) >> signal.AudioChannel0Shift)
dig.buffer[dig.bufferCt] = d
dig.bufferCt++
if dig.bufferCt >= audioBufferLength {
return dig.flushAudio()
}
}
return nil
}
// Reset implements the protocol.AudioMixer interface.
func (dig *Audio) Reset() {
_ = dig.flushAudio()
}
func (dig *Audio) flushAudio() error {
dig.digest = sha1.Sum(dig.buffer)
n := copy(dig.buffer, dig.digest[:])
if n != len(dig.digest) {
return fmt.Errorf("digest: audio: digest error while flushing audio stream")
}
dig.bufferCt = audioBufferStart
return nil
}
// EndMixing implements the protocol.AudioMixer interface.
func (dig *Audio) EndMixing() error {
return nil
}