Add projects
This commit is contained in:
parent
2d3a9ad623
commit
8b607dd700
1802 changed files with 503346 additions and 2 deletions
147
backend/examples/realtime-openai-go/wav.go
Normal file
147
backend/examples/realtime-openai-go/wav.go
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
const (
|
||||
maxInputPCMBytes = 15 << 20
|
||||
maxOutputPCMBytes = 64 << 20
|
||||
wavHeaderSize = 44
|
||||
)
|
||||
|
||||
func readPCM16WAV(path string) ([]byte, error) {
|
||||
fileInfo, errStat := os.Stat(path)
|
||||
if errStat != nil {
|
||||
return nil, errStat
|
||||
}
|
||||
if fileInfo.Size() > maxInputPCMBytes+(1<<20) {
|
||||
return nil, fmt.Errorf("WAV file is too large: %d bytes", fileInfo.Size())
|
||||
}
|
||||
payload, errRead := os.ReadFile(path)
|
||||
if errRead != nil {
|
||||
return nil, errRead
|
||||
}
|
||||
if len(payload) < 12 || string(payload[:4]) != "RIFF" || string(payload[8:12]) != "WAVE" {
|
||||
return nil, errors.New("input is not a RIFF/WAVE file")
|
||||
}
|
||||
|
||||
var formatFound bool
|
||||
var audioFormat uint16
|
||||
var channels uint16
|
||||
var sampleRate uint32
|
||||
var bitsPerSample uint16
|
||||
var pcm bytes.Buffer
|
||||
for offset := 12; offset+8 <= len(payload); {
|
||||
chunkID := string(payload[offset : offset+4])
|
||||
chunkSize := int(binary.LittleEndian.Uint32(payload[offset+4 : offset+8]))
|
||||
chunkStart := offset + 8
|
||||
chunkEnd := chunkStart + chunkSize
|
||||
if chunkSize < 0 || chunkEnd < chunkStart || chunkEnd > len(payload) {
|
||||
return nil, fmt.Errorf("invalid WAV %q chunk size", chunkID)
|
||||
}
|
||||
switch chunkID {
|
||||
case "fmt ":
|
||||
if chunkSize < 16 {
|
||||
return nil, errors.New("WAV fmt chunk is too short")
|
||||
}
|
||||
audioFormat = binary.LittleEndian.Uint16(payload[chunkStart : chunkStart+2])
|
||||
channels = binary.LittleEndian.Uint16(payload[chunkStart+2 : chunkStart+4])
|
||||
sampleRate = binary.LittleEndian.Uint32(payload[chunkStart+4 : chunkStart+8])
|
||||
bitsPerSample = binary.LittleEndian.Uint16(payload[chunkStart+14 : chunkStart+16])
|
||||
formatFound = true
|
||||
case "data":
|
||||
if pcm.Len()+chunkSize > maxInputPCMBytes {
|
||||
return nil, fmt.Errorf("WAV PCM data exceeds %d bytes", maxInputPCMBytes)
|
||||
}
|
||||
_, _ = pcm.Write(payload[chunkStart:chunkEnd])
|
||||
}
|
||||
offset = chunkEnd
|
||||
if chunkSize%2 != 0 {
|
||||
offset++
|
||||
}
|
||||
}
|
||||
if !formatFound {
|
||||
return nil, errors.New("WAV fmt chunk is missing")
|
||||
}
|
||||
if audioFormat != 1 {
|
||||
return nil, fmt.Errorf("WAV audio format must be PCM (1), got %d", audioFormat)
|
||||
}
|
||||
if channels != 1 {
|
||||
return nil, fmt.Errorf("WAV must be mono, got %d channels", channels)
|
||||
}
|
||||
if sampleRate != audioSampleRate {
|
||||
return nil, fmt.Errorf("WAV sample rate must be %d Hz, got %d Hz", audioSampleRate, sampleRate)
|
||||
}
|
||||
if bitsPerSample != 16 {
|
||||
return nil, fmt.Errorf("WAV must use 16-bit samples, got %d bits", bitsPerSample)
|
||||
}
|
||||
if pcm.Len() == 0 {
|
||||
return nil, errors.New("WAV data chunk is empty or missing")
|
||||
}
|
||||
if pcm.Len()%audioBytesPerSample != 0 {
|
||||
return nil, errors.New("WAV PCM data contains an incomplete sample")
|
||||
}
|
||||
return append([]byte(nil), pcm.Bytes()...), nil
|
||||
}
|
||||
|
||||
func writePCM16WAV(path string, pcm []byte) error {
|
||||
if len(pcm) == 0 {
|
||||
return errors.New("cannot write an empty WAV response")
|
||||
}
|
||||
if len(pcm) > maxOutputPCMBytes {
|
||||
return fmt.Errorf("response PCM data exceeds %d bytes", maxOutputPCMBytes)
|
||||
}
|
||||
if len(pcm)%audioBytesPerSample != 0 {
|
||||
return errors.New("response PCM data contains an incomplete sample")
|
||||
}
|
||||
|
||||
var payload bytes.Buffer
|
||||
payload.Grow(wavHeaderSize + len(pcm))
|
||||
writeString := func(value string) error {
|
||||
_, errWrite := payload.WriteString(value)
|
||||
return errWrite
|
||||
}
|
||||
writeValue := func(value any) error {
|
||||
return binary.Write(&payload, binary.LittleEndian, value)
|
||||
}
|
||||
if errWrite := writeString("RIFF"); errWrite != nil {
|
||||
return errWrite
|
||||
}
|
||||
if errWrite := writeValue(uint32(36 + len(pcm))); errWrite != nil {
|
||||
return errWrite
|
||||
}
|
||||
if errWrite := writeString("WAVEfmt "); errWrite != nil {
|
||||
return errWrite
|
||||
}
|
||||
for _, value := range []any{
|
||||
uint32(16),
|
||||
uint16(1),
|
||||
uint16(1),
|
||||
uint32(audioSampleRate),
|
||||
uint32(audioSampleRate * audioBytesPerSample),
|
||||
uint16(audioBytesPerSample),
|
||||
uint16(16),
|
||||
} {
|
||||
if errWrite := writeValue(value); errWrite != nil {
|
||||
return errWrite
|
||||
}
|
||||
}
|
||||
if errWrite := writeString("data"); errWrite != nil {
|
||||
return errWrite
|
||||
}
|
||||
if errWrite := writeValue(uint32(len(pcm))); errWrite != nil {
|
||||
return errWrite
|
||||
}
|
||||
if _, errWrite := payload.Write(pcm); errWrite != nil {
|
||||
return errWrite
|
||||
}
|
||||
if errWrite := os.WriteFile(path, payload.Bytes(), 0o644); errWrite != nil {
|
||||
return errWrite
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Loading…
Reference in a new issue