You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

232 lines
6.5KB

  1. /***************************************************/
  2. /*! \class InetWvOut
  3. \brief STK internet streaming output class.
  4. This WvOut subclass can stream data over a network via a TCP or
  5. UDP socket connection. The data is converted to big-endian byte
  6. order, if necessary, before being transmitted.
  7. InetWvOut supports multi-channel data. It is important to
  8. distinguish the tick() method that outputs a single sample to all
  9. channels in a sample frame from the overloaded one that takes a
  10. reference to an StkFrames object for multi-channel and/or
  11. multi-frame data.
  12. This class connects to a socket server, the port and IP address of
  13. which must be specified as constructor arguments. The default
  14. data type is signed 16-bit integers but any of the defined
  15. StkFormats are permissible.
  16. by Perry R. Cook and Gary P. Scavone, 1995--2017.
  17. */
  18. /***************************************************/
  19. #include "InetWvOut.h"
  20. #include "TcpClient.h"
  21. #include "UdpSocket.h"
  22. #include <sstream>
  23. namespace stk {
  24. InetWvOut :: InetWvOut( unsigned long packetFrames )
  25. : buffer_(0), soket_(0), bufferFrames_(packetFrames), bufferBytes_(0)
  26. {
  27. }
  28. InetWvOut :: InetWvOut( int port, Socket::ProtocolType protocol, std::string hostname,
  29. unsigned int nChannels, Stk::StkFormat format, unsigned long packetFrames )
  30. : buffer_(0), soket_(0), bufferFrames_(packetFrames), bufferBytes_(0)
  31. {
  32. connect( port, protocol, hostname, nChannels, format );
  33. }
  34. InetWvOut :: ~InetWvOut()
  35. {
  36. disconnect();
  37. if ( soket_ ) delete soket_;
  38. if ( buffer_ ) delete [] buffer_;
  39. }
  40. void InetWvOut :: connect( int port, Socket::ProtocolType protocol, std::string hostname,
  41. unsigned int nChannels, Stk::StkFormat format )
  42. {
  43. if ( soket_ && soket_->isValid( soket_->id() ) )
  44. disconnect();
  45. if ( nChannels == 0 ) {
  46. oStream_ << "InetWvOut::connect: the channel argument must be greater than zero!";
  47. handleError( StkError::FUNCTION_ARGUMENT );
  48. }
  49. if ( format == STK_SINT8 ) dataBytes_ = 1;
  50. else if ( format == STK_SINT16 ) dataBytes_ = 2;
  51. else if ( format == STK_SINT32 || format == STK_FLOAT32 ) dataBytes_ = 4;
  52. else if ( format == STK_FLOAT64 ) dataBytes_ = 8;
  53. else {
  54. oStream_ << "InetWvOut::connect: unknown data type specified.";
  55. handleError( StkError::FUNCTION_ARGUMENT );
  56. }
  57. dataType_ = format;
  58. if ( protocol == Socket::PROTO_TCP ) {
  59. soket_ = new TcpClient( port, hostname );
  60. }
  61. else {
  62. // For UDP sockets, the sending and receiving sockets cannot have
  63. // the same port number. Since the port argument corresponds to
  64. // the destination port, we will associate this socket instance
  65. // with a different port number (arbitrarily determined as port -
  66. // 1).
  67. UdpSocket *socket = new UdpSocket( port - 1 );
  68. socket->setDestination( port, hostname );
  69. soket_ = (Socket *) socket;
  70. }
  71. // Allocate new memory if necessary.
  72. data_.resize( bufferFrames_, nChannels );
  73. unsigned long bufferBytes = dataBytes_ * bufferFrames_ * nChannels;
  74. if ( bufferBytes > bufferBytes_ ) {
  75. if ( buffer_) delete [] buffer_;
  76. buffer_ = (char *) new char[ bufferBytes ];
  77. bufferBytes_ = bufferBytes;
  78. }
  79. frameCounter_ = 0;
  80. bufferIndex_ = 0;
  81. iData_ = 0;
  82. }
  83. void InetWvOut :: disconnect(void)
  84. {
  85. if ( soket_ ) {
  86. writeData( bufferIndex_ );
  87. soket_->close( soket_->id() );
  88. delete soket_;
  89. soket_ = 0;
  90. }
  91. }
  92. void InetWvOut :: writeData( unsigned long frames )
  93. {
  94. unsigned long samples = frames * data_.channels();
  95. if ( dataType_ == STK_SINT8 ) {
  96. signed char *ptr = (signed char *) buffer_;
  97. for ( unsigned long k=0; k<samples; k++ ) {
  98. this->clipTest( data_[k] );
  99. *ptr++ = (signed char) (data_[k] * 127.0);
  100. }
  101. }
  102. else if ( dataType_ == STK_SINT16 ) {
  103. SINT16 *ptr = (SINT16 *) buffer_;
  104. for ( unsigned long k=0; k<samples; k++ ) {
  105. this->clipTest( data_[k] );
  106. *ptr = (SINT16) (data_[k] * 32767.0);
  107. #ifdef __LITTLE_ENDIAN__
  108. swap16 ((unsigned char *)ptr);
  109. #endif
  110. ptr++;
  111. }
  112. }
  113. else if ( dataType_ == STK_SINT32 ) {
  114. SINT32 *ptr = (SINT32 *) buffer_;
  115. for ( unsigned long k=0; k<samples; k++ ) {
  116. this->clipTest( data_[k] );
  117. *ptr = (SINT32) (data_[k] * 2147483647.0);
  118. #ifdef __LITTLE_ENDIAN__
  119. swap32 ((unsigned char *)ptr);
  120. #endif
  121. ptr++;
  122. }
  123. }
  124. else if ( dataType_ == STK_FLOAT32 ) {
  125. FLOAT32 *ptr = (FLOAT32 *) buffer_;
  126. for ( unsigned long k=0; k<samples; k++ ) {
  127. this->clipTest( data_[k] );
  128. *ptr = (FLOAT32) data_[k];
  129. #ifdef __LITTLE_ENDIAN__
  130. swap32 ((unsigned char *)ptr);
  131. #endif
  132. ptr++;
  133. }
  134. }
  135. else if ( dataType_ == STK_FLOAT64 ) {
  136. FLOAT64 *ptr = (FLOAT64 *) buffer_;
  137. for ( unsigned long k=0; k<samples; k++ ) {
  138. this->clipTest( data_[k] );
  139. *ptr = (FLOAT64) data_[k];
  140. #ifdef __LITTLE_ENDIAN__
  141. swap64 ((unsigned char *)ptr);
  142. #endif
  143. ptr++;
  144. }
  145. }
  146. long bytes = dataBytes_ * samples;
  147. if ( soket_->writeBuffer( (const void *)buffer_, bytes, 0 ) < 0 ) {
  148. oStream_ << "InetWvOut: connection to socket server failed!";
  149. handleError( StkError::PROCESS_SOCKET );
  150. }
  151. }
  152. void InetWvOut :: incrementFrame( void )
  153. {
  154. frameCounter_++;
  155. bufferIndex_++;
  156. if ( bufferIndex_ == bufferFrames_ ) {
  157. writeData( bufferFrames_ );
  158. bufferIndex_ = 0;
  159. iData_ = 0;
  160. }
  161. }
  162. void InetWvOut :: tick( const StkFloat sample )
  163. {
  164. if ( !soket_ || !soket_->isValid( soket_->id() ) ) {
  165. #if defined(_STK_DEBUG_)
  166. oStream_ << "InetWvOut::tick(): a valid socket connection does not exist!";
  167. handleError( StkError::DEBUG_PRINT );
  168. #endif
  169. return;
  170. }
  171. unsigned int nChannels = data_.channels();
  172. StkFloat input = sample;
  173. clipTest( input );
  174. for ( unsigned int j=0; j<nChannels; j++ )
  175. data_[iData_++] = input;
  176. this->incrementFrame();
  177. }
  178. void InetWvOut :: tick( const StkFrames& frames )
  179. {
  180. if ( !soket_ || !soket_->isValid( soket_->id() ) ) {
  181. #if defined(_STK_DEBUG_)
  182. oStream_ << "InetWvOut::tick(): a valid socket connection does not exist!";
  183. handleError( StkError::DEBUG_PRINT );
  184. #endif
  185. return;
  186. }
  187. #if defined(_STK_DEBUG_)
  188. if ( data_.channels() != frames.channels() ) {
  189. oStream_ << "InetWvOut::tick(): incompatible channel value in StkFrames argument!";
  190. handleError( StkError::FUNCTION_ARGUMENT );
  191. }
  192. #endif
  193. unsigned int j, nChannels = data_.channels();
  194. unsigned int iFrames = 0;
  195. for ( unsigned int i=0; i<frames.frames(); i++ ) {
  196. for ( j=0; j<nChannels; j++ ) {
  197. data_[iData_] = frames[iFrames++];
  198. clipTest( data_[iData_++] );
  199. }
  200. this->incrementFrame();
  201. }
  202. }
  203. } // stk namespace