changeset 19508:91ee78cdba6c

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
author Vytautas Jančauskas <unaudio@gmail.com>
date Wed, 11 Sep 2013 22:08:20 +0300
parents 2e174b5e7703
children b9df6b3fd5ef
files libinterp/dldfcn/player_class.cc libinterp/dldfcn/player_class.h libinterp/dldfcn/recorder_class.cc libinterp/dldfcn/recorder_class.h
diffstat 4 files changed, 1226 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /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 <octave/oct.h>
+#include <octave/ov.h>
+#include <octave/parse.h>
+#include <portaudio.h>
+#include <stdint.h>
+
+#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
--- /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 <string>
+#include <octave/oct.h>
+#include <octave/ov-int32.h>
+#include <portaudio.h>
+
+#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
--- /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 <octave/oct.h>
+#include <octave/ov.h>
+#include <octave/parse.h>
+#include <portaudio.h>
+#include <stdint.h>
+
+#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;
+}
--- /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 <vector>
+
+#include <octave/oct.h>
+#include <octave/ov-int32.h>
+#include <portaudio.h>
+
+#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<float> left;
+    std::vector<float> 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