1
0

decode.go 2.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071
  1. package wav
  2. import (
  3. "encoding/binary"
  4. "fmt"
  5. "io"
  6. "math"
  7. "os"
  8. )
  9. // DecodeFile reads the whole WAV at path and returns its samples as 32-bit
  10. // floats in [-1, 1], one slice per channel. It is the preview fallback for
  11. // formats a webview cannot decode (build plan section 9).
  12. func DecodeFile(path string) (Info, [][]float32, error) {
  13. f, err := os.Open(path)
  14. if err != nil {
  15. return Info{}, nil, err
  16. }
  17. defer f.Close()
  18. st, err := f.Stat()
  19. if err != nil {
  20. return Info{}, nil, err
  21. }
  22. info, err := Read(f, st.Size())
  23. if err != nil {
  24. return Info{}, nil, err
  25. }
  26. if err := info.Validate(); err != nil {
  27. return Info{}, nil, err
  28. }
  29. raw := make([]byte, info.Frames*int64(info.BlockAlign))
  30. if _, err := f.ReadAt(raw, info.DataOffset); err != nil && err != io.EOF {
  31. return Info{}, nil, fmt.Errorf("reading samples: %w", err)
  32. }
  33. return info, Decode(info, raw), nil
  34. }
  35. // Decode converts raw sample data described by info into per-channel floats.
  36. // info must have passed Validate.
  37. func Decode(info Info, raw []byte) [][]float32 {
  38. le := binary.LittleEndian
  39. width := info.BlockAlign / info.Channels
  40. frames := len(raw) / info.BlockAlign
  41. out := make([][]float32, info.Channels)
  42. for c := range out {
  43. out[c] = make([]float32, frames)
  44. }
  45. var sample func(b []byte) float32
  46. switch {
  47. case info.Format == FormatFloat:
  48. sample = func(b []byte) float32 { return math.Float32frombits(le.Uint32(b)) }
  49. case info.Bits == 8: // unsigned, centred on 128
  50. sample = func(b []byte) float32 { return (float32(b[0]) - 128) / 128 }
  51. case info.Bits == 16:
  52. sample = func(b []byte) float32 { return float32(int16(le.Uint16(b))) / (1 << 15) }
  53. case info.Bits == 24:
  54. sample = func(b []byte) float32 {
  55. v := int32(uint32(b[0])<<8|uint32(b[1])<<16|uint32(b[2])<<24) >> 8
  56. return float32(v) / (1 << 23)
  57. }
  58. case info.Bits == 32:
  59. sample = func(b []byte) float32 { return float32(float64(int32(le.Uint32(b))) / (1 << 31)) }
  60. }
  61. for i := 0; i < frames; i++ {
  62. frame := raw[i*info.BlockAlign:]
  63. for c := 0; c < info.Channels; c++ {
  64. out[c][i] = sample(frame[c*width:])
  65. }
  66. }
  67. return out
  68. }