1 /***************************************************/
2 /*! \class FileWvOut
3     \brief STK audio file output class.
4 
5     This class inherits from WvOut.  It provides a "tick-level"
6     interface to the FileWrite class.
7 
8     FileWvOut writes samples to an audio file and supports
9     multi-channel data.  It is important to distinguish the tick()
10     method that outputs a single sample to all channels in a sample
11     frame from the overloaded one that takes a reference to an
12     StkFrames object for multi-channel and/or multi-frame data.
13 
14     See the FileWrite class for a description of the supported audio
15     file formats.
16 
17     Currently, FileWvOut is non-interpolating and the output rate is
18     always Stk::sampleRate().
19 
20     by Perry R. Cook and Gary P. Scavone, 1995--2021.
21 */
22 /***************************************************/
23 
24 #include "FileWvOut.h"
25 
26 namespace stk {
27 
28 FileWvOut :: FileWvOut( unsigned int bufferFrames )
29   :bufferFrames_( bufferFrames )
30 {
31 }
32 
33 FileWvOut::FileWvOut( std::string fileName, unsigned int nChannels, FileWrite::FILE_TYPE type, Stk::StkFormat format, unsigned int bufferFrames )
34   :bufferFrames_( bufferFrames )
35 {
36   this->openFile( fileName, nChannels, type, format );
37 }
38 
39 FileWvOut :: ~FileWvOut()
40 {
41   this->closeFile();
42 }
43 
44 void FileWvOut :: closeFile( void )
45 {
46   if ( file_.isOpen() ) {
47 
48     // Output any remaining samples in the buffer before closing.
49     if ( bufferIndex_ > 0 ) {
50       data_.resize( bufferIndex_, data_.channels() );
51       file_.write( data_ );
52     }
53 
54     file_.close();
55     frameCounter_ = 0;
56   }
57 }
58 
59 void FileWvOut :: openFile( std::string fileName,
60                             unsigned int nChannels,
61                             FileWrite::FILE_TYPE type,
62                             Stk::StkFormat format )
63 {
64   closeFile();
65 
66   if ( nChannels < 1 ) {
67     oStream_ << "FileWvOut::openFile: the channels argument must be greater than zero!";
68     handleError( StkError::FUNCTION_ARGUMENT );
69   }
70 
71   // An StkError can be thrown by the FileWrite class here.
72   file_.open( fileName, nChannels, type, format );
73 
74   // Allocate new memory if necessary.
75   data_.resize( bufferFrames_, nChannels );
76 
77   bufferIndex_ = 0;
78   iData_ = 0;
79 }
80 
81 void FileWvOut :: incrementFrame( void )
82 {
83   frameCounter_++;
84   bufferIndex_++;
85 
86   if ( bufferIndex_ == bufferFrames_ ) {
87     file_.write( data_ );
88     bufferIndex_ = 0;
89     iData_ = 0;
90   }
91 }
92 
93 void FileWvOut :: tick( const StkFloat sample )
94 {
95 #if defined(_STK_DEBUG_)
96   if ( !file_.isOpen() ) {
97     oStream_ << "FileWvOut::tick(): no file open!";
98     handleError( StkError::WARNING );
99     return;
100   }
101 #endif
102 
103   unsigned int nChannels = data_.channels();
104   StkFloat input = sample;
105   clipTest( input );
106   for ( unsigned int j=0; j<nChannels; j++ )
107     data_[iData_++] = input;
108 
109   this->incrementFrame();
110 }
111 
112 void FileWvOut :: tick( const StkFrames& frames )
113 {
114 #if defined(_STK_DEBUG_)
115   if ( !file_.isOpen() ) {
116     oStream_ << "FileWvOut::tick(): no file open!";
117     handleError( StkError::WARNING );
118     return;
119   }
120 
121   if ( data_.channels() != frames.channels() ) {
122     oStream_ << "FileWvOut::tick(): incompatible channel value in StkFrames argument!";
123     handleError( StkError::FUNCTION_ARGUMENT );
124   }
125 #endif
126 
127   unsigned int iFrames = 0;
128   unsigned int j, nChannels = data_.channels();
129   for ( unsigned int i=0; i<frames.frames(); i++ ) {
130 
131     for ( j=0; j<nChannels; j++ ) {
132       data_[iData_] = frames[iFrames++];
133       clipTest( data_[iData_++] );
134     }
135 
136     this->incrementFrame();
137   }
138 }
139 
140 } // stk namespace
141