Logo Search packages:      
Sourcecode: csound version File versions  Download package

InetWvOut.cpp

/***************************************************/
/*! \class InetWvOut
    \brief STK internet streaming output class.

    This WvOut subclass can stream data over a network via a TCP or
    UDP socket connection.  The data is converted to big-endian byte
    order, if necessary, before being transmitted.

    InetWvOut supports multi-channel data.  It is important to
    distinguish the tick() methods, which output single samples to all
    channels in a sample frame, from the tickFrame() method, which
    takes a reference to multi-channel sample frame data.

    This class connects to a socket server, the port and IP address of
    which must be specified as constructor arguments.  The default
    data type is signed 16-bit integers but any of the defined
    StkFormats are permissible.

    by Perry R. Cook and Gary P. Scavone, 1995 - 2005.
*/
/***************************************************/

#include "InetWvOut.h"
#include "TcpClient.h"
#include "UdpSocket.h"

00027 InetWvOut :: InetWvOut( unsigned long packetFrames )
  : buffer_(0), soket_(0), bufferFrames_(packetFrames), bufferBytes_(0)
{
}

00032 InetWvOut :: InetWvOut( int port, Socket::ProtocolType protocol, std::string hostname,
                        unsigned int nChannels, Stk::StkFormat format, unsigned long packetFrames )
  : buffer_(0), soket_(0), bufferFrames_(packetFrames), bufferBytes_(0)
{
  connect( port, protocol, hostname, nChannels, format );
}

00039 InetWvOut :: ~InetWvOut()
{
  disconnect();
  if ( soket_ ) delete soket_;
  if ( buffer_ ) delete [] buffer_;
}

00046 void InetWvOut :: connect( int port, Socket::ProtocolType protocol, std::string hostname,
                           unsigned int nChannels, Stk::StkFormat format )
{
  if ( soket_ && soket_->isValid( soket_->id() ) )
    disconnect();

  if ( nChannels == 0 ) {
    errorString_ << "InetWvOut::connect: the channel argument (" << nChannels << ") must be greater than zero!";
    handleError( StkError::FUNCTION_ARGUMENT );
  }

  if ( format == STK_SINT8 ) dataBytes_ = 1;
  else if ( format == STK_SINT16 ) dataBytes_ = 2;
  else if ( format == STK_SINT32 || format == STK_FLOAT32 ) dataBytes_ = 4;
  else if ( format == STK_FLOAT64 ) dataBytes_ = 8;
  else {
    errorString_ << "InetWvOut::connect: unknown data type specified (" << format << ").";
    handleError( StkError::FUNCTION_ARGUMENT );
  } 
  dataType_ = format;

  if ( protocol == Socket::PROTO_TCP ) {
    soket_ = new TcpClient( port, hostname );
  }
  else {
    // For UDP sockets, the sending and receiving sockets cannot have
    // the same port number.  Since the port argument corresponds to
    // the destination port, we will associate this socket instance
    // with a different port number (arbitrarily determined as port -
    // 1).
    UdpSocket *socket = new UdpSocket( port - 1 );
    socket->setDestination( port, hostname );
    soket_ = (Socket *) socket;
  }

  // Allocate new memory if necessary.
  data_.resize( bufferFrames_, nChannels );
  unsigned long bufferBytes = dataBytes_ * bufferFrames_ * nChannels;
  if ( bufferBytes > bufferBytes_ ) {
    if ( buffer_) delete [] buffer_;
    buffer_ = (char *) new char[ bufferBytes ];
    bufferBytes_ = bufferBytes;
  }
  frameCounter_ = 0;
  bufferIndex_ = 0;
  iData_ = 0;
}

00094 void InetWvOut :: disconnect(void)
{
  if ( soket_ ) {
    writeData( bufferIndex_ );
    soket_->close( soket_->id() );
    delete soket_;
    soket_ = 0;
  }
}

