recognizer.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2021, Rein Appeldoorn
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17 
18 #include <cmath>
19 #include <boost/filesystem.hpp>
20 #include <chrono>
21 extern "C" {
22 #include <pv_recorder.h>
23 }
24 #include <sndfile.h>
25 #include <stdexcept>
26 #include <vector>
27 
28 #include "./recognizer.h"
29 
30 namespace picovoice_driver
31 {
32 std::string getEpochStamp()
33 {
34  using namespace std::chrono;
35  unsigned long ms_since_epoch = duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
36  unsigned long seconds_since_epoch = ms_since_epoch / 1e3;
37  unsigned long ms_decimals_since_epoch = ms_since_epoch - seconds_since_epoch * 1e3;
38  return std::to_string(seconds_since_epoch) + "." + std::to_string(ms_decimals_since_epoch);
39 }
40 
41 void writeWav(const std::vector<int16_t>& buffer, size_t buffer_size, size_t sample_rate, const std::string& directory)
42 {
43  boost::filesystem::create_directories(directory);
44  std::string filename = directory + "/recording-" + getEpochStamp() + ".wav";
45 
46  SF_INFO sfinfo;
47  sfinfo.channels = 1;
48  sfinfo.samplerate = sample_rate;
49  sfinfo.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16;
50  SNDFILE* outfile = sf_open(filename.c_str(), SFM_WRITE, &sfinfo);
51  if (outfile != nullptr)
52  {
53  sf_write_short(outfile, buffer.data(), buffer_size);
54  sf_write_sync(outfile);
55  sf_close(outfile);
56  }
57 }
58 
60 {
61  try
62  {
63  recognizeInit();
64  }
65  catch (const std::exception& e)
66  {
67  throw std::runtime_error("recognizeInit failed: " + std::string(e.what()));
68  }
69 
70  RecordSettings record_settings;
71  try
72  {
73  record_settings = getRecordSettings();
74  }
75  catch (const std::exception& e)
76  {
77  throw std::runtime_error("getRecordSettings failed: " + std::string(e.what()));
78  }
79 
80  pv_recorder_t* recorder = NULL;
81  pv_recorder_status_t recorder_status = pv_recorder_init(-1, record_settings.frame_length_, 100, true, &recorder);
82  if (recorder_status != PV_RECORDER_STATUS_SUCCESS)
83  {
84  throw std::runtime_error("Failed to initialize device with " +
85  std::string(pv_recorder_status_to_string(recorder_status)));
86  }
87 
88  recorder_status = pv_recorder_start(recorder);
89  if (recorder_status != PV_RECORDER_STATUS_SUCCESS)
90  {
91  pv_recorder_delete(recorder);
92  throw std::runtime_error("Failed to start device with " +
93  std::string(pv_recorder_status_to_string(recorder_status)));
94  }
95 
96  bool is_finalized = false;
97  size_t frame_index = 0;
98  size_t total_frames = std::ceil((record_timeout_ * record_settings.sample_rate_) / record_settings.frame_length_);
99  std::vector<int16_t> pcm(record_settings.frame_length_);
100  std::vector<int16_t> record_buffer(record_settings.frame_length_ * total_frames, 0);
101  while (frame_index < total_frames && !is_finalized && !preempt_requested_.load())
102  {
103  recorder_status = pv_recorder_read(recorder, pcm.data());
104  if (recorder_status != PV_RECORDER_STATUS_SUCCESS)
105  {
106  is_recognizing_.store(false);
107  pv_recorder_delete(recorder);
108  throw std::runtime_error("Failed to read with " + std::string(pv_recorder_status_to_string(recorder_status)));
109  }
110 
111  try
112  {
113  is_finalized = recognizeProcess(pcm.data());
114  }
115  catch (const std::exception& e)
116  {
117  is_recognizing_.store(false);
118  pv_recorder_delete(recorder);
119  throw std::runtime_error("recognizeProcess failed: " + std::string(e.what()));
120  }
121 
122  std::copy(pcm.begin(), pcm.end(), record_buffer.begin() + frame_index * pcm.size());
123  ++frame_index;
124  }
125 
126  recorder_status = pv_recorder_stop(recorder);
127  if (recorder_status != PV_RECORDER_STATUS_SUCCESS)
128  {
129  is_recognizing_.store(false);
130  pv_recorder_delete(recorder);
131  throw std::runtime_error("Failed to stop device with " +
132  std::string(pv_recorder_status_to_string(recorder_status)));
133  }
134 
135  if (!record_directory_.empty())
136  {
137  writeWav(record_buffer, frame_index * record_settings.frame_length_, record_settings.sample_rate_,
139  }
140 
141  pv_recorder_delete(recorder);
142  is_recognizing_.store(false);
143 }
144 
146 {
147  try
148  {
149  recognizeThread();
150  }
151  catch (const std::exception& e)
152  {
153  recognize_thread_exception_string_ = std::string(e.what());
154  }
155 }
156 
157 void Recognizer::initialize(const std::string& record_directory, double record_timeout)
158 {
159  record_directory_ = record_directory;
160  record_timeout_ = record_timeout;
161  initialized_ = true;
162 }
163 
165 {
166  if (!initialized_)
167  {
168  throw std::runtime_error("Recognizer not initialized");
169  }
170 
171  if (recognize_thread_ != nullptr)
172  {
173  throw std::runtime_error("Already recognizing");
174  }
176  is_recognizing_.store(true);
177  preempt_requested_.store(false);
178  recognize_thread_.reset(new std::thread(&Recognizer::recognizeThreadCatchException, this));
179 }
180 
182 {
183  if (!initialized_)
184  {
185  throw std::runtime_error("Recognizer not initialized");
186  }
187  preempt_requested_.store(true);
188 }
189 
191 {
192  if (!initialized_)
193  {
194  throw std::runtime_error("Recognizer not initialized");
195  }
196  return preempt_requested_.load();
197 }
198 
200 {
201  if (!initialized_)
202  {
203  throw std::runtime_error("Recognizer not initialized");
204  }
205  bool is_recognizing = is_recognizing_.load();
206  if (!is_recognizing)
207  {
208  recognize_thread_->join();
209  recognize_thread_.reset();
211  {
212  throw std::runtime_error("Recognize thread exception: " + recognize_thread_exception_string_);
213  }
214  }
215  return is_recognizing;
216 }
217 } // namespace picovoice_driver
NULL
#define NULL
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/extras/speex_resampler/thirdparty/resample.c:92
pv_recorder_delete
PV_API void pv_recorder_delete(pv_recorder_t *object)
Definition: porcupine/demo/c/pvrecorder/src/pv_recorder.c:162
picovoice_driver::Recognizer::recognizeThread
void recognizeThread()
Definition: recognizer.cpp:59
pv_recorder_init
PV_API pv_recorder_status_t pv_recorder_init(int32_t device_index, int32_t frame_length, int32_t buffer_size_msec, bool log_overflow, pv_recorder_t **object)
Definition: porcupine/demo/c/pvrecorder/src/pv_recorder.c:51
picovoice_driver::Recognizer::recognizeThreadCatchException
void recognizeThreadCatchException()
Definition: recognizer.cpp:145
recognizer.h
pv_recorder_read
PV_API pv_recorder_status_t pv_recorder_read(pv_recorder_t *object, int16_t *pcm)
Definition: porcupine/demo/c/pvrecorder/src/pv_recorder.c:213
picovoice_driver::Recognizer::isPreempting
bool isPreempting()
isPreempting Whether a preempt was requested
Definition: recognizer.cpp:190
picovoice_driver::Recognizer::recognize_thread_exception_string_
std::string recognize_thread_exception_string_
Definition: recognizer.h:83
picovoice_driver::Recognizer::recognize_thread_
std::shared_ptr< std::thread > recognize_thread_
Definition: recognizer.h:84
picovoice_driver::Recognizer::is_recognizing_
std::atomic< bool > is_recognizing_
Definition: recognizer.h:97
pv_recorder_stop
PV_API pv_recorder_status_t pv_recorder_stop(pv_recorder_t *object)
Definition: porcupine/demo/c/pvrecorder/src/pv_recorder.c:192
pv_recorder_status_t
pv_recorder_status_t
Definition: porcupine/demo/c/pvrecorder/include/pv_recorder.h:31
picovoice_driver::getEpochStamp
std::string getEpochStamp()
Definition: recognizer.cpp:32
picovoice_driver
Definition: porcupine_node.cpp:24
picovoice_driver::Recognizer::RecordSettings::frame_length_
size_t frame_length_
Definition: recognizer.h:80
pv_recorder
Definition: porcupine/demo/c/pvrecorder/src/pv_recorder.c:28
picovoice_driver::Recognizer::getRecordSettings
virtual RecordSettings getRecordSettings()=0
picovoice_driver::Recognizer::recognizeProcess
virtual bool recognizeProcess(int16_t *frames)=0
picovoice_driver::Recognizer::isRecognizing
bool isRecognizing()
isRecognizing Whether the recognize method is running
Definition: recognizer.cpp:199
picovoice_driver::Recognizer::initialized_
bool initialized_
Definition: recognizer.h:94
picovoice_driver::Recognizer::preempt
void preempt()
preempt Preempt the recognition
Definition: recognizer.cpp:181
picovoice_driver::Recognizer::preempt_requested_
std::atomic< bool > preempt_requested_
Definition: recognizer.h:96
picovoice_driver::Recognizer::RecordSettings::sample_rate_
size_t sample_rate_
Definition: recognizer.h:79
picovoice_driver::writeWav
void writeWav(const std::vector< int16_t > &buffer, size_t buffer_size, size_t sample_rate, const std::string &directory)
Definition: recognizer.cpp:41
picovoice_driver::Recognizer::recognize
void recognize()
recognize Recognize something from an audio input stream
Definition: recognizer.cpp:164
picovoice_driver::Recognizer::record_directory_
std::string record_directory_
Definition: recognizer.h:92
pv_recorder_status_to_string
const PV_API char * pv_recorder_status_to_string(pv_recorder_status_t status)
Definition: porcupine/demo/c/pvrecorder/src/pv_recorder.c:323
pv_recorder_start
PV_API pv_recorder_status_t pv_recorder_start(pv_recorder_t *object)
Definition: porcupine/demo/c/pvrecorder/src/pv_recorder.c:172
picovoice_driver::Recognizer::RecordSettings
Definition: recognizer.h:77
time_since_epoch
double time_since_epoch()
PV_RECORDER_STATUS_SUCCESS
@ PV_RECORDER_STATUS_SUCCESS
Definition: porcupine/demo/c/pvrecorder/include/pv_recorder.h:32
picovoice_driver::Recognizer::recognizeInit
virtual void recognizeInit()=0
picovoice_driver::Recognizer::record_timeout_
double record_timeout_
Definition: recognizer.h:93
picovoice_driver::Recognizer::initialize
void initialize(const std::string &record_directory, double record_timeout)
initialize Initialize the recognizer
Definition: recognizer.cpp:157


picovoice_driver
Author(s):
autogenerated on Fri Apr 1 2022 02:14:50