apple2-go/audio/audio.go

47 lines
1.4 KiB
Go
Raw Normal View History

package audio
2018-05-28 09:43:21 +00:00
// Very simple implementation of audio. Every frame, a channel is filled with
// all the audio samples from the last frame. Each time the speaker clicks, the
// channel is filled with the last audio samples. The channel is also
// filled at the end of the frame.
2019-11-02 13:33:05 +00:00
import "github.com/freewilll/apple2-go/system"
2018-05-28 09:43:21 +00:00
// Click handles a speaker click
func Click() {
ForwardToFrameCycle()
2018-05-14 21:44:44 +00:00
system.AudioAttenuationCounter = 400
system.LastAudioValue = ^system.LastAudioValue
}
2018-05-28 09:43:21 +00:00
// attenuate makes sure the audio goes down to zero after a period of inactivity
2018-05-14 21:44:44 +00:00
func attenuate(sample int16) int16 {
if system.AudioAttenuationCounter == 0 {
return 0
}
2018-05-28 16:31:52 +00:00
system.AudioAttenuationCounter--
return sample
}
2018-05-28 09:43:21 +00:00
// ForwardToFrameCycle calculates how many audio samples need to be written to
// the channel based on how many CPU cycles have been executed since the last
// flush and shove them into the channel.
func ForwardToFrameCycle() {
// 1023000/44100=23.19 cycles per audio sample
2018-05-28 16:31:52 +00:00
cyclesPerAudioSample := system.CPUFrequency / float64(system.AudioSampleRate)
// Should be about 1023000/60=17050
elapsedCycles := system.FrameCycles - system.LastAudioCycles
// Should be about 17050/23.19=735 audio samples per frame
audioSamples := uint64(float64(elapsedCycles) / cyclesPerAudioSample)
for i := uint64(0); i < audioSamples; i++ {
b := attenuate(system.LastAudioValue)
system.AudioChannel <- b
}
system.LastAudioCycles = system.FrameCycles
}