You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

79 lines
1.7KB

  1. package recorder
  2. import (
  3. "encoding/binary"
  4. "os"
  5. )
  6. func writeWAV(path string, samples []float32, sampleRate int) error {
  7. f, err := os.Create(path)
  8. if err != nil {
  9. return err
  10. }
  11. defer f.Close()
  12. // 16-bit PCM
  13. dataSize := uint32(len(samples) * 2)
  14. // RIFF header
  15. if _, err := f.Write([]byte("RIFF")); err != nil {
  16. return err
  17. }
  18. if err := binary.Write(f, binary.LittleEndian, uint32(36)+dataSize); err != nil {
  19. return err
  20. }
  21. if _, err := f.Write([]byte("WAVE")); err != nil {
  22. return err
  23. }
  24. // fmt chunk
  25. if _, err := f.Write([]byte("fmt ")); err != nil {
  26. return err
  27. }
  28. if err := binary.Write(f, binary.LittleEndian, uint32(16)); err != nil {
  29. return err
  30. }
  31. if err := binary.Write(f, binary.LittleEndian, uint16(1)); err != nil { // PCM
  32. return err
  33. }
  34. if err := binary.Write(f, binary.LittleEndian, uint16(1)); err != nil { // mono
  35. return err
  36. }
  37. if err := binary.Write(f, binary.LittleEndian, uint32(sampleRate)); err != nil {
  38. return err
  39. }
  40. byteRate := uint32(sampleRate * 2)
  41. if err := binary.Write(f, binary.LittleEndian, byteRate); err != nil {
  42. return err
  43. }
  44. if err := binary.Write(f, binary.LittleEndian, uint16(2)); err != nil { // block align
  45. return err
  46. }
  47. if err := binary.Write(f, binary.LittleEndian, uint16(16)); err != nil { // bits
  48. return err
  49. }
  50. // data chunk
  51. if _, err := f.Write([]byte("data")); err != nil {
  52. return err
  53. }
  54. if err := binary.Write(f, binary.LittleEndian, dataSize); err != nil {
  55. return err
  56. }
  57. // samples
  58. for _, s := range samples {
  59. v := int16(clip(s * 32767))
  60. if err := binary.Write(f, binary.LittleEndian, v); err != nil {
  61. return err
  62. }
  63. }
  64. return nil
  65. }
  66. func clip(v float32) float32 {
  67. if v > 32767 {
  68. return 32767
  69. }
  70. if v < -32768 {
  71. return -32768
  72. }
  73. return v
  74. }