Nsound  0.9.4
AudioPlaybackRt.cc
Go to the documentation of this file.
1 //-----------------------------------------------------------------------------
2 //
3 // $Id: AudioPlaybackRt.cc 897 2015-06-07 17:43:34Z weegreenblobbie $
4 //
5 // Copyright (c) 2005-2006 Nick Hilton
6 //
7 // weegreenblobbie_yahoo_com (replace '_' with '@' and '.')
8 //
9 //-----------------------------------------------------------------------------
10 
11 //-----------------------------------------------------------------------------
12 //
13 // This program is free software; you can redistribute it and/or modify
14 // it under the terms of the GNU General Public License as published by
15 // the Free Software Foundation; either version 2 of the License, or
16 // (at your option) any later version.
17 //
18 // This program is distributed in the hope that it will be useful,
19 // but WITHOUT ANY WARRANTY; without even the implied warranty of
20 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 // GNU Library General Public License for more details.
22 //
23 // You should have received a copy of the GNU General Public License
24 // along with this program; if not, write to the Free Software
25 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
26 //
27 //-----------------------------------------------------------------------------
28 //
29 // Some PortAudio notes:
30 //
31 // A "frame" consists of all the samples for a given time step. If you have
32 // stereo audio, then frames 0 and 1 will contain:
33 // frame 0 [left_sample_0, right_sample0]
34 // frame 1 [left_sample_1, right_sample1]
35 // ...
36 //
37 // The data above might contain 4 samples, but only 2 frames, or 2 samples in
38 // time.
39 //
40 //-----------------------------------------------------------------------------
41 
42 #include <Nsound/Nsound.h>
43 
44 #include <Nsound/AudioPlaybackRt.h>
45 #include <Nsound/AudioStream.h>
46 #include <Nsound/Buffer.h>
48 #include <Nsound/Sine.h>
49 #include <Nsound/Wavefile.h>
50 
51 #include <cstring> // for memset
52 #include <limits>
53 
54 #ifdef NSOUND_CPP11
55  #include <atomic>
56  #include <thread>
57 #endif
58 
59 using std::cerr;
60 using std::cout;
61 using std::endl;
62 
63 namespace Nsound
64 {
65 
66 bool AudioPlaybackRt::use_jack_ = false;
67 
68 //-----------------------------------------------------------------------------
69 // stub out class if we don't have portaudio or c++11
70 
71 #if !defined(NSOUND_LIBPORTAUDIO) || !defined(NSOUND_CPP11)
72 
74  {
75  M_THROW("Nsound was not compiled with portaudio.");
76  }
77 
80  std::string AudioPlaybackRt::getInfo() { return "nsound was compiled without rt playback"; }
82  void AudioPlaybackRt::play(const Buffer &) {}
86  std::string AudioPlaybackRt::debug_print() { return "nsound was compiled without rt playback"; }
87 
89 
90 
91 //-----------------------------------------------------------------------------
92 // Real class implementation with c++11
93 
94 #else
95 
96 void my_atomic_init(std::atomic_uint & a, unsigned int v)
97 {
98  // Windows
99  #ifdef __WIN32__
100  std::atomic_init(&a, v);
101  #else
102  a = v;
103  #endif
104 }
105 
108  float64 sample_rate,
109  uint32 channels,
110  uint32 n_buffers,
111  float64 buffer_size_sec)
112  :
113  sample_rate_(sample_rate),
114  channels_(channels),
115  underrun_mode_(BUM_SILENCE),
116  underrun_count_(0),
117  overrun_count_(0),
118  unknown_error_count_(0),
119  stop_error_count_(0),
120  pa_underrun_count_(0),
121  pa_overrun_count_(0),
122  n_history_(),
123  sine_(new Sine(sample_rate)),
124  pool_(),
125  pool_size_(n_buffers),
126  pool_begin_(),
127  pool_end_(),
128  n_ready_(),
129  rd_ptr_(),
130  wr_ptr_(),
131  wr_index_(0),
132  driver_(),
133  actual_latency_sec_(0)
134 {
135  M_ASSERT_VALUE(channels_, >, 0);
136  M_ASSERT_VALUE(channels_, <=, 2);
137  M_ASSERT_VALUE(n_buffers, >=, 2);
138 
139  my_atomic_init(n_ready_, 0u);
140 
141  n_history_.reserve(16);
142 
143 //~ std::cerr << "lock free? " << n_ready_.is_lock_free() << "\n";
144 
145  PaError ecode = Pa_Initialize();
146 
147  if(ecode != paNoError)
148  {
149  M_THROW(
150  "Nsound::AudioPlaybackRt"
151  << ": Pa_Initialize() failed"
152  << endl
153  << Pa_GetErrorText(ecode));
154  }
155 
156  // Allocate params object
158 
159  std::memset(driver_.out_params_, 0, sizeof(PaStreamParameters));
160 
161  // Try to get the JACK Audio Connection Ket Host API if available.
162 
163  PaHostApiIndex api_index = -1;
164 
165  if(use_jack_)
166  {
167  api_index = Pa_HostApiTypeIdToHostApiIndex(paJACK);
168  }
169  else
170  {
171  api_index = Pa_GetDefaultHostApi();
172  }
173 
174  if(api_index < 0)
175  {
176  Pa_Terminate();
177 
178  if(use_jack_)
179  {
180  M_THROW(
181  "Nsound::AudioPlaybackRt"
182  << ": could not find JACK host api! "
183  "Is the JACK server running?");
184  }
185  else
186  {
187  M_THROW(
188  "Nsound::AudioPlaybackRt"
189  << ": could not find host api to use!");
190  }
191  }
192 
193  driver_.host_api_ = api_index;
194 
195  const PaHostApiInfo * info = Pa_GetHostApiInfo(driver_.host_api_);
196 
197  if(info == nullptr)
198  {
199  Pa_Terminate();
200 
201  M_THROW(
202  "Nsound::AudioPlaybackRt"
203  << ": Pa_GetHostApiInfo() failed"
204  << endl);
205  }
206 
207  driver_.host_api_str_ = std::string(info->name);
208 
209  // Get the default ouput device
210 
211  driver_.out_params_->device = info->defaultOutputDevice;
212 
213  if(driver_.out_params_->device == paNoDevice)
214  {
215  Pa_Terminate();
216  delete driver_.out_params_;
217  driver_.out_params_ = nullptr;
218 
219  M_THROW(
220  "Nsound::AudioPlaybackRt"
221  << ": failed to get default output device!");
222  }
223 
224  // use default low output latency if unspecified by user.
225  if(buffer_size_sec <= 0.0)
226  {
227  const PaDeviceInfo * dinfo = Pa_GetDeviceInfo(
228  driver_.out_params_->device);
229 
230  if(dinfo == nullptr)
231  {
232  Pa_Terminate();
233 
234  M_THROW(
235  "Nsound::AudioPlaybackRt"
236  << ": Pa_GetDeviceInfo() failed\n");
237  }
238 
239  buffer_size_sec = dinfo->defaultLowOutputLatency;
240  }
241 
242  driver_.out_params_->channelCount = channels_;
243  driver_.out_params_->sampleFormat = paInt16;
244  driver_.out_params_->suggestedLatency = buffer_size_sec;
245  driver_.out_params_->hostApiSpecificStreamInfo = nullptr;
246 
247  //-------------------------------------------------------------------------
248  // Allocate circular buffers.
249 
250  driver_.n_frames_per_buffer_ = static_cast<uint32>(
251  buffer_size_sec * sample_rate_);
252 
254 
256  {
257  Pa_Terminate();
258 
259  M_THROW(
260  "Nsound::AudioPlaybackRt"
261  << ": n_frames_per_buffer_ < 16"
262  << endl);
263  }
264 
265  for(uint32 i = 0; i < n_buffers; ++i)
266  {
268  pool_.push_back(buf);
269  }
270 
271  pool_begin_ = pool_.begin();
272  pool_end_ = pool_.end();
273 
276 
277  //-------------------------------------------------------------------------
278  // Check if format is supported.
279 
280  ecode = Pa_IsFormatSupported(nullptr, driver_.out_params_, sample_rate_);
281 
282  if(ecode != paNoError)
283  {
284  Pa_Terminate();
285 
286  M_THROW(
287  "Nsound::AudioPlaybackRt"
288  << ": Pa_IsFormatSupported() failed ("
289  << sample_rate_
290  << " sample rate, paInt16, "
291  << channels_ << " channel(s))"
292  << endl
293  << Pa_GetErrorText(ecode));
294  }
295 
296  //-------------------------------------------------------------------------
297  // Open the stream.
298 
299  ecode = Pa_OpenStream(
300  &driver_.stream_,
301  nullptr, // no input channel
303  sample_rate_,
305  paClipOff | paDitherOff,
307  reinterpret_cast<void *>(this));
308 
309  if(ecode != paNoError)
310  {
311  Pa_Terminate();
312 
313  M_THROW(
314  "Nsound::AudioPlaybackRt:"
315  << __LINE__
316  << ": Pa_OpenStream() failed"
317  << endl
318  << Pa_GetErrorText(ecode));
319  }
320 
321  // Grab output latencey.
322  const PaStreamInfo * sinfo = Pa_GetStreamInfo(driver_.stream_);
323 
324  if(sinfo == nullptr)
325  {
326  Pa_Terminate();
327 
328  M_THROW(
329  "Nsound::AudioPlaybackRt"
330  << ": Pa_GetStreamInfo() failed"
331  << endl
332  << Pa_GetErrorText(ecode));
333  }
334 
335  actual_latency_sec_ = sinfo->outputLatency;
336 }
337 
340 {
341  stop();
342 
343  PaError ecode = paNoError;
344 
345  if(driver_.stream_)
346  {
347  ecode = Pa_CloseStream(driver_.stream_);
348 
349  driver_.stream_ = nullptr;
350 
351  delete driver_.out_params_;
352  driver_.out_params_ = nullptr;
353  }
354 
355  delete sine_;
356 
357  if(ecode != paNoError)
358  {
359  Pa_Terminate();
360 
361  M_THROW(
362  "Nsound::AudioPlaybackRt"
363  << ": Pa_CloseStream() failed"
364  << endl
365  << Pa_GetErrorText(ecode));
366  }
367 
368  ecode = Pa_Terminate();
369 
370  if(ecode != paNoError)
371  {
372  M_THROW(
373  "Nsound::AudioPlaybackRt"
374  << ": Pa_Terminate() failed"
375  << endl
376  << Pa_GetErrorText(ecode));
377  }
378 }
379 
380 int
383  const void * input,
384  void * output,
385  unsigned long frame_count,
386  const PaStreamCallbackTimeInfo * time_info,
387  PaStreamCallbackFlags status_flags,
388  void * ap_obj )
389 {
390  return reinterpret_cast<AudioPlaybackRt *>(ap_obj)->_callback(
391  input, output, frame_count, time_info, status_flags);
392 }
393 
394 #define SCALE static_cast<float64>(std::numeric_limits<int16>::max())
395 
396 int
398 _callback(
399  const void * input,
400  void * output,
401  const uint32 frames_per_buffer,
402  const PaStreamCallbackTimeInfo * time_info,
403  PaStreamCallbackFlags status_flags)
404 {
405  if(frames_per_buffer != driver_.n_frames_per_buffer_) ++unknown_error_count_;
406 
407  int16 * dst_ptr = reinterpret_cast<int16 *>(output);
408 
409  uint32 n = n_ready_.load();
410 
411 //~ DEBUG
412 //~ if(n_history_.size() < n_history_.capacity()) n_history_.push_back(n);
413 
415 
416  int16 * src = (*rd_ptr_)->data();
417 
418  // No underrun
419  if(n > 0)
420  {
421  for(uint32 i = 0; i < driver_.n_samples_per_buffer_; ++i)
422  {
423  dst_ptr[i] = src[i];
424  }
425 
426  n_ready_.fetch_sub(1);
427 
428  ++rd_ptr_;
429 
430  if(rd_ptr_ == pool_end_)
431  {
433  }
434  }
435 
436  // Oops, underrun!
437  else
438  {
439  ++underrun_count_;
440 
441  switch(bum)
442  {
443  case BUM_SILENCE:
444  {
445  for(uint32 i = 0; i < driver_.n_samples_per_buffer_; ++i)
446  {
447  dst_ptr[i] = 0;
448  }
449 
450  break;
451  }
452 
453  case BUM_NOISE:
454  {
455  RandomNumberGenerator & rng = sine_->getRandomNumberGenerator();
456 
457  for(uint32 i = 0; i < driver_.n_samples_per_buffer_; ++i)
458  {
459  float64 sample = SCALE * rng.get(-0.666, 0.666);
460  dst_ptr[i] = static_cast<int16>(sample);
461  }
462 
463  break;
464  }
465 
466  case BUM_TONE:
467  {
468  float64 tone = 440.0;
469 
470  uint32 i = 0;
471 
472  while(i < driver_.n_frames_per_buffer_)
473  {
474  float64 s = SCALE * 0.666 * sine_->generate(tone);
475 
476  int16 sample = static_cast<int16>(s);
477 
478  for(uint32 j = 0; j < channels_; ++j)
479  {
480  dst_ptr[i++] = sample;
481  }
482  }
483  }
484  }
485  }
486 
487  if(status_flags & paOutputUnderflow)
488  {
490  }
491 
492  if(status_flags & paOutputOverflow)
493  {
495  }
496 
497  return paContinue;
498 }
499 
500 void
502 _start()
503 {
504  if(0 == Pa_IsStreamStopped(driver_.stream_)) return;
505 
506  n_history_.clear();
507 
508  PaError ecode = Pa_StartStream( driver_.stream_ );
509 
510  if(ecode != paNoError)
511  {
512  Pa_Terminate();
513 
514  M_THROW(
515  "Nsound::AudioPlaybackRt"
516  << ": Pa_StartStream() failed"
517  << endl
518  << Pa_GetErrorText(ecode));
519  }
520 }
521 
522 void
524 stop()
525 {
526  if(Pa_IsStreamStopped(driver_.stream_)) return;
527 
528  PaError ecode = Pa_StopStream(driver_.stream_);
529 
530  if(ecode != paNoError)
531  {
533  M_THROW(
534  "Nsound::AudioPlaybackRt"
535  << ": Pa_StopStream() failed"
536  << endl
537  << Pa_GetErrorText(ecode));
538  }
539 
540  // zero out buffers, reset read/write pointers.
541 
542  n_ready_ = wr_index_ = 0;
544 
545  for(size_t i = 0; i < pool_.size(); ++i)
546  {
547  Int16Vector & vec = *pool_[i];
548  std::fill(vec.begin(), vec.end(), 0);
549  }
550 }
551 
552 void
555 {
556  M_ASSERT_VALUE(1, ==, Pa_IsStreamStopped(driver_.stream_));
557  underrun_mode_ = bum;
558 }
559 
560 void
562 play(const AudioStream & as)
563 {
564  M_ASSERT_VALUE(as.getNChannels(), <=, 2);
565 
566  uint32 sr1 = static_cast<uint32>(as.getSampleRate());
567  uint32 sr2 = static_cast<uint32>(sample_rate_);
568 
569  if(sr1 != sr2)
570  {
571  std::cerr
572  << "\nWARNING: AudioStream sample_rate != AudioPlaybackRt "
573  << "sample_rate ("
574  << sr1
575  << " != "
576  << sr2
577  << ")\n";
578  }
579 
580  if(as.getNChannels() == 1)
581  {
582  play(as[0]);
583  return;
584  }
585 
586  M_ASSERT_VALUE(as[0].getLength(), ==, as[1].getLength());
587 
588  for(uint32 i = 0; i < as.getLength(); ++i)
589  {
590  play(as[0][i], as[1][i]);
591  }
592 
593 }
594 
595 void
597 play(const Buffer & b)
598 {
599  for(auto & s : b)
600  {
601  play(s);
602  }
603 }
604 
605 void
607 play(float64 sample)
608 {
609  if(channels_ == 2)
610  {
611  return play(sample, sample);
612  }
613 
614  Int16Vector * ptr = *wr_ptr_;
615 
617 
618  M_ASSERT_VALUE(sample, <, 1.0);
619  M_ASSERT_VALUE(sample, >, -1.0);
620 
621  (*ptr)[wr_index_++] = static_cast<int16>(SCALE * sample);
622 
623  // limit check, block until next buffer is available.
625  {
626  uint32 n = n_ready_.load();
627 
628  if(n == pool_size_)
629  {
630  _start();
631  }
632 
633  while(n == pool_size_)
634  {
635  ++overrun_count_;
636  std::this_thread::yield();
637  n = n_ready_.load();
638  }
639 
640  n_ready_.fetch_add(1);
641 
642  wr_index_ = 0;
643 
644  ++wr_ptr_;
645 
646  if(wr_ptr_ == pool_end_)
647  {
649  }
650  }
651 }
652 
653 void
655 play(float64 left, float64 right)
656 {
657  Int16Vector * ptr = *wr_ptr_;
658 
660 
661  (*ptr)[wr_index_++] = static_cast<int16>(SCALE * left);
662  (*ptr)[wr_index_++] = static_cast<int16>(SCALE * right);
663 
664  // limit check, block until next buffer is available.
666  {
667  uint32 n = n_ready_.load();
668 
669  if(n == pool_size_)
670  {
671  _start();
672  }
673 
674  while(n == pool_size_)
675  {
676  ++overrun_count_;
677  std::this_thread::yield();
678  n = n_ready_.load();
679  }
680 
681  n_ready_.fetch_add(1);
682 
683  wr_index_ = 0;
684 
685  ++wr_ptr_;
686 
687  if(wr_ptr_ == pool_end_)
688  {
690  }
691  }
692 }
693 
694 std::string
696 getInfo()
697 {
698  const PaDeviceInfo * info = nullptr;
699 
700  info = Pa_GetDeviceInfo(driver_.out_params_->device);
701 
702  if(info == nullptr)
703  {
704  M_THROW("Nsound::AudioPlaybackRt::getInfo():"
705  << ": Pa_GetDeviceInfo() failed\n");
706 
707  return "";
708  }
709 
710  std::stringstream ss;
711 
712  ss << "libportaudio Default Driver Info:" << endl
713  << " deviceCount: " << Pa_GetDeviceCount() << endl
714  << " structVersion: " << info->structVersion << endl
715  << " name: " << info->name << endl
716  << " hostApi(index): " << info->hostApi << endl
717  << " maxInputChannels: " << info->maxInputChannels << endl
718  << " maxOutputChannels: " << info->maxOutputChannels << endl
719  << " defaultLowInputLatency: " << info->defaultLowInputLatency << endl
720  << " defaultHighInputLatency: " << info->defaultHighInputLatency << endl
721  << " defaultLowOutputLatency: " << info->defaultLowOutputLatency << endl
722  << " defaultHighOutputLatency: " << info->defaultHighOutputLatency << endl
723  << " defaultSampleRate: " << info->defaultSampleRate << endl;
724 
725  const PaHostApiInfo * api_info = nullptr;
726 
727  api_info = Pa_GetHostApiInfo(info->hostApi);
728 
729  if(info == nullptr)
730  {
731  M_THROW("Nsound::AudioPlaybackRt::getInfo():"
732  << ": Pa_GetHostApiInfo() failed\n");
733  return ss.str();
734  }
735 
736  ss << "libportaudio Default Host API Info:" << endl
737  << " structVersion: " << api_info->structVersion << endl
738  << " name: " << api_info->name << endl
739  << " deviceCount: " << api_info->deviceCount << endl
740  << " defaultInputDevice: " << api_info->defaultInputDevice << endl
741  << " defaultOutputDevice: " << api_info->defaultOutputDevice << endl;
742 
743  return ss.str();
744 }
745 
746 std::string
748 debug_print()
749 {
750  std::stringstream ss;
751 
752  ss
753  << "AudioPlaybackRt:\n"
754  << " sample_rate_ = " << sample_rate_ << "\n"
755  << " channels_ = " << channels_ << "\n"
756  << " pool_size_ = " << pool_size_ << "\n"
757  << " n_ready_ = " << n_ready_.load() << "\n"
758  << " wr_index_ = " << wr_index_ << "\n"
759  << " underrun_count_ = " << underrun_count_ << "\n"
760  << " overrun_count_ = " << overrun_count_ << "\n"
761  << " unknown_error_count_ = " << unknown_error_count_ << "\n"
762  << " stop_error_count_ = " << stop_error_count_ << "\n"
763  << " pa_underrun_count_ = " << pa_underrun_count_ << "\n"
764  << " pa_overrun_count_ = " << pa_overrun_count_ << "\n"
765  << " driver_.n_frames_per_buffer_ = "
766  << driver_.n_frames_per_buffer_ << "\n"
767  << " driver_.n_samples_per_buffer_ = "
768  << driver_.n_samples_per_buffer_ << "\n";
769 
770  if(driver_.out_params_)
771  {
772  ss
773  << " driver_.out_params_->suggestedLatency = "
774  << driver_.out_params_->suggestedLatency << "\n";
775  }
776 
777  if(driver_.stream_)
778  {
779  const PaStreamInfo * sinfo = Pa_GetStreamInfo(driver_.stream_);
780 
781  M_CHECK_PTR(sinfo);
782 
783  ss
784  << " actual samplerate = " << sinfo->sampleRate << "\n"
785  << " actual output latency = " << sinfo->outputLatency << "\n";
786  }
787 
788  ss
789  << " PortAudio Device Driver Info:\n"
790  << " Host API: " << driver_.host_api_str_ << "\n";
791 
792  const PaDeviceInfo * info = Pa_GetDeviceInfo(driver_.out_params_->device);
793 
794  if(info == nullptr)
795  {
796  ss << " Pa_GetDeviceInfo() failed!\n";
797  }
798  else
799  {
800  ss
801  << " Name: " << info->name << "\n"
802  << " maxOutputChannels: " << info->maxOutputChannels << "\n"
803  << " defaultSampleRate: " << info->defaultSampleRate << "\n"
804  << " defaultLowOutputLatency: " << info->defaultLowOutputLatency << "\n"
805  << " defaultHighOutputLatency: " << info->defaultHighOutputLatency << "\n";
806  }
807 
808  return ss.str();
809 }
810 
811 
812 AudioPlaybackRtDebug
814 get_debug_info() const
815 {
816  AudioPlaybackRtDebug info;
817 
819  info.overrun_count = overrun_count_;
820  info.underrun_count = underrun_count_;
821  info.pa_overrun_count = pa_overrun_count_;
822  info.pa_underrun_count = pa_underrun_count_;
823  info.pool_size = static_cast<uint32>(pool_.size());
824  info.n_ready = n_ready_.load();
825  info.wr_index = wr_index_;
826  info.n_history = n_history_;
827 
828  info.wr_ptr = 0;
829 
830  Int16Vector * ptr_wr = *wr_ptr_;
831  Int16Vector * ptr_rd = *rd_ptr_;
832 
833  for(auto itor : pool_)
834  {
835  if(itor == ptr_wr) break;
836 
837  ++info.wr_ptr;
838  }
839 
840  info.rd_ptr = 0;
841 
842  for(const auto & itor : pool_)
843  {
844  if(itor == ptr_rd) break;
845 
846  ++info.rd_ptr;
847  }
848 
849  const PaStreamInfo * sinfo = Pa_GetStreamInfo(driver_.stream_);
850 
851  if(sinfo)
852  {
853  info.samplerate = sinfo->sampleRate;
854  }
855  else
856  {
857  info.samplerate = -1.0;
858  }
859 
860  info.samples_per_buffer = driver_.n_samples_per_buffer_;
861 
862  info.is_streaming = 1 == Pa_IsStreamActive(driver_.stream_);
863 
864  return info;
865 }
866 
867 #endif
868 //
869 //-----------------------------------------------------------------------------
870 
871 void
873 {
874  rhs.play(lhs);
875 }
876 
877 void
878 operator>>(const Buffer & lhs, AudioPlaybackRt & rhs)
879 {
880  rhs.play(lhs);
881 }
882 
883 void
885 {
886  rhs.play(sample);
887 }
888 
889 std::string
891 __str__() const
892 {
893  std::stringstream ss;
894 
895  ss
896  << "AudioPlaybackRtDebug:\n"
897  << " unknown_error_count = " << unknown_error_count << "\n"
898  << " overrun_count = " << overrun_count << "\n"
899  << " underrun_count = " << underrun_count << "\n"
900  << " pa_overrun_count = " << pa_overrun_count << "\n"
901  << " pa_underrun_count = " << pa_underrun_count << "\n"
902  << " pool_size = " << pool_size << "\n"
903  << " n_ready = " << n_ready << "\n"
904  << " wr_index = " << wr_index << "\n"
905  << " wr_ptr = " << wr_ptr << "\n"
906  << " rd_ptr = " << rd_ptr << "\n"
907  << " sampleRate = " << samplerate << "\n"
908  << " samples_per_buffer = " << samples_per_buffer << "\n"
909  << " is_streaming = ";
910 
911  if(is_streaming) ss << "yes\n";
912  else ss << "no\n";
913 
914  ss << " n_history:\n";
915 
916  for(uint32 n : n_history)
917  {
918  ss << " " << n << "\n";
919  }
920 
921  return ss.str();
922 }
923 
924 
925 } // namespace
unsigned int uint32
Definition: Nsound.h:153
#define M_ASSERT_VALUE(a, op, value)
Definition: Macros.h:76
BufferUnderrunMode underrun_mode_
void stop()
Stops playback.
Pool::iterator pool_begin_
std::string getInfo()
Returns information about the backend driver.
std::string __str__() const
#define M_CHECK_PTR(ptr)
Definition: Macros.h:64
double float64
Definition: Nsound.h:146
std::vector< uint32 > n_history
void operator>>(const AudioStream &lhs, AudioPlayback &rhs)
virtual float64 generate(const float64 &frequency)
This is a real-time method for the wavetable oscillator.
Definition: Generator.cc:972
signed short int16
Definition: Nsound.h:141
int _callback(const void *input, void *output, const uint32 frame_count, const PaStreamCallbackTimeInfo *time_info, PaStreamCallbackFlags status_flags)
AudioPlaybackRtDebug get_debug_info() const
#define M_THROW(message)
Definition: Macros.h:108
void setBufferUnderrunMode(BufferUnderrunMode bum)
PaStreamParameters * out_params_
A Buffer for storing audio samples.
Definition: Buffer.h:60
AudioPlaybackRt(float64 sample_rate=44100.0, uint32 channels=1, uint32 n_buffers=3, float64 buffer_size_sec=-1.0)
static int _pa_callback(const void *input, void *output, unsigned long frame_count, const PaStreamCallbackTimeInfo *time_info, PaStreamCallbackFlags status_flags, void *ap_obj)
std::vector< int16 > Int16Vector
std::vector< uint32 > n_history_
RandomNumberGenerator & getRandomNumberGenerator()
Definition: Generator.h:562
void play(const AudioStream &a)
Writes samples to the internal circular buffer to be played.