# HG changeset patch # User Vytautas JanĨauskas # Date 1378926500 -10800 # Node ID 91ee78cdba6c97bcf436ed64622a6265745f33d0 # Parent 2e174b5e7703a3442c826fcbc74c847c1c12255d New files for audio playback and recording * player_class.cc, player_class.h: source files implementing player class for audio playback * recorder_class.cc, recorder_class.h: source files implementing recorder class for audio recording diff -r 2e174b5e7703 -r 91ee78cdba6c libinterp/dldfcn/player_class.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libinterp/dldfcn/player_class.cc Wed Sep 11 22:08:20 2013 +0300 @@ -0,0 +1,584 @@ +#include +#include +#include +#include +#include + +#include "common.h" +#include "player_class.h" + +#define BUFFER_SIZE 512 + +DEFINE_OCTAVE_ALLOCATOR (audioplayer); +DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (audioplayer, "audioplayer", "audioplayer"); + +int is_big_endian (void) +{ + union + { + uint32_t i; + char c[4]; + } bint = {0x01020304}; + return bint.c[0] == 1; +} + +static int octave_play_callback(const void *input, void *output, + unsigned long frames, + const PaStreamCallbackTimeInfo *time, + PaStreamCallbackFlags status, + void *data) +{ + audioplayer *player = (audioplayer *)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; + 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) + { + for (int i = 0; i < frames; i++) + { + sound_l(i) = sound(i, 0); + sound_r(i) = sound(i, 0); + } + } + else if (sound.cols () == 2) + { + for (int i = 0; i < frames; i++) + { + sound_l(i) = sound(i, 0); + sound_r(i) = sound(i, 1); + } + } + else + { + return paAbort; + } + for (int i = 0; i < frames; i++) + { + if (player->get_nbits () == 8) + { + int8_t *buffer = (int8_t *)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 = (int16_t *)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 = (uint8_t *)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; + uint8_t *_sample_l = (uint8_t *)&sample_l; + uint8_t *_sample_r = (uint8_t *)&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]; + } + } + return return_status; +} + +static int portaudio_play_callback (const void *input, void *output, + unsigned long frames, + const PaStreamCallbackTimeInfo* time, + PaStreamCallbackFlags status, + void *data) +{ + audioplayer *player = (audioplayer *)data; + int big_endian = is_big_endian (); + int channels = player->get_channels (); + RowVector *sound_l = player->get_left (); + RowVector *sound_r; + if (channels > 1) + { + sound_r = player->get_right (); + } + else + { + sound_r = sound_l; + } + for (int j = 0, k = 0; j < frames; j++, k += 2) + { + unsigned int sample_number = player->get_sample_number(); + if (sample_number > player->get_end_sample ()) + { + return paAbort; + } + if (player->get_type () == DOUBLE) + { + if (player->get_nbits () == 8) + { + int8_t *buffer = (int8_t *)output; + buffer[k] = sound_l->elem (sample_number) * (pow (2.0, 7) - 1); + buffer[k + 1] = sound_r->elem (sample_number) * (pow (2.0, 7) - 1); + } + else if (player->get_nbits () == 16) + { + int16_t *buffer = (int16_t *)output; + buffer[k] = sound_l->elem (sample_number) * (pow (2.0, 15) - 1); + buffer[k + 1] = sound_r->elem (sample_number) * (pow (2.0, 15) - 1); + } + else if (player->get_nbits() == 24) + { + uint8_t *buffer = (uint8_t *)output; + int32_t sample_l = sound_l->elem(sample_number) * (pow (2.0, 23) - 1); + int32_t sample_r = sound_r->elem(sample_number) * (pow (2.0, 23) - 1); + sample_l &= 0x00ffffff; + sample_r &= 0x00ffffff; + uint8_t *_sample_l = (uint8_t *)&sample_l; + uint8_t *_sample_r = (uint8_t *)&sample_r; + buffer[j * 6 + 0] = _sample_l[0 + big_endian]; + buffer[j * 6 + 1] = _sample_l[1 + big_endian]; + buffer[j * 6 + 2] = _sample_l[2 + big_endian]; + buffer[j * 6 + 3] = _sample_r[0 + big_endian]; + buffer[j * 6 + 4] = _sample_r[1 + big_endian]; + buffer[j * 6 + 5] = _sample_r[2 + big_endian]; + } + } + else if (player->get_type () == INT8) + { + int8_t *buffer = (int8_t *)output; + buffer[k] = sound_l->elem (sample_number); + buffer[k + 1] = sound_r->elem (sample_number); + } + else if (player->get_type () == UINT8) + { + uint8_t *buffer = (uint8_t *)output; + buffer[k] = sound_l->elem (sample_number); + buffer[k + 1] = sound_r->elem (sample_number); + } + else if (player->get_type () == INT16) + { + int16_t *buffer = (int16_t *)output; + buffer[k] = sound_l->elem (sample_number); + buffer[k + 1] = sound_r->elem (sample_number); + } + player->set_sample_number (sample_number + 1); + } + return paContinue; +} + +audioplayer::audioplayer () +{ + this->nbits = 16; + this->id = -1; + this->sample_number = 0; + this->tag = charMatrix (""); + Matrix userdata; + this->userdata = octave_value (userdata); + this->stream = 0; + this->octave_callback_function = 0; +} + +audioplayer::~audioplayer () +{ + +} + +void audioplayer::print (std::ostream& os, bool pr_as_read_syntax ) const +{ + print_raw (os, pr_as_read_syntax); + newline (os); +} + +void audioplayer::print_raw (std::ostream& os, bool pr_as_read_syntax) const +{ + os << 0; +} + +void audioplayer::init_fn() +{ + PaError err; + int device; + err = Pa_Initialize (); + if (err != paNoError) + { + error ("audioplayer: Initialization error!"); + return; + } + int numDevices; + numDevices = Pa_GetDeviceCount (); + if (numDevices < 0) + { + error ("audioplayer: No audio devices found!"); + return; + } + if (this->get_id () == -1) + { + device = Pa_GetDefaultOutputDevice (); + } + else + { + device = this->get_id (); + } + output_parameters.device = device; + output_parameters.channelCount = 2; + output_parameters.sampleFormat = bits_to_format (this->get_nbits ()); + output_parameters.suggestedLatency = Pa_GetDeviceInfo (device)->defaultHighOutputLatency; + output_parameters.hostApiSpecificStreamInfo = NULL; +} + +void audioplayer::init () +{ + PaError err; + int channels = this->y.rows (); + RowVector *sound_l = this->get_left (); + int device; + err = Pa_Initialize (); + if (err != paNoError) + { + error ("audioplayer: Initialization error!"); + return; + } + int numDevices; + numDevices = Pa_GetDeviceCount (); + if (numDevices < 0) + { + error ("audioplayer: No audio devices found!"); + return; + } + if (this->get_id () == -1) + { + device = Pa_GetDefaultOutputDevice (); + } + else + { + device = this->get_id (); + } + output_parameters.device = device; + output_parameters.channelCount = 2; + if (this->type == DOUBLE) + { + output_parameters.sampleFormat = bits_to_format (this->get_nbits ()); + } + else if (this->type == INT8) + { + output_parameters.sampleFormat = paInt8; + } + else if (this->type == UINT8) + { + output_parameters.sampleFormat = paUInt8; + } + else if (this->type == INT16) + { + output_parameters.sampleFormat = paInt16; + } + output_parameters.suggestedLatency = Pa_GetDeviceInfo (device)->defaultHighOutputLatency; + output_parameters.hostApiSpecificStreamInfo = NULL; +} + +void audioplayer::set_y (octave_value y) +{ + if (y.is_int8_type ()) + { + this->type = INT8; + } + else if (y.is_uint8_type ()) + { + this->type = UINT8; + } + else if (y.is_int16_type ()) + { + this->type = INT16; + } + else + { + this->type = DOUBLE; + } + this->y = y.matrix_value (); + if (this->y.rows () > 2) + { + this->y = this->y.transpose (); + } + this->channels = this->y.rows (); + this->left = this->y.row (0); + if (this->channels == 2) + { + this->right = this->y.row (1); + } + this->reset_end_sample (); +} + +void audioplayer::set_y (octave_function *fn) +{ + this->octave_callback_function = fn; + this->channels = 2; + this->reset_end_sample (); +} + +Matrix &audioplayer::get_y () +{ + return this->y; +} + +RowVector *audioplayer::get_left () +{ + return &(this->left); +} + +RowVector *audioplayer::get_right () +{ + return &(this->right); +} + +void audioplayer::set_fs (int fs) +{ + this->fs = fs; +} + +int audioplayer::get_fs () +{ + return this->fs; +} + +void audioplayer::set_nbits (int nbits) +{ + this->nbits = nbits; +} + +int audioplayer::get_nbits () +{ + return this->nbits; +} + +void audioplayer::set_id (int id) +{ + this->id = id; +} + +int audioplayer::get_id () +{ + return this->id; +} + +int audioplayer::get_channels () +{ + return this->channels; +} + +audio_type audioplayer::get_type () +{ + return this->type; +} + +void audioplayer::set_sample_number (unsigned int sample_number) +{ + this->sample_number = sample_number; +} + +unsigned int audioplayer::get_sample_number () +{ + return this->sample_number; +} + +unsigned int audioplayer::get_total_samples () +{ + return this->left.length (); +} + +void audioplayer::set_end_sample (unsigned int end_sample) +{ + this->end_sample = end_sample; +} + +unsigned int audioplayer::get_end_sample () +{ + return this->end_sample; +} + +void audioplayer::reset_end_sample () +{ + this->set_end_sample (this->left.length ()); +} + +void audioplayer::set_tag (charMatrix tag) +{ + this->tag = tag; +} + +charMatrix audioplayer::get_tag () +{ + return this->tag; +} + +void audioplayer::set_userdata (octave_value userdata) +{ + this->userdata = userdata; +} + +octave_value audioplayer::get_userdata () +{ + return this->userdata; +} + +void audioplayer::playblocking () +{ + if (this->get_stream ()) + { + this->stop (); + } + PaError err; + uint32_t buffer[BUFFER_SIZE * 2]; + err = Pa_OpenStream (&stream, NULL, &(this->output_parameters), this->get_fs (), BUFFER_SIZE, paClipOff, NULL, NULL); + if (err != paNoError) + { + error ("audioplayer: Error opening audio playback stream"); + return; + } + err = Pa_StartStream (stream); + if (err != paNoError) + { + error ("audioplayer: Error starting audio playback stream"); + return; + } + unsigned int start, end; + start = this->get_sample_number (); + end = this->get_end_sample (); + for (int i = start; i < end; i += BUFFER_SIZE) + { + if (this->octave_callback_function != 0) + { + octave_play_callback (0, (void *)buffer, BUFFER_SIZE, 0, 0, (void *)this); + } + else + { + portaudio_play_callback (0, (void *)buffer, BUFFER_SIZE, 0, 0, (void *)this); + } + err = Pa_WriteStream (stream, buffer, BUFFER_SIZE); + } + err = Pa_StopStream (stream); + if (err != paNoError) + { + error ("audioplayer: Error stoping audio playback stream"); + return; + } + err = Pa_CloseStream (stream); + if (err != paNoError) + { + error ("audioplayer: Error closing audio playback stream"); + return; + } + stream = 0; + this->set_sample_number (0); + this->reset_end_sample (); +} + +void audioplayer::play () +{ + if (this->get_stream ()) + { + this->stop (); + } + PaError err; + if (this->octave_callback_function != 0) + { + err = Pa_OpenStream (&stream, NULL, &(this->output_parameters), this->get_fs (), BUFFER_SIZE, paClipOff, octave_play_callback, (void *)this); + } + else + { + err = Pa_OpenStream (&stream, NULL, &(this->output_parameters), this->get_fs (), BUFFER_SIZE, paClipOff, portaudio_play_callback, (void *)this); + } + if (err != paNoError) + { + error ("audioplayer: Error opening audio playback stream"); + return; + } + err = Pa_StartStream (stream); + if (err != paNoError) + { + error ("audioplayer: Error starting audio playback stream"); + return; + } +} + +void audioplayer::pause () +{ + if (this->get_stream () == 0) + { + return; + } + PaError err; + err = Pa_StopStream (stream); + if (err != paNoError) + { + error ("audiorecorder: Error stoping audio recording stream"); + return; + } +} + +void audioplayer::resume () +{ + if (this->get_stream() == 0) + { + return; + } + PaError err; + err = Pa_StartStream (stream); + if (err != paNoError) + { + error ("audiorecorder: Error starting audio recording stream"); + return; + } +} + +PaStream *audioplayer::get_stream() +{ + return this->stream; +} + +void audioplayer::stop() +{ + if (this->get_stream () == 0) + { + return; + } + PaError err; + this->set_sample_number (0); + this->reset_end_sample (); + if (not Pa_IsStreamStopped (this->get_stream ())) + { + err = Pa_AbortStream (this->get_stream ()); + if (err != paNoError) + { + error ("audioplayer: Error stopping audio playback stream"); + return; + } + } + err = Pa_CloseStream (this->get_stream ()); + if (err != paNoError) + { + error ("audioplayer: Error closing audio playback stream"); + return; + } + stream = 0; +} + +bool audioplayer::isplaying () +{ + if (this->get_stream() == 0) + { + return false; + } + PaError err; + err = Pa_IsStreamActive (stream); + if (err != 0 and err != 1) + { + error ("audiorecorder: Error checking stream activity status"); + return false; + } + return bool(err); +} \ No newline at end of file diff -r 2e174b5e7703 -r 91ee78cdba6c libinterp/dldfcn/player_class.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libinterp/dldfcn/player_class.h Wed Sep 11 22:08:20 2013 +0300 @@ -0,0 +1,86 @@ +#ifndef PLAYER_CLASS_H +#define PLAYER_CLASS_H + +#include +#include +#include +#include + +#include "player_class.h" + +enum audio_type {INT8, UINT8, INT16, DOUBLE}; + +class audioplayer : public octave_base_value +{ +public: + audioplayer(); + ~audioplayer(); + // Overloaded base functions + double player_value() const { return 0; } + virtual double scalar_value (bool frc_str_conv = false) const + { + return 0; + } + void print (std::ostream& os, bool pr_as_read_syntax = false) const; + void print_raw (std::ostream& os, bool pr_as_read_syntax) const; + // Properties + bool is_constant (void) const { return true;} + bool is_defined (void) const { return true;} + bool print_as_scalar (void) const { return true;} + + void init(); + void init_fn(); + void set_y(octave_value y); + void set_y(octave_function *fn); + void set_y(std::string fn); + Matrix &get_y(); + RowVector *get_left(); + RowVector *get_right(); + void set_fs(int fs); + int get_fs(); + void set_nbits(int nbits); + int get_nbits(); + void set_id(int id); + int get_id(); + int get_channels(); + audio_type get_type(); + + void set_sample_number(unsigned int sample); + unsigned int get_sample_number(); + unsigned int get_total_samples(); + void set_end_sample(unsigned int sample); + unsigned int get_end_sample(); + void reset_end_sample(); + void set_tag(charMatrix tag); + charMatrix get_tag(); + void set_userdata(octave_value userdata); + octave_value get_userdata(); + PaStream *get_stream(); + octave_function *octave_callback_function; + + void playblocking(); + void play(); + void pause(); + void resume(); + void stop(); + bool isplaying(); +private: + Matrix y; + RowVector left; + RowVector right; + charMatrix tag; + octave_value userdata; + int channels; + int fs; + int nbits; + int id; + unsigned int sample_number; + unsigned int end_sample; + PaStream *stream; + PaStreamParameters output_parameters; + audio_type type; + DECLARE_OCTAVE_ALLOCATOR + DECLARE_OV_TYPEID_FUNCTIONS_AND_DATA +}; + +#endif // PLAYER_CLASS_H diff -r 2e174b5e7703 -r 91ee78cdba6c libinterp/dldfcn/recorder_class.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libinterp/dldfcn/recorder_class.cc Wed Sep 11 22:08:20 2013 +0300 @@ -0,0 +1,473 @@ +#include +#include +#include +#include +#include + +#include "common.h" +#include "player_class.h" +#include "recorder_class.h" + +#define BUFFER_SIZE 512 + +DEFINE_OCTAVE_ALLOCATOR (audiorecorder); +DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (audiorecorder, "audiorecorder", "audiorecorder"); + +static int octave_record_callback (const void *input, void *output, + unsigned long frames, + const PaStreamCallbackTimeInfo* time, + PaStreamCallbackFlags status, + void *data) +{ + audiorecorder *recorder = (audiorecorder *)data; + int channels = recorder->get_channels (); + int return_status; + float sample_l, sample_r; + Matrix sound; + sound.resize(frames, 2); + if (recorder->get_nbits () == 8) + { + int8_t *input8 = (int8_t *)input; + for (int i = 0; i < frames; i++) + { + sample_l = input8[i * channels] / (pow(2.0, 7) - 1.0); + sample_r = input8[i * channels + (channels - 1)] / (pow(2.0, 7) - 1.0); + sound(i, 0) = sample_l; + sound(i, 1) = sample_r; + } + } + else if (recorder->get_nbits () == 16) + { + int16_t *input16 = (int16_t *)input; + for (int i = 0; i < frames; i++) + { + sample_l = input16[i * channels] / (pow(2.0, 15) - 1.0); + sample_r = input16[i * channels + (channels - 1)] / (pow(2.0, 15) - 1.0); + sound(i, 0) = sample_l; + sound(i, 1) = sample_r; + } + } + else if (recorder->get_nbits () == 24) + { + uint8_t *input24 = (uint8_t *)input; + int32_t sample_l32, sample_r32; + uint8_t *_sample_l = (uint8_t *)&sample_l; + uint8_t *_sample_r = (uint8_t *)&sample_r; + for (int i = 0; i < frames; i++) + { + for (int j = 0; j < 3; j++) + { + _sample_l[j] = input24[i * channels * 3 + j]; + _sample_r[j] = input24[i * channels * 3 + (channels - 1) * 3 + j]; + } + if (sample_l32 & 0x00800000) + { + sample_l32 |= 0xff000000; + } + if (sample_r32 & 0x00800000) + { + sample_r32 |= 0xff000000; + } + sound(i, 0) = sample_l32 / pow(2.0, 23); + sound(i, 1) = sample_r32 / pow(2.0, 23); + } + } + octave_value_list args, retval; + args(0) = sound; + retval = feval (recorder->octave_callback_function, args, 1); + return_status = retval(0).int_value (); + return return_status; +} + +static int portaudio_record_callback (const void *input, void *output, + unsigned long frames, + const PaStreamCallbackTimeInfo* time, + PaStreamCallbackFlags status, + void *data) +{ + audiorecorder *recorder = (audiorecorder *)data; + int channels = recorder->get_channels (); + float sample_l, sample_r; + if (recorder->get_nbits () == 8) + { + int8_t *input8 = (int8_t *)input; + for (int i = 0; i < frames; i++) + { + sample_l = input8[i * channels] / (pow(2.0, 7) - 1.0); + sample_r = input8[i * channels + (channels - 1)] / (pow(2.0, 7) - 1.0); + recorder->append(sample_l, sample_r); + } + } + else if (recorder->get_nbits () == 16) + { + int16_t *input16 = (int16_t *)input; + for (int i = 0; i < frames; i++) + { + sample_l = input16[i * channels] / (pow(2.0, 15) - 1.0); + sample_r = input16[i * channels + (channels - 1)] / (pow(2.0, 15) - 1.0); + recorder->append(sample_l, sample_r); + } + } + else if (recorder->get_nbits () == 24) + { + uint8_t *input24 = (uint8_t *)input; + int32_t sample_l32, sample_r32; + uint8_t *_sample_l = (uint8_t *)&sample_l; + uint8_t *_sample_r = (uint8_t *)&sample_r; + for (int i = 0; i < frames; i++) + { + for (int j = 0; j < 3; j++) + { + _sample_l[j] = input24[i * channels * 3 + j]; + _sample_r[j] = input24[i * channels * 3 + (channels - 1) * 3 + j]; + } + if (sample_l32 & 0x00800000) + { + sample_l32 |= 0xff000000; + } + if (sample_r32 & 0x00800000) + { + sample_r32 |= 0xff000000; + } + recorder->append(sample_l32 / pow(2.0, 23), sample_r32 / pow(2.0, 23)); + } + } + if (recorder->get_sample_number () > recorder->get_end_sample ()) + { + return paComplete; + } + return paContinue; +} + +audiorecorder::audiorecorder () +{ + this->id = -1; + this->sample_number = 0; + this->channels = 1; + this->tag = charMatrix (""); + Matrix userdata; + this->userdata = octave_value (userdata); + this->stream = 0; + this->end_sample = -1; + this->set_fs(44100); + this->set_nbits(16); + this->set_channels(2); + this->octave_callback_function = 0; +} + +audiorecorder::~audiorecorder () +{ + +} + +void audiorecorder::print (std::ostream& os, bool pr_as_read_syntax ) const +{ + print_raw (os, pr_as_read_syntax); + newline (os); +} + +void audiorecorder::print_raw (std::ostream& os, bool pr_as_read_syntax) const +{ + os << 0; +} + +void audiorecorder::init () +{ + PaError err; + int device; + err = Pa_Initialize (); + if (err != paNoError) + { + error ("audiorecorder: Initialization error!"); + return; + } + int numDevices; + numDevices = Pa_GetDeviceCount (); + if (numDevices < 0) + { + error ("audiorecorder: No audio devices found!"); + return; + } + if (this->get_id () == -1) + { + device = Pa_GetDefaultInputDevice (); + } + else + { + device = this->get_id (); + } + this->input_parameters.device = device; + this->input_parameters.channelCount = this->get_channels (); + this->input_parameters.sampleFormat = bits_to_format (this->get_nbits ()); + this->input_parameters.suggestedLatency = Pa_GetDeviceInfo (device)->defaultHighInputLatency; + this->input_parameters.hostApiSpecificStreamInfo = NULL; +} + +void audiorecorder::set_fs (int fs) +{ + this->fs = fs; +} + +int audiorecorder::get_fs () +{ + return this->fs; +} + +void audiorecorder::set_nbits (int nbits) +{ + this->nbits = nbits; +} + +int audiorecorder::get_nbits () +{ + return this->nbits; +} + +void audiorecorder::set_id (int id) +{ + this->id = id; +} + +int audiorecorder::get_id () +{ + return this->id; +} + +void audiorecorder::set_channels (int channels) +{ + assert(channels == 1 or channels == 2); + this->channels = channels; +} + +int audiorecorder::get_channels () +{ + return this->channels; +} + +audio_type audiorecorder::get_type () +{ + return this->type; +} + +void audiorecorder::set_sample_number (unsigned int sample_number) +{ + this->sample_number = sample_number; +} + +unsigned int audiorecorder::get_sample_number () +{ + return this->sample_number; +} + +unsigned int audiorecorder::get_total_samples () +{ + return this->left.size (); +} + +void audiorecorder::set_end_sample (unsigned int end_sample) +{ + this->end_sample = end_sample; +} + +unsigned int audiorecorder::get_end_sample () +{ + return this->end_sample; +} + +void audiorecorder::reset_end_sample () +{ + this->set_end_sample (this->left.size ()); +} + +void audiorecorder::set_tag (charMatrix tag) +{ + this->tag = tag; +} + +charMatrix audiorecorder::get_tag () +{ + return this->tag; +} + +void audiorecorder::set_userdata (octave_value userdata) +{ + this->userdata = userdata; +} + +octave_value audiorecorder::get_userdata () +{ + return this->userdata; +} + +octave_value audiorecorder::getaudiodata() +{ + Matrix audio (2, this->left.size()); + for (int i = 0; i < this->left.size(); i++) + { + audio(0, i) = this->left[i]; + audio(1, i) = this->right[i]; + } + return octave_value (audio); +} + +audioplayer *audiorecorder::getplayer () +{ + audioplayer *player = new audioplayer (); + player->set_y(this->getaudiodata ()); + player->set_fs(this->get_fs ()); + player->set_nbits(this->get_nbits ()); + player->init(); + return player; +} + +bool audiorecorder::isrecording() +{ + if (this->get_stream() == 0) + { + return false; + } + PaError err; + err = Pa_IsStreamActive (stream); + if (err != 0 and err != 1) + { + error ("audiorecorder: Error checking stream activity status"); + return false; + } + return bool(err); +} + +void audiorecorder::record() +{ + if (this->get_stream()) + { + this->stop (); + } + this->left.clear (); + this->right.clear (); + PaError err; + if (this->octave_callback_function != 0) + { + err = Pa_OpenStream (&stream, &(this->input_parameters), NULL, this->get_fs (), BUFFER_SIZE, paClipOff, octave_record_callback, (void *)this); + } + else + { + err = Pa_OpenStream (&stream, &(this->input_parameters), NULL, this->get_fs (), BUFFER_SIZE, paClipOff, portaudio_record_callback, (void *)this); + } + if (err != paNoError) + { + error ("audiorecorder: Error opening audio recording stream"); + return; + } + err = Pa_StartStream (stream); + if (err != paNoError) + { + error ("audiorecorder: Error starting audio recording stream"); + return; + } +} + +void audiorecorder::recordblocking (float seconds) +{ + if (this->get_stream ()) + { + this->stop (); + } + this->left.clear (); + this->right.clear (); + PaError err; + err = Pa_OpenStream (&stream, &(this->input_parameters), NULL, this->get_fs (), BUFFER_SIZE, paClipOff, NULL, (void *)this); + if (err != paNoError) + { + error ("audiorecorder: Error opening audio recording stream"); + return; + } + err = Pa_StartStream (stream); + if (err != paNoError) + { + error ("audiorecorder: Error starting audio recording stream"); + return; + } + unsigned int frames = seconds * this->get_fs (); + uint8_t buffer[BUFFER_SIZE * 2 * 3]; + for (int i = 0; i < frames / BUFFER_SIZE; i++) + { + Pa_ReadStream(this->get_stream (), (void *)buffer, BUFFER_SIZE); + if (this->octave_callback_function != 0) + { + octave_record_callback((void *)buffer, NULL, BUFFER_SIZE, 0, 0, (void *)this); + } + else + { + portaudio_record_callback((void *)buffer, NULL, BUFFER_SIZE, 0, 0, (void *)this); + } + } +} + +void audiorecorder::pause () +{ + if (this->get_stream () == 0) + { + return; + } + PaError err; + err = Pa_StopStream (stream); + if (err != paNoError) + { + error ("audiorecorder: Error stoping audio recording stream"); + return; + } +} + +void audiorecorder::resume() +{ + if (this->get_stream() == 0) + { + return; + } + PaError err; + err = Pa_StartStream (stream); + if (err != paNoError) + { + error ("audiorecorder: Error starting audio recording stream"); + return; + } +} + +void audiorecorder::stop() +{ + if (this->get_stream() == 0) + { + return; + } + PaError err; + if (not Pa_IsStreamStopped (this->get_stream ())) + { + err = Pa_AbortStream (this->get_stream ()); + if (err != paNoError) + { + error ("audioplayer: Error stopping audio playback stream"); + return; + } + } + err = Pa_CloseStream (stream); + if (err != paNoError) + { + error ("audiorecorder: Error closing audio recording stream"); + return; + } + this->set_sample_number (0); + this->reset_end_sample (); + stream = 0; +} + +void audiorecorder::append (float sample_l, float sample_r) +{ + this->left.push_back (sample_l); + this->right.push_back (sample_r); + this->set_sample_number (this->get_sample_number () + 1); +} + +PaStream *audiorecorder::get_stream() +{ + return this->stream; +} diff -r 2e174b5e7703 -r 91ee78cdba6c libinterp/dldfcn/recorder_class.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libinterp/dldfcn/recorder_class.h Wed Sep 11 22:08:20 2013 +0300 @@ -0,0 +1,83 @@ +#ifndef RECORDER_CLASS_H +#define RECORDER_CLASS_H + +#include + +#include +#include +#include + +#include "player_class.h" + +class audiorecorder : public octave_base_value +{ +public: + audiorecorder(); + ~audiorecorder(); + // Overloaded base functions + double player_value() const { return 0; } + virtual double scalar_value (bool frc_str_conv = false) const + { + return 0; + } + void print (std::ostream& os, bool pr_as_read_syntax = false) const; + void print_raw (std::ostream& os, bool pr_as_read_syntax) const; + // Properties + bool is_constant (void) const { return true;} + bool is_defined (void) const { return true;} + bool print_as_scalar (void) const { return true;} + + void init(); + void set_fs(int fs); + int get_fs(); + void set_nbits(int nbits); + int get_nbits(); + void set_id(int id); + int get_id(); + void set_channels(int channels); + int get_channels(); + audio_type get_type(); + + void set_sample_number(unsigned int sample); + unsigned int get_sample_number(); + unsigned int get_total_samples(); + void set_end_sample(unsigned int sample); + unsigned int get_end_sample(); + void reset_end_sample(); + void set_tag(charMatrix tag); + charMatrix get_tag(); + void set_userdata(octave_value userdata); + octave_value get_userdata(); + PaStream *get_stream(); + octave_function *octave_callback_function; + + octave_value getaudiodata(); + audioplayer *getplayer(); + bool isrecording(); + audioplayer play(); + void record(); + void recordblocking(float seconds); + void pause(); + void resume(); + void stop(); + void append(float sample_l, float sample_r); +private: + Matrix y; + std::vector left; + std::vector right; + charMatrix tag; + octave_value userdata; + int channels; + int fs; + int nbits; + int id; + unsigned int sample_number; + unsigned int end_sample; + PaStream *stream; + PaStreamParameters input_parameters; + audio_type type; + DECLARE_OCTAVE_ALLOCATOR + DECLARE_OV_TYPEID_FUNCTIONS_AND_DATA +}; + +#endif // RECORDER_CLASS_H