46 lines
1.8 KiB
Go
46 lines
1.8 KiB
Go
// Copyright (c) 2026 Storm Dragon
|
|
// Authors: Storm Dragon, Angus Kola
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
package sound
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/binary"
|
|
"math"
|
|
"time"
|
|
)
|
|
|
|
// tone_wav generates mono, 16-bit PCM at 22050 Hz for the existing Player.
|
|
// Callers supply a positive frequency/duration, amplitude in [0, 1], and a
|
|
// nonnegative edge ramp. A zero ramp preserves an unsmoothed sine tone.
|
|
// Playback volume, pan, queuing, and cancellation belong to the sound service.
|
|
func tone_wav(frequency float64, duration time.Duration, amplitude float64, ramp time.Duration) []byte {
|
|
const sampleRate = 22050
|
|
sampleCount := int(float64(sampleRate) * duration.Seconds())
|
|
rampSamples := int(float64(sampleRate) * ramp.Seconds())
|
|
dataSize := sampleCount * 2
|
|
buffer := bytes.NewBuffer(make([]byte, 0, 44+dataSize))
|
|
buffer.WriteString("RIFF")
|
|
_ = binary.Write(buffer, binary.LittleEndian, uint32(36+dataSize))
|
|
buffer.WriteString("WAVEfmt ")
|
|
_ = binary.Write(buffer, binary.LittleEndian, uint32(16))
|
|
_ = binary.Write(buffer, binary.LittleEndian, uint16(1))
|
|
_ = binary.Write(buffer, binary.LittleEndian, uint16(1))
|
|
_ = binary.Write(buffer, binary.LittleEndian, uint32(sampleRate))
|
|
_ = binary.Write(buffer, binary.LittleEndian, uint32(sampleRate*2))
|
|
_ = binary.Write(buffer, binary.LittleEndian, uint16(2))
|
|
_ = binary.Write(buffer, binary.LittleEndian, uint16(16))
|
|
buffer.WriteString("data")
|
|
_ = binary.Write(buffer, binary.LittleEndian, uint32(dataSize))
|
|
for sample := 0; sample < sampleCount; sample++ {
|
|
envelope := 1.0
|
|
if rampSamples > 0 {
|
|
envelope = min(1.0, float64(min(sample, sampleCount-1-sample))/float64(rampSamples))
|
|
}
|
|
value := int16(math.Sin(2*math.Pi*frequency*float64(sample)/sampleRate) * amplitude * envelope * math.MaxInt16)
|
|
_ = binary.Write(buffer, binary.LittleEndian, value)
|
|
}
|
|
return buffer.Bytes()
|
|
}
|