Go-based FM stereo transmitter with RDS, Windows-first and cross-platform
Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

89 řádky
2.3KB

  1. package audio
  2. import (
  3. "encoding/binary"
  4. "fmt"
  5. "io"
  6. "os"
  7. )
  8. type WAVSource struct {
  9. frames []Frame
  10. index int
  11. SampleRate int
  12. Channels int
  13. }
  14. func LoadWAVSource(path string) (*WAVSource, error) {
  15. f, err := os.Open(path)
  16. if err != nil {
  17. return nil, err
  18. }
  19. defer f.Close()
  20. header := make([]byte, 44)
  21. if _, err := io.ReadFull(f, header); err != nil {
  22. return nil, fmt.Errorf("read wav header: %w", err)
  23. }
  24. if string(header[0:4]) != "RIFF" || string(header[8:12]) != "WAVE" {
  25. return nil, fmt.Errorf("unsupported wav header")
  26. }
  27. audioFormat := binary.LittleEndian.Uint16(header[20:22])
  28. channels := binary.LittleEndian.Uint16(header[22:24])
  29. sampleRate := binary.LittleEndian.Uint32(header[24:28])
  30. bitsPerSample := binary.LittleEndian.Uint16(header[34:36])
  31. dataSize := binary.LittleEndian.Uint32(header[40:44])
  32. if audioFormat != 1 {
  33. return nil, fmt.Errorf("only PCM wav supported")
  34. }
  35. if bitsPerSample != 16 {
  36. return nil, fmt.Errorf("only 16-bit PCM wav supported")
  37. }
  38. if channels != 1 && channels != 2 {
  39. return nil, fmt.Errorf("only mono/stereo wav supported")
  40. }
  41. if sampleRate == 0 {
  42. return nil, fmt.Errorf("invalid wav sample rate")
  43. }
  44. raw := make([]byte, dataSize)
  45. if _, err := io.ReadFull(f, raw); err != nil {
  46. return nil, fmt.Errorf("read wav data: %w", err)
  47. }
  48. step := int(channels) * 2
  49. frames := make([]Frame, 0, len(raw)/step)
  50. for i := 0; i+step <= len(raw); i += step {
  51. l := pcm16ToSample(int16(binary.LittleEndian.Uint16(raw[i : i+2])))
  52. r := l
  53. if channels == 2 {
  54. r = pcm16ToSample(int16(binary.LittleEndian.Uint16(raw[i+2 : i+4])))
  55. }
  56. frames = append(frames, NewFrame(l, r))
  57. }
  58. return &WAVSource{
  59. frames: frames,
  60. SampleRate: int(sampleRate),
  61. Channels: int(channels),
  62. }, nil
  63. }
  64. func (s *WAVSource) NextFrame() Frame {
  65. if len(s.frames) == 0 {
  66. return NewFrame(0, 0)
  67. }
  68. frame := s.frames[s.index]
  69. s.index++
  70. if s.index >= len(s.frames) {
  71. s.index = 0
  72. }
  73. return frame
  74. }
  75. func pcm16ToSample(v int16) Sample {
  76. return Sample(float64(v) / 32768.0).Clamp()
  77. }