experiments

All kinds of coding experiments
Log | Files | Refs | Submodules

wavtest2.go (3035B)


      1 package main
      2 
      3 import (
      4 	"bytes"
      5 	"encoding/binary"
      6 	"fmt"
      7 	"io"
      8 	"os"
      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          []byte
     27 }
     28 
     29 func (wav *Wave) Len() uint32 {
     30 	return uint32(len(wav.Data)) / uint32(wav.NumChannels*wav.BitsPerSample/8)
     31 }
     32 
     33 func (wav *Wave) LoadMetaData(file *os.File) {
     34 	// can use nil instead of BigEndian when reading into []byte (endianness is ignored)
     35 	binary.Read(file, binary.BigEndian, &wav.ChunkID)
     36 	binary.Read(file, binary.LittleEndian, &wav.ChunkSize)
     37 	binary.Read(file, binary.BigEndian, &wav.Format)
     38 	binary.Read(file, binary.BigEndian, &wav.Subchunk1ID)
     39 	binary.Read(file, binary.LittleEndian, &wav.Subchunk1Size)
     40 	binary.Read(file, binary.LittleEndian, &wav.AudioFormat)
     41 	binary.Read(file, binary.LittleEndian, &wav.NumChannels)
     42 	binary.Read(file, binary.LittleEndian, &wav.SampleRate)
     43 	binary.Read(file, binary.LittleEndian, &wav.ByteRate)
     44 	binary.Read(file, binary.LittleEndian, &wav.BlockAlign)
     45 	binary.Read(file, binary.LittleEndian, &wav.BitsPerSample)
     46 	binary.Read(file, binary.BigEndian, &wav.Subchunk2ID)
     47 	binary.Read(file, binary.LittleEndian, &wav.Subchunk2Size)
     48 }
     49 
     50 func LoadFile(filename string) *Wave {
     51 	file, err := os.Open(filename)
     52 	if err != nil {
     53 		fmt.Println("error when opening file:", err)
     54 		panic(err)
     55 	}
     56 	wav := Wave{}
     57 	wav.LoadMetaData(file)
     58 	wav.Data = make([]byte, wav.Subchunk2Size)
     59 	err = binary.Read(file, nil, &wav.Data)
     60 	if err != nil && err != io.EOF {
     61 		fmt.Println("error when reading wave data:", err)
     62 	}
     63 	return &wav
     64 }
     65 
     66 // PCM Int 16 and 32 are always signed integers
     67 func (wav *Wave) FromInt32() [][]float64 {
     68 	fData := make([][]float64, wav.Len())
     69 	buf := bytes.NewReader(wav.Data)
     70 	var err error
     71 	for n := uint32(0); n < wav.Len(); n++ {
     72 		fData[n] = make([]float64, wav.NumChannels)
     73 		var sample int32
     74 		for c := range fData[n] {
     75 			err = binary.Read(buf, binary.LittleEndian, &sample)
     76 			if err != nil {
     77 				panic(err)
     78 			}
     79 			fData[n][c] = float64(sample) / float64(1<<31)
     80 		}
     81 	}
     82 	return fData
     83 }
     84 
     85 func (wav *Wave) FromInt16() [][]float64 {
     86 	fData := make([][]float64, wav.Len())
     87 	buf := bytes.NewReader(wav.Data)
     88 	var err error
     89 	for n := uint32(0); n < wav.Len(); n++ {
     90 		fData[n] = make([]float64, wav.NumChannels)
     91 		var sample int16
     92 		for c := range fData[n] {
     93 			err = binary.Read(buf, binary.LittleEndian, &sample)
     94 			if err != nil {
     95 				panic(err)
     96 			}
     97 			fData[n][c] = float64(sample) / float64(1<<15)
     98 		}
     99 	}
    100 	return fData
    101 }
    102 
    103 func main() {
    104 	if len(os.Args) < 2 {
    105 		fmt.Println("No filename given")
    106 		os.Exit(1)
    107 	}
    108 	wav := LoadFile(os.Args[1])
    109 	switch wav.BitsPerSample {
    110 	case 16:
    111 		fmt.Println(wav.FromInt16())
    112 	case 32:
    113 		fmt.Println(wav.FromInt32())
    114 	default:
    115 		panic("unsupported number of bits per sample")
    116 	}
    117 }