Mercurial > octave
changeset 27882:65a54ab6ceaa
Workaround for a bug in PortAudio 8-bit recording (bug #44305).
Detect 8-bit format and call PortAudio in 16-bit format instead,
and then scale to 8-bit.
* audiodevinfo.cc (audiorecorder): Add new member function get_sampleFormat.
* audiodevinfo.cc (audiorecorder::get_sampleFormat): New member function.
* audiodevinfo.cc (octave_record_callback, portaudio_record_callback): Correct
text in error() meessage. Use new get_sampleFormat to find number of bits in
requested. Detect 16-bit format where number of bits is 8 and use special case
code to discard lower 8 bits of recorded data and then scale to 8-bits.
author | Lars Kindermann <lars.kindermann@reglos.de> |
---|---|
date | Sun, 24 Nov 2019 12:54:59 +0100 |
parents | f5e1072f1635 |
children | 8675d88a0e26 |
files | libinterp/dldfcn/audiodevinfo.cc |
diffstat | 1 files changed, 60 insertions(+), 8 deletions(-) [+] |
line wrap: on
line diff
--- a/libinterp/dldfcn/audiodevinfo.cc Sun Dec 29 12:40:07 2019 +0100 +++ b/libinterp/dldfcn/audiodevinfo.cc Sun Nov 24 12:54:59 2019 +0100 @@ -1243,6 +1243,7 @@ int get_fs (void); void set_nbits (int nbits); int get_nbits (void); + PaSampleFormat get_sampleFormat (void); void set_id (int id); int get_id (void); void set_channels (int channels); @@ -1303,14 +1304,14 @@ audiorecorder *recorder = static_cast<audiorecorder *> (data); if (! recorder) - error ("audio recorder callback function called without player"); + error ("audio recorder callback function called without recorder"); int channels = recorder->get_channels (); Matrix sound (frames, 2); sound.resize (frames, 2); - if (recorder->get_nbits () == 8) + if (recorder->get_sampleFormat () == bits_to_format (8)) { static double scale_factor = std::pow (2.0, 7) - 1.0; @@ -1325,7 +1326,27 @@ sound(i,1) = sample_r; } } - else if (recorder->get_nbits () == 16) + // FIXME: This is a workaround for a bug in PortAudio affecting 8-Bit + // recording (see Octave bug #44305). + // Remove this clause once the bug in PortAudio has been fixed. + else if (recorder->get_sampleFormat () == bits_to_format (16) + && recorder->get_nbits () == 8) + { + static double scale_factor = std::pow (2.0, 7) - 1.0; + + const int16_t *input16 = static_cast<const int16_t *> (input); + + for (unsigned long i = 0; i < frames; i++) + { + float sample_l = (input16[i*channels] >> 8) / scale_factor; + float sample_r = (input16[i*channels + (channels - 1)] >> 8) + / scale_factor; + + sound(i,0) = sample_l; + sound(i,1) = sample_r; + } + } + else if (recorder->get_sampleFormat () == bits_to_format (16)) { static double scale_factor = std::pow (2.0, 15) - 1.0; @@ -1340,7 +1361,7 @@ sound(i,1) = sample_r; } } - else if (recorder->get_nbits () == 24) + else if (recorder->get_sampleFormat () == bits_to_format (24)) { static double scale_factor = std::pow (2.0, 23); @@ -1386,11 +1407,11 @@ audiorecorder *recorder = static_cast<audiorecorder *> (data); if (! recorder) - error ("audio recorder callback function called without player"); + error ("audio recorder callback function called without recorder"); int channels = recorder->get_channels (); - if (recorder->get_nbits () == 8) + if (recorder->get_sampleFormat () == bits_to_format (8)) { static float scale_factor = std::pow (2.0f, 7) - 1.0f; @@ -1404,7 +1425,26 @@ recorder->append (sample_l, sample_r); } } - else if (recorder->get_nbits () == 16) + // FIXME: This is a workaround for a bug in PortAudio affecting 8-Bit + // recording (see Octave bug #44305). + // Remove this clause once the bug in PortAudio has been fixed. + else if (recorder->get_sampleFormat () == bits_to_format (16) + && recorder->get_nbits () == 8) + { + static double scale_factor = std::pow (2.0, 7) - 1.0; + + const int16_t *input16 = static_cast<const int16_t *> (input); + + for (unsigned long i = 0; i < frames; i++) + { + float sample_l = (input16[i*channels] >> 8) / scale_factor; + float sample_r = (input16[i*channels + (channels - 1)] >> 8) + / scale_factor; + + recorder->append (sample_l, sample_r); + } + } + else if (recorder->get_sampleFormat () == bits_to_format (16)) { static float scale_factor = std::pow (2.0f, 15) - 1.0f; @@ -1418,7 +1458,7 @@ recorder->append (sample_l, sample_r); } } - else if (recorder->get_nbits () == 24) + else if (recorder->get_sampleFormat () == bits_to_format (24)) { static float scale_factor = std::pow (2.0f, 23); @@ -1510,6 +1550,12 @@ input_parameters.channelCount = get_channels (); input_parameters.sampleFormat = bits_to_format (get_nbits ()); + // FIXME: This is a workaround for a bug in PortAudio affecting 8-Bit + // recording (see Octave bug #44305). + // Remove this clause once the bug in PortAudio has been fixed. + if (get_nbits () == 8) + input_parameters.sampleFormat = bits_to_format (16); + const PaDeviceInfo *device_info = Pa_GetDeviceInfo (device); if (! device_info) @@ -1546,6 +1592,12 @@ return nbits; } +PaSampleFormat +audiorecorder::get_sampleFormat (void) +{ + return input_parameters.sampleFormat; +} + void audiorecorder::set_id (int id_arg) {