snowboy_ros
demo.cc
Go to the documentation of this file.
1 // example/C++/demo.cc
2 
3 // Copyright 2016 KITT.AI (author: Guoguo Chen)
4 
5 #include <cassert>
6 #include <csignal>
7 #include <iostream>
8 #include <pa_ringbuffer.h>
9 #include <pa_util.h>
10 #include <portaudio.h>
11 #include <string>
12 #include <vector>
13 
14 #include "include/snowboy-detect.h"
15 
16 int PortAudioCallback(const void* input,
17  void* output,
18  unsigned long frame_count,
19  const PaStreamCallbackTimeInfo* time_info,
20  PaStreamCallbackFlags status_flags,
21  void* user_data);
22 
24  public:
25  // Constructor.
26  PortAudioWrapper(int sample_rate, int num_channels, int bits_per_sample) {
28  min_read_samples_ = sample_rate * 0.1;
29  Init(sample_rate, num_channels, bits_per_sample);
30  }
31 
32  // Reads data from ring buffer.
33  template<typename T>
35  assert(data != NULL);
36 
37  // Checks ring buffer overflow.
38  if (num_lost_samples_ > 0) {
39  std::cerr << "Lost " << num_lost_samples_ << " samples due to ring"
40  << " buffer overflow." << std::endl;
42  }
43 
44  ring_buffer_size_t num_available_samples = 0;
45  while (true) {
46  num_available_samples =
47  PaUtil_GetRingBufferReadAvailable(&pa_ringbuffer_);
48  if (num_available_samples >= min_read_samples_) {
49  break;
50  }
51  Pa_Sleep(5);
52  }
53 
54  // Reads data.
55  num_available_samples = PaUtil_GetRingBufferReadAvailable(&pa_ringbuffer_);
56  data->resize(num_available_samples);
57  ring_buffer_size_t num_read_samples = PaUtil_ReadRingBuffer(
58  &pa_ringbuffer_, data->data(), num_available_samples);
59  if (num_read_samples != num_available_samples) {
60  std::cerr << num_available_samples << " samples were available, but "
61  << "only " << num_read_samples << " samples were read." << std::endl;
62  }
63  }
64 
65  int Callback(const void* input, void* output,
66  unsigned long frame_count,
67  const PaStreamCallbackTimeInfo* time_info,
68  PaStreamCallbackFlags status_flags) {
69  // Input audio.
70  ring_buffer_size_t num_written_samples =
71  PaUtil_WriteRingBuffer(&pa_ringbuffer_, input, frame_count);
72  num_lost_samples_ += frame_count - num_written_samples;
73  return paContinue;
74  }
75 
77  Pa_StopStream(pa_stream_);
78  Pa_CloseStream(pa_stream_);
79  Pa_Terminate();
80  PaUtil_FreeMemory(ringbuffer_);
81  }
82 
83  private:
84  // Initialization.
85  bool Init(int sample_rate, int num_channels, int bits_per_sample) {
86  // Allocates ring buffer memory.
87  int ringbuffer_size = 16384;
88  ringbuffer_ = static_cast<char*>(
89  PaUtil_AllocateMemory(bits_per_sample / 8 * ringbuffer_size));
90  if (ringbuffer_ == NULL) {
91  std::cerr << "Fail to allocate memory for ring buffer." << std::endl;
92  return false;
93  }
94 
95  // Initializes PortAudio ring buffer.
96  ring_buffer_size_t rb_init_ans =
97  PaUtil_InitializeRingBuffer(&pa_ringbuffer_, bits_per_sample / 8,
98  ringbuffer_size, ringbuffer_);
99  if (rb_init_ans == -1) {
100  std::cerr << "Ring buffer size is not power of 2." << std::endl;
101  return false;
102  }
103 
104  // Initializes PortAudio.
105  PaError pa_init_ans = Pa_Initialize();
106  if (pa_init_ans != paNoError) {
107  std::cerr << "Fail to initialize PortAudio, error message is \""
108  << Pa_GetErrorText(pa_init_ans) << "\"" << std::endl;
109  return false;
110  }
111 
112  PaError pa_open_ans;
113  if (bits_per_sample == 8) {
114  pa_open_ans = Pa_OpenDefaultStream(
115  &pa_stream_, num_channels, 0, paUInt8, sample_rate,
116  paFramesPerBufferUnspecified, PortAudioCallback, this);
117  } else if (bits_per_sample == 16) {
118  pa_open_ans = Pa_OpenDefaultStream(
119  &pa_stream_, num_channels, 0, paInt16, sample_rate,
120  paFramesPerBufferUnspecified, PortAudioCallback, this);
121  } else if (bits_per_sample == 32) {
122  pa_open_ans = Pa_OpenDefaultStream(
123  &pa_stream_, num_channels, 0, paInt32, sample_rate,
124  paFramesPerBufferUnspecified, PortAudioCallback, this);
125  } else {
126  std::cerr << "Unsupported BitsPerSample: " << bits_per_sample
127  << std::endl;
128  return false;
129  }
130  if (pa_open_ans != paNoError) {
131  std::cerr << "Fail to open PortAudio stream, error message is \""
132  << Pa_GetErrorText(pa_open_ans) << "\"" << std::endl;
133  return false;
134  }
135 
136  PaError pa_stream_start_ans = Pa_StartStream(pa_stream_);
137  if (pa_stream_start_ans != paNoError) {
138  std::cerr << "Fail to start PortAudio stream, error message is \""
139  << Pa_GetErrorText(pa_stream_start_ans) << "\"" << std::endl;
140  return false;
141  }
142  return true;
143  }
144 
145  private:
146  // Pointer to the ring buffer memory.
147  char* ringbuffer_;
148 
149  // Ring buffer wrapper used in PortAudio.
150  PaUtilRingBuffer pa_ringbuffer_;
151 
152  // Pointer to PortAudio stream.
153  PaStream* pa_stream_;
154 
155  // Number of lost samples at each Read() due to ring buffer overflow.
157 
158  // Wait for this number of samples in each Read() call.
160 };
161 
162 int PortAudioCallback(const void* input,
163  void* output,
164  unsigned long frame_count,
165  const PaStreamCallbackTimeInfo* time_info,
166  PaStreamCallbackFlags status_flags,
167  void* user_data) {
168  PortAudioWrapper* pa_wrapper = reinterpret_cast<PortAudioWrapper*>(user_data);
169  pa_wrapper->Callback(input, output, frame_count, time_info, status_flags);
170  return paContinue;
171 }
172 
173 void SignalHandler(int signal){
174  std::cerr << "Caught signal " << signal << ", terminating..." << std::endl;
175  exit(0);
176 }
177 
178 int main(int argc, char* argv[]) {
179  std::string usage =
180  "Example that shows how to use Snowboy in C++. Parameters are\n"
181  "hard-coded in the parameter section. Please check the source code for\n"
182  "more details. Audio is captured by PortAudio.\n"
183  "\n"
184  "To run the example:\n"
185  " ./demo\n";
186 
187  // Checks the command.
188  if (argc > 1) {
189  std::cerr << usage;
190  exit(1);
191  }
192 
193  // Configures signal handling.
194  struct sigaction sig_int_handler;
195  sig_int_handler.sa_handler = SignalHandler;
196  sigemptyset(&sig_int_handler.sa_mask);
197  sig_int_handler.sa_flags = 0;
198  sigaction(SIGINT, &sig_int_handler, NULL);
199 
200  // Parameter section.
201  // If you have multiple hotword models (e.g., 2), you should set
202  // <model_filename> and <sensitivity_str> as follows:
203  // model_filename = "resources/snowboy.umdl,resources/alexa.pmdl";
204  // sensitivity_str = "0.4,0.4";
205  std::string resource_filename = "resources/common.res";
206  std::string model_filename = "resources/snowboy.umdl";
207  std::string sensitivity_str = "0.5";
208  float audio_gain = 1;
209 
210  // Initializes Snowboy detector.
211  snowboy::SnowboyDetect detector(resource_filename, model_filename);
212  detector.SetSensitivity(sensitivity_str);
213  detector.SetAudioGain(audio_gain);
214 
215  // Initializes PortAudio. You may use other tools to capture the audio.
216  PortAudioWrapper pa_wrapper(detector.SampleRate(),
217  detector.NumChannels(), detector.BitsPerSample());
218 
219  // Runs the detection.
220  // Note: I hard-coded <int16_t> as data type because detector.BitsPerSample()
221  // returns 16.
222  std::cout << "Listening... Press Ctrl+C to exit" << std::endl;
224  while (true) {
225  pa_wrapper.Read(&data);
226  if (data.size() != 0) {
227  int result = detector.RunDetection(data.data(), data.size());
228  if (result > 0) {
229  std::cout << "Hotword " << result << " detected!" << std::endl;
230  }
231  }
232  }
233 
234  return 0;
235 }
snowboy-detect.h
std::string
vector
SignalHandler
void SignalHandler(int signal)
Definition: demo.cc:173
PortAudioCallback
int PortAudioCallback(const void *input, void *output, unsigned long frame_count, const PaStreamCallbackTimeInfo *time_info, PaStreamCallbackFlags status_flags, void *user_data)
Definition: demo.cc:162
std::cerr
main
int main(int argc, char *argv[])
Definition: demo.cc:178
PortAudioWrapper::pa_ringbuffer_
PaUtilRingBuffer pa_ringbuffer_
Definition: demo.cc:150
iostream
PortAudioWrapper::min_read_samples_
int min_read_samples_
Definition: demo.cc:159
PortAudioWrapper::PortAudioWrapper
PortAudioWrapper(int sample_rate, int num_channels, int bits_per_sample)
Definition: demo.cc:26
std::cout
training_service.data
dictionary data
END OF MODIFY ##################.
Definition: training_service.py:31
PortAudioWrapper::Callback
int Callback(const void *input, void *output, unsigned long frame_count, const PaStreamCallbackTimeInfo *time_info, PaStreamCallbackFlags status_flags)
Definition: demo.cc:65
PortAudioWrapper::num_lost_samples_
int num_lost_samples_
Definition: demo.cc:156
csignal
PortAudioWrapper::~PortAudioWrapper
~PortAudioWrapper()
Definition: demo.cc:76
PortAudioWrapper
Definition: demo.cc:23
std::endl
T endl(T... args)
PortAudioWrapper::Read
void Read(std::vector< T > *data)
Definition: demo.cc:34
cassert
demo.detector
detector
Definition: demo.py:27
snowboy::SnowboyDetect
Definition: snowboy-detect.h:22
PortAudioWrapper::ringbuffer_
char * ringbuffer_
Definition: demo.cc:147
PortAudioWrapper::Init
bool Init(int sample_rate, int num_channels, int bits_per_sample)
Definition: demo.cc:85
PortAudioWrapper::pa_stream_
PaStream * pa_stream_
Definition: demo.cc:153
string