diff options
Diffstat (limited to 'src/loris/SpcFile.h')
-rw-r--r-- | src/loris/SpcFile.h | 368 |
1 files changed, 368 insertions, 0 deletions
diff --git a/src/loris/SpcFile.h b/src/loris/SpcFile.h new file mode 100644 index 0000000..118b30d --- /dev/null +++ b/src/loris/SpcFile.h @@ -0,0 +1,368 @@ +/* + * This is the Loris C++ Class Library, implementing analysis, + * manipulation, and synthesis of digitized sounds using the Reassigned + * Bandwidth-Enhanced Additive Sound Model. + * + * Loris is Copyright (c) 1999-2010 by Kelly Fitz and Lippold Haken + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY, without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * SpcFile.h + * + * Definition of SpcFile class for Partial import and export for + * real-time synthesis in Kyma. + * + * Spc files always represent a number of Partials that is a power of + * two. This is not necessary for purely-sinusoidal files, but might be + * (not clear) for enhanced data to be properly processed in Kyma. + * + * All of this is kind of disgusting right now. This code has evolved + * somewhat randomly, and we are awaiting full support for bandwidth- + * enhanced data in Kyma.. + * + * Kelly Fitz, 8 Jan 2003 + * loris@cerlsoundgroup.org + * + * http://www.cerlsoundgroup.org/Loris/ + * + */ +#include "Marker.h" +#include "Partial.h" + +#if defined(NO_TEMPLATE_MEMBERS) +#include "PartialList.h" +#endif + +#include <string> +#include <vector> + +// begin namespace +namespace Loris { + +// --------------------------------------------------------------------------- +// class SpcFile +// +//! Class SpcFile represents a collection of reassigned bandwidth-enhanced +//! Partial data in a SPC-format envelope stream data file, used by the +//! real-time bandwidth-enhanced additive synthesizer implemented on the +//! Symbolic Sound Kyma Sound Design Workstation. Class SpcFile manages +//! file I/O and conversion between Partials and envelope parameter streams. +// +class SpcFile +{ +// -- public interface -- +public: + +// -- types -- + + //! the type of the container of Markers + //! stored with an SpcFile + typedef std::vector< Marker > markers_type; + + //! the type of the container of Partials + //! stored with an SpcFile + typedef std::vector< Partial > partials_type; + +// -- construction -- + + //! Initialize an instance of SpcFile by importing envelope parameter + //! streams from the file having the specified filename or path. + //! + //! \param filename the name of the file to import + explicit SpcFile( const std::string & filename ); + + //! Initialize an instance of SpcFile with copies of the Partials + //! on the specified half-open (STL-style) range. + //! + //! If compiled with NO_TEMPLATE_MEMBERS defined, this member accepts + //! only PartialList::const_iterator arguments. + //! + //! \param begin_partials the beginning of a range of Partials to prepare + //! for Spc export + //! \param end_partials the end of a range of Partials to prepare + //! for Spc export + //! \param midiNoteNum the fractional MIDI note number, if specified + //! (default is 60) +#if !defined(NO_TEMPLATE_MEMBERS) + template<typename Iter> + SpcFile( Iter begin_partials, Iter end_partials, double midiNoteNum = 60 ); +#else + SpcFile( PartialList::const_iterator begin_partials, + PartialList::const_iterator end_partials, + double midiNoteNum = 60 ); +#endif + + //! Initialize an instance of SpcFile having the specified fractional + //! MIDI note number, and no Partials (or envelope parameter streams). + //! + //! \param midiNoteNum the fractional MIDI note number, if specified + //! (default is 60) + explicit SpcFile( double midiNoteNum = 60 ); + + // copy, assign, and delete are compiler-generated + +// -- access -- + + //! Return a reference to the MarkerContainer (see Marker.h) for this SpcFile. + markers_type & markers( void ); + + //! Return a reference to the MarkerContainer (see Marker.h) for this SpcFile. + const markers_type & markers( void ) const; + + //! Return the fractional MIDI note number assigned to this SpcFile. + //! If the sound has no definable pitch, note number 60.0 is used. + double midiNoteNumber( void ) const; + + //! Return a read-only (const) reference to the bandwidth-enhanced + //! Partials represented by the envelope parameter streams in this SpcFile. + const partials_type & partials( void ) const; + + //! Return the sampling freqency in Hz for the spc data in this + //! SpcFile. This is the rate at which Kyma must be running to ensure + //! proper playback of bandwidth-enhanced Spc data. + double sampleRate( void ) const; + +// -- mutation -- + + //! Add the specified Partial to the enevelope parameter streams + //! represented by this SpcFile. + //! + //! A SpcFile can contain only one Partial having any given (non-zero) + //! label, so an added Partial will replace a Partial having the + //! same label, if such a Partial exists. + //! + //! This may throw an InvalidArgument exception if an attempt is made + //! to add unlabeled Partials, or Partials labeled higher than the + //! allowable maximum. + //! + //! \param p the Partial to add to this SpcFile + void addPartial( const Loris::Partial & p ); + + //! Add a Partial, assigning it the specified label (and position in the + //! Spc data). + //! + //! A SpcFile can contain only one Partial having any given (non-zero) + //! label, so an added Partial will replace a Partial having the + //! same label, if such a Partial exists. + //! + //! This may throw an InvalidArgument exception if an attempt is made + //! to add unlabeled Partials, or Partials labeled higher than the + //! allowable maximum. + //! + //! \param p the Partial to add to this SpcFile + //! \param label the label to associate with this Partial in + //! the Spc file (the Partial's own label is ignored). + void addPartial( const Loris::Partial & p, int label ); + + //! Add all Partials on the specified half-open (STL-style) range + //! to the enevelope parameter streams represented by this SpcFile. + //! + //! A SpcFile can contain only one Partial having any given (non-zero) + //! label, so an added Partial will replace a Partial having the + //! same label, if such a Partial exists. + //! + //! If compiled with NO_TEMPLATE_MEMBERS defined, this member accepts + //! only PartialList::const_iterator arguments. + //! + //! This may throw an InvalidArgument exception if an attempt is made + //! to add unlabeled Partials, or Partials labeled higher than the + //! allowable maximum. + //! + //! \param begin_partials the beginning of a range of Partials + //! to add to this Spc file + //! \param end_partials the end of a range of Partials + //! to add to this Spc file +#if !defined(NO_TEMPLATE_MEMBERS) + template<typename Iter> + void addPartials( Iter begin_partials, Iter end_partials ); +#else + void addPartials( PartialList::const_iterator begin_partials, + PartialList::const_iterator end_partials ); +#endif + + //! Set the fractional MIDI note number assigned to this SpcFile. + //! If the sound has no definable pitch, use note number 60.0 + //! (the default). + void setMidiNoteNumber( double nn ); + + //! Set the sampling freqency in Hz for the spc data in this + //! SpcFile. This is the rate at which Kyma must be running to ensure + //! proper playback of bandwidth-enhanced Spc data. + //! + //! The default sample rate is 44100 Hz. + void setSampleRate( double rate ); + +// -- export -- + + //! Export the phase-correct bandwidth-enhanced envelope parameter + //! streams represented by this SpcFile to the file having the specified + //! filename or path. + //! + //! A nonzero endApproachTime indicates that the Partials do not include a + //! release or decay, but rather end in a static spectrum corresponding to the + //! final Breakpoint values of the partials. The endApproachTime specifies how + //! long before the end of the sound the amplitude, frequency, and bandwidth + //! values are to be modified to make a gradual transition to the static spectrum. + //! + //! If the endApproachTime is not specified, it is assumed to be zero, + //! corresponding to Partials that decay or release normally. + //! + //! \param filename the name of the file to create + //! \param endApproachTime the duration in seconds of the gradual transition + //! to a static spectrum at the end of the sound (default 0) + void write( const std::string & filename, double endApproachTime = 0 ); + + //! Export the pure sinsoidal (omitting phase and bandwidth data) envelope + //! parameter streams represented by this SpcFile to the file having the + //! specified filename or path. + //! + //! A nonzero endApproachTime indicates that the Partials do not include a + //! release or decay, but rather end in a static spectrum corresponding to the + //! final Breakpoint values of the partials. The endApproachTime specifies how + //! long before the end of the sound the amplitude, frequency, and bandwidth + //! values are to be modified to make a gradual transition to the static spectrum. + //! + //! If the endApproachTime is not specified, it is assumed to be zero, + //! corresponding to Partials that decay or release normally. + //! + //! \param filename the name of the file to create + //! \param endApproachTime the duration in seconds of the gradual transition + //! to a static spectrum at the end of the sound (default 0) + void writeSinusoidal( const std::string & filename, double endApproachTime = 0 ); + + //! Export the envelope parameter streams represented by this SpcFile to + //! the file having the specified filename or path. Export phase-correct + //! bandwidth-enhanced envelope parameter streams if enhanced is true + //! (the default), or pure sinsoidal streams otherwise. + //! + //! A nonzero endApproachTime indicates that the Partials do not include a + //! release or decay, but rather end in a static spectrum corresponding to the + //! final Breakpoint values of the partials. The endApproachTime specifies how + //! long before the end of the sound the amplitude, frequency, and bandwidth + //! values are to be modified to make a gradual transition to the static spectrum. + //! + //! If the endApproachTime is not specified, it is assumed to be zero, + //! corresponding to Partials that decay or release normally. + //! + //! \deprecated This version of write is deprecated, use the two-argument + //! versions write and writeSinusoidal. + //! + //! \param filename the name of the file to create + //! \param enhanced flag indicating whether to export enhanced (true) + //! or sinusoidal (false) data + //! \param endApproachTime the duration in seconds of the gradual transition + //! to a static spectrum at the end of the sound (default 0) + void write( const std::string & filename, bool enhanced, + double endApproachTime = 0 ); + +private: +// -- implementation -- + partials_type partials_; //! Partials to store in Spc format + markers_type markers_; //! AIFF Markers + + double notenum_; //! fractional MIDI note number + double rate_; //! sample rate in Hz at which the data plays at the + //! correction default pitch + + static const int MinNumPartials; //! the minimum number of Partials to export (32) + //! (if necessary, extra empty (silent) Partials + //! will be exported to make up the difference between + //! the size of partials_ and the next larger power + //! of two, not less than MinNumPartials + static const double DefaultRate; //! the default Spc export sample rate in Hz (44kHz) + +// -- helpers -- + void readSpcData( const std::string & filename ); + void growPartials( partials_type::size_type sz ); + +}; // end of class SpcFile + + +// --------------------------------------------------------------------------- +// constructor from Partial range +// --------------------------------------------------------------------------- +//! Initialize an instance of SpcFile with copies of the Partials +//! on the specified half-open (STL-style) range. +//! +//! If compiled with NO_TEMPLATE_MEMBERS defined, this member accepts +//! only PartialList::const_iterator arguments. +//! +//! \param begin_partials the beginning of a range of Partials to prepare +//! for Spc export +//! \param end_partials the end of a range of Partials to prepare +//! for Spc export +//! \param midiNoteNum the fractional MIDI note number, if specified +//! (default is 60) +#if !defined(NO_TEMPLATE_MEMBERS) +template< typename Iter > +SpcFile::SpcFile( Iter begin_partials, Iter end_partials, double midiNoteNum ) : +#else +SpcFile::SpcFile( PartialList::const_iterator begin_partials, + PartialList::const_iterator end_partials, + double midiNoteNum ) : +#endif +// initializers: + notenum_( midiNoteNum ), + rate_( DefaultRate ) +{ + growPartials( MinNumPartials ); + addPartials( begin_partials, end_partials ); +} + +// --------------------------------------------------------------------------- +// addPartials +// --------------------------------------------------------------------------- +//! Add all Partials on the specified half-open (STL-style) range +//! to the enevelope parameter streams represented by this SpcFile. +//! +//! A SpcFile can contain only one Partial having any given (non-zero) +//! label, so an added Partial will replace a Partial having the +//! same label, if such a Partial exists. +//! +//! If compiled with NO_TEMPLATE_MEMBERS defined, this member accepts +//! only PartialList::const_iterator arguments. +//! +//! This may throw an InvalidArgument exception if an attempt is made +//! to add unlabeled Partials, or Partials labeled higher than the +//! allowable maximum. +//! +//! \param begin_partials the beginning of a range of Partials +//! to add to this Spc file +//! \param end_partials the end of a range of Partials +//! to add to this Spc file +#if !defined(NO_TEMPLATE_MEMBERS) +template<typename Iter> +void SpcFile::addPartials( Iter begin_partials, Iter end_partials ) +#else +void SpcFile::addPartials( PartialList::const_iterator begin_partials, + PartialList::const_iterator end_partials ) +#endif +{ + while ( begin_partials != end_partials ) + { + // do not try to add unlabeled Partials, or + // Partials labeled beyond 256: + if ( 0 != begin_partials->label() && 257 > begin_partials->label() ) + { + addPartial( *begin_partials ); + } + ++begin_partials; + } +} + +} // end of namespace Loris + + |