mirror of
https://github.com/freewilll/apple2-go.git
synced 2024-09-27 01:55:21 +00:00
Added more comments
This commit is contained in:
parent
7caa6647e7
commit
9b34349e8a
@ -1,13 +1,20 @@
|
|||||||
package audio
|
package audio
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
|
||||||
import "github.com/freewilll/apple2/system"
|
import "github.com/freewilll/apple2/system"
|
||||||
|
|
||||||
|
// Click handles a speaker click
|
||||||
func Click() {
|
func Click() {
|
||||||
ForwardToFrameCycle()
|
ForwardToFrameCycle()
|
||||||
system.AudioAttenuationCounter = 400
|
system.AudioAttenuationCounter = 400
|
||||||
system.LastAudioValue = ^system.LastAudioValue
|
system.LastAudioValue = ^system.LastAudioValue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// attenuate makes sure the audio goes down to zero after a period of inactivity
|
||||||
func attenuate(sample int16) int16 {
|
func attenuate(sample int16) int16 {
|
||||||
if system.AudioAttenuationCounter == 0 {
|
if system.AudioAttenuationCounter == 0 {
|
||||||
return 0
|
return 0
|
||||||
@ -17,6 +24,9 @@ func attenuate(sample int16) int16 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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() {
|
func ForwardToFrameCycle() {
|
||||||
// 1023000/44100=23.19 cycles per audio sample
|
// 1023000/44100=23.19 cycles per audio sample
|
||||||
cyclesPerAudioSample := system.CpuFrequency / float64(system.AudioSampleRate)
|
cyclesPerAudioSample := system.CpuFrequency / float64(system.AudioSampleRate)
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package audio
|
package audio
|
||||||
|
|
||||||
|
// This file contains the consumer part of the audio code. audio.go is responsible for producing to it
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
@ -8,20 +10,23 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
audioContext *ebiten_audio.Context
|
audioContext *ebiten_audio.Context // Ebitem audio context
|
||||||
player *ebiten_audio.Player
|
player *ebiten_audio.Player // Ebitem stream player
|
||||||
firstAudio bool
|
firstAudio bool // True at startup
|
||||||
Mute bool
|
Mute bool // Mute
|
||||||
ClickWhenDriveHeadMoves bool
|
ClickWhenDriveHeadMoves bool // Click speaker when the drive head moves
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// The streaming code is based on the ebiten sinewave example
|
||||||
type stream struct{}
|
type stream struct{}
|
||||||
|
|
||||||
|
// Read is called whenever the sound hardware wants some samples. Convert the
|
||||||
|
// 16 bit data in the sound buffer to 8 bit stereo values.
|
||||||
func (s *stream) Read(data []byte) (int, error) {
|
func (s *stream) Read(data []byte) (int, error) {
|
||||||
dataLen := len(data)
|
dataLen := len(data)
|
||||||
|
|
||||||
if firstAudio {
|
if firstAudio {
|
||||||
// The first time, drain the audio queue
|
// The first time, drain the audio queue and exit
|
||||||
firstAudio = false
|
firstAudio = false
|
||||||
|
|
||||||
for i := 0; i < len(system.AudioChannel); i++ {
|
for i := 0; i < len(system.AudioChannel); i++ {
|
||||||
@ -30,14 +35,18 @@ func (s *stream) Read(data []byte) (int, error) {
|
|||||||
return dataLen, nil
|
return dataLen, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sanity test
|
||||||
if dataLen%4 != 0 {
|
if dataLen%4 != 0 {
|
||||||
return 0, errors.New("dataLen % 4 must be 0")
|
return 0, errors.New("dataLen % 4 must be 0")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Do nothing if we're muted, but ensure the channel keeps getting drained
|
||||||
if Mute {
|
if Mute {
|
||||||
|
firstAudio = true
|
||||||
return dataLen, nil
|
return dataLen, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Consume the samples from the channel
|
||||||
samples := dataLen / 4
|
samples := dataLen / 4
|
||||||
|
|
||||||
for i := 0; i < dataLen; i++ {
|
for i := 0; i < dataLen; i++ {
|
||||||
@ -56,12 +65,14 @@ func (s *stream) Read(data []byte) (int, error) {
|
|||||||
return dataLen, nil
|
return dataLen, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Close is called when the program exits
|
||||||
func (s *stream) Close() error {
|
func (s *stream) Close() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// InitEbiten initializes the audio sets up the ebiten output stream
|
// InitEbiten initializes the audio sets up the ebiten output stream
|
||||||
func InitEbiten() {
|
func InitEbiten() {
|
||||||
|
// Setup initial state
|
||||||
firstAudio = true
|
firstAudio = true
|
||||||
Mute = false
|
Mute = false
|
||||||
ClickWhenDriveHeadMoves = false
|
ClickWhenDriveHeadMoves = false
|
||||||
|
Loading…
Reference in New Issue
Block a user