| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990 |
- // Command gentone writes the WAV test pack's tone (0.8 s at 440 Hz, then
- // 0.2 s at 880 Hz as an end marker) as integer PCM, optionally with the
- // WAVE_FORMAT_EXTENSIBLE header many audio tools write.
- //
- // go run ./tools/checkpoint-a/gentone -rate 48000 -bits 24 -channels 2 -extensible out.wav
- package main
- import (
- "bytes"
- "encoding/binary"
- "flag"
- "fmt"
- "math"
- "os"
- )
- func main() {
- rate := flag.Int("rate", 44100, "sample rate")
- bits := flag.Int("bits", 16, "bits per sample: 16 or 24")
- channels := flag.Int("channels", 1, "1 or 2")
- ext := flag.Bool("extensible", false, "write a WAVE_FORMAT_EXTENSIBLE header (PCM sub-format)")
- flag.Parse()
- if flag.NArg() != 1 || (*bits != 16 && *bits != 24) || *channels < 1 || *channels > 2 {
- fmt.Fprintln(os.Stderr, "usage: gentone [-rate N] [-bits 16|24] [-channels 1|2] [-extensible] out.wav")
- os.Exit(2)
- }
- if err := os.WriteFile(flag.Arg(0), tone(*rate, *bits, *channels, *ext), 0o644); err != nil {
- fmt.Fprintln(os.Stderr, err)
- os.Exit(1)
- }
- }
- func tone(rate, bits, channels int, ext bool) []byte {
- le := binary.LittleEndian
- width := bits / 8
- var data bytes.Buffer
- fade := 0.005 * float64(rate)
- for i := 0; i < rate; i++ {
- t := float64(i) / float64(rate)
- f := 440.0
- if t >= 0.8 {
- f = 880
- }
- env := math.Min(1, math.Min(float64(i)/fade, float64(rate-1-i)/fade))
- v := 0.5 * env * math.Sin(2*math.Pi*f*t)
- s := int32(math.Round(v * float64(int32(1)<<(bits-1)-1)))
- var b [4]byte
- le.PutUint32(b[:], uint32(s))
- for c := 0; c < channels; c++ {
- data.Write(b[:width])
- }
- }
- align := channels * width
- var fmtc bytes.Buffer
- tag := uint16(1)
- if ext {
- tag = 0xFFFE
- }
- for _, v := range []any{tag, uint16(channels), uint32(rate), uint32(rate * align), uint16(align), uint16(bits)} {
- binary.Write(&fmtc, le, v)
- }
- if ext {
- mask := uint32(4) // front centre
- if channels == 2 {
- mask = 3 // front left, front right
- }
- for _, v := range []any{uint16(22), uint16(bits), mask} {
- binary.Write(&fmtc, le, v)
- }
- // KSDATAFORMAT_SUBTYPE_PCM 00000001-0000-0010-8000-00aa00389b71
- fmtc.Write([]byte{1, 0, 0, 0, 0, 0, 0x10, 0, 0x80, 0, 0, 0xaa, 0, 0x38, 0x9b, 0x71})
- }
- var body bytes.Buffer
- body.WriteString("WAVEfmt ")
- binary.Write(&body, le, uint32(fmtc.Len()))
- body.Write(fmtc.Bytes())
- body.WriteString("data")
- binary.Write(&body, le, uint32(data.Len()))
- body.Write(data.Bytes())
- if data.Len()%2 == 1 {
- body.WriteByte(0)
- }
- var out bytes.Buffer
- out.WriteString("RIFF")
- binary.Write(&out, le, uint32(body.Len()))
- out.Write(body.Bytes())
- return out.Bytes()
- }
|