speaker_identification_test.dart
3.7 KB
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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
// Copyright (c) 2024 Xiaomi Corporation
import 'package:sherpa_onnx/sherpa_onnx.dart' as sherpa_onnx;
import 'dart:typed_data';
import 'package:path/path.dart';
import './utils.dart';
Float32List computeEmbedding(
{required sherpa_onnx.SpeakerEmbeddingExtractor extractor,
required String filename}) {
final stream = extractor.createStream();
final waveData = sherpa_onnx.readWave(filename);
stream.acceptWaveform(
samples: waveData.samples, sampleRate: waveData.sampleRate);
stream.inputFinished();
final embedding = extractor.compute(stream);
stream.free();
return embedding;
}
Future<void> testSpeakerID() async {
final src =
'assets/3dspeaker_speech_eres2net_base_sv_zh-cn_3dspeaker_16k.onnx';
final modelPath = await copyAssetFile(src: src, dst: 'model.onnx');
final config = sherpa_onnx.SpeakerEmbeddingExtractorConfig(model: modelPath);
final extractor = sherpa_onnx.SpeakerEmbeddingExtractor(config: config);
const _spk1Files = [
'assets/sr-data/enroll/fangjun-sr-1.wav',
'assets/sr-data/enroll/fangjun-sr-2.wav',
'assets/sr-data/enroll/fangjun-sr-3.wav',
];
final spk1Files = <String>[];
for (final f in _spk1Files) {
spk1Files.add(await copyAssetFile(src: f, dst: basename(f)));
}
final spk1Vec = <Float32List>[];
for (final f in spk1Files) {
spk1Vec.add(computeEmbedding(extractor: extractor, filename: f));
}
const _spk2Files = [
'assets/sr-data/enroll/leijun-sr-1.wav',
'assets/sr-data/enroll/leijun-sr-2.wav',
];
final spk2Files = <String>[];
for (final f in _spk2Files) {
spk2Files.add(await copyAssetFile(src: f, dst: basename(f)));
}
final spk2Vec = <Float32List>[];
for (final f in spk2Files) {
spk2Vec.add(computeEmbedding(extractor: extractor, filename: f));
}
final manager = sherpa_onnx.SpeakerEmbeddingManager(extractor.dim);
assert(manager.numSpeakers == 0, '${manager.numSpeakers}');
bool ok = manager.addMulti(name: 'fangjun', embeddingList: spk1Vec);
assert(ok, "Failed to add fangjun");
assert(manager.numSpeakers == 1, '${manager.numSpeakers}');
ok = manager.addMulti(name: 'leijun', embeddingList: spk2Vec);
assert(ok, "Failed to add leijun");
assert(manager.numSpeakers == 2, '${manager.numSpeakers}');
bool found = manager.contains('fangjun');
assert(found, 'Failed to find fangjun');
found = manager.contains('leijun');
assert(found, 'Failed to find leijun');
print('---All speakers---');
print(manager.allSpeakerNames);
print('------------');
const _testFiles = [
'assets/sr-data/test/fangjun-test-sr-1.wav',
'assets/sr-data/test/leijun-test-sr-1.wav',
'assets/sr-data/test/liudehua-test-sr-1.wav',
];
final testFiles = <String>[];
for (final f in _testFiles) {
testFiles.add(await copyAssetFile(src: f, dst: basename(f)));
}
const threshold = 0.6;
for (final f in testFiles) {
final embedding = computeEmbedding(extractor: extractor, filename: f);
var name = manager.search(embedding: embedding, threshold: threshold);
if (name == '') {
name = '<Unknown>';
}
print('${f}: ${name}');
}
ok = manager.verify(
name: 'fangjun',
embedding: computeEmbedding(extractor: extractor, filename: testFiles[0]),
threshold: threshold);
assert(ok, 'Failed to verify fangjun using ${testFiles[0]}');
ok = manager.remove('fangjun');
assert(ok, 'Failed to remove fangjun');
assert(manager.numSpeakers == 1, '${manager.numSpeakers}');
found = manager.contains('fangjun');
assert(!found, 'Still found fangjun!');
ok = manager.verify(
name: 'fangjun',
embedding: computeEmbedding(extractor: extractor, filename: testFiles[0]),
threshold: threshold);
assert(!ok, '${testFiles[0]}');
manager.free();
extractor.free();
}