# HG changeset patch # User John W. Eaton # Date 1420742294 18000 # Node ID e4bce89532bc33319d65f00c7ea15d3076b9471f # Parent 0083cc91bfaa22cc8ddd29bf8272fb19beb1d12a improve error checking and efficiency of octave audio callback function * audiodevinfo.cc (octave_play_callback): Check for non-null player object. Move computations of constant values outside of loop. Invert nesting of switch statements and loops. Use const pointer to data instead of RowVector::elem method. (portaudio_play_callback): Check for non-null player object. diff -r 0083cc91bfaa -r e4bce89532bc libinterp/dldfcn/audiodevinfo.cc --- a/libinterp/dldfcn/audiodevinfo.cc Thu Jan 08 13:20:47 2015 -0500 +++ b/libinterp/dldfcn/audiodevinfo.cc Thu Jan 08 13:38:14 2015 -0500 @@ -532,66 +532,124 @@ PaStreamCallbackFlags, void *data) { audioplayer *player = static_cast (data); - int big_endian = is_big_endian (); - octave_value_list args, retval; - args(0) = frames; - retval = feval (player->octave_callback_function, args, 1); - RowVector sound_l, sound_r; + + if (! player) + { + error ("audio player callback function called without player"); + return paAbort; + } + + octave_value_list retval = feval (player->octave_callback_function, + ovl (static_cast (frames)), 1); + + if (error_state || retval.length () < 2) + { + error ("audio player callback function failed"); + return paAbort; + } + Matrix sound = retval(0).matrix_value (); int return_status = retval(1).int_value (); - sound_l.resize (frames); - sound_r.resize (frames); - if (sound.cols () == 1) + + if (error_state || frames != sound.rows () + || sound.columns () < 1 || sound.columns () > 2) { - for (unsigned long i = 0; i < frames; i++) - { - sound_l(i) = sound(i, 0); - sound_r(i) = sound(i, 0); - } + error ("audio player callback function failed"); + return paAbort; } - else if (sound.cols () == 2) + + double scale_factor = 1.0; + + switch (player->get_nbits ()) { - for (unsigned long i = 0; i < frames; i++) - { - sound_l(i) = sound(i, 0); - sound_r(i) = sound(i, 1); - } + case 8: + scale_factor = pow (2.0, 7) - 1.0; + break; + + case 16: + scale_factor = pow (2.0, 15) - 1.0; + break; + + case 24: + scale_factor = pow (2.0, 23) - 1.0; + break; + + default: + error ("invalid player bit depth in callback function"); + break; } - else - return paAbort; - - for (unsigned long i = 0; i < frames; i++) + + sound = sound * scale_factor; + + const RowVector sound_l = (sound.column (0)).transpose (); + const RowVector sound_r = (sound.columns () == 1) + ? sound_l : (sound.column (1)).transpose (); + + const double *p_l = sound_l.data (); + const double *p_r = sound_r.data (); + + switch (player->get_nbits ()) { - if (player->get_nbits () == 8) - { - int8_t *buffer = static_cast (output); - buffer[2 * i] = sound_l.elem (i) * (pow (2.0, 7) - 1); - buffer[2 * i + 1] = sound_r.elem (i) * (pow (2.0, 7) - 1); - } - else if (player->get_nbits () == 16) - { - int16_t *buffer = static_cast (output); - buffer[2 * i] = sound_l.elem (i) * (pow (2.0, 15) - 1); - buffer[2 * i + 1] = sound_r.elem (i) * (pow (2.0, 15) - 1); - } - else if (player->get_nbits () == 24) - { - uint8_t *buffer = static_cast (output); - int32_t sample_l = sound_l.elem (i) * (pow (2.0, 23) - 1); - int32_t sample_r = sound_r.elem (i) * (pow (2.0, 23) - 1); - sample_l &= 0x00ffffff; - sample_r &= 0x00ffffff; - // FIXME: Would a mask work better? - uint8_t *_sample_l = reinterpret_cast (&sample_l); - uint8_t *_sample_r = reinterpret_cast (&sample_r); - buffer[i * 6 + 0] = _sample_l[0 + big_endian]; - buffer[i * 6 + 1] = _sample_l[1 + big_endian]; - buffer[i * 6 + 2] = _sample_l[2 + big_endian]; - buffer[i * 6 + 3] = _sample_r[0 + big_endian]; - buffer[i * 6 + 4] = _sample_r[1 + big_endian]; - buffer[i * 6 + 5] = _sample_r[2 + big_endian]; - } + case 8: + { + int8_t *buffer = static_cast (output); + + for (unsigned long i = 0; i < frames; i++) + { + buffer[2*i] = p_l[i]; + buffer[2*i+1] = p_r[i]; + } + } + break; + + case 16: + { + int16_t *buffer = static_cast (output); + + for (unsigned long i = 0; i < frames; i++) + { + buffer[2*i] = p_l[i]; + buffer[2*i+1] = p_r[i]; + } + } + break; + + case 24: + { + int big_endian = is_big_endian (); + + uint8_t *buffer = static_cast (output); + + for (unsigned long i = 0; i < frames; i++) + { + int32_t sample_l = p_l[i]; + int32_t sample_r = p_r[i]; + + sample_l &= 0x00ffffff; + sample_r &= 0x00ffffff; + + // FIXME: Would a mask work better? + uint8_t *_sample_l = reinterpret_cast (&sample_l); + uint8_t *_sample_r = reinterpret_cast (&sample_r); + + unsigned long offset = i * 6; + + buffer[offset+0] = _sample_l[0+big_endian]; + buffer[offset+1] = _sample_l[1+big_endian]; + buffer[offset+2] = _sample_l[2+big_endian]; + + buffer[offset+3] = _sample_r[0+big_endian]; + buffer[offset+4] = _sample_r[1+big_endian]; + buffer[offset+5] = _sample_r[2+big_endian]; + } + } + break; + + default: + error ("invalid player bit depth in callback function"); + break; } + return return_status; } @@ -602,6 +660,12 @@ { audioplayer *player = static_cast (data); + if (! player) + { + error ("audio player callback function called without player"); + return paAbort; + } + double scale_factor = 1.0; switch (player->get_nbits ())