feat: added record qso dvk
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
//go:build windows
|
||||
|
||||
package audio
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
// The DVK/recorder pipeline uses a single fixed PCM format end-to-end: 16 kHz
|
||||
// mono 16-bit. That's plenty for SSB voice (3 kHz audio bandwidth), keeps files
|
||||
// tiny (~32 KB/s), and — fed through WASAPI's AUTOCONVERTPCM — plays/records on
|
||||
// any device regardless of its native mix format.
|
||||
const (
|
||||
sampleRate = 16000
|
||||
channels = 1
|
||||
bitsPerSample = 16
|
||||
blockAlign = channels * bitsPerSample / 8 // bytes per frame (=2)
|
||||
bytesPerSec = sampleRate * blockAlign // =32000
|
||||
)
|
||||
|
||||
// writeWAV writes 16-bit PCM as a canonical RIFF/WAVE file.
|
||||
func writeWAV(path string, pcm []byte) error {
|
||||
f, err := os.Create(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
dataLen := len(pcm)
|
||||
put := func(v any) { _ = binary.Write(f, binary.LittleEndian, v) }
|
||||
f.WriteString("RIFF")
|
||||
put(uint32(36 + dataLen))
|
||||
f.WriteString("WAVE")
|
||||
f.WriteString("fmt ")
|
||||
put(uint32(16)) // PCM fmt chunk size
|
||||
put(uint16(1)) // WAVE_FORMAT_PCM
|
||||
put(uint16(channels)) //
|
||||
put(uint32(sampleRate)) //
|
||||
put(uint32(bytesPerSec)) // byte rate
|
||||
put(uint16(blockAlign)) //
|
||||
put(uint16(bitsPerSample)) //
|
||||
f.WriteString("data")
|
||||
put(uint32(dataLen))
|
||||
_, err = f.Write(pcm)
|
||||
return err
|
||||
}
|
||||
|
||||
// readWAV reads a PCM WAV and returns the raw sample bytes plus its format.
|
||||
// Handles arbitrary chunk ordering (walks the RIFF chunk list).
|
||||
func readWAV(path string) (pcm []byte, rate, ch, bits int, err error) {
|
||||
b, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, 0, 0, 0, err
|
||||
}
|
||||
if len(b) < 12 || string(b[0:4]) != "RIFF" || string(b[8:12]) != "WAVE" {
|
||||
return nil, 0, 0, 0, fmt.Errorf("not a WAVE file")
|
||||
}
|
||||
i := 12
|
||||
for i+8 <= len(b) {
|
||||
id := string(b[i : i+4])
|
||||
size := int(binary.LittleEndian.Uint32(b[i+4 : i+8]))
|
||||
body := i + 8
|
||||
if body+size > len(b) {
|
||||
size = len(b) - body
|
||||
}
|
||||
switch id {
|
||||
case "fmt ":
|
||||
if size >= 16 {
|
||||
ch = int(binary.LittleEndian.Uint16(b[body+2 : body+4]))
|
||||
rate = int(binary.LittleEndian.Uint32(b[body+4 : body+8]))
|
||||
bits = int(binary.LittleEndian.Uint16(b[body+14 : body+16]))
|
||||
}
|
||||
case "data":
|
||||
pcm = b[body : body+size]
|
||||
}
|
||||
i = body + size
|
||||
if size%2 == 1 {
|
||||
i++ // chunks are word-aligned
|
||||
}
|
||||
}
|
||||
if pcm == nil || rate == 0 {
|
||||
return nil, 0, 0, 0, fmt.Errorf("WAV missing fmt/data")
|
||||
}
|
||||
return pcm, rate, ch, bits, nil
|
||||
}
|
||||
Reference in New Issue
Block a user