void InetWvOut :: writeData( unsigned long frames )
{
  unsigned long samples = frames * data_.channels();
  if ( dataType_ == STK_SINT8 ) {
    signed char *ptr = (signed char *) buffer_;
    for ( unsigned long k=0; k<samples; k++ ) {
      this->clipTest( data_[k] );
      *ptr++ = (signed char) (data_[k] * 127.0);
    }
  }
  else if ( dataType_ == STK_SINT16 ) {
    SINT16 *ptr = (SINT16 *) buffer_;
    for ( unsigned long k=0; k<samples; k++ ) {
      this->clipTest( data_[k] );
      *ptr = (SINT16) (data_[k] * 32767.0);
#ifdef __LITTLE_ENDIAN__
      swap16 ((unsigned char *)ptr);
#endif
      ptr++;
    }
  }
  else if ( dataType_ == STK_SINT32 ) {
    SINT32 *ptr = (SINT32 *) buffer_;
    for ( unsigned long k=0; k<samples; k++ ) {
      this->clipTest( data_[k] );
      *ptr = (SINT32) (data_[k] * 2147483647.0);
#ifdef __LITTLE_ENDIAN__
      swap32 ((unsigned char *)ptr);
#endif
      ptr++;
    }
  }
  else if ( dataType_ == STK_FLOAT32 ) {
    FLOAT32 *ptr = (FLOAT32 *) buffer_;
    for ( unsigned long k=0; k<samples; k++ ) {
      this->clipTest( data_[k] );
      *ptr = (FLOAT32) data_[k];
#ifdef __LITTLE_ENDIAN__
      swap32 ((unsigned char *)ptr);
#endif
      ptr++;
    }
  }
  else if ( dataType_ == STK_FLOAT64 ) {
    FLOAT64 *ptr = (FLOAT64 *) buffer_;
    for ( unsigned long k=0; k<samples; k++ ) {
      this->clipTest( data_[k] );
      *ptr = (FLOAT64) data_[k];
#ifdef __LITTLE_ENDIAN__
      swap64 ((unsigned char *)ptr);
#endif
      ptr++;
    }
  }

  long bytes = dataBytes_ * samples;
  if ( soket_->writeBuffer( (const void *)buffer_, bytes, 0 ) < 0 ) {
    errorString_ << "InetWvOut: connection to socket server failed!";
    handleError( StkError::PROCESS_SOCKET );
  }
}

void InetWvOut :: incrementFrame( void )
{
  frameCounter_++;
  bufferIndex_++;

  if ( bufferIndex_ == bufferFrames_ ) {
    writeData( bufferFrames_ );
    bufferIndex_ = 0;
    iData_ = 0;
  }
}

void InetWvOut :: computeSample( const StkFloat sample )
{
  if ( !soket_ || !soket_->isValid( soket_->id() ) ) return;

  unsigned int nChannels = data_.channels();
  StkFloat input = sample;
  clipTest( input );
  for ( unsigned int j=0; j<nChannels; j++ )
    data_[iData_++] = input;

  this->incrementFrame();
}

void InetWvOut :: computeFrames( const StkFrames& frames )
{
  if ( !soket_ || !soket_->isValid( soket_->id() ) ) return;

  if ( data_.channels() != frames.channels() ) {
    errorString_ << "InetWvOut::computeFrames(): incompatible channel value in StkFrames argument!";
    handleError( StkError::FUNCTION_ARGUMENT );
  }

  unsigned int j, nChannels = data_.channels();
  if ( nChannels == 1 || frames.interleaved() ) {

    unsigned int iFrames = 0;
    for ( unsigned int i=0; i<frames.frames(); i++ ) {

      for ( j=0; j<nChannels; j++ ) {
        data_[iData_] = frames[iFrames++];
        clipTest( data_[iData_++] );
      }

      this->incrementFrame();
    }
  }
  else { // non-interleaved frames

    unsigned long hop = frames.frames();
    unsigned int index;
    for ( unsigned int i=0; i<frames.frames(); i++ ) {

      index = i;
      for ( j=0; j<nChannels; j++ ) {
        data_[iData_] = frames[index];
        clipTest( data_[iData_++] );
        index += hop;
      }

      this->incrementFrame();
    }
  }
}

Generated by  Doxygen 1.6.0   Back to index