wavtest.go (4429B)
1 package main 2 3 import ( 4 "encoding/binary" 5 "fmt" 6 "io" 7 "os" 8 "time" 9 ) 10 11 // Thanks: https://wavefilegem.com/how_wave_files_work.html 12 type Wave struct { 13 ChunkID [4]byte 14 ChunkSize uint32 15 Format [4]byte 16 Subchunk1ID [4]byte 17 Subchunk1Size uint32 18 AudioFormat uint16 19 NumChannels uint16 20 SampleRate uint32 21 ByteRate uint32 22 BlockAlign uint16 23 BitsPerSample uint16 24 Subchunk2ID [4]byte 25 Subchunk2Size uint32 26 Data [][]float64 27 } 28 29 // Descriptor returns a string of the data that should be common 30 func (w *Wave) Descriptor() string { 31 return fmt.Sprintf("ChunkID: '%s', Format: '%s': Subchunk1ID: '%s', Subchunk2ID: '%s'", 32 w.ChunkID, w.Format, w.Subchunk1ID, w.Subchunk2ID) 33 } 34 35 // CheckFormat checks that the common bytes (chunk IDs and format code) are like expected 36 func (w *Wave) CheckFormat() error { 37 return nil 38 } 39 40 func (w *Wave) FormatString() string { 41 var format string 42 switch w.AudioFormat { 43 case 1: 44 format = "integer PCM" 45 case 2: 46 format = "ADPCM" 47 case 3: 48 format = "floating point PCM" 49 case 6: 50 format = "A-law" 51 case 7: 52 format = "mu-law" 53 case 65534: 54 format = "WaveFormatExtensible" 55 default: 56 format = fmt.Sprintf("unknown (code %v)", w.AudioFormat) 57 } 58 return fmt.Sprintf("AudioFormat: %v, Channels: %v, Sample rate: %v, Bits/sample: %v", format, w.NumChannels, w.SampleRate, w.BitsPerSample) 59 } 60 61 //func (w *Wave) String() string { 62 // return fmt.Sprintf("WAVE, fs=%v, 63 //} 64 65 func (wav *Wave) LoadMetaData(file *os.File) { 66 // can use nil instead of BigEndian when reading into []byte (endianness is ignored) 67 binary.Read(file, binary.BigEndian, &wav.ChunkID) 68 binary.Read(file, binary.LittleEndian, &wav.ChunkSize) 69 binary.Read(file, binary.BigEndian, &wav.Format) 70 binary.Read(file, binary.BigEndian, &wav.Subchunk1ID) 71 binary.Read(file, binary.LittleEndian, &wav.Subchunk1Size) 72 binary.Read(file, binary.LittleEndian, &wav.AudioFormat) 73 binary.Read(file, binary.LittleEndian, &wav.NumChannels) 74 binary.Read(file, binary.LittleEndian, &wav.SampleRate) 75 binary.Read(file, binary.LittleEndian, &wav.ByteRate) 76 binary.Read(file, binary.LittleEndian, &wav.BlockAlign) 77 binary.Read(file, binary.LittleEndian, &wav.BitsPerSample) 78 binary.Read(file, binary.BigEndian, &wav.Subchunk2ID) 79 binary.Read(file, binary.LittleEndian, &wav.Subchunk2Size) 80 } 81 82 func LoadFile1(filename string) *Wave { 83 file, err := os.Open(filename) 84 if err != nil { 85 fmt.Println("error when opening file:", err) 86 panic(err) 87 } 88 wav := Wave{} 89 wav.LoadMetaData(file) 90 numSamples := wav.Subchunk2Size / (uint32(wav.NumChannels) * uint32(wav.BitsPerSample) / 8) 91 waveBytes := make([][][]byte, numSamples) 92 for sample := range waveBytes { 93 waveBytes[sample] = make([][]byte, wav.NumChannels) 94 for channel := range waveBytes[sample] { 95 waveBytes[sample][channel] = make([]byte, wav.BitsPerSample/8) 96 } 97 } 98 var sample int 99 var channel uint16 100 for err == nil && sample < len(waveBytes) { 101 err = binary.Read(file, binary.LittleEndian, &waveBytes[sample][channel]) 102 sample++ 103 channel++ 104 if uint16(channel) >= wav.NumChannels { 105 channel = 0 106 } 107 } 108 if err != nil && err != io.EOF { 109 fmt.Println("error when reading wave data:", err) 110 } 111 return &wav 112 } 113 114 func LoadFile2(filename string) *Wave { 115 file, err := os.Open(filename) 116 if err != nil { 117 fmt.Println("error when opening file:", err) 118 panic(err) 119 } 120 wav := Wave{} 121 wav.LoadMetaData(file) 122 waveBytes := make([]byte, wav.Subchunk2Size) 123 err = binary.Read(file, nil, &waveBytes) 124 if err != nil && err != io.EOF { 125 fmt.Println("error when reading wave data:", err) 126 } 127 for _, b := range waveBytes[:30] { 128 fmt.Printf("%x ", b) 129 } 130 fmt.Println("") 131 return &wav 132 } 133 134 func LoadFile3(filename string) *Wave { 135 file, err := os.Open(filename) 136 if err != nil { 137 fmt.Println("error when opening file:", err) 138 panic(err) 139 } 140 wav := Wave{} 141 err = binary.Read(file, nil, wav) 142 if err != nil && err != io.EOF { 143 fmt.Println("error when reading wave data:", err) 144 } 145 return &wav 146 } 147 148 func main() { 149 if len(os.Args) < 2 { 150 fmt.Println("No filename given") 151 os.Exit(1) 152 } 153 start := time.Now() 154 LoadFile1(os.Args[1]) 155 fmt.Printf("LoadFile1 finished in %s\n", time.Since(start)) 156 start = time.Now() 157 LoadFile2(os.Args[1]) 158 fmt.Printf("LoadFile2 finished in %s\n", time.Since(start)) 159 //fmt.Println(wav.FormatString()) 160 //fmt.Println(wav.Descriptor()) 161 start = time.Now() 162 LoadFile3(os.Args[1]) 163 fmt.Printf("LoadFile3 finished in %s\n", time.Since(start)) 164 }