Ariver
2026-07-13 490d60bbc90a4f407d2d9111e0da70e7efe6995a
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
package main
 
import (
    "encoding/binary"
    "flag"
    "fmt"
    "os"
    "time"
    "voicesnap/internal/engine"
)
 
func main() {
    wavPath := flag.String("wav", "", "16kHz mono PCM16 WAV file")
    runs := flag.Int("runs", 3, "number of recognition runs")
    flag.Parse()
 
    if *wavPath == "" {
        fmt.Fprintln(os.Stderr, "missing -wav")
        os.Exit(2)
    }
    if *runs < 1 {
        *runs = 1
    }
 
    samples, sampleRate, err := readPCM16WAV(*wavPath)
    if err != nil {
        fmt.Fprintf(os.Stderr, "read wav: %v\n", err)
        os.Exit(1)
    }
    if sampleRate != 16000 {
        fmt.Fprintf(os.Stderr, "unsupported sample rate %d: provide 16kHz mono PCM16 WAV\n", sampleRate)
        os.Exit(1)
    }
 
    eng, err := engine.New()
    if err != nil {
        fmt.Fprintf(os.Stderr, "init engine: %v\n", err)
        os.Exit(1)
    }
    defer eng.Close()
 
    audioMS := int64(len(samples)) * 1000 / 16000
    fmt.Printf("engine=%q samples=%d audio_ms=%d runs=%d\n", eng.HardwareInfo(), len(samples), audioMS, *runs)
    var total int64
    for i := 1; i <= *runs; i++ {
        start := time.Now()
        text, err := eng.Recognize(samples)
        elapsedMS := time.Since(start).Milliseconds()
        if err != nil {
            fmt.Fprintf(os.Stderr, "run=%d error=%v\n", i, err)
            os.Exit(1)
        }
        total += elapsedMS
        fmt.Printf("run=%d recognize_ms=%d rtf=%.3f text_runes=%d\n", i, elapsedMS, float64(elapsedMS)/float64(audioMS), len([]rune(text)))
    }
    fmt.Printf("avg_recognize_ms=%d\n", total/int64(*runs))
}
 
func readPCM16WAV(path string) ([]float32, int, error) {
    data, err := os.ReadFile(path)
    if err != nil {
        return nil, 0, err
    }
    if len(data) < 12 || string(data[0:4]) != "RIFF" || string(data[8:12]) != "WAVE" {
        return nil, 0, fmt.Errorf("not a RIFF/WAVE file")
    }
 
    var audioFormat, channels, bitsPerSample uint16
    var sampleRate uint32
    var pcm []byte
    for offset := 12; offset+8 <= len(data); {
        chunkID := string(data[offset : offset+4])
        chunkSize := int(binary.LittleEndian.Uint32(data[offset+4 : offset+8]))
        chunkStart := offset + 8
        chunkEnd := chunkStart + chunkSize
        if chunkEnd > len(data) {
            return nil, 0, fmt.Errorf("truncated %s chunk", chunkID)
        }
 
        switch chunkID {
        case "fmt ":
            if chunkSize < 16 {
                return nil, 0, fmt.Errorf("fmt chunk too small")
            }
            audioFormat = binary.LittleEndian.Uint16(data[chunkStart : chunkStart+2])
            channels = binary.LittleEndian.Uint16(data[chunkStart+2 : chunkStart+4])
            sampleRate = binary.LittleEndian.Uint32(data[chunkStart+4 : chunkStart+8])
            bitsPerSample = binary.LittleEndian.Uint16(data[chunkStart+14 : chunkStart+16])
        case "data":
            pcm = data[chunkStart:chunkEnd]
        }
 
        offset = chunkEnd
        if offset%2 == 1 {
            offset++
        }
    }
 
    if audioFormat != 1 || channels != 1 || bitsPerSample != 16 {
        return nil, 0, fmt.Errorf("unsupported WAV format: audio_format=%d channels=%d bits_per_sample=%d; want PCM16 mono", audioFormat, channels, bitsPerSample)
    }
    if len(pcm) == 0 {
        return nil, 0, fmt.Errorf("missing data chunk")
    }
    if len(pcm)%2 != 0 {
        return nil, 0, fmt.Errorf("odd PCM data length")
    }
 
    samples := make([]float32, len(pcm)/2)
    for i := range samples {
        v := int16(binary.LittleEndian.Uint16(pcm[i*2 : i*2+2]))
        samples[i] = float32(v) / 32768.0
    }
    return samples, int(sampleRate), nil
}