GNU Octave 10.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
 
Loading...
Searching...
No Matches
audiodevinfo.cc
Go to the documentation of this file.
1////////////////////////////////////////////////////////////////////////
2//
3// Copyright (C) 2013-2025 The Octave Project Developers
4//
5// See the file COPYRIGHT.md in the top-level directory of this
6// distribution or <https://octave.org/copyright/>.
7//
8// This file is part of Octave.
9//
10// Octave is free software: you can redistribute it and/or modify it
11// under the terms of the GNU General Public License as published by
12// the Free Software Foundation, either version 3 of the License, or
13// (at your option) any later version.
14//
15// Octave is distributed in the hope that it will be useful, but
16// WITHOUT ANY WARRANTY; without even the implied warranty of
17// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18// GNU General Public License for more details.
19//
20// You should have received a copy of the GNU General Public License
21// along with Octave; see the file COPYING. If not, see
22// <https://www.gnu.org/licenses/>.
23//
24////////////////////////////////////////////////////////////////////////
25
26#if defined (HAVE_CONFIG_H)
27# include "config.h"
28#endif
29
30#include <cstdint>
31
32#include <algorithm>
33#include <ostream>
34#include <string>
35#include <vector>
36
37#include "Matrix.h"
38#include "mach-info.h"
39#include "oct-locbuf.h"
40#include "quit.h"
41#include "unwind-prot.h"
42
43#include "Cell.h"
44#include "defun-dld.h"
45#include "error.h"
46#include "errwarn.h"
47#include "interpreter-private.h"
48#include "interpreter.h"
49#include "oct-map.h"
50#include "ov-int32.h"
51#include "ov.h"
52#include "ovl.h"
53
54#if defined (HAVE_PORTAUDIO)
55# include <portaudio.h>
56#endif
57
59
60#if defined (HAVE_PORTAUDIO)
61
62static PaSampleFormat
63bits_to_format (int bits)
64{
65 if (bits == 8)
66 return paInt8;
67 else if (bits == 16)
68 return paInt16;
69 else if (bits == 24)
70 return paInt24;
71 else if (bits == 32)
72 return paInt32;
73 else if (bits == -1)
74 return paFloat32;
75 else
76 return 0;
77}
78
79#endif
80
81DEFUN_DLD (audiodevinfo, args, ,
82 doc: /* -*- texinfo -*-
83@deftypefn {} {@var{devinfo} =} audiodevinfo ()
84
85@deftypefnx {} {@var{devs} =} audiodevinfo (@var{io})
86@deftypefnx {} {@var{name} =} audiodevinfo (@var{io}, @var{id})
87@deftypefnx {} {@var{id} =} audiodevinfo (@var{io}, @var{name})
88@deftypefnx {} {@var{driverversion} =} audiodevinfo (@var{io}, @var{id}, "DriverVersion")
89@deftypefnx {} {@var{id} =} audiodevinfo (@var{io}, @var{rate}, @var{bits}, @var{chans})
90@deftypefnx {} {@var{supports} =} audiodevinfo (@var{io}, @var{id}, @var{rate}, @var{bits}, @var{chans})
91
92Return a structure describing the available audio input and output devices.
93
94The @var{devinfo} structure has two fields @qcode{"input"} and
95@qcode{"output"}. The value of each field is a structure array with fields
96@qcode{"Name"}, @nospell{@qcode{"DriverVersion"}} and @qcode{"ID"} describing
97an audio device.
98
99If the optional argument @var{io} is 1, return information about input devices
100only. If it is 0, return information about output devices only. If @var{io}
101is the only argument supplied, return the number of input or output devices
102available.
103
104If the optional argument @var{id} is provided, return information about the
105corresponding device.
106
107If the optional argument @var{name} is provided, return the ID of the named
108device.
109
110If the optional argument @nospell{@qcode{"DriverVersion"}} is given, return the
111name of the driver for the specified device.
112
113Given a sampling rate, bits per sample, and number of channels for an input or
114output device, return the ID of the first device that supports playback or
115recording using the specified parameters.
116
117If also given a device ID, return true if the device supports playback or
118recording using those parameters.
119@end deftypefn */)
120{
121#if defined (HAVE_PORTAUDIO)
122
123 int nargin = args.length ();
124
125 if (nargin > 5)
126 print_usage ();
127
128 octave_scalar_map devinfo;
129 octave_value_list input;
130 octave_value_list output;
131
132 PaError err = Pa_Initialize ();
133
134 if (err != paNoError)
135 error ("audiodevinfo: PortAudio initialization failed");
136
137 int num_devices = Pa_GetDeviceCount ();
138
139 if (num_devices < 0)
140 num_devices = 0;
141
142 octave_idx_type numinput, numoutput;
143 numinput = numoutput = 0;
144 for (int i = 0; i < num_devices; i++)
145 {
146 const PaDeviceInfo *device_info = Pa_GetDeviceInfo (i);
147
148 if (! device_info)
149 {
150 warning_with_id ("Octave:invalid-audio-device",
151 "invalid audio device ID = %d", i);
152 continue;
153 }
154
155 if (device_info->maxInputChannels != 0)
156 numinput++;
157
158 if (device_info->maxOutputChannels != 0)
159 numoutput++;
160 }
161
162 Cell input_name (dim_vector (1, numinput));
163 Cell input_driver_version (dim_vector (1, numinput));
164 Cell input_id (dim_vector (1, numinput));
165 Cell output_name (dim_vector (1, numoutput));
166 Cell output_driver_version (dim_vector (1, numoutput));
167 Cell output_id (dim_vector (1, numoutput));
168
169 octave_idx_type idx_i, idx_o;
170 idx_i = idx_o = 0;
171 for (int i = 0; i < num_devices; i++)
172 {
173 const PaDeviceInfo *device_info = Pa_GetDeviceInfo (i);
174
175 if (! device_info)
176 {
177 warning_with_id ("Octave:invalid-audio-device",
178 "invalid audio device ID = %d", i);
179 continue;
180 }
181
182 const PaHostApiInfo *api_info = Pa_GetHostApiInfo (device_info->hostApi);
183
184 const char *driver = (api_info ? api_info->name : "");
185
186 char name[256];
187 snprintf (name, 256, "%s (%s)", device_info->name, driver);
188
189 if (device_info->maxInputChannels != 0)
190 {
191 input_name(idx_i) = name;
192 input_driver_version(idx_i) = driver;
193 input_id(idx_i) = i;
194 idx_i++;
195 }
196
197 if (device_info->maxOutputChannels != 0)
198 {
199 output_name(idx_o) = name;
200 output_driver_version(idx_o) = driver;
201 output_id(idx_o) = i;
202 idx_o++;
203 }
204 }
205
206 octave_map inputdev, outputdev;
207 inputdev.setfield ("Name", input_name);
208 inputdev.setfield ("DriverVersion", input_driver_version);
209 inputdev.setfield ("ID", input_id);
210 outputdev.setfield ("Name", output_name);
211 outputdev.setfield ("DriverVersion", output_driver_version);
212 outputdev.setfield ("ID", output_id);
213 devinfo.setfield ("input", inputdev);
214 devinfo.setfield ("output", outputdev);
215
216 octave_value retval;
217
218 // Return information about input & output audio devices and their properties.
219 if (nargin == 0)
220 {
221 retval = devinfo;
222 }
223 // Return the number of input or output devices
224 else if (nargin == 1)
225 {
226 if (args(0).int_value () == 0)
227 retval = numoutput;
228 else if (args(0).int_value () == 1)
229 retval = numinput;
230 else
231 error ("audiodevinfo: specify 0 for output and 1 for input devices");
232 }
233 // Return device name when given id or id when given device name.
234 else if (nargin == 2)
235 {
236 bool found = false;
237 int outin = args(0).int_value ();
238 if (args(1).is_string ())
239 {
240 std::string name = args(1).string_value ();
241 if (outin == 0)
242 {
243 for (int i = 0; i < numoutput; i++)
244 {
245 if (output_name(i).string_value () == name)
246 {
247 retval = output_id(i);
248 found = true;
249 break;
250 }
251 }
252 }
253 else if (outin == 1)
254 {
255 for (int i = 0; i < numinput; i++)
256 {
257 if (input_name(i).string_value () == name)
258 {
259 retval = input_id(i);
260 found = true;
261 break;
262 }
263 }
264 }
265 else
266 error ("audiodevinfo: specify 0 for output and 1 for input devices");
267 }
268 else
269 {
270 if (outin == 0)
271 {
272 for (int i = 0; i < numoutput; i++)
273 {
274 if (output_id(i).int_value () == args(1).int_value ())
275 {
276 retval = output_name(i);
277 found = true;
278 break;
279 }
280 }
281 }
282 else if (outin == 1)
283 {
284 for (int i = 0; i < numinput; i++)
285 {
286 if (input_id(i).int_value () == args(1).int_value ())
287 {
288 retval = input_name(i);
289 found = true;
290 break;
291 }
292 }
293 }
294 else
295 error ("audiodevinfo: specify 0 for output and 1 for input devices");
296 }
297
298 if (! found)
299 error ("audiodevinfo: no device found for the specified criteria");
300 }
301 // Return the DriverVersion (really, name of driver) of the specified device
302 else if (nargin == 3)
303 {
304 bool found = false;
305 int outin = args(0).int_value ();
306 int m_id = args(1).int_value ();
307
308 std::string arg3 = args(2).string_value ();
309 std::transform (arg3.begin (), arg3.end (), arg3.begin (), tolower);
310 if (arg3 != "driverversion")
311 error (R"(audiodevinfo: third argument must be "DriverVersion")");
312
313 if (outin == 0)
314 {
315 for (int i = 0; i < numoutput; i++)
316 {
317 if (output_id(i).int_value () == m_id)
318 {
319 found = true;
320 retval = output_driver_version(i);
321 break;
322 }
323 }
324 }
325 else if (outin == 1)
326 {
327 for (int i = 0; i < numinput; i++)
328 {
329 if (input_id(i).int_value () == m_id)
330 {
331 found = true;
332 retval = input_driver_version(i);
333 break;
334 }
335 }
336 }
337 else
338 error ("audiodevinfo: specify 0 for output and 1 for input devices");
339
340 if (! found)
341 error ("audiodevinfo: no device found for the specified criteria");
342 }
343 // Return the ID of the first device meeting specified criteria.
344 else if (nargin == 4)
345 {
346 int io = args(0).int_value ();
347 int rate = args(1).int_value ();
348 int bits = args(2).int_value ();
349 int chans = args(3).int_value ();
350
351 for (int i = 0; i < num_devices; i++)
352 {
353 PaStreamParameters stream_parameters;
354 stream_parameters.device = i;
355 stream_parameters.channelCount = chans;
356 PaSampleFormat format = bits_to_format (bits);
357
358 if (format != 0)
359 stream_parameters.sampleFormat = format;
360 else
361 error ("audiodevinfo: invalid bits per sample format");
362
363 const PaDeviceInfo *device_info = Pa_GetDeviceInfo (i);
364
365 if (! device_info)
366 {
367 warning_with_id ("Octave:invalid-audio-device",
368 "invalid audio device ID = %d", i);
369 continue;
370 }
371
372 stream_parameters.suggestedLatency
373 = device_info->defaultLowInputLatency;
374
375 stream_parameters.hostApiSpecificStreamInfo = nullptr;
376
377 if (io == 0)
378 {
379 if (device_info->maxOutputChannels < chans)
380 continue;
381
382 err = Pa_IsFormatSupported (nullptr, &stream_parameters, rate);
383
384 if (err == paFormatIsSupported)
385 {
386 retval = i;
387 return retval;
388 }
389 }
390 else if (io == 1)
391 {
392 if (device_info->maxInputChannels < chans)
393 continue;
394
395 err = Pa_IsFormatSupported (&stream_parameters, nullptr, rate);
396 if (err == paFormatIsSupported)
397 {
398 retval = i;
399 return retval;
400 }
401 }
402 }
403 retval = -1;
404 }
405 // Check if given device supports specified playback or recording modes.
406 else if (nargin == 5)
407 {
408 int io = args(0).int_value ();
409 int m_id = args(1).int_value ();
410 int rate = args(2).int_value ();
411 int bits = args(3).int_value ();
412 int chans = args(4).int_value ();
413 PaStreamParameters stream_parameters;
414 stream_parameters.device = m_id;
415 stream_parameters.channelCount = chans;
416 PaSampleFormat format = bits_to_format (bits);
417 if (format != 0)
418 stream_parameters.sampleFormat = format;
419 else
420 error ("audiodevinfo: invalid bits per sample format");
421
422 const PaDeviceInfo *device_info = Pa_GetDeviceInfo (m_id);
423
424 if (! device_info)
425 error ("audiodevinfo: invalid audio device ID = %d", m_id);
426
427 stream_parameters.suggestedLatency
428 = device_info->defaultLowInputLatency;
429
430 stream_parameters.hostApiSpecificStreamInfo = nullptr;
431 if (io == 0)
432 {
433 if (device_info->maxOutputChannels < chans)
434 {
435 retval = false;
436 return retval;
437 }
438 err = Pa_IsFormatSupported (nullptr, &stream_parameters, rate);
439 if (err == paFormatIsSupported)
440 {
441 retval = true;
442 return retval;
443 }
444 }
445 else if (io == 1)
446 {
447 if (device_info->maxInputChannels < chans)
448 {
449 retval = false;
450 return retval;
451 }
452 err = Pa_IsFormatSupported (&stream_parameters, nullptr, rate);
453 if (err == paFormatIsSupported)
454 {
455 retval = true;
456 return retval;
457 }
458 }
459 else
460 error ("audiodevinfo: specify 0 for output and 1 for input devices");
461
462 retval = false;
463 }
464
465 return retval;
466
467#else
468 octave_unused_parameter (args);
469
470 err_disabled_feature ("audiodevinfo",
471 "audio playback and recording through PortAudio");
472#endif
473}
474
475/*
476%!testif HAVE_PORTAUDIO
477%! devinfo = audiodevinfo;
478%! assert (rows (devinfo.input), 1);
479%! assert (rows (devinfo.output), 1);
480
481%!testif HAVE_PORTAUDIO
482%! devinfo = audiodevinfo;
483%! nout = audiodevinfo (0);
484%! nin = audiodevinfo (1);
485%! assert (columns (devinfo.output), nout);
486%! assert (columns (devinfo.input), nin);
487
488%!testif HAVE_PORTAUDIO
489%! devinfo = audiodevinfo;
490%! nout = audiodevinfo (0);
491%! nin = audiodevinfo (1);
492%! for i = 1:nout
493%! assert (devinfo.output(i).Name, audiodevinfo (0, devinfo.output(i).ID));
494%! endfor
495%! for i=1:nin
496%! assert (devinfo.input (i).Name, audiodevinfo (1, devinfo.input (i).ID));
497%! endfor
498
499%!testif HAVE_PORTAUDIO
500%! devinfo = audiodevinfo;
501%! nout = audiodevinfo (0);
502%! nin = audiodevinfo (1);
503%! ## There might be multiple devices with the same name
504%! ## (e.g., on Windows WDM-KS)
505%! ## Check only the first of each unique device name.
506%! [unq_out_name, idx_unique] = unique ({devinfo.output(:).Name});
507%! unq_out_id = [devinfo.output(idx_unique).ID];
508%! for i = 1:numel (unq_out_name)
509%! assert (audiodevinfo (0, unq_out_name{i}), unq_out_id(i));
510%! endfor
511%! [unq_in_name, idx_unique] = unique ({devinfo.input(:).Name});
512%! unq_in_id = [devinfo.input(idx_unique).ID];
513%! for i = 1:numel (unq_in_name)
514%! assert (audiodevinfo (1, unq_in_name{i}), unq_in_id(i));
515%! endfor
516*/
517
518#if defined (HAVE_PORTAUDIO)
519
520enum audio_type { TYPE_INT8, TYPE_UINT8, TYPE_UINT16, TYPE_DOUBLE };
521
522class audioplayer : public octave_base_dld_value
523{
524public:
525
526 audioplayer ();
527
528 OCTAVE_DISABLE_COPY_MOVE (audioplayer)
529
530 ~audioplayer ();
531
532 // Overloaded base functions
533 double player_value () const { return 0; }
534 virtual double scalar_value (bool = false) const { return 0; }
535 void print (std::ostream& os, bool pr_as_read_syntax = false);
536 void print_raw (std::ostream& os, bool pr_as_read_syntax) const;
537
538 // Properties
539 bool is_constant () const { return true; }
540 bool is_defined () const { return true; }
541 bool print_as_scalar () const { return true; }
542
543 void init ();
544 void set_y (const octave_value& m_y);
545 void set_y (octave_function *fcn);
546 void set_y (std::string fcn);
547 Matrix& get_y ();
548 RowVector get_left () const;
549 RowVector get_right () const;
550 void set_fs (int m_fs);
551 int get_fs ();
552 void set_nbits (int m_nbits);
553 int get_nbits ();
554 void set_id (int m_id);
555 int get_id ();
556 int get_channels ();
557 audio_type get_type ();
558
559 void set_sample_number (unsigned int sample);
560 unsigned int get_sample_number ();
561 unsigned int get_total_samples ();
562 void set_end_sample (unsigned int sample);
563 unsigned int get_end_sample ();
564 void reset_end_sample ();
565 void set_tag (const charMatrix& m_tag);
566 charMatrix get_tag ();
567 void set_userdata (const octave_value& m_userdata);
568 octave_value get_userdata ();
569 PaStream * get_stream ();
570
571 void play ();
572 void playblocking ();
573 void pause ();
574 void resume ();
575 void stop ();
576 bool isplaying ();
577
578 octave_function *octave_callback_function;
579
580private:
581 int m_id;
582 int m_fs;
583 int m_nbits;
584 int m_channels;
585 unsigned int m_sample_number;
586 unsigned int m_end_sample;
587 charMatrix m_tag;
588 Matrix m_y;
589 octave_value m_userdata;
590 RowVector m_left;
591 RowVector m_right;
592 PaStream *m_stream;
593 PaStreamParameters m_output_parameters;
594 audio_type m_type;
595
597};
598
599DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (audioplayer, "audioplayer", "audioplayer");
600
601static int
602octave_play_callback (const void *, void *output, unsigned long frames,
603 const PaStreamCallbackTimeInfo *,
604 PaStreamCallbackFlags, void *data)
605{
606 audioplayer *player = static_cast<audioplayer *> (data);
607
608 if (! player)
609 error ("audioplayer callback function called without player");
610
611 interpreter& interp = __get_interpreter__ ();
612
613 octave_value_list retval
614 = interp.feval (player->octave_callback_function,
615 ovl (static_cast<double> (frames)), 1);
616
617 if (retval.length () < 2)
618 error ("audioplayer callback function failed");
619
620 const Matrix sound = retval(0).matrix_value ();
621 int return_status = retval(1).int_value ();
622
623 if (frames - sound.rows () != 0 || sound.columns () < 1
624 || sound.columns () > 2)
625 error ("audioplayer callback function failed");
626
627 // Don't multiply the audio data by scale_factor here. Although it
628 // does move the operation outside of the loops below, it also causes
629 // a second copy of the data array to be made.
630
631 const ColumnVector sound_l = sound.column (0);
632 const ColumnVector sound_r = (sound.columns () == 1
633 ? sound_l : sound.column (1));
634
635 const double *p_l = sound_l.data ();
636 const double *p_r = sound_r.data ();
637
638 switch (player->get_nbits ())
639 {
640 case 8:
641 {
642 static double scale_factor = std::pow (2.0, 7) - 1.0;
643
644 int8_t *buffer = static_cast<int8_t *> (output);
645
646 for (unsigned long i = 0; i < frames; i++)
647 {
648 buffer[2*i] = p_l[i] * scale_factor;
649 buffer[2*i+1] = p_r[i] * scale_factor;
650 }
651 }
652 break;
653
654 case 16:
655 {
656 static double scale_factor = std::pow (2.0, 15) - 1.0;
657
658 int16_t *buffer = static_cast<int16_t *> (output);
659
660 for (unsigned long i = 0; i < frames; i++)
661 {
662 buffer[2*i] = p_l[i] * scale_factor;
663 buffer[2*i+1] = p_r[i] * scale_factor;
664 }
665 }
666 break;
667
668 case 24:
669 {
670 static double scale_factor = std::pow (2.0, 23) - 1.0;
671
672 static int big_endian = mach_info::words_big_endian ();
673
674 uint8_t *buffer = static_cast<uint8_t *> (output);
675
676 for (unsigned long i = 0; i < frames; i++)
677 {
678 int32_t sample_l = p_l[i];
679 int32_t sample_r = p_r[i];
680
681 sample_l &= 0x00ffffff;
682 sample_r &= 0x00ffffff;
683
684 uint8_t *_sample_l = reinterpret_cast<uint8_t *> (&sample_l);
685 uint8_t *_sample_r = reinterpret_cast<uint8_t *> (&sample_r);
686
687 unsigned long offset = i * 6;
688
689 buffer[offset+0] = _sample_l[0+big_endian] * scale_factor;
690 buffer[offset+1] = _sample_l[1+big_endian] * scale_factor;
691 buffer[offset+2] = _sample_l[2+big_endian] * scale_factor;
692
693 buffer[offset+3] = _sample_r[0+big_endian] * scale_factor;
694 buffer[offset+4] = _sample_r[1+big_endian] * scale_factor;
695 buffer[offset+5] = _sample_r[2+big_endian] * scale_factor;
696 }
697 }
698 break;
699
700 default:
701 error ("invalid bit depth in audioplayer callback function");
702 }
703
704 return return_status;
705}
706
707static int
708portaudio_play_callback (const void *, void *output, unsigned long frames,
709 const PaStreamCallbackTimeInfo *,
710 PaStreamCallbackFlags, void *data)
711{
712 audioplayer *player = static_cast<audioplayer *> (data);
713
714 if (! player)
715 error ("audioplayer callback function called without player");
716
717 // Don't multiply the audio data by scale_factor here. Although it would
718 // move the operation outside of the loops below, it also causes a second
719 // copy of the *entire* data array to be made when only a small portion
720 // (buffer_size elements) is usually needed for this callback.
721
722 const RowVector sound_l = player->get_left ();
723 const RowVector sound_r = player->get_right ();
724
725 const double *pl = sound_l.data ();
726 const double *pr = sound_r.data ();
727
728 if (player->get_type () == TYPE_DOUBLE)
729 {
730 switch (player->get_nbits ())
731 {
732 case 8:
733 {
734 static double scale_factor = std::pow (2.0, 7) - 1.0;
735
736 int8_t *buffer = static_cast<int8_t *> (output);
737
738 for (unsigned long j = 0; j < frames; j++)
739 {
740 unsigned int m_sample_number = player->get_sample_number ();
741
742 if (m_sample_number >= player->get_end_sample ())
743 return paComplete;
744
745 unsigned long offset = j * 2;
746
747 buffer[offset+0] = pl[m_sample_number] * scale_factor;
748 buffer[offset+1] = pr[m_sample_number] * scale_factor;
749
750 player->set_sample_number (m_sample_number + 1);
751 }
752 }
753 break;
754
755 case 16:
756 {
757 static double scale_factor = std::pow (2.0, 15) - 1.0;
758
759 int16_t *buffer = static_cast<int16_t *> (output);
760
761 for (unsigned long j = 0; j < frames; j++)
762 {
763 unsigned int m_sample_number = player->get_sample_number ();
764
765 if (m_sample_number >= player->get_end_sample ())
766 return paComplete;
767
768 unsigned long offset = j * 2;
769
770 buffer[offset+0] = pl[m_sample_number] * scale_factor;
771 buffer[offset+1] = pr[m_sample_number] * scale_factor;
772
773 player->set_sample_number (m_sample_number + 1);
774 }
775 }
776 break;
777
778 case 24:
779 {
780 static double scale_factor = std::pow (2.0, 23) - 1.0;
781
782 static int big_endian = mach_info::words_big_endian ();
783
784 uint8_t *buffer = static_cast<uint8_t *> (output);
785
786 for (unsigned long j = 0; j < frames; j++)
787 {
788 unsigned int m_sample_number = player->get_sample_number ();
789
790 if (m_sample_number >= player->get_end_sample ())
791 return paComplete;
792
793 int32_t sample_l = pl[m_sample_number] * scale_factor;
794 int32_t sample_r = pr[m_sample_number] * scale_factor;
795
796 sample_l &= 0x00ffffff;
797 sample_r &= 0x00ffffff;
798
799 uint8_t *_sample_l = reinterpret_cast<uint8_t *> (&sample_l);
800 uint8_t *_sample_r = reinterpret_cast<uint8_t *> (&sample_r);
801
802 unsigned long offset = j * 6;
803
804 buffer[offset+0] = _sample_l[0+big_endian];
805 buffer[offset+1] = _sample_l[1+big_endian];
806 buffer[offset+2] = _sample_l[2+big_endian];
807
808 buffer[offset+3] = _sample_r[0+big_endian];
809 buffer[offset+4] = _sample_r[1+big_endian];
810 buffer[offset+5] = _sample_r[2+big_endian];
811
812 player->set_sample_number (m_sample_number + 1);
813 }
814 }
815 break;
816
817 default:
818 error ("invalid bit depth in audioplayer callback function");
819 }
820 }
821 else if (player->get_type () == TYPE_INT8)
822 {
823 int8_t *buffer = static_cast<int8_t *> (output);
824
825 for (unsigned long j = 0; j < frames; j++)
826 {
827 unsigned int m_sample_number = player->get_sample_number ();
828
829 if (m_sample_number >= player->get_end_sample ())
830 return paComplete;
831
832 unsigned long offset = j * 2;
833
834 buffer[offset+0] = pl[m_sample_number];
835 buffer[offset+1] = pr[m_sample_number];
836
837 player->set_sample_number (m_sample_number + 1);
838 }
839 }
840 else if (player->get_type () == TYPE_UINT8)
841 {
842 uint8_t *buffer = static_cast<uint8_t *> (output);
843
844 for (unsigned long j = 0; j < frames; j++)
845 {
846 unsigned int m_sample_number = player->get_sample_number ();
847
848 if (m_sample_number >= player->get_end_sample ())
849 return paComplete;
850
851 unsigned long offset = j * 2;
852
853 buffer[offset+0] = pl[m_sample_number];
854 buffer[offset+1] = pr[m_sample_number];
855
856 player->set_sample_number (m_sample_number + 1);
857 }
858 }
859 else if (player->get_type () == TYPE_UINT16)
860 {
861 int16_t *buffer = static_cast<int16_t *> (output);
862
863 for (unsigned long j = 0; j < frames; j++)
864 {
865 unsigned int m_sample_number = player->get_sample_number ();
866
867 if (m_sample_number >= player->get_end_sample ())
868 return paComplete;
869
870 unsigned long offset = j * 2;
871
872 buffer[offset+0] = pl[m_sample_number];
873 buffer[offset+1] = pr[m_sample_number];
874
875 player->set_sample_number (m_sample_number + 1);
876 }
877 }
878
879 return paContinue;
880}
881
882audioplayer::audioplayer ()
883 : octave_callback_function (nullptr),
884 m_id (-1), m_fs (0), m_nbits (16), m_channels (0), m_sample_number (0),
885 m_end_sample (-1), m_tag (""), m_y (), m_userdata (Matrix ()),
886 m_left (), m_right (), m_stream (nullptr), m_output_parameters (), m_type ()
887{ }
888
889audioplayer::~audioplayer ()
890{
891 if (isplaying ())
892 {
893 warning_with_id ("Octave:audio-interrupt",
894 "interrupting audioplayer during playback");
895 stop ();
896 }
897}
898
899void
900audioplayer::print (std::ostream& os, bool pr_as_read_syntax)
901{
902 print_raw (os, pr_as_read_syntax);
903 newline (os);
904}
905
906void
907audioplayer::print_raw (std::ostream& os, bool) const
908{
909 os << 0;
910}
911
912void
913audioplayer::init ()
914{
915 // FIXME: Both of these variables are unused.
916 // Should they be eliminated or is something not yet implemented?
917 //
918 // int channels = y.rows ();
919 // RowVector *sound_l = get_left ();
920
921 if (Pa_Initialize () != paNoError)
922 error ("audioplayer: initialization error");
923
924 if (Pa_GetDeviceCount () < 1)
925 error ("audioplayer: no audio devices found or available");
926
927 int device = get_id ();
928
929 if (device == -1)
930 device = Pa_GetDefaultOutputDevice ();
931
932 m_output_parameters.device = device;
933 m_output_parameters.channelCount = 2;
934
935 if (m_type == TYPE_DOUBLE)
936 m_output_parameters.sampleFormat = bits_to_format (get_nbits ());
937 else if (m_type == TYPE_INT8)
938 m_output_parameters.sampleFormat = paInt8;
939 else if (m_type == TYPE_UINT8)
940 m_output_parameters.sampleFormat = paUInt8;
941 else if (m_type == TYPE_UINT16)
942 m_output_parameters.sampleFormat = paInt16;
943
944 const PaDeviceInfo *device_info = Pa_GetDeviceInfo (device);
945
946 if (! device_info)
947 warning_with_id ("Octave:invalid-default-audio-device",
948 "invalid default audio device ID = %d", device);
949
950 m_output_parameters.suggestedLatency
951 = (device_info ? device_info->defaultHighOutputLatency : -1);
952
953 m_output_parameters.hostApiSpecificStreamInfo = nullptr;
954}
955
956void
957audioplayer::set_y (const octave_value& y_arg)
958{
959 if (y_arg.is_int8_type ())
960 m_type = TYPE_INT8;
961 else if (y_arg.is_uint8_type ())
962 m_type = TYPE_UINT8;
963 else if (y_arg.is_int16_type ())
964 m_type = TYPE_UINT16;
965 else
966 m_type = TYPE_DOUBLE;
967
968 m_y = y_arg.matrix_value ();
969
970 if (m_y.rows () > 2)
971 m_y = m_y.transpose ();
972
973 m_channels = m_y.rows ();
974 m_left = m_y.row (0);
975
976 if (m_channels == 2)
977 m_right = m_y.row (1);
978
979 reset_end_sample ();
980}
981
982void
983audioplayer::set_y (octave_function *fcn)
984{
985 octave_callback_function = fcn;
986 m_channels = 2;
987 reset_end_sample ();
988}
989
990Matrix&
991audioplayer::get_y ()
992{
993 return m_y;
994}
995
997audioplayer::get_left () const
998{
999 return m_left;
1000}
1001
1003audioplayer::get_right () const
1004{
1005 return m_channels == 1 ? m_left : m_right;
1006}
1007
1008void
1009audioplayer::set_fs (int fs_arg)
1010{
1011 m_fs = fs_arg;
1012}
1013
1014int
1015audioplayer::get_fs ()
1016{
1017 return m_fs;
1018}
1019
1020void
1021audioplayer::set_nbits (int nbits_arg)
1022{
1023 m_nbits = nbits_arg;
1024}
1025
1026int
1027audioplayer::get_nbits ()
1028{
1029 return m_nbits;
1030}
1031
1032void
1033audioplayer::set_id (int id_arg)
1034{
1035 m_id = id_arg;
1036}
1037
1038int
1039audioplayer::get_id ()
1040{
1041 return m_id;
1042}
1043
1044int
1045audioplayer::get_channels ()
1046{
1047 return m_channels;
1048}
1049
1050audio_type
1051audioplayer::get_type ()
1052{
1053 return m_type;
1054}
1055
1056void
1057audioplayer::set_sample_number (unsigned int sample_number_arg)
1058{
1059 m_sample_number = sample_number_arg;
1060}
1061
1062unsigned int
1063audioplayer::get_sample_number ()
1064{
1065 return m_sample_number;
1066}
1067
1068unsigned int
1069audioplayer::get_total_samples ()
1070{
1071 return m_left.numel ();
1072}
1073
1074void
1075audioplayer::set_end_sample (unsigned int end_sample_arg)
1076{
1077 m_end_sample = end_sample_arg;
1078}
1079
1080unsigned int
1081audioplayer::get_end_sample ()
1082{
1083 return m_end_sample;
1084}
1085
1086void
1087audioplayer::reset_end_sample ()
1088{
1089 set_end_sample (m_left.numel ());
1090}
1091
1092void
1093audioplayer::set_tag (const charMatrix& tag_arg)
1094{
1095 m_tag = tag_arg;
1096}
1097
1099audioplayer::get_tag ()
1100{
1101 return m_tag;
1102}
1103
1104void
1105audioplayer::set_userdata (const octave_value& userdata_arg)
1106{
1107 m_userdata = userdata_arg;
1108}
1109
1111audioplayer::get_userdata ()
1112{
1113 return m_userdata;
1114}
1115
1116void
1117audioplayer::playblocking ()
1118{
1119 if (get_stream ())
1120 stop ();
1121
1122 const unsigned int buffer_size = get_fs () / 20;
1123 OCTAVE_LOCAL_BUFFER (uint32_t, buffer, buffer_size * 2);
1124
1125 PaError err;
1126 err = Pa_OpenStream (&m_stream, nullptr, &(m_output_parameters), get_fs (),
1127 buffer_size, paClipOff, nullptr, nullptr);
1128 if (err != paNoError)
1129 error ("audioplayer: unable to open audio playback stream");
1130
1131 err = Pa_StartStream (m_stream);
1132 if (err != paNoError)
1133 error ("audioplayer: unable to start audio playback stream");
1134
1135 unsigned int start, end;
1136 start = get_sample_number ();
1137 end = get_end_sample ();
1138
1139 unwind_action stop_audioplayer ([this] () { stop (); });
1140
1141 for (unsigned int i = start; i < end; i += buffer_size)
1142 {
1143 octave_quit ();
1144
1145 if (octave_callback_function != nullptr)
1146 octave_play_callback (nullptr, buffer, buffer_size, nullptr, 0, this);
1147 else
1148 portaudio_play_callback (nullptr, buffer, buffer_size, nullptr, 0, this);
1149
1150 err = Pa_WriteStream (m_stream, buffer, buffer_size);
1151 }
1152}
1153
1154void
1155audioplayer::play ()
1156{
1157 if (get_stream ())
1158 stop ();
1159
1160 const unsigned int buffer_size = get_fs () / 20;
1161
1162 PaError err;
1163 if (octave_callback_function != nullptr)
1164 err = Pa_OpenStream (&m_stream, nullptr, &(m_output_parameters),
1165 get_fs (), buffer_size, paClipOff,
1166 octave_play_callback, this);
1167 else
1168 err = Pa_OpenStream (&m_stream, nullptr, &(m_output_parameters),
1169 get_fs (), buffer_size, paClipOff,
1170 portaudio_play_callback, this);
1171
1172 if (err != paNoError)
1173 error ("audioplayer: failed to open audio playback stream");
1174
1175 err = Pa_StartStream (m_stream);
1176 if (err != paNoError)
1177 error ("audioplayer: failed to start audio playback stream");
1178}
1179
1180void
1181audioplayer::pause ()
1182{
1183 if (get_stream () == nullptr)
1184 return;
1185
1186 PaError err;
1187 err = Pa_StopStream (m_stream);
1188 if (err != paNoError)
1189 error ("audioplayer: failed to stop audio playback stream");
1190}
1191
1192void
1193audioplayer::resume ()
1194{
1195 if (get_stream () == nullptr)
1196 return;
1197
1198 PaError err;
1199 err = Pa_StartStream (m_stream);
1200 if (err != paNoError)
1201 error ("audioplayer: failed to start audio playback stream");
1202}
1203
1204PaStream *
1205audioplayer::get_stream ()
1206{
1207 return m_stream;
1208}
1209
1210void
1211audioplayer::stop ()
1212{
1213 if (get_stream () == nullptr)
1214 return;
1215
1216 PaError err;
1217 set_sample_number (0);
1218 reset_end_sample ();
1219 if (! Pa_IsStreamStopped (get_stream ()))
1220 {
1221 err = Pa_AbortStream (get_stream ());
1222 if (err != paNoError)
1223 error ("audioplayer: failed to stop audio playback stream");
1224 }
1225
1226 err = Pa_CloseStream (get_stream ());
1227 if (err != paNoError)
1228 error ("audioplayer: failed to close audio playback stream");
1229
1230 m_stream = nullptr;
1231}
1232
1233bool
1234audioplayer::isplaying ()
1235{
1236 if (get_stream () == nullptr)
1237 return false;
1238
1239 PaError err;
1240 err = Pa_IsStreamActive (m_stream);
1241 if (err != 0 && err != 1)
1242 error ("audioplayer: checking stream activity status failed");
1243
1244 return (err == 1);
1245}
1246
1247class audiorecorder : public octave_base_dld_value
1248{
1249public:
1250
1251 audiorecorder ();
1252
1253 OCTAVE_DISABLE_COPY_MOVE (audiorecorder)
1254
1255 ~audiorecorder ();
1256
1257 // Overloaded base functions
1258 double player_value () const { return 0; }
1259 virtual double scalar_value (bool = false) const { return 0; }
1260 void print (std::ostream& os, bool pr_as_read_syntax = false);
1261 void print_raw (std::ostream& os, bool pr_as_read_syntax) const;
1262
1263 // Properties
1264 bool is_constant () const { return true; }
1265 bool is_defined () const { return true; }
1266 bool print_as_scalar () const { return true; }
1267
1268 void init ();
1269 void set_fs (int m_fs);
1270 int get_fs ();
1271 void set_nbits (int m_nbits);
1272 int get_nbits ();
1273 PaSampleFormat get_sampleFormat ();
1274 void set_id (int m_id);
1275 int get_id ();
1276 void set_channels (int m_channels);
1277 int get_channels ();
1278 audio_type get_type ();
1279
1280 void set_sample_number (unsigned int sample);
1281 unsigned int get_sample_number ();
1282 unsigned int get_total_samples ();
1283 void set_end_sample (unsigned int sample);
1284 unsigned int get_end_sample ();
1285 void reset_end_sample ();
1286 void set_tag (const charMatrix& m_tag);
1287 charMatrix get_tag ();
1288 void set_userdata (const octave_value& m_userdata);
1289 octave_value get_userdata ();
1290 PaStream * get_stream ();
1291
1292 octave_value getaudiodata ();
1293 audioplayer * getplayer ();
1294 bool isrecording ();
1295 audioplayer play ();
1296 void record ();
1297 void recordblocking (float seconds);
1298 void pause ();
1299 void resume ();
1300 void stop ();
1301 void append (float sample_l, float sample_r);
1302
1303 octave_function *octave_callback_function;
1304
1305private:
1306 int m_id;
1307 int m_fs;
1308 int m_nbits;
1309 int m_channels;
1310 unsigned int m_sample_number;
1311 unsigned int m_end_sample;
1312 charMatrix m_tag;
1313 Matrix m_y;
1314 octave_value m_userdata;
1315 std::vector<float> m_left;
1316 std::vector<float> m_right;
1317 PaStream *m_stream;
1318 PaStreamParameters m_input_parameters;
1319 audio_type m_type;
1320
1322};
1323
1324DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (audiorecorder, "audiorecorder", "audiorecorder");
1325
1326static int
1327octave_record_callback (const void *input, void *, unsigned long frames,
1328 const PaStreamCallbackTimeInfo *,
1329 PaStreamCallbackFlags, void *data)
1330{
1331 audiorecorder *recorder = static_cast<audiorecorder *> (data);
1332
1333 if (! recorder)
1334 error ("audiorecorder callback function called without recorder");
1335
1336 int m_channels = recorder->get_channels ();
1337
1338 Matrix sound (frames, 2);
1339 sound.resize (frames, 2);
1340
1341 if (recorder->get_sampleFormat () == bits_to_format (8))
1342 {
1343 static double scale_factor = std::pow (2.0, 7) - 1.0;
1344
1345 const int8_t *input8 = static_cast<const int8_t *> (input);
1346
1347 for (unsigned long i = 0; i < frames; i++)
1348 {
1349 float sample_l = input8[i*m_channels] / scale_factor;
1350 float sample_r = input8[i*m_channels + (m_channels - 1)] / scale_factor;
1351
1352 sound(i, 0) = sample_l;
1353 sound(i, 1) = sample_r;
1354 }
1355 }
1356 // FIXME: This is a workaround for a bug in PortAudio affecting 8-Bit
1357 // recording (see Octave bug #44305).
1358 // Remove this clause once the bug in PortAudio has been fixed.
1359 else if (recorder->get_sampleFormat () == bits_to_format (16)
1360 && recorder->get_nbits () == 8)
1361 {
1362 static double scale_factor = std::pow (2.0, 7) - 1.0;
1363
1364 const int16_t *input16 = static_cast<const int16_t *> (input);
1365
1366 for (unsigned long i = 0; i < frames; i++)
1367 {
1368 float sample_l = (input16[i*m_channels] >> 8) / scale_factor;
1369 float sample_r = (input16[i*m_channels + (m_channels - 1)] >> 8)
1370 / scale_factor;
1371
1372 sound(i, 0) = sample_l;
1373 sound(i, 1) = sample_r;
1374 }
1375 }
1376 else if (recorder->get_sampleFormat () == bits_to_format (16))
1377 {
1378 static double scale_factor = std::pow (2.0, 15) - 1.0;
1379
1380 const int16_t *input16 = static_cast<const int16_t *> (input);
1381
1382 for (unsigned long i = 0; i < frames; i++)
1383 {
1384 float sample_l = input16[i*m_channels] / scale_factor;
1385 float sample_r = input16[i*m_channels + (m_channels - 1)] / scale_factor;
1386
1387 sound(i, 0) = sample_l;
1388 sound(i, 1) = sample_r;
1389 }
1390 }
1391 else if (recorder->get_sampleFormat () == bits_to_format (24))
1392 {
1393 static double scale_factor = std::pow (2.0, 23);
1394
1395 // FIXME: Is there a better way?
1396 // Could use union of int32_t, uint8_t[3:0]? (12/31/19)
1397 const uint8_t *input24 = static_cast<const uint8_t *> (input);
1398
1399 int32_t sample_l32, sample_r32;
1400
1401 uint8_t *sample_l = reinterpret_cast<uint8_t *> (&sample_l32);
1402 uint8_t *sample_r = reinterpret_cast<uint8_t *> (&sample_r32);
1403
1404 for (unsigned long i = 0; i < frames; i++)
1405 {
1406 sample_l32 = sample_r32 = 0;
1407 for (int j = 0; j < 3; j++)
1408 {
1409 sample_l[j] = input24[i*m_channels*3 + j];
1410 sample_r[j] = input24[i*m_channels*3 + (m_channels - 1)*3 + j];
1411 }
1412
1413 if (sample_l32 & 0x00800000)
1414 sample_l32 |= 0xff000000;
1415
1416 if (sample_r32 & 0x00800000)
1417 sample_r32 |= 0xff000000;
1418
1419 sound(i, 0) = sample_l32 / scale_factor;
1420 sound(i, 1) = sample_r32 / scale_factor;
1421 }
1422 }
1423
1424 interpreter& interp = __get_interpreter__ ();
1425
1426 octave_value_list retval
1427 = interp.feval (recorder->octave_callback_function, ovl (sound), 1);
1428
1429 return retval(0).int_value ();
1430}
1431
1432static int
1433portaudio_record_callback (const void *input, void *, unsigned long frames,
1434 const PaStreamCallbackTimeInfo *,
1435 PaStreamCallbackFlags, void *data)
1436{
1437 audiorecorder *recorder = static_cast<audiorecorder *> (data);
1438
1439 if (! recorder)
1440 error ("audiorecorder callback function called without recorder");
1441
1442 int m_channels = recorder->get_channels ();
1443
1444 if (recorder->get_sampleFormat () == bits_to_format (8))
1445 {
1446 static float scale_factor = std::pow (2.0f, 7) - 1.0f;
1447
1448 const int8_t *input8 = static_cast<const int8_t *> (input);
1449
1450 for (unsigned long i = 0; i < frames; i++)
1451 {
1452 float sample_l = input8[i*m_channels] / scale_factor;
1453 float sample_r = input8[i*m_channels + (m_channels - 1)] / scale_factor;
1454
1455 recorder->append (sample_l, sample_r);
1456 }
1457 }
1458 // FIXME: This is a workaround for a bug in PortAudio affecting 8-Bit
1459 // recording (see Octave bug #44305).
1460 // Remove this clause once the bug in PortAudio has been fixed.
1461 else if (recorder->get_sampleFormat () == bits_to_format (16)
1462 && recorder->get_nbits () == 8)
1463 {
1464 static double scale_factor = std::pow (2.0, 7) - 1.0;
1465
1466 const int16_t *input16 = static_cast<const int16_t *> (input);
1467
1468 for (unsigned long i = 0; i < frames; i++)
1469 {
1470 float sample_l = (input16[i*m_channels] >> 8) / scale_factor;
1471 float sample_r = (input16[i*m_channels + (m_channels - 1)] >> 8)
1472 / scale_factor;
1473
1474 recorder->append (sample_l, sample_r);
1475 }
1476 }
1477 else if (recorder->get_sampleFormat () == bits_to_format (16))
1478 {
1479 static float scale_factor = std::pow (2.0f, 15) - 1.0f;
1480
1481 const int16_t *input16 = static_cast<const int16_t *> (input);
1482
1483 for (unsigned long i = 0; i < frames; i++)
1484 {
1485 float sample_l = input16[i*m_channels] / scale_factor;
1486 float sample_r = input16[i*m_channels + (m_channels - 1)] / scale_factor;
1487
1488 recorder->append (sample_l, sample_r);
1489 }
1490 }
1491 else if (recorder->get_sampleFormat () == bits_to_format (24))
1492 {
1493 static float scale_factor = std::pow (2.0f, 23);
1494
1495 // FIXME: Is there a better way?
1496 // Could use union of int32_t, uint8_t[3:0]? (12/31/19)
1497 const uint8_t *input24 = static_cast<const uint8_t *> (input);
1498
1499 int32_t sample_l32, sample_r32;
1500
1501 uint8_t *sample_l = reinterpret_cast<uint8_t *> (&sample_l32);
1502 uint8_t *sample_r = reinterpret_cast<uint8_t *> (&sample_r32);
1503
1504 for (unsigned long i = 0; i < frames; i++)
1505 {
1506 sample_l32 = sample_r32 = 0;
1507 for (int j = 0; j < 3; j++)
1508 {
1509 sample_l[j] = input24[i*m_channels*3 + j];
1510 sample_r[j] = input24[i*m_channels*3 + (m_channels - 1)*3 + j];
1511 }
1512
1513 if (sample_l32 & 0x00800000)
1514 sample_l32 |= 0xff000000;
1515
1516 if (sample_r32 & 0x00800000)
1517 sample_r32 |= 0xff000000;
1518
1519 recorder->append (sample_l32 / scale_factor,
1520 sample_r32 / scale_factor);
1521 }
1522 }
1523
1524 if (recorder->get_sample_number () >= recorder->get_end_sample ())
1525 return paComplete;
1526
1527 return paContinue;
1528}
1529
1530audiorecorder::audiorecorder ()
1531 : octave_callback_function (nullptr),
1532 m_id (-1), m_fs (8000), m_nbits (8), m_channels (1), m_sample_number (0),
1533 m_end_sample (-1), m_tag (""), m_y (), m_userdata (Matrix ()),
1534 m_left (), m_right (), m_stream (nullptr), m_input_parameters (), m_type ()
1535{ }
1536
1537audiorecorder::~audiorecorder ()
1538{
1539 if (isrecording ())
1540 {
1541 warning_with_id ("Octave:audio-interrupt",
1542 "interrupting audiorecorder during recording");
1543 stop ();
1544 }
1545}
1546
1547void
1548audiorecorder::print (std::ostream& os, bool pr_as_read_syntax)
1549{
1550 print_raw (os, pr_as_read_syntax);
1551 newline (os);
1552}
1553
1554void
1555audiorecorder::print_raw (std::ostream& os, bool) const
1556{
1557 os << 0;
1558}
1559
1560void
1561audiorecorder::init ()
1562{
1563 if (Pa_Initialize () != paNoError)
1564 error ("audiorecorder: initialization error");
1565
1566 if (Pa_GetDeviceCount () < 1)
1567 error ("audiorecorder: no audio devices found or available");
1568
1569 int device = get_id ();
1570
1571 if (device == -1)
1572 device = Pa_GetDefaultInputDevice ();
1573
1574 m_input_parameters.device = device;
1575 m_input_parameters.channelCount = get_channels ();
1576 m_input_parameters.sampleFormat = bits_to_format (get_nbits ());
1577
1578 // FIXME: This is a workaround for a bug in PortAudio affecting 8-Bit
1579 // recording (see Octave bug #44305).
1580 // Remove this clause once the bug in PortAudio has been fixed.
1581 if (get_nbits () == 8)
1582 m_input_parameters.sampleFormat = bits_to_format (16);
1583
1584 const PaDeviceInfo *device_info = Pa_GetDeviceInfo (device);
1585
1586 if (! device_info)
1587 warning_with_id ("Octave:invalid-default-audio-device",
1588 "invalid default audio device ID = %d", device);
1589
1590 m_input_parameters.suggestedLatency
1591 = (device_info ? device_info->defaultHighInputLatency : -1);
1592
1593 m_input_parameters.hostApiSpecificStreamInfo = nullptr;
1594}
1595
1596void
1597audiorecorder::set_fs (int fs_arg)
1598{
1599 m_fs = fs_arg;
1600}
1601
1602int
1603audiorecorder::get_fs ()
1604{
1605 return m_fs;
1606}
1607
1608void
1609audiorecorder::set_nbits (int nbits_arg)
1610{
1611 m_nbits = nbits_arg;
1612}
1613
1614int
1615audiorecorder::get_nbits ()
1616{
1617 return m_nbits;
1618}
1619
1620PaSampleFormat
1621audiorecorder::get_sampleFormat ()
1622{
1623 return m_input_parameters.sampleFormat;
1624}
1625
1626void
1627audiorecorder::set_id (int id_arg)
1628{
1629 m_id = id_arg;
1630}
1631
1632int
1633audiorecorder::get_id ()
1634{
1635 return m_id;
1636}
1637
1638void
1639audiorecorder::set_channels (int channels_arg)
1640{
1641 if (channels_arg != 1 && channels_arg != 2)
1642 error ("audiorecorder: number of channels must be 1 or 2");
1643
1644 m_channels = channels_arg;
1645}
1646
1647int
1648audiorecorder::get_channels ()
1649{
1650 return m_channels;
1651}
1652
1653audio_type
1654audiorecorder::get_type ()
1655{
1656 return m_type;
1657}
1658
1659void
1660audiorecorder::set_sample_number (unsigned int sample_number_arg)
1661{
1662 m_sample_number = sample_number_arg;
1663}
1664
1665unsigned int
1666audiorecorder::get_sample_number ()
1667{
1668 return m_sample_number;
1669}
1670
1671unsigned int
1672audiorecorder::get_total_samples ()
1673{
1674 return m_left.size ();
1675}
1676
1677void
1678audiorecorder::set_end_sample (unsigned int end_sample_arg)
1679{
1680 m_end_sample = end_sample_arg;
1681}
1682
1683unsigned int
1684audiorecorder::get_end_sample ()
1685{
1686 return m_end_sample;
1687}
1688
1689void
1690audiorecorder::reset_end_sample ()
1691{
1692 set_end_sample (m_left.size ());
1693}
1694
1695void
1696audiorecorder::set_tag (const charMatrix& tag_arg)
1697{
1698 m_tag = tag_arg;
1699}
1700
1702audiorecorder::get_tag ()
1703{
1704 return m_tag;
1705}
1706
1707void
1708audiorecorder::set_userdata (const octave_value& userdata_arg)
1709{
1710 m_userdata = userdata_arg;
1711}
1712
1714audiorecorder::get_userdata ()
1715{
1716 return m_userdata;
1717}
1718
1720audiorecorder::getaudiodata ()
1721{
1722 // Must get size before entering loop as the value of left.size() may change
1723 // during loop with simultaneous recording and playback (bug #50674).
1724 unsigned int ls = m_left.size ();
1725 Matrix audio (2, ls);
1726
1727 for (unsigned int i = 0; i < ls; i++)
1728 {
1729 audio(0, i) = m_left[i];
1730 audio(1, i) = m_right[i];
1731 }
1732
1733 return audio;
1734}
1735
1736audioplayer *
1737audiorecorder::getplayer ()
1738{
1739 audioplayer *player = new audioplayer ();
1740
1741 player->set_y (getaudiodata ());
1742 player->set_fs (get_fs ());
1743 player->set_nbits (get_nbits ());
1744 player->init ();
1745
1746 return player;
1747}
1748
1749bool
1750audiorecorder::isrecording ()
1751{
1752 if (get_stream () == nullptr)
1753 return false;
1754
1755 PaError err;
1756 err = Pa_IsStreamActive (m_stream);
1757 if (err != 0 && err != 1)
1758 error ("audiorecorder: checking stream activity status failed");
1759
1760 return (err == 1);
1761}
1762
1763void
1764audiorecorder::record ()
1765{
1766 if (get_stream ())
1767 stop ();
1768
1769 m_left.clear ();
1770 m_right.clear ();
1771
1772 const unsigned int buffer_size = get_fs () / 20;
1773
1774 PaError err;
1775 if (octave_callback_function != nullptr)
1776 {
1777 err = Pa_OpenStream (&m_stream, &(m_input_parameters), nullptr,
1778 get_fs (), buffer_size, paClipOff,
1779 octave_record_callback, this);
1780 }
1781 else
1782 {
1783 err = Pa_OpenStream (&m_stream, &(m_input_parameters), nullptr,
1784 get_fs (), buffer_size, paClipOff,
1785 portaudio_record_callback, this);
1786 }
1787 if (err != paNoError)
1788 error ("audiorecorder: unable to open audio recording stream");
1789
1790 err = Pa_StartStream (m_stream);
1791 if (err != paNoError)
1792 error ("audiorecorder: unable to start audio recording stream");
1793}
1794
1795void
1796audiorecorder::recordblocking (float seconds)
1797{
1798 if (get_stream ())
1799 stop ();
1800
1801 m_left.clear ();
1802 m_right.clear ();
1803
1804 const unsigned int buffer_size = get_fs () / 20;
1805 OCTAVE_LOCAL_BUFFER (uint8_t, buffer, buffer_size * 2 * 3);
1806
1807 PaError err;
1808 err = Pa_OpenStream (&m_stream, &(m_input_parameters), nullptr,
1809 get_fs (), buffer_size, paClipOff, nullptr, this);
1810 if (err != paNoError)
1811 error ("audiorecorder: unable to open audio recording stream");
1812
1813 err = Pa_StartStream (m_stream);
1814 if (err != paNoError)
1815 error ("audiorecorder: unable to start audio recording stream");
1816
1817 unsigned int frames = seconds * get_fs ();
1818
1819 unwind_action stop_audiorecorder ([this] () { stop (); });
1820
1821 for (unsigned int i = 0; i < frames; i += buffer_size)
1822 {
1823 octave_quit ();
1824
1825 Pa_ReadStream (get_stream (), buffer, buffer_size);
1826
1827 if (octave_callback_function != nullptr)
1828 octave_record_callback (buffer, nullptr, buffer_size, nullptr, 0, this);
1829 else
1830 portaudio_record_callback (buffer, nullptr, buffer_size, nullptr, 0, this);
1831 }
1832}
1833
1834void
1835audiorecorder::pause ()
1836{
1837 if (get_stream () == nullptr)
1838 return;
1839
1840 PaError err;
1841 err = Pa_StopStream (m_stream);
1842 if (err != paNoError)
1843 error ("audiorecorder: unable to stop audio recording stream");
1844}
1845
1846void
1847audiorecorder::resume ()
1848{
1849 if (get_stream () == nullptr)
1850 return;
1851
1852 PaError err;
1853 err = Pa_StartStream (m_stream);
1854 if (err != paNoError)
1855 error ("audiorecorder: unable to start audio recording stream");
1856}
1857
1858void
1859audiorecorder::stop ()
1860{
1861 if (get_stream () == nullptr)
1862 return;
1863
1864 PaError err;
1865 if (! Pa_IsStreamStopped (get_stream ()))
1866 {
1867 err = Pa_AbortStream (get_stream ());
1868 if (err != paNoError)
1869 error ("audioplayer: unable to stop audio playback stream");
1870 }
1871
1872 err = Pa_CloseStream (m_stream);
1873 if (err != paNoError)
1874 error ("audiorecorder: unable to close audio recording stream");
1875
1876 set_sample_number (0);
1877 reset_end_sample ();
1878 m_stream = nullptr;
1879}
1880
1881void
1882audiorecorder::append (float sample_l, float sample_r)
1883{
1884 m_left.push_back (sample_l);
1885 m_right.push_back (sample_r);
1886 set_sample_number (get_sample_number () + 1);
1887}
1888
1889PaStream *
1890audiorecorder::get_stream ()
1891{
1892 return m_stream;
1893}
1894
1895#endif
1896
1897DEFUN_DLD (__recorder_audiorecorder__, args, ,
1898 doc: /* -*- texinfo -*-
1899@deftypefn {} {@var{recorder} =} __recorder_audiorecorder__ (@var{fs}, @var{nbits}, @var{channels})
1900@deftypefnx {} {@var{recorder} =} __recorder_audiorecorder__ (@var{fs}, @var{nbits}, @var{channels}, @var{id})
1901Undocumented internal function.
1902@end deftypefn */)
1903{
1904 octave_value retval;
1905
1906#if defined (HAVE_PORTAUDIO)
1907
1908 int nargin = args.length ();
1909
1910 audiorecorder *recorder = new audiorecorder ();
1911
1912 if (nargin >= 3)
1913 {
1914 recorder->set_fs (args(0).int_value ());
1915 recorder->set_nbits (args(1).int_value ());
1916 recorder->set_channels (args(2).int_value ());
1917 }
1918
1919 if (nargin == 4)
1920 {
1921 recorder->set_id (args(3).int_value ());
1922 }
1923
1924 recorder->init ();
1925 retval = recorder;
1926
1927#else
1928 octave_unused_parameter (args);
1929
1930 err_disabled_feature ("__recorder_audiorecorder__",
1931 "audio playback and recording through PortAudio");
1932#endif
1933
1934 return retval;
1935}
1936
1937#if defined (HAVE_PORTAUDIO)
1938
1939static audiorecorder *
1940get_recorder (const octave_value& ov)
1941{
1942 const octave_base_value& rep = ov.get_rep ();
1943
1944 octave_base_value *ncrep = const_cast<octave_base_value *> (&rep);
1945
1946 audiorecorder *rec = dynamic_cast<audiorecorder *> (ncrep);
1947 if (! rec)
1948 error ("audiodevinfo.cc (get_recorder): dynamic_cast to audiorecorder failed");
1949
1950 return rec;
1951}
1952
1953#endif
1954
1955DEFUN_DLD (__recorder_getaudiodata__, args, ,
1956 doc: /* -*- texinfo -*-
1957@deftypefn {} {@var{data} =} __recorder_getaudiodata__ (@var{recorder})
1958Undocumented internal function.
1959@end deftypefn */)
1960{
1961 octave_value retval;
1962
1963#if defined (HAVE_PORTAUDIO)
1964 retval = get_recorder (args(0))->getaudiodata ();
1965#else
1966 octave_unused_parameter (args);
1967
1968 err_disabled_feature ("__recorder_getaudiodata__",
1969 "audio playback and recording through PortAudio");
1970#endif
1971
1972 return retval;
1973}
1974
1975DEFUN_DLD (__recorder_get_channels__, args, ,
1976 doc: /* -*- texinfo -*-
1977@deftypefn {} {@var{n} =} __recorder_get_channels__ (@var{recorder})
1978Undocumented internal function.
1979@end deftypefn */)
1980{
1981 octave_value retval;
1982
1983#if defined (HAVE_PORTAUDIO)
1984 retval = get_recorder (args(0))->get_channels ();
1985#else
1986 octave_unused_parameter (args);
1987
1988 err_disabled_feature ("__recorder_get_channels__",
1989 "audio playback and recording through PortAudio");
1990#endif
1991
1992 return retval;
1993}
1994
1995DEFUN_DLD (__recorder_get_fs__, args, ,
1996 doc: /* -*- texinfo -*-
1997@deftypefn {} {@var{fs} =} __recorder_get_fs__ (@var{recorder})
1998Undocumented internal function.
1999@end deftypefn */)
2000{
2001 octave_value retval;
2002
2003#if defined (HAVE_PORTAUDIO)
2004 retval = get_recorder (args(0))->get_fs ();
2005#else
2006 octave_unused_parameter (args);
2007
2008 err_disabled_feature ("__recorder_get_fs__",
2009 "audio playback and recording through PortAudio");
2010#endif
2011
2012 return retval;
2013}
2014
2015DEFUN_DLD (__recorder_get_id__, args, ,
2016 doc: /* -*- texinfo -*-
2017@deftypefn {} {@var{id} =} __recorder_get_id__ (@var{recorder})
2018Undocumented internal function.
2019@end deftypefn */)
2020{
2021 octave_value retval;
2022
2023#if defined (HAVE_PORTAUDIO)
2024 retval = get_recorder (args(0))->get_id ();
2025#else
2026 octave_unused_parameter (args);
2027
2028 err_disabled_feature ("__recorder_get_id__",
2029 "audio playback and recording through PortAudio");
2030#endif
2031
2032 return retval;
2033}
2034
2035DEFUN_DLD (__recorder_get_nbits__, args, ,
2036 doc: /* -*- texinfo -*-
2037@deftypefn {} {@var{nbits} =} __recorder_get_nbits__ (@var{recorder})
2038Undocumented internal function.
2039@end deftypefn */)
2040{
2041 octave_value retval;
2042
2043#if defined (HAVE_PORTAUDIO)
2044 retval = get_recorder (args(0))->get_nbits ();
2045#else
2046 octave_unused_parameter (args);
2047
2048 err_disabled_feature ("__recorder_get_nbits__",
2049 "audio playback and recording through PortAudio");
2050#endif
2051
2052 return retval;
2053}
2054
2055DEFUN_DLD (__recorder_get_sample_number__, args, ,
2056 doc: /* -*- texinfo -*-
2057@deftypefn {} {@var{n} =} __recorder_get_sample_number__ (@var{recorder})
2058Undocumented internal function.
2059@end deftypefn */)
2060{
2061 octave_value retval;
2062
2063#if defined (HAVE_PORTAUDIO)
2064 retval = get_recorder (args(0))->get_sample_number ();
2065#else
2066 octave_unused_parameter (args);
2067
2068 err_disabled_feature ("__recorder_get_sample_number__",
2069 "audio playback and recording through PortAudio");
2070#endif
2071
2072 return retval;
2073}
2074
2075DEFUN_DLD (__recorder_get_tag__, args, ,
2076 doc: /* -*- texinfo -*-
2077@deftypefn {} {@var{tag} =} __recorder_get_tag__ (@var{recorder})
2078Undocumented internal function.
2079@end deftypefn */)
2080{
2081 octave_value retval;
2082
2083#if defined (HAVE_PORTAUDIO)
2084 retval = get_recorder (args(0))->get_tag ();
2085#else
2086 octave_unused_parameter (args);
2087
2088 err_disabled_feature ("__recorder_get_tag__",
2089 "audio playback and recording through PortAudio");
2090#endif
2091
2092 return retval;
2093}
2094
2095DEFUN_DLD (__recorder_get_total_samples__, args, ,
2096 doc: /* -*- texinfo -*-
2097@deftypefn {} {@var{n} =} __recorder_get_total_samples__ (@var{recorder})
2098Undocumented internal function.
2099@end deftypefn */)
2100{
2101 octave_value retval;
2102
2103#if defined (HAVE_PORTAUDIO)
2104 retval = get_recorder (args(0))->get_total_samples ();
2105#else
2106 octave_unused_parameter (args);
2107
2108 err_disabled_feature ("__recorder_get_total_samples__",
2109 "audio playback and recording through PortAudio");
2110#endif
2111
2112 return retval;
2113}
2114
2115DEFUN_DLD (__recorder_get_userdata__, args, ,
2116 doc: /* -*- texinfo -*-
2117@deftypefn {} {@var{data} =} __recorder_get_userdata__ (@var{recorder})
2118Undocumented internal function.
2119@end deftypefn */)
2120{
2121 octave_value retval;
2122
2123#if defined (HAVE_PORTAUDIO)
2124 retval = get_recorder (args(0))->get_userdata ();
2125#else
2126 octave_unused_parameter (args);
2127
2128 err_disabled_feature ("__recorder_get_userdata__",
2129 "audio playback and recording through PortAudio");
2130#endif
2131
2132 return retval;
2133}
2134
2135DEFUN_DLD (__recorder_isrecording__, args, ,
2136 doc: /* -*- texinfo -*-
2137@deftypefn {} {@var{tf} =} __recorder_isrecording__ (@var{recorder})
2138Undocumented internal function.
2139@end deftypefn */)
2140{
2141 octave_value retval;
2142
2143#if defined (HAVE_PORTAUDIO)
2144 retval = get_recorder (args(0))->isrecording ();
2145#else
2146 octave_unused_parameter (args);
2147
2148 err_disabled_feature ("__recorder_isrecording__",
2149 "audio playback and recording through PortAudio");
2150#endif
2151
2152 return retval;
2153}
2154
2155DEFUN_DLD (__recorder_pause__, args, ,
2156 doc: /* -*- texinfo -*-
2157@deftypefn {} {} __recorder_pause__ (@var{recorder})
2158Undocumented internal function.
2159@end deftypefn */)
2160{
2161#if defined (HAVE_PORTAUDIO)
2162 get_recorder (args(0))->pause ();
2163 return ovl ();
2164#else
2165 octave_unused_parameter (args);
2166
2167 err_disabled_feature ("__recorder_pause__",
2168 "audio playback and recording through PortAudio");
2169#endif
2170}
2171
2172DEFUN_DLD (__recorder_recordblocking__, args, ,
2173 doc: /* -*- texinfo -*-
2174@deftypefn {} {} __recorder_recordblocking__ (@var{recorder}, @var{seconds})
2175Undocumented internal function.
2176@end deftypefn */)
2177{
2178#if defined (HAVE_PORTAUDIO)
2179 float seconds = args(1).float_value ();
2180 get_recorder (args(0))->recordblocking (seconds);
2181 return ovl ();
2182#else
2183 octave_unused_parameter (args);
2184
2185 err_disabled_feature ("__recorder_recordblocking__",
2186 "audio playback and recording through PortAudio");
2187#endif
2188}
2189
2190DEFUN_DLD (__recorder_record__, args, ,
2191 doc: /* -*- texinfo -*-
2192@deftypefn {} {} __recorder_record__ (@var{recorder})
2193@deftypefnx {} {} __recorder_record__ (@var{recorder}, @var{seconds})
2194Undocumented internal function.
2195@end deftypefn */)
2196{
2197#if defined (HAVE_PORTAUDIO)
2198 audiorecorder *recorder = get_recorder (args(0));
2199
2200 if (args.length () == 2)
2201 recorder->set_end_sample (args(1).int_value () * recorder->get_fs ());
2202
2203 recorder->record ();
2204 return ovl ();
2205#else
2206 octave_unused_parameter (args);
2207
2208 err_disabled_feature ("__recorder_record__",
2209 "audio playback and recording through PortAudio");
2210#endif
2211}
2212
2213DEFUN_DLD (__recorder_resume__, args, ,
2214 doc: /* -*- texinfo -*-
2215@deftypefn {} {} __recorder_resume__ (@var{recorder})
2216Undocumented internal function.
2217@end deftypefn */)
2218{
2219#if defined (HAVE_PORTAUDIO)
2220 if (args.length () == 1)
2221 get_recorder (args(0))->resume ();
2222 return ovl ();
2223#else
2224 octave_unused_parameter (args);
2225
2226 err_disabled_feature ("__recorder_resume__",
2227 "audio playback and recording through PortAudio");
2228#endif
2229}
2230
2231DEFUN_DLD (__recorder_set_fs__, args, ,
2232 doc: /* -*- texinfo -*-
2233@deftypefn {} {} __recorder_set_fs__ (@var{recorder}, @var{fs})
2234Undocumented internal function.
2235@end deftypefn */)
2236{
2237#if defined (HAVE_PORTAUDIO)
2238 if (args.length () == 2)
2239 get_recorder (args(0))->set_fs (args(1).int_value ());
2240 return ovl ();
2241#else
2242 octave_unused_parameter (args);
2243
2244 err_disabled_feature ("__recorder_set_fs__",
2245 "audio playback and recording through PortAudio");
2246#endif
2247}
2248
2249DEFUN_DLD (__recorder_set_tag__, args, ,
2250 doc: /* -*- texinfo -*-
2251@deftypefn {} {} __recorder_set_tag__ (@var{recorder}, @var{tag})
2252Undocumented internal function.
2253@end deftypefn */)
2254{
2255#if defined (HAVE_PORTAUDIO)
2256 if (args.length () == 2)
2257 get_recorder (args(0))->set_tag (args(1).char_matrix_value ());
2258 return ovl ();
2259#else
2260 octave_unused_parameter (args);
2261
2262 err_disabled_feature ("__recorder_set_tag__",
2263 "audio playback and recording through PortAudio");
2264#endif
2265}
2266
2267DEFUN_DLD (__recorder_set_userdata__, args, ,
2268 doc: /* -*- texinfo -*-
2269@deftypefn {} {} __recorder_set_userdata__ (@var{recorder}, @var{data})
2270Undocumented internal function.
2271@end deftypefn */)
2272{
2273#if defined (HAVE_PORTAUDIO)
2274 if (args.length () == 2)
2275 get_recorder (args(0))->set_userdata (args(1));
2276 return ovl ();
2277#else
2278 octave_unused_parameter (args);
2279
2280 err_disabled_feature ("__recorder_set_userdata__",
2281 "audio playback and recording through PortAudio");
2282#endif
2283}
2284
2285DEFUN_DLD (__recorder_stop__, args, ,
2286 doc: /* -*- texinfo -*-
2287@deftypefn {} {} __recorder_stop__ (@var{recorder})
2288Undocumented internal function.
2289@end deftypefn */)
2290{
2291#if defined (HAVE_PORTAUDIO)
2292 if (args.length () == 1)
2293 get_recorder (args(0))->stop ();
2294 return ovl ();
2295#else
2296 octave_unused_parameter (args);
2297
2298 err_disabled_feature ("__recorder_stop__",
2299 "audio playback and recording through PortAudio");
2300#endif
2301}
2302
2303DEFUN_DLD (__player_audioplayer__, args, ,
2304 doc: /* -*- texinfo -*-
2305@deftypefn {} {@var{player} =} __player_audioplayer__ (@var{y}, @var{fs})
2306@deftypefnx {} {@var{player} =} __player_audioplayer__ (@var{y}, @var{fs}, @var{nbits})
2307@deftypefnx {} {@var{player} =} __player_audioplayer__ (@var{y}, @var{fs}, @var{nbits}, @var{id})
2308Undocumented internal function.
2309@end deftypefn */)
2310{
2311 octave_value retval;
2312
2313#if defined (HAVE_PORTAUDIO)
2314
2315 audioplayer *recorder = new audioplayer ();
2316
2317 recorder->set_y (args(0));
2318 recorder->set_fs (args(1).int_value ());
2319
2320 if (args.length () > 2)
2321 {
2322 // FIXME: Should be able to support 32-bit streams (bug #57939)
2323 int m_nbits = args(2).int_value ();
2324 if (m_nbits != 8 && m_nbits != 16 && m_nbits != 24)
2325 error ("audioplayer: NBITS must be 8, 16, or 24");
2326
2327 switch (args.length ())
2328 {
2329 case 3:
2330 recorder->set_nbits (m_nbits);
2331 break;
2332
2333 case 4:
2334 recorder->set_nbits (m_nbits);
2335 recorder->set_id (args(3).int_value ());
2336 break;
2337 }
2338 }
2339
2340 recorder->init ();
2341
2342 retval = recorder;
2343#else
2344 octave_unused_parameter (args);
2345
2346 err_disabled_feature ("__player_audioplayer__",
2347 "audio playback and recording through PortAudio");
2348#endif
2349
2350 return retval;
2351}
2352
2353#if defined (HAVE_PORTAUDIO)
2354
2355static audioplayer *
2356get_player (const octave_value& ov)
2357{
2358 const octave_base_value& rep = ov.get_rep ();
2359
2360 octave_base_value *ncrep = const_cast<octave_base_value *> (&rep);
2361
2362 audioplayer *pl = dynamic_cast<audioplayer *> (ncrep);
2363 if (! pl)
2364 error ("audiodevinfo.cc (get_player): dynamic_cast to audioplayer failed");
2365
2366 return pl;
2367}
2368
2369#endif
2370
2371DEFUN_DLD (__player_get_channels__, args, ,
2372 doc: /* -*- texinfo -*-
2373@deftypefn {} {@var{n} =} __player_get_channels__ (@var{player})
2374Undocumented internal function.
2375@end deftypefn */)
2376{
2377 octave_value retval;
2378
2379#if defined (HAVE_PORTAUDIO)
2380 if (args.length () == 1)
2381 retval = get_player (args(0))->get_channels ();
2382#else
2383 octave_unused_parameter (args);
2384
2385 err_disabled_feature ("__player_get_channels__",
2386 "audio playback and recording through PortAudio");
2387#endif
2388
2389 return retval;
2390}
2391
2392DEFUN_DLD (__player_get_fs__, args, ,
2393 doc: /* -*- texinfo -*-
2394@deftypefn {} {@var{fs} =} __player_get_fs__ (@var{player})
2395Undocumented internal function.
2396@end deftypefn */)
2397{
2398 octave_value retval;
2399
2400#if defined (HAVE_PORTAUDIO)
2401 if (args.length () == 1)
2402 retval = get_player (args(0))->get_fs ();
2403#else
2404 octave_unused_parameter (args);
2405
2406 err_disabled_feature ("__player_get_fs__",
2407 "audio playback and recording through PortAudio");
2408#endif
2409
2410 return retval;
2411}
2412
2413DEFUN_DLD (__player_get_id__, args, ,
2414 doc: /* -*- texinfo -*-
2415@deftypefn {} {@var{id} =} __player_get_id__ (@var{player})
2416Undocumented internal function.
2417@end deftypefn */)
2418{
2419 octave_value retval;
2420
2421#if defined (HAVE_PORTAUDIO)
2422 if (args.length () == 1)
2423 retval = get_player (args(0))->get_id ();
2424#else
2425 octave_unused_parameter (args);
2426
2427 err_disabled_feature ("__player_get_id__",
2428 "audio playback and recording through PortAudio");
2429#endif
2430
2431 return retval;
2432}
2433
2434DEFUN_DLD (__player_get_nbits__, args, ,
2435 doc: /* -*- texinfo -*-
2436@deftypefn {} {@var{nbits} =} __player_get_nbits__ (@var{player})
2437Undocumented internal function.
2438@end deftypefn */)
2439{
2440 octave_value retval;
2441
2442#if defined (HAVE_PORTAUDIO)
2443 if (args.length () == 1)
2444 retval = get_player (args(0))->get_nbits ();
2445#else
2446 octave_unused_parameter (args);
2447
2448 err_disabled_feature ("__player_get_nbits__",
2449 "audio playback and recording through PortAudio");
2450#endif
2451
2452 return retval;
2453}
2454
2455DEFUN_DLD (__player_get_sample_number__, args, ,
2456 doc: /* -*- texinfo -*-
2457@deftypefn {} {@var{n} =} __player_get_sample_number__ (@var{player})
2458Undocumented internal function.
2459@end deftypefn */)
2460{
2461 octave_value retval;
2462
2463#if defined (HAVE_PORTAUDIO)
2464 if (args.length () == 1)
2465 retval = get_player (args(0))->get_sample_number ();
2466#else
2467 octave_unused_parameter (args);
2468
2469 err_disabled_feature ("__player_get_sample_number__",
2470 "audio playback and recording through PortAudio");
2471#endif
2472
2473 return retval;
2474}
2475
2476DEFUN_DLD (__player_get_tag__, args, ,
2477 doc: /* -*- texinfo -*-
2478@deftypefn {} {@var{tag} =} __player_get_tag__ (@var{player})
2479Undocumented internal function.
2480@end deftypefn */)
2481{
2482 octave_value retval;
2483
2484#if defined (HAVE_PORTAUDIO)
2485 if (args.length () == 1)
2486 retval = get_player (args(0))->get_tag ();
2487#else
2488 octave_unused_parameter (args);
2489
2490 err_disabled_feature ("__player_get_tag__",
2491 "audio playback and recording through PortAudio");
2492#endif
2493
2494 return retval;
2495}
2496
2497DEFUN_DLD (__player_get_total_samples__, args, ,
2498 doc: /* -*- texinfo -*-
2499@deftypefn {} {@var{n} =} __player_get_total_samples__ (@var{player})
2500Undocumented internal function.
2501@end deftypefn */)
2502{
2503 octave_value retval;
2504
2505#if defined (HAVE_PORTAUDIO)
2506 if (args.length () == 1)
2507 retval = get_player (args(0))->get_total_samples ();
2508#else
2509 octave_unused_parameter (args);
2510
2511 err_disabled_feature ("__player_get_total_samples__",
2512 "audio playback and recording through PortAudio");
2513#endif
2514
2515 return retval;
2516}
2517
2518DEFUN_DLD (__player_get_userdata__, args, ,
2519 doc: /* -*- texinfo -*-
2520@deftypefn {} {@var{data} =} __player_get_userdata__ (@var{player})
2521Undocumented internal function.
2522@end deftypefn */)
2523{
2524 octave_value retval;
2525
2526#if defined (HAVE_PORTAUDIO)
2527 if (args.length () == 1)
2528 retval = get_player (args(0))->get_userdata ();
2529#else
2530 octave_unused_parameter (args);
2531
2532 err_disabled_feature ("__player_get_userdata__",
2533 "audio playback and recording through PortAudio");
2534#endif
2535
2536 return retval;
2537}
2538
2539DEFUN_DLD (__player_isplaying__, args, ,
2540 doc: /* -*- texinfo -*-
2541@deftypefn {} {@var{tf} =} __player_isplaying__ (@var{player})
2542Undocumented internal function.
2543@end deftypefn */)
2544{
2545 octave_value retval;
2546
2547#if defined (HAVE_PORTAUDIO)
2548 if (args.length () == 1)
2549 retval = get_player (args(0))->isplaying ();
2550#else
2551 octave_unused_parameter (args);
2552
2553 err_disabled_feature ("__player_isplaying__",
2554 "audio playback and recording through PortAudio");
2555#endif
2556
2557 return retval;
2558}
2559
2560DEFUN_DLD (__player_pause__, args, ,
2561 doc: /* -*- texinfo -*-
2562@deftypefn {} {} __player_pause__ (@var{player})
2563Undocumented internal function.
2564@end deftypefn */)
2565{
2566#if defined (HAVE_PORTAUDIO)
2567 if (args.length () == 1)
2568 get_player (args(0))->pause ();
2569 return ovl ();
2570#else
2571 octave_unused_parameter (args);
2572
2573 err_disabled_feature ("__player_pause__",
2574 "audio playback and recording through PortAudio");
2575#endif
2576}
2577
2578DEFUN_DLD (__player_playblocking__, args, ,
2579 doc: /* -*- texinfo -*-
2580@deftypefn {} {} __player_playblocking__ (@var{player})
2581@deftypefnx {} {} __player_playblocking__ (@var{player}, @var{start})
2582@deftypefnx {} {} __player_playblocking__ (@var{player}, [@var{start}, @var{end}])
2583Undocumented internal function.
2584@end deftypefn */)
2585{
2586#if defined (HAVE_PORTAUDIO)
2587
2588 audioplayer *player = get_player (args(0));
2589
2590 if (args.length () == 1)
2591 {
2592 player->playblocking ();
2593 }
2594 else if (args.length () == 2)
2595 {
2596 if (args(1).is_matrix_type ())
2597 {
2598 RowVector range = args(1).row_vector_value ();
2599
2600 unsigned int start = range.elem (0) - 1;
2601 unsigned int end = range.elem (1) - 1;
2602
2603 if (start > player->get_total_samples ()
2604 || start > end || end > player->get_total_samples ())
2605 error ("audioplayer: invalid range specified for playback");
2606
2607 player->set_sample_number (start);
2608 player->set_end_sample (end);
2609 }
2610 else
2611 {
2612 unsigned int start = args(1).int_value () - 1;
2613
2614 if (start > player->get_total_samples ())
2615 error ("audioplayer: invalid range specified for playback");
2616
2617 player->set_sample_number (start);
2618 }
2619
2620 player->playblocking ();
2621 }
2622
2623 return ovl ();
2624#else
2625 octave_unused_parameter (args);
2626
2627 err_disabled_feature ("__player_playblocking__",
2628 "audio playback and recording through PortAudio");
2629#endif
2630}
2631
2632DEFUN_DLD (__player_play__, args, ,
2633 doc: /* -*- texinfo -*-
2634@deftypefn {} {} __player_play__ (@var{player})
2635@deftypefnx {} {} __player_play__ (@var{player}, @var{start})
2636@deftypefnx {} {} __player_play__ (@var{player}, [@var{start}, @var{end}])
2637Undocumented internal function.
2638@end deftypefn */)
2639{
2640#if defined (HAVE_PORTAUDIO)
2641
2642 if (args.length () == 1)
2643 {
2644 get_player (args(0))->play ();
2645 }
2646 else if (args.length () == 2)
2647 {
2648 audioplayer *player = get_player (args(0));
2649
2650 if (args(1).is_matrix_type ())
2651 {
2652 RowVector range = args(1).row_vector_value ();
2653
2654 unsigned int start = range.elem (0) - 1;
2655 unsigned int end = range.elem (1) - 1;
2656
2657 if (start > player->get_total_samples ()
2658 || start > end || end > player->get_total_samples ())
2659 error ("audioplayer: invalid range specified for playback");
2660
2661 player->set_sample_number (start);
2662 player->set_end_sample (end);
2663 }
2664 else
2665 {
2666 unsigned int start = args(1).int_value () - 1;
2667
2668 if (start > player->get_total_samples ())
2669 error ("audioplayer: invalid range specified for playback");
2670
2671 player->set_sample_number (start);
2672 }
2673
2674 player->play ();
2675 }
2676
2677 return ovl ();
2678#else
2679 octave_unused_parameter (args);
2680
2681 err_disabled_feature ("__player_play__",
2682 "audio playback and recording through PortAudio");
2683#endif
2684}
2685
2686DEFUN_DLD (__player_resume__, args, ,
2687 doc: /* -*- texinfo -*-
2688@deftypefn {} {} __player_resume__ (@var{player})
2689Undocumented internal function.
2690@end deftypefn */)
2691{
2692#if defined (HAVE_PORTAUDIO)
2693 if (args.length () == 1)
2694 get_player (args(0))->resume ();
2695 return ovl ();
2696#else
2697 octave_unused_parameter (args);
2698
2699 err_disabled_feature ("__player_resume__",
2700 "audio playback and recording through PortAudio");
2701#endif
2702}
2703
2704DEFUN_DLD (__player_set_fs__, args, ,
2705 doc: /* -*- texinfo -*-
2706@deftypefn {} {} __player_set_fs__ (@var{player}, @var{fs})
2707Undocumented internal function.
2708@end deftypefn */)
2709{
2710#if defined (HAVE_PORTAUDIO)
2711 if (args.length () == 2)
2712 get_player (args(0))->set_fs (args(1).int_value ());
2713 return ovl ();
2714#else
2715 octave_unused_parameter (args);
2716
2717 err_disabled_feature ("__player_set_fs__",
2718 "audio playback and recording through PortAudio");
2719#endif
2720}
2721
2722DEFUN_DLD (__player_set_tag__, args, ,
2723 doc: /* -*- texinfo -*-
2724@deftypefn {} {} __player_set_tag__ (@var{player}, @var{tag})
2725Undocumented internal function.
2726@end deftypefn */)
2727{
2728#if defined (HAVE_PORTAUDIO)
2729 if (args.length () == 2)
2730 get_player (args(0))->set_tag (args(1).char_matrix_value ());
2731 return ovl ();
2732#else
2733 octave_unused_parameter (args);
2734
2735 err_disabled_feature ("__player_set_tag__",
2736 "audio playback and recording through PortAudio");
2737#endif
2738}
2739
2740DEFUN_DLD (__player_set_userdata__, args, ,
2741 doc: /* -*- texinfo -*-
2742@deftypefn {} {} __player_set_userdata__ (@var{player}, @var{data})
2743Undocumented internal function.
2744@end deftypefn */)
2745{
2746#if defined (HAVE_PORTAUDIO)
2747 if (args.length () == 2)
2748 get_player (args(0))->set_userdata (args(1));
2749 return ovl ();
2750#else
2751 octave_unused_parameter (args);
2752
2753 err_disabled_feature ("__player_set_userdata__",
2754 "audio playback and recording through PortAudio");
2755#endif
2756}
2757
2758DEFUN_DLD (__player_stop__, args, ,
2759 doc: /* -*- texinfo -*-
2760@deftypefn {} {} __player_stop__ (@var{player})
2761Undocumented internal function.
2762@end deftypefn */)
2763{
2764#if defined (HAVE_PORTAUDIO)
2765 if (args.length () == 1)
2766 get_player (args(0))->stop ();
2767 return ovl ();
2768#else
2769 octave_unused_parameter (args);
2770
2771 err_disabled_feature ("__player_stop__",
2772 "audio playback and recording through PortAudio");
2773#endif
2774}
2775
2776OCTAVE_END_NAMESPACE(octave)
octave_idx_type rows() const
Definition Array.h:463
octave_idx_type columns() const
Definition Array.h:475
const T * data() const
Size of the specified dimension.
Definition Array.h:665
Definition Cell.h:41
Matrix transpose() const
Definition dMatrix.h:138
void resize(octave_idx_type nr, octave_idx_type nc, double rfv=0)
Definition dMatrix.h:156
ColumnVector column(octave_idx_type i) const
Definition dMatrix.cc:423
Vector representing the dimensions (size) of an Array.
Definition dim-vector.h:90
octave_value_list feval(const char *name, const octave_value_list &args=octave_value_list(), int nargout=0)
Evaluate an Octave function (built-in or interpreted) and return the list of result values.
virtual bool is_constant() const
Definition ov-base.h:535
virtual void print_raw(std::ostream &os, bool pr_as_read_syntax=false) const
Definition ov-base.cc:463
virtual bool print_as_scalar() const
Definition ov-base.h:746
virtual double scalar_value(bool frc_str_conv=false) const
Definition ov-base.h:600
virtual void print(std::ostream &os, bool pr_as_read_syntax=false)
Definition ov-base.cc:457
virtual bool is_defined() const
Definition ov-base.h:423
void setfield(const std::string &key, const Cell &val)
Definition oct-map.cc:282
void setfield(const std::string &key, const octave_value &val)
Definition oct-map.cc:190
octave_idx_type length() const
Definition ovl.h:111
const octave_base_value & get_rep() const
Definition ov.h:1374
int int_value(bool req_int=false, bool frc_str_conv=false) const
Definition ov.h:812
bool is_int8_type() const
Definition ov.h:706
Matrix size()
Definition ov.h:462
bool is_uint8_type() const
Definition ov.h:718
bool is_int16_type() const
Definition ov.h:709
Matrix matrix_value(bool frc_str_conv=false) const
Definition ov.h:859
OCTAVE_BEGIN_NAMESPACE(octave) static octave_value daspk_fcn
#define DEFUN_DLD(name, args_name, nargout_name, doc)
Macro to define an at run time dynamically loadable builtin function.
Definition defun-dld.h:61
void print_usage()
Definition defun-int.h:72
void warning_with_id(const char *id, const char *fmt,...)
Definition error.cc:1093
void error(const char *fmt,...)
Definition error.cc:1003
void err_disabled_feature(const std::string &fcn, const std::string &feature, const std::string &pkg)
Definition errwarn.cc:53
interpreter & __get_interpreter__()
#define OCTAVE_LOCAL_BUFFER(T, buf, size)
Definition oct-locbuf.h:44
#define DECLARE_OV_TYPEID_FUNCTIONS_AND_DATA
Definition ov-base.h:181
#define DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA(t, n, c)
Definition ov-base.h:246
octave_value_list ovl(const OV_Args &... args)
Construct an octave_value_list with less typing.
Definition ovl.h:217
std::size_t format(std::ostream &os, const char *fmt,...)
Definition utils.cc:1514