-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathSpeechToTextManager.cs
More file actions
131 lines (120 loc) · 4.96 KB
/
SpeechToTextManager.cs
File metadata and controls
131 lines (120 loc) · 4.96 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
130
131
using NAudio.Wave;
using System.Diagnostics;
using System.Timers;
using Whisper.net;
using Whisper.net.Ggml;
namespace RoleplayingVoiceCore {
public class SpeechToTextManager {
private Stopwatch _timer = new Stopwatch();
private WaveInEvent _waveSource;
private MemoryStream _recordedAudioStream;
private WaveFileWriter _waveWriter;
private string _basePath;
private string _modelName;
private string _finalText;
int _retry;
private bool _isRecording;
private bool _rpMode;
public string FinalText { get => _finalText; set => _finalText = value; }
public bool IsRecording { get => _isRecording; set => _isRecording = value; }
public bool RpMode { get => _rpMode; set => _rpMode = value; }
public SpeechToTextManager(string path) {
_basePath = path;
_modelName = Path.Combine(path, "ggml-base.bin");
CheckForDependancies();
}
public async void CheckForDependancies() {
try {
if (!File.Exists(_modelName)) {
using var modelStream = await WhisperGgmlDownloader.GetGgmlModelAsync(GgmlType.Base);
using var fileWriter = File.OpenWrite(_modelName);
await modelStream.CopyToAsync(fileWriter);
}
} catch {
}
}
public event EventHandler<string> RecordingFinished;
/// <summary>
/// Record from the mic
/// </summary>
/// <param name="seconds">Duration in seconds</param>
/// <param name="filename">Output file name</param>
public void RecordAudio() {
_waveSource = new WaveInEvent {
WaveFormat = new WaveFormat(16000, 1),
};
_waveSource.DataAvailable += DataAvailable;
_waveSource.RecordingStopped += RecordingStopped;
_recordedAudioStream = new MemoryStream();
_waveWriter = new WaveFileWriter(_recordedAudioStream, _waveSource.WaveFormat);
_waveSource.StartRecording();
_isRecording = true;
}
/// <summary>
/// Callback executed when new data is available
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void DataAvailable(object sender, WaveInEventArgs e) {
if (_waveWriter != null) {
_waveWriter.Write(e.Buffer, 0, e.BytesRecorded);
int threshold = 500;
int value = Math.Abs(BitConverter.ToInt16(e.Buffer, (e.BytesRecorded - 2)));
if (value < threshold) {
if (!_timer.IsRunning) {
_timer.Start();
}
if (_timer.ElapsedMilliseconds > 1000) {
StopRecording();
}
} else {
_timer.Reset();
}
}
}
/// <summary>
/// Callback that will be executed once the recording duration has elapsed
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
public async void StopRecording() {
_waveSource?.StopRecording();
_waveWriter.Flush();
_waveSource.DataAvailable -= DataAvailable;
_waveSource.RecordingStopped -= RecordingStopped;
/*Stop the audio recording*/
if (File.Exists(_modelName)) {
try {
using var whisperFactory = WhisperFactory.FromPath(_modelName, false, _basePath + @"\runtimes\win-x64\whisper.dll");
using var processor = whisperFactory.CreateBuilder()
.WithLanguage("en")
.Build();
_finalText = "";
_recordedAudioStream.Position = 0;
await foreach (var result in processor.ProcessAsync(_recordedAudioStream)) {
Console.WriteLine($"{result.Start}->{result.End}: {result.Text}");
_finalText += result.Text.Replace("]", "[").Replace("(", "[").Replace(")", "[").Replace("*", "[").Split("[")[0];
break;
}
_finalText = FinalText.Trim();
/*Send notification that the recording is complete*/
RecordingFinished?.Invoke(this, _finalText);
} catch {
}
}
try {
_waveSource?.Dispose();
_waveWriter?.Dispose();
} catch { }
_timer.Reset();
_isRecording = false;
}
/// <summary>
/// Callback executed when the recording is stopped
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private async void RecordingStopped(object sender, StoppedEventArgs e) {
}
}
}