mirror of
https://github.com/thestk/stk
synced 2026-01-12 20:41:52 +00:00
Version 4.2.1
This commit is contained in:
committed by
Stephen Sinclair
parent
a6381b9d38
commit
2cbce2d8bd
230
src/InetWvOut.cpp
Normal file
230
src/InetWvOut.cpp
Normal file
@@ -0,0 +1,230 @@
|
||||
/***************************************************/
|
||||
/*! \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"
|
||||
|
||||
InetWvOut :: InetWvOut( unsigned long packetFrames )
|
||||
: buffer_(0), soket_(0), bufferFrames_(packetFrames), bufferBytes_(0)
|
||||
{
|
||||
}
|
||||
|
||||
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 );
|
||||
}
|
||||
|
||||
InetWvOut :: ~InetWvOut()
|
||||
{
|
||||
disconnect();
|
||||
if ( soket_ ) delete soket_;
|
||||
if ( buffer_ ) delete [] buffer_;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user