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