1
0

tone.go 1.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
  1. package main
  2. import (
  3. "bytes"
  4. "encoding/binary"
  5. "math"
  6. )
  7. // tone returns the WAV test pack's tone (0.8 s at 440 Hz, then 0.2 s at
  8. // 880 Hz as an end marker) as a WAV file of integer PCM, optionally with the
  9. // WAVE_FORMAT_EXTENSIBLE header many audio tools write. bits is 16 or 24.
  10. func tone(rate, bits, channels int, ext bool) []byte {
  11. le := binary.LittleEndian
  12. width := bits / 8
  13. var data bytes.Buffer
  14. fade := 0.005 * float64(rate)
  15. for i := 0; i < rate; i++ {
  16. t := float64(i) / float64(rate)
  17. f := 440.0
  18. if t >= 0.8 {
  19. f = 880
  20. }
  21. env := math.Min(1, math.Min(float64(i)/fade, float64(rate-1-i)/fade))
  22. v := 0.5 * env * math.Sin(2*math.Pi*f*t)
  23. s := int32(math.Round(v * float64(int32(1)<<(bits-1)-1)))
  24. var b [4]byte
  25. le.PutUint32(b[:], uint32(s))
  26. for c := 0; c < channels; c++ {
  27. data.Write(b[:width])
  28. }
  29. }
  30. align := channels * width
  31. var fmtc bytes.Buffer
  32. tag := uint16(1)
  33. if ext {
  34. tag = 0xFFFE
  35. }
  36. for _, v := range []any{tag, uint16(channels), uint32(rate), uint32(rate * align), uint16(align), uint16(bits)} {
  37. binary.Write(&fmtc, le, v)
  38. }
  39. if ext {
  40. mask := uint32(4) // front centre
  41. if channels == 2 {
  42. mask = 3 // front left, front right
  43. }
  44. for _, v := range []any{uint16(22), uint16(bits), mask} {
  45. binary.Write(&fmtc, le, v)
  46. }
  47. // KSDATAFORMAT_SUBTYPE_PCM 00000001-0000-0010-8000-00aa00389b71
  48. fmtc.Write([]byte{1, 0, 0, 0, 0, 0, 0x10, 0, 0x80, 0, 0, 0xaa, 0, 0x38, 0x9b, 0x71})
  49. }
  50. var body bytes.Buffer
  51. body.WriteString("WAVEfmt ")
  52. binary.Write(&body, le, uint32(fmtc.Len()))
  53. body.Write(fmtc.Bytes())
  54. body.WriteString("data")
  55. binary.Write(&body, le, uint32(data.Len()))
  56. body.Write(data.Bytes())
  57. if data.Len()%2 == 1 {
  58. body.WriteByte(0)
  59. }
  60. var out bytes.Buffer
  61. out.WriteString("RIFF")
  62. binary.Write(&out, le, uint32(body.Len()))
  63. out.Write(body.Bytes())
  64. return out.Bytes()
  65. }