Skip to content

Commit bec76ed

Browse files
committed
Add README
1 parent 99e87bd commit bec76ed

12 files changed

+175
-11
lines changed

.github/workflows/build-linux-x64.yml .github/workflows/linux-x64.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
name: build-linux-x64
1+
name: linux-x64
22
on:
33
push:
44
branches: [main]

.github/workflows/build-mac-arm64.yml .github/workflows/mac-arm64.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
name: build-mac-arm64
1+
name: mac-arm64
22
on:
33
push:
44
branches: [main]

.github/workflows/build-mac-x64.yml .github/workflows/mac-x64.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
name: build-mac-x64
1+
name: mac-x64
22
on:
33
push:
44
branches: [main]

.github/workflows/build-windows-x64.yml .github/workflows/windows-x64.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
name: build-windows-x64
1+
name: windows-x64
22
on:
33
push:
44
branches: [main]

README.lhs

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
README.md

README.md

+59-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,60 @@
11
# silero-vad-hs
2-
Voice activity detection powered by SileroVAD
2+
3+
[![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](https://opensource.org/licenses/MIT) [![Hackage](http://img.shields.io/hackage/v/silero-vad.svg)](https://hackage.haskell.org/package/silero-vad)
4+
5+
Voice activity detection powered by SileroVAD.
6+
7+
## Supported architectures
8+
9+
- [![build-linux-x64](https://github.com/qwbarch/silero-vad-hs/actions/workflows/linux-x64.yml/badge.svg)](https://github.com/qwbarch/silero-vad-hs/actions/workflows/linux-x64.yml)
10+
- [![build-mac-arm64](https://github.com/qwbarch/silero-vad-hs/actions/workflows/mac-arm64.yml/badge.svg)](https://github.com/qwbarch/silero-vad-hs/actions/workflows/mac-arm64.yml)
11+
- [![build-mac-x64](https://github.com/qwbarch/silero-vad-hs/actions/workflows/mac-x64.yml/badge.svg)](https://github.com/qwbarch/silero-vad-hs/actions/workflows/mac-x64.yml)
12+
- [![build-windows-x64](https://github.com/qwbarch/silero-vad-hs/actions/workflows/windows-x64.yml/badge.svg)](https://github.com/qwbarch/silero-vad-hs/actions/workflows/windows-x64.yml)
13+
14+
## Quick start
15+
16+
This is a literate haskell file. You can run this example via the following:
17+
```bash
18+
nix develop --command bash -c '
19+
export LD_LIBRARY_PATH=lib:$(nix path-info .#stdenv.cc.cc.lib)/lib
20+
cabal run --flags="build-readme"
21+
'
22+
```
23+
24+
Necessary language extensions and imports for the example:
25+
```haskell
26+
import qualified Data.Vector.Storable as Vector
27+
import Data.Function ((&))
28+
import Data.WAVE (sampleToDouble, WAVE (waveSamples), getWAVEFile)
29+
import Silero (withVad, withModel, detectSegments, detectSpeech, windowLength)
30+
```
31+
32+
For this example, the [WAVE](https://hackage.haskell.org/package/WAVE) library is used for simplicity.
33+
Unfortunately, its design is flawed and represents audio in a lazy linked list.
34+
Prefer using [wave](https://hackage.haskell.org/package/wave) for better performance.
35+
36+
```haskell
37+
main :: IO ()
38+
main = do
39+
wav <- getWAVEFile "lib/jfk.wav"
40+
```
41+
The functions below expects a ``Vector Float``. This converts it to the expected format.
42+
```haskell
43+
let samples =
44+
concat (waveSamples wav)
45+
& Vector.fromList
46+
& Vector.map (realToFrac . sampleToDouble)
47+
```
48+
Use ``detectSegments`` to detect the start/end times of voice activity segments.
49+
```haskell
50+
withVad $ \vad -> do
51+
segments <- detectSegments vad samples
52+
print segments
53+
pure ()
54+
```
55+
Alternatively, use ``detectSpeech`` if you want to detect if speech is found in a single window:
56+
```haskell
57+
withModel $ \model -> do
58+
probability <- detectSpeech model $ Vector.take windowLength samples
59+
putStrLn $ "Probability: " <> show probability
60+
```

cbits/silero/model.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ int64_t get_window_length() { return WINDOW_LENGTH; }
2323
int64_t get_sample_rate() { return SAMPLE_RATE; }
2424

2525
struct SileroModel *load_model(OrtApiBase *(*ortGetApiBase)(),
26-
const char *model_path) {
26+
const void *model_path) {
2727
struct SileroModel *model = malloc(sizeof(struct SileroModel));
2828
model->api = ortGetApiBase()->GetApi(ORT_API_VERSION);
2929
(void)model->api->CreateEnv(ORT_LOGGING_LEVEL, "silero-vad-hs", &model->env);

cbits/silero/model.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ struct SileroModel
2525
bool is_first_run;
2626
};
2727

28-
struct SileroModel *load_model(OrtApiBase *(*ortGetApiBase)(), const char *model_path);
28+
struct SileroModel *load_model(OrtApiBase *(*ortGetApiBase)(), const void *model_path);
2929
void release_model(struct SileroModel *model);
3030
void reset_model(struct SileroModel *model);
3131
float detect_speech(struct SileroModel *model, const float *samples);

package.yaml

+28
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,37 @@ data-files:
2424
- lib/silero_vad.onnx
2525
- lib/jfk.wav
2626

27+
flags:
28+
build-readme:
29+
description: "Build the literate haskell README example."
30+
default: false
31+
manual: false
32+
2733
library:
2834
source-dirs: src
2935

36+
executables:
37+
readme:
38+
when:
39+
condition: "!flag(build-readme)"
40+
buildable: False
41+
build-tools: markdown-unlit:markdown-unlit
42+
main: README.lhs
43+
source-dirs:
44+
- .
45+
- src
46+
ghc-options:
47+
- -threaded
48+
- -rtsopts
49+
- -with-rtsopts=-N
50+
- -flate-specialise
51+
- -fspecialise-aggressively
52+
- -Wall
53+
- -Wno-name-shadowing
54+
- -pgmL markdown-unlit
55+
dependencies:
56+
- WAVE ^>= 0.1
57+
3058
tests:
3159
test:
3260
main: Main.hs

silero-vad.cabal

+70
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,14 @@ data-files:
2828
lib/silero_vad.onnx
2929
lib/jfk.wav
3030

31+
flag build-readme
32+
description: Build the literate haskell README example.
33+
manual: False
34+
default: False
35+
3136
library
3237
exposed-modules:
38+
Silero
3339
Silero.Detector
3440
Silero.Model
3541
other-modules:
@@ -83,10 +89,74 @@ library
8389
build-depends:
8490
Win32 ==2.*
8591

92+
executable readme
93+
main-is: README.lhs
94+
other-modules:
95+
Silero
96+
Silero.Detector
97+
Silero.Model
98+
Paths_silero_vad
99+
hs-source-dirs:
100+
./
101+
src
102+
default-extensions:
103+
DataKinds
104+
DeriveAnyClass
105+
DeriveGeneric
106+
DerivingStrategies
107+
DuplicateRecordFields
108+
EmptyDataDecls
109+
ExplicitNamespaces
110+
FlexibleContexts
111+
GeneralizedNewtypeDeriving
112+
LambdaCase
113+
MultiParamTypeClasses
114+
NegativeLiterals
115+
NumericUnderscores
116+
OverloadedLabels
117+
OverloadedStrings
118+
PolyKinds
119+
QuasiQuotes
120+
RankNTypes
121+
ScopedTypeVariables
122+
StrictData
123+
TemplateHaskell
124+
TypeApplications
125+
TypeOperators
126+
ghc-options: -threaded -rtsopts -with-rtsopts=-N -flate-specialise -fspecialise-aggressively -Wall -Wno-name-shadowing -pgmL markdown-unlit
127+
cc-options: -Wno-unused-result
128+
include-dirs:
129+
cbits
130+
c-sources:
131+
cbits/silero/detector.c
132+
cbits/silero/detector.h
133+
cbits/silero/model.c
134+
cbits/silero/model.h
135+
cbits/vec.c
136+
cbits/vec.h
137+
build-tool-depends:
138+
markdown-unlit:markdown-unlit
139+
build-depends:
140+
WAVE ==0.1.*
141+
, base >=4.14.3.0 && <5
142+
, derive-storable >=0.3.0.0 && <1
143+
, unliftio >=0.2.20.0 && <1
144+
, vector >=0.13.0.0 && <1
145+
default-language: Haskell2010
146+
if os(linux) || os(darwin)
147+
build-depends:
148+
unix ==2.*
149+
if os(windows)
150+
build-depends:
151+
Win32 ==2.*
152+
if !flag(build-readme)
153+
buildable: False
154+
86155
test-suite test
87156
type: exitcode-stdio-1.0
88157
main-is: Main.hs
89158
other-modules:
159+
Silero
90160
Silero.Detector
91161
Silero.Model
92162
Paths_silero_vad

src/Silero.hs

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
module Silero (
2+
module Silero.Detector,
3+
module Silero.Model,
4+
) where
5+
6+
import Silero.Detector
7+
import Silero.Model

src/Silero/Model.hs

+4-4
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
module Silero.Model (
44
SileroModel (..),
55
detectSpeech,
6-
windowSize,
6+
windowLength,
77
resetModel,
88
sampleRate,
99
withModel,
@@ -53,8 +53,8 @@ foreign import ccall "model.h load_model" c_load_model :: FunPtr () -> CWString
5353

5454
#endif
5555

56-
windowSize :: Int
57-
windowSize = fromIntegral $ unsafeDupablePerformIO c_get_window_length
56+
windowLength :: Int
57+
windowLength = fromIntegral $ unsafeDupablePerformIO c_get_window_length
5858

5959
sampleRate :: Int
6060
sampleRate = fromIntegral $ unsafeDupablePerformIO c_get_sample_rate
@@ -156,7 +156,7 @@ resetModel = liftIO . c_reset_model . api
156156
-- | **Warning: SileroModel holds internal state and is NOT thread safe.**
157157
detectSpeech :: (MonadIO m) => SileroModel -> Vector Float -> m Float
158158
detectSpeech (SileroModel api) samples
159-
| Vector.length samples /= windowSize =
159+
| Vector.length samples /= windowLength =
160160
return 0.0
161161
| otherwise =
162162
liftIO . Vector.unsafeWith samples $

0 commit comments

Comments
 (0)